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/task/service/TaskExecutionEngine.java | 1027 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 914 insertions(+), 113 deletions(-)

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 627c88e..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
@@ -102,6 +102,8 @@
 
         TaskExecutionContext context = new TaskExecutionContext(parameters);
         runningTaskContexts.put(task.getTaskId(), context);
+        // 灏嗘湰娆′换鍔℃秹鍙婄殑璁惧鍒楄〃瀛樺叆涓婁笅鏂囷紝渚夸簬鍙栨秷浠诲姟鏃跺仛璁惧绾ф敹灏撅紙濡傚仠姝㈠ぇ杞﹀唴閮ㄧ洃鎺у畾鏃跺櫒锛�
+        context.getSharedData().put("devices", devices);
         
         task.setTotalSteps(devices.size());
         task.setStatus(MultiDeviceTask.Status.RUNNING.name());
@@ -245,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;
                 }
@@ -340,6 +336,35 @@
         if (context != null) {
             context.getSharedData().put("taskCancelled", true);
             log.warn("宸叉爣璁颁换鍔″彇娑�: taskId={}", taskId);
+
+            // 鍚屾椂閫氱煡鐩稿叧璁惧閫昏緫澶勭悊鍣ㄦ墽琛屽彇娑堟敹灏鹃�昏緫锛堜緥濡傚仠姝㈠ぇ杞﹀唴閮ㄧ殑鐩戞帶瀹氭椂鍣級
+            try {
+                Map<String, Object> cancelParams = new HashMap<>();
+                cancelParams.put("_taskContext", context);
+                Object devicesObj = context.getSharedData().get("devices");
+                if (devicesObj instanceof List) {
+                    @SuppressWarnings("unchecked")
+                    List<DeviceConfig> devices = (List<DeviceConfig>) devicesObj;
+                    for (DeviceConfig device : devices) {
+                        if (device == null) {
+                            continue;
+                        }
+                        try {
+                            DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
+                            if (handler != null) {
+                                // 鐩墠澶ц溅閫昏緫澶勭悊鍣ㄤ細鍦╮eset/clear绛夋搷浣滀腑鍋滄鍐呴儴鐩戞帶瀹氭椂鍣�
+                                // 杩欓噷缁熶竴璋冪敤涓�娆♀�渞eset鈥濅綔涓轰换鍔″彇娑堟椂鐨勬敹灏惧姩浣�
+                                handler.execute(device, "reset", cancelParams);
+                            }
+                        } catch (Exception e) {
+                            log.warn("浠诲姟鍙栨秷鏃舵墽琛岃澶囨敹灏�(reset)澶辫触: taskId={}, deviceId={}, error={}",
+                                    taskId, device.getId(), e.getMessage());
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                log.warn("浠诲姟鍙栨秷鏃舵墽琛岃澶囨敹灏鹃�昏緫寮傚父: taskId={}, error={}", taskId, e.getMessage());
+            }
         } else {
             log.warn("璇锋眰鍙栨秷浠诲姟浣嗘湭鎵惧埌涓婁笅鏂�: taskId={}", taskId);
         }
@@ -382,10 +407,13 @@
             ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
                 try {
                     if (isTaskCancelled(context)) {
-                        log.debug("浠诲姟宸插彇娑堬紝鍋滄鍗ц浆绔嬫壂鐮佸畾鏃跺櫒: taskId={}, deviceId={}", 
+                        log.debug("浠诲姟宸插彇娑堬紝鍋滄鍗ц浆绔嬫壂鐮佸畾鏃跺櫒: taskId={}, deviceId={}",
                                 task.getTaskId(), device.getId());
                         return;
                     }
+                    // 瀹氭椂鍣ㄧ涓�娆℃墽琛屾椂锛屽皢璁惧鐘舵�佷粠 WAITING 璁剧疆涓� RUNNING
+                    deviceCoordinationService.syncDeviceStatus(device,
+                            DeviceCoordinationService.DeviceStatus.RUNNING, context);
                     ensureStepRunning(step, task.getTaskId());
                     // 妫�鏌ユ槸鍚﹂渶瑕佹殏鍋�
                     if (shouldPauseScanner(context)) {
@@ -484,6 +512,8 @@
                 }
             }, 0, scanIntervalMs, TimeUnit.MILLISECONDS);
             
+            // 鍦ㄤ覆琛屾墽琛屾ā寮忎笅锛屾壂鐮佽澶囨槸绗竴涓紝搴旇绔嬪嵆璁剧疆涓� RUNNING
+            // 鍏朵粬璁惧淇濇寔 WAITING锛岀洿鍒板畠浠湡姝e紑濮嬪伐浣�
             deviceCoordinationService.syncDeviceStatus(device,
                     DeviceCoordinationService.DeviceStatus.RUNNING, context);
             return future;
@@ -509,6 +539,9 @@
                     task.getTaskId(), device.getId(), monitorIntervalMs);
             
             // 鍚姩瀹氭椂浠诲姟
+            // 浣跨敤AtomicBoolean鏍囪鏄惁绗竴娆℃墽琛�
+            final java.util.concurrent.atomic.AtomicBoolean firstExecution = new java.util.concurrent.atomic.AtomicBoolean(true);
+            
             ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
                 try {
                     if (isTaskCancelled(context)) {
@@ -516,7 +549,14 @@
                                 task.getTaskId(), device.getId());
                         return;
                     }
-                    ensureStepRunning(step, task.getTaskId());
+                    
+                    // 濡傛灉姝ラ宸茬粡瀹屾垚锛屼笉鍐嶆墽琛屽悗缁�昏緫锛堥伩鍏嶇姸鎬佽閲嶇疆锛�
+                    if (TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())) {
+                        log.debug("鍗ц浆绔嬭澶囨楠ゅ凡瀹屾垚锛屽仠姝㈠畾鏃跺櫒鎵ц: taskId={}, deviceId={}",
+                                task.getTaskId(), device.getId());
+                        return;
+                    }
+                    
                     // 鏋勫缓鍙傛暟
                     Map<String, Object> params = new HashMap<>();
                     params.put("_taskContext", context);
@@ -529,19 +569,61 @@
                     if (handler != null) {
                         DevicePlcVO.OperationResult result = handler.execute(device, "checkAndProcess", params);
                         
+                        // 妫�鏌ユ槸鍚︽湁鏁版嵁锛氬鏋滄湁鏁版嵁鎴栨鍦ㄥ鐞嗭紝璁剧疆涓篟UNNING锛涘鏋滅紦鍐查槦鍒椾负绌轰笖鏃犲緟澶勭悊鐜荤拑锛屼繚鎸丳ENDING
+                        String message = result.getMessage();
+                        boolean hasData = result.getSuccess() != null && result.getSuccess() 
+                                && message != null && !message.contains("缂撳啿闃熷垪涓虹┖锛屾棤寰呭鐞嗙幓鐠�");
+                        
+                        // 濡傛灉褰撳墠鏄疨ENDING鐘舵�侊紝涓旀娴嬪埌鏈夋暟鎹紝鍒欒缃负RUNNING锛堣澶囧紑濮嬪伐浣滐級
+                        boolean isPending = TaskStepDetail.Status.PENDING.name().equals(step.getStatus());
+                        
+                        if (hasData && isPending) {
+                            // 妫�娴嬪埌鏁版嵁涓斿綋鍓嶆槸绛夊緟鐘舵�侊紝璁惧寮�濮嬪伐浣滐紝璁剧疆涓篟UNNING
+                            deviceCoordinationService.syncDeviceStatus(device,
+                                    DeviceCoordinationService.DeviceStatus.RUNNING, context);
+                            step.setStatus(TaskStepDetail.Status.RUNNING.name());
+                            if (step.getStartTime() == null) {
+                                step.setStartTime(new Date());
+                            }
+                            taskStepDetailMapper.updateById(step);
+                            notificationService.notifyStepUpdate(task.getTaskId(), step);
+                            log.debug("鍗ц浆绔嬭澶囧畾鏃跺櫒妫�娴嬪埌鏁版嵁锛屼粠PENDING杞负RUNNING: taskId={}, deviceId={}, message={}",
+                                    task.getTaskId(), device.getId(), message);
+                        } else if (!hasData) {
+                            // 娌℃湁鏁版嵁锛屼繚鎸丳ENDING鐘舵�侊紝绛夊緟鎵爜璁惧杈撳嚭
+                            if (firstExecution.compareAndSet(true, false)) {
+                                // 绗竴娆℃墽琛岋紝纭繚鐘舵�佹槸PENDING
+                                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("鍗ц浆绔嬭澶囧畾鏃跺櫒绗竴娆℃墽琛岋紝鏃犳暟鎹紝淇濇寔PENDING: taskId={}, deviceId={}, message={}",
+                                        task.getTaskId(), device.getId(), message);
+                            }
+                            return; // 涓嶆墽琛屽悗缁�昏緫锛岀瓑寰呬笅涓�娆″畾鏃跺櫒瑙﹀彂
+                        }
+                        
                         // 鏇存柊姝ラ鐘舵�侊紙鍖哄垎绛夊緟涓拰鐪熸瀹屾垚锛�
-                        updateStepStatusForTransfer(step, result);
+                        updateStepStatusForTransfer(step, result, device, context);
                         // 閫氱煡姝ラ鏇存柊锛堣鍓嶇瀹炴椂鐪嬪埌姝ラ鐘舵�侊級
                         notificationService.notifyStepUpdate(task.getTaskId(), step);
                         boolean opSuccess = Boolean.TRUE.equals(result.getSuccess());
                         updateTaskProgress(task, step.getStepOrder(), opSuccess);
+                        
+                        // 鏍规嵁鎵ц缁撴灉鏇存柊璁惧鐘舵��
+                        // 娉ㄦ剰锛氳澶囧凡缁忓紑濮嬪伐浣滐紙瀹氭椂鍣ㄥ凡鎵ц锛夛紝鎵�浠ュ簲璇ヤ繚鎸丷UNNING鐘舵��
+                        // 鍙湁鍦ㄧ湡姝e畬鎴愭椂鎵嶈缃负COMPLETED
                         if (opSuccess) {
-                            String message = result.getMessage();
+                            // 璁惧姝e湪宸ヤ綔锛堢瓑寰呯紦鍐层�佸鐞嗕腑绛夛級锛屼繚鎸丷UNNING鐘舵��
+                            deviceCoordinationService.syncDeviceStatus(device,
+                                    DeviceCoordinationService.DeviceStatus.RUNNING, context);
                             if (message != null && message.contains("鎵规宸插啓鍏LC")) {
-                        log.debug("鍗ц浆绔嬭澶囧畾鏃跺櫒鎵ц鎴愬姛锛堝凡鍐欏叆PLC锛�: taskId={}, deviceId={}, message={}",
+                                log.debug("鍗ц浆绔嬭澶囧畾鏃跺櫒鎵ц鎴愬姛锛堝凡鍐欏叆PLC锛�: taskId={}, deviceId={}, message={}",
                                         task.getTaskId(), device.getId(), message);
                             } else {
-                        log.debug("鍗ц浆绔嬭澶囧畾鏃跺櫒绛夊緟涓�: taskId={}, deviceId={}, message={}",
+                                log.debug("鍗ц浆绔嬭澶囧畾鏃跺櫒宸ヤ綔涓紙绛夊緟缂撳啿锛�: taskId={}, deviceId={}, message={}",
                                         task.getTaskId(), device.getId(), message);
                             }
                         } else {
@@ -556,8 +638,9 @@
                 }
             }, 0, monitorIntervalMs, TimeUnit.MILLISECONDS);
             
+            // 鍦ㄤ覆琛屾墽琛屾ā寮忎笅锛岃澶囧惎鍔ㄥ畾鏃跺櫒鏃跺厛璁剧疆涓� WAITING锛屽畾鏃跺櫒绗竴娆℃墽琛屾椂鍐嶈缃负 RUNNING
             deviceCoordinationService.syncDeviceStatus(device,
-                    DeviceCoordinationService.DeviceStatus.RUNNING, context);
+                    DeviceCoordinationService.DeviceStatus.WAITING, context);
             return future;
         } catch (Exception e) {
             log.error("鍚姩鍗ц浆绔嬭澶囧畾鏃跺櫒澶辫触: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
@@ -587,17 +670,91 @@
                                 task.getTaskId(), device.getId());
                         return;
                     }
