deploy-ease-platform/frontend/src/pages/Workflow2/Design/components/NodeConfigModal.tsx
dengqichen 20c4184d45 1
2025-10-20 21:38:09 +08:00

257 lines
7.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import { Modal, Form, Input, Tabs, Card, Button, Space, message } from 'antd';
import { SaveOutlined, ReloadOutlined } from '@ant-design/icons';
import type { FlowNode, FlowNodeData } from '../types';
interface NodeConfigModalProps {
visible: boolean;
node: FlowNode | null;
onCancel: () => void;
onOk: (nodeId: string, updatedData: Partial<FlowNodeData>) => void;
}
const { TextArea } = Input;
const NodeConfigModal: React.FC<NodeConfigModalProps> = ({
visible,
node,
onCancel,
onOk
}) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [activeTab, setActiveTab] = useState('basic');
// 重置表单数据
useEffect(() => {
if (visible && node) {
form.setFieldsValue({
label: node.data.label,
description: node.data.nodeDefinition?.description || '',
// 基础配置
timeout: node.data.configs?.timeout || 3600,
retryCount: node.data.configs?.retryCount || 0,
priority: node.data.configs?.priority || 'normal',
// 输入映射
inputMapping: JSON.stringify(node.data.inputMapping || {}, null, 2),
// 输出映射
outputMapping: JSON.stringify(node.data.outputMapping || {}, null, 2),
});
} else {
form.resetFields();
}
}, [visible, node, form]);
const handleSubmit = async () => {
if (!node) return;
try {
const values = await form.validateFields();
setLoading(true);
// 解析JSON字符串
let inputMapping = {};
let outputMapping = {};
try {
inputMapping = values.inputMapping ? JSON.parse(values.inputMapping) : {};
} catch (error) {
message.error('输入映射JSON格式错误');
return;
}
try {
outputMapping = values.outputMapping ? JSON.parse(values.outputMapping) : {};
} catch (error) {
message.error('输出映射JSON格式错误');
return;
}
const updatedData: Partial<FlowNodeData> = {
label: values.label,
configs: {
...node.data.configs,
timeout: values.timeout,
retryCount: values.retryCount,
priority: values.priority,
},
inputMapping,
outputMapping,
};
onOk(node.id, updatedData);
message.success('节点配置保存成功');
onCancel();
} catch (error) {
console.error('保存节点配置失败:', error);
} finally {
setLoading(false);
}
};
const handleReset = () => {
form.resetFields();
if (node) {
form.setFieldsValue({
label: node.data.label,
description: node.data.nodeDefinition?.description || '',
timeout: 3600,
retryCount: 0,
priority: 'normal',
inputMapping: '{}',
outputMapping: '{}',
});
}
};
const renderBasicConfig = () => (
<Card size="small" title="基本信息">
<Form.Item
label="节点名称"
name="label"
rules={[{ required: true, message: '请输入节点名称' }]}
>
<Input placeholder="请输入节点名称" />
</Form.Item>
<Form.Item label="节点描述" name="description">
<TextArea
placeholder="请输入节点描述"
rows={3}
maxLength={500}
showCount
/>
</Form.Item>
<Form.Item
label="超时时间(秒)"
name="timeout"
rules={[{ required: true, message: '请输入超时时间' }]}
>
<Input type="number" min={1} placeholder="3600" />
</Form.Item>
<Form.Item
label="重试次数"
name="retryCount"
>
<Input type="number" min={0} max={10} placeholder="0" />
</Form.Item>
<Form.Item
label="优先级"
name="priority"
>
<Input placeholder="normal" />
</Form.Item>
</Card>
);
const renderInputMapping = () => (
<Card size="small" title="输入参数映射">
<Form.Item
label="输入映射配置"
name="inputMapping"
extra="请输入有效的JSON格式用于配置节点的输入参数映射"
>
<TextArea
placeholder={`示例:
{
"param1": "\${workflow.variable1}",
"param2": "固定值",
"param3": "\${previous.output.result}"
}`}
rows={12}
style={{ fontFamily: 'Monaco, Consolas, monospace' }}
/>
</Form.Item>
</Card>
);
const renderOutputMapping = () => (
<Card size="small" title="输出参数映射">
<Form.Item
label="输出映射配置"
name="outputMapping"
extra="请输入有效的JSON格式用于配置节点的输出参数映射"
>
<TextArea
placeholder={`示例:
{
"result": "\${task.output.result}",
"status": "\${task.status}",
"message": "\${task.output.message}"
}`}
rows={12}
style={{ fontFamily: 'Monaco, Consolas, monospace' }}
/>
</Form.Item>
</Card>
);
return (
<Modal
title={`配置节点: ${node?.data?.label || '未知节点'}`}
open={visible}
onCancel={onCancel}
width={800}
style={{ top: 20 }}
footer={
<Space>
<Button onClick={onCancel}></Button>
<Button
icon={<ReloadOutlined />}
onClick={handleReset}
>
</Button>
<Button
type="primary"
loading={loading}
icon={<SaveOutlined />}
onClick={handleSubmit}
>
</Button>
</Space>
}
>
<Form
form={form}
layout="vertical"
initialValues={{
timeout: 3600,
retryCount: 0,
priority: 'normal',
inputMapping: '{}',
outputMapping: '{}'
}}
>
<Tabs
activeKey={activeTab}
onChange={setActiveTab}
items={[
{
key: 'basic',
label: '基本配置',
children: renderBasicConfig()
},
{
key: 'input',
label: '输入映射',
children: renderInputMapping()
},
{
key: 'output',
label: '输出映射',
children: renderOutputMapping()
}
]}
/>
</Form>
</Modal>
);
};
export default NodeConfigModal;