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 ? (
+

+ ) : 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