diff --git a/src/pages/flowEditor/components/nodeContent.tsx b/src/pages/flowEditor/components/nodeContent.tsx new file mode 100644 index 0000000..f0fc7f9 --- /dev/null +++ b/src/pages/flowEditor/components/nodeContent.tsx @@ -0,0 +1,96 @@ +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[]; + outputs?: any[]; + }; + showFooter?: boolean; + type?: string; + + [key: string]: any; +} + +const NodeContent = ({ data }: { data: NodeContentData }) => { + const inputs = data.parameters?.inputs || []; + const outputs = data.parameters?.outputs || []; + const showFooter = data.showFooter || false; + return ( + <> + {/*content栏*/} +
+ {inputs.length > 0 && ( +
+ {inputs.map((input, index) => ( +
+ {input.name || `输入${index + 1}`} +
+ ))} +
+ )} + + {outputs.length > 0 && ( +
+ {outputs.map((output, index) => ( +
+ {output.name || `输出${index + 1}`} +
+ ))} +
+ )} +
+ + {/*footer栏*/} + {showFooter && ( +
+ 暂定的footer +
+ )} + + {/* 默认连接端点*/} + + + {/*输入参数连接端点*/} + {inputs.map((_, index) => ( + + ))} + + {/*输出参数连接端点*/} + {outputs.map((_, index) => ( + + ))} + + ); +}; + +export default NodeContent; \ No newline at end of file diff --git a/src/pages/flowEditor/components/nodeWrapper.tsx b/src/pages/flowEditor/components/nodeWrapper.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/flowEditor/index.tsx b/src/pages/flowEditor/index.tsx index c774e29..be0c542 100644 --- a/src/pages/flowEditor/index.tsx +++ b/src/pages/flowEditor/index.tsx @@ -19,6 +19,8 @@ import StartNode from './node/startNode/StartNode'; import EndNode from './node/endNode/EndNode'; import DraggableNode from './node/draggableNode/DraggableNode'; import SideBar from './sideBar/sideBar'; +import { convertFlowData } from '@/utils/convertFlowData'; +import { exampleFlowData } from '@/pages/flowEditor/test/exampleFlowData'; const nodeTypes: NodeTypes = { textUpdater: TextUpdaterNode, @@ -27,41 +29,7 @@ const nodeTypes: NodeTypes = { draggable: DraggableNode }; -const initialNodes: Node[] = [ - { - id: 'start-node', - position: { x: 0, y: 0 }, - data: { label: '开始' }, - type: 'start' - }, - { - id: 'end-node', - position: { x: 1000, y: 0 }, - data: { label: '结束' }, - type: 'end' - }, - { - id: 'node-1', - type: 'textUpdater', - position: { x: 400, y: 0 }, - data: { value: 123 } - } -]; - -const initialEdges: Edge[] = [ - { - id: 'start-node-1', - source: 'start-node', - target: 'node-1', - sourceHandle: 'start-source' - }, - { - id: 'node-1-end', - source: 'node-1', - target: 'end-node', - targetHandle: 'end-target' - } -]; +const { nodes: convertedNodes, edges: convertedEdges } = convertFlowData(exampleFlowData); const FlowEditorWithProvider: React.FC = () => { return ( @@ -75,8 +43,8 @@ const FlowEditorWithProvider: React.FC = () => { }; const FlowEditor: React.FC = () => { - const [nodes, setNodes] = useState(initialNodes); - const [edges, setEdges] = useState(initialEdges); + const [nodes, setNodes] = useState(convertedNodes); + const [edges, setEdges] = useState(convertedEdges); const reactFlowInstance = useReactFlow(); const reactFlowWrapper = useRef(null); diff --git a/src/pages/flowEditor/node/endNode/EndNode.tsx b/src/pages/flowEditor/node/endNode/EndNode.tsx index ea7d654..fd8df34 100644 --- a/src/pages/flowEditor/node/endNode/EndNode.tsx +++ b/src/pages/flowEditor/node/endNode/EndNode.tsx @@ -1,6 +1,6 @@ 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'; interface EndNodeData { title?: string; @@ -15,9 +15,6 @@ interface EndNodeData { const EndNode = ({ data }: { data: EndNodeData }) => { const title = data.title || '结束'; - const inputs = data.parameters?.inputs || []; - const outputs = data.parameters?.outputs || []; - const showFooter = data.showFooter || false; return (
@@ -25,72 +22,7 @@ const EndNode = ({ data }: { data: EndNodeData }) => { {title}
-
- {inputs.length > 0 && ( -
- {inputs.map((input, index) => ( -
- {input.name || `输入${index + 1}`} -
- ))} -
- )} - - {outputs.length > 0 && ( -
- {outputs.map((output, index) => ( -
- {output.name || `输出${index + 1}`} -
- ))} -
- )} -
- - {showFooter && ( -
- 暂定的footer -
- )} - - {/* Dynamic handles based on parameters */} - - - {/* Add additional handles based on parameters */} - {inputs.map((_, index) => ( - - ))} - - {outputs.map((_, index) => ( - - ))} + ); }; diff --git a/src/pages/flowEditor/node/startNode/StartNode.tsx b/src/pages/flowEditor/node/startNode/StartNode.tsx index 1c92f1a..0f6e935 100644 --- a/src/pages/flowEditor/node/startNode/StartNode.tsx +++ b/src/pages/flowEditor/node/startNode/StartNode.tsx @@ -1,6 +1,6 @@ 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'; interface StartNodeData { title?: string; @@ -15,82 +15,13 @@ interface StartNodeData { const StartNode = ({ data }: { data: StartNodeData }) => { const title = data.title || '开始'; - const inputs = data.parameters?.inputs || []; - const outputs = data.parameters?.outputs || []; - const showFooter = data.showFooter || false; return (
{title}
-
- - {inputs.length > 0 && ( -
- {inputs.map((input, index) => ( -
- {input.name || `输入${index + 1}`} -
- ))} -
- )} - - {outputs.length > 0 && ( -
- {outputs.map((output, index) => ( -
- {output.name || `输出${index + 1}`} -
- ))} -
- )} -
- - {showFooter && ( -
- 暂定的footer -
- )} - - {/* Dynamic handles based on parameters */} - - - {/* Add additional handles based on parameters */} - {inputs.map((_, index) => ( - - ))} - - {outputs.map((_, index) => ( - - ))} +
); }; diff --git a/src/pages/flowEditor/test/exampleFlowData.ts b/src/pages/flowEditor/test/exampleFlowData.ts new file mode 100644 index 0000000..68da610 --- /dev/null +++ b/src/pages/flowEditor/test/exampleFlowData.ts @@ -0,0 +1,288 @@ +export const exampleFlowData = { + 'main': { + 'id': 'main', + 'lineConfigs': [ + { + 'id': '437d6a3c-ae8f-4a34-a195-33dcfa9747cf', + 'lineType': 'API', + 'next': { + 'endpointId': 'move', + 'nodeId': 'node_34' + }, + 'prev': { + 'endpointId': 'start', + 'nodeId': 'start' + }, + 'x6': '{"vertices":[]}' + }, + { + 'id': '7f9b61cd-eb12-4914-af90-85ec73bf1fec', + 'lineType': 'API', + 'next': { + 'endpointId': 'controlClaw', + 'nodeId': 'node_43' + }, + 'prev': { + 'endpointId': 'done', + 'nodeId': 'node_34' + }, + 'x6': '{"vertices":[]}' + }, + { + 'id': '6f670427-d8a5-494e-ae25-ffa1491014bf', + 'lineType': 'API', + 'next': { + 'endpointId': 'move', + 'nodeId': 'node_17' + }, + 'prev': { + 'endpointId': 'done', + 'nodeId': 'node_43' + }, + 'x6': '{"vertices":[]}' + }, + { + 'id': '621f19c1-8d7c-48f7-8158-17418b118fa2', + 'lineType': 'API', + 'next': { + 'endpointId': 'end', + 'nodeId': 'end' + }, + 'prev': { + 'endpointId': 'done', + 'nodeId': 'node_17' + }, + 'x6': '{"vertices":[]}' + } + ], + 'name': '', + 'nodeConfigs': [ + { + 'apiId': '', + 'component': null, + 'dataIns': [], + 'dataOfPrevNodeMap': {}, + 'dataOuts': [], + 'defaultValues': [], + 'description': '', + 'joinLines': {}, + 'nodeId': 'start', + 'nodeName': '', + 'x6': '{"position":{"x":-550,"y":-25}}' + }, + { + 'apiId': '', + 'component': { + 'compIdentifier': 'admin_dazu-mechanical-arm', + 'compInstanceIdentifier': 'admin_dazu-mechanical-arm', + 'customDef': '', + 'type': 'BASIC' + }, + 'dataIns': [ + { + 'arrayType': null, + 'dataType': null, + 'defaultValue': null, + 'desc': '', + 'id': 'input' + }, + { + 'arrayType': null, + 'dataType': 'INTEGER', + 'defaultValue': 50, + 'desc': '力值(百分比:20-100)', + 'id': 'force' + }, + { + 'arrayType': null, + 'dataType': 'INTEGER', + 'defaultValue': 850, + 'desc': '位置(千分比:0-1000)', + 'id': 'location' + }, + { + 'arrayType': 'DOUBLE', + 'dataType': 'ARRAY', + 'defaultValue': [ + 64.018, + 912.91, + 373.288, + -171.439, + 75.154, + -81.128 + ], + 'desc': '六位坐标', + 'id': 'position' + }, + { + 'arrayType': null, + 'dataType': 'INTEGER', + 'defaultValue': 20, + 'desc': '速度(百分比:1-100)', + 'id': 'speed' + } + ], + 'dataOfPrevNodeMap': {}, + 'dataOuts': [ + { + 'arrayType': null, + 'dataType': null, + 'defaultValue': null, + 'desc': '', + 'id': 'output' + } + ], + 'defaultValues': [], + 'description': '', + 'joinLines': {}, + 'nodeId': 'node_34', + 'nodeName': 'mechanical-arm', + 'x6': '{"position":{"x":-360,"y":-120}}' + }, + { + 'apiId': '', + 'component': { + 'compIdentifier': 'admin_dazu-mechanical-arm', + 'compInstanceIdentifier': 'admin_dazu-mechanical-arm', + 'customDef': '', + 'type': 'BASIC' + }, + 'dataIns': [ + { + 'arrayType': null, + 'dataType': null, + 'defaultValue': null, + 'desc': '', + 'id': 'input' + }, + { + 'arrayType': null, + 'dataType': 'INTEGER', + 'defaultValue': 50, + 'desc': '力值(百分比:20-100)', + 'id': 'force' + }, + { + 'arrayType': null, + 'dataType': 'INTEGER', + 'defaultValue': 950, + 'desc': '位置(千分比:0-1000)', + 'id': 'location' + }, + { + 'arrayType': 'DOUBLE', + 'dataType': 'ARRAY', + 'defaultValue': null, + 'desc': '六位坐标', + 'id': 'position' + }, + { + 'arrayType': null, + 'dataType': 'INTEGER', + 'defaultValue': 20, + 'desc': '速度(百分比:1-100)', + 'id': 'speed' + } + ], + 'dataOfPrevNodeMap': {}, + 'dataOuts': [ + { + 'arrayType': null, + 'dataType': null, + 'defaultValue': null, + 'desc': '', + 'id': 'output' + } + ], + 'defaultValues': [], + 'description': '', + 'joinLines': {}, + 'nodeId': 'node_43', + 'nodeName': 'mechanical-arm', + 'x6': '{"position":{"x":-120,"y":-145}}' + }, + { + 'apiId': '', + 'component': { + 'compIdentifier': 'admin_dazu-mechanical-arm', + 'compInstanceIdentifier': 'admin_dazu-mechanical-arm', + 'customDef': '', + 'type': 'BASIC' + }, + 'dataIns': [ + { + 'arrayType': null, + 'dataType': null, + 'defaultValue': null, + 'desc': '', + 'id': 'input' + }, + { + 'arrayType': null, + 'dataType': 'INTEGER', + 'defaultValue': 50, + 'desc': '力值(百分比:20-100)', + 'id': 'force' + }, + { + 'arrayType': null, + 'dataType': 'INTEGER', + 'defaultValue': 850, + 'desc': '位置(千分比:0-1000)', + 'id': 'location' + }, + { + 'arrayType': 'DOUBLE', + 'dataType': 'ARRAY', + 'defaultValue': [ + -224.639, + 216.57, + 574.605, + -156, + 81.787, + -74.001 + ], + 'desc': '六位坐标', + 'id': 'position' + }, + { + 'arrayType': null, + 'dataType': 'INTEGER', + 'defaultValue': 20, + 'desc': '速度(百分比:1-100)', + 'id': 'speed' + } + ], + 'dataOfPrevNodeMap': {}, + 'dataOuts': [ + { + 'arrayType': null, + 'dataType': null, + 'defaultValue': null, + 'desc': '', + 'id': 'output' + } + ], + 'defaultValues': [], + 'description': '', + 'joinLines': {}, + 'nodeId': 'node_17', + 'nodeName': 'mechanical-arm', + 'x6': '{"position":{"x":120,"y":-120}}' + }, + { + 'apiId': '', + 'component': null, + 'dataIns': [], + 'dataOfPrevNodeMap': {}, + 'dataOuts': [], + 'defaultValues': [], + 'description': '', + 'joinLines': {}, + 'nodeId': 'end', + 'nodeName': '', + 'x6': '{"position":{"x":370,"y":0}}' + } + ] + } +}; \ No newline at end of file diff --git a/src/utils/convertFlowData.ts b/src/utils/convertFlowData.ts new file mode 100644 index 0000000..f5f5de7 --- /dev/null +++ b/src/utils/convertFlowData.ts @@ -0,0 +1,86 @@ +/** + * 将提供的数据结构转换为适用于 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 = 'BASIC'; + if (nodeConfig.nodeId === 'start') { + nodeType = 'start'; + } + else if (nodeConfig.nodeId === 'end') { + nodeType = 'end'; + } + else { + nodeType = nodeConfig.component.type; + } + + // 解析位置信息 + 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, + 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); + } + + console.log('nodes, edges:', nodes, edges); + + return { nodes, edges }; +}; \ No newline at end of file