huang
昨天 04914a9997afbbead6f8adbb9d9c40e05b2edbd1
mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java
@@ -1331,10 +1331,22 @@
            MesTaskInfo existingTask = currentTasks.get(deviceId);
            if (existingTask != null) {
                log.debug("设备已有任务在执行中,跳过检查MES任务: deviceId={}", deviceId);
                // 仍然返回当前任务的玻璃列表,供任务引擎记录/对账本批次
                List<String> batchIds = new ArrayList<>();
                if (existingTask.glasses != null) {
                    for (GlassTaskInfo g : existingTask.glasses) {
                        if (g != null && g.glassId != null && !g.glassId.isEmpty()) {
                            batchIds.add(g.glassId);
                        }
                    }
                }
                return DevicePlcVO.OperationResult.builder()
                        .success(true)
                        .message("任务执行中,无需重复检查MES任务")
                        .data(Collections.singletonMap("waiting", false))
                        .data(new HashMap<String, Object>() {{
                            put("waiting", false);
                            put("batchGlassIds", batchIds);
                        }})
                        .build();
            }
            
@@ -1357,6 +1369,7 @@
                waitData.put("completed", false);
                waitData.put("waiting", true);
                waitData.put("waitingReason", "mesSend=0");
                waitData.put("batchGlassIds", new ArrayList<>());
                return DevicePlcVO.OperationResult.builder()
                        .success(true)
                        .message("等待MES发送请求(mesSend=0)")
@@ -1501,6 +1514,39 @@
            
            currentTasks.put(deviceId, taskInfo);
            
            // 如果有多设备任务上下文,则记录本次MES下发的玻璃ID列表到上下文,供分批校验使用
            if (params != null) {
                Object ctxObj = params.get("_taskContext");
                if (ctxObj instanceof com.mes.task.model.TaskExecutionContext) {
                    com.mes.task.model.TaskExecutionContext ctx = (com.mes.task.model.TaskExecutionContext) ctxObj;
                    List<String> batchIds = new ArrayList<>();
                    for (GlassTaskInfo g : glasses) {
                        if (g != null && g.glassId != null && !g.glassId.isEmpty()) {
                            batchIds.add(g.glassId);
                        }
                    }
                    // 1. 记录当前批次的玻璃ID
                    ctx.getSharedData().put("currentMesBatchGlassIds", batchIds);
                    log.info("记录本次MES批次玻璃列表: deviceId={}, batchIds={}", deviceId, batchIds);
                    // 2. 初始化总待出片玻璃列表(仅第一次初始化,从任务参数获取)
                    if (!ctx.getSharedData().containsKey("initialGlassIds")) {
                        // 从任务参数中获取总待出片玻璃ID(核心:总列表来自任务参数,而非MES批次)
                        List<String> taskGlassIds = ctx.getParameters().getGlassIds();
                        if (taskGlassIds != null && !taskGlassIds.isEmpty()) {
                            ctx.getSharedData().put("initialGlassIds", new ArrayList<>(taskGlassIds));
                            // 初始化已出片列表为空
                            if (!ctx.getSharedData().containsKey("outboundGlassIds")) {
                                ctx.getSharedData().put("outboundGlassIds", new ArrayList<>());
                            }
                            log.info("初始化总待出片玻璃列表: deviceId={}, taskGlassIds={}", deviceId, taskGlassIds);
                        } else {
                            log.warn("任务参数中未找到总待出片玻璃ID列表: deviceId={}", deviceId);
                        }
                    }
                }
            }
            // 清空plcRequest(表示已接收任务)
            Map<String, Object> payload = new HashMap<>();
            payload.put("plcRequest", 0);
@@ -1537,6 +1583,14 @@
            Map<String, Object> successData = new HashMap<>();
            successData.put("waiting", false);
            successData.put("taskStarted", true);
            // 将本次MES下发的玻璃ID列表通过返回值带回(任务引擎不再依赖_taskContext写入)
            List<String> batchIdsForReturn = new ArrayList<>();
            for (GlassTaskInfo g : glasses) {
                if (g != null && g.glassId != null && !g.glassId.isEmpty()) {
                    batchIdsForReturn.add(g.glassId);
                }
            }
            successData.put("batchGlassIds", batchIdsForReturn);
            
            return DevicePlcVO.OperationResult.builder()
                    .success(true)
