mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java
@@ -233,8 +233,18 @@
            return result;
        }
        // 工程号生成:每次导入都生成新的工程号(先只生成,不保存到数据库,等到MES调用成功后再保存)
        final String engineerId = engineeringSequenceService.generateEngineeringId(new Date());
        // 工程号:代表整个Excel表,优先使用Excel中的工程号(从第一行或任意一行获取),如果所有行都没有则自动生成
        String engineerIdFromExcel = null;
        for (Map<String, Object> row : excelRows) {
            String engineeringId = str(row.get("engineeringId"));
            if (engineeringId != null && !engineeringId.trim().isEmpty()) {
                engineerIdFromExcel = engineeringId.trim();
                break; // 找到第一个非空的工程号就使用
            }
        }
        final String engineerId = engineerIdFromExcel != null
                ? engineerIdFromExcel
                : engineeringSequenceService.generateEngineeringId(new Date());
        final String filmsIdDefault = firstValue(excelRows, "filmsId", "白玻");
        final double thicknessDefault = parseDouble(firstValue(excelRows, "thickness"), 0d);
@@ -246,6 +256,15 @@
        // 生成日期字符串(yyMMdd格式),用于流程卡ID生成
        LocalDate localDate = new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        String dateStr = localDate.format(DateTimeFormatter.ofPattern("yyMMdd"));
        // 检查是否有流程卡ID:如果所有行的流程卡ID都为空,则所有记录共享同一个流程卡ID
        boolean allFlowCardIdEmpty = excelRows.stream()
                .allMatch(row -> {
                    String flowCardId = str(row.get("flowCardId"));
                    return flowCardId == null || flowCardId.trim().isEmpty();
                });
        // 如果所有流程卡ID都为空,生成一个共享的流程卡ID
        String sharedFlowCardId = allFlowCardIdEmpty ? "NG" + dateStr + "01A001" : null;
        
        // 用于存储每个玻璃ID对应的流程卡ID(同一玻璃ID的多个玻璃共享同一个流程卡ID)
        Map<String, String> glassIdFlowCardIdMap = new HashMap<>();