-                    ensureStepRunning(step, task.getTaskId());
-                    // 妫�鏌ユ槸鍚︽湁鍗ц浆绔嬩富浣撳凡杈撳嚭銆佸噯澶囦笂澶ц溅鐨勭幓鐠冧俊鎭�
-                    List<String> readyGlassIds = getTransferReadyGlassIds(context);
-                    if (CollectionUtils.isEmpty(readyGlassIds)) {
-                        // 娌℃湁鍗ц浆绔嬭緭鍑虹殑鐜荤拑锛岀户缁瓑寰�
+                    // 宸插畬鎴�/澶辫触鐨勬楠や笉鍐嶅洖閫�鐘舵��
+                    if (TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())
+                            || TaskStepDetail.Status.FAILED.name().equals(step.getStatus())) {
+                        return;
+                    }
+                    // 杩涚墖澶ц溅璁惧锛氬彧鏈夊湪鐪熸寮�濮嬪鐞嗘椂鎵嶈缃负RUNNING
+                    // 鍏堟鏌ュ崸杞珛璁惧鏄惁宸插畬鎴愶紝濡傛灉杩樺湪鎵ц涓紝涓嶅簲璇ュ紑濮嬪ぇ杞︾殑宸ヤ綔
+                    boolean transferCompleted = isTransferDeviceCompleted(task.getTaskId(), context);
+                    if (!transferCompleted) {
+                        // 鍗ц浆绔嬭繕鍦ㄦ墽琛屼腑锛岀瓑寰呭崸杞珛瀹屾垚
+                        if (!TaskStepDetail.Status.PENDING.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);
+                        }
+                        log.debug("鍗ц浆绔嬭繕鍦ㄦ墽琛屼腑锛岃繘鐗囧ぇ杞︾瓑寰�: taskId={}, deviceId={}", 
+                                task.getTaskId(), device.getId());
                         return;
                     }
                     
