预览
img
img
img
美化代码
来源:https://www.nodeseek.com/post-311746-1

<script>
    /* 这部分这几个挂在 window 下的变量是哪吒内置的, 详见 https://nezha.wiki/guide/settings.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E4%BB%A3%E7%A0%81 */
    window.CustomBackgroundImage = 'https://r2.wuxie.de/blog/20250414_8d62ff03.jpg'; /* PC 端背景图 */
    window.CustomMobileBackgroundImage = 'https://img-api.wuxie.de/acg/13/sp'; /* 移动端背景图 */
    window.CustomLogo = 'https://xiny.cc/xiny/favicon.ico'; /* 页面左上角和标题栏展示的 Logo */
    window.CustomDesc = 'XINY'; /* 页面左上角副标题 */
    window.ShowNetTransfer = true; /* 服务器卡片是否显示上下行流量, 默认不显示 */
    /* window.DisableAnimatedMan = true; */
    window.CustomIllustration = 'https://r2.wuxie.de/blog/20250415_762b4cb3.webp';
    window.FixedTopServerName = true; /* 是否固定顶部显示服务器名称, 默认不固定 */
    window.CustomLinks = '[{\"link\":\"https://xiny.cc/\",\"name\":\"首页\"},{\"link\":\"https://blog.xiny.cc/\",\"name\":\"博客\"}]'; /* 自定义导航栏链接 */

    /* 自定义字体, 注意需要同步修改下方 CSS 中的 font-family */
    var link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = 'https://font.sec.miui.com/font/css?family=MiSans:400,700:MiSans'; // MiSans
    // link.href = 'https://npm.elemecdn.com/lxgw-wenkai-screen-webfont@1.7.0/style.css'; // 霞鹜文楷, font-family: 'LXGW WenKai Screen'
    document.head.appendChild(link);
</script>
<style>
    /* 自定义字体 */
    * {
        font-family: 'MiSans';
    }
    h1, h2, h3, h4, h5 {
        font-family: 'MiSans', sans-serif;
    }

    /* 背景压暗和模糊, 开了背景图建议开启 */
    .dark .bg-cover::after {
        content: '';
        position: absolute;
        inset: 0;
        backdrop-filter: blur(2px);
        background-color: rgba(0, 0, 0, 0.1);
    }
    .light .bg-cover::after {
        content: '';
        position: absolute;
        inset: 0;
        backdrop-filter: blur(2px);
        background-color: rgba(255, 255, 255, 0);
    }

    footer {
        display: none;
    }
