Commit 1684706e9aa70df8675b4b6bba212b7f5541d078
1 parent
76d89067
feat: [BPM 工作流] 增加跳过表达式判断。
Showing
5 changed files
with
71 additions
and
8 deletions
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
| @@ -71,6 +71,9 @@ public class BpmSimpleModelNodeVO { | @@ -71,6 +71,9 @@ public class BpmSimpleModelNodeVO { | ||
| 71 | @Schema(description = "是否填写审批意见", example = "false") | 71 | @Schema(description = "是否填写审批意见", example = "false") |
| 72 | private Boolean reasonRequire; | 72 | private Boolean reasonRequire; |
| 73 | 73 | ||
| 74 | + @Schema(description = "跳过表达式", example = "{true}") | ||
| 75 | + private String skipExpression; // 用于审批节点 | ||
| 76 | + | ||
| 74 | /** | 77 | /** |
| 75 | * 审批节点拒绝处理 | 78 | * 审批节点拒绝处理 |
| 76 | */ | 79 | */ |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatusEnum.java
| @@ -13,7 +13,7 @@ import lombok.Getter; | @@ -13,7 +13,7 @@ import lombok.Getter; | ||
| 13 | @Getter | 13 | @Getter |
| 14 | @AllArgsConstructor | 14 | @AllArgsConstructor |
| 15 | public enum BpmTaskStatusEnum { | 15 | public enum BpmTaskStatusEnum { |
| 16 | - | 16 | + SKIP(-2, "跳过"), |
| 17 | NOT_START(-1, "未开始"), | 17 | NOT_START(-1, "未开始"), |
| 18 | RUNNING(1, "审批中"), | 18 | RUNNING(1, "审批中"), |
| 19 | APPROVE(2, "审批通过"), | 19 | APPROVE(2, "审批通过"), |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
| @@ -800,9 +800,10 @@ public class BpmnModelUtils { | @@ -800,9 +800,10 @@ public class BpmnModelUtils { | ||
| 800 | || currentElement instanceof EndEvent | 800 | || currentElement instanceof EndEvent |
| 801 | || currentElement instanceof UserTask | 801 | || currentElement instanceof UserTask |
| 802 | || currentElement instanceof ServiceTask) { | 802 | || currentElement instanceof ServiceTask) { |
| 803 | - // 添加元素 | 803 | + // 添加节点 |
| 804 | FlowNode flowNode = (FlowNode) currentElement; | 804 | FlowNode flowNode = (FlowNode) currentElement; |
| 805 | resultElements.add(flowNode); | 805 | resultElements.add(flowNode); |
| 806 | + | ||
| 806 | // 遍历子节点 | 807 | // 遍历子节点 |
| 807 | flowNode.getOutgoingFlows().forEach( | 808 | flowNode.getOutgoingFlows().forEach( |
| 808 | nextElement -> simulateNextFlowElements(nextElement.getTargetFlowElement(), variables, resultElements, visitElements)); | 809 | nextElement -> simulateNextFlowElements(nextElement.getTargetFlowElement(), variables, resultElements, visitElements)); |
| @@ -836,6 +837,31 @@ public class BpmnModelUtils { | @@ -836,6 +837,31 @@ public class BpmnModelUtils { | ||
| 836 | } | 837 | } |
| 837 | 838 | ||
| 838 | /** | 839 | /** |
| 840 | + * 判断是否跳过此节点 | ||
| 841 | + * | ||
| 842 | + * @param flowNode 节点 | ||
| 843 | + * @param variables 流程变量 | ||
| 844 | + */ | ||
| 845 | + public static boolean isSkipNode(FlowElement flowNode, Map<String, Object> variables) { | ||
| 846 | + // 1. 检查节点是否有跳过表达式(支持多种任务节点类型) | ||
| 847 | + String skipExpression = null; | ||
| 848 | + if (flowNode instanceof UserTask) { | ||
| 849 | + skipExpression = ((UserTask) flowNode).getSkipExpression(); | ||
| 850 | + } else if (flowNode instanceof ServiceTask) { | ||
| 851 | + skipExpression = ((ServiceTask) flowNode).getSkipExpression(); | ||
| 852 | + } else if (flowNode instanceof ScriptTask) { | ||
| 853 | + skipExpression = ((ScriptTask) flowNode).getSkipExpression(); | ||
| 854 | + } | ||
| 855 | + | ||
| 856 | + if (StrUtil.isEmpty(skipExpression)) { | ||
| 857 | + return false; | ||
| 858 | + } | ||
| 859 | + | ||
| 860 | + // 2. 计算跳过表达式的值 | ||
| 861 | + return evalConditionExpress(variables, skipExpression); | ||
| 862 | + } | ||
| 863 | + | ||
| 864 | + /** | ||
| 839 | * 根据当前节点,获取下一个节点 | 865 | * 根据当前节点,获取下一个节点 |
| 840 | * | 866 | * |
| 841 | * @param currentElement 当前节点 | 867 | * @param currentElement 当前节点 |
| @@ -997,7 +1023,7 @@ public class BpmnModelUtils { | @@ -997,7 +1023,7 @@ public class BpmnModelUtils { | ||
| 997 | * @return 是否满足条件 | 1023 | * @return 是否满足条件 |
| 998 | */ | 1024 | */ |
| 999 | public static boolean evalConditionExpress(Map<String, Object> variables, String expression) { | 1025 | public static boolean evalConditionExpress(Map<String, Object> variables, String expression) { |
| 1000 | - if (expression == null) { | 1026 | + if (StrUtil.isEmpty(expression)) { |
| 1001 | return Boolean.FALSE; | 1027 | return Boolean.FALSE; |
| 1002 | } | 1028 | } |
| 1003 | // 如果 variables 为空,则创建一个的原因?可能 expression 的计算,不依赖于 variables | 1029 | // 如果 variables 为空,则创建一个的原因?可能 expression 的计算,不依赖于 variables |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
| @@ -464,9 +464,15 @@ public class SimpleModelUtils { | @@ -464,9 +464,15 @@ public class SimpleModelUtils { | ||
| 464 | addReasonRequire(node.getReasonRequire(), userTask); | 464 | addReasonRequire(node.getReasonRequire(), userTask); |
| 465 | // 节点类型 | 465 | // 节点类型 |
| 466 | addNodeType(node.getType(), userTask); | 466 | addNodeType(node.getType(), userTask); |
| 467 | + // 添加跳过表达式 | ||
| 468 | + if (StrUtil.isNotEmpty(node.getSkipExpression())) { | ||
| 469 | + userTask.setSkipExpression(node.getSkipExpression()); | ||
| 470 | + } | ||
| 467 | return userTask; | 471 | return userTask; |
| 468 | } | 472 | } |
| 469 | 473 | ||
| 474 | + | ||
| 475 | + | ||
| 470 | private void addUserTaskListener(BpmSimpleModelNodeVO node, UserTask userTask) { | 476 | private void addUserTaskListener(BpmSimpleModelNodeVO node, UserTask userTask) { |
| 471 | List<FlowableListener> flowableListeners = new ArrayList<>(3); | 477 | List<FlowableListener> flowableListeners = new ArrayList<>(3); |
| 472 | if (node.getTaskCreateListener() != null | 478 | if (node.getTaskCreateListener() != null |
| @@ -967,7 +973,7 @@ public class SimpleModelUtils { | @@ -967,7 +973,7 @@ public class SimpleModelUtils { | ||
| 967 | || nodeType == BpmSimpleModelNodeTypeEnum.COPY_NODE | 973 | || nodeType == BpmSimpleModelNodeTypeEnum.COPY_NODE |
| 968 | || nodeType == BpmSimpleModelNodeTypeEnum.CHILD_PROCESS | 974 | || nodeType == BpmSimpleModelNodeTypeEnum.CHILD_PROCESS |
| 969 | || nodeType == BpmSimpleModelNodeTypeEnum.END_NODE) { | 975 | || nodeType == BpmSimpleModelNodeTypeEnum.END_NODE) { |
| 970 | - // 添加元素 | 976 | + // 添加此节点 |
| 971 | resultNodes.add(currentNode); | 977 | resultNodes.add(currentNode); |
| 972 | } | 978 | } |
| 973 | 979 | ||
| @@ -1013,6 +1019,16 @@ public class SimpleModelUtils { | @@ -1013,6 +1019,16 @@ public class SimpleModelUtils { | ||
| 1013 | simulateNextNode(currentNode.getChildNode(), variables, resultNodes); | 1019 | simulateNextNode(currentNode.getChildNode(), variables, resultNodes); |
| 1014 | } | 1020 | } |
| 1015 | 1021 | ||
| 1022 | + /** | ||
| 1023 | + * 根据跳过表达式,判断是否跳过此节点。 | ||
| 1024 | + */ | ||
| 1025 | + public static boolean isSkipNode(BpmSimpleModelNodeVO currentNode, Map<String, Object> variables) { | ||
| 1026 | + if (StrUtil.isEmpty(currentNode.getSkipExpression())) { | ||
| 1027 | + return false; | ||
| 1028 | + } | ||
| 1029 | + return BpmnModelUtils.evalConditionExpress(variables, currentNode.getSkipExpression()); | ||
| 1030 | + } | ||
| 1031 | + | ||
| 1016 | public static boolean evalConditionExpress(Map<String, Object> variables, BpmSimpleModelNodeVO.ConditionSetting conditionSetting) { | 1032 | public static boolean evalConditionExpress(Map<String, Object> variables, BpmSimpleModelNodeVO.ConditionSetting conditionSetting) { |
| 1017 | return BpmnModelUtils.evalConditionExpress(variables, buildConditionExpression(conditionSetting)); | 1033 | return BpmnModelUtils.evalConditionExpress(variables, buildConditionExpression(conditionSetting)); |
| 1018 | } | 1034 | } |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
| @@ -398,7 +398,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -398,7 +398,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 398 | ? BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType() | 398 | ? BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType() |
| 399 | : ObjUtil.defaultIfNull(parseNodeType(flowNode), // 目的:解决“办理节点”的识别 | 399 | : ObjUtil.defaultIfNull(parseNodeType(flowNode), // 目的:解决“办理节点”的识别 |
| 400 | BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())) | 400 | BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())) |
| 401 | - .setStatus(FlowableUtils.getTaskStatus(task)) | 401 | + .setStatus(getEndActivityNodeStatus(task)) |
| 402 | .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) | 402 | .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) |
| 403 | .setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime())) | 403 | .setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime())) |
| 404 | .setTasks(singletonList(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task))); | 404 | .setTasks(singletonList(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task))); |
| @@ -462,6 +462,15 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -462,6 +462,15 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 462 | return approvalNodes; | 462 | return approvalNodes; |
| 463 | } | 463 | } |
| 464 | 464 | ||
| 465 | + | ||
| 466 | + /** | ||
| 467 | + * 获取结束节点的状态 | ||
| 468 | + */ | ||
| 469 | + private Integer getEndActivityNodeStatus(HistoricTaskInstance task) { | ||
| 470 | + Integer status = FlowableUtils.getTaskStatus(task); | ||
| 471 | + return status == null ? BpmTaskStatusEnum.SKIP.getStatus() : status; // 结束节点未获取到状态,为跳过状态 | ||
| 472 | + } | ||
| 473 | + | ||
| 465 | /** | 474 | /** |
| 466 | * 获得【进行中】的活动节点们 | 475 | * 获得【进行中】的活动节点们 |
| 467 | */ | 476 | */ |
| @@ -565,10 +574,14 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -565,10 +574,14 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 565 | if (runActivityIds.contains(node.getId())) { | 574 | if (runActivityIds.contains(node.getId())) { |
| 566 | return null; | 575 | return null; |
| 567 | } | 576 | } |
| 568 | - | 577 | + Integer status = BpmTaskStatusEnum.NOT_START.getStatus(); |
| 578 | + // 如果节点被跳过。设置状态为跳过 | ||
| 579 | + if (SimpleModelUtils.isSkipNode(node, processVariables)) { | ||
| 580 | + status = BpmTaskStatusEnum.SKIP.getStatus(); | ||
| 581 | + } | ||
| 569 | ActivityNode activityNode = new ActivityNode().setId(node.getId()).setName(node.getName()) | 582 | ActivityNode activityNode = new ActivityNode().setId(node.getId()).setName(node.getName()) |
| 570 | .setNodeType(node.getType()).setCandidateStrategy(node.getCandidateStrategy()) | 583 | .setNodeType(node.getType()).setCandidateStrategy(node.getCandidateStrategy()) |
| 571 | - .setStatus(BpmTaskStatusEnum.NOT_START.getStatus()); | 584 | + .setStatus(status); |
| 572 | 585 | ||
| 573 | // 1. 开始节点/审批节点 | 586 | // 1. 开始节点/审批节点 |
| 574 | if (ObjectUtils.equalsAny(node.getType(), | 587 | if (ObjectUtils.equalsAny(node.getType(), |
| @@ -608,8 +621,13 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -608,8 +621,13 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 608 | if (runActivityIds.contains(node.getId())) { | 621 | if (runActivityIds.contains(node.getId())) { |
| 609 | return null; | 622 | return null; |
| 610 | } | 623 | } |
| 624 | + Integer status = BpmTaskStatusEnum.NOT_START.getStatus(); | ||
| 625 | + // 如果节点被跳过,状态设置为跳过 | ||
| 626 | + if(BpmnModelUtils.isSkipNode(node, processVariables)){ | ||
| 627 | + status = BpmTaskStatusEnum.SKIP.getStatus(); | ||
| 628 | + } | ||
| 611 | ActivityNode activityNode = new ActivityNode().setId(node.getId()) | 629 | ActivityNode activityNode = new ActivityNode().setId(node.getId()) |
| 612 | - .setStatus(BpmTaskStatusEnum.NOT_START.getStatus()); | 630 | + .setStatus(status); |
| 613 | 631 | ||
| 614 | // 1. 开始节点 | 632 | // 1. 开始节点 |
| 615 | if (node instanceof StartEvent) { | 633 | if (node instanceof StartEvent) { |