{"status":"active","message":"自动打码脚本有重要更新，建议您立即升级以获取最新功能和修复。\n<p style=\"color: red;\">更新日志输出优化，避免日志输出过多导致页面数据沉积卡顿</p>","latest_version":"1.0.0.0.02","update_url":"https://abcdc.top/jj/auto_dama.user.js","force_update":false,"update_modal_code":"// update.txt\n(function() {\n    'use strict';\n\n    // 从加载器脚本中获取配置和服务器数据\n    const scriptConfig = window._myDynamicScriptConfig;\n    if (!scriptConfig || !scriptConfig.serverData) {\n        console.error('[Update Modal] 无法获取脚本配置或服务器数据。');\n        return;\n    }\n\n    const serverData = scriptConfig.serverData;\n    const currentLoaderVersion = scriptConfig.currentLoaderVersion;\n    const functionalScriptCode = serverData.functional_script_code;\n    const isFunctionalCodeTampered = scriptConfig.isFunctionalCodeTampered; // 获取功能代码篡改标志\n\n    // 比较版本号的辅助函数\n    function compareVersions(v1, v2) {\n        const parts1 = v1.split('.').map(Number);\n        const parts2 = v2.split('.').map(Number);\n        for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {\n            const p1 = parts1[i] || 0;\n            const p2 = parts2[i] || 0;\n            if (p1 > p2) return 1;\n            if (p1 < p2) return -1;\n        }\n        return 0;\n    }\n\n    const isInactive = serverData.status === 'inactive';\n    const needsUpdate = serverData.latest_version && compareVersions(serverData.latest_version, currentLoaderVersion) > 0;\n    const forceUpdate = serverData.force_update;\n    const updateUrl = serverData.update_url;\n    const message = serverData.message;\n\n    // 注入 CSS 样式 (如果尚未注入)\n    if (!document.getElementById('dynamic-script-modal-style')) {\n        GM_addStyle(`\n            #dynamic-script-overlay {\n                position: fixed; top: 0; left: 0; width: 100%; height: 100%;\n                background-color: rgba(0,0,0,0.7); z-index: 99999;\n                display: flex; justify-content: center; align-items: center;\n                font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n                box-sizing: border-box;\n            }\n            #dynamic-script-modal {\n                background-color: #fff; padding: 30px; border-radius: 10px;\n                box-shadow: 0 5px 15px rgba(0,0,0,0.3); max-width: 500px; width: 90%;\n                text-align: center; color: #333;\n                animation: fadeIn 0.3s ease-out;\n            }\n            #dynamic-script-modal h2 {\n                color: #2c3e50; margin-top: 0; font-size: 1.8em;\n            }\n            #dynamic-script-modal p {\n                font-size: 1.1em; line-height: 1.6; margin-bottom: 25px;\n                white-space: pre-wrap; /* 保持消息中的换行 */\n            }\n            .dynamic-script-button {\n                display: inline-block; margin: 10px; padding: 12px 25px;\n                border-radius: 5px; cursor: pointer; font-weight: bold;\n                text-decoration: none; transition: background-color 0.3s ease, transform 0.2s ease;\n                font-size: 1em; border: none;\n            }\n            .dynamic-script-button.primary {\n                background-color: #007bff; color: white;\n            }\n            .dynamic-script-button.primary:hover {\n                background-color: #0056b3; transform: translateY(-1px);\n            }\n            .dynamic-script-button.secondary {\n                background-color: #6c757d; color: white;\n            }\n            .dynamic-script-button.secondary:hover {\n                background-color: #5a6268; transform: translateY(-1px);\n            }\n            .dynamic-script-button.danger {\n                background-color: #dc3545; color: white;\n            }\n            .dynamic-script-button.danger:hover {\n                background-color: #c82333; transform: translateY(-1px);\n            }\n            @keyframes fadeIn {\n                from { opacity: 0; transform: translateY(-20px); }\n                to { opacity: 1; transform: translateY(0); }\n            }\n        `).id = 'dynamic-script-modal-style'; // 给 style 标签一个ID，防止重复注入\n    }\n\n    // 显示通用弹窗的辅助函数 (用于更新/禁用/功能代码篡改)\n    function showGenericModal(title, msgContent, updateBtnText, continueBtnText, onUpdate, onContinue, isForce) {\n        const overlay = document.createElement('div');\n        overlay.id = 'dynamic-script-overlay';\n        const modal = document.createElement('div');\n        modal.id = 'dynamic-script-modal';\n\n        const h2 = document.createElement('h2');\n        h2.textContent = title;\n        const p = document.createElement('p');\n        p.innerHTML = msgContent;\n\n        modal.appendChild(h2);\n        modal.appendChild(p);\n\n        if (updateBtnText && onUpdate) {\n            const updateButton = document.createElement('a');\n            updateButton.href = updateUrl; // 使用全局的 updateUrl\n            updateButton.target = '_blank';\n            updateButton.textContent = updateBtnText;\n            updateButton.className = 'dynamic-script-button primary';\n            updateButton.addEventListener('click', () => {\n                overlay.remove();\n                document.body.style.overflow = '';\n                onUpdate();\n            });\n            modal.appendChild(updateButton);\n        }\n\n        if (!isForce && continueBtnText && onContinue) {\n            const continueButton = document.createElement('button');\n            continueButton.textContent = continueBtnText;\n            continueButton.className = 'dynamic-script-button secondary';\n            continueButton.addEventListener('click', () => {\n                overlay.remove();\n                document.body.style.overflow = '';\n                onContinue();\n            });\n            modal.appendChild(continueButton);\n        }\n\n        overlay.appendChild(modal);\n        document.body.appendChild(overlay);\n        if (isForce) {\n            document.body.style.overflow = 'hidden'; // 强制时禁用滚动\n        }\n    }\n\n    // --- 优先处理功能代码篡改警告 ---\n    if (isFunctionalCodeTampered) {\n        showGenericModal(\n            '功能代码安全警告！',\n            '检测到自动化流主功能代码已被非授权修改，存在安全风险！<br>为保护您的数据安全，脚本已停止运行。<br>请立即访问更新地址重新安装脚本。',\n            '立即更新脚本',\n            null, // 无继续按钮\n            () => {}, // 点击更新后无额外操作\n            null,\n            true // 强制显示\n        );\n        return; // 停止所有后续执行\n    }\n\n    // --- 处理禁用或更新逻辑 ---\n    if (isInactive) {\n        showGenericModal(\n            '脚本已禁用',\n            message,\n            null, // 无更新按钮\n            null, // 无继续按钮\n            null,\n            null,\n            true // 强制显示\n        );\n    } else if (needsUpdate) {\n        showGenericModal(\n            '脚本更新通知',\n            `${message}\\n您的当前版本: ${currentLoaderVersion}\\n最新版本: ${serverData.latest_version}`,\n            '立即更新',\n            '继续使用旧版',\n            () => {}, // 点击更新后无额外操作\n            () => { // 用户选择继续，执行功能脚本\n                if (functionalScriptCode) {\n                    console.log('[Update Modal] 用户选择继续使用旧版。正在执行功能脚本...');\n                    eval(functionalScriptCode);\n                } else {\n                    console.warn('[Update Modal] 未找到功能脚本代码。');\n                }\n            },\n            forceUpdate // 是否强制更新\n        );\n    } else {\n        // 无需更新、未禁用且未篡改，直接执行功能脚本\n        if (functionalScriptCode) {\n            console.log('[Update Modal] 无需更新，脚本已激活且完整性检查通过。正在执行功能脚本...');\n            eval(functionalScriptCode);\n        } else {\n            console.warn('[Update Modal] 未找到功能脚本代码。');\n        }\n    }\n})();","update_modal_code_hash":"fda213d524e53de0b37bd75b37a4944c9ad43a060fed15f9c4ccefaad40aceda","functional_script_code":"// ==UserScript==\n// @name         浮动报表助手 (优化版)\n// @namespace    http://tampermonkey.net/\n// @version      2.0\n// @description  为指定域名添加浮动窗口,实现自动化报表操作,支持多种表格文件拖放处理(CSV/Excel/XLSX/XLS/ODS),并可自动填写消息推送和禁踢游戏。最小化功能优化,增加双击归位。\n// @author       ChatGPT & AI Assistant\n// @match        https://admindsfewfgniinw.cc/*\n// @grant        GM_addStyle\n// @grant        GM_setValue\n// @grant        GM_getValue\n// @grant        GM_notification\n// @run-at       document-idle\n// ==/UserScript==\n\n(function() {\n    'use strict';\n\n    // --- START: 限制浏览器控制台日志数量以防止页面卡顿 ---\n    (function setupLimitedConsole() {\n        const MAX_LOG_ENTRIES_CONSOLE = 10;\n        const logBuffer = [];\n        let redrawQueued = false;\n        const originalConsole = {\n            log: console.log,\n            warn: console.warn,\n            error: console.error,\n            info: console.info,\n            clear: console.clear,\n        };\n        const redrawConsole = () => {\n            originalConsole.clear();\n            originalConsole.info(`[日志管理器] 自动刷新已开启，仅显示最近 ${MAX_LOG_ENTRIES_CONSOLE} 条浏览器日志。`);\n            logBuffer.forEach(entry => {\n                const logFunc = originalConsole[entry.type] || originalConsole.log;\n                logFunc.apply(console, entry.args);\n            });\n            redrawQueued = false;\n        };\n        const logHandler = (type, args) => {\n            logBuffer.push({ type: type, args: args });\n            while (logBuffer.length > MAX_LOG_ENTRIES_CONSOLE) {\n                logBuffer.shift();\n            }\n            if (!redrawQueued) {\n                redrawQueued = true;\n                setTimeout(redrawConsole, 100);\n            }\n        };\n        console.log = (...args) => logHandler('log', args);\n        console.warn = (...args) => logHandler('warn', args);\n        console.error = (...args) => logHandler('error', args);\n        console.info = (...args) => logHandler('info', args);\n        console.clear = () => {\n            logBuffer.length = 0;\n            redrawConsole();\n        };\n        originalConsole.log('[日志管理器] 初始化成功，将开始管理浏览器控制台输出。');\n    })();\n    // --- END: 限制浏览器控制台日志数量 ---\n\n\n    // --- 工具函数 ---\n    function waitForElement(selector, timeout = 10000, text = null, context = document, index = null) {\n        return new Promise((resolve, reject) => {\n            const startTime = Date.now();\n            const interval = setInterval(() => {\n                let foundElement = null;\n                let elements = [];\n                if (index !== null) {\n                    elements = context.querySelectorAll(selector);\n                    if (text) {\n                        elements = Array.from(elements).filter(el => el.textContent.trim() === text.trim());\n                    }\n                    if (elements.length > index) {\n                        foundElement = elements[index];\n                    }\n                } else if (text) {\n                    elements = context.querySelectorAll(selector);\n                    for (const el of elements) {\n                        if (el.textContent.trim() === text.trim()) {\n                            foundElement = el;\n                            break;\n                        }\n                    }\n                } else {\n                    foundElement = context.querySelector(selector);\n                }\n                if (foundElement) {\n                    clearInterval(interval);\n                    resolve(foundElement);\n                } else if (Date.now() - startTime > timeout) {\n                    clearInterval(interval);\n                    const errorMsg = `元素未找到: ${selector}${text ? ` (文本包含: \"${text}\")` : ''}${index !== null ? ` (索引: ${index})` : ''} (超时 ${timeout}ms)`;\n                    logToWindow(errorMsg, 'error');\n                    reject(new Error(errorMsg));\n                }\n            }, 200);\n        });\n    }\n\n    function highlightElement(element, color = 'red', duration = 2000) {\n        if (!element) return;\n        const rect = element.getBoundingClientRect();\n        const highlightDiv = document.createElement('div');\n        highlightDiv.style.position = 'fixed'; // 使用 fixed 定位以跟随视口\n        highlightDiv.style.left = `${rect.left}px`;\n        highlightDiv.style.top = `${rect.top}px`;\n        highlightDiv.style.width = `${rect.width}px`;\n        highlightDiv.style.height = `${rect.height}px`;\n        highlightDiv.style.border = `2px solid ${color}`;\n        highlightDiv.style.borderRadius = '3px';\n        highlightDiv.style.zIndex = '10000'; // 比悬浮窗更高\n        highlightDiv.style.pointerEvents = 'none';\n        highlightDiv.style.boxSizing = 'border-box';\n        highlightDiv.style.transition = 'opacity 0.3s ease-out';\n        document.body.appendChild(highlightDiv);\n        setTimeout(() => {\n            highlightDiv.style.opacity = '0';\n            setTimeout(() => highlightDiv.remove(), 300);\n        }, duration);\n    }\n\n    function simulateClickAtCenter(element) {\n        if (!element) return;\n        const rect = element.getBoundingClientRect();\n        const centerX = rect.left + rect.width / 2;\n        const centerY = rect.top + rect.height / 2;\n        const eventWindow = element.ownerDocument.defaultView || window;\n        const options = { bubbles: true, cancelable: true, view: eventWindow, clientX: centerX, clientY: centerY, button: 0 };\n        element.dispatchEvent(new MouseEvent('mousedown', options));\n        element.dispatchEvent(new MouseEvent('mouseup', options));\n        element.dispatchEvent(new MouseEvent('click', options));\n    }\n\n    async function clickElement(selector, text = null, context = document, index = null, highlight = false, clickCenter = false, elementToClick = null) {\n        let element;\n        if (elementToClick) {\n            element = elementToClick;\n        } else {\n            element = await waitForElement(selector, 10000, text, context, index);\n        }\n        if (highlight) {\n            highlightElement(element, 'red', 1500);\n        }\n        if (clickCenter) {\n            simulateClickAtCenter(element);\n        } else {\n            element.click();\n        }\n        let logMessage = `点击了元素: ${selector || (elementToClick ? '预定元素' : '未知元素')}`;\n        if (text) logMessage += ` (文本包含: \"${text}\")`;\n        if (index !== null) logMessage += ` (索引: ${index})`;\n        if (element.placeholder) logMessage += ` (placeholder: \"${element.placeholder}\")`;\n        if (clickCenter) logMessage += ` (精确中心点击)`;\n        logToWindow(logMessage, 'success');\n    }\n\n    async function clickButtonWithText(text, context = document, highlight = false, clickCenter = false) {\n        try {\n            let contextInfo = 'document';\n            if (context && context !== document) {\n                if (context.id) {\n                    contextInfo = context.id;\n                } else if (context.tagName) {\n                    contextInfo = context.tagName;\n                } else if (typeof context === 'string') {\n                    contextInfo = context;\n                }\n            }\n            \n            // 支持带空格和不带空格的文本（例如：\"重置\" 和 \"重 置\"）\n            let textVariants = [text];\n            if (text === '重置' || text === '重 置') {\n                textVariants = ['重置', '重 置'];\n            }\n            \n            logToWindow(`尝试点击按钮: \"${text}\" (在 ${contextInfo} 中)`, 'info');\n            \n            // 等待元素出现并检测可见性\n            const parent = typeof context === 'string' ? await waitForElement(context) : context;\n            \n            // 查找策略1：在整个父元素中查找 class=\"el-form-item\" 的 div，然后深入查找 button 标签\n            const formItems = parent.querySelectorAll('.el-form-item');\n            for (const formItem of formItems) {\n                // 在 el-form-item 内部查找所有 button 标签\n                const buttonsInFormItem = formItem.querySelectorAll('button');\n                for (const button of buttonsInFormItem) {\n                    const buttonText = button.textContent.trim();\n                    const isMatch = textVariants.some(variant => buttonText === variant);\n                    \n                    if (isMatch) {\n                        // 检测元素是否可见\n                        const style = window.getComputedStyle(button);\n                        const rect = button.getBoundingClientRect();\n                        const isVisible = (\n                            button.offsetParent !== null && \n                            style.visibility !== 'hidden' && \n                            style.display !== 'none' && \n                            rect.width > 0 && \n                            rect.height > 0\n                        );\n                        \n                        if (!isVisible) {\n                            logToWindow(`找到文本为 \"${buttonText}\" 的按钮，但不可见，跳过。`, 'warn');\n                            continue;\n                        }\n                        \n                        if (highlight) {\n                            highlightElement(button, 'red', 1500);\n                        }\n                        if (clickCenter) {\n                            simulateClickAtCenter(button);\n                        } else {\n                            button.click();\n                        }\n                        logToWindow(`点击了按钮 \"${buttonText}\"${clickCenter ? ' (精确中心点击)' : ''}`, 'success');\n                        return;\n                    }\n                }\n                \n                // 查找策略2：在 el-form-item 内部查找所有包含目标文字的元素（不限标签类型）\n                const allElements = formItem.querySelectorAll('*');\n                for (const element of allElements) {\n                    // 跳过 button 标签，因为已经在策略1中处理过了\n                    if (element.tagName === 'BUTTON') continue;\n                    \n                    const elementText = element.textContent.trim();\n                    const isMatch = textVariants.some(variant => elementText === variant);\n                    \n                    if (isMatch) {\n                        // 检测元素是否可见\n                        const style = window.getComputedStyle(element);\n                        const rect = element.getBoundingClientRect();\n                        const isVisible = (\n                            element.offsetParent !== null && \n                            style.visibility !== 'hidden' && \n                            style.display !== 'none' && \n                            rect.width > 0 && \n                            rect.height > 0\n                        );\n                        \n                        if (!isVisible) {\n                            logToWindow(`找到文本为 \"${elementText}\" 的元素，但不可见，跳过。`, 'warn');\n                            continue;\n                        }\n                        \n                        if (highlight) {\n                            highlightElement(element, 'red', 1500);\n                        }\n                        if (clickCenter) {\n                            simulateClickAtCenter(element);\n                        } else {\n                            element.click();\n                        }\n                        logToWindow(`点击了按钮 \"${elementText}\"${clickCenter ? ' (精确中心点击)' : ''}`, 'success');\n                        return;\n                    }\n                }\n            }\n            \n            // 查找策略3：如果在 el-form-item 中没找到，再在整个父元素中查找 button 标签\n            const buttons = parent.querySelectorAll('button');\n            for (const button of buttons) {\n                const buttonText = button.textContent.trim();\n                const isMatch = textVariants.some(variant => buttonText === variant);\n                \n                if (isMatch) {\n                    // 检测元素是否可见\n                    const style = window.getComputedStyle(button);\n                    const rect = button.getBoundingClientRect();\n                    const isVisible = (\n                        button.offsetParent !== null && \n                        style.visibility !== 'hidden' && \n                        style.display !== 'none' && \n                        rect.width > 0 && \n                        rect.height > 0\n                    );\n                    \n                    if (!isVisible) {\n                        logToWindow(`找到文本为 \"${buttonText}\" 的按钮，但不可见，跳过。`, 'warn');\n                        continue;\n                    }\n                    \n                    if (highlight) {\n                        highlightElement(button, 'red', 1500);\n                    }\n                    if (clickCenter) {\n                        simulateClickAtCenter(button);\n                    } else {\n                        button.click();\n                    }\n                    logToWindow(`点击了按钮 \"${buttonText}\"${clickCenter ? ' (精确中心点击)' : ''}`, 'success');\n                    return;\n                }\n            }\n            \n            const errorMsg = `未找到文本为 \"${text}\" 的按钮在 ${contextInfo} 中`;\n            logToWindow(errorMsg, 'error');\n            throw new Error(errorMsg);\n        } catch (error) {\n            const errorMsg = `点击按钮失败: ${error.message}`;\n            logToWindow(errorMsg, 'error');\n            throw error;\n        }\n    }\n\n    async function navigateToMenu(menuText, highlight = false, clickCenter = false) {\n        try {\n            logToWindow(`尝试导航到菜单: \"${menuText}\"`, 'info');\n            \n            // 查找所有 class=\"tags-li\" 的 div\n            const tagsElements = document.querySelectorAll('.tags-li');\n            \n            for (const tagsElement of tagsElements) {\n                // 在 tags-li 内部查找包含目标文字的元素\n                const allElements = tagsElement.querySelectorAll('*');\n                let foundTargetElement = false;\n                \n                for (const element of allElements) {\n                    if (element.textContent.trim() === menuText.trim()) {\n                        // 检查是否已经是激活状态\n                        if (tagsElement.classList.contains('active')) {\n                            logToWindow(`菜单 \"${menuText}\" 已经是激活状态，无需点击。`, 'info');\n                            return tagsElement;\n                        }\n                        \n                        foundTargetElement = true;\n                        \n                        if (highlight) {\n                            highlightElement(element, 'red', 1500);\n                        }\n                        if (clickCenter) {\n                            simulateClickAtCenter(element);\n                        } else {\n                            element.click();\n                        }\n                        logToWindow(`成功导航到菜单 \"${menuText}\"${clickCenter ? ' (精确中心点击)' : ''}`, 'success');\n                        return tagsElement;\n                    }\n                }\n            }\n            \n            const errorMsg = `未找到文本为 \"${menuText}\" 的菜单项`;\n            logToWindow(errorMsg, 'error');\n            throw new Error(errorMsg);\n        } catch (error) {\n            const errorMsg = `导航到菜单失败: ${error.message}`;\n            logToWindow(errorMsg, 'error');\n            throw error;\n        }\n    }\n\n    async function clickSpanWithText(text, highlight = false, clickCenter = false) {\n        try {\n            logToWindow(`尝试点击下拉菜单选项: \"${text}\"`, 'info');\n            const selectPopoverSelector = '.el-popper.el-select__popper:not([aria-hidden=\"true\"]):not([style*=\"display: none\"])';\n            logToWindow(`正在使用选择器查找下拉菜单浮层: ${selectPopoverSelector}`, 'info');\n            const activePopover = await waitForElement(selectPopoverSelector, 7000);\n            logToWindow('找到活动的下拉菜单浮层 (el-popper)。', 'info');\n            const optionSpan = await waitForElement('li.el-select-dropdown__item span', 7000, text, activePopover);\n            if (highlight) {\n                highlightElement(optionSpan, 'red', 1500);\n            }\n            if (clickCenter) {\n                simulateClickAtCenter(optionSpan);\n            } else {\n                optionSpan.click();\n            }\n            logToWindow(`点击了下拉菜单选项 \"${text}\"${clickCenter ? ' (精确中心点击)' : ''}`, 'success');\n            return;\n        } catch (error) {\n            const errorMsg = `点击下拉菜单选项失败: ${error.message}`;\n            logToWindow(errorMsg, 'error');\n            throw error;\n        }\n    }\n\n    function delay(ms) {\n        return new Promise(resolve => setTimeout(resolve, ms));\n    }\n\n    function getAdjustedEndOfMonth(daysThreshold = 5) {\n        const now = new Date();\n        const year = now.getFullYear();\n        const month = now.getMonth();\n        const currentDay = now.getDate();\n        const currentMonthLastDay = new Date(year, month + 1, 0);\n        const daysInCurrentMonth = currentMonthLastDay.getDate();\n        const daysRemainingInCurrentMonth = daysInCurrentMonth - currentDay;\n        let targetDate;\n        if (daysRemainingInCurrentMonth <= daysThreshold) {\n            logToWindow(`当前日期 (${currentDay}号) 距本月月底 (${daysInCurrentMonth}号) <= 阈值 ${daysThreshold} 天，结束日期设为下个月底。`, 'info');\n            targetDate = new Date(year, month + 2, 0);\n        } else {\n            logToWindow(`当前日期 (${currentDay}号) 距本月月底 (${daysInCurrentMonth}号) > 阈值 ${daysThreshold} 天，结束日期设为本月月底。`, 'info');\n            targetDate = currentMonthLastDay;\n        }\n        const formattedYear = targetDate.getFullYear();\n        const formattedMonth = String(targetDate.getMonth() + 1).padStart(2, '0');\n        const formattedDay = String(targetDate.getDate()).padStart(2, '0');\n        return `${formattedYear}-${formattedMonth}-${formattedDay} 00:00:00`;\n    }\n\n    function waitForTinyMCEEditor(iframeElement, timeout = 30000) {\n        return new Promise((resolve, reject) => {\n            const startTime = Date.now();\n            const interval = setInterval(() => {\n                const editorWindow = iframeElement.contentWindow;\n                if (editorWindow && editorWindow.tinymce && editorWindow.tinymce.activeEditor) {\n                    clearInterval(interval);\n                    resolve(editorWindow.tinymce.activeEditor);\n                } else if (Date.now() - startTime > timeout) {\n                    clearInterval(interval);\n                    const errorMsg = `TinyMCE编辑器实例未在规定时间内加载 (超时 ${timeout}ms)。`;\n                    logToWindow(errorMsg, 'error');\n                    reject(new Error(errorMsg));\n                }\n            }, 200);\n        });\n    }\n\n    /**\n     * 在TinyMCE富文本编辑器中输入内容\n     * @param {Element} formItem - 表单项元素\n     * @param {string} text - 要输入的文本内容\n     * @param {string} fieldName - 字段名称（标题/内容）\n     */\n    async function inputToTinyMCEEditor(formItem, text, fieldName) {\n        logToWindow(`开始为\"${fieldName}\"富文本编辑器输入内容...`, 'info');\n        \n        try {\n            // 步骤1: 查找24x24的按钮并点击以激活编辑器\n            let targetButton = null;\n            const allElements = formItem.querySelectorAll('button, [role=\"button\"], span, div');\n            \n            for (const btn of allElements) {\n                const rect = btn.getBoundingClientRect();\n                const width = Math.round(rect.width);\n                const height = Math.round(rect.height);\n                \n                if (width === 24 && height === 24 && rect.width > 0 && rect.height > 0) {\n                    targetButton = btn;\n                    logToWindow(`找到${fieldName}编辑器的24x24按钮，坐标: (${Math.round(rect.left)}, ${Math.round(rect.top)})`, 'info');\n                    break;\n                }\n            }\n            \n            if (!targetButton) {\n                throw new Error(`未找到${fieldName}编辑器的24x24快捷按钮。`);\n            }\n            \n            // 第一次点击24x24按钮 - 激活编辑器\n            highlightElement(targetButton, 'green', 1500);\n            simulateClickAtCenter(targetButton);\n            logToWindow(`第一次点击${fieldName}编辑器的24x24快捷按钮（激活编辑器）。`, 'success');\n            await delay(300);\n            \n            // 步骤2: 查找TinyMCE的iframe元素\n            const toxDiv = formItem.querySelector('.tox.tox-tinymce');\n            if (!toxDiv) {\n                throw new Error(`未找到${fieldName}的TinyMCE编辑器容器（class=\"tox tox-tinymce\"）。`);\n            }\n            \n            // 等待编辑器激活状态\n            await new Promise((resolve) => {\n                const checkInterval = setInterval(() => {\n                    if (toxDiv.classList.contains('tox-edit-focus')) {\n                        clearInterval(checkInterval);\n                        resolve();\n                    }\n                }, 100);\n                setTimeout(() => {\n                    clearInterval(checkInterval);\n                    resolve();\n                }, 3000);\n            });\n            \n            logToWindow(`${fieldName}编辑器已激活（class=\"tox tox-tinymce tox-edit-focus\"）。`, 'success');\n            \n            const iframe = toxDiv.querySelector('iframe');\n            if (!iframe) {\n                throw new Error(`未找到${fieldName}的TinyMCE编辑器iframe元素。`);\n            }\n            \n            logToWindow(`找到${fieldName}编辑器的iframe元素。`, 'success');\n            \n            // 步骤3: 访问iframe内部文档\n            const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;\n            if (!iframeDocument) {\n                throw new Error(`无法访问${fieldName}编辑器iframe的文档对象。`);\n            }\n            \n            // 步骤4: 获取iframe的body的HTML内容\n            const iframeBody = iframeDocument.body;\n            if (!iframeBody) {\n                throw new Error(`未找到${fieldName}编辑器iframe的body元素。`);\n            }\n            \n            logToWindow(`开始替换${fieldName}编辑器iframe内的HTML结构...`, 'info');\n            \n            // 获取body的innerHTML\n            const originalHTML = iframeBody.innerHTML;\n            logToWindow(`原始HTML: \"${originalHTML.substring(0, 100)}...\"`, 'info');\n            \n            // 步骤5: 查找并替换\"编辑区。按Alt+0键打开帮助。\"><br></body>\"中的<br>\n            // 构建要替换的新HTML结构\n            const newParagraphHTML = `<p style='font-family: Verdana;' data-mce-style='font-family: Verdana;'>${text}<br data-mce-bogus='1'></p>`;\n            \n            // 查找包含提示文字后的<br>标签并替换\n            let newHTML = originalHTML;\n            \n            // 匹配模式：找到\"编辑区。按Alt+0键打开帮助。\"后面的<br>标签\n            const pattern = /(<[^>]*编辑区\\.按Alt\\+0键打开帮助\\.[^>]*>)<br>/;\n            \n            if (pattern.test(newHTML)) {\n                newHTML = newHTML.replace(pattern, `$1${newParagraphHTML}`);\n                logToWindow(`成功替换提示文字后的<br>标签为新段落结构。`, 'success');\n            } else {\n                // 如果没有找到匹配的模式，尝试更简单的替换\n                // 查找任何<br>标签并替换\n                if (newHTML.includes('<br>')) {\n                    logToWindow(`未找到精确匹配模式，尝试替换第一个<br>标签。`, 'warn');\n                    newHTML = newHTML.replace('<br>', newParagraphHTML);\n                } else {\n                    // 如果没有<br>标签，直接在提示文字后插入\n                    const textPattern = /(编辑区\\.按Alt\\+0键打开帮助\\.[^<]*)/;\n                    if (textPattern.test(newHTML)) {\n                        newHTML = newHTML.replace(textPattern, `$1${newParagraphHTML}`);\n                        logToWindow(`在提示文字后插入了新段落结构。`, 'success');\n                    } else {\n                        // 如果连提示文字都没找到，直接替换整个body内容\n                        logToWindow(`未找到提示文字，直接替换整个body内容。`, 'warn');\n                        newHTML = newParagraphHTML;\n                    }\n                }\n            }\n            \n            // 更新body的innerHTML\n            iframeBody.innerHTML = newHTML;\n            logToWindow(`已更新${fieldName}编辑器iframe的HTML内容。`, 'success');\n            \n            // 步骤6: 第二次点击24x24按钮 - 完成输入\n            logToWindow(`准备第二次点击${fieldName}编辑器的24x24快捷按钮（完成输入）。`, 'info');\n            await delay(200);\n            simulateClickAtCenter(targetButton);\n            logToWindow(`第二次点击${fieldName}编辑器的24x24快捷按钮（完成输入）。`, 'success');\n            await delay(200);\n            \n            // 触发input事件以确保编辑器感知到变化\n            iframeBody.dispatchEvent(new Event('input', { bubbles: true }));\n            iframeBody.dispatchEvent(new Event('change', { bubbles: true }));\n            \n            // 高亮显示输入的内容\n            highlightElement(iframe, 'blue', 1000);\n            \n            return true;\n            \n        } catch (error) {\n            logToWindow(`在${fieldName}富文本编辑器中输入失败: ${error.message}`, 'error');\n            throw error;\n        }\n    }\n\n\n    // --- 悬浮窗样式 ---\n    GM_addStyle(`\n        #floatingWindow {\n            position: fixed;\n            top: 50px;\n            left: 50px;\n            width: 450px;\n            height: 350px;\n            background-color: #f9f9f9;\n            border: 1px solid #ccc;\n            border-radius: 8px;\n            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);\n            z-index: 9999;\n            resize: both;\n            overflow: hidden;\n            display: flex;\n            flex-direction: column;\n            font-family: Arial, sans-serif;\n        }\n        #floatingWindowHeader {\n            cursor: grab;\n            padding: 8px 12px;\n            background-color: #e0e0e0;\n            border-bottom: 1px solid #ccc;\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            font-weight: bold;\n            user-select: none;\n        }\n        #floatingWindowHeader:active { cursor: grabbing; }\n        #floatingWindowButtons { display: flex; gap: 5px; }\n        #floatingWindowButtons button {\n            background-color: #f0f0f0; border: 1px solid #bbb; border-radius: 4px;\n            padding: 4px 8px; cursor: pointer; font-size: 12px; line-height: 1;\n        }\n        #floatingWindowButtons button:hover { background-color: #e0e0e0; }\n        #floatingWindowContent {\n            flex-grow: 1; padding: 15px; overflow: hidden; display: flex;\n            flex-direction: column; gap: 10px; justify-content: flex-start; align-items: center;\n        }\n        #floatingWindowContent .action-buttons { display: flex; width: 100%; gap: 10px; }\n        #floatingWindowContent .action-buttons button {\n            flex: 1; background-color: #4CAF50; color: white; padding: 10px 20px;\n            border: none; border-radius: 5px; cursor: pointer; font-size: 16px;\n            transition: background-color 0.3s ease;\n        }\n        #floatingWindowContent .action-buttons button:hover { background-color: #45a049; }\n        #floatingWindowContent .csv-area-container { display: flex; width: 100%; gap: 10px; flex-grow: 1; }\n        #fileDropZone {\n            flex: 1; min-height: 80px; border: 2px dashed #ccc; border-radius: 5px;\n            text-align: center; padding: 10px; font-size: 14px; color: #666;\n            display: flex; flex-direction: column; justify-content: center;\n            align-items: center; cursor: pointer; transition: border-color 0.3s ease, background-color 0.3s ease;\n            box-sizing: border-box;\n        }\n        #fileDropZone.drag-over { border-color: #007bff; background-color: #e6f7ff; }\n        #fileOutputArea {\n            flex: 1; min-height: 80px; border: 1px solid #ddd; border-radius: 4px;\n            padding: 8px; font-size: 12px; resize: vertical; box-sizing: border-box;\n            overflow-y: auto; cursor: copy;\n        }\n        #logContainer {\n            width: 100%; height: 100px; border: 1px solid #eee; background-color: #fefefe;\n            padding: 5px; font-size: 12px; overflow-y: auto; box-sizing: border-box;\n            margin-top: 10px; border-radius: 4px;\n        }\n        .log-entry { margin-bottom: 3px; line-height: 1.3; word-break: break-all; }\n        .log-info { color: #333; }\n        .log-success { color: #28a745; }\n        .log-error { color: #dc3545; font-weight: bold; }\n        .log-warn { color: #ffc107; }\n\n        /* --- START: 新增恢复条样式 --- */\n        #restoreHandle {\n            position: fixed;\n            top: 10px;\n            right: 10px;\n            padding: 8px 15px;\n            background-color: #007bff;\n            color: white;\n            border-radius: 5px;\n            box-shadow: 0 2px 5px rgba(0,0,0,0.2);\n            cursor: grab;\n            z-index: 9998;\n            font-size: 14px;\n            user-select: none;\n            display: none; /* 默认隐藏 */\n        }\n        #restoreHandle:active {\n            cursor: grabbing;\n        }\n        /* --- END: 新增恢复条样式 --- */\n    `);\n\n    // --- 创建悬浮窗 ---\n    const floatingWindow = document.createElement('div');\n    floatingWindow.id = 'floatingWindow';\n    floatingWindow.innerHTML = `\n        <div id=\"floatingWindowHeader\">\n            <span>报表助手 (双击空白处归位)</span>\n            <div id=\"floatingWindowButtons\">\n                <button id=\"minimizeButton\">最小化</button>\n            </div>\n        </div>\n        <div id=\"floatingWindowContent\">\n            <div class=\"action-buttons\">\n                <button id=\"performReportButton\">打卡报表</button>\n                <button id=\"pushNotificationButton\">推送</button>\n                <button id=\"banKickGameButton\">禁踢游戏</button>\n            </div>\n            <div class=\"csv-area-container\">\n                <div id=\"fileDropZone\">\n                    <p>拖放表格文件到此处</p>\n                    <p>支持: CSV / Excel (XLSX, XLS) / ODS</p>\n                    <p>或点击选择文件</p>\n                    <input type=\"file\" id=\"fileInput\" accept=\".csv,.xlsx,.xls,.ods\" style=\"display: none;\">\n                </div>\n                <textarea id=\"fileOutputArea\" placeholder=\"处理后的会员ID将显示在此处，点击可复制\" readonly></textarea>\n            </div>\n            <div id=\"logContainer\"></div>\n        </div>\n    `;\n    document.body.appendChild(floatingWindow);\n\n    // --- 创建恢复条 ---\n    const restoreHandle = document.createElement('div');\n    restoreHandle.id = 'restoreHandle';\n    restoreHandle.textContent = '≡ 展开报表助手';\n    document.body.appendChild(restoreHandle);\n\n    const header = document.getElementById('floatingWindowHeader');\n    const minimizeButton = document.getElementById('minimizeButton');\n    const performReportButton = document.getElementById('performReportButton');\n    const pushNotificationButton = document.getElementById('pushNotificationButton');\n    const banKickGameButton = document.getElementById('banKickGameButton');\n    const fileDropZone = document.getElementById('fileDropZone');\n    const fileInput = document.getElementById('fileInput');\n    const fileOutputArea = document.getElementById('fileOutputArea');\n    const logContainer = document.getElementById('logContainer');\n\n    let isDragging = false;\n    let offsetX, offsetY;\n    const DEFAULT_POS = { top: '50px', left: '50px' };\n\n    // --- 日志输出函数 ---\n    const MAX_LOG_ENTRIES_WINDOW = 100; // 增加悬浮窗日志条数\n    function logToWindow(message, type = 'info') {\n        while (logContainer.children.length >= MAX_LOG_ENTRIES_WINDOW) {\n            if (logContainer.firstChild) {\n                logContainer.removeChild(logContainer.firstChild);\n            }\n        }\n        const timestamp = new Date().toLocaleTimeString();\n        const logEntry = document.createElement('div');\n        logEntry.classList.add('log-entry', `log-${type}`);\n        logEntry.textContent = `[${timestamp}] ${message}`;\n        logContainer.appendChild(logEntry);\n        logContainer.scrollTop = logContainer.scrollHeight;\n    }\n\n    // --- 加载保存的悬浮窗状态 ---\n    const savedLeft = GM_getValue('floatingWindowLeft', DEFAULT_POS.left);\n    const savedTop = GM_getValue('floatingWindowTop', DEFAULT_POS.top);\n    const savedWidth = GM_getValue('floatingWindowWidth', '450px');\n    const savedHeight = GM_getValue('floatingWindowHeight', '350px');\n    const savedMinimized = GM_getValue('floatingWindowMinimized', false);\n    const savedHandleLeft = GM_getValue('restoreHandleLeft', 'auto');\n    const savedHandleTop = GM_getValue('restoreHandleTop', '10px');\n    const savedHandleRight = GM_getValue('restoreHandleRight', '10px');\n\n\n    floatingWindow.style.left = savedLeft;\n    floatingWindow.style.top = savedTop;\n    floatingWindow.style.width = savedWidth;\n    floatingWindow.style.height = savedHeight;\n\n    restoreHandle.style.left = savedHandleLeft;\n    restoreHandle.style.top = savedHandleTop;\n    restoreHandle.style.right = savedHandleRight;\n\n\n    if (savedMinimized) {\n        floatingWindow.style.display = 'none';\n        restoreHandle.style.display = 'block';\n    } else {\n        floatingWindow.style.display = 'flex';\n        restoreHandle.style.display = 'none';\n    }\n\n    logToWindow(`脚本已加载 (v2.0 - 支持多种表格格式)。悬浮窗日志最多显示 ${MAX_LOG_ENTRIES_WINDOW} 条。`, 'info');\n\n    // --- 主窗口拖动功能 ---\n    header.addEventListener('mousedown', (e) => {\n        if (e.target.tagName === 'BUTTON') return;\n        isDragging = true;\n        offsetX = e.clientX - floatingWindow.getBoundingClientRect().left;\n        offsetY = e.clientY - floatingWindow.getBoundingClientRect().top;\n        header.style.cursor = 'grabbing';\n    });\n\n    document.addEventListener('mousemove', (e) => {\n        if (!isDragging) return;\n        floatingWindow.style.left = `${e.clientX - offsetX}px`;\n        floatingWindow.style.top = `${e.clientY - offsetY}px`;\n    });\n\n    document.addEventListener('mouseup', () => {\n        if (isDragging) {\n            isDragging = false;\n            header.style.cursor = 'grab';\n            GM_setValue('floatingWindowLeft', floatingWindow.style.left);\n            GM_setValue('floatingWindowTop', floatingWindow.style.top);\n        }\n    });\n\n    // --- 恢复条拖动功能 (带边界限制) ---\n    let isHandleDragging = false;\n    let handleOffsetX, handleOffsetY;\n\n    restoreHandle.addEventListener('mousedown', (e) => {\n        isHandleDragging = true;\n        handleOffsetX = e.clientX - restoreHandle.getBoundingClientRect().left;\n        handleOffsetY = e.clientY - restoreHandle.getBoundingClientRect().top;\n        restoreHandle.style.cursor = 'grabbing';\n        // 拖动时清除 right 属性，只用 left/top 定位\n        restoreHandle.style.right = 'auto';\n    });\n\n    document.addEventListener('mousemove', (e) => {\n        if (!isHandleDragging) return;\n        let newLeft = e.clientX - handleOffsetX;\n        let newTop = e.clientY - handleOffsetY;\n        const handleRect = restoreHandle.getBoundingClientRect();\n        const winWidth = window.innerWidth;\n        const winHeight = window.innerHeight;\n\n        // 边界检测\n        newLeft = Math.max(0, Math.min(newLeft, winWidth - handleRect.width));\n        newTop = Math.max(0, Math.min(newTop, winHeight - handleRect.height));\n\n        restoreHandle.style.left = `${newLeft}px`;\n        restoreHandle.style.top = `${newTop}px`;\n    });\n\n    document.addEventListener('mouseup', () => {\n        if (isHandleDragging) {\n            isHandleDragging = false;\n            restoreHandle.style.cursor = 'grab';\n            // 保存恢复条的位置\n            GM_setValue('restoreHandleLeft', restoreHandle.style.left);\n            GM_setValue('restoreHandleTop', restoreHandle.style.top);\n            GM_setValue('restoreHandleRight', 'auto'); // 清除 right\n        }\n    });\n\n    // --- 监听悬浮窗大小变化并保存 ---\n    new ResizeObserver(entries => {\n        for (const entry of entries) {\n            if (entry.target === floatingWindow && floatingWindow.style.display !== 'none') {\n                GM_setValue('floatingWindowWidth', floatingWindow.style.width);\n                GM_setValue('floatingWindowHeight', floatingWindow.style.height);\n            }\n        }\n    }).observe(floatingWindow);\n\n    // --- 双击归位功能 ---\n    floatingWindow.addEventListener('dblclick', (e) => {\n        // 检查双击事件是否发生在功能性元素上\n        if (e.target.closest('button, input, textarea, #fileDropZone, #logContainer')) {\n            return; // 如果是，则不执行归位操作\n        }\n        logToWindow('双击空白区域，悬浮窗位置已重置。', 'info');\n        floatingWindow.style.left = DEFAULT_POS.left;\n        floatingWindow.style.top = DEFAULT_POS.top;\n        GM_setValue('floatingWindowLeft', DEFAULT_POS.left);\n        GM_setValue('floatingWindowTop', DEFAULT_POS.top);\n    });\n\n    // --- 最小化/展开功能 (已优化) ---\n    minimizeButton.addEventListener('click', () => {\n        floatingWindow.style.display = 'none';\n        restoreHandle.style.display = 'block';\n        GM_setValue('floatingWindowMinimized', true);\n        logToWindow('悬浮窗已最小化。', 'info');\n    });\n\n    restoreHandle.addEventListener('click', (e) => {\n        // 只有在非拖动结束时才触发展开\n        if (!isHandleDragging) {\n            restoreHandle.style.display = 'none';\n            floatingWindow.style.display = 'flex';\n            GM_setValue('floatingWindowMinimized', false);\n            logToWindow('悬浮窗已展开。', 'info');\n        }\n    });\n\n    // =====================================================\n    // 表格文件处理核心函数 - 支持多种格式\n    // =====================================================\n\n    /**\n     * 将Excel日期序号转换为JavaScript日期字符串\n     * @param {number} serial - Excel日期序号\n     * @returns {string} 格式化的日期字符串\n     */\n    function excelDateToJSDate(serial) {\n        if (typeof serial !== 'number') return serial;\n        // Excel基准日期: 1900-01-01 (实际上Excel错误地将1900当作闰年)\n        const utc_days  = Math.floor(serial - 25569);\n        const utc_value = utc_days * 86400;                                        \n        const date_info = new Date(utc_value * 1000);\n        \n        const year = date_info.getFullYear();\n        const month = String(date_info.getMonth() + 1).padStart(2, '0');\n        const day = String(date_info.getDate()).padStart(2, '0');\n        \n        return `${year}-${month}-${day}`;\n    }\n\n    /**\n     * 检测单元格值是否为会员ID\n     * @param {*} value - 单元格值\n     * @returns {boolean} 是否为有效的会员ID\n     */\n    function isValidMemberId(value) {\n        if (value === null || value === undefined || value === '') return false;\n        \n        // 转换为字符串\n        const strValue = String(value).trim();\n        \n        // 检查是否为纯数字（常见会员ID格式）\n        if (/^\\d+$/.test(strValue)) return true;\n        \n        // 检查是否为字母数字组合\n        if (/^[a-zA-Z0-9]+$/.test(strValue)) return true;\n        \n        return false;\n    }\n\n    /**\n     * 从CSV文本中提取会员ID\n     * @param {string} csvText - CSV文本内容\n     * @returns {Array} 会员ID数组\n     */\n    function extractMemberIdsFromCSV(csvText) {\n        logToWindow('正在解析CSV文件...', 'info');\n        \n        // 处理CSV，考虑引号包裹的情况\n        const lines = csvText.split(/\\r?\\n/).filter(line => line.trim() !== '');\n        if (lines.length === 0) {\n            throw new Error('CSV文件内容为空');\n        }\n\n        // 解析第一行作为标题\n        const headerLine = lines[0];\n        const headers = parseCSVLine(headerLine);\n        \n        // 查找\"会员ID\"列\n        let memberIdIndex = headers.findIndex(h => \n            h.trim().toLowerCase() === '会员id' || \n            h.trim() === '会员ID' ||\n            h.trim().toLowerCase() === 'memberid' ||\n            h.trim().toLowerCase() === 'member id'\n        );\n\n        // 如果没有找到\"会员ID\"列，尝试智能识别\n        let autoDetectColumn = -1;\n        if (memberIdIndex === -1) {\n            logToWindow('未找到\"会员ID\"列标题，尝试智能识别...', 'info');\n            \n            // 分析第二行数据，查找最像会员ID的列\n            if (lines.length > 1) {\n                const secondLineColumns = parseCSVLine(lines[1]);\n                for (let i = 0; i < secondLineColumns.length; i++) {\n                    if (isValidMemberId(secondLineColumns[i])) {\n                        autoDetectColumn = i;\n                        memberIdIndex = i;\n                        logToWindow(`智能识别第 ${i + 1} 列为会员ID列 (样本: ${secondLineColumns[i]})`, 'info');\n                        break;\n                    }\n                }\n            }\n            \n            if (memberIdIndex === -1) {\n                throw new Error('未找到\"会员ID\"列，且无法智能识别会员ID列');\n            }\n        } else {\n            logToWindow(`找到\"会员ID\"列，位于第 ${memberIdIndex + 1} 列`, 'info');\n        }\n\n        // 提取所有会员ID\n        const memberIds = [];\n        for (let i = 1; i < lines.length; i++) {\n            const columns = parseCSVLine(lines[i]);\n            if (columns.length > memberIdIndex) {\n                const memberId = columns[memberIdIndex].trim();\n                if (isValidMemberId(memberId)) {\n                    memberIds.push(memberId);\n                }\n            }\n        }\n\n        return memberIds;\n    }\n\n    /**\n     * 解析CSV行，正确处理引号\n     * @param {string} line - CSV行\n     * @returns {Array} 字段数组\n     */\n    function parseCSVLine(line) {\n        const result = [];\n        let current = '';\n        let inQuotes = false;\n        \n        for (let i = 0; i < line.length; i++) {\n            const char = line[i];\n            \n            if (char === '\"') {\n                if (inQuotes && line[i + 1] === '\"') {\n                    current += '\"';\n                    i++;\n                } else {\n                    inQuotes = !inQuotes;\n                }\n            } else if (char === ',' && !inQuotes) {\n                result.push(current);\n                current = '';\n            } else {\n                current += char;\n            }\n        }\n        \n        result.push(current);\n        return result;\n    }\n\n    /**\n     * 从Excel工作簿数据中提取会员ID\n     * @param {Array} sheetData - 工作表数据 (二维数组)\n     * @returns {Array} 会员ID数组\n     */\n    function extractMemberIdsFromExcelData(sheetData) {\n        if (!sheetData || sheetData.length === 0) {\n            throw new Error('Excel工作表数据为空');\n        }\n\n        logToWindow(`正在解析Excel数据，共 ${sheetData.length} 行`, 'info');\n\n        // 第一行作为标题\n        const headers = sheetData[0].map(h => {\n            const value = h === null || h === undefined ? '' : String(h);\n            return excelDateToJSDate(value);\n        });\n        \n        // 查找\"会员ID\"列\n        let memberIdIndex = headers.findIndex(h => \n            h.trim().toLowerCase() === '会员id' || \n            h.trim() === '会员ID' ||\n            h.trim().toLowerCase() === 'memberid' ||\n            h.trim().toLowerCase() === 'member id'\n        );\n\n        // 如果没有找到\"会员ID\"列，尝试智能识别\n        if (memberIdIndex === -1) {\n            logToWindow('未找到\"会员ID\"列标题，尝试智能识别...', 'info');\n            \n            // 分析第二行数据，查找最像会员ID的列\n            if (sheetData.length > 1) {\n                const secondRow = sheetData[1];\n                for (let i = 0; i < secondRow.length; i++) {\n                    const value = secondRow[i];\n                    const strValue = excelDateToJSDate(value);\n                    if (isValidMemberId(strValue)) {\n                        memberIdIndex = i;\n                        logToWindow(`智能识别第 ${i + 1} 列为会员ID列 (样本: ${strValue})`, 'info');\n                        break;\n                    }\n                }\n            }\n            \n            if (memberIdIndex === -1) {\n                throw new Error('未找到\"会员ID\"列，且无法智能识别会员ID列');\n            }\n        } else {\n            logToWindow(`找到\"会员ID\"列，位于第 ${memberIdIndex + 1} 列`, 'info');\n        }\n\n        // 提取所有会员ID\n        const memberIds = [];\n        for (let i = 1; i < sheetData.length; i++) {\n            const row = sheetData[i];\n            if (row.length > memberIdIndex) {\n                let value = row[memberIdIndex];\n                const strValue = excelDateToJSDate(value);\n                if (isValidMemberId(strValue)) {\n                    memberIds.push(strValue.trim());\n                }\n            }\n        }\n\n        return memberIds;\n    }\n\n    /**\n     * 读取Excel文件为CSV文本 (无需第三方库)\n     * 通过解析Office Open XML格式提取第一个工作表的数据\n     * @param {ArrayBuffer} arrayBuffer - 文件内容\n     * @returns {string} CSV文本\n     */\n    function readExcelAsCSV(arrayBuffer) {\n        return new Promise((resolve, reject) => {\n            logToWindow('正在解析Excel文件 (无需外部依赖)...', 'info');\n            \n            const decoder = new TextDecoder('utf-8');\n            const xmlText = decoder.decode(arrayBuffer);\n            \n            try {\n                // 解析XML文档\n                const parser = new DOMParser();\n                const xmlDoc = parser.parseFromString(xmlText, 'application/xml');\n                \n                // 查找共享字符串表\n                const sharedStrings = [];\n                const sharedStringsElement = xmlDoc.getElementsByTagName('sst')[0];\n                if (sharedStringsElement) {\n                    const siElements = sharedStringsElement.getElementsByTagName('si');\n                    for (const si of siElements) {\n                        const t = si.getElementsByTagName('t')[0];\n                        sharedStrings.push(t ? t.textContent : '');\n                    }\n                }\n                \n                // 查找第一个工作表\n                const worksheetElements = xmlDoc.getElementsByTagName('worksheet');\n                if (worksheetElements.length === 0) {\n                    throw new Error('未找到工作表');\n                }\n                \n                const worksheet = worksheetElements[0];\n                const sheetData = worksheet.getElementsByTagName('sheetData')[0];\n                if (!sheetData) {\n                    throw new Error('工作表数据为空');\n                }\n                \n                // 解析行数据\n                const rows = [];\n                const rowElements = sheetData.getElementsByTagName('row');\n                \n                for (const rowElement of rowElements) {\n                    const cells = [];\n                    const cellElements = rowElement.getElementsByTagName('c');\n                    \n                    let currentColIndex = 0;\n                    for (const cellElement of cellElements) {\n                        // 获取单元格列索引 (如A=0, B=1, AA=26等)\n                        const cellRef = cellElement.getAttribute('r');\n                        const colIndex = columnLetterToIndex(cellRef.replace(/[0-9]/g, ''));\n                        \n                        // 填充空单元格\n                        while (currentColIndex < colIndex) {\n                            cells.push('');\n                            currentColIndex++;\n                        }\n                        \n                        // 获取单元格值\n                        const cellType = cellElement.getAttribute('t');\n                        const valueElement = cellElement.getElementsByTagName('v')[0];\n                        let cellValue = '';\n                        \n                        if (valueElement) {\n                            const rawValue = valueElement.textContent;\n                            \n                            if (cellType === 's') {\n                                // 共享字符串\n                                const stringIndex = parseInt(rawValue, 10);\n                                cellValue = sharedStrings[stringIndex] || '';\n                            } else if (cellType === 'b') {\n                                // 布尔值\n                                cellValue = rawValue === '1' ? 'TRUE' : 'FALSE';\n                            } else if (cellType === 'n' || cellType === null || cellType === undefined) {\n                                // 数字\n                                const numValue = parseFloat(rawValue);\n                                if (!isNaN(numValue)) {\n                                    cellValue = String(numValue);\n                                } else {\n                                    cellValue = rawValue;\n                                }\n                            } else {\n                                // 其他类型\n                                cellValue = rawValue;\n                            }\n                        }\n                        \n                        cells.push(cellValue);\n                        currentColIndex++;\n                    }\n                    \n                    if (cells.length > 0) {\n                        rows.push(cells);\n                    }\n                }\n                \n                // 转换为CSV格式\n                const csvLines = rows.map(row => \n                    row.map(cell => {\n                        const cellStr = String(cell);\n                        // 如果包含逗号、引号或换行符，需要用引号包裹\n                        if (cellStr.includes(',') || cellStr.includes('\"') || cellStr.includes('\\n')) {\n                            return `\"${cellStr.replace(/\"/g, '\"\"')}\"`;\n                        }\n                        return cellStr;\n                    }).join(',')\n                );\n                \n                resolve(csvLines.join('\\n'));\n                \n            } catch (error) {\n                logToWindow(`Excel解析失败: ${error.message}`, 'error');\n                reject(new Error(`Excel解析失败: ${error.message}`));\n            }\n        });\n    }\n\n    /**\n     * 将列字母转换为索引 (A=0, B=1, AA=26, etc.)\n     * @param {string} letter - 列字母\n     * @returns {number} 列索引\n     */\n    function columnLetterToIndex(letter) {\n        let index = 0;\n        for (let i = 0; i < letter.length; i++) {\n            index = index * 26 + (letter.charCodeAt(i) - 64);\n        }\n        return index - 1;\n    }\n\n    /**\n     * 主文件处理函数 - 自动识别文件格式并处理\n     * @param {File} file - 文件对象\n     */\n    async function handleTableFile(file) {\n        if (!file) {\n            logToWindow('未提供文件', 'error');\n            return;\n        }\n\n        logToWindow(`开始处理文件: ${file.name} (${formatFileSize(file.size)})`, 'info');\n        fileOutputArea.value = '';\n\n        try {\n            const fileName = file.name.toLowerCase();\n            const fileType = file.type;\n\n            // 判断文件类型\n            if (fileType === 'text/csv' || fileName.endsWith('.csv')) {\n                // CSV文件\n                logToWindow('识别为CSV文件', 'info');\n                const csvText = await readFileAsText(file);\n                const memberIds = extractMemberIdsFromCSV(csvText);\n                displayResults(memberIds);\n                \n            } else if (fileName.endsWith('.xlsx') || fileName.endsWith('.xls')) {\n                // Excel文件\n                logToWindow('识别为Excel文件', 'info');\n                const arrayBuffer = await readFileAsArrayBuffer(file);\n                const csvText = await readExcelAsCSV(arrayBuffer);\n                const memberIds = extractMemberIdsFromCSV(csvText);\n                displayResults(memberIds);\n                \n            } else if (fileName.endsWith('.ods')) {\n                // ODS文件\n                logToWindow('ODS文件需要转换为CSV或Excel格式', 'warn');\n                logToWindow('建议: 在Excel中打开ODS文件，另存为.xlsx或.csv格式', 'info');\n                throw new Error('暂时不支持直接处理ODS格式，请转换为CSV或Excel格式');\n                \n            } else {\n                // 尝试按文本文件处理\n                logToWindow(`未知文件类型: ${fileType}，尝试按文本文件处理`, 'warn');\n                const text = await readFileAsText(file);\n                \n                // 检查是否看起来像CSV\n                if (text.includes(',') && text.includes('\\n')) {\n                    const memberIds = extractMemberIdsFromCSV(text);\n                    displayResults(memberIds);\n                } else {\n                    // 尝试逐行提取数字ID\n                    const lines = text.split(/\\r?\\n/).filter(line => line.trim() !== '');\n                    const memberIds = [];\n                    for (const line of lines) {\n                        const trimmed = line.trim();\n                        if (isValidMemberId(trimmed)) {\n                            memberIds.push(trimmed);\n                        }\n                    }\n                    \n                    if (memberIds.length > 0) {\n                        logToWindow(`从纯文本文件中提取到 ${memberIds.length} 个会员ID`, 'info');\n                        displayResults(memberIds);\n                    } else {\n                        throw new Error('无法从文件中识别出有效的会员ID');\n                    }\n                }\n            }\n            \n        } catch (error) {\n            logToWindow(`处理文件失败: ${error.message}`, 'error');\n            fileOutputArea.value = '';\n        }\n    }\n\n    /**\n     * 读取文件为文本\n     * @param {File} file - 文件对象\n     * @returns {Promise<string>} 文本内容\n     */\n    function readFileAsText(file) {\n        return new Promise((resolve, reject) => {\n            const reader = new FileReader();\n            reader.onload = (e) => resolve(e.target.result);\n            reader.onerror = () => reject(new Error('读取文件失败'));\n            \n            // 尝试检测编码\n            reader.readAsText(file, 'UTF-8');\n        });\n    }\n\n    /**\n     * 读取文件为ArrayBuffer\n     * @param {File} file - 文件对象\n     * @returns {Promise<ArrayBuffer>} 文件内容\n     */\n    function readFileAsArrayBuffer(file) {\n        return new Promise((resolve, reject) => {\n            const reader = new FileReader();\n            reader.onload = (e) => resolve(e.target.result);\n            reader.onerror = () => reject(new Error('读取文件失败'));\n            reader.readAsArrayBuffer(file);\n        });\n    }\n\n    /**\n     * 格式化文件大小\n     * @param {number} bytes - 字节数\n     * @returns {string} 格式化后的大小\n     */\n    function formatFileSize(bytes) {\n        if (bytes === 0) return '0 B';\n        const k = 1024;\n        const sizes = ['B', 'KB', 'MB', 'GB'];\n        const i = Math.floor(Math.log(bytes) / Math.log(k));\n        return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];\n    }\n\n    /**\n     * 显示处理结果\n     * @param {Array} memberIds - 会员ID数组\n     */\n    function displayResults(memberIds) {\n        logToWindow(`提取到 ${memberIds.length} 个会员ID (含重复)`, 'info');\n        \n        const uniqueMemberIds = [...new Set(memberIds)];\n        logToWindow(`去重后得到 ${uniqueMemberIds.length} 个唯一会员ID`, 'info');\n        \n        const result = uniqueMemberIds.join(',');\n        fileOutputArea.value = result;\n        \n        logToWindow(`文件处理完成，共提取 ${uniqueMemberIds.length} 个唯一会员ID`, 'success');\n    }\n\n    // === 事件监听器 ===\n\n    fileDropZone.addEventListener('dragover', (e) => {\n        e.preventDefault();\n        fileDropZone.classList.add('drag-over');\n    });\n\n    fileDropZone.addEventListener('dragleave', (e) => {\n        e.preventDefault();\n        fileDropZone.classList.remove('drag-over');\n    });\n\n    fileDropZone.addEventListener('drop', (e) => {\n        e.preventDefault();\n        fileDropZone.classList.remove('drag-over');\n        if (e.dataTransfer.files.length > 0) {\n            handleTableFile(e.dataTransfer.files[0]);\n        }\n    });\n\n    fileDropZone.addEventListener('click', () => {\n        fileInput.click();\n    });\n\n    fileInput.addEventListener('change', (e) => {\n        if (e.target.files.length > 0) {\n            handleTableFile(e.target.files[0]);\n        }\n    });\n\n    fileOutputArea.addEventListener('click', () => {\n        if (fileOutputArea.value) {\n            fileOutputArea.select();\n            try {\n                if (navigator.clipboard && navigator.clipboard.writeText) {\n                    navigator.clipboard.writeText(fileOutputArea.value)\n                        .then(() => logToWindow('内容已复制到剪贴板。', 'success'))\n                        .catch(err => { \n                            logToWindow('复制失败，请手动复制。', 'error'); \n                            console.error('Clipboard API 复制失败:', err); \n                        });\n                } else {\n                    document.execCommand('copy');\n                    logToWindow('内容已复制到剪贴板。', 'success');\n                }\n            } catch (err) {\n                logToWindow('复制失败，请手动复制。', 'error');\n                console.error('复制失败:', err);\n            }\n        }\n    });\n\n\n    // === 原有业务逻辑 (保持不变) ===\n\n    // --- \"打卡报表\" 按钮功能 ---\n    performReportButton.addEventListener('click', async () => {\n        performReportButton.disabled = true;\n        performReportButton.textContent = '执行中...';\n        logToWindow('开始执行报表操作...', 'info');\n        let operationTime = '';\n        try {\n            logToWindow('导航到\"消息推送\"页面...', 'info');\n            await navigateToMenu('消息推送', true);\n            await delay(2000);\n            logToWindow('点击\"消息推送\"页面的\"重置\"按钮...', 'info');\n            await clickButtonWithText('重置', document, true);\n            await delay(2000);\n            logToWindow('正在查找\"操作时间\"列的索引...', 'info');\n            let operationTimeColIndex = -1;\n            const headerRowNotification = await waitForElement('.el-table__header-wrapper th', 10000);\n            const headerCellsNotification = document.querySelectorAll('.el-table__header-wrapper thead th .cell');\n            for (let i = 0; i < headerCellsNotification.length; i++) {\n                if (headerCellsNotification[i].textContent.trim() === '操作时间') {\n                    operationTimeColIndex = i + 1;\n                    break;\n                }\n            }\n            if (operationTimeColIndex === -1) {\n                throw new Error('未在\"消息推送\"页面的表头中找到\"操作时间\"列。');\n            }\n            logToWindow(`\"操作时间\"列位于第 ${operationTimeColIndex} 列。`, 'success');\n            logToWindow('获取\"消息推送\"表格第一行\"操作时间\"数据...', 'info');\n            await waitForElement('div.el-table__body-wrapper tbody tr.el-table__row:first-child', 10000);\n            const operationTimeElement = await waitForElement(`div.el-table__body-wrapper tbody tr.el-table__row:first-child td:nth-child(${operationTimeColIndex}) div.cell`, 10000);\n            operationTime = operationTimeElement.textContent.trim();\n            logToWindow(`已成功获取操作时间: \"${operationTime}\"`, 'success');\n            highlightElement(operationTimeElement, 'blue', 1500);\n            logToWindow('导航到\"投注记录\"页面...', 'info');\n            await navigateToMenu('投注记录', true);\n            await delay(2000);\n            logToWindow('点击\"投注记录\"页面的\"重置\"按钮...', 'info');\n            await clickButtonWithText('重置', document, true);\n            await delay(2000);\n            logToWindow(`填写\"开始时间\"为: ${operationTime}`, 'info');\n            const startTimeInput = await waitForElement('input.el-range-input[placeholder=\"开始时间\"]');\n            highlightElement(startTimeInput, 'green', 1500);\n            startTimeInput.focus();\n            startTimeInput.select();\n            startTimeInput.value = operationTime;\n            startTimeInput.dispatchEvent(new Event('input', { bubbles: true }));\n            startTimeInput.dispatchEvent(new Event('change', { bubbles: true }));\n            await delay(500);\n            logToWindow('填写\"最小值\"和\"最大值\"...', 'info');\n            const minInput = await waitForElement('input.el-input__inner[placeholder=\"最小值\"]');\n            highlightElement(minInput, 'green', 1500);\n            minInput.value = '100';\n            minInput.dispatchEvent(new Event('input', { bubbles: true }));\n            minInput.dispatchEvent(new Event('change', { bubbles: true }));\n            logToWindow('已填写最小值: 100', 'success');\n            await delay(100);\n            const maxInput = await waitForElement('input.el-input__inner[placeholder=\"最大值\"]');\n            highlightElement(maxInput, 'green', 1500);\n            maxInput.value = '999999999';\n            maxInput.dispatchEvent(new Event('input', { bubbles: true }));\n            maxInput.dispatchEvent(new Event('change', { bubbles: true }));\n            logToWindow('已填写最大值: 999999999', 'success');\n            await delay(100);\n            logToWindow('点击\"搜索\"按钮...', 'info');\n            await clickButtonWithText('搜 索', document, true);\n            await delay(3000);\n            logToWindow('点击\"导出报表\"按钮...', 'info');\n            await clickButtonWithText('导出报表', document, true);\n            await delay(1000);\n            logToWindow('\"投注记录\"报表导出流程完成！', 'success');\n            logToWindow('导航到\"导出下载\"页面...', 'info');\n            await navigateToMenu('导出下载', true);\n            await delay(1000);\n            logToWindow('点击\"导出下载\"页面的\"重置\"按钮...', 'info');\n            await clickButtonWithText('重置', document, true);\n            await delay(2000);\n            let downloadClicked = false;\n            let retryCount = 0;\n            const MAX_RETRIES = 5;\n            while (!downloadClicked && retryCount < MAX_RETRIES) {\n                logToWindow(`尝试查找并点击\"下载\"按钮 (第 ${retryCount + 1} 次)...`, 'info');\n                try {\n                    let operationColIndex = -1;\n                    await waitForElement('.el-table__header-wrapper th', 10000);\n                    const headerCellsExport = document.querySelectorAll('.el-table__header-wrapper th .cell');\n                    for (let i = 0; i < headerCellsExport.length; i++) {\n                        if (headerCellsExport[i].textContent.trim() === '操作') {\n                            operationColIndex = i + 1;\n                            break;\n                        }\n                    }\n                    if (operationColIndex === -1) {\n                        throw new Error('未在\"导出下载\"页面的表头中找到\"操作\"列。');\n                    }\n                    logToWindow(`\"操作\"列位于第 ${operationColIndex} 列。`, 'success');\n                    await waitForElement('div.el-table__body-wrapper tbody tr.el-table__row:first-child', 10000);\n                    const operationCellSelector = `div.el-table__body-wrapper tbody tr.el-table__row:first-child td:nth-child(${operationColIndex})`;\n                    const operationCell = await waitForElement(operationCellSelector, 5000);\n                    const downloadButton = operationCell.querySelector('button');\n                    if (downloadButton && downloadButton.textContent.trim().includes('下载')) {\n                        highlightElement(downloadButton, 'red', 1500);\n                        downloadButton.click();\n                        logToWindow('已成功点击\"下载\"按钮。', 'success');\n                        downloadClicked = true;\n                    } else {\n                        logToWindow('未找到\"下载\"按钮，将重置并重试。', 'warn');\n                        retryCount++;\n                        if (retryCount < MAX_RETRIES) {\n                            await clickButtonWithText('重置', document);\n                            await delay(2000);\n                        }\n                    }\n                } catch (error) {\n                    logToWindow(`尝试点击下载时出错: ${error.message}，将重试。`, 'warn');\n                    retryCount++;\n                    if (retryCount < MAX_RETRIES) {\n                        await clickButtonWithText('重置', document);\n                        await delay(2000);\n                    } else {\n                        throw new Error(`达到最大重试次数 (${MAX_RETRIES})，未能点击下载。`);\n                    }\n                }\n            }\n            if (!downloadClicked) {\n                throw new Error('未能成功点击下载按钮。');\n            }\n            logToWindow('所有报表操作成功完成！', 'success');\n            GM_notification('报表操作成功完成！', '成功');\n        } catch (error) {\n            console.error('报表操作失败:', error);\n            logToWindow(`报表操作失败: ${error.message}`, 'error');\n            GM_notification(`报表操作失败: ${error.message}`, '错误');\n        } finally {\n            performReportButton.disabled = false;\n            performReportButton.textContent = '打卡报表';\n            logToWindow('报表操作结束。', 'info');\n        }\n    });\n\n    // --- \"推送\" 按钮功能 ---\n    pushNotificationButton.addEventListener('click', async () => {\n        const btn = pushNotificationButton;\n        btn.disabled = true;\n        btn.textContent = '推送中...';\n        logToWindow('开始执行消息推送操作...', 'info');\n        \n        const allMemberIds = fileOutputArea.value.split(',').map(s => s.trim()).filter(Boolean);\n        if (!allMemberIds.length) {\n            logToWindow('会员ID列表为空，请先处理表格文件。', 'error');\n            GM_notification('会员ID列表为空，请先处理表格文件。', '错误');\n            btn.disabled = false;\n            btn.textContent = '推送';\n            return;\n        }\n        \n        let batchIndex = 0;\n        const batchSize = 1000;\n        let overallBatchSummaries = [];\n        let autoExecuteTimer = null;\n        \n        function reset() {\n            if (autoExecuteTimer) {\n                clearTimeout(autoExecuteTimer);\n                autoExecuteTimer = null;\n            }\n            const extras = btn.nextElementSibling;\n            if (extras && extras.classList.contains('batch-controls')) extras.remove();\n            btn.disabled = false;\n            btn.textContent = '推送';\n            logToWindow('消息推送操作结束。', 'info');\n        }\n        \n        function renderExtras(hasMore) {\n            const extras = btn.nextElementSibling;\n            if (extras && extras.classList.contains('batch-controls')) extras.remove();\n            \n            if (!hasMore) return;\n            \n            const wrap = document.createElement('span');\n            wrap.classList.add('batch-controls');\n            wrap.style.marginLeft = '8px';\n            \n            const nextBatchBtn = document.createElement('button');\n            nextBatchBtn.textContent = '继续执行下一批';\n            nextBatchBtn.style.marginRight = '4px';\n            const countdownSpan = document.createElement('span');\n            countdownSpan.textContent = ' (3秒后自动)';\n            countdownSpan.style.marginLeft = '4px';\n            countdownSpan.style.color = '#666';\n            countdownSpan.style.fontSize = '12px';\n            nextBatchBtn.appendChild(countdownSpan);\n            \n            let countdown = 3;\n            nextBatchBtn.onclick = async () => {\n                if (autoExecuteTimer) {\n                    clearTimeout(autoExecuteTimer);\n                    autoExecuteTimer = null;\n                }\n                nextBatchBtn.disabled = true;\n                btn.disabled = true;\n                wrap.remove();\n                await runBatch();\n            };\n            wrap.appendChild(nextBatchBtn);\n            \n            autoExecuteTimer = setTimeout(async () => {\n                if (nextBatchBtn && nextBatchBtn.parentElement) {\n                    nextBatchBtn.disabled = true;\n                    btn.disabled = true;\n                    wrap.remove();\n                    await runBatch();\n                }\n            }, 3000);\n            \n            const countdownInterval = setInterval(() => {\n                countdown--;\n                if (countdownSpan.parentElement) {\n                    countdownSpan.textContent = ` (${countdown}秒后自动)`;\n                }\n                if (countdown <= 0) {\n                    clearInterval(countdownInterval);\n                }\n            }, 1000);\n            \n            const close = document.createElement('button');\n            close.textContent = '×';\n            close.onclick = () => {\n                if (autoExecuteTimer) {\n                    clearTimeout(autoExecuteTimer);\n                    autoExecuteTimer = null;\n                }\n                wrap.remove();\n                reset();\n                logToWindow('用户手动停止操作。', 'warn');\n            };\n            wrap.appendChild(close);\n            \n            btn.insertAdjacentElement('afterend', wrap);\n        }\n        \n        async function processSingleBatch(memberIds) {\n            try {\n                logToWindow('导航到\"消息推送\"页面...', 'info');\n                await navigateToMenu('消息推送', true);\n                await delay(1500);\n                \n                logToWindow('点击\"新增\"按钮...', 'info');\n                await clickButtonWithText('新增消息', document, true);\n                await delay(1500);\n                \n                const addDialogTitle = await waitForElement('.el-dialog__title', 10000, '新增');\n                const addDialog = addDialogTitle.closest('.el-dialog');\n                if (!addDialog) {\n                    throw new Error('未能找到\"新增\"弹窗。');\n                }\n                logToWindow('\"新增\"弹窗已加载。', 'success');\n                \n                // 点击 el-radio 的 label 标签\n                logToWindow('点击 el-radio 标签...', 'info');\n                const radioLabels = addDialog.querySelectorAll('label.el-radio');\n                let radioClicked = false;\n                for (const radioLabel of radioLabels) {\n                    if (!radioLabel.classList.contains('is-checked')) {\n                        highlightElement(radioLabel, 'red', 1500);\n                        simulateClickAtCenter(radioLabel);\n                        logToWindow('已点击 el-radio 标签。', 'success');\n                        radioClicked = true;\n                        await delay(500);\n                        break;\n                    }\n                }\n                if (!radioClicked) {\n                    logToWindow('未找到未选中的 el-radio 标签，可能已经选中。', 'info');\n                }\n                \n                // 查找 el-form-item is-required 内包含\"会员ID\"的div块并点击\n                logToWindow('查找\"会员ID\"输入框区域...', 'info');\n                const requiredFormItems = addDialog.querySelectorAll('.el-form-item.is-required');\n                let memberIdInputDiv = null;\n                for (const formItem of requiredFormItems) {\n                    const allDivs = formItem.querySelectorAll('div');\n                    for (const div of allDivs) {\n                        if (div.textContent.includes('会员ID')) {\n                            memberIdInputDiv = div;\n                            break;\n                        }\n                    }\n                    if (memberIdInputDiv) break;\n                }\n                \n                if (!memberIdInputDiv) {\n                    throw new Error('未找到\"会员ID\"输入框区域。');\n                }\n                \n                highlightElement(memberIdInputDiv, 'green', 1500);\n                simulateClickAtCenter(memberIdInputDiv);\n                logToWindow('已点击\"会员ID\"输入框区域。', 'success');\n                await delay(500);\n                \n                // 填写会员ID\n                logToWindow(`填写 ${memberIds.length} 个会员ID...`, 'info');\n                const memberIdTextarea = await waitForElement('textarea', 5000, null, addDialog);\n                if (memberIdTextarea) {\n                    memberIdTextarea.value = memberIds.join(',');\n                    memberIdTextarea.dispatchEvent(new Event('input', { bubbles: true }));\n                    memberIdTextarea.dispatchEvent(new Event('change', { bubbles: true }));\n                    logToWindow('会员ID已填写。', 'success');\n                } else {\n                    const memberIdInput = await waitForElement('input[placeholder*=\"会员ID\"], input[placeholder*=\"英文逗号\"]', 5000, null, addDialog);\n                    if (memberIdInput) {\n                        highlightElement(memberIdInput, 'green', 1500);\n                        memberIdInput.value = memberIds.join(',');\n                        memberIdInput.dispatchEvent(new Event('input', { bubbles: true }));\n                        memberIdInput.dispatchEvent(new Event('change', { bubbles: true }));\n                        logToWindow('会员ID已填写。', 'success');\n                    } else {\n                        throw new Error('未找到会员ID输入框。');\n                    }\n                }\n                await delay(500);\n                \n                // 查找 el-form-item item-box 内包含\"发送时间\"的标签\n                logToWindow('查找\"发送时间\"选择器区域...', 'info');\n                const itemBoxFormItems = addDialog.querySelectorAll('.el-form-item.item-box');\n                let sendTimeDiv = null;\n                for (const formItem of itemBoxFormItems) {\n                    const allDivs = formItem.querySelectorAll('div');\n                    for (const div of allDivs) {\n                        if (div.textContent.includes('发送时间')) {\n                            sendTimeDiv = div;\n                            break;\n                        }\n                    }\n                    if (sendTimeDiv) break;\n                }\n                \n                if (!sendTimeDiv) {\n                    throw new Error('未找到\"发送时间\"选择器区域。');\n                }\n                \n                // 深入查找所有输入框和label\n                logToWindow('深入查找\"开始时间\"和\"结束时间\"输入框...', 'info');\n                \n                // 获取该区域内所有可能的输入框\n                const allInputs = sendTimeDiv.querySelectorAll('input');\n                \n                // 遍历该区域的所有元素，查找包含\"开始时间\"或\"结束时间\"文字的元素，然后找到对应的输入框\n                let startTimeInput = null;\n                let endTimeInput = null;\n                \n                // 方法1：查找包含\"开始时间\"/\"结束时间\"的label，然后找相邻的输入框\n                const allLabels = sendTimeDiv.querySelectorAll('label, div, span');\n                for (const label of allLabels) {\n                    const text = label.textContent.trim();\n                    if (text.includes('开始时间') || text.includes('开始')) {\n                        // 查找该label所在form-item或父容器中的第一个input\n                        const parentFormItem = label.closest('.el-form-item') || label.closest('.el-date-editor');\n                        if (parentFormItem) {\n                            const input = parentFormItem.querySelector('input');\n                            if (input) {\n                                startTimeInput = input;\n                                break;\n                            }\n                        }\n                    }\n                }\n                \n                for (const label of allLabels) {\n                    const text = label.textContent.trim();\n                    if (text.includes('结束时间') || text.includes('结束')) {\n                        const parentFormItem = label.closest('.el-form-item') || label.closest('.el-date-editor');\n                        if (parentFormItem) {\n                            const input = parentFormItem.querySelector('input');\n                            if (input) {\n                                endTimeInput = input;\n                                break;\n                            }\n                        }\n                    }\n                }\n                \n                // 方法2：如果方法1没找到，尝试直接查找\n                if (!startTimeInput) {\n                    const startFormItem = sendTimeDiv.closest('.el-form-item');\n                    if (startFormItem) {\n                        startTimeInput = startFormItem.querySelector('input[placeholder*=\"开始\"], input[placeholder*=\"Start\"]');\n                    }\n                }\n                \n                if (!endTimeInput) {\n                    const endFormItem = sendTimeDiv.closest('.el-form-item');\n                    if (endFormItem) {\n                        endTimeInput = endFormItem.querySelector('input[placeholder*=\"结束\"], input[placeholder*=\"End\"]');\n                    }\n                }\n                \n                // 方法3：遍历所有input，通过兄弟元素判断\n                if (!startTimeInput || !endTimeInput) {\n                    const inputs = sendTimeDiv.querySelectorAll('input');\n                    for (const input of inputs) {\n                        const prevSibling = input.previousElementSibling;\n                        const nextSibling = input.nextElementSibling;\n                        const parent = input.parentElement;\n                        \n                        let labelText = '';\n                        if (prevSibling) labelText += prevSibling.textContent;\n                        if (nextSibling) labelText += nextSibling.textContent;\n                        if (parent) labelText += parent.textContent;\n                        \n                        if (!startTimeInput && (labelText.includes('开始时间') || labelText.includes('开始'))) {\n                            startTimeInput = input;\n                        }\n                        if (!endTimeInput && (labelText.includes('结束时间') || labelText.includes('结束'))) {\n                            endTimeInput = input;\n                        }\n                    }\n                }\n                \n                if (!startTimeInput) {\n                    throw new Error('未找到\"开始时间\"输入框。');\n                }\n                if (!endTimeInput) {\n                    throw new Error('未找到\"结束时间\"输入框。');\n                }\n                \n                logToWindow('成功找到\"开始时间\"和\"结束时间\"输入框。', 'success');\n                \n                // 优化：直接点击 input 标签，使用精确中心点模拟真实鼠标点击\n                logToWindow('定位\"开始时间\"input标签并计算中心点...', 'info');\n                \n                if (!startTimeInput) {\n                    throw new Error('未找到\"开始时间\"输入框。');\n                }\n                \n                highlightElement(startTimeInput, 'blue', 1500);\n                \n                // 计算精确中心点并模拟真实鼠标点击\n                const rect = startTimeInput.getBoundingClientRect();\n                const centerX = rect.left + rect.width / 2;\n                const centerY = rect.top + rect.height / 2;\n                \n                logToWindow(`Input中心点坐标: (${Math.round(centerX)}, ${Math.round(centerY)})`, 'info');\n                \n                // 模拟真实的鼠标点击事件序列\n                const eventWindow = startTimeInput.ownerDocument.defaultView || window;\n                \n                // mousedown 事件\n                startTimeInput.dispatchEvent(new MouseEvent('mousedown', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: eventWindow,\n                    clientX: centerX,\n                    clientY: centerY,\n                    button: 0\n                }));\n                \n                await delay(50);\n                \n                // mouseup 事件\n                startTimeInput.dispatchEvent(new MouseEvent('mouseup', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: eventWindow,\n                    clientX: centerX,\n                    clientY: centerY,\n                    button: 0\n                }));\n                \n                await delay(50);\n                \n                // click 事件\n                startTimeInput.dispatchEvent(new MouseEvent('click', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: eventWindow,\n                    clientX: centerX,\n                    clientY: centerY,\n                    button: 0\n                }));\n                \n                await delay(50);\n                \n                // focus 事件（确保输入框获得焦点）\n                startTimeInput.focus();\n                startTimeInput.dispatchEvent(new FocusEvent('focus', { bubbles: true }));\n                \n                logToWindow('已完成input中心点真实点击，等待时间选择器弹出...', 'info');\n                await delay(800);\n                \n                // 监测弹出时间选择器：class=\"el-popper is-pure is-light el-picker__popper\" 且style中的display:none被清除\n                logToWindow('监测时间选择器弹出状态...', 'info');\n                let startTimePicker = null;\n                let maxWaitTime = 5000;\n                let waitStartTime = Date.now();\n                \n                while (Date.now() - waitStartTime < maxWaitTime) {\n                    const allPoppers = document.querySelectorAll('.el-popper.is-pure.is-light.el-picker__popper');\n                    \n                    for (const popper of allPoppers) {\n                        const style = popper.getAttribute('style') || '';\n                        const inlineStyle = popper.style.cssText || '';\n                        \n                        // 检查 style 属性和内联样式中都不包含 display: none\n                        const hasDisplayNone = style.includes('display: none') || \n                                              style.includes('display:none') ||\n                                              inlineStyle.includes('display: none') ||\n                                              inlineStyle.includes('display:none');\n                        \n                        // 同时检查元素的实际显示状态\n                        const computedStyle = window.getComputedStyle(popper);\n                        const actualDisplay = computedStyle.display;\n                        \n                        // 只有当 style 中的 display: none 被清除，且实际显示不为 none 时才算弹出\n                        if (!hasDisplayNone && actualDisplay !== 'none') {\n                            startTimePicker = popper;\n                            logToWindow('检测到时间选择器已弹出（display: none 已清除）。', 'success');\n                            break;\n                        }\n                    }\n                    \n                    if (startTimePicker) break;\n                    await delay(200);\n                }\n                \n                if (!startTimePicker) {\n                    throw new Error('时间选择器未弹出。');\n                }\n                \n                logToWindow('时间选择器已弹出，选择第一个可用日期...', 'info');\n                \n                // 在时间选择器中查找所有class包含\"available\"的td标签\n                const availableDateCells = startTimePicker.querySelectorAll('td.available');\n                if (availableDateCells.length === 0) {\n                    throw new Error('未找到可用日期。');\n                }\n                \n                // 选择第一个可用日期\n                const firstAvailableDate = availableDateCells[0];\n                highlightElement(firstAvailableDate, 'green', 1000);\n                simulateClickAtCenter(firstAvailableDate);\n                logToWindow('已选择第一个可用日期。', 'success');\n                await delay(500);\n                \n                logToWindow('开始时间选择完成，继续处理结束时间...', 'info');\n                \n                // 优化：直接点击结束时间 input 标签，使用精确中心点模拟真实鼠标点击\n                logToWindow('定位\"结束时间\"input标签并计算中心点...', 'info');\n                \n                if (!endTimeInput) {\n                    throw new Error('未找到\"结束时间\"输入框。');\n                }\n                \n                highlightElement(endTimeInput, 'red', 1500);\n                \n                // 计算精确中心点并模拟真实鼠标点击\n                const endRect = endTimeInput.getBoundingClientRect();\n                const endCenterX = endRect.left + endRect.width / 2;\n                const endCenterY = endRect.top + endRect.height / 2;\n                \n                logToWindow(`Input中心点坐标: (${Math.round(endCenterX)}, ${Math.round(endCenterY)})`, 'info');\n                \n                // 模拟真实的鼠标点击事件序列\n                const endEventWindow = endTimeInput.ownerDocument.defaultView || window;\n                \n                // mousedown 事件\n                endTimeInput.dispatchEvent(new MouseEvent('mousedown', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: endEventWindow,\n                    clientX: endCenterX,\n                    clientY: endCenterY,\n                    button: 0\n                }));\n                \n                await delay(50);\n                \n                // mouseup 事件\n                endTimeInput.dispatchEvent(new MouseEvent('mouseup', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: endEventWindow,\n                    clientX: endCenterX,\n                    clientY: endCenterY,\n                    button: 0\n                }));\n                \n                await delay(50);\n                \n                // click 事件\n                endTimeInput.dispatchEvent(new MouseEvent('click', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: endEventWindow,\n                    clientX: endCenterX,\n                    clientY: endCenterY,\n                    button: 0\n                }));\n                \n                await delay(50);\n                \n                // focus 事件（确保输入框获得焦点）\n                endTimeInput.focus();\n                endTimeInput.dispatchEvent(new FocusEvent('focus', { bubbles: true }));\n                \n                logToWindow('已完成input中心点真实点击，等待时间选择器弹出...', 'info');\n                await delay(800);\n                \n                // 监测弹出时间选择器：class=\"el-popper is-pure is-light el-picker__popper\" 且style中的display:none被清除\n                logToWindow('监测时间选择器弹出状态...', 'info');\n                let endTimePicker = null;\n                waitStartTime = Date.now();\n                \n                while (Date.now() - waitStartTime < maxWaitTime) {\n                    const allPoppers = document.querySelectorAll('.el-popper.is-pure.is-light.el-picker__popper');\n                    \n                    for (const popper of allPoppers) {\n                        const style = popper.getAttribute('style') || '';\n                        const inlineStyle = popper.style.cssText || '';\n                        \n                        // 检查 style 属性和内联样式中都不包含 display: none\n                        const hasDisplayNone = style.includes('display: none') || \n                                              style.includes('display:none') ||\n                                              inlineStyle.includes('display: none') ||\n                                              inlineStyle.includes('display:none');\n                        \n                        // 同时检查元素的实际显示状态\n                        const computedStyle = window.getComputedStyle(popper);\n                        const actualDisplay = computedStyle.display;\n                        \n                        // 只有当 style 中的 display: none 被清除，且实际显示不为 none 时才算弹出\n                        if (!hasDisplayNone && actualDisplay !== 'none') {\n                            endTimePicker = popper;\n                            logToWindow('检测到时间选择器已弹出（display: none 已清除）。', 'success');\n                            break;\n                        }\n                    }\n                    if (endTimePicker) break;\n                    await delay(200);\n                }\n                \n                if (!endTimePicker) {\n                    throw new Error('时间选择器未弹出。');\n                }\n                \n                logToWindow('时间选择器已弹出，选择最后一个可用日期...', 'info');\n                \n                // 在时间选择器中查找所有class包含\"available\"的td标签\n                const endAvailableDateCells = endTimePicker.querySelectorAll('td.available');\n                if (endAvailableDateCells.length === 0) {\n                    throw new Error('未找到可用日期。');\n                }\n                \n                // 选择最后一个可用日期\n                const lastAvailableDate = endAvailableDateCells[endAvailableDateCells.length - 1];\n                highlightElement(lastAvailableDate, 'green', 1000);\n                simulateClickAtCenter(lastAvailableDate);\n                logToWindow(`已选择最后一个可用日期（第 ${endAvailableDateCells.length} 个可用日期）。`, 'success');\n                await delay(500);\n                \n                logToWindow('结束时间选择完成，继续填写其他信息...', 'info');\n                await delay(500);\n                \n                // 查找包含\"标题\"的 el-form-item is-required 整个div块并点击其中心\n                logToWindow('查找\"标题\"所在的 el-form-item is-required 整个div块...', 'info');\n                const requiredFormItemsTitle = addDialog.querySelectorAll('.el-form-item.is-required');\n                let titleFormItem = null;\n                for (const formItem of requiredFormItemsTitle) {\n                    const allDivs = formItem.querySelectorAll('div');\n                    for (const div of allDivs) {\n                        if (div.textContent.includes('标题')) {\n                            titleFormItem = formItem;\n                            break;\n                        }\n                    }\n                    if (titleFormItem) break;\n                }\n                \n                if (!titleFormItem) {\n                    throw new Error('未找到\"标题\"所在的 el-form-item is-required div块。');\n                }\n                \n                highlightElement(titleFormItem, 'green', 1500);\n                \n                // 计算精确中心点并模拟真实鼠标点击\n                const titleRect = titleFormItem.getBoundingClientRect();\n                const titleCenterX = titleRect.left + titleRect.width / 2;\n                const titleCenterY = titleRect.top + titleRect.height / 2;\n                \n                logToWindow(`标题div块中心点坐标: (${Math.round(titleCenterX)}, ${Math.round(titleCenterY)})`, 'info');\n                \n                // 模拟真实的鼠标点击事件序列\n                const titleEventWindow = titleFormItem.ownerDocument.defaultView || window;\n                \n                // mousedown 事件\n                titleFormItem.dispatchEvent(new MouseEvent('mousedown', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: titleEventWindow,\n                    clientX: titleCenterX,\n                    clientY: titleCenterY,\n                    button: 0\n                }));\n                \n                await delay(50);\n                \n                // mouseup 事件\n                titleFormItem.dispatchEvent(new MouseEvent('mouseup', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: titleEventWindow,\n                    clientX: titleCenterX,\n                    clientY: titleCenterY,\n                    button: 0\n                }));\n                \n                await delay(50);\n                \n                // click 事件\n                titleFormItem.dispatchEvent(new MouseEvent('click', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: titleEventWindow,\n                    clientX: titleCenterX,\n                    clientY: titleCenterY,\n                    button: 0\n                }));\n                \n                logToWindow('已点击\"标题\" el-form-item is-required 整个div块中心。', 'success');\n                await delay(500);\n                \n                // 填写标题 - 精确查找并点击24x24尺寸的快捷按钮\n                logToWindow('查找标题富文本编辑器的24x24快捷按钮...', 'info');\n                \n                // 查找包含特定文字的div\n                let targetButton = null;\n                let targetTextDiv = null;\n                \n                // 先查找包含\"按Shitf+Enter键打开对话框\"或类似提示文字的div\n                const allDivs = titleFormItem.querySelectorAll('div');\n                for (const div of allDivs) {\n                    const divText = div.textContent.trim();\n                    if (divText.includes('按Shitf+Enter') || divText.includes('Shift+Enter') || \n                        divText.includes('打开对话框')) {\n                        targetTextDiv = div;\n                        logToWindow(`找到提示文字div: \"${divText.substring(0, 50)}...\"`, 'info');\n                        break;\n                    }\n                }\n                \n                if (targetTextDiv) {\n                    // 在提示文字div的父级或兄弟元素中查找24x24的按钮\n                    const allButtons = titleFormItem.querySelectorAll('button, [role=\"button\"], span');\n                    for (const btn of allButtons) {\n                        const rect = btn.getBoundingClientRect();\n                        const width = Math.round(rect.width);\n                        const height = Math.round(rect.height);\n                        \n                        // 精确匹配24x24尺寸\n                        if (width === 24 && height === 24) {\n                            targetButton = btn;\n                            logToWindow(`找到24x24按钮，坐标: (${Math.round(rect.left)}, ${Math.round(rect.top)})`, 'info');\n                            break;\n                        }\n                    }\n                }\n                \n                // 如果没通过文字找到，直接在整个form-item中查找24x24的按钮\n                if (!targetButton) {\n                    logToWindow('未通过提示文字找到按钮，直接查找24x24按钮...', 'info');\n                    const allButtons = titleFormItem.querySelectorAll('button, [role=\"button\"], span, div');\n                    for (const btn of allButtons) {\n                        const rect = btn.getBoundingClientRect();\n                        const width = Math.round(rect.width);\n                        const height = Math.round(rect.height);\n                        \n                        if (width === 24 && height === 24) {\n                            targetButton = btn;\n                            logToWindow(`直接找到24x24按钮，坐标: (${Math.round(rect.left)}, ${Math.round(rect.top)})`, 'info');\n                            break;\n                        }\n                    }\n                }\n                \n                if (targetButton) {\n                    highlightElement(targetButton, 'green', 1500);\n                    simulateClickAtCenter(targetButton);\n                    logToWindow('已点击标题编辑器的24x24快捷按钮，等待300毫秒...', 'info');\n                    await delay(300);\n                }\n                \n                // 使用新的TinyMCE输入方法\n                logToWindow('使用TinyMCE富文本编辑器输入标题...', 'info');\n                await inputToTinyMCEEditor(titleFormItem, 'Lembrete de restrição de jogo', '标题');\n                logToWindow('标题已填写。', 'success');\n                await delay(500);\n                \n                // 查找包含\"内容\"的 el-form-item is-required 整个div块并点击其中心\n                logToWindow('查找\"内容\"所在的 el-form-item is-required 整个div块...', 'info');\n                let contentFormItem = null;\n                for (const formItem of requiredFormItemsTitle) {\n                    const allDivs = formItem.querySelectorAll('div');\n                    for (const div of allDivs) {\n                        if (div.textContent.includes('内容')) {\n                            contentFormItem = formItem;\n                            break;\n                        }\n                    }\n                    if (contentFormItem) break;\n                }\n                \n                if (!contentFormItem) {\n                    throw new Error('未找到\"内容\"所在的 el-form-item is-required div块。');\n                }\n                \n                highlightElement(contentFormItem, 'green', 1500);\n                \n                // 计算精确中心点并模拟真实鼠标点击\n                const contentRect = contentFormItem.getBoundingClientRect();\n                const contentCenterX = contentRect.left + contentRect.width / 2;\n                const contentCenterY = contentRect.top + contentRect.height / 2;\n                \n                logToWindow(`内容div块中心点坐标: (${Math.round(contentCenterX)}, ${Math.round(contentCenterY)})`, 'info');\n                \n                // 模拟真实的鼠标点击事件序列\n                const contentEventWindow = contentFormItem.ownerDocument.defaultView || window;\n                \n                // mousedown 事件\n                contentFormItem.dispatchEvent(new MouseEvent('mousedown', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: contentEventWindow,\n                    clientX: contentCenterX,\n                    clientY: contentCenterY,\n                    button: 0\n                }));\n                \n                await delay(50);\n                \n                // mouseup 事件\n                contentFormItem.dispatchEvent(new MouseEvent('mouseup', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: contentEventWindow,\n                    clientX: contentCenterX,\n                    clientY: contentCenterY,\n                    button: 0\n                }));\n                \n                await delay(50);\n                \n                // click 事件\n                contentFormItem.dispatchEvent(new MouseEvent('click', {\n                    bubbles: true,\n                    cancelable: true,\n                    view: contentEventWindow,\n                    clientX: contentCenterX,\n                    clientY: contentCenterY,\n                    button: 0\n                }));\n                \n                logToWindow('已点击\"内容\" el-form-item is-required 整个div块中心。', 'success');\n                await delay(500);\n                \n                // 填写内容 - 精确查找并点击24x24尺寸的快捷按钮\n                const contentText = 'Caro usuário, o sistema detectou que sua conta tem lucros enormes. Para a segurança de sua conta, retire dinheiro imediatamente. Após a conclusão do saque, sua experiência de jogo retornará automaticamente ao normal após a próxima recarga ser concluída. Se você tiver alguma dúvida, clique no serviço de atendimento ao cliente online para consulta. Desejo a você uma vida feliz!';\n                logToWindow('查找内容富文本编辑器的24x24快捷按钮...', 'info');\n                \n                // 查找包含特定文字的div\n                let contentTargetButton = null;\n                let contentTargetTextDiv = null;\n                \n                // 先查找包含\"按Shitf+Enter键打开对话框\"或类似提示文字的div\n                const allContentDivs = contentFormItem.querySelectorAll('div');\n                for (const div of allContentDivs) {\n                    const divText = div.textContent.trim();\n                    if (divText.includes('按Shitf+Enter') || divText.includes('Shift+Enter') || \n                        divText.includes('打开对话框')) {\n                        contentTargetTextDiv = div;\n                        logToWindow(`找到内容提示文字div: \"${divText.substring(0, 50)}...\"`, 'info');\n                        break;\n                    }\n                }\n                \n                if (contentTargetTextDiv) {\n                    // 在提示文字div的父级或兄弟元素中查找24x24的按钮\n                    const allContentButtons = contentFormItem.querySelectorAll('button, [role=\"button\"], span');\n                    for (const btn of allContentButtons) {\n                        const rect = btn.getBoundingClientRect();\n                        const width = Math.round(rect.width);\n                        const height = Math.round(rect.height);\n                        \n                        // 精确匹配24x24尺寸\n                        if (width === 24 && height === 24) {\n                            contentTargetButton = btn;\n                            logToWindow(`找到内容24x24按钮，坐标: (${Math.round(rect.left)}, ${Math.round(rect.top)})`, 'info');\n                            break;\n                        }\n                    }\n                }\n                \n                // 如果没通过文字找到，直接在整个form-item中查找24x24的按钮\n                if (!contentTargetButton) {\n                    logToWindow('未通过提示文字找到按钮，直接查找24x24按钮...', 'info');\n                    const allContentButtons = contentFormItem.querySelectorAll('button, [role=\"button\"], span, div');\n                    for (const btn of allContentButtons) {\n                        const rect = btn.getBoundingClientRect();\n                        const width = Math.round(rect.width);\n                        const height = Math.round(rect.height);\n                        \n                        if (width === 24 && height === 24) {\n                            contentTargetButton = btn;\n                            logToWindow(`直接找到内容24x24按钮，坐标: (${Math.round(rect.left)}, ${Math.round(rect.top)})`, 'info');\n                            break;\n                        }\n                    }\n                }\n                \n                if (contentTargetButton) {\n                    highlightElement(contentTargetButton, 'green', 1500);\n                    simulateClickAtCenter(contentTargetButton);\n                    logToWindow('已点击内容编辑器的24x24快捷按钮，等待300毫秒...', 'info');\n                    await delay(300);\n                }\n                \n                // 使用新的TinyMCE输入方法\n                logToWindow('使用TinyMCE富文本编辑器输入内容...', 'info');\n                await inputToTinyMCEEditor(contentFormItem, contentText, '内容');\n                logToWindow('内容已填写。', 'success');\n                await delay(500);\n                \n                // 查找class为\"el-form-item\"且包含文字\"是否弹窗\"的div标签\n                logToWindow('查找\"是否弹窗\"选项区域...', 'info');\n                let popupFormItem = null;\n                const allFormItemsPopup = addDialog.querySelectorAll('.el-form-item');\n                for (const formItem of allFormItemsPopup) {\n                    const allDivs = formItem.querySelectorAll('div');\n                    for (const div of allDivs) {\n                        if (div.textContent.includes('是否弹窗')) {\n                            popupFormItem = formItem;\n                            break;\n                        }\n                    }\n                    if (popupFormItem) break;\n                }\n                \n                if (!popupFormItem) {\n                    throw new Error('未找到\"是否弹窗\"选项区域。');\n                }\n                \n                highlightElement(popupFormItem, 'green', 1500);\n                logToWindow('已找到\"是否弹窗\"的 el-form-item 区域。', 'success');\n                \n                // 查找该区域内的 input 标签开关\n                const popupInput = popupFormItem.querySelector('input');\n                if (!popupInput) {\n                    throw new Error('未找到\"是否弹窗\"的input标签开关。');\n                }\n                \n                highlightElement(popupInput, 'green', 1500);\n                \n                // 检查当前状态\n                const currentAriaChecked = popupInput.getAttribute('aria-checked');\n                logToWindow(`\"是否弹窗\"当前状态: aria-checked=\"${currentAriaChecked}\"`, 'info');\n                \n                if (currentAriaChecked !== 'true') {\n                    logToWindow('\"是否弹窗\"当前为关闭状态，准备打开...', 'info');\n                    simulateClickAtCenter(popupInput);\n                    await delay(300);\n                    \n                    // 再次检查状态\n                    const newAriaChecked = popupInput.getAttribute('aria-checked');\n                    if (newAriaChecked === 'true') {\n                        logToWindow('已成功打开\"是否弹窗\"开关（aria-checked=\"true\"）。', 'success');\n                    } else {\n                        throw new Error('打开\"是否弹窗\"开关失败，状态未改变。');\n                    }\n                } else {\n                    logToWindow('\"是否弹窗\"已经是打开状态（aria-checked=\"true\"）。', 'info');\n                }\n                await delay(500);\n                \n                // 查找class为\"el-form-item is-required\"且包含文字\"弹窗方式\"的div标签\n                logToWindow('查找\"弹窗方式\"选择器区域...', 'info');\n                let popupModeFormItem = null;\n                const requiredFormItemsPopupMode = addDialog.querySelectorAll('.el-form-item.is-required');\n                for (const formItem of requiredFormItemsPopupMode) {\n                    const allDivs = formItem.querySelectorAll('div');\n                    for (const div of allDivs) {\n                        if (div.textContent.includes('弹窗方式')) {\n                            popupModeFormItem = formItem;\n                            break;\n                        }\n                    }\n                    if (popupModeFormItem) break;\n                }\n                \n                if (!popupModeFormItem) {\n                    throw new Error('未找到\"弹窗方式\"选择器区域。');\n                }\n                \n                highlightElement(popupModeFormItem, 'green', 1500);\n                logToWindow('已找到\"弹窗方式\"的 el-form-item is-required 区域。', 'success');\n                \n                // 深入该div标签内查找input多选下拉框\n                const popupModeInput = popupModeFormItem.querySelector('input');\n                if (!popupModeInput) {\n                    throw new Error('未找到\"弹窗方式\"的input多选下拉框。');\n                }\n                \n                highlightElement(popupModeInput, 'green', 1500);\n                logToWindow('已找到\"弹窗方式\"的input下拉框。', 'success');\n                \n                // 点击input展开选项\n                simulateClickAtCenter(popupModeInput);\n                logToWindow('已点击\"弹窗方式\"input下拉框，等待选项展开...', 'info');\n                await delay(800);\n                \n                // 选择\"每次登录\"选项\n                logToWindow('选择\"每次登录\"选项...', 'info');\n                await clickSpanWithText('每次登录', true, true);\n                logToWindow('已选择\"每次登录\"。', 'success');\n                await delay(500);\n                \n                // 点击保存按钮（在\"取消保存\"按钮组中）\n                logToWindow('点击\"保存\"按钮...', 'info');\n                await clickButtonWithText('保存', addDialog, true);\n                await delay(2000);\n                \n                // 等待页面返回到\"消息推送\"窗口\n                logToWindow('等待页面返回到\"消息推送\"窗口...', 'info');\n                await delay(1500);\n                \n                // 查找表格中最新新增的消息行中的\"操作\"列内的\"审核\"按键\n                logToWindow('查找最新新增消息行的\"审核\"按钮...', 'info');\n                \n                // 等待表格加载完成\n                await waitForElement('div.el-table__body-wrapper tbody tr.el-table__row', 10000);\n                \n                // 获取所有行，找到最新的一行（通常在表格顶部）\n                const allRows = document.querySelectorAll('div.el-table__body-wrapper tbody tr.el-table__row');\n                if (allRows.length === 0) {\n                    throw new Error('未找到表格中的任何消息行。');\n                }\n                \n                // 查找\"操作\"列的索引\n                let operationColIndex = -1;\n                const headerCells = document.querySelectorAll('.el-table__header-wrapper thead th .cell');\n                for (let i = 0; i < headerCells.length; i++) {\n                    if (headerCells[i].textContent.trim() === '操作') {\n                        operationColIndex = i + 1;\n                        break;\n                    }\n                }\n                \n                if (operationColIndex === -1) {\n                    throw new Error('未在表头中找到\"操作\"列。');\n                }\n                \n                logToWindow(`\"操作\"列位于第 ${operationColIndex} 列。`, 'success');\n                \n                // 获取最新的一行（第一行）\n                const latestRow = allRows[0];\n                highlightElement(latestRow, 'yellow', 1000);\n                \n                // 在最新行中查找\"操作\"列的\"审核\"按钮\n                const operationCell = latestRow.querySelector(`td:nth-child(${operationColIndex})`);\n                if (!operationCell) {\n                    throw new Error('未找到最新消息行的\"操作\"单元格。');\n                }\n                \n                const auditButton = operationCell.querySelector('button');\n                if (!auditButton || !auditButton.textContent.includes('审核')) {\n                    throw new Error('未找到\"审核\"按钮。');\n                }\n                \n                highlightElement(auditButton, 'green', 1500);\n                simulateClickAtCenter(auditButton);\n                logToWindow('已点击最新消息行的\"审核\"按钮。', 'success');\n                await delay(1000);\n                \n                // 查找审核弹窗中的\"通过并发送\"按钮\n                logToWindow('查找审核弹窗中的\"通过并发送\"按钮...', 'info');\n                \n                // 等待审核弹窗出现\n                const auditDialogTitle = await waitForElement('.el-dialog__title', 10000, '审核');\n                const auditDialog = auditDialogTitle.closest('.el-dialog');\n                if (!auditDialog) {\n                    throw new Error('未找到\"审核\"弹窗。');\n                }\n                logToWindow('\"审核\"弹窗已打开。', 'success');\n                \n                // 点击\"通过并发送\"按钮\n                await clickButtonWithText('通过并发送', auditDialog, true);\n                logToWindow('已点击\"通过并发送\"按钮。', 'success');\n                await delay(1500);\n                \n                return true;\n            } catch (error) {\n                logToWindow(`批次处理失败: ${error.message}`, 'error');\n                throw error;\n            }\n        }\n        \n        async function runBatch() {\n            const start = batchIndex * batchSize;\n            const slice = allMemberIds.slice(start, start + batchSize);\n            const hasMoreBatches = (start + batchSize < allMemberIds.length);\n            \n            if (!slice.length) {\n                logToWindow('所有批次处理完毕。', 'success');\n                if (overallBatchSummaries.length > 0) {\n                    logToWindow('--- 最终操作总结 ---', 'info');\n                    overallBatchSummaries.forEach(summary => logToWindow(summary, 'info'));\n                }\n                if (typeof GM_notification === 'function') {\n                    GM_notification('所有推送批次处理完毕。', '成功');\n                }\n                return reset();\n            }\n            \n            logToWindow(`开始第 ${batchIndex + 1} 批（共 ${slice.length} 条）...`, 'info');\n            btn.textContent = `推送中... (第 ${batchIndex + 1} 批)`;\n            \n            try {\n                await processSingleBatch(slice);\n                overallBatchSummaries.push(`批次 ${batchIndex + 1} (推送ID: ${slice.length})：已完成`);\n                batchIndex++;\n                \n                if (hasMoreBatches) {\n                    btn.disabled = false;\n                    btn.textContent = '推送';\n                    renderExtras(true);\n                } else {\n                    logToWindow('所有批次处理完毕。', 'success');\n                    if (overallBatchSummaries.length > 0) {\n                        logToWindow('--- 最终操作总结 ---', 'info');\n                        overallBatchSummaries.forEach(summary => logToWindow(summary, 'info'));\n                    }\n                    if (typeof GM_notification === 'function') {\n                        GM_notification('所有推送批次处理完毕。', '成功');\n                    }\n                    reset();\n                }\n            } catch (err) {\n                logToWindow(`批次处理失败: ${err.message}`, 'error');\n                if (typeof GM_notification === 'function') {\n                    GM_notification(`批次处理失败: ${err.message}`, '错误');\n                }\n                reset();\n            }\n        }\n        \n        try {\n            await runBatch();\n        } catch (err) {\n            logToWindow(`推送操作失败: ${err.message}`, 'error');\n            if (typeof GM_notification === 'function') {\n                GM_notification(`推送操作失败: ${err.message}`, '错误');\n            }\n            reset();\n        }\n    });\n\n    // --- \"禁踢游戏\" 按钮功能 ---\n    banKickGameButton.addEventListener('click', async function() {\n        const btn = this;\n        let currentHighlightElement = null;\n        let overallBatchSummaries = [];\n        function _highlightElement(element, duration = 1000) {\n            if (!element || !element.style) return;\n            if (currentHighlightElement && currentHighlightElement !== element && currentHighlightElement.style) {\n                currentHighlightElement.style.boxShadow = '';\n                currentHighlightElement.style.border = '';\n                currentHighlightElement.style.transition = '';\n            }\n            currentHighlightElement = element;\n            element.style.boxShadow = '0 0 0 3px rgba(255, 0, 0, 0.6)';\n            element.style.border = '2px solid red';\n            element.style.transition = 'boxShadow 0.2s ease-out, border 0.2s ease-out';\n            setTimeout(() => {\n                if (currentHighlightElement === element && element.style) {\n                    element.style.boxShadow = '';\n                    element.style.border = '';\n                    element.style.transition = '';\n                    currentHighlightElement = null;\n                }\n            }, duration);\n        }\n        function _simulateClickAtCenter(element) {\n            if (!element) return;\n            _highlightElement(element, 1000);\n            const rect = element.getBoundingClientRect();\n            const x = rect.left + rect.width / 2;\n            const y = rect.top + rect.height / 2;\n            element.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true, clientX: x, clientY: y }));\n            element.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, cancelable: true, clientX: x, clientY: y }));\n            element.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, clientX: x, clientY: y }));\n        }\n        async function _waitForElement(selector, timeout = 10000, text = null, root = document, checkVisibility = true) {\n            const start = Date.now();\n            while (Date.now() - start < timeout) {\n                const elements = root.querySelectorAll(selector);\n                for (const element of elements) {\n                    let isVisible = true;\n                    if (checkVisibility) {\n                        const style = window.getComputedStyle(element);\n                        const rect = element.getBoundingClientRect();\n                        isVisible = (element.offsetParent !== null && style.visibility !== 'hidden' && style.display !== 'none' && rect.width > 0 && rect.height > 0);\n                    }\n                    if (isVisible && (text === null || element.textContent.includes(text))) {\n                        if (checkVisibility) {\n                            _highlightElement(element, 1500);\n                        }\n                        return element;\n                    }\n                }\n                await delay(100);\n            }\n            throw new Error(`等待元素超时: ${selector}${text ? ` (包含文本: \"${text}\")` : ''}`);\n        }\n        async function _clickElement(selector, text, root = document, timeout = 5000, clickParent = false, element = null, checkVisibility = true) {\n            let targetElement = element;\n            if (!targetElement) {\n                targetElement = await _waitForElement(selector, timeout, text, root, checkVisibility);\n            }\n            if (targetElement) {\n                const logIdentifier = text || selector || (targetElement.tagName + (targetElement.className ? '.' + targetElement.className.split(' ')[0] : ''));\n                logToWindow(`准备点击元素: \"${logIdentifier}\"`, 'info');\n                if (clickParent) {\n                    _simulateClickAtCenter(targetElement.parentElement);\n                } else {\n                    _simulateClickAtCenter(targetElement);\n                }\n                await delay(50);\n                logToWindow(`成功点击元素: \"${logIdentifier}\"`, 'success');\n            } else {\n                throw new Error(`未找到可点击的元素: \"${text || selector}\"`);\n            }\n        }\n        async function _clickButtonWithText(buttonText, root = document) {\n            const buttons = root.querySelectorAll('button, [role=\"button\"]');\n            for (const btn of buttons) {\n                if (btn.textContent.trim() === buttonText.trim()) {\n                    await _clickElement(null, buttonText, null, null, false, btn);\n                    return;\n                }\n            }\n            throw new Error(`未找到文本为 \"${buttonText}\" 的按钮`);\n        }\n        let allIds = [];\n        let batchIndex = 0;\n        let balanceColIdx = null;\n        const batchSize = 100;\n        function reset() {\n            removeExtras();\n            btn.disabled = false;\n            btn.textContent = '禁踢游戏';\n            logToWindow('\"禁踢游戏\"操作结束。', 'info');\n            allIds = [];\n            batchIndex = 0;\n            balanceColIdx = null;\n            overallBatchSummaries = [];\n        }\n        function removeExtras() {\n            const ex = btn.nextElementSibling;\n            if (ex && ex.classList.contains('batch-controls')) ex.remove();\n        }\n        let autoExecuteTimer = null;\n        function renderExtras(hasMore) {\n            removeExtras();\n            const wrap = document.createElement('span');\n            wrap.classList.add('batch-controls');\n            wrap.style.marginLeft = '8px';\n            if (hasMore) {\n                const nextBatchBtn = document.createElement('button');\n                nextBatchBtn.textContent = '继续执行下一批';\n                nextBatchBtn.style.marginRight = '4px';\n                const countdownSpan = document.createElement('span');\n                countdownSpan.textContent = ' (3秒后自动)';\n                countdownSpan.style.marginLeft = '4px';\n                countdownSpan.style.color = '#666';\n                countdownSpan.style.fontSize = '12px';\n                nextBatchBtn.appendChild(countdownSpan);\n                let countdown = 3;\n                nextBatchBtn.onclick = async () => {\n                    if (autoExecuteTimer) {\n                        clearTimeout(autoExecuteTimer);\n                        autoExecuteTimer = null;\n                    }\n                    nextBatchBtn.disabled = true;\n                    btn.disabled = true;\n                    wrap.remove();\n                    await runBatch();\n                };\n                wrap.appendChild(nextBatchBtn);\n                // 启动倒计时自动执行\n                autoExecuteTimer = setTimeout(async () => {\n                    if (nextBatchBtn && nextBatchBtn.parentElement) {\n                        nextBatchBtn.disabled = true;\n                        btn.disabled = true;\n                        wrap.remove();\n                        await runBatch();\n                    }\n                }, 3000);\n                // 更新倒计时显示\n                const countdownInterval = setInterval(() => {\n                    countdown--;\n                    if (countdownSpan.parentElement) {\n                        countdownSpan.textContent = ` (${countdown}秒后自动)`;\n                    }\n                    if (countdown <= 0) {\n                        clearInterval(countdownInterval);\n                    }\n                }, 1000);\n            }\n            const close = document.createElement('button');\n            close.textContent = '×';\n            close.onclick = () => {\n                if (autoExecuteTimer) {\n                    clearTimeout(autoExecuteTimer);\n                    autoExecuteTimer = null;\n                }\n                wrap.remove();\n                reset();\n                logToWindow('用户手动停止操作。', 'warn');\n            };\n            wrap.appendChild(close);\n            btn.insertAdjacentElement('afterend', wrap);\n        }\n        async function clickVisibleOption(optionText, timeout = 8000) {\n            const start = Date.now();\n            while (Date.now() - start < timeout) {\n                const items = Array.from(document.querySelectorAll('.el-dropdown-menu__item, .el-select-dropdown__item span, li.el-dropdown-menu__item'));\n                const target = items.find(it => {\n                    if (it.textContent.trim() !== optionText.trim()) return false;\n                    const style = window.getComputedStyle(it);\n                    const rect = it.getBoundingClientRect();\n                    return (it.offsetParent !== null && style.visibility !== 'hidden' && style.display !== 'none' && rect.width > 0 && rect.height > 0);\n                });\n                if (target) {\n                    _highlightElement(target, 1500);\n                    _simulateClickAtCenter(target);\n                    await delay(200);\n                    logToWindow(`点击下拉菜单选项: \"${optionText}\"`, 'success');\n                    return;\n                }\n                await delay(200);\n            }\n            throw new Error(`下拉菜单项未找到或不可见: \"${optionText}\" (超时 ${timeout}ms)`);\n        }\n        async function smartSelectRows(balanceColumnIndex) {\n            logToWindow('开始智能勾选符合条件的表格行...', 'info');\n            const tableBody = await _waitForElement('div.el-table__body-wrapper tbody', 10000);\n            await _waitForElement('tr.el-table__row', 10000, null, tableBody);\n            await delay(300);\n            logToWindow('表格主体中已检测到至少一行数据，并已等待渲染稳定。', 'info');\n            const rows = tableBody.querySelectorAll('tr.el-table__row');\n            logToWindow(`在表格体中找到 ${rows.length} 行数据。`, 'info');\n            let selectedCount = 0;\n            let processedCount = 0;\n            if (rows.length === 0) {\n                logToWindow('当前页面没有找到任何表格行，跳过勾选。', 'warn');\n                return 0;\n            }\n            for (const row of rows) {\n                processedCount++;\n                try {\n                    const balanceCell = await _waitForElement(`td:nth-child(${balanceColumnIndex}) div.cell`, 5000, null, row);\n                    const balanceText = balanceCell.textContent.trim();\n                    const balance = parseFloat(balanceText);\n                    if (!isNaN(balance) && balance >= 100) {\n                        logToWindow(`行 ${processedCount}: 余额 ${balance} >= 100。检查勾选框...`, 'info');\n                        const checkboxLabel = await _waitForElement('td.el-table-column--selection label.el-checkbox', 5000, null, row);\n                        const actualCheckboxInput = checkboxLabel.querySelector('.el-checkbox__original');\n                        if (checkboxLabel && actualCheckboxInput && !actualCheckboxInput.checked) {\n                            await _clickElement(null, null, null, null, false, checkboxLabel);\n                            selectedCount++;\n                            logToWindow(`行 ${processedCount}: 成功勾选。`, 'success');\n                            await delay(50);\n                        } else if (actualCheckboxInput && actualCheckboxInput.checked) {\n                            logToWindow(`行 ${processedCount}: 余额 ${balance} >= 100，但已勾选。`, 'info');\n                        } else {\n                            logToWindow(`行 ${processedCount}: 余额 ${balance} >= 100，但未找到或无法点击勾选框。`, 'warn');\n                        }\n                    } else {\n                        logToWindow(`行 ${processedCount}: 余额 ${balance} < 100 或无效。跳过。`, 'info');\n                    }\n                } catch (e) {\n                    logToWindow(`处理行 ${processedCount} 时发生错误: ${e.message}`, 'warn');\n                }\n            }\n            logToWindow(`智能勾选完成。共处理 ${processedCount} 行，勾选 ${selectedCount} 行。`, 'success');\n            return selectedCount;\n        }\n        async function waitForCondition(conditionFn, timeout = 15000, errorMessage = '条件未满足') {\n            const start = Date.now();\n            while (Date.now() - start < timeout) {\n                if (await conditionFn()) {\n                    return true;\n                }\n                await delay(200);\n            }\n            throw new Error(errorMessage);\n        }\n        async function performBatchActions(initialSelectedCount) {\n            const currentBatchActionsSummary = [];\n            if (initialSelectedCount === 0) {\n                logToWindow('本次未勾选任何行，跳过批量操作。', 'info');\n                return currentBatchActionsSummary;\n            }\n            logToWindow('开始执行批量操作：批量游戏踢下线...', 'info');\n            const batchOpSpan = await _waitForElement('button.el-button--primary span', 5000, '批量操作');\n            const actualBatchButton = batchOpSpan.closest('button');\n            _highlightElement(actualBatchButton, 2000);\n            logToWindow('模拟鼠标悬停在\"批量操作\"按钮上以显示下拉菜单...', 'info');\n            actualBatchButton.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, cancelable: true }));\n            actualBatchButton.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true, cancelable: true }));\n            await delay(500);\n            logToWindow('正在等待下拉菜单选项出现并点击\"批量游戏踢下线\"...', 'info');\n            await clickVisibleOption('批量游戏踢下线（不支持踢出厂家：BBGT、DB、MG、EVO、PG）');\n            await delay(1000);\n            logToWindow(`已成功对 ${initialSelectedCount} 个会员执行\"批量游戏踢下线\"操作。`, 'success');\n            currentBatchActionsSummary.push(`踢下线 ${initialSelectedCount} 行`);\n            actualBatchButton.dispatchEvent(new MouseEvent('mouseleave', { bubbles: true, cancelable: true }));\n            actualBatchButton.dispatchEvent(new MouseEvent('mouseout', { bubbles: true, cancelable: true }));\n            await delay(200);\n            logToWindow('等待表格行取消勾选（踢下线操作后）...', 'info');\n            await waitForCondition(async () => {\n                return document.querySelectorAll('td.el-table-column--selection .el-checkbox__original:checked').length === 0;\n            }, 30000, '等待表格行取消勾选超时（踢下线操作后）');\n            logToWindow('表格行已取消勾选。', 'success');\n            logToWindow('重新智能勾选符合条件的表格行，以执行第二次批量操作...', 'info');\n            const reSelectedCount = await smartSelectRows(balanceColIdx);\n            if (reSelectedCount === 0) {\n                logToWindow('重新勾选后，没有符合条件的行，跳过第二次批量操作。', 'warn');\n                return currentBatchActionsSummary;\n            }\n            logToWindow('开始执行批量操作：批量禁止进入游戏...', 'info');\n            logToWindow('再次模拟鼠标悬停在\"批量操作\"按钮上以显示下拉菜单...', 'info');\n            _highlightElement(actualBatchButton, 2000);\n            actualBatchButton.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, cancelable: true }));\n            actualBatchButton.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true, cancelable: true }));\n            await delay(500);\n            logToWindow('正在等待下拉菜单选项出现并点击\"批量禁止进入游戏\"...', 'info');\n            await clickVisibleOption('批量禁止进入游戏（无法进游戏，其他操作不影响）');\n            await delay(1000);\n            logToWindow(`已成功对 ${reSelectedCount} 个会员执行\"批量禁止进入游戏\"操作。`, 'success');\n            currentBatchActionsSummary.push(`禁游戏 ${reSelectedCount} 行`);\n            actualBatchButton.dispatchEvent(new MouseEvent('mouseleave', { bubbles: true, cancelable: true }));\n            actualBatchButton.dispatchEvent(new MouseEvent('mouseout', { bubbles: true, cancelable: true }));\n            await delay(200);\n            logToWindow('等待表格行取消勾选（禁止进入游戏操作后）...', 'info');\n            await waitForCondition(async () => {\n                return document.querySelectorAll('td.el-table-column--selection .el-checkbox__original:checked').length === 0;\n            }, 30000, '等待表格行取消勾选超时（禁止进入游戏操作后）');\n            logToWindow('表格行已取消勾选。', 'success');\n            logToWindow('所有批量操作（踢下线和禁止进入游戏）已成功完成。', 'success');\n            return currentBatchActionsSummary;\n        }\n        async function doSearchAndSelect(idSlice) {\n            logToWindow('开始执行搜索和选择流程...', 'info');\n            \n            // 使用旧版的精确导航方式：直接点击链接而不是通过菜单文本匹配\n            await _clickElement('div.tags-li a[href=\"/user-manage/all-member\"]', null, document);\n            await delay(800);\n            \n            // 尝试点击重置按钮（带空格和不带空格都尝试）\n            try {\n                await _clickButtonWithText('重置', document);\n                logToWindow('已点击\"重置\"按钮。', 'success');\n            } catch (error) {\n                logToWindow(`未找到\"重置\"按钮，尝试\"重 置\"...`, 'warn');\n                try {\n                    await _clickButtonWithText('重 置', document);\n                    logToWindow('已点击\"重 置\"按钮。', 'success');\n                } catch (error2) {\n                    throw new Error('未找到\"重置\"或\"重 置\"按钮。');\n                }\n            }\n            await delay(800);\n            await _clickButtonWithText('高级搜索', document);\n            await delay(800);\n            const advTitle = await _waitForElement('.el-dialog__title', 5000, '高级搜索');\n            const advDialog = advTitle.closest('.el-dialog');\n            await _clickButtonWithText('重置', advDialog);\n            await delay(500);\n            const radio = await _waitForElement('input[type=\"radio\"][value=\"2\"]', 5000, null, advDialog);\n            _simulateClickAtCenter(radio.closest('label.el-radio'));\n            await delay(300);\n            const ta = await _waitForElement('textarea[placeholder*=\"英文逗号隔开\"]', 5000, null, advDialog);\n            _highlightElement(ta, 1000);\n            ta.value = idSlice.join(',');\n            ta.dispatchEvent(new Event('input', { bubbles: true }));\n            logToWindow(`已在文本框中输入 ${idSlice.length} 个会员ID。`, 'info');\n            await delay(300);\n            const vipIn = await _waitForElement('input[placeholder=\"VIP等级\"]', 5000, null, advDialog);\n            _simulateClickAtCenter(vipIn);\n            await delay(200);\n            await clickVisibleOption('VIP0');\n            await delay(50);\n            await clickVisibleOption('VIP1');\n            await delay(50);\n            await clickVisibleOption('VIP2');\n            await delay(50);\n            logToWindow('已选择 VIP 等级。', 'info');\n            await _clickButtonWithText('确认', advDialog);\n            await delay(500);\n            logToWindow('已点击高级搜索\"确认\"按钮。', 'info');\n            \n            // 使用旧版的分页设置方式：通过el-input__wrapper索引\n            const wrappers = Array.from(document.querySelectorAll('div.el-input__wrapper'));\n            const pgWrap = wrappers[5];\n            if (!pgWrap) {\n                throw new Error('未找到分页设置的输入框（el-input__wrapper[5]）。请检查页面结构或调整索引。');\n            }\n            _simulateClickAtCenter(pgWrap.querySelector('input') || pgWrap);\n            await delay(200);\n            await clickVisibleOption('100条/页');\n            await delay(500);\n            logToWindow('已设置每页显示 100 条。', 'info');\n            logToWindow('等待表格加载完成（可能包含加载蒙版和数据渲染）...', 'info');\n            try {\n                await _waitForElement('.el-loading-mask', 2000, null, document, false);\n                logToWindow('检测到表格加载中，等待加载完成...', 'info');\n                await waitForCondition(async () => {\n                    const loadingMask = document.querySelector('.el-loading-mask');\n                    return loadingMask === null || window.getComputedStyle(loadingMask).display === 'none' || loadingMask.offsetParent === null;\n                }, 10000, '等待表格加载完成超时（加载蒙版未消失）');\n                logToWindow('表格加载完成（加载蒙版已消失）。', 'success');\n            } catch (e) {\n                logToWindow('未检测到表格加载蒙版或加载蒙版等待超时（可能加载很快），继续。', 'warn');\n            }\n            await _waitForElement('div.el-table__body-wrapper tbody tr.el-table__row', 15000, null, document, true);\n            await delay(500);\n            logToWindow('表格行已加载并可见，并已等待渲染稳定。', 'info');\n            if (balanceColIdx === null) {\n                const headerCells = document.querySelectorAll('.el-table__header-wrapper th .cell');\n                let foundBalanceCol = false;\n                headerCells.forEach((c, i) => {\n                    if (c.textContent.trim() === '余额') {\n                        balanceColIdx = i + 1;\n                        foundBalanceCol = true;\n                    }\n                });\n                if (!foundBalanceCol) {\n                    throw new Error('未找到\"余额\"列，无法进行余额筛选。');\n                }\n                logToWindow(`\"余额\"列索引为: ${balanceColIdx}`, 'info');\n            }\n            logToWindow('调用 smartSelectRows 进行智能勾选...', 'info');\n            const count = await smartSelectRows(balanceColIdx);\n            logToWindow(`smartSelectRows 返回勾选数量: ${count}`, 'info');\n            return count;\n        }\n        async function runBatch() {\n            btn.disabled = true;\n            const start = batchIndex * batchSize;\n            const slice = allIds.slice(start, start + batchSize);\n            const hasMoreBatches = (start + batchSize < allIds.length);\n            if (!slice.length) {\n                logToWindow('所有批次处理完毕。', 'success');\n                if (overallBatchSummaries.length > 0) {\n                    logToWindow('--- 最终操作总结 ---', 'info');\n                    overallBatchSummaries.forEach(summary => logToWindow(summary, 'info'));\n                }\n                if (typeof GM_notification === 'function') {\n                    GM_notification('所有批次处理完毕。', '成功');\n                }\n                return reset();\n            }\n            logToWindow(`开始第 ${batchIndex + 1} 批（共 ${slice.length} 条）…`, 'info');\n            btn.textContent = `执行中... (第 ${batchIndex + 1} 批)`;\n            try {\n                const selectedCount = await doSearchAndSelect(slice);\n                logToWindow(`doSearchAndSelect 流程完成，本次勾选数量: ${selectedCount}`, 'info');\n                const batchActionsSummary = await performBatchActions(selectedCount);\n                if (batchActionsSummary.length > 0) {\n                    overallBatchSummaries.push(`批次 ${batchIndex + 1} (处理ID: ${slice.length})：${batchActionsSummary.join(', ')}`);\n                } else {\n                    overallBatchSummaries.push(`批次 ${batchIndex + 1} (处理ID: ${slice.length})：无符合条件的批量操作`);\n                }\n                batchIndex++;\n                if (hasMoreBatches) {\n                    btn.disabled = false;\n                    btn.textContent = '禁踢游戏';\n                    renderExtras(true);\n                } else {\n                    logToWindow('所有批次处理完毕。', 'success');\n                    if (overallBatchSummaries.length > 0) {\n                        logToWindow('--- 最终操作总结 ---', 'info');\n                        overallBatchSummaries.forEach(summary => logToWindow(summary, 'info'));\n                    }\n                    if (typeof GM_notification === 'function') {\n                        GM_notification('所有批次处理完毕。', '成功');\n                    }\n                    reset();\n                }\n            } catch (err) {\n                logToWindow(`批次处理失败: ${err.message}`, 'error');\n                if (typeof GM_notification === 'function') {\n                    GM_notification(`批次处理失败: ${err.message}`, '错误');\n                }\n                reset();\n            }\n        }\n        btn.disabled = true;\n        btn.textContent = '执行中...';\n        logToWindow('开始执行\"禁踢游戏\"操作...', 'info');\n        if (!fileOutputArea) {\n            logToWindow('错误: 未找到全局 fileOutputArea 元素。', 'error');\n            if (typeof GM_notification === 'function') {\n                GM_notification('错误: 未找到表格输入区域。', '错误');\n            }\n            return reset();\n        }\n        allIds = fileOutputArea.value.split(',').map(s => s.trim()).filter(Boolean);\n        if (!allIds.length) {\n            logToWindow('会员ID列表为空，请先拖入表格文件并处理。', 'error');\n            if (typeof GM_notification === 'function') {\n                GM_notification('会员ID列表为空，请先拖入表格文件并处理。', '错误');\n            }\n            return reset();\n        }\n        try {\n            await runBatch();\n        } catch (err) {\n            logToWindow(`操作失败: ${err.message}`, 'error');\n            if (typeof GM_notification === 'function') {\n                GM_notification(`操作失败: ${err.message}`, '错误');\n            }\n            reset();\n        }\n    });\n\n})();\n","functional_script_code_hash":"e8e17e9cf3474d66229174a9c8576212b2734db1ffbfa0d757424b8d7b92bdb2","loader_script_hash":"035f2d5b91af78bd8d4f0ecef490768c03e1e401363d0177500d2c3d1e6ceefd","config":{"feature_x_enabled":true,"keyword_list":["example","test"],"salesmartly_api_key":"YOUR_SALESMARTLY_API_KEY_IF_NEEDED"}}