From b176072388747abb438990157bfa305b215b4b90 Mon Sep 17 00:00:00 2001
From: zwl <1051256694@qq.com>
Date: 星期二, 14 四月 2026 21:59:39 +0800
Subject: [PATCH] 我们现在讨论一下系统找库位方案, 如何实现,对现有找库位规则进行整改,数据库也要整改 1、要能方便的填写单伸堆垛机或双伸堆垛机的深浅库位配置 2、根据设备状态分配库位,离线设备不分配 3、库位分配要均衡到每一个设备  4、库位高度需要匹配到对应库位信息,低库位能向上兼容  5、空托盘优先放在locType2库位=1的库位,没有这种库位了,允许放到其他库位 6、给入库站点设置有限去那些堆垛机,其次去那些堆垛机,弄成页面可以配置入库站点 7、在系统配置新增优先放前几列的配置,当入库的货物是高频货物时放在前几列 8、组托中会标识该托盘是高频还是低频,如果是高频则从前往后找库位,如果是低频则从后往前找库位 9、找库位时locMast中whsType字段无用

---
 src/main/java/com/zy/common/service/CommonService.java |  781 ++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 542 insertions(+), 239 deletions(-)

diff --git a/src/main/java/com/zy/common/service/CommonService.java b/src/main/java/com/zy/common/service/CommonService.java
index c9a4cac..b0132dd 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;
 
 /**
@@ -185,6 +188,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);
@@ -250,7 +255,7 @@
         }
         StartupDto startupDto = new StartupDto();
         LocMast locMast = findRun2EmptyLocByCrnNos(searchRowLastno, rowLastnoType, candidateCrnNos, locTypeDto,
-                staDescId, sourceStaNo, startupDto, preferredArea, "reassign-inbound");
+                staDescId, sourceStaNo, startupDto, preferredArea, null, "reassign-inbound");
         if (Cools.isEmpty(locMast) || !"O".equals(locMast.getLocSts())) {
             return null;
         }
@@ -310,30 +315,37 @@
     /**
      * 绌烘墭鐩樺浐瀹氭寜 4 娈靛紡鎵句綅锛�
      * 1. 涓ユ牸楂樺害 + narrow
-     * 2. 涓ユ牸楂樺害 + any locType2
-     * 3. 鍚戜笂鍏煎楂樺害 + narrow
-     * 4. 鍚戜笂鍏煎楂樺害 + any locType2
+     * 2. 鍚戜笂鍏煎楂樺害 + narrow
+     * 3. 涓ユ牸楂樺害 + open
+     * 4. 鍚戜笂鍏煎楂樺害 + 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 openStrictLocType = copyLocTypeDto(baseLocTypeDto);
+        openStrictLocType.setLocType2((short) 0);
+        searchLocTypes.add(openStrictLocType);
+
+        LocTypeDto openCompatibleLocType = buildUpwardCompatibleLocTypeDto(openStrictLocType);
+        if (openCompatibleLocType != null) {
+            openCompatibleLocType.setLocType2((short) 0);
+            searchLocTypes.add(openCompatibleLocType);
+        }
+        return searchLocTypes;
     }
 
     private String buildEmptyPalletStageCode(LocTypeDto baseLocTypeDto, LocTypeDto stageLocTypeDto) {
@@ -385,45 +397,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;
     }
 
     /**
@@ -584,6 +570,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;
@@ -596,7 +588,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;
                 }
@@ -953,13 +946,236 @@
     }
 
     /**
-     * 鏋勯�犵┖鎵樼洏璺ㄥ簱鍖烘悳绱㈤『搴忥細
-     * 鍏堝綋鍓嶅簱鍖猴紝鍐嶄緷娆¤ˉ瓒冲叾瀹冨簱鍖猴紝閬垮厤閲嶅銆�
+     * 璇诲彇绔欑偣閰嶇疆鐨勪紭鍏堟睜鍫嗗灈鏈哄彿骞跺仛鍘婚噸銆�
      */
-    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;
+    }
+
+    /**
+     * 鎸夌涓�浼樺厛姹� -> 绗簩浼樺厛姹犵殑椤哄簭鏌ユ壘鍙敤搴撲綅銆�
+     */
+    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);
+    }
+
+    /**
+     * 鍦ㄥ崟涓紭鍏堟睜鍐呮寜杞浆椤哄簭鎵句綅銆�
+     */
+    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;
+    }
+
+    /**
+     * 鍦ㄥ崟涓紭鍏堟睜鍐呭厛鎸夊綋鍓嶈鏍兼壘浣嶏紝澶辫触鍚庡啀鍋氫竴娆� locType1 鍚戜笂鍏煎銆�
+     */
+    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);
@@ -968,7 +1184,7 @@
     }
 
     /**
-     * 棰勮 run2 褰撳墠浼氬弬涓庣殑搴撳尯銆佸爢鍨涙満椤哄簭鍜屾繁娴呮帓鐢诲儚锛屼笉钀戒换鍔℃。銆�
+     * 棰勮 run2 褰撳墠浼氬弬涓庣殑浼樺厛姹犮�佸爢鍨涙満椤哄簭鍜屾繁娴呮帓鐢诲儚锛屼笉钀戒换鍔℃。銆�
      */
     public Map<String, Object> previewRun2Allocation(BasCrnDepthRuleRuntimePreviewParam param) {
         if (param == null || param.getStaDescId() == null || param.getSourceStaNo() == null) {
@@ -977,6 +1193,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());
@@ -990,68 +1207,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;
     }
 
