huang
昨天 ea51b55feb73883040ed8a87b5a4aeb0bf94bb5e
修改出片任务分批进行
2个文件已修改
248 ■■■■ 已修改文件
mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java 173 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java
@@ -223,7 +223,7 @@
                    result = handleSetOnlineState(deviceConfig, params, logicParams);
                    break;
                case "checkMesConfirm":
                    result = checkMesConfirm(deviceConfig, logicParams);
                    result = checkMesConfirm(deviceConfig, params, logicParams);
                    break;
                case "markBroken":
                    result = handleMarkBroken(deviceConfig, params, logicParams);
@@ -2040,6 +2040,7 @@
     * 返回OperationResult.data中的 completed 标志表示是否已确认完成
     */
    public DevicePlcVO.OperationResult checkMesConfirm(DeviceConfig deviceConfig,
                                                       Map<String, Object> params,
                                                       Map<String, Object> logicParams) {
        if (plcDynamicDataService == null || s7SerializerProvider == null) {
            return DevicePlcVO.OperationResult.builder()
@@ -2149,6 +2150,78 @@
            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和汇报字
                clearTaskStates(deviceConfig, serializer);
mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java
@@ -829,7 +829,9 @@
                        // 只有在任务已开始执行(有任务记录)时才检查MES确认
                        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("进片大车设备检查MES确认状态异常: taskId={}, deviceId={}, error={}",
                                    task.getTaskId(), device.getId(), e.getMessage());
@@ -933,10 +935,42 @@
                    // 检查是否有已处理的玻璃信息(从大理片笼来的)
                    List<String> processedGlassIds = getProcessedGlassIds(context);
                    boolean isRunning = TaskStepDetail.Status.RUNNING.name().equals(step.getStatus());
                    boolean isCompleted = TaskStepDetail.Status.COMPLETED.name().equals(step.getStatus());
                    // 获取已出片的玻璃ID列表(在方法开始处声明,避免重复定义)
                    List<String> outboundGlassIds = getOutboundGlassIds(context);
                    // 如果步骤已完成,检查是否所有初始玻璃都已出片
                    if (isCompleted) {
                        @SuppressWarnings("unchecked")
                        List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
                        // 如果还有未出片的玻璃,重置步骤状态为RUNNING,继续等待
                        if (initialGlassIds != null && !initialGlassIds.isEmpty()
                                && (outboundGlassIds == null || !outboundGlassIds.containsAll(initialGlassIds))) {
                            log.info("出片大车步骤已完成,但还有未出片的玻璃,重置为RUNNING继续等待: taskId={}, deviceId={}, initialCount={}, outboundCount={}",
                                    task.getTaskId(), device.getId(),
                                    initialGlassIds.size(),
                                    outboundGlassIds != null ? outboundGlassIds.size() : 0);
                            step.setStatus(TaskStepDetail.Status.RUNNING.name());
                            step.setEndTime(null); // 清除结束时间
                            step.setSuccessMessage("等待剩余玻璃出片");
                            taskStepDetailMapper.updateById(step);
                            notificationService.notifyStepUpdate(task.getTaskId(), step);
                            // 继续执行后续逻辑,检查是否有新的已处理玻璃
                        } else {
                            // 所有玻璃都已出片,保持完成状态
                            log.debug("出片大车所有玻璃都已出片: taskId={}, deviceId={}, initialCount={}, outboundCount={}",
                                    task.getTaskId(), device.getId(),
                                    initialGlassIds != null ? initialGlassIds.size() : 0,
                                    outboundGlassIds != null ? outboundGlassIds.size() : 0);
                            return;
                        }
                    }
                    
                    // 如果没有已处理玻璃,则不应主动把步骤拉到RUNNING,只保持已运行状态
                    if (CollectionUtils.isEmpty(processedGlassIds)) {
                        if (isRunning) {
                        if (isRunning || isCompleted) {
                            // 已经在运行的情况下,继续轮询MES任务/确认,避免错过确认
                            DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
                            if (handler != null) {
@@ -946,9 +980,14 @@
                                DevicePlcVO.OperationResult mesTaskResult = null;
                                try {
                                    mesTaskResult = handler.execute(device, "checkMesTask", Collections.emptyMap());
                                    if (mesTaskResult != null && Boolean.TRUE.equals(mesTaskResult.getSuccess())) {
                                        log.info("出片大车设备已检查MES任务并开始执行: taskId={}, deviceId={}, message={}",
                                                task.getTaskId(), device.getId(), mesTaskResult.getMessage());
                                    if (mesTaskResult != null) {
                                        if (Boolean.TRUE.equals(mesTaskResult.getSuccess())) {
                                            log.info("出片大车设备已检查MES任务并开始执行: taskId={}, deviceId={}, message={}",
                                                    task.getTaskId(), device.getId(), mesTaskResult.getMessage());
                                        } else {
                                            log.debug("出片大车设备检查MES任务,等待中: taskId={}, deviceId={}, message={}",
                                                    task.getTaskId(), device.getId(), mesTaskResult.getMessage());
                                        }
                                    }
                                } catch (Exception e) {
                                    log.warn("出片大车设备检查MES任务异常: taskId={}, deviceId={}, error={}",
@@ -958,7 +997,9 @@
                                // 然后检查MES确认状态(只有在任务已开始执行时才检查)
                                DevicePlcVO.OperationResult mesResult = null;
                                try {
                                    mesResult = handler.execute(device, "checkMesConfirm", Collections.emptyMap());
                                    Map<String, Object> checkParams = new HashMap<>();
                                    checkParams.put("_taskContext", context);
                                    mesResult = handler.execute(device, "checkMesConfirm", checkParams);
                                } catch (Exception e) {
                                    log.warn("出片大车设备检查MES确认状态异常: taskId={}, deviceId={}, error={}",
                                            task.getTaskId(), device.getId(), e.getMessage());
@@ -993,28 +1034,30 @@
                    log.debug("出片大车设备定时器检测到已处理的玻璃信息: taskId={}, deviceId={}, glassCount={}",
                            task.getTaskId(), device.getId(), processedGlassIds.size());
                    // 需等待大理片笼完成全部玻璃的处理后再出片
                    @SuppressWarnings("unchecked")
                    List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
                    if (!CollectionUtils.isEmpty(initialGlassIds)
                            && !processedGlassIds.containsAll(initialGlassIds)) {
                        // 部分玻璃尚未由大理片笼处理完成,保持等待
                        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);
                    // 过滤出还未出片的玻璃(支持分批出片)
                    // 重新获取已出片的玻璃ID列表(可能在上面的逻辑中已更新)
                    outboundGlassIds = getOutboundGlassIds(context);
                    List<String> glassIdsToOutbound = new ArrayList<>();
                    for (String glassId : processedGlassIds) {
                        if (outboundGlassIds == null || !outboundGlassIds.contains(glassId)) {
                            glassIdsToOutbound.add(glassId);
                        }
                        log.debug("出片大车等待大理片笼完成全部玻璃: taskId={}, deviceId={}, processed={}, initial={}",
                                task.getTaskId(), device.getId(), processedGlassIds.size(), initialGlassIds.size());
                    }
                    // 如果没有需要出片的玻璃(都已经出片过了),继续等待新的已处理玻璃
                    if (glassIdsToOutbound.isEmpty()) {
                        log.debug("出片大车已处理的玻璃都已出片,等待新的已处理玻璃: taskId={}, deviceId={}",
                                task.getTaskId(), device.getId());
                        return;
                    }
                    
                    log.debug("出片大车准备出片: taskId={}, deviceId={}, 待出片数量={}, 已出片数量={}",
                            task.getTaskId(), device.getId(), glassIdsToOutbound.size(),
                            outboundGlassIds != null ? outboundGlassIds.size() : 0);
                    // 执行出片操作
                    Map<String, Object> checkParams = new HashMap<>();
                    checkParams.put("glassIds", new ArrayList<>(processedGlassIds));
                    checkParams.put("glassIds", glassIdsToOutbound);
                    checkParams.put("_taskContext", context);
                    
                    DeviceLogicHandler handler = handlerFactory.getHandler(device.getDeviceType());
@@ -1041,9 +1084,17 @@
                                notificationService.notifyStepUpdate(task.getTaskId(), step);
                            }
                            log.debug("出片大车设备定时器执行成功: taskId={}, deviceId={}, glassCount={}",
                                    task.getTaskId(), device.getId(), processedGlassIds.size());
                            // 清空已处理的玻璃ID列表(已处理)
                            clearProcessedGlassIds(context);
                                    task.getTaskId(), device.getId(), glassIdsToOutbound.size());
                            // 记录已出片的玻璃ID(只记录本次出片的玻璃)
                            addOutboundGlassIds(context, glassIdsToOutbound);
                            // 从processedGlassIds中移除已出片的玻璃,保留未出片的玻璃
                            processedGlassIds.removeAll(glassIdsToOutbound);
                            // 如果还有未出片的玻璃,不清空processedGlassIds;如果全部出片了,清空
                            if (processedGlassIds.isEmpty()) {
                                clearProcessedGlassIds(context);
                            } else {
                                setProcessedGlassIds(context, processedGlassIds);
                            }
                            
                            // feedGlass成功后,先检查MES任务(checkMesTask)来开始执行任务
                            DevicePlcVO.OperationResult mesTaskResult = null;
@@ -1075,10 +1126,49 @@
                        // 只有在任务已开始执行(有任务记录)时才检查MES确认
                        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("出片大车设备检查MES确认状态异常: taskId={}, deviceId={}, error={}",
                                    task.getTaskId(), device.getId(), e.getMessage());
                        }
                        // 对于出片大车,需要检查是否所有初始玻璃都已出片
                        // 如果MES返回completed=true,但还有未出片的玻璃,则不应标记为完成
                        if (mesResult != null && mesResult.getData() != null) {
                            Object completedFlag = mesResult.getData().get("completed");
                            boolean mesCompleted = false;
                            if (completedFlag instanceof Boolean) {
                                mesCompleted = (Boolean) completedFlag;
                            } else if (completedFlag != null) {
                                mesCompleted = "true".equalsIgnoreCase(String.valueOf(completedFlag));
                            }
                            // 如果MES返回completed=true,检查是否所有初始玻璃都已出片
                            if (mesCompleted) {
                                @SuppressWarnings("unchecked")
                                List<String> initialGlassIds = (List<String>) context.getSharedData().get("initialGlassIds");
                                // 重新获取已出片的玻璃ID列表(可能在上面的逻辑中已更新)
                                outboundGlassIds = getOutboundGlassIds(context);
                                // 如果还有未出片的玻璃,修改mesResult,将completed设为false
                                if (initialGlassIds != null && !initialGlassIds.isEmpty()
                                        && (outboundGlassIds == null || !outboundGlassIds.containsAll(initialGlassIds))) {
                                    log.debug("出片大车MES返回completed=true,但还有未出片的玻璃: taskId={}, deviceId={}, initialCount={}, outboundCount={}",
                                            task.getTaskId(), device.getId(),
                                            initialGlassIds.size(),
                                            outboundGlassIds != null ? outboundGlassIds.size() : 0);
                                    // 修改mesResult,将completed设为false,保持RUNNING状态
                                    Map<String, Object> modifiedData = new HashMap<>(mesResult.getData());
                                    modifiedData.put("completed", false);
                                    DevicePlcVO.OperationResult modifiedResult = new DevicePlcVO.OperationResult();
                                    modifiedResult.setSuccess(mesResult.getSuccess());
                                    modifiedResult.setMessage(mesResult.getMessage());
                                    modifiedResult.setData(modifiedData);
                                    mesResult = modifiedResult;
                                }
                            }
                        }
                        
                        // 更新步骤状态(大车设备保持RUNNING,直到MES确认完成或任务取消)
@@ -1364,6 +1454,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));
        }
    }
    
@@ -1818,7 +1935,9 @@
            // 然后检查MES确认状态
            DevicePlcVO.OperationResult mesResult = null;
            try {
                mesResult = handler.execute(device, "checkMesConfirm", Collections.emptyMap());
                Map<String, Object> checkParams = new HashMap<>();
                checkParams.put("_taskContext", context);
                mesResult = handler.execute(device, "checkMesConfirm", checkParams);
            } catch (Exception e) {
                log.warn("大车设备检查MES确认状态异常: taskId={}, deviceId={}, error={}",
                        task.getTaskId(), device.getId(), e.getMessage());