Browse Source

连接桩问题

CzRger 3 months ago
parent
commit
42eb7a282c

+ 72 - 6
src/views/workflow/chart/index.vue

@@ -7,9 +7,11 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import {getCurrentInstance, inject, onMounted, reactive, ref, watch} from "vue";
-import { Graph } from '@antv/x6'
+import {createVNode, getCurrentInstance, inject, onMounted, reactive, ref, render, watch} from "vue";
+import {Graph, Shape} from '@antv/x6'
 import {WorkflowFunc} from "@/views/workflow/types";
 import {WorkflowFunc} from "@/views/workflow/types";
+import {lineStyle} from "@/views/workflow/config";
+import {ElTooltip} from "element-plus";
 
 
 const emits = defineEmits([])
 const emits = defineEmits([])
 const props = defineProps({
 const props = defineProps({
@@ -43,14 +45,78 @@ const initChart = () => {
       ],
       ],
     },
     },
     connecting: {
     connecting: {
-      anchor: {
-        name: 'topLeft',
+      snap: { //  连线过程中自动吸附
+        radius: 20,
+      },
+      allowBlank: false,  //  是否允许连接到画布空白位置的点
+      allowLoop: false,  //  是否允许创建循环连线,即边的起始节点和终止节点为同一节点
+      allowNode: false,  //  是否允许边连接到节点
+      allowEdge: false,  //  是否允许边链接到另一个边
+      allowPort: ({sourcePort, targetPort}: any) => {  //  是否允许边链接到连接桩
+        return !sourcePort?.includes('start') && targetPort?.includes('start')
+      },
+      allowMulti: 'withPort', //  当设置为 'withPort' 时,在起始和终止节点的相同连接桩之间只允许创建一条边(即,起始和终止节点之间可以创建多条边,但必须要要链接在不同的连接桩上)
+      highlight: true,
+      router: {
+        name: 'manhattan',
+        args: {
+          startDirections: ['right'],
+          endDirections: ['left'],
+        },
+      },
+      connector: {
+        name: 'rounded',
         args: {
         args: {
-          dx: 0,
-          dy: 25
+          radius: 20,
         },
         },
       },
       },
+      createEdge: () => new Shape.Edge({
+        attrs: lineStyle
+      })
     },
     },
+    onPortRendered: (args: any) => {
+      const selectors = args.contentSelectors;
+      const container = selectors && selectors.foContent;
+      if (container) {
+        const portName = '<div><div><span style="font-weight: bold">点击</span>添加节点</div><div><span style="font-weight: bold">拖拽</span>连接节点</div></div>'
+        const dom = createVNode(
+          ElTooltip,
+          {
+            effect: "light",
+            content: portName,
+            placement: "top",
+            rawContent: true
+          },
+          [
+            createVNode("div", {
+              class: "createVNode",
+              style: {
+                border: '1px solid #8f8f8f',
+                backgroundColor: '#ffffff',
+                height: '100%',
+                width: '100%',
+                borderRadius: '50%',
+              }
+            }),
+          ]
+        );
+        render(dom, container);
+      }
+      // container.addEventListener('mouseenter', (e: MouseEvent) => {
+      //   const tooltip = document.querySelector('.x6-tooltip') as HTMLElement
+      //   const content = tooltip?.querySelector('.ant-tooltip-inner') as HTMLElement
+      //   if (content) {
+      //     content.innerText = text
+      //     tooltip.style.left = `${e.clientX - content.offsetWidth / 2}px`
+      //     tooltip.style.top = `${e.clientY - 50}px`
+      //   }
+      // })
+      // container.addEventListener('mouseleave', () => {
+      //   const tooltip = document.querySelector('.x6-tooltip') as HTMLElement
+      //   tooltip.style.left = '-1000px'
+      //   tooltip.style.top = '-1000px'
+      // })
+    }
   })
   })
   graph.fromJSON(props.data)
   graph.fromJSON(props.data)
   graph.zoomToFit({ maxScale: 1 })
   graph.zoomToFit({ maxScale: 1 })

+ 24 - 0
src/views/workflow/config.ts

@@ -0,0 +1,24 @@
+export const lineStyle = {
+  line: {
+    stroke: '#8f8f8f',
+    strokeWidth: 1,
+  },
+}
+
+export const portStyle = {
+  attrs: {
+    fo: {
+      width: 12,
+      height: 12,
+      x: -6,
+      y: -6,
+      magnet: true,
+    },
+  },
+  position: {
+    name: 'right',
+    args: {
+      dx: 3
+    }
+  },
+}

+ 45 - 13
src/views/workflow/index.vue

@@ -17,6 +17,8 @@ import { getTeleport, register } from '@antv/x6-vue-shape'
 import {data} from './mockJson'
 import {data} from './mockJson'
 import {WorkflowFunc} from "@/views/workflow/types";
 import {WorkflowFunc} from "@/views/workflow/types";
 import WorkflowNode from "@/views/workflow/nodes/index.vue";
 import WorkflowNode from "@/views/workflow/nodes/index.vue";
