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<String> 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<String, Object> 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<String> 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<String, Object> 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<String, Object> 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;
|
}
|
}
|