Browse Source

feat(flow): 更新在线表单工作流业务数据获取功能

- 在 BaseFlowOnlineService 中的 getBusinessData 方法添加 FlowEntry 参数
- 在 BaseOnlineBusinessDataExtHelper 中同步更新方法签名以传递 FlowEntry 对象
- 修改 FlowApiService 中的 resolveTitle 方法以接收 FlowEntry 参数进行在线表单判断
- 在 FlowApiServiceImpl 中实现批量加载 FlowEntry 数据并优化标题解析逻辑
- 添加对流程绑定表单类型的判断逻辑,以 FlowBindFormType.ONLINE_FORM 为准
- 实现对运行时变量查询失败时的历史变量回退机制
- 在 FlowOnlineBusinessServiceImpl 中重构 getBusinessData 方法,优先使用工单上的 onlineTableId
- 添加 resolveMasterTable 私有方法,通过 FlowEntry.pageId 解析在线表单主表
- 在控制器层更新任务信息和流程实例列表中的标题解析调用方式
feature/2026-07-ccc-dev
chenchuchuan 3 days ago
parent
commit
9c618961ce
  1. 42
      common/common-flow-online/src/main/java/apelet/common/flow/online/service/impl/FlowOnlineBusinessServiceImpl.java
  2. 4
      common/common-flow/src/main/java/apelet/common/flow/base/service/BaseFlowOnlineService.java
  3. 64
      common/common-flow/src/main/java/apelet/common/flow/controller/FlowOperationController.java
  4. 2
      common/common-flow/src/main/java/apelet/common/flow/model/FlowEntry.java
  5. 4
      common/common-flow/src/main/java/apelet/common/flow/service/FlowApiService.java
  6. 44
      common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowApiServiceImpl.java
  7. 6
      common/common-flow/src/main/java/apelet/common/flow/util/BaseOnlineBusinessDataExtHelper.java

42
common/common-flow-online/src/main/java/apelet/common/flow/online/service/impl/FlowOnlineBusinessServiceImpl.java

