From 73aa66976e35252378be3f09be2474193ccd0bf6 Mon Sep 17 00:00:00 2001
From: huang <1532065656@qq.com>
Date: 星期五, 05 十二月 2025 17:15:20 +0800
Subject: [PATCH] 修改任务执行步骤状态完成检验

---
 mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java |  741 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 647 insertions(+), 94 deletions(-)

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 62569ad..b77deae 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
@@ -62,9 +62,19 @@
     private S7SerializerProvider s7SerializerProvider;
 
     // MES瀛楁鍒楄〃锛堣繘鐗囧拰鍑虹墖鍏辩敤鍚屼竴濂楀崗璁級
+    // 鏍规嵁鍗忚锛屼娇鐢ㄥ甫鏁板瓧鍚庣紑鐨勫瓧娈靛悕锛�1-6瀵瑰簲6涓幓鐠冧綅缃級
+    // 鏀寔璇诲彇鎵�鏈�6涓幓鐠冪殑淇℃伅
     private static final List<String> MES_FIELDS = Arrays.asList(
-            "mesSend", "mesGlassId", "mesWidth", "mesHeight", 
-            "startSlot", "targetSlot", "workLine"
+            "mesSend", "mesConfirm",
+            // 鐜荤拑1-6鐨処D
+            "mesGlassId1", "mesGlassId2", "mesGlassId3", "mesGlassId4", "mesGlassId5", "mesGlassId6",
+            // 鐜荤拑1-6鐨勫昂瀵�
+            "mesWidth1", "mesWidth2", "mesWidth3", "mesWidth4", "mesWidth5", "mesWidth6",
+            "mesHeight1", "mesHeight2", "mesHeight3", "mesHeight4", "mesHeight5", "mesHeight6",
+            "mesThickness1", "mesThickness2", "mesThickness3", "mesThickness4", "mesThickness5", "mesThickness6",
+            // 鐜荤拑1-6鐨勮捣濮嬩綅缃拰鐩爣浣嶇疆
+            "start1", "start2", "start3", "start4", "start5", "start6",
+            "target1", "target2", "target3", "target4", "target5", "target6"
     );
 
     // 鐩戞帶绾跨▼姹狅細鐢ㄤ簬瀹氭湡妫�鏌ュぇ杞︾姸鎬佸苟鍗忚皟鍗ц浆绔嬭澶�
@@ -102,6 +112,10 @@
     
     // 璁板綍褰撳墠浠诲姟锛歞eviceId -> 浠诲姟淇℃伅
     private final Map<String, MesTaskInfo> currentTasks = new ConcurrentHashMap<>();
+    /**
+     * 璁板綍鏈�杩戜竴娆″凡瀹屾垚浣哅ES鏈浣嶇殑浠诲姟绛惧悕锛岄伩鍏嶉噸澶嶆媺璧�
+     */
+    private final Map<String, CompletedMesRecord> lastCompletedMesRecords = new ConcurrentHashMap<>();
 
     @Autowired
     public LoadVehicleLogicHandler(
@@ -131,14 +145,25 @@
         if (needsStateCheck(operation)) {
             VehicleStatus status = statusManager.getVehicleStatus(deviceId);
             if (status != null && !status.isAvailable()) {
-                return DevicePlcVO.OperationResult.builder()
-                    .success(false)
-                    .message(String.format("杞﹁締 %s (%s) 褰撳墠鐘舵�佷负 %s锛屾棤娉曟墽琛屾搷浣� %s", 
-                        deviceConfig.getDeviceName(), 
-                        deviceId,
-                        status.getState(),
-                        operation))
-                    .build();
+                // 瀵逛簬 feedGlass 鎿嶄綔锛屽鏋滅姸鎬佹槸 EXECUTING锛屽厑璁哥户缁墽琛�
+                // 鍥犱负瀹氭椂鍣ㄥ彲鑳戒細閲嶅璋冪敤锛屾垨鑰呴渶瑕佺瓑寰呬换鍔″畬鎴�
+                if ("feedGlass".equals(operation) && status.isExecuting()) {
+                    log.debug("杞﹁締 {} 褰撳墠鐘舵�佷负 EXECUTING锛屼絾鍏佽缁х画鎵ц feedGlass锛堝畾鏃跺櫒閲嶅璋冪敤锛�", deviceId);
+                    // 鍏佽缁х画鎵ц锛屼笉杩斿洖閿欒
+                } else if ("clearGlass".equals(operation) || "clearPlc".equals(operation) || "clear".equals(operation)) {
+                    // 娓呴櫎鎿嶄綔搴旇鍏佽鍦ㄤ换浣曠姸鎬佷笅鎵ц锛屽洜涓哄叾鐩殑灏辨槸閲嶇疆璁惧鐘舵��
+                    log.debug("杞﹁締 {} 褰撳墠鐘舵�佷负 {}锛屼絾鍏佽鎵ц娓呴櫎鎿嶄綔 {}", deviceId, status.getState(), operation);
+                    // 鍏佽缁х画鎵ц锛屼笉杩斿洖閿欒
+                } else {
+                    return DevicePlcVO.OperationResult.builder()
+                        .success(false)
+                        .message(String.format("杞﹁締 %s (%s) 褰撳墠鐘舵�佷负 %s锛屾棤娉曟墽琛屾搷浣� %s", 
+                            deviceConfig.getDeviceName(), 
+                            deviceId,
+                            status.getState(),
+                            operation))
+                        .build();
+                }
             }
         }
 
@@ -196,6 +221,12 @@
                     break;
                 case "setOnlineState":
                     result = handleSetOnlineState(deviceConfig, params, logicParams);
+                    break;
+                case "checkMesConfirm":
+                    result = checkMesConfirm(deviceConfig, logicParams);
+                    break;
+                case "markBroken":
+                    result = handleMarkBroken(deviceConfig, params, logicParams);
                     break;
                 default:
                     log.warn("涓嶆敮鎸佺殑鎿嶄綔绫诲瀷: {}", operation);
@@ -317,8 +348,7 @@
         // 浠庨�昏緫鍙傛暟涓幏鍙栭厤缃紙浠� extraParams.deviceLogic 璇诲彇锛�
         Integer vehicleCapacity = getLogicParam(logicParams, "vehicleCapacity", 6000);
         Integer glassGap = getLogicParam(logicParams, "glassGap", 200); // 鐜荤拑涔嬮棿鐨勭墿鐞嗛棿闅旓紙mm锛夛紝榛樿200mm
-        Boolean autoFeed = getLogicParam(logicParams, "autoFeed", true);
-        Integer maxRetryCount = getLogicParam(logicParams, "maxRetryCount", 5);
+        Boolean autoFeed = getLogicParam(logicParams, "autoFeed", true); // 鑷姩涓婃枡锛氭槸鍚﹁嚜鍔ㄨЕ鍙戜笂鏂欒姹傦紙鍐欏叆plcRequest=1锛�
 
         // 浠庤繍琛屾椂鍙傛暟涓幏鍙栨暟鎹紙浠庢帴鍙h皟鐢ㄦ椂浼犲叆锛�
         List<GlassInfo> glassInfos = extractGlassInfos(params);
@@ -475,6 +505,10 @@
         Map<String, Object> payload = new HashMap<>();
         payload.put("plcRequest", 0);
         payload.put("plcReport", 0);
+        // 娓呯┖state1~6锛岄伩鍏嶉仐鐣欑姸鎬佸鑷磋鍒�
+        for (int i = 1; i <= 6; i++) {
+            payload.put("state" + i, 0);
+        }
         payload.put("onlineState", Boolean.TRUE);
         
         log.info("澶ц溅璁惧閲嶇疆: deviceId={}", deviceConfig.getId());
@@ -490,7 +524,14 @@
             statusManager.clearVehicleTask(deviceConfig.getDeviceId());
             statusManager.updateVehicleStatus(deviceConfig.getDeviceId(), VehicleState.IDLE);
             stopStateMonitoring(deviceConfig.getDeviceId());
+            handleStopTaskMonitor(deviceConfig);
+            handleStopIdleMonitor(deviceConfig);
             updateDeviceOnlineStatus(deviceConfig, true);
+        } else {
+            // 鍗充究閲嶇疆澶辫触锛屼篃灏濊瘯鍋滄鍐呴儴鐩戞帶锛岄伩鍏嶄换鍔″彇娑堝悗浠嶇劧鍙嶅鍐橮LC
+            stopStateMonitoring(deviceConfig.getDeviceId());
+            handleStopTaskMonitor(deviceConfig);
+            handleStopIdleMonitor(deviceConfig);
         }
         
         return result;
