nezha/resource/template/theme-default/home.html
naiba 5f140f1d04 熊大给出的配色建议
Co-authored-by: xiongbao <4247191+xiongbao@users.noreply.github.com>
2021-08-06 10:43:21 +08:00

287 lines
11 KiB
HTML
Vendored
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{{define "theme-default/home"}} {{template "common/header" .}} {{if ts
.CustomCode}} {{.CustomCode|safe}} {{end}} {{template "common/menu" .}}
<div class="nb-container">
<div class="ui container">
<div id="app">
<div class="ui styled fluid accordion" v-for="group in groups">
<div class="active title">
<i class="dropdown icon"></i>@#(group.Tag!==''?group.Tag:'默认')#@
</div>
<div class="active content">
<div class="ui four stackable status cards">
<div v-for="server in group.data" :id="server.ID" class="ui card">
<div
class="content"
v-if="server.Host"
style="margin-top: 10px; padding-bottom: 5px"
>
<div class="header">
<i :class="server.Host.CountryCode + ' flag'"></i
><i
v-if='server.Host.Platform == "darwin"'
class="apple icon"
></i
><i
v-if='server.Host.Platform == "linux"'
class="linux icon"
></i
><i
v-if='server.Host.Platform == "windows"'
class="windows icon"
></i
><i
v-if='server.Host.Platform == "freebsd"'
class="freebsd icon"
></i
>@#server.Name + (server.live?'':' [已离线]')#@
<i class="yellow info circle icon"></i>
<div class="ui content popup" style="margin-bottom: 0">
系统:@#server.Host.Platform#@-@#server.Host.PlatformVersion#@
[<span v-if="server.Host.Virtualization"
>@#server.Host.Virtualization#@:</span
>@#server.Host.Arch#@]<br />
CPU@#server.Host.CPU#@<br />
硬盘:@#formatByteSize(server.State.DiskUsed)#@/@#formatByteSize(server.Host.DiskTotal)#@<br />
内存:@#formatByteSize(server.State.MemUsed)#@/@#formatByteSize(server.Host.MemTotal)#@<br />
交换:@#formatByteSize(server.State.SwapUsed)#@/@#formatByteSize(server.Host.SwapTotal)#@<br />
流量:<i
class="arrow alternate circle down outline icon"
></i
>@#formatByteSize(server.State.NetInTransfer)#@<i
class="arrow alternate circle up outline icon"
></i
>@#formatByteSize(server.State.NetOutTransfer)#@<br />
启动:@# formatTimestamp(server.Host.BootTime) #@<br />
活动:@# new Date(server.LastActive).toLocaleString() #@<br />
版本:@#server.Host.Version#@<br />
</div>
<div class="ui divider" style="margin-bottom: 5px"></div>
</div>
<div class="description">
<div class="ui grid">
<div class="three wide column">CPU</div>
<div class="thirteen wide column">
<div
:class="formatPercent(server.live,server.State.CPU, 100).class"
>
<div
class="bar"
:style="formatPercent(server.live,server.State.CPU, 100).style"
>
<small
>@#formatPercent(server.live,server.State.CPU,100).percent#@%</small
>
</div>
</div>
</div>
<div class="three wide column">内存</div>
<div class="thirteen wide column">
<div
:class="formatPercent(server.live,server.State.MemUsed, server.Host.MemTotal).class"
>
<div
class="bar"
:style="formatPercent(server.live,server.State.MemUsed, server.Host.MemTotal).style"
>
<small
>@#parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0)#@%</small
>
</div>
</div>
</div>
<div class="three wide column">交换</div>
<div class="thirteen wide column">
<div
:class="formatPercent(server.live,server.State.SwapUsed, server.Host.SwapTotal).class"
>
<div
class="bar"
:style="formatPercent(server.live,server.State.SwapUsed, server.Host.SwapTotal).style"
>
<small
>@#parseInt(server.State?server.State.SwapUsed/server.Host.SwapTotal*100:0)#@%</small
>
</div>
</div>
</div>
<div class="three wide column">网络</div>
<div class="thirteen wide column">
<i class="arrow alternate circle down outline icon"></i>
@#formatByteSize(server.State.NetInSpeed)#@/s
<i class="arrow alternate circle up outline icon"></i>
@#formatByteSize(server.State.NetOutSpeed)#@/s
</div>
<div class="three wide column">硬盘</div>
<div class="thirteen wide column">
<div
:class="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).class"
>
<div
class="bar"
:style="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).style"
>
<small
>@#parseInt(server.State?server.State.DiskUsed/server.Host.DiskTotal*100:0)#@%</small
>
</div>
</div>
</div>
<div class="three wide column">在线</div>
<div class="thirteen wide column">
<i class="clock icon"></i
>@#secondToDate(server.State.Uptime)#@
</div>
</div>
</div>
</div>
<div class="content" v-else>
<p>@#server.Name#@</p>
<p>节点已离线</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{template "common/footer" .}}
<script>
const initData = {{.Servers}};
var statusCards = new Vue({
el: '#app',
delimiters: ['@#', '#@'],
data: {
data: initData,
groups: [],
cache: [],
},
created() {
this.group()
},
mounted() {
$('.yellow.info.icon').popup({
popup: '.ui.content.popup',
exclusive: true,
});
},
methods: {
group() {
this.groups = groupingData(this.data, "Tag")
},
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'] = '#0a94f2'
this.cache[percent].class.fine = true
} else if (percent < 81) {
this.cache[percent].style['background-color'] = 'orange'
this.cache[percent].class.warning = true
} else {
this.cache[percent].style['background-color'] = 'crimson'
this.cache[percent].class.error = true
}
}
return this.cache[percent]
},
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 = readableBytes(bs)
return x != "NaN undefined" ? x : '0B'
}
}
})
function groupingData(data, filed) {
let map = {};
let dest = [];
data.forEach(item => {
if (!map[item[filed]]) {
dest.push({
[filed]: item[filed],
data: [item]
});
map[item[filed]] = item;
} else {
dest.forEach(dItem => {
if (dItem[filed] == item[filed]) {
dItem.data.push(item);
}
});
}
})
return dest;
}
const wsProtocol = window.location.protocol == "https:" ? "wss" : "ws"
const ws = new WebSocket(wsProtocol + '://' + window.location.host + '/ws');
ws.onopen = function (evt) {
$.suiAlert({
title: '实时通道建立',
description: '可以实时获取最新监控数据啦',
type: 'success',
time: '2',
position: 'top-center',
});
}
ws.onmessage = function (evt) {
const oldServers = statusCards.servers
const data = JSON.parse(evt.data)
statusCards.servers = data.servers
for (let i = 0; i < statusCards.servers.length; i++) {
const ns = statusCards.servers[i];
if (!ns.Host) ns.live = false
else {
const lastActive = new Date(ns.LastActive).getTime()
if (data.now - lastActive > 10 * 1000) {
ns.live = false
} else {
ns.live = true
}
}
}
statusCards.groups = groupingData(statusCards.servers, "Tag")
}
ws.onclose = function () {
$.suiAlert({
title: '实时通道断开',
description: '无法实时获取最新监控数据咯',
type: 'warning',
time: '2',
position: 'top-center',
});
}
$('.ui.accordion')
.accordion({"exclusive": false})
;
</script>
{{end}}