Commit 8a9d64bbaf7948e099ae52c7d7d8ae18397beb31
1 parent
9c9f2812
feat: 子流程-多实例
Showing
8 changed files
with
198 additions
and
52 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessMultiInstanceSourceTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.enums.definition; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.ArrayUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.core.ArrayValuable; | |
| 5 | +import lombok.AllArgsConstructor; | |
| 6 | +import lombok.Getter; | |
| 7 | + | |
| 8 | +import java.util.Arrays; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * BPM 子流程多实例来源类型枚举 | |
| 12 | + * | |
| 13 | + * @author Lesan | |
| 14 | + */ | |
| 15 | +@Getter | |
| 16 | +@AllArgsConstructor | |
| 17 | +public enum BpmChildProcessMultiInstanceSourceTypeEnum implements ArrayValuable<Integer> { | |
| 18 | + | |
| 19 | + FIXED_QUANTITY(1, "固定数量"), | |
| 20 | + DIGITAL_FORM(2, "数字表单"), | |
| 21 | + MULTI_FORM(3, "多项表单"); | |
| 22 | + | |
| 23 | + private final Integer type; | |
| 24 | + private final String name; | |
| 25 | + | |
| 26 | + public static final Integer[] ARRAYS = Arrays.stream(values()).map(BpmChildProcessMultiInstanceSourceTypeEnum::getType).toArray(Integer[]::new); | |
| 27 | + | |
| 28 | + public static BpmChildProcessMultiInstanceSourceTypeEnum typeOf(Integer type) { | |
| 29 | + return ArrayUtil.firstMatch(item -> item.getType().equals(type), values()); | |
| 30 | + } | |
| 31 | + | |
| 32 | + @Override | |
| 33 | + public Integer[] array() { | |
| 34 | + return ARRAYS; | |
| 35 | + } | |
| 36 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
| ... | ... | @@ -452,6 +452,9 @@ public class BpmSimpleModelNodeVO { |
| 452 | 452 | @Schema(description = "超时设置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") |
| 453 | 453 | private TimeoutSetting timeoutSetting; |
| 454 | 454 | |
| 455 | + @Schema(description = "多实例设置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") | |
| 456 | + private MultiInstanceSetting multiInstanceSetting; | |
| 457 | + | |
| 455 | 458 | @Schema(description = "子流程发起人配置") |
| 456 | 459 | @Data |
| 457 | 460 | @Valid |
| ... | ... | @@ -490,5 +493,33 @@ public class BpmSimpleModelNodeVO { |
| 490 | 493 | |
| 491 | 494 | } |
| 492 | 495 | |
| 496 | + @Schema(description = "多实例设置") | |
| 497 | + @Data | |
| 498 | + @Valid | |
| 499 | + public static class MultiInstanceSetting { | |
| 500 | + | |
| 501 | + @Schema(description = "是否开启多实例", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") | |
| 502 | + @NotNull(message = "是否开启多实例不能为空") | |
| 503 | + private Boolean enable; | |
| 504 | + | |
| 505 | + @Schema(description = "是否串行", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") | |
| 506 | + @NotNull(message = "是否串行不能为空") | |
| 507 | + private Boolean sequential; | |
| 508 | + | |
| 509 | + @Schema(description = "完成比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") | |
| 510 | + @NotNull(message = "完成比例不能为空") | |
| 511 | + private Integer completeRatio; | |
| 512 | + | |
| 513 | + @Schema(description = "多实例来源类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 514 | + @NotNull(message = "多实例来源类型不能为空") | |
| 515 | + @InEnum(BpmChildProcessMultiInstanceSourceTypeEnum.class) | |
| 516 | + private Integer sourceType; | |
| 517 | + | |
| 518 | + @Schema(description = "多实例来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 519 | + @NotNull(message = "多实例来源不能为空") | |
| 520 | + private String source; | |
| 521 | + | |
| 522 | + } | |
| 523 | + | |
| 493 | 524 | } |
| 494 | 525 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java
| 1 | 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | |
| 5 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmChildProcessMultiInstanceSourceTypeEnum; | |
| 4 | 6 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; |
| 7 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; | |
| 5 | 8 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; |
| 6 | -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | |
| 7 | 9 | import lombok.Setter; |
| 8 | 10 | import org.flowable.bpmn.model.Activity; |
| 11 | +import org.flowable.bpmn.model.CallActivity; | |
| 12 | +import org.flowable.bpmn.model.FlowElement; | |
| 13 | +import org.flowable.bpmn.model.UserTask; | |
| 9 | 14 | import org.flowable.engine.delegate.DelegateExecution; |
| 10 | 15 | import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; |
| 11 | 16 | import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; |
| 12 | 17 | |
| 18 | +import java.util.List; | |
| 13 | 19 | import java.util.Set; |
| 14 | 20 | |
| 15 | 21 | /** |
| ... | ... | @@ -42,27 +48,42 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav |
| 42 | 48 | */ |
| 43 | 49 | @Override |
| 44 | 50 | protected int resolveNrOfInstances(DelegateExecution execution) { |
| 45 | - // 第一步,设置 collectionVariable 和 CollectionVariable | |
| 46 | - // 从 execution.getVariable() 读取所有任务处理人的 key | |
| 47 | - super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 | |
| 48 | - super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId()); | |
| 49 | - // 从 execution.getVariable() 读取当前所有任务处理的人的 key | |
| 50 | - super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); | |
| 51 | + if (execution.getCurrentFlowElement() instanceof UserTask) { | |
| 52 | + // 第一步,设置 collectionVariable 和 CollectionVariable | |
| 53 | + // 从 execution.getVariable() 读取所有任务处理人的 key | |
| 54 | + super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 | |
| 55 | + super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId()); | |
| 56 | + // 从 execution.getVariable() 读取当前所有任务处理的人的 key | |
| 57 | + super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); | |
| 51 | 58 | |
| 52 | - // 第二步,获取任务的所有处理人 | |
| 53 | - @SuppressWarnings("unchecked") | |
| 54 | - Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class); | |
| 55 | - if (assigneeUserIds == null) { | |
| 56 | - assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution); | |
| 57 | - if (CollUtil.isEmpty(assigneeUserIds)) { | |
| 58 | - // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过! | |
| 59 | - // 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务 | |
| 60 | - // 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时 | |
| 61 | - assigneeUserIds = SetUtils.asSet((Long) null); | |
| 59 | + // 第二步,获取任务的所有处理人 | |
| 60 | + @SuppressWarnings("unchecked") | |
| 61 | + Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class); | |
| 62 | + if (assigneeUserIds == null) { | |
| 63 | + assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution); | |
| 64 | + if (CollUtil.isEmpty(assigneeUserIds)) { | |
| 65 | + // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过! | |
| 66 | + // 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务 | |
| 67 | + // 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时 | |
| 68 | + assigneeUserIds = SetUtils.asSet((Long) null); | |
| 69 | + } | |
| 70 | + execution.setVariableLocal(super.collectionVariable, assigneeUserIds); | |
| 62 | 71 | } |
| 63 | - execution.setVariableLocal(super.collectionVariable, assigneeUserIds); | |
| 72 | + return assigneeUserIds.size(); | |
| 64 | 73 | } |
| 65 | - return assigneeUserIds.size(); | |
| 74 | + | |
| 75 | + if (execution.getCurrentFlowElement() instanceof CallActivity) { | |
| 76 | + FlowElement flowElement = execution.getCurrentFlowElement(); | |
| 77 | + Integer sourceType = BpmnModelUtils.parseMultiInstanceSourceType(flowElement); | |
| 78 | + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType())) { | |
| 79 | + return execution.getVariable(super.collectionExpression.getExpressionText(), Integer.class); | |
| 80 | + } | |
| 81 | + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) { | |
| 82 | + return execution.getVariable(super.collectionExpression.getExpressionText(), List.class).size(); | |
| 83 | + } | |
| 84 | + } | |
| 85 | + | |
| 86 | + return super.resolveNrOfInstances(execution); | |
| 66 | 87 | } |
| 67 | 88 | |
| 68 | 89 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java
| ... | ... | @@ -2,14 +2,20 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.util.collection.SetUtils; |
| 5 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmChildProcessMultiInstanceSourceTypeEnum; | |
| 5 | 6 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; |
| 7 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; | |
| 6 | 8 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; |
| 7 | 9 | import lombok.Setter; |
| 8 | 10 | import org.flowable.bpmn.model.Activity; |
| 11 | +import org.flowable.bpmn.model.CallActivity; | |
| 12 | +import org.flowable.bpmn.model.FlowElement; | |
| 13 | +import org.flowable.bpmn.model.UserTask; | |
| 9 | 14 | import org.flowable.engine.delegate.DelegateExecution; |
| 10 | 15 | import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; |
| 11 | 16 | import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; |
| 12 | 17 | |
| 18 | +import java.util.List; | |
| 13 | 19 | import java.util.Set; |
| 14 | 20 | |
| 15 | 21 | /** |
| ... | ... | @@ -35,28 +41,43 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB |
| 35 | 41 | */ |
| 36 | 42 | @Override |
| 37 | 43 | protected int resolveNrOfInstances(DelegateExecution execution) { |
| 38 | - // 第一步,设置 collectionVariable 和 CollectionVariable | |
| 39 | - // 从 execution.getVariable() 读取所有任务处理人的 key | |
| 40 | - super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 | |
| 41 | - super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId()); | |
| 42 | - // 从 execution.getVariable() 读取当前所有任务处理的人的 key | |
| 43 | - super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); | |
| 44 | - | |
| 45 | - // 第二步,获取任务的所有处理人 | |
| 46 | - // 不使用 execution.getVariable 原因:目前依次审批任务回退后 collectionVariable 变量没有清理, 如果重新进入该任务不会重新分配审批人 | |
| 47 | - @SuppressWarnings("unchecked") | |
| 48 | - Set<Long> assigneeUserIds = (Set<Long>) execution.getVariableLocal(super.collectionVariable, Set.class); | |
| 49 | - if (assigneeUserIds == null) { | |
| 50 | - assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution); | |
| 51 | - if (CollUtil.isEmpty(assigneeUserIds)) { | |
| 52 | - // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过! | |
| 53 | - // 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务 | |
| 54 | - // 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时 | |
| 55 | - assigneeUserIds = SetUtils.asSet((Long) null); | |
| 44 | + if (execution.getCurrentFlowElement() instanceof UserTask) { | |
| 45 | + // 第一步,设置 collectionVariable 和 CollectionVariable | |
| 46 | + // 从 execution.getVariable() 读取所有任务处理人的 key | |
| 47 | + super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 | |
| 48 | + super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId()); | |
| 49 | + // 从 execution.getVariable() 读取当前所有任务处理的人的 key | |
| 50 | + super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); | |
| 51 | + | |
| 52 | + // 第二步,获取任务的所有处理人 | |
| 53 | + // 不使用 execution.getVariable 原因:目前依次审批任务回退后 collectionVariable 变量没有清理, 如果重新进入该任务不会重新分配审批人 | |
| 54 | + @SuppressWarnings("unchecked") | |
| 55 | + Set<Long> assigneeUserIds = (Set<Long>) execution.getVariableLocal(super.collectionVariable, Set.class); | |
| 56 | + if (assigneeUserIds == null) { | |
| 57 | + assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution); | |
| 58 | + if (CollUtil.isEmpty(assigneeUserIds)) { | |
| 59 | + // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过! | |
| 60 | + // 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务 | |
| 61 | + // 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时 | |
| 62 | + assigneeUserIds = SetUtils.asSet((Long) null); | |
| 63 | + } | |
| 64 | + execution.setVariableLocal(super.collectionVariable, assigneeUserIds); | |
| 65 | + } | |
| 66 | + return assigneeUserIds.size(); | |
| 67 | + } | |
| 68 | + | |
| 69 | + if (execution.getCurrentFlowElement() instanceof CallActivity) { | |
| 70 | + FlowElement flowElement = execution.getCurrentFlowElement(); | |
| 71 | + Integer sourceType = BpmnModelUtils.parseMultiInstanceSourceType(flowElement); | |
| 72 | + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType())) { | |
| 73 | + return execution.getVariable(super.collectionExpression.getExpressionText(), Integer.class); | |
| 74 | + } | |
| 75 | + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) { | |
| 76 | + return execution.getVariable(super.collectionExpression.getExpressionText(), List.class).size(); | |
| 56 | 77 | } |
| 57 | - execution.setVariableLocal(super.collectionVariable, assigneeUserIds); | |
| 58 | 78 | } |
| 59 | - return assigneeUserIds.size(); | |
| 79 | + | |
| 80 | + return super.resolveNrOfInstances(execution); | |
| 60 | 81 | } |
| 61 | 82 | |
| 62 | 83 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java
| ... | ... | @@ -69,6 +69,11 @@ public interface BpmnModelConstants { |
| 69 | 69 | String USER_TASK_APPROVE_METHOD = "approveMethod"; |
| 70 | 70 | |
| 71 | 71 | /** |
| 72 | + * BPMN Child Process 的扩展属性,用于标记多实例来源类型 | |
| 73 | + */ | |
| 74 | + String CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE = "childProcessMultiInstanceSourceType"; | |
| 75 | + | |
| 76 | + /** | |
| 72 | 77 | * BPMN ExtensionElement 流程表单字段权限元素, 用于标记字段权限 |
| 73 | 78 | */ |
| 74 | 79 | String FORM_FIELD_PERMISSION_ELEMENT = "fieldsPermission"; | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
| ... | ... | @@ -159,6 +159,17 @@ public class BpmnModelUtils { |
| 159 | 159 | } |
| 160 | 160 | |
| 161 | 161 | /** |
| 162 | + * 解析子流程多实例来源类型 | |
| 163 | + * | |
| 164 | + * @see BpmChildProcessMultiInstanceSourceTypeEnum | |
| 165 | + * @param element 任务节点 | |
| 166 | + * @return 多实例来源类型 | |
| 167 | + */ | |
| 168 | + public static Integer parseMultiInstanceSourceType(FlowElement element) { | |
| 169 | + return NumberUtils.parseInt(parseExtensionElement(element, BpmnModelConstants.CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE)); | |
| 170 | + } | |
| 171 | + | |
| 172 | + /** | |
| 162 | 173 | * 添加任务拒绝处理元素 |
| 163 | 174 | * |
| 164 | 175 | * @param rejectHandler 任务拒绝处理 | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
| ... | ... | @@ -853,18 +853,35 @@ public class SimpleModelUtils { |
| 853 | 853 | callActivity.setExecutionListeners(executionListeners); |
| 854 | 854 | |
| 855 | 855 | // 7. 超时设置 |
| 856 | - if (childProcessSetting.getTimeoutSetting() != null) { | |
| 856 | + if (childProcessSetting.getTimeoutSetting() != null && Boolean.TRUE.equals(childProcessSetting.getTimeoutSetting().getEnable())) { | |
| 857 | 857 | BoundaryEvent boundaryEvent = null; |
| 858 | - if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerTypeEnum.FIXED_DATE_TIME.getType())) { | |
| 858 | + if (childProcessSetting.getTimeoutSetting().getType().equals(BpmDelayTimerTypeEnum.FIXED_DATE_TIME.getType())) { | |
| 859 | 859 | boundaryEvent = buildTimeoutBoundaryEvent(callActivity, BpmBoundaryEventTypeEnum.DELAY_TIMER_TIMEOUT.getType(), |
| 860 | - node.getDelaySetting().getDelayTime(), null, null); | |
| 861 | - } else if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerTypeEnum.FIXED_TIME_DURATION.getType())) { | |
| 860 | + childProcessSetting.getTimeoutSetting().getTimeExpression(), null, null); | |
| 861 | + } else if (childProcessSetting.getTimeoutSetting().getType().equals(BpmDelayTimerTypeEnum.FIXED_TIME_DURATION.getType())) { | |
| 862 | 862 | boundaryEvent = buildTimeoutBoundaryEvent(callActivity, BpmBoundaryEventTypeEnum.CHILD_PROCESS_TIMEOUT.getType(), |
| 863 | - null, null, node.getDelaySetting().getDelayTime()); | |
| 863 | + null, null, childProcessSetting.getTimeoutSetting().getTimeExpression()); | |
| 864 | 864 | } |
| 865 | 865 | flowElements.add(boundaryEvent); |
| 866 | 866 | } |
| 867 | 867 | |
| 868 | + // 8. 多实例 | |
| 869 | + if (childProcessSetting.getMultiInstanceSetting() != null && Boolean.TRUE.equals(childProcessSetting.getMultiInstanceSetting().getEnable())) { | |
| 870 | + MultiInstanceLoopCharacteristics multiInstanceCharacteristics = new MultiInstanceLoopCharacteristics(); | |
| 871 | + multiInstanceCharacteristics.setSequential(childProcessSetting.getMultiInstanceSetting().getSequential()); | |
| 872 | + if (childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.FIXED_QUANTITY.getType())) { | |
| 873 | + multiInstanceCharacteristics.setLoopCardinality(childProcessSetting.getMultiInstanceSetting().getSource()); | |
| 874 | + } | |
| 875 | + if (childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType()) || | |
| 876 | + childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) { | |
| 877 | + multiInstanceCharacteristics.setInputDataItem(childProcessSetting.getMultiInstanceSetting().getSource()); | |
| 878 | + } | |
| 879 | + multiInstanceCharacteristics.setCompletionCondition(String.format("${ nrOfCompletedInstances/nrOfInstances >= %s}", | |
| 880 | + String.format("%.2f", childProcessSetting.getMultiInstanceSetting().getCompleteRatio() / 100D))); | |
| 881 | + callActivity.setLoopCharacteristics(multiInstanceCharacteristics); | |
| 882 | + addExtensionElement(callActivity, CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE, childProcessSetting.getMultiInstanceSetting().getSourceType()); | |
| 883 | + } | |
| 884 | + | |
| 868 | 885 | // 添加节点类型 |
| 869 | 886 | addNodeType(node.getType(), callActivity); |
| 870 | 887 | flowElements.add(callActivity); | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java
| 1 | 1 | package cn.iocoder.yudao.module.bpm.service.task.listener; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.lang.Assert; |
| 4 | +import cn.hutool.core.map.MapUtil; | |
| 4 | 5 | import cn.hutool.core.util.StrUtil; |
| 5 | 6 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 6 | 7 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; |
| ... | ... | @@ -9,13 +10,14 @@ import cn.iocoder.yudao.module.bpm.enums.definition.BpmChildProcessStartUserEmpt |
| 9 | 10 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmChildProcessStartUserTypeEnum; |
| 10 | 11 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; |
| 11 | 12 | import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; |
| 13 | +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; | |
| 12 | 14 | import jakarta.annotation.Resource; |
| 13 | 15 | import lombok.Setter; |
| 14 | 16 | import lombok.extern.slf4j.Slf4j; |
| 15 | 17 | import org.flowable.engine.delegate.DelegateExecution; |
| 16 | 18 | import org.flowable.engine.delegate.ExecutionListener; |
| 17 | 19 | import org.flowable.engine.impl.el.FixedValue; |
| 18 | -import org.flowable.engine.impl.persistence.entity.ExecutionEntity; | |
| 20 | +import org.flowable.engine.runtime.ProcessInstance; | |
| 19 | 21 | import org.springframework.stereotype.Component; |
| 20 | 22 | |
| 21 | 23 | import java.util.List; |
| ... | ... | @@ -37,30 +39,32 @@ public class BpmCallActivityListener implements ExecutionListener { |
| 37 | 39 | @Resource |
| 38 | 40 | private BpmProcessDefinitionService processDefinitionService; |
| 39 | 41 | |
| 42 | + @Resource | |
| 43 | + private BpmProcessInstanceService processInstanceService; | |
| 44 | + | |
| 40 | 45 | @Override |
| 41 | 46 | public void notify(DelegateExecution execution) { |
| 42 | 47 | String expressionText = listenerConfig.getExpressionText(); |
| 43 | 48 | Assert.notNull(expressionText, "监听器扩展字段({})不能为空", expressionText); |
| 44 | 49 | BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting startUserSetting = JsonUtils.parseObject( |
| 45 | 50 | expressionText, BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting.class); |
| 51 | + ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getRootProcessInstanceId()); | |
| 46 | 52 | |
| 47 | 53 | // 1. 当发起人来源为主流程发起人时,并兜底 startUserSetting 为空时 |
| 48 | 54 | if (startUserSetting == null |
| 49 | 55 | || startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.MAIN_PROCESS_START_USER.getType())) { |
| 50 | - ExecutionEntity parent = (ExecutionEntity) execution.getParent(); | |
| 51 | - FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); | |
| 56 | + FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId())); | |
| 52 | 57 | return; |
| 53 | 58 | } |
| 54 | 59 | |
| 55 | 60 | // 2. 当发起人来源为表单时 |
| 56 | 61 | if (startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.FROM_FORM.getType())) { |
| 57 | - ExecutionEntity parent = (ExecutionEntity) execution.getParent(); | |
| 58 | - String formFieldValue = parent.getVariable(startUserSetting.getFormField(), String.class); | |
| 62 | + String formFieldValue = MapUtil.getStr(processInstance.getProcessVariables(), startUserSetting.getFormField()); | |
| 59 | 63 | // 2.1 当表单值为空时 |
| 60 | 64 | if (StrUtil.isEmpty(formFieldValue)) { |
| 61 | 65 | // 2.1.1 来自主流程发起人 |
| 62 | 66 | if (startUserSetting.getEmptyType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_START_USER.getType())) { |
| 63 | - FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); | |
| 67 | + FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId())); | |
| 64 | 68 | return; |
| 65 | 69 | } |
| 66 | 70 | // 2.1.2 来自子流程管理员 |
| ... | ... | @@ -72,7 +76,7 @@ public class BpmCallActivityListener implements ExecutionListener { |
| 72 | 76 | } |
| 73 | 77 | // 2.1.3 来自主流程管理员 |
| 74 | 78 | if (startUserSetting.getEmptyType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_ADMIN.getType())) { |
| 75 | - BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(parent.getProcessDefinitionId()); | |
| 79 | + BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(processInstance.getProcessDefinitionId()); | |
| 76 | 80 | List<Long> managerUserIds = processDefinition.getManagerUserIds(); |
| 77 | 81 | FlowableUtils.setAuthenticatedUserId(managerUserIds.get(0)); |
| 78 | 82 | return; |
| ... | ... | @@ -84,7 +88,7 @@ public class BpmCallActivityListener implements ExecutionListener { |
| 84 | 88 | } catch (Exception e) { |
| 85 | 89 | log.error("[notify][监听器:{},子流程监听器设置流程的发起人字符串转 Long 失败,字符串:{}]", |
| 86 | 90 | DELEGATE_EXPRESSION, formFieldValue); |
| 87 | - FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); | |
| 91 | + FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId())); | |
| 88 | 92 | } |
| 89 | 93 | } |
| 90 | 94 | } | ... | ... |