From 04914a9997afbbead6f8adbb9d9c40e05b2edbd1 Mon Sep 17 00:00:00 2001
From: huang <1532065656@qq.com>
Date: 星期三, 17 十二月 2025 17:04:34 +0800
Subject: [PATCH] 修复调用导入工程失败 重复保存;修复分批出片逻辑

---
 mes-processes/mes-plcSend/src/main/java/com/mes/interaction/largeglass/config/LargeGlassConfig.java                        |    6 
 mes-web/src/views/device/components/DeviceLogicConfig/LargeGlassConfig.vue                                                 |   21 +
 mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java |    5 
 mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java                                      |  576 +++++++++++++++++++----------------
 mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java                   |  145 ++++----
 mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java                              |   16 
 mes-processes/mes-plcSend/src/main/java/com/mes/device/service/EngineeringSequenceService.java                             |   18 +
 mes-processes/mes-plcSend/src/main/java/com/mes/device/controller/GlassInfoImportController.java                           |   93 +++--
 mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/EngineeringSequenceServiceImpl.java                    |   55 ++
 mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue                                                 |   18 
 10 files changed, 536 insertions(+), 417 deletions(-)

diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/device/controller/GlassInfoImportController.java b/mes-processes/mes-plcSend/src/main/java/com/mes/device/controller/GlassInfoImportController.java
index aac3b58..191d48c 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/device/controller/GlassInfoImportController.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/device/controller/GlassInfoImportController.java
@@ -42,6 +42,11 @@
      */
     @PostMapping("/importExcel")
     public ResponseEntity<?> importEngineer(@RequestBody Map<String, Object> body) {
+        // 鍒濆鍖栬繑鍥炵粨鏋滃拰鍏抽敭鏍囪
+        Map<String, Object> errorResponse = new HashMap<>();
+        boolean mesSuccess = false;
+        String engineeringId = null;
+        // 1. 鏍¢獙
         Object rowsObj = body.get("excelRows");
         if (!(rowsObj instanceof List)) {
             return ResponseEntity.badRequest().body("excelRows 蹇呴』鏄暟缁�");
@@ -52,71 +57,75 @@
             return ResponseEntity.badRequest().body("excelRows 涓嶈兘涓虹┖");
         }
 
-        Map<String, Object> payload = glassInfoService.buildEngineerImportPayload(excelRows);
-        log.info("鏋勫缓鐨� MES 瀵煎叆鏁版嵁: {}", payload);
+         try {
+            // 2. 鏋勫缓MES瀵煎叆鏁版嵁
+            Map<String, Object> payload = glassInfoService.buildEngineerImportPayload(excelRows);
+            log.info("鏋勫缓鐨� MES 瀵煎叆鏁版嵁: {}", payload);
 
-        // 浠巔ayload涓彁鍙栧伐绋嬪彿锛坧ayload涓娇鐢ㄧ殑鏄痚ngineerId锛�
-        String engineeringId = (String) payload.get("engineerId");
-        if (engineeringId == null || engineeringId.isEmpty()) {
-            // 濡傛灉payload涓病鏈塭ngineerId锛屽皾璇曚粠glassInfolList涓幏鍙�
-            @SuppressWarnings("unchecked")
-            List<Map<String, Object>> glassInfoList = (List<Map<String, Object>>) payload.get("glassInfolList");
-            if (glassInfoList != null && !glassInfoList.isEmpty()) {
-                Object firstEngineerId = glassInfoList.get(0).get("engineerId");
-                if (firstEngineerId != null) {
-                    engineeringId = firstEngineerId.toString();
+            // 3. 鎻愬彇宸ョ▼鍙�
+            engineeringId = (String) payload.get("engineerId");
+            if (engineeringId == null || engineeringId.isEmpty()) {
+                @SuppressWarnings("unchecked")
+                List<Map<String, Object>> glassInfoList = (List<Map<String, Object>>) payload.get("glassInfolList");
+                if (glassInfoList != null && !glassInfoList.isEmpty()) {
+                    Object firstEngineerId = glassInfoList.get(0).get("engineerId");
+                    if (firstEngineerId != null) {
+                        engineeringId = firstEngineerId.toString();
+                    }
                 }
             }
-        }
 
-        String mesEngineeringImportUrl = glassInfoService.getMesEngineeringImportUrl();
-
-        try {
+          // 4. 璋冪敤MES鎺ュ彛
+            String mesEngineeringImportUrl = glassInfoService.getMesEngineeringImportUrl();
             ResponseEntity<Map> mesResp = restTemplate.postForEntity(mesEngineeringImportUrl, payload, Map.class);
             Map<String, Object> mesBody = mesResp.getBody();
-            
-            // 妫�鏌ES鍝嶅簲鏄惁鐪熸鎴愬姛锛堜笉浠呮鏌TTP鐘舵�佺爜锛岃繕瑕佹鏌ュ搷搴斾綋涓殑code瀛楁锛�
-            boolean mesSuccess = false;
+
+            // 5. 妫�鏌ES鍝嶅簲鏄惁鐪熸鎴愬姛锛堜紭鍖栧悗鐨勫垽鏂�昏緫锛屽鍔犲紓甯告崟鑾凤級
             if (mesResp.getStatusCode().is2xxSuccessful() && mesBody != null) {
                 Object codeObj = mesBody.get("code");
                 if (codeObj != null) {
-                    int code = codeObj instanceof Number ? ((Number) codeObj).intValue() : 
-                              Integer.parseInt(String.valueOf(codeObj));
-                    // MES鎴愬姛閫氬父杩斿洖code=200鎴�0
-                    mesSuccess = (code == 200 || code == 0);
+                    try {
+                        // 瀹夊叏杞崲code涓烘暣鏁帮紝閬垮厤绫诲瀷杞崲寮傚父
+                        int code = codeObj instanceof Number ? ((Number) codeObj).intValue() :
+                                Integer.parseInt(String.valueOf(codeObj).trim());
+                        // MES鎴愬姛閫氬父杩斿洖code=200鎴�0
+                        mesSuccess = (code == 200 || code == 0);
+                    } catch (NumberFormatException e) {
+                        log.warn("MES鍝嶅簲code瀛楁涓嶆槸鏈夋晥鏁板瓧锛歿}", codeObj, e);
+                    }
                 } else {
-                    // 濡傛灉娌℃湁code瀛楁锛岃涓篐TTP 2xx灏辨槸鎴愬姛
+                    // 娌℃湁code瀛楁锛岃涓篐TTP 2xx灏辨槸鎴愬姛
                     mesSuccess = true;
                 }
-            }
-            
-            // 鍙湁MES瀵煎叆鐪熸鎴愬姛鏃讹紝鎵嶄繚瀛樼幓鐠冧俊鎭埌鏈湴鏁版嵁搴擄紝骞跺叧鑱攅ngineering_id
-            if (mesSuccess && engineeringId != null) {
-                try {
-                    glassInfoService.saveGlassInfosFromExcel(excelRows, engineeringId);
-                    log.info("MES瀵煎叆鎴愬姛锛屽凡淇濆瓨鐜荤拑淇℃伅鍒版湰鍦版暟鎹簱锛屽伐绋嬪彿: {}", engineeringId);
-                } catch (Exception e) {
-                    log.error("MES瀵煎叆鎴愬姛锛屼絾淇濆瓨鐜荤拑淇℃伅鍒版湰鍦版暟鎹簱澶辫触: engineeringId={}", engineeringId, e);
-                    // 鍗充娇淇濆瓨澶辫触锛屼篃杩斿洖MES鐨勬垚鍔熷搷搴旓紝浣嗚褰曢敊璇棩蹇�
-                }
             } else {
-                log.warn("MES瀵煎叆鏈垚鍔燂紝涓嶄繚瀛樼幓鐠冧俊鎭埌鏈湴鏁版嵁搴�: engineeringId={}, mesSuccess={}", engineeringId, mesSuccess);
+                // HTTP鐘舵�佺爜涓嶆槸2xx鎴栧搷搴斾綋涓虹┖锛岃涓哄け璐�
+                mesSuccess = false;
+                log.warn("MES鎺ュ彛杩斿洖闈�2xx鐘舵�佺爜鎴栫┖鍝嶅簲浣擄紝鐘舵�佺爜锛歿}", mesResp.getStatusCode());
             }
-            
-            // 鐩存帴杩斿洖 MES 鐨勫搷搴旓紝璁╁墠绔牴鎹搷搴斾綋涓殑 code 瀛楁鍒ゆ柇鏄惁鎴愬姛
+
+            // 6. 鍙湁MES瀵煎叆鐪熸鎴愬姛涓斿伐绋嬪彿涓嶄负绌烘椂锛屾墠淇濆瓨鍒版湰鍦版暟鎹簱
+            if (mesSuccess && engineeringId != null && !engineeringId.isEmpty()) {
+                // 鍏堜繚瀛樺伐绋嬪彿
+                engineeringSequenceService.saveEngineeringId(new Date(), engineeringId);
+                // 鍐嶄繚瀛樼幓鐠冧俊鎭�
+                glassInfoService.saveGlassInfosFromExcel(excelRows, engineeringId);
+                log.info("MES瀵煎叆鎴愬姛锛屽凡淇濆瓨宸ョ▼鍙峰拰鐜荤拑淇℃伅鍒版湰鍦版暟鎹簱锛屽伐绋嬪彿: {}", engineeringId);
+            } else {
+                log.warn("MES瀵煎叆鏈垚鍔燂紝涓嶄繚瀛樺伐绋嬪彿鍜岀幓鐠冧俊鎭埌鏈湴鏁版嵁搴�: engineeringId={}, mesSuccess={}", engineeringId, mesSuccess);
+            }
+
+            // 7. 杩斿洖MES鐨勫搷搴�
             return ResponseEntity.status(mesResp.getStatusCode()).body(mesBody);
         } catch (org.springframework.web.client.ResourceAccessException e) {
             // 杩炴帴瓒呮椂鎴栨棤娉曡繛鎺�
-            log.error("杞彂 MES 瀵煎叆鎺ュ彛澶辫触锛堣繛鎺ラ棶棰橈級 url={}, error={}", mesEngineeringImportUrl, e.getMessage(), e);
-            Map<String, Object> errorResponse = new java.util.HashMap<>();
+            log.error("杞彂 MES 瀵煎叆鎺ュ彛澶辫触锛堣繛鎺ラ棶棰橈級 url={}, error={}", glassInfoService.getMesEngineeringImportUrl(), e.getMessage(), e);
             errorResponse.put("code", 500);
             errorResponse.put("message", "鏃犳硶杩炴帴鍒� MES 鎺ュ彛锛岃妫�鏌ョ綉缁滆繛鎺ユ垨鑱旂郴绠$悊鍛�");
             errorResponse.put("data", false);
             return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
         } catch (Exception e) {
             // 鍏朵粬寮傚父
-            log.error("杞彂 MES 瀵煎叆鎺ュ彛澶辫触 url={}, error={}", mesEngineeringImportUrl, e.getMessage(), e);
-            Map<String, Object> errorResponse = new java.util.HashMap<>();
+            log.error("杞彂 MES 瀵煎叆鎺ュ彛澶辫触 url={}, error={}", glassInfoService.getMesEngineeringImportUrl(), e.getMessage(), e);
             errorResponse.put("code", 500);
             errorResponse.put("message", "杞彂 MES 澶辫触: " + e.getMessage());
             errorResponse.put("data", false);
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/EngineeringSequenceService.java b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/EngineeringSequenceService.java
index 6ebaa44..368cff8 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/EngineeringSequenceService.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/EngineeringSequenceService.java
@@ -21,5 +21,23 @@
      * @return 鐢熸垚鐨勫伐绋嬪彿锛堟牸寮忥細P + yyMMdd + 涓や綅搴忓彿锛�
      */
     String generateAndSaveEngineeringId(Date date);
+    
+    /**
+     * 鐢熸垚宸ョ▼鍙蜂絾涓嶄繚瀛�
+     * 鏍规嵁鏃ユ湡鑾峰彇鏈�澶у簭鍙凤紝鐒跺悗鑷1鐢熸垚鏂扮殑宸ョ▼鍙凤紝浣嗕笉淇濆瓨鍒版暟鎹簱
+     * 
+     * @param date 鏃ユ湡
+     * @return 鐢熸垚鐨勫伐绋嬪彿锛堟牸寮忥細P + yyMMdd + 涓や綅搴忓彿锛�
+     */
+    String generateEngineeringId(Date date);
+    
+    /**
+     * 淇濆瓨宸ョ▼鍙�
+     * 
+     * @param date 鏃ユ湡
+     * @param engineeringId 宸ョ▼鍙�
+     * @return 淇濆瓨鏄惁鎴愬姛
+     */
+    boolean saveEngineeringId(Date date, String engineeringId);
 }
 
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/EngineeringSequenceServiceImpl.java b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/EngineeringSequenceServiceImpl.java
index 0a37fb0..f5eaab5 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/EngineeringSequenceServiceImpl.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/EngineeringSequenceServiceImpl.java
@@ -34,36 +34,61 @@
     private static final int RETRY_INTERVAL_MAX = 200;
 
     @Override
-    @Transactional(rollbackFor = Exception.class)
-    public String generateAndSaveEngineeringId(Date date) {
-        try {
-            Integer maxSequence = baseMapper.selectMaxSequenceByDate(date);
-            maxSequence = (maxSequence == null) ? 0 : maxSequence;
-            int newSequence = maxSequence + 1;
+    public String generateEngineeringId(Date date) {
+        Integer maxSequence = baseMapper.selectMaxSequenceByDate(date);
+        maxSequence = (maxSequence == null) ? 0 : maxSequence;
+        int newSequence = maxSequence + 1;
 
+        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+        String dateStr = DATE_FORMATTER_THREAD_LOCAL.get().format(localDate);
+        String engineeringId = "P" + dateStr + String.format("%02d", newSequence);
+
+        log.info("鐢熸垚宸ョ▼鍙凤紙鏈繚瀛橈級: engineeringId={}, date={}, sequence={}", engineeringId, date, newSequence);
+        return engineeringId;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean saveEngineeringId(Date date, String engineeringId) {
+        try {
+            // 瑙f瀽宸ョ▼鍙疯幏鍙栧簭鍙�
             LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
             String dateStr = DATE_FORMATTER_THREAD_LOCAL.get().format(localDate);
-            String engineeringId = "P" + dateStr + String.format("%02d", newSequence);
+            String sequenceStr = engineeringId.substring(engineeringId.length() - 2);
+            int sequence = Integer.parseInt(sequenceStr);
 
             EngineeringSequence engineeringSequence = new EngineeringSequence();
             engineeringSequence.setEngineeringId(engineeringId);
             engineeringSequence.setDate(date);
-            engineeringSequence.setSequence(newSequence);
+            engineeringSequence.setSequence(sequence);
             engineeringSequence.setCreatedTime(new Date());
             engineeringSequence.setUpdatedTime(new Date());
             engineeringSequence.setCreatedBy("system");
             engineeringSequence.setUpdatedBy("system");
 
-            save(engineeringSequence);
+            boolean result = save(engineeringSequence);
 
-            log.info("鐢熸垚宸ョ▼鍙锋垚鍔�: engineeringId={}, date={}, sequence={}", engineeringId, date, newSequence);
-            return engineeringId;
+            if (result) {
+                log.info("淇濆瓨宸ョ▼鍙锋垚鍔�: engineeringId={}, date={}, sequence={}", engineeringId, date, sequence);
+            } else {
+                log.error("淇濆瓨宸ョ▼鍙峰け璐�: engineeringId={}, date={}, sequence={}", engineeringId, date, sequence);
+            }
+
+            return result;
         } catch (DuplicateKeyException dup) {
-            log.error("鐢熸垚宸ョ▼鍙峰敮涓�閿啿绐�: date={}", date, dup);
-            throw new RuntimeException("鐢熸垚宸ョ▼鍙峰け璐�", dup);
+            log.error("淇濆瓨宸ョ▼鍙峰敮涓�閿啿绐�: date={}, engineeringId={}", date, engineeringId, dup);
+            throw new RuntimeException("淇濆瓨宸ョ▼鍙峰け璐�", dup);
         } catch (Exception e) {
-            log.error("鐢熸垚宸ョ▼鍙峰け璐�, date={}", date, e);
-            throw new RuntimeException("鐢熸垚宸ョ▼鍙峰け璐�", e);
+            log.error("淇濆瓨宸ョ▼鍙峰け璐�, date={}, engineeringId={}", date, engineeringId, e);
+            throw new RuntimeException("淇濆瓨宸ョ▼鍙峰け璐�", e);
         }
     }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String generateAndSaveEngineeringId(Date date) {
+        String engineeringId = generateEngineeringId(date);
+        saveEngineeringId(date, engineeringId);
+        return engineeringId;
+    }
 }
\ No newline at end of file
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 e0c1ea0..34d9d87 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
@@ -232,8 +232,8 @@
             return result;
         }
 
-        // 宸ョ▼鍙风敓鎴愶細姣忔瀵煎叆閮界敓鎴愭柊鐨勫伐绋嬪彿锛堜娇鐢ㄦ暟鎹簱鑷搴忓彿锛岄伩鍏嶉噸澶嶏級
-        final String engineerId = engineeringSequenceService.generateAndSaveEngineeringId(new Date());
+        // 宸ョ▼鍙风敓鎴愶細姣忔瀵煎叆閮界敓鎴愭柊鐨勫伐绋嬪彿锛堝厛鍙敓鎴愶紝涓嶄繚瀛樺埌鏁版嵁搴擄紝绛夊埌MES璋冪敤鎴愬姛鍚庡啀淇濆瓨锛�
+        final String engineerId = engineeringSequenceService.generateEngineeringId(new Date());
         final String filmsIdDefault = firstValue(excelRows, "filmsId", "鐧界幓");
         final double thicknessDefault = parseDouble(firstValue(excelRows, "thickness"), 0d);
 
@@ -254,7 +254,7 @@
         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 height = parseDouble(row.get("length"), 0d);
             double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal);
             String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal);
             String key = width + "_" + height + "_" + thickness + "_" + filmsId;
@@ -279,7 +279,7 @@
                     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 height = parseDouble(row.get("length"), 0d);
                     double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal);
                     
                     // 璁$畻 rawSequence
@@ -352,7 +352,7 @@
         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 height = parseDouble(row.get("length"), 0d);
             double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal);
             String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal);
             String key = width + "_" + height + "_" + thickness + "_" + filmsId;
