504 lines
13 KiB
HTML
504 lines
13 KiB
HTML
<!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> |