|
|
|
|
@ -8,6 +8,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
|
|
|
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
|
|
|
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
|
|
|
import cn.iocoder.yudao.framework.common.util.opc.OpcUtils;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductUnitMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.controller.admin.device.enums.DeviceRateTrendPeriodEnum;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.controller.admin.device.enums.DeviceStatusEnum;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.utils.CronExpressionUtils;
|
|
|
|
|
@ -45,6 +47,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceAttributeDO;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceAttributeMapper;
|
|
|
|
|
|
|
|
|
|
import cn.iocoder.yudao.module.iot.framework.mqtt.consumer.IMqttservice;
|
|
|
|
|
import cn.iocoder.yudao.module.iot.util.MapListStatsCalculator;
|
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
|
|
@ -54,6 +57,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
|
import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
import org.apache.commons.lang.math.NumberUtils;
|
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Qualifier;
|
|
|
|
|
@ -65,9 +69,13 @@ import org.springframework.validation.annotation.Validated;
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
|
|
import java.sql.Timestamp;
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
|
import java.time.LocalDate;
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
import java.time.LocalTime;
|
|
|
|
|
import java.time.*;
|
|
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
import java.util.function.Function;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
@ -128,12 +136,17 @@ public class DeviceServiceImpl implements DeviceService {
|
|
|
|
|
@Resource
|
|
|
|
|
private IMqttservice mqttService;
|
|
|
|
|
|
|
|
|
|
@Resource
|
|
|
|
|
private ErpProductUnitMapper productUnitMapper;
|
|
|
|
|
|
|
|
|
|
// @Resource
|
|
|
|
|
// private GatewayService gatewayService;
|
|
|
|
|
|
|
|
|
|
@Resource
|
|
|
|
|
private GatewayMapper gatewayMapper;
|
|
|
|
|
|
|
|
|
|
private static final String[] colors = new String[]{"#4888FF", "#00B42A", "#722ED1", "#FF7D00", "#F53F3F", "#86909C", "#FF7D00",
|
|
|
|
|
"#13A8A8","#7C3AED","#EF4444","#10B981","#FF9800","#4F46E5","#E11D48","#22C55E","#F97316","#9333EA","#F87171","#34D399","#FBBF24","#A855F7","#F87171","#FBBF24","#A855F7","#F87171","#FBBF24","#A855F7","#F871"};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
@ -972,6 +985,197 @@ public class DeviceServiceImpl implements DeviceService {
|
|
|
|
|
return resultMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List<Map<String, Object>> singleDeviceFrom(Long deviceId) {
|
|
|
|
|
Map<String, List<Map<String, Object>>> resultMap = new LinkedHashMap<>();
|
|
|
|
|
List<Map<String, Object>> resultList = new ArrayList<>();
|
|
|
|
|
List<DeviceContactModelDO> records = deviceContactModelMapper.selectList(Wrappers.<DeviceContactModelDO>lambdaQuery()
|
|
|
|
|
.eq(DeviceContactModelDO::getDeviceId,deviceId)
|
|
|
|
|
.orderByDesc(DeviceContactModelDO::getId));
|
|
|
|
|
|
|
|
|
|
if (records == null || records.isEmpty()) {
|
|
|
|
|
return resultList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 获取最新一行数据
|
|
|
|
|
Map<String, Object> latestRow = tdengineService.newSelectLatestRow(deviceId);
|
|
|
|
|
if (latestRow == null || latestRow.isEmpty()) {
|
|
|
|
|
return resultList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 属性类型映射
|
|
|
|
|
Map<Long, String> idToNameMap = deviceAttributeTypeMapper.selectList()
|
|
|
|
|
.stream()
|
|
|
|
|
.collect(Collectors.toMap(
|
|
|
|
|
DeviceAttributeTypeDO::getId,
|
|
|
|
|
DeviceAttributeTypeDO::getName
|
|
|
|
|
));
|
|
|
|
|
Map<Long, String> attributeTypeCache = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
// 遍历 records 填充数据
|
|
|
|
|
for (DeviceContactModelDO record : records) {
|
|
|
|
|
|
|
|
|
|
String attributeCode = record.getAttributeCode();
|
|
|
|
|
if (attributeCode == null) continue;
|
|
|
|
|
|
|
|
|
|
Object rawValue = latestRow.get(attributeCode);
|
|
|
|
|
|
|
|
|
|
Object finalValue = DataTypeParseUtil.parse(rawValue, record.getDataType());
|
|
|
|
|
|
|
|
|
|
record.setAddressValue(finalValue);
|
|
|
|
|
|
|
|
|
|
// 属性类型名称
|
|
|
|
|
String attributeTypeName = "其他";
|
|
|
|
|
Object typeObj = record.getAttributeType();
|
|
|
|
|
if (typeObj != null) {
|
|
|
|
|
String typeStr = typeObj.toString();
|
|
|
|
|
try {
|
|
|
|
|
Long typeId = Long.parseLong(typeStr);
|
|
|
|
|
attributeTypeName = attributeTypeCache.computeIfAbsent(typeId,
|
|
|
|
|
k -> idToNameMap.getOrDefault(typeId, typeStr));
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
attributeTypeName = typeStr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Map<String, Object> simplifiedData = new HashMap<>();
|
|
|
|
|
simplifiedData.put("value", record.getAddressValue());
|
|
|
|
|
simplifiedData.put("label", record.getAttributeName());
|
|
|
|
|
simplifiedData.put("prop", "parpmeter_" + record.getId());
|
|
|
|
|
resultMap.computeIfAbsent(attributeTypeName, k -> new ArrayList<>()).add(simplifiedData);
|
|
|
|
|
}
|
|
|
|
|
if (!resultMap.isEmpty()) {
|
|
|
|
|
AtomicInteger a= new AtomicInteger(0);
|
|
|
|
|
resultMap.forEach((key, value) -> {
|
|
|
|
|
HashMap<String, Object> objectObjectHashMap = new HashMap<>();
|
|
|
|
|
objectObjectHashMap.put("id", a.incrementAndGet());
|
|
|
|
|
objectObjectHashMap.put("title", key);
|
|
|
|
|
objectObjectHashMap.put("items", value);
|
|
|
|
|
resultList.add(objectObjectHashMap);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.warn("处理设备 {} 最新数据时异常: {}", deviceId, e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resultList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List<Map<String, Object>> getDeviceAttributeGroupList(DeviceContactModelPageReqVO deviceModelAttributePageReqVO) {
|
|
|
|
|
//Map<String, List<Map<String, Object>>> resultMap = new LinkedHashMap<>();
|
|
|
|
|
List<Map<String, Object>> resultList = new ArrayList<>();
|
|
|
|
|
// 参数校验
|
|
|
|
|
if (deviceModelAttributePageReqVO.getDeviceId() == null) {
|
|
|
|
|
throw exception(DEVICE_ID_MODEL_NOT_EXISTS);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
//查询采集设备
|
|
|
|
|
DeviceDO deviceDO = deviceMapper.selectById(deviceModelAttributePageReqVO.getDeviceId());
|
|
|
|
|
// 判断设备模型ID是否有效
|
|
|
|
|
List<DeviceContactModelDO> deviceModelAttributeDOPageResult = deviceContactModelMapper.selectListById(deviceModelAttributePageReqVO);
|
|
|
|
|
if(CollUtil.isNotEmpty(deviceModelAttributeDOPageResult)){
|
|
|
|
|
List<String> typeNames = deviceModelAttributeDOPageResult.stream().map(DeviceContactModelDO::getTypeName).distinct().collect(Collectors.toList());
|
|
|
|
|
List<String> codes = deviceModelAttributeDOPageResult.stream().map(DeviceContactModelDO::getAttributeCode).distinct().collect(Collectors.toList());
|
|
|
|
|
Map<String, List<DeviceContactModelDO>> resultMap = deviceModelAttributeDOPageResult.stream().filter(d -> d.getTypeName() != null).collect(Collectors.groupingBy(DeviceContactModelDO::getTypeName));
|
|
|
|
|
resultMap.forEach((key, value) -> {
|
|
|
|
|
HashMap<String, Object> objectObjectHashMap = new HashMap<>();
|
|
|
|
|
objectObjectHashMap.put("group", key);
|
|
|
|
|
objectObjectHashMap.put("typeNames", typeNames);
|
|
|
|
|
objectObjectHashMap.put("codes", codes);
|
|
|
|
|
List<Map<String,Object>> objects = new ArrayList<>();
|
|
|
|
|
value.stream().forEach(item -> {
|
|
|
|
|
Map<String, Object> objectObjectHashMap1 = new HashMap<>();
|
|
|
|
|
objectObjectHashMap1.put("name", item.getAttributeName());
|
|
|
|
|
objectObjectHashMap1.put("code", item.getAttributeCode());
|
|
|
|
|
objects.add(objectObjectHashMap1);
|
|
|
|
|
});
|
|
|
|
|
objectObjectHashMap.put("points", objects);
|
|
|
|
|
objectObjectHashMap.put("deviceDO", deviceDO);
|
|
|
|
|
resultList.add(objectObjectHashMap);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return resultList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Map<String, Object> historyAnalyse(Long deviceId, String collectionStartTime, String collectionEndTime, List<String> attributeCodes) {
|
|
|
|
|
|
|
|
|
|
if (deviceId == null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
List<DeviceContactModelDO> deviceContactModelDOS = deviceContactModelMapper.selectList(Wrappers.lambdaQuery(DeviceContactModelDO.class).eq(DeviceContactModelDO::getDeviceId, deviceId));
|
|
|
|
|
if (attributeCodes == null) {
|
|
|
|
|
attributeCodes=deviceContactModelDOS.stream().map(DeviceContactModelDO::getAttributeCode).collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
//查询所有单位
|
|
|
|
|
List<ErpProductUnitDO> erpProductUnitDOS = productUnitMapper.selectList();
|
|
|
|
|
Map<Long, List<ErpProductUnitDO>> unitMap = erpProductUnitDOS.stream().collect(Collectors.groupingBy(ErpProductUnitDO::getId));
|
|
|
|
|
try {
|
|
|
|
|
// 1. 查询TDengine分页数据
|
|
|
|
|
List<Map<String, Object>> deviceDataList = tdengineService.queryHistoryList(deviceId, collectionStartTime, collectionEndTime,attributeCodes);
|
|
|
|
|
|
|
|
|
|
if (deviceDataList.isEmpty()) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
Map<String, Object> resultMap = new HashMap();
|
|
|
|
|
List<Object> time = deviceDataList.stream().map(map -> map.get("time")).collect(Collectors.toList());
|
|
|
|
|
resultMap.put("time", time);
|
|
|
|
|
|
|
|
|
|
//查询点位
|
|
|
|
|
|
|
|
|
|
Map<String, List<DeviceContactModelDO>> collect = deviceContactModelDOS.stream().collect(Collectors.groupingBy(DeviceContactModelDO::getAttributeCode));
|
|
|
|
|
List<Map<String, Object>> dataMap=new ArrayList<>();
|
|
|
|
|
AtomicInteger a= new AtomicInteger(0);
|
|
|
|
|
attributeCodes.stream().forEach(item-> {
|
|
|
|
|
Map<String, Object> map = new HashMap();
|
|
|
|
|
List<DeviceContactModelDO> deviceContactModelDOS1 = collect.get(item);
|
|
|
|
|
if (CollUtil.isNotEmpty(deviceContactModelDOS1))
|
|
|
|
|
map.put("name", deviceContactModelDOS1.get(0).getAttributeName());
|
|
|
|
|
map.put("type", "line");
|
|
|
|
|
map.put("color", colors[a.incrementAndGet()]);
|
|
|
|
|
map.put("data", deviceDataList.stream().map(map1 -> map1.get(item)).collect(Collectors.toList()));
|
|
|
|
|
dataMap.add(map);
|
|
|
|
|
a.getAndIncrement();
|
|
|
|
|
});
|
|
|
|
|
resultMap.put("series", dataMap);
|
|
|
|
|
resultMap.put("data", deviceDataList);
|
|
|
|
|
|
|
|
|
|
//查询点位的最大值,及最小值及平局值及波动值
|
|
|
|
|
|
|
|
|
|
// 简洁用法
|
|
|
|
|
Map<String, Double> maxValues = MapListStatsCalculator.getMaxValues(deviceDataList, attributeCodes);
|
|
|
|
|
Map<String, Double> minValues = MapListStatsCalculator.getMinValues(deviceDataList, attributeCodes);
|
|
|
|
|
Map<String, Double> avgValues = MapListStatsCalculator.getAvgValues(deviceDataList, attributeCodes);
|
|
|
|
|
Map<String, Double> rangeValues = MapListStatsCalculator.getRangeValues(deviceDataList, attributeCodes);
|
|
|
|
|
List<Map<String, Object>> analyseData=new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
List<String> finalAttributeCodes = attributeCodes;
|
|
|
|
|
deviceContactModelDOS.stream().filter(device -> finalAttributeCodes.contains(device.getAttributeCode())).forEach(item ->{
|
|
|
|
|
Map<String, Object> map = new HashMap();
|
|
|
|
|
map.put("code", item.getAttributeCode());
|
|
|
|
|
map.put("name", item.getAttributeName());
|
|
|
|
|
List<ErpProductUnitDO> erpProductUnitDOS1 = unitMap.get( NumberUtils.toLong(item.getDataUnit(), 0));
|
|
|
|
|
if (CollUtil.isNotEmpty(erpProductUnitDOS1)) map.put("unit", erpProductUnitDOS1.get(0).getName());
|
|
|
|
|
map.put("max", maxValues.get(item.getAttributeCode()));
|
|
|
|
|
map.put("min", minValues.get(item.getAttributeCode()));
|
|
|
|
|
map.put("avg", avgValues.get(item.getAttributeCode()));
|
|
|
|
|
map.put("range", rangeValues.get(item.getAttributeCode()));
|
|
|
|
|
analyseData.add(map);
|
|
|
|
|
});
|
|
|
|
|
resultMap.put("analyseData", analyseData);
|
|
|
|
|
return resultMap;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
|
|
log.error("处理设备历史数据异常", e);
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public PageResult<Map<String, Object>> historyRecord(
|
|
|
|
|
@ -1749,6 +1953,7 @@ public class DeviceServiceImpl implements DeviceService {
|
|
|
|
|
return deviceMapper.selectList(pageReqVO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 按时间区间查询设备整体开机率、稼动率日趋势
|
|
|
|
|
* 一次性查询时间范围内按天、按设备的统计数据,避免按天循环重复查库
|
|
|
|
|
|