Browse Source

feat:新增搜索历史功能模块及相关代码
feat:新增预警恢复/设备离线/设备上线微信模版消息推送
feat:新增根据冰箱状态筛选
feat:新增获取告警类型接口
feat:新增根据告警类型筛选功能

黄渊昊 4 tháng trước cách đây
mục cha
commit
84fe3211ed
39 tập tin đã thay đổi với 595 bổ sung57 xóa
  1. 1 1
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/bean/SensorAlarm.java
  2. 15 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/config/ColdChainAlarmMessageProperties.java
  3. 12 6
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/offline/DeviceOfflineDetectionService.java
  4. 4 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/SensorAlarmService.java
  5. 17 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/SensorAlarmServiceImpl.java
  6. 29 9
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/check/DefaultSensorAlarmChecker.java
  7. 24 9
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/LocalSensorAlarmMessagePushService.java
  8. 6 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/MessagePushService.java
  9. 24 9
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/RedisSensorAlarmMessagePushService.java
  10. 15 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/DingTalkMessagePushService.java
  11. 15 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/EmailPushService.java
  12. 15 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/PushNotificationService.java
  13. 15 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/SMSPushService.java
  14. 55 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/WechatMessagePushService.java
  15. 15 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/WechatMiniMessagePushService.java
  16. 4 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/app/param/AppDevicePageParam.java
  17. 6 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/app/param/MessagePageParam.java
  18. 1 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/app/service/AppDeviceService.java
  19. 10 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitornotice/controller/MonitorNoticeController.java
  20. 6 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitornotice/param/MonitorNoticePageParam.java
  21. 22 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/controller/SearchHistory.java
  22. 59 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/entity/SearchHistoryController.java
  23. 19 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/mapper/SearchHistoryMapper.java
  24. 4 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/mapper/mapping/SearchHistoryMapper.xml
  25. 17 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/param/SearchHistoryAddParam.java
  26. 34 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/param/SearchHistoryIdParam.java
  27. 16 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/service/SearchHistoryService.java
  28. 72 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/service/impl/SearchHistoryServiceImpl.java
  29. 4 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitortarget/mapper/mapping/MonitorTargetMapper.xml
  30. 6 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitortarget/param/MonitorTargetPageParam.java
  31. 5 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/param/AlarmPushParam.java
  32. 9 4
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/param/AlarmRecoverPushParam.java
  33. 4 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/param/OfflinePushParam.java
  34. 4 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/param/OnlinePushParam.java
  35. 18 18
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/utils/PushUtil.java
  36. 4 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/targetroom/entity/TargetRoom.java
  37. 4 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/targetroom/param/TargetRoomAddParam.java
  38. 4 0
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/targetroom/param/TargetRoomEditParam.java
  39. 1 1
      snowy-web-app/src/main/resources/application.properties

+ 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:设备离线)
+     * 预警类型(0:数据异常 1:设备离线 2:数据恢复 4:设备上线)
      */
     @Schema(description = "类型SensorAlarmType")
     private String type;

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

