#
Administrator
2026-04-25 a55f2835748bd494ff46ca3e1a2d7d672153cb2f
#
3个文件已添加
5个文件已修改
1958 ■■■■ 已修改文件
src/main/java/com/zy/core/plugin/XiaosongProcess.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/task/MainProcessAsyncTaskScheduler.java 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/task/MainProcessLane.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/task/MainProcessTaskSubmitter.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/utils/CrnOperateProcessUtils.java 486 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/utils/DualCrnOperateProcessUtils.java 171 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/utils/StationOperateProcessUtils.java 957 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/plugin/XiaosongProcess.java
@@ -24,6 +24,8 @@
import com.zy.core.model.command.StationCommand;
import com.zy.core.model.protocol.StationProtocol;
import com.zy.core.plugin.api.MainProcessPluginApi;
import com.zy.core.task.MainProcessLane;
import com.zy.core.task.MainProcessTaskSubmitter;
import com.zy.core.thread.StationThread;
import com.zy.core.utils.CrnOperateProcessUtils;
import com.zy.core.utils.DualCrnOperateProcessUtils;
@@ -40,6 +42,8 @@
@Slf4j
@Component
public class XiaosongProcess implements MainProcessPluginApi {
    private static final long DISPATCH_INTERVAL_MS = 200L;
    private static final long MAINTENANCE_INTERVAL_MS = 500L;
    @Autowired
    private CrnOperateProcessUtils crnOperateUtils;
@@ -57,36 +61,46 @@
    private WmsOperateUtils wmsOperateUtils;
    @Autowired
    private DualCrnOperateProcessUtils dualCrnOperateProcessUtils;
    @Autowired
    private MainProcessTaskSubmitter mainProcessTaskSubmitter;
    @Override
    public void run() {
        //检测入库站是否有任务生成,并启动入库
        checkInStationHasTask();
        //请求生成入库任务
        generateStoreWrkFile();
        // 检测入库站是否有任务生成,并按站点 lane 异步启动入库
        stationOperateProcessUtils.submitStationEnableInTasks(DISPATCH_INTERVAL_MS);
        // 请求生成入库任务,放入独立 lane,避免拖慢其他主流程方法
        submitGenerateStoreWrkFileTask();
        //执行堆垛机任务
        crnOperateUtils.crnIoExecute();
        //堆垛机任务执行完成
        crnOperateUtils.crnIoExecuteFinish();
        //执行输送站点入库任务
        stationOperateProcessUtils.stationInExecute();
        //执行堆垛机输送站点出库任务
        stationOperateProcessUtils.crnStationOutExecute();
        //执行双工位堆垛机输送站点出库任务
        stationOperateProcessUtils.dualCrnStationOutExecute();
        //检测输送站点出库任务执行完成
        stationOperateProcessUtils.stationOutExecuteFinish();
        // 执行堆垛机任务
        crnOperateUtils.submitCrnIoTasks(DISPATCH_INTERVAL_MS);
        // 堆垛机任务执行完成
        crnOperateUtils.submitCrnIoExecuteFinishTasks(DISPATCH_INTERVAL_MS);
        // 执行输送站点入库任务
        stationOperateProcessUtils.submitStationInTasks(DISPATCH_INTERVAL_MS);
        // 执行堆垛机输送站点出库任务
        stationOperateProcessUtils.submitCrnStationOutTasks(DISPATCH_INTERVAL_MS);
        // 执行双工位堆垛机输送站点出库任务
        stationOperateProcessUtils.submitDualCrnStationOutTasks(DISPATCH_INTERVAL_MS);
        // 检测输送站点出库任务执行完成
        stationOperateProcessUtils.submitStationOutExecuteFinishTasks(DISPATCH_INTERVAL_MS);
        // 检测任务转完成
        stationOperateProcessUtils.checkTaskToComplete();
        //检测输送站点是否运行堵塞
        stationOperateProcessUtils.checkStationRunBlock();
        stationOperateProcessUtils.submitCheckTaskToCompleteTasks(DISPATCH_INTERVAL_MS);
        // 检测输送站点是否运行堵塞
        stationOperateProcessUtils.submitCheckStationRunBlockTasks(MAINTENANCE_INTERVAL_MS);
        // 执行双工位堆垛机任务
        dualCrnOperateProcessUtils.dualCrnIoExecute();
        dualCrnOperateProcessUtils.submitDualCrnIoTasks(DISPATCH_INTERVAL_MS);
        // 双工位堆垛机任务执行完成
        dualCrnOperateProcessUtils.dualCrnIoExecuteFinish();
        dualCrnOperateProcessUtils.submitDualCrnIoExecuteFinishTasks(DISPATCH_INTERVAL_MS);
    }
    private void submitGenerateStoreWrkFileTask() {
        mainProcessTaskSubmitter.submitSerialTask(
                MainProcessLane.GENERATE_STORE,
                "generateStoreWrkFile",
                DISPATCH_INTERVAL_MS,
                this::generateStoreWrkFile
        );
    }
    /**
src/main/java/com/zy/core/task/MainProcessAsyncTaskScheduler.java
New file
@@ -0,0 +1,161 @@
package com.zy.core.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * 主流程异步任务调度器。
 * 按执行通道串行执行任务,并对同名任务提供最小提交间隔和不重入保护。
 */
@Slf4j
@Component
public class MainProcessAsyncTaskScheduler {
    private static final long DEFAULT_SHUTDOWN_TIMEOUT_SECONDS = 5L;
    private final Map<String, SerialTaskLane> laneMap = new ConcurrentHashMap<>();
    private final Map<String, TaskGuard> taskGuardMap = new ConcurrentHashMap<>();
    public boolean submit(String laneName,
                          String taskName,
                          long minIntervalMs,
                          long slowLogThresholdMs,
                          Runnable task) {
        if (isBlank(laneName) || isBlank(taskName) || task == null) {
            return false;
        }
        long now = System.currentTimeMillis();
        String taskKey = buildTaskKey(laneName, taskName);
        TaskGuard taskGuard = taskGuardMap.computeIfAbsent(taskKey, key -> new TaskGuard());
        synchronized (taskGuard) {
            if (taskGuard.lastSubmitTimeMs > 0L && now - taskGuard.lastSubmitTimeMs < minIntervalMs) {
                return false;
            }
            if (!taskGuard.running.compareAndSet(false, true)) {
                return false;
            }
            taskGuard.lastSubmitTimeMs = now;
            taskGuard.lastQueueEnterTimeMs = now;
        }
        try {
            ensureLane(laneName).executorService.execute(() -> executeTask(laneName, taskName, slowLogThresholdMs, taskGuard, task));
            return true;
        } catch (Exception e) {
            taskGuard.running.set(false);
            log.error("MainProcess async task submit error, lane={}, task={}", laneName, taskName, e);
            return false;
        }
    }
    private void executeTask(String laneName,
                             String taskName,
                             long slowLogThresholdMs,
                             TaskGuard taskGuard,
                             Runnable task) {
        long startMs = System.currentTimeMillis();
        long queueWaitMs = taskGuard.lastQueueEnterTimeMs > 0L ? startMs - taskGuard.lastQueueEnterTimeMs : 0L;
        try {
            task.run();
        } catch (Exception e) {
            log.error("MainProcess async task execute error, lane={}, task={}", laneName, taskName, e);
        } finally {
            long costMs = System.currentTimeMillis() - startMs;
            if (slowLogThresholdMs > 0L && costMs > slowLogThresholdMs) {
                log.warn("MainProcess async task executed slowly, lane={}, task={}, cost={}ms, queueWaitMs={}ms", laneName, taskName, costMs, queueWaitMs);
            }
            taskGuard.running.set(false);
        }
    }
    private SerialTaskLane ensureLane(String laneName) {
        SerialTaskLane lane = laneMap.get(laneName);
        if (lane != null && !lane.executorService.isShutdown()) {
            return lane;
        }
        synchronized (laneMap) {
            lane = laneMap.get(laneName);
            if (lane == null || lane.executorService.isShutdown()) {
                lane = new SerialTaskLane(Executors.newSingleThreadExecutor(new NamedThreadFactory("main-process-" + laneName + "-")));
                laneMap.put(laneName, lane);
            }
            return lane;
        }
    }
    @PreDestroy
    public void shutdown() {
        for (SerialTaskLane lane : laneMap.values()) {
            if (lane == null || lane.executorService == null) {
                continue;
            }
            lane.executorService.shutdownNow();
        }
        for (Map.Entry<String, SerialTaskLane> entry : laneMap.entrySet()) {
            SerialTaskLane lane = entry.getValue();
            if (lane == null || lane.executorService == null) {
                continue;
            }
            try {
                if (!lane.executorService.awaitTermination(DEFAULT_SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
                    log.warn("MainProcess async task lane did not terminate in time, lane={}", entry.getKey());
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
        }
    }
    private String buildTaskKey(String laneName, String taskName) {
        return laneName + "::" + taskName;
    }
    private boolean isBlank(String value) {
        return value == null || value.trim().isEmpty();
    }
    private static class SerialTaskLane {
        private final ExecutorService executorService;
        private SerialTaskLane(ExecutorService executorService) {
            this.executorService = executorService;
        }
    }
    private static class TaskGuard {
        private final AtomicBoolean running = new AtomicBoolean(false);
        private volatile long lastSubmitTimeMs = 0L;
        private volatile long lastQueueEnterTimeMs = 0L;
    }
    private static class NamedThreadFactory implements ThreadFactory {
        private final String prefix;
        private final AtomicInteger index = new AtomicInteger(1);
        private NamedThreadFactory(String prefix) {
            this.prefix = prefix;
        }
        @Override
        public Thread newThread(Runnable runnable) {
            Thread thread = new Thread(runnable, prefix + index.getAndIncrement());
            thread.setDaemon(true);
            return thread;
        }
    }
}
src/main/java/com/zy/core/task/MainProcessLane.java
New file
@@ -0,0 +1,47 @@
package com.zy.core.task;
public enum MainProcessLane {
    CRN("crn"),
    CRN_IO("crn-io-"),
    CRN_IO_FINISH("crn-io-finish-"),
    DUAL_CRN_IO("dual-crn-io-"),
    DUAL_CRN_IO_FINISH("dual-crn-io-finish-"),
    STATION("station"),
    STATION_ENABLE_IN("station-enable-in-"),
    STATION_IN("station-in-"),
    STATION_OUT("station-out-"),
    DUAL_STATION_OUT("dual-station-out-"),
    STATION_OUT_FINISH("station-out-finish-"),
    STATION_IN_ARRIVAL("station-in-arrival-"),
    STATION_COMPLETE("station-complete-"),
    STATION_OUT_ORDER("station-out-order-"),
    STATION_RUN_BLOCK("station-run-block-"),
    GENERATE_STORE("generate-store-"),
    FAKE_CRN_IO("fake-crn-io-"),
    FAKE_CRN_IO_FINISH("fake-crn-io-finish-"),
    FAKE_STATION_IN("fake-station-in-"),
    FAKE_STATION_OUT("fake-station-out-"),
    FAKE_STATION_OUT_ORDER("fake-station-out-order-"),
    FAKE_STATION_RUN_BLOCK("fake-station-run-block-"),
    FAKE_DUAL_CRN_IO("fake-dual-crn-io-"),
    FAKE_DUAL_CRN_IO_FINISH("fake-dual-crn-io-finish-"),
    FAKE_GENERATE_STORE("fake-generate-store-"),
    FAKE_ASYNC("fake-async-");
    private final String laneName;
    MainProcessLane(String laneName) {
        this.laneName = laneName;
    }
    public String laneName() {
        return laneName;
    }
    public String keyedLaneName(Object laneKey) {
        if (laneKey == null) {
            return null;
        }
        return laneName + laneKey;
    }
}
src/main/java/com/zy/core/task/MainProcessTaskSubmitter.java
New file
@@ -0,0 +1,62 @@
package com.zy.core.task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MainProcessTaskSubmitter {
    private static final long DEFAULT_SLOW_LOG_THRESHOLD_MS = 1000L;
    @Autowired
    private MainProcessAsyncTaskScheduler mainProcessAsyncTaskScheduler;
    public boolean submitSerialTask(String laneName,
                                    String taskName,
                                    long minIntervalMs,
                                    Runnable task) {
        return mainProcessAsyncTaskScheduler.submit(
                laneName,
                taskName,
                minIntervalMs,
                DEFAULT_SLOW_LOG_THRESHOLD_MS,
                task
        );
    }
    public boolean submitSerialTask(MainProcessLane lane,
                                    String taskName,
                                    long minIntervalMs,
                                    Runnable task) {
        if (lane == null) {
            return false;
        }
        return submitSerialTask(lane.laneName(), taskName, minIntervalMs, task);
    }
    public boolean submitKeyedSerialTask(String lanePrefix,
                                         Object laneKey,
                                         String taskName,
                                         long minIntervalMs,
                                         Runnable task) {
        if (laneKey == null) {
            return false;
        }
        return submitSerialTask(lanePrefix + laneKey, taskName, minIntervalMs, task);
    }
    public boolean submitKeyedSerialTask(MainProcessLane lane,
                                         Object laneKey,
                                         String taskName,
                                         long minIntervalMs,
                                         Runnable task) {
        if (lane == null) {
            return false;
        }
        String laneName = lane.keyedLaneName(laneKey);
        if (laneName == null) {
            return false;
        }
        return submitSerialTask(laneName, taskName, minIntervalMs, task);
    }
}
src/main/java/com/zy/core/utils/CrnOperateProcessUtils.java
@@ -27,6 +27,8 @@
import com.zy.core.model.command.CrnCommand;
import com.zy.core.model.protocol.CrnProtocol;
import com.zy.core.model.protocol.StationProtocol;
import com.zy.core.task.MainProcessLane;
import com.zy.core.task.MainProcessTaskSubmitter;
import com.zy.core.thread.CrnThread;
import com.zy.core.thread.StationThread;
import org.springframework.beans.factory.annotation.Autowired;
@@ -56,6 +58,8 @@
    private NotifyUtils notifyUtils;
    @Autowired
    private StationOperateProcessUtils stationOperateProcessUtils;
    @Autowired
    private MainProcessTaskSubmitter mainProcessTaskSubmitter;
    public synchronized void crnIoExecute() {
        Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key);
@@ -69,81 +73,103 @@
        }
    }
    public void crnIoExecute(BasCrnp basCrnp) {
        if (basCrnp == null || basCrnp.getCrnNo() == null) {
            return;
        }
        Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key);
        if (systemConfigMapObj != null) {
            HashMap<String, String> systemConfigMap = (HashMap<String, String>) systemConfigMapObj;
            if ("solver".equals(systemConfigMap.get("crnRunMethod"))) {
                plannerExecute(basCrnp);
            } else {
                crnIoExecuteNormal(basCrnp);
            }
        } else {
            crnIoExecuteNormal(basCrnp);
        }
    }
    //入出库  ===>>  堆垛机入出库作业下发
    public synchronized void crnIoExecuteNormal() {
        List<BasCrnp> basCrnps = basCrnpService.selectList(new EntityWrapper<>());
        for (BasCrnp basCrnp : basCrnps) {
            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, basCrnp.getCrnNo());
            if(crnThread == null){
                continue;
            crnIoExecuteNormal(basCrnp);
        }
    }
    public void crnIoExecuteNormal(BasCrnp basCrnp) {
        if (basCrnp == null || basCrnp.getCrnNo() == null) {
            return;
        }
        CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, basCrnp.getCrnNo());
        if(crnThread == null){
            return;
        }
        CrnProtocol crnProtocol = crnThread.getStatus();
        if(crnProtocol == null){
            return;
        }
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                .eq("crn_no", basCrnp.getCrnNo())
                .in("wrk_sts", WrkStsType.INBOUND_RUN.sts, WrkStsType.OUTBOUND_RUN.sts)
                .orderBy("batch_seq", false)
        );
        if(!wrkMasts.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
        ) {
            Object clearLock = redisUtil.get(RedisKeyType.CLEAR_CRN_TASK_LIMIT.key + basCrnp.getCrnNo());
            if (clearLock != null) {
                return;
            }
            CrnProtocol crnProtocol = crnThread.getStatus();
            if(crnProtocol == null){
                continue;
            }
            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                    .eq("crn_no", basCrnp.getCrnNo())
                    .in("wrk_sts", WrkStsType.INBOUND_RUN.sts, WrkStsType.OUTBOUND_RUN.sts)
                    .orderBy("batch_seq", false)
            );
            if(!wrkMasts.isEmpty()){
                continue;
            }
            // 只有当堆垛机空闲 并且 无任务时才继续执行
            if (crnProtocol.getMode() == CrnModeType.AUTO.id
                    && crnProtocol.getTaskNo() == 0
                    && crnProtocol.getStatus() == CrnStatusType.IDLE.id
                    && crnProtocol.getLoaded() == 0
                    && crnProtocol.getForkPos() == 0
                    && crnProtocol.getAlarm() == 0
            ) {
                Object clearLock = redisUtil.get(RedisKeyType.CLEAR_CRN_TASK_LIMIT.key + basCrnp.getCrnNo());
                if (clearLock != null) {
                    continue;
                }
                // 如果最近一次是入库模式
                if (crnProtocol.getLastIo().equals("I")) {
                    if (basCrnp.getInEnable().equals("Y")) {
                        boolean result = this.crnExecuteIn(basCrnp, crnThread);//  入库
                        crnProtocol.setLastIo("O");
                        if (result) {
                            break;
                        }
                    } else if (basCrnp.getOutEnable().equals("Y")) {
                        boolean result = this.crnExecuteOut(basCrnp, crnThread);//  出库
                        crnProtocol.setLastIo("I");
                        if (result) {
                            break;
                        }
            // 如果最近一次是入库模式
            if (crnProtocol.getLastIo().equals("I")) {
                if (basCrnp.getInEnable().equals("Y")) {
                    boolean result = this.crnExecuteIn(basCrnp, crnThread);//  入库
                    crnProtocol.setLastIo("O");
                    if (result) {
                        return;
                    }
                } else if (basCrnp.getOutEnable().equals("Y")) {
                    boolean result = this.crnExecuteOut(basCrnp, crnThread);//  出库
                    crnProtocol.setLastIo("I");
                    if (result) {
                        return;
                    }
                }
                // 如果最近一次是出库模式
                else if (crnProtocol.getLastIo().equals("O")) {
                    if (basCrnp.getOutEnable().equals("Y")) {
                        boolean result = this.crnExecuteOut(basCrnp, crnThread);//  出库
                        crnProtocol.setLastIo("I");
                        if (result) {
                            break;
                        }
                    } else if (basCrnp.getInEnable().equals("Y")) {
                        boolean result = this.crnExecuteIn(basCrnp, crnThread);//  入库
                        crnProtocol.setLastIo("O");
                        if (result) {
                            break;
                        }
            }
            // 如果最近一次是出库模式
            else if (crnProtocol.getLastIo().equals("O")) {
                if (basCrnp.getOutEnable().equals("Y")) {
                    boolean result = this.crnExecuteOut(basCrnp, crnThread);//  出库
                    crnProtocol.setLastIo("I");
                    if (result) {
                        return;
                    }
                } else if (basCrnp.getInEnable().equals("Y")) {
                    boolean result = this.crnExecuteIn(basCrnp, crnThread);//  入库
                    crnProtocol.setLastIo("O");
                    if (result) {
                        return;
                    }
                }
                //库位移转
                boolean transfer = this.crnExecuteLocTransfer(basCrnp, crnThread);
                if (transfer) {
                    break;
                }
            }
            //库位移转
            this.crnExecuteLocTransfer(basCrnp, crnThread);
        }
    }
@@ -587,168 +613,184 @@
    public synchronized void crnIoExecuteFinish() {
        List<BasCrnp> basCrnps = basCrnpService.selectList(new EntityWrapper<>());
        for (BasCrnp basCrnp : basCrnps) {
            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, basCrnp.getCrnNo());
            if(crnThread == null){
                continue;
            crnIoExecuteFinish(basCrnp);
        }
    }
    public void crnIoExecuteFinish(BasCrnp basCrnp) {
        if (basCrnp == null || basCrnp.getCrnNo() == null) {
            return;
        }
        CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, basCrnp.getCrnNo());
        if(crnThread == null){
            return;
        }
        CrnProtocol crnProtocol = crnThread.getStatus();
        if(crnProtocol == null){
            return;
        }
        if (crnProtocol.getMode() == CrnModeType.AUTO.id
                && crnProtocol.getTaskNo() > 0
                && crnProtocol.getStatus() == CrnStatusType.WAITING.id
        ) {
            Object lock = redisUtil.get(RedisKeyType.CRN_IO_EXECUTE_FINISH_LIMIT.key + basCrnp.getCrnNo());
            if(lock != null){
                return;
            }
            CrnProtocol crnProtocol = crnThread.getStatus();
            if(crnProtocol == null){
                continue;
            // 获取待确认工作档
            WrkMast wrkMast = wrkMastService.selectByWorkNo(crnProtocol.getTaskNo());
            if (wrkMast == null) {
                News.error("堆垛机处于等待确认且任务完成状态,但未找到工作档。堆垛机号={},工作号={}", basCrnp.getCrnNo(), crnProtocol.getTaskNo());
                return;
            }
            if (crnProtocol.getMode() == CrnModeType.AUTO.id
                    && crnProtocol.getTaskNo() > 0
                    && crnProtocol.getStatus() == CrnStatusType.WAITING.id
            ) {
                Object lock = redisUtil.get(RedisKeyType.CRN_IO_EXECUTE_FINISH_LIMIT.key + basCrnp.getCrnNo());
                if(lock != null){
                    continue;
            Long updateWrkSts = null;
            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());
                    return;
                }
                // 获取待确认工作档
                WrkMast wrkMast = wrkMastService.selectByWorkNo(crnProtocol.getTaskNo());
                if (wrkMast == null) {
                    News.error("堆垛机处于等待确认且任务完成状态,但未找到工作档。堆垛机号={},工作号={}", basCrnp.getCrnNo(), crnProtocol.getTaskNo());
                    continue;
                }
                Long updateWrkSts = null;
                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());
                        return;
                StationObjModel outStationObjModel = null;
                for (StationObjModel stationObjModel : outStationList) {
                    if (stationObjModel.getStationId().equals(wrkMast.getSourceStaNo())) {
                        outStationObjModel = stationObjModel;
                        break;
                    }
                    StationObjModel outStationObjModel = null;
                    for (StationObjModel stationObjModel : outStationList) {
                        if (stationObjModel.getStationId().equals(wrkMast.getSourceStaNo())) {
                            outStationObjModel = stationObjModel;
                            break;
                        }
                    }
                    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{
                    News.error("堆垛机处于等待确认且任务完成状态,但工作状态异常。堆垛机号={},工作号={}", basCrnp.getCrnNo(), crnProtocol.getTaskNo());
                    continue;
                }
                wrkMast.setWrkSts(updateWrkSts);
                wrkMast.setSystemMsg("");
                wrkMast.setIoTime(new Date());
                if (wrkMastService.updateById(wrkMast)) {
                    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);
                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{
                News.error("堆垛机处于等待确认且任务完成状态,但工作状态异常。堆垛机号={},工作号={}", basCrnp.getCrnNo(), crnProtocol.getTaskNo());
                return;
            }
            wrkMast.setWrkSts(updateWrkSts);
            wrkMast.setSystemMsg("");
            wrkMast.setIoTime(new Date());
            if (wrkMastService.updateById(wrkMast)) {
                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);
        }
    }
    public synchronized void plannerExecute() {
        int nowSec = (int) (System.currentTimeMillis() / 1000);
        List<BasCrnp> basCrnps = basCrnpService.selectList(new EntityWrapper<>());
        for (BasCrnp basCrnp : basCrnps) {
            String key = RedisKeyType.PLANNER_SCHEDULE.key + "CRN-" + basCrnp.getCrnNo();
            List<Object> items = redisUtil.lGet(key, 0, -1);
            if (items == null || items.isEmpty()) {
            plannerExecute(basCrnp);
        }
    }
    public void plannerExecute(BasCrnp basCrnp) {
        if (basCrnp == null || basCrnp.getCrnNo() == null) {
            return;
        }
        int nowSec = (int) (System.currentTimeMillis() / 1000);
        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.selectList(new EntityWrapper<WrkMast>()
                .eq("crn_no", basCrnp.getCrnNo())
                .in("wrk_sts", WrkStsType.INBOUND_RUN.sts, WrkStsType.OUTBOUND_RUN.sts, WrkStsType.LOC_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) {
                continue;
            }
            CrnProtocol crnProtocol = crnThread.getStatus();
            if (crnProtocol == null) {
                continue;
            }
            List<WrkMast> running = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                    .eq("crn_no", basCrnp.getCrnNo())
                    .in("wrk_sts", WrkStsType.INBOUND_RUN.sts, WrkStsType.OUTBOUND_RUN.sts, WrkStsType.LOC_MOVE_RUN.sts)
            );
            if (!running.isEmpty()) {
                continue;
            }
            if (!(crnProtocol.getMode() == CrnModeType.AUTO.id
                    && crnProtocol.getTaskNo() == 0
                    && crnProtocol.getStatus() == CrnStatusType.IDLE.id
                    && crnProtocol.getLoaded() == 0
                    && crnProtocol.getForkPos() == 0
                    && crnProtocol.getAlarm() == 0)) {
            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;
                    return;
                }
                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;
                    return;
                }
                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);
                    return;
                }
            }
        }
