Skip to content

Commit 0614157

Browse files
authored
fix: data collection create task page (#33)
* feat: Update site name to DataMate and refine text for AI data processing * feat: Refactor settings page and implement model access functionality - Created a new ModelAccess component for managing model configurations. - Removed the old Settings component and replaced it with a new SettingsPage component that integrates ModelAccess, SystemConfig, and WebhookConfig. - Added SystemConfig component for managing system settings. - Implemented WebhookConfig component for managing webhook configurations. - Updated API functions for model management in settings.apis.ts. - Adjusted routing to point to the new SettingsPage component. * feat: Implement Data Collection Page with Task Management and Execution Log - Created DataCollectionPage component to manage data collection tasks. - Added TaskManagement and ExecutionLog components for task handling and logging. - Integrated task operations including start, stop, edit, and delete functionalities. - Implemented filtering and searching capabilities in task management. - Introduced SimpleCronScheduler for scheduling tasks with cron expressions. - Updated CreateTask component to utilize new scheduling and template features. - Enhanced BasicInformation component to conditionally render fields based on visibility settings. - Refactored ImportConfiguration component to remove NAS import section. * feat: Update task creation API endpoint and enhance task creation form with new fields and validation
1 parent 3f484e9 commit 0614157

8 files changed

Lines changed: 213 additions & 135 deletions

File tree

frontend/src/mock/mock-apis.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const { addMockPrefix } = require("./mock-core/util.cjs");
33
const MockAPI = {
44
// 数据归集接口
55
queryTasksUsingGet: "/data-collection/tasks", // 获取数据源任务列表
6-
createTaskUsingPost: "/data-collection/tasks/create", // 创建数据源任务
6+
createTaskUsingPost: "/data-collection/tasks", // 创建数据源任务
77
queryTaskByIdUsingGet: "/data-collection/tasks/:id", // 根据ID获取数据源任务详情
88
updateTaskByIdUsingPut: "/data-collection/tasks/:id", // 更新数据源任务
99
queryDataXTemplatesUsingGet: "/data-collection/templates", // 获取DataX数据源模板列表

frontend/src/pages/DataCollection/Create/CreateTask.tsx

Lines changed: 110 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,14 @@ import { Link, useNavigate } from "react-router";
44
import { ArrowLeft } from "lucide-react";
55
import { createTaskUsingPost } from "../collection.apis";
66
import SimpleCronScheduler from "@/pages/DataCollection/Create/SimpleCronScheduler";
7+
import RadioCard from "@/components/RadioCard";
8+
import { datasetTypes } from "@/pages/DataManagement/dataset.const";
9+
import { SyncModeMap } from "../collection.const";
10+
import { SyncMode } from "../collection.model";
11+
import { DatasetSubType } from "@/pages/DataManagement/dataset.model";
712

813
const { TextArea } = Input;
914

10-
interface ScheduleConfig {
11-
type: "immediate" | "scheduled";
12-
scheduleType?: "day" | "week" | "month" | "custom";
13-
time?: string;
14-
dayOfWeek?: string;
15-
dayOfMonth?: string;
16-
cronExpression?: string;
17-
maxRetries?: number;
18-
}
19-
2015
const defaultTemplates = [
2116
{
2217
id: "nas",
@@ -47,6 +42,8 @@ const defaultTemplates = [
4742
},
4843
];
4944

45+
const syncModeOptions = Object.values(SyncModeMap);
46+
5047
enum TemplateType {
5148
NAS = "nas",
5249
OBS = "obs",
@@ -64,36 +61,40 @@ export default function CollectionTaskCreate() {
6461
const [selectedTemplate, setSelectedTemplate] = useState("nas");
6562
const [customConfig, setCustomConfig] = useState("");
6663

67-
const [scheduleConfig, setScheduleConfig] = useState<ScheduleConfig>({
68-
type: "immediate",
64+
const [newTask, setNewTask] = useState({
65+
name: "",
66+
description: "",
67+
syncMode: SyncMode.ONCE,
68+
cronExpression: "",
6969
maxRetries: 10,
70-
scheduleType: "daily",
70+
dataset: {},
71+
});
72+
const [scheduleExpression, setScheduleExpression] = useState({
73+
type: SyncMode.SCHEDULED,
74+
time: "00:00",
75+
cronExpression: "0 0 0 * * ?",
7176
});
7277

7378
const [isCreateDataset, setIsCreateDataset] = useState(false);
7479

7580
const handleSubmit = async () => {
76-
const formData = await form.validateFields();
77-
if (templateType === "default" && !selectedTemplate) {
78-
window.alert("请选择默认模板");
79-
return;
81+
try {
82+
const formData = await form.validateFields();
83+
if (templateType === "default" && !selectedTemplate) {
84+
window.alert("请选择默认模板");
85+
return;
86+
}
87+
if (templateType === "custom" && !customConfig.trim()) {
88+
window.alert("请填写自定义配置");
89+
return;
90+
}
91+
// Create task logic here
92+
await createTaskUsingPost(newTask);
93+
message.success("任务创建成功");
94+
navigate("/data/collection");
95+
} catch (error) {
96+
message.error(`${error?.data?.message}${error?.data?.data}`);
8097
}
81-
if (templateType === "custom" && !customConfig.trim()) {
82-
window.alert("请填写自定义配置");
83-
return;
84-
}
85-
// Create task logic here
86-
const params = {
87-
...formData,
88-
templateType,
89-
selectedTemplate: templateType === "default" ? selectedTemplate : null,
90-
customConfig: templateType === "custom" ? customConfig : null,
91-
scheduleConfig,
92-
};
93-
console.log("Creating task:", params);
94-
await createTaskUsingPost(params);
95-
message.success("任务创建成功");
96-
navigate("/data/collection");
9798
};
9899

99100
return (
@@ -114,17 +115,16 @@ export default function CollectionTaskCreate() {
114115
<Form
115116
form={form}
116117
layout="vertical"
117-
initialValues={scheduleConfig}
118+
initialValues={newTask}
118119
onValuesChange={(_, allValues) => {
119-
// 文件格式变化时重置模板选择
120-
if (_.fileFormat !== undefined) setSelectedTemplate("");
120+
setNewTask({ ...newTask, ...allValues });
121121
}}
122122
>
123123
{/* 基本信息 */}
124124
<h2 className="font-medium text-gray-900 text-lg mb-2">基本信息</h2>
125125

126126
<Form.Item
127-
label="任务名称"
127+
label="名称"
128128
name="name"
129129
rules={[{ required: true, message: "请输入任务名称" }]}
130130
>
@@ -138,32 +138,37 @@ export default function CollectionTaskCreate() {
138138
<h2 className="font-medium text-gray-900 pt-6 mb-2 text-lg">
139139
同步配置
140140
</h2>
141-
<Form.Item label="同步方式">
141+
<Form.Item name="syncMode" label="同步方式">
142142
<Radio.Group
143-
value={scheduleConfig.type}
144-
onChange={(e) =>
145-
setScheduleConfig({
146-
type: e.target.value as ScheduleConfig["type"],
147-
})
148-
}
149-
>
150-
<Radio value="immediate">立即同步</Radio>
151-
<Radio value="scheduled">定时同步</Radio>
152-
</Radio.Group>
143+
value={newTask.syncMode}
144+
options={syncModeOptions}
145+
onChange={(e) => {
146+
const value = e.target.value;
147+
setNewTask({
148+
...newTask,
149+
scheduleExpression:
150+
value === SyncMode.SCHEDULED
151+
? scheduleExpression.cronExpression
152+
: "",
153+
});
154+
}}
155+
></Radio.Group>
153156
</Form.Item>
154-
{scheduleConfig.type === "scheduled" && (
157+
{newTask.syncMode === SyncMode.SCHEDULED && (
155158
<Form.Item
156159
label=""
157-
name="cronExpression"
158160
rules={[{ required: true, message: "请输入Cron表达式" }]}
159161
>
160162
<SimpleCronScheduler
161163
className="px-2 rounded"
162-
value={scheduleConfig.cronExpression || "* * * * *"}
163-
showYear
164-
onChange={(value) =>
165-
setScheduleConfig({ ...scheduleConfig, cron: value })
166-
}
164+
value={scheduleExpression}
165+
onChange={(value) => {
166+
setScheduleExpression(value);
167+
setNewTask({
168+
...newTask,
169+
scheduleExpression: value.cronExpression,
170+
});
171+
}}
167172
/>
168173
</Form.Item>
169174
)}
@@ -213,29 +218,25 @@ export default function CollectionTaskCreate() {
213218
{selectedTemplate === TemplateType.NAS && (
214219
<div className="grid grid-cols-2 gap-3 px-2 rounded">
215220
<Form.Item
216-
name="nasPath"
221+
name={["config", "ip"]}
217222
rules={[{ required: true, message: "请输入NAS地址" }]}
218223
label="NAS地址"
219224
>
220225
<Input placeholder="192.168.1.100" />
221226
</Form.Item>
222227
<Form.Item
223-
name="sharePath"
228+
name={["config", "path"]}
224229
rules={[{ required: true, message: "请输入共享路径" }]}
225230
label="共享路径"
226231
>
227232
<Input placeholder="/share/importConfig" />
228233
</Form.Item>
229234
<Form.Item
230-
name="fileList"
235+
name={["config", "files"]}
231236
label="文件列表"
232237
className="col-span-2"
233238
>
234-
<Select
235-
placeholder="请选择文件列表"
236-
mode="tags"
237-
multiple
238-
/>
239+
<Select placeholder="请选择文件列表" mode="tags" />
239240
</Form.Item>
240241
</div>
241242
)}
@@ -309,7 +310,19 @@ export default function CollectionTaskCreate() {
309310
>
310311
<Radio.Group
311312
value={isCreateDataset}
312-
onChange={(e) => setIsCreateDataset(e.target.value)}
313+
onChange={(e) => {
314+
const value = e.target.value;
315+
if (value === false) {
316+
form.setFieldsValue({
317+
dataset: {},
318+
});
319+
setNewTask({
320+
...newTask,
321+
dataset: {},
322+
});
323+
}
324+
setIsCreateDataset(e.target.value);
325+
}}
313326
>
314327
<Radio value={true}></Radio>
315328
<Radio value={false}></Radio>
@@ -319,10 +332,40 @@ export default function CollectionTaskCreate() {
319332
<>
320333
<Form.Item
321334
label="数据集名称"
322-
name="datasetName"
323-
rules={[{ required: true, message: "请输入数据集名称" }]}
335+
name={["dataset", "name"]}
336+
required
324337
>
325-
<Input placeholder="请输入数据集名称" />
338+
<Input
339+
placeholder="输入数据集名称"
340+
onChange={(e) => {
341+
setNewTask({
342+
...newTask,
343+
dataset: {
344+
...newTask.dataset,
345+
name: e.target.value,
346+
},
347+
});
348+
}}
349+
/>
350+
</Form.Item>
351+
<Form.Item
352+
label="数据集类型"
353+
name={["dataset", "datasetType"]}
354+
rules={[{ required: true, message: "请选择数据集类型" }]}
355+
>
356+
<RadioCard
357+
options={datasetTypes}
358+
value={newTask.dataset.datasetType}
359+
onChange={(type) => {
360+
form.setFieldValue(["dataset", "datasetType"], type);
361+
setNewTask({
362+
...newTask,
363+
dataset: {
364+
datasetType: type as DatasetSubType,
365+
},
366+
});
367+
}}
368+
/>
326369
</Form.Item>
327370
</>
328371
)}

frontend/src/pages/DataCollection/Create/SimpleCronScheduler.tsx

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,42 @@ const SimpleCronScheduler: React.FC<SimpleCronSchedulerProps> = ({
130130
return (
131131
<Space direction="vertical" className={`w-full ${className || ""}`}>
132132
{/* 执行周期选择 */}
133-
<Form.Item label="执行周期" required>
134-
<Select value={config.type} onChange={handleTypeChange}>
135-
<Select.Option value="once">仅执行一次</Select.Option>
136-
<Select.Option value="daily">每天执行</Select.Option>
137-
<Select.Option value="weekly">每周执行</Select.Option>
138-
<Select.Option value="monthly">每月执行</Select.Option>
139-
</Select>
140-
</Form.Item>
133+
<div className="grid grid-cols-2 gap-4">
134+
<Form.Item label="执行周期" required>
135+
<Select value={config.type} onChange={handleTypeChange}>
136+
<Select.Option value="once">仅执行一次</Select.Option>
137+
<Select.Option value="daily">每天执行</Select.Option>
138+
<Select.Option value="weekly">每周执行</Select.Option>
139+
<Select.Option value="monthly">每月执行</Select.Option>
140+
</Select>
141+
</Form.Item>
142+
143+
{/* 周几选择 */}
144+
{config.type === "weekly" && (
145+
<Form.Item label="执行日期" required>
146+
<Select
147+
className="w-32"
148+
value={config.weekDay}
149+
onChange={(weekDay) => updateConfig({ weekDay })}
150+
placeholder="选择周几"
151+
options={weekDayOptions}
152+
></Select>
153+
</Form.Item>
154+
)}
155+
156+
{/* 月份日期选择 */}
157+
{config.type === "monthly" && (
158+
<Form.Item label="执行日期" required>
159+
<Select
160+
className="w-32"
161+
value={config.monthDay}
162+
onChange={(monthDay) => updateConfig({ monthDay })}
163+
placeholder="选择日期"
164+
options={monthDayOptions}
165+
></Select>
166+
</Form.Item>
167+
)}
168+
</div>
141169

142170
{/* 时间选择 */}
143171
<Form.Item label="执行时间" required>
@@ -165,32 +193,6 @@ const SimpleCronScheduler: React.FC<SimpleCronSchedulerProps> = ({
165193
</Space>
166194
</Form.Item>
167195

168-
{/* 周几选择 */}
169-
{config.type === "weekly" && (
170-
<Form.Item label="执行日期" required>
171-
<Select
172-
className="w-32"
173-
value={config.weekDay}
174-
onChange={(weekDay) => updateConfig({ weekDay })}
175-
placeholder="选择周几"
176-
options={weekDayOptions}
177-
></Select>
178-
</Form.Item>
179-
)}
180-
181-
{/* 月份日期选择 */}
182-
{config.type === "monthly" && (
183-
<Form.Item label="执行日期" required>
184-
<Select
185-
className="w-32"
186-
value={config.monthDay}
187-
onChange={(monthDay) => updateConfig({ monthDay })}
188-
placeholder="选择日期"
189-
options={monthDayOptions}
190-
></Select>
191-
</Form.Item>
192-
)}
193-
194196
{/* Cron 表达式预览 */}
195197
{/* <div className="mt-4 pt-4 border-t border-gray-200">
196198
<Text>生成的 Cron 表达式</Text>

frontend/src/pages/DataCollection/Home/DataCollectionPage.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,11 @@ import { PlusOutlined } from "@ant-design/icons";
44
import TaskManagement from "./TaskManagement";
55
import ExecutionLog from "./ExecutionLog";
66
import { useNavigate } from "react-router";
7-
import DevelopmentInProgress from "@/components/DevelopmentInProgress";
87

98
export default function DataCollection() {
109
const navigate = useNavigate();
1110
const [activeTab, setActiveTab] = useState("task-management");
1211

13-
// return <DevelopmentInProgress showTime="2025.10.30" />;
14-
1512
return (
1613
<div className="gap-4 h-full flex flex-col">
1714
<div className="flex justify-between items-end">
@@ -32,7 +29,7 @@ export default function DataCollection() {
3229
activeKey={activeTab}
3330
items={[
3431
{ label: "任务管理", key: "task-management" },
35-
{ label: "执行日志", key: "execution-log" },
32+
// { label: "执行日志", key: "execution-log" },
3633
]}
3734
onChange={(tab) => {
3835
setActiveTab(tab);

0 commit comments

Comments
 (0)