小米路由器(mini)PC端设备实时网速

小米路由器(mini)PC端后台管理界面设备实时网速

// ==UserScript==
// @name         小米路由器(mini)PC端设备实时网速
// @namespace    http://tampermonkey.net/
// @version      1.04
// @description  小米路由器(mini)PC端后台管理界面设备实时网速
// @author       过去终究是个回忆
// @license      MIT
// @match        http://192.168.31.1/cgi-bin/luci/*/web/home*
// @require      https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/dayjs/1.10.8/dayjs.min.js
// @require      https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js
// @require      https://unpkg.com/[email protected]/dist/ajaxhook.min.js
// @require      https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-ui/2.15.7/index.min.js
// @require      https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/echarts/5.3.0-rc.1/echarts.min.js
// @grant        GM_getResourceText
// @grant        GM_addStyle
// @grant        GM_addStyle
// @grant        unsafeWindow
// @resource     element-ui https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-ui/2.15.7/theme-chalk/index.min.css
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    GM_addStyle(GM_getResourceText('element-ui'))
    GM_addStyle(`
        @font-face{font-family:element-icons;src:url(https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-ui/2.15.7/theme-chalk/fonts/element-icons.woff) format("woff"),url(https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-ui/2.15.7/theme-chalk/fonts/element-icons.ttf) format("truetype");font-weight:400;font-display:"auto";font-style:normal}
        #net-speed {
            float: left;
            margin-top: 40px;
            width: 100%;
            }
            .demo-table-expand {
            font-size: 0;
        }
        .speed-line {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .speed-line div[role="progressbar"] {
            width: 300px;
        }
        #net-speed-charts {
            height: 600px;
        }
    `)

    const maxEachDataStorage = 100
    const updateDevDataEvent = new Event('updateDevData')
    const initData = {
        history: {},
        tableData: []
    }

    window.ah.proxy({
        //请求成功后进入
        onResponse: (response, handler) => {
            if (response.config.url.includes('/api/misystem/status')) {
                const data = JSON.parse(response.response)
                initData.tableData = data.dev.map(item => ({
                    ...item,
                    download: Number(item.download),
                    downspeed: Number(item.downspeed),
                    maxdownloadspeed: Number(item.maxdownloadspeed),
                    maxuploadspeed: Number(item.maxuploadspeed),
                    online: Number(item.online),
                    upload: Number(item.upload),
                    upspeed: Number(item.upspeed),
                    dateSecond: Date.now(),
                    combinedSpeed: Number(item.upspeed) + Number(item.downspeed),
                }))
                data.dev.forEach(item => {
                    if (!initData.history[item.mac]) {
                        initData.history[item.mac] = []
                    }
                    initData.history[item.mac].push({
                        ...item,
                        dateSecond: Date.now(),
                    })
                    if (initData.history[item.mac].length > maxEachDataStorage) {
                        initData.history[item.mac].shift()
                    }
                })
                document.dispatchEvent(updateDevDataEvent)
            }
            handler.next(response)
        }
    }, unsafeWindow)

    window.onload = function () {
        const container = document.createElement('div')
        container.id = 'net-speed'
        console.log('net-speed starting...')

        const target = document.querySelector('#bd>.mod-routerstatus.nav-tab-content')
        target.appendChild(container)

        new Vue({
            el: container,
            data() {
                return {
                    dialogTableTitle: 'dialogTableTitle',
                    dialogTableVisible: false,
                    currentRow: {},
                    history: {},
                    tableData: [],
                    dataSource: 1,
                    stok: '',
                    totalDownloadSpeed: 0,
                    totalUploadSpeed: 0,
                    myChart: null,
                }
            },
            async created() {
                this.stok = location.pathname.match(/\/;stok=(.*?)\//)?.[1]
                this.history = initData.history
                this.tableData = initData.tableData
                document.addEventListener("updateDevData", () => {
                    if (this.dataSource === 1) {
                        this.history = initData.history
                        this.tableData = initData.tableData
                        if (this.myChart) {
                            const $row = this.history[this.currentRow.mac]
                            this.myChart.setOption({
                                xAxis: {
                                    data: $row.map(item => this.dateTimeFormatter(item.dateSecond))
                                },
                                series: [
                                    {
                                        name: '上传',
                                        data: $row.map(item => item.upspeed)
                                    },
                                    {
                                        name: '下载',
                                        data: $row.map(item => item.downspeed)
                                    },
                                ]
                            });
                        }
                        console.log(this.tableData, 'this.tableData')
                        console.log(this.history, 'this.history')
                    }
                })
                const res = await this.getBbandwidth()
                this.totalDownloadSpeed = res.bandwidth / 8 * 1024 * 1024
                this.totalUploadSpeed = res.bandwidth2 / 8 * 1024 * 1024

                window.addEventListener('resize', () => {
                    this.myChart && this.myChart.resize();
                });
            },
            watch: {
                dataSource(prev, next) {
                    if (prev !== next) {
                        this.history = []
                        this.tableData = []
                        if (next === 2) {

                        }
                    }
                },
            },
            methods: {
                byteFormat: byteFormat,
                secondToDate: secondToDate,
                speedFormat(number, precision, isarray) {
                    return this.byteFormat(number, precision, isarray) + '/S'
                },
                speedFormatter(row, column, cellValue) {
                    return this.speedFormat(cellValue, 100)
                },
                dataFormatter(row, column, cellValue) {
                    return this.byteFormat(cellValue, 100)
                },
                secondFormatter(row, column, cellValue) {
                    return this.secondToDate(cellValue)
                },
                dateTimeFormatter(cellValue) {
                    return dayjs(cellValue).format('YYYY-MM-DD HH:mm:ss')
                },
                showHistoryData(row) {
                    this.dialogTableVisible = true
                    this.dialogTableTitle = `${row.devname}(${row.mac}) 历史数据`
                    this.currentRow = row
                    const $row = this.history[this.currentRow.mac]
                    this.$nextTick(() => {
                        this.myChart = echarts.init(document.getElementById('net-speed-charts'));
                        // 绘制图表
                        this.myChart.setOption({
                            tooltip: {
                                trigger: 'axis',
                                axisPointer: {
                                    type: 'cross',
                                    label: {
                                        backgroundColor: '#6a7985'
                                    }
                                }
                            },
                            dataZoom: [
                                {
                                    show: true,
                                    realtime: true,
                                    start: 0,
                                    end: 100
                                },
                                {
                                    type: 'inside',
                                    realtime: true,
                                    start: 0,
                                    end: 100
                                },
                            ],
                            color: ['#2673bf', '#33cc33'],
                            legend: {
                                data: ['上传', '下载']
                            },
                            xAxis: [
                                {
                                    type: 'category',
                                    boundaryGap: false,
                                    data: $row.map(item => this.dateTimeFormatter(item.dateSecond)),
                                }
                            ],
                            yAxis: [
                                {
                                    type: 'value',
                                    axisLabel: {
                                        formatter: (value) => this.speedFormat(value, 100),
                                    },
                                }
                            ],
                            series: [
                                {
                                    name: '上传',
                                    type: 'line',
                                    areaStyle: {},
                                    tooltip: {
                                        valueFormatter: (value) => this.speedFormat(value, 100)
                                    },
                                    emphasis: {
                                        focus: 'series'
                                    },
                                    data: $row.map(item => item.upspeed)
                                },
                                {
                                    name: '下载',
                                    type: 'line',
                                    areaStyle: {},
                                    tooltip: {
                                        valueFormatter: (value) => this.speedFormat(value, 100)
                                    },
                                    emphasis: {
                                        focus: 'series'
                                    },
                                    data: $row.map(item => item.downspeed)
                                },
                            ]
                        });

                    })
                },
                beforeDialogTableClose(done) {
                    this.myChart.dispose()
                    this.myChart = null
                    done()
                },
                async getBbandwidth() {
                    const res = await fetch(`/cgi-bin/luci/;stok=${this.stok}/api/misystem/bandwidth_test?history=1`).then(result => result.json())
                    if (res.code === 0) {
                        return res
                    } else {
                        throw res;
                    }
                },
                async updateNetSpeed() {
                    const res = await fetch(`/cgi-bin/luci/;stok=${this.stok}/api/misystem/devicelist`).then(result => result.json())
                    if (res.code === 0) {
                        const devList = res.data.map(item => ({ ...item, ...item.statistics, ip: item.ip[0].ip }))
                        this.tableData = devList
                    }
                }
            },
            template: `
            <div id="net-speed">
                <div style="margin-bottom: 20px;">
                    数据来源(切换会清空历史记录):
                    <el-radio-group v-model="dataSource">
                        <el-tooltip content="性能开销小" placement="top">
                            <el-radio-button :label="1">请求代理</el-radio-button>
                        </el-tooltip>
                        <el-tooltip content="通用、设备全(尚未开发)" placement="top">
                            <el-radio-button :label="2" disabled>主动请求</el-radio-button>
                        </el-tooltip>
                    </el-radio-group>
                </div>
                <el-table
                    v-loading="!tableData.length"
                    :data="tableData"
                    :default-sort="{prop: 'combinedSpeed', order: 'descending'}"
                    border
                    fit
                    max-height="500px"
                    style="width: 100%;"
                >
                    <el-table-column
                        prop="devname"
                        label="设备"
                        sortable
                        width="200"
                    />
                    <el-table-column
                        prop="mac"
                        label="MAC"
                        sortable
                        width="148"
                    />
                    <el-table-column
                        prop="combinedSpeed"
                        label="网速"
                        width="540"
                        sortable
                        sort-by="combinedSpeed"
                    >
                        <template slot-scope="scope">
                            <p class="speed-line">上传速度: <el-progress :percentage="scope.row.upspeed / totalUploadSpeed * 100" :show-text="false" color="#2673bf"></el-progress>{{speedFormat(scope.row.upspeed, 100)}}</p>
                            <p class="speed-line">下载速度: <el-progress :percentage="scope.row.downspeed / totalDownloadSpeed * 100" :show-text="false" color="#33cc33"></el-progress>{{speedFormat(scope.row.downspeed, 100)}}</p>
                        </template>
                    </el-table-column>
                    <el-table-column
                        prop="maxuploadspeed"
                        label="历史最大上传速度"
                        width="158"
                        sortable
                        :formatter="speedFormatter"
                    />
                    <el-table-column
                        prop="maxdownloadspeed"
                        label="历史最大下载速度"
                        width="158"
                        sortable
                        :formatter="speedFormatter"
                    />
                    <el-table-column
                        prop="upload"
                        label="上传流量"
                        width="102"
                        sortable
                        :formatter="dataFormatter"
                    />
                    <el-table-column
                        prop="download"
                        label="下载流量"
                        width="102"
                        sortable
                        :formatter="dataFormatter"
                    />
                    <el-table-column
                        prop="online"
                        label="在线时间"
                        width="140"
                        sortable
                        :formatter="secondFormatter"
                    />
                    <el-table-column
                        prop="devname"
                        label="操作"
                        fixed="right"
                    >
                        <template slot-scope="scope">
                            <el-button type="text" size="small" @click="showHistoryData(scope.row)">历史数据</el-button>
                        </template>
                    </el-table-column>
                </el-table>
                <el-dialog :title="dialogTableTitle" :visible.sync="dialogTableVisible" :before-close="beforeDialogTableClose" width="80%">
                    <div id="net-speed-charts"></div>
                </el-dialog>
            </div>
        `
        })
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址