652 lines
34 KiB
HTML
652 lines
34 KiB
HTML
<!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>
|
||
.layui-tab-content{padding: 1.2em;}
|
||
.transfer-wrap{display:flex;justify-content:center;align-items:flex-start;padding:1em 0}
|
||
.transfer-inner{min-width:720px}
|
||
#rtk-transfer .layui-transfer{display:flex;justify-content:center}
|
||
#rtk-transfer .layui-transfer .layui-transfer-box{width:50% !important;height:360px !important}
|
||
/* RTK panel ~80vh */
|
||
#rtk-panel{height:80vh;}
|
||
#rtk-info{max-height:calc(80vh - 120px);} /* leave room for header/badges */
|
||
#table-ntrip + .layui-table-view{ width:100% !important; }
|
||
#table-device + .layui-table-view{ width:100% !important; }
|
||
#table-group + .layui-table-view{ width:100% !important; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="layuimini-container">
|
||
<div class="layuimini-main">
|
||
<div class="layui-tab layui-tab-card" lay-filter="rtk-tab">
|
||
<ul class="layui-tab-title">
|
||
<li class="layui-this">Ntrip 推送管理</li>
|
||
<li>分组管理</li>
|
||
<li>设备管理</li>
|
||
<li>单设备定位</li>
|
||
<li style="display:none;">组设备定位</li>
|
||
</ul>
|
||
<div class="layui-tab-content">
|
||
<div class="layui-tab-item layui-show">
|
||
<div class="layui-row" style="margin:10px 0;">
|
||
<div class="layui-col-md12">
|
||
<div class="layui-form layui-form-pane">
|
||
<div class="layui-form-item">
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">设备号</label>
|
||
<div class="layui-input-inline">
|
||
<input type="text" id="ntrip-deviceid" placeholder="设备号" autocomplete="off" class="layui-input" />
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<button class="layui-btn" id="btn-ntrip-search">搜索</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style="margin-top:10px;">
|
||
<table class="layui-hide" id="table-ntrip" lay-filter="table-ntrip-filter"></table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="layui-tab-item">
|
||
<div class="layui-row">
|
||
<div class="layui-col-md12">
|
||
<div class="btn-bar">
|
||
<button class="layui-btn" id="btn-group-add">新增分组</button>
|
||
<button class="layui-btn layui-btn-normal" id="btn-group-edit">编辑分组</button>
|
||
<button class="layui-btn layui-btn-danger" id="btn-group-del">删除分组</button>
|
||
<button class="layui-btn layui-btn-warm" id="btn-transfer-save">保存设备分配</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style="margin-top:10px;">
|
||
<table class="layui-hide" id="table-group" lay-filter="table-group-filter"></table>
|
||
</div>
|
||
<div class="transfer-wrap">
|
||
<div class="transfer-inner">
|
||
<div id="rtk-transfer"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="layui-tab-item">
|
||
<div class="layui-row" style="margin:10px 0;">
|
||
<div class="layui-col-md12">
|
||
<div class="layui-form layui-form-pane">
|
||
<div class="layui-form-item">
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">分组</label>
|
||
<div class="layui-input-inline">
|
||
<select id="sel-group" lay-search=""><option value="">全部</option></select>
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">设备号</label>
|
||
<div class="layui-input-inline">
|
||
<input type="text" id="q-deviceid" placeholder="设备号" autocomplete="off" class="layui-input" />
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<button class="layui-btn" id="btn-device-search">搜索</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style="margin-top:10px;">
|
||
<table class="layui-hide" id="table-device" lay-filter="table-device-filter"></table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="layui-tab-item">
|
||
<div class="layui-row">
|
||
<div class="layui-col-md12">
|
||
<form class="layui-form layui-form-pane" action="" id="rtk-form">
|
||
<div class="layui-form-item">
|
||
<label class="layui-form-label">分组</label>
|
||
<div class="layui-input-block">
|
||
<select id="rtk-group" lay-search="" lay-filter="rtk-group"></select>
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item">
|
||
<label class="layui-form-label">设备</label>
|
||
<div class="layui-input-block">
|
||
<select id="rtk-device" lay-search="" lay-filter="rtk-device"></select>
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item">
|
||
<button class="layui-btn" id="btn-rtk-start" type="button">开始定位</button>
|
||
<button class="layui-btn layui-btn-warm" id="btn-connect-cmd" type="button">连接设备通讯通道</button>
|
||
</div>
|
||
<div class="layui-form-item">
|
||
<div class="layui-btn-container">
|
||
<button class="layui-btn layui-btn-primary" type="button" id="btn-cmd-open-rtcm">博通开所有RTCM</button>
|
||
<button class="layui-btn layui-btn-primary" type="button" id="btn-cmd-close-4065">博通关4065</button>
|
||
<button class="layui-btn layui-btn-primary" type="button" id="btn-cmd-msm4">RTCM MSM4</button>
|
||
<button class="layui-btn layui-btn-primary" type="button" id="btn-cmd-save">博通save</button>
|
||
<button class="layui-btn layui-btn-normal" type="button" id="btn-cmd-0102">0102</button>
|
||
<button class="layui-btn layui-btn-normal" type="button" id="btn-cmd-0100">0100</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<div class="layui-row" style="margin-top: 1em;">
|
||
<div class="layui-col-md12">
|
||
<div id="rtk-panel" style="border: 1px solid #e6e6e6;border-radius: 2px;padding: 1em;">
|
||
<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;">
|
||
<div class="layui-text">RTK定位信息</div>
|
||
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
|
||
<span id="rtk-sol-badge" class="layui-badge layui-bg-gray">--</span>
|
||
<span id="rtk-sat-badge" class="layui-badge layui-bg-gray">--</span>
|
||
<span id="rtk-llh" class="layui-badge-rim">LLH: --</span>
|
||
<span id="rtk-gngga" class="layui-badge-rim">GNGGA: --</span>
|
||
</div>
|
||
</div>
|
||
<hr>
|
||
<pre id="rtk-info" style="white-space: pre-wrap;word-break: break-all;overflow-y:auto;"></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="layui-row" style="margin-top: 1em;">
|
||
<div class="layui-col-md12">
|
||
<div id="cmd-panel" style="border: 1px solid #e6e6e6;border-radius: 2px;padding: 1em;">
|
||
<div class="layui-text">命令行消息</div>
|
||
<hr>
|
||
<pre id="cmd-info" style="white-space: pre-wrap;word-break: break-all;max-height:30vh;overflow-y:auto;"></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="layui-tab-item" style="display:none;">
|
||
<div class="layui-row">
|
||
<div class="layui-col-md12">
|
||
<form class="layui-form layui-form-pane" action="" id="rtk-group-form">
|
||
<div class="layui-form-item">
|
||
<label class="layui-form-label">分组</label>
|
||
<div class="layui-input-block">
|
||
<select id="gr-group" lay-search="" lay-filter="gr-group"></select>
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item">
|
||
<button class="layui-btn" id="btn-gr-start" type="button">开始组定位</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<div class="layui-row" style="margin-top: 1em;">
|
||
<div class="layui-col-md12">
|
||
<table class="layui-hide" id="group-table" lay-filter="group-table-filter"></table>
|
||
</div>
|
||
</div>
|
||
<div class="layui-row" style="margin-top: 1em;">
|
||
<div class="layui-col-md12">
|
||
<div id="group-panel" style="border:1px solid #e6e6e6;border-radius:2px;padding:1em;height:60vh;">
|
||
<div class="layui-text">组定位消息</div>
|
||
<hr>
|
||
<pre id="group-info" style="white-space: pre-wrap;word-break: break-all;overflow-y:auto;height:calc(60vh - 80px);"></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
|
||
<script>
|
||
layui.use(['form','table','element','layer','transfer'], function(){
|
||
var $ = layui.$,
|
||
form = layui.form,
|
||
table = layui.table,
|
||
element = layui.element,
|
||
layer = layui.layer,
|
||
transfer = layui.transfer;
|
||
|
||
form.render();
|
||
|
||
// Ntrip 推送管理
|
||
var ntripTableIns = table.render({
|
||
elem: '#table-ntrip',
|
||
url: '/gnss/ntrip/list',
|
||
id: 'ntrip-table-id',
|
||
cols: [ [
|
||
{field:'deviceid', title:'设备号', sort:true},
|
||
{field:'tenantname', title:'所属组织', sort:true},
|
||
{field:'devicetype', title:'设备类型', templet: '#ntripDevTypeTrans'},
|
||
{field:'model', title:'型号', templet: '#ntripModelTrans'},
|
||
{field:'project_id', title:'项目号'},
|
||
{field:'updatetime', title:'更新时间', templet: "<div>{{layui.util.toDateString(d.updatetime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
||
{field:'forward_to_ntrip', title:'推送Ntrip', width:120, fixed:'right', align:'center', templet: function(d){
|
||
var checked = d.forward_to_ntrip? 'checked' : '';
|
||
return '<input type="checkbox" lay-filter="ntrip-fwd-switch" data-device="'+ (d.deviceid||'') +'" '+checked+' lay-skin="switch" lay-text="开|关">';
|
||
}}
|
||
] ],
|
||
limits:[10,20,50,100],
|
||
limit:10,
|
||
page:true,
|
||
skin:'line'
|
||
});
|
||
|
||
$('#btn-ntrip-search').on('click', function(){
|
||
var did = $('#ntrip-deviceid').val();
|
||
ntripTableIns.reload({ where:{ device_id: did }, page:{ curr:1 } });
|
||
});
|
||
|
||
form.on('switch(ntrip-fwd-switch)', function(obj){
|
||
var el = $(obj.elem);
|
||
var device = el.attr('data-device');
|
||
var val = obj.elem.checked;
|
||
$.post('/gnss/ntrip/update_forward', { device_id: device, forward: val }, function(res){
|
||
if(res === 'ok' || (res && res.code === 0)){
|
||
layer.msg('已更新');
|
||
} else {
|
||
layer.alert((res && res.msg) || '更新失败');
|
||
obj.elem.checked = !val; form.render('checkbox');
|
||
}
|
||
}).fail(function(){
|
||
layer.alert('请求失败');
|
||
obj.elem.checked = !val; form.render('checkbox');
|
||
});
|
||
});
|
||
|
||
var selectedGroup = null;
|
||
var transferIns = null;
|
||
var groupTableIns = table.render({
|
||
elem: '#table-group',
|
||
url: '/rtk/group/list',
|
||
cols: [ [
|
||
{type:'radio', width:50},
|
||
{field:'id', title:'ID', width:90},
|
||
{field:'name', title:'分组名称', width:180},
|
||
{field:'inpstr2_path', title:'inpstr2-path'},
|
||
{field:'inpstr3_path', title:'inpstr3-path'}
|
||
] ],
|
||
limits: [10,20,50,100],
|
||
limit: 10,
|
||
page: true,
|
||
skin: 'line'
|
||
});
|
||
|
||
table.on('radio(table-group-filter)', function(obj){
|
||
selectedGroup = obj.data;
|
||
loadTransfer();
|
||
});
|
||
|
||
$('#btn-group-add').on('click', function(){
|
||
var index = layer.open({
|
||
title: '新增分组',
|
||
type: 2,
|
||
shade: 0.2,
|
||
maxmin:true,
|
||
shadeClose: true,
|
||
area: ['600px', '420px'],
|
||
content: '../page/table/rtk_group_edit'
|
||
});
|
||
});
|
||
|
||
$('#btn-group-edit').on('click', function(){
|
||
if(!selectedGroup){ layer.msg('请先选择一行'); return; }
|
||
var index = layer.open({
|
||
title: '编辑分组',
|
||
type: 2,
|
||
shade: 0.2,
|
||
maxmin:true,
|
||
shadeClose: true,
|
||
area: ['600px', '420px'],
|
||
content: '../page/table/rtk_group_edit',
|
||
success: function(layero, idx){
|
||
var iframeWin = window[layero.find('iframe')[0]['name']];
|
||
if(iframeWin && iframeWin.setParams){
|
||
iframeWin.setParams(selectedGroup);
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
$('#btn-group-del').on('click', function(){
|
||
if(!selectedGroup){ layer.msg('请先选择一行'); return; }
|
||
layer.confirm('确认删除该分组?', function(i){
|
||
$.post('/rtk/group/delete', {del_id: selectedGroup.id}, function(res){
|
||
if(res === 'ok' || res.code === 0){
|
||
onRtkGroupUpdated();
|
||
layer.close(i);
|
||
} else {
|
||
layer.alert(res.msg || '删除失败');
|
||
}
|
||
}).fail(function(){ layer.alert('请求失败'); });
|
||
});
|
||
});
|
||
|
||
window.onRtkGroupUpdated = function(){
|
||
selectedGroup = null;
|
||
groupTableIns.reload({page:{curr:1}});
|
||
}
|
||
|
||
function loadTransfer(){
|
||
if(!selectedGroup) return;
|
||
$.get('/rtk/transfer/options', {group_id: selectedGroup.id}, function(res){
|
||
if(res.code !== 0){ layer.alert(res.msg || '加载失败'); return; }
|
||
var opt = res.data;
|
||
if(transferIns){ $("#rtk-transfer").html(''); }
|
||
transferIns = transfer.render({
|
||
elem: '#rtk-transfer',
|
||
title: ['待加入设备','组内设备'],
|
||
data: opt.data,
|
||
value: opt.value,
|
||
id: 'rtk-transfer-id',
|
||
showSearch: true,
|
||
parseData: function(item){ return {value: item.value, title: item.title}; }
|
||
});
|
||
// 覆盖渲染后的内联尺寸
|
||
var boxes = $('#rtk-transfer .layui-transfer .layui-transfer-box');
|
||
if(boxes && boxes.length){ boxes.css({width:'50%', height:'360px'}); }
|
||
}).fail(function(){ layer.alert('请求失败'); });
|
||
}
|
||
|
||
$('#btn-transfer-save').on('click', function(){
|
||
if(!selectedGroup){ layer.msg('请先选择分组'); return; }
|
||
var vals = transfer.getData('rtk-transfer-id').map(function(it){ return it.value; });
|
||
$.ajax({
|
||
type: 'POST',
|
||
url: '/rtk/profile/save_group_devices',
|
||
contentType: 'application/json;charset=UTF-8',
|
||
data: JSON.stringify({group_id: selectedGroup.id, device_ids: vals}),
|
||
success: function(result){
|
||
if(result.code === 0){ layer.msg('已保存'); }
|
||
else { layer.alert(result.msg || '保存失败'); }
|
||
},
|
||
error: function(){ layer.alert('请求失败'); }
|
||
});
|
||
});
|
||
|
||
function loadGroupSelect(){
|
||
$.get('/rtk/group/list', {page:1, limit:1000}, function(res){
|
||
if(res.code===0){
|
||
var sel = $('#sel-group');
|
||
sel.empty(); sel.append('<option value="">全部</option>');
|
||
res.data.forEach(function(g){ sel.append('<option value="'+g.id+'">'+g.name+'</option>'); });
|
||
form.render('select');
|
||
var gr = $('#gr-group');
|
||
gr.empty(); gr.append('<option value="">请选择</option>');
|
||
res.data.forEach(function(g){ gr.append('<option value="'+g.id+'">'+g.name+'</option>'); });
|
||
form.render('select');
|
||
}
|
||
});
|
||
}
|
||
loadGroupSelect();
|
||
|
||
var deviceTableIns = table.render({
|
||
elem: '#table-device',
|
||
url: '/rtk/profile/list',
|
||
id: 'rtk-profile-table',
|
||
cols: [ [
|
||
{type:'numbers', title:'序号', width:70},
|
||
{field:'id', title:'ID', width:80},
|
||
{field:'device_id', title:'设备号', width:140},
|
||
{field:'rtkgroup_id', title:'分组ID', width:100},
|
||
{field:'pos1_posmode', title:'pos1-posmode', width:130},
|
||
{field:'inpstr1_type', title:'inpstr1-type', width:120},
|
||
{field:'inpstr1_path', title:'inpstr1-path'},
|
||
{field:'outstr2_path', title:'outstr2-path'},
|
||
{field:'out_height', title:'out-height', width:120},
|
||
{title: '操作', toolbar: '#rtkProfileBar', fixed: 'right', width: 100}
|
||
] ],
|
||
limits: [10,20,50,100],
|
||
limit: 10,
|
||
page: true,
|
||
skin: 'line'
|
||
});
|
||
|
||
$('#btn-device-search').on('click', function(){
|
||
var gid = $('#sel-group').val();
|
||
var did = $('#q-deviceid').val();
|
||
deviceTableIns.reload({where:{group_id: gid, device_id: did}, page:{curr:1}});
|
||
});
|
||
|
||
table.on('tool(table-device-filter)', function(obj){
|
||
var data = obj.data;
|
||
if(obj.event === 'edit'){
|
||
var index = layer.open({
|
||
title: '编辑设备配置',
|
||
type: 2,
|
||
shade: 0.2,
|
||
maxmin:true,
|
||
shadeClose: true,
|
||
area: ['700px', '520px'],
|
||
content: '../page/table/rtk_profile_edit',
|
||
success: function(layero){
|
||
var iframeWin = window[layero.find('iframe')[0]['name']];
|
||
if(iframeWin && iframeWin.setParams){ iframeWin.setParams(data); }
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
// toolbar template for device table
|
||
|
||
|
||
var rtkWs = null;
|
||
var rtkSelectedDevice = '';
|
||
var rtkRunning = false;
|
||
var rtkGnggaTimer = null;
|
||
var cmdWs = null;
|
||
var cmdConnected = false;
|
||
function connectRtkWs(){
|
||
if(rtkWs && rtkWs.readyState === WebSocket.OPEN) return;
|
||
var curPath = window.document.location.href;
|
||
var pathName = window.document.location.pathname;
|
||
var pos = curPath.indexOf(pathName);
|
||
var basePath = curPath.substring(0, pos);
|
||
var wsUrl = (basePath+"/websocket/rtkrcv").replace("http","ws");
|
||
rtkWs = new WebSocket(wsUrl);
|
||
rtkWs.onopen = function(){ };
|
||
rtkWs.onerror = function(){ layer.msg('RTK WebSocket 连接失败'); };
|
||
rtkWs.onclose = function(){ };
|
||
rtkWs.onmessage = function (event) {
|
||
var msg = event.data || '';
|
||
var info = $('#rtk-info');
|
||
try {
|
||
var obj = JSON.parse(msg);
|
||
if(obj && obj.type==='rtk'){
|
||
if(rtkSelectedDevice && obj.deviceId !== rtkSelectedDevice) return;
|
||
var sol = (obj.q===1)?'固定解':((obj.q===2)?'浮点解':'--');
|
||
var solCls = (obj.q===1)?'layui-bg-green':((obj.q===2)?'layui-bg-orange':'layui-bg-gray');
|
||
$('#rtk-sol-badge').attr('class','layui-badge ' + solCls).text(sol);
|
||
var ns = (obj.ns!=null? obj.ns : '--');
|
||
$('#rtk-sat-badge').attr('class','layui-badge layui-bg-blue').text('卫星数: '+ns);
|
||
var llh = (obj.lat && obj.lon && obj.h!=null)? (obj.lat.toFixed(9)+' '+obj.lon.toFixed(9)+' '+obj.h) : '--';
|
||
$('#rtk-llh').text('LLH: ' + llh);
|
||
info.text(info.text() + (obj.raw || msg) + "\n");
|
||
} else if(obj && obj.type==='rtk_gngga'){
|
||
if(rtkSelectedDevice && obj.deviceId !== rtkSelectedDevice) return;
|
||
var gtxt = 'lat='+ (obj.lat!=null?obj.lat:0) + ', lon='+(obj.lon!=null?obj.lon:0)+', alt='+(obj.alt!=null?obj.alt:0)+', geo='+(obj.geo!=null?obj.geo:0);
|
||
$('#rtk-gngga').text('GNGGA: ' + gtxt);
|
||
} else if(obj && obj.type==='rtk_ctrl'){
|
||
if(obj.action==='auto_stop' && (!rtkSelectedDevice || obj.deviceId === rtkSelectedDevice)){
|
||
rtkRunning = false; updateToggleBtn();
|
||
layer.msg('已自动停止: 连续固定解达阈值');
|
||
}
|
||
if(groupSelectedId){
|
||
if(obj.deviceId){ groupStatus[obj.deviceId]='DONE'; renderGroupTable(); }
|
||
}
|
||
} else if(obj && obj.type==='rtk_group'){
|
||
if(groupSelectedId && obj.groupId==groupSelectedId){
|
||
groupStatus[obj.deviceId]=obj.status; renderGroupTable();
|
||
}
|
||
} else {
|
||
info.text(info.text() + msg + "\n");
|
||
}
|
||
} catch(e){
|
||
var parts = msg.trim().split(/\s+/);
|
||
var ok = parts.length >= 3 && parts[0] === 'RTK';
|
||
if(ok){
|
||
var did = parts[1];
|
||
if(rtkSelectedDevice && did !== rtkSelectedDevice) return;
|
||
}
|
||
info.text(info.text() + msg + "\n");
|
||
}
|
||
var el = document.getElementById('rtk-info');
|
||
el.scrollTop = el.scrollHeight;
|
||
if(groupSelectedId){
|
||
try{ var o=JSON.parse(msg); if(o && o.type==='rtk' && groupDevices.has(o.deviceId)){ appendGroupLog(o.raw || msg); } }catch(ex){ var pp=msg.trim().split(/\s+/); if(pp[0]==='RTK' && groupDevices.has(pp[1])) appendGroupLog(msg); }
|
||
}
|
||
};
|
||
}
|
||
function closeRtkWs(){ if(rtkWs){ try{ rtkWs.close(); }catch(e){} rtkWs=null; } }
|
||
function updateCmdBtn(){ var b=$('#btn-connect-cmd'); if(cmdConnected){ b.text('关闭设备通讯通道'); b.addClass('layui-btn-danger'); } else { b.text('连接设备通讯通道'); b.removeClass('layui-btn-danger'); } }
|
||
function connectCmdWs(){ if(cmdWs && cmdWs.readyState===WebSocket.OPEN) return; var cur=window.location.href; var pn=window.location.pathname; var pos=cur.indexOf(pn); var base=cur.substring(0,pos); var url=(base+"/websocket/cmdline").replace("http","ws"); cmdWs=new WebSocket(url); cmdWs.onopen=function(){ cmdConnected=true; updateCmdBtn(); }; cmdWs.onmessage=function(e){ var msg=e.data||''; var did=$('#rtk-device').val(); var parts=msg.trim().split(/\s+/); if(parts[0]==='RX' && parts.length>3){ if(did && parts[3]!==did) return; } var ci=$('#cmd-info'); ci.text(ci.text()+msg+'\n'); var el=document.getElementById('cmd-info'); el.scrollTop=el.scrollHeight; }; cmdWs.onclose=function(){ cmdConnected=false; updateCmdBtn(); }; cmdWs.onerror=function(){ layer.msg('通讯通道连接失败'); } }
|
||
function closeCmdWs(){ if(cmdWs){ try{ cmdWs.close(); }catch(e){} cmdWs=null; } }
|
||
function startGnggaTimer(){ if(rtkGnggaTimer) clearInterval(rtkGnggaTimer); rtkGnggaTimer = setInterval(function(){ if(!rtkSelectedDevice) return; $.get('/rtk/gngga',{device_id: rtkSelectedDevice}, function(res){ if(res){ var gtxt = 'lat='+(res.lat!=null?res.lat:0)+', lon='+(res.lon!=null?res.lon:0)+', alt='+(res.alt!=null?res.alt:0)+', geo='+(res.geo!=null?res.geo:0); $('#rtk-gngga').text('GNGGA: '+gtxt); } }); }, 5000); }
|
||
function stopGnggaTimer(){ if(rtkGnggaTimer){ clearInterval(rtkGnggaTimer); rtkGnggaTimer=null; } }
|
||
|
||
function loadRtkGroups(){
|
||
$.get('/rtk/group/list', {page:1,limit:1000}, function(res){
|
||
if(res.code===0){
|
||
var sel = $('#rtk-group'); sel.empty();
|
||
sel.append('<option value="">请选择</option>');
|
||
(res.data||[]).forEach(function(g){ sel.append('<option value="'+g.id+'">'+g.name+'</option>'); });
|
||
form.render('select');
|
||
}
|
||
});
|
||
}
|
||
function loadRtkDevices(gid){
|
||
var devSel = $('#rtk-device'); devSel.empty();
|
||
devSel.append('<option value="">请选择</option>');
|
||
if(!gid){ form.render('select'); return; }
|
||
$.get('/rtk/profile/list', {page:1,limit:1000, group_id: gid}, function(res){
|
||
if(res.code===0){
|
||
(res.data||[]).forEach(function(p){ devSel.append('<option value="'+p.device_id+'">'+p.device_id+'</option>'); });
|
||
form.render('select');
|
||
}
|
||
});
|
||
}
|
||
loadRtkGroups();
|
||
|
||
form.on('select(rtk-group)', function(data){
|
||
loadRtkDevices(data.value);
|
||
});
|
||
form.on('select(rtk-device)', function(data){ rtkSelectedDevice = data.value; });
|
||
|
||
function updateToggleBtn(){
|
||
var btn = $('#btn-rtk-start');
|
||
if(rtkRunning){
|
||
btn.text('停止定位');
|
||
btn.addClass('layui-btn-danger');
|
||
} else {
|
||
btn.text('开始定位');
|
||
btn.removeClass('layui-btn-danger');
|
||
}
|
||
}
|
||
updateToggleBtn();
|
||
|
||
$('#btn-rtk-start').on('click', function(){
|
||
rtkSelectedDevice = $('#rtk-device').val();
|
||
if(!rtkSelectedDevice){ layer.msg('请选择设备'); return; }
|
||
if(!rtkRunning){
|
||
$.get('/rtk/log_exists', {device_id: rtkSelectedDevice}, function(exists){
|
||
function doStart(clear){
|
||
$.post('/rtk/start', {device_id: rtkSelectedDevice, clear_log: clear}, function(res){
|
||
if(res && res.code === 0){
|
||
if(res.data === 'ok' || res.data === 'all_zero'){
|
||
connectRtkWs(); startGnggaTimer(); rtkRunning = true; updateToggleBtn();
|
||
if(res.data === 'all_zero'){ layer.msg('GNGGA全零,使用默认配置启动'); }
|
||
} else {
|
||
layer.msg(res.data||'已处理');
|
||
}
|
||
} else { layer.alert((res&&res.msg)||'启动失败'); }
|
||
}).fail(function(){ layer.alert('启动请求失败'); });
|
||
}
|
||
if(exists){
|
||
layer.confirm('检测到已有日志,是否清空后再开始?', {btn:['清空','追加','取消']}, function(idx){
|
||
layer.close(idx); doStart(true);
|
||
}, function(idx){
|
||
layer.close(idx); doStart(false);
|
||
});
|
||
} else {
|
||
doStart(false);
|
||
}
|
||
}).fail(function(){ layer.alert('检查日志失败'); });
|
||
} else {
|
||
$.post('/rtk/stop', {device_id: rtkSelectedDevice}, function(){
|
||
rtkRunning = false; updateToggleBtn();
|
||
closeRtkWs(); stopGnggaTimer();
|
||
});
|
||
}
|
||
});
|
||
$('#btn-connect-cmd').on('click', function(){ if(!cmdConnected){ connectCmdWs(); layer.msg('已连接设备通讯通道'); } else { closeCmdWs(); layer.msg('已关闭设备通讯通道'); } });
|
||
|
||
function sendHexCmd(hex){ var dev=$('#rtk-device').val(); if(!dev){ layer.msg('请选择设备'); return; } $.ajax({ type:'POST', url:'/gnss/config_cmd', data:{ tx_win: hex, device_id: dev, cmd_type: 0, send_channel: 0 }, success:function(res){ if(res && res.code===0){ var ci=$('#cmd-info'); ci.text(ci.text()+(res.data||'')+'\n'); var el=document.getElementById('cmd-info'); el.scrollTop=el.scrollHeight; } else { layer.alert((res&&res.msg)||'发送失败'); } }, error:function(){ layer.alert('请求失败'); } }); }
|
||
function sendDebugCmd(content){ var dev=$('#rtk-device').val(); if(!dev){ layer.msg('请选择设备'); return; } $.ajax({ type:'POST', url:'/gnss/config_cmd', data:{ tx_win: content, device_id: dev, cmd_type: 3, send_channel: 0 }, success:function(res){ if(res && res.code===0){ var ci=$('#cmd-info'); ci.text(ci.text()+(res.data||'')+'\n'); var el=document.getElementById('cmd-info'); el.scrollTop=el.scrollHeight; } else { layer.alert((res&&res.msg)||'发送失败'); } }, error:function(){ layer.alert('请求失败'); } }); }
|
||
$('#btn-cmd-open-rtcm').on('click', function(){ sendHexCmd('42 4b 51 45 26 02 00 0c 55 00 23 71 00 00 00 31 00 00 00 ff'); });
|
||
$('#btn-cmd-close-4065').on('click', function(){ sendHexCmd('42 4b e4 6b 26 02 00 0c 55 55 00 01 00 00 00 31 00 00 00 01'); });
|
||
$('#btn-cmd-msm4').on('click', function(){ sendHexCmd('42 4b 46 8e 26 02 00 0c 55 55 00 01 00 00 00 10 00 00 00 01'); });
|
||
$('#btn-cmd-save').on('click', function(){ sendHexCmd('42 4b cc 17 26 04 00 00'); });
|
||
$('#btn-cmd-0102').on('click', function(){ sendDebugCmd('0102'); });
|
||
$('#btn-cmd-0100').on('click', function(){ sendDebugCmd('0100'); });
|
||
|
||
var grRunning = false; function updateGrBtn(){ var b=$('#btn-gr-start'); if(grRunning){b.text('停止组定位').addClass('layui-btn-danger');} else {b.text('开始组定位').removeClass('layui-btn-danger');} }
|
||
updateGrBtn();
|
||
var groupSelectedId = null; var groupDevices = new Set(); var groupStatus = {};
|
||
form.on('select(gr-group)', function(data){ groupSelectedId = data.value; reloadGroupStatus(); loadGroupDevices(); });
|
||
function loadGroupDevices(){ groupDevices.clear(); if(!groupSelectedId)return; $.get('/rtk/profile/list',{page:1,limit:1000, group_id: groupSelectedId}, function(res){ if(res.code===0){ (res.data||[]).forEach(function(p){ groupDevices.add(p.device_id);}); renderGroupTable(); } }); }
|
||
function renderGroupTable(){
|
||
table.render({
|
||
elem: '#group-table',
|
||
data: Array.from(groupDevices).map(function(d){ return {device_id:d, status: (groupStatus[d]||'--')}; }),
|
||
cols: [ [
|
||
{field:'device_id', title:'设备号'},
|
||
{field:'status', title:'状态', templet: function(d){
|
||
var s=d.status;
|
||
var m={'RUNNING':'layui-bg-green','QUEUED':'','DONE':'layui-bg-blue','FAILED':'layui-bg-red'};
|
||
var cls=m[s]||'';
|
||
return '<span class="layui-badge '+cls+'">'+(s||'--')+'</span>';
|
||
}}
|
||
] ],
|
||
page: true,
|
||
limit: 10,
|
||
limits: [10,20,50,100]
|
||
});
|
||
}
|
||
function reloadGroupStatus(){ if(!groupSelectedId) return; $.get('/rtk/group/status',{group_id: groupSelectedId}, function(res){ if(res.code===0){ (res.data||[]).forEach(function(r){ groupStatus[r.device_id]=r.status; }); renderGroupTable(); } }); }
|
||
$('#btn-gr-start').on('click', function(){ if(!groupSelectedId){ layer.msg('请选择分组'); return; } if(!grRunning){ layer.confirm('是否清空日志后开始?',{btn:['清空','追加','取消']}, function(idx){ layer.close(idx); $.post('/rtk/group/start',{group_id: groupSelectedId, clear_log:true}, function(){ grRunning=true; updateGrBtn(); connectRtkWs(); }); }, function(idx){ layer.close(idx); $.post('/rtk/group/start',{group_id: groupSelectedId, clear_log:false}, function(){ grRunning=true; updateGrBtn(); connectRtkWs(); }); }); } else { $.post('/rtk/group/stop',{group_id: groupSelectedId}, function(){ grRunning=false; updateGrBtn(); }); } });
|
||
|
||
function appendGroupLog(msg){ var gi=$('#group-info'); gi.text(gi.text()+msg+'\n'); var el=document.getElementById('group-info'); el.scrollTop=el.scrollHeight; }
|
||
});
|
||
</script>
|
||
|
||
<script type="text/html" id="rtkProfileBar">
|
||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit">编辑</a>
|
||
|
||
</script>
|
||
|
||
<script type="text/html" id="ntripDevTypeTrans">
|
||
{{# if(d.devicetype == 1){ }}
|
||
<span>基准站</span>
|
||
{{# } else { }}
|
||
<span>监测站</span>
|
||
{{# } }}
|
||
</script>
|
||
|
||
<script type="text/html" id="ntripModelTrans">
|
||
{{# if(d.model == 1){ }}
|
||
<span>G510</span>
|
||
{{# } else { }}
|
||
<span>G505</span>
|
||
{{# } }}
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|