diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/controller/FlowTaskController.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/controller/FlowTaskController.java index 4952851..3c15ca2 100644 --- a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/controller/FlowTaskController.java +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/controller/FlowTaskController.java @@ -36,7 +36,7 @@ public class FlowTaskController { @ApiOperation(value = "我发起的流程", response = FlowTaskDto.class) @GetMapping(value = "/myProcess") public AjaxResult myProcess(@ApiParam(value = "当前页码", required = true) @RequestParam Integer pageNum, - @ApiParam(value = "每页条数", required = true) @RequestParam Integer pageSize) { + @ApiParam(value = "每页条数", required = true) @RequestParam Integer pageSize) { return flowTaskService.myProcess(pageNum, pageSize); } @@ -69,20 +69,20 @@ public class FlowTaskController { @ApiOperation(value = "流程历史流转记录", response = FlowTaskDto.class) @GetMapping(value = "/flowRecord") - public AjaxResult flowRecord(String procInsId,String deployId) { - return flowTaskService.flowRecord(procInsId,deployId); + public AjaxResult flowRecord(String procInsId, String deployId) { + return flowTaskService.flowRecord(procInsId, deployId); } @ApiOperation(value = "获取流程变量", response = FlowTaskDto.class) @GetMapping(value = "/processVariables/{taskId}") - public AjaxResult processVariables(@ApiParam(value = "流程任务Id") @PathVariable(value = "taskId") String taskId) { + public AjaxResult processVariables(@ApiParam(value = "流程任务Id") @PathVariable(value = "taskId") String taskId) { return flowTaskService.processVariables(taskId); } @ApiOperation(value = "审批任务") @PostMapping(value = "/complete") public AjaxResult complete(@RequestBody FlowTaskVo flowTaskVo) { - return flowTaskService.complete(flowTaskVo); + return flowTaskService.complete(flowTaskVo); } @ApiOperation(value = "驳回任务") @@ -154,7 +154,7 @@ public class FlowTaskController { @RequestMapping("/diagram/{processId}") public void genProcessDiagram(HttpServletResponse response, @PathVariable("processId") String processId) { - InputStream inputStream = flowTaskService.diagram(processId); + InputStream inputStream = flowTaskService.diagram(processId); OutputStream os = null; BufferedImage image = null; try { @@ -164,9 +164,9 @@ public class FlowTaskController { if (image != null) { ImageIO.write(image, "png", os); } - }catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); - }finally { + } finally { try { if (os != null) { os.flush(); @@ -181,10 +181,12 @@ public class FlowTaskController { /** * 生成流程图 * - * @param procInsId 任务ID + * @param procInsId 流程实例编号 + * @param procInsId 任务执行编号 */ - @RequestMapping("/flowViewer/{procInsId}") - public AjaxResult getFlowViewer(@PathVariable("procInsId") String procInsId) { - return flowTaskService.getFlowViewer(procInsId); + @RequestMapping("/flowViewer/{procInsId}/{executionId}") + public AjaxResult getFlowViewer(@PathVariable("procInsId") String procInsId, + @PathVariable("executionId") String executionId) { + return flowTaskService.getFlowViewer(procInsId, executionId); } } diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/domain/dto/FlowTaskDto.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/domain/dto/FlowTaskDto.java index 86ec8ce..4985379 100644 --- a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/domain/dto/FlowTaskDto.java +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/domain/dto/FlowTaskDto.java @@ -26,6 +26,9 @@ public class FlowTaskDto implements Serializable { @ApiModelProperty("任务编号") private String taskId; + @ApiModelProperty("任务执行编号") + private String executionId; + @ApiModelProperty("任务名称") private String taskName; diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/domain/dto/FlowViewerDto.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/domain/dto/FlowViewerDto.java index 29b4776..b63ee0e 100644 --- a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/domain/dto/FlowViewerDto.java +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/domain/dto/FlowViewerDto.java @@ -11,6 +11,13 @@ import java.io.Serializable; @Data public class FlowViewerDto implements Serializable { + /** + * 流程key + */ private String key; + + /** + * 是否完成(已经审批) + */ private boolean completed; } diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/flow/FlowableUtils.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/flow/FlowableUtils.java index 21c2026..82509bd 100644 --- a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/flow/FlowableUtils.java +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/flow/FlowableUtils.java @@ -129,7 +129,7 @@ public class FlowableUtils { /** * 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找 - * @param source 起始节点 + * @param source 起始节点(退回节点) * @param runTaskKeyList 正在运行的任务 Key,用于校验任务节点是否是正在运行的节点 * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 * @param userTaskList 需要撤回的用户任务列表 @@ -323,7 +323,7 @@ public class FlowableUtils { */ public static Boolean dirtyTargetInChildProcess(FlowElement source, Set hasSequenceFlow, List targets, Boolean inChildProcess) { hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; - inChildProcess = inChildProcess == null ? false : inChildProcess; + inChildProcess = inChildProcess != null && inChildProcess; // 根据类型,获取出口连线 List sequenceFlows = getElementOutgoingFlows(source); @@ -363,7 +363,7 @@ public class FlowableUtils { * @return */ public static Boolean iteratorCheckSequentialReferTarget(FlowElement source, String targetKsy, Set hasSequenceFlow, Boolean isSequential) { - isSequential = isSequential == null ? true : isSequential; + isSequential = isSequential == null || isSequential; hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 @@ -384,7 +384,7 @@ public class FlowableUtils { // 添加已经走过的连线 hasSequenceFlow.add(sequenceFlow.getId()); // 如果目标节点已被判断为并行,后面都不需要执行,直接返回 - if (isSequential == false) { + if (!isSequential) { break; } // 这条线路存在目标节点,这条线路完成,进入下个线路 @@ -464,7 +464,7 @@ public class FlowableUtils { }); // 循环放入栈,栈 LIFO:后进先出 Stack stack = new Stack<>(); - historicTaskInstanceList.forEach(item -> stack.push(item)); + historicTaskInstanceList.forEach(stack::push); // 清洗后的历史任务实例 List lastHistoricTaskInstanceList = new ArrayList<>(); // 网关存在可能只走了部分分支情况,且还存在跳转废弃数据以及其他分支数据的干扰,因此需要对历史节点数据进行清洗 @@ -492,14 +492,14 @@ public class FlowableUtils { } // 删除原因不为空,说明从这条数据开始回跳或者回退的 // MI_END:会签完成后,其他未签到节点的删除原因,不在处理范围内 - if (stack.peek().getDeleteReason() != null && !stack.peek().getDeleteReason().equals("MI_END")) { + if (stack.peek().getDeleteReason() != null && !"MI_END".equals(stack.peek().getDeleteReason())) { // 可以理解为脏线路起点 String dirtyPoint = ""; - if (stack.peek().getDeleteReason().indexOf("Change activity to ") >= 0) { + if (stack.peek().getDeleteReason().contains("Change activity to ")) { dirtyPoint = stack.peek().getDeleteReason().replace("Change activity to ", ""); } // 会签回退删除原因有点不同 - if (stack.peek().getDeleteReason().indexOf("Change parent activity to ") >= 0) { + if (stack.peek().getDeleteReason().contains("Change parent activity to ")) { dirtyPoint = stack.peek().getDeleteReason().replace("Change parent activity to ", ""); } FlowElement dirtyTask = null; diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/service/IFlowTaskService.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/service/IFlowTaskService.java index e80ab3d..74035f4 100644 --- a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/service/IFlowTaskService.java +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/service/IFlowTaskService.java @@ -149,7 +149,7 @@ public interface IFlowTaskService { * @param procInsId * @return */ - AjaxResult getFlowViewer(String procInsId); + AjaxResult getFlowViewer(String procInsId,String executionId); /** * 获取流程变量 diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/service/impl/FlowTaskServiceImpl.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/service/impl/FlowTaskServiceImpl.java index 003ae89..69089fb 100644 --- a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/service/impl/FlowTaskServiceImpl.java +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/service/impl/FlowTaskServiceImpl.java @@ -32,12 +32,15 @@ import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; import org.flowable.common.engine.api.FlowableException; import org.flowable.common.engine.api.FlowableObjectNotFoundException; +import org.flowable.common.engine.api.query.QueryProperty; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.engine.ProcessEngineConfiguration; import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; +import org.flowable.engine.impl.ActivityInstanceQueryProperty; import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ActivityInstance; import org.flowable.engine.runtime.Execution; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.task.Comment; @@ -57,6 +60,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * @author XuanXuan @@ -109,7 +113,7 @@ public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTask @Override public void taskReject(FlowTaskVo flowTaskVo) { if (taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult().isSuspended()) { - throw new CustomException("任务处于挂起状态"); + throw new CustomException("任务处于挂起状态!"); } // 当前任务 task Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); @@ -288,9 +292,7 @@ public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTask } })); // 设置回退意见 - for (String currentTaskId : currentTaskIds) { - taskService.addComment(currentTaskId, task.getProcessInstanceId(), FlowComment.REBACK.getType(), flowTaskVo.getComment()); - } + currentTaskIds.forEach(currentTaskId -> taskService.addComment(currentTaskId, task.getProcessInstanceId(), FlowComment.REBACK.getType(), flowTaskVo.getComment())); try { // 1 对 1 或 多 对 1 情况,currentIds 当前要跳转的节点列表(1或多),targetKey 跳转到的节点(1) @@ -583,6 +585,7 @@ public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTask flowTask.setTaskDefKey(task.getTaskDefinitionKey()); flowTask.setCreateTime(task.getCreateTime()); flowTask.setProcDefId(task.getProcessDefinitionId()); + flowTask.setExecutionId(task.getExecutionId()); flowTask.setTaskName(task.getName()); // 流程定义信息 ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() @@ -818,22 +821,39 @@ public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTask /** * 获取流程执行过程 * - * @param procInsId + * @param procInsId 流程实例id * @return */ @Override - public AjaxResult getFlowViewer(String procInsId) { + public AjaxResult getFlowViewer(String procInsId, String executionId) { List flowViewerList = new ArrayList<>(); FlowViewerDto flowViewerDto; - // 获得活动的节点 - List hisActIns = historyService.createHistoricActivityInstanceQuery() + // 获取任务开始节点(临时处理方式) + List startNodeList = historyService.createHistoricActivityInstanceQuery() .processInstanceId(procInsId) .orderByHistoricActivityInstanceStartTime() + .asc().listPage(0,3); + for (HistoricActivityInstance startInstance : startNodeList) { + if (!"sequenceFlow".equals(startInstance.getActivityType())) { + flowViewerDto = new FlowViewerDto(); + if (!"sequenceFlow".equals(startInstance.getActivityType())) { + flowViewerDto.setKey(startInstance.getActivityId()); + // 根据流程节点处理时间校验改节点是否已完成 + flowViewerDto.setCompleted(!Objects.isNull(startInstance.getEndTime())); + flowViewerList.add(flowViewerDto); + } + } + } + // 历史节点 + List hisActIns = historyService.createHistoricActivityInstanceQuery() + .executionId(executionId) + .orderByHistoricActivityInstanceStartTime() .asc().list(); for (HistoricActivityInstance activityInstance : hisActIns) { if (!"sequenceFlow".equals(activityInstance.getActivityType())) { flowViewerDto = new FlowViewerDto(); flowViewerDto.setKey(activityInstance.getActivityId()); + // 根据流程节点处理时间校验改节点是否已完成 flowViewerDto.setCompleted(!Objects.isNull(activityInstance.getEndTime())); flowViewerList.add(flowViewerDto); } diff --git a/ruoyi-ui/src/api/flowable/definition.js b/ruoyi-ui/src/api/flowable/definition.js index d1ad9d0..9041c34 100644 --- a/ruoyi-ui/src/api/flowable/definition.js +++ b/ruoyi-ui/src/api/flowable/definition.js @@ -10,7 +10,7 @@ export function listDefinition(query) { } // 部署流程实例 -export function definitionStart(procDefId,data) { +export function definitionStart(procDefId, data) { return request({ url: '/flowable/definition/start/' + procDefId, method: 'post', @@ -60,6 +60,7 @@ export function readXml(deployId) { method: 'get' }) } + // 读取image文件 export function readImage(deployId) { return request({ @@ -69,9 +70,9 @@ export function readImage(deployId) { } // 读取image文件 -export function getFlowViewer(procInsId) { +export function getFlowViewer(procInsId, executionId) { return request({ - url: '/flowable/task/flowViewer/' + procInsId, + url: '/flowable/task/flowViewer/' + procInsId + '/' + executionId, method: 'get' }) } diff --git a/ruoyi-ui/src/views/flowable/task/record/flowview.vue b/ruoyi-ui/src/views/flowable/task/record/flowview.vue index 6912a02..e306487 100644 --- a/ruoyi-ui/src/views/flowable/task/record/flowview.vue +++ b/ruoyi-ui/src/views/flowable/task/record/flowview.vue @@ -56,10 +56,10 @@ export default { async getImg(xmlUrl) { const self = this try { - await this.bpmnViewer.importXML(xmlUrl); - this.fitViewport() - if (this.taskList !==undefined && this.taskList.length > 0 ) { - this.fillColor() + await self.bpmnViewer.importXML(xmlUrl); + self.fitViewport() + if (self.taskList !==undefined && self.taskList.length > 0 ) { + self.fillColor() } } catch (err) { console.error(err.message, err.warnings) diff --git a/ruoyi-ui/src/views/flowable/task/record/index.vue b/ruoyi-ui/src/views/flowable/task/record/index.vue index edefcd4..90ace8c 100644 --- a/ruoyi-ui/src/views/flowable/task/record/index.vue +++ b/ruoyi-ui/src/views/flowable/task/record/index.vue @@ -276,11 +276,12 @@ export default { this.taskForm.deployId = this.$route.query && this.$route.query.deployId; this.taskForm.taskId = this.$route.query && this.$route.query.taskId; this.taskForm.procInsId = this.$route.query && this.$route.query.procInsId; + this.taskForm.executionId = this.$route.query && this.$route.query.executionId; this.taskForm.instanceId = this.$route.query && this.$route.query.procInsId; // 初始化表单 this.taskForm.procDefId = this.$route.query && this.$route.query.procDefId; // 回显流程记录 - this.getFlowViewer(this.taskForm.procInsId); + this.getFlowViewer(this.taskForm.procInsId,this.taskForm.executionId); this.getModelDetail(this.taskForm.deployId); // 流程任务重获取变量表单 if (this.taskForm.taskId){ @@ -323,8 +324,8 @@ export default { this.xmlData = res.data }) }, - getFlowViewer(procInsId) { - getFlowViewer(procInsId).then(res => { + getFlowViewer(procInsId,executionId) { + getFlowViewer(procInsId,executionId).then(res => { this.taskList = res.data }) }, diff --git a/ruoyi-ui/src/views/flowable/task/todo/index.vue b/ruoyi-ui/src/views/flowable/task/todo/index.vue index f5ae308..52a7eb3 100644 --- a/ruoyi-ui/src/views/flowable/task/todo/index.vue +++ b/ruoyi-ui/src/views/flowable/task/todo/index.vue @@ -145,6 +145,7 @@ export default { this.$router.push({ path: '/flowable/task/record/index', query: { procInsId: row.procInsId, + executionId: row.executionId, deployId: row.deployId, taskId: row.taskId, finished: true