用旧苹果手机当nas监控副屏(二)

• 29 分钟阅读 • nas · linux · deepseek

前文实现了在苹果手机旧版ios(12.5.8)上nas实时信息的显示,背景是纯色或渐变色,有用但不够炫酷,比图灵智显差那么一些意思。本文在web界面上进行了改进。

ios12.5.8的webview不支持body的background属性设置,无法直接换背景。这里采用img标签显示全屏图片作为背景,再把要显示的信息小卡片放置在图片的指定位置上方。

status2.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>NAS监控仪表盘</title>
    <style>
        /* 基础重置 */
        * { margin: 0; padding: 0; box-sizing: border-box; }
        html, body { height: 100%; overflow: hidden; }

        /* 背景容器 */
        #bg-container {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
        }

        /* 背景图片样式 */
        #bg-image {
            width: 100%;
            height: 100%;
            object-fit: cover;
            min-width: 100%;
            min-height: 100%;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }

        /* 内容容器 - 减少遮罩透明度 */
        #content {
            position: relative;
            z-index: 1;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.1); /* 减少遮罩 */
        }

        /* 数据卡片样式 - 增大透明度 */
        .data-card {
            position: absolute;
            background-color: rgba(0, 20, 40, 0.5); /* 透明度从0.7改为0.5 */
            border: 1px solid rgba(100, 210, 255, 0.4); /* 边框更明显 */
            border-radius: 12px;
            padding: 15px 20px;
            text-align: center;
            text-shadow: 0 0 10px rgba(0, 0, 0, 0.9),
                         0 0 5px rgba(0, 0, 0, 0.7),
                         2px 2px 4px rgba(0, 0, 0, 0.5);
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
            backdrop-filter: blur(5px); /* 稍微增加模糊 */
            -webkit-backdrop-filter: blur(5px); /* Safari支持 */
            transition: all 0.3s ease; /* 添加过渡效果 */
        }

        /* 卡片悬停效果(可选) */
        .data-card:hover {
            background-color: rgba(0, 20, 40, 0.6); /* 悬停时稍微加深 */
            border-color: rgba(100, 210, 255, 0.6);
            box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5),
                        0 0 25px rgba(100, 210, 255, 0.2);
        }

        /* 前三个卡片 - 宽度较小 */
        .small-card {
            min-width: 120px;
            max-width: 140px;
        }

        /* 后三个卡片 - 宽度较大 */
        .large-card {
            min-width: 180px;
            max-width: 220px;
        }

        .card-title {
            font-size: 14px;
            font-weight: bold;
            color: #64d2ff;
            margin-bottom: 8px;
            display: block;
            letter-spacing: 1px;
        }

        .card-value {
            font-size: 28px;
            font-weight: bold;
            font-family: 'Courier New', Courier, monospace;
            color: #ffffff;
            display: block;
            line-height: 1.2;
            text-shadow: 0 0 10px rgba(100, 210, 255, 0.3); /* 增加文字发光 */
        }

        /* 运行时间字体较小 */
        #uptime-card .card-value {
            font-size: 22px;
        }

        /* 状态指示灯 */
        .status-indicator {
            display: inline-block;
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background-color: #34c759;
            margin-right: 8px;
            box-shadow: 0 0 8px #34c759;
        }

        /* 前三个卡片位置 - 顶部一行 */
        #cpu-card { 
            top: 15%; 
            left: 10%; 
        }
        #mem-card { 
            top: 15%; 
            left: 50%; 
            transform: translateX(-50%);
        }
        #disk-card { 
            top: 15%; 
            right: 10%; 
        }

        /* 后三个卡片位置 - 中间垂直排列 */
        #net-up-card { 
            top: 40%; 
            left: 50%; 
            transform: translateX(-50%);
        }
        #net-down-card { 
            top: 55%; 
            left: 50%; 
            transform: translateX(-50%);
        }
        #uptime-card { 
            top: 70%; 
            left: 50%; 
            transform: translateX(-50%);
        }

        /* 刷新指示器 */
        .refresh-indicator {
            position: fixed;
            top: 10px;
            right: 10px;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background-color: rgba(100, 210, 255, 0.3);
            z-index: 100;
            display: none;
        }
        
        .refresh-indicator.active {
            display: block;
            animation: pulse 1s infinite;
        }
        
        @keyframes pulse {
            0% { opacity: 0.3; }
            50% { opacity: 1; }
            100% { opacity: 0.3; }
        }

        /* 最后更新时间 */
        .last-update {
            position: fixed;
            bottom: 10px;
            right: 10px;
            color: rgba(255, 255, 255, 0.6); /* 提高可见度 */
            font-size: 12px;
            font-family: 'Courier New', Courier, monospace;
            z-index: 10;
            background-color: rgba(0, 0, 0, 0.3); /* 添加半透明背景 */
            padding: 5px 10px;
            border-radius: 5px;
            border: 1px solid rgba(255, 255, 255, 0.1);
        }

        /* 备用提示 */
        .fallback-message {
            display: none;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: white;
            text-align: center;
            background: rgba(0,0,0,0.8);
            padding: 20px;
            border-radius: 10px;
            z-index: 10;
            border: 1px solid rgba(255, 255, 255, 0.1);
        }

        /* iOS优化 */
        .data-card {
            -webkit-tap-highlight-color: transparent;
            -webkit-touch-callout: none;
            user-select: none;
        }
        
        /* 移动端适配 */
        @media (max-width: 768px) {
            .small-card {
                min-width: 100px;
                max-width: 120px;
                padding: 10px 15px;
            }
            
            .large-card {
                min-width: 150px;
                max-width: 180px;
                padding: 12px 18px;
            }
            
            .card-value {
                font-size: 24px;
            }
            
            #uptime-card .card-value {
                font-size: 18px;
            }
            
            /* 调整位置适应小屏幕 */
            #cpu-card { 
                top: 10%; 
                left: 5%; 
            }
            #mem-card { 
                top: 10%; 
                left: 50%; 
                transform: translateX(-50%);
            }
            #disk-card { 
                top: 10%; 
                right: 5%; 
            }
            
            #net-up-card { 
                top: 35%; 
            }
            #net-down-card { 
                top: 55%; 
            }
            #uptime-card { 
                top: 80%; 
            }
            
            /* 移动端减小透明度 */
            .data-card {
                background-color: rgba(0, 20, 40, 0.6);
            }
        }
        
        /* 超小屏幕适配 */
        @media (max-width: 480px) {
            .small-card {
                min-width: 90px;
                max-width: 110px;
                padding: 8px 12px;
            }
            
            .large-card {
                min-width: 130px;
                max-width: 160px;
                padding: 10px 15px;
            }
            
            .card-value {
                font-size: 20px;
            }
            
            #uptime-card .card-value {
                font-size: 16px;
            }
            
            .card-title {
                font-size: 12px;
            }
        }
    </style>
