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

This commit is contained in:
YunaiV
2025-07-22 20:15:52 +08:00
parent 7ba084bc4d
commit b766f8d820
2 changed files with 104 additions and 74 deletions

View File

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

View File

@@ -4,10 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil; import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.*;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 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.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; 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 org.springframework.validation.annotation.Validated;
import java.util.*; import java.util.*;
@@ -449,7 +448,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
.setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus) .setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus)
.setStartTime(DateUtils.of(activity.getStartTime())) .setStartTime(DateUtils.of(activity.getStartTime()))
.setEndTime(DateUtils.of(activity.getEndTime())) .setEndTime(DateUtils.of(activity.getEndTime()))
.setProcessInstanceId(activity.getCalledProcessInstanceId()); .setProcessInstanceId(activity.getProcessInstanceId());
approvalNodes.add(callActivity); approvalNodes.add(callActivity);
} }
}); });
@@ -521,7 +520,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size())); activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size()));
} }
if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) { if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) {
activityNode.setProcessInstanceId(firstActivity.getCalledProcessInstanceId()); activityNode.setProcessInstanceId(firstActivity.getProcessInstanceId());
} }
return activityNode; return activityNode;
}); });
@@ -771,17 +770,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
processInstanceBuilder.predefineProcessInstanceId(processIdRedisDAO.generate(processIdRule)); processInstanceBuilder.predefineProcessInstanceId(processIdRedisDAO.generate(processIdRule));
} }
// 3.2 流程名称 // 3.2 流程名称
BpmModelMetaInfoVO.TitleSetting titleSetting = processDefinitionInfo.getTitleSetting(); processInstanceBuilder.name(generateProcessInstanceName(userId, definition, processDefinitionInfo, variables));
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());
}
// 3.3 发起流程实例 // 3.3 发起流程实例
ProcessInstance instance = processInstanceBuilder.start(); ProcessInstance instance = processInstanceBuilder.start();
return instance.getId(); 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 @Override
public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) {
// 1.1 校验流程实例存在 // 1.1 校验流程实例存在
@@ -833,7 +841,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
.getProcessDefinitionInfo(instance.getProcessDefinitionId()); .getProcessDefinitionInfo(instance.getProcessDefinitionId());
Assert.notNull(processDefinitionInfo, "流程定义({})不存在", processDefinitionInfo); Assert.notNull(processDefinitionInfo, "流程定义({})不存在", processDefinitionInfo);
if (processDefinitionInfo.getAllowCancelRunningProcess() != null // 防止未配置 AllowCancelRunningProcess , 默认为可取消 if (processDefinitionInfo.getAllowCancelRunningProcess() != null // 防止未配置 AllowCancelRunningProcess , 默认为可取消
&& Boolean.FALSE.equals(processDefinitionInfo.getAllowCancelRunningProcess())) { && BooleanUtil.isFalse(processDefinitionInfo.getAllowCancelRunningProcess())) {
throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW); throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW);
} }
// 1.4 子流程不允许取消 // 1.4 子流程不允许取消
@@ -900,8 +908,6 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
@Override @Override
public void processProcessInstanceCompleted(ProcessInstance instance) { public void processProcessInstanceCompleted(ProcessInstance instance) {
// 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号
FlowableUtils.execute(instance.getTenantId(), () -> {
// 1.1 获取当前状态 // 1.1 获取当前状态
Integer status = (Integer) instance.getProcessVariables() Integer status = (Integer) instance.getProcessVariables()
.get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS); .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
@@ -940,24 +946,39 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
} }
} }
});
} }
@Override @Override
public void processProcessInstanceCreated(ProcessInstance instance) { public void processProcessInstanceCreated(ProcessInstance instance) {
// 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号
FlowableUtils.execute(instance.getTenantId(), () -> {
// 流程前置通知
BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService. BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.
getProcessDefinitionInfo(instance.getProcessDefinitionId()); getProcessDefinitionInfo(instance.getProcessDefinitionId());
if (ObjUtil.isNull(processDefinitionInfo) || ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(instance.getProcessDefinitionId());
ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) { if (processDefinition == null || processDefinitionInfo == null) {
return;
}
// 自定义标题。目的:主要处理子流程的标题无法处理
// 注意:必须使用 TransactionSynchronizationManager 事务提交后,否则不生效!!!
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@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);
}
}
});
// 流程前置通知
if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) {
return; return;
} }
BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting(); BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting();
BpmHttpRequestUtils.executeBpmHttpRequest(instance, BpmHttpRequestUtils.executeBpmHttpRequest(instance,
setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
});
} }
} }