diff --git a/frontend/src/pages/DataAnnotation/Create/components/CreateAnnotationTaskDialog.tsx b/frontend/src/pages/DataAnnotation/Create/components/CreateAnnotationTaskDialog.tsx index 840ebd1..8ae25dc 100644 --- a/frontend/src/pages/DataAnnotation/Create/components/CreateAnnotationTaskDialog.tsx +++ b/frontend/src/pages/DataAnnotation/Create/components/CreateAnnotationTaskDialog.tsx @@ -6,22 +6,30 @@ import { useEffect, useState } from "react"; import { Eye } from "lucide-react"; import { createAnnotationTaskUsingPost, + getAnnotationTaskByIdUsingGet, + updateAnnotationTaskByIdUsingPut, queryAnnotationTemplatesUsingGet, } from "../../annotation.api"; import { type Dataset } from "@/pages/DataManagement/dataset.model"; -import type { AnnotationTemplate } from "../../annotation.model"; +import type { AnnotationTemplate, AnnotationTask } from "../../annotation.model"; import LabelStudioEmbed from "@/components/business/LabelStudioEmbed"; import TemplateConfigurationForm from "../../components/TemplateConfigurationForm"; +interface AnnotationTaskDialogProps { + open: boolean; + onClose: () => void; + onRefresh: () => void; + /** 编辑模式:传入要编辑的任务数据 */ + editTask?: AnnotationTask | null; +} + export default function CreateAnnotationTask({ open, onClose, onRefresh, -}: { - open: boolean; - onClose: () => void; - onRefresh: () => void; -}) { + editTask, +}: AnnotationTaskDialogProps) { + const isEditMode = !!editTask; const { message } = App.useApp(); const [manualForm] = Form.useForm(); const [datasets, setDatasets] = useState([]); @@ -34,6 +42,8 @@ export default function CreateAnnotationTask({ const [showPreview, setShowPreview] = useState(false); const [previewTaskData, setPreviewTaskData] = useState>({}); const [configMode, setConfigMode] = useState<"template" | "custom">("template"); + // 模板编辑模式切换(可视化 vs XML) + const [templateEditTab, setTemplateEditTab] = useState<"visual" | "xml">("visual"); // 是否已选择模板(用于启用受限编辑模式) const [hasSelectedTemplate, setHasSelectedTemplate] = useState(false); @@ -51,6 +61,9 @@ export default function CreateAnnotationTask({ const [previewFileType, setPreviewFileType] = useState<"text" | "image" | "video" | "audio">("text"); const [previewMediaUrl, setPreviewMediaUrl] = useState(""); + // 任务详情加载状态(编辑模式) + const [taskDetailLoading, setTaskDetailLoading] = useState(false); + useEffect(() => { if (!open) return; const fetchData = async () => { @@ -83,7 +96,7 @@ export default function CreateAnnotationTask({ fetchData(); }, [open]); - // Reset form and manual-edit flag when modal opens + // Reset form and manual-edit flag when modal opens, or load task data in edit mode useEffect(() => { if (open) { manualForm.resetFields(); @@ -91,12 +104,58 @@ export default function CreateAnnotationTask({ setCustomXml(""); setShowPreview(false); setPreviewTaskData({}); - setConfigMode("template"); - setHasSelectedTemplate(false); - setSelectedDatasetId(null); setDatasetPreviewData([]); + + if (isEditMode && editTask) { + // 编辑模式:加载任务详情 + setTaskDetailLoading(true); + getAnnotationTaskByIdUsingGet(editTask.id) + .then((res: any) => { + if (res.code === 200 && res.data) { + const taskDetail = res.data; + // 填充基本信息 + manualForm.setFieldsValue({ + name: taskDetail.name, + description: taskDetail.description, + datasetId: taskDetail.datasetId, + }); + setSelectedDatasetId(taskDetail.datasetId); + + // 填充模板配置 + if (taskDetail.configuration) { + const { objects, labels } = taskDetail.configuration; + manualForm.setFieldsValue({ + objects: objects || [], + labels: labels || [], + }); + } + + // 设置 XML 配置用于预览 + if (taskDetail.labelConfig) { + setCustomXml(taskDetail.labelConfig); + } + + // 编辑模式始终使用 custom 配置模式(不改变结构,只改标签) + setConfigMode("custom"); + // 编辑模式下启用受限编辑 + setHasSelectedTemplate(true); + } + }) + .catch((err) => { + console.error("Failed to load task detail:", err); + message.error("加载任务详情失败"); + }) + .finally(() => { + setTaskDetailLoading(false); + }); + } else { + // 创建模式:重置为默认状态 + setConfigMode("template"); + setHasSelectedTemplate(false); + setSelectedDatasetId(null); + } } - }, [open, manualForm]); + }, [open, manualForm, isEditMode, editTask, message]); // 预览数据集 const handlePreviewDataset = async () => { @@ -342,14 +401,27 @@ export default function CreateAnnotationTask({ datasetId: values.datasetId, templateId: configMode === 'template' ? values.templateId : undefined, labelConfig: finalLabelConfig, + // 编辑模式需要传递配置结构,用于后端保存 + configuration: { + objects: objects || [], + labels: labels || [], + }, }; - await createAnnotationTaskUsingPost(requestData); - message.success("创建标注任务成功"); + + if (isEditMode && editTask) { + // 编辑模式:调用更新接口 + await updateAnnotationTaskByIdUsingPut(editTask.id, requestData); + message.success("更新标注任务成功"); + } else { + // 创建模式:调用创建接口 + await createAnnotationTaskUsingPost(requestData); + message.success("创建标注任务成功"); + } onClose(); onRefresh(); } catch (err: any) { - console.error("Create annotation task failed", err); - const msg = err?.message || err?.data?.message || "创建失败,请稍后重试"; + console.error(isEditMode ? "Update annotation task failed" : "Create annotation task failed", err); + const msg = err?.message || err?.data?.message || (isEditMode ? "更新失败,请稍后重试" : "创建失败,请稍后重试"); message.error(msg); } finally { setSubmitting(false); @@ -378,7 +450,8 @@ export default function CreateAnnotationTask({