#
Junjie
13 小时以前 02551a6a9aa82dd483fe059890767853f15ee172
src/main/java/com/zy/core/utils/StationOperateProcessUtils.java
@@ -20,6 +20,7 @@
import com.zy.common.utils.NavigateUtils;
import com.zy.common.utils.RedisUtil;
import com.zy.core.move.StationMoveCoordinator;
import com.zy.core.move.StationMoveDispatchMode;
import com.zy.core.move.StationMoveSession;
import com.zy.core.News;
import com.zy.core.cache.MessageQueue;
@@ -162,7 +163,16 @@
                        wrkMast.setModiTime(now);
                        if (wrkMastService.updateById(wrkMast)) {
                            wrkAnalysisService.markInboundStationStart(wrkMast, now);
                            offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "stationInExecute");
                            boolean offered = offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "stationInExecute");
                            if (offered && stationMoveCoordinator != null) {
                                stationMoveCoordinator.recordDispatch(
                                        wrkMast.getWrkNo(),
                                        stationProtocol.getStationId(),
                                        "stationInExecute",
                                        command,
                                        false
                                );
                            }
                            News.info("输送站点入库命令下发成功,站点号={},工作号={},命令数据={}", stationId, wrkMast.getWrkNo(), JSON.toJSONString(command));
                            redisUtil.set(RedisKeyType.STATION_IN_EXECUTE_LIMIT.key + stationId, "lock", 5);
                            loadGuardState.reserveLoopTask(loopHitResult.getLoopNo());
@@ -333,7 +343,16 @@
                    wrkMast.setSystemMsg("");
                    wrkMast.setIoTime(new Date());
                    if (wrkMastService.updateById(wrkMast)) {
                        offerDevpCommandWithDedup(stationObjModel.getDeviceNo(), command, "dualCrnStationOutExecute");
                        boolean offered = offerDevpCommandWithDedup(stationObjModel.getDeviceNo(), command, "dualCrnStationOutExecute");
                        if (offered && stationMoveCoordinator != null) {
                            stationMoveCoordinator.recordDispatch(
                                    wrkMast.getWrkNo(),
                                    stationProtocol.getStationId(),
                                    "dualCrnStationOutExecute",
                                    command,
                                    false
                            );
                        }
                        notifyUtils.notify(String.valueOf(SlaveType.Devp), stationObjModel.getDeviceNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.STATION_OUT_TASK_RUN, null);
                        News.info("输送站点出库命令下发成功,站点号={},工作号={},命令数据={}", stationProtocol.getStationId(), wrkMast.getWrkNo(), JSON.toJSONString(command));
                        redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_LIMIT.key + stationProtocol.getStationId(), "lock", 5);
