From a3b3f7a1c358dbf3cb89942905de527eef6fe650 Mon Sep 17 00:00:00 2001 From: zhanghao <774378400@qq.com> Date: Tue, 4 Aug 2026 10:08:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=A4=8D=E5=88=B6?= =?UTF-8?q?=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/flow/index.vue | 85 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 7 deletions(-) diff --git a/src/views/flow/index.vue b/src/views/flow/index.vue index 1aa9636..c1554e6 100644 --- a/src/views/flow/index.vue +++ b/src/views/flow/index.vue @@ -193,7 +193,8 @@ v-if="property.componentType === 'number'" v-model="property.input" :min="0" - :controls="false" + :max="property.max || Infinity" + :step="property.step || 1" :step-strictly="true" placeholder="请输入" clearable @@ -880,6 +881,7 @@ const nodeAction = ref(""); const singleNodeExecution = (e) => { const { name, nodeType, nodeParams, action } = e.detail; + console.log('nodeParams', nodeParams) nodeName.value = name; visible.value = true; nodeAction.value = action; @@ -932,11 +934,80 @@ const clearRun = () => { totalRunningTime.value = 0; } -const handleDeleteKey = (event) => { - const activeElement = document.activeElement; - if (["INPUT", "TEXTAREA"].includes(activeElement?.tagName) || activeElement?.isContentEditable) return; +const NODE_PASTE_OFFSET = 40; +const NON_COPYABLE_NODE_TYPES = new Set(["start", "end", "selectArea"]); +let copiedNodes = []; +let pasteCount = 0; - if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "z") { +const isTextEditing = (event) => { + const element = event.target || document.activeElement; + return ["INPUT", "TEXTAREA", "SELECT"].includes(element?.tagName) + || element?.isContentEditable; +}; + +const copySelectedNodes = (event) => { + const nodes = lf.getSelectElements().nodes.filter( + (node) => !NON_COPYABLE_NODE_TYPES.has(node.type), + ); + if (!nodes.length) return; + + event.preventDefault(); + copiedNodes = JSON.parse(JSON.stringify(nodes)); + pasteCount = 0; +}; + +const pasteCopiedNodes = (event) => { + if (!copiedNodes.length || flowStore.disableForm) return; + + event.preventDefault(); + pasteCount += 1; + const offset = NODE_PASTE_OFFSET * pasteCount; + const pastedNodes = copiedNodes.map((sourceNode) => { + const properties = JSON.parse(JSON.stringify(sourceNode.properties || {})); + const parentId = properties.parentId; + delete properties.parentId; + + const newNode = lf.addNode({ + type: sourceNode.type, + x: Number(sourceNode.x || 0) + offset, + y: Number(sourceNode.y || 0) + offset, + properties, + }); + + if (sourceNode.type === "branch" && Array.isArray(properties.anchor)) { + const oldElseId = `${sourceNode.id}_else`; + const newElseId = `${newNode.id}_else`; + const anchors = properties.anchor.map((anchor) => ( + anchor.id === oldElseId ? { ...anchor, id: newElseId } : anchor + )); + lf.setProperties(newNode.id, { ...properties, anchor: anchors }); + } + + if (parentId && lf.getNodeModelById(parentId)) { + lf.addToGroup(parentId, newNode.id, { x: newNode.x, y: newNode.y }); + } + return newNode; + }); + + lf.clearSelectElements(); + if (pastedNodes.length === 1) lf.selectElementById(pastedNodes[0].id); +}; + +const handleKeyboardShortcut = (event) => { + if (isTextEditing(event)) return; + + const isModifierKey = event.ctrlKey || event.metaKey; + const key = event.key.toLowerCase(); + if (isModifierKey && key === "c") { + if (!flowStore.disableForm) copySelectedNodes(event); + return; + } + if (isModifierKey && key === "v") { + pasteCopiedNodes(event); + return; + } + + if (isModifierKey && key === "z") { if (flowStore.disableForm) return; event.preventDefault(); if (event.shiftKey) lf.redo(); @@ -972,7 +1043,7 @@ onMounted(() => { initFlow(); document.addEventListener("singleNodeExecution", singleNodeExecution); registerBeforeUnload(); - window.addEventListener("keydown", handleDeleteKey); + window.addEventListener("keydown", handleKeyboardShortcut); onFlowEvent("openParamsDrawer", (node) => { showParamsDrawer.value = true; @@ -1024,7 +1095,7 @@ onUnmounted(() => { if (window.lf === lf) delete window.lf; window.removeEventListener("beforeunload", handleBeforeUnload); - window.removeEventListener("keydown", handleDeleteKey); + window.removeEventListener("keydown", handleKeyboardShortcut); document.removeEventListener("singleNodeExecution", singleNodeExecution); });