From 0dfdc8148cc266fd3e877183c5b162fb986d5c65 Mon Sep 17 00:00:00 2001
From: huang <1532065656@qq.com>
Date: 星期五, 12 十二月 2025 15:38:56 +0800
Subject: [PATCH] 修改导入工程json格式

---
 mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java |  547 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 541 insertions(+), 6 deletions(-)

diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java
index 2e81b91..e0c1ea0 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java
@@ -1,19 +1,25 @@
 package com.mes.device.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.mes.device.entity.GlassInfo;
 import com.mes.device.mapper.DeviceGlassInfoMapper;
+import com.mes.device.service.EngineeringSequenceService;
 import com.mes.device.service.GlassInfoService;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
+
+import static java.util.stream.IntStream.range;
 
 /**
  * 鐜荤拑淇℃伅鏈嶅姟瀹炵幇绫�
@@ -22,8 +28,12 @@
  * @since 2024-11-20
  */
 @Slf4j
+@RefreshScope
 @Service("deviceGlassInfoService")
 public class GlassInfoServiceImpl extends ServiceImpl<DeviceGlassInfoMapper, GlassInfo> implements GlassInfoService {
+
+    @Autowired
+    private EngineeringSequenceService engineeringSequenceService;
 
     @Override
     public GlassInfo getGlassInfo(String glassId) {
@@ -100,8 +110,35 @@
             GlassInfo existing = baseMapper.selectByGlassId(glassInfo.getGlassId());
             if (existing != null) {
                 glassInfo.setId(existing.getId());
+                // 淇濈暀鍘熷鍒涘缓淇℃伅
+                if (glassInfo.getCreatedTime() == null) {
+                    glassInfo.setCreatedTime(existing.getCreatedTime());
+                }
+                if (glassInfo.getCreatedBy() == null) {
+                    glassInfo.setCreatedBy(existing.getCreatedBy());
+                }
+                // 鏇存柊涓哄綋鍓嶆椂闂�
+                if (glassInfo.getUpdatedTime() == null) {
+                    glassInfo.setUpdatedTime(new Date());
+                }
+                if (glassInfo.getUpdatedBy() == null) {
+                    glassInfo.setUpdatedBy("system");
+                }
                 return updateById(glassInfo);
             } else {
+                Date now = new Date();
+                if (glassInfo.getCreatedTime() == null) {
+                    glassInfo.setCreatedTime(now);
+                }
+                if (glassInfo.getUpdatedTime() == null) {
+                    glassInfo.setUpdatedTime(now);
+                }
+                if (glassInfo.getCreatedBy() == null) {
+                    glassInfo.setCreatedBy("system");
+                }
+                if (glassInfo.getUpdatedBy() == null) {
+                    glassInfo.setUpdatedBy("system");
+                }
                 return save(glassInfo);
             }
         } catch (Exception e) {
@@ -136,7 +173,7 @@
             Date timeThreshold = new Date(System.currentTimeMillis() - minutes * 60 * 1000L);
             
             LambdaQueryWrapper<GlassInfo> wrapper = new LambdaQueryWrapper<>();
-            wrapper.eq(GlassInfo::getStatus, GlassInfo.Status.ACTIVE)
+            wrapper.eq(GlassInfo::getStatus, GlassInfo.Status.PENDING)
                    .ge(GlassInfo::getCreatedTime, timeThreshold)
                    .orderByDesc(GlassInfo::getCreatedTime)
                    .last("LIMIT " + limit);
@@ -160,5 +197,503 @@
             return Collections.emptyList();
         }
     }
