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

This commit is contained in:
YunaiV 2022-01-19 08:54:54 +08:00
parent 676e4f29d9
commit 8e18a63d34
8 changed files with 131 additions and 20 deletions

View File

@ -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 {

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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) {
// 获得流程实例

View File

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

View File

@ -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
}

View File

@ -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;