@@ -483,169 +502,26 @@
                        }
                        redisUtil.set(RedisKeyType.CHECK_STATION_RUN_BLOCK_LIMIT_.key + stationProtocol.getTaskNo(), "lock", 15);
                        if (wrkMast.getIoType() == WrkIoType.IN.id && runBlockReassignLocStationList.contains(stationProtocol.getStationId())) {
                            //站点处于重新分配库位区域
                            int currentTaskBufferCommandCount = countCurrentTaskBufferCommands(
                                    stationProtocol.getTaskBufferItems(),
                                    stationProtocol.getTaskNo()
                            );
                            if (currentTaskBufferCommandCount > 0) {
                                News.info("输送站点运行堵塞重分配已跳过,缓存区仍存在当前任务命令。站点号={},工作号={},当前任务命令数={}",
                                        stationProtocol.getStationId(),
                                        stationProtocol.getTaskNo(),
                                        currentTaskBufferCommandCount);
                                continue;
                            }
                            if (stationMoveCoordinator != null) {
                                stationMoveCoordinator.cancelSession(wrkMast.getWrkNo());
                            }
                            //运行堵塞,重新申请任务
                            String response = wmsOperateUtils.applyReassignTaskLocNo(wrkMast.getWrkNo(), stationProtocol.getStationId());
                            if (Cools.isEmpty(response)) {
                                News.taskError(wrkMast.getWrkNo(), "请求WMS重新分配库位接口失败,接口未响应!!!response:{}", response);
                                continue;
                            }
                            JSONObject jsonObject = JSON.parseObject(response);
                            if (jsonObject.getInteger("code").equals(200)) {
                                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);
                                    continue;
                                }
                                if (!sourceLocMast.getLocSts().equals("S")) {
                                    News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 源库位状态不处于入库预约", sourceLocNo);
                                    continue;
                                }
                                LocMast locMast = locMastService.queryByLoc(locNo);
                                if (locMast == null) {
                                    News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 目标库位信息不存在", locNo);
                                    continue;
                                }
                                if (!locMast.getLocSts().equals("O")) {
                                    News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 目标库位状态不处于空库位", locNo);
                                    continue;
                                }
                                FindCrnNoResult findCrnNoResult = commonService.findCrnNoByLocNo(locNo);
                                if (findCrnNoResult == null) {
                                    News.taskInfo(wrkMast.getWrkNo(), "{}工作,未匹配到堆垛机", wrkMast.getWrkNo());
                                    continue;
                                }
                                Integer crnNo = findCrnNoResult.getCrnNo();
                                Integer targetStationId = commonService.findInStationId(findCrnNoResult, stationProtocol.getStationId());
                                if (targetStationId == null) {
                                    News.taskInfo(wrkMast.getWrkNo(), "{}站点,搜索入库站点失败", stationProtocol.getStationId());
                                    continue;
                                }
                                StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), targetStationId, 0);
                                if (command == null) {
                                    News.taskInfo(wrkMast.getWrkNo(), "{}工作,获取输送线命令失败", wrkMast.getWrkNo());
                                    continue;
                                }
                                //更新源库位
                                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)) {
                                    boolean offered = offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "checkStationRunBlock_direct");
                                    if (!offered) {
                                        continue;
                                    }
                                    if (stationMoveCoordinator != null) {
                                        stationMoveCoordinator.recordDispatch(
                                                wrkMast.getWrkNo(),
                                                stationProtocol.getStationId(),
                                                "checkStationRunBlock_direct",
                                                command,
                                                false
                                        );
                                    }
                                }
                            } else {
                                News.error("请求WMS接口失败!!!response:{}", response);
                            }
                        } else {
                            //运行堵塞,重新计算路线
                            Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast);
                            OutOrderDispatchDecision dispatchDecision = resolveOutboundDispatchDecision(
                                    stationProtocol.getStationId(),
                                    wrkMast,
                                    outOrderStationIds,
                                    pathLenFactor
                            );
                            Integer moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId();
                            if (moveStaNo == null || Objects.equals(moveStaNo, stationProtocol.getStationId())) {
                                continue;
                            }
                            if (countCurrentTaskBufferCommands(stationProtocol.getTaskBufferItems(), stationProtocol.getTaskNo()) > 0) {
                                continue;
                            }
                            StationCommand command = stationThread.getRunBlockRerouteCommand(
                                    wrkMast.getWrkNo(),
                                    stationProtocol.getStationId(),
                                    moveStaNo,
                                    0,
                                    pathLenFactor
                            );
                            if (command == null) {
                                News.taskInfo(wrkMast.getWrkNo(),
                                        "输送站点堵塞重规划未找到可下发路线,当前站点={},目标站点={}",
                                        stationProtocol.getStationId(),
                                        moveStaNo);
                                continue;
                            }
                            if (stationMoveCoordinator != null) {
                                stationMoveCoordinator.cancelSession(wrkMast.getWrkNo());
                            }
                            resetSegmentMoveCommandsBeforeReroute(wrkMast.getWrkNo());
                            boolean offered = offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "checkStationRunBlock_reroute");
                            if (!offered) {
                                continue;
                            }
                            syncOutOrderWatchState(wrkMast, stationProtocol.getStationId(), outOrderStationIds, dispatchDecision, command);
                            if (stationMoveCoordinator != null) {
                                stationMoveCoordinator.recordDispatch(
                                        wrkMast.getWrkNo(),
                                        stationProtocol.getStationId(),
                                        "checkStationRunBlock_reroute",
                                        command,
                                        dispatchDecision != null && dispatchDecision.isCircle()
                                );
                            }
                            News.info("输送站点堵塞后重新计算路径命令下发成功,站点号={},工作号={},命令数据={}", stationProtocol.getStationId(), wrkMast.getWrkNo(), JSON.toJSONString(command));
                        if (shouldUseRunBlockDirectReassign(wrkMast, stationProtocol.getStationId(), runBlockReassignLocStationList)) {
                            executeRunBlockDirectReassign(basDevp, stationThread, stationProtocol, wrkMast);
                            continue;
                        }
                        Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast);
                        RerouteContext context = RerouteContext.create(
                                RerouteSceneType.RUN_BLOCK_REROUTE,
                                basDevp,
                                stationThread,
                                stationProtocol,
                                wrkMast,
                                outOrderStationIds,
                                pathLenFactor,
                                "checkStationRunBlock_reroute"
                        ).withRunBlockCommand()
                                .withSuppressDispatchGuard()
                                .withCancelSessionBeforeDispatch()
                                .withResetSegmentCommandsBeforeDispatch();
                        executeSharedReroute(context);
                    }
                }
            }