@@ -389,7 +389,7 @@
             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 height = parseDouble(row.get("length"), 0d);
             double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal);
             String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal);
             String productName = str(row.get("productName"));
@@ -590,7 +590,7 @@
             if (qty <= 0) qty = 1;
 
             double width = parseDouble(row.get("width"), 0d);
-            double height = parseDouble(row.get("height"), 0d);
+            double length = parseDouble(row.get("length"), 0d);
             double thickness = parseDouble(row.get("thickness"), 0d);
 
             // 涓庡鍏ヨ鍒欎繚鎸佷竴鑷达細glassId 鍓嶅姞宸ョ▼鍙峰墠缂�锛屾暟閲�>1鏃惰拷鍔犲簭鍙�
@@ -601,7 +601,7 @@
                 GlassInfo glassInfo = new GlassInfo();
                 glassInfo.setGlassId(finalGlassId);
                 glassInfo.setEngineeringId(engineeringId.trim());
-                glassInfo.setGlassLength((int) Math.round(height));
+                glassInfo.setGlassLength((int) Math.round(length));
                 glassInfo.setGlassWidth((int) Math.round(width));
                 glassInfo.setGlassThickness(BigDecimal.valueOf(thickness));
                 glassInfo.setStatus(GlassInfo.Status.ACTIVE);
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/largeglass/config/LargeGlassConfig.java b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/largeglass/config/LargeGlassConfig.java
index 883349e..371c34f 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/largeglass/config/LargeGlassConfig.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/largeglass/config/LargeGlassConfig.java
@@ -33,5 +33,11 @@
      * 姣忔牸鍘氬害锛坢m锛�
      */
     private Integer gridThickness = 5;
+
+    /**
+     * 澶勭悊鏃堕棿锛堢锛�
+     * 澶х悊鐗囩澶勭悊鐜荤拑鐨勬椂闂达紝榛樿30绉�
+     */
+    private Integer processTimeSeconds = 30;
 }
 
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java
index 5ae4704..63b1ea4 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java
@@ -1331,10 +1331,22 @@
             MesTaskInfo existingTask = currentTasks.get(deviceId);
             if (existingTask != null) {
                 log.debug("璁惧宸叉湁浠诲姟鍦ㄦ墽琛屼腑锛岃烦杩囨鏌ES浠诲姟: deviceId={}", deviceId);
+                // 浠嶇劧杩斿洖褰撳墠浠诲姟鐨勭幓鐠冨垪琛紝渚涗换鍔″紩鎿庤褰�/瀵硅处鏈壒娆�
+                List<String> batchIds = new ArrayList<>();
+                if (existingTask.glasses != null) {
+                    for (GlassTaskInfo g : existingTask.glasses) {
+                        if (g != null && g.glassId != null && !g.glassId.isEmpty()) {
+                            batchIds.add(g.glassId);
+                        }
+                    }
+                }
                 return DevicePlcVO.OperationResult.builder()
                         .success(true)
                         .message("浠诲姟鎵ц涓紝鏃犻渶閲嶅妫�鏌ES浠诲姟")
-                        .data(Collections.singletonMap("waiting", false))
+                        .data(new HashMap<String, Object>() {{
+                            put("waiting", false);
+                            put("batchGlassIds", batchIds);
+                        }})
                         .build();
             }
             
