From 163c93142ef15efc6d20cd4b2057fcdde3f87842 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Mon, 19 Jan 2026 10:32:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(annotation):=20=E6=B7=BB=E5=8A=A0=E6=A0=87?= =?UTF-8?q?=E6=B3=A8=E4=BB=BB=E5=8A=A1=E9=A2=84=E8=A7=88=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 previewTaskData 状态管理预览数据 - 实现 generateExampleData 函数根据对象配置生成示例数据 - 支持多种数据类型(图片、音频、视频、文本等)的示例生成 - 优化预览按钮逻辑,自动生成适配的示例数据 - 移除固定示例数据,使用动态生成的数据进行预览 - 调整模板列表组件的分页参数以修复数据获取问题 --- .../components/CreateAnnotationTaskDialog.tsx | 97 ++++++++++++++----- .../DataAnnotation/Template/TemplateList.tsx | 2 +- 2 files changed, 75 insertions(+), 24 deletions(-) diff --git a/frontend/src/pages/DataAnnotation/Create/components/CreateAnnotationTaskDialog.tsx b/frontend/src/pages/DataAnnotation/Create/components/CreateAnnotationTaskDialog.tsx index 8d0d2de..403bc7c 100644 --- a/frontend/src/pages/DataAnnotation/Create/components/CreateAnnotationTaskDialog.tsx +++ b/frontend/src/pages/DataAnnotation/Create/components/CreateAnnotationTaskDialog.tsx @@ -116,10 +116,11 @@ export default function CreateAnnotationTask({ const [submitting, setSubmitting] = useState(false); const [nameManuallyEdited, setNameManuallyEdited] = useState(false); const [activeMode, setActiveMode] = useState<"manual" | "auto">("manual"); - + // Custom template state const [customXml, setCustomXml] = useState(""); const [showPreview, setShowPreview] = useState(false); + const [previewTaskData, setPreviewTaskData] = useState>({}); const [configMode, setConfigMode] = useState<"template" | "custom">("template"); const [templateEditTab, setTemplateEditTab] = useState<"visual" | "xml">("visual"); @@ -174,6 +175,7 @@ export default function CreateAnnotationTask({ setImageFileCount(0); setCustomXml(""); setShowPreview(false); + setPreviewTaskData({}); setConfigMode("template"); setTemplateEditTab("visual"); } @@ -190,7 +192,7 @@ export default function CreateAnnotationTask({ const generateXmlFromConfig = (objects: any[], labels: any[]) => { let xml = '\n'; - + // Objects if (objects) { objects.forEach((obj: any) => { @@ -203,9 +205,9 @@ export default function CreateAnnotationTask({ labels.forEach((lbl: any) => { let attrs = `name="${lbl.fromName}" toName="${lbl.toName}"`; if (lbl.required) attrs += ' required="true"'; - + xml += ` <${lbl.type} ${attrs}>\n`; - + const options = lbl.type === 'Choices' ? lbl.options : lbl.labels; if (options && options.length) { options.forEach((opt: string) => { @@ -234,6 +236,58 @@ export default function CreateAnnotationTask({ } }; + // 根据 objects 配置生成预览用的示例数据 + const generateExampleData = (objects: any[]) => { + const exampleUrls: Record = { + Image: "https://labelstud.io/images/opa-header.png", + Audio: "https://labelstud.io/files/sample.wav", + Video: "https://labelstud.io/files/sample.mp4", + }; + const exampleTexts: Record = { + Text: "这是示例文本,用于预览标注界面。", + HyperText: "

这是示例 HTML 内容

", + Header: "示例标题", + Paragraphs: "段落一\n\n段落二\n\n段落三", + }; + + const data: Record = {}; + + if (!objects || objects.length === 0) { + // 默认数据 + return { + image: exampleUrls.Image, + text: exampleTexts.Text, + audio: exampleUrls.Audio, + }; + } + + objects.forEach((obj: any) => { + if (!obj?.name || !obj?.value) return; + // 变量名从 $varName 中提取 + const varName = obj.value.startsWith("$") ? obj.value.slice(1) : obj.name; + + if (exampleUrls[obj.type]) { + data[varName] = exampleUrls[obj.type]; + } else if (exampleTexts[obj.type]) { + data[varName] = exampleTexts[obj.type]; + } else { + // 未知类型,尝试根据名称猜测 + const lowerName = varName.toLowerCase(); + if (lowerName.includes("image") || lowerName.includes("img")) { + data[varName] = exampleUrls.Image; + } else if (lowerName.includes("audio") || lowerName.includes("sound")) { + data[varName] = exampleUrls.Audio; + } else if (lowerName.includes("video")) { + data[varName] = exampleUrls.Video; + } else { + data[varName] = exampleTexts.Text; + } + } + }); + + return data; + }; + // 当选择模板时,加载模板配置到表单 const handleTemplateSelect = (value: string, option: any) => { if (option && option.config) { @@ -483,7 +537,7 @@ export default function CreateAnnotationTask({ {/* 标注模板选择 */}
标注配置 - +
现有模板 @@ -494,18 +548,19 @@ export default function CreateAnnotationTask({ type="link" size="small" onClick={() => { - // 如果在可视化模式,先同步生成 XML - if (configMode === 'template' && templateEditTab === 'visual') { - syncFormToXml(); - } else if (configMode === 'custom') { - // 自定义模式也从表单生成 - const objects = manualForm.getFieldValue("objects"); - const labels = manualForm.getFieldValue("labels"); - if (objects && objects.length > 0) { - const xml = generateXmlFromConfig(objects, labels || []); - setCustomXml(xml); - } + const objects = manualForm.getFieldValue("objects"); + const labels = manualForm.getFieldValue("labels"); + + // 生成 XML + if (objects && objects.length > 0) { + const xml = generateXmlFromConfig(objects, labels || []); + setCustomXml(xml); } + + // 生成适配的示例数据 + const exampleData = generateExampleData(objects); + setPreviewTaskData(exampleData); + setShowPreview(true); }} > @@ -513,7 +568,7 @@ export default function CreateAnnotationTask({
- + {configMode === 'template' ? (
{showPreview && ( - )} diff --git a/frontend/src/pages/DataAnnotation/Template/TemplateList.tsx b/frontend/src/pages/DataAnnotation/Template/TemplateList.tsx index 5278169..265fa12 100644 --- a/frontend/src/pages/DataAnnotation/Template/TemplateList.tsx +++ b/frontend/src/pages/DataAnnotation/Template/TemplateList.tsx @@ -71,7 +71,7 @@ const TemplateList: React.FC = () => { fetchData, handleFiltersChange, handleKeywordChange, - } = useFetchData(queryAnnotationTemplatesUsingGet, undefined, undefined, undefined, undefined, 0); + } = useFetchData(queryAnnotationTemplatesUsingGet, undefined, undefined, undefined, undefined); const handleCreate = () => { setFormMode("create");