Skip to content

Commit 100e4c1

Browse files
committed
frontend: 新增数据集分片上传功能,未启用
1 parent c59d3e5 commit 100e4c1

File tree

10 files changed

+708
-63
lines changed

10 files changed

+708
-63
lines changed

frontend/package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"dependencies": {
1414
"@xyflow/react": "^12.8.3",
1515
"antd": "^5.27.0",
16+
"jssha": "^3.3.1",
1617
"lucide-react": "^0.539.0",
1718
"react": "^18.1.1",
1819
"react-dom": "^18.1.1",

frontend/src/mock/mock-apis.cjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ const MockAPI = {
3131
updateTagUsingPost: "/data-management/tags", // 更新数据集标签
3232
deleteTagUsingPost: "/data-management/tags", // 删除数据集标签
3333
queryDatasetStatisticsUsingGet: "/data-management/datasets/statistics", // 获取数据集统计信息
34+
preUploadFileUsingPost:
35+
"/data-management/datasets/:id/upload/pre-upload", // 预上传文件
36+
cancelUploadUsingPut: "/data-management/datasets/upload/cancel-upload/:id", // 取消上传
37+
uploadFileChunkUsingPost: "/data-management/datasets/:id/upload/chunk", // 上传切片
3438

3539
// 数据清洗接口
3640
queryCleaningTasksUsingGet: "/cleaning/tasks", // 获取清洗任务列表

frontend/src/mock/mock-seed/data-management.cjs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,4 +426,19 @@ module.exports = function (router) {
426426
data: newTag,
427427
});
428428
});
429+
430+
router.post(API.preUploadFileUsingPost, (req, res) => {
431+
res.status(201).send(Mock.Random.guid());
432+
});
433+
434+
// 上传
435+
router.post(API.uploadFileChunkUsingPost, (req, res) => {
436+
res.status(500).send({ message: "Simulated upload failure" });
437+
// res.status(201).send({ data: "success" });
438+
});
439+
440+
// 取消上传
441+
router.put(API.cancelUploadUsingPut, (req, res) => {
442+
res.status(201).send({ data: "success" });
443+
});
429444
};

frontend/src/pages/DataManagement/dataset.api.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { get, post, put, del, download } from "@/utils/request";
1+
import { get, post, put, del, download, upload } from "@/utils/request";
22