</head>
<body>
    <!-- 刷新指示器 -->
    <div class="refresh-indicator" id="refresh-indicator"></div>
    
    <!-- 最后更新时间 -->
    <div class="last-update" id="last-update">--:--:--</div>

    <!-- 背景容器 -->
    <div id="bg-container">
        <img id="bg-image" 
             src="dashboard-bg3.jpg" 
             alt="仪表盘背景"
             onerror="showFallback()">
        <!-- 备用纯色背景 -->
        <div style="position:absolute; top:0; left:0; width:100%; height:100%; background:linear-gradient(135deg, #0f2027 0%, #203a43 100%); display:none;" 
             id="fallback-bg"></div>
    </div>

    <!-- 备用提示 -->
    <div class="fallback-message" id="fallback-msg">
        <p>仪表盘背景加载失败</p>
        <p>正在使用简约模式</p>
    </div>

    <!-- 内容区域 -->
    <div id="content">
        <!-- 前三个卡片 - 小宽度 -->
        <div class="data-card small-card" id="cpu-card">
            <span class="card-title"><span class="status-indicator"></span>CPU</span>
            <span class="card-value" id="cpu-value">--</span>
        </div>

        <div class="data-card small-card" id="mem-card">
            <span class="card-title"><span class="status-indicator"></span>内存</span>
            <span class="card-value" id="mem-value">--</span>
        </div>

        <div class="data-card small-card" id="disk-card">
            <span class="card-title">💾 存储</span>
            <span class="card-value" id="disk-value">--</span>
        </div>

        <!-- 后三个卡片 - 大宽度 -->
        <div class="data-card large-card" id="net-up-card">
            <span class="card-title">▲ 上传速度</span>
            <span class="card-value" id="net-up-value">--</span>
        </div>

        <div class="data-card large-card" id="net-down-card">
            <span class="card-title">▼ 下载速度</span>
            <span class="card-value" id="net-down-value">--</span>
        </div>

        <div class="data-card large-card" id="uptime-card">
            <span class="card-title">⏱️ 运行时间</span>
            <span class="card-value" id="uptime-value">--</span>
        </div>
    </div>

