package com.mes.interaction.impl; import com.mes.device.entity.DeviceConfig; import com.mes.interaction.BaseDeviceLogicHandler; import com.mes.device.service.DevicePlcOperationService; import com.mes.device.vo.DevicePlcVO; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; /** * 上大车设备逻辑处理器 * * @author mes * @since 2025-01-XX */ @Slf4j @Component public class LoadVehicleLogicHandler extends BaseDeviceLogicHandler { public LoadVehicleLogicHandler(DevicePlcOperationService devicePlcOperationService) { super(devicePlcOperationService); } @Override public String getDeviceType() { return DeviceConfig.DeviceType.LOAD_VEHICLE; } @Override protected DevicePlcVO.OperationResult doExecute( DeviceConfig deviceConfig, String operation, Map params, Map logicParams) { log.info("执行上大车设备操作: deviceId={}, operation={}", deviceConfig.getId(), operation); switch (operation) { case "feedGlass": return handleFeedGlass(deviceConfig, params, logicParams); case "triggerRequest": return handleTriggerRequest(deviceConfig, params, logicParams); case "triggerReport": return handleTriggerReport(deviceConfig, params, logicParams); case "reset": return handleReset(deviceConfig, params, logicParams); default: log.warn("不支持的操作类型: {}", operation); return DevicePlcVO.OperationResult.builder() .success(false) .message("不支持的操作: " + operation) .build(); } } /** * 处理玻璃上料操作 */ private DevicePlcVO.OperationResult handleFeedGlass( DeviceConfig deviceConfig, Map params, Map logicParams) { // 从逻辑参数中获取配置(从 extraParams.deviceLogic 读取) Integer vehicleCapacity = getLogicParam(logicParams, "vehicleCapacity", 6000); Integer glassIntervalMs = getLogicParam(logicParams, "glassIntervalMs", 1000); Boolean autoFeed = getLogicParam(logicParams, "autoFeed", true); Integer maxRetryCount = getLogicParam(logicParams, "maxRetryCount", 5); // 从运行时参数中获取数据(从接口调用时传入) List glassInfos = extractGlassInfos(params); if (glassInfos.isEmpty()) { return DevicePlcVO.OperationResult.builder() .success(false) .message("未提供有效的玻璃信息") .build(); } String positionCode = (String) params.get("positionCode"); Integer positionValue = (Integer) params.get("positionValue"); Boolean triggerRequest = (Boolean) params.getOrDefault("triggerRequest", autoFeed); List plannedGlasses = planGlassLoading(glassInfos, vehicleCapacity, getLogicParam(logicParams, "defaultGlassLength", 2000)); if (plannedGlasses.isEmpty()) { return DevicePlcVO.OperationResult.builder() .success(false) .message("当前玻璃尺寸超出车辆容量,无法装载") .build(); } // 构建写入数据 Map payload = new HashMap<>(); // 写入玻璃ID int plcSlots = Math.min(plannedGlasses.size(), 6); for (int i = 0; i < plcSlots; i++) { String fieldName = "plcGlassId" + (i + 1); payload.put(fieldName, plannedGlasses.get(i).getGlassId()); } payload.put("plcGlassCount", plcSlots); // 写入位置信息 if (positionValue != null) { payload.put("inPosition", positionValue); } else if (positionCode != null) { // 从位置映射中获取位置值 @SuppressWarnings("unchecked") Map positionMapping = getLogicParam(logicParams, "positionMapping", new HashMap<>()); Integer mappedValue = positionMapping.get(positionCode); if (mappedValue != null) { payload.put("inPosition", mappedValue); } } // 自动触发请求字 if (triggerRequest != null && triggerRequest) { payload.put("plcRequest", 1); } String operationName = "上大车-玻璃上料"; if (positionCode != null) { operationName += "(" + positionCode + ")"; } log.info("上大车玻璃上料: deviceId={}, glassCount={}, position={}, plannedGlassIds={}", deviceConfig.getId(), plcSlots, positionCode, plannedGlasses); if (glassIntervalMs != null && glassIntervalMs > 0) { try { Thread.sleep(glassIntervalMs); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } return devicePlcOperationService.writeFields(deviceConfig.getId(), payload, operationName); } /** * 处理触发请求操作 */ private DevicePlcVO.OperationResult handleTriggerRequest( DeviceConfig deviceConfig, Map params, Map logicParams) { Map payload = new HashMap<>(); payload.put("plcRequest", 1); log.info("上大车触发请求: deviceId={}", deviceConfig.getId()); return devicePlcOperationService.writeFields( deviceConfig.getId(), payload, "上大车-触发请求" ); } /** * 处理触发汇报操作 */ private DevicePlcVO.OperationResult handleTriggerReport( DeviceConfig deviceConfig, Map params, Map logicParams) { Map payload = new HashMap<>(); payload.put("plcReport", 1); log.info("上大车触发汇报: deviceId={}", deviceConfig.getId()); return devicePlcOperationService.writeFields( deviceConfig.getId(), payload, "上大车-触发汇报" ); } /** * 处理重置操作 */ private DevicePlcVO.OperationResult handleReset( DeviceConfig deviceConfig, Map params, Map logicParams) { Map payload = new HashMap<>(); payload.put("plcRequest", 0); payload.put("plcReport", 0); log.info("上大车重置: deviceId={}", deviceConfig.getId()); return devicePlcOperationService.writeFields( deviceConfig.getId(), payload, "上大车-重置" ); } @Override public String validateLogicParams(DeviceConfig deviceConfig) { Map logicParams = parseLogicParams(deviceConfig); // 验证必填参数 Integer vehicleCapacity = getLogicParam(logicParams, "vehicleCapacity", null); if (vehicleCapacity == null || vehicleCapacity <= 0) { return "车辆容量(vehicleCapacity)必须大于0"; } Integer glassIntervalMs = getLogicParam(logicParams, "glassIntervalMs", null); if (glassIntervalMs != null && glassIntervalMs < 0) { return "玻璃间隔时间(glassIntervalMs)不能为负数"; } return null; // 验证通过 } @Override public String getDefaultLogicParams() { Map defaultParams = new HashMap<>(); defaultParams.put("vehicleCapacity", 6000); defaultParams.put("glassIntervalMs", 1000); defaultParams.put("autoFeed", true); defaultParams.put("maxRetryCount", 5); defaultParams.put("defaultGlassLength", 2000); Map positionMapping = new HashMap<>(); positionMapping.put("POS1", 1); positionMapping.put("POS2", 2); defaultParams.put("positionMapping", positionMapping); try { return objectMapper.writeValueAsString(defaultParams); } catch (Exception e) { log.error("生成默认逻辑参数失败", e); return "{}"; } } @SuppressWarnings("unchecked") private List extractGlassInfos(Map params) { List result = new ArrayList<>(); Object rawGlassInfos = params.get("glassInfos"); if (rawGlassInfos instanceof List) { List list = (List) rawGlassInfos; for (Object item : list) { GlassInfo info = convertToGlassInfo(item); if (info != null) { result.add(info); } } } if (result.isEmpty()) { List glassIds = (List) params.get("glassIds"); if (glassIds != null) { for (String glassId : glassIds) { result.add(new GlassInfo(glassId, null)); } } } return result; } private GlassInfo convertToGlassInfo(Object source) { if (source instanceof GlassInfo) { return (GlassInfo) source; } if (source instanceof Map) { Map map = (Map) source; Object id = map.get("glassId"); if (id == null) { id = map.get("id"); } if (id == null) { return null; } Integer length = parseLength(map.get("length")); if (length == null) { length = parseLength(map.get("size")); } return new GlassInfo(String.valueOf(id), length); } if (source instanceof String) { return new GlassInfo((String) source, null); } return null; } private Integer parseLength(Object value) { if (value instanceof Number) { return ((Number) value).intValue(); } if (value instanceof String) { try { return Integer.parseInt((String) value); } catch (NumberFormatException ignored) { } } return null; } private List planGlassLoading(List source, int vehicleCapacity, Integer defaultGlassLength) { List planned = new ArrayList<>(); int usedLength = 0; int capacity = Math.max(vehicleCapacity, 1); int fallbackLength = defaultGlassLength != null && defaultGlassLength > 0 ? defaultGlassLength : 2000; for (GlassInfo info : source) { int length = info.getLength() != null && info.getLength() > 0 ? info.getLength() : fallbackLength; if (planned.isEmpty()) { planned.add(info.withLength(length)); usedLength = length; continue; } if (usedLength + length <= capacity) { planned.add(info.withLength(length)); usedLength += length; } else { break; } } return planned; } private static class GlassInfo { private final String glassId; private final Integer length; GlassInfo(String glassId, Integer length) { this.glassId = glassId; this.length = length; } public String getGlassId() { return glassId; } public Integer getLength() { return length; } public GlassInfo withLength(Integer newLength) { return new GlassInfo(this.glassId, newLength); } @Override public String toString() { return glassId; } @Override public int hashCode() { return Objects.hash(glassId, length); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; GlassInfo other = (GlassInfo) obj; return Objects.equals(glassId, other.glassId) && Objects.equals(length, other.length); } } }