package com.mes.device.service.impl;
|
|
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.mes.device.entity.DeviceConfig;
|
import com.mes.device.service.DeviceConfigService;
|
import com.mes.device.service.DeviceGroupRelationService;
|
import com.mes.device.service.DevicePlcOperationService;
|
import com.mes.device.util.ConfigJsonHelper;
|
import com.mes.device.vo.DeviceGroupVO;
|
import com.mes.device.vo.DevicePlcVO;
|
import com.mes.service.PlcTestWriteService;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.CollectionUtils;
|
|
import java.time.LocalDateTime;
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.stream.Collectors;
|
|
/**
|
* 设备 PLC 操作服务实现
|
*
|
* @author mes
|
* @since 2025-11-17
|
*/
|
@Slf4j
|
@Service
|
@RequiredArgsConstructor
|
public class DevicePlcOperationServiceImpl implements DevicePlcOperationService {
|
|
private static final String PLC_PROJECT_ID_KEY = "plcProjectId";
|
|
private final DeviceConfigService deviceConfigService;
|
private final DeviceGroupRelationService deviceGroupRelationService;
|
private final PlcTestWriteService plcTestWriteService;
|
private final ObjectMapper objectMapper;
|
|
public static enum PlcOperationType {
|
/** PLC请求操作 */
|
REQUEST("PLC请求", "PLC 请求发送成功", "PLC 请求发送失败"),
|
/** PLC汇报操作 */
|
REPORT("PLC汇报", "PLC 汇报模拟成功", "PLC 汇报模拟失败"),
|
/** PLC重置操作 */
|
RESET("PLC重置", "PLC 状态已重置", "PLC 状态重置失败");
|
|
/** 操作显示名称 */
|
private final String display;
|
/** 操作成功提示信息 */
|
private final String successMsg;
|
/** 操作失败提示信息 */
|
private final String failedMsg;
|
|
/**
|
* 构造方法
|
* @param display 操作显示名称
|
* @param successMsg 成功提示信息
|
* @param failedMsg 失败提示信息
|
*/
|
PlcOperationType(String display, String successMsg, String failedMsg) {
|
this.display = display;
|
this.successMsg = successMsg;
|
this.failedMsg = failedMsg;
|
}
|
}
|
|
@Override
|
public DevicePlcVO.OperationResult triggerRequest(Long deviceId) {
|
return executeOperation(deviceId, PlcOperationType.REQUEST);
|
}
|
|
@Override
|
public List<DevicePlcVO.OperationResult> triggerRequest(List<Long> deviceIds) {
|
return executeBatch(deviceIds, PlcOperationType.REQUEST);
|
}
|
|
@Override
|
public List<DevicePlcVO.OperationResult> triggerRequestByGroup(Long groupId) {
|
return executeBatch(getDeviceIdsByGroup(groupId), PlcOperationType.REQUEST);
|
}
|
|
@Override
|
public DevicePlcVO.OperationResult triggerReport(Long deviceId) {
|
return executeOperation(deviceId, PlcOperationType.REPORT);
|
}
|
|
@Override
|
public List<DevicePlcVO.OperationResult> triggerReport(List<Long> deviceIds) {
|
return executeBatch(deviceIds, PlcOperationType.REPORT);
|
}
|
|
@Override
|
public List<DevicePlcVO.OperationResult> triggerReportByGroup(Long groupId) {
|
return executeBatch(getDeviceIdsByGroup(groupId), PlcOperationType.REPORT);
|
}
|
|
@Override
|
public DevicePlcVO.OperationResult resetDevice(Long deviceId) {
|
return executeOperation(deviceId, PlcOperationType.RESET);
|
}
|
|
@Override
|
public List<DevicePlcVO.OperationResult> resetDevices(List<Long> deviceIds) {
|
return executeBatch(deviceIds, PlcOperationType.RESET);
|
}
|
|
@Override
|
public DevicePlcVO.StatusInfo readStatus(Long deviceId) {
|
DeviceConfig device = deviceConfigService.getDeviceById(deviceId);
|
if (device == null) {
|
return DevicePlcVO.StatusInfo.builder()
|
.deviceId(deviceId)
|
.deviceName("未知设备")
|
.fieldValues(Collections.emptyMap())
|
.timestamp(LocalDateTime.now())
|
.build();
|
}
|
|
try {
|
Map<String, Object> data = plcTestWriteService.readPlcStatusByDevice(deviceId);
|
return DevicePlcVO.StatusInfo.builder()
|
.deviceId(device.getId())
|
.deviceName(device.getDeviceName())
|
.deviceCode(device.getDeviceCode())
|
.projectId(String.valueOf(device.getProjectId()))
|
.fieldValues(data)
|
.timestamp(LocalDateTime.now())
|
.build();
|
} catch (Exception e) {
|
log.error("读取设备 PLC 状态失败, deviceId={}", deviceId, e);
|
return DevicePlcVO.StatusInfo.builder()
|
.deviceId(device.getId())
|
.deviceName(device.getDeviceName())
|
.deviceCode(device.getDeviceCode())
|
.projectId(null)
|
.fieldValues(Collections.emptyMap())
|
.timestamp(LocalDateTime.now())
|
.build();
|
}
|
}
|
|
@Override
|
public List<DevicePlcVO.StatusInfo> readStatusByGroup(Long groupId) {
|
List<Long> deviceIds = getDeviceIdsByGroup(groupId);
|
if (CollectionUtils.isEmpty(deviceIds)) {
|
return Collections.emptyList();
|
}
|
return deviceIds.stream()
|
.map(this::readStatus)
|
.collect(Collectors.toList());
|
}
|
|
private List<DevicePlcVO.OperationResult> executeBatch(List<Long> deviceIds, PlcOperationType type) {
|
if (CollectionUtils.isEmpty(deviceIds)) {
|
return Collections.emptyList();
|
}
|
return deviceIds.stream()
|
.filter(Objects::nonNull)
|
.distinct()
|
.map(id -> executeOperation(id, type))
|
.collect(Collectors.toList());
|
}
|
|
private DevicePlcVO.OperationResult executeOperation(Long deviceId, PlcOperationType type) {
|
DeviceConfig device = deviceConfigService.getDeviceById(deviceId);
|
if (device == null) {
|
return buildResult(deviceId, null, null, type, false, "设备不存在");
|
}
|
|
try {
|
boolean success = invokeOperation(type, deviceId);
|
String message = success ? type.successMsg : type.failedMsg;
|
return buildResult(device.getId(), device, String.valueOf(device.getProjectId()), type, success, message);
|
} catch (Exception e) {
|
log.error("执行 PLC 操作失败, deviceId={}, operation={}", deviceId, type, e);
|
return buildResult(device.getId(), device, null, type, false, e.getMessage());
|
}
|
}
|
|
private boolean invokeOperation(PlcOperationType type, Long deviceId) {
|
switch (type) {
|
case REQUEST:
|
return plcTestWriteService.simulatePlcRequestByDevice(deviceId);
|
case REPORT:
|
return plcTestWriteService.simulatePlcReportByDevice(deviceId);
|
case RESET:
|
return plcTestWriteService.resetPlcByDevice(deviceId);
|
default:
|
return false;
|
}
|
}
|
|
private DevicePlcVO.OperationResult buildResult(Long deviceId, DeviceConfig device, String projectId,
|
PlcOperationType type, boolean success, String message) {
|
return DevicePlcVO.OperationResult.builder()
|
.deviceId(deviceId)
|
.deviceName(device != null ? device.getDeviceName() : "未知设备")
|
.deviceCode(device != null ? device.getDeviceCode() : null)
|
.projectId(projectId)
|
.operation(type.display)
|
.success(success)
|
.message(message)
|
.timestamp(LocalDateTime.now())
|
.build();
|
}
|
|
private List<Long> getDeviceIdsByGroup(Long groupId) {
|
if (groupId == null) {
|
return Collections.emptyList();
|
}
|
try {
|
List<DeviceGroupVO.DeviceInfo> devices = deviceGroupRelationService.getGroupDevices(groupId);
|
if (CollectionUtils.isEmpty(devices)) {
|
return Collections.emptyList();
|
}
|
return devices.stream()
|
.map(DeviceGroupVO.DeviceInfo::getId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toList());
|
} catch (Exception e) {
|
log.error("获取设备组设备失败, groupId={}", groupId, e);
|
return Collections.emptyList();
|
}
|
}
|
|
@Override
|
public DevicePlcVO.OperationResult writeFields(Long deviceId, Map<String, Object> fieldValues, String operationName) {
|
DeviceConfig device = deviceConfigService.getDeviceById(deviceId);
|
if (device == null) {
|
return buildResult(deviceId, null, null, PlcOperationType.REQUEST, false, "设备不存在");
|
}
|
try {
|
boolean success = plcTestWriteService.writeFieldsByDevice(deviceId, fieldValues);
|
String opName = operationName != null ? operationName : "PLC写入";
|
return DevicePlcVO.OperationResult.builder()
|
.deviceId(device.getId())
|
.deviceName(device.getDeviceName())
|
.deviceCode(device.getDeviceCode())
|
.projectId(String.valueOf(device.getProjectId()))
|
.operation(opName)
|
.success(success)
|
.message(success ? opName + "成功" : opName + "失败")
|
.timestamp(LocalDateTime.now())
|
.build();
|
} catch (Exception e) {
|
log.error("写入PLC字段失败, deviceId={}", deviceId, e);
|
return DevicePlcVO.OperationResult.builder()
|
.deviceId(device.getId())
|
.deviceName(device.getDeviceName())
|
.deviceCode(device.getDeviceCode())
|
.projectId(null)
|
.operation(operationName)
|
.success(false)
|
.message(e.getMessage())
|
.timestamp(LocalDateTime.now())
|
.build();
|
}
|
}
|
|
@Override
|
public String resolveProjectId(Long deviceId) {
|
DeviceConfig device = deviceConfigService.getDeviceById(deviceId);
|
if (device == null) {
|
throw new IllegalArgumentException("设备不存在: " + deviceId);
|
}
|
return resolveProjectId(device);
|
}
|
|
private String resolveProjectId(DeviceConfig device) {
|
if (device == null) {
|
throw new IllegalArgumentException("设备信息为空");
|
}
|
|
// 优先从configJson中获取
|
Map<String, Object> configParams = ConfigJsonHelper.parseToMap(device.getConfigJson(), objectMapper);
|
Object plcProjectId = configParams.get(PLC_PROJECT_ID_KEY);
|
if (plcProjectId != null) {
|
return String.valueOf(plcProjectId);
|
}
|
|
// 其次从扩展参数中获取(兼容旧配置)
|
String extra = device.getExtraParams();
|
if (extra != null && !extra.isEmpty()) {
|
try {
|
Map<String, Object> extraParams = objectMapper.readValue(extra, new TypeReference<Map<String, Object>>() {});
|
Object plcProjectIdFromExtra = extraParams.get(PLC_PROJECT_ID_KEY);
|
if (plcProjectIdFromExtra != null) {
|
return String.valueOf(plcProjectIdFromExtra);
|
}
|
} catch (Exception e) {
|
log.warn("解析设备扩展参数失败, deviceId={}", device.getId(), e);
|
}
|
}
|
|
if (device.getProjectId() != null) {
|
return String.valueOf(device.getProjectId());
|
}
|
|
if (device.getDeviceCode() != null && !device.getDeviceCode().isEmpty()) {
|
return device.getDeviceCode();
|
}
|
|
throw new IllegalStateException("无法解析设备的 PLC 项目标识, deviceId=" + device.getId());
|
}
|
|
|
}
|