<script>
// 全局状态
var lastUpdateTime = null;
var refreshInterval = null;
var isPageVisible = true;

// 显示刷新指示器
function showRefreshIndicator() {
    var indicator = document.getElementById('refresh-indicator');
    indicator.classList.add('active');
    setTimeout(function() {
        indicator.classList.remove('active');
    }, 1000);
}

// 更新最后更新时间显示
function updateLastUpdateTime() {
    var now = new Date();
    var timeString = now.toLocaleTimeString('zh-CN', { 
        hour12: false,
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit'
    });
    document.getElementById('last-update').textContent = '更新: ' + timeString;
    lastUpdateTime = now;
}

// 图片加载失败处理
function showFallback() {
    document.getElementById('fallback-bg').style.display = 'block';
    document.getElementById('fallback-msg').style.display = 'block';
    console.log('背景图加载失败,使用备用背景');
}

// 从status.json获取数据
function fetchData() {
    showRefreshIndicator();
    
    // iOS 12需要强制清除缓存
    var url = 'status.json?_=' + new Date().getTime();
    
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.timeout = 8000;
    
    // 设置缓存控制
    xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
    xhr.setRequestHeader('Pragma', 'no-cache');
    xhr.setRequestHeader('Expires', '0');
    
    xhr.onload = function() {
        if (xhr.status === 200 || xhr.status === 0) {
            try {
                var data = JSON.parse(xhr.responseText);
                updateDisplay(data);
                updateLastUpdateTime();
                console.log('数据更新成功:', new Date().toLocaleTimeString());
            } catch(e) {
                console.error('数据解析错误:', e);
                showDataError();
            }
        } else {
            console.error('HTTP错误:', xhr.status);
            showDataError();
        }
    };
    
    xhr.onerror = function() {
        console.error('网络请求错误');
        showDataError();
    };
    
    xhr.ontimeout = function() {
        console.error('请求超时');
        showDataError();
    };
    
    try {
        xhr.send();
    } catch(e) {
        console.error('发送请求错误:', e);
        showDataError();
    }
}

// 更新显示
function updateDisplay(data) {
    console.log('更新数据显示');
    
    // CPU
    var cpuText = data.cpu || "--";
    document.getElementById('cpu-value').textContent = cpuText;
    
    // 内存
    var memText = data.memory ? (data.memory.usage || "--") : "--";
    document.getElementById('mem-value').textContent = memText;
    
    // 存储
    var diskText = data.disk ? (data.disk.usage || "--") : "--";
    document.getElementById('disk-value').textContent = diskText;
    
    // 网络 - 直接使用JSON中的完整字符串
    var downText = data.network ? (data.network.download_speed || "--") : "--";
    var upText = data.network ? (data.network.upload_speed || "--") : "--";
    
    document.getElementById('net-down-value').textContent = downText;
    document.getElementById('net-up-value').textContent = upText;
    
    // 运行时间 - 直接显示JSON中的完整字符串
    var uptimeText = data.system ? (data.system.uptime || "--") : "--";
    document.getElementById('uptime-value').textContent = uptimeText;
    
    // 动态更新状态指示灯颜色
    updateIndicatorColor('cpu', extractNumber(cpuText));
    updateIndicatorColor('mem', extractNumber(memText));
    updateIndicatorColor('disk', extractNumber(diskText));
}

