Browse Source

feat:新增首页统计图接口
pref:优化获取报警最多的10台设备接口
pref:优化获取预警日志分页接口
feat:新增适配RS_WD_WIFI5_C3_Y*_5WL设备
build:新增配置文件,将系统分为work和master两部分

黄渊昊 1 month ago
parent
commit
d52fdb2a91
33 changed files with 551 additions and 115 deletions
  1. 15 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/bean/DataTrendDto.java
  2. 10 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/bean/DataTrendMapperDto.java
  3. 1 1
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/bean/SensorAlarm.java
  4. 16 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/mapper/SensorAlarmMapper.java
  5. 70 23
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/mapper/mapping/SensorAlarmMapper.xml
  6. 4 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/SensorAlarmService.java
  7. 171 29
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/SensorAlarmServiceImpl.java
  8. 2 2
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/check/DefaultSensorAlarmChecker.java
  9. 1 1
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/event/SensorDataEventListener.java
  10. 25 4
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/renke/RenKeService.java
  11. 28 18
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/renke/config/JfcloudColdChainServerAutoConfiguration.java
  12. 1 1
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/renke/config/JfcloudColdChainServerProperties.java
  13. 4 1
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/renke/listener/JfcloudColdChainRenKeDefaultDataListener.java
  14. 10 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/MonitorDataProcessor.java
  15. 2 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/impl/AbsRenkeMonitorDataProcessor.java
  16. 2 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/impl/WifiLowTempRecorderProcessor1.java
  17. 61 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/impl/WifiSuperLowTempRecorderProcessorBattery4.java
  18. 55 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/impl/WifiSuperLowTempRecorderProcessorBatteryY2.java
  19. 16 6
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/airnow/config/MqttConfig.java
  20. 11 2
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/airnow/service/impl/AirNowServiceImpl.java
  21. 3 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/enums/DeviceModelEnum.java
  22. 1 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevicetype/service/DeviceMonitorScheduleService.java
  23. 6 4
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevicetype/service/impl/MonitorDeviceTypeServiceImpl.java
  24. 8 8
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitornotice/service/impl/MonitorNoticeServiceImpl.java
  25. 10 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/controller/SearchHistoryController.java
  26. 1 1
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitortarget/param/MonitorTargetAddParam.java
  27. 1 1
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitortarget/param/MonitorTargetEditParam.java
  28. 5 0
      snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/user/entity/SysUser.java
  29. 2 0
      snowy-web-app/src/main/resources/application-master.properties
  30. 2 0
      snowy-web-app/src/main/resources/application-work.properties
  31. 6 12
      snowy-web-app/src/main/resources/application.properties
  32. 1 1
      snowy-web-app/src/main/resources/logback-spring.xml
  33. BIN
      snowy-web-app/src/main/resources/冷链前端部署nginx.zip

+ 15 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/bean/DataTrendDto.java

@@ -0,0 +1,15 @@
+package vip.xiaonuo.coldchain.core.alarm.bean;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class DataTrendDto {
+    private List<String> xData;
+    private List<Integer> temperatureData;
+    private List<Integer> humidityData;
+    private List<Integer> co2Data;
+    private List<Integer> batteryData;
+    private List<Integer> offlineData;
+}

+ 10 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/bean/DataTrendMapperDto.java

@@ -0,0 +1,10 @@
+package vip.xiaonuo.coldchain.core.alarm.bean;
+
+import lombok.Data;
+
+@Data
+public class DataTrendMapperDto {
+    private Long alarmCount;
+    private String alarmType;
+    private String alarmTime;
+}

+ 1 - 1
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/bean/SensorAlarm.java

@@ -47,7 +47,7 @@ public class SensorAlarm extends OrgEntity {
     private List<SensorAlarmUser> alarmUsers = Lists.newArrayList();
 
     /**
-     * 预警类型(0:数据异常 1:设备离线 2:数据恢复 4:设备上线)
+     * 预警类型(0:数据异常 1:设备离线 2:数据恢复 4:设备上线 5:电量过低)
      */
     @Schema(description = "类型SensorAlarmType")
     private String type;

+ 16 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/mapper/SensorAlarmMapper.java

@@ -7,6 +7,7 @@ import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.ResultType;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.cursor.Cursor;
+import vip.xiaonuo.coldchain.core.alarm.bean.DataTrendMapperDto;
 import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarm;
 import vip.xiaonuo.coldchain.core.alarm.enums.SensorAlarmType;
 import vip.xiaonuo.coldchain.modular.monitorsearchhistory.dto.TopWarningDto;
@@ -43,4 +44,19 @@ public interface SensorAlarmMapper extends BaseMapper<SensorAlarm> {
                      @Param("route") String route,
                      @Param("startDate") String startDate,
                      @Param("endDate") String endDate);
+
+    List<DataTrendMapperDto> countByType(@Param("orgId") String orgId,
+                                         @Param("alarmType") String alarmType,
+                                         @Param("startDate") String startDate,
+                                         @Param("endDate") String endDate);
+
+    List<String> getAlarmTypeList(@Param("orgId") String orgId,
+                                  @Param("type1") String type1,
+                                  @Param("type2") String type2,
+                                  @Param("time") Date time);
+
+    Long countInPage(@Param("orgId") String orgId,
+                     @Param("typeCodes") List<String> typeCodes,
+                     @Param("startTime") Date startTime,
+                     @Param("endTime") Date endTime);
 }

+ 70 - 23
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/mapper/mapping/SensorAlarmMapper.xml

@@ -2,28 +2,75 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="vip.xiaonuo.coldchain.core.alarm.mapper.SensorAlarmMapper">
 
