|
|
|
|
@ -42,6 +42,7 @@ import com.alibaba.fastjson.JSON;
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
|
|
@ -63,6 +64,7 @@ import java.text.SimpleDateFormat;
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.function.Function;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
|
|
|
@ -1184,91 +1186,110 @@ public class DeviceServiceImpl implements DeviceService {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List<Map<String, Object>> getMultiDeviceAttributes(Long goviewId) {
|
|
|
|
|
|
|
|
|
|
List<Map<String, Object>> result = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 直接从数据库查询deviceIds JSON字符串
|
|
|
|
|
|
|
|
|
|
String deviceIdsJson = deviceMapper.selectDeviceIdsByGoviewId(goviewId);
|
|
|
|
|
if (StringUtils.isBlank(deviceIdsJson)) {
|
|
|
|
|
log.info("No deviceIds found for goviewId: {}", goviewId);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 解析JSON格式的deviceIds
|
|
|
|
|
Map<Long, Set<Long>> deviceAttributeMap = parseDeviceIdsJson(deviceIdsJson);
|
|
|
|
|
if (deviceAttributeMap.isEmpty()) {
|
|
|
|
|
log.warn("No valid device-attribute mapping found for goviewId: {}", goviewId);
|
|
|
|
|
// 1. 解析(允许重复 device)
|
|
|
|
|
List<Map.Entry<Long, Set<Long>>> deviceAttributeList =
|
|
|
|
|
parseDeviceIdsJson(deviceIdsJson);
|
|
|
|
|
|
|
|
|
|
if (CollectionUtils.isEmpty(deviceAttributeList)) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 批量获取所有设备的最新运行记录,减少数据库查询次数
|
|
|
|
|
Map<Long, DeviceOperationRecordDO> latestRecordMap = getLatestDeviceOperationRecords(deviceAttributeMap.keySet());
|
|
|
|
|
// 2. 收集所有 deviceId / attributeId(用于批量查询)
|
|
|
|
|
Set<Long> allDeviceIds = deviceAttributeList.stream()
|
|
|
|
|
.map(Map.Entry::getKey)
|
|
|
|
|
.collect(Collectors.toSet());
|
|
|
|
|
|
|
|
|
|
log.info("Found {} devices with attribute mappings for goviewId {}: {}",
|
|
|
|
|
deviceAttributeMap.size(), goviewId, deviceAttributeMap);
|
|
|
|
|
Set<Long> allAttributeIds = deviceAttributeList.stream()
|
|
|
|
|
.flatMap(e -> e.getValue().stream())
|
|
|
|
|
.collect(Collectors.toSet());
|
|
|
|
|
|
|
|
|
|
// 3. 批量查设备
|
|
|
|
|
Map<Long, DeviceDO> deviceMap = deviceMapper
|
|
|
|
|
.selectBatchIds(allDeviceIds)
|
|
|
|
|
.stream()
|
|
|
|
|
.collect(Collectors.toMap(DeviceDO::getId, Function.identity()));
|
|
|
|
|
|
|
|
|
|
// 4. 批量查属性
|
|
|
|
|
Map<Long, DeviceContactModelDO> attributeMap =
|
|
|
|
|
deviceContactModelMapper.selectList(
|
|
|
|
|
Wrappers.<DeviceContactModelDO>lambdaQuery()
|
|
|
|
|
.in(DeviceContactModelDO::getId, allAttributeIds)
|
|
|
|
|
).stream().collect(Collectors.toMap(
|
|
|
|
|
DeviceContactModelDO::getId,
|
|
|
|
|
Function.identity()
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
// 5. 批量查运行状态
|
|
|
|
|
Map<Long, DeviceOperationRecordDO> latestRecordMap =
|
|
|
|
|
getLatestDeviceOperationRecords(allDeviceIds);
|
|
|
|
|
|
|
|
|
|
// 6. 批量查最新采集数据(需为批量方法)
|
|
|
|
|
Map<Long, Map<Long, Map<String, Object>>> deviceDataMap =
|
|
|
|
|
createDeviceDataMapBatch(allDeviceIds, attributeMap);
|
|
|
|
|
|
|
|
|
|
// 7. 按原始结构组装(不合并重复设备)
|
|
|
|
|
for (Map.Entry<Long, Set<Long>> entry : deviceAttributeList) {
|
|
|
|
|
|
|
|
|
|
// 遍历每个设备ID,获取设备属性数据
|
|
|
|
|
for (Map.Entry<Long, Set<Long>> entry : deviceAttributeMap.entrySet()) {
|
|
|
|
|
Long deviceId = entry.getKey();
|
|
|
|
|
Set<Long> attributeIds = entry.getValue();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 获取设备信息
|
|
|
|
|
DeviceDO device = deviceMapper.selectById(deviceId);
|
|
|
|
|
if (device == null) {
|
|
|
|
|
log.warn("Device not found for ID: {}", deviceId);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
DeviceDO device = deviceMap.get(deviceId);
|
|
|
|
|
if (device == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建设备层级的Map
|
|
|
|
|
Map<String, Object> deviceMap = new HashMap<>();
|
|
|
|
|
deviceMap.put("deviceId", deviceId);
|
|
|
|
|
deviceMap.put("deviceName", device.getDeviceName());
|
|
|
|
|
deviceMap.put("deviceCode", device.getDeviceCode());
|
|
|
|
|
Map<String, Object> deviceResult = new HashMap<>();
|
|
|
|
|
deviceResult.put("deviceId", deviceId);
|
|
|
|
|
deviceResult.put("deviceName", device.getDeviceName());
|
|
|
|
|
deviceResult.put("deviceCode", device.getDeviceCode());
|
|
|
|
|
|
|
|
|
|
// 添加设备运行状态
|
|
|
|
|
String operatingStatus = getDeviceOperatingStatus(deviceId, latestRecordMap);
|
|
|
|
|
deviceMap.put("operatingStatus", operatingStatus);
|
|
|
|
|
String operatingStatus =
|
|
|
|
|
getDeviceOperatingStatus(deviceId, latestRecordMap);
|
|
|
|
|
deviceResult.put("operatingStatus", operatingStatus);
|
|
|
|
|
|
|
|
|
|
// 获取设备属性列表,只查询指定的属性ID
|
|
|
|
|
List<DeviceContactModelDO> attributes = deviceContactModelMapper.selectList(
|
|
|
|
|
Wrappers.<DeviceContactModelDO>lambdaQuery()
|
|
|
|
|
.eq(DeviceContactModelDO::getDeviceId, deviceId)
|
|
|
|
|
.in(DeviceContactModelDO::getId, attributeIds));
|
|
|
|
|
|
|
|
|
|
// 获取设备最新数据
|
|
|
|
|
Map<Long, Map<String, Object>> deviceDataMap = createDeviceDataMap(deviceId);
|
|
|
|
|
|
|
|
|
|
// 创建属性集合
|
|
|
|
|
List<Map<String, Object>> attributeList = new ArrayList<>();
|
|
|
|
|
for (DeviceContactModelDO attribute : attributes) {
|
|
|
|
|
Map<String, Object> attributeData = new HashMap<>();
|
|
|
|
|
attributeData.put("attributeId", attribute.getId());
|
|
|
|
|
attributeData.put("attributeName", attribute.getAttributeName());
|
|
|
|
|
attributeData.put("attributeCode", attribute.getAttributeCode());
|
|
|
|
|
attributeData.put("dataType", attribute.getDataType());
|
|
|
|
|
attributeData.put("dataUnit", attribute.getDataUnit());
|
|
|
|
|
|
|
|
|
|
// 获取最新数据
|
|
|
|
|
Map<String, Object> latestData = deviceDataMap.get(attribute.getId());
|
|
|
|
|
if (latestData != null) {
|
|
|
|
|
attributeData.put("addressValue", adjustByRatio(latestData.get("addressValue"), attribute.getRatio()));
|
|
|
|
|
attributeData.put("latestCollectionTime", latestData.get("timestamp"));
|
|
|
|
|
}
|
|
|
|
|
List<Map<String, Object>> attributeList = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
Map<Long, Map<String, Object>> deviceAttrData =
|
|
|
|
|
deviceDataMap.getOrDefault(deviceId, Collections.emptyMap());
|
|
|
|
|
|
|
|
|
|
for (Long attributeId : attributeIds) {
|
|
|
|
|
|
|
|
|
|
attributeList.add(attributeData);
|
|
|
|
|
DeviceContactModelDO attribute = attributeMap.get(attributeId);
|
|
|
|
|
if (attribute == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将属性集合添加到设备层级
|
|
|
|
|
deviceMap.put("attributes", attributeList);
|
|
|
|
|
Map<String, Object> attrResult = new HashMap<>();
|
|
|
|
|
attrResult.put("attributeId", attribute.getId());
|
|
|
|
|
attrResult.put("attributeName", attribute.getAttributeName());
|
|
|
|
|
attrResult.put("attributeCode", attribute.getAttributeCode());
|
|
|
|
|
attrResult.put("dataType", attribute.getDataType());
|
|
|
|
|
attrResult.put("dataUnit", attribute.getDataUnit());
|
|
|
|
|
|
|
|
|
|
Map<String, Object> latestData = deviceAttrData.get(attributeId);
|
|
|
|
|
if (latestData != null) {
|
|
|
|
|
attrResult.put("addressValue",
|
|
|
|
|
adjustByRatio(latestData.get("addressValue"), attribute.getRatio()));
|
|
|
|
|
attrResult.put("latestCollectionTime", latestData.get("timestamp"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加到结果列表
|
|
|
|
|
result.add(deviceMap);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("Error processing device ID: {} with attributes: {}", deviceId, attributeIds, e);
|
|
|
|
|
// 继续处理其他设备,不中断整体流程
|
|
|
|
|
attributeList.add(attrResult);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deviceResult.put("attributes", attributeList);
|
|
|
|
|
result.add(deviceResult);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("Failed to get multi-device attributes by goviewId: {}", goviewId, e);
|
|
|
|
|
}
|
|
|
|
|
@ -1276,6 +1297,11 @@ public class DeviceServiceImpl implements DeviceService {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Map<Long, Map<Long, Map<String, Object>>> createDeviceDataMapBatch(Set<Long> allDeviceIds, Map<Long, DeviceContactModelDO> deviceContactModelDOMap) {
|
|
|
|
|
return tdengineService.createDeviceDataMapBatch(allDeviceIds,deviceContactModelDOMap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取设备运行状态
|
|
|
|
|
* @param deviceId 设备ID
|
|
|
|
|
@ -1327,74 +1353,60 @@ public class DeviceServiceImpl implements DeviceService {
|
|
|
|
|
* @param deviceIdsJson JSON格式的设备和属性映射字符串
|
|
|
|
|
* @return 设备ID到属性ID集合的映射(已去重)
|
|
|
|
|
*/
|
|
|
|
|
private Map<Long, Set<Long>> parseDeviceIdsJson(String deviceIdsJson) {
|
|
|
|
|
Map<Long, Set<Long>> deviceAttributeMap = new HashMap<>();
|
|
|
|
|
private List<Map.Entry<Long, Set<Long>>> parseDeviceIdsJson(String deviceIdsJson) {
|
|
|
|
|
|
|
|
|
|
List<Map.Entry<Long, Set<Long>>> result = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
if (StringUtils.isBlank(deviceIdsJson)) {
|
|
|
|
|
return deviceAttributeMap;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 使用Jackson解析JSON字符串
|
|
|
|
|
ObjectMapper objectMapper = new ObjectMapper();
|
|
|
|
|
List<Map<String, Object>> deviceAttributeList = objectMapper.readValue(
|
|
|
|
|
deviceIdsJson, new TypeReference<List<Map<String, Object>>>() {});
|
|
|
|
|
|
|
|
|
|
// 遍历解析结果,构建设备-属性映射并去重
|
|
|
|
|
List<Map<String, Object>> deviceAttributeList =
|
|
|
|
|
objectMapper.readValue(deviceIdsJson,
|
|
|
|
|
new TypeReference<List<Map<String, Object>>>() {});
|
|
|
|
|
|
|
|
|
|
for (Map<String, Object> item : deviceAttributeList) {
|
|
|
|
|
try {
|
|
|
|
|
// 提取设备ID
|
|
|
|
|
Object deviceIdObj = item.get("deviceId");
|
|
|
|
|
if (deviceIdObj == null) {
|
|
|
|
|
log.warn("Device ID is null in item: {}", item);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Long deviceId = null;
|
|
|
|
|
if (deviceIdObj instanceof Number) {
|
|
|
|
|
deviceId = ((Number) deviceIdObj).longValue();
|
|
|
|
|
} else {
|
|
|
|
|
deviceId = Long.parseLong(deviceIdObj.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 提取属性ID数组
|
|
|
|
|
List<Long> attributeIds = new ArrayList<>();
|
|
|
|
|
Object attributesIdsObj = item.get("attributesIds");
|
|
|
|
|
if (attributesIdsObj instanceof List) {
|
|
|
|
|
List<?> attributesList = (List<?>) attributesIdsObj;
|
|
|
|
|
for (Object attrIdObj : attributesList) {
|
|
|
|
|
if (attrIdObj instanceof Number) {
|
|
|
|
|
attributeIds.add(((Number) attrIdObj).longValue());
|
|
|
|
|
} else if (attrIdObj != null) {
|
|
|
|
|
try {
|
|
|
|
|
attributeIds.add(Long.parseLong(attrIdObj.toString()));
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
log.warn("Invalid attribute ID: {}", attrIdObj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Object deviceIdObj = item.get("deviceId");
|
|
|
|
|
if (deviceIdObj == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 合并属性ID到现有设备映射中(避免Lambda变量捕获问题)
|
|
|
|
|
Set<Long> existingAttributes = deviceAttributeMap.get(deviceId);
|
|
|
|
|
if (existingAttributes == null) {
|
|
|
|
|
// 如果设备不存在,创建新的属性集合
|
|
|
|
|
Set<Long> newAttributesSet = new HashSet<>(attributeIds);
|
|
|
|
|
deviceAttributeMap.put(deviceId, newAttributesSet);
|
|
|
|
|
} else {
|
|
|
|
|
// 如果设备已存在,将新的属性ID添加到现有集合中
|
|
|
|
|
for (Long attrId : attributeIds) {
|
|
|
|
|
existingAttributes.add(attrId);
|
|
|
|
|
Long deviceId;
|
|
|
|
|
if (deviceIdObj instanceof Number) {
|
|
|
|
|
deviceId = ((Number) deviceIdObj).longValue();
|
|
|
|
|
} else {
|
|
|
|
|
deviceId = Long.parseLong(deviceIdObj.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Set<Long> attributeIds = new HashSet<>();
|
|
|
|
|
|
|
|
|
|
Object attributesIdsObj = item.get("attributesIds");
|
|
|
|
|
if (attributesIdsObj instanceof List) {
|
|
|
|
|
for (Object attrIdObj : (List<?>) attributesIdsObj) {
|
|
|
|
|
if (attrIdObj instanceof Number) {
|
|
|
|
|
attributeIds.add(((Number) attrIdObj).longValue());
|
|
|
|
|
} else if (attrIdObj != null) {
|
|
|
|
|
try {
|
|
|
|
|
attributeIds.add(Long.parseLong(attrIdObj.toString()));
|
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.warn("Error parsing device-attribute item: {}", item, e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 每条记录单独保存,不合并
|
|
|
|
|
result.add(new AbstractMap.SimpleEntry<>(deviceId, attributeIds));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("Error parsing deviceIds JSON: {}", deviceIdsJson, e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return deviceAttributeMap;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|