Browse Source

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

YunaiV 3 years ago
parent
commit
8e18a63d34

+ 15 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmActivityController.java

@@ -1,7 +1,9 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.controller.task;
 
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity.BpmActivityRespVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmActivityService;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
@@ -15,6 +17,9 @@ import org.springframework.web.bind.annotation.RestController;
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
 @Api(tags = "流程活动实例")
 @RestController
@@ -25,11 +30,20 @@ public class BpmActivityController {
     @Resource
     private BpmActivityService activityService;
 
-    // TODO 芋艿:注解、权限、validtion
+    // TODO 芋艿:权限
 
+    @GetMapping("/list")
     @ApiOperation(value = "生成指定流程实例的高亮流程图",
             notes = "只高亮进行中的任务。不过要注意,该接口暂时没用,通过前端的 ProcessViewer.vue 界面的 highlightDiagram 方法生成")
+    @ApiImplicitParam(name = "id", value = "流程实例的编号", required = true, dataTypeClass = String.class)
+    public CommonResult<List<BpmActivityRespVO>> getActivityList(
+            @RequestParam("processInstanceId") String processInstanceId) {
+        return success(activityService.getActivityListByProcessInstanceId(processInstanceId));
+    }
+
     @GetMapping("/generate-highlight-diagram")
+    @ApiOperation(value = "生成指定流程实例的高亮流程图",
+            notes = "只高亮进行中的任务。不过要注意,该接口暂时没用,通过前端的 ProcessViewer.vue 界面的 highlightDiagram 方法生成")
     @ApiImplicitParam(name = "id", value = "流程实例的编号", required = true, dataTypeClass = String.class)
     public void generateHighlightDiagram(@RequestParam("processInstanceId") String processInstanceId,
                                          HttpServletResponse response) throws IOException {

+ 23 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/activity/BpmActivityRespVO.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@ApiModel("流程活动的 Response VO")
+@Data
+public class BpmActivityRespVO {
+
+    @ApiModelProperty(value = "流程活动的标识", required = true, example = "1024")
+    private String key;
+    @ApiModelProperty(value = "流程活动的类型", required = true, example = "StartEvent")
+    private String type;
+
+    @ApiModelProperty(value = "流程活动的开始时间", required = true)
+    private Date startTime;
+    @ApiModelProperty(value = "流程活动的结束时间", required = true)
+    private Date endTime;
+
+}

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

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.convert.task;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity.BpmActivityRespVO;
+import org.activiti.engine.history.HistoricActivityInstance;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+/**
+ * BPM 活动 Convert
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface BpmActivityConvert {
+
+    BpmActivityConvert INSTANCE = Mappers.getMapper(BpmActivityConvert.class);
+
+    List<BpmActivityRespVO> convertList(List<HistoricActivityInstance> list);
+
+    @Mappings({
+            @Mapping(source = "activityId", target = "key"),
+            @Mapping(source = "activityType", target = "type")
+    })
+    BpmActivityRespVO convert(HistoricActivityInstance bean);
+
+}

+ 13 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmActivityService.java

@@ -1,5 +1,9 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.service.task;
 
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity.BpmActivityRespVO;
+
+import java.util.List;
+
 /**
  * BPM 活动实例 Service 接口
  *
@@ -7,6 +11,14 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.task;
  */
 public interface BpmActivityService {
 
+    /**
+     * 获得指定流程实例的活动实例列表
+     *
+     * @param processInstanceId 流程实例的编号
+     * @return 活动实例列表
+     */
+    List<BpmActivityRespVO> getActivityListByProcessInstanceId(String processInstanceId);
+
     /**
      * 生成指定流程实例的高亮流程图,只高亮进行中的任务
      *
@@ -17,7 +29,7 @@ public interface BpmActivityService {
      *
      * 如果你想实现高亮已完成的任务,可参考 https://blog.csdn.net/qiuxinfa123/article/details/119579863 博客。不过测试下来,貌似不太对~
      *
-     * @param processInstanceId 实例Id
+     * @param processInstanceId 流程实例的编号
      * @return 图的字节数组
      */
     byte[] generateHighlightDiagram(String processInstanceId);

+ 14 - 2
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmActivityServiceImpl.java

@@ -1,6 +1,9 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.service.task.impl;
 
 import cn.hutool.core.io.IoUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity.BpmActivityRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.task.BpmActivityConvert;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.task.BpmTaskConvert;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmActivityService;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
@@ -11,6 +14,7 @@ import org.activiti.bpmn.model.BpmnModel;
 import org.activiti.engine.HistoryService;
 import org.activiti.engine.RepositoryService;
 import org.activiti.engine.RuntimeService;
+import org.activiti.engine.history.HistoricActivityInstance;
 import org.activiti.engine.history.HistoricProcessInstance;
 import org.activiti.engine.task.Task;
 import org.activiti.image.ProcessDiagramGenerator;
@@ -22,8 +26,7 @@ import java.io.InputStream;
 import java.util.Collections;
 import java.util.List;
 
-import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_DEFINITION_BPMN_MODEL_NOT_EXISTS;
-import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS;
+import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*;
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 
 /**
@@ -40,6 +43,8 @@ public class BpmActivityServiceImpl implements BpmActivityService {
 
     @Resource
     private ProcessDiagramGenerator processDiagramGenerator;
+    @Resource
+    private HistoryService historyService;
 
     @Resource
     private BpmProcessInstanceService processInstanceService;
@@ -48,6 +53,13 @@ public class BpmActivityServiceImpl implements BpmActivityService {
     @Resource
     private BpmTaskService taskService;
 
+    @Override
+    public List<BpmActivityRespVO> getActivityListByProcessInstanceId(String processInstanceId) {
+        List<HistoricActivityInstance> activityList = historyService.createHistoricActivityInstanceQuery()
+                .processInstanceId(processInstanceId).list();
+        return BpmActivityConvert.INSTANCE.convertList(activityList);
+    }
+
     @Override
     public byte[] generateHighlightDiagram(String processInstanceId) {
         // 获得流程实例

+ 9 - 0
yudao-admin-ui/src/api/bpm/activity.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function getActivityList(query) {
+  return request({
+    url: '/bpm/activity/list',
+    method: 'get',
+    params: query
+  })
+}

+ 16 - 13
yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue

@@ -82,24 +82,27 @@ export default {
     },
     /* 高亮流程图 */
     async highlightDiagram() {
-      if (this.tasks.length === 0) {
-        return;
-      }
-      if (!this.bpmnModeler.getDefinitions().rootElements[0].flowElements) {
+      // let tasks = this.tasks.filter(task => {
+      //   if (task.type !== 'sequenceFlow') { // 去除连线元素
+      //     return true;
+      //   }
+      // });
+      let tasks = this.tasks;
+      if (tasks.length === 0) {
         return;
       }
       // 参考自 https://gitee.com/tony2y/RuoYi-flowable/blob/master/ruoyi-ui/src/components/Process/index.vue#L222 实现
       let canvas = this.bpmnModeler.get('canvas');
       this.bpmnModeler.getDefinitions().rootElements[0].flowElements?.forEach(n => {
-        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]
+        let completeTask = tasks.find(m => m.key === n.id)
+        let todoTask = tasks.find(m => !m.endTime)
+        let endTask = tasks[tasks.length - 1]
         if (n.$type === 'bpmn:UserTask') { // 用户任务
           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)
+              let targetTask = tasks.find(m => m.key === nn.targetRef.id)
               if (targetTask) {
                 canvas.addMarker(nn.id, targetTask.endTime ? 'highlight' : 'highlight-todo');
               } else if (nn.targetRef.$type === 'bpmn:ExclusiveGateway') {
@@ -107,7 +110,7 @@ export default {
                 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) {
+                if (!todoTask && endTask.key === n.id) {
                   canvas.addMarker(nn.id, 'highlight');
                   canvas.addMarker(nn.targetRef.id, 'highlight');
                 }
@@ -120,7 +123,7 @@ export default {
           }
         } else if (n.$type === 'bpmn:ExclusiveGateway') { // 排它网关
           n.outgoing?.forEach(nn => {
-            let targetTask = this.tasks.find(m => m.definitionKey === nn.targetRef.id)
+            let targetTask = tasks.find(m => m.key === nn.targetRef.id)
             if (targetTask) {
               canvas.addMarker(nn.id, targetTask.endTime ? 'highlight' : 'highlight-todo');
             }
@@ -129,7 +132,7 @@ export default {
           if (completeTask) {
             canvas.addMarker(n.id, completeTask.endTime ? 'highlight' : 'highlight-todo')
             n.outgoing?.forEach(nn => {
-              const targetTask = this.taskList.find(m => m.definitionKey === nn.targetRef.id)
+              const targetTask = this.taskList.find(m => m.key === nn.targetRef.id)
               if (targetTask) {
                 canvas.addMarker(nn.id, targetTask.endTime ? 'highlight' : 'highlight-todo')
                 canvas.addMarker(nn.targetRef.id, targetTask.endTime ? 'highlight' : 'highlight-todo')
@@ -138,7 +141,7 @@ export default {
           }
         } else if (n.$type === 'bpmn:StartEvent') { // 开始节点
           n.outgoing?.forEach(nn => {
-            let completeTask = this.tasks.find(m => m.definitionKey === nn.targetRef.id)
+            let completeTask = tasks.find(m => m.key === nn.targetRef.id)
             if (completeTask) {
               canvas.addMarker(nn.id, 'highlight');
               canvas.addMarker(n.id, 'highlight');
@@ -146,7 +149,7 @@ export default {
             }
           });
         } else if (n.$type === 'bpmn:EndEvent') { // 结束节点
-          if (endTask.definitionKey === n.id && endTask.endTime) {
+          if (endTask.key === n.id && endTask.endTime) {
             canvas.addMarker(n.id, 'highlight')
             return
           }

+ 11 - 3
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" :taskData="tasks" />
+      <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" :taskData="activityList" />
     </el-card>
 
     <!-- 对话框(转派审批人) -->
@@ -103,6 +103,7 @@ import {createProcessInstance, getProcessInstance} from "@/api/bpm/processInstan
 import {approveTask, getTaskListByProcessInstanceId, rejectTask, updateTaskAssignee} from "@/api/bpm/task";
 import {getDate} from "@/utils/dateUtils";
 import {listSimpleUsers} from "@/api/system/user";
+import {getActivityList} from "@/api/bpm/activity";
 
 // 流程实例的详情页,可用于审批
 export default {
@@ -128,6 +129,7 @@ export default {
       bpmnControlForm: {
         prefix: "activiti"
       },
+      activityList: [],
 
       // 审批记录
       tasksLoad: true,
@@ -196,12 +198,18 @@ export default {
           if (val) {
             item.__config__.defaultValue = val
           }
-        })
+        });
 
         // 加载流程图
         getProcessDefinitionBpmnXML(this.processInstance.processDefinition.id).then(response => {
           this.bpmnXML = response.data
-        })
+        });
+        // 加载活动列表
+        getActivityList({
+          processInstanceId: this.processInstance.id
+        }).then(response => {
+          this.activityList = response.data;
+        });
 
         // 取消加载中
         this.processInstanceLoading = false;