#
Junjie
11 小时以前 bdf43f554f9bc7f0de94e7530e79af9193341334
src/main/java/com/zy/core/network/fake/ZyStationFakeSegConnect.java
@@ -27,6 +27,7 @@
import java.util.Arrays;
public class ZyStationFakeSegConnect implements ZyStationConnectApi {
    private static final long DEFAULT_FAKE_RUN_BLOCK_TIMEOUT_MS = 10000L;
    // 站点级锁:每个站点独立一把锁,提升并发性能
    private final Map<Integer, ReentrantLock> stationLocks = new ConcurrentHashMap<>();
@@ -128,6 +129,9 @@
            boolean initialized = false;
            // 上一步执行时间(用于堵塞检测)
            long stepExecuteTime = System.currentTimeMillis();
            long runBlockTimeoutMs = getFakeRunBlockTimeoutMs();
            // 仅在每次到达目标时执行一次到位处理,避免重复生成条码
            boolean arrivalHandled = false;
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
@@ -143,30 +147,35 @@
                StationCommand command = commandQueue.poll(100, TimeUnit.MILLISECONDS);
                if (command != null) {
                    taskLastUpdateTime.put(taskNo, System.currentTimeMillis());
                    List<Integer> newPath = command.getNavigatePath();
                    Integer lastInQueue = getLastInQueue(pendingPathQueue);
                    int startIndex = getPathAppendStartIndex(newPath, currentStationId, lastInQueue);
                    // 首次接收命令时初始化
                    if (finalTargetStationId == null) {
                        finalTargetStationId = command.getTargetStaNo();
                        if (checkTaskNoInArea(taskNo)) {
                            generateBarcode = true;
                    if (newPath != null && !newPath.isEmpty() && startIndex < 0) {
                        News.info("[WCS Debug] 任务{}忽略无法衔接的旧路径段: {}, 当前位置: {}, 队列尾: {}", taskNo,
                                newPath, currentStationId, lastInQueue);
                        continue;
                    }
                    // 每次接收命令都刷新目标,避免沿用旧目标导致状态抖动
                    Integer commandTargetStationId = command.getTargetStaNo();
                    if (commandTargetStationId != null) {
                        if (!commandTargetStationId.equals(finalTargetStationId)) {
                            arrivalHandled = false;
                            News.info("[WCS Debug] 任务{}切换目标: {} -> {}", taskNo, finalTargetStationId,
                                    commandTargetStationId);
                        }
                        finalTargetStationId = commandTargetStationId;
                        // 当前站点先同步最新目标,避免上层在窗口期重复下发同一路径
                        syncCurrentStationTarget(taskNo, currentStationId, finalTargetStationId);
                    }
                    if (!generateBarcode && checkTaskNoInArea(taskNo)) {
                        generateBarcode = true;
                    }
                    // 将新路径追加到待执行队列
                    List<Integer> newPath = command.getNavigatePath();
                    if (newPath != null && !newPath.isEmpty()) {
                        // 获取队列中最后一个站点(用于衔接点去重)
                        Integer lastInQueue = getLastInQueue(pendingPathQueue);
                        if (lastInQueue == null) {
                            lastInQueue = currentStationId;
                        }
                        int startIndex = 0;
                        // 如果新路径的起点与当前位置或队列末尾重复,则跳过
                        if (lastInQueue != null && !newPath.isEmpty() && newPath.get(0).equals(lastInQueue)) {
                            startIndex = 1;
                        }
                        for (int i = startIndex; i < newPath.size(); i++) {
                            pendingPathQueue.offer(newPath.get(i));
                        }
@@ -232,6 +241,7 @@
                            currentStationId = nextStationId;
                            pendingPathQueue.poll();
                            stepExecuteTime = System.currentTimeMillis();
                            arrivalHandled = false;
                            News.info("[WCS Debug] 任务{}移动到站点: {}, 剩余队列: {}", taskNo, currentStationId,
                                    pendingPathQueue.size());
                            sleep(1000); // 模拟移动耗时
@@ -240,7 +250,8 @@
                            if (!checkTaskNoInArea(taskNo)) {
                                boolean fakeAllowCheckBlock = getFakeAllowCheckBlock();
                                if (fakeAllowCheckBlock && System.currentTimeMillis() - stepExecuteTime > 10000) {
                                if (fakeAllowCheckBlock
                                        && System.currentTimeMillis() - stepExecuteTime > runBlockTimeoutMs) {
                                    // 认定堵塞
                                    boolean result = runBlockStation(taskNo, currentStationId, currentDeviceNo, taskNo,
                                            currentStationId);
@@ -261,18 +272,20 @@
                    // 路径队列为空,等待新的分段命令
                    if (currentStationId != null && finalTargetStationId != null
                            && currentStationId.equals(finalTargetStationId)) {
                        // 已到达最终目标,正常结束
                        if (generateBarcode) {
                            Integer targetDeviceNo = getDeviceNoByStationId(finalTargetStationId);
                            if (targetDeviceNo != null) {
                                generateStationBarcode(taskNo, finalTargetStationId, targetDeviceNo);
                                News.info("[WCS Debug] 任务{}到达目标{}并生成条码", taskNo, finalTargetStationId);
                        // 已到达当前目标后继续等待下一条分段命令,避免排序/绕圈场景吞掉后续命令
                        if (!arrivalHandled) {
                            if (generateBarcode) {
                                Integer targetDeviceNo = getDeviceNoByStationId(finalTargetStationId);
                                if (targetDeviceNo != null) {
                                    generateStationBarcode(taskNo, finalTargetStationId, targetDeviceNo);
                                    News.info("[WCS Debug] 任务{}到达目标{}并生成条码", taskNo, finalTargetStationId);
                                }
                            }
                            arrivalHandled = true;
                        }
                        break;
                    }
                    // 未到达最终目标,等待新的分段命令
                    // 继续等待新的分段命令
                    Long lastTime = taskLastUpdateTime.get(taskNo);
                    if (lastTime != null && System.currentTimeMillis() - lastTime > 30000) {
                        // 超时:30秒内没有收到新分段命令
@@ -305,6 +318,72 @@
    }
    /**
     * 计算新路径在队列中的追加起点,避免重复下发导致路径来回跳
     */
    private int getPathAppendStartIndex(List<Integer> newPath, Integer currentStationId, Integer lastInQueue) {
        if (newPath == null || newPath.isEmpty()) {
            return 0;
        }
        if (lastInQueue != null) {
            int idx = newPath.lastIndexOf(lastInQueue);
            if (idx >= 0) {
                return idx + 1;
            }
        }
        if (currentStationId != null) {
            int idx = newPath.lastIndexOf(currentStationId);
            if (idx >= 0) {
                return idx + 1;
            }
            return -1;
        }
        if (lastInQueue != null) {
            return -1;
        }
        return 0;
    }
    /**
     * 命令刚到达时同步当前站点目标,降低上层重复发同一路径的概率
     */
    private void syncCurrentStationTarget(Integer taskNo, Integer currentStationId, Integer targetStationId) {
        if (currentStationId == null || targetStationId == null) {
            return;
        }
        Integer currentDeviceNo = getDeviceNoByStationId(currentStationId);
        if (currentDeviceNo == null) {
            return;
        }
        lockStations(currentStationId);
        try {
            List<ZyStationStatusEntity> statusList = deviceStatusMap.get(currentDeviceNo);
            if (statusList == null) {
                return;
            }
            ZyStationStatusEntity currentStatus = statusList.stream()
                    .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
            if (currentStatus == null) {
                return;
            }
            if (currentStatus.getTaskNo() != null && currentStatus.getTaskNo() > 0
                    && !currentStatus.getTaskNo().equals(taskNo) && currentStatus.isLoading()) {
                return;
            }
            updateStationDataInternal(currentStationId, currentDeviceNo, taskNo, targetStationId, null, null, null);
        } finally {
            unlockStations(currentStationId);
        }
    }
    /**
     * 获取是否允许检查堵塞的配置
     */
    private boolean getFakeAllowCheckBlock() {
@@ -318,6 +397,25 @@
            }
        }
        return fakeAllowCheckBlock;
    }
    private long getFakeRunBlockTimeoutMs() {
        long timeoutMs = DEFAULT_FAKE_RUN_BLOCK_TIMEOUT_MS;
        Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key);
        if (systemConfigMapObj instanceof Map) {
            Map<?, ?> systemConfigMap = (Map<?, ?>) systemConfigMapObj;
            Object value = systemConfigMap.get("fakeRunBlockTimeoutMs");
            if (value != null) {
                try {
                    long parsed = Long.parseLong(String.valueOf(value).trim());
                    if (parsed > 0) {
                        timeoutMs = parsed;
                    }
                } catch (Exception ignore) {
                }
            }
        }
        return timeoutMs;
    }
    @Override
@@ -347,6 +445,10 @@
        }
        if (command.getCommandType() == StationCommandType.WRITE_INFO) {
            if (command.getBarcode() != null) {
                updateStationBarcode(deviceNo, stationId, command.getBarcode());
                return;
            }
            if (taskNo == 9998 && targetStationId == 0) {
                // 生成出库站点仿真数据
                generateFakeOutStationData(deviceNo, stationId);
@@ -402,6 +504,23 @@
        }
    }
    private void updateStationBarcode(Integer deviceNo, Integer stationId, String barcode) {
        List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
        if (statusList == null) {
            return;
        }
        ZyStationStatusEntity status = statusList.stream()
                .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null);
        if (status == null) {
            return;
        }
        synchronized (status) {
            status.setBarcode(barcode);
        }
    }
    // segmentedPathCommand 方法已删除,功能已整合到 runTaskLoop
    private Integer getDeviceNoByStationId(Integer stationId) {