Progressbar restructure and UI design update

This commit is contained in:
Jackie Sung 2021-01-29 00:49:49 +08:00
parent c55cb942b3
commit d831c00895
8 changed files with 285 additions and 305 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
function callAllJsFiles(t){var e=document.createElement("script");e.setAttribute("type","text/javascript"),e.setAttribute("src",t),document.getElementsByTagName("head")[0].appendChild(e)}callAllJsFiles("/static/theme-daynight/js/mode.js?v202101241800"),callAllJsFiles("/static/theme-daynight/js/navtop.js?v202101241800");
function callAllJsFiles(t){var e=document.createElement("script");e.setAttribute("type","text/javascript"),e.setAttribute("src",t),document.getElementsByTagName("head")[0].appendChild(e)}callAllJsFiles("/static/theme-daynight/js/mode.js?v202101290086"),callAllJsFiles("/static/theme-daynight/js/navtop.js?v202101290086");

View File

@ -1 +1 @@
var darkCheckBox=document.querySelector("input[name=theme]"),themeStatus=document.getElementsByTagName("BODY")[0];darkCheckBox.addEventListener("change",(function(){this.checked?(trans(),themeStatus.setAttribute("data-theme","dark")):(trans(),themeStatus.setAttribute("data-theme","light"))}));let trans=()=>{themeStatus.classList.add("transition-theme"),window.setTimeout(()=>{themeStatus.classList.remove("transition-theme")},1e3)};var listCheckBox=document.querySelector("input[name=grid]");themeStatus=document.getElementsByTagName("BODY")[0];listCheckBox.addEventListener("change",(function(){this.checked?(transs(),themeStatus.setAttribute("data-gridlist","list")):(transs(),themeStatus.setAttribute("data-gridlist","grid"))}));let transs=()=>{themeStatus.classList.add("transition-theme"),window.setTimeout(()=>{themeStatus.classList.remove("transition-theme")},1e3)};
let darkCheckBox=$("input[name=theme]"),listCheckBox=$("input[name=grid]");darkCheckBox.change((function(){this.checked?(trans(),$("body").attr("data-theme","dark")):(trans(),$("body").attr("data-theme","light"))})),listCheckBox.change((function(){this.checked?(trans(),$("body").attr("data-gridlist","list")):(trans(),$("body").attr("data-gridlist","grid"))}));let servicedarkCheckBox=$("input[name=service-theme]"),servicelistCheckBox=$("input[name=service-grid]");function lightModeSwitch(){trans(),$("body").attr("data-theme","light")}function darkModeSwitch(){trans(),$("body").attr("data-theme","dark")}function gridModeSwitch(){trans(),$("body").attr("data-gridlist","grid")}function listModeSwitch(){trans(),$("body").attr("data-gridlist","list")}servicedarkCheckBox.change((function(){this.checked?(trans(),$("body").attr("data-theme","dark"),$(".service-mobile-toggle").toggleClass("smt-active")):(trans(),$("body").attr("data-theme","light"),$(".service-mobile-toggle").toggleClass("smt-active"))})),servicelistCheckBox.change((function(){this.checked?(trans(),$("body").attr("data-gridlist","list"),$(".service-mobile-toggle").toggleClass("smt-active")):(trans(),$("body").attr("data-gridlist","grid"),$(".service-mobile-toggle").toggleClass("smt-active"))})),$(document).ready((function(){$(".sidebar-container ul li:first-child").click(lightModeSwitch),$(".sidebar-container ul li:nth-child(2)").click(darkModeSwitch),$(".sidebar-container ul li:nth-child(3)").click(gridModeSwitch),$(".sidebar-container ul li:last-child").click(listModeSwitch)}));let trans=()=>{$("body").addClass("transition-theme"),window.setTimeout(()=>{$("body").removeClass("transition-theme")},1e3)},transSidebar=()=>{$("body").addClass("transition-sidebar"),window.setTimeout(()=>{$("body").removeClass("transition-sidebar")},1e3)};$(document).ready((function(){$(".sidebar-container ul li").hover((function(){transSidebar()}))}));