-                    // 濡傛灉鐜荤拑ID鏁伴噺娌℃湁鍙樺寲锛岃鏄庢病鏈夋柊鐨勭幓鐠冿紝缁х画绛夊緟
+                    // 妫�鏌ユ槸鍚︽湁鍗ц浆绔嬩富浣撳凡杈撳嚭銆佸噯澶囦笂澶ц溅鐨勭幓鐠冧俊鎭�
+                    List<String> readyGlassIds = getTransferReadyGlassIds(context);
+                    
+                    // 濡傛灉褰撳墠娌℃湁鏂扮殑鐜荤拑锛屼絾鍗ц浆绔嬪凡瀹屾垚锛屽彲浠ヨ疆璇ES浠诲姟/纭鐘舵��
+                    if (CollectionUtils.isEmpty(readyGlassIds)) {
+                        // 妫�鏌ユ槸鍚︽墍鏈夊垵濮嬬幓鐠冮兘宸茶杞�
+                        @SuppressWarnings("unchecked")
+                        List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
+                        List<String> loadedGlassIds = getLoadedGlassIds(context);
+                        
+                        if (initialGlassIds != null && !initialGlassIds.isEmpty()) {
+                            // 濡傛灉鎵�鏈夊垵濮嬬幓鐠冮兘宸茶杞斤紝璇存槑宸茬粡澶勭悊瀹岋紝涓嶅簲璇ュ啀鍙樺洖绛夊緟
+                            if (loadedGlassIds != null && !loadedGlassIds.isEmpty() 
+                                    && loadedGlassIds.containsAll(initialGlassIds)) {
+                                // 鎵�鏈夌幓鐠冮兘宸茶杞斤紝淇濇寔RUNNING鐘舵�侊紝缁х画杞MES浠诲姟/纭
+                                if (!TaskStepDetail.Status.RUNNING.name().equals(step.getStatus())) {
+                                    step.setStatus(TaskStepDetail.Status.RUNNING.name());
+                                    if (step.getStartTime() == null) {
+                                        step.setStartTime(new Date());
+                                    }
+                                    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())) {
+                                step.setStatus(TaskStepDetail.Status.PENDING.name());
+                                step.setSuccessMessage("绛夊緟鍗ц浆绔嬭緭鍑虹幓鐠�");
+                                if (step.getStartTime() == null) {
+                                    step.setStartTime(new Date());
+                                }
+                                taskStepDetailMapper.updateById(step);
+                                notificationService.notifyStepUpdate(task.getTaskId(), step);
+                            }
+                        }
+                        return;
+                    }
+                    
+                    // 濡傛灉鐜荤拑ID鏁伴噺娌℃湁鍙樺寲锛岃鏄庢病鏈夋柊鐨勭幓鐠�
                     int currentCount = readyGlassIds.size();
                     if (currentCount == lastProcessedCount.get()) {
+                        // 鐜荤拑鏁伴噺娌℃湁鍙樺寲锛氭病鏈夋柊鐜荤拑锛屼絾浠嶉渶杞MES浠诲姟/纭锛岄伩鍏嶉敊杩嘙ES渚х殑鍙樺寲
+                        pollMesForVehicle(task, step, device, context);
                         log.debug("澶ц溅璁惧瀹氭椂鍣細鐜荤拑ID鏁伴噺鏈彉鍖栵紝缁х画绛夊緟: taskId={}, deviceId={}, count={}",
                                 task.getTaskId(), device.getId(), currentCount);
                         return;
@@ -622,6 +779,18 @@
                         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());
+                                }
+                                taskStepDetailMapper.updateById(step);
+                                notificationService.notifyStepUpdate(task.getTaskId(), step);
+                            }
                             log.debug("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屾垚鍔�: taskId={}, deviceId={}, glassCount={}",
                                     task.getTaskId(), device.getId(), readyGlassIds.size());
                             // 灏嗗凡瑁呰浇鐨勭幓鐠僆D淇濆瓨鍒板叡浜暟鎹腑锛堜緵澶х悊鐗囩浣跨敤锛�
@@ -631,7 +800,29 @@
                             lastProcessedCount.set(0);
                             // 纭繚鍗ц浆绔嬫壂鐮佺户缁繍琛�
                             setScannerPause(context, false);
+                            
+                            // 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());
+                                }
+                            } catch (Exception e) {
+                                log.warn("杩涚墖澶ц溅璁惧妫�鏌ES浠诲姟寮傚父: taskId={}, deviceId={}, error={}",
+                                        task.getTaskId(), device.getId(), e.getMessage());
+                            }
                         } else {
+                            // 瑁呬笉涓嬶紝淇濇寔WAITING鐘舵�佸拰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.warn("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄥ閲忎笉瓒�: taskId={}, deviceId={}, message={}",
                                     task.getTaskId(), device.getId(), feedResult.getMessage());
@@ -639,17 +830,59 @@
                         }
                         
                         // 绗簩姝ワ細妫�鏌ES纭鐘舵�侊紙濡傛灉澶ц溅澶勭悊鍣ㄦ敮鎸佺殑璇濓級
+                        // 鍙湁鍦ㄤ换鍔″凡寮�濮嬫墽琛岋紙鏈変换鍔¤褰曪級鏃舵墠妫�鏌ES纭
                         DevicePlcVO.OperationResult mesResult = null;
                         try {
-                            mesResult = handler.execute(device, "checkMesConfirm", Collections.emptyMap());
+                            Map<String, Object> confirmParams = new HashMap<>();
+                            confirmParams.put("_taskContext", context);
+                            mesResult = handler.execute(device, "checkMesConfirm", confirmParams);
                         } catch (Exception e) {
                             log.warn("杩涚墖澶ц溅璁惧妫�鏌ES纭鐘舵�佸紓甯�: taskId={}, deviceId={}, error={}",
                                     task.getTaskId(), device.getId(), e.getMessage());
                         }
                         
