fix(flow): 修复流程控制中的循环数组传递问题

- 在EdgeHlcServiceImpl中添加触控坐标验证,防止坐标为0时的异常
- 在FlowControlService中为resumeMessage添加loopArray属性传递,确保恢复时保留循环数组数据
- 修改FlowGetCurrentObjNodeHandler中获取当前对象的方式,使用loopArray替代inputParams中的array
- 在FlowItemExecutor中将rootMessage的loopArray传递给子消息
- 更新FlowLoopNodeHandler中循环处理逻辑,确保loopArray在循环过程中正确传递
- 调整FlowNodeParamPreparer中循环目标解析方式,直接使用loopNumVal作为目标对象
- 在TaskNodeExecuteContext和TaskNodeExecuteMessage中添加loopArray属性支持
This commit is contained in:
stream 2026-03-24 10:59:50 +08:00 committed by lixiaolong
parent 5be7f81924
commit a1c3040210
9 changed files with 35 additions and 16 deletions

View File

@ -3,6 +3,7 @@ package com.cmvr.edge.client.service.impl;
import cmvr.api.HlcCommand; import cmvr.api.HlcCommand;
import cmvr.api.HlcServiceGrpc; import cmvr.api.HlcServiceGrpc;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.cmvr.common.exception.GlobalException;
import com.cmvr.edge.client.manage.GrpcServiceManager; import com.cmvr.edge.client.manage.GrpcServiceManager;
import com.cmvr.edge.client.model.hlc.EdgeTouchVO; import com.cmvr.edge.client.model.hlc.EdgeTouchVO;
import com.cmvr.edge.client.service.EdgeHlcService; import com.cmvr.edge.client.service.EdgeHlcService;
@ -85,6 +86,9 @@ public class EdgeHlcServiceImpl implements EdgeHlcService {
@Override @Override
public String touch(EdgeTouchVO edgeTouchVO) { public String touch(EdgeTouchVO edgeTouchVO) {
if (edgeTouchVO.getX() == edgeTouchVO.getY() && edgeTouchVO.getX() == 0) {
throw new GlobalException("触控坐标不能为0");
}
HlcServiceGrpc.HlcServiceBlockingStub stub = grpcServiceManager.getGrpcClient(edgeTouchVO.getTerminalId(), HlcServiceGrpc.HlcServiceBlockingStub.class); HlcServiceGrpc.HlcServiceBlockingStub stub = grpcServiceManager.getGrpcClient(edgeTouchVO.getTerminalId(), HlcServiceGrpc.HlcServiceBlockingStub.class);
HlcCommand.Touch.Request request = HlcCommand.Touch.Request.newBuilder() HlcCommand.Touch.Request request = HlcCommand.Touch.Request.newBuilder()
.setHeader(EdgeCommonUtil.buildRequest(edgeTouchVO.getDeviceId())) .setHeader(EdgeCommonUtil.buildRequest(edgeTouchVO.getDeviceId()))

View File

@ -78,7 +78,11 @@ public class FlowControlService {
if (ctx.isPaused()) { if (ctx.isPaused()) {
throw new GlobalException("任务已处于暂停状态"); throw new GlobalException("任务已处于暂停状态");
} }
edgeSystemService.stopAll(ctx.getTerminalId()); try {
edgeSystemService.stopAll(ctx.getTerminalId());
} catch (Exception e) {
}
ctx.setPaused(true); ctx.setPaused(true);
ctx.setTerminalStatus(TerminalStatusEnum.RUNNING); ctx.setTerminalStatus(TerminalStatusEnum.RUNNING);
ctx.setStatus(TaskStatusEnum.PAUSED); ctx.setStatus(TaskStatusEnum.PAUSED);
@ -144,6 +148,7 @@ public class FlowControlService {
TaskNodeExecuteMessage resumeMessage = new TaskNodeExecuteMessage(); TaskNodeExecuteMessage resumeMessage = new TaskNodeExecuteMessage();
BeanUtil.copyProperties(pendingNode.getRootMessage(), resumeMessage); BeanUtil.copyProperties(pendingNode.getRootMessage(), resumeMessage);
resumeMessage.setLoopNum(pendingNode.getLoopIteration()); // 保留中断时的循环次数 resumeMessage.setLoopNum(pendingNode.getLoopIteration()); // 保留中断时的循环次数
resumeMessage.setLoopArray(pendingNode.getLoopArray()); // 保留中断时的循环次数
resumeMessage.setIterations(new ArrayList<>(pendingNode.getIterations())); // 保留中断时的路径 resumeMessage.setIterations(new ArrayList<>(pendingNode.getIterations())); // 保留中断时的路径
flowItemExecutor.executeNode( flowItemExecutor.executeNode(
@ -169,6 +174,7 @@ public class FlowControlService {
TaskNodeExecuteMessage resumeMessage = new TaskNodeExecuteMessage(); TaskNodeExecuteMessage resumeMessage = new TaskNodeExecuteMessage();
BeanUtil.copyProperties(pendingNode.getRootMessage(), resumeMessage); BeanUtil.copyProperties(pendingNode.getRootMessage(), resumeMessage);
resumeMessage.setLoopNum(pendingNode.getLoopIteration()); // 保留循环次数 resumeMessage.setLoopNum(pendingNode.getLoopIteration()); // 保留循环次数
resumeMessage.setLoopArray(pendingNode.getLoopArray()); // 保留循环次数
resumeMessage.setIterations(new ArrayList<>(pendingNode.getIterations())); // 保留路径 resumeMessage.setIterations(new ArrayList<>(pendingNode.getIterations())); // 保留路径
flowItemExecutor.executeNode( flowItemExecutor.executeNode(

View File

@ -8,6 +8,7 @@ import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List; import java.util.List;
@Slf4j @Slf4j
@ -18,17 +19,17 @@ public class FlowGetCurrentObjNodeHandler implements FlowNodeTypeHandler {
@Override @Override
public TaskNodeExecuteResult handle(TaskNodeExecuteMessage message) { public TaskNodeExecuteResult handle(TaskNodeExecuteMessage message) {
try { try {
JSONObject inputParams = message.getInputParams(); // JSONObject inputParams = message.getInputParams();
JSONArray jsonArray = inputParams.getJSONArray("array"); // JSONArray jsonArray = inputParams.getJSONArray("array");
//
List<Integer> iterations = message.getIterations(); // List<Integer> iterations = message.getIterations();
int last = CollUtil.getLast(iterations) - 1; // int last = CollUtil.getLast(iterations) - 1;
int index = message.getLoopNum() - 1;
JSONObject output = new JSONObject(); JSONObject output = new JSONObject();
output.put("index", last); output.put("index", index);
JSONArray objects = (JSONArray)message.getLoopArray();
if (CollUtil.isNotEmpty(jsonArray) && last >= 0) { if (CollUtil.isNotEmpty(objects) && index >= 0) {
output.put("object", jsonArray.get(last)); output.put("object", objects.get(index));
} }
return TaskNodeExecuteResult.success(output); return TaskNodeExecuteResult.success(output);

View File

@ -37,6 +37,7 @@ public class FlowLoopNodeHandler implements FlowNodeTypeHandler {
String nodeId = message.getNodeId(); String nodeId = message.getNodeId();
FlowNodeWrapper nodeWrapper = graph.getNode(nodeId); FlowNodeWrapper nodeWrapper = graph.getNode(nodeId);
int loopCount = inputParams.getIntValue("loopNum"); // 获取循环次数 int loopCount = inputParams.getIntValue("loopNum"); // 获取循环次数
Object loopArray = inputParams.get("loopArray"); // 获取循环次数
// 如果没有设置循环次数或者循环次数为 0则跳过处理 // 如果没有设置循环次数或者循环次数为 0则跳过处理
if (loopCount <= 0) { if (loopCount <= 0) {
@ -65,8 +66,9 @@ public class FlowLoopNodeHandler implements FlowNodeTypeHandler {
// 克隆 message并明确设置 loopNum // 克隆 message并明确设置 loopNum
TaskNodeExecuteMessage subMessage = new TaskNodeExecuteMessage(); TaskNodeExecuteMessage subMessage = new TaskNodeExecuteMessage();
BeanUtil.copyProperties(message, subMessage); BeanUtil.copyProperties(message, subMessage);
// subMessage.setLoopNum(i); // 当前 loop i subMessage.setLoopNum(i); // 当前 loop i
subMessage.setIterations(newIterations); // 完整路径 subMessage.setIterations(newIterations); // 完整路径
subMessage.setLoopArray(loopArray);
flowItemExecutor.executeSubGraph(subGraph, subMessage, latch::countDown, newIterations); flowItemExecutor.executeSubGraph(subGraph, subMessage, latch::countDown, newIterations);

View File

@ -84,7 +84,7 @@ public class FlowItemExecutor {
// 执行子图起始节点 // 执行子图起始节点
executeNode(subGraph, subStartNode, subStartNodeId, startInputDefs, executeNode(subGraph, subStartNode, subStartNodeId, startInputDefs,
rootMessage, onFinished, iterations); rootMessage, onFinished, iterations);
log.info("当前执行-子图");
// 启动子图调度 // 启动子图调度
flowTaskScheduler.subStart(subGraph, taskInstHolder.getContext(rootMessage.getInstId()), flowTaskScheduler.subStart(subGraph, taskInstHolder.getContext(rootMessage.getInstId()),
executor, onFinished, iterations); executor, onFinished, iterations);
@ -172,6 +172,8 @@ public class FlowItemExecutor {
// loopNum 不在这里计算而是由 FlowLoopNodeHandler / resume 显式写入 // loopNum 不在这里计算而是由 FlowLoopNodeHandler / resume 显式写入
// 如果 rootMessage 里已经带了 loopNum就沿用它 // 如果 rootMessage 里已经带了 loopNum就沿用它
message.setLoopNum(rootMessage.getLoopNum()); message.setLoopNum(rootMessage.getLoopNum());
message.setLoopArray(rootMessage.getLoopArray());
return message; return message;
} }

View File

@ -84,11 +84,12 @@ public class FlowNodeParamPreparer {
// 4 LOOP 节点动态计算 loopCount // 4 LOOP 节点动态计算 loopCount
if (node.getNodeType() == NodeTypeEnum.LOOP) { if (node.getNodeType() == NodeTypeEnum.LOOP) {
Object loopNumVal = input.get("loopNum"); Object loopNumVal = input.get("loopNum");
input.put("loopArray", loopNumVal);
int loopCount = 0; int loopCount = 0;
// 根据迭代路径找到当前层的集合对象 // 根据迭代路径找到当前层的集合对象
Object target = resolveLoopTarget(loopNumVal, rootMessage.getIterations(), 0); // Object target = resolveLoopTarget(loopNumVal, rootMessage.getIterations(), 0);
Object target = loopNumVal;
if (target instanceof JSONArray) { if (target instanceof JSONArray) {
loopCount = ((JSONArray) target).size(); loopCount = ((JSONArray) target).size();
} else if (target instanceof Collection) { } else if (target instanceof Collection) {

View File

@ -22,5 +22,6 @@ public class TaskNodeExecuteContext {
private TaskNodeExecuteMessage rootMessage; private TaskNodeExecuteMessage rootMessage;
private Runnable onFinished; private Runnable onFinished;
private int loopIteration; private int loopIteration;
private Object loopArray;
private List<Integer> iterations = new ArrayList<>(); private List<Integer> iterations = new ArrayList<>();
} }

View File

@ -55,6 +55,8 @@ public class TaskNodeExecuteMessage {
*/ */
private List<Integer> iterations = new ArrayList<>(); private List<Integer> iterations = new ArrayList<>();
private Object loopArray;
/** /**
* 节点名称 * 节点名称
*/ */

View File

@ -40,7 +40,7 @@ public class TiVehicleFunctionServiceImpl extends ServiceImpl<TiVehicleFunctionM
@Override @Override
public JSONObject selectTiVehicleFunctionDetailById(Long id) { public JSONObject selectTiVehicleFunctionDetailById(Long id) {
JSONObject jsonObject = JSONObject.from(this.getById(id)); JSONObject jsonObject = JSONObject.from(this.getById(id));
jsonObject.put("funcName", id== 26 ? "首页" : "设置"); jsonObject.put("funcName", sysDictDataService.selectDictLabel("ti_function_config", jsonObject.getString("funcKey")));
return jsonObject; return jsonObject;
} }