33
// 数据集统计接口
44
export function getDatasetStatisticsUsingGet() {
@@ -104,7 +104,7 @@ export function updateDatasetTagByIdUsingPut(id: string | number, data: any) {
104104
// 删除数据集标签
105105
export function deleteDatasetTagByIdUsingDelete(tag) {
106106
console.log(tag);
107-
107+
108108
return del(`/api/data-management/tags/${tag.id}`);
109109
}
110110

@@ -168,3 +168,34 @@ export function deleteDatasetVersionUsingDelete(
168168
) {
169169
return del(`/api/data-management/datasets/${id}/versions/${versionId}`);
170170
}
171+
172+
/**
173+
* 文件上传相关接口
174+
*/
175+
176+
export function preUploadUsingPost(id: string | number, data: any) {
177+
console.log('pre upload');
178+
179+
return post(`/api/data-management/datasets/${id}/upload/pre-upload`, data);
180+
}
181+
182+
export function cancelUploadUsingPut(id) {
183+
return put(
184+
`/api/data-management/datasets/upload/cancel-upload/${id}`,
185+
{},
186+
{ showLoading: false }
187+
);
188+
}
189+
190+
export function uploadFileChunkUsingPost(id: string | number, params, config) {
191+
console.log('upload chunk');
192+
return upload(`/api/data-management/datasets/${id}/upload/chunk`, params, {
193+
headers: {
194+
accept: "*/*",
195+
"Content-Type": "multipart/form-data;charset=UTF-8",
196+
},
197+
showLoading: false,
198+
isUploading: true,
199+
...config,
200+
});
201+
}

frontend/src/pages/DataManagement/dataset.model.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,13 @@ export interface DatasetTask {
105105
lastExecution?: string;
106106
executionHistory?: { time: string; status: string }[];
107107
}
108+
109+
export interface TaskItem {
110+
key: string;
111+
title: string;
112+
percent: number;
113+
reqId: number;
114+
isCancel?: boolean;
115+
controller: AbortController;
116+
cancelFn?: () => void;
117+
}

frontend/src/pages/Layout/Sidebar.tsx

Lines changed: 108 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,74 @@ import { Button, Menu } from "antd";
33
import {
44
CloseOutlined,
55
MenuOutlined,
6-
OrderedListOutlined,
76
SettingOutlined,
87
} from "@ant-design/icons";
9-
import { Sparkles, X, Menu as MenuIcon } from "lucide-react";
8+
import { ClipboardList, Sparkles } from "lucide-react";
109
import { antMenuItems, antMenuItems as items } from "@/pages/Layout/menu";
11-
import TaskPopover from "../../components/TaskPopover";
1210
import { NavLink, useLocation, useNavigate } from "react-router";
11+
import TaskUpload from "./TaskUpload";
12+
13+
const TaskUploadPopover = ({ sidebarOpen, toggleShowTaskPopover }) => {
14+
const arrowStyle = sidebarOpen ? {} : { top: "calc(100% - 68px)" };
15+
const popoverStyle = sidebarOpen
16+
? {
17+
bottom: "48px",
18+
left: "0px",
19+
}
20+
: {
21+
bottom: "-48px",
22+
left: "68px",
23+
};
24+
25+
return (
26+
<div
27+
id="header-task-popover"
28+
className={`absolute left-full w-md transition-all duration-300 ease-in-out z-50 opacity-0 invisible transform -translate-x-4`}
29+
style={popoverStyle}
30+
>
31+
{/* 箭头 - 指向按钮中心 */}
32+
{/* <div
33+
className="absolute -left-2 w-0 h-0 transform -translate-y-1/2"
34+
style={{
35+
borderTop: "8px solid transparent",
36+
borderBottom: "8px solid transparent",
37+
borderRight: "8px solid #e5e7eb",
38+
...arrowStyle,
39+
}}
40+
/>
41+
<div
42+
className="absolute -left-1.5 top-1/2 w-0 h-0 transform -translate-y-1/2"
43+
style={{
44+
borderTop: "8px solid transparent",
45+
borderBottom: "8px solid transparent",
46+
borderRight: "8px solid white",
47+
...arrowStyle,
48+
}}
49+
/> */}
50+
<div className="bg-white rounded-lg shadow-lg border border-gray-200 min-w-80">
51+
<div className="flex justify-between items-center p-3 border-b border-gray-100">
52+
<span className="text-sm font-medium text-gray-900">任务中心</span>
53+
<Button
54+
type="text"
55+
size="small"
56+
icon={<CloseOutlined />}
57+
onClick={() => toggleShowTaskPopover(false)}
58+
/>
59+
</div>
60+
<div className="p-0 h-[250px] overflow-y-auto">
61+
<TaskUpload />
62+
</div>
63+
</div>
64+
</div>
65+
);
66+
};
1367

1468
const AsiderAndHeaderLayout = () => {
1569
const { pathname } = useLocation();
1670
const navigate = useNavigate();
1771
const [activeItem, setActiveItem] = useState<string>("management");
1872
const [sidebarOpen, setSidebarOpen] = useState(true);
73+
const [taskCenterVisible, setTaskCenterVisible] = useState(false);
1974

2075
// Initialize active item based on current pathname
2176
const initActiveItem = () => {
@@ -39,11 +94,22 @@ const AsiderAndHeaderLayout = () => {
3994
initActiveItem();
4095
}, [pathname]);
4196

97+
const toggleShowTaskPopover = (show: boolean = true) => {
98+
const taskEl = document.getElementById("header-task-popover");
99+
if (show && !taskEl?.classList.contains("show-task-popover")) {
100+
taskEl?.classList?.add("show-task-popover");
101+
return;
102+
}
103+
if (!show && taskEl?.classList.contains("show-task-popover")) {
104+
taskEl?.classList?.remove("show-task-popover");
105+
}
106+
};
107+
42108
return (
43109
<div
44110
className={`${
45111
sidebarOpen ? "w-64" : "w-20"
46-
} bg-white border-r border-gray-200 transition-all duration-300 flex flex-col`}
112+
} bg-white border-r border-gray-200 transition-all duration-300 flex flex-col relative`}
47113
>
48114
{/* Header */}
49115
<div className="flex items-center justify-between p-4 border-b border-gray-200">
@@ -55,12 +121,11 @@ const AsiderAndHeaderLayout = () => {
55121
<span className="text-lg font-bold text-gray-900">ModelEngine</span>
56122
</NavLink>
57123
)}
58-
<span className="cursor-pointer hover:text-blue-500" onClick={() => setSidebarOpen(!sidebarOpen)}>
59-
{sidebarOpen ? (
60-
<CloseOutlined />
61-
) : (
62-
<MenuOutlined className="ml-4" />
63-
)}
124+
<span
125+
className="cursor-pointer hover:text-blue-500"
126+
onClick={() => setSidebarOpen(!sidebarOpen)}
127+
>
128+
{sidebarOpen ? <CloseOutlined /> : <MenuOutlined className="ml-4" />}
64129
</span>
65130
</div>
66131

@@ -84,22 +149,51 @@ const AsiderAndHeaderLayout = () => {
84149
<div className="p-4 border-t border-gray-200">
85150
{sidebarOpen ? (
86151
<div className="space-y-2">
87-
{/* <TaskPopover /> */}
152+
<div className="relative">
153+
<Button block onClick={() => toggleShowTaskPopover(true)}>
154+
任务中心
155+
</Button>
156+
<TaskUploadPopover
157+
sidebarOpen={sidebarOpen}
158+
toggleShowTaskPopover={toggleShowTaskPopover}
159+
/>
160+
</div>
88161
<Button block onClick={() => navigate("/data/settings")}>
89162
设置
90163
</Button>
91164
</div>
92165
) : (
93166
<div className="space-y-2">
94-
<Button block>
95-
<OrderedListOutlined />
96-
</Button>
167+
<div className="relative">
168+
<Button
169+
block
170+
onClick={() => toggleShowTaskPopover(true)}
171+
icon={<ClipboardList className="w-4 h-4" />}
172+
></Button>
173+
<TaskUploadPopover
174+
sidebarOpen={sidebarOpen}
175+
toggleShowTaskPopover={toggleShowTaskPopover}
176+
/>
177+
</div>
97178
<Button block onClick={() => navigate("/data/settings")}>
98179
<SettingOutlined />
99180
</Button>
100181
</div>
101182
)}
102183
</div>
184+
185+
{/* 添加遮罩层,点击外部区域时关闭 */}
186+
{taskCenterVisible && (
187+
<div
188+
className="fixed inset-0 z-40"
189+
onClick={() => {
190+
console.log('clicked outside');
191+
192+
setTaskCenterVisible(false);
193+
toggleShowTaskPopover(false);
194+
}}
195+
/>
196+
)}
103197
</div>
104198
);
105199
};

0 commit comments

Comments
 (0)