|
|
|
|
@ -0,0 +1,504 @@
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="en">
|
|
|
|
|
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
<title>费县林业防灭火无人机平台</title>
|
|
|
|
|
<style>
|
|
|
|
|
body {
|
|
|
|
|
margin: 0;
|
|
|
|
|
padding: 0;
|
|
|
|
|
font-family: Arial, sans-serif;
|
|
|
|
|
background-color: #050D12;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
* {
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ul,
|
|
|
|
|
li {
|
|
|
|
|
list-style: none;
|
|
|
|
|
margin: 0;
|
|
|
|
|
padding: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.header {
|
|
|
|
|
background-color: #333;
|
|
|
|
|
color: #fff;
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100px;
|
|
|
|
|
background-image: url('./img/img1.png');
|
|
|
|
|
background-size: 100% 100px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.header-left {
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.header-left img {
|
|
|
|
|
width: 58px;
|
|
|
|
|
height: 55px;
|
|
|
|
|
position: absolute;
|
|
|
|
|
left: 18px;
|
|
|
|
|
top: 15px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.header-left h1 {
|
|
|
|
|
position: absolute;
|
|
|
|
|
left: 101px;
|
|
|
|
|
top: -10px;
|
|
|
|
|
width: 468px;
|
|
|
|
|
font-family: PingFangSC, PingFang SC;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
font-size: 38px;
|
|
|
|
|
text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5);
|
|
|
|
|
text-align: right;
|
|
|
|
|
font-style: normal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.header-right {
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.header-right .time {
|
|
|
|
|
position: absolute;
|
|
|
|
|
right: 240px;
|
|
|
|
|
top: 11px;
|
|
|
|
|
width: 91px;
|
|
|
|
|
width: 91px;
|
|
|
|
|
height: 24px;
|
|
|
|
|
font-family: D-DIN, D-DIN;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
line-height: 26px;
|
|
|
|
|
letter-spacing: 1px;
|
|
|
|
|
text-align: left;
|
|
|
|
|
font-style: normal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.header-right .day {
|
|
|
|
|
position: absolute;
|
|
|
|
|
right: 163px;
|
|
|
|
|
top: 17px;
|
|
|
|
|
width: 40px;
|
|
|
|
|
height: 16px;
|
|
|
|
|
font-family: D, D;
|
|
|
|
|
font-weight: normal;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
line-height: 17px;
|
|
|
|
|
letter-spacing: 1px;
|
|
|
|
|
text-align: left;
|
|
|
|
|
font-style: normal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.week {
|
|
|
|
|
position: absolute;
|
|
|
|
|
right: 50px;
|
|
|
|
|
top: 16px;
|
|
|
|
|
width: 45px;
|
|
|
|
|
height: 20px;
|
|
|
|
|
font-family: PingFangSC, PingFang SC;
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
line-height: 20px;
|
|
|
|
|
text-align: left;
|
|
|
|
|
font-style: normal;
|
|
|
|
|
}
|
|
|
|
|
.container{
|
|
|
|
|
display: flex;
|
|
|
|
|
}
|
|
|
|
|
.menu {
|
|
|
|
|
background-color: rgb(36, 33, 36);
|
|
|
|
|
border: 1px solid #616466;
|
|
|
|
|
height: calc( 100vh - 115px);
|
|
|
|
|
width: 473px;
|
|
|
|
|
padding: 20px 0;
|
|
|
|
|
position:relative;
|
|
|
|
|
}
|
|
|
|
|
.no-data{
|
|
|
|
|
width:100%;
|
|
|
|
|
position:absolute;
|
|
|
|
|
top:0px;
|
|
|
|
|
padding-top:200px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
color:#999;
|
|
|
|
|
}
|
|
|
|
|
.menu ul {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
overflow-y: scroll;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::-webkit-scrollbar {
|
|
|
|
|
width: 0;
|
|
|
|
|
height: 0;
|
|
|
|
|
background-color: transparent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.menu .menu-li {
|
|
|
|
|
width: 472px;
|
|
|
|
|
height: 82px;
|
|
|
|
|
border-top: 1px solid rgba(255, 255, 255, .3);
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
padding-left: 26px;
|
|
|
|
|
cursor:pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.menu .menu-li:nth-last-of-type(1) {
|
|
|
|
|
border-bottom: 1px solid rgba(255, 255, 255, .3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.menu .menu-li span {
|
|
|
|
|
font-family: PingFangSC, PingFang SC;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
line-height: 28px;
|
|
|
|
|
text-align: right;
|
|
|
|
|
font-style: normal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.menu .menu-li img {
|
|
|
|
|
margin-right: 46px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.menu .menu-li-select {
|
|
|
|
|
width: 472px;
|
|
|
|
|
height: 82px;
|
|
|
|
|
background-image: url('./img/img4.png');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.content {
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
padding: 20px;
|
|
|
|
|
width: calc(100% - 500px);
|
|
|
|
|
height: calc(100vh 200px);
|
|
|
|
|
border: 1px solid #616466;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.video-contain {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media only screen and (max-width: 600px) {
|
|
|
|
|
.menu {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: auto;
|
|
|
|
|
position: static;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.content {
|
|
|
|
|
margin-left: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.vjs-errors-content-container{
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
<script src="https://cdn.bootcdn.net/ajax/libs/flv.js/1.6.2/flv.js"></script>
|
|
|
|
|
<!-- jQuery -->
|
|
|
|
|
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
|
|
|
|
|
|
|
|
|
|
<!-- 腾讯云视频直播 -->
|
|
|
|
|
<link href="https://web.sdk.qcloud.com/player/tcplayer/release/v4.6.0/tcplayer.min.css" rel="stylesheet" />
|
|
|
|
|
<script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.6.0/libs/TXLivePlayer-1.2.3.min.js"></script>
|
|
|
|
|
<script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.6.0/libs/hls.min.1.1.5.js"></script>
|
|
|
|
|
<script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.6.0/libs/flv.min.1.6.3.js"></script>
|
|
|
|
|
<script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.6.0/libs/dash.all.min.4.4.1.js"></script>
|
|
|
|
|
<script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.6.0/tcplayer.v4.6.0.min.js"></script>
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
|
|
<body>
|
|
|
|
|
|
|
|
|
|
<div class="header">
|
|
|
|
|
<div class="header-left">
|
|
|
|
|
<img src="./img/img2.png" alt="">
|
|
|
|
|
<h1>费县林业防灭火无人机平台</h1>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="header-right">
|
|
|
|
|
<span class="time" id="time">17:00:55</span>
|
|
|
|
|
<span class="day" id="day">2024.00.00</span>
|
|
|
|
|
<span class="week" id="week">星期一</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="container">
|
|
|
|
|
<div class="menu">
|
|
|
|
|
<div class="no-data">
|
|
|
|
|
<p>
|
|
|
|
|
<img src="./img/empty.png" alt="">
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
暂无无人机巡航信息
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
<ul id="uav-list-container">
|
|
|
|
|
|
|
|
|
|
<!-- <li class="menu-li menu-li-select">
|
|
|
|
|
<span class="menu-title">大疆无人机1111</span>
|
|
|
|
|
<img class="meun-button" src="./img/img3.png" />
|
|
|
|
|
</li> -->
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="content">
|
|
|
|
|
<video class="video-contain" id="video"></video>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
<script>
|
|
|
|
|
// 时间日期处理
|
|
|
|
|
function handlerDateTime(){
|
|
|
|
|
let date = new Date();
|
|
|
|
|
let dateStr = date.getFullYear()+"."+(date.getMonth()+1<9 ? '0'+(date.getMonth()+1) : date.getMonth()+1)+"."+date.getDate();
|
|
|
|
|
let timeStr = (date.getHours()<10 ? '0'+date.getHours() : date.getHours())+":"+(date.getMinutes() < 10 ? '0'+date.getMinutes() : date.getMinutes())+":"+(date.getSeconds()<10 ? '0'+date.getSeconds() : date.getSeconds());
|
|
|
|
|
let weekdays = ['日','一','二','三','四','五','六'];
|
|
|
|
|
let weekStr = "星期"+weekdays[date.getDay()];
|
|
|
|
|
document.getElementById("time").innerText = timeStr;
|
|
|
|
|
document.getElementById("day").innerText = dateStr;
|
|
|
|
|
document.getElementById("week").innerText = weekStr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setInterval(function(){
|
|
|
|
|
handlerDateTime();
|
|
|
|
|
},1000)
|
|
|
|
|
|
|
|
|
|
// WebSocket推送
|
|
|
|
|
|
|
|
|
|
// socket参数
|
|
|
|
|
const WS_URL = "ws://221.2.83.254:9002/ws"
|
|
|
|
|
let socket = null
|
|
|
|
|
let timeout = 10 * 1000// 45秒一次心跳
|
|
|
|
|
let timeoutObj = null // 心跳心跳倒计时
|
|
|
|
|
let serverTimeoutObj = null // 心跳倒计时
|
|
|
|
|
let timeoutnum = null // 断开 重连倒计时
|
|
|
|
|
let lockReconnect= false // 防止
|
|
|
|
|
|
|
|
|
|
function initWebSocket() {
|
|
|
|
|
// WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
|
|
|
|
|
let wsUrl = WS_URL;
|
|
|
|
|
window.websocket = new WebSocket(wsUrl);
|
|
|
|
|
window.websocket.onopen = websocketonopen;
|
|
|
|
|
window.websocket.onerror = websocketonerror;
|
|
|
|
|
window.websocket.onmessage = setOnmessageMessage;
|
|
|
|
|
window.websocket.onclose = websocketclose;
|
|
|
|
|
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
|
|
|
|
|
// window.onbeforeunload = that.onbeforeunload
|
|
|
|
|
}
|
|
|
|
|
function start() {
|
|
|
|
|
// console.log("start");
|
|
|
|
|
//清除延时器
|
|
|
|
|
timeoutObj && clearTimeout(timeoutObj);
|
|
|
|
|
serverTimeoutObj && clearTimeout(serverTimeoutObj);
|
|
|
|
|
timeoutObj = setTimeout(() => {
|
|
|
|
|
if (window.websocket && window.websocket.readyState == 1) {
|
|
|
|
|
//发送消息,服务端返回信息,即表示连接良好,可以在socket的onmessage事件重置心跳机制函数
|
|
|
|
|
window.websocket.send("heartBath");
|
|
|
|
|
} else {
|
|
|
|
|
reconnect();
|
|
|
|
|
}
|
|
|
|
|
//定义一个延时器等待服务器响应,若超时,则关闭连接,重新请求server建立socket连接
|
|
|
|
|
serverTimeoutObj = setTimeout(() => {
|
|
|
|
|
window.websocket.close();
|
|
|
|
|
}, timeout);
|
|
|
|
|
}, timeout);
|
|
|
|
|
}
|
|
|
|
|
function reset() {
|
|
|
|
|
// 重置心跳
|
|
|
|
|
// 清除时间
|
|
|
|
|
clearTimeout(timeoutObj);
|
|
|
|
|
clearTimeout(serverTimeoutObj);
|
|
|
|
|
// 重启心跳
|
|
|
|
|
start();
|
|
|
|
|
}
|
|
|
|
|
// 重新连接
|
|
|
|
|
function reconnect() {
|
|
|
|
|
if (lockReconnect) return;
|
|
|
|
|
lockReconnect = true;
|
|
|
|
|
//没连接上会一直重连,设置延迟避免请求过多
|
|
|
|
|
timeoutnum && clearTimeout(timeoutnum);
|
|
|
|
|
timeoutnum = setTimeout(() => {
|
|
|
|
|
initWebSocket();
|
|
|
|
|
lockReconnect = false;
|
|
|
|
|
}, 5000);
|
|
|
|
|
}
|
|
|
|
|
async function setOnmessageMessage(event) {
|
|
|
|
|
// console.log(event.data, "获得消息");
|
|
|
|
|
reset();
|
|
|
|
|
|
|
|
|
|
// 自定义全局监听事件
|
|
|
|
|
window.dispatchEvent(
|
|
|
|
|
new CustomEvent("onmessageWS", {
|
|
|
|
|
detail: {
|
|
|
|
|
data: event.data,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
function websocketonopen() {
|
|
|
|
|
//开启心跳
|
|
|
|
|
start();
|
|
|
|
|
console.log(
|
|
|
|
|
"WebSocket连接成功!!!" + new Date() + "----" + window.websocket.readyState
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
function websocketonerror(e) {
|
|
|
|
|
closeWebSocket()
|
|
|
|
|
console.log("WebSocket连接发生错误,重启socket");
|
|
|
|
|
console.log('Error:',e)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
function websocketclose(e) {
|
|
|
|
|
window.websocket.close();
|
|
|
|
|
clearTimeout(timeoutObj);
|
|
|
|
|
clearTimeout(serverTimeoutObj);
|
|
|
|
|
console.log("WebSocket连接关闭,重启socket");
|
|
|
|
|
reconnect();
|
|
|
|
|
}
|
|
|
|
|
function websocketsend(messsage) {
|
|
|
|
|
window.websocket.send(messsage);
|
|
|
|
|
}
|
|
|
|
|
function closeWebSocket() {
|
|
|
|
|
// 关闭websocket
|
|
|
|
|
window.websocket.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
initWebSocket();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 无人机在线列表更新
|
|
|
|
|
|
|
|
|
|
window.addEventListener("onmessageWS", getSocketData);
|
|
|
|
|
function isJson(str){
|
|
|
|
|
if (typeof str == 'string') {
|
|
|
|
|
try {
|
|
|
|
|
var obj = JSON.parse(str);
|
|
|
|
|
// 等于这个条件说明就是JSON字符串 会返回true
|
|
|
|
|
if (typeof obj == 'object' && obj) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
//不是就返回false
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
function getSocketData(evt){
|
|
|
|
|
if (isJson(evt.detail.data)){
|
|
|
|
|
let obj = JSON.parse(evt.detail.data);
|
|
|
|
|
if (obj != "close") {
|
|
|
|
|
if (obj != "" && obj.ip) {
|
|
|
|
|
isAddUav(obj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}else if(evt.detail.data.match("close")){
|
|
|
|
|
let ip = evt.detail.data.split(",")[0];
|
|
|
|
|
isUAVHave(ip);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let list = [];
|
|
|
|
|
let currentUav = null;
|
|
|
|
|
|
|
|
|
|
function isUAVHave(ip){
|
|
|
|
|
// 如果匹配到IP就删除掉
|
|
|
|
|
list.forEach((item,index)=>{
|
|
|
|
|
if(item.ip == ip){
|
|
|
|
|
list.splice(index,1);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
updateList();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
function isAddUav(obj){
|
|
|
|
|
let idx = null;
|
|
|
|
|
let uav = list.find((item,index)=>{
|
|
|
|
|
if(item.ip == obj.ip){
|
|
|
|
|
idx = index;
|
|
|
|
|
}
|
|
|
|
|
return item.ip == obj.ip
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if(!uav){
|
|
|
|
|
list.push(obj);
|
|
|
|
|
}else{
|
|
|
|
|
list[idx] = obj;
|
|
|
|
|
}
|
|
|
|
|
updateList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateList(){
|
|
|
|
|
$("#uav-list-container").empty();
|
|
|
|
|
$(".no-data").hide();
|
|
|
|
|
if(list.length==0){
|
|
|
|
|
$(".no-data").show();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
list.forEach((item,index)=>{
|
|
|
|
|
let checkclass = "";
|
|
|
|
|
if(item.account == currentUav){
|
|
|
|
|
checkclass = "menu-li-select"
|
|
|
|
|
}
|
|
|
|
|
let template = `<li class="menu-li ${checkclass}" onclick="updateUi(this);" data-phone="${item.account}">
|
|
|
|
|
<span class="menu-title" onclick="playerVideo(${item.account});">${item.model} ${item.account}</span>
|
|
|
|
|
<img class="meun-button" onclick="copyAddress(${item.account})" src="./img/img3.png" />
|
|
|
|
|
</li>`
|
|
|
|
|
$("#uav-list-container").append(template)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 视频画面切换和播放
|
|
|
|
|
function updateUi(obj){
|
|
|
|
|
$("#uav-list-container").children("li").removeClass("menu-li-select");
|
|
|
|
|
|
|
|
|
|
$(obj).addClass("menu-li-select")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let player = null;
|
|
|
|
|
|
|
|
|
|
function playerVideo(phone) {
|
|
|
|
|
currentUav = phone
|
|
|
|
|
window.websocket.send(phone);
|
|
|
|
|
if (player) {
|
|
|
|
|
player.src("http://live.hopetrytech.com/live/" + phone + ".flv");
|
|
|
|
|
} else {
|
|
|
|
|
player = TCPlayer("video", {});
|
|
|
|
|
player.src("http://live.hopetrytech.com/live/" + phone + ".flv");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function copyAddress(phone){
|
|
|
|
|
navigator.clipboard.writeText("http://live.hopetrytech.com/live/" + phone + ".flv");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if (flvjs.isSupported()) {
|
|
|
|
|
// var videoElement = document.getElementById('video');
|
|
|
|
|
// var flvPlayer = flvjs.createPlayer({
|
|
|
|
|
// type: 'flv',
|
|
|
|
|
// url: 'https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv'
|
|
|
|
|
// });
|
|
|
|
|
// flvPlayer.attachMediaElement(videoElement);
|
|
|
|
|
// flvPlayer.load();
|
|
|
|
|
// flvPlayer.play();
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
</html>
|