@@ -1357,6 +1369,7 @@
                 waitData.put("completed", false);
                 waitData.put("waiting", true);
                 waitData.put("waitingReason", "mesSend=0");
+                waitData.put("batchGlassIds", new ArrayList<>());
                 return DevicePlcVO.OperationResult.builder()
                         .success(true)
                         .message("绛夊緟MES鍙戦�佽姹傦紙mesSend=0锛�")
@@ -1500,6 +1513,39 @@
             }
             
             currentTasks.put(deviceId, taskInfo);
+
+            // 濡傛灉鏈夊璁惧浠诲姟涓婁笅鏂囷紝鍒欒褰曟湰娆ES涓嬪彂鐨勭幓鐠僆D鍒楄〃鍒颁笂涓嬫枃锛屼緵鍒嗘壒鏍¢獙浣跨敤
+            if (params != null) {
+                Object ctxObj = params.get("_taskContext");
+                if (ctxObj instanceof com.mes.task.model.TaskExecutionContext) {
+                    com.mes.task.model.TaskExecutionContext ctx = (com.mes.task.model.TaskExecutionContext) ctxObj;
+                    List<String> batchIds = new ArrayList<>();
+                    for (GlassTaskInfo g : glasses) {
+                        if (g != null && g.glassId != null && !g.glassId.isEmpty()) {
+                            batchIds.add(g.glassId);
+                        }
+                    }
+                    // 1. 璁板綍褰撳墠鎵规鐨勭幓鐠僆D
+                    ctx.getSharedData().put("currentMesBatchGlassIds", batchIds);
+                    log.info("璁板綍鏈MES鎵规鐜荤拑鍒楄〃: deviceId={}, batchIds={}", deviceId, batchIds);
+                    
+                    // 2. 鍒濆鍖栨�诲緟鍑虹墖鐜荤拑鍒楄〃锛堜粎绗竴娆″垵濮嬪寲锛屼粠浠诲姟鍙傛暟鑾峰彇锛�
+                    if (!ctx.getSharedData().containsKey("initialGlassIds")) {
+                        // 浠庝换鍔″弬鏁颁腑鑾峰彇鎬诲緟鍑虹墖鐜荤拑ID锛堟牳蹇冿細鎬诲垪琛ㄦ潵鑷换鍔″弬鏁帮紝鑰岄潪MES鎵规锛�
+                        List<String> taskGlassIds = ctx.getParameters().getGlassIds();
+                        if (taskGlassIds != null && !taskGlassIds.isEmpty()) {
+                            ctx.getSharedData().put("initialGlassIds", new ArrayList<>(taskGlassIds));
+                            // 鍒濆鍖栧凡鍑虹墖鍒楄〃涓虹┖
+                            if (!ctx.getSharedData().containsKey("outboundGlassIds")) {
+                                ctx.getSharedData().put("outboundGlassIds", new ArrayList<>());
+                            }
+                            log.info("鍒濆鍖栨�诲緟鍑虹墖鐜荤拑鍒楄〃: deviceId={}, taskGlassIds={}", deviceId, taskGlassIds);
+                        } else {
+                            log.warn("浠诲姟鍙傛暟涓湭鎵惧埌鎬诲緟鍑虹墖鐜荤拑ID鍒楄〃: deviceId={}", deviceId);
+                        }
+                    }
+                }
+            }
             
             // 娓呯┖plcRequest锛堣〃绀哄凡鎺ユ敹浠诲姟锛�
             Map<String, Object> payload = new HashMap<>();
@@ -1537,6 +1583,14 @@
             Map<String, Object> successData = new HashMap<>();
             successData.put("waiting", false);
             successData.put("taskStarted", true);
+            // 灏嗘湰娆ES涓嬪彂鐨勭幓鐠僆D鍒楄〃閫氳繃杩斿洖鍊煎甫鍥烇紙浠诲姟寮曟搸涓嶅啀渚濊禆_taskContext鍐欏叆锛�
+            List<String> batchIdsForReturn = new ArrayList<>();
+            for (GlassTaskInfo g : glasses) {
+                if (g != null && g.glassId != null && !g.glassId.isEmpty()) {
+                    batchIdsForReturn.add(g.glassId);
+                }
+            }
+            successData.put("batchGlassIds", batchIdsForReturn);
             
             return DevicePlcVO.OperationResult.builder()
                     .success(true)
