133 lines
2.9 KiB
TypeScript
133 lines
2.9 KiB
TypeScript
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<string, string> = {
|
|
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);
|
|
}
|