mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 02:08:43 +08:00 
			
		
		
		
	修改流程图的高亮实现,采用 activity 替代 task 作为数据源
This commit is contained in:
		| @@ -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 { | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
| } | ||||
| @@ -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); | ||||
|  | ||||
| } | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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
									
								
								yudao-admin-ui/src/api/bpm/activity.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								yudao-admin-ui/src/api/bpm/activity.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| import request from '@/utils/request' | ||||
|  | ||||
| export function getActivityList(query) { | ||||
|   return request({ | ||||
|     url: '/bpm/activity/list', | ||||
|     method: 'get', | ||||
|     params: query | ||||
|   }) | ||||
| } | ||||
| @@ -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 | ||||
|           } | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV