diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmActivityController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmActivityController.java index 15931ffaa..b348603c3 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmActivityController.java +++ b/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> 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 { 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 new file mode 100644 index 000000000..afde11cb8 --- /dev/null +++ b/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; + +} 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 new file mode 100644 index 000000000..a9882f960 --- /dev/null +++ b/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 convertList(List list); + + @Mappings({ + @Mapping(source = "activityId", target = "key"), + @Mapping(source = "activityType", target = "type") + }) + BpmActivityRespVO convert(HistoricActivityInstance bean); + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmActivityService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmActivityService.java index 3fa4a5acc..8fb15f5ba 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmActivityService.java +++ b/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 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); 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 299b4a980..a4d834a9f 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 @@ -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 getActivityListByProcessInstanceId(String processInstanceId) { + List activityList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId).list(); + return BpmActivityConvert.INSTANCE.convertList(activityList); + } + @Override public byte[] generateHighlightDiagram(String processInstanceId) { // 获得流程实例 diff --git a/yudao-admin-ui/src/api/bpm/activity.js b/yudao-admin-ui/src/api/bpm/activity.js new file mode 100644 index 000000000..8f1241ed6 --- /dev/null +++ b/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 + }) +} 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 9bd1dd3b0..b37ee8ab6 100644 --- a/yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue +++ b/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 } diff --git a/yudao-admin-ui/src/views/bpm/processInstance/detail.vue b/yudao-admin-ui/src/views/bpm/processInstance/detail.vue index 9f3f7e5b4..433bd6b2b 100644 --- a/yudao-admin-ui/src/views/bpm/processInstance/detail.vue +++ b/yudao-admin-ui/src/views/bpm/processInstance/detail.vue @@ -73,7 +73,7 @@
流程图
- + @@ -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;