View File

@ -1 +1 @@
$(document).ready((function(){$(".hamburger").click((function(){$(this).toggleClass("is-active"),$(".nav-menu").toggleClass("active"),$(".nav-bar").toggleClass("active")}))}));var btn=$("#back-to-top");$(window).scroll((function(){$(window).scrollTop()>300?btn.addClass("show"):btn.removeClass("show")})),btn.on("click",(function(o){o.preventDefault(),$("html, body").animate({scrollTop:0},"300")}));
$(document).ready((function(){$(".hamburger").click((function(){$(this).toggleClass("is-active"),$(".nav-menu").toggleClass("active"),$(".nav-bar").toggleClass("active")}))}));var btn=$("#back-to-top");$(window).scroll((function(){$(window).scrollTop()>300?btn.addClass("show"):btn.removeClass("show")})),btn.on("click",(function(o){o.preventDefault(),$(".service-mobile-toggle").hasClass("smt-active")&&($(".service-mobile-toggle ").removeClass("smt-active"),$("html, body").animate({scrollTop:0},"300")),$("html, body").animate({scrollTop:0},"300")}));

View File

@ -1 +1 @@
function callAllJsFiles(t){var e=document.createElement("script");e.setAttribute("type","text/javascript"),e.setAttribute("src",t),document.getElementsByTagName("head")[0].appendChild(e)}callAllJsFiles("/static/theme-daynight/js/navtop.js?v202101241800"),callAllJsFiles("/static/theme-daynight/js/mode.js?v202101241800"),callAllJsFiles("/static/theme-daynight/js/tooltip.js?v202101241800"),$(".corner").hover((function(){$(this).attr("aria-expanded","true")}));const hour=new Date(Date.now()).getHours();(hour>17||hour<4)&&(document.querySelector("input[name=theme]").checked=!0,document.getElementsByTagName("BODY")[0].setAttribute("data-theme","dark"));
function callAllJsFiles(e){var t=document.createElement("script");t.setAttribute("type","text/javascript"),t.setAttribute("src",e),document.getElementsByTagName("head")[0].appendChild(t)}callAllJsFiles("/static/theme-daynight/js/navtop.js?v202101290086"),callAllJsFiles("/static/theme-daynight/js/mode.js?v202101290086"),callAllJsFiles("/static/theme-daynight/js/tooltip.js?v202101290086"),$(".corner").hover((function(){$(this).attr("aria-expanded","true"===$(this).attr("aria-expanded")?"false":"true")}));const hour=new Date(Date.now()).getHours();(hour>17||hour<4)&&(document.querySelector("input[name=service-theme]").checked=!0,document.getElementsByTagName("BODY")[0].setAttribute("data-theme","dark")),$(document).ready((function(){$(".fa-plus").click((function(){$(".service-mobile-toggle").toggleClass("smt-active")}))}));

View File