+                        // 濡傛灉MES宸茬‘璁ゅ畬鎴愶紙mesConfirm=1锛夛紝妫�鏌ュ崸杞珛璁惧鐘舵�佸拰鐜荤拑淇℃伅
+                        // 濡傛灉鍗ц浆绔嬪凡瀹屾垚涓旀墍鏈夌幓鐠冮兘宸茶杞斤紝鍙互鏍囪涓哄畬鎴�
+                        if (mesResult != null && mesResult.getData() != null) {
+                            Object completedFlag = mesResult.getData().get("completed");
+                            boolean mesConfirmed = false;
+                            if (completedFlag instanceof Boolean) {
+                                mesConfirmed = (Boolean) completedFlag;
+                            } else if (completedFlag != null) {
+                                mesConfirmed = "true".equalsIgnoreCase(String.valueOf(completedFlag));
+                            }
+                            
+                            if (mesConfirmed) {
+                                // MES宸茬‘璁ゅ畬鎴愶紝妫�鏌ュ崸杞珛璁惧鏄惁宸插畬鎴�
+                                boolean transferCompletedForMes = isTransferDeviceCompleted(task.getTaskId(), context);
+                                if (transferCompletedForMes) {
+                                    // 妫�鏌ヤ换鍔′笂涓嬫枃涓殑鍒濆鐜荤拑ID鍜屽凡瑁呰浇鐨勭幓鐠僆D
+                                    @SuppressWarnings("unchecked")
+                                    List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
+                                    List<String> loadedGlassIds = getLoadedGlassIds(context);
+                                    
+                                    if (initialGlassIds != null && !initialGlassIds.isEmpty() 
+                                            && loadedGlassIds != null && !loadedGlassIds.isEmpty()) {
+                                        // 妫�鏌ユ槸鍚︽墍鏈夊垵濮嬬幓鐠冮兘宸茶杞�
+                                        boolean allGlassesLoaded = loadedGlassIds.containsAll(initialGlassIds);
+                                        if (allGlassesLoaded) {
+                                            // 鍗ц浆绔嬪凡瀹屾垚涓旀墍鏈夌幓鐠冮兘宸茶杞斤紝鏍囪涓哄畬鎴�
+                                            log.info("MES宸茬‘璁や笖鍗ц浆绔嬪凡瀹屾垚涓旀墍鏈夌幓鐠冨凡瑁呰浇锛屼换鍔¤嚜鍔ㄥ畬鎴�: taskId={}, deviceId={}, initialCount={}, loadedCount={}",
+                                                    task.getTaskId(), device.getId(), initialGlassIds.size(), loadedGlassIds.size());
+                                            // mesResult宸茬粡鍖呭惈completed=true锛屼笉闇�瑕佷慨鏀�
+                                        }
+                                    }
+                                } else {
+                                    // 鍗ц浆绔嬭繕鏈畬鎴愶紝涓嶅簲璇ユ爣璁颁负瀹屾垚
+                                    log.debug("MES宸茬‘璁や絾鍗ц浆绔嬫湭瀹屾垚锛岀瓑寰呭崸杞珛瀹屾垚: taskId={}, deviceId={}", 
+                                            task.getTaskId(), device.getId());
+                                }
+                            }
+                        }
+                        
                         // 鏇存柊姝ラ鐘舵�侊紙澶ц溅璁惧淇濇寔RUNNING锛岀洿鍒癕ES纭瀹屾垚鎴栦换鍔″彇娑堬級
                         if (mesResult != null) {
-                            updateStepStatusForVehicle(step, mesResult);
+                            updateStepStatusForVehicle(task.getTaskId(), step, mesResult);
                             boolean opSuccess = Boolean.TRUE.equals(mesResult.getSuccess());
                             updateTaskProgress(task, step.getStepOrder(), opSuccess);
                             if (!opSuccess) {
@@ -657,7 +890,7 @@
                                         DeviceCoordinationService.DeviceStatus.FAILED, context);
                             }
                         } else {
-                            updateStepStatusForVehicle(step, feedResult);
+                            updateStepStatusForVehicle(task.getTaskId(), step, feedResult);
                             boolean opSuccess = Boolean.TRUE.equals(feedResult.getSuccess());
                             updateTaskProgress(task, step.getStepOrder(), opSuccess);
                             if (!opSuccess) {
@@ -665,14 +898,20 @@
                                         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);
                 }
             }, 0, MONITOR_INTERVAL_MS, TimeUnit.MILLISECONDS);
             
+            // 鍦ㄤ覆琛屾墽琛屾ā寮忎笅锛岃澶囧惎鍔ㄥ畾鏃跺櫒鏃跺厛璁剧疆涓� WAITING锛屽畾鏃跺櫒绗竴娆℃墽琛屾椂鍐嶈缃负 RUNNING
             deviceCoordinationService.syncDeviceStatus(device,
-                    DeviceCoordinationService.DeviceStatus.RUNNING, context);
+                    DeviceCoordinationService.DeviceStatus.WAITING, context);
             return future;
         } catch (Exception e) {
             log.error("鍚姩杩涚墖澶ц溅璁惧瀹氭椂鍣ㄥけ璐�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
@@ -689,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)) {
@@ -701,78 +939,244 @@
                                 task.getTaskId(), device.getId());
                         return;
                     }
-                    ensureStepRunning(step, task.getTaskId());
-                    // 妫�鏌ユ槸鍚︽湁宸插鐞嗙殑鐜荤拑淇℃伅锛堜粠澶х悊鐗囩鏉ョ殑锛�
-                    List<String> processedGlassIds = getProcessedGlassIds(context);
-                    if (CollectionUtils.isEmpty(processedGlassIds)) {
-                        log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣細鏆傛棤宸插鐞嗙殑鐜荤拑淇℃伅: taskId={}, deviceId={}",
-                                task.getTaskId(), device.getId());
+
+                    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);
+                        }
                         return;
                     }
-                    
-                    log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ娴嬪埌宸插鐞嗙殑鐜荤拑淇℃伅: taskId={}, deviceId={}, glassCount={}",
-                            task.getTaskId(), device.getId(), processedGlassIds.size());
-                    
-                    // 鎵ц鍑虹墖鎿嶄綔
-                    Map<String, Object> checkParams = new HashMap<>();
-                    checkParams.put("glassIds", new ArrayList<>(processedGlassIds));
-                    checkParams.put("_taskContext", context);
-                    
+
+                    // 2) 宸插畬鎴愮疮绉細outboundGlassIds锛堜换鍔′晶缁存姢锛屾寜mesConfirm=1绱姞锛�
+                    Set<String> processedSet = new LinkedHashSet<>();
+                    for (String id : processedGlassIdsRaw) {
+                        if (StringUtils.hasText(id)) {
+                            processedSet.add(id);
+                        }
+                    }
+                    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;
+                    }
+
+                    // 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);
+                    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));
+                                    }
+                                }
+                                if (!batchIds.isEmpty()) {
+                                    context.getSharedData().put("currentMesBatchGlassIds", batchIds);
+                                }
+                            }
                         }
-                        // 绗竴姝ワ細鍐欏叆澶ц溅鍑虹墖璇锋眰
-                        DevicePlcVO.OperationResult feedResult = handler.execute(device, "feedGlass", checkParams);
-                        
-                        if (Boolean.TRUE.equals(feedResult.getSuccess())) {
-                            log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屾垚鍔�: taskId={}, deviceId={}, glassCount={}",
-                                    task.getTaskId(), device.getId(), processedGlassIds.size());
-                            // 娓呯┖宸插鐞嗙殑鐜荤拑ID鍒楄〃锛堝凡澶勭悊锛�
-                            clearProcessedGlassIds(context);
-                        } else {
-                            log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屽け璐�: taskId={}, deviceId={}, message={}",
-                                    task.getTaskId(), device.getId(), feedResult.getMessage());
+                    } 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;
                         }
-                        
-                        // 绗簩姝ワ細妫�鏌ES纭鐘舵�侊紙濡傛灉澶ц溅澶勭悊鍣ㄦ敮鎸佺殑璇濓級
-                        DevicePlcVO.OperationResult mesResult = null;
+                    } 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 {
-                            mesResult = handler.execute(device, "checkMesConfirm", Collections.emptyMap());
+                            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());
                         }
-                        
-                        // 鏇存柊姝ラ鐘舵�侊紙澶ц溅璁惧淇濇寔RUNNING锛岀洿鍒癕ES纭瀹屾垚鎴栦换鍔″彇娑堬級
-                        if (mesResult != null) {
-                            updateStepStatusForVehicle(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(step, feedResult);
-                            boolean opSuccess = Boolean.TRUE.equals(feedResult.getSuccess());
-                            updateTaskProgress(task, step.getStepOrder(), opSuccess);
-                            if (!opSuccess) {
-                                deviceCoordinationService.syncDeviceStatus(device,
-                                        DeviceCoordinationService.DeviceStatus.FAILED, context);
-                            }
+                    }
+
+                    // 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);
+                        }
+                        // 娓呯┖鏈壒娆¤褰曪紝閬垮厤涓嬩竴娆¤疆璇㈤噸澶嶄娇鐢ㄦ棫鎵规
+                        context.getSharedData().put("currentMesBatchGlassIds", new ArrayList<>());
                     }
                 } catch (Exception e) {
                     log.error("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屽紓甯�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
                 }
             }, 0, MONITOR_INTERVAL_MS, TimeUnit.MILLISECONDS);
