feat(bpm): 新增流程变量本地服务及完善 XiSpeak 流程相关功能

- 新增 BpmVariableLocalService 流程变量本地服务接口及实现
- XiSpeakFlow 完善流程变量读取逻辑
- ActProcessController 流程控制器功能增强
- FlowNodeExpression 扩展表达式能力

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
wsm
2026-05-27 15:57:20 +08:00
co-authored by Claude Opus 4.7
parent d5a1d9842d
commit 1b49fdbbe0
5 changed files with 156 additions and 0 deletions
@@ -194,6 +194,25 @@ public class XiSpeakFlow {
return flowNodeExpression.getSonProcessHqVariableList(execution,xiSpeakConfig.getXiSpeak().getTemImplWorkerKey()).size(); return flowNodeExpression.getSonProcessHqVariableList(execution,xiSpeakConfig.getXiSpeak().getTemImplWorkerKey()).size();
} }
/**
* 流程表达式内用法: ${xiSpeakFlow.getIsEnd(execution)}
*/
public int getIsEnd(DelegateExecution execution) {
Object value = flowNodeExpression.getSonProcessHqVariable(execution, "isEnd");
if (value == null) {
return 0;
}
if (value instanceof Number) {
return ((Number) value).intValue();
}
try {
return Integer.parseInt(String.valueOf(value));
} catch (NumberFormatException e) {
log.warn("isEnd变量值无法解析为int: {}", value);
return 0;
}
}
/** /**
* 流程表达式内用法: ${xiSpeakFlow.getTemImplLeaderList(execution)} * 流程表达式内用法: ${xiSpeakFlow.getTemImplLeaderList(execution)}
*/ */
@@ -222,6 +241,13 @@ public class XiSpeakFlow {
return flowNodeExpression.getSonProcessHqVariableList(execution,xiSpeakConfig.getXiSpeak().getTemBgLeaderKey()).size(); return flowNodeExpression.getSonProcessHqVariableList(execution,xiSpeakConfig.getXiSpeak().getTemBgLeaderKey()).size();
} }
/**
* 流程表达式内用法: ${xiSpeakFlow.getTemBgLeaderListLength(execution)}
*/
public int getImplDeptLeaderIsEnd(DelegateExecution execution) {
return flowNodeExpression.getSonProcessHqVariableList(execution,xiSpeakConfig.getXiSpeak().getTemBgLeaderKey());
}
/** /**
* 流程表达式内用法: ${xiSpeakFlow.getTemBgLeader(execution)} * 流程表达式内用法: ${xiSpeakFlow.getTemBgLeader(execution)}
@@ -19,6 +19,7 @@ import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.TokenUtils; import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils; import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.bpm.dto.ProcessVariableDTO; import org.jeecg.modules.bpm.dto.ProcessVariableDTO;
import org.jeecg.modules.bpm.service.BpmVariableLocalService;
import org.jeecg.modules.bpm.service.impl.ActProcessService; import org.jeecg.modules.bpm.service.impl.ActProcessService;
import org.jeecg.modules.extbpm.process.service.IExtActProcessService; import org.jeecg.modules.extbpm.process.service.IExtActProcessService;
import org.jeecg.modules.extbpm.util.CommonRandomUtil; import org.jeecg.modules.extbpm.util.CommonRandomUtil;
@@ -57,6 +58,8 @@ public class ActProcessController {
@Autowired @Autowired
private TaskService taskService; private TaskService taskService;
@Autowired @Autowired
private BpmVariableLocalService bpmVariableLocalService;
@Autowired
private ActProcessService actProcessService; private ActProcessService actProcessService;
@Autowired @Autowired
private IExtActProcessService extActProcessService; private IExtActProcessService extActProcessService;
@@ -115,6 +118,24 @@ public class ActProcessController {
return Result.OK("保存成功"); return Result.OK("保存成功");
} }
@PostMapping(value = "/setBpmVariableLocal")
@Operation(summary = "设置局部流程变量(向上追溯2层父级执行实例)")
public Result<String> setBpmVariableLocal(@RequestBody ProcessVariableDTO dto) {
if (dto == null || oConvertUtils.isEmpty(dto.getTaskId())) {
return Result.error("任务ID不能为空");
}
if (oConvertUtils.isEmpty(dto.getVarField())) {
return Result.error("流程变量名不能为空");
}
try {
bpmVariableLocalService.setVariableLocal(dto.getTaskId(), dto.getVarField(), dto.getVarVal());
return Result.OK("保存成功");
} catch (Exception e) {
log.error("设置BPM局部变量失败", e);
return Result.error("保存失败: " + e.getMessage());
}
}
@PostMapping("deploy") @PostMapping("deploy")
@Operation(summary = "部署流程文件") @Operation(summary = "部署流程文件")
public Result deploy(@RequestParam("processFile") MultipartFile file) throws IOException { public Result deploy(@RequestParam("processFile") MultipartFile file) throws IOException {
@@ -0,0 +1,13 @@
package org.jeecg.modules.bpm.service;
public interface BpmVariableLocalService {
/**
* 将变量存入向上追溯2层的父级执行实例中(与 AfterImplWorkerTemStoreListener 逻辑一致)
*
* @param taskId 当前任务ID
* @param varField 变量名
* @param varVal 变量值
*/
void setVariableLocal(String taskId, String varField, Object varVal);
}
@@ -0,0 +1,59 @@
package org.jeecg.modules.bpm.service.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.Execution;
import org.flowable.task.api.Task;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.bpm.service.BpmVariableLocalService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class BpmVariableLocalServiceImpl implements BpmVariableLocalService {
private final RuntimeService runtimeService;
private final TaskService taskService;
@Override
public void setVariableLocal(String taskId, String varField, Object varVal) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
throw new IllegalArgumentException("任务ID不存在: " + taskId);
}
String executionId = task.getExecutionId();
Execution currentExecution = runtimeService.createExecutionQuery()
.executionId(executionId)
.singleResult();
if (currentExecution == null) {
runtimeService.setVariableLocal(executionId, varField, varVal);
return;
}
String parentId = currentExecution.getParentId();
if (oConvertUtils.isEmpty(parentId)) {
runtimeService.setVariableLocal(executionId, varField, varVal);
return;
}
Execution parentExecution = runtimeService.createExecutionQuery()
.executionId(parentId)
.singleResult();
if (parentExecution == null) {
runtimeService.setVariableLocal(parentId, varField, varVal);
return;
}
String grandParentId = parentExecution.getParentId();
String targetId = oConvertUtils.isNotEmpty(grandParentId) ? grandParentId : parentId;
runtimeService.setVariableLocal(targetId, varField, varVal);
log.info("BPM局部变量已存入: targetId={}, varField={}, varVal={}", targetId, varField, varVal);
}
}
@@ -427,6 +427,43 @@ public class FlowNodeExpression {
return this.getSonProcessHqVariableList(execution,variableName).size(); return this.getSonProcessHqVariableList(execution,variableName).size();
} }
/**
* 获取子流程原始变量值(不经过 splitUsernames 逗号分割),适用于非列表类型的变量。
* 遍历逻辑与 getSonProcessHqVariableList 一致。
*/
public Object getSonProcessHqVariable(DelegateExecution execution, String variableName) {
if (execution == null || StringUtils.isBlank(variableName)) {
return null;
}
try {
String parentExecutionId = execution.getParentId();
if (StringUtils.isBlank(parentExecutionId)) {
return null;
}
if (execution.hasVariableLocal(variableName)) {
return execution.getVariableLocal(variableName);
}
List<Execution> executions = runtimeService.createExecutionQuery()
.processInstanceId(parentExecutionId)
.list();
for (Execution childExecution : executions) {
if (execution.getId().equals(childExecution.getId())) {
continue;
}
Object localVariable = runtimeService.getVariableLocal(childExecution.getId(), variableName);
if (localVariable != null) {
return localVariable;
}
}
return execution.getVariable(variableName);
} catch (Exception e) {
log.warn("getSonProcessHqVariable failed, executionId={}, variableName={}",
execution.getId(), variableName, e);
return null;
}
}
public String getSonProcessHqVariableString(DelegateExecution execution, String variableName) { public String getSonProcessHqVariableString(DelegateExecution execution, String variableName) {
if(execution == null || StringUtils.isBlank(variableName) || getSonProcessHqVariableList(execution, variableName).isEmpty()) return StringUtils.EMPTY; if(execution == null || StringUtils.isBlank(variableName) || getSonProcessHqVariableList(execution, variableName).isEmpty()) return StringUtils.EMPTY;
return getSonProcessHqVariableList(execution, variableName).get(0); return getSonProcessHqVariableList(execution, variableName).get(0);