Parcourir la source

白坯布靶向预测按平方米克重匹配

wukai il y a 3 mois
Parent
commit
b82993ba1d

+ 1 - 1
jjt-admin/src/test/java/com/jjt/order/OrderTest.java

@@ -29,7 +29,7 @@ public class OrderTest {
 
     @Test
     void test() {
-        String d = "2025-02-13";
+        String d = "2025-02-18";
         LocalDate start = LocalDate.parse(d);
         LocalDate end = LocalDate.now().minusDays(1);
         do {

+ 2 - 1
jjt-biz/src/main/java/com/jjt/biz/vo/GramMassDetail.java

@@ -111,8 +111,9 @@ public class GramMassDetail {
         BigDecimal width = BigDecimal.valueOf(this.formula_data_17);
         //面积
         BigDecimal area = length.multiply(width);
-        //重量,单位kg,需要转换成克
+//       重量,单位kg,需要转换成克
         BigDecimal weight = BigDecimal.valueOf(this.formula_data_18 * 1000);
+        //计算平方米克重 重量除以面积
         if (area.floatValue() != 0 && weight.floatValue() != 0) {
             this.gramMass = weight.divide(area, 2, RoundingMode.HALF_UP).floatValue();
         }

+ 10 - 0
jjt-biz/src/main/java/com/jjt/calc/domain/TwinFormulaInfo.java

@@ -3,11 +3,13 @@ package com.jjt.calc.domain;
 import com.jjt.biz.domain.TwinDevice;
 import com.jjt.common.annotation.Excel;
 import com.jjt.common.core.domain.BaseEntity;
+import com.jjt.order.utils.CalcUtil;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.math.BigDecimal;
 import java.util.Map;
 
 /**
@@ -70,6 +72,8 @@ public class TwinFormulaInfo extends BaseEntity {
      */
     private Long specInfoId;
 
+    @ApiModelProperty("平方米克重")
+    private BigDecimal gsm;
     /**
      * 设备ID
      */
@@ -321,4 +325,10 @@ public class TwinFormulaInfo extends BaseEntity {
     @Excel(name = "GB5盘头剩余圈数")
     @ApiModelProperty("GB5盘头剩余圈数")
     private Integer cd19;
+
+
+    public void setGsm() {
+        int weight = (int) (this.fd18 * 1000);
+        this.gsm = CalcUtil.calcGsm(this.fd16, this.fd17, weight);
+    }
 }

+ 76 - 111
jjt-biz/src/main/java/com/jjt/order/controller/OrderApiController.java

@@ -9,34 +9,27 @@ import com.jjt.common.core.controller.BaseController;
 import com.jjt.common.core.redis.RedisCache;
 import com.jjt.common.utils.DateUtils;
 import com.jjt.order.domain.TwinOrder;
-import com.jjt.order.domain.TwinOrderDetail;
 import com.jjt.order.domain.VmsStock;
 import com.jjt.order.service.ITwinOrderService;
 import com.jjt.order.utils.OrderExportUtil;
-import com.jjt.order.vo.BomVO;
-import com.jjt.order.vo.SkuVO;
+import com.jjt.order.utils.OrderGsmExportUtil;
 import com.jjt.utils.MssqlUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
-import java.io.BufferedOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.math.BigDecimal;
+import java.io.*;
 import java.net.URLEncoder;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 
 /**
  * @author ruoyi
@@ -81,116 +74,52 @@ public class OrderApiController extends BaseController {
         //按设备ID分组
         Map<Long, TwinCalcDay> dayMap = dayList.stream().collect(Collectors.toMap(TwinCalcDay::getDeviceId, o -> o));
         List<VmsStock> stocks = MssqlUtil.vmsStock();
-        List<TwinOrderDetail> all = new ArrayList<>();
-        orderList.forEach(to -> all.addAll(to.getTwinOrderDetailList().stream().filter(tod -> tod.getBomSpec() != null).collect(Collectors.toList())));
-        //按规格分组
-        Map<String, List<TwinOrderDetail>> allMap = all.stream().collect(Collectors.groupingBy(TwinOrderDetail::getBomSpec, LinkedHashMap::new, Collectors.toList()));
-        List<BomVO> bomList = new ArrayList<>();
-        List<SkuVO> skuList = new ArrayList<>();
-        for (String spec : allMap.keySet()) {
-            List<TwinOrderDetail> todList = allMap.get(spec);
-            //匹配白坯布库存
-            Float kc = 0f;
-            VmsStock stock = matchStock(spec, stocks);
-            if (stock != null) {
-                kc = stock.getQty();
-            }
-            //匹配生产设备
-            List<TwinFormulaInfo> matchFormula = matchFormula(spec, infos);
-            BigDecimal cl = BigDecimal.ZERO;
-            String deviceIds = "";
-            for (TwinFormulaInfo match : matchFormula) {
-                if (StringUtils.isNotEmpty(deviceIds)) {
-                    deviceIds += ",";
-                }
-                deviceIds += match.getDeviceId();
-                TwinCalcDay day = dayMap.get(match.getDeviceId());
-                if (day != null) {
-                    cl = cl.add(day.getWeight());
-                }
-            }
-
-            cl = cl.multiply(BigDecimal.valueOf(1000));
-
-            BomVO bom = new BomVO();
-            bom.setDeviceIds(deviceIds);
-            bom.setLast(cl.doubleValue());
-            //统计订单数量
-            long orders = todList.stream().map(TwinOrderDetail::getOderId).distinct().count();
-            double totalWeight = todList.stream().mapToDouble(o -> o.getWeight().doubleValue()).sum();
-            TwinOrderDetail tod = todList.get(0);
-            bom.setBomCode(tod.getBomCode());
-            bom.setBomName(tod.getBomName());
-            bom.setBomSpec(spec);
-
-            bom.setXql(totalWeight);
-            bom.setKcl(kc);
-            bom.setOrders(orders);
-            double ycl = cl.multiply(BigDecimal.TEN).doubleValue();
-            double cz = totalWeight - kc - ycl;
-            bom.setYcl(ycl);
-            bom.setCz(cz);
-            bom.setCl(cz / totalWeight);
+        try (OutputStream outputStream = new BufferedOutputStream(response.getOutputStream()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ZipOutputStream zipOut = new ZipOutputStream(bos);) {
+            // 创建临时输出流
+            response.reset();
+            response.setCharacterEncoding("UTF-8");
+            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("白坯布靶向预测" + start + "至" + end + ".zip", "UTF-8"));
+            response.setContentType("application/octet-stream");
 
-            SkuVO sku = new SkuVO();
-            sku.setBomCode(tod.getBomCode());
-            sku.setBomName(tod.getBomName());
-            sku.setBomSpec(spec);
-            if (stock != null) {
-                sku.setSku(stock.getSku());
-                sku.setDesc(stock.getDesc());
-                sku.setNum(stock.getNum());
-                sku.setQty(stock.getQty());
-            } else {
-                sku.setSku("");
-                sku.setDesc("");
-                sku.setNum(0);
-                sku.setQty(0f);
-            }
-            sku.setXql(bom.getXql());
-            List<TwinOrder> skuOrder = new ArrayList<>();
-            //按订单分组
-            Map<Long, List<TwinOrderDetail>> map = todList.stream().collect(Collectors.groupingBy(TwinOrderDetail::getOderId, LinkedHashMap::new, Collectors.toList()));
-            for (Long oid : map.keySet()) {
-                TwinOrder to = orderMap.get(oid);
-                to.setTwinOrderDetailList(map.get(oid));
-                skuOrder.add(to);
+            try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("tpl/order.xlsx"); XSSFWorkbook wb = new XSSFWorkbook(inputStream);) {
+                OrderExportUtil oe = new OrderExportUtil();
+                String title = "白坯布靶向生产测算-10天(" + start + " 至 " + end + ")\n按重量匹配";
+                oe.process(wb, title, orderList, infos, orderMap, dayMap, stocks);
+                // 将第一个工作簿写入 ZIP
+                ZipEntry entry = new ZipEntry("按重量匹配.xlsx");
+                zipOut.putNextEntry(entry);
+                wb.write(zipOut);
+                zipOut.closeEntry();
+
+            } catch (IOException ex) {
+                ex.printStackTrace();
             }
-            sku.setOrderList(skuOrder);
-            bom.setOrderList(skuOrder);
-            bomList.add(bom);
-            skuList.add(sku);
-        }
-
-        try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("tpl/order.xlsx"); XSSFWorkbook wb = new XSSFWorkbook(inputStream); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
-            OrderExportUtil oe = new OrderExportUtil(wb);
 
-            XSSFSheet sheet0 = wb.getSheetAt(0);
-            Cell title = sheet0.getRow(0).getCell(0);
-            title.setCellValue("白坯布靶向生产测算-10天(" + start + " 至 " + end + ")");
+            try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("tpl/order-gsm.xlsx"); XSSFWorkbook wb = new XSSFWorkbook(inputStream);) {
+                OrderGsmExportUtil oe = new OrderGsmExportUtil();
+                String title = "白坯布靶向生产测算-10天(" + start + " 至 " + end + ")\n按平方米克重匹配";
+                oe.process(wb, title, orderList, infos, orderMap, dayMap, stocks);
+                // 将第二个工作簿写入 ZIP
+                ZipEntry entry = new ZipEntry("按平方米克重匹配.xlsx");
+                zipOut.putNextEntry(entry);
+                wb.write(zipOut);
+                zipOut.closeEntry();
+            } catch (IOException ex) {
+                ex.printStackTrace();
+            }
 
-            oe.sheet0(sheet0, bomList);
-            oe.sheet1(wb.getSheetAt(1), stocks);
-            oe.sheet2(wb.getSheetAt(2), skuList);
-            oe.sheet4(wb.getSheetAt(4), infos);
-            response.reset();
-            // 设置response的Header
-            response.setCharacterEncoding("UTF-8");
-            //Content-Disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存
-            //attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3"
-            // filename表示文件的默认名称,因为网络传输只支持URL编码的相关支付,因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
-            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("白坯布靶向预测" + start + "至" + end + ".xlsx", "UTF-8"));
-            response.setContentType("application/octet-stream");
-            wb.write(outputStream);
+            // 完成 ZIP 文件
+            zipOut.finish();
+            outputStream.write(bos.toByteArray());
             outputStream.flush();
-        } catch (IOException ex) {
-            ex.printStackTrace();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
         }
     }
 
 
     /**
-     * 匹配库存
+     * 先按重量匹配,再匹配长或者宽大于规格的长宽
      *
      * @param spec   规格
      * @param stocks 库存
@@ -202,8 +131,11 @@ public class OrderApiController extends BaseController {
         if (spec != null) {
             String[] tmp = spec.split("\\*");
             if (tmp.length == 3) {
+                //长
                 float length = Float.parseFloat(tmp[0]);
+                //宽
                 float width = Float.parseFloat(tmp[1]);
+                //重量,单位kg,需要转换成克
                 int weight = (int) (Float.parseFloat(tmp[2]) * 1000);
                 List<VmsStock> tempList = stockMap.get(weight);
                 if (tempList != null) {
@@ -220,6 +152,39 @@ public class OrderApiController extends BaseController {
     }
 
     /**
+     * 匹配库存,新匹配方式,以幅宽和平方米克重来匹配
+     * 订单中计算得到毛毯平方米克重要求,根据长宽规格,先以产品长度匹配白胚库中的幅宽规格。
+     * 如没有或不足,以宽匹配,但此时要做标注,以准备网框的工艺切换。
+     * 白胚库的规格,只以平方米克重和幅宽为规格单位。
+     *
+     * @param spec   规格
+     * @param stocks 库存
+     * @return 结果
+     */
+    private VmsStock matchStockGsm(String spec, List<VmsStock> stocks) {
+        //按重量分组
+//        Map<Integer, List<VmsStock>> stockMap = stocks.stream().collect(Collectors.groupingBy(VmsStock::getWeight, LinkedHashMap::new, Collectors.toList()));
+//        if (spec != null) {
+//            String[] tmp = spec.split("\\*");
+//            if (tmp.length == 3) {
+//                float length = Float.parseFloat(tmp[0]);
+//                float width = Float.parseFloat(tmp[1]);
+//                int weight = (int) (Float.parseFloat(tmp[2]) * 1000);
+//                List<VmsStock> tempList = stockMap.get(weight);
+//                if (tempList != null) {
+//                    for (VmsStock stock : tempList) {
+//                        if (length > stock.getLength() || width > stock.getLength()) {
+//                            return stock;
+//                        }
+//                    }
+//                }
+//            }
+//        }
+
+        return null;
+    }
+
+    /**
      * 匹配产线
      *
      * @param spec 规格

+ 12 - 0
jjt-biz/src/main/java/com/jjt/order/domain/VmsStock.java

@@ -4,6 +4,9 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
 /**
  * 白胚布库存
  *
@@ -28,4 +31,13 @@ public class VmsStock {
     private Float length;
     @ApiModelProperty("米克重")
     private Integer mick;
+    @ApiModelProperty("平方米克重")
+    private BigDecimal gsm;
+
+    public void setGsm() {
+        this.gsm = BigDecimal.ZERO;
+        if (length > 0f) {
+            this.gsm = BigDecimal.valueOf(mick).divide(BigDecimal.valueOf(length), 2, RoundingMode.HALF_UP);
+        }
+    }
 }

+ 49 - 0
jjt-biz/src/main/java/com/jjt/order/utils/CalcUtil.java

@@ -0,0 +1,49 @@
+package com.jjt.order.utils;
+
+import com.jjt.common.utils.StringUtils;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+/**
+ * OrderExportUtils$
+ *
+ * @author wukai
+ * @date 2025/2/12 02:27
+ */
+public class CalcUtil {
+    /**
+     * 根据规格计算平方米克重
+     *
+     * @param spec 规格
+     * @return 平方米克重
+     */
+    public static BigDecimal calcGsm(String spec) {
+        BigDecimal gsm = BigDecimal.ZERO;
+        if (StringUtils.isNotEmpty(spec)) {
+            String[] tmp = spec.split("\\*");
+            if (tmp.length == 3) {
+                //长
+                float length = Float.parseFloat(tmp[0]);
+                //宽
+                float width = Float.parseFloat(tmp[1]);
+                //重量,单位kg,需要转换成克
+                int weight = (int) (Float.parseFloat(tmp[2]) * 1000);
+                gsm = calcGsm(length, width, weight);
+            }
+        }
+        return gsm;
+    }
+
+    public static BigDecimal calcGsm(float length, float width, int weight) {
+        BigDecimal gsm = BigDecimal.ZERO;
+        //面积
+        BigDecimal area = BigDecimal.valueOf(length).multiply(BigDecimal.valueOf(width));
+        if (area.compareTo(BigDecimal.ZERO) != 0) {
+            //计算平方米克重 重量除以面积
+            gsm = BigDecimal.valueOf(weight).divide(area, 2, RoundingMode.HALF_UP);
+        }
+
+        return gsm;
+    }
+}

+ 204 - 12
jjt-biz/src/main/java/com/jjt/order/utils/OrderExportUtil.java

@@ -1,7 +1,9 @@
 package com.jjt.order.utils;
 
+import com.jjt.calc.domain.TwinCalcDay;
 import com.jjt.calc.domain.TwinFormulaInfo;
 import com.jjt.common.utils.DateUtils;
+import com.jjt.common.utils.StringUtils;
 import com.jjt.order.domain.TwinOrder;
 import com.jjt.order.domain.TwinOrderDetail;
 import com.jjt.order.domain.VmsStock;
@@ -14,9 +16,10 @@ import org.apache.poi.xssf.usermodel.*;
 import org.openxmlformats.schemas.drawingml.x2006.chart.CTDLbls;
 
 import java.math.BigDecimal;
-import java.util.Comparator;
-import java.util.List;
+import java.math.RoundingMode;
+import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
 
 /**
  * OrderExportUtils$
@@ -28,7 +31,7 @@ public class OrderExportUtil {
     private CellStyle p2;
     private CellStyle percentStyle;
 
-    public OrderExportUtil(XSSFWorkbook wb) {
+    public void init(XSSFWorkbook wb) {
         CreationHelper creationHelper = wb.getCreationHelper();
         this.percentStyle = wb.createCellStyle();
         percentStyle.setDataFormat(creationHelper.createDataFormat().getFormat("0.00%"));
@@ -38,6 +41,102 @@ public class OrderExportUtil {
         p2.setVerticalAlignment(VerticalAlignment.CENTER);
     }
 
+    public void process(XSSFWorkbook wb, String sheetTitle, List<TwinOrder> orderList, List<TwinFormulaInfo> infos, Map<Long, TwinOrder> orderMap, Map<Long, TwinCalcDay> dayMap, List<VmsStock> stocks) {
+        init(wb);
+        List<TwinOrderDetail> all = new ArrayList<>();
+        orderList.forEach(to -> all.addAll(to.getTwinOrderDetailList().stream().filter(tod -> tod.getBomSpec() != null).collect(Collectors.toList())));
+        //按规格分组
+        Map<String, List<TwinOrderDetail>> allMap = all.stream().collect(Collectors.groupingBy(TwinOrderDetail::getBomSpec, LinkedHashMap::new, Collectors.toList()));
+        List<BomVO> bomList = new ArrayList<>();
+        List<SkuVO> skuList = new ArrayList<>();
+        for (String spec : allMap.keySet()) {
+            List<TwinOrderDetail> todList = allMap.get(spec);
+            //匹配白坯布库存
+            Float kc = 0f;
+            VmsStock stock = matchStock(spec, stocks);
+            if (stock != null) {
+                kc = stock.getQty();
+            }
+            //匹配生产设备
+            List<TwinFormulaInfo> matchFormula = matchFormula(spec, infos);
+            BigDecimal cl = BigDecimal.ZERO;
+            String deviceIds = "";
+            for (TwinFormulaInfo match : matchFormula) {
+                if (org.apache.commons.lang3.StringUtils.isNotEmpty(deviceIds)) {
+                    deviceIds += ",";
+                }
+                deviceIds += match.getDeviceId();
+                TwinCalcDay day = dayMap.get(match.getDeviceId());
+                if (day != null) {
+                    cl = cl.add(day.getWeight());
+                }
+            }
+
+            cl = cl.multiply(BigDecimal.valueOf(1000));
+
+            BomVO bom = new BomVO();
+            bom.setDeviceIds(deviceIds);
+            bom.setLast(cl.doubleValue());
+            //统计订单数量
+            long orders = todList.stream().map(TwinOrderDetail::getOderId).distinct().count();
+            double totalWeight = todList.stream().mapToDouble(o -> o.getWeight().doubleValue()).sum();
+            TwinOrderDetail tod = todList.get(0);
+            bom.setBomCode(tod.getBomCode());
+            bom.setBomName(tod.getBomName());
+            bom.setBomSpec(spec);
+            bom.setGsm(OrderExportUtil.calcGsm(spec));
+
+            bom.setXql(totalWeight);
+            bom.setKcl(kc);
+            bom.setOrders(orders);
+            double ycl = cl.multiply(BigDecimal.TEN).doubleValue();
+            double cz = totalWeight - kc - ycl;
+            bom.setYcl(ycl);
+            bom.setCz(cz);
+            bom.setCl(cz / totalWeight);
+
+            SkuVO sku = new SkuVO();
+            sku.setBomCode(tod.getBomCode());
+            sku.setBomName(tod.getBomName());
+            sku.setBomSpec(spec);
+            sku.setGsm(OrderExportUtil.calcGsm(spec));
+            if (stock != null) {
+                sku.setSku(stock.getSku());
+                sku.setDesc(stock.getDesc());
+                sku.setNum(stock.getNum());
+                sku.setQty(stock.getQty());
+            } else {
+                sku.setSku("");
+                sku.setDesc("");
+                sku.setNum(0);
+                sku.setQty(0f);
+            }
+            sku.setXql(bom.getXql());
+            List<TwinOrder> skuOrder = new ArrayList<>();
+            //按订单分组
+            Map<Long, List<TwinOrderDetail>> map = todList.stream().collect(Collectors.groupingBy(TwinOrderDetail::getOderId, LinkedHashMap::new, Collectors.toList()));
+            for (Long oid : map.keySet()) {
+                TwinOrder to = orderMap.get(oid);
+                to.setTwinOrderDetailList(map.get(oid));
+                skuOrder.add(to);
+            }
+            sku.setOrderList(skuOrder);
+            bom.setOrderList(skuOrder);
+            bomList.add(bom);
+            skuList.add(sku);
+        }
+        XSSFSheet sheet0 = wb.getSheetAt(0);
+        Cell title = sheet0.getRow(0).getCell(0);
+        title.setCellValue(sheetTitle);
+
+        sheet0(sheet0, bomList);
+        sheet1(wb.getSheetAt(1), stocks);
+        sheet2(wb.getSheetAt(2), skuList);
+        sheet3(wb.getSheetAt(3), bomList);
+        sheet4(wb.getSheetAt(4), infos);
+    }
+
+
     /**
      * 总览
      *
@@ -47,12 +146,7 @@ public class OrderExportUtil {
     public void sheet0(XSSFSheet sheet, List<BomVO> bomList) {
         AtomicInteger num = new AtomicInteger(3);
         BomVO bom = new BomVO();
-        bom.setOrders(0L);
-        bom.setXql(0d);
-        bom.setKcl(0f);
-        bom.setYcl(0d);
-        bom.setCz(0d);
-        bom.setCl(0d);
+        bom.init();
         bomList.forEach(obj -> {
             Row row = sheet.createRow(num.getAndIncrement());
             Cell[] cells = new Cell[10];
@@ -142,10 +236,10 @@ public class OrderExportUtil {
      * @param stocks 库存
      */
     public void sheet1(Sheet sheet, List<VmsStock> stocks) {
-        AtomicInteger num = new AtomicInteger(2);
+        AtomicInteger num = new AtomicInteger(3);
         stocks.forEach(stock -> {
             Row row = sheet.createRow(num.getAndIncrement());
-            Cell[] cells = new Cell[6];
+            Cell[] cells = new Cell[9];
             for (int i = 0; i < cells.length; i++) {
                 cells[i] = row.createCell(i);
             }
@@ -154,7 +248,11 @@ public class OrderExportUtil {
             cells[2].setCellValue(stock.getNum());
             cells[3].setCellValue(stock.getQty());
             cells[3].setCellStyle(p2);
-//            cells[4].setCellValue();
+            cells[4].setCellValue(stock.getWeight());
+            cells[5].setCellValue(stock.getLength());
+            cells[6].setCellValue(stock.getMick());
+            cells[7].setCellValue(stock.getGsm().doubleValue());
+            cells[7].setCellStyle(p2);
 //            cells[5].setCellValue();
         });
     }
@@ -356,4 +454,98 @@ public class OrderExportUtil {
             cells[34].setCellValue(info.getFd12());
         });
     }
+
+    /**
+     * 根据规格计算平方米克重
+     *
+     * @param spec 规格
+     * @return 平方米克重
+     */
+    public static BigDecimal calcGsm(String spec) {
+        BigDecimal gsm = BigDecimal.ZERO;
+        if (StringUtils.isNotEmpty(spec)) {
+            String[] tmp = spec.split("\\*");
+            if (tmp.length == 3) {
+                //长
+                float length = Float.parseFloat(tmp[0]);
+                //宽
+                float width = Float.parseFloat(tmp[1]);
+                //重量,单位kg,需要转换成克
+                int weight = (int) (Float.parseFloat(tmp[2]) * 1000);
+                //面积
+                BigDecimal area = BigDecimal.valueOf(length).multiply(BigDecimal.valueOf(width));
+                if (area.compareTo(BigDecimal.ZERO) != 0) {
+                    //计算平方米克重 重量除以面积
+                    gsm = BigDecimal.valueOf(weight).divide(area, 2, RoundingMode.HALF_UP);
+                }
+            }
+        }
+        return gsm;
+    }
+
+
+    /**
+     * 先按重量匹配,再匹配长或者宽大于规格的长宽
+     *
+     * @param spec   规格
+     * @param stocks 库存
+     * @return 结果
+     */
+    private VmsStock matchStock(String spec, List<VmsStock> stocks) {
+        //按重量分组
+        Map<Integer, List<VmsStock>> stockMap = stocks.stream().collect(Collectors.groupingBy(VmsStock::getWeight, LinkedHashMap::new, Collectors.toList()));
+        if (spec != null) {
+            String[] tmp = spec.split("\\*");
+            if (tmp.length == 3) {
+                //长
+                float length = Float.parseFloat(tmp[0]);
+                //宽
+                float width = Float.parseFloat(tmp[1]);
+                //重量,单位kg,需要转换成克
+                int weight = (int) (Float.parseFloat(tmp[2]) * 1000);
+                List<VmsStock> tempList = stockMap.get(weight);
+                if (tempList != null) {
+                    for (VmsStock stock : tempList) {
+                        if (length <= stock.getLength() || width <= stock.getLength()) {
+                            return stock;
+                        }
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * 匹配产线
+     *
+     * @param spec 规格
+     * @param list 产线
+     * @return 结果
+     */
+    private List<TwinFormulaInfo> matchFormula(String spec, List<TwinFormulaInfo> list) {
+        List<TwinFormulaInfo> result = new ArrayList<>();
+        //按重量分组
+        Map<Float, List<TwinFormulaInfo>> formulaMap = list.stream().collect(Collectors.groupingBy(TwinFormulaInfo::getFd18, LinkedHashMap::new, Collectors.toList()));
+        if (spec != null) {
+            String[] tmp = spec.split("\\*");
+            if (tmp.length == 3) {
+                Float length = Float.parseFloat(tmp[0]);
+                Float width = Float.parseFloat(tmp[1]);
+                Float weight = Float.parseFloat(tmp[2]);
+                List<TwinFormulaInfo> infos = formulaMap.get(weight);
+                if (infos != null) {
+                    for (TwinFormulaInfo info : infos) {
+                        if (length.equals(info.getFd16()) && width.equals(info.getFd17()) ||
+                                length.equals(info.getFd17()) && width.equals(info.getFd16())) {
+                            result.add(info);
+                        }
+                    }
+                }
+            }
+        }
+        return result;
+    }
 }

+ 559 - 0
jjt-biz/src/main/java/com/jjt/order/utils/OrderGsmExportUtil.java

@@ -0,0 +1,559 @@
+package com.jjt.order.utils;
+
+import com.jjt.calc.domain.TwinCalcDay;
+import com.jjt.calc.domain.TwinFormulaInfo;
+import com.jjt.common.utils.DateUtils;
+import com.jjt.order.domain.TwinOrder;
+import com.jjt.order.domain.TwinOrderDetail;
+import com.jjt.order.domain.VmsStock;
+import com.jjt.order.vo.BomVO;
+import com.jjt.order.vo.SkuVO;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.chart.*;
+import org.apache.poi.xssf.usermodel.*;
+import org.openxmlformats.schemas.drawingml.x2006.chart.CTDLbls;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+/**
+ * OrderExportUtils$
+ *
+ * @author wukai
+ * @date 2025/2/12 02:27
+ */
+public class OrderGsmExportUtil {
+    private CellStyle p2;
+    private CellStyle percentStyle;
+
+    public void init(XSSFWorkbook wb) {
+        CreationHelper creationHelper = wb.getCreationHelper();
+        this.percentStyle = wb.createCellStyle();
+        percentStyle.setDataFormat(creationHelper.createDataFormat().getFormat("0.00%"));
+        percentStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+        this.p2 = wb.createCellStyle();
+        p2.setDataFormat(wb.createDataFormat().getFormat("0.00"));
+        p2.setVerticalAlignment(VerticalAlignment.CENTER);
+    }
+
+    public void process(XSSFWorkbook wb, String sheetTitle, List<TwinOrder> orderList, List<TwinFormulaInfo> infos, Map<Long, TwinOrder> orderMap, Map<Long, TwinCalcDay> dayMap, List<VmsStock> stocks) {
+        init(wb);
+        infos.forEach(info -> info.setGsm());
+        infos.sort(Comparator.comparing(TwinFormulaInfo::getDeviceId));
+        List<TwinOrderDetail> all = new ArrayList<>();
+        orderList.forEach(to -> all.addAll(to.getTwinOrderDetailList().stream().filter(tod -> tod.getBomSpec() != null).collect(Collectors.toList())));
+        //按规格分组
+        Map<String, List<TwinOrderDetail>> allMap = all.stream().collect(Collectors.groupingBy(TwinOrderDetail::getBomSpec, LinkedHashMap::new, Collectors.toList()));
+        List<BomVO> bomList = new ArrayList<>();
+        List<SkuVO> skuList = new ArrayList<>();
+        for (String spec : allMap.keySet()) {
+            List<TwinOrderDetail> todList = allMap.get(spec);
+            //匹配白坯布库存
+            Float kc = 0f;
+            VmsStock stock = matchStock(spec, stocks);
+            if (stock != null) {
+                stock.setGsm();
+                kc = stock.getQty();
+            }
+            //匹配生产设备
+            List<TwinFormulaInfo> matchFormula = matchFormula(spec, infos);
+            BigDecimal cl = BigDecimal.ZERO;
+            String deviceIds = "";
+            for (TwinFormulaInfo match : matchFormula) {
+                if (org.apache.commons.lang3.StringUtils.isNotEmpty(deviceIds)) {
+                    deviceIds += ",";
+                }
+                deviceIds += match.getDeviceId();
+                TwinCalcDay day = dayMap.get(match.getDeviceId());
+                if (day != null) {
+                    cl = cl.add(day.getWeight());
+                }
+            }
+
+            cl = cl.multiply(BigDecimal.valueOf(1000));
+
+            BomVO bom = new BomVO();
+            bom.setDeviceIds(deviceIds);
+            bom.setLast(cl.doubleValue());
+            //统计订单数量
+            long orders = todList.stream().map(TwinOrderDetail::getOderId).distinct().count();
+            double totalWeight = todList.stream().mapToDouble(o -> o.getWeight().doubleValue()).sum();
+            TwinOrderDetail tod = todList.get(0);
+            bom.setBomCode(tod.getBomCode());
+            bom.setBomName(tod.getBomName());
+            bom.setBomSpec(spec);
+            bom.setGsm(OrderExportUtil.calcGsm(spec));
+
+            bom.setXql(totalWeight);
+            bom.setKcl(kc);
+            bom.setOrders(orders);
+            double ycl = cl.multiply(BigDecimal.TEN).doubleValue();
+            double cz = totalWeight - kc - ycl;
+            bom.setYcl(ycl);
+            bom.setCz(cz);
+            bom.setCl(cz / totalWeight);
+
+            SkuVO sku = new SkuVO();
+            sku.setBomCode(tod.getBomCode());
+            sku.setBomName(tod.getBomName());
+            sku.setBomSpec(spec);
+            if (stock != null) {
+                sku.setSku(stock.getSku());
+                sku.setDesc(stock.getDesc());
+                sku.setNum(stock.getNum());
+                sku.setQty(stock.getQty());
+                sku.setGsm(stock.getGsm());
+            } else {
+                sku.setSku("");
+                sku.setDesc("");
+                sku.setNum(0);
+                sku.setQty(0f);
+                sku.setGsm(BigDecimal.ZERO);
+            }
+            sku.setXql(bom.getXql());
+            List<TwinOrder> skuOrder = new ArrayList<>();
+            //按订单分组
+            Map<Long, List<TwinOrderDetail>> map = todList.stream().collect(Collectors.groupingBy(TwinOrderDetail::getOderId, LinkedHashMap::new, Collectors.toList()));
+            for (Long oid : map.keySet()) {
+                TwinOrder to = orderMap.get(oid);
+                to.setTwinOrderDetailList(map.get(oid));
+                skuOrder.add(to);
+            }
+            sku.setOrderList(skuOrder);
+            bom.setOrderList(skuOrder);
+            bomList.add(bom);
+            skuList.add(sku);
+        }
+        XSSFSheet sheet0 = wb.getSheetAt(0);
+        Cell title = sheet0.getRow(0).getCell(0);
+        title.setCellValue(sheetTitle);
+
+        sheet0(sheet0, bomList);
+        sheet1(wb.getSheetAt(1), stocks);
+        sheet2(wb.getSheetAt(2), skuList);
+        sheet3(wb.getSheetAt(3), bomList);
+        sheet4(wb.getSheetAt(4), infos);
+    }
+
+
+    /**
+     * 总览
+     *
+     * @param sheet   sheet
+     * @param bomList 物料列表
+     */
+    public void sheet0(XSSFSheet sheet, List<BomVO> bomList) {
+        AtomicInteger num = new AtomicInteger(3);
+        BomVO bom = new BomVO();
+        bom.init();
+        bomList.forEach(obj -> {
+            Row row = sheet.createRow(num.getAndIncrement());
+            Cell[] cells = new Cell[11];
+            for (int i = 0; i < cells.length; i++) {
+                cells[i] = row.createCell(i);
+            }
+            cells[0].setCellValue(obj.getBomCode());
+            cells[1].setCellValue(obj.getBomName());
+            cells[2].setCellValue(obj.getBomSpec());
+            cells[3].setCellValue(obj.getGsm().doubleValue());
+            cells[4].setCellValue(obj.getOrders());
+            cells[5].setCellValue(obj.getXql());
+            cells[6].setCellValue(obj.getKcl());
+            cells[8].setCellValue(obj.getYcl());
+            cells[9].setCellValue(obj.getCz());
+            cells[10].setCellValue(obj.getCl());
+            cells[10].setCellStyle(percentStyle);
+            bom.setOrders(bom.getOrders() + obj.getOrders());
+            bom.setXql(bom.getXql() + obj.getXql());
+            bom.setKcl(bom.getKcl() + obj.getKcl());
+            bom.setYcl(bom.getYcl() + obj.getYcl());
+            bom.setCz(bom.getCz() + obj.getCz());
+            bom.setCl(bom.getCl() + obj.getCl());
+        });
+        Row row = sheet.createRow(num.getAndIncrement());
+        Cell[] cells = new Cell[11];
+        for (int i = 0; i < cells.length; i++) {
+            cells[i] = row.createCell(i);
+        }
+        cells[0].setCellValue("合计");
+//        cells[3].setCellValue(bom.getOrders());
+        cells[5].setCellValue(bom.getXql());
+        cells[6].setCellValue(bom.getKcl());
+        cells[8].setCellValue(bom.getYcl());
+        cells[9].setCellValue(bom.getCz());
+        for (int i = 4; i < 9; i++) {
+            cells[i].setCellStyle(p2);
+        }
+        cells[10].setCellValue(bom.getCl() / bomList.size());
+        cells[10].setCellStyle(percentStyle);
+        // 创建一个画布
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+        // 前四个默认0,[0,4]:从0列4行开始;[7,20]:到7列20行结束
+        // 默认宽度(14-8)*12
+        XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 12, 3, 18, 20);
+        // 创建一个chart对象
+        XSSFChart chart = drawing.createChart(anchor);
+        // 标题
+        chart.setTitleText("需求重量占比图");
+        // 标题是否覆盖图表
+        chart.setTitleOverlay(false);
+
+        // 图例位置
+        XDDFChartLegend legend = chart.getOrAddLegend();
+        legend.setPosition(LegendPosition.TOP_RIGHT);
+
+        XDDFCategoryDataSource countries = XDDFDataSourcesFactory.fromStringCellRange(sheet, new CellRangeAddress(3, num.get() - 2, 2, 2));
+        // 数据1,单元格范围位置[1, 0]到[1, 6]
+        XDDFNumericalDataSource<Double> area = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(3, num.get() - 2, 4, 4));
+//         XDDFChartData data = chart.createData(ChartTypes.PIE3D, null, null);
+        XDDFChartData data = chart.createData(ChartTypes.PIE, null, null);
+        // 设置为可变颜色
+        data.setVaryColors(true);
+        // 图表加载数据
+        data.addSeries(countries, area);
+
+        // 绘制
+        chart.plot(data);
+        CTDLbls dLbls = chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).addNewDLbls();
+        dLbls.addNewShowVal().setVal(false);
+        dLbls.addNewShowLegendKey().setVal(false);
+        dLbls.addNewShowCatName().setVal(true);
+        // 类别名称
+        dLbls.addNewShowSerName().setVal(false);
+        dLbls.addNewShowPercent().setVal(true);
+        // 百分比
+        dLbls.addNewShowLeaderLines().setVal(true);
+        // 引导线
+        dLbls.setSeparator("\n");
+        // 分隔符为分行符
+
+    }
+
+    /**
+     * 白坯布全量
+     *
+     * @param sheet  sheet
+     * @param stocks 库存
+     */
+    public void sheet1(Sheet sheet, List<VmsStock> stocks) {
+        AtomicInteger num = new AtomicInteger(3);
+        stocks.forEach(stock -> {
+            Row row = sheet.createRow(num.getAndIncrement());
+            Cell[] cells = new Cell[9];
+            for (int i = 0; i < cells.length; i++) {
+                cells[i] = row.createCell(i);
+            }
+            cells[0].setCellValue(stock.getSku());
+            cells[1].setCellValue(stock.getDesc());
+            cells[2].setCellValue(stock.getNum());
+            cells[3].setCellValue(stock.getQty());
+            cells[3].setCellStyle(p2);
+            cells[4].setCellValue(stock.getWeight());
+            cells[5].setCellValue(stock.getLength());
+            cells[6].setCellValue(stock.getMick());
+            cells[7].setCellValue(stock.getGsm().doubleValue());
+            cells[7].setCellStyle(p2);
+//            cells[5].setCellValue();
+        });
+    }
+
+    /**
+     * 白坯库存匹配
+     *
+     * @param sheet   sheet
+     * @param skuList 库存
+     */
+    public void sheet2(Sheet sheet, List<SkuVO> skuList) {
+        AtomicInteger num = new AtomicInteger(3);
+        skuList.forEach(sku -> {
+            int sr = num.get();
+            Row row = sheet.createRow(num.getAndIncrement());
+            Cell[] cells = new Cell[20];
+            for (int i = 0; i < cells.length; i++) {
+                cells[i] = row.createCell(i);
+            }
+            cells[0].setCellValue(sku.getSku());
+            cells[1].setCellValue(sku.getDesc());
+            cells[2].setCellValue(sku.getGsm().doubleValue());
+            cells[3].setCellValue(sku.getNum());
+            cells[4].setCellValue(sku.getQty());
+            cells[4].setCellStyle(p2);
+            cells[5].setCellValue(sku.getXql());
+            cells[5].setCellStyle(p2);
+            cells[6].setCellValue(sku.getBomCode());
+            cells[7].setCellValue(sku.getBomName());
+            cells[8].setCellValue(sku.getBomSpec());
+            cells[9].setCellValue(CalcUtil.calcGsm(sku.getBomSpec()).doubleValue());
+            boolean out = false;
+            for (TwinOrder order : sku.getOrderList()) {
+                if (out) {
+                    row = sheet.createRow(num.getAndIncrement());
+                    cells = new Cell[20];
+                    for (int i = 0; i < cells.length; i++) {
+                        cells[i] = row.createCell(i);
+                    }
+                }
+                cells[10].setCellValue(DateUtils.parseDateToStr(order.getOrderDate()));
+                cells[11].setCellValue(order.getOrderCode());
+                cells[12].setCellValue(order.getCustomerCode());
+                cells[13].setCellValue(order.getCustomerName());
+                boolean in = false;
+                int ssr = num.get() - 1;
+                for (TwinOrderDetail detail : order.getTwinOrderDetailList()) {
+                    if (in) {
+                        row = sheet.createRow(num.getAndIncrement());
+                        cells = new Cell[20];
+                        for (int i = 0; i < cells.length; i++) {
+                            cells[i] = row.createCell(i);
+                        }
+                    }
+                    cells[14].setCellValue(detail.getColor());
+                    cells[15].setCellValue(detail.getPrice().doubleValue());
+                    cells[16].setCellValue(detail.getTotalPrice().doubleValue());
+                    cells[17].setCellValue(detail.getUnit());
+                    cells[18].setCellValue(detail.getNum().doubleValue());
+                    cells[19].setCellValue(detail.getWeight().doubleValue());
+                    in = true;
+                }
+                out = true;
+                int eer = num.get() - 1;
+                for (int i = 10; i < 14; i++) {
+                    sheet.addMergedRegion(new CellRangeAddress(ssr, eer, i, i));
+                }
+            }
+            int er = num.get() - 1;
+            for (int i = 0; i < 10; i++) {
+                sheet.addMergedRegion(new CellRangeAddress(sr, er, i, i));
+            }
+        });
+    }
+
+    /**
+     * 经编机规格分布
+     *
+     * @param sheet   sheet
+     * @param bomList 库存
+     */
+    public void sheet3(Sheet sheet, List<BomVO> bomList) {
+        AtomicInteger num = new AtomicInteger(3);
+        bomList.forEach(obj -> {
+            int sr = num.get();
+            Row row = sheet.createRow(num.getAndIncrement());
+            Cell[] cells = new Cell[19];
+            for (int i = 0; i < cells.length; i++) {
+                cells[i] = row.createCell(i);
+            }
+            cells[0].setCellValue(obj.getBomCode());
+            cells[1].setCellValue(obj.getBomName());
+            cells[2].setCellValue(obj.getBomSpec());
+            cells[3].setCellValue(obj.getGsm().doubleValue());
+            cells[4].setCellValue(obj.getXql());
+            cells[5].setCellValue(obj.getDeviceIds());
+            cells[6].setCellValue(obj.getLast());
+            cells[7].setCellValue(obj.getYcl());
+
+            boolean out = false;
+            for (TwinOrder order : obj.getOrderList()) {
+                if (out) {
+                    row = sheet.createRow(num.getAndIncrement());
+                    cells = new Cell[19];
+                    for (int i = 0; i < cells.length; i++) {
+                        cells[i] = row.createCell(i);
+                    }
+                }
+                Cell xql = cells[8];
+                cells[9].setCellValue(DateUtils.parseDateToStr(order.getOrderDate()));
+                cells[10].setCellValue(order.getOrderCode());
+                cells[11].setCellValue(order.getCustomerCode());
+                cells[12].setCellValue(order.getCustomerName());
+                boolean in = false;
+                int ssr = num.get() - 1;
+                BigDecimal ow = BigDecimal.ZERO;
+                for (TwinOrderDetail detail : order.getTwinOrderDetailList()) {
+                    if (in) {
+                        row = sheet.createRow(num.getAndIncrement());
+                        cells = new Cell[19];
+                        for (int i = 0; i < cells.length; i++) {
+                            cells[i] = row.createCell(i);
+                        }
+                    }
+                    cells[13].setCellValue(detail.getColor());
+                    cells[14].setCellValue(detail.getPrice().doubleValue());
+                    cells[15].setCellValue(detail.getTotalPrice().doubleValue());
+                    cells[16].setCellValue(detail.getUnit());
+                    cells[17].setCellValue(detail.getNum().doubleValue());
+                    cells[18].setCellValue(detail.getWeight().doubleValue());
+                    ow = ow.add(detail.getWeight());
+                    in = true;
+                }
+                xql.setCellValue(ow.doubleValue());
+                xql.setCellStyle(p2);
+                out = true;
+                int eer = num.get() - 1;
+                for (int i = 8; i < 12; i++) {
+                    sheet.addMergedRegion(new CellRangeAddress(ssr, eer, i, i));
+                }
+            }
+            int er = num.get() - 1;
+            for (int i = 0; i < 8; i++) {
+                sheet.addMergedRegion(new CellRangeAddress(sr, er, i, i));
+            }
+        });
+    }
+
+
+    /**
+     * 白坯布库存--全量
+     *
+     * @param sheet sheet
+     * @param infos 库存
+     */
+    public void sheet4(Sheet sheet, List<TwinFormulaInfo> infos) {
+        AtomicInteger num = new AtomicInteger(3);
+//        infos.sort(Comparator.comparing(TwinFormulaInfo::getFd18).reversed().thenComparing(TwinFormulaInfo::getFd16).thenComparing(TwinFormulaInfo::getFd17).thenComparing(TwinFormulaInfo::getFd3));
+        infos.forEach(info -> {
+            Row row = sheet.createRow(num.getAndIncrement());
+            Cell[] cells = new Cell[36];
+            for (int i = 0; i < cells.length; i++) {
+                cells[i] = row.createCell(i);
+            }
+            cells[0].setCellValue(info.getFd2());
+            cells[1].setCellValue(info.getFd18());
+            cells[2].setCellValue(info.getFd16());
+            cells[3].setCellValue(info.getFd17());
+            cells[4].setCellValue(info.getGsm().floatValue());
+            cells[5].setCellValue(info.getFd3());
+            cells[6].setCellValue(info.getFd15());
+            cells[7].setCellValue(info.getFd4());
+            cells[8].setCellValue(info.getFd5());
+            cells[9].setCellValue(info.getFd6());
+            cells[10].setCellValue(info.getFd1());
+            cells[11].setCellValue(info.getFd13());
+            cells[12].setCellValue(info.getFd14());
+            cells[13].setCellValue(info.getFd24());
+            cells[14].setCellValue(info.getFd25());
+
+            cells[15].setCellValue(info.getCd10());
+            cells[16].setCellValue(info.getCd11());
+            cells[17].setCellValue(info.getCd12());
+            cells[18].setCellValue(info.getCd13());
+            cells[19].setCellValue(info.getCd14());
+            cells[20].setCellValue(info.getCd15());
+            cells[21].setCellValue(info.getCd16());
+            cells[22].setCellValue(info.getCd17());
+            cells[23].setCellValue(info.getCd18());
+            cells[24].setCellValue(info.getCd19());
+
+            cells[25].setCellValue(info.getFd19());
+            cells[26].setCellValue(info.getFd20());
+            cells[27].setCellValue(info.getFd21());
+            cells[28].setCellValue(info.getFd22());
+            cells[29].setCellValue(info.getFd23());
+
+            cells[30].setCellValue(info.getFd7());
+            cells[31].setCellValue(info.getFd8());
+            cells[32].setCellValue(info.getFd9());
+            cells[33].setCellValue(info.getFd10());
+            cells[34].setCellValue(info.getFd11());
+            cells[35].setCellValue(info.getFd12());
+        });
+    }
+
+    /**
+     * 匹配库存,新匹配方式,以幅宽和平方米克重来匹配
+     * 订单中计算得到毛毯平方米克重要求,根据长宽规格,先以产品长度匹配白胚库中的幅宽规格。
+     * 如没有或不足,以宽匹配,但此时要做标注,以准备网框的工艺切换。
+     * 白胚库的规格,只以平方米克重和幅宽为规格单位。
+     *
+     * @param spec   规格
+     * @param stocks 库存
+     * @return 结果
+     */
+    private VmsStock matchStock(String spec, List<VmsStock> stocks) {
+        //按平方米克重分组
+        Map<BigDecimal, List<VmsStock>> stockMap = stocks.stream().collect(Collectors.groupingBy(VmsStock::getGsm, LinkedHashMap::new, Collectors.toList()));
+        if (spec != null) {
+            String[] tmp = spec.split("\\*");
+            if (tmp.length == 3) {
+                //长
+                float length = Float.parseFloat(tmp[0]);
+                //宽
+                float width = Float.parseFloat(tmp[1]);
+                BigDecimal gsm = CalcUtil.calcGsm(spec);
+                List<VmsStock> tempList = new ArrayList<>();
+                for (BigDecimal key : stockMap.keySet()) {
+                    // 计算 gsm 和 key 的差值
+                    BigDecimal difference = gsm.subtract(key).abs();
+                    // 如果差值在正负10之间
+                    if (difference.compareTo(new BigDecimal(10)) <= 0) {
+                        // 将对应的 VmsStock 列表添加到 tempList 中
+                        tempList.addAll(stockMap.get(key));
+                    }
+                }
+                //计算差值,匹配差值最小的
+                float xx = 1000f;
+                VmsStock result = null;
+                for (VmsStock stock : tempList) {
+                    float yyy = stock.getLength().floatValue() - length;
+                    if (yyy < xx) {
+                        result = stock;
+                    }
+                }
+                if (result == null) {
+                    for (VmsStock stock : tempList) {
+                        float yyy = stock.getLength().floatValue() - width;
+                        if (yyy < xx) {
+                            result = stock;
+                        }
+                    }
+                }
+                return result;
+
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * 匹配产线
+     *
+     * @param spec 规格
+     * @param list 产线
+     * @return 结果
+     */
+    private List<TwinFormulaInfo> matchFormula(String spec, List<TwinFormulaInfo> list) {
+        List<TwinFormulaInfo> result = new ArrayList<>();
+        //按平方米克重分组
+        Map<BigDecimal, List<TwinFormulaInfo>> formulaMap = list.stream().collect(Collectors.groupingBy(TwinFormulaInfo::getGsm, LinkedHashMap::new, Collectors.toList()));
+        if (spec != null) {
+            String[] tmp = spec.split("\\*");
+            if (tmp.length == 3) {
+                Float length = Float.parseFloat(tmp[0]);
+                Float width = Float.parseFloat(tmp[1]);
+                BigDecimal gsm = CalcUtil.calcGsm(spec);
+                List<TwinFormulaInfo> tempList = new ArrayList<>();
+                for (BigDecimal key : formulaMap.keySet()) {
+                    // 计算 gsm 和 key 的差值
+                    BigDecimal difference = gsm.subtract(key).abs();
+                    // 如果差值在正负10之间
+                    if (difference.compareTo(new BigDecimal(10)) <= 0) {
+                        // 将对应的 VmsStock 列表添加到 tempList 中
+                        tempList.addAll(formulaMap.get(key));
+                    }
+                }
+                for (TwinFormulaInfo info : tempList) {
+                    if (info.getFd16() >= length && info.getFd17() >= width ||
+                            info.getFd17() >= length && info.getFd16() >= width) {
+                        result.add(info);
+                    }
+                }
+                return result;
+            }
+        }
+        return result;
+    }
+}

+ 15 - 1
jjt-biz/src/main/java/com/jjt/order/vo/BomVO.java

@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -15,8 +16,9 @@ import java.util.List;
  */
 @Data
 @ApiModel(value = "BomVO", description = "物料视图")
-public class BomVO{
+public class BomVO {
     private static final long serialVersionUID = 1L;
+
     @ApiModelProperty(name = "物料编码")
     private String bomCode;
 
@@ -53,6 +55,18 @@ public class BomVO{
     @ApiModelProperty(name = "最近日产量")
     private Double last;
 
+    @ApiModelProperty(name = "平方米克重")
+    private BigDecimal gsm;
+
     @ApiModelProperty(name = "订单信息")
     private List<TwinOrder> orderList;
+
+    public void init() {
+        this.orders = 0L;
+        this.xql = 0d;
+        this.kcl = 0f;
+        this.ycl = 0d;
+        this.cz = 0d;
+        this.cl = 0d;
+    }
 }

+ 3 - 0
jjt-biz/src/main/java/com/jjt/order/vo/SkuVO.java

@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -33,6 +34,8 @@ public class SkuVO {
     private String bomSpec;
     @ApiModelProperty(name = "需求总重量")
     private Double xql;
+    @ApiModelProperty(name = "平方米克重")
+    private BigDecimal gsm;
     @ApiModelProperty(name = "订单信息")
     private List<TwinOrder> orderList;
 }

+ 1 - 0
jjt-biz/src/main/java/com/jjt/utils/MssqlUtil.java

@@ -84,6 +84,7 @@ public class MssqlUtil {
                         if (tmp.length > 1) {
                             stock.setLength(Float.parseFloat(tmp[0]));
                             stock.setMick(Integer.parseInt(tmp[1]));
+                            stock.setGsm();
                         }
                     }
                     stocks.add(stock);

BIN
jjt-biz/src/main/resources/tpl/order-gsm.xlsx


BIN
jjt-biz/src/main/resources/tpl/order.xlsx