瀏覽代碼

fix:【BPM 工作流】子流程支持流程 title 自定义标题

YunaiV 3 月之前
父節點
當前提交
b766f8d820

+ 13 - 4
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener;
 
+import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 import com.google.common.collect.ImmutableSet;
 import jakarta.annotation.Resource;
@@ -37,18 +38,26 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent
 
     @Override
     protected void processCreated(FlowableEngineEntityEvent event) {
-        processInstanceService.processProcessInstanceCreated((ProcessInstance)event.getEntity());
+        ProcessInstance processInstance = (ProcessInstance) event.getEntity();
+        FlowableUtils.execute(processInstance.getTenantId(),
+                () -> processInstanceService.processProcessInstanceCreated(processInstance));
     }
 
     @Override
     protected void processCompleted(FlowableEngineEntityEvent event) {
-        processInstanceService.processProcessInstanceCompleted((ProcessInstance)event.getEntity());
+        ProcessInstance processInstance = (ProcessInstance) event.getEntity();
+        FlowableUtils.execute(processInstance.getTenantId(),
+                () -> processInstanceService.processProcessInstanceCompleted(processInstance));
     }
 
-    @Override // 特殊情况:当跳转到 EndEvent 流程实例未结束, 会执行 deleteProcessInstance 方法
+    @Override
     protected void processCancelled(FlowableCancelledEvent event) {
+        // 特殊情况:当跳转到 EndEvent 流程实例未结束, 会执行 deleteProcessInstance 方法
         ProcessInstance processInstance = processInstanceService.getProcessInstance(event.getProcessInstanceId());
-        processInstanceService.processProcessInstanceCompleted(processInstance);
+        if (processInstance != null) {
+            FlowableUtils.execute(processInstance.getTenantId(),
+                    () -> processInstanceService.processProcessInstanceCompleted(processInstance));
+        }
     }
 
 }

+ 89 - 68
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java

@@ -4,10 +4,7 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.lang.Assert;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.ObjUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.*;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
@@ -61,6 +58,8 @@ import org.flowable.task.api.history.HistoricTaskInstance;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.support.TransactionSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
 import org.springframework.validation.annotation.Validated;
 
 import java.util.*;
@@ -244,7 +243,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
         if (historicProcessInstance == null) {
             throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS);
         }
-        // 1.3 校验 BpmnModel
+        // 1.3 校验BpmnModel
         BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(task.getProcessDefinitionId());
         if (bpmnModel == null) {
             return null;
@@ -449,7 +448,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
                         .setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus)
                         .setStartTime(DateUtils.of(activity.getStartTime()))
                         .setEndTime(DateUtils.of(activity.getEndTime()))
-                        .setProcessInstanceId(activity.getCalledProcessInstanceId());
+                        .setProcessInstanceId(activity.getProcessInstanceId());
                 approvalNodes.add(callActivity);
             }
         });
@@ -521,7 +520,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
                 activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size()));
             }
             if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) {
-                activityNode.setProcessInstanceId(firstActivity.getCalledProcessInstanceId());
+                activityNode.setProcessInstanceId(firstActivity.getProcessInstanceId());
             }
             return activityNode;
         });
@@ -771,17 +770,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
             processInstanceBuilder.predefineProcessInstanceId(processIdRedisDAO.generate(processIdRule));
         }
         // 3.2 流程名称
-        BpmModelMetaInfoVO.TitleSetting titleSetting = processDefinitionInfo.getTitleSetting();
-        if (titleSetting != null && Boolean.TRUE.equals(titleSetting.getEnable())) {
-            AdminUserRespDTO user = adminUserApi.getUser(userId);
-            Map<String, Object> cloneVariables = new HashMap<>(variables);
-            cloneVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, user.getNickname());
-            cloneVariables.put(BpmnVariableConstants.PROCESS_START_TIME, DateUtil.now());
-            cloneVariables.put(BpmnVariableConstants.PROCESS_DEFINITION_NAME, definition.getName().trim());
-            processInstanceBuilder.name(StrUtil.format(titleSetting.getTitle(), cloneVariables));
-        } else {
-            processInstanceBuilder.name(definition.getName().trim());
-        }
+        processInstanceBuilder.name(generateProcessInstanceName(userId, definition, processDefinitionInfo, variables));
         // 3.3 发起流程实例
         ProcessInstance instance = processInstanceBuilder.start();
         return instance.getId();
@@ -817,6 +806,25 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
         });
     }
 
