Merge remote-tracking branch 'origin/master' into feature/beidou

# Conflicts:
#	sec-api/src/main/java/com/imdroid/secapi/dto/WarningCfg.java
#	sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/WarningServiceImpl.java
#	sec-beidou/src/main/java/com/imdroid/beidou/controller/WarningController.java
#	sec-beidou/src/main/resources/db/schema.sql
This commit is contained in:
zms 2025-02-24 14:21:17 +08:00
commit c6fe8d403a
33 changed files with 952 additions and 53 deletions

View File

@ -17,6 +17,7 @@
<module>sec-test-device</module> <module>sec-test-device</module>
<module>sec-ntrip-proxy</module> <module>sec-ntrip-proxy</module>
<module>sec-exapi</module> <module>sec-exapi</module>
<module>sec-beidou-ehm</module>
</modules> </modules>
<properties> <properties>

View File

@ -0,0 +1,34 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
* GNSS设备配置数据
*
* @author LiGang
*/
@Data
@TableName(value = "ehm")
public class Ehm {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Integer tenantid;
private String deviceid;
private LocalDateTime createtime;
private Short offlinestatdays;
private Integer offlinecount;
private Integer offlineminutes;
private Integer calcstathours;
private Float stdeve;
private Float stdevn;
private Float stdevu;
private Float fixrate;
private Float validrate;
private Integer jumpcount;
}

View File

@ -0,0 +1,19 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
* GNSS设备配置数据
*
* @author LiGang
*/
@Data
@TableName(value = "ehmconfig")
public class EhmConfig {
private LocalDateTime updatetime;
private Short offlinestatdays;
private Integer calcstathours;
}

View File

@ -0,0 +1,8 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface EhmConfigMapper extends BaseMapper<EhmConfig> {
}

View File

@ -0,0 +1,36 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
* GNSS设备配置数据
*
* @author LiGang
*/
@Data
@TableName(value = "ehm")
public class EhmJoin {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Integer tenantid;
private String deviceid;
private Short devicetype;
private Short model;
private LocalDateTime createtime;
private Short offlinestatdays;
private Integer offlinecount;
private Integer offlineminutes;
private Integer calcstathours;
private Float stdeve;
private Float stdevn;
private Float stdevu;
private Float fixrate;
private Float validrate;
private Integer jumpcount;
}

View File

@ -0,0 +1,8 @@
package com.imdroid.secapi.dto;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface EhmMapper extends MPJBaseMapper<Ehm> {
}

View File

@ -25,6 +25,7 @@ public class GnssGroup implements Serializable {
Short rs_adv; // reference station only Short rs_adv; // reference station only
Short power_mode; Short power_mode;
Integer device_num; Integer device_num;
Short gnss_sample_s;
public String getConfigCmd(GnssDevice device){ public String getConfigCmd(GnssDevice device){
String cmd = "D3110009"; String cmd = "D3110009";
@ -33,7 +34,8 @@ public class GnssGroup implements Serializable {
+HexUtil.Byte2HexString((byte) active_time.intValue()) +HexUtil.Byte2HexString((byte) active_time.intValue())
+HexUtil.Byte2HexString((byte) active_offset.intValue()) +HexUtil.Byte2HexString((byte) active_offset.intValue())
+((device.getDevicetype() == GnssDevice.TYPE_ROVER)?"00":HexUtil.Byte2HexString((byte) rs_adv.shortValue())) +((device.getDevicetype() == GnssDevice.TYPE_ROVER)?"00":HexUtil.Byte2HexString((byte) rs_adv.shortValue()))
+HexUtil.Byte2HexString((byte) power_mode.shortValue()); +HexUtil.Byte2HexString((byte) power_mode.shortValue())
+HexUtil.Byte2HexString((byte) gnss_sample_s.shortValue());
return cmd; return cmd;
} }

View File

@ -76,6 +76,8 @@ public class GnssStatusJoin {
@ExcelProperty("设备类型") @ExcelProperty("设备类型")
Short devicetype; Short devicetype;
@ExcelProperty("设备型号")
Short model;
@ExcelIgnore @ExcelIgnore
Integer group_id; Integer group_id;

View File

@ -19,26 +19,26 @@ public interface GnssStatusMapper extends MPJBaseMapper<GnssStatus> {
@Update({"update gnssstatus set state=0,warning=#{warning},warningcode=#{warningcode} where deviceid=#{deviceid}"}) @Update({"update gnssstatus set state=0,warning=#{warning},warningcode=#{warningcode} where deviceid=#{deviceid}"})
int setOfflineByDeviceId(GnssStatusJoin status); int setOfflineByDeviceId(GnssStatusJoin status);
@Select({"select s.*, d.devicetype, d.group_id, d.name from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid and s.state <> 0"}) @Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid and s.state <> 0"})
List<GnssStatusJoin> queryOnline(); List<GnssStatusJoin> queryOnline();
@Select({"select s.*, d.devicetype, d.group_id, d.name from gnssstatus s ,gnssdevices d where " + @Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id from gnssstatus s ,gnssdevices d where " +
"s.deviceid=d.deviceid and d.tenantid<>0 and d.opmode=0"}) "s.deviceid=d.deviceid and d.tenantid<>0 and d.opmode=0"})
List<GnssStatusJoin> queryDeployed(); List<GnssStatusJoin> queryDeployed();
@Select({"select s.*, d.devicetype, d.group_id, d.name, d.project_id from gnssstatus s ,gnssdevices d where " + @Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id from gnssstatus s ,gnssdevices d where " +
"s.deviceid=d.deviceid and d.tenantid = #{tenantid} and d.opmode=0"}) "s.deviceid=d.deviceid and d.tenantid = #{tenantid} and d.opmode=0"})
List<GnssStatusJoin> queryDeployedByTenant(int tenantid); List<GnssStatusJoin> queryDeployedByTenant(int tenantid);
//多个入参要用Param注解 //多个入参要用Param注解
@Select({"select s.*, d.devicetype, d.group_id, d.name, d.project_id from gnssstatus s ,gnssdevices d where " + @Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id from gnssstatus s ,gnssdevices d where " +
"s.deviceid=d.deviceid and d.tenantid = #{tenantid} and d.opmode=0 and d.project_id = #{projectName}"}) "s.deviceid=d.deviceid and d.tenantid = #{tenantid} and d.opmode=0 and d.project_id = #{projectName}"})
List<GnssStatusJoin> queryDeployedByProject(@Param("tenantid") int tenantid, @Param("projectName") String projectName); List<GnssStatusJoin> queryDeployedByProject(@Param("tenantid") int tenantid, @Param("projectName") String projectName);
// 需要关联设备类型 // 需要关联设备类型
@Select({"select s.*, d.devicetype from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid and s.deviceid = #{deviceId}"}) @Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid and s.deviceid = #{deviceId}"})
GnssStatusJoin queryByDeviceId(String deviceId); GnssStatusJoin queryByDeviceId(String deviceId);
@Select({"select s.*, d.devicetype from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid"}) @Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid"})
GnssStatusJoin queryAll(); GnssStatusJoin queryAll();
} }