@@ -805,6 +847,48 @@
        return false;
    }
    public void submitCrnIoTasks(long minIntervalMs) {
        submitCrnIoTasks(MainProcessLane.CRN_IO, minIntervalMs);
    }
    public void submitCrnIoTasks(MainProcessLane lane, long minIntervalMs) {
        List<BasCrnp> basCrnps = basCrnpService.selectList(new EntityWrapper<>());
        for (BasCrnp basCrnp : basCrnps) {
            if (basCrnp == null || basCrnp.getCrnNo() == null) {
                continue;
            }
            final BasCrnp currentCrn = basCrnp;
            mainProcessTaskSubmitter.submitKeyedSerialTask(
                    lane,
                    currentCrn.getCrnNo(),
                    "crnIoExecute",
                    minIntervalMs,
                    () -> crnIoExecute(currentCrn)
            );
        }
    }
    public void submitCrnIoExecuteFinishTasks(long minIntervalMs) {
        submitCrnIoExecuteFinishTasks(MainProcessLane.CRN_IO_FINISH, minIntervalMs);
    }
    public void submitCrnIoExecuteFinishTasks(MainProcessLane lane, long minIntervalMs) {
        List<BasCrnp> basCrnps = basCrnpService.selectList(new EntityWrapper<>());
        for (BasCrnp basCrnp : basCrnps) {
            if (basCrnp == null || basCrnp.getCrnNo() == null) {
                continue;
            }
            final BasCrnp currentCrn = basCrnp;
            mainProcessTaskSubmitter.submitKeyedSerialTask(
                    lane,
                    currentCrn.getCrnNo(),
                    "crnIoExecuteFinish",
                    minIntervalMs,
                    () -> crnIoExecuteFinish(currentCrn)
            );
        }
    }
    //检测浅库位状态
    public synchronized boolean checkShallowLocStatus(String locNo, Integer taskNo) {
        String checkDeepLocOutTaskBlockReport = "Y";
src/main/java/com/zy/core/utils/DualCrnOperateProcessUtils.java
@@ -29,6 +29,8 @@
import com.zy.core.model.param.SendDualCrnCommandParam;
import com.zy.core.model.protocol.DualCrnProtocol;
import com.zy.core.model.protocol.StationProtocol;
import com.zy.core.task.MainProcessLane;
import com.zy.core.task.MainProcessTaskSubmitter;
import com.zy.core.thread.DualCrnThread;
import com.zy.core.thread.StationThread;
import org.springframework.beans.factory.annotation.Autowired;
@@ -60,43 +62,52 @@
    private CommonService commonService;
    @Autowired
    private NotifyUtils notifyUtils;
    @Autowired
    private MainProcessTaskSubmitter mainProcessTaskSubmitter;
    //入出库  ===>>  双工位堆垛机入出库作业下发
    public synchronized void dualCrnIoExecute() {
        List<BasDualCrnp> basDualCrnps = basDualCrnpService.selectList(new EntityWrapper<>());
        for (BasDualCrnp basDualCrnp : basDualCrnps) {
            DualCrnThread dualCrnThread = (DualCrnThread) SlaveConnection.get(SlaveType.DualCrn, basDualCrnp.getCrnNo());
            if(dualCrnThread == null){
                continue;
            }
            DualCrnProtocol dualCrnProtocol = dualCrnThread.getStatus();
            if(dualCrnProtocol == null){
                continue;
            }
            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                    .eq("dual_crn_no", basDualCrnp.getCrnNo())
                    .in("wrk_sts", WrkStsType.INBOUND_RUN.sts, WrkStsType.OUTBOUND_RUN.sts)
            );
            if(wrkMasts.size() >= 2){
                continue;
            }
            if(dualCrnProtocol.getMode() != DualCrnModeType.AUTO.id) {
                continue;
            }
            if(dualCrnProtocol.getAlarm() != 0) {
                continue;
            }
            if(dualCrnProtocol.getTaskSend() != 0 || dualCrnProtocol.getTaskSendTwo() != 0) {
                continue;
            }
            this.crnExecute(basDualCrnp, dualCrnThread);
            dualCrnIoExecute(basDualCrnp);
        }
    }
    public void dualCrnIoExecute(BasDualCrnp basDualCrnp) {
        if (basDualCrnp == null || basDualCrnp.getCrnNo() == null) {
            return;
        }
        DualCrnThread dualCrnThread = (DualCrnThread) SlaveConnection.get(SlaveType.DualCrn, basDualCrnp.getCrnNo());
        if(dualCrnThread == null){
            return;
        }
        DualCrnProtocol dualCrnProtocol = dualCrnThread.getStatus();
        if(dualCrnProtocol == null){
            return;
        }
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                .eq("dual_crn_no", basDualCrnp.getCrnNo())
                .in("wrk_sts", WrkStsType.INBOUND_RUN.sts, WrkStsType.OUTBOUND_RUN.sts)
        );
        if(wrkMasts.size() >= 2){
            return;
        }
        if(dualCrnProtocol.getMode() != DualCrnModeType.AUTO.id) {
            return;
        }
        if(dualCrnProtocol.getAlarm() != 0) {
            return;
        }
        if(dualCrnProtocol.getTaskSend() != 0 || dualCrnProtocol.getTaskSendTwo() != 0) {
            return;
        }
        this.crnExecute(basDualCrnp, dualCrnThread);
    }
    private synchronized void crnExecute(BasDualCrnp basDualCrnp, DualCrnThread dualCrnThread) {
@@ -691,33 +702,91 @@
    public synchronized void dualCrnIoExecuteFinish() {
        List<BasDualCrnp> basDualCrnps = basDualCrnpService.selectList(new EntityWrapper<>());
        for (BasDualCrnp basDualCrnp : basDualCrnps) {
            DualCrnThread dualCrnThread = (DualCrnThread) SlaveConnection.get(SlaveType.DualCrn, basDualCrnp.getCrnNo());
            if(dualCrnThread == null){
                continue;
            }
            dualCrnIoExecuteFinish(basDualCrnp);
        }
    }
            DualCrnProtocol dualCrnProtocol = dualCrnThread.getStatus();
            if(dualCrnProtocol == null){
                continue;
            }
    public void dualCrnIoExecuteFinish(BasDualCrnp basDualCrnp) {
        if (basDualCrnp == null || basDualCrnp.getCrnNo() == null) {
            return;
        }
        DualCrnThread dualCrnThread = (DualCrnThread) SlaveConnection.get(SlaveType.DualCrn, basDualCrnp.getCrnNo());
        if(dualCrnThread == null){
            return;
        }
            if(dualCrnProtocol.getMode() != DualCrnModeType.AUTO.id) {
                continue;
            }
        DualCrnProtocol dualCrnProtocol = dualCrnThread.getStatus();
        if(dualCrnProtocol == null){
            return;
        }
            if(dualCrnProtocol.getAlarm() != 0) {
                continue;
            }
        if(dualCrnProtocol.getMode() != DualCrnModeType.AUTO.id) {
            return;
        }
            if((dualCrnProtocol.getTaskNo() > 0 && dualCrnProtocol.getDeviceTaskNo() > 0) && dualCrnProtocol.getTaskSend() == 0 && dualCrnProtocol.getStatus().equals(DualCrnStatusType.WAITING.id)) {
                executeFinish(basDualCrnp, dualCrnThread, dualCrnProtocol, dualCrnProtocol.getTaskNo(), 1);
                continue;
            }
        if(dualCrnProtocol.getAlarm() != 0) {
            return;
        }
            if((dualCrnProtocol.getTaskNoTwo() > 0 && dualCrnProtocol.getDeviceTaskNoTwo() > 0) && dualCrnProtocol.getTaskSendTwo() == 0 && dualCrnProtocol.getStatusTwo().equals(DualCrnStatusType.WAITING.id)) {
                executeFinish(basDualCrnp, dualCrnThread, dualCrnProtocol, dualCrnProtocol.getTaskNoTwo(), 2);
        if((dualCrnProtocol.getTaskNo() > 0 && dualCrnProtocol.getDeviceTaskNo() > 0) && dualCrnProtocol.getTaskSend() == 0 && dualCrnProtocol.getStatus().equals(DualCrnStatusType.WAITING.id)) {
            executeFinish(basDualCrnp, dualCrnThread, dualCrnProtocol, dualCrnProtocol.getTaskNo(), 1);
            return;
        }
        if((dualCrnProtocol.getTaskNoTwo() > 0 && dualCrnProtocol.getDeviceTaskNoTwo() > 0) && dualCrnProtocol.getTaskSendTwo() == 0 && dualCrnProtocol.getStatusTwo().equals(DualCrnStatusType.WAITING.id)) {
            executeFinish(basDualCrnp, dualCrnThread, dualCrnProtocol, dualCrnProtocol.getTaskNoTwo(), 2);
        }
    }
    public void submitDualCrnIoTasks(long minIntervalMs) {
        submitDualCrnIoTasks(MainProcessLane.DUAL_CRN_IO, minIntervalMs);
    }
    public void submitDualCrnIoTasks(MainProcessLane lane, long minIntervalMs) {
        List<BasDualCrnp> basDualCrnps = basDualCrnpService.selectList(new EntityWrapper<>());
        for (final BasDualCrnp basDualCrnp : basDualCrnps) {
            Integer crnNo = basDualCrnp == null ? null : basDualCrnp.getCrnNo();
            if (crnNo == null) {
                continue;
            }
            mainProcessTaskSubmitter.submitKeyedSerialTask(
                    lane,
                    crnNo,
                    "dualCrnIoExecute",
                    minIntervalMs,
                    new Runnable() {
                        @Override
                        public void run() {
                            dualCrnIoExecute(basDualCrnp);
                        }
                    }
            );
        }
    }
    public void submitDualCrnIoExecuteFinishTasks(long minIntervalMs) {
        submitDualCrnIoExecuteFinishTasks(MainProcessLane.DUAL_CRN_IO_FINISH, minIntervalMs);
    }
    public void submitDualCrnIoExecuteFinishTasks(MainProcessLane lane, long minIntervalMs) {
        List<BasDualCrnp> basDualCrnps = basDualCrnpService.selectList(new EntityWrapper<>());
        for (final BasDualCrnp basDualCrnp : basDualCrnps) {
            Integer crnNo = basDualCrnp == null ? null : basDualCrnp.getCrnNo();
            if (crnNo == null) {
                continue;
            }
            mainProcessTaskSubmitter.submitKeyedSerialTask(
                    lane,
                    crnNo,
                    "dualCrnIoExecuteFinish",
                    minIntervalMs,
                    new Runnable() {
                        @Override
                        public void run() {
                            dualCrnIoExecuteFinish(basDualCrnp);
                        }
                    }
            );
        }
    }
src/main/java/com/zy/core/utils/StationOperateProcessUtils.java
@@ -26,6 +26,8 @@
import com.zy.core.model.Task;
import com.zy.core.model.command.StationCommand;
import com.zy.core.model.protocol.StationProtocol;
import com.zy.core.task.MainProcessLane;
import com.zy.core.task.MainProcessTaskSubmitter;
import com.zy.core.thread.StationThread;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -56,6 +58,203 @@
    private BasStationService basStationService;
    @Autowired
    private StationCycleCapacityService stationCycleCapacityService;
    @Autowired
    private MainProcessTaskSubmitter mainProcessTaskSubmitter;
    public void submitStationEnableInTasks(long minIntervalMs) {
        submitStationEnableInTasks(MainProcessLane.STATION_ENABLE_IN, minIntervalMs);
    }
    public void submitStationEnableInTasks(MainProcessLane lane, long minIntervalMs) {
        List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>());
        for (final BasDevp basDevp : basDevps) {
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
            if (stationThread == null) {
                continue;
            }
            Map<Integer, StationProtocol> stationMap = stationThread.getStatusMap();
            if (stationMap == null || stationMap.isEmpty()) {
                continue;
            }
            List<StationObjModel> list = basDevp.getInStationList$();
            for (final StationObjModel stationObjModel : list) {
                Integer stationId = stationObjModel == null ? null : stationObjModel.getStationId();
                if (stationId == null || !stationMap.containsKey(stationId)) {
                    continue;
                }
                mainProcessTaskSubmitter.submitKeyedSerialTask(
                        lane,
                        stationId,
                        "stationEnableInExecute",
                        minIntervalMs,
                        new Runnable() {
                            @Override
                            public void run() {
                                stationEnableInExecute(basDevp, stationObjModel);
                            }
                        }
                );
            }
        }
    }
    public void submitStationInTasks(long minIntervalMs) {
        submitStationInTasks(MainProcessLane.STATION_IN, minIntervalMs);
    }
    public void submitStationInTasks(MainProcessLane lane, long minIntervalMs) {
        // 入库下发依赖单轮共享的承载预占状态,必须整体串行,避免多个站点并发时同时通过容量检查。
        mainProcessTaskSubmitter.submitSerialTask(
                MainProcessLane.STATION,
                "stationInExecute",
                minIntervalMs,
                new Runnable() {
                    @Override
                    public void run() {
                        stationInExecute();
                    }
                }
        );
    }
    public void submitCrnStationOutTasks(long minIntervalMs) {
        submitCrnStationOutTasks(MainProcessLane.STATION_OUT, minIntervalMs);
    }
    public void submitCrnStationOutTasks(MainProcessLane lane, long minIntervalMs) {
        // 出库站点下发同样会预占输送线/环线容量,与 stationInExecute 共用 STATION lane 串行。
        mainProcessTaskSubmitter.submitSerialTask(
                MainProcessLane.STATION,
                "crnStationOutExecute",
                minIntervalMs,
                new Runnable() {
                    @Override
                    public void run() {
                        crnStationOutExecute();
                    }
                }
        );
    }
    public void submitDualCrnStationOutTasks(long minIntervalMs) {
        submitDualCrnStationOutTasks(MainProcessLane.DUAL_STATION_OUT, minIntervalMs);
    }
    public void submitDualCrnStationOutTasks(MainProcessLane lane, long minIntervalMs) {
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                .eq("wrk_sts", WrkStsType.OUTBOUND_RUN_COMPLETE.sts)
                .isNotNull("dual_crn_no")
        );
        for (final WrkMast wrkMast : wrkMasts) {
            Integer laneKey = wrkMast == null ? null : wrkMast.getSourceStaNo();
            if (laneKey == null) {
                laneKey = wrkMast == null ? null : wrkMast.getWrkNo();
            }
            mainProcessTaskSubmitter.submitKeyedSerialTask(
                    lane,
                    laneKey,
                    "dualCrnStationOutExecute",
                    minIntervalMs,
                    new Runnable() {
                        @Override
                        public void run() {
                            dualCrnStationOutExecute(wrkMast);
                        }
                    }
            );
        }
    }
    public void submitStationOutExecuteFinishTasks(long minIntervalMs) {
        submitStationOutExecuteFinishTasks(MainProcessLane.STATION_OUT_FINISH, minIntervalMs);
    }
    public void submitStationOutExecuteFinishTasks(MainProcessLane lane, long minIntervalMs) {
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("wrk_sts", WrkStsType.STATION_RUN.sts));
        for (final WrkMast wrkMast : wrkMasts) {
            Integer laneKey = wrkMast == null ? null : wrkMast.getStaNo();
            if (laneKey == null) {
                laneKey = wrkMast == null ? null : wrkMast.getWrkNo();
            }
            mainProcessTaskSubmitter.submitKeyedSerialTask(
                    lane,
                    laneKey,
                    "stationOutExecuteFinish",
                    minIntervalMs,
                    new Runnable() {
                        @Override
                        public void run() {
                            stationOutExecuteFinish(wrkMast);
                        }
                    }
            );
        }
    }
    public void submitCheckTaskToCompleteTasks(long minIntervalMs) {
        submitCheckTaskToCompleteTasks(MainProcessLane.STATION_COMPLETE, minIntervalMs);
    }
    public void submitCheckTaskToCompleteTasks(MainProcessLane lane, long minIntervalMs) {
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("wrk_sts", WrkStsType.STATION_RUN_COMPLETE.sts));
        for (final WrkMast wrkMast : wrkMasts) {
            Integer laneKey = wrkMast == null ? null : wrkMast.getStaNo();
            if (laneKey == null) {
                laneKey = wrkMast == null ? null : wrkMast.getWrkNo();
            }
            mainProcessTaskSubmitter.submitKeyedSerialTask(
                    lane,
                    laneKey,
                    "checkTaskToComplete",
                    minIntervalMs,
                    new Runnable() {
                        @Override
                        public void run() {
                            checkTaskToComplete(wrkMast);
                        }
                    }
            );
        }
    }
    public void submitCheckStationRunBlockTasks(long minIntervalMs) {
        submitCheckStationRunBlockTasks(MainProcessLane.STATION_RUN_BLOCK, minIntervalMs);
    }
    public void submitCheckStationRunBlockTasks(MainProcessLane lane, long minIntervalMs) {
        List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>());
        for (final BasDevp basDevp : basDevps) {
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
            if (stationThread == null) {
                continue;
            }
            List<StationProtocol> statusList = stationThread.getStatus();
            for (StationProtocol stationProtocol : statusList) {
                final Integer stationId = stationProtocol == null ? null : stationProtocol.getStationId();
                if (stationId == null) {
                    continue;
                }
                if (!stationProtocol.isAutoing()
                        || !stationProtocol.isLoading()
                        || stationProtocol.getTaskNo() <= 0
                        || !stationProtocol.isRunBlock()) {
                    continue;
                }
                mainProcessTaskSubmitter.submitKeyedSerialTask(
                        lane,
                        stationId,
                        "checkStationRunBlock",
                        minIntervalMs,
                        new Runnable() {
                            @Override
                            public void run() {
                                checkStationRunBlock(basDevp, stationId);
                            }
                        }
                );
            }
        }
    }
    //执行输送站点入库任务
    public synchronized void stationInExecute() {
@@ -75,79 +274,165 @@
                List<StationObjModel> list = basDevp.getBarcodeStationList$();
                for (StationObjModel entity : list) {
                    Integer stationId = entity.getStationId();
                    if (!stationMap.containsKey(stationId)) {
                        continue;
                    }
                    StationProtocol stationProtocol = stationMap.get(stationId);
                    if (stationProtocol == null) {
                        continue;
                    }
                    Object lock = redisUtil.get(RedisKeyType.STATION_IN_EXECUTE_LIMIT.key + stationId);
                    if (lock != null) {
                        continue;
                    }
                    //满足自动、有物、有工作号
                    if (stationProtocol.isAutoing()
                            && stationProtocol.isLoading()
                            && stationProtocol.getTaskNo() > 0
                    ) {
                        //检测任务是否生成
                        WrkMast wrkMast = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("barcode", stationProtocol.getBarcode()));
                        if (wrkMast == null) {
                            continue;
                        }
                        if (wrkMast.getWrkSts() == WrkStsType.INBOUND_DEVICE_RUN.sts) {
                            continue;
                        }
                        String locNo = wrkMast.getLocNo();
                        FindCrnNoResult findCrnNoResult = commonService.findCrnNoByLocNo(locNo);
                        if (findCrnNoResult == null) {
                            News.taskInfo(wrkMast.getWrkNo(), "{}工作,未匹配到堆垛机", wrkMast.getWrkNo());
                            continue;
                        }
                        Integer targetStationId = commonService.findInStationId(findCrnNoResult, stationId);
                        if (targetStationId == null) {
                            News.taskInfo(wrkMast.getWrkNo(), "{}站点,搜索入库站点失败", stationId);
                            continue;
                        }
                        LoopHitResult loopHitResult = findPathLoopHit(limitConfig, stationProtocol.getStationId(), targetStationId, loadGuardState);
                        if (isDispatchBlocked(limitConfig, currentStationTaskCountRef[0], loadGuardState, loopHitResult.isThroughLoop())) {
                            return;
                        }
                        StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationId, targetStationId, 0);
                        if (command == null) {
                            News.taskInfo(wrkMast.getWrkNo(), "{}工作,获取输送线命令失败", wrkMast.getWrkNo());
                            continue;
                        }
                        wrkMast.setWrkSts(WrkStsType.INBOUND_DEVICE_RUN.sts);
                        wrkMast.setSourceStaNo(stationProtocol.getStationId());
                        wrkMast.setStaNo(targetStationId);
                        wrkMast.setSystemMsg("");
                        wrkMast.setIoTime(new Date());
                        if (wrkMastService.updateById(wrkMast)) {
                            MessageQueue.offer(SlaveType.Devp, basDevp.getDevpNo(), new Task(2, command));
                            News.info("输送站点入库命令下发成功,站点号={},工作号={},命令数据={}", stationId, wrkMast.getWrkNo(), JSON.toJSONString(command));
                            redisUtil.set(RedisKeyType.STATION_IN_EXECUTE_LIMIT.key + stationId, "lock", 5);
                            loadGuardState.reserveLoopTask(loopHitResult.getLoopNo());
                            saveLoopLoadReserve(wrkMast.getWrkNo(), loopHitResult);
                        }
                    if (stationInExecute(basDevp, entity, limitConfig, currentStationTaskCountRef, loadGuardState)) {
                        return;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void stationEnableInExecute(BasDevp basDevp, StationObjModel stationObjModel) {
        try {
            if (basDevp == null || stationObjModel == null || stationObjModel.getStationId() == null) {
                return;
            }
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
            if (stationThread == null) {
                return;
            }
            Map<Integer, StationProtocol> stationMap = stationThread.getStatusMap();
            if (stationMap == null) {
                return;
            }
            Integer stationId = stationObjModel.getStationId();
            if (!stationMap.containsKey(stationId)) {
                return;
            }
            StationProtocol stationProtocol = stationMap.get(stationId);
            if (stationProtocol == null) {
                return;
            }
            Object lock = redisUtil.get(RedisKeyType.GENERATE_ENABLE_IN_STATION_DATA_LIMIT.key + stationId);
            if (lock != null) {
                return;
            }
            if (stationProtocol.isAutoing()
                    && stationProtocol.isLoading()
                    && stationProtocol.getTaskNo() == 0
                    && stationProtocol.isEnableIn()
            ) {
                StationObjModel barcodeStation = stationObjModel.getBarcodeStation();
                if (barcodeStation == null || barcodeStation.getStationId() == null) {
                    return;
                }
                StationCommand command = stationThread.getCommand(StationCommandType.MOVE, commonService.getWorkNo(WrkIoType.ENABLE_IN.id), stationId, barcodeStation.getStationId(), 0);
                if (command == null) {
                    News.info("{}站点启动入库失败,获取输送线命令失败", stationId);
                    return;
                }
                MessageQueue.offer(SlaveType.Devp, basDevp.getDevpNo(), new Task(2, command));
                redisUtil.set(RedisKeyType.GENERATE_ENABLE_IN_STATION_DATA_LIMIT.key + stationId, "lock", 15);
                News.info("{}站点启动入库成功,数据包:{}", stationId, JSON.toJSONString(command));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void stationInExecute(BasDevp basDevp, StationObjModel stationObjModel) {
        try {
            DispatchLimitConfig limitConfig = getDispatchLimitConfig();
            int[] currentStationTaskCountRef = new int[]{countCurrentStationTask()};
            LoadGuardState loadGuardState = buildLoadGuardState(limitConfig);
            stationInExecute(basDevp, stationObjModel, limitConfig, currentStationTaskCountRef, loadGuardState);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private boolean stationInExecute(BasDevp basDevp,
                                     StationObjModel stationObjModel,
                                     DispatchLimitConfig limitConfig,
                                     int[] currentStationTaskCountRef,
                                     LoadGuardState loadGuardState) {
        if (basDevp == null || stationObjModel == null || stationObjModel.getStationId() == null) {
            return false;
        }
        StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
        if (stationThread == null) {
            return false;
        }
        Map<Integer, StationProtocol> stationMap = stationThread.getStatusMap();
        Integer stationId = stationObjModel.getStationId();
        if (stationMap == null || !stationMap.containsKey(stationId)) {
            return false;
        }
        StationProtocol stationProtocol = stationMap.get(stationId);
        if (stationProtocol == null) {
            return false;
        }
        Object lock = redisUtil.get(RedisKeyType.STATION_IN_EXECUTE_LIMIT.key + stationId);
        if (lock != null) {
            return false;
        }
        //满足自动、有物、有工作号
        if (stationProtocol.isAutoing()
                && stationProtocol.isLoading()
                && stationProtocol.getTaskNo() > 0
        ) {
            //检测任务是否生成
            WrkMast wrkMast = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("barcode", stationProtocol.getBarcode()));
            if (wrkMast == null) {
                return false;
            }
            if (wrkMast.getWrkSts() == WrkStsType.INBOUND_DEVICE_RUN.sts) {
                return false;
            }
            String locNo = wrkMast.getLocNo();
            FindCrnNoResult findCrnNoResult = commonService.findCrnNoByLocNo(locNo);
            if (findCrnNoResult == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}工作,未匹配到堆垛机", wrkMast.getWrkNo());
                return false;
            }
            Integer targetStationId = commonService.findInStationId(findCrnNoResult, stationId);
            if (targetStationId == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}站点,搜索入库站点失败", stationId);
                return false;
            }
            LoopHitResult loopHitResult = findPathLoopHit(limitConfig, stationProtocol.getStationId(), targetStationId, loadGuardState);
            if (isDispatchBlocked(limitConfig, currentStationTaskCountRef[0], loadGuardState, loopHitResult.isThroughLoop())) {
                return true;
            }
            StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationId, targetStationId, 0);
            if (command == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}工作,获取输送线命令失败", wrkMast.getWrkNo());
                return false;
            }
            wrkMast.setWrkSts(WrkStsType.INBOUND_DEVICE_RUN.sts);
            wrkMast.setSourceStaNo(stationProtocol.getStationId());
            wrkMast.setStaNo(targetStationId);
            wrkMast.setSystemMsg("");
            wrkMast.setIoTime(new Date());
            if (wrkMastService.updateById(wrkMast)) {
                MessageQueue.offer(SlaveType.Devp, basDevp.getDevpNo(), new Task(2, command));
                News.info("输送站点入库命令下发成功,站点号={},工作号={},命令数据={}", stationId, wrkMast.getWrkNo(), JSON.toJSONString(command));
                redisUtil.set(RedisKeyType.STATION_IN_EXECUTE_LIMIT.key + stationId, "lock", 5);
                loadGuardState.reserveLoopTask(loopHitResult.getLoopNo());
                saveLoopLoadReserve(wrkMast.getWrkNo(), loopHitResult);
            }
        }
        return false;
    }
    //执行堆垛机输送站点出库任务
@@ -164,80 +449,110 @@
            List<Integer> outOrderList = getAllOutOrderList();
            for (WrkMast wrkMast : wrkMasts) {
                Object infoObj = redisUtil.get(RedisKeyType.CRN_OUT_TASK_COMPLETE_STATION_INFO.key + wrkMast.getWrkNo());
                if (infoObj == null) {
                    News.info("出库任务{}数据缓存不存在", wrkMast.getWrkNo());
                    continue;
                }
                StationObjModel stationObjModel = JSON.parseObject(infoObj.toString(), StationObjModel.class);
                StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, stationObjModel.getDeviceNo());
                if (stationThread == null) {
                    continue;
                }
                Map<Integer, StationProtocol> stationMap = stationThread.getStatusMap();
                StationProtocol stationProtocol = stationMap.get(stationObjModel.getStationId());
                if (stationProtocol == null) {
                    continue;
                }
                Object lock = redisUtil.get(RedisKeyType.STATION_OUT_EXECUTE_LIMIT.key + stationProtocol.getStationId());
                if (lock != null) {
                    continue;
                }
                //满足自动、有物、工作号0
                if (stationProtocol.isAutoing()
                        && stationProtocol.isLoading()
                        && stationProtocol.getTaskNo() == 0
                ) {
                    Integer moveStaNo = wrkMast.getStaNo();
                    if (!outOrderList.isEmpty()) {
                        List<NavigateNode> nodes = navigateUtils.calcByStationId(stationProtocol.getStationId(), wrkMast.getStaNo());
                        for (int i = nodes.size() - 1; i >= 0; i--) {
                            NavigateNode node = nodes.get(i);
                            JSONObject v = JSONObject.parseObject(node.getNodeValue());
                            if (v != null) {
                                Integer stationId = v.getInteger("stationId");
                                if (outOrderList.contains(stationId)) {
                                    moveStaNo = stationId;
                                    break;
                                }
                            }
                        }
                    }
                    LoopHitResult loopHitResult = findPathLoopHit(limitConfig, stationProtocol.getStationId(), moveStaNo, loadGuardState);
                    if (isDispatchBlocked(limitConfig, currentStationTaskCountRef[0], loadGuardState, loopHitResult.isThroughLoop())) {
                        return;
                    }
                    StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), moveStaNo, 0);
                    if (command == null) {
                        News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败");
                        continue;
                    }
                    wrkMast.setWrkSts(WrkStsType.STATION_RUN.sts);
                    wrkMast.setSystemMsg("");
                    wrkMast.setIoTime(new Date());
                    if (wrkMastService.updateById(wrkMast)) {
                        MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command));
                        News.info("输送站点出库命令下发成功,站点号={},工作号={},命令数据={}", stationProtocol.getStationId(), wrkMast.getWrkNo(), JSON.toJSONString(command));
                        redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_LIMIT.key + stationProtocol.getStationId(), "lock", 5);
                        redisUtil.del(RedisKeyType.CRN_OUT_TASK_COMPLETE_STATION_INFO.key + wrkMast.getWrkNo());
                        currentStationTaskCountRef[0]++;
                        loadGuardState.reserveLoopTask(loopHitResult.getLoopNo());
                        saveLoopLoadReserve(wrkMast.getWrkNo(), loopHitResult);
                    }
                if (crnStationOutExecute(wrkMast, limitConfig, currentStationTaskCountRef, loadGuardState, outOrderList)) {
                    return;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void crnStationOutExecute(WrkMast wrkMast) {
        try {
            DispatchLimitConfig limitConfig = getDispatchLimitConfig();
            int[] currentStationTaskCountRef = new int[]{countCurrentStationTask()};
            LoadGuardState loadGuardState = buildLoadGuardState(limitConfig);
            List<Integer> outOrderList = getAllOutOrderList();
            crnStationOutExecute(wrkMast, limitConfig, currentStationTaskCountRef, loadGuardState, outOrderList);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private boolean crnStationOutExecute(WrkMast wrkMast,
                                         DispatchLimitConfig limitConfig,
                                         int[] currentStationTaskCountRef,
                                         LoadGuardState loadGuardState,
                                         List<Integer> outOrderList) {
        if (wrkMast == null || wrkMast.getWrkNo() == null) {
            return false;
        }
        Object infoObj = redisUtil.get(RedisKeyType.CRN_OUT_TASK_COMPLETE_STATION_INFO.key + wrkMast.getWrkNo());
        if (infoObj == null) {
            News.info("出库任务{}数据缓存不存在", wrkMast.getWrkNo());
            return false;
        }
        StationObjModel stationObjModel = JSON.parseObject(infoObj.toString(), StationObjModel.class);
        if (stationObjModel == null) {
            return false;
        }
        StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, stationObjModel.getDeviceNo());
        if (stationThread == null) {
            return false;
        }
        Map<Integer, StationProtocol> stationMap = stationThread.getStatusMap();
        StationProtocol stationProtocol = stationMap == null ? null : stationMap.get(stationObjModel.getStationId());
        if (stationProtocol == null) {
            return false;
        }
        Object lock = redisUtil.get(RedisKeyType.STATION_OUT_EXECUTE_LIMIT.key + stationProtocol.getStationId());
        if (lock != null) {
            return false;
        }
        //满足自动、有物、工作号0
        if (stationProtocol.isAutoing()
                && stationProtocol.isLoading()
                && stationProtocol.getTaskNo() == 0
        ) {
            Integer moveStaNo = wrkMast.getStaNo();
            if (outOrderList != null && !outOrderList.isEmpty()) {
                List<NavigateNode> nodes = navigateUtils.calcByStationId(stationProtocol.getStationId(), wrkMast.getStaNo());
                for (int i = nodes.size() - 1; i >= 0; i--) {
                    NavigateNode node = nodes.get(i);
                    JSONObject v = JSONObject.parseObject(node.getNodeValue());
                    if (v != null) {
                        Integer stationId = v.getInteger("stationId");
                        if (outOrderList.contains(stationId)) {
                            moveStaNo = stationId;
                            break;
                        }
                    }
                }
            }
            LoopHitResult loopHitResult = findPathLoopHit(limitConfig, stationProtocol.getStationId(), moveStaNo, loadGuardState);
            if (isDispatchBlocked(limitConfig, currentStationTaskCountRef[0], loadGuardState, loopHitResult.isThroughLoop())) {
                return true;
            }
            StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), moveStaNo, 0);
            if (command == null) {
                News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败");
                return false;
            }
            wrkMast.setWrkSts(WrkStsType.STATION_RUN.sts);
            wrkMast.setSystemMsg("");
            wrkMast.setIoTime(new Date());
            if (wrkMastService.updateById(wrkMast)) {
                MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command));
                News.info("输送站点出库命令下发成功,站点号={},工作号={},命令数据={}", stationProtocol.getStationId(), wrkMast.getWrkNo(), JSON.toJSONString(command));
                redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_LIMIT.key + stationProtocol.getStationId(), "lock", 5);
                redisUtil.del(RedisKeyType.CRN_OUT_TASK_COMPLETE_STATION_INFO.key + wrkMast.getWrkNo());
                currentStationTaskCountRef[0]++;
                loadGuardState.reserveLoopTask(loopHitResult.getLoopNo());
                saveLoopLoadReserve(wrkMast.getWrkNo(), loopHitResult);
            }
        }
        return false;
    }
    //执行双工位堆垛机输送站点出库任务