@ -1,282 +1,273 @@
{{define "theme-daynight/home"}}
<!doctype html>
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<title>{{.Title}}</title>
<link rel="shortcut icon" type="image/png" href="/static/logo.png" />
<link rel="stylesheet" href="/static/theme-daynight/css/main.css?v202101241800">
<link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/5.15.1/css/all.min.css" rel="stylesheet">
<link rel="stylesheet" href="/static/theme-daynight/css/main.css?v202101290086" />
<link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/5.15.1/css/all.min.css" rel="stylesheet" />
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
{{if ts .CustomCode}}
{{.CustomCode|safe}}
{{end}}
</head>
{{if ts .CustomCode}} {{.CustomCode|safe}} {{end}}
</head>
<body data-theme="light" data-gridlist="grid">
<body data-theme="light" data-gridlist="grid">
<header class="nav-bar clearfix">
<figure class="logo"><a href="/">{{.Conf.Site.Brand}}</a></figure>
<div class="icon-container">
<div class="row cf">
<div class="three col">
<div class="hamburger" id="hamburger-icon"><span class="line"></span><span class="line"></span><span
class="line"></span></div>
</div>
</div>
</div>
<nav class="nav-menu">
<ul>
<li><a href="/">首页</a></li>
<li><a href="/service">服务状态</a></li>
{{if .Admin}}
<li><a href="/server" style="padding:.8em;text-align:center;">管理后台</a></li>
{{else}}
<li><a href="/login">登录</a></li>
{{end}}
</ul>
</nav>
</header>
<section class="toggle-container">
<div class="dark-mode-toggle">
<label class="switcher">
<input type="checkbox" name="theme" id="dark-light" />
<div>
<i class="fas fa-sun" title="白昼模式"></i>
<i class="fas fa-moon" title="暗黑模式"></i>
<figure class="logo"><a href="/">{{.Conf.Site.Brand}}</a></figure>
<div class="icon-container">
<div class="row cf">
<div class="three col">
<div class="hamburger" id="hamburger-icon"><span class="line"></span><span class="line"></span><span class="line"></span></div>
</div>
</label>
</div>
</div>
<nav class="nav-menu">
<ul>
<li><a href="/">首页</a></li>
<li><a href="/service">服务状态</a></li>
{{if .Admin}}
<li><a href="/server" style="padding: 0.8em; text-align: center">管理后台</a></li>
{{else}}
<li><a href="/login">登录</a></li>
{{end}}
</ul>
</nav>
</header>
<main>
<div id="app">
<div class="server-info-container" v-for="server in servers" :id="server.ID">
<div class="info-body">
<ul class="server-info-body-container">
<li>
<div :class="'state-'+ (server.live?'online':'offline')">
<p>@#server.live?'Running':'Down'#@</p>
</div>
</li>
<li>
<h3>@#server.Name#@</h3>
</li>
<li><img :src="'/static/theme-daynight/img/flag/'+(server.Host&&server.Host.CountryCode?server.Host.CountryCode.toUpperCase():'CN')+'.png'" :title="server.Host.CountryCode.toUpperCase()" /></li>
<li>@#server.Host.Platform#@</li>
<li>@#server.Host.CountryCode.toUpperCase()#@</li>
<li>@#formatByteSize(server.State.MemUsed)#@ / @#formatByteSize(server.Host.MemTotal)#@</li>
<li>@#server.State?secondToDate(server.State.Uptime):'-'#@</li>
<li>@#formatByteSize(server.State.SwapUsed)#@ / @#formatByteSize(server.Host.SwapTotal)#@</li>
<li>@#formatByteSize(server.State.DiskUsed)#@ / @#formatByteSize(server.Host.DiskTotal)#@</li>
<li>@#formatByteSize(server.State.NetInTransfer)#@ (@#formatByteSize(server.State.NetInSpeed)#@/s)</li>
<li>@#formatByteSize(server.State.NetOutTransfer)#@ (@#formatByteSize(server.State.NetOutSpeed)#@/s)</li>
<li>
<div class="cpu-bar">
<div>
<h4>CPU</h4>
</div>
<div v-if="server.State" :class="formatPercent(server.live,server.State.CPU, 100).class" :title="formatPercent(server.live,server.State.CPU,100).percent+'%'">
<div class="progress-bar" role="progressbar" :aria-valuenow="formatPercent(server.live,server.State.CPU,100).percent" aria-valuemin="0" aria-valuemax="100" :style="formatPercent(server.live,server.State.CPU, 100).style">
<p>@#formatPercent(server.live,server.State.CPU,100).percent#@%</p>
</div>
</div>
</div>
</li>
<li>
<div class="ram-bar">
<div>
<h4>RAM</h4>
</div>
<div v-if="server.State" :class="formatPercent(server.live,server.State.MemUsed, server.Host.MemTotal).class" :title="parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0)+'%'">
<div class="progress-bar" role="progressbar" :aria-valuenow="parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0)" aria-valuemin="0" aria-valuemax="100" :style="formatPercent(server.live,server.State.MemUsed, server.Host.MemTotal).style">
<p>@#parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0)#@%</p>
</div>
</div>
</div>
</li>
<li>
<div class="disk-bar">
<div>
<h4>硬盘</h4>
</div>
<div v-if="server.State" :class="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).class" :title="parseInt(server.State?server.State.DiskUsed/server.Host.DiskTotal*100:0)+'%'">
<div class="progress-bar" role="progressbar" :aria-valuenow="parseInt(server.State?server.State.DiskUsed/server.Host.DiskTotal*100:0)" aria-valuemin="0" aria-valuemax="100" :style="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).style">
<p>@#parseInt(server.State?server.State.DiskUsed/server.Host.DiskTotal*100:0)#@%</p>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="grid-mode-toggle">
<label class="switcher">
<input type="checkbox" name="grid" id="grid-list" />
<div>
<i class="fas fa-th" title="网格视图"></i>
<i class="fas fa-list-ul" title="列表视图"></i>
</div>
</label>
<div class="sidebar-container">
<ul>
<li><i class="fas fa-sun" title="白昼模式"></i><span>白昼模式</span></li>
<li><i class="fas fa-moon" title="暗黑模式"></i><span>暗黑模式</span></li>
<li><i class="fas fa-th" title="网格视图"></i><span>网格视图</span></li>
<li><i class="fas fa-list-ul" title="列表视图"></i><span>列表视图</span></li>
</ul>
</div>
</section>
<div id="app">
<div class="server-info-container" v-for='server in servers' :id="server.ID">
<div class="info-body">
<ul class="server-info-body-container">
<li>
<div :class="'state-'+ (server.live?'online':'offline')">
<p>@#server.live?'Running':'Down'#@</p>
</div>
</li>
<li>
<h3>@#server.Name#@</h3>
</li>
<li><img :src="'/static/theme-daynight/img/flag/'+(server.Host&&server.Host.CountryCode?server.Host.CountryCode.toUpperCase():'CN')+'.png'"
:title="server.Host.CountryCode.toUpperCase()" /></li>
<li>@#server.Host.Platform#@</li>
<li>@#server.Host.CountryCode.toUpperCase()#@</li>
<li>@#formatByteSize(server.State.MemUsed)#@ / @#formatByteSize(server.Host.MemTotal)#@</li>
<li>@#server.State?secondToDate(server.State.Uptime):'-'#@</li>
<li>@#formatByteSize(server.State.SwapUsed)#@ / @#formatByteSize(server.Host.SwapTotal)#@</li>
<li>@#formatByteSize(server.State.DiskUsed)#@ / @#formatByteSize(server.Host.DiskTotal)#@</li>
<li>@#formatByteSize(server.State.NetInTransfer)#@ (@#formatByteSize(server.State.NetInSpeed)#@/s)</li>
<li>@#formatByteSize(server.State.NetOutTransfer)#@ (@#formatByteSize(server.State.NetOutSpeed)#@/s)</li>
<li>
<div class="cpu-bar">
<div>
<h4>CPU</h4>
</div>
<div v-if="server.State" :class="formatPercent(server.live,server.State.CPU, 100).class"
:title="formatPercent(server.live,server.State.CPU,100).percent+'%'">
<div class="bar td-padding"
:style="formatPercent(server.live,server.State.CPU, 100).style">
<p>@#formatPercent(server.live,server.State.CPU,100).percent#@%</p>
</div>
</div>
</div>
</li>
<li>
<div class="ram-bar">
<div>
<h4>RAM</h4>
</div>
<div v-if="server.State"
:class="formatPercent(server.live,server.State.MemUsed, server.Host.MemTotal).class"
:title="parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0)+'%'">
<div class="bar td-padding"
:style="formatPercent(server.live,server.State.MemUsed, server.Host.MemTotal).style">
<p>@#parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0)#@%</p>
</div>
</div>
</div>
</li>
<li>
<div class="disk-bar">
<div>
<h4>硬盘</h4>
</div>
<div v-if="server.State"
:class="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).class"
:title="parseInt(server.State?server.State.DiskUsed/server.Host.DiskTotal*100:0)+'%'">
<div class="bar td-padding"
:style="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).style">
<p>@#parseInt(server.State?server.State.DiskUsed/server.Host.DiskTotal*100:0)#@%</p>
</div>
</div>
</div>
</li>
</ul>
</div>
</main>
<section class="dark-light-toggle">
<label class="switcher">
<input type="checkbox" name="theme" id="dark-light" />
<div>
<i class="fas fa-adjust"></i>
</div>
</div>
</label>
</section>
<!-- Back to top button -->
<a id="back-to-top"></a>
<footer>
<div class="footer-container">
<div><a href="https://github.com/naiba/nezha" target="_blank">Powered by 哪吒面板 · {{.Version}}</a>
<p>&copy; <span id="copyright-date">
<script>document.getElementById('copyright-date').appendChild(document.createTextNode(new Date().getFullYear()))</script>
</span> · <a href="https://blog.jackiesung.com" target="_blank">Theme designed by Jackie Sung</a>
</p>
</div>
<div class="footer-container">
<div>
<a href="https://github.com/naiba/nezha" target="_blank">Powered by 哪吒面板 · {{.Version}}</a>
<p>
&copy;
<span id="copyright-date">
<script>
document.getElementById("copyright-date").appendChild(document.createTextNode(new Date().getFullYear()));
</script>
</span>
· <a href="https://blog.jackiesung.com" target="_blank">Theme designed by Jackie Sung</a>
</p>
</div>
</div>
</footer>
<script src="/static/theme-daynight/js/main.js?v202101241800" ></script>
<script src="/static/theme-daynight/js/main.js?v202101290086"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
<script>
const initData = {{.Servers }};
var statusCards = new Vue({
el: '#app',
delimiters: ['@#', '#@'],
data: {
servers: initData,
cache: [],
},
mounted() {
this.DarkMode();
},
methods: {
mergeUsage(state, host) {
if (!state) {
return 0
}
if (!host) {
return state.CPU
}
return (state.CPU + (state.MemUsed / host.MemTotal * 100) + (state.DiskUsed / host.DiskTotal * 100)) / 3
},
formatPercent(live, used, total) {
const percent = live ? (parseInt(used / total * 100) || 0) : -1
if (!this.cache[percent]) {
this.cache[percent] = {
class: {
ui: true,
progress: true,
},
style: {
'transition-duration': '300ms',
'min-width': 'unset',
width: percent + '% !important',
},
percent,
}
if (percent < 0) {
this.cache[percent].style['background-color'] = 'slategray'
this.cache[percent].class.offline = true
} else if (percent < 51) {
this.cache[percent].style['background-color'] = '#53B449'
this.cache[percent].class.fine = true
} else if (percent < 81) {
this.cache[percent].style['background-color'] = '#FBB142'
this.cache[percent].class.warning = true
} else {
this.cache[percent].style['background-color'] = '#F23D34'
this.cache[percent].class.error = true
}
}
return this.cache[percent]
},
readableBytes(bytes) {
var i = Math.floor(Math.log(bytes) / Math.log(1024)),
sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
return (bytes / Math.pow(1024, i)).toFixed(0) + ' ' + sizes[i];
},
DarkMode() {
const hour = new Date(Date.now()).getHours()
if (hour > 17 || hour < 4) {
document.querySelector("input[name=theme]").checked = true;
document.getElementsByTagName("BODY")[0].setAttribute('data-theme', 'dark');
}
},
secondToDate(s) {
var d = Math.floor(s / 3600 / 24);
if (d > 0) {
return d + "天"
}
var h = Math.floor(s / 3600 % 24);
var m = Math.floor(s / 60 % 60);
var s = Math.floor(s % 60);
return h + ":" + ("0" + m).slice(-2) + ":" + ("0" + s).slice(-2);
},
formatTimestamp(t) {
return new Date(t * 1000).toLocaleString()
},
formatByteSize(bs) {
const x = this.readableBytes(bs)
return x != "NaN undefined" ? x : '0 KB'
}
}
})
const wsProtocol = window.location.protocol == "https:" ? "wss" : "ws"
const ws = new WebSocket(wsProtocol + '://' + window.location.host + '/ws');
ws.onopen = function (evt) {
Swal.fire({
position: 'top',
icon: 'success',
title: '实时通道建立',
text: '可以实时获取最新监控数据啦',
showConfirmButton: false,
timer: 2000
});
}
ws.onmessage = function (evt) {
statusCards.servers = JSON.parse(evt.data)
const keys = Object.keys(statusCards.servers)
for (let i = 0; i < keys.length; i++) {
const ns = statusCards.servers[keys[i]];
if (!ns.Host) ns.live = false
else {
const lastActive = new Date(ns.LastActive).getTime()
if (Date.now() - lastActive > 20 * 1000) {
ns.live = false
} else {
ns.live = true
}
}
}
}
ws.onclose = function () {
Swal.fire({
position: 'top',
icon: 'error',
title: '实时通道断开',
text: '无法实时获取最新监控数据咯',
showConfirmButton: false,
timer: 2000
});
const initData = {{.Servers }};
var statusCards = new Vue({
el: '#app',
delimiters: ['@#', '#@'],
data: {
servers: initData,
cache: [],
},
mounted() {
this.DarkMode();
},
methods: {
mergeUsage(state, host) {
if (!state) {
return 0
}
if (!host) {
return state.CPU
}
return (state.CPU + (state.MemUsed / host.MemTotal * 100) + (state.DiskUsed / host.DiskTotal * 100)) / 3
},
formatPercent(live, used, total) {
const percent = live ? (parseInt(used / total * 100) || 0) : -1
if (!this.cache[percent]) {
this.cache[percent] = {
class: {
ui: true,
progress: true,
},
style: {
'transition-duration': '300ms',
'min-width': 'unset',
width: percent + '% !important',
},
percent,
}
if (percent < 0) {
this.cache[percent].style['background-color'] = 'slategray'
this.cache[percent].class.offline = true
} else if (percent < 51) {
this.cache[percent].style['background-color'] = '#53B449'
this.cache[percent].class.fine = true
} else if (percent < 81) {
this.cache[percent].style['background-color'] = '#FBB142'
this.cache[percent].class.warning = true
} else {
this.cache[percent].style['background-color'] = '#F23D34'
this.cache[percent].class.error = true
}
}
return this.cache[percent]
},
readableBytes(bytes) {
var i = Math.floor(Math.log(bytes) / Math.log(1024)),
sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
return (bytes / Math.pow(1024, i)).toFixed(0) + ' ' + sizes[i];
},
DarkMode() {
const hour = new Date(Date.now()).getHours()
if (hour > 17 || hour < 4) {
document.querySelector("input[name=theme]").checked = true;
document.getElementsByTagName("BODY")[0].setAttribute('data-theme', 'dark');
}
},
secondToDate(s) {
var d = Math.floor(s / 3600 / 24);
if (d > 0) {
return d + "天"
}
var h = Math.floor(s / 3600 % 24);
var m = Math.floor(s / 60 % 60);
var s = Math.floor(s % 60);
return h + ":" + ("0" + m).slice(-2) + ":" + ("0" + s).slice(-2);
},
formatTimestamp(t) {
return new Date(t * 1000).toLocaleString()
},
formatByteSize(bs) {
const x = this.readableBytes(bs)
return x != "NaN undefined" ? x : '0 KB'
}
}
})
const wsProtocol = window.location.protocol == "https:" ? "wss" : "ws"
const ws = new WebSocket(wsProtocol + '://' + window.location.host + '/ws');
ws.onopen = function (evt) {
Swal.fire({
position: 'top',
icon: 'success',
title: '实时通道建立',
text: '可以实时获取最新监控数据啦',
showConfirmButton: false,
timer: 2000
});
}
ws.onmessage = function (evt) {
statusCards.servers = JSON.parse(evt.data)
const keys = Object.keys(statusCards.servers)
for (let i = 0; i < keys.length; i++) {
const ns = statusCards.servers[keys[i]];
if (!ns.Host) ns.live = false
else {
const lastActive = new Date(ns.LastActive).getTime()
if (Date.now() - lastActive > 20 * 1000) {
ns.live = false
} else {
ns.live = true
}
}
}
}
ws.onclose = function () {
Swal.fire({
position: 'top',
icon: 'error',
title: '实时通道断开',
text: '无法实时获取最新监控数据咯',
showConfirmButton: false,
timer: 2000
});
}
}
</script>
</body>
</body>
</html>
{{end}}

