林倩 пре 3 година
родитељ
комит
2927f62046

+ 43 - 59
src/pages/permission-selfhelp-manage/component/flow-chart/index.vue

@@ -368,11 +368,8 @@ export default {
         { name: 'pictureTemplate' },
         { name: 'pictureTemplate' },
         $(
         $(
           go.Shape,
           go.Shape,
-          'DataStorage',
-          {
-            margin: new go.Margin(0, 0, 0, 18),
-            desiredSize: new go.Size(220, 36)
-          },
+          'RoundedRectangle',
+          this.nodeText(),
           new go.Binding('stroke', function (e) {
           new go.Binding('stroke', function (e) {
             const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
             const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
             return textColor[status];
             return textColor[status];
@@ -381,35 +378,6 @@ export default {
             const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
             const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
             return bgColor[status];
             return bgColor[status];
           })
           })
-        ),
-        $(
-          go.Shape,
-          'Circle',
-          { desiredSize: new go.Size(36, 36) },
-          new go.Binding('stroke', function (e) {
-            const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
-            return textColor[status];
-          }),
-          new go.Binding('fill', function (e) {
-            const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
-            return bgColor[status];
-          })
-        ),
-        $(
-          go.Shape,
-          {
-            desiredSize: new go.Size(16, 16),
-            margin: new go.Margin(10, 0, 0, 10),
-            strokeWidth: 0
-          },
-          new go.Binding('fill', function (e) {
-            const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
-            return textColor[status];
-          }),
-          new go.Binding('geometry', function (e) {
-            return geoFunc('' + e.type);
-            // return geoFunc("serviceTask");
-          })
         )
         )
       );
       );
     },
     },
@@ -505,6 +473,27 @@ export default {
 
 
       console.log('详情数据', this.detailBindData);
       console.log('详情数据', this.detailBindData);
     },
     },
