package com.zy.core.utils.station; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.core.common.Cools; import com.core.exception.CoolException; import com.zy.asrs.entity.BasDevp; import com.zy.asrs.entity.LocMast; import com.zy.asrs.entity.WrkMast; import com.zy.asrs.service.LocMastService; import com.zy.asrs.service.WrkMastService; import com.zy.common.entity.FindCrnNoResult; import com.zy.common.model.NavigateNode; import com.zy.common.model.StartupDto; import com.zy.common.service.CommonService; import com.zy.common.utils.NavigateUtils; import com.zy.common.utils.RedisUtil; import com.zy.core.News; import com.zy.core.cache.SlaveConnection; import com.zy.core.dispatch.StationCommandDispatchResult; import com.zy.core.dispatch.StationCommandDispatcher; import com.zy.core.enums.RedisKeyType; import com.zy.core.enums.SlaveType; import com.zy.core.enums.StationCommandType; import com.zy.core.enums.WrkIoType; import com.zy.core.enums.WrkStsType; import com.zy.core.model.StationObjModel; import com.zy.core.model.command.StationCommand; import com.zy.core.model.protocol.StationProtocol; import com.zy.core.model.protocol.StationTaskBufferItem; import com.zy.core.move.StationMoveCoordinator; import com.zy.core.thread.StationThread; import com.zy.core.utils.station.model.OutOrderDispatchDecision; import com.zy.core.utils.station.model.RerouteCommandPlan; import com.zy.core.utils.station.model.RerouteContext; import com.zy.core.utils.station.model.RerouteDecision; import com.zy.core.utils.station.model.RerouteExecutionResult; import com.zy.core.utils.station.model.RerouteSceneType; import com.zy.core.utils.WmsOperateUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Objects; @Component public class StationRerouteProcessor { private static final int OUT_ORDER_DISPATCH_LIMIT_SECONDS = 2; private static final long STATION_MOVE_RESET_WAIT_MS = 1000L; private static final int RUN_BLOCK_DIRECT_REASSIGN_LIMIT_SECONDS = 8 * 60; private static final int RUN_BLOCK_DIRECT_REASSIGN_NEAREST_CACHE_SECONDS = 60 * 60 * 24; @Autowired private WrkMastService wrkMastService; @Autowired private CommonService commonService; @Autowired private RedisUtil redisUtil; @Autowired private LocMastService locMastService; @Autowired private WmsOperateUtils wmsOperateUtils; @Autowired private StationMoveCoordinator stationMoveCoordinator; @Autowired private StationCommandDispatcher stationCommandDispatcher; @Autowired private StationOutboundDecisionSupport stationOutboundDecisionSupport; @Autowired private StationDispatchRuntimeStateSupport stationDispatchRuntimeStateSupport; @Autowired private NavigateUtils navigateUtils; public void checkStationRunBlock(BasDevp basDevp, Integer stationId) { try { if (basDevp == null || basDevp.getDevpNo() == null || stationId == null) { return; } if (shouldSkipRunBlockStation(basDevp, stationId)) { return; } StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo()); if (stationThread == null) { return; } Map statusMap = stationThread.getStatusMap(); StationProtocol stationProtocol = statusMap == null ? null : statusMap.get(stationId); if (stationProtocol == null || !stationProtocol.isAutoing() || !stationProtocol.isLoading() || stationProtocol.getTaskNo() <= 0 || !stationProtocol.isRunBlock()) { return; } List runBlockReassignLocStationList = new ArrayList<>(); for (StationObjModel stationObjModel : basDevp.getRunBlockReassignLocStationList$()) { runBlockReassignLocStationList.add(stationObjModel.getStationId()); } List outOrderStationIds = basDevp.getOutOrderIntList(); WrkMast wrkMast = wrkMastService.selectByWorkNo(stationProtocol.getTaskNo()); if (wrkMast == null) { News.info("输送站点号={} 运行阻塞,但无法找到对应任务,工作号={}", stationProtocol.getStationId(), stationProtocol.getTaskNo()); return; } Object lock = redisUtil.get(RedisKeyType.CHECK_STATION_RUN_BLOCK_LIMIT_.key + stationProtocol.getTaskNo()); if (lock != null) { return; } redisUtil.set(RedisKeyType.CHECK_STATION_RUN_BLOCK_LIMIT_.key + stationProtocol.getTaskNo(), "lock", 30); if (shouldUseRunBlockDirectReassign(wrkMast, stationProtocol.getStationId(), runBlockReassignLocStationList)) { if (stationMoveCoordinator != null) { stationMoveCoordinator.withTaskDispatchLock(stationProtocol.getTaskNo(), () -> { executeRunBlockDirectReassign(basDevp, stationThread, stationProtocol, wrkMast); return null; }); } else { executeRunBlockDirectReassign(basDevp, stationThread, stationProtocol, wrkMast); } return; } Double pathLenFactor = stationOutboundDecisionSupport.resolveOutboundPathLenFactor(wrkMast); RerouteContext context = RerouteContext.create( RerouteSceneType.RUN_BLOCK_REROUTE, basDevp, stationThread, stationProtocol, wrkMast, outOrderStationIds, pathLenFactor, "checkStationRunBlock_reroute" ).withRunBlockCommand() .withSuppressDispatchGuard() .withCancelSessionBeforeDispatch() .withResetSegmentCommandsBeforeDispatch(); executeSharedReroute(context); } catch (Exception e) { e.printStackTrace(); } } public void checkStationOutOrder(BasDevp basDevp, StationObjModel stationObjModel) { try { if (basDevp == null || basDevp.getDevpNo() == null || stationObjModel == null || stationObjModel.getStationId() == null) { return; } StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo()); if (stationThread == null) { return; } Map statusMap = stationThread.getStatusMap(); StationProtocol stationProtocol = statusMap == null ? null : statusMap.get(stationObjModel.getStationId()); if (stationProtocol == null || !stationProtocol.isAutoing() || !stationProtocol.isLoading() || stationProtocol.getTaskNo() <= 0 || stationProtocol.isRunBlock() || !stationProtocol.getStationId().equals(stationProtocol.getTargetStaNo())) { return; } WrkMast wrkMast = wrkMastService.selectByWorkNo(stationProtocol.getTaskNo()); if (wrkMast == null || !Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts) || Objects.equals(stationProtocol.getStationId(), wrkMast.getStaNo())) { return; } if (stationOutboundDecisionSupport.shouldSkipOutOrderDispatchForExistingRoute(wrkMast.getWrkNo(), stationProtocol.getStationId())) { return; } Double pathLenFactor = stationOutboundDecisionSupport.resolveOutboundPathLenFactor(wrkMast); RerouteContext context = RerouteContext.create( RerouteSceneType.OUT_ORDER, basDevp, stationThread, stationProtocol, wrkMast, basDevp.getOutOrderIntList(), pathLenFactor, "checkStationOutOrder" ).withDispatchDeviceNo(stationObjModel.getDeviceNo()) .withSuppressDispatchGuard() .withOutOrderDispatchLock() .withResetSegmentCommandsBeforeDispatch(); executeSharedReroute(context); } catch (Exception e) { e.printStackTrace(); } } public RerouteCommandPlan buildRerouteCommandPlan(RerouteContext context, RerouteDecision decision) { if (context == null) { return RerouteCommandPlan.skip("missing-context"); } if (decision == null) { return RerouteCommandPlan.skip("missing-decision"); } if (decision.skip()) { return RerouteCommandPlan.skip(decision.skipReason()); } if (context.stationThread() == null || context.stationProtocol() == null || context.wrkMast() == null) { return RerouteCommandPlan.skip("missing-runtime-dependency"); } Integer currentStationId = context.stationProtocol().getStationId(); Integer targetStationId = decision.targetStationId(); if (currentStationId == null || targetStationId == null) { return RerouteCommandPlan.skip("missing-target-station"); } if (Objects.equals(currentStationId, targetStationId)) { return RerouteCommandPlan.skip("same-station"); } StationCommand command = context.useRunBlockCommand() ? context.stationThread().getRunBlockRerouteCommand( context.wrkMast().getWrkNo(), currentStationId, targetStationId, 0, context.pathLenFactor() ) : stationOutboundDecisionSupport.buildOutboundMoveCommand( context.stationThread(), context.wrkMast(), currentStationId, targetStationId, context.pathLenFactor() ); if (command == null) { if (context.sceneType() == RerouteSceneType.RUN_BLOCK_REROUTE) { News.taskInfo(context.wrkMast().getWrkNo(), "输送站点堵塞重规划未找到可下发路线,当前站点={},目标站点={}", currentStationId, targetStationId); } else if (context.sceneType() == RerouteSceneType.IDLE_RECOVER) { News.taskInfo(context.wrkMast().getWrkNo(), "站点任务停留超时后重算路径失败,当前站点={},目标站点={}", currentStationId, targetStationId); } else { News.taskInfo(context.wrkMast().getWrkNo(), "获取输送线命令失败"); } return RerouteCommandPlan.skip("missing-command"); } return RerouteCommandPlan.dispatch(command, decision, context.dispatchScene()); } public RerouteExecutionResult executeReroutePlan(RerouteContext context, RerouteCommandPlan plan) { if (context == null) { return RerouteExecutionResult.skip("missing-context"); } if (plan == null) { return RerouteExecutionResult.skip("missing-plan"); } if (plan.skip()) { return RerouteExecutionResult.skip(plan.skipReason()); } StationProtocol stationProtocol = context.stationProtocol(); if (stationProtocol == null) { return RerouteExecutionResult.skip("missing-station-protocol"); } Integer taskNo = stationProtocol.getTaskNo(); Integer stationId = stationProtocol.getStationId(); if (taskNo == null || taskNo <= 0 || stationId == null) { return RerouteExecutionResult.skip("invalid-station-task"); } if (stationMoveCoordinator != null) { return stationMoveCoordinator.withTaskDispatchLock(taskNo, () -> executeReroutePlanWithTaskLock(context, plan, stationProtocol, taskNo, stationId)); } return executeReroutePlanWithTaskLock(context, plan, stationProtocol, taskNo, stationId); } public RerouteDecision resolveSharedRerouteDecision(RerouteContext context) { if (context == null || context.wrkMast() == null || context.stationProtocol() == null) { return RerouteDecision.skip("missing-runtime-dependency"); } Integer currentStationId = context.stationProtocol().getStationId(); if (currentStationId == null) { return RerouteDecision.skip("missing-current-station"); } if (context.sceneType() == RerouteSceneType.IDLE_RECOVER && !Objects.equals(context.wrkMast().getWrkSts(), WrkStsType.STATION_RUN.sts)) { Integer targetStationId = context.wrkMast().getStaNo(); return targetStationId == null || Objects.equals(targetStationId, currentStationId) ? RerouteDecision.skip("same-station") : RerouteDecision.proceed(targetStationId); } OutOrderDispatchDecision dispatchDecision = stationOutboundDecisionSupport.resolveOutboundDispatchDecision( currentStationId, context.wrkMast(), context.outOrderStationIds(), context.pathLenFactor() ); Integer targetStationId = dispatchDecision == null ? null : dispatchDecision.getTargetStationId(); if (targetStationId == null || Objects.equals(targetStationId, currentStationId)) { return RerouteDecision.skip("same-station"); } return RerouteDecision.proceed(targetStationId, dispatchDecision); } public boolean shouldUseRunBlockDirectReassign(WrkMast wrkMast, Integer stationId, List runBlockReassignLocStationList) { if (wrkMast == null || stationId == null) { return false; } if (!Objects.equals(wrkMast.getIoType(), WrkIoType.IN.id)) { return false; } if (runBlockReassignLocStationList == null || !runBlockReassignLocStationList.contains(stationId)) { return false; } if (shouldForceRunBlockPathReroute(wrkMast, stationId, runBlockReassignLocStationList)) { return false; } return true; } private boolean shouldForceRunBlockPathReroute(WrkMast wrkMast, Integer stationId, List runBlockReassignLocStationList) { if (wrkMast == null || stationId == null) { return false; } Integer nearestStationId = resolveNearestRunBlockDirectReassignStationId(wrkMast, runBlockReassignLocStationList); return nearestStationId != null && !Objects.equals(stationId, nearestStationId); } private Integer resolveNearestRunBlockDirectReassignStationId(WrkMast wrkMast, List runBlockReassignLocStationList) { if (wrkMast == null || wrkMast.getStaNo() == null || navigateUtils == null || runBlockReassignLocStationList == null || runBlockReassignLocStationList.isEmpty()) { return null; } Integer targetStationId = wrkMast.getStaNo(); Integer cachedStationId = loadCachedNearestRunBlockDirectReassignStationId(targetStationId, runBlockReassignLocStationList); if (cachedStationId != null) { return cachedStationId; } Integer nearestStationId = null; int nearestPathLen = Integer.MAX_VALUE; for (Integer candidateStationId : runBlockReassignLocStationList) { if (candidateStationId == null) { continue; } List path = navigateUtils.calcOptimalPathByStationId(candidateStationId, targetStationId, wrkMast.getWrkNo(), null); if (path == null || path.isEmpty()) { continue; } int pathLen = countStationNodes(path); if (pathLen <= 0) { continue; } if (pathLen < nearestPathLen || (pathLen == nearestPathLen && nearestStationId != null && candidateStationId < nearestStationId)) { nearestStationId = candidateStationId; nearestPathLen = pathLen; } } cacheNearestRunBlockDirectReassignStationId(targetStationId, runBlockReassignLocStationList, nearestStationId); return nearestStationId; } private Integer loadCachedNearestRunBlockDirectReassignStationId(Integer targetStationId, List runBlockReassignLocStationList) { String cacheKey = buildNearestRunBlockDirectReassignCacheKey(targetStationId, runBlockReassignLocStationList); if (cacheKey == null || redisUtil == null) { return null; } Object cacheValue = redisUtil.get(cacheKey); if (cacheValue == null) { return null; } try { Integer stationId = Integer.valueOf(String.valueOf(cacheValue)); return runBlockReassignLocStationList.contains(stationId) ? stationId : null; } catch (Exception ignore) { return null; } } private void cacheNearestRunBlockDirectReassignStationId(Integer targetStationId, List runBlockReassignLocStationList, Integer nearestStationId) { String cacheKey = buildNearestRunBlockDirectReassignCacheKey(targetStationId, runBlockReassignLocStationList); if (cacheKey == null || nearestStationId == null || redisUtil == null) { return; } redisUtil.set(cacheKey, nearestStationId, RUN_BLOCK_DIRECT_REASSIGN_NEAREST_CACHE_SECONDS); } private String buildNearestRunBlockDirectReassignCacheKey(Integer targetStationId, List runBlockReassignLocStationList) { if (targetStationId == null || runBlockReassignLocStationList == null || runBlockReassignLocStationList.isEmpty()) { return null; } List normalizedStationIdList = new ArrayList<>(); for (Integer stationId : runBlockReassignLocStationList) { if (stationId != null && !normalizedStationIdList.contains(stationId)) { normalizedStationIdList.add(stationId); } } if (normalizedStationIdList.isEmpty()) { return null; } Collections.sort(normalizedStationIdList); return RedisKeyType.STATION_RUN_BLOCK_DIRECT_REASSIGN_NEAREST_CACHE_.key + targetStationId + "_" + JSON.toJSONString(normalizedStationIdList); } private int countStationNodes(List path) { if (path == null || path.isEmpty()) { return 0; } int count = 0; for (NavigateNode node : path) { if (extractStationId(node) != null) { count++; } } return count; } private Integer extractStationId(NavigateNode node) { if (node == null || Cools.isEmpty(node.getNodeValue())) { return null; } try { JSONObject valueObject = JSONObject.parseObject(node.getNodeValue()); return valueObject == null ? null : valueObject.getInteger("stationId"); } catch (Exception ignore) { return null; } } private boolean shouldSkipRunBlockStation(BasDevp basDevp, Integer stationId) { if (basDevp == null || stationId == null) { return false; } return containsStation(basDevp.getBarcodeStationList$(), stationId) || containsStation(basDevp.getInStationList$(), stationId); } private boolean containsStation(List stationList, Integer stationId) { if (stationList == null || stationList.isEmpty() || stationId == null) { return false; } for (StationObjModel stationObjModel : stationList) { if (stationObjModel != null && Objects.equals(stationObjModel.getStationId(), stationId)) { return true; } } return false; } private RerouteExecutionResult executeReroutePlanWithTaskLock(RerouteContext context, RerouteCommandPlan plan, StationProtocol stationProtocol, Integer taskNo, Integer stationId) { boolean runBlockReroute = context.sceneType() == RerouteSceneType.RUN_BLOCK_REROUTE; int currentTaskBufferCommandCount = countCurrentTaskBufferCommands(stationProtocol.getTaskBufferItems(), taskNo); if (currentTaskBufferCommandCount > 0 && !runBlockReroute) { return RerouteExecutionResult.skip("buffer-has-current-task"); } if (currentTaskBufferCommandCount > 0 && runBlockReroute) { News.info("输送站点运行堵塞重规划检测到旧分段命令残留,已先清理本地状态后继续重发。站点号={},工作号={},当前任务命令数={}", stationId, taskNo, currentTaskBufferCommandCount); } if (!runBlockReroute && context.checkSuppressDispatch() && stationMoveCoordinator != null && stationMoveCoordinator.shouldSuppressDispatch(taskNo, stationId, plan.command())) { return RerouteExecutionResult.skip("dispatch-suppressed"); } if (context.requireOutOrderDispatchLock() && !stationDispatchRuntimeStateSupport.tryAcquireOutOrderDispatchLock(taskNo, stationId, OUT_ORDER_DISPATCH_LIMIT_SECONDS)) { return RerouteExecutionResult.skip("out-order-lock"); } if (!isBlank(context.executionLockKey()) && !stationDispatchRuntimeStateSupport.tryAcquireLock(context.executionLockKey(), context.executionLockSeconds())) { return RerouteExecutionResult.skip("scene-lock"); } if (context.resetSegmentCommandsBeforeDispatch()) { stationDispatchRuntimeStateSupport.signalSegmentReset(taskNo, STATION_MOVE_RESET_WAIT_MS); } int clearedCommandCount = 0; boolean offered = offerDevpCommandWithDedup(context.dispatchDeviceNo(), plan.command(), plan.dispatchScene()); if (!offered) { return RerouteExecutionResult.skip("dispatch-dedup"); } if (context.cancelSessionBeforeDispatch() && stationMoveCoordinator != null) { stationMoveCoordinator.markCancelPending(taskNo, "reroute_pending"); stationMoveCoordinator.cancelSession(taskNo); } applyRerouteDispatchEffects(context, plan, clearedCommandCount); return RerouteExecutionResult.dispatched(plan.command(), clearedCommandCount); } private RerouteExecutionResult executeSharedReroute(RerouteContext context) { RerouteDecision decision = resolveSharedRerouteDecision(context); if (decision.skip()) { return RerouteExecutionResult.skip(decision.skipReason()); } RerouteCommandPlan plan = buildRerouteCommandPlan(context, decision); return executeReroutePlan(context, plan); } private void applyRerouteDispatchEffects(RerouteContext context, RerouteCommandPlan plan, int clearedCommandCount) { if (context == null || plan == null || plan.command() == null || context.wrkMast() == null || context.stationProtocol() == null) { return; } WrkMast wrkMast = context.wrkMast(); StationProtocol stationProtocol = context.stationProtocol(); OutOrderDispatchDecision dispatchDecision = plan.decision() == null ? null : plan.decision().dispatchDecision(); stationOutboundDecisionSupport.syncOutOrderWatchState( wrkMast, stationProtocol.getStationId(), context.outOrderStationIds(), dispatchDecision, plan.command() ); if (stationMoveCoordinator != null) { stationMoveCoordinator.recordDispatch( wrkMast.getWrkNo(), stationProtocol.getStationId(), plan.dispatchScene(), plan.command(), dispatchDecision != null && dispatchDecision.isCircle() ); } if (context.sceneType() == RerouteSceneType.RUN_BLOCK_REROUTE) { News.info("输送站点堵塞后重新计算路径命令下发成功,站点号={},工作号={},命令数据={}", stationProtocol.getStationId(), wrkMast.getWrkNo(), JSON.toJSONString(plan.command())); return; } if (context.sceneType() == RerouteSceneType.OUT_ORDER) { News.info(dispatchDecision != null && dispatchDecision.isCircle() ? "{}任务进行绕圈" : "{}任务直接去目标点", wrkMast.getWrkNo()); } } private void executeRunBlockDirectReassign(BasDevp basDevp, StationThread stationThread, StationProtocol stationProtocol, WrkMast wrkMast) { if (basDevp == null || stationThread == null || stationProtocol == null || wrkMast == null) { return; } int currentTaskBufferCommandCount = countCurrentTaskBufferCommands( stationProtocol.getTaskBufferItems(), stationProtocol.getTaskNo() ); if (currentTaskBufferCommandCount > 0) { News.info("输送站点运行堵塞重分配检测到旧分段命令残留,将先重置本地分段状态后继续重发。站点号={},工作号={},当前任务命令数={}", stationProtocol.getStationId(), stationProtocol.getTaskNo(), currentTaskBufferCommandCount); } if (stationDispatchRuntimeStateSupport.hasRunBlockDirectReassignLimit( wrkMast.getWrkNo(), stationProtocol.getStationId())) { News.info("输送站点运行堵塞重分配已跳过,8分钟内不允许重复申请。站点号={},工作号={}", stationProtocol.getStationId(), wrkMast.getWrkNo()); return; } String response = wmsOperateUtils.applyReassignTaskLocNo(wrkMast.getWrkNo(), stationProtocol.getStationId()); if (Cools.isEmpty(response)) { News.taskError(wrkMast.getWrkNo(), "请求WMS重新分配库位接口失败,接口未响应!!!response:{}", response); return; } JSONObject jsonObject = JSON.parseObject(response); if (!jsonObject.getInteger("code").equals(200)) { News.error("请求WMS接口失败!!!response:{}", response); return; } StartupDto dto = jsonObject.getObject("data", StartupDto.class); String sourceLocNo = wrkMast.getLocNo(); String locNo = dto.getLocNo(); LocMast sourceLocMast = locMastService.queryByLoc(sourceLocNo); if (sourceLocMast == null) { News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 源库位信息不存在", sourceLocNo); return; } if (!sourceLocMast.getLocSts().equals("S")) { News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 源库位状态不处于入库预约", sourceLocNo); return; } LocMast locMast = locMastService.queryByLoc(locNo); if (locMast == null) { News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 目标库位信息不存在", locNo); return; } if (!locMast.getLocSts().equals("O")) { News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 目标库位状态不处于空库位", locNo); return; } FindCrnNoResult findCrnNoResult = commonService.findCrnNoByLocNo(locNo); if (findCrnNoResult == null) { News.taskInfo(wrkMast.getWrkNo(), "{}工作,未匹配到堆垛机", wrkMast.getWrkNo()); return; } Integer crnNo = findCrnNoResult.getCrnNo(); Integer targetStationId = commonService.findInStationId(findCrnNoResult, stationProtocol.getStationId()); if (targetStationId == null) { News.taskInfo(wrkMast.getWrkNo(), "{}站点,搜索入库站点失败", stationProtocol.getStationId()); return; } StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), targetStationId, 0); if (command == null) { News.taskInfo(wrkMast.getWrkNo(), "{}工作,获取输送线命令失败", wrkMast.getWrkNo()); return; } sourceLocMast.setLocSts("O"); sourceLocMast.setModiTime(new Date()); locMastService.updateById(sourceLocMast); locMast.setLocSts("S"); locMast.setModiTime(new Date()); locMastService.updateById(locMast); wrkMast.setLocNo(locNo); wrkMast.setStaNo(targetStationId); if (findCrnNoResult.getCrnType().equals(SlaveType.Crn)) { wrkMast.setCrnNo(crnNo); } else if (findCrnNoResult.getCrnType().equals(SlaveType.DualCrn)) { wrkMast.setDualCrnNo(crnNo); } else { throw new CoolException("未知设备类型"); } if (!wrkMastService.updateById(wrkMast)) { return; } stationDispatchRuntimeStateSupport.recordRunBlockDirectReassignLimit( wrkMast.getWrkNo(), stationProtocol.getStationId(), RUN_BLOCK_DIRECT_REASSIGN_LIMIT_SECONDS); stationDispatchRuntimeStateSupport.signalSegmentReset(wrkMast.getWrkNo(), STATION_MOVE_RESET_WAIT_MS); boolean offered = offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "checkStationRunBlock_direct"); if (!offered) { return; } if (stationMoveCoordinator != null) { stationMoveCoordinator.markCancelPending(wrkMast.getWrkNo(), "reroute_pending"); stationMoveCoordinator.cancelSession(wrkMast.getWrkNo()); stationMoveCoordinator.recordDispatch( wrkMast.getWrkNo(), stationProtocol.getStationId(), "checkStationRunBlock_direct", command, false ); } } private int countCurrentTaskBufferCommands(List taskBufferItems, Integer currentTaskNo) { if (taskBufferItems == null || taskBufferItems.isEmpty() || currentTaskNo == null || currentTaskNo <= 0) { return 0; } int count = 0; for (StationTaskBufferItem item : taskBufferItems) { if (item == null || item.getTaskNo() == null) { continue; } if (currentTaskNo.equals(item.getTaskNo())) { count++; } } return count; } private boolean offerDevpCommandWithDedup(Integer deviceNo, StationCommand command, String scene) { StationCommandDispatchResult dispatchResult = stationCommandDispatcher .dispatch(deviceNo, command, "station-operate-process", scene); return dispatchResult.isAccepted(); } private boolean isBlank(String value) { return value == null || value.trim().isEmpty(); } }