Commit 5a4392dc4e1d8ed55e073e586a00d0a2b6fcb335

Authored by YunaiV
1 parent 0765f481

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

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; @@ -14,6 +14,9 @@ import java.util.List;
14 @ToString(callSuper = true) 14 @ToString(callSuper = true)
15 public class BpmTaskRespVO extends BpmTaskDonePageItemRespVO { 15 public class BpmTaskRespVO extends BpmTaskDonePageItemRespVO {
16 16
  17 + @ApiModelProperty(value = "任务定义的标识", required = true, example = "user-001")
  18 + private String definitionKey;
  19 +
17 /** 20 /**
18 * 审核的用户信息 21 * 审核的用户信息
19 */ 22 */
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmTaskConvert.java
@@ -99,6 +99,7 @@ public interface BpmTaskConvert { @@ -99,6 +99,7 @@ public interface BpmTaskConvert {
99 }); 99 });
100 } 100 }
101 101
  102 + @Mapping(source = "taskDefinitionKey", target = "definitionKey")
102 BpmTaskRespVO convert3(HistoricTaskInstance bean); 103 BpmTaskRespVO convert3(HistoricTaskInstance bean);
103 BpmTaskRespVO.User convert3(SysUserDO bean); 104 BpmTaskRespVO.User convert3(SysUserDO bean);
104 105
yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue
1 <template> 1 <template>
2 <div class="my-process-designer"> 2 <div class="my-process-designer">
3 <div class="my-process-designer__container"> 3 <div class="my-process-designer__container">
4 - <div class="my-process-designer__canvas" ref="bpmn-canvas"></div> 4 + <div class="my-process-designer__canvas" ref="canvas"></div>
5 </div> 5 </div>
6 </div> 6 </div>
7 </template> 7 </template>
@@ -18,14 +18,24 @@ export default { @@ -18,14 +18,24 @@ export default {
18 prefix: { 18 prefix: {
19 type: String, 19 type: String,
20 default: "camunda" 20 default: "camunda"
  21 + },
  22 + taskData: {
  23 + type: Array,
  24 + default: () => []
21 } 25 }
22 }, 26 },
23 data() { 27 data() {
24 - return {}; 28 + return {
  29 + xml: '',
  30 + tasks: [],
  31 + };
25 }, 32 },
26 mounted() { 33 mounted() {
  34 + this.xml = this.value;
  35 + this.tasks = this.taskData;
  36 + // 初始化
27 this.initBpmnModeler(); 37 this.initBpmnModeler();
28 - this.createNewDiagram(this.value); 38 + this.createNewDiagram(this.xml);
29 this.$once("hook:beforeDestroy", () => { 39 this.$once("hook:beforeDestroy", () => {
30 if (this.bpmnModeler) this.bpmnModeler.destroy(); 40 if (this.bpmnModeler) this.bpmnModeler.destroy();
31 this.$emit("destroy", this.bpmnModeler); 41 this.$emit("destroy", this.bpmnModeler);
@@ -34,14 +44,21 @@ export default { @@ -34,14 +44,21 @@ export default {
34 }, 44 },
35 watch: { 45 watch: {
36 value: function (newValue) { // 在 xmlString 发生变化时,重新创建,从而绘制流程图 46 value: function (newValue) { // 在 xmlString 发生变化时,重新创建,从而绘制流程图
37 - this.createNewDiagram(newValue); 47 + this.xml = newValue;
  48 + this.createNewDiagram(this.xml);
  49 + },
  50 + taskData: function (newTaskData) {
  51 + this.tasks = newTaskData;
  52 + this.createNewDiagram(this.xml);
38 } 53 }
39 }, 54 },
40 methods: { 55 methods: {
41 initBpmnModeler() { 56 initBpmnModeler() {
42 if (this.bpmnModeler) return; 57 if (this.bpmnModeler) return;
43 this.bpmnModeler = new BpmnViewer({ 58 this.bpmnModeler = new BpmnViewer({
44 - container: this.$refs["bpmn-canvas"] 59 + container: this.$refs["canvas"],
  60 + bpmnRenderer: {
  61 + }
45 }) 62 })
46 }, 63 },
47 /* 创建新的流程图 */ 64 /* 创建新的流程图 */
@@ -51,15 +68,133 @@ export default { @@ -51,15 +68,133 @@ export default {
51 let newName = `业务流程_${new Date().getTime()}`; 68 let newName = `业务流程_${new Date().getTime()}`;
52 let xmlString = xml || DefaultEmptyXML(newId, newName, this.prefix); 69 let xmlString = xml || DefaultEmptyXML(newId, newName, this.prefix);
53 try { 70 try {
54 - console.log(this.bpmnModeler.importXML); 71 + // console.log(this.bpmnModeler.importXML);
55 let { warnings } = await this.bpmnModeler.importXML(xmlString); 72 let { warnings } = await this.bpmnModeler.importXML(xmlString);
56 if (warnings && warnings.length) { 73 if (warnings && warnings.length) {
57 warnings.forEach(warn => console.warn(warn)); 74 warnings.forEach(warn => console.warn(warn));
58 } 75 }
  76 + // 高亮流程图
  77 + await this.highlightDiagram();
59 } catch (e) { 78 } catch (e) {
60 - console.error(`[Process Designer Warn]: ${e?.message || e}`); 79 + console.error(e);
  80 + // console.error(`[Process Designer Warn]: ${e?.message || e}`);
61 } 81 }
  82 + },
  83 + /* 高亮流程图 */
  84 + async highlightDiagram() {
  85 + if (this.tasks.length === 0) {
  86 + return;
  87 + }
  88 + if (!this.bpmnModeler.getDefinitions().rootElements[0].flowElements) {
  89 + return;
  90 + }
  91 + let canvas = this.bpmnModeler.get('canvas');
  92 + this.bpmnModeler.getDefinitions().rootElements[0].flowElements.forEach(n => {
  93 + if (n.$type === 'bpmn:UserTask') {
  94 + let completeTask = this.tasks.find(m => m.definitionKey === n.id)
  95 + let todoTask = this.tasks.find(m => !m.endTime)
  96 + let endTask = this.tasks[this.tasks.length - 1]
  97 + if (completeTask) {
  98 + canvas.addMarker(n.id, completeTask.endTime ? 'highlight' : 'highlight-todo');
  99 + console.log(n.id + ' : ' + (completeTask.endTime ? 'highlight' : 'highlight-todo'));
  100 + // n.outgoing.forEach(nn => {
  101 + // let targetTask = this.tasks.find(m => m.definitionKey === nn.targetRef.id)
  102 + // if (targetTask) {
  103 + // canvas.addMarker(nn.id, targetTask.endTime ? 'highlight' : 'highlight-todo');
  104 + // } else if (nn.targetRef.$type === 'bpmn:ExclusiveGateway') {
  105 + // // canvas.addMarker(nn.id, 'highlight');
  106 + // canvas.addMarker(nn.id, completeTask.endTime ? 'highlight' : 'highlight-todo');
  107 + // canvas.addMarker(nn.targetRef.id, completeTask.endTime ? 'highlight' : 'highlight-todo');
  108 + // } else if (nn.targetRef.$type === 'bpmn:EndEvent') {
  109 + // if (!todoTask && endTask.definitionKey === n.id) {
  110 + // canvas.addMarker(nn.id, 'highlight');
  111 + // canvas.addMarker(nn.targetRef.id, 'highlight');
  112 + // }
  113 + // if (!completeTask.endTime) {
  114 + // canvas.addMarker(nn.id, 'highlight-todo');
  115 + // canvas.addMarker(nn.targetRef.id, 'highlight-todo');
  116 + // }
  117 + // }
  118 + // });
  119 + }
  120 + } else if (n.$type === 'bpmn:ExclusiveGateway') {
  121 + // n.outgoing.forEach(nn => {
  122 + // let targetTask = this.tasks.find(m => m.definitionKey === nn.targetRef.id)
  123 + // if (targetTask) {
  124 + // canvas.addMarker(nn.id, targetTask.endTime ? 'highlight' : 'highlight-todo');
  125 + // }
  126 + // })
  127 + }
  128 + if (n.$type === 'bpmn:StartEvent') {
  129 + canvas.addMarker(n.id, 'highlight-todo');
  130 +
  131 + // n.outgoing.forEach(nn => {
  132 + // let completeTask = this.tasks.find(m => m.definitionKey === nn.targetRef.id)
  133 + // if (completeTask) {
  134 + // canvas.addMarker(nn.id, 'highlight');
  135 + // canvas.addMarker(n.id, 'highlight');
  136 + // return
  137 + // }
  138 + // });
  139 + }
  140 + })
62 } 141 }
63 } 142 }
64 }; 143 };
65 </script> 144 </script>
  145 +
  146 +<style>
  147 +.containers {
  148 + position: absolute;
  149 + background-color: #ffffff;
  150 + top:0;
  151 + left: 0;
  152 + width: 100%;
  153 + height: 100%;
  154 +}
  155 +.canvas {
  156 + width: 100%;
  157 + height: 100%;
  158 +}
  159 +
  160 +/*/deep/.highlight-todo {*/
  161 +/* background-color: red;*/
  162 +/* fill: green !important;*/
  163 +/* stroke: green !important;*/
  164 +/*}*/
  165 +
  166 +/deep/.highlight.djs-shape .djs-visual > :nth-child(1) {
  167 + fill: green !important;
  168 + stroke: green !important;
  169 + fill-opacity: 0.2 !important;
  170 +}
  171 +/deep/.highlight.djs-shape .djs-visual > :nth-child(2) {
  172 + fill: green !important;
  173 +}
  174 +/deep/.highlight.djs-shape .djs-visual > path {
  175 + fill: green !important;
  176 + fill-opacity: 0.2 !important;
  177 + stroke: green !important;
  178 +}
  179 +/deep/.highlight.djs-connection > .djs-visual > path {
  180 + stroke: green !important;
  181 +}
  182 +/deep/.highlight-todo.djs-connection > .djs-visual > path {
  183 + stroke: orange !important;
  184 + stroke-dasharray: 4px !important;
  185 + fill-opacity: 0.2 !important;
  186 + marker-end: url(#sequenceflow-end-_E7DFDF-_E7DFDF-803g1kf6zwzmcig1y2ulm5egr);
  187 +}
  188 +/deep/.highlight-todo.djs-shape .djs-visual > :nth-child(1) {
  189 + fill: orange !important;
  190 + stroke: orange !important;
  191 + stroke-dasharray: 4px !important;
  192 + fill-opacity: 0.2 !important;
  193 +}
  194 +/deep/.overlays-div {
  195 + font-size: 10px;
  196 + color: red;
  197 + width: 100px;
  198 + top: -20px !important;
  199 +}
  200 +</style>
yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/index.js
@@ -4,4 +4,5 @@ MyProcessDesigner.install = function(Vue) { @@ -4,4 +4,5 @@ MyProcessDesigner.install = function(Vue) {
4 Vue.component(MyProcessDesigner.name, MyProcessDesigner); 4 Vue.component(MyProcessDesigner.name, MyProcessDesigner);
5 }; 5 };
6 6
  7 +// 流程图的设计器,可编辑
7 export default MyProcessDesigner; 8 export default MyProcessDesigner;
yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/index2.js
@@ -4,4 +4,5 @@ MyProcessViewer.install = function(Vue) { @@ -4,4 +4,5 @@ MyProcessViewer.install = function(Vue) {
4 Vue.component(MyProcessViewer.name, MyProcessViewer); 4 Vue.component(MyProcessViewer.name, MyProcessViewer);
5 }; 5 };
6 6
  7 +// 流程图的查看器,不可编辑
7 export default MyProcessViewer; 8 export default MyProcessViewer;
yudao-admin-ui/src/main.js
@@ -83,6 +83,7 @@ import &quot;@/components/bpmnProcessDesigner/package/theme/index.scss&quot;; @@ -83,6 +83,7 @@ import &quot;@/components/bpmnProcessDesigner/package/theme/index.scss&quot;;
83 import "bpmn-js/dist/assets/diagram-js.css"; 83 import "bpmn-js/dist/assets/diagram-js.css";
84 import "bpmn-js/dist/assets/bpmn-font/css/bpmn.css"; 84 import "bpmn-js/dist/assets/bpmn-font/css/bpmn.css";
85 import "bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css"; 85 import "bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css";
  86 +import "bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
86 87
87 // Form Generator 组件需要使用到 tinymce 88 // Form Generator 组件需要使用到 tinymce
88 import Tinymce from '@/components/tinymce/index.vue' 89 import Tinymce from '@/components/tinymce/index.vue'
yudao-admin-ui/src/views/bpm/processInstance/detail.vue
@@ -73,7 +73,7 @@ @@ -73,7 +73,7 @@
73 <div slot="header" class="clearfix"> 73 <div slot="header" class="clearfix">
74 <span class="el-icon-picture-outline">流程图</span> 74 <span class="el-icon-picture-outline">流程图</span>
75 </div> 75 </div>
76 - <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" /> 76 + <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" :taskData="historicTasks" />
77 </el-card> 77 </el-card>
78 78
79 <!-- 对话框(转派审批人) --> 79 <!-- 对话框(转派审批人) -->