@@ -2063,8 +2117,11 @@
        if (taskInfo == null) {
            log.info("检查MES确认时未找到任务记录,尝试补偿检查MES任务: deviceId={}", deviceId);
            try {
                // 关键:补偿检查时也要透传params(包含_taskContext),
                // 否则handleCheckMesTask无法把本批次玻璃ID写入currentMesBatchGlassIds,任务引擎无法累加完成进度
                Map<String, Object> checkParams = params != null ? params : Collections.emptyMap();
                DevicePlcVO.OperationResult checkResult =
                        handleCheckMesTask(deviceConfig, Collections.emptyMap(), logicParams);
                        handleCheckMesTask(deviceConfig, checkParams, logicParams);
                if (Boolean.TRUE.equals(checkResult.getSuccess())) {
                    taskInfo = currentTasks.get(deviceId);
                    if (taskInfo != null) {
@@ -2150,84 +2207,14 @@
            data.put("completed", completed);
            if (completed) {
                // MES已确认,检查是否还有未出片的玻璃(仅对出片任务)
                boolean hasMoreGlass = false;
                int completedCount = 0;
                int totalCount = 0;
                if (taskInfo.isOutbound && params != null) {
                    // 从TaskExecutionContext中获取已出片的玻璃ID列表和初始玻璃ID列表
                    Object contextObj = params.get("_taskContext");
                    if (contextObj instanceof com.mes.task.model.TaskExecutionContext) {
                        com.mes.task.model.TaskExecutionContext context =
                                (com.mes.task.model.TaskExecutionContext) contextObj;
                        @SuppressWarnings("unchecked")
                        List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
                        @SuppressWarnings("unchecked")
                        List<String> outboundGlassIds = (List<String>) context.getSharedData().get("outboundGlassIds");
                        if (initialGlassIds != null && !initialGlassIds.isEmpty()) {
                            totalCount = initialGlassIds.size();
                            completedCount = (outboundGlassIds != null) ? outboundGlassIds.size() : 0;
                            // 检查是否所有玻璃都已出片
                            if (outboundGlassIds == null || !outboundGlassIds.containsAll(initialGlassIds)) {
                                hasMoreGlass = true;
                            }
                        }
                    }
                }
                // 如果还有未出片的玻璃,保持plcRequest=1,清理本次任务状态,等待下次交互
                // 这样第二次交互时,checkMesTask可以检测到mesSend=1,创建新任务,完整地走一遍逻辑
                if (hasMoreGlass) {
                    // 清空state和汇报字(本次交互已完成)
                    clearTaskStates(deviceConfig, serializer);
                    // 注意:不记录lastCompletedMesRecords,因为还有未出片的玻璃,任务未真正完成
                    // 这样第二次交互时,即使MES发送新任务(新的玻璃ID),也不会被误判为旧任务
                    // 任务完成,恢复为空闲状态(本次交互已完成)
                    statusManager.updateVehicleStatus(
                            deviceConfig.getDeviceId(), VehicleState.IDLE);
                    statusManager.clearVehicleTask(deviceConfig.getDeviceId());
                    // 移除任务记录(本次交互已完成,等待下次交互时创建新任务)
                    currentTasks.remove(deviceConfig.getDeviceId());
                    // 停止任务监控(本次交互已完成)
                    handleStopTaskMonitor(deviceConfig);
                    // 保持plcRequest=1(可以接收下次任务)
                    Map<String, Object> payload = new HashMap<>();
                    payload.put("plcRequest", 1);
                    plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
                    log.info("出片任务本次交互完成,还有未出片的玻璃,等待下次交互: deviceId={}, completedCount={}, totalCount={}",
                            deviceConfig.getDeviceId(), completedCount, totalCount);
                    String progressMessage = String.format("目前完成出片玻璃数量%d/%d,等待下次交互任务", completedCount, totalCount);
                    data.put("completed", false); // 标记为未完成,因为还有未出片的玻璃
                    data.put("waiting", true);
                    data.put("waitingReason", "moreGlassToOutbound");
                    data.put("completedCount", completedCount);
                    data.put("totalCount", totalCount);
                    return DevicePlcVO.OperationResult.builder()
                            .success(true)
                            .message(String.format("出片任务本次交互完成:MES已确认(mesConfirm=1),已清空state和汇报字。%s。大车空闲(plcRequest=1),等待MES发送下次任务", progressMessage))
                            .data(data)
                            .build();
                }
                // 所有玻璃都已出片,正常完成流程
                // MES已确认,清空state和汇报字
                // MES已确认:本次交互完成(不在设备侧判断“是否还有更多玻璃”,由任务引擎统一编排)
                clearTaskStates(deviceConfig, serializer);
                // 记录已完成的任务签名,避免MES未复位时被重复拉起
                if (taskInfo != null && taskInfo.mesSignature != null) {
                lastCompletedMesRecords.put(deviceId,
                        new CompletedMesRecord(taskInfo.mesSignature, System.currentTimeMillis()));
                }
                // 任务完成,恢复为空闲状态
                statusManager.updateVehicleStatus(
@@ -2246,10 +2233,10 @@
                plcDynamicDataService.writePlcData(deviceConfig, payload, serializer);
                log.info("MES任务已确认完成: deviceId={}", deviceConfig.getDeviceId());
                String taskType = taskInfo.isOutbound ? "出片" : "进片";
                String taskType = (taskInfo != null && taskInfo.isOutbound) ? "出片" : "进片";
                return DevicePlcVO.OperationResult.builder()
                        .success(true)
                        .message(String.format("%s任务完成:MES已确认(mesConfirm=1),已清空state和汇报字,大车空闲(plcRequest=1),可以等待下次任务", taskType))
                        .message(String.format("%s任务交互完成:MES已确认(mesConfirm=1),已清空state和汇报字,大车空闲(plcRequest=1)", taskType))
                        .data(data)
                        .build();
            }