logo NodeSeekbeta

【已PR并合入官方v0.16.3】【哪吒优化教程最后一期】三网延迟界面图表美化

已PR并合入官方,大家可以直接通过官方享用 xhj008

前言

这是哪吒系列技术教程的最后一期分享,先前由于个人原因干扰了版面,在这里表示歉意,恳请各位海涵

哪吒的三网延迟是最近刚推出的功能,还有很多不尽如人意的地方,比如

  • 延迟默认最高300ms,超过后默认抹平
  • 曲线上有很多ping值为0的无效散点,导致毛刺很多,干扰效果
  • 图标的y轴比例失调,上方大片留白,大大降低了有效显示区域
  • 默认只显示最近不到半小时左右的延迟表现,想看全天需要拖动,影响效果
  • 曲线不显示极大极小值,不够直观

因此,我们即将开启快进按钮,一步到位,全部解决!让这一系列教程有一个圆满的结束。

美化效果

⛱️Arioc's Needle 阿里欧克之针

美化前 美化后
美化前 美化后

美化方法

  1. 修改ping值上限为1000(或任意你希望的取值)
vim /opt/nezha/dashboard/data/config.yaml
  1. 找到第26行,修改为
MaxTCPPingValue: 1000
  1. 美化图表
vim /opt/nezha/dashboard/theme-custom/template/network.html

或者

vim /opt/nezha/dashboard/resource/template/theme-custom/network.html
  1. 找到第28-217行<script>标签全部内容替换为以下内容