// 从文本中提取数字
function extractNumber(text) {
    if (text === "--") return 0;
    var match = text.match(/(\d+(\.\d+)?)/);
    return match ? parseFloat(match[1]) : 0;
}

// 更新状态指示灯颜色
function updateIndicatorColor(type, value) {
    var indicator = document.querySelector('#' + type + '-card .status-indicator');
    if (!indicator) return;
    
    // 重置样式
    indicator.style.backgroundColor = '#34c759';
    indicator.style.boxShadow = '0 0 8px #34c759';
    
    if (value > 80) {
        indicator.style.backgroundColor = '#ff3b30';
        indicator.style.boxShadow = '0 0 8px #ff3b30';
    } else if (value > 60) {
        indicator.style.backgroundColor = '#ff9500';
        indicator.style.boxShadow = '0 0 8px #ff9500';
    }
}

// 数据显示错误
function showDataError() {
    var cards = document.querySelectorAll('.data-card');
    cards.forEach(function(card) {
        var valueElem = card.querySelector('.card-value');
        if (valueElem) {
            valueElem.textContent = 'ERR';
            valueElem.style.color = '#ff6b6b';
        }
    });
}

// 初始化定时刷新
function initRefreshTimer() {
    // 清除现有定时器
    if (refreshInterval) {
        clearInterval(refreshInterval);
    }
    
    // 设置新的定时器 - 每10秒刷新
    refreshInterval = setInterval(function() {
        if (isPageVisible) {
            fetchData();
        }
    }, 10000);
}

// 页面可见性处理
document.addEventListener('visibilitychange', function() {
    isPageVisible = !document.hidden;
    console.log('页面可见性:', isPageVisible ? '可见' : '隐藏');
    
    if (isPageVisible) {
        // 页面重新可见时立即刷新
        fetchData();
        initRefreshTimer();
    } else {
        // 页面隐藏时停止定时器
        if (refreshInterval) {
            clearInterval(refreshInterval);
            refreshInterval = null;
        }
    }
});

// 防止iOS页面缓存
window.addEventListener('pageshow', function(event) {
    if (event.persisted) {
        console.log('页面从缓存恢复,强制刷新');
        fetchData();
    }
});

// 添加手动刷新功能(点击任意位置刷新)
document.addEventListener('click', function(e) {
    // 避免点击刷新指示器时触发
    if (e.target.id !== 'refresh-indicator') {
        fetchData();
    }
});

// 页面加载完成
window.addEventListener('load', function() {
    console.log('NAS监控仪表盘初始化...');
    
    // 初始化最后更新时间
    updateLastUpdateTime();
    
    // 立即加载数据
    fetchData();
    
    // 初始化定时器
    initRefreshTimer();
    
    // 检查背景图片
    var bgImg = document.getElementById('bg-image');
    if (bgImg.complete) {
        console.log('背景图片已加载');
    } else {
        bgImg.onload = function() {
            console.log('背景图片加载完成');
        };
        bgImg.onerror = function() {
            console.log('背景图片加载失败');
        };
    }
    
    // 添加触摸事件支持
    document.addEventListener('touchstart', function() {}, {passive: true});
});

// 页面卸载清理
window.addEventListener('beforeunload', function() {
    if (refreshInterval) {
        clearInterval(refreshInterval);
    }
});

// 添加键盘快捷键支持(可选)
document.addEventListener('keydown', function(e) {
    if (e.code === 'Space' || e.code === 'KeyR') {
        fetchData();
        e.preventDefault();
    }
});
</script>
</body>
</html>

<img id="bg-image" src="dashboard-bg3.jpg" alt="仪表盘背景" onerror="showFallback()">
更改src对应的图片就可以更换背景图。
各信息标签的位置是通过相对top百分比位置设置的,是针对小屏手机设置,iphone5s的浏览器显示范围640*1000,在更大屏手机上显示可能太松散,可自行调整。

体验




html代码依然是deepseek生成,手动做少量调整。

文章标签: nas, linux, deepseek

上一篇 : 一个简单的书影音记录应用
下一篇 : 用旧苹果手机当nas监控副屏(一)
留言
阅读进度 0%