From dad0263459b30dbfa75f06dff062a0c85183517b Mon Sep 17 00:00:00 2001
From: huang <1532065656@qq.com>
Date: 星期一, 01 十二月 2025 17:01:51 +0800
Subject: [PATCH] 添加卧转立扫码设备交互逻辑,任务流转

---
 mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java | 1234 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 1,195 insertions(+), 39 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 2919b0f..986a06b 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
@@ -7,14 +7,16 @@
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.mes.device.entity.DeviceConfig;
 import com.mes.device.entity.DeviceGroupConfig;
+import com.mes.device.service.DeviceCoordinationService;
+import com.mes.device.service.DeviceInteractionService;
+import com.mes.device.service.GlassInfoService;
+import com.mes.device.vo.DevicePlcVO;
 import com.mes.interaction.DeviceInteraction;
 import com.mes.interaction.DeviceInteractionRegistry;
 import com.mes.interaction.DeviceLogicHandler;
 import com.mes.interaction.DeviceLogicHandlerFactory;
 import com.mes.interaction.base.InteractionContext;
 import com.mes.interaction.base.InteractionResult;
-import com.mes.device.service.DeviceCoordinationService;
-import com.mes.device.service.DeviceInteractionService;
 import com.mes.task.dto.TaskParameters;
 import com.mes.task.entity.MultiDeviceTask;
 import com.mes.task.entity.TaskStepDetail;
@@ -23,16 +25,16 @@
 import com.mes.task.model.RetryPolicy;
 import com.mes.task.model.TaskExecutionContext;
 import com.mes.task.model.TaskExecutionResult;
-import com.mes.task.service.TaskStatusNotificationService;
-import com.mes.device.vo.DevicePlcVO;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * 澶氳澶囦换鍔℃墽琛屽紩鎿�
@@ -45,6 +47,8 @@
 
     private static final Map<String, String> DEFAULT_OPERATIONS = new HashMap<>();
     private static final TypeReference<Map<String, Object>> MAP_TYPE = new TypeReference<Map<String, Object>>() {};
+    private static final int SCANNER_LOOKBACK_MINUTES = 2;
+    private static final int SCANNER_LOOKBACK_LIMIT = 20;
 
     // 鎵ц妯″紡甯搁噺
     private static final String EXECUTION_MODE_SERIAL = "SERIAL";
@@ -53,7 +57,8 @@
     static {
         DEFAULT_OPERATIONS.put(DeviceConfig.DeviceType.LOAD_VEHICLE, "feedGlass");
         DEFAULT_OPERATIONS.put(DeviceConfig.DeviceType.LARGE_GLASS, "processGlass");
-        DEFAULT_OPERATIONS.put(DeviceConfig.DeviceType.GLASS_STORAGE, "storeGlass");
+        DEFAULT_OPERATIONS.put(DeviceConfig.DeviceType.WORKSTATION_SCANNER, "scanOnce");
+        DEFAULT_OPERATIONS.put(DeviceConfig.DeviceType.WORKSTATION_TRANSFER, "checkAndProcess");
     }
 
     private final TaskStepDetailMapper taskStepDetailMapper;
@@ -64,6 +69,8 @@
     private final DeviceCoordinationService deviceCoordinationService;
     private final TaskStatusNotificationService notificationService;
     private final ObjectMapper objectMapper;
+    @Qualifier("deviceGlassInfoService")
+    private final GlassInfoService glassInfoService;
 
     // 绾跨▼姹犵敤浜庡苟琛屾墽琛�
     private final ExecutorService executorService = Executors.newCachedThreadPool(r -> {
@@ -71,6 +78,18 @@
         t.setDaemon(true);
         return t;
     });
+    
+    // 瀹氭椂鍣ㄧ嚎绋嬫睜锛氱敤浜庤澶囧畾鏃舵壂鎻�
+    private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(10, r -> {
+        Thread t = new Thread(r, "TaskExecutionEngine-Scheduled");
+        t.setDaemon(true);
+        return t;
+    });
+    
+    // 瀛樺偍姣忎釜浠诲姟鐨勫畾鏃跺櫒浠诲姟锛歵askId -> List<ScheduledFuture>
+    private final Map<String, List<ScheduledFuture<?>>> taskScheduledTasks = new ConcurrentHashMap<>();
+    // 璁板綍姝e湪杩愯浠诲姟鐨勪笂涓嬫枃锛屼究浜庡彇娑堜换鍔℃椂璁块棶
+    private final Map<String, TaskExecutionContext> runningTaskContexts = new ConcurrentHashMap<>();
 
     public TaskExecutionResult execute(MultiDeviceTask task,
                                        DeviceGroupConfig groupConfig,
@@ -82,16 +101,8 @@
         }
 
         TaskExecutionContext context = new TaskExecutionContext(parameters);
+        runningTaskContexts.put(task.getTaskId(), context);
         
-        // 璁惧鍗忚皟锛氭鏌ヤ緷璧栧叧绯诲拰鎵ц鏉′欢
-        DeviceCoordinationService.CoordinationResult coordinationResult = 
-            deviceCoordinationService.coordinateExecution(groupConfig, devices, context);
-        if (!coordinationResult.canExecute()) {
-            log.warn("璁惧鍗忚皟澶辫触: {}", coordinationResult.getMessage());
-            return TaskExecutionResult.failure(coordinationResult.getMessage(), Collections.emptyMap());
-        }
-        log.info("璁惧鍗忚皟鎴愬姛: {}", coordinationResult.getMessage());
-
         task.setTotalSteps(devices.size());
         task.setStatus(MultiDeviceTask.Status.RUNNING.name());
         multiDeviceTaskMapper.updateById(task);
@@ -120,10 +131,133 @@
             stepSummaries = new ArrayList<>();
             success = true;
             failureMessage = null;
