Compare commits

...

7 Commits

Author SHA1 Message Date
d388b848e5 Merge pull request 'feature/ui' (#5) from feature/ui into develop
Reviewed-on: #5
2025-06-10 02:41:12 -07:00
fengyarnom
3a7b33259f fix:调整设备总览的样式 2025-06-10 18:09:07 +08:00
fengyarnom
ba8b2e9512 feat:显示未推送的设备 2025-06-10 16:48:40 +08:00
fengyarnom
8ec6d394b3 feat:命令行新增一些功能 2025-06-10 16:04:42 +08:00
fengyarnom
2b9ba6c1d2 feat:定位设备到地图
- 定位设备到地图
- 定时更新我的位置
2025-06-10 11:50:46 +08:00
fengyarnom
07f1057c2b feat:新增设备在地图查询的功能 2025-06-10 09:20:20 +08:00
fengyarnom
0b777802bf feat:将 OpenLayers 替换百度地图地图,加入高德和天地图 2025-06-09 17:56:25 +08:00
6 changed files with 1373 additions and 358 deletions

View File

@ -26,4 +26,6 @@ public class DeviceCmd {
String name; String name;
Short type; Short type;
String content; String content;
Integer sort;
} }

View File

@ -183,7 +183,7 @@ public class CmdLineController extends BasicController{
public JSONObject listCmd(int page, int limit) { public JSONObject listCmd(int page, int limit) {
Page<DeviceCmd> pageable = new Page<>(page, limit); Page<DeviceCmd> pageable = new Page<>(page, limit);
QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>(); QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("id"); queryWrapper.orderByAsc("sort");
IPage<DeviceCmd> cs = deviceCmdMapper.selectPage(pageable, queryWrapper); IPage<DeviceCmd> cs = deviceCmdMapper.selectPage(pageable, queryWrapper);
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
@ -208,10 +208,19 @@ public class CmdLineController extends BasicController{
return jsonObject; return jsonObject;
} }
private int getMaxSort() {
QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("sort");
queryWrapper.last("limit 1");
DeviceCmd maxSortCmd = deviceCmdMapper.selectOne(queryWrapper);
return maxSortCmd != null ? maxSortCmd.getSort() : 0;
}
@PostMapping("/gnss/cmd/add") @PostMapping("/gnss/cmd/add")
@ResponseBody @ResponseBody
public String addCmd(@RequestBody JSONObject object) throws Exception { public String addCmd(@RequestBody JSONObject object) throws Exception {
DeviceCmd deviceCmd = JSONObject.toJavaObject(object,DeviceCmd.class); DeviceCmd deviceCmd = JSONObject.toJavaObject(object, DeviceCmd.class);
deviceCmd.setSort(getMaxSort() + 1);
int num = deviceCmdMapper.insert(deviceCmd); int num = deviceCmdMapper.insert(deviceCmd);
if (num == 0) { if (num == 0) {
@ -229,6 +238,7 @@ public class CmdLineController extends BasicController{
return HttpResult.failed(); return HttpResult.failed();
} else return HttpResult.ok(); } else return HttpResult.ok();
} }
@PostMapping("/gnss/cmd/go_top") @PostMapping("/gnss/cmd/go_top")
@ResponseBody @ResponseBody
public String topCmd(@RequestParam int id) throws Exception { public String topCmd(@RequestParam int id) throws Exception {
@ -236,14 +246,75 @@ public class CmdLineController extends BasicController{
if(cmd == null) return HttpResult.failed(); if(cmd == null) return HttpResult.failed();
QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>(); QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("id"); queryWrapper.orderByAsc("sort");
queryWrapper.last("limit 1"); queryWrapper.last("limit 1");
DeviceCmd cmdMaxId = deviceCmdMapper.selectOne(queryWrapper); DeviceCmd minSortCmd = deviceCmdMapper.selectOne(queryWrapper);
if(!cmdMaxId.getId().equals(cmd.getId())){
deviceCmdMapper.deleteById(cmd.getId()); if(minSortCmd != null && !minSortCmd.getId().equals(cmd.getId())) {
cmd.setId(cmdMaxId.getId()+1); cmd.setSort(minSortCmd.getSort() - 1);
deviceCmdMapper.insert(cmd); deviceCmdMapper.updateById(cmd);
} }
return HttpResult.ok();
}
@PostMapping("/gnss/cmd/go_bottom")
@ResponseBody
public String bottomCmd(@RequestParam int id) throws Exception {
DeviceCmd cmd = deviceCmdMapper.selectById(id);
if(cmd == null) return HttpResult.failed();
cmd.setSort(getMaxSort() + 1);
deviceCmdMapper.updateById(cmd);
return HttpResult.ok();
}
@PostMapping("/gnss/cmd/move_up")
@ResponseBody
public String moveUpCmd(@RequestParam int id) throws Exception {
DeviceCmd cmd = deviceCmdMapper.selectById(id);
if(cmd == null) return HttpResult.failed();
QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>();
queryWrapper.lt("sort", cmd.getSort());
queryWrapper.orderByDesc("sort");
queryWrapper.last("limit 1");
DeviceCmd prevCmd = deviceCmdMapper.selectOne(queryWrapper);
if(prevCmd != null) {
int tempSort = cmd.getSort();
cmd.setSort(prevCmd.getSort());
prevCmd.setSort(tempSort);
deviceCmdMapper.updateById(cmd);
deviceCmdMapper.updateById(prevCmd);
}
return HttpResult.ok();
}
@PostMapping("/gnss/cmd/move_down")
@ResponseBody
public String moveDownCmd(@RequestParam int id) throws Exception {
DeviceCmd cmd = deviceCmdMapper.selectById(id);
if(cmd == null) return HttpResult.failed();
QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("sort", cmd.getSort());
queryWrapper.orderByAsc("sort");
queryWrapper.last("limit 1");
DeviceCmd nextCmd = deviceCmdMapper.selectOne(queryWrapper);
if(nextCmd != null) {
int tempSort = cmd.getSort();
cmd.setSort(nextCmd.getSort());
nextCmd.setSort(tempSort);
deviceCmdMapper.updateById(cmd);
deviceCmdMapper.updateById(nextCmd);
}
return HttpResult.ok(); return HttpResult.ok();
} }
@ -255,4 +326,17 @@ public class CmdLineController extends BasicController{
return HttpResult.failed(); return HttpResult.failed();
} else return HttpResult.ok(); } else return HttpResult.ok();
} }
@PostMapping("/gnss/cmd/update")
@ResponseBody
public String updateCmd(@RequestBody JSONObject object) throws Exception {
DeviceCmd deviceCmd = JSONObject.toJavaObject(object, DeviceCmd.class);
int num = deviceCmdMapper.updateById(deviceCmd);
if (num == 0) {
return HttpResult.failed();
} else {
return HttpResult.ok();
}
}
} }

View File

