From 42bb7c4d621ce4ebe1c1d12203bf874f0b0b296e Mon Sep 17 00:00:00 2001
From: Administrator <1051256694@qq.com>
Date: 星期五, 24 四月 2026 14:37:20 +0800
Subject: [PATCH] 电视机入库托数修复

---
 src/main/java/com/zy/common/service/CommonService.java |  986 +++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 731 insertions(+), 255 deletions(-)

diff --git a/src/main/java/com/zy/common/service/CommonService.java b/src/main/java/com/zy/common/service/CommonService.java
index 5f92b5b..c4f7002 100644
--- a/src/main/java/com/zy/common/service/CommonService.java
+++ b/src/main/java/com/zy/common/service/CommonService.java
@@ -28,11 +28,14 @@
 import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -165,7 +168,10 @@
     }
 
     /**
-     * 妫�绱㈠簱浣嶅彿
+     * 鍏ュ簱鎵惧簱浣嶇粺涓�鍏ュ彛銆�
+     *
+     * 绌烘墭鐩樺叆搴撲篃浠庤繖閲岃繘鍏ワ紝鍏堢敱 {@link #normalizeLocTypeDto(Integer, FindLocNoAttributeVo, LocTypeDto)}
+     * 缁熶竴璇嗗埆绌烘墭鐩樺拰鏁寸悊搴撲綅瑙勬牸锛屽啀鎸� row_lastno_type 鍒嗘祦鍒颁笉鍚屽簱鍨嬬殑鎵句綅瀹炵幇銆�
      *
      * @param staDescId            璺緞ID
      * @param sourceStaNo          婧愮珯
@@ -185,6 +191,8 @@
             Integer whsType = Utils.GetWhsType(sourceStaNo);
             RowLastno rowLastno = rowLastnoService.selectById(whsType);
             RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId());
+            List<Integer> stationAreas = Utils.getStationStorageAreas(sourceStaNo);
+            findLocNoAttributeVo.setOutAreas(stationAreas);
             Integer preferredArea = resolvePreferredArea(sourceStaNo, findLocNoAttributeVo);
             if (preferredArea != null) {
                 findLocNoAttributeVo.setOutArea(preferredArea);
@@ -196,9 +204,9 @@
             switch (rowLastnoType.getType()) {
                 case 1:
                 case 2:
-                    return getLocNoRun2(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 0, locTypeDto, recommendRows, 0);
                 case 3:
-                    return getLocNoRun(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 0, locTypeDto, 0);
+                    return getLocNoRun2(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 0, locTypeDto, recommendRows, 0);
+
                 case 4:
                     return getLocNoRun4(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 4, locTypeDto, 0);
                 case 5:
@@ -213,6 +221,51 @@
             log.error("绔欑偣={} 鏌ユ壘搴撲綅寮傚父", sourceStaNo, e);
             throw new CoolException("绔欑偣=" + sourceStaNo + " 鏌ユ壘搴撲綅澶辫触");
         }
+    }
+
+    /**
+     * 渚� 6.15 閲嶅垎閰嶆帴鍙e鐢細鎸夊閮ㄦ寚瀹氱殑鍫嗗灈鏈洪『搴忥紝鍦ㄦ寚瀹氬簱鍖哄唴鎵炬柊鐨勫叆搴撲綅銆�
+     *
+     * 杩欓噷涓嶆帹杩� row_lastno 娓告爣锛屽彧璐熻矗涓�娆℃�х殑璺緞鏍¢獙 + 璁惧鏍¢獙 + 绌哄簱浣嶆悳绱€��
+     */
+    public StartupDto findRun2InboundLocByCandidateCrnNos(Integer sourceStaNo, Integer staDescId, Integer preferredArea,
+                                                          List<Integer> candidateCrnNos, LocTypeDto locTypeDto) {
+        if (sourceStaNo == null) {
+            throw new CoolException("婧愮珯涓嶈兘涓虹┖");
+        }
+        if (Cools.isEmpty(candidateCrnNos)) {
+            return null;
+        }
+        Integer whsType = Utils.GetWhsType(sourceStaNo);
+        RowLastno defaultRowLastno = rowLastnoService.selectById(whsType);
+        if (Cools.isEmpty(defaultRowLastno)) {
+            throw new CoolException("绔欑偣=" + sourceStaNo + " 鏈煡璇㈠埌瀵瑰簲鐨勫簱浣嶈鍒�");
+        }
+        RowLastno searchRowLastno = defaultRowLastno;
+        if (preferredArea != null && preferredArea > 0) {
+            RowLastno areaRowLastno = rowLastnoService.selectById(preferredArea);
+            if (Cools.isEmpty(areaRowLastno)) {
+                throw new CoolException("鏈壘鍒板簱鍖鸿疆璇㈣鍒�");
+            }
+            searchRowLastno = areaRowLastno;
+        }
+        RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(searchRowLastno.getTypeId());
+        if (Cools.isEmpty(rowLastnoType)) {
+            throw new CoolException("鏁版嵁寮傚父锛岃鑱旂郴绠$悊鍛�===銆嬪簱浣嶈鍒欑被鍨嬫湭鐭�");
+        }
+        if (rowLastnoType.getType() != 1 && rowLastnoType.getType() != 2) {
+            throw new CoolException("褰撳墠浠撳簱涓嶆敮鎸侀噸鏂板垎閰嶅叆搴撲綅");
+        }
+        StartupDto startupDto = new StartupDto();
+        LocMast locMast = findRun2EmptyLocByCrnNos(searchRowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
+                staDescId, sourceStaNo, startupDto, preferredArea, null, "reassign-inbound");
+        if (Cools.isEmpty(locMast) || !"O".equals(locMast.getLocSts())) {
+            return null;
+        }
+        startupDto.setSourceStaNo(sourceStaNo);
+        startupDto.setCrnNo(locMast.getCrnNo());
+        startupDto.setLocNo(locMast.getLocNo());
+        return startupDto;
     }
 
     /**
@@ -231,8 +284,8 @@
      * 缁熶竴鏁寸悊鍏ュ簱瑙勬牸锛岄伩鍏嶄笉鍚屽叆鍙d紶鍏ョ殑 locType 涓嶄竴鑷淬��
      *
      * 绌烘墭鐩樼殑搴撲綅绛栫暐鏈変袱娈碉細
-     * 1. 棣栬疆鍙檺鍒� loc_type2=1锛岃〃绀轰紭鍏堟壘绐勫簱浣嶃��
-     * 2. loc_type1 楂樺害淇℃伅蹇呴』淇濈暀锛屽悗缁啀鎸変綆浣嶅悜楂樹綅鍏煎銆�
+     * 1. 鍏堥檺鍒� loc_type2=1锛岃〃绀轰紭鍏堟壘绐勫簱浣嶏紝骞朵繚鐣� loc_type1 楂樺害鍏煎銆�
+     * 2. 绐勫簱浣嶆病鏈夌粨鏋滃悗锛屾妸 loc_type1 鏀逛负 3 鍐嶆壘搴撲綅銆�
      *
      * 闈炵┖鎵樼洏鍙繚鐣� loc_type1锛屾弧鎵樻壘浣嶄笉鍐嶄娇鐢� loc_type2/loc_type3 杩囨护銆�
      */
