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 = "算不出标题跳过的条数")