export type DisplayMode = "list" | "grid"; export type FileItemType = "dir" | "file"; export interface ServerFile { name: string; extension?: string; absolutePath?: string; size?: number; modifiedAt?: number; type?: string; isFile?: boolean; isDirectory?: boolean; canPreview?: boolean; previewURI?: string; } export interface ExplorerItem { name: string; type: FileItemType; size?: string; updatedAt: string; icon: string; path: string; rawType?: string; } const fileIconMap: Record = { TXT: "file-text", CODE: "code", SCRIPT: "code", ZIP: "file-zip", MICROSOFT: "file-excel", JAVA: "logo-android", VIDEO: "video", FONT: "font-size", AUDIO: "music", IMAGE: "image", SYSTEM: "setting", FILE: "file" }; const dateTimeFormatter = new Intl.DateTimeFormat("zh-CN", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", hour12: false }); export function mapServerFileToExplorerItem(file: ServerFile): ExplorerItem { const isDirectory = file.isDirectory || file.type === "DIRECTORY"; const rawPath = typeof file.absolutePath === "string" ? file.absolutePath.trim() : ""; return { name: file.name || "未命名", type: isDirectory ? "dir" : "file", size: isDirectory ? undefined : formatFileSize(file.size), updatedAt: formatModifiedAt(file.modifiedAt), icon: resolveFileIcon(file, isDirectory), path: rawPath || file.name || "", rawType: file.type }; } export function sortExplorerItems(items: ExplorerItem[]): ExplorerItem[] { return [...items].sort((left, right) => { if (left.type !== right.type) { return left.type === "dir" ? -1 : 1; } return left.name.localeCompare(right.name, "zh-CN"); }); } export function formatItemDesc(item: ExplorerItem): string { if (item.type === "dir") { return `文件夹 | ${item.updatedAt}`; } return `${item.size || "--"} | ${item.updatedAt}`; } function resolveFileIcon(file: ServerFile, isDirectory: boolean): string { if (isDirectory) { return "folder"; } const rawType = typeof file.type === "string" ? file.type.toUpperCase() : "FILE"; return fileIconMap[rawType] || "file"; } function formatModifiedAt(modifiedAt?: number): string { if (!modifiedAt) { return "未知时间"; } return dateTimeFormatter.format(modifiedAt); } function formatFileSize(size?: number): string { if (typeof size !== "number" || Number.isNaN(size) || size < 0) { return "--"; } if (size < 1024) { return `${size} B`; } const units = ["KB", "MB", "GB", "TB"]; let nextSize = size / 1024; let unitIndex = 0; while (1024 <= nextSize && unitIndex < units.length - 1) { nextSize /= 1024; unitIndex += 1; } return `${trimDecimal(nextSize)} ${units[unitIndex]}`; } function trimDecimal(value: number): string { if (10 <= value || Number.isInteger(value)) { return value.toFixed(0); } if (1 <= value) { return value.toFixed(1); } return value.toFixed(2); }