@@ -727,6 +603,10 @@
                    continue;
                }
                if (stationProtocol.isRunBlock()) {
                    continue;
                }
                if (!stationProtocol.getStationId().equals(stationProtocol.getTargetStaNo())) {
                    continue;
                }
@@ -741,57 +621,25 @@
                if (Objects.equals(stationProtocol.getStationId(), wrkMast.getStaNo())) {
                    continue;
                }
                if (countCurrentTaskBufferCommands(stationProtocol.getTaskBufferItems(), stationProtocol.getTaskNo()) > 0) {
                if (shouldSkipOutOrderDispatchForExistingRoute(wrkMast.getWrkNo(), stationProtocol.getStationId())) {
                    continue;
                }
                Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast);
                OutOrderDispatchDecision dispatchDecision = resolveOutboundDispatchDecision(
                        stationProtocol.getStationId(),
                RerouteContext context = RerouteContext.create(
                        RerouteSceneType.OUT_ORDER,
                        basDevp,
                        stationThread,
                        stationProtocol,
                        wrkMast,
                        outOrderStationIds,
                        pathLenFactor
                );
                Integer moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId();
                if (moveStaNo == null || Objects.equals(moveStaNo, stationProtocol.getStationId())) {
                    continue;
                }
                StationCommand command = buildOutboundMoveCommand(
                        stationThread,
                        wrkMast,
                        stationProtocol.getStationId(),
                        moveStaNo,
                        pathLenFactor
                );
                if (command == null) {
                    News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败");
                    continue;
                }
                if (stationMoveCoordinator != null
                        && stationMoveCoordinator.shouldSuppressDispatch(wrkMast.getWrkNo(), stationProtocol.getStationId(), command)) {
                    continue;
                }
                if (!tryAcquireOutOrderDispatchLock(wrkMast.getWrkNo(), stationProtocol.getStationId())) {
                    continue;
                }
                resetSegmentMoveCommandsBeforeReroute(wrkMast.getWrkNo());
                boolean offered = offerDevpCommandWithDedup(stationObjModel.getDeviceNo(), command, "checkStationOutOrder");
                if (!offered) {
                    continue;
                }
                syncOutOrderWatchState(wrkMast, stationProtocol.getStationId(), outOrderStationIds, dispatchDecision, command);
                if (stationMoveCoordinator != null) {
                    stationMoveCoordinator.recordDispatch(
                            wrkMast.getWrkNo(),
                            stationProtocol.getStationId(),
                            "checkStationOutOrder",
                            command,
                            dispatchDecision != null && dispatchDecision.isCircle()
                    );
                }
                News.info(dispatchDecision.isCircle() ? "{}任务进行绕圈" : "{}任务直接去目标点", wrkMast.getWrkNo());
                        pathLenFactor,
                        "checkStationOutOrder"
                ).withDispatchDeviceNo(stationObjModel.getDeviceNo())
                        .withSuppressDispatchGuard()
                        .withOutOrderDispatchLock()
                        .withResetSegmentCommandsBeforeDispatch();
                executeSharedReroute(context);
            }
        }
    }