-            
+
+            // 鍚姩鏃朵繚鎸乄AITING锛屽悗缁敱瀹氭椂鍣ㄩ�昏緫鍒囨崲涓篟UNNING/COMPLETED
             deviceCoordinationService.syncDeviceStatus(device,
-                    DeviceCoordinationService.DeviceStatus.RUNNING, context);
+                    DeviceCoordinationService.DeviceStatus.WAITING, context);
             return future;
         } catch (Exception e) {
             log.error("鍚姩鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄥけ璐�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
@@ -804,20 +1208,86 @@
                                 task.getTaskId(), device.getId());
                         return;
                     }
-                    ensureStepRunning(step, task.getTaskId());
+                    // 濡傛灉姝ラ宸茬粡瀹屾垚锛屼笉鍐嶅鐞�
+                    if (TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())) {
+                        // 妫�鏌ユ槸鍚︽墍鏈夊垵濮嬬幓鐠冮兘宸插鐞嗗畬
+                        @SuppressWarnings("unchecked")
+                        List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
+                        List<String> processedGlassIds = getProcessedGlassIds(context);
+                        
+                        if (initialGlassIds != null && !initialGlassIds.isEmpty() 
+                                && processedGlassIds != null && !processedGlassIds.isEmpty()
+                                && processedGlassIds.containsAll(initialGlassIds)) {
+                            // 鎵�鏈夌幓鐠冮兘宸插鐞嗗畬锛屼繚鎸佸畬鎴愮姸鎬�
+                            log.debug("澶х悊鐗囩璁惧宸插畬鎴愪笖鎵�鏈夌幓鐠冨凡澶勭悊: taskId={}, deviceId={}, initialCount={}, processedCount={}",
+                                    task.getTaskId(), device.getId(), initialGlassIds.size(), processedGlassIds.size());
+                            return;
+                        }
+                    }
+                    
+                    // 澶х悊鐗囩璁惧锛氬彧鏈夊湪鐪熸寮�濮嬪鐞嗘椂鎵嶈缃负RUNNING
                     // 妫�鏌ユ槸鍚︽湁宸茶杞界殑鐜荤拑淇℃伅锛堜粠杩涚墖澶ц溅鏉ョ殑锛�
                     List<String> loadedGlassIds = getLoadedGlassIds(context);
                     if (CollectionUtils.isEmpty(loadedGlassIds)) {
+                        // 娌℃湁鏁版嵁锛屾鏌ユ槸鍚︽墍鏈夌幓鐠冮兘宸插鐞嗗畬
+                        @SuppressWarnings("unchecked")
+                        List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
+                        List<String> processedGlassIds = getProcessedGlassIds(context);
+                        
+                        if (initialGlassIds != null && !initialGlassIds.isEmpty() 
+                                && processedGlassIds != null && !processedGlassIds.isEmpty()
+                                && processedGlassIds.containsAll(initialGlassIds)) {
+                            // 鎵�鏈夌幓鐠冮兘宸插鐞嗗畬锛屾爣璁颁负瀹屾垚
+                            if (!TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())) {
+                                step.setStatus(TaskStepDetail.Status.COMPLETED.name());
+                                step.setSuccessMessage("鎵�鏈夌幓鐠冨凡澶勭悊瀹屾垚");
+                                if (step.getEndTime() == null) {
+                                    step.setEndTime(new Date());
+                                }
+                                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());
+                            }
+                            return;
+                        }
+                        
+                        // 娌℃湁鏁版嵁涓旀湭瀹屾垚锛屼繚鎸乄AITING鐘舵�佸拰PENDING姝ラ鐘舵��
+                        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("绛夊緟杩涚墖澶ц溅瑁呰浇鐜荤拑");
+                            taskStepDetailMapper.updateById(step);
+                            notificationService.notifyStepUpdate(task.getTaskId(), step);
+                        }
                         log.debug("澶х悊鐗囩璁惧瀹氭椂鍣細鏆傛棤宸茶杞界殑鐜荤拑淇℃伅: taskId={}, deviceId={}",
                                 task.getTaskId(), device.getId());
                         return;
                     }
                     
+                    // 鏈夋暟鎹紝璁剧疆涓篟UNNING
+                    deviceCoordinationService.syncDeviceStatus(device,
+                            DeviceCoordinationService.DeviceStatus.RUNNING, context);
+                    
                     // 妫�鏌ョ幓鐠冩槸鍚﹀凡缁忓鐞嗗畬鎴愶紙閫氳繃澶勭悊鏃堕棿鍒ゆ柇锛�
                     Long processStartTime = getProcessStartTime(context);
                     if (processStartTime == null) {
                         // 绗竴娆℃娴嬪埌鐜荤拑锛岃褰曞紑濮嬪鐞嗘椂闂�
-                        setProcessStartTime(context, System.currentTimeMillis());
+                        long now = System.currentTimeMillis();
+                        setProcessStartTime(context, now);
+                        // 琛ラ綈姝ラ鐨勫紑濮嬫椂闂翠笌鐘舵�侊紝纭繚鍓嶇鑰楁椂姝e父鏄剧ず
+                        if (!TaskStepDetail.Status.RUNNING.name().equals(step.getStatus())) {
+                            step.setStatus(TaskStepDetail.Status.RUNNING.name());
+                        }
+                        if (step.getStartTime() == null) {
+                            step.setStartTime(new Date(now));
+                        }
+                        taskStepDetailMapper.updateById(step);
+                        notificationService.notifyStepUpdate(task.getTaskId(), step);
                         log.debug("澶х悊鐗囩璁惧寮�濮嬪鐞�: taskId={}, deviceId={}, glassCount={}, processTime={}s",
                                 task.getTaskId(), device.getId(), loadedGlassIds.size(), processTimeSeconds);
                         return;
@@ -843,8 +1313,21 @@
                     // 鏇存柊姝ラ鐘舵��
                     step.setStatus(TaskStepDetail.Status.COMPLETED.name());
                     step.setErrorMessage(null);
+                    // 璁板綍缁撴潫鏃堕棿涓庤�楁椂
+                    if (step.getEndTime() == null) {
+                        step.setEndTime(new Date());
+                    }
+                    if (step.getStartTime() == null) {
+                        // 濡傛灉寮�濮嬫椂闂寸己澶憋紝鐢ㄥ鐞嗗紑濮嬫椂闂存垨缁撴潫鏃堕棿鍏滃簳
+                        step.setStartTime(new Date(processStartTime));
+                    }
+                    if (step.getStartTime() != null && step.getEndTime() != null) {
+                        step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
+                    }
                     step.setOutputData(toJson(Collections.singletonMap("glassIds", loadedGlassIds)));
                     taskStepDetailMapper.updateById(step);
+                    // 閫氱煡鍓嶇鐘舵�佹洿鏂�
+                    notificationService.notifyStepUpdate(task.getTaskId(), step);
                     // 澶х悊鐗囩瀹屾垚鍚庡皾璇曡嚜鍔ㄦ敹灏炬暣涓换鍔�
                     checkAndCompleteTaskIfDone(step.getTaskId());
                     
@@ -853,6 +1336,9 @@
                 }
             }, 0, 1_000, TimeUnit.MILLISECONDS); // 姣忕妫�鏌ヤ竴娆�
             