@ -1,6 +1,7 @@
package com.imdroid.beidou.controller; package com.imdroid.beidou.controller;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.query.MPJQueryWrapper; import com.github.yulichang.query.MPJQueryWrapper;
@ -45,6 +46,26 @@ public class IndexController extends BasicController{
int noGGA = 0; int noGGA = 0;
int noFix = 0; int noFix = 0;
//未推送设备数同时满足非SAAS服务商使用状态正常fwd_group_id和fwd_group_id2都为"不推送"的设备
Long deviceNoFwdNum;
QueryWrapper<GnssDevice> noFwdQueryWrapper = new QueryWrapper<>();
if (tenantId != Tenant.SAAS_PROVIDER_ID) {
// 非SAAS服务商查询当前租户
noFwdQueryWrapper.eq("tenantid", tenantId);
} else {
// SAAS服务商查询所有非SAAS的租户
noFwdQueryWrapper.ne("tenantid", Tenant.SAAS_PROVIDER_ID);
}
// 使用状态正常
noFwdQueryWrapper.eq("opmode", GnssDevice.OP_MODE_USE);
// 设备类型为测站非基站
noFwdQueryWrapper.eq("devicetype", GnssDevice.TYPE_ROVER);
// fwd_group_id为"不推送"
noFwdQueryWrapper.eq("fwd_group_id", GnssGroupFwd.FWD_TYPE_NONE);
// fwd_group_id2为"不推送"或为null
noFwdQueryWrapper.and(wrapper -> wrapper.eq("fwd_group_id2", GnssGroupFwd.FWD_TYPE_NONE).or().isNull("fwd_group_id2"));
deviceNoFwdNum = gnssDeviceMapper.selectCount(noFwdQueryWrapper);
List<GnssStatusJoin> deviceList; List<GnssStatusJoin> deviceList;
if(tenantId == Tenant.SAAS_PROVIDER_ID){ if(tenantId == Tenant.SAAS_PROVIDER_ID){
deviceList = statusMapper.queryDeployed(); deviceList = statusMapper.queryDeployed();
@ -94,6 +115,7 @@ public class IndexController extends BasicController{
m.addAttribute("warningTotalNum", warning1Num+warning2Num); m.addAttribute("warningTotalNum", warning1Num+warning2Num);
m.addAttribute("noGGA", noGGA); m.addAttribute("noGGA", noGGA);
m.addAttribute("noFix", noFix); m.addAttribute("noFix", noFix);
m.addAttribute("deviceNoFwdNum", deviceNoFwdNum);
m.addAttribute("deviceList", deviceList); m.addAttribute("deviceList", deviceList);
return "/page/device_overview"; return "/page/device_overview";
@ -149,6 +171,13 @@ public class IndexController extends BasicController{
else if(query.equals("nogga")){ else if(query.equals("nogga")){
queryWrapper.isNull("latitude"); queryWrapper.isNull("latitude");
} }
else if(query.equals("no_fwd")){
// 查询同时满足使用状态正常设备类型为测站fwd_group_id和fwd_group_id2都为"不推送"的设备
queryWrapper.eq("d.opmode", GnssDevice.OP_MODE_USE)
.eq("d.devicetype", GnssDevice.TYPE_ROVER)
.eq("d.fwd_group_id", GnssGroupFwd.FWD_TYPE_NONE)
.and(wrapper -> wrapper.eq("d.fwd_group_id2", GnssGroupFwd.FWD_TYPE_NONE).or().isNull("d.fwd_group_id2"));
}
session.setAttribute("query",query); session.setAttribute("query",query);
} }

View File

@ -6,28 +6,64 @@
<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 name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<link rel="stylesheet" href="../lib/layui-v2.6.3/css/layui.css" media="all"> <link rel="stylesheet" href="../lib/layui-v2.6.3/css/layui.css" media="all">
<link rel="stylesheet" href="../lib/font-awesome-4.7.0/css/font-awesome.min.css" media="all"> <link rel="stylesheet" href="../lib/font-awesome-4.7.0/css/font-awesome.min.css" media="all">
<link rel="stylesheet" href="../css/public.css" media="all"> <link rel="stylesheet" href="../css/public.css" media="all">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v10.5.0/ol.css">
<style> <style>
.top-panel { .top-panel {
border: 1px solid #eceff9; border: 1px solid #eceff9;
border-radius: 5px; border-radius: 5px;
text-align: center; text-align: center;
} }
.top-panel > .layui-card-body{
height: 60px; .stats-panel {
height: 100%;
display: flex;
flex-direction: column;
} }
.top-panel-number{
line-height:60px; .stats-panel > .layui-card-body {
height: auto;
min-height: 60px;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.top-panel-number {
/* line-height: 60px; // 删除或注释掉这一行 */
font-size: 30px; font-size: 30px;
border-right:1px solid #eceff9; border-right: 1px solid #eceff9;
height: 100%;
display: flex;
align-items: center;
justify-content: center; /* 可选:让数字水平居中 */
} }
.top-panel-tips{ .top-panel-tips{
line-height:30px; line-height:30px;
font-size: 12px font-size: 12px
} }
.flex-row {
display: flex;
align-items: stretch;
}
.flex-row > .layui-col-xs12,
.flex-row > .layui-col-md6 {
display: flex;
flex-direction: column;
}
.stats-panel .layui-col-xs3 a,
.stats-panel .layui-col-md4 a,
.stats-panel .layui-col-xs3 div a,
.stats-panel .layui-col-md4 div a {
display: block;
margin-bottom: 2px;
}
ul li { ul li {
list-style: none; list-style: none;
} }
@ -54,22 +90,72 @@
text-align: center; text-align: center;
line-height: 30px; line-height: 30px;
} }
.btn:hover { .btn:hover, .btn.active {
background-color: rgba(27, 142, 236, 0.8); background-color: rgba(27, 142, 236, 0.8);
color: #fff; color: #fff;
} }
#map-container {
height: 85vh;
width: 100%;
padding:0px;
position: relative;
}
.map-control-card {
position: absolute;
top: 10px;
right: 10px;
z-index: 1000;
background: white;
padding: 10px;
border-radius: 3px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
min-width: 220px;
}
.map-control-card .title {
font-size: 14px;
font-weight: bold;
margin-bottom: 8px;
color: #1aa094;
}
.search-box {
display: flex;
margin-bottom: 10px;
}
.search-box input {
flex: 1;
border: 1px solid #e6e6e6;
height: 30px;
padding: 0 10px;
}
.search-box button {
width: 50px;
height: 30px;
background-color: #1aa094;
color: white;
border: none;
border-radius: 3px;
margin-left: 5px;
cursor: pointer;
}
.search-box button:hover {
background-color: #148e83;
}
.map-controls select {
width: 100%;
border: 1px solid #e6e6e6;
height: 30px;
}
</style> </style>
<script type="text/javascript" src="//api.map.baidu.com/api?type=webgl&v=1.0&ak=4ef46ba62e8fba67b53a0becca4d05da"> <script src="https://cdn.jsdelivr.net/npm/ol@v10.5.0/dist/ol.js"></script>
</script>
</head> </head>
<body> <body>
<div class="layuimini-main"> <div class="layuimini-main">
<div class="layui-row layui-col-space30"> <div class="layui-row layui-col-space30 flex-row" style="margin-bottom: 2em;">
<div class="layui-col-xs12 layui-col-md6"> <div class="layui-col-xs12 layui-col-md6">
<div class="layui-card top-panel"> <div class="layui-card top-panel stats-panel">
<div class="layui-card-header">设备数量</div> <div class="layui-card-header">设备数量</div>
<div class="layui-card-body"> <div class="layui-card-body">
<div class="layui-row layui-col-space5"> <div class="layui-row layui-col-space5">
@ -77,8 +163,9 @@
<a style="color: #1aa094" th:text="${deviceOnlineNum}">2,020</a><br> <a style="color: #1aa094" th:text="${deviceOnlineNum}">2,020</a><br>
</div> </div>
<div class="layui-col-xs3 layui-col-md4"> <div class="layui-col-xs3 layui-col-md4">
<a href="#" onclick="queryDevices('offline')" style="color: #bd3004" th:text="'掉线数 '+${deviceOfflineNum}">0</a><br> <a href="#" onclick="queryDevices('offline')" style="color: #bd3004" th:text="'掉线数 '+${deviceOfflineNum}">0</a>
<div th:if="${noFix>0}"><a href="#" onclick="queryDevices('nofixed')" style="color: #bd3004" th:text="'长期无效解 '+${noFix}">0</a><br></div> <div th:if="${deviceNoFwdNum>0}"><a href="#" onclick="queryDevices('no_fwd')" style="color: #bd3004" th:text="'未推送数 '+${deviceNoFwdNum}">0</a></div>
<div th:if="${noFix>0}"><a href="#" onclick="queryDevices('nofixed')" style="color: #bd3004" th:text="'长期无效解 '+${noFix}">0</a></div>
<a style="color: #000000" th:text="'装机量 '+${deviceDeployedNum}">2020</a> <a style="color: #000000" th:text="'装机量 '+${deviceDeployedNum}">2020</a>
</div> </div>
</div> </div>
@ -86,7 +173,7 @@
</div> </div>
</div> </div>
<div class="layui-col-xs12 layui-col-md6"> <div class="layui-col-xs12 layui-col-md6">
<div class="layui-card top-panel"> <div class="layui-card top-panel stats-panel">
<div class="layui-card-header">告警统计</div> <div class="layui-card-header">告警统计</div>
<div class="layui-card-body"> <div class="layui-card-body">
<div class="layui-row layui-col-space5"> <div class="layui-row layui-col-space5">
@ -94,9 +181,9 @@
<a style="color: #f6c102" th:text="${warningTotalNum}">20</a><br> <a style="color: #f6c102" th:text="${warningTotalNum}">20</a><br>
</div> </div>
<div class="layui-col-xs3 layui-col-md4"> <div class="layui-col-xs3 layui-col-md4">
<a href="#" onclick="queryDevices('warning2')" style="color: #bd3004" th:text="'严重 '+${warning2Num}">5</a><br> <a href="#" onclick="queryDevices('warning2')" style="color: #bd3004" th:text="'严重 '+${warning2Num}">5</a>
<a href="#" onclick="queryDevices('warning1')" style="color: #f6c102" th:text="'一般 '+${warning1Num}">20</a> <a href="#" onclick="queryDevices('warning1')" style="color: #f6c102" th:text="'一般 '+${warning1Num}">20</a>
<div th:if="${noGGA>0}"><a href="#" onclick="queryDevices('nogga')" style="color: #e7be1d" th:text="'无GGA '+${noGGA}">0</a><br></div> <div th:if="${noGGA>0}"><a href="#" onclick="queryDevices('nogga')" style="color: #e7be1d" th:text="'无GGA '+${noGGA}">0</a></div>
</div> </div>
</div> </div>
</div> </div>
@ -107,242 +194,618 @@
<div class="layui-row layui-col-space15"> <div class="layui-row layui-col-space15">
<div class="layui-card top-panel"> <div class="layui-card top-panel">
<ul class="btn-wrap" style="z-index: 99;"> <ul class="btn-wrap" style="z-index: 99;">
<li class="light btn" onclick="showAll()">全部</li> <li class="light btn" id="btn-all" onclick="showAll()">全部</li>
<li class="night btn" onclick="showWarning1()">一般告警</li> <li class="night btn" id="btn-warning1" onclick="showWarning1()">一般告警</li>
<li class="night btn" onclick="showWarning2()">严重告警</li> <li class="night btn active" id="btn-warning2" onclick="showWarning2()">严重告警</li>
<li class="night btn" id="btn-device-locate" style="display: none; min-width: 120px;"> 设备定位: <span id="current-device-id"></span> </li>
</ul> </ul>
<div id="map-container" class="layui-card-body" style="height: 85vh;weight :100vw"></div> <div id="map-container" class="layui-card-body">
<div class="map-control-card">
<div class="map-controls">
<form class="layui-form">
<div class="layui-form-item">
<select id="mapTypeSelect" lay-filter="mapType">
<option value="tianditu_satellite" selected>天地图-卫星影像</option>
<option value="tianditu_normal">天地图-矢量</option>
<option value="amap_satellite">高德-卫星影像</option>
<option value="amap">高德-矢量</option>
</select>
</div>
</form>
</div>
<div class="search-box">
<input type="text" id="deviceSearch" placeholder="输入设备编号搜索">
<button onclick="searchDevice()">搜索</button>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script th:inline="javascript"> <script th:inline="javascript">
var greenMarkers=[]; var map;
var orangeMarkers=[]; var vectorSource;
var redMarkers=[]; var vectorLayer;
var greenLabels=[]; var currentBaseLayer;
var orangeLabels=[]; var greenFeatures = [];
var redLabels=[]; var orangeFeatures = [];
var batch_id = 0; var redFeatures = [];
var deviceList= var marker_state = 3; // 1:all; 2:orange; 3:red
[ var allFeatures = []; // 存储所有设备标记,用于搜索功能
var currentSearchedDevice = null; // 当前搜索的设备ID
var myLocationFeature = null; // 存储"我的位置"标记
var myLocationInterval; // 存储定时更新位置的interval对象
// 天地图 API 密钥fengyarnom@gmail.com
var TIANDITU_KEY = '0c260b8a094a4e0bc507808812cefdac';
var deviceList = [
[# th:each="device : ${deviceList}"] [# th:each="device : ${deviceList}"]
{deviceid:[[${device.deviceid}]], {
latitude:[[${device.latitude}]], deviceid: [[${device.deviceid}]],
longitude:[[${device.longitude}]], latitude: [[${device.latitude}]],
warning:[[${device.warning}]]}, longitude: [[${device.longitude}]],
warning: [[${device.warning}]]
},
[/] [/]
]; ];
var marker_state = 0;//0: translating; 1:all; 2:orange; 3:red
var map = new BMapGL.Map("map-container"); var pi = 3.14159265358979324;
var convertor = new BMapGL.Convertor(); var a = 6378245.0;
var loc_green = new BMapGL.Icon("../images/loc1_green.png", new BMapGL.Size(18, 24)); var ee = 0.00669342162296594323;
var loc_red = new BMapGL.Icon("../images/loc1_red.png", new BMapGL.Size(18, 24));
var loc_orange = new BMapGL.Icon("../images/loc1_orange.png", new BMapGL.Size(18, 24));
var loc_blue = new BMapGL.Icon("../images/loc_blue.png", new BMapGL.Size(18, 24));
initialize(); /*判断是否在国内,不在国内则不做偏移*/
myLocation(); 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;
}
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}'
})
})
]
}),
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
})
}),
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
})
})
]
}),
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
})
}),
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
})
})
]
})
};
function initialize() { function initialize() {
var point = new BMapGL.Point(116.404, 39.915); vectorSource = new ol.source.Vector();
map.centerAndZoom(point, 7); vectorLayer = new ol.layer.Vector({
map.enableScrollWheelZoom(true); source: vectorSource
//map.setMapType(BMAP_SATELLITE_MAP); });
var initialMapType = document.getElementById('mapTypeSelect').value;
currentBaseLayer = mapLayers[initialMapType];
map = new ol.Map({
target: 'map-container',
layers: [
currentBaseLayer,
vectorLayer
],
view: new ol.View({
center: ol.proj.fromLonLat([116.404, 39.915]),
zoom: 7
})
});
if (deviceList.length > 0) {
var centerLat = 0; var centerLat = 0;
var centerLon = 0; var centerLon = 0;
//console.log(deviceList);
for(var i=0; i<deviceList.length; i++) { for (var i = 0; i < deviceList.length; i++) {
centerLat += deviceList[i].latitude; centerLat += deviceList[i].latitude;
centerLon += deviceList[i].longitude; centerLon += deviceList[i].longitude;
} }
if(deviceList.length>0) {
centerLat = centerLat/deviceList.length; centerLat = centerLat / deviceList.length;
centerLon = centerLon/deviceList.length; centerLon = centerLon / deviceList.length;
map.setCenter(new BMapGL.Point(centerLon,centerLat));
map.getView().setCenter(ol.proj.fromLonLat([centerLon, centerLat]));
} }
marker_state = 0;
translateCallback = function (data){ addDeviceMarkers();
if(data.status === 0) { myLocation();
var i=0; startLocationUpdates(); // 启动位置定时更新
for(; i<data.points.length; i++){ }
var label = new BMapGL.Label(deviceList[batch_id+i].deviceid, function switchMapType(mapType) {
{ console.log('切换地图类型到:', mapType);
position: data.points[i], // 指定文本标注所在的地理位置 map.removeLayer(currentBaseLayer);
offset: new BMapGL.Size(10, 10) // 设置文本偏移量 currentBaseLayer = mapLayers[mapType];
}); // 创建文本标注对象 map.getLayers().insertAt(0, currentBaseLayer);
var marker; // 更新我的位置标记,使用正确的坐标系
if(deviceList[batch_id+i].warning == 2) { updateMyLocationForMapType(mapType);
marker = new BMapGL.Marker(data.points[i], {
icon: loc_red // 更新设备标记
addDeviceMarkers();
}
// 根据地图类型更新我的位置标记
function updateMyLocationForMapType(mapType) {
if (myLocationFeature) {
// 获取原始坐标
var originalCoords = myLocationFeature.get('originalCoords');
if (originalCoords) {
var lat = originalCoords.lat;
var lon = originalCoords.lon;
var coordinates;
// 根据地图类型进行坐标转换
if (mapType === 'amap' || mapType === 'amap_satellite') {
// 高德地图使用GCJ-02坐标系需要转换
var gcjCoord = transform(lat, lon);
coordinates = ol.proj.fromLonLat([gcjCoord.lon, gcjCoord.lat]);
} else {
// 天地图使用CGCS2000/WGS84坐标系直接使用
coordinates = ol.proj.fromLonLat([lon, lat]);
}
// 更新位置标记的几何坐标
myLocationFeature.getGeometry().setCoordinates(coordinates);
}
}
}
function addDeviceMarkers() {
// 保存我的位置标记
var savedMyLocationFeature = myLocationFeature;
// 清除现有标记
vectorSource.clear();
greenFeatures = [];
orangeFeatures = [];
redFeatures = [];
allFeatures = [];
for (var i = 0; i < deviceList.length; i++) {
var device = deviceList[i];
var mapCoordinates;
var currentMapType = document.getElementById('mapTypeSelect').value;
if (currentMapType === 'amap' || currentMapType === 'amap_satellite') {
// 高德地图 WGS84 转换为 GCJ-02
var gcjCoord = transform(device.latitude, device.longitude);
mapCoordinates = ol.proj.fromLonLat([gcjCoord.lon, gcjCoord.lat]);
} else {
// 天地图 CGCS20002000国家大地坐标系与WGS84实质一样
mapCoordinates = ol.proj.fromLonLat([device.longitude, device.latitude]);
}
var feature = new ol.Feature({
geometry: new ol.geom.Point(mapCoordinates),
deviceInfo: device
}); });
redMarkers.push(marker);
redLabels.push(label); var iconSrc;
var color = '#000';
if (device.warning == 2) {
iconSrc = '../images/loc1_red.png';
redFeatures.push(feature);
} else if (device.warning == 1) {
iconSrc = '../images/loc1_orange.png';
orangeFeatures.push(feature);
} else {
iconSrc = '../images/loc1_green.png';
greenFeatures.push(feature);
} }
else if(deviceList[batch_id+i].warning == 1) {
marker = new BMapGL.Marker(data.points[i], { var style = new ol.style.Style({
icon: loc_orange image: new ol.style.Icon({
anchor: [0.5, 1],
src: iconSrc,
scale: 1
}),
text: new ol.style.Text({
text: device.deviceid,
offsetY: -30,
fill: new ol.style.Fill({ color: color }),
stroke: new ol.style.Stroke({ color: '#fff', width: 2 }),
font: '12px Arial'
})
}); });
orangeMarkers.push(marker);
orangeLabels.push(label); feature.setStyle(style);
allFeatures.push(feature);
vectorSource.addFeature(feature);
} }
else {
marker = new BMapGL.Marker(data.points[i], { if (savedMyLocationFeature) {
icon: loc_green vectorSource.addFeature(savedMyLocationFeature);
}
if (currentSearchedDevice) {
filterByDeviceId(currentSearchedDevice);
} else {
if (marker_state === 2) {
hideGreen();
hideRed();
} else if (marker_state === 3) {
hideGreen();
hideOrange();
}
}
}
function myLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var lon = position.coords.longitude;
var lat = position.coords.latitude;
var currentMapType = document.getElementById('mapTypeSelect').value;
var coordinates;
if (currentMapType === 'amap' || currentMapType === 'amap_satellite') {
// 高德地图使用GCJ-02坐标系需要转换
var gcjCoord = transform(lat, lon);
coordinates = ol.proj.fromLonLat([gcjCoord.lon, gcjCoord.lat]);
} else {
// 天地图使用CGCS2000/WGS84坐标系直接使用
coordinates = ol.proj.fromLonLat([lon, lat]);
}
// 如果已经存在位置标记,则先移除
if (myLocationFeature) {
vectorSource.removeFeature(myLocationFeature);
}
myLocationFeature = new ol.Feature({
geometry: new ol.geom.Point(coordinates),
isMyLocation: true,
originalCoords: {lat: lat, lon: lon}
}); });
greenMarkers.push(marker);
greenLabels.push(label);
}
// 点标记添加点击事件 var style = new ol.style.Style({
map.addOverlay(marker); image: new ol.style.Icon({
map.addOverlay(label); anchor: [0.5, 1],
src: '../images/loc_blue.png',
} scale: 1
})
}
batch_id+=10;
// 函数内定时器的回调函数会继续调用 timer()
if(batch_id<deviceList.length) {
setTimeout(() => {
timer();
}, 500);
}
else marker_state = 1;
}
//每秒转换10个坐标否则会受百度并发限制
function timer() {
var pointArr = [];
var count = batch_id+10;
var totalNum = deviceList.length;
if(count>totalNum) count=totalNum;
for (var i = batch_id; i < count; i++) {
point = new BMapGL.Point(deviceList[i].longitude, deviceList[i].latitude);
pointArr.push(point);
}
convertor.translate(pointArr, 1, 5, translateCallback);
}
// 启动函数
timer();
}
function myLocation(){
var geolocation = new BMapGL.Geolocation();
geolocation.getCurrentPosition(function(r){
if(this.getStatus() == BMAP_STATUS_SUCCESS){
var mk = new BMapGL.Marker(r.point, {
icon: loc_blue
}); });
map.addOverlay(mk);
map.panTo(r.point); myLocationFeature.setStyle(style);
} vectorSource.addFeature(myLocationFeature);
map.getView().setCenter(coordinates);
}); });
} }
}
function startLocationUpdates() {
if (myLocationInterval) {
clearInterval(myLocationInterval);
}
myLocationInterval = setInterval(function() {
myLocation();
}, 10 * 60 * 1000); // 10 min = 10 * 60 * 1000ms
}
function showAll() {
document.getElementById('btn-all').classList.add('active');
document.getElementById('btn-warning1').classList.remove('active');
document.getElementById('btn-warning2').classList.remove('active');
document.getElementById('btn-device-locate').classList.remove('active');
document.getElementById('btn-device-locate').style.display = 'none';
currentSearchedDevice = null;
document.getElementById('deviceSearch').value = '';
var savedMyLocationFeature = myLocationFeature;
vectorSource.clear();
if (savedMyLocationFeature) {
vectorSource.addFeature(savedMyLocationFeature);
}
for (var i = 0; i < allFeatures.length; i++) {
vectorSource.addFeature(allFeatures[i]);
}
function showAll(){
if(marker_state == 2){
showGreen();
showRed();
marker_state = 1;
}
else if(marker_state == 3){
showGreen();
showOrange();
marker_state = 1; marker_state = 1;
} }
function showWarning1() {
document.getElementById('btn-all').classList.remove('active');
document.getElementById('btn-warning1').classList.add('active');
document.getElementById('btn-warning2').classList.remove('active');
document.getElementById('btn-device-locate').classList.remove('active');
document.getElementById('btn-device-locate').style.display = 'none';
currentSearchedDevice = null;
document.getElementById('deviceSearch').value = '';
var savedMyLocationFeature = myLocationFeature;
vectorSource.clear();
if (savedMyLocationFeature) {
vectorSource.addFeature(savedMyLocationFeature);
}
for (var i = 0; i < allFeatures.length; i++) {
vectorSource.addFeature(allFeatures[i]);
} }
function showWarning1(){
if(marker_state == 1){
hideGreen(); hideGreen();
hideRed(); hideRed();
marker_state = 2; marker_state = 2;
} }
else if(marker_state == 3){
hideRed(); function showWarning2() {
showOrange(); document.getElementById('btn-all').classList.remove('active');
marker_state = 2; document.getElementById('btn-warning1').classList.remove('active');
} document.getElementById('btn-warning2').classList.add('active');
document.getElementById('btn-device-locate').classList.remove('active');
document.getElementById('btn-device-locate').style.display = 'none';
currentSearchedDevice = null;
document.getElementById('deviceSearch').value = '';
var savedMyLocationFeature = myLocationFeature;
vectorSource.clear();
if (savedMyLocationFeature) {
vectorSource.addFeature(savedMyLocationFeature);
}
for (var i = 0; i < allFeatures.length; i++) {
vectorSource.addFeature(allFeatures[i]);
} }
function showWarning2(){
if(marker_state == 1){
hideGreen(); hideGreen();
hideOrange(); hideOrange();
marker_state = 3; marker_state = 3;
} }
else if(marker_state == 2){
function showGreen() {
for (var i = 0; i < greenFeatures.length; i++) {
if (!vectorSource.hasFeature(greenFeatures[i])) {
vectorSource.addFeature(greenFeatures[i]);
}
}
}
function showOrange() {
for (var i = 0; i < orangeFeatures.length; i++) {
if (!vectorSource.hasFeature(orangeFeatures[i])) {
vectorSource.addFeature(orangeFeatures[i]);
}
}
}
function showRed() {
for (var i = 0; i < redFeatures.length; i++) {
if (!vectorSource.hasFeature(redFeatures[i])) {
vectorSource.addFeature(redFeatures[i]);
}
}
}
function hideGreen() {
for (var i = 0; i < greenFeatures.length; i++) {
vectorSource.removeFeature(greenFeatures[i]);
}
}
function hideOrange() {
for (var i = 0; i < orangeFeatures.length; i++) {
vectorSource.removeFeature(orangeFeatures[i]);
}
}
function hideRed() {
for (var i = 0; i < redFeatures.length; i++) {
vectorSource.removeFeature(redFeatures[i]);
}
}
function searchDevice() {
var deviceId = document.getElementById('deviceSearch').value.trim();
if (!deviceId) {
currentSearchedDevice = null;
vectorSource.clear();
for (var i = 0; i < allFeatures.length; i++) {
vectorSource.addFeature(allFeatures[i]);
}
if (marker_state === 2) {
hideGreen();
hideRed();
} else if (marker_state === 3) {
hideGreen();
hideOrange(); hideOrange();
showRed(); }
marker_state = 3;
document.getElementById('btn-device-locate').style.display = 'none';
updateFilterButtonsState(marker_state);
return;
}
currentSearchedDevice = deviceId;
filterByDeviceId(deviceId);
}
function locateDeviceOnMap(deviceId, latitude, longitude) {
currentSearchedDevice = deviceId;
filterByDeviceId(deviceId);
var layerIndex = layer.index;
layer.close(layerIndex);
layer.msg('已定位到设备: ' + deviceId);
}
function updateFilterButtonsState(state) {
document.getElementById('btn-all').classList.remove('active');
document.getElementById('btn-warning1').classList.remove('active');
document.getElementById('btn-warning2').classList.remove('active');
if (state === 1) {
document.getElementById('btn-all').classList.add('active');
} else if (state === 2) {
document.getElementById('btn-warning1').classList.add('active');
} else if (state === 3) {
document.getElementById('btn-warning2').classList.add('active');
} }
} }
function showGreen(){ function filterByDeviceId(deviceId) {
for(var i=0; i<greenMarkers.length; i++){ var savedMyLocationFeature = myLocationFeature;
map.addOverlay(greenMarkers[i]);
map.addOverlay(greenLabels[i]); vectorSource.clear();
if (savedMyLocationFeature) {
vectorSource.addFeature(savedMyLocationFeature);
}
var found = false;
for (var i = 0; i < allFeatures.length; i++) {
var feature = allFeatures[i];
var deviceInfo = feature.get('deviceInfo');
if (deviceInfo && deviceInfo.deviceid.includes(deviceId)) {
vectorSource.addFeature(feature);
found = true;
// 将地图中心移动到该设备位置
var geometry = feature.getGeometry();
var deviceCoord = geometry.getCoordinates();
map.getView().setCenter(deviceCoord);
map.getView().setZoom(15);
} }
} }
function showOrange(){ if (!found) {
for(var i=0; i<orangeMarkers.length; i++){ layer.msg('未找到设备: ' + deviceId);
map.addOverlay(orangeMarkers[i]);
map.addOverlay(orangeLabels[i]); if (marker_state === 1) {
showAll();
} else if (marker_state === 2) {
showWarning1();
} else if (marker_state === 3) {
showWarning2();
} }
} }
function showRed(){ document.getElementById('current-device-id').textContent = deviceId;
for(var i=0; i<redMarkers.length; i++){ document.getElementById('btn-device-locate').style.display = 'block';
map.addOverlay(redMarkers[i]); document.getElementById('btn-device-locate').classList.add('active');
map.addOverlay(redLabels[i]); document.getElementById('btn-all').classList.remove('active');
} document.getElementById('btn-warning1').classList.remove('active');
document.getElementById('btn-warning2').classList.remove('active');
} }
layui.use(['form'], function(){
var form = layui.form;
form.on('select(mapType)', function(data){
switchMapType(data.value);
});
function hideGreen(){ initialize();
for(var i=0; i<greenMarkers.length; i++){
map.removeOverlay(greenMarkers[i]);
map.removeOverlay(greenLabels[i]);
}
}
function hideOrange(){ showWarning2();
for(var i=0; i<orangeMarkers.length; i++){ });
map.removeOverlay(orangeMarkers[i]);
map.removeOverlay(orangeLabels[i]);
}
}
function hideRed(){ function queryDevices(status_type) {
for(var i=0; i<redMarkers.length; i++){
map.removeOverlay(redMarkers[i]);
map.removeOverlay(redLabels[i]);
}
}
</script>
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script>
function queryDevices(status_type){
var index = layer.open({ var index = layer.open({
title: '', title: '',
type: 2, type: 2,
shade: 0.2, shade: 0.2,
maxmin:true, maxmin: true,
shadeClose: true, shadeClose: true,
anim: 2, anim: 2,
offset: 'rb', offset: 'rb',
area: ['100%', '50%'], area: ['100%', '50%'],
content: '../page/gnss_q_status?query='+status_type, content: '../page/gnss_q_status?query=' + status_type,
}); });
} }
</script> </script>

