From fd837cb1e5b3f5ebfba12c29f32fe34dd4c38669 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期四, 19 三月 2026 18:38:26 +0800
Subject: [PATCH] #

---
 src/main/java/com/zy/core/network/fake/ZyStationFakeSegConnect.java |  839 ++++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 532 insertions(+), 307 deletions(-)

diff --git a/src/main/java/com/zy/core/network/fake/ZyStationFakeSegConnect.java b/src/main/java/com/zy/core/network/fake/ZyStationFakeSegConnect.java
index b5a077f..2f2c744 100644
--- a/src/main/java/com/zy/core/network/fake/ZyStationFakeSegConnect.java
+++ b/src/main/java/com/zy/core/network/fake/ZyStationFakeSegConnect.java
@@ -2,6 +2,7 @@
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.core.common.SpringUtils;
 import com.zy.asrs.entity.DeviceConfig;
 import com.zy.common.utils.RedisUtil;
 import com.zy.core.News;
@@ -11,41 +12,51 @@
 import com.zy.core.model.command.StationCommand;
 import com.zy.core.network.api.ZyStationConnectApi;
 import com.zy.core.network.entity.ZyStationStatusEntity;
+
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Random;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantLock;
-import java.util.Map;
-import java.util.Arrays;
 
 public class ZyStationFakeSegConnect implements ZyStationConnectApi {
 
-    // 绔欑偣绾ч攣锛氭瘡涓珯鐐圭嫭绔嬩竴鎶婇攣锛屾彁鍗囧苟鍙戞�ц兘
-    private final Map<Integer, ReentrantLock> stationLocks = new ConcurrentHashMap<>();
-    private HashMap<Integer, List<ZyStationStatusEntity>> deviceStatusMap = new HashMap<>();
-    private HashMap<Integer, DeviceConfig> deviceConfigMap = new HashMap<>();
-    private RedisUtil redisUtil;
-    private final Map<Integer, BlockingQueue<StationCommand>> taskQueues = new ConcurrentHashMap<>();
-    private final Map<Integer, Long> taskLastUpdateTime = new ConcurrentHashMap<>();
-    private final Map<Integer, Boolean> taskRunning = new ConcurrentHashMap<>();
+    private static final long DEFAULT_FAKE_RUN_BLOCK_TIMEOUT_MS = 10000L;
+    private static final long WAIT_SEGMENT_TIMEOUT_MS = 30000L;
+
+    private static final String STATUS_WAITING = "WAITING";
+    private static final String STATUS_RUNNING = "RUNNING";
+    private static final String STATUS_BLOCKED = "BLOCKED";
+    private static final String STATUS_CANCELLED = "CANCELLED";
+    private static final String STATUS_TIMEOUT = "TIMEOUT";
+    private static final String STATUS_FINISHED = "FINISHED";
+
+    private final Map<Integer, ReentrantLock> stationLocks = new ConcurrentHashMap<Integer, ReentrantLock>();
+    private final Map<Integer, List<ZyStationStatusEntity>> deviceStatusMap = new ConcurrentHashMap<Integer, List<ZyStationStatusEntity>>();
+    private final Map<Integer, DeviceConfig> deviceConfigMap = new ConcurrentHashMap<Integer, DeviceConfig>();
+    private final Map<Integer, BlockingQueue<StationCommand>> taskQueues = new ConcurrentHashMap<Integer, BlockingQueue<StationCommand>>();
+    private final Map<Integer, Long> taskLastUpdateTime = new ConcurrentHashMap<Integer, Long>();
+    private final Map<Integer, Boolean> taskRunning = new ConcurrentHashMap<Integer, Boolean>();
     private final ExecutorService executor = Executors.newCachedThreadPool();
+
+    private RedisUtil redisUtil;
 
     public void addFakeConnect(DeviceConfig deviceConfig, RedisUtil redisUtil) {
         this.redisUtil = redisUtil;
-
         if (deviceConfigMap.containsKey(deviceConfig.getDeviceNo())) {
             return;
         }
         deviceConfigMap.put(deviceConfig.getDeviceNo(), deviceConfig);
-        deviceStatusMap.put(deviceConfig.getDeviceNo(), new CopyOnWriteArrayList<>());
+        deviceStatusMap.put(deviceConfig.getDeviceNo(), new CopyOnWriteArrayList<ZyStationStatusEntity>());
     }
 
     @Override
@@ -63,10 +74,11 @@
     public List<ZyStationStatusEntity> getStatus(Integer deviceNo) {
         List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
         if (statusList == null) {
-            return new ArrayList<>();
+            return new ArrayList<ZyStationStatusEntity>();
         }
+
         DeviceConfig deviceConfig = deviceConfigMap.get(deviceNo);
-        if (statusList.isEmpty()) {
+        if (statusList.isEmpty() && deviceConfig != null) {
             List<ZyStationStatusEntity> init = JSON.parseArray(deviceConfig.getFakeInitStatus(),
                     ZyStationStatusEntity.class);
             if (init != null) {
@@ -96,41 +108,92 @@
             return new CommandResponse(false, "浠诲姟鍙蜂负绌�");
         }
 
-        // 澶勭悊闈炵Щ鍔ㄥ懡浠�
         if (command.getCommandType() != StationCommandType.MOVE) {
             handleCommand(deviceNo, command);
-        } else {
-            // 灏嗙Щ鍔ㄥ懡浠よ拷鍔犲埌浠诲姟闃熷垪锛堟敮鎸佸垎娈典笅鍙戯級
-            taskQueues.computeIfAbsent(taskNo, k -> new LinkedBlockingQueue<>()).offer(command);
-            taskLastUpdateTime.put(taskNo, System.currentTimeMillis());
+            return new CommandResponse(true, "鍛戒护宸插彈鐞嗭紙寮傛鎵ц锛�");
+        }
 
-            // 鍙湁浠诲姟鏈惎鍔ㄦ椂鎵嶅惎鍔ㄦ墽琛屽櫒锛屽悗缁垎娈靛懡浠や粎杩藉姞鍒伴槦鍒�
-            if (taskRunning.putIfAbsent(taskNo, true) == null) {
-                executor.submit(() -> runTaskLoop(deviceNo, taskNo));
-            }
-            // 鍚庣画鍒嗘鍛戒护涓嶅啀杩斿洖閿欒锛屾甯歌拷鍔犲埌闃熷垪
+        if (isDirectMoveCommand(command)) {
+            handleDirectMoveCommand(deviceNo, command);
+            return new CommandResponse(true, "鍛戒护宸插彈鐞嗭紙寮傛鎵ц锛�");
+        }
+
+        taskQueues.computeIfAbsent(taskNo, key -> new LinkedBlockingQueue<StationCommand>()).offer(command);
+        taskLastUpdateTime.put(taskNo, System.currentTimeMillis());
+
+        if (taskRunning.putIfAbsent(taskNo, true) == null) {
+            executor.submit(new Runnable() {
+                @Override
+                public void run() {
+                    runTaskLoop(deviceNo, taskNo);
+                }
+            });
         }
 
         return new CommandResponse(true, "鍛戒护宸插彈鐞嗭紙寮傛鎵ц锛�");
     }
 
-    private void runTaskLoop(Integer deviceNo, Integer taskNo) {
-        try {
-            // 寰呮墽琛岀殑璺緞闃熷垪锛堝瓨鍌ㄧ珯鐐笽D搴忓垪锛�
-            LinkedBlockingQueue<Integer> pendingPathQueue = new LinkedBlockingQueue<>();
-            // 褰撳墠鎵�鍦ㄧ珯鐐笽D
-            Integer currentStationId = null;
-            // 鏈�缁堢洰鏍囩珯鐐笽D
-            Integer finalTargetStationId = null;
-            // 鏄惁闇�瑕佺敓鎴愭潯鐮�
-            boolean generateBarcode = false;
-            // 鏄惁宸插垵濮嬪寲璧风偣
-            boolean initialized = false;
-            // 涓婁竴姝ユ墽琛屾椂闂达紙鐢ㄤ簬鍫靛妫�娴嬶級
-            long stepExecuteTime = System.currentTimeMillis();
+    @Override
+    public CommandResponse sendOriginCommand(String address, short[] data) {
+        return new CommandResponse(true, "鍘熷鍛戒护宸插彈鐞嗭紙寮傛鎵ц锛�");
+    }
 
+    @Override
+    public byte[] readOriginCommand(String address, int length) {
+        return new byte[0];
+    }
+
+    private boolean isDirectMoveCommand(StationCommand command) {
+        if (command == null || command.getCommandType() != StationCommandType.MOVE) {
+            return false;
+        }
+        List<Integer> path = command.getNavigatePath();
+        return (path == null || path.isEmpty()) && command.getStationId() != null
+                && command.getStationId().equals(command.getTargetStaNo());
+    }
+
+    private void handleDirectMoveCommand(Integer deviceNo, StationCommand command) {
+        Integer taskNo = command.getTaskNo();
+        Integer stationId = command.getStationId();
+        Integer targetStationId = command.getTargetStaNo();
+        if (taskNo != null && taskNo > 0 && taskNo != 9999 && taskNo != 9998 && stationId != null
+                && stationId.equals(targetStationId)) {
+            generateStationData(deviceNo, taskNo, stationId, targetStationId);
+        }
+
+        TaskRuntimeContext context = new TaskRuntimeContext(taskNo, getThreadImpl(deviceNo));
+        context.startStationId = stationId;
+        context.currentStationId = stationId;
+        context.finalTargetStationId = targetStationId;
+        context.initialized = true;
+        context.status = STATUS_RUNNING;
+        context.appendStitchedPath(Arrays.asList(stationId));
+        context.addPassedStation(stationId);
+        context.generateBarcode = checkTaskNoInArea(taskNo);
+
+        traceEvent(deviceNo, context, "MOVE_INIT", "鍚岀珯鐐逛换鍔$洿鎺ュ埌浣�", buildDetails("stationId", stationId), false);
+        if (context.generateBarcode) {
+            generateStationBarcode(taskNo, stationId, deviceNo);
+        }
+        traceEvent(deviceNo, context, "ARRIVED", "浠诲姟宸插湪璧风偣绔欑偣瀹屾垚", buildDetails("barcodeGenerated",
+                context.generateBarcode, "stationId", stationId), false);
+        context.status = STATUS_FINISHED;
+        traceEvent(deviceNo, context, "TASK_END", "浠诲姟鎵ц瀹屾垚", buildDetails("reason", STATUS_FINISHED), true);
+    }
+
+    private void runTaskLoop(Integer deviceNo, Integer taskNo) {
+        TaskRuntimeContext context = new TaskRuntimeContext(taskNo, getThreadImpl(deviceNo));
+        try {
             while (true) {
                 if (Thread.currentThread().isInterrupted()) {
+                    if (!isTerminalStatus(context.status)) {
+                        context.status = STATUS_CANCELLED;
+                    }
+                    break;
+                }
+
+                if (hasTaskReset(taskNo)) {
+                    context.status = STATUS_CANCELLED;
                     break;
                 }
 
@@ -139,166 +202,278 @@
                     break;
                 }
 
-                // 灏濊瘯鑾峰彇鏂扮殑鍒嗘鍛戒护
                 StationCommand command = commandQueue.poll(100, TimeUnit.MILLISECONDS);
                 if (command != null) {
                     taskLastUpdateTime.put(taskNo, System.currentTimeMillis());
-
-                    // 姣忔鎺ユ敹鍛戒护閮藉埛鏂扮洰鏍囷紝閬垮厤娌跨敤鏃х洰鏍囧鑷寸姸鎬佹姈鍔�
-                    Integer commandTargetStationId = command.getTargetStaNo();
-                    if (commandTargetStationId != null) {
-                        if (!commandTargetStationId.equals(finalTargetStationId)) {
-                            News.info("[WCS Debug] 浠诲姟{}鍒囨崲鐩爣: {} -> {}", taskNo, finalTargetStationId,
-                                    commandTargetStationId);
-                        }
-                        finalTargetStationId = commandTargetStationId;
-                        // 褰撳墠绔欑偣鍏堝悓姝ユ渶鏂扮洰鏍囷紝閬垮厤涓婂眰鍦ㄧ獥鍙f湡閲嶅涓嬪彂鍚屼竴璺緞
-                        syncCurrentStationTarget(taskNo, currentStationId, finalTargetStationId);
-                    }
-
-                    if (!generateBarcode && checkTaskNoInArea(taskNo)) {
-                        generateBarcode = true;
-                    }
-
-                    // 灏嗘柊璺緞杩藉姞鍒板緟鎵ц闃熷垪
-                    List<Integer> newPath = command.getNavigatePath();
-                    if (newPath != null && !newPath.isEmpty()) {
-                        // 鑾峰彇闃熷垪涓渶鍚庝竴涓珯鐐癸紙鐢ㄤ簬琛旀帴鐐瑰幓閲嶏級
-                        Integer lastInQueue = getLastInQueue(pendingPathQueue);
-                        int startIndex = getPathAppendStartIndex(newPath, currentStationId, lastInQueue);
-
-                        for (int i = startIndex; i < newPath.size(); i++) {
-                            pendingPathQueue.offer(newPath.get(i));
-                        }
-
-                        News.info("[WCS Debug] 浠诲姟{}杩藉姞璺緞娈�: {} -> 闃熷垪澶у皬: {}", taskNo, newPath, pendingPathQueue.size());
-                    }
+                    context.lastCommandAt = System.currentTimeMillis();
+                    handleIncomingSegment(deviceNo, context, command);
                 }
 
-                // 鎵ц绉诲姩閫昏緫
-                if (!pendingPathQueue.isEmpty()) {
-                    Integer nextStationId = pendingPathQueue.peek();
-
-                    // 濡傛灉灏氭湭鍒濆鍖栬捣鐐�
-                    if (!initialized && currentStationId == null) {
-                        // 浼樺厛鏌ユ壘鎵樼洏褰撳墠瀹為檯浣嶇疆锛堟敮鎸佸牭濉炲悗閲嶈矾鐢卞満鏅級
-                        Integer actualCurrentStationId = findCurrentStationIdByTask(taskNo);
-                        if (actualCurrentStationId != null) {
-                            // 鎵惧埌浜嗗綋鍓嶆墭鐩樹綅缃紝浣跨敤瀹為檯浣嶇疆浣滀负璧风偣
-                            currentStationId = actualCurrentStationId;
-                            initialized = true;
-
-                            // 娓呴櫎璇ョ珯鐐圭殑 runBlock 鏍囪锛堝牭濉炴仮澶嶏級
-                            Integer deviceId = getDeviceNoByStationId(currentStationId);
-                            if (deviceId != null) {
-                                clearRunBlock(currentStationId, deviceId);
-                            }
-
-                            // 濡傛灉璺緞璧风偣涓庡綋鍓嶄綅缃浉鍚岋紝绉婚櫎璧风偣閬垮厤閲嶅
-                            if (nextStationId.equals(currentStationId)) {
-                                pendingPathQueue.poll();
-                            }
-
-                            stepExecuteTime = System.currentTimeMillis();
-                            News.info("[WCS Debug] 浠诲姟{}鎭㈠鎵ц锛屽綋鍓嶄綅缃�: {}", taskNo, currentStationId);
-                            continue;
-                        }
-
-                        // 鏈壘鍒板綋鍓嶄綅缃紙棣栨鎵ц锛夛紝棣栦釜绔欑偣灏辨槸璧风偣
-                        currentStationId = nextStationId;
-                        Integer deviceId = getDeviceNoByStationId(currentStationId);
-                        if (deviceId != null) {
-                            boolean result = initStationMove(taskNo, currentStationId, deviceId, taskNo,
-                                    finalTargetStationId, true, null);
-                            if (result) {
-                                initialized = true;
-                                pendingPathQueue.poll(); // 绉婚櫎璧风偣
-                                stepExecuteTime = System.currentTimeMillis();
-                                News.info("[WCS Debug] 浠诲姟{}鍒濆鍖栬捣鐐�: {}", taskNo, currentStationId);
-                            }
-                        }
-                        sleep(500);
+                if (!context.pendingPathQueue.isEmpty()) {
+                    if (!context.initialized || context.currentStationId == null) {
+                        initializeTaskPosition(deviceNo, context);
                         continue;
                     }
 
-                    // 鎵ц浠庡綋鍓嶇珯鐐瑰埌涓嬩竴绔欑偣鐨勭Щ鍔�
-                    Integer currentDeviceNo = getDeviceNoByStationId(currentStationId);
-                    Integer nextDeviceNo = getDeviceNoByStationId(nextStationId);
-
-                    if (currentDeviceNo != null && nextDeviceNo != null) {
-                        boolean moveSuccess = stationMoveToNext(taskNo, currentStationId, currentDeviceNo,
-                                nextStationId, nextDeviceNo, taskNo, finalTargetStationId);
-                        if (moveSuccess) {
-                            currentStationId = nextStationId;
-                            pendingPathQueue.poll();
-                            stepExecuteTime = System.currentTimeMillis();
-                            News.info("[WCS Debug] 浠诲姟{}绉诲姩鍒扮珯鐐�: {}, 鍓╀綑闃熷垪: {}", taskNo, currentStationId,
-                                    pendingPathQueue.size());
-                            sleep(1000); // 妯℃嫙绉诲姩鑰楁椂
-                        } else {
-                            // 绉诲姩澶辫触锛屾鏌ユ槸鍚﹀牭濉�
-                            if (!checkTaskNoInArea(taskNo)) {
-                                boolean fakeAllowCheckBlock = getFakeAllowCheckBlock();
-
-                                if (fakeAllowCheckBlock && System.currentTimeMillis() - stepExecuteTime > 10000) {
-                                    // 璁ゅ畾鍫靛
-                                    boolean result = runBlockStation(taskNo, currentStationId, currentDeviceNo, taskNo,
-                                            currentStationId);
-                                    if (result) {
-                                        News.info("[WCS Debug] 浠诲姟{}鍦ㄧ珯鐐箋}琚爣璁颁负鍫靛", taskNo, currentStationId);
-                                        pendingPathQueue.clear();
-                                        break;
-                                    }
-                                }
-                            }
-                            sleep(500); // 澶辫触閲嶈瘯绛夊緟
-                        }
-                    } else {
-                        // 鏃犳硶鑾峰彇璁惧鍙凤紝璺宠繃璇ョ珯鐐�
-                        pendingPathQueue.poll();
-                    }
-                } else {
-                    // 璺緞闃熷垪涓虹┖锛岀瓑寰呮柊鐨勫垎娈靛懡浠�
-                    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);
-                            }
-                        }
-                        commandQueue.clear();
-                        pendingPathQueue.clear();
-                        News.info("[WCS Debug] 浠诲姟{}鍒拌揪鐩爣鍚庢竻绌洪槦鍒楀苟缁撴潫锛岀瓑寰呭悗缁柊鍛戒护閲嶅惎", taskNo);
+                    if (!executeNextMove(deviceNo, context)) {
                         break;
                     }
+                    continue;
+                }
 
-                    // 缁х画绛夊緟鏂扮殑鍒嗘鍛戒护
-                    Long lastTime = taskLastUpdateTime.get(taskNo);
-                    if (lastTime != null && System.currentTimeMillis() - lastTime > 30000) {
-                        // 瓒呮椂锛�30绉掑唴娌℃湁鏀跺埌鏂板垎娈靛懡浠�
-                        News.info("[WCS Debug] 浠诲姟{}绛夊緟鍒嗘瓒呮椂锛屽綋鍓嶄綅缃�: {}, 鐩爣: {}", taskNo, currentStationId,
-                                finalTargetStationId);
-                        break;
-                    }
-                    // 缁х画绛夊緟鏂板垎娈靛懡浠わ紙涓嶅仛浠讳綍浜嬫儏锛屼笅涓�杞惊鐜細灏濊瘯鑾峰彇鏂板懡浠わ級
+                if (handleIdleState(deviceNo, context)) {
+                    break;
                 }
             }
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
+            if (!isTerminalStatus(context.status)) {
+                context.status = STATUS_CANCELLED;
+            }
         } finally {
             taskQueues.remove(taskNo);
             taskLastUpdateTime.remove(taskNo);
             taskRunning.remove(taskNo);
-            News.info("[WCS Debug] 浠诲姟{}鎵ц缁撴潫骞舵竻鐞嗚祫婧�", taskNo);
+
+            if (!isTerminalStatus(context.status)) {
+                context.status = STATUS_FINISHED;
+            }
+            traceEvent(deviceNo, context, "TASK_END", "浠诲姟鎵ц缁撴潫骞舵竻鐞嗚祫婧�",
+                    buildDetails("reason", context.status), true);
+            News.info("[WCS Debug] 浠诲姟{}鎵ц缁撴潫骞舵竻鐞嗚祫婧愶紝鐘舵��={}", taskNo, context.status);
         }
     }
 
-    /**
-     * 鑾峰彇闃熷垪涓渶鍚庝竴涓厓绱狅紙涓嶇Щ闄わ級
-     */
+    private void handleIncomingSegment(Integer deviceNo, TaskRuntimeContext context, StationCommand command) {
+        List<Integer> newPath = normalizePath(command.getNavigatePath());
+        Integer lastInQueue = getLastInQueue(context.pendingPathQueue);
+        int startIndex = getPathAppendStartIndex(newPath, context.currentStationId, lastInQueue);
+
+        context.setStartStationIdIfAbsent(command.getStationId());
+        if (!context.generateBarcode && checkTaskNoInArea(context.taskNo)) {
+            context.generateBarcode = true;
+        }
+
+        traceEvent(deviceNo, context, "SEGMENT_RECEIVED", "鏀跺埌鏂扮殑璺緞鍒嗘鍛戒护",
+                buildDetails("segmentPath", newPath, "appendStartIndex", startIndex, "currentStationId",
+                        context.currentStationId, "queueTailStationId", lastInQueue, "commandStationId",
+                        command.getStationId(), "commandTargetStationId", command.getTargetStaNo()),
+                false);
+
+        Integer commandTargetStationId = command.getTargetStaNo();
+        if (commandTargetStationId != null) {
+            if (!commandTargetStationId.equals(context.finalTargetStationId)) {
+                traceEvent(deviceNo, context, "TARGET_SWITCHED",
+                        "浠诲姟鐩爣绔欏彂鐢熷垏鎹�: " + context.finalTargetStationId + " -> " + commandTargetStationId,
+                        buildDetails("fromTargetStationId", context.finalTargetStationId, "toTargetStationId",
+                                commandTargetStationId),
+                        false);
+                context.arrivalHandled = false;
+            }
+            context.finalTargetStationId = commandTargetStationId;
+            syncCurrentStationTarget(context.taskNo, context.currentStationId, context.finalTargetStationId);
+        }
+
+        if (!newPath.isEmpty() && startIndex < 0) {
+            traceEvent(deviceNo, context, "SEGMENT_IGNORED", "璺緞鍒嗘鏃犳硶涓庡綋鍓嶈繍琛屼笂涓嬫枃琛旀帴锛屽凡蹇界暐",
+                    buildDetails("segmentPath", newPath, "currentStationId", context.currentStationId,
+                            "queueTailStationId", lastInQueue, "ignoreReason", "PATH_NOT_CONNECTED"),
+                    false);
+            context.latestAppendedPath.clear();
+            return;
+        }
+
+        List<Integer> appendedPath = new ArrayList<Integer>();
+        for (int i = startIndex; i < newPath.size(); i++) {
+            Integer stationId = newPath.get(i);
+            context.pendingPathQueue.offer(stationId);
+            appendedPath.add(stationId);
+        }
+        context.appendStitchedPath(appendedPath);
+
+        if (!appendedPath.isEmpty()) {
+            traceEvent(deviceNo, context, "SEGMENT_APPENDED",
+                    "璺緞鍒嗘宸茶拷鍔犲埌寰呮墽琛岄槦鍒楋紝闃熷垪闀垮害=" + context.pendingPathQueue.size(),
+                    buildDetails("segmentPath", newPath, "appendedPath", appendedPath, "appendStartIndex",
+                            startIndex, "queueSize", context.pendingPathQueue.size()),
+                    false);
+        }
+    }
+
+    private void initializeTaskPosition(Integer deviceNo, TaskRuntimeContext context) {
+        Integer nextStationId = context.pendingPathQueue.peek();
+        if (nextStationId == null) {
+            return;
+        }
+
+        if (context.currentStationId == null) {
+            Integer actualCurrentStationId = findCurrentStationIdByTask(context.taskNo);
+            if (actualCurrentStationId != null) {
+                context.currentStationId = actualCurrentStationId;
+                context.initialized = true;
+                context.status = STATUS_RUNNING;
+                context.blockedStationId = null;
+
+                Integer actualDeviceNo = getDeviceNoByStationId(actualCurrentStationId);
+                if (actualDeviceNo != null) {
+                    clearRunBlock(actualCurrentStationId, actualDeviceNo);
+                }
+
+                trimPendingPathToCurrent(context.pendingPathQueue, actualCurrentStationId);
+                if (actualCurrentStationId.equals(context.pendingPathQueue.peek())) {
+                    context.pendingPathQueue.poll();
+                }
+
+                context.addPassedStation(actualCurrentStationId);
+                context.lastStepAt = System.currentTimeMillis();
+                traceEvent(deviceNo, context, "MOVE_INIT", "浠诲姟浠庡綋鍓嶅疄闄呯珯鐐规仮澶嶆墽琛�",
+                        buildDetails("stationId", actualCurrentStationId, "recovered", true), false);
+                return;
+            }
+        }
+
+        context.currentStationId = nextStationId;
+        Integer currentDeviceNo = getDeviceNoByStationId(context.currentStationId);
+        if (currentDeviceNo == null) {
+            context.pendingPathQueue.poll();
+            return;
+        }
+
+        boolean result = initStationMove(context.taskNo, context.currentStationId, currentDeviceNo, context.taskNo,
+                context.finalTargetStationId, true, null);
+        if (!result) {
+            sleep(200);
+            return;
+        }
+
+        context.initialized = true;
+        context.status = STATUS_RUNNING;
+        context.pendingPathQueue.poll();
+        context.addPassedStation(context.currentStationId);
+        context.lastStepAt = System.currentTimeMillis();
+        traceEvent(deviceNo, context, "MOVE_INIT", "浠诲姟鍒濆鍖栬捣鐐圭珯鐐�",
+                buildDetails("stationId", context.currentStationId, "recovered", false), false);
+        sleep(500);
+    }
+
+    private boolean executeNextMove(Integer deviceNo, TaskRuntimeContext context) {
+        Integer nextStationId = context.pendingPathQueue.peek();
+        if (nextStationId == null || context.currentStationId == null) {
+            return true;
+        }
+
+        Integer currentDeviceNo = getDeviceNoByStationId(context.currentStationId);
+        Integer nextDeviceNo = getDeviceNoByStationId(nextStationId);
+        if (currentDeviceNo == null || nextDeviceNo == null) {
+            context.pendingPathQueue.poll();
+            return true;
+        }
+
+        boolean moveSuccess = stationMoveToNext(context.taskNo, context.currentStationId, currentDeviceNo,
+                nextStationId, nextDeviceNo, context.taskNo, context.finalTargetStationId);
+        if (moveSuccess) {
+            Integer previousStationId = context.currentStationId;
+            context.currentStationId = nextStationId;
+            context.pendingPathQueue.poll();
+            context.addPassedStation(nextStationId);
+            context.arrivalHandled = false;
+            context.blockedStationId = null;
+            context.status = STATUS_RUNNING;
+            context.lastStepAt = System.currentTimeMillis();
+            traceEvent(deviceNo, context, "MOVE_STEP_OK", "浠诲姟瀹屾垚涓�姝ョ珯鐐圭Щ鍔�",
+                    buildDetails("fromStationId", previousStationId, "toStationId", nextStationId,
+                            "remainingPendingPath", context.getPendingStationIds()),
+                    false);
+            sleep(1000);
+            return true;
+        }
+
+        if (!checkTaskNoInArea(context.taskNo) && getFakeAllowCheckBlock()
+                && System.currentTimeMillis() - context.lastStepAt > getFakeRunBlockTimeoutMs()) {
+            boolean blocked = runBlockStation(context.taskNo, context.currentStationId, currentDeviceNo, context.taskNo,
+                    context.currentStationId);
+            if (blocked) {
+                context.blockedStationId = context.currentStationId;
+                context.status = STATUS_BLOCKED;
+                context.pendingPathQueue.clear();
+                traceEvent(deviceNo, context, "RUN_BLOCKED", "浠诲姟鍦ㄥ綋鍓嶇珯鐐硅鏍囪涓哄牭濉�",
+                        buildDetails("blockedStationId", context.currentStationId), false);
+                return false;
+            }
+        }
+
+        sleep(500);
+        return true;
+    }
+
+    private boolean handleIdleState(Integer deviceNo, TaskRuntimeContext context) {
+        if (context.currentStationId != null && context.finalTargetStationId != null
+                && context.currentStationId.equals(context.finalTargetStationId)) {
+            if (!context.arrivalHandled) {
+                boolean barcodeGenerated = false;
+                if (context.generateBarcode) {
+                    Integer targetDeviceNo = getDeviceNoByStationId(context.finalTargetStationId);
+                    if (targetDeviceNo != null) {
+                        barcodeGenerated = generateStationBarcode(context.taskNo, context.finalTargetStationId,
+                                targetDeviceNo);
+                    }
+                }
+                context.arrivalHandled = true;
+                traceEvent(deviceNo, context, "ARRIVED", "浠诲姟鍒拌揪鏈�缁堢洰鏍囩珯鐐�",
+                        buildDetails("stationId", context.currentStationId, "barcodeGenerated", barcodeGenerated),
+                        false);
+            }
+            context.status = STATUS_FINISHED;
+            return true;
+        }
+
+        Long lastTime = taskLastUpdateTime.get(context.taskNo);
+        if (lastTime != null && System.currentTimeMillis() - lastTime > WAIT_SEGMENT_TIMEOUT_MS) {
+            context.status = STATUS_TIMEOUT;
+            traceEvent(deviceNo, context, "WAIT_TIMEOUT", "绛夊緟鏂扮殑璺緞鍒嗘瓒呮椂",
+                    buildDetails("timeoutMs", WAIT_SEGMENT_TIMEOUT_MS, "currentStationId", context.currentStationId,
+                            "targetStationId", context.finalTargetStationId),
+                    false);
+            return true;
+        }
+        return false;
+    }
+
+    private List<Integer> normalizePath(List<Integer> path) {
+        List<Integer> result = new ArrayList<Integer>();
+        if (path == null) {
+            return result;
+        }
+        for (Integer stationId : path) {
+            if (stationId != null) {
+                result.add(stationId);
+            }
+        }
+        return result;
+    }
+
+    private void trimPendingPathToCurrent(LinkedBlockingQueue<Integer> queue, Integer currentStationId) {
+        if (queue == null || currentStationId == null || queue.isEmpty()) {
+            return;
+        }
+        List<Integer> snapshot = new ArrayList<Integer>(queue);
+        int index = snapshot.indexOf(currentStationId);
+        if (index <= 0) {
+            return;
+        }
+        for (int i = 0; i < index; i++) {
+            queue.poll();
+        }
+    }
+
+    private boolean hasTaskReset(Integer taskNo) {
+        if (redisUtil == null || taskNo == null) {
+            return false;
+        }
+        Object cancel = redisUtil.get(RedisKeyType.DEVICE_STATION_MOVE_RESET.key + taskNo);
+        return cancel != null;
+    }
+
     private Integer getLastInQueue(LinkedBlockingQueue<Integer> queue) {
         Integer last = null;
         for (Integer item : queue) {
@@ -307,9 +482,6 @@
         return last;
     }
 
-    /**
-     * 璁$畻鏂拌矾寰勫湪闃熷垪涓殑杩藉姞璧风偣锛岄伩鍏嶉噸澶嶄笅鍙戝鑷磋矾寰勬潵鍥炶烦
-     */
     private int getPathAppendStartIndex(List<Integer> newPath, Integer currentStationId, Integer lastInQueue) {
         if (newPath == null || newPath.isEmpty()) {
             return 0;
@@ -327,14 +499,16 @@
             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;
@@ -368,30 +542,37 @@
         }
     }
 
-    /**
-     * 鑾峰彇鏄惁鍏佽妫�鏌ュ牭濉炵殑閰嶇疆
-     */
+    @SuppressWarnings("unchecked")
     private boolean getFakeAllowCheckBlock() {
         boolean fakeAllowCheckBlock = true;
-        Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key);
-        if (systemConfigMapObj != null) {
-            HashMap<String, String> systemConfigMap = (HashMap<String, String>) systemConfigMapObj;
+        Object systemConfigMapObj = redisUtil == null ? null : redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key);
+        if (systemConfigMapObj instanceof Map) {
+            Map<String, String> systemConfigMap = (Map<String, String>) systemConfigMapObj;
             String value = systemConfigMap.get("fakeAllowCheckBlock");
-            if (value != null && !value.equals("Y")) {
+            if (value != null && !"Y".equals(value)) {
                 fakeAllowCheckBlock = false;
             }
         }
         return fakeAllowCheckBlock;
     }
 
-    @Override
-    public CommandResponse sendOriginCommand(String address, short[] data) {
-        return new CommandResponse(true, "鍘熷鍛戒护宸插彈鐞嗭紙寮傛鎵ц锛�");
-    }
-
-    @Override
-    public byte[] readOriginCommand(String address, int length) {
-        return new byte[0];
+    private long getFakeRunBlockTimeoutMs() {
+        long timeoutMs = DEFAULT_FAKE_RUN_BLOCK_TIMEOUT_MS;
+        Object systemConfigMapObj = redisUtil == null ? null : 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;
     }
 
     private void handleCommand(Integer deviceNo, StationCommand command) {
@@ -399,15 +580,10 @@
         Integer taskNo = command.getTaskNo();
         Integer stationId = command.getStationId();
         Integer targetStationId = command.getTargetStaNo();
-        boolean generateBarcode = false;
 
         if (command.getCommandType() == StationCommandType.RESET) {
             resetStation(deviceNo, stationId);
             return;
-        }
-
-        if (checkTaskNoInArea(taskNo)) {
-            generateBarcode = true;
         }
 
         if (command.getCommandType() == StationCommandType.WRITE_INFO) {
@@ -416,26 +592,27 @@
                 return;
             }
             if (taskNo == 9998 && targetStationId == 0) {
-                // 鐢熸垚鍑哄簱绔欑偣浠跨湡鏁版嵁
                 generateFakeOutStationData(deviceNo, stationId);
                 return;
             }
         }
 
-        if (taskNo > 0 && taskNo != 9999 && taskNo != 9998 && stationId == targetStationId) {
+        if (taskNo != null && taskNo > 0 && taskNo != 9999 && taskNo != 9998 && stationId != null
+                && stationId.equals(targetStationId)) {
             generateStationData(deviceNo, taskNo, stationId, targetStationId);
         }
-        // 娉ㄦ剰锛歁OVE 绫诲瀷鐨勫懡浠ょ幇宸插湪 sendCommand 涓鐞嗭紝handleCommand 浠呭鐞嗛潪 MOVE 鍛戒护
     }
 
     private void generateFakeOutStationData(Integer deviceNo, Integer stationId) {
         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.setLoading(true);
         }
@@ -443,12 +620,14 @@
 
     private void generateStationData(Integer deviceNo, Integer taskNo, Integer stationId, Integer targetStationId) {
         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.setTaskNo(taskNo);
             status.setTargetStaNo(targetStationId);
@@ -457,12 +636,14 @@
 
     private void resetStation(Integer deviceNo, Integer stationId) {
         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.setTaskNo(0);
             status.setLoading(false);
@@ -475,29 +656,25 @@
         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) {
-        for (Integer devNo : deviceStatusMap.keySet()) {
-            List<ZyStationStatusEntity> list = deviceStatusMap.get(devNo);
+        for (Map.Entry<Integer, List<ZyStationStatusEntity>> entry : deviceStatusMap.entrySet()) {
+            List<ZyStationStatusEntity> list = entry.getValue();
             if (list == null) {
                 continue;
             }
-            for (ZyStationStatusEntity e : list) {
-                if (e.getStationId() != null && e.getStationId().equals(stationId)) {
-                    return devNo;
+            for (ZyStationStatusEntity entity : list) {
+                if (entity.getStationId() != null && entity.getStationId().equals(stationId)) {
+                    return entry.getKey();
                 }
             }
         }
@@ -505,21 +682,18 @@
     }
 
     private Integer findCurrentStationIdByTask(Integer taskNo) {
-        for (Integer devNo : deviceStatusMap.keySet()) {
-            List<ZyStationStatusEntity> list = deviceStatusMap.get(devNo);
+        for (List<ZyStationStatusEntity> list : deviceStatusMap.values()) {
             if (list == null) {
                 continue;
             }
-            for (ZyStationStatusEntity e : list) {
-                if (e.getTaskNo() != null && e.getTaskNo().equals(taskNo) && e.isLoading()) {
-                    return e.getStationId();
+            for (ZyStationStatusEntity entity : list) {
+                if (entity.getTaskNo() != null && entity.getTaskNo().equals(taskNo) && entity.isLoading()) {
+                    return entity.getStationId();
                 }
             }
         }
         return null;
     }
-
-    // stationMoveByPathIds 鏂规硶宸插垹闄わ紝鍔熻兘宸叉暣鍚堝埌 runTaskLoop
 
     private void sleep(long ms) {
         try {
@@ -529,16 +703,10 @@
         }
     }
 
-    /**
-     * 鑾峰彇绔欑偣閿侊紝濡傛灉涓嶅瓨鍦ㄥ垯鍒涘缓
-     */
     private ReentrantLock getStationLock(Integer stationId) {
-        return stationLocks.computeIfAbsent(stationId, k -> new ReentrantLock());
+        return stationLocks.computeIfAbsent(stationId, key -> new ReentrantLock());
     }
 
-    /**
-     * 鎸夐『搴忛攣瀹氬涓珯鐐癸紙閬垮厤姝婚攣锛�
-     */
     private void lockStations(Integer... stationIds) {
         Integer[] sorted = Arrays.copyOf(stationIds, stationIds.length);
         Arrays.sort(sorted);
@@ -547,9 +715,6 @@
         }
     }
 
-    /**
-     * 鎸夐�嗗簭瑙i攣澶氫釜绔欑偣
-     */
     private void unlockStations(Integer... stationIds) {
         Integer[] sorted = Arrays.copyOf(stationIds, stationIds.length);
         Arrays.sort(sorted);
@@ -558,19 +723,14 @@
         }
     }
 
-    /**
-     * 鏇存柊绔欑偣鏁版嵁锛堣皟鐢ㄥ墠蹇呴』宸叉寔鏈夎绔欑偣鐨勯攣锛�
-     */
     private boolean updateStationDataInternal(Integer stationId, Integer deviceNo, Integer taskNo, Integer targetStaNo,
             Boolean isLoading, String barcode, Boolean runBlock) {
         List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
         if (statusList == null) {
             return false;
         }
-
         ZyStationStatusEntity currentStatus = statusList.stream()
                 .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null);
-
         if (currentStatus == null) {
             return false;
         }
@@ -578,28 +738,21 @@
         if (taskNo != null) {
             currentStatus.setTaskNo(taskNo);
         }
-
         if (targetStaNo != null) {
             currentStatus.setTargetStaNo(targetStaNo);
         }
-
         if (isLoading != null) {
             currentStatus.setLoading(isLoading);
         }
-
         if (barcode != null) {
             currentStatus.setBarcode(barcode);
         }
-
         if (runBlock != null) {
             currentStatus.setRunBlock(runBlock);
         }
         return true;
     }
 
-    /**
-     * 鍒濆鍖栫珯鐐圭Щ鍔紙浣跨敤绔欑偣绾ч攣锛�
-     */
     public boolean initStationMove(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo,
             Integer taskNo, Integer targetStationId, Boolean isLoading, String barcode) {
         lockStations(currentStationId);
@@ -608,18 +761,14 @@
             if (statusList == null) {
                 return false;
             }
-
             ZyStationStatusEntity currentStatus = statusList.stream()
                     .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
-
             if (currentStatus == null) {
                 return false;
             }
-
-            if (currentStatus.getTaskNo() > 0) {
-                if (!currentStatus.getTaskNo().equals(taskNo) && currentStatus.isLoading()) {
-                    return false;
-                }
+            if (currentStatus.getTaskNo() != null && currentStatus.getTaskNo() > 0
+                    && !currentStatus.getTaskNo().equals(taskNo) && currentStatus.isLoading()) {
+                return false;
             }
 
             return updateStationDataInternal(currentStationId, currentStationDeviceNo, taskNo, targetStationId,
@@ -629,35 +778,24 @@
         }
     }
 
-    /**
-     * 绔欑偣绉诲姩鍒颁笅涓�涓綅缃紙浣跨敤绔欑偣绾ч攣锛屾寜ID椤哄簭鑾峰彇閿侀伩鍏嶆閿侊級
-     */
     public boolean stationMoveToNext(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo,
             Integer nextStationId, Integer nextStationDeviceNo, Integer taskNo, Integer targetStaNo) {
-        // 鍚屾椂閿佸畾褰撳墠绔欑偣鍜屼笅涓�涓珯鐐癸紙鎸塈D椤哄簭锛岄伩鍏嶆閿侊級
         lockStations(currentStationId, nextStationId);
         try {
             List<ZyStationStatusEntity> statusList = deviceStatusMap.get(currentStationDeviceNo);
-            if (statusList == null) {
-                return false;
-            }
-
             List<ZyStationStatusEntity> nextStatusList = deviceStatusMap.get(nextStationDeviceNo);
-            if (nextStatusList == null) {
+            if (statusList == null || nextStatusList == null) {
                 return false;
             }
 
             ZyStationStatusEntity currentStatus = statusList.stream()
                     .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
-
             ZyStationStatusEntity nextStatus = nextStatusList.stream()
                     .filter(item -> item.getStationId().equals(nextStationId)).findFirst().orElse(null);
-
             if (currentStatus == null || nextStatus == null) {
                 return false;
             }
-
-            if (nextStatus.getTaskNo() > 0 || nextStatus.isLoading()) {
+            if (nextStatus.getTaskNo() != null && nextStatus.getTaskNo() > 0 || nextStatus.isLoading()) {
                 return false;
             }
 
@@ -666,53 +804,35 @@
             if (!result) {
                 return false;
             }
-
-            boolean result2 = updateStationDataInternal(currentStationId, currentStationDeviceNo, 0, 0, false, "",
-                    false);
-            if (!result2) {
-                return false;
-            }
-
-            return true;
+            return updateStationDataInternal(currentStationId, currentStationDeviceNo, 0, 0, false, "", false);
         } finally {
             unlockStations(currentStationId, nextStationId);
         }
     }
 
-    /**
-     * 鐢熸垚绔欑偣鏉$爜锛堜娇鐢ㄧ珯鐐圭骇閿侊級
-     */
-    public boolean generateStationBarcode(Integer lockTaskNo, Integer currentStationId,
-            Integer currentStationDeviceNo) {
+    public boolean generateStationBarcode(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo) {
         lockStations(currentStationId);
         try {
             List<ZyStationStatusEntity> statusList = deviceStatusMap.get(currentStationDeviceNo);
             if (statusList == null) {
                 return false;
             }
-
             ZyStationStatusEntity currentStatus = statusList.stream()
                     .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
-
             if (currentStatus == null) {
                 return false;
             }
 
             Random random = new Random();
-
             String barcodeTime = String.valueOf(System.currentTimeMillis());
             String barcode = String.valueOf(random.nextInt(10)) + String.valueOf(random.nextInt(10))
                     + barcodeTime.substring(7);
-
             return updateStationDataInternal(currentStationId, currentStationDeviceNo, null, null, null, barcode, null);
         } finally {
             unlockStations(currentStationId);
         }
     }
 
-    /**
-     * 娓呴櫎绔欑偣鏁版嵁锛堜娇鐢ㄧ珯鐐圭骇閿侊級
-     */
     public boolean clearStation(Integer deviceNo, Integer lockTaskNo, Integer currentStationId) {
         lockStations(currentStationId);
         try {
@@ -720,23 +840,17 @@
             if (statusList == null) {
                 return false;
             }
-
             ZyStationStatusEntity currentStatus = statusList.stream()
                     .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
-
             if (currentStatus == null) {
                 return false;
             }
-
             return updateStationDataInternal(currentStationId, deviceNo, 0, 0, false, "", false);
         } finally {
             unlockStations(currentStationId);
         }
     }
 
-    /**
-     * 鏍囪绔欑偣鍫靛锛堜娇鐢ㄧ珯鐐圭骇閿侊級
-     */
     public boolean runBlockStation(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo,
             Integer taskNo, Integer blockStationId) {
         lockStations(currentStationId);
@@ -745,14 +859,11 @@
             if (statusList == null) {
                 return false;
             }
-
             ZyStationStatusEntity currentStatus = statusList.stream()
                     .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
-
             if (currentStatus == null) {
                 return false;
             }
-
             return updateStationDataInternal(currentStationId, currentStationDeviceNo, taskNo, blockStationId, true, "",
                     true);
         } finally {
@@ -760,9 +871,6 @@
         }
     }
 
-    /**
-     * 娓呴櫎绔欑偣鍫靛鏍囪锛堝牭濉炴仮澶嶆椂浣跨敤锛�
-     */
     public void clearRunBlock(Integer stationId, Integer deviceNo) {
         lockStations(stationId);
         try {
@@ -770,14 +878,11 @@
             if (statusList == null) {
                 return;
             }
-
             ZyStationStatusEntity currentStatus = statusList.stream()
                     .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null);
-
             if (currentStatus == null) {
                 return;
             }
-
             if (currentStatus.isRunBlock()) {
                 currentStatus.setRunBlock(false);
                 News.info("[WCS Debug] 绔欑偣{}鍫靛鏍囪宸叉竻闄�", stationId);
@@ -788,6 +893,10 @@
     }
 
     private boolean checkTaskNoInArea(Integer taskNo) {
+        if (taskNo == null || redisUtil == null) {
+            return false;
+        }
+
         Object fakeTaskNoAreaObj = redisUtil.get(RedisKeyType.FAKE_TASK_NO_AREA.key);
         if (fakeTaskNoAreaObj == null) {
             return false;
@@ -796,11 +905,127 @@
         JSONObject data = JSON.parseObject(String.valueOf(fakeTaskNoAreaObj));
         Integer start = data.getInteger("start");
         Integer end = data.getInteger("end");
+        if (start == null || end == null) {
+            return false;
+        }
+        return taskNo >= start && taskNo <= end;
+    }
 
-        if (taskNo >= start && taskNo <= end) {
-            return true;
+    private Map<String, Object> buildDetails(Object... keyValues) {
+        Map<String, Object> details = new LinkedHashMap<String, Object>();
+        if (keyValues == null) {
+            return details;
+        }
+        for (int i = 0; i + 1 < keyValues.length; i += 2) {
+            Object key = keyValues[i];
+            if (key != null) {
+                details.put(String.valueOf(key), keyValues[i + 1]);
+            }
+        }
+        return details;
+    }
+
+    private void traceEvent(Integer deviceNo, TaskRuntimeContext context, String eventType, String message,
+            Map<String, Object> details, boolean terminal) {
+        if (context == null || context.taskNo == null) {
+            return;
+        }
+        try {
+            FakeTaskTraceRegistry registry = SpringUtils.getBean(FakeTaskTraceRegistry.class);
+            if (registry == null) {
+                return;
+            }
+            registry.record(context.taskNo, context.threadImpl != null ? context.threadImpl : getThreadImpl(deviceNo),
+                    context.status, context.startStationId, context.currentStationId, context.finalTargetStationId,
+                    context.blockedStationId, context.getStitchedPathStationIds(), context.getPassedStationIds(),
+                    context.getPendingStationIds(), context.getLatestAppendedPath(), eventType, message, details,
+                    terminal);
+        } catch (Exception ignore) {
+        }
+    }
+
+    private String getThreadImpl(Integer deviceNo) {
+        DeviceConfig deviceConfig = deviceConfigMap.get(deviceNo);
+        return deviceConfig == null ? "" : deviceConfig.getThreadImpl();
+    }
+
+    private boolean isTerminalStatus(String status) {
+        return STATUS_BLOCKED.equals(status) || STATUS_CANCELLED.equals(status) || STATUS_TIMEOUT.equals(status)
+                || STATUS_FINISHED.equals(status);
+    }
+
+    private static class TaskRuntimeContext {
+
+        private final Integer taskNo;
+        private final String threadImpl;
+        private final LinkedBlockingQueue<Integer> pendingPathQueue = new LinkedBlockingQueue<Integer>();
+        private final List<Integer> stitchedPathStationIds = new ArrayList<Integer>();
+        private final List<Integer> passedStationIds = new ArrayList<Integer>();
+        private final List<Integer> latestAppendedPath = new ArrayList<Integer>();
+
+        private Integer startStationId;
+        private Integer currentStationId;
+        private Integer finalTargetStationId;
+        private Integer blockedStationId;
+        private boolean generateBarcode;
+        private boolean initialized;
+        private boolean arrivalHandled;
+        private long lastStepAt = System.currentTimeMillis();
+        private long lastCommandAt = System.currentTimeMillis();
+        private String status = STATUS_WAITING;
+
+        private TaskRuntimeContext(Integer taskNo, String threadImpl) {
+            this.taskNo = taskNo;
+            this.threadImpl = threadImpl;
         }
 
-        return false;
+        private void setStartStationIdIfAbsent(Integer stationId) {
+            if (startStationId == null && stationId != null) {
+                startStationId = stationId;
+            }
+        }
+
+        private void appendStitchedPath(List<Integer> path) {
+            latestAppendedPath.clear();
+            if (path == null) {
+                return;
+            }
+            for (Integer stationId : path) {
+                if (stationId == null) {
+                    continue;
+                }
+                latestAppendedPath.add(stationId);
+                if (stitchedPathStationIds.isEmpty()
+                        || !stationId.equals(stitchedPathStationIds.get(stitchedPathStationIds.size() - 1))) {
+                    stitchedPathStationIds.add(stationId);
+                }
+            }
+        }
+
+        private void addPassedStation(Integer stationId) {
+            if (stationId == null) {
+                return;
+            }
+            if (passedStationIds.isEmpty()
+                    || !stationId.equals(passedStationIds.get(passedStationIds.size() - 1))) {
+                passedStationIds.add(stationId);
+            }
+        }
+
+        private List<Integer> getPendingStationIds() {
+            return new ArrayList<Integer>(pendingPathQueue);
+        }
+
+        private List<Integer> getPassedStationIds() {
+            return new ArrayList<Integer>(passedStationIds);
+        }
+
+        private List<Integer> getStitchedPathStationIds() {
+            return new ArrayList<Integer>(stitchedPathStationIds);
+        }
+
+        private List<Integer> getLatestAppendedPath() {
+            return new ArrayList<Integer>(latestAppendedPath);
+        }
     }
 }

--
Gitblit v1.9.1