package com.mes.interaction.vehicle.flow; import com.mes.device.entity.DeviceConfig; import com.mes.device.service.DeviceInteractionService; import com.mes.device.vo.DevicePlcVO; import com.mes.interaction.DeviceInteraction; import com.mes.interaction.base.InteractionContext; import com.mes.interaction.base.InteractionResult; import com.mes.interaction.vehicle.coordination.VehicleCoordinationService; import com.mes.interaction.vehicle.coordination.VehicleStatusManager; import com.mes.interaction.vehicle.model.VehicleState; import com.mes.interaction.vehicle.model.VehiclePosition; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 大车设备交互实现(增强版) * 集成多车协调和状态管理功能 * * @author mes * @since 2025-01-XX */ @Slf4j @Component @RequiredArgsConstructor public class LoadVehicleInteraction implements DeviceInteraction { private final DeviceInteractionService deviceInteractionService; @Autowired private VehicleCoordinationService coordinationService; @Autowired private VehicleStatusManager statusManager; @Override public String getDeviceType() { return DeviceConfig.DeviceType.LOAD_VEHICLE; } @Override public InteractionResult execute(InteractionContext context) { try { // 前置条件验证 if (context.getCurrentDevice() == null) { return InteractionResult.fail("设备配置不存在"); } DeviceConfig currentDevice = context.getCurrentDevice(); String deviceId = currentDevice.getDeviceId(); // 1. 检查车辆状态(如果设备已指定) if (deviceId != null) { if (!statusManager.isVehicleAvailable(deviceId)) { com.mes.interaction.vehicle.model.VehicleStatus status = statusManager.getVehicleStatus(deviceId); String stateMsg = status != null ? status.getState().name() : "未知"; return InteractionResult.fail( String.format("车辆 %s (%s) 当前状态为 %s,无法执行操作", currentDevice.getDeviceName(), deviceId, stateMsg)); } } // 2. 如果没有指定设备,尝试从设备组中选择可用车辆 DeviceConfig selectedDevice = currentDevice; Long groupId = extractGroupId(context); if (groupId != null && (deviceId == null || !statusManager.isVehicleAvailable(deviceId))) { DeviceConfig availableVehicle = coordinationService.selectAvailableVehicle(groupId); if (availableVehicle != null) { selectedDevice = availableVehicle; log.info("从设备组 {} 中选择可用车辆: {}", groupId, availableVehicle.getDeviceName()); } else if (deviceId == null) { // 没有可用车辆,返回等待结果 return InteractionResult.waitResult( "设备组中没有可用的大车设备,等待车辆空闲", null); } } // 3. 验证玻璃ID List glassIds = context.getParameters().getGlassIds(); if (CollectionUtils.isEmpty(glassIds)) { return InteractionResult.waitResult("未提供玻璃ID,等待输入", null); } // 验证玻璃ID格式 for (String glassId : glassIds) { if (glassId == null || glassId.trim().isEmpty()) { return InteractionResult.fail("玻璃ID不能为空"); } } // 4. 标记车辆为执行中 String selectedDeviceId = selectedDevice.getDeviceId(); statusManager.updateVehicleStatus( selectedDeviceId, selectedDevice.getDeviceName(), VehicleState.EXECUTING); try { // 5. 构建PLC写入参数 Map params = new HashMap<>(); params.put("glassIds", glassIds); params.put("positionCode", context.getParameters().getPositionCode()); params.put("positionValue", context.getParameters().getPositionValue()); params.put("triggerRequest", true); // 6. 执行实际的PLC写入操作 DevicePlcVO.OperationResult plcResult = deviceInteractionService.executeOperation( selectedDevice.getId(), "feedGlass", params ); // 7. 检查PLC写入结果 if (plcResult == null || !Boolean.TRUE.equals(plcResult.getSuccess())) { String errorMsg = plcResult != null ? plcResult.getMessage() : "PLC写入操作返回空结果"; // 执行失败,恢复为空闲状态 statusManager.updateVehicleStatus(selectedDeviceId, VehicleState.IDLE); return InteractionResult.fail("PLC写入失败: " + errorMsg); } // 8. 更新车辆位置信息(如果有) if (context.getParameters().getPositionCode() != null || context.getParameters().getPositionValue() != null) { com.mes.interaction.vehicle.model.VehicleStatus vehicleStatus = statusManager.getOrCreateVehicleStatus( selectedDeviceId, selectedDevice.getDeviceName()); VehiclePosition position = new VehiclePosition( context.getParameters().getPositionCode(), context.getParameters().getPositionValue()); vehicleStatus.setCurrentPosition(position); } // 9. 执行大车设备操作(数据流转) List copied = new ArrayList<>(glassIds); context.setLoadedGlassIds(copied); context.getSharedData().put("glassesFromVehicle", copied); context.getSharedData().put("loadVehicleTime", System.currentTimeMillis()); context.getSharedData().put("selectedVehicleId", selectedDeviceId); context.getSharedData().put("selectedVehicleName", selectedDevice.getDeviceName()); // 10. 后置条件检查 if (context.getLoadedGlassIds().isEmpty()) { statusManager.updateVehicleStatus(selectedDeviceId, VehicleState.IDLE); return InteractionResult.fail("大车设备操作失败:玻璃ID列表为空"); } // 11. 构建返回数据 Map data = new HashMap<>(); data.put("loaded", copied); data.put("glassCount", copied.size()); data.put("deviceId", selectedDevice.getId()); data.put("deviceCode", selectedDevice.getDeviceCode()); data.put("deviceName", selectedDevice.getDeviceName()); data.put("deviceIdString", selectedDeviceId); data.put("plcResult", plcResult.getMessage()); // 注意:这里不立即恢复为空闲状态,因为实际执行可能需要时间 // 真正的状态恢复应该在任务完成后通过回调或状态查询来更新 // 或者可以通过异步任务在后台监控PLC状态,确认完成后再恢复 log.info("大车设备交互执行成功: deviceId={}, deviceName={}, glassCount={}", selectedDeviceId, selectedDevice.getDeviceName(), copied.size()); return InteractionResult.success(data); } catch (Exception e) { // 发生异常时,恢复为空闲状态 statusManager.updateVehicleStatus(selectedDeviceId, VehicleState.ERROR); log.error("大车设备交互执行异常: deviceId={}", selectedDeviceId, e); throw e; } } catch (Exception e) { return InteractionResult.fail("大车设备交互执行异常: " + e.getMessage()); } } /** * 从上下文中提取设备组ID */ private Long extractGroupId(InteractionContext context) { // 尝试从共享数据中获取 Map sharedData = context.getSharedData(); if (sharedData != null) { Object groupIdObj = sharedData.get("groupId"); if (groupIdObj instanceof Number) { return ((Number) groupIdObj).longValue(); } else if (groupIdObj instanceof String) { try { return Long.parseLong((String) groupIdObj); } catch (NumberFormatException ignored) { } } } // 尝试从任务参数中获取 if (context.getParameters() != null && context.getParameters().getExtra() != null) { Object groupIdObj = context.getParameters().getExtra().get("groupId"); if (groupIdObj instanceof Number) { return ((Number) groupIdObj).longValue(); } } return null; } @Override public boolean supportsOperation(String operation) { // 支持所有操作,但主要关注 feedGlass return true; } }