@@ -820,11 +668,7 @@
                    continue;
                }
                StationCommand circleCommand = getWatchCircleCommand(stationProtocol.getTaskNo());
                if (circleCommand == null) {
                    continue;
                }
                if (!stationProtocol.getStationId().equals(circleCommand.getTargetStaNo())) {
                if (!isWatchingCircleArrival(stationProtocol.getTaskNo(), stationProtocol.getStationId())) {
                    continue;
                }
@@ -838,55 +682,20 @@
                if (Objects.equals(stationProtocol.getStationId(), wrkMast.getStaNo())) {
                    continue;
                }
                if (countCurrentTaskBufferCommands(stationProtocol.getTaskBufferItems(), stationProtocol.getTaskNo()) > 0) {
                    continue;
                }
                Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast);
                OutOrderDispatchDecision dispatchDecision = resolveOutboundDispatchDecision(
                        stationProtocol.getStationId(),
                RerouteContext context = RerouteContext.create(
                        RerouteSceneType.WATCH_CIRCLE,
                        basDevp,
                        stationThread,
                        stationProtocol,
                        wrkMast,
                        outOrderList,
                        pathLenFactor
                );
                Integer moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId();
                if (moveStaNo == null || Objects.equals(moveStaNo, stationProtocol.getStationId())) {
                    continue;
                }
                StationCommand command = buildOutboundMoveCommand(
                        stationThread,
                        wrkMast,
                        stationProtocol.getStationId(),
                        moveStaNo,
                        pathLenFactor
                );
                if (command == null) {
                    News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败");
                    continue;
                }
                if (stationMoveCoordinator != null
                        && stationMoveCoordinator.shouldSuppressDispatch(wrkMast.getWrkNo(), stationProtocol.getStationId(), command)) {
                    continue;
                }
                if (!tryAcquireOutOrderDispatchLock(wrkMast.getWrkNo(), stationProtocol.getStationId())) {
                    continue;
                }
                resetSegmentMoveCommandsBeforeReroute(wrkMast.getWrkNo());
                boolean offered = offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "watchCircleStation");
                if (!offered) {
                    continue;
                }
                syncOutOrderWatchState(wrkMast, stationProtocol.getStationId(), outOrderList, dispatchDecision, command);
                if (stationMoveCoordinator != null) {
                    stationMoveCoordinator.recordDispatch(
                            wrkMast.getWrkNo(),
                            stationProtocol.getStationId(),
                            "watchCircleStation",
                            command,
                            dispatchDecision != null && dispatchDecision.isCircle()
                    );
                }
                        pathLenFactor,
                        "watchCircleStation"
                ).withSuppressDispatchGuard()
                        .withOutOrderDispatchLock()
                        .withResetSegmentCommandsBeforeDispatch();
                executeSharedReroute(context);
            }
        }
    }
@@ -948,6 +757,19 @@
                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());