+    private String generateProcessInstanceName(Long userId,
+                                               ProcessDefinition definition,
+                                               BpmProcessDefinitionInfoDO definitionInfo,
+                                               Map<String, Object> variables) {
+        if (definition == null || definitionInfo == null) {
+            return null;
+        }
+        BpmModelMetaInfoVO.TitleSetting titleSetting = definitionInfo.getTitleSetting();
+        if (titleSetting == null || !BooleanUtil.isTrue(titleSetting.getEnable())) {
+            return definition.getName();
+        }
+        AdminUserRespDTO user = adminUserApi.getUser(userId);
+        Map<String, Object> cloneVariables = new HashMap<>(variables);
+        cloneVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, user.getNickname());
+        cloneVariables.put(BpmnVariableConstants.PROCESS_START_TIME, DateUtil.now());
+        cloneVariables.put(BpmnVariableConstants.PROCESS_DEFINITION_NAME, definition.getName().trim());
+        return StrUtil.format(definitionInfo.getTitleSetting().getTitle(), cloneVariables);
+    }
+
     @Override
     public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) {
         // 1.1 校验流程实例存在
@@ -833,7 +841,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
                 .getProcessDefinitionInfo(instance.getProcessDefinitionId());
         Assert.notNull(processDefinitionInfo, "流程定义({})不存在", processDefinitionInfo);
         if (processDefinitionInfo.getAllowCancelRunningProcess() != null // 防止未配置 AllowCancelRunningProcess , 默认为可取消
-                && Boolean.FALSE.equals(processDefinitionInfo.getAllowCancelRunningProcess())) {
+                && BooleanUtil.isFalse(processDefinitionInfo.getAllowCancelRunningProcess())) {
             throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW);
         }
         // 1.4 子流程不允许取消
@@ -900,64 +908,77 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
 
     @Override
     public void processProcessInstanceCompleted(ProcessInstance instance) {
-        // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号
-        FlowableUtils.execute(instance.getTenantId(), () -> {
-            // 1.1 获取当前状态
-            Integer status = (Integer) instance.getProcessVariables()
-                    .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
-            String reason = (String) instance.getProcessVariables()
-                    .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON);
-            // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态
-            // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了
-            if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) {
-                status = BpmProcessInstanceStatusEnum.APPROVE.getStatus();
-                runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS,
-                        status);
-            }
+        // 1.1 获取当前状态
+        Integer status = (Integer) instance.getProcessVariables()
+                .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
+        String reason = (String) instance.getProcessVariables()
+                .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON);
+        // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态
+        // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了
+        if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) {
+            status = BpmProcessInstanceStatusEnum.APPROVE.getStatus();
+            runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS,
+                    status);
+        }
+
+        // 2. 发送对应的消息通知
+        if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
+            messageService.sendMessageWhenProcessInstanceApprove(
+                    BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance));
+        } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) {
+            messageService.sendMessageWhenProcessInstanceReject(
+                    BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason));
+        }
+
+        // 3. 发送流程实例的状态事件
+        processInstanceEventPublisher.sendProcessInstanceResultEvent(
+                BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status));
+
+        // 4. 流程后置通知
+        if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
+            BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.
+                    getProcessDefinitionInfo(instance.getProcessDefinitionId());
+            if (ObjUtil.isNotNull(processDefinitionInfo) &&
+                    ObjUtil.isNotNull(processDefinitionInfo.getProcessAfterTriggerSetting())) {
+                BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessAfterTriggerSetting();
 
-            // 2. 发送对应的消息通知
-            if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
-                messageService.sendMessageWhenProcessInstanceApprove(
-                        BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance));
-            } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) {
-                messageService.sendMessageWhenProcessInstanceReject(
-                        BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason));
+                BpmHttpRequestUtils.executeBpmHttpRequest(instance,
+                        setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
             }
+        }
+    }
 
-            // 3. 发送流程实例的状态事件
-            processInstanceEventPublisher.sendProcessInstanceResultEvent(
-                    BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status));
+    @Override
+    public void processProcessInstanceCreated(ProcessInstance instance) {
+        BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.
+                getProcessDefinitionInfo(instance.getProcessDefinitionId());
+        ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(instance.getProcessDefinitionId());
+        if (processDefinition == null || processDefinitionInfo == null) {
+            return;
+        }
 
-            // 4. 流程后置通知
-            if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
-                BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.
-                        getProcessDefinitionInfo(instance.getProcessDefinitionId());
-                if (ObjUtil.isNotNull(processDefinitionInfo) &&
-                        ObjUtil.isNotNull(processDefinitionInfo.getProcessAfterTriggerSetting())) {
-                    BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessAfterTriggerSetting();
+        // 自定义标题。目的:主要处理子流程的标题无法处理
+        // 注意:必须使用 TransactionSynchronizationManager 事务提交后,否则不生效!!!
+        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
 
-                    BpmHttpRequestUtils.executeBpmHttpRequest(instance,
-                            setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
+            @Override
+            public void afterCommit() {
+                String name = generateProcessInstanceName(Long.valueOf(instance.getStartUserId()),
+                        processDefinition, processDefinitionInfo, instance.getProcessVariables());
+                if (ObjUtil.notEqual(instance.getName(), name)) {
+                    runtimeService.setProcessInstanceName(instance.getProcessInstanceId(), name);
                 }
             }
-        });
-    }
 
-    @Override
-    public void processProcessInstanceCreated(ProcessInstance instance) {
-        // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号
-        FlowableUtils.execute(instance.getTenantId(), () -> {
-            // 流程前置通知
-            BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.
-                    getProcessDefinitionInfo(instance.getProcessDefinitionId());
-            if (ObjUtil.isNull(processDefinitionInfo) ||
-                    ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) {
-                return;
-            }
-            BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting();
-            BpmHttpRequestUtils.executeBpmHttpRequest(instance,
-                    setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
         });
+
+        // 流程前置通知
+        if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) {
+            return;
+        }
+        BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting();
+        BpmHttpRequestUtils.executeBpmHttpRequest(instance,
+                setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
     }
 
 }