@@ -16,6 +16,10 @@ public class ColdChainAlarmMessageProperties {
             "当前温度:{value} {unit},已低于下限(阈值:{threshold})。\n" +
             "报警时间:{time}";
 
+    private String temperatureRecover = "{deviceName}的温度已恢复正常,\n" +
+            "当前温度:{value} {unit},阈值:{threshold}。\n" +
+            "恢复时间:{time}";
+
     private String humidityOverLimit = "湿度报警:{deviceName}的湿度超标!\n" +
             "当前湿度:{value} {unit},已超出上限(阈值:{threshold})。\n" +
             "报警时间:{time}";
@@ -24,6 +28,10 @@ public class ColdChainAlarmMessageProperties {
             "当前湿度:{value} {unit},已低于下限(阈值:{threshold})。\n" +
             "报警时间:{time}";
 
+    private String humidityRecover = "{deviceName}的湿度已恢复正常,\n" +
+            "当前湿度:{value} {unit},阈值:{threshold}。\n" +
+            "恢复时间:{time}";
+
     private String co2OverLimit = "二氧化碳报警:{deviceName}的二氧化碳浓度超标!\n" +
             "当前浓度:{value} {unit},已超出上限(阈值:{threshold})。\n" +
             "报警时间:{time}";
@@ -32,6 +40,13 @@ public class ColdChainAlarmMessageProperties {
             "当前浓度:{value} {unit},已低于下限(阈值:{threshold})。\n" +
             "报警时间:{time}";
 
+    private String co2Recover = "{deviceName}的二氧化碳浓度已恢复正常,\n" +
+            "当前浓度:{value} {unit},阈值:{threshold}。\n" +
+            "恢复时间:{time}";
+
     private String deviceOfflineLimit = "设备离线:{deviceName}的设备断电或者离线\n" +
             "报警时间:{time}";
+
+    private String deviceOnlineLimit = "设备上线:{deviceName}的设备已上线\n" +
+            "上线时间:{time}";
 }

+ 12 - 6
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/offline/DeviceOfflineDetectionService.java

@@ -10,6 +10,8 @@ import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarm;
 import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarmUser;
 import vip.xiaonuo.coldchain.core.alarm.config.ColdChainAlarmMessageProperties;
 import vip.xiaonuo.coldchain.core.alarm.enums.SensorAlarmType;
+import vip.xiaonuo.coldchain.core.alarm.service.messagepush.LocalSensorAlarmMessagePushService;
+import vip.xiaonuo.coldchain.core.alarm.service.messagepush.RedisSensorAlarmMessagePushService;
 import vip.xiaonuo.coldchain.core.event.SensorAlarmEvent;
 import vip.xiaonuo.coldchain.core.renke.config.JfcloudColdChainServerProperties;
 import vip.xiaonuo.coldchain.modular.monitordevice.service.MonitorDeviceService;
@@ -46,6 +48,7 @@ public class DeviceOfflineDetectionService {
     private final MonitorDeviceService monitorDeviceService;
     private final ColdChainAlarmMessageProperties alarmMessageProperties;
     private final JfcloudColdChainServerProperties jfcloudColdChainServerProperties;
+    private final RedisSensorAlarmMessagePushService redisSensorAlarmMessagePushService;
     private static final String KEY_SPILT = "-";
 
 
@@ -96,9 +99,9 @@ public class DeviceOfflineDetectionService {
     }
 
 
-
     /**
      * 处理设备状态
+     *
      * @param key
      * @param now
      * @param offlineThresholdMinutes
@@ -127,9 +130,13 @@ public class DeviceOfflineDetectionService {
             if (lastReportTime.plusMinutes(offlineThresholdMinutes).isBefore(now)) {
                 status = MonitorStatusEnum.OFF;
                 log.warn("设备 {}-{} 已离线,最后上报时间:{}。", deviceCode, route, lastReportTimeStr);
-                publishAlarm(deviceCode, route, lastReportTimeStr);
+                publishAlarm(deviceCode, route, lastReportTimeStr, "设备离线", SensorAlarmType.SENSOR_OFF_LINE.getDeviceCode());
             } else {
-                // TODO怎么之前是离线才推送它上线
+                // TODO
+                // 怎么之前是离线才推送它上线
+                if (redisSensorAlarmMessagePushService.hasExceededPushLimit("*", deviceCode, route,"设备离线")) {
+                    publishAlarm(deviceCode, route, lastReportTimeStr, "设备上线",SensorAlarmType.SENSOR_ON_LINE.getDeviceCode());
+                }
                 status = MonitorStatusEnum.ONLINE;
                 log.debug("设备 {}-{} 在线,最后上报时间:{}。", deviceCode, route, lastReportTimeStr);
             }
@@ -141,8 +148,7 @@ public class DeviceOfflineDetectionService {
     }
 
 
-
-    private void publishAlarm(String deviceCode, Integer route, String time) {
+    private void publishAlarm(String deviceCode, Integer route, String time, String alarmType, String type) {
         MonitorTargetRegion monitorTargetRegion = monitorTargetRegionService.findOneByDeviceCodeAndSensorNo(deviceCode, route);
         if (Objects.isNull(monitorTargetRegion)) {
             return;
@@ -159,7 +165,6 @@ public class DeviceOfflineDetectionService {
         String sensorCode = monitorTargetRegion.getSensorCode();
         String deviceName = monitorTargetRegion.getName();
         String deviceId = monitorTargetRegion.getId();
-        final String alarmType = "设备离线";
         String alarmMessage = getAlarmMessage(deviceName, time);
         SensorAlarm sensorAlarm = new SensorAlarm();
         sensorAlarm.setAlarmType(alarmType);
@@ -185,6 +190,7 @@ public class DeviceOfflineDetectionService {
         sensorAlarm.setType(SensorAlarmType.SENSOR_OFF_LINE.getDeviceCode());
         sensorAlarm.setCreateOrg(monitorTargetRegion.getCreateOrg());
         sensorAlarm.setRoomName(monitorTargetRegion.getRoomName());
+        sensorAlarm.setType(type);
         log.warn("设备断电报警: 类型: {},详细报警内容 : {}", alarmType, alarmMessage);
         // 发布报警事件
         applicationEventPublisher.publishEvent(new SensorAlarmEvent(this, sensorAlarm));

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

@@ -8,6 +8,8 @@ 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 java.util.List;
+
 /**
  * @author jackzhou
  * @version 1.0
@@ -21,4 +23,6 @@ public interface SensorAlarmService extends IService<SensorAlarm> {
     Page<SensorAlarm> getMessages(MonitorNoticePageParam monitorNoticePageParam);
 
     long countAlarms(String startDate, String endDate, String sensorCode, String sensorRoute, SensorAlarmType type);
+
+    List<String> getAlarmTypeList();
 }

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

@@ -4,12 +4,14 @@ import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 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.enums.SensorAlarmType;
@@ -18,8 +20,10 @@ import vip.xiaonuo.coldchain.modular.app.param.Message;
 import vip.xiaonuo.coldchain.modular.app.param.MessagePageParam;
 import vip.xiaonuo.coldchain.modular.app.param.MessageType;
 import vip.xiaonuo.coldchain.modular.monitornotice.param.MonitorNoticePageParam;
+import vip.xiaonuo.common.enums.CommonDeleteFlagEnum;
 import vip.xiaonuo.common.page.CommonPageRequest;
 
+import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
@@ -90,6 +94,16 @@ public class SensorAlarmServiceImpl extends ServiceImpl<SensorAlarmMapper, Senso
         return this.count(queryWrapper);
     }
 
+    @Override
+    public List<String> getAlarmTypeList() {
+        SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
+        LambdaQueryWrapper<SensorAlarm> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(SensorAlarm::getCreateOrg, loginUser.getOrgId())
+                .eq(SensorAlarm::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE)
+                .groupBy(SensorAlarm::getAlarmType);
+        return list(queryWrapper).stream().map(SensorAlarm::getAlarmType).collect(Collectors.toList());
+    }
+
     public Page<SensorAlarm> getSensorAlarmPage(MessagePageParam messagePageParam) {
         // 创建查询条件
         QueryWrapper<SensorAlarm> queryWrapper = new QueryWrapper<SensorAlarm>().checkSqlInjection();
@@ -120,6 +134,9 @@ public class SensorAlarmServiceImpl extends ServiceImpl<SensorAlarmMapper, Senso
         if (StrUtil.isNotBlank(messagePageParam.getStartTime())) {
             queryWrapper.lambda().le(SensorAlarm::getCreateTime, DateUtil.parse(messagePageParam.getEndTime(), "yyyy-MM-dd HH:mm:ss"));  // greater than or equal to start time
         }
+        if (StrUtil.isNotBlank(messagePageParam.getAlarmType())) {
+            queryWrapper.lambda().eq(SensorAlarm::getAlarmType, messagePageParam.getAlarmType());
+        }
         // 按创建时间降序排序
         queryWrapper.lambda().orderByDesc(SensorAlarm::getCreateTime);
         // 执行查询,传入分页对象

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

@@ -11,6 +11,7 @@ import vip.xiaonuo.coldchain.core.alarm.bean.SensorThreshold;
 import vip.xiaonuo.coldchain.core.alarm.config.ColdChainAlarmMessageProperties;
 import vip.xiaonuo.coldchain.core.alarm.enums.SensorAlarmType;
 import vip.xiaonuo.coldchain.core.alarm.offline.DeviceOfflineDetectionService;
+import vip.xiaonuo.coldchain.core.alarm.service.messagepush.RedisSensorAlarmMessagePushService;
 import vip.xiaonuo.coldchain.core.alarm.service.threshold.SensorThresholdService;
 import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
 import vip.xiaonuo.coldchain.core.event.SensorAlarmEvent;
@@ -29,6 +30,7 @@ public class DefaultSensorAlarmChecker implements SensorAlarmChecker {
     private final SensorThresholdService thresholdService;
     private final ColdChainAlarmMessageProperties alarmMessageProperties;
     private final ApplicationEventPublisher applicationEventPublisher;
+    private final RedisSensorAlarmMessagePushService redisSensorAlarmMessagePushService;
 
     private final DeviceOfflineDetectionService deviceOfflineDetectionService;
 
@@ -78,16 +80,23 @@ public class DefaultSensorAlarmChecker implements SensorAlarmChecker {
         String unit = getUnit(type);
         if (noNull(upperThreshold) && value > upperThreshold) {
             // 超过上限,触发超标报警
-            publishAlarm(type + "超标", value, unit, time, upperThreshold, monitorTargetRegion);
+            publishAlarm(type + "超标", value, unit, time, upperThreshold, monitorTargetRegion
+                    , SensorAlarmType.DATA_ALARM.getDeviceCode());
             alarmTriggered = true;
         } else if (noNull(lowerThreshold) && value < lowerThreshold) {
             // 低于下限,触发低于阈值报警
-            publishAlarm(type + "过低", value, unit, time, lowerThreshold, monitorTargetRegion);
+            publishAlarm(type + "过低", value, unit, time, lowerThreshold, monitorTargetRegion
+                    , SensorAlarmType.DATA_ALARM.getDeviceCode());
             alarmTriggered = true;
-        }else{
+        } else {
+            //todo
             // SensorAlarmType.DATA_RESTORE_ALARM
-            log.info("针对异常设备数据恢复?设备正常");
-
+            if (redisSensorAlarmMessagePushService.hasExceededPushLimit("*", monitorTargetRegion.getDeviceCode(), monitorTargetRegion.getSensorRoute(),type + "??")) {
+                publishAlarm(type + "恢复", value, unit, time, upperThreshold, monitorTargetRegion
+                        , SensorAlarmType.DATA_RESTORE_ALARM.getDeviceCode());
+                alarmTriggered = true;
+                log.info("针对异常设备数据恢复?设备正常");
+            }
         }
         return alarmTriggered;
     }
@@ -100,11 +109,13 @@ public class DefaultSensorAlarmChecker implements SensorAlarmChecker {
      * @param value     传感器数据值
      * @param unit      传感器数据单位
      * @param time      时间戳
+     * @param type      SensorAlarmType
      */
-    private void publishAlarm(String alarmType, Float value, String unit, String time, float threshold, MonitorTargetRegion monitorTargetRegion) {
+    private void publishAlarm(String alarmType, Float value, String unit, String time
+            , float threshold, MonitorTargetRegion monitorTargetRegion, String type) {
         String monitorTargetId = monitorTargetRegion.getMonitorTargetId();
         Integer sensorRoute = monitorTargetRegion.getSensorRoute();
-        String  sensorCode = monitorTargetRegion.getSensorCode();
+        String sensorCode = monitorTargetRegion.getSensorCode();
         String deviceName = monitorTargetRegion.getName();
         String deviceId = monitorTargetRegion.getId();
         String alarmMessage = getAlarmMessage(alarmType, value, unit, deviceName, time, threshold);
@@ -127,8 +138,8 @@ public class DefaultSensorAlarmChecker implements SensorAlarmChecker {
         List<SensorAlarmUser> alarmUsers = monitorTargetRegion.getAlarmUsers();
         sensorAlarm.setAlarmUsers(alarmUsers);
         sensorAlarm.setThreshold(threshold);
-        // 修改TODO
-        sensorAlarm.setType(SensorAlarmType.DATA_ALARM.getDeviceCode());
+        // TODO
+        sensorAlarm.setType(type);
         // 设置报警人机构 所属用户和机构
         sensorAlarm.setCreateUser(monitorTargetRegion.getCreateUser());
         sensorAlarm.setCreateOrg(monitorTargetRegion.getCreateOrg());
@@ -171,6 +182,15 @@ public class DefaultSensorAlarmChecker implements SensorAlarmChecker {
             case "二氧化碳过低":
                 messageTemplate = alarmMessageProperties.getCo2BelowLimit();
                 break;
+            case "温度恢复":
+                messageTemplate = alarmMessageProperties.getTemperatureRecover();
+                break;
+            case "湿度恢复":
+                messageTemplate = alarmMessageProperties.getHumidityRecover();
+                break;
+            case "二氧化碳恢复":
+                messageTemplate = alarmMessageProperties.getCo2Recover();
+                break;
             default:
                 messageTemplate = "{alarmType}: 当前值:{value} {unit}";
                 break;

+ 24 - 9
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/LocalSensorAlarmMessagePushService.java

@@ -42,7 +42,7 @@ public class LocalSensorAlarmMessagePushService {
 
         for (String openid : openids) {
             // 判断该用户对该设备和告警类型的推送是否超过限制
-            if (hasExceededPushLimit(openid, deviceID, alarmType)) {
+            if (hasExceededPushLimit(openid, deviceID,alarm.getSensorRoute(), alarmType)) {
                 log.info("用户 {} 对设备 {} 的告警类型 {} \n在过去{}分钟内推送次数超过限制,跳过推送", openid, deviceID, alarmType, JfcloudColdChainConstants.MESS_PUSH_TIME_WINDOW / 60 / 1000);
                 continue;
             }
@@ -51,7 +51,22 @@ public class LocalSensorAlarmMessagePushService {
                 MessagePushService pushService = pushServices.get(channel.name());
                 if (pushService != null) {
                     try {
-                        boolean b = pushService.sendAlarmMessage(alarm);
+                        boolean b = false;
+                        switch (alarm.getType()) {
+                            case "0":
+                                b = pushService.sendAlarmMessage(alarm);
+                                break;
+                            case "1":
+                                b = pushService.sendAlarmRecoverMessage(alarm);
+                                break;
+                            case "2":
+                                b = pushService.sendOfflineMessage(alarm);
+                                break;
+                            case "4":
+                                b = pushService.sendOnlineMessage(alarm);
+                                break;
+
+                        }
                         // 设置已通知状态
                         alarm.setNotified(b);
                     } catch (Exception e) {
@@ -62,7 +77,7 @@ public class LocalSensorAlarmMessagePushService {
                 }
             }
             // 记录推送时间
-            recordPushTime(openid, deviceID, alarmType);
+            recordPushTime(openid, deviceID, alarm.getSensorRoute() , alarmType);
         }
         // 将告警信息存储到数据库
         saveAlarmToDatabase(alarm);
@@ -76,8 +91,8 @@ public class LocalSensorAlarmMessagePushService {
      * @param alarmType 告警类型
      * @return 是否超过限制
      */
-    private boolean hasExceededPushLimit(String openid, String deviceID, String alarmType) {
-        String key = generatePushHistoryKey(openid, deviceID, alarmType);
+    public boolean hasExceededPushLimit(String openid, String deviceID, Integer sensorRoute, String alarmType) {
+        String key = generatePushHistoryKey(openid, deviceID, sensorRoute, alarmType);
         List<Long> pushTimes = userDeviceAlarmPushHistory.get(key);
         if (pushTimes == null) {
             return false; // 没有记录,说明该用户、设备、告警类型组合没有推送记录
@@ -97,8 +112,8 @@ public class LocalSensorAlarmMessagePushService {
      * @param alarmType 告警类型
      * @return 唯一的键值
      */
-    private String generatePushHistoryKey(String openid, String deviceID, String alarmType) {
-        return openid + "_" + deviceID + "_" + alarmType;
+    private String generatePushHistoryKey(String openid, String deviceID, Integer sensorRoute, String alarmType) {
+        return openid + "_" + deviceID + "_" + + sensorRoute +  "_" + alarmType;
     }
 
     /**
@@ -108,8 +123,8 @@ public class LocalSensorAlarmMessagePushService {
      * @param deviceID  设备ID
      * @param alarmType 告警类型
      */
-    private void recordPushTime(String openid, String deviceID, String alarmType) {
-        String key = generatePushHistoryKey(openid, deviceID, alarmType);
+    private void recordPushTime(String openid, String deviceID, Integer sensorRoute, String alarmType) {
+        String key = generatePushHistoryKey(openid, deviceID, sensorRoute, alarmType);
         List<Long> pushTimes = userDeviceAlarmPushHistory.computeIfAbsent(key, k -> new ArrayList<>());
         pushTimes.add(System.currentTimeMillis());
     }

+ 6 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/MessagePushService.java

@@ -26,4 +26,10 @@ public interface MessagePushService {
      * @param alarm 告警信息
      */
     boolean sendAlarmMessage(SensorAlarm alarm);
+
+    boolean sendAlarmRecoverMessage(SensorAlarm alarm);
+
+    boolean sendOfflineMessage(SensorAlarm alarm);
+
+    boolean sendOnlineMessage(SensorAlarm alarm);
 }

+ 24 - 9
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/RedisSensorAlarmMessagePushService.java

@@ -49,7 +49,7 @@ public class RedisSensorAlarmMessagePushService {
         List<SensorAlarmUser> alarmUsers = users.values().stream().toList();
         for (String openid : users.keySet()) {
             SensorAlarmUser user = users.get(openid);
-            if (hasExceededPushLimit(openid, deviceID, alarmType)) {
+            if (hasExceededPushLimit(openid, deviceID,alarm.getSensorRoute(), alarmType)) {
                 log.info("用户 {} 对设备 {} 的告警类型 {} \n在过去{}分钟内推送次数超过限制,跳过推送", openid, deviceID, alarmType, JfcloudColdChainConstants.MESS_PUSH_TIME_WINDOW / 60 / 1000);
                 continue;
             }
@@ -59,7 +59,21 @@ public class RedisSensorAlarmMessagePushService {
                 MessagePushService pushService = pushServices.get(channel.name());
                 if (pushService != null) {
                     try {
-                        boolean b = pushService.sendAlarmMessage(alarm);
+                        boolean b = false;
+                        switch (alarm.getType()) {
+                            case "0":
+                                b = pushService.sendAlarmMessage(alarm);
+                                break;
+                            case "1":
+                                b = pushService.sendAlarmRecoverMessage(alarm);
+                                break;
+                            case "2":
+                                b = pushService.sendOfflineMessage(alarm);
+                                break;
+                            case "4":
+                                b = pushService.sendOnlineMessage(alarm);
+                                break;
+                        }
                         alarm.setNotified(b);
                     } catch (Exception e) {
                         log.error("推送消息失败,渠道: {},错误: {}", channel.getChannelName(), e.getMessage());
@@ -68,15 +82,15 @@ public class RedisSensorAlarmMessagePushService {
                     log.warn("不支持的通知渠道: {}", channel.getChannelName());
                 }
             }
-            recordPushTime(openid, deviceID, alarmType);
+            recordPushTime(openid, deviceID,alarm.getSensorRoute(), alarmType);
         }
         // 还原这条消息的发送所有人
         alarm.setAlarmUsers(alarmUsers);
         saveAlarmToDatabase(alarm);
     }
 
-    private boolean hasExceededPushLimit(String openid, String deviceID, String alarmType) {
-        String key = generatePushHistoryKey(openid, deviceID, alarmType);
+    public boolean hasExceededPushLimit(String openid, String deviceID, Integer sensorRoute,  String alarmType) {
+        String key = generatePushHistoryKey(openid, deviceID, sensorRoute, alarmType);
         List<Object> pushTimes = redisTemplate.opsForList().range(key, 0, -1);
         if (pushTimes == null || pushTimes.isEmpty()) {
             return false;
@@ -86,8 +100,8 @@ public class RedisSensorAlarmMessagePushService {
         return pushTimes.size() >= JfcloudColdChainConstants.MESS_PUSH_MAX_PUSH_COUNT;
     }
 
-    private void recordPushTime(String openid, String deviceID, String alarmType) {
-        String key = generatePushHistoryKey(openid, deviceID, alarmType);
+    private void recordPushTime(String openid, String deviceID, Integer sensorRoute, String alarmType) {
+        String key = generatePushHistoryKey(openid, deviceID, sensorRoute, alarmType);
         long currentTime = System.currentTimeMillis();
         redisTemplate.opsForList().rightPush(key, currentTime);
         redisTemplate.opsForList().trim(key, -JfcloudColdChainConstants.MESS_PUSH_MAX_PUSH_COUNT, -1);
@@ -101,7 +115,8 @@ public class RedisSensorAlarmMessagePushService {
         }
     }
 
-    private String generatePushHistoryKey(String openid, String deviceID, String alarmType) {
-        return JfcloudColdChainConstants.REDIS_PUSH_HISTORY_KEY_PREFIX + ":" + openid + ":" + deviceID + ":" + alarmType;
+    private String generatePushHistoryKey(String openid, String deviceID, Integer sensorRoute, String alarmType) {
+        return JfcloudColdChainConstants.REDIS_PUSH_HISTORY_KEY_PREFIX
+                + ":" + openid + ":" + deviceID + ":" + sensorRoute + ":" + alarmType;
     }
 }

+ 15 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/DingTalkMessagePushService.java

@@ -19,4 +19,19 @@ public class DingTalkMessagePushService implements MessagePushService {
         System.out.println("发送渠道:" + alarm);
         return false;
     }
+
+    @Override
+    public boolean sendAlarmRecoverMessage(SensorAlarm alarm) {
+        return false;
+    }
+
+    @Override
+    public boolean sendOfflineMessage(SensorAlarm alarm) {
+        return false;
+    }
+
+    @Override
+    public boolean sendOnlineMessage(SensorAlarm alarm) {
+        return false;
+    }
 }

+ 15 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/EmailPushService.java

@@ -22,6 +22,21 @@ public class EmailPushService implements MessagePushService {
         return false;
     }
 
+    @Override
+    public boolean sendAlarmRecoverMessage(SensorAlarm alarm) {
+        return false;
+    }
+
+    @Override
+    public boolean sendOfflineMessage(SensorAlarm alarm) {
+        return false;
+    }
+
+    @Override
+    public boolean sendOnlineMessage(SensorAlarm alarm) {
+        return false;
+    }
+
     private String buildMessage(SensorAlarm alarm) {
         return "告警信息:设备 " + alarm.getDeviceName() + " " + alarm.getMessage();
     }

+ 15 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/PushNotificationService.java

@@ -22,6 +22,21 @@ public class PushNotificationService implements MessagePushService {
         return false;
     }
 
+    @Override
+    public boolean sendAlarmRecoverMessage(SensorAlarm alarm) {
+        return false;
+    }
+
+    @Override
+    public boolean sendOfflineMessage(SensorAlarm alarm) {
+        return false;
+    }
+
+    @Override
+    public boolean sendOnlineMessage(SensorAlarm alarm) {
+        return false;
+    }
+
     private String buildMessage(SensorAlarm alarm) {
         return "告警信息:设备 " + alarm.getDeviceName() + " " + alarm.getMessage();
     }

+ 15 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/SMSPushService.java

@@ -22,6 +22,21 @@ public class SMSPushService implements MessagePushService {
         return false;
     }
 
+    @Override
+    public boolean sendAlarmRecoverMessage(SensorAlarm alarm) {
+        return false;
+    }
+
+    @Override
+    public boolean sendOfflineMessage(SensorAlarm alarm) {
+        return false;
+    }
+
+    @Override
+    public boolean sendOnlineMessage(SensorAlarm alarm) {
+        return false;
+    }
+
     private String buildMessage(SensorAlarm alarm) {
         return "告警信息:设备 " + alarm.getDeviceName() + " " + alarm.getMessage();
     }

+ 55 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/WechatMessagePushService.java

@@ -6,6 +6,9 @@ import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarm;
 import vip.xiaonuo.coldchain.core.alarm.bean.SensorAlarmUser;
 import vip.xiaonuo.coldchain.core.alarm.service.messagepush.MessagePushService;
 import vip.xiaonuo.coldchain.modular.push.param.AlarmPushParam;
+import vip.xiaonuo.coldchain.modular.push.param.AlarmRecoverPushParam;
+import vip.xiaonuo.coldchain.modular.push.param.OfflinePushParam;
+import vip.xiaonuo.coldchain.modular.push.param.OnlinePushParam;
 import vip.xiaonuo.coldchain.modular.push.utils.PushUtil;
 
 import java.util.Date;
@@ -49,4 +52,56 @@ public class WechatMessagePushService implements MessagePushService {
         alarm.setWeixinRequestCode(pushCode);
         return !StrUtil.isBlank(pushCode);
     }
+
+    @Override
+    public boolean sendAlarmRecoverMessage(SensorAlarm alarm) {
+        AlarmRecoverPushParam pushParam = new AlarmRecoverPushParam();
+        pushParam.setDeviceName(alarm.getSource());
+        pushParam.setRecoverTime(new Date());
+        pushParam.setType(alarm.getAlarmType());
+        pushParam.setValue(alarm.getValue());
+        pushParam.setUserIdList(alarm.getAlarmUsers().stream().map(SensorAlarmUser::getOpenId).collect(Collectors.toSet()));
+        if (alarm.getMessage().length() > 17) {
+            pushParam.setRecoverCause(alarm.getMessage().substring(0, 17) + "...");
+        } else {
+            pushParam.setRecoverCause(alarm.getMessage());
+        }
+        if (StrUtil.isNotBlank(alarm.getRoomName())) {
+            pushParam.setDeviceName(alarm.getSource() + "(" + alarm.getRoomName() + ")");
+        } else {
+            pushParam.setDeviceName(alarm.getSource());
+        }
+        //推送到公众号
+        String pushCode = PushUtil.alarmRecoverPush(pushParam);
+        alarm.setWeixinRequestCode(pushCode);
+        return !StrUtil.isBlank(pushCode);
+    }
+
+    @Override
+    public boolean sendOfflineMessage(SensorAlarm alarm) {
+        OfflinePushParam pushParam = new OfflinePushParam();
+        pushParam.setOfflineTime(new Date());
+        pushParam.setDeviceName(alarm.getSource());
+        pushParam.setStatus("离线");
+        if (StrUtil.isNotBlank(alarm.getRoomName())) {
+            pushParam.setLocation(alarm.getRoomName());
+        }
+        String pushCode = PushUtil.offlinePush(pushParam);
+        alarm.setWeixinRequestCode(pushCode);
+        return !StrUtil.isBlank(pushCode);
+    }
+
+    @Override
+    public boolean sendOnlineMessage(SensorAlarm alarm) {
+        OnlinePushParam pushParam = new OnlinePushParam();
+        pushParam.setOnlineTime(new Date());
+        pushParam.setDeviceName(alarm.getSource());
+        pushParam.setLocation("上线");
+        if (StrUtil.isNotBlank(alarm.getRoomName())) {
+            pushParam.setLocation(alarm.getRoomName());
+        }
+        String pushCode = PushUtil.onlinePush(pushParam);
+        alarm.setWeixinRequestCode(pushCode);
+        return !StrUtil.isBlank(pushCode);
+    }
 }

+ 15 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/alarm/service/messagepush/impl/WechatMiniMessagePushService.java

@@ -17,4 +17,19 @@ public class WechatMiniMessagePushService implements MessagePushService {
         System.out.println("发送微信小程序通知:");
         return false;
     }
+
+    @Override
+    public boolean sendAlarmRecoverMessage(SensorAlarm alarm) {
+        return false;
+    }
+
+    @Override
+    public boolean sendOfflineMessage(SensorAlarm alarm) {
+        return false;
+    }
+
+    @Override
+    public boolean sendOnlineMessage(SensorAlarm alarm) {
+        return false;
+    }
 }

+ 4 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/app/param/AppDevicePageParam.java

@@ -77,4 +77,8 @@ public class AppDevicePageParam {
     /** 房间id */
     @Schema(description = "房间id")
     private String roomId;
+
+    /** 冰箱状态 */
+    @Schema(description = "冰箱状态")
+    private String status;
 }

+ 6 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/app/param/MessagePageParam.java

@@ -77,4 +77,10 @@ public class MessagePageParam {
      */
     @Schema(description = "查询结束时间")
     private String endTime;
+
+    /**
+     * 告警类型
+     */
+    @Schema(description = "告警类型")
+    private String alarmType;
 }

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

@@ -67,6 +67,7 @@ public class AppDeviceService {
         monitorTargetPageParam.setName(appDevicePageParam.getName());
         monitorTargetPageParam.setRoomId(appDevicePageParam.getRoomId());
         monitorTargetPageParam.setOrgId(StpLoginUserUtil.getLoginUser().getOrgId());
+        monitorTargetPageParam.setStatus(appDevicePageParam.getStatus());
         // 调用 monitorTargetService 查询当前用户的监控目标数据,分页结果
         Page<MonitorTarget> pageByUser = monitorTargetService.selectMonitorTargetByPage(monitorTargetPageParam);
         // 遍历监控目标分页记录

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

@@ -69,6 +69,16 @@ public class MonitorNoticeController {
         return CommonResult.data(sensorAlarmService.getMessages(monitorNoticePageParam));
     }
 
+    /**
+     * 获取告警类型
+     */
+    @Operation(summary = "获取告警类型")
+    @SaCheckPermission("/coldchain/monitornotice/getAlarmTypeList")
+    @GetMapping("/coldchain/monitornotice/getAlarmTypeList")
+    public CommonResult<List<String>> getAlarmTypeList() {
+        return CommonResult.data(sensorAlarmService.getAlarmTypeList());
+    }
+
     /**
      * 获取监控通知列表
      *

+ 6 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitornotice/param/MonitorNoticePageParam.java

@@ -61,4 +61,10 @@ public class MonitorNoticePageParam {
      */
     @Schema(description = "查询结束时间")
     private String endTime;
+
+    /**
+     * 告警类型
+     */
+    @Schema(description = "告警类型")
+    private String alarmType;
 }

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

@@ -0,0 +1,22 @@
+package vip.xiaonuo.coldchain.modular.monitorsearchhistory.controller;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+import vip.xiaonuo.common.pojo.OrgEntity;
+
+@Getter
+@Setter
+@Data
+@TableName("monitor_search_history")
+public class SearchHistory extends OrgEntity {
+    /**
+     * id
+     */
+    private String id;
+    /**
+     * 搜索关键字
+     */
+    private String searchKey;
+}

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

@@ -0,0 +1,59 @@
+package vip.xiaonuo.coldchain.modular.monitorsearchhistory.entity;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+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.modular.monitorsearchhistory.controller.SearchHistory;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.param.SearchHistoryAddParam;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.param.SearchHistoryIdParam;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.service.SearchHistoryService;
+import vip.xiaonuo.common.pojo.CommonResult;
+
+import java.util.List;
+
+/**
+ * 搜索记录控制器
+ *
+ * @author 黄渊昊
+ */
+@Tag(name = "搜索记录控制器")
+@RestController
+@Validated
+public class SearchHistoryController {
+    @Resource
+    private SearchHistoryService searchHistoryService;
+
+    /**
+     * 获取最新十条搜索记录
+     */
+    @Operation(summary = "获取最新十条搜索记录")
+    @GetMapping("/coldchain/searchhistory/getSearchHistory")
+    public CommonResult<List<SearchHistory>> getSearchHistory() {
+        return CommonResult.data(searchHistoryService.getSearchHistory());
+    }
+
+    /**
+     * 新增搜索记录
+     */
+    @Operation(summary = "新增搜索记录")
+    @GetMapping("/coldchain/searchhistory/add")
+    public CommonResult<String> add(@Validated SearchHistoryAddParam searchHistoryAddParam) {
+        searchHistoryService.add(searchHistoryAddParam);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除搜索记录
+     */
+    @Operation(summary = "删除搜索记录")
+    @GetMapping("/coldchain/searchhistory/delete")
+    public CommonResult<String> delete(SearchHistoryIdParam searchHistoryIdParam) {
+        searchHistoryService.delete(searchHistoryIdParam);
+        return CommonResult.ok();
+    }
+}

+ 19 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/mapper/SearchHistoryMapper.java

@@ -0,0 +1,19 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.coldchain.modular.monitorsearchhistory.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.controller.SearchHistory;
+
+public interface SearchHistoryMapper extends BaseMapper<SearchHistory> {
+}

+ 4 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/mapper/mapping/SearchHistoryMapper.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="vip.xiaonuo.coldchain.modular.monitorsearchhistory.mapper.SearchHistoryMapper">
+</mapper>

+ 17 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/param/SearchHistoryAddParam.java

@@ -0,0 +1,17 @@
+package vip.xiaonuo.coldchain.modular.monitorsearchhistory.param;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+import vip.xiaonuo.common.pojo.OrgEntity;
+
+@Getter
+@Setter
+public class SearchHistoryAddParam extends OrgEntity {
+    /**
+     * 搜索关键字
+     */
+    private String searchKey;
+}

+ 34 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/param/SearchHistoryIdParam.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.coldchain.modular.monitorsearchhistory.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 监控设备型号Id参数
+ *
+ * @author 黄渊昊
+ * @date  2024/11/25 10:15
+ **/
+@Getter
+@Setter
+public class SearchHistoryIdParam {
+    @Schema(description = "唯一标识符,UUID", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "id不能为空")
+    private String id;
+}

+ 16 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/service/SearchHistoryService.java

@@ -0,0 +1,16 @@
+package vip.xiaonuo.coldchain.modular.monitorsearchhistory.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.controller.SearchHistory;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.param.SearchHistoryAddParam;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.param.SearchHistoryIdParam;
+
+import java.util.List;
+
+public interface SearchHistoryService extends IService<SearchHistory> {
+    List<SearchHistory> getSearchHistory();
+
+    void add(SearchHistoryAddParam searchHistoryAddParam);
+
+    void delete(SearchHistoryIdParam searchHistoryIdParam);
+}

+ 72 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitorsearchhistory/service/impl/SearchHistoryServiceImpl.java

@@ -0,0 +1,72 @@
+package vip.xiaonuo.coldchain.modular.monitorsearchhistory.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
+import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
+import vip.xiaonuo.coldchain.modular.monitordevicetype.param.MonitorDeviceTypeIdParam;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.controller.SearchHistory;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.mapper.SearchHistoryMapper;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.param.SearchHistoryAddParam;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.param.SearchHistoryIdParam;
+import vip.xiaonuo.coldchain.modular.monitorsearchhistory.service.SearchHistoryService;
+import vip.xiaonuo.common.enums.CommonDeleteFlagEnum;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+
+@Service
+public class SearchHistoryServiceImpl extends ServiceImpl<SearchHistoryMapper, SearchHistory> implements SearchHistoryService {
+    @Override
+    public List<SearchHistory> getSearchHistory() {
+        SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
+        LambdaQueryWrapper<SearchHistory> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper
+                .eq(SearchHistory::getCreateUser, loginUser.getId())
+                .eq(SearchHistory::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE)
+                .groupBy(SearchHistory::getSearchKey)
+                .orderByDesc(SearchHistory::getCreateTime)
+                .last("limit 10");
+        return list(queryWrapper);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void add(SearchHistoryAddParam searchHistoryAddParam) {
+        if (StrUtil.isNotBlank(searchHistoryAddParam.getSearchKey())) {
+            SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
+            LambdaQueryWrapper<SearchHistory> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(SearchHistory::getCreateUser, loginUser.getId())
+                    .eq(SearchHistory::getSearchKey, searchHistoryAddParam.getSearchKey())
+                    .eq(SearchHistory::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE);
+            SearchHistory one = getOne(queryWrapper);
+            SearchHistory searchHistory = BeanUtil.copyProperties(searchHistoryAddParam, SearchHistory.class);
+            if (Objects.nonNull(one)) {
+                searchHistory.setCreateTime(new Date());
+                searchHistory.setId(one.getId());
+                updateById(searchHistory);
+            } else {
+                save(searchHistory);
+            }
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void delete(SearchHistoryIdParam searchHistoryIdParam) {
+        SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
+        LambdaQueryWrapper<SearchHistory> queryWrapper = new LambdaQueryWrapper<>();
+        if (StrUtil.isNotBlank(searchHistoryIdParam.getId())) {
+            this.removeById(searchHistoryIdParam.getId());
+        } else {
+            queryWrapper.eq(SearchHistory::getCreateUser, loginUser.getId());
+            this.remove(queryWrapper);
+        }
+    }
+}

+ 4 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitortarget/mapper/mapping/MonitorTargetMapper.xml

@@ -62,6 +62,10 @@
         <if test="param.orgId != null and param.orgId.trim() != ''">
             AND t.create_org = #{param.orgId}
         </if>
+        <!-- 动态条件:按冰箱状态查询 -->
+        <if test="param.status != null and param.status.trim() != ''">
+            AND t.status = #{param.status}
+        </if>
         GROUP BY t.id
         <!-- 动态排序 -->
         <choose>

+ 6 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitortarget/param/MonitorTargetPageParam.java

@@ -80,6 +80,12 @@ public class MonitorTargetPageParam {
     @Schema(description = "房间id")
     private String roomId;
 
+    /**
+     * 冰箱状态
+     */
+    @Schema(description = "冰箱状态")
+    private String status;
+
     // 计算分页偏移量
     public int getOffset() {
         return (current - 1) * size;  // 当前页 - 1 乘以每页条数

+ 5 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/param/AlarmPushParam.java

@@ -1,5 +1,6 @@
 package vip.xiaonuo.coldchain.modular.push.param;
 
+import jakarta.validation.constraints.Size;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -17,10 +18,12 @@ public class AlarmPushParam {
     /**
      * 设备名
      */
+    @Size(min = 0, max = 20)
     private String deviceName;
     /**
      * 告警内容
      */
+    @Size(min = 0, max = 20)
     private String context;
     /**
      * 告警时间
@@ -29,10 +32,12 @@ public class AlarmPushParam {
     /**
      * 告警类型
      */
+    @Size(min = 0, max = 20)
     private String type;
     /**
      * 告警值
      */
+    @Size(min = 0, max = 32)
     private String value;
     /**
      * 用户名

+ 9 - 4
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/param/AlarmRecoverPushParam.java

@@ -1,5 +1,6 @@
 package vip.xiaonuo.coldchain.modular.push.param;
 
+import jakarta.validation.constraints.Size;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -17,15 +18,18 @@ public class AlarmRecoverPushParam {
     /**
      * 设备名
      */
+    @Size(min = 1, max = 20)
     private String deviceName;
     /**
-     * 告警时间
+     * 事件类型
      */
-    private Date alarmTime;
+    @Size(min = 1, max = 20)
+    private String type;
     /**
-     * 告警原因
+     * 告警
      */
-    private String alarmCause;
+    @Size(min = 1, max = 20)
+    private Float value;
     /**
      * 恢复时间
      */
@@ -33,6 +37,7 @@ public class AlarmRecoverPushParam {
     /**
      * 恢复原因
      */
+    @Size(min = 1, max = 20)
     private String recoverCause;
     /**
      * 用户名

+ 4 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/param/OfflinePushParam.java

@@ -1,5 +1,6 @@
 package vip.xiaonuo.coldchain.modular.push.param;
 
+import jakarta.validation.constraints.Size;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -17,14 +18,17 @@ public class OfflinePushParam {
     /**
      * 设备名
      */
+    @Size(min = 0, max = 20)
     private String deviceName;
     /**
      * 设备状态(五个以内汉字)
      */
+    @Size(min = 0, max = 5)
     private String status;
     /**
      * 设备位置
      */
+    @Size(min = 0, max = 20)
     private String location;
     /**
      * 上线时间

+ 4 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/param/OnlinePushParam.java

@@ -1,5 +1,6 @@
 package vip.xiaonuo.coldchain.modular.push.param;
 
+import jakarta.validation.constraints.Size;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -17,14 +18,17 @@ public class OnlinePushParam {
     /**
      * 设备名
      */
+    @Size(min = 0, max = 20)
     private String deviceName;
     /**
      * 设备状态(五个以内汉字)
      */
+    @Size(min = 0, max = 5)
     private String status;
     /**
      * 设备位置
      */
+    @Size(min = 0, max = 20)
     private String location;
     /**
      * 上线时间

+ 18 - 18
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/push/utils/PushUtil.java

@@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONObject;
+import jakarta.validation.Valid;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
@@ -49,7 +50,7 @@ public class PushUtil {
     /**
      * 设备告警推送
      */
-    public static String alarmPush(AlarmPushParam pushParam) {
+    public static String alarmPush(@Valid AlarmPushParam pushParam) {
         WxMpTemplateMessage.MiniProgram miniProgram = getMiniProgram(pushParam.getUserIdList());
 
         if (Objects.isNull(miniProgram)) {
@@ -108,7 +109,7 @@ public class PushUtil {
     /**
      * 预警恢复消息推送
      */
-    public static String alarmRecoverPush(AlarmRecoverPushParam pushParam) {
+    public static String alarmRecoverPush(@Valid AlarmRecoverPushParam pushParam) {
         WxMpTemplateMessage.MiniProgram miniProgram = getMiniProgram(pushParam.getUserIdList());
 
         if (Objects.isNull(miniProgram)) {
@@ -133,28 +134,27 @@ public class PushUtil {
                 pushParam.setDeviceName(" ");
             }
             templateMessage.addData(new WxMpTemplateData("thing15", pushParam.getDeviceName()));
-            //告警时间
-            if (Objects.isNull(pushParam.getAlarmTime())) {
-                pushParam.setAlarmTime(new Date());
+            //事件类型
+            if (Objects.isNull(pushParam.getType())) {
+                pushParam.setType(" ");
+            }
+            templateMessage.addData(new WxMpTemplateData("thing4", pushParam.getType()));
+            //恢复原因
+            if (StrUtil.isBlank(pushParam.getRecoverCause())) {
+                pushParam.setRecoverCause(" ");
             }
-            String alarmTimeFormat = DateUtil.format(pushParam.getAlarmTime(), "yyyy-MM-dd HH:mm:ss");
-            templateMessage.addData(new WxMpTemplateData("time5", alarmTimeFormat));
-            //告警原因
-            if (StrUtil.isBlank(pushParam.getAlarmCause())) {
-                pushParam.setAlarmCause(" ");
+            templateMessage.addData(new WxMpTemplateData("number31", pushParam.getRecoverCause()));
+            //恢复原因
+            if (StrUtil.isBlank(pushParam.getRecoverCause())) {
+                pushParam.setRecoverCause(" ");
             }
-            templateMessage.addData(new WxMpTemplateData("thing8", pushParam.getAlarmCause()));
+            templateMessage.addData(new WxMpTemplateData("thing16", pushParam.getRecoverCause()));
             //恢复时间
             if (Objects.isNull(pushParam.getRecoverTime())) {
                 pushParam.setRecoverTime(new Date());
             }
             String recoverTimeFormat = DateUtil.format(pushParam.getRecoverTime(), "yyyy-MM-dd HH:mm:ss");
             templateMessage.addData(new WxMpTemplateData("time6", recoverTimeFormat));
-            //恢复原因
-            if (StrUtil.isBlank(pushParam.getRecoverCause())) {
-                pushParam.setRecoverCause(" ");
-            }
-            templateMessage.addData(new WxMpTemplateData("time3", pushParam.getRecoverCause()));
 
             try {
                 pushCode = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
@@ -168,7 +168,7 @@ public class PushUtil {
     /**
      * 设备上线消息推送
      */
-    public static String onlinePush(OnlinePushParam pushParam) {
+    public static String onlinePush(@Valid OnlinePushParam pushParam) {
         WxMpTemplateMessage.MiniProgram miniProgram = getMiniProgram(pushParam.getUserIdList());
 
         if (Objects.isNull(miniProgram)) {
@@ -222,7 +222,7 @@ public class PushUtil {
     /**
      * 设备上线消息推送
      */
-    public static String onlinePush(OfflinePushParam pushParam) {
+    public static String offlinePush(@Valid OfflinePushParam pushParam) {
         WxMpTemplateMessage.MiniProgram miniProgram = getMiniProgram(pushParam.getUserIdList());
 
         if (Objects.isNull(miniProgram)) {

+ 4 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/targetroom/entity/TargetRoom.java

@@ -41,6 +41,10 @@ public class TargetRoom extends OrgEntity {
     @Schema(description = "房间名")
     private String name;
 
+    /** 背景图 */
+    @Schema(description = "背景图")
+    private String bgImg;
+
     /** 排序码 */
     @Schema(description = "排序码")
     private Integer sortCode;

+ 4 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/targetroom/param/TargetRoomAddParam.java

@@ -38,6 +38,10 @@ public class TargetRoomAddParam {
     @Length(min = 1, max = 10)
     private String name;
 
+    /** 背景图 */
+    @Schema(description = "背景图")
+    private String bgImg;
+
     /** 组织id */
     @Schema(description = "组织id")
     private String createOrg;

+ 4 - 0
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/targetroom/param/TargetRoomEditParam.java

@@ -43,6 +43,10 @@ public class TargetRoomEditParam {
     @Length(min = 1, max = 10)
     private String name;
 
+    /** 背景图 */
+    @Schema(description = "背景图")
+    private String bgImg;
+
     /** 组织id */
     @Schema(description = "组织id")
     private String createOrg;

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

@@ -247,7 +247,7 @@ wechat.appID=wx49b1fb6f9c0d0b8d
 wechat.secret=6b177348efc2b21da105fc126b933db9
 wechat.templateId=WgKOAJrnNhnr2lIkfI_vppfY--7oImjddrd4GPnE_UA
 wechat.alarmsTemplateId=WgKOAJrnNhnr2lIkfI_vppfY--7oImjddrd4GPnE_UA
-wechat.alarmsRecoverTemplateId=VTN3rREcSxV9Hv9WKgu_jyLDT9rsWyNMcLYKMZCgEgA
+wechat.alarmsRecoverTemplateId=VTN3rREcSxV9Hv9WKgu_j875Bux-_auOeOLO8EUTRgA
 wechat.OnlineTemplateId=nQXwP-WWRi71C2-9-EnYfDSuQ2ez1RBS585ra6aeKvM
 wechat.offlineTemplateId=qxBSnOKZcN6MpC8Vwpy1lyIfB8ZTxyITR3f-Bzv8zGs
 wechat.miniProgram=wx1eebc072a607c055