数据归集
diff --git a/frontend/src/pages/DataCollection/Home/components/ExecutionLog.tsx b/frontend/src/pages/DataCollection/Home/ExecutionLog.tsx
similarity index 96%
rename from frontend/src/pages/DataCollection/Home/components/ExecutionLog.tsx
rename to frontend/src/pages/DataCollection/Home/ExecutionLog.tsx
index b89e13067..6e2a58589 100644
--- a/frontend/src/pages/DataCollection/Home/components/ExecutionLog.tsx
+++ b/frontend/src/pages/DataCollection/Home/ExecutionLog.tsx
@@ -2,8 +2,8 @@ import { Card, Badge, Table } from "antd";
import type { ColumnsType } from "antd/es/table";
import { SearchControls } from "@/components/SearchControls";
import type { CollectionLog } from "@/pages/DataCollection/collection.model";
-import { queryExecutionLogUsingPost } from "../../collection.apis";
-import { LogStatusMap, LogTriggerTypeMap } from "../../collection.const";
+import { queryExecutionLogUsingPost } from "../collection.apis";
+import { LogStatusMap, LogTriggerTypeMap } from "../collection.const";
import useFetchData from "@/hooks/useFetchData";
const filterOptions = [
diff --git a/frontend/src/pages/DataCollection/Home/components/TaskManagement.tsx b/frontend/src/pages/DataCollection/Home/TaskManagement.tsx
similarity index 52%
rename from frontend/src/pages/DataCollection/Home/components/TaskManagement.tsx
rename to frontend/src/pages/DataCollection/Home/TaskManagement.tsx
index 9678ef082..5bc6169ae 100644
--- a/frontend/src/pages/DataCollection/Home/components/TaskManagement.tsx
+++ b/frontend/src/pages/DataCollection/Home/TaskManagement.tsx
@@ -1,16 +1,34 @@
-import { Card, Button, Badge, Table, Dropdown, App } from "antd";
-import { EllipsisOutlined } from "@ant-design/icons";
+import {
+ Card,
+ Button,
+ Badge,
+ Table,
+ Dropdown,
+ App,
+ Tooltip,
+ Popconfirm,
+} from "antd";
+import {
+ DeleteOutlined,
+ EditOutlined,
+ EllipsisOutlined,
+ PauseCircleOutlined,
+ PauseOutlined,
+ PlayCircleOutlined,
+ StopOutlined,
+} from "@ant-design/icons";
import { SearchControls } from "@/components/SearchControls";
import {
deleteTaskByIdUsingDelete,
executeTaskByIdUsingPost,
queryTasksUsingGet,
stopTaskByIdUsingPost,
-} from "../../collection.apis";
-import { TaskStatus, type CollectionTask } from "../../collection.model";
-import { StatusMap, SyncModeMap } from "../../collection.const";
+} from "../collection.apis";
+import { TaskStatus, type CollectionTask } from "../collection.model";
+import { StatusMap, SyncModeMap } from "../collection.const";
import useFetchData from "@/hooks/useFetchData";
import { useNavigate } from "react-router";
+import { mapCollectionTask } from "../collection.const";
export default function TaskManagement() {
const { message } = App.useApp();
@@ -34,7 +52,7 @@ export default function TaskManagement() {
setSearchParams,
fetchData,
handleFiltersChange,
- } = useFetchData(queryTasksUsingGet);
+ } = useFetchData(queryTasksUsingGet, mapCollectionTask);
const handleStartTask = async (taskId: string) => {
await executeTaskByIdUsingPost(taskId);
@@ -54,35 +72,61 @@ export default function TaskManagement() {
fetchData();
};
+ const taskOperations = (record: CollectionTask) => {
+ const isStopped = record.status === TaskStatus.STOPPED;
+ const startButton = {
+ key: "start",
+ label: "启动",
+ icon:
,
+ onClick: () => handleStartTask(record.id),
+ };
+ const stopButton = {
+ key: "stop",
+ label: "停止",
+ icon:
,
+ onClick: () => handleStopTask(record.id),
+ };
+ const items = [
+ isStopped ? startButton : stopButton,
+ {
+ key: "edit",
+ label: "编辑",
+ icon:
,
+ onClick: () => {
+ showEditTaskModal(record);
+ },
+ },
+ {
+ key: "delete",
+ label: "删除",
+ danger: true,
+ icon:
,
+ confirm: {
+ title: "确定要删除该任务吗?此操作不可撤销。",
+ okText: "删除",
+ cancelText: "取消",
+ okType: "danger",
+ },
+ onClick: () => handleDeleteTask(record.id),
+ },
+ ];
+ return items;
+ };
+
const columns = [
{
title: "任务名称",
dataIndex: "name",
key: "name",
fixed: "left",
- render: (text: string, record: CollectionTask) => (
-
- ),
},
-
{
title: "状态",
dataIndex: "status",
key: "status",
- render: (status: string) =>
- StatusMap[status] ? (
-
- ) : (
-
- ),
+ render: (status: string) => (
+
+ ),
},
{
title: "同步方式",
@@ -115,47 +159,42 @@ export default function TaskManagement() {
title: "操作",
key: "action",
fixed: "right" as const,
- render: (_: any, record: Task) => (
-
handleStartTask(record.id),
- }
- : {
- key: "stop",
- label: "停止",
- onClick: () => handleStopTask(record.id),
- },
- {
- key: "edit",
- label: "编辑",
- onClick: () => handleViewDetail(record),
- },
- {
- key: "delete",
- label: "删除",
- danger: true,
- onClick: () => handleDeleteTask(record.id),
- },
- ],
- }}
- trigger={["click"]}
- >
- }
- />
-
- ),
+ render: (_: any, record: CollectionTask) => {
+ return taskOperations(record).map((op) => {
+ const button = (
+
+
+ );
+ if (op.confirm) {
+ return (
+
op.onClick(record)}
+ >
+
+
+
+
+ );
+ }
+ return button;
+ });
+ },
},
];
return (
-
+
{/* Header Actions */}
{/* Tasks Table */}
@@ -192,7 +230,7 @@ export default function TaskManagement() {
pageSize: searchParams.pageSize,
total: pagination.total,
}}
- scroll={{ x: "max-content" }}
+ scroll={{ x: "max-content", y: "calc(100vh - 25rem)" }}
/>
diff --git a/frontend/src/pages/DataCollection/collection.const.ts b/frontend/src/pages/DataCollection/collection.const.ts
index b7cf8f8c1..544bfb74e 100644
--- a/frontend/src/pages/DataCollection/collection.const.ts
+++ b/frontend/src/pages/DataCollection/collection.const.ts
@@ -1,4 +1,9 @@
-import { LogStatus, SyncMode, TaskStatus, TriggerType } from "./collection.model";
+import {
+ LogStatus,
+ SyncMode,
+ TaskStatus,
+ TriggerType,
+} from "./collection.model";
export const StatusMap: Record<
TaskStatus,
@@ -67,3 +72,10 @@ export const LogTriggerTypeMap: Record<
[TriggerType.SCHEDULED]: { label: "定时", value: TriggerType.SCHEDULED },
[TriggerType.API]: { label: "API", value: TriggerType.API },
};
+
+export function mapCollectionTask(task: CollectionTask): CollectionTask {
+ return {
+ ...task,
+ status: StatusMap[task.status],
+ };
+}
diff --git a/frontend/src/pages/DataManagement/Create/components/BasicInformation.tsx b/frontend/src/pages/DataManagement/Create/components/BasicInformation.tsx
index ae56fb0f9..63f51625b 100644
--- a/frontend/src/pages/DataManagement/Create/components/BasicInformation.tsx
+++ b/frontend/src/pages/DataManagement/Create/components/BasicInformation.tsx
@@ -23,6 +23,7 @@ export default function BasicInformation({
// 获取标签
const fetchTags = async () => {
+ if (hidden.includes("tags")) return;
try {
const { data } = await queryDatasetTagsUsingGet();
const customTags = data.map((tag) => ({
@@ -47,9 +48,11 @@ export default function BasicInformation({
>
-
-
-
+ {!hidden.includes("description") && (
+
+
+
+ )}
{/* 数据集类型选择 - 使用卡片形式 */}
{!hidden.includes("datasetType") && (
@@ -65,14 +68,16 @@ export default function BasicInformation({
/>
)}
-
-
-
+ {!hidden.includes("tags") && (
+
+
+
+ )}
>
);
}
diff --git a/frontend/src/pages/DataManagement/Detail/components/ImportConfiguration.tsx b/frontend/src/pages/DataManagement/Detail/components/ImportConfiguration.tsx
index d59d2622a..0d73f2fe5 100644
--- a/frontend/src/pages/DataManagement/Detail/components/ImportConfiguration.tsx
+++ b/frontend/src/pages/DataManagement/Detail/components/ImportConfiguration.tsx
@@ -152,40 +152,6 @@ export default function ImportConfiguration({
)}
- {/* nas import */}
- {importConfig?.source === DataSource.NAS && (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
{/* obs import */}
{importConfig?.source === DataSource.OBS && (
From 4169399a37748caa52358f9ed43d77b807d8aa59 Mon Sep 17 00:00:00 2001
From: chenghh-9609 <1159096025@qq.com>
Date: Tue, 28 Oct 2025 17:35:48 +0800
Subject: [PATCH 4/4] feat: Update task creation API endpoint and enhance task
creation form with new fields and validation
---
frontend/src/mock/mock-apis.cjs | 2 +-
.../DataCollection/Create/CreateTask.tsx | 177 +++++++++++-------
.../Create/SimpleCronScheduler.tsx | 70 +++----
.../Home/DataCollectionPage.tsx | 5 +-
.../DataCollection/Home/TaskManagement.tsx | 32 +++-
frontend/src/pages/Layout/Sidebar.tsx | 23 ++-
.../src/pages/SettingsPage/ModelAccess.tsx | 37 ++--
frontend/src/utils/request.ts | 2 +-
8 files changed, 213 insertions(+), 135 deletions(-)
diff --git a/frontend/src/mock/mock-apis.cjs b/frontend/src/mock/mock-apis.cjs
index dba93f159..bab1f9daa 100644
--- a/frontend/src/mock/mock-apis.cjs
+++ b/frontend/src/mock/mock-apis.cjs
@@ -3,7 +3,7 @@ const { addMockPrefix } = require("./mock-core/util.cjs");
const MockAPI = {
// 数据归集接口
queryTasksUsingGet: "/data-collection/tasks", // 获取数据源任务列表
- createTaskUsingPost: "/data-collection/tasks/create", // 创建数据源任务
+ createTaskUsingPost: "/data-collection/tasks", // 创建数据源任务
queryTaskByIdUsingGet: "/data-collection/tasks/:id", // 根据ID获取数据源任务详情
updateTaskByIdUsingPut: "/data-collection/tasks/:id", // 更新数据源任务
queryDataXTemplatesUsingGet: "/data-collection/templates", // 获取DataX数据源模板列表
diff --git a/frontend/src/pages/DataCollection/Create/CreateTask.tsx b/frontend/src/pages/DataCollection/Create/CreateTask.tsx
index 506c44560..8d594c420 100644
--- a/frontend/src/pages/DataCollection/Create/CreateTask.tsx
+++ b/frontend/src/pages/DataCollection/Create/CreateTask.tsx
@@ -4,19 +4,14 @@ import { Link, useNavigate } from "react-router";
import { ArrowLeft } from "lucide-react";
import { createTaskUsingPost } from "../collection.apis";
import SimpleCronScheduler from "@/pages/DataCollection/Create/SimpleCronScheduler";
+import RadioCard from "@/components/RadioCard";
+import { datasetTypes } from "@/pages/DataManagement/dataset.const";
+import { SyncModeMap } from "../collection.const";
+import { SyncMode } from "../collection.model";
+import { DatasetSubType } from "@/pages/DataManagement/dataset.model";
const { TextArea } = Input;
-interface ScheduleConfig {
- type: "immediate" | "scheduled";
- scheduleType?: "day" | "week" | "month" | "custom";
- time?: string;
- dayOfWeek?: string;
- dayOfMonth?: string;
- cronExpression?: string;
- maxRetries?: number;
-}
-
const defaultTemplates = [
{
id: "nas",
@@ -47,6 +42,8 @@ const defaultTemplates = [
},
];
+const syncModeOptions = Object.values(SyncModeMap);
+
enum TemplateType {
NAS = "nas",
OBS = "obs",
@@ -64,36 +61,40 @@ export default function CollectionTaskCreate() {
const [selectedTemplate, setSelectedTemplate] = useState("nas");
const [customConfig, setCustomConfig] = useState("");
- const [scheduleConfig, setScheduleConfig] = useState
({
- type: "immediate",
+ const [newTask, setNewTask] = useState({
+ name: "",
+ description: "",
+ syncMode: SyncMode.ONCE,
+ cronExpression: "",
maxRetries: 10,
- scheduleType: "daily",
+ dataset: {},
+ });
+ const [scheduleExpression, setScheduleExpression] = useState({
+ type: SyncMode.SCHEDULED,
+ time: "00:00",
+ cronExpression: "0 0 0 * * ?",
});
const [isCreateDataset, setIsCreateDataset] = useState(false);
const handleSubmit = async () => {
- const formData = await form.validateFields();
- if (templateType === "default" && !selectedTemplate) {
- window.alert("请选择默认模板");
- return;
+ try {
+ const formData = await form.validateFields();
+ if (templateType === "default" && !selectedTemplate) {
+ window.alert("请选择默认模板");
+ return;
+ }
+ if (templateType === "custom" && !customConfig.trim()) {
+ window.alert("请填写自定义配置");
+ return;
+ }
+ // Create task logic here
+ await createTaskUsingPost(newTask);
+ message.success("任务创建成功");
+ navigate("/data/collection");
+ } catch (error) {
+ message.error(`${error?.data?.message}:${error?.data?.data}`);
}
- if (templateType === "custom" && !customConfig.trim()) {
- window.alert("请填写自定义配置");
- return;
- }
- // Create task logic here
- const params = {
- ...formData,
- templateType,
- selectedTemplate: templateType === "default" ? selectedTemplate : null,
- customConfig: templateType === "custom" ? customConfig : null,
- scheduleConfig,
- };
- console.log("Creating task:", params);
- await createTaskUsingPost(params);
- message.success("任务创建成功");
- navigate("/data/collection");
};
return (
@@ -114,17 +115,16 @@ export default function CollectionTaskCreate() {
@@ -138,32 +138,37 @@ export default function CollectionTaskCreate() {
同步配置
-
+
- setScheduleConfig({
- type: e.target.value as ScheduleConfig["type"],
- })
- }
- >
- 立即同步
- 定时同步
-
+ value={newTask.syncMode}
+ options={syncModeOptions}
+ onChange={(e) => {
+ const value = e.target.value;
+ setNewTask({
+ ...newTask,
+ scheduleExpression:
+ value === SyncMode.SCHEDULED
+ ? scheduleExpression.cronExpression
+ : "",
+ });
+ }}
+ >
- {scheduleConfig.type === "scheduled" && (
+ {newTask.syncMode === SyncMode.SCHEDULED && (
- setScheduleConfig({ ...scheduleConfig, cron: value })
- }
+ value={scheduleExpression}
+ onChange={(value) => {
+ setScheduleExpression(value);
+ setNewTask({
+ ...newTask,
+ scheduleExpression: value.cronExpression,
+ });
+ }}
/>
)}
@@ -213,29 +218,25 @@ export default function CollectionTaskCreate() {
{selectedTemplate === TemplateType.NAS && (
-
+
)}
@@ -309,7 +310,19 @@ export default function CollectionTaskCreate() {
>
setIsCreateDataset(e.target.value)}
+ onChange={(e) => {
+ const value = e.target.value;
+ if (value === false) {
+ form.setFieldsValue({
+ dataset: {},
+ });
+ setNewTask({
+ ...newTask,
+ dataset: {},
+ });
+ }
+ setIsCreateDataset(e.target.value);
+ }}
>
是
否
@@ -319,10 +332,40 @@ export default function CollectionTaskCreate() {
<>
-
+ {
+ setNewTask({
+ ...newTask,
+ dataset: {
+ ...newTask.dataset,
+ name: e.target.value,
+ },
+ });
+ }}
+ />
+
+
+ {
+ form.setFieldValue(["dataset", "datasetType"], type);
+ setNewTask({
+ ...newTask,
+ dataset: {
+ datasetType: type as DatasetSubType,
+ },
+ });
+ }}
+ />
>
)}
diff --git a/frontend/src/pages/DataCollection/Create/SimpleCronScheduler.tsx b/frontend/src/pages/DataCollection/Create/SimpleCronScheduler.tsx
index cb4b56ae9..097474d6b 100644
--- a/frontend/src/pages/DataCollection/Create/SimpleCronScheduler.tsx
+++ b/frontend/src/pages/DataCollection/Create/SimpleCronScheduler.tsx
@@ -130,14 +130,42 @@ const SimpleCronScheduler: React.FC = ({
return (
{/* 执行周期选择 */}
-
-
-
+
+
+
+
+
+ {/* 周几选择 */}
+ {config.type === "weekly" && (
+
+
+
+ )}
+
+ {/* 月份日期选择 */}
+ {config.type === "monthly" && (
+
+
+
+ )}
+
{/* 时间选择 */}
@@ -165,32 +193,6 @@ const SimpleCronScheduler: React.FC = ({
- {/* 周几选择 */}
- {config.type === "weekly" && (
-
-
-
- )}
-
- {/* 月份日期选择 */}
- {config.type === "monthly" && (
-
-
-
- )}
-
{/* Cron 表达式预览 */}
{/*
生成的 Cron 表达式
diff --git a/frontend/src/pages/DataCollection/Home/DataCollectionPage.tsx b/frontend/src/pages/DataCollection/Home/DataCollectionPage.tsx
index 3dd3d5203..89ade8969 100644
--- a/frontend/src/pages/DataCollection/Home/DataCollectionPage.tsx
+++ b/frontend/src/pages/DataCollection/Home/DataCollectionPage.tsx
@@ -4,14 +4,11 @@ import { PlusOutlined } from "@ant-design/icons";
import TaskManagement from "./TaskManagement";
import ExecutionLog from "./ExecutionLog";
import { useNavigate } from "react-router";
-import DevelopmentInProgress from "@/components/DevelopmentInProgress";
export default function DataCollection() {
const navigate = useNavigate();
const [activeTab, setActiveTab] = useState("task-management");
- // return
;
-
return (
@@ -32,7 +29,7 @@ export default function DataCollection() {
activeKey={activeTab}
items={[
{ label: "任务管理", key: "task-management" },
- { label: "执行日志", key: "execution-log" },
+ // { label: "执行日志", key: "execution-log" },
]}
onChange={(tab) => {
setActiveTab(tab);
diff --git a/frontend/src/pages/DataCollection/Home/TaskManagement.tsx b/frontend/src/pages/DataCollection/Home/TaskManagement.tsx
index 5bc6169ae..f67e21718 100644
--- a/frontend/src/pages/DataCollection/Home/TaskManagement.tsx
+++ b/frontend/src/pages/DataCollection/Home/TaskManagement.tsx
@@ -87,15 +87,15 @@ export default function TaskManagement() {
onClick: () => handleStopTask(record.id),
};
const items = [
- isStopped ? startButton : stopButton,
- {
- key: "edit",
- label: "编辑",
- icon: ,
- onClick: () => {
- showEditTaskModal(record);
- },
- },
+ // isStopped ? startButton : stopButton,
+ // {
+ // key: "edit",
+ // label: "编辑",
+ // icon: ,
+ // onClick: () => {
+ // showEditTaskModal(record);
+ // },
+ // },
{
key: "delete",
label: "删除",
@@ -119,11 +119,15 @@ export default function TaskManagement() {
dataIndex: "name",
key: "name",
fixed: "left",
+ width: 150,
+ ellipsis: true,
},
{
title: "状态",
dataIndex: "status",
key: "status",
+ width: 150,
+ ellipsis: true,
render: (status: string) => (
),
@@ -132,28 +136,37 @@ export default function TaskManagement() {
title: "同步方式",
dataIndex: "syncMode",
key: "syncMode",
+ width: 150,
+ ellipsis: true,
render: (text: string) => {SyncModeMap[text]?.label},
},
{
title: "创建时间",
dataIndex: "createdAt",
key: "createdAt",
+ width: 150,
+ ellipsis: true,
},
{
title: "更新时间",
dataIndex: "updatedAt",
key: "updatedAt",
+ width: 150,
+ ellipsis: true,
},
{
title: "最近执行ID",
dataIndex: "lastExecutionId",
key: "lastExecutionId",
+ width: 150,
+ ellipsis: true,
},
{
title: "描述",
dataIndex: "description",
key: "description",
ellipsis: true,
+ width: 200,
},
{
title: "操作",
@@ -215,6 +228,7 @@ export default function TaskManagement() {
filters: {},
}))
}
+ onReload={fetchData}
/>
{/* Tasks Table */}
diff --git a/frontend/src/pages/Layout/Sidebar.tsx b/frontend/src/pages/Layout/Sidebar.tsx
index f881d801a..2c9c81810 100644
--- a/frontend/src/pages/Layout/Sidebar.tsx
+++ b/frontend/src/pages/Layout/Sidebar.tsx
@@ -13,7 +13,7 @@ import TaskUpload from "./TaskUpload";
const AsiderAndHeaderLayout = () => {
const { pathname } = useLocation();
const navigate = useNavigate();
- const [activeItem, setActiveItem] = useState("management");
+ const [activeItem, setActiveItem] = useState("");
const [sidebarOpen, setSidebarOpen] = useState(true);
const [taskCenterVisible, setTaskCenterVisible] = useState(false);
@@ -33,6 +33,7 @@ const AsiderAndHeaderLayout = () => {
return;
}
}
+ console.log(pathname);
};
useEffect(() => {
@@ -134,7 +135,15 @@ const AsiderAndHeaderLayout = () => {
任务中心
-
@@ -156,7 +165,15 @@ const AsiderAndHeaderLayout = () => {
>
-
navigate("/data/settings")}>
+ {
+ setActiveItem("");
+ navigate("/data/settings");
+ }}
+ >
diff --git a/frontend/src/pages/SettingsPage/ModelAccess.tsx b/frontend/src/pages/SettingsPage/ModelAccess.tsx
index 932a48b22..23c71c1c1 100644
--- a/frontend/src/pages/SettingsPage/ModelAccess.tsx
+++ b/frontend/src/pages/SettingsPage/ModelAccess.tsx
@@ -79,14 +79,18 @@ export default function EnvironmentAccess() {
} = useFetchData(queryModelListUsingGet);
const handleAddModel = async () => {
- const formValues = await form.validateFields();
- const fn = isEditMode
- ? () => updateModelByIdUsingPut(newModel.id, formValues)
- : () => createModelUsingPost(formValues);
- await fn();
- setShowModelDialog(false);
- fetchData();
- message.success("模型添加成功");
+ try {
+ const formValues = await form.validateFields();
+ const fn = isEditMode
+ ? () => updateModelByIdUsingPut(newModel.id, formValues)
+ : () => createModelUsingPost(formValues);
+ await fn();
+ setShowModelDialog(false);
+ fetchData();
+ message.success("模型添加成功");
+ } catch (error) {
+ message.error(`${error?.data?.message}:${error?.data?.data}`);
+ }
};
const [providerOptions, setProviderOptions] = useState([]);
@@ -303,14 +307,6 @@ export default function EnvironmentAccess() {
}}
layout="vertical"
>
-
-
-
+
+
+