From 9b8ba51387d0a8db467bafaf7ecd09d93bded873 Mon Sep 17 00:00:00 2001
From: skyouc
Date: 星期一, 28 四月 2025 13:23:37 +0800
Subject: [PATCH] 添加简略出库策略

---
 /dev/null                                                                                 |   90 ----------
 rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WaveItem.java              |   10 +
 rsf-server/src/main/Test/CombinationFinder.java                                           |  123 +++++++++++++
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java |   60 +++--
 rsf-admin/src/page/orders/wave/ItemToTaskModal.jsx                                        |   48 +++-
 rsf-admin/src/i18n/zh.js                                                                  |    4 
 rsf-admin/src/i18n/en.js                                                                  |    5 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaveController.java    |    6 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/utils/OptimalAlgorithmUtil.java   |  174 ++++++++++++++----
 9 files changed, 342 insertions(+), 178 deletions(-)

diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js
index 3a583e9..6207c83 100644
--- a/rsf-admin/src/i18n/en.js
+++ b/rsf-admin/src/i18n/en.js
@@ -70,6 +70,7 @@
             loadMore: 'Load More Data',
             complete: 'Complete',
             deprecate: 'Deprecate',
+            stockError: 'Insuff stock ',
             inputPlaceholder: 'Use commas to separate',
             resend: 'RESEND',
             selected: 'selected',
@@ -746,7 +747,9 @@
                 anfme: "anfme",
                 workQty: "workQty",
                 qty: "Qty",
-                stockLocs: "Stock Locs"
+                stockLocs: "Stock Locs",
+                stockQty: "Stock Qty",
+
             },
             task: {
                 taskCode: "TaskCode",
diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js
index af8f418..53d905e 100644
--- a/rsf-admin/src/i18n/zh.js
+++ b/rsf-admin/src/i18n/zh.js
@@ -71,6 +71,7 @@
             loadMore: '鍔犺浇鏇村',
             complete: '瀹屾垚',
             deprecate: '搴熷純',
+            stockError: '搴撳瓨涓嶈冻',
             resend: '閲嶅彂',
             selected: '椤归�変腑',
             batch: '鎵归噺缂栬緫'
@@ -792,7 +793,8 @@
                 anfme: "鏁伴噺",
                 workQty: "鎵ц鏁�",
                 qty: "瀹屾垚鏁伴噺",
-                stockLocs: "搴撳瓨浣嶇疆"
+                stockLocs: "搴撳瓨浣嶇疆",
+                stockQty: "搴撳瓨鏁伴噺",
             },
             task: {
                 taskCode: "浠诲姟鍙�",
diff --git a/rsf-admin/src/page/orders/wave/ItemToTaskModal.jsx b/rsf-admin/src/page/orders/wave/ItemToTaskModal.jsx
index 6b6c39e..a0b4d7e 100644
--- a/rsf-admin/src/page/orders/wave/ItemToTaskModal.jsx
+++ b/rsf-admin/src/page/orders/wave/ItemToTaskModal.jsx
@@ -37,11 +37,10 @@
     ListContextProvider,
     useList,
     Toolbar,
-    SingleFieldList,
 } from 'react-admin';
 
 import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
-import { Box, Typography, Card, Stack, DialogContent, DialogTitle, DialogActions, Dialog } from '@mui/material';
+import { Box, Typography, Card, Stack, DialogContent, DialogTitle, DialogActions, Dialog, Chip, ListItem, Paper } from '@mui/material';
 import { styled } from '@mui/material/styles';
 import DialogCloseButton from "../../components/DialogCloseButton";
 import request from '@/utils/request';
@@ -131,7 +130,6 @@
                             <NumberField source="waveId" label="table.field.waveItem.waveId" />
                             <TextField source="waveCode" label="table.field.waveItem.waveCode" />
                             <TextField source="orderCode" label="table.field.waveItem.orderCode" />
-                            {/* <TextField source="maktx" label="table.field.waveItem.matnrName" /> */}
                             <NumberField source="matnrId" label="table.field.waveItem.matnrId" />
                             <TextField source="matnrCode" label="table.field.waveItem.matnrCode" />
                             <TextField source="batch" label="table.field.waveItem.batch" />
