server-status主题重写network页面 (#407)
* 修复浏览器高分辨率下网络页echart图表显示不全 * server-status主题重写network页面 1. 点击“网络监控”弹出选择服务器 2. 增加服务器搜索筛选功能 3. 自适应lenged高度 4. 适配深色模式与浅色模式 5. 适配半透明模式 6. 适配pc段与移动端 * 刷新cdn缓存 * 增加disposeCharts逻辑 * 增加disposeCharts逻辑 * 标题增加服务器所在地区国旗展示 * 国旗样式修复 * 修复国旗样式 * echart图标高度适配不同分辨率浏览器
This commit is contained in:
		
							parent
							
								
									d9097540c3
								
							
						
					
					
						commit
						c18e0e420e
					
				
							
								
								
									
										3
									
								
								resource/l10n/en-US.toml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								resource/l10n/en-US.toml
									
									
									
									
										vendored
									
									
								
							@ -651,3 +651,6 @@ other = "Servers On World Map"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[NAT]
 | 
					[NAT]
 | 
				
			||||||
other = "NAT"
 | 
					other = "NAT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[NetworkSpiterList]
 | 
				
			||||||
 | 
					other = "Network Monitor"
 | 
				
			||||||
							
								
								
									
										3
									
								
								resource/l10n/es-ES.toml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								resource/l10n/es-ES.toml
									
									
									
									
										vendored
									
									
								
							@ -651,3 +651,6 @@ other = "Servidores en el mapa mundial"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[NAT]
 | 
					[NAT]
 | 
				
			||||||
other = "NAT"
 | 
					other = "NAT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[NetworkSpiterList]
 | 
				
			||||||
 | 
					other = "Red Monitor"
 | 
				
			||||||
							
								
								
									
										3
									
								
								resource/l10n/zh-CN.toml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								resource/l10n/zh-CN.toml
									
									
									
									
										vendored
									
									
								
							@ -651,3 +651,6 @@ other = "服务器世界分布图"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[NAT]
 | 
					[NAT]
 | 
				
			||||||
other = "内网穿透"
 | 
					other = "内网穿透"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[NetworkSpiterList]
 | 
				
			||||||
 | 
					other = "网络监控"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										3
									
								
								resource/l10n/zh-TW.toml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								resource/l10n/zh-TW.toml
									
									
									
									
										vendored
									
									
								
							@ -651,3 +651,6 @@ other = "伺服器世界分布圖"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[NAT]
 | 
					[NAT]
 | 
				
			||||||
other = "NAT"
 | 
					other = "NAT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[NetworkSpiterList]
 | 
				
			||||||
 | 
					other = "網絡監控"
 | 
				
			||||||
@ -172,3 +172,7 @@ body[theme="dark"] .toolbox i{
 | 
				
			|||||||
    color: rgba(241, 241, 241, 1);
 | 
					    color: rgba(241, 241, 241, 1);
 | 
				
			||||||
    background-color: rgba(0, 0, 0, 0.5);
 | 
					    background-color: rgba(0, 0, 0, 0.5);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					body[theme="dark"] .network-box .network-box-header{
 | 
				
			||||||
 | 
					    border-bottom: 1px solid rgba(110, 112, 121, 0.25);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -197,6 +197,10 @@ body[theme="light"] .modal-header i.xclose{
 | 
				
			|||||||
    color: rgba(0, 0, 0, 0.87);
 | 
					    color: rgba(0, 0, 0, 0.87);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					body[theme="light"] .network-box .network-box-header{
 | 
				
			||||||
 | 
					    border-bottom: 1px solid rgba(224, 230, 241, 0.6);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@media only screen and (max-width: 767px) {
 | 
					@media only screen and (max-width: 767px) {
 | 
				
			||||||
    body[theme="light"] .navbar .navbar-nav .open .dropdown-menu {
 | 
					    body[theme="light"] .navbar .navbar-nav .open .dropdown-menu {
 | 
				
			||||||
        background-color: rgba(249, 249, 249, 1);
 | 
					        background-color: rgba(249, 249, 249, 1);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										90
									
								
								resource/static/theme-server-status/css/main.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										90
									
								
								resource/static/theme-server-status/css/main.css
									
									
									
									
										vendored
									
									
								
							@ -317,6 +317,78 @@ td.ping-network-quality {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
/* 服务页 正文结束 */
 | 
					/* 服务页 正文结束 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 网络页 正文*/
 | 
				
			||||||
 | 
					.network-box .btn-group.open .dropdown-toggle{
 | 
				
			||||||
 | 
					    box-shadow:unset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.network-box .network-box-header{
 | 
				
			||||||
 | 
					    font-size: 18px;
 | 
				
			||||||
 | 
					    padding: 5px 0px 15px 5px;
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.network-box .network-box-header .dropdown-menu {
 | 
				
			||||||
 | 
					    max-height: 22.5em;
 | 
				
			||||||
 | 
					    overflow-y: auto;
 | 
				
			||||||
 | 
					    z-index:99999998;
 | 
				
			||||||
 | 
					    min-width: 200px;
 | 
				
			||||||
 | 
					    padding: 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.network-box .network-box-header .dropdown-menu::-webkit-scrollbar {
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.network-box .network-box-header .dropdown-menu li{
 | 
				
			||||||
 | 
					    height: 2em;
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.network-box .network-box-header .dropdown-menu li.input-group{
 | 
				
			||||||
 | 
					    margin: 0 auto;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    position: sticky;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    z-index: 99999997;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.network-box .network-box-header .dropdown-menu li.input-group input{
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    height: 2em;
 | 
				
			||||||
 | 
					    border-top: none;
 | 
				
			||||||
 | 
					    border-left: none;
 | 
				
			||||||
 | 
					    border-right: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.network-box .network-box-header .dropdown-menu li a {
 | 
				
			||||||
 | 
					    padding: 5px 5px 5px 15px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.network-box .network-box-header .dropdown-menu li.hidden {
 | 
				
			||||||
 | 
					    height: 0;
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					    visibility:hidden;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.network-box .network-box-header .dropdown-menu li.visible {
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.network-box .chartTitle {
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    font-size: 18px;
 | 
				
			||||||
 | 
					    margin: 18px 0px 15px 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.network-box .chartTitle i.chartCountryCode{
 | 
				
			||||||
 | 
					    font-size: 16px;
 | 
				
			||||||
 | 
					    border-radius: 12.5%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 网络页 正文结束 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 地图版服务器分布图 */
 | 
					/* 地图版服务器分布图 */
 | 
				
			||||||
#mapChartBox{
 | 
					#mapChartBox{
 | 
				
			||||||
    z-index: 999999999;
 | 
					    z-index: 999999999;
 | 
				
			||||||
@ -393,6 +465,12 @@ footer p{
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 彩虹旗 */
 | 
				
			||||||
 | 
					.fi-rb {
 | 
				
			||||||
 | 
					    background-image: url(/static/theme-server-status/img/rb.png);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@media only screen and (max-width: 767px) {
 | 
					@media only screen and (max-width: 767px) {
 | 
				
			||||||
    body {
 | 
					    body {
 | 
				
			||||||
        font-size: 10px !important;
 | 
					        font-size: 10px !important;
 | 
				
			||||||
@ -482,6 +560,18 @@ footer p{
 | 
				
			|||||||
    td.ping-network-quality {
 | 
					    td.ping-network-quality {
 | 
				
			||||||
        width: 110px;
 | 
					        width: 110px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    .network-box .network-box-header {
 | 
				
			||||||
 | 
					        margin: 8px 0px 0px 8px;
 | 
				
			||||||
 | 
					        font-size: 16px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .network-box .chartTitle {
 | 
				
			||||||
 | 
					        font-size: 16px;
 | 
				
			||||||
 | 
					        margin: 10px 0px 10px 0px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .network-box .chartTitle i.chartCountryCode{
 | 
				
			||||||
 | 
					        font-size: 15px;
 | 
				
			||||||
 | 
					        border-radius: 12.5%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@media only screen and (min-width: 768px) {
 | 
					@media only screen and (min-width: 768px) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								resource/static/theme-server-status/img/rb.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								resource/static/theme-server-status/img/rb.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 5.8 KiB  | 
							
								
								
									
										10
									
								
								resource/static/theme-server-status/js/mixin.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								resource/static/theme-server-status/js/mixin.js
									
									
									
									
										vendored
									
									
								
							@ -14,7 +14,10 @@ const mixinsVue = {
 | 
				
			|||||||
            { key: 'default', name: 'Default', icon: 'th large' },
 | 
					            { key: 'default', name: 'Default', icon: 'th large' },
 | 
				
			||||||
            { key: 'angel-kanade', name: 'AngelKanade', icon: 'square' },
 | 
					            { key: 'angel-kanade', name: 'AngelKanade', icon: 'square' },
 | 
				
			||||||
            { key: 'server-status', name: 'ServerStatus', icon: 'list' }
 | 
					            { key: 'server-status', name: 'ServerStatus', icon: 'list' }
 | 
				
			||||||
        ]
 | 
					        ],
 | 
				
			||||||
 | 
					        colors: [],
 | 
				
			||||||
 | 
					        colorsDark: ['#4992FF', '#08C091', '#FDDD5F', '#FF6E76', '#58D9F9', '#7CFFB2', '#FF8A44', '#8D48E3', '#DD79FF', '#5470C6', '#3BA272', '#FAC758', '#EE6666', '#72C0DE', '#91CC76', '#FB8352', '#9A60B4', '#EA7BCC'],
 | 
				
			||||||
 | 
					        colorsLight: ['#5470C6', '#3BA272', '#FAC758', '#EE6666', '#72C0DE', '#91CC76', '#FB8352', '#9A60B4', '#EA7BCC', '#4992FF', '#08C091', '#FDDD5F', '#FF6E76', '#58D9F9', '#7CFFB2', '#FF8A44', '#8D48E3', '#DD79FF'],
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    created() {
 | 
					    created() {
 | 
				
			||||||
        this.isMobile = this.checkIsMobile();
 | 
					        this.isMobile = this.checkIsMobile();
 | 
				
			||||||
@ -22,6 +25,7 @@ const mixinsVue = {
 | 
				
			|||||||
        this.showGroup = this.initShowGroup();
 | 
					        this.showGroup = this.initShowGroup();
 | 
				
			||||||
        this.semiTransparent = this.initSemiTransparent();
 | 
					        this.semiTransparent = this.initSemiTransparent();
 | 
				
			||||||
        this.preferredTemplate = this.getCookie('preferred_theme') ? this.getCookie('preferred_theme') : this.$root.defaultTemplate;
 | 
					        this.preferredTemplate = this.getCookie('preferred_theme') ? this.getCookie('preferred_theme') : this.$root.defaultTemplate;
 | 
				
			||||||
 | 
					        this.colors = this.theme == "dark" ? this.colorsDark : this.colorsLight;
 | 
				
			||||||
        window.addEventListener('scroll', this.handleScroll);
 | 
					        window.addEventListener('scroll', this.handleScroll);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    destroyed() {
 | 
					    destroyed() {
 | 
				
			||||||
@ -51,7 +55,7 @@ const mixinsVue = {
 | 
				
			|||||||
            // 重新赋值全局调色
 | 
					            // 重新赋值全局调色
 | 
				
			||||||
            this.colors = this.theme == "dark" ? this.colorsDark : this.colorsLight;
 | 
					            this.colors = this.theme == "dark" ? this.colorsDark : this.colorsLight;
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            if(this.$root.page == 'index') {
 | 
					            if(this.$root.page == 'index' || this.$root.page == 'network') {
 | 
				
			||||||
                this.reloadCharts(); // 重新载入echarts图表
 | 
					                this.reloadCharts(); // 重新载入echarts图表
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@ -81,7 +85,7 @@ const mixinsVue = {
 | 
				
			|||||||
        toggleSemiTransparent(){
 | 
					        toggleSemiTransparent(){
 | 
				
			||||||
            this.semiTransparent = !this.semiTransparent;
 | 
					            this.semiTransparent = !this.semiTransparent;
 | 
				
			||||||
            localStorage.setItem("semiTransparent", this.semiTransparent);
 | 
					            localStorage.setItem("semiTransparent", this.semiTransparent);
 | 
				
			||||||
            if(this.$root.page == 'index') {
 | 
					            if(this.$root.page == 'index' || this.$root.page == 'network') {
 | 
				
			||||||
                this.reloadCharts(); // 重新载入echarts图表
 | 
					                this.reloadCharts(); // 重新载入echarts图表
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
				
			|||||||
@ -16,10 +16,10 @@
 | 
				
			|||||||
    <script src="https://unpkg.com/bootstrap@3.4.1/dist/js/bootstrap.min.js"></script>
 | 
					    <script src="https://unpkg.com/bootstrap@3.4.1/dist/js/bootstrap.min.js"></script>
 | 
				
			||||||
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
 | 
					    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
 | 
				
			||||||
    <script src="https://unpkg.com/echarts@5.5.0/dist/echarts.min.js"></script>
 | 
					    <script src="https://unpkg.com/echarts@5.5.0/dist/echarts.min.js"></script>
 | 
				
			||||||
    <link rel="stylesheet" href="/static/theme-server-status/css/main.css?v20240807">
 | 
					    <link rel="stylesheet" href="/static/theme-server-status/css/main.css?v202408011">
 | 
				
			||||||
    <link rel="stylesheet" href="/static/theme-server-status/css/dark.css?v20240807">
 | 
					    <link rel="stylesheet" href="/static/theme-server-status/css/dark.css?v202408011">
 | 
				
			||||||
    <link rel="stylesheet" href="/static/theme-server-status/css/light.css?v20240807">
 | 
					    <link rel="stylesheet" href="/static/theme-server-status/css/light.css?v20240811">
 | 
				
			||||||
    <script src="/static/theme-server-status/js/mixin.js?v20240807"></script>
 | 
					    <script src="/static/theme-server-status/js/mixin.js?v20240811"></script>
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
<div id="app">
 | 
					<div id="app">
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										28
									
								
								resource/template/theme-server-status/home.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								resource/template/theme-server-status/home.html
									
									
									
									
										vendored
									
									
								
							@ -155,14 +155,13 @@
 | 
				
			|||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                const unit = this.language=='zh-CN' ? '台' : 'servers';
 | 
					                const unit = this.language=='zh-CN' ? '台' : 'servers';
 | 
				
			||||||
                const isMobile = this.checkIsMobile();
 | 
					 | 
				
			||||||
                const width = window.innerWidth;
 | 
					                const width = window.innerWidth;
 | 
				
			||||||
                const height = 0.95 * window.innerHeight;
 | 
					                const height = 0.95 * window.innerHeight;
 | 
				
			||||||
                const backgroundColor = this.theme == "dark" ? '' : '';
 | 
					                const backgroundColor = this.theme == "dark" ? '' : '';
 | 
				
			||||||
                const inRangeColor = this.theme == "dark" ? '#D2B206' : '#FFDF32';
 | 
					                const inRangeColor = this.theme == "dark" ? '#D2B206' : '#FFDF32';
 | 
				
			||||||
                const tooltipBackgroundColor = this.theme == "dark" ? "#ffffff" : '#ffffff';
 | 
					                const tooltipBackgroundColor = this.theme == "dark" ? "#ffffff" : '#ffffff';
 | 
				
			||||||
                const tooltipBorderColor = this.theme == "dark" ? "#ffffff" : "#ffffff"; 
 | 
					                const tooltipBorderColor = this.theme == "dark" ? "#ffffff" : "#ffffff"; 
 | 
				
			||||||
                const fontSize = isMobile ? 10 : 12;
 | 
					                const fontSize = this.isMobile ? 10 : 12;
 | 
				
			||||||
                const fontColor = this.theme == "dark" ? "#000000" : "#000000";     
 | 
					                const fontColor = this.theme == "dark" ? "#000000" : "#000000";     
 | 
				
			||||||
                const chartContainer = document.getElementById('mapChart');
 | 
					                const chartContainer = document.getElementById('mapChart');
 | 
				
			||||||
                const mapChart = echarts.init(chartContainer, '', { // init图表
 | 
					                const mapChart = echarts.init(chartContainer, '', { // init图表
 | 
				
			||||||
@ -510,13 +509,12 @@
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                // 定义图表参数值
 | 
					                // 定义图表参数值
 | 
				
			||||||
                const MaxTCPPingValue = {{.Conf.MaxTCPPingValue}} ? {{.Conf.MaxTCPPingValue}} : 300;
 | 
					                const MaxTCPPingValue = {{.Conf.MaxTCPPingValue}} ? {{.Conf.MaxTCPPingValue}} : 300;
 | 
				
			||||||
                const isMobile = this.checkIsMobile();
 | 
					                const fontSize = this.isMobile ? 10 : 14;
 | 
				
			||||||
                const fontSize = isMobile ? 10 : 14;
 | 
					                const gridLeft = this.isMobile ? 25 : 36;
 | 
				
			||||||
                const gridLeft = isMobile ? 25 : 36;
 | 
					                const gridRight = this.isMobile ? 5 : 20;
 | 
				
			||||||
                const gridRight = isMobile ? 5 : 20;
 | 
					                const legendLeft = this.isMobile ? 'center' : 'center';
 | 
				
			||||||
                const legendLeft = isMobile ? 'center' : 'center';
 | 
					                const legendTop = this.isMobile ? 5 : 5;
 | 
				
			||||||
                const legendTop = isMobile ? 5 : 5;
 | 
					                const legendPadding= this.isMobile ? [5,0,5,0] : [5,0,5,0];
 | 
				
			||||||
                const legendPadding= isMobile ? [5,0,5,0] : [5,0,5,0];
 | 
					 | 
				
			||||||
                const systemDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
 | 
					                const systemDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
 | 
				
			||||||
                const theme = localStorage.getItem("theme") ? localStorage.getItem("theme") : systemDarkMode;
 | 
					                const theme = localStorage.getItem("theme") ? localStorage.getItem("theme") : systemDarkMode;
 | 
				
			||||||
                const chartTheme = theme == "dark" ? "dark" : "default";
 | 
					                const chartTheme = theme == "dark" ? "dark" : "default";
 | 
				
			||||||
@ -524,8 +522,8 @@
 | 
				
			|||||||
                const backgroundColor = theme == "dark" ? '' : '';
 | 
					                const backgroundColor = theme == "dark" ? '' : '';
 | 
				
			||||||
                const tooltipBackgroundColor = this.theme == "dark" ? (this.semiTransparent ? "rgba(28,29,38,0.85)" : "rgba(28,29,38,1)") : (this.semiTransparent ? "rgba(255,255,255,0.85)" : "rgba(255,255,255,1)");
 | 
					                const tooltipBackgroundColor = this.theme == "dark" ? (this.semiTransparent ? "rgba(28,29,38,0.85)" : "rgba(28,29,38,1)") : (this.semiTransparent ? "rgba(255,255,255,0.85)" : "rgba(255,255,255,1)");
 | 
				
			||||||
                const tooltipBorderColor = this.theme == "dark" ? (this.semiTransparent ? "rgba(28,29,38,0.9)" : "rgba(28,29,38,1)") : (this.semiTransparent ? "rgba(255,255,255,0.9)" : "rgba(255,255,255,1)");
 | 
					                const tooltipBorderColor = this.theme == "dark" ? (this.semiTransparent ? "rgba(28,29,38,0.9)" : "rgba(28,29,38,1)") : (this.semiTransparent ? "rgba(255,255,255,0.9)" : "rgba(255,255,255,1)");
 | 
				
			||||||
                const lineStyleWidth = isMobile ? 1 : 2;
 | 
					                const lineStyleWidth = this.isMobile ? 1 : 2;
 | 
				
			||||||
                const splitLineWidth = isMobile ? 0.5 : 1;
 | 
					                const splitLineWidth = this.isMobile ? 0.5 : 1;
 | 
				
			||||||
                // 渲染图表
 | 
					                // 渲染图表
 | 
				
			||||||
                const chart = echarts.init(chartContainer, chartTheme, {
 | 
					                const chart = echarts.init(chartContainer, chartTheme, {
 | 
				
			||||||
                    renderer: 'canvas',
 | 
					                    renderer: 'canvas',
 | 
				
			||||||
@ -562,12 +560,12 @@
 | 
				
			|||||||
                const legendData = chartData.map(item => item.monitor_name);
 | 
					                const legendData = chartData.map(item => item.monitor_name);
 | 
				
			||||||
                const maxLegendsPerRowMobile = localStorage.getItem("maxLegendsPerRowMobile") ? localStorage.getItem("maxLegendsPerRowMobile") : 3;
 | 
					                const maxLegendsPerRowMobile = localStorage.getItem("maxLegendsPerRowMobile") ? localStorage.getItem("maxLegendsPerRowMobile") : 3;
 | 
				
			||||||
                const maxLegendsPerRowPc = localStorage.getItem("maxLegendsPerRowPc") ? localStorage.getItem("maxLegendsPerRowPc") : 6;
 | 
					                const maxLegendsPerRowPc = localStorage.getItem("maxLegendsPerRowPc") ? localStorage.getItem("maxLegendsPerRowPc") : 6;
 | 
				
			||||||
                const autoIncrement = Math.floor((legendData.length - 1) / (isMobile ? maxLegendsPerRowMobile : maxLegendsPerRowPc)) * (isMobile ? 20 : 28)
 | 
					                const autoIncrement = Math.floor((legendData.length - 1) / (this.isMobile ? maxLegendsPerRowMobile : maxLegendsPerRowPc)) * (this.isMobile ? 20 : 28)
 | 
				
			||||||
                const height = 300 + autoIncrement;
 | 
					                const height = 300 + autoIncrement;
 | 
				
			||||||
                const gridTop = 40 + autoIncrement;
 | 
					                const gridTop = 40 + autoIncrement;
 | 
				
			||||||
                const legendIcon = isMobile ? 'rect' : ""; 
 | 
					                const legendIcon = this.isMobile ? 'rect' : ""; 
 | 
				
			||||||
                const itemWidth = isMobile ? 10 : 25;
 | 
					                const itemWidth = this.isMobile ? 10 : 25;
 | 
				
			||||||
                const itemHeight = isMobile ? 10 : 14;
 | 
					                const itemHeight = this.isMobile ? 10 : 14;
 | 
				
			||||||
                chart.resize({
 | 
					                chart.resize({
 | 
				
			||||||
                    width: 'auto',
 | 
					                    width: 'auto',
 | 
				
			||||||
                    height: height
 | 
					                    height: height
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										515
									
								
								resource/template/theme-server-status/network.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										515
									
								
								resource/template/theme-server-status/network.html
									
									
									
									
										vendored
									
									
								
							@ -1,239 +1,362 @@
 | 
				
			|||||||
{{define "theme-server-status/network"}}
 | 
					{{define "theme-server-status/network"}}
 | 
				
			||||||
{{template "theme-server-status/header" .}}
 | 
					{{template "theme-server-status/header" .}}
 | 
				
			||||||
{{template "theme-server-status/menu" .}}
 | 
					{{template "theme-server-status/menu" .}}
 | 
				
			||||||
<div class="container-fluid table-responsive content">
 | 
					<div class="container-fluid content network-box">
 | 
				
			||||||
    <table class="table table-striped table-condensed table-hover">
 | 
					    <div class="network-box-header btn-group">
 | 
				
			||||||
        <button class="ui nezha-primary-btn button"
 | 
					        <div class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
 | 
				
			||||||
                v-for="server in servers"
 | 
					            <i class="bi bi-list-ul"></i> {{tr "NetworkSpiterList"}} <i class="bi bi-chevron-compact-down"></i>
 | 
				
			||||||
                style="margin-top: 3px"
 | 
					        </div>
 | 
				
			||||||
                @click="redirectNetwork(server.ID)">
 | 
					        <ul class="dropdown-menu">
 | 
				
			||||||
            @#server.Name#@  <i :class="'fi fi-' + server.Host.CountryCode"></i><span class="node-cell-location-text text-uppercase">  @#server.Host.CountryCode#@</span>
 | 
					            <li class="input-group fixed-top">
 | 
				
			||||||
        </button>
 | 
					                <input type="text" id="dropdown-search" class="form-control" placeholder="Search...">
 | 
				
			||||||
    </table>
 | 
					            </li>
 | 
				
			||||||
</div>
 | 
					            <li class="dropdown-item" v-for="server in servers" @click="showCharts(server.ID)">
 | 
				
			||||||
<div class="container-fluid table-responsive content">
 | 
					                <a><i :class="'fi fi-' + (server.Host.CountryCode || 'rb')"></i> @#server.Name#@ <i v-if="server.ID == currentServerId" class="check icon"></i></a>
 | 
				
			||||||
    <div ref="chartDom" style="border-radius: 28px; margin-top: 15px;height: 520px;max-width: 1400px;overflow: hidden"></div>
 | 
					            </li>          
 | 
				
			||||||
 | 
					        </ul>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div class="chartTitle"><i class="chartCountryCode" :class="'fi fi-' + chartCountryCode"></i> @#chartTitle#@</div>
 | 
				
			||||||
 | 
					    <div id="chartbox" style="width:100%;height:auto;"></div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
{{template "theme-server-status/footer" .}}
 | 
					{{template "theme-server-status/footer" .}}
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
    const monitorInfo =  JSON.parse('{{.MonitorInfos}}');
 | 
					 | 
				
			||||||
    const initData = JSON.parse('{{.Servers}}').servers;
 | 
					 | 
				
			||||||
    let MaxTCPPingValue = {{.Conf.MaxTCPPingValue}};
 | 
					 | 
				
			||||||
    new Vue({
 | 
					    new Vue({
 | 
				
			||||||
        el: '#app',
 | 
					        el: '#app',
 | 
				
			||||||
        delimiters: ['@#', '#@'],
 | 
					        delimiters: ['@#', '#@'],
 | 
				
			||||||
        data: {
 | 
					        data: {
 | 
				
			||||||
            page: 'network',
 | 
					            page: 'network',
 | 
				
			||||||
            defaultTemplate: {{.Conf.Site.Theme}},
 | 
					            defaultTemplate: "{{.Conf.Site.Theme}}",
 | 
				
			||||||
            templates: {{.Themes}},
 | 
					            templates: "{{.Themes }}",
 | 
				
			||||||
            servers: initData,
 | 
					            servers: [],
 | 
				
			||||||
            option: {
 | 
					            chartDataList: [],
 | 
				
			||||||
                tooltip: {
 | 
					            chartTitle: '',
 | 
				
			||||||
                    trigger: 'axis',
 | 
					            chartCountryCode: '',
 | 
				
			||||||
                    position: function (pt) {
 | 
					            chart: null,
 | 
				
			||||||
                        return [pt[0], '10%'];
 | 
					            currentServerId: ''
 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    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
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                backgroundColor: 'rgba(255, 255, 255, 0.8)',
 | 
					 | 
				
			||||||
                toolbox: {
 | 
					 | 
				
			||||||
                    feature: {
 | 
					 | 
				
			||||||
                        dataZoom: {
 | 
					 | 
				
			||||||
                            yAxisIndex: 'none'
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        restore: {},
 | 
					 | 
				
			||||||
                        saveAsImage: {}
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                dataZoom: [
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        start: 0,
 | 
					 | 
				
			||||||
                        end: 100
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                ],
 | 
					 | 
				
			||||||
                xAxis: {
 | 
					 | 
				
			||||||
                    type: 'time',
 | 
					 | 
				
			||||||
                    boundaryGap: false
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                yAxis: {
 | 
					 | 
				
			||||||
                    type: 'value',
 | 
					 | 
				
			||||||
                    boundaryGap: false
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                series: [],
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            chartOnOff: true,
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        mixins: [mixinsVue],
 | 
					        mixins: [mixinsVue],
 | 
				
			||||||
 | 
					        created() {
 | 
				
			||||||
 | 
					            this.servers = JSON.parse('{{.Servers}}').servers;
 | 
				
			||||||
 | 
					            this.showCharts(this.servers[0].ID);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        mounted() {
 | 
					        mounted() {
 | 
				
			||||||
            this.renderChart();
 | 
					            this.initSearch();            
 | 
				
			||||||
            this.parseMonitorInfo(monitorInfo);
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        methods: {
 | 
					        methods: {
 | 
				
			||||||
            getFontLogoClass(str) {
 | 
					            showCharts(id) {
 | 
				
			||||||
                if (["almalinux",
 | 
					                const chartContainer = document.getElementById('chartbox');
 | 
				
			||||||
                        "alpine",
 | 
					                // 发起数据请求
 | 
				
			||||||
                        "aosc",
 | 
					                const url = `/api/v1/monitor/${id}`;
 | 
				
			||||||
                        "apple",
 | 
					                fetch(url)
 | 
				
			||||||
                        "archlinux",
 | 
					                    .then(response => response.json())
 | 
				
			||||||
                        "archlabs",
 | 
					                    .then(data => {
 | 
				
			||||||
                        "artix",
 | 
					                        if (data.result) { // 数据请求成功,更新数据并渲染图表
 | 
				
			||||||
                        "budgie",
 | 
					                            this.chartDataList[id] = data.result;
 | 
				
			||||||
                        "centos",
 | 
					                            this.$nextTick(() => {
 | 
				
			||||||
                        "coreos",
 | 
					                                this.renderCharts(id);
 | 
				
			||||||
                        "debian",
 | 
					                            });
 | 
				
			||||||
                        "deepin",
 | 
					                        } else {
 | 
				
			||||||
                        "devuan",
 | 
					                            console.log('this server (id:'+ id + ') has no monitor.');
 | 
				
			||||||
                        "docker",
 | 
					 | 
				
			||||||
                        "elementary",
 | 
					 | 
				
			||||||
                        "fedora",
 | 
					 | 
				
			||||||
                        "ferris",
 | 
					 | 
				
			||||||
                        "flathub",
 | 
					 | 
				
			||||||
                        "freebsd",
 | 
					 | 
				
			||||||
                        "gentoo",
 | 
					 | 
				
			||||||
                        "gnu-guix",
 | 
					 | 
				
			||||||
                        "illumos",
 | 
					 | 
				
			||||||
                        "kali-linux",
 | 
					 | 
				
			||||||
                        "linuxmint",
 | 
					 | 
				
			||||||
                        "mageia",
 | 
					 | 
				
			||||||
                        "mandriva",
 | 
					 | 
				
			||||||
                        "manjaro",
 | 
					 | 
				
			||||||
                        "nixos",
 | 
					 | 
				
			||||||
                        "openbsd",
 | 
					 | 
				
			||||||
                        "opensuse",
 | 
					 | 
				
			||||||
                        "pop-os",
 | 
					 | 
				
			||||||
                        "raspberry-pi",
 | 
					 | 
				
			||||||
                        "redhat",
 | 
					 | 
				
			||||||
                        "rocky-linux",
 | 
					 | 
				
			||||||
                        "sabayon",
 | 
					 | 
				
			||||||
                        "slackware",
 | 
					 | 
				
			||||||
                        "snappy",
 | 
					 | 
				
			||||||
                        "solus",
 | 
					 | 
				
			||||||
                        "tux",
 | 
					 | 
				
			||||||
                        "ubuntu",
 | 
					 | 
				
			||||||
                        "void",
 | 
					 | 
				
			||||||
                        "zorin"].indexOf(str)
 | 
					 | 
				
			||||||
                    > -1) {
 | 
					 | 
				
			||||||
                    return str;
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                if (['openwrt', 'linux', "immortalwrt"].indexOf(str) > -1) {
 | 
					 | 
				
			||||||
                    return 'tux';
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (str == 'amazon') {
 | 
					 | 
				
			||||||
                    return 'redhat';
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (str == 'arch') {
 | 
					 | 
				
			||||||
                    return 'archlinux';
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return '';
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            redirectNetwork(id) {
 | 
					 | 
				
			||||||
                this.getMonitorHistory(id)
 | 
					 | 
				
			||||||
                .then(function(monitorInfo) {
 | 
					 | 
				
			||||||
                      var vm = app.__vue__;
 | 
					 | 
				
			||||||
                      vm.parseMonitorInfo(monitorInfo);
 | 
					 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
                .catch(function(error){
 | 
					                    .catch(error => {
 | 
				
			||||||
                    window.location.href = "/404";
 | 
					                        console.error('Error fetching data:', error);
 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            getMonitorHistory(id) {
 | 
					 | 
				
			||||||
                  return $.ajax({
 | 
					 | 
				
			||||||
                    url: "/api/v1/monitor/"+id,
 | 
					 | 
				
			||||||
                    method: "GET"
 | 
					 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            parseMonitorInfo(monitorInfo) {
 | 
					            renderCharts(id, reload = false) {
 | 
				
			||||||
                let tSeries = [];
 | 
					                if (!this.chartDataList[id]) return;  
 | 
				
			||||||
                let tLegendData = [];
 | 
					                this.disposeCharts();
 | 
				
			||||||
                var lcolors = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
 | 
					                this.currentServerId = id;
 | 
				
			||||||
                for (let i = 0; i < monitorInfo.result.length; i++) {
 | 
					                this.chartCountryCode = this.getServerCountryCode(id);
 | 
				
			||||||
                    var lcolor = lcolors[i % lcolors.length];
 | 
					                const chartData = this.chartDataList[id];
 | 
				
			||||||
                    var rgbaColorMarker = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.5)';
 | 
					                const chartContainer = document.getElementById('chartbox');
 | 
				
			||||||
                    var rgbaColorBar = 'rgba(' + parseInt(lcolor.slice(1, 3), 16) + ',' + parseInt(lcolor.slice(3, 5), 16) + ',' + parseInt(lcolor.slice(5, 7), 16) + ',0.35)';
 | 
					                this.chartTitle = chartData[0].server_name;
 | 
				
			||||||
                    let loss = 0;
 | 
					                if (reload) {
 | 
				
			||||||
                    let data = [];
 | 
					                    const existingChart = echarts.getInstanceByDom(chartContainer);
 | 
				
			||||||
                    let datal = [];
 | 
					                    if (existingChart) existingChart.dispose();
 | 
				
			||||||
                    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 {
 | 
					                // 定义图表参数值
 | 
				
			||||||
 | 
					                const MaxTCPPingValue = {{.Conf.MaxTCPPingValue}} ? {{.Conf.MaxTCPPingValue}} : 300;
 | 
				
			||||||
 | 
					                const autoheight = this.isMobile ? (window.innerHeight - 200) : (window.innerHeight - 250);
 | 
				
			||||||
 | 
					                const fontSize = this.isMobile ? 10 : 14;
 | 
				
			||||||
 | 
					                const gridLeft = this.isMobile ? 30 : 36;
 | 
				
			||||||
 | 
					                const gridRight = this.isMobile ? 12 : 20;
 | 
				
			||||||
 | 
					                const legendLeft = this.isMobile ? 'center' : 'center';
 | 
				
			||||||
 | 
					                const legendTop = this.isMobile ? 5 : 5;
 | 
				
			||||||
 | 
					                const legendPadding= this.isMobile ? [5,0,5,0] : [5,0,5,0];
 | 
				
			||||||
 | 
					                const fontColor = this.theme == "dark" ? "#f1f1f1" : "#000000";
 | 
				
			||||||
 | 
					                const backgroundColor = this.theme == "dark" ? '' : '';
 | 
				
			||||||
 | 
					                const tooltipBackgroundColor = this.theme == "dark" ? (this.semiTransparent ? "rgba(28,29,38,0.85)" : "rgba(28,29,38,1)") : (this.semiTransparent ? "rgba(255,255,255,0.85)" : "rgba(255,255,255,1)");
 | 
				
			||||||
 | 
					                const tooltipBorderColor = this.theme == "dark" ? (this.semiTransparent ? "rgba(28,29,38,0.9)" : "rgba(28,29,38,1)") : (this.semiTransparent ? "rgba(255,255,255,0.9)" : "rgba(255,255,255,1)");
 | 
				
			||||||
 | 
					                const lineStyleWidth = this.isMobile ? 1 : 2;
 | 
				
			||||||
 | 
					                const splitLineWidth = this.isMobile ? 0.5 : 1;
 | 
				
			||||||
 | 
					                const splitLineColor = this.theme == "dark" ? "rgba(110, 112, 121, 0.95)" : "rgba(224, 230, 241, 0.95)";
 | 
				
			||||||
 | 
					                const markPointLabelColor = this.theme == "dark" ? "#111111" : "#000000";
 | 
				
			||||||
 | 
					                const markPointItemStyleOpacity = this.semiTransparent ? 1 : 0.75;
 | 
				
			||||||
 | 
					                const markLineItemStyleOpacity = this.semiTransparent ? 1 : 0.75;
 | 
				
			||||||
 | 
					                const markLineLineStyleWidth = this.isMobile ? 0.15 : 0.3;
 | 
				
			||||||
 | 
					                this.chart = echarts.init(chartContainer, '', { // init图表
 | 
				
			||||||
 | 
					                    renderer: 'canvas',
 | 
				
			||||||
 | 
					                    useDirtyRect: false,
 | 
				
			||||||
 | 
					                    width: 'auto',
 | 
				
			||||||
 | 
					                    height: autoheight,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                // 获取图表数据
 | 
				
			||||||
 | 
					                let legendData = [];
 | 
				
			||||||
 | 
					                let seriesData = [];
 | 
				
			||||||
 | 
					                chartData.forEach((item,key)=> {
 | 
				
			||||||
 | 
					                    let loss = 0;
 | 
				
			||||||
 | 
					                    let totalLossRate = 0;
 | 
				
			||||||
 | 
					                    let legendName = '';
 | 
				
			||||||
 | 
					                    let data = { main: [], markLine: []};
 | 
				
			||||||
 | 
					                    item.avg_delay.forEach((avgDelay, index) => {
 | 
				
			||||||
 | 
					                        const threshold = 0.9 * MaxTCPPingValue; // 定义阀值,用于判断是否丢包
 | 
				
			||||||
 | 
					                        const filterAvgDelay = item.avg_delay.filter(value => value !== 0 && value !== MaxTCPPingValue);
 | 
				
			||||||
 | 
					                        const max = Math.max(...filterAvgDelay).toFixed(1);
 | 
				
			||||||
 | 
					                        const autoAvgDelay = 1.05 * max > 0.91 * MaxTCPPingValue ? 1.05 * max : 0.91 * MaxTCPPingValue;
 | 
				
			||||||
 | 
					                        // 定义丢包 1. avgDelay==0  2. avgDelay>=MaxTCPPingValue 3. avgDelay>=threshold
 | 
				
			||||||
 | 
					                        if(avgDelay == 0 || avgDelay >= MaxTCPPingValue){ //绝对丢包
 | 
				
			||||||
                            loss += 1;
 | 
					                            loss += 1;
 | 
				
			||||||
                            datal.push({
 | 
					                            const lossrate = 100 * loss / (index + 1);
 | 
				
			||||||
                                xAxis: monitorInfo.result[i].created_at[j],
 | 
					                            data['main'].push(
 | 
				
			||||||
 | 
					                                [item.created_at[index], autoAvgDelay, lossrate]
 | 
				
			||||||
 | 
					                            );
 | 
				
			||||||
 | 
					                            data['markLine'].push({
 | 
				
			||||||
 | 
					                                xAxis: item.created_at[index],
 | 
				
			||||||
                                label: { show: false },
 | 
					                                label: { show: false },
 | 
				
			||||||
                                emphasis: { disabled: true },
 | 
					                                emphasis: { disabled: true },
 | 
				
			||||||
                                lineStyle: {
 | 
					                                lineStyle: { type: "solid" }
 | 
				
			||||||
                                    type: "solid",
 | 
					                            });
 | 
				
			||||||
                                    color: rgbaColorBar
 | 
					                        } else if (avgDelay >= threshold && avgDelay < MaxTCPPingValue){ // 相对丢包
 | 
				
			||||||
 | 
					                            loss += 1;
 | 
				
			||||||
 | 
					                            const lossrate = 100 * loss / (index + 1);
 | 
				
			||||||
 | 
					                            data['main'].push(
 | 
				
			||||||
 | 
					                                [item.created_at[index], avgDelay, lossrate]
 | 
				
			||||||
 | 
					                            );
 | 
				
			||||||
 | 
					                            data['markLine'].push({
 | 
				
			||||||
 | 
					                                xAxis: item.created_at[index],
 | 
				
			||||||
 | 
					                                label: { show: false },
 | 
				
			||||||
 | 
					                                emphasis: { disabled: true },
 | 
				
			||||||
 | 
					                                lineStyle: { type: "solid" }
 | 
				
			||||||
 | 
					                            });
 | 
				
			||||||
 | 
					                        } else { // 未丢包
 | 
				
			||||||
 | 
					                            const lossrate = 100 * loss / (index + 1);
 | 
				
			||||||
 | 
					                            data['main'].push(
 | 
				
			||||||
 | 
					                                [item.created_at[index], avgDelay, lossrate]
 | 
				
			||||||
 | 
					                            );
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
                        }
 | 
					                    // 处理legendData
 | 
				
			||||||
                    }
 | 
					                    totalLossRate = ((loss / item.created_at.length) * 100).toFixed(1);
 | 
				
			||||||
                    lossRate = ((loss / monitorInfo.result[i].created_at.length) * 100).toFixed(1);
 | 
					                    legendName = `${item.monitor_name} ${totalLossRate}%`;
 | 
				
			||||||
                    if (lossRate > 99) {
 | 
					                    legendData.push(legendName);
 | 
				
			||||||
                        datal = [];
 | 
					                    // 处理seriesData
 | 
				
			||||||
                    }
 | 
					                    seriesData.push(
 | 
				
			||||||
                    legendName = monitorInfo.result[i].monitor_name +" "+ lossRate + "%";
 | 
					                        {
 | 
				
			||||||
                    tLegendData.push(legendName);
 | 
					 | 
				
			||||||
                    tSeries.push({
 | 
					 | 
				
			||||||
                            name: legendName,
 | 
					                            name: legendName,
 | 
				
			||||||
                            type: 'line',
 | 
					                            type: 'line',
 | 
				
			||||||
                            smooth: true,
 | 
					                            smooth: true,
 | 
				
			||||||
                            symbol: 'none',
 | 
					                            symbol: 'none',
 | 
				
			||||||
                            data: data,
 | 
					                            connectNulls: true,
 | 
				
			||||||
 | 
					                            lineStyle: {
 | 
				
			||||||
 | 
					                                width: lineStyleWidth
 | 
				
			||||||
 | 
					                            },  
 | 
				
			||||||
 | 
					                            data: data['main'],
 | 
				
			||||||
                            markLine: {
 | 
					                            markLine: {
 | 
				
			||||||
                                symbol: "none",
 | 
					                                symbol: "none",
 | 
				
			||||||
                                symbolSize :0,
 | 
					                                symbolSize :0,
 | 
				
			||||||
                                data: datal
 | 
					                                data: data['markLine'],
 | 
				
			||||||
 | 
					                                itemStyle: { 
 | 
				
			||||||
 | 
					                                    opacity: markLineItemStyleOpacity
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                lineStyle:{
 | 
				
			||||||
 | 
					                                    width: markLineLineStyleWidth
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
                            },
 | 
					                            },
 | 
				
			||||||
                            markPoint: {
 | 
					                            markPoint: {
 | 
				
			||||||
                                data: [
 | 
					                                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 }
 | 
					                                        name: 'Max',
 | 
				
			||||||
 | 
					                                        type: 'max', 
 | 
				
			||||||
 | 
					                                        symbol: 'pin', 
 | 
				
			||||||
 | 
					                                        itemStyle: { 
 | 
				
			||||||
 | 
					                                            opacity: markPointItemStyleOpacity
 | 
				
			||||||
 | 
					                                        }, 
 | 
				
			||||||
 | 
					                                        symbolSize: 30, 
 | 
				
			||||||
 | 
					                                        label: { 
 | 
				
			||||||
 | 
					                                            fontSize: 8,
 | 
				
			||||||
 | 
					                                            color: markPointLabelColor,
 | 
				
			||||||
 | 
					                                            formatter: function (params) {
 | 
				
			||||||
 | 
					                                                return Math.round(params.value);
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        name: 'Min',
 | 
				
			||||||
 | 
					                                        type: 'min', 
 | 
				
			||||||
 | 
					                                        symbol: 'pin', 
 | 
				
			||||||
 | 
					                                        itemStyle: { 
 | 
				
			||||||
 | 
					                                            opacity: markPointItemStyleOpacity
 | 
				
			||||||
 | 
					                                        }, 
 | 
				
			||||||
 | 
					                                        symbolSize: 30, 
 | 
				
			||||||
 | 
					                                        label: { 
 | 
				
			||||||
 | 
					                                            fontSize: 8,
 | 
				
			||||||
 | 
					                                            color: markPointLabelColor,
 | 
				
			||||||
 | 
					                                            offset: [0, 8],
 | 
				
			||||||
 | 
					                                            formatter: function (params) {
 | 
				
			||||||
 | 
					                                                return Math.round(params.value);
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        }, 
 | 
				
			||||||
 | 
					                                        symbolRotate: 180 
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
                                ]
 | 
					                                ]
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                const maxLegendsPerRowMobile = localStorage.getItem("maxLegendsPerRowMobile") ? localStorage.getItem("maxLegendsPerRowMobile") : 3;
 | 
				
			||||||
 | 
					                const maxLegendsPerRowPc = localStorage.getItem("maxLegendsPerRowPc") ? localStorage.getItem("maxLegendsPerRowPc") : 6;
 | 
				
			||||||
 | 
					                const autoIncrement = Math.floor((legendData.length - 1) / (this.isMobile ? maxLegendsPerRowMobile : maxLegendsPerRowPc)) * (this.isMobile ? 20 : 28)
 | 
				
			||||||
 | 
					                const height = autoheight + autoIncrement;
 | 
				
			||||||
 | 
					                const gridTop = 40 + autoIncrement;
 | 
				
			||||||
 | 
					                const legendIcon = this.isMobile ? 'rect' : ""; 
 | 
				
			||||||
 | 
					                const itemWidth = this.isMobile ? 10 : 25;
 | 
				
			||||||
 | 
					                const itemHeight = this.isMobile ? 10 : 14;
 | 
				
			||||||
 | 
					                this.chart.resize({
 | 
				
			||||||
 | 
					                    width: 'auto',
 | 
				
			||||||
 | 
					                    height: height
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                // 设置图表配置项
 | 
				
			||||||
 | 
					                const option = {
 | 
				
			||||||
 | 
					                    // 全局调色盘
 | 
				
			||||||
 | 
					                    color: this.colors,
 | 
				
			||||||
 | 
					                    // 背景颜色
 | 
				
			||||||
 | 
					                    backgroundColor: backgroundColor,
 | 
				
			||||||
 | 
					                    // 文字样式
 | 
				
			||||||
 | 
					                    textStyle: {
 | 
				
			||||||
 | 
					                        fontSize: fontSize,
 | 
				
			||||||
 | 
					                        color: fontColor
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    // 图表网格设置
 | 
				
			||||||
 | 
					                    grid: {
 | 
				
			||||||
 | 
					                        top: gridTop,
 | 
				
			||||||
 | 
					                        left: gridLeft,
 | 
				
			||||||
 | 
					                        right: gridRight
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    // 图表标题设置
 | 
				
			||||||
 | 
					                    title: {
 | 
				
			||||||
 | 
					                        show: false,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    // 图表系列数据设置
 | 
				
			||||||
 | 
					                    series: seriesData.flat(),
 | 
				
			||||||
 | 
					                    // X轴设置
 | 
				
			||||||
 | 
					                    xAxis: {
 | 
				
			||||||
 | 
					                        type: 'time',
 | 
				
			||||||
 | 
					                        axisLabel: {
 | 
				
			||||||
 | 
					                            textStyle: {
 | 
				
			||||||
 | 
					                                fontSize: fontSize
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    // Y轴设置
 | 
				
			||||||
 | 
					                    yAxis: {
 | 
				
			||||||
 | 
					                        type: 'value',
 | 
				
			||||||
 | 
					                        axisLabel: {
 | 
				
			||||||
 | 
					                            textStyle: {
 | 
				
			||||||
 | 
					                                fontSize: fontSize
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        splitLine: {
 | 
				
			||||||
 | 
					                            lineStyle: {
 | 
				
			||||||
 | 
					                                width: splitLineWidth,
 | 
				
			||||||
 | 
					                                color: splitLineColor
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    // 图例设置
 | 
				
			||||||
 | 
					                    legend: {
 | 
				
			||||||
 | 
					                        data: legendData,
 | 
				
			||||||
 | 
					                        show: true,
 | 
				
			||||||
 | 
					                        icon: legendIcon,
 | 
				
			||||||
 | 
					                        textStyle: {
 | 
				
			||||||
 | 
					                            fontSize: fontSize,
 | 
				
			||||||
 | 
					                            color: fontColor
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        top: legendTop,
 | 
				
			||||||
 | 
					                        bottom: 0,
 | 
				
			||||||
 | 
					                        left: legendLeft,
 | 
				
			||||||
 | 
					                        padding: legendPadding,
 | 
				
			||||||
 | 
					                        itemWidth: itemWidth,
 | 
				
			||||||
 | 
					                        itemHeight: itemHeight,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    // 提示框设置
 | 
				
			||||||
 | 
					                    tooltip: {
 | 
				
			||||||
 | 
					                        trigger: 'axis',
 | 
				
			||||||
 | 
					                        backgroundColor: tooltipBackgroundColor,
 | 
				
			||||||
 | 
					                        borderColor: tooltipBorderColor,
 | 
				
			||||||
 | 
					                        textStyle: {
 | 
				
			||||||
 | 
					                            fontSize: fontSize,
 | 
				
			||||||
 | 
					                            color: fontColor
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        formatter: function (params) {
 | 
				
			||||||
 | 
					                            let tooltipContent = '';
 | 
				
			||||||
 | 
					                            const formattedTime = new Date(params[0].value[0]).toLocaleString(); 
 | 
				
			||||||
 | 
					                            tooltipContent += `<span style="line-height:2em">${formattedTime}</span><br>`;
 | 
				
			||||||
 | 
					                            params.forEach(param => {
 | 
				
			||||||
 | 
					                                const formattedTime = new Date(param.value[0]).toLocaleString();
 | 
				
			||||||
 | 
					                                if (!param.seriesName.includes('stack')) {
 | 
				
			||||||
 | 
					                                    const name = param.seriesName.replace(/\s\d+(\.\d+)?%$/, '');
 | 
				
			||||||
 | 
					                                    tooltipContent += `<span style="line-height:2em">${param.marker} ${name} ${param.value[2].toFixed(1)}% ${param.value[1].toFixed(2)}</span><br>`;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            });
 | 
				
			||||||
 | 
					                            return tooltipContent;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    // 数据缩放设置
 | 
				
			||||||
 | 
					                    dataZoom: [
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            type: 'slider',
 | 
				
			||||||
 | 
					                            start: 0,
 | 
				
			||||||
 | 
					                            end: 100
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    ]
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                // 设置图表的配置选项
 | 
				
			||||||
 | 
					                this.chart.setOption(option);
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            reloadCharts() { // 重新加载所有图表
 | 
				
			||||||
 | 
					                this.servers.forEach(node => {
 | 
				
			||||||
 | 
					                    const id = node.ID;
 | 
				
			||||||
 | 
					                    const chartData = this.chartDataList[id];
 | 
				
			||||||
 | 
					                    if (chartData) {
 | 
				
			||||||
 | 
					                        this.renderCharts(id,true);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            disposeCharts(){
 | 
				
			||||||
 | 
					                if(this.chart) {
 | 
				
			||||||
 | 
					                    this.chart.dispose();
 | 
				
			||||||
 | 
					                    this.chart = null;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            getServerCountryCode(id){
 | 
				
			||||||
 | 
					                const result = this.servers.find(item => item.ID == id);
 | 
				
			||||||
 | 
					                return result.Host.CountryCode ? result.Host.CountryCode : 'rb';
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            initSearch() {
 | 
				
			||||||
 | 
					                $('#dropdown-search').on('keyup', function() {
 | 
				
			||||||
 | 
					                    var searchTerm = $(this).val().toLowerCase();
 | 
				
			||||||
 | 
					                    $('.dropdown-menu .dropdown-item').each(function() {
 | 
				
			||||||
 | 
					                        var text = $(this).text().toLowerCase();
 | 
				
			||||||
 | 
					                        if (text.indexOf(searchTerm) > -1) {
 | 
				
			||||||
 | 
					                            $(this).removeClass('hidden').addClass('visible'); // 显示元素
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            $(this).removeClass('visible').addClass('hidden'); // 隐藏元素
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
                this.option.title.text = monitorInfo.result[0].server_name;
 | 
					        }
 | 
				
			||||||
                this.option.series = tSeries;
 | 
					 | 
				
			||||||
                this.option.legend.data = tLegendData;
 | 
					 | 
				
			||||||
                this.myChart.clear();
 | 
					 | 
				
			||||||
                this.myChart.setOption(this.option);
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            isWindowsPlatform(str) {
 | 
					 | 
				
			||||||
                return str.includes('Windows')
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            renderChart() {
 | 
					 | 
				
			||||||
              this.myChart = echarts.init(this.$refs.chartDom);
 | 
					 | 
				
			||||||
              this.myChart.setOption(this.option);
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        beforeDestroy() {
 | 
					 | 
				
			||||||
            this.myChart.dispose();
 | 
					 | 
				
			||||||
            this.myChart = null;
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
{{end}}
 | 
					{{end}}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user