300 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			HTML
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			HTML
		
	
	
	
		
			Vendored
		
	
	
	
{{define "theme-daynight/network"}}
 | 
						||
<!doctype html>
 | 
						||
<html lang="{{.Conf.Language}}">
 | 
						||
 | 
						||
<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.svg?v20210804" />
 | 
						||
 | 
						||
    <link rel="stylesheet" href="/static/theme-daynight/css/main.css?v202108042286">
 | 
						||
    <link href="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
 | 
						||
    <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/jquery/3.6.0/jquery.min.js"></script>
 | 
						||
    <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/echarts/5.3.0-rc.1/echarts.min.js"></script>
 | 
						||
 | 
						||
    {{if ts .CustomCode}}
 | 
						||
    {{.CustomCode|safe}}
 | 
						||
    {{end}}
 | 
						||
</head>
 | 
						||
 | 
						||
<body data-theme="light" data-gridlist="grid">
 | 
						||
    <header>
 | 
						||
        <section class="nav-bar clearfix">
 | 
						||
            <figure class="logo">
 | 
						||
                <a href="/">
 | 
						||
                    <img src="/static/logo.svg?v20210804" alt='{{tr "NezhaMonitoring"}}' width="50" height="50">
 | 
						||
                </a>
 | 
						||
                <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="/">{{tr "Home"}}</a></li>
 | 
						||
                    <li><a href="/service">{{tr "Services"}}</a></li>
 | 
						||
                    <li><a href="/network">{{tr "NetworkSpiter"}}</a></li>
 | 
						||
                    {{if .Admin}}
 | 
						||
                    <li><a href="/server">{{tr "AdminPanel"}}</a></li>
 | 
						||
                    {{else}}
 | 
						||
                    <li><a href="/login">{{tr "Login"}}</a></li>
 | 
						||
                    {{end}}
 | 
						||
                </ul>
 | 
						||
            </nav>
 | 
						||
        </section>
 | 
						||
    </header>
 | 
						||
 | 
						||
    <main>
 | 
						||
        <div id="network">
 | 
						||
            <div class="server-info-container" v-for='server in servers' :id="server.ID">
 | 
						||
                <div class="info-body" @click="redirectNetwork(server.ID)">
 | 
						||
                    <ul class="server-info-body-container">
 | 
						||
                        <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>
 | 
						||
                    </ul>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
        <div class="network-chart" style="height: 800px;overflow: hidden">
 | 
						||
            <div id="monitor-info-container" style="height: 520px;max-width: 1400px">
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
        <div class="sidebar-container">
 | 
						||
            <ul>
 | 
						||
                <li><i class="fas fa-sun" title='{{tr "LightMode"}}'></i><span>{{tr "LightMode"}}</span></li>
 | 
						||
                <li><i class="fas fa-moon" title='{{tr "DarkMode"}}'></i><span>{{tr "DarkMode"}}</span></li>
 | 
						||
                <li><i class="fas fa-th" title='{{tr "GridLayout"}}'></i><span>{{tr "GridLayout"}}</span></li>
 | 
						||
                <li><i class="fas fa-list-ul" title='{{tr "ListLayout"}}'></i><span>{{tr "ListLayout"}}</span></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>
 | 
						||
        </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 {{tr "NezhaMonitoring"}} ·
 | 
						||
                    {{.Version}}</a>
 | 
						||
                <p>© <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?v202102012266"></script>
 | 
						||
    <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/vue/2.6.14/vue.min.js"></script>
 | 
						||
    <script
 | 
						||
        src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/limonte-sweetalert2/11.4.4/sweetalert2.all.min.js"></script>
 | 
						||
 | 
						||
    <script>
 | 
						||
        const monitorInfo = JSON.parse('{{.MonitorInfos}}');
 | 
						||
        const initData = JSON.parse('{{.Servers}}').servers;
 | 
						||
        let MaxTCPPingValue = {{.Conf.MaxTCPPingValue}};
 | 
						||
        // 基于准备好的dom,初始化echarts实例
 | 
						||
        const myChart = echarts.init(document.getElementById('monitor-info-container'));
 | 
						||
 | 
						||
        // 使用刚指定的配置项和数据显示图表。
 | 
						||
        var statusCards = new Vue({
 | 
						||
            el: '#network',
 | 
						||
            delimiters: ['@#', '#@'],
 | 
						||
            data: {
 | 
						||
                servers: initData,
 | 
						||
                cache: [],
 | 
						||
                option: {
 | 
						||
                    tooltip: {
 | 
						||
                        trigger: 'axis',
 | 
						||
                        position: function (pt) {
 | 
						||
                            return [pt[0], '10%'];
 | 
						||
                        },
 | 
						||
                        formatter: function (params) {
 | 
						||
                            let result = params[0].axisValueLabel + "<br />";
 | 
						||
                            params.forEach(function (item) {
 | 
						||
                                result += item.marker + item.seriesName + ": " + item.value[1].toFixed(2) + " ms<br />";
 | 
						||
                            })
 | 
						||
                            return result;
 | 
						||
                        },
 | 
						||
                        confine: true,
 | 
						||
                        transitionDuration: 0
 | 
						||
                    },
 | 
						||
                    title: {
 | 
						||
                        left: 'center',
 | 
						||
                        text: "",
 | 
						||
                        textStyle: {}
 | 
						||
                    },
 | 
						||
                    legend: {
 | 
						||
                        top: '5%',
 | 
						||
                        data: [],
 | 
						||
                        textStyle: {
 | 
						||
                            fontSize: 14
 | 
						||
                        }
 | 
						||
                    },
 | 
						||
                    toolbox: {
 | 
						||
                        feature: {
 | 
						||
                            dataZoom: {
 | 
						||
                                yAxisIndex: 'none'
 | 
						||
                            },
 | 
						||
                            restore: {},
 | 
						||
                            saveAsImage: {}
 | 
						||
                        }
 | 
						||
                    },
 | 
						||
                    dataZoom: [
 | 
						||
                        {
 | 
						||
                            start: 94,
 | 
						||
                            end: 100
 | 
						||
                        }
 | 
						||
                    ],
 | 
						||
                    xAxis: {
 | 
						||
                        type: 'time',
 | 
						||
                        boundaryGap: false
 | 
						||
                    },
 | 
						||
                    yAxis: {
 | 
						||
                        type: 'value',
 | 
						||
                        boundaryGap: [0, '100%']
 | 
						||
                    },
 | 
						||
                    series: [],
 | 
						||
                }
 | 
						||
            },
 | 
						||
            mounted() {
 | 
						||
                this.DarkMode();
 | 
						||
                this.parseMonitorInfo(monitorInfo);
 | 
						||
                window.addEventListener('resize', this.resizeHandle);
 | 
						||
            },
 | 
						||
            destroyed() {
 | 
						||
                window.removeEventListener('resize', this.resizeHandle)
 | 
						||
            },
 | 
						||
            methods: {
 | 
						||
                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');
 | 
						||
                        document.getElementById("monitor-info-container").style.backgroundColor = "#1E1E1E";
 | 
						||
                    }
 | 
						||
                },
 | 
						||
                redirectNetwork(id) {
 | 
						||
                    this.getMonitorHistory(id)
 | 
						||
                        .then(function (monitorInfo) {
 | 
						||
                            var vm = network.__vue__;
 | 
						||
                            vm.parseMonitorInfo(monitorInfo);
 | 
						||
                        })
 | 
						||
                        .catch(function (error) {
 | 
						||
                            window.location.href = "/404";
 | 
						||
                        })
 | 
						||
                },
 | 
						||
                getMonitorHistory(id) {
 | 
						||
                    return $.ajax({
 | 
						||
                        url: "/api/v1/monitor/" + id,
 | 
						||
                        method: "GET"
 | 
						||
                    });
 | 
						||
                },
 | 
						||
                parseMonitorInfo(monitorInfo) {
 | 
						||
                    let tSeries = [];
 | 
						||
                    let tLegendData = [];
 | 
						||
                    var lcolors = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
 | 
						||
                    for (let i = 0; i < monitorInfo.result.length; i++) {
 | 
						||
                        var lcolor = lcolors[i % lcolors.length];
 | 
						||
                        var rgbaColorMarker = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.5)';
 | 
						||
                        var rgbaColorBar = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.35)';
 | 
						||
                        let loss = 0;
 | 
						||
                        let data = [];
 | 
						||
                        let datal = [];
 | 
						||
                        for (let j = 0; j < monitorInfo.result[i].created_at.length; j++) {
 | 
						||
                            avgDelay = Math.round(monitorInfo.result[i].avg_delay[j]);
 | 
						||
                            if (avgDelay > 0 && avgDelay < MaxTCPPingValue) {
 | 
						||
                                data.push([monitorInfo.result[i].created_at[j], avgDelay]);
 | 
						||
                            }
 | 
						||
                            else {
 | 
						||
                                loss += 1;
 | 
						||
                                datal.push({
 | 
						||
                                    xAxis: monitorInfo.result[i].created_at[j],
 | 
						||
                                    label: { show: false },
 | 
						||
                                    emphasis: { disabled: true },
 | 
						||
                                    lineStyle: {
 | 
						||
                                        type: "solid",
 | 
						||
                                        color: rgbaColorBar
 | 
						||
                                    }
 | 
						||
                                });
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
                        lossRate = ((loss / monitorInfo.result[i].created_at.length) * 100).toFixed(1);
 | 
						||
                        if (lossRate > 99) {
 | 
						||
                            datal = [];
 | 
						||
                        }
 | 
						||
                        legendName = monitorInfo.result[i].monitor_name + " " + lossRate + "%";
 | 
						||
                        tLegendData.push(legendName);
 | 
						||
                        tSeries.push({
 | 
						||
                            name: legendName,
 | 
						||
                            type: 'line',
 | 
						||
                            smooth: true,
 | 
						||
                            symbol: 'none',
 | 
						||
                            data: data,
 | 
						||
                            markLine: {
 | 
						||
                                symbol: "none",
 | 
						||
                                symbolSize: 0,
 | 
						||
                                data: datal
 | 
						||
                            },
 | 
						||
                            markPoint: {
 | 
						||
                                data: [
 | 
						||
                                    { type: 'max', symbol: 'pin', name: 'Max', itemStyle: { color: rgbaColorMarker }, symbolSize: 30, label: { fontSize: 8 } },
 | 
						||
                                    { type: 'min', symbol: 'pin', name: 'Min', itemStyle: { color: rgbaColorMarker }, symbolSize: 30, label: { fontSize: 8, offset: [0, 7.5] }, symbolRotate: 180 }
 | 
						||
                                ]
 | 
						||
                            }
 | 
						||
                        });
 | 
						||
                    }
 | 
						||
                    this.option.title.text = monitorInfo.result[0].server_name;
 | 
						||
                    this.option.series = tSeries;
 | 
						||
                    this.option.legend.data = tLegendData;
 | 
						||
                    myChart.clear();
 | 
						||
                    myChart.setOption(this.option);
 | 
						||
                },
 | 
						||
                resizeHandle() {
 | 
						||
                    myChart.resize();
 | 
						||
                },
 | 
						||
            }
 | 
						||
        });
 | 
						||
    </script>
 | 
						||
</body>
 | 
						||
<style>
 | 
						||
    #network {
 | 
						||
        width: calc(100vw - 6em);
 | 
						||
        max-width: 1400px;
 | 
						||
        margin: 1em auto;
 | 
						||
    }
 | 
						||
 | 
						||
    #monitor-info-container {
 | 
						||
        margin: 0em auto;
 | 
						||
        align-content: start;
 | 
						||
        background-color: #F1F1F2;
 | 
						||
    }
 | 
						||
 | 
						||
    .server-info-container {
 | 
						||
        font-size: .6em;
 | 
						||
        width: fit-content;
 | 
						||
        display: inline-block;
 | 
						||
    }
 | 
						||
</style>
 | 
						||
 | 
						||
</html>
 | 
						||
{{end}} |