@@ -2063,8 +2117,11 @@
         if (taskInfo == null) {
             log.info("妫�鏌ES纭鏃舵湭鎵惧埌浠诲姟璁板綍锛屽皾璇曡ˉ鍋挎鏌ES浠诲姟: deviceId={}", deviceId);
             try {
+                // 鍏抽敭锛氳ˉ鍋挎鏌ユ椂涔熻閫忎紶params锛堝寘鍚玙taskContext锛夛紝
+                // 鍚﹀垯handleCheckMesTask鏃犳硶鎶婃湰鎵规鐜荤拑ID鍐欏叆currentMesBatchGlassIds锛屼换鍔″紩鎿庢棤娉曠疮鍔犲畬鎴愯繘搴�
+                Map<String, Object> checkParams = params != null ? params : Collections.emptyMap();
                 DevicePlcVO.OperationResult checkResult =
-                        handleCheckMesTask(deviceConfig, Collections.emptyMap(), logicParams);
+                        handleCheckMesTask(deviceConfig, checkParams, logicParams);
                 if (Boolean.TRUE.equals(checkResult.getSuccess())) {
                     taskInfo = currentTasks.get(deviceId);
                     if (taskInfo != null) {
@@ -2150,84 +2207,14 @@
             data.put("completed", completed);
 
             if (completed) {
-                // MES宸茬‘璁わ紝妫�鏌ユ槸鍚﹁繕鏈夋湭鍑虹墖鐨勭幓鐠冿紙浠呭鍑虹墖浠诲姟锛�
-                boolean hasMoreGlass = false;
-                int completedCount = 0;
-                int totalCount = 0;
-                
-                if (taskInfo.isOutbound && params != null) {
-                    // 浠嶵askExecutionContext涓幏鍙栧凡鍑虹墖鐨勭幓鐠僆D鍒楄〃鍜屽垵濮嬬幓鐠僆D鍒楄〃
-                    Object contextObj = params.get("_taskContext");
-                    if (contextObj instanceof com.mes.task.model.TaskExecutionContext) {
-                        com.mes.task.model.TaskExecutionContext context = 
-                                (com.mes.task.model.TaskExecutionContext) contextObj;
-                        
-                        @SuppressWarnings("unchecked")
-                        List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
-                        @SuppressWarnings("unchecked")
-                        List<String> outboundGlassIds = (List<String>) context.getSharedData().get("outboundGlassIds");
-                        
-                        if (initialGlassIds != null && !initialGlassIds.isEmpty()) {
-                            totalCount = initialGlassIds.size();
-                            completedCount = (outboundGlassIds != null) ? outboundGlassIds.size() : 0;
-                            
-                            // 妫�鏌ユ槸鍚︽墍鏈夌幓鐠冮兘宸插嚭鐗�
-                            if (outboundGlassIds == null || !outboundGlassIds.containsAll(initialGlassIds)) {
-                                hasMoreGlass = true;
-                            }
-                        }
-                    }
-                }
-                
-                // 濡傛灉杩樻湁鏈嚭鐗囩殑鐜荤拑锛屼繚鎸乸lcRequest=1锛屾竻鐞嗘湰娆′换鍔$姸鎬侊紝绛夊緟涓嬫浜や簰
-                // 杩欐牱绗簩娆′氦浜掓椂锛宑heckMesTask鍙互妫�娴嬪埌mesSend=1锛屽垱寤烘柊浠诲姟锛屽畬鏁村湴璧颁竴閬嶉�昏緫
-                if (hasMoreGlass) {
-                    // 娓呯┖state鍜屾眹鎶ュ瓧锛堟湰娆′氦浜掑凡瀹屾垚锛�
-                    clearTaskStates(deviceConfig, serializer);
-                    
-                    // 娉ㄦ剰锛氫笉璁板綍lastCompletedMesRecords锛屽洜涓鸿繕鏈夋湭鍑虹墖鐨勭幓鐠冿紝浠诲姟鏈湡姝e畬鎴�
-                    // 杩欐牱绗簩娆′氦浜掓椂锛屽嵆浣縈ES鍙戦�佹柊浠诲姟锛堟柊鐨勭幓鐠僆D锛夛紝涔熶笉浼氳璇垽涓烘棫浠诲姟
-                    
-                    // 浠诲姟瀹屾垚锛屾仮澶嶄负绌洪棽鐘舵�侊紙鏈浜や簰宸插畬鎴愶級
-                    statusManager.updateVehicleStatus(
-                            deviceConfig.getDeviceId(), VehicleState.IDLE);
-                    statusManager.clearVehicleTask(deviceConfig.getDeviceId());
-                    
-                    // 绉婚櫎浠诲姟璁板綍锛堟湰娆′氦浜掑凡瀹屾垚锛岀瓑寰呬笅娆′氦浜掓椂鍒涘缓鏂颁换鍔★級
-                    currentTasks.remove(deviceConfig.getDeviceId());
-                    
-                    // 鍋滄浠诲姟鐩戞帶锛堟湰娆′氦浜掑凡瀹屾垚锛�
-                    handleStopTaskMonitor(deviceConfig);
-                    
-                    // 淇濇寔plcRequest=1锛堝彲浠ユ帴鏀朵笅娆′换鍔★級
-                    Map<String, Object> payload = new HashMap<>();
-                    payload.put("plcRequest", 1);
-                    plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
-                    
-                    log.info("鍑虹墖浠诲姟鏈浜や簰瀹屾垚锛岃繕鏈夋湭鍑虹墖鐨勭幓鐠冿紝绛夊緟涓嬫浜や簰: deviceId={}, completedCount={}, totalCount={}", 
-                            deviceConfig.getDeviceId(), completedCount, totalCount);
-                    
-                    String progressMessage = String.format("鐩墠瀹屾垚鍑虹墖鐜荤拑鏁伴噺%d/%d锛岀瓑寰呬笅娆′氦浜掍换鍔�", completedCount, totalCount);
-                    data.put("completed", false); // 鏍囪涓烘湭瀹屾垚锛屽洜涓鸿繕鏈夋湭鍑虹墖鐨勭幓鐠�
-                    data.put("waiting", true);
-                    data.put("waitingReason", "moreGlassToOutbound");
-                    data.put("completedCount", completedCount);
-                    data.put("totalCount", totalCount);
-                    
-                    return DevicePlcVO.OperationResult.builder()
-                            .success(true)
-                            .message(String.format("鍑虹墖浠诲姟鏈浜や簰瀹屾垚锛歁ES宸茬‘璁わ紙mesConfirm=1锛夛紝宸叉竻绌簊tate鍜屾眹鎶ュ瓧銆�%s銆傚ぇ杞︾┖闂诧紙plcRequest=1锛夛紝绛夊緟MES鍙戦�佷笅娆′换鍔�", progressMessage))
-                            .data(data)
-                            .build();
-                }
-                
-                // 鎵�鏈夌幓鐠冮兘宸插嚭鐗囷紝姝e父瀹屾垚娴佺▼
-                // MES宸茬‘璁わ紝娓呯┖state鍜屾眹鎶ュ瓧
+                // MES宸茬‘璁わ細鏈浜や簰瀹屾垚锛堜笉鍦ㄨ澶囦晶鍒ゆ柇鈥滄槸鍚﹁繕鏈夋洿澶氱幓鐠冣�濓紝鐢变换鍔″紩鎿庣粺涓�缂栨帓锛�
                 clearTaskStates(deviceConfig, serializer);
 
                 // 璁板綍宸插畬鎴愮殑浠诲姟绛惧悕锛岄伩鍏峂ES鏈浣嶆椂琚噸澶嶆媺璧�
-                lastCompletedMesRecords.put(deviceId,
-                        new CompletedMesRecord(taskInfo.mesSignature, System.currentTimeMillis()));
+                if (taskInfo != null && taskInfo.mesSignature != null) {
+                    lastCompletedMesRecords.put(deviceId,
+                            new CompletedMesRecord(taskInfo.mesSignature, System.currentTimeMillis()));
+                }
 
                 // 浠诲姟瀹屾垚锛屾仮澶嶄负绌洪棽鐘舵��
                 statusManager.updateVehicleStatus(
@@ -2246,10 +2233,10 @@
                 plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
 
                 log.info("MES浠诲姟宸茬‘璁ゅ畬鎴�: deviceId={}", deviceConfig.getDeviceId());
-                String taskType = taskInfo.isOutbound ? "鍑虹墖" : "杩涚墖";
+                String taskType = (taskInfo != null && taskInfo.isOutbound) ? "鍑虹墖" : "杩涚墖";
                 return DevicePlcVO.OperationResult.builder()
                         .success(true)
-                        .message(String.format("%s浠诲姟瀹屾垚锛歁ES宸茬‘璁わ紙mesConfirm=1锛夛紝宸叉竻绌簊tate鍜屾眹鎶ュ瓧锛屽ぇ杞︾┖闂诧紙plcRequest=1锛夛紝鍙互绛夊緟涓嬫浠诲姟", taskType))
+                        .message(String.format("%s浠诲姟浜や簰瀹屾垚锛歁ES宸茬‘璁わ紙mesConfirm=1锛夛紝宸叉竻绌簊tate鍜屾眹鎶ュ瓧锛屽ぇ杞︾┖闂诧紙plcRequest=1锛�", taskType))
                         .data(data)
                         .build();
             }
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java
index f676a3d..a374ca8 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java
@@ -144,12 +144,11 @@
         saveScannedGlassId(params, glassId);
 
         Integer intervalMs = config != null ? config.getScanIntervalMs() : null;
-        String msg = String.format("鐜荤拑[%s] 灏哄[瀹�:%s x 闀�:%s] 宸叉帴鏀讹紝workLine=%s锛屾壂鎻忛棿闅�=%s",
+        String msg = String.format("鐜荤拑[%s] 灏哄[瀹�:%s x 闀�:%s] 宸叉帴鏀讹紝workLine=%s",
                 glassId,
                 rawWidth != null ? rawWidth + "mm" : "-",
                 rawHeight != null ? rawHeight + "mm" : "-",
-                workLine != null ? workLine : "-",
-                intervalMs != null ? intervalMs + "ms" : "-");
+                workLine != null ? workLine : "-");
         Map<String, Object> resultData = new HashMap<>();
         resultData.put("glassIds", Collections.singletonList(glassId));
         if (workLine != null) {
diff --git a/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java b/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java
index 2362f2e..196e3d7 100644
--- a/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java
+++ b/mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java
@@ -247,17 +247,11 @@
                 // 4. 澶х悊鐗囩璁惧锛氬惎鍔ㄥ畾鏃跺櫒閫昏緫澶勭悊锛堜笉娑夊強PLC浜や簰锛屽彧璐熻矗閫昏緫澶勭悊锛�
                 if (isLargeGlass) {
                     TaskStepDetail step = createStepRecord(task, device, currentOrder);
-                    
-                    ScheduledFuture<?> largeGlassTask = startLargeGlassTimer(task, step, device, context);
-                    if (largeGlassTask != null) {
-                        registerScheduledTask(task.getTaskId(), largeGlassTask);
-                        stepSummaries.add(createStepSummary(device.getDeviceName(), true, "澶х悊鐗囩瀹氭椂鍣ㄥ凡鍚姩锛岄�昏緫澶勭悊涓�"));
-                    } else {
-                        stepSummaries.add(createStepSummary(device.getDeviceName(), false, "鍚姩瀹氭椂鍣ㄥけ璐�"));
-                        success = false;
-                        failureMessage = "澶х悊鐗囩璁惧鍚姩瀹氭椂鍣ㄥけ璐�";
-                        break;
-                    }
+                  
+                    // 绛夎繘鐗囧ぇ杞︽楠ょ湡姝e畬鎴愬悗鍐嶅惎鍔ㄥぇ鐞嗙墖绗煎畾鏃跺櫒锛屼繚璇佹墽琛岄『搴忎负锛氳繘鐗囧ぇ杞� -> 澶х悊鐗囩
+                    context.getSharedData().put("largeGlassStepId", step.getId());
+                    context.getSharedData().put("largeGlassDeviceId", device.getId());
+                    stepSummaries.add(createStepSummary(device.getDeviceName(), true, "宸插垱寤哄ぇ鐞嗙墖绗兼楠わ紝绛夊緟杩涚墖澶ц溅瀹屾垚鍚庡惎鍔ㄥ畾鏃跺櫒"));
                     currentOrder++;
                     continue;
                 }
@@ -723,14 +717,24 @@
                                     taskStepDetailMapper.updateById(step);
                                     notificationService.notifyStepUpdate(task.getTaskId(), step);
                                 }
+                                // 缁х画杞MES浠诲姟/纭鐘舵�侊紝鑻ES纭瀹屾垚浼氬湪鍐呴儴鏇存柊姝ラ涓篊OMPLETED
                                 pollMesForVehicle(task, step, device, context);
+                                // 濡傛灉杩涚墖澶ц溅姝ラ鍦ㄨ疆璇㈠悗宸插畬鎴愶紝鍒欏皾璇曞惎鍔ㄥぇ鐞嗙墖绗煎畾鏃跺櫒
+                                if (TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())) {
+                                    startLargeGlassTimerIfNeeded(task, context);
+                                }
                                 return;
                             }
                         }
                         
                         // 濡傛灉澶ц溅宸茬粡瑁呰浇杩囩幓鐠冿紙RUNNING鐘舵�侊級锛岃疆璇ES浠诲姟/纭鐘舵��
                         if (TaskStepDetail.Status.RUNNING.name().equals(step.getStatus())) {
+                            // 杞MES浠诲姟/纭鐘舵�侊紝鑻ES纭瀹屾垚浼氬湪鍐呴儴鏇存柊姝ラ涓篊OMPLETED
                             pollMesForVehicle(task, step, device, context);
+                            // 濡傛灉杩涚墖澶ц溅姝ラ鍦ㄨ疆璇㈠悗宸插畬鎴愶紝鍒欏皾璇曞惎鍔ㄥぇ鐞嗙墖绗煎畾鏃跺櫒
+                            if (TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())) {
+                                startLargeGlassTimerIfNeeded(task, context);
+                            }
                         } else {
                             // 濡傛灉杩樻病鏈夎杞借繃鐜荤拑锛岀瓑寰呭崸杞珛杈撳嚭
                             if (!TaskStepDetail.Status.PENDING.name().equals(step.getStatus())) {
@@ -894,6 +898,11 @@
                                         DeviceCoordinationService.DeviceStatus.FAILED, context);
                             }
                         }
