Przeglądaj źródła

Merge branch 'develop' of com_yunfei_saas/agmp_iots into master

yf_zn 1 rok temu
rodzic
commit
f45a181d15
31 zmienionych plików z 1448 dodań i 349 usunięć
  1. 8 0
      src/main/java/com/yunfeiyun/agmp/iots/AgmpIotsApplication.java
  2. 15 0
      src/main/java/com/yunfeiyun/agmp/iots/core/http/AdznGssqService.java
  3. 78 16
      src/main/java/com/yunfeiyun/agmp/iots/device/controller/TestController.java
  4. 13 0
      src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/BzyDeviceImpl.java
  5. 13 0
      src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/CqCbdDeviceImpl.java
  6. 19 6
      src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/IYfXctDeviceImpl.java
  7. 13 24
      src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/XphYfQxzDeviceImpl.java
  8. 12 1
      src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/YfQxzDeviceImpl.java
  9. 13 1
      src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/YfScdDeviceImpl.java
  10. 1 0
      src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/YfXycb2DeviceImpl.java
  11. 13 0
      src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/YfXycbIIIDeviceImpl.java
  12. 0 13
      src/main/java/com/yunfeiyun/agmp/iots/service/impl/IotCbdImgService.java
  13. 13 35
      src/main/java/com/yunfeiyun/agmp/iots/service/impl/IotDeviceServiceImpl.java
  14. 1 1
      src/main/java/com/yunfeiyun/agmp/iots/task/AdznGssqScheduler.java
  15. 74 101
      src/main/java/com/yunfeiyun/agmp/iots/task/IotStatusService.java
  16. 38 1
      src/main/java/com/yunfeiyun/agmp/iots/warn/job/WarnJob.java
  17. 31 1
      src/main/java/com/yunfeiyun/agmp/iots/warn/mapper/IotWarnBussinessMapper.java
  18. 9 0
      src/main/java/com/yunfeiyun/agmp/iots/warn/model/CountResultDto.java
  19. 16 0
      src/main/java/com/yunfeiyun/agmp/iots/warn/model/IotWarnconfigCbdInfoVo.java
  20. 13 0
      src/main/java/com/yunfeiyun/agmp/iots/warn/model/IotWarnconfigDevVo.java
  21. 1 1
      src/main/java/com/yunfeiyun/agmp/iots/warn/model/WarnQxSqInfoDto.java
  22. 9 0
      src/main/java/com/yunfeiyun/agmp/iots/warn/model/WarnPestDetailStatDto.java
  23. 7 0
      src/main/java/com/yunfeiyun/agmp/iots/warn/model/WarnResult.java
  24. 278 33
      src/main/java/com/yunfeiyun/agmp/iots/warn/service/IotWarnBussinessService.java
  25. 9 3
      src/main/java/com/yunfeiyun/agmp/iots/warn/service/ReCountService.java
  26. 341 0
      src/main/java/com/yunfeiyun/agmp/iots/warn/service/WarnPestService.java
  27. 226 91
      src/main/java/com/yunfeiyun/agmp/iots/warn/service/WarnService.java
  28. 45 5
      src/main/java/com/yunfeiyun/agmp/iots/warn/util/WarnMessageBuilderUtil.java
  29. 4 0
      src/main/resources/application-dev.yml
  30. 4 3
      src/main/resources/application-test.yml
  31. 131 13
      src/main/resources/mapper/IotWarnBusinessMapper.xml

+ 8 - 0
src/main/java/com/yunfeiyun/agmp/iots/AgmpIotsApplication.java

@@ -2,6 +2,7 @@ package com.yunfeiyun.agmp.iots;
 
 import com.yunfeiyun.agmp.common.utils.spring.SpringUtils;
 import com.yunfeiyun.agmp.iots.core.manager.ConnectionManager;
