Vue2.0+AntvX6
Vue2.0+AntvX6
·
Vue2.0+AntvX6
前篇文章实现了AntvX6流程图 这篇是另一种效果,但都是Vue2.0+AntvX6,antv/x6版本都是"@antv/x6": “~1.16.0”,其实现的效果图如下:
流程线也可以配置信息
其实现的代码如下:
<template>
<div>
<el-button style="float: right; margin-top: -75px; margin-right: 80px" size="mini" type="primary" @click="saveFlow">保存</el-button>
<el-container class="process-edit-container">
<!-- 顶部功能区域 -->
<!-- <el-header>-->
<!-- </el-header>-->
<el-container>
<!-- 左侧组件区域 -->
<el-aside width="200px">
<div class="process-component-list">
<img
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0ic3RhcnRfbm9kZSIgd2lkdGg9IjgwcHgiIGhlaWdodD0iODBweCIgdmlld0JveD0iMCAwIDgwIDgwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPCEtLSBHZW5lcmF0b3I6IFNrZXRjaCA0OS4xICg1MTE0NykgLSBodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2ggLS0+CiAgICA8dGl0bGU+R3JvdXAgMjwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPgogICAgICAgIDxjaXJjbGUgaWQ9InBhdGgtMSIgY3g9IjM2IiBjeT0iMzYiIHI9IjM2Ij48L2NpcmNsZT4KICAgICAgICA8ZmlsdGVyIHg9Ii05LjclIiB5PSItNi45JSIgd2lkdGg9IjExOS40JSIgaGVpZ2h0PSIxMTkuNCUiIGZpbHRlclVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgaWQ9ImZpbHRlci0yIj4KICAgICAgICAgICAgPGZlT2Zmc2V0IGR4PSIwIiBkeT0iMiIgaW49IlNvdXJjZUFscGhhIiByZXN1bHQ9InNoYWRvd09mZnNldE91dGVyMSI+PC9mZU9mZnNldD4KICAgICAgICAgICAgPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMiIgaW49InNoYWRvd09mZnNldE91dGVyMSIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIj48L2ZlR2F1c3NpYW5CbHVyPgogICAgICAgICAgICA8ZmVDb21wb3NpdGUgaW49InNoYWRvd0JsdXJPdXRlcjEiIGluMj0iU291cmNlQWxwaGEiIG9wZXJhdG9yPSJvdXQiIHJlc3VsdD0ic2hhZG93Qmx1ck91dGVyMSI+PC9mZUNvbXBvc2l0ZT4KICAgICAgICAgICAgPGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgICAwIDAgMCAwIDAgICAwIDAgMCAwIDAgIDAgMCAwIDAuMDQgMCIgdHlwZT0ibWF0cml4IiBpbj0ic2hhZG93Qmx1ck91dGVyMSI+PC9mZUNvbG9yTWF0cml4PgogICAgICAgIDwvZmlsdGVyPgogICAgPC9kZWZzPgogICAgPGcgaWQ9IlBhZ2UtMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IuWfuuehgOa1geeoi+Wbvi0wMSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEwNi4wMDAwMDAsIC05My4wMDAwMDApIj4KICAgICAgICAgICAgPGcgaWQ9Ikdyb3VwLTIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDExMC4wMDAwMDAsIDk1LjAwMDAwMCkiPgogICAgICAgICAgICAgICAgPGcgaWQ9Ik92YWwiPgogICAgICAgICAgICAgICAgICAgIDx1c2UgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMSIgZmlsdGVyPSJ1cmwoI2ZpbHRlci0yKSIgeGxpbms6aHJlZj0iI3BhdGgtMSI+PC91c2U+CiAgICAgICAgICAgICAgICAgICAgPHVzZSBmaWxsLW9wYWNpdHk9IjAuOTIiIGZpbGw9IiNGRkYyRTgiIGZpbGwtcnVsZT0iZXZlbm9kZCIgeGxpbms6aHJlZj0iI3BhdGgtMSI+PC91c2U+CiAgICAgICAgICAgICAgICAgICAgPGNpcmNsZSBzdHJva2U9IiNGRkMwNjkiIHN0cm9rZS13aWR0aD0iMSIgY3g9IjM2IiBjeT0iMzYiIHI9IjM1LjUiPjwvY2lyY2xlPgogICAgICAgICAgICAgICAgPC9nPgogICAgICAgICAgICAgICAgPHRleHQgaWQ9IuW8gOWni+iKgueCuSIgZm9udC1mYW1pbHk9IlBpbmdGYW5nU0MtUmVndWxhciwgUGluZ0ZhbmcgU0MiIGZvbnQtc2l6ZT0iMTIiIGZvbnQtd2VpZ2h0PSJub3JtYWwiIGxpbmUtc3BhY2luZz0iMTIiIGZpbGw9IiMwMDAwMDAiIGZpbGwtb3BhY2l0eT0iMC42NSI+CiAgICAgICAgICAgICAgICAgICAgPHRzcGFuIHg9IjEyIiB5PSI0MSI+5byA5aeL6IqC54K5PC90c3Bhbj4KICAgICAgICAgICAgICAgIDwvdGV4dD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+"
data-type="node"
data-shape="circle"
data-size="72*72"
data-color="#FA8C16"
data-label="开始节点"
@mousedown="addNodeToGraph">
<img
draggable="false"
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iODhweCIgaGVpZ2h0PSI1NnB4IiB2aWV3Qm94PSIwIDAgODggNTYiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDQ5LjEgKDUxMTQ3KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Hcm91cDwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPgogICAgICAgIDxyZWN0IGlkPSJwYXRoLTEiIHg9IjAiIHk9IjAiIHdpZHRoPSI4MCIgaGVpZ2h0PSI0OCIgcng9IjQiPjwvcmVjdD4KICAgICAgICA8ZmlsdGVyIHg9Ii04LjglIiB5PSItMTAuNCUiIHdpZHRoPSIxMTcuNSUiIGhlaWdodD0iMTI5LjIlIiBmaWx0ZXJVbml0cz0ib2JqZWN0Qm91bmRpbmdCb3giIGlkPSJmaWx0ZXItMiI+CiAgICAgICAgICAgIDxmZU9mZnNldCBkeD0iMCIgZHk9IjIiIGluPSJTb3VyY2VBbHBoYSIgcmVzdWx0PSJzaGFkb3dPZmZzZXRPdXRlcjEiPjwvZmVPZmZzZXQ+CiAgICAgICAgICAgIDxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIiIGluPSJzaGFkb3dPZmZzZXRPdXRlcjEiIHJlc3VsdD0ic2hhZG93Qmx1ck91dGVyMSI+PC9mZUdhdXNzaWFuQmx1cj4KICAgICAgICAgICAgPGZlQ29tcG9zaXRlIGluPSJzaGFkb3dCbHVyT3V0ZXIxIiBpbjI9IlNvdXJjZUFscGhhIiBvcGVyYXRvcj0ib3V0IiByZXN1bHQ9InNoYWRvd0JsdXJPdXRlcjEiPjwvZmVDb21wb3NpdGU+CiAgICAgICAgICAgIDxmZUNvbG9yTWF0cml4IHZhbHVlcz0iMCAwIDAgMCAwICAgMCAwIDAgMCAwICAgMCAwIDAgMCAwICAwIDAgMCAwLjA0IDAiIHR5cGU9Im1hdHJpeCIgaW49InNoYWRvd0JsdXJPdXRlcjEiPjwvZmVDb2xvck1hdHJpeD4KICAgICAgICA8L2ZpbHRlcj4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSLln7rnoYDmtYHnqIvlm74tMDEiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC02LjAwMDAwMCwgLTEwNS4wMDAwMDApIj4KICAgICAgICAgICAgPGcgaWQ9Ikdyb3VwIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMC4wMDAwMDAsIDEwNy4wMDAwMDApIj4KICAgICAgICAgICAgICAgIDxnIGlkPSJSZWN0YW5nbGUtMTUtQ29weSI+CiAgICAgICAgICAgICAgICAgICAgPHVzZSBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIxIiBmaWx0ZXI9InVybCgjZmlsdGVyLTIpIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgICAgICAgICA8dXNlIGZpbGwtb3BhY2l0eT0iMC45MiIgZmlsbD0iI0U2RjdGRiIgZmlsbC1ydWxlPSJldmVub2RkIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgICAgICAgICA8cmVjdCBzdHJva2U9IiMxODkwRkYiIHN0cm9rZS13aWR0aD0iMSIgeD0iMC41IiB5PSIwLjUiIHdpZHRoPSI3OSIgaGVpZ2h0PSI0NyIgcng9IjQiPjwvcmVjdD4KICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgICAgIDx0ZXh0IGlkPSLlrqHmibnoioLngrkiIGZvbnQtZmFtaWx5PSJQaW5nRmFuZ1NDLVJlZ3VsYXIsIFBpbmdGYW5nIFNDIiBmb250LXNpemU9IjEyIiBmb250LXdlaWdodD0ibm9ybWFsIiBsaW5lLXNwYWNpbmc9IjEyIiBmaWxsPSIjMDAwMDAwIiBmaWxsLW9wYWNpdHk9IjAuNjUiPgogICAgICAgICAgICAgICAgICAgIDx0c3BhbiB4PSIxNiIgeT0iMjkiPuWuoeaJueiKgueCuTwvdHNwYW4+CiAgICAgICAgICAgICAgICA8L3RleHQ+CiAgICAgICAgICAgIDwvZz4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg=="
data-type="node"
data-shape="rect"
data-size="80*48"
data-color="#1890FF"
data-label="审批节点"
@mousedown="addNodeToGraph">
<img
draggable="false"
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iODZweCIgaGVpZ2h0PSI3OHB4IiB2aWV3Qm94PSIwIDAgODYgNzgiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDQ5LjEgKDUxMTQ3KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Hcm91cCAzPC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGRlZnM+CiAgICAgICAgPHBhdGggZD0iTTQyLjY3MDM3MjIsMS42Njk5NTcyOCBMNzcuNjM1MzAyNiwzMy4wMjE4OTQ1IEM3OS4yODAwNjQ4LDM0LjQ5NjcwMDMgNzkuNDE3ODQxNywzNy4wMjU2MDk5IDc3Ljk0MzAzNTksMzguNjcwMzcyMiBDNzcuODQ2MTE4NSwzOC43Nzg0NTgzIDc3Ljc0MzM4ODcsMzguODgxMTg4MSA3Ny42MzUzMDI2LDM4Ljk3ODEwNTUgTDQyLjY3MDM3MjIsNzAuMzMwMDQyNyBDNDEuMTUwODI4OSw3MS42OTI1Njg3IDM4Ljg0OTE3MTEsNzEuNjkyNTY4NyAzNy4zMjk2Mjc4LDcwLjMzMDA0MjcgTDIuMzY0Njk3NDQsMzguOTc4MTA1NSBDMC43MTk5MzUxODMsMzcuNTAzMjk5NyAwLjU4MjE1ODI3MiwzNC45NzQzOTAxIDIuMDU2OTY0MSwzMy4zMjk2Mjc4IEMyLjE1Mzg4MTUsMzMuMjIxNTQxNyAyLjI1NjYxMTI5LDMzLjExODgxMTkgMi4zNjQ2OTc0NCwzMy4wMjE4OTQ1IEwzNy4zMjk2Mjc4LDEuNjY5OTU3MjggQzM4Ljg0OTE3MTEsMC4zMDc0MzEzMDMgNDEuMTUwODI4OSwwLjMwNzQzMTMwMyA0Mi42NzAzNzIyLDEuNjY5OTU3MjggWiIgaWQ9InBhdGgtMSI+PC9wYXRoPgogICAgICAgIDxmaWx0ZXIgeD0iLTguOCUiIHk9Ii02LjklIiB3aWR0aD0iMTE3LjUlIiBoZWlnaHQ9IjExOS40JSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94IiBpZD0iZmlsdGVyLTIiPgogICAgICAgICAgICA8ZmVPZmZzZXQgZHg9IjAiIGR5PSIyIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIj48L2ZlT2Zmc2V0PgogICAgICAgICAgICA8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSIyIiBpbj0ic2hhZG93T2Zmc2V0T3V0ZXIxIiByZXN1bHQ9InNoYWRvd0JsdXJPdXRlcjEiPjwvZmVHYXVzc2lhbkJsdXI+CiAgICAgICAgICAgIDxmZUNvbXBvc2l0ZSBpbj0ic2hhZG93Qmx1ck91dGVyMSIgaW4yPSJTb3VyY2VBbHBoYSIgb3BlcmF0b3I9Im91dCIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIj48L2ZlQ29tcG9zaXRlPgogICAgICAgICAgICA8ZmVDb2xvck1hdHJpeCB2YWx1ZXM9IjAgMCAwIDAgMCAgIDAgMCAwIDAgMCAgIDAgMCAwIDAgMCAgMCAwIDAgMC4wNCAwIiB0eXBlPSJtYXRyaXgiIGluPSJzaGFkb3dCbHVyT3V0ZXIxIj48L2ZlQ29sb3JNYXRyaXg+CiAgICAgICAgPC9maWx0ZXI+CiAgICA8L2RlZnM+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0i5Z+656GA5rWB56iL5Zu+LTAxIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNy4wMDAwMDAsIC0xODQuMDAwMDAwKSI+CiAgICAgICAgICAgIDxnIGlkPSJHcm91cC0zIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMC4wMDAwMDAsIDE4NS4wMDAwMDApIj4KICAgICAgICAgICAgICAgIDxnIGlkPSJQb2x5Z29uIj4KICAgICAgICAgICAgICAgICAgICA8dXNlIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjEiIGZpbHRlcj0idXJsKCNmaWx0ZXItMikiIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICAgICAgICAgIDx1c2UgZmlsbC1vcGFjaXR5PSIwLjkyIiBmaWxsPSIjRTZGRkZCIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIHN0cm9rZT0iIzVDREJEMyIgc3Ryb2tlLXdpZHRoPSIxIiBkPSJNNDIuMzM2NTc1NywyLjA0MjIyMDQ3IEM0MS4wMDY5NzUzLDAuODUwMDEwMjM5IDM4Ljk5MzAyNDcsMC44NTAwMTAyMzkgMzcuNjYzNDI0MywyLjA0MjIyMDQ3IEwyLjY5ODQ5Mzk2LDMzLjM5NDE1NzcgQzIuNjAzOTE4NTgsMzMuNDc4OTYwNCAyLjUxNDAzMDAyLDMzLjU2ODg0OSAyLjQyOTIyNzI5LDMzLjY2MzQyNDMgQzEuMTM4NzcyMTksMzUuMTAyNTkxMyAxLjI1OTMyNjk5LDM3LjMxNTM4NzIgMi42OTg0OTM5NiwzOC42MDU4NDIzIEwzNy42NjM0MjQzLDY5Ljk1Nzc3OTUgQzM4Ljk5MzAyNDcsNzEuMTQ5OTg5OCA0MS4wMDY5NzUzLDcxLjE0OTk4OTggNDIuMzM2NTc1Nyw2OS45NTc3Nzk1IEw3Ny4zMDE1MDYsMzguNjA1ODQyMyBDNzcuMzk2MDgxNCwzOC41MjEwMzk2IDc3LjQ4NTk3LDM4LjQzMTE1MSA3Ny41NzA3NzI3LDM4LjMzNjU3NTcgQzc4Ljg2MTIyNzgsMzYuODk3NDA4NyA3OC43NDA2NzMsMzQuNjg0NjEyOCA3Ny4zMDE1MDYsMzMuMzk0MTU3NyBMNDIuMzM2NTc1NywyLjA0MjIyMDQ3IFoiPjwvcGF0aD4KICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgICAgIDx0ZXh0IGlkPSLlpITnkIboioLngrkiIGZvbnQtZmFtaWx5PSJQaW5nRmFuZ1NDLVJlZ3VsYXIsIFBpbmdGYW5nIFNDIiBmb250LXNpemU9IjEyIiBmb250LXdlaWdodD0ibm9ybWFsIiBsaW5lLXNwYWNpbmc9IjEyIiBmaWxsPSIjMDAwMDAwIiBmaWxsLW9wYWNpdHk9IjAuNjUiPgogICAgICAgICAgICAgICAgICAgIDx0c3BhbiB4PSIxNiIgeT0iNDIiPuWkhOeQhuiKgueCuTwvdHNwYW4+CiAgICAgICAgICAgICAgICA8L3RleHQ+CiAgICAgICAgICAgIDwvZz4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg=="
data-type="node"
data-shape="polygon"
data-size="80*72"
data-color="#13C2C2"
data-label="处理节点"
@mousedown="addNodeToGraph">
<img
draggable="false"
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iODhweCIgaGVpZ2h0PSI1NnB4IiB2aWV3Qm94PSIwIDAgODggNTYiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDQ5LjEgKDUxMTQ3KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Hcm91cCA0PC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGRlZnM+CiAgICAgICAgPHJlY3QgaWQ9InBhdGgtMSIgeD0iMCIgeT0iMCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjQ4IiByeD0iMjQiPjwvcmVjdD4KICAgICAgICA8ZmlsdGVyIHg9Ii04LjglIiB5PSItMTAuNCUiIHdpZHRoPSIxMTcuNSUiIGhlaWdodD0iMTI5LjIlIiBmaWx0ZXJVbml0cz0ib2JqZWN0Qm91bmRpbmdCb3giIGlkPSJmaWx0ZXItMiI+CiAgICAgICAgICAgIDxmZU9mZnNldCBkeD0iMCIgZHk9IjIiIGluPSJTb3VyY2VBbHBoYSIgcmVzdWx0PSJzaGFkb3dPZmZzZXRPdXRlcjEiPjwvZmVPZmZzZXQ+CiAgICAgICAgICAgIDxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIiIGluPSJzaGFkb3dPZmZzZXRPdXRlcjEiIHJlc3VsdD0ic2hhZG93Qmx1ck91dGVyMSI+PC9mZUdhdXNzaWFuQmx1cj4KICAgICAgICAgICAgPGZlQ29tcG9zaXRlIGluPSJzaGFkb3dCbHVyT3V0ZXIxIiBpbjI9IlNvdXJjZUFscGhhIiBvcGVyYXRvcj0ib3V0IiByZXN1bHQ9InNoYWRvd0JsdXJPdXRlcjEiPjwvZmVDb21wb3NpdGU+CiAgICAgICAgICAgIDxmZUNvbG9yTWF0cml4IHZhbHVlcz0iMCAwIDAgMCAwICAgMCAwIDAgMCAwICAgMCAwIDAgMCAwICAwIDAgMCAwLjA0IDAiIHR5cGU9Im1hdHJpeCIgaW49InNoYWRvd0JsdXJPdXRlcjEiPjwvZmVDb2xvck1hdHJpeD4KICAgICAgICA8L2ZpbHRlcj4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSLln7rnoYDmtYHnqIvlm74tMDEiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xMDIuMDAwMDAwLCAtMTk1LjAwMDAwMCkiPgogICAgICAgICAgICA8ZyBpZD0iR3JvdXAtNCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTA2LjAwMDAwMCwgMTk3LjAwMDAwMCkiPgogICAgICAgICAgICAgICAgPGcgaWQ9IlJlY3RhbmdsZS0xNS1Db3B5LTM1Ij4KICAgICAgICAgICAgICAgICAgICA8dXNlIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjEiIGZpbHRlcj0idXJsKCNmaWx0ZXItMikiIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICAgICAgICAgIDx1c2UgZmlsbC1vcGFjaXR5PSIwLjkyIiBmaWxsPSIjRjlGMEZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICAgICAgICAgIDxyZWN0IHN0cm9rZT0iI0IzN0ZFQiIgc3Ryb2tlLXdpZHRoPSIxIiB4PSIwLjUiIHk9IjAuNSIgd2lkdGg9Ijc5IiBoZWlnaHQ9IjQ3IiByeD0iMjMuNSI+PC9yZWN0PgogICAgICAgICAgICAgICAgPC9nPgogICAgICAgICAgICAgICAgPHRleHQgaWQ9Iue7k+adn+iKgueCuSIgZm9udC1mYW1pbHk9IlBpbmdGYW5nU0MtUmVndWxhciwgUGluZ0ZhbmcgU0MiIGZvbnQtc2l6ZT0iMTIiIGZvbnQtd2VpZ2h0PSJub3JtYWwiIGxpbmUtc3BhY2luZz0iMTIiIGZpbGw9IiMwMDAwMDAiIGZpbGwtb3BhY2l0eT0iMC42NSI+CiAgICAgICAgICAgICAgICAgICAgPHRzcGFuIHg9IjE2IiB5PSIyOSI+57uT5p2f6IqC54K5PC90c3Bhbj4KICAgICAgICAgICAgICAgIDwvdGV4dD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+"
data-type="node"
data-shape="ellipse"
data-size="80*48"
data-color="#722ED1"
data-label="结束节点"
@mousedown="addNodeToGraph">
</div>
</el-aside>
<el-main>
<div class="process-canvas" ref="processCanvas"></div>
</el-main>
<!-- 右侧配置区域 -->
<el-aside>
<el-tabs v-model="activeTab" type="card">
<el-tab-pane label="流程信息" name="processInfo">
<el-form :model="workflow" :rules="rules" ref="workflow" label-width="80px" style="margin-right: 8px">
<el-form-item label="名称" prop="name">
<el-input v-model="workflow.name" size="mini"></el-input>
</el-form-item>
<el-form-item label="分类" prop="projectId">
<el-select
clearable
filterable
placeholder="请选择分类"
size="mini"
style="width: 100%"
v-model="workflow.projectId"
>
<el-option
:key="index"
:label="option.name"
:value="option.id"
v-for="(option, index) in projectListTmp"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="模版" prop="tpl">
<el-select
size="mini"
v-model="workflow.tpl"
multiple
filterable
clearable
placeholder="请选择"
style="width: 100%">
<el-option
v-for="item in templateList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input type="textarea" v-model="workflow.description" size="mini"></el-input>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="配置信息" name="cellInfo">
<el-form :model="node" :rules="rules" ref="node" label-width="80px" v-if="selectCell && selectCell.shape !== 'edge'">
<el-form-item label="名称" prop="name">
<el-input v-model="node.name" size="mini" @input="updateNodeName" placeholder="请输入节点名称"></el-input>
</el-form-item>
<el-form-item label="是否隐藏" prop="isHidden" style="margin-top: -20px">
<el-select v-model="node.isHidden" placeholder="请选择是否隐藏" size="mini" style="width: 100%" filterable>
<el-option label="是" :value="true"></el-option>
<el-option label="否" :value="false"></el-option>
</el-select>
</el-form-item>
<el-form-item label="顺序" prop="orderId" style="margin-top: -20px">
<el-input v-model.number="node.orderId" size="mini" placeholder="请输入顺序值"></el-input>
</el-form-item>
<el-form-item label="人员类型" prop="participantTypeId" style="margin-top: -20px;">
<el-select filterable v-model.number="node.participantTypeId" placeholder="请选择处理人类型" @change="getParticipantList" size="mini" style="width: 100%">
<el-option
v-for="item in participantTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="处理人" prop="participant" style="margin-top: -20px;" v-if="node.participantTypeId!==0">
<el-select filterable v-model="node.participant" placeholder="请选择处理人" size="mini" style="width: 100%">
<el-option
v-for="item in participantOptions"
:key="item.id"
:label="item.name===undefined?item.nickname:item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="分配方式" prop="distributeTypeId" style="margin-top: -20px;">
<el-select filterable v-model.number="node.distributeTypeId" placeholder="请选择分配方式" size="mini" style="width: 100%">
<el-option
v-for="item in distributeTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="可写模版" style="margin-top: -20px;">
<el-select
filterable
multiple
v-model="node.writableTemplate"
placeholder="请选择可写模版"
size="mini"
style="width: 100%"
@change="uniqueTemplate($event, 'writable')"
>
<el-option
v-for="item in currentTemplateList"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="隐藏模版" style="margin-top: -20px;">
<el-select
filterable
multiple
v-model="node.hideTemplate"
placeholder="请选择需要隐藏的模版"
size="mini"
style="width: 100%"
@change="uniqueTemplate($event, 'hidden')"
>
<el-option
v-for="item in currentTemplateList"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="状态属性" prop="attributeTypeId" style="margin-top: -20px;">
<el-select filterable v-model.number="node.attributeTypeId" placeholder="请选择状态属性" size="mini" style="width: 100%">
<el-option
v-for="item in attributeTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="抄送" style="margin-top: -20px;">
<el-select filterable multiple clearable v-model.number="node.ccEmail" placeholder="请选择抄送人" size="mini" style="width: 100%">
<el-option
v-for="item in participantOptions"
:key="item.id"
:label="item.name===undefined?item.nickname:item.name"
:value="item.email">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="标签" style="margin-top: -20px;">
<el-select multiple clearable filterable v-model="node.label" placeholder="请选择标签" size="mini" style="width: 100%">
<el-option
v-for="item in labelOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
<el-form :model="edge" :rules="rules" ref="edge" label-width="80px" v-if="selectCell && selectCell.shape === 'edge'">
<el-form-item label="名称" prop="name">
<el-input v-model="edge.name" size="mini" @input="updateEdgeName" placeholder="请输入流转名称"></el-input>
</el-form-item>
<el-form-item label="源节点" prop="sourceStatus" style="margin-top: -20px" v-show="false">
<el-input v-model.number="edge.sourceStatus" size="mini" placeholder="请输入源节点" readonly></el-input>
</el-form-item>
<el-form-item label="目标节点" prop="destinationStatus" style="margin-top: -20px;" v-show="false">
<el-input v-model.number="edge.destinationStatus" size="mini" placeholder="请输入目标节点" readonly></el-input>
</el-form-item>
<el-form-item label="流转属性" prop="attributeTypeId" style="margin-top: -20px;">
<el-select v-model.number="edge.attributeTypeId" placeholder="请选择流转属性" size="mini" style="width: 100%">
<el-option
v-for="item in tranAttributeTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="标签" style="margin-top: -20px;">
<el-select multiple clearable filterable v-model="edge.label" placeholder="请选择标签" size="mini" style="width: 100%">
<el-option
v-for="item in edgeLabelOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
</el-tab-pane>
</el-tabs>
</el-aside>
</el-container>
</el-container>
</div>
</template>
<script>
// import {
// loadProjectList, loadTemplateList, loadUserList, loadDepartList,
// } from '@/api/processCenter';
import { deepCopy } from '../utils/utils';
import { Graph, Addon } from '@antv/x6';
const { Dnd } = Addon;
export default {
name: 'ProcessEdit',
props: {
data: {
type: Object,
default: () => ({
name: '',
projectId: null,
description: '',
icon: 'el-icon-user',
iconColor: 'blue',
tpl: [],
flowchart: {
nodes: [],
edges: [],
workflow: {},
},
}),
},
},
computed: {
// workflow: {
// get () {
// return this.data;
// },
// set (val) {
// this.$emit('update:data', val);
// }
// },
currentTemplateList () {
return this.templateList.filter((tpl) => {
if (!this.workflow.tpl || !Array.isArray(this.workflow.tpl) || this.workflow.tpl.length === 0) {
return false;
}
return this.workflow.tpl.indexOf(tpl.id) >= 0;
});
},
},
watch: {
data: {
handler (val) {
if (this.internalChange) {
return;
}
// nodeConfigs: {},
// edgeConfigs: {},
this.workflow = {
name: val.name,
projectId: val.projectId,
description: val.description,
icon: val.icon,
iconColor: val.iconColor,
tpl: deepCopy(val.tpl),
nodeConfigs: {},
edgeConfigs: {},
}
const cells = [];
if (val.flowchart.nodes.length > 0) {
val.flowchart.nodes.forEach((node) => {
const temp = deepCopy(node);
this.workflow.nodeConfigs[node.id] = temp.valueData;
delete temp.valueData;
cells.push(temp);
});
}
if (val.flowchart.edges.length > 0) {
val.flowchart.edges.forEach((edge) => {
const temp = deepCopy(edge);
this.workflow.edgeConfigs[edge.id] = temp.valueData;
delete temp.valueData;
cells.push(temp);
});
}
if (this.graph) {
this.graph.fromJSON({ cells });
this.graph.centerContent();
} else {
this.cells = cells;
}
},
deep: true,
immediate: true,
},
},
data: () => ({
cells: [],
workflow: {},
internalChange: false,
graph: null,
dnd: null,
selectCell: null,
activeTab: 'processInfo',
projectListTmp: [],
templateList: [],
node: {},
edge: {},
rules: {
name: [
{ required: true, message: ' ', trigger: 'change' }
],
tpl: [
{ required: true, message: ' ', trigger: 'change' }
],
icon: [
{ required: true, message: ' ', trigger: 'change' }
],
orderId: [
{ required: true, message: ' ', trigger: 'change' }
],
participant: [
{ required: true, message: ' ', trigger: 'change' }
],
participantTypeId: [
{ required: true, message: ' ', trigger: 'change' }
],
distributeTypeId: [
{ required: true, message: ' ', trigger: 'change' }
],
attributeTypeId: [
{ required: true, message: ' ', trigger: 'change' }
],
sourceStatus: [
{ required: true, message: ' ', trigger: 'change' }
],
projectId: [
{ required: true, message: '请选择项目', trigger: 'change' }
],
destinationStatus: [
{ required: true, message: ' ', trigger: 'change' }
]
},
participantTypeOptions: [
{ label: '无处理人', value: 0 },
{ label: '个人', value: 1 },
{ label: '业务组', value: 2 },
// { label: '部门', value: 3 },
{ label: '变量', value: 4 },
],
distributeTypeOptions: [
// { label: '主动接单', value: 1 },
{ label: '直接处理', value: 2 }
// { label: '随机分配', value: 3 },
// { label: '全部处理', value: 4 }
],
attributeTypeOptions: [
{ label: '新建', value: 1 },
{ label: '审批', value: 2 },
{ label: '处理', value: 3 },
{ label: '结束', value: 4 },
{ label: '其他', value: 5 }
],
labelOptions: [
{ label: '抄送HRBP', value: 'ccHrbp' },
{ label: '指定交接人', value: 'handover' },
{ label: '分管负责人', value: 'chargeLeader' }
],
edgeLabelOptions: [
{ label: 'leader申请', value: 'leaderApply' },
{ label: '指定分管领导', value: 'plusSign' }
],
tranAttributeTypeOptions: [
{ label: '同意', value: 1 },
{ label: '拒绝', value: 2 },
{ label: '其他', value: 3 }
],
participantOptions: [],
participantMap: {},
clickCellMap: {},
loadUserPromise: [],
}),
created () {
this.loadProject();
this.loadTemplate();
// this.loadUserListPartial();
},
methods: {
uniqueTemplate (select, type) {
// debugger;
let uniqueList = [];
if (type === 'writable') {
uniqueList = this.node.hideTemplate;
} else {
uniqueList = this.node.writableTemplate;
}
select.forEach(v => {
const index = uniqueList.findIndex(value => value === v);
if (index >= 0) {
uniqueList.splice(index, 1);
}
});
// this.node.name = this.node.hideTemplate.length;
this.$forceUpdate();
},
async loadUserListPartialFunc () {
const params = {
page: 1,
perPage: 100,
sort: 1,
}
// const loadAction = async (params, res) => {
// return await loadUserList(params).then(response => {
// res.push(...response.data);
// return response.data.length === params.perPage;
// }, () => false);
// }
const res = [];
let flag = await loadAction(params, res);
while (flag) {
params.page = params.page + 1;
flag = await loadAction(params, res);
}
this.participantMap.user = res;
while (this.loadUserPromise.length > 0) {
const callback = this.loadUserPromise.shift();
callback[0]();
}
},
loadUserListPartial () {
if (this.loadUserPromise.length === 0) {
this.loadUserListPartialFunc();
}
return new Promise((resolve, reject) => {
this.loadUserPromise.push([resolve, reject]);
});
},
getParticipantList (init = false) {
// this.node.participant = '';
this.participantOptions = [];
const params = {
page: 1,
perPage: 99999,
sort: 1,
}
if (this.node.participantTypeId === 1) {
if (!init || this.node.participant === 0) this.node.participant = '';
this.participantOptions = this.participantMap.user;
if (!this.participantMap.user) {
this.loadUserListPartial().then(() => {
this.participantOptions = this.participantMap.user;
});
// loadUserList(params).then(res => {
// this.participantMap.user = res.data;
// this.participantOptions = res.data;
// }, err => {
// console.error(err);
// this.$message({
// type: 'error',
// message: err.errmsg,
// });
// });
} else {
this.participantOptions = this.participantMap.user;
}
} else if (this.node.participantTypeId === 2) {
if (!this.participantMap.depart) {
// loadDepartList(params).then(res => {
// this.participantMap.depart = res.data;
// this.participantOptions = res.data;
// }, err => {
// console.error(err);
// this.$message({
// type: 'error',
// message: err.errmsg,
// });
// });
} else {
this.participantOptions = this.participantMap.depart;
}
} else if (this.node.participantTypeId === 4) {
// 处理变量
this.participantOptions = [
{ id: 1, name: '创建者' },
{ id: 2, name: '创建者Leader' },
{ id: 3, name: '汇报对象' },
{ id: 4, name: '分管负责人' },
{ id: 5, name: 'HRBP' },
{ id: 6, name: 'VP' }
]
if (!init) this.node.participant = 1;
} else if (this.node.participantTypeId === 0) {
this.node.participant = 0;
}
},
loadTemplate () {
const params = {
page: 1,
perPage: 99999,
sort: 1,
}
// loadTemplateList(params).then((res) => {
// this.templateList = res.data;
// }, (err) => {
// this.$message({
// type: 'error',
// message: err.errmsg,
// });
// console.error(err);
// });
},
loadProject () {
const params = {
page: 1,
perPage: 99999,
sort: 1,
}
// loadProjectList(params).then((res) => {
// this.projectListTmp = res.data;
// }, (err) => {
// this.$message({
// type: 'error',
// message: err.errmsg,
// });
// console.error(err);
// });
},
handleCellClick (cell) {
this.activeTab = 'cellInfo';
this.selectCell = cell;
const id = cell.id;
if (cell.isNode()) {
if (!this.workflow.nodeConfigs[id]) {
let attributeTypeId = 1;
if (cell.shape === 'rect') {
attributeTypeId = 2;
} else if (cell.shape === 'polygon') {
attributeTypeId = 3;
} else if (cell.shape === 'ellipse') {
attributeTypeId = 4;
}
// { label: '新建', value: 1 },
// { label: '审批', value: 2 },
// { label: '处理', value: 3 },
// { label: '结束', value: 4 },
// { label: '其他', value: 5 }
this.workflow.nodeConfigs[id] = {
tmpId: id,
name: cell.attrs.label.text,
isHidden: false,
orderId: null,
participantTypeId: 0,
participant: '',
distributeTypeId: 2,
attributeTypeId,
writableTemplate: [],
hideTemplate: [],
label: [],
ccEmail: [],
};
}
this.node = this.workflow.nodeConfigs[id];
} else {
if (!this.workflow.edgeConfigs[id]) {
this.workflow.edgeConfigs[id] = {
tmpId: id,
label: [],
name: '',
sourceStatus: cell.source.cell,
destinationStatus: cell.target.cell,
attributeTypeId: '',
};
}
this.edge = this.workflow.edgeConfigs[id];
}
this.getParticipantList(true);
},
updateEdgeName (name) {
this.selectCell.setLabels(name);
},
updateNodeName (name) {
this.selectCell.setAttrs({
label: {
text: name,
},
});
},
addNodeToGraph (event) {
const target = event.currentTarget;
const type = target.getAttribute('data-type');
let node = null;
if (type === 'node') {
const shape = target.getAttribute('data-shape');
const size = target.getAttribute('data-size');
const width = Number(size.split('*')[0]);
const height = Number(size.split('*')[1]);
// data-color="#1890FF"
const label = target.getAttribute('data-label');
const color = target.getAttribute('data-color');
const rgbToHex = (r, g, b) => {
const hex = ((r << 16) | (g << 8) | b).toString(16);
return '#' + new Array(Math.abs(hex.length - 7)).join('0') + hex;
}
// hex to rgb
const hexToRgb = (hex) => {
const rgb = [];
for (let i = 1; i < 7; i += 2) {
rgb.push(parseInt('0x' + hex.slice(i, i + 2)));
}
return rgb;
}
// 计算渐变过渡色
const gradient = (startColor, endColor, step) => {
// 将 hex 转换为rgb
const sColor = hexToRgb(startColor);
const eColor = hexToRgb(endColor);
// 计算R\G\B每一步的差值
const rStep = (eColor[0] - sColor[0]) / step;
const gStep = (eColor[1] - sColor[1]) / step;
const bStep = (eColor[2] - sColor[2]) / step;
const gradientColorArr = [];
for (let i = 0; i < step; i++) {
// 计算每一步的hex值
gradientColorArr.push(rgbToHex(parseInt(rStep * i + sColor[0]), parseInt(gStep * i + sColor[1]), parseInt(bStep * i + sColor[2])));
}
return gradientColorArr;
}
const colorList = gradient(color, '#ffffff', 10);
const halfColor = colorList[9];
const fillColor = colorList[6];
const ports = {
groups: {
top: {
position: 'top',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff',
}
}
},
bottom: {
position: 'bottom',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff',
}
}
},
left: {
position: 'left',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff',
}
}
},
right: {
position: 'right',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#31d0c6',
strokeWidth: 2,
fill: '#fff',
}
}
}
},
items: [
{
id: 'top',
group: 'top',
},
{
id: 'bottom',
group: 'bottom',
},
{
id: 'left',
group: 'left',
},
{
id: 'right',
group: 'right',
}
],
}
const nodeInfo = {
shape,
width,
height,
attrs: {
label: {
'font-size': 12,
text: label,
fill: 'black',
},
body: {
stroke: fillColor,
fill: halfColor,
strokeWidth: 2,
},
},
ports,
};
if (shape === 'polygon') {
nodeInfo.points = '0,10 10,0 20,10 10,20';
}
node = this.graph.createNode(nodeInfo);
} else {
node = {};
}
this.dnd.start(node, event);
},
initG6 () {
const that = this;
this.graph = new Graph({
container: that.$refs.processCanvas,
autoResize: true,
connecting: {
snap: true, // 自动吸附连接线
allowBlank: false, // 不允许只有一个节点的线
// allowMulti: false, // 不允许在两个节点间创建多个线
highlight: true, // 高亮可被连接的点
},
grid: true,
history: true,
snapline: {
enabled: true, // 对齐线
sharp: true,
},
scroller: {
enabled: true,
pageVisible: false,
pageBreak: false,
pannable: true,
},
// mousewheel: {
// enabled: true,
// modifiers: ['ctrl', 'meta'],
// },
});
// this.graph.fromJSON(data);
this.dnd = new Dnd({
target: this.graph,
scaled: false,
animation: true,
});
this.graph.on('edge:connected', ({ isNew, edge }) => {
if (isNew) {
that.handleCellClick(edge);
}
});
this.graph.on('cell:mouseenter', ({ cell }) => {
if (this.clickCellMap[cell.id]) {
clearTimeout(this.clickCellMap[cell.id]);
delete this.clickCellMap[cell.id];
}
if (cell.isNode()) {
let offset = { x: 10, y: 10 };
if (cell.shape === 'polygon') {
offset = { x: 20, y: 20 };
}
cell.addTools([
{
name: 'boundary',
args: {
attrs: {
fill: '#7c68fc',
stroke: '#333',
'stroke-width': 1,
'fill-opacity': 0.2,
},
},
},
{
name: 'button-remove',
args: {
x: 0,
y: 0,
offset,
},
},
])
} else {
cell.addTools(['button-remove']);
}
});
this.graph.on('cell:mouseleave', ({ cell }) => {
cell.removeTools();
});
this.graph.on('cell:click', ({ cell }) => {
that.handleCellClick(cell);
});
this.graph.on('node:added', ({ cell }) => {
that.handleCellClick(cell);
});
if (this.cells.length > 0) {
this.graph.fromJSON({ cells: this.cells });
this.$nextTick(() => {
this.graph.centerContent();
});
this.cells = [];
}
},
async saveFlow () {
let workflowValid;
await this.$refs.workflow.validate(valid => {
workflowValid = valid;
});
if (!workflowValid) {
this.activeTab = 'processInfo';
this.$message({
type: 'warning',
message: '请完成流程信息的配置',
});
return;
}
const data = this.graph.toJSON();
const { cells } = data;
const workflow = {
name: this.workflow.name,
projectId: this.workflow.projectId,
description: this.workflow.description,
icon: this.workflow.icon,
iconColor: this.workflow.iconColor,
tpl: deepCopy(this.workflow.tpl),
}
const flowchart = {};
flowchart.workflow = deepCopy(workflow);
flowchart.nodes = [];
flowchart.edges = [];
const that = this;
const checkEmpty = (v) => (v === null || v === undefined || v === '');
const checkNode = (form) => {
if (checkEmpty(form.name)) {
return false;
}
if (checkEmpty(form.orderId)) {
return false;
}
if (checkEmpty(form.participantTypeId)) {
return false;
}
if (checkEmpty(form.participant)) {
return false;
}
if (checkEmpty(form.distributeTypeId)) {
return false;
}
return !checkEmpty(form.attributeTypeId);
}
const checkEdge = (form) => {
if (checkEmpty(form.name)) {
return false;
}
return form.attributeTypeId;
}
const cellValid = cells.every((cell) => {
// 线
if (cell.shape === 'edge') {
const { id } = cell;
if (!that.workflow.edgeConfigs[id]) {
const cellObj = that.graph.getCell(id);
that.handleCellClick(cellObj);
that.$nextTick(() => {
that.$refs.edge.validate();
});
return false;
}
if (!checkEdge(that.workflow.edgeConfigs[id])) {
const cellObj = that.graph.getCell(id);
that.handleCellClick(cellObj);
that.$nextTick(() => {
that.$refs.edge.validate();
});
this.$message({
type: 'warning',
message: '请完成流转信息的配置',
});
return false;
}
const temp = deepCopy(cell);
temp.valueData = that.workflow.edgeConfigs[id];
flowchart.edges.push(temp);
return true;
} else {
const { id } = cell;
if (!that.workflow.nodeConfigs[id]) {
const cellObj = that.graph.getCell(id);
that.activeTab = 'cellInfo';
that.handleCellClick(cellObj);
that.$nextTick(() => {
that.$refs.node.validate();
});
return false;
}
if (!checkNode(that.workflow.nodeConfigs[id])) {
const cellObj = that.graph.getCell(id);
that.activeTab = 'cellInfo';
that.handleCellClick(cellObj);
that.$nextTick(() => {
that.$refs.node.validate();
});
this.$message({
type: 'warning',
message: '请完成节点信息的配置',
});
return false;
}
const temp = deepCopy(cell);
temp.valueData = that.workflow.nodeConfigs[id];
flowchart.nodes.push(temp);
return true;
}
});
// workflow.flowchart = flowchart;
if (!cellValid) {
return;
}
this.internalChange = true;
this.$emit('update', flowchart);
this.$nextTick(() => {
this.internalChange = false;
});
},
},
mounted () {
this.initG6();
},
}
</script>
<style scoped>
.process-edit-container {
margin-top: 20px;
/* height: calc(100% - 20px); */
height: 90vh;
}
.process-canvas {
width: 100%;
height: 100%;
}
.process-component-list {
height: 100%;
background-color: #e6e6e6;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-around;
align-content: flex-start;
}
</style>
上面的代码作为一个公用组件在下面这个组件中导入,根据后端返回的json可以对流程图进行编辑
<template>
<span class="staff-title" style="padding-top: 100px">{{activeTitle}}</span>
<process-edit :data="processInfo" @update="handleSave"/>
</template>
<script>
// 导入的后端服务地址,这个不需要参考
import { loadFlowById, createFlow, updateFlowById } from '@/api/processCenter';
import { deepCopy } from '@/utils/utils'; // 深拷贝(贴到下面了)
import processEdit from '@/components/processEditor/processEdit.vue'; // 上面的代码作为子组件导入
export default {
name: 'editProcess',
components: {
processEdit,
},
props: {
processId: { // 父组件传入的值
type: [Number, String],
default: -1,
},
},
data: () => ({
init: false,
realId: null,
processInfo: {
name: '',
projectId: null,
description: '',
icon: 'el-icon-user',
iconColor: 'blue',
tpl: [],
flowchart: {
nodes: [],
edges: [],
workflow: {},
},
},
// rDong修改
activeTitle: ''
}),
created () {
// 父组件传入processId后传入后端地址请求数据
if (Number(this.processId) !== -1) {
this.init = true;
this.activeTitle = '编辑流程';
this.realId = this.processId;
loadFlowById(this.processId).then(res => {
this.processInfo = res;
this.$nextTick(() => {
this.init = false;
});
}, (err) => {
this.$message({
type: 'error',
message: err.errmsg,
});
console.error(err);
});
} else {
this.activeTitle = '新建流程';
}
},
watch: {
// 将后端返回的数据进行处理转变为子组件可以接收展示的数据,并传给子组件展示并可编辑
// 这边不用参考, 可以将之前子组件传过来的值直接保存到后端,到时候请求将后端保存的值在进行返回展示编辑,这样可以不进行数据格式的处理。
processInfo: {
handler (val) {
if (this.init) {
return;
}
// let func = createFlow;
// if (this.realId) {
// func = (data) => updateFlowById(this.realId, data);
// }
const data = deepCopy(val);
const statusList = [];
const transformList = [];
const statusIDList = [];
const transformIDList = [];
for (const arrayValue of data.nodes) {
if (statusIDList.indexOf(arrayValue.valueData.id) === -1) {
statusIDList.push(arrayValue.valueData.id);
} else {
delete arrayValue.valueData.id;
}
arrayValue.valueData.tmpId = arrayValue.id;
statusList.push(arrayValue.valueData);
arrayValue.label = arrayValue.valueData.name;
}
for (const transformValue of data.edges) {
if (transformIDList.indexOf(transformValue.valueData.id) === -1) {
transformIDList.push(transformValue.valueData.id);
} else {
delete transformValue.valueData.id;
}
transformValue.valueData.tmpId = transformValue.id;
transformList.push(transformValue.valueData);
}
const workflowValue = Object.assign({}, data.workflow);
workflowValue.flowchart = data;
const jsonData = {
workflow: workflowValue,
status: statusList,
transform: transformList,
}
if (this.realId === null) {
createFlow(jsonData).then((res) => {
this.realId = res;
this.$router.replace({ name: 'WorkProcess' });
this.$message({
type: 'success',
message: '保存流程成功',
});
}, err => {
this.$message({
type: 'error',
message: err.errmsg,
});
console.error(err);
});
} else {
jsonData.workflow.id = Number(this.realId);
updateFlowById(Number(this.realId), jsonData).then(() => {
this.$router.replace({ name: 'WorkProcess' });
this.$message({
type: 'success',
message: '保存流程成功',
});
}, err => {
this.$message({
type: 'error',
message: err.errmsg,
});
console.error(err);
});
}
}
},
},
methods: {
// 子组件发过来的值($emit) 将发过来的值进行处理改变为后端需要的数据格式然后发给后端
// 看业务需求。可以不进行处理直接发给后端,后端只是保存数据的作用,编辑的时候再请求过来直接传给子组件赋值就可以
handleSave (val) {
const data = deepCopy(val);
const statusList = [];
const transformList = [];
const statusIDList = [];
const transformIDList = [];
for (const arrayValue of data.nodes) {
if (statusIDList.indexOf(arrayValue.valueData.id) === -1) {
statusIDList.push(arrayValue.valueData.id);
} else {
delete arrayValue.valueData.id;
}
arrayValue.valueData.tmpId = arrayValue.id;
statusList.push(arrayValue.valueData);
arrayValue.label = arrayValue.valueData.name;
}
for (const transformValue of data.edges) {
if (transformIDList.indexOf(transformValue.valueData.id) === -1) {
transformIDList.push(transformValue.valueData.id);
} else {
delete transformValue.valueData.id;
}
transformValue.valueData.tmpId = transformValue.id;
transformList.push(transformValue.valueData);
}
const workflowValue = Object.assign({}, data.workflow);
workflowValue.flowchart = data;
const jsonData = {
workflow: workflowValue,
status: statusList,
transform: transformList,
}
if (this.realId === null) {
createFlow(jsonData).then((res) => {
this.realId = res;
this.$router.replace({ name: 'WorkProcess' });
this.$message({
type: 'success',
message: '保存流程成功',
});
}, err => {
this.$message({
type: 'error',
message: err.errmsg,
});
console.error(err);
});
} else {
jsonData.workflow.id = Number(this.realId);
updateFlowById(Number(this.realId), jsonData).then(() => {
this.$router.replace({ name: 'WorkProcess' });
this.$message({
type: 'success',
message: '保存流程成功',
});
}, err => {
this.$message({
type: 'error',
message: err.errmsg,
});
console.error(err);
});
}
}
},
}
</script>
<style lang="less" scoped>
.staff-title {
display: block;
width: 100%;
height: 40px;
padding: 20px 0 0 30px;
font-size: 16px;
margin-top: 20px;
border-bottom: 1px solid #ccc;
margin-bottom: 30px;
background-color: skyblue;
}
</style>
深拷贝也贴上来吧
// 深拷贝
export function deepCopy(obj, cache = []) {
// just return if obj is immutable value
if (obj === null || typeof obj !== 'object') {
return obj
}
// if obj is hit, it is in circular structure
const hit = find(cache, (c) => c.original === obj)
if (hit) {
return hit.copy
}
const copy = Array.isArray(obj) ? [] : {}
// put the copy into cache at first
// because we want to refer it in recursive deepCopy
cache.push({
original: obj,
copy
})
Object.keys(obj).forEach((key) => {
copy[key] = deepCopy(obj[key], cache)
})
return copy
}
更多推荐
已为社区贡献2条内容
所有评论(0)