Commit 149cab1dac170df649be1c0d08e446b58bb42a11
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
Showing
7 changed files
with
37 additions
and
45 deletions
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java
| ... | ... | @@ -45,10 +45,6 @@ public class BpmModelMetaInfoVO { |
| 45 | 45 | @Schema(description = "表单编号", example = "1024") |
| 46 | 46 | private Long formId; // formType 为 NORMAL 使用,必须非空 |
| 47 | 47 | |
| 48 | - @Schema(description = "表单的配置-JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 49 | - private String formConf; | |
| 50 | - @Schema(description = "表单项的数组-JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 51 | - private List<String> formFields; | |
| 52 | 48 | @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/create") |
| 53 | 49 | private String formCustomCreatePath; // 表单类型为 CUSTOM 时,必须非空 |
| 54 | 50 | @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/view") | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java
| ... | ... | @@ -21,9 +21,6 @@ public class BpmModelSaveReqVO extends BpmModelMetaInfoVO { |
| 21 | 21 | @NotEmpty(message = "流程名称不能为空") |
| 22 | 22 | private String name; |
| 23 | 23 | |
| 24 | - @Schema(description = "表单名字", example = "请假表单") | |
| 25 | - private String formName; | |
| 26 | - | |
| 27 | 24 | @Schema(description = "流程分类", example = "1") |
| 28 | 25 | private String category; |
| 29 | 26 | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java
| ... | ... | @@ -20,9 +20,6 @@ public class BpmProcessDefinitionRespVO extends BpmModelMetaInfoVO { |
| 20 | 20 | @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") |
| 21 | 21 | private String name; |
| 22 | 22 | |
| 23 | - @Schema(description = "表单名字", example = "请假表单") | |
| 24 | - private String formName; | |
| 25 | - | |
| 26 | 23 | @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "youdao") |
| 27 | 24 | private String key; |
| 28 | 25 | |
| ... | ... | @@ -37,6 +34,13 @@ public class BpmProcessDefinitionRespVO extends BpmModelMetaInfoVO { |
| 37 | 34 | @Schema(description = "流程模型的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "ABC") |
| 38 | 35 | private String modelId; |
| 39 | 36 | |
| 37 | + @Schema(description = "表单的配置-JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 38 | + private String formConf; | |
| 39 | + @Schema(description = "表单项的数组-JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 40 | + private List<String> formFields; | |
| 41 | + @Schema(description = "表单名字", example = "请假表单") | |
| 42 | + private String formName; | |
| 43 | + | |
| 40 | 44 | @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 41 | 45 | private Integer suspensionState; // 参见 SuspensionState 枚举 |
| 42 | 46 | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
| ... | ... | @@ -907,9 +907,17 @@ public class BpmnModelUtils { |
| 907 | 907 | * @return 符合条件的路径 |
| 908 | 908 | */ |
| 909 | 909 | private static SequenceFlow findMatchSequenceFlowByExclusiveGateway(Gateway gateway, Map<String, Object> variables) { |
| 910 | - SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), | |
| 910 | + // TODO 表单无可编辑字段时variables为空,流程走向会出现问题,比如流程审批过程中无需要修改的字段值, | |
| 911 | + // TODO @小北:是不是还是保证,编辑的时候,如果计算下一个节点,还是 variables 是完整体?而不是空的!!!(可以微信讨论下) | |
| 912 | + SequenceFlow matchSequenceFlow; | |
| 913 | + if (CollUtil.isNotEmpty(variables)) { | |
| 914 | + matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), | |
| 911 | 915 | flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) |
| 912 | 916 | && (evalConditionExpress(variables, flow.getConditionExpression()))); |
| 917 | + } else { | |
| 918 | + matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), | |
| 919 | + flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId())); | |
| 920 | + } | |
| 913 | 921 | if (matchSequenceFlow == null) { |
| 914 | 922 | matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), |
| 915 | 923 | flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId())); | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java
| ... | ... | @@ -194,7 +194,7 @@ public class FlowableUtils { |
| 194 | 194 | @SuppressWarnings("unchecked") |
| 195 | 195 | public static Map<String, List<Long>> getStartUserSelectAssignees(Map<String, Object> processVariables) { |
| 196 | 196 | if (processVariables == null) { |
| 197 | - return null; | |
| 197 | + return new HashMap<>(); | |
| 198 | 198 | } |
| 199 | 199 | return (Map<String, List<Long>>) processVariables.get( |
| 200 | 200 | BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES); |
| ... | ... | @@ -219,7 +219,7 @@ public class FlowableUtils { |
| 219 | 219 | @SuppressWarnings("unchecked") |
| 220 | 220 | public static Map<String, List<Long>> getApproveUserSelectAssignees(Map<String, Object> processVariables) { |
| 221 | 221 | if (processVariables == null) { |
| 222 | - return null; | |
| 222 | + return new HashMap<>(); | |
| 223 | 223 | } |
| 224 | 224 | return (Map<String, List<Long>>) processVariables.get( |
| 225 | 225 | BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES); | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
| ... | ... | @@ -231,7 +231,7 @@ public class BpmModelServiceImpl implements BpmModelService { |
| 231 | 231 | repositoryService.saveModel(model); |
| 232 | 232 | } |
| 233 | 233 | |
| 234 | - private void validateBpmnXml(byte[] bpmnBytes, int type) { | |
| 234 | + private void validateBpmnXml(byte[] bpmnBytes, Integer type) { | |
| 235 | 235 | BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); |
| 236 | 236 | if (bpmnModel == null) { |
| 237 | 237 | throw exception(MODEL_NOT_EXISTS); |
| ... | ... | @@ -248,6 +248,7 @@ public class BpmModelServiceImpl implements BpmModelService { |
| 248 | 248 | throw exception(MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS, userTask.getId()); |
| 249 | 249 | } |
| 250 | 250 | }); |
| 251 | + // TODO @小北:是不是可以 UserTask firUserTask = CollUtil.get(userTasks, BpmModelTypeEnum.BPMN.getType().equals(type) ? 0 : 1);然后,最好判空。。。极端情况下,没 usertask ,哈哈哈哈。 | |
| 251 | 252 | // 3. 校验第一个用户任务节点的规则类型是否为“审批人自选” |
| 252 | 253 | Map<Integer, UserTask> userTaskMap = new HashMap<>(); |
| 253 | 254 | // BPMN 设计器,校验第一个用户任务节点 | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| ... | ... | @@ -557,26 +557,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 557 | 557 | // 2.2 添加评论 |
| 558 | 558 | taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), |
| 559 | 559 | BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); |
| 560 | - | |
| 561 | - // 如果流程变量前端传空,需要从历史实例中获取,原因:前端表单如果在当前节点无可编辑的字段时variables一定会为空 | |
| 562 | - // 场景一:A节点发起,B节点表单无可编辑字段,审批通过时,C节点需要流程变量获取下一个执行节点,但因为B节点无可编辑的字段,variables为空,流程可能出现问题 | |
| 563 | - // 场景二:A节点发起,B节点只有某一个字段可编辑(比如day),但C节点需要多个节点(比如workday,在发起时填写,因为B节点只有day的编辑权限,在审批后。variables会缺少work的值) | |
| 564 | - // 历史中的变量值 | |
| 565 | - // 3.1 设置流程变量 | |
| 566 | - Map<String, Object> processVariables = new HashMap<>(); | |
| 567 | - // 3.2 获取历史中流程变量 | |
| 568 | - if (CollUtil.isNotEmpty(instance.getProcessVariables())) { | |
| 569 | - processVariables.putAll(instance.getProcessVariables()); | |
| 570 | - } | |
| 571 | - // 3.3 合并前端传递的流程变量,以前端为准 | |
| 572 | - if (CollUtil.isNotEmpty(reqVO.getVariables())) { | |
| 573 | - processVariables.putAll(reqVO.getVariables()); | |
| 574 | - } | |
| 575 | - // 校验并处理 APPROVE_USER_SELECT 当前审批人,选择下一节点审批人的逻辑 | |
| 576 | - Map<String, Object> variables = validateAndSetNextAssignees(task.getTaskDefinitionKey(), processVariables, | |
| 560 | + // 2.3 校验并处理 APPROVE_USER_SELECT 当前审批人,选择下一节点审批人的逻辑 | |
| 561 | + Map<String, Object> variables = validateAndSetNextAssignees(task.getTaskDefinitionKey(), reqVO.getVariables(), | |
| 577 | 562 | bpmnModel, reqVO.getNextAssignees(), instance); |
| 578 | - // 3.4 调用 BPM complete 去完成任务 | |
| 579 | 563 | runtimeService.setVariables(task.getProcessInstanceId(), variables); |
| 564 | + // 2.4 调用 BPM complete 去完成任务 | |
| 580 | 565 | taskService.complete(task.getId(), variables, true); |
| 581 | 566 | |
| 582 | 567 | // 【加签专属】处理加签任务 |
| ... | ... | @@ -601,10 +586,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 601 | 586 | // 1. 获取下一个将要执行的节点集合 |
| 602 | 587 | FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey); |
| 603 | 588 | List<FlowNode> nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables); |
| 604 | - // 2. 循环下一个将要执行的节点集合 | |
| 589 | + | |
| 590 | + // 2. 校验选择的下一个节点的审批人,是否合法 | |
| 605 | 591 | Map<String, List<Long>> processVariables; |
| 606 | 592 | for (FlowNode nextFlowNode : nextFlowNodes) { |
| 607 | - // 获取任务节点中的审批人策略 | |
| 608 | 593 | Integer candidateStrategy = parseCandidateStrategy(nextFlowNode); |
| 609 | 594 | // 2.1 情况一:如果节点中的审批人策略为 发起人自选 |
| 610 | 595 | if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy())) { |
| ... | ... | @@ -614,16 +599,16 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 614 | 599 | throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); |
| 615 | 600 | } |
| 616 | 601 | processVariables = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); |
| 617 | - if (processVariables == null){ | |
| 602 | + // 特殊:如果当前节点已经存在审批人,则不允许覆盖 | |
| 603 | + // TODO @小北:【不用改】通过 if return,让逻辑更简洁一点;虽然会多判断一次 processVariables,但是 if else 层级更少。 | |
| 604 | + if (processVariables != null | |
| 605 | + && CollUtil.isNotEmpty(processVariables.get(nextFlowNode.getId()))) { | |
| 606 | + continue; | |
| 607 | + } | |
| 608 | + // 设置 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES | |
| 609 | + if (processVariables == null) { | |
| 618 | 610 | processVariables = new HashMap<>(); |
| 619 | - }else { | |
| 620 | - List<Long> startUserSelectAssignee = processVariables.get(nextFlowNode.getId()); | |
| 621 | - // 特殊:如果当前节点已经存在审批人,则不允许覆盖 | |
| 622 | - if (CollUtil.isNotEmpty(startUserSelectAssignee)) { | |
| 623 | - continue; | |
| 624 | - } | |
| 625 | 611 | } |
| 626 | - // 校验通过的全部节点和审批人 | |
| 627 | 612 | processVariables.put(nextFlowNode.getId(), assignees); |
| 628 | 613 | variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, processVariables); |
| 629 | 614 | } |
| ... | ... | @@ -635,16 +620,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 635 | 620 | throw exception(PROCESS_INSTANCE_APPROVE_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); |
| 636 | 621 | } |
| 637 | 622 | processVariables = FlowableUtils.getApproveUserSelectAssignees(processInstance.getProcessVariables()); |
| 638 | - if (processVariables == null){ | |
| 623 | + if (processVariables == null) { | |
| 639 | 624 | processVariables = new HashMap<>(); |
| 640 | - }else { | |
| 625 | + } else { | |
| 641 | 626 | List<Long> approveUserSelectAssignee = processVariables.get(nextFlowNode.getId()); |
| 642 | 627 | // 特殊:如果当前节点已经存在审批人,则不允许覆盖 |
| 628 | + // TODO @小北:这种,应该可以覆盖呢。 | |
| 643 | 629 | if (CollUtil.isNotEmpty(approveUserSelectAssignee)) { |
| 644 | 630 | continue; |
| 645 | 631 | } |
| 646 | 632 | } |
| 647 | - // 校验通过的全部节点和审批人 | |
| 633 | + // 设置 PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES | |
| 648 | 634 | processVariables.put(nextFlowNode.getId(), assignees); |
| 649 | 635 | variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES, processVariables); |
| 650 | 636 | } | ... | ... |