-  <select id="getTop10Warning" resultType="vip.xiaonuo.coldchain.modular.monitorsearchhistory.dto.TopWarningDto">
-    SELECT
-    *
-    FROM
-      (SELECT
+    <select id="getTop10Warning" resultType="vip.xiaonuo.coldchain.modular.monitorsearchhistory.dto.TopWarningDto">
+        SELECT
         COUNT(*) AS totalWarnings,
-        s.device_id as deviceId,
-        r.name as device_name,
-        s.sensor_code as sensorCode,
-        s.sensor_route as sensorRoute
-      FROM sensor_alarm s
-      left join monitor_target_region r
-      on s.device_id = r.id
-      WHERE s.create_time > #{time}
-      AND r.delete_flag = 'NOT_DELETE'
-      AND s.type in
-      <foreach collection="types" item="type" open="(" separator="," close=")">
-        #{type}
-      </foreach>
-      AND s.CREATE_ORG = #{orgId}
-      GROUP BY s.device_id , s.sensor_route) tmp
-    ORDER BY tmp.totalWarnings DESC
-    limit 10
-  </select>
+        s.device_id AS deviceId,
+        r.NAME AS device_name,
+        s.sensor_code AS sensorCode,
+        s.sensor_route AS sensorRoute
+        FROM
+        sensor_alarm s
+        INNER JOIN monitor_target_region r ON s.device_id = r.id
+        AND r.delete_flag = 'NOT_DELETE'
+        WHERE
+        s.create_time > #{time}
+        AND s.type IN
+        <foreach collection="types" item="type" open="(" separator="," close=")">
+            #{type}
+        </foreach>
+        AND s.CREATE_ORG = #{orgId}
+        GROUP BY
+        r.id,
+        s.sensor_code,
+        s.sensor_route,
+        r.NAME
+        ORDER BY
+        totalWarnings DESC
+        LIMIT 10
+    </select>
+
+    <select id="countByType" resultType="vip.xiaonuo.coldchain.core.alarm.bean.DataTrendMapperDto">
+        select COUNT(*) as alarm_count, alarm_type, date (CREATE_TIME) as alarm_time
+        from sensor_alarm
+        WHERE
+            alarm_type like CONCAT('%'
+            , #{alarmType}
+            , '%')
+          and DELETE_FLAG = 'NOT_DELETE'
+          and CREATE_TIME >= #{startDate}
+          and CREATE_TIME
+         &lt; #{endDate}
+          and CREATE_ORG = #{orgId}
+        GROUP BY alarm_type, date(CREATE_TIME)
+        order by alarm_time
+    </select>
+
+    <select id="getAlarmTypeList" resultType="String">
+        SELECT alarm_type
+        FROM sensor_alarm FORCE INDEX(sensoralarm_alarmtype)
+        WHERE delete_flag = 'NOT_DELETE'
+          AND create_org = #{orgId}
+          AND type IN (#{type1}
+            , #{type2})
+          AND create_time >= #{time}
+        GROUP BY alarm_type
+    </select>
+
+    <select id="countInPage" resultType="Long">
+        SELECT COUNT(id) AS total
+        FROM sensor_alarm FORCE INDEX(sensoralarm_page)
+        WHERE DELETE_FLAG = 'NOT_DELETE'
+        AND CREATE_ORG = #{orgId}
+        AND type IN
+        <foreach collection="typeCodes" item="type" open="(" separator="," close=")">
+            #{type}
+        </foreach>
+        <if test="startTime != null">
+            AND CREATE_TIME &gt;= #{startTime}
+        </if>
+        <if test="endTime != null">
+            AND CREATE_TIME &lt;= #{endTime}
+        </if>
+    </select>
 </mapper>

+ 4 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/SensorAlarmService.java

@@ -2,12 +2,14 @@ package vip.xiaonuo.coldchain.core.alarm.service;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
+import vip.xiaonuo.coldchain.core.alarm.bean.DataTrendDto;
 import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarm;
 import vip.xiaonuo.coldchain.core.alarm.enums.SensorAlarmType;
 import vip.xiaonuo.coldchain.modular.app.param.Message;
 import vip.xiaonuo.coldchain.modular.app.param.MessagePageParam;
 import vip.xiaonuo.coldchain.modular.monitornotice.param.MonitorNoticePageParam;
 import vip.xiaonuo.coldchain.modular.monitorsearchhistory.dto.TopWarningDto;
+import vip.xiaonuo.common.pojo.CommonResult;
 
 import java.util.List;
 
@@ -34,4 +36,6 @@ public interface SensorAlarmService extends IService<SensorAlarm> {
      * @return
      */
     List<TopWarningDto> topWarning(List<String> types);
+
+    DataTrendDto getLastWeekDataTrend(String type);
 }

+ 171 - 29
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/SensorAlarmServiceImpl.java

@@ -5,17 +5,24 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.date.StopWatch;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import jakarta.annotation.Resource;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.time.DateUtils;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
+import vip.xiaonuo.auth.core.util.StpClientUtil;
 import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
+import vip.xiaonuo.coldchain.core.alarm.bean.DataTrendDto;
+import vip.xiaonuo.coldchain.core.alarm.bean.DataTrendMapperDto;
 import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarm;
 import vip.xiaonuo.coldchain.core.alarm.enums.SensorAlarmType;
 import vip.xiaonuo.coldchain.core.alarm.mapper.SensorAlarmMapper;
@@ -25,6 +32,7 @@ import vip.xiaonuo.coldchain.modular.app.param.MessageType;
 import vip.xiaonuo.coldchain.modular.monitornotice.param.MonitorNoticePageParam;
 import vip.xiaonuo.coldchain.modular.monitorsearchhistory.dto.TopWarningDto;
 import vip.xiaonuo.common.enums.CommonDeleteFlagEnum;
+import vip.xiaonuo.common.exception.CommonException;
 import vip.xiaonuo.common.page.CommonPageRequest;
 
 import java.text.SimpleDateFormat;
@@ -142,35 +150,150 @@ public class SensorAlarmServiceImpl extends ServiceImpl<SensorAlarmMapper, Senso
 
     @Override
     public List<String> getAlarmTypeList(String type) {
+        // 1. 获取当前用户信息
         SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
-        LambdaQueryWrapper<SensorAlarm> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(SensorAlarm::getCreateOrg, loginUser.getOrgId())
-                .eq(SensorAlarm::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE);
 
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTime(new Date());
-        calendar.add(Calendar.MONTH, -2);
-        queryWrapper.ge(SensorAlarm::getCreateTime,sdf.format(calendar.getTime()));
+        List<String> alarmTypeList = new ArrayList<>();
 
-        if (type.equals("system")) {
-            queryWrapper.and(q -> q.eq(SensorAlarm::getType, SensorAlarmType.SENSOR_OFF_LINE.getDeviceCode())
-                    .or().eq(SensorAlarm::getType, SensorAlarmType.SENSOR_ON_LINE.getDeviceCode()));
+        // 3. 根据类型添加条件
+        if ("system".equals(type)) {
+            alarmTypeList = sensorAlarmMapper.getAlarmTypeList(loginUser.getOrgId(),
+                    SensorAlarmType.SENSOR_OFF_LINE.getDeviceCode(),
+                    SensorAlarmType.SENSOR_ON_LINE.getDeviceCode(),
+                    DateUtils.addMonths(new Date(), -1));
         } else {
-            queryWrapper.and(q -> q.eq(SensorAlarm::getType, SensorAlarmType.DATA_ALARM.getDeviceCode())
-                    .or().eq(SensorAlarm::getType, SensorAlarmType.DATA_RESTORE_ALARM.getDeviceCode()));
+            alarmTypeList = sensorAlarmMapper.getAlarmTypeList(loginUser.getOrgId(),
+                    SensorAlarmType.DATA_ALARM.getDeviceCode(),
+                    SensorAlarmType.DATA_RESTORE_ALARM.getDeviceCode(),
+                    DateUtils.addMonths(new Date(), -1));
         }
-                queryWrapper.groupBy(SensorAlarm::getAlarmType);
-        return list(queryWrapper).stream().map(SensorAlarm::getAlarmType).collect(Collectors.toList());
+
+        return alarmTypeList;
     }
 
     @Override
     public List<TopWarningDto> topWarning(List<String> types) {
         SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
+        Date time = DateUtils.addDays(new Date(), -7);
+        return getBaseMapper().getTop10Warning(loginUser.getOrgId(), types, time);
+    }
+
+    @Override
+    public DataTrendDto getLastWeekDataTrend(String type) {
+        SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        DataTrendDto dataTrendDto = new DataTrendDto();
+
+        // 获取最近一周的数据
         Calendar calendar = Calendar.getInstance();
-        calendar.setTime(new Date());
-        calendar.add(Calendar.DAY_OF_MONTH,-7);
-        return getBaseMapper().getTop10Warning(loginUser.getOrgId(), types, calendar.getTime());
+        calendar.add(Calendar.DAY_OF_MONTH, 1);
+        Date now = calendar.getTime();
+        calendar.add(Calendar.DAY_OF_MONTH, -8);
+        Date lastWeek = calendar.getTime();
+
+        String alarmKeyword = null;
+        // 查询超标或过低数据
+        if (type.equals("1")) {
+            alarmKeyword = "超标";
+        } else if (type.equals("2")) {
+            alarmKeyword = "过低";
+        } else if (type.equals("3")) {
+            alarmKeyword = "电量过低";
+        } else if (type.equals("4")) {
+            alarmKeyword = "设备离线";
+        } else {
+            throw new CommonException("type参数错误");
+        }
+        List<DataTrendMapperDto> dataTrendMapperDtos = sensorAlarmMapper.countByType(
+                loginUser.getOrgId(), alarmKeyword, sdf.format(lastWeek), sdf.format(now));
+
+        // 按日期分组统计数据
+        Map<String, Map<String, Integer>> dateDataMap = new LinkedHashMap<>();
+
+        // 准备7天的日期列表(确保包含所有日期)
+        List<String> dateList = new ArrayList<>();
+        Calendar tempCal = Calendar.getInstance();
+        tempCal.setTime(DateUtils.addDays(lastWeek,1));
+        for (int i = 0; i < 7; i++) {
+            String dateStr = sdf.format(tempCal.getTime());
+            dateList.add(dateStr);
+            dateDataMap.put(dateStr, new HashMap<>());
+            tempCal.add(Calendar.DAY_OF_MONTH, 1);
+        }
+
+        // 填充统计数据
+        boolean hasTemperature = false;
+        boolean hasHumidity = false;
+        boolean hasCo2 = false;
+        boolean hasBattery = false;
+        boolean hasOffline = false;
+
+        for (DataTrendMapperDto dto : dataTrendMapperDtos) {
+            String dateKey = dto.getAlarmTime().substring(0, 10);
+            String alarmType = dto.getAlarmType();
+            int count = dto.getAlarmCount() != null ? dto.getAlarmCount().intValue() : 0;
+
+            Map<String, Integer> typeCountMap = dateDataMap.getOrDefault(dateKey, new HashMap<>());
+
+            if (alarmType.contains("温度")) {
+                typeCountMap.put("temperature", typeCountMap.getOrDefault("temperature", 0) + count);
+                hasTemperature = true;
+            } else if (alarmType.contains("湿度")) {
+                typeCountMap.put("humidity", typeCountMap.getOrDefault("humidity", 0) + count);
+                hasHumidity = true;
+            } else if (alarmType.contains("二氧化碳") || alarmType.contains("CO2")) {
+                typeCountMap.put("co2", typeCountMap.getOrDefault("co2", 0) + count);
+                hasCo2 = true;
+            } else if (alarmType.contains("电量过低")) {
+                typeCountMap.put("battery", typeCountMap.getOrDefault("battery", 0) + count);
+                hasBattery = true;
+            } else if (alarmType.contains("设备离线")) {
+                typeCountMap.put("offline", typeCountMap.getOrDefault("offline", 0) + count);
+                hasOffline = true;
+            }
+
+            dateDataMap.put(dateKey, typeCountMap);
+        }
+
+        // 准备返回数据
+        List<String> xData = new ArrayList<>();
+        List<Integer> yData1 = hasTemperature ? new ArrayList<>() : Collections.emptyList();
+        List<Integer> yData2 = hasHumidity ? new ArrayList<>() : Collections.emptyList();
+        List<Integer> yData3 = hasCo2 ? new ArrayList<>() : Collections.emptyList();
+        List<Integer> yData4 = hasBattery ? new ArrayList<>() : Collections.emptyList();
+        List<Integer> yData5 = hasOffline ? new ArrayList<>() : Collections.emptyList();
+
+        // 按日期顺序填充数据
+        for (String date : dateList) {
+            xData.add(date);
+            Map<String, Integer> counts = dateDataMap.get(date);
+
+            if (hasTemperature) {
+                yData1.add(counts.getOrDefault("temperature", 0));
+            }
+            if (hasHumidity) {
+                yData2.add(counts.getOrDefault("humidity", 0));
+            }
+            if (hasCo2) {
+                yData3.add(counts.getOrDefault("co2", 0));
+            }
+            if (hasBattery) {
+                yData4.add(counts.getOrDefault("battery", 0));
+            }
+            if (hasOffline) {
+                yData5.add(counts.getOrDefault("offline", 0));
+            }
+        }
+
+        // 设置返回对象
+        dataTrendDto.setXData(xData);
+        dataTrendDto.setTemperatureData(yData1);
+        dataTrendDto.setHumidityData(yData2);
+        dataTrendDto.setCo2Data(yData3);
+        dataTrendDto.setBatteryData(yData4);
+        dataTrendDto.setOfflineData(yData5);
+
+        return dataTrendDto;
     }
 
     public Page<SensorAlarm> getSensorAlarmPage(MessagePageParam messagePageParam) {
@@ -209,37 +332,56 @@ public class SensorAlarmServiceImpl extends ServiceImpl<SensorAlarmMapper, Senso
         if (StrUtil.isNotBlank(messagePageParam.getAlarmType())) {
             queryWrapper.lambda().eq(SensorAlarm::getAlarmType, messagePageParam.getAlarmType());
         }
+
+        Calendar calendar = Calendar.getInstance();
         if (StrUtil.isNotBlank(messagePageParam.getEndTime()) && StrUtil.isNotBlank(messagePageParam.getStartTime())) {
             queryWrapper.lambda().ge(SensorAlarm::getCreateTime, DateUtil.parse(messagePageParam.getStartTime(), "yyyy-MM-dd HH:mm:ss"));  // greater than or equal to start time
             queryWrapper.lambda().le(SensorAlarm::getCreateTime, DateUtil.parse(messagePageParam.getEndTime(), "yyyy-MM-dd HH:mm:ss"));  // greater than or equal to start time
         } else {
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-            Calendar calendar = Calendar.getInstance();
             calendar.setTime(new Date());
-            calendar.add(Calendar.MONTH, -2);
+            calendar.add(Calendar.MONTH, -1);
             queryWrapper.lambda().ge(SensorAlarm::getCreateTime,sdf.format(calendar.getTime()));
         }
 
+        Date time = DateUtils.addMonths(new Date(), -1);
+
+        Date startTime = StringUtils.isNotBlank(messagePageParam.getStartTime())
+                ? DateUtil.parse(messagePageParam.getStartTime(), "yyyy-MM-dd HH:mm:ss")
+                : time;
+
+        Date endTime = StringUtils.isNotBlank(messagePageParam.getEndTime())
+                ? DateUtil.parse(messagePageParam.getEndTime(), "yyyy-MM-dd HH:mm:ss")
+                : null;
+
+        long count = sensorAlarmMapper.countInPage(orgId, typeCodes, startTime, endTime);
+
         // 按创建时间降序排序
-        queryWrapper.lambda().orderByDesc(SensorAlarm::getCreateTime);
+        queryWrapper.lambda().orderByDesc(SensorAlarm::getCreateTime).last("limit " + messagePageParam.getSize() * (messagePageParam.getCurrent() - 1) + "," + messagePageParam.getSize() * messagePageParam.getCurrent());
+
+
+        List<SensorAlarm> ids = list(queryWrapper);
         // 执行查询,传入分页对象
-        Page<Object> page = CommonPageRequest.defaultPage();
+        Page<SensorAlarm> page = CommonPageRequest.defaultPage();
         page.setOptimizeCountSql(false);
         page.setSearchCount(false);
-        page.setTotal(count(queryWrapper));
-        Page<SensorAlarm> sensorAlarmPage = this.page(CommonPageRequest.defaultPage(), queryWrapper).setOptimizeCountSql(false);
+        page.setTotal(count);
+        page.setCurrent(messagePageParam.getCurrent());
+        page.setSize(messagePageParam.getSize());
+        page.setRecords(ids);
+//        Page<SensorAlarm> sensorAlarmPage = this.page(CommonPageRequest.defaultPage(), queryWrapper).setOptimizeCountSql(false);
         stopWatch.stop();
 
         List<SensorAlarm> sensorAlarms = new ArrayList<>();
-        if (sensorAlarmPage.getRecords().isEmpty()) {
-            return sensorAlarmPage;
+        if (page.getRecords().isEmpty()) {
+            return page;
         } else {
-            sensorAlarms = listByIds(sensorAlarmPage.getRecords().stream().map(SensorAlarm::getId).collect(Collectors.toList()));
+            sensorAlarms = listByIds(page.getRecords().stream().map(SensorAlarm::getId).collect(Collectors.toList()));
         }
-        sensorAlarmPage.setRecords(sensorAlarms);
+        page.setRecords(sensorAlarms);
 
         log.info(stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
-        return sensorAlarmPage;
+        return page;
     }
 
     private Message convertToMessage(SensorAlarm sensorAlarm) {

+ 2 - 2
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/check/DefaultSensorAlarmChecker.java

@@ -78,12 +78,12 @@ public class DefaultSensorAlarmChecker implements SensorAlarmChecker {
         boolean alarmTriggered = false;
         String time = DATE_FORMAT.format(new Date()); // 获取当前时间
         String unit = getUnit(type);
-        if (noNull(upperThreshold) && value > upperThreshold) {
+        if (noNull(upperThreshold) && value >= upperThreshold) {
             // 超过上限,触发超标报警
             publishAlarm(type + "超标", value, unit, time, upperThreshold, monitorTargetRegion
                     , SensorAlarmType.DATA_ALARM.getDeviceCode());
             alarmTriggered = true;
-        } else if (noNull(lowerThreshold) && value < lowerThreshold) {
+        } else if (noNull(lowerThreshold) && value <= lowerThreshold) {
             // 低于下限,触发低于阈值报警
             publishAlarm(type + "过低", value, unit, time, lowerThreshold, monitorTargetRegion
                     , SensorAlarmType.DATA_ALARM.getDeviceCode());

+ 1 - 1
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/event/SensorDataEventListener.java

@@ -37,7 +37,7 @@ public class SensorDataEventListener {
                 sensorAlarmChecker.checkAlarm(sensorData);
             }
             jfcloudInfluxDBService.writePojo(sensorData);
-//            log.info("成功写入数据到 InfluxDB: {}", sensorData);
+            log.info("成功写入数据到 InfluxDB: {}", sensorData);
         } catch (Exception e) {
             log.error("写入数据到 InfluxDB 时出错: {}", e.getMessage(), e);
         }

+ 25 - 4
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/renke/RenKeService.java

@@ -1,6 +1,9 @@
 package vip.xiaonuo.coldchain.core.renke;
 
 import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.stereotype.Component;
 import rk.netDevice.sdk.p2.ParamItem;
 import rk.netDevice.sdk.p2.RSServer;
@@ -17,7 +20,9 @@ import java.util.List;
 @Component
 @RequiredArgsConstructor
 public class RenKeService {
-    private final RSServer rsServer;
+    //    private final RSServer rsServer;
+    @Autowired(required = false)
+    private RSServer rsServer;
 
     /**
      * 召唤设备参数信息
@@ -26,15 +31,31 @@ public class RenKeService {
      * @return
      */
     public boolean callParamIds(Integer deviceId) {
-        return rsServer.callParamList(deviceId);
+        if (isConnected()) {
+            return rsServer.callParamList(deviceId);
+        }
+        return false;
     }
 
     public boolean callParameters(Integer deviceId, List<Integer> paramIds) {
-        return rsServer.callParam(deviceId, paramIds);
+        if (isConnected()) {
+            return rsServer.callParam(deviceId, paramIds);
+        }
+        return false;
     }
 
     public boolean writeParams(Integer deviceId, List<ParamItem> parameters) {
-        return rsServer.writeParam(deviceId, parameters);
+        if (isConnected()) {
+            return rsServer.writeParam(deviceId, parameters);
+        }
+        return false;
     }
 
+    public RSServer getRsServer() {
+        return rsServer;
+    }
+
+    public boolean isConnected() {
+        return rsServer != null;
+    }
 }

+ 28 - 18
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/renke/config/JfcloudColdChainServerAutoConfiguration.java

@@ -3,12 +3,15 @@ package vip.xiaonuo.coldchain.core.renke.config;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.EnableAsync;
 import rk.netDevice.sdk.p2.IDataListener;
 import rk.netDevice.sdk.p2.RSServer;
 import vip.xiaonuo.coldchain.core.renke.listener.JfcloudColdChainRenKeDefaultDataListener;
@@ -18,6 +21,7 @@ import vip.xiaonuo.coldchain.core.service.dataprocess.handler.impl.RenKeColdChai
 import vip.xiaonuo.coldchain.modular.monitordevice.service.MonitorDeviceService;
 
 import javax.annotation.PreDestroy;
+import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -37,8 +41,7 @@ public class JfcloudColdChainServerAutoConfiguration {
      */
     @Bean
     @ConditionalOnMissingBean
-    public IDataListener defaultRkDataListener(RenKeColdChainDataHandler renKeColdChainDataHandler,
-                                               @Autowired @Lazy MonitorDeviceService monitorDeviceService) {
+    public IDataListener defaultRkDataListener(RenKeColdChainDataHandler renKeColdChainDataHandler, @Autowired @Lazy MonitorDeviceService monitorDeviceService) {
         return new JfcloudColdChainRenKeDefaultDataListener(renKeColdChainDataHandler, monitorDeviceService);
     }
 
@@ -54,19 +57,22 @@ public class JfcloudColdChainServerAutoConfiguration {
     @ConditionalOnMissingBean
     @SneakyThrows
     public RSServer jfcloudColdChainServer(JfcloudColdChainServerProperties properties, IDataListener dataListener) {
-        // 初始化 RSServer,并注入数据监听器
-        String paramFilePath = ParamFileUtil.copyParamDatFileFromJarToCurrentDirectory();
-        rsServer = RSServer.Initiate(properties.getPort(), paramFilePath);
-        rsServer.addDataListener(dataListener);
-        log.info("""
-                ----------------------------------------------------------
-                冷链通信服务(JfcloudColdChainServer)正在启动, Access URLs:
-                访问地址:    tcp://{}:{}
-                ----------------------------------------------------------
-                """, IPUtil.getIp(), properties.getPort());
-        // 异步启动 RSServer,避免阻塞主线程
-        startJfcloudColdChainServerAsync(rsServer);
-        return rsServer;
+        if ((Objects.nonNull(properties.getPort()) && properties.getPort() > 0)) {
+            // 初始化 RSServer,并注入数据监听器
+            String paramFilePath = ParamFileUtil.copyParamDatFileFromJarToCurrentDirectory();
+            rsServer = RSServer.Initiate(properties.getPort(), paramFilePath);
+            rsServer.addDataListener(dataListener);
+            log.info("""
+                    ----------------------------------------------------------
+                    冷链通信服务(JfcloudColdChainServer)正在启动, Access URLs:
+                    访问地址:    tcp://{}:{}
+                    ----------------------------------------------------------
+                    """, IPUtil.getIp(), properties.getPort());
+            // 异步启动 RSServer,避免阻塞主线程
+            startJfcloudColdChainServerAsync(rsServer);
+            return rsServer;
+        }
+        return null;
     }
 
     /**
@@ -75,11 +81,15 @@ public class JfcloudColdChainServerAutoConfiguration {
      * @param rsServer 要启动的 RSServer 实例
      */
     @Async("coldChainAsyncTask")
-    public void startJfcloudColdChainServerAsync(RSServer rsServer) {
+    public void startJfcloudColdChainServerAsync(@Autowired(required = false) RSServer rsServer) {
         executorService.submit(() -> {
             try {
-                rsServer.start();
-                log.info("RSServer 已成功启动");
+                if (rsServer != null) {
+                    rsServer.start();
+                    log.info("RSServer 已成功启动");
+                } else {
+                    log.error("RSServer 未启动");
+                }
             } catch (Exception e) {
                 log.error("RSServer 启动失败", e);
             }

+ 1 - 1
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/renke/config/JfcloudColdChainServerProperties.java

@@ -17,7 +17,7 @@ public class JfcloudColdChainServerProperties {
     /**
      * 配置 RSServer 的端口号,默认为 2404
      */
-    private int port = JfcloudColdChainConstants.SERVER_PORT;
+    private Integer port = JfcloudColdChainConstants.SERVER_PORT;
 
     /**
      * 缓存方式redis/local

+ 4 - 1
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/renke/listener/JfcloudColdChainRenKeDefaultDataListener.java

@@ -1,5 +1,6 @@
 package vip.xiaonuo.coldchain.core.renke.listener;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.json.JSONUtil;
 import lombok.extern.slf4j.Slf4j;
@@ -46,10 +47,12 @@ public class JfcloudColdChainRenKeDefaultDataListener implements IDataListener {
     public void receiveStoreData(StoreData data) {
         log.info("======================== 设备ID: {} ========================================", data.getDeviceId());
         log.info("接收到存储数据: 设备ID = {}", data.getDeviceId());
+        StoreData storeData = BeanUtil.copyProperties(data, StoreData.class);
         data.getNodeList().forEach(nodeData -> log.info("记录ID: {}, 记录时间: {}, 温度: {}, 湿度: {}", nodeData.getNodeId(), nodeData.getRecordTime(), nodeData.getTem(), nodeData.getHum()));
         log.info("*************************************************************************");
         RenKeColdChainMessageData renKeColdChainMessageData = new RenKeColdChainMessageData();
-        renKeColdChainMessageData.setStoreData(data);
+        renKeColdChainMessageData.setStoreData(storeData);
+        log.info("list大小:{}", storeData.getNodeList().size());
         renKeColdChainDataHandler.handleStoreData(renKeColdChainMessageData);
     }
 

+ 10 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/MonitorDataProcessor.java

@@ -42,6 +42,16 @@ public interface MonitorDataProcessor<T> {
      */
     String RS_CO2WS_WIFI_2_2000P = "RS-CO2-2000P-WIFI-2-C3";
 
+    /**
+     * 带电池正负200℃温湿度两路
+     */
+    String RS_WD_WIFI5_C3_Y2_5WL = "RS-WD-WIFI5-C3-Y2-5WL";
+
+    /**
+     * 带电池正负200℃温湿度四路
+     */
+    String RS_WD_WIFI5_C3_Y4_5WL = "RS-WD-WIFI5-C3-Y4-5WL";
+
     Boolean processData(T data);
 
     /**

+ 2 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/impl/AbsRenkeMonitorDataProcessor.java

@@ -125,6 +125,7 @@ public abstract class AbsRenkeMonitorDataProcessor implements MonitorDataProcess
         List<SensorData> rlts = new ArrayList<>();
         int deviceId = storeData.getDeviceId();
         if (deviceId == 0 || storeData.getNodeList() == null || storeData.getNodeList().size() == 0) {
+            log.error("deviceId={}, nodeList={}", deviceId, storeData.getNodeList());
             return null;
         }
         List<NodeData> nodeList = storeData.getNodeList();
@@ -144,6 +145,7 @@ public abstract class AbsRenkeMonitorDataProcessor implements MonitorDataProcess
                 rlts.add(sensorData);
             }
         }
+        log.info("deviceId={}, nodeList={}", deviceId, rlts);
         return rlts;
     }
 

+ 2 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/impl/WifiLowTempRecorderProcessor1.java

@@ -33,6 +33,7 @@ public class WifiLowTempRecorderProcessor1 extends AbsRenkeMonitorDataProcessor
         List<NodeData> nodeList = data.getNodeList();
         final int numNodes = nodeList.size();
         if (numNodes == 0) {
+            log.error("There is no wifi low temperature data");
             return Lists.newArrayList();
         }
         NodeData nodeData = nodeList.get(0);
@@ -43,6 +44,7 @@ public class WifiLowTempRecorderProcessor1 extends AbsRenkeMonitorDataProcessor
         sensorData.setHumidity(floatValue(nodeData.getHum()));
         sensorData.setPlugInStatus(plugInStatus);
         sensorData.setRoads(1);
+        log.info("sensorData: {}", sensorData);
         return Lists.newArrayList(sensorData);
     }
 

+ 61 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/impl/WifiSuperLowTempRecorderProcessorBattery4.java

@@ -0,0 +1,61 @@
+package vip.xiaonuo.coldchain.core.service.dataprocess.dataclean.impl;
+
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
+import rk.netDevice.sdk.p2.NodeData;
+import rk.netDevice.sdk.p2.RealTimeData;
+import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
+import vip.xiaonuo.coldchain.core.service.dataprocess.dataclean.MonitorDataProcessor;
+import vip.xiaonuo.coldchain.core.service.dataprocess.model.PowerEnum;
+import vip.xiaonuo.coldchain.modular.monitordevice.enums.DeviceModelEnum;
+
+import java.util.List;
+
+/**
+ * @author jackzhou
+ * @version 1.0
+ * @project jfcloud-coldchain
+ * @description
+ * @date 2024/11/20 21:25:30
+ */
+@Slf4j
+@Component(MonitorDataProcessor.RS_WD_WIFI5_C3_Y4_5WL)
+public class WifiSuperLowTempRecorderProcessorBattery4 extends AbsRenkeMonitorDataProcessor {
+    public WifiSuperLowTempRecorderProcessorBattery4(ApplicationEventPublisher applicationEventPublisher) {
+        super(applicationEventPublisher);
+    }
+
+    List<SensorData> transRealTimeData2SensorDatas(@NotNull RealTimeData data) {
+        List<NodeData> nodeList = data.getNodeList();
+        final int numNodes = nodeList.size();
+        if (numNodes < 6) {
+            log.error("数据节点数量不够,需要6个节点,但只有{}个", nodeList.size());
+            return null;
+        }
+        List<SensorData> rlt = Lists.newArrayList();
+        // 倒数第二路的温度的值  是电池的电量
+        final float battery = nodeList.get(numNodes - 2).getTem();
+        // 最后一路的温度的值0=电源供电  100 电池供电
+        final String plugInStatus = nodeList.get(numNodes - 1).getTem() < 1 ? PowerEnum.AC.getCode() : PowerEnum.DC.getCode();
+        for (int i = 0; i < 4; i++) {
+            NodeData nodeData = nodeList.get(i);
+            SensorData sensorData = defaultSensorData(data);
+            sensorData.setTemperature(floatValue(nodeData.getTem()));
+            sensorData.setHumidity(floatValue(nodeData.getHum()));
+            //设置路数
+            sensorData.setRoads(nodeData.getNodeId());
+            sensorData.setBattery(battery);
+            sensorData.setPlugInStatus(plugInStatus);
+            rlt.add(sensorData);
+        }
+        return rlt;
+    }
+
+    @Override
+    DeviceModelEnum deviceModel() {
+        return DeviceModelEnum.WIFI_MULTI_PROBE_TEMP_HUMIDITY_RECORDER_4;
+    }
+}

+ 55 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/impl/WifiSuperLowTempRecorderProcessorBatteryY2.java

@@ -0,0 +1,55 @@
+package vip.xiaonuo.coldchain.core.service.dataprocess.dataclean.impl;
+
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
+import rk.netDevice.sdk.p2.NodeData;
+import rk.netDevice.sdk.p2.RealTimeData;
+import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
+import vip.xiaonuo.coldchain.core.service.dataprocess.dataclean.MonitorDataProcessor;
+import vip.xiaonuo.coldchain.core.service.dataprocess.model.PowerEnum;
+import vip.xiaonuo.coldchain.modular.monitordevice.enums.DeviceModelEnum;
+
+import java.util.List;
+
+@Slf4j
+@Component(MonitorDataProcessor.RS_WD_WIFI5_C3_Y2_5WL)
+public class WifiSuperLowTempRecorderProcessorBatteryY2 extends AbsRenkeMonitorDataProcessor {
+    public WifiSuperLowTempRecorderProcessorBatteryY2(ApplicationEventPublisher applicationEventPublisher) {
+        super(applicationEventPublisher);
+    }
+
+    List<SensorData> transRealTimeData2SensorDatas(@NotNull RealTimeData data) {
+        List<NodeData> nodeList = data.getNodeList();
+        final int numNodes = nodeList.size();
+        if (numNodes < 3) {
+            log.error("数据节点数量不够,需要2个节点,但只有{}个", nodeList.size());
+            return null;
+        }
+        List<SensorData> rlt = Lists.newArrayList();
+        // 倒数第二路的温度的值  是电池的电量
+        final float battery = nodeList.get(numNodes - 2).getTem();
+        // 最后一路的温度的值0=电源供电  100 电池供电
+        final String plugInStatus = nodeList.get(numNodes - 1).getTem() < 1 ? PowerEnum.AC.getCode() : PowerEnum.DC.getCode();
+        //前面两路的温湿度
+        for (int i = 0; i < 2; i++) {
+            NodeData nodeData = nodeList.get(i);
+            SensorData sensorData = defaultSensorData(data);
+            sensorData.setTemperature(floatValue(nodeData.getTem()));
+            sensorData.setHumidity(floatValue(nodeData.getHum()));
+            //设置路数
+            sensorData.setRoads(nodeData.getNodeId());
+            sensorData.setBattery(battery);//第三路温度表示电量
+            sensorData.setPlugInStatus(plugInStatus);//第三路温度表示电量
+            rlt.add(sensorData);
+        }
+        return rlt;
+    }
+
+    @Override
+    DeviceModelEnum deviceModel() {
+        return DeviceModelEnum.WIFI_MULTI_PROBE_TEMP_HUMIDITY_RECORDER_2;
+    }
+}

+ 16 - 6
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/airnow/config/MqttConfig.java

@@ -5,6 +5,7 @@ import cn.hutool.json.JSONUtil;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -19,23 +20,32 @@ import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
 import org.springframework.integration.mqtt.support.MqttHeaders;
 import org.springframework.messaging.MessageChannel;
 import org.springframework.messaging.MessageHandler;
+import vip.xiaonuo.coldchain.core.renke.config.JfcloudColdChainServerProperties;
 import vip.xiaonuo.coldchain.modular.airnow.entity.AirNow;
 import vip.xiaonuo.coldchain.modular.airnow.service.AirNowService;
 
+import java.util.Objects;
+
 @Configuration
 @Slf4j
 public class MqttConfig {
 
     // MQTT服务器配置
-    private static final String BROKER_URL = "tcp://coldchain.nzkcloud.com:51883";
-    private static final String USERNAME = "coldchain";
-    private static final String PASSWORD = "C123456";
-    private static final String CLIENT_ID = "springboot-client-" + System.currentTimeMillis();
-
+//    private static final String BROKER_URL = "tcp://coldchain.nzkcloud.com:51883";
+//    private static final String USERNAME = "coldchain";
+//    private static final String PASSWORD = "C123456";
+//    private static final String CLIENT_ID = "springboot-client-" + System.currentTimeMillis();
+    @Value("${mqtt.serverUri}")
+    private String BROKER_URL;
+    @Value("${mqtt.username}")
+    private String USERNAME;
+    @Value("${mqtt.password}")
+    private String PASSWORD;
+    @Value("${mqtt.clientId}")
+    private String CLIENT_ID;
     // 订阅主题 - 所有设备
     @Value("${SUBSCRIBE_TOPIC}")
     private String SUBSCRIBE_TOPIC;
-
     // 发布主题 - 群发所有设备
     @Value("${PUBLISH_TOPIC}")
     private String PUBLISH_TOPIC;

+ 11 - 2
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/airnow/service/impl/AirNowServiceImpl.java

@@ -1,5 +1,6 @@
 package vip.xiaonuo.coldchain.modular.airnow.service.impl;
 
+import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import com.github.jfcloud.influxdb.flux.JfcloudFluxDataService;
@@ -11,9 +12,11 @@ import com.influxdb.query.FluxTable;
 import jakarta.annotation.Resource;
 import lombok.Value;
 import org.apache.poi.ss.formula.functions.T;
+import org.eclipse.paho.client.mqttv3.IMqttAsyncClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
 import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
 import org.springframework.integration.mqtt.support.MqttHeaders;
 import org.springframework.integration.support.MessageBuilder;
@@ -23,9 +26,11 @@ import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import vip.xiaonuo.coldchain.core.alarm.service.check.DefaultSensorAlarmChecker;
 import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
+import vip.xiaonuo.coldchain.core.renke.config.JfcloudColdChainServerProperties;
 import vip.xiaonuo.coldchain.core.service.FluxQueryBuilder;
 import vip.xiaonuo.coldchain.modular.airnow.entity.AirNow;
 import vip.xiaonuo.coldchain.modular.airnow.service.AirNowService;
+
 import java.time.OffsetDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.ZoneOffset;
@@ -48,6 +53,8 @@ public class AirNowServiceImpl implements AirNowService {
     JfcloudFluxDataService jfcloudFluxDataService;
     @Resource
     DefaultSensorAlarmChecker defaultSensorAlarmChecker;
+    @Resource
+    private JfcloudColdChainServerProperties properties;
 
     // 查询传感器数据
     public void querySensorData() {
@@ -146,7 +153,7 @@ public class AirNowServiceImpl implements AirNowService {
                         sensorData.setType(Integer.parseInt(String.valueOf(values.get("_value"))));
                         break;
                 }
-                String deviceId = (String)values.get("device_id");
+                String deviceId = (String) values.get("device_id");
                 sensorData.setDeviceId(deviceId);
             }
         }
@@ -169,6 +176,8 @@ public class AirNowServiceImpl implements AirNowService {
         }
         sensorData.setModelName(airNow.getDevType());
         jfcloudInfluxDBService.writePojo(sensorData);
-        defaultSensorAlarmChecker.checkAlarm(sensorData);
+        if ((Objects.nonNull(properties.getPort()) && properties.getPort() > 0)) {
+            defaultSensorAlarmChecker.checkAlarm(sensorData);
+        }
     }
 }

+ 3 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/enums/DeviceModelEnum.java

@@ -21,8 +21,11 @@ public enum DeviceModelEnum {
     RS_WS_WIFI5_Y2(MonitorDataProcessor.RS_WS_WIFI5_Y2, "WIFI多探头温湿度不带电池(2路)"),
     RS_WS_WIFI5_Y4(MonitorDataProcessor.RS_WS_WIFI5_Y4, "WIFI多探头温湿度不带电池(4路)"),
     RS_CO2WS_WIFI_2_2000P(MonitorDataProcessor.RS_CO2WS_WIFI_2_2000P, "WIFI单二氧化碳指标不带温湿度"),
+    RS_WD_WIFI5_C3_Y2_5WL(MonitorDataProcessor.RS_WD_WIFI5_C3_Y2_5WL, "WIFI多探头单温度变迭记录仪带电池(2路)"),
+    RS_WD_WIFI5_C3_Y4_5WL(MonitorDataProcessor.RS_WD_WIFI5_C3_Y4_5WL, "WIFI多探头单温度变迭记录仪带电池(4路)"),
     DEFAULT(MonitorDataProcessor.RS_WS_DEFAULT, "默认温湿度处理");
 
+
     private final String deviceCode;  // 设备型号
     private final String deviceName;  // 设备名称
 

+ 1 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevicetype/service/DeviceMonitorScheduleService.java

@@ -5,6 +5,7 @@ import jakarta.annotation.PostConstruct;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
 import org.springframework.scheduling.support.CronTrigger;

+ 6 - 4
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevicetype/service/impl/MonitorDeviceTypeServiceImpl.java

@@ -86,10 +86,12 @@ public class MonitorDeviceTypeServiceImpl extends ServiceImpl<MonitorDeviceTypeM
         if (this.getByName(monitorDeviceType.getName())) {
             throw new CommonException("设备名已注册使用:{}", monitorDeviceType.getName());
         }
-        if (monitorDeviceTypeAddParam.getUploadInterval() < 60 && monitorDeviceTypeAddParam.getUploadInterval() >= 1) {
-            monitorDeviceType.setUploadInterval("0 0/" + monitorDeviceTypeAddParam.getUploadInterval() + " * * * ?");
-        } else {
-            throw new CommonException("上传间隔必须在0-60min之间");
+        if (ObjectUtil.isNotNull(monitorDeviceTypeAddParam.getUploadInterval())) {
+            if (monitorDeviceTypeAddParam.getUploadInterval() < 60 && monitorDeviceTypeAddParam.getUploadInterval() >= 1) {
+                monitorDeviceType.setUploadInterval("0 0/" + monitorDeviceTypeAddParam.getUploadInterval() + " * * * ?");
+            } else {
+                throw new CommonException("上传间隔必须在0-60min之间");
+            }
         }
         this.save(monitorDeviceType);
     }

+ 8 - 8
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitornotice/service/impl/MonitorNoticeServiceImpl.java

@@ -193,9 +193,9 @@ public class MonitorNoticeServiceImpl extends ServiceImpl<MonitorNoticeMapper, M
             sensorEchartDataResult.setTemperature(new SensorEchartData(newX, tList));
         }
         if (!hList.isEmpty()) {
-            double hMax = hList.stream().mapToDouble(Number::floatValue).min().getAsDouble();
-            double hMin = hList.stream().mapToDouble(Number::floatValue).max().getAsDouble();
-            double hAvg = hList.stream().mapToDouble(Number::floatValue).min().getAsDouble();
+            double hMax = hList.stream().mapToDouble(Number::floatValue).max().getAsDouble();
+            double hMin = hList.stream().mapToDouble(Number::floatValue).min().getAsDouble();
+            double hAvg = hList.stream().mapToDouble(Number::floatValue).average().getAsDouble();
             trend.setHMax((float) hMax);
             trend.setHMin((float) hMin);
             trend.setHAvg((float) hAvg);
@@ -204,12 +204,12 @@ public class MonitorNoticeServiceImpl extends ServiceImpl<MonitorNoticeMapper, M
             x.forEach(xData -> {
                 newX.add(formatTime(xData));
             });
-            sensorEchartDataResult.setHumidity(new SensorEchartData(newX, tList));
+            sensorEchartDataResult.setHumidity(new SensorEchartData(newX, hList));
         }
         if (!cList.isEmpty()) {
-            double cMax = cList.stream().mapToDouble(Number::floatValue).min().getAsDouble();
-            double cMin = cList.stream().mapToDouble(Number::floatValue).max().getAsDouble();
-            double cAvg = cList.stream().mapToDouble(Number::floatValue).min().getAsDouble();
+            double cMax = cList.stream().mapToDouble(Number::floatValue).max().getAsDouble();
+            double cMin = cList.stream().mapToDouble(Number::floatValue).min().getAsDouble();
+            double cAvg = cList.stream().mapToDouble(Number::floatValue).average().getAsDouble();
             trend.setCMax((float) cMax);
             trend.setCMin((float) cMin);
             trend.setCAvg((float) cAvg);
@@ -218,7 +218,7 @@ public class MonitorNoticeServiceImpl extends ServiceImpl<MonitorNoticeMapper, M
             x.forEach(xData -> {
                 newX.add(formatTime(xData));
             });
-            sensorEchartDataResult.setCo2(new SensorEchartData(newX, tList));
+            sensorEchartDataResult.setCo2(new SensorEchartData(newX, cList));
         }
         trend.setSensorEchartDataResult(sensorEchartDataResult);
         return trend;

+ 10 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/controller/SearchHistoryController.java

@@ -8,6 +8,7 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
+import vip.xiaonuo.coldchain.core.alarm.bean.DataTrendDto;
 import vip.xiaonuo.coldchain.core.alarm.enums.SensorAlarmType;
 import vip.xiaonuo.coldchain.core.alarm.service.SensorAlarmService;
 import vip.xiaonuo.coldchain.modular.monitorsearchhistory.entity.SearchHistory;
@@ -72,4 +73,13 @@ public class SearchHistoryController {
         searchHistoryService.delete(searchHistoryIdParam);
         return CommonResult.ok();
     }
+
+    /**
+     * 获取近七日数据预警次数趋势
+     */
+    @Operation(summary = "获取近七日数据预警次数趋势(type=1读数超标2读数过低3电量过低4设备离线)")
+    @GetMapping("/coldchain/monitornotice/getLastWeekDataTrend")
+    public CommonResult<DataTrendDto> getLastWeekDataTrend(String type) {
+        return CommonResult.data(sensorAlarmService.getLastWeekDataTrend(type));
+    }
 }

+ 1 - 1
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitortarget/param/MonitorTargetAddParam.java

@@ -38,7 +38,7 @@ public class MonitorTargetAddParam {
      * 名称
      */
     @Schema(description = "名称")
-    @Length(min = 1, max = 12)
+    @Length(min = 1, max = 22)
     private String name;
 
     /**

+ 1 - 1
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitortarget/param/MonitorTargetEditParam.java

@@ -46,7 +46,7 @@ public class MonitorTargetEditParam {
      * 名称
      */
     @Schema(description = "名称")
-    @Length(min = 1, max = 12)
+    @Length(min = 1, max = 22)
     private String name;
 
     /**

+ 5 - 0
snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/user/entity/SysUser.java

@@ -205,6 +205,11 @@ public class SysUser extends CommonEntity {
     @TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
     private String openId;
 
+    /** 基础平台id */
+    @Schema(description = "基础平台id")
+    @TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
+    private String jfcloudId;
+
     /** 职位id */
     @Schema(description = "职位id")
     @TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)

+ 2 - 0
snowy-web-app/src/main/resources/application-master.properties

@@ -0,0 +1,2 @@
+server.port=58888
+coldchain.port=0

+ 2 - 0
snowy-web-app/src/main/resources/application-work.properties

@@ -0,0 +1,2 @@
+server.port=58889
+coldchain.port=40404

+ 6 - 12
snowy-web-app/src/main/resources/application.properties

@@ -1,8 +1,3 @@
-#########################################
-# server configuration
-#########################################
-server.port=58888
-
 #########################################
 # spring allow-circular-references
 #########################################
@@ -11,9 +6,8 @@ spring.main.allow-circular-references=true
 #########################################
 # spring profiles configuration
 #########################################
-spring.profiles.active=local
-#spring.profiles.active=test
-#spring.profiles.active=prod
+spring.profiles.active=master
+#spring.profiles.active=work
 
 #########################################
 # multipart configuration
@@ -33,10 +27,10 @@ spring.datasource.dynamic.datasource.master.password=Root123...
 spring.datasource.dynamic.strict=true
 
 # MQTT
-mqtt.serverUri=tcp://coldchain.nzkcloud.com:51183
+mqtt.serverUri=tcp://coldchain.nzkcloud.com:51883
 mqtt.username=coldchain
 mqtt.password=C123456
-mqtt.clientId=springboot_client_${random.uuid}
+mqtt.clientId=springboot-client-${random.uuid}
 SUBSCRIBE_TOPIC=coldchain/airnow/+/post
 PUBLISH_TOPIC=coldchain/airnow/set
 
@@ -143,8 +137,8 @@ spring.data.redis.lettuce.pool.min-idle=0
 #########################################
 # mybatis-plus configuration
 #########################################
-mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
-#mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.slf4j.Slf4jImpl
+#mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
+mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.slf4j.Slf4jImpl
 mybatis-plus.configuration.jdbc-type-for-null=null
 mybatis-plus.global-config.banner=false
 mybatis-plus.global-config.enable-sql-runner=true

+ 1 - 1
snowy-web-app/src/main/resources/logback-spring.xml

@@ -107,7 +107,7 @@
         </appender>
 
         <!--记录到文件时,记录两类一类是error日志,一个是所有日志-->
-        <root level="info">
+        <root level="WARN">
             <appender-ref ref="STDOUT"/>
             <appender-ref ref="FILE_ERROR"/>
             <appender-ref ref="FILE_ALL"/>

BIN
snowy-web-app/src/main/resources/冷链前端部署nginx.zip