From a2b0fc3674dd0efd437af90aa388da2fc0637079 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Sun, 18 Jan 2026 21:59:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(annotation):=20=E6=B7=BB=E5=8A=A0=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E7=A4=BA=E4=BE=8B=E6=95=B0=E6=8D=AE=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在模板配置表单中新增示例数据输入区域 - 实现不同数据类型的示例输入框(文本、图片、音频、视频等) - 添加图片类型示例的实时预览功能 - 在模板详情页增加示例数据预览卡片 - 支持多种媒体类型的示例展示(图片、音频、视频、文本) - 更新前后端数据模型以支持exampleData字段 - 添加示例数据的placeholder提示文案 --- .../Template/TemplateDetail.tsx | 65 ++++++++++- .../pages/DataAnnotation/annotation.model.ts | 6 ++ .../components/TemplateConfigurationForm.tsx | 101 ++++++++++++++++++ .../app/module/annotation/schema/template.py | 7 +- 4 files changed, 177 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/DataAnnotation/Template/TemplateDetail.tsx b/frontend/src/pages/DataAnnotation/Template/TemplateDetail.tsx index 202aa6f..091eadf 100644 --- a/frontend/src/pages/DataAnnotation/Template/TemplateDetail.tsx +++ b/frontend/src/pages/DataAnnotation/Template/TemplateDetail.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Modal, Descriptions, Tag, Space, Divider, Card, Typography } from "antd"; +import { Modal, Descriptions, Tag, Space, Divider, Card, Typography, Image, Empty } from "antd"; import type { AnnotationTemplate } from "../annotation.model"; const { Text, Paragraph } = Typography; @@ -81,6 +81,69 @@ const TemplateDetail: React.FC = ({ + {/* 示例数据预览 */} + + {template.configuration.exampleData && + Object.keys(template.configuration.exampleData).length > 0 ? ( + + {template.configuration.objects.map((obj, index) => { + const varName = obj.value?.replace(/^\$/, "") || obj.name; + const exampleValue = template.configuration.exampleData?.[varName]; + + if (!exampleValue) return null; + + return ( + + +
+ {obj.name} + + ({obj.type}) + +
+ {/* 根据类型渲染不同的预览 */} + {obj.type === "Image" ? ( + {`示例: + ) : obj.type === "Audio" ? ( +
+
+ ); + })} +
+ ) : ( + + )} +
+ {template.configuration.labels.map((label, index) => ( diff --git a/frontend/src/pages/DataAnnotation/annotation.model.ts b/frontend/src/pages/DataAnnotation/annotation.model.ts index e74859a..42b4e23 100644 --- a/frontend/src/pages/DataAnnotation/annotation.model.ts +++ b/frontend/src/pages/DataAnnotation/annotation.model.ts @@ -53,6 +53,12 @@ export interface TemplateConfiguration { labels: LabelDefinition[]; objects: ObjectDefinition[]; metadata?: Record; + /** + * 示例数据,用于模板预览 + * key: 变量名(不带$前缀,如 "image"、"text") + * value: 示例内容(URL 或文本) + */ + exampleData?: Record; } export interface AnnotationTemplate { diff --git a/frontend/src/pages/DataAnnotation/components/TemplateConfigurationForm.tsx b/frontend/src/pages/DataAnnotation/components/TemplateConfigurationForm.tsx index 90995ea..708039c 100644 --- a/frontend/src/pages/DataAnnotation/components/TemplateConfigurationForm.tsx +++ b/frontend/src/pages/DataAnnotation/components/TemplateConfigurationForm.tsx @@ -8,11 +8,15 @@ import { Divider, Card, Checkbox, + Typography, + Image, } from "antd"; import { PlusOutlined, MinusCircleOutlined } from "@ant-design/icons"; import TagSelector from "../Template/components/TagSelector"; const { Option } = Select; +const { TextArea } = Input; +const { Text } = Typography; interface TemplateConfigurationFormProps { form: any; @@ -27,6 +31,31 @@ const TemplateConfigurationForm: React.FC = ({ ); }; + /** 判断对象类型是否为文本类 */ + const isTextType = (type: string) => { + return ["Text", "HyperText", "Table", "List"].includes(type); + }; + + /** 判断对象类型是否为图片类 */ + const isImageType = (type: string) => { + return ["Image"].includes(type); + }; + + /** 获取示例数据输入提示 */ + const getExamplePlaceholder = (type: string) => { + const map: Record = { + Text: "输入示例文本内容...", + HyperText: "输入示例 HTML 内容...", + Image: "输入图片 URL,如 https://example.com/image.jpg", + Audio: "输入音频 URL,如 https://example.com/audio.mp3", + Video: "输入视频 URL,如 https://example.com/video.mp4", + Table: "输入示例表格数据(JSON 格式)...", + List: "输入示例列表数据(JSON 格式)...", + TimeSeries: "输入时间序列数据 URL...", + }; + return map[type] || "输入示例数据..."; + }; + return ( <> 数据对象 @@ -287,6 +316,78 @@ const TemplateConfigurationForm: React.FC = ({ )} + + 示例数据(可选) + + + 为数据对象提供示例数据,帮助用户在模板预览时直观了解标注效果 + + prev.objects !== curr.objects}> + {({ getFieldValue }) => { + const objects = getFieldValue("objects") || []; + if (objects.length === 0) { + return ( + 请先添加数据对象 + ); + } + return ( + + {objects.map((obj: any, index: number) => { + if (!obj?.name) return null; + const varName = obj.value?.replace(/^\$/, "") || obj.name; + const objType = obj.type || "Text"; + + return ( + + +
+ {obj.name} + + ({objType}) + +
+ + {isTextType(objType) ? ( +