From 3e28500e76ffd71b7da90f40d1f3126c00a0e5f0 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期一, 13 四月 2026 14:49:41 +0800
Subject: [PATCH] #站点运行优化

---
 AGENTS.md                                                            |   39 ++++++++-
 src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java |  155 +++++++++++++++++++++++++++++++++++---
 src/main/java/com/zy/core/enums/RedisKeyType.java                    |    1 
 3 files changed, 178 insertions(+), 17 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index a4e415b..2446768 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -174,7 +174,36 @@
 - 涓嶆柊澧炰笌鐜版湁浣撶郴骞惰浣嗚亴璐i噸澶嶇殑 Service銆乁til銆佺嚎绋嬫垨椤甸潰銆�
 - 涓嶇粫杩� Mapper XML 鐩存帴鎷兼帴鏉傛暎 SQL銆�
 
-## 5. 鎵ц鍓嶆鏌�
+## 5. 浠g爜鍙鎬ц姹�
+
+Agent 鐢熸垚鐨勪唬鐮佸繀椤绘槗浜庝汉绫婚槄璇诲拰缁存姢锛岀姝互涓嬪啓娉曪細
+
+### 5.1 鍛藉悕
+
+- 绂佹鍗曞瓧姣嶅彉閲忓悕锛堝惊鐜鏁板櫒 `i`/`j` 闄ゅ锛夈�佹棤鎰忎箟缂╁啓锛坄mgr`銆乣hdl`銆乣proc` 闄ら潪鏄」鐩棦鏈夌害瀹氾級銆�
+- 鍙橀噺鍚嶅拰鏂规硶鍚嶅繀椤昏兘琛ㄨ揪鎰忓浘锛岃鍚嶅瓧灏辩煡閬�"杩欐槸浠�涔�"鎴�"鍋氫粈涔�"銆�
+- 涓枃涓氬姟鏈鍙洿鎺ョ敤鎷奸煶鎴栬嫳鏂囧叏绉帮紝涓嶈鍙戞槑缂╁啓銆�
+
+### 5.2 鎺у埗娴�
+
+- 绂佹瓒呰繃 3 灞傜殑宓屽 if/for銆傞亣鍒版繁灞傚祵濂楋紝鎻愬彇涓虹嫭绔嬫柟娉曟垨鐢� early-return 鎵佸钩鍖栥��
+- 绂佹瓒呴暱鏂规硶锛堣秴杩� 80 琛屽簲鑰冭檻鎷嗗垎锛夈��
+- 绂佹鍦ㄤ竴涓〃杈惧紡閲岄摼寮忚皟鐢ㄨ秴杩� 3 涓搷浣滐紙濡� `a.getB().getC().getD().do()`锛夛紝搴旀媶鎴愪腑闂村彉閲忓苟鍛藉悕銆�
+- 涓夊厓杩愮畻绗﹀彧鐢ㄤ簬绠�鍗曡祴鍊硷紝绂佹宓屽涓夊厓銆�
+
+### 5.3 娉ㄩ噴涓庢剰鍥�
+
+- 涓嶅啓"缈昏瘧寮忔敞閲�"锛堝 `// 鑾峰彇鐢ㄦ埛鍚嶇О` 鏀惧湪 `getUserName()` 涓婃柟锛夈��
+- 娉ㄩ噴鍙В閲�"涓轰粈涔堣繖鏍峰仛"锛屼笉閲嶅"鍋氫簡浠�涔�"銆�
+- 澶嶆潅涓氬姟閫昏緫銆侀潪鏄捐�屾槗瑙佺殑杈圭晫澶勭悊銆佺粫杩囩殑鍧戯紝蹇呴』鍔犳敞閲婅鏄庡師鍥犮��
+
+### 5.4 缁撴瀯
+
+- 涓嶆妸澶氭閫昏緫鍘嬬缉鎴愪竴琛屼互"鍑忓皯琛屾暟"銆備竴琛屽彧鍋氫竴浠朵簨銆�
+- 涓嶄负浜�"閫氱敤"鑰屾彁鍓嶆娊璞°�備笁娆′互涓婇噸澶嶆墠鑰冭檻鎻愬彇銆�
+- 寮傚父澶勭悊蹇呴』鏈夊疄闄呮剰涔夛紝绂佹绌� catch銆乣e.printStackTrace()` 鎴栧悶鎺夊紓甯稿悗缁х画璺戙��
+
+## 6. 鎵ц鍓嶆鏌�
 
 寮�濮嬪疄鐜板墠鑷冲皯纭浠ヤ笅鍑犵偣锛�
 
@@ -187,7 +216,7 @@
 
 濡傛灉杩欎簺闂閲屾湁浠讳綍涓�椤圭瓟妗堟槸鈥滄槸鈥濓紝瀹炵幇鏃跺繀椤绘妸鐩稿叧閾捐矾涓�骞剁撼鍏ャ��
 
-## 6. 鎼滅储涓庢帓鏌ユ柟寮�
+## 7. 鎼滅储涓庢帓鏌ユ柟寮�
 
 浼樺厛鐢ㄥ揩閫熷畾浣嶏紝涓嶅仛鏃犺竟鐣屾壂璇伙細
 
@@ -205,7 +234,7 @@
 4. 鐘舵�佸洖鍐欑偣
 5. 椤甸潰娓叉煋鎴� WebSocket 娑堣垂鐐�
 
-## 7. 鏍¢獙涓庨獙璇�
+## 8. 鏍¢獙涓庨獙璇�
 
 鎸夋垚鏈粠浣庡埌楂樻墽琛岋紝鏃犳硶鎵ц鏃惰鏄庣‘璇存槑鍘熷洜銆�
 
@@ -251,7 +280,7 @@
 - `/wcs/views/locMap/locMap.html`
 - `/wcs/views/ai/*.html`
 
-## 8. 楂橀闄╂敼鍔ㄦ彁閱�
+## 9. 楂橀闄╂敼鍔ㄦ彁閱�
 
 - 鏀� Mapper XML 鏃讹紝閲嶇偣闃插瓧娈垫紡鏄犲皠銆佸埆鍚嶄笉涓�鑷淬�佺粨鏋滈泦绫诲瀷閿欒銆�
 - 鏀圭嚎绋�/璋冨害閫昏緫鏃讹紝閲嶇偣闃茬珵鎬併�侀噸澶嶄笅鍙戙�佺姸鎬佷笉鍥炴敹銆佹寰幆銆佸紓甯镐涪澶便��
@@ -260,7 +289,7 @@
 - 鏀� AI 閰嶇疆鏃讹紝閲嶇偣闃叉妸鏁版嵁搴撻厤缃摼璺拰 YAML 鍥為��閾捐矾娣锋穯銆�
 - 鏀圭洃鎺�/鍦板浘閫昏緫鏃讹紝閲嶇偣闃测�滃悗绔暟鎹纭絾鍓嶇娓叉煋閿欎綅鈥濆拰鈥滃墠绔樉绀烘甯镐絾鐘舵�佹簮閿欒鈥濅簰鐩歌鍒ゃ��
 
-## 9. 杈撳嚭瑕佹眰
+## 10. 杈撳嚭瑕佹眰
 
 瀹屾垚浠诲姟鍚庯紝缁撴灉璇存槑搴斿敖閲忓寘鍚細
 
diff --git a/src/main/java/com/zy/core/enums/RedisKeyType.java b/src/main/java/com/zy/core/enums/RedisKeyType.java
index d8aa37f..c1261f3 100644
--- a/src/main/java/com/zy/core/enums/RedisKeyType.java
+++ b/src/main/java/com/zy/core/enums/RedisKeyType.java
@@ -49,6 +49,7 @@
     STATION_OUT_PENDING_DISPATCH_("station_out_pending_dispatch_"),
     STATION_OUT_ORDER_DISPATCH_LIMIT_("station_out_order_dispatch_limit_"),
     STATION_RUN_BLOCK_DIRECT_REASSIGN_LIMIT_("station_run_block_direct_reassign_limit_"),
+    STATION_RUN_BLOCK_DIRECT_REASSIGN_NEAREST_CACHE_("station_run_block_direct_reassign_nearest_cache_"),
     STATION_OUT_EXECUTE_COMPLETE_LIMIT("station_out_execute_complete_limit_"),
     CHECK_STATION_RUN_BLOCK_LIMIT_("check_station_run_block_limit_"),
     STATION_RUN_BLOCK_REROUTE_STATE_("station_run_block_reroute_state_"),
diff --git a/src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java b/src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java
index a2e460d..dddde68 100644
--- a/src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java
+++ b/src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java
@@ -2,18 +2,18 @@
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.core.common.Cools;
 import com.core.exception.CoolException;
 import com.zy.asrs.entity.BasDevp;
 import com.zy.asrs.entity.LocMast;
 import com.zy.asrs.entity.WrkMast;
-import com.zy.asrs.service.BasDevpService;
 import com.zy.asrs.service.LocMastService;
 import com.zy.asrs.service.WrkMastService;
 import com.zy.common.entity.FindCrnNoResult;
+import com.zy.common.model.NavigateNode;
 import com.zy.common.model.StartupDto;
 import com.zy.common.service.CommonService;
+import com.zy.common.utils.NavigateUtils;
 import com.zy.common.utils.RedisUtil;
 import com.zy.core.News;
 import com.zy.core.cache.SlaveConnection;
@@ -29,7 +29,6 @@
 import com.zy.core.model.protocol.StationProtocol;
 import com.zy.core.model.protocol.StationTaskBufferItem;
 import com.zy.core.move.StationMoveCoordinator;
-import com.zy.core.move.StationMoveSession;
 import com.zy.core.thread.StationThread;
 import com.zy.core.utils.station.model.OutOrderDispatchDecision;
 import com.zy.core.utils.station.model.RerouteCommandPlan;
@@ -42,6 +41,7 @@
 import org.springframework.stereotype.Component;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -51,10 +51,9 @@
 public class StationRerouteProcessor {
     private static final int OUT_ORDER_DISPATCH_LIMIT_SECONDS = 2;
     private static final long STATION_MOVE_RESET_WAIT_MS = 1000L;
-    private static final int RUN_BLOCK_DIRECT_REASSIGN_LIMIT_SECONDS = 15 * 60;
+    private static final int RUN_BLOCK_DIRECT_REASSIGN_LIMIT_SECONDS = 8 * 60;
+    private static final int RUN_BLOCK_DIRECT_REASSIGN_NEAREST_CACHE_SECONDS = 60 * 60 * 24;
 
-    @Autowired
-    private BasDevpService basDevpService;
     @Autowired
     private WrkMastService wrkMastService;
     @Autowired
@@ -73,6 +72,8 @@
     private StationOutboundDecisionSupport stationOutboundDecisionSupport;
     @Autowired
     private StationDispatchRuntimeStateSupport stationDispatchRuntimeStateSupport;
+    @Autowired
+    private NavigateUtils navigateUtils;
 
     public void checkStationRunBlock(BasDevp basDevp, Integer stationId) {
         try {
@@ -316,11 +317,141 @@
     public boolean shouldUseRunBlockDirectReassign(WrkMast wrkMast,
                                                    Integer stationId,
                                                    List<Integer> runBlockReassignLocStationList) {
-        return wrkMast != null
-                && Objects.equals(wrkMast.getIoType(), WrkIoType.IN.id)
-                && stationId != null
-                && runBlockReassignLocStationList != null
-                && runBlockReassignLocStationList.contains(stationId);
+        if (wrkMast == null || stationId == null) {
+            return false;
+        }
+        if (!Objects.equals(wrkMast.getIoType(), WrkIoType.IN.id)) {
+            return false;
+        }
+        if (runBlockReassignLocStationList == null || !runBlockReassignLocStationList.contains(stationId)) {
+            return false;
+        }
+        if (shouldForceRunBlockPathReroute(wrkMast, stationId, runBlockReassignLocStationList)) {
+            return false;
+        }
+        return true;
+    }
+
+    private boolean shouldForceRunBlockPathReroute(WrkMast wrkMast,
+                                                   Integer stationId,
+                                                   List<Integer> runBlockReassignLocStationList) {
+        if (wrkMast == null || stationId == null) {
+            return false;
+        }
+        Integer nearestStationId = resolveNearestRunBlockDirectReassignStationId(wrkMast, runBlockReassignLocStationList);
+        return nearestStationId != null && !Objects.equals(stationId, nearestStationId);
+    }
+
+    private Integer resolveNearestRunBlockDirectReassignStationId(WrkMast wrkMast,
+                                                                  List<Integer> runBlockReassignLocStationList) {
+        if (wrkMast == null
+                || wrkMast.getStaNo() == null
+                || navigateUtils == null
+                || runBlockReassignLocStationList == null
+                || runBlockReassignLocStationList.isEmpty()) {
+            return null;
+        }
+        Integer targetStationId = wrkMast.getStaNo();
+        Integer cachedStationId = loadCachedNearestRunBlockDirectReassignStationId(targetStationId, runBlockReassignLocStationList);
+        if (cachedStationId != null) {
+            return cachedStationId;
+        }
+        Integer nearestStationId = null;
+        int nearestPathLen = Integer.MAX_VALUE;
+        for (Integer candidateStationId : runBlockReassignLocStationList) {
+            if (candidateStationId == null) {
+                continue;
+            }
+            List<NavigateNode> path = navigateUtils.calcOptimalPathByStationId(candidateStationId, targetStationId, wrkMast.getWrkNo(), null);
+            if (path == null || path.isEmpty()) {
+                continue;
+            }
+            int pathLen = countStationNodes(path);
+            if (pathLen <= 0) {
+                continue;
+            }
+            if (pathLen < nearestPathLen
+                    || (pathLen == nearestPathLen && nearestStationId != null && candidateStationId < nearestStationId)) {
+                nearestStationId = candidateStationId;
+                nearestPathLen = pathLen;
+            }
+        }
+        cacheNearestRunBlockDirectReassignStationId(targetStationId, runBlockReassignLocStationList, nearestStationId);
+        return nearestStationId;
+    }
+
+    private Integer loadCachedNearestRunBlockDirectReassignStationId(Integer targetStationId,
+                                                                     List<Integer> runBlockReassignLocStationList) {
+        String cacheKey = buildNearestRunBlockDirectReassignCacheKey(targetStationId, runBlockReassignLocStationList);
+        if (cacheKey == null || redisUtil == null) {
+            return null;
+        }
+        Object cacheValue = redisUtil.get(cacheKey);
+        if (cacheValue == null) {
+            return null;
+        }
+        try {
+            Integer stationId = Integer.valueOf(String.valueOf(cacheValue));
+            return runBlockReassignLocStationList.contains(stationId) ? stationId : null;
+        } catch (Exception ignore) {
+            return null;
+        }
+    }
+
+    private void cacheNearestRunBlockDirectReassignStationId(Integer targetStationId,
+                                                             List<Integer> runBlockReassignLocStationList,
+                                                             Integer nearestStationId) {
+        String cacheKey = buildNearestRunBlockDirectReassignCacheKey(targetStationId, runBlockReassignLocStationList);
+        if (cacheKey == null || nearestStationId == null || redisUtil == null) {
+            return;
+        }
+        redisUtil.set(cacheKey, nearestStationId, RUN_BLOCK_DIRECT_REASSIGN_NEAREST_CACHE_SECONDS);
+    }
+
+    private String buildNearestRunBlockDirectReassignCacheKey(Integer targetStationId,
+                                                              List<Integer> runBlockReassignLocStationList) {
+        if (targetStationId == null || runBlockReassignLocStationList == null || runBlockReassignLocStationList.isEmpty()) {
+            return null;
+        }
+        List<Integer> normalizedStationIdList = new ArrayList<>();
+        for (Integer stationId : runBlockReassignLocStationList) {
+            if (stationId != null && !normalizedStationIdList.contains(stationId)) {
+                normalizedStationIdList.add(stationId);
+            }
+        }
+        if (normalizedStationIdList.isEmpty()) {
+            return null;
+        }
+        Collections.sort(normalizedStationIdList);
+        return RedisKeyType.STATION_RUN_BLOCK_DIRECT_REASSIGN_NEAREST_CACHE_.key
+                + targetStationId
+                + "_"
+                + JSON.toJSONString(normalizedStationIdList);
+    }
+
+    private int countStationNodes(List<NavigateNode> path) {
+        if (path == null || path.isEmpty()) {
+            return 0;
+        }
+        int count = 0;
+        for (NavigateNode node : path) {
+            if (extractStationId(node) != null) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    private Integer extractStationId(NavigateNode node) {
+        if (node == null || Cools.isEmpty(node.getNodeValue())) {
+            return null;
+        }
+        try {
+            JSONObject valueObject = JSONObject.parseObject(node.getNodeValue());
+            return valueObject == null ? null : valueObject.getInteger("stationId");
+        } catch (Exception ignore) {
+            return null;
+        }
     }
 
     private boolean shouldSkipRunBlockStation(BasDevp basDevp, Integer stationId) {
@@ -461,7 +592,7 @@
         if (stationDispatchRuntimeStateSupport.hasRunBlockDirectReassignLimit(
                 wrkMast.getWrkNo(),
                 stationProtocol.getStationId())) {
-            News.info("杈撻�佺珯鐐硅繍琛屽牭濉為噸鍒嗛厤宸茶烦杩囷紝15鍒嗛挓鍐呬笉鍏佽閲嶅鐢宠銆傜珯鐐瑰彿={}锛屽伐浣滃彿={}",
+            News.info("杈撻�佺珯鐐硅繍琛屽牭濉為噸鍒嗛厤宸茶烦杩囷紝8鍒嗛挓鍐呬笉鍏佽閲嶅鐢宠銆傜珯鐐瑰彿={}锛屽伐浣滃彿={}",
                     stationProtocol.getStationId(),
                     wrkMast.getWrkNo());
             return;

--
Gitblit v1.9.1