feat: 子流程-多实例
This commit is contained in:
parent
9c9f2812e9
commit
8a9d64bbaf
|
@ -0,0 +1,36 @@
|
||||||
|
package cn.iocoder.yudao.module.bpm.enums.definition;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BPM 子流程多实例来源类型枚举
|
||||||
|
*
|
||||||
|
* @author Lesan
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum BpmChildProcessMultiInstanceSourceTypeEnum implements ArrayValuable<Integer> {
|
||||||
|
|
||||||
|
FIXED_QUANTITY(1, "固定数量"),
|
||||||
|
DIGITAL_FORM(2, "数字表单"),
|
||||||
|
MULTI_FORM(3, "多项表单");
|
||||||
|
|
||||||
|
private final Integer type;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static final Integer[] ARRAYS = Arrays.stream(values()).map(BpmChildProcessMultiInstanceSourceTypeEnum::getType).toArray(Integer[]::new);
|
||||||
|
|
||||||
|
public static BpmChildProcessMultiInstanceSourceTypeEnum typeOf(Integer type) {
|
||||||
|
return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer[] array() {
|
||||||
|
return ARRAYS;
|
||||||
|
}
|
||||||
|
}
|
|
@ -452,6 +452,9 @@ public class BpmSimpleModelNodeVO {
|
||||||
@Schema(description = "超时设置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
|
@Schema(description = "超时设置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
|
||||||
private TimeoutSetting timeoutSetting;
|
private TimeoutSetting timeoutSetting;
|
||||||
|
|
||||||
|
@Schema(description = "多实例设置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
|
||||||
|
private MultiInstanceSetting multiInstanceSetting;
|
||||||
|
|
||||||
@Schema(description = "子流程发起人配置")
|
@Schema(description = "子流程发起人配置")
|
||||||
@Data
|
@Data
|
||||||
@Valid
|
@Valid
|
||||||
|
@ -490,5 +493,33 @@ public class BpmSimpleModelNodeVO {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Schema(description = "多实例设置")
|
||||||
|
@Data
|
||||||
|
@Valid
|
||||||
|
public static class MultiInstanceSetting {
|
||||||
|
|
||||||
|
@Schema(description = "是否开启多实例", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||||
|
@NotNull(message = "是否开启多实例不能为空")
|
||||||
|
private Boolean enable;
|
||||||
|
|
||||||
|
@Schema(description = "是否串行", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||||
|
@NotNull(message = "是否串行不能为空")
|
||||||
|
private Boolean sequential;
|
||||||
|
|
||||||
|
@Schema(description = "完成比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||||
|
@NotNull(message = "完成比例不能为空")
|
||||||
|
private Integer completeRatio;
|
||||||
|
|
||||||
|
@Schema(description = "多实例来源类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "多实例来源类型不能为空")
|
||||||
|
@InEnum(BpmChildProcessMultiInstanceSourceTypeEnum.class)
|
||||||
|
private Integer sourceType;
|
||||||
|
|
||||||
|
@Schema(description = "多实例来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "多实例来源不能为空")
|
||||||
|
private String source;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmChildProcessMultiInstanceSourceTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.flowable.bpmn.model.Activity;
|
import org.flowable.bpmn.model.Activity;
|
||||||
|
import org.flowable.bpmn.model.CallActivity;
|
||||||
|
import org.flowable.bpmn.model.FlowElement;
|
||||||
|
import org.flowable.bpmn.model.UserTask;
|
||||||
import org.flowable.engine.delegate.DelegateExecution;
|
import org.flowable.engine.delegate.DelegateExecution;
|
||||||
import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
|
import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
|
||||||
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
|
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,27 +48,42 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected int resolveNrOfInstances(DelegateExecution execution) {
|
protected int resolveNrOfInstances(DelegateExecution execution) {
|
||||||
// 第一步,设置 collectionVariable 和 CollectionVariable
|
if (execution.getCurrentFlowElement() instanceof UserTask) {
|
||||||
// 从 execution.getVariable() 读取所有任务处理人的 key
|
// 第一步,设置 collectionVariable 和 CollectionVariable
|
||||||
super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的
|
// 从 execution.getVariable() 读取所有任务处理人的 key
|
||||||
super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId());
|
super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的
|
||||||
// 从 execution.getVariable() 读取当前所有任务处理的人的 key
|
super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId());
|
||||||
super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId());
|
// 从 execution.getVariable() 读取当前所有任务处理的人的 key
|
||||||
|
super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId());
|
||||||
|
|
||||||
// 第二步,获取任务的所有处理人
|
// 第二步,获取任务的所有处理人
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class);
|
Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class);
|
||||||
if (assigneeUserIds == null) {
|
if (assigneeUserIds == null) {
|
||||||
assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
|
assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
|
||||||
if (CollUtil.isEmpty(assigneeUserIds)) {
|
if (CollUtil.isEmpty(assigneeUserIds)) {
|
||||||
// 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过!
|
// 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过!
|
||||||
// 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务
|
// 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务
|
||||||
// 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时
|
// 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时
|
||||||
assigneeUserIds = SetUtils.asSet((Long) null);
|
assigneeUserIds = SetUtils.asSet((Long) null);
|
||||||
|
}
|
||||||
|
execution.setVariableLocal(super.collectionVariable, assigneeUserIds);
|
||||||
}
|
}
|
||||||
execution.setVariableLocal(super.collectionVariable, assigneeUserIds);
|
return assigneeUserIds.size();
|
||||||
}
|
}
|
||||||
return assigneeUserIds.size();
|
|
||||||
|
if (execution.getCurrentFlowElement() instanceof CallActivity) {
|
||||||
|
FlowElement flowElement = execution.getCurrentFlowElement();
|
||||||
|
Integer sourceType = BpmnModelUtils.parseMultiInstanceSourceType(flowElement);
|
||||||
|
if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType())) {
|
||||||
|
return execution.getVariable(super.collectionExpression.getExpressionText(), Integer.class);
|
||||||
|
}
|
||||||
|
if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) {
|
||||||
|
return execution.getVariable(super.collectionExpression.getExpressionText(), List.class).size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.resolveNrOfInstances(execution);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,20 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmChildProcessMultiInstanceSourceTypeEnum;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.flowable.bpmn.model.Activity;
|
import org.flowable.bpmn.model.Activity;
|
||||||
|
import org.flowable.bpmn.model.CallActivity;
|
||||||
|
import org.flowable.bpmn.model.FlowElement;
|
||||||
|
import org.flowable.bpmn.model.UserTask;
|
||||||
import org.flowable.engine.delegate.DelegateExecution;
|
import org.flowable.engine.delegate.DelegateExecution;
|
||||||
import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
|
import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
|
||||||
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
|
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,28 +41,43 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected int resolveNrOfInstances(DelegateExecution execution) {
|
protected int resolveNrOfInstances(DelegateExecution execution) {
|
||||||
// 第一步,设置 collectionVariable 和 CollectionVariable
|
if (execution.getCurrentFlowElement() instanceof UserTask) {
|
||||||
// 从 execution.getVariable() 读取所有任务处理人的 key
|
// 第一步,设置 collectionVariable 和 CollectionVariable
|
||||||
super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的
|
// 从 execution.getVariable() 读取所有任务处理人的 key
|
||||||
super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId());
|
super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的
|
||||||
// 从 execution.getVariable() 读取当前所有任务处理的人的 key
|
super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId());
|
||||||
super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId());
|
// 从 execution.getVariable() 读取当前所有任务处理的人的 key
|
||||||
|
super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId());
|
||||||
|
|
||||||
// 第二步,获取任务的所有处理人
|
// 第二步,获取任务的所有处理人
|
||||||
// 不使用 execution.getVariable 原因:目前依次审批任务回退后 collectionVariable 变量没有清理, 如果重新进入该任务不会重新分配审批人
|
// 不使用 execution.getVariable 原因:目前依次审批任务回退后 collectionVariable 变量没有清理, 如果重新进入该任务不会重新分配审批人
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Set<Long> assigneeUserIds = (Set<Long>) execution.getVariableLocal(super.collectionVariable, Set.class);
|
Set<Long> assigneeUserIds = (Set<Long>) execution.getVariableLocal(super.collectionVariable, Set.class);
|
||||||
if (assigneeUserIds == null) {
|
if (assigneeUserIds == null) {
|
||||||
assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
|
assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
|
||||||
if (CollUtil.isEmpty(assigneeUserIds)) {
|
if (CollUtil.isEmpty(assigneeUserIds)) {
|
||||||
// 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过!
|
// 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过!
|
||||||
// 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务
|
// 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务
|
||||||
// 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时
|
// 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时
|
||||||
assigneeUserIds = SetUtils.asSet((Long) null);
|
assigneeUserIds = SetUtils.asSet((Long) null);
|
||||||
|
}
|
||||||
|
execution.setVariableLocal(super.collectionVariable, assigneeUserIds);
|
||||||
}
|
}
|
||||||
execution.setVariableLocal(super.collectionVariable, assigneeUserIds);
|
return assigneeUserIds.size();
|
||||||
}
|
}
|
||||||
return assigneeUserIds.size();
|
|
||||||
|
if (execution.getCurrentFlowElement() instanceof CallActivity) {
|
||||||
|
FlowElement flowElement = execution.getCurrentFlowElement();
|
||||||
|
Integer sourceType = BpmnModelUtils.parseMultiInstanceSourceType(flowElement);
|
||||||
|
if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType())) {
|
||||||
|
return execution.getVariable(super.collectionExpression.getExpressionText(), Integer.class);
|
||||||
|
}
|
||||||
|
if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) {
|
||||||
|
return execution.getVariable(super.collectionExpression.getExpressionText(), List.class).size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.resolveNrOfInstances(execution);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,11 @@ public interface BpmnModelConstants {
|
||||||
*/
|
*/
|
||||||
String USER_TASK_APPROVE_METHOD = "approveMethod";
|
String USER_TASK_APPROVE_METHOD = "approveMethod";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BPMN Child Process 的扩展属性,用于标记多实例来源类型
|
||||||
|
*/
|
||||||
|
String CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE = "childProcessMultiInstanceSourceType";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BPMN ExtensionElement 流程表单字段权限元素, 用于标记字段权限
|
* BPMN ExtensionElement 流程表单字段权限元素, 用于标记字段权限
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -158,6 +158,17 @@ public class BpmnModelUtils {
|
||||||
return NumberUtils.parseInt(parseExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_TYPE));
|
return NumberUtils.parseInt(parseExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_TYPE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析子流程多实例来源类型
|
||||||
|
*
|
||||||
|
* @see BpmChildProcessMultiInstanceSourceTypeEnum
|
||||||
|
* @param element 任务节点
|
||||||
|
* @return 多实例来源类型
|
||||||
|
*/
|
||||||
|
public static Integer parseMultiInstanceSourceType(FlowElement element) {
|
||||||
|
return NumberUtils.parseInt(parseExtensionElement(element, BpmnModelConstants.CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加任务拒绝处理元素
|
* 添加任务拒绝处理元素
|
||||||
*
|
*
|
||||||
|
|
|
@ -853,18 +853,35 @@ public class SimpleModelUtils {
|
||||||
callActivity.setExecutionListeners(executionListeners);
|
callActivity.setExecutionListeners(executionListeners);
|
||||||
|
|
||||||
// 7. 超时设置
|
// 7. 超时设置
|
||||||
if (childProcessSetting.getTimeoutSetting() != null) {
|
if (childProcessSetting.getTimeoutSetting() != null && Boolean.TRUE.equals(childProcessSetting.getTimeoutSetting().getEnable())) {
|
||||||
BoundaryEvent boundaryEvent = null;
|
BoundaryEvent boundaryEvent = null;
|
||||||
if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerTypeEnum.FIXED_DATE_TIME.getType())) {
|
if (childProcessSetting.getTimeoutSetting().getType().equals(BpmDelayTimerTypeEnum.FIXED_DATE_TIME.getType())) {
|
||||||
boundaryEvent = buildTimeoutBoundaryEvent(callActivity, BpmBoundaryEventTypeEnum.DELAY_TIMER_TIMEOUT.getType(),
|
boundaryEvent = buildTimeoutBoundaryEvent(callActivity, BpmBoundaryEventTypeEnum.DELAY_TIMER_TIMEOUT.getType(),
|
||||||
node.getDelaySetting().getDelayTime(), null, null);
|
childProcessSetting.getTimeoutSetting().getTimeExpression(), null, null);
|
||||||
} else if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerTypeEnum.FIXED_TIME_DURATION.getType())) {
|
} else if (childProcessSetting.getTimeoutSetting().getType().equals(BpmDelayTimerTypeEnum.FIXED_TIME_DURATION.getType())) {
|
||||||
boundaryEvent = buildTimeoutBoundaryEvent(callActivity, BpmBoundaryEventTypeEnum.CHILD_PROCESS_TIMEOUT.getType(),
|
boundaryEvent = buildTimeoutBoundaryEvent(callActivity, BpmBoundaryEventTypeEnum.CHILD_PROCESS_TIMEOUT.getType(),
|
||||||
null, null, node.getDelaySetting().getDelayTime());
|
null, null, childProcessSetting.getTimeoutSetting().getTimeExpression());
|
||||||
}
|
}
|
||||||
flowElements.add(boundaryEvent);
|
flowElements.add(boundaryEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 8. 多实例
|
||||||
|
if (childProcessSetting.getMultiInstanceSetting() != null && Boolean.TRUE.equals(childProcessSetting.getMultiInstanceSetting().getEnable())) {
|
||||||
|
MultiInstanceLoopCharacteristics multiInstanceCharacteristics = new MultiInstanceLoopCharacteristics();
|
||||||
|
multiInstanceCharacteristics.setSequential(childProcessSetting.getMultiInstanceSetting().getSequential());
|
||||||
|
if (childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.FIXED_QUANTITY.getType())) {
|
||||||
|
multiInstanceCharacteristics.setLoopCardinality(childProcessSetting.getMultiInstanceSetting().getSource());
|
||||||
|
}
|
||||||
|
if (childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType()) ||
|
||||||
|
childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) {
|
||||||
|
multiInstanceCharacteristics.setInputDataItem(childProcessSetting.getMultiInstanceSetting().getSource());
|
||||||
|
}
|
||||||
|
multiInstanceCharacteristics.setCompletionCondition(String.format("${ nrOfCompletedInstances/nrOfInstances >= %s}",
|
||||||
|
String.format("%.2f", childProcessSetting.getMultiInstanceSetting().getCompleteRatio() / 100D)));
|
||||||
|
callActivity.setLoopCharacteristics(multiInstanceCharacteristics);
|
||||||
|
addExtensionElement(callActivity, CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE, childProcessSetting.getMultiInstanceSetting().getSourceType());
|
||||||
|
}
|
||||||
|
|
||||||
// 添加节点类型
|
// 添加节点类型
|
||||||
addNodeType(node.getType(), callActivity);
|
addNodeType(node.getType(), callActivity);
|
||||||
flowElements.add(callActivity);
|
flowElements.add(callActivity);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package cn.iocoder.yudao.module.bpm.service.task.listener;
|
package cn.iocoder.yudao.module.bpm.service.task.listener;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
|
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
|
||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmChildProcessStartUserTypeEnum;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmChildProcessStartUserTypeEnum;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
|
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
|
||||||
|
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.flowable.engine.delegate.DelegateExecution;
|
import org.flowable.engine.delegate.DelegateExecution;
|
||||||
import org.flowable.engine.delegate.ExecutionListener;
|
import org.flowable.engine.delegate.ExecutionListener;
|
||||||
import org.flowable.engine.impl.el.FixedValue;
|
import org.flowable.engine.impl.el.FixedValue;
|
||||||
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
|
import org.flowable.engine.runtime.ProcessInstance;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -37,30 +39,32 @@ public class BpmCallActivityListener implements ExecutionListener {
|
||||||
@Resource
|
@Resource
|
||||||
private BpmProcessDefinitionService processDefinitionService;
|
private BpmProcessDefinitionService processDefinitionService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BpmProcessInstanceService processInstanceService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notify(DelegateExecution execution) {
|
public void notify(DelegateExecution execution) {
|
||||||
String expressionText = listenerConfig.getExpressionText();
|
String expressionText = listenerConfig.getExpressionText();
|
||||||
Assert.notNull(expressionText, "监听器扩展字段({})不能为空", expressionText);
|
Assert.notNull(expressionText, "监听器扩展字段({})不能为空", expressionText);
|
||||||
BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting startUserSetting = JsonUtils.parseObject(
|
BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting startUserSetting = JsonUtils.parseObject(
|
||||||
expressionText, BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting.class);
|
expressionText, BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting.class);
|
||||||
|
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getRootProcessInstanceId());
|
||||||
|
|
||||||
// 1. 当发起人来源为主流程发起人时,并兜底 startUserSetting 为空时
|
// 1. 当发起人来源为主流程发起人时,并兜底 startUserSetting 为空时
|
||||||
if (startUserSetting == null
|
if (startUserSetting == null
|
||||||
|| startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.MAIN_PROCESS_START_USER.getType())) {
|
|| startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.MAIN_PROCESS_START_USER.getType())) {
|
||||||
ExecutionEntity parent = (ExecutionEntity) execution.getParent();
|
FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId()));
|
||||||
FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId()));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 当发起人来源为表单时
|
// 2. 当发起人来源为表单时
|
||||||
if (startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.FROM_FORM.getType())) {
|
if (startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.FROM_FORM.getType())) {
|
||||||
ExecutionEntity parent = (ExecutionEntity) execution.getParent();
|
String formFieldValue = MapUtil.getStr(processInstance.getProcessVariables(), startUserSetting.getFormField());
|
||||||
String formFieldValue = parent.getVariable(startUserSetting.getFormField(), String.class);
|
|
||||||
// 2.1 当表单值为空时
|
// 2.1 当表单值为空时
|
||||||
if (StrUtil.isEmpty(formFieldValue)) {
|
if (StrUtil.isEmpty(formFieldValue)) {
|
||||||
// 2.1.1 来自主流程发起人
|
// 2.1.1 来自主流程发起人
|
||||||
if (startUserSetting.getEmptyType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_START_USER.getType())) {
|
if (startUserSetting.getEmptyType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_START_USER.getType())) {
|
||||||
FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId()));
|
FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 2.1.2 来自子流程管理员
|
// 2.1.2 来自子流程管理员
|
||||||
|
@ -72,7 +76,7 @@ public class BpmCallActivityListener implements ExecutionListener {
|
||||||
}
|
}
|
||||||
// 2.1.3 来自主流程管理员
|
// 2.1.3 来自主流程管理员
|
||||||
if (startUserSetting.getEmptyType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_ADMIN.getType())) {
|
if (startUserSetting.getEmptyType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_ADMIN.getType())) {
|
||||||
BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(parent.getProcessDefinitionId());
|
BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(processInstance.getProcessDefinitionId());
|
||||||
List<Long> managerUserIds = processDefinition.getManagerUserIds();
|
List<Long> managerUserIds = processDefinition.getManagerUserIds();
|
||||||
FlowableUtils.setAuthenticatedUserId(managerUserIds.get(0));
|
FlowableUtils.setAuthenticatedUserId(managerUserIds.get(0));
|
||||||
return;
|
return;
|
||||||
|
@ -84,7 +88,7 @@ public class BpmCallActivityListener implements ExecutionListener {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[notify][监听器:{},子流程监听器设置流程的发起人字符串转 Long 失败,字符串:{}]",
|
log.error("[notify][监听器:{},子流程监听器设置流程的发起人字符串转 Long 失败,字符串:{}]",
|
||||||
DELEGATE_EXPRESSION, formFieldValue);
|
DELEGATE_EXPRESSION, formFieldValue);
|
||||||
FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId()));
|
FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue