mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-02-04 12:40:07 +00:00
12
resource/template/theme-default/footer.html
vendored
Normal file
12
resource/template/theme-default/footer.html
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
{{define "theme-default/footer"}}
|
||||
</div>
|
||||
<div class="ui inverted vertical footer segment">
|
||||
<div class="ui center aligned is-size-7 container">
|
||||
<b>© <a style="color: white;" href="/">{{.Conf.Site.Brand}}</a></b> | <small>Powered by <a
|
||||
href="https://github.com/naiba/nezha" style="color: white;" target="_blank">{{tr "NezhaMonitoring"}}</a>
|
||||
{{.Version}}</small>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
25
resource/template/theme-default/header.html
vendored
Normal file
25
resource/template/theme-default/header.html
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
{{define "theme-default/header"}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{.Conf.Language}}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta content="telephone=no" name="format-detection">
|
||||
<title>{{.Title}}</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.1/dist/semantic.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-logos@0.17/assets/font-logos.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/lipis/flag-icons@7.0.0/css/flag-icons.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="/static/theme-default/css/main.css?v20240222">
|
||||
<link rel="shortcut icon" type="image/png" href="/static/logo.svg" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.1/dist/semantic.min.js"></script>
|
||||
<script src="/static/semantic-ui-alerts.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
|
||||
<script src="/static/theme-default/js/mixin.js?v20240225"></script>
|
||||
</head>
|
||||
<body>
|
||||
{{end}}
|
||||
260
resource/template/theme-default/home.html
vendored
260
resource/template/theme-default/home.html
vendored
@@ -1,10 +1,10 @@
|
||||
{{define "theme-default/home"}}
|
||||
{{template "common/header" .}}
|
||||
{{template "theme-default/header" .}}
|
||||
{{if ts .CustomCode}} {{.CustomCode|safe}} {{end}}
|
||||
{{template "common/menu" .}}
|
||||
{{template "theme-default/menu" .}}
|
||||
<div class="nb-container">
|
||||
<div class="ui container">
|
||||
<div id="app">
|
||||
<div class="ui container">
|
||||
<template v-if="groups">
|
||||
<div class="ui styled fluid accordion" v-for="group in groups">
|
||||
<div class="active title">
|
||||
<i class="dropdown icon"></i>
|
||||
@@ -15,12 +15,13 @@
|
||||
<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"'
|
||||
<i :class="'fi fi-' + server.Host.CountryCode"></i> <i v-if='server.Host.Platform == "darwin"'
|
||||
class="apple icon"></i><i v-else-if='isWindowsPlatform(server.Host.Platform)'
|
||||
class="windows icon"></i><i v-else :class="'fl-' + getFontLogoClass(server.Host.Platform)"></i>
|
||||
@#server.Name + (server.live?'':'[{{tr "Offline"}}]')#@
|
||||
<i class="nezha-secondary-font info circle icon" style="height: 28px"></i>
|
||||
<div class="ui content popup" style="margin-bottom: 0">
|
||||
<i @click="togglePopup($event, server.ID)" aria-expanded="false" class="nezha-secondary-font info circle icon" style="height: 28px"></i>
|
||||
<div class="ui content popup" :class="{ 'visible': isActive(server.ID) }" style="margin-bottom: 0;">
|
||||
<i class="closePopup window close icon" @click="closePopup(server.ID)"></i>
|
||||
{{tr "Platform"}}: @#server.Host.Platform#@-@#server.Host.PlatformVersion#@
|
||||
[<span
|
||||
v-if="server.Host.Virtualization">@#server.Host.Virtualization#@:</span>@#server.Host.Arch#@]<br />
|
||||
@@ -40,7 +41,8 @@
|
||||
{{tr "ConnCount"}}: TCP @# server.State.TcpConnCount #@ / UDP @# server.State.UdpConnCount #@<br />
|
||||
{{tr "BootTime"}}: @# formatTimestamp(server.Host.BootTime) #@<br />
|
||||
{{tr "LastActive"}}: @# new Date(server.LastActive).toLocaleString() #@<br />
|
||||
{{tr "Version"}}: @#server.Host.Version#@<br />
|
||||
{{tr "Version"}}: @#server.Host.Version#@
|
||||
<div class="chartbox" :key="server.ID" :ref="`chart${server.ID}`" style="width: 100%; height: auto; margin-bottom: 2px;"></div>
|
||||
</div>
|
||||
<div class="ui divider" style="margin-bottom: 5px"></div>
|
||||
</div>
|
||||
@@ -72,13 +74,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="three wide column">{{tr "NetSpeed"}}</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">{{tr "DiskUsed"}}</div>
|
||||
<div class="thirteen wide column">
|
||||
<div :class="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).class">
|
||||
@@ -88,6 +83,36 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="three wide column">{{tr "NetSpeed"}}</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">
|
||||
<i class="arrow circle down icon"></i>
|
||||
@#formatByteSize(server.State.NetInTransfer)#@
|
||||
|
||||
<i class="arrow circle up icon"></i>
|
||||
@#formatByteSize(server.State.NetOutTransfer)#@
|
||||
</div>
|
||||
<div class="three wide column">信息</div>
|
||||
<div class="thirteen wide column">
|
||||
<i class="bi bi-cpu-fill" style="font-size: 1.1rem; color: #4a86e8;"></i> @#getCoreAndGHz(server.Host.CPU)#@
|
||||
|
||||
<i class="bi bi-memory" style="font-size: 1.1rem; color: #00ac0d;"></i> @#getK2Gb(server.Host.MemTotal)#@
|
||||
|
||||
<i class="bi bi-hdd" style="font-size: 1.1rem; color: #e41e10"></i> @#getK2Gb(server.Host.DiskTotal)#@
|
||||
</div>
|
||||
<div class="three wide column">{{tr "Load"}}</div>
|
||||
<div class="thirteen wide column">
|
||||
<i class="bi bi-activity" style="font-size: 1.1rem; color: #e41e10;"></i>
|
||||
@# toFixed2(server.State.Load1) #@ |
|
||||
@# toFixed2(server.State.Load5) #@ |
|
||||
@# toFixed2(server.State.Load15) #@
|
||||
</div>
|
||||
<div class="three wide column">{{tr "Uptime"}}</div>
|
||||
<div class="thirteen wide column">
|
||||
<i class="clock icon"></i>@#secondToDate(server.State.Uptime)#@
|
||||
@@ -103,30 +128,171 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
{{template "common/footer" .}}
|
||||
{{template "theme-default/footer" .}}
|
||||
<script>
|
||||
const initData = JSON.parse('{{.Servers}}').servers;
|
||||
var statusCards = new Vue({
|
||||
el: '#app',
|
||||
delimiters: ['@#', '#@'],
|
||||
data: {
|
||||
data: initData,
|
||||
page: 'index',
|
||||
templates: {{.Themes}},
|
||||
data: [],
|
||||
groups: [],
|
||||
cache: [],
|
||||
chartDataList: [],
|
||||
activePopup: null,
|
||||
|
||||
},
|
||||
mixins: [mixinsVue],
|
||||
created() {
|
||||
this.data = JSON.parse('{{.Servers}}').servers;
|
||||
this.group()
|
||||
},
|
||||
mounted() {
|
||||
$('.nezha-secondary-font.info.icon').popup({
|
||||
popup: '.ui.content.popup',
|
||||
exclusive: true,
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
togglePopup(event, id) {
|
||||
// 切换弹出层的激活状态
|
||||
this.activePopup = this.activePopup === id ? null : id;
|
||||
this.showCharts(id);
|
||||
},
|
||||
isActive(id) {
|
||||
// 检查弹出层是否处于激活状态
|
||||
return this.activePopup === id;
|
||||
},
|
||||
closePopup(id) {
|
||||
this.activePopup = null;
|
||||
},
|
||||
showCharts(id) {
|
||||
// 发起数据请求
|
||||
const url = `/api/v1/monitor/${id}`;
|
||||
fetch(url)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.result) { // 数据请求成功,更新数据并渲染图表
|
||||
this.chartDataList[id - 1] = data.result;
|
||||
this.$nextTick(() => {
|
||||
this.renderCharts(id);
|
||||
});
|
||||
} else {
|
||||
console.log('this agent (id:'+ id + ') has no monitor.');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching data:', error);
|
||||
});
|
||||
},
|
||||
renderCharts(id) {
|
||||
if (!this.chartDataList[id - 1]) return;
|
||||
const MaxTCPPingValue = {{.MaxTCPPingValue}} ? {{.MaxTCPPingValue}} : 300;
|
||||
const isMobile = this.checkIsMobile();
|
||||
const fontSize = isMobile ? 10 : 9;
|
||||
const itemGap = isMobile ? 5 : 2;
|
||||
const itemWidth = isMobile ? 20 : 15;
|
||||
const gridLeft = 25;
|
||||
const gridRight = 12;
|
||||
const fontColor = "rgba(0, 0, 0, 0.68)";
|
||||
const backgroundColor = '';
|
||||
const borderColor = "#ffffff";
|
||||
const chartData = this.chartDataList[id - 1];
|
||||
const chartContainer = this.$refs[`chart${id}`][0];
|
||||
const chart = echarts.init(chartContainer, null, {
|
||||
renderer: 'canvas',
|
||||
useDirtyRect: false,
|
||||
width: 'auto',
|
||||
height: 120,
|
||||
});
|
||||
const xAxisData = chartData[0].created_at.map(time => new Date(time).toLocaleString());
|
||||
const seriesData = chartData.map(item => {
|
||||
let loss = 0;
|
||||
const data = item.avg_delay.map((avgDelay, index) => {
|
||||
if (avgDelay > 0.9 * MaxTCPPingValue) {
|
||||
loss += 1;
|
||||
}
|
||||
return [new Date(item.created_at[index]).toLocaleString(), avgDelay];
|
||||
});
|
||||
const lossRate = ((loss / item.created_at.length) * 100).toFixed(1);
|
||||
item.monitor_name = item.monitor_name + " " + lossRate + "%";
|
||||
return {
|
||||
name: item.monitor_name,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'none',
|
||||
data: data
|
||||
};
|
||||
});
|
||||
const option = {
|
||||
backgroundColor: backgroundColor,
|
||||
title: {
|
||||
show: false
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
trigger: 'axis',
|
||||
textStyle: {
|
||||
fontSize: fontSize,
|
||||
color: fontColor
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: chartData.map(item => item.monitor_name),
|
||||
show: true,
|
||||
textStyle: {
|
||||
fontSize: fontSize,
|
||||
color: fontColor
|
||||
},
|
||||
lineStyle: {
|
||||
cap: 'butt'
|
||||
},
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
itemGap: itemGap,
|
||||
itemWidth: itemWidth,
|
||||
padding: [5,0,5,0]
|
||||
},
|
||||
xAxis: {
|
||||
type: 'time',
|
||||
data: xAxisData,
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
fontSize: fontSize
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
fontSize: fontSize
|
||||
}
|
||||
}
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
show: false,
|
||||
type: 'slider',
|
||||
start: 0,
|
||||
end: 100
|
||||
}
|
||||
],
|
||||
series: seriesData,
|
||||
textStyle: {
|
||||
fontSize: fontSize,
|
||||
color: fontColor
|
||||
},
|
||||
grid: {
|
||||
top: '40',
|
||||
bottom: '20',
|
||||
left: gridLeft,
|
||||
right: gridRight
|
||||
}
|
||||
};
|
||||
chart.setOption(option);
|
||||
},
|
||||
checkIsMobile() { // 检测设备类型,页面宽度小于768px认为是移动设备
|
||||
return window.innerWidth <= 768;
|
||||
},
|
||||
toFixed2(f) {
|
||||
return f.toFixed(2)
|
||||
},
|
||||
@@ -227,7 +393,7 @@
|
||||
secondToDate(s) {
|
||||
var d = Math.floor(s / 3600 / 24);
|
||||
if (d > 0) {
|
||||
return d + ' {{tr "Day"}}'
|
||||
return d + " {{tr "Day"}}"
|
||||
}
|
||||
var h = Math.floor(s / 3600 % 24);
|
||||
var m = Math.floor(s / 60 % 60);
|
||||
@@ -238,8 +404,48 @@
|
||||
return new Date(t * 1000).toLocaleString()
|
||||
},
|
||||
formatByteSize(bs) {
|
||||
const x = readableBytes(bs)
|
||||
const x = this.readableBytes(bs)
|
||||
return x != "NaN undefined" ? x : '0B'
|
||||
},
|
||||
readableBytes(bytes) {
|
||||
if (!bytes) {
|
||||
return '0B'
|
||||
}
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(1024)),
|
||||
sizes = ["B", "K", "M", "G", "T", "P", "E", "Z", "Y"];
|
||||
return parseFloat((bytes / Math.pow(1024, i)).toFixed(2)) + sizes[i];
|
||||
},
|
||||
getCoreAndGHz(str){
|
||||
if((str || []).hasOwnProperty(0) === false){
|
||||
return '';
|
||||
}
|
||||
str = str[0];
|
||||
let GHz = str.match(/(\d|\.)+GHz/g);
|
||||
let Core = str.match(/(\d|\.)+ Physical/g);
|
||||
GHz = GHz!==null?GHz.hasOwnProperty(0)===false?'':GHz[0]:''
|
||||
Core = Core!==null?Core.hasOwnProperty(0)===false?'?':Core[0]:'?'
|
||||
if(Core === '?'){
|
||||
let Core = str.match(/(\d|\.)+ Virtual/g);
|
||||
Core = Core!==null?Core.hasOwnProperty(0)===false?'?':Core[0]:'?'
|
||||
return Core.replace('Virtual','Core')
|
||||
}
|
||||
return Core.replace('Physical','Core');
|
||||
},
|
||||
getK2Gb(bs){
|
||||
bs = bs / 1024 /1024 /1024;
|
||||
if(bs>=1){
|
||||
return Math.ceil(bs.toFixed(2)) + 'GB';
|
||||
}else{
|
||||
bs = bs * 1024;
|
||||
return Math.ceil(bs.toFixed(2)) + 'MB';
|
||||
}
|
||||
},
|
||||
listTipsMouseenter(obj,strs,tipsNum=1){
|
||||
this.layerIndex = layer.tips(strs, '#'+obj,{tips: [tipsNum, 'rgb(0 0 0 / 85%)'],time:0});
|
||||
$('#'+obj).attr('layerIndex',this.layerIndex)
|
||||
},
|
||||
listTipsMouseleave(obj){
|
||||
layer.close(this.layerIndex)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
47
resource/template/theme-default/menu.html
vendored
Normal file
47
resource/template/theme-default/menu.html
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
{{define "theme-default/menu"}}
|
||||
<div id="app">
|
||||
<div class="ui large top fixed menu nb-menu" style="z-index:9999999;">
|
||||
<div class="ui container">
|
||||
<a class="item" href="/">
|
||||
<img src="/static/logo.svg?v20210804">
|
||||
</a>
|
||||
<a class='item' href="/"><i class="home icon"></i>{{tr "Home"}}</a>
|
||||
<template v-if="isMobile">
|
||||
<div class="item ui simple dropdown">
|
||||
<div class="text"><i class="bi bi-gear-wide-connected icon" style="margin-right:3px;"></i>{{tr "Feature" }}<i class="dropdown icon" style="margin-right:0px;"></i></div>
|
||||
<div class="menu">
|
||||
<a href="/service" class="item"><i class="rss icon"></i>{{tr "Services" }}</a>
|
||||
<a href="/network" class="item"><i class="bi bi-hdd-network icon"></i>{{tr "NetworkSpiter"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a href="/service" class='item'><i class="rss icon"></i>{{tr "Services" }}</a>
|
||||
<a href="/network" class="item"><i class="bi bi-hdd-network icon"></i>{{tr "NetworkSpiter"}}</a>
|
||||
</template>
|
||||
<div class="item ui simple dropdown">
|
||||
<div class="text"><i class="bi bi-incognito icon" style="margin-right:3px;"></i>{{tr "Template" }}<i class="dropdown icon" style="margin-right:0px;"></i></div>
|
||||
<div class="menu">
|
||||
<a v-for="(value, key) in templates" :key="key" @click="toggleTemplate(key)" class="item"><i class="th large icon"></i>@#value#@
|
||||
<i class="check icon" v-if="preferredTemplate === key"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{{if .Admin}}
|
||||
<div class="item right item-right ui simple dropdown">
|
||||
<div class="text">
|
||||
<i class="user icon" style="margin-right:3px"></i>{{.Admin.Name}}
|
||||
<i class="dropdown icon"></i>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<a class="item" href="/server"><i class="terminal icon"></i>{{tr "AdminPanel"}}</a>
|
||||
<a class="item" @click="logOut({{.Admin.ID}})"><i class="logout icon"></i>{{tr "Logout"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<a href="/login" class="item right item-right" style="padding-right:1.2rem"><i class="sign-in icon"></i>{{tr "Login"}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{template "component/confirm" .}}
|
||||
{{end}}
|
||||
12
resource/template/theme-default/network.html
vendored
12
resource/template/theme-default/network.html
vendored
@@ -1,10 +1,10 @@
|
||||
{{define "theme-default/network"}}
|
||||
{{template "common/header" .}}
|
||||
{{template "theme-default/header" .}}
|
||||
{{if ts .CustomCode}}
|
||||
{{.CustomCode|safe}}
|
||||
{{end}}
|
||||
{{template "common/menu" .}}
|
||||
<div class="nb-container" id="app">
|
||||
{{template "theme-default/menu" .}}
|
||||
<div class="nb-container">
|
||||
<div class="ui container">
|
||||
<div class="service-status">
|
||||
<table class="ui celled table">
|
||||
@@ -22,8 +22,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "common/footer" .}}
|
||||
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/echarts/5.3.0-rc.1/echarts.min.js"></script>
|
||||
{{template "theme-default/footer" .}}
|
||||
|
||||
<script>
|
||||
const monitorInfo = JSON.parse('{{.MonitorInfos}}');
|
||||
@@ -36,6 +35,8 @@
|
||||
el: '#app',
|
||||
delimiters: ['@#', '#@'],
|
||||
data: {
|
||||
page: 'network',
|
||||
templates: {{.Themes}},
|
||||
servers: initData,
|
||||
option: {
|
||||
tooltip: {
|
||||
@@ -93,6 +94,7 @@
|
||||
},
|
||||
chartOnOff: true,
|
||||
},
|
||||
mixins: [mixinsVue],
|
||||
mounted() {
|
||||
this.renderChart();
|
||||
this.parseMonitorInfo(monitorInfo);
|
||||
|
||||
18
resource/template/theme-default/service.html
vendored
18
resource/template/theme-default/service.html
vendored
@@ -1,9 +1,9 @@
|
||||
{{define "theme-default/service"}}
|
||||
{{template "common/header" .}}
|
||||
{{template "theme-default/header" .}}
|
||||
{{if ts .CustomCode}}
|
||||
{{.CustomCode|safe}}
|
||||
{{end}}
|
||||
{{template "common/menu" .}}
|
||||
{{template "theme-default/menu" .}}
|
||||
<div class="nb-container">
|
||||
<div class="ui container">
|
||||
<div class="service-status">
|
||||
@@ -76,10 +76,20 @@
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "common/footer" .}}
|
||||
{{template "theme-default/footer" .}}
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
delimiters: ['@#', '#@'],
|
||||
data: {
|
||||
page: 'service',
|
||||
templates: {{.Themes}}
|
||||
},
|
||||
mixins: [mixinsVue]
|
||||
})
|
||||
</script>
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user