From 73efdd4df78ad972411afa59f4008125f2e2bc87 Mon Sep 17 00:00:00 2001 From: chenchuchuan <13554600537@163.com> Date: Thu, 15 Oct 2026 13:45:24 +0800 Subject: [PATCH] =?UTF-8?q?refactor(flow):=20=E7=AE=80=E5=8C=96=E6=A0=87?= =?UTF-8?q?=E9=A2=98=E8=A7=A3=E6=9E=90=E9=80=BB=E8=BE=91=E5=B9=B6=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=9C=AA=E8=A7=A3=E6=9E=90=E6=A0=87=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除标题解析中对 FlowTaskExt、FlowEntry、FlowEntryPublish 的前置条件判断,标题只认 zz_flow_task_instance_ext 落库值 - 删除 FlowApiServiceImpl 和 FlowOperationController 中冗余的批量预加载逻辑,减少不必要的数据库查询 - 新增 title_incomplete 字段,当标题中残留未解析的 ${...} 占位符时自动标记 - FlowTaskInstanceExtMapper.xml 的 upsert 语句增加 title_incomplete 字段的插入与更新 - FlowTaskTitleBackfillServiceImpl 回填时统计 incomplete 条数,FlowTaskTitleBackfillVo 新增 incompleteCount 字段 - FlowConstant 中新增 TITLE_PLACEHOLDER_PREFIX 常量用于占位符检测 --- .../apelet/common/flow/constant/FlowConstant.java | 7 +++ .../flow/controller/FlowOperationController.java | 61 ++++------------------ .../flow/dao/mapper/FlowTaskInstanceExtMapper.xml | 10 ++-- .../common/flow/model/FlowTaskInstanceExt.java | 7 +++ .../flow/service/impl/FlowApiServiceImpl.java | 17 ++---- .../impl/FlowTaskInstanceExtServiceImpl.java | 5 ++ .../impl/FlowTaskTitleBackfillServiceImpl.java | 7 +++ .../common/flow/vo/FlowTaskTitleBackfillVo.java | 7 +++ 8 files changed, 53 insertions(+), 68 deletions(-) diff --git a/common/common-flow/src/main/java/apelet/common/flow/constant/FlowConstant.java b/common/common-flow/src/main/java/apelet/common/flow/constant/FlowConstant.java index faaf71c..6c4dc8f 100644 --- a/common/common-flow/src/main/java/apelet/common/flow/constant/FlowConstant.java +++ b/common/common-flow/src/main/java/apelet/common/flow/constant/FlowConstant.java @@ -39,6 +39,13 @@ public class FlowConstant { public static final String SUBMIT_USER_VAR = "submitUser"; /** + * 标题模板里未解析占位符的起始标记。 + *

resolveTitle 对"占位符取不到值"是静默处理的 —— 不删不报错,把 ${xxx} 原样留在标题里 + * (最常见的原因是该实例的业务数据已经不存在了)。写入标题时据此打 title_incomplete 标记。

+ */ + public static final String TITLE_PLACEHOLDER_PREFIX = "${"; + + /** * 多任务拒绝数量变量。 */ public static final String MULTI_REFUSE_COUNT_VAR = "multiRefuseCount"; diff --git a/common/common-flow/src/main/java/apelet/common/flow/controller/FlowOperationController.java b/common/common-flow/src/main/java/apelet/common/flow/controller/FlowOperationController.java index 4b39b89..d6ac6aa 100644 --- a/common/common-flow/src/main/java/apelet/common/flow/controller/FlowOperationController.java +++ b/common/common-flow/src/main/java/apelet/common/flow/controller/FlowOperationController.java @@ -853,18 +853,6 @@ public class FlowOperationController { // 节点标题按实例批量预载(一次 IN 查询覆盖整页),避免逐行查询造成 N+1。 Map taskInstanceExtMap = flowTaskInstanceExtService.getMapByProcessInstanceIds(instanceIdSet); - Set processDefinitionIdSet = taskInstanceList.stream() - .map(HistoricTaskInstance::getProcessDefinitionId).collect(Collectors.toSet()); - List flowEntryPublishList = - flowEntryService.getFlowEntryPublishList(processDefinitionIdSet); - Map flowEntryPublishMap = - flowEntryPublishList.stream().collect(Collectors.toMap(FlowEntryPublish::getProcessDefinitionId, c -> c)); - Set entryIdSet = flowEntryPublishList.stream() - .map(FlowEntryPublish::getEntryId).filter(Objects::nonNull).collect(Collectors.toSet()); - Map flowEntryMap = flowEntryService.listByIds(entryIdSet).stream() - .collect(Collectors.toMap(FlowEntry::getEntryId, e -> e)); - Map flowTaskExtMap = flowTaskExtService.getByProcessDefinitionId(processDefinitionIdSet).stream() - .collect(Collectors.toMap(t -> t.getProcessDefinitionId() + ":" + t.getTaskId(), t -> t, (k1, k2) -> k1)); resultList.forEach(result -> { String instanceId = result.get(INSTANCE_ID).toString(); HistoricProcessInstance instance = instanceMap.get(instanceId); @@ -878,19 +866,11 @@ public class FlowOperationController { FlowWorkOrder flowWorkOrder = workOrderMap.get(instanceId); if (flowWorkOrder != null) { result.put("workOrderCode", flowWorkOrder.getWorkOrderCode()); - String processDefinitionId = result.get("processDefinitionId").toString(); - FlowEntryPublish flowEntryPublish = flowEntryPublishMap.get(processDefinitionId); - FlowTaskExt flowTaskExt = flowTaskExtMap.get( - processDefinitionId + ":" + result.get("taskDefinitionKey")); - if (flowEntryPublish != null && flowTaskExt != null) { - FlowEntry flowEntry = flowEntryMap.get(flowEntryPublish.getEntryId()); - if (flowEntry != null) { - Object taskDefinitionKey = result.get("taskDefinitionKey"); - String taskKey = taskDefinitionKey == null ? null : taskDefinitionKey.toString(); - result.put("title", flowApiService.resolveTitleCached(flowWorkOrder, taskKey, - taskKey == null ? null : taskInstanceExtMap.get(instanceId + ":" + taskKey))); - } - } + // 标题只认 zz_flow_task_instance_ext 的落库值:没有标题行就是空 + Object taskDefinitionKey = result.get("taskDefinitionKey"); + String taskKey = taskDefinitionKey == null ? null : taskDefinitionKey.toString(); + result.put("title", flowApiService.resolveTitleCached(flowWorkOrder, taskKey, + taskKey == null ? null : taskInstanceExtMap.get(instanceId + ":" + taskKey))); } }); Set taskIdSet = @@ -949,22 +929,11 @@ public class FlowOperationController { Map taskInstanceExtMap = flowTaskInstanceExtService.getMapByProcessInstanceIds(instanceIdSet); Set processDefinitionIdSet = pageData.getDataList().stream() .map(HistoricProcessInstance::getProcessDefinitionId).collect(Collectors.toSet()); - Map flowEntryPublishMap = new HashMap<>(); - Map flowEntryMap = new HashMap<>(); - Map flowTaskExtMap = new HashMap<>(); - // 流程实例列表使用起始节点的标题模板。 + // 流程实例列表使用起始节点的标题,首节点 taskKey 存在发布版本的 initTaskInfo 里。 Map initTaskKeyMap = new HashMap<>(); if (CollUtil.isNotEmpty(processDefinitionIdSet)) { List flowEntryPublishList = flowEntryService.getFlowEntryPublishList(processDefinitionIdSet); - flowEntryPublishMap.putAll(flowEntryPublishList.stream() - .collect(Collectors.toMap(FlowEntryPublish::getProcessDefinitionId, c -> c))); - Set entryIdSet = flowEntryPublishList.stream() - .map(FlowEntryPublish::getEntryId).filter(Objects::nonNull).collect(Collectors.toSet()); - if (CollUtil.isNotEmpty(entryIdSet)) { - flowEntryMap.putAll(flowEntryService.listByIds(entryIdSet).stream() - .collect(Collectors.toMap(FlowEntry::getEntryId, e -> e))); - } for (FlowEntryPublish flowEntryPublish : flowEntryPublishList) { TaskInfoVo initTaskInfo = StrUtil.isBlank(flowEntryPublish.getInitTaskInfo()) ? null : JSON.parseObject(flowEntryPublish.getInitTaskInfo(), TaskInfoVo.class); @@ -972,8 +941,6 @@ public class FlowOperationController { initTaskKeyMap.put(flowEntryPublish.getProcessDefinitionId(), initTaskInfo.getTaskKey()); } } - flowTaskExtMap.putAll(flowTaskExtService.getByProcessDefinitionId(processDefinitionIdSet).stream() - .collect(Collectors.toMap(t -> t.getProcessDefinitionId() + ":" + t.getTaskId(), t -> t, (k1, k2) -> k1))); } List> resultList = new LinkedList<>(); pageData.getDataList().forEach(instance -> { @@ -987,18 +954,10 @@ public class FlowOperationController { if (workOrder != null) { data.put("workOrderCode", workOrder.getWorkOrderCode()); data.put("flowStatus", workOrder.getFlowStatus()); - FlowEntryPublish flowEntryPublish = flowEntryPublishMap.get(instance.getProcessDefinitionId()); - FlowTaskExt flowTaskExt = flowTaskExtMap.get( - instance.getProcessDefinitionId() + ":" + initTaskKeyMap.get(instance.getProcessDefinitionId())); - if (flowEntryPublish != null && flowTaskExt != null) { - FlowEntry flowEntry = flowEntryMap.get(flowEntryPublish.getEntryId()); - if (flowEntry != null) { - // 流程实例列表使用起始节点的标题。 - String initTaskKey = initTaskKeyMap.get(instance.getProcessDefinitionId()); - data.put("title", flowApiService.resolveTitleCached(workOrder, initTaskKey, - initTaskKey == null ? null : taskInstanceExtMap.get(instance.getId() + ":" + initTaskKey))); - } - } + // 流程实例列表使用起始节点的标题;标题只认落库值,没有标题行就是空 + String initTaskKey = initTaskKeyMap.get(instance.getProcessDefinitionId()); + data.put("title", flowApiService.resolveTitleCached(workOrder, initTaskKey, + initTaskKey == null ? null : taskInstanceExtMap.get(instance.getId() + ":" + initTaskKey))); } resultList.add(data); }); diff --git a/common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTaskInstanceExtMapper.xml b/common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTaskInstanceExtMapper.xml index 9cfe484..751d890 100644 --- a/common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTaskInstanceExtMapper.xml +++ b/common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTaskInstanceExtMapper.xml @@ -9,6 +9,7 @@ + @@ -17,13 +18,14 @@ INSERT INTO zz_flow_task_instance_ext - (id, tenant_id, app_code, process_instance_id, process_definition_id, task_key, title, - create_time, create_user_id, update_time, update_user_id) + (id, tenant_id, app_code, process_instance_id, process_definition_id, task_key, + title, title_incomplete, create_time, create_user_id, update_time, update_user_id) VALUES - (#{id}, #{tenantId}, #{appCode}, #{processInstanceId}, #{processDefinitionId}, #{taskKey}, #{title}, - #{createTime}, #{createUserId}, #{updateTime}, #{updateUserId}) + (#{id}, #{tenantId}, #{appCode}, #{processInstanceId}, #{processDefinitionId}, #{taskKey}, + #{title}, #{titleIncomplete}, #{createTime}, #{createUserId}, #{updateTime}, #{updateUserId}) ON DUPLICATE KEY UPDATE title = VALUES(title), + title_incomplete = VALUES(title_incomplete), process_definition_id = VALUES(process_definition_id), update_time = VALUES(update_time), update_user_id = VALUES(update_user_id) diff --git a/common/common-flow/src/main/java/apelet/common/flow/model/FlowTaskInstanceExt.java b/common/common-flow/src/main/java/apelet/common/flow/model/FlowTaskInstanceExt.java index 864373c..18aa027 100644 --- a/common/common-flow/src/main/java/apelet/common/flow/model/FlowTaskInstanceExt.java +++ b/common/common-flow/src/main/java/apelet/common/flow/model/FlowTaskInstanceExt.java @@ -61,6 +61,13 @@ public class FlowTaskInstanceExt { private String title; /** + * 标题是否未完整解析:0-完整;1-模板里还有没解析出来的 ${...} 占位符。 + *

resolveTitle 取不到值时是静默保留占位符的,靠这个标记才能事后筛出没算全的标题。

+ */ + @TableField(value = "title_incomplete") + private Integer titleIncomplete; + + /** * 创建时间。 */ @TableField(value = "create_time") diff --git a/common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowApiServiceImpl.java b/common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowApiServiceImpl.java index 8809994..bbc5930 100644 --- a/common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowApiServiceImpl.java +++ b/common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowApiServiceImpl.java @@ -982,11 +982,6 @@ public class FlowApiServiceImpl implements FlowApiService { flowEntryService.getFlowEntryPublishList(processDefinitionIdSet); Map flowEntryPublishMap = flowEntryPublishList.stream().collect(Collectors.toMap(FlowEntryPublish::getProcessDefinitionId, c -> c)); - // 批量加载流程对象,用于判断在线表单(bindFormType=0) - Set entryIdSet = flowEntryPublishList.stream() - .map(FlowEntryPublish::getEntryId).filter(Objects::nonNull).collect(Collectors.toSet()); - Map flowEntryMap = flowEntryService.listByIds(entryIdSet).stream() - .collect(Collectors.toMap(FlowEntry::getEntryId, e -> e)); List instanceList = this.getProcessInstanceList(procInstanceIdSet); Map instanceMap = instanceList.stream().collect(Collectors.toMap(ProcessInstance::getId, c -> c)); @@ -1000,8 +995,6 @@ public class FlowApiServiceImpl implements FlowApiService { // 节点标题按实例批量预载(一次 IN 查询覆盖整页),避免逐行查询造成 N+1。 Map taskInstanceExtMap = flowTaskInstanceExtService.getMapByProcessInstanceIds(procInstanceIdSet); - List allFlowTaskExtList = flowTaskExtService.getByProcessDefinitionId(processDefinitionIdSet); - Map flowTaskExtMap = allFlowTaskExtList.stream().collect(Collectors.toMap(t -> t.getProcessDefinitionId() + ":" + t.getTaskId(), t -> t, (k1, k2) -> k1)); Map multiInstanceTaskMap = new HashMap<>(); for (Task task : taskList) { FlowTaskVo flowTaskVo = new FlowTaskVo(); @@ -1029,12 +1022,10 @@ public class FlowApiServiceImpl implements FlowApiService { flowTaskVo.setIsDraft(flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.DRAFT)); flowTaskVo.setWorkOrderCode(flowWorkOrder.getWorkOrderCode()); } - FlowTaskExt flowTaskExt = flowTaskExtMap.get(task.getProcessDefinitionId() + ":" + task.getTaskDefinitionKey()); - FlowEntry flowEntry = flowEntryMap.get(flowEntryPublishMap.get(task.getProcessDefinitionId()).getEntryId()); - if (flowTaskExt != null && flowEntry != null) { - flowTaskVo.setTitle(this.resolveTitleCached(flowWorkOrder, task.getTaskDefinitionKey(), - taskInstanceExtMap.get(task.getProcessInstanceId() + ":" + task.getTaskDefinitionKey()))); - } + // 标题只以 zz_flow_task_instance_ext 的落库值为准:没有标题行就是空, + // 不需要再按"节点配没配模板""是不是在线表单"做前置判断(那两个条件对标题行本身没有约束力)。 + flowTaskVo.setTitle(this.resolveTitleCached(flowWorkOrder, task.getTaskDefinitionKey(), + taskInstanceExtMap.get(task.getProcessInstanceId() + ":" + task.getTaskDefinitionKey()))); flowTaskVoList.add(flowTaskVo); } Set loginNameSet = flowTaskVoList.stream() diff --git a/common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowTaskInstanceExtServiceImpl.java b/common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowTaskInstanceExtServiceImpl.java index 224269a..d44ae85 100644 --- a/common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowTaskInstanceExtServiceImpl.java +++ b/common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowTaskInstanceExtServiceImpl.java @@ -6,6 +6,7 @@ import apelet.common.core.base.service.BaseService; import apelet.common.core.constant.ApplicationConstant; import apelet.common.core.object.TokenData; import apelet.common.core.util.DefaultDataSourceResolver; +import apelet.common.flow.constant.FlowConstant; import apelet.common.flow.dao.FlowTaskInstanceExtMapper; import apelet.common.flow.model.FlowTaskInstanceExt; import apelet.common.flow.service.FlowTaskInstanceExtService; @@ -73,6 +74,10 @@ public class FlowTaskInstanceExtServiceImpl extends BaseService最常见的原因是该实例的业务数据已经不存在了。这些行的 title_incomplete 为 1。

+ */ + @Schema(description = "标题未完整解析的条数") + private Integer incompleteCount; + + /** * 算不出标题(非在线表单 / 模板为空 / 业务数据取不到)而跳过的条数。 */ @Schema(description = "算不出标题跳过的条数")