</style>
<script>
window.FixedTopServerName = true; /* 是否固定顶部显示服务器名称, 默认不固定 */
setInterval(function() {
    function formatFileSize(bytes) {
        if (bytes === 0) return { value: '0', unit: 'B' };
        
        const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
        let unitIndex = 0;
        let size = bytes;
        
        while (size >= 1024 && unitIndex < units.length - 1) {
            size /= 1024;
            unitIndex++;
        }
        
        let decimalPlaces = 1;
        if (unitIndex === 0) decimalPlaces = 0;
        
        return {
            value: size.toFixed(decimalPlaces),
            unit: units[unitIndex]
        };
    }
    
    function calculatePercentage(used, total) {
        if (typeof used === 'string') used = Number(used);
        if (typeof total === 'string') total = Number(total);
        
        if (used > 1e15 || total > 1e15) {
            used = used / 1e10;
            total = total / 1e10;
        }
        
        return (used / total * 100).toFixed(1);
    }
    fetch('/api/v1/service')
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                const trafficData = data.data.cycle_transfer_stats;
                
                const serverMap = new Map();
                
                for (const cycleId in trafficData) {
                    const cycle = trafficData[cycleId];
                    if (cycle.server_name && cycle.transfer) {
                        for (const serverId in cycle.server_name) {
                            const serverName = cycle.server_name[serverId];
                            const transfer = cycle.transfer[serverId];
                            const max = cycle.max;
                            
                            if (serverName && transfer !== undefined && max) {
                                serverMap.set(serverName, {
                                    id: serverId,         // 服务器ID
                                    transfer: transfer,   // 已使用流量(字节)
                                    max: max,            // 最大流量(字节)
                                    name: cycle.name     // 流量包名称
                                });
                            }
                        }
                    }
                }
                
                serverMap.forEach((serverData, serverName) => {
                    const targetElement = Array.from(document.querySelectorAll('section.grid.items-center.gap-2')).find(el => 
                        el.textContent.trim().includes(serverName));
                    
                    if (targetElement) {
                        
                        const usedFormatted = formatFileSize(serverData.transfer);
                        const totalFormatted = formatFileSize(serverData.max);
                        
                        const percentage = calculatePercentage(serverData.transfer, serverData.max);
                        
                        const uniqueClassName = 'traffic-stats-for-server-' + serverData.id;
                        
                        const insertedElement = targetElement.parentNode.querySelector('.' + uniqueClassName);
                        
                        if (insertedElement) {
                            const usedSpan = insertedElement.querySelector('.used-traffic');
                            const usedUnitSpan = insertedElement.querySelector('.used-unit');
                            const totalSpan = insertedElement.querySelector('.total-traffic');
                            const totalUnitSpan = insertedElement.querySelector('.total-unit');
                            const percentageSpan = insertedElement.querySelector('.percentage-value');
                            const progressBar = insertedElement.querySelector('.progress-bar');
                            
                            if (usedSpan) usedSpan.textContent = usedFormatted.value;
                            if (usedUnitSpan) usedUnitSpan.textContent = usedFormatted.unit;
                            if (totalSpan) totalSpan.textContent = totalFormatted.value;
                            if (totalUnitSpan) totalUnitSpan.textContent = totalFormatted.unit;
                            if (percentageSpan) percentageSpan.textContent = percentage + '%';
                            if (progressBar) progressBar.style.width = percentage + '%';
                            
                            return;
                        }
                        
                        
                        let currentElement = targetElement;
                        for (let i = 0; i < 2; i++) {
                            currentElement = currentElement.nextElementSibling;
                            if (!currentElement) {
                                currentElement = targetElement;
                                currentElement = currentElement.nextElementSibling;
                            }
                        }
                        
                        const newElement = document.createElement('div');
                        newElement.classList.add('space-y-1.5', 'new-inserted-element', uniqueClassName);
                        newElement.style.width = '100%';
                        
                        newElement.innerHTML = `
                            <div class="flex items-center justify-between">
                                <div class="flex items-baseline gap-1">
                                    <span class="text-sm font-medium text-neutral-800 dark:text-neutral-200 used-traffic">${usedFormatted.value}</span>
                                    <span class="text-sm font-medium text-neutral-800 dark:text-neutral-200 used-unit">${usedFormatted.unit}</span>
                                    <span class="text-xs text-neutral-500 dark:text-neutral-400">/ </span>
                                    <span class="text-xs text-neutral-500 dark:text-neutral-400 total-traffic">${totalFormatted.value}</span>
                                    <span class="text-xs text-neutral-500 dark:text-neutral-400 total-unit">${totalFormatted.unit}</span>
                                </div>
                                <span class="text-xs font-medium text-neutral-600 dark:text-neutral-300 percentage-value">${percentage}%</span>
                            </div>
                            <div class="relative h-1.5">
                                <div class="absolute inset-0 bg-neutral-100 dark:bg-neutral-800 rounded-full"></div>
                                <div class="absolute inset-0 bg-emerald-500 rounded-full transition-all duration-300 progress-bar" style="width: ${percentage}%;"></div>
                            </div>
                        `;
                        
                        currentElement.insertAdjacentElement('afterend', newElement);
                    } else {
                        console.log(`没有找到服务器 ${serverName}(ID: ${serverData.id}) 的元素`);
                    }
                });
            } else {
                console.log('API请求成功但返回数据不正确');
            }
        })
        .catch(error => {
            console.error('获取流量数据失败:', error);
        });
}, 3000);
</script>

服务器卡片下方显示周期性流量见给哪吒V1探针面板添加周期流量显示

文章作者: 子受
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 薪萤-博客
技术
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