View File

@ -7,14 +7,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{.Title}}</title>
<link rel="shortcut icon" type="image/png" href="/static/logo.png" />
<link rel="stylesheet" href="/static/theme-daynight/css/service.css?v202101241800" />
<link rel="stylesheet" href="/static/theme-daynight/css/service.css?v202101290086" />
<link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/5.15.1/css/all.min.css" rel="stylesheet" />
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
{{if ts .CustomCode}}
{{.CustomCode|safe}}
{{end}}
{{if ts .CustomCode}} {{.CustomCode|safe}} {{end}}
</head>
<body data-theme="light" data-gridlist="list">
@ -33,7 +31,7 @@
<li><a href="/">首页</a></li>
<li><a href="/service">服务状态</a></li>
{{if .Admin}}
<li><a href="/server" style="padding:.8em;text-align:center;">管理后台</a></li>
<li><a href="/server" style="padding: 0.8em; text-align: center">管理后台</a></li>
{{else}}
<li><a href="/login">登录</a></li>
{{end}}
@ -41,28 +39,6 @@
</nav>
</header>
<section class="toggle-container">
<div class="dark-mode-toggle">
<label class="switcher">
<input type="checkbox" name="theme" id="dark-light" />
<div>
<i class="fas fa-sun" title="白昼模式"></i>
<i class="fas fa-moon" title="暗黑模式"></i>
</div>
</label>
</div>
<div class="grid-mode-toggle">
<label class="switcher">
<input type="checkbox" name="grid" id="grid-list" checked />
<div>
<i class="fas fa-th" title="网格视图"></i>
<i class="fas fa-list-ul" title="列表视图"></i>
</div>
</label>
</div>
</section>
<main>
<section class="monitor-header">
<h2>服务状态</h2>
@ -94,6 +70,37 @@
</section>
</main>
<div class="sidebar-container">
<ul>
<li><i class="fas fa-sun" title="白昼模式"></i><span>白昼模式</span></li>
<li><i class="fas fa-moon" title="暗黑模式"></i><span>暗黑模式</span></li>
<li><i class="fas fa-th" title="网格视图"></i><span>网格视图</span></li>
<li><i class="fas fa-list-ul" title="列表视图"></i><span>列表视图</span></li>
</ul>
</div>
<section class="service-mobile-toggle">
<ul>
<li><i class="fas fa-plus"></i></li>
<li>
<label class="switcher">
<input type="checkbox" name="service-theme" id="dark-light" />
<div>
<i class="fas fa-adjust"></i>
</div>
</label>
</li>
<li>
<label class="switcher">
<input type="checkbox" name="service-grid" id="grid-list" checked />
<div>
<i class="fas fa-grip-horizontal"></i>
</div>
</label>
</li>
</ul>
</section>
<footer>
<div class="footer-container">
<div>
@ -110,12 +117,12 @@
</div>
</div>
</footer>
<!-- Back to top button -->
<a id="back-to-top"></a>
</article>
<script src="/static/theme-daynight/js/service.js?v202101241800"></script>
<script src="/static/theme-daynight/js/service.js?v202101290086"></script>
</body>
</html>
{{end}}