From 37ead877ecb5ae6e5d342259a372d4361f989342 Mon Sep 17 00:00:00 2001 From: ZLY Date: Fri, 24 Oct 2025 10:54:21 +0800 Subject: [PATCH] =?UTF-8?q?feat(flow):=20=E6=B7=BB=E5=8A=A0=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E5=A4=8D=E5=88=B6=E7=B2=98=E8=B4=B4=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useFlowCallbacks.ts | 79 ++++++++++++++++++- .../flowEditor/components/paneContextMenu.tsx | 24 +++++- 2 files changed, 97 insertions(+), 6 deletions(-) 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 && ( + + 粘贴节点 + + )} ); };