+import com.yunfeiyun.agmp.iots.warn.service.WarnService;
 import org.mybatis.spring.annotation.MapperScan;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -28,6 +29,13 @@ public class AgmpIotsApplication {
     public static void main(String[] args) {
         SpringApplication.run(AgmpIotsApplication.class, args);
         log.info("物联网服务子系统启动成功");
+        //启动后检查离线配置,没有则自动添加
+        try {
+            log.info("【告警】检查租户 离线配置 {}");
+            SpringUtils.getBean(WarnService.class).checkTenantOfflineConfig();
+        } catch (Exception e) {
+            log.info("【告警】检查租户 离线配置 异常", e);
+        }
         //便启动边订阅收到消息处理导致启动太慢,启动之后再进行连接创建和链接
         log.info("【链接建立初始化】【执行】");
         long st = System.currentTimeMillis();

+ 15 - 0
src/main/java/com/yunfeiyun/agmp/iots/core/http/AdznGssqService.java

@@ -15,6 +15,7 @@ import com.yunfeiyun.agmp.iot.common.service.MongoService;
 import com.yunfeiyun.agmp.iots.common.annotate.HttpCore;
 import com.yunfeiyun.agmp.iots.service.IIotDeviceService;
 import com.yunfeiyun.agmp.iots.service.impl.IotDeviceAddressService;
+import com.yunfeiyun.agmp.iots.warn.service.WarnService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
@@ -148,6 +149,8 @@ public class AdznGssqService extends HttpClient {
         IotDeviceAddressService iotDeviceAddressService = SpringUtils.getBean(IotDeviceAddressService.class);
         List<IotAdznGssqdata> iotAdznGssqdataList = new ArrayList<>();
         List<IotDevice> updateList = new ArrayList<>();
+        Map<IotDevice, List<IotAdznGssqdata>> extMap = new HashMap<>();
+
         for(IotDevice iotDevice : iotDeviceList){
             List<IotAdznGssqdata> childList = parseDevListData(iotDevice);
 
@@ -164,7 +167,9 @@ public class AdznGssqService extends HttpClient {
                         continue;
                     }
                 }
+
                 iotAdznGssqdataList.addAll(childList);
+                extMap.put(iotDevice, childList);
 
                 JSONObject devInfo = (JSONObject)devMap.get(iotDevice.getDevCode());
                 String devLng = devInfo.getString("LNG");
@@ -190,6 +195,16 @@ public class AdznGssqService extends HttpClient {
         if(!iotAdznGssqdataList.isEmpty()){
             MongoService mongoService = SpringUtils.getBean(MongoService.class);
             mongoService.insertList(IotAdznGssqdata.class, iotAdznGssqdataList);
+
+            // 发送告警消息
+            WarnService warnService = SpringUtils.getBean(WarnService.class);
+            for(Map.Entry<IotDevice, List<IotAdznGssqdata>> entry : extMap.entrySet()){
+                IotDevice iotDeviceOld = entry.getKey();
+                List<IotAdznGssqdata> ext = entry.getValue();
+                JSONObject warnData = new JSONObject();
+                warnData.put("data", ext);
+                warnService.processWarningReportData(iotDeviceOld, warnData);
+            }
         }
         if(!updateList.isEmpty()){
             SpringUtils.getBean(IIotDeviceService.class).updateIotDeviceBatch(updateList);

+ 78 - 16
src/main/java/com/yunfeiyun/agmp/iots/device/controller/TestController.java

@@ -3,9 +3,11 @@ package com.yunfeiyun.agmp.iots.device.controller;
 import com.alibaba.fastjson2.JSONObject;
 import com.yunfeiyun.agmp.common.constant.ErrorCode;
 import com.yunfeiyun.agmp.common.core.domain.AjaxResult;
+import com.yunfeiyun.agmp.common.exception.BizException;
 import com.yunfeiyun.agmp.common.utils.DateUtils;
 import com.yunfeiyun.agmp.common.utils.JSONUtils;
 import com.yunfeiyun.agmp.common.utils.StringUtils;
+import com.yunfeiyun.agmp.common.utils.spring.SpringUtils;
 import com.yunfeiyun.agmp.common.utils.uuid.IdUtils;
 import com.yunfeiyun.agmp.iot.common.constant.IotErrorCode;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.IotDeviceDictConst;
@@ -13,8 +15,9 @@ import com.yunfeiyun.agmp.iot.common.domain.*;
 import com.yunfeiyun.agmp.iot.common.exception.IotBizException;
 import com.yunfeiyun.agmp.iot.common.model.cmd.CmdGroupModel;
 import com.yunfeiyun.agmp.iot.common.service.MongoService;
-import com.yunfeiyun.agmp.iot.common.util.dev.QxzTypeUtil;
+import com.yunfeiyun.agmp.iot.common.util.dev.DevTypeUtil;
 import com.yunfeiyun.agmp.iots.core.cmd.core.CmdDispatcherService;
+import com.yunfeiyun.agmp.iots.core.manager.ConnectionManager;
 import com.yunfeiyun.agmp.iots.device.domain.WarnTestReq;
 import com.yunfeiyun.agmp.iots.device.mapper.IotDeviceMapper;
 import com.yunfeiyun.agmp.iots.device.service.IYfQxzDevice;
@@ -22,6 +25,9 @@ import com.yunfeiyun.agmp.iots.device.serviceImp.YfQxzDeviceImpl;
 import com.yunfeiyun.agmp.iots.service.IIotDeviceService;
 import com.yunfeiyun.agmp.iots.service.IIotDevicelasteddataService;
 import com.yunfeiyun.agmp.iots.service.IIotYfScddataService;
+import com.yunfeiyun.agmp.iots.service.impl.IotCbdImgService;
+import com.yunfeiyun.agmp.iots.warn.service.WarnPestService;
+import com.yunfeiyun.agmp.iots.warn.service.WarnService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.mongodb.core.MongoTemplate;
@@ -44,8 +50,8 @@ import java.util.concurrent.CompletableFuture;
 @RequestMapping("/test")
 @Slf4j
 public class TestController {
-
-
+    @Autowired
+    private IIotDeviceService iIotDeviceService;
     @Resource(name = "threadPoolTaskExecutor")
     private ThreadPoolTaskExecutor threadPoolTaskExecutor;
 
@@ -609,11 +615,11 @@ public class TestController {
         String devCode = req.getDevCode();
         JSONObject data = req.getData();
 
-        if(StringUtils.isEmpty(devCode)) {
+        if (StringUtils.isEmpty(devCode)) {
             throw new IotBizException(IotErrorCode.FAILURE.getCode(), "设备编码为空");
         }
 
-        if(data == null) {
+        if (data == null) {
             throw new IotBizException(IotErrorCode.FAILURE.getCode(), "数据为空");
         }
 
@@ -621,7 +627,7 @@ public class TestController {
         if (iotDeviceList == null || iotDeviceList.isEmpty()) {
             throw new IotBizException(IotErrorCode.FAILURE.getCode(), "设备不存在");
         }
-        if(iotDeviceList.size() > 1) {
+        if (iotDeviceList.size() > 1) {
             throw new IotBizException(IotErrorCode.FAILURE.getCode(), "设备不唯一");
         }
         IotDevice iotDevice = iotDeviceList.get(0);
@@ -629,11 +635,11 @@ public class TestController {
             throw new IotBizException(IotErrorCode.FAILURE.getCode(), "设备不存在");
         }
         String devtypeBid = iotDevice.getDevtypeBid();
-        if(QxzTypeUtil.isYfCommQxz(devtypeBid)){
+        if (DevTypeUtil.isYfCommQxz(devtypeBid)) {
             YfQxzDeviceImpl yfQxzDevice = (YfQxzDeviceImpl) iYfQxzDevice;
             String devUpdateddate = DateUtils.dateTimeNow();
             yfQxzDevice.processData(iotDevice, data, devUpdateddate);
-        }else{
+        } else {
             throw new IotBizException(IotErrorCode.FAILURE.getCode(), "设备类型不支持");
         }
         return AjaxResult.success();
@@ -641,9 +647,9 @@ public class TestController {
 
     public Class getTableClass(String devtypeBid) {
         Class tableClass = null;
-        if(QxzTypeUtil.isXphYfQxSq(devtypeBid)){
+        if (DevTypeUtil.isXphYfQxSq(devtypeBid)) {
             tableClass = IotXphYfqxzdata.class;
-        }else if(QxzTypeUtil.isYfQxSq(devtypeBid)){
+        } else if (DevTypeUtil.isYfQxSq(devtypeBid)) {
             tableClass = IotYfqxzdata.class;
         }
 //        else if (devtypeBid.equals(IotDeviceDictConst.TYPE_ADZN_GSSQ)) {
@@ -655,6 +661,7 @@ public class TestController {
 
     /**
      * 设备上报数据
+     *
      * @param req
      * @return
      * @throws Exception
@@ -663,7 +670,7 @@ public class TestController {
     public AjaxResult getDevData(WarnTestReq req) throws Exception {
         String devCode = req.getDevCode();
 
-        if(StringUtils.isEmpty(devCode)) {
+        if (StringUtils.isEmpty(devCode)) {
             throw new IotBizException(IotErrorCode.FAILURE.getCode(), "设备编码为空");
         }
 
@@ -671,16 +678,16 @@ public class TestController {
         if (iotDeviceList == null || iotDeviceList.isEmpty()) {
             throw new IotBizException(IotErrorCode.FAILURE.getCode(), "设备不存在");
         }
-        if(iotDeviceList.size() > 1) {
+        if (iotDeviceList.size() > 1) {
             throw new IotBizException(IotErrorCode.FAILURE.getCode(), "设备不唯一");
         }
         IotDevice iotDevice = iotDeviceList.get(0);
 
         String devtypeBid = iotDevice.getDevtypeBid();
         String devBid = iotDevice.getDevBid();
-        if(QxzTypeUtil.isYfCommQxz(devtypeBid)){
+        if (DevTypeUtil.isYfCommQxz(devtypeBid)) {
             Class tableClass = getTableClass(devtypeBid);
-            if(tableClass == null){
+            if (tableClass == null) {
                 throw new IotBizException(ErrorCode.INVALID_PARAMETER.getCode(), "设备类型不存在");
             }
 
@@ -688,7 +695,7 @@ public class TestController {
             String devldContent = iotDevicelasteddata.getDevldContent();
             List jsonList = JSONUtils.toList(devldContent);
             List<Map<String, String>> dataList = new ArrayList<>();
-            for(Object dataObj : jsonList){
+            for (Object dataObj : jsonList) {
                 JSONObject jsonData = JSONObject.from(dataObj);
                 Map<String, String> dataMap = new HashMap<>();
                 dataMap.put("eNum", jsonData.getString("eNum"));
@@ -700,8 +707,63 @@ public class TestController {
             JSONObject data = new JSONObject();
             data.put("data", dataList);
             return AjaxResult.success(data);
-        }else{
+        } else {
             throw new IotBizException(IotErrorCode.FAILURE.getCode(), "设备类型不支持");
         }
     }
+
+    @RequestMapping("/warn/cmd/offline")
+    public AjaxResult cmdOffline(WarnTestReq req) {
+        List<IotDevice> oldIotDevice = iIotDeviceService.selectIotDeviceByDevCode(req.getDevCode());
+        for (IotDevice iotDevice : oldIotDevice) {
+            IotDevice newIotDevice = new IotDevice();
+            newIotDevice.setDevBid(iotDevice.getDevBid());
+            newIotDevice.setDevOriginalStatus(iotDevice.getDevStatus());
+            newIotDevice.setDevStatus("0");
+            newIotDevice.setDevOfflinedate(DateUtils.dateTimeNow());
+            newIotDevice.setTid(iotDevice.getTid());
+            newIotDevice.setDevtypeBid(iotDevice.getDevtypeBid());
+            newIotDevice.setDevCreateddate(iotDevice.getDevCreateddate());
+            newIotDevice.setDevUpdateddate(iotDevice.getDevUpdateddate());
+            newIotDevice.setDevCode(iotDevice.getDevCode());
+            iIotDeviceService.updateIotDevice(newIotDevice);
+            //发送离线预警
+            SpringUtils.getBean(WarnService.class).processWarningOfflineData(newIotDevice, JSONObject.from(iotDevice));
+        }
+
+        return AjaxResult.success();
+    }
+
+
+    @Autowired
+    private IotCbdImgService iotCbdImgService;
+
+    @RequestMapping("/warn/cmd/cbd")
+    public AjaxResult cmdCbdWarn(@RequestBody WarnTestReq req) {
+        JSONObject jsonObject = req.getData();
+        if (StringUtils.isEmpty(req.getDevCode())) {
+            throw new BizException(ErrorCode.FAILURE.getCode(), "设备code为空");
+        }
+        List<IotDevice> oldIotDevice = iIotDeviceService.selectIotDeviceByDevCode(req.getDevCode());
+        for (IotDevice iotDevice : oldIotDevice) {
+            String devtypeBid = "3";
+            //String deviceTypeId = jsonObject.getString("device_type_id");
+            String deviceTypeId = iotDevice.getDevtypeBid();
+            //String devCode = jsonObject.getString("imei");
+            String devCode = req.getDevCode();
+            log.info("【解析测报灯图片数据】:devtypeBid:{},deviceTypeId,{},devCode:{}", devtypeBid, deviceTypeId, devCode);
+            String cbdimgAddr = jsonObject.getString("Image");
+            if (StringUtils.isEmpty(cbdimgAddr)) {
+                continue;
+            }
+            // 保存测报灯图片数据到mongodb
+            iotCbdImgService.insertIotCbdimg(iotDevice, jsonObject, DateUtils.dateTimeNow());
+        }
+
+        SpringUtils.getBean(WarnPestService.class).process();
+
+        return AjaxResult.success();
+    }
+
+
 }

+ 13 - 0
src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/BzyDeviceImpl.java

@@ -6,6 +6,7 @@ import com.yunfeiyun.agmp.common.utils.DateUtils;
 import com.yunfeiyun.agmp.common.utils.JSONUtils;
 import com.yunfeiyun.agmp.common.utils.StringUtils;
 import com.yunfeiyun.agmp.common.utils.reflect.ReflectUtils;
+import com.yunfeiyun.agmp.common.utils.spring.SpringUtils;
 import com.yunfeiyun.agmp.iot.common.constant.cmd.CmdDef;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.ServiceNameConst;
 import com.yunfeiyun.agmp.iot.common.constant.mqtt.IotMqttConstant;
@@ -23,6 +24,7 @@ import com.yunfeiyun.agmp.iots.device.service.IBzyDevice;
 import com.yunfeiyun.agmp.iots.service.*;
 import com.yunfeiyun.agmp.iots.service.impl.IotBzyImgService;
 import com.yunfeiyun.agmp.iots.service.impl.IotDeviceAddressService;
+import com.yunfeiyun.agmp.iots.warn.service.WarnService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.http.util.TextUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -192,6 +194,7 @@ public class BzyDeviceImpl extends DeviceAbstractImpl implements IBzyDevice {
         newIotDevice.setDevtypeBid(devtypeBid);
         newIotDevice.setDevUpdateddate(devUpdateddate);
         newIotDevice.setDevStatus(IotDeviceStatusTypeEnum.ONLINE.getCode());
+        newIotDevice.setDevOriginalStatus(oldIotDevice.getDevOriginalStatus());
 
         HashMap<String, String> keyMaps = new HashMap<>();
         keyMaps.put("dver", "devVersion");
@@ -239,7 +242,17 @@ public class BzyDeviceImpl extends DeviceAbstractImpl implements IBzyDevice {
         newIotDevice.setDevBid(oldIotDevice.getDevBid());
         newIotDevice.setDevStatus("0");
         newIotDevice.setDevOfflinedate(DateUtils.dateTimeNow());
+        //这些参数预警需要用,携带过去
+        newIotDevice.setTid(oldIotDevice.getTid());
+        newIotDevice.setDevtypeBid(oldIotDevice.getDevtypeBid());
+        newIotDevice.setDevCreateddate(oldIotDevice.getDevCreateddate());
+        newIotDevice.setDevUpdateddate(oldIotDevice.getDevUpdateddate());
+        newIotDevice.setDevCode(oldIotDevice.getDevCode());
+        newIotDevice.setDevOriginalStatus(oldIotDevice.getDevOriginalStatus());
         iIotDeviceService.updateIotDevice(newIotDevice);
+
+        //发送离线预警
+        SpringUtils.getBean(WarnService.class).processWarningOfflineData(newIotDevice, ext);
     }
 
 

+ 13 - 0
src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/CqCbdDeviceImpl.java

@@ -6,6 +6,7 @@ import com.yunfeiyun.agmp.common.utils.DateUtils;
 import com.yunfeiyun.agmp.common.utils.JSONUtils;
 import com.yunfeiyun.agmp.common.utils.StringUtils;
 import com.yunfeiyun.agmp.common.utils.reflect.ReflectUtils;
+import com.yunfeiyun.agmp.common.utils.spring.SpringUtils;
 import com.yunfeiyun.agmp.iot.common.constant.cmd.CmdDef;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.ServiceNameConst;
 import com.yunfeiyun.agmp.iot.common.constant.mqtt.IotMqttConstant;
@@ -25,6 +26,7 @@ import com.yunfeiyun.agmp.iots.device.service.ICbdDevice;
 import com.yunfeiyun.agmp.iots.service.*;
 import com.yunfeiyun.agmp.iots.service.impl.IotCbdImgService;
 import com.yunfeiyun.agmp.iots.service.impl.IotDeviceAddressService;
+import com.yunfeiyun.agmp.iots.warn.service.WarnService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.http.util.TextUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -71,6 +73,7 @@ public class CqCbdDeviceImpl extends DeviceAbstractImpl implements ICbdDevice {
     @Autowired
     private IotDeviceAddressService iotDeviceAddressService;
 
+
     @Override
     public Object sendCmd(CmdModel cmdModel) throws Exception {
         log.info("【测报灯】发送指令 任务 cmdModel={}", cmdModel);
@@ -293,7 +296,17 @@ public class CqCbdDeviceImpl extends DeviceAbstractImpl implements ICbdDevice {
         newIotDevice.setDevBid(devId);
         newIotDevice.setDevStatus("0");
         newIotDevice.setDevOfflinedate(DateUtils.dateTimeNow());
+        newIotDevice.setTid(iotDevice.getTid());
+        newIotDevice.setDevtypeBid(iotDevice.getDevtypeBid());
+        newIotDevice.setDevOriginalStatus(iotDevice.getDevOriginalStatus());
+        newIotDevice.setDevCreateddate(iotDevice.getDevCreateddate());
+        newIotDevice.setDevUpdateddate(iotDevice.getDevUpdateddate());
+        newIotDevice.setDevCode(iotDevice.getDevCode());
         iIotDeviceService.updateIotDevice(newIotDevice);
+
+
+        //发送离线预警
+        SpringUtils.getBean(WarnService.class).processWarningOfflineData(newIotDevice, ext);
     }
 
     /**

+ 19 - 6
src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/IYfXctDeviceImpl.java

@@ -7,6 +7,7 @@ import com.yunfeiyun.agmp.common.utils.DateUtils;
 import com.yunfeiyun.agmp.common.utils.JSONUtils;
 import com.yunfeiyun.agmp.common.utils.StringUtils;
 import com.yunfeiyun.agmp.common.utils.reflect.ReflectUtils;
+import com.yunfeiyun.agmp.common.utils.spring.SpringUtils;
 import com.yunfeiyun.agmp.iot.common.constant.cmd.CmdDef;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.ServiceNameConst;
 import com.yunfeiyun.agmp.iot.common.constant.mqtt.IotMqttConstant;
@@ -30,6 +31,7 @@ import com.yunfeiyun.agmp.iots.service.IIotDeviceconfigService;
 import com.yunfeiyun.agmp.iots.service.IIotDevicelasteddataService;
 import com.yunfeiyun.agmp.iots.service.impl.IotCbdImgService;
 import com.yunfeiyun.agmp.iots.service.impl.IotDeviceAddressService;
+import com.yunfeiyun.agmp.iots.warn.service.WarnService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.http.util.TextUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -39,7 +41,7 @@ import java.util.*;
 
 @Component(ServiceNameConst.SERVICE_YF_XCT)
 @Slf4j
-public class  IYfXctDeviceImpl extends DeviceAbstractImpl implements IYfXctDevice {
+public class IYfXctDeviceImpl extends DeviceAbstractImpl implements IYfXctDevice {
     @Autowired
     private MqttManager mqttManager;
 
@@ -153,6 +155,7 @@ public class  IYfXctDeviceImpl extends DeviceAbstractImpl implements IYfXctDevic
         newIotDevice.setDevtypeBid(oldIotDevice.getDevtypeBid());
         newIotDevice.setDevUpdateddate(devUpdateddate);
         newIotDevice.setDevStatus(IotDeviceStatusTypeEnum.ONLINE.getCode());
+        newIotDevice.setDevOriginalStatus(oldIotDevice.getDevOriginalStatus());
 
         HashMap<String, String> keyMaps = new HashMap<>();
         keyMaps.put("dver", "devVersion");
@@ -238,7 +241,17 @@ public class  IYfXctDeviceImpl extends DeviceAbstractImpl implements IYfXctDevic
         newIotDevice.setDevBid(iotDevice.getDevBid());
         newIotDevice.setDevStatus(IotDeviceStatusTypeEnum.OFFLINE.getCode());
         newIotDevice.setDevOfflinedate(DateUtils.dateTimeNow());
+        newIotDevice.setTid(iotDevice.getTid());
+        newIotDevice.setDevtypeBid(iotDevice.getDevtypeBid());
+        newIotDevice.setDevCreateddate(iotDevice.getDevCreateddate());
+        newIotDevice.setDevUpdateddate(iotDevice.getDevUpdateddate());
+        newIotDevice.setDevCode(iotDevice.getDevCode());
+        newIotDevice.setDevOriginalStatus(iotDevice.getDevOriginalStatus());
         iIotDeviceService.updateIotDevice(newIotDevice);
+
+
+        //发送离线预警
+        SpringUtils.getBean(WarnService.class).processWarningOfflineData(newIotDevice, ext);
     }
 
     /**
@@ -256,12 +269,12 @@ public class  IYfXctDeviceImpl extends DeviceAbstractImpl implements IYfXctDevic
         if (StringUtils.isEmpty(devUpdateddate)) {
             devUpdateddate = DateUtils.dateTimeNow();
         }
-        if(topic.startsWith(IotMqttConstant.YFXctTopic.TOPIC_XCT_PEST_IMG)){
+        if (topic.startsWith(IotMqttConstant.YFXctTopic.TOPIC_XCT_PEST_IMG)) {
             Object result = this.receivePicData(dataJson, devUpdateddate, topic, connectionId);
             log.info("【吸虫塔】图片数据处理完成");
             return result;
         }
-        if(topic.startsWith(IotMqttConstant.YFCbdTopic.TOPIC_CBD_REPORT_PREFIX)){
+        if (topic.startsWith(IotMqttConstant.YFCbdTopic.TOPIC_CBD_REPORT_PREFIX)) {
             String cmd = dataJson.getString("cmd");
             JSONObject ext = dataJson.getJSONObject("ext");
             if (TextUtils.isEmpty(cmd)) {
@@ -289,7 +302,7 @@ public class  IYfXctDeviceImpl extends DeviceAbstractImpl implements IYfXctDevic
      * @param connectionId
      * @return
      */
- 
+
     public Object receivePicData(JSONObject jsonObject, String devUpdateddate, String topic, String connectionId) {
         IotDevice oldIotDevice = findIotDevice(topic, jsonObject, connectionId);
         if (oldIotDevice == null) {
@@ -334,8 +347,8 @@ public class  IYfXctDeviceImpl extends DeviceAbstractImpl implements IYfXctDevic
      * @return
      */
     @Override
-    public IotDevice findIotDevice(String topic, JSONObject jobjMsg,String connectionId) {
-        String devId = mqttManager.getDevIdByTopic(connectionId,topic);
+    public IotDevice findIotDevice(String topic, JSONObject jobjMsg, String connectionId) {
+        String devId = mqttManager.getDevIdByTopic(connectionId, topic);
         return iIotDeviceService.selectIotDeviceByDevBid(devId);
     }
 }

+ 13 - 24
src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/XphYfQxzDeviceImpl.java

@@ -7,6 +7,7 @@ import com.yunfeiyun.agmp.common.service.LocationService;
 import com.yunfeiyun.agmp.common.utils.DateUtils;
 import com.yunfeiyun.agmp.common.utils.JSONUtils;
 import com.yunfeiyun.agmp.common.utils.StringUtils;
+import com.yunfeiyun.agmp.common.utils.spring.SpringUtils;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.ServiceNameConst;
 import com.yunfeiyun.agmp.iot.common.constant.mqtt.IotMqttConstant;
 import com.yunfeiyun.agmp.iot.common.domain.*;
@@ -248,6 +249,7 @@ public class XphYfQxzDeviceImpl extends DeviceAbstractImpl implements IXphYfQxzD
         iotDevice.setDevCode(devCode);
         iotDevice.setDevBid(iotDeviceOld.getDevBid());
         iotDevice.setDevVersion(jobjStatus.getString("Version"));
+        iotDevice.setDevOriginalStatus(iotDeviceOld.getDevOriginalStatus());
 
         String lng = jobjStatus.getString("longitude");
         String lat = jobjStatus.getString("latitude");
@@ -303,33 +305,20 @@ public class XphYfQxzDeviceImpl extends DeviceAbstractImpl implements IXphYfQxzD
             newIotDevice.setDevOfflinedate(devUpdateddate);
         }else if("online".equalsIgnoreCase(cmd)){
             newIotDevice.setDevStatus("1");
-
         }
+        newIotDevice.setTid(iotDeviceOld.getTid());
         newIotDevice.setDevUpdateddate(devUpdateddate);
-
+        newIotDevice.setDevtypeBid(iotDeviceOld.getDevtypeBid());
+        newIotDevice.setDevCreateddate(iotDeviceOld.getDevCreateddate());
+        newIotDevice.setDevUpdateddate(iotDeviceOld.getDevUpdateddate());
+        newIotDevice.setDevCode(iotDeviceOld.getDevCode());
+        newIotDevice.setDevOriginalStatus(iotDeviceOld.getDevOriginalStatus());
         iIotDeviceService.updateIotDevice(newIotDevice);
-        // 主动进行查询,以确保不是误判离线
-        // 新普惠设备不能控制,不用在查询检测
-//        if("offline".equalsIgnoreCase(cmd)){
-//            new Thread(new Runnable() {
-//                @Override
-//                public void run() {
-//                    try {
-//                        Thread.sleep(2*1000);
-//                    }catch (InterruptedException e){
-//                        e.printStackTrace();
-//                    }
-//                    //主动进行查询,以确保不是误判离线
-//                    log.info("【YFQXZ】主动进行查询,以确保不是误判离线" + iotDeviceOld);
-//                    YfQxzReqMsg reqMsg = new YfQxzReqMsg();
-//                    JSONObject jobjParams = new JSONObject();
-//                    jobjParams.put("type","data");
-//                    reqMsg.setExt(jobjParams);
-//
-//                    publishMsg(iotDeviceOld, reqMsg);
-//                }
-//            }).start();
-//        }
+
+
+        //发送离线预警
+        SpringUtils.getBean(WarnService.class).processWarningOfflineData(newIotDevice, dataJson);
+
     }
 
     @Override

+ 12 - 1
src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/YfQxzDeviceImpl.java

@@ -7,6 +7,7 @@ import com.yunfeiyun.agmp.common.service.LocationService;
 import com.yunfeiyun.agmp.common.utils.DateUtils;
 import com.yunfeiyun.agmp.common.utils.JSONUtils;
 import com.yunfeiyun.agmp.common.utils.StringUtils;
+import com.yunfeiyun.agmp.common.utils.spring.SpringUtils;
 import com.yunfeiyun.agmp.iot.common.constant.cmd.CmdDef;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.ServiceNameConst;
 import com.yunfeiyun.agmp.iot.common.constant.mqtt.IotMqttConstant;
@@ -395,6 +396,7 @@ public class YfQxzDeviceImpl extends DeviceAbstractImpl implements IYfQxzDevice
         iotDevice.setFirmBid(iotDeviceOld.getFirmBid());
         iotDevice.setDevUpdateddate(devUpdateddate);
         iotDevice.setDevStatus("1");
+        iotDevice.setDevOriginalStatus(iotDeviceOld.getDevOriginalStatus());
 
         iotDevice.setDevCode(devCode);
         iotDevice.setDevBid(iotDeviceOld.getDevBid());
@@ -448,7 +450,8 @@ public class YfQxzDeviceImpl extends DeviceAbstractImpl implements IYfQxzDevice
         // 设备不存在 就不再处理
         IotDevice newIotDevice = new IotDevice();
         newIotDevice.setDevBid(iotDeviceOld.getDevBid());
-
+        newIotDevice.setTid(iotDeviceOld.getTid());
+        newIotDevice.setDevtypeBid(iotDeviceOld.getDevtypeBid());
         if("offline".equalsIgnoreCase(cmd)){
             newIotDevice.setDevStatus("0");
             newIotDevice.setDevOfflinedate(devUpdateddate);
@@ -456,7 +459,15 @@ public class YfQxzDeviceImpl extends DeviceAbstractImpl implements IYfQxzDevice
             newIotDevice.setDevStatus("1");
             newIotDevice.setDevUpdateddate(devUpdateddate);
         }
+        newIotDevice.setDevOriginalStatus(iotDeviceOld.getDevOriginalStatus());
+        newIotDevice.setDevCreateddate(iotDeviceOld.getDevCreateddate());
+        newIotDevice.setDevUpdateddate(iotDeviceOld.getDevUpdateddate());
+        newIotDevice.setDevCode(iotDeviceOld.getDevCode());
         iIotDeviceService.updateIotDevice(newIotDevice);
+
+
+        //发送离线预警
+        SpringUtils.getBean(WarnService.class).processWarningOfflineData(newIotDevice, ext);
         // 主动进行查询,以确保不是误判离线
 
         if("offline".equalsIgnoreCase(cmd)){

+ 13 - 1
src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/YfScdDeviceImpl.java

@@ -5,6 +5,7 @@ import com.yunfeiyun.agmp.common.utils.DateUtils;
 import com.yunfeiyun.agmp.common.utils.JSONUtils;
 import com.yunfeiyun.agmp.common.utils.StringUtils;
 import com.yunfeiyun.agmp.common.utils.reflect.ReflectUtils;
+import com.yunfeiyun.agmp.common.utils.spring.SpringUtils;
 import com.yunfeiyun.agmp.iot.common.constant.cmd.CmdDef;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.IotDeviceDictConst;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.ServiceNameConst;
@@ -17,6 +18,7 @@ import com.yunfeiyun.agmp.iots.service.IIotYfScddataService;
 import com.yunfeiyun.agmp.iots.device.service.IYfScdDevice;
 import com.yunfeiyun.agmp.iots.service.*;
 import com.yunfeiyun.agmp.iots.service.impl.IotDeviceAddressService;
+import com.yunfeiyun.agmp.iots.warn.service.WarnService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.http.util.TextUtils;
 import org.eclipse.paho.client.mqttv3.MqttException;
@@ -158,7 +160,7 @@ public class YfScdDeviceImpl extends DeviceAbstractImpl implements IYfScdDevice
         iotDevice.setDevBid(oldIotDevice.getDevBid());
         iotDevice.setDevUpdateddate(devUpdateddate);
         iotDevice.setDevStatus("1");//设备上线
-
+        iotDevice.setDevOriginalStatus(oldIotDevice.getDevOriginalStatus());
         HashMap<String, String> keyMaps = new HashMap<>();
         keyMaps.put("dver", "devVersion");
         keyMaps.put("imei", "devCode");
@@ -226,8 +228,18 @@ public class YfScdDeviceImpl extends DeviceAbstractImpl implements IYfScdDevice
         newIotDevice.setDevBid(oldIotDevice.getDevBid());
         newIotDevice.setDevStatus("0");
         newIotDevice.setDevOfflinedate(DateUtils.dateTimeNow());
+        newIotDevice.setTid(oldIotDevice.getTid());
+        newIotDevice.setDevtypeBid(oldIotDevice.getDevtypeBid());
+        newIotDevice.setDevCreateddate(oldIotDevice.getDevCreateddate());
+        newIotDevice.setDevUpdateddate(oldIotDevice.getDevUpdateddate());
+        newIotDevice.setDevCode(oldIotDevice.getDevCode());
+        newIotDevice.setDevOriginalStatus(oldIotDevice.getDevOriginalStatus());
         iIotDeviceService.updateIotDevice(newIotDevice);
 
+
+        //发送离线预警
+        SpringUtils.getBean(WarnService.class).processWarningOfflineData(newIotDevice, dataJson);
+
         /**
          * 下发刷新指令,检测设备是否真离线
          */

+ 1 - 0
src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/YfXycb2DeviceImpl.java

@@ -90,6 +90,7 @@ public class YfXycb2DeviceImpl extends DeviceAbstractImpl implements IYfXycb2Dev
         newIotDevice.setDevVersion("YF-XY-2.0");
         newIotDevice.setDevUpdateddate(devUpdateddate);
         newIotDevice.setDevStatus(IotDeviceStatusTypeEnum.ONLINE.getCode());
+        newIotDevice.setDevOriginalStatus(oldIotDevice.getDevOriginalStatus());
 
         // 更新设备基础信息数据库 mysql
         iIotDeviceService.updateIotDevice(newIotDevice);

+ 13 - 0
src/main/java/com/yunfeiyun/agmp/iots/device/serviceImp/YfXycbIIIDeviceImpl.java

@@ -5,6 +5,7 @@ import com.alibaba.fastjson2.JSONObject;
 import com.yunfeiyun.agmp.common.utils.DateUtils;
 import com.yunfeiyun.agmp.common.utils.JSONUtils;
 import com.yunfeiyun.agmp.common.utils.StringUtils;
+import com.yunfeiyun.agmp.common.utils.spring.SpringUtils;
 import com.yunfeiyun.agmp.iot.common.constant.cmd.CmdDef;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.IotDeviceDictEnum;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.ServiceNameConst;
@@ -19,6 +20,7 @@ import com.yunfeiyun.agmp.iots.service.IIotYfXycbIIIdataService;
 import com.yunfeiyun.agmp.iots.device.service.IYfXycbIIIDevice;
 import com.yunfeiyun.agmp.iots.service.*;
 import com.yunfeiyun.agmp.iots.service.impl.IotDeviceAddressService;
+import com.yunfeiyun.agmp.iots.warn.service.WarnService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.http.util.TextUtils;
 import org.eclipse.paho.client.mqttv3.MqttException;
@@ -87,6 +89,8 @@ public class YfXycbIIIDeviceImpl extends DeviceAbstractImpl implements IYfXycbII
         newIotDevice.setDevVersion("YF-XY-III");
         newIotDevice.setDevUpdateddate(devUpdateddate);
         newIotDevice.setDevStatus(IotDeviceStatusTypeEnum.ONLINE.getCode());
+        newIotDevice.setDevCode(oldIotDevice.getDevCode());
+        newIotDevice.setDevOriginalStatus(oldIotDevice.getDevOriginalStatus());
 
         String[] keyArrays = {
                 "ts",
@@ -204,8 +208,17 @@ public class YfXycbIIIDeviceImpl extends DeviceAbstractImpl implements IYfXycbII
         newIotDevice.setDevBid(oldIotDevice.getDevBid());
         newIotDevice.setDevStatus("0");
         newIotDevice.setDevOfflinedate(devUpdateddate);
+        newIotDevice.setTid(oldIotDevice.getTid());
+        newIotDevice.setDevtypeBid(oldIotDevice.getDevtypeBid());
+        newIotDevice.setDevCreateddate(oldIotDevice.getDevCreateddate());
+        newIotDevice.setDevUpdateddate(oldIotDevice.getDevUpdateddate());
+        newIotDevice.setDevCode(oldIotDevice.getDevCode());
+        newIotDevice.setDevOriginalStatus(oldIotDevice.getDevOriginalStatus());
         iIotDeviceService.updateIotDevice(newIotDevice);
 
+
+        //发送离线预警
+        SpringUtils.getBean(WarnService.class).processWarningOfflineData(newIotDevice, dataJson);
         /**
          * 下发刷新指令,检测设备是否真离线
          */

+ 0 - 13
src/main/java/com/yunfeiyun/agmp/iots/service/impl/IotCbdImgService.java

@@ -43,9 +43,6 @@ public class IotCbdImgService {
     @Resource
     private IIotPestService iotPestService;
 
-
-
-
     @Autowired
     private IIotDeviceService iIotDeviceService;
 
@@ -174,16 +171,6 @@ public class IotCbdImgService {
         iotCbdimg.setCbdrecog(cbdrecog);
         mongoService.saveOne(iotCbdimg);
 
-//        if("3".equals(warnService.getWarnVer()) ){
-//            //要求预警检查 V3
-//            IotWarncheck warncheck = new IotWarncheck();
-//            warncheck.setDevBid(iotDevice.getDevBid());
-//            // TODO
-//            // iotsMqService.sendMsg(IotMqConstant.TOPIC_WARNCHECK, IotMqConstant.TOPIC_WARNCHECK, warncheck);
-//        }else{
-//            //预警
-//            warnService.checkCbdData("0","",iotDevice.getDevBid());
-//        }
         return iotCbdimg;
     }
 

+ 13 - 35
src/main/java/com/yunfeiyun/agmp/iots/service/impl/IotDeviceServiceImpl.java

@@ -2,15 +2,15 @@ package com.yunfeiyun.agmp.iots.service.impl;
 
 import com.yunfeiyun.agmp.common.utils.DateUtils;
 import com.yunfeiyun.agmp.common.utils.StringUtils;
-import com.yunfeiyun.agmp.common.web.system.service.ISysConfigService;
 import com.yunfeiyun.agmp.iot.common.constant.IotErrorCode;
 import com.yunfeiyun.agmp.iot.common.domain.IotDevice;
 import com.yunfeiyun.agmp.iot.common.exception.IotBizException;
 import com.yunfeiyun.agmp.iot.common.model.device.IotDeviceStatusResVo;
-import com.yunfeiyun.agmp.iot.common.service.MongoService;
 import com.yunfeiyun.agmp.iots.device.mapper.IotDeviceMapper;
 import com.yunfeiyun.agmp.iots.service.IIotDeviceService;
 import com.yunfeiyun.agmp.iot.common.service.IotDeviceGeoLocationCommonService;
+import com.yunfeiyun.agmp.iots.warn.service.WarnService;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -28,19 +28,17 @@ import java.util.Map;
  * @date 2024-01-04
  */
 @Service
+@Slf4j
 public class IotDeviceServiceImpl implements IIotDeviceService {
 
     @Autowired
     private IotDeviceMapper iotDeviceMapper;
 
     @Autowired
-    private ISysConfigService sysConfigService;
-
-    @Autowired
-    private MongoService mongoService;
+    private IotDeviceGeoLocationCommonService iotDeviceGeoLocationCommonService;
 
     @Autowired
-    private IotDeviceGeoLocationCommonService iotDeviceGeoLocationCommonService;
+    private WarnService warnService;
 
     /**
      * 查询设备基础
@@ -92,9 +90,6 @@ public class IotDeviceServiceImpl implements IIotDeviceService {
      */
     @Override
     public int updateIotDevice(IotDevice iotDevice) {
-        if (needFakeStatus(iotDevice.getDevBid())) {
-            iotDevice.setDevStatus("1");
-        }
         List<IotDevice> iotDeviceList = new ArrayList<>();
         iotDeviceList.add(iotDevice);
         return updateIotDeviceBatch(iotDeviceList);
@@ -106,19 +101,20 @@ public class IotDeviceServiceImpl implements IIotDeviceService {
     @Transactional(rollbackFor = Exception.class)
     @Override
     public int updateIotDeviceBatch(List<IotDevice> iotDeviceList) {
-        for (IotDevice iotDevice : iotDeviceList) {
-            if (needFakeStatus(iotDevice.getDevBid())) {
-                iotDevice.setDevStatus("1");
-            }
-        }
         int status = iotDeviceMapper.updateIotDeviceBatch(iotDeviceList);
         iotDeviceGeoLocationCommonService.insertOrUpdateBatchData(iotDeviceList);
+        //检查离线告警消息
+        warnService.processWarningOfflineToOnlineDeviceData(iotDeviceList);
         return status;
     }
 
     @Override
     public IotDevice selectIotDeviceByDevBid(String devBid) {
-        return iotDeviceMapper.selectIotDeviceByDevBid(devBid);
+        IotDevice iotDevice = iotDeviceMapper.selectIotDeviceByDevBid(devBid);
+        if (iotDevice != null) {
+            iotDevice.setDevOriginalStatus(iotDevice.getDevStatus());
+        }
+        return iotDevice;
     }
 
     @Override
@@ -171,7 +167,7 @@ public class IotDeviceServiceImpl implements IIotDeviceService {
     @Override
     public void updateIotDeviceExtInfo(String devBid, String extInfo) {
         String updateDate = DateUtils.dateTimeNow();
-        iotDeviceMapper.updateIotDeviceExtInfo(devBid, extInfo,updateDate);
+        iotDeviceMapper.updateIotDeviceExtInfo(devBid, extInfo, updateDate);
     }
 
     @Override
@@ -191,22 +187,4 @@ public class IotDeviceServiceImpl implements IIotDeviceService {
     }
 
 
-    /**
-     * 是否是属于需要忽略状态的设备
-     *
-     * @param devBid
-     * @return
-     */
-    private boolean needFakeStatus(String devBid) {
-        String ignorStatusDeviceList = sysConfigService.selectConfigValueByCommonKey("iot_ignor_status_devicelist");
-        String[] ignorStatusDevBids = ignorStatusDeviceList.split(",");
-        //判断devbid是否在忽略状态设备列表中
-        for (String ignorDevBid : ignorStatusDevBids) {
-            if (ignorDevBid.equals(devBid)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
 }

+ 1 - 1
src/main/java/com/yunfeiyun/agmp/iots/task/AdznGssqScheduler.java

@@ -3,8 +3,8 @@ package com.yunfeiyun.agmp.iots.task;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.IotDeviceDictConst;
 import com.yunfeiyun.agmp.iot.common.domain.IotDevice;
 import com.yunfeiyun.agmp.iot.common.enums.ybq.YbqTypeConst;
-import com.yunfeiyun.agmp.iots.core.manager.HttpManager;
 import com.yunfeiyun.agmp.iots.core.http.AdznGssqService;
+import com.yunfeiyun.agmp.iots.core.manager.HttpManager;
 import com.yunfeiyun.agmp.iots.service.IIotDeviceService;
 import com.yunfeiyun.agmp.iots.service.IIotDevicelasteddataService;
 import lombok.extern.slf4j.Slf4j;

+ 74 - 101
src/main/java/com/yunfeiyun/agmp/iots/task/IotStatusService.java

@@ -10,6 +10,7 @@ import com.yunfeiyun.agmp.iot.common.model.device.IotDeviceStatusResVo;
 import com.yunfeiyun.agmp.iots.core.manager.ConnectionManager;
 import com.yunfeiyun.agmp.iots.service.IIotDeviceService;
 import com.yunfeiyun.agmp.iots.service.IIotDeviceconfigService;
+import com.yunfeiyun.agmp.iots.warn.service.WarnService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -27,8 +28,7 @@ import java.util.*;
 @Slf4j
 public class IotStatusService {
     /**
-     * 用于存放检测的设备类型
-     * 稳定后,所有设备都基于devcieConfig 更新最新数据,进而统一监控
+     * 用于存放检测的设备类型,saas需要检测所有的,看似无用,保留它按类型检查搜索设备,集中处理
      */
     private Set validateDeviceType = new HashSet();
 
@@ -37,78 +37,62 @@ public class IotStatusService {
 
     @Autowired
     IIotDeviceconfigService iIotDeviceconfigService;
+
     @Resource
     private ConnectionManager connectionManager;
 
+    @Autowired
+    private WarnService warnService;
+
     @PostConstruct
     void init() {
-        // 目前基于已经实现将最新数据放到DeviceConfig的设备,没有的将进行实现
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_YF_CBD);// 云飞测报灯
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_YF_BZY);// 云飞孢子仪
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_YF_SCD);// 云飞杀虫灯
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_YF_SQZ);// 云飞墒情站
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_YF_QXZ);// 云飞环境监测
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_XPH_YF_GSSQ);// 新浦会管式墒情
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_XPH_YF_SQZ);// 新浦会云飞墒情站
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_ADZN_GSSQ);// 爱迪智农管式墒情
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_YF_XYCB_2);// 性诱测报2.0
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_YF_XYCB_III);// 云飞-性诱测报灯III
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_ZJSF_XYCB);// 中捷四方性诱
-//        validateDeviceType.add(IotDeviceDictConst.TYPE_YF_XCT);// 云飞吸虫塔
-
-
-        //validateDeviceType.add(IotDeviceDictConst.TYPE_ZHAO_HE_SFJ);// 赵赫水肥机
-
-        //validateDeviceType.add(IotDeviceDictConst.TYPE_XPH_LDSW_JC);// 新浦会雷达水位监测
-        //validateDeviceType.add(IotDeviceDictConst.TYPE_XPH_SZZX_JC);// 新浦会水质在线监测
-        //validateDeviceType.add(IotDeviceDictConst.TYPE_XPH_WSHJ_JC);// 新浦会温室环境监测
-
-        //validateDeviceType.add(IotDeviceDictConst.TYPE_YF_GXZW);// 根系作物
-        //validateDeviceType.add(IotDeviceDictConst.TYPE_XPH_TRSH_CL);// 新普惠土壤水势
-        //validateDeviceType.add(IotDeviceDictConst.TYPE_XPH_WSKZ);// 新浦会温室环境控制
-        //validateDeviceType.add(IotDeviceDictConst.TYPE_HPF_WSMJ_ZNKG);// 海普发智能温室控制
-
-        //validateDeviceType.add(IotDeviceDictConst.TYPE_BY_SFJ);// 云飞水肥机
-        //validateDeviceType.add(IotDeviceDictConst.TYPE_HT_SFJ);// 宏泰水肥机
-
         String[] deviceTypes = {
+                IotDeviceDictConst.TYPE_DAHUA_DEVICE,
+                IotDeviceDictConst.TYPE_HIK_OPEN_DEVICE,
+                IotDeviceDictConst.TYPE_BIG_DATA_MONITOR_DEVICE,
+                IotDeviceDictConst.TYPE_OB_NTSWJ,
                 IotDeviceDictConst.TYPE_YF_CBD,
-                IotDeviceDictConst.TYPE_YF_BZY,
                 IotDeviceDictConst.TYPE_YF_SCD,
                 IotDeviceDictConst.TYPE_YF_SQZ,
                 IotDeviceDictConst.TYPE_YF_QXZ,
-                IotDeviceDictConst.TYPE_XPH_YF_GSSQ,
-                IotDeviceDictConst.TYPE_XPH_YF_SQZ,
-                IotDeviceDictConst.TYPE_ADZN_GSSQ,
-                IotDeviceDictConst.TYPE_YF_XYCB_2,
-                IotDeviceDictConst.TYPE_YF_XYCB_III,
-                IotDeviceDictConst.TYPE_ZJSF_XYCB,
-                IotDeviceDictConst.TYPE_YF_XCT,
+                IotDeviceDictConst.TYPE_YF_GKCBD,
+                IotDeviceDictConst.TYPE_YF_SDCBD,
+                IotDeviceDictConst.TYPE_YF_FXSSCD,
+                IotDeviceDictConst.TYPE_YF_JGFXSSCD,
+                IotDeviceDictConst.TYPE_XPH_YF_QXZ,
+                IotDeviceDictConst.TYPE_XPH_GP_QXZ,
                 IotDeviceDictConst.TYPE_HS_YBQ_DWB,
                 IotDeviceDictConst.TYPE_HS_YBQ_CMB,
                 IotDeviceDictConst.TYPE_HS_YBQ_DBB,
                 IotDeviceDictConst.TYPE_HS_YBQ_TXB,
-                IotDeviceDictConst.TYPE_HS_YBQ_BFB
-        };
+                IotDeviceDictConst.TYPE_HS_YBQ_BFB,
+                IotDeviceDictConst.TYPE_ADZN_GSSQ,
+                IotDeviceDictConst.TYPE_YF_BZY,
+                IotDeviceDictConst.TYPE_YF_XYCB_III,
+                IotDeviceDictConst.TYPE_DAHUA_YUNRUI_DEVICE,
+                IotDeviceDictConst.TYPE_EZVIZ_JKSB,
+                IotDeviceDictConst.TYPE_XPH_YF_SQZ,
+                IotDeviceDictConst.TYPE_XPH_YF_GSSQ,
+                IotDeviceDictConst.TYPE_ZJSF_XYCB,
+                IotDeviceDictConst.TYPE_YF_XYCB_2,
+                IotDeviceDictConst.TYPE_YF_XCT,
 
+        };
         Collections.addAll(validateDeviceType, deviceTypes);
-
-
         try {
             validateStatusByDevType();
         } catch (Exception e) {
             log.error("【设备检测】异常", e);
         }
-
     }
 
     /**
      * 定期根据类型查设备最新设备数据,是否长时间不上报。
      */
-//    @Scheduled(cron = "30 * * * * ?")
-    @Scheduled(cron = "0 0/20 * * * ? ")
+    // @Scheduled(cron = "30 * * * * ?")
+    @Scheduled(cron = "0 0 * * * ?")
     public void validateStatusByDevType() {
-        if(!connectionManager.initCompleted()){
+        if (!connectionManager.initCompleted()) {
             return;
         }
         Iterator<String> iterator = validateDeviceType.iterator();
@@ -127,66 +111,25 @@ public class IotStatusService {
         log.info("【设备检测开始 类型:{}】#########################", type);
         Map param = new HashMap();
         param.put("type", type);
-        // 查出来待检查的设备。根据类型
-        if(Objects.equals(type, IotDeviceDictConst.TYPE_YF_XCT)){
-            log.info("【吸虫塔检测");
-        }
         List<IotDeviceStatusResVo> iotDeviceStatusResVos = iIotDeviceService.selectAllDeviceConfigStatus(param);
         log.info("【设备检测】【设备类型{} 】设备:{} 个", type, iotDeviceStatusResVos.size());
         for (IotDeviceStatusResVo iotDeviceStatusResVo : iotDeviceStatusResVos) {
             try {
                 // 获取设备类型id,存在的在进行检查,因为有些设备不是基于device config 上报
                 String devtypeBid = iotDeviceStatusResVo.getDevtypeBid();
-                if (validateDeviceType.contains(devtypeBid)) {
-                    String devStatus = iotDeviceStatusResVo.getDevStatus();
-                    // 获取最新上报时间
-                    // 如果没有更新的上报时间,使用创建时间
-                    //      因为刚创建的离线设备,不会上报激活设备,导致设备一直处于待激活状态
-                    // 如果没有更新的上报时间,则跳过不处理,正常他本身就是离线
-                    String updateTime = iotDeviceStatusResVo.getDevUpdateddate();
-                    if(StringUtils.isEmpty(updateTime) && IotDeviceStatusTypeEnum.WAIT_ACTIVATE.getCode().equals(devStatus)){
-                        updateTime = iotDeviceStatusResVo.getDevCreateddate();
-                    }
-
-                    if (StringUtils.isEmpty(updateTime)) {
-                        continue;
-                    }
-                    String devCode = iotDeviceStatusResVo.getDevCode();
-                    String devName = iotDeviceStatusResVo.getDevName();
-                    String devBid = iotDeviceStatusResVo.getDevBid();
-
-                    // 检查时间上报间隔是否异常,60分钟没有,则异常
-                    if (!validateTime(updateTime, 90)) {
-                        log.info("【设备检测】【正常】:设备:{} {} 上次时间:{}", iotDeviceStatusResVo.getDevName(), iotDeviceStatusResVo.getDevCode(), updateTime);
-                        continue;
-                    }
-                    // 1. 当前在线的进行检查;
-                    if (!IotDeviceStatusTypeEnum.OFFLINE.getCode().equals(devStatus)) {
-                        // 更新状态
-                        IotDevice iotDevice = new IotDevice();
-                        iotDevice.setDevCode(iotDeviceStatusResVo.getDevCode());
-                        iotDevice.setDevBid(devBid);
-                        iotDevice.setDevStatus(IotDeviceStatusTypeEnum.OFFLINE.getCode());
-                        iotDevice.setDevOfflinedate(DateUtils.dateTimeNow());
-                        iotDevice.setDevModifieddate(DateUtils.dateTimeNow());
-                        iotDevice.setDevtypeBid(iotDeviceStatusResVo.getDevtypeBid());
-                        iotDevice.setDevconnBid(iotDeviceStatusResVo.getDevconnBid());
-
-                        if(IotDeviceStatusTypeEnum.WAIT_ACTIVATE.getCode().equals(devStatus)){
-                            iotDevice.setDevUpdateddate(iotDeviceStatusResVo.getDevCreateddate());
-                        }
-                        iIotDeviceService.updateIotDevice(iotDevice);
-                        log.info("【设备检测】【设备状态异常更新-设备类型{} 】设备标识:{} 设备编号 {} 设备名称 {} 异常状态 {}", type, devBid, devCode, devName, iotDeviceStatusResVo.getDevStatus());
-                        reCreateDeviceTopic(iotDevice);
-                    }else{
-                        log.info("【设备检测】【设备状态异常更新-不处理-设备类型{} 】设备标识:{} 设备编号 {} 设备名称 {} 异常状态 {}", type, devBid, devCode, devName, iotDeviceStatusResVo.getDevStatus());
-
-                        // 更新状态
-//                        IotDevice iotDevice = new IotDevice();
-//                        iotDevice.setDevBid(devBid);
-//                        iotDevice.setDevStatus(IotDeviceStatusTypeEnum.ONLINE.getCode());
-//                        iIotDeviceService.updateIotDevice(iotDevice);
-                    }
+                if (!validateDeviceType.contains(devtypeBid)) {
+                    continue;
+                }
+                // 不管状态,只要超过时间,就将他改为离线
+                // 1. 本身是离线,一个周期检查后还是离线,告警
+                // 2. 本身是在线,发现上报数据没上报,告警
+                // 3. 本身处于待激活,没有更新时间,改为离线,告警
+                String updateTime = iotDeviceStatusResVo.getDevUpdateddate();
+                log.info("【设备检测】【异常】:设备:{} {} 上次时间:{}", iotDeviceStatusResVo.getDevName(), iotDeviceStatusResVo.getDevCode(), updateTime);
+                // updateTime时间为空,或者 检查时间上报间隔超过60min
+                if (StringUtils.isEmpty(updateTime) || validateTime(updateTime, 60)) {
+                    //处理离线的设备
+                    handleOfflineDevice(iotDeviceStatusResVo);
                 }
             } catch (Exception e) {
                 log.info("【设备检测】【程序异常】:设备:{} {} {} {}", iotDeviceStatusResVo.getDevName(), iotDeviceStatusResVo.getDevCode(), iotDeviceStatusResVo, e);
@@ -196,6 +139,36 @@ public class IotStatusService {
     }
 
     /**
+     * 集中处理离线设备
+     *
+     * @param iotDeviceStatusResVo
+     */
+    void handleOfflineDevice(IotDeviceStatusResVo iotDeviceStatusResVo) {
+        String devCode = iotDeviceStatusResVo.getDevCode();
+        String devName = iotDeviceStatusResVo.getDevName();
+        String devBid = iotDeviceStatusResVo.getDevBid();
+        // 更新状态
+        IotDevice iotDevice = new IotDevice();
+        iotDevice.setDevCode(iotDeviceStatusResVo.getDevCode());
+        iotDevice.setDevBid(iotDeviceStatusResVo.getDevBid());
+        iotDevice.setDevOriginalStatus(iotDeviceStatusResVo.getDevStatus());
+        iotDevice.setDevStatus(IotDeviceStatusTypeEnum.OFFLINE.getCode());
+        iotDevice.setDevOfflinedate(DateUtils.dateTimeNow());
+        iotDevice.setDevModifieddate(DateUtils.dateTimeNow());
+        iotDevice.setDevtypeBid(iotDeviceStatusResVo.getDevtypeBid());
+        iotDevice.setDevconnBid(iotDeviceStatusResVo.getDevconnBid());
+        iotDevice.setTid(iotDeviceStatusResVo.getTid());
+        iotDevice.setDevCreateddate(iotDeviceStatusResVo.getDevCreateddate());
+        iotDevice.setDevUpdateddate(iotDeviceStatusResVo.getDevUpdateddate());
+        //编辑离线
+        iIotDeviceService.updateIotDevice(iotDevice);
+        //发送预警
+        warnService.processWarningOfflineData(iotDevice);
+        log.info("【设备检测】【设备状态异常更新-设备类型{} 】设备标识:{} 设备编号 {} 设备名称 {} 异常状态 {}", iotDeviceStatusResVo.getDevtypeBid(), devBid, devCode, devName, iotDeviceStatusResVo.getDevStatus());
+        reCreateDeviceTopic(iotDevice);
+    }
+
+    /**
      * 重新订阅和构建topic
      *
      * @param iotDevice

+ 38 - 1
src/main/java/com/yunfeiyun/agmp/iots/warn/job/WarnJob.java

@@ -1,8 +1,10 @@
 package com.yunfeiyun.agmp.iots.warn.job;
 
 import com.yunfeiyun.agmp.iots.warn.service.ReCountService;
+import com.yunfeiyun.agmp.iots.warn.service.WarnService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
@@ -13,6 +15,13 @@ public class WarnJob {
     @Autowired
     private ReCountService reCountService;
 
+
+    @Autowired
+    private WarnService warnService;
+
+    @Value("${warn.cbdDateDiff:1}")
+    private String cbdDateDiff;
+
     /**
      * 每天凌晨12点清除重复次数...
      */
@@ -25,9 +34,37 @@ public class WarnJob {
     /**
      * 每2时执行一次...
      */
-    @Scheduled(cron = "0 0 0/2 * * ?")
+    //@Scheduled(cron = "0 0 0/2 * * ?")
     public void resetReCount2() {
         log.info("【设备预警】定时清空所有重复次数,临时配置,0 0 0/2 * * ?  每2时执行一次");
         reCountService.resetAllReCount();
     }
+
+    /**
+     * 病虫害告警定时检查方法
+     */
+    @Scheduled(cron = "0 0/20 * * * ?")
+    public void pestWarnJob20() {
+        if("0".equals(cbdDateDiff)){
+            log.info("【设备预警】测报类检测,0 0/20 * * * ?  临时配置 每20分钟执行一次");
+            // 处理虫害
+            warnService.processWarningPestData();
+            // 处理病害
+            warnService.processWarningDiseaseData();
+        }
+    }
+
+    /**
+     * 每天八点
+     */
+    @Scheduled(cron = "0 0 8 * * ?")
+    public void pestWarnJob08() {
+        log.info("【设备预警】测报类检测,0 0 8 * * ?  每天8点执行一次");
+        // 处理虫害
+        warnService.processWarningPestData();
+        // 处理病害
+        warnService.processWarningDiseaseData();
+
+    }
+
 }

+ 31 - 1
src/main/java/com/yunfeiyun/agmp/iots/warn/mapper/IotWarnBussinessMapper.java

@@ -1,7 +1,10 @@
 package com.yunfeiyun.agmp.iots.warn.mapper;
 
+import com.yunfeiyun.agmp.iot.common.domain.IotWarnconfig;
 import com.yunfeiyun.agmp.iot.common.domain.IotWarncount;
+import com.yunfeiyun.agmp.iot.common.domain.IotWarnindicator;
 import com.yunfeiyun.agmp.iot.common.domain.IotWarnlog;
+import com.yunfeiyun.agmp.iots.warn.model.IotWarnconfigDevVo;
 import com.yunfeiyun.agmp.iots.warn.model.WarnConfigInfo;
 import org.apache.ibatis.annotations.Param;
 
@@ -49,5 +52,32 @@ public interface IotWarnBussinessMapper {
 
     List<WarnConfigInfo> selectIotWarnConfigInfoList(WarnConfigInfo warnConfigInfo);
 
-    int resetReCountByDevIdAndConfigId(@Param("devBid") String devBid, @Param("wcBid") String configId);
+    int resetReCountByDevBidAndConfigId(@Param("devBid") String devBid, @Param("wcBid") String configId);
+
+    IotWarnconfig selectIotWarnOfflineConfigInfo(@Param("tid") String tid);
+
+    List<String> selectAllTid();
+
+    int insertIotOfflineWarnconfig(IotWarnconfig iotWarnconfig);
+
+    void autoDealWarnOfflineLog(IotWarnlog iotWarnlog);
+
+    List<IotWarnindicator> selectIotWarnPestConfigInfoList(@Param("code") String code);
+
+    List<IotWarnindicator> selectIotWarnindicatorList(IotWarnindicator iotWarnindicator);
+
+
+    /**
+     * 查询测报灯设备所有告警配置信息列表
+     * @return
+     */
+    List<IotWarnindicator> selectCbdIndicatorAllList();
+
+
+    /**
+     * 查询测报灯设备所有告警配置信息列表
+     *
+     * @return
+     */
+    List<IotWarnconfigDevVo> selectIotWarnconfigCbdDevList();
 }

+ 9 - 0
src/main/java/com/yunfeiyun/agmp/iots/warn/model/CountResultDto.java

@@ -0,0 +1,9 @@
+package com.yunfeiyun.agmp.iots.warn.model;
+
+import lombok.Data;
+
+@Data
+public class CountResultDto {
+    private int pestTypesCount;
+
+}

+ 16 - 0
src/main/java/com/yunfeiyun/agmp/iots/warn/model/IotWarnconfigCbdInfoVo.java

@@ -0,0 +1,16 @@
+package com.yunfeiyun.agmp.iots.warn.model;
+
+import com.yunfeiyun.agmp.iot.common.domain.IotDevice;
+import com.yunfeiyun.agmp.iot.common.domain.IotWarnconfig;
+import com.yunfeiyun.agmp.iot.common.domain.IotWarnindicator;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class IotWarnconfigCbdInfoVo extends IotWarnconfig {
+
+    private IotDevice iotDevice;
+
+    private List<IotWarnindicator> iotWarnindicatorList;
+}

+ 13 - 0
src/main/java/com/yunfeiyun/agmp/iots/warn/model/IotWarnconfigDevVo.java

@@ -0,0 +1,13 @@
+package com.yunfeiyun.agmp.iots.warn.model;
+
+import com.yunfeiyun.agmp.iot.common.domain.IotWarnconfig;
+import lombok.Data;
+
+@Data
+public class IotWarnconfigDevVo extends IotWarnconfig {
+    private String wiBid;
+    private String devBid;
+    private String devCode;
+    private String devtypeBid;
+    private String devCbdrecogtype;
+}

+ 1 - 1
src/main/java/com/yunfeiyun/agmp/iots/warn/model/WarnQxSqInfoDto.java

@@ -10,7 +10,7 @@ import java.util.List;
 import java.util.Map;
 
 @Data
-public class WarnQxSqInfoDto {
+public class WarnInfoDto {
     private IotDevice iotDevice;
     private List<WarnConfigInfo> configList;
     private JSONObject jsonObject;

+ 9 - 0
src/main/java/com/yunfeiyun/agmp/iots/warn/model/WarnPestDetailStatDto.java

@@ -0,0 +1,9 @@
+package com.yunfeiyun.agmp.iots.warn.model;
+
+import lombok.Data;
+
+@Data
+public class WarnPestDetailStatDto {
+    private String pestBusid;
+    private int totalPestCount;
+}

+ 7 - 0
src/main/java/com/yunfeiyun/agmp/iots/warn/model/WarnResult.java

@@ -49,11 +49,18 @@ public class WarnResult extends IotBaseEntity {
      */
     private IotWarnconfig config;
 
+    /**
+     * 是不是离线指标
+     */
+    private boolean isOffline;
+
     public WarnResult(boolean isTriggered, String message) {
         this.isTriggered = isTriggered;
         this.message = message;
+        this.isOffline = false;
     }
 
     public WarnResult() {
+        this.isOffline = false;
     }
 }

+ 278 - 33
src/main/java/com/yunfeiyun/agmp/iots/warn/service/IotWarnBussinessService.java

@@ -4,67 +4,70 @@ import com.yunfeiyun.agmp.common.enums.RedisCacheKey;
 import com.yunfeiyun.agmp.common.framework.manager.RedisCacheManager;
 import com.yunfeiyun.agmp.common.utils.DateUtils;
 import com.yunfeiyun.agmp.common.utils.uuid.IdUtils;
-import com.yunfeiyun.agmp.iot.common.domain.IotWarncount;
-import com.yunfeiyun.agmp.iot.common.domain.IotWarnlog;
+import com.yunfeiyun.agmp.iot.common.domain.*;
 import com.yunfeiyun.agmp.iots.warn.mapper.IotWarnBussinessMapper;
-import com.yunfeiyun.agmp.iots.warn.model.WarnConfigInfo;
-import com.yunfeiyun.agmp.iots.warn.model.WarnResult;
+import com.yunfeiyun.agmp.iots.warn.model.*;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.aggregation.*;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 @Service
 @Slf4j
 public class IotWarnBussinessService {
 
     @Autowired
-    private IotWarnBussinessMapper iotWarncountMapper;
+    private IotWarnBussinessMapper iotWarnBussinessMapper;
 
     @Resource
     private RedisCacheManager redisCacheManager;
 
-    public Long selectIotWarnCountByDevAndConfig(String devId, String configId) {
-        log.info("查询设备ID: {}, 配置ID: {} 的重复次数", devId, configId);
-        Long count = redisCacheManager.getCacheObject(RedisCacheKey.IOT_WARN_RE_COUNTS, configId + ":" + devId);
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+    public Long selectIotWarnCountByDevAndConfig(String devBid, String configId) {
+        log.info("查询设备ID: {}, 配置ID: {} 的重复次数", devBid, configId);
+        Long count = redisCacheManager.getCacheObject(RedisCacheKey.IOT_WARN_RE_COUNTS, configId + ":" + devBid);
         if (count != null) {
             log.info("从缓存中获取到重复次数: {}", count);
             return count;
         }
-        IotWarncount iotWarncount = iotWarncountMapper.selectIotWarnCountByDevAndConfig(devId, configId);
+        IotWarncount iotWarncount = iotWarnBussinessMapper.selectIotWarnCountByDevAndConfig(devBid, configId);
         if (iotWarncount == null) {
-            log.warn("数据库中未找到设备ID: {}, 配置ID: {} 的重复次数数据", devId, configId);
+            log.warn("数据库中未找到设备ID: {}, 配置ID: {} 的重复次数数据", devBid, configId);
             return null;
         } else {
             log.info("从数据库中获取到重复次数: {}, 并将其加入缓存", iotWarncount.getWctCount());
-            redisCacheManager.setCacheObject(RedisCacheKey.IOT_WARN_RE_COUNTS, configId + ":" + devId, iotWarncount.getWctCount());
+            redisCacheManager.setCacheObject(RedisCacheKey.IOT_WARN_RE_COUNTS, configId + ":" + devBid, iotWarncount.getWctCount());
             return iotWarncount.getWctCount();
         }
     }
 
-    public int incrementReCount(Long reCount, String devId, String configId, String tid) {
-        log.info("增加设备ID: {}, 配置ID: {} 的重复次数", devId, configId);
+    public int incrementReCount(Long reCount, String devBid, String configId, String tid) {
+        log.info("增加设备ID: {}, 配置ID: {} 的重复次数", devBid, configId);
         if (reCount == null) {
             log.info("初始化重复次数为1");
             IotWarncount iotWarncount = new IotWarncount();
             iotWarncount.setWctBid(IdUtils.fastUUID());
-            iotWarncount.setDevBid(devId);
+            iotWarncount.setDevBid(devBid);
             iotWarncount.setWcBid(configId);
             iotWarncount.setLastUpdateTime(DateUtils.dateTimeNow());
             iotWarncount.setWctCount(1L);
             iotWarncount.setTid(tid);
-            int result = iotWarncountMapper.insertIncrementReCount(iotWarncount);
-            redisCacheManager.setCacheObject(RedisCacheKey.IOT_WARN_RE_COUNTS, configId + ":" + devId, iotWarncount.getWctCount());
+            int result = iotWarnBussinessMapper.insertIncrementReCount(iotWarncount);
+            redisCacheManager.setCacheObject(RedisCacheKey.IOT_WARN_RE_COUNTS, configId + ":" + devBid, iotWarncount.getWctCount());
             log.info("初始化重复次数成功, 结果: {}", result);
             return result;
         } else {
-            int result = iotWarncountMapper.updateIncrementReCount(devId, configId);
-            redisCacheManager.setCacheObject(RedisCacheKey.IOT_WARN_RE_COUNTS, configId + ":" + devId, reCount + 1);
+            int result = iotWarnBussinessMapper.updateIncrementReCount(devBid, configId);
+            redisCacheManager.setCacheObject(RedisCacheKey.IOT_WARN_RE_COUNTS, configId + ":" + devBid, reCount + 1);
             log.info("更新重复次数成功, 新的重复次数: {}", reCount + 1);
             return result;
         }
@@ -76,42 +79,48 @@ public class IotWarnBussinessService {
 
     public int resetReCount() {
         log.info("重置所有重复次数");
-        List<IotWarncount> iotWarncounts = iotWarncountMapper.getAllReCount();
+        List<IotWarncount> iotWarncounts = iotWarnBussinessMapper.getAllReCount();
         for (IotWarncount iotWarncount : iotWarncounts) {
             try {
                 redisCacheManager.deleteObject(RedisCacheKey.IOT_WARN_RE_COUNTS, iotWarncount.getWcBid() + ":" + iotWarncount.getDevBid());
-                log.info("重置所有重复次数:配置id:{},设备id{},成功", iotWarncount.getWcBid() , iotWarncount.getDevBid());
+                log.info("重置所有重复次数:配置id:{},设备id{},成功", iotWarncount.getWcBid(), iotWarncount.getDevBid());
             } catch (Exception e) {
-                log.info("重置所有重复次数:配置id:{},设备id{},异常:{}", iotWarncount.getWcBid() , iotWarncount.getDevBid(), e);
+                log.info("重置所有重复次数:配置id:{},设备id{},异常:{}", iotWarncount.getWcBid(), iotWarncount.getDevBid(), e);
             }
         }
-        int result = iotWarncountMapper.resetReCount();
+        int result = iotWarnBussinessMapper.resetReCount();
         log.info("重置所有重复次数结果: {}", result);
         return result;
     }
 
-    public int resetReCountByDevIdAndConfigId(String devId, String configId) {
-        log.info("重置设备ID: {}, 配置ID: {} 的重复次数", devId, configId);
-        redisCacheManager.deleteObject(RedisCacheKey.IOT_WARN_RE_COUNTS, configId + ":" + devId);
-        int result = iotWarncountMapper.resetReCountByDevIdAndConfigId(devId, configId);
+    public int resetReCountByDevBidAndConfigId(String devBid, String configId) {
+        log.info("重置设备ID: {}, 配置ID: {} 的重复次数", devBid, configId);
+        redisCacheManager.deleteObject(RedisCacheKey.IOT_WARN_RE_COUNTS, configId + ":" + devBid);
+        int result = iotWarnBussinessMapper.resetReCountByDevBidAndConfigId(devBid, configId);
         log.info("重置结果: {}", result);
         return result;
     }
 
     public int insertWarnRecord(IotWarnlog iotWarnlog) {
         log.info("插入预警记录: {}", iotWarnlog);
-        int result = iotWarncountMapper.insertWarnRecord(iotWarnlog);
+        int result = iotWarnBussinessMapper.insertWarnRecord(iotWarnlog);
         log.info("插入预警记录结果: {}", result);
         return result;
     }
 
-    List<WarnConfigInfo> selectIotWarnConfigInfoList(WarnConfigInfo warnConfigInfo) {
+    public List<WarnConfigInfo> selectIotWarnConfigInfoList(WarnConfigInfo warnConfigInfo) {
         log.info("查询预警配置信息列表");
-        List<WarnConfigInfo> list = iotWarncountMapper.selectIotWarnConfigInfoList(warnConfigInfo);
+        List<WarnConfigInfo> list = iotWarnBussinessMapper.selectIotWarnConfigInfoList(warnConfigInfo);
         log.info("查询到 {} 条预警配置信息", list.size());
         return list;
     }
 
+    public IotWarnconfig selectIotWarnOfflineConfigInfo(String tid) {
+        log.info("查询预警离线配置tid:{}", tid);
+        IotWarnconfig list = iotWarnBussinessMapper.selectIotWarnOfflineConfigInfo(tid);
+        return list;
+    }
+
     Map<String, List<WarnConfigInfo>> selectIotWarnConfigInfoMap(WarnConfigInfo warnConfigInfo) {
         log.info("构建预警配置信息映射");
         List<WarnConfigInfo> warnConfigInfoList = selectIotWarnConfigInfoList(warnConfigInfo);
@@ -126,4 +135,240 @@ public class IotWarnBussinessService {
         log.info("构建完成,共包含 {} 个不同的配置ID", warnConfigInfoMap.size());
         return warnConfigInfoMap;
     }
+
+    public List<String> selectAllTid() {
+        return iotWarnBussinessMapper.selectAllTid();
+    }
+
+    /**
+     * 插入离线告警规则
+     *
+     * @param tid
+     * @return
+     */
+    public int insertIotOfflineWarnConfig(String tid) {
+        IotWarnconfig iotWarnconfig = new IotWarnconfig();
+        iotWarnconfig.setWcBid(IdUtils.fastUUID());
+        iotWarnconfig.setWcName("离线告警");
+        iotWarnconfig.setWcDesc("离线告警");
+        iotWarnconfig.setWcStatus("0");
+        iotWarnconfig.setWcLevel("0");
+        iotWarnconfig.setWcTouchtype("1");
+        iotWarnconfig.setWcCreator("system");
+        iotWarnconfig.setWcCreateddate(DateUtils.dateTimeNow());
+        iotWarnconfig.setTid(tid);
+        return iotWarnBussinessMapper.insertIotOfflineWarnconfig(iotWarnconfig);
+    }
+
+    /**
+     * 设备若正常上报数据后,则离线告警自动处理
+     *
+     * @param devBid
+     */
+    public void autoDealWarnOfflineLog(String devBid) {
+        IotWarnlog iotWarnlog = new IotWarnlog();
+        iotWarnlog.setDevBid(devBid);
+        iotWarnlog.setWlDealtime(DateUtils.dateTimeNow());
+        iotWarnlog.setWlDealresult("该设备已于" + DateUtils.dateTimeNow() + "上报数据,离线告警自动恢复。");
+        iotWarnlog.setStatus("1");
+        iotWarnBussinessMapper.autoDealWarnOfflineLog(iotWarnlog);
+    }
+
+    /**
+     * 查询虫情的指定配置列表。集中处理
+     *
+     * @param code
+     * @return
+     */
+    public List<IotWarnindicator> selectIotWarnPestConfigInfoList(String code) {
+        log.info("查询虫情的指定配置列表");
+        List<IotWarnindicator> list = iotWarnBussinessMapper.selectIotWarnPestConfigInfoList(code);
+        log.info("查询到 {} 条预警配置信息", list.size());
+        return list;
+    }
+
+    /**
+     * 统计设备的虫子种类数量
+     *
+     * @param devBid    设备业务标识
+     * @param startTime 开始时间
+     * @param endTime   结束时间
+     * @return 虫子种类数量
+     */
+    public int statPestTypeCountByDevBid(String devBid, String startTime, String endTime) {
+        // 创建匹配条件
+        MatchOperation matchOperation = Aggregation.match(
+                new Criteria().andOperator(
+                        Criteria.where("devBid").is(devBid),
+                        Criteria.where("pestrecogCreatedDate").gte(startTime).lte(endTime)
+                )
+        );
+
+        // 分组操作,按pestBusid分组
+        GroupOperation groupOperation = Aggregation.group("pestBusid");
+
+        // 计数操作
+        CountOperation countOperation = Aggregation.count().as("pestTypesCount");
+
+        // 构建聚合管道
+        Aggregation aggregation = Aggregation.newAggregation(matchOperation, groupOperation, countOperation);
+
+        // 执行聚合查询
+        AggregationResults<CountResultDto> results = mongoTemplate.aggregate(aggregation, "IotPestrecog", CountResultDto.class);
+
+        // 获取结果
+        List<CountResultDto> mappedResults = results.getMappedResults();
+        if (mappedResults != null && !mappedResults.isEmpty()) {
+            return mappedResults.get(0).getPestTypesCount();
+        }
+
+        // 如果没有结果,则返回0
+        return 0;
+    }
+
+
+    /**
+     * 统计设备的虫子总数量
+     *
+     * @param devBid    设备业务标识
+     * @param startTime 开始时间
+     * @param endTime   结束时间
+     * @return 虫子总数量
+     */
+    public int statPestCountByDevBid(String devBid, String startTime, String endTime) {
+        Query query = new Query();
+
+        // 添加条件:设备业务标识
+        query.addCriteria(Criteria.where("devBid").is(devBid));
+
+        // 添加条件:创建时间在指定范围内
+        query.addCriteria(Criteria.where("pestrecogCreatedDate").gte(startTime).lte(endTime));
+
+        // 使用聚合查询统计害虫数量
+        Aggregation aggregation = Aggregation.newAggregation(
+                Aggregation.match(Criteria.where("devBid").is(devBid)
+                        .and("pestrecogCreatedDate").gte(startTime).lte(endTime)),
+                Aggregation.group().sum("pestrecogNum").as("totalPestCount")
+        );
+
+        // 执行聚合查询
+        AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, "IotPestrecog", Map.class);
+        Map<String, Object> result = results.getUniqueMappedResult();
+
+        // 获取统计结果,默认为0
+        return result != null ? ((Number) result.get("totalPestCount")).intValue() : 0;
+    }
+
+    public List<WarnPestDetailStatDto> statPestDetailByDevBid(IotDevice iotDevice, String startTime, String endTime) {
+        String devBid = iotDevice.getDevBid();
+        String devCbdrecogtype = iotDevice.getDevCbdrecogtype();
+
+        // 添加条件:设备业务标识
+        Criteria criteria = Criteria.where("devBid").is(devBid)
+                .and("cbdrecogType").is(devCbdrecogtype)
+                .and("pestrecogCreatedDate").gte(startTime).lte(endTime);
+
+        MatchOperation matchOperation = Aggregation.match(criteria);
+        GroupOperation groupOperation = Aggregation.group("pestBusid")
+                .sum("pestrecogNum").as("totalPestCount");
+        ProjectionOperation projectionOperation = Aggregation.project()
+                .and("_id").as("pestBusid")
+                .and("totalPestCount").as("totalPestCount");
+        // 使用聚合查询统计害虫数量
+        Aggregation aggregation = Aggregation.newAggregation(
+                matchOperation,
+                groupOperation,
+                projectionOperation
+        );
+
+        // 执行聚合查询
+        AggregationResults<WarnPestDetailStatDto> results = mongoTemplate.aggregate(aggregation, "IotPestrecog", WarnPestDetailStatDto.class);
+        return results.getMappedResults();
+    }
+
+    /**
+     * 查询告警指标,存储所有与告警相关的指标信息列表
+     *
+     * @param iotWarnindicator 告警指标,存储所有与告警相关的指标信息
+     * @return 告警指标,存储所有与告警相关的指标信息集合
+     */
+    public Map<String, List<IotWarnindicator>> selectIotWarnindicatorMap(IotWarnindicator iotWarnindicator) {
+        List<IotWarnindicator> iotWarnindicatorList = iotWarnBussinessMapper.selectIotWarnindicatorList(iotWarnindicator);
+        Map<String, List<IotWarnindicator>> iotWarnindicatorMap = new HashMap<>();
+        for (IotWarnindicator item : iotWarnindicatorList) {
+            String wcBid = item.getWcBid();
+            if (!iotWarnindicatorMap.containsKey(wcBid)) {
+                iotWarnindicatorMap.put(wcBid, new ArrayList<>());
+            }
+            iotWarnindicatorMap.get(wcBid).add(item);
+        }
+        return iotWarnindicatorMap;
+    }
+
+    /**
+     * 查询测报灯设备所有告警配置信息
+     *
+     * @return
+     */
+
+    public Map<String, List<IotWarnindicator>> selectCbdIndicatorAllMap() {
+        List<IotWarnindicator> iotWarnindicators = iotWarnBussinessMapper.selectCbdIndicatorAllList();
+        Map<String, List<IotWarnindicator>> iotWarnindicatorMap = new LinkedHashMap<>();
+        for (IotWarnindicator iotWarnindicator : iotWarnindicators) {
+            String wcBid = iotWarnindicator.getWcBid();
+            if (!iotWarnindicatorMap.containsKey(wcBid)) {
+                iotWarnindicatorMap.put(wcBid, new ArrayList<>());
+            }
+            iotWarnindicatorMap.get(wcBid).add(iotWarnindicator);
+        }
+        return iotWarnindicatorMap;
+    }
+
+    /**
+     * 查询测报灯设备所有告警配置信息列表
+     *
+     * @return
+     */
+
+    public List<IotWarnconfigCbdInfoVo> selectIotWarnconfigCbdInfoList() {
+        List<IotWarnconfigDevVo> iotWarnconfigDevVoList = iotWarnBussinessMapper.selectIotWarnconfigCbdDevList();
+        Map<String, List<IotWarnindicator>> iotWarnindicatorMap = selectCbdIndicatorAllMap();
+        List<IotWarnconfigCbdInfoVo> iotWarnconfigCbdInfoVoList = new ArrayList<>();
+        List<String> parentbidList = new ArrayList<>();
+        for (IotWarnconfigDevVo iotWarnconfigDevVo : iotWarnconfigDevVoList) {
+            String wcBid = iotWarnconfigDevVo.getWcBid();
+            List<IotWarnindicator> iotWarnindicatorList = iotWarnindicatorMap.get(wcBid);
+            for (IotWarnindicator item : iotWarnindicatorList) {
+                String wiCode = item.getWiCode();
+                if ("pestDetail".equals(wiCode)) {
+                    parentbidList.add(item.getWiBid());
+                }
+            }
+            IotDevice iotDevice = new IotDevice();
+            BeanUtils.copyProperties(iotWarnconfigDevVo, iotDevice);
+
+            IotWarnconfigCbdInfoVo iotWarnconfigCbdInfoVo = new IotWarnconfigCbdInfoVo();
+            BeanUtils.copyProperties(iotWarnconfigDevVo, iotWarnconfigCbdInfoVo);
+            iotWarnconfigCbdInfoVo.setIotDevice(iotDevice);
+            iotWarnconfigCbdInfoVo.setIotWarnindicatorList(iotWarnindicatorList);
+            iotWarnconfigCbdInfoVoList.add(iotWarnconfigCbdInfoVo);
+        }
+        if (!parentbidList.isEmpty()) {
+            IotWarnindicator selectIotWarnindicator = new IotWarnindicator();
+            selectIotWarnindicator.setWiParentbidList(parentbidList);
+            Map<String, List<IotWarnindicator>> iotMap = selectIotWarnindicatorMap(selectIotWarnindicator);
+            for (IotWarnconfigCbdInfoVo cbdInfoVo : iotWarnconfigCbdInfoVoList) {
+                String wcBid = cbdInfoVo.getWcBid();
+                List<IotWarnindicator> pestDetailList = iotMap.get(wcBid);
+                List<IotWarnindicator> iotWarnindicatorList = cbdInfoVo.getIotWarnindicatorList();
+                for (IotWarnindicator item : iotWarnindicatorList) {
+                    String wiCode = item.getWiCode();
+                    if ("pestDetail".equals(wiCode)) {
+                        item.setChildrenList(pestDetailList);
+                    }
+                }
+            }
+        }
+        return iotWarnconfigCbdInfoVoList;
+    }
 }

+ 9 - 3
src/main/java/com/yunfeiyun/agmp/iots/warn/service/ReCountService.java

@@ -29,9 +29,15 @@ public class ReCountService {
     public void handlerMessage(WarnResult warnResult) {
         // 注意必要字段必须传过来
         validateMessageParam(warnResult);
-
         String messageId = warnResult.getMessageId();
         log.info("【设备预警】消息标识{}:处理数据:{}", messageId, warnResult);
+
+        // 离线的只用直接入库即可
+        if (warnResult.isTriggered() && warnResult.isOffline()) {
+            log.info("【设备预警】消息标识{}:当前设备ID:{},离线告警", messageId, warnResult.getDevId(), warnResult.getConfigId(), warnResult);
+            iotWarnBussinessService.insertWarnRecord(buildWarnMessage(messageId, warnResult));
+            return;
+        }
         // 触发了预警,进行校验处理
         if (warnResult.isTriggered()) {
             Long reCount = iotWarnBussinessService.selectIotWarnCountByDevAndConfig(warnResult.getDevId(), warnResult.getConfigId());
@@ -41,7 +47,7 @@ public class ReCountService {
             if (thisReCount + 1 > targetReCount) {
                 log.info("【设备预警】消息标识{}:达到或超过阈值, 不再增加重复次数,直接生成预警记录", messageId);
                 iotWarnBussinessService.insertWarnRecord(buildWarnMessage(messageId, warnResult));
-            }else {
+            } else {
                 log.info("【设备预警】消息标识{}:未达阈值, 增加重复次数", messageId);
                 iotWarnBussinessService.incrementReCount(reCount, warnResult);
             }
@@ -121,7 +127,7 @@ public class ReCountService {
         }
         if (count != 0) {
             log.info("【设备预警】消息标识{}:重置设备ID:{}, 配置ID:{} 的重复计数", messageId, devId, configId);
-            iotWarnBussinessService.resetReCountByDevIdAndConfigId(devId, configId);
+            iotWarnBussinessService.resetReCountByDevBidAndConfigId(devId, configId);
         }
     }
 

+ 341 - 0
src/main/java/com/yunfeiyun/agmp/iots/warn/service/WarnPestService.java

@@ -0,0 +1,341 @@
+package com.yunfeiyun.agmp.iots.warn.service;
+
+import com.yunfeiyun.agmp.common.constant.ErrorCode;
+import com.yunfeiyun.agmp.common.exception.BizException;
+import com.yunfeiyun.agmp.common.utils.DateUtils;
+import com.yunfeiyun.agmp.common.utils.StringUtils;
+import com.yunfeiyun.agmp.iot.common.constant.devicetype.IotDeviceDictEnum;
+import com.yunfeiyun.agmp.iot.common.domain.IotDevice;
+import com.yunfeiyun.agmp.iot.common.domain.IotPest;
+import com.yunfeiyun.agmp.iot.common.domain.IotWarnconfig;
+import com.yunfeiyun.agmp.iot.common.domain.IotWarnindicator;
+import com.yunfeiyun.agmp.iot.common.enums.EnumWarnRuleOp;
+import com.yunfeiyun.agmp.iots.service.IIotPestService;
+import com.yunfeiyun.agmp.iots.warn.model.IotWarnconfigCbdInfoVo;
+import com.yunfeiyun.agmp.iots.warn.model.WarnPestDetailStatDto;
+import com.yunfeiyun.agmp.iots.warn.model.WarnResult;
+import com.yunfeiyun.agmp.iots.warn.model.WarnStatusDto;
+import com.yunfeiyun.agmp.iots.warn.util.CompareUtil;
+import com.yunfeiyun.agmp.iots.warn.util.WarnMessageBuilderUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+
+@Service
+@Slf4j
+public class WarnPestService {
+    @Autowired
+    private IotWarnBussinessService iotWarnBussinessService;
+    @Autowired
+    private ReCountService reCountService;
+
+    @Autowired
+    private IIotPestService iotPestService;
+
+    @Value("${warn.cbdDateDiff:1}")
+    private String cbdDateDiff;
+
+    /**
+     * 虫害处理入口
+     */
+    public void process() {
+        //单个配置单个设备的处理逻辑,外层需要遍历
+        List<IotWarnconfigCbdInfoVo> iotWarnconfigCbdInfoVoList = iotWarnBussinessService.selectIotWarnconfigCbdInfoList();
+        for (IotWarnconfigCbdInfoVo iotWarnconfigCbdInfoVo : iotWarnconfigCbdInfoVoList) {
+            try {
+                IotDevice iotDevice = iotWarnconfigCbdInfoVo.getIotDevice();
+                String devBid = iotDevice.getDevBid();
+                List<IotWarnindicator> iotWarnindicatorList = iotWarnconfigCbdInfoVo.getIotWarnindicatorList();
+                IotWarnconfig iotWarnconfig = new IotWarnconfig();
+                BeanUtils.copyProperties(iotWarnconfigCbdInfoVo, iotWarnconfig);
+
+                IotWarnindicator pestByTypeWarnindicator = new IotWarnindicator();
+                IotWarnindicator pestByCountWarnindicator = new IotWarnindicator();
+                IotWarnindicator designatePestWarnindicator = new IotWarnindicator();
+                for (IotWarnindicator iotWarnindicator : iotWarnindicatorList) {
+                    BeanUtils.copyProperties(iotDevice, iotWarnindicator);
+
+                    if ("pestType".equals(iotWarnindicator.getWiCode())) {
+                        BeanUtils.copyProperties(iotWarnindicator, pestByTypeWarnindicator);
+                    } else if ("pestNum".equals(iotWarnindicator.getWiCode())) {
+                        BeanUtils.copyProperties(iotWarnindicator, pestByCountWarnindicator);
+                    } else if ("pestDetail".equals(iotWarnindicator.getWiCode())) {
+                        BeanUtils.copyProperties(iotWarnindicator, designatePestWarnindicator);
+                    }
+                }
+                //底层调用:统一处理一个虫情设备的三个要素
+                processPestIotWarnindicators(iotDevice, iotWarnconfig, pestByTypeWarnindicator, pestByCountWarnindicator, designatePestWarnindicator);
+            } catch (Exception e) {
+                log.error("{}", e);
+            }
+        }
+    }
+
+    /**
+     * 处理一个虫情设备的三个要素
+     *
+     * @param devId
+     * @param iotWarnconfig
+     * @param pestByTypeWarnindicator
+     * @param pestByCountWarnindicator
+     * @param designatePestWarnindicator
+     */
+    private void processPestIotWarnindicators(IotDevice iotDevice, IotWarnconfig iotWarnconfig, IotWarnindicator pestByTypeWarnindicator, IotWarnindicator pestByCountWarnindicator, IotWarnindicator designatePestWarnindicator) {
+        WarnStatusDto pestByType = processPestByType(iotDevice, pestByTypeWarnindicator);
+        WarnStatusDto pestByCount = processPestByCount(iotDevice, pestByCountWarnindicator);
+        List<WarnStatusDto> warnStatusDtoList = processPestByDesignatePest(iotDevice, designatePestWarnindicator);
+        //合并结果
+        String devBid = iotDevice.getDevBid();
+        handlerAllWarnLog(devBid, iotWarnconfig, pestByType, pestByCount, warnStatusDtoList);
+    }
+
+    /**
+     * 根据虫害类型处理
+     */
+    private WarnStatusDto processPestByType(IotDevice iotDevice, IotWarnindicator iotWarnindicator) {
+        validateParam(iotWarnindicator);
+        String datePre = getDateBefore();
+        String startTime = datePre + " 00:00:00";
+        String endTime = datePre + " 23:59:59";
+        String devBid = iotWarnindicator.getDevBid();
+        int currentValue = iotWarnBussinessService.statPestTypeCountByDevBid(devBid, startTime, endTime);
+        return buildWarnStatusDto(currentValue, iotWarnindicator);
+    }
+
+    String getDateBefore() {
+        int cbdDateDiffInt = Integer.parseInt(cbdDateDiff);
+        return DateUtils.parseDateToStr("yyyy-MM-dd", DateUtils.addDays(new Date(), -cbdDateDiffInt));
+    }
+
+    /**
+     * 根据虫害总数处理
+     */
+    private WarnStatusDto processPestByCount(IotDevice iotDevice, IotWarnindicator iotWarnindicator) {
+        validateParam(iotWarnindicator);
+        String datePre = getDateBefore();
+        String startTime = datePre + " 00:00:00";
+        String endTime = datePre + " 23:59:59";
+        String devBid = iotDevice.getDevBid();
+        int currentValue = iotWarnBussinessService.statPestCountByDevBid(devBid, startTime, endTime);
+        return buildWarnStatusDto(currentValue, iotWarnindicator);
+    }
+
+    /**
+     * @param currentValue
+     * @param iotWarnindicator
+     * @return
+     */
+    private WarnStatusDto buildWarnStatusDto(int currentValue, IotWarnindicator iotWarnindicator) {
+        String expression = iotWarnindicator.getWiExpression();
+        String targetValue = iotWarnindicator.getWiValue();
+        String statue = iotWarnindicator.getWiStatus();
+        //开启的处理
+        if ("0".equals(statue)) {
+            String devtypeBid = iotWarnindicator.getDevtypeBid();
+            EnumWarnRuleOp warnRuleOp = EnumWarnRuleOp.findEnumByCode(expression);
+            String devType = IotDeviceDictEnum.getLv1NameByCode(devtypeBid);
+            boolean tempSuccess = CompareUtil.comp(currentValue + "", expression, targetValue);
+            WarnStatusDto warnStatusDto = new WarnStatusDto();
+            warnStatusDto.setDevType(devType);
+            warnStatusDto.setDevCode(iotWarnindicator.getDevCode());
+            warnStatusDto.setName(iotWarnindicator.getWiName());
+            warnStatusDto.setValue(currentValue + "");
+            warnStatusDto.setUnit(iotWarnindicator.getWiUnit());
+            warnStatusDto.setOpt(warnRuleOp.getName());
+            warnStatusDto.setIndicatorValue(targetValue);
+            warnStatusDto.setWarn(tempSuccess);
+            return warnStatusDto;
+        }
+        return null;
+    }
+
+    /**
+     * 根据指定虫害处理
+     */
+    private List<WarnStatusDto> processPestByDesignatePest(IotDevice iotDevice, IotWarnindicator iotWarnindicator) {
+        validateParam(iotWarnindicator);
+        List<IotWarnindicator> childrenList = iotWarnindicator.getChildrenList();
+        List<WarnStatusDto> warnStatusDtoList = new ArrayList<>();
+
+        if(Objects.equals(iotWarnindicator.getWiStatus(), "1")){
+            return warnStatusDtoList;
+        }
+
+        if(childrenList == null || childrenList.isEmpty()){
+            return warnStatusDtoList;
+        }
+
+        HashMap<String, IotPest> iotPestHashMap = iotPestService.selectIotPestHashMap(null);
+        Map<String, IotWarnindicator> iotWarnindicatorMap = new HashMap<>();
+        for (IotWarnindicator item : childrenList) {
+            item.setDevBid(iotWarnindicator.getDevBid());
+            item.setDevtypeBid(iotWarnindicator.getDevtypeBid());
+            item.setDevCode(iotWarnindicator.getDevCode());
+
+            String pestId = item.getWiCode();
+            IotPest iotPest = iotPestHashMap.get(pestId);
+            if (iotPest == null) {
+                log.error("【设备预警】虫害:配置ID: {}, 虫情ID: {} 不存在", iotWarnindicator.getWcBid(), pestId);
+                continue;
+            }
+            iotWarnindicatorMap.put(iotPest.getPestBid(), item);
+        }
+        String datePre = getDateBefore();
+        String startTime = datePre + " 00:00:00";
+        String endTime = datePre + " 23:59:59";
+        List<WarnPestDetailStatDto> warnPestDetailStatDtoList = iotWarnBussinessService.statPestDetailByDevBid(iotDevice, startTime, endTime);
+
+        for (WarnPestDetailStatDto item : warnPestDetailStatDtoList) {
+            String pestBusid = item.getPestBusid();
+            int totalPestCount = item.getTotalPestCount();
+            IotWarnindicator iotWarnindicatorItem = iotWarnindicatorMap.get(pestBusid); //根据虫情业务id获取虫情配置
+            if (iotWarnindicatorItem == null) {
+                continue;
+            }
+            WarnStatusDto warnStatusDto = buildWarnStatusDto(totalPestCount, iotWarnindicatorItem);
+            if(warnStatusDto != null && warnStatusDto.isWarn()){
+                warnStatusDtoList.add(warnStatusDto);
+            }
+        }
+        return warnStatusDtoList;
+    }
+
+    /**
+     * 将三个的告警处理结果合并
+     *
+     * @param devBid
+     * @param iotWarnconfig
+     * @param pestByType
+     * @param pestByCount
+     * @param designatePest
+     */
+    private void handlerAllWarnLog(String devBid, IotWarnconfig iotWarnconfig, WarnStatusDto pestByType, WarnStatusDto pestByCount, List<WarnStatusDto> warnStatusDtoList) {
+        if (StringUtils.isEmpty(devBid)) {
+            log.error("【设备预警】病虫害:设备id 不可为空. 设备ID: {}, 配置ID: {}", devBid, iotWarnconfig.getWcBid());
+            throw new BizException(ErrorCode.FAILURE.getCode(), "病虫害:设备id 不可为空");
+        }
+        log.info("开始处理设备ID为 {}, 配置ID为 {} 的预警信息", devBid, iotWarnconfig.getWcBid());
+        log.info("开始处理设备ID为 {}, 配置ID为 {} 的预警信息:pestByType: {}", iotWarnconfig.getWcBid(), devBid, pestByType);
+        log.info("开始处理设备ID为 {}, 配置ID为 {} 的预警信息:pestByCount: {}", iotWarnconfig.getWcBid(), devBid, pestByCount);
+        log.info("开始处理设备ID为 {}, 配置ID为 {} 的预警信息:designatePest: {}", devBid, iotWarnconfig.getWcBid(), warnStatusDtoList);
+
+        String pestByTypeMessage = null;
+        String pestByCountMessage = null;
+        String designatePestMessage = null;
+        boolean isWarn = false;
+        String devType = null;
+        String devCode = null;
+
+        // 构建消息
+        if (pestByType != null && pestByType.isWarn()) {
+            devType = pestByType.getDevType();
+            devCode = pestByType.getDevCode();
+
+            pestByTypeMessage = WarnMessageBuilderUtil.buildWarningMessage(
+                    null,
+                    null,
+                    pestByType.getName(),
+                    pestByType.getValue(),
+                    pestByType.getUnit(),
+                    pestByType.getOpt(),
+                    pestByType.getIndicatorValue()
+            );
+            log.info("根据类型生成警告消息: {}. 设备ID: {}, 配置ID: {}", pestByTypeMessage, devBid, iotWarnconfig.getWcBid());
+            isWarn = true;
+        }
+
+        if (pestByCount != null && pestByCount.isWarn()) {
+            devType = pestByCount.getDevType();
+            devCode = pestByCount.getDevCode();
+
+            pestByCountMessage = WarnMessageBuilderUtil.buildWarningMessage(
+                    null,
+                    null,
+                    pestByCount.getName(),
+                    pestByCount.getValue(),
+                    pestByCount.getUnit(),
+                    pestByCount.getOpt(),
+                    pestByCount.getIndicatorValue()
+            );
+            log.info("根据数量生成警告消息: {}. 设备ID: {}, 配置ID: {}", pestByCountMessage, devBid, iotWarnconfig.getWcBid());
+            isWarn = true;
+        }
+        StringBuilder messageBuilder = new StringBuilder();
+        if(warnStatusDtoList != null && !warnStatusDtoList.isEmpty()) {
+            messageBuilder.append("指定虫害: \n");
+            for(WarnStatusDto warnStatusDto : warnStatusDtoList) {
+                devType = warnStatusDto.getDevType();
+                devCode = warnStatusDto.getDevCode();
+
+                String message = WarnMessageBuilderUtil.buildWarningMessage(
+                        null,
+                        null,
+                        warnStatusDto.getName(),
+                        warnStatusDto.getValue(),
+                        warnStatusDto.getUnit(),
+                        warnStatusDto.getOpt(),
+                        warnStatusDto.getIndicatorValue()
+                );
+                messageBuilder.append(message).append("\n");
+            }
+        }
+        if(messageBuilder.length() > 0) {
+            designatePestMessage = messageBuilder.toString();
+            log.info("针对指定病虫害生成警告消息: {}. 设备ID: {}, 配置ID: {}", designatePestMessage, devBid, iotWarnconfig.getWcBid());
+            isWarn = true;
+        }
+
+        StringBuffer buffer = new StringBuffer();
+        if(isWarn){
+            buffer.append(devType).append("设备(").append(devCode).append("), 触发告警,告警原因: \n");
+        }
+        if (pestByTypeMessage != null) {
+            buffer.append(pestByTypeMessage);
+            buffer.append("\n");
+        }
+        if (pestByCountMessage != null) {
+            buffer.append(pestByCountMessage);
+            buffer.append("\n");
+        }
+        if (designatePestMessage != null) {
+            buffer.append(designatePestMessage);
+        }
+
+
+        // 构建发送消息的参数
+        WarnResult warnResult = new WarnResult();
+        warnResult.setMessageId(warnResult.getUUId()); // 确保WarnResult中有getUUId方法
+        warnResult.setDevId(devBid);
+        warnResult.setTid(iotWarnconfig.getTid());
+        warnResult.setConfigId(iotWarnconfig.getWcBid());
+        warnResult.setReportData("-");
+        warnResult.setTargetReCount(iotWarnconfig.getWcRepeatnum() == null ? 0 : iotWarnconfig.getWcRepeatnum());
+        warnResult.setDevtypeBid(iotWarnconfig.getDevtypeBid());
+        warnResult.setConfig(iotWarnconfig);
+        warnResult.setTriggered(isWarn);
+        warnResult.setMessage(buffer.toString());
+
+        log.info("准备发送告警信息: {}. 设备ID: {}, 配置ID: {}", warnResult.getMessage(), devBid, iotWarnconfig.getWcBid());
+        // 发送告警
+        reCountService.handlerMessage(warnResult);
+        log.info("告警信息已发送完成. 设备ID: {}, 配置ID: {}", devBid, iotWarnconfig.getWcBid());
+    }
+
+
+    public void validateParam(IotWarnindicator warnStatusDto) {
+        if (StringUtils.isEmpty(warnStatusDto.getDevCode())) {
+            log.error("【设备预警】病虫害:设备code 不可为空");
+            throw new BizException(ErrorCode.FAILURE.getCode(), "设备code不可为空");
+        }
+        String devtypeBid = warnStatusDto.getDevtypeBid();
+        if (StringUtils.isEmpty(devtypeBid)) {
+            log.error("【设备预警】病虫害:设备类型 不可为空");
+            throw new BizException(ErrorCode.FAILURE.getCode(), "病虫害:设备类型 不可为空");
+        }
+    }
+}

+ 226 - 91
src/main/java/com/yunfeiyun/agmp/iots/warn/service/WarnService.java

@@ -3,6 +3,7 @@ package com.yunfeiyun.agmp.iots.warn.service;
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import com.yunfeiyun.agmp.common.utils.StringUtils;
+import com.yunfeiyun.agmp.iot.common.constant.IotEnumOnlineStatus;
 import com.yunfeiyun.agmp.iot.common.constant.device.ElementFormatUtil;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.IotDeviceDictEnum;
 import com.yunfeiyun.agmp.iot.common.constant.devicetype.IotDeviceTypeLv1Enum;
@@ -10,9 +11,10 @@ import com.yunfeiyun.agmp.iot.common.domain.IotDevice;
 import com.yunfeiyun.agmp.iot.common.domain.IotDevicefactor;
 import com.yunfeiyun.agmp.iot.common.domain.IotWarnconfig;
 import com.yunfeiyun.agmp.iot.common.enums.EnumWarnRuleOp;
+import com.yunfeiyun.agmp.iot.common.enums.IotDeviceStatusTypeEnum;
 import com.yunfeiyun.agmp.iots.service.IIotDevicefactorService;
 import com.yunfeiyun.agmp.iots.warn.model.WarnConfigInfo;
-import com.yunfeiyun.agmp.iots.warn.model.WarnQxSqInfoDto;
+import com.yunfeiyun.agmp.iots.warn.model.WarnInfoDto;
 import com.yunfeiyun.agmp.iots.warn.model.WarnResult;
 import com.yunfeiyun.agmp.iots.warn.model.WarnStatusDto;
 import com.yunfeiyun.agmp.iots.warn.util.CompareUtil;
@@ -46,42 +48,101 @@ public class WarnService {
 
     @Autowired
     private IIotDevicefactorService iotDevicefactorService;
+    @Autowired
+    private WarnPestService warnPestService;
 
-    private Map<String, IotDevicefactor> getDevicefactorMap(String devBid){
-        IotDevicefactor param = new IotDevicefactor();
-        param.setDevBid(devBid);
-        List<IotDevicefactor> factorList = iotDevicefactorService.selectIotDevicefactorList(param);
-        Map<String, IotDevicefactor> factorMap = new HashMap<>();
-        for(IotDevicefactor factor : factorList){
-            String dfCode = factor.getDfCode();
-            String dfAddress = factor.getDfAddress();
-            String key = dfAddress + dfCode;
-            factorMap.put(key, factor);
-        }
-        return factorMap;
+
+    /**
+     * 【主】统一处理上报离线数据
+     *
+     * @param data 上报的数据对象
+     *             param ext   上报的原始数据
+     */
+    public void processWarningOfflineData(IotDevice iotDevice, JSONObject data) {
+        //转异步处理
+        processWarningOfflineDataSyn(iotDevice, data);
     }
 
     /**
-     * 统一处理上报数据
+     * 【主】处理离线数据:针对定时检查的离线
      *
-     * @param data  上报的数据对象
-     * param ext   上报的原始数据
+     * @param iotDevice
+     */
+    public void processWarningOfflineData(IotDevice iotDevice) {
+        processWarningOfflineDataSyn(iotDevice, JSONObject.from(iotDevice));
+    }
+
+    /**
+     * 【主】统一处理上报数据
+     *
+     * @param data 上报的数据对象
+     *             param ext   上报的原始数据
      */
     public void processWarningReportData(IotDevice iotDevice, JSONObject data) {
         //转异步处理
         processWarningReportDataSyn(iotDevice, data);
     }
 
+    private void processWarningOfflineDataSyn(IotDevice iotDevice, JSONObject data) {
+        try {
+            // 记录开始处理离线数据的日志
+            log.info("[设备告警] 开始处理设备{}的离线数据{}", iotDevice.getDevBid(), data);
+            // 不是离线的不处理
+            if (!IotDeviceStatusTypeEnum.OFFLINE.getCode().equals(iotDevice.getDevStatus())) {
+                log.info("[设备告警] 设备{}当前不是离线状态,跳过处理", iotDevice.getDevBid());
+                return;
+            }
+
+            CompletableFuture.runAsync(() -> {
+                try {
+                    // 获取该设备有哪些告警配置
+                    IotWarnconfig warnConfigInfo = iotWarnBussinessService.selectIotWarnOfflineConfigInfo(iotDevice.getTid());
+
+                    // 存在离线配置,且开启
+                    if (warnConfigInfo != null && "0".equals(warnConfigInfo.getWcStatus())) {
+                        // 离线
+                        if (IotEnumOnlineStatus.OFFLINE.getStatus().equals(iotDevice.getDevStatus())) {
+                            WarnResult warnResult = new WarnResult();
+                            warnResult.setMessageId(warnResult.getUUId());
+                            warnResult.setDevId(iotDevice.getDevBid());
+                            warnResult.setTid(iotDevice.getTid());
+                            warnResult.setConfigId(warnConfigInfo.getWcBid());
+                            warnResult.setReportData(data.toJSONString());
+                            warnResult.setTargetReCount(warnConfigInfo.getWcRepeatnum() == null ? 0 : warnConfigInfo.getWcRepeatnum());
+                            warnResult.setDevtypeBid(iotDevice.getDevtypeBid());
+                            warnResult.setConfig(warnConfigInfo);
+                            warnResult.setOffline(true);
+                            warnResult.setTriggered(true);
+                            warnResult.setMessage(WarnMessageBuilderUtil.buildWarningOfflineMessage(iotDevice.getDevtypeBid(), iotDevice.getDevCode(), StringUtils.isEmpty(iotDevice.getDevUpdateddate()) ? iotDevice.getDevCreateddate() : iotDevice.getDevUpdateddate()));
+                            // 处理警告记录前的日志
+                            log.info("[设备告警] 正在为设备{}处理警告记录:{}", iotDevice.getDevBid(), warnResult);
+                            handleWarnRecord(warnResult);
+                        }
+                    } else {
+                        // 日志记录没有离线告警配置或者已经关闭的情况
+                        log.error("[设备告警] devId:{} , tid{},没有离线告警配置或者已经关闭:{}", iotDevice.getDevBid(), iotDevice.getTid(), warnConfigInfo);
+                    }
+                } catch (Exception e) {
+                    log.error("{}", e);
+                }
+
+            }, threadPoolTaskExecutor);
+        } catch (Exception e) {
+            // 异常捕获时的日志记录
+            log.error("[设备告警] 在处理设备{}时发生异常:{}", iotDevice.getDevBid(), e.getMessage(), e);
+        }
+    }
+
 
     /**
      * 统一处理上报数据:异步处理
      *
-     * @param data  上报的数据对象
+     * @param data 上报的数据对象
      */
     private void processWarningReportDataSyn(IotDevice iotDevice, JSONObject data) {
         String devBid = iotDevice.getDevBid();
         String devtypeBid = iotDevice.getDevtypeBid();
-        String devClass =  IotDeviceDictEnum.getLv1CodeByCode(devtypeBid);
+        String devClass = IotDeviceDictEnum.getLv1CodeByCode(devtypeBid);
         IotDeviceTypeLv1Enum iotDeviceTypeLv1Enum = IotDeviceTypeLv1Enum.findEnumByCode(devClass);
         if (iotDeviceTypeLv1Enum == null) {
             log.error("[设备告警] 设备大类不存在,devBid:{}, devtypeBid:{}", devBid, devtypeBid);
@@ -103,31 +164,31 @@ public class WarnService {
             Map<String, IotDevicefactor> factorMap = getDevicefactorMap(devBid);
 
             //配置一个个检查
-            for(Map.Entry<String, List<WarnConfigInfo>> entry : configMap.entrySet()) {
+            for (Map.Entry<String, List<WarnConfigInfo>> entry : configMap.entrySet()) {
                 List<WarnConfigInfo> configList = entry.getValue();
                 WarnResult warnResult = null;
 
-                WarnQxSqInfoDto warnQxSqInfoDto = new WarnQxSqInfoDto();
-                warnQxSqInfoDto.setIotDevice(iotDevice);
-                warnQxSqInfoDto.setConfigList(configList);
-                warnQxSqInfoDto.setJsonObject(data);
-                warnQxSqInfoDto.setFactorMap(factorMap);
-                warnQxSqInfoDto.setIotDeviceTypeLv1Enum(iotDeviceTypeLv1Enum);
+                WarnInfoDto warnInfoDto = new WarnInfoDto();
+                warnInfoDto.setIotDevice(iotDevice);
+                warnInfoDto.setConfigList(configList);
+                warnInfoDto.setJsonObject(data);
+                warnInfoDto.setFactorMap(factorMap);
+                warnInfoDto.setIotDeviceTypeLv1Enum(iotDeviceTypeLv1Enum);
 
-                try{
+                try {
                     switch (iotDeviceTypeLv1Enum) {
                         case QXZ: {
-                            warnResult = comparableQxzReportData(warnQxSqInfoDto);
+                            warnResult = comparableQxzReportData(warnInfoDto);
+                            break;
+                        }
+                        case SQZ: {
+                            warnResult = comparableSqzReportData(warnInfoDto);
+                            break;
+                        }
+                        case GSSQ: {
+                            warnResult = comparableGssqReportData(warnInfoDto);
                             break;
                         }
-//                        case SQZ: {
-//                            warnResult = comparableSqzReportData(warnQxSqInfoDto);
-//                            break;
-//                        }
-//                        case GSSQ: {
-//                            warnResult = comparableGssqReportData(warnQxSqInfoDto);
-//                            break;
-//                        }
 //                    case "病虫害": {
 //                        warnResult = comparableBchReportData(devBid, config, data);
 //                        break;
@@ -135,7 +196,7 @@ public class WarnService {
                         default:
                             break;
                     }
-                }catch (Exception e){
+                } catch (Exception e) {
                     log.error("[设备告警] 设备上报数据 异常,devBid:{}, config:{}, data:{}", devBid, configList, data, e);
                 }
 
@@ -157,6 +218,40 @@ public class WarnService {
     }
 
     /**
+     * 检查租户是否有默认的离线告警信息
+     */
+    public void checkTenantOfflineConfig() {
+        List<String> tids = iotWarnBussinessService.selectAllTid();
+        for (String tid : tids) {
+            log.info("【告警】检查租户 tid:{}离线配置 {}", tid);
+            try {
+                IotWarnconfig iotWarnconfig = iotWarnBussinessService.selectIotWarnOfflineConfigInfo(tid);
+                if (iotWarnconfig == null) {
+                    log.info("【告警】检查租户 tid:{}离线配置不存在,自动添加", tid);
+                    iotWarnBussinessService.insertIotOfflineWarnConfig(tid);
+                    log.info("【告警】检查租户 tid:{}离线配置不存在,自动添加完毕", tid);
+                }
+            } catch (Exception e) {
+                log.error("【告警】检查租户 tid:{}离线配置 {}", tid, e);
+            }
+        }
+    }
+
+    private Map<String, IotDevicefactor> getDevicefactorMap(String devBid) {
+        IotDevicefactor param = new IotDevicefactor();
+        param.setDevBid(devBid);
+        List<IotDevicefactor> factorList = iotDevicefactorService.selectIotDevicefactorList(param);
+        Map<String, IotDevicefactor> factorMap = new HashMap<>();
+        for (IotDevicefactor factor : factorList) {
+            String dfCode = factor.getDfCode();
+            String dfAddress = factor.getDfAddress();
+            String key = dfAddress + dfCode;
+            factorMap.put(key, factor);
+        }
+        return factorMap;
+    }
+
+    /**
      * 根据设备id获取策略,可能有多个
      *
      * @param devBid
@@ -171,7 +266,7 @@ public class WarnService {
         String devCode = iotDevice.getDevCode();
         BigDecimal errorValue = new BigDecimal("-99");
         Map<String, String> currentValueMap = new HashMap<>();
-        for(Object obj : jsonArray) {
+        for (Object obj : jsonArray) {
             JSONObject ob;
             try {
                 ob = JSONObject.from(obj);
@@ -201,16 +296,16 @@ public class WarnService {
         return currentValueMap;
     }
 
-    private String getDisplayName(String key, Map<String, IotDevicefactor> factorMap){
+    private String getDisplayName(String key, Map<String, IotDevicefactor> factorMap) {
         String wiName = "";
-        if(factorMap.containsKey(key)){
+        if (factorMap.containsKey(key)) {
             IotDevicefactor iotDevicefactor = factorMap.get(key);
             // 如果禁用,直接返回null,不进行预警判断
-            if(Objects.equals(iotDevicefactor.getDfDisable(), "1")){
+            if (Objects.equals(iotDevicefactor.getDfDisable(), "1")) {
                 return null;
             }
             String displayname = iotDevicefactor.getDfDisplayname();
-            if(StringUtils.isNotEmpty(displayname)){
+            if (StringUtils.isNotEmpty(displayname)) {
                 wiName = displayname;
             }
         }
@@ -218,12 +313,12 @@ public class WarnService {
         return wiName;
     }
 
-    private WarnStatusDto getQxzWarnStatusDto(WarnConfigInfo config, WarnQxSqInfoDto warnQxSqInfoDto) {
-        IotDevice iotDevice = warnQxSqInfoDto.getIotDevice();
+    private WarnStatusDto getQxzWarnStatusDto(WarnConfigInfo config, WarnInfoDto warnInfoDto) {
+        IotDevice iotDevice = warnInfoDto.getIotDevice();
         String devCode = iotDevice.getDevCode();
-        Map<String, String> currentValueMap = warnQxSqInfoDto.getCurrentValueMap();
-        Map<String, IotDevicefactor> factorMap = warnQxSqInfoDto.getFactorMap();
-        IotDeviceTypeLv1Enum iotDeviceTypeLv1Enum = warnQxSqInfoDto.getIotDeviceTypeLv1Enum();
+        Map<String, String> currentValueMap = warnInfoDto.getCurrentValueMap();
+        Map<String, IotDevicefactor> factorMap = warnInfoDto.getFactorMap();
+        IotDeviceTypeLv1Enum iotDeviceTypeLv1Enum = warnInfoDto.getIotDeviceTypeLv1Enum();
 
         String targetValue = config.getWiValue();
         String wiAddress = config.getWiAddress();
@@ -235,7 +330,7 @@ public class WarnService {
 
         // 如果配置禁用,或者要素禁用,直接返回null,不进行预警判断
         boolean status = "0".equals(wcStatus) && "0".equals(wiStatus);
-        if(!status){
+        if (!status) {
             return null;
         }
 
@@ -245,25 +340,25 @@ public class WarnService {
         }
 
         // 如果没有配置预警条件和值,直接返回null,不进行预警判断
-        if(StringUtils.isEmpty(expression) || StringUtils.isEmpty(targetValue)){
+        if (StringUtils.isEmpty(expression) || StringUtils.isEmpty(targetValue)) {
             return null;
         }
 
         String wiName = config.getWiName();
         // 如果禁用,直接返回null,不进行预警判断
         String displayname = getDisplayName(key, factorMap);
-        if(displayname == null){
+        if (displayname == null) {
             return null;
         }
 
-        if(StringUtils.isNotEmpty(displayname)){
+        if (StringUtils.isNotEmpty(displayname)) {
             wiName = displayname;
         }
         String wiUnit = config.getWiUnit();
         String currentValue = currentValueMap.get(key);
 
         EnumWarnRuleOp warnRuleOp = EnumWarnRuleOp.findEnumByCode(expression);
-        if(warnRuleOp == null){
+        if (warnRuleOp == null) {
             log.error("[设备告警] 表达式不正确,devCode:{}, wiAddress:{}, config:{}", devCode, wiAddress, config);
             return null;
         }
@@ -285,28 +380,26 @@ public class WarnService {
 
     /**
      * 【气象站】比较该设备上报的任一要素否达到预警条件
+     *
      * @param warnResult
-     * @param configList
-     * @param factorMap
-     * @param currentValueMap
-     * @param devCode
+     * @param warnInfoDto
      * @return
      */
-    public WarnResult comparableQxzSingleIndicator(WarnResult warnResult, WarnQxSqInfoDto warnQxSqInfoDto) {
-        List<WarnConfigInfo> configList = warnQxSqInfoDto.getConfigList();
+    public WarnResult comparableQxzSingleIndicator(WarnResult warnResult, WarnInfoDto warnInfoDto) {
+        List<WarnConfigInfo> configList = warnInfoDto.getConfigList();
         WarnStatusDto warnStatusDto = null;
         for (WarnConfigInfo config : configList) {
-            warnStatusDto = getQxzWarnStatusDto(config, warnQxSqInfoDto);
+            warnStatusDto = getQxzWarnStatusDto(config, warnInfoDto);
             // 如果没有预警配置,直接返回null,不进行预警判断
-            if(warnStatusDto == null){
+            if (warnStatusDto == null) {
                 continue;
             }
-            if(warnStatusDto.isWarn()){
+            if (warnStatusDto.isWarn()) {
                 break;
             }
         }
-        if(warnStatusDto != null && warnStatusDto.isWarn()){
-            String message = WarnMessageBuilderUtil.buildQxzWarningMessage(
+        if (warnStatusDto != null && warnStatusDto.isWarn()) {
+            String message = WarnMessageBuilderUtil.buildWarningMessage(
                     warnStatusDto.getDevType(),
                     warnStatusDto.getDevCode(),
                     warnStatusDto.getName(),
@@ -325,40 +418,39 @@ public class WarnService {
     /**
      * 处理多个指标是否同时满足预警条件。
      *
-     * @param devId      设备ID
-     * @param config     告警规则
-     * @param jsonObject 上报的数据
+     * @param warnResult
+     * @param warnInfoDto
      * @return WarnResult 包含是否触发告警的信息
      */
-    public WarnResult comparableQxzMultipleIndicators(WarnResult warnResult, WarnQxSqInfoDto warnQxSqInfoDto) {
-        List<WarnConfigInfo> configList = warnQxSqInfoDto.getConfigList();
+    public WarnResult comparableQxzMultipleIndicators(WarnResult warnResult, WarnInfoDto warnInfoDto) {
+        List<WarnConfigInfo> configList = warnInfoDto.getConfigList();
         WarnStatusDto warnStatusDto = null;
         List<WarnStatusDto> warnStatusDtos = new ArrayList<>();
         for (WarnConfigInfo config : configList) {
-            warnStatusDto = getQxzWarnStatusDto(config, warnQxSqInfoDto);
+            warnStatusDto = getQxzWarnStatusDto(config, warnInfoDto);
             // 如果没有预警配置,直接返回null,不进行预警判断
-            if(warnStatusDto == null){
+            if (warnStatusDto == null) {
                 continue;
             }
-            if(!warnStatusDto.isWarn()){
+            if (!warnStatusDto.isWarn()) {
                 return warnResult;
             }
             warnStatusDtos.add(warnStatusDto);
         }
-        if(warnStatusDtos.isEmpty()){
+        if (warnStatusDtos.isEmpty()) {
             return warnResult;
         }
 
         StringBuilder messageBuilder = new StringBuilder();
-        for(int i = 0; i < warnStatusDtos.size(); i++){
+        for (int i = 0; i < warnStatusDtos.size(); i++) {
             warnStatusDto = warnStatusDtos.get(i);
             String devType = null;
             String dCode = null;
-            if(i == 0){
+            if (i == 0) {
                 devType = warnStatusDto.getDevType();
                 dCode = warnStatusDto.getDevCode();
             }
-            String message = WarnMessageBuilderUtil.buildQxzWarningMessage(
+            String message = WarnMessageBuilderUtil.buildWarningMessage(
                     devType,
                     dCode,
                     warnStatusDto.getName(),
@@ -378,18 +470,17 @@ public class WarnService {
     /**
      * 【气象站】比较该设备上报的要素和配置是否达到预警条件
      *
-     * @param devBid      设备id
-     * @param config     对应的配置
-     * @param jsonObject 上报的数据
+     * @param warnInfoDto
+     * @return
      */
-    private WarnResult comparableQxzReportData(WarnQxSqInfoDto warnQxSqInfoDto) {
-        IotDevice iotDevice = warnQxSqInfoDto.getIotDevice();
-        List<WarnConfigInfo> configList = warnQxSqInfoDto.getConfigList();
-        JSONObject jsonObject = warnQxSqInfoDto.getJsonObject();
+    private WarnResult comparableQxzReportData(WarnInfoDto warnInfoDto) {
+        IotDevice iotDevice = warnInfoDto.getIotDevice();
+        List<WarnConfigInfo> configList = warnInfoDto.getConfigList();
+        JSONObject jsonObject = warnInfoDto.getJsonObject();
         JSONArray jsonArray = jsonObject.getJSONArray("data");
         Map<String, String> currentValueMap = getQxzCurrentValueMap(iotDevice, jsonArray);
 
-        warnQxSqInfoDto.setCurrentValueMap(currentValueMap);
+        warnInfoDto.setCurrentValueMap(currentValueMap);
 
         String devBid = iotDevice.getDevBid();
         WarnConfigInfo configInfo = configList.get(0);
@@ -409,10 +500,10 @@ public class WarnService {
         warnResult.setConfig(iotWarnconfig);
         warnResult.setTriggered(false);
 
-        if("0".equals(wcCondition)){
-            warnResult = comparableQxzSingleIndicator(warnResult, warnQxSqInfoDto);
+        if ("0".equals(wcCondition)) {
+            warnResult = comparableQxzSingleIndicator(warnResult, warnInfoDto);
         } else {
-            warnResult = comparableQxzMultipleIndicators(warnResult, warnQxSqInfoDto);
+            warnResult = comparableQxzMultipleIndicators(warnResult, warnInfoDto);
         }
         return warnResult;
     }
@@ -420,19 +511,17 @@ public class WarnService {
 
     /**
      * 【墒情站】比较该设备上报的要素和配置是否达到预警条件
-     *
      */
-    WarnResult comparableSqzReportData(WarnQxSqInfoDto warnQxSqInfoDto) {
-        return comparableQxzReportData(warnQxSqInfoDto);
+    WarnResult comparableSqzReportData(WarnInfoDto warnInfoDto) {
+        return comparableQxzReportData(warnInfoDto);
 
     }
 
     /**
      * 【管式墒情】比较该设备上报的要素和配置是否达到预警条件
-     *
      */
-    WarnResult comparableGssqReportData(WarnQxSqInfoDto warnQxSqInfoDto) {
-        return comparableQxzReportData(warnQxSqInfoDto);
+    WarnResult comparableGssqReportData(WarnInfoDto warnInfoDto) {
+        return comparableQxzReportData(warnInfoDto);
 
     }
 
@@ -448,4 +537,50 @@ public class WarnService {
 
     }
 
+    /**
+     * 拦截处理设备变更:如果离线转离线进行预警处理
+     *
+     * @param iotDeviceList
+     */
+    public void processWarningOfflineToOnlineDeviceData(List<IotDevice> iotDeviceList) {
+
+        CompletableFuture.runAsync(() -> {
+            try {
+                for (IotDevice iotDevice : iotDeviceList) {
+
+                    //离线转在线
+                    if (IotDeviceStatusTypeEnum.OFFLINE.getCode().equals(iotDevice.getDevOriginalStatus())
+                            && IotDeviceStatusTypeEnum.ONLINE.getCode().equals(iotDevice.getDevStatus()
+                    )) {
+                        log.info("[离线告警]自动处理离线告警消息:设备号: {} ,bid:{}", iotDevice.getDevCode(), iotDevice.getDevBid());
+                        autoDealWarnOfflineLog(iotDevice.getDevBid());
+                    } else {
+                        log.info("[离线告警]自动处理离线告警消息:设备号: {} ,bid:{} ,原始状态:", iotDevice.getDevCode(), iotDevice.getDevBid(), iotDevice.getDevOriginalStatus());
+                    }
+                }
+            } catch (Exception e) {
+                log.error("[离线告警]自动处理离线告警消息:失败 {}", e);
+            }
+        }, threadPoolTaskExecutor);
+
+    }
+
+    private void autoDealWarnOfflineLog(String devId) {
+        iotWarnBussinessService.autoDealWarnOfflineLog(devId);
+    }
+
+    /**
+     * 虫害
+     */
+    public void processWarningPestData() {
+        warnPestService.process();
+    }
+
+
+    /**
+     * 病害
+     */
+    public void processWarningDiseaseData() {
+
+    }
 }

+ 45 - 5
src/main/java/com/yunfeiyun/agmp/iots/warn/util/WarnMessageBuilderUtil.java

@@ -1,5 +1,8 @@
 package com.yunfeiyun.agmp.iots.warn.util;
 
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
 public class WarnMessageBuilderUtil {
     /**
      * 构建告警信息。
@@ -13,10 +16,10 @@ public class WarnMessageBuilderUtil {
      * @param indicatorValue 设定的目标对比值,例如“10-35℃”。
      * @return 格式化后的告警信息。
      */
-    public static String buildQxzWarningMessage(String devType, String devCode, String name, String value, String unit, String opt, String indicatorValue) {
+    public static String buildWarningMessage(String devType, String devCode, String name, String value, String unit, String opt, String indicatorValue) {
         // 格式化字符串,将设备类型、设备唯一编码、告警参数名、当前值、单位、动作和目标对比值插入到模板中
         String tag = "";
-        if(devType != null && devCode != null){
+        if (devType != null && devCode != null) {
             tag = String.format("%s设备(%s), 触发告警,告警原因: \n", devType, devCode);
         }
         return String.format("%s %s 上报值 %s%s,%s设置的阀值%s。",
@@ -28,8 +31,45 @@ public class WarnMessageBuilderUtil {
                 indicatorValue);
     }
 
-    public static void main(String[] args) {
-        String message = buildQxzWarningMessage("气象站", "87872877485", "温度", "42", "℃", "超过", "10-35℃");
-        System.out.println(message);
+    /**
+     * 构建离线消息
+     *
+     * @param devType
+     * @param devCode
+     * @param name
+     * @return
+     */
+    public static String buildWarningOfflineMessage(String devType, String devCode, String lastUpdateTime) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        try {
+            Date lastUpdate = sdf.parse(lastUpdateTime);
+            long diffInMillis = System.currentTimeMillis() - lastUpdate.getTime();
+
+            long diffMinutes = diffInMillis / (60 * 1000) % 60;
+            long diffHours = diffInMillis / (60 * 60 * 1000) % 24;
+            long diffDays = diffInMillis / (24 * 60 * 60 * 1000);
+
+            String durationStr;
+            if (diffDays > 0) {
+                durationStr = String.format("已离线%d天%d小时%d分", diffDays, diffHours, diffMinutes);
+            } else if (diffHours > 0) {
+                durationStr = String.format("已离线%d小时%d分", diffHours, diffMinutes);
+            } else {
+                durationStr = String.format("已离线%d分钟", diffMinutes);
+            }
+
+            String content = String.format("%s设备(%s)%s;", devType, devCode, durationStr);
+            return content;
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "无法解析离线时间";
+        }
     }
+
+//    public static void main(String[] args) {
+//        String message = buildQxzWarningMessage("气象站", "87872877485", "温度", "42", "℃", "超过", "10-35℃");
+//        System.out.println(message);
+//        System.out.println(buildWarningOfflineMessage("温度计", "T123", "温度监控器A", "2025-03-19 12:35:00"));
+//    }
 }

+ 4 - 0
src/main/resources/application-dev.yml

@@ -277,3 +277,7 @@ map:
   gaode:
     api: http://restapi.amap.com
     key: 78ce288400f4fc6d9458989875c833c2
+
+#只允许在228机器上访问,其他环境不要配置
+warn:
+  cbdDateDiff: 0

+ 4 - 3
src/main/resources/application-test.yml

@@ -76,11 +76,11 @@ spring:
         username:
         password:
       # 初始连接数
-      initialSize: 5
+      initialSize: 100
       # 最小连接池数量
-      minIdle: 10
+      minIdle: 100
       # 最大连接池数量
-      maxActive: 20
+      maxActive: 200
       # 配置获取连接等待超时的时间
       maxWait: 60000
       # 配置连接超时时间
@@ -270,3 +270,4 @@ map:
   gaode:
     api: http://restapi.amap.com
     key: 78ce288400f4fc6d9458989875c833c2
+

+ 131 - 13
src/main/resources/mapper/IotWarnBusinessMapper.xml

@@ -70,33 +70,151 @@
     <update id="updateIncrementReCount">
              update IotWarncount set wctCount=wctCount+1 where devBid=#{devBid} and wcBid=#{wcBid};
     </update>
-    <update id="resetReCountByDevIdAndConfigId">
+    <update id="resetReCountByDevBidAndConfigId">
               update IotWarncount set wctCount=0 where devBid=#{devBid} and wcBid=#{wcBid};
     </update>
 
+
     <select id="selectIotWarnCountByDevAndConfig"
             resultType="com.yunfeiyun.agmp.iot.common.domain.IotWarncount">
         select  * from IotWarncount where devBid=#{devBid} and wcBid=#{wcBid};
     </select>
 
-    <select id="selectIotWarnConfigInfoList" parameterType="com.yunfeiyun.agmp.iots.warn.model.WarnConfigInfo" resultType="com.yunfeiyun.agmp.iots.warn.model.WarnConfigInfo">
+    <select id="selectIotWarnConfigInfoList" parameterType="com.yunfeiyun.agmp.iots.warn.model.WarnConfigInfo"
+            resultType="com.yunfeiyun.agmp.iots.warn.model.WarnConfigInfo">
         SELECT wc.*, wi.wiBid, wi.wiAddress,
-            wi.wiCode, wi.wiName, wi.wiUnit, wi.wiExpression, wi.wiValue, wi.wiStatus
+        wi.wiCode, wi.wiName, wi.wiUnit, wi.wiExpression, wi.wiValue, wi.wiStatus
         FROM IotWarnconfig AS wc
-            LEFT JOIN IotWarnindicator AS wi ON wi.wcBid = wc.wcBid
-            <if test="devBid != null">
-                LEFT JOIN IotWarnobject AS wo ON wo.wcBid = wc.wcBid
-            </if>
+        LEFT JOIN IotWarnindicator AS wi ON wi.wcBid = wc.wcBid
+        <if test="devBid != null">
+            LEFT JOIN IotWarnobject AS wo ON wo.wcBid = wc.wcBid
+        </if>
 
         WHERE wc.tid = #{tid} AND wi.wiBid IS NOT NULL
-            <if test="devBid != null">
-                AND wo.devBid = #{devBid} AND wo.woBid IS NOT NULL
-            </if>
-            <if test="devtypeBid!= null">
-                AND wc.devtypeBid = #{devtypeBid}
-            </if>
+        <if test="devBid != null">
+            AND wo.devBid = #{devBid} AND wo.woBid IS NOT NULL
+        </if>
+        <if test="devtypeBid!= null">
+            AND wc.devtypeBid = #{devtypeBid}
+        </if>
     </select>
     <select id="getAllReCount" resultType="com.yunfeiyun.agmp.iot.common.domain.IotWarncount">
         select  * from IotWarncount
     </select>
+    <select id="selectIotWarnOfflineConfigInfo" resultType="com.yunfeiyun.agmp.iot.common.domain.IotWarnconfig">
+        select * from IotWarnconfig where tid = #{tid} and wcTouchtype='1';
+    </select>
+    <select id="selectAllTid" resultType="java.lang.String">
+        select tid from SysUser group by tid
+    </select>
+
+    <!-- 根据code查询虫害规则指标-->
+    <select id="selectIotWarnPestConfigInfoList"
+            resultType="com.yunfeiyun.agmp.iot.common.domain.IotWarnindicator">
+
+          SELECT tb_wi.*,tb_it.devBid,tb_it.devCode,tb_it.devtypeBid from (
+                SELECT tb_2.*,iwo.devBid from (
+                    select * from IotWarnindicator  where wiCode=#{code}
+                ) tb_2
+                LEFT JOIN IotWarnconfig iwc ON tb_2.wcBid=iwc.wcBid
+                LEFT JOIN IotWarnobject iwo on tb_2.wcBid=iwo.wcBid
+        ) tb_wi  LEFT JOIN IotWarnconfig tb_config on tb_wi.wcBid=tb_config.wcBid
+        LEFT JOIN IotDevice tb_it on tb_it.devBid = tb_wi.devBid
+        where tb_config.wcStatus='0'
+    </select>
+    <insert id="insertIotOfflineWarnconfig" parameterType="IotWarnconfig" useGeneratedKeys="true" keyProperty="id">
+        insert into IotWarnconfig
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="wcBid != null">wcBid,</if>
+            <if test="wcName != null">wcName,</if>
+            <if test="wcDesc != null">wcDesc,</if>
+            <if test="wcStatus != null">wcStatus,</if>
+            <if test="wcLevel != null">wcLevel,</if>
+            <if test="wcTouchtype != null">wcTouchtype,</if>
+            <if test="wcCondition != null">wcCondition,</if>
+            <if test="devtypeBid != null">devtypeBid,</if>
+            <if test="wcRepeatnum != null">wcRepeatnum,</if>
+            <if test="wcCreator != null">wcCreator,</if>
+            <if test="wcCreateddate != null">wcCreateddate,</if>
+            <if test="wcModifieddate != null">wcModifieddate,</if>
+            <if test="wcModifier != null">wcModifier,</if>
+            <if test="tid != null and tid != ''">tid,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="wcBid != null">#{wcBid},</if>
+            <if test="wcName != null">#{wcName},</if>
+            <if test="wcDesc != null">#{wcDesc},</if>
+            <if test="wcStatus != null">#{wcStatus},</if>
+            <if test="wcLevel != null">#{wcLevel},</if>
+            <if test="wcTouchtype != null">#{wcTouchtype},</if>
+            <if test="wcCondition != null">#{wcCondition},</if>
+            <if test="devtypeBid != null">#{devtypeBid},</if>
+            <if test="wcRepeatnum != null">#{wcRepeatnum},</if>
+            <if test="wcCreator != null">#{wcCreator},</if>
+            <if test="wcCreateddate != null">#{wcCreateddate},</if>
+            <if test="wcModifieddate != null">#{wcModifieddate},</if>
+            <if test="wcModifier != null">#{wcModifier},</if>
+            <if test="tid != null and tid != ''">#{tid},</if>
+        </trim>
+    </insert>
+    <update id="autoDealWarnOfflineLog">
+        update IotWarnlog
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="status != null">status = #{status},</if>
+            <if test="wlDealresult != null">wlDealresult = #{wlDealresult},</if>
+            <if test="wlDealtime != null">wlDealtime = #{wlDealtime},</if>
+        </trim>
+        where devBid = #{devBid} and wlType='1' and status='0'
+
+    </update>
+
+    <select id="selectIotWarnconfigCbdDevList" resultType="com.yunfeiyun.agmp.iots.warn.model.IotWarnconfigDevVo">
+        SELECT wi.wiBid, d.devBid, d.devCode, d.devtypeBid, d.devCbdrecogtype, wc.*
+        FROM IotWarnindicator AS wi
+            LEFT JOIN IotWarnconfig AS wc ON wc.wcBid = wi.wcBid
+            LEFT JOIN IotWarnobject AS wo ON wo.wcBid = wc.wcBid
+            LEFT JOIN IotDevice AS d ON d.devBid = wo.devBid
+        WHERE wi.wiCode = "pestDetail" AND wc.wcStatus = "0" AND d.devDelstatus = "0"
+    </select>
+
+
+    <select id="selectCbdIndicatorAllList"
+            resultType="com.yunfeiyun.agmp.iot.common.domain.IotWarnindicator">
+        SELECT wi.*
+        FROM IotWarnindicator AS wi
+        LEFT JOIN IotWarnconfig AS wc ON wc.wcBid = wi.wcBid
+        WHERE wi.wiCode IN ('pestType', 'pestNum', 'pestDetail') AND wc.wcStatus = "0"
+    </select>
+
+    <select id="selectIotWarnindicatorList" parameterType="IotWarnindicator" resultType="IotWarnindicator">
+        select id, wiBid, wcBid, wdBid, wiAddress, wiCode, wiName, wiUnit,wiStatus,wiExpression, wiValue, wiCreator,
+            wiCreateddate, wiModifieddate, wiModifier, tid, wiOptiontype, wiParentbid
+        from IotWarnindicator
+        <where>
+            <if test="wiBid != null  and wiBid != ''"> and wiBid = #{wiBid}</if>
+            <if test="wcBid != null  and wcBid != ''"> and wcBid = #{wcBid}</if>
+            <if test="wdBid != null  and wdBid != ''"> and wdBid = #{wdBid}</if>
+            <if test="wiAddress != null  and wiAddress != ''"> and wiAddress = #{wiAddress}</if>
+            <if test="wiCode != null  and wiCode != ''"> and wiCode = #{wiCode}</if>
+            <if test="wiName != null  and wiName != ''"> and wiName = #{wiName}</if>
+            <if test="wiUnit != null  and wiUnit != ''"> and wiUnit = #{wiUnit}</if>
+            <if test="wiStatus != null  and wiStatus != ''"> and wiStatus = #{wiStatus}</if>
+            <if test="wiExpression != null  and wiExpression != ''"> and wiExpression = #{wiExpression}</if>
+            <if test="wiValue != null  and wiValue != ''"> and wiValue = #{wiValue}</if>
+            <if test="wiCreator != null  and wiCreator != ''"> and wiCreator = #{wiCreator}</if>
+            <if test="wiCreateddate != null  and wiCreateddate != ''"> and wiCreateddate = #{wiCreateddate}</if>
+            <if test="wiModifieddate != null  and wiModifieddate != ''"> and wiModifieddate = #{wiModifieddate}</if>
+            <if test="wiModifier != null  and wiModifier != ''"> and wiModifier = #{wiModifier}</if>
+            <if test="tid != null  and tid != ''"> and tid = #{tid}</if>
+            <if test="wiOptiontype != null  and wiOptiontype != ''"> and wiOptiontype = #{wiOptiontype}</if>
+            <if test="wiParentbid != null  and wiParentbid != ''"> and wiParentbid = #{wiParentbid}</if>
+            <if test="wiParentbidList != null and wiParentbidList.size() > 0">
+                and wiParentbid in
+                <foreach collection="wiParentbidList" item="item" index="index" open="(" close=")" separator=",">
+                    #{item}
+                </foreach>
+            </if>
+        </where>
+    </select>
+
 </mapper>