+
+                        // 褰撹繘鐗囧ぇ杞︽楠ょ湡姝e畬鎴愬悗锛屽啀鍚姩澶х悊鐗囩瀹氭椂鍣紝淇濊瘉鎵ц椤哄簭
+                        if (TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())) {
+                            startLargeGlassTimerIfNeeded(task, context);
+                        }
                     }
                 } catch (Exception e) {
                     log.error("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屽紓甯�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
@@ -919,11 +928,10 @@
                                                          TaskExecutionContext context) {
         try {
             final long MONITOR_INTERVAL_MS = 2_000; // 2绉掔洃鎺т竴娆�
-            
+
             log.debug("鍚姩鍑虹墖澶ц溅璁惧瀹氭椂鍣�: taskId={}, deviceId={}, interval={}s",
                     task.getTaskId(), device.getId(), MONITOR_INTERVAL_MS / 1000);
-            
-            // 鍚姩瀹氭椂浠诲姟
+
             ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
                 try {
                     if (isTaskCancelled(context)) {
@@ -931,271 +939,242 @@
                                 task.getTaskId(), device.getId());
                         return;
                     }
-                    // 鍑虹墖澶ц溅璁惧锛氬彧鏈夊湪鐪熸寮�濮嬪鐞嗘椂鎵嶈缃负RUNNING
-                    // 妫�鏌ユ槸鍚︽湁宸插鐞嗙殑鐜荤拑淇℃伅锛堜粠澶х悊鐗囩鏉ョ殑锛�
-                    List<String> processedGlassIds = getProcessedGlassIds(context);
-                    boolean isRunning = TaskStepDetail.Status.RUNNING.name().equals(step.getStatus());
-                    boolean isCompleted = TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus());
-                    
-                    // 鑾峰彇宸插嚭鐗囩殑鐜荤拑ID鍒楄〃锛堝湪鏂规硶寮�濮嬪澹版槑锛岄伩鍏嶉噸澶嶅畾涔夛級
-                    List<String> outboundGlassIds = getOutboundGlassIds(context);
-                    
-                    // 濡傛灉姝ラ宸插畬鎴愶紝妫�鏌ユ槸鍚︽墍鏈夊垵濮嬬幓鐠冮兘宸插嚭鐗�
-                    if (isCompleted) {
-                        @SuppressWarnings("unchecked")
-                        List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
-                        
-                        // 濡傛灉杩樻湁鏈嚭鐗囩殑鐜荤拑锛岄噸缃楠ょ姸鎬佷负RUNNING锛岀户缁瓑寰�
-                        if (initialGlassIds != null && !initialGlassIds.isEmpty() 
-                                && (outboundGlassIds == null || !outboundGlassIds.containsAll(initialGlassIds))) {
-                            log.info("鍑虹墖澶ц溅姝ラ宸插畬鎴愶紝浣嗚繕鏈夋湭鍑虹墖鐨勭幓鐠冿紝閲嶇疆涓篟UNNING缁х画绛夊緟: taskId={}, deviceId={}, initialCount={}, outboundCount={}",
-                                    task.getTaskId(), device.getId(), 
-                                    initialGlassIds.size(), 
-                                    outboundGlassIds != null ? outboundGlassIds.size() : 0);
-                            step.setStatus(TaskStepDetail.Status.RUNNING.name());
-                            step.setEndTime(null); // 娓呴櫎缁撴潫鏃堕棿
-                            step.setSuccessMessage("绛夊緟鍓╀綑鐜荤拑鍑虹墖");
+
+                    final String lastMsgKey = "outboundVehicleLastMessage:" + device.getId();
+
+                    // 1) 鎬荤洰鏍囷細澶х悊鐗囩浜у嚭鐨勨�滃簲鍑虹墖鐜荤拑鍒楄〃鈥�
+                    List<String> processedGlassIdsRaw = getProcessedGlassIds(context);
+                    if (CollectionUtils.isEmpty(processedGlassIdsRaw)) {
+                        // 灏氭湭鏈夊ぇ鐞嗙墖绗艰緭鍑猴紝淇濇寔绛夊緟
+                        deviceCoordinationService.syncDeviceStatus(device,
+                                DeviceCoordinationService.DeviceStatus.WAITING, context);
+                        if (!TaskStepDetail.Status.PENDING.name().equals(step.getStatus())
+                                && !TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())) {
+                            step.setStatus(TaskStepDetail.Status.PENDING.name());
+                            step.setSuccessMessage("绛夊緟澶х悊鐗囩澶勭悊瀹屾垚");
+                            if (step.getStartTime() == null) {
+                                step.setStartTime(new Date());
+                            }
                             taskStepDetailMapper.updateById(step);
                             notificationService.notifyStepUpdate(task.getTaskId(), step);
-                            // 缁х画鎵ц鍚庣画閫昏緫锛屾鏌ユ槸鍚︽湁鏂扮殑宸插鐞嗙幓鐠�
-                        } else {
-                            // 鎵�鏈夌幓鐠冮兘宸插嚭鐗囷紝淇濇寔瀹屾垚鐘舵��
-                            log.debug("鍑虹墖澶ц溅鎵�鏈夌幓鐠冮兘宸插嚭鐗�: taskId={}, deviceId={}, initialCount={}, outboundCount={}",
-                                    task.getTaskId(), device.getId(), 
-                                    initialGlassIds != null ? initialGlassIds.size() : 0, 
-                                    outboundGlassIds != null ? outboundGlassIds.size() : 0);
-                            return;
-                        }
-                    }
-                    
-                    // 濡傛灉娌℃湁宸插鐞嗙幓鐠冿紝鍒欎笉搴斾富鍔ㄦ妸姝ラ鎷夊埌RUNNING锛屽彧淇濇寔宸茶繍琛岀姸鎬�
-                    if (CollectionUtils.isEmpty(processedGlassIds)) {
-                        if (isRunning || isCompleted) {
-                            // 宸茬粡鍦ㄨ繍琛岀殑鎯呭喌涓嬶紝缁х画杞MES浠诲姟/纭锛岄伩鍏嶉敊杩囩‘璁�
-                            DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
-                            if (handler != null) {
-                                Map<String, Object> logicParams = parseLogicParams(device);
-                                
-                                // 鍏堟鏌ES浠诲姟锛堝鏋渕esSend=1锛屼細鍒涘缓浠诲姟骞跺紑濮嬫墽琛岋級
-                                DevicePlcVO.OperationResult mesTaskResult = null;
-                                try {
-                                    mesTaskResult = handler.execute(device, "checkMesTask", Collections.emptyMap());
-                                    if (mesTaskResult != null) {
-                                        if (Boolean.TRUE.equals(mesTaskResult.getSuccess())) {
-                                            log.info("鍑虹墖澶ц溅璁惧宸叉鏌ES浠诲姟骞跺紑濮嬫墽琛�: taskId={}, deviceId={}, message={}",
-                                                    task.getTaskId(), device.getId(), mesTaskResult.getMessage());
-                                        } else {
-                                            log.debug("鍑虹墖澶ц溅璁惧妫�鏌ES浠诲姟锛岀瓑寰呬腑: taskId={}, deviceId={}, message={}",
-                                                    task.getTaskId(), device.getId(), mesTaskResult.getMessage());
-                                        }
-                                    }
-                                } catch (Exception e) {
-                                    log.warn("鍑虹墖澶ц溅璁惧妫�鏌ES浠诲姟寮傚父: taskId={}, deviceId={}, error={}",
-                                            task.getTaskId(), device.getId(), e.getMessage());
-                                }
-                                
-                                // 鐒跺悗妫�鏌ES纭鐘舵�侊紙鍙湁鍦ㄤ换鍔″凡寮�濮嬫墽琛屾椂鎵嶆鏌ワ級
-                                DevicePlcVO.OperationResult mesResult = null;
-                                try {
-                                    Map<String, Object> checkParams = new HashMap<>();
-                                    checkParams.put("_taskContext", context);
-                                    mesResult = handler.execute(device, "checkMesConfirm", checkParams);
-                                } catch (Exception e) {
-                                    log.warn("鍑虹墖澶ц溅璁惧妫�鏌ES纭鐘舵�佸紓甯�: taskId={}, deviceId={}, error={}",
-                                            task.getTaskId(), device.getId(), e.getMessage());
-                                }
-                                
-                                // 鏇存柊姝ラ鐘舵�侊紙澶ц溅璁惧淇濇寔RUNNING锛岀洿鍒癕ES纭瀹屾垚鎴栦换鍔″彇娑堬級
-                                if (mesResult != null) {
-                                    updateStepStatusForVehicle(task.getTaskId(), step, mesResult);
-                                    boolean opSuccess = Boolean.TRUE.equals(mesResult.getSuccess());
-                                    updateTaskProgress(task, step.getStepOrder(), opSuccess);
-                                    if (!opSuccess) {
-                                        deviceCoordinationService.syncDeviceStatus(device,
-                                                DeviceCoordinationService.DeviceStatus.FAILED, context);
-                                    }
-                                }
-                            }
-                        } else {
-                            // 鏈繍琛屼笖娌℃湁宸插鐞嗙幓鐠冿紝淇濇寔PENDING
-                            if (!TaskStepDetail.Status.PENDING.name().equals(step.getStatus())
-                                    && !TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())) {
-                                step.setStatus(TaskStepDetail.Status.PENDING.name());
-                                step.setSuccessMessage("绛夊緟澶х悊鐗囩澶勭悊瀹屾垚");
-                                taskStepDetailMapper.updateById(step);
-                                notificationService.notifyStepUpdate(task.getTaskId(), step);
-                            }
-                            log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣細鏆傛棤宸插鐞嗙殑鐜荤拑淇℃伅: taskId={}, deviceId={}",
-                                    task.getTaskId(), device.getId());
                         }
                         return;
                     }
-                    
-                    log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ娴嬪埌宸插鐞嗙殑鐜荤拑淇℃伅: taskId={}, deviceId={}, glassCount={}",
-                            task.getTaskId(), device.getId(), processedGlassIds.size());
 