<script>
    const monitorInfo =  JSON.parse('{{.MonitorInfos}}');
    const initData = JSON.parse('{{.Servers}}').servers;
    let MaxTCPPingValue = {{.MaxTCPPingValue}};
    if (MaxTCPPingValue == null) {
        MaxTCPPingValue = 1000;
    }
    new Vue({
        el: '#app',
        delimiters: ['@#', '#@'],
        data: {
            servers: initData,
            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
                    }
                },
                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,
        },
        mounted() {
            this.renderChart();
             this.parseMonitorInfo(monitorInfo);
        },
        methods: {
            getFontLogoClass(str) {
                if (["almalinux",
                        "alpine",
                        "aosc",
                        "apple",
                        "archlinux",
                        "archlabs",
                        "artix",
                        "budgie",
                        "centos",
                        "coreos",
                        "debian",
                        "deepin",
                        "devuan",
                        "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){
                        window.location.href = "/404";
                    })
                },
            getMonitorHistory(id) {
                  return $.ajax({
                    url: "/api/v1/monitor/"+id,
                    method: "GET"
                  });
            },
            parseMonitorInfo(monitorInfo) {
                let tSeries = [];
                let tLegendData = [];
                for (let i = 0; i < monitorInfo.result.length; i++) {
                    let loss = 0;
                    let data = [];
                    for (let j = 0; j < monitorInfo.result[i].created_at.length; j++) {
                        avgDelay = Math.round(monitorInfo.result[i].avg_delay[j]);
                        if (avgDelay > 0.9 * MaxTCPPingValue) {
                            loss += 1
                        }
                        if (avgDelay > 0) {
                            data.push([monitorInfo.result[i].created_at[j], avgDelay]);
                        }
                    }
                    lossRate = ((loss / monitorInfo.result[i].created_at.length) * 100).toFixed(1);
                    legendName = monitorInfo.result[i].monitor_name +" "+ lossRate + "%";
                    tLegendData.push(legendName);
                    tSeries.push({
                            name: legendName,
                            type: 'line',
                            smooth: true,
                            symbol: 'none',
                            data: data,
                            markPoint: {
                                data: [
                                    { type: 'max', symbol: 'pin', name: 'Max', itemStyle: { color: '#f00' } },
                                    { type: 'min', symbol: 'pin', name: 'Min', itemStyle: { color: '#0f0' } }
                                ]
                            }
                    });
                }
                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>
  1. 重启面板生效
systemctl restart nezha-dashboard

鸣谢

感谢为历史tcpping功能做出重大贡献的 @lvgj 同学!
ref. 【已合入官方,使用官方脚本升级面板版本即可】哪吒面板+自定义主题+默认主题+历史tcpping食用教程

后续补充

  • 有小伙伴反馈没有network.html文件
    这个官方的已经更新了,但是只有default主题有,所以需要去这里手动下载下来,然后修改一下这个文件头部的相关主题信息才行。另外如果主页没有network链接入口,还需要更新一下menu,更新的时候注意不要破坏原有主题。
  • 有小伙伴反馈network里面一片空白
    还是没有匹配主题的锅,需要手动修改这个文件第1、2、6、25行的主题信息,以匹配你定义的主题,然后才能用
  • 有小伙伴反馈根据lvgj兄弟的教程改完代码不显示图标和图表
    我没用过lvgj兄弟的改版,不太清楚,这里引用#37层 @Stevie0427及#47层 @lyy0709兄弟给出的方案:把文件里的#app改成#network即可
  • 有小伙伴反馈不知道如何添加三网测速曲线
    这个要进后台->服务->新增监控,三网地址参考@FCB 兄弟的分享地址,新增的监控要等一会儿才会有数据
  • 丢包率并不是真实的情况,如何去掉
    network.html第189-190行
                    lossRate = ((loss / monitorInfo.result[i].created_at.length) * 100).toFixed(1);
                    legendName = monitorInfo.result[i].monitor_name +" "+ lossRate + "%";

替换为

                    legendName = monitorInfo.result[i].monitor_name;
  • 支持,感谢bug师傅一直以来的教程 xhj006

  • @hakka #3 感谢兄弟支持 xhj008

  • @Stevie0427 #35 发布于2024/2/19 09:10:00,编辑于2024/2/19 09:11:40
    @xy #0 用lvgj大佬的主题修改后将#app改为#network之后点击别的机器就会403(访问被拒绝) xhj027

    不好意思是我的问题 ac01 后面有个地方函数名没改,现在把用LVGJ大佬的修改后(app修改为network)的代码贴上来

    {{define "theme-custom/network"}}
    {{template "theme-custom/header" .}}
    {{if ts .CustomCode}}
    {{.CustomCode|safe}}
    {{end}}
    {{template "theme-custom/menu" .}}
    <div id="network" class="nb-container">
        <div class="ui container">
            <div class="service-status">
                <div class="ui icon button"
                     v-for='server in servers'
                     :id="server.ID"
                     style="margin-top: 3px"
                     @click="redirectNetwork(server.ID)">
                    @#server.Name#@<i :class="server.Host.CountryCode + ' flag'"></i>&nbsp;<i
                        v-if='server.Host.Platform == "darwin"' class="apple icon"></i><i
                        v-else-if='isWindowsPlatform(server.Host.Platform)' class="windows icon"></i><i
                        v-else :class="'fl-' + getFontLogoClass(server.Host.Platform)"></i>
                </div>
                <div ref="chartDom" style="border-radius: 28px; margin-top: 15px;height: 520px;max-width: 1400px;overflow: hidden"></div>
            </div>
        </div>
    </div>
    
    {{template "theme-custom/footer" .}}
    <script>
        const monitorInfo =  JSON.parse('{{.MonitorInfos}}');
        const initData = JSON.parse('{{.Servers}}').servers;
        let MaxTCPPingValue = {{.MaxTCPPingValue}};
        if (MaxTCPPingValue == null) {
            MaxTCPPingValue = 1000;
        }
        new Vue({
            el: '#network',
            delimiters: ['@#', '#@'],
            data: {
                servers: initData,
                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
                        }
                    },
                    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,
            },
            mounted() {
                this.renderChart();
                 this.parseMonitorInfo(monitorInfo);
            },
            methods: {
                getFontLogoClass(str) {
                    if (["almalinux",
                            "alpine",
                            "aosc",
                            "apple",
                            "archlinux",
                            "archlabs",
                            "artix",
                            "budgie",
                            "centos",
                            "coreos",
                            "debian",
                            "deepin",
                            "devuan",
                            "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 = 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 = [];
                    for (let i = 0; i < monitorInfo.result.length; i++) {
                        let loss = 0;
                        let data = [];
                        for (let j = 0; j < monitorInfo.result[i].created_at.length; j++) {
                            avgDelay = Math.round(monitorInfo.result[i].avg_delay[j]);
                            if (avgDelay > 0.9 * MaxTCPPingValue) {
                                loss += 1
                            }
                            if (avgDelay > 0) {
                                data.push([monitorInfo.result[i].created_at[j], avgDelay]);
                            }
                        }
                        lossRate = ((loss / monitorInfo.result[i].created_at.length) * 100).toFixed(1);
                        legendName = monitorInfo.result[i].monitor_name +" "+ lossRate + "%";
                        tLegendData.push(legendName);
                        tSeries.push({
                                name: legendName,
                                type: 'line',
                                smooth: true,
                                symbol: 'none',
                                data: data,
                                markPoint: {
                                    data: [
                                        { type: 'max', symbol: 'pin', name: 'Max', itemStyle: { color: '#f00' } },
                                        { type: 'min', symbol: 'pin', name: 'Min', itemStyle: { color: '#0f0' } }
                                    ]
                                }
                        });
                    }
                    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>
    {{end}}
    
    
  • @rayhope #46 把文件里的#app改成#network,后面有一个app.也改成network.

  • mark

  • 666

  • 太强了 xhj003

  • 厉害了,支持

  • 能不能PR到官方

  • 前排留名

  • 第三点建议大佬给官方提个pr,造福广大用户 ac01

  • ac32 xhj006

  • @kk #8 @samiya #6 感谢建议,这就去弄! xhj008

你好啊,陌生人!

我的朋友,看起来你是新来的,如果想参与到讨论中,点击下面的按钮!

📈用户数目📈

目前论坛共有72280位seeker

🎉欢迎新用户🎉