{renderTemplateFields(
@@ -524,7 +581,7 @@ export default function CollectionTaskCreate() {
{getPropertyCountSafe(selectedTemplate.templateContent?.reader) > 0 ? (
<>
- 源端参数
+ {t("dataCollection.createTask.sourceParams.title")}
{renderTemplateFields(
@@ -538,7 +595,7 @@ export default function CollectionTaskCreate() {
{getPropertyCountSafe(selectedTemplate.templateContent?.writer) > 0 ? (
<>
- 目标端参数
+ {t("dataCollection.createTask.targetParams.title")}
{renderTemplateFields(
@@ -553,9 +610,11 @@ export default function CollectionTaskCreate() {
-
+
diff --git a/frontend/src/pages/DataCollection/Create/SimpleCronScheduler.tsx b/frontend/src/pages/DataCollection/Create/SimpleCronScheduler.tsx
index 51c58a482..24b2d4d2d 100644
--- a/frontend/src/pages/DataCollection/Create/SimpleCronScheduler.tsx
+++ b/frontend/src/pages/DataCollection/Create/SimpleCronScheduler.tsx
@@ -8,6 +8,7 @@ import {
} from "antd";
import type { Dayjs } from "dayjs";
import dayjs from "dayjs";
+import { useTranslation } from "react-i18next";
export interface SimpleCronConfig {
type: "daily" | "weekly" | "monthly";
@@ -29,40 +30,41 @@ const defaultConfig: SimpleCronConfig = {
cronExpression: "0 0 * * *",
};
-// 生成周几选项
-const weekDayOptions = [
- { label: "周日", value: 0 },
- { label: "周一", value: 1 },
- { label: "周二", value: 2 },
- { label: "周三", value: 3 },
- { label: "周四", value: 4 },
- { label: "周五", value: 5 },
- { label: "周六", value: 6 },
-];
-
-// 生成月份日期选项
-const monthDayOptions = Array.from({ length: 31 }, (_, i) => ({
- label: `${i + 1}日`,
- value: i + 1,
-}));
-
-// 常用时间预设
-const commonTimePresets = [
- { label: "上午 9:00", value: "09:00" },
- { label: "中午 12:00", value: "12:00" },
- { label: "下午 2:00", value: "14:00" },
- { label: "下午 6:00", value: "18:00" },
- { label: "晚上 8:00", value: "20:00" },
- { label: "午夜 0:00", value: "00:00" },
-];
-
const SimpleCronScheduler: React.FC
= ({
value = defaultConfig,
onChange,
className,
}) => {
+ const { t } = useTranslation();
const [config, setConfig] = useState(value);
+ // 生成周几选项
+ const weekDayOptions = [
+ { label: t("dataCollection.scheduler.weekdays.sunday"), value: 0 },
+ { label: t("dataCollection.scheduler.weekdays.monday"), value: 1 },
+ { label: t("dataCollection.scheduler.weekdays.tuesday"), value: 2 },
+ { label: t("dataCollection.scheduler.weekdays.wednesday"), value: 3 },
+ { label: t("dataCollection.scheduler.weekdays.thursday"), value: 4 },
+ { label: t("dataCollection.scheduler.weekdays.friday"), value: 5 },
+ { label: t("dataCollection.scheduler.weekdays.saturday"), value: 6 },
+ ];
+
+ // 生成月份日期选项
+ const monthDayOptions = Array.from({ length: 31 }, (_, i) => ({
+ label: `${i + 1}${t("dataCollection.scheduler.monthDaySuffix")}`,
+ value: i + 1,
+ }));
+
+ // 常用时间预设
+ const commonTimePresets = [
+ { label: t("dataCollection.scheduler.timePresets.morning9"), value: "09:00" },
+ { label: t("dataCollection.scheduler.timePresets.noon12"), value: "12:00" },
+ { label: t("dataCollection.scheduler.timePresets.afternoon2"), value: "14:00" },
+ { label: t("dataCollection.scheduler.timePresets.afternoon6"), value: "18:00" },
+ { label: t("dataCollection.scheduler.timePresets.evening8"), value: "20:00" },
+ { label: t("dataCollection.scheduler.timePresets.midnight0"), value: "00:00" },
+ ];
+
useEffect(() => {
setConfig(value || defaultConfig);
}, [value]);
@@ -130,22 +132,22 @@ const SimpleCronScheduler: React.FC = ({
{/* 执行周期选择 */}
-
+
{/* 周几选择 */}
{config.type === "weekly" && (
-
+
@@ -153,12 +155,12 @@ const SimpleCronScheduler: React.FC = ({
{/* 月份日期选择 */}
{config.type === "monthly" && (
-
+
@@ -166,13 +168,13 @@ const SimpleCronScheduler: React.FC = ({
{/* 时间选择 */}
-
+
{commonTimePresets.map((preset) => (
diff --git a/frontend/src/pages/DataCollection/Home/DataCollectionPage.tsx b/frontend/src/pages/DataCollection/Home/DataCollectionPage.tsx
index f1f7b71bf..48a02e13c 100644
--- a/frontend/src/pages/DataCollection/Home/DataCollectionPage.tsx
+++ b/frontend/src/pages/DataCollection/Home/DataCollectionPage.tsx
@@ -5,10 +5,12 @@ import TaskManagement from "./TaskManagement";
import Execution from "./Execution.tsx";
import TemplateManagement from "./TemplateManagement";
import { useLocation, useNavigate } from "react-router";
+import { useTranslation } from "react-i18next";
export default function DataCollection() {
const navigate = useNavigate();
const location = useLocation();
+ const { t } = useTranslation();
const [activeTab, setActiveTab] = useState("task-management");
const [taskId, setTaskId] = useState(undefined);
@@ -27,7 +29,7 @@ export default function DataCollection() {
-
数据归集
+ {t("dataCollection.title")}
{
setActiveTab(tab);
diff --git a/frontend/src/pages/DataCollection/Home/Execution.tsx b/frontend/src/pages/DataCollection/Home/Execution.tsx
index 6d20aa27f..dc5de56b6 100644
--- a/frontend/src/pages/DataCollection/Home/Execution.tsx
+++ b/frontend/src/pages/DataCollection/Home/Execution.tsx
@@ -1,29 +1,17 @@
-import {Card, Badge, Button, Modal, Table, Tag} from "antd";
+import { Card, Badge, Button, Modal, Table, Tag } from "antd";
import type { ColumnsType } from "antd/es/table";
import { SearchControls } from "@/components/SearchControls";
import { queryExecutionLogUsingPost } from "../collection.apis";
import useFetchData from "@/hooks/useFetchData";
import { useEffect, useState } from "react";
-import {TaskExecution} from "@/pages/DataCollection/collection.model.ts";
-import {mapTaskExecution} from "@/pages/DataCollection/collection.const.ts";
+import { TaskExecution } from "@/pages/DataCollection/collection.model.ts";
+import { mapTaskExecution } from "@/pages/DataCollection/collection.const.ts";
import { queryExecutionLogFileByIdUsingGet } from "../collection.apis";
import { FileTextOutlined } from "@ant-design/icons";
-
-const filterOptions = [
- {
- key: "status",
- label: "状态筛选",
- options: [
- { value: "all", label: "全部状态" },
- { value: "RUNNING", label: "运行中" },
- { value: "SUCCESS", label: "成功" },
- { value: "FAILED", label: "失败" },
- { value: "STOPPED", label: "停止" },
- ],
- },
-];
+import { useTranslation } from "react-i18next";
export default function Execution({ taskId }: { taskId?: string }) {
+ const { t } = useTranslation();
const [dateRange, setDateRange] = useState<[any, any] | null>(null);
const [logOpen, setLogOpen] = useState(false);
const [logLoading, setLogLoading] = useState(false);
@@ -32,13 +20,27 @@ export default function Execution({ taskId }: { taskId?: string }) {
const [logFilename, setLogFilename] = useState("");
const [logBlobUrl, setLogBlobUrl] = useState("");
+ const filterOptions = [
+ {
+ key: "status",
+ label: t("dataCollection.execution.filters.statusFilter"),
+ options: [
+ { value: "all", label: t("dataCollection.execution.filters.allStatus") },
+ { value: "RUNNING", label: t("dataCollection.execution.filters.running") },
+ { value: "SUCCESS", label: t("dataCollection.execution.filters.success") },
+ { value: "FAILED", label: t("dataCollection.execution.filters.failed") },
+ { value: "STOPPED", label: t("dataCollection.execution.filters.stopped") },
+ ],
+ },
+ ];
+
const formatDuration = (seconds?: number) => {
- if (seconds === undefined || seconds === null) return "-";
+ if (seconds === undefined || seconds === null) return t("common.placeholders.empty");
const total = Math.max(0, Math.floor(seconds));
- if (total < 60) return `${total}s`;
+ if (total < 60) return `${total}${t("dataCollection.execution.duration.secondsSuffix")}`;
const min = Math.floor(total / 60);
const sec = total % 60;
- return `${min}min${sec}s`;
+ return `${min}${t("dataCollection.execution.duration.minutesSuffix")}${sec}${t("dataCollection.execution.duration.secondsSuffix")}`;
};
const handleReset = () => {
@@ -74,7 +76,7 @@ export default function Execution({ taskId }: { taskId?: string }) {
end_time,
});
},
- mapTaskExecution,
+ (execution) => mapTaskExecution(execution, t),
30000,
false,
[],
@@ -86,7 +88,7 @@ export default function Execution({ taskId }: { taskId?: string }) {
...prev,
current: 1,
}));
- }, [taskId, setSearchParams]);
+ }, [taskId, setSearchParams, t]);
const handleViewLog = async (record: TaskExecution) => {
setLogOpen(true);
@@ -106,7 +108,7 @@ export default function Execution({ taskId }: { taskId?: string }) {
const text = await blob.text();
setLogContent(text);
} catch (e: any) {
- setLogContent(e?.data?.detail || e?.message || "Failed to load log");
+ setLogContent(e?.data?.detail || e?.message || t("dataCollection.execution.messages.loadLogFailed"));
} finally {
setLogLoading(false);
}
@@ -114,7 +116,7 @@ export default function Execution({ taskId }: { taskId?: string }) {
const columns: ColumnsType = [
{
- title: "任务名称",
+ title: t("dataCollection.execution.columns.taskName"),
dataIndex: "taskName",
key: "taskName",
fixed: "left",
@@ -123,7 +125,7 @@ export default function Execution({ taskId }: { taskId?: string }) {
),
},
{
- title: "状态",
+ title: t("dataCollection.execution.columns.status"),
dataIndex: "status",
key: "status",
render: (status: any) => ((
@@ -132,23 +134,23 @@ export default function Execution({ taskId }: { taskId?: string }) {
),
},
{
- title: "开始时间",
+ title: t("dataCollection.execution.columns.startTime"),
dataIndex: "startedAt",
key: "startedAt",
},
{
- title: "结束时间",
+ title: t("dataCollection.execution.columns.endTime"),
dataIndex: "completedAt",
key: "completedAt",
},
{
- title: "执行时长",
+ title: t("dataCollection.execution.columns.duration"),
dataIndex: "durationSeconds",
key: "durationSeconds",
render: (v?: number) => formatDuration(v),
},
{
- title: "错误信息",
+ title: t("dataCollection.execution.columns.errorMessage"),
dataIndex: "errorMessage",
key: "errorMessage",
render: (msg?: string) =>
@@ -157,11 +159,11 @@ export default function Execution({ taskId }: { taskId?: string }) {
{msg}
) : (
- -
+ {t("common.placeholders.empty")}
),
},
{
- title: "操作",
+ title: t("dataCollection.execution.columns.actions"),
key: "action",
fixed: "right",
width: 120,
@@ -171,7 +173,7 @@ export default function Execution({ taskId }: { taskId?: string }) {
icon={}
onClick={() => handleViewLog(record)}
>
- 查看日志
+ {t("dataCollection.execution.actions.viewLog")}
),
},
@@ -208,7 +210,7 @@ export default function Execution({ taskId }: { taskId?: string }) {
}));
}}
onReload={handleReset}
- searchPlaceholder="搜索任务名称..."
+ searchPlaceholder={t("dataCollection.execution.filters.searchPlaceholder")}
className="flex-1"
/>
@@ -224,7 +226,7 @@ export default function Execution({ taskId }: { taskId?: string }) {
{
setLogOpen(false);
@@ -248,7 +250,7 @@ export default function Execution({ taskId }: { taskId?: string }) {
document.body.removeChild(a);
}}
>
- 下载日志
+ {t("dataCollection.execution.modal.downloadLog")}
) : null}
@@ -283,7 +285,9 @@ export default function Execution({ taskId }: { taskId?: string }) {
wordBreak: "break-word",
}}
>
- {logLoading ? "Loading..." : (logContent || "(empty)")}
+ {logLoading
+ ? t("dataCollection.execution.modal.loading")
+ : (logContent || t("dataCollection.execution.modal.empty"))}
diff --git a/frontend/src/pages/DataCollection/Home/TaskManagement.tsx b/frontend/src/pages/DataCollection/Home/TaskManagement.tsx
index 5482d45bd..d6d69fa37 100644
--- a/frontend/src/pages/DataCollection/Home/TaskManagement.tsx
+++ b/frontend/src/pages/DataCollection/Home/TaskManagement.tsx
@@ -1,27 +1,36 @@
-import {App, Button, Card, Popconfirm, Table, Tag, Tooltip,} from "antd";
-import {DeleteOutlined, PauseCircleOutlined, PlayCircleOutlined, ProfileOutlined,} from "@ant-design/icons";
-import {SearchControls} from "@/components/SearchControls";
+import { App, Button, Card, Popconfirm, Table, Tag, Tooltip } from "antd";
+import {
+ DeleteOutlined,
+ PauseCircleOutlined,
+ PlayCircleOutlined,
+ ProfileOutlined,
+} from "@ant-design/icons";
+import { SearchControls } from "@/components/SearchControls";
import {
deleteTaskByIdUsingDelete,
executeTaskByIdUsingPost,
queryTasksUsingGet,
stopTaskByIdUsingPost,
} from "../collection.apis";
-import {type CollectionTask, TaskStatus} from "../collection.model";
-import {mapCollectionTask, StatusMap} from "../collection.const";
+import { type CollectionTask, TaskStatus } from "../collection.model";
+import { getStatusMap, mapCollectionTask } from "../collection.const";
import useFetchData from "@/hooks/useFetchData";
-import {useNavigate} from "react-router";
+import { useNavigate } from "react-router";
+import { useTranslation } from "react-i18next";
+import { useEffect } from "react";
export default function TaskManagement() {
const { message } = App.useApp();
const navigate = useNavigate();
+ const { t } = useTranslation();
+ const statusMap = getStatusMap(t);
const filters = [
{
key: "status",
- label: "状态筛选",
+ label: t("dataCollection.taskManagement.filters.statusFilter"),
options: [
- { value: "all", label: "全部状态" },
- ...Object.values(StatusMap),
+ { value: "all", label: t("dataCollection.taskManagement.filters.allStatus") },
+ ...Object.values(statusMap),
],
},
];
@@ -41,28 +50,32 @@ export default function TaskManagement() {
name: keyword || undefined,
});
},
- mapCollectionTask,
+ (task) => mapCollectionTask(task, t),
30000,
false,
[],
0
);
+ useEffect(() => {
+ fetchData()
+ }, [t]);
+
const handleStartTask = async (taskId: string) => {
await executeTaskByIdUsingPost(taskId);
- message.success("任务启动请求已发送");
+ message.success(t("dataCollection.taskManagement.messages.startSuccess"));
fetchData();
};
const handleStopTask = async (taskId: string) => {
await stopTaskByIdUsingPost(taskId);
- message.success("任务停止请求已发送");
+ message.success(t("dataCollection.taskManagement.messages.stopSuccess"));
fetchData();
};
const handleDeleteTask = async (taskId: string) => {
await deleteTaskByIdUsingDelete(taskId);
- message.success("任务已删除");
+ message.success(t("dataCollection.taskManagement.messages.deleteSuccess"));
fetchData();
};
@@ -70,21 +83,21 @@ export default function TaskManagement() {
const isStopped = record.status === TaskStatus.STOPPED;
const startButton = {
key: "start",
- label: "启动",
+ label: t("dataCollection.taskManagement.actions.start"),
icon: