From abe0fc554a4b64d7ec7233016a1c009621a8f845 Mon Sep 17 00:00:00 2001 From: zly Date: Fri, 17 Apr 2026 17:15:38 +0800 Subject: [PATCH] =?UTF-8?q?fix(flowEditor):=20=E4=BF=AE=E5=A4=8D=E7=B2=98?= =?UTF-8?q?=E8=B4=B4=E9=80=BB=E8=BE=91=E6=97=A0=E6=95=88=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flowEditor/components/paneContextMenu.tsx | 2 +- src/pages/flowEditor/index.tsx | 64 ++++++++++++++----- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/pages/flowEditor/components/paneContextMenu.tsx b/src/pages/flowEditor/components/paneContextMenu.tsx index 21ba2db..629154d 100644 --- a/src/pages/flowEditor/components/paneContextMenu.tsx +++ b/src/pages/flowEditor/components/paneContextMenu.tsx @@ -29,7 +29,7 @@ const PaneContextMenu: React.FC = ({ }, []); // 检查是否有复制的节点数据 - const hasCopiedNode = !!localStorage.getItem('copiedNode'); + const hasCopiedNode = !!localStorage.getItem('copiedNode') || !!localStorage.getItem('copiedFlowData'); return ( = ({ initialData, useDefault, readOnly }) => { +const FlowEditorWithProvider: React.FC<{ + initialData?: any, + useDefault?: boolean, + readOnly?: boolean +}> = ({ initialData, useDefault, readOnly }) => { return (
e.preventDefault()}> @@ -22,7 +26,11 @@ const FlowEditorWithProvider: React.FC<{ initialData?: any, useDefault?: boolean ); }; -const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean, readOnly?: boolean }> = ({ initialData, useDefault, readOnly = false }) => { +const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean, readOnly?: boolean }> = ({ + initialData, + useDefault, + readOnly = false + }) => { const reactFlowInstance = useReactFlow(); const reactFlowWrapper = useRef(null); const [menu, setMenu] = useState<{ @@ -205,30 +213,56 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean, readOnly?: setMenu(null); }, [setMenu]); - // 添加处理粘贴事件的函数 + // 存储最后的鼠标位置 + const lastMousePositionRef = useRef<{ x: number; y: number } | null>(null); + + // 跟踪鼠标位置 + useEffect(() => { + const handleMouseMove = (event: MouseEvent) => { + const pane = reactFlowWrapper.current?.getBoundingClientRect(); + if (pane && reactFlowInstance) { + const position = reactFlowInstance.screenToFlowPosition({ + x: event.clientX, + y: event.clientY + }); + lastMousePositionRef.current = position; + } + }; + + const canvasElement = reactFlowWrapper.current; + if (canvasElement) { + canvasElement.addEventListener('mousemove', handleMouseMove); + } + + return () => { + if (canvasElement) { + canvasElement.removeEventListener('mousemove', handleMouseMove); + } + }; + }, [reactFlowInstance]); + + // 处理粘贴事件 const handlePasteNode = useCallback((event: ClipboardEvent) => { - // 检查是否是粘贴操作且在画布区域内 + // 右键菜单触发的粘贴(有menu.position) if (event.clipboardData?.getData('text') === 'paste-node' && menu?.type === 'pane' && menu.position) { pasteNode(menu.position); setMenu(null); } - }, [menu, pasteNode]); + }, [menu, pasteNode, setMenu]); // 添加键盘事件监听 useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { // 检查是否按下了 Ctrl+V (Windows/Linux) 或 Cmd+V (Mac) if ((event.ctrlKey || event.metaKey) && event.key === 'v') { - // 触发自定义粘贴事件 - const pasteEvent = new ClipboardEvent('paste', { - clipboardData: new DataTransfer() - }); - pasteEvent.clipboardData?.setData('text', 'paste-node'); - document.dispatchEvent(pasteEvent); + // 键盘快捷键粘贴,使用最后的鼠标位置 + if (lastMousePositionRef.current) { + pasteNode(lastMousePositionRef.current); + } } }; - // 为画布添加键盘事件监听 + // 为画布添加键盘和粘贴事件监听 const canvasElement = reactFlowWrapper.current; if (canvasElement) { canvasElement.addEventListener('keydown', handleKeyDown); @@ -241,7 +275,7 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean, readOnly?: } document.removeEventListener('paste', handlePasteNode); }; - }, [handlePasteNode]); + }, [pasteNode, handlePasteNode]); // 监听边的变化,处理添加节点的触发 useEffect(() => { @@ -281,8 +315,8 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean, readOnly?: } return ( -
e.preventDefault()} tabIndex={0} // 使div可获得焦点以接收键盘事件