@@ -572,7 +613,6 @@
             payload.put(field, "");
         }
 
-        payload.put("plcGlassCount", 0);
         payload.put("plcRequest", 0);
         payload.put("plcReport", 0);
         payload.put("onlineState", Boolean.TRUE);
@@ -590,13 +630,23 @@
                 payload,
                 "澶ц溅璁惧-娓呯┖鐜荤拑鏁版嵁"
         );
+
+        // 鍚屾娓呯┖state1~6绛夊姩鎬佸瓧娈碉紙鍦ㄥ姩鎬佹暟鎹尯涓級
+        clearDynamicTaskStates(deviceConfig);
         
         // 娓呯┖鍚庯紝鎭㈠涓虹┖闂茬姸鎬侊紝鍋滄鐩戞帶
         if (Boolean.TRUE.equals(result.getSuccess())) {
             statusManager.clearVehicleTask(deviceConfig.getDeviceId());
             statusManager.updateVehicleStatus(deviceConfig.getDeviceId(), VehicleState.IDLE);
             stopStateMonitoring(deviceConfig.getDeviceId());
+            handleStopTaskMonitor(deviceConfig);
+            handleStopIdleMonitor(deviceConfig);
             updateDeviceOnlineStatus(deviceConfig, true);
+        } else {
+            // 鍐欏叆澶辫触涔熷皾璇曞仠姝㈢洃鎺э紝閬垮厤浠诲姟鍙栨秷鍚庝粛鏃ц繍琛�
+            stopStateMonitoring(deviceConfig.getDeviceId());
+            handleStopTaskMonitor(deviceConfig);
+            handleStopIdleMonitor(deviceConfig);
         }
         
         return result;
@@ -663,9 +713,8 @@
         Map<String, Object> defaultParams = new HashMap<>();
         defaultParams.put("vehicleCapacity", 6000);
         defaultParams.put("glassGap", 200); // 鐜荤拑涔嬮棿鐨勭墿鐞嗛棿闅旓紙mm锛夛紝榛樿200mm
-        defaultParams.put("autoFeed", true);
+        defaultParams.put("autoFeed", true); // 鑷姩涓婃枡锛氭槸鍚﹁嚜鍔ㄨЕ鍙戜笂鏂欒姹傦紙鍐欏叆plcRequest=1锛夛紝榛樿true
         defaultParams.put("maxRetryCount", 5);
-        defaultParams.put("defaultGlassLength", 2000);
         
         // MES浠诲姟鐩稿叧閰嶇疆
         defaultParams.put("vehicleSpeed", 1.0); // 杞﹁締閫熷害锛堟牸/绉掞紝grid/s锛夛紝榛樿1鏍�/绉�
@@ -768,7 +817,7 @@
      * @param vehicleCapacity 杞﹁締瀹归噺锛坢m锛�
      * @param glassGap 鐜荤拑涔嬮棿鐨勭墿鐞嗛棿闅旓紙mm锛夛紝榛樿200mm
      * @param deviceId 璁惧ID锛堢敤浜庢棩蹇楋級