@@ -276,32 +295,25 @@
            String glassId = str(row.get("glassId"));
            String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal);
            String flowCardId = str(row.get("flowCardId"));
            // 如果流程卡ID为空,按新规则生成:NG + yyMMdd + 序号(两位,使用玻璃ID) + A001
            if (flowCardId.isEmpty()) {
                // 检查是否已为该玻璃ID生成过流程卡ID(同一玻璃ID的多个玻璃共享同一个流程卡ID)
                String generatedFlowCardId = glassIdFlowCardIdMap.get(glassId);
                if (generatedFlowCardId == null) {
                    // 使用玻璃ID作为序号(解析为整数,如果解析失败则使用1)
                    int sequence;
                    try {
                        sequence = Integer.parseInt(glassId.trim());
                        if (sequence <= 0) {
                            sequence = 1;
                        }
                    } catch (NumberFormatException e) {
                        log.warn("玻璃ID无法解析为整数,使用默认值1: glassId={}", glassId);
                        sequence = 1;
                    }
                    generatedFlowCardId = "NG" + dateStr + String.format("%02d", sequence) + "A001";
                    glassIdFlowCardIdMap.put(glassId, generatedFlowCardId);
                    log.info("为玻璃ID {} 生成流程卡ID: flowCardId={}", glassId, generatedFlowCardId);
                }
                flowCardId = generatedFlowCardId;
            // 流程卡ID:如果Excel中有,使用Excel的;如果为空,使用共享的流程卡ID
            String flowCardIdFromExcel = str(row.get("flowCardId"));
            String flowCardId;
            if (flowCardIdFromExcel != null && !flowCardIdFromExcel.trim().isEmpty()) {
                // Excel中有流程卡ID,使用Excel的
                flowCardId = flowCardIdFromExcel.trim();
            } else {
                // Excel中流程卡ID为空,使用共享的流程卡ID
                flowCardId = sharedFlowCardId != null ? sharedFlowCardId : getOrGenerateFlowCardId(glassId, dateStr, glassIdFlowCardIdMap);
            }
            // 去掉尾部 "/数字"(如果有)
            String baseFlowCardId = flowCardId.replaceFirst("/\\d+$", "");
            // 层号:如果Excel中有,使用Excel的;如果没有,默认1
            Object layerObj = row.get("layer");
            int layer = layerObj != null ? (int) parseDouble(layerObj, 1) : 1;
            if (layer <= 0) {
                layer = 1;
            }
            
            // orderNumber 是整型(玻璃类型),从 Excel 读取或使用默认值 1
            Object orderNumberObj = row.get("orderNumber");
@@ -351,7 +363,7 @@
                m.put("height", height);
                m.put("thickness", thickness);
                m.put("filmsId", filmsId);
                m.put("layer", 1);
                m.put("layer", layer);
                m.put("totalLayer", 1);
                m.put("edgWidth", width);
                m.put("edgHeight", height);
@@ -403,26 +415,15 @@
        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()) {
                // 使用已生成的流程卡ID(与glassInfolList中的逻辑保持一致)
                flowCardId = glassIdFlowCardIdMap.get(glassId);
                if (flowCardId == null) {
                    // 如果未生成,则按规则生成(理论上不应该走到这里,因为glassInfolList已经生成过)
                    int sequence;
                    try {
                        sequence = Integer.parseInt(glassId.trim());
                        if (sequence <= 0) {
                            sequence = 1;
                        }
                    } catch (NumberFormatException e) {
                        log.warn("玻璃ID无法解析为整数,使用默认值1: glassId={}", glassId);
                        sequence = 1;
                    }
                    flowCardId = "NG" + dateStr + String.format("%02d", sequence) + "A001";
                    glassIdFlowCardIdMap.put(glassId, flowCardId);
                    log.warn("流程卡ID未在glassInfolList中生成,此处补充生成: flowCardId={}, glassId={}", flowCardId, glassId);
                }
            // 流程卡ID:如果Excel中有,使用Excel的;如果为空,使用共享的流程卡ID(与glassInfolList逻辑一致)
            String flowCardIdFromExcel = str(row.get("flowCardId"));
            String flowCardId;
            if (flowCardIdFromExcel != null && !flowCardIdFromExcel.trim().isEmpty()) {
                // Excel中有流程卡ID,使用Excel的
                flowCardId = flowCardIdFromExcel.trim();
            } else {
                // Excel中流程卡ID为空,使用共享的流程卡ID
                flowCardId = sharedFlowCardId != null ? sharedFlowCardId : getOrGenerateFlowCardId(glassId, dateStr, glassIdFlowCardIdMap);
            }
            // 去掉尾部 "/数字"(如果有)
            flowCardId = flowCardId.replaceFirst("/\\d+$", "");
@@ -592,6 +593,40 @@
            return def;
        }
    }
    /**
     * 获取或生成流程卡ID
     * 如果已存在则返回,否则生成新的流程卡ID并缓存
     * 前端格式:原始glassId + 两位序号(如"101"、"102"、"201"),通过除以100去掉最后两位提取原始glassId
     *
     * @param glassId 玻璃ID(如"101"、"102"、"201")
     * @param dateStr 日期字符串(yyMMdd格式)
     * @param glassIdFlowCardIdMap 玻璃ID到流程卡ID的映射缓存
     * @return 流程卡ID(格式:NG + yyMMdd + 序号(两位) + A001)
     */
    private String getOrGenerateFlowCardId(String glassId, String dateStr, Map<String, String> glassIdFlowCardIdMap) {
        String flowCardId = glassIdFlowCardIdMap.get(glassId);
        if (flowCardId == null) {
            // 从glassId中提取原始数字:101 -> 1, 102 -> 1, 201 -> 2
            int sequence = 1;
            if (glassId != null && !glassId.trim().isEmpty()) {
                try {
                    String cleaned = glassId.trim().split("[\\r\\n\\t\\s]+")[0];
                    if (cleaned.matches("\\d+")) {
                        int num = Integer.parseInt(cleaned);
                        // 如果长度>=3,除以100去掉最后两位(前端追加的序号)
                        sequence = (cleaned.length() >= 3 && num >= 100) ? num / 100 : (num > 0 ? num : 1);
                    }
                } catch (Exception e) {
                    log.error("从glassId中提取原始数字失败: glassId={}", glassId, e);
                }
            }
            flowCardId = "NG" + dateStr + String.format("%02d", sequence) + "A001";
            glassIdFlowCardIdMap.put(glassId, flowCardId);
            log.info("为玻璃ID {} 生成流程卡ID: flowCardId={}", glassId, flowCardId);
        }
        return flowCardId;
    }
    /**
     * 保留两位小数(四舍五入)
@@ -622,6 +657,13 @@
            return;
        }
        // 如果工程号已存在,先删除该工程号下的旧数据,实现覆盖更新
        List<GlassInfo> existingGlassInfos = getGlassInfosByEngineeringId(engineeringId.trim());
        if (!existingGlassInfos.isEmpty()) {
            log.info("检测到工程号 {} 已存在 {} 条记录,将删除旧数据并更新", engineeringId, existingGlassInfos.size());
            deleteGlassInfosByEngineeringId(engineeringId.trim());
        }
        List<GlassInfo> glassInfos = new ArrayList<>();
        Date now = new Date();
@@ -641,7 +683,7 @@
            // 与导入规则保持一致:glassId 前加工程号前缀,数量>1时追加序号
            String baseGlassId = engineeringId.trim() + glassId;
            for (int idx = 0; idx < qty; idx++) {
                String finalGlassId = qty > 1 ? baseGlassId + "_" + (idx + 1) : baseGlassId;
                String finalGlassId = qty > 1 ? baseGlassId + (idx + 1) : baseGlassId;
                GlassInfo glassInfo = new GlassInfo();
                glassInfo.setGlassId(finalGlassId);