diff --git a/frontend/src/pages/DataManagement/Detail/components/Overview.tsx b/frontend/src/pages/DataManagement/Detail/components/Overview.tsx index 5def6069..bf4d942c 100644 --- a/frontend/src/pages/DataManagement/Detail/components/Overview.tsx +++ b/frontend/src/pages/DataManagement/Detail/components/Overview.tsx @@ -1,4 +1,4 @@ -import { App, Button, Descriptions, DescriptionsProps, Modal, Table, Input } from "antd"; +import { App, Button, Descriptions, DescriptionsProps, Modal, Table, Input, Spin } from "antd"; import { formatBytes, formatDateTime } from "@/utils/unit"; import { Download, Trash2, Folder, File } from "lucide-react"; import { datasetTypeMap } from "../../dataset.const"; @@ -13,6 +13,9 @@ export default function Overview({ dataset, filesOperation, fetchDataset }) { previewVisible, previewFileName, previewContent, + previewUrl, + previewFileDetail, + previewLoading, setPreviewVisible, handleDeleteFile, handleDownloadFile, @@ -23,6 +26,7 @@ export default function Overview({ dataset, filesOperation, fetchDataset }) { handleDeleteDirectory, handleRenameFile, handleRenameDirectory, + handlePreviewFile, } = filesOperation; // 文件列表多选配置 @@ -142,7 +146,7 @@ export default function Overview({ dataset, filesOperation, fetchDataset }) { return ( @@ -453,18 +457,101 @@ export default function Overview({ dataset, filesOperation, fetchDataset }) { open={previewVisible} onCancel={() => setPreviewVisible(false)} footer={null} - width={700} + width={1000} > -
-          {previewContent}
-        
+
+ {/* 左侧预览区域 */} +
+ {previewLoading ? ( + + ) : previewUrl ? ( + {previewFileName} + ) : previewContent ? ( +
+                {previewContent}
+              
+ ) : ( + + 暂无预览内容,或当前文件类型暂不支持预览。 + + )} +
+ + {/* 右侧文件信息(来自 t_dm_dataset_files) */} +
+

文件信息

+
+
+ 文件名: + {previewFileDetail?.fileName || previewFileName} +
+ {previewFileDetail?.originalName && ( +
+ 原始文件名: + {previewFileDetail.originalName} +
+ )} + {previewFileDetail?.fileType && ( +
+ 文件类型: + {previewFileDetail.fileType} +
+ )} + {typeof previewFileDetail?.fileSize === "number" && ( +
+ 文件大小: + {formatBytes(previewFileDetail.fileSize || 0)} +
+ )} + {previewFileDetail?.status && ( +
+ 状态: + {previewFileDetail.status} +
+ )} + {previewFileDetail?.uploadTime && ( +
+ 上传时间: + {formatDateTime(previewFileDetail.uploadTime)} +
+ )} + {previewFileDetail?.uploadedBy && ( +
+ 上传者: + {previewFileDetail.uploadedBy} +
+ )} + {previewFileDetail?.filePath && ( +
+ 文件路径: + {previewFileDetail.filePath} +
+ )} + {previewFileDetail?.description && ( +
+ 描述: + {previewFileDetail.description} +
+ )} +
+
+
); diff --git a/frontend/src/pages/DataManagement/Detail/useFilesOperation.ts b/frontend/src/pages/DataManagement/Detail/useFilesOperation.ts index 88318013..64c852e0 100644 --- a/frontend/src/pages/DataManagement/Detail/useFilesOperation.ts +++ b/frontend/src/pages/DataManagement/Detail/useFilesOperation.ts @@ -35,6 +35,9 @@ export function useFilesOperation(dataset: Dataset) { const [previewVisible, setPreviewVisible] = useState(false); const [previewContent, setPreviewContent] = useState(""); const [previewFileName, setPreviewFileName] = useState(""); + const [previewUrl, setPreviewUrl] = useState(); + const [previewFileDetail, setPreviewFileDetail] = useState(); + const [previewLoading, setPreviewLoading] = useState(false); const fetchFiles = async (prefix?: string, current?, pageSize?) => { // 如果明确传了 prefix(包括空字符串),使用传入的值;否则使用当前 pagination.prefix @@ -88,16 +91,47 @@ export function useFilesOperation(dataset: Dataset) { setSelectedFiles([]); // 清空选中状态 }; - const handleShowFile = (file: any) => async () => { - // 请求文件内容并弹窗预览 + const isImageFile = (fileName?: string, fileType?: string) => { + const lowerType = (fileType || "").toLowerCase(); + if (lowerType.includes("image")) return true; + const name = (fileName || "").toLowerCase(); + return [".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"].some((ext) => + name.endsWith(ext) + ); + }; + + const handlePreviewFile = async (file: any) => { + if (!file || !file.id) return; + const datasetId = dataset.id; + setPreviewVisible(true); + setPreviewLoading(true); + setPreviewFileName(file.fileName || ""); + setPreviewContent(""); + setPreviewUrl(undefined); + setPreviewFileDetail(undefined); try { - const res = await fetch(`/api/datasets/${dataset.id}/file/${file.id}`); - const data = await res.text(); - setPreviewFileName(file.fileName); - setPreviewContent(data); - setPreviewVisible(true); - } catch (err) { + // 获取文件元信息(来自 t_dm_dataset_files) + const detailRes: any = await (await import("../dataset.api")).getDatasetFileByIdUsingGet( + datasetId, + file.id + ); + const detail = detailRes?.data || detailRes; + setPreviewFileDetail(detail); + + const downloadUrl = `/api/data-management/datasets/${datasetId}/files/${file.id}/download`; + const image = isImageFile(detail?.fileName || file.fileName, detail?.fileType); + + if (image) { + setPreviewUrl(downloadUrl); + } else { + const res = await fetch(downloadUrl); + const text = await res.text(); + setPreviewContent(text); + } + } catch (error) { message.error({ content: "文件预览失败" }); + } finally { + setPreviewLoading(false); } }; @@ -141,13 +175,16 @@ export function useFilesOperation(dataset: Dataset) { setPreviewVisible, previewContent, previewFileName, + previewUrl, + previewFileDetail, + previewLoading, setPreviewContent, setPreviewFileName, fetchFiles, setFileList, handleBatchDeleteFiles, handleDownloadFile, - handleShowFile, + handlePreviewFile, handleDeleteFile, handleBatchExport, handleCreateDirectory: async (directoryName: string) => { diff --git a/frontend/src/pages/DataManagement/dataset.api.ts b/frontend/src/pages/DataManagement/dataset.api.ts index 8ef3e0fd..f6d4e3f3 100644 --- a/frontend/src/pages/DataManagement/dataset.api.ts +++ b/frontend/src/pages/DataManagement/dataset.api.ts @@ -49,6 +49,16 @@ export function queryDatasetFilesUsingGet(id: string | number, params?: any) { return get(`/api/data-management/datasets/${id}/files`, params); } +// 根据ID获取单个数据集文件详情 +export function getDatasetFileByIdUsingGet( + datasetId: string | number, + fileId: string | number +) { + return get( + `/api/data-management/datasets/${datasetId}/files/${fileId}` + ); +} + // 上传数据集文件 export function uploadDatasetFileUsingPost(id: string | number, data: any) { return post(`/api/data-management/datasets/${id}/files`, data); diff --git a/runtime/datamate-python/app/module/annotation/interface/auto.py b/runtime/datamate-python/app/module/annotation/interface/auto.py index 5c8638eb..9239eeb4 100644 --- a/runtime/datamate-python/app/module/annotation/interface/auto.py +++ b/runtime/datamate-python/app/module/annotation/interface/auto.py @@ -9,7 +9,7 @@ """ from __future__ import annotations -from typing import List, Optional, Dict +from typing import List, Optional, Dict, Any from fastapi import APIRouter, Depends, HTTPException, Path from fastapi.responses import StreamingResponse