-     * @return 瑙勫垝鍚庣殑鐜荤拑鍒楄〃锛屽鏋滅幓鐠冩病鏈夐暱搴﹀垯杩斿洖null锛堢敤浜庢祴璇昅ES绋嬪簭锛�
+     * @return 瑙勫垝鍚庣殑鐜荤拑鍒楄〃锛屽鏋滅幓鐠冩病鏈夐暱搴﹀垯杩斿洖null锛圡ES鏈彁渚涢暱搴︽暟鎹級
      */
     private List<GlassInfo> planGlassLoading(List<GlassInfo> source,
                                              int vehicleCapacity,
@@ -782,8 +831,8 @@
         for (GlassInfo info : source) {
             Integer glassLength = info.getLength();
             
+            // 濡傛灉鐜荤拑娌℃湁闀垮害锛岃鏄嶮ES鏈彁渚涳紝鐩存帴鎶ラ敊
             if (glassLength == null || glassLength <= 0) {
-                // 鐜荤拑娌℃湁闀垮害锛岀洿鎺ユ姤閿欙紙鐢ㄤ簬娴嬭瘯MES绋嬪簭锛�
                 log.error("鐜荤拑[{}]缂哄皯闀垮害鏁版嵁锛屾棤娉曡繘琛屽閲忚绠椼�俤eviceId={}锛岃妫�鏌ES绋嬪簭鏄惁姝g‘鎻愪緵鐜荤拑闀垮害銆�", 
                         info.getGlassId(), deviceId);
                 return null;
@@ -1278,84 +1327,177 @@
         }
         
         try {
+            // 妫�鏌ユ槸鍚﹀凡鏈変换鍔″湪鎵ц涓�
+            MesTaskInfo existingTask = currentTasks.get(deviceId);
+            if (existingTask != null) {
+                log.debug("璁惧宸叉湁浠诲姟鍦ㄦ墽琛屼腑锛岃烦杩囨鏌ES浠诲姟: deviceId={}", deviceId);
+                return DevicePlcVO.OperationResult.builder()
+                        .success(true)
+                        .message("浠诲姟鎵ц涓紝鏃犻渶閲嶅妫�鏌ES浠诲姟")
+                        .data(Collections.singletonMap("waiting", false))
+                        .build();
+            }
+            
             // 璇诲彇MES瀛楁锛堣繘鐗囧拰鍑虹墖鍏辩敤锛�
             Map<String, Object> mesData = plcDynamicDataService.readPlcData(
                     deviceConfig, MES_FIELDS, serializer);
             if (mesData == null || mesData.isEmpty()) {
+                log.warn("璇诲彇MES瀛楁澶辫触: deviceId={}, mesData涓虹┖鎴杗ull", deviceId);
                 return DevicePlcVO.OperationResult.builder()
                         .success(false)
                         .message("璇诲彇MES瀛楁澶辫触")
                         .build();
             }
-            
+
+            // 瑙f瀽mesSend
             Integer mesSend = parseInteger(mesData.get("mesSend"));
+            
             if (mesSend == null || mesSend == 0) {
+                Map<String, Object> waitData = new HashMap<>();
+                waitData.put("completed", false);
+                waitData.put("waiting", true);
+                waitData.put("waitingReason", "mesSend=0");
                 return DevicePlcVO.OperationResult.builder()
                         .success(true)
-                        .message("鏆傛棤MES浠诲姟锛坢esSend=0锛�")
+                        .message("绛夊緟MES鍙戦�佽姹傦紙mesSend=0锛�")
+                        .data(waitData)
                         .build();
             }
             
-            // mesSend=1锛岃鍙栦换鍔″弬鏁�
-            String glassId = parseString(mesData.get("mesGlassId"));
-            Integer startSlot = parseInteger(mesData.get("startSlot")); // 璧峰浣嶇疆缂栧彿
-            Integer targetSlot = parseInteger(mesData.get("targetSlot")); // 鐩爣浣嶇疆缂栧彿
-            Integer workLine = parseInteger(mesData.get("workLine"));
-            
-            if (glassId == null || glassId.isEmpty()) {
-                return DevicePlcVO.OperationResult.builder()
-                        .success(false)
-                        .message("MES鏈彁渚涚幓鐠僆D")
-                        .build();
+            // 鏋勫缓褰撳墠MES鏁版嵁绛惧悕锛岀敤浜庡垽鏂槸鍚︿负宸茬‘璁や絾鏈浣嶇殑鏃т换鍔�
+            String mesSignature = buildMesSignature(mesData);
+            CompletedMesRecord completedRecord = lastCompletedMesRecords.get(deviceId);
+            if (completedRecord != null
+                    && mesSignature.equals(completedRecord.signature)) {
+                Integer mesConfirm = parseInteger(mesData.get("mesConfirm"));
+                if (mesConfirm != null && mesConfirm == 1) {
+                    Map<String, Object> waitData = new HashMap<>();
+                    waitData.put("completed", true);
+                    waitData.put("waiting", true);
+                    waitData.put("waitingReason", "mesNotReset");
+                    return DevicePlcVO.OperationResult.builder()
+                            .success(true)
+                            .message("MES宸茬‘璁ゅ畬鎴愪絾鏈浣嶏紙mesSend/mesConfirm锛夛紝绛夊緟澶嶄綅鍚庡啀鎺ユ敹鏂颁换鍔�")
+                            .data(waitData)
+                            .build();
+                }
             }
             
-            // 鍒ゆ柇鏄繘鐗囪繕鏄嚭鐗囦换鍔�
-            // 鏂规硶锛氶�氳繃startSlot鍒ゆ柇
-            // - 濡傛灉startSlot鏄崸杞珛缂栧彿锛堝900/901锛夛紝鍒欐槸杩涚墖浠诲姟
-            // - 濡傛灉startSlot鏄牸瀛愮紪鍙凤紙鍦ㄥぇ鐞嗙墖绗艰寖鍥村唴锛夛紝鍒欐槸鍑虹墖浠诲姟
-            boolean isOutbound = isOutboundTask(startSlot, logicParams);
+            // mesSend=1锛岃褰曟棩蹇�
+            log.info("妫�娴嬪埌mesSend=1锛屽紑濮嬭鍙朚ES浠诲姟淇℃伅: deviceId={}", deviceId);
             
-            // 浣嶇疆鏄犲皠
-            Integer startPosition;
-            if (isOutbound) {
-                // 鍑虹墖浠诲姟锛歴tartSlot鏄牸瀛愮紪鍙凤紝闇�瑕佹槧灏勫埌瀹為檯浣嶇疆
-                startPosition = mapOutboundPosition(startSlot, logicParams);
-            } else {
-                // 杩涚墖浠诲姟锛歴tartSlot鏄崸杞珛缂栧彿锛岄�氳繃positionMapping鏄犲皠
-                startPosition = mapPosition(startSlot, logicParams);
+            // mesSend=1锛岃鍙栨墍鏈夌幓鐠冪殑浠诲姟鍙傛暟锛堟敮鎸�1-6涓幓鐠冿級
+            List<GlassTaskInfo> glasses = new ArrayList<>();
+            boolean isOutbound = false; // 灏嗗湪澶勭悊绗竴涓湁鏁堢幓鐠冩椂纭畾
+            
+            // 璇诲彇鎵�鏈�6涓幓鐠冪殑淇℃伅
+            for (int i = 1; i <= 6; i++) {
+                String glassId = parseString(mesData.get("mesGlassId" + i));
+                if (glassId == null || glassId.isEmpty()) {
+                    continue; // 璺宠繃绌虹殑鐜荤拑ID
+                }
+                
+                Integer startSlot = parseInteger(mesData.get("start" + i));
+                Integer targetSlot = parseInteger(mesData.get("target" + i));
+                Integer width = parseInteger(mesData.get("mesWidth" + i));
+                Integer height = parseInteger(mesData.get("mesHeight" + i));
+                Integer thickness = parseInteger(mesData.get("mesThickness" + i));
+                
+                log.debug("璇诲彇鐜荤拑{}淇℃伅: deviceId={}, glassId={}, startSlot={}, targetSlot={}, width={}, height={}, thickness={}", 
+                        i, deviceId, glassId, startSlot, targetSlot, width, height, thickness);
+                
+                if (startSlot == null || targetSlot == null) {
+                    log.warn("鐜荤拑{}淇℃伅涓嶅畬鏁达紝璺宠繃: glassId={}, startSlot={}, targetSlot={}", 
+                            i, glassId, startSlot, targetSlot);
+                    continue;
+                }
+                
+                // 瀵逛簬绗竴涓湁鏁堢幓鐠冿紝鍒ゆ柇鏄繘鐗囪繕鏄嚭鐗囦换鍔�
+                if (glasses.isEmpty()) {
+                    isOutbound = isOutboundTask(startSlot, logicParams);
+                }
+                
+                // 浣嶇疆鏄犲皠
+                Integer startPosition;
+                if (isOutbound) {
+                    // 鍑虹墖浠诲姟锛歴tartSlot鏄牸瀛愮紪鍙凤紝闇�瑕佹槧灏勫埌瀹為檯浣嶇疆
+                    startPosition = mapOutboundPosition(startSlot, logicParams);
+                } else {
+                    // 杩涚墖浠诲姟锛歴tartSlot鏄崸杞珛缂栧彿锛岄�氳繃positionMapping鏄犲皠
+                    startPosition = mapPosition(startSlot, logicParams);
+                }
+                
+                // targetSlot缁熶竴閫氳繃positionMapping鏄犲皠
+                Integer targetPosition = mapPosition(targetSlot, logicParams);
+                
+                if (startPosition == null || targetPosition == null) {
+                    log.warn("鐜荤拑{}浣嶇疆鏄犲皠澶辫触锛岃烦杩�: glassId={}, startSlot={}, targetSlot={}", 
+                            i, glassId, startSlot, targetSlot);
+                    continue;
+                }
+                
+                // 鍒涘缓鐜荤拑浠诲姟淇℃伅
+                GlassTaskInfo glassInfo = new GlassTaskInfo();
+                glassInfo.glassId = glassId;
+                glassInfo.startSlot = startSlot;
+                glassInfo.targetSlot = targetSlot;
+                glassInfo.startPosition = startPosition;
+                glassInfo.targetPosition = targetPosition;
+                glassInfo.width = width;
+                glassInfo.height = height;
+                glassInfo.thickness = thickness;
+                glasses.add(glassInfo);
             }
             
-            // targetSlot缁熶竴閫氳繃positionMapping鏄犲皠
-            Integer targetPosition = mapPosition(targetSlot, logicParams);
-            
-            if (startPosition == null || targetPosition == null) {
+            if (glasses.isEmpty()) {
+                // 璁板綍璇︾粏鐨凪ES鏁版嵁锛屽府鍔╄皟璇�
+                log.warn("MES鏈彁渚涙湁鏁堢殑鐜荤拑淇℃伅: deviceId={}, mesSend={}, mesData={}", 
+                        deviceId, mesSend, mesData);
+                Map<String, Object> waitData = new HashMap<>();
+                waitData.put("completed", false);
+                waitData.put("waiting", true);
+                waitData.put("waitingReason", "glassInfoMissing");
                 return DevicePlcVO.OperationResult.builder()
                         .success(false)
-                        .message(String.format("浣嶇疆鏄犲皠澶辫触: startSlot=%s, targetSlot=%s, isOutbound=%s", 
-                                startSlot, targetSlot, isOutbound))
+                        .message("MES鏈彁渚涙湁鏁堢殑鐜荤拑淇℃伅锛坢esSend=1浣嗘湭鎵惧埌鏈夋晥鐨刧lassId銆乻tartSlot銆乼argetSlot锛�")
+                        .data(waitData)
                         .build();
             }
             
             // 璇诲彇褰撳墠浣嶇疆
             Integer currentPosition = getCurrentPosition(deviceConfig, logicParams);
             
-            // 璁$畻鏃堕棿
+            // 浣跨敤绗竴涓幓鐠冪殑浣嶇疆璁$畻鏃堕棿锛堟墍鏈夌幓鐠冧娇鐢ㄧ浉鍚岀殑璺緞锛�
+            GlassTaskInfo firstGlass = glasses.get(0);
             TimeCalculation timeCalc = calculateTime(
-                    currentPosition, startPosition, targetPosition, logicParams);
+                    currentPosition, firstGlass.startPosition, firstGlass.targetPosition, logicParams);
             
             // 鍒涘缓浠诲姟淇℃伅
             MesTaskInfo taskInfo = new MesTaskInfo();
-            taskInfo.glassId = glassId;
-            taskInfo.startSlot = startSlot;
-            taskInfo.targetSlot = targetSlot;
-            taskInfo.startPosition = startPosition;
-            taskInfo.targetPosition = targetPosition;
+            taskInfo.glasses = glasses;
             taskInfo.currentPosition = currentPosition;
             taskInfo.gotime = timeCalc.gotime;
             taskInfo.cartime = timeCalc.cartime;
-            taskInfo.workLine = workLine;
             taskInfo.createdTime = System.currentTimeMillis();
             taskInfo.isOutbound = isOutbound;
+            taskInfo.mesSignature = mesSignature;
+            
+            // 浠庨厤缃腑璇诲彇鐮存崯鐜荤拑绱㈠紩锛堢敤浜庢祴璇曞満鏅級
+            // 閰嶇疆鏍煎紡锛歜rokenGlassIndices: [0, 2] 琛ㄧず绗�1涓拰绗�3涓幓鐠冨簲璇ョ牬鎹�
+            @SuppressWarnings("unchecked")
+            List<Integer> brokenIndices = getLogicParam(logicParams, "brokenGlassIndices", null);
+            if (brokenIndices != null && !brokenIndices.isEmpty()) {
+                taskInfo.brokenGlassIndices = new ArrayList<>();
+                for (Integer index : brokenIndices) {
+                    if (index != null && index >= 0 && index < glasses.size()) {
+                        taskInfo.brokenGlassIndices.add(index);
+                    }
+                }
+                if (!taskInfo.brokenGlassIndices.isEmpty()) {
+                    log.info("浠诲姟鍒涘缓鏃舵爣璁扮牬鎹熺幓鐠�: deviceId={}, brokenIndices={}", 
+                            deviceId, taskInfo.brokenGlassIndices);
+                }
+            }
             
             currentTasks.put(deviceId, taskInfo);
             
@@ -1363,23 +1505,43 @@
             Map<String, Object> payload = new HashMap<>();
             payload.put("plcRequest", 0);
             plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
+            log.info("宸叉竻绌簆lcRequest=0: deviceId={}", deviceId);
             
             // 鏇存柊杞﹁締鐘舵�佷负鎵ц涓�
             statusManager.updateVehicleStatus(deviceId, deviceConfig.getDeviceName(), VehicleState.EXECUTING);
             
             // 鍚姩浠诲姟鐩戞帶
             handleStartTaskMonitor(deviceConfig, params, logicParams);
+            log.info("宸插惎鍔ㄤ换鍔$洃鎺�: deviceId={}", deviceId);
             
             String taskType = isOutbound ? "鍑虹墖" : "杩涚墖";
-            log.info("MES{}浠诲姟宸插垱寤�: deviceId={}, glassId={}, startSlot={}(浣嶇疆{}鏍�), targetSlot={}(浣嶇疆{}鏍�), 璺濈{}鏍�->{}鏍�, gotime={}ms({}绉�), cartime={}ms({}绉�)", 
-                    taskType, deviceId, glassId, startSlot, startPosition, targetSlot, targetPosition,
-                    Math.abs(startPosition - currentPosition), Math.abs(targetPosition - startPosition),
+            String glassIds = glasses.stream()
+                    .map(g -> g.glassId)
+                    .collect(java.util.stream.Collectors.joining(","));
+            log.info("MES{}浠诲姟宸插垱寤�: deviceId={}, glassCount={}, glassIds=[{}], 璧峰浣嶇疆={}鏍�, 鐩爣浣嶇疆={}鏍�, 璺濈{}鏍�->{}鏍�, gotime={}ms({}绉�), cartime={}ms({}绉�)", 
+                    taskType, deviceId, glasses.size(), glassIds,
+                    firstGlass.startPosition, firstGlass.targetPosition,
+                    Math.abs(firstGlass.startPosition - currentPosition), 
+                    Math.abs(firstGlass.targetPosition - firstGlass.startPosition),
                     timeCalc.gotime, timeCalc.gotime / 1000.0, timeCalc.cartime, timeCalc.cartime / 1000.0);
+            
+            // 鏋勫缓璇︾粏鐨勬楠ゆ彁绀轰俊鎭�
+            StringBuilder stepMessage = new StringBuilder();
+            stepMessage.append("妫�娴嬪埌MES浠诲姟锛坢esSend=1锛夛紝宸叉竻绌鸿姹傚瓧锛坧lcRequest=0锛�");
+            stepMessage.append("锛涘紑濮嬭绠楁椂闂达紝棰勮鍒拌揪璧峰浣嶇疆鑰楁椂").append(timeCalc.gotime / 1000.0).append("绉�");
+            stepMessage.append("锛岃繍杈撳埌鐩爣浣嶇疆鑰楁椂").append(timeCalc.cartime / 1000.0).append("绉�");
+            if (!isOutbound) {
+                stepMessage.append("锛涜繘鐗囦换鍔★細绛夊緟鐜荤拑涓婅溅鍚庯紝灏嗗憡鐭ュ崸杞珛璁惧");
+            }
+            
+            Map<String, Object> successData = new HashMap<>();
+            successData.put("waiting", false);
+            successData.put("taskStarted", true);
             
             return DevicePlcVO.OperationResult.builder()
                     .success(true)
-                    .message(String.format("MES%s浠诲姟宸插垱寤�: glassId=%s, start=%d, target=%d", 
-                            taskType, glassId, startPosition, targetPosition))
+                    .message(stepMessage.toString())
+                    .data(successData)
                     .build();
                     
         } catch (Exception e) {
@@ -1531,7 +1693,22 @@
         }
         
         // 鑾峰彇閫熷害锛堟牸/绉掞紝grid/s锛�
-        Double speed = getLogicParam(logicParams, "vehicleSpeed", 1.0);
+        // 杩欓噷涓嶈兘鐩存帴鐢� Double 娉涘瀷锛屽惁鍒欏綋閰嶇疆閲屾槸 Integer 鏃朵細鍑虹幇
+        // java.lang.Integer cannot be cast to java.lang.Double 鐨勫紓甯�
+        Object speedObj = getLogicParam(logicParams, "vehicleSpeed", 1.0);
+        Double speed = null;
+        if (speedObj instanceof Double) {
+            speed = (Double) speedObj;
+        } else if (speedObj instanceof Integer) {
+            speed = ((Integer) speedObj).doubleValue();
+        } else if (speedObj instanceof Number) {
+            speed = ((Number) speedObj).doubleValue();
+        } else {
+            try {
+                speed = Double.parseDouble(String.valueOf(speedObj));
+            } catch (Exception ignore) {
+            }
+        }
         if (speed == null || speed <= 0) {
             speed = 1.0; // 榛樿1鏍�/绉�
         }
@@ -1645,24 +1822,90 @@
             long state1Time = taskInfo.gotime; // 鍒拌揪璧峰浣嶇疆锛屼笂杞﹀畬鎴�
             long state2Time = taskInfo.gotime + taskInfo.cartime; // 鍒拌揪鐩爣浣嶇疆锛岃繍杈撳畬鎴�
             
-            // 鏇存柊state鐘舵��
-            if (elapsed >= state1Time && elapsed < state2Time) {
-                // state搴旇涓�1
-                if (taskInfo.isOutbound) {
-                    // 鍑虹墖浠诲姟锛氬埌杈炬簮浣嶇疆锛堝ぇ鐞嗙墖绗硷級锛屽彇鐗囧畬鎴�
-                    updateStateIfNeeded(deviceConfig, serializer, stateValues, 1, taskInfo);
-                } else {
-                    // 杩涚墖浠诲姟锛氬埌杈捐捣濮嬩綅缃紙鍗ц浆绔嬶級锛屼笂杞﹀畬鎴�
-                    updateStateIfNeeded(deviceConfig, serializer, stateValues, 1, taskInfo);
-                }
-            } else if (elapsed >= state2Time) {
-                // state搴旇涓�2锛堣繍杈撳畬鎴愶級
-                updateStateIfNeeded(deviceConfig, serializer, stateValues, 2, taskInfo);
+            // 鑾峰彇瓒呮椂鏃堕棿閰嶇疆锛堥粯璁わ細瓒呰繃棰勬湡瀹屾垚鏃堕棿鐨�200%瑙嗕负瓒呮椂鏈畬鎴愶級
+            Double timeoutRatio = getLogicParam(logicParams, "state3TimeoutRatio", 2.0);
+            long state3TimeoutTime = (long) (state2Time * timeoutRatio); // 瓒呮椂鏃堕棿鐐�
+            
+            // 鏇存柊state鐘舵�侊紙姣忎釜鐜荤拑瀵瑰簲涓�涓猻tate锛�
+            int glassCount = taskInfo.glasses.size();
+            boolean hasStateOne = false; // 鏍囪鏄惁鏈塻tate鍙樹负1
+            boolean hasStateTwo = false; // 鏍囪鏄惁鏈塻tate鍙樹负2
+            String currentStepDesc = ""; // 褰撳墠姝ラ鎻忚堪
+            
+            for (int i = 0; i < glassCount && i < 6; i++) {
+                String stateField = "state" + (i + 1);
+                Object currentValue = stateValues.get(stateField);
+                Integer currentState = parseInteger(currentValue);
                 
-                // 妫�鏌ユ槸鍚︽墍鏈塻tate閮�>=2锛屽鏋滄槸鍒欑粰MES姹囨姤
-                if (allStatesCompleted(stateValues)) {
-                    reportToMes(deviceConfig, serializer, taskInfo, logicParams);
+                // 濡傛灉褰撳墠state宸茬粡鏄�3锛堟湭瀹屾垚锛夋垨8锛堢牬鎹燂級锛岃烦杩�
+                if (currentState != null && (currentState == 3 || currentState == 8)) {
+                    continue;
                 }
+                
+                // 浼樺厛妫�鏌ユ槸鍚︽爣璁颁负鐮存崯锛坰tate=8锛�
+                // 妫�鏌ヤ换鍔′俊鎭腑鏄惁鏍囪浜嗚鐜荤拑涓虹牬鎹�
+                if (taskInfo.brokenGlassIndices != null && taskInfo.brokenGlassIndices.contains(i)) {
+                    updateStateIfNeeded(deviceConfig, serializer, stateValues, stateField, 8, taskInfo);
+                    log.info("鐜荤拑鏍囪涓虹牬鎹�: deviceId={}, stateField={}, glassIndex={}", 
+                            deviceConfig.getDeviceId(), stateField, i);
+                    continue;
+                }
+                
+                // 妫�鏌ヨ秴鏃舵湭瀹屾垚锛坰tate=3锛�
+                if (elapsed >= state3TimeoutTime && (currentState == null || currentState < 2)) {
+                    updateStateIfNeeded(deviceConfig, serializer, stateValues, stateField, 3, taskInfo);
+                    log.warn("浠诲姟瓒呮椂鏈畬鎴�: deviceId={}, stateField={}, elapsed={}ms, expectedTime={}ms", 
+                            deviceConfig.getDeviceId(), stateField, elapsed, state2Time);
+                    continue;
+                }
+                
+                // 姝e父鐘舵�佹洿鏂�
+                if (elapsed >= state1Time && elapsed < state2Time) {
+                    // state搴旇涓�1锛堜笂杞﹀畬鎴愶級
+                    boolean stateChanged = updateStateIfNeeded(deviceConfig, serializer, stateValues, stateField, 1, taskInfo);
+                    if (stateChanged) {
+                        hasStateOne = true;
+                        currentStepDesc = "鐜荤拑宸蹭笂杞︼紙state=1锛夛紝姝e湪杩愯緭鍒扮洰鏍囦綅缃�";
+                    } else if (currentState != null && currentState == 1) {
+                        currentStepDesc = "鐜荤拑宸蹭笂杞︼紙state=1锛夛紝姝e湪杩愯緭鍒扮洰鏍囦綅缃�";
+                    }
+                } else if (elapsed >= state2Time) {
+                    // state搴旇涓�2锛堣繍杈撳畬鎴愶級
+                    boolean stateChanged = updateStateIfNeeded(deviceConfig, serializer, stateValues, stateField, 2, taskInfo);
+                    if (stateChanged) {
+                        hasStateTwo = true;
+                        currentStepDesc = "鐜荤拑宸插埌杈剧洰鏍囦綅缃紙state=2锛夛紝绛夊緟MES纭";
+                    } else if (currentState != null && currentState == 2) {
+                        currentStepDesc = "鐜荤拑宸插埌杈剧洰鏍囦綅缃紙state=2锛夛紝绛夊緟MES纭";
+                    }
+                } else {
+                    // 杩樺湪鍓嶅線璧峰浣嶇疆
+                    currentStepDesc = "姝e湪鍓嶅線璧峰浣嶇疆锛岄璁¤�楁椂" + (state1Time / 1000.0) + "绉�";
+                }
+            }
+            
+            // 褰搒tate鍙樹负1鏃讹紙鐜荤拑涓婅溅瀹屾垚锛夛紝娓呯┖鍗ц浆绔嬭澶囩殑plcRequest锛堝彧鎵ц涓�娆★級
+            if (hasStateOne && !taskInfo.transferPlcRequestCleared) {
+                clearTransferPlcRequest(deviceConfig, logicParams);
+                taskInfo.transferPlcRequestCleared = true; // 鏍囪宸叉竻绌猴紝閬垮厤閲嶅鎵ц
+                if (!taskInfo.isOutbound) {
+                    currentStepDesc = "鐜荤拑宸蹭笂杞︼紙state=1锛夛紝宸插憡鐭ュ崸杞珛璁惧锛坧lcRequest=0锛夛紝姝e湪杩愯緭鍒扮洰鏍囦綅缃�";
+                }
+            }
+            
+            // 妫�鏌ユ槸鍚︽墍鏈塻tate閮�>=2锛屽鏋滄槸鍒欑粰MES姹囨姤
+            if (elapsed >= state2Time && allStatesCompleted(stateValues, glassCount)) {
+                reportToMes(deviceConfig, serializer, taskInfo, logicParams);
+                // 璁板綍MES纭寮�濮嬬瓑寰呯殑鏃堕棿锛堝彧璁板綍涓�娆★級
+                if (taskInfo.mesConfirmStartTime == null) {
+                    taskInfo.mesConfirmStartTime = System.currentTimeMillis();
+                    currentStepDesc = "鐜荤拑宸插埌杈剧洰鏍囦綅缃紙state=2锛夛紝宸插彂閫佹眹鎶ワ紙plcReport=1锛夛紝绛夊緟MES纭";
+                }
+            }
+            
+            // 淇濆瓨褰撳墠姝ラ鎻忚堪鍒颁换鍔′俊鎭腑锛屼緵checkMesConfirm浣跨敤
+            if (!currentStepDesc.isEmpty()) {
+                taskInfo.currentStepDesc = currentStepDesc;
             }
             
         } catch (Exception e) {
@@ -1672,30 +1915,97 @@
 
     /**
      * 鏇存柊state鐘舵�侊紙濡傛灉闇�瑕侊級
+     * @return 鏄惁鍙戠敓浜嗙姸鎬佸彉鍖栵紙浠庨潪鐩爣鐘舵�佸彉涓虹洰鏍囩姸鎬侊級
      */
-    private void updateStateIfNeeded(DeviceConfig deviceConfig,
+    private boolean updateStateIfNeeded(DeviceConfig deviceConfig,
                                      EnhancedS7Serializer serializer,
                                      Map<String, Object> currentStates,
+                                     String stateField,
                                      int targetState,
                                      MesTaskInfo taskInfo) {
         
-        // 杩欓噷鍙互鏍规嵁瀹為檯闇�姹傛洿鏂皊tate瀛楁
-        // 鏆傛椂鍙褰曟棩蹇楋紝瀹為檯鏇存柊鍙兘闇�瑕佹牴鎹叿浣揚LC瀛楁閰嶇疆
-        log.debug("浠诲姟鐘舵�佹洿鏂�: deviceId={}, targetState={}", 
-                deviceConfig.getDeviceId(), targetState);
+        // 妫�鏌ュ綋鍓峴tate鍊�
+        Object currentValue = currentStates.get(stateField);
+        Integer currentState = parseInteger(currentValue);
+        
+        // 濡傛灉褰撳墠state灏忎簬鐩爣state锛屽垯鏇存柊
+        // 娉ㄦ剰锛氬鏋滃綋鍓峴tate宸茬粡鏄�3锛堟湭瀹屾垚锛夋垨8锛堢牬鎹燂級锛屼笉鍐嶆洿鏂�
+        if (currentState != null && (currentState == 3 || currentState == 8)) {
+            log.debug("浠诲姟鐘舵�佸凡涓哄紓甯哥姸鎬侊紝涓嶅啀鏇存柊: deviceId={}, stateField={}, currentState={}, targetState={}", 
+                    deviceConfig.getDeviceId(), stateField, currentState, targetState);
+            return false;
+        }
+        
+        if (currentState == null || currentState < targetState) {
+            // 瀹為檯鍐欏叆PLC鐨剆tate瀛楁
+            try {
+                Map<String, Object> payload = new HashMap<>();
+                payload.put(stateField, targetState);
+                plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
+                
+                log.info("浠诲姟鐘舵�佸凡鏇存柊鍒癙LC: deviceId={}, stateField={}, currentState={}, targetState={}", 
+                        deviceConfig.getDeviceId(), stateField, currentState, targetState);
+                // 杩斿洖true琛ㄧず鐘舵�佸彂鐢熶簡鍙樺寲
+                return true;
+            } catch (Exception e) {
+                log.error("鍐欏叆PLC state瀛楁澶辫触: deviceId={}, stateField={}, targetState={}, error={}", 
+                        deviceConfig.getDeviceId(), stateField, targetState, e.getMessage());
+                return false;
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * 娓呯┖鍗ц浆绔嬭澶囩殑plcRequest锛堝綋澶ц溅state=1鏃讹紝琛ㄧず鐜荤拑宸蹭笂杞︼級
+     */
+    private void clearTransferPlcRequest(DeviceConfig deviceConfig, Map<String, Object> logicParams) {
+        try {
+            // 鏌ユ壘鍚岀粍鐨勫崸杞珛璁惧
+            List<DeviceConfig> transferDevices = findTransferDevicesInSameGroup(deviceConfig);
+            if (transferDevices.isEmpty()) {
+                log.debug("鏈壘鍒板悓缁勭殑鍗ц浆绔嬭澶囷紝璺宠繃娓呯┖plcRequest: deviceId={}", deviceConfig.getId());
+                return;
+            }
+            
+            // 灏嗘瘡涓崸杞珛璁惧鐨� plcRequest 缃� 0
+            for (DeviceConfig transferDevice : transferDevices) {
+                Map<String, Object> payload = new HashMap<>();
+                payload.put("plcRequest", 0);
+                
+                DevicePlcVO.OperationResult result = devicePlcOperationService.writeFields(
+                        transferDevice.getId(),
+                        payload,
+                        "澶ц溅state=1鑷姩娓呯┖鍗ц浆绔嬭姹�"
+                );
+                
+                if (Boolean.TRUE.equals(result.getSuccess())) {
+                    log.info("宸茶嚜鍔ㄦ竻绌哄崸杞珛璁惧 plcRequest: vehicleDeviceId={}, transferDeviceId={}, transferDeviceName={}", 
+                            deviceConfig.getId(), transferDevice.getId(), transferDevice.getDeviceName());
+                } else {
+                    log.warn("鑷姩娓呯┖鍗ц浆绔嬭澶� plcRequest 澶辫触: vehicleDeviceId={}, transferDeviceId={}, message={}", 
+                            deviceConfig.getId(), transferDevice.getId(), result.getMessage());
+                }
+            }
+        } catch (Exception e) {
+            log.error("娓呯┖鍗ц浆绔嬭澶噋lcRequest寮傚父: deviceId={}", deviceConfig.getId(), e);
+        }
     }
 
     /**
      * 妫�鏌ユ槸鍚︽墍鏈塻tate閮藉凡瀹屾垚锛�>=2锛�
      */
-    private boolean allStatesCompleted(Map<String, Object> stateValues) {
-        for (Object value : stateValues.values()) {
+    private boolean allStatesCompleted(Map<String, Object> stateValues, int glassCount) {
+        // 鍙鏌ュ疄闄呮湁鐜荤拑鐨剆tate瀛楁
+        for (int i = 1; i <= glassCount && i <= 6; i++) {
+            String stateField = "state" + i;
+            Object value = stateValues.get(stateField);
             Integer state = parseInteger(value);
             if (state == null || state < 2) {
                 return false;
             }
         }
-        return !stateValues.isEmpty();
+        return glassCount > 0;
     }
 
     /**
@@ -1713,8 +2023,11 @@
             plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
             
             String taskType = taskInfo.isOutbound ? "鍑虹墖" : "杩涚墖";
-            log.info("宸茬粰MES姹囨姤({}浠诲姟): deviceId={}, glassId={}", 
-                    taskType, deviceConfig.getDeviceId(), taskInfo.glassId);
+            String glassIds = taskInfo.glasses.stream()
+                    .map(g -> g.glassId)
+                    .collect(java.util.stream.Collectors.joining(","));
+            log.info("宸茬粰MES姹囨姤({}浠诲姟): deviceId={}, glassCount={}, glassIds=[{}]", 
+                    taskType, deviceConfig.getDeviceId(), taskInfo.glasses.size(), glassIds);
             
             // 澶氳澶囦换鍔″満鏅笅锛屼笉鍦ㄨ繖閲岄樆濉炵瓑寰匨ES纭锛岀敱浠诲姟寮曟搸瀹氭椂璋冪敤checkMesConfirm
         } catch (Exception e) {
@@ -1742,8 +2055,93 @@
                     .build();
         }
 
+        String deviceId = deviceConfig.getDeviceId();
+        MesTaskInfo taskInfo = currentTasks.get(deviceId);
+        
+        // 濡傛灉娌℃湁浠诲姟璁板綍锛屼紭鍏堝皾璇曡ˉ鍋挎�у湴妫�鏌ヤ竴娆ES浠诲姟锛堥伩鍏嶅洜鏃跺簭闂涓�鐩磏oTask锛�
+        if (taskInfo == null) {
+            log.info("妫�鏌ES纭鏃舵湭鎵惧埌浠诲姟璁板綍锛屽皾璇曡ˉ鍋挎鏌ES浠诲姟: deviceId={}", deviceId);
+            try {
+                DevicePlcVO.OperationResult checkResult =
+                        handleCheckMesTask(deviceConfig, Collections.emptyMap(), logicParams);
+                if (Boolean.TRUE.equals(checkResult.getSuccess())) {
+                    taskInfo = currentTasks.get(deviceId);
+                    if (taskInfo != null) {
+                        log.info("琛ュ伩妫�鏌ES浠诲姟鎴愬姛锛屽凡鍒涘缓浠诲姟璁板綍: deviceId={}", deviceId);
+                    } else {
+                        log.info("琛ュ伩妫�鏌ES浠诲姟鎵ц鎴愬姛浣嗘湭鍒涘缓浠诲姟璁板綍: deviceId={}, message={}",
+                                deviceId, checkResult.getMessage());
+                    }
+                } else {
+                    log.warn("琛ュ伩妫�鏌ES浠诲姟澶辫触: deviceId={}, message={}", deviceId, checkResult.getMessage());
+                }
+            } catch (Exception e) {
+                log.warn("琛ュ伩妫�鏌ES浠诲姟寮傚父: deviceId={}, error={}", deviceId, e.getMessage());
+            }
+        }
+        
+        // 琛ュ伩鍚庝粛鐒舵病鏈変换鍔¤褰曪紝璇存槑MES灏氭湭鎻愪緵鍙墽琛屼换鍔�
+        if (taskInfo == null) {
+            Map<String, Object> waitData = new HashMap<>();
+            waitData.put("completed", false);
+            waitData.put("waiting", true);
+            waitData.put("waitingReason", "noTask");
+            return DevicePlcVO.OperationResult.builder()
+                    .success(true)
+                    .message("绛夊緟MES鍙戦�佽姹傦紙mesSend=1锛�")
+                    .data(waitData)
+                    .build();
+        }
+        
+        // 鑾峰彇MES纭瓒呮椂閰嶇疆锛堥粯璁�30绉掞級
+        Integer mesConfirmTimeoutMs = getLogicParam(logicParams, "mesConfirmTimeoutMs", 30000);
+        
         Map<String, Object> data = new HashMap<>();
         try {
+            // 濡傛灉灏氭湭鍚慚ES姹囨姤锛坧lcReport=1锛夛紝鏃犻渶妫�鏌ョ‘璁�
+            if (taskInfo.mesConfirmStartTime == null) {
+                data.put("completed", false);
+                data.put("waiting", true);
+                data.put("waitingReason", "waitingReport");
+                String detail = taskInfo.currentStepDesc;
+                String message = "澶ц溅浠诲姟鎵ц涓紝灏氭湭姹囨姤锛屾棤闇�妫�鏌ョ‘璁�";
+                if (detail != null && !detail.isEmpty()) {
+                    message = detail + "锛�" + message;
+                }
+                return DevicePlcVO.OperationResult.builder()
+                        .success(true)
+                        .message(message)
+                        .data(data)
+                        .build();
+            }
+            
+            // 妫�鏌ヨ秴鏃�
+            long waitTime = System.currentTimeMillis() - taskInfo.mesConfirmStartTime;
+            if (waitTime > mesConfirmTimeoutMs) {
+                log.warn("MES纭瓒呮椂: deviceId={}, waitTime={}ms, timeout={}ms", 
+                        deviceId, waitTime, mesConfirmTimeoutMs);
+                data.put("completed", false);
+                data.put("timeout", true);
+                data.put("waitTime", waitTime);
+
+                // 瓒呮椂瑙嗕负浠诲姟澶辫触锛氭竻鐞嗕换鍔$姸鎬佸苟鍋滄鐩戞帶锛岄伩鍏嶇户缁疮鍔犵瓑寰呮椂闂�
+                try {
+                    clearTaskStates(deviceConfig, serializer);
+                } catch (Exception e) {
+                    log.warn("MES纭瓒呮椂鏃舵竻绌轰换鍔$姸鎬佸け璐�: deviceId={}, error={}", deviceId, e.getMessage());
+                }
+                statusManager.updateVehicleStatus(deviceConfig.getDeviceId(), VehicleState.ERROR);
+                statusManager.clearVehicleTask(deviceConfig.getDeviceId());
+                currentTasks.remove(deviceConfig.getDeviceId());
+                handleStopTaskMonitor(deviceConfig);
+
+                return DevicePlcVO.OperationResult.builder()
+                        .success(false)
+                        .message(String.format("MES纭瓒呮椂: 绛夊緟鏃堕棿%dms锛岃秴鏃舵椂闂�%dms", waitTime, mesConfirmTimeoutMs))
+                        .data(data)
+                        .build();
+            }
+            
             Object confirmValue = plcDynamicDataService.readPlcField(
                     deviceConfig, "mesConfirm", serializer);
             Integer confirm = parseInteger(confirmValue);
@@ -1753,6 +2151,10 @@
             if (completed) {
                 // MES宸茬‘璁わ紝娓呯┖state鍜屾眹鎶ュ瓧
                 clearTaskStates(deviceConfig, serializer);
+
+                // 璁板綍宸插畬鎴愮殑浠诲姟绛惧悕锛岄伩鍏峂ES鏈浣嶆椂琚噸澶嶆媺璧�
+                lastCompletedMesRecords.put(deviceId,
+                        new CompletedMesRecord(taskInfo.mesSignature, System.currentTimeMillis()));
 
                 // 浠诲姟瀹屾垚锛屾仮澶嶄负绌洪棽鐘舵��
                 statusManager.updateVehicleStatus(
@@ -1771,16 +2173,26 @@
                 plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
 
                 log.info("MES浠诲姟宸茬‘璁ゅ畬鎴�: deviceId={}", deviceConfig.getDeviceId());
+                String taskType = taskInfo.isOutbound ? "鍑虹墖" : "杩涚墖";
                 return DevicePlcVO.OperationResult.builder()
                         .success(true)
-                        .message("MES浠诲姟宸茬‘璁ゅ畬鎴�")
+                        .message(String.format("%s浠诲姟瀹屾垚锛歁ES宸茬‘璁わ紙mesConfirm=1锛夛紝宸叉竻绌簊tate鍜屾眹鎶ュ瓧锛屽ぇ杞︾┖闂诧紙plcRequest=1锛夛紝鍙互绛夊緟涓嬫浠诲姟", taskType))
                         .data(data)
                         .build();
             }
 
+            // 鏋勫缓璇︾粏鐨勭瓑寰呮彁绀轰俊鎭�
+            String waitMessage = "绛夊緟MES纭涓紙mesConfirm=0锛�";
+            if (taskInfo.currentStepDesc != null && !taskInfo.currentStepDesc.isEmpty()) {
+                waitMessage = taskInfo.currentStepDesc + "锛�" + waitMessage;
+            } else if (taskInfo.mesConfirmStartTime != null) {
+                long waitMillis = System.currentTimeMillis() - taskInfo.mesConfirmStartTime;
+                waitMessage = String.format("绛夊緟MES纭涓紙mesConfirm=0锛夛紝宸茬瓑寰�%.1f绉�", waitMillis / 1000.0);
+            }
+            
             return DevicePlcVO.OperationResult.builder()
                     .success(true)
-                    .message("绛夊緟MES纭涓�")
+                    .message(waitMessage)
                     .data(data)
                     .build();
         } catch (Exception e) {
@@ -1793,6 +2205,84 @@
         }
     }
 
+    /**
+     * 璁剧疆鐜荤拑涓虹牬鎹熺姸鎬侊紙state=8锛�
+     * 鐢ㄤ簬娴嬭瘯鍦烘櫙锛屾ā鎷熺幓鐠冪牬鎹�
+     */
+    private DevicePlcVO.OperationResult handleMarkBroken(DeviceConfig deviceConfig,
+                                                         Map<String, Object> params,
+                                                         Map<String, Object> logicParams) {
+        String deviceId = deviceConfig.getDeviceId();
+        MesTaskInfo taskInfo = currentTasks.get(deviceId);
+        if (taskInfo == null) {
+            return DevicePlcVO.OperationResult.builder()
+                    .success(false)
+                    .message("娌℃湁姝e湪鎵ц鐨勪换鍔�")
+                    .build();
+        }
+        
+        // 浠庡弬鏁颁腑鑾峰彇瑕佹爣璁颁负鐮存崯鐨勭幓鐠冪储寮曪紙0-based锛�
+        // 鏀寔鍗曚釜绱㈠紩鎴栫储寮曞垪琛�
+        List<Integer> brokenIndices = new ArrayList<>();
+        Object brokenIndexObj = params.get("glassIndex");
+        if (brokenIndexObj != null) {
+            if (brokenIndexObj instanceof List) {
+                @SuppressWarnings("unchecked")
+                List<Object> indexList = (List<Object>) brokenIndexObj;
+                for (Object idx : indexList) {
+                    Integer index = parseInteger(idx);
+                    if (index != null && index >= 0 && index < taskInfo.glasses.size()) {
+                        brokenIndices.add(index);
+                    }
+                }
+            } else {
+                Integer index = parseInteger(brokenIndexObj);
+                if (index != null && index >= 0 && index < taskInfo.glasses.size()) {
+                    brokenIndices.add(index);
+                }
+            }
+        }
+        
+        if (brokenIndices.isEmpty()) {
+            return DevicePlcVO.OperationResult.builder()
+                    .success(false)
+                    .message("鏈寚瀹氭湁鏁堢殑鐜荤拑绱㈠紩")
+                    .build();
+        }
+        
+        // 鏍囪涓虹牬鎹�
+        if (taskInfo.brokenGlassIndices == null) {
+            taskInfo.brokenGlassIndices = new ArrayList<>();
+        }
+        for (Integer index : brokenIndices) {
+            if (!taskInfo.brokenGlassIndices.contains(index)) {
+                taskInfo.brokenGlassIndices.add(index);
+            }
+        }
+        
+        // 绔嬪嵆鍐欏叆PLC鐨剆tate瀛楁
+        EnhancedS7Serializer serializer = s7SerializerProvider.getSerializer(deviceConfig);
+        if (serializer != null) {
+            try {
+                Map<String, Object> payload = new HashMap<>();
+                for (Integer index : brokenIndices) {
+                    String stateField = "state" + (index + 1);
+                    payload.put(stateField, 8);
+                }
+                plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
+                log.info("宸叉爣璁扮幓鐠冧负鐮存崯骞跺啓鍏LC: deviceId={}, brokenIndices={}", 
+                        deviceId, brokenIndices);
+            } catch (Exception e) {
+                log.error("鍐欏叆鐮存崯鐘舵�佸埌PLC澶辫触: deviceId={}, error={}", deviceId, e.getMessage());
+            }
+        }
+        
+        return DevicePlcVO.OperationResult.builder()
+                .success(true)
+                .message(String.format("宸叉爣璁扮幓鐠冧负鐮存崯: indices=%s", brokenIndices))
+                .build();
+    }
+    
     /**
      * 娓呯┖浠诲姟鐘舵��
      */
@@ -1841,20 +2331,47 @@
     }
 
     /**
-     * MES浠诲姟淇℃伅
+     * 鍗曚釜鐜荤拑鐨勪换鍔′俊鎭�
      */
-    private static class MesTaskInfo {
+    private static class GlassTaskInfo {
         String glassId;
         Integer startSlot;
         Integer targetSlot;
         Integer startPosition;
         Integer targetPosition;
+        Integer width;
+        Integer height;
+        Integer thickness;
+    }
+    
+    /**
+     * MES浠诲姟淇℃伅锛堝彲鑳藉寘鍚涓幓鐠冿級
+     */
+    private static class MesTaskInfo {
+        List<GlassTaskInfo> glasses = new ArrayList<>(); // 澶氫釜鐜荤拑淇℃伅
         Integer currentPosition;
         long gotime;
         long cartime;
-        Integer workLine;
         long createdTime;
         boolean isOutbound = false; // 鏄惁涓哄嚭鐗囦换鍔★紙false=杩涚墖锛宼rue=鍑虹墖锛�
+        boolean transferPlcRequestCleared = false; // 鏄惁宸叉竻绌哄崸杞珛plcRequest锛堥伩鍏嶉噸澶嶆竻绌猴級
+        List<Integer> brokenGlassIndices = null; // 鏍囪涓虹牬鎹熺殑鐜荤拑绱㈠紩鍒楄〃锛�0-based锛岀敤浜庢祴璇曞満鏅級
+        Long mesConfirmStartTime = null; // MES纭寮�濮嬬瓑寰呯殑鏃堕棿锛堢敤浜庤秴鏃舵娴嬶級
+        String currentStepDesc = null; // 褰撳墠姝ラ鎻忚堪锛堢敤浜庢樉绀鸿缁嗙殑鎵ц鐘舵�侊級
+        String mesSignature = null; // MES鏁版嵁绛惧悕锛岀敤浜庨伩鍏嶆湭澶嶄綅鏃堕噸澶嶆媺璧�
+    }
+
+    /**
+     * 璁板綍宸插畬鎴愪絾MES鏈浣嶇殑浠诲姟淇℃伅
+     */
+    private static class CompletedMesRecord {
+        final String signature;
+        final long completedAt;
+
+        CompletedMesRecord(String signature, long completedAt) {
+            this.signature = signature;
+            this.completedAt = completedAt;
+        }
     }
 
     /**
@@ -1919,5 +2436,41 @@
             log.debug("鏈壘鍒癟askExecutionContext锛屾棤娉曢�氱煡鍗ц浆绔嬫壂鐮佽澶囨殏鍋�");
         }
     }
+
+    private void clearDynamicTaskStates(DeviceConfig deviceConfig) {
+        if (plcDynamicDataService == null || s7SerializerProvider == null) {
+            return;
+        }
+        try {
+            EnhancedS7Serializer serializer = s7SerializerProvider.getSerializer(deviceConfig);
+            if (serializer != null) {
+                clearTaskStates(deviceConfig, serializer);
+            }
+        } catch (Exception e) {
+            log.warn("娓呯┖澶ц溅state瀛楁澶辫触: deviceId={}, error={}", deviceConfig != null ? deviceConfig.getId() : "null", e.getMessage());
+        }
+    }
+
+    /**
+     * 灏哅ES鏁版嵁鏋勯�犳垚绛惧悕瀛楃涓诧紝鐢ㄤ簬璇嗗埆鏄惁涓哄悓涓�鎵规浠诲姟
+     */
+    private String buildMesSignature(Map<String, Object> mesData) {
+        if (mesData == null || mesData.isEmpty()) {
+            return "empty";
+        }
+        StringBuilder sb = new StringBuilder();
+        sb.append("mesSend=").append(mesData.getOrDefault("mesSend", ""))
+                .append(";mesConfirm=").append(mesData.getOrDefault("mesConfirm", ""));
+        for (int i = 1; i <= 6; i++) {
+            sb.append(";g").append(i).append("=")
+                    .append(mesData.getOrDefault("mesGlassId" + i, ""))
+                    .append(",s").append(mesData.getOrDefault("start" + i, ""))
+                    .append(",t").append(mesData.getOrDefault("target" + i, ""))
+                    .append(",w").append(mesData.getOrDefault("mesWidth" + i, ""))
+                    .append(",h").append(mesData.getOrDefault("mesHeight" + i, ""))
+                    .append(",th").append(mesData.getOrDefault("mesThickness" + i, ""));
+        }
+        return sb.toString();
+    }
 }
 

--
Gitblit v1.8.0