nezha/resource/template/theme-hotaru/home.html

290 lines
13 KiB
HTML
Raw Normal View History

2020-12-09 06:05:40 -05:00
{{define "theme-hotaru/home"}}
<!doctype html>
<html lang="zh">
<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>
2021-08-04 01:35:41 -04:00
<link rel="shortcut icon" type="image/png" href="/static/logo.svg?v20210804" />
2020-12-09 06:05:40 -05:00
<!-- Fix chrome language detection -->
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<meta http-equiv="Content-Language" content="zh" />
<!-- Styles -->
2020-12-09 06:10:28 -05:00
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
<link rel="stylesheet" type="text/css" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/5.15.1/css/all.min.css">
2020-12-09 06:05:40 -05:00
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
2020-12-18 23:43:03 -05:00
<link rel="stylesheet" href="/static/theme-hotaru/css/core.css?v202012121912" type="text/css">
2021-01-16 22:53:43 -05:00
<link rel="stylesheet" href="/static/theme-hotaru/css/main.css?v202101171153" type="text/css">
<link rel="stylesheet" href="/static/theme-hotaru/css/darkmode.css?v202103021121" type="text/css">
2020-12-23 20:54:17 -05:00
{{if ts .CustomCode}}
{{.CustomCode|safe}}
2020-12-18 21:57:10 -05:00
{{end}}
2020-12-09 06:05:40 -05:00
</head>
<body>
<section class="hotaru-cover">
<div class="container" style="text-align: center;">
<h1>
<strong>{{.Title}}</strong>
</h1>
<div>
<p>
<small>狀態更新和事件報告可能會延遲最多30秒鐘<br />具體取決於手頭的技術問題。請向下滾動查看過去的事件報告</small>
</p>
</div>
</div>
</section>
<div id="app">
<div class="container">
<table class="table table-striped">
<thead>
<tr>
<th>运行状态</th>
<th>节点名</th>
<th>系统</th>
2020-12-21 03:34:21 -05:00
<th>位置</th>
<th>在线</th>
2020-12-09 06:05:40 -05:00
<th>网络(B/s) ↓|↑</th>
<th>流量(B) ↓|↑</th>
<th>CPU</th>
<th>RAM</th>
<th>硬盘</th>
</tr>
</thead>
<tbody id="servers" style="text-align:center;">
<tr v-for='server in servers' :id="server.ID">
<td>
<div class="progress">
<div :class="'state-'+ (server.live?'online':'offline')">
<small>@#server.live?'运行中':'已离线'#@</small>
2020-12-09 06:05:40 -05:00
</div>
</div>
</td>
<td>@#server.Name#@</td>
<td>@#server.Host?server.Host.Platform:'-'#@</td>
<td>@#server.Host?server.Host.CountryCode:'-'#@</td>
<td>@#server.State?secondToDate(server.State.Uptime):'-'#@</td>
<td>@#server.State?readableBytes(server.State.NetInSpeed)+'/s|'+readableBytes(server.State.NetOutSpeed)+'/s':'-'#@
2020-12-09 06:05:40 -05:00
</td>
<td>@#server.State?readableBytes(server.State.NetInTransfer)+'|'+readableBytes(server.State.NetOutTransfer):'-'#@
2020-12-09 06:05:40 -05:00
</td>
<td>
2020-12-18 23:43:03 -05:00
<div v-if="server.State" :class="formatPercent(server.live,server.State.CPU, 100).class">
<div class="bar" :style="formatPercent(server.live,server.State.CPU, 100).style">
2020-12-18 23:52:28 -05:00
<small>@#formatPercent(server.live,server.State.CPU,100).percent#@%</small>
2020-12-09 06:05:40 -05:00
</div>
</div>
</td>
<td>
2020-12-18 23:43:03 -05:00
<div v-if="server.State"
: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">
2020-12-09 07:26:14 -05:00
<small>@#parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0)#@%</small>
2020-12-09 06:05:40 -05:00
</div>
</div>
</td>
<td>
2020-12-18 23:43:03 -05:00
<div v-if="server.State"
:class="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).class">
2020-12-20 10:15:57 -05:00
<div class="bar"
2020-12-18 23:43:03 -05:00
:style="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).style">
2020-12-09 07:26:14 -05:00
<small>@#parseInt(server.State?server.State.DiskUsed/server.Host.DiskTotal*100:0)#@%</small>
2020-12-09 06:05:40 -05:00
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="page-section">
<div class="container">
<div class="row">
<div class="col-lg-4 col-md-4 col-sm-4" v-for='server in servers' :id="server.ID">
<div class="panel panel-block panel-block-sm panel-location">
<div class="location-header">
<h3 class="h4"><img
:src="'/static/theme-hotaru/img/clients/'+(server.Host&&server.Host.CountryCode?server.Host.CountryCode.toUpperCase():'CN')+'.png'">
2020-12-09 06:05:40 -05:00
&nbsp;@#server.Name#@</h3>
<i class="zmdi zmdi-check-circle text-success"></i>
</div>
<div class="location-progress">
<div
:class="formatPercent(server.live,mergeUsage(server.State, server.Host),100).class">
2020-12-18 23:43:03 -05:00
<div class="bar"
:style="formatPercent(server.live,mergeUsage(server.State, server.Host),100).style">
2020-12-09 06:05:40 -05:00
</div>
</div>
</div>
<ul class="location-info list-styled">
<li><span class="list-label">网络:</span>
@#server.State?formatByteSize(server.State.NetInSpeed)+'/s|'+formatByteSize(server.State.NetOutSpeed)+'/s':'-'#@
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sidebar-container">
<ul>
<li id='sun'><i class="fas fa-sun" title="白昼模式"></i><span>白昼模式</span></li>
<li id='moon'><i class="fas fa-moon" title="暗黑模式"></i><span>暗黑模式</span></li>
</ul>
</div>
2020-12-09 06:05:40 -05:00
<footer>
<p style="text-align:center;padding: 15px;">Powered by <a href="https://github.com/naiba/nezha">哪吒监控</a> build ·
2020-12-09 17:46:31 -05:00
{{.Version}}
<a href="/service">服务状态</a>
2020-12-09 17:46:31 -05:00
<a href="/server">管理后台</a>
2020-12-09 06:05:40 -05:00
</p>
</footer>
2020-12-09 06:10:28 -05:00
<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.1/dist/semantic.min.js"></script>
2020-12-09 06:05:40 -05:00
<script src="/static/semantic-ui-alerts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js"></script>
2020-12-09 06:05:40 -05:00
<script>
2022-03-23 09:07:38 -04:00
const initData = JSON.parse('{{.Servers}}').servers;
2020-12-09 06:05:40 -05:00
var statusCards = new Vue({
el: '#app',
delimiters: ['@#', '#@'],
data: {
servers: initData,
2020-12-18 23:43:03 -05:00
cache: [],
2020-12-09 06:05:40 -05:00
},
mounted() {
this.troggleDarkMode();
},
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
},
2020-12-18 23:43:03 -05:00
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'
2020-12-18 23:43:03 -05:00
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]
},
2020-12-09 06:05:40 -05:00
readableBytes(bytes) {
2021-07-05 01:44:21 -04:00
if (!bytes) {
return '0B'
}
2020-12-09 06:05:40 -05:00
var i = Math.floor(Math.log(bytes) / Math.log(1024)),
2021-07-05 01:44:21 -04:00
sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
return parseFloat((bytes / Math.pow(1024, i)).toFixed(2)) + sizes[i];
2020-12-09 06:05:40 -05:00
},
2021-07-05 23:57:53 -04:00
formatByteSize(bs) {
const x = this.readableBytes(bs)
return x != "NaN undefined" ? x : '0B'
},
2020-12-09 06:05:40 -05:00
troggleDarkMode() {
2020-12-18 23:43:03 -05:00
const hour = new Date(Date.now()).getHours()
if (hour > 17 || hour < 4) {
document.body.classList.add('dark');
}
2020-12-09 06:05:40 -05:00
},
secondToDate(s) {
var d = Math.floor(s / 3600 / 24);
2020-12-21 03:34:21 -05:00
if (d > 0) {
return d + "天"
}
2020-12-09 06:05:40 -05:00
var h = Math.floor(s / 3600 % 24);
2020-12-21 03:34:21 -05:00
var m = Math.floor(s / 60 % 60);
var s = Math.floor(s % 60);
return h + ":" + ("0" + m).slice(-2) + ":" + ("0" + s).slice(-2);
2020-12-09 06:05:40 -05:00
},
formatTimestamp(t) {
return new Date(t * 1000).toLocaleString()
}
}
})
$(function(){
$('#sun').click(function(){
$('body').removeClass('dark');
});
$('#moon').click(function(){
$('body').addClass('dark');
})
})
2020-12-09 06:05:40 -05:00
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 data = JSON.parse(evt.data)
statusCards.servers = data.servers
2021-01-08 08:04:50 -05:00
for (let i = 0; i < statusCards.servers.length; i++) {
const ns = statusCards.servers[i];
2020-12-18 23:43:03 -05:00
if (!ns.Host) ns.live = false
else {
const lastActive = new Date(ns.LastActive).getTime()
if (data.now - lastActive > 10 * 1000) {
2020-12-18 23:43:03 -05:00
ns.live = false
} else {
ns.live = true
2020-12-09 06:05:40 -05:00
}
}
}
}
ws.onclose = function () {
$.suiAlert({
title: '实时通道断开',
description: '无法实时获取最新监控数据咯',
type: 'warning',
time: '2',
position: 'top-center',
});
}
</script>
</body>
</html>
{{end}}