+    nodeStyle() {
+      return [
+        new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
+        {
+          locationSpot: go.Spot.Center
+        }
+      ];
+    },
+    nodeText(defaultSize = ['90', '50']) {
+      return [
+        new go.Binding('desiredSize', function (e) {
+          let size;
+          if (e.size) {
+            size = e.size.split(' ');
+          } else {
+            size = defaultSize;
+          }
+          return new go.Size(Number(size[0]), Number(size[1]));
+        })
+      ];
+    },
     initDiagram() {
     initDiagram() {
       const {
       const {
         getTaskStatus,
         getTaskStatus,
@@ -517,23 +506,17 @@ export default {
         getTaskPictureTemplate,
         getTaskPictureTemplate,
         getlDetail,
         getlDetail,
         closeModal,
         closeModal,
-        getSubContainerDrawData
+        getSubContainerDrawData,
+        nodeStyle,
+        nodeText
       } = this;
       } = this;
 
 
       let { myDiagram } = this;
       let { myDiagram } = this;
 
 
       myDiagram = $(go.Diagram, 'myDiagramDiv', {
       myDiagram = $(go.Diagram, 'myDiagramDiv', {
-        // 'toolManager.mouseWheelBehavior': go.ToolManager.WheelZoom,
-        initialContentAlignment: go.Spot.Center,
+        initialContentAlignment: go.Spot.Left,
         allowCopy: false,
         allowCopy: false,
-        allowDelete: false,
-        layout: $(go.TreeLayout, {
-          angle: 90, // 垂直
-          // angle: 0, // 水平
-          // layerSpacing: 80, // 节点间垂直距离
-          nodeSpacing: 120 // 横向节点的间距宽度
-        })
-        // "grid.visible": true, // 是否展示网格
+        allowDelete: false
       });
       });
 
 
       // 返回文字节点模板
       // 返回文字节点模板
@@ -542,13 +525,12 @@ export default {
           go.TextBlock,
           go.TextBlock,
           {
           {
             font: '10pt Lato, Helvetica, Arial, sans-serif',
             font: '10pt Lato, Helvetica, Arial, sans-serif',
-            overflow: go.TextBlock.OverflowEllipsis,
-            maxLines: 1,
-            maxSize: new go.Size(140, NaN),
-            margin: new go.Margin(0, 0, 0, 15),
-            wrap: go.TextBlock.WrapFit,
-            name: 'textTemplate'
+            name: 'textTemplate',
+            wrap: go.TextBlock.WrapDesiredSize,
+            verticalAlignment: go.Spot.Center,
+            textAlign: 'center'
           },
           },
+          nodeText(),
           new go.Binding('stroke', function (e) {
           new go.Binding('stroke', function (e) {
             const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
             const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
             return textColor[status];
             return textColor[status];
@@ -574,10 +556,11 @@ export default {
       const eventNodeTemplate = $(
       const eventNodeTemplate = $(
         go.Node,
         go.Node,
         'Table',
         'Table',
+        nodeStyle(),
         $(
         $(
           go.Panel,
           go.Panel,
           'Spot',
           'Spot',
-          { desiredSize: new go.Size(75, 75) },
+          { desiredSize: new go.Size(45, 45) },
           new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
           new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
           $(
           $(
             go.Shape,
             go.Shape,
@@ -593,7 +576,7 @@ export default {
             go.Shape,
             go.Shape,
             'Circle',
             'Circle',
             {
             {
-              desiredSize: new go.Size(55, 55),
+              desiredSize: new go.Size(35, 35),
               strokeWidth: 2,
               strokeWidth: 2,
               stroke: null
               stroke: null
             },
             },
@@ -608,7 +591,7 @@ export default {
           $(
           $(
             go.TextBlock,
             go.TextBlock,
             {
             {
-              font: 'bold 14pt helvetica, bold arial, sans-serif'
+              font: 'bold 9pt helvetica, bold arial, sans-serif'
             },
             },
             new go.Binding('stroke', function (e) {
             new go.Binding('stroke', function (e) {
               if (e.type == 'start') {
               if (e.type == 'start') {
@@ -623,7 +606,7 @@ export default {
       );
       );
 
 
       // 定义节点默认模板
       // 定义节点默认模板
-      const defaultNodeTemplate = $(go.Node, 'Auto', getTaskPictureTemplate(), getTextTemplate(), {
+      const defaultNodeTemplate = $(go.Node, 'Auto', nodeStyle(), getTaskPictureTemplate(), getTextTemplate(), {
         toolTip: getToolTipTemplate(),
         toolTip: getToolTipTemplate(),
         click: function (e, o) {
         click: function (e, o) {
           return getlDetail(e, o);
           return getlDetail(e, o);
@@ -640,10 +623,11 @@ export default {
       const gatewayNodeTemplate = $(
       const gatewayNodeTemplate = $(
         go.Node,
         go.Node,
         'Table',
         'Table',
+        nodeStyle(),
         $(
         $(
           go.Panel,
           go.Panel,
           'Spot',
           'Spot',
-          { desiredSize: new go.Size(55, 55) },
+          { desiredSize: new go.Size(40, 40) },
           new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
           new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
           // 最外层
           // 最外层
           $(
           $(
@@ -662,7 +646,7 @@ export default {
             go.Shape,
             go.Shape,
             'Diamond',
             'Diamond',
             {
             {
-              desiredSize: new go.Size(35, 35),
+              desiredSize: new go.Size(25, 25),
               strokeWidth: 2
               strokeWidth: 2
             },
             },
             new go.Binding('stroke', function (e) {
             new go.Binding('stroke', function (e) {
@@ -794,9 +778,9 @@ export default {
       myDiagram.linkTemplate = $(
       myDiagram.linkTemplate = $(
         go.Link, // the whole link panel
         go.Link, // the whole link panel
         {
         {
-          routing: go.Link.AvoidsNodes
+          routing: go.Link.AvoidsNodes,
           // curve: go.Link.JumpOver,
           // curve: go.Link.JumpOver,
-          // corner: 5,
+          corner: 5
         },
         },
         $(
         $(
           go.Shape, // the link path shape
           go.Shape, // the link path shape

+ 931 - 0
src/pages/permission-selfhelp-manage/component/flow-chart/index1.vue

@@ -0,0 +1,931 @@
+<!--
+流程图展示组件
+@Author: linqian
+@Date: 2020/06/22
+-->
+<template>
+  <div>
+    <div class="legend-group">
+      <div class="legend-group__item" v-for="(item, index) in chartLegend" :key="index">
+        <span class="retange" :style="{ background: item.color }"></span>
+        <span>{{ item.text }}</span>
+      </div>
+    </div>
+    <div id="myDiagramDiv" ref="myDiagramDiv" style="width: 100%; height: 600px; overflow: auto"></div>
+    <!-- 详情弹出框 -->
+    <div class="shallow-box" v-if="isShow" :style="modalStyle" ref="shallowBox">
+      <span class="close" @click="closeModal"><i class="el-icon-close"></i></span>
+      <div class="header">
+        <span class="title">{{ detailBindData.name }}</span>
+        <span id="time" class="time" v-if="detailBindData.showCountDown">{{ detailBindData.countTime }}</span>
+      </div>
+      <div class="form">
+        <div class="form-item" v-if="detailBindData.actStartTime">
+          <span class="label">转入时间</span>
+          <span class="text">{{ detailBindData.actStartTime }}</span>
+        </div>
+        <div class="form-item" v-if="detailBindData.actEndTime">
+          <span class="label">转出时间</span>
+          <span class="text">{{ detailBindData.actEndTime }}</span>
+        </div>
+        <div class="form-item" v-if="detailBindData.assigneeList.length > 0">
+          <span class="label">处理人</span>
+          <span class="text">{{ detailBindData.assigneeList.join(' ') }}</span>
+        </div>
+        <div class="form-item" v-if="detailBindData.statusStr">
+          <span class="label">状态</span>
+          <span class="text">{{ detailBindData.statusStr }}</span>
+        </div>
+        <div class="form-item" v-if="detailBindData.dueDateNum">
+          <span class="label">办理期限</span>
+          <span class="text">{{ detailBindData.dueDateNum }}H</span>
+        </div>
+        <div class="form-item" v-if="detailBindData.beforeDueLimit">
+          <span class="label">催办期限</span>
+          <span class="text">{{ detailBindData.beforeDueLimit }}H</span>
+        </div>
+        <div class="form-item" v-if="detailBindData.description">
+          <span class="label">任务描述</span>
+          <span class="text">{{ detailBindData.description }}</span>
+        </div>
+        <div class="form-item" style="color: red" v-if="detailBindData.tipMsgStr">
+          <span id="tipMsgSpan">{{ detailBindData.tipMsgStr }}</span>
+        </div>
+        <div class="form-item" v-if="detailBindData.approveMessage">
+          <span class="label">审批信息</span>
+          <span class="text">{{ detailBindData.approveMessage }}</span>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import '../../../../../static/go';
+import icons from './icon.js';
+import { processConfig, getFlowChartDetail } from '@/api/permission-selfhelp-manage';
+import moment from 'moment';
+// 颜色变量
+const lightGray = 'rgb(233,233,233)';
+const lightBlue = 'rgb(227,239,255)';
+const lightGreen = 'rgb(201,226,206)';
+const blue = 'rgb(64,144,255)';
+const green = 'rgb(52,159,29)';
+const $ = window.go.GraphObject.make;
+
+// 预定义图形
+const GeneratorEllipseSpot1 = new go.Spot(0.156, 0.156);
+const GeneratorEllipseSpot2 = new go.Spot(0.844, 0.844);
+
+go.Shape.defineFigureGenerator('CircleLine', function (shape, w, h) {
+  const rad = w / 2;
+  const geo = new go.Geometry().add(
+    new go.PathFigure(w, w / 2, false) // clockwise
+      .add(new go.PathSegment(go.PathSegment.Arc, 0, 360, rad, rad, rad, rad).close())
+  );
+  geo.spot1 = GeneratorEllipseSpot1;
+  geo.spot2 = GeneratorEllipseSpot2;
+  geo.defaultStretch = go.GraphObject.Uniform;
+  return geo;
+});
+
+go.Shape.defineFigureGenerator('DataStorage', function (shape, w, h) {
+  var geo = new go.Geometry();
+  var fig = new go.PathFigure(0, 0, true);
+  geo.add(fig);
+  fig.add(new go.PathSegment(go.PathSegment.Line, 200, 0));
+  fig.add(new go.PathSegment(go.PathSegment.Bezier, 200, h, 220, 0.05 * h, 226, 0.85 * h));
+  fig.add(new go.PathSegment(go.PathSegment.Line, 0, h));
+  fig.add(new go.PathSegment(go.PathSegment.Bezier, 0, 0, 26, 0.7 * h, 8, (0.5).h).close());
+
+  geo.spot1 = new go.Spot(0.226, 0);
+  geo.spot2 = new go.Spot(0.81, 1);
+  return geo;
+});
+
+function geoFunc(geoname) {
+  var geo = icons[geoname];
+  if (geo === undefined) geo = icons['home']; // use this for an unknown icon name
+  if (typeof geo === 'string') {
+    geo = icons[geoname] = go.Geometry.parse(geo, true); // fill each geometry
+  }
+  return geo;
+}
+
+export default {
+  components: {},
+  props: {
+    applyOrdNo: [String, Number]
+  },
+  data() {
+    return {
+      modelData: {},
+      isEmpty: false,
+      taskDetail: {},
+      isShow: false,
+      textColor: {
+        ready: 'gray',
+        complete: blue,
+        ing: 'white'
+      },
+      borderColor: {
+        ready: 'gray',
+        complete: blue,
+        ing: green
+      },
+      bgColor: {
+        ready: 'white',
+        complete: lightBlue,
+        ing: green
+      },
+      myDiagram: null,
+      modalStyle: {},
+      timer: null,
+      // 详情框绑定的数据
+      detailBindData: {},
+      chartLegend: [
+        {
+          color: 'rgb(64,144,255)',
+          text: '已经过的节点'
+        },
+        {
+          color: 'gray',
+          text: '未经过的节点'
+        },
+        {
+          color: 'rgb(52,159,29)',
+          text: '当前节点'
+        }
+      ]
+    };
+  },
+  computed: {
+    // 已生成的任务
+    taskList() {
+      return this.modelData.data;
+    },
+    // 所有节点数据
+    allNodeList() {
+      return JSON.parse(this.modelData.json).dataModel;
+    }
+  },
+  methods: {
+    // 关闭弹框
+    closeModal() {
+      this.isShow = false;
+      clearTimeout(this.timer);
+    },
+
+    getSubContainerDrawData(id) {
+      for (const key in this.allNodeList) {
+        const element = this.allNodeList[key];
+        if (key === id) {
+          return element;
+        }
+      }
+    },
+
+    // 返回当前节点(非子容器)的状态
+    // 三种状态: 未开始、进行中、 已完成
+    getTaskStatus(id) {
+      const item = this.taskList.find((el) => el.id === id);
+      if (item === undefined) {
+        return 'ready';
+      } else {
+        return item.activity === false ? 'complete' : 'ing';
+      }
+    },
+
+    getTaskColor() {},
+
+    // 返回子容器状态,根据子容器里面的节点状态判断,所有节点都完成 - 完成, 部分节点进行中 - 进行中 , 节点都没有开始 - 未开始
+    getSubContainerStatus(id) {
+      const node = this.getSubContainerDrawData(id);
+      if (!node) {
+        return 'ready';
+      }
+      const { nodeDataArray } = node.diagramModel;
+      const groupItems = nodeDataArray.filter((el) => el.category !== 'event');
+      // 交集
+      let attr = [...groupItems].filter((x) => [...this.taskList].some((y) => y.id === x.id));
+      if (groupItems.length === 0 || attr.length === 0) {
+        return 'ready';
+      } else if (attr.length < groupItems.length) {
+        return 'ing';
+      } else {
+        return 'complete';
+      }
+    },
+    // 添加子容器里面的节点数据
+    addGroupItems(data, myDiagram) {
+      myDiagram.startTransaction('addGroupContents');
+      const subKey = data.key;
+      const id = data.id;
+      const { nodeDataArray } = JSON.parse(this.modelData.json); // 主图的绘图数据
+      const node = this.getSubContainerDrawData(id);
+      // 子容器的绘图数据
+      let subNodeDataArray = node.diagramModel.nodeDataArray;
+      let subLinkDataArray = node.diagramModel.linkDataArray;
+      // const isEnd =
+      //   subNodeDataArray.find(
+      //     el => el.category === "event" && el.type === "end"
+      //   ) === undefined
+      //     ? false
+      //     : true;
+      const isEnd =
+        subNodeDataArray.find((el) => el.category === 'event' && el.text === '终止') === undefined ? false : true;
+
+      // 数据模型中需要添加子节点集合, 去除开始、结束/终止节点
+      let nodeAttr = subNodeDataArray.filter((el) => el.category !== 'event');
+
+      // 注意:  子容器里的节点key不唯一,所以给key添加一个时间戳 格式为${key}_ ${time}
+      let time = new Date().getTime();
+      nodeAttr.map((item) => {
+        item.group = subKey; // 组成员标识
+        item.key = item.key + '_' + time;
+      });
+
+      // 修改连线集合中对应的节点key
+      subLinkDataArray.map((item) => {
+        item.to = item.to + '_' + time;
+        item.from = item.from + '_' + time;
+      });
+
+      // 将节点添加到数据模型中
+      for (let i = 0; i < nodeAttr.length; i++) {
+        let nodeItem = nodeAttr[i];
+        myDiagram.model.addNodeData(nodeItem);
+      }
+
+      // 获取当前子容器节点
+      let subNode = myDiagram.findNodeForKey(subKey);
+
+      // 进入子容器线集合
+      let linkIntoAttr = [];
+
+      // 从子容器出来线集合
+      let linkOutOfAttr = [];
+
+      // 获取进入节点的线
+      subNode.findLinksInto().each((item) => {
+        linkIntoAttr.push(item.data);
+      });
+      // 获取从节点出来的线
+      subNode.findLinksOutOf().each((item) => {
+        linkOutOfAttr.push(item.data);
+      });
+
+      // 删除子组件本身的连线
+      let removeLinks = [];
+      subNode.findLinksConnected().each(function (link) {
+        removeLinks.push(link.data);
+      });
+      myDiagram.model.removeLinkDataCollection(removeLinks);
+
+      const subStartLink = subLinkDataArray.find((el) => el.sourceRef === 'pre');
+
+      for (let i = 0; i < linkIntoAttr.length; i++) {
+        let linkItem = linkIntoAttr[i];
+        linkItem.to = subStartLink.to;
+      }
+
+      // 新增流入的连线
+      subLinkDataArray = [...subLinkDataArray, ...linkIntoAttr];
+
+      const subEndLink = subLinkDataArray.find((el) => el.targetRef === 'next' || el.targetRef === 'end');
+
+      const subEndIndex = subLinkDataArray.findIndex((el) => el.targetRef === 'next' || el.targetRef === 'end');
+
+      // 判断该流程是否是终止状态,如果是,则最终指向主流程的结束, 如果不是,则最终指向子容器的下一节点
+      if (isEnd) {
+        subLinkDataArray[subEndIndex].to = nodeDataArray.filter((el) => el.type === 'end').key;
+      } else {
+        for (let i = 0; i < linkOutOfAttr.length; i++) {
+          let linkItem = linkOutOfAttr[i];
+          linkItem.from = subEndLink.from;
+        }
+        subLinkDataArray = [...subLinkDataArray, ...linkOutOfAttr];
+      }
+
+      subLinkDataArray = subLinkDataArray.filter(
+        (item) => item.sourceRef !== 'pre' && item.targetRef !== 'next' && item.targetRef !== 'end'
+      );
+
+      console.log('subNodeDataArray', subNodeDataArray);
+      console.log('subLinkDataArray', subLinkDataArray);
+
+      for (let i = 0; i < subLinkDataArray.length; i++) {
+        const linkItem = subLinkDataArray[i];
+        myDiagram.model.addLinkData(linkItem);
+      }
+
+      myDiagram.commitTransaction('addGroupContents');
+
+      // 当前画布中的绘图数据
+      const aa = JSON.parse(myDiagram.model.toJson());
+      console.log(aa.nodeDataArray.length, aa.linkDataArray.length);
+    },
+
+    // 获取连线颜色 -
+    // 普通节点: 根据sourceRef和targetRef分为去匹配已经生成的任务,如果有两个id中有任意一个不存在于taskList中,则说明是未走过流程
+    // 子容器节点:
+    getLinkColor(data) {
+      const { sourceRef, targetRef } = data;
+      let fromNodeStatus = false;
+      let toNodeStatus = false;
+      // 判断节点是普通节点还是子容器节点
+      const isSubNodeFrom = sourceRef.startsWith('subContainer');
+      const isSubNodeTo = targetRef.startsWith('subContainer');
+
+      if (isSubNodeFrom) {
+        fromNodeStatus = this.getSubContainerStatus(sourceRef);
+      } else {
+        fromNodeStatus = this.taskList.find((el) => el.id === sourceRef);
+      }
+
+      if (isSubNodeTo) {
+        toNodeStatus = this.getSubContainerStatus(targetRef);
+      } else {
+        toNodeStatus = this.taskList.find((el) => el.id === targetRef);
+      }
+      if (
+        fromNodeStatus !== 'ready' &&
+        fromNodeStatus !== undefined &&
+        toNodeStatus !== 'ready' &&
+        toNodeStatus !== undefined
+      ) {
+        return blue;
+      } else {
+        return 'gray';
+      }
+    },
+
+    // 返回节点背景图模板
+    getTaskPictureTemplate() {
+      const { getSubContainerStatus, getTaskStatus, textColor, bgColor } = this;
+      return $(
+        go.Panel,
+        { name: 'pictureTemplate' },
+        $(
+          go.Shape,
+          'DataStorage',
+          {
+            margin: new go.Margin(0, 0, 0, 18),
+            desiredSize: new go.Size(220, 36)
+          },
+          new go.Binding('stroke', function (e) {
+            const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
+            return textColor[status];
+          }),
+          new go.Binding('fill', function (e) {
+            const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
+            return bgColor[status];
+          })
+        ),
+        $(
+          go.Shape,
+          'Circle',
+          { desiredSize: new go.Size(36, 36) },
+          new go.Binding('stroke', function (e) {
+            const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
+            return textColor[status];
+          }),
+          new go.Binding('fill', function (e) {
+            const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
+            return bgColor[status];
+          })
+        ),
+        $(
+          go.Shape,
+          {
+            desiredSize: new go.Size(16, 16),
+            margin: new go.Margin(10, 0, 0, 10),
+            strokeWidth: 0
+          },
+          new go.Binding('fill', function (e) {
+            const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
+            return textColor[status];
+          }),
+          new go.Binding('geometry', function (e) {
+            return geoFunc('' + e.type);
+            // return geoFunc("serviceTask");
+          })
+        )
+      );
+    },
+
+    // 获取详情框数据
+    getlDetail(e, o) {
+      const status = this.getTaskStatus(o.data.id);
+      const params = {
+        applyOrdNo: this.applyOrdNo,
+        nodeKey: o.data.id,
+        nodeStatus: status == 'complete' ? 'finish' : status == 'ing' ? 'unfinish' : 'unstart'
+      };
+
+      getFlowChartDetail(params).then((res) => {
+        // 模拟接口返回的详情数据
+        let result = res.data.content;
+        result.actStartTime = result.actStartTime ? moment(result.actStartTime).format('YYYY-MM-DD HH:mm') : '';
+        result.actEndTime = result.actEndTime ? moment(result.actEndTime).format('YYYY-MM-DD HH:mm') : '';
+        const obj = result;
+        this.renderModal(obj);
+        this.isShow = true;
+
+        this.$nextTick(() => {
+          // 弹框展示
+          let left = e.Dr.offsetX;
+          let top = e.Dr.offsetY + 50;
+
+          const diagramDom = this.$refs['myDiagramDiv'];
+          const dom = this.$refs['shallowBox'];
+
+          // 防止弹框超出画布范围
+          if (left + dom.clientWidth > diagramDom.clientWidth) {
+            left = left - dom.clientWidth;
+          }
+          if (top + dom.clientHeight > diagramDom.clientHeight) {
+            top = top - 50 - dom.clientHeight;
+          }
+          // 设置弹出框的位置
+          this.modalStyle = {
+            left: left + 'px',
+            top: top + 'px'
+          };
+        });
+      });
+    },
+    // 渲染弹出框信息
+    renderModal(obj) {
+      this.detailBindData = obj;
+      const { actStartTime, dueDate, beforeDueLimit } = obj;
+      let tipMsg = [];
+      let currentTime = new Date().getTime();
+
+      // 倒计时计算 - 前提:流入时间/办理期限不为空
+      if (actStartTime) {
+        if (dueDate) {
+          // 任务截止时间 - 当前时间 ---> > 0 计算倒计时 , <= 0 提示节点超时
+          let differTime = new Date(dueDate).getTime() - currentTime; // 任务截止与流入时间差值
+          if (differTime > 0) {
+            // 倒计时
+            let h = Math.floor(differTime / 1000 / 60 / 60);
+            let m = Math.floor((differTime / 1000 / 60) % 60);
+            let s = Math.floor((differTime / 1000) % 60);
+            h = h < 10 ? '0' + h : h;
+            m = m < 10 ? '0' + m : m;
+            s = s < 10 ? '0' + s : s;
+            this.detailBindData = {
+              ...this.detailBindData,
+              showCountDown: true,
+              countTime: h + ':' + m + ':' + s
+            };
+            this.timer = setTimeout(() => {
+              this.renderModal(obj);
+            }, 1000);
+          } else {
+            // 系统超时
+            tipMsg.push('节点超时');
+          }
+        }
+
+        // 系统催办时间 - 当前时间 ---> > 0 不催办, <= 0 提示系统催办
+        if (beforeDueLimit) {
+          let differPress = new Date(actStartTime).getTime() + Number(beforeDueLimit) * 60 * 60 * 1000 - currentTime; // 催办时间与流入时间差值
+          if (differPress <= 0) {
+            tipMsg.push('系统催办');
+          }
+        }
+      }
+
+      this.detailBindData = {
+        ...this.detailBindData,
+        tipMsgStr: tipMsg.length > 0 ? tipMsg.join('/') : ''
+      };
+
+      console.log('详情数据', this.detailBindData);
+    },
+    initDiagram() {
+      const {
+        getTaskStatus,
+        getSubContainerStatus,
+        textColor,
+        borderColor,
+        bgColor,
+        getLinkColor,
+        addGroupItems,
+        getTaskPictureTemplate,
+        getlDetail,
+        closeModal,
+        getSubContainerDrawData
+      } = this;
+
+      let { myDiagram } = this;
+
+      myDiagram = $(go.Diagram, 'myDiagramDiv', {
+        // 'toolManager.mouseWheelBehavior': go.ToolManager.WheelZoom,c
+        initialContentAlignment: go.Spot.Center,
+        allowCopy: false,
+        allowDelete: false,
+        layout: $(go.TreeLayout, {
+          angle: 90, // 垂直
+          // angle: 0, // 水平
+          // layerSpacing: 80, // 节点间垂直距离
+          nodeSpacing: 120 // 横向节点的间距宽度
+        })
+        // "grid.visible": true, // 是否展示网格
+      });
+
+      // 返回文字节点模板
+      function getTextTemplate() {
+        return $(
+          go.TextBlock,
+          {
+            font: '10pt Lato, Helvetica, Arial, sans-serif',
+            overflow: go.TextBlock.OverflowEllipsis,
+            maxLines: 1,
+            maxSize: new go.Size(140, NaN),
+            margin: new go.Margin(0, 0, 0, 15),
+            wrap: go.TextBlock.WrapFit,
+            name: 'textTemplate'
+          },
+          new go.Binding('stroke', function (e) {
+            const status = e.category === 'subprocess' ? getSubContainerStatus(e.id) : getTaskStatus(e.id);
+            return textColor[status];
+          }),
+          new go.Binding('text', 'text', function (text) {
+            // 只截取7个字符长度,超过部分用'...'表示
+            if (text.length > 10) {
+              return text.substr(0, 10) + '...';
+            } else {
+              return text;
+            }
+          })
+        );
+      }
+
+      // 返回悬浮提示框节点模板
+      function getToolTipTemplate() {
+        return $('ToolTip', $(go.TextBlock, { margin: 3 }, new go.Binding('text')));
+      }
+
+      // 定义事件-开始/结束模板
+      // 结束节点 -> 只有“未开始/已完成” 状态, 开始节点 -> 只有“已完成”状态
+      const eventNodeTemplate = $(
+        go.Node,
+        'Table',
+        $(
+          go.Panel,
+          'Spot',
+          { desiredSize: new go.Size(75, 75) },
+          new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
+          $(
+            go.Shape,
+            'Circle',
+            {
+              stroke: null
+            },
+            new go.Binding('fill', function (e) {
+              return e.type == 'start' ? lightBlue : lightGray;
+            })
+          ),
+          $(
+            go.Shape,
+            'Circle',
+            {
+              desiredSize: new go.Size(55, 55),
+              strokeWidth: 2,
+              stroke: null
+            },
+            new go.Binding('fill', function (e) {
+              if (e.type == 'start') {
+                return blue;
+              } else {
+                return getTaskStatus(e.id) === 'ready' ? 'white' : blue;
+              }
+            })
+          ),
+          $(
+            go.TextBlock,
+            {
+              font: 'bold 14pt helvetica, bold arial, sans-serif'
+            },
+            new go.Binding('stroke', function (e) {
+              if (e.type == 'start') {
+                return 'white';
+              } else {
+                return getTaskStatus(e.id) === 'ready' ? 'gray' : 'white';
+              }
+            }),
+            new go.Binding('text')
+          )
+        )
+      );
+
+      // 定义节点默认模板
+      const defaultNodeTemplate = $(go.Node, 'Auto', getTaskPictureTemplate(), getTextTemplate(), {
+        toolTip: getToolTipTemplate(),
+        click: function (e, o) {
+          return getlDetail(e, o);
+        },
+        selectionChanged: function (e) {
+          if (!e.isSelected) {
+            closeModal();
+          }
+        }
+      });
+
+      // 定义网关节点模板
+      // const gatewayNodeTemplate = $(go.Node, "Auto", getTaskPictureTemplate());
+      const gatewayNodeTemplate = $(
+        go.Node,
+        'Table',
+        $(
+          go.Panel,
+          'Spot',
+          { desiredSize: new go.Size(55, 55) },
+          new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
+          // 最外层
+          $(
+            go.Shape,
+            'Diamond',
+            {
+              stroke: null
+            },
+            new go.Binding('fill', function (e) {
+              const status = getTaskStatus(e.id);
+              return status === 'ready' ? lightGray : status === 'complete' ? lightBlue : lightGreen;
+            })
+          ),
+          // 中间层
+          $(
+            go.Shape,
+            'Diamond',
+            {
+              desiredSize: new go.Size(35, 35),
+              strokeWidth: 2
+            },
+            new go.Binding('stroke', function (e) {
+              const status = getTaskStatus(e.id);
+              return status === 'ready' ? 'gray' : null;
+            }),
+            new go.Binding('fill', function (e) {
+              const status = getTaskStatus(e.id);
+              return status === 'ready' ? 'white' : status === 'complete' ? blue : green;
+            })
+          ),
+          // 里层
+          $(
+            go.Shape,
+            {
+              desiredSize: new go.Size(10, 10),
+              strokeWidth: 2
+            },
+            new go.Binding('stroke', function (e) {
+              const status = getTaskStatus(e.id);
+              return status === 'ready' ? 'gray' : 'white';
+            }),
+            new go.Binding('figure', function (obj) {
+              const { type } = obj;
+              return type == 'exclusiveGateway' ? 'XLine' : type == 'inclusiveGateway' ? 'CircleLine' : 'PlusLine';
+            })
+          )
+        )
+      );
+
+      // 定义子容器分组
+      const defaultGroupTemplate = $(
+        go.Group,
+        'Auto',
+        {
+          layout: $(go.TreeLayout, {
+            angle: 90,
+            arrangement: go.TreeLayout.ArrangementHorizontal,
+            isRealtime: false
+          }),
+          isSubGraphExpanded: false,
+          subGraphExpandedChanged: function (group) {
+            // 动态修改节点属性值
+            let box = group.findObject('box');
+            let pictureTemplate = group.findObject('pictureTemplate');
+            let textTemplate = group.findObject('textTemplate');
+            box.visible = group.isSubGraphExpanded;
+            pictureTemplate.visible = !box.visible;
+            textTemplate.visible = !box.visible;
+            if (group.memberParts.count === 0) {
+              addGroupItems(group.data, myDiagram);
+            }
+          }
+        },
+        $(
+          go.Shape,
+          'Rectangle',
+          {
+            name: 'box',
+            fill: null,
+            visible: false,
+            strokeDashArray: [10, 10] // 设置虚线
+          },
+          new go.Binding('stroke', 'id', function (id) {
+            let status = getSubContainerStatus(id);
+            return borderColor[status];
+          })
+        ),
+        $(
+          go.Panel,
+          'Table',
+          { margin: new go.Margin(0, 0, 0, 0) },
+          getTaskPictureTemplate(),
+          getTextTemplate(),
+          $(
+            'SubGraphExpanderButton',
+            {
+              alignment: go.Spot.Right,
+              margin: new go.Margin(0, 15, 0, 0),
+              width: 18,
+              height: 18
+            },
+            new go.Binding('visible', 'id', function (id) {
+              let node = getSubContainerDrawData(id);
+              if (node) {
+                // 子容器的绘图数据
+                let subNodeDataArray = node.diagramModel.nodeDataArray;
+                let subLinkDataArray = node.diagramModel.linkDataArray;
+
+                // 节点或者连线,两者有一个没有数据,则默认不绘图
+                if (
+                  subNodeDataArray.length === 0 ||
+                  subLinkDataArray.length === 0 ||
+                  subNodeDataArray.length === 2 ||
+                  subLinkDataArray.length < subNodeDataArray.length - 1
+                ) {
+                  return false;
+                } else {
+                  return true;
+                }
+              } else {
+                return false;
+              }
+            })
+          ),
+          $(go.Placeholder, {
+            row: 1,
+            columnSpan: 2,
+            padding: 10,
+            alignment: go.Spot.TopLeft
+          })
+        ),
+
+        {
+          toolTip: getToolTipTemplate()
+        }
+      );
+
+      /*******************  节点模板引用    ***************************/
+      myDiagram.nodeTemplateMap.add('', defaultNodeTemplate);
+      myDiagram.nodeTemplateMap.add('event', eventNodeTemplate);
+      myDiagram.nodeTemplateMap.add('gateway', gatewayNodeTemplate);
+
+      /*******************  分组模板引用    ***************************/
+      myDiagram.groupTemplateMap.add('subprocess', defaultGroupTemplate);
+
+      /*******************  连线模板    ***************************/
+
+      myDiagram.linkTemplate = $(
+        go.Link, // the whole link panel
+        {
+          routing: go.Link.AvoidsNodes
+          // curve: go.Link.JumpOver,
+          // corner: 5,
+        },
+        $(
+          go.Shape, // the link path shape
+          { isPanelMain: true, strokeWidth: 1 },
+          new go.Binding('stroke', function (e) {
+            let color = getLinkColor(e);
+            return color;
+          })
+          // new go.Binding("stroke", "isSelected", function (sel) {
+          //   return sel ? "dodgerblue" : "gray";
+          // }).ofObject()
+        ),
+        // 箭头
+        $(
+          go.Shape,
+          { toArrow: 'standard', strokeWidth: 0 },
+          new go.Binding('fill', function (e) {
+            return getLinkColor(e);
+          })
+        ),
+        $(
+          go.Panel,
+          'Auto',
+          $(
+            go.TextBlock,
+            {
+              textAlign: 'center',
+              font: '9pt helvetica, arial, sans-serif',
+              margin: 4
+            },
+            new go.Binding('text')
+          )
+        )
+      );
+
+      // 鼠标滚轮滚动,隐藏弹框
+      const tool = myDiagram.toolManager;
+      tool.standardMouseWheel = () => {
+        if (this.isShow) {
+          this.isShow = false;
+        }
+        go.ToolManager.prototype.standardMouseWheel.call(tool);
+      };
+
+      // 加载数据
+      myDiagram.model = go.Model.fromJson(this.modelData.json);
+      this.isEmpty = Object.keys(this.modelData).length == 0;
+    }
+  },
+  mounted() {
+    processConfig(this.applyOrdNo).then((res) => {
+      if (res.data.content) {
+        this.modelData = res.data.content;
+        this.$nextTick(() => {
+          this.initDiagram();
+        });
+      }
+    });
+  },
+  created() {}
+};
+</script>
+
+<style lang="scss">
+/* -- 流程图状态说明 ---------*/
+.legend-group {
+  display: flex;
+  align-items: center;
+  &__item {
+    display: flex;
+    align-items: center;
+    margin-left: 20px;
+    .retange {
+      display: inline-block;
+      width: 16px;
+      height: 16px;
+      border: 1px;
+      background: red;
+      margin-right: 5px;
+    }
+  }
+}
+.shallow-box {
+  position: absolute;
+  top: 300px;
+  left: 100px;
+  padding: 12px;
+  width: 300px;
+  border: 1px solid lightgray;
+  background: white;
+  z-index: 10000;
+  color: rgba(0, 0, 0, 0.85);
+  .close {
+    position: absolute;
+    right: 10px;
+    top: 5px;
+    cursor: pointer;
+  }
+  .header {
+    display: flex;
+    align-items: center;
+    border-bottom: 1px solid lightgray;
+    padding-bottom: 12px;
+    .title {
+      width: 270px;
+      display: inline-block;
+      // white-space: nowrap;
+      // overflow: hidden;
+      // text-overflow: ellipsis;
+    }
+    .time {
+      margin-left: 30px;
+      background: rgb(227, 239, 255);
+      height: 24px;
+      padding: 0 5px;
+    }
+  }
+  .form-item {
+    display: flex;
+    margin: 10px 0;
+    .label {
+      width: 80px;
+      color: gray;
+      display: inline-block;
+    }
+    .text {
+      width: calc(100% - 80px);
+    }
+  }
+}
+</style>
+

+ 1 - 1
src/pages/permission-selfhelp-manage/index.vue

@@ -144,7 +144,7 @@ export default {
           type: 'detail'
           type: 'detail'
         },
         },
         content: require('./component/detail.vue'),
         content: require('./component/detail.vue'),
-        area: ['1100px', '800px'],
+        area: ['1280px', '800px'],
         on: {
         on: {
           success(params) {
           success(params) {
             layer.close(layer.dialogIndex);
             layer.close(layer.dialogIndex);