@@ -248,50 +563,65 @@
                    .isNotNull("dual_crn_no")
            );
            for (WrkMast wrkMast : wrkMasts) {
                Object infoObj = redisUtil.get(RedisKeyType.DUAL_CRN_OUT_TASK_STATION_INFO.key + wrkMast.getWrkNo());
                if (infoObj == null) {
                    News.info("出库任务{}数据缓存不存在", wrkMast.getWrkNo());
                    continue;
                dualCrnStationOutExecute(wrkMast);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void dualCrnStationOutExecute(WrkMast wrkMast) {
        try {
            if (wrkMast == null || wrkMast.getWrkNo() == null) {
                return;
            }
            Object infoObj = redisUtil.get(RedisKeyType.DUAL_CRN_OUT_TASK_STATION_INFO.key + wrkMast.getWrkNo());
            if (infoObj == null) {
                News.info("出库任务{}数据缓存不存在", wrkMast.getWrkNo());
                return;
            }
            StationObjModel stationObjModel = JSON.parseObject(infoObj.toString(), StationObjModel.class);
            if (stationObjModel == null) {
                return;
            }
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, stationObjModel.getDeviceNo());
            if (stationThread == null) {
                return;
            }
            Map<Integer, StationProtocol> stationMap = stationThread.getStatusMap();
            StationProtocol stationProtocol = stationMap == null ? null : stationMap.get(stationObjModel.getStationId());
            if (stationProtocol == null) {
                return;
            }
            Object lock = redisUtil.get(RedisKeyType.STATION_OUT_EXECUTE_LIMIT.key + stationProtocol.getStationId());
            if (lock != null) {
                return;
            }
            //满足自动、有物、工作号0
            if (stationProtocol.isAutoing()
                    && stationProtocol.isLoading()
                    && stationProtocol.getTaskNo() == 0
            ) {
                StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), wrkMast.getStaNo(), 0);
                if (command == null) {
                    News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败");
                    return;
                }
                StationObjModel stationObjModel = JSON.parseObject(infoObj.toString(), StationObjModel.class);
                StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, stationObjModel.getDeviceNo());
                if (stationThread == null) {
                    continue;
                }
                Map<Integer, StationProtocol> stationMap = stationThread.getStatusMap();
                StationProtocol stationProtocol = stationMap.get(stationObjModel.getStationId());
                if (stationProtocol == null) {
                    continue;
                }
                Object lock = redisUtil.get(RedisKeyType.STATION_OUT_EXECUTE_LIMIT.key + stationProtocol.getStationId());
                if (lock != null) {
                    continue;
                }
                //满足自动、有物、工作号0
                if (stationProtocol.isAutoing()
                        && stationProtocol.isLoading()
                        && stationProtocol.getTaskNo() == 0
                ) {
                    StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), wrkMast.getStaNo(), 0);
                    if (command == null) {
                        News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败");
                        continue;
                    }
                    wrkMast.setWrkSts(WrkStsType.STATION_RUN.sts);
                    wrkMast.setSystemMsg("");
                    wrkMast.setIoTime(new Date());
                    if (wrkMastService.updateById(wrkMast)) {
                        MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command));
                        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);
                        redisUtil.del(RedisKeyType.DUAL_CRN_OUT_TASK_STATION_INFO.key + wrkMast.getWrkNo());
                    }
                wrkMast.setWrkSts(WrkStsType.STATION_RUN.sts);
                wrkMast.setSystemMsg("");
                wrkMast.setIoTime(new Date());
                if (wrkMastService.updateById(wrkMast)) {
                    MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command));
                    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);
                    redisUtil.del(RedisKeyType.DUAL_CRN_OUT_TASK_STATION_INFO.key + wrkMast.getWrkNo());
                }
            }
        } catch (Exception e) {
@@ -304,37 +634,48 @@
        try {
            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("wrk_sts", WrkStsType.STATION_RUN.sts));
            for (WrkMast wrkMast : wrkMasts) {
                Integer wrkNo = wrkMast.getWrkNo();
                Integer targetStaNo = wrkMast.getStaNo();
                stationOutExecuteFinish(wrkMast);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
                boolean complete = false;
                BasStation basStation = basStationService.selectOne(new EntityWrapper<BasStation>().eq("station_id", targetStaNo));
                if (basStation == null) {
                    continue;
                }
    public void stationOutExecuteFinish(WrkMast wrkMast) {
        try {
            if (wrkMast == null) {
                return;
            }
            Integer wrkNo = wrkMast.getWrkNo();
            Integer targetStaNo = wrkMast.getStaNo();
                StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo());
                if (stationThread == null) {
                    continue;
                }
            boolean complete = false;
            BasStation basStation = basStationService.selectOne(new EntityWrapper<BasStation>().eq("station_id", targetStaNo));
            if (basStation == null) {
                return;
            }
                Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap();
                StationProtocol stationProtocol = statusMap.get(basStation.getStationId());
                if (stationProtocol == null) {
                    continue;
                }
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo());
            if (stationThread == null) {
                return;
            }
                if (stationProtocol.getTaskNo().equals(wrkNo)) {
                    complete = true;
                }
            Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap();
            StationProtocol stationProtocol = statusMap == null ? null : statusMap.get(basStation.getStationId());
            if (stationProtocol == null) {
                return;
            }
                if (complete) {
                    wrkMast.setWrkSts(WrkStsType.STATION_RUN_COMPLETE.sts);
                    wrkMast.setIoTime(new Date());
                    wrkMastService.updateById(wrkMast);
                    notifyUtils.notify(String.valueOf(SlaveType.Devp), basStation.getDeviceNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.STATION_OUT_TASK_RUN_COMPLETE, null);
                    redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkMast.getWrkNo(), "lock", 60);
                }
            if (stationProtocol.getTaskNo().equals(wrkNo)) {
                complete = true;
            }
            if (complete) {
                wrkMast.setWrkSts(WrkStsType.STATION_RUN_COMPLETE.sts);
                wrkMast.setIoTime(new Date());
                wrkMastService.updateById(wrkMast);
                notifyUtils.notify(String.valueOf(SlaveType.Devp), basStation.getDeviceNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.STATION_OUT_TASK_RUN_COMPLETE, null);
                redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkMast.getWrkNo(), "lock", 60);
            }
        } catch (Exception e) {
            e.printStackTrace();
@@ -346,40 +687,51 @@
        try {
            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("wrk_sts", WrkStsType.STATION_RUN_COMPLETE.sts));
            for (WrkMast wrkMast : wrkMasts) {
                Integer wrkNo = wrkMast.getWrkNo();
                Integer targetStaNo = wrkMast.getStaNo();
                checkTaskToComplete(wrkMast);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
                Object lock = redisUtil.get(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkNo);
                if (lock != null) {
                    continue;
                }
    public void checkTaskToComplete(WrkMast wrkMast) {
        try {
            if (wrkMast == null) {
                return;
            }
            Integer wrkNo = wrkMast.getWrkNo();
            Integer targetStaNo = wrkMast.getStaNo();
                boolean complete = false;
                BasStation basStation = basStationService.selectOne(new EntityWrapper<BasStation>().eq("station_id", targetStaNo));
                if (basStation == null) {
                    continue;
                }
            Object lock = redisUtil.get(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkNo);
            if (lock != null) {
                return;
            }
                StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo());
                if (stationThread == null) {
                    continue;
                }
            boolean complete = false;
            BasStation basStation = basStationService.selectOne(new EntityWrapper<BasStation>().eq("station_id", targetStaNo));
            if (basStation == null) {
                return;
            }
                Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap();
                StationProtocol stationProtocol = statusMap.get(basStation.getStationId());
                if (stationProtocol == null) {
                    continue;
                }
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo());
            if (stationThread == null) {
                return;
            }
                if (!stationProtocol.getTaskNo().equals(wrkNo)) {
                    complete = true;
                }
            Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap();
            StationProtocol stationProtocol = statusMap == null ? null : statusMap.get(basStation.getStationId());
            if (stationProtocol == null) {
                return;
            }
                if (complete) {
                    wrkMast.setWrkSts(WrkStsType.COMPLETE_OUTBOUND.sts);
                    wrkMast.setIoTime(new Date());
                    wrkMastService.updateById(wrkMast);
                }
            if (!stationProtocol.getTaskNo().equals(wrkNo)) {
                complete = true;
            }
            if (complete) {
                wrkMast.setWrkSts(WrkStsType.COMPLETE_OUTBOUND.sts);
                wrkMast.setIoTime(new Date());
                wrkMastService.updateById(wrkMast);
            }
        } catch (Exception e) {
            e.printStackTrace();
@@ -523,6 +875,147 @@
        }
    }
    public void checkStationRunBlock(BasDevp basDevp, Integer stationId) {
        try {
            if (basDevp == null || stationId == null) {
                return;
            }
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
            if (stationThread == null) {
                return;
            }
            Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap();
            StationProtocol stationProtocol = statusMap == null ? null : statusMap.get(stationId);
            if (stationProtocol == null) {
                return;
            }
            List<Integer> runBlockReassignLocStationList = new ArrayList<>();
            for (StationObjModel stationObjModel : basDevp.getRunBlockReassignLocStationList$()) {
                runBlockReassignLocStationList.add(stationObjModel.getStationId());
            }
            if (!(stationProtocol.isAutoing()
                    && stationProtocol.isLoading()
                    && stationProtocol.getTaskNo() > 0
                    && stationProtocol.isRunBlock())) {
                return;
            }
            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", 15);
            if (wrkMast.getIoType() == WrkIoType.IN.id && runBlockReassignLocStationList.contains(stationProtocol.getStationId())) {
                //站点处于重新分配库位区域
                //运行堵塞,重新申请任务
                String response = wmsOperateUtils.applyReassignTaskLocNo(wrkMast.getWrkNo(), stationProtocol.getStationId());
                if (response == null) {
                    News.taskError(wrkMast.getWrkNo(), "请求WMS重新分配库位接口失败,接口未响应!!!response:{}", response);
                    return;
                }
                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);
                        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)) {
                        MessageQueue.offer(SlaveType.Devp, basDevp.getDevpNo(), new Task(2, command));
                    }
                } else {
                    News.error("请求WMS接口失败!!!response:{}", response);
                }
            } else {
                //运行堵塞,重新计算路线
                StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), wrkMast.getStaNo(), 0);
                if (command == null) {
                    News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败");
                    return;
                }
                MessageQueue.offer(SlaveType.Devp, basDevp.getDevpNo(), new Task(2, command));
                News.info("输送站点堵塞后重新计算路径命令下发成功,站点号={},工作号={},命令数据={}", stationProtocol.getStationId(), wrkMast.getWrkNo(), JSON.toJSONString(command));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取输送线任务数量
    public synchronized int getCurrentStationTaskCount() {
        return countCurrentStationTask();
src/main/resources/application.yml
@@ -86,21 +86,9 @@
  platform: java
  pythonPlatformUrl: http://127.0.0.1:9000/ai/diagnose/askStream
  thinking: enable
#  base-url: https://api.siliconflow.cn/v1
#  api-key: sk-sxdtebtquwrugzrmaqqqkzdzmrgzhzmplwwuowysdasccent
#  model: deepseek-ai/DeepSeek-V3.2
#  base-url: http://47.76.147.249:9998/e/7g7kqxxt1ei2un71
#  api-key: app-mP0O6aY5WpbfaHs7BNnjVkli
#  model: deepseek-ai/DeepSeek-V3.2
#  base-url: http://34.2.134.223:3000/v1
#  api-key: sk-WabrmtOezCFwVo7XvVOrO3QkmfcKG7T7jy0BaVnmQTWm5GXh
#  model: gemini-3-pro-preview
#  base-url: http://127.0.0.1:8317/v1
#  api-key: WznOjAGJNVFKSe9kBZTr
#  model: gpt-5
  base-url: https://api.xiaomimimo.com/v1
  api-key: sk-cw7e4se9cal8cxdgjml8dmtn4pdmqtvfccg5fcermt0ddtys
  model: mimo-v2-flash
  base-url: http://127.0.0.1:8317/v1
  api-key: WznOjAGJNVFKSe9kBZTr
  model: gpt-5
perf:
  methodTiming: