mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 10:37:41 +08:00 
			
		
		
		
	Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm
# Conflicts: # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
This commit is contained in:
		| @ -45,10 +45,6 @@ public class BpmModelMetaInfoVO { | ||||
|     @Schema(description = "表单编号", example = "1024") | ||||
|     private Long formId; // formType 为 NORMAL 使用,必须非空 | ||||
|  | ||||
|     @Schema(description = "表单的配置-JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) | ||||
|     private String formConf; | ||||
|     @Schema(description = "表单项的数组-JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) | ||||
|     private List<String> formFields; | ||||
|     @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/create") | ||||
|     private String formCustomCreatePath; // 表单类型为 CUSTOM 时,必须非空 | ||||
|     @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/view") | ||||
|  | ||||
| @ -21,9 +21,6 @@ public class BpmModelSaveReqVO extends BpmModelMetaInfoVO { | ||||
|     @NotEmpty(message = "流程名称不能为空") | ||||
|     private String name; | ||||
|  | ||||
|     @Schema(description = "表单名字", example = "请假表单") | ||||
|     private String formName; | ||||
|  | ||||
|     @Schema(description = "流程分类", example = "1") | ||||
|     private String category; | ||||
|  | ||||
|  | ||||
| @ -20,9 +20,6 @@ public class BpmProcessDefinitionRespVO extends BpmModelMetaInfoVO { | ||||
|     @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") | ||||
|     private String name; | ||||
|  | ||||
|     @Schema(description = "表单名字", example = "请假表单") | ||||
|     private String formName; | ||||
|  | ||||
|     @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "youdao") | ||||
|     private String key; | ||||
|  | ||||
| @ -37,6 +34,13 @@ public class BpmProcessDefinitionRespVO extends BpmModelMetaInfoVO { | ||||
|     @Schema(description = "流程模型的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "ABC") | ||||
|     private String modelId; | ||||
|  | ||||
|     @Schema(description = "表单的配置-JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) | ||||
|     private String formConf; | ||||
|     @Schema(description = "表单项的数组-JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) | ||||
|     private List<String> formFields; | ||||
|     @Schema(description = "表单名字", example = "请假表单") | ||||
|     private String formName; | ||||
|  | ||||
|     @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer suspensionState; // 参见 SuspensionState 枚举 | ||||
|  | ||||
|  | ||||
| @ -907,9 +907,17 @@ public class BpmnModelUtils { | ||||
|      * @return 符合条件的路径 | ||||
|      */ | ||||
|     private static SequenceFlow findMatchSequenceFlowByExclusiveGateway(Gateway gateway, Map<String, Object> variables) { | ||||
|         SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), | ||||
|         // TODO 表单无可编辑字段时variables为空,流程走向会出现问题,比如流程审批过程中无需要修改的字段值, | ||||
|         // TODO @小北:是不是还是保证,编辑的时候,如果计算下一个节点,还是 variables 是完整体?而不是空的!!!(可以微信讨论下) | ||||
|         SequenceFlow matchSequenceFlow; | ||||
|         if (CollUtil.isNotEmpty(variables)) { | ||||
|              matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), | ||||
|                     flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) | ||||
|                             && (evalConditionExpress(variables, flow.getConditionExpression()))); | ||||
|         } else { | ||||
|             matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), | ||||
|                     flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId())); | ||||
|         } | ||||
|         if (matchSequenceFlow == null) { | ||||
|             matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), | ||||
|                     flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId())); | ||||
|  | ||||
| @ -194,7 +194,7 @@ public class FlowableUtils { | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static Map<String, List<Long>> getStartUserSelectAssignees(Map<String, Object> processVariables) { | ||||
|         if (processVariables == null) { | ||||
|             return null; | ||||
|             return new HashMap<>(); | ||||
|         } | ||||
|         return (Map<String, List<Long>>) processVariables.get( | ||||
|                 BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES); | ||||
| @ -219,7 +219,7 @@ public class FlowableUtils { | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static Map<String, List<Long>> getApproveUserSelectAssignees(Map<String, Object> processVariables) { | ||||
|         if (processVariables == null) { | ||||
|             return null; | ||||
|             return new HashMap<>(); | ||||
|         } | ||||
|         return (Map<String, List<Long>>) processVariables.get( | ||||
|                 BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES); | ||||
|  | ||||
| @ -231,7 +231,7 @@ public class BpmModelServiceImpl implements BpmModelService { | ||||
|         repositoryService.saveModel(model); | ||||
|     } | ||||
|  | ||||
|     private void validateBpmnXml(byte[] bpmnBytes, int type) { | ||||
|     private void validateBpmnXml(byte[] bpmnBytes, Integer type) { | ||||
|         BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); | ||||
|         if (bpmnModel == null) { | ||||
|             throw exception(MODEL_NOT_EXISTS); | ||||
| @ -248,6 +248,7 @@ public class BpmModelServiceImpl implements BpmModelService { | ||||
|                 throw exception(MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS, userTask.getId()); | ||||
|             } | ||||
|         }); | ||||
|         // TODO @小北:是不是可以 UserTask firUserTask = CollUtil.get(userTasks, BpmModelTypeEnum.BPMN.getType().equals(type) ? 0 : 1);然后,最好判空。。。极端情况下,没 usertask ,哈哈哈哈。 | ||||
|         // 3. 校验第一个用户任务节点的规则类型是否为“审批人自选” | ||||
|         Map<Integer, UserTask> userTaskMap = new HashMap<>(); | ||||
|         // BPMN 设计器,校验第一个用户任务节点 | ||||
|  | ||||
| @ -557,26 +557,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|         // 2.2 添加评论 | ||||
|         taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), | ||||
|                 BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); | ||||
|  | ||||
|         // 如果流程变量前端传空,需要从历史实例中获取,原因:前端表单如果在当前节点无可编辑的字段时variables一定会为空 | ||||
|         // 场景一:A节点发起,B节点表单无可编辑字段,审批通过时,C节点需要流程变量获取下一个执行节点,但因为B节点无可编辑的字段,variables为空,流程可能出现问题 | ||||
|         // 场景二:A节点发起,B节点只有某一个字段可编辑(比如day),但C节点需要多个节点(比如workday,在发起时填写,因为B节点只有day的编辑权限,在审批后。variables会缺少work的值) | ||||
|         // 历史中的变量值 | ||||
|         // 3.1 设置流程变量 | ||||
|         Map<String, Object> processVariables = new HashMap<>(); | ||||
|         // 3.2 获取历史中流程变量 | ||||
|         if (CollUtil.isNotEmpty(instance.getProcessVariables())) { | ||||
|             processVariables.putAll(instance.getProcessVariables()); | ||||
|         } | ||||
|         // 3.3 合并前端传递的流程变量,以前端为准 | ||||
|         if (CollUtil.isNotEmpty(reqVO.getVariables())) { | ||||
|             processVariables.putAll(reqVO.getVariables()); | ||||
|         } | ||||
|         // 校验并处理 APPROVE_USER_SELECT 当前审批人,选择下一节点审批人的逻辑 | ||||
|         Map<String, Object> variables = validateAndSetNextAssignees(task.getTaskDefinitionKey(), processVariables, | ||||
|         // 2.3 校验并处理 APPROVE_USER_SELECT 当前审批人,选择下一节点审批人的逻辑 | ||||
|         Map<String, Object> variables = validateAndSetNextAssignees(task.getTaskDefinitionKey(), reqVO.getVariables(), | ||||
|                 bpmnModel, reqVO.getNextAssignees(), instance); | ||||
|         // 3.4 调用 BPM complete 去完成任务 | ||||
|         runtimeService.setVariables(task.getProcessInstanceId(), variables); | ||||
|         // 2.4 调用 BPM complete 去完成任务 | ||||
|         taskService.complete(task.getId(), variables, true); | ||||
|  | ||||
|         // 【加签专属】处理加签任务 | ||||
| @ -601,10 +586,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|         // 1. 获取下一个将要执行的节点集合 | ||||
|         FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey); | ||||
|         List<FlowNode> nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables); | ||||
|         // 2. 循环下一个将要执行的节点集合 | ||||
|  | ||||
|         // 2. 校验选择的下一个节点的审批人,是否合法 | ||||
|         Map<String, List<Long>> processVariables; | ||||
|         for (FlowNode nextFlowNode : nextFlowNodes) { | ||||
|             // 获取任务节点中的审批人策略 | ||||
|             Integer candidateStrategy = parseCandidateStrategy(nextFlowNode); | ||||
|             // 2.1 情况一:如果节点中的审批人策略为 发起人自选 | ||||
|             if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy())) { | ||||
| @ -614,16 +599,16 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|                     throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); | ||||
|                 } | ||||
|                 processVariables = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); | ||||
|                 if (processVariables == null){ | ||||
|                     processVariables = new HashMap<>(); | ||||
|                 }else { | ||||
|                     List<Long> startUserSelectAssignee = processVariables.get(nextFlowNode.getId()); | ||||
|                 // 特殊:如果当前节点已经存在审批人,则不允许覆盖 | ||||
|                     if (CollUtil.isNotEmpty(startUserSelectAssignee)) { | ||||
|                 // TODO @小北:【不用改】通过 if return,让逻辑更简洁一点;虽然会多判断一次 processVariables,但是 if else 层级更少。 | ||||
|                 if (processVariables != null | ||||
|                         && CollUtil.isNotEmpty(processVariables.get(nextFlowNode.getId()))) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 // 设置 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES | ||||
|                 if (processVariables == null) { | ||||
|                     processVariables = new HashMap<>(); | ||||
|                 } | ||||
|                 // 校验通过的全部节点和审批人 | ||||
|                 processVariables.put(nextFlowNode.getId(), assignees); | ||||
|                 variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, processVariables); | ||||
|             } | ||||
| @ -635,16 +620,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|                     throw exception(PROCESS_INSTANCE_APPROVE_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); | ||||
|                 } | ||||
|                 processVariables = FlowableUtils.getApproveUserSelectAssignees(processInstance.getProcessVariables()); | ||||
|                 if (processVariables == null){ | ||||
|                 if (processVariables == null) { | ||||
|                     processVariables = new HashMap<>(); | ||||
|                 }else  { | ||||
|                 } else  { | ||||
|                     List<Long> approveUserSelectAssignee = processVariables.get(nextFlowNode.getId()); | ||||
|                     // 特殊:如果当前节点已经存在审批人,则不允许覆盖 | ||||
|                     // TODO @小北:这种,应该可以覆盖呢。 | ||||
|                     if (CollUtil.isNotEmpty(approveUserSelectAssignee)) { | ||||
|                         continue; | ||||
|                     } | ||||
|                 } | ||||
|                 // 校验通过的全部节点和审批人 | ||||
|                 // 设置 PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES | ||||
|                 processVariables.put(nextFlowNode.getId(), assignees); | ||||
|                 variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES, processVariables); | ||||
|             } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 lizhixian
					lizhixian