+            // 鍦ㄤ覆琛屾墽琛屾ā寮忎笅锛岃澶囧惎鍔ㄥ畾鏃跺櫒鏃跺厛璁剧疆涓� WAITING锛屽畾鏃跺櫒绗竴娆℃墽琛屾椂鍐嶈缃负 RUNNING
+            deviceCoordinationService.syncDeviceStatus(device,
+                    DeviceCoordinationService.DeviceStatus.WAITING, context);
             return future;
         } catch (Exception e) {
             log.error("鍚姩澶х悊鐗囩璁惧瀹氭椂鍣ㄥけ璐�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
@@ -896,10 +1382,16 @@
     
     /**
      * 璁剧疆宸茶杞界殑鐜荤拑ID鍒楄〃
+     * 瀵逛簬鍒嗘壒鍑虹墖鍦烘櫙锛屾瘡娆¤缃簲鏇挎崲涓哄綋鍓嶆壒娆$殑鐜荤拑ID
      */
     private void setLoadedGlassIds(TaskExecutionContext context, List<String> glassIds) {
         if (context != null) {
-            context.getSharedData().put("loadedGlassIds", new ArrayList<>(glassIds));
+            // 鏇挎崲涓哄綋鍓嶆壒娆$殑鐜荤拑ID
+            List<String> currentBatch = new ArrayList<>();
+            if (glassIds != null) {
+                currentBatch.addAll(glassIds);
+            }
+            context.getSharedData().put("loadedGlassIds", currentBatch);
         }
     }
     
@@ -942,6 +1434,33 @@
     private void clearProcessedGlassIds(TaskExecutionContext context) {
         if (context != null) {
             context.getSharedData().put("processedGlassIds", new ArrayList<>());
+        }
+    }
+    
+    /**
+     * 鑾峰彇宸插嚭鐗囩殑鐜荤拑ID鍒楄〃
+     */
+    @SuppressWarnings("unchecked")
+    private List<String> getOutboundGlassIds(TaskExecutionContext context) {
+        if (context == null) {
+            return Collections.emptyList();
+        }
+        Object glassIds = context.getSharedData().get("outboundGlassIds");
+        if (glassIds instanceof List) {
+            return new ArrayList<>((List<String>) glassIds);
+        }
+        return Collections.emptyList();
+    }
+    
+    /**
+     * 娣诲姞宸插嚭鐗囩殑鐜荤拑ID鍒楄〃
+     */
+    private void addOutboundGlassIds(TaskExecutionContext context, List<String> glassIds) {
+        if (context != null && glassIds != null && !glassIds.isEmpty()) {
+            List<String> existing = getOutboundGlassIds(context);
+            Set<String> allOutbound = new HashSet<>(existing);
+            allOutbound.addAll(glassIds);
+            context.getSharedData().put("outboundGlassIds", new ArrayList<>(allOutbound));
         }
     }
     
@@ -1151,6 +1670,8 @@
             
             // 鎵�鏈夋楠ら兘宸插畬鎴愶紝鏀跺熬浠诲姟
             task.setStatus(MultiDeviceTask.Status.COMPLETED.name());
+            // 鍏抽敭锛氬悓姝ヨ繘搴﹀埌鏈�缁堝�硷紝閬垮厤鍓嶇浠嶆樉绀衡��3/5鈥濊繖绫绘棫杩涘害
+            task.setCurrentStep(totalSteps);
             task.setEndTime(new Date());
             multiDeviceTaskMapper.updateById(task);
             
@@ -1196,6 +1717,9 @@
         }
         step.setOutputData(toJson(result));
         taskStepDetailMapper.updateById(step);
+        if (StringUtils.hasText(step.getTaskId())) {
+            notificationService.notifyStepUpdate(step.getTaskId(), step);
+        }
     }
     
     /**
@@ -1266,8 +1790,14 @@
     /**
      * 鏇存柊澶ц溅璁惧姝ラ鐘舵�侊紙淇濇寔RUNNING锛岀洿鍒版墜鍔ㄥ仠姝㈡垨浠诲姟鍙栨秷锛涘け璐ユ椂鏍囪涓篎AILED锛�
      */
-    private void updateStepStatusForVehicle(TaskStepDetail step, DevicePlcVO.OperationResult result) {
+    private void updateStepStatusForVehicle(String taskId, TaskStepDetail step, DevicePlcVO.OperationResult result) {
         if (step == null || result == null) {
+            return;
+        }
+        // 濡傛灉姝ラ宸茬粡澶勪簬瀹屾垚鎴栧け璐ョ姸鎬侊紝鍒欎笉鍐嶈閲嶅鏇存柊锛堥槻姝㈢姸鎬佸弽澶嶅垏鎹級
+        if (TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())
+                || TaskStepDetail.Status.FAILED.name().equals(step.getStatus())) {
+            log.debug("姝ラ宸插畬鎴愭垨澶辫触锛屼笉鍐嶆洿鏂扮姸鎬�: stepId={}, status={}", step.getId(), step.getStatus());
             return;
         }
         boolean success = Boolean.TRUE.equals(result.getSuccess());
@@ -1287,11 +1817,37 @@
             step.setStartTime(now);
         }
 
