Junjie
3 天以前 708422d37c02c225aa4fd793bff06de5fcb821dc
src/main/java/com/zy/core/utils/CrnOperateProcessUtils.java
@@ -2,7 +2,6 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.core.common.Cools;
import com.core.exception.CoolException;
@@ -38,15 +37,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.*;
@Component
public class CrnOperateProcessUtils {
@@ -76,15 +67,7 @@
    private static final String CRN_OUT_REQUIRE_STATION_OUT_ENABLE_CONFIG = "crnOutRequireStationOutEnable";
    public synchronized void crnIoExecute() {
        Set<Integer> crnMoveBlockedCrnNos = executeCrnMoveTask();
        List<BasCrnp> basCrnps = basCrnpService.list(new QueryWrapper<>());
        for (BasCrnp basCrnp : basCrnps) {
            crnIoExecute(basCrnp, crnMoveBlockedCrnNos);
        }
    }
    public void crnIoExecute(BasCrnp basCrnp, Set<Integer> crnMoveBlockedCrnNos) {
    public void crnIoExecute(BasCrnp basCrnp) {
        if (basCrnp == null || basCrnp.getCrnNo() == null) {
            return;
        }
@@ -92,16 +75,16 @@
        if (systemConfigMapObj != null) {
            HashMap<String, String> systemConfigMap = (HashMap<String, String>) systemConfigMapObj;
            if (systemConfigMap.get("crnRunMethod").equals("solver")) {
                plannerExecute(basCrnp, crnMoveBlockedCrnNos);
                plannerExecute(basCrnp);
            }else {
                crnIoExecuteNormal(basCrnp, crnMoveBlockedCrnNos);
                crnIoExecuteNormal(basCrnp);
            }
        }
    }
    //入出库  ===>>  堆垛机入出库作业下发
    private void crnIoExecuteNormal(BasCrnp currentCrn, Set<Integer> crnMoveBlockedCrnNos) {
        if (currentCrn == null || currentCrn.getCrnNo() == null || crnMoveBlockedCrnNos.contains(currentCrn.getCrnNo())) {
    private void crnIoExecuteNormal(BasCrnp currentCrn) {
        if (currentCrn == null || currentCrn.getCrnNo() == null) {
            return;
        }
@@ -118,7 +101,12 @@
        long runningCount = wrkMastService.count(new QueryWrapper<WrkMast>()
                .eq("crn_no", crnNo)
                .in("wrk_sts", WrkStsType.INBOUND_RUN.sts, WrkStsType.OUTBOUND_RUN.sts, WrkStsType.LOC_MOVE_RUN.sts, WrkStsType.CRN_MOVE_RUN.sts));
                .in("wrk_sts",
                        WrkStsType.INBOUND_RUN.sts
                        , WrkStsType.OUTBOUND_RUN.sts
                        , WrkStsType.LOC_MOVE_RUN.sts
                        , WrkStsType.CRN_MOVE_RUN.sts
                ));
        if (runningCount > 0) {
            return;
        }
@@ -138,6 +126,12 @@
            return;
        }
        //执行移动任务
        boolean executed = executeCrnMoveTask(crnThread, crnProtocol);
        if (executed) {
            return;
        }
        String lastIo = resolveCrnLastIo(crnProtocol);
        List<WrkMast> taskQueue = wrkMastService.list(new QueryWrapper<WrkMast>()
@@ -147,10 +141,10 @@
                        WrkStsType.NEW_OUTBOUND.sts,
                        WrkStsType.NEW_LOC_MOVE.sts));
        taskQueue.sort(Comparator.comparingInt((WrkMast wrkMast) -> resolveTaskTypeRank(wrkMast, lastIo))
                .thenComparingInt(this::resolveBatchOutboundRank)
                .thenComparingInt(this::resolveBatchSeqOrder)
                .thenComparingDouble(this::resolveTaskIoPri)
                .thenComparingLong(this::resolveTaskQueueTime)
                .thenComparingInt(this::resolveBatchOutboundRank)
                .thenComparingInt(this::resolveBatchSeqOrder)
                .thenComparingInt(this::resolveTaskQueueNo));
        for (WrkMast wrkMast : taskQueue) {
@@ -161,7 +155,7 @@
            if (wrkMast.getWrkSts() != null && wrkMast.getWrkSts() == WrkStsType.INBOUND_STATION_RUN_COMPLETE.sts) {
                boolean result = this.crnExecuteInPlanner(currentCrn, crnThread, wrkMast);
                if (result) {
                    crnProtocol.setLastIo("O");
                    crnProtocol.setLastIo("I");
                    return;
                }
                continue;
@@ -170,7 +164,7 @@
            if (wrkMast.getWrkSts() != null && wrkMast.getWrkSts() == WrkStsType.NEW_OUTBOUND.sts) {
                boolean result = this.crnExecuteOutPlanner(currentCrn, crnThread, wrkMast);
                if (result) {
                    crnProtocol.setLastIo("I");
                    crnProtocol.setLastIo("O");
                    return;
                }
                continue;
@@ -375,7 +369,7 @@
            return false;
        }
        if (isOutboundStationTaskLimitReached()) {
        if (isConveyorStationTaskLimitReached()) {
            return false;
        }
@@ -386,6 +380,12 @@
        }
        if (!allowBatchOutboundExecute(wrkMast, true)) {
            return false;
        }
        //检查是否为出库模式
        if(!checkOutTargetStationIoMode(wrkMast)) {
            News.taskInfo(wrkMast.getWrkNo(), "堆垛机:{} 任务:{}禁止执行,出库站:{} 不处于出库模式", basCrnp.getCrnNo(), wrkMast.getWrkNo(), wrkMast.getStaNo());
            return false;
        }
@@ -586,15 +586,17 @@
        return false;
    }
    private boolean isOutboundStationTaskLimitReached() {
        int stationMaxTaskCount = getSystemConfigInt("stationMaxTaskCountLimit", 30);
        if (stationMaxTaskCount <= 0) {
    private boolean isConveyorStationTaskLimitReached() {
        int conveyorStationTaskLimit = getSystemConfigInt("conveyorStationTaskLimit", 30);
        if (conveyorStationTaskLimit <= 0) {
            return false;
        }
        int currentStationTaskCount = stationOperateProcessUtils.getCurrentStationTaskCount();
        if (currentStationTaskCount >= stationMaxTaskCount) {
            News.warn("输送站点任务数量达到上限,已停止任务下发。当前任务数={},上限={}", currentStationTaskCount, stationMaxTaskCount);
        if (currentStationTaskCount >= conveyorStationTaskLimit) {
            News.warn("输送站点任务数量达到上限,已停止任务下发。当前任务数={},上限={}",
                    currentStationTaskCount,
                    conveyorStationTaskLimit);
            return true;
        }
        return false;
@@ -616,6 +618,36 @@
                    currentStationTaskCount,
                    basStation.getOutTaskLimit());
            return true;
        }
        return false;
    }
    //检查是否为出库模式
    private boolean checkOutTargetStationIoMode(WrkMast wrkMast) {
        if (wrkMast == null || wrkMast.getStaNo() == null) {
            return false;
        }
        BasStation basStation = basStationService.getById(wrkMast.getStaNo());
        if (basStation == null) {
            return false;
        }
        StationThread targetStationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo());
        if (targetStationThread == null) {
            return false;
        }
        StationProtocol targetStationProtocol = targetStationThread.getStatusMap().get(wrkMast.getStaNo());
        if (targetStationProtocol == null) {
            return false;
        }
        if (targetStationProtocol.getIoMode() == null) {
            return false;
        }
        if (targetStationProtocol.getIoMode() == 2) {
            return true;//出库模式
        }
        return false;
    }
@@ -659,14 +691,6 @@
        return defaultValue;
    }
    //堆垛机任务执行完成
    public synchronized void crnIoExecuteFinish() {
        List<BasCrnp> basCrnps = basCrnpService.list(new QueryWrapper<>());
        for (BasCrnp basCrnp : basCrnps) {
            crnIoExecuteFinish(basCrnp);
        }
    }
    public void crnIoExecuteFinish(BasCrnp basCrnp) {
        if (basCrnp == null || basCrnp.getCrnNo() == null) {
            return;
@@ -696,157 +720,151 @@
                return;
            }
            Long updateWrkSts = null;
            Date now = new Date();
            if(wrkMast.getWrkSts() == WrkStsType.INBOUND_RUN.sts){
                updateWrkSts = WrkStsType.COMPLETE_INBOUND.sts;
                notifyUtils.notify(String.valueOf(SlaveType.Crn), crnProtocol.getCrnNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.CRN_IN_TASK_COMPLETE, null);
            }else if(wrkMast.getWrkSts() == WrkStsType.OUTBOUND_RUN.sts){
                updateWrkSts = WrkStsType.OUTBOUND_RUN_COMPLETE.sts;
                notifyUtils.notify(String.valueOf(SlaveType.Crn), crnProtocol.getCrnNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.CRN_OUT_TASK_COMPLETE, null);
                List<StationObjModel> outStationList = basCrnp.getOutStationList$();
                if(outStationList.isEmpty()){
                    News.info("堆垛机:{} 出库站点未设置", basCrnp.getCrnNo());
            String ownerLockKey = RedisKeyType.CRN_IO_EXECUTE_FINISH_OWNER_LOCK.key + wrkMast.getWrkNo();
            String ownerLockToken = UUID.randomUUID().toString();
            if (!redisUtil.trySetStringIfAbsent(ownerLockKey, ownerLockToken, 10)) {
                return;
            }
            try {
                wrkMast = wrkMastService.selectByWorkNo(crnProtocol.getTaskNo());
                if (wrkMast == null) {
                    News.error("堆垛机处于等待确认且任务完成状态,但未找到工作档。堆垛机号={},工作号={}", basCrnp.getCrnNo(), crnProtocol.getTaskNo());
                    return;
                }
                StationObjModel outStationObjModel = null;
                for (StationObjModel stationObjModel : outStationList) {
                    if (stationObjModel.getStationId().equals(wrkMast.getSourceStaNo())) {
                        outStationObjModel = stationObjModel;
                        break;
                    }
                Long currentWrkSts = wrkMast.getWrkSts();
                Long updateWrkSts = null;
                Date now = new Date();
                if(currentWrkSts == WrkStsType.INBOUND_RUN.sts){
                    updateWrkSts = WrkStsType.COMPLETE_INBOUND.sts;
                    notifyUtils.notify(String.valueOf(SlaveType.Crn), crnProtocol.getCrnNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.CRN_IN_TASK_COMPLETE, null);
                }else if(currentWrkSts == WrkStsType.OUTBOUND_RUN.sts){
                    updateWrkSts = WrkStsType.OUTBOUND_RUN_COMPLETE.sts;
                    notifyUtils.notify(String.valueOf(SlaveType.Crn), crnProtocol.getCrnNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.CRN_OUT_TASK_COMPLETE, null);
                }else if(currentWrkSts == WrkStsType.LOC_MOVE_RUN.sts){
                    updateWrkSts = WrkStsType.COMPLETE_LOC_MOVE.sts;
                    notifyUtils.notify(String.valueOf(SlaveType.Crn), crnProtocol.getCrnNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.CRN_TRANSFER_TASK_COMPLETE, null);
                }else if(currentWrkSts == WrkStsType.CRN_MOVE_RUN.sts){
                    updateWrkSts = WrkStsType.COMPLETE_CRN_MOVE.sts;
                }else{
                    News.error("堆垛机处于等待确认且任务完成状态,但工作状态异常。堆垛机号={},工作号={}", basCrnp.getCrnNo(), crnProtocol.getTaskNo());
                    return;
                }
                redisUtil.set(RedisKeyType.CRN_OUT_TASK_COMPLETE_STATION_INFO.key + wrkMast.getWrkNo(), JSON.toJSONString(outStationObjModel, SerializerFeature.DisableCircularReferenceDetect), 60 * 60 * 24);
            }else if(wrkMast.getWrkSts() == WrkStsType.LOC_MOVE_RUN.sts){
                updateWrkSts = WrkStsType.COMPLETE_LOC_MOVE.sts;
                notifyUtils.notify(String.valueOf(SlaveType.Crn), crnProtocol.getCrnNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.CRN_TRANSFER_TASK_COMPLETE, null);
            }else if(wrkMast.getWrkSts() == WrkStsType.CRN_MOVE_RUN.sts){
                updateWrkSts = WrkStsType.COMPLETE_CRN_MOVE.sts;
            }else{
                News.error("堆垛机处于等待确认且任务完成状态,但工作状态异常。堆垛机号={},工作号={}", basCrnp.getCrnNo(), crnProtocol.getTaskNo());
                return;
            }
            wrkMast.setWrkSts(updateWrkSts);
            wrkMast.setSystemMsg("");
            wrkMast.setIoTime(now);
            wrkMast.setModiTime(now);
            if (wrkMastService.updateById(wrkMast)) {
                wrkAnalysisService.markCraneComplete(wrkMast, now, updateWrkSts);
                CrnCommand resetCommand = crnThread.getResetCommand(crnProtocol.getTaskNo(), crnProtocol.getCrnNo());
                MessageQueue.offer(SlaveType.Crn, crnProtocol.getCrnNo(), new Task(2, resetCommand));
                News.info("堆垛机任务状态更新成功,堆垛机号={},工作号={}", basCrnp.getCrnNo(), crnProtocol.getTaskNo());
                if (wrkMastService.updateWrkStsByWrkNoAndCurrentWrkSts(wrkMast.getWrkNo(), updateWrkSts, currentWrkSts) > 0) {
                    wrkMast.setWrkSts(updateWrkSts);
                    wrkMast.setSystemMsg("");
                    wrkMast.setIoTime(now);
                    wrkMast.setModiTime(now);
                    wrkAnalysisService.markCraneComplete(wrkMast, now, updateWrkSts);
                    CrnCommand resetCommand = crnThread.getResetCommand(crnProtocol.getTaskNo(), crnProtocol.getCrnNo());
                    MessageQueue.offer(SlaveType.Crn, crnProtocol.getCrnNo(), new Task(2, resetCommand));
                    News.info("堆垛机任务状态更新成功,堆垛机号={},工作号={}", basCrnp.getCrnNo(), crnProtocol.getTaskNo());
                    redisUtil.set(RedisKeyType.CRN_IO_EXECUTE_FINISH_LIMIT.key + basCrnp.getCrnNo(), "lock",10);
                } else {
                    News.info("堆垛机完成确认跳过,任务状态已变化。堆垛机号={},工作号={}", basCrnp.getCrnNo(), crnProtocol.getTaskNo());
                }
            } finally {
                redisUtil.compareAndDelete(ownerLockKey, ownerLockToken);
            }
            redisUtil.set(RedisKeyType.CRN_IO_EXECUTE_FINISH_LIMIT.key + basCrnp.getCrnNo(), "lock",10);
        }
    }
    public synchronized void plannerExecute() {
        Set<Integer> crnMoveBlockedCrnNos = executeCrnMoveTask();
        List<BasCrnp> basCrnps = basCrnpService.list(new QueryWrapper<>());
        for (BasCrnp basCrnp : basCrnps) {
            plannerExecute(basCrnp, crnMoveBlockedCrnNos);
        }
    }
    private void plannerExecute(BasCrnp basCrnp, Set<Integer> crnMoveBlockedCrnNos) {
    private void plannerExecute(BasCrnp basCrnp) {
        int nowSec = (int) (System.currentTimeMillis() / 1000);
        if (basCrnp == null || basCrnp.getCrnNo() == null || crnMoveBlockedCrnNos.contains(basCrnp.getCrnNo())) {
        if (basCrnp == null || basCrnp.getCrnNo() == null) {
            return;
        }
            String key = RedisKeyType.PLANNER_SCHEDULE.key + "CRN-" + basCrnp.getCrnNo();
            List<Object> items = redisUtil.lGet(key, 0, -1);
            if (items == null || items.isEmpty()) {
                return;
        String key = RedisKeyType.PLANNER_SCHEDULE.key + "CRN-" + basCrnp.getCrnNo();
        List<Object> items = redisUtil.lGet(key, 0, -1);
        if (items == null || items.isEmpty()) {
            return;
        }
        CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, basCrnp.getCrnNo());
        if (crnThread == null) {
            return;
        }
        CrnProtocol crnProtocol = crnThread.getStatus();
        if (crnProtocol == null) {
            return;
        }
        List<WrkMast> running = wrkMastService.list(new QueryWrapper<WrkMast>()
                .eq("crn_no", basCrnp.getCrnNo())
                .in("wrk_sts", WrkStsType.INBOUND_RUN.sts, WrkStsType.OUTBOUND_RUN.sts, WrkStsType.LOC_MOVE_RUN.sts, WrkStsType.CRN_MOVE_RUN.sts)
        );
        if (!running.isEmpty()) {
            return;
        }
        if (!(crnProtocol.getMode() == CrnModeType.AUTO.id
                && crnProtocol.getTaskNo() == 0
                && crnProtocol.getStatus() == CrnStatusType.IDLE.id
                && crnProtocol.getLoaded() == 0
                && crnProtocol.getForkPos() == 0
                && crnProtocol.getAlarm() == 0)) {
            return;
        }
        for (Object v : items) {
            String s = String.valueOf(v);
            JSONObject obj = null;
            try { obj = JSON.parseObject(s); } catch (Exception ignore) {}
            if (obj == null) {
                continue;
            }
            Integer startEpochSec = obj.getInteger("startEpochSec");
            Integer endEpochSec = obj.getInteger("endEpochSec");
            Integer taskId = obj.getInteger("taskId");
            String taskType = obj.getString("taskType");
            if (startEpochSec == null || taskId == null || taskType == null) {
                continue;
            }
            int earlySlackSec = 5;
            int lateSlackSec = 10;
            Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key);
            if (systemConfigMapObj != null) {
                try {
                    HashMap<String, String> systemConfigMap = (HashMap<String, String>) systemConfigMapObj;
                    String es = systemConfigMap.getOrDefault("plannerEarlySlackSec", "60");
                    String ls = systemConfigMap.getOrDefault("plannerLateSlackSec", "10");
                    earlySlackSec = Integer.parseInt(es);
                    lateSlackSec = Integer.parseInt(ls);
                } catch (Exception ignore) {}
            }
            if (nowSec < startEpochSec - earlySlackSec) {
                continue;
            }
            if (endEpochSec != null && nowSec > endEpochSec + lateSlackSec) {
                redisUtil.lRemove(key, 1, s);
                continue;
            }
            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, basCrnp.getCrnNo());
            if (crnThread == null) {
                return;
            }
            CrnProtocol crnProtocol = crnThread.getStatus();
            if (crnProtocol == null) {
                return;
            }
            List<WrkMast> running = wrkMastService.list(new QueryWrapper<WrkMast>()
                    .eq("crn_no", basCrnp.getCrnNo())
                    .in("wrk_sts", WrkStsType.INBOUND_RUN.sts, WrkStsType.OUTBOUND_RUN.sts, WrkStsType.LOC_MOVE_RUN.sts, WrkStsType.CRN_MOVE_RUN.sts)
            );
            if (!running.isEmpty()) {
                return;
            }
            if (!(crnProtocol.getMode() == CrnModeType.AUTO.id
                    && crnProtocol.getTaskNo() == 0
                    && crnProtocol.getStatus() == CrnStatusType.IDLE.id
                    && crnProtocol.getLoaded() == 0
                    && crnProtocol.getForkPos() == 0
                    && crnProtocol.getAlarm() == 0)) {
                return;
            WrkMast wrkMast = wrkMastService.selectByWorkNo(taskId);
            if (wrkMast == null) {
                redisUtil.lRemove(key, 1, s);
                continue;
            }
            for (Object v : items) {
                String s = String.valueOf(v);
                JSONObject obj = null;
                try { obj = JSON.parseObject(s); } catch (Exception ignore) {}
                if (obj == null) {
                    continue;
                }
                Integer startEpochSec = obj.getInteger("startEpochSec");
                Integer endEpochSec = obj.getInteger("endEpochSec");
                Integer taskId = obj.getInteger("taskId");
                String taskType = obj.getString("taskType");
                if (startEpochSec == null || taskId == null || taskType == null) {
                    continue;
                }
                int earlySlackSec = 5;
                int lateSlackSec = 10;
                Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key);
                if (systemConfigMapObj != null) {
                    try {
                        HashMap<String, String> systemConfigMap = (HashMap<String, String>) systemConfigMapObj;
                        String es = systemConfigMap.getOrDefault("plannerEarlySlackSec", "60");
                        String ls = systemConfigMap.getOrDefault("plannerLateSlackSec", "10");
                        earlySlackSec = Integer.parseInt(es);
                        lateSlackSec = Integer.parseInt(ls);
                    } catch (Exception ignore) {}
                }
                if (nowSec < startEpochSec - earlySlackSec) {
                    continue;
                }
                if (endEpochSec != null && nowSec > endEpochSec + lateSlackSec) {
            if ("IN".equalsIgnoreCase(taskType)) {
                boolean result = this.crnExecuteInPlanner(basCrnp, crnThread, wrkMast);//入库
                if (result) {
                    redisUtil.lRemove(key, 1, s);
                    continue;
                    break;
                }
                WrkMast wrkMast = wrkMastService.selectByWorkNo(taskId);
                if (wrkMast == null) {
            } else if ("OUT".equalsIgnoreCase(taskType)) {
                boolean result = this.crnExecuteOutPlanner(basCrnp, crnThread, wrkMast);//出库
                if (result) {
                    redisUtil.lRemove(key, 1, s);
                    continue;
                    break;
                }
                if ("IN".equalsIgnoreCase(taskType)) {
                    boolean result = this.crnExecuteInPlanner(basCrnp, crnThread, wrkMast);//入库
                    if (result) {
                        redisUtil.lRemove(key, 1, s);
                        break;
                    }
                } else if ("OUT".equalsIgnoreCase(taskType)) {
                    boolean result = this.crnExecuteOutPlanner(basCrnp, crnThread, wrkMast);//出库
                    if (result) {
                        redisUtil.lRemove(key, 1, s);
                        break;
                    }
                } else if ("MOVE".equalsIgnoreCase(taskType)) {
                    boolean result = this.crnExecuteMovePlanner(basCrnp, crnThread, wrkMast);//移库
                    if (result) {
                        redisUtil.lRemove(key, 1, s);
                        break;
                    }
            } else if ("MOVE".equalsIgnoreCase(taskType)) {
                boolean result = this.crnExecuteMovePlanner(basCrnp, crnThread, wrkMast);//移库
                if (result) {
                    redisUtil.lRemove(key, 1, s);
                    break;
                }
            }
        }
    }
    private synchronized boolean crnExecuteMovePlanner(BasCrnp basCrnp, CrnThread crnThread, WrkMast wrkMast) {
@@ -903,76 +921,20 @@
        return false;
    }
    private Set<Integer> executeCrnMoveTask() {
        List<WrkMast> pendingTaskQueue = wrkMastService.list(new QueryWrapper<WrkMast>()
                .eq("io_type", WrkIoType.CRN_MOVE.id)
                .eq("wrk_sts", WrkStsType.NEW_CRN_MOVE.sts)
                .orderByAsc("appe_time")
                .orderByAsc("wrk_no"));
        Set<Integer> blockedCrnNoSet = new HashSet<>();
        for (WrkMast wrkMast : pendingTaskQueue) {
            if (wrkMast != null && wrkMast.getCrnNo() != null) {
                blockedCrnNoSet.add(wrkMast.getCrnNo());
            }
        }
        if (blockedCrnNoSet.isEmpty()) {
            return blockedCrnNoSet;
        }
        List<BasCrnp> basCrnps = basCrnpService.list(new QueryWrapper<>());
        Map<Integer, CrnThread> dispatchThreadMap = new HashMap<>();
        Map<Integer, CrnProtocol> dispatchProtocolMap = new HashMap<>();
        for (BasCrnp basCrnp : basCrnps) {
            if (basCrnp == null || basCrnp.getCrnNo() == null) {
                continue;
            }
            Integer crnNo = basCrnp.getCrnNo();
            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crnNo);
            if (crnThread == null) {
                continue;
            }
            CrnProtocol crnProtocol = crnThread.getStatus();
            if (crnProtocol == null) {
                continue;
            }
            long runningCount = wrkMastService.count(new QueryWrapper<WrkMast>()
                    .eq("crn_no", crnNo)
                    .in("wrk_sts",
                            WrkStsType.INBOUND_RUN.sts,
                            WrkStsType.OUTBOUND_RUN.sts,
                            WrkStsType.LOC_MOVE_RUN.sts,
                            WrkStsType.CRN_MOVE_RUN.sts));
            if (runningCount > 0) {
                continue;
            }
            if (!Objects.equals(crnProtocol.getMode(), CrnModeType.AUTO.id)
                    || !Objects.equals(crnProtocol.getTaskNo(), 0)
                    || !Objects.equals(crnProtocol.getStatus(), CrnStatusType.IDLE.id)
                    || !Objects.equals(crnProtocol.getLoaded(), 0)
                    || !Objects.equals(crnProtocol.getForkPos(), 0)
                    || !Objects.equals(crnProtocol.getAlarm(), 0)) {
                continue;
            }
            Object clearLock = redisUtil.get(RedisKeyType.CLEAR_CRN_TASK_LIMIT.key + crnNo);
            if (clearLock != null) {
                continue;
            }
            dispatchThreadMap.put(crnNo, crnThread);
            dispatchProtocolMap.put(crnNo, crnProtocol);
        }
        if (dispatchThreadMap.isEmpty()) {
            return blockedCrnNoSet;
    private boolean executeCrnMoveTask(CrnThread crnThread, CrnProtocol crnProtocol) {
        long runningCount = wrkMastService.count(new QueryWrapper<WrkMast>()
                .eq("crn_no", crnProtocol.getCrnNo())
                .in("wrk_sts",
                        WrkStsType.INBOUND_RUN.sts,
                        WrkStsType.OUTBOUND_RUN.sts,
                        WrkStsType.LOC_MOVE_RUN.sts,
                        WrkStsType.CRN_MOVE_RUN.sts));
        if (runningCount > 0) {
            return false;
        }
        List<WrkMast> taskQueue = wrkMastService.list(new QueryWrapper<WrkMast>()
                .in("crn_no", new ArrayList<>(dispatchThreadMap.keySet()))
                .eq("crn_no", crnProtocol.getCrnNo())
                .eq("io_type", WrkIoType.CRN_MOVE.id)
                .eq("wrk_sts", WrkStsType.NEW_CRN_MOVE.sts)
                .orderByAsc("appe_time")
@@ -983,36 +945,38 @@
                continue;
            }
            Integer crnNo = wrkMast.getCrnNo();
            CrnThread crnThread = dispatchThreadMap.get(crnNo);
            if (crnThread == null || dispatchProtocolMap.get(crnNo) == null) {
            if (crnProtocol.getBay() == Utils.getBay(wrkMast.getLocNo())) {
                Date now = new Date();
                wrkMast.setWrkSts(WrkStsType.COMPLETE_CRN_MOVE.sts);
                wrkMast.setSystemMsg("堆垛机已在目标点,任务直接完成");
                wrkMast.setIoTime(now);
                wrkMast.setModiTime(now);
                if (wrkMastService.updateById(wrkMast)) {
                    wrkAnalysisService.markCraneStart(wrkMast, now);
                }
                continue;
            }
            CrnCommand moveCommand = crnThread.getMoveCommand(wrkMast.getLocNo(), wrkMast.getWrkNo(), crnNo);
            CrnCommand moveCommand = crnThread.getMoveCommand(wrkMast.getLocNo(), wrkMast.getWrkNo(), crnProtocol.getCrnNo());
            if (moveCommand == null) {
                continue;
            }
            Date now = new Date();
            wrkMast.setWrkSts(WrkStsType.CRN_MOVE_RUN.sts);
            wrkMast.setCrnNo(crnNo);
            wrkMast.setSystemMsg("");
            wrkMast.setIoTime(now);
            wrkMast.setModiTime(now);
            if (wrkMastService.updateById(wrkMast)) {
                wrkAnalysisService.markCraneStart(wrkMast, now);
                MessageQueue.offer(SlaveType.Crn, crnNo, new Task(2, moveCommand));
                MessageQueue.offer(SlaveType.Crn, crnProtocol.getCrnNo(), new Task(2, moveCommand));
                News.info("堆垛机移动命令下发成功,堆垛机号={},工作号={},目标位={},任务数据={}",
                        crnNo, wrkMast.getWrkNo(), wrkMast.getLocNo(), JSON.toJSON(moveCommand));
                return blockedCrnNoSet;
                        crnProtocol.getCrnNo(), wrkMast.getWrkNo(), wrkMast.getLocNo(), JSON.toJSON(moveCommand));
                return true;
            }
        }
        return blockedCrnNoSet;
    }
    public Set<Integer> executeCrnMoveTaskAndGetBlockedCrnNos() {
        return executeCrnMoveTask();
        return false;
    }
    public void submitCrnIoTasks(long minIntervalMs) {
@@ -1020,7 +984,6 @@
    }
    public void submitCrnIoTasks(MainProcessLane lane, long minIntervalMs) {
        Set<Integer> blockedCrnNos = executeCrnMoveTaskAndGetBlockedCrnNos();
        List<BasCrnp> basCrnps = basCrnpService.list(new QueryWrapper<>());
        for (BasCrnp basCrnp : basCrnps) {
            Integer crnNo = basCrnp == null ? null : basCrnp.getCrnNo();
@@ -1032,7 +995,7 @@
                    crnNo,
                    "crnIoExecute",
                    minIntervalMs,
                    () -> crnIoExecute(basCrnp, blockedCrnNos)
                    () -> crnIoExecute(basCrnp)
            );
        }
    }
@@ -1153,10 +1116,6 @@
        }
        if (crnProtocol.getBay() == targetBay) {
            return false;
        }
        if (crnProtocol.getLevel() == targetLev) {
            return false;
        }