Commit 8e18a63d340891a27be24adf90723e838a7cee9f

Authored by YunaiV
1 parent 676e4f29

修改流程图的高亮实现,采用 activity 替代 task 作为数据源

yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmActivityController.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.controller.task;
2 2  
3 3 import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity.BpmActivityRespVO;
4 5 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmActivityService;
  6 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 7 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
6 8 import io.swagger.annotations.Api;
7 9 import io.swagger.annotations.ApiImplicitParam;
... ... @@ -15,6 +17,9 @@ import org.springframework.web.bind.annotation.RestController;
15 17 import javax.annotation.Resource;
16 18 import javax.servlet.http.HttpServletResponse;
17 19 import java.io.IOException;
  20 +import java.util.List;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
18 23  
19 24 @Api(tags = "流程活动实例")
20 25 @RestController
... ... @@ -25,11 +30,20 @@ public class BpmActivityController {
25 30 @Resource
26 31 private BpmActivityService activityService;
27 32  
28   - // TODO 芋艿:注解、权限、validtion
  33 + // TODO 芋艿:权限
29 34  
  35 + @GetMapping("/list")
30 36 @ApiOperation(value = "生成指定流程实例的高亮流程图",
31 37 notes = "只高亮进行中的任务。不过要注意,该接口暂时没用,通过前端的 ProcessViewer.vue 界面的 highlightDiagram 方法生成")
  38 + @ApiImplicitParam(name = "id", value = "流程实例的编号", required = true, dataTypeClass = String.class)
  39 + public CommonResult<List<BpmActivityRespVO>> getActivityList(
  40 + @RequestParam("processInstanceId") String processInstanceId) {
  41 + return success(activityService.getActivityListByProcessInstanceId(processInstanceId));
  42 + }
  43 +
32 44 @GetMapping("/generate-highlight-diagram")
  45 + @ApiOperation(value = "生成指定流程实例的高亮流程图",
  46 + notes = "只高亮进行中的任务。不过要注意,该接口暂时没用,通过前端的 ProcessViewer.vue 界面的 highlightDiagram 方法生成")
33 47 @ApiImplicitParam(name = "id", value = "流程实例的编号", required = true, dataTypeClass = String.class)
34 48 public void generateHighlightDiagram(@RequestParam("processInstanceId") String processInstanceId,
35 49 HttpServletResponse response) throws IOException {
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/activity/BpmActivityRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Date;
  8 +
  9 +@ApiModel("流程活动的 Response VO")
  10 +@Data
  11 +public class BpmActivityRespVO {
  12 +
  13 + @ApiModelProperty(value = "流程活动的标识", required = true, example = "1024")
  14 + private String key;
  15 + @ApiModelProperty(value = "流程活动的类型", required = true, example = "StartEvent")
  16 + private String type;
  17 +
  18 + @ApiModelProperty(value = "流程活动的开始时间", required = true)
  19 + private Date startTime;
  20 + @ApiModelProperty(value = "流程活动的结束时间", required = true)
  21 + private Date endTime;
  22 +
  23 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmActivityConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.convert.task;
  2 +
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity.BpmActivityRespVO;
  4 +import org.activiti.engine.history.HistoricActivityInstance;
  5 +import org.mapstruct.Mapper;
  6 +import org.mapstruct.Mapping;
  7 +import org.mapstruct.Mappings;
  8 +import org.mapstruct.factory.Mappers;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * BPM 活动 Convert
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface BpmActivityConvert {
  19 +
  20 + BpmActivityConvert INSTANCE = Mappers.getMapper(BpmActivityConvert.class);
  21 +
  22 + List<BpmActivityRespVO> convertList(List<HistoricActivityInstance> list);
  23 +
  24 + @Mappings({
  25 + @Mapping(source = "activityId", target = "key"),
  26 + @Mapping(source = "activityType", target = "type")
  27 + })
  28 + BpmActivityRespVO convert(HistoricActivityInstance bean);
  29 +
  30 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmActivityService.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.service.task;
2 2  
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity.BpmActivityRespVO;
  4 +
  5 +import java.util.List;
  6 +
3 7 /**
4 8 * BPM 活动实例 Service 接口
5 9 *
... ... @@ -8,6 +12,14 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.task;
8 12 public interface BpmActivityService {
9 13  
10 14 /**
  15 + * 获得指定流程实例的活动实例列表
  16 + *
  17 + * @param processInstanceId 流程实例的编号
  18 + * @return 活动实例列表
  19 + */
  20 + List<BpmActivityRespVO> getActivityListByProcessInstanceId(String processInstanceId);
  21 +
  22 + /**
11 23 * 生成指定流程实例的高亮流程图,只高亮进行中的任务
12 24 *
13 25 * 友情提示,非该方法的注释。如果想实现更高级的高亮流程图(当前节点红色 + 完成节点为绿色),可参考如下内容:
... ... @@ -17,7 +29,7 @@ public interface BpmActivityService {
17 29 *
18 30 * 如果你想实现高亮已完成的任务,可参考 https://blog.csdn.net/qiuxinfa123/article/details/119579863 博客。不过测试下来,貌似不太对~
19 31 *
20   - * @param processInstanceId 实例Id
  32 + * @param processInstanceId 流程实例的编号
21 33 * @return 图的字节数组
22 34 */
23 35 byte[] generateHighlightDiagram(String processInstanceId);
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmActivityServiceImpl.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.service.task.impl;
2 2  
3 3 import cn.hutool.core.io.IoUtil;
  4 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity.BpmActivityRespVO;
  5 +import cn.iocoder.yudao.adminserver.modules.bpm.convert.task.BpmActivityConvert;
  6 +import cn.iocoder.yudao.adminserver.modules.bpm.convert.task.BpmTaskConvert;
4 7 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
5 8 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmActivityService;
6 9 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
... ... @@ -11,6 +14,7 @@ import org.activiti.bpmn.model.BpmnModel;
11 14 import org.activiti.engine.HistoryService;
12 15 import org.activiti.engine.RepositoryService;
13 16 import org.activiti.engine.RuntimeService;
  17 +import org.activiti.engine.history.HistoricActivityInstance;
14 18 import org.activiti.engine.history.HistoricProcessInstance;
15 19 import org.activiti.engine.task.Task;
16 20 import org.activiti.image.ProcessDiagramGenerator;
... ... @@ -22,8 +26,7 @@ import java.io.InputStream;
22 26 import java.util.Collections;
23 27 import java.util.List;
24 28  
25   -import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_DEFINITION_BPMN_MODEL_NOT_EXISTS;
26   -import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS;
  29 +import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*;
27 30 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
28 31  
29 32 /**
... ... @@ -40,6 +43,8 @@ public class BpmActivityServiceImpl implements BpmActivityService {
40 43  
41 44 @Resource
42 45 private ProcessDiagramGenerator processDiagramGenerator;
  46 + @Resource
  47 + private HistoryService historyService;
43 48  
44 49 @Resource
45 50 private BpmProcessInstanceService processInstanceService;
... ... @@ -49,6 +54,13 @@ public class BpmActivityServiceImpl implements BpmActivityService {
49 54 private BpmTaskService taskService;
50 55  
51 56 @Override
  57 + public List<BpmActivityRespVO> getActivityListByProcessInstanceId(String processInstanceId) {
  58 + List<HistoricActivityInstance> activityList = historyService.createHistoricActivityInstanceQuery()
  59 + .processInstanceId(processInstanceId).list();
  60 + return BpmActivityConvert.INSTANCE.convertList(activityList);
  61 + }
  62 +
  63 + @Override
52 64 public byte[] generateHighlightDiagram(String processInstanceId) {
53 65 // 获得流程实例
54 66 HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId);
... ...
yudao-admin-ui/src/api/bpm/activity.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function getActivityList(query) {
  4 + return request({
  5 + url: '/bpm/activity/list',
  6 + method: 'get',
  7 + params: query
  8 + })
  9 +}
... ...
yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue
... ... @@ -82,24 +82,27 @@ export default {
82 82 },
83 83 /* 高亮流程图 */
84 84 async highlightDiagram() {
85   - if (this.tasks.length === 0) {
86   - return;
87   - }
88   - if (!this.bpmnModeler.getDefinitions().rootElements[0].flowElements) {
  85 + // let tasks = this.tasks.filter(task => {
  86 + // if (task.type !== 'sequenceFlow') { // 去除连线元素
  87 + // return true;
  88 + // }
  89 + // });
  90 + let tasks = this.tasks;
  91 + if (tasks.length === 0) {
89 92 return;
90 93 }
91 94 // 参考自 https://gitee.com/tony2y/RuoYi-flowable/blob/master/ruoyi-ui/src/components/Process/index.vue#L222 实现
92 95 let canvas = this.bpmnModeler.get('canvas');
93 96 this.bpmnModeler.getDefinitions().rootElements[0].flowElements?.forEach(n => {
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 + let completeTask = tasks.find(m => m.key === n.id)
  98 + let todoTask = tasks.find(m => !m.endTime)
  99 + let endTask = tasks[tasks.length - 1]
97 100 if (n.$type === 'bpmn:UserTask') { // 用户任务
98 101 if (completeTask) {
99 102 canvas.addMarker(n.id, completeTask.endTime ? 'highlight' : 'highlight-todo');
100 103 // console.log(n.id + ' : ' + (completeTask.endTime ? 'highlight' : 'highlight-todo'));
101 104 n.outgoing?.forEach(nn => {
102   - let targetTask = this.tasks.find(m => m.definitionKey === nn.targetRef.id)
  105 + let targetTask = tasks.find(m => m.key === nn.targetRef.id)
103 106 if (targetTask) {
104 107 canvas.addMarker(nn.id, targetTask.endTime ? 'highlight' : 'highlight-todo');
105 108 } else if (nn.targetRef.$type === 'bpmn:ExclusiveGateway') {
... ... @@ -107,7 +110,7 @@ export default {
107 110 canvas.addMarker(nn.id, completeTask.endTime ? 'highlight' : 'highlight-todo');
108 111 canvas.addMarker(nn.targetRef.id, completeTask.endTime ? 'highlight' : 'highlight-todo');
109 112 } else if (nn.targetRef.$type === 'bpmn:EndEvent') {
110   - if (!todoTask && endTask.definitionKey === n.id) {
  113 + if (!todoTask && endTask.key === n.id) {
111 114 canvas.addMarker(nn.id, 'highlight');
112 115 canvas.addMarker(nn.targetRef.id, 'highlight');
113 116 }
... ... @@ -120,7 +123,7 @@ export default {
120 123 }
121 124 } else if (n.$type === 'bpmn:ExclusiveGateway') { // 排它网关
122 125 n.outgoing?.forEach(nn => {
123   - let targetTask = this.tasks.find(m => m.definitionKey === nn.targetRef.id)
  126 + let targetTask = tasks.find(m => m.key === nn.targetRef.id)
124 127 if (targetTask) {
125 128 canvas.addMarker(nn.id, targetTask.endTime ? 'highlight' : 'highlight-todo');
126 129 }
... ... @@ -129,7 +132,7 @@ export default {
129 132 if (completeTask) {
130 133 canvas.addMarker(n.id, completeTask.endTime ? 'highlight' : 'highlight-todo')
131 134 n.outgoing?.forEach(nn => {
132   - const targetTask = this.taskList.find(m => m.definitionKey === nn.targetRef.id)
  135 + const targetTask = this.taskList.find(m => m.key === nn.targetRef.id)
133 136 if (targetTask) {
134 137 canvas.addMarker(nn.id, targetTask.endTime ? 'highlight' : 'highlight-todo')
135 138 canvas.addMarker(nn.targetRef.id, targetTask.endTime ? 'highlight' : 'highlight-todo')
... ... @@ -138,7 +141,7 @@ export default {
138 141 }
139 142 } else if (n.$type === 'bpmn:StartEvent') { // 开始节点
140 143 n.outgoing?.forEach(nn => {
141   - let completeTask = this.tasks.find(m => m.definitionKey === nn.targetRef.id)
  144 + let completeTask = tasks.find(m => m.key === nn.targetRef.id)
142 145 if (completeTask) {
143 146 canvas.addMarker(nn.id, 'highlight');
144 147 canvas.addMarker(n.id, 'highlight');
... ... @@ -146,7 +149,7 @@ export default {
146 149 }
147 150 });
148 151 } else if (n.$type === 'bpmn:EndEvent') { // 结束节点
149   - if (endTask.definitionKey === n.id && endTask.endTime) {
  152 + if (endTask.key === n.id && endTask.endTime) {
150 153 canvas.addMarker(n.id, 'highlight')
151 154 return
152 155 }
... ...
yudao-admin-ui/src/views/bpm/processInstance/detail.vue
... ... @@ -73,7 +73,7 @@
73 73 <div slot="header" class="clearfix">
74 74 <span class="el-icon-picture-outline">流程图</span>
75 75 </div>
76   - <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" :taskData="tasks" />
  76 + <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" :taskData="activityList" />
77 77 </el-card>
78 78  
79 79 <!-- 对话框(转派审批人) -->
... ... @@ -103,6 +103,7 @@ import {createProcessInstance, getProcessInstance} from &quot;@/api/bpm/processInstan
103 103 import {approveTask, getTaskListByProcessInstanceId, rejectTask, updateTaskAssignee} from "@/api/bpm/task";
104 104 import {getDate} from "@/utils/dateUtils";
105 105 import {listSimpleUsers} from "@/api/system/user";
  106 +import {getActivityList} from "@/api/bpm/activity";
106 107  
107 108 // 流程实例的详情页,可用于审批
108 109 export default {
... ... @@ -128,6 +129,7 @@ export default {
128 129 bpmnControlForm: {
129 130 prefix: "activiti"
130 131 },
  132 + activityList: [],
131 133  
132 134 // 审批记录
133 135 tasksLoad: true,
... ... @@ -196,12 +198,18 @@ export default {
196 198 if (val) {
197 199 item.__config__.defaultValue = val
198 200 }
199   - })
  201 + });
200 202  
201 203 // 加载流程图
202 204 getProcessDefinitionBpmnXML(this.processInstance.processDefinition.id).then(response => {
203 205 this.bpmnXML = response.data
204   - })
  206 + });
  207 + // 加载活动列表
  208 + getActivityList({
  209 + processInstanceId: this.processInstance.id
  210 + }).then(response => {
  211 + this.activityList = response.data;
  212 + });
205 213  
206 214 // 取消加载中
207 215 this.processInstanceLoading = false;
... ...