deploy-ease-platform/frontend/src/pages/Workflow/Design/components/NodeConfigModal.tsx
dengqichen 79c9804dbd 1
2025-10-20 17:50:37 +08:00

204 lines
6.8 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, { useEffect, useState } from 'react';
import { Tabs } from 'antd';
import { Cell } from '@antv/x6';
import type { WorkflowNodeDefinition, ConfigurableNodeDefinition } from "../nodes/types";
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
} from "@/components/ui/sheet";
import { Button } from "@/components/ui/button";
import { convertJsonSchemaToColumns } from '@/utils/jsonSchemaUtils';
import { BetaSchemaForm } from '@ant-design/pro-components';
interface NodeConfigModalProps {
visible: boolean;
node: Cell | null;
nodeDefinition: WorkflowNodeDefinition | null;
onOk: (values: any) => void;
onCancel: () => void;
}
interface FormData {
configs?: Record<string, any>;
inputMapping?: Record<string, any>;
outputMapping?: Record<string, any>;
}
const NodeConfigModal: React.FC<NodeConfigModalProps> = ({
visible,
node,
nodeDefinition,
onOk,
onCancel,
}) => {
const [formData, setFormData] = useState<FormData>({});
const [activeTab, setActiveTab] = useState('config');
// 判断是否为可配置节点
const isConfigurableNode = (def: WorkflowNodeDefinition): def is ConfigurableNodeDefinition => {
return 'inputMappingSchema' in def || 'outputMappingSchema' in def;
};
useEffect(() => {
if (nodeDefinition && node) {
// 从节点数据中获取现有配置
const nodeData = node.getData() || {};
// 准备默认的基本信息配置
const defaultConfig = {
nodeName: nodeDefinition.nodeName, // 默认节点名称
nodeCode: nodeDefinition.nodeCode, // 默认节点编码
description: nodeDefinition.description // 默认节点描述
};
// 合并默认值和已保存的配置
setFormData({
configs: { ...defaultConfig, ...(nodeData.configs || {}) },
inputMapping: nodeData.inputMapping || {},
outputMapping: nodeData.outputMapping || {},
});
} else {
setFormData({});
}
}, [nodeDefinition, node]);
const handleSubmit = () => {
onOk(formData);
};
const handleConfigChange = (values: Record<string, any>) => {
setFormData(prev => ({
...prev,
configs: values
}));
};
const handleInputMappingChange = (values: Record<string, any>) => {
setFormData(prev => ({
...prev,
inputMapping: values
}));
};
const handleOutputMappingChange = (values: Record<string, any>) => {
setFormData(prev => ({
...prev,
outputMapping: values
}));
};
if (!nodeDefinition) {
return null;
}
// 构建Tabs配置
const tabItems = [
{
key: 'config',
label: '基本配置',
children: (
<div style={{ padding: '16px 0' }}>
<BetaSchemaForm
key={`configs-${node?.id}-${JSON.stringify(formData.configs)}`}
layoutType="Form"
columns={convertJsonSchemaToColumns(nodeDefinition.configSchema as any)}
initialValues={formData.configs}
onValuesChange={(_, allValues) => handleConfigChange(allValues)}
submitter={false}
/>
</div>
),
},
];
// 如果是可配置节点添加输入和输出映射TAB
if (isConfigurableNode(nodeDefinition)) {
if (nodeDefinition.inputMappingSchema) {
tabItems.push({
key: 'input',
label: '输入映射',
children: (
<div style={{ padding: '16px 0' }}>
<BetaSchemaForm
key={`input-${node?.id}-${JSON.stringify(formData.inputMapping)}`}
layoutType="Form"
columns={convertJsonSchemaToColumns(nodeDefinition.inputMappingSchema as any)}
initialValues={formData.inputMapping}
onValuesChange={(_, allValues) => handleInputMappingChange(allValues)}
submitter={false}
/>
</div>
),
});
}
if (nodeDefinition.outputMappingSchema) {
tabItems.push({
key: 'output',
label: '输出映射',
children: (
<div style={{ padding: '16px 0' }}>
<BetaSchemaForm
key={`output-${node?.id}-${JSON.stringify(formData.outputMapping)}`}
layoutType="Form"
columns={convertJsonSchemaToColumns(nodeDefinition.outputMappingSchema as any)}
initialValues={formData.outputMapping}
onValuesChange={(_, allValues) => handleOutputMappingChange(allValues)}
submitter={false}
/>
</div>
),
});
}
}
return (
<Sheet open={visible} onOpenChange={(open) => !open && onCancel()}>
<SheetContent
style={{
width: '600px',
maxWidth: '90vw',
display: 'flex',
flexDirection: 'column'
}}
>
<SheetHeader>
<SheetTitle>
- {nodeDefinition.nodeName}
</SheetTitle>
</SheetHeader>
<div style={{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
<Tabs
activeKey={activeTab}
onChange={setActiveTab}
items={tabItems}
style={{ flex: 1, display: 'flex', flexDirection: 'column' }}
className="flex-tabs"
/>
</div>
<div
style={{
borderTop: '1px solid #f0f0f0',
padding: '16px 0 0 0',
display: 'flex',
justifyContent: 'flex-end',
gap: '8px'
}}
>
<Button variant="outline" onClick={onCancel}>
</Button>
<Button onClick={handleSubmit}>
</Button>
</div>
</SheetContent>
</Sheet>
);
};
export default NodeConfigModal;