diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessStartUserEmptyTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessStartUserEmptyTypeEnum.java new file mode 100644 index 0000000000..55e6e02e87 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessStartUserEmptyTypeEnum.java @@ -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 BpmChildProcessStartUserEmptyTypeEnum implements ArrayValuable { + + MAIN_PROCESS_START_USER(1, "同主流程发起人"), + CHILD_PROCESS_ADMIN(2, "子流程管理员"), + MAIN_PROCESS_ADMIN(3, "主流程管理员"); + + private final Integer type; + private final String name; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(BpmChildProcessStartUserEmptyTypeEnum::getType).toArray(Integer[]::new); + + public static BpmChildProcessStartUserEmptyTypeEnum typeOf(Integer type) { + return ArrayUtil.firstMatch(item -> item.getType().equals(type), values()); + } + + @Override + public Integer[] array() { + return ARRAYS; + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessStartUserTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessStartUserTypeEnum.java new file mode 100644 index 0000000000..10d04ea4f4 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessStartUserTypeEnum.java @@ -0,0 +1,35 @@ +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 BpmChildProcessStartUserTypeEnum implements ArrayValuable { + + MAIN_PROCESS_START_USER(1, "同主流程发起人"), + FROM_FORM(2, "表单"); + + private final Integer type; + private final String name; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(BpmChildProcessStartUserTypeEnum::getType).toArray(Integer[]::new); + + public static BpmChildProcessStartUserTypeEnum typeOf(Integer type) { + return ArrayUtil.firstMatch(item -> item.getType().equals(type), values()); + } + + @Override + public Integer[] array() { + return ARRAYS; + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java index 23371b19d7..fc1cc2bb4a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java @@ -428,5 +428,27 @@ public class BpmSimpleModelNodeVO { @NotNull(message = "是否自动跳过子流程发起节点不能为空") private Boolean skipStartUserNode; + @Schema(description = "子流程发起人配置", example = "{}") + private StartUserSetting startUserSetting; + + @Schema(description = "子流程发起人配置") + @Data + @Valid + public static class StartUserSetting { + + @Schema(description = "子流程发起人类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "子流程发起人类型") + @InEnum(BpmChildProcessStartUserTypeEnum.class) + private Integer type; + + @Schema(description = "表单", example = "xxx") + private String formField; + + @Schema(description = "当子流程发起人为空时类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(BpmChildProcessStartUserEmptyTypeEnum.class) + private Integer emptyHandleType; + + } + } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java index a458567d81..998320eb58 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; @@ -240,7 +241,7 @@ public class FlowableUtils { return formFieldsMap.entrySet().stream() .limit(3) .map(entry -> new KeyValue<>(entry.getValue().getTitle(), - processVariables.getOrDefault(entry.getValue().getField(), "").toString())) + StrUtil.toStringOrEmpty(processVariables.getOrDefault(entry.getValue().getField(), "")))) .collect(Collectors.toList()); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index 18798bb3fb..fbc38cbeab 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java @@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.*; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +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.ConditionGroups; import cn.iocoder.yudao.module.bpm.enums.definition.*; @@ -16,6 +17,7 @@ import org.flowable.bpmn.BpmnAutoLayout; import org.flowable.bpmn.constants.BpmnXMLConstants; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; +import org.flowable.engine.delegate.ExecutionListener; import org.flowable.engine.delegate.TaskListener; import org.springframework.util.MultiValueMap; @@ -816,6 +818,18 @@ public class SimpleModelUtils { if (childProcessSetting.getOutVariable() != null && !childProcessSetting.getOutVariable().isEmpty()) { callActivity.setOutParameters(childProcessSetting.getOutVariable()); } + // 6. 子流程发起人配置 + List executionListeners = new ArrayList<>(); + FlowableListener flowableListener = new FlowableListener(); + flowableListener.setEvent(ExecutionListener.EVENTNAME_START); + flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); + flowableListener.setImplementation("${bpmCallActivityListener}"); + FieldExtension fieldExtension = new FieldExtension(); + fieldExtension.setFieldName("listenerConfig"); + fieldExtension.setStringValue(JsonUtils.toJsonString(childProcessSetting.getStartUserSetting())); + flowableListener.getFieldExtensions().add(fieldExtension); + executionListeners.add(flowableListener); + callActivity.setExecutionListeners(executionListeners); // 添加节点类型 addNodeType(node.getType(), callActivity); return callActivity; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java new file mode 100644 index 0000000000..fe34c6964f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.bpm.service.task.listener; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +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.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmChildProcessStartUserEmptyTypeEnum; +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.service.definition.BpmProcessDefinitionService; +import jakarta.annotation.Resource; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; +import org.flowable.engine.impl.el.FixedValue; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * BPM 子流程监听器 + * + * @author Lesan + */ +@Component +@Slf4j +public class BpmCallActivityListener implements ExecutionListener { + + public static final String DELEGATE_EXPRESSION = "${bpmCallActivityListener}"; + + @Setter + private FixedValue listenerConfig; + + @Resource + private BpmProcessDefinitionService processDefinitionService; + + @Override + public void notify(DelegateExecution execution) { + String expressionText = listenerConfig.getExpressionText(); + Assert.notNull(expressionText, "监听器扩展字段({})不能为空", expressionText); + BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting startUserSetting = JsonUtils.parseObject(expressionText, BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting.class); + // 1. 当发起人来源为表单时 + if (startUserSetting != null && + startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.FROM_FORM.getType())) { + ExecutionEntity parent = (ExecutionEntity) execution.getParent(); + String formField = parent.getVariable(startUserSetting.getFormField(), String.class); + // 1.1 当表单值为空时 + if (StrUtil.isEmpty(formField)) { + // 1.1.1 来自主流程发起人 + if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_START_USER.getType())){ + FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); + return; + } + // 1.1.2 来自子流程管理员 + if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.CHILD_PROCESS_ADMIN.getType())){ + BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(execution.getProcessDefinitionId()); + List managerUserIds = processDefinition.getManagerUserIds(); + FlowableUtils.setAuthenticatedUserId(Convert.toLong(managerUserIds.get(0))); + return; + } + // 1.1.3 来自主流程管理员 + if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_ADMIN.getType())){ + BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(parent.getProcessDefinitionId()); + List managerUserIds = processDefinition.getManagerUserIds(); + FlowableUtils.setAuthenticatedUserId(Convert.toLong(managerUserIds.get(0))); + return; + } + } + // 1.2 使用表单值,并兜底字符串转Long失败时使用主流程发起人 + try { + FlowableUtils.setAuthenticatedUserId(Long.parseLong(formField)); + } catch (Exception e) { + FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); + } + } + // 2. 当发起人来源为主流程发起人时,并兜底startUserSetting为空时 + if (startUserSetting == null || + startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.MAIN_PROCESS_START_USER.getType())) { + ExecutionEntity parent = (ExecutionEntity) execution.getParent(); + FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); + } + } + +} \ No newline at end of file