View File

@ -56,6 +56,8 @@ public class GnssTrxMsg {
// 这里的收发都是服务端统计的终端收发详细统计在msg_trx表里 // 这里的收发都是服务端统计的终端收发详细统计在msg_trx表里
@ExcelProperty("B562") @ExcelProperty("B562")
Integer b562bytes; Integer b562bytes;
@ExcelProperty("B562Count")
Integer b562count;
@ExcelProperty("D3XX") @ExcelProperty("D3XX")
Integer d3xxbytes; Integer d3xxbytes;
@ -69,4 +71,6 @@ public class GnssTrxMsg {
Integer floatnum; Integer floatnum;
@ExcelProperty("备注") @ExcelProperty("备注")
String remark; String remark;
@ExcelProperty("JumpCount")
Integer jumpcount;
} }

View File

@ -44,8 +44,13 @@ public class WarningCfg {
public static final String TYPE_NAME_INCLINE = "异常倾斜"; public static final String TYPE_NAME_INCLINE = "异常倾斜";
public static final int TYPE_SIM_STATUS_ABNORMAL = 0x800; public static final int TYPE_SIM_STATUS_ABNORMAL = 0x800;
public static final String TYPE_NAME_SIM_STATUS_ABNORMAL = "流量卡状态异常"; public static final String TYPE_NAME_SIM_STATUS_ABNORMAL = "流量卡状态异常";
public static final int TYPE_SIM_LOW_TRAFFIC = 0x900; public static final int TYPE_SIM_LOW_TRAFFIC = 0x1000;
public static final String TYPE_NAME_SIM_LOW_TRAFFIC = "流量卡流量不足"; public static final String TYPE_NAME_SIM_LOW_TRAFFIC = "流量卡流量不足";
public static final int TYPE_XY_JUMP = 0x2000;
public static final String TYPE_NAME_XY_JUMP = "滤波结果水平跳变";
public static final int TYPE_Z_JUMP = 0x4000;
public static final String TYPE_NAME_Z_JUMP = "滤波结果高程跳变";
// warning level definition // warning level definition
public static final short LEVEL_0 = 0; //正常 public static final short LEVEL_0 = 0; //正常

107
sec-beidou-ehm/pom.xml Normal file
View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.imdroid</groupId>
<artifactId>security-monitor</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>sec-beidou-ehm</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version><!--$NO-MVN-MAN-VER$ -->
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.imdroid</groupId>
<artifactId>sec-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.imdroid</groupId>
<artifactId>sec-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>central</id>
<name>ali-mirror</name>
<url>https://maven.aliyun.com/repository/central</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@ -0,0 +1,22 @@
package com.imdroid.beidou_ehm;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
/**
* @author Layton
* @date 2023/1/31 20:33
*/
@SpringBootApplication(scanBasePackages = {"com.imdroid"})
@MapperScan({"com.imdroid.secapi","com.imdroid.beidou.entity"})
@ComponentScan({"com.imdroid.*"})
@EntityScan({"com.imdroid.*"})
public class BeidouEhmApp {
public static void main(String[] args) {
SpringApplication.run(BeidouEhmApp.class, args);
}
}

View File

@ -0,0 +1,171 @@
package com.imdroid.beidou_ehm.task;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.imdroid.secapi.dto.*;
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 org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;
@Component
@Configuration
@EnableScheduling
public class EhmTask{
@Autowired
GnssStatusMapper statusMapper;
@Autowired
EhmMapper ehmMapper;
@Autowired
EhmConfigMapper ehmConfigMapper;
@Autowired
WarningMsgMapper warningMsgMapper;
@Autowired
GnssCalcDataMapper gnssCalcDataMapper;
@Autowired
GnssTrxMsgMapper gnssTrxMsgMapper;
/**
* 每半小时转发GNSS解算结果
*/
@Scheduled(cron = "0 15 7 * * ?") // 每天7点15分钟执行一次
private void check() {
// 获取健康检查配置
List<EhmConfig> ehmConfigList = ehmConfigMapper.selectList(null);
EhmConfig ehmConfig;
if(ehmConfigList==null || ehmConfigList.size()==0){
ehmConfig = new EhmConfig();
ehmConfig.setUpdatetime(LocalDateTime.now());
ehmConfig.setCalcstathours(24);
ehmConfig.setOfflinestatdays((short) 7);
ehmConfigMapper.insert(ehmConfig);
}
else{
ehmConfig = ehmConfigList.get(0);
}
// 获取所有已部署的设备
List<GnssStatusJoin> deviceList= statusMapper.queryDeployed();
Iterator<GnssStatusJoin> iterator = deviceList.iterator();
while(iterator.hasNext()) {
GnssStatusJoin status=iterator.next();
Ehm ehm = new Ehm();
ehm.setDeviceid(status.getDeviceid());
ehm.setTenantid(status.getTenantid());
ehm.setCreatetime(LocalDateTime.now());
ehm.setOfflinestatdays(ehmConfig.getOfflinestatdays());
ehm.setCalcstathours(ehmConfig.getCalcstathours());
// 检查过去N天离线次数和时长
checkOffline(ehm, status.getState()==GnssStatus.STATE_OFFLINE);
// 计算过去N小时标准差
// 计算过去N小时有效解比例
// 计算过去N小时固定解比例
checkCalcResults(ehm);
ehmMapper.insert(ehm);
}
}
private void checkOffline(Ehm ehm, boolean isOffline){
LocalDateTime now = ehm.getCreatetime();
// 从告警消息里查询离线记录
QueryWrapper<WarningMsg> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deviceid",ehm.getDeviceid());
queryWrapper.ge("createtime",now.minusDays(ehm.getOfflinestatdays()));
queryWrapper.eq("code",WarningCfg.TYPE_DEVICE_OFF_LINE);
List<WarningMsg> warningMsgList = warningMsgMapper.selectList(queryWrapper);
if(warningMsgList==null || warningMsgList.size()==0){
if(isOffline){
ehm.setOfflinecount(1);
ehm.setOfflineminutes(ehm.getOfflinestatdays()*24*60);
}
else{
ehm.setOfflinecount(0);
ehm.setOfflineminutes(0);
}
}
else{
ehm.setOfflinecount(warningMsgList.size());
int offlineMinutes = 0;
LocalDateTime offlineEnd = null;
LocalDateTime offlineBegin = null;
for(WarningMsg warningMsg:warningMsgList){
// 读下一条纪录时才计算上一条的时间差因为cleartime有可能没有
if(offlineEnd==null) offlineEnd=warningMsg.getCreatetime();
if(offlineBegin!=null){
Duration duration = Duration.between(offlineBegin,offlineEnd);
offlineMinutes+=duration.toMinutes();
}
offlineBegin = warningMsg.getCreatetime();
offlineEnd = warningMsg.getCleartime();
}
if(offlineEnd==null) offlineEnd=now;
if(offlineBegin!=null){
Duration duration = Duration.between(offlineBegin,offlineEnd);
offlineMinutes+=duration.toMinutes();
}
ehm.setOfflineminutes(offlineMinutes);
}
}
private void checkCalcResults(Ehm ehm){
// 获取过去N小时的解算数据
QueryWrapper<GnssCalcData> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deviceid", ehm.getDeviceid());
queryWrapper.ge("createtime", ehm.getCreatetime().minusHours(ehm.getCalcstathours()));
List<GnssCalcData> gnssCalcDataList = gnssCalcDataMapper.selectList(queryWrapper);
// 计算过去N小时标准差不含有效值
// 计算过去N小时有效解比例
double avgE = 0;
double avgN = 0;
double avgU = 0;
double sedevE = 0;
double sedevN = 0;
double sedevU = 0;
int validCount = 0;
for(GnssCalcData gnssCalcData:gnssCalcDataList){
if(gnssCalcData.getEnabled()){
avgE += gnssCalcData.getB562e();
avgN += gnssCalcData.getB562n();
avgU += gnssCalcData.getB562d();
validCount++;
}
}
if(validCount>0){
avgE = avgE/validCount;
avgN = avgN/validCount;
avgU = avgU/validCount;
for(GnssCalcData gnssCalcData:gnssCalcDataList){
if(gnssCalcData.getEnabled()){
sedevE += Math.pow(gnssCalcData.getB562e()-avgE,2);
sedevN += Math.pow(gnssCalcData.getB562n()-avgN,2);
sedevU += Math.pow(gnssCalcData.getB562d()-avgU,2);
}
}
ehm.setStdeve((float) Math.sqrt(sedevE/validCount));
ehm.setStdevn((float) Math.sqrt(sedevN/validCount));
ehm.setStdevu((float) Math.sqrt(sedevU/validCount));
ehm.setValidrate((float) (validCount*100/gnssCalcDataList.size()));
}
// 计算过去N小时固定解比例
QueryWrapper<GnssTrxMsg> queryWrapper1 = new QueryWrapper<>();
queryWrapper1.eq("deviceid",ehm.getDeviceid());
queryWrapper1.ge("createtime", ehm.getCreatetime().minusHours(ehm.getCalcstathours()));
List<GnssTrxMsg> gnssTrxMsgList = gnssTrxMsgMapper.selectList(queryWrapper1);
int fixCount = 0;
int d341Count = 0;
int jumpCount = 0;
for(GnssTrxMsg gnssTrxMsg:gnssTrxMsgList){
if(gnssTrxMsg.getFixnum()!=null) fixCount += gnssTrxMsg.getFixnum();
if(gnssTrxMsg.getB562count()!=null) d341Count += gnssTrxMsg.getB562count();
if(gnssTrxMsg.getJumpcount()!=null) jumpCount += gnssTrxMsg.getJumpcount();
}
if(d341Count>0) ehm.setFixrate((float) (fixCount*100/d341Count));
ehm.setJumpcount(jumpCount);
}
}

View File

@ -0,0 +1,21 @@
server.port=9912
spring.application.name=beidou-ehm
spring.application.build=20250213
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = none
spring.jpa.database-platform = org.hibernate.dialect.MySQLDialect
#spring.datasource.url = jdbc:mysql://localhost:3306/beidou?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
spring.datasource.url=jdbc:mysql://139.9.51.237:3306/beidou?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
spring.datasource.username = radmin
spring.datasource.password = DBMgr_2022
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver
spring.jackson.dateFormat = yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone = GMT+8
app.format.date = yyyy-MM-dd
app.format.time = HH:mm:ss
app.format.datetime = yyyy-MM-dd HH:mm:ss
mybatis-plus.configuration.map-underscore-to-camel-case=false

View File

@ -145,6 +145,7 @@ public class SingleLineGNSSCalcService implements GNSSDataCalcService {
if(groupCalc.getVer() == 3 && focusCalculator.isJump()){ if(groupCalc.getVer() == 3 && focusCalculator.isJump()){
logger.info("{}发生周跳",deviceId); logger.info("{}发生周跳",deviceId);
hardResetDevice(deviceId); hardResetDevice(deviceId);
device.setJumpCount(device.getJumpCount()+1);
} }
} }
@ -278,11 +279,15 @@ public class SingleLineGNSSCalcService implements GNSSDataCalcService {
} }
} }
// 如果本次结果有跳变则停止推送并产生严重告警
//更新有效解时间 //更新有效解时间
if(locationRecord.getEnabled()){ if(locationRecord.getEnabled()){
if(device.getLastValidCalcDataTime()==null || device.getLastValidCalcDataTime().isBefore(resultTime)){ if(device.getLastValidCalcDataTime()==null || device.getLastValidCalcDataTime().isBefore(resultTime)){
device.setLastValidCalcDataTime(resultTime); device.setLastValidCalcDataTime(resultTime);
} }
if(latestRpos!=null){
warningService.checkFilteredResultJump(latestRpos, locationRecord);
}
} }
// 记录本次位置作为下次的参考 // 记录本次位置作为下次的参考
@ -379,6 +384,7 @@ public class SingleLineGNSSCalcService implements GNSSDataCalcService {
queryWrapper.eq("deviceid",deviceId); queryWrapper.eq("deviceid",deviceId);
queryWrapper.ge("createtime",LocalDateTime.now().minusHours(12)); queryWrapper.ge("createtime",LocalDateTime.now().minusHours(12));
queryWrapper.isNotNull("rpose"); queryWrapper.isNotNull("rpose");
queryWrapper.eq("enabled",true);
queryWrapper.orderByDesc("createtime"); queryWrapper.orderByDesc("createtime");
queryWrapper.last("limit 1"); queryWrapper.last("limit 1");
GnssCalcData gnssCalcData = dataMapper.selectOne(queryWrapper); GnssCalcData gnssCalcData = dataMapper.selectOne(queryWrapper);
@ -405,4 +411,5 @@ public class SingleLineGNSSCalcService implements GNSSDataCalcService {
deviceChannel.writeAndFlush(buf); deviceChannel.writeAndFlush(buf);
} }
} }
} }

