瀏覽代碼

连接桩布局

CzRger 2 月之前
父節點
當前提交
1645399552

+ 1 - 0
package.json

@@ -19,6 +19,7 @@
     "element-plus": "^2.9.7",
     "fast-glob": "^3.3.3",
     "highlight.js": "^11.11.1",
+    "lodash": "^4.17.21",
     "markdown-it": "^14.1.0",
     "marked": "^15.0.8",
     "npm": "^11.3.0",

+ 90 - 37
src/views/workflow/chart/index.vue

@@ -7,13 +7,70 @@
 </template>
 
 <script setup lang="ts">
-import {createVNode, getCurrentInstance, inject, onMounted, reactive, ref, render, watch} from "vue";
-import {Graph, Shape} from '@antv/x6'
+import {createVNode, getCurrentInstance, inject, nextTick, onMounted, provide, reactive, ref, render, watch} from "vue";
+import {Graph, Markup, Shape} from '@antv/x6'
 import {WorkflowFunc} from "@/views/workflow/types";
-import {lineStyle} from "@/views/workflow/config";
-import {ElTooltip} from "element-plus";
+import {lineStyle, portStyle} from "@/views/workflow/config";
 import nodeAdd from './node-add.vue'
+import {register} from "@antv/x6-vue-shape";
+import WorkflowNode from "@/views/workflow/nodes/index.vue";
+import {merge} from "lodash";
+import {handleEdge, handleNode} from "@/views/workflow/handle";
 
