Compare commits
86 Commits
develop
...
feature/rt
| Author | SHA1 | Date | |
|---|---|---|---|
| cc399deacc | |||
| 0ef993f9f9 | |||
| f75bafcc75 | |||
| dcfa0881f3 | |||
| bde6d798c5 | |||
| 6a9bcca4db | |||
| 3522e16070 | |||
| fb095ad52c | |||
| 499cbd663b | |||
| c72544cfd3 | |||
| f3aaea78a3 | |||
| a28251d787 | |||
| c252b11d3c | |||
| 2a9ab127c5 | |||
| 76831fb185 | |||
| 0b7789838b | |||
| e07250637e | |||
| ee77c07bc2 | |||
| d2c85d6d3b | |||
| 9e110d1218 | |||
| 11ef555eea | |||
| 69b1ccdfee | |||
| ec7f1b8ea9 | |||
| efa2cacd3b | |||
| bf9efff854 | |||
| 8bc91b3bac | |||
|
|
7b63f24af5 | ||
|
|
bd52c6df20 | ||
|
|
2f45c45ca7 | ||
|
|
d05e2c7adf | ||
|
|
7afdaa29dd | ||
|
|
4e50e98a3f | ||
|
|
440044c0ab | ||
|
|
d7067dbe88 | ||
|
|
2f8e8bb446 | ||
|
|
952b5dec28 | ||
|
|
256eaa351b | ||
|
|
d01764a1b6 | ||
|
|
4942c23200 | ||
|
|
bc1e20c287 | ||
|
|
8146ff1879 | ||
|
|
6f01e78368 | ||
| a5d76073f6 | |||
|
|
00fa3171ab | ||
|
|
209c992734 | ||
|
|
e14d2882fc | ||
|
|
4aec3ec815 | ||
|
|
74f50e47ba | ||
|
|
9103284ee4 | ||
|
|
f756e347aa | ||
|
|
0f6af2c170 | ||
|
|
b9c36bedac | ||
|
|
e852b7c640 | ||
|
|
15b4cbbe3e | ||
|
|
032ab5c46b | ||
| 1875b5e848 | |||
| 897507b97b | |||
|
|
40cee949a9 | ||
|
|
f68d548a2c | ||
|
|
2fd12b9361 | ||
|
|
e286c355ff | ||
|
|
cc5f3d0772 | ||
|
|
1e9e4b8680 | ||
|
|
6d0aa977fa | ||
|
|
1045e33d1a | ||
|
|
6d170eaed0 | ||
|
|
bedb2e3ef5 | ||
|
|
0acd7d31b8 | ||
|
|
063716d539 | ||
|
|
1996ef79d4 | ||
|
|
87d6f6073d | ||
|
|
cef333b56b | ||
|
|
21a6d2a8df | ||
|
|
db9d27b3a0 | ||
|
|
d250bfc671 | ||
| 7555c4c72b | |||
| d8456d165b | |||
|
|
983efb2d6b | ||
| 1191c17c35 | |||
|
|
f9b85cd2d5 | ||
|
|
a6f711f18d | ||
|
|
e6ad5a0a3d | ||
|
|
ae28807818 | ||
|
|
29af023a4f | ||
|
|
ee5bae1174 | ||
|
|
893fe1ea78 |
@ -64,6 +64,8 @@ public class GnssDevice {
|
|||||||
private Double iposn; //初始位置
|
private Double iposn; //初始位置
|
||||||
private Double iposd; //初始位置
|
private Double iposd; //初始位置
|
||||||
|
|
||||||
|
private Boolean forward_to_ntrip; // 是否转发至NtripCaster,默认false
|
||||||
|
|
||||||
private Double ecefx;
|
private Double ecefx;
|
||||||
private Double ecefy;
|
private Double ecefy;
|
||||||
private Double ecefz;
|
private Double ecefz;
|
||||||
|
|||||||
@ -47,4 +47,7 @@ public class GnssDeviceJoin {
|
|||||||
|
|
||||||
Double latitude;
|
Double latitude;
|
||||||
Double longitude;
|
Double longitude;
|
||||||
|
Double roll;
|
||||||
|
Double pitch;
|
||||||
|
Double yaw;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,8 @@ public class OpLogManager {
|
|||||||
public final static Short OP_OBJ_GROUP = 6;
|
public final static Short OP_OBJ_GROUP = 6;
|
||||||
public final static Short OP_OBJ_WARNING = 7;
|
public final static Short OP_OBJ_WARNING = 7;
|
||||||
public final static Short OP_OBJ_SYS = 8;
|
public final static Short OP_OBJ_SYS = 8;
|
||||||
public final static Short OP_OBJ_DEVICE_MSG = 9;
|
public final static Short OP_OBJ_FWD_RECORD = 9;
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
OpLogMapper opLogMapper;
|
OpLogMapper opLogMapper;
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
package com.imdroid.secapi.dto;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("rtkrcv_profile")
|
||||||
|
public class RtkrcvProfile {
|
||||||
|
|
||||||
|
@TableId(value = "device_id", type = IdType.INPUT)
|
||||||
|
private String deviceId;
|
||||||
|
@TableField("inpstr1_path")
|
||||||
|
private String inpstr1Path;
|
||||||
|
@TableField("inpstr2_path")
|
||||||
|
private String inpstr2Path;
|
||||||
|
@TableField("inpstr3_path")
|
||||||
|
private String inpstr3Path;
|
||||||
|
@TableField("outstr1_path")
|
||||||
|
private String outstr1Path;
|
||||||
|
@TableField("out_height")
|
||||||
|
private Integer outHeight;
|
||||||
|
@TableField("updated_at")
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.imdroid.secapi.dto;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface RtkrcvProfileMapper extends BaseMapper<RtkrcvProfile> {
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package com.imdroid.secapi.dto;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("rtkrcv_session")
|
||||||
|
public class RtkrcvSession {
|
||||||
|
|
||||||
|
@TableId(value = "session_id", type = IdType.AUTO)
|
||||||
|
private Long sessionId;
|
||||||
|
|
||||||
|
@TableField("device_id")
|
||||||
|
private String deviceId;
|
||||||
|
|
||||||
|
@TableField("state")
|
||||||
|
private String state;
|
||||||
|
|
||||||
|
@TableField("rtk_conf_path")
|
||||||
|
private String rtkConfPath;
|
||||||
|
|
||||||
|
@TableField("work_dir")
|
||||||
|
private String workDir;
|
||||||
|
@TableField("work_port")
|
||||||
|
private Integer workPort;
|
||||||
|
|
||||||
|
@TableField("pid")
|
||||||
|
private Integer pid;
|
||||||
|
|
||||||
|
@TableField("start_time")
|
||||||
|
private LocalDateTime startTime;
|
||||||
|
|
||||||
|
@TableField("end_time")
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
|
@TableField("heartbeat_at")
|
||||||
|
private LocalDateTime heartbeatAt;
|
||||||
|
|
||||||
|
@TableField("error_message")
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
@TableField("created_at")
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@TableField("updated_at")
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.imdroid.secapi.dto;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface RtkrcvSessionMapper extends BaseMapper<RtkrcvSession> {
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package com.imdroid.secapi.dto;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("rtkrcv_solution")
|
||||||
|
public class RtkrcvSolution {
|
||||||
|
|
||||||
|
@TableId(value = "solution_id", type = IdType.AUTO)
|
||||||
|
private Long solutionId;
|
||||||
|
|
||||||
|
@TableField("device_id")
|
||||||
|
private String deviceId;
|
||||||
|
|
||||||
|
@TableField("lat")
|
||||||
|
private Double lat;
|
||||||
|
|
||||||
|
@TableField("lon")
|
||||||
|
private Double lon;
|
||||||
|
|
||||||
|
@TableField("height")
|
||||||
|
private Double height;
|
||||||
|
|
||||||
|
@TableField("ecef_x")
|
||||||
|
private Double ecefX;
|
||||||
|
|
||||||
|
@TableField("ecef_y")
|
||||||
|
private Double ecefY;
|
||||||
|
|
||||||
|
@TableField("ecef_z")
|
||||||
|
private Double ecefZ;
|
||||||
|
|
||||||
|
@TableField("quality")
|
||||||
|
private String quality;
|
||||||
|
|
||||||
|
@TableField("duration_s")
|
||||||
|
private Integer durationSeconds;
|
||||||
|
|
||||||
|
@TableField("obs_count")
|
||||||
|
private Integer obsCount;
|
||||||
|
|
||||||
|
@TableField("created_at")
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.imdroid.secapi.dto;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface RtkrcvSolutionMapper extends BaseMapper<RtkrcvSolution> {
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
package com.imdroid.secapi.dto;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnore;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
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 = "surface_incline_data")
|
||||||
|
public class SurfaceInclineData {
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
@ExcelIgnore
|
||||||
|
Long id;
|
||||||
|
|
||||||
|
@ExcelProperty("租户id")
|
||||||
|
Integer tenantid;
|
||||||
|
|
||||||
|
@ExcelProperty("上报时间")
|
||||||
|
LocalDateTime createtime;
|
||||||
|
|
||||||
|
@ExcelProperty("设备编号")
|
||||||
|
String deviceid;
|
||||||
|
|
||||||
|
@ExcelProperty("传感器号")
|
||||||
|
Short sensorid;
|
||||||
|
|
||||||
|
@ExcelProperty("倾角X")
|
||||||
|
Float anglex;
|
||||||
|
|
||||||
|
@ExcelProperty("倾角Y")
|
||||||
|
Float angley;
|
||||||
|
|
||||||
|
@ExcelProperty("倾角Z")
|
||||||
|
Float anglez;
|
||||||
|
|
||||||
|
@ExcelProperty("加速度X")
|
||||||
|
Float accx;
|
||||||
|
|
||||||
|
@ExcelProperty("加速度Y")
|
||||||
|
Float accy;
|
||||||
|
|
||||||
|
@ExcelProperty("加速度Z")
|
||||||
|
Float accz;
|
||||||
|
|
||||||
|
@ExcelProperty("MaxX")
|
||||||
|
Float maxaccx;
|
||||||
|
|
||||||
|
@ExcelProperty("MaxY")
|
||||||
|
Float maxaccy;
|
||||||
|
|
||||||
|
@ExcelProperty("MaxZ")
|
||||||
|
Float maxaccz;
|
||||||
|
|
||||||
|
@ExcelProperty("MinX")
|
||||||
|
Float minaccx;
|
||||||
|
|
||||||
|
@ExcelProperty("MinY")
|
||||||
|
Float minaccy;
|
||||||
|
|
||||||
|
@ExcelProperty("MinZ")
|
||||||
|
Float minaccz;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.imdroid.secapi.dto;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface SurfaceInclineDataMapper extends BaseMapper<SurfaceInclineData> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
package com.imdroid.beidou_fwd.service;
|
package com.imdroid.beidou_fwd.service;
|
||||||
|
|
||||||
import com.imdroid.common.util.ThreadManager;
|
|
||||||
import io.netty.bootstrap.Bootstrap;
|
import io.netty.bootstrap.Bootstrap;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
@ -13,7 +12,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class TCPClient {
|
public class TCPClient {
|
||||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
@ -29,7 +27,7 @@ public class TCPClient {
|
|||||||
TCPListener listener;
|
TCPListener listener;
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
new Thread(this::connect, "forwarder tcp-client").start();
|
//new Thread(this::connect, host+":"+port+" forwarder tcp-client").start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(String dest_addr, int dest_port, TCPListener listener) {
|
public void init(String dest_addr, int dest_port, TCPListener listener) {
|
||||||
@ -54,7 +52,7 @@ public class TCPClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void connect() {
|
public void connect() {
|
||||||
logger.info("netty client starting");
|
logger.info("{}:{} tcp connecting...",host,port);
|
||||||
//启动客户端去连接服务器端
|
//启动客户端去连接服务器端
|
||||||
try {
|
try {
|
||||||
ChannelFuture cf = bootstrap.connect(host, port);
|
ChannelFuture cf = bootstrap.connect(host, port);
|
||||||
@ -62,17 +60,22 @@ public class TCPClient {
|
|||||||
@Override
|
@Override
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
public void operationComplete(ChannelFuture future) throws Exception {
|
||||||
if (!future.isSuccess()) {
|
if (!future.isSuccess()) {
|
||||||
|
logger.info("{}:{} tcp connect failed. {}",host,port,future.cause().toString());
|
||||||
//重连交给后端线程执行
|
//重连交给后端线程执行
|
||||||
future.channel().eventLoop().schedule(() -> {
|
/*future.channel().eventLoop().schedule(() -> {
|
||||||
logger.info("tcp client reconnect");
|
logger.info("{}:{} tcp client reconnect",host,port);
|
||||||
try {
|
try {
|
||||||
connect();
|
connect();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}, 5000, TimeUnit.MILLISECONDS);
|
}, 5000, TimeUnit.MILLISECONDS);*/
|
||||||
} else {
|
} else {
|
||||||
logger.info("tcp client start success!");
|
/*future.channel().config().setWriteBufferWaterMark(new WriteBufferWaterMark(
|
||||||
|
1024 * 1024, // low
|
||||||
|
4 *1024*1024 // high
|
||||||
|
));*/
|
||||||
|
logger.info("{}:{} tcp client start success!",host,port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -80,18 +83,35 @@ public class TCPClient {
|
|||||||
this.channel = cf.channel();
|
this.channel = cf.channel();
|
||||||
this.channel.closeFuture().sync();
|
this.channel.closeFuture().sync();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("netty client error:", e);
|
logger.error(host+":"+port+" tcp connect error:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean tryReconnect() throws Exception{
|
||||||
|
new Thread(this::connect, host+":"+port+" forwarder tcp-client").start();
|
||||||
|
for(int i=0; i<20; i++){
|
||||||
|
Thread.sleep(50);
|
||||||
|
if(channel!=null && channel.isActive()) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void writeAndFlush(String json) {
|
public void writeAndFlush(String json) {
|
||||||
ByteBuf sendBuffer = Unpooled.buffer();
|
ByteBuf sendBuffer = Unpooled.buffer();
|
||||||
sendBuffer.writeBytes(json.getBytes(StandardCharsets.UTF_8));
|
sendBuffer.writeBytes(json.getBytes(StandardCharsets.UTF_8));
|
||||||
|
//logger.info("send to {}: {}",host,json);
|
||||||
|
if(channel==null || !channel.isActive()){
|
||||||
|
try {
|
||||||
|
if(!tryReconnect()) return;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
channel.writeAndFlush(sendBuffer).addListener(future -> {
|
channel.writeAndFlush(sendBuffer).addListener(future -> {
|
||||||
if (future.isSuccess()) {
|
if (future.isSuccess()) {
|
||||||
logger.info("send to tcp:"+host+" succeed.");
|
logger.info("send to tcp:"+host+" succeed.");
|
||||||
} else {
|
} else {
|
||||||
logger.info("send to tcp:"+host+" failed.");
|
logger.info("send to tcp: {} failed. {}",host,future.cause().toString());
|
||||||
if(listener!=null){
|
if(listener!=null){
|
||||||
listener.onMessage("failed");
|
listener.onMessage("failed");
|
||||||
}
|
}
|
||||||
@ -103,8 +123,8 @@ public class TCPClient {
|
|||||||
connectTime = LocalDateTime.now();
|
connectTime = LocalDateTime.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDisconnect(){
|
public void onDisconnect(boolean isIdle){
|
||||||
if(connectTime.isBefore(LocalDateTime.now().minusMinutes(1))) {
|
/*if(connectTime.isBefore(LocalDateTime.now().minusMinutes(1))) {
|
||||||
connect();
|
connect();
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@ -114,8 +134,8 @@ public class TCPClient {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error(e.toString());
|
logger.error(e.toString());
|
||||||
}
|
}
|
||||||
},60, TimeUnit.SECONDS);
|
},isIdle?30:10, TimeUnit.SECONDS);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onMessage(String msg){
|
public void onMessage(String msg){
|
||||||
|
|||||||
@ -40,13 +40,14 @@ public class TcpMessageHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
|||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
logger.info("tcp channel inactive");
|
logger.info("tcp channel inactive");
|
||||||
tcpClient.onDisconnect();
|
tcpClient.onDisconnect(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
logger.error("TcpMessageHandler error: {}", cause.toString());
|
logger.error("TcpMessageHandler error: {}", cause.toString());
|
||||||
ctx.close();
|
ctx.close();
|
||||||
|
tcpClient.onDisconnect(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,17 +37,17 @@ public class Forwarder {
|
|||||||
static boolean isFwdTableInit = true;//false;
|
static boolean isFwdTableInit = true;//false;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private GnssDeviceMapper deviceMapper;
|
GnssDeviceMapper deviceMapper;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private GnssCalcDataMapper gnssDataMapper;
|
GnssCalcDataMapper gnssDataMapper;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private FwdRecordMapper fwdRecordsMapper;
|
FwdRecordMapper fwdRecordsMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ResendRecordMapper resendRecordMapper;
|
ResendRecordMapper resendRecordMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private GnssStatusMapper gnssStatusMapper;
|
GnssStatusMapper gnssStatusMapper;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
GnssGroupFwdMapper fwdMapper;
|
GnssGroupFwdMapper fwdMapper;
|
||||||
@ -112,22 +112,28 @@ public class Forwarder {
|
|||||||
List<GnssDeviceJoin> gnssDeviceList;
|
List<GnssDeviceJoin> gnssDeviceList;
|
||||||
MPJQueryWrapper jquery = null;
|
MPJQueryWrapper jquery = null;
|
||||||
|
|
||||||
if(resendRecord!=null && resendRecord.getDeviceid()!=null){
|
if(resendRecord!=null && StringUtils.hasText(resendRecord.getDeviceid())){
|
||||||
jquery = new MPJQueryWrapper<GnssDevice> ()
|
jquery = new MPJQueryWrapper<GnssDevice> ()
|
||||||
.selectAll(GnssDevice.class)
|
.selectAll(GnssDevice.class)
|
||||||
.select("d.latitude as latitude")
|
.select("d.latitude as latitude")
|
||||||
.select("d.longitude as longitude")
|
.select("d.longitude as longitude")
|
||||||
|
.select("d.roll as roll")
|
||||||
|
.select("d.pitch as pitch")
|
||||||
|
.select("d.yaw as yaw")
|
||||||
.leftJoin("gnssstatus d on t.deviceid = d.deviceid")
|
.leftJoin("gnssstatus d on t.deviceid = d.deviceid")
|
||||||
.and(warpper->warpper.eq("fwd_group_id", fwdGroupId)
|
.and(warpper->warpper.eq("fwd_group_id", fwdGroupId)
|
||||||
.or()
|
.or()
|
||||||
.eq("fwd_group_id2", fwdGroupId)).
|
.eq("fwd_group_id2", fwdGroupId)).
|
||||||
eq("deviceid", resendRecord.getDeviceid());
|
eq("t.deviceid", resendRecord.getDeviceid());
|
||||||
}
|
}
|
||||||
else if(resendRecord!=null && resendRecord.getProjectid()!=null){
|
else if(resendRecord!=null && resendRecord.getProjectid()!=null){
|
||||||
jquery = new MPJQueryWrapper<GnssDevice> ()
|
jquery = new MPJQueryWrapper<GnssDevice> ()
|
||||||
.selectAll(GnssDevice.class)
|
.selectAll(GnssDevice.class)
|
||||||
.select("d.latitude as latitude")
|
.select("d.latitude as latitude")
|
||||||
.select("d.longitude as longitude")
|
.select("d.longitude as longitude")
|
||||||
|
.select("d.roll as roll")
|
||||||
|
.select("d.pitch as pitch")
|
||||||
|
.select("d.yaw as yaw")
|
||||||
.leftJoin("gnssstatus d on t.deviceid = d.deviceid")
|
.leftJoin("gnssstatus d on t.deviceid = d.deviceid")
|
||||||
.and(warpper->warpper.eq("fwd_group_id", fwdGroupId)
|
.and(warpper->warpper.eq("fwd_group_id", fwdGroupId)
|
||||||
.or()
|
.or()
|
||||||
@ -141,6 +147,9 @@ public class Forwarder {
|
|||||||
.selectAll(GnssDevice.class)
|
.selectAll(GnssDevice.class)
|
||||||
.select("d.latitude as latitude")
|
.select("d.latitude as latitude")
|
||||||
.select("d.longitude as longitude")
|
.select("d.longitude as longitude")
|
||||||
|
.select("d.roll as roll")
|
||||||
|
.select("d.pitch as pitch")
|
||||||
|
.select("d.yaw as yaw")
|
||||||
.leftJoin("gnssstatus d on t.deviceid = d.deviceid")
|
.leftJoin("gnssstatus d on t.deviceid = d.deviceid")
|
||||||
.and(warpper->warpper.eq("fwd_group_id", fwdGroupId)
|
.and(warpper->warpper.eq("fwd_group_id", fwdGroupId)
|
||||||
.or()
|
.or()
|
||||||
@ -214,7 +223,11 @@ public class Forwarder {
|
|||||||
// 用r9250来传设备经纬度
|
// 用r9250来传设备经纬度
|
||||||
record.setR9250e(device.getLongitude());
|
record.setR9250e(device.getLongitude());
|
||||||
record.setR9250n(device.getLatitude());
|
record.setR9250n(device.getLatitude());
|
||||||
// 用aux来传基站经纬度
|
// 用aux来传xyz
|
||||||
|
record.setAuxe(device.getRoll());
|
||||||
|
record.setAuxn(device.getPitch());
|
||||||
|
record.setAuxd(device.getYaw());
|
||||||
|
|
||||||
recordsToSend.add(record);
|
recordsToSend.add(record);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,7 @@ public class GXJKForwarder extends Forwarder {
|
|||||||
/**
|
/**
|
||||||
* 每半小时转发GNSS解算结果
|
* 每半小时转发GNSS解算结果
|
||||||
*/
|
*/
|
||||||
@Scheduled(cron = "0 0/10 * * * ?") // 每30分钟执行一次
|
@Scheduled(cron = "0 0/30 * * * ?") // 每30分钟执行一次
|
||||||
private void forwardGnss() {
|
private void forwardGnss() {
|
||||||
logger.debug("gxjk forwardGnss");
|
logger.debug("gxjk forwardGnss");
|
||||||
if(mqttClient.isConnected()) forwardCurrentGnss();
|
if(mqttClient.isConnected()) forwardCurrentGnss();
|
||||||
|
|||||||
@ -0,0 +1,161 @@
|
|||||||
|
package com.imdroid.beidou_fwd.task;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
|
import com.imdroid.beidou_fwd.entity.XFZData;
|
||||||
|
import com.imdroid.beidou_fwd.service.TCPClient;
|
||||||
|
import com.imdroid.common.util.GsonUtil;
|
||||||
|
import com.imdroid.common.util.NumberUtils;
|
||||||
|
import com.imdroid.secapi.dto.GnssCalcData;
|
||||||
|
import com.imdroid.secapi.dto.ResendRecord;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
|
public class GXJS10mForwarder extends GXXfzForwarder{
|
||||||
|
private final String FORWARDER_NAME = "广西新发展10分钟推送";
|
||||||
|
@Value("${xfz.server.host}")
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@Value("${xfz.server.port}")
|
||||||
|
private int port;
|
||||||
|
private boolean enabled=true;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
void registerMe(){
|
||||||
|
init(FORWARDER_NAME, "TCP "+host+":"+port,1,FWD_DEVICE_ID,10);
|
||||||
|
xfzTcpClient = new TCPClient();
|
||||||
|
xfzTcpClient.init(host, port,listener);
|
||||||
|
if(!enabled) return;
|
||||||
|
|
||||||
|
xfzTcpClient.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每半小时转发GNSS解算结果
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0/10 * * * ?") // 每10分钟执行一次
|
||||||
|
private void forwardGnss() {
|
||||||
|
if(!enabled) return;
|
||||||
|
logger.debug("gxjs forwardGnss");
|
||||||
|
forwardCurrentGnss();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int send(String projectId, List<GnssCalcData> records, LocalDateTime sentTime){
|
||||||
|
int batchNum = 0;
|
||||||
|
int sendNum = 0;
|
||||||
|
if(records.size() == 0) return 0;
|
||||||
|
|
||||||
|
XFZData xfzTcpMessage = new XFZData();
|
||||||
|
xfzTcpMessage.setProjectID(projectId);
|
||||||
|
xfzTcpMessage.setWorkPointID(projectId);
|
||||||
|
|
||||||
|
List<XFZData.Data> dataList = new ArrayList<>(records.size());
|
||||||
|
xfzTcpMessage.setData(dataList);
|
||||||
|
|
||||||
|
for(GnssCalcData locationRecord: records) {
|
||||||
|
XFZData.Data data = new XFZData.Data();
|
||||||
|
dataList.add(data);
|
||||||
|
data.setDataTime(locationRecord.getCreatetime().format(formatter));
|
||||||
|
data.setDevNum(locationRecord.getDeviceid());
|
||||||
|
data.setDevtype("GNSS");
|
||||||
|
// 单位由mm转化为m
|
||||||
|
data.setX(NumberUtils.scale(locationRecord.getRpose() * 0.001, 5));
|
||||||
|
data.setY(NumberUtils.scale(locationRecord.getRposn() * 0.001, 5));
|
||||||
|
data.setZ(NumberUtils.scale(locationRecord.getRposd() * 0.001, 5));
|
||||||
|
// 经纬度
|
||||||
|
data.setDevLng(locationRecord.getR9250e());
|
||||||
|
data.setDevLat(locationRecord.getR9250n());
|
||||||
|
|
||||||
|
if(projectId!=null && projectId.equals("20257071")) {
|
||||||
|
//倾角
|
||||||
|
XFZData.Data data2 = new XFZData.Data();
|
||||||
|
dataList.add(data2);
|
||||||
|
data2.setDataTime(locationRecord.getCreatetime().format(formatter));
|
||||||
|
data2.setDevNum(locationRecord.getDeviceid() + "_qj");
|
||||||
|
data2.setDevtype("InclinoMeter");
|
||||||
|
// 角度
|
||||||
|
data2.setX(NumberUtils.scale(locationRecord.getAuxe(), 3));
|
||||||
|
data2.setY(NumberUtils.scale(locationRecord.getAuxn(), 3));
|
||||||
|
data2.setZ(NumberUtils.scale(locationRecord.getAuxd(), 3));
|
||||||
|
// 经纬度
|
||||||
|
data2.setDevLng(locationRecord.getR9250e());
|
||||||
|
data2.setDevLat(locationRecord.getR9250n());
|
||||||
|
}
|
||||||
|
// 发送
|
||||||
|
batchNum++;
|
||||||
|
|
||||||
|
if(batchNum==20){
|
||||||
|
String json = "#" + GsonUtil.toJson(xfzTcpMessage) + "!";
|
||||||
|
//logger.debug("project {}: forwad {} gnss records to {}",projectId, dataList.size(),fwdGroupId);
|
||||||
|
//logger.debug(json);
|
||||||
|
try {
|
||||||
|
listener.clear();
|
||||||
|
xfzTcpClient.writeAndFlush(json);
|
||||||
|
//等待应答
|
||||||
|
if(checkResult()) sendNum += batchNum;
|
||||||
|
} catch (Exception e1) {
|
||||||
|
logger.error(e1.toString());
|
||||||
|
}
|
||||||
|
batchNum = 0;
|
||||||
|
dataList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(batchNum>0){
|
||||||
|
String json = "#" + GsonUtil.toJson(xfzTcpMessage) + "!";
|
||||||
|
logger.debug("project {}: forwad {} gnss records to {}",projectId, dataList.size(),fwdGroupId);
|
||||||
|
logger.debug(json);
|
||||||
|
try {
|
||||||
|
listener.clear();
|
||||||
|
xfzTcpClient.writeAndFlush(json);
|
||||||
|
//等待应答
|
||||||
|
if(checkResult()) sendNum += batchNum;
|
||||||
|
} catch (Exception e1) {
|
||||||
|
logger.error(e1.toString());
|
||||||
|
}
|
||||||
|
dataList.clear();
|
||||||
|
}
|
||||||
|
return sendNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void forwardHistoryGnss(){
|
||||||
|
// 1.从转发记录表里检索待补传记录时间表,含设备Id,时间段
|
||||||
|
QueryWrapper<ResendRecord> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("fwd_group_id",fwdGroupId);
|
||||||
|
queryWrapper.eq("state",ResendRecord.STATE_BREAK_POINT);
|
||||||
|
queryWrapper.ge("createtime", LocalDateTime.now().minusDays(30));
|
||||||
|
List<ResendRecord> resendRecordsList = resendRecordMapper.selectList(queryWrapper);
|
||||||
|
|
||||||
|
if(resendRecordsList!=null && resendRecordsList.size()>0){
|
||||||
|
//修改状态
|
||||||
|
UpdateWrapper<ResendRecord> updateWrapper = new UpdateWrapper<>();
|
||||||
|
updateWrapper.eq("fwd_group_id",fwdGroupId);
|
||||||
|
updateWrapper.eq("state",ResendRecord.STATE_BREAK_POINT);
|
||||||
|
updateWrapper.ge("createtime", LocalDateTime.now().minusDays(30));
|
||||||
|
updateWrapper.set("state",ResendRecord.STATE_FWDING);
|
||||||
|
int updateNum = resendRecordMapper.update(null, updateWrapper);
|
||||||
|
logger.debug("{} forward history records: {}, update {}",fwdGroupId, resendRecordsList.size(),updateNum);
|
||||||
|
// 2.检索这个这个时间段的解算结果,如果有数据则单个终端转发,标志记录为已补传
|
||||||
|
for(ResendRecord record:resendRecordsList){
|
||||||
|
if(record.getProjectid()!=null)
|
||||||
|
logger.debug("{} forward history {}",fwdGroupId, record.getProjectid());
|
||||||
|
forwardBatchGnssRecords(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,170 @@
|
|||||||
|
package com.imdroid.beidou_fwd.task;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
|
import com.imdroid.beidou_fwd.entity.XFZData;
|
||||||
|
import com.imdroid.beidou_fwd.service.TCPClient;
|
||||||
|
import com.imdroid.common.util.GsonUtil;
|
||||||
|
import com.imdroid.common.util.NumberUtils;
|
||||||
|
import com.imdroid.secapi.dto.GnssCalcData;
|
||||||
|
import com.imdroid.secapi.dto.ResendRecord;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
|
public class GXJSForwarder extends GXXfzForwarder{
|
||||||
|
private final String FORWARDER_NAME = "广西新发展";
|
||||||
|
private final String inclineProjects = "20257071,20251131";
|
||||||
|
private HashSet<String> inclineProjectSet = new HashSet<>();
|
||||||
|
@Value("${xfz.server.host}")
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@Value("${xfz.server.port}")
|
||||||
|
private int port;
|
||||||
|
private boolean enabled=true;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
void registerMe(){
|
||||||
|
init(FORWARDER_NAME, "TCP "+host+":"+port,1,FWD_DEVICE_ID,30);
|
||||||
|
xfzTcpClient = new TCPClient();
|
||||||
|
xfzTcpClient.init(host, port,listener);
|
||||||
|
if(!enabled) return;
|
||||||
|
|
||||||
|
xfzTcpClient.start();
|
||||||
|
|
||||||
|
// incline devices
|
||||||
|
String[] inclineDeviceList = inclineProjects.split(",");
|
||||||
|
for(String s:inclineDeviceList){
|
||||||
|
inclineProjectSet.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每半小时转发GNSS解算结果
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0/30 * * * ?") // 每30分钟执行一次
|
||||||
|
private void forwardGnss() {
|
||||||
|
if(!enabled) return;
|
||||||
|
logger.debug("gxjs forwardGnss");
|
||||||
|
forwardCurrentGnss();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int send(String projectId, List<GnssCalcData> records, LocalDateTime sentTime){
|
||||||
|
int batchNum = 0;
|
||||||
|
int sendNum = 0;
|
||||||
|
if(records.size() == 0) return 0;
|
||||||
|
|
||||||
|
XFZData xfzTcpMessage = new XFZData();
|
||||||
|
xfzTcpMessage.setProjectID(projectId);
|
||||||
|
xfzTcpMessage.setWorkPointID(projectId);
|
||||||
|
|
||||||
|
List<XFZData.Data> dataList = new ArrayList<>(records.size());
|
||||||
|
xfzTcpMessage.setData(dataList);
|
||||||
|
|
||||||
|
for(GnssCalcData locationRecord: records) {
|
||||||
|
XFZData.Data data = new XFZData.Data();
|
||||||
|
dataList.add(data);
|
||||||
|
data.setDataTime(locationRecord.getCreatetime().format(formatter));
|
||||||
|
data.setDevNum(locationRecord.getDeviceid());
|
||||||
|
data.setDevtype("GNSS");
|
||||||
|
// 单位由mm转化为m
|
||||||
|
data.setX(NumberUtils.scale(locationRecord.getRpose() * 0.001, 5));
|
||||||
|
data.setY(NumberUtils.scale(locationRecord.getRposn() * 0.001, 5));
|
||||||
|
data.setZ(NumberUtils.scale(locationRecord.getRposd() * 0.001, 5));
|
||||||
|
// 经纬度
|
||||||
|
data.setDevLng(locationRecord.getR9250e());
|
||||||
|
data.setDevLat(locationRecord.getR9250n());
|
||||||
|
|
||||||
|
if(projectId!=null && inclineProjectSet.contains(projectId)) {
|
||||||
|
//倾角
|
||||||
|
XFZData.Data data2 = new XFZData.Data();
|
||||||
|
dataList.add(data2);
|
||||||
|
data2.setDataTime(locationRecord.getCreatetime().format(formatter));
|
||||||
|
data2.setDevNum(locationRecord.getDeviceid() + "_qj");
|
||||||
|
data2.setDevtype("InclinoMeter");
|
||||||
|
// 角度
|
||||||
|
data2.setX(NumberUtils.scale(locationRecord.getAuxe(), 3));
|
||||||
|
data2.setY(NumberUtils.scale(locationRecord.getAuxn(), 3));
|
||||||
|
data2.setZ(NumberUtils.scale(locationRecord.getAuxd(), 3));
|
||||||
|
// 经纬度
|
||||||
|
data2.setDevLng(locationRecord.getR9250e());
|
||||||
|
data2.setDevLat(locationRecord.getR9250n());
|
||||||
|
}
|
||||||
|
// 发送
|
||||||
|
batchNum++;
|
||||||
|
|
||||||
|
if(batchNum==20){
|
||||||
|
String json = "#" + GsonUtil.toJson(xfzTcpMessage) + "!";
|
||||||
|
//logger.debug("project {}: forwad {} gnss records to {}",projectId, dataList.size(),fwdGroupId);
|
||||||
|
//logger.debug(json);
|
||||||
|
try {
|
||||||
|
listener.clear();
|
||||||
|
xfzTcpClient.writeAndFlush(json);
|
||||||
|
//等待应答
|
||||||
|
if(checkResult()) sendNum += batchNum;
|
||||||
|
} catch (Exception e1) {
|
||||||
|
logger.error(e1.toString());
|
||||||
|
}
|
||||||
|
batchNum = 0;
|
||||||
|
dataList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(batchNum>0){
|
||||||
|
String json = "#" + GsonUtil.toJson(xfzTcpMessage) + "!";
|
||||||
|
logger.debug("project {}: forwad {} gnss records to {}",projectId, dataList.size(),fwdGroupId);
|
||||||
|
logger.debug(json);
|
||||||
|
try {
|
||||||
|
listener.clear();
|
||||||
|
xfzTcpClient.writeAndFlush(json);
|
||||||
|
//等待应答
|
||||||
|
if(checkResult()) sendNum += batchNum;
|
||||||
|
} catch (Exception e1) {
|
||||||
|
logger.error(e1.toString());
|
||||||
|
}
|
||||||
|
dataList.clear();
|
||||||
|
}
|
||||||
|
return sendNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void forwardHistoryGnss(){
|
||||||
|
// 1.从转发记录表里检索待补传记录时间表,含设备Id,时间段
|
||||||
|
QueryWrapper<ResendRecord> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("fwd_group_id",fwdGroupId);
|
||||||
|
queryWrapper.eq("state",ResendRecord.STATE_BREAK_POINT);
|
||||||
|
queryWrapper.ge("createtime", LocalDateTime.now().minusDays(30));
|
||||||
|
List<ResendRecord> resendRecordsList = resendRecordMapper.selectList(queryWrapper);
|
||||||
|
|
||||||
|
if(resendRecordsList!=null && resendRecordsList.size()>0){
|
||||||
|
//修改状态
|
||||||
|
UpdateWrapper<ResendRecord> updateWrapper = new UpdateWrapper<>();
|
||||||
|
updateWrapper.eq("fwd_group_id",fwdGroupId);
|
||||||
|
updateWrapper.eq("state",ResendRecord.STATE_BREAK_POINT);
|
||||||
|
updateWrapper.ge("createtime", LocalDateTime.now().minusDays(30));
|
||||||
|
updateWrapper.set("state",ResendRecord.STATE_FWDING);
|
||||||
|
int updateNum = resendRecordMapper.update(null, updateWrapper);
|
||||||
|
logger.debug("{} forward history records: {}, update {}",fwdGroupId, resendRecordsList.size(),updateNum);
|
||||||
|
// 2.检索这个这个时间段的解算结果,如果有数据则单个终端转发,标志记录为已补传
|
||||||
|
for(ResendRecord record:resendRecordsList){
|
||||||
|
if(record.getProjectid()!=null)
|
||||||
|
logger.debug("{} forward history {}",fwdGroupId, record.getProjectid());
|
||||||
|
forwardBatchGnssRecords(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import com.imdroid.beidou_fwd.service.TCPClient;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
@ -11,20 +12,31 @@ import javax.annotation.PostConstruct;
|
|||||||
@Component
|
@Component
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
public class GXXfz2Forwarder extends GXXfzForwarder{
|
public class GXLJForwarder extends GXXfzForwarder{
|
||||||
private String FORWARDER_NAME = "广西路建";
|
private final String FORWARDER_NAME = "广西路建";
|
||||||
@Value("${gxlj.server.host}")
|
@Value("${gxlj.server.host}")
|
||||||
private String host;
|
private String host;
|
||||||
|
|
||||||
@Value("${gxlj.server.port}")
|
@Value("${gxlj.server.port}")
|
||||||
private int port;
|
private int port;
|
||||||
|
private boolean enabled=true;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
@Override
|
|
||||||
void registerMe(){
|
void registerMe(){
|
||||||
init(FORWARDER_NAME, "TCP "+host+":"+port,6,FWD_DEVICE_ID,30);
|
init(FORWARDER_NAME, "TCP "+host+":"+port,6,FWD_DEVICE_ID,30);
|
||||||
xfzTcpClient = new TCPClient();
|
xfzTcpClient = new TCPClient();
|
||||||
xfzTcpClient.init(host, port,listener);
|
xfzTcpClient.init(host, port,listener);
|
||||||
|
if(!enabled) return;
|
||||||
xfzTcpClient.start();
|
xfzTcpClient.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每半小时转发GNSS解算结果
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0/30 * * * ?") // 每30分钟执行一次
|
||||||
|
private void forwardGnss() {
|
||||||
|
if(!enabled) return;
|
||||||
|
logger.debug("gxlj forwardGnss");
|
||||||
|
forwardCurrentGnss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -6,31 +6,15 @@ import com.imdroid.beidou_fwd.service.TCPListener;
|
|||||||
import com.imdroid.common.util.GsonUtil;
|
import com.imdroid.common.util.GsonUtil;
|
||||||
import com.imdroid.common.util.NumberUtils;
|
import com.imdroid.common.util.NumberUtils;
|
||||||
import com.imdroid.secapi.dto.GnssCalcData;
|
import com.imdroid.secapi.dto.GnssCalcData;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Component
|
|
||||||
@Configuration
|
|
||||||
@EnableScheduling
|
|
||||||
public class GXXfzForwarder extends Forwarder{
|
public class GXXfzForwarder extends Forwarder{
|
||||||
private final String FORWARDER_NAME = "广西新发展";
|
|
||||||
@Value("${xfz.server.host}")
|
|
||||||
private String host;
|
|
||||||
|
|
||||||
@Value("${xfz.server.port}")
|
|
||||||
private int port;
|
|
||||||
|
|
||||||
TCPClient xfzTcpClient;
|
TCPClient xfzTcpClient;
|
||||||
|
|
||||||
static class XFZTCPListener implements TCPListener{
|
class XFZTCPListener implements TCPListener{
|
||||||
public static final int STATE_NO_ACK = 0;
|
public static final int STATE_NO_ACK = 0;
|
||||||
public static final int STATE_OK = 1;
|
public static final int STATE_OK = 1;
|
||||||
public static final int STATE_FAILED = 2;
|
public static final int STATE_FAILED = 2;
|
||||||
@ -51,36 +35,16 @@ public class GXXfzForwarder extends Forwarder{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(String msg) {
|
public void onMessage(String msg) {
|
||||||
|
logger.info("{} client rx: {}",fwdGroupId, msg);
|
||||||
if(msg.contains("succeed")) state = STATE_OK;
|
if(msg.contains("succeed")) state = STATE_OK;
|
||||||
else state = STATE_FAILED;
|
else state = STATE_FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
XFZTCPListener listener = new XFZTCPListener();
|
XFZTCPListener listener = new XFZTCPListener();
|
||||||
@PostConstruct
|
|
||||||
void registerMe(){
|
|
||||||
init(FORWARDER_NAME, "TCP "+host+":"+port,1,FWD_DEVICE_ID,30);
|
|
||||||
xfzTcpClient = new TCPClient();
|
|
||||||
xfzTcpClient.init(host, port,listener);
|
|
||||||
xfzTcpClient.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 每半小时转发GNSS解算结果
|
|
||||||
*/
|
|
||||||
@Scheduled(cron = "0 0/30 * * * ?") // 每30分钟执行一次
|
|
||||||
private void forwardGnss() {
|
|
||||||
logger.debug("xfz forwardGnss");
|
|
||||||
forwardCurrentGnss();
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
@Scheduled(cron = "0 0/10 * * * ?") // 每30分钟执行一次
|
|
||||||
private void checkDevice() {
|
|
||||||
//logger.debug("zny checkDevice");
|
|
||||||
checkOfflineDevice("2345053","2350106","2350124");
|
|
||||||
}*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int send(String projectId, List<GnssCalcData> records, LocalDateTime sentTime){
|
int send(String projectId, List<GnssCalcData> records, LocalDateTime sentTime){
|
||||||
|
int batchNum = 0;
|
||||||
int sendNum = 0;
|
int sendNum = 0;
|
||||||
if(records.size() == 0) return 0;
|
if(records.size() == 0) return 0;
|
||||||
|
|
||||||
@ -104,27 +68,49 @@ public class GXXfzForwarder extends Forwarder{
|
|||||||
// 经纬度
|
// 经纬度
|
||||||
data.setDevLng(locationRecord.getR9250e());
|
data.setDevLng(locationRecord.getR9250e());
|
||||||
data.setDevLat(locationRecord.getR9250n());
|
data.setDevLat(locationRecord.getR9250n());
|
||||||
sendNum++;
|
|
||||||
}
|
// 发送
|
||||||
|
batchNum++;
|
||||||
|
|
||||||
|
if(batchNum==20){
|
||||||
String json = "#" + GsonUtil.toJson(xfzTcpMessage) + "!";
|
String json = "#" + GsonUtil.toJson(xfzTcpMessage) + "!";
|
||||||
logger.debug("project " + projectId + ": push calculation result to XFZ");
|
//logger.debug("project {}: forwad {} gnss records to {}",projectId, dataList.size(),fwdGroupId);
|
||||||
|
//logger.debug(json);
|
||||||
|
try {
|
||||||
|
listener.clear();
|
||||||
|
xfzTcpClient.writeAndFlush(json);
|
||||||
|
//等待应答
|
||||||
|
if(checkResult()) sendNum += batchNum;
|
||||||
|
} catch (Exception e1) {
|
||||||
|
logger.error(e1.toString());
|
||||||
|
}
|
||||||
|
batchNum = 0;
|
||||||
|
dataList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(batchNum>0){
|
||||||
|
String json = "#" + GsonUtil.toJson(xfzTcpMessage) + "!";
|
||||||
|
logger.debug("project {}: forwad {} gnss records to {}",projectId, dataList.size(),fwdGroupId);
|
||||||
logger.debug(json);
|
logger.debug(json);
|
||||||
try {
|
try {
|
||||||
listener.clear();
|
listener.clear();
|
||||||
xfzTcpClient.writeAndFlush(json);
|
xfzTcpClient.writeAndFlush(json);
|
||||||
//等待应答
|
//等待应答
|
||||||
if(!checkResult()) sendNum = 0;
|
if(checkResult()) sendNum += batchNum;
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
sendNum = 0;
|
logger.error(e1.toString());
|
||||||
e1.printStackTrace();
|
}
|
||||||
|
dataList.clear();
|
||||||
}
|
}
|
||||||
return sendNum;
|
return sendNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean checkResult() throws InterruptedException {
|
boolean checkResult() throws InterruptedException {
|
||||||
// 等待应答,最多等1s
|
// 等待应答,最多等500ms
|
||||||
for(int i=0; i<10; i++){
|
for(int i=0; i<10; i++){
|
||||||
Thread.sleep(100);
|
Thread.sleep(50);
|
||||||
if(listener.state == XFZTCPListener.STATE_OK) return true;
|
if(listener.state == XFZTCPListener.STATE_OK) return true;
|
||||||
else if(listener.state == XFZTCPListener.STATE_FAILED) return false;
|
else if(listener.state == XFZTCPListener.STATE_FAILED) return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
package com.imdroid.beidou_fwd.task;
|
||||||
|
|
||||||
|
import com.imdroid.beidou_fwd.service.TCPClient;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
|
public class GZB10mForwarder extends GXXfzForwarder{
|
||||||
|
private final String FORWARDER_NAME = "葛洲坝10分钟";
|
||||||
|
@Value("${gzb.server.host}")
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@Value("${gzb.server.port}")
|
||||||
|
private int port;
|
||||||
|
private boolean enabled=true;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
void registerMe(){
|
||||||
|
init(FORWARDER_NAME, "TCP "+host+":"+port,1,FWD_DEVICE_ID,10);
|
||||||
|
xfzTcpClient = new TCPClient();
|
||||||
|
xfzTcpClient.init(host, port,listener);
|
||||||
|
if(!enabled) return;
|
||||||
|
xfzTcpClient.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每半小时转发GNSS解算结果
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0/10 * * * ?") // 每10分钟执行一次
|
||||||
|
private void forwardGnss() {
|
||||||
|
if(!enabled) return;
|
||||||
|
logger.debug("gzb forwardGnss");
|
||||||
|
forwardCurrentGnss();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import com.imdroid.beidou_fwd.service.TCPClient;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
@ -12,20 +13,30 @@ import javax.annotation.PostConstruct;
|
|||||||
@Configuration
|
@Configuration
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
public class GZBForwarder extends GXXfzForwarder{
|
public class GZBForwarder extends GXXfzForwarder{
|
||||||
private String FORWARDER_NAME = "葛洲坝";
|
private final String FORWARDER_NAME = "葛洲坝";
|
||||||
@Value("${gzb.server.host}")
|
@Value("${gzb.server.host}")
|
||||||
private String host;
|
private String host;
|
||||||
|
|
||||||
@Value("${gzb.server.port}")
|
@Value("${gzb.server.port}")
|
||||||
private int port;
|
private int port;
|
||||||
|
private boolean enabled=true;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
@Override
|
|
||||||
void registerMe(){
|
void registerMe(){
|
||||||
init(FORWARDER_NAME, "TCP "+host+":"+port,1,FWD_DEVICE_ID,30);
|
init(FORWARDER_NAME, "TCP "+host+":"+port,1,FWD_DEVICE_ID,30);
|
||||||
xfzTcpClient = new TCPClient();
|
xfzTcpClient = new TCPClient();
|
||||||
xfzTcpClient.init(host, port,listener);
|
xfzTcpClient.init(host, port,listener);
|
||||||
|
if(!enabled) return;
|
||||||
xfzTcpClient.start();
|
xfzTcpClient.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每半小时转发GNSS解算结果
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0/30 * * * ?") // 每30分钟执行一次
|
||||||
|
private void forwardGnss() {
|
||||||
|
if(!enabled) return;
|
||||||
|
logger.debug("gzb forwardGnss");
|
||||||
|
forwardCurrentGnss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,17 +28,18 @@ import java.util.List;
|
|||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
public class GZYMQTTForwarder extends Forwarder {
|
public class GZYMQTTForwarder extends Forwarder {
|
||||||
static final String FORWARDER_NAME = "贵州交勘院MQTT";
|
static final String FORWARDER_NAME = "贵州交勘院MQTT";
|
||||||
@Value("${mqtt.server.brokerUrl}")
|
@Value("${gzymqtt.server.brokerUrl}")
|
||||||
private String brokerUrl;
|
private String brokerUrl;
|
||||||
@Value("${mqtt.server.username}")
|
@Value("${gzymqtt.server.username}")
|
||||||
private String username;
|
private String username;
|
||||||
@Value("${mqtt.server.password}")
|
@Value("${gzymqtt.server.password}")
|
||||||
private String password;
|
private String password;
|
||||||
@Value("${mqtt.server.clientid}")
|
@Value("${gzymqtt.server.clientid}")
|
||||||
private String clientid;
|
private String clientid;
|
||||||
@Value("${mqtt.server.topic}")
|
@Value("${gzymqtt.server.topic}")
|
||||||
private String topic;
|
private String topic;
|
||||||
|
//@Value("${gzymqtt.server.enabled}")
|
||||||
|
private boolean enabled=true;
|
||||||
@Autowired
|
@Autowired
|
||||||
GnssStatusMsgMapper statusMsgMapper;
|
GnssStatusMsgMapper statusMsgMapper;
|
||||||
MQTTClient mqttClient;
|
MQTTClient mqttClient;
|
||||||
@ -47,6 +48,7 @@ public class GZYMQTTForwarder extends Forwarder {
|
|||||||
void registerMe() throws MqttException {
|
void registerMe() throws MqttException {
|
||||||
init(FORWARDER_NAME, "MQTT "+brokerUrl,2,FWD_DEVICE_ALIAS_NAME,30);
|
init(FORWARDER_NAME, "MQTT "+brokerUrl,2,FWD_DEVICE_ALIAS_NAME,30);
|
||||||
mqttClient = new MQTTClient(brokerUrl, username, password,clientid);
|
mqttClient = new MQTTClient(brokerUrl, username, password,clientid);
|
||||||
|
if(!enabled) return;
|
||||||
try{
|
try{
|
||||||
mqttClient.connect();
|
mqttClient.connect();
|
||||||
}
|
}
|
||||||
@ -61,10 +63,11 @@ public class GZYMQTTForwarder extends Forwarder {
|
|||||||
@Scheduled(cron = "0 0 0/1 * * ?") // 每小时执行一次
|
@Scheduled(cron = "0 0 0/1 * * ?") // 每小时执行一次
|
||||||
//@Scheduled(cron = "0 0/5 * * * ?") // 每30分钟执行一次
|
//@Scheduled(cron = "0 0/5 * * * ?") // 每30分钟执行一次
|
||||||
private void forwardGnss() {
|
private void forwardGnss() {
|
||||||
|
if(!enabled) return;
|
||||||
logger.debug("gzy mqtt forwardGnss");
|
logger.debug("gzy mqtt forwardGnss");
|
||||||
if(mqttClient.isConnected()) {
|
if(mqttClient.isConnected()) {
|
||||||
forwardCurrentGnss();
|
forwardCurrentGnss();
|
||||||
//forwardAngleData();
|
forwardAngleData();
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
try{
|
try{
|
||||||
@ -75,6 +78,11 @@ public class GZYMQTTForwarder extends Forwarder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
@Scheduled(cron = "0 0/5 * * * ?") // 每30分钟执行一次
|
||||||
|
void forwardHistoryGnss() {
|
||||||
|
super.forwardHistoryGnss();
|
||||||
|
}*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int send(String projectId, List<GnssCalcData> records, LocalDateTime sentTime) {
|
int send(String projectId, List<GnssCalcData> records, LocalDateTime sentTime) {
|
||||||
@ -122,6 +130,7 @@ public class GZYMQTTForwarder extends Forwarder {
|
|||||||
|
|
||||||
GZYMQTTAngle tranData = new GZYMQTTAngle();
|
GZYMQTTAngle tranData = new GZYMQTTAngle();
|
||||||
tranData.setDeviceSn(msg.getDeviceid());
|
tranData.setDeviceSn(msg.getDeviceid());
|
||||||
|
tranData.setDeviceType(8);
|
||||||
tranData.setCollectTime(msg.getCreatetime().format(formatter));
|
tranData.setCollectTime(msg.getCreatetime().format(formatter));
|
||||||
float x = msg.getRoll()==null?0:msg.getRoll();
|
float x = msg.getRoll()==null?0:msg.getRoll();
|
||||||
float y = msg.getPitch()==null?0:msg.getPitch();
|
float y = msg.getPitch()==null?0:msg.getPitch();
|
||||||
|
|||||||
@ -0,0 +1,155 @@
|
|||||||
|
package com.imdroid.beidou_fwd.task;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.imdroid.beidou_fwd.entity.GZYMQTTAngle;
|
||||||
|
import com.imdroid.beidou_fwd.entity.GZYMQTTData;
|
||||||
|
import com.imdroid.beidou_fwd.service.MQTTClient;
|
||||||
|
import com.imdroid.common.util.GsonUtil;
|
||||||
|
import com.imdroid.common.util.NumberUtils;
|
||||||
|
import com.imdroid.secapi.dto.GnssCalcData;
|
||||||
|
import com.imdroid.secapi.dto.GnssStatusMsg;
|
||||||
|
import com.imdroid.secapi.dto.GnssStatusMsgMapper;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
|
public class GZYMqttTestForwarder extends Forwarder {
|
||||||
|
static final String FORWARDER_NAME = "贵州交勘院MQTT测试平台";
|
||||||
|
@Value("${gzymqtttest.server.brokerUrl}")
|
||||||
|
private String brokerUrl;
|
||||||
|
@Value("${gzymqtttest.server.username}")
|
||||||
|
private String username;
|
||||||
|
@Value("${gzymqtttest.server.password}")
|
||||||
|
private String password;
|
||||||
|
@Value("${gzymqtttest.server.clientid}")
|
||||||
|
private String clientid;
|
||||||
|
@Value("${gzymqtttest.server.topic}")
|
||||||
|
private String topic;
|
||||||
|
@Value("${gzymqtttest.server.enabled}")
|
||||||
|
private boolean enabled;
|
||||||
|
@Autowired
|
||||||
|
GnssStatusMsgMapper statusMsgMapper;
|
||||||
|
MQTTClient mqttClient;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
void registerMe() throws MqttException {
|
||||||
|
init(FORWARDER_NAME, "MQTT "+brokerUrl,2,FWD_DEVICE_ALIAS_NAME,30);
|
||||||
|
mqttClient = new MQTTClient(brokerUrl, username, password,clientid);
|
||||||
|
if(!enabled) return;
|
||||||
|
try{
|
||||||
|
mqttClient.connect();
|
||||||
|
}
|
||||||
|
catch (Exception e){
|
||||||
|
logger.error("gzy mqtt connect failed: {}",e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每半小时转发GNSS解算结果
|
||||||
|
*/
|
||||||
|
//@Scheduled(cron = "0 0 0/1 * * ?") // 每小时执行一次
|
||||||
|
@Scheduled(cron = "0 0/30 * * * ?") // 每30分钟执行一次
|
||||||
|
private void forwardGnss() {
|
||||||
|
if(!enabled) return;
|
||||||
|
logger.debug("gzy mqtt test forwardGnss");
|
||||||
|
if(mqttClient.isConnected()) {
|
||||||
|
forwardCurrentGnss();
|
||||||
|
//forwardAngleData();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
try{
|
||||||
|
mqttClient.connect();
|
||||||
|
}
|
||||||
|
catch (Exception e){
|
||||||
|
logger.error("gzy mqtt connect failed: {}",e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
@Scheduled(cron = "0 0/5 * * * ?") // 每30分钟执行一次
|
||||||
|
void forwardHistoryGnss() {
|
||||||
|
super.forwardHistoryGnss();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int send(String projectId, List<GnssCalcData> records, LocalDateTime sentTime) {
|
||||||
|
int sendNum = 0;
|
||||||
|
|
||||||
|
for (GnssCalcData locationRecord : records) {
|
||||||
|
GZYMQTTData tranData = new GZYMQTTData();
|
||||||
|
tranData.setCollectTime(locationRecord.getCreatetime().format(formatter));
|
||||||
|
double n = NumberUtils.scale(locationRecord.getRposn(), 2);
|
||||||
|
double e = NumberUtils.scale(locationRecord.getRpose(), 2);
|
||||||
|
double d = NumberUtils.scale(locationRecord.getRposd(), 2);
|
||||||
|
tranData.setX(n);
|
||||||
|
tranData.setY(e);
|
||||||
|
tranData.setZ(d);
|
||||||
|
tranData.setDeviceType(2);
|
||||||
|
tranData.setDeviceSn(locationRecord.getDeviceid());
|
||||||
|
String json = GsonUtil.toJson(tranData);
|
||||||
|
logger.debug("forward to GZY mqtt Test: {}",json);
|
||||||
|
try {
|
||||||
|
if(!mqttClient.publish(topic, json)) break;
|
||||||
|
Thread.sleep(50);
|
||||||
|
} catch (Exception e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
sendNum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void forwardAngleData() {
|
||||||
|
// 获取最近半小时的状态消息
|
||||||
|
LocalDateTime sentTime = LocalDateTime.now();
|
||||||
|
QueryWrapper<GnssStatusMsg> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("tenantid",tenantId);
|
||||||
|
queryWrapper.le("createtime",sentTime);
|
||||||
|
queryWrapper.ge("createtime",sentTime.minusMinutes(fwdCycleMinutes));
|
||||||
|
queryWrapper.orderByDesc("createtime");
|
||||||
|
HashMap<String,String> sendDeviceMap = new HashMap<>();
|
||||||
|
List<GnssStatusMsg> statusMsgs = statusMsgMapper.selectList(queryWrapper);
|
||||||
|
int sendNum = 0;
|
||||||
|
for(GnssStatusMsg msg:statusMsgs){
|
||||||
|
if(sendDeviceMap.get(msg.getDeviceid())!=null) continue;
|
||||||
|
sendDeviceMap.put(msg.getDeviceid(),msg.getDeviceid());
|
||||||
|
|
||||||
|
GZYMQTTAngle tranData = new GZYMQTTAngle();
|
||||||
|
tranData.setDeviceSn(msg.getDeviceid());
|
||||||
|
tranData.setCollectTime(msg.getCreatetime().format(formatter));
|
||||||
|
float x = msg.getRoll()==null?0:msg.getRoll();
|
||||||
|
float y = msg.getPitch()==null?0:msg.getPitch();
|
||||||
|
float az = msg.getYaw()==null?0:msg.getYaw();
|
||||||
|
tranData.setAngleX(NumberUtils.scale((double) x,2));
|
||||||
|
tranData.setAngleY(NumberUtils.scale((double) y,2));
|
||||||
|
tranData.setAngleAz(NumberUtils.scale((double) az,2));
|
||||||
|
|
||||||
|
String json = GsonUtil.toJson(tranData);
|
||||||
|
logger.debug("forward to GZY mqtt angles: {}",json);
|
||||||
|
try {
|
||||||
|
if(!mqttClient.publish(topic, json)) break;
|
||||||
|
Thread.sleep(10);
|
||||||
|
} catch (Exception e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
sendNum++;
|
||||||
|
}
|
||||||
|
logger.debug("total number of angles sent to GZY: {}",sendNum);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,160 @@
|
|||||||
|
package com.imdroid.beidou_fwd.task;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
|
import com.imdroid.beidou_fwd.entity.XFZData;
|
||||||
|
import com.imdroid.beidou_fwd.service.TCPClient;
|
||||||
|
import com.imdroid.common.util.GsonUtil;
|
||||||
|
import com.imdroid.common.util.NumberUtils;
|
||||||
|
import com.imdroid.secapi.dto.GnssCalcData;
|
||||||
|
import com.imdroid.secapi.dto.ResendRecord;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
|
public class GZYZForwarder extends GXXfzForwarder{
|
||||||
|
private final String FORWARDER_NAME = "广州英卓";
|
||||||
|
@Value("${gzyz.server.host}")
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@Value("${gzyz.server.port}")
|
||||||
|
private int port;
|
||||||
|
private boolean enabled=true;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
void registerMe(){
|
||||||
|
init(FORWARDER_NAME, "TCP "+host+":"+port,14,FWD_DEVICE_ID,30);
|
||||||
|
xfzTcpClient = new TCPClient();
|
||||||
|
xfzTcpClient.init(host, port,listener);
|
||||||
|
if(!enabled) return;
|
||||||
|
|
||||||
|
xfzTcpClient.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每半小时转发GNSS解算结果
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0/30 * * * ?") // 每30分钟执行一次
|
||||||
|
private void forwardGnss() {
|
||||||
|
if(!enabled) return;
|
||||||
|
logger.debug("gzyz forwardGnss");
|
||||||
|
forwardCurrentGnss();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int send(String projectId, List<GnssCalcData> records, LocalDateTime sentTime){
|
||||||
|
int batchNum = 0;
|
||||||
|
int sendNum = 0;
|
||||||
|
if(records.size() == 0) return 0;
|
||||||
|
|
||||||
|
XFZData xfzTcpMessage = new XFZData();
|
||||||
|
xfzTcpMessage.setProjectID(projectId);
|
||||||
|
xfzTcpMessage.setWorkPointID(projectId);
|
||||||
|
|
||||||
|
List<XFZData.Data> dataList = new ArrayList<>(records.size());
|
||||||
|
xfzTcpMessage.setData(dataList);
|
||||||
|
|
||||||
|
for(GnssCalcData locationRecord: records) {
|
||||||
|
XFZData.Data data = new XFZData.Data();
|
||||||
|
dataList.add(data);
|
||||||
|
data.setDataTime(locationRecord.getCreatetime().format(formatter));
|
||||||
|
data.setDevNum(locationRecord.getDeviceid());
|
||||||
|
data.setDevtype("GNSS");
|
||||||
|
// 单位由mm转化为m
|
||||||
|
data.setX(NumberUtils.scale(locationRecord.getRpose() * 0.001, 5));
|
||||||
|
data.setY(NumberUtils.scale(locationRecord.getRposn() * 0.001, 5));
|
||||||
|
data.setZ(NumberUtils.scale(locationRecord.getRposd() * 0.001, 5));
|
||||||
|
// 经纬度
|
||||||
|
data.setDevLng(locationRecord.getR9250e());
|
||||||
|
data.setDevLat(locationRecord.getR9250n());
|
||||||
|
|
||||||
|
//倾角
|
||||||
|
XFZData.Data data2 = new XFZData.Data();
|
||||||
|
dataList.add(data2);
|
||||||
|
data2.setDataTime(locationRecord.getCreatetime().format(formatter));
|
||||||
|
data2.setDevNum(locationRecord.getDeviceid() + "_qj");
|
||||||
|
data2.setDevtype("InclinoMeter");
|
||||||
|
// 角度
|
||||||
|
data2.setX(NumberUtils.scale(locationRecord.getAuxe(), 3));
|
||||||
|
data2.setY(NumberUtils.scale(locationRecord.getAuxn(), 3));
|
||||||
|
data2.setZ(NumberUtils.scale(locationRecord.getAuxd(), 3));
|
||||||
|
// 经纬度
|
||||||
|
data2.setDevLng(locationRecord.getR9250e());
|
||||||
|
data2.setDevLat(locationRecord.getR9250n());
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
batchNum++;
|
||||||
|
|
||||||
|
if(batchNum==20){
|
||||||
|
String json = "#" + GsonUtil.toJson(xfzTcpMessage) + "!";
|
||||||
|
//logger.debug("project {}: forwad {} gnss records to {}",projectId, dataList.size(),fwdGroupId);
|
||||||
|
//logger.debug(json);
|
||||||
|
try {
|
||||||
|
listener.clear();
|
||||||
|
xfzTcpClient.writeAndFlush(json);
|
||||||
|
//等待应答
|
||||||
|
if(checkResult()) sendNum += batchNum;
|
||||||
|
} catch (Exception e1) {
|
||||||
|
logger.error(e1.toString());
|
||||||
|
}
|
||||||
|
batchNum = 0;
|
||||||
|
dataList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(batchNum>0){
|
||||||
|
String json = "#" + GsonUtil.toJson(xfzTcpMessage) + "!";
|
||||||
|
logger.debug("project {}: forwad {} gnss records to {}",projectId, dataList.size(),fwdGroupId);
|
||||||
|
logger.debug(json);
|
||||||
|
try {
|
||||||
|
listener.clear();
|
||||||
|
xfzTcpClient.writeAndFlush(json);
|
||||||
|
//等待应答
|
||||||
|
if(checkResult()) sendNum += batchNum;
|
||||||
|
} catch (Exception e1) {
|
||||||
|
logger.error(e1.toString());
|
||||||
|
}
|
||||||
|
dataList.clear();
|
||||||
|
}
|
||||||
|
return sendNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void forwardHistoryGnss(){
|
||||||
|
// 1.从转发记录表里检索待补传记录时间表,含设备Id,时间段
|
||||||
|
QueryWrapper<ResendRecord> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("fwd_group_id",fwdGroupId);
|
||||||
|
queryWrapper.eq("state",ResendRecord.STATE_BREAK_POINT);
|
||||||
|
queryWrapper.ge("createtime", LocalDateTime.now().minusDays(30));
|
||||||
|
List<ResendRecord> resendRecordsList = resendRecordMapper.selectList(queryWrapper);
|
||||||
|
|
||||||
|
if(resendRecordsList!=null && resendRecordsList.size()>0){
|
||||||
|
//修改状态
|
||||||
|
UpdateWrapper<ResendRecord> updateWrapper = new UpdateWrapper<>();
|
||||||
|
updateWrapper.eq("fwd_group_id",fwdGroupId);
|
||||||
|
updateWrapper.eq("state",ResendRecord.STATE_BREAK_POINT);
|
||||||
|
updateWrapper.ge("createtime", LocalDateTime.now().minusDays(30));
|
||||||
|
updateWrapper.set("state",ResendRecord.STATE_FWDING);
|
||||||
|
int updateNum = resendRecordMapper.update(null, updateWrapper);
|
||||||
|
logger.debug("{} forward history records: {}, update {}",fwdGroupId, resendRecordsList.size(),updateNum);
|
||||||
|
// 2.检索这个这个时间段的解算结果,如果有数据则单个终端转发,标志记录为已补传
|
||||||
|
for(ResendRecord record:resendRecordsList){
|
||||||
|
if(record.getProjectid()!=null)
|
||||||
|
logger.debug("{} forward history {}",fwdGroupId, record.getProjectid());
|
||||||
|
forwardBatchGnssRecords(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -37,6 +37,11 @@ public class Gga {
|
|||||||
private int quality=0;
|
private int quality=0;
|
||||||
private int satellitesInUsed=0;
|
private int satellitesInUsed=0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 大地水准面相对椭球面的高度
|
||||||
|
*/
|
||||||
|
private double geoidSeparation = 0;
|
||||||
|
|
||||||
public Gga() {
|
public Gga() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,8 +99,8 @@ public class Gga {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(ggaStr != null){
|
if(ggaStr != null){
|
||||||
String[] params = ggaStr.split(",",11);
|
String[] params = ggaStr.split(",", 14);
|
||||||
if(params.length == 11){
|
if(params.length >= 12){
|
||||||
Gga gga = new Gga();
|
Gga gga = new Gga();
|
||||||
try {
|
try {
|
||||||
gga.setLatitude(transGGAPos(Double.parseDouble(params[2])));
|
gga.setLatitude(transGGAPos(Double.parseDouble(params[2])));
|
||||||
@ -103,6 +108,7 @@ public class Gga {
|
|||||||
gga.setAltitude(Double.parseDouble(params[9]));
|
gga.setAltitude(Double.parseDouble(params[9]));
|
||||||
gga.setQuality(Integer.parseInt(params[6]));
|
gga.setQuality(Integer.parseInt(params[6]));
|
||||||
gga.setSatellitesInUsed(Integer.parseInt(params[7]));
|
gga.setSatellitesInUsed(Integer.parseInt(params[7]));
|
||||||
|
gga.setGeoidSeparation(Double.parseDouble(params[11]));
|
||||||
return gga;
|
return gga;
|
||||||
}
|
}
|
||||||
catch (Exception e){
|
catch (Exception e){
|
||||||
|
|||||||
@ -44,11 +44,14 @@ public class GNSSCalcFilterService {
|
|||||||
Integer xyfilterCycle = groupCalc.getFilter_hour();
|
Integer xyfilterCycle = groupCalc.getFilter_hour();
|
||||||
Integer zfilterCycle = groupCalc.getZfilter_hour();
|
Integer zfilterCycle = groupCalc.getZfilter_hour();
|
||||||
if(null == zfilterCycle) zfilterCycle = xyfilterCycle;
|
if(null == zfilterCycle) zfilterCycle = xyfilterCycle;
|
||||||
|
if(groupCalc.getAuto_filter()) {
|
||||||
VaryFilterCycle varyCycle = autoCycleDevices.get(deviceId);
|
VaryFilterCycle varyCycle = autoCycleDevices.get(deviceId);
|
||||||
if (varyCycle != null) {
|
if (varyCycle != null) {
|
||||||
xyfilterCycle = varyCycle.filterCycleHour;
|
xyfilterCycle = varyCycle.filterCycleHour;
|
||||||
zfilterCycle = varyCycle.filterCycleHour;
|
zfilterCycle = varyCycle.filterCycleHour;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else autoCycleDevices.remove(deviceId);
|
||||||
|
|
||||||
// 平滑处理
|
// 平滑处理
|
||||||
calcFilterLocation(newRecord, referPos, xyfilterCycle, zfilterCycle, groupCalc.getFilter_min_hour(),
|
calcFilterLocation(newRecord, referPos, xyfilterCycle, zfilterCycle, groupCalc.getFilter_min_hour(),
|
||||||
@ -166,7 +169,7 @@ public class GNSSCalcFilterService {
|
|||||||
newRecord.setAuxn(NumberUtils.scaleTwo(msumN / minCount));
|
newRecord.setAuxn(NumberUtils.scaleTwo(msumN / minCount));
|
||||||
newRecord.setAuxd(NumberUtils.scaleTwo(msumD / minCount));
|
newRecord.setAuxd(NumberUtils.scaleTwo(msumD / minCount));
|
||||||
//滤波窗口里的时间跨度超过滤波时间的2/3才认为稳定
|
//滤波窗口里的时间跨度超过滤波时间的2/3才认为稳定
|
||||||
newRecord.setStabled(lastRecordTime.isBefore(newRecordTime.minusHours(filterCycleHour * 2 / 3)));
|
newRecord.setStabled(lastRecordTime.isBefore(newRecordTime.minusHours(filterCycleHour * 1 / 2)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,7 +249,7 @@ public class GNSSCalcFilterService {
|
|||||||
newRecord.setAuxn(NumberUtils.scaleTwo(msumN / minCount));
|
newRecord.setAuxn(NumberUtils.scaleTwo(msumN / minCount));
|
||||||
newRecord.setAuxd(NumberUtils.scaleTwo(msumD / minCount));
|
newRecord.setAuxd(NumberUtils.scaleTwo(msumD / minCount));
|
||||||
//滤波窗口里的时间跨度超过滤波时间的2/3才认为稳定
|
//滤波窗口里的时间跨度超过滤波时间的2/3才认为稳定
|
||||||
newRecord.setStabled(lastRecordTime.isBefore(newRecordTime.minusHours(filterCycleHour * 2 / 3)));
|
newRecord.setStabled(lastRecordTime.isBefore(newRecordTime.minusHours(filterCycleHour * 1 / 2)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.imdroid.sideslope.calc;
|
package com.imdroid.sideslope.calc;
|
||||||
|
|
||||||
import com.imdroid.secapi.dto.GnssGroupCalc;
|
import com.imdroid.secapi.dto.GnssGroupCalc;
|
||||||
|
import com.imdroid.sideslope.message.D331RtcmMessage;
|
||||||
import com.imdroid.sideslope.message.D341LocationMessage;
|
import com.imdroid.sideslope.message.D341LocationMessage;
|
||||||
import com.imdroid.sideslope.service.Device;
|
import com.imdroid.sideslope.service.Device;
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ public interface GNSSDataCalcService {
|
|||||||
* @param completeWhenIdle 是否根据空闲时间判断本轮结束
|
* @param completeWhenIdle 是否根据空闲时间判断本轮结束
|
||||||
*/
|
*/
|
||||||
void calcSingle(D341LocationMessage message, boolean completeWhenIdle);
|
void calcSingle(D341LocationMessage message, boolean completeWhenIdle);
|
||||||
|
void calcSingle(D331RtcmMessage message, boolean completeWhenIdle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单轮解算结束,计算平滑值
|
* 单轮解算结束,计算平滑值
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import com.imdroid.common.util.DataTypeUtil;
|
|||||||
import com.imdroid.common.util.ThreadManager;
|
import com.imdroid.common.util.ThreadManager;
|
||||||
import com.imdroid.secapi.dto.*;
|
import com.imdroid.secapi.dto.*;
|
||||||
import com.imdroid.sideslope.bd.*;
|
import com.imdroid.sideslope.bd.*;
|
||||||
|
import com.imdroid.sideslope.message.D331RtcmMessage;
|
||||||
import com.imdroid.sideslope.message.D341LocationMessage;
|
import com.imdroid.sideslope.message.D341LocationMessage;
|
||||||
import com.imdroid.sideslope.service.Device;
|
import com.imdroid.sideslope.service.Device;
|
||||||
import com.imdroid.sideslope.service.DeviceService;
|
import com.imdroid.sideslope.service.DeviceService;
|
||||||
@ -159,6 +160,92 @@ public class SingleLineGNSSCalcService implements GNSSDataCalcService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void calcSingle(D331RtcmMessage message, boolean completeWhenIdle) {
|
||||||
|
String deviceId = message.getId();
|
||||||
|
Device device = deviceService.findByDeviceId(deviceId);
|
||||||
|
if(device == null) return;
|
||||||
|
GnssGroupCalc groupCalc = groupParaService.getCalcGroup(device.getCalcGroupId());
|
||||||
|
if(groupCalc==null) return;
|
||||||
|
device.setB562AsCalc(groupCalc.getVer()!=3);
|
||||||
|
|
||||||
|
//todo 创建FocusCalculator对象需获取该测站的杆长度,上一小时的Tilt平均值,上一小时的测站相对坐标融合值ekfResult
|
||||||
|
FocusCalculator focusCalculator;
|
||||||
|
if(groupCalc.getVer() == 6){
|
||||||
|
focusCalculator = calculatorMap.computeIfAbsent(deviceId,s -> new FocusCalculator6(deviceId, 50));
|
||||||
|
}
|
||||||
|
else if(groupCalc.getVer() == 5){
|
||||||
|
focusCalculator = calculatorMap.get(deviceId);
|
||||||
|
if(focusCalculator ==null) {
|
||||||
|
Short removeRate = groupCalc.getRemove_rate();
|
||||||
|
if (removeRate == null) removeRate = 20;
|
||||||
|
focusCalculator = new FocusCalculator5(deviceId, 50, removeRate);
|
||||||
|
calculatorMap.put(deviceId,focusCalculator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(groupCalc.getVer() == 4){
|
||||||
|
focusCalculator = calculatorMap.computeIfAbsent(deviceId,s -> new FocusCalculator4());
|
||||||
|
}
|
||||||
|
else if(groupCalc.getVer() == 3){
|
||||||
|
Device bsDevice = deviceService.findByDeviceId(device.getParentId());
|
||||||
|
focusCalculator = calculatorMap.computeIfAbsent(deviceId,s -> new FocusCalculator3(bsDevice));
|
||||||
|
}
|
||||||
|
else if(groupCalc.getVer() == 2){
|
||||||
|
focusCalculator = calculatorMap.computeIfAbsent(deviceId,s -> new FocusCalculator2());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
focusCalculator = calculatorMap.computeIfAbsent(deviceId,s -> new FocusCalculator1());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取惯导
|
||||||
|
Tilt tilt = message.getTilt();
|
||||||
|
if(tilt != null) {
|
||||||
|
focusCalculator.addTilt(tilt);
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("测站{}惯导单次解析结果:{}", deviceId,tilt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 延迟
|
||||||
|
focusCalculator.addDelayMs(message.getPps());
|
||||||
|
|
||||||
|
// 单次GGA
|
||||||
|
Gga gga = message.getGga();
|
||||||
|
if(gga != null) {
|
||||||
|
focusCalculator.addGGA(gga);
|
||||||
|
logger.debug("测站{}的gga单次解析结果:{},{},{},{}",deviceId,
|
||||||
|
gga.getLongitude(), gga.getLatitude(), gga.getAltitude(), gga.getQuality());
|
||||||
|
if(groupCalc.getVer() == 3 && focusCalculator.isJump()){
|
||||||
|
logger.info("{}发生周跳",deviceId);
|
||||||
|
hardResetDevice(deviceId);
|
||||||
|
device.setJumpCount(device.getJumpCount()+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(completeWhenIdle &&
|
||||||
|
(gga.getQuality()==Gga.FIX_RESULT || gga.getQuality()==Gga.FLOAT_RESULT)) {
|
||||||
|
resultOutputTimer(device, groupCalc, message.getCreateTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 若是该设备开启了日志记录,则保存单次解析的数据
|
||||||
|
if(device.getLoggingmode() == GnssDevice.LOGGING_MODE_FULL){
|
||||||
|
// 保存单次解析的原始数据,受 loggingmode 字段控制
|
||||||
|
GnssSingleData gnssSingleData = new GnssSingleData();
|
||||||
|
gnssSingleData.setDeviceid(device.getDeviceId());
|
||||||
|
gnssSingleData.setCreatetime(LocalDateTime.now());
|
||||||
|
gnssSingleData.setModel(device.getModel());
|
||||||
|
if(gga !=null){
|
||||||
|
gnssSingleData.setX(gga.getLatitude());
|
||||||
|
gnssSingleData.setY(gga.getLongitude());
|
||||||
|
gnssSingleData.setZ(gga.getAltitude());
|
||||||
|
gnssSingleData.setStatus(gga.getQuality());
|
||||||
|
gnssSingleDataService.addData(gnssSingleData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void calSingleDone(Device device, GnssGroupCalc groupCalc, LocalDateTime resultTime) {
|
public void calSingleDone(Device device, GnssGroupCalc groupCalc, LocalDateTime resultTime) {
|
||||||
ScheduledFuture<?> future = timerMap.get(device.getDeviceId());
|
ScheduledFuture<?> future = timerMap.get(device.getDeviceId());
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package com.imdroid.sideslope.executor;
|
package com.imdroid.sideslope.executor;
|
||||||
|
|
||||||
import com.imdroid.sideslope.message.D314PingMessage;
|
import com.imdroid.sideslope.message.D314PingMessage;
|
||||||
|
import com.imdroid.sideslope.server.DeviceChannel;
|
||||||
import com.imdroid.sideslope.server.OnlineChannels;
|
import com.imdroid.sideslope.server.OnlineChannels;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12,17 +15,20 @@ import org.springframework.stereotype.Component;
|
|||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class D314PingMessageExecutor implements Executor<D314PingMessage, Void> {
|
public class D314PingMessageExecutor implements Executor<D314PingMessage, Void> {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void execute(D314PingMessage message) {
|
public Void execute(D314PingMessage message) {
|
||||||
String deviceId = message.getId();
|
String deviceId = message.getId();
|
||||||
byte[] forwardBytes = message.getSrcData();
|
byte[] forwardBytes = message.getSrcData();
|
||||||
OnlineChannels.INSTANCE.get(deviceId).ifPresent(deviceChannel -> {
|
DeviceChannel deviceChannel = OnlineChannels.INSTANCE.getConfigChannel(deviceId);
|
||||||
forwardBytes[12] = (byte) 1;//ping ack
|
if(deviceChannel!=null){
|
||||||
|
//forwardBytes[12] = (byte) 1;//ping ack
|
||||||
ByteBuf buf = Unpooled.buffer();
|
ByteBuf buf = Unpooled.buffer();
|
||||||
buf.writeBytes(forwardBytes);
|
buf.writeBytes(forwardBytes);
|
||||||
deviceChannel.writeAndFlush(buf);
|
deviceChannel.writeAndFlush(buf);
|
||||||
});
|
logger.info("{} ping ack",deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import com.imdroid.secapi.dto.GnssDevice;
|
|||||||
import com.imdroid.common.util.ByteUtil;
|
import com.imdroid.common.util.ByteUtil;
|
||||||
import com.imdroid.sideslope.bd.Gga;
|
import com.imdroid.sideslope.bd.Gga;
|
||||||
import com.imdroid.sideslope.bd.Rtcm1005;
|
import com.imdroid.sideslope.bd.Rtcm1005;
|
||||||
|
import com.imdroid.sideslope.calc.GNSSDataCalcService;
|
||||||
import com.imdroid.sideslope.message.D331RtcmMessage;
|
import com.imdroid.sideslope.message.D331RtcmMessage;
|
||||||
import com.imdroid.sideslope.ntrip.UdpNtripServer;
|
import com.imdroid.sideslope.ntrip.UdpNtripServer;
|
||||||
import com.imdroid.sideslope.service.Device;
|
import com.imdroid.sideslope.service.Device;
|
||||||
@ -15,6 +16,7 @@ import com.imdroid.sideslope.server.DeviceChannel;
|
|||||||
import com.imdroid.sideslope.server.OnlineChannels;
|
import com.imdroid.sideslope.server.OnlineChannels;
|
||||||
import com.imdroid.sideslope.service.DataPersistService;
|
import com.imdroid.sideslope.service.DataPersistService;
|
||||||
import com.imdroid.sideslope.bd.RtcmGgaUtil;
|
import com.imdroid.sideslope.bd.RtcmGgaUtil;
|
||||||
|
import com.imdroid.sideslope.rtkcluster.RtkClusterService;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -45,10 +47,14 @@ public class D331RtcmMessageExecutor implements Executor<D331RtcmMessage, Void>
|
|||||||
private DataPersistService dataPersistService;
|
private DataPersistService dataPersistService;
|
||||||
@Autowired
|
@Autowired
|
||||||
UdpNtripServer ntripServer;
|
UdpNtripServer ntripServer;
|
||||||
|
@Autowired
|
||||||
|
private GNSSDataCalcService gnssCalcService;
|
||||||
|
@Autowired
|
||||||
|
private RtkClusterService rtkClusterService;
|
||||||
|
|
||||||
// 添加一个成员变量用于追踪每个测站最后一次转发D300数据的时间
|
// 添加一个成员变量用于追踪每个测站最后一次转发D300数据的时间
|
||||||
private final Map<String, Long> lastD300ForwardTimeMap = new ConcurrentHashMap<>();
|
private final Map<String, Long> lastD300ForwardTimeMap = new ConcurrentHashMap<>();
|
||||||
private static final long D300_FORWARD_INTERVAL = 10000; // 10秒,单位毫秒
|
private static final long D300_FORWARD_INTERVAL = 5000; // 5秒,单位毫秒
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void execute(D331RtcmMessage message) {
|
public Void execute(D331RtcmMessage message) {
|
||||||
@ -59,158 +65,14 @@ public class D331RtcmMessageExecutor implements Executor<D331RtcmMessage, Void>
|
|||||||
|
|
||||||
// 推送基站数据
|
// 推送基站数据
|
||||||
if(deviceBs.getOpMode() == GnssDevice.OP_MODE_USE) {
|
if(deviceBs.getOpMode() == GnssDevice.OP_MODE_USE) {
|
||||||
|
if(deviceBs.getDeviceType()==GnssDevice.TYPE_REFERENCE_STATION) {
|
||||||
byte[] forwardBytes = message.getSrcData();
|
byte[] forwardBytes = message.getSrcData();
|
||||||
// 要求快速转发,因此用缓存,不要每次都查数据库
|
sendToRovers(deviceBs, forwardBytes);
|
||||||
List<Device> deviceList = deviceService.findByParentId(id);
|
|
||||||
//logger.debug("base station {} has {} rovers: ", message.getId(),deviceList.size());
|
|
||||||
DeviceChannel deviceChannel = null;
|
|
||||||
for (Device device : deviceList) {
|
|
||||||
if (device.getOpMode() != GnssDevice.OP_MODE_USE) continue;
|
|
||||||
if ((device.getModel()==GnssDevice.MODEL_G510) &&
|
|
||||||
(device.getFixedNum()>100) && (device.getGnssSampleRate()>1)
|
|
||||||
&& (deviceBs.getD3xxCount()%device.getGnssSampleRate()) != 0) {
|
|
||||||
//if(!UBXUtil.has1005(forwardBytes)) continue; //1005必推
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String deviceId = device.getDeviceId();
|
|
||||||
// 获取设备通道并发送数据
|
|
||||||
if(device.getDataChannelType() == Device.CHANNEL_TYPE_UDP) {
|
|
||||||
deviceChannel = OnlineChannels.INSTANCE.getDataChannel(deviceId);
|
|
||||||
} else {
|
|
||||||
deviceChannel = OnlineChannels.INSTANCE.getConfigChannel(deviceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取数据库中model字段,判断基站类型
|
|
||||||
Short baseStationModel = deviceBs.getModel();
|
|
||||||
// 如果model为null,使用默认值0
|
|
||||||
if (baseStationModel == null) {
|
|
||||||
baseStationModel = 0;
|
|
||||||
logger.warn("Base station model is null for device: {}, using default value 0", id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (baseStationModel == 1) {
|
|
||||||
// 基站类型为1,正常执行
|
|
||||||
if(deviceChannel != null && deviceChannel.isOnline()) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("forward d331 rtcm from {} to device {}", id, deviceId);
|
|
||||||
}
|
|
||||||
ByteBuf buf = Unpooled.buffer();
|
|
||||||
buf.writeBytes(forwardBytes);
|
|
||||||
deviceChannel.writeAndFlush(buf);
|
|
||||||
}
|
|
||||||
} else if (baseStationModel == 0) {
|
|
||||||
//logger.info("Base station model is 0 for device: {}", deviceId);
|
|
||||||
|
|
||||||
Short deviceModel = device.getModel();
|
|
||||||
// 如果model为null,使用默认值0
|
|
||||||
if (deviceModel == null) {
|
|
||||||
deviceModel = 0;
|
|
||||||
//logger.warn("Device model is null for device: {}, using default value 0", deviceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(deviceModel == 0){
|
|
||||||
// 测站类型为0,正常执行
|
|
||||||
if(deviceId.startsWith("2307")){
|
|
||||||
// 处理2307型号的测站
|
|
||||||
forwardBytes[2] = (byte) (forwardBytes[2] & 0x07);//兼容不带序号的测站
|
|
||||||
}
|
|
||||||
// 对所有测站类型为0的设备执行转发
|
|
||||||
if(deviceChannel != null && deviceChannel.isOnline()) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("forward d331 rtcm from {} to device {}", id, deviceId);
|
|
||||||
}
|
|
||||||
ByteBuf buf = Unpooled.buffer();
|
|
||||||
buf.writeBytes(forwardBytes);
|
|
||||||
deviceChannel.writeAndFlush(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(deviceModel == 1){
|
|
||||||
//logger.info("Device model is 1 for device: {}", deviceId);
|
|
||||||
|
|
||||||
if(deviceChannel != null && deviceChannel.isOnline()) {
|
|
||||||
//logger.info("Device channel is online for device: {}", deviceId);
|
|
||||||
|
|
||||||
ByteBuf buf = Unpooled.buffer();
|
|
||||||
buf.writeBytes(forwardBytes);
|
|
||||||
|
|
||||||
// 检查是否满足10秒转发间隔,只有满足条件时才添加D300字符串
|
|
||||||
long currentTime = System.currentTimeMillis();
|
|
||||||
Long lastForwardTime = lastD300ForwardTimeMap.getOrDefault(deviceId, 0L);
|
|
||||||
|
|
||||||
if(currentTime - lastForwardTime >= D300_FORWARD_INTERVAL) {
|
|
||||||
//logger.info("Adding D300 string for device: {}", deviceId);
|
|
||||||
|
|
||||||
// 获取当前buf中的数据
|
|
||||||
byte[] originalData = buf.array();
|
|
||||||
String originalHex = ByteUtil.bytesToHexString(originalData);
|
|
||||||
|
|
||||||
// 找到D300和D301的位置
|
|
||||||
int d300Index = originalHex.indexOf("d300");
|
|
||||||
int d301Index = originalHex.indexOf("d301");
|
|
||||||
|
|
||||||
// 确定插入位置:如果两个都存在,取位置靠前的;如果只存在一个,就用那个位置
|
|
||||||
int insertIndex = -1;
|
|
||||||
if (d300Index != -1 && d301Index != -1) {
|
|
||||||
// 两个都存在,取位置靠前的
|
|
||||||
insertIndex = (d300Index < d301Index) ? d300Index : d301Index;
|
|
||||||
//logger.info("Found both D300 and D301, D300 at {}, D301 at {}, will insert before position {}",
|
|
||||||
/// d300Index, d301Index, insertIndex);
|
|
||||||
} else if (d300Index != -1) {
|
|
||||||
insertIndex = d300Index;
|
|
||||||
//logger.info("Found D300 at position {}", d300Index);
|
|
||||||
} else if (d301Index != -1) {
|
|
||||||
insertIndex = d301Index;
|
|
||||||
//logger.info("Found D301 at position {}", d301Index);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (insertIndex != -1) {
|
|
||||||
// 创建新的buf
|
|
||||||
ByteBuf newBuf = Unpooled.buffer();
|
|
||||||
// 写入D300/D301之前的数据
|
|
||||||
newBuf.writeBytes(originalData, 0, insertIndex / 2);
|
|
||||||
|
|
||||||
// 使用f9p坐标生成1005消息,并插入
|
|
||||||
double[] ecef =new double[3];
|
|
||||||
ecef[0] = deviceBs.getEcefx();
|
|
||||||
ecef[1] = deviceBs.getEcefy();
|
|
||||||
ecef[2] = deviceBs.getEcefz();
|
|
||||||
String rtcm1005 = Rtcm1005.generateRtcm1005Hex(ecef, 0);
|
|
||||||
if (rtcm1005 != null) {
|
|
||||||
// 写入RTCM 1005消息
|
|
||||||
byte[] rtcm1005Bytes = ByteUtil.hexStringTobyte(rtcm1005);
|
|
||||||
newBuf.writeBytes(rtcm1005Bytes);
|
|
||||||
// logger.info("Generated RTCM 1005 message for base station {}: {}", deviceBs.getDeviceId(), rtcm1005);
|
|
||||||
} else {
|
|
||||||
//logger.warn("Failed to generate RTCM 1005 message for base station: {}", deviceBs.getDeviceId());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写入剩余的数据
|
|
||||||
newBuf.writeBytes(originalData, insertIndex / 2, originalData.length - insertIndex / 2);
|
|
||||||
|
|
||||||
// 更新buf
|
|
||||||
buf = newBuf;
|
|
||||||
|
|
||||||
// 添加日志,记录插入位置和完整数据
|
|
||||||
// logger.info("Inserted RTCM 1005 message before position {}, complete data: {}",
|
|
||||||
// insertIndex,
|
|
||||||
// ByteUtil.bytesToHexString(buf.array()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新最后转发时间
|
|
||||||
lastD300ForwardTimeMap.put(deviceId, currentTime);
|
|
||||||
|
|
||||||
// 添加日志,记录测站转发的完整数据
|
|
||||||
//logger.info("Forward data to device: {}, time: {}, complete data: {}",
|
|
||||||
// deviceId,
|
|
||||||
// LocalDateTime.now(),
|
|
||||||
// ByteUtil.bytesToHexString(buf.array()));
|
|
||||||
}
|
|
||||||
|
|
||||||
deviceChannel.writeAndFlush(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
ThreadManager.getFixedThreadPool().submit(() -> {
|
||||||
|
gnssCalcService.calcSingle(message, true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,12 +119,17 @@ public class D331RtcmMessageExecutor implements Executor<D331RtcmMessage, Void>
|
|||||||
deviceBs.setLatitude(gga.getLatitude());
|
deviceBs.setLatitude(gga.getLatitude());
|
||||||
deviceBs.setLongitude(gga.getLongitude());
|
deviceBs.setLongitude(gga.getLongitude());
|
||||||
deviceBs.setAltitude(gga.getAltitude());
|
deviceBs.setAltitude(gga.getAltitude());
|
||||||
|
deviceBs.setGeoidSeparation(gga.getGeoidSeparation());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加NTRIP处理
|
// 添加NTRIP处理
|
||||||
|
if(deviceBs.getForwardToNtrip()) {
|
||||||
byte[] srcdata = message.getSrcData();
|
byte[] srcdata = message.getSrcData();
|
||||||
String rtcm = ByteUtil.bytesToHexString(srcdata);
|
String rtcm = ByteUtil.bytesToHexString(srcdata);
|
||||||
sendToNtrip(id, rtcm);
|
sendToNtrip(id, rtcm);
|
||||||
|
rtkClusterService.sendRtcm(id, rtcm);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ThreadManager.getFixedThreadPool().submit(() -> {
|
ThreadManager.getFixedThreadPool().submit(() -> {
|
||||||
// 原始码流输出到日志文件 -- INFO 级别
|
// 原始码流输出到日志文件 -- INFO 级别
|
||||||
@ -275,6 +142,130 @@ public class D331RtcmMessageExecutor implements Executor<D331RtcmMessage, Void>
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendToRovers(Device deviceBs, byte[] forwardBytes){
|
||||||
|
List<Device> deviceList = deviceService.findByParentId(deviceBs.getDeviceId());
|
||||||
|
//logger.debug("base station {} has {} rovers: ", message.getId(),deviceList.size());
|
||||||
|
DeviceChannel deviceChannel = null;
|
||||||
|
|
||||||
|
for (Device device : deviceList) {
|
||||||
|
// 不是使用状态不推送
|
||||||
|
if (device.getOpMode() != GnssDevice.OP_MODE_USE) continue;
|
||||||
|
// 间隔推送
|
||||||
|
if ((device.getModel()==GnssDevice.MODEL_G510) &&
|
||||||
|
(device.getFixedNum()>100) && (device.getGnssSampleRate()>1)
|
||||||
|
&& (deviceBs.getD3xxCount()%device.getGnssSampleRate()) != 0) {
|
||||||
|
//if(!UBXUtil.has1005(forwardBytes)) continue; //1005必推
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 不在线的不推送
|
||||||
|
String deviceId = device.getDeviceId();
|
||||||
|
// 获取设备通道并发送数据
|
||||||
|
if(device.getDataChannelType() == Device.CHANNEL_TYPE_UDP) {
|
||||||
|
deviceChannel = OnlineChannels.INSTANCE.getDataChannel(deviceId);
|
||||||
|
} else {
|
||||||
|
deviceChannel = OnlineChannels.INSTANCE.getConfigChannel(deviceId);
|
||||||
|
}
|
||||||
|
if(deviceChannel == null || !deviceChannel.isOnline()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//推送
|
||||||
|
if(deviceId.startsWith("2307")){
|
||||||
|
// 处理2307型号的测站
|
||||||
|
forwardBytes[2] = (byte) (forwardBytes[2] & 0x07);//兼容不带序号的测站
|
||||||
|
}
|
||||||
|
// 对所有测站类型为0的设备执行转发
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("forward d331 rtcm from {} to device {}", deviceBs.getDeviceId(), deviceId);
|
||||||
|
}
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
buf.writeBytes(forwardBytes);
|
||||||
|
|
||||||
|
//推送策略:F9P基站(505)兼容博通(510)推送
|
||||||
|
if ((deviceBs.getModel()==null || deviceBs.getModel() == GnssDevice.MODEL_G505) &&
|
||||||
|
(device.getModel()!=null && device.getModel()==GnssDevice.MODEL_G510)){
|
||||||
|
buf = insert1005(deviceBs, deviceId, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceChannel.writeAndFlush(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ByteBuf insert1005(Device deviceBs, String deviceId, ByteBuf buf){
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
Long lastForwardTime = lastD300ForwardTimeMap.getOrDefault(deviceId, 0L);
|
||||||
|
|
||||||
|
ByteBuf buf1005 = buf;
|
||||||
|
|
||||||
|
// 检查是否满足10秒转发间隔,只有满足条件时才添加D300字符串
|
||||||
|
if(currentTime - lastForwardTime >= D300_FORWARD_INTERVAL) {
|
||||||
|
//logger.info("Adding D300 string for device: {}", deviceId);
|
||||||
|
|
||||||
|
// 获取当前buf中的数据
|
||||||
|
byte[] originalData = buf.array();
|
||||||
|
String originalHex = ByteUtil.bytesToHexString(originalData);
|
||||||
|
|
||||||
|
// 找到D300和D301的位置
|
||||||
|
int d300Index = originalHex.indexOf("d300");
|
||||||
|
int d301Index = originalHex.indexOf("d301");
|
||||||
|
|
||||||
|
// 确定插入位置:如果两个都存在,取位置靠前的;如果只存在一个,就用那个位置
|
||||||
|
int insertIndex = -1;
|
||||||
|
if (d300Index != -1 && d301Index != -1) {
|
||||||
|
// 两个都存在,取位置靠前的
|
||||||
|
insertIndex = (d300Index < d301Index) ? d300Index : d301Index;
|
||||||
|
//logger.info("Found both D300 and D301, D300 at {}, D301 at {}, will insert before position {}",
|
||||||
|
/// d300Index, d301Index, insertIndex);
|
||||||
|
} else if (d300Index != -1) {
|
||||||
|
insertIndex = d300Index;
|
||||||
|
//logger.info("Found D300 at position {}", d300Index);
|
||||||
|
} else if (d301Index != -1) {
|
||||||
|
insertIndex = d301Index;
|
||||||
|
//logger.info("Found D301 at position {}", d301Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (insertIndex != -1) {
|
||||||
|
// 创建新的buf
|
||||||
|
buf1005 = Unpooled.buffer();
|
||||||
|
// 写入D300/D301之前的数据
|
||||||
|
buf1005.writeBytes(originalData, 0, insertIndex / 2);
|
||||||
|
|
||||||
|
// 使用f9p坐标生成1005消息,并插入
|
||||||
|
double[] ecef =new double[3];
|
||||||
|
ecef[0] = deviceBs.getEcefx();
|
||||||
|
ecef[1] = deviceBs.getEcefy();
|
||||||
|
ecef[2] = deviceBs.getEcefz();
|
||||||
|
String rtcm1005 = Rtcm1005.generateRtcm1005Hex(ecef, 0);
|
||||||
|
if (rtcm1005 != null) {
|
||||||
|
// 写入RTCM 1005消息
|
||||||
|
byte[] rtcm1005Bytes = ByteUtil.hexStringTobyte(rtcm1005);
|
||||||
|
buf1005.writeBytes(rtcm1005Bytes);
|
||||||
|
// logger.info("Generated RTCM 1005 message for base station {}: {}", deviceBs.getDeviceId(), rtcm1005);
|
||||||
|
} else {
|
||||||
|
//logger.warn("Failed to generate RTCM 1005 message for base station: {}", deviceBs.getDeviceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入剩余的数据
|
||||||
|
buf1005.writeBytes(originalData, insertIndex / 2, originalData.length - insertIndex / 2);
|
||||||
|
|
||||||
|
// 添加日志,记录插入位置和完整数据
|
||||||
|
// logger.info("Inserted RTCM 1005 message before position {}, complete data: {}",
|
||||||
|
// insertIndex,
|
||||||
|
// ByteUtil.bytesToHexString(buf.array()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新最后转发时间
|
||||||
|
lastD300ForwardTimeMap.put(deviceId, currentTime);
|
||||||
|
|
||||||
|
// 添加日志,记录测站转发的完整数据
|
||||||
|
//logger.info("Forward data to device: {}, time: {}, complete data: {}",
|
||||||
|
// deviceId,
|
||||||
|
// LocalDateTime.now(),
|
||||||
|
// ByteUtil.bytesToHexString(buf.array()));
|
||||||
|
}
|
||||||
|
return buf1005;
|
||||||
|
}
|
||||||
|
|
||||||
private void sendToNtrip(String mountpoint, String hexData) {
|
private void sendToNtrip(String mountpoint, String hexData) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,47 @@
|
|||||||
|
package com.imdroid.sideslope.executor;
|
||||||
|
|
||||||
|
import com.imdroid.common.util.ThreadManager;
|
||||||
|
import com.imdroid.secapi.dto.*;
|
||||||
|
import com.imdroid.sideslope.message.D350SurfaceInclineMessage;
|
||||||
|
import com.imdroid.sideslope.service.Device;
|
||||||
|
import com.imdroid.sideslope.service.DeviceService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Layton
|
||||||
|
* @date 2023/2/2 20:40
|
||||||
|
* 1、回ACK,以便终端判断是否连接上服务器后台
|
||||||
|
* 2、同步参数
|
||||||
|
* 3、判断是否发冷启动指令
|
||||||
|
* 4、保存状态信息,判断是否有低电压等告警,清除离线告警
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class D350SurfaceInclineMessageExecutor implements Executor<D350SurfaceInclineMessage, Void> {
|
||||||
|
@Autowired
|
||||||
|
SurfaceInclineDataMapper dataMapper;
|
||||||
|
@Autowired
|
||||||
|
private DeviceService deviceService;
|
||||||
|
@Override
|
||||||
|
public Void execute(D350SurfaceInclineMessage message) {
|
||||||
|
Device device = deviceService.findByDeviceId(message.getId());
|
||||||
|
if(device == null) return null;
|
||||||
|
// 补齐tenantId
|
||||||
|
message.getInclineData().setTenantid(device.getTenantId());
|
||||||
|
|
||||||
|
ThreadManager.getFixedThreadPool().submit(() -> {
|
||||||
|
|
||||||
|
//保存状态信息,判断是否有低电压等告警,清除离线告警
|
||||||
|
dataMapper.insert(message.getInclineData());
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getMessageType() {
|
||||||
|
return D350SurfaceInclineMessage.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,32 +0,0 @@
|
|||||||
package com.imdroid.sideslope.executor;
|
|
||||||
|
|
||||||
import com.imdroid.sideslope.message.D350TestMessage;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Layton
|
|
||||||
* @date 2023/2/2 20:40
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class D350TestMessageExecutor implements Executor<D350TestMessage, Void> {
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void execute(D350TestMessage message) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("device {} max acc(g) in 1s: x={},y={},z={}",message.getId(),
|
|
||||||
message.getAccX(),message.getAccY(),message.getAccZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> getMessageType() {
|
|
||||||
return D350TestMessage.class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -36,7 +36,7 @@ public class MessageParser {
|
|||||||
types.put((short)0xd31A, D31xConfigAckMessage.class);//DTU配置应答
|
types.put((short)0xd31A, D31xConfigAckMessage.class);//DTU配置应答
|
||||||
types.put((short)0xd31B, D31xConfigAckMessage.class);//LORA配置应答
|
types.put((short)0xd31B, D31xConfigAckMessage.class);//LORA配置应答
|
||||||
types.put((short)0xd320, D31xConfigAckMessage.class);//v3.2 DTU配置应答
|
types.put((short)0xd320, D31xConfigAckMessage.class);//v3.2 DTU配置应答
|
||||||
types.put((short)0xd350, D350TestMessage.class);//ACC上报
|
types.put((short)0xd350, D350SurfaceInclineMessage.class);//ACC上报
|
||||||
types.put((short)0xd314, D314PingMessage.class);//ping
|
types.put((short)0xd314, D314PingMessage.class);//ping
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,50 @@
|
|||||||
|
package com.imdroid.sideslope.message;
|
||||||
|
|
||||||
|
import com.imdroid.secapi.dto.SurfaceInclineData;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自检消息
|
||||||
|
*
|
||||||
|
* @author Layton
|
||||||
|
* @date 2023/2/2 20:38
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper=true)
|
||||||
|
@Data
|
||||||
|
public class D350SurfaceInclineMessage extends BaseMessage {
|
||||||
|
|
||||||
|
SurfaceInclineData inclineData = new SurfaceInclineData();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decodeBody(ByteBuf src) {
|
||||||
|
// d3 50 length(2bytes) device_id(4bytes) seq(2bytes) data
|
||||||
|
this.len = src.readableBytes(); // total length
|
||||||
|
this.header = src.readUnsignedShort();// flag
|
||||||
|
src.readUnsignedShort();// d342 length
|
||||||
|
this.id = String.valueOf(src.readUnsignedInt());//id
|
||||||
|
this.seq = src.readUnsignedShort();
|
||||||
|
|
||||||
|
inclineData.setDeviceid(getId());
|
||||||
|
inclineData.setCreatetime(createTime);
|
||||||
|
|
||||||
|
inclineData.setSensorid(src.readUnsignedByte());
|
||||||
|
inclineData.setAnglex(src.readFloat());
|
||||||
|
inclineData.setAngley(src.readFloat());
|
||||||
|
inclineData.setAnglez(src.readFloat());
|
||||||
|
inclineData.setAccx(src.readFloat());
|
||||||
|
inclineData.setAccy(src.readFloat());
|
||||||
|
inclineData.setAccz(src.readFloat());
|
||||||
|
inclineData.setMaxaccx(src.readFloat());
|
||||||
|
inclineData.setMaxaccy(src.readFloat());
|
||||||
|
inclineData.setMaxaccz(src.readFloat());
|
||||||
|
inclineData.setMinaccx(src.readFloat());
|
||||||
|
inclineData.setMinaccy(src.readFloat());
|
||||||
|
inclineData.setMinaccz(src.readFloat());
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean shouldDecodeHeader() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,25 +0,0 @@
|
|||||||
package com.imdroid.sideslope.message;
|
|
||||||
|
|
||||||
import com.imdroid.sideslope.bd.Gga;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Layton
|
|
||||||
* @date 2023/2/2 20:50
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper=true)
|
|
||||||
public class D350TestMessage extends BaseMessage {
|
|
||||||
double accX;
|
|
||||||
double accY;
|
|
||||||
double accZ;
|
|
||||||
Gga gga;
|
|
||||||
@Override
|
|
||||||
public void decodeBody(ByteBuf src) {
|
|
||||||
accX = src.readFloat();
|
|
||||||
accY = src.readFloat();
|
|
||||||
accZ = src.readFloat();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
package com.imdroid.sideslope.ntrip;
|
||||||
|
|
||||||
|
import com.imdroid.secapi.dto.RtkrcvProfile;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class RtkrcvConfigService {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(RtkrcvConfigService.class);
|
||||||
|
|
||||||
|
@Value("${rtkrcv.workdir:/opt/rtk}")
|
||||||
|
private String defaultWorkDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate an RTKLIB rtkrcv config file from template using profile values.
|
||||||
|
* The file will be saved to `${rtkrcv.workdir:/opt/rtk}/rtkrcv_{deviceId}.conf`.
|
||||||
|
*/
|
||||||
|
public Path generateConfig(RtkrcvProfile profile) throws IOException {
|
||||||
|
return generateConfig(profile, java.nio.file.Paths.get(defaultWorkDir));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate an RTKLIB rtkrcv config file from the classpath template `rtkrcv_default.conf`.
|
||||||
|
* Only the following keys are substituted: inpstr1-path, inpstr2-path, inpstr3-path, out-height.
|
||||||
|
* The output filename will be `rtkrcv_{deviceId}.conf` under the provided outputDir.
|
||||||
|
*/
|
||||||
|
public Path generateConfig(RtkrcvProfile profile, Path outputDir) throws IOException {
|
||||||
|
if (profile == null) throw new IllegalArgumentException("profile must not be null");
|
||||||
|
if (profile.getDeviceId() == null || profile.getDeviceId().trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("profile.deviceId must not be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> lines = readTemplateLines();
|
||||||
|
|
||||||
|
List<String> rendered = new ArrayList<>(lines.size());
|
||||||
|
for (String line : lines) {
|
||||||
|
String replaced = line;
|
||||||
|
replaced = replaceValueLine(replaced, "inpstr1-path", nz(profile.getInpstr1Path()));
|
||||||
|
replaced = replaceValueLine(replaced, "inpstr2-path", nz(profile.getInpstr2Path()));
|
||||||
|
replaced = replaceValueLine(replaced, "inpstr3-path", nz(profile.getInpstr3Path()));
|
||||||
|
replaced = replaceValueLine(replaced, "outstr1-path", nz(profile.getOutstr1Path()));
|
||||||
|
// If local tcp endpoints are used (e.g., 127.0.0.1:port), force type to tcpcli
|
||||||
|
if (looksLikeTcpEndpoint(profile.getInpstr1Path())) {
|
||||||
|
replaced = replaceValueLine(replaced, "inpstr1-type", "tcpcli");
|
||||||
|
// relax timeouts to avoid frequent reconnects on local streams
|
||||||
|
replaced = replaceValueLine(replaced, "misc-timeout", "300000");
|
||||||
|
replaced = replaceValueLine(replaced, "misc-reconnect", "3000");
|
||||||
|
}
|
||||||
|
// For outstr1, if path looks like file, force type to file; if it looks like tcp, force tcpcli
|
||||||
|
if (looksLikeFilePath(profile.getOutstr1Path())) {
|
||||||
|
replaced = replaceValueLine(replaced, "outstr1-type", "file");
|
||||||
|
} else if (looksLikeTcpEndpoint(profile.getOutstr1Path())) {
|
||||||
|
replaced = replaceValueLine(replaced, "outstr1-type", "tcpcli");
|
||||||
|
replaced = replaceValueLine(replaced, "misc-timeout", "300000");
|
||||||
|
replaced = replaceValueLine(replaced, "misc-reconnect", "3000");
|
||||||
|
}
|
||||||
|
Integer outHeight = profile.getOutHeight();
|
||||||
|
int heightValue = (outHeight == null) ? 1 : (outHeight == 0 ? 0 : 1);
|
||||||
|
replaced = replaceValueLine(replaced, "out-height", String.valueOf(heightValue));
|
||||||
|
rendered.add(replaced);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Files.exists(outputDir)) {
|
||||||
|
Files.createDirectories(outputDir);
|
||||||
|
}
|
||||||
|
Path out = outputDir.resolve("rtkrcv_" + profile.getDeviceId() + ".conf");
|
||||||
|
try (BufferedWriter writer = Files.newBufferedWriter(out, StandardCharsets.UTF_8)) {
|
||||||
|
for (String l : rendered) {
|
||||||
|
writer.write(l);
|
||||||
|
writer.newLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOGGER.info("Generated rtkrcv config: {}", out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> readTemplateLines() throws IOException {
|
||||||
|
ClassPathResource resource = new ClassPathResource("rtkrcv_default.conf");
|
||||||
|
if (!resource.exists()) {
|
||||||
|
throw new IOException("Template rtkrcv_default.conf not found on classpath");
|
||||||
|
}
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
lines.add(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String nz(String s) {
|
||||||
|
return s == null ? "" : s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean looksLikeTcpEndpoint(String path) {
|
||||||
|
if (path == null) return false;
|
||||||
|
String p = path.trim();
|
||||||
|
// Plain host:port without '@' credentials or path '/' considered tcp endpoint
|
||||||
|
return p.contains(":") && !p.contains("@") && !p.contains("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean looksLikeFilePath(String path) {
|
||||||
|
if (path == null) return false;
|
||||||
|
String p = path.trim();
|
||||||
|
return p.startsWith("/") || p.startsWith("./") || p.startsWith("../");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the value of a line like: "key = value # comment" while preserving spacing and comment.
|
||||||
|
*/
|
||||||
|
private String replaceValueLine(String line, String key, String newValue) {
|
||||||
|
String regex = "^(\\s*" + key + "\\s*=\\s*)([^#]*?)(\\s*(#.*)?)$";
|
||||||
|
Pattern p = Pattern.compile(regex);
|
||||||
|
Matcher m = p.matcher(line);
|
||||||
|
if (!m.find()) return line;
|
||||||
|
String prefix = m.group(1);
|
||||||
|
String suffix = m.group(3) == null ? "" : m.group(3);
|
||||||
|
String value = newValue == null ? "" : newValue.trim();
|
||||||
|
return prefix + value + suffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,6 +20,8 @@ public class UdpNtripServer {
|
|||||||
private final Logger logger = LoggerFactory.getLogger(UdpNtripServer.class);
|
private final Logger logger = LoggerFactory.getLogger(UdpNtripServer.class);
|
||||||
@Value("${ntrip_server.port:9903}")
|
@Value("${ntrip_server.port:9903}")
|
||||||
private Integer port;
|
private Integer port;
|
||||||
|
@Value("${ntrip_server.host:localhost}")
|
||||||
|
private String host;
|
||||||
private DatagramSocket socket;
|
private DatagramSocket socket;
|
||||||
private DatagramPacket outPacket;
|
private DatagramPacket outPacket;
|
||||||
|
|
||||||
@ -33,7 +35,7 @@ public class UdpNtripServer {
|
|||||||
try{
|
try{
|
||||||
//随机端口
|
//随机端口
|
||||||
if(socket == null) socket = new DatagramSocket();
|
if(socket == null) socket = new DatagramSocket();
|
||||||
if(outPacket == null) outPacket = new DatagramPacket(new byte[0],0, InetAddress.getByName("localhost"),port);
|
if(outPacket == null) outPacket = new DatagramPacket(new byte[0],0, InetAddress.getByName(host),port);
|
||||||
outPacket.setData(encode(ByteUtil.addBytes(mount.getBytes(), ByteUtil.hexStringTobyte(hexRtcm))));
|
outPacket.setData(encode(ByteUtil.addBytes(mount.getBytes(), ByteUtil.hexStringTobyte(hexRtcm))));
|
||||||
socket.send(outPacket);
|
socket.send(outPacket);
|
||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
|
|||||||
@ -0,0 +1,276 @@
|
|||||||
|
package com.imdroid.sideslope.rtkcluster;
|
||||||
|
|
||||||
|
import com.imdroid.common.util.ByteUtil;
|
||||||
|
import com.imdroid.secapi.dto.RtkrcvProfile;
|
||||||
|
import com.imdroid.secapi.dto.RtkrcvProfileMapper;
|
||||||
|
import com.imdroid.secapi.dto.RtkrcvSession;
|
||||||
|
import com.imdroid.secapi.dto.RtkrcvSessionMapper;
|
||||||
|
import com.imdroid.sideslope.bd.RtcmGgaUtil;
|
||||||
|
import com.imdroid.sideslope.ntrip.RtkrcvConfigService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.ApplicationArguments;
|
||||||
|
import org.springframework.boot.ApplicationRunner;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RtkCluster: per-device TCP server that ONLY sends RTCM to rtkrcv (single purpose).
|
||||||
|
* - For each deviceId, we create a local server bound to 127.0.0.1:workPort.
|
||||||
|
* - rtkrcv (tcpcli) connects to this port to receive RTCM; we do not read solution via TCP anymore.
|
||||||
|
* - rtkrcv writes its solution to file (configured via outstr1-*).
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class RtkClusterService implements ApplicationRunner {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(RtkClusterService.class);
|
||||||
|
|
||||||
|
@Value("${rtk.cluster.basePort:24000}")
|
||||||
|
private int basePort;
|
||||||
|
|
||||||
|
@Value("${rtkrcv.workdir:/opt/rtk}")
|
||||||
|
private String rtkWorkDir;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RtkrcvProfileMapper profileMapper;
|
||||||
|
@Autowired
|
||||||
|
private RtkrcvSessionMapper sessionMapper;
|
||||||
|
@Autowired
|
||||||
|
private RtkrcvConfigService configService;
|
||||||
|
|
||||||
|
private final Map<String, DeviceEndpoint> endpoints = new ConcurrentHashMap<>();
|
||||||
|
private final Map<String, Process> processes = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private final ExecutorService worker = Executors.newCachedThreadPool(r -> {
|
||||||
|
Thread t = new Thread(r, "rtkcluster-worker");
|
||||||
|
t.setDaemon(true);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(ApplicationArguments args) {
|
||||||
|
// Load all profiles and bootstrap endpoints and sessions.
|
||||||
|
List<RtkrcvProfile> profiles = profileMapper.selectList(null);
|
||||||
|
if (profiles == null || profiles.isEmpty()) {
|
||||||
|
LOGGER.info("No rtkrcv_profile records found. RtkCluster idle.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int slot = 1;
|
||||||
|
for (RtkrcvProfile profile : profiles) {
|
||||||
|
try {
|
||||||
|
int port = basePort + slot++;
|
||||||
|
bootstrapDevice(profile, port);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("Bootstrap device {} failed: {}", profile.getDeviceId(), e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bootstrapDevice(RtkrcvProfile profile, int workPort) throws IOException {
|
||||||
|
String deviceId = profile.getDeviceId();
|
||||||
|
// 1) Start endpoint server (if not exists)
|
||||||
|
endpoints.computeIfAbsent(deviceId, k -> new DeviceEndpoint(workPort));
|
||||||
|
DeviceEndpoint ep = endpoints.get(deviceId);
|
||||||
|
ep.ensureStarted();
|
||||||
|
|
||||||
|
// 2) Update profile inpstr1 to local cluster port, and outstr1 to per-device file
|
||||||
|
String localPath = "127.0.0.1:" + workPort;
|
||||||
|
profile.setInpstr1Path(localPath);
|
||||||
|
String outFile = rtkWorkDir + "/" + deviceId + "_llh.log";
|
||||||
|
profile.setOutstr1Path(outFile);
|
||||||
|
profileMapper.updateById(profile);
|
||||||
|
|
||||||
|
// 3) Generate config and start rtkrcv
|
||||||
|
Path conf = configService.generateConfig(profile);
|
||||||
|
// 4) Insert session with rtk_conf_path present
|
||||||
|
RtkrcvSession session = new RtkrcvSession();
|
||||||
|
session.setDeviceId(deviceId);
|
||||||
|
session.setState("starting");
|
||||||
|
session.setWorkDir(rtkWorkDir);
|
||||||
|
session.setWorkPort(workPort);
|
||||||
|
session.setRtkConfPath(conf.toString());
|
||||||
|
session.setCreatedAt(LocalDateTime.now());
|
||||||
|
session.setUpdatedAt(LocalDateTime.now());
|
||||||
|
sessionMapper.insert(session);
|
||||||
|
|
||||||
|
startRtkrcv(deviceId, conf.getParent().toString(), conf.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startRtkrcv(String deviceId, String workDir, String confPath) {
|
||||||
|
if (processes.containsKey(deviceId)) {
|
||||||
|
Process p = processes.get(deviceId);
|
||||||
|
if (p != null && p.isAlive()) {
|
||||||
|
LOGGER.warn("rtkrcv for {} already running", deviceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
worker.submit(() -> {
|
||||||
|
try {
|
||||||
|
ProcessBuilder builder = new ProcessBuilder("rtkrcv", "-nc", "-o", confPath);
|
||||||
|
builder.directory(new File(workDir));
|
||||||
|
builder.redirectErrorStream(true);
|
||||||
|
LOGGER.info("Starting rtkrcv for {} with {}", deviceId, confPath);
|
||||||
|
Process p = builder.start();
|
||||||
|
processes.put(deviceId, p);
|
||||||
|
// async log stdout
|
||||||
|
logOutput(deviceId, p);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.error("Failed to start rtkrcv for {}: {}", deviceId, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logOutput(String deviceId, Process p) {
|
||||||
|
worker.submit(() -> {
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
LOGGER.info("[rtkrcv:{}] {}", deviceId, line);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.warn("Error reading rtkrcv output for {}: {}", deviceId, e.getMessage());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
int code = p.waitFor();
|
||||||
|
LOGGER.info("rtkrcv for {} exited with {}", deviceId, code);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendRtcm(String deviceId, String hexRtcm) {
|
||||||
|
DeviceEndpoint ep = endpoints.get(deviceId);
|
||||||
|
if (ep == null || hexRtcm == null || hexRtcm.isEmpty()) return;
|
||||||
|
try {
|
||||||
|
List<String> frames = RtcmGgaUtil.getRtcms(hexRtcm);
|
||||||
|
if (frames != null && !frames.isEmpty()) {
|
||||||
|
for (String f : frames) {
|
||||||
|
if (f != null && !f.isEmpty()) {
|
||||||
|
ep.enqueueRtcm(ByteUtil.hexStringTobyte(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignore) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendRtcmBytes(String deviceId, byte[] data) {
|
||||||
|
if (data == null || data.length == 0) return;
|
||||||
|
DeviceEndpoint ep = endpoints.get(deviceId);
|
||||||
|
if (ep == null) return;
|
||||||
|
ep.enqueueRtcm(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DeviceEndpoint {
|
||||||
|
private final int port;
|
||||||
|
private final ExecutorService exec;
|
||||||
|
private volatile boolean started = false;
|
||||||
|
private volatile ServerSocket server;
|
||||||
|
// Single sink connection where we WRITE RTCM to rtkrcv tcpcli
|
||||||
|
private volatile Socket sink;
|
||||||
|
private final java.util.concurrent.LinkedBlockingDeque<byte[]> rtcmQueue = new java.util.concurrent.LinkedBlockingDeque<>(1024);
|
||||||
|
|
||||||
|
DeviceEndpoint(int port) {
|
||||||
|
this.port = port;
|
||||||
|
this.exec = Executors.newCachedThreadPool(r -> {
|
||||||
|
Thread t = new Thread(r, "rtkcluster-ep-" + this.port);
|
||||||
|
t.setDaemon(true);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void ensureStarted() {
|
||||||
|
if (started) return;
|
||||||
|
exec.submit(this::acceptLoop);
|
||||||
|
exec.submit(this::dequeueLoop);
|
||||||
|
started = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enqueueRtcm(byte[] data) {
|
||||||
|
if (data == null || data.length == 0) return;
|
||||||
|
if (!rtcmQueue.offerLast(data)) {
|
||||||
|
// queue full: drop oldest to keep stream fresh
|
||||||
|
rtcmQueue.pollFirst();
|
||||||
|
rtcmQueue.offerLast(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void acceptLoop() {
|
||||||
|
try (ServerSocket ss = new ServerSocket()) {
|
||||||
|
ss.setReuseAddress(true);
|
||||||
|
ss.bind(new InetSocketAddress("127.0.0.1", port));
|
||||||
|
this.server = ss;
|
||||||
|
LOGGER.info("RtkCluster device endpoint listening on 127.0.0.1:{}", port);
|
||||||
|
while (true) {
|
||||||
|
Socket s = ss.accept();
|
||||||
|
onAccepted(s);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.error("Device endpoint on {} stopped: {}", port, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void onAccepted(Socket s) {
|
||||||
|
exec.submit(() -> {
|
||||||
|
try {
|
||||||
|
s.setTcpNoDelay(true);
|
||||||
|
s.setKeepAlive(true);
|
||||||
|
} catch (Exception ignore) {}
|
||||||
|
// Always replace previous sink with the latest connection
|
||||||
|
Socket prev = sink;
|
||||||
|
sink = s;
|
||||||
|
if (prev != null && prev != s) {
|
||||||
|
closeQuietly(prev);
|
||||||
|
}
|
||||||
|
LOGGER.info("Endpoint {} sink connected from {}", port, s.getRemoteSocketAddress());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dequeueLoop() {
|
||||||
|
byte[] pending = null;
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
Socket s = sink;
|
||||||
|
if (s == null || s.isClosed()) {
|
||||||
|
LOGGER.info("Endpoint {} waiting for tcpcli to connect before sending RTCM", port);
|
||||||
|
Thread.sleep(50);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (pending == null) {
|
||||||
|
pending = rtcmQueue.pollFirst(100, TimeUnit.MILLISECONDS);
|
||||||
|
if (pending == null) continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
OutputStream os = s.getOutputStream();
|
||||||
|
os.write(pending);
|
||||||
|
os.flush();
|
||||||
|
pending = null; // sent successfully
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.warn("Write RTCM failed on {}: {}", port, e.getMessage());
|
||||||
|
closeQuietly(s);
|
||||||
|
if (sink == s) sink = null;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeQuietly(Socket s) {
|
||||||
|
if (s == null) return;
|
||||||
|
try { s.close(); } catch (IOException ignore) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,12 +3,9 @@ package com.imdroid.sideslope.server;
|
|||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Layton
|
* @author Layton
|
||||||
@ -62,10 +59,6 @@ public class OnlineChannels {
|
|||||||
return Optional.ofNullable(dataChannels.get(deviceId));
|
return Optional.ofNullable(dataChannels.get(deviceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DeviceChannel> ifPresent(List<String> deviceIds) {
|
|
||||||
return deviceIds.stream().map(x -> dataChannels.get(x)).filter(Objects::nonNull).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public DeviceChannel getDataChannel(String deviceId){
|
public DeviceChannel getDataChannel(String deviceId){
|
||||||
return dataChannels.get(deviceId);
|
return dataChannels.get(deviceId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,6 +62,12 @@ public class Device {
|
|||||||
Double latitude;
|
Double latitude;
|
||||||
Double longitude;
|
Double longitude;
|
||||||
Double altitude;
|
Double altitude;
|
||||||
|
|
||||||
|
// 大地水准面相对椭球面的高度差
|
||||||
|
// 博通 GGA 此处可能非零,影响 RTK 运算,故需通过此属性判断。
|
||||||
|
Double geoidSeparation = 0.0;
|
||||||
|
|
||||||
|
|
||||||
Double ecefx;
|
Double ecefx;
|
||||||
Double ecefy;
|
Double ecefy;
|
||||||
Double ecefz;
|
Double ecefz;
|
||||||
@ -69,16 +75,19 @@ public class Device {
|
|||||||
Double iPose;
|
Double iPose;
|
||||||
Double iPosn;
|
Double iPosn;
|
||||||
Double iPosd;
|
Double iPosd;
|
||||||
|
|
||||||
private BigDecimal remaining;
|
private BigDecimal remaining;
|
||||||
private BigDecimal total;
|
private BigDecimal total;
|
||||||
private BigDecimal used;
|
private BigDecimal used;
|
||||||
|
|
||||||
LocalDateTime lastRxTime;
|
LocalDateTime lastRxTime;
|
||||||
|
LocalDateTime lastD3f0f2Time;
|
||||||
LocalDateTime lastD3f2Time;
|
LocalDateTime lastD3f2Time;
|
||||||
short noFixedAndFloatResult=0;
|
short noFixedAndFloatResult=0;
|
||||||
|
|
||||||
// 日志记录控制
|
|
||||||
Short loggingmode;
|
Short loggingmode;// 日志记录控制
|
||||||
|
Boolean forwardToNtrip = false;// NtripCaster 推送控制
|
||||||
|
|
||||||
int lastRxHead = 0;
|
int lastRxHead = 0;
|
||||||
|
|
||||||
@ -89,13 +98,17 @@ public class Device {
|
|||||||
short abnormalD341Num = 0;
|
short abnormalD341Num = 0;
|
||||||
byte cfgChannelType = CHANNEL_TYPE_TCP; // 0:TCP;1:DUP
|
byte cfgChannelType = CHANNEL_TYPE_TCP; // 0:TCP;1:DUP
|
||||||
byte dataChannelType = CHANNEL_TYPE_UDP; // 0:TCP;1:DUP
|
byte dataChannelType = CHANNEL_TYPE_UDP; // 0:TCP;1:DUP
|
||||||
|
int lasQuality = 0;
|
||||||
|
|
||||||
|
// rtkrcv cluster work port (127.0.0.1:port)
|
||||||
|
Integer rtkrcvWorkPort;
|
||||||
|
|
||||||
public void updateRx(int head, int bytes,int count){
|
public void updateRx(int head, int bytes,int count){
|
||||||
lastRxHead = head;
|
lastRxHead = head;
|
||||||
|
|
||||||
switch (head){
|
switch (head){
|
||||||
case 0xd3f0:
|
case 0xd3f0:
|
||||||
//lastD3f0f2Time = LocalDateTime.now();
|
lastD3f0f2Time = LocalDateTime.now();
|
||||||
//clearStat();
|
//clearStat();
|
||||||
break;
|
break;
|
||||||
case 0xd3f2:
|
case 0xd3f2:
|
||||||
@ -110,7 +123,7 @@ public class Device {
|
|||||||
d341Count+=count;
|
d341Count+=count;
|
||||||
d341bytes += bytes;
|
d341bytes += bytes;
|
||||||
lastRxTime = LocalDateTime.now();
|
lastRxTime = LocalDateTime.now();
|
||||||
if(model== GnssDevice.MODEL_G510 && bytes>100) abnormalD341Num++;
|
if(model== GnssDevice.MODEL_G510 && bytes>1400) abnormalD341Num++;
|
||||||
break;
|
break;
|
||||||
case 0xd342:
|
case 0xd342:
|
||||||
d342Count ++;
|
d342Count ++;
|
||||||
@ -128,6 +141,7 @@ public class Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateCalcQuality(int quality){
|
public void updateCalcQuality(int quality){
|
||||||
|
lasQuality = quality;
|
||||||
if(b562AsCalc) {
|
if(b562AsCalc) {
|
||||||
if (quality == UBXUtil.FIX_RESULT) fixedNum++;
|
if (quality == UBXUtil.FIX_RESULT) fixedNum++;
|
||||||
else if (quality == UBXUtil.FLOAT_RESULT) floatNum++;
|
else if (quality == UBXUtil.FLOAT_RESULT) floatNum++;
|
||||||
|
|||||||
@ -51,6 +51,7 @@ public class LocalDeviceServiceImpl implements DeviceService {
|
|||||||
device.setEcefy(gnssDevice.getEcefy());
|
device.setEcefy(gnssDevice.getEcefy());
|
||||||
device.setEcefz(gnssDevice.getEcefz());
|
device.setEcefz(gnssDevice.getEcefz());
|
||||||
device.setLoggingmode(gnssDevice.getLoggingmode());
|
device.setLoggingmode(gnssDevice.getLoggingmode());
|
||||||
|
device.setForwardToNtrip(gnssDevice.getForward_to_ntrip());
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,12 @@ warning.log.directory=./log
|
|||||||
|
|
||||||
ntrip_server.port = 11100
|
ntrip_server.port = 11100
|
||||||
|
|
||||||
|
rtkrcv.enable=true
|
||||||
|
rtkrcv.binary=rtkrcv
|
||||||
|
rtkrcv.config=/opt/rtk/rtk.conf
|
||||||
|
rtkrcv.workdir=/opt/rtk
|
||||||
|
rtk.tcp.port=20001
|
||||||
|
|
||||||
sim.url = http://120.78.169.220:8089
|
sim.url = http://120.78.169.220:8089
|
||||||
sim.username = gzyzdz
|
sim.username = gzyzdz
|
||||||
sim.key = 632629d1269a202c9d49a574623e4e4c
|
sim.key = 632629d1269a202c9d49a574623e4e4c
|
||||||
|
|||||||
162
sec-beidou-rtcm/src/main/resources/rtkrcv_default.conf
Normal file
162
sec-beidou-rtcm/src/main/resources/rtkrcv_default.conf
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
pos1-posmode =static # (0:single,1:dgps,2:kinematic,3:static,4:static-start,5:movingbase,6:fixed,7:ppp-kine,8:ppp-static,9:ppp-fixed)
|
||||||
|
pos1-frequency =l1+l2+l5 # (1:l1,2:l1+l2,3:l1+l2+l5,4:l1+l2+l5+l6)
|
||||||
|
pos1-soltype =forward # (0:forward,1:backward,2:combined,3:combined-nophasereset)
|
||||||
|
pos1-elmask =10 # (deg)
|
||||||
|
pos1-snrmask_r =on # (0:off,1:on)
|
||||||
|
pos1-snrmask_b =on # (0:off,1:on)
|
||||||
|
pos1-snrmask_L1 =0,0,0,0,0,0,0,0,0
|
||||||
|
pos1-snrmask_L2 =0,0,0,0,0,0,0,0,0
|
||||||
|
pos1-snrmask_L5 =0,0,0,0,0,0,0,0,0
|
||||||
|
pos1-dynamics =off # (0:off,1:on)
|
||||||
|
pos1-tidecorr =off # (0:off,1:on,2:otl)
|
||||||
|
pos1-ionoopt =brdc # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc)
|
||||||
|
pos1-tropopt =saas # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad)
|
||||||
|
pos1-sateph =brdc+sbas # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom)
|
||||||
|
pos1-posopt1 =off # (0:off,1:on)
|
||||||
|
pos1-posopt2 =off # (0:off,1:on)
|
||||||
|
pos1-posopt3 =off # (0:off,1:on,2:precise)
|
||||||
|
pos1-posopt4 =off # (0:off,1:on)
|
||||||
|
pos1-posopt5 =off # (0:off,1:on)
|
||||||
|
pos1-posopt6 =off # (0:off,1:on)
|
||||||
|
pos1-exclsats = # (prn ...)
|
||||||
|
pos1-navsys =45 # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:bds+64:navic)
|
||||||
|
pos2-armode =continuous # (0:off,1:continuous,2:instantaneous,3:fix-and-hold)
|
||||||
|
pos2-gloarmode =fix-and-hold # (0:off,1:on,2:autocal,3:fix-and-hold)
|
||||||
|
pos2-bdsarmode =on # (0:off,1:on)
|
||||||
|
pos2-arfilter =on # (0:off,1:on)
|
||||||
|
pos2-arthres =3
|
||||||
|
pos2-arthresmin =2
|
||||||
|
pos2-arthresmax =2
|
||||||
|
pos2-arthres1 =0.1
|
||||||
|
pos2-arthres2 =0
|
||||||
|
pos2-arthres3 =1e-09
|
||||||
|
pos2-arthres4 =1e-05
|
||||||
|
pos2-varholdamb =0.1 # (cyc^2)
|
||||||
|
pos2-gainholdamb =0.01
|
||||||
|
pos2-arlockcnt =5
|
||||||
|
pos2-minfixsats =4
|
||||||
|
pos2-minholdsats =5
|
||||||
|
pos2-mindropsats =10
|
||||||
|
pos2-arelmask =10 # (deg)
|
||||||
|
pos2-arminfix =20
|
||||||
|
pos2-armaxiter =1
|
||||||
|
pos2-elmaskhold =10 # (deg)
|
||||||
|
pos2-aroutcnt =20
|
||||||
|
pos2-maxage =30 # (s)
|
||||||
|
pos2-syncsol =off # (0:off,1:on)
|
||||||
|
pos2-slipthres =0.05 # (m)
|
||||||
|
pos2-dopthres =0 # (m)
|
||||||
|
pos2-rejionno =5 # (m)
|
||||||
|
pos2-rejcode =30 # (m)
|
||||||
|
pos2-niter =1
|
||||||
|
pos2-baselen =0 # (m)
|
||||||
|
pos2-basesig =0 # (m)
|
||||||
|
out-solformat =llh # (0:llh,1:xyz,2:enu,3:nmea)
|
||||||
|
out-outhead =on # (0:off,1:on)
|
||||||
|
out-outopt =on # (0:off,1:on)
|
||||||
|
out-outvel =off # (0:off,1:on)
|
||||||
|
out-timesys =gpst # (0:gpst,1:utc,2:jst)
|
||||||
|
out-timeform =hms # (0:tow,1:hms)
|
||||||
|
out-timendec =3
|
||||||
|
out-degform =deg # (0:deg,1:dms)
|
||||||
|
out-fieldsep =
|
||||||
|
out-outsingle =off # (0:off,1:on)
|
||||||
|
out-maxsolstd =0 # (m)
|
||||||
|
out-height =1 # (0:ellipsoidal,1:geodetic)
|
||||||
|
out-geoid =internal # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000)
|
||||||
|
out-solstatic =all # (0:all,1:single)
|
||||||
|
out-nmeaintv1 =0 # (s)
|
||||||
|
out-nmeaintv2 =0 # (s)
|
||||||
|
out-outstat =residual # (0:off,1:state,2:residual)
|
||||||
|
stats-eratio1 =300
|
||||||
|
stats-eratio2 =300
|
||||||
|
stats-eratio5 =300
|
||||||
|
stats-errphase =0.003 # (m)
|
||||||
|
stats-errphaseel =0.003 # (m)
|
||||||
|
stats-errphasebl =0 # (m/10km)
|
||||||
|
stats-errdoppler =1 # (Hz)
|
||||||
|
stats-snrmax =52 # (dB.Hz)
|
||||||
|
stats-errsnr =0 # (m)
|
||||||
|
stats-errrcv =0 # ( )
|
||||||
|
stats-stdbias =30 # (m)
|
||||||
|
stats-stdiono =0.03 # (m)
|
||||||
|
stats-stdtrop =0.3 # (m)
|
||||||
|
stats-prnaccelh =3 # (m/s^2)
|
||||||
|
stats-prnaccelv =1 # (m/s^2)
|
||||||
|
stats-prnbias =0.0001 # (m)
|
||||||
|
stats-prniono =0.001 # (m)
|
||||||
|
stats-prntrop =0.0001 # (m)
|
||||||
|
stats-prnpos =0 # (m)
|
||||||
|
stats-clkstab =5e-12 # (s/s)
|
||||||
|
ant1-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw)
|
||||||
|
ant1-pos1 =90 # (deg|m)
|
||||||
|
ant1-pos2 =0 # (deg|m)
|
||||||
|
ant1-pos3 =-6335367.6285 # (m|m)
|
||||||
|
ant1-anttype =
|
||||||
|
ant1-antdele =0 # (m)
|
||||||
|
ant1-antdeln =0 # (m)
|
||||||
|
ant1-antdelu =0 # (m)
|
||||||
|
ant2-postype =rtcm # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw)
|
||||||
|
ant2-pos1 =0 # (deg|m)
|
||||||
|
ant2-pos2 =0 # (deg|m)
|
||||||
|
ant2-pos3 =0 # (m|m)
|
||||||
|
ant2-anttype =
|
||||||
|
ant2-antdele =0 # (m)
|
||||||
|
ant2-antdeln =0 # (m)
|
||||||
|
ant2-antdelu =0 # (m)
|
||||||
|
ant2-maxaveep =1
|
||||||
|
ant2-initrst =on # (0:off,1:on)
|
||||||
|
misc-timeinterp =off # (0:off,1:on)
|
||||||
|
misc-sbasatsel =0 # (0:all)
|
||||||
|
misc-rnxopt1 =
|
||||||
|
misc-rnxopt2 =
|
||||||
|
misc-pppopt =
|
||||||
|
file-satantfile =
|
||||||
|
file-rcvantfile =
|
||||||
|
file-staposfile =
|
||||||
|
file-geoidfile =
|
||||||
|
file-ionofile =
|
||||||
|
file-dcbfile =
|
||||||
|
file-eopfile =
|
||||||
|
file-blqfile =
|
||||||
|
file-tempdir =./RTKNAVI
|
||||||
|
file-geexefile =
|
||||||
|
file-solstatfile =
|
||||||
|
file-tracefile =
|
||||||
|
#
|
||||||
|
|
||||||
|
inpstr1-type =tcpcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripcli,7:ftp,8:http)
|
||||||
|
inpstr2-type =ntripcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripcli,7:ftp,8:http)
|
||||||
|
inpstr3-type =ntripcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripcli,7:ftp,8:http)
|
||||||
|
inpstr1-path =127.0.0.1:24001
|
||||||
|
#inpstr2-path =cedr25866:fyx25455@120.253.226.97:8001/RTCM33_GRCEJ
|
||||||
|
inpstr2-path =ytcors14847:fyx25943@gnss.ytcors.cn:8003/RTCM33GRCEJpro
|
||||||
|
#inpstr2-path =beidou:29832611@192.168.100.206:2101/8507903
|
||||||
|
inpstr3-path =Ming:@Zhang12345@ntrip.data.gnss.ga.gov.au:2101/BCEP00BKG0
|
||||||
|
inpstr1-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,4:ubx,5:swift,6:hemis,7:skytraq,8:javad,9:nvs,10:binex,11:rt17,12:sbf,15:sp3)
|
||||||
|
inpstr2-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,4:ubx,5:swift,6:hemis,7:skytraq,8:javad,9:nvs,10:binex,11:rt17,12:sbf,15:sp3)
|
||||||
|
inpstr3-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,4:ubx,5:swift,6:hemis,7:skytraq,8:javad,9:nvs,10:binex,11:rt17,12:sbf,15:sp3)
|
||||||
|
inpstr2-nmeareq =single # (0:off,1:latlon,2:single)
|
||||||
|
inpstr2-nmealat = # (deg)
|
||||||
|
inpstr2-nmealon = # (deg)
|
||||||
|
outstr1-type =file # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,5:ntripsvr,9:ntripcas)
|
||||||
|
outstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,5:ntripsvr,9:ntripcas)
|
||||||
|
outstr1-path =/opt/rtk/temp/temp_llh.log
|
||||||
|
outstr2-path =
|
||||||
|
outstr1-format =llh # (0:llh,1:xyz,2:enu,3:nmea:4:stat)
|
||||||
|
outstr2-format = # (0:llh,1:xyz,2:enu,3:nmea:4:stat)
|
||||||
|
logstr1-type =0 # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,5:ntripsvr,9:ntripcas)
|
||||||
|
logstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,5:ntripsvr,9:ntripcas)
|
||||||
|
logstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,5:ntripsvr,9:ntripcas)
|
||||||
|
logstr1-path =
|
||||||
|
logstr2-path =
|
||||||
|
logstr3-path =
|
||||||
|
misc-svrcycle =10 # (ms)
|
||||||
|
misc-timeout =10000 # (ms)
|
||||||
|
misc-reconnect =10000 # (ms)
|
||||||
|
misc-nmeacycle =5000 # (ms)
|
||||||
|
misc-buffsize =32768 # (bytes)
|
||||||
|
misc-navmsgsel =all # (0:all,1:rover,2:base,3:corr)
|
||||||
|
misc-proxyaddr =
|
||||||
|
misc-fswapmargin =30 # (s)
|
||||||
|
console-passwd =
|
||||||
@ -13,6 +13,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class APIController extends BasicController {
|
public class APIController extends BasicController {
|
||||||
@ -170,12 +172,21 @@ public class APIController extends BasicController {
|
|||||||
GnssDevice device = deviceMapper.queryByDeviceId(deviceId);
|
GnssDevice device = deviceMapper.queryByDeviceId(deviceId);
|
||||||
if (device == null) return null;
|
if (device == null) return null;
|
||||||
|
|
||||||
|
Timer timerSyn = new Timer();
|
||||||
|
int delay = 500;
|
||||||
|
|
||||||
if (!device.getSyn()) {
|
if (!device.getSyn()) {
|
||||||
GnssGroup gnssGroup = groupMapper.selectById(device.getGroup_id());
|
GnssGroup gnssGroup = groupMapper.selectById(device.getGroup_id());
|
||||||
if (gnssGroup != null) {
|
if (gnssGroup != null) {
|
||||||
String config = gnssGroup.getConfigCmd(device);
|
String config = gnssGroup.getConfigCmd(device);
|
||||||
if (config != null) {
|
if (config != null) {
|
||||||
|
timerSyn.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
rtcmClient.config(deviceId, config);
|
rtcmClient.config(deviceId, config);
|
||||||
|
}
|
||||||
|
},delay);
|
||||||
|
delay += 1000;
|
||||||
// 保存
|
// 保存
|
||||||
saveMsg(deviceId, tenantId, 0xd311, config, true);
|
saveMsg(deviceId, tenantId, 0xd311, config, true);
|
||||||
}
|
}
|
||||||
@ -183,7 +194,13 @@ public class APIController extends BasicController {
|
|||||||
}
|
}
|
||||||
List<String> deviceCmds = device.getConfigCmd();
|
List<String> deviceCmds = device.getConfigCmd();
|
||||||
for(String deviceCmd:deviceCmds){
|
for(String deviceCmd:deviceCmds){
|
||||||
|
timerSyn.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
rtcmClient.config(deviceId, deviceCmd);
|
rtcmClient.config(deviceId, deviceCmd);
|
||||||
|
}
|
||||||
|
},delay);
|
||||||
|
delay += 1000;
|
||||||
// 保存
|
// 保存
|
||||||
saveMsg(deviceId, tenantId, 0xd312, deviceCmd, true);
|
saveMsg(deviceId, tenantId, 0xd312, deviceCmd, true);
|
||||||
|
|
||||||
@ -196,7 +213,13 @@ public class APIController extends BasicController {
|
|||||||
queryWrapper.last("limit 1");
|
queryWrapper.last("limit 1");
|
||||||
DeviceCacheCmd cacheCmd = cacheCmdMapper.selectOne(queryWrapper);
|
DeviceCacheCmd cacheCmd = cacheCmdMapper.selectOne(queryWrapper);
|
||||||
if (cacheCmd != null) {
|
if (cacheCmd != null) {
|
||||||
|
timerSyn.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
rtcmClient.config(deviceId, cacheCmd.getCmd());
|
rtcmClient.config(deviceId, cacheCmd.getCmd());
|
||||||
|
}
|
||||||
|
},delay);
|
||||||
|
delay += 1000;
|
||||||
cacheCmd.setSyn(true);
|
cacheCmd.setSyn(true);
|
||||||
cacheCmd.setUpdatetime(LocalDateTime.now());
|
cacheCmd.setUpdatetime(LocalDateTime.now());
|
||||||
cacheCmdMapper.updateById(cacheCmd);
|
cacheCmdMapper.updateById(cacheCmd);
|
||||||
@ -205,7 +228,12 @@ public class APIController extends BasicController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查iccid
|
// 检查iccid
|
||||||
|
timerSyn.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
checkAndAskICCID(device);
|
checkAndAskICCID(device);
|
||||||
|
}
|
||||||
|
},delay);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -253,6 +253,7 @@ public class GnssDeviceController extends BasicController{
|
|||||||
device.setUpdateuser(getLoginUser(session));
|
device.setUpdateuser(getLoginUser(session));
|
||||||
device.setUpdatetime(old_device.getUpdatetime());
|
device.setUpdatetime(old_device.getUpdatetime());
|
||||||
device.setSyn(old_device.getSyn());
|
device.setSyn(old_device.getSyn());
|
||||||
|
device.setChange_flag(old_device.getChange_flag());
|
||||||
String diff=ObjUtil.compare(old_device,device);
|
String diff=ObjUtil.compare(old_device,device);
|
||||||
if(!diff.isEmpty()) {
|
if(!diff.isEmpty()) {
|
||||||
opLogManager.addLog(getLoginUser(session), getTenantId(session),
|
opLogManager.addLog(getLoginUser(session), getTenantId(session),
|
||||||
@ -263,12 +264,14 @@ public class GnssDeviceController extends BasicController{
|
|||||||
if(!old_device.getGroup_id().equals(device.getGroup_id())){
|
if(!old_device.getGroup_id().equals(device.getGroup_id())){
|
||||||
device.setSyn(false);
|
device.setSyn(false);
|
||||||
}
|
}
|
||||||
|
int changeFlag = device.getChange_flag();
|
||||||
if(diff.contains("has_battery")){
|
if(diff.contains("has_battery")){
|
||||||
device.setChange_flag(GnssDevice.PARA_MASK_HAS_BATTERY);
|
changeFlag |= GnssDevice.PARA_MASK_HAS_BATTERY;
|
||||||
}
|
}
|
||||||
if(diff.contains("voltage_factor")){
|
if(diff.contains("voltage_factor")){
|
||||||
device.setChange_flag(GnssDevice.PARA_MASK_VOLTAGE_FACTOR);
|
changeFlag |= GnssDevice.PARA_MASK_VOLTAGE_FACTOR;
|
||||||
}
|
}
|
||||||
|
device.setChange_flag(changeFlag);
|
||||||
num = gnssDeviceMapper.updateById(device);
|
num = gnssDeviceMapper.updateById(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -341,6 +344,65 @@ public class GnssDeviceController extends BasicController{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/gnss/device/cont_loc")
|
||||||
|
@ResponseBody
|
||||||
|
public JSONObject contLoc(String deviceid,String createtime){
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
|
||||||
|
//old data
|
||||||
|
String[] paras = createtime.split(",");
|
||||||
|
String oldDeviceId;
|
||||||
|
if(paras.length==2){
|
||||||
|
oldDeviceId = paras[0];
|
||||||
|
createtime = paras[1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
oldDeviceId = deviceid;
|
||||||
|
createtime = paras[0];
|
||||||
|
}
|
||||||
|
QueryWrapper<GnssCalcData> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("deviceid",oldDeviceId);
|
||||||
|
queryWrapper.eq("enabled",1);
|
||||||
|
queryWrapper.eq("createtime",createtime);
|
||||||
|
queryWrapper.last("limit 1");
|
||||||
|
queryWrapper.isNotNull("rpose");
|
||||||
|
GnssCalcData calcOldData = gnssCalcDataMapper.selectOne(queryWrapper);
|
||||||
|
if(calcOldData==null) {
|
||||||
|
jsonObject.put("code",1);
|
||||||
|
jsonObject.put("msg","该时间无有效解算结果");
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
// new data
|
||||||
|
QueryWrapper<GnssCalcData> queryWrapper1 = new QueryWrapper<>();
|
||||||
|
queryWrapper1.eq("deviceid",deviceid);
|
||||||
|
queryWrapper1.eq("enabled",1);
|
||||||
|
queryWrapper1.orderByDesc("createtime");
|
||||||
|
queryWrapper1.last("limit 1");
|
||||||
|
queryWrapper1.isNotNull("rpose");
|
||||||
|
GnssCalcData calcNewData = gnssCalcDataMapper.selectOne(queryWrapper1);
|
||||||
|
if(calcNewData==null) {
|
||||||
|
jsonObject.put("code",1);
|
||||||
|
jsonObject.put("msg","无有效解算结果");
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 原来的初始值
|
||||||
|
QueryWrapper<GnssDevice> deviceQueryWrapper = new QueryWrapper<>();
|
||||||
|
deviceQueryWrapper.eq("deviceid",oldDeviceId);
|
||||||
|
deviceQueryWrapper.last("limit 1");
|
||||||
|
GnssDevice device = gnssDeviceMapper.selectOne(deviceQueryWrapper);
|
||||||
|
if(device.getIpose()==null) device.setIpose(0.0);
|
||||||
|
if(device.getIposn()==null) device.setIposn(0.0);
|
||||||
|
if(device.getIposd()==null) device.setIposd(0.0);
|
||||||
|
|
||||||
|
jsonObject.put("code",0);
|
||||||
|
jsonObject.put("ipose", NumberUtils.scaleTwo(calcNewData.getRpose()-calcOldData.getRpose()+device.getIpose()));
|
||||||
|
jsonObject.put("iposn",NumberUtils.scaleTwo(calcNewData.getRposn()-calcOldData.getRposn()+device.getIposn()));
|
||||||
|
jsonObject.put("iposd",NumberUtils.scaleTwo(calcNewData.getRposd()-calcOldData.getRposd()+device.getIposd()));
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
void updateBasicGroupAssociatedNum(GnssDevice newCfg, GnssDevice oldCfg){
|
void updateBasicGroupAssociatedNum(GnssDevice newCfg, GnssDevice oldCfg){
|
||||||
updateBasicGroupAssociatedNum(newCfg.getGroup_id());
|
updateBasicGroupAssociatedNum(newCfg.getGroup_id());
|
||||||
updateCalcGroupAssociatedNum(newCfg.getCalc_group_id());
|
updateCalcGroupAssociatedNum(newCfg.getCalc_group_id());
|
||||||
|
|||||||
@ -2,18 +2,16 @@ package com.imdroid.beidou.controller;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.imdroid.beidou.common.HttpResult;
|
||||||
import com.imdroid.beidou.service.CommonExcelService;
|
import com.imdroid.beidou.service.CommonExcelService;
|
||||||
import com.imdroid.secapi.dto.GnssGroupFwd;
|
import com.imdroid.secapi.dto.*;
|
||||||
import com.imdroid.secapi.dto.GnssGroupFwdMapper;
|
|
||||||
import com.imdroid.secapi.dto.ResendRecord;
|
|
||||||
import com.imdroid.secapi.dto.ResendRecordMapper;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@ -22,6 +20,10 @@ public class GnssResendController extends BasicController implements CommonExcel
|
|||||||
GnssGroupFwdMapper gnssGroupFwdMapper;
|
GnssGroupFwdMapper gnssGroupFwdMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
ResendRecordMapper resendRecordMapper;
|
ResendRecordMapper resendRecordMapper;
|
||||||
|
@Autowired
|
||||||
|
TenantMapper tenantMapper;
|
||||||
|
@Autowired
|
||||||
|
OpLogManager opLogManager;
|
||||||
|
|
||||||
/********* 推送页面 *********/
|
/********* 推送页面 *********/
|
||||||
@RequestMapping("/page/resend_records")
|
@RequestMapping("/page/resend_records")
|
||||||
@ -33,6 +35,19 @@ public class GnssResendController extends BasicController implements CommonExcel
|
|||||||
|
|
||||||
return "/page/resend_records";
|
return "/page/resend_records";
|
||||||
}
|
}
|
||||||
|
@RequestMapping("/page/table/resend_record_add")
|
||||||
|
public String gnssAddDev(Model m, HttpSession session) {
|
||||||
|
initModel(m, session);
|
||||||
|
//以下用于下拉框数据
|
||||||
|
List<Tenant> tenants = tenantMapper.selectList(null);
|
||||||
|
List<GnssGroupFwd> gnssGroupFwds = gnssGroupFwdMapper.selectList(null);
|
||||||
|
|
||||||
|
m.addAttribute("tenant_list", tenants);
|
||||||
|
m.addAttribute("gnss_group_fwd_list", gnssGroupFwds);
|
||||||
|
m.addAttribute("device", new GnssDevice());
|
||||||
|
|
||||||
|
return "/page/table/resend_record_add";
|
||||||
|
}
|
||||||
|
|
||||||
/********* 推送数据 *********/
|
/********* 推送数据 *********/
|
||||||
@RequestMapping("/fwd/resend_records")
|
@RequestMapping("/fwd/resend_records")
|
||||||
@ -41,6 +56,40 @@ public class GnssResendController extends BasicController implements CommonExcel
|
|||||||
return this.pageList(session, page, limit, searchParams);
|
return this.pageList(session, page, limit, searchParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/fwd/resend_records/add")
|
||||||
|
@ResponseBody
|
||||||
|
public String update(HttpSession session, @RequestBody JSONObject object) throws Exception {
|
||||||
|
// 从请求参数中创建对象
|
||||||
|
ResendRecord resendRecord = JSONObject.toJavaObject(object,ResendRecord.class);
|
||||||
|
resendRecord.setCreatetime(LocalDateTime.now());
|
||||||
|
resendRecord.setState(ResendRecord.STATE_BREAK_POINT);
|
||||||
|
int num = resendRecordMapper.insert(resendRecord);
|
||||||
|
if (num == 0) {
|
||||||
|
return HttpResult.failed();
|
||||||
|
} else {
|
||||||
|
opLogManager.addLog(getLoginUser(session),getTenantId(session),
|
||||||
|
OpLogManager.OP_TYPE_ADD,
|
||||||
|
OpLogManager.OP_OBJ_FWD_RECORD,
|
||||||
|
"create new resend record");
|
||||||
|
return HttpResult.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/fwd/resend_records/delete")
|
||||||
|
@ResponseBody
|
||||||
|
public String delete(HttpSession session, @RequestParam String del_id) throws Exception {
|
||||||
|
int num = resendRecordMapper.deleteById(del_id);
|
||||||
|
opLogManager.addLog(getLoginUser(session),getTenantId(session),
|
||||||
|
OpLogManager.OP_TYPE_DEL,
|
||||||
|
OpLogManager.OP_OBJ_FWD_RECORD,
|
||||||
|
del_id + " deleted");
|
||||||
|
if (num == 0) {
|
||||||
|
return HttpResult.failed();
|
||||||
|
} else{
|
||||||
|
return HttpResult.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取实体类的class
|
* 获取实体类的class
|
||||||
*
|
*
|
||||||
|
|||||||
@ -107,6 +107,11 @@ public class IndexController extends BasicController{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//temp
|
||||||
|
/* if(deviceOfflineNum>10) deviceOfflineNum=deviceOfflineNum/10;
|
||||||
|
if(warning1Num>10) warning1Num=warning1Num/10;
|
||||||
|
if(warning2Num>10) warning1Num=warning2Num/10;
|
||||||
|
*/
|
||||||
m.addAttribute("deviceDeployedNum", deviceDeployedNum);
|
m.addAttribute("deviceDeployedNum", deviceDeployedNum);
|
||||||
m.addAttribute("deviceOnlineNum", deviceDeployedNum-deviceOfflineNum);
|
m.addAttribute("deviceOnlineNum", deviceDeployedNum-deviceOfflineNum);
|
||||||
m.addAttribute("deviceOfflineNum", deviceOfflineNum);
|
m.addAttribute("deviceOfflineNum", deviceOfflineNum);
|
||||||
|
|||||||
@ -0,0 +1,75 @@
|
|||||||
|
package com.imdroid.beidou.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态消息 控制器
|
||||||
|
*
|
||||||
|
* @author LiGang
|
||||||
|
* @date 2024/1/6 14:37
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SurfaceInclineController extends BasicController implements CommonExcelService<SurfaceInclineData, SurfaceInclineData> {
|
||||||
|
@Autowired
|
||||||
|
SurfaceInclineDataMapper dataMapper;
|
||||||
|
|
||||||
|
@RequestMapping("/page/surface_incline_data")
|
||||||
|
public String surfaceInclineData(Model m, HttpSession session) {
|
||||||
|
initModel(m, session);
|
||||||
|
return "/page/surface_incline_data";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/surface_incline/data/list")
|
||||||
|
@ResponseBody
|
||||||
|
public JSONObject listData(HttpSession session, Integer page, Integer limit, String searchParams) {
|
||||||
|
return this.pageList(session, page, limit, searchParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出excel
|
||||||
|
*
|
||||||
|
* @param session HttpSession
|
||||||
|
* @param request HttpServletRequest
|
||||||
|
* @param response HttpServletResponse
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@RequestMapping("/surface_incline/data/export")
|
||||||
|
@ResponseBody
|
||||||
|
public void exportData(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||||
|
this.export(session, request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取实体类的class
|
||||||
|
*
|
||||||
|
* @return 实体类的class
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Class<SurfaceInclineData> getEntityClass() {
|
||||||
|
return SurfaceInclineData.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取实体类对应的mybatis mapper
|
||||||
|
*
|
||||||
|
* @return 实体类对应的mybatis mapper
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public BaseMapper<SurfaceInclineData> getMapper() {
|
||||||
|
return dataMapper;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -72,6 +72,7 @@ CREATE TABLE IF NOT EXISTS `gnssdevices` (
|
|||||||
`has_battery` bit(1) DEFAULT 0 COMMENT '是否内置电池',
|
`has_battery` bit(1) DEFAULT 0 COMMENT '是否内置电池',
|
||||||
`change_flag` int DEFAULT 0 COMMENT '参数改变标识',
|
`change_flag` int DEFAULT 0 COMMENT '参数改变标识',
|
||||||
`voltage_factor` tinyint DEFAULT NULL COMMENT '分压比',
|
`voltage_factor` tinyint DEFAULT NULL COMMENT '分压比',
|
||||||
|
`forward_to_ntrip` bit(1) DEFAULT 0 COMMENT '用于判断是否发送到NtripCaster',
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
@ -402,3 +403,27 @@ CREATE TABLE IF NOT EXISTS `traffic_records` (
|
|||||||
KEY `idx_iccid` (`iccid`),
|
KEY `idx_iccid` (`iccid`),
|
||||||
KEY `idx_recordtime` (`recordtime`)
|
KEY `idx_recordtime` (`recordtime`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流量使用记录表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流量使用记录表';
|
||||||
|
|
||||||
|
/***
|
||||||
|
倾角计
|
||||||
|
*/
|
||||||
|
CREATE TABLE IF NOT EXISTS `surface_incline_data` (
|
||||||
|
`id` bigint AUTO_INCREMENT,
|
||||||
|
`tenantid` int NOT NULL,
|
||||||
|
`createtime` datetime DEFAULT NULL,
|
||||||
|
`deviceid` varchar(20) NOT NULL,
|
||||||
|
`sensorid` smallint DEFAULT NULL,
|
||||||
|
`anglex` float DEFAULT NULL,
|
||||||
|
`angley` float DEFAULT NULL,
|
||||||
|
`anglez` float DEFAULT NULL,
|
||||||
|
`accx` float DEFAULT NULL,
|
||||||
|
`accy` float DEFAULT NULL,
|
||||||
|
`accz` float DEFAULT NULL,
|
||||||
|
`maxaccx` float DEFAULT NULL,
|
||||||
|
`maxaccy` float DEFAULT NULL,
|
||||||
|
`maxaccz` float DEFAULT NULL,
|
||||||
|
`minaccx` float DEFAULT NULL,
|
||||||
|
`minaccy` float DEFAULT NULL,
|
||||||
|
`minaccz` float DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"href": "page/device_overview"
|
"href": "page/device_overview"
|
||||||
},
|
},
|
||||||
"logoInfo": {
|
"logoInfo": {
|
||||||
"title": "北斗管理平台",
|
"title": "地质监测平台",
|
||||||
"image": "images/logo.png",
|
"image": "images/logo.png",
|
||||||
"href": ""
|
"href": ""
|
||||||
},
|
},
|
||||||
@ -41,12 +41,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"title": "解算结果",
|
|
||||||
"href": "page/gnss_data_calc",
|
|
||||||
"icon": "fa fa-calculator",
|
|
||||||
"target": "_self"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"title": "配置管理",
|
"title": "配置管理",
|
||||||
"href": "",
|
"href": "",
|
||||||
@ -82,6 +76,32 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "监测数据",
|
||||||
|
"icon": "fa fa-address-book",
|
||||||
|
"href": "",
|
||||||
|
"target": "_self",
|
||||||
|
"child": [
|
||||||
|
{
|
||||||
|
"title": "北斗",
|
||||||
|
"href": "page/gnss_data_calc",
|
||||||
|
"icon": "fa fa-calculator",
|
||||||
|
"target": "_self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "倾角计",
|
||||||
|
"href": "page/surface_incline_data",
|
||||||
|
"icon": "fa fa-calculator",
|
||||||
|
"target": "_self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "测斜仪",
|
||||||
|
"href": "",
|
||||||
|
"icon": "fa fa-calculator",
|
||||||
|
"target": "_self"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -4,7 +4,7 @@
|
|||||||
"href": "page/device_overview"
|
"href": "page/device_overview"
|
||||||
},
|
},
|
||||||
"logoInfo": {
|
"logoInfo": {
|
||||||
"title": "北斗管理平台",
|
"title": "地质监测平台",
|
||||||
"image": "images/logo.png",
|
"image": "images/logo.png",
|
||||||
"href": ""
|
"href": ""
|
||||||
},
|
},
|
||||||
@ -53,12 +53,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"title": "解算结果",
|
|
||||||
"href": "page/gnss_data_calc",
|
|
||||||
"icon": "fa fa-calculator",
|
|
||||||
"target": "_self"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"title": "日志",
|
"title": "日志",
|
||||||
"href": "page/gnss_single_data",
|
"href": "page/gnss_single_data",
|
||||||
@ -177,6 +171,32 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "监测数据",
|
||||||
|
"icon": "fa fa-address-book",
|
||||||
|
"href": "",
|
||||||
|
"target": "_self",
|
||||||
|
"child": [
|
||||||
|
{
|
||||||
|
"title": "北斗",
|
||||||
|
"href": "page/gnss_data_calc",
|
||||||
|
"icon": "fa fa-calculator",
|
||||||
|
"target": "_self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "倾角计",
|
||||||
|
"href": "page/surface_incline_data",
|
||||||
|
"icon": "fa fa-calculator",
|
||||||
|
"target": "_self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "测斜仪",
|
||||||
|
"href": "",
|
||||||
|
"icon": "fa fa-calculator",
|
||||||
|
"target": "_self"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "系统管理",
|
"title": "系统管理",
|
||||||
"icon": "fa fa-lemon-o",
|
"icon": "fa fa-lemon-o",
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"href": "page/device_overview"
|
"href": "page/device_overview"
|
||||||
},
|
},
|
||||||
"logoInfo": {
|
"logoInfo": {
|
||||||
"title": "北斗管理平台",
|
"title": "地质监测平台",
|
||||||
"image": "images/logo.png",
|
"image": "images/logo.png",
|
||||||
"href": ""
|
"href": ""
|
||||||
},
|
},
|
||||||
@ -47,12 +47,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"title": "解算结果",
|
|
||||||
"href": "page/gnss_data_calc",
|
|
||||||
"icon": "fa fa-calculator",
|
|
||||||
"target": "_self"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"title": "配置管理",
|
"title": "配置管理",
|
||||||
"href": "",
|
"href": "",
|
||||||
@ -135,6 +129,32 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "监测数据",
|
||||||
|
"icon": "fa fa-address-book",
|
||||||
|
"href": "",
|
||||||
|
"target": "_self",
|
||||||
|
"child": [
|
||||||
|
{
|
||||||
|
"title": "北斗",
|
||||||
|
"href": "page/gnss_data_calc",
|
||||||
|
"icon": "fa fa-calculator",
|
||||||
|
"target": "_self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "倾角计",
|
||||||
|
"href": "page/surface_incline_data",
|
||||||
|
"icon": "fa fa-calculator",
|
||||||
|
"target": "_self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "测斜仪",
|
||||||
|
"href": "",
|
||||||
|
"icon": "fa fa-calculator",
|
||||||
|
"target": "_self"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "系统管理",
|
"title": "系统管理",
|
||||||
"icon": "fa fa-lemon-o",
|
"icon": "fa fa-lemon-o",
|
||||||
|
|||||||
@ -0,0 +1,79 @@
|
|||||||
|
var CoordinateUtils = (function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var pi = 3.14159265358979324;
|
||||||
|
var a = 6378245.0;
|
||||||
|
var ee = 0.00669342162296594323;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否在国内,不在国内则不做偏移
|
||||||
|
*/
|
||||||
|
function outOfChina(lon, lat) {
|
||||||
|
if ((lon < 72.004 || lon > 137.8347) && (lat < 0.8293 || lat > 55.8271)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformLat(x, y) {
|
||||||
|
var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
|
||||||
|
ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
|
||||||
|
ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
|
||||||
|
ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformLon(x, y) {
|
||||||
|
var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
|
||||||
|
ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
|
||||||
|
ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
|
||||||
|
ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function transform(wgLat, wgLon) {
|
||||||
|
var mars_point = {lon: 0, lat: 0};
|
||||||
|
if (outOfChina(wgLon, wgLat)) {
|
||||||
|
mars_point.lat = wgLat;
|
||||||
|
mars_point.lon = wgLon;
|
||||||
|
return mars_point;
|
||||||
|
}
|
||||||
|
var dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
|
||||||
|
var dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
|
||||||
|
var radLat = wgLat / 180.0 * pi;
|
||||||
|
var magic = Math.sin(radLat);
|
||||||
|
magic = 1 - ee * magic * magic;
|
||||||
|
var sqrtMagic = Math.sqrt(magic);
|
||||||
|
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
|
||||||
|
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
|
||||||
|
mars_point.lat = wgLat + dLat;
|
||||||
|
mars_point.lon = wgLon + dLon;
|
||||||
|
return mars_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getMapCoordinates(lat, lon, mapType) {
|
||||||
|
var coordinates;
|
||||||
|
if (mapType === 'amap' || mapType === 'amap_satellite') {
|
||||||
|
// 高德地图 WGS84 转换为 GCJ-02
|
||||||
|
var gcjCoord = transform(lat, lon);
|
||||||
|
coordinates = ol.proj.fromLonLat([gcjCoord.lon, gcjCoord.lat]);
|
||||||
|
} else if (mapType.startsWith('google_')) {
|
||||||
|
// Google地图使用WGS84坐标系
|
||||||
|
coordinates = ol.proj.fromLonLat([lon, lat]);
|
||||||
|
} else {
|
||||||
|
// 天地图 CGCS2000,与WGS84实质一样
|
||||||
|
coordinates = ol.proj.fromLonLat([lon, lat]);
|
||||||
|
}
|
||||||
|
return coordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
transform: transform,
|
||||||
|
getMapCoordinates: getMapCoordinates,
|
||||||
|
outOfChina: outOfChina
|
||||||
|
};
|
||||||
|
})();
|
||||||
@ -0,0 +1,410 @@
|
|||||||
|
var DeviceMarkers = (function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var greenFeatures = [];
|
||||||
|
var orangeFeatures = [];
|
||||||
|
var redFeatures = [];
|
||||||
|
var allFeatures = [];
|
||||||
|
var myLocationFeature = null;
|
||||||
|
var myLocationInterval = null;
|
||||||
|
var showDeviceId = true;
|
||||||
|
var minZoomForLabels = 4;
|
||||||
|
|
||||||
|
|
||||||
|
var map = null;
|
||||||
|
var vectorSource = null;
|
||||||
|
var vectorLayer = null;
|
||||||
|
|
||||||
|
|
||||||
|
function init(mapInstance, vectorSourceInstance, vectorLayerInstance) {
|
||||||
|
map = mapInstance;
|
||||||
|
vectorSource = vectorSourceInstance;
|
||||||
|
vectorLayer = vectorLayerInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createDeviceStyle(feature) {
|
||||||
|
if (feature.get('isMyLocation')) {
|
||||||
|
return new ol.style.Style({
|
||||||
|
image: new ol.style.Icon({
|
||||||
|
anchor: [0.5, 1],
|
||||||
|
src: '../images/loc_blue.png',
|
||||||
|
scale: 0.7
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var deviceInfo = feature.get('deviceInfo');
|
||||||
|
if (!deviceInfo) return null;
|
||||||
|
|
||||||
|
var iconSrc;
|
||||||
|
var color = '#000';
|
||||||
|
var isHovered = feature.get('hovered') === true;
|
||||||
|
var scale = isHovered ? 0.85 : 0.7;
|
||||||
|
|
||||||
|
// 根据告警级别选择图标
|
||||||
|
if (deviceInfo.warning == 2) {
|
||||||
|
iconSrc = '../images/loc1_red.png';
|
||||||
|
} else if (deviceInfo.warning == 1) {
|
||||||
|
iconSrc = '../images/loc1_orange.png';
|
||||||
|
} else {
|
||||||
|
iconSrc = '../images/loc1_green.png';
|
||||||
|
}
|
||||||
|
|
||||||
|
var style = new ol.style.Style({
|
||||||
|
image: new ol.style.Icon({
|
||||||
|
anchor: [0.5, 1],
|
||||||
|
src: iconSrc,
|
||||||
|
scale: scale
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// 根据缩放级别和设置决定是否显示设备ID
|
||||||
|
if (showDeviceId && map && map.getView().getZoom() >= minZoomForLabels) {
|
||||||
|
style.setText(new ol.style.Text({
|
||||||
|
text: deviceInfo.deviceid,
|
||||||
|
offsetY: -30,
|
||||||
|
fill: new ol.style.Fill({
|
||||||
|
color: isHovered ? '#1aa094' : color
|
||||||
|
}),
|
||||||
|
stroke: new ol.style.Stroke({
|
||||||
|
color: '#fff',
|
||||||
|
width: isHovered ? 3 : 2
|
||||||
|
}),
|
||||||
|
font: isHovered ? 'bold 12px Arial' : '12px Arial'
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function addDeviceMarkers(deviceList) {
|
||||||
|
if (!vectorSource || !deviceList) return;
|
||||||
|
|
||||||
|
var savedMyLocationFeature = myLocationFeature;
|
||||||
|
|
||||||
|
vectorSource.clear();
|
||||||
|
greenFeatures = [];
|
||||||
|
orangeFeatures = [];
|
||||||
|
redFeatures = [];
|
||||||
|
allFeatures = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < deviceList.length; i++) {
|
||||||
|
var device = deviceList[i];
|
||||||
|
var currentMapType = getCurrentMapType();
|
||||||
|
var mapCoordinates = CoordinateUtils.getMapCoordinates(
|
||||||
|
device.latitude,
|
||||||
|
device.longitude,
|
||||||
|
currentMapType
|
||||||
|
);
|
||||||
|
|
||||||
|
var feature = new ol.Feature({
|
||||||
|
geometry: new ol.geom.Point(mapCoordinates),
|
||||||
|
deviceInfo: device
|
||||||
|
});
|
||||||
|
|
||||||
|
// 按告警级别分类
|
||||||
|
if (device.warning == 2) {
|
||||||
|
redFeatures.push(feature);
|
||||||
|
} else if (device.warning == 1) {
|
||||||
|
orangeFeatures.push(feature);
|
||||||
|
} else {
|
||||||
|
greenFeatures.push(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
allFeatures.push(feature);
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (savedMyLocationFeature) {
|
||||||
|
vectorSource.addFeature(savedMyLocationFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 强制更新样式
|
||||||
|
if (vectorLayer) {
|
||||||
|
vectorLayer.changed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getCurrentMapType() {
|
||||||
|
var mapTypeSelect = document.getElementById('mapTypeSelectNew');
|
||||||
|
return mapTypeSelect ? mapTypeSelect.value : 'tianditu_satellite';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showAllDevices() {
|
||||||
|
if (!vectorSource) return;
|
||||||
|
|
||||||
|
var savedMyLocationFeature = myLocationFeature;
|
||||||
|
vectorSource.clear();
|
||||||
|
|
||||||
|
if (savedMyLocationFeature) {
|
||||||
|
vectorSource.addFeature(savedMyLocationFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < allFeatures.length; i++) {
|
||||||
|
vectorSource.addFeature(allFeatures[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showWarning1Devices() {
|
||||||
|
if (!vectorSource) return;
|
||||||
|
|
||||||
|
var savedMyLocationFeature = myLocationFeature;
|
||||||
|
vectorSource.clear();
|
||||||
|
|
||||||
|
if (savedMyLocationFeature) {
|
||||||
|
vectorSource.addFeature(savedMyLocationFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < allFeatures.length; i++) {
|
||||||
|
vectorSource.addFeature(allFeatures[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideGreenFeatures();
|
||||||
|
hideRedFeatures();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showWarning2Devices() {
|
||||||
|
if (!vectorSource) return;
|
||||||
|
|
||||||
|
var savedMyLocationFeature = myLocationFeature;
|
||||||
|
vectorSource.clear();
|
||||||
|
|
||||||
|
if (savedMyLocationFeature) {
|
||||||
|
vectorSource.addFeature(savedMyLocationFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < allFeatures.length; i++) {
|
||||||
|
vectorSource.addFeature(allFeatures[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideGreenFeatures();
|
||||||
|
hideOrangeFeatures();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideGreenFeatures() {
|
||||||
|
for (var i = 0; i < greenFeatures.length; i++) {
|
||||||
|
vectorSource.removeFeature(greenFeatures[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideOrangeFeatures() {
|
||||||
|
for (var i = 0; i < orangeFeatures.length; i++) {
|
||||||
|
vectorSource.removeFeature(orangeFeatures[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideRedFeatures() {
|
||||||
|
for (var i = 0; i < redFeatures.length; i++) {
|
||||||
|
vectorSource.removeFeature(redFeatures[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findDeviceById(deviceId) {
|
||||||
|
// console.log('搜索设备:', deviceId, '(类型:', typeof deviceId, ')');
|
||||||
|
// console.log('当前设备总数:', allFeatures.length);
|
||||||
|
|
||||||
|
var searchTerm = String(deviceId).trim();
|
||||||
|
|
||||||
|
for (var i = 0; i < allFeatures.length; i++) {
|
||||||
|
var feature = allFeatures[i];
|
||||||
|
var deviceInfo = feature.get('deviceInfo');
|
||||||
|
if (deviceInfo) {
|
||||||
|
var currentDeviceId = String(deviceInfo.deviceid);
|
||||||
|
// console.log('检查设备:', currentDeviceId, '(类型:', typeof deviceInfo.deviceid, ')');
|
||||||
|
|
||||||
|
if (currentDeviceId === searchTerm) {
|
||||||
|
// console.log('精确匹配找到设备:', currentDeviceId);
|
||||||
|
return feature;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentDeviceId.indexOf(searchTerm) !== -1) {
|
||||||
|
// console.log('部分匹配找到设备:', currentDeviceId);
|
||||||
|
return feature;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentDeviceId.replace(/\s+/g, '') === searchTerm.replace(/\s+/g, '')) {
|
||||||
|
// console.log('去除空格后匹配找到设备:', currentDeviceId);
|
||||||
|
return feature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('未找到设备:', deviceId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function locateDevice(deviceId) {
|
||||||
|
var feature = findDeviceById(deviceId);
|
||||||
|
if (feature && map) {
|
||||||
|
var geometry = feature.getGeometry();
|
||||||
|
var coordinates = geometry.getCoordinates();
|
||||||
|
|
||||||
|
map.getView().animate({
|
||||||
|
center: coordinates,
|
||||||
|
zoom: Math.max(map.getView().getZoom(), 15),
|
||||||
|
duration: 1000
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取我的位置
|
||||||
|
*/
|
||||||
|
function getMyLocation() {
|
||||||
|
if (navigator.geolocation) {
|
||||||
|
navigator.geolocation.getCurrentPosition(
|
||||||
|
function(position) {
|
||||||
|
var lat = position.coords.latitude;
|
||||||
|
var lon = position.coords.longitude;
|
||||||
|
|
||||||
|
var currentMapType = getCurrentMapType();
|
||||||
|
var coordinates = CoordinateUtils.getMapCoordinates(lat, lon, currentMapType);
|
||||||
|
|
||||||
|
if (myLocationFeature) {
|
||||||
|
vectorSource.removeFeature(myLocationFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
myLocationFeature = new ol.Feature({
|
||||||
|
geometry: new ol.geom.Point(coordinates),
|
||||||
|
isMyLocation: true
|
||||||
|
});
|
||||||
|
|
||||||
|
vectorSource.addFeature(myLocationFeature);
|
||||||
|
|
||||||
|
// map.getView().animate({
|
||||||
|
// center: coordinates,
|
||||||
|
// zoom: 15,
|
||||||
|
// duration: 1000
|
||||||
|
// });
|
||||||
|
},
|
||||||
|
function(error) {
|
||||||
|
console.error('获取位置失败:', error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function locateMyLocation() {
|
||||||
|
if (myLocationFeature) {
|
||||||
|
var geometry = myLocationFeature.getGeometry();
|
||||||
|
var coordinates = geometry.getCoordinates();
|
||||||
|
|
||||||
|
map.getView().animate({
|
||||||
|
center: coordinates,
|
||||||
|
zoom: 15,
|
||||||
|
duration: 1000
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (navigator.geolocation) {
|
||||||
|
navigator.geolocation.getCurrentPosition(
|
||||||
|
function(position) {
|
||||||
|
var lat = position.coords.latitude;
|
||||||
|
var lon = position.coords.longitude;
|
||||||
|
|
||||||
|
var currentMapType = getCurrentMapType();
|
||||||
|
var coordinates = CoordinateUtils.getMapCoordinates(lat, lon, currentMapType);
|
||||||
|
|
||||||
|
if (myLocationFeature) {
|
||||||
|
vectorSource.removeFeature(myLocationFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
myLocationFeature = new ol.Feature({
|
||||||
|
geometry: new ol.geom.Point(coordinates),
|
||||||
|
isMyLocation: true
|
||||||
|
});
|
||||||
|
|
||||||
|
vectorSource.addFeature(myLocationFeature);
|
||||||
|
|
||||||
|
map.getView().animate({
|
||||||
|
center: coordinates,
|
||||||
|
zoom: 15,
|
||||||
|
duration: 1000
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function startLocationUpdates() {
|
||||||
|
if (navigator.geolocation) {
|
||||||
|
myLocationInterval = setInterval(function() {
|
||||||
|
getMyLocation();
|
||||||
|
}, 30000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function stopLocationUpdates() {
|
||||||
|
if (myLocationInterval) {
|
||||||
|
clearInterval(myLocationInterval);
|
||||||
|
myLocationInterval = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function updateMyLocationForMapType(mapType) {
|
||||||
|
if (myLocationFeature) {
|
||||||
|
var geometry = myLocationFeature.getGeometry();
|
||||||
|
var coordinates = geometry.getCoordinates();
|
||||||
|
var lonLat = ol.proj.toLonLat(coordinates);
|
||||||
|
|
||||||
|
var newCoordinates = CoordinateUtils.getMapCoordinates(lonLat[1], lonLat[0], mapType);
|
||||||
|
|
||||||
|
myLocationFeature.setGeometry(new ol.geom.Point(newCoordinates));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setShowDeviceId(show) {
|
||||||
|
showDeviceId = show;
|
||||||
|
if (vectorLayer) {
|
||||||
|
vectorLayer.changed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getDeviceStats() {
|
||||||
|
return {
|
||||||
|
total: allFeatures.length,
|
||||||
|
green: greenFeatures.length,
|
||||||
|
orange: orangeFeatures.length,
|
||||||
|
red: redFeatures.length
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: init,
|
||||||
|
createDeviceStyle: createDeviceStyle,
|
||||||
|
addDeviceMarkers: addDeviceMarkers,
|
||||||
|
showAllDevices: showAllDevices,
|
||||||
|
showWarning1Devices: showWarning1Devices,
|
||||||
|
showWarning2Devices: showWarning2Devices,
|
||||||
|
hideGreenFeatures: hideGreenFeatures,
|
||||||
|
hideOrangeFeatures: hideOrangeFeatures,
|
||||||
|
hideRedFeatures: hideRedFeatures,
|
||||||
|
findDeviceById: findDeviceById,
|
||||||
|
locateDevice: locateDevice,
|
||||||
|
getMyLocation: getMyLocation,
|
||||||
|
locateMyLocation: locateMyLocation,
|
||||||
|
startLocationUpdates: startLocationUpdates,
|
||||||
|
stopLocationUpdates: stopLocationUpdates,
|
||||||
|
updateMyLocationForMapType: updateMyLocationForMapType,
|
||||||
|
setShowDeviceId: setShowDeviceId,
|
||||||
|
getDeviceStats: getDeviceStats,
|
||||||
|
|
||||||
|
getAllFeatures: function() { return allFeatures; },
|
||||||
|
getGreenFeatures: function() { return greenFeatures; },
|
||||||
|
getOrangeFeatures: function() { return orangeFeatures; },
|
||||||
|
getRedFeatures: function() { return redFeatures; },
|
||||||
|
getMyLocationFeature: function() { return myLocationFeature; }
|
||||||
|
};
|
||||||
|
})();
|
||||||
@ -0,0 +1,149 @@
|
|||||||
|
var DeviceOverview = (function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var deviceList = [];
|
||||||
|
|
||||||
|
function init(devices, options) {
|
||||||
|
deviceList = devices || [];
|
||||||
|
|
||||||
|
window.deviceList = deviceList;
|
||||||
|
window.userRole = options && options.role ? options.role : 'USER';
|
||||||
|
|
||||||
|
layui.use(['form'], function(){
|
||||||
|
var form = layui.form;
|
||||||
|
|
||||||
|
form.on('select(mapTypeNew)', function(data){
|
||||||
|
MapCore.switchMapType(data.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
MapCore.initialize(deviceList);
|
||||||
|
|
||||||
|
document.getElementById('warningFilter').value = 'all';
|
||||||
|
SearchFilter.showAllDevices();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMapTypeChange() {
|
||||||
|
return MapCore.onMapTypeChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchDeviceNew() {
|
||||||
|
return MapCore.searchDeviceNew();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onWarningFilterChange() {
|
||||||
|
return MapCore.onWarningFilterChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMapFunctionsMenu() {
|
||||||
|
return MapCore.toggleMapFunctionsMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleDeviceId() {
|
||||||
|
return MapCore.toggleDeviceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleCluster() {
|
||||||
|
return MapCore.toggleCluster();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMeasureDistance() {
|
||||||
|
return MeasureTools.toggleMeasureDistance();
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishMeasuring() {
|
||||||
|
return MeasureTools.finishMeasuring();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearMeasure() {
|
||||||
|
return MeasureTools.clearMeasure();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleWeatherForecast() {
|
||||||
|
return WeatherForecast.toggleWeatherForecast();
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeWeatherCard() {
|
||||||
|
return WeatherForecast.closeWeatherCard();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPrevForecast() {
|
||||||
|
return WeatherForecast.showPrevForecast();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showNextForecast() {
|
||||||
|
return WeatherForecast.showNextForecast();
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryDevices(statusType) {
|
||||||
|
return SearchFilter.queryDevices(statusType);
|
||||||
|
}
|
||||||
|
|
||||||
|
function locateDeviceOnMap(deviceId, latitude, longitude) {
|
||||||
|
return SearchFilter.locateDeviceOnMap(deviceId, latitude, longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
function locateDeviceDirectly(deviceId) {
|
||||||
|
return SearchFilter.locateDeviceDirectly(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchMapType(mapType) {
|
||||||
|
return MapCore.switchMapType(mapType);
|
||||||
|
}
|
||||||
|
|
||||||
|
function locateMyLocation() {
|
||||||
|
return DeviceMarkers.locateMyLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearDeviceFilter() {
|
||||||
|
return SearchFilter.clearDeviceFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: init,
|
||||||
|
|
||||||
|
onMapTypeChange: onMapTypeChange,
|
||||||
|
switchMapType: switchMapType,
|
||||||
|
|
||||||
|
searchDeviceNew: searchDeviceNew,
|
||||||
|
onWarningFilterChange: onWarningFilterChange,
|
||||||
|
queryDevices: queryDevices,
|
||||||
|
locateDeviceOnMap: locateDeviceOnMap,
|
||||||
|
locateDeviceDirectly: locateDeviceDirectly,
|
||||||
|
locateMyLocation: locateMyLocation,
|
||||||
|
clearDeviceFilter: clearDeviceFilter,
|
||||||
|
|
||||||
|
toggleMapFunctionsMenu: toggleMapFunctionsMenu,
|
||||||
|
toggleDeviceId: toggleDeviceId,
|
||||||
|
toggleCluster: toggleCluster,
|
||||||
|
|
||||||
|
toggleMeasureDistance: toggleMeasureDistance,
|
||||||
|
finishMeasuring: finishMeasuring,
|
||||||
|
clearMeasure: clearMeasure,
|
||||||
|
|
||||||
|
toggleWeatherForecast: toggleWeatherForecast,
|
||||||
|
closeWeatherCard: closeWeatherCard,
|
||||||
|
showPrevForecast: showPrevForecast,
|
||||||
|
showNextForecast: showNextForecast
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
window.DeviceOverview = DeviceOverview;
|
||||||
|
window.onMapTypeChange = DeviceOverview.onMapTypeChange;
|
||||||
|
window.searchDeviceNew = DeviceOverview.searchDeviceNew;
|
||||||
|
window.onWarningFilterChange = DeviceOverview.onWarningFilterChange;
|
||||||
|
window.toggleMapFunctionsMenu = DeviceOverview.toggleMapFunctionsMenu;
|
||||||
|
window.toggleDeviceId = DeviceOverview.toggleDeviceId;
|
||||||
|
window.toggleCluster = DeviceOverview.toggleCluster;
|
||||||
|
window.toggleMeasureDistance = DeviceOverview.toggleMeasureDistance;
|
||||||
|
window.finishMeasuring = DeviceOverview.finishMeasuring;
|
||||||
|
window.clearMeasure = DeviceOverview.clearMeasure;
|
||||||
|
window.toggleWeatherForecast = DeviceOverview.toggleWeatherForecast;
|
||||||
|
window.closeWeatherCard = DeviceOverview.closeWeatherCard;
|
||||||
|
window.showPrevForecast = DeviceOverview.showPrevForecast;
|
||||||
|
window.showNextForecast = DeviceOverview.showNextForecast;
|
||||||
|
window.queryDevices = DeviceOverview.queryDevices;
|
||||||
|
window.locateDeviceOnMap = DeviceOverview.locateDeviceOnMap;
|
||||||
|
window.locateDeviceDirectly = DeviceOverview.locateDeviceDirectly;
|
||||||
|
window.locateMyLocation = DeviceOverview.locateMyLocation;
|
||||||
|
window.clearDeviceFilter = DeviceOverview.clearDeviceFilter;
|
||||||
@ -0,0 +1,347 @@
|
|||||||
|
var MapCore = (function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var map = null;
|
||||||
|
var vectorSource = null;
|
||||||
|
var vectorLayer = null;
|
||||||
|
var clusterSource = null;
|
||||||
|
var clusterLayer = null;
|
||||||
|
var currentBaseLayer = null;
|
||||||
|
var showDeviceId = true;
|
||||||
|
var showCluster = true;
|
||||||
|
var minZoomForLabels = 4;
|
||||||
|
var maxZoomForClustering = 8;
|
||||||
|
var hoveredFeature = null;
|
||||||
|
|
||||||
|
|
||||||
|
function initialize(deviceList) {
|
||||||
|
// 创建矢量数据源和图层
|
||||||
|
vectorSource = new ol.source.Vector();
|
||||||
|
vectorLayer = new ol.layer.Vector({
|
||||||
|
source: vectorSource,
|
||||||
|
style: function(feature) {
|
||||||
|
return DeviceMarkers.createDeviceStyle(feature);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建集群数据源和图层
|
||||||
|
clusterSource = new ol.source.Cluster({
|
||||||
|
distance: 40,
|
||||||
|
source: vectorSource
|
||||||
|
});
|
||||||
|
|
||||||
|
clusterLayer = new ol.layer.Vector({
|
||||||
|
source: clusterSource,
|
||||||
|
style: function(feature) {
|
||||||
|
var size = feature.get('features').length;
|
||||||
|
var style = new ol.style.Style({
|
||||||
|
image: new ol.style.Circle({
|
||||||
|
radius: 15,
|
||||||
|
fill: new ol.style.Fill({
|
||||||
|
color: '#3399CC'
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
text: new ol.style.Text({
|
||||||
|
text: size.toString(),
|
||||||
|
fill: new ol.style.Fill({
|
||||||
|
color: '#fff'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var initialMapType = document.getElementById('mapTypeSelectNew').value || 'tianditu_satellite';
|
||||||
|
currentBaseLayer = MapLayers.getLayer(initialMapType);
|
||||||
|
|
||||||
|
map = new ol.Map({
|
||||||
|
target: 'map-container',
|
||||||
|
layers: [
|
||||||
|
currentBaseLayer,
|
||||||
|
clusterLayer,
|
||||||
|
vectorLayer
|
||||||
|
],
|
||||||
|
view: new ol.View({
|
||||||
|
center: ol.proj.fromLonLat([116.404, 39.915]),
|
||||||
|
zoom: 7
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
DeviceMarkers.init(map, vectorSource, vectorLayer);
|
||||||
|
MeasureTools.init(map);
|
||||||
|
WeatherForecast.init();
|
||||||
|
|
||||||
|
var scaleLineControl = new ol.control.ScaleLine();
|
||||||
|
map.addControl(scaleLineControl);
|
||||||
|
|
||||||
|
var initialZoom = map.getView().getZoom();
|
||||||
|
updateLayerVisibility(initialZoom);
|
||||||
|
|
||||||
|
map.getView().on('change:resolution', function() {
|
||||||
|
var zoom = map.getView().getZoom();
|
||||||
|
updateLayerVisibility(zoom);
|
||||||
|
vectorLayer.changed();
|
||||||
|
});
|
||||||
|
|
||||||
|
bindMouseEvents();
|
||||||
|
|
||||||
|
if (deviceList && deviceList.length > 0) {
|
||||||
|
setCenterFromDevices(deviceList);
|
||||||
|
DeviceMarkers.addDeviceMarkers(deviceList);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceMarkers.getMyLocation();
|
||||||
|
DeviceMarkers.startLocationUpdates();
|
||||||
|
|
||||||
|
document.getElementById('showDeviceIdSwitch').checked = showDeviceId;
|
||||||
|
document.getElementById('showClusterSwitch').checked = showCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLayerVisibility(zoom) {
|
||||||
|
if (showCluster) {
|
||||||
|
if (zoom >= maxZoomForClustering) {
|
||||||
|
clusterLayer.setVisible(false);
|
||||||
|
vectorLayer.setVisible(true);
|
||||||
|
} else {
|
||||||
|
clusterLayer.setVisible(true);
|
||||||
|
vectorLayer.setVisible(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clusterLayer.setVisible(false);
|
||||||
|
vectorLayer.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindMouseEvents() {
|
||||||
|
map.on('pointermove', function(evt) {
|
||||||
|
if (evt.dragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pixel = map.getEventPixel(evt.originalEvent);
|
||||||
|
var hit = map.hasFeatureAtPixel(pixel);
|
||||||
|
|
||||||
|
map.getTargetElement().style.cursor = hit ? 'pointer' : '';
|
||||||
|
|
||||||
|
var feature = map.forEachFeatureAtPixel(pixel, function(feature) {
|
||||||
|
return feature;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hoveredFeature && hoveredFeature !== feature) {
|
||||||
|
hoveredFeature.set('hovered', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (feature) {
|
||||||
|
// 处理集群
|
||||||
|
var features = feature.get('features');
|
||||||
|
if (features && features.length === 1) {
|
||||||
|
features[0].set('hovered', true);
|
||||||
|
hoveredFeature = features[0];
|
||||||
|
} else if (!features && feature.get('deviceInfo')) {
|
||||||
|
feature.set('hovered', true);
|
||||||
|
hoveredFeature = feature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vectorLayer.changed();
|
||||||
|
});
|
||||||
|
|
||||||
|
map.on('click', function(evt) {
|
||||||
|
var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) {
|
||||||
|
return feature;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (feature) {
|
||||||
|
var features = feature.get('features');
|
||||||
|
if (features && features.length > 1) {
|
||||||
|
// 集群点击,扩展视图
|
||||||
|
var extent = vectorSource.getExtent();
|
||||||
|
map.getView().fit(extent, {
|
||||||
|
padding: [50, 50, 50, 50],
|
||||||
|
duration: 1000
|
||||||
|
});
|
||||||
|
} else if (features && features.length === 1) {
|
||||||
|
// 单个设备点击
|
||||||
|
var deviceInfo = features[0].get('deviceInfo');
|
||||||
|
if (deviceInfo) {
|
||||||
|
showDeviceInfo(deviceInfo);
|
||||||
|
// 如果天气预测开启,显示天气卡片
|
||||||
|
if (WeatherForecast.isEnabled()) {
|
||||||
|
WeatherForecast.showWeatherForecast(deviceInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (feature.get('deviceInfo')) {
|
||||||
|
var deviceInfo = feature.get('deviceInfo');
|
||||||
|
showDeviceInfo(deviceInfo);
|
||||||
|
// 如果天气预测开启,显示天气卡片
|
||||||
|
if (WeatherForecast.isEnabled()) {
|
||||||
|
WeatherForecast.showWeatherForecast(deviceInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showDeviceInfo(deviceInfo) {
|
||||||
|
var statusText = '';
|
||||||
|
|
||||||
|
if (deviceInfo.warning === 2) {
|
||||||
|
statusText = '严重告警';
|
||||||
|
} else if (deviceInfo.warning === 1) {
|
||||||
|
statusText = '一般告警';
|
||||||
|
} else {
|
||||||
|
statusText = '正常';
|
||||||
|
}
|
||||||
|
|
||||||
|
var infoMsg = ' 设备: ' + deviceInfo.deviceid +
|
||||||
|
' | 状态: ' + statusText +
|
||||||
|
' | 坐标: ' + deviceInfo.latitude.toFixed(4) + ', ' + deviceInfo.longitude.toFixed(4);
|
||||||
|
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg(infoMsg, {
|
||||||
|
time: 3000,
|
||||||
|
area: ['auto', 'auto'],
|
||||||
|
offset: 'auto'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCenterFromDevices(deviceList) {
|
||||||
|
if (!deviceList || deviceList.length === 0) return;
|
||||||
|
|
||||||
|
var sumLat = 0, sumLon = 0;
|
||||||
|
for (var i = 0; i < deviceList.length; i++) {
|
||||||
|
sumLat += deviceList[i].latitude;
|
||||||
|
sumLon += deviceList[i].longitude;
|
||||||
|
}
|
||||||
|
var centerLat = sumLat / deviceList.length;
|
||||||
|
var centerLon = sumLon / deviceList.length;
|
||||||
|
|
||||||
|
map.getView().setCenter(ol.proj.fromLonLat([centerLon, centerLat]));
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchMapType(mapType) {
|
||||||
|
if (!MapLayers.hasLayer(mapType)) {
|
||||||
|
console.error('未知的地图类型:', mapType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存当前视图状态
|
||||||
|
var currentCenter = map.getView().getCenter();
|
||||||
|
var currentZoom = map.getView().getZoom();
|
||||||
|
|
||||||
|
map.removeLayer(currentBaseLayer);
|
||||||
|
currentBaseLayer = MapLayers.getLayer(mapType);
|
||||||
|
map.getLayers().insertAt(0, currentBaseLayer);
|
||||||
|
|
||||||
|
DeviceMarkers.updateMyLocationForMapType(mapType);
|
||||||
|
|
||||||
|
var deviceList = window.deviceList || [];
|
||||||
|
DeviceMarkers.addDeviceMarkers(deviceList);
|
||||||
|
|
||||||
|
// 恢复之前的视图状态
|
||||||
|
map.getView().setCenter(currentCenter);
|
||||||
|
map.getView().setZoom(currentZoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleDeviceId() {
|
||||||
|
showDeviceId = document.getElementById('showDeviceIdSwitch').checked;
|
||||||
|
DeviceMarkers.setShowDeviceId(showDeviceId);
|
||||||
|
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg(showDeviceId ? '已显示设备信息' : '已隐藏设备信息');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleCluster() {
|
||||||
|
showCluster = document.getElementById('showClusterSwitch').checked;
|
||||||
|
var zoom = map.getView().getZoom();
|
||||||
|
updateLayerVisibility(zoom);
|
||||||
|
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg(showCluster ? '已启用集群显示' : '已禁用集群显示');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMapFunctionsMenu() {
|
||||||
|
var menu = document.getElementById('mapFunctionsMenu');
|
||||||
|
if (menu) {
|
||||||
|
menu.classList.toggle('show');
|
||||||
|
if (menu.classList.contains('show')) {
|
||||||
|
document.addEventListener('click', closeMapFunctionsMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeMapFunctionsMenu(event) {
|
||||||
|
var dropdown = document.getElementById('mapFunctionsMenu');
|
||||||
|
var toggleBtn = document.querySelector('.dropdown-toggle');
|
||||||
|
|
||||||
|
if (dropdown && !dropdown.contains(event.target) && !toggleBtn.contains(event.target)) {
|
||||||
|
dropdown.classList.remove('show');
|
||||||
|
document.removeEventListener('click', closeMapFunctionsMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMapTypeChange() {
|
||||||
|
var mapType = document.getElementById('mapTypeSelectNew').value;
|
||||||
|
switchMapType(mapType);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onWarningFilterChange() {
|
||||||
|
var filterValue = document.getElementById('warningFilter').value;
|
||||||
|
switch(filterValue) {
|
||||||
|
case 'all':
|
||||||
|
SearchFilter.showAllDevices();
|
||||||
|
break;
|
||||||
|
case 'warning1':
|
||||||
|
SearchFilter.showWarning1Devices();
|
||||||
|
break;
|
||||||
|
case 'warning2':
|
||||||
|
SearchFilter.showWarning2Devices();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchDeviceNew() {
|
||||||
|
var searchInput = document.getElementById('deviceSearchNew');
|
||||||
|
if (searchInput) {
|
||||||
|
var deviceId = searchInput.value.trim();
|
||||||
|
if (deviceId) {
|
||||||
|
SearchFilter.searchDevice(deviceId);
|
||||||
|
} else {
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('请输入设备编号');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVectorSource() {
|
||||||
|
return vectorSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVectorLayer() {
|
||||||
|
return vectorLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
initialize: initialize,
|
||||||
|
switchMapType: switchMapType,
|
||||||
|
toggleDeviceId: toggleDeviceId,
|
||||||
|
toggleCluster: toggleCluster,
|
||||||
|
toggleMapFunctionsMenu: toggleMapFunctionsMenu,
|
||||||
|
onMapTypeChange: onMapTypeChange,
|
||||||
|
onWarningFilterChange: onWarningFilterChange,
|
||||||
|
searchDeviceNew: searchDeviceNew,
|
||||||
|
getMap: getMap,
|
||||||
|
getVectorSource: getVectorSource,
|
||||||
|
getVectorLayer: getVectorLayer
|
||||||
|
};
|
||||||
|
})();
|
||||||
@ -0,0 +1,176 @@
|
|||||||
|
var MapLayers = (function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// 天地图 API 密钥 (fengyarnom@gmail.com)
|
||||||
|
// 天地图的英文就是 TIANDITU 所以这里用拼音指代
|
||||||
|
var TIANDITU_KEY = '0c260b8a094a4e0bc507808812cefdac';
|
||||||
|
|
||||||
|
function createTiandituTileLoadFunction() {
|
||||||
|
return function(imageTile, src) {
|
||||||
|
imageTile.getImage().src = src;
|
||||||
|
imageTile.getImage().onerror = function() {
|
||||||
|
// 天地图加载失败时切换到高德地图
|
||||||
|
var mapTypeSelect = document.getElementById('mapTypeSelectNew');
|
||||||
|
if(mapTypeSelect && mapTypeSelect.value.startsWith('tianditu_')) {
|
||||||
|
mapTypeSelect.value = 'amap';
|
||||||
|
if (window.DeviceOverview && typeof window.DeviceOverview.switchMapType === 'function') {
|
||||||
|
window.DeviceOverview.switchMapType('amap');
|
||||||
|
}
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('天地图加载失败,已自动切换到高德地图');
|
||||||
|
}
|
||||||
|
if (window.layui && window.layui.form) {
|
||||||
|
window.layui.form.render('select');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var mapLayers = {
|
||||||
|
// 高德地图
|
||||||
|
amap: new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://webrd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 高德卫星图
|
||||||
|
amap_satellite: new ol.layer.Group({
|
||||||
|
layers: [
|
||||||
|
new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://webst0{1-4}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}'
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://webst0{1-4}.is.autonavi.com/appmaptile?style=8&x={x}&y={y}&z={z}'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 谷歌卫星图
|
||||||
|
google_satellite: new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://mt{0-3}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}',
|
||||||
|
crossOrigin: 'anonymous'
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 谷歌地形图
|
||||||
|
google_terrain: new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://mt{0-3}.google.com/vt/lyrs=p&x={x}&y={y}&z={z}',
|
||||||
|
crossOrigin: 'anonymous'
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 谷歌道路图
|
||||||
|
google_roadmap: new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://mt{0-3}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',
|
||||||
|
crossOrigin: 'anonymous'
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 谷歌混合图
|
||||||
|
google_hybrid: new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://mt{0-3}.google.com/vt/lyrs=y&x={x}&y={y}&z={z}',
|
||||||
|
crossOrigin: 'anonymous'
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 天地图卫星影像
|
||||||
|
tianditu_satellite: new ol.layer.Group({
|
||||||
|
layers: [
|
||||||
|
new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://t{0-7}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
|
||||||
|
tileLoadFunction: createTiandituTileLoadFunction()
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://t{0-7}.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
|
||||||
|
tileLoadFunction: createTiandituTileLoadFunction()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 天地图矢量图
|
||||||
|
tianditu_normal: new ol.layer.Group({
|
||||||
|
layers: [
|
||||||
|
new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://t{0-7}.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
|
||||||
|
tileLoadFunction: createTiandituTileLoadFunction()
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://t{0-7}.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
|
||||||
|
tileLoadFunction: createTiandituTileLoadFunction()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 天地图地形图
|
||||||
|
tianditu_terrain: new ol.layer.Group({
|
||||||
|
layers: [
|
||||||
|
new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://t{0-7}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
|
||||||
|
tileLoadFunction: createTiandituTileLoadFunction()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 天地图地形混合图
|
||||||
|
tianditu_terrain_hybrid: new ol.layer.Group({
|
||||||
|
layers: [
|
||||||
|
new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://t{0-7}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
|
||||||
|
tileLoadFunction: createTiandituTileLoadFunction()
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
new ol.layer.Tile({
|
||||||
|
source: new ol.source.XYZ({
|
||||||
|
url: 'https://t{0-7}.tianditu.gov.cn/cta_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cta&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
|
||||||
|
tileLoadFunction: createTiandituTileLoadFunction()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function getLayer(mapType) {
|
||||||
|
return mapLayers[mapType];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function getAllLayers() {
|
||||||
|
return mapLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function hasLayer(mapType) {
|
||||||
|
return mapLayers.hasOwnProperty(mapType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
getLayer: getLayer,
|
||||||
|
getAllLayers: getAllLayers,
|
||||||
|
hasLayer: hasLayer
|
||||||
|
};
|
||||||
|
})();
|
||||||
@ -0,0 +1,299 @@
|
|||||||
|
var MeasureTools = (function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var measureActive = false;
|
||||||
|
var measureDraw = null;
|
||||||
|
var measureSource = null;
|
||||||
|
var measureLayer = null;
|
||||||
|
var measureTooltips = [];
|
||||||
|
var measureFeatures = [];
|
||||||
|
var currentMeasureTooltips = [];
|
||||||
|
var currentSketch = null;
|
||||||
|
var currentListener = null;
|
||||||
|
var segmentTooltips = [];
|
||||||
|
var map = null;
|
||||||
|
|
||||||
|
function init(mapInstance) {
|
||||||
|
map = mapInstance;
|
||||||
|
|
||||||
|
// 测距专用图层
|
||||||
|
measureSource = new ol.source.Vector();
|
||||||
|
measureLayer = new ol.layer.Vector({
|
||||||
|
source: measureSource,
|
||||||
|
style: new ol.style.Style({
|
||||||
|
fill: new ol.style.Fill({ color: 'rgba(255,255,255,0.2)' }),
|
||||||
|
stroke: new ol.style.Stroke({ color: '#ffcc33', width: 2 }),
|
||||||
|
image: new ol.style.RegularShape({
|
||||||
|
points: 4,
|
||||||
|
radius: 8,
|
||||||
|
radius2: 0,
|
||||||
|
angle: Math.PI / 4,
|
||||||
|
stroke: new ol.style.Stroke({ color: '#ed8936', width: 2 })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (map) {
|
||||||
|
map.addLayer(measureLayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMeasureDistance() {
|
||||||
|
if (measureActive) {
|
||||||
|
deactivateMeasure();
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('测距功能已关闭');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
activateMeasure();
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('点击左键添加距离节点,点击右键结束测量 :)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var menu = document.getElementById('mapFunctionsMenu');
|
||||||
|
if (menu) {
|
||||||
|
menu.classList.remove('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishMeasuring() {
|
||||||
|
if (measureActive && currentSketch && measureDraw) {
|
||||||
|
measureDraw.finishDrawing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function activateMeasure() {
|
||||||
|
if (!map || !measureSource) return;
|
||||||
|
|
||||||
|
measureActive = true;
|
||||||
|
|
||||||
|
// 显示测量状态指示器
|
||||||
|
var measureStatus = document.getElementById('measureStatus');
|
||||||
|
if (measureStatus) {
|
||||||
|
measureStatus.style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
|
measureDraw = new ol.interaction.Draw({
|
||||||
|
source: measureSource,
|
||||||
|
type: 'LineString',
|
||||||
|
style: new ol.style.Style({
|
||||||
|
fill: new ol.style.Fill({ color: 'rgba(255,255,255,0.2)' }),
|
||||||
|
stroke: new ol.style.Stroke({ color: '#ffcc33', width: 2 }),
|
||||||
|
image: new ol.style.RegularShape({
|
||||||
|
points: 4,
|
||||||
|
radius: 8,
|
||||||
|
radius2: 0,
|
||||||
|
angle: Math.PI / 4,
|
||||||
|
stroke: new ol.style.Stroke({ color: '#ed8936', width: 2 })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
map.addInteraction(measureDraw);
|
||||||
|
|
||||||
|
map.getViewport().addEventListener('contextmenu', function(e) {
|
||||||
|
if (measureActive && currentSketch) {
|
||||||
|
e.preventDefault();
|
||||||
|
measureDraw.finishDrawing();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
measureDraw.on('drawstart', function(evt) {
|
||||||
|
currentSketch = evt.feature;
|
||||||
|
currentMeasureTooltips = [];
|
||||||
|
segmentTooltips = [];
|
||||||
|
|
||||||
|
currentListener = currentSketch.getGeometry().on('change', function(e) {
|
||||||
|
var geom = e.target;
|
||||||
|
var coords = geom.getCoordinates();
|
||||||
|
|
||||||
|
clearTemporaryTooltips();
|
||||||
|
clearSegmentTooltips();
|
||||||
|
|
||||||
|
// 计算并显示每个节点的距离
|
||||||
|
var total = 0;
|
||||||
|
for (var i = 0; i < coords.length; i++) {
|
||||||
|
if (i === 0) {
|
||||||
|
// 起点
|
||||||
|
var startTooltip = createMeasureTooltip(coords[0], '起点');
|
||||||
|
currentMeasureTooltips.push(startTooltip);
|
||||||
|
} else {
|
||||||
|
// 计算段距离
|
||||||
|
var seg = new ol.geom.LineString([coords[i-1], coords[i]]);
|
||||||
|
var segmentLength = ol.sphere.getLength(seg);
|
||||||
|
total += segmentLength;
|
||||||
|
|
||||||
|
// 显示每个节点的累计距离
|
||||||
|
var output = formatLength(total);
|
||||||
|
var tooltip = createMeasureTooltip(coords[i], output);
|
||||||
|
segmentTooltips.push(tooltip);
|
||||||
|
|
||||||
|
if (i === coords.length - 1) {
|
||||||
|
currentMeasureTooltips.push(tooltip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 绘制结束
|
||||||
|
measureDraw.on('drawend', function(evt) {
|
||||||
|
var coords = evt.feature.getGeometry().getCoordinates();
|
||||||
|
|
||||||
|
clearTemporaryTooltips();
|
||||||
|
clearSegmentTooltips();
|
||||||
|
|
||||||
|
var total = 0;
|
||||||
|
for (var i = 0; i < coords.length; i++) {
|
||||||
|
if (i === 0) {
|
||||||
|
var startTooltip = createMeasureTooltip(coords[0], '起点', true);
|
||||||
|
measureTooltips.push(startTooltip);
|
||||||
|
} else {
|
||||||
|
var seg = new ol.geom.LineString([coords[i-1], coords[i]]);
|
||||||
|
total += ol.sphere.getLength(seg);
|
||||||
|
|
||||||
|
var output = formatLength(total);
|
||||||
|
var tooltip = createMeasureTooltip(coords[i], output, true);
|
||||||
|
measureTooltips.push(tooltip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
measureFeatures.push(evt.feature);
|
||||||
|
|
||||||
|
if (currentListener) {
|
||||||
|
ol.Observable.unByKey(currentListener);
|
||||||
|
}
|
||||||
|
currentSketch = null;
|
||||||
|
currentListener = null;
|
||||||
|
|
||||||
|
var measureStatus = document.getElementById('measureStatus');
|
||||||
|
if (measureStatus) {
|
||||||
|
measureStatus.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
map.removeInteraction(measureDraw);
|
||||||
|
measureActive = false;
|
||||||
|
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('测量完成');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deactivateMeasure() {
|
||||||
|
measureActive = false;
|
||||||
|
|
||||||
|
var measureStatus = document.getElementById('measureStatus');
|
||||||
|
if (measureStatus) {
|
||||||
|
measureStatus.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (measureDraw && map) {
|
||||||
|
map.removeInteraction(measureDraw);
|
||||||
|
measureDraw = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentListener) {
|
||||||
|
ol.Observable.unByKey(currentListener);
|
||||||
|
currentListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSketch = null;
|
||||||
|
clearTemporaryTooltips();
|
||||||
|
clearSegmentTooltips();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMeasureTooltip(coord, text, isStatic) {
|
||||||
|
var elem = document.createElement('div');
|
||||||
|
elem.className = isStatic ? 'ol-tooltip ol-tooltip-static' : 'ol-tooltip ol-tooltip-measure';
|
||||||
|
elem.innerHTML = text;
|
||||||
|
|
||||||
|
var overlay = new ol.Overlay({
|
||||||
|
element: elem,
|
||||||
|
offset: [0, -15],
|
||||||
|
positioning: 'bottom-center'
|
||||||
|
});
|
||||||
|
|
||||||
|
overlay.setPosition(coord);
|
||||||
|
|
||||||
|
if (map) {
|
||||||
|
map.addOverlay(overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
return overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatLength(length) {
|
||||||
|
if (length > 1000) {
|
||||||
|
return (Math.round(length / 100) / 10) + ' km';
|
||||||
|
} else {
|
||||||
|
return (Math.round(length * 10) / 10) + ' m';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearAllMeasureTooltips() {
|
||||||
|
if (!map) return;
|
||||||
|
|
||||||
|
for (var i = 0; i < measureTooltips.length; i++) {
|
||||||
|
map.removeOverlay(measureTooltips[i]);
|
||||||
|
}
|
||||||
|
measureTooltips = [];
|
||||||
|
|
||||||
|
clearTemporaryTooltips();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearTemporaryTooltips() {
|
||||||
|
if (!map) return;
|
||||||
|
|
||||||
|
for (var i = 0; i < currentMeasureTooltips.length; i++) {
|
||||||
|
map.removeOverlay(currentMeasureTooltips[i]);
|
||||||
|
}
|
||||||
|
currentMeasureTooltips = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearSegmentTooltips() {
|
||||||
|
if (!map) return;
|
||||||
|
|
||||||
|
for (var i = 0; i < segmentTooltips.length; i++) {
|
||||||
|
map.removeOverlay(segmentTooltips[i]);
|
||||||
|
}
|
||||||
|
segmentTooltips = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearMeasure() {
|
||||||
|
if (measureSource) {
|
||||||
|
measureSource.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
clearAllMeasureTooltips();
|
||||||
|
measureFeatures = [];
|
||||||
|
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('测距标记已清除');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭地图功能菜单
|
||||||
|
var menu = document.getElementById('mapFunctionsMenu');
|
||||||
|
if (menu) {
|
||||||
|
menu.classList.remove('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isActive() {
|
||||||
|
return measureActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMeasureCount() {
|
||||||
|
return measureFeatures.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: init,
|
||||||
|
toggleMeasureDistance: toggleMeasureDistance,
|
||||||
|
finishMeasuring: finishMeasuring,
|
||||||
|
clearMeasure: clearMeasure,
|
||||||
|
isActive: isActive,
|
||||||
|
getMeasureCount: getMeasureCount
|
||||||
|
};
|
||||||
|
})();
|
||||||
@ -0,0 +1,327 @@
|
|||||||
|
var SearchFilter = (function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var currentSearchedDevice = null;
|
||||||
|
var markerState = 3; // 1:all; 2:orange; 3:red
|
||||||
|
var filteredDeviceIds = [];
|
||||||
|
var isFilterActive = false;
|
||||||
|
|
||||||
|
function searchDevice(deviceId) {
|
||||||
|
if (!deviceId || !deviceId.trim()) {
|
||||||
|
clearSearch();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceId = deviceId.trim();
|
||||||
|
|
||||||
|
// 多设备
|
||||||
|
if (deviceId.indexOf(',') !== -1) {
|
||||||
|
return handleMultiDeviceSearch(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单设备
|
||||||
|
currentSearchedDevice = deviceId;
|
||||||
|
|
||||||
|
var success = DeviceMarkers.locateDevice(deviceId);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('已定位到设备: ' + deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取设备信息并显示天气预测(如果启用)
|
||||||
|
var targetFeature = DeviceMarkers.findDeviceById(deviceId);
|
||||||
|
if (targetFeature && window.WeatherForecast && window.WeatherForecast.isEnabled()) {
|
||||||
|
var deviceInfo = targetFeature.get('deviceInfo');
|
||||||
|
if (deviceInfo) {
|
||||||
|
window.WeatherForecast.showWeatherForecast(deviceInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('未找到设备: ' + deviceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMultiDeviceSearch(deviceIdsString) {
|
||||||
|
var deviceIds = deviceIdsString.split(',').map(function(id) {
|
||||||
|
return id.trim();
|
||||||
|
}).filter(function(id) {
|
||||||
|
return id !== '';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (deviceIds.length === 0) {
|
||||||
|
clearSearch();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredDeviceIds = deviceIds;
|
||||||
|
|
||||||
|
var foundDevices = filterDevicesByIds(deviceIds);
|
||||||
|
|
||||||
|
if (foundDevices.length > 0) {
|
||||||
|
showFilterStatus(deviceIds.length);
|
||||||
|
|
||||||
|
isFilterActive = true;
|
||||||
|
|
||||||
|
var firstDevice = foundDevices[0];
|
||||||
|
var geometry = firstDevice.getGeometry();
|
||||||
|
var coordinates = geometry.getCoordinates();
|
||||||
|
|
||||||
|
if (MapCore.getMap()) {
|
||||||
|
MapCore.getMap().getView().animate({
|
||||||
|
center: coordinates,
|
||||||
|
zoom: 12,
|
||||||
|
duration: 1000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('已过滤显示 ' + foundDevices.length + ' 个设备');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('未找到任何匹配的设备');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterDevicesByIds(deviceIds) {
|
||||||
|
if (!DeviceMarkers.getAllFeatures) return [];
|
||||||
|
|
||||||
|
var allFeatures = DeviceMarkers.getAllFeatures();
|
||||||
|
var foundDevices = [];
|
||||||
|
var vectorSource = MapCore.getVectorSource();
|
||||||
|
|
||||||
|
if (!vectorSource) return [];
|
||||||
|
|
||||||
|
var myLocationFeature = DeviceMarkers.getMyLocationFeature();
|
||||||
|
|
||||||
|
vectorSource.clear();
|
||||||
|
|
||||||
|
if (myLocationFeature) {
|
||||||
|
vectorSource.addFeature(myLocationFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < allFeatures.length; i++) {
|
||||||
|
var feature = allFeatures[i];
|
||||||
|
var deviceInfo = feature.get('deviceInfo');
|
||||||
|
|
||||||
|
if (deviceInfo) {
|
||||||
|
var deviceId = String(deviceInfo.deviceid).trim();
|
||||||
|
|
||||||
|
for (var j = 0; j < deviceIds.length; j++) {
|
||||||
|
var searchId = String(deviceIds[j]).trim();
|
||||||
|
|
||||||
|
if (deviceId === searchId ||
|
||||||
|
deviceId.indexOf(searchId) !== -1 ||
|
||||||
|
deviceId.replace(/\s+/g, '') === searchId.replace(/\s+/g, '')) {
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
foundDevices.push(feature);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showFilterStatus(count) {
|
||||||
|
var filterStatus = document.getElementById('filterStatus');
|
||||||
|
|
||||||
|
if (filterStatus) {
|
||||||
|
filterStatus.innerHTML =
|
||||||
|
'<span style="color: #1aa094; font-weight: bold; font-size: 12px;">定位中</span>' +
|
||||||
|
'<button class="toolbar-btn" onclick="clearDeviceFilter()" style="background: #f56565; margin-left: 6px;">' +
|
||||||
|
'<i class="layui-icon layui-icon-close" style="font-size: 12px;"></i>' +
|
||||||
|
'</button>';
|
||||||
|
|
||||||
|
filterStatus.style.display = 'flex';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideFilterStatus() {
|
||||||
|
var filterStatus = document.getElementById('filterStatus');
|
||||||
|
if (filterStatus) {
|
||||||
|
filterStatus.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearDeviceFilter() {
|
||||||
|
isFilterActive = false;
|
||||||
|
filteredDeviceIds = [];
|
||||||
|
hideFilterStatus();
|
||||||
|
|
||||||
|
applyCurrentFilter();
|
||||||
|
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('已清除设备过滤');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearSearch() {
|
||||||
|
currentSearchedDevice = null;
|
||||||
|
var searchInput = document.getElementById('deviceSearchNew');
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFilterActive) {
|
||||||
|
clearDeviceFilter();
|
||||||
|
} else {
|
||||||
|
// 恢复到当前的过滤状态
|
||||||
|
applyCurrentFilter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyCurrentFilter() {
|
||||||
|
switch(markerState) {
|
||||||
|
case 1:
|
||||||
|
showAllDevices();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
showWarning1Devices();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
showWarning2Devices();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAllDevices() {
|
||||||
|
currentSearchedDevice = null;
|
||||||
|
clearSearchInput();
|
||||||
|
DeviceMarkers.showAllDevices();
|
||||||
|
markerState = 1;
|
||||||
|
updateFilterSelect('all');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showWarning1Devices() {
|
||||||
|
currentSearchedDevice = null;
|
||||||
|
clearSearchInput();
|
||||||
|
DeviceMarkers.showWarning1Devices();
|
||||||
|
markerState = 2;
|
||||||
|
updateFilterSelect('warning1');
|
||||||
|
}
|
||||||
|
function showWarning2Devices() {
|
||||||
|
currentSearchedDevice = null;
|
||||||
|
clearSearchInput();
|
||||||
|
DeviceMarkers.showWarning2Devices();
|
||||||
|
markerState = 3;
|
||||||
|
updateFilterSelect('warning2');
|
||||||
|
}
|
||||||
|
function clearSearchInput() {
|
||||||
|
var searchInput = document.getElementById('deviceSearchNew');
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFilterSelect(filterValue) {
|
||||||
|
var filterSelect = document.getElementById('warningFilter');
|
||||||
|
if (filterSelect) {
|
||||||
|
filterSelect.value = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterDevicesByStatus(statusType) {
|
||||||
|
switch(statusType) {
|
||||||
|
case 'warning1':
|
||||||
|
showWarning1Devices();
|
||||||
|
break;
|
||||||
|
case 'warning2':
|
||||||
|
showWarning2Devices();
|
||||||
|
break;
|
||||||
|
case 'offline':
|
||||||
|
case 'no_fwd':
|
||||||
|
case 'nofixed':
|
||||||
|
case 'nogga':
|
||||||
|
// 对于这些状态,显示所有设备,让用户在弹窗中选择
|
||||||
|
showAllDevices();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
showAllDevices();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryDevices(statusType) {
|
||||||
|
filterDevicesByStatus(statusType);
|
||||||
|
|
||||||
|
// 打开设备列表弹窗
|
||||||
|
if (window.layer && typeof window.layer.open === 'function') {
|
||||||
|
var index = window.layer.open({
|
||||||
|
title: '设备列表',
|
||||||
|
type: 2,
|
||||||
|
shade: 0.2,
|
||||||
|
maxmin: true,
|
||||||
|
shadeClose: true,
|
||||||
|
anim: 2,
|
||||||
|
offset: 'rb',
|
||||||
|
area: ['100%', '50%'],
|
||||||
|
content: '../page/gnss_q_status?query=' + statusType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function locateDeviceOnMap(deviceId, latitude, longitude) {
|
||||||
|
currentSearchedDevice = deviceId;
|
||||||
|
var success = DeviceMarkers.locateDevice(deviceId);
|
||||||
|
|
||||||
|
if (success && window.layer && typeof window.layer.closeAll === 'function') {
|
||||||
|
window.layer.closeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
function locateDeviceDirectly(deviceId) {
|
||||||
|
currentSearchedDevice = deviceId;
|
||||||
|
return DeviceMarkers.locateDevice(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentSearchedDevice() {
|
||||||
|
return currentSearchedDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMarkerState() {
|
||||||
|
return markerState;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMarkerState(state) {
|
||||||
|
markerState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFilterModeActive() {
|
||||||
|
return isFilterActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFilteredDeviceIds() {
|
||||||
|
return filteredDeviceIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
searchDevice: searchDevice,
|
||||||
|
clearSearch: clearSearch,
|
||||||
|
showAllDevices: showAllDevices,
|
||||||
|
showWarning1Devices: showWarning1Devices,
|
||||||
|
showWarning2Devices: showWarning2Devices,
|
||||||
|
filterDevicesByStatus: filterDevicesByStatus,
|
||||||
|
queryDevices: queryDevices,
|
||||||
|
locateDeviceOnMap: locateDeviceOnMap,
|
||||||
|
locateDeviceDirectly: locateDeviceDirectly,
|
||||||
|
getCurrentSearchedDevice: getCurrentSearchedDevice,
|
||||||
|
getMarkerState: getMarkerState,
|
||||||
|
setMarkerState: setMarkerState,
|
||||||
|
clearDeviceFilter: clearDeviceFilter,
|
||||||
|
isFilterModeActive: isFilterModeActive,
|
||||||
|
getFilteredDeviceIds: getFilteredDeviceIds
|
||||||
|
};
|
||||||
|
})();
|
||||||
@ -0,0 +1,343 @@
|
|||||||
|
var WeatherForecast = (function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var weatherEnabled = false;
|
||||||
|
var weatherData = null;
|
||||||
|
var currentForecastIndex = 0;
|
||||||
|
var currentWeatherDevice = null;
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
// 天气预报模块初始化完成
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleWeatherForecast() {
|
||||||
|
var role = window.userRole || 'USER';
|
||||||
|
if (role !== 'SUPER_ADMIN') {
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('您没有权限使用此功能');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var enableSwitch = document.getElementById('enableWeatherSwitch');
|
||||||
|
weatherEnabled = enableSwitch ? enableSwitch.checked : false;
|
||||||
|
|
||||||
|
if (weatherEnabled) {
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg(
|
||||||
|
'搜索设备或点击地图设备图标即可自动查询天气预测',
|
||||||
|
{time: 3000, area: ['300px', '80px']}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('天气预测功能已关闭');
|
||||||
|
}
|
||||||
|
closeWeatherCard();
|
||||||
|
}
|
||||||
|
|
||||||
|
var menu = document.getElementById('mapFunctionsMenu');
|
||||||
|
if (menu) {
|
||||||
|
menu.classList.remove('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showWeatherForecast(deviceInfo) {
|
||||||
|
currentWeatherDevice = deviceInfo;
|
||||||
|
weatherData = null;
|
||||||
|
|
||||||
|
var role = window.userRole || 'USER';
|
||||||
|
if (role !== 'SUPER_ADMIN') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!weatherEnabled) {
|
||||||
|
if (window.layer && typeof window.layer.msg === 'function') {
|
||||||
|
window.layer.msg('天气预测功能未启用', {time: 2000});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var deviceIdElement = document.getElementById('weatherDeviceId');
|
||||||
|
var deviceCoordsElement = document.getElementById('weatherDeviceCoords');
|
||||||
|
|
||||||
|
if (deviceIdElement) {
|
||||||
|
deviceIdElement.textContent = '设备: ' + deviceInfo.deviceid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceCoordsElement) {
|
||||||
|
deviceCoordsElement.textContent =
|
||||||
|
'坐标: ' + deviceInfo.latitude.toFixed(4) + ', ' + deviceInfo.longitude.toFixed(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
var weatherCard = document.getElementById('weatherForecastCard');
|
||||||
|
if (weatherCard) {
|
||||||
|
weatherCard.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentElement = document.getElementById('weatherForecastContent');
|
||||||
|
if (contentElement) {
|
||||||
|
contentElement.innerHTML =
|
||||||
|
'<div class="weather-loading">' +
|
||||||
|
'<i class="layui-icon layui-icon-loading layui-icon-anim-rotate"></i>' +
|
||||||
|
'<p>正在获取天气预测数据...</p>' +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
var prevBtn = document.getElementById('prevForecast');
|
||||||
|
var nextBtn = document.getElementById('nextForecast');
|
||||||
|
var timeDisplay = document.getElementById('forecastTimeDisplay');
|
||||||
|
|
||||||
|
if (prevBtn) prevBtn.disabled = true;
|
||||||
|
if (nextBtn) nextBtn.disabled = true;
|
||||||
|
if (timeDisplay) timeDisplay.textContent = '--:--';
|
||||||
|
|
||||||
|
fetchWeatherData(deviceInfo.latitude, deviceInfo.longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeWeatherCard() {
|
||||||
|
var weatherCard = document.getElementById('weatherForecastCard');
|
||||||
|
if (weatherCard) {
|
||||||
|
weatherCard.style.display = 'none';
|
||||||
|
}
|
||||||
|
currentWeatherDevice = null;
|
||||||
|
weatherData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPrevForecast() {
|
||||||
|
if (!weatherData || currentForecastIndex <= 0) return;
|
||||||
|
|
||||||
|
currentForecastIndex--;
|
||||||
|
displayCurrentForecast();
|
||||||
|
updateForecastNavigation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showNextForecast() {
|
||||||
|
if (!weatherData || !weatherData.ts || currentForecastIndex >= weatherData.ts.length - 1) return;
|
||||||
|
|
||||||
|
currentForecastIndex++;
|
||||||
|
displayCurrentForecast();
|
||||||
|
updateForecastNavigation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateForecastNavigation() {
|
||||||
|
if (!weatherData || !weatherData.ts) return;
|
||||||
|
|
||||||
|
var prevBtn = document.getElementById('prevForecast');
|
||||||
|
var nextBtn = document.getElementById('nextForecast');
|
||||||
|
var timeDisplay = document.getElementById('forecastTimeDisplay');
|
||||||
|
|
||||||
|
if (prevBtn) prevBtn.disabled = (currentForecastIndex <= 0);
|
||||||
|
if (nextBtn) nextBtn.disabled = (currentForecastIndex >= weatherData.ts.length - 1);
|
||||||
|
|
||||||
|
if (timeDisplay) {
|
||||||
|
var timestamp = weatherData.ts[currentForecastIndex];
|
||||||
|
var date = new Date(timestamp);
|
||||||
|
timeDisplay.textContent = formatDateTime(date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchWeatherData(lat, lon) {
|
||||||
|
var url = 'https://api.open-meteo.com/v1/forecast?' +
|
||||||
|
'latitude=' + lat.toFixed(4) +
|
||||||
|
'&longitude=' + lon.toFixed(4) +
|
||||||
|
'¤t=temperature_2m,wind_speed_10m,wind_direction_10m,relative_humidity_2m,surface_pressure' +
|
||||||
|
'&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m,wind_direction_10m,precipitation,surface_pressure,wind_gusts_10m' +
|
||||||
|
'&forecast_days=3' +
|
||||||
|
'&timezone=auto';
|
||||||
|
|
||||||
|
fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(response) {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('网络响应状态: ' + response.status);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(function(data) {
|
||||||
|
weatherData = transformOpenMeteoData(data);
|
||||||
|
|
||||||
|
var currentTime = new Date().getTime();
|
||||||
|
var closestIndex = 0;
|
||||||
|
var futureIndex = -1;
|
||||||
|
|
||||||
|
if (weatherData.ts && weatherData.ts.length > 0) {
|
||||||
|
for (var i = 0; i < weatherData.ts.length; i++) {
|
||||||
|
if (weatherData.ts[i] > currentTime) {
|
||||||
|
futureIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (futureIndex >= 0) {
|
||||||
|
closestIndex = futureIndex;
|
||||||
|
} else {
|
||||||
|
var smallestDiff = Number.MAX_VALUE;
|
||||||
|
for (var i = 0; i < weatherData.ts.length; i++) {
|
||||||
|
var diff = Math.abs(weatherData.ts[i] - currentTime);
|
||||||
|
if (diff < smallestDiff) {
|
||||||
|
smallestDiff = diff;
|
||||||
|
closestIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentForecastIndex = closestIndex;
|
||||||
|
displayCurrentForecast();
|
||||||
|
updateForecastNavigation();
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
console.error('天气数据获取失败:', error);
|
||||||
|
displayWeatherError('获取天气数据失败: ' + error.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformOpenMeteoData(data) {
|
||||||
|
var transformed = {
|
||||||
|
ts: [],
|
||||||
|
'temp-surface': [],
|
||||||
|
'wind-speed': [],
|
||||||
|
'wind-direction': [],
|
||||||
|
'precipitation': [],
|
||||||
|
'rh-surface': [],
|
||||||
|
'pressure-surface': [],
|
||||||
|
'gust-surface': []
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!data.hourly || !data.hourly.time) {
|
||||||
|
return transformed;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < data.hourly.time.length; i++) {
|
||||||
|
transformed.ts.push(new Date(data.hourly.time[i]).getTime());
|
||||||
|
|
||||||
|
transformed['temp-surface'].push(data.hourly.temperature_2m[i]);
|
||||||
|
|
||||||
|
var windSpeedMs = data.hourly.wind_speed_10m[i] ? data.hourly.wind_speed_10m[i] / 3.6 : null;
|
||||||
|
transformed['wind-speed'].push(windSpeedMs);
|
||||||
|
transformed['wind-direction'].push(data.hourly.wind_direction_10m[i]);
|
||||||
|
transformed['precipitation'].push(data.hourly.precipitation[i]);
|
||||||
|
transformed['rh-surface'].push(data.hourly.relative_humidity_2m[i]);
|
||||||
|
transformed['pressure-surface'].push(data.hourly.surface_pressure[i]);
|
||||||
|
var gustMs = data.hourly.wind_gusts_10m[i] ? data.hourly.wind_gusts_10m[i] / 3.6 : null;
|
||||||
|
transformed['gust-surface'].push(gustMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return transformed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayCurrentForecast() {
|
||||||
|
if (!weatherData || !weatherData.ts || weatherData.ts.length === 0) {
|
||||||
|
displayWeatherError('无可用的天气预测数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = currentForecastIndex;
|
||||||
|
var forecastHtml = '<div class="weather-forecast-item"><div class="weather-param-grid">';
|
||||||
|
|
||||||
|
if (weatherData['temp-surface'] && weatherData['temp-surface'][i] !== null) {
|
||||||
|
var temp = weatherData['temp-surface'][i].toFixed(1);
|
||||||
|
forecastHtml += createWeatherParam('温度', temp + '°C');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weatherData['wind-speed'] && weatherData['wind-speed'][i] !== null) {
|
||||||
|
var windSpeed = weatherData['wind-speed'][i].toFixed(1);
|
||||||
|
forecastHtml += createWeatherParam('风速', windSpeed + ' m/s');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weatherData['wind-direction'] && weatherData['wind-direction'][i] !== null) {
|
||||||
|
var windDir = getWindDirectionFromDegrees(weatherData['wind-direction'][i]);
|
||||||
|
forecastHtml += createWeatherParam('风向', windDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weatherData['precipitation'] && weatherData['precipitation'][i] !== null) {
|
||||||
|
var precip = weatherData['precipitation'][i].toFixed(1);
|
||||||
|
forecastHtml += createWeatherParam('降水', precip + ' mm');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weatherData['rh-surface'] && weatherData['rh-surface'][i] !== null) {
|
||||||
|
var humidity = weatherData['rh-surface'][i].toFixed(0);
|
||||||
|
forecastHtml += createWeatherParam('湿度', humidity + '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weatherData['pressure-surface'] && weatherData['pressure-surface'][i] !== null) {
|
||||||
|
var pressure = weatherData['pressure-surface'][i].toFixed(0);
|
||||||
|
forecastHtml += createWeatherParam('气压', pressure + ' hPa');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weatherData['gust-surface'] && weatherData['gust-surface'][i] !== null) {
|
||||||
|
var gust = weatherData['gust-surface'][i].toFixed(1);
|
||||||
|
forecastHtml += createWeatherParam('阵风', gust + ' m/s');
|
||||||
|
}
|
||||||
|
|
||||||
|
forecastHtml += '</div></div>';
|
||||||
|
|
||||||
|
var contentElement = document.getElementById('weatherForecastContent');
|
||||||
|
if (contentElement) {
|
||||||
|
contentElement.innerHTML = forecastHtml;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayWeatherError(message) {
|
||||||
|
var contentElement = document.getElementById('weatherForecastContent');
|
||||||
|
if (contentElement) {
|
||||||
|
contentElement.innerHTML =
|
||||||
|
'<div class="weather-error">' +
|
||||||
|
'<i class="layui-icon layui-icon-close"></i>' +
|
||||||
|
'<p>' + message + '</p>' +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWeatherParam(label, value) {
|
||||||
|
return '<div class="weather-param">' +
|
||||||
|
'<span class="weather-param-label">' + label + '</span>' +
|
||||||
|
'<span class="weather-param-value">' + value + '</span>' +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDateTime(date) {
|
||||||
|
var month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||||
|
var day = date.getDate().toString().padStart(2, '0');
|
||||||
|
var hours = date.getHours().toString().padStart(2, '0');
|
||||||
|
var minutes = date.getMinutes().toString().padStart(2, '0');
|
||||||
|
|
||||||
|
return month + '-' + day + ' ' + hours + ':' + minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWindDirection(u, v) {
|
||||||
|
var angle = Math.atan2(-u, -v) * 180 / Math.PI;
|
||||||
|
angle = (angle + 360) % 360;
|
||||||
|
|
||||||
|
var directions = ['北', '东北', '东', '东南', '南', '西南', '西', '西北'];
|
||||||
|
var index = Math.round(angle / 45) % 8;
|
||||||
|
return directions[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWindDirectionFromDegrees(degrees) {
|
||||||
|
if (degrees === null || degrees === undefined) return '无风';
|
||||||
|
|
||||||
|
var directions = ['北', '东北', '东', '东南', '南', '西南', '西', '西北'];
|
||||||
|
var index = Math.round(degrees / 45) % 8;
|
||||||
|
return directions[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
function isEnabled() {
|
||||||
|
return weatherEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: init,
|
||||||
|
toggleWeatherForecast: toggleWeatherForecast,
|
||||||
|
showWeatherForecast: showWeatherForecast,
|
||||||
|
closeWeatherCard: closeWeatherCard,
|
||||||
|
showPrevForecast: showPrevForecast,
|
||||||
|
showNextForecast: showNextForecast,
|
||||||
|
isEnabled: isEnabled
|
||||||
|
};
|
||||||
|
})();
|
||||||
@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>北斗管理系统</title>
|
<title>地质监测平台</title>
|
||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta http-equiv="Access-Control-Allow-Origin" content="*">
|
<meta http-equiv="Access-Control-Allow-Origin" content="*">
|
||||||
|
|||||||
@ -59,7 +59,7 @@
|
|||||||
<div class="main-body">
|
<div class="main-body">
|
||||||
<div class="login-main">
|
<div class="login-main">
|
||||||
<div class="login-top">
|
<div class="login-top">
|
||||||
<span>北斗管理系统登录</span>
|
<span>地质监测系统登录</span>
|
||||||
<span class="bg1"></span>
|
<span class="bg1"></span>
|
||||||
<span class="bg2"></span>
|
<span class="bg2"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -147,6 +147,7 @@
|
|||||||
{field: 'tenantname', title: '所属组织', width: 120},
|
{field: 'tenantname', title: '所属组织', width: 120},
|
||||||
{field: 'fwd_group_id', title: '推送组', width: 80},
|
{field: 'fwd_group_id', title: '推送组', width: 80},
|
||||||
{field: 'fwd_group_id2', title: '推送2', width: 80},
|
{field: 'fwd_group_id2', title: '推送2', width: 80},
|
||||||
|
{field: 'forward_to_ntrip', title: '发送至NtripCaster', width: 120, templet: '#ntripTrans'},
|
||||||
{field: 'opmode', title: '使用状态', width: 80,templet: '#modeTrans'},
|
{field: 'opmode', title: '使用状态', width: 80,templet: '#modeTrans'},
|
||||||
{field: 'syn', title: '参数同步', width: 80,templet: '#synTrans'},
|
{field: 'syn', title: '参数同步', width: 80,templet: '#synTrans'},
|
||||||
{field: 'model', title: '型号', width: 80,templet: "<div>{{d.model==0?'G505':'G510'}}</div>"},
|
{field: 'model', title: '型号', width: 80,templet: "<div>{{d.model==0?'G505':'G510'}}</div>"},
|
||||||
@ -156,7 +157,8 @@
|
|||||||
{title: '操作', toolbar: '#currentTableBar', fixed: "right", width: 120}
|
{title: '操作', toolbar: '#currentTableBar', fixed: "right", width: 120}
|
||||||
];
|
];
|
||||||
if([[${role}]] == "USER") {
|
if([[${role}]] == "USER") {
|
||||||
cfg_cols[17].hide = true;
|
cfg_cols[1].hide = true;
|
||||||
|
cfg_cols[18].hide = true;
|
||||||
}
|
}
|
||||||
else if([[${role}]] != "SUPER_ADMIN") {
|
else if([[${role}]] != "SUPER_ADMIN") {
|
||||||
cfg_cols[1].hide = true;
|
cfg_cols[1].hide = true;
|
||||||
@ -288,5 +290,13 @@
|
|||||||
{{# } }}
|
{{# } }}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" id="ntripTrans">
|
||||||
|
{{# if(d.forward_to_ntrip == false){ }}
|
||||||
|
<span class="layui-badge layui-bg-gray">否</span>
|
||||||
|
{{# } else { }}
|
||||||
|
<span class="layui-badge layui-bg-green">是</span>
|
||||||
|
{{# } }}
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -24,6 +24,18 @@
|
|||||||
<input type="text" name="s_deviceid" autocomplete="off" class="layui-input">
|
<input type="text" name="s_deviceid" autocomplete="off" class="layui-input">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layui-inline">
|
||||||
|
<label class="layui-form-label">电压小于</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="number" name="nlt_voltage" autocomplete="off" class="layui-input">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-inline">
|
||||||
|
<label class="layui-form-label">湿度大于</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="number" name="ngt_humidity" 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">
|
||||||
@ -67,9 +79,9 @@
|
|||||||
var cfg_cols = [
|
var cfg_cols = [
|
||||||
{field: 'deviceid', title: '设备号', width: 100},
|
{field: 'deviceid', title: '设备号', width: 100},
|
||||||
{field: 'createtime', title: '上报时间', templet: "<div>{{layui.util.toDateString(d.createtime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
{field: 'createtime', title: '上报时间', templet: "<div>{{layui.util.toDateString(d.createtime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
||||||
{field: 'roll', title: 'roll', templet: "<div>{{d.roll.toFixed(2)}}</div>"},
|
{field: 'roll', title: 'roll', templet: "<div>{{d.roll.toFixed(3)}}</div>"},
|
||||||
{field: 'pitch', title: 'pitch', templet: "<div>{{d.pitch.toFixed(2)}}</div>"},
|
{field: 'pitch', title: 'pitch', templet: "<div>{{d.pitch.toFixed(3)}}</div>"},
|
||||||
{field: 'yaw', title: 'yaw', templet: "<div>{{d.yaw.toFixed(2)}}</div>"},
|
{field: 'yaw', title: 'yaw', templet: "<div>{{d.yaw.toFixed(3)}}</div>"},
|
||||||
{field: 'rssi', title: '信号强度'},
|
{field: 'rssi', title: '信号强度'},
|
||||||
{field: 'voltage', title: '电压(mV)'},
|
{field: 'voltage', title: '电压(mV)'},
|
||||||
{field: 'solarvoltage', title: '光伏电压(mV)'},
|
{field: 'solarvoltage', title: '光伏电压(mV)'},
|
||||||
|
|||||||
@ -53,16 +53,38 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<table class="layui-hide" id="forwardParaTableId" lay-filter="forwardParaTableFilter"></table>
|
<table class="layui-hide" id="forwardParaTableId" lay-filter="forwardParaTableFilter"></table>
|
||||||
|
<script type="text/html" id="currentTableBar">
|
||||||
|
<a class="layui-btn layui-btn-xs layui-btn-danger data-count-delete" lay-event="delete">删除</a>
|
||||||
|
</script>
|
||||||
|
<script type="text/html" id="toolbarTop">
|
||||||
|
<div class="layui-btn-container" th:if="${role=='SUPER_ADMIN'}">
|
||||||
|
<button class="layui-btn layui-btn-normal layui-btn-sm data-add-btn" lay-event="add">添加</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
|
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script th:inline="none">
|
<script th:inline="javascript">
|
||||||
layui.use(['form', 'table'], function () {
|
layui.use(['form', 'table'], function () {
|
||||||
var $ = layui.$,
|
var $ = layui.$,
|
||||||
form = layui.form,
|
form = layui.form,
|
||||||
table = layui.table,
|
table = layui.table,
|
||||||
laydate = layui.laydate;
|
laydate = layui.laydate;
|
||||||
|
var cfg_cols = [
|
||||||
|
{field: 'projectid', title: '项目号', sort: true},
|
||||||
|
{field: 'deviceid', title: '设备号'},
|
||||||
|
{field: 'createtime', title: '推送时间', templet: "<div>{{layui.util.toDateString(d.createtime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
||||||
|
{field: 'starttime', title: '数据开始时间', templet: "<div>{{layui.util.toDateString(d.starttime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
||||||
|
{field: 'endtime', title: '数据结束时间', templet: "<div>{{layui.util.toDateString(d.endtime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
||||||
|
{field: 'fwd_group_id', title: '推送组'},
|
||||||
|
{field: 'state', title: '状态',templet: '#stateTrans'},
|
||||||
|
{title: '操作', toolbar: '#currentTableBar', fixed: "right", width: 120}
|
||||||
|
];
|
||||||
|
if([[${role}]] != "SUPER_ADMIN") {
|
||||||
|
cfg_cols[7].hide = true;
|
||||||
|
}
|
||||||
|
|
||||||
laydate.render({
|
laydate.render({
|
||||||
elem: '#ID-laydate-start-date1',
|
elem: '#ID-laydate-start-date1',
|
||||||
type: 'datetime'
|
type: 'datetime'
|
||||||
@ -85,17 +107,11 @@
|
|||||||
table.render({
|
table.render({
|
||||||
elem: '#forwardParaTableId',
|
elem: '#forwardParaTableId',
|
||||||
url: '/fwd/resend_records',
|
url: '/fwd/resend_records',
|
||||||
toolbar: '#toolbarTable',
|
toolbar: '#toolbarTop',
|
||||||
defaultToolbar: ['filter'],
|
defaultToolbar: ['filter'],
|
||||||
cols: [[
|
cols: [
|
||||||
{field: 'projectid', title: '项目号', sort: true},
|
cfg_cols
|
||||||
{field: 'deviceid', title: '设备号'},
|
],
|
||||||
{field: 'createtime', title: '推送时间', templet: "<div>{{layui.util.toDateString(d.createtime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
|
||||||
{field: 'starttime', title: '数据开始时间', templet: "<div>{{layui.util.toDateString(d.starttime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
|
||||||
{field: 'endtime', title: '数据结束时间', templet: "<div>{{layui.util.toDateString(d.endtime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
|
||||||
{field: 'fwd_group_id', title: '推送组'},
|
|
||||||
{field: 'state', title: '状态',templet: '#stateTrans'}
|
|
||||||
]],
|
|
||||||
limits: [10, 20, 50, 100, 150],
|
limits: [10, 20, 50, 100, 150],
|
||||||
limit: 10,
|
limit: 10,
|
||||||
page: true,
|
page: true,
|
||||||
@ -119,8 +135,50 @@
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
table.on('toolbar(forwardParaTableFilter)', function (obj) {
|
||||||
|
if (obj.event === 'add') { // 监听添加操作
|
||||||
|
var index = layer.open({
|
||||||
|
title: '添加补传记录',
|
||||||
|
type: 2,
|
||||||
|
shade: 0.2,
|
||||||
|
maxmin:true,
|
||||||
|
shadeClose: true,
|
||||||
|
area: ['100%', '100%'],
|
||||||
|
content: '../page/table/resend_record_add'
|
||||||
|
});
|
||||||
|
$(window).on("resize", function () {
|
||||||
|
layer.full(index);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
table.on('tool(forwardParaTableFilter)', function (obj) {
|
||||||
|
var data = obj.data;
|
||||||
|
if (obj.event === 'delete') {
|
||||||
|
layer.confirm('确定删除?', function(index){
|
||||||
|
$.ajax({
|
||||||
|
type:"POST",
|
||||||
|
url:"/fwd/resend_records/delete",
|
||||||
|
data:{
|
||||||
|
'del_id':data.id
|
||||||
|
},
|
||||||
|
success: function (data) {
|
||||||
|
table.reload('forwardParaTableId');
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
console.log("ajax error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
layer.close(index);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function onUpdated(){
|
||||||
|
layui.table.reload('forwardParaTableId');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/html" id="stateTrans">
|
<script type="text/html" id="stateTrans">
|
||||||
@ -129,9 +187,9 @@
|
|||||||
{{# } else if(d.state == 1){ }}
|
{{# } else if(d.state == 1){ }}
|
||||||
<span class="layui-badge layui-bg-red">推送失败</span>
|
<span class="layui-badge layui-bg-red">推送失败</span>
|
||||||
{{# } else if(d.state == 2){ }}
|
{{# } else if(d.state == 2){ }}
|
||||||
<span class="layui-badge layui-bg-red">断点补传</span>
|
<span class="layui-badge layui-bg-orange">断点补传</span>
|
||||||
{{# } else { }}
|
{{# } else { }}
|
||||||
<span class="layui-badge layui-bg-orange">推送中</span>
|
<span class="layui-badge layui-bg-blue">推送中</span>
|
||||||
{{# } }}
|
{{# } }}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,138 @@
|
|||||||
|
<!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="s_deviceid" autocomplete="off" class="layui-input">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-inline">
|
||||||
|
<label class="layui-form-label">传感器号</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="s_sensorid" autocomplete="off" class="layui-input">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-inline">
|
||||||
|
<label class="layui-form-label">范围</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="dgt_createtime" autocomplete="off" id="ID-laydate-start-date" class="layui-input" placeholder="开始日期">
|
||||||
|
</div>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="dlt_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"></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, fixed: "left"},
|
||||||
|
{field: 'sensorid', title: '传感器号', width: 15, fixed: "left"},
|
||||||
|
{field: 'createtime', title: '上报时间', fixed: "left", templet: "<div>{{layui.util.toDateString(d.createtime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
||||||
|
{field: 'anglex', title: '倾角X', templet: "<div>{{d.anglex.toFixed(3)}}</div>"},
|
||||||
|
{field: 'angley', title: '倾角Y', templet: "<div>{{d.angley.toFixed(3)}}</div>"},
|
||||||
|
{field: 'anglez', title: '倾角Z', templet: "<div>{{d.anglez.toFixed(3)}}</div>"},
|
||||||
|
{field: 'accx', title: '加速度X', templet: "<div>{{d.accx.toFixed(3)}}</div>"},
|
||||||
|
{field: 'accy', title: '加速度Y', templet: "<div>{{d.accy.toFixed(3)}}</div>"},
|
||||||
|
{field: 'accz', title: '加速度Z', templet: "<div>{{d.accz.toFixed(3)}}</div>"},
|
||||||
|
{field: 'maxaccx', title: 'MaxX', templet: "<div>{{d.maxaccx.toFixed(3)}}</div>"},
|
||||||
|
{field: 'maxaccy', title: 'MaxY', templet: "<div>{{d.maxaccy.toFixed(3)}}</div>"},
|
||||||
|
{field: 'maxaccz', title: 'MaxZ', templet: "<div>{{d.maxaccz.toFixed(3)}}</div>"},
|
||||||
|
{field: 'minaccx', title: 'MinX', templet: "<div>{{d.minaccx.toFixed(3)}}</div>"},
|
||||||
|
{field: 'minaccy', title: 'MinY', templet: "<div>{{d.minaccy.toFixed(3)}}</div>"},
|
||||||
|
{field: 'minaccz', title: 'MinZ', templet: "<div>{{d.minaccz.toFixed(3)}}</div>"},
|
||||||
|
|
||||||
|
];
|
||||||
|
/**
|
||||||
|
* 初始化表单,要加上,不然刷新部分组件可能会不加载
|
||||||
|
*/
|
||||||
|
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: '/surface_incline/data/list',
|
||||||
|
toolbar: '#toolbarDemo',//开启头部工具栏
|
||||||
|
defaultToolbar: ['filter'],
|
||||||
|
cols: [
|
||||||
|
cfg_cols
|
||||||
|
],
|
||||||
|
limits: [10, 50, 100, 200],
|
||||||
|
limit: 10,
|
||||||
|
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 = "/surface_incline/data/export?" + result;
|
||||||
|
window.open(u, "_blank");
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -127,6 +127,15 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layui-inline">
|
||||||
|
<label class="layui-form-label">推送至NtripCaster</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<select name="forward_to_ntrip" id="forward_to_ntrip" th:field="*{forward_to_ntrip}" lay-search="">
|
||||||
|
<option value="false">否</option>
|
||||||
|
<option value="true">是</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
@ -193,6 +202,7 @@
|
|||||||
<input type="text" name="fwddeviceid" id="fwddeviceid" th:field="*{fwddeviceid}" class="layui-input">
|
<input type="text" name="fwddeviceid" id="fwddeviceid" th:field="*{fwddeviceid}" class="layui-input">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<div class="layui-inline">
|
<div class="layui-inline">
|
||||||
@ -230,8 +240,9 @@
|
|||||||
<hr th:if="${role=='SUPER_ADMIN'}">
|
<hr th:if="${role=='SUPER_ADMIN'}">
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<div class="layui-input-block" style="float:right" >
|
<div class="layui-input-block" style="float:right" >
|
||||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">确认保存</button>
|
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">保存</button>
|
||||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="initLocBtn">取初值</button>
|
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="initLocBtn">取初值</button>
|
||||||
|
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="contBtn">续数据</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -286,6 +297,47 @@
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
form.on('submit(contBtn)', function (data) {
|
||||||
|
// 弹出输入框
|
||||||
|
layer.prompt({
|
||||||
|
title: '请输入接续的设备编号和日期时间,用逗号隔开', // 弹窗标题
|
||||||
|
formType: 0, // 0-文本输入框
|
||||||
|
maxlength: 50, // 最大输入长度
|
||||||
|
value: '', // 初始值
|
||||||
|
btn: ['确定', '取消'] // 按钮组
|
||||||
|
}, function(value, index) { // 确定按钮回调
|
||||||
|
// 处理输入结果
|
||||||
|
if(value) {
|
||||||
|
$.ajax({
|
||||||
|
type:"POST",
|
||||||
|
url:"/gnss/device/cont_loc",
|
||||||
|
data:{
|
||||||
|
'deviceid':$('#deviceid').val(),
|
||||||
|
'createtime':value
|
||||||
|
},
|
||||||
|
success: function (result) {
|
||||||
|
if(result.code == 0) {
|
||||||
|
$('#ipose').val(result.ipose);
|
||||||
|
$('#iposn').val(result.iposn);
|
||||||
|
$('#iposd').val(result.iposd);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
layer.alert(result.msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
console.log("ajax error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
layer.msg('输入内容不能为空!', {icon: 2});
|
||||||
|
}
|
||||||
|
// 关闭当前弹窗
|
||||||
|
layer.close(index);
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
form.on('select(device_type)', function (data) {
|
form.on('select(device_type)', function (data) {
|
||||||
setEcefEditor();
|
setEcefEditor();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,136 @@
|
|||||||
|
<!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">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="layui-form layuimini-form">
|
||||||
|
<input type="hidden" name="id" id="id">
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">所属部门</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<select name="tenantid" id="tenantid" lay-search="" lay-filter="tenant">
|
||||||
|
<option value="">全部</option>
|
||||||
|
<option th:each="item : ${tenant_list}" th:text="${item.name}" th:value="${item.id}"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">所属项目</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<select name="project_id" id="projectid" lay-search="" lay-filter="project">
|
||||||
|
<option value="">全部</option>
|
||||||
|
<option th:each="item : ${project_list}" th:text="${item.project_id}" th:value="${item.project_id}"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">设备编号</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="deviceid" id="deviceid" class="layui-input">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label required">推送组</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<select name="fwd_group_id" id="fwd_group_id" lay-verify="required" lay-reqtext="不能为空" lay-search="">
|
||||||
|
<option th:each="item : ${gnss_group_fwd_list}" th:text="${item.name}" th:value="${item.name}"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label required">时间段</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="starttime" autocomplete="off" lay-verify="required" lay-reqtext="不能为空" id="ID-laydate-start-date" class="layui-input" placeholder="开始日期">
|
||||||
|
</div>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="endtime" autocomplete="off" lay-verify="required" lay-reqtext="不能为空" id="ID-laydate-end-date" class="layui-input" placeholder="结束日期">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">确认保存</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="../../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
|
||||||
|
<script>
|
||||||
|
layui.use(['form'], function () {
|
||||||
|
var form = layui.form,
|
||||||
|
$ = layui.$,
|
||||||
|
laydate = layui.laydate;
|
||||||
|
var iframeIndex = parent.layer.getFrameIndex(window.name);
|
||||||
|
|
||||||
|
laydate.render({
|
||||||
|
elem: '#ID-laydate-start-date',
|
||||||
|
type: 'datetime'
|
||||||
|
});
|
||||||
|
laydate.render({
|
||||||
|
elem: '#ID-laydate-end-date',
|
||||||
|
type: 'datetime'
|
||||||
|
});
|
||||||
|
// 所属部门下拉框改变,修改项目下拉框
|
||||||
|
form.on('select(tenant)', function (data) {
|
||||||
|
console.log(data.value);
|
||||||
|
$.ajax({
|
||||||
|
type:"GET",
|
||||||
|
url:"/gnss/device/q_project",
|
||||||
|
data:{
|
||||||
|
'tenantid':data.value
|
||||||
|
},
|
||||||
|
success: function(result) {
|
||||||
|
$('#projectid').empty();
|
||||||
|
$('#projectid').append(new Option("全部", ""));
|
||||||
|
$('#deviceid').empty();
|
||||||
|
//console.log(result);
|
||||||
|
$.each(result.data, function (index, item) {
|
||||||
|
$('#projectid')
|
||||||
|
.append(new Option(item.project_id, item.project_id));
|
||||||
|
});
|
||||||
|
layui.form.render("select");
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
console.log("ajax error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//监听提交
|
||||||
|
form.on('submit(saveBtn)', function (data) {
|
||||||
|
$.ajax({
|
||||||
|
type:"POST",
|
||||||
|
url:"/fwd/resend_records/add",
|
||||||
|
contentType: "application/json;charset=UTF-8",
|
||||||
|
data: JSON.stringify(data.field),
|
||||||
|
success: function (result) {
|
||||||
|
parent.onUpdated();
|
||||||
|
parent.layer.close(iframeIndex);
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
console.log("ajax error");
|
||||||
|
parent.layer.close(iframeIndex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -3,7 +3,9 @@ package com.imdroid.ntripproxy.service;
|
|||||||
public class Ntrip2Channels {
|
public class Ntrip2Channels {
|
||||||
final private String localHost="127.0.0.1";
|
final private String localHost="127.0.0.1";
|
||||||
final private int localPort=9903;
|
final private int localPort=9903;
|
||||||
final private String remoteHost="47.107.50.52";
|
final private String remoteHost="8.134.185.53";
|
||||||
|
//final private String remoteHost="100.91.37.6";
|
||||||
|
//final private String remoteHost="47.107.50.52";
|
||||||
final private int remotePort=9903;
|
final private int remotePort=9903;
|
||||||
|
|
||||||
public static final Ntrip2Channels INSTANCE = new Ntrip2Channels();
|
public static final Ntrip2Channels INSTANCE = new Ntrip2Channels();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user