huang
2025-12-02 628aa6a42e587e9f337e213f87f922fc2ab2af02
mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/transfer/handler/HorizontalTransferLogicHandler.java
@@ -83,7 +83,9 @@
            switch (operation) {
                case "checkAndProcess":
                case "process":
                    return handleCheckAndProcess(deviceConfig, config, logicParams);
                    // 这里必须把 params 传进去,以便在多设备任务流程中
                    // 能够通过 _taskContext 将卧转立输出的玻璃ID写入任务上下文
                    return handleCheckAndProcess(deviceConfig, config, logicParams, params);
                case "startMonitor":
                    return handleStartMonitor(deviceConfig, config, logicParams);
                case "stopMonitor":
@@ -109,7 +111,8 @@
    private DevicePlcVO.OperationResult handleCheckAndProcess(
            DeviceConfig deviceConfig,
            WorkstationLogicConfig config,
            Map<String, Object> logicParams) {
            Map<String, Object> logicParams,
            Map<String, Object> params) {
        
        String deviceId = deviceConfig.getDeviceId();
        EnhancedS7Serializer serializer = s7SerializerProvider.getSerializer(deviceConfig);
@@ -129,9 +132,13 @@
            log.info("查询到最近扫码的玻璃: deviceId={}, count={}", 
                    deviceId, recentGlasses.size());
            // 2. 更新缓冲队列和最后扫码时间
            updateBuffer(deviceId, recentGlasses);
            lastScanTime.put(deviceId, new AtomicLong(System.currentTimeMillis()));
            // 2. 更新缓冲队列;仅在有“新玻璃”加入缓冲时才更新最后扫码时间
            boolean hasNewGlass = updateBuffer(deviceId, recentGlasses);
            if (hasNewGlass) {
                lastScanTime
                        .computeIfAbsent(deviceId, k -> new AtomicLong())
                        .set(System.currentTimeMillis());
            }
            // 3. 检查是否需要立即处理(容量已满或30s内无新玻璃)
            List<GlassBufferItem> buffer = glassBuffer.get(deviceId);
@@ -162,8 +169,34 @@
                return writeResult;
            }
            // 7. 从缓冲队列中移除已处理的玻璃
            // 卧转立批次已成功写入PLC,将本批次玻璃ID写入任务上下文,供大车进片使用
            try {
                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> batchGlassIds = batch.stream()
                                .map(GlassInfo::getGlassId)
                                .filter(Objects::nonNull)
                                .collect(Collectors.toList());
                        if (!batchGlassIds.isEmpty()) {
                            ctx.getSharedData().put("transferReadyGlassIds",
                                    new java.util.ArrayList<>(batchGlassIds));
                            log.info("卧转立已输出批次玻璃到任务上下文: deviceId={}, glassIds={}",
                                    deviceConfig.getId(), batchGlassIds);
                        }
                    }
                }
            } catch (Exception e) {
                log.warn("卧转立写入任务上下文transferReadyGlassIds失败: deviceId={}", deviceConfig.getId(), e);
            }
            // 7. 从缓冲队列中移除已处理的玻璃并更新状态
            removeProcessedGlasses(deviceId, batch);
            glassInfoService.updateGlassStatus(
                    batch.stream().map(GlassInfo::getGlassId).collect(Collectors.toList()),
                    GlassInfo.Status.PROCESSED);
            String msg = String.format("批次已写入PLC: glassCount=%d, glassIds=%s", 
                    batch.size(), 
@@ -197,7 +230,7 @@
            Date twoMinutesAgo = new Date(System.currentTimeMillis() - 120000);
            
            LambdaQueryWrapper<GlassInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(GlassInfo::getStatus, GlassInfo.Status.ACTIVE)
            wrapper.in(GlassInfo::getStatus, GlassInfo.Status.PENDING, GlassInfo.Status.ACTIVE)
                   .ge(GlassInfo::getCreatedTime, twoMinutesAgo)
                   .orderByDesc(GlassInfo::getCreatedTime)
                   .last("LIMIT 20"); // 限制查询数量,避免过多
@@ -223,8 +256,9 @@
    /**
     * 更新缓冲队列
     * @return 是否有新的玻璃被加入缓冲(用于判断是否刷新 lastScanTime)
     */
    private void updateBuffer(String deviceId, List<GlassInfo> newGlasses) {
    private boolean updateBuffer(String deviceId, List<GlassInfo> newGlasses) {
        List<GlassBufferItem> buffer = glassBuffer.computeIfAbsent(
                deviceId, k -> new CopyOnWriteArrayList<>());
        
@@ -232,13 +266,16 @@
                .map(item -> item.glassInfo.getGlassId())
                .collect(Collectors.toSet());
        
        boolean hasNewGlass = false;
        for (GlassInfo glass : newGlasses) {
            if (!existingIds.contains(glass.getGlassId())) {
                buffer.add(new GlassBufferItem(glass, System.currentTimeMillis()));
                hasNewGlass = true;
                log.debug("添加玻璃到缓冲队列: deviceId={}, glassId={}", 
                        deviceId, glass.getGlassId());
            }
        }
        return hasNewGlass;
    }
    /**
@@ -375,7 +412,8 @@
        // 启动监控任务
        ScheduledFuture<?> future = monitorExecutor.scheduleWithFixedDelay(() -> {
            try {
                handleCheckAndProcess(deviceConfig, config, logicParams);
                // 监控任务不在多设备任务上下文中运行,这里不需要传入 params/_taskContext
                handleCheckAndProcess(deviceConfig, config, logicParams, null);
            } catch (Exception e) {
                log.error("监控任务执行异常: deviceId={}", deviceId, e);
            }