1
This commit is contained in:
parent
d8cc3c0983
commit
debef2f881
@ -1,13 +1,13 @@
|
|||||||
import React, { useEffect, ReactNode } from 'react';
|
import React, {useEffect, ReactNode} from 'react';
|
||||||
import { Drawer, Form, Input, Select, Button, Space, Divider, Tooltip } from 'antd';
|
import {Drawer, Form, Input, Select, Button, Space, Divider, Tooltip} from 'antd';
|
||||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
import {InfoCircleOutlined} from '@ant-design/icons';
|
||||||
import { Cell } from '@antv/x6';
|
import {Cell} from '@antv/x6';
|
||||||
import { NodeDefinition } from '../types';
|
import {NodeDefinitionResponse} from "@/pages/Workflow/NodeDesign/types";
|
||||||
|
|
||||||
interface NodeConfigDrawerProps {
|
interface NodeConfigDrawerProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
node: Cell | null;
|
node: Cell | null;
|
||||||
nodeDefinition: NodeDefinition | null;
|
nodeDefinition: NodeDefinitionResponse | null;
|
||||||
onOk: (values: any) => void;
|
onOk: (values: any) => void;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
}
|
}
|
||||||
@ -22,11 +22,11 @@ interface SchemaProperty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const NodeConfigDrawer: React.FC<NodeConfigDrawerProps> = ({
|
const NodeConfigDrawer: React.FC<NodeConfigDrawerProps> = ({
|
||||||
visible,
|
visible,
|
||||||
node,
|
node,
|
||||||
nodeDefinition,
|
nodeDefinition,
|
||||||
onOk,
|
onOk,
|
||||||
onCancel,
|
onCancel,
|
||||||
}) => {
|
}) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
@ -34,19 +34,8 @@ const NodeConfigDrawer: React.FC<NodeConfigDrawerProps> = ({
|
|||||||
if (visible && node && nodeDefinition) {
|
if (visible && node && nodeDefinition) {
|
||||||
const currentConfig = node.getProp('config') || {};
|
const currentConfig = node.getProp('config') || {};
|
||||||
if (!currentConfig.name) {
|
if (!currentConfig.name) {
|
||||||
currentConfig.name = nodeDefinition.name;
|
currentConfig.name = nodeDefinition.nodeName;
|
||||||
}
|
}
|
||||||
// 从节点定义中获取 delegate 的默认值
|
|
||||||
const defaultDelegate = nodeDefinition.graphConfig.configSchema?.properties?.delegate?.default;
|
|
||||||
// 优先使用当前配置的值,如果没有则使用默认值
|
|
||||||
const delegateValue = currentConfig.delegate !== undefined ? currentConfig.delegate : defaultDelegate;
|
|
||||||
|
|
||||||
// 设置表单值,包括 code 和其他配置项
|
|
||||||
form.setFieldsValue({
|
|
||||||
code: node.getProp('code') === undefined ? nodeDefinition.graphConfig.code : node.getProp('code'),
|
|
||||||
delegate: delegateValue, // 使用当前值或默认值
|
|
||||||
...currentConfig
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [visible, node, nodeDefinition, form]);
|
}, [visible, node, nodeDefinition, form]);
|
||||||
|
|
||||||
@ -73,12 +62,12 @@ const NodeConfigDrawer: React.FC<NodeConfigDrawerProps> = ({
|
|||||||
{property.title}
|
{property.title}
|
||||||
{property.description && (
|
{property.description && (
|
||||||
<Tooltip title={property.description}>
|
<Tooltip title={property.description}>
|
||||||
<InfoCircleOutlined />
|
<InfoCircleOutlined/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
),
|
),
|
||||||
rules: [{ required, message: `请输入${property.title}` }],
|
rules: [{required, message: `请输入${property.title}`}],
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (property.type) {
|
switch (property.type) {
|
||||||
@ -99,16 +88,16 @@ const NodeConfigDrawer: React.FC<NodeConfigDrawerProps> = ({
|
|||||||
return (
|
return (
|
||||||
<Form.Item key={key} {...baseProps}>
|
<Form.Item key={key} {...baseProps}>
|
||||||
{property.format === 'textarea' ? (
|
{property.format === 'textarea' ? (
|
||||||
<Input.TextArea rows={3} />
|
<Input.TextArea rows={3}/>
|
||||||
) : (
|
) : (
|
||||||
<Input />
|
<Input/>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
case 'number':
|
case 'number':
|
||||||
return (
|
return (
|
||||||
<Form.Item key={key} {...baseProps}>
|
<Form.Item key={key} {...baseProps}>
|
||||||
<Input type="number" />
|
<Input type="number"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
@ -131,7 +120,7 @@ const NodeConfigDrawer: React.FC<NodeConfigDrawerProps> = ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { configSchema } = nodeDefinition.graphConfig;
|
const {configSchema} = nodeDefinition.graphConfig;
|
||||||
console.log('NodeConfigModal - Rendering form items with schema:', configSchema);
|
console.log('NodeConfigModal - Rendering form items with schema:', configSchema);
|
||||||
|
|
||||||
const formItems: ReactNode[] = [];
|
const formItems: ReactNode[] = [];
|
||||||
@ -155,7 +144,7 @@ const NodeConfigDrawer: React.FC<NodeConfigDrawerProps> = ({
|
|||||||
const renderNodeDetails = () => {
|
const renderNodeDetails = () => {
|
||||||
if (!nodeDefinition?.graphConfig.details) return null;
|
if (!nodeDefinition?.graphConfig.details) return null;
|
||||||
|
|
||||||
const { details } = nodeDefinition.graphConfig;
|
const {details} = nodeDefinition.graphConfig;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Divider orientation="left">节点说明</Divider>
|
<Divider orientation="left">节点说明</Divider>
|
||||||
@ -188,7 +177,7 @@ const NodeConfigDrawer: React.FC<NodeConfigDrawerProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
title={`编辑节点 - ${nodeDefinition?.graphConfig.name || ''}`}
|
title={`编辑节点 - ${nodeDefinition?.nodeName || ''}`}
|
||||||
placement="right"
|
placement="right"
|
||||||
width={480}
|
width={480}
|
||||||
onClose={handleCancel}
|
onClose={handleCancel}
|
||||||
@ -210,16 +199,14 @@ const NodeConfigDrawer: React.FC<NodeConfigDrawerProps> = ({
|
|||||||
initialValues={{}}
|
initialValues={{}}
|
||||||
>
|
>
|
||||||
<Form.Item name="code" hidden>
|
<Form.Item name="code" hidden>
|
||||||
<Input />
|
<Input/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="delegate" hidden>
|
<Form.Item name="delegate" hidden>
|
||||||
<Input />
|
<Input/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{nodeDefinition?.graphConfig.configSchema &&
|
{nodeDefinition?.panelVariablesSchema &&
|
||||||
Object.entries(nodeDefinition.graphConfig.configSchema.properties).map(([key, property]) => {
|
Object.entries(nodeDefinition.panelVariablesSchema.properties).map(([key, property]) => {
|
||||||
// 跳过 code 和 delegate 字段的显示
|
const required = nodeDefinition.panelVariablesSchema?.properties.required?.includes(key) || false;
|
||||||
if (key === 'code' || key === 'delegate') return null;
|
|
||||||
const required = nodeDefinition.graphConfig.configSchema.required?.includes(key) || false;
|
|
||||||
return renderFormItem(key, property as SchemaProperty, required);
|
return renderFormItem(key, property as SchemaProperty, required);
|
||||||
})}
|
})}
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, {useState, useEffect} from 'react';
|
import React, {useState, useEffect} from 'react';
|
||||||
import {Card, Collapse, Tooltip, message, Spin} from 'antd';
|
import {Card, Collapse, Tooltip, message} from 'antd';
|
||||||
import type {NodeDefinition, NodeCategory} from '../types';
|
import type {NodeDefinition, NodeCategory} from '../types';
|
||||||
import {
|
import {
|
||||||
PlayCircleOutlined,
|
PlayCircleOutlined,
|
||||||
@ -13,6 +13,7 @@ import {
|
|||||||
BranchesOutlined
|
BranchesOutlined
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {getNodeDefinitionList} from "@/pages/Workflow/Definition/Design/service";
|
import {getNodeDefinitionList} from "@/pages/Workflow/Definition/Design/service";
|
||||||
|
import {NodeDefinitionResponse} from "@/pages/Workflow/NodeDesign/types";
|
||||||
|
|
||||||
const {Panel} = Collapse;
|
const {Panel} = Collapse;
|
||||||
|
|
||||||
@ -53,19 +54,20 @@ const categoryConfig: Record<NodeCategory, {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface NodePanelProps {
|
interface NodePanelProps {
|
||||||
onNodeDragStart?: (node: NodeDefinition, e: React.DragEvent) => void,
|
onNodeDragStart?: (node: NodeDefinitionResponse, e: React.DragEvent) => void,
|
||||||
nodeDefinitions?: NodeDefinition[]
|
nodeDefinitions?: NodeDefinitionResponse[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const NodePanel: React.FC<NodePanelProps> = ({onNodeDragStart}) => {
|
const NodePanel: React.FC<NodePanelProps> = ({onNodeDragStart}) => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [nodeDefinitions, setNodeDefinitions] = useState<NodeDefinition[]>([]);
|
const [nodeDefinitions, setNodeDefinitions] = useState<NodeDefinitionResponse[]>([]);
|
||||||
|
|
||||||
// 加载节点定义列表
|
// 加载节点定义列表
|
||||||
const loadNodeDefinitions = async () => {
|
const loadNodeDefinitions = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const data = await getNodeDefinitionList();
|
const data = await getNodeDefinitionList();
|
||||||
|
console.log(data)
|
||||||
setNodeDefinitions(data);
|
setNodeDefinitions(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
@ -87,29 +89,29 @@ const NodePanel: React.FC<NodePanelProps> = ({onNodeDragStart}) => {
|
|||||||
}
|
}
|
||||||
acc[node.category].push(node);
|
acc[node.category].push(node);
|
||||||
return acc;
|
return acc;
|
||||||
}, {} as Record<NodeCategory, NodeDefinition[]>);
|
}, {} as Record<NodeCategory, NodeDefinitionResponse[]>);
|
||||||
|
|
||||||
// 处理节点拖拽开始事件
|
// 处理节点拖拽开始事件
|
||||||
const handleDragStart = (node: NodeDefinition, e: React.DragEvent) => {
|
const handleDragStart = (node: NodeDefinitionResponse, e: React.DragEvent) => {
|
||||||
e.dataTransfer.setData('node', JSON.stringify(node));
|
e.dataTransfer.setData('node', JSON.stringify(node));
|
||||||
onNodeDragStart?.(node, e);
|
onNodeDragStart?.(node, e);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 渲染节点图标
|
// 渲染节点图标
|
||||||
const renderNodeIcon = (node: NodeDefinition) => {
|
const renderNodeIcon = (node: NodeDefinitionResponse) => {
|
||||||
const iconName = node.graphConfig.uiSchema.style.icon;
|
const iconName = node.uiVariables?.style.icon;
|
||||||
// 首先尝试使用配置的图标
|
// 首先尝试使用配置的图标
|
||||||
let IconComponent = iconMap[iconName];
|
let IconComponent = iconMap[iconName];
|
||||||
|
|
||||||
// 如果没有找到对应的图标,使用节点类型对应的默认图标
|
// 如果没有找到对应的图标,使用节点类型对应的默认图标
|
||||||
if (!IconComponent) {
|
if (!IconComponent) {
|
||||||
IconComponent = typeIconMap[node.type] || AppstoreOutlined;
|
IconComponent = typeIconMap[node.nodeType] || AppstoreOutlined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconComponent
|
<IconComponent
|
||||||
style={{
|
style={{
|
||||||
color: node.graphConfig.uiSchema.style.iconColor || '#1890ff',
|
color: node.uiVariables?.style.iconColor || '#1890ff',
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
marginRight: '6px'
|
marginRight: '6px'
|
||||||
}}
|
}}
|
||||||
@ -117,17 +119,17 @@ const NodePanel: React.FC<NodePanelProps> = ({onNodeDragStart}) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getNodeItemStyle = (node: NodeDefinition) => ({
|
const getNodeItemStyle = (node: NodeDefinitionResponse) => ({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
padding: '10px 12px',
|
padding: '10px 12px',
|
||||||
border: `1px solid ${node.graphConfig.uiSchema.style.stroke}`,
|
border: `1px solid ${node.uiVariables?.style.stroke}`,
|
||||||
borderRadius: '6px',
|
borderRadius: '6px',
|
||||||
cursor: 'move',
|
cursor: 'move',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
background: node.graphConfig.uiSchema.style.fill,
|
background: node.uiVariables?.style.fill,
|
||||||
transition: 'all 0.3s',
|
transition: 'all 0.3s',
|
||||||
boxShadow: '0 1px 2px rgba(0,0,0,0.05)',
|
boxShadow: '0 1px 2px rgba(0,0,0,0.05)',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
@ -163,19 +165,6 @@ const NodePanel: React.FC<NodePanelProps> = ({onNodeDragStart}) => {
|
|||||||
title={
|
title={
|
||||||
<div>
|
<div>
|
||||||
<div style={{fontSize: '14px', fontWeight: 500}}>{node.description}</div>
|
<div style={{fontSize: '14px', fontWeight: 500}}>{node.description}</div>
|
||||||
<div style={{marginTop: 12}}>
|
|
||||||
<div style={{fontSize: '13px', color: '#8c8c8c'}}>功能特点:</div>
|
|
||||||
<ul style={{
|
|
||||||
paddingLeft: 16,
|
|
||||||
margin: '8px 0',
|
|
||||||
fontSize: '13px',
|
|
||||||
color: '#595959'
|
|
||||||
}}>
|
|
||||||
{node.graphConfig.details.features.map((feature, index) => (
|
|
||||||
<li key={index}>{feature}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
overlayStyle={tooltipStyle}
|
overlayStyle={tooltipStyle}
|
||||||
@ -201,7 +190,7 @@ const NodePanel: React.FC<NodePanelProps> = ({onNodeDragStart}) => {
|
|||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
}}>{node.name}</span>
|
}}>{node.nodeName}({node.nodeType})</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
@ -43,6 +43,7 @@ import {
|
|||||||
DEFAULT_STYLES,
|
DEFAULT_STYLES,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
import {NodeDefinitionResponse, NodeDesignDataResponse} from "@/pages/Workflow/NodeDesign/types";
|
||||||
|
|
||||||
const WorkflowDesign: React.FC = () => {
|
const WorkflowDesign: React.FC = () => {
|
||||||
const {id} = useParams<{ id: string }>();
|
const {id} = useParams<{ id: string }>();
|
||||||
@ -52,10 +53,10 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
const minimapContainerRef = useRef<HTMLDivElement>(null);
|
const minimapContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const [graph, setGraph] = useState<Graph | null>(null);
|
const [graph, setGraph] = useState<Graph | null>(null);
|
||||||
const [selectedNode, setSelectedNode] = useState<Cell | null>(null);
|
const [selectedNode, setSelectedNode] = useState<Cell | null>(null);
|
||||||
const [selectedNodeDefinition, setSelectedNodeDefinition] = useState<NodeDefinition | null>(null);
|
const [selectedNodeDefinition, setSelectedNodeDefinition] = useState<NodeDefinitionResponse | null>(null);
|
||||||
const [configModalVisible, setConfigModalVisible] = useState(false);
|
const [configModalVisible, setConfigModalVisible] = useState(false);
|
||||||
const [definitionData, setDefinitionData] = useState<any>(null);
|
const [definitionData, setDefinitionData] = useState<any>(null);
|
||||||
const [nodeDefinitions, setNodeDefinitions] = useState<NodeDefinition[]>([]);
|
const [nodeDefinitions, setNodeDefinitions] = useState<NodeDefinitionResponse[]>([]);
|
||||||
const [isNodeDefinitionsLoaded, setIsNodeDefinitionsLoaded] = useState(false);
|
const [isNodeDefinitionsLoaded, setIsNodeDefinitionsLoaded] = useState(false);
|
||||||
const [forceUpdate, setForceUpdate] = useState(false);
|
const [forceUpdate, setForceUpdate] = useState(false);
|
||||||
const [scale, setScale] = useState(1);
|
const [scale, setScale] = useState(1);
|
||||||
@ -571,9 +572,8 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
// 节点双击事件
|
// 节点双击事件
|
||||||
graph.on('node:dblclick', ({node}) => {
|
graph.on('node:dblclick', ({node}) => {
|
||||||
const nodeType = node.getProp('type');
|
const nodeType = node.getProp('type');
|
||||||
console.log(nodeType)
|
|
||||||
// 从节点定义列表中找到对应的定义
|
// 从节点定义列表中找到对应的定义
|
||||||
const nodeDefinition = nodeDefinitions.find(def => def.type === nodeType);
|
const nodeDefinition = nodeDefinitions.find(def => def.nodeType === nodeType);
|
||||||
if (nodeDefinition) {
|
if (nodeDefinition) {
|
||||||
setSelectedNode(node);
|
setSelectedNode(node);
|
||||||
setSelectedNodeDefinition(nodeDefinition);
|
setSelectedNodeDefinition(nodeDefinition);
|
||||||
@ -1027,7 +1027,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
}, [graphContainerRef, id, nodeDefinitions, isNodeDefinitionsLoaded]);
|
}, [graphContainerRef, id, nodeDefinitions, isNodeDefinitionsLoaded]);
|
||||||
|
|
||||||
// 处理节点拖拽开始
|
// 处理节点拖拽开始
|
||||||
const handleNodeDragStart = (node: NodeDefinition, e: React.DragEvent) => {
|
const handleNodeDragStart = (node: NodeDefinitionResponse, e: React.DragEvent) => {
|
||||||
e.dataTransfer.setData('node', JSON.stringify(node));
|
e.dataTransfer.setData('node', JSON.stringify(node));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1043,6 +1043,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
const node = JSON.parse(nodeData);
|
const node = JSON.parse(nodeData);
|
||||||
const {clientX, clientY} = e;
|
const {clientX, clientY} = e;
|
||||||
const point = graph.clientToLocal({x: clientX, y: clientY});
|
const point = graph.clientToLocal({x: clientX, y: clientY});
|
||||||
|
console.log("dasdasd", graph, node, nodeDefinitions, point);
|
||||||
addNodeToGraph(true, graph, node, nodeDefinitions, point);
|
addNodeToGraph(true, graph, node, nodeDefinitions, point);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('创建节点失败:', error);
|
console.error('创建节点失败:', error);
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {convertPortConfig} from '../constants';
|
|||||||
* 添加节点到图形
|
* 添加节点到图形
|
||||||
* @param isNew 是否为新节点
|
* @param isNew 是否为新节点
|
||||||
* @param graph X6 Graph实例
|
* @param graph X6 Graph实例
|
||||||
* @param workflowDefinitionNode 工作流节点定义
|
* @param nodeDefinitions 工作流节点定义
|
||||||
* @param workflowNodeDefinitionList 工作流节点定义列表
|
* @param workflowNodeDefinitionList 工作流节点定义列表
|
||||||
* @param position 新节点的位置(可选)
|
* @param position 新节点的位置(可选)
|
||||||
* @returns 创建的节点实例
|
* @returns 创建的节点实例
|
||||||
@ -13,13 +13,13 @@ import {convertPortConfig} from '../constants';
|
|||||||
export const addNodeToGraph = (
|
export const addNodeToGraph = (
|
||||||
isNew: boolean,
|
isNew: boolean,
|
||||||
graph: Graph,
|
graph: Graph,
|
||||||
workflowDefinitionNode: any,
|
nodeDefinitions: any,
|
||||||
workflowNodeDefinitionList: any,
|
workflowNodeDefinitionList: any,
|
||||||
position?: { x: number; y: number }
|
position?: { x: number; y: number }
|
||||||
) => {
|
) => {
|
||||||
let nodeDefinition = workflowNodeDefinitionList.find(def => def.type === workflowDefinitionNode.type);
|
let nodeDefinition = workflowNodeDefinitionList.find(def => def.nodeType === nodeDefinitions.nodeType);
|
||||||
let uiGraph = isNew ? nodeDefinition.graphConfig.uiSchema : workflowDefinitionNode.graph;
|
let uiGraph = isNew ? nodeDefinition.uiVariables : nodeDefinitions.graph;
|
||||||
|
console.log(uiGraph)
|
||||||
// 根据形状类型设置正确的 shape
|
// 根据形状类型设置正确的 shape
|
||||||
let shape = 'rect'; // 默认使用矩形
|
let shape = 'rect'; // 默认使用矩形
|
||||||
if (uiGraph.shape === 'circle') {
|
if (uiGraph.shape === 'circle') {
|
||||||
@ -41,12 +41,12 @@ export const addNodeToGraph = (
|
|||||||
} : {})
|
} : {})
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
text: isNew ? nodeDefinition.name : workflowDefinitionNode.name
|
text: isNew ? nodeDefinition.nodeName : nodeDefinitions.name
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shape,
|
shape,
|
||||||
type: isNew ? nodeDefinition.type : workflowDefinitionNode.type,
|
type: isNew ? nodeDefinition.nodeType : nodeDefinitions.type,
|
||||||
code: uiGraph.code,
|
code: uiGraph.nodeCode,
|
||||||
ports: convertPortConfig(uiGraph.ports),
|
ports: convertPortConfig(uiGraph.ports),
|
||||||
nodeDefinition: nodeDefinition
|
nodeDefinition: nodeDefinition
|
||||||
};
|
};
|
||||||
@ -55,9 +55,9 @@ export const addNodeToGraph = (
|
|||||||
if (isNew && position) {
|
if (isNew && position) {
|
||||||
// 新节点:使用传入的position
|
// 新节点:使用传入的position
|
||||||
Object.assign(nodeConfig, { x: position.x, y: position.y });
|
Object.assign(nodeConfig, { x: position.x, y: position.y });
|
||||||
} else if (!isNew && workflowDefinitionNode.graph?.position) {
|
} else if (!isNew && nodeDefinitions.graph?.position) {
|
||||||
// 已有节点:使用后端返回的position
|
// 已有节点:使用后端返回的position
|
||||||
Object.assign(nodeConfig, { position: workflowDefinitionNode.graph.position });
|
Object.assign(nodeConfig, { position: nodeDefinitions.graph.position });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置节点ID(如果有)
|
// 设置节点ID(如果有)
|
||||||
|
|||||||
@ -65,8 +65,7 @@ const FormRenderer: React.FC<{
|
|||||||
schema: any;
|
schema: any;
|
||||||
path?: string;
|
path?: string;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
currentTab?: any;
|
}> = ({schema, path = '', readOnly = false}) => {
|
||||||
}> = ({schema, path = '', readOnly = false, currentTab}) => {
|
|
||||||
if (!schema || !schema.properties) return null;
|
if (!schema || !schema.properties) return null;
|
||||||
const renderPortConfig = (portSchema: any, portPath: string) => {
|
const renderPortConfig = (portSchema: any, portPath: string) => {
|
||||||
if (!portSchema || !portSchema.properties) return null;
|
if (!portSchema || !portSchema.properties) return null;
|
||||||
@ -86,12 +85,6 @@ const FormRenderer: React.FC<{
|
|||||||
required={portSchema.required?.includes('position')}
|
required={portSchema.required?.includes('position')}
|
||||||
initialValue={'default' in position ? position.default : undefined}
|
initialValue={'default' in position ? position.default : undefined}
|
||||||
style={{marginBottom: 16}}
|
style={{marginBottom: 16}}
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: portSchema.required?.includes('position'),
|
|
||||||
message: `请${position.type === 'string' ? '输入' : '选择'}${position.title}`
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
{readOnly ? (
|
{readOnly ? (
|
||||||
<span style={{color: '#666'}}>{position.default || '-'}</span>
|
<span style={{color: '#666'}}>{position.default || '-'}</span>
|
||||||
@ -119,7 +112,6 @@ const FormRenderer: React.FC<{
|
|||||||
schema={attrs}
|
schema={attrs}
|
||||||
path={`${portPath}.attrs`}
|
path={`${portPath}.attrs`}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
currentTab={currentTab}
|
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
@ -200,7 +192,6 @@ const FormRenderer: React.FC<{
|
|||||||
schema={value}
|
schema={value}
|
||||||
path={fieldPath}
|
path={fieldPath}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
currentTab={currentTab}
|
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
@ -216,15 +207,9 @@ const FormRenderer: React.FC<{
|
|||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
tooltip={value.description}
|
tooltip={value.description}
|
||||||
required={currentTab?.schemaKey === 'uiVariables' && schema.required?.includes(key)}
|
required={schema.required?.includes(key)}
|
||||||
initialValue={'default' in value ? value.default : undefined}
|
initialValue={'default' in value ? value.default : undefined}
|
||||||
style={{marginBottom: 16}}
|
style={{marginBottom: 16}}
|
||||||
rules={currentTab?.schemaKey === 'uiVariables' ? [
|
|
||||||
{
|
|
||||||
required: schema.required?.includes(key),
|
|
||||||
message: `请${value.type === 'string' ? '输入' : '选择'}${value.title}`
|
|
||||||
}
|
|
||||||
] : undefined}
|
|
||||||
>
|
>
|
||||||
{readOnly ? (
|
{readOnly ? (
|
||||||
<span style={{color: '#666'}}>{value.default || '-'}</span>
|
<span style={{color: '#666'}}>{value.default || '-'}</span>
|
||||||
@ -276,7 +261,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadNodeDetail = async () => {
|
const loadNodeDetail = async () => {
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const data = await service.getNodeDefinition(id);
|
const data = await service.getNodeDefinition(id);
|
||||||
@ -318,7 +303,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
console.log('选择节点:', node);
|
console.log('选择节点:', node);
|
||||||
console.log('当前编辑状态:', isEdit);
|
console.log('当前编辑状态:', isEdit);
|
||||||
console.log('当前编辑数据:', editData);
|
console.log('当前编辑数据:', editData);
|
||||||
|
|
||||||
setSelectedNode(node);
|
setSelectedNode(node);
|
||||||
// 更新表单数据
|
// 更新表单数据
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
@ -341,7 +326,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
try {
|
try {
|
||||||
const values = await form.validateFields();
|
const values = await form.validateFields();
|
||||||
console.log('Form values:', values);
|
console.log('Form values:', values);
|
||||||
|
|
||||||
// 提取基本信息字段
|
// 提取基本信息字段
|
||||||
const baseFields = {
|
const baseFields = {
|
||||||
nodeType: values['base.nodeType'],
|
nodeType: values['base.nodeType'],
|
||||||
@ -362,7 +347,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
// 处理颜色值转换为十六进制
|
// 处理颜色值转换为十六进制
|
||||||
const processColorValue = (value: any): any => {
|
const processColorValue = (value: any): any => {
|
||||||
if (!value || typeof value !== 'object') return value;
|
if (!value || typeof value !== 'object') return value;
|
||||||
|
|
||||||
// 如果是 ColorPicker 的值,转换为十六进制
|
// 如果是 ColorPicker 的值,转换为十六进制
|
||||||
if (value.metaColor) {
|
if (value.metaColor) {
|
||||||
const { r, g, b } = value.metaColor;
|
const { r, g, b } = value.metaColor;
|
||||||
@ -372,7 +357,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
};
|
};
|
||||||
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是普通对象,递归处理
|
// 如果是普通对象,递归处理
|
||||||
if (typeof value === 'object') {
|
if (typeof value === 'object') {
|
||||||
const result: any = {};
|
const result: any = {};
|
||||||
@ -381,39 +366,39 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 将扁平的键值对转换为嵌套对象
|
// 将扁平的键值对转换为嵌套对象
|
||||||
const convertToNestedObject = (flatObj: any) => {
|
const convertToNestedObject = (flatObj: any) => {
|
||||||
const result: any = {};
|
const result: any = {};
|
||||||
|
|
||||||
Object.keys(flatObj).forEach(key => {
|
Object.keys(flatObj).forEach(key => {
|
||||||
const parts = key.split('.');
|
const parts = key.split('.');
|
||||||
let current = result;
|
let current = result;
|
||||||
|
|
||||||
for (let i = 0; i < parts.length - 1; i++) {
|
for (let i = 0; i < parts.length - 1; i++) {
|
||||||
current[parts[i]] = current[parts[i]] || {};
|
current[parts[i]] = current[parts[i]] || {};
|
||||||
current = current[parts[i]];
|
current = current[parts[i]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理颜色值
|
// 处理颜色值
|
||||||
const value = processColorValue(flatObj[key]);
|
const value = processColorValue(flatObj[key]);
|
||||||
current[parts[parts.length - 1]] = value;
|
current[parts[parts.length - 1]] = value;
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveData = {
|
const saveData = {
|
||||||
...selectedNode,
|
...selectedNode,
|
||||||
...baseFields,
|
...baseFields,
|
||||||
uiVariables: convertToNestedObject(uiValues)
|
uiVariables: convertToNestedObject(uiValues)
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('Save data:', saveData);
|
console.log('Save data:', saveData);
|
||||||
|
|
||||||
// 根据是否是编辑模式调用不同的接口
|
// 根据是否是编辑模式调用不同的接口
|
||||||
if (isEdit && editData?.id) {
|
if (isEdit && editData?.id) {
|
||||||
await service.updateNodeDefinition(editData.id, saveData);
|
await service.updateNodeDefinition(editData.id, saveData);
|
||||||
@ -438,7 +423,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
console.log('当前 schema:', schema);
|
console.log('当前 schema:', schema);
|
||||||
console.log('是否编辑模式:', isEdit);
|
console.log('是否编辑模式:', isEdit);
|
||||||
console.log('编辑数据:', editData);
|
console.log('编辑数据:', editData);
|
||||||
|
|
||||||
// 如果是编辑模式且有保存的数据,合并到 schema
|
// 如果是编辑模式且有保存的数据,合并到 schema
|
||||||
if (isEdit && editData?.uiVariables) {
|
if (isEdit && editData?.uiVariables) {
|
||||||
console.log('开始合并 UI 配置数据');
|
console.log('开始合并 UI 配置数据');
|
||||||
@ -446,7 +431,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
// 处理颜色值
|
// 处理颜色值
|
||||||
const processColorValue = (value: any): string => {
|
const processColorValue = (value: any): string => {
|
||||||
if (!value || typeof value !== 'object') return value;
|
if (!value || typeof value !== 'object') return value;
|
||||||
|
|
||||||
// 如果是颜色对象结构
|
// 如果是颜色对象结构
|
||||||
if (value.metaColor) {
|
if (value.metaColor) {
|
||||||
const { r, g, b } = value.metaColor;
|
const { r, g, b } = value.metaColor;
|
||||||
@ -457,7 +442,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
};
|
};
|
||||||
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -466,7 +451,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
console.log('正在处理 schema:', schemaObj);
|
console.log('正在处理 schema:', schemaObj);
|
||||||
console.log('UI 数据:', uiData);
|
console.log('UI 数据:', uiData);
|
||||||
console.log('当前路径:', parentPath);
|
console.log('当前路径:', parentPath);
|
||||||
|
|
||||||
const result = {...schemaObj};
|
const result = {...schemaObj};
|
||||||
|
|
||||||
// 颜色字段路径列表
|
// 颜色字段路径列表
|
||||||
@ -484,7 +469,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
Object.keys(result.properties).forEach(key => {
|
Object.keys(result.properties).forEach(key => {
|
||||||
const currentPath = parentPath ? `${parentPath}.${key}` : key;
|
const currentPath = parentPath ? `${parentPath}.${key}` : key;
|
||||||
console.log('处理属性:', currentPath);
|
console.log('处理属性:', currentPath);
|
||||||
|
|
||||||
// 处理嵌套对象
|
// 处理嵌套对象
|
||||||
if (result.properties[key].type === 'object') {
|
if (result.properties[key].type === 'object') {
|
||||||
const nestedValue = currentPath.split('.').reduce((obj, key) => obj?.[key], uiData);
|
const nestedValue = currentPath.split('.').reduce((obj, key) => obj?.[key], uiData);
|
||||||
@ -492,7 +477,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
if (nestedValue !== undefined) {
|
if (nestedValue !== undefined) {
|
||||||
result.properties[key].default = nestedValue;
|
result.properties[key].default = nestedValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 处理基本类型
|
// 处理基本类型
|
||||||
else {
|
else {
|
||||||
const value = currentPath.split('.').reduce((obj, key) => obj?.[key], uiData);
|
const value = currentPath.split('.').reduce((obj, key) => obj?.[key], uiData);
|
||||||
@ -506,11 +491,11 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 递归处理嵌套属性
|
// 递归处理嵌套属性
|
||||||
result.properties[key] = mergeUiVariables(
|
result.properties[key] = mergeUiVariables(
|
||||||
result.properties[key],
|
result.properties[key],
|
||||||
uiData,
|
uiData,
|
||||||
currentPath
|
currentPath
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -527,7 +512,7 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
console.log('合并后的 schema:', mergedSchema);
|
console.log('合并后的 schema:', mergedSchema);
|
||||||
return mergedSchema;
|
return mergedSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('使用原始 schema');
|
console.log('使用原始 schema');
|
||||||
return schema;
|
return schema;
|
||||||
};
|
};
|
||||||
@ -551,8 +536,8 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
<Tabs
|
<Tabs
|
||||||
tabPosition="left"
|
tabPosition="left"
|
||||||
type="card"
|
type="card"
|
||||||
activeKey={isEdit && editData?.nodeType ?
|
activeKey={isEdit && editData?.nodeType ?
|
||||||
nodeDefinitionsDefined.find(n => n.nodeType === editData.nodeType)?.nodeCode || selectedNode?.nodeCode :
|
nodeDefinitionsDefined.find(n => n.nodeType === editData.nodeType)?.nodeCode || selectedNode?.nodeCode :
|
||||||
selectedNode?.nodeCode || ''
|
selectedNode?.nodeCode || ''
|
||||||
}
|
}
|
||||||
onChange={(key) => {
|
onChange={(key) => {
|
||||||
@ -653,7 +638,6 @@ const NodeDesignForm: React.FC = () => {
|
|||||||
<FormRenderer
|
<FormRenderer
|
||||||
schema={getCurrentSchema()}
|
schema={getCurrentSchema()}
|
||||||
readOnly={tab.readonly}
|
readOnly={tab.readonly}
|
||||||
currentTab={tab}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : null
|
) : null
|
||||||
|
|||||||
@ -71,11 +71,12 @@ export interface UIVariables extends BaseSchema {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 节点设计数据
|
// 节点设计数据
|
||||||
export interface NodeDesignDataResponse extends BaseResponse{
|
export interface NodeDesignDataResponse extends BaseResponse {
|
||||||
nodeCode: string;
|
nodeCode: string;
|
||||||
nodeName: string;
|
nodeName: string;
|
||||||
nodeType: string;
|
nodeType: string;
|
||||||
category: string;
|
category: string;
|
||||||
|
description: string;
|
||||||
panelVariablesSchema: NodeVariablesSchema | null;
|
panelVariablesSchema: NodeVariablesSchema | null;
|
||||||
localVariablesSchema: NodeVariablesSchema | null;
|
localVariablesSchema: NodeVariablesSchema | null;
|
||||||
formVariablesSchema: NodeVariablesSchema | null;
|
formVariablesSchema: NodeVariablesSchema | null;
|
||||||
@ -100,6 +101,8 @@ export interface NodeDefinitionResponse extends BaseResponse {
|
|||||||
nodeCode: string;
|
nodeCode: string;
|
||||||
nodeName: string;
|
nodeName: string;
|
||||||
nodeType: NodeTypeEnum;
|
nodeType: NodeTypeEnum;
|
||||||
|
category: string;
|
||||||
|
description: string;
|
||||||
panelVariablesSchema: NodeVariablesSchema | null;
|
panelVariablesSchema: NodeVariablesSchema | null;
|
||||||
uiVariables: UIVariables | null;
|
uiVariables: UIVariables | null;
|
||||||
localVariablesSchema: NodeVariablesSchema | null;
|
localVariablesSchema: NodeVariablesSchema | null;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user