Răsfoiți Sursa

临时提交,尝试实现流程图的高亮

YunaiV 3 ani în urmă
părinte
comite
5a4392dc4e

+ 3 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskRespVO.java

@@ -14,6 +14,9 @@ import java.util.List;
 @ToString(callSuper = true)
 public class BpmTaskRespVO extends BpmTaskDonePageItemRespVO {
 
+    @ApiModelProperty(value = "任务定义的标识", required = true, example = "user-001")
+    private String definitionKey;
+
     /**
      * 审核的用户信息
      */

+ 1 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmTaskConvert.java

@@ -99,6 +99,7 @@ public interface BpmTaskConvert {
         });
     }
 
+    @Mapping(source = "taskDefinitionKey", target = "definitionKey")
     BpmTaskRespVO convert3(HistoricTaskInstance bean);
     BpmTaskRespVO.User convert3(SysUserDO bean);
 

+ 142 - 7
yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="my-process-designer">
     <div class="my-process-designer__container">
-      <div class="my-process-designer__canvas" ref="bpmn-canvas"></div>
+      <div class="my-process-designer__canvas" ref="canvas"></div>
     </div>
   </div>
 </template>
@@ -18,14 +18,24 @@ export default {
     prefix: {
       type: String,
       default: "camunda"
+    },
+    taskData: {
+      type: Array,
+      default: () => []
     }
   },
   data() {
-    return {};
+    return {
+      xml: '',
+      tasks: [],
+    };
   },
   mounted() {
+    this.xml = this.value;
+    this.tasks = this.taskData;
+    // 初始化
     this.initBpmnModeler();
-    this.createNewDiagram(this.value);
+    this.createNewDiagram(this.xml);
     this.$once("hook:beforeDestroy", () => {
       if (this.bpmnModeler) this.bpmnModeler.destroy();
       this.$emit("destroy", this.bpmnModeler);
@@ -34,14 +44,21 @@ export default {
   },
   watch: {
     value: function (newValue) { // 在 xmlString 发生变化时,重新创建,从而绘制流程图
-      this.createNewDiagram(newValue);
+      this.xml = newValue;
+      this.createNewDiagram(this.xml);
+    },
+    taskData: function (newTaskData) {
+      this.tasks = newTaskData;
+      this.createNewDiagram(this.xml);
     }
   },
   methods: {
     initBpmnModeler() {
       if (this.bpmnModeler) return;
       this.bpmnModeler = new BpmnViewer({
-        container: this.$refs["bpmn-canvas"]
+        container: this.$refs["canvas"],
+        bpmnRenderer: {
+        }
       })
     },
     /* 创建新的流程图 */
@@ -51,15 +68,133 @@ export default {
       let newName = `业务流程_${new Date().getTime()}`;
       let xmlString = xml || DefaultEmptyXML(newId, newName, this.prefix);
       try {
-        console.log(this.bpmnModeler.importXML);
+        // console.log(this.bpmnModeler.importXML);
         let { warnings } = await this.bpmnModeler.importXML(xmlString);
         if (warnings && warnings.length) {
           warnings.forEach(warn => console.warn(warn));
         }
+        // 高亮流程图
+        await this.highlightDiagram();
       } catch (e) {
-        console.error(`[Process Designer Warn]: ${e?.message || e}`);
+        console.error(e);
+        // console.error(`[Process Designer Warn]: ${e?.message || e}`);
       }
+    },
+    /* 高亮流程图 */
+    async highlightDiagram() {
+      if (this.tasks.length === 0) {
+        return;
+      }
+      if (!this.bpmnModeler.getDefinitions().rootElements[0].flowElements) {
+        return;
+      }
+      let canvas = this.bpmnModeler.get('canvas');
+      this.bpmnModeler.getDefinitions().rootElements[0].flowElements.forEach(n => {
+        if (n.$type === 'bpmn:UserTask') {
+          let completeTask = this.tasks.find(m => m.definitionKey === n.id)
+          let todoTask = this.tasks.find(m => !m.endTime)
+          let endTask = this.tasks[this.tasks.length - 1]
+          if (completeTask) {
+            canvas.addMarker(n.id, completeTask.endTime ? 'highlight' : 'highlight-todo');
+            console.log(n.id + ' : ' + (completeTask.endTime ? 'highlight' : 'highlight-todo'));
+            // n.outgoing.forEach(nn => {
+            //   let targetTask = this.tasks.find(m => m.definitionKey === nn.targetRef.id)
+            //   if (targetTask) {
+            //     canvas.addMarker(nn.id, targetTask.endTime ? 'highlight' : 'highlight-todo');
+            //   } else if (nn.targetRef.$type === 'bpmn:ExclusiveGateway') {
+            //     // canvas.addMarker(nn.id, 'highlight');
+            //     canvas.addMarker(nn.id, completeTask.endTime ? 'highlight' : 'highlight-todo');
+            //     canvas.addMarker(nn.targetRef.id, completeTask.endTime ? 'highlight' : 'highlight-todo');
+            //   } else if (nn.targetRef.$type === 'bpmn:EndEvent') {
+            //     if (!todoTask && endTask.definitionKey === n.id) {
+            //       canvas.addMarker(nn.id, 'highlight');
+            //       canvas.addMarker(nn.targetRef.id, 'highlight');
+            //     }
+            //     if (!completeTask.endTime) {
+            //       canvas.addMarker(nn.id, 'highlight-todo');
+            //       canvas.addMarker(nn.targetRef.id, 'highlight-todo');
+            //     }
+            //   }
+            // });
+          }
+        } else if (n.$type === 'bpmn:ExclusiveGateway') {
+          // n.outgoing.forEach(nn => {
+          //   let targetTask = this.tasks.find(m => m.definitionKey === nn.targetRef.id)
+          //   if (targetTask) {
+          //     canvas.addMarker(nn.id, targetTask.endTime ? 'highlight' : 'highlight-todo');
+          //   }
+          // })
+        }
+        if (n.$type === 'bpmn:StartEvent') {
+          canvas.addMarker(n.id, 'highlight-todo');
+
+          // n.outgoing.forEach(nn => {
+          //   let completeTask = this.tasks.find(m => m.definitionKey === nn.targetRef.id)
+          //   if (completeTask) {
+          //     canvas.addMarker(nn.id, 'highlight');
+          //     canvas.addMarker(n.id, 'highlight');
+          //     return
+          //   }
+          // });
+        }
+      })
     }
   }
 };
 </script>
+
+<style>
+.containers {
+  position: absolute;
+  background-color: #ffffff;
+  top:0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+}
+.canvas {
+  width: 100%;
+  height: 100%;
+}
+
+/*/deep/.highlight-todo {*/
+/*  background-color: red;*/
+/*  fill: green !important;*/
+/*  stroke: green !important;*/
+/*}*/
+
+/deep/.highlight.djs-shape .djs-visual > :nth-child(1) {
+  fill: green !important;
+  stroke: green !important;
+  fill-opacity: 0.2 !important;
+}
+/deep/.highlight.djs-shape .djs-visual > :nth-child(2) {
+  fill: green !important;
+}
+/deep/.highlight.djs-shape .djs-visual > path {
+  fill: green !important;
+  fill-opacity: 0.2 !important;
+  stroke: green !important;
+}
+/deep/.highlight.djs-connection > .djs-visual > path {
+  stroke: green !important;
+}
+/deep/.highlight-todo.djs-connection > .djs-visual > path {
+  stroke: orange !important;
+  stroke-dasharray: 4px !important;
+  fill-opacity: 0.2 !important;
+  marker-end: url(#sequenceflow-end-_E7DFDF-_E7DFDF-803g1kf6zwzmcig1y2ulm5egr);
+}
+/deep/.highlight-todo.djs-shape .djs-visual > :nth-child(1) {
+  fill: orange !important;
+  stroke: orange !important;
+  stroke-dasharray: 4px !important;
+  fill-opacity: 0.2 !important;
+}
+/deep/.overlays-div {
+  font-size: 10px;
+  color: red;
+  width: 100px;
+  top: -20px !important;
+}
+</style>

+ 1 - 0
yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/index.js

@@ -4,4 +4,5 @@ MyProcessDesigner.install = function(Vue) {
   Vue.component(MyProcessDesigner.name, MyProcessDesigner);
 };
 
+// 流程图的设计器,可编辑
 export default MyProcessDesigner;

+ 1 - 0
yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/index2.js

@@ -4,4 +4,5 @@ MyProcessViewer.install = function(Vue) {
   Vue.component(MyProcessViewer.name, MyProcessViewer);
 };
 
+// 流程图的查看器,不可编辑
 export default MyProcessViewer;

+ 1 - 0
yudao-admin-ui/src/main.js

@@ -83,6 +83,7 @@ import "@/components/bpmnProcessDesigner/package/theme/index.scss";
 import "bpmn-js/dist/assets/diagram-js.css";
 import "bpmn-js/dist/assets/bpmn-font/css/bpmn.css";
 import "bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css";
+import "bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
 
 // Form Generator 组件需要使用到 tinymce
 import Tinymce from '@/components/tinymce/index.vue'

+ 1 - 1
yudao-admin-ui/src/views/bpm/processInstance/detail.vue

@@ -73,7 +73,7 @@
       <div slot="header" class="clearfix">
         <span class="el-icon-picture-outline">流程图</span>
       </div>
-      <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" />
+      <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" :taskData="historicTasks" />
     </el-card>
 
     <!-- 对话框(转派审批人) -->