+        boolean waiting = false;
+        String waitingReason = null;
+        if (result.getData() != null) {
+            Object waitingFlag = result.getData().get("waiting");
+            if (waitingFlag instanceof Boolean) {
+                waiting = (Boolean) waitingFlag;
+            } else if (waitingFlag != null) {
+                waiting = "true".equalsIgnoreCase(String.valueOf(waitingFlag));
+            }
+            Object reason = result.getData().get("waitingReason");
+            if (reason != null) {
+                waitingReason = String.valueOf(reason);
+            }
+        }
+        
         if (success && !completed) {
-            // 鎴愬姛浣嗘湭瀹屾垚锛氫繚鎸丷UNNING鐘舵�侊紝浠呮洿鏂版彁绀轰俊鎭拰鑰楁椂
-            step.setStatus(TaskStepDetail.Status.RUNNING.name());
+            // 鎴愬姛浣嗘湭瀹屾垚锛氭牴鎹畐aiting鐘舵�佸喅瀹氭樉绀轰负绛夊緟杩樻槸鎵ц涓�
+            // 娉ㄦ剰锛氬鏋滄楠ゅ凡缁忔槸RUNNING鐘舵�侊紙璇存槑宸茬粡瑁呰浇杩囩幓鐠冿級锛屼笉搴旇鏀瑰洖PENDING
+            boolean isAlreadyRunning = TaskStepDetail.Status.RUNNING.name().equals(step.getStatus());
+            if (waiting && !isAlreadyRunning) {
+                // 鍙湁鍦ㄨ繕娌℃湁寮�濮嬭繍琛屾椂锛屾墠璁剧疆涓篜ENDING
+                step.setStatus(TaskStepDetail.Status.PENDING.name());
+            } else {
+                // 濡傛灉宸茬粡杩愯杩囷紝鎴栬�呬笉鏄瓑寰呯姸鎬侊紝淇濇寔鎴栬缃负RUNNING
+                step.setStatus(TaskStepDetail.Status.RUNNING.name());
+            }
             String message = result.getMessage();
-            step.setSuccessMessage(StringUtils.hasText(message) ? message : "澶ц溅璁惧杩愯涓�");
+            if (!StringUtils.hasText(message) && waiting) {
+                message = "澶ц溅璁惧绛夊緟涓�" + (StringUtils.hasText(waitingReason) ? "锛�" + waitingReason + "锛�" : "");
+            }
+            step.setSuccessMessage(StringUtils.hasText(message) ? message : (waiting && !isAlreadyRunning ? "澶ц溅璁惧绛夊緟涓�" : "澶ц溅璁惧杩愯涓�"));
             step.setErrorMessage(null);
             if (step.getStartTime() != null) {
                 step.setDurationMs(now.getTime() - step.getStartTime().getTime());
@@ -1325,12 +1881,112 @@
 
         step.setOutputData(toJson(result));
         taskStepDetailMapper.updateById(step);
+        // 閫氱煡鍓嶇姝ラ鐘舵�佸凡鏇存柊
+        notificationService.notifyStepUpdate(taskId, step);
+    }
+
+    /**
+     * 杞澶ц溅璁惧鐨凪ES浠诲姟鍜岀‘璁ょ姸鎬�
+     * 鏃犺姝ラ褰撳墠鏄惁涓篟UNNING/PENDING锛岄兘鍙互璋冪敤锛岀敤浜庨伩鍏嶉敊杩嘙ES绔悗鍐欏叆鐨勪换鍔�
+     */
+    private void pollMesForVehicle(MultiDeviceTask task,
+                                   TaskStepDetail step,
+                                   DeviceConfig device,
+                                   TaskExecutionContext context) {
+        try {
+            DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
+            if (handler == null) {
+                return;
+            }
+
+            Map<String, Object> logicParams = parseLogicParams(device);
+
+            // 鍏堟鏌ES浠诲姟锛堝鏋渕esSend=1锛屼細鍒涘缓浠诲姟骞跺紑濮嬫墽琛岋級
+            DevicePlcVO.OperationResult mesTaskResult = null;
+            try {
+                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());
+                }
+            } 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());
+            }
+
+            // 濡傛灉MES宸茬‘璁ゅ畬鎴愶紙mesConfirm=1锛夛紝妫�鏌ュ崸杞珛璁惧鐘舵�佸拰鐜荤拑淇℃伅
+            // 濡傛灉鍗ц浆绔嬪凡瀹屾垚涓旀墍鏈夌幓鐠冮兘宸茶杞斤紝鍙互鏍囪涓哄畬鎴�
+            if (mesResult != null && mesResult.getData() != null) {
+                Object completedFlag = mesResult.getData().get("completed");
+                boolean mesConfirmed = false;
+                if (completedFlag instanceof Boolean) {
+                    mesConfirmed = (Boolean) completedFlag;
+                } else if (completedFlag != null) {
+                    mesConfirmed = "true".equalsIgnoreCase(String.valueOf(completedFlag));
+                }
+                
+                if (mesConfirmed) {
+                    // MES宸茬‘璁ゅ畬鎴愶紝妫�鏌ュ崸杞珛璁惧鏄惁宸插畬鎴�
+                    boolean transferCompleted = isTransferDeviceCompleted(task.getTaskId(), context);
+                    if (transferCompleted) {
+                        // 妫�鏌ヤ换鍔′笂涓嬫枃涓殑鍒濆鐜荤拑ID鍜屽凡瑁呰浇鐨勭幓鐠僆D
+                        @SuppressWarnings("unchecked")
+                        List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
+                        List<String> loadedGlassIds = getLoadedGlassIds(context);
+                        
+                        if (initialGlassIds != null && !initialGlassIds.isEmpty() 
+                                && loadedGlassIds != null && !loadedGlassIds.isEmpty()) {
+                            // 妫�鏌ユ槸鍚︽墍鏈夊垵濮嬬幓鐠冮兘宸茶杞�
+                            boolean allGlassesLoaded = loadedGlassIds.containsAll(initialGlassIds);
+                            if (allGlassesLoaded) {
+                                // 鍗ц浆绔嬪凡瀹屾垚涓旀墍鏈夌幓鐠冮兘宸茶杞斤紝鏍囪涓哄畬鎴�
+                                log.info("MES宸茬‘璁や笖鍗ц浆绔嬪凡瀹屾垚涓旀墍鏈夌幓鐠冨凡瑁呰浇锛屼换鍔¤嚜鍔ㄥ畬鎴�: taskId={}, deviceId={}, initialCount={}, loadedCount={}",
+                                        task.getTaskId(), device.getId(), initialGlassIds.size(), loadedGlassIds.size());
+                                // mesResult宸茬粡鍖呭惈completed=true锛屼笉闇�瑕佷慨鏀�
+                            }
+                        }
+                    } else {
+                        // 鍗ц浆绔嬭繕鏈畬鎴愶紝涓嶅簲璇ユ爣璁颁负瀹屾垚
+                        log.debug("MES宸茬‘璁や絾鍗ц浆绔嬫湭瀹屾垚锛岀瓑寰呭崸杞珛瀹屾垚: taskId={}, deviceId={}", 
+                                task.getTaskId(), device.getId());
+                    }
+                }
+            }
+
+            // 鏇存柊姝ラ鐘舵��
+            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);
+                }
+            }
+        } catch (Exception e) {
+            log.warn("杞澶ц溅璁惧MES浠诲姟/纭鐘舵�佸紓甯�: taskId={}, deviceId={}, error={}",
+                    task.getTaskId(), device.getId(), e.getMessage());
+        }
     }
     
     /**
      * 鏇存柊鍗ц浆绔嬭澶囨楠ょ姸鎬侊紙鍖哄垎绛夊緟涓拰鐪熸瀹屾垚锛�
      */