View File

@ -12,17 +12,45 @@
body { body {
background-color: #ffffff; background-color: #ffffff;
} }
.ctx-menu-container {
position: absolute;
background: #fff;
border: 1px solid #d2d2d2;
border-radius: 2px;
box-shadow: 0 2px 4px rgba(0,0,0,.12);
z-index: 999;
display: none;
}
.ctx-menu-container li {
padding: 7px 15px;
cursor: pointer;
}
.ctx-menu-container li:hover {
background-color: #f2f2f2;
}
.ctx-submenu {
padding-left: 20px;
display: none;
}
.active-row {
background-color: #f2f2f2 !important;
}
.highlight-row {
background-color: #fffdd1 !important;
transition: background-color 0.5s;
}
</style> </style>
</head> </head>
<body> <body>
<div class="layui-form layuimini-form"> <div class="layui-form layuimini-form">
<table class="layui-hide" id="currentTableId" lay-filter="currentTableFilter"></table> <table class="layui-hide" id="currentTableId" lay-filter="currentTableFilter"></table>
<input type="hidden" name="device_id" id="device_id"> <input type="hidden" name="device_id" id="device_id" th:value="${device_id}">
<input type="hidden" name="send_channel" id="send_channel"> <input type="hidden" name="send_channel" id="send_channel" th:value="${send_channel}">
</div>
<div class="layui-card top-panel"> <div id="cmdFormDialog" style="display: none; padding: 20px;">
<div class="layui-card-body"> <form class="layui-form" lay-filter="cmdForm">
<input type="hidden" name="id" id="id"> <input type="hidden" name="id" id="id">
<div class="layui-form-item"> <div class="layui-form-item">
@ -35,7 +63,7 @@
<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">
<select name="type" lay-filter="type"> <select name="type" id="type" lay-filter="type">
<option value="0">GNSS</option> <option value="0">GNSS</option>
<option value="10">DTU</option> <option value="10">DTU</option>
<option value="2">MPU</option> <option value="2">MPU</option>
@ -52,64 +80,192 @@
<textarea name="content" id="content" class="layui-textarea"></textarea> <textarea name="content" id="content" class="layui-textarea"></textarea>
</div> </div>
</div> </div>
</form>
</div>
<div class="layui-form-item"> <div class="ctx-menu-container" id="rightMenu">
<div class="layui-input-block"> <ul>
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">保存</button> <li id="ctx-menu-edit">编辑</li>
</div> <li id="ctx-menu-send">发送</li>
</div> <li id="ctx-menu-top">置顶</li>
</div> <li id="ctx-menu-up">上移</li>
</div> <li id="ctx-menu-down">下移</li>
<li id="ctx-menu-bottom">置底</li>
<li id="ctx-menu-delete">删除</li>
</ul>
</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 type="text/html" id="toolbarDemo">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm" lay-event="add">添加指令</button>
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="edit" id="btnEdit" disabled>编辑</button>
<button class="layui-btn layui-btn-sm" lay-event="go_top" id="btnTop" disabled>置顶</button>
<button class="layui-btn layui-btn-sm" lay-event="move_up" id="btnUp" disabled>上移</button>
<button class="layui-btn layui-btn-sm" lay-event="move_down" id="btnDown" disabled>下移</button>
<button class="layui-btn layui-btn-sm" lay-event="go_bottom" id="btnBottom" disabled>置底</button>
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="delete" id="btnDelete" disabled>删除</button>
</div>
</script>
<script type="text/html" id="currentTableBar"> <script type="text/html" id="currentTableBar">
<a class="layui-btn layui-btn-normal layui-btn-xs " lay-event="use">发送</a> <a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="use">发送</a>
<a class="layui-btn layui-btn-normal layui-btn-xs " lay-event="go_top">置顶</a>
<a class="layui-btn layui-btn-xs layui-btn-danger data-count-delete" lay-event="delete">删除</a>
</script> </script>
<script th:inline="javascript"> <script th:inline="javascript">
layui.use(['form', 'table'], function () { layui.use(['form', 'table', 'layer'], function () {
var $ = layui.$, var $ = layui.$,
form = layui.form, form = layui.form,
table = layui.table; table = layui.table,
layer = layui.layer;
var iframeIndex = parent.layer.getFrameIndex(window.name); var iframeIndex = parent.layer.getFrameIndex(window.name);
var isMoving = false;
var lastMovedId = null;
var isManualOperation = false;
/** /**
* 初始化表单,要加上,不然刷新部分组件可能会不加载 * 初始化表单,要加上,不然刷新部分组件可能会不加载
*/ */
form.render(); form.render();
table.render({ var selectedRow = null;
var tableIns = table.render({
elem: '#currentTableId', elem: '#currentTableId',
url: '/gnss/cmd/list', url: '/gnss/cmd/list',
cols: [ toolbar: '#toolbarDemo', // 指定工具栏
[ defaultToolbar: ['filter', 'exports', 'print'], // 默认工具栏
{field: 'name', title: '指令名称',width:'20%'}, cols: [[
{field: 'type', title: '类型',templet: '#typeTrans'}, {type: 'checkbox', fixed: 'left'}, // 添加复选框
{field: 'content', title: '指令',width:'40%'}, {field: 'name', title: '指令名称', width: '20%'},
{title: '操作', toolbar: '#currentTableBar', align: "center", minWidth: 180} {field: 'type', title: '类型', templet: '#typeTrans'},
] {field: 'content', title: '指令', width: '40%'},
], {title: '操作', toolbar: '#currentTableBar', width: 100} // 只保留发送按钮
]],
limits: [10, 15, 20, 25, 50, 100], limits: [10, 15, 20, 25, 50, 100],
limit: 10, limit: 10,
page: true, page: true,
skin: 'line' skin: 'line',
done: function(res, curr, count) {
// 表格加载完成后,检查是否有需要选中的行
// 这个部分是需要连续上移或者下移
//
if (lastMovedId && !isManualOperation) {
var data = res.data;
for (var i = 0; i < data.length; i++) {
if (data[i].id == lastMovedId) {
var index = i;
var tr = $('.layui-table-body').find('tr[data-index="' + index + '"]');
tr.find('.layui-form-checkbox').click();
tr.addClass('highlight-row');
setTimeout(function() {
tr.removeClass('highlight-row');
}, 1000);
break;
}
}
}
selectedRow = null;
updateToolbarStatus();
isMoving = false;
isManualOperation = false;
}
});
function updateToolbarStatus() {
var checkStatus = table.checkStatus('currentTableId');
var hasSelection = checkStatus.data.length > 0;
var isSingleSelection = checkStatus.data.length === 1;
// 只能删除,其他的不给点
$('#btnEdit').prop('disabled', !isSingleSelection);
$('#btnTop').prop('disabled', !isSingleSelection);
$('#btnUp').prop('disabled', !isSingleSelection);
$('#btnDown').prop('disabled', !isSingleSelection);
$('#btnBottom').prop('disabled', !isSingleSelection);
$('#btnDelete').prop('disabled', !hasSelection);
if (isSingleSelection) {
$('#btnEdit,#btnTop,#btnUp,#btnDown,#btnBottom').removeClass('layui-btn-disabled');
} else {
$('#btnEdit,#btnTop,#btnUp,#btnDown,#btnBottom').addClass('layui-btn-disabled');
}
if (hasSelection) {
$('#btnDelete').removeClass('layui-btn-disabled');
} else {
$('#btnDelete').addClass('layui-btn-disabled');
}
}
table.on('checkbox(currentTableFilter)', function(obj) {
updateToolbarStatus();
if (obj.type === 'one' && !obj.checked) {
isManualOperation = true;
lastMovedId = null;
}
});
// table.on('rowDouble(currentTableFilter)', function(obj) {
// var data = obj.data;
// editCmd(data);
// });
table.on('sort(currentTableFilter)', function(obj){
isManualOperation = true;
lastMovedId = null;
}); });
table.on('tool(currentTableFilter)', function (obj) { table.on('tool(currentTableFilter)', function (obj) {
isManualOperation = true;
lastMovedId = null;
var data = obj.data; var data = obj.data;
if (obj.event === 'use') { if (obj.event === 'use') {
sendCmd(data);
}
});
function editCmd(data) {
form.val("cmdForm", {
"id": data.id,
"name": data.name,
"type": data.type,
"content": data.content
});
layer.open({
type: 1,
title: '编辑指令',
area: ['500px', '400px'],
content: $('#cmdFormDialog'),
btn: ['保存', '取消'],
yes: function(index, layero) {
saveCmd(index);
},
btn2: function(index, layero) {
layer.close(index);
return false;
}
});
}
function sendCmd(data) {
parent.setCmd(data.type, data.content); parent.setCmd(data.type, data.content);
var deviceId = $('#device_id').val();
var sendChannel = $('#send_channel').val();
$.ajax({ $.ajax({
type:"POST", type:"POST",
url:"/gnss/config_cmd", url:"/gnss/config_cmd",
data: { data: {
'device_id':[[${device_id}]], 'device_id': deviceId,
'send_channel':[[${send_channel}]], 'send_channel': sendChannel,
'cmd_type':data.type, 'cmd_type': data.type,
'tx_win':data.content 'tx_win': data.content
}, },
success: function (result) { success: function (result) {
if(result.code == 0) parent.setResult(result); if(result.code == 0) parent.setResult(result);
@ -120,57 +276,258 @@
} }
}); });
} }
else if (obj.event === 'delete') {
layer.confirm('确定删除'+data.name+"?", function(index){ function deleteCmd(id) {
layer.confirm('确定删除此指令?', function(index) {
$.ajax({ $.ajax({
type:"POST", type:"POST",
url:"/gnss/cmd/delete", url:"/gnss/cmd/delete",
data:{ data:{
'del_id':data.id 'del_id':id
}, },
success: function (data) { success: function (data) {
//data是cotroller相应处理函数的返回值 tableIns.reload();
table.reload('currentTableId'); layer.close(index);
}, },
error: function () { error: function () {
console.log("ajax error"); console.log("ajax error");
} }
}); });
layer.close(index);
}); });
} }
else if (obj.event === 'go_top') {
// 监听头工具栏事件
table.on('toolbar(currentTableFilter)', function(obj){
var checkStatus = table.checkStatus(obj.config.id);
var data = checkStatus.data; // 获取选中的数据
// 如果不是移动操作重置lastMovedId
if (obj.event !== 'move_up' && obj.event !== 'move_down' &&
obj.event !== 'go_top' && obj.event !== 'go_bottom') {
lastMovedId = null;
isManualOperation = true;
}
switch(obj.event){
case 'add':
// 清空表单
form.val("cmdForm", {
"id": "",
"name": "",
"type": 0,
"content": ""
});
layer.open({
type: 1,
title: '添加指令',
area: ['500px', '400px'],
content: $('#cmdFormDialog'),
btn: ['保存', '取消'],
yes: function(index, layero) {
saveCmd(index);
},
btn2: function(index, layero) {
layer.close(index);
return false;
}
});
break;
case 'edit':
if(data.length === 1) {
editCmd(data[0]);
}
break;
case 'delete':
if(data.length === 0) {
layer.msg('请选择要删除的数据');
return;
}
layer.confirm('确定删除选中的 ' + data.length + ' 条数据?', function(index) {
var deleteCount = 0;
var totalCount = data.length;
for(var i = 0; i < data.length; i++) {
$.ajax({ $.ajax({
type:"POST", type:"POST",
url:"/gnss/cmd/go_top", url:"/gnss/cmd/delete",
data:{ data:{
'id':data.id 'del_id': data[i].id
}, },
success: function (data) { success: function() {
table.reload('currentTableId'); deleteCount++;
}, if(deleteCount === totalCount) {
error: function () { tableIns.reload();
console.log("ajax error"); layer.close(index);
}
} }
}); });
} }
}); });
break;
case 'go_top':
if(data.length === 1) {
moveCmd(data[0].id, 'go_top');
}
break;
case 'move_up':
if(data.length === 1) {
moveCmd(data[0].id, 'move_up');
}
break;
case 'move_down':
if(data.length === 1) {
moveCmd(data[0].id, 'move_down');
}
break;
case 'go_bottom':
if(data.length === 1) {
moveCmd(data[0].id, 'go_bottom');
}
break;
}
});
function saveCmd(index) {
var formData = form.val("cmdForm");
if(!formData.name) {
layer.msg('指令名称不能为空');
return;
}
var url = formData.id ? "/gnss/cmd/update" : "/gnss/cmd/add";
form.on('submit(saveBtn)', function (data) {
$.ajax({ $.ajax({
type:"POST", type: "POST",
url:"/gnss/cmd/add", url: url,
contentType: "application/json;charset=UTF-8", contentType: "application/json;charset=UTF-8",
data: JSON.stringify(data.field), data: JSON.stringify(formData),
success: function (result) { success: function(result) {
table.reload('currentTableId'); // 关闭弹窗
layer.close(index);
// 刷新表格
tableIns.reload();
layer.msg('保存成功');
}, },
error: function () { error: function() {
console.log("ajax error"); console.log("ajax error");
layer.msg('保存失败');
} }
}); });
}
// 移动指令(包括置顶、上移、下移、置底)
function moveCmd(id, moveType) {
// 如果当前正在进行移动操作,则忽略本次请求
if (isMoving) {
return;
}
// 设置锁定状态
isMoving = true;
// 记录移动的行ID
lastMovedId = id;
$.ajax({
type:"POST",
url:"/gnss/cmd/" + moveType,
data:{
'id': id
},
success: function() {
tableIns.reload();
},
error: function() {
console.log("ajax error");
isMoving = false;
lastMovedId = null;
}
});
}
var rightMenu = $('#rightMenu');
$(document).on('contextmenu', '.layui-table-view .layui-table-body table tr', function(e) {
var index = $(this).attr('data-index');
var tableData = table.cache['currentTableId'];
selectedRow = tableData[index];
$('.layui-table-body tr').removeClass('active-row');
$(this).addClass('active-row');
var mouseX = e.pageX;
var mouseY = e.pageY;
rightMenu.css({
left: mouseX,
top: mouseY
}).show();
return false; return false;
}); });
$(document).click(function() {
rightMenu.hide();
});
$('#ctx-menu-edit').click(function() {
if(selectedRow) {
editCmd(selectedRow);
rightMenu.hide();
}
});
$('#ctx-menu-send').click(function() {
if(selectedRow) {
sendCmd(selectedRow);
rightMenu.hide();
}
});
$('#ctx-menu-top').click(function() {
if(selectedRow) {
moveCmd(selectedRow.id, 'go_top');
rightMenu.hide();
}
});
$('#ctx-menu-up').click(function() {
if(selectedRow) {
moveCmd(selectedRow.id, 'move_up');
rightMenu.hide();
}
});
$('#ctx-menu-down').click(function() {
if(selectedRow) {
moveCmd(selectedRow.id, 'move_down');
rightMenu.hide();
}
});
$('#ctx-menu-bottom').click(function() {
if(selectedRow) {
moveCmd(selectedRow.id, 'go_bottom');
rightMenu.hide();
}
});
$('#ctx-menu-delete').click(function() {
if(selectedRow) {
deleteCmd(selectedRow.id);
rightMenu.hide();
}
});
$(document).on('click', '.layui-table-page a', function() {
lastMovedId = null;
isManualOperation = true;
});
$(document).on('click', '.layui-table-tool-panel li', function() {
lastMovedId = null;
isManualOperation = true;
});
}); });
</script> </script>

