|
@@ -0,0 +1,307 @@
|
|
|
+package vip.xiaonuo.coldchain.modular.monitorscreen.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.bean.BeanUtil;
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import jakarta.annotation.Resource;
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
|
|
|
+import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
|
|
|
+import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarm;
|
|
|
+import vip.xiaonuo.coldchain.core.alarm.service.SensorAlarmService;
|
|
|
+import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
|
|
|
+import vip.xiaonuo.coldchain.modular.app.param.AppDeviceQueryParams;
|
|
|
+import vip.xiaonuo.coldchain.modular.app.param.SensorEchartDataResult;
|
|
|
+import vip.xiaonuo.coldchain.modular.app.service.AppDeviceService;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitordevice.entity.MonitorDevice;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitordevice.service.MonitorDeviceService;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitordevicetype.entity.MonitorDeviceType;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitordevicetype.service.MonitorDeviceTypeService;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitornotice.entity.Trend;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitornotice.param.TrendParam;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitorscreen.dto.RegionDto;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitorscreen.dto.SensorAlarmDto;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitorscreen.dto.TrendDto;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitorscreen.param.AlarmTimeParam;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitorscreen.service.MonitorService;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitortarget.entity.MonitorTarget;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitortarget.service.MonitorTargetService;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitortargetregion.entity.MonitorTargetRegion;
|
|
|
+import vip.xiaonuo.coldchain.modular.monitortargetregion.service.MonitorTargetRegionService;
|
|
|
+import vip.xiaonuo.common.enums.CommonDeleteFlagEnum;
|
|
|
+import vip.xiaonuo.common.pojo.CommonResult;
|
|
|
+
|
|
|
+import java.text.DecimalFormat;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.time.Duration;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+import java.util.function.Function;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class MonitorServiceImpl implements MonitorService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private MonitorTargetRegionService monitorTargetRegionService;
|
|
|
+ @Resource
|
|
|
+ private MonitorDeviceService monitorDeviceService;
|
|
|
+ @Resource
|
|
|
+ private SensorAlarmService sensorAlarmService;
|
|
|
+ @Resource
|
|
|
+ private AppDeviceService appDeviceService;
|
|
|
+ @Resource
|
|
|
+ private MonitorDeviceTypeService monitorDeviceTypeService;
|
|
|
+ @Resource
|
|
|
+ private MonitorTargetService monitorTargetService;
|
|
|
+
|
|
|
+ /*@Override
|
|
|
+ public List<RegionDto> getRegionList() {
|
|
|
+ List<RegionDto> regionDtoList = new ArrayList<>();
|
|
|
+ SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
|
|
|
+ LambdaQueryWrapper<MonitorTargetRegion> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(MonitorTargetRegion::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE)
|
|
|
+ .eq(MonitorTargetRegion::getCreateOrg, loginUser.getOrgId());
|
|
|
+ List<MonitorTargetRegion> regionList = monitorTargetRegionService.list();
|
|
|
+ String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
|
|
+ if (!regionList.isEmpty()) {
|
|
|
+ for (MonitorTargetRegion region : regionList) {
|
|
|
+ RegionDto regionDto = new RegionDto();
|
|
|
+ regionDto.setMonitorTargetRegion(region);
|
|
|
+ SensorData sensorData = monitorDeviceService.queryLatestDataByDeviceIdAndRoads(region.getDeviceCode(), region.getSensorRoute());
|
|
|
+ if (ObjectUtil.isNull(sensorData)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ regionDto.setTemperature(sensorData.getTemperature());
|
|
|
+ regionDto.setHumidity(sensorData.getHumidity());
|
|
|
+ regionDto.setCo2(sensorData.getCo2());
|
|
|
+ regionDto.setTime(time);
|
|
|
+ regionDto.setOrgName(loginUser.getOrgName());
|
|
|
+ regionDtoList.add(regionDto);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return regionDtoList;
|
|
|
+ }*/
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<RegionDto> getRegionList() {
|
|
|
+ SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
|
|
|
+ LambdaQueryWrapper<MonitorTargetRegion> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(MonitorTargetRegion::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE)
|
|
|
+ .eq(MonitorTargetRegion::getCreateOrg, loginUser.getOrgId());
|
|
|
+ List<MonitorTargetRegion> regionList = monitorTargetRegionService.list(queryWrapper); // 修复查询条件
|
|
|
+ List<RegionDto> regionDtoList = new ArrayList<>(regionList.size()); // 预分配容量
|
|
|
+
|
|
|
+ String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); // 时间格式化移至循环外
|
|
|
+ String orgName = loginUser.getOrgName(); // 避免重复调用
|
|
|
+
|
|
|
+ List<MonitorTarget> monitorTargetList = monitorTargetService.myList(true);
|
|
|
+ List<MonitorDeviceType> monitorDeviceTypeList = monitorDeviceTypeService.myList(null);
|
|
|
+
|
|
|
+ regionList.parallelStream().forEach(region -> { // 并行处理
|
|
|
+ RegionDto regionDto = new RegionDto();
|
|
|
+ for (MonitorDeviceType deviceType : monitorDeviceTypeList) {
|
|
|
+ if (region.getModelName().equals(deviceType.getCode())) {
|
|
|
+ regionDto.setDeviceType(deviceType.getName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ regionDto.setMonitorTargetRegion(region);
|
|
|
+
|
|
|
+ for (MonitorTarget monitorTarget : monitorTargetList) {
|
|
|
+ if (monitorTarget.getId().equals(region.getMonitorTargetId())) {
|
|
|
+ switch (monitorTarget.getStatus()) {
|
|
|
+ case "0":
|
|
|
+ default:
|
|
|
+ regionDto.setStatus("正常");
|
|
|
+ break;
|
|
|
+ case "1":
|
|
|
+ regionDto.setStatus("停用");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ SensorData sensorData = monitorDeviceService.queryLatestDataByDeviceIdAndRoads(
|
|
|
+ region.getDeviceCode(), region.getSensorRoute());
|
|
|
+ if (ObjectUtil.isNotNull(sensorData)) {
|
|
|
+ regionDto.setTemperature(sensorData.getTemperature());
|
|
|
+ regionDto.setHumidity(sensorData.getHumidity());
|
|
|
+ regionDto.setCo2(sensorData.getCo2());
|
|
|
+ regionDto.setTime(time);
|
|
|
+ regionDto.setOrgName(orgName);
|
|
|
+ }
|
|
|
+ synchronized (regionDtoList) { // 确保线程安全
|
|
|
+ regionDtoList.add(regionDto);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return regionDtoList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<MonitorDevice> getDeviceList() {
|
|
|
+ SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
|
|
|
+ LambdaQueryWrapper<MonitorDevice> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(MonitorDevice::getCreateOrg, loginUser.getOrgId()).eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE);
|
|
|
+ List<MonitorDevice> monitorDeviceList = monitorDeviceService.list(queryWrapper);
|
|
|
+ List<MonitorDeviceType> monitorDeviceTypeList = monitorDeviceTypeService.myList(null);
|
|
|
+ for (MonitorDevice monitorDevice : monitorDeviceList) {
|
|
|
+ for (MonitorDeviceType deviceType : monitorDeviceTypeList) {
|
|
|
+ if (deviceType.getCode().equals(monitorDevice.getModelName())) {
|
|
|
+ monitorDevice.setTypeName(deviceType.getName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return monitorDeviceList;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<SensorAlarm> getWarningInfo(String s) {
|
|
|
+ List<SensorAlarm> sensorAlarmList = sensorAlarmService.list(getSensorAlarmQueryWrapper(s));
|
|
|
+ // 1. 按deviceId分组
|
|
|
+ Map<String, List<SensorAlarm>> groupedByDevice = sensorAlarmList.stream()
|
|
|
+ .filter(a -> a.getDeviceId() != null && a.getAlarmTime() != null)
|
|
|
+ .collect(Collectors.groupingBy(SensorAlarm::getDeviceId));
|
|
|
+
|
|
|
+ List<SensorAlarm> result = new ArrayList<>();
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+
|
|
|
+ groupedByDevice.forEach((deviceId, group) -> {
|
|
|
+ // 2. 按时间降序排序(最新数据在前)
|
|
|
+ group.sort((a1, a2) -> {
|
|
|
+ LocalDateTime t1 = LocalDateTime.parse(a1.getAlarmTime(), formatter);
|
|
|
+ LocalDateTime t2 = LocalDateTime.parse(a2.getAlarmTime(), formatter);
|
|
|
+ return t2.compareTo(t1); // 降序
|
|
|
+ });
|
|
|
+
|
|
|
+ // 3. 遍历去重逻辑
|
|
|
+ List<SensorAlarm> filteredGroup = new ArrayList<>();
|
|
|
+ LocalDateTime lastTime = null;
|
|
|
+ for (SensorAlarm alarm : group) {
|
|
|
+ LocalDateTime currentTime = LocalDateTime.parse(alarm.getAlarmTime(), formatter);
|
|
|
+ if (lastTime == null) {
|
|
|
+ filteredGroup.add(alarm);
|
|
|
+ lastTime = currentTime;
|
|
|
+ } else {
|
|
|
+ // 计算时间间隔
|
|
|
+ Duration duration = Duration.between(currentTime, lastTime);
|
|
|
+ if (duration.toMinutes() >= 5) { // 间隔≥5分钟则保留
|
|
|
+ filteredGroup.add(alarm);
|
|
|
+ lastTime = currentTime;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ result.addAll(filteredGroup);
|
|
|
+ });
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<SensorAlarmDto> getWarningInfoBar(String s) {
|
|
|
+ LambdaQueryWrapper<SensorAlarm> queryWrapper = getSensorAlarmQueryWrapper(s);
|
|
|
+ List<SensorAlarm> sensorAlarmList = sensorAlarmService.list(queryWrapper);
|
|
|
+
|
|
|
+ //按 sensorCode 分组,并统计不同 type 的告警次数
|
|
|
+ Map<String, Map<String, Long>> stats = sensorAlarmList.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ SensorAlarm::getDeviceId,
|
|
|
+ Collectors.groupingBy(
|
|
|
+ SensorAlarm::getType,
|
|
|
+ Collectors.counting()
|
|
|
+ )
|
|
|
+ ));
|
|
|
+
|
|
|
+ //转换为 SensorAlarmDto 列表
|
|
|
+ return stats.entrySet().stream()
|
|
|
+ .map(entry -> {
|
|
|
+ String deviceId = entry.getKey();
|
|
|
+ Map<String, Long> typeCounts = entry.getValue();
|
|
|
+
|
|
|
+ // 获取第一条记录(用于填充 deviceName 等字段)
|
|
|
+ SensorAlarm sample = sensorAlarmList.stream()
|
|
|
+ .filter(alarm -> alarm.getDeviceId().equals(deviceId))
|
|
|
+ .findFirst()
|
|
|
+ .orElse(null);
|
|
|
+
|
|
|
+ SensorAlarmDto dto = new SensorAlarmDto();
|
|
|
+ dto.setDeviceId(deviceId);
|
|
|
+ if (sample != null) {
|
|
|
+ dto.setDeviceName(sample.getDeviceName()); // 填充 deviceName
|
|
|
+ dto.setSensorRoute(sample.getSensorRoute()); // 填充 sensorRoute
|
|
|
+ }
|
|
|
+
|
|
|
+ // 统计 type 数量
|
|
|
+ typeCounts.forEach((type, count) -> {
|
|
|
+ if (type.equals("0")) {
|
|
|
+ dto.setDataExceptionCount(count.intValue());
|
|
|
+ dto.setDeviceExceptionCount(0);
|
|
|
+ } else if (type.equals("1")) {
|
|
|
+ dto.setDataExceptionCount(0);
|
|
|
+ dto.setDeviceExceptionCount(count.intValue());
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return dto;
|
|
|
+ })
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public TrendDto getTrend(TrendParam trendParam) {
|
|
|
+ MonitorDevice monitorDevice = monitorDeviceService.getById(trendParam.getDeviceId());
|
|
|
+ MonitorTargetRegion oneByDeviceCodeAndSensorNo = monitorTargetRegionService.findOneByDeviceCodeAndSensorNo(monitorDevice.getDeviceCode(), trendParam.getRoads());
|
|
|
+ AppDeviceQueryParams appDeviceQueryParams = new AppDeviceQueryParams();
|
|
|
+ appDeviceQueryParams.setSensorCode(oneByDeviceCodeAndSensorNo.getSensorCode());
|
|
|
+ appDeviceQueryParams.setStartTime(trendParam.getStartTime());
|
|
|
+ appDeviceQueryParams.setEndTime(trendParam.getEndTime());
|
|
|
+ appDeviceQueryParams.setSensorRoute(trendParam.getRoads());
|
|
|
+ appDeviceQueryParams.setAggregationWindow(trendParam.getAggregationWindow());
|
|
|
+ SensorEchartDataResult sensorEchartDataResult = appDeviceService.queryDataByDeviceIdAndRoads(appDeviceQueryParams);
|
|
|
+ List<Float> tList = sensorEchartDataResult.getTemperature().getY();
|
|
|
+ List<Float> hList = sensorEchartDataResult.getHumidity().getY();
|
|
|
+ List<Float> cList = sensorEchartDataResult.getCo2().getY();
|
|
|
+ TrendDto trend = new TrendDto();
|
|
|
+ DecimalFormat df = new DecimalFormat("#.00");
|
|
|
+ trend.setTemperature(tList);
|
|
|
+ trend.setHumidity(hList);
|
|
|
+ trend.setCo2(cList);
|
|
|
+ if (!tList.isEmpty()) {
|
|
|
+ trend.setXData(sensorEchartDataResult.getTemperature().getX());
|
|
|
+ } else if (!hList.isEmpty()) {
|
|
|
+ trend.setXData(sensorEchartDataResult.getHumidity().getX());
|
|
|
+ } else if (!cList.isEmpty()) {
|
|
|
+ trend.setXData(sensorEchartDataResult.getCo2().getX());
|
|
|
+ }
|
|
|
+ return trend;
|
|
|
+ }
|
|
|
+
|
|
|
+ private LambdaQueryWrapper<SensorAlarm> getSensorAlarmQueryWrapper(String s) {
|
|
|
+ SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
|
|
|
+ LambdaQueryWrapper<SensorAlarm> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+ LocalDateTime threshold;
|
|
|
+
|
|
|
+ switch (s) {
|
|
|
+ case "1d":
|
|
|
+ threshold = now.minusDays(1);
|
|
|
+ break;
|
|
|
+ case "3d":
|
|
|
+ threshold = now.minusDays(3);
|
|
|
+ break;
|
|
|
+ case "1w":
|
|
|
+ default:
|
|
|
+ threshold = now.minusWeeks(1);
|
|
|
+ break;
|
|
|
+ case "1m":
|
|
|
+ threshold = now.minusMonths(1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 直接传递LocalDateTime或格式化字符串(根据数据库支持选择)
|
|
|
+ queryWrapper.ge(SensorAlarm::getCreateTime, threshold) // 或 DATE_TIME_FORMATTER.format(threshold)
|
|
|
+ .eq(SensorAlarm::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE)
|
|
|
+ .eq(SensorAlarm::getCreateOrg, loginUser.getOrgId())
|
|
|
+ .orderByDesc(SensorAlarm::getCreateTime);
|
|
|
+ return queryWrapper;
|
|
|
+ }
|
|
|
+}
|