diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/activity/BpmActivityRespVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/activity/BpmActivityRespVO.java index afde11cb8..4da7519a4 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/activity/BpmActivityRespVO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/activity/BpmActivityRespVO.java @@ -20,4 +20,20 @@ public class BpmActivityRespVO { @ApiModelProperty(value = "流程活动的结束时间", required = true) private Date endTime; + /** + * 关联的流程任务,只有 UserTask 类型才有 + */ + private Task task; + + @ApiModel(value = "流程任务") + @Data + public static class Task { + + @ApiModelProperty(value = "关联的流程任务的编号", required = true, example = "2048") + private String id; + @ApiModelProperty(value = "关联的流程任务的结果", required = true, example = "2", notes = "参见 bpm_process_instance_result 枚举") + private Integer result; + + } + } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmActivityConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmActivityConvert.java index a9882f960..8e9b1a9b3 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmActivityConvert.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmActivityConvert.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.adminserver.modules.bpm.convert.task; import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity.BpmActivityRespVO; +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import org.activiti.engine.history.HistoricActivityInstance; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -8,6 +10,7 @@ import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; import java.util.List; +import java.util.Map; /** * BPM 活动 Convert @@ -19,7 +22,16 @@ public interface BpmActivityConvert { BpmActivityConvert INSTANCE = Mappers.getMapper(BpmActivityConvert.class); - List convertList(List list); + default List convertList(List list, Map taskExtMap) { + return CollectionUtils.convertList(list, bean -> { + BpmActivityRespVO respVO = convert(bean); + BpmTaskExtDO taskExt = taskExtMap.get(bean.getTaskId()); + if (taskExt != null) { + respVO.setTask(new BpmActivityRespVO.Task().setId(taskExt.getTaskId()).setResult(taskExt.getResult())); + } + return respVO; + }); + } @Mappings({ @Mapping(source = "activityId", target = "key"), diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/BpmTaskExtDO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/BpmTaskExtDO.java index 454b2c803..e3b31ec33 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/BpmTaskExtDO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/BpmTaskExtDO.java @@ -46,6 +46,12 @@ public class BpmTaskExtDO extends BaseDO { * 关联 {@link Task#getId()} */ private String taskId; +// /** +// * 任务的标识 +// * +// * 关联 {@link Task#getTaskDefinitionKey()} +// */ +// private String definitionKey; /** * 任务的结果 * diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/task/BpmTaskExtMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/task/BpmTaskExtMapper.java index a71f06151..e0c8d4726 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/task/BpmTaskExtMapper.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/task/BpmTaskExtMapper.java @@ -19,4 +19,7 @@ public interface BpmTaskExtMapper extends BaseMapperX { return selectList("task_id", taskIds); } + default List selectListByProcessInstanceId(String processInstanceId) { + return selectList("process_instance_id", processInstanceId); + } } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java index 383c124e4..47ee36bc8 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.task; import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.*; +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import org.activiti.engine.task.Task; @@ -139,4 +140,12 @@ public interface BpmTaskService { */ void updateTaskExtComplete(org.activiti.api.task.model.Task task); + /** + * 获得流程实例对应的 Task 拓展列表 + * + * @param processInstanceId 流程实例的编号 + * @return Task 拓展列表 + */ + List getTaskExtListByProcessInstanceId(String processInstanceId); + } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmActivityServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmActivityServiceImpl.java index a4d834a9f..8d4187b3a 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmActivityServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmActivityServiceImpl.java @@ -4,6 +4,7 @@ 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.dal.dataobject.task.BpmTaskExtDO; 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; @@ -25,9 +26,11 @@ import javax.annotation.Resource; import java.io.InputStream; import java.util.Collections; import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * BPM 活动实例 Service 实现类 @@ -57,7 +60,10 @@ public class BpmActivityServiceImpl implements BpmActivityService { public List getActivityListByProcessInstanceId(String processInstanceId) { List activityList = historyService.createHistoricActivityInstanceQuery() .processInstanceId(processInstanceId).list(); - return BpmActivityConvert.INSTANCE.convertList(activityList); + // 拼接数据 + List taskExts = taskService.getTaskExtListByProcessInstanceId(processInstanceId); + Map taskExtMap = convertMap(taskExts, BpmTaskExtDO::getTaskId); + return BpmActivityConvert.INSTANCE.convertList(activityList, taskExtMap); } @Override diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java index e199eba63..2135a8ce2 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.task.impl; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.*; import cn.iocoder.yudao.adminserver.modules.bpm.convert.task.BpmTaskConvert; @@ -16,36 +15,23 @@ import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService; import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; import cn.iocoder.yudao.framework.activiti.core.util.ActivitiUtils; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import lombok.extern.slf4j.Slf4j; -import org.activiti.bpmn.constants.BpmnXMLConstants; -import org.activiti.bpmn.model.BpmnModel; -import org.activiti.bpmn.model.FlowNode; -import org.activiti.bpmn.model.SequenceFlow; import org.activiti.engine.HistoryService; -import org.activiti.engine.RepositoryService; -import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; -import org.activiti.engine.history.HistoricActivityInstance; import org.activiti.engine.history.HistoricProcessInstance; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.history.HistoricTaskInstanceQuery; -import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.activiti.engine.task.TaskQuery; -import org.activiti.image.ProcessDiagramGenerator; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.ObjectUtils; import javax.annotation.Resource; import javax.validation.Valid; -import java.io.IOException; -import java.io.InputStream; import java.util.*; import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*; @@ -307,4 +293,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskExtMapper.updateByTaskId(taskExtDO); } + @Override + public List getTaskExtListByProcessInstanceId(String processInstanceId) { + return taskExtMapper.selectListByProcessInstanceId(processInstanceId); + } + } diff --git a/yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue b/yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue index b37ee8ab6..a1546e92d 100644 --- a/yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue +++ b/yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue @@ -82,55 +82,63 @@ export default { }, /* 高亮流程图 */ async highlightDiagram() { - // let tasks = this.tasks.filter(task => { - // if (task.type !== 'sequenceFlow') { // 去除连线元素 - // return true; - // } - // }); - let tasks = this.tasks; - if (tasks.length === 0) { + let activityList = this.tasks; + if (activityList.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'); + let todoActivity = activityList.find(m => !m.endTime) // 找到待办的任务 + let endActivity = activityList[activityList.length - 1] // 找到结束任务 this.bpmnModeler.getDefinitions().rootElements[0].flowElements?.forEach(n => { - let completeTask = tasks.find(m => m.key === n.id) - let todoTask = tasks.find(m => !m.endTime) - let endTask = tasks[tasks.length - 1] + let activity = activityList.find(m => m.key === n.id) // 找到对应的活动 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 = 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') { - // canvas.addMarker(nn.id, 'highlight'); - 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.key === n.id) { - canvas.addMarker(nn.id, 'highlight'); - canvas.addMarker(nn.targetRef.id, 'highlight'); - } - if (!completeTask.endTime) { - canvas.addMarker(nn.id, 'highlight-todo'); - canvas.addMarker(nn.targetRef.id, 'highlight-todo'); - } - } - }); + if (!activity) { + return; } + if (activity.task) { + const result = activity.task.result; + if (result === 1) { + canvas.addMarker(n.id, 'highlight-todo'); + } else if (result === 2) { + canvas.addMarker(n.id, 'highlight'); + } else if (result === 3) { + canvas.addMarker(n.id, 'highlight-reject'); + } else if (result === 4) { + canvas.addMarker(n.id, 'highlight-cancel'); + } + } + + n.outgoing?.forEach(nn => { + let targetTask = activityList.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') { + // canvas.addMarker(nn.id, 'highlight'); + canvas.addMarker(nn.id, activity.endTime ? 'highlight' : 'highlight-todo'); + canvas.addMarker(nn.targetRef.id, activity.endTime ? 'highlight' : 'highlight-todo'); + } else if (nn.targetRef.$type === 'bpmn:EndEvent') { + if (!todoActivity && endActivity.key === n.id) { + canvas.addMarker(nn.id, 'highlight'); + canvas.addMarker(nn.targetRef.id, 'highlight'); + } + if (!activity.endTime) { + canvas.addMarker(nn.id, 'highlight-todo'); + canvas.addMarker(nn.targetRef.id, 'highlight-todo'); + } + } + }); } else if (n.$type === 'bpmn:ExclusiveGateway') { // 排它网关 n.outgoing?.forEach(nn => { - let targetTask = tasks.find(m => m.key === nn.targetRef.id) + let targetTask = activityList.find(m => m.key === nn.targetRef.id) if (targetTask) { canvas.addMarker(nn.id, targetTask.endTime ? 'highlight' : 'highlight-todo'); } }) } else if (n.$type === 'bpmn:ParallelGateway') { // 并行网关 - if (completeTask) { - canvas.addMarker(n.id, completeTask.endTime ? 'highlight' : 'highlight-todo') + if (activity) { + canvas.addMarker(n.id, activity.endTime ? 'highlight' : 'highlight-todo') n.outgoing?.forEach(nn => { const targetTask = this.taskList.find(m => m.key === nn.targetRef.id) if (targetTask) { @@ -140,18 +148,21 @@ export default { }) } } else if (n.$type === 'bpmn:StartEvent') { // 开始节点 - n.outgoing?.forEach(nn => { - let completeTask = tasks.find(m => m.key === nn.targetRef.id) - if (completeTask) { + n.outgoing?.forEach(nn => { // outgoing 例如说【bpmn:SequenceFlow】连线 + let fromTask = activityList.find(m => m.key === nn.targetRef.id) + if (fromTask) { canvas.addMarker(nn.id, 'highlight'); canvas.addMarker(n.id, 'highlight'); - return } }); } else if (n.$type === 'bpmn:EndEvent') { // 结束节点 - if (endTask.key === n.id && endTask.endTime) { - canvas.addMarker(n.id, 'highlight') - return + if (endActivity.key !== n.id) { // 保证 endActivity 就是 EndEvent + return; + } + // 在并行网关后,跟着多个任务,如果其中一个任务完成,endActivity 的 endTime 就会存在值 + // 所以,通过 todoActivity 在做一次判断 + if (endActivity.endTime && !todoActivity) { + canvas.addMarker(n.id, 'highlight'); } } }) @@ -162,6 +173,7 @@ export default {