View File

@ -12,6 +12,65 @@
body { body {
background-color: #ffffff; background-color: #ffffff;
} }
.layui-btn-normal {
background-color: #1aa094;
}
.icon-btn {
/* width: 30px; */
height: 26px;
padding: 0;
}
.layui-table-fixed-l .layui-table-body {
box-shadow: none !important;
}
.layui-btn-normal:hover {
background-color: #148e83;
}
.layui-table-fixed-l .layui-table-body {
box-shadow: none !important;
}
.layui-table-cell {
height: auto;
line-height: 28px;
padding: 6px 15px;
position: relative;
box-sizing: border-box;
}
.layui-btn-xs {
padding: 0 8px;
font-size: 12px;
height: 26px;
line-height: 24px;
}
.device-id-btn {
display: flex;
align-items: center;
justify-content: center;
background-color: #4b97d5f5;
color: white;
border-radius: 5px;
padding: 3px 10px;
cursor: pointer;
transition: background-color 0.3s;
width: 100%;
}
.device-id-btn:hover {
background-color: #339af0;
}
.device-id-btn i {
margin-right: 5px;
}
.icon-only-btn {
background: none;
border: none;
padding: 0;
cursor: pointer;
font-size: 16px;
color: #1aa094;
}
.icon-only-btn:hover {
color: #148e83;
}
</style> </style>
</head> </head>
<body> <body>
@ -28,34 +87,49 @@
form = layui.form, form = layui.form,
table = layui.table; table = layui.table;
var iframeIndex = parent.layer.getFrameIndex(window.name); var iframeIndex = parent.layer.getFrameIndex(window.name);
/**
* 初始化表单,要加上,不然刷新部分组件可能会不加载
*/
form.render(); form.render();
table.render({ table.render({
elem: '#currentTableId', elem: '#currentTableId',
url: '/gnss/q_status/list', url: '/gnss/q_status/list',
cols: [[ cols: [[
{field: 'deviceid', title: '设备号', sort: true}, {field: 'deviceid', title: '设备号', width: 120, templet: '#deviceIdTpl', align: 'center',sort: true},
{field: 'devicetype', title: '设备类型',templet: '#typeTrans'}, {field: 'devicetype', title: '设备类型', templet: '#typeTrans', width: 100},
{field: 'project_id', title: '项目号'}, {field: 'project_id', title: '项目号', width: 100},
{field: 'name', title: '工点'}, {field: 'name', title: '工点', width: 150},
{field: 'updatetime', title: '更新时间', templet: "<div>{{layui.util.toDateString(d.updatetime, 'yyyy-MM-dd HH:mm:ss')}}</div>"}, {field: 'updatetime', title: '更新时间', templet: "<div>{{layui.util.toDateString(d.updatetime, 'yyyy-MM-dd HH:mm:ss')}}</div>", width: 170},
{field: 'state', title: '状态',templet: '#stateTrans'}, {field: 'state', title: '状态', templet: '#stateTrans', width: 80, align: 'center'},
{field: 'warning', title: '告警',templet: '#warningTrans'}, {field: 'warning', title: '告警', templet: '#warningTrans', width: 80, align: 'center'},
{field: 'voltage', title: '电压'}, {field: 'voltage', title: '电压', width: 80},
{field: 'temperature', title: '温度'}, {field: 'temperature', title: '温度', width: 80},
{field: 'humidity', title: '湿度'}, {field: 'humidity', title: '湿度', width: 80},
{field: 'rssi', title: '信号'}, {field: 'rssi', title: '信号', width: 80},
{field: 'pitch', title: 'x倾角'}, {field: 'pitch', title: 'x倾角', width: 80},
{field: 'roll', title: 'y倾角'}, {field: 'roll', title: 'y倾角', width: 80},
{field: 'satelliteinuse', title: '使用卫星数'} {field: 'satelliteinuse', title: '使用卫星数', width: 110},
{field: 'latitude', title: '纬度', hide: true},
{field: 'longitude', title: '经度', hide: true}
]], ]],
limits: [10, 15, 20, 25, 50, 100], limits: [10, 15, 20, 25, 50, 100],
limit: 15, limit: 15,
page: true, page: true,
skin: 'line' skin: 'line',
even: true,
loading: true,
text: {
none: '暂无符合条件的设备'
}
});
table.on('tool(currentTableFilter)', function(obj) {
var data = obj.data;
if (obj.event === 'locate') {
if (data.latitude && data.longitude) {
parent.locateDeviceOnMap(data.deviceid, data.latitude, data.longitude);
} else {
layer.msg('设备无经纬度信息,无法定位');
}
}
}); });
}); });
@ -92,5 +166,11 @@
{{# } }} {{# } }}
</script> </script>
<script type="text/html" id="deviceIdTpl">
<div class="device-id-btn" lay-event="locate">
<i class="layui-icon layui-icon-location"></i>{{d.deviceid}}
</div>
</script>
</body> </body>
</html> </html>