@@ -143,22 +141,16 @@
                             <NumberField source="anfme" label="table.field.waveItem.anfme" />
                             <NumberField source="workQty" label="table.field.waveItem.workQty" />
                             <NumberField source="qty" label="table.field.waveItem.qty" />
+                            <NumberField source="stockQty" label="table.field.waveItem.stockQty" />
                             <WrapperField cellClassName="opt" label="table.field.waveItem.stockLocs">
-                                <ArrayField source="stockLocs" stockLocs="table.field.waveItem.stockLocs">
-                                    <SingleFieldList linkType={false}>
-                                        <ChilpField source="" size="small"></ChilpField>
-                                    </SingleFieldList>
-                                </ArrayField>
-                                {/* <NumberField source="anfme" label="table.field.waveItem.stockLocs" /> */}
-                                {/* <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} />
-                                <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} /> */}
+                                <TagsField />
                             </WrapperField>
                         </StyledDatagrid>
                     </ListContextProvider>
                 </DialogContent>
                 <DialogActions>
                     <Toolbar sx={{ width: '100%', justifyContent: 'end' }} >
-                        <GenerateTaskButton record={[record?.id]} />
+                        <GenerateTaskButton record={[record?.id]} dataSource={data} />
                     </Toolbar>
                 </DialogActions>
             </Dialog>
@@ -168,12 +160,12 @@
 
 export default ItemToTaskModal;
 