View File

@ -67,9 +67,11 @@ public class D3F2StopIndicationMessageExecutor implements Executor<D3F2StopIndic
gnssTrxMsg.setTenantid(device.getTenantId()); gnssTrxMsg.setTenantid(device.getTenantId());
gnssTrxMsg.setD3xxbytes(device.getD3xxbytes()); gnssTrxMsg.setD3xxbytes(device.getD3xxbytes());
gnssTrxMsg.setB562bytes(device.getD341bytes()); gnssTrxMsg.setB562bytes(device.getD341bytes());
gnssTrxMsg.setB562count(device.getD341Count());
gnssTrxMsg.setSatelliteinuse(device.getSatelitesInUse()); gnssTrxMsg.setSatelliteinuse(device.getSatelitesInUse());
gnssTrxMsg.setFixnum(device.getFixedNum()); gnssTrxMsg.setFixnum(device.getFixedNum());
gnssTrxMsg.setFloatnum(device.getFloatNum()); gnssTrxMsg.setFloatnum(device.getFloatNum());
gnssTrxMsg.setJumpcount(device.getJumpCount());
// 储设备收发字节数统计信息 // 储设备收发字节数统计信息
ThreadManager.getFixedThreadPool().submit(() -> { ThreadManager.getFixedThreadPool().submit(() -> {

View File

@ -56,6 +56,7 @@ public class Device {
int d341In42Count = 0; int d341In42Count = 0;
int satelitesInUse = 0;//平均卫星数 int satelitesInUse = 0;//平均卫星数
int sataStatCount = 0; int sataStatCount = 0;
int jumpCount = 0;
Double latitude; Double latitude;
Double longitude; Double longitude;
@ -150,6 +151,7 @@ public class Device {
satelitesInUse = 0; satelitesInUse = 0;
fixedNum = 0; fixedNum = 0;
floatNum = 0; floatNum = 0;
jumpCount = 0;
} }
public void clearD342Stat(){ public void clearD342Stat(){

View File

@ -1,8 +1,8 @@
package com.imdroid.sideslope.service; package com.imdroid.sideslope.service;
import com.imdroid.secapi.dto.GnssCalcData;
import com.imdroid.secapi.dto.GnssStatus; import com.imdroid.secapi.dto.GnssStatus;
import com.imdroid.secapi.dto.GnssStatusMsg; import com.imdroid.secapi.dto.GnssStatusMsg;
import com.imdroid.secapi.dto.GnssTrxMsg;
import com.imdroid.sideslope.sal.Device; import com.imdroid.sideslope.sal.Device;
public interface WarningService { public interface WarningService {
@ -22,6 +22,5 @@ public interface WarningService {
/*** /***
* 检查未知报文是否较多 * 检查未知报文是否较多
*/ */
void checkTrx(GnssTrxMsg msg, GnssStatus curStatus); void checkFilteredResultJump(double[] latestRpos, GnssCalcData locationRecord);
} }

View File

@ -30,7 +30,8 @@ public class WarningServiceImpl implements WarningService {
WarningMsgMapper warningMsgMapper; WarningMsgMapper warningMsgMapper;
@Autowired @Autowired
GnssStatusMapper gnssStatusMapper; GnssStatusMapper gnssStatusMapper;
@Autowired
GnssDeviceMapper deviceMapper;
@Value("${warning.log.directory}") @Value("${warning.log.directory}")
private String logDirectory; private String logDirectory;
@ -224,14 +225,6 @@ public class WarningServiceImpl implements WarningService {
return isUpdated; return isUpdated;
} }
/***
* 检查未知报文是否较多
*/
@Override
public void checkTrx(GnssTrxMsg msg, GnssStatus curStatus){
}
public short getWarningLevel(int warningCode){ public short getWarningLevel(int warningCode){
if(warningCode == 0) return WarningCfg.LEVEL_0; if(warningCode == 0) return WarningCfg.LEVEL_0;
else if((warningCode & warningLevel2Code) !=0 ) return WarningCfg.LEVEL_2; else if((warningCode & warningLevel2Code) !=0 ) return WarningCfg.LEVEL_2;
@ -268,7 +261,80 @@ public class WarningServiceImpl implements WarningService {
} }
} }
} }
/*
// 检查SIM卡状态
public void checkSimCardStatus(Device device, SimCard simCard) {
GnssStatus status = gnssStatusMapper.getByDeviceId(device.getDeviceId());
if (status == null) return;
boolean isUpdated = false;
// 检查SIM卡状态是否异常停机注销失效
if (simCard.getStatus() == SimCard.STATUS_SUSPENDED ||
simCard.getStatus() == SimCard.STATUS_CANCELLED ||
simCard.getStatus() == SimCard.STATUS_INVALID) {
String statusDesc;
switch(simCard.getStatus()) {
case SimCard.STATUS_SUSPENDED:
statusDesc = "停机";
break;
case SimCard.STATUS_CANCELLED:
statusDesc = "注销";
break;
case SimCard.STATUS_INVALID:
statusDesc = "失效";
break;
default:
statusDesc = "未知状态";
}
if (check(status, WarningCfg.TYPE_SIM_STATUS_ABNORMAL,
WarningCfg.TYPE_NAME_SIM_STATUS_ABNORMAL, false,
simCard.getStatus(), null,
"SIM卡状态: " + statusDesc)) {
isUpdated = true;
}
} else if (simCard.getStatus() == SimCard.STATUS_ACTIVATED) {
// 状态正常已激活清除告警
if ((status.getWarningcode() & WarningCfg.TYPE_SIM_STATUS_ABNORMAL) != 0) {
clearWarning(status, WarningCfg.TYPE_SIM_STATUS_ABNORMAL);
isUpdated = true;
}
}
if (isUpdated) {
status.setWarning(getWarningLevel(status.getWarningcode()));
gnssStatusMapper.updateById(status);
}
}
public void checkSimCardTraffic(Device device, SimCard simCard) {
GnssStatus status = gnssStatusMapper.getByDeviceId(device.getDeviceId());
if (status == null) return;
boolean isUpdated = false;
BigDecimal usedPercentage = simCard.getUsed()
.divide(simCard.getTotal(), 4, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(100));
// 检查流量使用情况
if (check(status, WarningCfg.TYPE_SIM_LOW_TRAFFIC,
WarningCfg.TYPE_NAME_SIM_LOW_TRAFFIC,
false, // 大于等于流量门限值那么就报警
usedPercentage.intValue(),
null,
String.format("流量已使用 %.2f%%", usedPercentage.doubleValue()))) {
isUpdated = true;
}
if (isUpdated) {
status.setWarning(getWarningLevel(status.getWarningcode()));
gnssStatusMapper.updateById(status);
}
}
*/
// 检查SIM卡状态 // 检查SIM卡状态
public void checkSimCardStatus(Device device, SimCard simCard) { public void checkSimCardStatus(Device device, SimCard simCard) {
GnssStatus status = gnssStatusMapper.getByDeviceId(device.getDeviceId()); GnssStatus status = gnssStatusMapper.getByDeviceId(device.getDeviceId());
@ -365,4 +431,52 @@ public class WarningServiceImpl implements WarningService {
warningMsgMapper.updateById(warningMsg); warningMsgMapper.updateById(warningMsg);
} }
} }
@Override
public void checkFilteredResultJump(double[] latestRpos, GnssCalcData locationRecord){
int[] warningValuesXY = cfgMap.get(WarningCfg.TYPE_XY_JUMP);
int[] warningValuesZ = cfgMap.get(WarningCfg.TYPE_Z_JUMP);
int warningCode = 0;
if(warningValuesXY!=null){
if(Math.abs(locationRecord.getRpose()-latestRpos[0])>warningValuesXY[1] ||
Math.abs(locationRecord.getRposn()-latestRpos[1])>warningValuesXY[1]){
warningCode = WarningCfg.TYPE_XY_JUMP;
}
}
if(warningCode==0 && warningValuesZ!=null){
if(Math.abs(locationRecord.getRposd()-latestRpos[2])>warningValuesZ[1]){
warningCode = WarningCfg.TYPE_Z_JUMP;
}
}
if(warningCode!=0){
// 停止推送
QueryWrapper<GnssDevice> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deviceid",locationRecord.getDeviceid());
queryWrapper.last("limit 1");
GnssDevice device = deviceMapper.selectOne(queryWrapper);
String unFwdGroupName = "不推送";
if(device != null){
if(device.getTenantid() != Tenant.SAAS_PROVIDER_ID &&
!unFwdGroupName.equals(device.getFwd_group_id())){
device.setFwd_group_id(unFwdGroupName);
device.setFwd_group_id2(unFwdGroupName);
//deviceMapper.updateById(device);
// 产生告警
WarningMsg warningMsg = new WarningMsg();
warningMsg.setDeviceid(device.getDeviceid());
warningMsg.setTenantid(device.getTenantid());
warningMsg.setCreatetime(LocalDateTime.now());
warningMsg.setCode(warningCode);
warningMsg.setLevel(WarningCfg.LEVEL_2);
double deltaE = locationRecord.getRpose()-latestRpos[0];
double deltaN = locationRecord.getRposn()-latestRpos[1];
double deltaU = locationRecord.getRposd()-latestRpos[2];
warningMsg.setInfo("滤波结果跳变:"+deltaE+", "+deltaN+", "+deltaU);
warningMsg.setDevicetype(WarningCfg.TYPE_GNSS);
warningMsgMapper.insert(warningMsg);
}
}
}
}
} }

View File

@ -159,13 +159,14 @@ public class AbnormalDeviceProcessor{
void checkNotGoodDevice(String deviceId, String refDeviceId1){ void checkNotGoodDevice(String deviceId, String refDeviceId1){
LocalDateTime validTime = LocalDateTime.now().minusMinutes(10); LocalDateTime validTime = LocalDateTime.now().minusMinutes(10);
// 待修改的点 // 待修改的点
List<GnssCalcData> calcDataList = getLastTwo(deviceId,0); List<GnssCalcData> calcDataList = getLastTwo(deviceId,12);
if(calcDataList.size() < 2) return; if(calcDataList.size() < 2) return;
if(calcDataList.get(0).getCreatetime().isBefore(validTime)) return; //if(calcDataList.get(0).getCreatetime().isBefore(validTime)) return;
// 参考点 // 参考点
double deltaU = (Math.random()*2-1)/10; double deltaU = (Math.random()*2-1)/10;
List<GnssCalcData> calcDataList1 = getLastTwo(refDeviceId1,12); List<GnssCalcData> calcDataList1 = getLastTwo(refDeviceId1,12);
if(calcDataList1.size()==2){ if(calcDataList1.size()==2){
// 如果参考点的解算结果不是最新的就不要用否则可能会导致delta值不变
if(calcDataList1.get(0).getCreatetime().isAfter(validTime)){ if(calcDataList1.get(0).getCreatetime().isAfter(validTime)){
deltaU = calcDataList1.get(0).getRposd() - calcDataList1.get(1).getRposd(); deltaU = calcDataList1.get(0).getRposd() - calcDataList1.get(1).getRposd();
} }

View File

@ -140,24 +140,7 @@ public class ApiController {
Device device = localDeviceService.findByDeviceId(deviceId); Device device = localDeviceService.findByDeviceId(deviceId);
if(device!=null){ if(device!=null){
resp.setResponseMessage("set OK."); resp.setResponseMessage("set OK.");
if(paras.length>=3){ resp.setResponseMessage(device.toString());
if(paras[2].equals("type")) {
if (paras[1].equals("channel1")) {
if (device.getDataChannelType()==Device.CHANNEL_TYPE_TCP) {
resp.setResponseMessage(paras[1]+" tcp");
}
else resp.setResponseMessage(paras[1]+" udp");
} else if (paras[1].equals("channel0")) {
if (device.getCfgChannelType()==Device.CHANNEL_TYPE_TCP) {
resp.setResponseMessage(paras[1]+" tcp");
}
else resp.setResponseMessage(paras[1]+" udp");
}
}
}
else{
status.put("paras", "error");
}
} }
else { else {
status.put("status", "Offline"); status.put("status", "Offline");

View File

@ -123,7 +123,9 @@ public class GnssDeviceController extends BasicController{
//所属组织 //所属组织
String tenantname = search.getString("tenantname"); String tenantname = search.getString("tenantname");
if (StringUtils.hasText(tenantname)) { if (StringUtils.hasText(tenantname)) {
queryWrapper.like("tenantname", tenantname); if(tenantname.startsWith("非SAAS"))
queryWrapper.ne("tenantname",Tenant.SAAS_PROVIDER_NAME);
else queryWrapper.like("tenantname", tenantname);
} }
//设备类型 //设备类型
Integer devicetype = search.getInteger("devicetype"); Integer devicetype = search.getInteger("devicetype");

View File

@ -0,0 +1,149 @@
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.service.CommonExcelService;
import com.imdroid.secapi.dto.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
/**
* gnss统计消息 控制器
*
* @author LiGang
* @date 2024/1/6 15:29
*/
@Controller
@RequiredArgsConstructor
public class GnssEhmController extends BasicController implements CommonExcelService<Ehm, EhmJoin> {
final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Autowired
EhmMapper ehmMapper;
final List<String> sortItems = new ArrayList<>();
final List<String> sortSqls = new ArrayList<>();
@RequestMapping("/page/gnss_ehm")
public String gnssTrxMsg(Model m, HttpSession session) {
initModel(m, session);
if(sortItems.size()==0) {
sortItems.add("离线次数");sortSqls.add("order by offlinecount desc");
sortItems.add("离线时长");sortSqls.add("order by offlineminutes desc");
sortItems.add("东标准差");sortSqls.add("order by stdeve desc");
sortItems.add("北标准差");sortSqls.add("order by stdevn desc");
sortItems.add("天标准差");sortSqls.add("order by stdevu desc");
sortItems.add("有效率");sortSqls.add("order by validrate");
sortItems.add("固定率");sortSqls.add("order by fixrate");
sortItems.add("周跳次数");sortSqls.add("order by jumpcount desc");
}
m.addAttribute("sort_items", sortItems);
m.addAttribute("begin_time",LocalDateTime.now().minusDays(1).format(dateFormatter));
return "/page/gnss_ehm";
}
@RequestMapping("/gnss/ehm/list")
@ResponseBody
public JSONObject listTrxMsg(HttpSession session, int page, int limit, String searchParams) {
if(searchParams==null){
searchParams = "{'dgt_t.createtime':'"+ LocalDateTime.now().minusDays(1)+"','_sorttype':'离线次数'}";
}
return this.pageList(session, page, limit, searchParams);
}
@Override
public String getSortSql(JSONObject search){
if(search != null) {
String sortItem = search.getString("_sorttype");
int id = 0;
for(String item:sortItems){
if(item.equals(sortItem)){
return sortSqls.get(id);
}
id++;
}
}
return null;
}
/**
* 导出excel
*
* @param session HttpSession
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws Exception
*/
@RequestMapping("/gnss/ehm/export")
@ResponseBody
public void exportData(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws Exception {
this.export(session, request, response);
}
/**
* 获取实体类的class
*
* @return 实体类的class
*/
@Override
public Class<EhmJoin> getEntityClass() {
return EhmJoin.class;
}
/**
* 获取实体类对应的mybatis mapper
*
* @return 实体类对应的mybatis mapper
*/
@Override
public BaseMapper<Ehm> getMapper() {
return ehmMapper;
}
@Override
public String getOrderByColumn() {
return null;
}
/**
* 获取排序方式默认降序
*
* @return 排序方式
*/
@Override
public String getOrder() {
return null;
}
@Override
public MPJQueryWrapper<Ehm> prepareQueryWrapper() {
return new MPJQueryWrapper<Ehm>()
.selectAll(Ehm.class)
.select("d.devicetype as devicetype,d.model as model")
.leftJoin("gnssdevices d on t.deviceid = d.deviceid");
}
/**
* 是否联表查询
*
* @return 是否联表查询
*/
@Override
public boolean isJoinSelect() {
return true;
}
}

View File

@ -51,6 +51,10 @@ public class WarningController extends BasicController implements CommonExcelSer
warningMap.put(WarningCfg.TYPE_SIM_STATUS_ABNORMAL, WarningCfg.TYPE_NAME_SIM_STATUS_ABNORMAL); warningMap.put(WarningCfg.TYPE_SIM_STATUS_ABNORMAL, WarningCfg.TYPE_NAME_SIM_STATUS_ABNORMAL);
warningMap.put(WarningCfg.TYPE_SIM_LOW_TRAFFIC, WarningCfg.TYPE_NAME_SIM_LOW_TRAFFIC);
warningMap.put(WarningCfg.TYPE_SIM_STATUS_ABNORMAL, WarningCfg.TYPE_NAME_SIM_STATUS_ABNORMAL);
warningMap.put(WarningCfg.TYPE_XY_JUMP, WarningCfg.TYPE_NAME_XY_JUMP);
warningMap.put(WarningCfg.TYPE_Z_JUMP, WarningCfg.TYPE_NAME_Z_JUMP);
} }
/**** 推送页面 *****/ /**** 推送页面 *****/

View File

@ -119,6 +119,13 @@ public interface CommonExcelService<T, R> {
} }
} }
String sortSql = getSortSql(search);
if(sortSql!=null){
queryWrapper.last(sortSql);
//String sql = queryWrapper.getSqlSegment();
//System.out.println(sql);
}
// 查询 // 查询
IPage<R> cs = null; IPage<R> cs = null;
if (isJoinSelect()) { if (isJoinSelect()) {
@ -182,6 +189,7 @@ public interface CommonExcelService<T, R> {
default void checkSearchParams(JSONObject search){} default void checkSearchParams(JSONObject search){}
default void checkSearchParams(Enumeration<String> enu){} default void checkSearchParams(Enumeration<String> enu){}
default String getSortSql(JSONObject search){return null;}
/** /**
* 设置查询条件 * 设置查询条件
@ -195,9 +203,9 @@ public interface CommonExcelService<T, R> {
if (paraName.startsWith("s") && StringUtils.hasText((String)paraValue)) { if (paraName.startsWith("s") && StringUtils.hasText((String)paraValue)) {
addStringQueryWrapper(queryWrapper, paraName, paraValue); addStringQueryWrapper(queryWrapper, paraName, paraValue);
} }
// Number // Number,-1表示全部
else if (paraName.startsWith("n") && StringUtils.hasText((String)paraValue)) { else if (paraName.startsWith("n") && StringUtils.hasText((String)paraValue)) {
addNumberQueryWrapper(queryWrapper, paraName, paraValue); if(!paraValue.equals("-1")) addNumberQueryWrapper(queryWrapper, paraName, paraValue);
} }
// Date & Time // Date & Time
else if (paraName.startsWith("d") && StringUtils.hasText((String)paraValue)) { else if (paraName.startsWith("d") && StringUtils.hasText((String)paraValue)) {

View File

@ -79,6 +79,7 @@ CREATE TABLE IF NOT EXISTS `gnssgroup` (
`active_time` int DEFAULT 6, `active_time` int DEFAULT 6,
`active_offset` int DEFAULT 0, `active_offset` int DEFAULT 0,
`rs_adv` smallint DEFAULT 0, `rs_adv` smallint DEFAULT 0,
`gnss_sample_s` smallint DEFAULT 1,
`power_mode` smallint DEFAULT 0, `power_mode` smallint DEFAULT 0,
`device_num` int DEFAULT 0, `device_num` int DEFAULT 0,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
@ -219,6 +220,7 @@ CREATE TABLE IF NOT EXISTS `gnsstrxmsg` (
`satelliteinuse` int DEFAULT 0, `satelliteinuse` int DEFAULT 0,
`fixnum` int DEFAULT NULL, `fixnum` int DEFAULT NULL,
`floatnum` int DEFAULT NULL, `floatnum` int DEFAULT NULL,
`jumpcount` int DEFAULT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@ -361,4 +363,31 @@ CREATE TABLE IF NOT EXISTS `simcards` (
UNIQUE KEY `uk_msisd` (`msisd`), UNIQUE KEY `uk_msisd` (`msisd`),
INDEX `idx_deviceid` (`deviceid`), INDEX `idx_deviceid` (`deviceid`),
INDEX `idx_status` (`status`) INDEX `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='SIM卡信息表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='SIM卡信息表';
CREATE TABLE IF NOT EXISTS `ehm` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenantid` int DEFAULT 0,
`deviceid` varchar(64) NOT NULL COMMENT '设备ID',
`createtime` datetime(3) NOT NULL COMMENT '创建时间',
`offlinestatdays` smallint DEFAULT NULL COMMENT '离线统计周期',
`offlinecount` int DEFAULT NULL COMMENT '离线统计周期内的离线次数',
`offlineminutes` int DEFAULT NULL COMMENT '离线统计周期内的离线时长',
`calcstathours` int DEFAULT NULL COMMENT '数据分析周期',
`stdeve` float DEFAULT NULL COMMENT '标准差',
`stdevn` float DEFAULT NULL COMMENT '标准差',
`stdevu` float DEFAULT NULL COMMENT '标准差',
`fixrate` float DEFAULT NULL COMMENT '固定率',
`validrate` float DEFAULT NULL COMMENT '有效解比例',
`jumpcount` int DEFAULT NULL COMMENT '周跳次数',
PRIMARY KEY (`id`),
KEY `idx_deviceid_createtime` (`deviceid`,`createtime`),
KEY `idx_createtime` (`createtime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `ehmconfig` (
`updatetime` datetime(3) NOT NULL COMMENT '更新时间',
`offlinestatdays` smallint DEFAULT NULL COMMENT '离线统计周期',
`calcstathours` int DEFAULT NULL COMMENT '数据分析周期',
PRIMARY KEY (`updatetime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -21,6 +21,12 @@
"icon": "fa fa-home", "icon": "fa fa-home",
"target": "_self" "target": "_self"
}, },
{
"title": "健康检查报告",
"href": "page/gnss_ehm",
"icon": "fa fa-tachometer",
"target": "_self"
},
{ {
"title": "运行状态", "title": "运行状态",
"href": "page/gnss_status", "href": "page/gnss_status",

View File

@ -41,6 +41,7 @@
<div class="layui-input-inline"> <div class="layui-input-inline">
<select name="tenantname" id="tenantname" lay-search=""> <select name="tenantname" id="tenantname" lay-search="">
<option value="">全部</option> <option value="">全部</option>
<option value="非SAAS服务商">非SAAS服务商</option>
<option th:each="item : ${tenant_list}" th:text="${item.name}" th:value="${item.name}"></option> <option th:each="item : ${tenant_list}" th:text="${item.name}" th:value="${item.name}"></option>
</select> </select>
</div> </div>
@ -123,7 +124,7 @@
{field: 'project_id', title: '项目号', width: 120, sort: true}, {field: 'project_id', title: '项目号', width: 120, sort: true},
{field: 'sector', title: '桩号', width: 120, sort: true}, {field: 'sector', title: '桩号', width: 120, sort: true},
{field: 'name', title: '监测点号', width: 80}, {field: 'name', title: '监测点号', width: 80},
{field: 'devicetype', title: '类型', width: 80,templet: '#typeTrans'}, {field: 'devicetype', title: '类型', width: 80,templet: "<div>{{d.devicetype==0?'监测站':'基准站'}}</div>"},
{field: 'group_id', title: '基本参数组', width: 60, sort: true}, {field: 'group_id', title: '基本参数组', width: 60, sort: true},
{field: 'calc_group_id', title: '解算参数组', width: 60, sort: true}, {field: 'calc_group_id', title: '解算参数组', width: 60, sort: true},
{field: 'parentid', title: '基站编号', width: 80, sort: true}, {field: 'parentid', title: '基站编号', width: 80, sort: true},
@ -256,14 +257,6 @@
} }
</script> </script>
<script type="text/html" id="typeTrans">
{{# if(d.devicetype == 1){ }}
<span>基准站</span>
{{# } else { }}
<span>监测站</span>
{{# } }}
</script>
<script type="text/html" id="modeTrans"> <script type="text/html" id="modeTrans">
{{# if(d.opmode == 0){ }} {{# if(d.opmode == 0){ }}
<span class="layui-badge layui-bg-green">正常</span> <span class="layui-badge layui-bg-green">正常</span>

View File

@ -0,0 +1,146 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>健康检查报告</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="../lib/layui-v2.6.3/css/layui.css" media="all">
<link rel="stylesheet" href="../css/public.css" media="all">
</head>
<body>
<div class="layuimini-container">
<div class="layuimini-main">
<fieldset class="table-search-fieldset">
<legend>搜索信息</legend>
<div style="margin: 10px 10px 10px 10px">
<form class="layui-form layui-form-pane" action="" id="searchFrm">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">设备号</label>
<div class="layui-input-inline">
<input type="text" name="sl_t.deviceid" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">设备类型</label>
<div class="layui-input-inline">
<select name="n_d.devicetype" id="n_d.devicetype" lay-search="">
<option value="-1">全部</option>
<option value="0">监测站</option>
<option value="1">基准站</option>
</select>
</div>
</div>
<div class="layui-inline" >
<label class="layui-form-label">TopN排序</label>
<div class="layui-input-inline">
<select name="_sorttype" id="_sorttype" lay-search="">
<option th:each="item : ${sort_items}" th:text="${item}" th:value="${item}"></option>
</select>
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">范围</label>
<div class="layui-input-inline">
<input type="text" name="dgt_t.createtime" autocomplete="off" id="ID-laydate-start-date" class="layui-input" placeholder="开始日期" th:value="${begin_time}">
</div>
<div class="layui-input-inline">
<input type="text" name="dlt_t.createtime" autocomplete="off" id="ID-laydate-end-date" class="layui-input" placeholder="结束日期">
</div>
</div>
<div class="layui-inline">
<button type="submit" class="layui-btn layui-btn-primary" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜 索</button>
<button type="submit" class="layui-btn layui-btn-primary" lay-submit lay-filter="data-export-btn"><i class="layui-icon">&#xe67d;</i>导出</button>
</div>
</div>
</form>
</div>
</fieldset>
<table class="layui-hide" id="currentTableId" lay-filter="currentTableFilter"></table>
</div>
</div>
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script th:inline="javascript">
layui.use(['form', 'table', 'laydate'], function () {
var $ = layui.$;
var form = layui.form,
table = layui.table,
laydate = layui.laydate;
var cfg_cols = [
{field: 'deviceid', title: '设备号', width: 100},
{field: 'devicetype', title: '类型', width: 80,templet: "<div>{{d.devicetype==0?'监测站':'基准站'}}</div>"},
{field: 'model', title: '型号', width: 80,templet: "<div>{{d.model==0?'G505':'G510'}}</div>"},
{field: 'createtime', title: '创建时间', templet: "<div>{{layui.util.toDateString(d.createtime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
{field: 'offlinestatdays', title: '离线统计周期(天)'},
{field: 'calcstathours', title: '数据分析周期(小时)'},
{field: 'offlinecount', title: '离线次数'},
{field: 'offlineminutes', title: '离线分钟数'},
{field: 'stdeve', title: '东标准差'},
{field: 'stdevn', title: '北标准差'},
{field: 'stdevu', title: '天标准差'},
{field: 'fixrate', title: '固定率%'},
{field: 'validrate', title: '有效率%'},
{field: 'jumpcount', title: '周跳次数'}
];
/**
* 初始化表单,要加上,不然刷新部分组件可能会不加载
*/
form.render();
laydate.render({
elem: '#ID-laydate-start-date',
type: 'datetime'
});
laydate.render({
elem: '#ID-laydate-end-date',
type: 'datetime'
});
table.render({
elem: '#currentTableId',
url: '/gnss/ehm/list',
toolbar: '#toolbarDemo',//开启头部工具栏
defaultToolbar: ['filter'],
cols: [
cfg_cols
],
limits: [50, 100, 200, 300],
limit: 50,
page: true,
skin: 'line'
});
// 监听搜索操作
form.on('submit(data-search-btn)', function (data) {
var result = JSON.stringify(data.field);
//执行搜索重载
table.reload('currentTableId', {
page: {
curr: 1
}
, where: {
searchParams: result
}
}, 'data');
return false;
});
// 监听导出操作
form.on('submit(data-export-btn)', function (data) {
var result = $('#searchFrm').serialize();
var u = "/gnss/ehm/export?" + result;
window.open(u, "_blank");
return false;
});
});
</script>
</body>
</html>

View File

@ -54,6 +54,7 @@
{field: 'active_time', title: '激活时长(分钟)'}, {field: 'active_time', title: '激活时长(分钟)'},
{field: 'active_offset', title: '偏置(分钟)'}, {field: 'active_offset', title: '偏置(分钟)'},
{field: 'rs_adv', title: '基准站提前时间(分钟)'}, {field: 'rs_adv', title: '基准站提前时间(分钟)'},
{field: 'gnss_sample_s', title: 'GNSS上报'},
{field: 'power_mode', title: '功耗模式',templet: "<div>{{d.power_mode==0?'低功耗':'普通'}}</div>"}, {field: 'power_mode', title: '功耗模式',templet: "<div>{{d.power_mode==0?'低功耗':'普通'}}</div>"},
{field: 'device_num', title: '关联设备数'}, {field: 'device_num', title: '关联设备数'},
{title: '操作', toolbar: '#currentTableBar', align: "center"} {title: '操作', toolbar: '#currentTableBar', align: "center"}

View File

@ -47,6 +47,12 @@
<input type="number" name="active_offset" id="active_offset" placeholder="请输入配置" value="0" class="layui-input"> <input type="number" name="active_offset" id="active_offset" placeholder="请输入配置" value="0" class="layui-input">
</div> </div>
</div> </div>
<div class="layui-form-item">
<label class="layui-form-label">GNSS上报(秒)</label>
<div class="layui-input-block">
<input type="number" name="gnss_sample_s" id="gnss_sample_s" placeholder="请输入配置" value="0" class="layui-input">
</div>
</div>
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">基准站提前时间(分钟)</label> <label class="layui-form-label">基准站提前时间(分钟)</label>
<div class="layui-input-block"> <div class="layui-input-block">
@ -111,6 +117,7 @@
$('#rs_adv').val(data.rs_adv); $('#rs_adv').val(data.rs_adv);
$('#power_mode').val(data.power_mode); $('#power_mode').val(data.power_mode);
$('#name').val(data.name); $('#name').val(data.name);
$('#gnss_sample_s').val(data.gnss_sample_s);
form.render(); form.render();
} }
</script> </script>

View File

@ -34,6 +34,12 @@
</select> </select>
</div> </div>
</div> </div>
<div class="layui-inline">
<label class="layui-form-label">告警类型</label>
<div class="layui-input-inline">
<input type="text" name="n_code" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline"> <div class="layui-inline">
<label class="layui-form-label">范围</label> <label class="layui-form-label">范围</label>
<div class="layui-input-inline"> <div class="layui-input-inline">