diff --git a/src/components/FlowEditor/node/imageNode/ImageNode.tsx b/src/components/FlowEditor/node/imageNode/ImageNode.tsx new file mode 100644 index 0000000..b9a8b89 --- /dev/null +++ b/src/components/FlowEditor/node/imageNode/ImageNode.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { useStore } from '@xyflow/react'; +// import styles from '@/pages/flowEditor/node/style/base.module.less'; +import styles from '@/components/FlowEditor/node/style/baseOther.module.less'; +import DynamicIcon from '@/components/DynamicIcon'; +import NodeContentImage from '@/pages/flowEditor/components/nodeContentImage'; + +const setIcon = () => { + return ; +}; + +const ImageNode = ({ data, id }: { data: any; id: string }) => { + const title = data.title || '图片展示'; + + // 获取节点选中状态 - 适配React Flow v12 API + const isSelected = useStore((state) => + state.nodeLookup.get(id)?.selected || false + ); + + return ( +
+
+ {setIcon()} + {title} +
+ +
+ ); +}; + +export default ImageNode; \ No newline at end of file diff --git a/src/hooks/useFlowCallbacks.ts b/src/hooks/useFlowCallbacks.ts index 20b817d..25777da 100644 --- a/src/hooks/useFlowCallbacks.ts +++ b/src/hooks/useFlowCallbacks.ts @@ -20,10 +20,25 @@ import LocalNode from '@/components/FlowEditor/node/localNode/LocalNode'; import LoopNode from '@/components/FlowEditor/node/loopNode/LoopNode'; import BasicNode from '@/components/FlowEditor/node/basicNode/BasicNode'; import SwitchNode from '@/components/FlowEditor/node/switchNode/SwitchNode'; +import ImageNode from '@/components/FlowEditor/node/imageNode/ImageNode'; import { updateCanvasDataMap } from '@/store/ideContainer'; import { Dispatch } from 'redux'; +// 根据节点类型获取对应的节点组件 +const getNodeComponent = (nodeType: string) => { + switch (nodeType) { + case 'BASIC': + return BasicNode; + case 'SWITCH': + return SwitchNode; + case 'IMAGE': + return ImageNode; + default: + return LocalNode; + } +}; + export const useFlowCallbacks = ( nodes: Node[], setNodes: React.Dispatch>, @@ -512,14 +527,10 @@ export const useFlowCallbacks = ( setNodes(updatedNodes); closeEditModal(); - - // TODO 如果需要在节点编辑后立即保存到服务器,可以调用保存函数 - // saveFlowDataToServer(); }, [nodes, editingNode, closeEditModal]); // 删除节点函数 const deleteNode = useCallback((node: Node) => { - console.log('node:', node); setNodes((nds: Node[]) => nds.filter((n) => n.id !== node.id)); setEdges((eds: Edge[]) => eds.filter((e) => e.source !== node.id && e.target !== node.id)); @@ -615,7 +626,7 @@ export const useFlowCallbacks = ( // 将未定义的节点动态追加进nodeTypes const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key)); if (!nodeMap.includes(nodeType)) { - registerNodeType(nodeType, nodeType === 'BASIC' ? BasicNode : nodeType === 'SWITCH' ? SwitchNode : LocalNode, nodeDefinition.nodeName); + registerNodeType(nodeType, getNodeComponent(nodeType), nodeDefinition.nodeName); } // 添加新节点 @@ -727,7 +738,8 @@ export const useFlowCallbacks = ( const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key)); // 目前默认添加的都是系统组件/本地组件 if (!nodeMap.includes(nodeType)) { - registerNodeType(nodeType, nodeType === 'BASIC' ? BasicNode : nodeType === 'SWITCH' ? SwitchNode : LocalNode, nodeDefinition.nodeName); + // console.log('getRegisterNodes():', getRegisterNodes(nodeType)); + registerNodeType(nodeType, getNodeComponent(nodeType), nodeDefinition.nodeName); } setNodes((nds: Node[]) => { diff --git a/src/pages/flowEditor/components/nodeContentImage.tsx b/src/pages/flowEditor/components/nodeContentImage.tsx new file mode 100644 index 0000000..d600ff8 --- /dev/null +++ b/src/pages/flowEditor/components/nodeContentImage.tsx @@ -0,0 +1,189 @@ +import React from 'react'; +import styles from '@/components/FlowEditor/node/style/baseOther.module.less'; +import { Handle, Position, useStore } from '@xyflow/react'; +import { Image } from '@arco-design/web-react'; + +interface NodeContentData { + parameters?: { + dataIns?: any[]; + dataOuts?: any[]; + apiIns?: any[]; + apiOuts?: any[]; + }; + showFooter?: boolean; + type?: string; + + [key: string]: any; +} + +// 定义通用的句柄样式 +const handleStyles = { + mainSource: { + background: '#2290f6', + width: '8px', + height: '8px', + border: '2px solid #fff', + boxShadow: '0 0 4px rgba(0,0,0,0.2)' + }, + mainTarget: { + background: '#2290f6', + width: '8px', + height: '8px', + border: '2px solid #fff', + boxShadow: '0 0 4px rgba(0,0,0,0.2)' + }, + data: { + background: '#555', + width: '6px', + height: '6px', + border: '1px solid #fff', + boxShadow: '0 0 2px rgba(0,0,0,0.2)' + } +}; + +// 渲染普通节点的句柄 +const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[], apiOuts: any[]) => { + return ( + <> + {apiOuts.map((_, index) => ( + + ))} + {apiIns.map((_, index) => ( + + ))} + + {/* 输入参数连接端点 */} + {dataIns.map((_, index) => ( + + ))} + + {/* 输出参数连接端点 */} + {dataOuts.map((_, index) => ( + + ))} + + ); +}; + + +const NodeContent = ({ data }: { data: NodeContentData }) => { + const apiIns = data.parameters?.apiIns || []; + const apiOuts = data.parameters?.apiOuts || []; + const dataIns = data.parameters?.dataIns || []; + const dataOuts = data.parameters?.dataOuts || []; + + // 判断节点类型 + const isStartNode = data.type === 'start'; + const isEndNode = data.type === 'end'; + const isSpecialNode = isStartNode || isEndNode; + + return ( + <> + {/*content栏-api部分*/} +
+
+ {apiIns.length > 0 && ( +
+ {apiIns.map((input, index) => ( +
+ {input.desc} +
+ ))} +
+ )} + + {apiOuts.length > 0 && ( +
+ {apiOuts.map((output, index) => ( +
+ {output.desc} +
+ ))} +
+ )} +
+
+ {(dataIns.length > 0 || dataOuts.length > 0) && ( + <> + {/*分割*/} +
+ + {/*content栏-data部分*/} +
+
+ {dataIns.length > 0 && !isStartNode && ( +
+ {dataIns.map((input, index) => ( +
+ {`${input.desc} ${input.dataType}` || `输入${index + 1}`} +
+ ))} +
+ )} + + {dataOuts.length > 0 && !isEndNode && ( +
+ {dataOuts.map((output, index) => ( +
+ {output.id || `输出${index + 1}`} +
+ ))} +
+ )} +
+
+ + )} + + {/*图片展示 TODO 需要对接接口*/} + {/*
*/} + {/* */} + {/*
*/} + + {/* 根据节点类型渲染不同的句柄 */} + {renderRegularNodeHandles(dataIns, dataOuts, apiIns, apiOuts)} + + ); +}; + +export default NodeContent; \ No newline at end of file diff --git a/src/pages/flowEditor/sideBar/config/localNodeData.ts b/src/pages/flowEditor/sideBar/config/localNodeData.ts index 2d69939..3d3b0ef 100644 --- a/src/pages/flowEditor/sideBar/config/localNodeData.ts +++ b/src/pages/flowEditor/sideBar/config/localNodeData.ts @@ -62,6 +62,28 @@ const switchParameters = { dataIns: [], dataOuts: [] }; +const imageParameters = { + apiIns: [{ + name: 'start', + desc: '', + dataType: '', + defaultValue: '' + }], + apiOuts: [{ + name: 'done', + desc: '', + dataType: '', + defaultValue: '' + }], + dataIns: [{ + name: 'in', + desc: 'url', + dataType: 'STRING', + defaultValue: '', + arrayType: '' + }], + dataOuts: [] +}; // 定义节点基本信息 画布中添加的组件列表依赖这里 const nodeDefinitions = [ @@ -96,6 +118,9 @@ export const localNodeData = nodeDefinitions.map(({ nodeName, nodeType, nodeGrou else if (nodeType === 'SWITCH') { parameters = switchParameters; } + else if (nodeType === 'IMAGE') { + parameters = imageParameters; + } return { nodeName,