-            for (int i = 0; i < devices.size(); i++) {
-                DeviceConfig device = devices.get(i);
-                int order = i + 1;
-                TaskStepDetail step = createStepRecord(task, device, order);
+
+            TaskParameters params = context.getParameters();
+            boolean hasGlassIds = !CollectionUtils.isEmpty(params.getGlassIds());
+            boolean triggerFirst = Boolean.TRUE.equals(params.getTriggerRequestFirst());
+
+            int currentOrder = 1;
+            // 缁熻澶ц溅璁惧鏁伴噺锛岀敤浜庡尯鍒嗚繘鐗囧ぇ杞﹀拰鍑虹墖澶ц溅
+            int loadVehicleCount = 0;
+            for (DeviceConfig device : devices) {
+                if (DeviceConfig.DeviceType.LOAD_VEHICLE.equals(device.getDeviceType())) {
+                    loadVehicleCount++;
+                }
+            }
+            int currentLoadVehicleIndex = 0;
+            
+            for (DeviceConfig device : devices) {
+                String deviceType = device.getDeviceType();
+                log.info("澶勭悊璁惧: deviceId={}, deviceType={}, deviceName={}, WORKSTATION_SCANNER甯搁噺={}, equals={}", 
+                        device.getId(), deviceType, device.getDeviceName(), 
+                        DeviceConfig.DeviceType.WORKSTATION_SCANNER,
+                        DeviceConfig.DeviceType.WORKSTATION_SCANNER.equals(deviceType));
+                boolean isLoadVehicle = DeviceConfig.DeviceType.LOAD_VEHICLE.equals(deviceType);
+                boolean isScanner = DeviceConfig.DeviceType.WORKSTATION_SCANNER.equals(deviceType) 
+                        || (deviceType != null && (deviceType.contains("鎵爜") || deviceType.contains("SCANNER")));
+                boolean isLargeGlass = DeviceConfig.DeviceType.LARGE_GLASS.equals(deviceType);
+                boolean isTransfer = DeviceConfig.DeviceType.WORKSTATION_TRANSFER.equals(deviceType);
+                log.info("璁惧绫诲瀷鍒ゆ柇: deviceId={}, isLoadVehicle={}, isScanner={}, isLargeGlass={}, isTransfer={}", 
+                        device.getId(), isLoadVehicle, isScanner, isLargeGlass, isTransfer);
+
+                // 1. 鍗ц浆绔嬫壂鐮佽澶囷細鍚姩瀹氭椂鍣ㄦ壂鎻忥紙姣�10绉掑鐞嗕竴涓幓鐠僆D锛�
+                if (isScanner) {
+                    log.info("妫�娴嬪埌鎵爜璁惧锛屽噯澶囧惎鍔ㄥ畾鏃跺櫒: deviceId={}, deviceType={}, deviceName={}", 
+                            device.getId(), device.getDeviceType(), device.getDeviceName());
+                    TaskStepDetail step = createStepRecord(task, device, currentOrder);
+                    ScheduledFuture<?> scannerTask = startScannerTimer(task, step, device, context);
+                    if (scannerTask != null) {
+                        registerScheduledTask(task.getTaskId(), scannerTask);
+                        stepSummaries.add(createStepSummary(device.getDeviceName(), true, "瀹氭椂鍣ㄥ凡鍚姩锛屾瘡10绉掓壂鎻忎竴娆�"));
+                        log.info("鎵爜璁惧瀹氭椂鍣ㄥ惎鍔ㄦ垚鍔�: deviceId={}, taskId={}", device.getId(), task.getTaskId());
+                    } else {
+                        log.warn("鎵爜璁惧瀹氭椂鍣ㄥ惎鍔ㄥけ璐ワ紝glassIds鍙兘涓虹┖: deviceId={}, taskId={}, contextParams={}", 
+                                device.getId(), task.getTaskId(), context.getParameters());
+                        stepSummaries.add(createStepSummary(device.getDeviceName(), false, "鍚姩瀹氭椂鍣ㄥけ璐�"));
+                        success = false;
+                        failureMessage = "鍗ц浆绔嬫壂鐮佽澶囧惎鍔ㄥ畾鏃跺櫒澶辫触";
+                        break;
+                    }
+                    currentOrder++;
+                    continue;
+                }
+
+                // 2. 鍗ц浆绔嬭澶囷細鍚姩瀹氭椂鍣ㄥ畾鏈熸鏌ュ苟澶勭悊锛堜腑杞澶囷級
+                if (isTransfer) {
+                    log.info("妫�娴嬪埌鍗ц浆绔嬭澶囷紝鍑嗗鍚姩瀹氭椂鍣�: deviceId={}, deviceType={}, deviceName={}", 
+                            device.getId(), device.getDeviceType(), device.getDeviceName());
+                    TaskStepDetail step = createStepRecord(task, device, currentOrder);
+                    ScheduledFuture<?> transferTask = startTransferTimer(task, step, device, context);
+                    if (transferTask != null) {
+                        registerScheduledTask(task.getTaskId(), transferTask);
+                        stepSummaries.add(createStepSummary(device.getDeviceName(), true, "瀹氭椂鍣ㄥ凡鍚姩锛屽畾鏈熸鏌ュ苟澶勭悊鐜荤拑鎵规"));
+                        log.info("鍗ц浆绔嬭澶囧畾鏃跺櫒鍚姩鎴愬姛: deviceId={}, taskId={}", device.getId(), task.getTaskId());
+                    } else {
+                        log.warn("鍗ц浆绔嬭澶囧畾鏃跺櫒鍚姩澶辫触: deviceId={}, taskId={}", device.getId(), task.getTaskId());
+                        stepSummaries.add(createStepSummary(device.getDeviceName(), false, "鍚姩瀹氭椂鍣ㄥけ璐�"));
+                        success = false;
+                        failureMessage = "鍗ц浆绔嬭澶囧惎鍔ㄥ畾鏃跺櫒澶辫触";
+                        break;
+                    }
+                    currentOrder++;
+                    continue;
+                }
+
+                // 3. 杩涚墖澶ц溅璁惧锛氬惎鍔ㄥ畾鏃跺櫒鎸佺画鐩戞帶瀹归噺锛堢涓�涓ぇ杞﹁澶囷級
+                if (isLoadVehicle) {
+                    currentLoadVehicleIndex++;
+                    boolean isInboundVehicle = currentLoadVehicleIndex == 1; // 绗竴涓ぇ杞︽槸杩涚墖澶ц溅
+                    
+                    TaskStepDetail step = createStepRecord(task, device, currentOrder);
+                    ScheduledFuture<?> vehicleTask;
+                    if (isInboundVehicle) {
+                        // 杩涚墖澶ц溅锛氱洃鎺у閲忥紝鍔ㄦ�佸垽鏂�
+                        vehicleTask = startInboundVehicleTimer(task, step, device, context);
+                        if (vehicleTask != null) {
+                            registerScheduledTask(task.getTaskId(), vehicleTask);
+                            stepSummaries.add(createStepSummary(device.getDeviceName(), true, "杩涚墖澶ц溅瀹氭椂鍣ㄥ凡鍚姩锛屾寔缁洃鎺у閲�"));
+                        } else {
+                            stepSummaries.add(createStepSummary(device.getDeviceName(), false, "鍚姩瀹氭椂鍣ㄥけ璐�"));
+                            success = false;
+                            failureMessage = "杩涚墖澶ц溅璁惧鍚姩瀹氭椂鍣ㄥけ璐�";
+                            break;
+                        }
+                    } else {
+                        // 鍑虹墖澶ц溅锛氬惎鍔ㄥ畾鏃跺櫒鐩戞帶鍑虹墖浠诲姟
+                        vehicleTask = startOutboundVehicleTimer(task, step, device, context);
+                        if (vehicleTask != null) {
+                            registerScheduledTask(task.getTaskId(), vehicleTask);
+                            stepSummaries.add(createStepSummary(device.getDeviceName(), true, "鍑虹墖澶ц溅瀹氭椂鍣ㄥ凡鍚姩锛屾寔缁洃鎺у嚭鐗囦换鍔�"));
+                        } else {
+                            stepSummaries.add(createStepSummary(device.getDeviceName(), false, "鍚姩瀹氭椂鍣ㄥけ璐�"));
+                            success = false;
+                            failureMessage = "鍑虹墖澶ц溅璁惧鍚姩瀹氭椂鍣ㄥけ璐�";
+                            break;
+                        }
+                    }
+                    currentOrder++;
+                    continue;
+                }
+
+                // 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;
+                    }
+                    currentOrder++;
+                    continue;
+                }
+
+                // 鍏朵粬璁惧锛氭甯告墽琛�
+                TaskStepDetail step = createStepRecord(task, device, currentOrder);
                 StepResult stepResult = executeStep(task, step, device, context);
                 stepSummaries.add(stepResult.toSummary());
                 if (!stepResult.isSuccess()) {
@@ -131,7 +265,35 @@
                     failureMessage = stepResult.getMessage();
                     break;
                 }
+                currentOrder++;
             }
+            
+            // 濡傛灉鎵�鏈夎澶囬兘鏄畾鏃跺櫒妯″紡锛屼换鍔′繚鎸佽繍琛岀姸鎬侊紝涓嶇瓑寰呭畬鎴�
+            // 瀹氭椂鍣ㄤ細鍦ㄥ悗鍙版寔缁繍琛岋紝鐩村埌鎵嬪姩鍋滄鎴栬秴鏃�
+            boolean hasScheduledTasks = !CollectionUtils.isEmpty(taskScheduledTasks.get(task.getTaskId()));
+            if (hasScheduledTasks) {
+                log.info("浠诲姟宸插惎鍔ㄦ墍鏈夊畾鏃跺櫒锛屼繚鎸佽繍琛岀姸鎬�: taskId={}, scheduledTasksCount={}", 
+                        task.getTaskId(), taskScheduledTasks.get(task.getTaskId()).size());
+                // 浠诲姟淇濇寔 RUNNING 鐘舵�侊紝瀹氭椂鍣ㄥ湪鍚庡彴杩愯
+                // 涓嶆洿鏂颁换鍔$姸鎬佷负 COMPLETED锛岃浠诲姟鎸佺画杩愯
+                Map<String, Object> payload = new HashMap<>();
+                payload.put("steps", stepSummaries);
+                payload.put("groupId", groupConfig.getId());
+                payload.put("deviceCount", devices.size());
+                payload.put("executionMode", executionMode);
+                payload.put("message", "浠诲姟宸插惎鍔紝瀹氭椂鍣ㄥ湪鍚庡彴杩愯涓�");
+                
+                // 閫氱煡浠诲姟鐘舵�侊紙淇濇寔 RUNNING锛�
+                notificationService.notifyTaskStatus(task);
+                
+                if (success) {
+                    return TaskExecutionResult.success(payload);
+                }
+                return TaskExecutionResult.failure(failureMessage != null ? failureMessage : "浠诲姟鎵ц澶辫触", payload);
+            }
+            
+            // 濡傛灉娌℃湁瀹氭椂鍣ㄤ换鍔★紝绛夊緟鎵�鏈夋楠ゅ畬鎴�
+            // 杩欑鎯呭喌閫氬父涓嶄細鍙戠敓锛屽洜涓烘墍鏈夎澶囬兘鏄畾鏃跺櫒妯″紡
         }
 
         Map<String, Object> payload = new HashMap<>();
@@ -140,8 +302,15 @@
         payload.put("deviceCount", devices.size());
         payload.put("executionMode", executionMode);
 
+        // 鍋滄鎵�鏈夊畾鏃跺櫒浠诲姟
+        stopScheduledTasks(task.getTaskId());
+        
+        boolean cancelled = isTaskCancelled(context);
         // 鏇存柊浠诲姟鏈�缁堢姸鎬�
