TJ-DORM-WIFI 辅助

同济大学宿舍网络登录助手

// ==UserScript==
// @name         TJ-DORM-WIFI 辅助
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  同济大学宿舍网络登录助手
// @author       kexu
// @match        http://172.21.0.54/*
// @match        http://172.21.0.54:8080/*
// @match        http://172.21.0.54/index.html*
// @match        http://172.21.0.54/drcom/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @connect      172.21.0.54
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // 添加全局样式
    GM_addStyle(`
        .tj-wifi-container {
            position: fixed !important;
            top: 20px !important;
            right: 20px !important;
            bottom: 20px !important; /* 添加底部边距 */
            z-index: 999999999 !important;
            background: white !important;
            padding: 24px !important;
            border-radius: 20px !important;
            box-shadow: 0 8px 30px rgba(0,0,0,0.1) !important;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
            width: 380px !important; /* 固定宽度 */
            height: auto !important;
            max-height: calc(100vh - 40px) !important; /* 视窗高度减去上下边距 */
            visibility: visible !important;
            opacity: 1 !important;
            display: flex !important;
            flex-direction: column !important;
            pointer-events: auto !important;
            transform: none !important;
            backdrop-filter: blur(10px) !important;
            -webkit-backdrop-filter: blur(10px) !important;
            overflow: hidden !important;
        }

        .tj-wifi-container h2 {
            margin: 0 0 24px 0 !important;
            text-align: center !important;
            color: #1a202c !important;
            font-size: 22px !important;
            font-weight: 600 !important;
        }

        .tj-wifi-container input,
        .tj-wifi-container select {
            width: 100% !important;
            padding: 14px !important;
            border: 1px solid #e2e8f0 !important;
            border-radius: 16px !important;
            font-size: 15px !important;
            transition: all 0.3s ease !important;
            box-sizing: border-box !important;
            background: #f8fafc !important;
            margin-bottom: 12px !important;
            color: #1a202c !important;
            -webkit-appearance: none !important;
            appearance: none !important;
        }

        .tj-wifi-container select {
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23475569' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E") !important;
            background-repeat: no-repeat !important;
            background-position: right 12px center !important;
            background-size: 16px !important;
            padding-right: 40px !important;
        }

        .tj-wifi-container input:focus,
        .tj-wifi-container select:focus {
            border-color: #3b82f6 !important;
            outline: none !important;
            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1) !important;
            background: white !important;
        }

        .tj-wifi-container button {
            width: 100% !important;
            padding: 14px !important;
            border: none !important;
            border-radius: 16px !important;
            font-size: 15px !important;
            font-weight: 600 !important;
            cursor: pointer !important;
            transition: all 0.3s ease !important;
            margin-bottom: 12px !important;
            color: white !important;
            position: relative !important;
            overflow: hidden !important;
        }

        .tj-wifi-container button:hover {
            transform: translateY(-1px) !important;
            box-shadow: 0 4px 12px rgba(0,0,0,0.1) !important;
        }

        .tj-wifi-container button:active {
            transform: translateY(0) !important;
        }

        .tj-wifi-container button.login-btn {
            background: linear-gradient(135deg, #3b82f6, #10b981) !important;
        }

        .tj-wifi-container button.logout-btn {
            background: linear-gradient(135deg, #ef4444, #f59e0b) !important;
        }

        .tj-wifi-container button.device-btn {
            background: linear-gradient(135deg, #06b6d4, #0ea5e9) !important;
        }

        .status-card {
            background: #ffffff !important;
            border-radius: 12px !important;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) !important;
            overflow: hidden !important;
            border: 1px solid #e2e8f0 !important;
        }

        .status-header {
            padding: 12px 16px !important;
            background: #f8fafc !important;
            border-bottom: 1px solid #e2e8f0 !important;
            display: flex !important;
            align-items: center !important;
            gap: 8px !important;
        }

        .status-content {
            padding: 20px !important;
        }

        .status-row {
            display: flex !important;
            justify-content: space-between !important;
            align-items: center !important;
            margin-bottom: 16px !important;
            font-size: 14px !important;
            padding: 4px 8px !important;
            background: #f8fafc !important;
            border-radius: 6px !important;
        }

        .status-row:last-child {
            margin-bottom: 0 !important;
        }

        .status-label {
            color: #64748b !important;
            font-weight: 500 !important;
        }

        .status-value {
            color: #1e293b !important;
            font-weight: 600 !important;
        }

        .status-icon {
            display: inline-flex !important;
            align-items: center !important;
            justify-content: center !important;
            width: 20px !important;
            height: 20px !important;
            background: #dcfce7 !important;
            color: #16a34a !important;
            border-radius: 50% !important;
            font-size: 12px !important;
        }

        .status-footer {
            padding: 12px 16px !important;
            background: #f8fafc !important;
            border-top: 1px solid #e2e8f0 !important;
            font-size: 13px !important;
            color: #64748b !important;
            text-align: right !important;
        }

        .device-list {
            flex: 1 1 auto !important;
            overflow-y: auto !important;
            margin-top: 16px !important;
            padding-right: 8px !important;
            width: 100% !important; /* 确保列表占满容器宽度 */
        }

        .device-list::-webkit-scrollbar {
            width: 6px !important;
        }

        .device-list::-webkit-scrollbar-track {
            background: #f1f1f1 !important;
            border-radius: 3px !important;
        }

        .device-list::-webkit-scrollbar-thumb {
            background: #888 !important;
            border-radius: 3px !important;
        }

        .device-list::-webkit-scrollbar-thumb:hover {
            background: #555 !important;
        }

        .device-list-header {
            color: #64748b !important;
            font-size: 14px !important;
            margin-bottom: 12px !important;
            padding: 0 4px !important;
        }

        .device-card {
            background: #f8fafc !important;
            border-radius: 16px !important;
            padding: 16px !important;
            margin-bottom: 12px !important;
            border: 1px solid #e2e8f0 !important;
        }

        .device-card .device-header {
            display: flex !important;
            justify-content: space-between !important;
            align-items: center !important;
            margin-bottom: 12px !important;
            padding-bottom: 8px !important;
            border-bottom: 1px solid #e2e8f0 !important;
        }

        .device-card .device-title {
            color: #1e293b !important;
            font-weight: 600 !important;
            font-size: 15px !important;
        }

        .device-card .device-status {
            padding: 4px 12px !important;
            border-radius: 20px !important;
            font-size: 13px !important;
            background: #dcfce7 !important;
            color: #10b981 !important;
            font-weight: 500 !important;
        }

        .device-info-row {
            display: flex !important;
            justify-content: space-between !important;
            margin-bottom: 8px !important;
            font-size: 14px !important;
        }

        .device-info-row:last-child {
            margin-bottom: 0 !important;
        }

        .device-info-label {
            color: #64748b !important;
        }

        .device-info-value {
            color: #1e293b !important;
            font-weight: 500 !important;
        }

        .device-list-card {
            width: 100% !important;
            background: white !important;
            border-radius: 8px !important;
            overflow: hidden !important;
            border: 1px solid #17a2b820 !important;
        }
    `);

    // 检查UI是否已存在
    function isUIExists() {
        return document.getElementById('login-container') !== null;
    }

    // 创建UI
    function createUI() {
        try {
            console.log('[TJ-WIFI] 开始创建UI...');
            if (isUIExists()) {
                console.log('[TJ-WIFI] UI已存在,跳过创建');
                return;
            }

            const container = document.createElement('div');
            container.id = 'login-container';
            container.className = 'tj-wifi-container';
            console.log('[TJ-WIFI] 创建container元素');

            // 添加标题
            const title = document.createElement('h2');
            title.textContent = 'TJ-DORM-WIFI 辅助';
            title.style.cssText = `
                margin: 0 0 20px 0;
                text-align: center;
                color: #2c3e50;
                font-size: 20px;
                font-weight: 600;
            `;
            container.appendChild(title);

            // 添加登录部分
            const loginSection = document.createElement('div');
            loginSection.style.cssText = `
                display: flex;
                flex-direction: column;
                gap: 12px;
                margin-bottom: 20px;
            `;

            // 添加用户名输入框
            const username = document.createElement('input');
            username.id = 'username';
            username.type = 'text';
            username.placeholder = '学号';
            username.value = GM_getValue('username', '');

            // 添加密码输入框
            const password = document.createElement('input');
            password.id = 'password';
            password.type = 'password';
            password.placeholder = '密码';
            password.value = GM_getValue('password', '');

            // 添加网络选择下拉框
            const networkSelector = document.createElement('select');
            networkSelector.id = 'network-type';
            networkSelector.innerHTML = `
                <option value="0">校园网</option>
                <option value="2">中国移动</option>
                <option value="3">中国联通</option>
                <option value="4">中国电信</option>
            `;

            const savedNetworkType = GM_getValue('networkType', '0');
            networkSelector.value = savedNetworkType;

            networkSelector.addEventListener('change', function() {
                GM_setValue('networkType', this.value);
            });

            // 添加按钮容器
            const buttonContainer = document.createElement('div');
            buttonContainer.style.cssText = `
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 10px;
                margin-top: 10px;
            `;

            // 添加登录按钮
            const loginButton = document.createElement('button');
            loginButton.textContent = '登录';
            loginButton.className = 'login-btn';
            loginButton.addEventListener('click', autoLogin);

            // 添加登出按钮
            const logoutButton = document.createElement('button');
            logoutButton.textContent = '登出';
            logoutButton.className = 'logout-btn';
            logoutButton.addEventListener('click', autoLogout);

            // 添加设备列表按钮
            const deviceButton = document.createElement('button');
            deviceButton.textContent = '查看设备列表';
            deviceButton.className = 'device-btn';
            deviceButton.addEventListener('click', getDeviceList);

            // 添加状态显示区域
            const statusDiv = document.createElement('div');
            statusDiv.id = 'login-status';
            statusDiv.className = 'status-card';

            // 添加设备列表显示区域
            const deviceListDiv = document.createElement('div');
            deviceListDiv.id = 'device-list';
            deviceListDiv.style.cssText = `
                margin-top: 15px;
                display: none;
            `;

            // 组装UI
            loginSection.appendChild(username);
            loginSection.appendChild(password);
            loginSection.appendChild(networkSelector);
            buttonContainer.appendChild(loginButton);
            buttonContainer.appendChild(logoutButton);
            buttonContainer.appendChild(deviceButton);
            loginSection.appendChild(buttonContainer);
            container.appendChild(loginSection);
            container.appendChild(statusDiv);
            container.appendChild(deviceListDiv);

            document.body.appendChild(container);
            console.log('[TJ-WIFI] UI创建成功');

            // 保存用户名和密码
            username.addEventListener('change', () => {
                console.log('[TJ-WIFI] 保存用户名');
                GM_setValue('username', username.value);
            });
            password.addEventListener('change', () => {
                console.log('[TJ-WIFI] 保存密码');
                GM_setValue('password', password.value);
            });
        } catch (error) {
            console.error('[TJ-WIFI] 创建UI时发生错误:', error);
        }
    }

    // 自动登录功能
    function autoLogin() {
        const username = document.getElementById('username')?.value;
        const password = document.getElementById('password')?.value;
        const networkType = document.getElementById('network-type')?.value || '0';

        if (!username || !password) {
            updateStatus('请输入用户名和密码', 'error');
            return;
        }

        // 根据网络类型构建登录参数
        const loginParams = {
            callback: 'dr1003',
            DDDDD: username,
            upass: password,
            '0MKKey': '123456',
            R1: '0',
            R2: '',
            R3: networkType,  // 使用选择的网络类型
            R6: '0',
            para: '00',
            v6ip: '',
            terminal_type: '1',
            lang: 'zh-cn',
            jsVersion: '4.1',
            v: '2653',
            lang: 'zh'
        };

        // 构建URL参数字符串
        const queryString = Object.entries(loginParams)
            .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
            .join('&');

        const loginUrl = `http://172.21.0.54/drcom/login?${queryString}`;

        GM_xmlhttpRequest({
            method: 'GET',
            url: loginUrl,
            onload: function(response) {
                if (response.status === 200) {
                    updateStatus('登录请求已发送...', 'info');
                    setTimeout(() => {
                        checkLoginStatus(() => {
                            setTimeout(() => {
                                window.location.reload();
                            }, 300);
                        });
                    }, 500);
                } else {
                    updateStatus('登录请求失败', 'error');
                    setTimeout(() => {
                        window.location.reload();
                    }, 800);
                }
            },
            onerror: function() {
                updateStatus('网络错误', 'error');
                setTimeout(() => {
                    window.location.reload();
                }, 800);
            }
        });
    }

    // 自动登出功能
    function autoLogout() {
        GM_xmlhttpRequest({
            method: 'GET',
            url: 'http://172.21.0.54/drcom/logout?callback=dr1006',
            onload: function(response) {
                if (response.status === 200) {
                    updateStatus('已登出', 'success');
                    setTimeout(() => {
                        window.location.reload();
                    }, 800);
                } else {
                    updateStatus('登出失败', 'error');
                    setTimeout(() => {
                        window.location.reload();
                    }, 800);
                }
            },
            onerror: function() {
                updateStatus('网络错误', 'error');
                setTimeout(() => {
                    window.location.reload();
                }, 800);
            }
        });
    }

    // 检查登录状态
    function checkLoginStatus(callback) {
        console.log('[TJ-WIFI] 开始检查登录状态');
        GM_xmlhttpRequest({
            method: 'GET',
            url: 'http://172.21.0.54/',
            timeout: 5000,
            onload: function(response) {
                try {
                    const isLoggedIn = response.responseText.includes('注销页') &&
                                     !response.responseText.includes('上网登录页');

                    if (isLoggedIn) {
                        console.log('[TJ-WIFI] 检测到已登录状态');
                        const uidMatch = response.responseText.match(/uid\s*=\s*["']([^"']+)["']/);
                        const nameMatch = response.responseText.match(/NID\s*=\s*["']([^"']+)["']/);
                        const ipMatch = response.responseText.match(/v4ip\s*=\s*["']([^"']+)["']/);
                        const loginTimeMatch = response.responseText.match(/stime\s*=\s*["']([^"']+)["']/);

                        const uid = uidMatch ? uidMatch[1].trim() : '未知';
                        const name = nameMatch ? nameMatch[1].trim() : '未知';
                        const ip = ipMatch ? ipMatch[1].trim() : '未知';
                        const loginTime = loginTimeMatch ? loginTimeMatch[1].trim() : '未知';

                        const statusInfo = {
                            type: 'success',
                            status: '在线',
                            details: {
                                学号: uid,
                                姓名: name,
                                IP: ip,
                                登录时间: loginTime
                            }
                        };
                        updateStatusWithFormat(statusInfo);
                    } else {
                        console.log('[TJ-WIFI] 检测到未登录状态');
                        updateStatusWithFormat({
                            type: 'error',
                            status: '离线',
                            message: '未登录'
                        });
                    }

                    if (callback) callback();
                } catch (error) {
                    console.error('[TJ-WIFI] 解析登录状态失败:', error);
                    updateStatusWithFormat({
                        type: 'warning',
                        status: '错误',
                        message: '状态检查失败'
                    });
                    if (callback) callback();
                }
            },
            onerror: function() {
                console.error('[TJ-WIFI] 网络请求失败');
                updateStatusWithFormat({
                    type: 'error',
                    status: '错误',
                    message: '网络请求失败'
                });
                if (callback) callback();
            }
        });
    }

    // 格式化状态显示
    function updateStatusWithFormat(statusInfo) {
        const statusDiv = document.getElementById('login-status');
        if (!statusDiv) return;

        // 立即显示一个加载状态
        if (!statusDiv.innerHTML) {
            statusDiv.innerHTML = `
                <div class="status-card">
                    <div class="status-header">
                        <span style="color: #17a2b8;">⟳</span>
                        <span style="color: #17a2b8; font-weight: 500;">正在检查状态...</span>
                    </div>
                    <div class="status-content">
                        <div style="text-align: center; color: #4a5568;">
                            正在获取网络状态信息
                        </div>
                    </div>
                </div>
            `;
            statusDiv.style.display = 'block';
        }

        let content = '';

        if (statusInfo.type === 'success' && statusInfo.details) {
            content = `
                <div class="status-card">
                    <div class="status-header">
                        <span class="status-icon">✓</span>
                        <span style="color: #28a745; font-weight: 500;">在线</span>
                    </div>
                    <div class="status-content">
                        <div class="status-row">
                            <span class="status-label">学号</span>
                            <span class="status-value">${statusInfo.details.学号}</span>
                        </div>
                        <div class="status-row">
                            <span class="status-label">姓名</span>
                            <span class="status-value">${statusInfo.details.姓名}</span>
                        </div>
                        <div class="status-row">
                            <span class="status-label">IP</span>
                            <span class="status-value">${statusInfo.details.IP}</span>
                        </div>
                        <div class="status-row">
                            <span class="status-label">登录时间</span>
                            <span class="status-value">${statusInfo.details.登录时间}</span>
                        </div>
                    </div>
                    <div class="status-footer">
                        更新时间: ${new Date().toLocaleTimeString()}
                    </div>
                </div>
            `;
        } else {
            const colors = {
                error: '#dc3545',
                info: '#17a2b8',
                warning: '#ffc107'
            };

            content = `
                <div class="status-card">
                    <div class="status-header">
                        <span style="color: ${colors[statusInfo.type]};">${
                            statusInfo.type === 'error' ? '✗' :
                            statusInfo.type === 'warning' ? '⚠️' : 'ℹ'
                        }</span>
                        <span style="color: ${colors[statusInfo.type]}; font-weight: 500;">
                            ${statusInfo.status}
                        </span>
                    </div>
                    <div class="status-content">
                        <div style="text-align: center; color: #4a5568;">
                            ${statusInfo.message}
                        </div>
                    </div>
                    <div class="status-footer">
                        更新时间: ${new Date().toLocaleTimeString()}
                    </div>
                </div>
            `;
        }

        statusDiv.innerHTML = content;
        statusDiv.style.display = 'block';
    }

    // 更新状态显示(兼容旧的调用方式)
    function updateStatus(message, type = 'info') {
        if (message.includes('在线')) {
            const parts = message.split(' ');
            updateStatusWithFormat({
                type: 'success',
                status: '在线',
                details: {
                    学号: parts[2].split(':')[1],
                    姓名: parts[3].split(':')[1],
                    IP: parts[4].split(':')[1],
                    登录时间: parts[5].split(':').slice(1).join(':')
                }
            });
        } else {
            updateStatusWithFormat({
                type,
                status: type === 'success' ? '成功' : type === 'error' ? '错误' : '提示',
                message
            });
        }
    }

    // 获取设备列表
    function getDeviceList() {
        const username = document.getElementById('username')?.value;

        if (!username) {
            updateStatus('请先输入学号', 'error');
            return;
        }

        const deviceListUrl = `http://172.21.0.54:801/eportal/portal/mac/find?callback=dr1002&user_account=${username}`;

        GM_xmlhttpRequest({
            method: 'GET',
            url: deviceListUrl,
            headers: {
                'Host': '172.21.0.54:801',
                'Connection': 'keep-alive',
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
                'Accept': '*/*',
                'Sec-GPC': '1',
                'Accept-Language': 'zh-CN,zh',
                'Referer': 'http://172.21.0.54/'
            },
            onload: function(response) {
                try {
                    // 解析返回的数据
                    let jsonStr = response.responseText;

                    // 调试输出
                    console.log('Raw response:', jsonStr);

                    // 提取JSON部分
                    const match = jsonStr.match(/dr1002\((.*)\)/);
                    if (!match || !match[1]) {
                        throw new Error('Invalid response format');
                    }
                    jsonStr = match[1];

                    // 调试输出
                    console.log('Extracted JSON:', jsonStr);

                    const data = JSON.parse(jsonStr);
                    console.log('Parsed data:', data);

                    if (data.result === 1 && Array.isArray(data.list)) {
                        displayDeviceList(data.list, data.total);
                    } else {
                        updateDeviceListStatus(data.msg || '无设备数据', 'info');
                    }
                } catch (error) {
                    console.error('解析设备列表失败:', error);
                    console.error('原始数据:', response.responseText);
                    updateDeviceListStatus('获取设备列表失败: ' + error.message, 'error');
                }
            },
            onerror: function() {
                updateDeviceListStatus('网络请求失败', 'error');
            }
        });
    }

    // 显示设备列表
    function displayDeviceList(devices, total) {
        const deviceListDiv = document.getElementById('device-list');
        if (!deviceListDiv) return;

        // 确保容器可以滚动
        deviceListDiv.style.display = 'block';
        deviceListDiv.style.maxHeight = '400px';
        deviceListDiv.style.overflowY = 'auto';
        deviceListDiv.style.overflowX = 'hidden';
        deviceListDiv.style.paddingRight = '10px';
        deviceListDiv.style.position = 'relative';

        // 生成设备列表HTML
        let content = `
            <div class="device-list-card" style="
                background: white;
                border-radius: 8px;
                overflow: hidden;
                border: 1px solid #17a2b820;
            ">
                <div style="
                    display: flex;
                    align-items: center;
                    padding: 12px;
                    background: #17a2b810;
                    border-bottom: 1px solid #17a2b820;
                    position: sticky;
                    top: 0;
                    z-index: 1;
                    background: white;
                ">
                    <span style="
                        color: #17a2b8;
                        font-weight: 500;
                        display: flex;
                        align-items: center;
                        gap: 8px;
                    ">
                        设备列表 (共${total}台)
                    </span>
                </div>
                <div style="padding: 12px;">
                    <div style="
                        display: grid;
                        gap: 16px;
                        color: #4a5568;
                    ">
        `;

        // 添加每个设备的信息
        devices.forEach((device, index) => {
            // 计算在线时长
            const timeLong = parseInt(device.time_long);
            const hours = Math.floor(timeLong / 3600);
            const minutes = Math.floor((timeLong % 3600) / 60);
            const seconds = timeLong % 60;
            const timeStr = `${hours}小时${minutes}分${seconds}秒`;

            // 计算流量
            const uplink = (parseInt(device.uplink_bytes) / 1024 / 1024).toFixed(2);
            const downlink = (parseInt(device.downlink_bytes) / 1024 / 1024).toFixed(2);

            // 格式化登录时间
            const loginTime = device.online_time.split(' ');
            const datePart = loginTime[0];
            const timePart = loginTime[1];

            content += `
                <div style="
                    padding: 12px;
                    background: #e3f2fd;
                    border-radius: 6px;
                    border: 1px solid #90caf9;
                ">
                    <div style="
                        display: flex;
                        justify-content: space-between;
                        align-items: center;
                        margin-bottom: 8px;
                    ">
                        <span style="
                            font-weight: 500;
                            color: #1976d2;
                        ">
                            设备 ${index + 1}
                        </span>
                        <span style="
                            font-size: 12px;
                            padding: 2px 8px;
                            border-radius: 12px;
                            background: #28a74520;
                            color: #28a745;
                        ">
                            在线
                        </span>
                    </div>
                    <div style="display: grid; gap: 4px;">
                        <div style="display: flex; justify-content: space-between;">
                            <span style="color: #718096; font-size: 13px;">MAC地址</span>
                            <span style="text-align: right;">${device.online_mac || '-'}</span>
                        </div>
                        <div style="display: flex; justify-content: space-between;">
                            <span style="color: #718096; font-size: 13px;">IP地址</span>
                            <span style="text-align: right;">${device.online_ip || '-'}</span>
                        </div>
                        <div style="display: flex; justify-content: space-between; align-items: flex-start;">
                            <span style="color: #718096; font-size: 13px;">登录时间</span>
                            <span style="text-align: right;">
                                ${datePart}<br>${timePart}
                            </span>
                        </div>
                        <div style="display: flex; justify-content: space-between;">
                            <span style="color: #718096; font-size: 13px;">在线时长</span>
                            <span style="text-align: right;">${timeStr}</span>
                        </div>
                        <div style="display: flex; justify-content: space-between;">
                            <span style="color: #718096; font-size: 13px;">上行流量</span>
                            <span style="text-align: right;">${uplink} MB</span>
                        </div>
                        <div style="display: flex; justify-content: space-between;">
                            <span style="color: #718096; font-size: 13px;">下行流量</span>
                            <span style="text-align: right;">${downlink} MB</span>
                        </div>
                    </div>
                </div>
            `;
        });

        content += `
                </div>
            </div>
        </div>
    `;

    // 设置内容并确保可滚动
    deviceListDiv.innerHTML = content;
    deviceListDiv.style.webkitOverflowScrolling = 'touch'; // 移动端平滑滚动
    }

    // 更新设备列表状态
    function updateDeviceListStatus(message, type) {
        const deviceListDiv = document.getElementById('device-list');
        if (!deviceListDiv) return;

        deviceListDiv.style.display = 'block';

        const colors = {
            success: '#28a745',
            error: '#dc3545',
            info: '#17a2b8',
            warning: '#ffc107'
        };

        deviceListDiv.innerHTML = `
            <div style="
                padding: 12px;
                color: ${colors[type]};
                text-align: center;
                background: white;
                border-radius: 8px;
                border: 1px solid ${colors[type]}20;
            ">
                ${message}
            </div>
        `;
    }

    // 启动登录状态检查
    function startLoginStatusCheck() {
        checkLoginStatus();
        setInterval(checkLoginStatus, 30000);
    }

    // 初始化脚本
    function initScript() {
        console.log('[TJ-WIFI] 开始初始化脚本...');
        console.log('[TJ-WIFI] 当前URL:', window.location.href);

        if (window.top !== window.self) {
            console.log('[TJ-WIFI] 脚本在iframe中,停止初始化');
            return;
        }

        if (window.tjWifiInitialized) {
            console.log('[TJ-WIFI] 脚本已初始化,停止初始化');
            return;
        }

        // 使用 MutationObserver 监听页面变化,防止页面被重定向或修改
        const observer = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                // 检查是否有元素被移除
                if (mutation.removedNodes.length > 0) {
                    ensureUIExists();
                }
                // 检查是否有元素被添加
                if (mutation.addedNodes.length > 0) {
                    ensureUIExists();
                }
            });
        });

        // 监听整个文档的变化
        observer.observe(document.documentElement, {
            childList: true,
            subtree: true
        });

        window.tjWifiInitialized = true;
        console.log('[TJ-WIFI] 设置初始化标志');

        // 确保UI始终存在
        function ensureUIExists() {
            if (!isUIExists()) {
                console.log('[TJ-WIFI] UI不存在,重新创建');
                createUI();
                // 立即检查一次登录状态
                checkLoginStatus();
            }
        }

        try {
            // 立即创建UI并检查状态
            createUI();
            checkLoginStatus();

            // 定期检查UI是否存在和登录状态
            setInterval(() => {
                ensureUIExists();
                checkLoginStatus();
            }, 30000);

            // 添加页面卸载监听器
            window.addEventListener('beforeunload', () => {
                console.log('[TJ-WIFI] 页面即将卸载');
            });

            // 添加页面可见性变化监听器
            document.addEventListener('visibilitychange', () => {
                console.log('[TJ-WIFI] 页面可见性变化:', document.visibilityState);
                if (document.visibilityState === 'visible') {
                    ensureUIExists();
                    checkLoginStatus();
                }
            });

        } catch (error) {
            console.error('[TJ-WIFI] 初始化脚本时发生错误:', error);
        }
    }

    // 启动脚本
    console.log('[TJ-WIFI] 脚本开始执行');

    // 确保在页面加载的最早时机执行
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initScript);
    } else {
        initScript();
    }
})();