|
|
|
@ -906,6 +906,11 @@ public class FlowApiServiceImpl implements FlowApiService { |
|
|
|
flowWorkOrderService.getInList("processInstanceId", procInstanceIdSet); |
|
|
|
flowWorkOrderService.getInList("processInstanceId", procInstanceIdSet); |
|
|
|
Map<String, FlowWorkOrder> workOrderMap = |
|
|
|
Map<String, FlowWorkOrder> workOrderMap = |
|
|
|
workOrderList.stream().collect(Collectors.toMap(FlowWorkOrder::getProcessInstanceId, c -> c)); |
|
|
|
workOrderList.stream().collect(Collectors.toMap(FlowWorkOrder::getProcessInstanceId, c -> c)); |
|
|
|
|
|
|
|
// 标题快照按工单批量预载(一次 IN 查询覆盖整页),避免逐行查扩展对象造成 N+1。
|
|
|
|
|
|
|
|
Map<Long, FlowWorkOrderExt> workOrderExtMap = flowWorkOrderService |
|
|
|
|
|
|
|
.getFlowWorkOrderExtByWorkOrderIds(workOrderList.stream() |
|
|
|
|
|
|
|
.map(FlowWorkOrder::getWorkOrderId).filter(Objects::nonNull).collect(Collectors.toSet())) |
|
|
|
|
|
|
|
.stream().collect(Collectors.toMap(FlowWorkOrderExt::getWorkOrderId, c -> c, (k1, k2) -> k1)); |
|
|
|
List<FlowTaskExt> allFlowTaskExtList = flowTaskExtService.getByProcessDefinitionId(processDefinitionIdSet); |
|
|
|
List<FlowTaskExt> allFlowTaskExtList = flowTaskExtService.getByProcessDefinitionId(processDefinitionIdSet); |
|
|
|
Map<String, FlowTaskExt> flowTaskExtMap = allFlowTaskExtList.stream().collect(Collectors.toMap(t -> t.getProcessDefinitionId() + ":" + t.getTaskId(), t -> t, (k1, k2) -> k1)); |
|
|
|
Map<String, FlowTaskExt> flowTaskExtMap = allFlowTaskExtList.stream().collect(Collectors.toMap(t -> t.getProcessDefinitionId() + ":" + t.getTaskId(), t -> t, (k1, k2) -> k1)); |
|
|
|
Map<String, Boolean> multiInstanceTaskMap = new HashMap<>(); |
|
|
|
Map<String, Boolean> multiInstanceTaskMap = new HashMap<>(); |
|
|
|
@ -938,7 +943,9 @@ public class FlowApiServiceImpl implements FlowApiService { |
|
|
|
FlowTaskExt flowTaskExt = flowTaskExtMap.get(task.getProcessDefinitionId() + ":" + task.getTaskDefinitionKey()); |
|
|
|
FlowTaskExt flowTaskExt = flowTaskExtMap.get(task.getProcessDefinitionId() + ":" + task.getTaskDefinitionKey()); |
|
|
|
FlowEntry flowEntry = flowEntryMap.get(flowEntryPublishMap.get(task.getProcessDefinitionId()).getEntryId()); |
|
|
|
FlowEntry flowEntry = flowEntryMap.get(flowEntryPublishMap.get(task.getProcessDefinitionId()).getEntryId()); |
|
|
|
if (flowTaskExt != null && flowEntry != null) { |
|
|
|
if (flowTaskExt != null && flowEntry != null) { |
|
|
|
flowTaskVo.setTitle(this.resolveTitle(flowTaskExt.getTitleTemplate(), task.getProcessInstanceId(), flowWorkOrder, flowEntry)); |
|
|
|
flowTaskVo.setTitle(this.resolveTitleCached(flowTaskExt.getTitleTemplate(), |
|
|
|
|
|
|
|
task.getProcessInstanceId(), flowWorkOrder, flowEntry, task.getTaskDefinitionKey(), |
|
|
|
|
|
|
|
flowWorkOrder == null ? null : workOrderExtMap.get(flowWorkOrder.getWorkOrderId()))); |
|
|
|
} |
|
|
|
} |
|
|
|
flowTaskVoList.add(flowTaskVo); |
|
|
|
flowTaskVoList.add(flowTaskVo); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -2647,6 +2654,10 @@ public class FlowApiServiceImpl implements FlowApiService { |
|
|
|
String result = titleTemplate; |
|
|
|
String result = titleTemplate; |
|
|
|
// 1. Flowable 持久化变量: ${initiator}, ${startUserName}, ${submitUser}
|
|
|
|
// 1. Flowable 持久化变量: ${initiator}, ${startUserName}, ${submitUser}
|
|
|
|
List<String> varNames = ReUtil.findAll("\\$\\{(\\w+)\\}", result, 1); |
|
|
|
List<String> varNames = ReUtil.findAll("\\$\\{(\\w+)\\}", result, 1); |
|
|
|
|
|
|
|
// 业务数据只查一次。原来写在占位符循环内部,N 个业务占位符就调 N 次 getBusinessData(重操作:查库 +
|
|
|
|
|
|
|
|
// 字典翻译 + 附件列填充 + 关联重排),列表接口再逐行调用,会放大成 M 行 × N 占位符次查询。
|
|
|
|
|
|
|
|
JSONObject bizData = null; |
|
|
|
|
|
|
|
boolean bizDataLoaded = false; |
|
|
|
for (String varName : varNames) { |
|
|
|
for (String varName : varNames) { |
|
|
|
String value = null; |
|
|
|
String value = null; |
|
|
|
if (StrUtil.isNotBlank(processInstanceId)) { |
|
|
|
if (StrUtil.isNotBlank(processInstanceId)) { |
|
|
|
@ -2667,10 +2678,13 @@ public class FlowApiServiceImpl implements FlowApiService { |
|
|
|
} |
|
|
|
} |
|
|
|
if (value == null) { |
|
|
|
if (value == null) { |
|
|
|
// 2. 业务数据: ${number}, ${amount} 等在线表单字段。
|
|
|
|
// 2. 业务数据: ${number}, ${amount} 等在线表单字段。
|
|
|
|
String bizData = flowCustomExtFactory.getOnlineBusinessDataExtHelper().getBusinessData(workOrder, flowEntry); |
|
|
|
if (!bizDataLoaded) { |
|
|
|
if (StrUtil.isNotBlank(bizData)) { |
|
|
|
bizDataLoaded = true; |
|
|
|
JSONObject biz = JSON.parseObject(bizData); |
|
|
|
String bizJson = flowCustomExtFactory.getOnlineBusinessDataExtHelper().getBusinessData(workOrder, flowEntry); |
|
|
|
value = biz.getString(varName); |
|
|
|
bizData = StrUtil.isBlank(bizJson) ? null : JSON.parseObject(bizJson); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (bizData != null) { |
|
|
|
|
|
|
|
value = bizData.getString(varName); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (value != null) { |
|
|
|
if (value != null) { |
|
|
|
@ -2680,6 +2694,79 @@ public class FlowApiServiceImpl implements FlowApiService { |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public String resolveTitleCached(String titleTemplate, String processInstanceId, FlowWorkOrder workOrder, |
|
|
|
|
|
|
|
FlowEntry flowEntry, String taskKey, FlowWorkOrderExt workOrderExt) { |
|
|
|
|
|
|
|
if (workOrder != null && workOrderExt != null && StrUtil.isNotBlank(taskKey) |
|
|
|
|
|
|
|
&& StrUtil.isNotBlank(workOrderExt.getTitleJson())) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
String cached = JSON.parseObject(workOrderExt.getTitleJson()).getString(taskKey); |
|
|
|
|
|
|
|
if (StrUtil.isNotBlank(cached)) { |
|
|
|
|
|
|
|
return cached; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
// 快照解析失败不能影响列表整体,降级为实时解析。
|
|
|
|
|
|
|
|
log.warn("标题快照解析失败,降级为实时解析。workOrderId [{}], taskKey [{}]", |
|
|
|
|
|
|
|
workOrder.getWorkOrderId(), taskKey, e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return this.resolveTitle(titleTemplate, processInstanceId, workOrder, flowEntry); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public String buildAndSaveTaskTitle(FlowWorkOrder workOrder, String processDefinitionId, String taskKey) { |
|
|
|
|
|
|
|
if (workOrder == null || StrUtil.isBlank(workOrder.getProcessInstanceId())) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
String nodeKey = taskKey; |
|
|
|
|
|
|
|
if (StrUtil.isBlank(nodeKey)) { |
|
|
|
|
|
|
|
// 首节点补写场景:create 事件触发时工单还没创建,走到这里工单已建,取当前活动任务节点即可。
|
|
|
|
|
|
|
|
Task activeTask = taskService.createTaskQuery() |
|
|
|
|
|
|
|
.processInstanceId(workOrder.getProcessInstanceId()).active().singleResult(); |
|
|
|
|
|
|
|
if (activeTask == null) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
nodeKey = activeTask.getTaskDefinitionKey(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
FlowEntry flowEntry = StrUtil.isBlank(workOrder.getProcessDefinitionKey()) ? null |
|
|
|
|
|
|
|
: flowEntryService.getFlowEntryFromCache(workOrder.getProcessDefinitionKey()); |
|
|
|
|
|
|
|
if (flowEntry == null) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
FlowTaskExt flowTaskExt = flowTaskExtService.getByProcessDefinitionIdAndTaskId(processDefinitionId, nodeKey); |
|
|
|
|
|
|
|
String titleTemplate = flowTaskExt == null ? null : flowTaskExt.getTitleTemplate(); |
|
|
|
|
|
|
|
titleTemplate = this.replaceSubmitUserWhenAbsent(titleTemplate, workOrder.getProcessInstanceId()); |
|
|
|
|
|
|
|
String title = this.resolveTitle(titleTemplate, workOrder.getProcessInstanceId(), workOrder, flowEntry); |
|
|
|
|
|
|
|
if (StrUtil.isBlank(title)) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
flowWorkOrderService.saveTaskTitle(workOrder.getWorkOrderId(), nodeKey, title); |
|
|
|
|
|
|
|
return title; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 首节点生成标题时还没发生过任何任务完成,${submitUser} 尚未写入(它由 completeTask 设置), |
|
|
|
|
|
|
|
* 直接解析会留下字面量。首节点的"提交人"语义上就是发起人,故此时把模板里的 ${submitUser} 换成 ${initiator}。 |
|
|
|
|
|
|
|
* 第 2 个节点起上一个节点的 complete 已写好 submitUser,原样返回。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private String replaceSubmitUserWhenAbsent(String titleTemplate, String processInstanceId) { |
|
|
|
|
|
|
|
if (StrUtil.isBlank(titleTemplate) || StrUtil.isBlank(processInstanceId) |
|
|
|
|
|
|
|
|| !titleTemplate.contains("${" + FlowConstant.SUBMIT_USER_VAR + "}")) { |
|
|
|
|
|
|
|
return titleTemplate; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Object submitUser = null; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
submitUser = runtimeService.getVariable(processInstanceId, FlowConstant.SUBMIT_USER_VAR); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
submitUser = this.getHistoricProcessInstanceVariable(processInstanceId, FlowConstant.SUBMIT_USER_VAR); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (submitUser != null && StrUtil.isNotBlank(submitUser.toString())) { |
|
|
|
|
|
|
|
return titleTemplate; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return titleTemplate.replace("${" + FlowConstant.SUBMIT_USER_VAR + "}", |
|
|
|
|
|
|
|
"${" + FlowConstant.PROC_INSTANCE_INITIATOR_VAR + "}"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String buildDefaultTitle(FlowEntry flowEntry) { |
|
|
|
private String buildDefaultTitle(FlowEntry flowEntry) { |
|
|
|
String tableName = null; |
|
|
|
String tableName = null; |
|
|
|
if (flowEntry != null && flowEntry.getPageId() != null) { |
|
|
|
if (flowEntry != null && flowEntry.getPageId() != null) { |
|
|
|
|