@@ -1059,7 +1274,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;
@@ -1076,7 +1298,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));
@@ -1112,11 +1334,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;
             }
@@ -1125,9 +1348,12 @@
     }
 
     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;
@@ -1144,7 +1370,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);
             }
@@ -1184,7 +1410,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)));
@@ -1198,7 +1424,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);
     }
 
@@ -1296,12 +1523,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));
@@ -1312,14 +1546,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()) {
@@ -1331,19 +1566,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);
@@ -1353,7 +1588,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) {
@@ -1368,7 +1603,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));
@@ -1380,14 +1615,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) {
@@ -1402,20 +1637,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);
@@ -1425,7 +1660,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) {
@@ -1476,6 +1711,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;
         }
@@ -1486,20 +1727,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,
@@ -1636,33 +1875,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;
     }
 
     /**
@@ -1680,10 +2001,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]);
@@ -1699,7 +2016,13 @@
      */
     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;
         }
@@ -1728,7 +2051,18 @@
      * 鎸夋煇鍙板爢鍨涙満鐨勬繁娴呮帓鐢诲儚鎼滅储绗竴涓彲鍒嗛厤绌哄簱浣嶃��
      */
     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;
         }
@@ -1748,7 +2082,7 @@
                         continue;
                     }
                     LocMast candidateLoc = findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, searchRow,
-                            profile.getPairedDeepRow(searchRow), locTypeDto);
+                            profile.getPairedDeepRow(searchRow), locTypeDto, findLocNoAttributeVo);
                     if (!Cools.isEmpty(candidateLoc)) {
                         return candidateLoc;
                     }
@@ -1761,7 +2095,7 @@
                             continue;
                         }
                         LocMast candidateLoc = findPairAssignableLoc(rowLastno, rowLastnoType, crnNo, shallowRow,
-                                searchRow, locTypeDto);
+                                searchRow, locTypeDto, findLocNoAttributeVo);
                         if (!Cools.isEmpty(candidateLoc)) {
                             return candidateLoc;
                         }
@@ -1769,7 +2103,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);
             }
@@ -1967,7 +2301,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);
     }
 
     /**
@@ -2083,7 +2422,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);
@@ -2125,7 +2464,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())) {
@@ -2180,13 +2519,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)) {
@@ -2228,21 +2567,15 @@
      * run2 鍏ュ簱鎵句綅涓绘祦绋嬨��
      *
      * 褰撳墠鏂规硶鍙繚鐣欌�滅粍缁囨祦绋嬧�濆拰鈥滅粺涓�鏀跺彛鈥濈殑鑱岃矗锛屽叿浣撶瓥鐣ユ媶鎴愮嫭绔嬫柟娉曪細
-     * 1. 鏅�氱墿鏂欙細鎸� row_lastno 鑷韩杞椤哄簭 -> 绔欑偣浼樺厛搴撳尯/鍫嗗灈鏈� -> 鍏跺畠搴撳尯銆�
-     * 2. 绌烘墭鐩橈細浼樺厛搴撳尯 loc_type2=1 -> 鍏跺畠搴撳尯 loc_type2=1 -> loc_type1=2 鍏煎銆�
-     * 3. 鍛戒腑搴撲綅鍚庡垎鍒洖鍐欐櫘閫氱墿鏂欐父鏍囨垨绌烘墭鐩樺簱鍖烘父鏍囥��
-     *
-     * WCS 浼犲叆鐨勬帹鑽愭帓涓嶅啀鍙備笌 run2 閫変綅锛岄伩鍏嶄笂娓� row 鍙傛暟鎶婁换鍔¢噸鏂扮粦鍥炲浐瀹氬爢鍨涙満銆�
+     * 1. 鍏堟寜绔欑偣绗竴浼樺厛姹犳壘浣嶏紝鍐嶆壘绗簩浼樺厛姹犮��
+     * 2. 姹犲唴鎸� current_no 杞浆锛屼粠涓嬩竴鍙板爢鍨涙満寮�濮嬪钩鍧囧垎閰嶃��
+     * 3. 绌烘墭鐩樺厛鎸� loc_type2=1 鎼滅储锛屽悓姹犳棤缁撴灉鍐嶅厑璁稿叾瀹冨簱浣嶃��
+     * 4. 浣庡簱浣嶅彲鍚戜笂鍏煎锛屽吋瀹归噸璇曚粛淇濇寔涓ゅ眰浼樺厛姹犻『搴忋��
      */
+    @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("鏁版嵁寮傚父锛岃鑱旂郴绠$悊鍛�===>搴撲綅瑙勫垯鏈煡");
         }
@@ -2250,59 +2583,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;
@@ -2311,7 +2618,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) {
@@ -2356,7 +2668,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++;
@@ -2517,7 +2829,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);
@@ -2688,7 +3000,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)) {
@@ -2836,36 +3148,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