Skip to content

Commit 478b0a1

Browse files
committed
Merge remote-tracking branch 'origin/develop_930' into develop_930
2 parents a345d49 + c9d34bc commit 478b0a1

File tree

29 files changed

+1213
-1088
lines changed

29 files changed

+1213
-1088
lines changed

frontend/src/components/CardView.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ interface CardViewProps<T> {
3232
pageSize: number;
3333
total: number;
3434
};
35-
operations: {
36-
key: string;
37-
label: string;
38-
icon?: React.JSX.Element;
39-
onClick?: (item: T) => void;
40-
}[];
35+
operations:
36+
| {
37+
key: string;
38+
label: string;
39+
icon?: React.JSX.Element;
40+
onClick?: (item: T) => void;
41+
}[]
42+
| ((item: T) => ItemType[]);
4143
onView: (item: T) => void;
4244
onFavorite?: (item: T) => void;
4345
isFavorite?: (item: T) => boolean;
@@ -55,6 +57,9 @@ function CardView<T extends BaseCardDataType>(props: CardViewProps<T>) {
5557
);
5658
}
5759

60+
const ops = (item) =>
61+
typeof operations === "function" ? operations(item) : operations;
62+
5863
return (
5964
<div className="flex-1 overflow-auto">
6065
<div className="grid md:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4">
@@ -133,9 +138,9 @@ function CardView<T extends BaseCardDataType>(props: CardViewProps<T>) {
133138
<Dropdown
134139
trigger={["click"]}
135140
menu={{
136-
items: operations as ItemType[],
141+
items: ops(item),
137142
onClick: ({ key }) => {
138-
const operation = operations.find((op) => op.key === key);
143+
const operation = ops(item).find((op) => op.key === key);
139144
if (operation?.onClick) {
140145
operation.onClick(item);
141146
}

frontend/src/mock/mock-apis.cjs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,20 @@ const MockAPI = {
3232
// 数据清洗接口
3333
queryCleaningRulesUsingGet: "/v1/cleaning/rules", // 获取清洗规则列表
3434
createCleaningRuleUsingPost: "/v1/cleaning/rules", //创建清洗规则
35-
queryCleaningRuleByIdUsingGet: "/v1/cleaning/rules/{ruleId}", // 根据ID获取清洗规则详情
36-
updateCleaningRuleByIdUsingPut: "/v1/cleaning/rules/{ruleId}", // 更新清洗规则
37-
deleteCleaningRuleByIdUsingDelete: "/v1/cleaning/rules/{ruleId}", // 删除清洗规则
35+
queryCleaningRuleByIdUsingGet: "/v1/cleaning/rules/:ruleId", // 根据ID获取清洗规则详情
36+
updateCleaningRuleByIdUsingPut: "/v1/cleaning/rules/:ruleId", // 更新清洗规则
37+
deleteCleaningRuleByIdUsingDelete: "/v1/cleaning/rules/:ruleId", // 删除清洗规则
3838
queryCleaningJobsUsingPost: "/v1/cleaning/jobs", // 获取清洗任务列表
3939
createCleaningJobUsingPost: "/v1/cleaning/jobs/create", // 创建清洗任务
40-
queryCleaningJobByIdUsingGet: "/v1/cleaning/jobs/{jobId}", // 根据ID获取清洗任务详情
41-
deleteCleaningJobByIdUsingDelete: "/v1/cleaning/jobs/{jobId}", // 删除清洗任务
42-
executeCleaningJobUsingPost: "/v1/cleaning/jobs/{jobId}/execute", // 执行清洗任务
43-
stopCleaningJobUsingPost: "/v1/cleaning/jobs/{jobId}/stop", // 停止清洗任务
40+
queryCleaningJobByIdUsingGet: "/v1/cleaning/jobs/:jobId", // 根据ID获取清洗任务详情
41+
deleteCleaningJobByIdUsingDelete: "/v1/cleaning/jobs/:jobId", // 删除清洗任务
42+
executeCleaningJobUsingPost: "/v1/cleaning/jobs/:jobId/execute", // 执行清洗任务
43+
stopCleaningJobUsingPost: "/v1/cleaning/jobs/:jobId/stop", // 停止清洗任务
4444
queryCleaningTemplatesUsingPost: "/v1/cleaning/templates", // 获取清洗模板列表
4545
createCleaningTemplateUsingPost: "/v1/cleaning/templates/create", // 创建清洗模板
46-
queryCleaningTemplateByIdUsingGet: "/v1/cleaning/templates/{templateId}", // 根据ID获取清洗模板详情
46+
queryCleaningTemplateByIdUsingGet: "/v1/cleaning/templates/:templateId", // 根据ID获取清洗模板详情
4747
deleteCleaningTemplateByIdUsingDelete:
48-
"/v1/cleaning/templates/{templateId}", // 删除清洗模板
48+
"/v1/cleaning/templates/:templateId", // 删除清洗模板
4949
};
5050

5151
module.exports = addMockPrefix("/api", MockAPI);
File renamed without changes.

frontend/src/pages/DataCleansing/CreateTempate.tsx renamed to frontend/src/pages/DataCleansing/Create/CreateTempate.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { templateTypes, OPERATOR_CATEGORIES } from "@/mock/cleansing";
1212
import {
1313
createCleaningTemplateUsingPost,
1414
queryCleaningTemplatesUsingPost,
15-
} from "./cleansing-apis";
15+
} from "../cleansing-apis";
1616

1717
const { TextArea } = Input;
1818

frontend/src/pages/DataCleansing/components/FileComparison.tsx renamed to frontend/src/pages/DataCleansing/Create/components/FileComparison.tsx

File renamed without changes.

frontend/src/pages/DataCleansing/components/OperatorConfig.tsx renamed to frontend/src/pages/DataCleansing/Create/components/OperatorConfig.tsx

File renamed without changes.

frontend/src/pages/DataCleansing/components/OperatorLibrary.tsx renamed to frontend/src/pages/DataCleansing/Create/components/OperatorLibrary.tsx

File renamed without changes.

frontend/src/pages/DataCleansing/components/OperatorOrchestration.tsx renamed to frontend/src/pages/DataCleansing/Create/components/OperatorOrchestration.tsx

File renamed without changes.

frontend/src/pages/DataCleansing/components/ParamConfig.tsx renamed to frontend/src/pages/DataCleansing/Create/components/ParamConfig.tsx

File renamed without changes.
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import { useEffect, useState } from "react";
2+
import { Card, Breadcrumb, App } from "antd";
3+
import {
4+
Play,
5+
Pause,
6+
Clock,
7+
CheckCircle,
8+
AlertCircle,
9+
Database,
10+
Trash2,
11+
Download,
12+
Activity,
13+
} from "lucide-react";
14+
import DetailHeader from "@/components/DetailHeader";
15+
import { Link, useNavigate, useParams } from "react-router";
16+
import { deleteCleaningJobByIdUsingDelete, executeCleaningJobUsingPost, queryCleaningJobByIdUsingGet, stopCleaningJobUsingPost } from "../cleansing-apis";
17+
import { TaskStatusMap } from "../cleansing-model";
18+
import { JobStatus } from "@/types/cleansing";
19+
import BasicInfo from "./components/BasicInfo";
20+
import OperatorTable from "./components/OperatorTable";
21+
import FileTable from "./components/FileTable";
22+
import LogsTable from "./components/LogsTable";
23+
24+
// 任务详情页面组件
25+
export default function CleansingTaskDetail() {
26+
const { id } = useParams(); // 获取动态路由参数
27+
const { message } = App.useApp();
28+
const navigate = useNavigate();
29+
30+
const fetchTaskDetail = async () => {
31+
if (!id) return;
32+
try {
33+
const { data } = await queryCleaningJobByIdUsingGet(id);
34+
setTask(data);
35+
} catch (error) {
36+
message.error("获取任务详情失败");
37+
navigate("/data/cleansing");
38+
}
39+
};
40+
41+
const pauseTask = async () => {
42+
await stopCleaningJobUsingPost(id);
43+
message.success("任务已暂停");
44+
fetchTaskDetail();
45+
};
46+
47+
const startTask = async () => {
48+
await executeCleaningJobUsingPost(id);
49+
message.success("任务已启动");
50+
fetchTaskDetail();
51+
};
52+
53+
const deleteTask = async () => {
54+
await deleteCleaningJobByIdUsingDelete(id);
55+
message.success("任务已删除");
56+
navigate("/data/cleansing");
57+
};
58+
59+
useEffect(() => {
60+
fetchTaskDetail();
61+
}, [id]);
62+
63+
const [task, setTask] = useState(null);
64+
const [activeTab, setActiveTab] = useState("basic");
65+
66+
const headerData = {
67+
...task,
68+
icon: <Database className="w-8 h-8" />,
69+
status: TaskStatusMap[task?.status],
70+
createdAt: task?.startTime,
71+
lastUpdated: task?.updatedAt,
72+
};
73+
74+
const statistics = [
75+
{
76+
icon: <Clock className="w-4 h-4 text-blue-500" />,
77+
label: "总耗时",
78+
value: task?.duration || "--",
79+
},
80+
{
81+
icon: <CheckCircle className="w-4 h-4 text-green-500" />,
82+
label: "成功文件",
83+
value: task?.successFiles || "--",
84+
},
85+
{
86+
icon: <AlertCircle className="w-4 h-4 text-red-500" />,
87+
label: "失败文件",
88+
value: task?.failedFiles || "--",
89+
},
90+
{
91+
icon: <Activity className="w-4 h-4 text-purple-500" />,
92+
label: "成功率",
93+
value: `${task?.progress}%`,
94+
},
95+
];
96+
97+
const operations = [
98+
...(task?.status === JobStatus.RUNNING
99+
? [
100+
{
101+
key: "pause",
102+
label: "暂停任务",
103+
icon: <Pause className="w-4 h-4" />,
104+
onClick: pauseTask,
105+
},
106+
]
107+
: []),
108+
...(task?.status === JobStatus.PENDING
109+
? [
110+
{
111+
key: "start",
112+
label: "执行任务",
113+
icon: <Play className="w-4 h-4" />,
114+
onClick: startTask,
115+
},
116+
]
117+
: []),
118+
{
119+
key: "delete",
120+
label: "删除任务",
121+
icon: <Trash2 className="w-4 h-4" />,
122+
danger: true,
123+
onClick: deleteTask,
124+
},
125+
];
126+
127+
const tabList = [
128+
{
129+
key: "basic",
130+
tab: "基本信息",
131+
children: <BasicInfo task={task} />,
132+
},
133+
{
134+
key: "operators",
135+
tab: "处理算子",
136+
children: <OperatorTable task={task} />,
137+
},
138+
{
139+
key: "files",
140+
tab: "处理文件",
141+
children: <FileTable task={task} />,
142+
},
143+
{ key: "logs", tab: "运行日志", children: <LogsTable task={task} /> },
144+
];
145+
146+
const breadItems = [
147+
{
148+
title: <Link to="/data/cleansing">数据清洗</Link>,
149+
},
150+
{
151+
title: "清洗任务详情",
152+
},
153+
];
154+
155+
return (
156+
<div className="min-h-screen">
157+
<Breadcrumb items={breadItems} />
158+
<div className="mb-4 mt-4">
159+
<DetailHeader
160+
data={headerData}
161+
statistics={statistics}
162+
operations={operations}
163+
/>
164+
</div>
165+
<Card
166+
tabList={tabList}
167+
activeTabKey={activeTab}
168+
onTabChange={setActiveTab}
169+
></Card>
170+
</div>
171+
);
172+
}

0 commit comments

Comments
 (0)