-    private void updateStepStatusForTransfer(TaskStepDetail step, DevicePlcVO.OperationResult result) {
+    private void updateStepStatusForTransfer(TaskStepDetail step, DevicePlcVO.OperationResult result, 
+                                            DeviceConfig device, TaskExecutionContext context) {
         if (step == null || result == null) {
             return;
         }
@@ -1338,26 +1994,36 @@
         String message = result.getMessage();
         
         // 鍒ゆ柇鏄惁鐪熸瀹屾垚锛�
-        // 1. 鍐欏叆PLC鎴愬姛
-        // 2. 涓旂紦鍐插凡娓呯┖锛堣〃绀烘墍鏈夌幓鐠冨凡澶勭悊瀹岋紝鏃犳柊鐜荤拑锛�
-        boolean isRealCompleted = success && message != null 
-                && message.contains("鎵规宸插啓鍏LC") 
-                && message.contains("缂撳啿宸叉竻绌猴紝浠诲姟瀹屾垚");
+        // 1. 鍐欏叆PLC鎴愬姛涓旂紦鍐插凡娓呯┖锛堣〃绀烘墍鏈夌幓鐠冨凡澶勭悊瀹岋紝鏃犳柊鐜荤拑锛�
+        // 娉ㄦ剰锛氱紦鍐查槦鍒椾负绌轰笖鏃犲緟澶勭悊鐜荤拑锛屽湪浠诲姟鍒氬紑濮嬫椂涔熷彲鑳藉嚭鐜帮紝涓嶅簲璇ョ珛鍗虫爣璁颁负瀹屾垚
+        // 鍙湁褰撲换鍔″凡缁忚繍琛屼竴娈垫椂闂达紝涓旂‘瀹炴病鏈夌幓鐠冮渶瑕佸鐞嗘椂锛屾墠鏍囪涓哄畬鎴�
+        boolean isRealCompleted = success && message != null && (
+                (message.contains("鎵规宸插啓鍏LC") && message.contains("缂撳啿宸叉竻绌猴紝浠诲姟瀹屾垚"))
+        );
         
         if (isRealCompleted) {
             // 鐪熸瀹屾垚锛氳缃负瀹屾垚鐘舵�侊紝骞惰缃粨鏉熸椂闂�
-            step.setStatus(TaskStepDetail.Status.COMPLETED.name());
-            step.setSuccessMessage(message);
-            if (step.getEndTime() == null) {
-                step.setEndTime(new Date());
+            // 娉ㄦ剰锛氫竴鏃︽爣璁颁负瀹屾垚锛岀姸鎬佷笉搴旇鍐嶈鏀瑰彉
+            if (!TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus())) {
+                step.setStatus(TaskStepDetail.Status.COMPLETED.name());
+                step.setSuccessMessage(message);
+                if (step.getEndTime() == null) {
+                    step.setEndTime(new Date());
+                }
+                // 璁$畻鑰楁椂
+                if (step.getStartTime() != null && step.getEndTime() != null) {
+                    step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
+                }
+                log.info("鍗ц浆绔嬭澶囨楠ゅ凡瀹屾垚: stepId={}, durationMs={}, message={}", 
+                        step.getId(), step.getDurationMs(), message);
+                // 鍗ц浆绔嬩富浣撳畬鎴愬悗灏濊瘯鑷姩鏀跺熬鏁翠釜浠诲姟
+                checkAndCompleteTaskIfDone(step.getTaskId());
+                // 鏇存柊璁惧鐘舵�佷负宸插畬鎴�
+                if (device != null) {
+                    deviceCoordinationService.syncDeviceStatus(device, 
+                            DeviceCoordinationService.DeviceStatus.COMPLETED, context);
+                }
             }
-            // 璁$畻鑰楁椂
-            if (step.getStartTime() != null && step.getEndTime() != null) {
-                step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
-            }
-            log.debug("鍗ц浆绔嬭澶囨楠ゅ凡瀹屾垚: stepId={}, durationMs={}", step.getId(), step.getDurationMs());
-            // 鍗ц浆绔嬩富浣撳畬鎴愬悗灏濊瘯鑷姩鏀跺熬鏁翠釜浠诲姟
-            checkAndCompleteTaskIfDone(step.getTaskId());
         } else if (success && message != null && message.contains("鎵规宸插啓鍏LC")) {
             // 鍐欏叆PLC鎴愬姛浣嗙紦鍐茶繕鏈夌幓鐠冿紙杞︽弧鎯呭喌锛夛紝缁х画杩愯
             if (!TaskStepDetail.Status.RUNNING.name().equals(step.getStatus())) {
@@ -1369,12 +2035,13 @@
                 step.setStartTime(new Date());
             }
         } else if (success) {
-            // 绛夊緟涓細淇濇寔杩愯鐘舵�侊紝鍙洿鏂版秷鎭�
+            // 璁惧姝e湪宸ヤ綔锛堢瓑寰呯紦鍐层�佺瓑寰呮洿澶氱幓鐠冪瓑锛夛紝淇濇寔RUNNING鐘舵��
+            // 鍥犱负瀹氭椂鍣ㄥ凡缁忔墽琛岋紝璇存槑璁惧宸茬粡寮�濮嬪伐浣滀簡
             if (!TaskStepDetail.Status.RUNNING.name().equals(step.getStatus())) {
                 step.setStatus(TaskStepDetail.Status.RUNNING.name());
             }
             step.setSuccessMessage(message);
-            // 纭繚寮�濮嬫椂闂村凡璁剧疆
+            // 纭繚寮�濮嬫椂闂村凡璁剧疆锛堣澶囧凡缁忓紑濮嬪伐浣滐級
             if (step.getStartTime() == null) {
                 step.setStartTime(new Date());
             }
@@ -2125,6 +2792,140 @@
         }
     }
 
+    /**
+     * 褰撹繘鐗囧ぇ杞︽楠ゅ畬鎴愬悗锛屽鏋滃瓨鍦ㄥぇ鐞嗙墖绗艰澶囦笖灏氭湭鍚姩鍏跺畾鏃跺櫒锛屽垯鍚姩澶х悊鐗囩瀹氭椂鍣�
+     * 淇濊瘉鎵ц椤哄簭涓猴細杩涚墖澶ц溅 -> 澶х悊鐗囩
+     */
+    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锛夛紝涓嶅簲璇ユ爣璁板ぇ杞︿负瀹屾垚
+     */
+    private boolean isTransferDeviceCompleted(String taskId, TaskExecutionContext context) {
+        if (taskId == null || context == null) {
+            return false;
+        }
+        try {
+            // 浠庝笂涓嬫枃涓幏鍙栬澶囧垪琛�
+            @SuppressWarnings("unchecked")
+            List<DeviceConfig> devices = (List<DeviceConfig>) context.getSharedData().get("devices");
+            if (devices == null || devices.isEmpty()) {
+                return false;
+            }
+            
+            // 鏌ユ壘鍗ц浆绔嬭澶�
+            DeviceConfig transferDevice = null;
+            for (DeviceConfig device : devices) {
+                if (DeviceConfig.DeviceType.WORKSTATION_TRANSFER.equals(device.getDeviceType())) {
+                    transferDevice = device;
+                    break;
+                }
+            }
+            
+            if (transferDevice == null) {
+                // 娌℃湁鍗ц浆绔嬭澶囷紝杩斿洖true锛堜笉褰卞搷鍒ゆ柇锛�
+                return true;
+            }
+            
+            // 鏌ユ壘鍗ц浆绔嬭澶囩殑姝ラ锛堝簲璇ュ彧鏈変竴涓楠わ級
+            List<TaskStepDetail> transferSteps = taskStepDetailMapper.selectList(
+                Wrappers.<TaskStepDetail>lambdaQuery()
+                    .eq(TaskStepDetail::getTaskId, taskId)
+                    .eq(TaskStepDetail::getDeviceId, transferDevice.getId())
+                    .orderByDesc(TaskStepDetail::getStepOrder)
+                    .last("LIMIT 1")
+            );
+            
+            if (transferSteps == null || transferSteps.isEmpty()) {
+                // 娌℃湁鎵惧埌姝ラ锛岃繑鍥瀎alse锛堝崸杞珛鍙兘杩樻病寮�濮嬶級
+                return false;
+            }
+            
+            // 妫�鏌ユ楠ょ姸鎬侊細鍙湁COMPLETED鎵嶇畻瀹屾垚锛孯UNNING鎴朠ENDING閮戒笉绠楀畬鎴�
+            TaskStepDetail transferStep = transferSteps.get(0);
+            String status = transferStep.getStatus();
+            boolean isCompleted = TaskStepDetail.Status.COMPLETED.name().equals(status);
+            
+            log.debug("妫�鏌ュ崸杞珛璁惧鐘舵��: taskId={}, deviceId={}, status={}, isCompleted={}", 
+                    taskId, transferDevice.getId(), status, isCompleted);
+            
+            return isCompleted;
+        } catch (Exception e) {
+            log.warn("妫�鏌ュ崸杞珛璁惧鐘舵�佸け璐�: taskId={}", taskId, e);
+            return false;
+        }
+    }
+
     private String determineOperation(DeviceConfig device, Map<String, Object> params) {
         if (params != null && params.containsKey("operation")) {
             Object op = params.get("operation");

--
Gitblit v1.8.0