+import {lineStyle, portStyle} from "@/views/workflow/config";
+import {Markup} from "@antv/x6";
 const TeleportContainer = getTeleport()
 const TeleportContainer = getTeleport()
 register({
 register({
   shape: 'workflow-node',
   shape: 'workflow-node',
@@ -51,6 +53,43 @@ const initData = () => {
       const node = {
       const node = {
         ...v,
         ...v,
         shape: 'workflow-node',
         shape: 'workflow-node',
+        portMarkup: [Markup.getForeignObjectMarkup()],
+        ports: {
+          groups: {
+            start: {
+              ...portStyle,
+              position: {
+                name: 'left',
+              }
+            },
+            end: portStyle,
+            more: portStyle,
+          },
+          items: []
+        }
+      }
+      if (v.data.type !== 'root') {
+        node.ports.items.push({
+          id: `${v.id}_start`,
+          group: 'start'
+        },)
+      }
+      if (v.data.ports?.length > 0) {
+        v.data.ports.forEach((p, pI) => {
+          const offset = 50
+          node.ports.items.push({
+            id: p.id,
+            group: 'more',
+            args: {
+              dy: offset
+            }
+          },)
+        })
+      } else {
+        node.ports.items.push({
+          id: `${v.id}_end`,
+          group: 'end'
+        })
       }
       }
       res.nodes.push(node)
       res.nodes.push(node)
     })
     })
@@ -58,12 +97,7 @@ const initData = () => {
       const edge = {
       const edge = {
         ...v,
         ...v,
         shape: 'edge',
         shape: 'edge',
-        attrs: {
-          line: {
-            stroke: '#8f8f8f',
-            strokeWidth: 1,
-          },
-        },
+        attrs: lineStyle,
         router: {
         router: {
           name: 'manhattan',
           name: 'manhattan',
           args: {
           args: {
@@ -74,13 +108,11 @@ const initData = () => {
       }
       }
       edge.source = {
       edge.source = {
         cell: v.source,
         cell: v.source,
-        anchor: {
-          name: 'topRight',
-          args: {
-            dx: 0,
-            dy: 25
-          }
-        },
+        port: v.port || `${v.source}_end`
+      }
+      edge.target = {
+        cell: v.target,
+        port: `${v.target}_start`
       }
       }
       res.edges.push(edge)
       res.edges.push(edge)
     })
     })

+ 62 - 19
src/views/workflow/mockJson.ts

@@ -49,33 +49,76 @@
 // }
 // }
 
 
 export const data = {
 export const data = {
-  nodes: [
+  "nodes": [
     {
     {
-      id: 'node1',
-      x: 40,
-      y: 40,
-      data: {
-        title: '开始节点xx',
-        type: 'root',
-        p1: '啥的哈哈哈哈哈'
+      "id": "node1",
+      "x": 0,
+      "y": 0,
+      "data": {
+        "title": "开始",
+        "type": "root",
+        "p1": "开始的参数1",
       }
       }
     },
     },
     {
     {
-      id: 'node2',
-      x: 160,
-      y: 180,
-      data: {
-        title: '条件判断节点fff',
-        type: 'if-else',
-        p1: 'asfasfa飞洒'
+      "id": "node2",
+      "x": 400,
+      "y": 0,
+      "data": {
+        "title": "条件分支",
+        "type": "if-else",
+        "ports": [
+          {
+            "id": "port1",
+            "data": {
+              "p1": "条件分支1的桩1"
+            }
+          },
+          {
+            "id": "port2",
+            "data": {
+              "p1": "条件分支1的桩2"
+            }
+          }
+        ],
+        "p1": "条件分支1的的参数1",
       }
       }
     },
     },
+    {
+      "id": "node3",
+      "x": 400,
+      "y": 200,
+      "data": {
+        "title": "条件分支",
+        "type": "if-else",
+        "ports": [
+          {
+            "id": "port1",
+            "data": {
+              "p1": "条件分支1的桩1"
+            }
+          },
+          {
+            "id": "port2",
+            "data": {
+              "p1": "条件分支1的桩2"
+            }
+          }
+        ],
+        "p1": "条件分支2的参数1",
+      }
+    }
   ],
   ],
-  edges: [
+  "edges": [
     {
     {
-      source: 'node1',
-      target: 'node2',
+      "target": "node2",
+      "source": "node1"
     },
     },
-  ],
+    {
+      "target": "node3",
+      "source": "node2",
+      "port": "port1"
+    }
+  ]
 }
 }
 
 

+ 11 - 1
src/views/workflow/nodes/if-else/index.vue

@@ -1,6 +1,16 @@
 <template>
 <template>
   <div class="node-if-else">
   <div class="node-if-else">
-    <div>p1:{{state.nodeData?.p1}}</div>
+    <template v-for="(item, index) in state.nodeData.ports">
+      <template v-if="index === 0">
+        <div>IF</div>
+      </template>
+      <template v-else-if="index === state.nodeData.ports.length - 1">
+        <div>ELSE</div>
+      </template>
+      <template v-else>
+        <div>ELSE IF:{{state.nodeData?.p1}}</div>
+      </template>
+    </template>
   </div>
   </div>
 </template>
 </template>