Files
DataMate/frontend/src/pages/DataAnnotation/Template/TemplateForm.tsx
Jerry Yan b36fdd2438 feat(annotation): 添加数据类型过滤功能到标签配置树编辑器
- 引入 DataType 枚举类型定义
- 根据数据类型动态过滤对象标签选项
- 在模板表单中添加数据类型监听
- 改进错误处理逻辑以提高类型安全性
- 集成数据类型参数到配置树编辑器组件
2026-02-02 20:37:38 +08:00

212 lines
7.4 KiB
TypeScript

import React, { useState, useEffect } from "react";
import {
Modal,
Form,
Input,
Select,
Space,
message,
} from "antd";
import {
createAnnotationTemplateUsingPost,
updateAnnotationTemplateByIdUsingPut,
} from "../annotation.api";
import type { AnnotationTemplate } from "../annotation.model";
import { DataTypeMap, ClassificationMap, AnnotationTypeMap } from "../annotation.const";
import TemplateConfigurationTreeEditor from "../components/TemplateConfigurationTreeEditor";
const { TextArea } = Input;
const { Option } = Select;
interface TemplateFormProps {
visible: boolean;
mode: "create" | "edit";
template?: AnnotationTemplate;
onSuccess: () => void;
onCancel: () => void;
}
const TemplateForm: React.FC<TemplateFormProps> = ({
visible,
mode,
template,
onSuccess,
onCancel,
}) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [labelConfig, setLabelConfig] = useState("");
const selectedDataType = Form.useWatch("dataType", form);
useEffect(() => {
if (visible && template && mode === "edit") {
form.setFieldsValue({
name: template.name,
description: template.description,
dataType: template.dataType,
labelingType: template.labelingType,
style: template.style,
category: template.category,
});
setLabelConfig(template.labelConfig || "");
} else if (visible && mode === "create") {
form.resetFields();
// Set default values
form.setFieldsValue({
style: "horizontal",
category: "custom",
});
setLabelConfig("");
}
}, [visible, template, mode, form]);
const handleSubmit = async () => {
try {
const values = await form.validateFields();
if (!labelConfig.trim()) {
message.error("请配置标注模板");
return;
}
setLoading(true);
console.log("Form values:", values);
const requestData = {
name: values.name,
description: values.description,
dataType: values.dataType,
labelingType: values.labelingType,
style: values.style,
category: values.category,
labelConfig: labelConfig.trim(),
};
console.log("Request data:", requestData);
let response;
if (mode === "create") {
response = await createAnnotationTemplateUsingPost(requestData);
} else {
response = await updateAnnotationTemplateByIdUsingPut(template!.id, requestData);
}
if (response.code === 200) {
message.success(`模板${mode === "create" ? "创建" : "更新"}成功`);
form.resetFields();
onSuccess();
} else {
message.error(response.message || `模板${mode === "create" ? "创建" : "更新"}失败`);
}
} catch (error: unknown) {
const hasErrorFields =
typeof error === "object" &&
error !== null &&
"errorFields" in error;
if (hasErrorFields) {
message.error("请填写所有必填字段");
} else {
message.error(`模板${mode === "create" ? "创建" : "更新"}失败`);
console.error(error);
}
} finally {
setLoading(false);
}
};
return (
<Modal
title={mode === "create" ? "创建模板" : "编辑模板"}
open={visible}
onCancel={onCancel}
onOk={handleSubmit}
confirmLoading={loading}
width={900}
destroyOnClose
>
<Form
form={form}
layout="vertical"
style={{ maxHeight: "70vh", overflowY: "auto", paddingRight: 8 }}
>
<Form.Item
label="模板名称"
name="name"
rules={[{ required: true, message: "请输入模板名称" }]}
>
<Input placeholder="例如:产品质量分类" maxLength={100} />
</Form.Item>
<Form.Item label="描述" name="description">
<TextArea
placeholder="描述此模板的用途"
rows={2}
maxLength={500}
/>
</Form.Item>
<Space style={{ width: "100%" }} size="large" wrap>
<Form.Item
label="数据类型"
name="dataType"
rules={[{ required: true, message: "请选择数据类型" }]}
style={{ width: 200 }}
>
<Select placeholder="选择数据类型">
{Object.entries(DataTypeMap).map(([key, item]) => (
<Option key={key} value={item.value}>{item.label}</Option>
))}
</Select>
</Form.Item>
<Form.Item
label="标注类型"
name="labelingType"
rules={[{ required: true, message: "请选择标注类型" }]}
style={{ width: 220 }}
>
<Select placeholder="选择标注类型" showSearch optionFilterProp="children">
{Object.entries(AnnotationTypeMap).map(([key, item]) => (
<Option key={key} value={item.value}>{item.label}</Option>
))}
</Select>
</Form.Item>
<Form.Item
label="样式"
name="style"
style={{ width: 150 }}
>
<Select>
<Option value="horizontal"></Option>
<Option value="vertical"></Option>
</Select>
</Form.Item>
<Form.Item
label="分类"
name="category"
style={{ width: 180 }}
>
<Select showSearch optionFilterProp="children">
{Object.entries(ClassificationMap).map(([key, item]) => (
<Option key={key} value={item.value}>{item.label}</Option>
))}
</Select>
</Form.Item>
</Space>
<div className="bg-gray-50 p-4 rounded-md border border-gray-200">
<TemplateConfigurationTreeEditor
value={labelConfig}
onChange={setLabelConfig}
height={420}
dataType={selectedDataType}
/>
</div>
</Form>
</Modal>
);
};
export default TemplateForm;