Commit 8e18a63d340891a27be24adf90723e838a7cee9f
1 parent
676e4f29
修改流程图的高亮实现,采用 activity 替代 task 作为数据源
Showing
8 changed files
with
131 additions
and
20 deletions
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
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 "@/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; | ... | ... |