DEV 蓝色小慧 - 增强版

自动短信登录流程 + 文件下载监控 + 黑名单过滤

2025-06-05 기준 버전입니다. 최신 버전을 확인하세요.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         DEV 蓝色小慧 - 增强版
// @namespace    http://tampermonkey.net/
// @version      2025-06-05-enhanced
// @description  自动短信登录流程 + 文件下载监控 + 黑名单过滤
// @author       Eachann
// @match        https://codigger.onecloud.cn/*
// @icon         https://files.catbox.moe/8l13tx.jpg
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
    'use strict';

    // ==================== 配置管理 ====================
    const CONFIG_KEYS = {
        DOWNLOAD_ENABLED: 'downloadEnabled',
        BLACKLIST_ENABLED: 'blacklistEnabled',
        FILE_BLACKLIST: 'fileBlacklist',
        PHONE_NUMBER: 'phoneNumber'
    };

    // 默认配置
    const DEFAULT_CONFIG = {
        [CONFIG_KEYS.DOWNLOAD_ENABLED]: true,
        [CONFIG_KEYS.BLACKLIST_ENABLED]: false,
        [CONFIG_KEYS.FILE_BLACKLIST]: '.exe,.bat,.cmd,.scr,.pif',
        [CONFIG_KEYS.PHONE_NUMBER]: ''
    };

    // 获取配置
    function getConfig(key) {
        return GM_getValue(key, DEFAULT_CONFIG[key]);
    }

    // 设置配置
    function setConfig(key, value) {
        GM_setValue(key, value);
    }

    // 创建设置界面
    function createSettingsPanel() {
        const panel = document.createElement('div');
        panel.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: linear-gradient(135deg, #000000 0%, #1a1a1a 100%);
            border: 1px solid #333;
            border-radius: 16px;
            padding: 0;
            z-index: 10000;
            box-shadow: 0 20px 60px rgba(0,0,0,0.8);
            min-width: 480px;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            color: white;
            overflow: hidden;
        `;

        const downloadEnabled = getConfig(CONFIG_KEYS.DOWNLOAD_ENABLED);
        const blacklistEnabled = getConfig(CONFIG_KEYS.BLACKLIST_ENABLED);

        panel.innerHTML = `
            <div style="padding: 32px;">
                <!-- 作者信息区域 -->
                <div style="display: flex; align-items: center; margin-bottom: 32px; padding-bottom: 24px; border-bottom: 1px solid #333;">
                    <img src="https://files.catbox.moe/rnx7yz.jpeg"
                         style="width: 64px; height: 64px; border-radius: 50%; margin-right: 20px; border: 2px solid #E31937;">
                    <div>
                        <h2 style="margin: 0; font-size: 24px; font-weight: 600; color: #E31937;">Eachann</h2>
                        <p style="margin: 4px 0 0 0; color: #888; font-size: 14px;">村里唯一的程序员</p>
                    </div>
                </div>

                <h3 style="margin: 0 0 32px 0; font-size: 28px; font-weight: 300; text-align: center;">脚本设置</h3>

                <!-- 下载功能开关 -->
                <div style="margin: 24px 0; display: flex; justify-content: space-between; align-items: center; padding: 16px 0;">
                    <div>
                        <div style="font-size: 18px; font-weight: 500; margin-bottom: 4px;">启用文件下载功能</div>
                        <div style="color: #888; font-size: 14px;">自动检测并下载聊天中的文件</div>
                    </div>
                    <div id="downloadToggle" style="
                        width: 60px; height: 32px; border-radius: 16px; cursor: pointer; position: relative;
                        background: ${downloadEnabled ? '#E31937' : '#333'};
                        transition: all 0.3s ease;
                    ">
                        <div style="
                            width: 28px; height: 28px; border-radius: 50%; background: white;
                            position: absolute; top: 2px; left: ${downloadEnabled ? '30px' : '2px'};
                            transition: all 0.3s ease; box-shadow: 0 2px 8px rgba(0,0,0,0.3);
                        "></div>
                    </div>
                </div>

                <!-- 黑名单开关 -->
                <div style="margin: 24px 0; display: flex; justify-content: space-between; align-items: center; padding: 16px 0;">
                    <div>
                        <div style="font-size: 18px; font-weight: 500; margin-bottom: 4px;">启用黑名单过滤</div>
                        <div style="color: #888; font-size: 14px;">过滤指定类型的文件</div>
                    </div>
                    <div id="blacklistToggle" style="
                        width: 60px; height: 32px; border-radius: 16px; cursor: pointer; position: relative;
                        background: ${blacklistEnabled ? '#E31937' : '#333'};
                        transition: all 0.3s ease;
                    ">
                        <div style="
                            width: 28px; height: 28px; border-radius: 50%; background: white;
                            position: absolute; top: 2px; left: ${blacklistEnabled ? '30px' : '2px'};
                            transition: all 0.3s ease; box-shadow: 0 2px 8px rgba(0,0,0,0.3);
                        "></div>
                    </div>
                </div>

                <!-- 黑名单输入 -->
                <div style="margin: 24px 0;">
                    <label style="font-size: 18px; font-weight: 500; display: block; margin-bottom: 12px;">文件扩展名黑名单</label>
                    <input type="text" id="fileBlacklist" value="${getConfig(CONFIG_KEYS.FILE_BLACKLIST)}"
                           style="
                               width: 100%; padding: 16px; border: 1px solid #333; border-radius: 8px;
                               background: #1a1a1a; color: white; font-size: 16px; box-sizing: border-box;
                               transition: border-color 0.3s ease;
                           "
                           placeholder="例如:.js,.zip,.exe,.bat">
                    <small style="color: #888; font-size: 12px; margin-top: 8px; display: block;">用逗号分隔多个扩展名</small>
                </div>

                <!-- 手机号输入 -->
                <div style="margin: 24px 0;">
                    <label style="font-size: 18px; font-weight: 500; display: block; margin-bottom: 12px;">手机号码</label>
                    <input type="tel" id="phoneNumber" value="${getConfig(CONFIG_KEYS.PHONE_NUMBER)}"
                           style="
                               width: 100%; padding: 16px; border: 1px solid #333; border-radius: 8px;
                               background: #1a1a1a; color: white; font-size: 16px; box-sizing: border-box;
                               transition: border-color 0.3s ease;
                           "
                           placeholder="请输入手机号码">
                    <small style="color: #888; font-size: 12px; margin-top: 8px; display: block;">用于自动登录功能</small>
                </div>

                <!-- 按钮区域 -->
                <div style="margin-top: 40px; display: flex; gap: 16px; justify-content: flex-end;">
                    <button id="cancelSettings" style="
                        padding: 12px 32px; border: 1px solid #333; border-radius: 8px;
                        background: transparent; color: #888; font-size: 16px; cursor: pointer;
                        transition: all 0.3s ease;
                    ">取消</button>
                    <button id="saveSettings" style="
                        padding: 12px 32px; border: none; border-radius: 8px;
                        background: #E31937; color: white; font-size: 16px; cursor: pointer;
                        transition: all 0.3s ease; font-weight: 500;
                    ">保存设置</button>
                </div>
            </div>
        `;

        document.body.appendChild(panel);

        // 切换按钮状态
        let downloadState = downloadEnabled;
        let blacklistState = blacklistEnabled;

        // 下载功能切换
        const downloadToggle = panel.querySelector('#downloadToggle');
        downloadToggle.onclick = () => {
            downloadState = !downloadState;
            const toggle = downloadToggle.querySelector('div');
            downloadToggle.style.background = downloadState ? '#E31937' : '#333';
            toggle.style.left = downloadState ? '30px' : '2px';
        };

        // 黑名单切换
        const blacklistToggle = panel.querySelector('#blacklistToggle');
        blacklistToggle.onclick = () => {
            blacklistState = !blacklistState;
            const toggle = blacklistToggle.querySelector('div');
            blacklistToggle.style.background = blacklistState ? '#E31937' : '#333';
            toggle.style.left = blacklistState ? '30px' : '2px';
        };

        // 输入框焦点效果
        const fileBlacklistInput = panel.querySelector('#fileBlacklist');
        fileBlacklistInput.onfocus = () => {
            fileBlacklistInput.style.borderColor = '#E31937';
        };
        fileBlacklistInput.onblur = () => {
            fileBlacklistInput.style.borderColor = '#333';
        };

        // 按钮悬停效果
        const saveBtn = panel.querySelector('#saveSettings');
        const cancelBtn = panel.querySelector('#cancelSettings');

        saveBtn.onmouseenter = () => {
            saveBtn.style.background = '#ff1f47';
            saveBtn.style.transform = 'translateY(-2px)';
        };
        saveBtn.onmouseleave = () => {
            saveBtn.style.background = '#E31937';
            saveBtn.style.transform = 'translateY(0)';
        };

        cancelBtn.onmouseenter = () => {
            cancelBtn.style.borderColor = '#666';
            cancelBtn.style.color = '#fff';
        };
        cancelBtn.onmouseleave = () => {
            cancelBtn.style.borderColor = '#333';
            cancelBtn.style.color = '#888';
        };

        // 保存设置
        saveBtn.onclick = () => {
            setConfig(CONFIG_KEYS.DOWNLOAD_ENABLED, downloadState);
            setConfig(CONFIG_KEYS.BLACKLIST_ENABLED, blacklistState);
            setConfig(CONFIG_KEYS.FILE_BLACKLIST, fileBlacklistInput.value);
            setConfig(CONFIG_KEYS.PHONE_NUMBER, document.querySelector('#phoneNumber').value);
            document.body.removeChild(panel);

            // 显示保存成功提示并刷新页面
            const notification = document.createElement('div');
            notification.style.cssText = `
                position: fixed; top: 20px; right: 20px; z-index: 10001;
                background: #E31937; color: white; padding: 16px 24px;
                border-radius: 8px; font-size: 16px; font-weight: 500;
                box-shadow: 0 4px 20px rgba(227, 25, 55, 0.3);
                animation: slideIn 0.3s ease;
            `;
            notification.innerHTML = '✅ 设置已保存,页面即将刷新...';

            // 添加动画样式
            const style = document.createElement('style');
            style.textContent = `
                @keyframes slideIn {
                    from { transform: translateX(100%); opacity: 0; }
                    to { transform: translateX(0); opacity: 1; }
                }
            `;
            document.head.appendChild(style);
            document.body.appendChild(notification);

            // 2秒后刷新页面
            setTimeout(() => {
                window.location.reload();
            }, 2000);
        };

        // 取消设置
        cancelBtn.onclick = () => {
            document.body.removeChild(panel);
        };
    }

    // 注册菜单命令
    GM_registerMenuCommand('打开设置', createSettingsPanel);

    // 检查当前路由是否为登录页
    function isLoginPage() {
        return window.location.href.includes('/chat/#/login');
    }

    // 检查当前路由是否为聊天页
    function isChatPage() {
        return window.location.href.includes('/chat/#/chat');
    }

    // ==================== HTTP 请求监听 ====================

    // 检查文件是否在黑名单中
    function isFileBlacklisted(fileName) {
        if (!getConfig(CONFIG_KEYS.BLACKLIST_ENABLED)) return false;

        const blacklist = getConfig(CONFIG_KEYS.FILE_BLACKLIST).split(',').map(ext => ext.trim().toLowerCase());
        const fileExt = fileName.toLowerCase().substring(fileName.lastIndexOf('.'));
        return blacklist.includes(fileExt);
    }

    // 触发下载按钮点击
    function triggerDownload() {
        try {
            // 多种选择器尝试查找下载图标
            const selectors = [
                'svg.svg-icon.link use[href="#icon-下载"]',
                'svg[aria-hidden="true"].svg-icon.link use[href="#icon-下载"]',
                'use[href="#icon-下载"]',
                'svg.svg-icon.link',
                '.svg-icon.link'
            ];

            let downloadIcons = [];

            // 尝试不同的选择器
            for (let selector of selectors) {
                downloadIcons = document.querySelectorAll(selector);
                if (downloadIcons.length > 0) {
                    // console.log(`✅ 找到 ${downloadIcons.length} 个下载图标,使用选择器: ${selector}`);
                    break;
                }
            }

            if (downloadIcons.length > 0) {
                // 获取最后一个(最新的)下载图标
                const lastDownloadIcon = downloadIcons[downloadIcons.length - 1];

                // 调试信息:输出元素结构
                console.warn('🔍 找到的下载图标元素:', {
                    tagName: lastDownloadIcon.tagName,
                    className: lastDownloadIcon.className,
                    outerHTML: lastDownloadIcon.outerHTML.substring(0, 200),
                    parentElement: lastDownloadIcon.parentElement ? lastDownloadIcon.parentElement.outerHTML.substring(0, 200) : 'null'
                });

                // 尝试不同的点击目标
                let clickTarget = null;

                if (lastDownloadIcon.tagName === 'use') {
                    // 如果是 use 元素,找到父级 svg
                    clickTarget = lastDownloadIcon.closest('svg');
                } else if (lastDownloadIcon.tagName === 'svg') {
                    // 如果直接是 svg 元素
                    clickTarget = lastDownloadIcon;
                } else {
                    // 其他情况,直接使用该元素
                    clickTarget = lastDownloadIcon;
                }

                console.warn('🎯 选择的点击目标:', {
                    tagName: clickTarget ? clickTarget.tagName : 'null',
                    className: clickTarget ? clickTarget.className : 'null',
                    outerHTML: clickTarget ? clickTarget.outerHTML.substring(0, 200) : 'null'
                });

                if (clickTarget) {
                    // 使用最有效的点击方式
                    try {
                        // 方式1: 直接点击
                        clickTarget.click();
                        console.log('✅ 自动触发文件下载 (直接点击)');
                        return true;
                    } catch (e) {
                        try {
                            // 方式2: 简化的事件分发 (已验证有效)
                            const clickEvent = new Event('click', { bubbles: true });
                            clickTarget.dispatchEvent(clickEvent);
                            console.log('✅ 自动触发文件下载 (事件分发)');
                            return true;
                        } catch (e2) {
                            console.error('❌ 下载触发失败:', e2);
                        }
                    }
                }
            } else {
                console.warn('⚠️ 未找到下载图标,可能页面还未完全加载');

                // 尝试查找所有可能的下载相关元素
                const allSvgs = document.querySelectorAll('svg');
                console.log(`🔍 页面中共有 ${allSvgs.length} 个 SVG 元素`);

                // 输出一些调试信息
                allSvgs.forEach((svg, index) => {
                    if (svg.classList.contains('svg-icon') || svg.classList.contains('link')) {
                        console.log(`SVG ${index}:`, svg.outerHTML.substring(0, 100));
                    }
                });
            }
        } catch (error) {
            console.error('❌ 触发下载失败:', error);
        }
        return false;
    }

    // 监听DOM变化,等待新的下载按钮出现
    function watchForNewDownloadButton() {
        const observer = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                if (mutation.type === 'childList') {
                    // 检查新增的节点中是否有下载按钮
                    mutation.addedNodes.forEach((node) => {
                        if (node.nodeType === Node.ELEMENT_NODE) {
                            // 在新增的节点中查找下载图标
                            const downloadIcon = node.querySelector && node.querySelector('svg.svg-icon.link use[href="#icon-下载"]');
                            if (downloadIcon) {
                                console.log('🎯 检测到新的下载按钮,尝试点击');
                                setTimeout(() => {
                                    if (triggerDownload()) {
                                        observer.disconnect(); // 成功后停止监听
                                    }
                                }, 100);
                            }
                        }
                    });
                }
            });
        });

        // 监听聊天区域的变化
        const chatContainer = document.querySelector('.chat-content') ||
                             document.querySelector('.message-list') ||
                             document.querySelector('.chat-messages') ||
                             document.body;

        if (chatContainer) {
            observer.observe(chatContainer, {
                childList: true,
                subtree: true
            });

            // 5秒后停止监听,避免无限监听
            setTimeout(() => {
                observer.disconnect();
                console.warn('⏰ DOM监听超时,停止监听新下载按钮');
            }, 5000);
        }
    }

    // 拦截 XMLHttpRequest
    function interceptXHR() {
        const originalOpen = XMLHttpRequest.prototype.open;
        const originalSend = XMLHttpRequest.prototype.send;

        XMLHttpRequest.prototype.open = function(method, url, ...args) {
            this._url = url;
            return originalOpen.apply(this, [method, url, ...args]);
        };

        XMLHttpRequest.prototype.send = function(data) {
            const xhr = this;

            // 监听请求载荷(发送的数据)
            if (xhr._url && xhr._url.includes('add/record') && data) {
                try {
                    let requestData;

                    // 尝试解析请求数据
                    if (typeof data === 'string') {
                        requestData = JSON.parse(data);
                    } else if (data instanceof FormData) {
                        // 如果是 FormData,尝试获取数据
                        const formDataObj = {};
                        for (let [key, value] of data.entries()) {
                            formDataObj[key] = value;
                        }
                        requestData = formDataObj;
                    } else {
                        requestData = data;
                    }

                    console.log('🔍 监听到 add/record 请求载荷:', requestData);

                    // 检查是否是文件类型
                    if (requestData && requestData.chatType === 'file') {
                        console.log('📁 检测到文件消息:', requestData.fileName);

                        // 检查是否启用下载功能
                        if (!getConfig(CONFIG_KEYS.DOWNLOAD_ENABLED)) {
                            console.log('⚠️ 文件下载功能已禁用');
                            return originalSend.call(this, data);
                        }

                        // 检查文件是否在黑名单中
                        if (isFileBlacklisted(requestData.fileName)) {
                            console.log('🚫 文件在黑名单中,跳过下载:', requestData.fileName);
                            return originalSend.call(this, data);
                        }

                        // 延迟触发下载,等待DOM更新
                        setTimeout(() => {
                            triggerDownload();
                        }, 1000); // 增加延迟时间,确保消息已经渲染到页面

                        // 如果第一次尝试失败,使用 MutationObserver 监听DOM变化
                        setTimeout(() => {
                            if (!triggerDownload()) {
                                watchForNewDownloadButton();
                            }
                        }, 2000);
                    }
                } catch (error) {
                    console.error('❌ 解析请求载荷失败:', error);
                }
            }

            return originalSend.call(this, data);
        };
    }

    // 拦截 fetch
    function interceptFetch() {
        const originalFetch = window.fetch;

        window.fetch = function(...args) {
            const url = args[0];
            const options = args[1] || {};

            // 检查是否是 add/record 请求并且有请求体
            if (url && url.includes && url.includes('add/record') && options.body) {
                try {
                    let requestData;

                    // 尝试解析请求数据
                    if (typeof options.body === 'string') {
                        requestData = JSON.parse(options.body);
                    } else {
                        requestData = options.body;
                    }

                    console.log('🔍 监听到 fetch add/record 请求载荷:', requestData);

                    // 检查是否是文件类型
                    if (requestData && requestData.chatType === 'file') {
                        console.log('📁 检测到文件消息:', requestData.fileName);

                        // 检查是否启用下载功能
                        if (!getConfig(CONFIG_KEYS.DOWNLOAD_ENABLED)) {
                            console.log('⚠️ 文件下载功能已禁用');
                            return originalFetch.apply(this, args);
                        }

                        // 检查文件是否在黑名单中
                        if (isFileBlacklisted(requestData.fileName)) {
                            console.log('🚫 文件在黑名单中,跳过下载:', requestData.fileName);
                            return originalFetch.apply(this, args);
                        }

                        // 延迟触发下载,等待DOM更新
                        setTimeout(() => {
                            triggerDownload();
                        }, 1000); // 增加延迟时间,确保消息已经渲染到页面

                        // 如果第一次尝试失败,使用 MutationObserver 监听DOM变化
                        setTimeout(() => {
                            if (!triggerDownload()) {
                                watchForNewDownloadButton();
                            }
                        }, 2000);
                    }
                } catch (error) {
                    console.error('❌ 解析 fetch 请求载荷失败:', error);
                }
            }

            return originalFetch.apply(this, args);
        };
    }

    // ==================== 主要功能初始化 ====================

    // 初始化所有功能
    function initializeFeatures() {
        // 如果在登录页,执行登录逻辑
        if (isLoginPage()) {
            console.warn('当前是登录页面,执行自动登录');
            executeAutoLogin();
        }

        // 如果在聊天页或登录页,都启动HTTP监听
        if (isChatPage() || isLoginPage()) {
            console.warn('启动HTTP请求监听');
            interceptXHR();
            interceptFetch();
        }
    }

    /**
     * 等待元素加载完成
     * @param {string} selector - CSS选择器
     * @param {number} timeout - 超时时间(ms)
     * @returns {Promise<Element>}
     */
    function waitForElement(selector, timeout = 3000) {
        return new Promise((resolve, reject) => {
            const element = document.querySelector(selector);
            if (element) {
                return resolve(element);
            }

            const observer = new MutationObserver(() => {
                const element = document.querySelector(selector);
                if (element) {
                    resolve(element);
                    observer.disconnect();
                }
            });

            observer.observe(document.body, {
                childList: true,
                subtree: true
            });

            setTimeout(() => {
                observer.disconnect();
                console.error(`等待元素超时: ${selector}`);
                reject(new Error(`等待元素超时: ${selector}`));
            }, timeout);
        });
    }

    /**
     * 设置输入框的值并触发事件
     * @param {Element} input - 输入框元素
     * @param {string} value - 要设置的值
     */
    function setInputValue(input, value) {
        input.value = value;
        input.dispatchEvent(new Event('input', { bubbles: true }));
        input.dispatchEvent(new Event('change', { bubbles: true }));
    }

    // 主要逻辑 - 短信登录流程
    async function executeAutoLogin() {
        try {
            const phoneNumber = getConfig(CONFIG_KEYS.PHONE_NUMBER);
            if (!phoneNumber) {
                console.warn('未设置手机号,跳过自动登录');
                return;
            }

            // 1.5. 选择COC域名
            try {
                const cocDomain = document.querySelector('.domain-item span');
                if (cocDomain && cocDomain.textContent.includes('COC')) {
                    cocDomain.closest('.domain-item').click();
                    await new Promise(resolve => setTimeout(resolve, 100));
                } else {
                    // 如果没有直接找到,尝试查找所有域名选项
                    const domainItems = document.querySelectorAll('.domain-item');
                    for (let item of domainItems) {
                        if (item.textContent.includes('COC')) {
                            item.click();
                            await new Promise(resolve => setTimeout(resolve, 100));
                            break;
                        }
                    }
                }
            } catch (error) {
                console.error('域名选择失败:', error);
            }

            // 2. 点击短信登录标签
            const smsTab = await waitForElement('.ant-tabs-tab');
            if (smsTab) {
                // 查找包含"短信登录"文本的标签
                const tabs = document.querySelectorAll('.ant-tabs-tab');
                for (let tab of tabs) {
                    if (tab.textContent.includes('短信登录')) {
                        tab.click();
                        await new Promise(resolve => setTimeout(resolve, 100));
                        break;
                    }
                }
            }

            // 3. 等待手机号输入框并输入手机号
            const phoneInput = await waitForElement('input[name="phone"]');
            setInputValue(phoneInput, phoneNumber);
            await new Promise(resolve => setTimeout(resolve, 100));

            // 4. 点击发送验证码按钮
            const codeBtn = await waitForElement('.code-btn.mini-font-size');
            codeBtn.click();
            await new Promise(resolve => setTimeout(resolve, 200));

            // 5. 等待验证码输入框并自动填写验证码
            const codeInput = await waitForElement('input[name="code"]');
            setInputValue(codeInput, '123456');
            await new Promise(resolve => setTimeout(resolve, 100));

            // 6. 点击登录按钮
            const loginBtn = await waitForElement('.ant-btn.ant-btn-primary.login-btn');
            loginBtn.click();


        } catch (error) {
            console.error('自动短信登录脚本执行失败:', error);
        }
    }

    // ==================== 脚本启动 ====================

    // 页面加载完成后执行
    if (document.readyState === 'complete') {
        initializeFeatures();
    } else {
        window.addEventListener('load', () => {
            initializeFeatures();
        });
    }

    // 添加延迟执行作为备用方案
    setTimeout(() => {
        initializeFeatures();
    }, 1000);
})();