+
+    @Override
+    public boolean updateGlassStatus(List<String> glassIds, String status) {
+        if (CollectionUtils.isEmpty(glassIds) || status == null) {
+            return true;
+        }
+        try {
+            LambdaUpdateWrapper<GlassInfo> wrapper = new LambdaUpdateWrapper<>();
+            wrapper.in(GlassInfo::getGlassId, glassIds);
+            GlassInfo update = new GlassInfo();
+            update.setStatus(status);
+            update.setUpdatedTime(new Date());
+            update.setUpdatedBy("system");
+            return this.update(update, wrapper);
+        } catch (Exception e) {
+            log.error("鎵归噺鏇存柊鐜荤拑鐘舵�佸け璐�, glassIds={}, status={}", glassIds, status, e);
+            return false;
+        }
+    }
+
+    @Value("${mes.engineering.import-url}")
+    private String mesEngineeringImportUrl;
+
+    @Override
+    public String getMesEngineeringImportUrl() {
+        return mesEngineeringImportUrl;
+    }
+
+    @Override
+    public Map<String, Object> buildEngineerImportPayload(List<Map<String, Object>> excelRows) {
+        Map<String, Object> result = new HashMap<>();
+        if (excelRows == null || excelRows.isEmpty()) {
+            return result;
+        }
+
+        // 宸ョ▼鍙风敓鎴愶細姣忔瀵煎叆閮界敓鎴愭柊鐨勫伐绋嬪彿锛堜娇鐢ㄦ暟鎹簱鑷搴忓彿锛岄伩鍏嶉噸澶嶏級
+        final String engineerId = engineeringSequenceService.generateAndSaveEngineeringId(new Date());
+        final String filmsIdDefault = firstValue(excelRows, "filmsId", "鐧界幓");
+        final double thicknessDefault = parseDouble(firstValue(excelRows, "thickness"), 0d);
+
+        // glassInfolList
+        final String engineerIdFinal = engineerId;
+        final String filmsIdDefaultFinal = filmsIdDefault;
+        final double thicknessDefaultFinal = thicknessDefault;
+
+        // 鐢ㄤ簬鎸� flowCardId 鍏ㄥ眬璁℃暟搴忓彿
+        Map<String, Integer> flowCardSequenceCounter = new HashMap<>();
+        // 鐢ㄤ簬鎸� flowCardId 璁℃暟 temperingFeedSequence
+        Map<String, Integer> temperingFeedSequenceCounter = new HashMap<>();
+        // 鐢ㄤ簬鎸� flowCardId 鍒嗛厤 temperingLayoutId
+        Map<String, Integer> temperingLayoutIdMap = new HashMap<>();
+        AtomicInteger nextTemperingLayoutId = new AtomicInteger(1);
+        
+        // 鍏堝缓绔嬪師鐗囨槧灏勶紝鐢ㄤ簬鍚庣画鍖归厤 rawSequence
+        Map<String, Integer> rawSequenceMap = new HashMap<>();
+        for (Map<String, Object> row : excelRows) {
+            double width = parseDouble(row.get("width"), 0d);
+            double height = parseDouble(row.get("height"), 0d);
+            double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal);
+            String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal);
+            String key = width + "_" + height + "_" + thickness + "_" + filmsId;
+            if (!rawSequenceMap.containsKey(key)) {
+                rawSequenceMap.put(key, rawSequenceMap.size() + 1);
+            }
+        }
+
+        List<Map<String, Object>> glassInfolList = excelRows.stream()
+                .flatMap(row -> {
+                    Object qtyObj = row.getOrDefault("quantity", 1);
+                    int qty = parseDouble(qtyObj, 1) > 0 ? (int) parseDouble(qtyObj, 1) : 1;
+
+                    String glassId = str(row.get("glassId"));
+                    String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal);
+                    String flowCardId = str(row.get("flowCardId"));
+                    // orderNumber 鏄暣鍨嬶紙鐜荤拑绫诲瀷锛夛紝浠� Excel 璇诲彇鎴栦娇鐢ㄩ粯璁ゅ�� 1
+                    Object orderNumberObj = row.get("orderNumber");
+                    final Integer finalOrderNumber = orderNumberObj != null 
+                            ? (int) parseDouble(orderNumberObj, 1) 
+                            : 1;
+                    String productName = str(row.get("productName"));
+                    String customerName = str(row.get("customerName"));
+                    double width = parseDouble(row.get("width"), 0d);
+                    double height = parseDouble(row.get("height"), 0d);
+                    double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal);
+                    
+                    // 璁$畻 rawSequence
+                    String rawKey = width + "_" + height + "_" + thickness + "_" + filmsId;
+                    Integer rawSequence = rawSequenceMap.get(rawKey);
+
+                    int finalQty = qty;
+                    log.info("瑙f瀽鍒版暟閲忥細row={}, quantity={}, 鏈�缁坬ty={}", row, qtyObj, finalQty);
+                    return range(0, qty).mapToObj(idx -> {
+                        String baseGlassId = engineerIdFinal + glassId;
+                        String finalGlassId = finalQty > 1 ? baseGlassId + (idx + 1) : baseGlassId;
+
+                        String baseFlowCardId = flowCardId.isEmpty() ? baseGlassId : flowCardId;
+                        // 濡傛灉 baseFlowCardId 宸茬粡鍖呭惈灏鹃儴 "/鏁板瓧"锛屽厛鍘绘帀锛屽啀鐢卞悗绔粺涓�杩藉姞搴忓彿
+                        baseFlowCardId = baseFlowCardId.replaceFirst("/\\d+$", "");
+                        // 鎸� flowCardId 鍏ㄥ眬閫掑搴忓彿
+                        int sequenceNum = flowCardSequenceCounter.compute(baseFlowCardId, (k, v) -> (v == null ? 0 : v) + 1);
+                        String finalFlowCardSequence = baseFlowCardId + "/" + 1;
+                        
+                        // 鎸� flowCardId 鍒嗛厤 temperingLayoutId
+                        Integer temperingLayoutId = temperingLayoutIdMap.computeIfAbsent(baseFlowCardId, k -> nextTemperingLayoutId.getAndIncrement());
+                        // 鎸� flowCardId 閫掑 temperingFeedSequence
+                        int temperingFeedSequence = temperingFeedSequenceCounter.compute(baseFlowCardId, (k, v) -> (v == null ? 0 : v) + 1);
+                        
+                        log.debug("鐢熸垚flowCardSequence: idx={}, baseFlowCardId={}, sequenceNum={}, finalFlowCardSequence={}, temperingLayoutId={}, temperingFeedSequence={}", 
+                                idx, baseFlowCardId, sequenceNum, finalFlowCardSequence, temperingLayoutId, temperingFeedSequence);
+
+                        Map<String, Object> m = new HashMap<>();
+                        m.put("xAxis", 0);
+                        m.put("xCoordinate", 0);
+                        m.put("yAxis", 0);
+                        m.put("yCoordinate", 0);
+                        m.put("glassId", finalGlassId);
+                        m.put("engineerId", engineerIdFinal);
+                        m.put("flowCardId", baseFlowCardId);
+                        m.put("orderNumber", finalOrderNumber);
+                        m.put("productSortNumber", 1); // 缁熶竴涓�1
+                        m.put("hollowCombineDirection", "");
+                        m.put("width", width);
+                        m.put("height", height);
+                        m.put("thickness", thickness);
+                        m.put("filmsId", filmsId);
+                        m.put("layer", 1);
+                        m.put("totalLayer", 1);
+                        m.put("edgWidth", width);
+                        m.put("edgHeight", height);
+                        m.put("isMultiple", finalQty > 1 ? 1 : 0); // 鏁伴噺>1鏃朵负1
+                        m.put("maxWidth", width);
+                        m.put("maxHeight", height);
+                        m.put("isHorizontal", 0);
+                        m.put("rawSequence", rawSequence != null ? rawSequence : 0);
+                        m.put("temperingLayoutId", temperingLayoutId);
+                        m.put("temperingFeedSequence", temperingFeedSequence);
+                        m.put("angle", 0);
+                        m.put("ruleId", 0);
+                        m.put("combine", 0);
+                        m.put("markIcon", "");
+                        m.put("filmRemove", 0);
+                        m.put("flowCardSequence", finalFlowCardSequence);
+                        m.put("process", "");
+                        m.put("rawAngle", 0);
+                        m.put("graphNo", 0);
+                        m.put("processParam", "");
+                        return m;
+                    });
+                })
+                .collect(Collectors.toList());
+
+        // 鍘熺墖淇℃伅鍘婚噸
+        Map<String, Map<String, Object>> rawGlassMap = new HashMap<>();
+        for (Map<String, Object> row : excelRows) {
+            double width = parseDouble(row.get("width"), 0d);
+            double height = parseDouble(row.get("height"), 0d);
+            double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal);
+            String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal);
+            String key = width + "_" + height + "_" + thickness + "_" + filmsId;
+            if (!rawGlassMap.containsKey(key)) {
+                Map<String, Object> m = new HashMap<>();
+                m.put("engineeringId", engineerIdFinal);
+                m.put("filmsId", filmsId);
+                m.put("rawGlassWidth", width);
+                m.put("rawGlassHeight", height);
+                m.put("rawGlassThickness", thickness);
+                m.put("rawSequence", rawGlassMap.size() + 1);
+                m.put("usageRate", "0.95");
+                rawGlassMap.put(key, m);
+            }
+        }
+
+        List<Map<String, Object>> engineeringRawQueueList = rawGlassMap.values().stream().collect(Collectors.toList());
+
+        // 娴佺▼鍗′俊鎭紙闇�瑕佺粺璁℃瘡涓� flowCardId 鐨勫疄闄呯幓鐠冩暟閲忥紝鑰冭檻 quantity锛�
+        Map<String, Map<String, Object>> flowCardMap = new HashMap<>();
+        for (Map<String, Object> row : excelRows) {
+            String glassId = str(row.get("glassId"));
+            String flowCardId = str(row.get("flowCardId"));
+            if (flowCardId.isEmpty()) {
+                flowCardId = engineerIdFinal + glassId;
+            }
+            // 鍘绘帀灏鹃儴 "/鏁板瓧"锛堝鏋滄湁锛�
+            flowCardId = flowCardId.replaceFirst("/\\d+$", "");
+            // orderNumber 鏄暣鍨嬶紙鐜荤拑绫诲瀷锛夛紝浠� Excel 璇诲彇鎴栦娇鐢ㄩ粯璁ゅ�� 1
+            Object orderNumberObj = row.get("orderNumber");
+            Integer orderNumber = orderNumberObj != null 
+                    ? (int) parseDouble(orderNumberObj, 1) 
+                    : 1;
+            Object qtyObj = row.getOrDefault("quantity", 1);
+            int qty = parseDouble(qtyObj, 1) > 0 ? (int) parseDouble(qtyObj, 1) : 1;
+            double width = parseDouble(row.get("width"), 0d);
+            double height = parseDouble(row.get("height"), 0d);
+            double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal);
+            String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal);
+            String productName = str(row.get("productName"));
+            String customerName = str(row.get("customerName"));
+
+            Map<String, Object> exist = flowCardMap.get(flowCardId);
+            if (exist == null) {
+                Map<String, Object> m = new HashMap<>();
+                m.put("flowCardId", flowCardId);
+                m.put("width", width);
+                m.put("height", height);
+                m.put("thickness", thickness);
+                m.put("filmsId", filmsId);
+                m.put("totalLayer", 1);
+                m.put("layer", 1);
+                m.put("glassTotal", qty); // 浣跨敤瀹為檯鏁伴噺
+                m.put("orderNumber", orderNumber);
+                m.put("productName", productName);
+                m.put("customerName", customerName);
+                flowCardMap.put(flowCardId, m);
+            } else {
+                int count = (int) exist.getOrDefault("glassTotal", 0);
+                exist.put("glassTotal", count + qty); // 绱姞鏁伴噺
+            }
+        }
+        List<Map<String, Object>> flowCardInfoList = flowCardMap.values().stream().collect(Collectors.toList());
+
+        // 姹囨��
+        int glassTotal = glassInfolList.size();
+        double glassTotalArea = glassInfolList.stream()
+                .mapToDouble(m -> parseDouble(m.get("width"), 0d) * parseDouble(m.get("height"), 0d) / 1_000_000d)
+                .sum();
+        double patternArea = engineeringRawQueueList.stream()
+                .mapToDouble(m -> parseDouble(m.get("rawGlassWidth"), 0d) * parseDouble(m.get("rawGlassHeight"), 0d) / 1_000_000d)
+                .sum();
+
+        // 璁$畻鏈�澶ц礋杞藉昂瀵革紙鐢ㄤ簬閽㈠寲鍙傛暟锛�
+        double maxLoadWidth = glassInfolList.stream()
+                .mapToDouble(m -> parseDouble(m.get("width"), 0d))
+                .max().orElse(2000);
+        double maxLoadLength = glassInfolList.stream()
+                .mapToDouble(m -> parseDouble(m.get("height"), 0d))
+                .max().orElse(3000);
+        
+        // 鐢熸垚閽㈠寲鍙傛暟
+        List<Map<String, Object>> temperingParameterList = new ArrayList<>();
+        Map<String, Object> temperingParam = new HashMap<>();
+        temperingParam.put("engineerId", engineerIdFinal);
+        temperingParam.put("heatMode", 1);
+        temperingParam.put("chaosPct", 50);
+        temperingParam.put("maxLoadPct", 100);
+        temperingParam.put("loadWidth", (int) Math.round(maxLoadWidth));
+        temperingParam.put("loadLength", (int) Math.round(maxLoadLength));
+        temperingParam.put("xSpace", 50);
+        temperingParam.put("ySpace", 50);
+        temperingParam.put("rotateMode", 0);
+        temperingParam.put("allowRotate", 0);
+        temperingParam.put("tempering", 1);
+        temperingParam.put("curtainWall", 0);
+        temperingParameterList.add(temperingParam);
+        
+        result.put("engineerId", engineerIdFinal);
+        result.put("engineerName", thicknessDefaultFinal + "mm" + filmsIdDefaultFinal);
+        result.put("avgAvailability", "90");
+        result.put("validAvailability", "90");
+        result.put("lastAvailability", "90");
+        result.put("glassTotal", glassTotal);
+        result.put("glassTotalArea", round2(glassTotalArea));
+        result.put("planPatternTotal", engineeringRawQueueList.size());
+        result.put("planPatternTotalArea", round2(patternArea));
+        result.put("realityPatternTotal", engineeringRawQueueList.size());
+        result.put("realityPatternTotalArea", round2(patternArea));
+        result.put("filmsId", filmsIdDefaultFinal);
+        result.put("thickness", thicknessDefaultFinal);
+        result.put("engineeringRawQueueList", engineeringRawQueueList);
+        result.put("glassInfolList", glassInfolList);
+        result.put("flowCardInfoList", flowCardInfoList);
+        result.put("hollowFormulaDetailsList", null);
+        result.put("temperingParameterList", null);
+
+        return result;
+    }
+
+
+    /**
+     * 鎻愬彇List涓涓�涓狹ap鐨勬寚瀹歬ey鍊硷紙榛樿绌哄瓧绗︿覆锛�
+     *
+     * @param rows 鏁版嵁琛屽垪琛紙鍙负null/绌猴級
+     * @param key  瑕佹彁鍙栫殑閿�
+     * @return 绗竴涓狹ap鐨刱ey瀵瑰簲鍊硷紙绌哄垯杩斿洖""锛�
+     */
+    private String firstValue(List<Map<String, Object>> rows, String key) {
+        return firstValue(rows, key, "");
+    }
+
+    /**
+     * 鎻愬彇List涓涓�涓狹ap鐨勬寚瀹歬ey鍊硷紙鑷畾涔夐粯璁ゅ�硷級
+     *
+     * @param rows       鏁版嵁琛屽垪琛紙鍙负null/绌猴級
+     * @param key        瑕佹彁鍙栫殑閿�
+     * @param defaultVal 绌哄�兼椂鐨勯粯璁よ繑鍥炲��
+     * @return 绗竴涓狹ap鐨刱ey瀵瑰簲鍊硷紙绌哄垯杩斿洖defaultVal锛�
+     */
+    private String firstValue(List<Map<String, Object>> rows, String key, String defaultVal) {
+        if (rows == null || rows.isEmpty() || key == null) {
+            return defaultVal;
+        }
+
+        Map<String, Object> firstRow = rows.get(0);
+        Object value = firstRow.get(key);
+        return value == null ? defaultVal : value.toString();
+    }
+
+    /**
+     * 瀵硅薄杞瓧绗︿覆锛坣ull杞┖涓诧紝鑷姩鍘婚櫎棣栧熬绌烘牸锛�
+     *
+     * @param v 寰呰浆鎹㈠璞�
+     * @return 澶勭悊鍚庣殑瀛楃涓�
+     */
+    private String str(Object v) {
+        return v == null ? "" : v.toString().trim();
+    }
+
+    /**
+     * 瀵硅薄杞瓧绗︿覆锛堢┖涓叉椂杩斿洖榛樿鍊硷紝鑷姩鍘婚櫎棣栧熬绌烘牸锛�
+     *
+     * @param v   寰呰浆鎹㈠璞�
+     * @param def 绌哄�奸粯璁ゅ��
+     * @return 澶勭悊鍚庣殑瀛楃涓�
+     */
+    private String strOrDefault(Object v, String def) {
+        String result = str(v);
+        return result.isEmpty() ? def : result;
+    }
+
+    /**
+     * 瑙f瀽瀵硅薄涓篸ouble锛堝け璐�/绌哄�艰繑鍥為粯璁ゅ�硷級
+     *
+     * @param v   寰呰В鏋愬璞★紙鏀寔鏁板瓧/瀛楃涓茬被鍨嬶級
+     * @param def 瑙f瀽澶辫触鏃剁殑榛樿鍊�
+     * @return 瑙f瀽鍚庣殑double鍊�
+     */
+    private double parseDouble(Object v, double def) {
+        if (v == null) {
+            return def;
+        }
+
+        try {
+            if (v instanceof Number) {
+                return ((Number) v).doubleValue();
+            }
+            return Double.parseDouble(v.toString().trim());
+        } catch (NumberFormatException e) {
+            // 浠呮崟鑾锋暟瀛楁牸寮忓寲寮傚父锛岄伩鍏嶅悶鎺夊叾浠栧紓甯�
+            return def;
+        }
+    }
+
+    /**
+     * 淇濈暀涓や綅灏忔暟锛堝洓鑸嶄簲鍏ワ級
+     *
+     * @param v 鍘熷鏁板��
+     * @return 淇濈暀涓や綅灏忔暟鍚庣殑鏁板��
+     */
+    private double round2(double v) {
+        return Math.round(v * 100.0) / 100.0;
+    }
+
+    @Override
+    public List<GlassInfo> getGlassInfosByEngineeringId(String engineeringId) {
+        if (engineeringId == null || engineeringId.trim().isEmpty()) {
+            return Collections.emptyList();
+        }
+        try {
+            return baseMapper.selectByEngineeringId(engineeringId.trim());
+        } catch (Exception e) {
+            log.error("鏍规嵁宸ョ▼鍙锋煡璇㈢幓鐠冧俊鎭け璐�, engineeringId={}", engineeringId, e);
+            return Collections.emptyList();
+        }
+    }
+
+    @Override
+    public void saveGlassInfosFromExcel(List<Map<String, Object>> excelRows, String engineeringId) {
+        if (excelRows == null || excelRows.isEmpty() || engineeringId == null || engineeringId.trim().isEmpty()) {
+            return;
+        }
+
+        List<GlassInfo> glassInfos = new ArrayList<>();
+        Date now = new Date();
+
+        for (Map<String, Object> row : excelRows) {
+            String glassId = str(row.get("glassId"));
+            if (glassId == null || glassId.trim().isEmpty()) {
+                continue;
+            }
+
+            int qty = (int) parseDouble(row.getOrDefault("quantity", 1), 1);
+            if (qty <= 0) qty = 1;
+
+            double width = parseDouble(row.get("width"), 0d);
+            double height = parseDouble(row.get("height"), 0d);
+            double thickness = parseDouble(row.get("thickness"), 0d);
+
+            // 涓庡鍏ヨ鍒欎繚鎸佷竴鑷达細glassId 鍓嶅姞宸ョ▼鍙峰墠缂�锛屾暟閲�>1鏃惰拷鍔犲簭鍙�
+            String baseGlassId = engineeringId.trim() + glassId;
+            for (int idx = 0; idx < qty; idx++) {
+                String finalGlassId = qty > 1 ? baseGlassId + "_" + (idx + 1) : baseGlassId;
+
+                GlassInfo glassInfo = new GlassInfo();
+                glassInfo.setGlassId(finalGlassId);
+                glassInfo.setEngineeringId(engineeringId.trim());
+                glassInfo.setGlassLength((int) Math.round(height));
+                glassInfo.setGlassWidth((int) Math.round(width));
+                glassInfo.setGlassThickness(BigDecimal.valueOf(thickness));
+                glassInfo.setStatus(GlassInfo.Status.ACTIVE);
+                glassInfo.setState(0);
+                glassInfo.setCreatedTime(now);
+                glassInfo.setUpdatedTime(now);
+                glassInfo.setCreatedBy("system");
+                glassInfo.setUpdatedBy("system");
+
+                glassInfos.add(glassInfo);
+            }
+        }
+
+        if (!glassInfos.isEmpty()) {
+            batchSaveOrUpdateGlassInfo(glassInfos);
+            log.info("宸蹭繚瀛� {} 鏉$幓鐠冧俊鎭埌鏈湴鏁版嵁搴擄紝宸ョ▼鍙�: {}", glassInfos.size(), engineeringId);
+        }
+    }
+
+    @Override
+    public boolean updateGlassStateAfterScan(String glassId, Integer width, Integer height, Integer workLine) {
+        if (glassId == null || glassId.trim().isEmpty()) {
+            return false;
+        }
+
+        try {
+            // 鏌ヨ宸插瓨鍦ㄧ殑鐜荤拑淇℃伅
+            GlassInfo existing = baseMapper.selectByGlassId(glassId.trim());
+            if (existing == null) {
+                log.debug("鐜荤拑淇℃伅涓嶅瓨鍦紝鏃犳硶鏇存柊鐘舵��: glassId={}", glassId);
+                return false;
+            }
+
+            // 鏇存柊鐘舵�佷负1锛堝凡鎵爜浜や簰锛�
+            LambdaUpdateWrapper<GlassInfo> wrapper = new LambdaUpdateWrapper<>();
+            wrapper.eq(GlassInfo::getGlassId, glassId.trim())
+                   .eq(GlassInfo::getIsDeleted, 0)
+                   .set(GlassInfo::getState, 1)
+                   .set(GlassInfo::getUpdatedTime, new Date())
+                   .set(GlassInfo::getUpdatedBy, "system");
+
+            // 濡傛灉鎻愪緵浜嗗昂瀵镐俊鎭紝涔熸洿鏂板昂瀵�
+            if (width != null) {
+                wrapper.set(GlassInfo::getGlassWidth, width);
+            }
+            if (height != null) {
+                wrapper.set(GlassInfo::getGlassLength, height);
+            }
+            if (workLine != null) {
+                wrapper.set(GlassInfo::getWorkLine, workLine);
+            }
+
+            boolean updated = this.update(wrapper);
+            if (updated) {
+                log.info("宸叉洿鏂扮幓鐠冧俊鎭姸鎬佷负宸叉壂鐮佷氦浜�: glassId={}, state=1", glassId);
+            }
+            return updated;
+        } catch (Exception e) {
+            log.error("鏇存柊鐜荤拑淇℃伅鐘舵�佸け璐�: glassId={}", glassId, e);
+            return false;
+        }
+    }
+
+    @Override
+    public int deleteGlassInfosByEngineeringId(String engineeringId) {
+        if (engineeringId == null || engineeringId.trim().isEmpty()) {
+            return 0;
+        }
+
+        try {
+            // 鍏堟煡璇㈣鍒犻櫎鐨勬暟閲忥紙鍒犻櫎鍓嶏級
+            LambdaQueryWrapper<GlassInfo> countWrapper = new LambdaQueryWrapper<>();
+            countWrapper.eq(GlassInfo::getEngineeringId, engineeringId.trim())
+                       .eq(GlassInfo::getIsDeleted, 0); // 鏌ヨ鏈垹闄ょ殑璁板綍
+            long count = this.count(countWrapper);
+            
+            // 浣跨敤MyBatis-Plus鐨剅emove鏂规硶锛屼細鏍规嵁@TableLogic鑷姩杩涜閫昏緫鍒犻櫎
+            LambdaQueryWrapper<GlassInfo> removeWrapper = new LambdaQueryWrapper<>();
+            removeWrapper.eq(GlassInfo::getEngineeringId, engineeringId.trim())
+                        .eq(GlassInfo::getIsDeleted, 0); // 鍙垹闄ゆ湭鍒犻櫎鐨勮褰�
+            
+            boolean result = this.remove(removeWrapper);
+            if (result) {
+                log.info("宸插垹闄ゅ伐绋嬪彿涓嬬殑鐜荤拑淇℃伅: engineeringId={}, count={}", engineeringId, count);
+                return (int) count;
+            }
+            return 0;
+        } catch (Exception e) {
+            log.error("鍒犻櫎宸ョ▼鍙蜂笅鐨勭幓鐠冧俊鎭け璐�: engineeringId={}", engineeringId, e);
+            return 0;
+        }
+    }
+
 }
 

--
Gitblit v1.8.0