-        if (success) {
+        if (cancelled) {
+            task.setStatus(MultiDeviceTask.Status.CANCELLED.name());
+            task.setErrorMessage("浠诲姟宸插彇娑�");
+        } else if (success) {
             task.setStatus(MultiDeviceTask.Status.COMPLETED.name());
         } else {
             task.setStatus(MultiDeviceTask.Status.FAILED.name());
@@ -157,6 +326,744 @@
             return TaskExecutionResult.success(payload);
         }
         return TaskExecutionResult.failure(failureMessage != null ? failureMessage : "浠诲姟鎵ц澶辫触", payload);
+    }
+
+    /**
+     * 璇锋眰鍙栨秷浠诲姟锛氬仠姝㈡墍鏈夊畾鏃跺櫒骞舵爣璁颁笂涓嬫枃
+     */
+    public void requestTaskCancellation(String taskId) {
+        TaskExecutionContext context = runningTaskContexts.get(taskId);
+        if (context != null) {
+            context.getSharedData().put("taskCancelled", true);
+            log.warn("宸叉爣璁颁换鍔″彇娑�: taskId={}", taskId);
+        } else {
+            log.warn("璇锋眰鍙栨秷浠诲姟浣嗘湭鎵惧埌涓婁笅鏂�: taskId={}", taskId);
+        }
+        stopScheduledTasks(taskId);
+    }
+    
+    /**
+     * 鍚姩鍗ц浆绔嬫壂鐮佽澶囧畾鏃跺櫒锛氭瘡10绉掑鐞嗕竴涓幓鐠僆D
+     */
+    private ScheduledFuture<?> startScannerTimer(MultiDeviceTask task,
+                                                 TaskStepDetail step,
+                                                 DeviceConfig device,
+                                                 TaskExecutionContext context) {
+        try {
+            TaskParameters params = context.getParameters();
+            List<String> glassIds = params.getGlassIds();
+            log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒鍒濆鍖�: taskId={}, deviceId={}, glassIds={}, glassIdsSize={}, isEmpty={}", 
+                    task.getTaskId(), device.getId(), glassIds, 
+                    glassIds != null ? glassIds.size() : 0, 
+                    CollectionUtils.isEmpty(glassIds));
+            if (CollectionUtils.isEmpty(glassIds)) {
+                log.warn("鍗ц浆绔嬫壂鐮佽澶囨病鏈夌幓鐠僆D锛屽畾鏃跺櫒涓嶅惎鍔�: deviceId={}", device.getId());
+                return null;
+            }
+            
+            // 鍒涘缓寰呭鐞嗙幓鐠僆D闃熷垪
+            Queue<String> glassIdQueue = new ConcurrentLinkedQueue<>(glassIds);
+            AtomicInteger processedCount = new AtomicInteger(0);
+            AtomicInteger successCount = new AtomicInteger(0);
+            AtomicInteger failCount = new AtomicInteger(0);
+            
+            final long CYCLE_INTERVAL_MS = 10_000; // 10绉掗棿闅�
+            
+            log.info("鍚姩鍗ц浆绔嬫壂鐮佸畾鏃跺櫒: taskId={}, deviceId={}, glassCount={}, interval={}s, glassIds={}",
+                    task.getTaskId(), device.getId(), glassIds.size(), CYCLE_INTERVAL_MS / 1000, glassIds);
+            
+            // 鍚姩瀹氭椂浠诲姟
+            ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
+                try {
+                    if (isTaskCancelled(context)) {
+                        log.info("浠诲姟宸插彇娑堬紝鍋滄鍗ц浆绔嬫壂鐮佸畾鏃跺櫒: taskId={}, deviceId={}", 
+                                task.getTaskId(), device.getId());
+                        return;
+                    }
+                    // 妫�鏌ユ槸鍚﹂渶瑕佹殏鍋�
+                    if (shouldPauseScanner(context)) {
+                        log.debug("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒鏆傚仠: taskId={}, deviceId={}", task.getTaskId(), device.getId());
+                        return;
+                    }
+                    
+                    // 妫�鏌ユ槸鍚﹁繕鏈夊緟澶勭悊鐨勭幓鐠僆D
+                    String glassId = glassIdQueue.poll();
+                    if (glassId == null) {
+                        log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒瀹屾垚: taskId={}, deviceId={}, processed={}/{}, success={}, fail={}",
+                                task.getTaskId(), device.getId(), processedCount.get(), glassIds.size(),
+                                successCount.get(), failCount.get());
+                        deviceCoordinationService.syncDeviceStatus(device,
+                                DeviceCoordinationService.DeviceStatus.COMPLETED, context);
+                        return;
+                    }
+                    
+                    int currentIndex = processedCount.incrementAndGet();
+                    log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒澶勭悊绗瑊}/{}涓幓鐠�: taskId={}, deviceId={}, glassId={}",
+                            currentIndex, glassIds.size(), task.getTaskId(), device.getId(), glassId);
+                    
+                    // 鎵ц鍗曟鎵弿
+                    Map<String, Object> scanParams = new HashMap<>();
+                    scanParams.put("glassId", glassId);
+                    scanParams.put("_taskContext", context);
+                    log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒鍑嗗鎵ц: taskId={}, deviceId={}, glassId={}, scanParams={}", 
+                            task.getTaskId(), device.getId(), glassId, scanParams);
+                    
+                    DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
+                    if (handler != null) {
+                        // 灏唋ogicParams鍚堝苟鍒皊canParams涓�
+                        Map<String, Object> logicParams = parseLogicParams(device);
+                        if (logicParams != null && !logicParams.isEmpty()) {
+                            scanParams.put("_logicParams", logicParams);
+                        }
+                        log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒璋冪敤handler.execute: taskId={}, deviceId={}, glassId={}, operation=scanOnce, scanParamsKeys={}, scanParams={}", 
+                                task.getTaskId(), device.getId(), glassId, scanParams.keySet(), scanParams);
+                        DevicePlcVO.OperationResult result = handler.execute(device, "scanOnce", scanParams);
+                        log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒handler.execute杩斿洖: taskId={}, deviceId={}, glassId={}, success={}", 
+                                task.getTaskId(), device.getId(), glassId, result.getSuccess());
+                        
+                        if (Boolean.TRUE.equals(result.getSuccess())) {
+                            successCount.incrementAndGet();
+                            log.info("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒澶勭悊鎴愬姛: taskId={}, deviceId={}, glassId={}",
+                                    task.getTaskId(), device.getId(), glassId);
+                        } else {
+                            failCount.incrementAndGet();
+                            log.warn("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒澶勭悊澶辫触: taskId={}, deviceId={}, glassId={}, error={}",
+                                    task.getTaskId(), device.getId(), glassId, result.getMessage());
+                        }
+                        
+                        // 鏇存柊姝ラ鐘舵��
+                        updateStepStatus(step, result);
+                        // 閫氱煡姝ラ鏇存柊锛堣鍓嶇瀹炴椂鐪嬪埌姝ラ鐘舵�侊級
+                        notificationService.notifyStepUpdate(task.getTaskId(), step);
+                        boolean opSuccess = Boolean.TRUE.equals(result.getSuccess());
+                        updateTaskProgress(task, step.getStepOrder(), opSuccess);
+                        if (!opSuccess) {
+                            deviceCoordinationService.syncDeviceStatus(device,
+                                    DeviceCoordinationService.DeviceStatus.FAILED, context);
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("鍗ц浆绔嬫壂鐮佸畾鏃跺櫒鎵ц寮傚父: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
+                    failCount.incrementAndGet();
+                }
+            }, 0, CYCLE_INTERVAL_MS, TimeUnit.MILLISECONDS);
+            
+            deviceCoordinationService.syncDeviceStatus(device,
+                    DeviceCoordinationService.DeviceStatus.RUNNING, context);
+            return future;
+        } catch (Exception e) {
+            log.error("鍚姩鍗ц浆绔嬫壂鐮佸畾鏃跺櫒澶辫触: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
+            return null;
+        }
+    }
+    
+    /**
+     * 鍚姩鍗ц浆绔嬭澶囧畾鏃跺櫒锛氬畾鏈熸鏌ュ苟澶勭悊鐜荤拑鎵规
+     */
+    private ScheduledFuture<?> startTransferTimer(MultiDeviceTask task,
+                                                  TaskStepDetail step,
+                                                  DeviceConfig device,
+                                                  TaskExecutionContext context) {
+        try {
+            // 浠庤澶囬厤缃腑鑾峰彇鐩戞帶闂撮殧锛岄粯璁�5绉�
+            Map<String, Object> logicParams = parseLogicParams(device);
+            Integer monitorIntervalMs = getLogicParam(logicParams, "monitorIntervalMs", 5_000);
+            
+            log.info("鍚姩鍗ц浆绔嬭澶囧畾鏃跺櫒: taskId={}, deviceId={}, interval={}ms",
+                    task.getTaskId(), device.getId(), monitorIntervalMs);
+            
+            // 鍚姩瀹氭椂浠诲姟
+            ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
+                try {
+                    if (isTaskCancelled(context)) {
+                        log.info("浠诲姟宸插彇娑堬紝鍋滄鍗ц浆绔嬭澶囧畾鏃跺櫒: taskId={}, deviceId={}",
+                                task.getTaskId(), device.getId());
+                        return;
+                    }
+                    // 鏋勫缓鍙傛暟
+                    Map<String, Object> params = new HashMap<>();
+                    params.put("_taskContext", context);
+                    if (logicParams != null && !logicParams.isEmpty()) {
+                        params.put("_logicParams", logicParams);
+                    }
+                    
+                    // 璋冪敤handler鎵цcheckAndProcess
+                    DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
+                    if (handler != null) {
+                        DevicePlcVO.OperationResult result = handler.execute(device, "checkAndProcess", params);
+                        
+                        // 鏇存柊姝ラ鐘舵��
+                        updateStepStatus(step, result);
+                        // 閫氱煡姝ラ鏇存柊锛堣鍓嶇瀹炴椂鐪嬪埌姝ラ鐘舵�侊級
+                        notificationService.notifyStepUpdate(task.getTaskId(), step);
+                        boolean opSuccess = Boolean.TRUE.equals(result.getSuccess());
+                        updateTaskProgress(task, step.getStepOrder(), opSuccess);
+                        if (opSuccess) {
+                            log.debug("鍗ц浆绔嬭澶囧畾鏃跺櫒鎵ц鎴愬姛: taskId={}, deviceId={}, message={}",
+                                    task.getTaskId(), device.getId(), result.getMessage());
+                        } else {
+                            log.warn("鍗ц浆绔嬭澶囧畾鏃跺櫒鎵ц澶辫触: taskId={}, deviceId={}, message={}",
+                                    task.getTaskId(), device.getId(), result.getMessage());
+                            deviceCoordinationService.syncDeviceStatus(device,
+                                    DeviceCoordinationService.DeviceStatus.FAILED, context);
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("鍗ц浆绔嬭澶囧畾鏃跺櫒鎵ц寮傚父: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
+                }
+            }, 0, monitorIntervalMs, TimeUnit.MILLISECONDS);
+            
+            deviceCoordinationService.syncDeviceStatus(device,
+                    DeviceCoordinationService.DeviceStatus.RUNNING, context);
+            return future;
+        } catch (Exception e) {
+            log.error("鍚姩鍗ц浆绔嬭澶囧畾鏃跺櫒澶辫触: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
+            return null;
+        }
+    }
+    
+    /**
+     * 鍚姩杩涚墖澶ц溅璁惧瀹氭椂鍣細鎸佺画鐩戞帶瀹归噺锛屽姩鎬佸垽鏂�
+     */
+    private ScheduledFuture<?> startInboundVehicleTimer(MultiDeviceTask task,
+                                                        TaskStepDetail step,
+                                                        DeviceConfig device,
+                                                        TaskExecutionContext context) {
+        try {
+            final long MONITOR_INTERVAL_MS = 2_000; // 2绉掔洃鎺т竴娆�
+            final AtomicInteger lastProcessedCount = new AtomicInteger(0);
+            
+            log.info("鍚姩杩涚墖澶ц溅璁惧瀹氭椂鍣�: taskId={}, deviceId={}, interval={}s",
+                    task.getTaskId(), device.getId(), MONITOR_INTERVAL_MS / 1000);
+            
+            // 鍚姩瀹氭椂浠诲姟
+            ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
+                try {
+                    if (isTaskCancelled(context)) {
+                        log.info("浠诲姟宸插彇娑堬紝鍋滄杩涚墖澶ц溅瀹氭椂鍣�: taskId={}, deviceId={}",
+                                task.getTaskId(), device.getId());
+                        return;
+                    }
+                    // 妫�鏌ユ槸鍚︽湁宸叉壂鎻忕殑鐜荤拑淇℃伅
+                    List<String> scannedGlassIds = getScannedGlassIds(context);
+                    if (CollectionUtils.isEmpty(scannedGlassIds)) {
+                        // 娌℃湁宸叉壂鎻忕殑鐜荤拑锛岀‘淇濆崸杞珛鎵爜缁х画杩愯
+                        setScannerPause(context, false);
+                        return;
+                    }
+                    
+                    // 濡傛灉鐜荤拑ID鏁伴噺娌℃湁鍙樺寲锛岃鏄庢病鏈夋柊鐨勭幓鐠冿紝缁х画绛夊緟
+                    int currentCount = scannedGlassIds.size();
+                    if (currentCount == lastProcessedCount.get()) {
+                        log.debug("澶ц溅璁惧瀹氭椂鍣細鐜荤拑ID鏁伴噺鏈彉鍖栵紝缁х画绛夊緟: taskId={}, deviceId={}, count={}",
+                                task.getTaskId(), device.getId(), currentCount);
+                        return;
+                    }
+                    
+                    log.info("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄦ娴嬪埌鏂扮殑鐜荤拑淇℃伅: taskId={}, deviceId={}, glassCount={}",
+                            task.getTaskId(), device.getId(), currentCount);
+                    
+                    // 妫�鏌ュ閲�
+                    Map<String, Object> checkParams = new HashMap<>();
+                    checkParams.put("glassIds", new ArrayList<>(scannedGlassIds));
+                    checkParams.put("_taskContext", context);
+                    
+                    DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
+                    if (handler != null) {
+                        // 灏唋ogicParams鍚堝苟鍒癱heckParams涓�
+                        Map<String, Object> logicParams = parseLogicParams(device);
+                        if (logicParams != null && !logicParams.isEmpty()) {
+                            checkParams.put("_logicParams", logicParams);
+                        }
+                        DevicePlcVO.OperationResult result = handler.execute(device, "feedGlass", checkParams);
+                        
+                        if (Boolean.TRUE.equals(result.getSuccess())) {
+                            log.info("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屾垚鍔�: taskId={}, deviceId={}, glassCount={}",
+                                    task.getTaskId(), device.getId(), scannedGlassIds.size());
+                            // 灏嗗凡瑁呰浇鐨勭幓鐠僆D淇濆瓨鍒板叡浜暟鎹腑锛堜緵澶х悊鐗囩浣跨敤锛�
+                            setLoadedGlassIds(context, new ArrayList<>(scannedGlassIds));
+                            // 娓呯┖宸叉壂鎻忕殑鐜荤拑ID鍒楄〃锛堝凡澶勭悊锛�
+                            clearScannedGlassIds(context);
+                            lastProcessedCount.set(0);
+                            // 纭繚鍗ц浆绔嬫壂鐮佺户缁繍琛�
+                            setScannerPause(context, false);
+                        } else {
+                            // 瑁呬笉涓嬶紝閫氱煡鍗ц浆绔嬫壂鐮佹殏鍋�
+                            log.warn("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄥ閲忎笉瓒�: taskId={}, deviceId={}, message={}, 宸查�氱煡鍗ц浆绔嬫壂鐮佹殏鍋�",
+                                    task.getTaskId(), device.getId(), result.getMessage());
+                            setScannerPause(context, true);
+                            lastProcessedCount.set(currentCount); // 璁板綍褰撳墠鏁伴噺锛岄伩鍏嶉噸澶嶆鏌�
+                        }
+                        
+                        // 鏇存柊姝ラ鐘舵��
+                        updateStepStatus(step, result);
+                        boolean opSuccess = Boolean.TRUE.equals(result.getSuccess());
+                        updateTaskProgress(task, step.getStepOrder(), opSuccess);
+                        if (!opSuccess) {
+                            deviceCoordinationService.syncDeviceStatus(device,
+                                    DeviceCoordinationService.DeviceStatus.FAILED, context);
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("杩涚墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屽紓甯�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
+                }
+            }, 0, MONITOR_INTERVAL_MS, TimeUnit.MILLISECONDS);
+            
+            deviceCoordinationService.syncDeviceStatus(device,
+                    DeviceCoordinationService.DeviceStatus.RUNNING, context);
+            return future;
+        } catch (Exception e) {
+            log.error("鍚姩杩涚墖澶ц溅璁惧瀹氭椂鍣ㄥけ璐�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
+            return null;
+        }
+    }
+    
+    /**
+     * 鍚姩鍑虹墖澶ц溅璁惧瀹氭椂鍣細鎸佺画鐩戞帶鍑虹墖浠诲姟
+     */
+    private ScheduledFuture<?> startOutboundVehicleTimer(MultiDeviceTask task,
+                                                         TaskStepDetail step,
+                                                         DeviceConfig device,
+                                                         TaskExecutionContext context) {
+        try {
+            final long MONITOR_INTERVAL_MS = 2_000; // 2绉掔洃鎺т竴娆�
+            
+            log.info("鍚姩鍑虹墖澶ц溅璁惧瀹氭椂鍣�: taskId={}, deviceId={}, interval={}s",
+                    task.getTaskId(), device.getId(), MONITOR_INTERVAL_MS / 1000);
+            
+            // 鍚姩瀹氭椂浠诲姟
+            ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
+                try {
+                    if (isTaskCancelled(context)) {
+                        log.info("浠诲姟宸插彇娑堬紝鍋滄鍑虹墖澶ц溅瀹氭椂鍣�: taskId={}, deviceId={}",
+                                task.getTaskId(), device.getId());
+                        return;
+                    }
+                    // 妫�鏌ユ槸鍚︽湁宸插鐞嗙殑鐜荤拑淇℃伅锛堜粠澶х悊鐗囩鏉ョ殑锛�
+                    List<String> processedGlassIds = getProcessedGlassIds(context);
+                    if (CollectionUtils.isEmpty(processedGlassIds)) {
+                        log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣細鏆傛棤宸插鐞嗙殑鐜荤拑淇℃伅: taskId={}, deviceId={}",
+                                task.getTaskId(), device.getId());
+                        return;
+                    }
+                    
+                    log.info("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ娴嬪埌宸插鐞嗙殑鐜荤拑淇℃伅: 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);
+                    
+                    DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
+                    if (handler != null) {
+                        // 灏唋ogicParams鍚堝苟鍒癱heckParams涓�
+                        Map<String, Object> logicParams = parseLogicParams(device);
+                        if (logicParams != null && !logicParams.isEmpty()) {
+                            checkParams.put("_logicParams", logicParams);
+                        }
+                        DevicePlcVO.OperationResult result = handler.execute(device, "feedGlass", checkParams);
+                        
+                        if (Boolean.TRUE.equals(result.getSuccess())) {
+                            log.info("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屾垚鍔�: taskId={}, deviceId={}, glassCount={}",
+                                    task.getTaskId(), device.getId(), processedGlassIds.size());
+                            // 娓呯┖宸插鐞嗙殑鐜荤拑ID鍒楄〃锛堝凡澶勭悊锛�
+                            clearProcessedGlassIds(context);
+                        } else {
+                            log.debug("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屽け璐�: taskId={}, deviceId={}, message={}",
+                                    task.getTaskId(), device.getId(), result.getMessage());
+                        }
+                        
+                        // 鏇存柊姝ラ鐘舵��
+                        updateStepStatus(step, result);
+                        boolean opSuccess = Boolean.TRUE.equals(result.getSuccess());
+                        updateTaskProgress(task, step.getStepOrder(), opSuccess);
+                        if (!opSuccess) {
+                            deviceCoordinationService.syncDeviceStatus(device,
+                                    DeviceCoordinationService.DeviceStatus.FAILED, context);
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄦ墽琛屽紓甯�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
+                }
+            }, 0, MONITOR_INTERVAL_MS, TimeUnit.MILLISECONDS);
+            
+            deviceCoordinationService.syncDeviceStatus(device,
+                    DeviceCoordinationService.DeviceStatus.RUNNING, context);
+            return future;
+        } catch (Exception e) {
+            log.error("鍚姩鍑虹墖澶ц溅璁惧瀹氭椂鍣ㄥけ璐�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
+            return null;
+        }
+    }
+    
+    /**
+     * 鍚姩澶х悊鐗囩璁惧瀹氭椂鍣細閫昏緫澶勭悊锛堜笉娑夊強PLC浜や簰锛屽彧璐熻矗閫昏緫澶勭悊锛屾瘮濡傚涔呯粰浠诲姟姹囨姤锛�
+     */
+    private ScheduledFuture<?> startLargeGlassTimer(MultiDeviceTask task,
+                                                    TaskStepDetail step,
+                                                    DeviceConfig device,
+                                                    TaskExecutionContext context) {
+        try {
+            // 浠庤澶囬厤缃腑鑾峰彇澶勭悊鏃堕棿锛堥粯璁�30绉掞級
+            Map<String, Object> logicParams = parseLogicParams(device);
+            Integer processTimeSeconds = getLogicParam(logicParams, "processTimeSeconds", 30);
+            final long PROCESS_TIME_MS = processTimeSeconds * 1000;
+            
+            log.info("鍚姩澶х悊鐗囩璁惧瀹氭椂鍣�: taskId={}, deviceId={}, processTime={}s",
+                    task.getTaskId(), device.getId(), processTimeSeconds);
+            
+            // 鍚姩瀹氭椂浠诲姟
+            ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(() -> {
+                try {
+                    if (isTaskCancelled(context)) {
+                        log.info("浠诲姟宸插彇娑堬紝鍋滄澶х悊鐗囩瀹氭椂鍣�: taskId={}, deviceId={}",
+                                task.getTaskId(), device.getId());
+                        return;
+                    }
+                    // 妫�鏌ユ槸鍚︽湁宸茶杞界殑鐜荤拑淇℃伅锛堜粠杩涚墖澶ц溅鏉ョ殑锛�
+                    List<String> loadedGlassIds = getLoadedGlassIds(context);
+                    if (CollectionUtils.isEmpty(loadedGlassIds)) {
+                        log.debug("澶х悊鐗囩璁惧瀹氭椂鍣細鏆傛棤宸茶杞界殑鐜荤拑淇℃伅: taskId={}, deviceId={}",
+                                task.getTaskId(), device.getId());
+                        return;
+                    }
+                    
+                    // 妫�鏌ョ幓鐠冩槸鍚﹀凡缁忓鐞嗗畬鎴愶紙閫氳繃澶勭悊鏃堕棿鍒ゆ柇锛�
+                    Long processStartTime = getProcessStartTime(context);
+                    if (processStartTime == null) {
+                        // 绗竴娆℃娴嬪埌鐜荤拑锛岃褰曞紑濮嬪鐞嗘椂闂�
+                        setProcessStartTime(context, System.currentTimeMillis());
+                        log.info("澶х悊鐗囩璁惧寮�濮嬪鐞�: taskId={}, deviceId={}, glassCount={}, processTime={}s",
+                                task.getTaskId(), device.getId(), loadedGlassIds.size(), processTimeSeconds);
+                        return;
+                    }
+                    
+                    long elapsed = System.currentTimeMillis() - processStartTime;
+                    if (elapsed < PROCESS_TIME_MS) {
+                        // 澶勭悊鏃堕棿鏈埌锛岀户缁瓑寰�
+                        log.debug("澶х悊鐗囩璁惧澶勭悊涓�: taskId={}, deviceId={}, elapsed={}s, remaining={}s",
+                                task.getTaskId(), device.getId(), elapsed / 1000, (PROCESS_TIME_MS - elapsed) / 1000);
+                        return;
+                    }
+                    
+                    // 澶勭悊鏃堕棿宸插埌锛屽畬鎴愪换鍔℃眹鎶�
+                    log.info("澶х悊鐗囩璁惧澶勭悊瀹屾垚: taskId={}, deviceId={}, glassCount={}, processTime={}s",
+                            task.getTaskId(), device.getId(), loadedGlassIds.size(), processTimeSeconds);
+                    
+                    // 灏嗗凡澶勭悊鐨勭幓鐠僆D杞Щ鍒板凡澶勭悊鍒楄〃锛堜緵鍑虹墖澶ц溅浣跨敤锛�
+                    setProcessedGlassIds(context, new ArrayList<>(loadedGlassIds));
+                    clearLoadedGlassIds(context);
+                    clearProcessStartTime(context);
+                    
+                    // 鏇存柊姝ラ鐘舵��
+                    step.setStatus(TaskStepDetail.Status.COMPLETED.name());
+                    step.setErrorMessage(null);
+                    step.setOutputData(toJson(Collections.singletonMap("glassIds", loadedGlassIds)));
+                    taskStepDetailMapper.updateById(step);
+                    
+                } catch (Exception e) {
+                    log.error("澶х悊鐗囩璁惧瀹氭椂鍣ㄦ墽琛屽紓甯�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
+                }
+            }, 0, 1_000, TimeUnit.MILLISECONDS); // 姣忕妫�鏌ヤ竴娆�
+            
+            return future;
+        } catch (Exception e) {
+            log.error("鍚姩澶х悊鐗囩璁惧瀹氭椂鍣ㄥけ璐�: taskId={}, deviceId={}", task.getTaskId(), device.getId(), e);
+            return null;
+        }
+    }
+    
+    /**
+     * 鑾峰彇閫昏緫鍙傛暟
+     */
+    @SuppressWarnings("unchecked")
+    private <T> T getLogicParam(Map<String, Object> logicParams, String key, T defaultValue) {
+        if (logicParams == null) {
+            return defaultValue;
+        }
+        Object value = logicParams.get(key);
+        if (value == null) {
+            return defaultValue;
+        }
+        try {
+            return (T) value;
+        } catch (ClassCastException e) {
+            return defaultValue;
+        }
+    }
+    
+    /**
+     * 鑾峰彇宸茶杞界殑鐜荤拑ID鍒楄〃
+     */
+    @SuppressWarnings("unchecked")
+    private List<String> getLoadedGlassIds(TaskExecutionContext context) {
+        if (context == null) {
+            return Collections.emptyList();
+        }
+        Object glassIds = context.getSharedData().get("loadedGlassIds");
+        if (glassIds instanceof List) {
+            return new ArrayList<>((List<String>) glassIds);
+        }
+        return Collections.emptyList();
+    }
+    
+    /**
+     * 璁剧疆宸茶杞界殑鐜荤拑ID鍒楄〃
+     */
+    private void setLoadedGlassIds(TaskExecutionContext context, List<String> glassIds) {
+        if (context != null) {
+            context.getSharedData().put("loadedGlassIds", new ArrayList<>(glassIds));
+        }
+    }
+    
+    /**
+     * 娓呯┖宸茶杞界殑鐜荤拑ID鍒楄〃
+     */
+    private void clearLoadedGlassIds(TaskExecutionContext context) {
+        if (context != null) {
+            context.getSharedData().put("loadedGlassIds", new ArrayList<>());
+        }
+    }
+    
+    /**
+     * 鑾峰彇宸插鐞嗙殑鐜荤拑ID鍒楄〃
+     */
+    @SuppressWarnings("unchecked")
+    private List<String> getProcessedGlassIds(TaskExecutionContext context) {
+        if (context == null) {
+            return Collections.emptyList();
+        }
+        Object glassIds = context.getSharedData().get("processedGlassIds");
+        if (glassIds instanceof List) {
+            return new ArrayList<>((List<String>) glassIds);
+        }
+        return Collections.emptyList();
+    }
+    
+    /**
+     * 璁剧疆宸插鐞嗙殑鐜荤拑ID鍒楄〃
+     */
+    private void setProcessedGlassIds(TaskExecutionContext context, List<String> glassIds) {
+        if (context != null) {
+            context.getSharedData().put("processedGlassIds", new ArrayList<>(glassIds));
+        }
+    }
+    
+    /**
+     * 娓呯┖宸插鐞嗙殑鐜荤拑ID鍒楄〃
+     */
+    private void clearProcessedGlassIds(TaskExecutionContext context) {
+        if (context != null) {
+            context.getSharedData().put("processedGlassIds", new ArrayList<>());
+        }
+    }
+    
+    /**
+     * 鑾峰彇澶勭悊寮�濮嬫椂闂�
+     */
+    private Long getProcessStartTime(TaskExecutionContext context) {
+        if (context == null) {
+            return null;
+        }
+        Object time = context.getSharedData().get("processStartTime");
+        if (time instanceof Number) {
+            return ((Number) time).longValue();
+        }
+        return null;
+    }
+    
+    /**
+     * 璁剧疆澶勭悊寮�濮嬫椂闂�
+     */
+    private void setProcessStartTime(TaskExecutionContext context, long time) {
+        if (context != null) {
+            context.getSharedData().put("processStartTime", time);
+        }
+    }
+    
+    /**
+     * 娓呯┖澶勭悊寮�濮嬫椂闂�
+     */
+    private void clearProcessStartTime(TaskExecutionContext context) {
+        if (context != null) {
+            context.getSharedData().remove("processStartTime");
+        }
+    }
+    
+    /**
+     * 璁剧疆鍗ц浆绔嬫壂鐮佹殏鍋滄爣蹇�
+     */
+    private void setScannerPause(TaskExecutionContext context, boolean pause) {
+        if (context != null) {
+            context.getSharedData().put("scannerPause", pause);
+        }
+    }
+
+    private boolean isTaskCancelled(TaskExecutionContext context) {
+        if (context == null) {
+            return false;
+        }
+        Object cancelled = context.getSharedData().get("taskCancelled");
+        return cancelled instanceof Boolean && (Boolean) cancelled;
+    }
+    
+    /**
+     * 妫�鏌ユ槸鍚﹂渶瑕佹殏鍋滃崸杞珛鎵爜
+     */
+    private boolean shouldPauseScanner(TaskExecutionContext context) {
+        if (context == null) {
+            return false;
+        }
+        Object pauseFlag = context.getSharedData().get("scannerPause");
+        return pauseFlag instanceof Boolean && (Boolean) pauseFlag;
+    }
+    
+    /**
+     * 鑾峰彇宸叉壂鎻忕殑鐜荤拑ID鍒楄〃
+     */
+    @SuppressWarnings("unchecked")
+    private List<String> getScannedGlassIds(TaskExecutionContext context) {
+        if (context == null) {
+            return Collections.emptyList();
+        }
+        Object glassIds = context.getSharedData().get("scannedGlassIds");
+        if (glassIds instanceof List) {
+            return new ArrayList<>((List<String>) glassIds);
+        }
+        return Collections.emptyList();
+    }
+    
+    /**
+     * 娓呯┖宸叉壂鎻忕殑鐜荤拑ID鍒楄〃
+     */
+    private void clearScannedGlassIds(TaskExecutionContext context) {
+        if (context != null) {
+            context.getSharedData().put("scannedGlassIds", new ArrayList<>());
+        }
+    }
+    
+    /**
+     * 娉ㄥ唽瀹氭椂鍣ㄤ换鍔�
+     */
+    private void registerScheduledTask(String taskId, ScheduledFuture<?> future) {
+        taskScheduledTasks.computeIfAbsent(taskId, k -> new ArrayList<>()).add(future);
+    }
+    
+    /**
+     * 鍋滄鎵�鏈夊畾鏃跺櫒浠诲姟
+     */
+    private void stopScheduledTasks(String taskId) {
+        List<ScheduledFuture<?>> futures = taskScheduledTasks.remove(taskId);
+        if (futures != null) {
+            for (ScheduledFuture<?> future : futures) {
+                if (future != null && !future.isCancelled()) {
+                    future.cancel(false);
+                }
+            }
+            log.info("宸插仠姝换鍔$殑鎵�鏈夊畾鏃跺櫒: taskId={}, count={}", taskId, futures.size());
+        }
+        runningTaskContexts.remove(taskId);
+    }
+    
+    /**
+     * 绛夊緟瀹氭椂鍣ㄤ换鍔″畬鎴愶紙甯﹁秴鏃讹級
+     */
+    private void waitForScheduledTasks(String taskId, TaskExecutionContext context) {
+        // 鑾峰彇浠诲姟瓒呮椂鏃堕棿锛堥粯璁�30鍒嗛挓锛�
+        TaskParameters params = context.getParameters();
+        long timeoutMinutes = params != null && params.getTimeoutMinutes() != null
+                ? params.getTimeoutMinutes() : 30;
+        long timeoutMs = timeoutMinutes * 60 * 1000;
+        long deadline = System.currentTimeMillis() + timeoutMs;
+        
+        log.info("绛夊緟瀹氭椂鍣ㄤ换鍔″畬鎴�: taskId={}, timeout={}鍒嗛挓", taskId, timeoutMinutes);
+        
+        while (System.currentTimeMillis() < deadline) {
+            List<ScheduledFuture<?>> futures = taskScheduledTasks.get(taskId);
+            if (futures == null || futures.isEmpty()) {
+                break;
+            }
+            
+            // 妫�鏌ユ槸鍚︽墍鏈変换鍔¢兘宸插畬鎴�
+            boolean allDone = true;
+            for (ScheduledFuture<?> future : futures) {
+                if (future != null && !future.isDone()) {
+                    allDone = false;
+                    break;
+                }
+            }
+            
+            if (allDone) {
+                break;
+            }
+            
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                break;
+            }
+        }
+        
+        log.info("瀹氭椂鍣ㄤ换鍔$瓑寰呭畬鎴�: taskId={}", taskId);
+    }
+    
+    /**
+     * 鏇存柊姝ラ鐘舵��
+     */
+    private void updateStepStatus(TaskStepDetail step, DevicePlcVO.OperationResult result) {
+        if (step == null || result == null) {
+            return;
+        }
+        boolean success = Boolean.TRUE.equals(result.getSuccess());
+        step.setStatus(success 
+                ? TaskStepDetail.Status.COMPLETED.name() 
+                : TaskStepDetail.Status.FAILED.name());
+        // 璁剧疆娑堟伅锛氭垚鍔熸椂濡傛灉鏈夋秷鎭篃淇濆瓨锛屽け璐ユ椂淇濆瓨閿欒娑堟伅
+        String message = result.getMessage();
+        if (success) {
+            // 鎴愬姛鏃讹紝濡傛灉鏈夋秷鎭垯淇濆瓨锛堢敤浜庢彁绀轰俊鎭級锛屽惁鍒欐竻绌�
+            step.setSuccessMessage(StringUtils.hasText(message) ? message : null);
+        } else {
+            // 澶辫触鏃朵繚瀛橀敊璇秷鎭�
+            step.setErrorMessage(message);
+        }
+        step.setOutputData(toJson(result));
+        taskStepDetailMapper.updateById(step);
+    }
+    
+    /**
+     * 鍒涘缓姝ラ鎽樿
+     */
+    private Map<String, Object> createStepSummary(String deviceName, boolean success, String message) {
+        Map<String, Object> summary = new HashMap<>();
+        summary.put("deviceName", deviceName);
+        summary.put("success", success);
+        summary.put("message", message);
+        return summary;
+    }
+    
+    /**
+     * 瑙f瀽璁惧閫昏緫鍙傛暟
+     */
+    @SuppressWarnings("unchecked")
+    private Map<String, Object> parseLogicParams(DeviceConfig device) {
+        String extraParams = device.getExtraParams();
+        if (!StringUtils.hasText(extraParams)) {
+            return Collections.emptyMap();
+        }
+        try {
+            Map<String, Object> extraParamsMap = objectMapper.readValue(extraParams, MAP_TYPE);
+            Object deviceLogic = extraParamsMap.get("deviceLogic");
+            if (deviceLogic instanceof Map) {
+                return (Map<String, Object>) deviceLogic;
+            }
+            return Collections.emptyMap();
+        } catch (Exception e) {
+            log.warn("瑙f瀽璁惧閫昏緫鍙傛暟澶辫触: deviceId={}", device.getId(), e);
+            return Collections.emptyMap();
+        }
     }
 
     /**
@@ -346,6 +1253,74 @@
         }
     }
 
+    /**
+     * 鍒嗘壒鎵ц澶ц溅璁惧鐜荤拑涓婃枡锛堝綋鐜荤拑ID鏁伴噺瓒呰繃6涓笖璁剧疆浜嗗崟鐗囬棿闅旀椂锛�
+     */
+    private StepResult executeLoadVehicleWithBatches(MultiDeviceTask task,
+                                                      DeviceConfig device,
+                                                      int order,
+                                                      TaskExecutionContext context,
+                                                      List<Map<String, Object>> stepSummaries) {
+        List<String> allGlassIds = context.getParameters().getGlassIds();
+        Integer glassIntervalMs = context.getParameters().getGlassIntervalMs();
+        int batchSize = 6; // 姣忔壒鏈�澶�6涓幓鐠僆D
+        
+        // 鍒嗘壒澶勭悊
+        int totalBatches = (allGlassIds.size() + batchSize - 1) / batchSize;
+        log.info("澶ц溅璁惧鍒嗘壒涓婃枡: deviceId={}, totalGlassIds={}, batchSize={}, totalBatches={}, glassIntervalMs={}",
+                device.getId(), allGlassIds.size(), batchSize, totalBatches, glassIntervalMs);
+        
+        for (int batchIndex = 0; batchIndex < totalBatches; batchIndex++) {
+            int startIndex = batchIndex * batchSize;
+            int endIndex = Math.min(startIndex + batchSize, allGlassIds.size());
+            List<String> batchGlassIds = allGlassIds.subList(startIndex, endIndex);
+            
+            // 鍒涘缓涓存椂鍙傛暟锛屽彧鍖呭惈褰撳墠鎵规鐨勭幓鐠僆D
+            TaskParameters batchParams = new TaskParameters();
+            batchParams.setGlassIds(new ArrayList<>(batchGlassIds));
+            batchParams.setGlassIntervalMs(glassIntervalMs);
+            batchParams.setPositionCode(context.getParameters().getPositionCode());
+            batchParams.setPositionValue(context.getParameters().getPositionValue());
+            
+            // 鍒涘缓涓存椂涓婁笅鏂�
+            TaskExecutionContext batchContext = new TaskExecutionContext(batchParams);
+            
+            // 鍒涘缓姝ラ璁板綍
+            TaskStepDetail step = createStepRecord(task, device, order);
+            step.setStepName(step.getStepName() + String.format(" (鎵规 %d/%d)", batchIndex + 1, totalBatches));
+            
+            // 鎵ц褰撳墠鎵规
+            StepResult stepResult = executeStep(task, step, device, batchContext);
+            stepSummaries.add(stepResult.toSummary());
+            
+            if (!stepResult.isSuccess()) {
+                log.error("澶ц溅璁惧鍒嗘壒涓婃枡澶辫触: deviceId={}, batchIndex={}/{}, error={}",
+                        device.getId(), batchIndex + 1, totalBatches, stepResult.getMessage());
+                return stepResult;
+            }
+            
+            log.info("澶ц溅璁惧鍒嗘壒涓婃枡鎴愬姛: deviceId={}, batchIndex={}/{}, glassIds={}",
+                    device.getId(), batchIndex + 1, totalBatches, batchGlassIds);
+            
+            // 濡傛灉涓嶆槸鏈�鍚庝竴鎵癸紝绛夊緟闂撮殧锛堟ā鎷熺幓鐠冩瘡鐗囪繍鍔ㄧ殑鏃堕棿锛�
+            // 杩欎釜绛夊緟璁╁ぇ杞︽湁鏃堕棿澶勭悊褰撳墠鎵规鐨勭幓鐠冿紝鐒跺悗鍐嶄紶閫掍笅涓�鎵�
+            if (batchIndex < totalBatches - 1 && glassIntervalMs != null && glassIntervalMs > 0) {
+                try {
+                    log.info("绛夊緟鍗曠墖闂撮殧锛堟ā鎷熺幓鐠冭繍鍔ㄦ椂闂达級: glassIntervalMs={}ms, 澶ц溅鍙湪姝ゆ湡闂寸户缁鐜荤拑", glassIntervalMs);
+                    Thread.sleep(glassIntervalMs);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    return StepResult.failure(device.getDeviceName(), "绛夊緟鍗曠墖闂撮殧鏃惰涓柇");
+                }
+            }
+        }
+        
+        // 鏇存柊涓婁笅鏂囦腑鐨勫凡鍔犺浇鐜荤拑ID
+        context.setLoadedGlassIds(new ArrayList<>(allGlassIds));
+        
+        return StepResult.success(device.getDeviceName(), "鍒嗘壒涓婃枡瀹屾垚锛屽叡" + totalBatches + "鎵�");
+    }
+
     private TaskStepDetail createStepRecord(MultiDeviceTask task, DeviceConfig device, int order) {
         TaskStepDetail step = new TaskStepDetail();
         step.setTaskId(task.getTaskId());
@@ -362,6 +1337,18 @@
                                    TaskStepDetail step,
                                    DeviceConfig device,
                                    TaskExecutionContext context) {
+        DeviceCoordinationService.DependencyCheckResult dependencyResult =
+                deviceCoordinationService.checkDependencies(device, context);
+        if (!dependencyResult.isSatisfied()) {
+            log.warn("璁惧渚濊禆鏈弧瓒�: deviceId={}, message={}", device.getId(), dependencyResult.getMessage());
+            step.setStatus(TaskStepDetail.Status.FAILED.name());
+            step.setErrorMessage(dependencyResult.getMessage());
+            step.setStartTime(new Date());
+            step.setEndTime(new Date());
+            taskStepDetailMapper.updateById(step);
+            updateTaskProgress(task, step.getStepOrder(), false);
+            return StepResult.failure(device.getDeviceName(), dependencyResult.getMessage());
+        }
         return executeStepWithRetry(task, step, device, context, getRetryPolicy(device));
     }
 
@@ -384,6 +1371,10 @@
         }
 
         Map<String, Object> params = buildOperationParams(device, context);
+        // 灏哻ontext寮曠敤鏀惧叆params锛屼緵璁惧澶勭悊鍣ㄤ娇鐢紙鐢ㄤ簬璁惧鍗忚皟锛�
+        params.put("_taskContext", context);
+        log.info("executeStepWithRetry鏋勫缓鍙傛暟: deviceId={}, deviceType={}, operation={}, paramsKeys={}, params={}", 
+                device.getId(), device.getDeviceType(), determineOperation(device, params), params.keySet(), params);
         step.setInputData(toJson(params));
         taskStepDetailMapper.updateById(step);
 
@@ -424,7 +1415,7 @@
                 notificationService.notifyStepUpdate(task.getTaskId(), step);
 
                 if (opSuccess) {
-                    updateContextAfterSuccess(device, context, params);
+                    updateContextAfterSuccess(device, context, params, result);
                     
                     // 鍚屾璁惧鐘舵��
                     deviceCoordinationService.syncDeviceStatus(device, 
@@ -511,6 +1502,69 @@
         
         return StepResult.failure(device.getDeviceName(), 
             String.format("鎵ц澶辫触锛堝凡閲嶈瘯%d娆★級", retryAttempt));
+    }
+
+    /**
+     * 鎵ц涓�娆$畝鍗曠殑璁惧鎿嶄綔姝ラ锛堜笉璧颁氦浜掑紩鎿庯級锛岀敤浜庤Е鍙戣姹傜瓑鍦烘櫙
+     */
+    private StepResult executeDirectOperationStep(MultiDeviceTask task,
+                                                  TaskStepDetail step,
+                                                  DeviceConfig device,
+                                                  TaskExecutionContext context,
+                                                  String operation,
+                                                  Map<String, Object> params) {
+        Date startTime = new Date();
+        step.setStartTime(startTime);
+        step.setStatus(TaskStepDetail.Status.RUNNING.name());
+        step.setRetryCount(0);
+        step.setInputData(toJson(params));
+        taskStepDetailMapper.updateById(step);
+
+        try {
+            DeviceCoordinationService.DependencyCheckResult dependencyResult =
+                    deviceCoordinationService.checkDependencies(device, context);
+            if (!dependencyResult.isSatisfied()) {
+                log.warn("鐩存帴鎿嶄綔渚濊禆鏈弧瓒�: deviceId={}, message={}", device.getId(), dependencyResult.getMessage());
+                step.setStatus(TaskStepDetail.Status.FAILED.name());
+                step.setErrorMessage(dependencyResult.getMessage());
+                step.setEndTime(new Date());
+                step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
+                taskStepDetailMapper.updateById(step);
+                updateTaskProgress(task, step.getStepOrder(), false);
+                return StepResult.failure(device.getDeviceName(), dependencyResult.getMessage());
+            }
+
+            DevicePlcVO.OperationResult result = deviceInteractionService.executeOperation(
+                    device.getId(), operation, params);
+
+            boolean opSuccess = Boolean.TRUE.equals(result.getSuccess());
+            updateStepAfterOperation(step, result, opSuccess);
+            updateTaskProgress(task, step.getStepOrder(), opSuccess);
+
+            if (opSuccess) {
+                updateContextAfterSuccess(device, context, params, result);
+                // 绠�鍗曞悓姝ヨ澶囩姸鎬佷负宸插畬鎴�
+                deviceCoordinationService.syncDeviceStatus(device,
+                        DeviceCoordinationService.DeviceStatus.COMPLETED, context);
+                return StepResult.success(device.getDeviceName(), result.getMessage());
+            } else {
+                deviceCoordinationService.syncDeviceStatus(device,
+                        DeviceCoordinationService.DeviceStatus.FAILED, context);
+                return StepResult.failure(device.getDeviceName(), result.getMessage());
+            }
+        } catch (Exception e) {
+            log.error("鐩存帴璁惧鎿嶄綔寮傚父, deviceId={}, operation={}", device.getId(), operation, e);
+            step.setStatus(TaskStepDetail.Status.FAILED.name());
+            step.setErrorMessage(e.getMessage());
+            step.setEndTime(new Date());
+            step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
+            taskStepDetailMapper.updateById(step);
+            updateTaskProgress(task, step.getStepOrder(), false);
+
+            deviceCoordinationService.syncDeviceStatus(device,
+                    DeviceCoordinationService.DeviceStatus.FAILED, context);
+            return StepResult.failure(device.getDeviceName(), e.getMessage());
+        }
     }
 
     /**
@@ -652,7 +1706,15 @@
             step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
         }
         step.setStatus(success ? TaskStepDetail.Status.COMPLETED.name() : TaskStepDetail.Status.FAILED.name());
-        step.setErrorMessage(success ? null : result.getMessage());
+        // 璁剧疆娑堟伅锛氭垚鍔熸椂濡傛灉鏈夋秷鎭篃淇濆瓨锛屽け璐ユ椂淇濆瓨閿欒娑堟伅
+        String message = result != null ? result.getMessage() : null;
+        if (success) {
+            // 鎴愬姛鏃讹紝濡傛灉鏈夋秷鎭垯淇濆瓨锛堢敤浜庢彁绀轰俊鎭級锛屽惁鍒欐竻绌�
+            step.setErrorMessage(StringUtils.hasText(message) ? message : null);
+        } else {
+            // 澶辫触鏃朵繚瀛橀敊璇秷鎭�
+            step.setErrorMessage(message);
+        }
         step.setOutputData(toJson(result));
         taskStepDetailMapper.updateById(step);
     }
@@ -671,20 +1733,48 @@
     }
 
     private void updateTaskProgress(MultiDeviceTask task, int currentStep, boolean success) {
-        task.setCurrentStep(currentStep);
         if (!success) {
             task.setStatus(MultiDeviceTask.Status.FAILED.name());
         }
+        
+        // 璁$畻宸插畬鎴愮殑姝ラ鏁帮紙鐢ㄤ簬杩涘害鏄剧ず锛�
+        int completedSteps = countCompletedSteps(task.getTaskId());
+        int progressStep = success
+                ? completedSteps
+                : Math.max(completedSteps, currentStep); // 澶辫触鏃惰嚦灏戞樉绀哄綋鍓嶆楠�
+        
         LambdaUpdateWrapper<MultiDeviceTask> update = Wrappers.<MultiDeviceTask>lambdaUpdate()
                 .eq(MultiDeviceTask::getId, task.getId())
-                .set(MultiDeviceTask::getCurrentStep, currentStep);
+                .set(MultiDeviceTask::getCurrentStep, progressStep);
         if (!success) {
             update.set(MultiDeviceTask::getStatus, MultiDeviceTask.Status.FAILED.name());
         }
         multiDeviceTaskMapper.update(null, update);
         
-        // 閫氱煡浠诲姟鐘舵�佹洿鏂�
+        // 鏇存柊浠诲姟瀵硅薄鐨勮繘搴︼紝鐢ㄤ簬閫氱煡
+        task.setCurrentStep(progressStep);
+        
+        // 閫氱煡浠诲姟鐘舵�佹洿鏂帮紙鍖呭惈杩涘害淇℃伅锛�
         notificationService.notifyTaskStatus(task);
+    }
+    
+    /**
+     * 缁熻宸插畬鎴愮殑姝ラ鏁�
+     */
+    private int countCompletedSteps(String taskId) {
+        if (taskId == null) {
+            return 0;
+        }
+        try {
+            return taskStepDetailMapper.selectCount(
+                Wrappers.<TaskStepDetail>lambdaQuery()
+                    .eq(TaskStepDetail::getTaskId, taskId)
+                    .eq(TaskStepDetail::getStatus, TaskStepDetail.Status.COMPLETED.name())
+            ).intValue();
+        } catch (Exception e) {
+            log.warn("缁熻宸插畬鎴愭楠ゆ暟澶辫触: taskId={}", taskId, e);
+            return 0;
+        }
     }
 
     private String determineOperation(DeviceConfig device, Map<String, Object> params) {
@@ -710,6 +1800,10 @@
                 if (taskParams.getPositionValue() != null) {
                     params.put("positionValue", taskParams.getPositionValue());
                 }
+                // 浼犻�掑崟鐗囬棿闅旈厤缃紝濡傛灉浠诲姟鍙傛暟涓湁璁剧疆锛屼紭鍏堜娇鐢ㄤ换鍔″弬鏁扮殑锛屽惁鍒欎娇鐢ㄨ澶囬厤缃殑
+                if (taskParams.getGlassIntervalMs() != null) {
+                    params.put("glassIntervalMs", taskParams.getGlassIntervalMs());
+                }
                 params.put("triggerRequest", true);
                 break;
             case DeviceConfig.DeviceType.LARGE_GLASS:
@@ -724,19 +1818,21 @@
                 params.put("processType", taskParams.getProcessType() != null ? taskParams.getProcessType() : 1);
                 params.put("triggerRequest", true);
                 break;
-            case DeviceConfig.DeviceType.GLASS_STORAGE:
-                List<String> processed = context.getSafeProcessedGlassIds();
-                if (CollectionUtils.isEmpty(processed)) {
-                    processed = context.getSafeLoadedGlassIds();
+            case DeviceConfig.DeviceType.WORKSTATION_SCANNER:
+                // 鍗ц浆绔嬫壂鐮佽澶囷細浠庝换鍔″弬鏁颁腑鑾峰彇鐜荤拑ID鍒楄〃锛屽彇绗竴涓綔涓哄綋鍓嶈娴嬭瘯鐨勭幓鐠僆D
+                // 娉ㄦ剰锛氭壂鐮佽澶囬�氬父閫氳繃瀹氭椂鍣ㄦ墽琛岋紝浣嗗鏋滈�氳繃executeStep鎵ц锛屼篃闇�瑕佷紶閫抔lassId
+                log.info("buildOperationParams澶勭悊鎵爜璁惧: deviceId={}, taskParams.glassIds={}, isEmpty={}", 
+                        device.getId(), taskParams.getGlassIds(), 
+                        CollectionUtils.isEmpty(taskParams.getGlassIds()));
+                if (!CollectionUtils.isEmpty(taskParams.getGlassIds())) {
+                    params.put("glassId", taskParams.getGlassIds().get(0));
+                    params.put("glassIds", new ArrayList<>(taskParams.getGlassIds()));
+                    log.info("buildOperationParams涓烘壂鐮佽澶囨坊鍔爂lassId: deviceId={}, glassId={}, glassIdsSize={}", 
+                            device.getId(), taskParams.getGlassIds().get(0), taskParams.getGlassIds().size());
+                } else {
+                    log.warn("buildOperationParams鎵爜璁惧glassIds涓虹┖: deviceId={}, taskParams.glassIds={}, taskParams={}", 
+                            device.getId(), taskParams.getGlassIds(), taskParams);
                 }
-                if (!CollectionUtils.isEmpty(processed)) {
-                    params.put("glassId", processed.get(0));
-                    params.put("glassIds", new ArrayList<>(processed));
-                }
-                if (taskParams.getStoragePosition() != null) {
-                    params.put("storagePosition", taskParams.getStoragePosition());
-                }
-                params.put("triggerRequest", true);
                 break;
             default:
                 if (!CollectionUtils.isEmpty(taskParams.getExtra())) {
@@ -763,13 +1859,17 @@
 
     private void updateContextAfterSuccess(DeviceConfig device,
                                            TaskExecutionContext context,
-                                           Map<String, Object> params) {
+                                           Map<String, Object> params,
+                                           DevicePlcVO.OperationResult result) {
         List<String> glassIds = extractGlassIds(params);
-        
+
         switch (device.getDeviceType()) {
+            case DeviceConfig.DeviceType.WORKSTATION_SCANNER:
+                handleScannerSuccess(context, result);
+                break;
             case DeviceConfig.DeviceType.LOAD_VEHICLE:
                 context.setLoadedGlassIds(glassIds);
-                // 鏁版嵁浼犻�掞細涓婂ぇ杞� -> 涓嬩竴涓澶�
+                // 鏁版嵁浼犻�掞細澶ц溅璁惧 -> 涓嬩竴涓澶�
                 if (!CollectionUtils.isEmpty(glassIds)) {
                     Map<String, Object> transferData = new HashMap<>();
                     transferData.put("glassIds", glassIds);
@@ -792,6 +1892,23 @@
         }
     }
 
+    private void handleScannerSuccess(TaskExecutionContext context,
+                                      DevicePlcVO.OperationResult result) {
+        List<String> scannerGlassIds = extractGlassIdsFromResult(result);
+        if (CollectionUtils.isEmpty(scannerGlassIds)) {
+            String workLine = resolveWorkLineFromResult(result, context.getParameters());
+            scannerGlassIds = glassInfoService.getRecentScannedGlassIds(
+                    SCANNER_LOOKBACK_MINUTES, SCANNER_LOOKBACK_LIMIT, workLine);
+        }
+        if (!CollectionUtils.isEmpty(scannerGlassIds)) {
+            context.getParameters().setGlassIds(new ArrayList<>(scannerGlassIds));
+            context.setLoadedGlassIds(new ArrayList<>(scannerGlassIds));
+            log.info("鍗ц浆绔嬫壂鐮佽幏鍙栧埌鐜荤拑ID: {}", scannerGlassIds);
+        } else {
+            log.warn("鍗ц浆绔嬫壂鐮佹湭鑾峰彇鍒扮幓鐠僆D锛屽悗缁澶囧彲鑳芥棤娉曟墽琛�");
+        }
+    }
+
     private List<String> extractGlassIds(Map<String, Object> params) {
         if (params == null) {
             return Collections.emptyList();
@@ -809,6 +1926,45 @@
         return Collections.emptyList();
     }
 
+    @SuppressWarnings("unchecked")
+    private List<String> extractGlassIdsFromResult(DevicePlcVO.OperationResult result) {
+        if (result == null || result.getData() == null) {
+            return Collections.emptyList();
+        }
+        Object data = result.getData().get("glassIds");
+        if (data instanceof List) {
+            List<Object> raw = (List<Object>) data;
+            List<String> converted = new ArrayList<>();
+            for (Object item : raw) {
+                if (item != null) {
+                    converted.add(String.valueOf(item));
+                }
+            }
+            return converted;
+        }
+        if (data instanceof String && StringUtils.hasText((String) data)) {
+            return Collections.singletonList((String) data);
+        }
+        return Collections.emptyList();
+    }
+
+    private String resolveWorkLineFromResult(DevicePlcVO.OperationResult result,
+                                             TaskParameters parameters) {
+        if (result != null && result.getData() != null) {
+            Object workLine = result.getData().get("workLine");
+            if (workLine != null && StringUtils.hasText(String.valueOf(workLine))) {
+                return String.valueOf(workLine);
+            }
+        }
+        if (parameters != null && !CollectionUtils.isEmpty(parameters.getExtra())) {
+            Object extraWorkLine = parameters.getExtra().get("workLine");
+            if (extraWorkLine != null) {
+                return String.valueOf(extraWorkLine);
+            }
+        }
+        return null;
+    }
+
     private String toJson(Object value) {
         try {
             return objectMapper.writeValueAsString(value);

--
Gitblit v1.8.0