You've already forked DataMate
- 引入 DataType 枚举类型定义 - 根据数据类型动态过滤对象标签选项 - 在模板表单中添加数据类型监听 - 改进错误处理逻辑以提高类型安全性 - 集成数据类型参数到配置树编辑器组件
212 lines
7.4 KiB
TypeScript
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;
|