@@ -978,12 +800,26 @@
            return RerouteExecutionResult.skip("recent-dispatch");
        }
        if (countCurrentTaskBufferCommands(stationProtocol.getTaskBufferItems(), taskNo) > 0) {
            if (context.sceneType() == RerouteSceneType.IDLE_RECOVER) {
                News.info("输送站点任务停留超时,但缓存区仍存在当前任务命令,已跳过重算。站点号={},工作号={},当前任务命令数={}",
                        stationId,
                        taskNo,
                        countCurrentTaskBufferCommands(stationProtocol.getTaskBufferItems(), taskNo));
            }
            return RerouteExecutionResult.skip("buffer-has-current-task");
        }
        if (context.checkSuppressDispatch()
                && stationMoveCoordinator != null
                && stationMoveCoordinator.shouldSuppressDispatch(taskNo, stationId, plan.command())) {
            return RerouteExecutionResult.skip("dispatch-suppressed");
        }
        if (context.sceneType() == RerouteSceneType.RUN_BLOCK_REROUTE
                && shouldSkipRunBlockRerouteForExistingSession(taskNo, stationId, plan.command())) {
            News.info("输送站点堵塞重规划命中已生效同路径路线,已跳过重复下发。站点号={},工作号={},目标站={}",
                    stationId,
                    taskNo,
                    plan.command().getTargetStaNo());
            return RerouteExecutionResult.skip("run-block-same-path");
        }
        if (context.requireOutOrderDispatchLock()
                && !tryAcquireOutOrderDispatchLock(taskNo, stationId)) {
@@ -1018,7 +854,7 @@
        return RerouteExecutionResult.dispatched(plan.command(), clearedCommandCount);
    }
    private RerouteDecision resolveSharedRerouteDecision(RerouteContext context) {
    RerouteDecision resolveSharedRerouteDecision(RerouteContext context) {
        if (context == null || context.wrkMast() == null || context.stationProtocol() == null) {
            return RerouteDecision.skip("missing-runtime-dependency");
        }
@@ -1547,6 +1383,50 @@
        return true;
    }
    private boolean shouldSkipOutOrderDispatchForExistingRoute(Integer wrkNo, Integer stationId) {
        if (stationMoveCoordinator == null || wrkNo == null || wrkNo <= 0 || stationId == null) {
            return false;
        }
        StationMoveSession session = stationMoveCoordinator.loadSession(wrkNo);
        if (session == null) {
            return false;
        }
        boolean protectedStatus = session.isActive() || StationMoveSession.STATUS_BLOCKED.equals(session.getStatus());
        if (!protectedStatus || !session.containsStation(stationId)) {
            return false;
        }
        if (StationMoveDispatchMode.CIRCLE == session.getDispatchMode()) {
            return true;
        }
        return !Objects.equals(stationId, session.getCurrentRouteTargetStationId());
    }
    private boolean shouldSkipRunBlockRerouteForExistingSession(Integer wrkNo,
                                                                Integer stationId,
                                                                StationCommand candidateCommand) {
        if (stationMoveCoordinator == null
                || wrkNo == null || wrkNo <= 0
                || stationId == null
                || candidateCommand == null) {
            return false;
        }
        StationMoveSession session = stationMoveCoordinator.loadSession(wrkNo);
        if (session == null) {
            return false;
        }
        boolean protectedStatus = session.isActive() || StationMoveSession.STATUS_BLOCKED.equals(session.getStatus());
        if (!protectedStatus) {
            return false;
        }
        boolean sameDispatchStation = Objects.equals(stationId, session.getCurrentStationId())
                || Objects.equals(stationId, session.getDispatchStationId());
        if (!sameDispatchStation) {
            return false;
        }
        String candidateSignature = stationMoveCoordinator.buildPathSignature(candidateCommand);
        return !isBlank(candidateSignature) && Objects.equals(candidateSignature, session.getPathSignature());
    }
    private boolean isWatchingCircleArrival(Integer wrkNo, Integer stationId) {
        if (stationMoveCoordinator != null) {
            StationMoveSession session = stationMoveCoordinator.loadSession(wrkNo);
@@ -1641,67 +1521,143 @@
        if (lock != null) {
            return;
        }
        Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast);
        RerouteContext context = RerouteContext.create(
                RerouteSceneType.IDLE_RECOVER,
                basDevp,
                stationThread,
                stationProtocol,
                wrkMast,
                outOrderList,
                pathLenFactor,
                "checkStationIdleRecover"
        ).withCancelSessionBeforeDispatch()
                .withExecutionLock(RedisKeyType.CHECK_STATION_IDLE_RECOVER_LIMIT_.key + stationProtocol.getTaskNo(), STATION_IDLE_RECOVER_LIMIT_SECONDS)
                .withResetSegmentCommandsBeforeDispatch()
                .clearIdleIssuedCommands(idleTrack);
        executeSharedReroute(context);
    }
    boolean shouldUseRunBlockDirectReassign(WrkMast wrkMast,
                                            Integer stationId,
                                            List<Integer> runBlockReassignLocStationList) {
        return wrkMast != null
                && Objects.equals(wrkMast.getIoType(), WrkIoType.IN.id)
                && stationId != null
                && runBlockReassignLocStationList != null
                && runBlockReassignLocStationList.contains(stationId);
    }
    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("输送站点任务停留超时,但缓存区仍存在当前任务命令,已跳过重算。站点号={},工作号={},当前任务命令数={}",
            News.info("输送站点运行堵塞重分配已跳过,缓存区仍存在当前任务命令。站点号={},工作号={},当前任务命令数={}",
                    stationProtocol.getStationId(),
                    stationProtocol.getTaskNo(),
                    currentTaskBufferCommandCount);
            return;
        }
        Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast);
        OutOrderDispatchDecision dispatchDecision = null;
        Integer moveStaNo;
        if (Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts)) {
            dispatchDecision = resolveOutboundDispatchDecision(stationProtocol.getStationId(), wrkMast, outOrderList, pathLenFactor);
            moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId();
        } else {
            moveStaNo = wrkMast.getStaNo();
        }
        if (moveStaNo == null || Objects.equals(moveStaNo, stationProtocol.getStationId())) {
            return;
        }
        if (stationMoveCoordinator != null) {
            stationMoveCoordinator.cancelSession(stationProtocol.getTaskNo());
            stationMoveCoordinator.cancelSession(wrkMast.getWrkNo());
        }
        redisUtil.set(RedisKeyType.CHECK_STATION_IDLE_RECOVER_LIMIT_.key + stationProtocol.getTaskNo(), "lock", STATION_IDLE_RECOVER_LIMIT_SECONDS);
        resetSegmentMoveCommandsBeforeReroute(stationProtocol.getTaskNo());
        int clearedCommandCount = clearIssuedMoveCommandsDuringIdleStay(idleTrack, stationProtocol.getTaskNo(), stationProtocol.getStationId());
        StationCommand command = buildOutboundMoveCommand(
                stationThread,
                wrkMast,
                stationProtocol.getStationId(),
                moveStaNo,
                pathLenFactor
        );
        if (command == null) {
            News.taskInfo(wrkMast.getWrkNo(), "站点任务停留超时后重算路径失败,当前站点={},目标站点={}", stationProtocol.getStationId(), moveStaNo);
        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;
        }
        boolean offered = offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "checkStationIdleRecover");
        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;
        }
        boolean offered = offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "checkStationRunBlock_direct");
        if (!offered) {
            return;
        }
        syncOutOrderWatchState(wrkMast, stationProtocol.getStationId(), outOrderList, dispatchDecision, command);
        if (stationMoveCoordinator != null) {
            stationMoveCoordinator.recordDispatch(
                    wrkMast.getWrkNo(),
                    stationProtocol.getStationId(),
                    "checkStationIdleRecover",
                    "checkStationRunBlock_direct",
                    command,
                    dispatchDecision != null && dispatchDecision.isCircle()
                    false
            );
        }
        saveStationTaskIdleTrack(new StationTaskIdleTrack(wrkMast.getWrkNo(), stationProtocol.getStationId(), System.currentTimeMillis()));
        News.info("输送站点任务停留{}秒未运行,已重新计算路径并重启运行,站点号={},目标站={},工作号={},清理旧分段命令数={},命令数据={}",
                STATION_IDLE_RECOVER_SECONDS, stationProtocol.getStationId(), moveStaNo, wrkMast.getWrkNo(), clearedCommandCount, JSON.toJSONString(command));
    }
    private boolean canRecoverIdleStationTask(WrkMast wrkMast, Integer currentStationId) {