-const GenerateTaskButton = (record) => {
+const GenerateTaskButton = (record, dataSource) => {
     const refresh = useRefresh();
     const notify = useNotify();
     const redirect = useRedirect();
     const generateTask = async () => {
-        const res = await request.post(`/wave/public/task`, { ids: record?.record });
+        const res = await request.post(`/wave/public/task`, { wave: dataSource });
         if (res?.data?.code === 200) {
             notify(res.data.msg);
             redirect("/task")
@@ -183,4 +175,32 @@
         refresh();
     }
     return (<Button variant="contained" label={"ra.action.save"} onClick={generateTask}></Button>)
+}
+
+const TagsField = () => {
+    const record = useRecordContext();
+    const translate = useTranslate();
+    const locs = JSON.parse(record.stockLocs);
+    if (locs == undefined || locs.length < 1) {
+        return (
+            <>
+                <ListItem>
+                    <Chip color="error" label={translate("common.action.stockError")} variant="outlined" />
+                </ListItem>
+            </>
+        )
+    } else {
+        return (
+            <>
+                {locs.map((data) => {
+                    return (
+                        <ListItem key={data?.id}>
+                            <Chip label={data?.locCode} />
+                        </ListItem>
+                    )
+                })}
+            </>
+        )
+    }
+
 }
\ No newline at end of file
diff --git a/rsf-server/src/main/Test/CombinationFinder.java b/rsf-server/src/main/Test/CombinationFinder.java
new file mode 100644
index 0000000..cd7ee08
--- /dev/null
+++ b/rsf-server/src/main/Test/CombinationFinder.java
@@ -0,0 +1,123 @@
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class CombinationFinder {
+
+    public List<Integer> findCombination(double[] nums, double target) {
+        // 澶勭悊绛夊�兼儏鍐�
+        List<Integer> equal = findEqual(nums, target);
+        if (equal != null && !equal.isEmpty()) {
+            return equal;
+        }
+
+        // 澶勭悊澶т簬鐨勬儏鍐�
+        List<Integer> greater = findGreater(nums, target);
+        if (greater != null && !greater.isEmpty()) {
+            return greater;
+        }
+
+        // 澶勭悊灏忎簬鐨勬儏鍐�
+        List<Integer> less = findLess(nums, target);
+        return less != null ? less : new ArrayList<>(); // 纭繚涓嶈繑鍥瀗ull
+    }
+
+    private List<Integer> findEqual(double[] nums, double target) {
+        int n = nums.length;
+        double[] dp = new double[(int) (target * 100 + 1)]; // 鏀惧ぇ100鍊嶅鐞嗙簿搴﹂棶棰�
+        Arrays.fill(dp, Double.MAX_VALUE);
+        dp[0] = 0;
+        int[] prev = new int[(int) (target * 100 + 1)];
+        Arrays.fill(prev, -1);
+
+        for (int j = 0; j < n; j++) {
+            int num = (int) (nums[j] * 100); // 鏀惧ぇ100鍊嶅鐞嗙簿搴﹂棶棰�
+            for (int i = (int) (target * 100); i >= num; i--) {
+                if (dp[i - num] != Double.MAX_VALUE && dp[i - num] + 1 < dp[i]) {
+                    dp[i] = dp[i - num] + 1;
+                    prev[i] = j;
+                }
+            }
+        }
+
+        if (dp[(int) (target * 100)] == Double.MAX_VALUE) {
+            return null;
+        }
+
+        List<Integer> indices = new ArrayList<>();
+        int current = (int) (target * 100);
+        while (current > 0) {
+            int j = prev[current];
+            if (j == -1) return null;
+            indices.add(j);
+            current -= (int) (nums[j] * 100);
+        }
+
+        return indices;
+    }
+
+    private List<Integer> findGreater(double[] nums, double target) {
+        List<double[]> sorted = new ArrayList<>();
+        for (int i = 0; i < nums.length; i++) {
+            sorted.add(new double[]{nums[i], i});
+        }
+        sorted.sort((a, b) -> Double.compare(b[0], a[0]));
+
+        double sum = 0;
+        List<Integer> indices = new ArrayList<>();
+        for (double[] pair : sorted) {
+            sum += pair[0];
+            indices.add((int) pair[1]);
+            if (sum > target) {
+                return indices;
+            }
+        }
+
+        return null;
+    }
+
+    private List<Integer> findLess(double[] nums, double target) {
+        int n = nums.length;
+        List<Integer> bestIndices = new ArrayList<>();
+        double[] maxSum = {-1.0};
+        for (int k = 1; k <= n; k++) {
+            List<Integer> currentIndices = new ArrayList<>();
+            double[] currentMax = {-1.0};
+            backtrack(nums, target, 0, k, 0.0, 0, currentIndices, currentMax, new ArrayList<>());
+            if (currentMax[0] != -1.0) {
+                if (currentMax[0] > maxSum[0] || (currentMax[0] == maxSum[0] && currentIndices.size() < bestIndices.size())) {
+                    maxSum[0] = currentMax[0];
+                    bestIndices = new ArrayList<>(currentIndices);
+                }
+            }
+        }
+
+        return bestIndices.isEmpty() ? null : bestIndices;
+    }
+
+    private void backtrack(double[] nums, double target, int start, int k, double currentSum, int count, List<Integer> currentIndices, double[] currentMax, List<Integer> path) {
+        if (count == k) {
+            if (currentSum <= target && currentSum > currentMax[0]) {
+                currentMax[0] = currentSum;
+                currentIndices.clear();
+                currentIndices.addAll(path);
+            }
+            return;
+        }
+
+        for (int i = start; i < nums.length; i++) {
+            if (currentSum + nums[i] > target) continue;
+            path.add(i);
+            backtrack(nums, target, i + 1, k, currentSum + nums[i], count + 1, currentIndices, currentMax, path);
+            path.remove(path.size() - 1);
+        }
+    }
+
+    public static void main(String[] args) {
+        CombinationFinder finder = new CombinationFinder();
+        double[] nums = {3.0, 1.0, 4.0, 2.0};
+        double target = 0.1;
+        List<Integer> result = finder.findCombination(nums, target);
+        System.out.println("鏈�浼樼粍鍚堢殑绱㈠紩: " + result); // 渚嬪锛岀瓑鍊肩粍鍚堝彲鑳戒负绱㈠紩2锛�4.0锛夊拰3锛�1.0锛�
+    }
+}
\ No newline at end of file
diff --git a/rsf-server/src/main/Test/MinimalCombinationSum.java b/rsf-server/src/main/Test/MinimalCombinationSum.java
deleted file mode 100644
index 624a4f1..0000000
--- a/rsf-server/src/main/Test/MinimalCombinationSum.java
+++ /dev/null
@@ -1,90 +0,0 @@
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class MinimalCombinationSum {
-
-    private static List<Double> bestSolution;
-    private static double target;
-    private static double minDifference;
-    private static final double EPSILON = 1e-10;
-
-    public static List<Double> findBestCombination(Double[] candidates, double targetSum) {
-        bestSolution = null;
-        target = targetSum;
-        minDifference = Double.MAX_VALUE;
-        Arrays.sort(candidates);
-        backtrack(candidates, 0, new ArrayList<>(), 0.0);
-
-        // 濡傛灉娌℃湁绮剧‘瑙o紝杩斿洖鏈�鎺ヨ繎鐨勮繎浼艰В
-        return bestSolution != null ? bestSolution : new ArrayList<>();
-    }
-
-    private static void backtrack(Double[] candidates, int start,
-                                  List<Double> current, double currentSum) {
-        // 璁$畻褰撳墠鍜屼笌鐩爣鐨勫樊鍊�
-        double difference = Math.abs(currentSum - target);
-
-        // 濡傛灉鎵惧埌鏇翠紭瑙o紙宸�兼洿灏忔垨宸�肩浉鍚屼絾缁勫悎鏇寸煭锛�
-        if (difference < minDifference - EPSILON ||
-                (Math.abs(difference - minDifference) < EPSILON &&
-                        (bestSolution == null || current.size() < bestSolution.size()))) {
-            minDifference = difference;
-            bestSolution = new ArrayList<>(current);
-        }
-
-        // 濡傛灉宸茬粡鎵惧埌绮剧‘瑙o紝涓嶉渶瑕佺户缁悳绱㈡洿闀跨殑缁勫悎
-        if (minDifference < EPSILON) {
-            return;
-        }
-
-        // 閬嶅巻鍊欓�夋暟瀛�
-        for (int i = start; i < candidates.length; i++) {
-            double num = candidates[i];
-
-            // 鍓灊锛氬鏋滃綋鍓嶅拰宸茬粡杩滃ぇ浜庣洰鏍囧�硷紝璺宠繃
-            if (currentSum + num > target + minDifference + EPSILON) {
-                continue;
-            }
-
-            // 璺宠繃閲嶅鏁板瓧
-            if (i > start && Math.abs(candidates[i] - candidates[i - 1]) < EPSILON) {
-                continue;
-            }
-
-            current.add(num);
-            backtrack(candidates, i + 1, current, currentSum + num);
-            current.remove(current.size() - 1);
-        }
-    }
-
-    public static void main(String[] args) {
-        Double[] candidates1 = {1.5, 2.3, 3.1, 4.7};
-        double target1 = 3.8;
-        System.out.println("鍊欓�夋暟瀛�: " + Arrays.toString(candidates1));
-        System.out.println("鐩爣鍊�: " + target1);
-        List<Double> result1 = findBestCombination(candidates1, target1);
-        printResult(result1, target1);
-
-//        Double[] candidates2 = {0.8, 1.2, 1.7, 2.5};
-//        double target2 = 3.9;
-//        System.out.println("\n鍊欓�夋暟瀛�: " + Arrays.toString(candidates2));
-//        System.out.println("鐩爣鍊�: " + target2);
-//        List<Double> result2 = findBestCombination(candidates2, target2);
-//        printResult(result2, target2);
-    }
-
-    private static void printResult(List<Double> result, double target) {
-        if (result.isEmpty()) {
-            System.out.println("鏃犺В");
-        } else {
-            double sum = result.stream().mapToDouble(Double::doubleValue).sum();
-            if (Math.abs(sum - target) < EPSILON) {
-                System.out.printf("绮剧‘瑙�: %s (鍜�=%.2f)\n", result, sum);
-            } else {
-                System.out.printf("杩戜技瑙�: %s (鍜�=%.2f, 涓庣洰鏍囩浉宸�: %.2f)\n",
-                        result, sum, sum - target);
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaveController.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaveController.java
index cd19c30..a14c907 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaveController.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaveController.java
@@ -111,13 +111,11 @@
         ExcelUtil.build(ExcelUtil.create(waveService.list(), Wave.class), response);
     }
 
-
-
     @PreAuthorize("hasAuthority('manager:wave:update')")
     @ApiOperation("娉㈡涓嬪彂浠诲姟")
     @PostMapping("/wave/public/task")
     public R publicTask(@RequestBody Map<String, Object> map) {
-        if (Cools.isEmpty(map)) {
+        if (Cools.isEmpty(map) || Cools.isEmpty(map.get("wave"))) {
             throw new CoolException("鍙傛暟涓嶈兘涓虹┖锛侊紒");
         }
         return waveService.publicTask(map);
@@ -127,7 +125,7 @@
     @ApiOperation("娉㈡鍑哄簱浠诲姟棰勮")
     @PostMapping("/wave/locs/preview/page")
     public R mergeWavePreview(@RequestBody Map<String, Object> map) {
-        if (Cools.isEmpty(map.get("waveId")) || StringUtils.isBlank(map.get("waveId").toString())) {
+        if (Cools.isEmpty(map.get("wave")) || StringUtils.isBlank(map.get("wave").toString())) {
             throw new CoolException("鍙傛暟涓嶈兘涓虹┖锛侊紒");
         }
         Long waveId = Long.parseLong(map.get("waveId").toString());
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WaveItem.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WaveItem.java
index ee1a48c..619bc5f 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WaveItem.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WaveItem.java
@@ -170,11 +170,21 @@
     @ApiModelProperty(value= "淇敼浜哄憳")
     private Long updateBy;
 
+    /**
+     * 鐩爣搴撲綅
+     */
     @ApiModelProperty("鐩爣搴撲綅")
     @TableField(exist = false)
     private String stockLocs;
 
     /**
+     * 搴撳瓨鏁伴噺
+     */
+    @ApiModelProperty("搴撳瓨鏁伴噺")
+    @TableField(exist = false)
+    private Double stockQty;
+
+    /**
      * 澶囨敞
      */
     @ApiModelProperty(value= "澶囨敞")
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java
index 111ac2f..96355b3 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java
@@ -17,15 +17,14 @@
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.vincent.rsf.server.manager.utils.OptimalAlgorithmUtil;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 @Service("waveService")
 public class WaveServiceImpl extends ServiceImpl<WaveMapper, Wave> implements WaveService {
@@ -53,10 +52,11 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public R publicTask(Map<String, Object> map) {
-        List<Long> ids = (List<Long>) map.get("ids");
-        if (Objects.isNull(ids) || ids.isEmpty()) {
+        List<WaveItem> itemParams = (List<WaveItem>) map.get("wave");
+        if (Objects.isNull(itemParams) || itemParams.isEmpty()) {
             throw new CoolException("鍙傛暟涓嶈兘涓虹┖锛侊紒");
         }
+        List<Long> ids = itemParams.stream().map(WaveItem::getWaveId).collect(Collectors.toList());
         List<Wave> waves = this.list(new LambdaQueryWrapper<Wave>().in(Wave::getId, ids));
         if (Objects.isNull(waves) || waves.isEmpty()) {
             throw new CoolException("娉㈡鏁版嵁涓嶅瓨鍦紒锛�");
@@ -67,10 +67,9 @@
             throw new CoolException("娉㈡鏄庣粏涓嶅瓨鍦紒锛�");
         }
         List<Long> orderIds = waveItems.stream().map(WaveItem::getOrderId).collect(Collectors.toList());
-
         /**鏌ヨ姣忔潯鏄庣粏鍖归厤鐨勫簱浣�*/
         try {
-            List<WaveItem> items = getLocs(waveItems);
+//            List<WaveItem> items = getLocs(waveItems);
         } catch (Exception e) {
             throw new CoolException("搴撲綅鑾峰彇澶辫触锛侊紒锛�");
         }
@@ -78,16 +77,16 @@
         // 2. 鏍规嵁鐗╂枡SKU瀵绘壘绗﹀悎鐗╂枡搴撲綅  {1. 鏍规嵁鐗╂枡缂栫爜锛屾壒娆★紝鍔ㄦ�佸瓧娈� 鏌ヨ绗﹀悎鐨勫簱浣嶏紝鍐嶆牴鎹簱浣嶄腑鐗╂枡鐨勬暟閲忛�夋嫨鏈�閫傚悎鐨勫簱浣� 2. 鍒ゆ柇褰撳墠璁㈠崟鏄叏鎷栧嚭搴撹繕鏄嫞鏂欏叆搴搣
         // 3. 淇敼涓诲崟銆佹尝娆℃墽琛屾暟閲�
         // 4. 鍒ゆ柇鍏ㄤ粨鍑哄簱鎴栨嫞鏂欏嚭搴�
-        List<AsnOrder> orders = asnOrderService.list(new LambdaQueryWrapper<AsnOrder>().in(AsnOrder::getId, orderIds));
-        /**淇敼鍘熷嚭搴撳崟鐘舵��*/
-        if (!asnOrderService.update(new LambdaQueryWrapper<AsnOrder>()
-                .eq(AsnOrder::getExceStatus, AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val)
-                .in(AsnOrder::getId, orders))) {
-            throw new CoolException("鍑哄簱鍗曟嵁鐘舵�佷慨鏀瑰け璐ワ紒锛�");
-        }
-        if (!this.update(new LambdaUpdateWrapper<Wave>().set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK).in(Wave::getId, ids))) {
-            throw new CoolException("娉㈡鐘舵�佷慨鏀瑰け璐ワ紒锛�");
-        }
+//        List<AsnOrder> orders = asnOrderService.list(new LambdaQueryWrapper<AsnOrder>().in(AsnOrder::getId, orderIds));
+//        /**淇敼鍘熷嚭搴撳崟鐘舵��*/
+//        if (!asnOrderService.update(new LambdaQueryWrapper<AsnOrder>()
+//                .eq(AsnOrder::getExceStatus, AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val)
+//                .in(AsnOrder::getId, orders))) {
+//            throw new CoolException("鍑哄簱鍗曟嵁鐘舵�佷慨鏀瑰け璐ワ紒锛�");
+//        }
+//        if (!this.update(new LambdaUpdateWrapper<Wave>().set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK).in(Wave::getId, ids))) {
+//            throw new CoolException("娉㈡鐘舵�佷慨鏀瑰け璐ワ紒锛�");
+//        }
         return R.ok();
     }
 
@@ -136,15 +135,26 @@
                     .eq(LocItem::getSplrBatch, waveItem.getSplrBatch())
                     .eq(StringUtils.isNotBlank(waveItem.getFieldsIndex()), LocItem::getFieldsIndex, waveItem.getFieldsIndex())
                     .groupBy(LocItem::getMatnrCode, LocItem::getSplrBatch, LocItem::getFieldsIndex, LocItem::getId));
+            List<Double> doubles1 = locItems.stream().map(LocItem::getAnfme).collect(Collectors.toList());
+            double[] doubles = doubles1.stream().mapToDouble(Double::doubleValue).toArray();
 
-            Double[] doubles = locItems.stream().map(LocItem::getAnfme).toArray(Double[]::new);
-            List<Double> result = OptimalAlgorithmUtil.findBestCombination(doubles, waveItem.getAnfme());
-            String locs = JSONArray.toJSONString(new ArrayList<>());
-            if (!locItems.isEmpty()) {
-                List<String> codes = locItems.stream().map(LocItem::getLocCode).collect(Collectors.toList());
-                locs = JSONArray.toJSONString(codes);
+            /**浣跨敤鍥炴函绠楁硶璁$畻锛岃幏鍙栫鍚堝嚭搴撻噺鐨勬渶绠�缁勫悎*/
+            List<Integer> result = OptimalAlgorithmUtil.findCombination(doubles, waveItem.getAnfme());
+            String locs = "[]";
+            if (Objects.isNull(result)) {
+                waveItem.setStockLocs(locs).setStockQty(0.0);
+            } else {
+                /**杩囨护闆嗗悎涓渶绠�鐭殑缁勫悎*/
+                List<LocItem> locsInfo = result.stream()
+                        .filter(i -> i >= 0 && i < locItems.size())
+                        .map(locItems::get).collect(Collectors.toList());
+                locs = JSONArray.toJSONString(locsInfo);
+                double sumQty = locItems.stream().mapToDouble(LocItem::getAnfme).sum();
+                double surQty = locItems.stream().mapToDouble(LocItem::getWorkQty).sum();
+                double qty = locItems.stream().mapToDouble(LocItem::getQty).sum();
+                double v = sumQty - surQty - qty;
+                waveItem.setStockLocs(locs).setStockQty(v);
             }
-            waveItem.setStockLocs(locs);
         });
         return waveItems;
     }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/utils/OptimalAlgorithmUtil.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/utils/OptimalAlgorithmUtil.java
index 7ada63a..a3704cb 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/utils/OptimalAlgorithmUtil.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/utils/OptimalAlgorithmUtil.java
@@ -6,9 +6,9 @@
 import java.util.stream.Collectors;
 
 /**
+ * @param
  * @author Ryan
  * @description 鏍规嵁瀵硅薄澶氫釜灞炴�у悎骞跺鐞�
- * @param
  * @return
  * @time 2025/4/25 10:55
  */
@@ -46,9 +46,9 @@
     }
 
     /**
+     * @param
      * @author Ryan
      * @description 鐢ㄤ簬瀛樺偍澶氫釜鍒嗙粍閿殑鍐呴儴绫�
-     * @param
      * @return
      * @time 2025/4/25 10:56
      */
@@ -80,52 +80,140 @@
     }
 
 
-    public static List<Double> findBestCombination(Double[] candidates, double targetSum) {
-        bestSolution = null;
-        target = targetSum;
-        minDifference = Double.MAX_VALUE;
-        Arrays.sort(candidates);
-        backtrack(candidates, 0, new ArrayList<>(), 0.0);
-
-        // 濡傛灉娌℃湁绮剧‘瑙o紝杩斿洖鏈�鎺ヨ繎鐨勮繎浼艰В
-        return bestSolution != null ? bestSolution : new ArrayList<>();
-    }
-
-    private static void backtrack(Double[] candidates, int start,
-                                  List<Double> current, double currentSum) {
-        // 璁$畻褰撳墠鍜屼笌鐩爣鐨勫樊鍊�
-        double difference = Math.abs(currentSum - target);
-
-        // 濡傛灉鎵惧埌鏇翠紭瑙o紙宸�兼洿灏忔垨宸�肩浉鍚屼絾缁勫悎鏇寸煭锛�
-        if (difference < minDifference - EPSILON ||
-                (Math.abs(difference - minDifference) < EPSILON &&
-                        (bestSolution == null || current.size() < bestSolution.size()))) {
-            minDifference = difference;
-            bestSolution = new ArrayList<>(current);
+    /**
+     * @param
+     * @return
+     * @author Ryan
+     * @description 鑾峰彇鍏ㄦ嫋鎴栭潪鍏ㄦ嫋搴撲綅
+     * @time 2025/4/28 09:41
+     */
+    public static List<Integer> findCombination(double[] nums, Double target) {
+        // 澶勭悊绛夊�兼儏鍐�
+        List<Integer> equal = findEqual(nums, target);
+        if (equal != null && !equal.isEmpty()) {
+            return equal;
         }
 
-        // 濡傛灉宸茬粡鎵惧埌绮剧‘瑙o紝涓嶉渶瑕佺户缁悳绱㈡洿闀跨殑缁勫悎
-        if (minDifference < EPSILON) {
+        // 澶勭悊澶т簬鐨勬儏鍐�
+        List<Integer> greater = findGreater(nums, target);
+        if (greater != null && !greater.isEmpty()) {
+            return greater;
+        }
+
+        // 澶勭悊灏忎簬鐨勬儏鍐�
+        List<Integer> less = findLess(nums, target);
+        return less != null ? less : new ArrayList<>(); // 纭繚涓嶈繑鍥瀗ull
+    }
+
+    /**
+     * @author Ryan
+     * @description 浣跨敤鍔ㄦ�佽鍒掑鎵惧拰绛変簬鐩爣鍊肩殑鏈�灏戝厓绱犵粍鍚堛�傚姩鎬佽鍒掓暟缁刣p璁板綍杈惧埌姣忎釜鍜屾墍闇�鐨勬渶灏戝厓绱犳暟鐩紝prev鏁扮粍璁板綍璺緞浠ヤ究鍥炴函鎵惧埌鍏蜂綋绱㈠紩銆�
+     * @param  
+     * @return 
+     * @time 2025/4/28 12:33
+     */
+    private static List<Integer> findEqual(double[] nums, double target) {
+        int n = nums.length;
+        double[] dp = new double[(int) (target * 100 + 1)]; // 鏀惧ぇ100鍊嶅鐞嗙簿搴﹂棶棰�
+        Arrays.fill(dp, Double.MAX_VALUE);
+        dp[0] = 0;
+        int[] prev = new int[(int) (target * 100 + 1)];
+        Arrays.fill(prev, -1);
+
+        for (int j = 0; j < n; j++) {
+            int num = (int) (nums[j] * 100); // 鏀惧ぇ100鍊嶅鐞嗙簿搴﹂棶棰�
+            for (int i = (int) (target * 100); i >= num; i--) {
+                if (dp[i - num] != Double.MAX_VALUE && dp[i - num] + 1 < dp[i]) {
+                    dp[i] = dp[i - num] + 1;
+                    prev[i] = j;
+                }
+            }
+        }
+
+        if (dp[(int) (target * 100)] == Double.MAX_VALUE) {
+            return null;
+        }
+
+        List<Integer> indices = new ArrayList<>();
+        int current = (int) (target * 100);
+        while (current > 0) {
+            int j = prev[current];
+            if (j == -1) return null;
+            indices.add(j);
+            current -= (int) (nums[j] * 100);
+        }
+
+        return indices;
+    }
+
+    /**
+     * @author Ryan
+     * @description 灏嗘暟缁勯檷搴忔帓搴忓悗锛岃椽蹇冨湴绱姞鍏冪礌鐩村埌鎬诲拰瓒呰繃鐩爣鍊硷紝杩斿洖杩欎簺鍏冪礌鐨勭储寮�
+     * @param
+     * @return 
+     * @time 2025/4/28 12:34
+     */
+    private static List<Integer> findGreater(double[] nums, double target) {
+        List<double[]> sorted = new ArrayList<>();
+        for (int i = 0; i < nums.length; i++) {
+            sorted.add(new double[]{nums[i], i});
+        }
+        sorted.sort((a, b) -> Double.compare(b[0], a[0]));
+
+        double sum = 0;
+        List<Integer> indices = new ArrayList<>();
+        for (double[] pair : sorted) {
+            sum += pair[0];
+            indices.add((int) pair[1]);
+            if (sum > target) {
+                return indices;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * @author Ryan
+     * @description 浣跨敤鍥炴函娉曠敓鎴愭墍鏈夊彲鑳界殑缁勫悎锛屽鎵炬�诲拰鏈�澶т絾涓嶈秴杩囩洰鏍囧�肩殑缁勫悎锛屽苟璁板綍鍏冪礌鏁扮洰鏈�灏戠殑缁勫悎銆�
+     * @param
+     * @return
+     * @time 2025/4/28 12:34
+     */
+    private static List<Integer> findLess(double[] nums, double target) {
+        int n = nums.length;
+        List<Integer> bestIndices = new ArrayList<>();
+        double[] maxSum = {-1.0};
+        for (int k = 1; k <= n; k++) {
+            List<Integer> currentIndices = new ArrayList<>();
+            double[] currentMax = {-1.0};
+            backtrack(nums, target, 0, k, 0.0, 0, currentIndices, currentMax, new ArrayList<>());
+            if (currentMax[0] != -1.0) {
+                if (currentMax[0] > maxSum[0] || (currentMax[0] == maxSum[0] && currentIndices.size() < bestIndices.size())) {
+                    maxSum[0] = currentMax[0];
+                    bestIndices = new ArrayList<>(currentIndices);
+                }
+            }
+        }
+
+        return bestIndices.isEmpty() ? null : bestIndices;
+    }
+
+    private static void backtrack(double[] nums, double target, int start, int k, double currentSum, int count, List<Integer> currentIndices, double[] currentMax, List<Integer> path) {
+        if (count == k) {
+            if (currentSum <= target && currentSum > currentMax[0]) {
+                currentMax[0] = currentSum;
+                currentIndices.clear();
+                currentIndices.addAll(path);
+            }
             return;
         }
 
-        // 閬嶅巻鍊欓�夋暟瀛�
-        for (int i = start; i < candidates.length; i++) {
-            double num = candidates[i];
-
-            // 鍓灊锛氬鏋滃綋鍓嶅拰宸茬粡杩滃ぇ浜庣洰鏍囧�硷紝璺宠繃
-            if (currentSum + num > target + minDifference + EPSILON) {
-                continue;
-            }
-
-            // 璺宠繃閲嶅鏁板瓧
-            if (i > start && Math.abs(candidates[i] - candidates[i - 1]) < EPSILON) {
-                continue;
-            }
-
-            current.add(num);
-            backtrack(candidates, i + 1, current, currentSum + num);
-            current.remove(current.size() - 1);
+        for (int i = start; i < nums.length; i++) {
+            if (currentSum + nums[i] > target) continue;
+            path.add(i);
+            backtrack(nums, target, i + 1, k, currentSum + nums[i], count + 1, currentIndices, currentMax, path);
+            path.remove(path.size() - 1);
         }
     }
 

--
Gitblit v1.9.1