| 1 |  | -import { GraphEdge, GraphNode, VueFlowStore } from '@vue-flow/core'; | 
|  | 1 | +import { GraphEdge, GraphNode, VueFlowStore, pointToRendererPoint } from '@vue-flow/core'; | 
| 2 | 2 | import { getRuleNodeCache, setRuleNodeCache } from './useRuleCopyPaste'; | 
| 3 | 3 | import { RuleContextMenuEnum } from './useRuleChainContextMenu'; | 
| 4 | 4 | import { useAddNodes } from './useAddNodes'; | 
| ... | ... | @@ -65,15 +65,15 @@ export function useContextMenuAction() { | 
| 65 | 65 | const copy = (params: HandleContextMenuActionParamsType) => { | 
| 66 | 66 | const { node } = params; | 
| 67 | 67 | if (!node) return; | 
| 68 |  | -    const { position, data } = node; | 
|  | 68 | +    const { position, data, id } = node; | 
| 69 | 69 | const { getAddNodesParams } = useAddNodes(); | 
| 70 | 70 | const { x, y } = position; | 
| 71 | 71 |  | 
| 72 |  | -    const value = getAddNodesParams(position, data, { id: buildUUID() }); | 
|  | 72 | +    const value = getAddNodesParams(position, data, { id }); | 
| 73 | 73 |  | 
| 74 | 74 | setRuleNodeCache({ | 
| 75 | 75 | nodes: [value], | 
| 76 |  | -      originX: x + NODE_WIDTH / 2 + x, | 
|  | 76 | +      originX: x + NODE_WIDTH / 2, | 
| 77 | 77 | originY: y + NODE_HEIGHT / 2, | 
| 78 | 78 | }); | 
| 79 | 79 | }; | 
| ... | ... | @@ -81,24 +81,49 @@ export function useContextMenuAction() { | 
| 81 | 81 | const paste = (params: HandleContextMenuActionParamsType) => { | 
| 82 | 82 | const { event, flowActionType, useSaveAndRedoActionType } = params; | 
| 83 | 83 | const { triggerChange } = useSaveAndRedoActionType || {}; | 
|  | 84 | + | 
| 84 | 85 | const { getAddNodesParams } = useAddNodes(); | 
| 85 | 86 | const { getAddedgesParams } = useAddEdges(); | 
| 86 |  | -    const clientX = (event as MouseEvent).offsetX; | 
| 87 |  | -    const clientY = (event as MouseEvent).offsetY; | 
| 88 | 87 |  | 
| 89 | 88 | const { edges = [], nodes = [], originX, originY } = getRuleNodeCache(); | 
| 90 | 89 |  | 
|  | 90 | +    const { x: clientX, y: clientY } = pointToRendererPoint( | 
|  | 91 | +      { x: (event as MouseEvent).offsetX, y: (event as MouseEvent).offsetY }, | 
|  | 92 | +      flowActionType!.getViewport(), | 
|  | 93 | +      false, | 
|  | 94 | +      [25, 25] | 
|  | 95 | +    ); | 
|  | 96 | + | 
|  | 97 | +    const xAxisMoveDistance = clientX - originX!; | 
|  | 98 | +    const yAxisMoveDistance = clientY - originY!; | 
|  | 99 | + | 
|  | 100 | +    const newEdges = edges.map((edge) => | 
|  | 101 | +      getAddedgesParams({ ...edge, id: buildUUID() }, edge.data) | 
|  | 102 | +    ); | 
|  | 103 | + | 
| 91 | 104 | const newNode = nodes.map((node) => { | 
| 92 |  | -      const { position, data, id } = node; | 
|  | 105 | +      const { position, data, id: oldId } = node; | 
| 93 | 106 | const { x, y } = position; | 
|  | 107 | +      const newId = buildUUID(); | 
| 94 | 108 |  | 
| 95 |  | -      const newX = clientX - originX! + x + NODE_WIDTH / 2; | 
| 96 |  | -      const newY = clientY - originY! + y + NODE_HEIGHT / 2; | 
|  | 109 | +      const newX = xAxisMoveDistance + x; | 
|  | 110 | +      const newY = yAxisMoveDistance + y; | 
| 97 | 111 |  | 
| 98 |  | -      return getAddNodesParams({ x: newX, y: newY }, { ...data, created: false }, { id }); | 
| 99 |  | -    }); | 
|  | 112 | +      for (const connection of newEdges || []) { | 
|  | 113 | +        if (connection.source.includes(oldId)) { | 
|  | 114 | +          connection.source = newId; | 
|  | 115 | +          connection.sourceHandle = connection.sourceHandle?.replaceAll(oldId, newId); | 
|  | 116 | +          continue; | 
|  | 117 | +        } | 
| 100 | 118 |  | 
| 101 |  | -    const newEdges = edges.map((edge) => getAddedgesParams(edge, edge.data)); | 
|  | 119 | +        if (connection.target.includes(oldId)) { | 
|  | 120 | +          connection.target = newId; | 
|  | 121 | +          connection.targetHandle = connection.targetHandle?.replaceAll(oldId, newId); | 
|  | 122 | +        } | 
|  | 123 | +      } | 
|  | 124 | + | 
|  | 125 | +      return getAddNodesParams({ x: newX, y: newY }, { ...data, created: false }, { id: newId }); | 
|  | 126 | +    }); | 
| 102 | 127 |  | 
| 103 | 128 | flowActionType?.addNodes(newNode); | 
| 104 | 129 | flowActionType?.addEdges(newEdges); | 
| ... | ... | @@ -153,23 +178,9 @@ export function useContextMenuAction() { | 
| 153 | 178 | ); | 
| 154 | 179 |  | 
| 155 | 180 | const nodes = unref(flowActionType?.getSelectedNodes)?.map((node) => { | 
| 156 |  | -      const { id: oldId } = node; | 
| 157 |  | -      const newId = buildUUID(); | 
| 158 |  | - | 
| 159 |  | -      for (const connection of edges || []) { | 
| 160 |  | -        if (connection.source.includes(oldId)) { | 
| 161 |  | -          connection.source = newId; | 
| 162 |  | -          connection.sourceHandle = connection.sourceHandle?.replaceAll(oldId, newId); | 
| 163 |  | -          continue; | 
| 164 |  | -        } | 
| 165 |  | - | 
| 166 |  | -        if (connection.target.includes(oldId)) { | 
| 167 |  | -          connection.target = newId; | 
| 168 |  | -          connection.targetHandle = connection.targetHandle?.replaceAll(oldId, newId); | 
| 169 |  | -        } | 
| 170 |  | -      } | 
|  | 181 | +      const { id } = node; | 
| 171 | 182 |  | 
| 172 |  | -      return getAddNodesParams(node.position, toRaw(unref(node.data)), { id: newId }); | 
|  | 183 | +      return getAddNodesParams(node.position, toRaw(unref(node.data)), { id }); | 
| 173 | 184 | }); | 
| 174 | 185 |  | 
| 175 | 186 | const originRect = getElementsCenter(unref(flowActionType?.getSelectedNodes) || []); | 
... | ... |  |