-                    // 杩囨护鍑鸿繕鏈嚭鐗囩殑鐜荤拑锛堟敮鎸佸垎鎵瑰嚭鐗囷級
-                    // 閲嶆柊鑾峰彇宸插嚭鐗囩殑鐜荤拑ID鍒楄〃锛堝彲鑳藉湪涓婇潰鐨勯�昏緫涓凡鏇存柊锛�
-                    outboundGlassIds = getOutboundGlassIds(context);
-                    List<String> glassIdsToOutbound = new ArrayList<>();
-                    for (String glassId : processedGlassIds) {
-                        if (outboundGlassIds == null || !outboundGlassIds.contains(glassId)) {
-                            glassIdsToOutbound.add(glassId);
+                    // 2) 宸插畬鎴愮疮绉細outboundGlassIds锛堜换鍔′晶缁存姢锛屾寜mesConfirm=1绱姞锛�
+                    Set<String> processedSet = new LinkedHashSet<>();
+                    for (String id : processedGlassIdsRaw) {
+                        if (StringUtils.hasText(id)) {
+                            processedSet.add(id);
                         }
                     }
-                    
-                    // 濡傛灉娌℃湁闇�瑕佸嚭鐗囩殑鐜荤拑锛堥兘宸茬粡鍑虹墖杩囦簡锛夛紝缁х画绛夊緟鏂扮殑宸插鐞嗙幓鐠�
-                    if (glassIdsToOutbound.isEmpty()) {
-                        log.debug("鍑虹墖澶ц溅宸插鐞嗙殑鐜荤拑閮藉凡鍑虹墖锛岀瓑寰呮柊鐨勫凡澶勭悊鐜荤拑: taskId={}, deviceId={}",
-                                task.getTaskId(), device.getId());
+                    Set<String> outboundSet = new HashSet<>();
+                    for (String id : getOutboundGlassIds(context)) {
+                        if (StringUtils.hasText(id)) {
+                            outboundSet.add(id);
+                        }
+                    }
+
+                    List<String> remaining = new ArrayList<>();
+                    for (String id : processedSet) {
+                        if (!outboundSet.contains(id)) {
+                            remaining.add(id);
+                        }
+                    }
+                    int total = processedSet.size();
+                    int done = total - remaining.size();
+
+                    // 3) 鑻ュ凡鍏ㄩ儴瀹屾垚锛岀洿鎺ユ敹灏炬楠�
+                    if (total > 0 && remaining.isEmpty()) {
+                        if (!TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())) {
+                            step.setStatus(TaskStepDetail.Status.COMPLETED.name());
+                            String lastMsg = null;
+                            Object lastObj = context.getSharedData().get(lastMsgKey);
+                            if (lastObj != null && StringUtils.hasText(String.valueOf(lastObj))) {
+                                lastMsg = String.valueOf(lastObj);
+                            }
+                            step.setSuccessMessage(StringUtils.hasText(lastMsg)
+                                    ? String.format("鍑虹墖瀹屾垚锛�%d/%d锛�%s", done, total, lastMsg)
+                                    : String.format("鍑虹墖瀹屾垚锛�%d/%d", done, total));
+                            step.setErrorMessage(null);
+                            Date now = new Date();
+                            if (step.getStartTime() == null) {
+                                step.setStartTime(now);
+                            }
+                            if (step.getEndTime() == null) {
+                                step.setEndTime(now);
+                            }
+                            if (step.getStartTime() != null && step.getEndTime() != null) {
+                                step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
+                            }
+                            taskStepDetailMapper.updateById(step);
+                            notificationService.notifyStepUpdate(task.getTaskId(), step);
+                            checkAndCompleteTaskIfDone(step.getTaskId());
+                        }
+                        deviceCoordinationService.syncDeviceStatus(device,
+                                DeviceCoordinationService.DeviceStatus.COMPLETED, context);
                         return;
                     }
-                    
-                    log.debug("鍑虹墖澶ц溅鍑嗗鍑虹墖: taskId={}, deviceId={}, 寰呭嚭鐗囨暟閲�={}, 宸插嚭鐗囨暟閲�={}",
-                            task.getTaskId(), device.getId(), glassIdsToOutbound.size(), 
-                            outboundGlassIds != null ? outboundGlassIds.size() : 0);
-                    
-                    // 鎵ц鍑虹墖鎿嶄綔
-                    Map<String, Object> checkParams = new HashMap<>();
-                    checkParams.put("glassIds", glassIdsToOutbound);
-                    checkParams.put("_taskContext", context);
-                    
+
+                    // 4) 杩涘叆杩愯鎬侊紙鍙湪鐪熸寮�濮嬪嚭鐗囨椂锛�
+                    if (!TaskStepDetail.Status.RUNNING.name().equals(step.getStatus())) {
+                        step.setStatus(TaskStepDetail.Status.RUNNING.name());
+                        if (step.getStartTime() == null) {
+                            step.setStartTime(new Date());
+                        }
+                    }
+                    // 鏇存柊杩涘害淇℃伅锛堜究浜庡墠绔疄鏃跺睍绀猴級
+                    Date now = new Date();
+                    if (step.getStartTime() != null) {
+                        step.setDurationMs(now.getTime() - step.getStartTime().getTime());
+                    }
+                    taskStepDetailMapper.updateById(step);
+                    notificationService.notifyStepUpdate(task.getTaskId(), step);
+
                     DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
-                    if (handler != null) {
-                        // 灏唋ogicParams鍚堝苟鍒癱heckParams涓�
-                        Map<String, Object> logicParams = parseLogicParams(device);
-                        if (logicParams != null && !logicParams.isEmpty()) {
-                            checkParams.put("_logicParams", logicParams);
-                        }
-                        // 绗竴姝ワ細鍐欏叆澶ц溅鍑虹墖璇锋眰
-                        DevicePlcVO.OperationResult feedResult = handler.execute(device, "feedGlass", checkParams);
-                        
-                        if (Boolean.TRUE.equals(feedResult.getSuccess())) {
-                            // 鐪熸寮�濮嬪鐞嗭紝璁剧疆涓篟UNNING
-                            deviceCoordinationService.syncDeviceStatus(device,
-                                    DeviceCoordinationService.DeviceStatus.RUNNING, context);
-                            // 姝ラ鐘舵�佷篃璁剧疆涓篟UNNING
-                            if (!TaskStepDetail.Status.RUNNING.name().equals(step.getStatus())) {
-                                step.setStatus(TaskStepDetail.Status.RUNNING.name());
-                                if (step.getStartTime() == null) {
-                                    step.setStartTime(new Date());
+                    if (handler == null) {
+                        log.warn("鏈壘鍒板嚭鐗囧ぇ杞andler: deviceId={}, deviceType={}", device.getId(), device.getDeviceType());
+                        return;
+                    }
+
+                    Map<String, Object> logicParams = parseLogicParams(device);
+                    Map<String, Object> baseParams = new HashMap<>();
+                    baseParams.put("_taskContext", context);
+                    if (logicParams != null && !logicParams.isEmpty()) {
+                        baseParams.put("_logicParams", logicParams);
+                    }
+
+                    String latestInteractionMsg = null;
+
+                    // 5) 鍏堟鏌ES浠诲姟锛坢esSend=1鏃朵細鎶婃湰鎵规鐜荤拑ID鍐欏叆currentMesBatchGlassIds锛�
+                    DevicePlcVO.OperationResult mesTaskResult = null;
+                    try {
+                        mesTaskResult = handler.execute(device, "checkMesTask", new HashMap<>(baseParams));
+                    } catch (Exception e) {
+                        log.warn("鍑虹墖澶ц溅妫�鏌ES浠诲姟寮傚父: taskId={}, deviceId={}, error={}",
+                                task.getTaskId(), device.getId(), e.getMessage());
+                    }
+                    if (mesTaskResult != null && StringUtils.hasText(mesTaskResult.getMessage())) {
+                        latestInteractionMsg = mesTaskResult.getMessage();
+                    }
+
+                    // 浠巆heckMesTask杩斿洖鍊间腑璇诲彇鏈壒娆$幓鐠僆D锛堜笉渚濊禆璁惧渚у啓_taskContext锛�
+                    try {
+                        if (mesTaskResult != null && mesTaskResult.getData() != null) {
+                            Object batchObj = mesTaskResult.getData().get("batchGlassIds");
+                            if (batchObj instanceof List) {
+                                @SuppressWarnings("unchecked")
+                                List<Object> raw = (List<Object>) batchObj;
+                                List<String> batchIds = new ArrayList<>();
+                                for (Object o : raw) {
+                                    if (o != null && StringUtils.hasText(String.valueOf(o))) {
+                                        batchIds.add(String.valueOf(o));
+                                    }
                                 }
-                                taskStepDetailMapper.updateById(step);
-                                notificationService.notifyStepUpdate(task.getTaskId(), step);
-                            }
-                            log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屾垚鍔�: taskId={}, deviceId={}, glassCount={}",
-                                    task.getTaskId(), device.getId(), glassIdsToOutbound.size());
-                            // 璁板綍宸插嚭鐗囩殑鐜荤拑ID锛堝彧璁板綍鏈鍑虹墖鐨勭幓鐠冿級
-                            addOutboundGlassIds(context, glassIdsToOutbound);
-                            // 浠巔rocessedGlassIds涓Щ闄ゅ凡鍑虹墖鐨勭幓鐠冿紝淇濈暀鏈嚭鐗囩殑鐜荤拑
-                            processedGlassIds.removeAll(glassIdsToOutbound);
-                            // 濡傛灉杩樻湁鏈嚭鐗囩殑鐜荤拑锛屼笉娓呯┖processedGlassIds锛涘鏋滃叏閮ㄥ嚭鐗囦簡锛屾竻绌�
-                            if (processedGlassIds.isEmpty()) {
-                                clearProcessedGlassIds(context);
-                            } else {
-                                setProcessedGlassIds(context, processedGlassIds);
-                            }
-                            
-                            // feedGlass鎴愬姛鍚庯紝鍏堟鏌ES浠诲姟锛坈heckMesTask锛夋潵寮�濮嬫墽琛屼换鍔�
-                            DevicePlcVO.OperationResult mesTaskResult = null;
-                            try {
-                                mesTaskResult = handler.execute(device, "checkMesTask", Collections.emptyMap());
-                                if (mesTaskResult != null && Boolean.TRUE.equals(mesTaskResult.getSuccess())) {
-                                    log.info("鍑虹墖澶ц溅璁惧宸叉鏌ES浠诲姟骞跺紑濮嬫墽琛�: taskId={}, deviceId={}, message={}",
-                                            task.getTaskId(), device.getId(), mesTaskResult.getMessage());
+                                if (!batchIds.isEmpty()) {
+                                    context.getSharedData().put("currentMesBatchGlassIds", batchIds);
                                 }
-                            } catch (Exception e) {
-                                log.warn("鍑虹墖澶ц溅璁惧妫�鏌ES浠诲姟寮傚父: taskId={}, deviceId={}, error={}",
-                                        task.getTaskId(), device.getId(), e.getMessage());
                             }
-                        } else {
-                            // 娌℃湁鏁版嵁锛屼繚鎸乄AITING鐘舵�佸拰PENDING姝ラ鐘舵��
-                            deviceCoordinationService.syncDeviceStatus(device,
-                                    DeviceCoordinationService.DeviceStatus.WAITING, context);
-                            if (!TaskStepDetail.Status.PENDING.name().equals(step.getStatus())) {
-                                step.setStatus(TaskStepDetail.Status.PENDING.name());
-                                step.setSuccessMessage("绛夊緟涓�");
-                                taskStepDetailMapper.updateById(step);
-                                notificationService.notifyStepUpdate(task.getTaskId(), step);
-                            }
-                            log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屽け璐�: taskId={}, deviceId={}, message={}",
-                                    task.getTaskId(), device.getId(), feedResult.getMessage());
                         }
-                        
-                        // 绗簩姝ワ細妫�鏌ES纭鐘舵�侊紙濡傛灉澶ц溅澶勭悊鍣ㄦ敮鎸佺殑璇濓級
-                        // 鍙湁鍦ㄤ换鍔″凡寮�濮嬫墽琛岋紙鏈変换鍔¤褰曪級鏃舵墠妫�鏌ES纭
-                        DevicePlcVO.OperationResult mesResult = null;
+                    } catch (Exception ignore) {
+                        // 涓嶅奖鍝嶄富娴佺▼
+                    }
+
+                    boolean mesSendIsZero = false;
+                    if (mesTaskResult != null && mesTaskResult.getData() != null) {
+                        Object reason = mesTaskResult.getData().get("waitingReason");
+                        if ("mesSend=0".equals(String.valueOf(reason))) {
+                            mesSendIsZero = true;
+                        }
+                    } else if (mesTaskResult != null && StringUtils.hasText(mesTaskResult.getMessage())
+                            && mesTaskResult.getMessage().contains("mesSend=0")) {
+                        mesSendIsZero = true;
+                    }
+
+                    // 6) 鑻ES灏氭湭涓嬪彂浠诲姟锛坢esSend=0锛夛紝瑙﹀彂涓�娆″嚭鐗囪姹傦紙feedGlass锛�
+                    if (mesSendIsZero && !remaining.isEmpty()) {
+                        Map<String, Object> feedParams = new HashMap<>(baseParams);
+                        feedParams.put("glassIds", new ArrayList<>(remaining));
                         try {
-                            Map<String, Object> confirmParams = new HashMap<>();
-                            confirmParams.put("_taskContext", context);
-                            mesResult = handler.execute(device, "checkMesConfirm", confirmParams);
+                            DevicePlcVO.OperationResult feedResult = handler.execute(device, "feedGlass", feedParams);
+                            if (feedResult != null && StringUtils.hasText(feedResult.getMessage())) {
+                                latestInteractionMsg = feedResult.getMessage();
+                            }
+                            if (Boolean.TRUE.equals(feedResult.getSuccess())) {
+                                deviceCoordinationService.syncDeviceStatus(device,
+                                        DeviceCoordinationService.DeviceStatus.RUNNING, context);
+                            } else {
+                                deviceCoordinationService.syncDeviceStatus(device,
+                                        DeviceCoordinationService.DeviceStatus.WAITING, context);
+                            }
                         } catch (Exception e) {
-                            log.warn("鍑虹墖澶ц溅璁惧妫�鏌ES纭鐘舵�佸紓甯�: taskId={}, deviceId={}, error={}",
+                            log.warn("鍑虹墖澶ц溅瑙﹀彂feedGlass寮傚父: taskId={}, deviceId={}, error={}",
                                     task.getTaskId(), device.getId(), e.getMessage());
                         }
-                        
-                        // 瀵逛簬鍑虹墖澶ц溅锛岄渶瑕佹鏌ユ槸鍚︽墍鏈夊垵濮嬬幓鐠冮兘宸插嚭鐗�
-                        // 濡傛灉MES杩斿洖completed=true锛屼絾杩樻湁鏈嚭鐗囩殑鐜荤拑锛屽垯涓嶅簲鏍囪涓哄畬鎴�
-                        if (mesResult != null && mesResult.getData() != null) {
-                            Object completedFlag = mesResult.getData().get("completed");
-                            boolean mesCompleted = false;
-                            if (completedFlag instanceof Boolean) {
-                                mesCompleted = (Boolean) completedFlag;
-                            } else if (completedFlag != null) {
-                                mesCompleted = "true".equalsIgnoreCase(String.valueOf(completedFlag));
-                            }
-                            
-                            // 濡傛灉MES杩斿洖completed=true锛屾鏌ユ槸鍚︽墍鏈夊垵濮嬬幓鐠冮兘宸插嚭鐗�
-                            if (mesCompleted) {
-                                @SuppressWarnings("unchecked")
-                                List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
-                                // 閲嶆柊鑾峰彇宸插嚭鐗囩殑鐜荤拑ID鍒楄〃锛堝彲鑳藉湪涓婇潰鐨勯�昏緫涓凡鏇存柊锛�
-                                outboundGlassIds = getOutboundGlassIds(context);
-                                
-                                // 濡傛灉杩樻湁鏈嚭鐗囩殑鐜荤拑锛屼慨鏀筸esResult锛屽皢completed璁句负false
-                                if (initialGlassIds != null && !initialGlassIds.isEmpty() 
-                                        && (outboundGlassIds == null || !outboundGlassIds.containsAll(initialGlassIds))) {
-                                    log.debug("鍑虹墖澶ц溅MES杩斿洖completed=true锛屼絾杩樻湁鏈嚭鐗囩殑鐜荤拑: taskId={}, deviceId={}, initialCount={}, outboundCount={}",
-                                            task.getTaskId(), device.getId(), 
-                                            initialGlassIds.size(), 
-                                            outboundGlassIds != null ? outboundGlassIds.size() : 0);
-                                    // 淇敼mesResult锛屽皢completed璁句负false锛屼繚鎸丷UNNING鐘舵��
-                                    Map<String, Object> modifiedData = new HashMap<>(mesResult.getData());
-                                    modifiedData.put("completed", false);
-                                    DevicePlcVO.OperationResult modifiedResult = new DevicePlcVO.OperationResult();
-                                    modifiedResult.setSuccess(mesResult.getSuccess());
-                                    modifiedResult.setMessage(mesResult.getMessage());
-                                    modifiedResult.setData(modifiedData);
-                                    mesResult = modifiedResult;
+                    }
+
+                    // 7) 鍐嶆鏌ES纭锛坢esConfirm=1琛ㄧず鏈浜や簰瀹屾垚锛�
+                    DevicePlcVO.OperationResult mesConfirmResult = null;
+                    try {
+                        mesConfirmResult = handler.execute(device, "checkMesConfirm", new HashMap<>(baseParams));
+                    } catch (Exception e) {
+                        log.warn("鍑虹墖澶ц溅妫�鏌ES纭寮傚父: taskId={}, deviceId={}, error={}",
+                                task.getTaskId(), device.getId(), e.getMessage());
+                    }
+                    if (mesConfirmResult != null && StringUtils.hasText(mesConfirmResult.getMessage())) {
+                        // 纭鎻愮ず浼樺厛绾ф渶楂�
+                        latestInteractionMsg = mesConfirmResult.getMessage();
+                    }
+
+                    boolean interactionCompleted = false;
+                    if (mesConfirmResult != null && mesConfirmResult.getData() != null) {
+                        Object completedFlag = mesConfirmResult.getData().get("completed");
+                        if (completedFlag instanceof Boolean) {
+                            interactionCompleted = (Boolean) completedFlag;
+                        } else if (completedFlag != null) {
+                            interactionCompleted = "true".equalsIgnoreCase(String.valueOf(completedFlag));
+                        }
+                    }
+
+                    // 8) 鏇存柊鈥滄渶杩戜竴娆′氦浜掓彁绀衡�濅笌姝ラ鎻愮ず鏂囨锛堥伩鍏嶈绾繘搴﹁鐩栵級
+                    if (StringUtils.hasText(latestInteractionMsg)) {
+                        context.getSharedData().put(lastMsgKey, latestInteractionMsg);
+                    }
+                    String lastMsg = null;
+                    Object lastObj = context.getSharedData().get(lastMsgKey);
+                    if (lastObj != null && StringUtils.hasText(String.valueOf(lastObj))) {
+                        lastMsg = String.valueOf(lastObj);
+                    }
+                    step.setSuccessMessage(StringUtils.hasText(lastMsg)
+                            ? String.format("鍑虹墖杩涜涓細%d/%d锛�%s", done, total, lastMsg)
+                            : String.format("鍑虹墖杩涜涓細%d/%d", done, total));
+                    taskStepDetailMapper.updateById(step);
+                    notificationService.notifyStepUpdate(task.getTaskId(), step);
+
+                    if (interactionCompleted) {
+                        // 鏈浜や簰瀹屾垚锛氬皢鏈壒娆�(currentMesBatchGlassIds)绱姞鍒板凡鍑虹墖(outboundGlassIds)
+                        Object batchObj = context.getSharedData().get("currentMesBatchGlassIds");
+                        if (batchObj instanceof List) {
+                            @SuppressWarnings("unchecked")
+                            List<String> batchIds = new ArrayList<>((List<String>) batchObj);
+                            // 浠呯疮鍔犫�滅洰鏍囬泦鍚堚�濆唴鐨勭幓鐠冿紝閬垮厤鑴忔暟鎹�
+                            List<String> filtered = new ArrayList<>();
+                            for (String id : batchIds) {
+                                if (StringUtils.hasText(id) && processedSet.contains(id)) {
+                                    filtered.add(id);
                                 }
                             }
+                            addOutboundGlassIds(context, filtered);
                         }
-                        
-                        // 鏇存柊姝ラ鐘舵�侊紙澶ц溅璁惧淇濇寔RUNNING锛岀洿鍒癕ES纭瀹屾垚鎴栦换鍔″彇娑堬級
-                        if (mesResult != null) {
-                            updateStepStatusForVehicle(task.getTaskId(), step, mesResult);
-                            boolean opSuccess = Boolean.TRUE.equals(mesResult.getSuccess());
-                            updateTaskProgress(task, step.getStepOrder(), opSuccess);
-                            if (!opSuccess) {
-                                deviceCoordinationService.syncDeviceStatus(device,
-                                        DeviceCoordinationService.DeviceStatus.FAILED, context);
-                            }
-                        } else {
-                            updateStepStatusForVehicle(task.getTaskId(), step, feedResult);
-                            boolean opSuccess = Boolean.TRUE.equals(feedResult.getSuccess());
-                            updateTaskProgress(task, step.getStepOrder(), opSuccess);
-                            if (!opSuccess) {
-                                deviceCoordinationService.syncDeviceStatus(device,
-                                        DeviceCoordinationService.DeviceStatus.FAILED, context);
-                            }
-                        }
+                        // 娓呯┖鏈壒娆¤褰曪紝閬垮厤涓嬩竴娆¤疆璇㈤噸澶嶄娇鐢ㄦ棫鎵规
+                        context.getSharedData().put("currentMesBatchGlassIds", new ArrayList<>());
                     }
                 } catch (Exception e) {
                     log.error("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屽紓甯�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
                 }
             }, 0, MONITOR_INTERVAL_MS, TimeUnit.MILLISECONDS);
-            
-            // 鍦ㄤ覆琛屾墽琛屾ā寮忎笅锛岃澶囧惎鍔ㄥ畾鏃跺櫒鏃跺厛璁剧疆涓� WAITING锛屽畾鏃跺櫒绗竴娆℃墽琛屾椂鍐嶈缃负 RUNNING
+
+            // 鍚姩鏃朵繚鎸乄AITING锛屽悗缁敱瀹氭椂鍣ㄩ�昏緫鍒囨崲涓篟UNNING/COMPLETED
             deviceCoordinationService.syncDeviceStatus(device,
                     DeviceCoordinationService.DeviceStatus.WAITING, context);
             return future;
@@ -1347,6 +1326,8 @@
                     }
                     step.setOutputData(toJson(Collections.singletonMap("glassIds", loadedGlassIds)));
                     taskStepDetailMapper.updateById(step);
+                    // 閫氱煡鍓嶇鐘舵�佹洿鏂�
+                    notificationService.notifyStepUpdate(task.getTaskId(), step);
                     // 澶х悊鐗囩瀹屾垚鍚庡皾璇曡嚜鍔ㄦ敹灏炬暣涓换鍔�
                     checkAndCompleteTaskIfDone(step.getTaskId());
                     
@@ -1401,17 +1382,16 @@
     
     /**
      * 璁剧疆宸茶杞界殑鐜荤拑ID鍒楄〃
+     * 瀵逛簬鍒嗘壒鍑虹墖鍦烘櫙锛屾瘡娆¤缃簲鏇挎崲涓哄綋鍓嶆壒娆$殑鐜荤拑ID
      */
     private void setLoadedGlassIds(TaskExecutionContext context, List<String> glassIds) {
         if (context != null) {
-            // 绱姞璁板綍锛岄伩鍏嶅悗缁� containsAll 鍒ゆ柇鍥犺鐩栦涪澶卞巻鍙茬幓鐠冭�屽洖閫�涓虹瓑寰�
-            List<String> merged = new ArrayList<>(getLoadedGlassIds(context)); // 纭繚鍙彉
+            // 鏇挎崲涓哄綋鍓嶆壒娆$殑鐜荤拑ID
+            List<String> currentBatch = new ArrayList<>();
             if (glassIds != null) {
-                merged.addAll(glassIds);
+                currentBatch.addAll(glassIds);
             }
-            // 鍘婚噸
-            List<String> distinct = merged.stream().distinct().collect(java.util.stream.Collectors.toList());
-            context.getSharedData().put("loadedGlassIds", distinct);
+            context.getSharedData().put("loadedGlassIds", currentBatch);
         }
     }
     
@@ -1690,6 +1670,8 @@
             
             // 鎵�鏈夋楠ら兘宸插畬鎴愶紝鏀跺熬浠诲姟
             task.setStatus(MultiDeviceTask.Status.COMPLETED.name());
+            // 鍏抽敭锛氬悓姝ヨ繘搴﹀埌鏈�缁堝�硷紝閬垮厤鍓嶇浠嶆樉绀衡��3/5鈥濊繖绫绘棫杩涘害
+            task.setCurrentStep(totalSteps);
             task.setEndTime(new Date());
             multiDeviceTaskMapper.updateById(task);
             
@@ -1922,7 +1904,9 @@
             // 鍏堟鏌ES浠诲姟锛堝鏋渕esSend=1锛屼細鍒涘缓浠诲姟骞跺紑濮嬫墽琛岋級
             DevicePlcVO.OperationResult mesTaskResult = null;
             try {
-                mesTaskResult = handler.execute(device, "checkMesTask", Collections.emptyMap());
+                Map<String, Object> taskParams = new HashMap<>();
+                taskParams.put("_taskContext", context);
+                mesTaskResult = handler.execute(device, "checkMesTask", taskParams);
                 if (mesTaskResult != null && Boolean.TRUE.equals(mesTaskResult.getSuccess())) {
                     log.info("澶ц溅璁惧宸叉鏌ES浠诲姟骞跺紑濮嬫墽琛�: taskId={}, deviceId={}, message={}",
                             task.getTaskId(), device.getId(), mesTaskResult.getMessage());
@@ -2809,6 +2793,80 @@
     }
 
     /**
+     * 褰撹繘鐗囧ぇ杞︽楠ゅ畬鎴愬悗锛屽鏋滃瓨鍦ㄥぇ鐞嗙墖绗艰澶囦笖灏氭湭鍚姩鍏跺畾鏃跺櫒锛屽垯鍚姩澶х悊鐗囩瀹氭椂鍣�
+     * 淇濊瘉鎵ц椤哄簭涓猴細杩涚墖澶ц溅 -> 澶х悊鐗囩
+     */
+    private void startLargeGlassTimerIfNeeded(MultiDeviceTask task, TaskExecutionContext context) {
+        if (task == null || context == null) {
+            return;
+        }
+        // 闃叉閲嶅鍚姩
+        Object startedFlag = context.getSharedData().get("largeGlassTimerStarted");
+        if (startedFlag instanceof Boolean && (Boolean) startedFlag) {
+            return;
+        }
+
+        try {
+            // 浠庝笂涓嬫枃涓幏鍙栬澶囧垪琛�
+            @SuppressWarnings("unchecked")
+            List<DeviceConfig> devices = (List<DeviceConfig>) context.getSharedData().get("devices");
+            if (devices == null || devices.isEmpty()) {
+                return;
+            }
+
+            DeviceConfig largeGlassDevice = null;
+            for (DeviceConfig device : devices) {
+                if (DeviceConfig.DeviceType.LARGE_GLASS.equals(device.getDeviceType())) {
+                    largeGlassDevice = device;
+                    break;
+                }
+            }
+            if (largeGlassDevice == null) {
+                log.warn("鏈湪璁惧鍒楄〃涓壘鍒板ぇ鐞嗙墖绗艰澶�: taskId={}", task.getTaskId());
+                return;
+            }
+
+            // 閲嶆柊鍔犺浇澶х悊鐗囩姝ラ锛岀‘淇濇嬁鍒版渶鏂扮姸鎬侊紙鍙栬璁惧鏈�鏂扮殑涓�鏉℃楠よ褰曪級
+            List<TaskStepDetail> largeGlassSteps = taskStepDetailMapper.selectList(
+                    Wrappers.<TaskStepDetail>lambdaQuery()
+                            .eq(TaskStepDetail::getTaskId, task.getTaskId())
+                            .eq(TaskStepDetail::getDeviceId, largeGlassDevice.getId())
+                            .orderByDesc(TaskStepDetail::getStepOrder)
+                            .last("LIMIT 1")
+            );
+            TaskStepDetail largeGlassStep = (largeGlassSteps != null && !largeGlassSteps.isEmpty())
+                    ? largeGlassSteps.get(0)
+                    : null;
+            if (largeGlassStep == null) {
+                log.warn("鏈壘鍒板ぇ鐞嗙墖绗兼楠よ褰�: taskId={}, deviceId={}", task.getTaskId(), largeGlassDevice.getId());
+                return;
+            }
+
+            // 濡傛灉姝ラ宸茬粡瀹屾垚鎴栧け璐ワ紝鍒欎笉鍐嶅惎鍔ㄥ畾鏃跺櫒
+            String status = largeGlassStep.getStatus();
+            if (TaskStepDetail.Status.COMPLETED.name().equals(status)
+                    || TaskStepDetail.Status.FAILED.name().equals(status)) {
+                log.debug("澶х悊鐗囩姝ラ宸茬粨鏉燂紝涓嶅啀鍚姩瀹氭椂鍣�: taskId={}, stepId={}, status={}", task.getTaskId(), largeGlassStep.getId(), status);
+                context.getSharedData().put("largeGlassTimerStarted", true);
+                return;
+            }
+
+            ScheduledFuture<?> largeGlassTask = startLargeGlassTimer(task, largeGlassStep, largeGlassDevice, context);
+            if (largeGlassTask != null) {
+                registerScheduledTask(task.getTaskId(), largeGlassTask);
+                context.getSharedData().put("largeGlassTimerStarted", true);
+                log.info("宸插湪杩涚墖澶ц溅瀹屾垚鍚庡惎鍔ㄥぇ鐞嗙墖绗煎畾鏃跺櫒: taskId={}, largeGlassDeviceId={}, largeGlassStepId={}",
+                        task.getTaskId(), largeGlassDevice.getId(), largeGlassStep.getId());
+            } else {
+                log.warn("鍦ㄨ繘鐗囧ぇ杞﹀畬鎴愬悗鍚姩澶х悊鐗囩瀹氭椂鍣ㄥけ璐�: taskId={}, largeGlassDeviceId={}, largeGlassStepId={}",
+                        task.getTaskId(), largeGlassDevice.getId(), largeGlassStep.getId());
+            }
+        } catch (Exception e) {
+            log.warn("鍦ㄨ繘鐗囧ぇ杞﹀畬鎴愬悗鍚姩澶х悊鐗囩瀹氭椂鍣ㄥ紓甯�: taskId={}", task.getTaskId(), e);
+        }
+    }
+
+    /**
      * 妫�鏌ュ崸杞珛璁惧鏄惁宸插畬鎴�
      * 杩斿洖true琛ㄧず鍗ц浆绔嬪凡瀹屾垚锛圕OMPLETED锛夛紝鍙互鍒ゆ柇澶ц溅鏄惁瀹屾垚
      * 杩斿洖false琛ㄧず鍗ц浆绔嬭繕鍦ㄨ繍琛屼腑锛圧UNNING锛夋垨绛夊緟涓紙PENDING锛夛紝涓嶅簲璇ユ爣璁板ぇ杞︿负瀹屾垚
diff --git a/mes-web/src/views/device/components/DeviceLogicConfig/LargeGlassConfig.vue b/mes-web/src/views/device/components/DeviceLogicConfig/LargeGlassConfig.vue
index 7e76bb6..ce24c85 100644
--- a/mes-web/src/views/device/components/DeviceLogicConfig/LargeGlassConfig.vue
+++ b/mes-web/src/views/device/components/DeviceLogicConfig/LargeGlassConfig.vue
@@ -79,6 +79,21 @@
         </el-form-item>
       </el-col>
     </el-row>
+
+    <el-row :gutter="20">
+      <el-col :span="8">
+        <el-form-item label="澶勭悊鏃堕棿(绉�)">
+          <el-input-number
+            v-model="config.processTimeSeconds"
+            :min="1"
+            :max="3600"
+            :step="1"
+            style="width: 100%;"
+          />
+          <span class="form-tip">澶х悊鐗囩澶勭悊鐜荤拑鐨勬椂闂达紙绉掞級锛岄粯璁�30绉�</span>
+        </el-form-item>
+      </el-col>
+    </el-row>
   </div>
 </template>
 
@@ -102,7 +117,8 @@
   ],
   gridLength: 2000,
   gridWidth: 1500,
-  gridThickness: 5
+  gridThickness: 5,
+  processTimeSeconds: 30
 })
 
 // 鐩戝惉props鍙樺寲
@@ -122,7 +138,8 @@
       gridRanges: gridRanges,
       gridLength: newVal.gridLength ?? 2000,
       gridWidth: newVal.gridWidth ?? 1500,
-      gridThickness: newVal.gridThickness ?? 5
+      gridThickness: newVal.gridThickness ?? 5,
+      processTimeSeconds: newVal.processTimeSeconds ?? 30
     }
   }
 }, { immediate: true, deep: true })
diff --git a/mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue b/mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue
index 5f2b44e..7d4eb7c 100644
--- a/mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue
+++ b/mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue
@@ -531,10 +531,10 @@
       headerStr === 'w' || headerStr === '瀹藉害') {
       headerMap.width = index
     }
-    // 楂樺害
-    else if (headerStr.includes('楂�') || headerStr.includes('height') ||
-      headerStr === 'h' || headerStr === '楂樺害') {
-      headerMap.height = index
+    // 闀垮害
+    else if (headerStr.includes('闀�') || headerStr.includes('length') ||
+      headerStr === 'l' || headerStr === '闀垮害') {
+      headerMap.length = index
     }
     // 鍘氬害
     else if (headerStr.includes('鍘�') || headerStr.includes('thickness') ||
@@ -570,10 +570,10 @@
 
   // 濡傛灉娌℃湁鎵惧埌琛ㄥご锛屽皾璇曚娇鐢ㄧ涓�琛屼綔涓鸿〃澶达紙绱㈠紩鏂瑰紡锛�
   if (Object.keys(headerMap).length === 0 && jsonData.length > 1) {
-    // 榛樿鏍煎紡锛氱幓鐠僆D, 瀹�, 楂�, 鍘�, 鏁伴噺锛堟寜鍒楅『搴忥級
+    // 榛樿鏍煎紡锛氱幓鐠僆D, 瀹�, 闀�, 鍘�, 鏁伴噺锛堟寜鍒楅『搴忥級
     headerMap.glassId = 0
     headerMap.width = 1
-    headerMap.height = 2
+    headerMap.length = 2
     headerMap.thickness = 3
     headerMap.quantity = 4
   }
@@ -586,7 +586,7 @@
 
     const glassId = row[headerMap.glassId] ? String(row[headerMap.glassId]).trim() : ''
     const width = row[headerMap.width] ? String(row[headerMap.width]).trim() : ''
-    const height = row[headerMap.height] ? String(row[headerMap.height]).trim() : ''
+    const length = row[headerMap.length] ? String(row[headerMap.length]).trim() : ''
     const thickness = row[headerMap.thickness] ? String(row[headerMap.thickness]).trim() : ''
     const quantity = row[headerMap.quantity] ? String(row[headerMap.quantity]).trim() : ''
     const filmsId = row[headerMap.filmsId] ? String(row[headerMap.filmsId]).trim() : ''
@@ -595,7 +595,7 @@
     const customerName = row[headerMap.customerName] ? String(row[headerMap.customerName]).trim() : ''
 
     // 璺宠繃绌鸿
-    if (!glassId && !width && !height && !thickness && !quantity) {
+    if (!glassId && !width && !length && !thickness && !quantity) {
       continue
     }
 
@@ -621,7 +621,7 @@
       result.push({
         glassId: finalGlassId,
         width: parseNumber(width),
-        height: parseNumber(height),
+        length: parseNumber(length),
         thickness: parseNumber(thickness),
         quantity: '1', // 姣忔潯璁板綍鏁伴噺涓�1
         filmsId: filmsId,

--
Gitblit v1.8.0