@ -3,8 +3,10 @@ package apelet.common.flow.online.service.impl; @@ -3,8 +3,10 @@ package apelet.common.flow.online.service.impl;
import apelet.common.core.annotation.MyDataSource;
import apelet.common.core.constant.ApplicationConstant;
import apelet.common.flow.base.service.BaseFlowOnlineService;
import apelet.common.flow.model.FlowEntry;
import apelet.common.flow.model.FlowWorkOrder;
import apelet.common.flow.online.object.TransactionalFlowBusinessData;
import apelet.common.flow.service.FlowEntryService;
import apelet.common.flow.util.FlowCustomExtFactory;
import apelet.common.generator.model.OnlFormHead;
import apelet.common.generator.service.IOnlFormHeadService;
@ -39,6 +41,8 @@ public class FlowOnlineBusinessServiceImpl implements BaseFlowOnlineService { @@ -39,6 +41,8 @@ public class FlowOnlineBusinessServiceImpl implements BaseFlowOnlineService {
@Autowired
private FlowCustomExtFactory flowCustomExtFactory;
@Autowired
private FlowEntryService flowEntryService;
@Autowired
private OnlineTableService onlineTableService;
@Autowired
private OnlinePageService onlinePageService;
@ -113,15 +117,47 @@ public class FlowOnlineBusinessServiceImpl implements BaseFlowOnlineService { @@ -113,15 +117,47 @@ public class FlowOnlineBusinessServiceImpl implements BaseFlowOnlineService {
}
@Override
public String getBusinessData(FlowWorkOrder workOrder) {
OnlineTable onlineTable = onlineTableService.getOnlineTableFromCache(workOrder.getOnlineTableId());
if (onlineTable == null || workOrder.getBusinessKey() == null) {
public String getBusinessData(FlowWorkOrder workOrder, FlowEntry flowEntry) {
// 优先使用工单上的 onlineTableId;部分在线表单启动路径不会回填该字段,此时通过流程绑定的在线表单 pageId 解析主表。
OnlineTable onlineTable = this.resolveMasterTable(workOrder, flowEntry);
if (onlineTable == null || workOrder == null || workOrder.getBusinessKey() == null) {
return null;
}
Map<String, Object> dataMap = onlineOperationService.getMasterData(onlineTable, null, null, workOrder.getBusinessKey());
return dataMap == null ? null : JSON.toJSONString(dataMap);
}
/**
* 解析在线表单工作流的主表优先取工单上的 onlineTableId为空时通过 FlowEntry.pageId 页面关联数据源的主表Id 兜底
* 注意OnlinePage.masterTableId 是表单元数据(OnlFormHead)的Id不能直接作为 OnlineTable 的tableId 使用
*
* @param workOrder 流程工单对象
* @return 在线表单主表无法解析返回null
*/
private OnlineTable resolveMasterTable(FlowWorkOrder workOrder, FlowEntry flowEntry) {
if (workOrder == null && flowEntry == null) {
return null;
}
if (workOrder != null) {
if (workOrder.getOnlineTableId() != null) {
return onlineTableService.getOnlineTableFromCache(workOrder.getOnlineTableId());
}
if (StringUtils.isBlank(workOrder.getProcessDefinitionKey())) {
return null;
}
flowEntry = flowEntryService.getFlowEntryFromCache(workOrder.getProcessDefinitionKey());
}
if (flowEntry == null || flowEntry.getPageId() == null) {
return null;
}
// 参考 OnlineOperationController#getEntryListByDatasourceId:通过页面关联的数据源解析主表。
List<OnlineDatasource> datasourceList = onlineDatasourceService.getOnlineDatasourceListByPageId(flowEntry.getPageId(), null, null);
if (CollUtil.isEmpty(datasourceList) || datasourceList.get(0).getMasterTableId() == null) {
return null;
}
return onlineTableService.getOnlineTableFromCache(datasourceList.get(0).getMasterTableId());
}
private void handleTransactionalFlowBusinessData(FlowWorkOrder workOrder, String desc) {
TransactionalFlowBusinessData eventData = TransactionalFlowBusinessData.getFromRequestAttribute();
if (eventData != null) {

4
common/common-flow/src/main/java/apelet/common/flow/base/service/BaseFlowOnlineService.java

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
package apelet.common.flow.base.service;
import apelet.common.flow.model.FlowEntry;
import apelet.common.flow.model.FlowWorkOrder;
/**
@ -38,9 +39,10 @@ public interface BaseFlowOnlineService { @@ -38,9 +39,10 @@ public interface BaseFlowOnlineService {
* 获取在线表单工作流的业务主表数据
*
* @param workOrder 工单对象
* @param flowEntry 流程节点对象
* @return JSON格式的业务主表数据如果无法获取返回null
*/
default String getBusinessData(FlowWorkOrder workOrder) {
default String getBusinessData(FlowWorkOrder workOrder, FlowEntry flowEntry) {
return null;
}
}

64
common/common-flow/src/main/java/apelet/common/flow/controller/FlowOperationController.java

@ -212,7 +212,8 @@ public class FlowOperationController { @@ -212,7 +212,8 @@ public class FlowOperationController {
taskInfoVo.setVariableList(JSON.parseArray(flowTaskExt.getVariableListJson(), JSONObject.class));
}
FlowWorkOrder workOrder = flowWorkOrderService.getFlowWorkOrderByProcessInstanceId(processInstanceId);
taskInfoVo.setTitle(flowApiService.resolveTitle(flowTaskExt.getTitleTemplate(), processInstanceId, workOrder));
FlowEntry flowEntry = workOrder == null ? null : flowEntryService.getFlowEntryFromCache(workOrder.getProcessDefinitionKey());
taskInfoVo.setTitle(flowApiService.resolveTitle(flowTaskExt.getTitleTemplate(), processInstanceId, workOrder, flowEntry));
}
return ResponseResult.success(taskInfoVo);
}
@ -833,6 +834,18 @@ public class FlowOperationController { @@ -833,6 +834,18 @@ public class FlowOperationController {
flowWorkOrderService.getInList(INSTANCE_ID, instanceIdSet);
Map<String, FlowWorkOrder> workOrderMap =
workOrderList.stream().collect(Collectors.toMap(FlowWorkOrder::getProcessInstanceId, c -> c));
Set<String> processDefinitionIdSet = taskInstanceList.stream()
.map(HistoricTaskInstance::getProcessDefinitionId).collect(Collectors.toSet());
List<FlowEntryPublish> flowEntryPublishList =
flowEntryService.getFlowEntryPublishList(processDefinitionIdSet);
Map<String, FlowEntryPublish> flowEntryPublishMap =
flowEntryPublishList.stream().collect(Collectors.toMap(FlowEntryPublish::getProcessDefinitionId, c -> c));
Set<Long> entryIdSet = flowEntryPublishList.stream()
.map(FlowEntryPublish::getEntryId).filter(Objects::nonNull).collect(Collectors.toSet());
Map<Long, FlowEntry> flowEntryMap = flowEntryService.listByIds(entryIdSet).stream()
.collect(Collectors.toMap(FlowEntry::getEntryId, e -> e));
Map<String, FlowTaskExt> 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);
@ -846,6 +859,17 @@ public class FlowOperationController { @@ -846,6 +859,17 @@ 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) {
result.put("title", flowApiService.resolveTitle(
flowTaskExt.getTitleTemplate(), instanceId, flowWorkOrder, flowEntry));
}
}
}
});
Set<String> taskIdSet =
@ -898,6 +922,34 @@ public class FlowOperationController { @@ -898,6 +922,34 @@ public class FlowOperationController {
flowWorkOrderService.getInList(INSTANCE_ID, instanceIdSet);
Map<String, FlowWorkOrder> workOrderMap =
workOrderList.stream().collect(Collectors.toMap(FlowWorkOrder::getProcessInstanceId, c -> c));
Set<String> processDefinitionIdSet = pageData.getDataList().stream()
.map(HistoricProcessInstance::getProcessDefinitionId).collect(Collectors.toSet());
Map<String, FlowEntryPublish> flowEntryPublishMap = new HashMap<>();
Map<Long, FlowEntry> flowEntryMap = new HashMap<>();
Map<String, FlowTaskExt> flowTaskExtMap = new HashMap<>();
// 流程实例列表使用起始节点的标题模板。
Map<String, String> initTaskKeyMap = new HashMap<>();
if (CollUtil.isNotEmpty(processDefinitionIdSet)) {
List<FlowEntryPublish> flowEntryPublishList =
flowEntryService.getFlowEntryPublishList(processDefinitionIdSet);
flowEntryPublishMap.putAll(flowEntryPublishList.stream()
.collect(Collectors.toMap(FlowEntryPublish::getProcessDefinitionId, c -> c)));
Set<Long> 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);
if (initTaskInfo != null && StrUtil.isNotBlank(initTaskInfo.getTaskKey())) {
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<Map<String, Object>> resultList = new LinkedList<>();
pageData.getDataList().forEach(instance -> {
Map<String, Object> data = BeanUtil.beanToMap(instance);
@ -910,6 +962,16 @@ public class FlowOperationController { @@ -910,6 +962,16 @@ 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) {
data.put("title", flowApiService.resolveTitle(
flowTaskExt.getTitleTemplate(), instance.getId(), workOrder, flowEntry));
}
}
}
resultList.add(data);
});

2
common/common-flow/src/main/java/apelet/common/flow/model/FlowEntry.java

@ -2,6 +2,7 @@ package apelet.common.flow.model; @@ -2,6 +2,7 @@ package apelet.common.flow.model;
import apelet.common.core.annotation.RelationOneToOne;
import apelet.common.core.base.mapper.BaseModelMapper;
import apelet.common.flow.model.constant.FlowBindFormType;
import apelet.common.flow.model.constant.FlowEntryStatus;
import apelet.common.flow.vo.FlowEntryVo;
import com.baomidou.mybatisplus.annotation.TableField;
@ -93,6 +94,7 @@ public class FlowEntry { @@ -93,6 +94,7 @@ public class FlowEntry {
/**
* 绑定表单类型
* @see FlowBindFormType
*/
@TableField(value = "bind_form_type")
private Integer bindFormType;

4
common/common-flow/src/main/java/apelet/common/flow/service/FlowApiService.java

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
package apelet.common.flow.service;
import apelet.common.core.object.*;
import apelet.common.flow.model.FlowEntry;
import apelet.common.flow.model.FlowTaskComment;
import apelet.common.flow.model.FlowTaskExt;
import apelet.common.flow.model.FlowWorkOrder;
@ -643,7 +644,8 @@ public interface FlowApiService { @@ -643,7 +644,8 @@ public interface FlowApiService {
* @param titleTemplate 节点配置的标题模板为空时使用默认标题
* @param processInstanceId 流程实例Id
* @param workOrder 流程工单对象
* @param flowEntry 流程对象用于判断是否为在线表单bindFormType=0
* @return 解析后的标题非在线表单工作流返回null
*/
String resolveTitle(String titleTemplate, String processInstanceId, FlowWorkOrder workOrder);
String resolveTitle(String titleTemplate, String processInstanceId, FlowWorkOrder workOrder, FlowEntry flowEntry);
}

44
common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowApiServiceImpl.java

@ -16,6 +16,7 @@ import apelet.common.flow.constant.FlowConstant; @@ -16,6 +16,7 @@ import apelet.common.flow.constant.FlowConstant;
import apelet.common.flow.constant.FlowTaskStatus;
import apelet.common.flow.exception.FlowOperationException;
import apelet.common.flow.model.*;
import apelet.common.flow.model.constant.FlowBindFormType;
import apelet.common.flow.object.*;
import apelet.common.flow.service.*;
import apelet.common.flow.util.BaseFlowIdentityExtHelper;
@ -789,6 +790,11 @@ public class FlowApiServiceImpl implements FlowApiService { @@ -789,6 +790,11 @@ public class FlowApiServiceImpl implements FlowApiService {
flowEntryService.getFlowEntryPublishList(processDefinitionIdSet);
Map<String, FlowEntryPublish> flowEntryPublishMap =
flowEntryPublishList.stream().collect(Collectors.toMap(FlowEntryPublish::getProcessDefinitionId, c -> c));
// 批量加载流程对象,用于判断在线表单(bindFormType=0)
Set<Long> entryIdSet = flowEntryPublishList.stream()
.map(FlowEntryPublish::getEntryId).filter(Objects::nonNull).collect(Collectors.toSet());
Map<Long, FlowEntry> flowEntryMap = flowEntryService.listByIds(entryIdSet).stream()
.collect(Collectors.toMap(FlowEntry::getEntryId, e -> e));
List<ProcessInstance> instanceList = this.getProcessInstanceList(procInstanceIdSet);
Map<String, ProcessInstance> instanceMap =
instanceList.stream().collect(Collectors.toMap(ProcessInstance::getId, c -> c));
@ -825,10 +831,11 @@ public class FlowApiServiceImpl implements FlowApiService { @@ -825,10 +831,11 @@ public class FlowApiServiceImpl implements FlowApiService {
if (flowWorkOrder != null) {
flowTaskVo.setIsDraft(flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.DRAFT));
flowTaskVo.setWorkOrderCode(flowWorkOrder.getWorkOrderCode());
FlowTaskExt flowTaskExt = flowTaskExtMap.get(task.getProcessDefinitionId() + ":" + task.getTaskDefinitionKey());
if (flowTaskExt != null) {
flowTaskVo.setTitle(this.resolveTitle(flowTaskExt.getTitleTemplate(), task.getProcessInstanceId(), flowWorkOrder));
}
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.resolveTitle(flowTaskExt.getTitleTemplate(), task.getProcessInstanceId(), flowWorkOrder, flowEntry));
}
flowTaskVoList.add(flowTaskVo);
}
@ -2456,13 +2463,13 @@ public class FlowApiServiceImpl implements FlowApiService { @@ -2456,13 +2463,13 @@ public class FlowApiServiceImpl implements FlowApiService {
}
@Override
public String resolveTitle(String titleTemplate, String processInstanceId, FlowWorkOrder workOrder) {
// 非在线表单(路由表单)工作流不支持自定义标题
if (workOrder == null || workOrder.getOnlineTableId() == null) {
public String resolveTitle(String titleTemplate, String processInstanceId, FlowWorkOrder workOrder, FlowEntry flowEntry) {
// 在线表单判断以流程绑定的表单类型为准(bindFormType=0),不能依赖工单上的 onlineTableId(部分在线表单启动路径不会回填该字段)
if (!ObjectUtil.equal(flowEntry.getBindFormType(), FlowBindFormType.ONLINE_FORM)) {
return null;
}
if (StrUtil.isBlank(titleTemplate)) {
titleTemplate = this.buildDefaultTitle(workOrder);
titleTemplate = this.buildDefaultTitle(flowEntry);
}
String result = titleTemplate;
// 1. Flowable 持久化变量: ${initiator}, ${startUserName}, ${submitUser}
@ -2470,14 +2477,24 @@ public class FlowApiServiceImpl implements FlowApiService { @@ -2470,14 +2477,24 @@ public class FlowApiServiceImpl implements FlowApiService {
for (String varName : varNames) {
String value = null;
if (StrUtil.isNotBlank(processInstanceId)) {
Object v = runtimeService.getVariable(processInstanceId, varName);
Object v = null;
try {
v = runtimeService.getVariable(processInstanceId, varName);
} catch (Exception e) {
// 流程实例已结束,运行时变量已被清理,回退到历史变量查询。
log.warn("查询流程实例运行时变量失败,回退到历史变量查询。processInstanceId [{}], varName [{}]",
processInstanceId, varName);
}
if (v == null) {
v = this.getHistoricProcessInstanceVariable(processInstanceId, varName);
}
if (v != null) {
value = v.toString();
}
}
if (value == null && workOrder.getBusinessKey() != null) {
if (value == null) {
// 2. 业务数据: ${number}, ${amount} 等在线表单字段。
String bizData = flowCustomExtFactory.getOnlineBusinessDataExtHelper().getBusinessData(workOrder);
String bizData = flowCustomExtFactory.getOnlineBusinessDataExtHelper().getBusinessData(workOrder, flowEntry);
if (StrUtil.isNotBlank(bizData)) {
JSONObject biz = JSON.parseObject(bizData);
value = biz.getString(varName);
@ -2490,15 +2507,12 @@ public class FlowApiServiceImpl implements FlowApiService { @@ -2490,15 +2507,12 @@ public class FlowApiServiceImpl implements FlowApiService {
return result;
}
private String buildDefaultTitle(FlowWorkOrder workOrder) {
private String buildDefaultTitle(FlowEntry flowEntry) {
String tableName = null;
if (workOrder.getOnlineTableId() != null) {
// 在线表单:FlowEntry.pageId → OnlinePage.masterTableName
FlowEntry flowEntry = flowEntryService.getFlowEntryFromCache(workOrder.getProcessDefinitionKey());
if (flowEntry != null && flowEntry.getPageId() != null) {
// 在线表单:FlowEntry.pageId → OnlinePage.masterTableName
tableName = flowCustomExtFactory.getOnlineBusinessDataExtHelper().getTableTxt(flowEntry.getPageId());
}
}
if (StrUtil.isBlank(tableName)) {
tableName = "业务";
}

6
common/common-flow/src/main/java/apelet/common/flow/util/BaseOnlineBusinessDataExtHelper.java

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
package apelet.common.flow.util;
import apelet.common.flow.base.service.BaseFlowOnlineService;
import apelet.common.flow.model.FlowEntry;
import apelet.common.flow.model.FlowWorkOrder;
import cn.hutool.core.lang.Assert;
import lombok.extern.slf4j.Slf4j;
@ -63,9 +64,10 @@ public class BaseOnlineBusinessDataExtHelper { @@ -63,9 +64,10 @@ public class BaseOnlineBusinessDataExtHelper {
* 获取在线表单工作流的业务主表数据
*
* @param workOrder 工单对象
* @param flowEntry 流程节点对象
* @return JSON格式的业务主表数据如果无法获取返回null
*/
public String getBusinessData(FlowWorkOrder workOrder) {
return this.onlineBusinessService == null ? null : onlineBusinessService.getBusinessData(workOrder);
public String getBusinessData(FlowWorkOrder workOrder, FlowEntry flowEntry) {
return this.onlineBusinessService == null ? null : onlineBusinessService.getBusinessData(workOrder, flowEntry);
}
}

Loading…
Cancel
Save