diff --git a/src/hooks/useFlowCallbacks.ts b/src/hooks/useFlowCallbacks.ts index ad02e8f..b6e7a53 100644 --- a/src/hooks/useFlowCallbacks.ts +++ b/src/hooks/useFlowCallbacks.ts @@ -422,9 +422,80 @@ export const useFlowCallbacks = ( }, []); // 复制节点 const copyNode = useCallback((node: Node) => { - // 这里可以实现节点复制逻辑 + // 将节点数据存储到localStorage中,以便粘贴时使用 + const nodeData = { + ...node, + // 清除可能存在的运行时状态 + selected: false, + dragging: false + }; + + localStorage.setItem('copiedNode', JSON.stringify(nodeData)); console.log('复制节点:', node); }, []); + + // 粘贴节点 + const pasteNode = useCallback((position: { x: number; y: number }) => { + const copiedNodeStr = localStorage.getItem('copiedNode'); + if (!copiedNodeStr) { + console.warn('没有找到复制的节点数据'); + return; + } + + try { + const copiedNode = JSON.parse(copiedNodeStr); + + // 创建新节点,更新ID和位置 + const newNode = { + ...copiedNode, + id: `${copiedNode.type}-${Date.now()}`, // 生成新的唯一ID + position, // 使用传入的位置 + selected: false, + dragging: false + }; + + // 特殊处理循环节点 + if (copiedNode.type === 'LOOP') { + // 对于循环节点,我们需要特殊处理 + setNodes((nds: Node[]) => { + const newNodes = [...nds, newNode]; + + // 添加节点后记录历史 + setTimeout(() => { + const event = new CustomEvent('takeSnapshot', { + detail: { nodes: [...newNodes], edges: [...edges] } + }); + document.dispatchEvent(event); + }, 0); + + return newNodes; + }); + return; + } + + // 将未定义的节点动态追加进nodeTypes + const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key)); + if (!nodeMap.includes(newNode.type)) { + registerNodeType(newNode.type, getNodeComponent(newNode.type), newNode.data?.title || newNode.type); + } + + setNodes((nds: Node[]) => { + const newNodes = [...nds, newNode]; + + // 添加节点后记录历史 + setTimeout(() => { + const event = new CustomEvent('takeSnapshot', { + detail: { nodes: [...newNodes], edges: [...edges] } + }); + document.dispatchEvent(event); + }, 0); + + return newNodes; + }); + } catch (error) { + console.error('粘贴节点时出错:', error); + } + }, [edges]); // endregion // region 节点/边操作 @@ -750,11 +821,12 @@ export const useFlowCallbacks = ( data: { ...nodeDefinition.data, title: nodeDefinition.nodeName, - type: nodeType, - compId: nodeDefinition.id || nodeDefinition.flowHousVO.id + type: nodeType } }; + if (nodeDefinition.id || nodeDefinition?.flowHousVO?.id) newNode.data.compId = nodeDefinition.id || nodeDefinition?.flowHousVO?.id; + if (nodeType === 'SWITCH') { newNode.data.component = { customDef: JSON.stringify({ @@ -994,6 +1066,7 @@ export const useFlowCallbacks = ( editNode, editEdge, copyNode, + pasteNode, // 添加粘贴节点功能 // Node operations addNodeOnEdge, diff --git a/src/pages/flowEditor/components/paneContextMenu.tsx b/src/pages/flowEditor/components/paneContextMenu.tsx index f75be12..21ba2db 100644 --- a/src/pages/flowEditor/components/paneContextMenu.tsx +++ b/src/pages/flowEditor/components/paneContextMenu.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useCallback } from 'react'; import { Menu } from '@arco-design/web-react'; import AddNodeMenu from './addNodeMenu'; @@ -14,9 +14,22 @@ const PaneContextMenu: React.FC = ({ position }) => { // 包装onAddNode函数以适配AddNodeMenu组件的接口 - const handleAddNode = (nodeType: string, node: any) => { + const handleAddNode = useCallback((nodeType: string, node: any) => { onAddNode(nodeType, position, node); - }; + }, [onAddNode, position]); + + // 处理粘贴节点 + const handlePasteNode = useCallback(() => { + // 创建自定义粘贴事件 + const pasteEvent = new ClipboardEvent('paste', { + clipboardData: new DataTransfer() + }); + pasteEvent.clipboardData?.setData('text', 'paste-node'); + document.dispatchEvent(pasteEvent); + }, []); + + // 检查是否有复制的节点数据 + const hasCopiedNode = !!localStorage.getItem('copiedNode'); return ( = ({ handleAddNode(nodeType, node); }} /> + {hasCopiedNode && ( + + 粘贴节点 + + )} ); };