+register({
+  shape: 'workflow-node',
+  component: WorkflowNode,
+})
+let edgeTimer: any = null
+Graph.registerPortLayout('start', (portsPositionArgs, elemBBox) => {
+  return portsPositionArgs.map((_, index) => {
+    return {
+      position: {
+        x: 3,
+        y: 25 + 3,
+      },
+    }
+  })
+})
+Graph.registerPortLayout('end', (portsPositionArgs, elemBBox) => {
+  if (edgeTimer) {
+    clearTimeout(edgeTimer)
+  }
+  edgeTimer = setTimeout(() => {
+    initEdges()
+  }, 100)
+  return portsPositionArgs.map((_, index) => {
+    return {
+      position: {
+        x: elemBBox.width + 3,
+        y: 25 + 3,
+      },
+    }
+  })
+})
+Graph.registerPortLayout('more', (portsPositionArgs, elemBBox) => {
+  return portsPositionArgs.map((_, index) => {
+    nextTick(() => {
+      const dom = document.getElementById(_.portId)
+      if (dom) {
+        const node = state.graph.getCellById(_.nodeId)
+        node.portProp(_.portId, ['args', 'dy'], dom.offsetTop + 17)
+        if (edgeTimer) {
+          clearTimeout(edgeTimer)
+        }
+        edgeTimer = setTimeout(() => {
+          initEdges()
+        }, 100)
+      }
+    })
+    return {
+      position: {
+        x: elemBBox.width + 3,
+        y: _.dy,
+      },
+    }
+  })
+})
 const emits = defineEmits([])
 const props = defineProps({
   data: <any>{}
@@ -23,10 +80,11 @@ const state: any = reactive({
   graph: null,
   isPort: false
 })
+provide('graph', state.graph)
 const ref_chart = ref()
 const workflowFuncInject = inject('workflowFunc', {} as WorkflowFunc)
 const initChart = () => {
-  const graph = new Graph({
+  state.graph = new Graph({
     container: ref_chart.value,
     autoResize: true,
     panning: true,
@@ -77,54 +135,49 @@ const initChart = () => {
       })
     },
     onPortRendered: (args: any) => {
-      const selectors = args.contentSelectors;
-      const container = selectors && selectors.foContent;
+      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(
-          nodeAdd,
-          // {
-          //   // 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);
+        render(createVNode(nodeAdd, {
+          port: args.port,
+          node: args.node,
+          graph: state.graph,
+        }), container)
       }
     }
   })
-  graph.fromJSON(props.data)
-  graph.zoomToFit({ maxScale: 1 })
-  graph.centerContent() // 居中显示
-  graph.on('node:click', ({ e, x, y, node, view, port }) => {
+  initNodes()
+  state.graph.zoomToFit({ maxScale: 1 })
+  state.graph.centerContent() // 居中显示
+  initWatch()
+  // positionPort()
+}
+const initNodes = () => {
+  props.data.nodes.forEach(v => {
+    state.graph.addNode(handleNode(v))
+  })
+}
+const initEdges = () => {
+  props.data.edges.forEach(v => {
+    state.graph.addEdge(handleEdge(v))
+  })
+}
+const initWatch = () => {
+  state.graph.on('node:click', ({ e, x, y, node, view, port }) => {
     setTimeout(() => {
       if (!state.isPort) {
-        console.log(node)
         workflowFuncInject.nodeClick(node)
       }
     }, 50)
   })
-  graph.on('node:port:click', ({ e, x, y, node, view, port }) => {
+  state.graph.on('node:port:click', ({ e, x, y, node, view, port }) => {
     state.isPort = true;
     setTimeout(() => {
       state.isPort = false
     }, 100)
   })
-  state.graph = graph
 }
+
 watch(() => props.data, (n) => {
   if (n) {
     initChart()

+ 79 - 17
src/views/workflow/chart/node-add.vue

@@ -1,34 +1,96 @@
 <template>
-  <ElPopover placement="right" :width="400" trigger="click">
-    <template #reference>
-      <ElTooltip
-        placement="top"
-        content="123"
-        raw-content
-      >
-        <div class="port"/>
-      </ElTooltip>
-    </template>
-    <div> asdasdasdasdSdasdasdasdasdsdasd</div>
-  </ElPopover>
+  <template v-if="port?.group === 'start'">
+    <div class="port">
+      <div/>
+    </div>
+  </template>
+  <template v-else>
+    <ElPopover placement="right" trigger="click">
+      <template #reference>
+        <div class="port">
+          <ElTooltip
+            placement="top"
+            content="123"
+            raw-content
+          >
+            <div/>
+          </ElTooltip>
+        </div>
+      </template>
+      <div class="node-add">
+        <div class="node-add-item __hover" @click="onAddNode('test')">测试节点</div>
+        <div class="node-add-item __hover" @click="onAddNode('if-else')">条件分支</div>
+      </div>
+    </ElPopover>
+  </template>
 </template>
 
 <script setup lang="ts">
-import {getCurrentInstance, reactive, ref} from "vue";
+import {getCurrentInstance, inject, reactive, ref} from "vue";
 import { ElPopover, ElTooltip } from 'element-plus';
+import {getNodeDefault} from "@/views/workflow/config";
+import {WorkflowFunc} from "@/views/workflow/types";
+import {handleEdge, handleNode} from "@/views/workflow/handle";
 
 const emits = defineEmits([])
-const props = defineProps({})
+const props = defineProps({
+  port: <any>{},
+  node: <any>{},
+  graph: <any>{},
+})
 const {proxy}: any = getCurrentInstance()
 const state: any = reactive({})
+const onAddNode = (type) => {
+  console.log(props.port)
+  const node = getNodeDefault(type)
+  console.log(props.node.getChildren())
+  const sons = props.graph.getSuccessors(props.node, {breadthFirst: true, deep: false, distance: 1})
+  const diff = 100
+  let X = 0
+  let Y = 0
+  console.log(sons)
+  if (sons.length > 0) {
+    sons.forEach(s => {
+      const {x, y} = s.position()
+      const {width, height} = s.size()
+      X = Math.max(x, X)
+      Y = Math.max(y + height, Y)
+    })
+  } else {
+    const {x, y} = props.node.position()
+    const {width, height} = props.node.size()
+    X = x + width + diff
+    Y = y
+  }
+
+  node.x = X
+  node.y = Y + diff
+  props.graph.addNode(handleNode(node))
+  const edge = {
+    target: node.id,
+    source: props.port.args.nodeId,
+    port: '',
+  }
+  if (props.port.args.type === 'more') {
+    edge.port = props.port.id
+  }
+  props.graph.addEdge(handleEdge(edge))
+}
 </script>
 
 <style lang="scss" scoped>
 .port {
   width: 100%;
   height: 100%;
-  border: 1px solid #8f8f8f;
-  background-color: #ffffff;
-  border-radius: 50%;
+  >div {
+    width: 100%;
+    height: 100%;
+    border: 1px solid #8f8f8f;
+    background-color: #ffffff;
+    border-radius: 50%;
+  }
+}
+.node-add {
+  width: 100px;
 }
 </style>

+ 60 - 4
src/views/workflow/config.ts

@@ -1,3 +1,6 @@
+import { v4 } from "uuid";
+import {NodeDataStruct, NodePortStruct, NodeStruct} from "@/views/workflow/types";
+
 export const lineStyle = {
   line: {
     stroke: '#8f8f8f',
@@ -15,10 +18,63 @@ export const portStyle = {
       magnet: true,
     },
   },
-  position: {
-    name: 'right',
-    args: {
-      dx: 3
+}
+
+export const nodeDefault = {
+
+  test: <NodeStruct>{
+    id: '',
+    x: 0,
+    y: 0,
+    data: <NodeDataStruct>{
+      id: '',
+      title: '测试节点',
+      type: 'test',
     }
   },
+  root: <NodeStruct>{
+    id: '',
+    x: 0,
+    y: 0,
+    data: <NodeDataStruct>{
+      id: '',
+      title: '开始',
+      type: 'root',
+    }
+  },
+  'if-else': <NodeStruct>{
+    id: '',
+    x: 0,
+    y: 0,
+    data: <NodeDataStruct>{
+      id: '',
+      title: '条件分支',
+      type: 'if-else',
+      ports: <NodePortStruct[]>[
+        {
+          id: '',
+          data: {
+            p1: ''
+          }
+        },
+        {
+          id: '',
+          data: {
+            p1: ''
+          }
+        },
+      ],
+    }
+  }
 }
+export const getNodeDefault = (type) => {
+  const res = nodeDefault[type]
+  res.id = v4()
+  res.data.id = res.id
+  if (type === "if-else") {
+    res.data.ports.forEach(port => {
+      port.id = v4()
+    })
+  }
+  return res
+}

+ 79 - 0
src/views/workflow/handle.ts

@@ -0,0 +1,79 @@
+import { v4 } from "uuid";
+import {Markup} from "@antv/x6";
+import {merge} from "lodash";
+import {lineStyle, portStyle} from "@/views/workflow/config";
+
+export const handleNode = (data) => {
+  const node: any = {
+    ...data,
+    shape: 'workflow-node',
+    portMarkup: [Markup.getForeignObjectMarkup()],
+    ports: {
+      groups: {
+        start: merge(JSON.parse(JSON.stringify(portStyle)), {position: {name: 'start'}}),
+        end: merge(JSON.parse(JSON.stringify(portStyle)), {position: {name: 'end'}}),
+        more: merge(JSON.parse(JSON.stringify(portStyle)), {position: {name: 'more'}}),
+      },
+      items: []
+    },
+  }
+  node.data.id = data.id
+  if (data.data.type !== 'root') {
+    node.ports.items.push({
+      id: `${data.id}_start`,
+      group: 'start',
+      args: {
+        type: 'start',
+        nodeId: data.id,
+      }
+    })
+  }
+  if (data.data.ports?.length > 0) {
+    data.data.ports.forEach((p, pI) => {
+      node.ports.items.push({
+        id: p.id,
+        group: 'more',
+        args: {
+          type: 'more',
+          portId: p.id,
+          nodeId: data.id,
+          dy: 0
+        }
+      })
+    })
+  } else {
+    node.ports.items.push({
+      id: `${data.id}_end`,
+      group: 'end',
+      args: {
+        type: 'end',
+        nodeId: data.id,
+      }
+    })
+  }
+  return node
+}
+
+export const handleEdge = (data) => {
+  const edge = {
+    ...data,
+    shape: 'edge',
+    attrs: lineStyle,
+    router: {
+      name: 'manhattan',
+      args: {
+        startDirections: ['right'],
+        endDirections: ['left'],
+      },
+    },
+  }
+  edge.source = {
+    cell: data.source,
+    port: data.port || `${data.source}_end`
+  }
+  edge.target = {
+    cell: data.target,
+    port: `${data.target}_start`
+  }
+  return edge
+}

+ 3 - 83
src/views/workflow/index.vue

@@ -13,17 +13,11 @@
 import {getCurrentInstance, onMounted, provide, reactive, ref} from "vue";
 import workflowChart from './chart/index.vue'
 import workflowPanel from './panel/index.vue'
-import { getTeleport, register } from '@antv/x6-vue-shape'
+import { getTeleport } from '@antv/x6-vue-shape'
 import {data} from './mockJson'
 import {WorkflowFunc} from "@/views/workflow/types";
-import WorkflowNode from "@/views/workflow/nodes/index.vue";
-import {lineStyle, portStyle} from "@/views/workflow/config";
-import {Markup} from "@antv/x6";
 const TeleportContainer = getTeleport()
-register({
-  shape: 'workflow-node',
-  component: WorkflowNode,
-})
+
 const emits = defineEmits([])
 const props = defineProps({})
 const {proxy}: any = getCurrentInstance()
@@ -44,81 +38,7 @@ const getJsonData = () => {
   console.log(data)
 }
 const initData = () => {
-  const formatData = (data) => {
-    const res: any = {
-      nodes: [],
-      edges: [],
-    }
-    data.nodes.forEach((v) => {
-      const node = {
-        ...v,
-        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)
-    })
-    data.edges.forEach((v) => {
-      const edge = {
-        ...v,
-        shape: 'edge',
-        attrs: lineStyle,
-        router: {
-          name: 'manhattan',
-          args: {
-            startDirections: ['right'],
-            endDirections: ['left'],
-          },
-        },
-      }
-      edge.source = {
-        cell: v.source,
-        port: v.port || `${v.source}_end`
-      }
-      edge.target = {
-        cell: v.target,
-        port: `${v.target}_start`
-      }
-      res.edges.push(edge)
-    })
-    return res
-  }
-  state.workflowData = formatData(data)
+  state.workflowData = data
 }
 onMounted(() => {
   initData()

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

@@ -1,57 +1,7 @@
-// export const data = {
-//   nodes: [
-//     {
-//       id: 'node1',
-//       shape: 'workflow-node',
-//       x: 40,
-//       y: 40,
-//       width: 100,
-//       height: 100,
-//       data: {
-//         title: '开始节点xx',
-//         type: 'root',
-//         p1: '啥的哈哈哈哈哈'
-//       }
-//     },
-//     {
-//       id: 'node2',
-//       shape: 'workflow-node',
-//       x: 160,
-//       y: 180,
-//       width: 100,
-//       height: 100,
-//       data: {
-//         title: '条件判断节点fff',
-//         type: 'if-else',
-//         p1: 'asfasfa飞洒'
-//       }
-//     },
-//   ],
-//   edges: [
-//     {
-//       shape: 'edge',
-//       source: {
-//         cell: 'node1',
-//         anchor: {
-//           name: 'topRight'
-//         }
-//       },
-//       target: 'node2',
-//       attrs: {
-//         // line 是选择器名称,选中的边的 path 元素
-//         line: {
-//           stroke: '#8f8f8f',
-//           strokeWidth: 1,
-//         },
-//       },
-//     },
-//   ],
-// }
-
 export const data = {
   "nodes": [
     {
-      "id": "node1",
+      "id": "3ba412bb-3772-4f61-85de-095f4017858c",
       "x": 0,
       "y": 0,
       "data": {
@@ -61,7 +11,7 @@ export const data = {
       }
     },
     {
-      "id": "node2",
+      "id": "676e9ade-d857-4fea-b2d4-ff9484dcebb8",
       "x": 400,
       "y": 0,
       "data": {
@@ -69,13 +19,13 @@ export const data = {
         "type": "if-else",
         "ports": [
           {
-            "id": "port1",
+            "id": "ce2c26aa-9b40-4e32-858e-38fa4b09718d",
             "data": {
               "p1": "条件分支1的桩1"
             }
           },
           {
-            "id": "port2",
+            "id": "7171167d-873b-4621-9ce1-dd45f9f4c9c3",
             "data": {
               "p1": "条件分支1的桩2"
             }
@@ -85,7 +35,7 @@ export const data = {
       }
     },
     {
-      "id": "node3",
+      "id": "b39b1a2f-8474-456b-8859-ce0b6597dd47",
       "x": 400,
       "y": 200,
       "data": {
@@ -93,13 +43,13 @@ export const data = {
         "type": "if-else",
         "ports": [
           {
-            "id": "port1",
+            "id": "6a5cde35-141d-4006-b5b2-89f0e567c7a8",
             "data": {
               "p1": "条件分支1的桩1"
             }
           },
           {
-            "id": "port2",
+            "id": "fab2de26-7769-4a3d-8727-1f11b01054c6",
             "data": {
               "p1": "条件分支1的桩2"
             }
@@ -111,13 +61,13 @@ export const data = {
   ],
   "edges": [
     {
-      "target": "node2",
-      "source": "node1"
+      "target": "676e9ade-d857-4fea-b2d4-ff9484dcebb8",
+      "source": "3ba412bb-3772-4f61-85de-095f4017858c"
     },
     {
-      "target": "node3",
-      "source": "node2",
-      "port": "port1"
+      "target": "b39b1a2f-8474-456b-8859-ce0b6597dd47",
+      "source": "676e9ade-d857-4fea-b2d4-ff9484dcebb8",
+      "port": "7171167d-873b-4621-9ce1-dd45f9f4c9c3"
     }
   ]
 }

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

@@ -1,15 +1,25 @@
 <template>
   <div class="node-if-else">
-    <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 v-for="(port, index) in state.nodeData.ports">
+      <div class="port-item" :id="port.id">
+        <div class="port-item-head">
+          <template v-if="index === 0">
+            <span>CASE {{ index + 1 }}</span>
+            <span>IF</span>
+          </template>
+          <template v-else-if="index === state.nodeData.ports.length - 1">
+            <span></span>
+            <span>ELSE</span>
+          </template>
+          <template v-else>
+            <span>CASE {{ index + 1 }}</span>
+            <span>ELSE IF</span>
+          </template>
+        </div>
+        <div v-if="index < state.nodeData.ports.length - 1">
+          {{port.data.p1}}
+        </div>
+      </div>
     </template>
   </div>
 </template>
@@ -31,6 +41,12 @@ onMounted(() => {
 </script>
 
 <style lang="scss" scoped>
-.node-root {
+.node-if-else {
+  .port-item {
+    .port-item-head {
+      display: flex;
+      justify-content: space-between;
+    }
+  }
 }
 </style>

+ 5 - 2
src/views/workflow/nodes/index.vue

@@ -13,7 +13,7 @@
 </template>
 
 <script setup lang="ts">
-import {computed, getCurrentInstance, inject, onMounted, reactive, ref} from "vue";
+import {computed, getCurrentInstance, inject, nextTick, onMounted, reactive, ref} from "vue";
 import rootNode from './root/index.vue'
 import ifElseNode from './if-else/index.vue'
 
@@ -27,9 +27,12 @@ const state: any = reactive({
 })
 const ref_node = ref()
 onMounted(() => {
+  console.log(123)
   state.node = getNode()
   state.nodeData = state.node.data
-  state.node.size(ref_node.value.clientWidth, ref_node.value.clientHeight)
+  nextTick(() => {
+    state.node.size(ref_node.value.clientWidth, ref_node.value.clientHeight)
+  })
 })
 </script>
 

+ 32 - 1
src/views/workflow/panel/is-else/index.vue

@@ -1,11 +1,22 @@
 <template>
   <div class="root-panel" v-if="state.nodeData">
-    <el-input v-model="state.nodeData.p1"/>
+    <template v-for="(port, index) in state.nodeData.ports">
+      <div v-if="index < state.nodeData.ports.length - 1">
+        <div>
+          CASE {{index + 1}}
+        </div>
+        <div>
+          <el-input v-model="port.data.p1"/>
+        </div>
+      </div>
+    </template>
+    <el-button type="primary" @click="onAddPort">添加条件分支</el-button>
   </div>
 </template>
 
 <script setup lang="ts">
 import {getCurrentInstance, reactive, ref, watch} from "vue";
+import { v4 } from "uuid";
 
 const emits = defineEmits([])
 const props = defineProps({
@@ -18,8 +29,28 @@ const state: any = reactive({
 watch(() => props.node, (n) => {
   if (n) {
     state.nodeData = n.data
+    console.log(state.nodeData)
   }
 }, {immediate: true})
+const onAddPort = () => {
+  console.log(props.node)
+  const data = {
+    id: v4(),
+    data: {
+      p1: ''
+    }
+  }
+  props.node.addPort({
+    id: data.id,
+    group: 'more',
+    args: {
+      portId: data.id,
+      nodeId: props.node.id,
+      dy: 0
+    }
+  })
+  state.nodeData.ports.splice(state.nodeData.ports.length - 1, 0, data)
+}
 </script>
 
 <style lang="scss" scoped>

+ 19 - 0
src/views/workflow/types.ts

@@ -1,3 +1,22 @@
 export type WorkflowFunc = {
   nodeClick: (node) => void
+}
+
+export type NodeStruct = {
+  id: string
+  x: number
+  y: number
+  data: NodeDataStruct
+}
+
+export type NodeDataStruct = {
+  id: string
+  title: string
+  type: 'test' | 'root' | 'if-else'
+  ports?: NodePortStruct[]
+}
+
+export type NodePortStruct = {
+  id: string
+  data: any
 }

+ 2 - 7
yarn.lock

@@ -2908,7 +2908,7 @@ lodash-unified@^1.0.2:
 
 lodash@^4.17.21:
   version "4.17.21"
-  resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz"
+  resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
   integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
 
 lru-cache@^10.0.1, lru-cache@^10.2.0, lru-cache@^10.2.2:
@@ -4683,12 +4683,7 @@ vscode-uri@^3.0.8:
   resolved "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz"
   integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==
 
-vue-demi@*:
-  version "0.14.10"
-  resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz"
-  integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
-
-vue-demi@latest:
+vue-demi@*, vue-demi@latest:
   version "0.14.10"
   resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
   integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==