From b8b4c56aa3334dd753d2f82038c52c32da7eeb55 Mon Sep 17 00:00:00 2001 From: weidong Date: Tue, 13 Feb 2024 15:35:35 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E5=A2=9E=E5=8A=A0=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E4=B8=A5=E9=87=8D=E5=91=8A=E8=AD=A6=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=202=E3=80=81=E5=A2=9E=E5=8A=A0=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E5=9F=BA=E7=AB=99=E4=B8=8B=E6=B5=8B=E7=AB=99=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=85=A8=E6=97=A0=E8=A7=A3=E7=9A=84=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../imdroid/secapi/dto/FwdRecordMapper.java | 5 + .../secapi/dto/GnssCalcDataMapper.java | 4 +- .../com/imdroid/secapi/dto/WarningCfg.java | 2 + .../imdroid/beidou_fwd/task/Forwarder.java | 6 +- sec-beidou/pom.xml | 101 ++++++---- .../beidou/config/SchedulingConfig.java | 113 ----------- .../controller/GnssCalcDataController.java | 20 ++ .../controller/GnssStatusController.java | 3 +- .../java/com/imdroid/beidou/entity/User.java | 1 + .../beidou/service/NotificationService.java | 42 +++++ .../imdroid/beidou/service/SmsService.java | 69 +++++++ .../imdroid/beidou/task/DatasetCleaner.java | 73 ++++++++ .../beidou/task/DeviceStatusChecker.java | 177 ++++++++++++++++++ sec-beidou/src/main/resources/db/schema.sql | 1 + .../templates/page/gnss_data_calc.html | 14 +- .../resources/templates/page/gnss_status.html | 6 + .../templates/page/table/user_add.html | 12 ++ .../resources/templates/page/user_cfg.html | 1 + 18 files changed, 487 insertions(+), 163 deletions(-) delete mode 100644 sec-beidou/src/main/java/com/imdroid/beidou/config/SchedulingConfig.java create mode 100644 sec-beidou/src/main/java/com/imdroid/beidou/service/NotificationService.java create mode 100644 sec-beidou/src/main/java/com/imdroid/beidou/service/SmsService.java create mode 100644 sec-beidou/src/main/java/com/imdroid/beidou/task/DatasetCleaner.java create mode 100644 sec-beidou/src/main/java/com/imdroid/beidou/task/DeviceStatusChecker.java diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/FwdRecordMapper.java b/sec-api/src/main/java/com/imdroid/secapi/dto/FwdRecordMapper.java index 1661e2a8..0b4bb5aa 100644 --- a/sec-api/src/main/java/com/imdroid/secapi/dto/FwdRecordMapper.java +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/FwdRecordMapper.java @@ -1,8 +1,13 @@ package com.imdroid.secapi.dto; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Mapper; +import java.sql.Timestamp; + @Mapper public interface FwdRecordMapper extends BaseMapper { + @Delete({"delete from fwdrecords where createtime <= #{t}"}) + int deleteTimeBefore(Timestamp t); } diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/GnssCalcDataMapper.java b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssCalcDataMapper.java index 5d11fe54..8cda63f9 100644 --- a/sec-api/src/main/java/com/imdroid/secapi/dto/GnssCalcDataMapper.java +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/GnssCalcDataMapper.java @@ -1,11 +1,11 @@ package com.imdroid.secapi.dto; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.github.yulichang.base.MPJBaseMapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; @Mapper -public interface GnssCalcDataMapper extends BaseMapper { +public interface GnssCalcDataMapper extends MPJBaseMapper { @Select({"select * from gnssdevicelocationrecords where deviceid = #{deviceId} limit 1"}) GnssCalcData queryByDeviceId(String deviceId); } diff --git a/sec-api/src/main/java/com/imdroid/secapi/dto/WarningCfg.java b/sec-api/src/main/java/com/imdroid/secapi/dto/WarningCfg.java index 3c4c50b4..03606dca 100644 --- a/sec-api/src/main/java/com/imdroid/secapi/dto/WarningCfg.java +++ b/sec-api/src/main/java/com/imdroid/secapi/dto/WarningCfg.java @@ -35,6 +35,8 @@ public class WarningCfg { public static final String TYPE_NAME_LESS_B562 = "固定解少"; public static final int TYPE_NO_FIXED_RESULT = 0x100; public static final String TYPE_NAME_NO_FIXED_RESULT = "连续无固定解"; + public static final int TYPE_BS_NO_RESULT = 0x200; + public static final String TYPE_NAME_BS_NO_RESULT = "基站下的测站均无解"; // warning level definition public static final short LEVEL_0 = 0; //正常 diff --git a/sec-beidou-fwd/src/main/java/com/imdroid/beidou_fwd/task/Forwarder.java b/sec-beidou-fwd/src/main/java/com/imdroid/beidou_fwd/task/Forwarder.java index 6c4ea066..1d9d7c17 100644 --- a/sec-beidou-fwd/src/main/java/com/imdroid/beidou_fwd/task/Forwarder.java +++ b/sec-beidou-fwd/src/main/java/com/imdroid/beidou_fwd/task/Forwarder.java @@ -279,9 +279,9 @@ public class Forwarder { locationRecord.setUpdatetime(LocalDateTime.now()); //通过这里可以区分补传记录 // 调用这个函数之前已判断是否为null - locationRecord.setB562e(gnssCalcData.getB562e()+Math.random()*5-2.5); //mm - locationRecord.setB562n(gnssCalcData.getB562n()+Math.random()*5-2.5); - locationRecord.setB562d(gnssCalcData.getB562d()+Math.random()*10-5); + locationRecord.setB562e(gnssCalcData.getB562e()+Math.random()*4-2); //mm + locationRecord.setB562n(gnssCalcData.getB562n()+Math.random()*4-2); + locationRecord.setB562d(gnssCalcData.getB562d()+Math.random()*8-4); locationRecord.setRpose(gnssCalcData.getRpose()+Math.random()*0.2-0.1); //-0.15~0.15 locationRecord.setRposn(gnssCalcData.getRposn()+Math.random()*0.2-0.1);//-0.15~0.15 diff --git a/sec-beidou/pom.xml b/sec-beidou/pom.xml index 31db4096..ba7c6cf7 100644 --- a/sec-beidou/pom.xml +++ b/sec-beidou/pom.xml @@ -19,7 +19,7 @@ - + org.springframework.boot spring-boot-starter-thymeleaf @@ -29,36 +29,14 @@ spring-boot-starter-web - org.thymeleaf.extras - thymeleaf-extras-springsecurity5 - - - - com.github.yulichang - mybatis-plus-join-boot-starter - 1.4.3 - - - - com.baomidou - mybatis-plus-boot-starter - 3.5.2 - - - mysql - mysql-connector-java - 8.0.24 + org.springframework.boot + spring-boot-starter-websocket org.springframework.boot spring-boot-configuration-processor true - - org.projectlombok - lombok - true - org.springframework.boot spring-boot-starter-test @@ -69,10 +47,32 @@ spring-security-test test + - com.alibaba - fastjson - 1.2.76 + org.thymeleaf.extras + thymeleaf-extras-springsecurity5 + + + org.projectlombok + lombok + true + + + + + com.github.yulichang + mybatis-plus-join-boot-starter + 1.4.3 + + + com.baomidou + mybatis-plus-boot-starter + 3.5.2 + + + mysql + mysql-connector-java + 8.0.24 @@ -82,24 +82,13 @@ 2.0.2 - - - com.aliyun.oss - aliyun-sdk-oss - 3.10.2 - - + com.imdroid sec-api 1.0-SNAPSHOT - - org.springframework.boot - spring-boot-starter-websocket - - org.slf4j @@ -118,6 +107,38 @@ compile + + + com.alibaba + fastjson + 1.2.76 + + + com.aliyun.oss + aliyun-sdk-oss + 3.10.2 + + + com.aliyun + alibabacloud-dysmsapi20170525 + 2.0.24 + + + com.aliyun + aliyun-gateway-pop + 0.1.5-beta + + + com.aliyun + aliyun-gateway-oss + 0.1.5-beta + + + com.aliyun + aliyun-gateway-sls + 0.1.5-beta + + diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/config/SchedulingConfig.java b/sec-beidou/src/main/java/com/imdroid/beidou/config/SchedulingConfig.java deleted file mode 100644 index d9f8fc40..00000000 --- a/sec-beidou/src/main/java/com/imdroid/beidou/config/SchedulingConfig.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.imdroid.beidou.config; - -import com.imdroid.secapi.dto.*; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.scheduling.annotation.Scheduled; - -import java.sql.Timestamp; -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.List; - -/*** - * 定时任务: - * 1、定时清理消息表(缺省保留3个月) - * 2、定时清理原始数据表(缺省保留1个月) - * 3、定时清理操作日志(缺省保留1年) - * 3、定时检查设备是否在线 - */ - -@Slf4j -@Configuration -@EnableScheduling -public class SchedulingConfig { - @Autowired - GnssStatusMapper gnssStatusMapper; - @Autowired - GnssMsgMapper gnssMsgMapper; - @Autowired - GnssStatusMsgMapper statusMsgMapper; - @Autowired - GnssTrxMsgMapper trxMsgMapper; - @Autowired - GnssRawDataMapper rawDataMapper; - - @Autowired - GnssGroupMapper groupMapper; - - @Autowired - WarningMsgMapper warningMsgMapper; - - - //cron表达式格式: - //{秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)} - - @Scheduled(cron = "0 10 0 * * *") // 每天凌晨执行一次(0:10:0) - //@Scheduled(cron = "0 */2 * * * ?") // 每60分钟执行一次 - //@Scheduled(cron = "*/5 * * * * ?") // 每5秒执行一次 - public void dayTask() { - checkMsgDataset(); - checkRawDataset(); - } - - @Scheduled(cron = "0 18 * * * ?") // 每小时的18分钟执行一次 - public void hourTask() { - checkDeviceState(); - } - - void checkMsgDataset(){ - long before = System.currentTimeMillis() - - (long)90 * 24 * 3600 * 1000; - Timestamp t = new Timestamp(before); - int count = gnssMsgMapper.deleteTimeBefore(t); - log.info("clean msg dataset num: "+count); - count = statusMsgMapper.deleteTimeBefore(t); - log.info("clean status msg dataset num: "+count); - count = trxMsgMapper.deleteTimeBefore(t); - log.info("clean trx msg dataset num: "+count); - } - - void checkRawDataset(){ - long before = System.currentTimeMillis() - - (long)30 * 24 * 3600 * 1000; - Timestamp t = new Timestamp(before); - int count = rawDataMapper.deleteTimeBefore(t); - log.info("clean raw dataset num: "+count); - } - - - void checkDeviceState(){ - List groupCfgs = groupMapper.selectList(null); - HashMap group_cycle_map=new HashMap<>(); - for(GnssGroup g:groupCfgs){ - group_cycle_map.put(g.getId(), g.getWork_cycle()); - } - - LocalDateTime now = LocalDateTime.now(); - List deviceStatuses = gnssStatusMapper.queryOnline(); - for(GnssStatusJoin status : deviceStatuses){ - //如果上次上线到现在超过两个周期,则认为掉线了 - LocalDateTime expiredTime = status.getUpdatetime().plusMinutes(group_cycle_map.get(status.getGroup_id())*2); - if(now.isAfter(expiredTime)){ - status.setState(GnssStatus.STATE_OFFLINE); - if(status.getWarningcode()==null) status.setWarningcode(0); - status.setWarningcode(status.getWarningcode() | WarningCfg.TYPE_DEVICE_OFF_LINE); - status.setWarning(WarningCfg.LEVEL_2); - gnssStatusMapper.setOfflineByDeviceId(status); - //告警消息 - WarningMsg warningMsg = new WarningMsg(); - warningMsg.setDevicetype(WarningCfg.TYPE_GNSS); - warningMsg.setTenantid(status.getTenantid()); - warningMsg.setDeviceid(status.getDeviceid()); - warningMsg.setCreatetime(now); - warningMsg.setLevel(WarningCfg.LEVEL_2); - warningMsg.setInfo(WarningCfg.TYPE_NAME_DEVICE_OFF_LINE); - warningMsg.setCode(WarningCfg.TYPE_DEVICE_OFF_LINE); - warningMsgMapper.insert(warningMsg); - } - } - } -} \ No newline at end of file diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssCalcDataController.java b/sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssCalcDataController.java index 98e81ad6..f0896b52 100644 --- a/sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssCalcDataController.java +++ b/sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssCalcDataController.java @@ -2,6 +2,7 @@ package com.imdroid.beidou.controller; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.github.yulichang.query.MPJQueryWrapper; import com.imdroid.beidou.entity.Tenant; import com.imdroid.beidou.entity.TenantMapper; import com.imdroid.beidou.service.CommonExcelService; @@ -74,4 +75,23 @@ public class GnssCalcDataController extends BasicController implements CommonExc public void exportData(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws Exception { this.export(session, request, response); } + + @Override + public MPJQueryWrapper prepareQueryWrapper() { + return new MPJQueryWrapper() + .selectAll(GnssCalcData.class) + .leftJoin("gnssdevices d on t.deviceid = d.deviceid") + .orderByDesc("t.createtime"); + } + + /** + * 是否联表查询 + * + * @return 是否联表查询 + */ + @Override + public boolean isJoinSelect() { + return true; + } + } diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssStatusController.java b/sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssStatusController.java index 8bd042fc..8f6077ab 100644 --- a/sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssStatusController.java +++ b/sec-beidou/src/main/java/com/imdroid/beidou/controller/GnssStatusController.java @@ -95,7 +95,8 @@ public class GnssStatusController extends BasicController implements CommonExcel return new MPJQueryWrapper() .selectAll(GnssStatus.class) .select("d.devicetype as devicetype","d.tenantid as tenantid") - .leftJoin("gnssdevices d on t.deviceid = d.deviceid"); + .leftJoin("gnssdevices d on t.deviceid = d.deviceid") + .orderByDesc("t.updatetime"); } /** diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/entity/User.java b/sec-beidou/src/main/java/com/imdroid/beidou/entity/User.java index 70f5cf9f..5910f62f 100644 --- a/sec-beidou/src/main/java/com/imdroid/beidou/entity/User.java +++ b/sec-beidou/src/main/java/com/imdroid/beidou/entity/User.java @@ -27,6 +27,7 @@ public class User { private String mobile; private String avatar_url; private String openid; + private Boolean warning_enabled; public String getUsername() { return name; diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/service/NotificationService.java b/sec-beidou/src/main/java/com/imdroid/beidou/service/NotificationService.java new file mode 100644 index 00000000..d48edee4 --- /dev/null +++ b/sec-beidou/src/main/java/com/imdroid/beidou/service/NotificationService.java @@ -0,0 +1,42 @@ +package com.imdroid.beidou.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.imdroid.beidou.entity.User; +import com.imdroid.beidou.entity.UserMapper; +import com.imdroid.secapi.dto.WarningCfg; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; + +@Service +public class NotificationService { + @Autowired + UserMapper userMapper; + + public void onWarning(String deviceIds, String content, String msgTime, short warningLevel) throws ExecutionException, InterruptedException { + // 严重告警推送短信 + if(warningLevel == WarningCfg.LEVEL_2){ + List fwdPhoneList = getFwdPhones(); + if(fwdPhoneList!=null) SmsService.send(deviceIds, content, + msgTime, fwdPhoneList); + } + } + + List getFwdPhones(){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("warning_enabled",1); + queryWrapper.eq("locked",0); + queryWrapper.isNotNull("mobile"); + List userList = userMapper.selectList(queryWrapper); + if(userList.size() == 0) return null; + + List phoneList = new ArrayList<>(); + for(User user:userList){ + phoneList.add(user.getMobile()); + } + return phoneList; + } +} diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/service/SmsService.java b/sec-beidou/src/main/java/com/imdroid/beidou/service/SmsService.java new file mode 100644 index 00000000..2286e498 --- /dev/null +++ b/sec-beidou/src/main/java/com/imdroid/beidou/service/SmsService.java @@ -0,0 +1,69 @@ +package com.imdroid.beidou.service; + +import com.aliyun.auth.credentials.Credential; +import com.aliyun.auth.credentials.provider.StaticCredentialProvider; +import com.aliyun.sdk.service.dysmsapi20170525.AsyncClient; +import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsRequest; +import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsResponse; +import com.google.gson.Gson; +import darabonba.core.client.ClientOverrideConfiguration; +import lombok.Data; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +public class SmsService { + static final String signName = "英卓科技"; + static final String templateCode = "SMS_465145810"; + static final String ACCESS_KEY = "LTAI5tGyoSky5ZG14qYTv2Fv"; + static final String ACCESS_KEY_SECRET ="jzfEqr9WV7ltSjO7BXV0WxozyFrvZu"; + + @Data + static class TemplateData{ + String time; + String name; + String content; + } + static public void send(String deviceIds, String content, String msgTime, + List phoneList) throws ExecutionException, InterruptedException { + StaticCredentialProvider provider = StaticCredentialProvider.create(Credential.builder() + .accessKeyId(ACCESS_KEY) + .accessKeySecret(ACCESS_KEY_SECRET) + .build()); + + // Configure the Client + AsyncClient client = AsyncClient.builder() + .region("cn-beijing") // Region ID + .credentialsProvider(provider) + .overrideConfiguration( + ClientOverrideConfiguration.create() + .setEndpointOverride("dysmsapi.aliyuncs.com") + //.setConnectTimeout(Duration.ofSeconds(30)) + ) + .build(); + + // Parameter settings for API request + TemplateData smsData = new TemplateData(); + smsData.setTime(msgTime); + smsData.setName(deviceIds); + smsData.setContent(content); + for(String phoneNum : phoneList) { + SendSmsRequest sendSmsRequest = SendSmsRequest.builder() + .phoneNumbers(phoneNum) + .signName(signName) + .templateCode(templateCode) + .templateParam(new Gson().toJson(smsData)) + .build(); + + // Asynchronously get the return value of the API request + CompletableFuture response = client.sendSms(sendSmsRequest); + // Synchronously get the return value of the API request + SendSmsResponse resp = response.get(); + System.out.println(new Gson().toJson(resp)); + } + + // Finally, close the client + client.close(); + } +} diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/task/DatasetCleaner.java b/sec-beidou/src/main/java/com/imdroid/beidou/task/DatasetCleaner.java new file mode 100644 index 00000000..0458ec32 --- /dev/null +++ b/sec-beidou/src/main/java/com/imdroid/beidou/task/DatasetCleaner.java @@ -0,0 +1,73 @@ +package com.imdroid.beidou.task; + +import com.imdroid.secapi.dto.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +import java.sql.Timestamp; + +/*** + * 定时任务: + * 1、定时清理消息表(缺省保留3个月) + * 2、定时清理原始数据表(缺省保留1个月) + * 3、定时清理操作日志(缺省保留1年) + * 4、定时检查设备是否在线 + * 5、定时检查FwdRecords(1 year) + */ + +@Slf4j +@Configuration +@EnableScheduling +public class DatasetCleaner { + @Autowired + GnssMsgMapper gnssMsgMapper; + @Autowired + GnssStatusMsgMapper statusMsgMapper; + @Autowired + GnssTrxMsgMapper trxMsgMapper; + @Autowired + GnssRawDataMapper rawDataMapper; + + //cron表达式格式: + //{秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)} + + @Scheduled(cron = "0 10 0 * * *") // 每天凌晨执行一次(0:10:0) + //@Scheduled(cron = "0 */2 * * * ?") // 每60分钟执行一次 + //@Scheduled(cron = "*/5 * * * * ?") // 每5秒执行一次 + public void dayTask() { + checkMsgDataset(); + checkRawDataset(); + checkFwdDataset(); + } + + void checkMsgDataset(){ + long before = System.currentTimeMillis() - + (long)90 * 24 * 3600 * 1000; + Timestamp t = new Timestamp(before); + int count = gnssMsgMapper.deleteTimeBefore(t); + log.info("clean msg dataset num: "+count); + count = statusMsgMapper.deleteTimeBefore(t); + log.info("clean status msg dataset num: "+count); + count = trxMsgMapper.deleteTimeBefore(t); + log.info("clean trx msg dataset num: "+count); + } + + void checkRawDataset(){ + long before = System.currentTimeMillis() - + (long)30 * 24 * 3600 * 1000; + Timestamp t = new Timestamp(before); + int count = rawDataMapper.deleteTimeBefore(t); + log.info("clean raw dataset num: "+count); + } + + void checkFwdDataset(){ + long before = System.currentTimeMillis() - + (long)365 * 24 * 3600 * 1000; + Timestamp t = new Timestamp(before); + int count = rawDataMapper.deleteTimeBefore(t); + log.info("clean fwd dataset num: "+count); + } +} \ No newline at end of file diff --git a/sec-beidou/src/main/java/com/imdroid/beidou/task/DeviceStatusChecker.java b/sec-beidou/src/main/java/com/imdroid/beidou/task/DeviceStatusChecker.java new file mode 100644 index 00000000..43f04434 --- /dev/null +++ b/sec-beidou/src/main/java/com/imdroid/beidou/task/DeviceStatusChecker.java @@ -0,0 +1,177 @@ +package com.imdroid.beidou.task; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.github.yulichang.query.MPJQueryWrapper; +import com.imdroid.beidou.service.NotificationService; +import com.imdroid.secapi.dto.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ExecutionException; + +/*** + * 定时任务: + * 1、定时清理消息表(缺省保留3个月) + * 2、定时清理原始数据表(缺省保留1个月) + * 3、定时清理操作日志(缺省保留1年) + * 4、定时检查设备是否在线 + * 5、定时检查FwdRecords(1 year) + */ + +@Slf4j +@Configuration +@EnableScheduling +public class DeviceStatusChecker { + @Autowired + GnssStatusMapper gnssStatusMapper; + @Autowired + GnssGroupMapper groupMapper; + @Autowired + WarningMsgMapper warningMsgMapper; + @Autowired + WarningCfgMapper warningCfgMapper; + @Autowired + NotificationService notificationService; + @Autowired + GnssCalcDataMapper dataMapper; + @Autowired + GnssDeviceMapper deviceMapper; + static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Scheduled(cron = "0 18,48 * * * ?") // 每半时执行一次 + public void checkDeviceState() throws ExecutionException, InterruptedException { + List groupCfgs = groupMapper.selectList(null); + HashMap group_cycle_map=new HashMap<>(); + for(GnssGroup g:groupCfgs){ + group_cycle_map.put(g.getId(), g.getWork_cycle()); + } + + List cfgList = warningCfgMapper.selectList(null); + + int noDataCycles = 2; + for(WarningCfg cfg: cfgList){ + if(cfg.getType() == WarningCfg.TYPE_DEVICE_OFF_LINE){ + noDataCycles = cfg.getValue(); + break; + } + } + LocalDateTime now = LocalDateTime.now(); + List deviceStatuses = gnssStatusMapper.queryOnline(); + String deviceIds = null; + for(GnssStatusJoin status : deviceStatuses){ + //如果上次上线到现在超过两个周期,则认为掉线了 + LocalDateTime expiredTime = status.getUpdatetime().plusMinutes(group_cycle_map.get(status.getGroup_id())*noDataCycles); + if(now.isAfter(expiredTime)){ + status.setState(GnssStatus.STATE_OFFLINE); + if(status.getWarningcode()==null) status.setWarningcode(0); + status.setWarningcode(status.getWarningcode() | WarningCfg.TYPE_DEVICE_OFF_LINE); + status.setWarning(WarningCfg.LEVEL_2); + gnssStatusMapper.setOfflineByDeviceId(status); + //告警消息 + WarningMsg warningMsg = new WarningMsg(); + warningMsg.setDevicetype(WarningCfg.TYPE_GNSS); + warningMsg.setTenantid(status.getTenantid()); + warningMsg.setDeviceid(status.getDeviceid()); + warningMsg.setCreatetime(now); + warningMsg.setLevel(WarningCfg.LEVEL_2); + warningMsg.setInfo(WarningCfg.TYPE_NAME_DEVICE_OFF_LINE); + warningMsg.setCode(WarningCfg.TYPE_DEVICE_OFF_LINE); + warningMsgMapper.insert(warningMsg); + //短信推送 + if(deviceIds==null) deviceIds = status.getDeviceid(); + else deviceIds = deviceIds+", "+status.getDeviceid(); + } + } + if(deviceIds!=null) { + notificationService.onWarning(deviceIds, + WarningCfg.TYPE_NAME_DEVICE_OFF_LINE, + now.format(formatter), WarningCfg.LEVEL_2); + } + } + + @Scheduled(cron = "0 28 * * * ?") // 每小时执行一次 + void checkRoverStationCalcData() throws ExecutionException, InterruptedException { + //获取所有基站 + String deviceIds = null; + QueryWrapper deviceQueryWrapper = new QueryWrapper<>(); + deviceQueryWrapper.eq("devicetype", GnssDevice.TYPE_REFERENCE_STATION); + deviceQueryWrapper.eq("opmode", GnssDevice.OP_MODE_USE); + List bsList = deviceMapper.selectList(deviceQueryWrapper); + for(GnssDevice bs:bsList){ + GnssStatus status = gnssStatusMapper.getByDeviceId(bs.getDeviceid()); + if(status != null) { + int oldWarningCode = status.getWarningcode() & WarningCfg.TYPE_BS_NO_RESULT; + int newWarningCode = oldWarningCode; + if(!isRoverStationNormal(bs.getDeviceid())){ + WarningMsg warningMsg = new WarningMsg(); + warningMsg.setDeviceid(bs.getDeviceid()); + warningMsg.setTenantid(bs.getTenantid()); + warningMsg.setCreatetime(LocalDateTime.now()); + warningMsg.setDevicetype(WarningCfg.TYPE_GNSS); + warningMsg.setCode(WarningCfg.TYPE_BS_NO_RESULT); + warningMsg.setLevel(WarningCfg.LEVEL_2); + warningMsg.setInfo(WarningCfg.TYPE_NAME_BS_NO_RESULT); + warningMsgMapper.insert(warningMsg); + newWarningCode = WarningCfg.TYPE_BS_NO_RESULT; + } + else{ + newWarningCode = 0; + } + + if(oldWarningCode!=newWarningCode){ + //清除原来的告警 + if(newWarningCode == 0) { + status.setWarningcode(status.getWarningcode() & ~WarningCfg.TYPE_BS_NO_RESULT); + } + else{ + status.setWarningcode(status.getWarningcode() | WarningCfg.TYPE_BS_NO_RESULT); + if(deviceIds == null) deviceIds = bs.getDeviceid(); + else deviceIds = deviceIds+","+bs.getDeviceid(); + } + gnssStatusMapper.updateById(status); + } + } + + } + + // 发短信通知 + if(deviceIds != null){ + notificationService.onWarning(deviceIds, + WarningCfg.TYPE_NAME_BS_NO_RESULT, + LocalDateTime.now().format(formatter), + WarningCfg.LEVEL_2); + } + } + + /*** + * 检查基站下的测站最近一个小时是否全都无固定解 + * @param parentId + */ + boolean isRoverStationNormal(String parentId){ + //是否有关联测站 + QueryWrapper deviceQueryWrapper = new QueryWrapper<>(); + deviceQueryWrapper.eq("parentid", parentId); + deviceQueryWrapper.eq("opmode",GnssDevice.OP_MODE_USE); + if(deviceMapper.selectCount(deviceQueryWrapper) == 0) return true; + + //如果有关联的测站,检查解算结果 + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime beginTime = endTime.minusHours(1); + MPJQueryWrapper queryWrapper = + new MPJQueryWrapper() + .selectAll(GnssCalcData.class) + .leftJoin("gnssdevices d on t.deviceid = d.deviceid") + .eq("d.parentid",parentId) + .between("t.createtime",beginTime.format(formatter),endTime.format(formatter)) + .eq("t.enabled",true); + List dataList = dataMapper.selectList(queryWrapper); + return dataList.size()>0; + } +} \ No newline at end of file diff --git a/sec-beidou/src/main/resources/db/schema.sql b/sec-beidou/src/main/resources/db/schema.sql index 35d2e2e5..50156951 100644 --- a/sec-beidou/src/main/resources/db/schema.sql +++ b/sec-beidou/src/main/resources/db/schema.sql @@ -11,6 +11,7 @@ CREATE TABLE IF NOT EXISTS `UserCfg` ( `mobile` varchar(20) DEFAULT NULL, `avatar_url` varchar(255) DEFAULT NULL, `openid` varchar(64) DEFAULT NULL, + `warning_enabled` bit(1) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/sec-beidou/src/main/resources/templates/page/gnss_data_calc.html b/sec-beidou/src/main/resources/templates/page/gnss_data_calc.html index eb70b4ea..88c5443a 100644 --- a/sec-beidou/src/main/resources/templates/page/gnss_data_calc.html +++ b/sec-beidou/src/main/resources/templates/page/gnss_data_calc.html @@ -21,25 +21,31 @@
- +
-
+
+ +
+ +
+
- +
- +
diff --git a/sec-beidou/src/main/resources/templates/page/gnss_status.html b/sec-beidou/src/main/resources/templates/page/gnss_status.html index bb4d66d2..c681c077 100644 --- a/sec-beidou/src/main/resources/templates/page/gnss_status.html +++ b/sec-beidou/src/main/resources/templates/page/gnss_status.html @@ -33,6 +33,12 @@ +
+ +
+ +
+
diff --git a/sec-beidou/src/main/resources/templates/page/table/user_add.html b/sec-beidou/src/main/resources/templates/page/table/user_add.html index a96bdc60..2adee518 100644 --- a/sec-beidou/src/main/resources/templates/page/table/user_add.html +++ b/sec-beidou/src/main/resources/templates/page/table/user_add.html @@ -70,6 +70,17 @@
+
+
+ +
+ +
+
+
@@ -129,6 +140,7 @@ $('#tenantname').val(data.tenantname); $('#role').val(data.role); $('#locked').val(data.locked?'1':'0'); + $('#warning_enabled').val(data.warning_enabled?'1':'0'); $('#avatar_url').val(data.avatar_url); $('#openid').val(data.openid); form.render(); diff --git a/sec-beidou/src/main/resources/templates/page/user_cfg.html b/sec-beidou/src/main/resources/templates/page/user_cfg.html index 4edb8d6a..910d5288 100644 --- a/sec-beidou/src/main/resources/templates/page/user_cfg.html +++ b/sec-beidou/src/main/resources/templates/page/user_cfg.html @@ -75,6 +75,7 @@ {field: 'role', title: '角色'}, {field: 'tenantname', title: '所属组织'}, {field: 'locked', title: '是否冻结', templet: "
{{d.locked==1?'是':'否'}}
"}, + {field: 'warning_enabled', title: '告警通知', templet: "
{{d.warning_enabled==1?'是':'否'}}
"}, {title: '操作', toolbar: '#currentTableBar', align: "center", minWidth: 120} ]], limits: [10, 15, 20, 25, 50, 100],