Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 100 additions & 13 deletions frontend/src/pages/DataManagement/Detail/components/Overview.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -13,6 +13,9 @@ export default function Overview({ dataset, filesOperation, fetchDataset }) {
previewVisible,
previewFileName,
previewContent,
previewUrl,
previewFileDetail,
previewLoading,
setPreviewVisible,
handleDeleteFile,
handleDownloadFile,
Expand All @@ -23,6 +26,7 @@ export default function Overview({ dataset, filesOperation, fetchDataset }) {
handleDeleteDirectory,
handleRenameFile,
handleRenameDirectory,
handlePreviewFile,
} = filesOperation;

// 文件列表多选配置
Expand Down Expand Up @@ -142,7 +146,7 @@ export default function Overview({ dataset, filesOperation, fetchDataset }) {
return (
<Button
type="link"
onClick={(e) => {}}
onClick={() => handlePreviewFile(record)}
>
{content}
</Button>
Expand Down Expand Up @@ -453,18 +457,101 @@ export default function Overview({ dataset, filesOperation, fetchDataset }) {
open={previewVisible}
onCancel={() => setPreviewVisible(false)}
footer={null}
width={700}
width={1000}
>
<pre
style={{
whiteSpace: "pre-wrap",
wordBreak: "break-all",
fontSize: 14,
color: "#222",
}}
>
{previewContent}
</pre>
<div className="flex gap-4" style={{ minHeight: 400 }}>
{/* 左侧预览区域 */}
<div className="flex-1 border border-gray-200 rounded-md p-3 flex items-center justify-center overflow-auto bg-gray-50">
{previewLoading ? (
<Spin />
) : previewUrl ? (
<img
src={previewUrl}
alt={previewFileName}
style={{
maxWidth: "100%",
maxHeight: 500,
objectFit: "contain",
}}
/>
) : previewContent ? (
<pre
style={{
whiteSpace: "pre-wrap",
wordBreak: "break-all",
fontSize: 14,
color: "#222",
maxHeight: 500,
}}
>
{previewContent}
</pre>
) : (
<span className="text-gray-500 text-sm">
暂无预览内容,或当前文件类型暂不支持预览。
</span>
)}
</div>

{/* 右侧文件信息(来自 t_dm_dataset_files) */}
<div className="w-72 border border-gray-200 rounded-md p-3 bg-white overflow-auto">
<h3 className="text-sm font-semibold mb-3">文件信息</h3>
<div className="space-y-2 text-xs text-gray-700">
<div>
<span className="text-gray-500">文件名:</span>
<span>{previewFileDetail?.fileName || previewFileName}</span>
</div>
{previewFileDetail?.originalName && (
<div>
<span className="text-gray-500">原始文件名:</span>
<span>{previewFileDetail.originalName}</span>
</div>
)}
{previewFileDetail?.fileType && (
<div>
<span className="text-gray-500">文件类型:</span>
<span>{previewFileDetail.fileType}</span>
</div>
)}
{typeof previewFileDetail?.fileSize === "number" && (
<div>
<span className="text-gray-500">文件大小:</span>
<span>{formatBytes(previewFileDetail.fileSize || 0)}</span>
</div>
)}
{previewFileDetail?.status && (
<div>
<span className="text-gray-500">状态:</span>
<span>{previewFileDetail.status}</span>
</div>
)}
{previewFileDetail?.uploadTime && (
<div>
<span className="text-gray-500">上传时间:</span>
<span>{formatDateTime(previewFileDetail.uploadTime)}</span>
</div>
)}
{previewFileDetail?.uploadedBy && (
<div>
<span className="text-gray-500">上传者:</span>
<span>{previewFileDetail.uploadedBy}</span>
</div>
)}
{previewFileDetail?.filePath && (
<div>
<span className="text-gray-500">文件路径:</span>
<span>{previewFileDetail.filePath}</span>
</div>
)}
{previewFileDetail?.description && (
<div>
<span className="text-gray-500">描述:</span>
<span>{previewFileDetail.description}</span>
</div>
)}
</div>
</div>
</div>
</Modal>
</>
);
Expand Down
55 changes: 46 additions & 9 deletions frontend/src/pages/DataManagement/Detail/useFilesOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string | undefined>();
const [previewFileDetail, setPreviewFileDetail] = useState<any | undefined>();
const [previewLoading, setPreviewLoading] = useState(false);

const fetchFiles = async (prefix?: string, current?, pageSize?) => {
// 如果明确传了 prefix(包括空字符串),使用传入的值;否则使用当前 pagination.prefix
Expand Down Expand Up @@ -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);
}
};

Expand Down Expand Up @@ -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) => {
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/pages/DataManagement/dataset.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading