2023-11-07 00:46:28 -05:00
|
|
|
|
{{define "theme-server-status/service"}}
|
|
|
|
|
{{template "theme-server-status/header" .}}
|
|
|
|
|
<div id="app">
|
|
|
|
|
{{template "theme-server-status/content-nav" .}}
|
|
|
|
|
<div class="container content" style="max-width: 95vw">
|
|
|
|
|
<table class="table table-striped table-condensed service-status">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th class="node-cell" style="min-width: 60px">🍀 {{tr "Status"}}</th>
|
|
|
|
|
<th class="node-cell" style="min-width: 60px">🚀 {{tr "Name"}}</th>
|
|
|
|
|
<th class="node-cell center">🗂 {{tr "Details"}}</th>
|
|
|
|
|
<th class="node-cell center" style="min-width: 80px">⚡️{{tr "AverageLatency"}}</th>
|
|
|
|
|
<th class="node-cell center" style="min-width: 80px">⏱️ {{tr "30DaysOnline"}}</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody id="servers">
|
|
|
|
|
<template v-for="service in services">
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="text-align: left" class="node-cell">
|
|
|
|
|
<div class="delay-today">
|
|
|
|
|
<i class="delay-today" :class="service.health.className"></i>
|
|
|
|
|
@#service.health.text#@
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td class="node-cell">@#service.name#@</td>
|
|
|
|
|
<td class="node-cell center">
|
|
|
|
|
<template v-for="(item,index) in service.dayDetail">
|
|
|
|
|
<div class="service-day-status-icon" :class="item.className"
|
|
|
|
|
:data-tooltip="item.text">
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</td>
|
|
|
|
|
<td class="node-cell center">@#service.avgDelay#@</td>
|
|
|
|
|
<td class="node-cell center">
|
|
|
|
|
<div class="progress">
|
|
|
|
|
<div :style="service.totalUpTime.style" :class="service.totalUpTime.className">
|
|
|
|
|
<small>@#service.totalUpTime.percent#@%</small>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</template>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
2023-11-08 00:17:42 -05:00
|
|
|
|
<div class="container" style="margin-bottom: 20px;padding:unset">
|
2023-11-07 09:56:59 -05:00
|
|
|
|
{{if .CycleTransferStats}}
|
2023-11-08 00:17:42 -05:00
|
|
|
|
<h4 style="text-align: center;">{{tr "CycleTransferStats"}}</h4>
|
|
|
|
|
<div class="table-responsive content">
|
|
|
|
|
<table class="table table-striped table-condensed">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th>ID</th>
|
|
|
|
|
<th>{{tr "Rules"}}</th>
|
|
|
|
|
<th>{{tr "Server"}}</th>
|
|
|
|
|
<th>{{tr "From"}}</th>
|
|
|
|
|
<th>{{tr "To"}}</th>
|
|
|
|
|
<th>MAX</th>
|
|
|
|
|
<th>MIN</th>
|
|
|
|
|
<th>{{tr "NextCheck"}}</th>
|
|
|
|
|
<th>{{tr "CurrentUsage"}}</th>
|
|
|
|
|
<th class='ui center aligned'>{{tr "Transleft"}}</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
{{range $id, $stats := .CycleTransferStats}}
|
|
|
|
|
{{range $innerId, $transfer := $stats.Transfer}}
|
|
|
|
|
{{$TransLeftPercent := TransLeftPercent (UintToFloat $transfer) (UintToFloat $stats.Max)}}
|
|
|
|
|
<tr>
|
|
|
|
|
<td>{{$id}}</td>
|
|
|
|
|
<td>{{$stats.Name}}</td>
|
|
|
|
|
<td>{{index $stats.ServerName $innerId}}</td>
|
|
|
|
|
<td>{{$stats.From|tf}}</td>
|
|
|
|
|
<td>{{$stats.To|tf}}</td>
|
|
|
|
|
<td>{{$stats.Max|bf}}</td>
|
|
|
|
|
<td>{{$stats.Min|bf}}</td>
|
|
|
|
|
<td>{{(index $stats.NextUpdate $innerId)|sft}}</td>
|
|
|
|
|
<td>{{$transfer|bf}}</td>
|
|
|
|
|
<td>
|
|
|
|
|
<div class="ui progress {{TransClassName $TransLeftPercent}}"
|
|
|
|
|
style=" background: rgba(0,0,0,.1); background-color: rgba(0,0,0,.1)!important; height: 25px; margin: unset !important">
|
|
|
|
|
<div class="bar"
|
|
|
|
|
style="transition-duration: 300ms; min-width: unset; background-color: rgb(10, 148, 242); width: {{$TransLeftPercent}}% !important">
|
|
|
|
|
</div>
|
|
|
|
|
<small style="position: relative; top: -2em;">{{TransLeft $stats.Max $transfer}} /
|
|
|
|
|
{{$TransLeftPercent}} %</small>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
{{end}}
|
|
|
|
|
{{end}}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
2023-11-07 09:56:59 -05:00
|
|
|
|
{{end}}
|
2023-11-07 00:46:28 -05:00
|
|
|
|
</div>
|
|
|
|
|
{{template "theme-server-status/content-footer" .}}
|
|
|
|
|
</div>
|
|
|
|
|
<script>
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
<script>
|
|
|
|
|
new Vue({
|
|
|
|
|
el: '#app',
|
|
|
|
|
delimiters: ['@#', '#@'],
|
|
|
|
|
data: {
|
|
|
|
|
services: []
|
|
|
|
|
},
|
|
|
|
|
created() {
|
|
|
|
|
this.initData()
|
|
|
|
|
},
|
|
|
|
|
mounted() {
|
|
|
|
|
},
|
|
|
|
|
mixins: [mixinsVue],
|
|
|
|
|
methods: {
|
|
|
|
|
initData() {
|
|
|
|
|
// @formatter:off
|
|
|
|
|
const services = []
|
|
|
|
|
{{range $service := .Services}}
|
|
|
|
|
services.push({
|
|
|
|
|
name: '{{$service.Monitor.Name}}',
|
|
|
|
|
currentUp: parseInt('{{$service.CurrentUp}}'),
|
|
|
|
|
currentDown: parseInt('{{$service.CurrentDown}}'),
|
|
|
|
|
totalUp: parseInt('{{$service.TotalUp}}'),
|
|
|
|
|
totalDown: parseInt('{{$service.TotalDown}}'),
|
|
|
|
|
delay: '{{$service.Delay}}'.replaceAll("[","").replaceAll("]","").split(" "),
|
|
|
|
|
up: '{{$service.Up}}'.replaceAll("[","").replaceAll("]","").split(" "),
|
|
|
|
|
down: '{{$service.Down}}'.replaceAll("[","").replaceAll("]","").split(" "),
|
|
|
|
|
})
|
|
|
|
|
{{end}}
|
|
|
|
|
// @formatter:on
|
|
|
|
|
for (let i = 0; i < services.length; i++) {
|
|
|
|
|
const service = services[i];
|
|
|
|
|
service.avgDelay = parseInt(service.delay[service.delay.length - 1]) + "ms"
|
|
|
|
|
service.health = this.getStateInfo(this.getPercent(service.currentUp, service.currentDown))
|
|
|
|
|
service.dayDetail = this.getDayTails(service)
|
|
|
|
|
service.totalUpTime = this.getProgressInfo(this.getPercent(service.totalUp, service.totalDown))
|
|
|
|
|
}
|
|
|
|
|
this.services = services
|
|
|
|
|
},
|
|
|
|
|
getPercent(up, down) {
|
|
|
|
|
if (!up) {
|
|
|
|
|
up = 0;
|
|
|
|
|
}
|
|
|
|
|
if (!down) {
|
|
|
|
|
down = 0
|
|
|
|
|
}
|
|
|
|
|
const currentUp = parseInt(up)
|
|
|
|
|
const currentDown = parseInt(down)
|
|
|
|
|
const total = currentUp + currentDown
|
|
|
|
|
if (total === 0) {
|
|
|
|
|
if (currentUp > 0) {
|
|
|
|
|
return 100
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
} else if (currentUp === 0) {
|
|
|
|
|
return 0.00001 / total * 100
|
|
|
|
|
}
|
|
|
|
|
return this.toFixed2(currentUp / total * 100)
|
|
|
|
|
},
|
|
|
|
|
getDayTails(service) {
|
|
|
|
|
const result = []
|
|
|
|
|
for (let i = 0; i < service.up.length; i++) {
|
|
|
|
|
const up = service.up[i]
|
|
|
|
|
const down = service.down[i]
|
|
|
|
|
const delay = service.delay[i]
|
|
|
|
|
let percent = this.getPercent(up, down)
|
|
|
|
|
if (percent <= 0) {
|
|
|
|
|
percent = 0;
|
|
|
|
|
}
|
|
|
|
|
let className = this.getStateInfo(percent).className
|
|
|
|
|
let available = '{{tr "Availability"}}'
|
|
|
|
|
let averageLatency = '{{tr "AverageLatency"}}'
|
|
|
|
|
const text = `${this.beforeDay(service.up.length - i - 1)},${available}:${percent}%,${averageLatency}:${delay}ms`
|
|
|
|
|
result.push({
|
|
|
|
|
text, className
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
return result
|
|
|
|
|
},
|
|
|
|
|
beforeDay(days) {
|
|
|
|
|
const today = new Date();
|
|
|
|
|
today.setDate(today.getDate() - days);
|
|
|
|
|
// 获取月份和日期并格式化
|
|
|
|
|
const month = (today.getMonth() + 1).toString().padStart(2, '0');
|
|
|
|
|
const day = today.getDate().toString().padStart(2, '0');
|
|
|
|
|
return `${month}-${day}`;
|
|
|
|
|
},
|
|
|
|
|
getStateInfo(percent) {
|
|
|
|
|
if (percent < 0) {
|
|
|
|
|
percent = 0;
|
|
|
|
|
}
|
|
|
|
|
const result = {
|
|
|
|
|
className: "good",
|
|
|
|
|
text: "",
|
|
|
|
|
percent
|
|
|
|
|
}
|
|
|
|
|
if (percent === 0) {
|
|
|
|
|
result.className = ""
|
|
|
|
|
result.text = '{{tr "StatusNoData"}}'
|
|
|
|
|
} else if (percent > 95) {
|
|
|
|
|
result.className = "good"
|
|
|
|
|
result.text = '{{tr "StatusGood"}}'
|
|
|
|
|
} else if (percent > 80) {
|
|
|
|
|
result.className = "warning"
|
|
|
|
|
result.text = '{{tr "StatusLowAvailability"}}'
|
|
|
|
|
} else {
|
|
|
|
|
result.className = "danger"
|
|
|
|
|
result.text = '{{tr "StatusDown"}}'
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
},
|
|
|
|
|
getProgressInfo(percent) {
|
|
|
|
|
const result = this.getStateInfo(percent)
|
|
|
|
|
result.style = `width: ${parseInt(percent)}%`;
|
|
|
|
|
const className = result.className;
|
|
|
|
|
if (className === "good") {
|
|
|
|
|
result.className = 'progress-bar progress-bar-success'
|
|
|
|
|
} else if (className === "waining") {
|
|
|
|
|
result.className = 'progress-bar progress-bar-warning'
|
|
|
|
|
} else if (className === "danger") {
|
|
|
|
|
result.className = 'progress-bar progress-bar-danger'
|
|
|
|
|
} else {
|
|
|
|
|
result.className = ""
|
|
|
|
|
result.style = "width: 100%"
|
|
|
|
|
}
|
|
|
|
|
return result
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
{{template "theme-server-status/footer" .}}
|
|
|
|
|
{{end}}
|