@@ -263,35 +316,45 @@
     }
 
     /**
-     * 绌烘墭鐩樺浐瀹氭寜 4 娈靛紡鎵句綅锛�
+     * 绌烘墭鐩樺浐瀹氭寜绐勫簱浣嶄紭鍏堟壘浣嶏細
      * 1. 涓ユ牸楂樺害 + narrow
-     * 2. 涓ユ牸楂樺害 + any locType2
-     * 3. 鍚戜笂鍏煎楂樺害 + narrow
-     * 4. 鍚戜笂鍏煎楂樺害 + any locType2
+     * 2. 鍚戜笂鍏煎楂樺害 + narrow
+     * 3. loc_type1=3 + open
      */
     private List<LocTypeDto> buildEmptyPalletSearchLocTypes(LocTypeDto locTypeDto) {
-        LinkedHashSet<LocTypeDto> searchLocTypes = new LinkedHashSet<LocTypeDto>();
-        LocTypeDto narrowStrictLocType = copyLocTypeDto(locTypeDto == null ? new LocTypeDto() : locTypeDto);
-        if (narrowStrictLocType != null) {
-            narrowStrictLocType.setLocType2((short) 1);
-            searchLocTypes.add(narrowStrictLocType);
-            LocTypeDto openStrictLocType = copyLocTypeDto(narrowStrictLocType);
-            openStrictLocType.setLocType2(null);
-            searchLocTypes.add(openStrictLocType);
-
-            LocTypeDto narrowCompatibleLocType = buildUpwardCompatibleLocTypeDto(narrowStrictLocType);
-            if (narrowCompatibleLocType != null) {
-                narrowCompatibleLocType.setLocType2((short) 1);
-                searchLocTypes.add(narrowCompatibleLocType);
-                LocTypeDto openCompatibleLocType = copyLocTypeDto(narrowCompatibleLocType);
-                openCompatibleLocType.setLocType2(null);
-                searchLocTypes.add(openCompatibleLocType);
-            }
+        List<LocTypeDto> searchLocTypes = new ArrayList<LocTypeDto>();
+        LocTypeDto baseLocTypeDto = copyLocTypeDto(locTypeDto == null ? new LocTypeDto() : locTypeDto);
+        if (baseLocTypeDto == null) {
+            return searchLocTypes;
         }
-        return new ArrayList<LocTypeDto>(searchLocTypes);
+
+        LocTypeDto narrowStrictLocType = copyLocTypeDto(baseLocTypeDto);
+        narrowStrictLocType.setLocType2((short) 1);
+        searchLocTypes.add(narrowStrictLocType);
+
+        LocTypeDto narrowCompatibleLocType = buildUpwardCompatibleLocTypeDto(narrowStrictLocType);
+        if (narrowCompatibleLocType != null) {
+            narrowCompatibleLocType.setLocType2((short) 1);
+            searchLocTypes.add(narrowCompatibleLocType);
+        }
+
+        LocTypeDto emptyPalletFallbackLocType = copyLocTypeDto(baseLocTypeDto);
+        emptyPalletFallbackLocType.setLocType1((short) 3);
+        emptyPalletFallbackLocType.setLocType2((short) 0);
+        searchLocTypes.add(emptyPalletFallbackLocType);
+        return searchLocTypes;
     }
 
+    /**
+     * 缁欑┖鎵樼洏鎵句綅闃舵鐢熸垚鏃ュ織鏍囪瘑锛屼究浜庢帓鏌ュ埌搴曞崱鍦ㄧ獎搴撲綅銆侀珮搴﹀吋瀹硅繕鏄� loc_type1=3 鍏滃簳闃舵銆�
+     */
     private String buildEmptyPalletStageCode(LocTypeDto baseLocTypeDto, LocTypeDto stageLocTypeDto) {
+        boolean emptyPalletType3Fallback = stageLocTypeDto != null
+                && stageLocTypeDto.getLocType1() != null
+                && stageLocTypeDto.getLocType1() == 3;
+        if (emptyPalletType3Fallback) {
+            return "empty-pallet-locType1-3";
+        }
         boolean compatibleHeight = baseLocTypeDto != null
                 && baseLocTypeDto.getLocType1() != null
                 && stageLocTypeDto != null
@@ -316,6 +379,9 @@
 
     /**
      * 鎶� locType 鏉′欢杩藉姞鍒板簱浣嶆煡璇㈡潯浠堕噷銆�
+     *
+     * 绌烘墭鐩樹細鏄惧紡浼� loc_type2锛氱涓�杞� loc_type2=1 浼樺厛绐勫簱浣嶏紝鍏滃簳闃舵 loc_type2=0 琛ㄧず涓嶅啀闄愬埗瀹界獎銆�
+     * 婊℃墭鐩樻暣鐞嗗悗娌℃湁 loc_type2/loc_type3锛屾澶勪細鎺掗櫎 loc_type2=1锛岄伩鍏嶆弧鎵樺崰鐢ㄧ┖鎵樼洏绐勫簱浣嶃��
      */
     private Wrapper<LocMast> applyLocTypeFilters(Wrapper<LocMast> wrapper, LocTypeDto locTypeDto, boolean includeLocType1) {
         if (wrapper == null || locTypeDto == null) {
@@ -340,45 +406,19 @@
      * 瑙f瀽鏈鎵句綅搴斾紭鍏堜娇鐢ㄧ殑搴撳尯锛岀珯鐐圭粦瀹氫紭鍏堜簬鎺ュ彛浼犲弬銆�
      */
     private Integer resolvePreferredArea(Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo) {
-        BasDevp sourceStation = basDevpService.selectById(sourceStaNo);
-        Integer stationArea = parseArea(sourceStation == null ? null : sourceStation.getArea());
+        Integer stationArea = Utils.getStationStorageArea(sourceStaNo);
         if (stationArea != null) {
             return stationArea;
         }
         Integer requestArea = findLocNoAttributeVo.getOutArea();
-        if (requestArea != null && requestArea >= 1 && requestArea <= 3) {
+        if (isValidArea(requestArea)) {
             return requestArea;
         }
         return null;
     }
 
-    /**
-     * 鎶婄珯鐐圭淮鎶ょ殑搴撳尯鍊肩粺涓�瑙f瀽鎴� 1/2/3銆�
-     */
-    private Integer parseArea(String area) {
-        if (Cools.isEmpty(area)) {
-            return null;
-        }
-        String normalized = area.trim();
-        if (normalized.isEmpty()) {
-            return null;
-        }
-        try {
-            int areaNo = Integer.parseInt(normalized);
-            return areaNo >= 1 && areaNo <= 3 ? areaNo : null;
-        } catch (NumberFormatException ignored) {
-        }
-        String upper = normalized.toUpperCase(Locale.ROOT);
-        if ("A".equals(upper) || "A鍖�".equals(upper) || "A搴�".equals(upper) || "A搴撳尯".equals(upper)) {
-            return 1;
-        }
-        if ("B".equals(upper) || "B鍖�".equals(upper) || "B搴�".equals(upper) || "B搴撳尯".equals(upper)) {
-            return 2;
-        }
-        if ("C".equals(upper) || "C鍖�".equals(upper) || "C搴�".equals(upper) || "C搴撳尯".equals(upper)) {
-            return 3;
-        }
-        return null;
+    private boolean isValidArea(Integer area) {
+        return area != null && area >= 1 && area <= 3;
     }
 
     /**
@@ -539,6 +579,12 @@
     private LocMast findAgvLocByRows(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> rows,
                                      int startBay, int endBay, int curRow, int nearRow,
                                      LocTypeDto locTypeDto, boolean useDeepCheck) {
+        return findAgvLocByRows(rowLastno, rowLastnoType, rows, startBay, endBay, curRow, nearRow, locTypeDto, null, useDeepCheck);
+    }
+
+    private LocMast findAgvLocByRows(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> rows,
+                                     int startBay, int endBay, int curRow, int nearRow,
+                                     LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo, boolean useDeepCheck) {
         for (Integer row : rows) {
             if (row == null) {
                 continue;
@@ -551,7 +597,8 @@
             applyLocTypeFilters(wrapper, locTypeDto, true);
             wrapper.orderBy("lev1", true).orderBy("bay1", true);
             List<LocMast> locMasts = locMastService.selectList(wrapper);
-            for (LocMast candidate : locMasts) {
+            List<LocMast> sortedLocMasts = sortLocCandidates(locMasts, findLocNoAttributeVo);
+            for (LocMast candidate : sortedLocMasts) {
                 if (!VersionUtils.locMoveCheckLocTypeComplete(candidate, locTypeDto)) {
                     continue;
                 }
@@ -908,13 +955,251 @@
     }
 
     /**
-     * 鏋勯�犵┖鎵樼洏璺ㄥ簱鍖烘悳绱㈤『搴忥細
-     * 鍏堝綋鍓嶅簱鍖猴紝鍐嶄緷娆¤ˉ瓒冲叾瀹冨簱鍖猴紝閬垮厤閲嶅銆�
+     * 璇诲彇绔欑偣閰嶇疆鐨勪紭鍏堟睜鍫嗗灈鏈哄彿骞跺仛鍘婚噸銆�
      */
-    private List<Integer> buildAreaSearchOrder(Integer preferredArea) {
+    private List<Integer> loadPriorityCrnNos(String csv) {
+        return Utils.distinctCrnNos(csv);
+    }
+
+    /**
+     * 浠庡�欓�夊爢鍨涙満姹犱腑绉婚櫎宸茬粡鍑虹幇鍦ㄦ帓闄ゅ垪琛ㄩ噷鐨勫爢鍨涙満锛屼繚鎸佸師濮嬮『搴忎笉鍙樸��
+     */
+    private List<Integer> excludePriorityCrnNos(List<Integer> crnNos, List<Integer> excludedCrnNos) {
+        List<Integer> result = new ArrayList<Integer>();
+        if (Cools.isEmpty(crnNos)) {
+            return result;
+        }
+        LinkedHashSet<Integer> excludedCrnNoSet = new LinkedHashSet<Integer>(Utils.distinctCrnNos(excludedCrnNos));
+        for (Integer crnNo : Utils.distinctCrnNos(crnNos)) {
+            if (crnNo == null || excludedCrnNoSet.contains(crnNo)) {
+                continue;
+            }
+            result.add(crnNo);
+        }
+        return result;
+    }
+
+    /**
+     * 浠庡綋鍓嶆父鏍囩殑涓嬩竴鍙板爢鍨涙満寮�濮嬭疆杞��
+     */
+    private List<Integer> rotatePriorityCrnNos(List<Integer> crnNos, Integer currentCrnNo) {
+        List<Integer> orderedCrnNos = Utils.distinctCrnNos(crnNos);
+        if (Cools.isEmpty(orderedCrnNos) || currentCrnNo == null) {
+            return orderedCrnNos;
+        }
+        int currentIndex = orderedCrnNos.indexOf(currentCrnNo);
+        if (currentIndex < 0) {
+            return orderedCrnNos;
+        }
+        List<Integer> rotatedCrnNos = new ArrayList<>();
+        for (int index = currentIndex + 1; index < orderedCrnNos.size(); index++) {
+            rotatedCrnNos.add(orderedCrnNos.get(index));
+        }
+        for (int index = 0; index <= currentIndex; index++) {
+            rotatedCrnNos.add(orderedCrnNos.get(index));
+        }
+        return rotatedCrnNos;
+    }
+
+    /**
+     * run2 绔欑偣浼樺厛姹犳壘浣嶅叆鍙c��
+     *
+     * 绌烘墭鐩樿鍒欙細
+     * 1. 鍏堟壘绔欑偣绗竴浼樺厛姹狅紝鍐嶆壘绗簩浼樺厛姹狅紱绗簩姹犱細鎺掗櫎绗竴姹犲凡閰嶇疆鐨勫爢鍨涙満銆�
+     * 2. 姣忎釜浼樺厛姹犲唴鍏堟壘绐勫簱浣嶏紝鍐嶅仛楂樺害鍚戜笂鍏煎锛屾渶鍚庢妸 loc_type1 鏀逛负 3 鍏滃簳銆�
+     * 3. 鍙湁鍛戒腑搴撲綅鐨勬睜浼氭帹杩涜嚜宸辩殑 currentNo 娓告爣锛屾湭鍛戒腑鐨勬睜涓嶆敼鍙樿疆璇㈢姸鎬併��
+     */
+    private LocMast findRun2PriorityLocInPools(BasDevp station, RowLastno rowLastno, RowLastnoType rowLastnoType,
+                                                Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo,
+                                                LocTypeDto locTypeDto, StartupDto startupDto, boolean emptyPalletRequest) {
+        if (station == null) {
+            return null;
+        }
+        List<Integer> firstPoolCrnNos = loadPriorityCrnNos(station.getInFirstCrnCsv());
+        List<Integer> secondPoolCrnNos = excludePriorityCrnNos(loadPriorityCrnNos(station.getInSecondCrnCsv()), firstPoolCrnNos);
+        if (Cools.isEmpty(firstPoolCrnNos) && Cools.isEmpty(secondPoolCrnNos)) {
+            throw new CoolException("绔欑偣=" + station.getDevNo() + " 鏈厤缃叆搴撲紭鍏堝爢鍨涙満");
+        }
+
+        if (emptyPalletRequest) {
+            for (int poolNo = 1; poolNo <= 2; poolNo++) {
+                List<Integer> poolCrnNos = poolNo == 1 ? firstPoolCrnNos : secondPoolCrnNos;
+                Integer currentCrnNo = poolNo == 1 ? station.getInFirstCrnCurrentNo() : station.getInSecondCrnCurrentNo();
+                for (LocTypeDto searchLocTypeDto : buildEmptyPalletSearchLocTypes(locTypeDto)) {
+                    LocMast locMast = findRun2PriorityLocInPool(rowLastno, rowLastnoType, station, poolCrnNos, currentCrnNo,
+                            poolNo, searchLocTypeDto, staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, true);
+                    if (locMast != null) {
+                        return locMast;
+                    }
+                }
+            }
+            return null;
+        }
+
+        LocMast locMast = findRun2PriorityLocInPoolWithCompatibility(rowLastno, rowLastnoType, station, firstPoolCrnNos,
+                station.getInFirstCrnCurrentNo(), 1, locTypeDto, staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, false);
+        if (locMast != null) {
+            return locMast;
+        }
+        return findRun2PriorityLocInPoolWithCompatibility(rowLastno, rowLastnoType, station, secondPoolCrnNos,
+                station.getInSecondCrnCurrentNo(), 2, locTypeDto, staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, false);
+    }
+
+    /**
+     * 鍦ㄥ崟涓紭鍏堟睜鍐呮寜杞浆椤哄簭鎵句綅銆�
+     *
+     * 姹犲唴瑙勫垯锛�
+     * 1. 浠� currentNo 鐨勪笅涓�鍙板爢鍨涙満寮�濮嬭疆杞紝淇濊瘉鍚屼竴浼樺厛姹犲唴鍧囧垎銆�
+     * 2. 璺宠繃涓嶅彲鍏ャ�佹晠闅滄垨婧愮珯鍒扮洰鏍囧爢鍨涙満鏃犲叆搴撹矾寰勭殑鍫嗗灈鏈恒��
+     * 3. 姣忓彴鍫嗗灈鏈哄唴閮ㄤ氦缁� {@link #findConfiguredEmptyLocForCrn(RowLastno, RowLastnoType, Integer, Integer, LocTypeDto, FindLocNoAttributeVo, boolean)}
+     *    鎸夋繁娴呮帓鐢诲儚閫夋嫨绗竴涓彲鍒嗛厤搴撲綅銆�
+     * 4. 鍛戒腑鍚庡洖鍐欒浼樺厛姹犳父鏍囷紝骞舵妸鐩爣绔欏啓鍏� startupDto銆�
+     */
+    private LocMast findRun2PriorityLocInPool(RowLastno rowLastno, RowLastnoType rowLastnoType, BasDevp station,
+                                              List<Integer> crnNos, Integer currentCrnNo, int poolNo, LocTypeDto locTypeDto,
+                                              Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo,
+                                              StartupDto startupDto) {
+        return findRun2PriorityLocInPool(rowLastno, rowLastnoType, station, crnNos, currentCrnNo, poolNo, locTypeDto,
+                staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, false);
+    }
+
+    private LocMast findRun2PriorityLocInPool(RowLastno rowLastno, RowLastnoType rowLastnoType, BasDevp station,
+                                              List<Integer> crnNos, Integer currentCrnNo, int poolNo, LocTypeDto locTypeDto,
+                                              Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo,
+                                              StartupDto startupDto, boolean ignoreFreqType) {
+        if (Cools.isEmpty(crnNos)) {
+            return null;
+        }
+        List<Integer> rotatedCrnNos = rotatePriorityCrnNos(crnNos, currentCrnNo);
+        if (Cools.isEmpty(rotatedCrnNos)) {
+            return null;
+        }
+        for (Integer candidateCrnNo : rotatedCrnNos) {
+            if (candidateCrnNo == null || !basCrnpService.checkSiteError(candidateCrnNo, true)) {
+                continue;
+            }
+            Integer targetStaNo = resolveTargetStaNo(rowLastno, staDescId, sourceStaNo, candidateCrnNo);
+            if (Utils.BooleanWhsTypeSta(rowLastno, staDescId) && targetStaNo == null) {
+                continue;
+            }
+            Integer preferredNearRow = getCrnStartRow(rowLastno, candidateCrnNo);
+            LocMast candidateLoc = findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, candidateCrnNo,
+                    preferredNearRow, locTypeDto, findLocNoAttributeVo, ignoreFreqType);
+            if (Cools.isEmpty(candidateLoc)) {
+                continue;
+            }
+            if (!updatePriorityCursor(station, poolNo, currentCrnNo, candidateCrnNo)) {
+                throw new CoolException("绔欑偣=" + station.getDevNo() + " 浼樺厛姹犺疆杞洿鏂板け璐ワ紝璇烽噸璇�");
+            }
+            if (targetStaNo != null) {
+                startupDto.setStaNo(targetStaNo);
+            }
+            return candidateLoc;
+        }
+        return null;
+    }
+
+    /**
+     * 鏅�氭墭鐩樼殑浼樺厛姹犺鏍煎吋瀹瑰叆鍙c��
+     *
+     * 绌烘墭鐩樹笉璧拌繖涓柟娉曪紝鍥犱负绌烘墭鐩樺凡缁忓湪 {@link #buildEmptyPalletSearchLocTypes(LocTypeDto)}
+     * 涓浐瀹氬睍寮�浜嗏�滅獎搴撲綅浼樺厛 + 楂樺害鍚戜笂鍏煎 + loc_type1=3 鍏滃簳鈥濈殑椤哄簭銆�
+     */
+    private LocMast findRun2PriorityLocInPoolWithCompatibility(RowLastno rowLastno, RowLastnoType rowLastnoType,
+                                                                BasDevp station, List<Integer> crnNos, Integer currentCrnNo,
+                                                                int poolNo, LocTypeDto locTypeDto, Integer staDescId,
+                                                                Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo,
+                                                                StartupDto startupDto, boolean ignoreFreqType) {
+        LocMast locMast = findRun2PriorityLocInPool(rowLastno, rowLastnoType, station, crnNos, currentCrnNo, poolNo,
+                locTypeDto, staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, ignoreFreqType);
+        if (locMast != null) {
+            return locMast;
+        }
+        LocTypeDto compatibleLocTypeDto = buildRetryCompatibleLocTypeDto(staDescId, findLocNoAttributeVo, locTypeDto);
+        if (compatibleLocTypeDto == null) {
+            return null;
+        }
+        return findRun2PriorityLocInPool(rowLastno, rowLastnoType, station, crnNos, currentCrnNo, poolNo,
+                compatibleLocTypeDto, staDescId, sourceStaNo, findLocNoAttributeVo, startupDto, ignoreFreqType);
+    }
+
+    /**
+     * 浠ヤ箰瑙傛柟寮忓洖鍐欎紭鍏堟睜娓告爣銆�
+     */
+    private boolean updatePriorityCursor(BasDevp station, int poolNo, Integer expectedCurrentNo, Integer selectedCrnNo) {
+        if (station == null || station.getDevNo() == null || selectedCrnNo == null) {
+            return false;
+        }
+        BasDevp updateStation = new BasDevp();
+        String cursorColumn;
+        if (poolNo == 1) {
+            updateStation.setInFirstCrnCurrentNo(selectedCrnNo);
+            cursorColumn = "in_first_crn_current_no";
+        } else {
+            updateStation.setInSecondCrnCurrentNo(selectedCrnNo);
+            cursorColumn = "in_second_crn_current_no";
+        }
+        EntityWrapper<BasDevp> wrapper = new EntityWrapper<>();
+        wrapper.eq("dev_no", station.getDevNo());
+        if (expectedCurrentNo == null) {
+            wrapper.isNull(cursorColumn);
+        } else {
+            wrapper.eq(cursorColumn, expectedCurrentNo);
+        }
+        if (basDevpService.update(updateStation, wrapper)) {
+            return true;
+        }
+        BasDevp latestStation = basDevpService.selectById(station.getDevNo());
+        if (latestStation == null) {
+            return false;
+        }
+        Integer latestCurrentNo = poolNo == 1 ? latestStation.getInFirstCrnCurrentNo() : latestStation.getInSecondCrnCurrentNo();
+        return Objects.equals(latestCurrentNo, selectedCrnNo);
+    }
+
+    /**
+     * 缁勮浼樺厛姹犻瑙堟暟鎹��
+     */
+    private Map<String, Object> buildPriorityPoolPreview(RowLastno rowLastno, RowLastnoType rowLastnoType, int poolNo,
+                                                          List<Integer> crnNos, Integer currentCrnNo, Integer staDescId,
+                                                          Integer sourceStaNo, LocTypeDto locTypeDto,
+                                                          FindLocNoAttributeVo findLocNoAttributeVo) {
+        return buildPriorityPoolPreview(rowLastno, rowLastnoType, poolNo, crnNos, currentCrnNo, staDescId, sourceStaNo,
+                locTypeDto, findLocNoAttributeVo, false);
+    }
+
+    private Map<String, Object> buildPriorityPoolPreview(RowLastno rowLastno, RowLastnoType rowLastnoType, int poolNo,
+                                                          List<Integer> crnNos, Integer currentCrnNo, Integer staDescId,
+                                                          Integer sourceStaNo, LocTypeDto locTypeDto,
+                                                          FindLocNoAttributeVo findLocNoAttributeVo, boolean ignoreFreqType) {
+        Map<String, Object> item = new HashMap<String, Object>();
+        List<Integer> configuredCrnNos = Utils.distinctCrnNos(crnNos);
+        List<Integer> rotatedCrnNos = rotatePriorityCrnNos(configuredCrnNos, currentCrnNo);
+        item.put("poolNo", poolNo);
+        item.put("currentCrnNo", currentCrnNo);
+        item.put("configuredCrnNos", configuredCrnNos);
+        item.put("rotatedCrnNos", rotatedCrnNos);
+        item.put("runnableCrnNos", getOrderedRunnableRun2CrnNos(rowLastno, staDescId, sourceStaNo, rotatedCrnNos));
+        item.put("profiles", buildRun2ProfilePreview(rowLastno, rowLastnoType, rotatedCrnNos, staDescId, sourceStaNo,
+                locTypeDto, findLocNoAttributeVo, ignoreFreqType));
+        return item;
+    }
+
+    /**
+     * 鏋勯�犵┖鎵樼洏璺ㄥ簱鍖烘悳绱㈤『搴忥細
+     * 鍏堢珯鐐圭粦瀹氬簱鍖猴紝鍐嶈ˉ璇锋眰搴撳尯锛屾渶鍚庡洖閫�鍏ㄤ粨搴撳尯锛岄伩鍏嶉噸澶嶃��
+     */
+    private List<Integer> buildAreaSearchOrder(List<Integer> preferredAreas, Integer requestArea) {
         LinkedHashSet<Integer> areaOrder = new LinkedHashSet<>();
-        if (preferredArea != null && preferredArea >= 1 && preferredArea <= 3) {
-            areaOrder.add(preferredArea);
+        if (!Cools.isEmpty(preferredAreas)) {
+            for (Integer area : preferredAreas) {
+                if (isValidArea(area)) {
+                    areaOrder.add(area);
+                }
+            }
+        }
+        if (isValidArea(requestArea)) {
+            areaOrder.add(requestArea);
         }
         for (int area = 1; area <= 3; area++) {
             areaOrder.add(area);
@@ -923,7 +1208,7 @@
     }
 
     /**
-     * 棰勮 run2 褰撳墠浼氬弬涓庣殑搴撳尯銆佸爢鍨涙満椤哄簭鍜屾繁娴呮帓鐢诲儚锛屼笉钀戒换鍔℃。銆�
+     * 棰勮 run2 褰撳墠浼氬弬涓庣殑浼樺厛姹犮�佸爢鍨涙満椤哄簭鍜屾繁娴呮帓鐢诲儚锛屼笉钀戒换鍔℃。銆�
      */
     public Map<String, Object> previewRun2Allocation(BasCrnDepthRuleRuntimePreviewParam param) {
         if (param == null || param.getStaDescId() == null || param.getSourceStaNo() == null) {
@@ -932,6 +1217,7 @@
         FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo();
         findLocNoAttributeVo.setMatnr(param.getMatnr());
         findLocNoAttributeVo.setOutArea(param.getOutArea());
+        findLocNoAttributeVo.setFreqType(param.getFreqType());
 
         LocTypeDto locTypeDto = new LocTypeDto();
         locTypeDto.setLocType1(param.getLocType1());
@@ -945,68 +1231,66 @@
             throw new CoolException("鏈壘鍒颁粨搴撹疆璇㈣鍒�");
         }
         RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId());
-        Integer preferredArea = resolvePreferredArea(param.getSourceStaNo(), findLocNoAttributeVo);
+        List<Integer> stationAreas = Utils.getStationStorageAreas(param.getSourceStaNo());
         boolean emptyPalletRequest = isEmptyPalletRequest(param.getStaDescId(), findLocNoAttributeVo);
+        BasDevp station = basDevpService.selectById(param.getSourceStaNo());
+        if (Cools.isEmpty(station)) {
+            throw new CoolException("绔欑偣=" + param.getSourceStaNo() + " 鏈厤缃叆搴撲紭鍏堝爢鍨涙満");
+        }
+        List<Integer> firstPoolCrnNos = loadPriorityCrnNos(station.getInFirstCrnCsv());
+        List<Integer> secondPoolCrnNos = excludePriorityCrnNos(loadPriorityCrnNos(station.getInSecondCrnCsv()), firstPoolCrnNos);
 
         Map<String, Object> result = new HashMap<String, Object>();
         result.put("whsType", whsType);
-        result.put("preferredArea", preferredArea);
+        result.put("preferredArea", findLocNoAttributeVo.getOutArea());
+        result.put("preferredAreas", stationAreas);
         result.put("emptyPallet", emptyPalletRequest);
         result.put("locType", locTypeDto);
         result.put("stationPriorityEntries", Utils.getStationStorageAreaName(
                 param.getSourceStaNo(),
                 locTypeDto == null || locTypeDto.getLocType1() == null ? null : locTypeDto.getLocType1().intValue(),
                 findLocNoAttributeVo.getMatnr()));
+        result.put("firstPriorityCrnNos", firstPoolCrnNos);
+        result.put("secondPriorityCrnNos", secondPoolCrnNos);
+        result.put("firstPriorityCurrentNo", station.getInFirstCrnCurrentNo());
+        result.put("secondPriorityCurrentNo", station.getInSecondCrnCurrentNo());
+        result.put("firstPriorityRotatedCrnNos", rotatePriorityCrnNos(firstPoolCrnNos, station.getInFirstCrnCurrentNo()));
+        result.put("secondPriorityRotatedCrnNos", rotatePriorityCrnNos(secondPoolCrnNos, station.getInSecondCrnCurrentNo()));
 
         List<Integer> orderedCrnNos = getOrderedCrnNos(rowLastno, resolveRun2CrnNo(rowLastno));
         List<Integer> runnableCrnNos = getOrderedRunnableRun2CrnNos(rowLastno, param.getStaDescId(), param.getSourceStaNo(), orderedCrnNos);
         result.put("orderedCrnNos", orderedCrnNos);
         result.put("runnableCrnNos", runnableCrnNos);
+        List<Map<String, Object>> poolPreviews = new ArrayList<Map<String, Object>>();
 
         if (emptyPalletRequest) {
-            List<Integer> areaSearchOrder = buildAreaSearchOrder(preferredArea);
-            List<Map<String, Object>> searchStages = new ArrayList<Map<String, Object>>();
-            for (LocTypeDto stageLocTypeDto : buildEmptyPalletSearchLocTypes(locTypeDto)) {
-                List<Map<String, Object>> areaPreviews = new ArrayList<Map<String, Object>>();
-                for (Integer area : areaSearchOrder) {
-                    RowLastno areaRowLastno = getAreaRowLastno(area, rowLastno);
-                    RowLastnoType areaRowLastnoType = rowLastnoTypeService.selectById(areaRowLastno.getTypeId());
-                    List<Integer> areaOrderedCrnNos = getOrderedCrnNos(areaRowLastno, resolveRun2CrnNo(areaRowLastno));
-                    List<Integer> areaRunnableCrnNos = getOrderedRunnableRun2CrnNos(areaRowLastno, param.getStaDescId(),
-                            param.getSourceStaNo(), areaOrderedCrnNos, false);
-                    Map<String, Object> areaItem = new HashMap<String, Object>();
-                    areaItem.put("area", area);
-                    areaItem.put("orderedCrnNos", areaOrderedCrnNos);
-                    areaItem.put("runnableCrnNos", areaRunnableCrnNos);
-                    areaItem.put("profiles", buildRun2ProfilePreview(areaRowLastno, areaRowLastnoType, areaOrderedCrnNos,
-                            param.getStaDescId(), param.getSourceStaNo(), stageLocTypeDto));
-                    areaPreviews.add(areaItem);
+            for (int poolNo = 1; poolNo <= 2; poolNo++) {
+                List<Integer> poolCrnNos = poolNo == 1 ? firstPoolCrnNos : secondPoolCrnNos;
+                Integer currentCrnNo = poolNo == 1 ? station.getInFirstCrnCurrentNo() : station.getInSecondCrnCurrentNo();
+                Map<String, Object> poolPreview = buildPriorityPoolPreview(rowLastno, rowLastnoType, poolNo, poolCrnNos,
+                        currentCrnNo, param.getStaDescId(), param.getSourceStaNo(), locTypeDto, findLocNoAttributeVo, true);
+                List<Map<String, Object>> stagePreviews = new ArrayList<Map<String, Object>>();
+                for (LocTypeDto stageLocTypeDto : buildEmptyPalletSearchLocTypes(locTypeDto)) {
+                    Map<String, Object> stagePreview = buildPriorityPoolPreview(rowLastno, rowLastnoType, poolNo, poolCrnNos,
+                            currentCrnNo, param.getStaDescId(), param.getSourceStaNo(), stageLocTypeDto, findLocNoAttributeVo, true);
+                    stagePreview.put("stageCode", buildEmptyPalletStageCode(locTypeDto, stageLocTypeDto));
+                    stagePreview.put("locType", stageLocTypeDto);
+                    stagePreviews.add(stagePreview);
                 }
-                Map<String, Object> stageItem = new HashMap<String, Object>();
-                stageItem.put("stageCode", buildEmptyPalletStageCode(locTypeDto, stageLocTypeDto));
-                stageItem.put("locType", stageLocTypeDto);
-                stageItem.put("areaSearchOrder", areaSearchOrder);
-                stageItem.put("areaPreviews", areaPreviews);
-                searchStages.add(stageItem);
+                poolPreview.put("stagePreviews", stagePreviews);
+                poolPreviews.add(poolPreview);
             }
-            result.put("areaSearchOrder", areaSearchOrder);
-            result.put("searchStages", searchStages);
+            result.put("poolPreviews", poolPreviews);
             return result;
         }
 
-        if (preferredArea != null) {
-            List<Integer> preferredCrnNos = filterCrnNosByRows(rowLastno, orderedCrnNos, getRun2AreaRows(preferredArea, rowLastno));
-            result.put("candidateCrnNos", preferredCrnNos);
-            result.put("profiles", buildRun2ProfilePreview(rowLastno, rowLastnoType, preferredCrnNos,
-                    param.getStaDescId(), param.getSourceStaNo(), locTypeDto));
-            result.put("areaMode", "preferred-area-only");
-            return result;
-        }
-
-        result.put("candidateCrnNos", orderedCrnNos);
-        result.put("profiles", buildRun2ProfilePreview(rowLastno, rowLastnoType, orderedCrnNos,
-                param.getStaDescId(), param.getSourceStaNo(), locTypeDto));
-        result.put("areaMode", "warehouse-round-robin");
+        poolPreviews.add(buildPriorityPoolPreview(rowLastno, rowLastnoType, 1, firstPoolCrnNos,
+                station.getInFirstCrnCurrentNo(), param.getStaDescId(), param.getSourceStaNo(), locTypeDto,
+                findLocNoAttributeVo));
+        poolPreviews.add(buildPriorityPoolPreview(rowLastno, rowLastnoType, 2, secondPoolCrnNos,
+                station.getInSecondCrnCurrentNo(), param.getStaDescId(), param.getSourceStaNo(), locTypeDto,
+                findLocNoAttributeVo));
+        result.put("poolPreviews", poolPreviews);
         return result;
     }
 
@@ -1014,7 +1298,14 @@
      * 缁勮鏌愭壒鍫嗗灈鏈虹殑杩愯鏃剁敾鍍忛瑙堟暟鎹��
      */
     private List<Map<String, Object>> buildRun2ProfilePreview(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> crnNos,
-                                                              Integer staDescId, Integer sourceStaNo, LocTypeDto locTypeDto) {
+                                                              Integer staDescId, Integer sourceStaNo, LocTypeDto locTypeDto,
+                                                              FindLocNoAttributeVo findLocNoAttributeVo) {
+        return buildRun2ProfilePreview(rowLastno, rowLastnoType, crnNos, staDescId, sourceStaNo, locTypeDto, findLocNoAttributeVo, false);
+    }
+
+    private List<Map<String, Object>> buildRun2ProfilePreview(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> crnNos,
+                                                              Integer staDescId, Integer sourceStaNo, LocTypeDto locTypeDto,
+                                                              FindLocNoAttributeVo findLocNoAttributeVo, boolean ignoreFreqType) {
         List<Map<String, Object>> profiles = new ArrayList<Map<String, Object>>();
         if (Cools.isEmpty(crnNos)) {
             return profiles;
@@ -1031,7 +1322,7 @@
             item.put("shallowRows", profile == null ? null : profile.getShallowRows());
             item.put("deepRows", profile == null ? null : profile.getDeepRows());
             LocMast firstMatchLoc = findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo,
-                    getCrnStartRow(rowLastno, crnNo), locTypeDto);
+                    getCrnStartRow(rowLastno, crnNo), locTypeDto, findLocNoAttributeVo, ignoreFreqType);
             item.put("firstMatchLocNo", firstMatchLoc == null ? null : firstMatchLoc.getLocNo());
             item.put("assignableLocCount", countAssignableLocForCrn(rowLastno, rowLastnoType, crnNo,
                     getCrnStartRow(rowLastno, crnNo) == null ? 0 : getCrnStartRow(rowLastno, crnNo), locTypeDto));
@@ -1056,10 +1347,13 @@
     }
 
     /**
-     * 绌烘墭鐩� run2 涓撶敤鎼滅储閾捐矾銆�
+     * 淇濈暀鐨勭┖鎵樼洏 run2 鎸夊簱鍖鸿疆璇㈡悳绱㈤摼璺��
+     *
+     * 褰撳墠 getLocNoRun2 鐨勭┖鎵樼洏瀹為檯鍏ュ彛璧� {@link #findRun2PriorityLocInPools(BasDevp, RowLastno, RowLastnoType, Integer, Integer, FindLocNoAttributeVo, LocTypeDto, StartupDto, boolean)}
+     * 鐨勭珯鐐逛紭鍏堟睜瑙勫垯锛涘鏋滃悗缁渶瑕佹仮澶嶁�滃綋鍓嶅簱鍖� -> 鍏跺畠搴撳尯鈥濈殑鍏滃簳锛屽彲浠ヤ粠杩欓噷鎺ュ洖銆�
      *
      * 鎵ц椤哄簭锛�
-     * 1. 鍏堟寜鍥哄畾瑙勬牸闃舵鏋勯�� 4 娈靛紡 locType 鍥為��椤哄簭銆�
+     * 1. 鍏堟寜鍥哄畾瑙勬牸闃舵鏋勯�犫�滅獎搴撲綅浼樺厛 + loc_type1=3 鍏滃簳鈥濈殑 locType 鍥為��椤哄簭銆�
      * 2. 姣忎釜瑙勬牸闃舵閮芥寜鈥滃綋鍓嶅簱鍖� -> 鍏跺畠搴撳尯鈥濈殑椤哄簭鎼滅储銆�
      * 3. 姣忎釜搴撳尯鍐呴儴閮芥寜璇ュ簱鍖鸿嚜宸辩殑 rowLastno/currentRow 鍋氳疆璇㈠潎鍒嗐��
      *
@@ -1067,11 +1361,12 @@
      * 鍥犱负绌烘墭鐩樼殑涓氬姟鍙e緞宸茬粡鍒囨崲鎴愨�滄寜搴撳尯鎵惧爢鍨涙満鈥濓紝涓嶆槸鎸夋帹鑽愭帓鎵惧贩閬撱��
      */
     private Run2AreaSearchResult findEmptyPalletRun2Loc(RowLastno defaultRowLastno, Integer staDescId, Integer sourceStaNo,
-                                                        StartupDto startupDto, Integer preferredArea, LocTypeDto locTypeDto) {
+                                                        StartupDto startupDto, FindLocNoAttributeVo findLocNoAttributeVo,
+                                                        LocTypeDto locTypeDto) {
         for (LocTypeDto stageLocTypeDto : buildEmptyPalletSearchLocTypes(locTypeDto)) {
             String stageCode = buildEmptyPalletStageCode(locTypeDto, stageLocTypeDto);
             Run2AreaSearchResult searchResult = findEmptyPalletRun2AreaLoc(defaultRowLastno, staDescId, sourceStaNo,
-                    startupDto, preferredArea, stageLocTypeDto, stageCode);
+                    startupDto, findLocNoAttributeVo, stageLocTypeDto, stageCode);
             if (!Cools.isEmpty(searchResult) && !Cools.isEmpty(searchResult.locMast)) {
                 return searchResult;
             }
@@ -1079,10 +1374,19 @@
         return null;
     }
 
+    /**
+     * 淇濈暀閾捐矾锛氬湪鏌愪釜绌烘墭鐩樿鏍奸樁娈靛唴鎸夊簱鍖洪『搴忔悳绱€��
+     *
+     * 搴撳尯椤哄簭鐢� {@link #buildAreaSearchOrder(List, Integer)} 鐢熸垚锛氱珯鐐圭粦瀹氬簱鍖轰紭鍏堬紝鍏舵鎺ュ彛璇锋眰搴撳尯锛�
+     * 鏈�鍚庤ˉ榻� 1/2/3 鍏ㄥ簱鍖恒�傛瘡涓簱鍖轰娇鐢ㄨ嚜宸辩殑 row_lastno 娓告爣锛屽苟涓旇法搴撳尯鏃朵笉寮哄埗 sta_desc 璺緞鏍¢獙銆�
+     */
     private Run2AreaSearchResult findEmptyPalletRun2AreaLoc(RowLastno defaultRowLastno, Integer staDescId, Integer sourceStaNo,
-                                                            StartupDto startupDto, Integer preferredArea, LocTypeDto locTypeDto,
+                                                            StartupDto startupDto, FindLocNoAttributeVo findLocNoAttributeVo, LocTypeDto locTypeDto,
                                                             String stageCode) {
-        for (Integer area : buildAreaSearchOrder(preferredArea)) {
+        List<Integer> areaSearchOrder = buildAreaSearchOrder(
+                findLocNoAttributeVo == null ? null : findLocNoAttributeVo.getOutAreas(),
+                findLocNoAttributeVo == null ? null : findLocNoAttributeVo.getOutArea());
+        for (Integer area : areaSearchOrder) {
             RowLastno areaRowLastno = getAreaRowLastno(area, defaultRowLastno);
             if (Cools.isEmpty(areaRowLastno)) {
                 continue;
@@ -1099,7 +1403,7 @@
                 continue;
             }
             LocMast locMast = findRun2EmptyLocByCrnNos(areaRowLastno, areaRowLastnoType, runnableAreaCrnNos, locTypeDto,
-                    staDescId, sourceStaNo, startupDto, area, stageCode + "-area-" + area, false);
+                    staDescId, sourceStaNo, startupDto, area, findLocNoAttributeVo, stageCode + "-area-" + area, false);
             if (!Cools.isEmpty(locMast)) {
                 return new Run2AreaSearchResult(locMast, areaRowLastno, runnableAreaCrnNos);
             }
@@ -1139,7 +1443,7 @@
             // 绔欑偣浼樺厛绾у彧鏄�滀紭鍏堝皾璇曗�濓紝娌℃湁鍛戒腑鏃跺繀椤荤户缁蛋榛樿/搴撳尯鍥為��锛�
             // 鍚﹀垯浼氭妸鈥滀紭鍏堝�欓�夋棤浣嶁�濊鍒ゆ垚鈥滄暣浠撴棤浣嶁�濄��
             LocMast locMast = findRun2EmptyLocByCrnLocTypeEntries(rowLastno, rowLastnoType, stationCrnLocTypes,
-                    locTypeDto, staDescId, sourceStaNo, startupDto, preferredArea, "station-priority");
+                    locTypeDto, staDescId, sourceStaNo, startupDto, preferredArea, "station-priority", findLocNoAttributeVo);
             if (!Cools.isEmpty(locMast)) {
                 return new Run2SearchResult(locMast, rowLastno,
                         getOrderedRunnableRun2CrnNos(rowLastno, staDescId, sourceStaNo, extractCrnNos(stationCrnLocTypes)));
@@ -1153,7 +1457,8 @@
         }
         List<Integer> runnableCrnNos = getOrderedRunnableRun2CrnNos(rowLastno, staDescId, sourceStaNo, candidateCrnNos);
         LocMast locMast = findRun2EmptyLocByCrnNos(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
-                staDescId, sourceStaNo, startupDto, preferredArea, preferredArea == null ? "default" : "preferred-area");
+                staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo,
+                preferredArea == null ? "default" : "preferred-area");
         return new Run2SearchResult(locMast, rowLastno, runnableCrnNos);
     }
 
@@ -1218,7 +1523,7 @@
                 .eq("stn_no", sourceStaNo)
                 .eq("crn_no", crnNo));
         if (Cools.isEmpty(staDesc)) {
-            log.error("type_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo);
+            log.error("娌℃湁鍏ュ簱璺緞type_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo);
             return null;
         }
         BasDevp staNo = basDevpService.selectById(staDesc.getCrnStn());
@@ -1251,12 +1556,19 @@
                                              LocTypeDto locTypeDto, Integer staDescId, Integer sourceStaNo, StartupDto startupDto,
                                              Integer preferredArea, String stage) {
         return findRun2EmptyLocByCrnNos(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
-                staDescId, sourceStaNo, startupDto, preferredArea, stage, true);
+                staDescId, sourceStaNo, startupDto, preferredArea, null, stage, true);
     }
 
     private LocMast findRun2EmptyLocByCrnNos(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> candidateCrnNos,
                                              LocTypeDto locTypeDto, Integer staDescId, Integer sourceStaNo, StartupDto startupDto,
-                                             Integer preferredArea, String stage, boolean routeRequired) {
+                                             Integer preferredArea, FindLocNoAttributeVo findLocNoAttributeVo, String stage) {
+        return findRun2EmptyLocByCrnNos(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
+                staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, true);
+    }
+
+    private LocMast findRun2EmptyLocByCrnNos(RowLastno rowLastno, RowLastnoType rowLastnoType, List<Integer> candidateCrnNos,
+                                             LocTypeDto locTypeDto, Integer staDescId, Integer sourceStaNo, StartupDto startupDto,
+                                             Integer preferredArea, FindLocNoAttributeVo findLocNoAttributeVo, String stage, boolean routeRequired) {
         if (Cools.isEmpty(candidateCrnNos)) {
             log.warn("run2 skip empty candidate list. stage={}, sourceStaNo={}, preferredArea={}, spec={}",
                     stage, sourceStaNo, preferredArea, JSON.toJSONString(locTypeDto));
@@ -1267,14 +1579,15 @@
         List<Integer> noEmptyCrns = new ArrayList<>();
         List<Integer> locTypeBlockedCrns = new ArrayList<>();
         return findRun2EmptyLocByCrnNosRecursively(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
-                staDescId, sourceStaNo, startupDto, preferredArea, stage, routeRequired, 0,
+                staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, 0,
                 crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
     }
 
     private LocMast findRun2EmptyLocByCrnNosRecursively(RowLastno rowLastno, RowLastnoType rowLastnoType,
                                                         List<Integer> candidateCrnNos, LocTypeDto locTypeDto,
                                                         Integer staDescId, Integer sourceStaNo, StartupDto startupDto,
-                                                        Integer preferredArea, String stage, boolean routeRequired, int index,
+                                                        Integer preferredArea, FindLocNoAttributeVo findLocNoAttributeVo,
+                                                        String stage, boolean routeRequired, int index,
                                                         List<Integer> crnErrorCrns, List<Integer> routeBlockedCrns,
                                                         List<Integer> noEmptyCrns, List<Integer> locTypeBlockedCrns) {
         if (index >= candidateCrnNos.size()) {
@@ -1286,19 +1599,19 @@
         if (!isCrnActive(candidateCrnNo)) {
             crnErrorCrns.add(candidateCrnNo);
             return findRun2EmptyLocByCrnNosRecursively(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
-                    staDescId, sourceStaNo, startupDto, preferredArea, stage, routeRequired, index + 1,
+                    staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, index + 1,
                     crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
         }
         Integer targetStaNo = routeRequired ? resolveTargetStaNo(rowLastno, staDescId, sourceStaNo, candidateCrnNo) : null;
         if (routeRequired && Utils.BooleanWhsTypeSta(rowLastno, staDescId) && targetStaNo == null) {
             routeBlockedCrns.add(candidateCrnNo);
             return findRun2EmptyLocByCrnNosRecursively(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
-                    staDescId, sourceStaNo, startupDto, preferredArea, stage, routeRequired, index + 1,
+                    staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, index + 1,
                     crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
         }
         Integer preferredNearRow = getCrnStartRow(rowLastno, candidateCrnNo);
         LocMast candidateLoc = findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, candidateCrnNo,
-                preferredNearRow, locTypeDto);
+                preferredNearRow, locTypeDto, findLocNoAttributeVo);
         if (Cools.isEmpty(candidateLoc)) {
             int availableLocCount = countAssignableLocForCrn(rowLastno, rowLastnoType, candidateCrnNo,
                     preferredNearRow == null ? 0 : preferredNearRow, locTypeDto);
@@ -1308,7 +1621,7 @@
                 locTypeBlockedCrns.add(candidateCrnNo);
             }
             return findRun2EmptyLocByCrnNosRecursively(rowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
-                    staDescId, sourceStaNo, startupDto, preferredArea, stage, routeRequired, index + 1,
+                    staDescId, sourceStaNo, startupDto, preferredArea, findLocNoAttributeVo, stage, routeRequired, index + 1,
                     crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
         }
         if (targetStaNo != null) {
@@ -1323,7 +1636,7 @@
     private LocMast findRun2EmptyLocByCrnLocTypeEntries(RowLastno rowLastno, RowLastnoType rowLastnoType,
                                                         List<Map<String, Integer>> crnLocTypeEntries, LocTypeDto locTypeDto,
                                                         Integer staDescId, Integer sourceStaNo, StartupDto startupDto,
-                                                        Integer preferredArea, String stage) {
+                                                        Integer preferredArea, String stage, FindLocNoAttributeVo findLocNoAttributeVo) {
         if (Cools.isEmpty(crnLocTypeEntries)) {
             log.warn("run2 skip empty crn-locType list. stage={}, sourceStaNo={}, preferredArea={}, spec={}",
                     stage, sourceStaNo, preferredArea, JSON.toJSONString(locTypeDto));
@@ -1335,14 +1648,14 @@
         List<Integer> noEmptyCrns = new ArrayList<>();
         List<Integer> locTypeBlockedCrns = new ArrayList<>();
         return findRun2EmptyLocByCrnLocTypeEntriesRecursively(rowLastno, rowLastnoType, crnLocTypeEntries, locTypeDto,
-                staDescId, sourceStaNo, startupDto, preferredArea, stage, 0, candidateCrnNos,
+                staDescId, sourceStaNo, startupDto, preferredArea, stage, findLocNoAttributeVo, 0, candidateCrnNos,
                 crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
     }
 
     private LocMast findRun2EmptyLocByCrnLocTypeEntriesRecursively(RowLastno rowLastno, RowLastnoType rowLastnoType,
                                                                    List<Map<String, Integer>> crnLocTypeEntries, LocTypeDto locTypeDto,
                                                                    Integer staDescId, Integer sourceStaNo, StartupDto startupDto,
-                                                                   Integer preferredArea, String stage, int index,
+                                                                   Integer preferredArea, String stage, FindLocNoAttributeVo findLocNoAttributeVo, int index,
                                                                    List<Integer> candidateCrnNos, List<Integer> crnErrorCrns,
                                                                    List<Integer> routeBlockedCrns, List<Integer> noEmptyCrns,
                                                                    List<Integer> locTypeBlockedCrns) {
@@ -1357,20 +1670,20 @@
         if (!isCrnActive(candidateCrnNo)) {
             crnErrorCrns.add(candidateCrnNo);
             return findRun2EmptyLocByCrnLocTypeEntriesRecursively(rowLastno, rowLastnoType, crnLocTypeEntries, locTypeDto,
-                    staDescId, sourceStaNo, startupDto, preferredArea, stage, index + 1, candidateCrnNos,
+                    staDescId, sourceStaNo, startupDto, preferredArea, stage, findLocNoAttributeVo, index + 1, candidateCrnNos,
                     crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
         }
         Integer targetStaNo = resolveTargetStaNo(rowLastno, staDescId, sourceStaNo, candidateCrnNo);
         if (Utils.BooleanWhsTypeSta(rowLastno, staDescId) && targetStaNo == null) {
             routeBlockedCrns.add(candidateCrnNo);
             return findRun2EmptyLocByCrnLocTypeEntriesRecursively(rowLastno, rowLastnoType, crnLocTypeEntries, locTypeDto,
-                    staDescId, sourceStaNo, startupDto, preferredArea, stage, index + 1, candidateCrnNos,
+                    staDescId, sourceStaNo, startupDto, preferredArea, stage, findLocNoAttributeVo, index + 1, candidateCrnNos,
                     crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
         }
         LocTypeDto searchLocTypeDto = buildRun2SearchLocTypeDto(locTypeDto, candidateLocType1);
         Integer preferredNearRow = getCrnStartRow(rowLastno, candidateCrnNo);
         LocMast candidateLoc = findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, candidateCrnNo,
-                preferredNearRow, searchLocTypeDto);
+                preferredNearRow, searchLocTypeDto, findLocNoAttributeVo);
         if (Cools.isEmpty(candidateLoc)) {
             int availableLocCount = countAssignableLocForCrn(rowLastno, rowLastnoType, candidateCrnNo,
                     preferredNearRow == null ? 0 : preferredNearRow, searchLocTypeDto);
@@ -1380,7 +1693,7 @@
                 locTypeBlockedCrns.add(candidateCrnNo);
             }
             return findRun2EmptyLocByCrnLocTypeEntriesRecursively(rowLastno, rowLastnoType, crnLocTypeEntries, locTypeDto,
-                    staDescId, sourceStaNo, startupDto, preferredArea, stage, index + 1, candidateCrnNos,
+                    staDescId, sourceStaNo, startupDto, preferredArea, stage, findLocNoAttributeVo, index + 1, candidateCrnNos,
                     crnErrorCrns, routeBlockedCrns, noEmptyCrns, locTypeBlockedCrns);
         }
         if (targetStaNo != null) {
@@ -1431,6 +1744,12 @@
      */
     private LocMast findRun2OrderedEmptyLocByCrnLocType(RowLastnoType rowLastnoType, Integer candidateCrnNo,
                                                         Short candidateLocType1, LocTypeDto locTypeDto) {
+        return findRun2OrderedEmptyLocByCrnLocType(rowLastnoType, candidateCrnNo, candidateLocType1, locTypeDto, null);
+    }
+
+    private LocMast findRun2OrderedEmptyLocByCrnLocType(RowLastnoType rowLastnoType, Integer candidateCrnNo,
+                                                        Short candidateLocType1, LocTypeDto locTypeDto,
+                                                        FindLocNoAttributeVo findLocNoAttributeVo) {
         if (candidateCrnNo == null) {
             return null;
         }
@@ -1441,20 +1760,18 @@
             wrapper.eq("loc_type1", candidateLocType1);
         }
         applyLocTypeFilters(wrapper, locTypeDto, false);
-        // 鍗曚几鍫嗗灈鏈烘寜灞傘�佸垪閫掑椤哄簭鎵剧涓�涓┖搴撲綅銆�
-        if (rowLastnoType != null && rowLastnoType.getType() != null && (rowLastnoType.getType() == 1 || rowLastnoType.getType() == 2)) {
-            wrapper.orderBy("lev1", true).orderBy("bay1", true);
-        } else {
-            wrapper.orderBy("lev1", true).orderBy("bay1", true);
+        List<LocMast> locMasts = locMastService.selectList(wrapper);
+        List<LocMast> sortedLocMasts = sortLocCandidates(locMasts, findLocNoAttributeVo);
+        for (LocMast candidateLoc : sortedLocMasts) {
+            if (candidateLoc == null) {
+                continue;
+            }
+            if (locTypeDto != null && !VersionUtils.locMoveCheckLocTypeComplete(candidateLoc, locTypeDto)) {
+                continue;
+            }
+            return candidateLoc;
         }
-        LocMast candidateLoc = locMastService.selectOne(wrapper);
-        if (Cools.isEmpty(candidateLoc)) {
-            return null;
-        }
-        if (locTypeDto != null && !VersionUtils.locMoveCheckLocTypeComplete(candidateLoc, locTypeDto)) {
-            return null;
-        }
-        return candidateLoc;
+        return null;
     }
 
     private Optional<CrnRowInfo> findAvailableCrnAndNearRow(RowLastno rowLastno, int curRow, int crnNumber, int times,
@@ -1591,33 +1908,115 @@
     }
 
     /**
-     * 鏌ヨ鏌愪竴鎺掍笂鐨勬墍鏈夌┖搴撲綅锛屽苟鎸夊崟浼�/鍙屼几绛栫暐鎺掑簭銆�
+     * 鏌ヨ鏌愪竴鎺掍笂鐨勬墍鏈夌┖搴撲綅锛屽苟鎸夊崟浼�/鍙屼几绛栫暐涓庨娆℃帓搴忋��
      */
     private List<LocMast> findOpenLocsByRow(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer row,
                                             Integer crnNo, LocTypeDto locTypeDto, boolean singleExtension) {
+        return findOpenLocsByRow(rowLastno, rowLastnoType, row, crnNo, locTypeDto, null, singleExtension, false);
+    }
+
+    private List<LocMast> findOpenLocsByRow(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer row,
+                                            Integer crnNo, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo,
+                                            boolean singleExtension) {
+        return findOpenLocsByRow(rowLastno, rowLastnoType, row, crnNo, locTypeDto, findLocNoAttributeVo, singleExtension, false);
+    }
+
+    private List<LocMast> findOpenLocsByRow(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer row,
+                                            Integer crnNo, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo,
+                                            boolean singleExtension, boolean ignoreFreqType) {
         List<LocMast> result = new ArrayList<LocMast>();
         if (row == null) {
             return result;
         }
         Wrapper<LocMast> wrapper = new EntityWrapper<LocMast>()
-//                .eq("row1", row)
                 .eq("loc_sts", "O");
         if (crnNo != null) {
             wrapper.eq("crn_no", crnNo);
         }
         applyLocTypeFilters(wrapper, locTypeDto, true);
-        if (singleExtension) {
-            wrapper.orderBy("lev1", true).orderBy("bay1", true);
-        } else {
-            wrapper.orderBy("lev1", true).orderBy("bay1", true);
-        }
         List<LocMast> locMasts = locMastService.selectList(wrapper);
-        for (LocMast locMast : locMasts) {
+        List<LocMast> sortedLocMasts = sortLocCandidates(locMasts, findLocNoAttributeVo, ignoreFreqType);
+        for (LocMast locMast : sortedLocMasts) {
             if (matchesLocType(locMast, locTypeDto)) {
                 result.add(locMast);
             }
         }
         return result;
+    }
+
+    private List<LocMast> sortLocCandidates(List<LocMast> locMasts, FindLocNoAttributeVo findLocNoAttributeVo) {
+        return sortLocCandidates(locMasts, findLocNoAttributeVo, false);
+    }
+
+    private List<LocMast> sortLocCandidates(List<LocMast> locMasts, FindLocNoAttributeVo findLocNoAttributeVo, boolean ignoreFreqType) {
+        Integer freqType = ignoreFreqType ? null : (findLocNoAttributeVo == null ? null : findLocNoAttributeVo.getFreqType());
+        return sortLocCandidates(locMasts, freqType, getHighFreqFrontBayCount());
+    }
+
+    private List<LocMast> sortLocCandidates(List<LocMast> locMasts, Integer freqType, Integer frontBayCount) {
+        List<LocMast> result = new ArrayList<LocMast>();
+        if (Cools.isEmpty(locMasts)) {
+            return result;
+        }
+        result.addAll(locMasts);
+
+        Integer normalizedFreqType = normalizeFreqType(freqType);
+        if (normalizedFreqType == null) {
+            result.sort(Comparator
+                    .comparing(LocMast::getLev1, Comparator.nullsLast(Integer::compareTo))
+                    .thenComparing(LocMast::getBay1, Comparator.nullsLast(Integer::compareTo))
+                    .thenComparing(LocMast::getLocNo, Comparator.nullsLast(String::compareTo)));
+            return result;
+        }
+
+        if (Objects.equals(normalizedFreqType, 2)) {
+            result.sort(Comparator
+                    .comparing(LocMast::getLev1, Comparator.nullsLast(Integer::compareTo))
+                    .thenComparing(LocMast::getBay1, Comparator.nullsLast(Comparator.reverseOrder()))
+                    .thenComparing(LocMast::getLocNo, Comparator.nullsLast(String::compareTo)));
+            return result;
+        }
+
+        int normalizedFrontBayCount = frontBayCount == null ? 0 : frontBayCount;
+        if (normalizedFrontBayCount > 0) {
+            result.sort(Comparator
+                    .comparingInt((LocMast loc) -> resolveFrontBayGroup(loc, normalizedFrontBayCount))
+                    .thenComparing(LocMast::getBay1, Comparator.nullsLast(Integer::compareTo))
+                    .thenComparing(LocMast::getLev1, Comparator.nullsLast(Integer::compareTo))
+                    .thenComparing(LocMast::getLocNo, Comparator.nullsLast(String::compareTo)));
+        } else {
+            result.sort(Comparator
+                    .comparing(LocMast::getBay1, Comparator.nullsLast(Integer::compareTo))
+                    .thenComparing(LocMast::getLev1, Comparator.nullsLast(Integer::compareTo))
+                    .thenComparing(LocMast::getLocNo, Comparator.nullsLast(String::compareTo)));
+        }
+        return result;
+    }
+
+    private int resolveFrontBayGroup(LocMast locMast, int frontBayCount) {
+        if (locMast == null || locMast.getBay1() == null || locMast.getBay1() <= 0) {
+            return 1;
+        }
+        return locMast.getBay1() <= frontBayCount ? 0 : 1;
+    }
+
+    private Integer normalizeFreqType(Integer freqType) {
+        if (freqType == null || (freqType != 1 && freqType != 2)) {
+            return null;
+        }
+        return freqType;
+    }
+
+    private int getHighFreqFrontBayCount() {
+        Parameter parameter = Parameter.get();
+        if (parameter == null || Cools.isEmpty(parameter.getHighFreqFrontBayCount())) {
+            return 0;
+        }
+        Integer parsedCount = safeParseInt(parameter.getHighFreqFrontBayCount());
+        if (parsedCount == null || parsedCount <= 0) {
+            return 0;
+        }
+        return parsedCount;
     }
 
     /**
@@ -1635,10 +2034,6 @@
         if (crnNo != null) {
             wrapper.eq("crn_no", crnNo);
         }
-        Long whsType = resolveLocWhsType(rowLastno, rowLastnoType);
-        if (whsType != null) {
-            wrapper.eq("whs_type", whsType);
-        }
         if (statuses != null && statuses.length > 0) {
             if (statuses.length == 1) {
                 wrapper.eq("loc_sts", statuses[0]);
@@ -1650,11 +2045,105 @@
     }
 
     /**
+     * 鍙屼几鍫嗗灈鏈哄悓璐т紭鍏堬細
+     * 鍏堟壘娣卞簱浣嶄腑 standby1 鐩稿悓涓旂姸鎬佷负 F 鐨勮揣浣嶏紝鍐嶆鏌ュ叾瀵瑰簲娴呭簱浣嶆槸鍚︿负绌恒��
+     */
+    private LocMast findDoubleExtensionSameGoodsPreferredLoc(RowLastno rowLastno, RowLastnoType rowLastnoType,
+                                                             Integer crnNo, CrnDepthRuleProfile profile,
+                                                             LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo) {
+        if (profile == null || !profile.isDoubleExtension() || findLocNoAttributeVo == null
+                || Cools.isEmpty(findLocNoAttributeVo.getStandby1())) {
+            return null;
+        }
+        String standby1 = findLocNoAttributeVo.getStandby1();
+        LinkedHashSet<Integer> processedDeepRows = new LinkedHashSet<Integer>();
+        for (Integer searchRow : profile.getSearchRows()) {
+            if (searchRow == null || !profile.isDeepRow(searchRow) || !processedDeepRows.add(searchRow)) {
+                continue;
+            }
+            Integer shallowRow = profile.getPairedShallowRow(searchRow);
+            if (shallowRow == null) {
+                continue;
+            }
+            List<LocMast> deepLocs = findOccupiedLocsByRow(searchRow, crnNo, findLocNoAttributeVo);
+            if (Cools.isEmpty(deepLocs)) {
+                continue;
+            }
+            List<String> deepLocNos = new ArrayList<String>();
+            for (LocMast deepLoc : deepLocs) {
+                if (deepLoc == null || Cools.isEmpty(deepLoc.getLocNo())) {
+                    continue;
+                }
+                deepLocNos.add(deepLoc.getLocNo());
+            }
+            if (Cools.isEmpty(deepLocNos)) {
+                continue;
+            }
+            List<LocDetl> sameGoodsLocDetls = locDetlService.selectList(new EntityWrapper<LocDetl>()
+                    .eq("standby1", standby1)
+                    .in("loc_no", deepLocNos));
+            if (Cools.isEmpty(sameGoodsLocDetls)) {
+                continue;
+            }
+            LinkedHashSet<String> sameGoodsLocNos = new LinkedHashSet<String>();
+            for (LocDetl locDetl : sameGoodsLocDetls) {
+                if (locDetl == null || Cools.isEmpty(locDetl.getLocNo())) {
+                    continue;
+                }
+                sameGoodsLocNos.add(locDetl.getLocNo());
+            }
+            if (Cools.isEmpty(sameGoodsLocNos)) {
+                continue;
+            }
+            for (LocMast deepLoc : deepLocs) {
+                if (deepLoc == null || !sameGoodsLocNos.contains(deepLoc.getLocNo())) {
+                    continue;
+                }
+                LocMast shallowLoc = findLocByPosition(rowLastno, rowLastnoType, crnNo, shallowRow,
+                        deepLoc.getBay1(), deepLoc.getLev1(), "O");
+                if (!Cools.isEmpty(shallowLoc) && matchesLocType(shallowLoc, locTypeDto)) {
+                    return shallowLoc;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 鏌ヨ鏌愪竴鎺掍笂鐘舵�佷负 F 鐨勫簱浣嶏紝骞舵寜褰撳墠棰戞/鍓嶅嚑鍒楃瓥鐣ユ帓搴忋��
+     */
+    private List<LocMast> findOccupiedLocsByRow(Integer row, Integer crnNo, FindLocNoAttributeVo findLocNoAttributeVo) {
+        List<LocMast> result = new ArrayList<LocMast>();
+        if (row == null) {
+            return result;
+        }
+        Wrapper<LocMast> wrapper = new EntityWrapper<LocMast>()
+                .eq("row1", row)
+                .eq("loc_sts", "F");
+        if (crnNo != null) {
+            wrapper.eq("crn_no", crnNo);
+        }
+        List<LocMast> locMasts = locMastService.selectList(wrapper);
+        return sortLocCandidates(locMasts, findLocNoAttributeVo, false);
+    }
+
+    /**
      * 鍦ㄤ竴瀵规祬鎺�/娣辨帓涔嬮棿閫夋嫨鐪熸鍙姇鏀剧殑鐩爣搴撲綅銆�
+     *
+     * 鍙屼几浣嶈鍒欙細
+     * 1. 娴呬綅鍜屾繁浣嶅悓鍒楀悓灞傞兘涓虹┖鏃讹紝浼樺厛杩斿洖娣变綅锛岄伩鍏嶆祬浣嶅厛鍗犱綇鍚庢尅浣忔繁浣嶃��
+     * 2. 娣变綅宸叉湁璐ф椂锛屽厑璁歌繑鍥炲搴旀祬浣嶃��
+     * 3. 娣变綅涓虹┖浣嗚鏍间笉鍖归厤鏃讹紝涓嶆妸娴呬綅浣滀负鍙姇鏀剧粨鏋滐紝缁х画鎵句笅涓�缁勫悓鍒楀悓灞備綅缃��
      */
     private LocMast findPairAssignableLoc(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo,
                                           Integer shallowRow, Integer deepRow, LocTypeDto locTypeDto) {
-        List<LocMast> shallowOpenLocs = findOpenLocsByRow(rowLastno, rowLastnoType, shallowRow, crnNo, locTypeDto, false);
+        return findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, shallowRow, deepRow, locTypeDto, null);
+    }
+
+    private LocMast findPairAssignableLoc(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo,
+                                          Integer shallowRow, Integer deepRow, LocTypeDto locTypeDto,
+                                          FindLocNoAttributeVo findLocNoAttributeVo) {
+        List<LocMast> shallowOpenLocs = findOpenLocsByRow(rowLastno, rowLastnoType, shallowRow, crnNo, locTypeDto, findLocNoAttributeVo, false);
         if (Cools.isEmpty(shallowOpenLocs)) {
             return null;
         }
@@ -1668,11 +2157,8 @@
             }
         }
         for (LocMast shallowLoc : shallowOpenLocs) {
-            LocMast deepBlockingLoc = findLocByPosition(rowLastno, rowLastnoType, crnNo, deepRow, shallowLoc.getBay1(), shallowLoc.getLev1(), "F", "D");
-            if (!Cools.isEmpty(deepBlockingLoc)) {
-                return shallowLoc;
-            }
-            if (findLocByPosition(rowLastno, rowLastnoType, crnNo, deepRow, shallowLoc.getBay1(), shallowLoc.getLev1()) == null) {
+            LocMast deepInStockLoc = findLocByPosition(rowLastno, rowLastnoType, crnNo, deepRow, shallowLoc.getBay1(), shallowLoc.getLev1(), "F");
+            if (!Cools.isEmpty(deepInStockLoc)) {
                 return shallowLoc;
             }
         }
@@ -1681,15 +2167,37 @@
 
     /**
      * 鎸夋煇鍙板爢鍨涙満鐨勬繁娴呮帓鐢诲儚鎼滅储绗竴涓彲鍒嗛厤绌哄簱浣嶃��
+     *
+     * 杩欐槸绌烘墭鐩樻渶缁堣惤搴撲綅鐨勬牳蹇冮�夋嫨鏂规硶锛�
+     * 1. 鍏堣鍙栧爢鍨涙満娣辨祬搴撲綅瑙勫垯鐢诲儚锛屽緱鍒拌鍫嗗灈鏈烘湰娆″簲鎵弿鐨勬帓椤哄簭銆�
+     * 2. 鍙屼几鍫嗗灈鏈哄厛灏濊瘯鍚岃揣浼樺厛瑙勫垯锛屽啀鎸夋祬鎺�/娣辨帓鎴愬鍒ゆ柇鍙姇鏀句綅缃��
+     * 3. 鍗曚几鍫嗗灈鏈虹洿鎺ユ寜鎺掑唴鎺掑簭鍚庣殑绌哄簱浣嶈繑鍥炵涓�涓尮閰嶉」銆�
+     * 4. 鎺掑唴鎺掑簭浼氱户缁彈棰戞銆佸墠鍑犲垪绛栫暐鍜� locType 杩囨护褰卞搷銆�
      */
     private LocMast findConfiguredEmptyLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo,
-                                                 Integer preferredNearRow, LocTypeDto locTypeDto) {
+                                                  Integer preferredNearRow, LocTypeDto locTypeDto) {
+        return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, preferredNearRow, locTypeDto, null, false);
+    }
+
+    private LocMast findConfiguredEmptyLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo,
+                                                  Integer preferredNearRow, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo) {
+        return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, preferredNearRow, locTypeDto, findLocNoAttributeVo, false);
+    }
+
+    private LocMast findConfiguredEmptyLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, Integer crnNo,
+                                                 Integer preferredNearRow, LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo,
+                                                 boolean ignoreFreqType) {
         if (rowLastno == null || crnNo == null) {
             return null;
         }
         CrnDepthRuleProfile profile = basCrnDepthRuleService.resolveProfile(rowLastno, crnNo, preferredNearRow);
         if (profile == null || Cools.isEmpty(profile.getSearchRows())) {
             return null;
+        }
+        LocMast sameGoodsPreferredLoc = findDoubleExtensionSameGoodsPreferredLoc(rowLastno, rowLastnoType, crnNo,
+                profile, locTypeDto, findLocNoAttributeVo);
+        if (!Cools.isEmpty(sameGoodsPreferredLoc)) {
+            return sameGoodsPreferredLoc;
         }
         LinkedHashSet<Integer> processedShallowRows = new LinkedHashSet<Integer>();
         boolean singleExtension = profile.isSingleExtension();
@@ -1703,7 +2211,7 @@
                         continue;
                     }
                     LocMast candidateLoc = findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, searchRow,
-                            profile.getPairedDeepRow(searchRow), locTypeDto);
+                            profile.getPairedDeepRow(searchRow), locTypeDto, findLocNoAttributeVo);
                     if (!Cools.isEmpty(candidateLoc)) {
                         return candidateLoc;
                     }
@@ -1716,7 +2224,7 @@
                             continue;
                         }
                         LocMast candidateLoc = findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, shallowRow,
-                                searchRow, locTypeDto);
+                                searchRow, locTypeDto, findLocNoAttributeVo);
                         if (!Cools.isEmpty(candidateLoc)) {
                             return candidateLoc;
                         }
@@ -1724,7 +2232,7 @@
                     }
                 }
             }
-            List<LocMast> locMasts = findOpenLocsByRow(rowLastno, rowLastnoType, searchRow, crnNo, locTypeDto, singleExtension);
+            List<LocMast> locMasts = findOpenLocsByRow(rowLastno, rowLastnoType, searchRow, crnNo, locTypeDto, findLocNoAttributeVo, singleExtension, ignoreFreqType);
             if (!Cools.isEmpty(locMasts)) {
                 return locMasts.get(0);
             }
@@ -1791,9 +2299,8 @@
                 count++;
                 continue;
             }
-            LocMast deepBlockingLoc = findLocByPosition(rowLastno, rowLastnoType, crnNo, deepRow, shallowLoc.getBay1(), shallowLoc.getLev1(), "F", "D");
-            if (!Cools.isEmpty(deepBlockingLoc) ||
-                    findLocByPosition(rowLastno, rowLastnoType, crnNo, deepRow, shallowLoc.getBay1(), shallowLoc.getLev1()) == null) {
+            LocMast deepInStockLoc = findLocByPosition(rowLastno, rowLastnoType, crnNo, deepRow, shallowLoc.getBay1(), shallowLoc.getLev1(), "F");
+            if (!Cools.isEmpty(deepInStockLoc)) {
                 count++;
             }
         }
@@ -1922,7 +2429,12 @@
      * run/run2 鏍囧噯鍫嗗灈鏈虹粺涓�鐨勭┖搴撲綅鏌ヨ鍏ュ彛銆�
      */
     private LocMast findStandardEmptyLoc(RowLastno rowLastno, RowLastnoType rowLastnoType, int crnNo, int nearRow, LocTypeDto locTypeDto) {
-        return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto);
+        return findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto, null);
+    }
+
+    private LocMast findStandardEmptyLoc(RowLastno rowLastno, RowLastnoType rowLastnoType, int crnNo, int nearRow,
+                                         LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo) {
+        return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto, findLocNoAttributeVo);
     }
 
     /**
@@ -2038,7 +2550,7 @@
         if (signRule1) {
             if (nearRow != curRow) {
                 List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
-                        .eq("row1", nearRow).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()));
+                        .eq("row1", nearRow).eq("loc_sts", "O"));
                 for (LocMast locMast1 : locMasts) {
                     //鑾峰彇宸烽亾
 //                    List<String> groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,locMast1.getLocNo(), curRow>nearRow);
@@ -2080,7 +2592,7 @@
         // 闈犺繎鎽嗘斁瑙勫垯 --- 绌烘墭 //浜掗�氱増
         if (staDescId == 10 && Utils.BooleanWhsTypeStaIoType(rowLastno)) {
             List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
-                    .eq("loc_sts", "D").ge("row1", sRow).le("row1", eRow).eq("whs_type", rowLastnoType.getType().longValue()));
+                    .eq("loc_sts", "D").ge("row1", sRow).le("row1", eRow));
             if (!locMasts.isEmpty()) {
                 for (LocMast loc : locMasts) {
                     if (Utils.isShallowLoc(slaveProperties, loc.getLocNo())) {
@@ -2135,13 +2647,13 @@
 
         // Search empty location ==============================>>
         if (staDescId == 10 && Cools.isEmpty(locMast) && crnNo != 0) {
-            locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto);
+            locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto, findLocNoAttributeVo);
         }
 
 
 
         if (Cools.isEmpty(locMast) && crnNo != 0) {
-            locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto);
+            locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto, findLocNoAttributeVo);
         }
 
         if (!Cools.isEmpty(locMast) && !basCrnpService.checkSiteError(crnNo, true)) {
@@ -2183,21 +2695,15 @@
      * run2 鍏ュ簱鎵句綅涓绘祦绋嬨��
      *
      * 褰撳墠鏂规硶鍙繚鐣欌�滅粍缁囨祦绋嬧�濆拰鈥滅粺涓�鏀跺彛鈥濈殑鑱岃矗锛屽叿浣撶瓥鐣ユ媶鎴愮嫭绔嬫柟娉曪細
-     * 1. 鏅�氱墿鏂欙細鎸� row_lastno 鑷韩杞椤哄簭 -> 绔欑偣浼樺厛搴撳尯/鍫嗗灈鏈� -> 鍏跺畠搴撳尯銆�
-     * 2. 绌烘墭鐩橈細浼樺厛搴撳尯 loc_type2=1 -> 鍏跺畠搴撳尯 loc_type2=1 -> loc_type1=2 鍏煎銆�
-     * 3. 鍛戒腑搴撲綅鍚庡垎鍒洖鍐欐櫘閫氱墿鏂欐父鏍囨垨绌烘墭鐩樺簱鍖烘父鏍囥��
-     *
-     * WCS 浼犲叆鐨勬帹鑽愭帓涓嶅啀鍙備笌 run2 閫変綅锛岄伩鍏嶄笂娓� row 鍙傛暟鎶婁换鍔¢噸鏂扮粦鍥炲浐瀹氬爢鍨涙満銆�
+     * 1. 鍏堟寜绔欑偣绗竴浼樺厛姹犳壘浣嶏紝鍐嶆壘绗簩浼樺厛姹犮��
+     * 2. 姹犲唴鎸� current_no 杞浆锛屼粠涓嬩竴鍙板爢鍨涙満寮�濮嬪钩鍧囧垎閰嶃��
+     * 3. 绌烘墭鐩樼敱 matnr=emptyPallet 鎴� staDescId=10 璇嗗埆锛屽厛鎵剧獎搴撲綅锛屽け璐ュ悗鐢� loc_type1=3 鍏滃簳銆�
+     * 4. 鏅�氭墭鐩樺彧鍋� loc_type1 鍚戜笂鍏煎锛屽苟鎺掗櫎绌烘墭鐩樹笓鐢ㄧ獎搴撲綅銆�
      */
+    @Transactional
     public StartupDto getLocNoRun2(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, List<Integer> recommendRows, int times) {
-
-        int crnNo = 0;
-        int nearRow = 0;
-        LocMast locMast = null;
-
         StartupDto startupDto = new StartupDto();
         RowLastno rowLastno = rowLastnoService.selectById(whsType);
-
         if (Cools.isEmpty(rowLastno)) {
             throw new CoolException("鏁版嵁寮傚父锛岃鑱旂郴绠$悊鍛�===>搴撲綅瑙勫垯鏈煡");
         }
@@ -2205,59 +2711,33 @@
         if (Cools.isEmpty(rowLastnoType)) {
             throw new CoolException("鏁版嵁寮傚父锛岃鑱旂郴绠$悊鍛�===銆嬪簱浣嶈鍒欑被鍨嬫湭鐭�");
         }
-        int curRow = rowLastno.getCurrentRow() == null ? 0 : rowLastno.getCurrentRow();
-        crnNo = resolveRun2CrnNo(rowLastno);
-        Integer preferredArea = findLocNoAttributeVo.getOutArea();
+        BasDevp station = basDevpService.selectById(sourceStaNo);
+        if (Cools.isEmpty(station)) {
+            throw new CoolException("绔欑偣=" + sourceStaNo + " 鏈厤缃叆搴撲紭鍏堝爢鍨涙満");
+        }
+        List<Integer> firstPoolCrnNos = loadPriorityCrnNos(station.getInFirstCrnCsv());
+        List<Integer> secondPoolCrnNos = loadPriorityCrnNos(station.getInSecondCrnCsv());
+        if (Cools.isEmpty(firstPoolCrnNos) && Cools.isEmpty(secondPoolCrnNos)) {
+            throw new CoolException("绔欑偣=" + sourceStaNo + " 鏈厤缃叆搴撲紭鍏堝爢鍨涙満");
+        }
         boolean emptyPalletRequest = isEmptyPalletRequest(staDescId, findLocNoAttributeVo);
-        Run2AreaSearchResult emptyPalletAreaSearchResult = null;
-        Run2SearchResult normalRun2SearchResult = null;
-
-        List<Integer> orderedCrnNos = getOrderedCrnNos(rowLastno, crnNo);
-        List<Integer> orderedRunnableCrnNos = getOrderedRunnableRun2CrnNos(rowLastno, staDescId, sourceStaNo, orderedCrnNos);
-        if (emptyPalletRequest) {
-            emptyPalletAreaSearchResult = findEmptyPalletRun2Loc(rowLastno, staDescId, sourceStaNo, startupDto, preferredArea, locTypeDto);
-            if (!Cools.isEmpty(emptyPalletAreaSearchResult)) {
-                locMast = emptyPalletAreaSearchResult.locMast;
-            }
-        } else {
-            normalRun2SearchResult = findNormalRun2Loc(rowLastno, rowLastnoType, sourceStaNo, staDescId, findLocNoAttributeVo,
-                    locTypeDto, startupDto, preferredArea, orderedCrnNos);
-            if (normalRun2SearchResult != null) {
-                locMast = normalRun2SearchResult.locMast;
-            }
-        }
-
-        if (!Cools.isEmpty(locMast)) {
-            crnNo = locMast.getCrnNo();
-            nearRow = locMast.getRow1();
-        }
-        if (emptyPalletRequest) {
-            advanceEmptyPalletRun2Cursor(emptyPalletAreaSearchResult, locMast);
-        } else if (!Cools.isEmpty(locMast)) {
-            List<Integer> cursorCrnNos = normalRun2SearchResult == null || Cools.isEmpty(normalRun2SearchResult.runnableCrnNos)
-                    ? orderedRunnableCrnNos
-                    : normalRun2SearchResult.runnableCrnNos;
-            advanceNormalRun2Cursor(rowLastno, curRow, cursorCrnNos, locMast.getCrnNo());
-        }
-
+        LocMast locMast = findRun2PriorityLocInPools(station, rowLastno, rowLastnoType, staDescId, sourceStaNo,
+                findLocNoAttributeVo, locTypeDto, startupDto, emptyPalletRequest);
         if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) {
             if (emptyPalletRequest) {
-                log.error("No empty location found. spec={}, preferredArea={}, nearRow={}",
-                        JSON.toJSONString(locTypeDto), preferredArea, nearRow);
+                log.error("No empty location found. spec={}, station={}, firstPool={}, secondPool={}",
+                        JSON.toJSONString(locTypeDto), sourceStaNo, JSON.toJSONString(firstPoolCrnNos),
+                        JSON.toJSONString(secondPoolCrnNos));
                 throw new CoolException("娌℃湁绌哄簱浣�");
             }
-            LocTypeDto compatibleLocTypeDto = buildRetryCompatibleLocTypeDto(staDescId, findLocNoAttributeVo, locTypeDto);
-            if (compatibleLocTypeDto != null) {
-                log.warn("locType compatibility retry. source={}, target={}", JSON.toJSONString(locTypeDto), JSON.toJSONString(compatibleLocTypeDto));
-                return getLocNoRun2(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, compatibleLocTypeDto, recommendRows, 0);
-            }
-            log.error("No empty location found. spec={}, preferredArea={}, nearRow={}", JSON.toJSONString(locTypeDto), preferredArea, nearRow);
+            log.error("No empty location found. spec={}, station={}, firstPool={}, secondPool={}",
+                    JSON.toJSONString(locTypeDto), sourceStaNo, JSON.toJSONString(firstPoolCrnNos), JSON.toJSONString(secondPoolCrnNos));
             throw new CoolException("娌℃湁绌哄簱浣�");
         }
 
         int workNo = getWorkNo(0);
         startupDto.setWorkNo(workNo);
-        startupDto.setCrnNo(crnNo);
+        startupDto.setCrnNo(locMast.getCrnNo());
         startupDto.setSourceStaNo(sourceStaNo);
         startupDto.setLocNo(locMast.getLocNo());
         return startupDto;
@@ -2266,7 +2746,12 @@
      * 鍗曚几鍫嗗灈鏈哄鐢ㄧ粺涓�鐢诲儚绠楁硶鏌ヨ绌哄簱浣嶃��
      */
     private LocMast findSingleExtensionEmptyLoc(RowLastno rowLastno, int crnNo, int nearRow, RowLastnoType rowLastnoType, LocTypeDto locTypeDto) {
-        return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto);
+        return findSingleExtensionEmptyLoc(rowLastno, crnNo, nearRow, rowLastnoType, locTypeDto, null);
+    }
+
+    private LocMast findSingleExtensionEmptyLoc(RowLastno rowLastno, int crnNo, int nearRow, RowLastnoType rowLastnoType,
+                                                LocTypeDto locTypeDto, FindLocNoAttributeVo findLocNoAttributeVo) {
+        return findConfiguredEmptyLocForCrn(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto, findLocNoAttributeVo);
     }
 
     public StartupDto getLocNoRun4(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, int times) {
@@ -2311,7 +2796,7 @@
             crnNo = locNecessaryParameters[2];
             nearRow = locNecessaryParameters[3];
             List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
-                    .eq("crn_no", crnNo).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()));
+                    .eq("crn_no", crnNo).eq("loc_sts", "O"));
             if (locMasts.size() <= 5) {
                 nearRow = 0;
                 times++;
@@ -2472,7 +2957,7 @@
         if (signRule1) {
             if (nearRow != curRow) {
                 List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
-                        .eq("row1", nearRow).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()));
+                        .eq("row1", nearRow).eq("loc_sts", "O"));
                 for (LocMast locMast1 : locMasts) {
                     //鑾峰彇宸烽亾
 //                    List<String> groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,locMast1.getLocNo(), curRow>nearRow);
@@ -2643,7 +3128,7 @@
         if (Cools.isEmpty(locMast) && crnNo != 0) {
             List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
                     .eq("row1", nearRow)
-                    .eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue())
+                    .eq("loc_sts", "O")
                     .orderBy("lev1", true).orderBy("bay1", true));//鏈�娴呭簱浣�
             for (LocMast locMast1 : locMasts) {
                 if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
@@ -2791,36 +3276,27 @@
 
         // 寮�濮嬫煡鎵惧簱浣� ==============================>>
 
-        Integer preferredArea = findLocNoAttributeVo.getOutArea();
+        Integer preferredArea = findLocNoAttributeVo == null ? null : findLocNoAttributeVo.getOutArea();
+        List<Integer> areaSearchOrder = buildAreaSearchOrder(findLocNoAttributeVo == null ? null : findLocNoAttributeVo.getOutAreas(), preferredArea);
 
-        if (Cools.isEmpty(locMast) && preferredArea == null) {
-            List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
-                    .eq("row1", nearRow)
-                    .eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue())
-                    .orderBy("lev1", true).orderBy("bay1", true)); // 鏈�娴呭簱浣�
-            for (LocMast locMast1 : locMasts) {
-                if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
+        if (Cools.isEmpty(locMast)) {
+            for (Integer area : areaSearchOrder) {
+                int[] bayRange = getAgvAreaBayRange(area);
+                List<Integer> areaRows = getAgvAreaRows(area, rowLastno);
+                if (Cools.isEmpty(areaRows)) {
                     continue;
                 }
-                if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
-                    // 鑾峰彇鐩爣搴撲綅鎵�鍦ㄥ贩閬撴渶娣辩┖搴撲綅
-                    LocMast locMast2 = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue());
-                    if (!Cools.isEmpty(locMast2) && locMast2.getRow1() == curRow) {
-                        locMast = locMast2;
-                        break;
-                    }
+                locMast = findAgvLocByRows(rowLastno, rowLastnoType, areaRows,
+                        bayRange[0], bayRange[1], curRow, nearRow, locTypeDto, findLocNoAttributeVo, false);
+                if (!Cools.isEmpty(locMast)) {
+                    crnNo = locMast.getCrnNo();
+                    preferredArea = area;
+                    break;
                 }
-            }
-        } else if (Cools.isEmpty(locMast)) {
-            int[] bayRange = getAgvAreaBayRange(preferredArea);
-            locMast = findAgvLocByRows(rowLastno, rowLastnoType, getAgvAreaRows(preferredArea, rowLastno),
-                    bayRange[0], bayRange[1], curRow, nearRow, locTypeDto, false);
-            if (!Cools.isEmpty(locMast)) {
-                crnNo = locMast.getCrnNo();
             }
             if (Cools.isEmpty(locMast)) {
                 locMast = findAgvLocByRows(rowLastno, rowLastnoType, getAgvFallbackRows(rowLastno),
-                        1, 19, curRow, nearRow, locTypeDto, true);
+                        1, 19, curRow, nearRow, locTypeDto, findLocNoAttributeVo, true);
                 if (!Cools.isEmpty(locMast)) {
                     crnNo = locMast.getCrnNo();
                 }

--
Gitblit v1.9.1