refactor(flowEditor): 重构节点渲染逻辑并优化数据转换

- 重构了 DraggableNode 组件,使用新设计的 NodeContent组件来渲染节点内容
-优化了节点类型判断和处理逻辑,支持开始和结束节点的特殊处理
- 改进了节点参数的渲染方式,根据节点类型动态显示输入和输出端点
- 新增 convertFlowData 工具函数,用于将原始数据结构转换为 flow editor 可用的节点和边数据
master
钟良源 5 months ago
parent ebc6de6965
commit f084c93b39

@ -2,7 +2,6 @@ import React from 'react';
import styles from '@/pages/flowEditor/node/style/base.module.less';
import { Handle, Position } from '@xyflow/react';
interface NodeContentData {
parameters?: {
inputs?: any[];
@ -18,11 +17,17 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
const inputs = data.parameters?.inputs || [];
const outputs = data.parameters?.outputs || [];
const showFooter = data.showFooter || false;
// 判断节点类型
const isStartNode = data.type === 'start';
const isEndNode = data.type === 'end';
const isSpecialNode = isStartNode || isEndNode;
return (
<>
{/*content栏*/}
<div className={styles['node-content']}>
{inputs.length > 0 && (
{inputs.length > 0 && !isStartNode && (
<div className={styles['node-inputs']}>
{inputs.map((input, index) => (
<div key={`input-${index}`} className={styles['node-input-label']}>
@ -32,7 +37,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
</div>
)}
{outputs.length > 0 && (
{outputs.length > 0 && !isEndNode && (
<div className={styles['node-outputs']}>
{outputs.map((output, index) => (
<div key={`output-${index}`} style={{ fontSize: '12px', padding: '2px 0' }}>
@ -50,45 +55,78 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
</div>
)}
{/* 默认连接端点*/}
<Handle
type={data.type === 'start' ? 'source' : 'target'}
position={data.type === 'start' ? Position.Right : Position.Left}
id={data.type === 'start' ? 'start-source' : 'end-target'}
style={{
background: '#555',
top: '40px'
}}
/>
{/* 流程传输(开始/结束)只在一侧显示端点 */}
{isSpecialNode ? (
<>
<Handle
type={isStartNode ? 'source' : 'target'}
position={isStartNode ? Position.Right : Position.Left}
id={isStartNode ? 'start-source' : 'end-target'}
style={{
background: '#555',
top: '40px'
}}
/>
{/*输入参数连接端点*/}
{inputs.map((_, index) => (
<Handle
key={`input-handle-${index}`}
type="target"
position={Position.Left}
id={`input-${index}`}
style={{
background: '#555',
top: `${60 + index * 20}px`
}}
/>
))}
{/* 为流程传输的参数也添加句柄 */}
{isStartNode && outputs.map((_, index) => (
<Handle
key={`output-handle-${index}`}
type="source"
position={Position.Right}
id={outputs[index].name || `output-${index}`}
style={{
background: '#555',
top: `${60 + index * 20}px`
}}
/>
))}
{/*输出参数连接端点*/}
{outputs.map((_, index) => (
<Handle
key={`output-handle-${index}`}
type="source"
position={Position.Right}
id={`output-${index}`}
style={{
background: '#555',
// top: `${80 + inputs.length * 20 + index * 20}px`
top: `${60 + index * 20}px`
}}
/>
))}
{isEndNode && inputs.map((_, index) => (
<Handle
key={`input-handle-${index}`}
type="target"
position={Position.Left}
id={inputs[index].name || `input-${index}`}
style={{
background: '#555',
top: `${60 + index * 20}px`
}}
/>
))}
</>
) : (
/* 普通节点可以在两侧显示多个端点 */
<>
{/* 输入参数连接端点 */}
{inputs.map((_, index) => (
<Handle
key={`input-handle-${index}`}
type="target"
position={Position.Left}
id={inputs[index].name || `input-${index}`}
style={{
background: '#555',
top: `${40 + index * 20}px`
}}
/>
))}
{/* 输出参数连接端点 */}
{outputs.map((_, index) => (
<Handle
key={`output-handle-${index}`}
type="source"
position={Position.Right}
id={outputs[index].name || `output-${index}`}
style={{
background: '#555',
top: `${40 + index * 20}px`
}}
/>
))}
</>
)}
</>
);
};

@ -1,28 +1,17 @@
import React from 'react';
import { Handle, Position } from '@xyflow/react';
import styles from '@/pages/flowEditor/node/style/base.module.less';
import NodeContent from '@/pages/flowEditor/components/nodeContent';
const DraggableNode = ({ data }: { data: any }) => {
const title = data.title || '任务节点';
return (
<div style={{
padding: '10px 20px',
backgroundColor: '#1890ff',
borderRadius: '5px',
color: 'white',
fontWeight: 'bold'
}}>
<div>{data.label || '任务节点'}</div>
<Handle
type="target"
position={Position.Left}
id="task-target"
style={{ background: '#555' }}
/>
<Handle
type="source"
position={Position.Right}
id="task-source"
style={{ background: '#555' }}
/>
<div className={styles['node-container']}>
<div className={styles['node-header']} style={{ backgroundColor: '#1890ff' }}>
{title}
</div>
<NodeContent data={data} />
</div>
);
};

@ -0,0 +1,81 @@
/**
* flow editor nodes edges
* @param flowData -
* @returns nodes edges
*/
export const convertFlowData = (flowData: any) => {
const nodes: any[] = [];
const edges: any[] = [];
// 处理节点配置
const nodeConfigs = flowData.main?.nodeConfigs || [];
for (const nodeConfig of nodeConfigs) {
// 确定节点类型
let nodeType = 'draggable';
if (nodeConfig.nodeId === 'start') {
nodeType = 'start';
} else if (nodeConfig.nodeId === 'end') {
nodeType = 'end';
}
// 解析位置信息
let position = { x: 0, y: 0 };
try {
const x6Data = JSON.parse(nodeConfig.x6);
position = x6Data.position || { x: 0, y: 0 };
} catch (e) {
console.warn('Failed to parse position for node:', nodeConfig.nodeId);
}
// 构造节点数据
const node: any = {
id: nodeConfig.nodeId,
type: nodeType,
position,
data: {
title: nodeConfig.nodeName || nodeConfig.nodeId,
type: nodeType, // 添加节点类型到data中供NodeContent使用
parameters: {
inputs: nodeConfig.dataIns?.map((input: any) => ({
name: input.id,
desc: input.desc,
dataType: input.dataType,
defaultValue: input.defaultValue
})) || [],
outputs: nodeConfig.dataOuts?.map((output: any) => ({
name: output.id,
desc: output.desc,
dataType: output.dataType,
defaultValue: output.defaultValue
})) || []
}
}
};
// 如果是机械臂节点,添加组件标识信息
if (nodeConfig.component) {
node.data.component = {
compIdentifier: nodeConfig.component.compIdentifier,
compInstanceIdentifier: nodeConfig.component.compInstanceIdentifier
};
}
nodes.push(node);
}
// 处理连线配置
const lineConfigs = flowData.main?.lineConfigs || [];
for (const lineConfig of lineConfigs) {
const edge: any = {
id: lineConfig.id,
source: lineConfig.prev.nodeId,
target: lineConfig.next.nodeId,
sourceHandle: lineConfig.prev.endpointId,
targetHandle: lineConfig.next.endpointId
};
edges.push(edge);
}
return { nodes, edges };
};

@ -52,7 +52,7 @@ export const convertFlowData = (flowData: any) => {
defaultValue: output.defaultValue
})) || []
},
type: nodeType,
type: nodeType
}
};

Loading…
Cancel
Save