diff --git a/ruoyi-admin/src/main/java/com/ruoyi/wcs/flow/engine/FlowEngineService.java b/ruoyi-admin/src/main/java/com/ruoyi/wcs/flow/engine/FlowEngineService.java new file mode 100644 index 00000000..6fddfc39 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/wcs/flow/engine/FlowEngineService.java @@ -0,0 +1,246 @@ +package com.ruoyi.wcs.flow.engine; + +import java.util.*; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.ruoyi.wcs.flow.domain.*; +import com.ruoyi.wcs.flow.service.*; + +/** + * WCS 轻量流程执行引擎 + * 按流程定义依次执行节点,记录实例和节点日志 + * + * @author wcs + */ +@Service +public class FlowEngineService +{ + private static final Logger log = LoggerFactory.getLogger(FlowEngineService.class); + + private Map handlerMap = new HashMap<>(); + + @Autowired + private IWcsFlowDefService flowDefService; + + @Autowired + private IWcsFlowNodeService flowNodeService; + + @Autowired + private IWcsFlowLineService flowLineService; + + @Autowired + private IWcsFlowInstanceService flowInstanceService; + + @Autowired + private IWcsFlowNodeLogService flowNodeLogService; + + @Autowired + public void setHandlers(List handlers) + { + for (INodeHandler handler : handlers) + { + handlerMap.put(handler.getNodeType(), handler); + } + log.info("[FlowEngine] 已注册 {} 个节点处理器: {}", handlerMap.size(), handlerMap.keySet()); + } + + /** + * 执行流程 + * + * @param flowDefId 流程定义ID + * @return 流程实例ID + */ + @Transactional + public Long executeFlow(Long flowDefId) + { + // 1. 查询流程定义 + WcsFlowDef flowDef = flowDefService.selectFlowDefById(flowDefId); + if (flowDef == null) + { + throw new RuntimeException("流程定义不存在: " + flowDefId); + } + if (!"1".equals(flowDef.getStatus())) + { + throw new RuntimeException("流程未发布,无法执行: " + flowDef.getFlowCode()); + } + + // 2. 创建流程实例 + WcsFlowInstance instance = new WcsFlowInstance(); + instance.setFlowDefId(flowDefId); + instance.setStatus("1"); // 执行中 + instance.setStartTime(new Date()); + flowInstanceService.insertFlowInstance(instance); + Long instanceId = instance.getId(); + log.info("[FlowEngine] 流程实例创建: instanceId={}, flowCode={}", instanceId, flowDef.getFlowCode()); + + // 3. 加载节点和连线 + List nodes = flowNodeService.selectFlowNodeListByFlowId(flowDefId); + List lines = flowLineService.selectFlowLineListByFlowId(flowDefId); + + // 按nodeId建索引 + Map nodeMap = nodes.stream() + .collect(Collectors.toMap(WcsFlowNode::getNodeId, n -> n)); + + // 4. 找到开始节点 + WcsFlowNode currentNode = findStartNode(nodes); + if (currentNode == null) + { + updateInstanceStatus(instance, "3", "未找到开始节点"); + throw new RuntimeException("流程缺少开始节点: " + flowDef.getFlowCode()); + } + + // 5. 执行上下文 + Map context = new HashMap<>(); + context.put("flowDefId", flowDefId); + context.put("instanceId", instanceId); + + // 6. 按连线顺序执行 + int maxSteps = 100; // 防止死循环 + int step = 0; + try + { + while (currentNode != null && step < maxSteps) + { + step++; + log.info("[FlowEngine] 执行节点: step={}, nodeId={}, type={}, name={}", + step, currentNode.getNodeId(), currentNode.getNodeType(), currentNode.getNodeName()); + + // 记录节点日志-开始 + WcsFlowNodeLog nodeLog = new WcsFlowNodeLog(); + nodeLog.setInstanceId(instanceId); + nodeLog.setNodeId(String.valueOf(currentNode.getNodeId())); + nodeLog.setNodeType(currentNode.getNodeType()); + nodeLog.setStatus("1"); // 执行中 + nodeLog.setStartTime(new Date()); + flowNodeLogService.insertFlowNodeLog(nodeLog); + + // 获取handler + INodeHandler handler = getHandler(currentNode.getNodeType()); + if (handler == null) + { + nodeLog.setStatus("3"); // 失败 + nodeLog.setErrorMsg("未找到节点处理器: " + currentNode.getNodeType()); + nodeLog.setEndTime(new Date()); + flowNodeLogService.updateFlowNodeLog(nodeLog); + updateInstanceStatus(instance, "3", nodeLog.getErrorMsg()); + return instanceId; + } + + // 执行节点 + NodeResult result = handler.execute(currentNode.getConfigJson(), context); + + // 更新节点日志 + nodeLog.setEndTime(new Date()); + if (result.isSuccess()) + { + nodeLog.setStatus("2"); // 成功 + nodeLog.setOutput(result.getOutput()); + } + else + { + nodeLog.setStatus("3"); // 失败 + nodeLog.setErrorMsg(result.getErrorMsg()); + flowNodeLogService.updateFlowNodeLog(nodeLog); + updateInstanceStatus(instance, "3", result.getErrorMsg()); + return instanceId; + } + flowNodeLogService.updateFlowNodeLog(nodeLog); + + // end节点,流程结束 + if ("end".equals(currentNode.getNodeType())) + { + log.info("[FlowEngine] 流程执行完成: instanceId={}", instanceId); + updateInstanceStatus(instance, "2", null); // 已完成 + return instanceId; + } + + // 找下一个节点 + currentNode = findNextNode(currentNode, result, lines, nodeMap); + } + + // 超过最大步数 + if (step >= maxSteps) + { + updateInstanceStatus(instance, "3", "超过最大执行步数: " + maxSteps); + } + } + catch (Exception e) + { + log.error("[FlowEngine] 流程执行异常: instanceId={}", instanceId, e); + updateInstanceStatus(instance, "3", e.getMessage()); + } + + return instanceId; + } + + /** + * 找开始节点 + */ + private WcsFlowNode findStartNode(List nodes) + { + return nodes.stream() + .filter(n -> "start".equals(n.getNodeType())) + .findFirst() + .orElse(null); + } + + /** + * 根据连线找下一个节点 + */ + private WcsFlowNode findNextNode(WcsFlowNode current, NodeResult result, + List lines, Map nodeMap) + { + List outLines = lines.stream() + .filter(l -> current.getNodeId().equals(l.getSourceNodeId())) + .sorted(Comparator.comparingInt(l -> l.getSortOrder() != null ? l.getSortOrder() : 0)) + .collect(Collectors.toList()); + + if (outLines.isEmpty()) + { + return null; + } + + // condition节点:按branchKey匹配conditionExpr + if ("condition".equals(current.getNodeType()) && result.getBranchKey() != null) + { + for (WcsFlowLine line : outLines) + { + if (result.getBranchKey().equals(line.getConditionExpr())) + { + return nodeMap.get(line.getTargetNodeId()); + } + } + // 没匹配到,走第一条(默认分支) + log.warn("[FlowEngine] 条件分支未匹配, branchKey={}, 走默认分支", result.getBranchKey()); + } + + // 非condition节点或默认:走第一条连线 + return nodeMap.get(outLines.get(0).getTargetNodeId()); + } + + /** + * 获取节点处理器 + */ + private INodeHandler getHandler(String nodeType) + { + return handlerMap.get(nodeType); + } + + /** + * 更新流程实例状态 + */ + private void updateInstanceStatus(WcsFlowInstance instance, String status, String remark) + { + instance.setStatus(status); + instance.setEndTime(new Date()); + if (remark != null) + { + instance.setRemark(remark); + } + flowInstanceService.updateFlowInstance(instance); + } +}