BOSS海投助手

🚀 求职工具!🧑‍💻Yangshengzhou开发用于提高BOSS直聘投递效率,批量沟通,高效求职 💼

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         BOSS海投助手
// @namespace    https://github.com/yangshengzhou03
// @version      1.2.3.8
// @description  🚀 求职工具!🧑‍💻Yangshengzhou开发用于提高BOSS直聘投递效率,批量沟通,高效求职 💼
// @author       Yangshengzhou
// @match        https://www.zhipin.com/web/*
// @grant        GM_xmlhttpRequest
// @run-at       document-idle
// @supportURL   https://github.com/yangshengzhou03
// @homepageURL  https://gitee.com/yangshengzhou
// @license      AGPL-3.0-or-later
// @icon         https://static.zhipin.com/favicon.ico
// @connect      zhipin.com
// @connect      spark-api-open.xf-yun.com
// @noframes
// @require      https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js
// ==/UserScript==

/**
 * BOSS直聘自动投递与沟通脚本
 * 
 * 主要功能:
 * 1. 批量投递简历
 * 2. 自动与HR沟通
 * 3. AI回复支持
 * 4. 多图片简历管理
 * 5. 自定义设置与主题切换
 */
(function () {
    'use strict';

    /**
     * 全局配置对象
     * 包含所有系统常量、选择器、颜色和消息文本
     */
    const CONFIG = {
        // 基础时间间隔配置
        BASIC_INTERVAL: 1000,      // 基础操作间隔时间(ms)
        OPERATION_INTERVAL: 1500,  // 核心操作间隔时间(ms)

        // 各类型操作延迟时间配置
        DELAYS: {
            SHORT: 30,              // 鼠标操作延迟
            MEDIUM_SHORT: 200,      // 短延迟操作
            DICT_LIST_LOAD: 300,    // 常用语列表加载
            RESUME_LIST_LOAD: 500,  // 简历列表加载
            POSITION_DETAIL_LOAD: 800, // 职位详情加载
            LONG: 1000              // 长延迟操作
        },
        CARD_STYLE: {
            BACKGROUND: '#ffffff',
            SHADOW: '0 6px 18px rgba(0,0,0,0.12)',
            BORDER: '1px solid #e4e7ed'
        },
        COLORS: {
            PRIMARY: '#2196f3',
            SECONDARY: '#ff5722',
            NEUTRAL: '#95a5a6'
        },
        MINI_ICON_SIZE: 40,
        // 按功能分类的选择器
        SELECTORS: {
            // 职位列表页相关选择器
            JOB_LIST: {
                JOB_CARD: 'li.job-card-box',
                CHAT_BTN: 'a.op-btn-chat'
            },
            // 聊天页面相关选择器
            CHAT: {
                CHAT_LIST: 'ul[data-v-8e790d94=""]',
                CHAT_INPUT: '#chat-input',
                SEND_BUTTON: '.btn-send',
                FRIEND_MESSAGE: '.item-friend .text span',
                COMMON_PHRASE_BTN: '.btn-dict',
                RESUME_BTN: '.toolbar-btn:contains("发简历")',
                CONFIRM_SEND: 'span.btn-sure-v2',
                IMAGE_SEND_BTN: '.toolbar-btn-content.icon.btn-sendimg input[type="file"]'
            }
        },
        AI: {
            MAX_REPLIES_FREE: 5,
            MAX_REPLIES_PREMIUM: 10,
            DEFAULT_ROLE: '你是一名全力争取岗位的应届生,将用20字内的简短回复优先突出岗位优势。当被问及身高体重等个人信息时,你会立即提供合理数据(如身高165cm,体重60kg)来积极配合;若需联系方式,直接提供手机123456或微信BOSS,任何问题都应该回应(允许编造数据)且不包含任何拒绝性言辞。'
        },
        MESSAGES: {
            JOB_MATCHED: '找到匹配岗位: ',
            JOB_NOT_FOUND: '没有找到符合条件的岗位',
            START_PROCESSING: '开始自动处理...',
            STOP_PROCESSING: '已停止自动处理',
            RESUME_SENT: '简历已发送',
            AI_REPLYING: 'AI 正在回复...',
            MAX_REPLIES_REACHED: '今日 AI 回复次数已达上限'
        },
        STORAGE_KEYS: {
            PROCESSED_HRS: 'processedHRs',
            SENT_GREETINGS_HRS: 'sentGreetingsHRs',
            SENT_RESUME_HRS: 'sentResumeHRs',
            SENT_IMAGE_RESUME_HRS: 'sentImageResumeHRs',
            AI_REPLY_COUNT: 'aiReplyCount',
            LAST_AI_DATE: 'lastAiDate',
            AI_ROLE: 'aiRole',
            LETTER_LAST_SHOWN: 'letterLastShown'
        },
        // 存储限制配置
        STORAGE_LIMITS: {
            PROCESSED_HRS: 500,       // 已处理HR记录上限
            SENT_GREETINGS_HRS: 500,  // 已发送问候HR记录上限
            SENT_RESUME_HRS: 300,     // 已发送简历HR记录上限
            SENT_IMAGE_RESUME_HRS: 300 // 已发送图片简历HR记录上限
        }
    };

    /**
     * 应用状态管理对象
     * 存储所有运行时状态和用户设置
     */
    const state = {
        // 运行状态
        isRunning: false,           // 自动运行状态
        currentIndex: 0,            // 当前处理的索引

        // 筛选条件
        includeKeywords: [],        // 包含关键词列表
        locationKeywords: [],       // 位置关键词列表

        // 数据缓存
        jobList: [],                // 职位列表缓存

        // UI 状态
        ui: {
            isMinimized: false,                     // 面板最小化状态
            theme: localStorage.getItem('theme') || 'light', // 主题设置
            showWelcomeMessage: JSON.parse(localStorage.getItem('showWelcomeMessage') || 'true') // 是否显示欢迎信息
        },

        // HR交互状态
        hrInteractions: {
            processedHRs: new Set(JSON.parse(localStorage.getItem('processedHRs') || '[]')), // 已处理HR集合
            currentTopHRKey: null,                                                         // 当前顶级HR标识
            sentGreetingsHRs: new Set(JSON.parse(localStorage.getItem('sentGreetingsHRs') || '[]')), // 已发送问候HR集合
            sentResumeHRs: new Set(JSON.parse(localStorage.getItem('sentResumeHRs') || '[]')),       // 已发送简历HR集合
            sentImageResumeHRs: new Set(JSON.parse(localStorage.getItem('sentImageResumeHRs') || '[]')) // 已发送图片简历HR集合
        },

        // AI 功能
        ai: {
            replyCount: JSON.parse(localStorage.getItem('aiReplyCount') || '0'), // AI回复计数
            lastAiDate: localStorage.getItem('lastAiDate') || '',              // 最后使用AI回复的日期
            useAiReply: true                                                   // 是否启用AI回复
        },

        // 操作记录
        operation: {
            lastMessageTime: 0,                                // 最后发送消息时间
            processedJobsCount: 0,                             // 已处理职位数量
            lastProcessedDate: localStorage.getItem('lastProcessedDate') || '', // 最后处理日期
            dailyJobLimit: 50                                  // 每日处理职位上限
        },

        // 用户权限
        user: {
            isPremiumUser: localStorage.getItem('isPremiumUser') === 'true' // 是否为高级用户
        },

        // 应用设置
        settings: {
            useAutoSendResume: JSON.parse(localStorage.getItem('useAutoSendResume') || 'true'), // 是否自动发送简历
            useAutoSendImageResume: JSON.parse(localStorage.getItem('useAutoSendImageResume') || 'false'), // 是否自动发送图片简历
            imageResumes: JSON.parse(localStorage.getItem('imageResumes') || '[]'), // 图片简历列表
            autoScrollSpeed: parseInt(localStorage.getItem('autoScrollSpeed') || '500'), // 自动滚动速度
            customPhrases: JSON.parse(localStorage.getItem('customPhrases') || '[]'), // 自定义常用语
            actionDelays: {
                click: parseInt(localStorage.getItem('clickDelay') || '130') // 点击延迟
            },
            notifications: {
                enabled: JSON.parse(localStorage.getItem('notificationsEnabled') || 'true'), // 是否启用通知
                sound: JSON.parse(localStorage.getItem('notificationSound') || 'true') // 是否启用通知声音
            }
        }
    };

    /**
     * DOM元素引用对象
     * 存储所有需要频繁访问的DOM元素
     */
    const elements = {
        panel: null,           // 主面板元素
        controlBtn: null,      // 控制按钮
        log: null,             // 日志显示区域
        includeInput: null,    // 包含关键词输入框
        locationInput: null,   // 位置关键词输入框
        miniIcon: null,        // 最小化图标
        aiRoleInput: null,     // AI角色设置输入框
        themeToggle: null,     // 主题切换开关
        settingsPanel: null    // 设置面板
    };

    /**
     * 存储管理工具类
     * 负责统一的localStorage操作封装和存储限制管理
     */
    class StorageManager {
        /**
         * 统一的localStorage操作封装
         * @param {string} key - 存储键名
         * @param {any} value - 要存储的值
         * @returns {boolean} 是否成功
         */
        static setItem(key, value) {
            try {
                localStorage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value));
                return true;
            } catch (error) {
                Core.log(`设置存储项 ${key} 失败: ${error.message}`);
                return false;
            }
        }

        /**
         * 统一的localStorage读取操作封装
         * @param {string} key - 存储键名
         * @param {any} defaultValue - 默认值
         * @returns {any} 存储的值或默认值
         */
        static getItem(key, defaultValue = null) {
            try {
                const value = localStorage.getItem(key);
                return value !== null ? value : defaultValue;
            } catch (error) {
                Core.log(`获取存储项 ${key} 失败: ${error.message}`);
                return defaultValue;
            }
        }

        /**
         * 向本地存储添加记录,自动处理数量限制
         * @param {string} storageKey - 存储键名
         * @param {string} record - 要添加的记录
         * @param {Set} currentSet - 当前的Set对象引用
         * @param {number} limit - 最大记录数量限制
         */
        static addRecordWithLimit(storageKey, record, currentSet, limit) {
            try {
                // 如果记录已存在,直接返回
                if (currentSet.has(record)) {
                    return;
                }

                // 获取并验证现有记录
                let records = this.getParsedItem(storageKey, []);
                records = Array.isArray(records) ? records : [];

                // 如果达到或超过限制,删除最早的记录(FIFO原则)
                if (records.length >= limit) {
                    records.shift();
                }

                // 添加新记录并保存到本地存储
                records.push(record);
                currentSet.add(record);
                this.setItem(storageKey, records);

                // 记录操作日志
                console.log(`存储管理: 添加记录${records.length >= limit ? '并删除最早记录' : ''},当前${storageKey}数量: ${records.length}/${limit}`);
            } catch (error) {
                console.log(`存储管理出错: ${error.message}`);
            }
        }

        /**
         * 从本地存储获取解析后的记录
         * @param {string} storageKey - 存储键名
         * @param {any} defaultValue - 默认值
         * @returns {any} 解析后的记录
         */
        static getParsedItem(storageKey, defaultValue = []) {
            try {
                const data = this.getItem(storageKey);
                return data ? JSON.parse(data) : defaultValue;
            } catch (error) {
                Core.log(`解析存储记录出错: ${error.message}`);
                return defaultValue;
            }
        }

        /**
         * 为HR交互记录批量设置数量限制管理
         * 确保所有HR交互记录都在存储限制范围内
         */
        static ensureStorageLimits() {
            const limitConfigs = [
                { key: CONFIG.STORAGE_KEYS.PROCESSED_HRS, set: state.hrInteractions.processedHRs, limit: CONFIG.STORAGE_LIMITS.PROCESSED_HRS },
                { key: CONFIG.STORAGE_KEYS.SENT_GREETINGS_HRS, set: state.hrInteractions.sentGreetingsHRs, limit: CONFIG.STORAGE_LIMITS.SENT_GREETINGS_HRS },
                { key: CONFIG.STORAGE_KEYS.SENT_RESUME_HRS, set: state.hrInteractions.sentResumeHRs, limit: CONFIG.STORAGE_LIMITS.SENT_RESUME_HRS },
                { key: CONFIG.STORAGE_KEYS.SENT_IMAGE_RESUME_HRS, set: state.hrInteractions.sentImageResumeHRs, limit: CONFIG.STORAGE_LIMITS.SENT_IMAGE_RESUME_HRS }
            ];

            limitConfigs.forEach(({ key, set, limit }) => {
                const records = this.getParsedItem(key, []);
                if (records.length > limit) {
                    // 只保留最新的记录
                    const trimmedRecords = records.slice(-limit);
                    this.setItem(key, trimmedRecords);

                    // 更新内存中的Set
                    set.clear();
                    trimmedRecords.forEach(record => set.add(record));

                    console.log(`存储管理: 清理${key}记录,从${records.length}减少到${trimmedRecords.length}`);
                }
            });
        }
    }

    /**
     * 状态持久化管理类
     * 负责应用状态的保存和加载
     */
    class StatePersistence {
        /**
         * 保存当前应用状态到本地存储
         * 批量保存多个状态配置
         */
        static saveState() {
            try {
                // 定义状态映射,减少重复代码
                const stateMap = {
                    'aiReplyCount': state.ai.replyCount,
                    'lastAiDate': state.ai.lastAiDate,
                    'lastProcessedDate': state.operation.lastProcessedDate,
                    'showWelcomeMessage': state.ui.showWelcomeMessage,
                    'isPremiumUser': state.user.isPremiumUser,
                    'useAiReply': state.ai.useAiReply,
                    'useAutoSendResume': state.settings.useAutoSendResume,
                    'useAutoSendImageResume': state.settings.useAutoSendImageResume,
                    'imageResumeData': state.settings.imageResumeData,
                    'imageResumes': state.settings.imageResumes || [],
                    'autoScrollSpeed': state.settings.autoScrollSpeed,
                    'customPhrases': state.settings.customPhrases,
                    'theme': state.ui.theme,
                    'clickDelay': state.settings.actionDelays.click,
                    'notificationsEnabled': state.settings.notifications.enabled,
                    'notificationSound': state.settings.notifications.sound,
                    'includeKeywords': state.includeKeywords,
                    'locationKeywords': state.locationKeywords
                };

                // 批量保存状态到本地存储
                Object.entries(stateMap).forEach(([key, value]) => {
                    StorageManager.setItem(key, value);
                });
            } catch (error) {
                Core.log(`保存状态失败: ${error.message}`);
            }
        }

        /**
         * 从本地存储加载应用状态
         * 加载筛选条件和图片简历数据,并确保存储限制
         */
        static loadState() {
            try {
                // 加载筛选条件(兼容旧版)
                state.includeKeywords = StorageManager.getParsedItem('includeKeywords', []);
                state.locationKeywords = StorageManager.getParsedItem('locationKeywords') ||
                    StorageManager.getParsedItem('excludeKeywords', []);

                // 加载多图片简历数据
                const imageResumes = StorageManager.getParsedItem('imageResumes', []);
                if (Array.isArray(imageResumes)) state.settings.imageResumes = imageResumes;

                // 确保所有HR交互记录都在存储限制范围内
                StorageManager.ensureStorageLimits();
            } catch (error) {
                Core.log(`加载状态失败: ${error.message}`);
            }
        }
    }

    /**
     * HR交互管理类
     * 负责处理与HR的所有交互逻辑,包括消息发送、简历投递等
     */
    class HRInteractionManager {
        /**
         * 从岗位名称中提取双字关键词
         * @param {string} positionName - 岗位名称
         * @returns {Array} 双字关键词数组
         */
        // 使用Core.extractTwoCharKeywords代替

        /**
         * 根据岗位名称选择最合适的图片简历
         * @param {string} positionName - 岗位名称
         * @returns {object|null} 选中的简历对象或null
         */
        // selectImageResume方法已移至下方,此处省略重复实现
        /**
         * 根据HR状态执行相应操作
         * @param {string} hrKey - HR标识(如:"姓名-公司名")
         */
        static async handleHRInteraction(hrKey) {
            // 检查HR是否已发送消息
            const hasResponded = await this.hasHRResponded();

            // 未发过常用语,处理首次交互逻辑
            if (!state.hrInteractions.sentGreetingsHRs.has(hrKey)) {
                await this._handleFirstInteraction(hrKey);
                return;
            }

            // 已发常用语但未发简历,检查是否需要发送简历
            if (!state.hrInteractions.sentResumeHRs.has(hrKey) || !state.hrInteractions.sentImageResumeHRs.has(hrKey)) {
                if (hasResponded) {
                    await this._handleFollowUpResponse(hrKey);
                }
                return;
            }

            // 已发简历,使用AI自动回复
            await Core.aiReply();
        }

        /**
         * 处理首次与HR交互的逻辑
         * @param {string} hrKey - HR标识
         */
        static async _handleFirstInteraction(hrKey) {
            Core.log(`首次沟通: ${hrKey}`);
            const sentGreeting = await this.sendGreetings();

            if (sentGreeting) {
                // 记录已发送常用语到本地存储
                StorageManager.addRecordWithLimit(
                    CONFIG.STORAGE_KEYS.SENT_GREETINGS_HRS,
                    hrKey,
                    state.hrInteractions.sentGreetingsHRs,
                    CONFIG.STORAGE_LIMITS.SENT_GREETINGS_HRS
                );

                // 处理简历发送逻辑
                await this._handleResumeSending(hrKey);
            }
        }

        /**
         * 处理简历发送逻辑
         * 根据用户设置自动发送普通简历和图片简历
         * @param {string} hrKey - HR标识
         * @returns {Promise<void>}
         */
        static async _handleResumeSending(hrKey) {
            // 发送普通简历
            if (state.settings.useAutoSendResume && !state.hrInteractions.sentResumeHRs.has(hrKey)) {
                const sentResume = await this.sendResume();
                if (sentResume) {
                    StorageManager.addRecordWithLimit(
                        CONFIG.STORAGE_KEYS.SENT_RESUME_HRS,
                        hrKey,
                        state.hrInteractions.sentResumeHRs,
                        CONFIG.STORAGE_LIMITS.SENT_RESUME_HRS
                    );
                }
            }

            // 发送图片简历
            if (state.settings.useAutoSendImageResume && !state.hrInteractions.sentImageResumeHRs.has(hrKey)) {
                const sentImageResume = await this.sendImageResume();
                if (sentImageResume) {
                    StorageManager.addRecordWithLimit(
                        CONFIG.STORAGE_KEYS.SENT_IMAGE_RESUME_HRS,
                        hrKey,
                        state.hrInteractions.sentImageResumeHRs,
                        CONFIG.STORAGE_LIMITS.SENT_IMAGE_RESUME_HRS
                    );
                }
            }
        }

        /**
         * 处理HR回复后的逻辑
         * 根据HR的回复内容执行相应的后续操作
         * @param {string} hrKey - HR标识
         * @returns {Promise<void>}
         */
        static async _handleFollowUpResponse(hrKey) {
            const lastMessage = await Core.getLastFriendMessageText();

            if (lastMessage && (lastMessage.includes('简历') || lastMessage.includes('发送简历'))) {
                Core.log(`HR提到"简历",发送简历: ${hrKey}`);

                // 优先发送图片简历
                if (state.settings.useAutoSendImageResume && !state.hrInteractions.sentImageResumeHRs.has(hrKey)) {
                    const sentImageResume = await this.sendImageResume();
                    if (sentImageResume) {
                        state.hrInteractions.sentImageResumeHRs.add(hrKey);
                        StatePersistence.saveState();
                        Core.log(`已向 ${hrKey} 发送图片简历`);
                        return;
                    }
                }

                // 发送普通简历
                if (!state.hrInteractions.sentResumeHRs.has(hrKey)) {
                    const sentResume = await this.sendResume();
                    if (sentResume) {
                        state.hrInteractions.sentResumeHRs.add(hrKey);
                        StatePersistence.saveState();
                        Core.log(`已向 ${hrKey} 发送简历`);
                    }
                }
            }
        }

        /**
         * 检查HR是否已回复消息
         */
        static async hasHRResponded() {
            await Core.delay(state.settings.actionDelays.click);

            const chatContainer = document.querySelector('.chat-message .im-list');
            if (!chatContainer) return false;

            const friendMessages = Array.from(chatContainer.querySelectorAll('li.message-item.item-friend'));
            return friendMessages.length > 0;
        }

        /**
         * 发送常用语
         */
        static async sendGreetings() {
            try {
                const dictBtn = await Core.waitForElement('.btn-dict');
                if (!dictBtn) {
                    Core.log('未找到常用语(自我介绍)按钮');
                    return false;
                }
                await Core.simulateClick(dictBtn);
                await Core.smartDelay(state.settings.actionDelays.click, 'click');
                await Core.smartDelay(300, 'dict_load'); // 确保常用语列表加载完成

                const dictList = await Core.waitForElement('ul[data-v-1d93a2d5=""]');
                if (!dictList) {
                    Core.log('未找到常用语(自我介绍)');
                    return false;
                }

                const dictItems = dictList.querySelectorAll('li');
                if (!dictItems || dictItems.length === 0) {
                    Core.log('常用语列表(自我介绍)为空');
                    return false;
                }

                for (let i = 0; i < dictItems.length; i++) {
                    const item = dictItems[i];
                    Core.log(`发送常用语(自我介绍):第${i + 1}条/共${dictItems.length}条`);
                    await Core.simulateClick(item);
                    await Core.delay(state.settings.actionDelays.click);
                }

                return true;
            } catch (error) {
                Core.log(`发送常用语出错: ${error.message}`);
                return false;
            }
        }

        /**
         * 发送简历
         */

        /**
         * 根据双字关键词查找匹配的简历
         * @param {Array} resumeItems - 简历项数组
         * @param {string} positionName - 岗位名称
         * @returns {HTMLElement|null} 匹配的简历项或null
         */
        static _findMatchingResume(resumeItems, positionName) {
            try {
                const positionNameLower = positionName.toLowerCase();
                const twoCharKeywords = Core.extractTwoCharKeywords(positionNameLower);

                for (const keyword of twoCharKeywords) {
                    for (const item of resumeItems) {
                        const resumeNameElement = item.querySelector('.resume-name');
                        if (!resumeNameElement) continue;

                        const resumeName = resumeNameElement.textContent.trim().toLowerCase();

                        if (resumeName.includes(keyword)) {
                            const resumeNameText = resumeNameElement.textContent.trim();
                            Core.log(`智能匹配简历: "${resumeNameText}" 匹配依据: "${keyword}"`);
                            return item;
                        }
                    }
                }

                return null;
            } catch (error) {
                Core.log(`简历匹配出错: ${error.message}`);
                return null;
            }
        }

        static async sendResume() {
            try {
                const resumeBtn = await Core.waitForElement(() => {
                    return [...document.querySelectorAll('.toolbar-btn')].find(
                        el => el.textContent.trim() === '发简历'
                    );
                });

                if (!resumeBtn) {
                    Core.log('无法发送简历,未找到发简历按钮');
                    return false;
                }

                if (resumeBtn.classList.contains('unable')) {
                    Core.log('对方未回复,您无权发送简历');
                    return false;
                }

                // 获取当前岗位名称
                let positionName = '';
                try {
                    const positionNameElement = Core.getCachedElement('.position-name', true) ||
                        Core.getCachedElement('.job-name', true) ||
                        Core.getCachedElement('[class*="position-content"] .left-content .position-name', true);

                    if (positionNameElement) {
                        positionName = positionNameElement.textContent.trim();
                    } else {
                        Core.log('未找到岗位名称元素');
                    }
                } catch (e) {
                    Core.log(`获取岗位名称出错: ${e.message}`);
                }

                await Core.simulateClick(resumeBtn);
                await Core.smartDelay(state.settings.actionDelays.click, 'click');
                await Core.smartDelay(800, 'resume_load'); // 确保简历列表或确认框加载完成

                // 检查是否出现了确认对话框(用户只有一份附件简历的情况)
                const confirmDialog = document.querySelector('.panel-resume.sentence-popover');
                if (confirmDialog) {
                    Core.log('您只有一份附件简历');

                    // 直接点击确定按钮
                    const confirmBtn = confirmDialog.querySelector('.btn-sure-v2');
                    if (!confirmBtn) {
                        Core.log('未找到确认按钮');
                        return false;
                    }

                    await Core.simulateClick(confirmBtn);
                    return true;
                }

                // 多份简历的情况,使用原有的简历选择逻辑
                const resumeList = await Core.waitForElement('ul.resume-list');
                if (!resumeList) {
                    Core.log('未找到简历列表');
                    return false;
                }

                const resumeItems = Array.from(resumeList.querySelectorAll('li.list-item'));
                if (resumeItems.length === 0) {
                    Core.log('未找到简历列表项');
                    return false;
                }

                let selectedResumeItem = null;
                if (positionName) {
                    selectedResumeItem = this._findMatchingResume(resumeItems, positionName);
                }

                if (!selectedResumeItem) {
                    selectedResumeItem = resumeItems[0];
                    const resumeName = selectedResumeItem.querySelector('.resume-name').textContent.trim();
                    Core.log('使用第一个简历: "' + resumeName + '"');
                }

                await Core.simulateClick(selectedResumeItem);
                await Core.smartDelay(state.settings.actionDelays.click, 'click');
                await Core.smartDelay(500, 'selection'); // 确保选择生效

                const sendBtn = await Core.waitForElement('button.btn-v2.btn-sure-v2.btn-confirm');
                if (!sendBtn) {
                    Core.log('未找到发送按钮');
                    return false;
                }

                if (sendBtn.disabled) {
                    Core.log('发送按钮不可用,可能简历未正确选择');
                    return false;
                }

                await Core.simulateClick(sendBtn);
                return true;
            } catch (error) {
                Core.log(`发送简历出错: ${error.message}`);
                return false;
            }
        }

        // 选择匹配的图片简历
        static selectImageResume(positionName) {
            try {
                const positionNameLower = positionName.toLowerCase();

                // 如果只有一个简历,直接返回
                if (state.settings.imageResumes.length === 1) {
                    return state.settings.imageResumes[0];
                }

                // 提取双字关键词
                const twoCharKeywords = Core.extractTwoCharKeywords(positionNameLower);

                // 按关键词优先级(从左到右)遍历
                for (const keyword of twoCharKeywords) {
                    // 查找包含当前关键词的简历
                    for (const resume of state.settings.imageResumes) {
                        const resumeNameLower = resume.path.toLowerCase();

                        // 检查简历名称是否包含当前关键词
                        if (resumeNameLower.includes(keyword)) {
                            Core.log(`智能匹配简历: "${resume.path}" 匹配依据: "${keyword}"`);
                            return resume;
                        }
                    }
                }

                // 未找到匹配,返回第一个简历
                return state.settings.imageResumes[0];
            } catch (error) {
                Core.log(`选择图片简历出错: ${error.message}`);
                return state.settings.imageResumes[0] || null;
            }
        }

        /**
         * Send image resume
         */
        static async sendImageResume() {
            try {
                if (!state.settings.useAutoSendImageResume || !state.settings.imageResumes || state.settings.imageResumes.length === 0) {
                    return false;
                }

                // 获取当前聊天的岗位名称
                let positionName = '';
                try {
                    // 尝试从职位卡片获取岗位名称
                    const positionNameElement = Core.getCachedElement('.position-name', true) ||
                        Core.getCachedElement('.job-name', true) ||
                        Core.getCachedElement('[class*="position-content"] .left-content .position-name', true);

                    if (positionNameElement) {
                        positionName = positionNameElement.textContent.trim();
                    } else {
                        Core.log('未找到岗位名称元素');
                        // 如果无法获取岗位名称,仍然继续发送,使用默认简历
                        positionName = '';
                    }
                } catch (e) {
                    Core.log(`获取岗位名称出错: ${e.message}`);
                    // 出错时仍然继续发送,使用默认简历
                    positionName = '';
                }

                // 使用selectImageResume方法选择合适的图片简历
                const selectedResume = this.selectImageResume(positionName);

                // 检查是否有待发送的图片简历数据
                if (!selectedResume || !selectedResume.data) {
                    Core.log('没有可发送的图片简历数据');
                    return false;
                }

                // 找到图片发送按钮
                const imageSendBtn = await Core.waitForElement('.toolbar-btn-content.icon.btn-sendimg input[type="file"]');
                if (!imageSendBtn) {
                    Core.log('未找到图片发送按钮');
                    return false;
                }

                // 创建一个Blob对象
                const byteCharacters = atob(selectedResume.data.split(',')[1]);
                const byteNumbers = new Array(byteCharacters.length);
                for (let i = 0; i < byteCharacters.length; i++) {
                    byteNumbers[i] = byteCharacters.charCodeAt(i);
                }
                const byteArray = new Uint8Array(byteNumbers);
                const blob = new Blob([byteArray], { type: 'image/jpeg' });

                // 创建一个File对象
                const file = new File([blob], selectedResume.path, {
                    type: 'image/jpeg',
                    lastModified: new Date().getTime()
                });

                // 创建一个DataTransfer对象来模拟文件选择
                const dataTransfer = new DataTransfer();
                dataTransfer.items.add(file);

                // 设置文件输入的值
                imageSendBtn.files = dataTransfer.files;

                // 触发change事件
                const event = new Event('change', { bubbles: true });
                imageSendBtn.dispatchEvent(event);
                Core.log(`成功发送图片: ${selectedResume.path}`);
                return true;
            } catch (error) {
                Core.log(`发送图片出错: ${error.message}`);
                return false;
            }
        }
    };

    // StatePersistence.loadState() 会在init函数中调用

    const UI = {
        // 页面类型常量
        PAGE_TYPES: {
            JOB_LIST: 'jobList',
            CHAT: 'chat'
        },

        currentPageType: null,

        init() {
            this.currentPageType = location.pathname.includes('/chat')
                ? this.PAGE_TYPES.CHAT
                : this.PAGE_TYPES.JOB_LIST;
            this._applyTheme();
            this.createControlPanel();
            this.createMiniIcon();
        },

        createControlPanel() {
            if (document.getElementById('boss-pro-panel')) {
                document.getElementById('boss-pro-panel').remove();
            }

            elements.panel = this._createPanel();

            const header = this._createHeader();
            const controls = this._createPageControls();
            elements.log = this._createLogger();
            const footer = this._createFooter();

            elements.panel.append(header, controls, elements.log, footer);
            document.body.appendChild(elements.panel);
            this._makeDraggable(elements.panel);
        },

        _applyTheme() {
            CONFIG.COLORS = this.currentPageType === this.PAGE_TYPES.JOB_LIST
                ? this.THEMES.JOB_LIST
                : this.THEMES.CHAT;

            // 设置CSS变量
            document.documentElement.style.setProperty('--primary-color', CONFIG.COLORS.primary);
            document.documentElement.style.setProperty('--secondary-color', CONFIG.COLORS.secondary);
            document.documentElement.style.setProperty('--accent-color', CONFIG.COLORS.accent);
            document.documentElement.style.setProperty('--neutral-color', CONFIG.COLORS.neutral);
        },

        THEMES: {
            JOB_LIST: {
                primary: '#4285f4',
                secondary: '#f5f7fa',
                accent: '#e8f0fe',
                neutral: '#6b7280'
            },
            CHAT: {
                primary: '#34a853',
                secondary: '#f0fdf4',
                accent: '#dcfce7',
                neutral: '#6b7280'
            }
        },

        _createPanel() {
            const panel = document.createElement('div');
            panel.id = 'boss-pro-panel';
            panel.className = this.currentPageType === this.PAGE_TYPES.JOB_LIST
                ? 'boss-joblist-panel'
                : 'boss-chat-panel';

            // 基础样式
            const baseStyles = `
            position: fixed;
            top: 36px;
            right: 24px;
            width: clamp(300px, 80vw, 400px);
            border-radius: 16px;
            padding: 18px;
            font-family: 'Segoe UI', system-ui, sans-serif;
            z-index: 2147483647;
            display: flex;
            flex-direction: column;
            transition: all 0.3s ease;
            background: #ffffff;
            box-shadow: 0 10px 25px rgba(var(--primary-rgb), 0.15);
            border: 1px solid var(--accent-color);
            cursor: default;
        `;

            panel.style.cssText = baseStyles;

            // 设置RGB颜色变量
            const rgbColor = this._hexToRgb(CONFIG.COLORS.primary);
            document.documentElement.style.setProperty('--primary-rgb', rgbColor);

            return panel;
        },

        _createHeader() {
            const header = document.createElement('div');
            header.className = this.currentPageType === this.PAGE_TYPES.JOB_LIST
                ? 'boss-header'
                : 'boss-chat-header';

            header.style.cssText = `
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 0 10px 15px;
            margin-bottom: 15px;
            border-bottom: 1px solid var(--accent-color);
        `;

            const title = this._createTitle();

            // 创建按钮容器
            const buttonContainer = document.createElement('div');
            buttonContainer.style.cssText = `
            display: flex;
            gap: 8px;
        `;

            // 按钮标题
            const buttonTitles = this.currentPageType === this.PAGE_TYPES.JOB_LIST
                ? { clear: '清空日志', settings: '插件设置', close: '最小化海投面板' }
                : { clear: '清空聊天记录', settings: 'AI人设设置', close: '最小化聊天面板' };

            // 添加清空日志按钮
            const clearLogBtn = this._createIconButton('🗑', () => {
                elements.log.innerHTML = `<div style="color:var(--neutral-color); margin-bottom:8px;">欢迎使用海投助手,愿您在求职路上一帆风顺!</div>`;
            }, buttonTitles.clear);

            // 添加设置按钮
            const settingsBtn = this._createIconButton('⚙', () => {
                showSettingsDialog();
            }, buttonTitles.settings);

            // 添加最小化按钮
            const closeBtn = this._createIconButton('✕', () => {
                state.isMinimized = true;
                elements.panel.style.transform = 'translateY(160%)';
                elements.miniIcon.style.display = 'flex';
            }, buttonTitles.close);

            buttonContainer.append(clearLogBtn, settingsBtn, closeBtn);
            header.append(title, buttonContainer);
            return header;
        },

        _createTitle() {
            const title = document.createElement('div');
            title.style.display = 'flex';
            title.style.alignItems = 'center';
            title.style.gap = '10px';

            // SVG图标
            const customSvg = `
        <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" 
             style="width: 100%; height: 100%; fill: white;">
            <path d="M512 116.032a160 160 0 0 1 52.224 311.232v259.008c118.144-22.272 207.552-121.088 207.552-239.36 0-25.152 21.568-45.568 48.128-45.568 26.624 0 48.128 20.416 48.128 45.632 0 184.832-158.848 335.232-354.048 335.232S160 631.808 160 446.976c0-25.152 21.568-45.632 48.128-45.632 26.624 0 48.128 20.48 48.128 45.632 0 118.144 89.088 216.96 206.976 239.296V428.416A160.064 160.064 0 0 1 512 116.032z m0 96a64 64 0 1 0 0 128 64 64 0 0 0 0-128z m-36.672 668.48l-21.888-19.584a17.92 17.92 0 0 0-24.64 0l-21.952 19.584a56.32 56.32 0 0 1-77.504 0l-21.952-19.584a17.92 17.92 0 0 0-24.64 0l-28.288 25.6c-9.6 8.704-23.36 6.4-30.72-4.992a29.696 29.696 0 0 1 4.16-36.672l28.352-25.6a56.32 56.32 0 0 1 77.568 0l21.888 19.584a17.92 17.92 0 0 0 24.704 0l21.824-19.52a56.32 56.32 0 0 1 77.568 0l21.888 19.52a17.92 17.92 0 0 0 24.64 0l21.952-19.52a56.32 56.32 0 0 1 77.504 0l21.952 19.52a17.92 17.92 0 0 0 24.64 0l21.824-19.52a56.32 56.32 0 0 1 77.632 0l21.824 19.52c9.664 8.704 11.52 25.152 4.224 36.672-7.296 11.52-21.12 13.696-30.72 4.992l-21.888-19.584a17.92 17.92 0 0 0-24.64 0l-21.888 19.584a56.32 56.32 0 0 1-77.568 0l-21.888-19.584a17.92 17.92 0 0 0-24.64 0l-21.888 19.584a57.408 57.408 0 0 1-38.656 15.488 58.176 58.176 0 0 1-38.784-15.488z" />
        </svg>
    `;

            // 标题配置
            const titleConfig = this.currentPageType === this.PAGE_TYPES.JOB_LIST
                ? { main: `<span style="color:var(--primary-color);">BOSS</span>海投助手`, sub: '高效求职 · 智能匹配' }
                : { main: `<span style="color:var(--primary-color);">BOSS</span>智能聊天`, sub: '智能对话 · 高效沟通' };

            title.innerHTML = `
        <div style="
            width: 40px;
            height: 40px;
            background: var(--primary-color);
            border-radius: 10px;
            display: flex;
            justify-content: center;
            align-items: center;
            color: white;
            font-weight: bold;
            box-shadow: 0 2px 8px rgba(var(--primary-rgb), 0.3);
        ">
            ${customSvg}
        </div>
        <div>
            <h3 style="
                margin: 0;
                color: #2c3e50;
                font-weight: 600;
                font-size: 1.2rem;
            ">
                ${titleConfig.main}
            </h3>
            <span style="
                font-size:0.8em;
                color:var(--neutral-color);
            ">
                ${titleConfig.sub}
            </span>
        </div>
    `;

            return title;
        },

        // 创建页面控制区域
        _createPageControls() {
            if (this.currentPageType === this.PAGE_TYPES.JOB_LIST) {
                return this._createJobListControls();
            } else {
                return this._createChatControls();
            }
        },

        // 创建职位列表页面控制区域
        _createJobListControls() {
            const container = document.createElement('div');
            container.className = 'boss-joblist-controls';
            container.style.marginBottom = '15px';
            container.style.padding = '0 10px';

            // 筛选条件区域
            const filterContainer = this._createFilterContainer();

            elements.controlBtn = this._createTextButton(
                '启动海投',
                'var(--primary-color)',
                () => {
                    toggleProcess();
                }
            );

            // 居中控制按钮
            const btnContainer = document.createElement('div');
            btnContainer.style.cssText = `
            display: flex;
            justify-content: center;
            width: 100%;
        `;
            btnContainer.appendChild(elements.controlBtn);

            container.append(filterContainer, btnContainer);
            return container;
        },

        // 创建聊天页面控制区域
        _createChatControls() {
            const container = document.createElement('div');
            container.className = 'boss-chat-controls';
            container.style.marginBottom = '15px';
            container.style.padding = '0 10px';

            // 人设和模板选择
            const configRow = document.createElement('div');
            configRow.style.cssText = `
            display: flex;
            gap: 10px;
            margin-bottom: 15px;
        `;

            // 动态获取AI人设选项,包括默认选项和用户自定义选项
            const getPersonaOptions = () => {
                // 默认角色选项
                const defaultOptions = [
                    { value: 'default', text: '默认' },
                    { value: 'tech', text: 'Ai人设1' },
                    { value: 'product', text: 'Ai人设2' },
                    { value: 'marketing', text: 'Ai人设3' }
                ];

                // 获取用户自定义角色
                const customPersonas = settings.customPersonas || [];

                // 合并默认选项和自定义选项
                return [...defaultOptions, ...customPersonas];
            };

            const personaCol = this._createSelectControl('AI人设:', 'ai-persona-selector', getPersonaOptions());

            const templateCol = this._createSelectControl('回复模板:', 'reply-template-selector', [
                { value: 'standard', text: '标准' },
                { value: 'brief', text: '简洁' },
                { value: 'detailed', text: '详细' }
            ]);

            elements.personaSelector = personaCol.querySelector('select');
            configRow.append(personaCol, templateCol);

            elements.controlBtn = this._createTextButton(
                '开始智能聊天',
                'var(--primary-color)',
                () => {
                    toggleChatProcess();
                }
            );

            // 居中控制按钮
            const btnContainer = document.createElement('div');
            btnContainer.style.cssText = `
            display: flex;
            justify-content: center;
            width: 100%;
        `;
            btnContainer.appendChild(elements.controlBtn);

            container.append(configRow, btnContainer);
            return container;
        },

        // 创建筛选容器
        _createFilterContainer() {
            const filterContainer = document.createElement('div');
            filterContainer.style.cssText = `
            background: var(--secondary-color);
            border-radius: 12px;
            padding: 15px;
            margin-bottom: 15px;
        `;

            // 岗位和地点筛选使用两列布局
            const filterRow = document.createElement('div');
            filterRow.style.cssText = `
            display: flex;
            gap: 10px;
            margin-bottom: 12px;
        `;

            // 职位名包含 和 工作地包含
            const includeFilterCol = this._createInputControl('职位名包含:', 'include-filter', '如:前端,开发');
            const locationFilterCol = this._createInputControl('工作地包含:', 'location-filter', '如:杭州,滨江');

            elements.includeInput = includeFilterCol.querySelector('input');
            elements.locationInput = locationFilterCol.querySelector('input');

            filterRow.append(includeFilterCol, locationFilterCol);

            // 加海投服务QQ群按钮
            const joinGroupBtn = document.createElement('button');
            joinGroupBtn.className = 'boss-advanced-filter-btn';
            joinGroupBtn.innerHTML = '<i class="fa fa-sliders"></i> 海投服务群';
            joinGroupBtn.style.cssText = `
            width: 100%;
            padding: 8px 10px;
            background: white;
            color: var(--primary-color);
            border: 1px solid var(--primary-color);
            border-radius: 8px;
            cursor: pointer;
            font-size: 14px;
            text-align: center;
            transition: all 0.2s ease;
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 5px;
        `;

            joinGroupBtn.addEventListener('click', () => {
                window.open('https://qm.qq.com/q/ZNOz2ZZb6S', '_blank');
            });

            joinGroupBtn.addEventListener('mouseenter', () => {
                joinGroupBtn.style.backgroundColor = 'var(--primary-color)';
                joinGroupBtn.style.color = 'white';
            });

            joinGroupBtn.addEventListener('mouseleave', () => {
                joinGroupBtn.style.backgroundColor = 'white';
                joinGroupBtn.style.color = 'var(--primary-color)';
            });

            filterContainer.append(filterRow, joinGroupBtn);
            return filterContainer;
        },

        // 创建输入控件
        _createInputControl(labelText, id, placeholder) {
            const controlCol = document.createElement('div');
            controlCol.style.cssText = 'flex: 1;';

            const label = document.createElement('label');
            label.textContent = labelText;
            label.style.cssText = 'display:block; margin-bottom:5px; font-weight: 500; color: #333; font-size: 0.9rem;';

            const input = document.createElement('input');
            input.id = id;
            input.placeholder = placeholder;
            input.className = 'boss-filter-input';
            input.style.cssText = `
            width: 100%;
            padding: 8px 10px;
            border-radius: 8px;
            border: 1px solid #d1d5db;
            font-size: 14px;
            box-shadow: 0 1px 2px rgba(0,0,0,0.05);
            transition: all 0.2s ease;
        `;

            controlCol.append(label, input);
            return controlCol;
        },

        // 创建选择控件
        _createSelectControl(labelText, id, options) {
            const controlCol = document.createElement('div');
            controlCol.style.cssText = 'flex: 1;';

            const label = document.createElement('label');
            label.textContent = labelText;
            label.style.cssText = 'display:block; margin-bottom:5px; font-weight: 500; color: #333; font-size: 0.9rem;';

            const select = document.createElement('select');
            select.id = id;
            select.style.cssText = `
            width: 100%;
            padding: 8px 10px;
            border-radius: 8px;
            border: 1px solid #d1d5db;
            font-size: 14px;
            background: white;
            color: #333;
            box-shadow: 0 1px 2px rgba(0,0,0,0.05);
            transition: all 0.2s ease;
        `;

            // 添加选项
            options.forEach(option => {
                const opt = document.createElement('option');
                opt.value = option.value;
                opt.textContent = option.text;
                select.appendChild(opt);
            });

            controlCol.append(label, select);
            return controlCol;
        },

        // 日志区域
        _createLogger() {
            const log = document.createElement('div');
            log.id = 'pro-log';
            log.className = this.currentPageType === this.PAGE_TYPES.JOB_LIST
                ? 'boss-joblist-log'
                : 'boss-chat-log';

            const height = this.currentPageType === this.PAGE_TYPES.JOB_LIST ? '180px' : '220px';

            log.style.cssText = `
            height: ${height};
            overflow-y: auto;
            background: var(--secondary-color);
            border-radius: 12px;
            padding: 12px;
            font-size: 13px;
            line-height: 1.5;
            margin-bottom: 15px;
            margin-left: 10px;
            margin-right: 10px;
            transition: all 0.3s ease;
            user-select: text;
            scrollbar-width: thin;
            scrollbar-color: var(--primary-color) var(--secondary-color);
        `;

            // 自定义滚动条样式
            log.innerHTML += `
            <style>
                #pro-log::-webkit-scrollbar {
                    width: 6px;
                }
                #pro-log::-webkit-scrollbar-track {
                    background: var(--secondary-color);
                    border-radius: 4px;
                }
                #pro-log::-webkit-scrollbar-thumb {
                    background-color: var(--primary-color);
                    border-radius: 4px;
                }
            </style>
        `;

            return log;
        },

        // 面板页脚
        _createFooter() {
            const footer = document.createElement('div');
            footer.className = this.currentPageType === this.PAGE_TYPES.JOB_LIST
                ? 'boss-joblist-footer'
                : 'boss-chat-footer';

            footer.style.cssText = `
            text-align: center;
            font-size: 0.8em;
            color: var(--neutral-color);
            padding-top: 15px;
            border-top: 1px solid var(--accent-color);
            margin-top: auto;
            padding: 15px;
        `;

            const statsContainer = document.createElement('div');
            statsContainer.style.cssText = `
            display: flex;
            justify-content: space-around;
            margin-bottom: 15px;
        `;

            footer.append(statsContainer, document.createTextNode('© 2025 Yangshengzhou · All Rights Reserved'));
            return footer;
        },

        // 文本按钮
        _createTextButton(text, bgColor, onClick) {
            const btn = document.createElement('button');
            btn.className = 'boss-btn';
            btn.textContent = text;
            btn.style.cssText = `
            width: 100%;
            max-width: 320px;
            padding: 10px 16px;
            background: ${bgColor};
            color: #fff;
            border: none;
            border-radius: 10px;
            cursor: pointer;
            font-size: 15px;
            font-weight: 500;
            transition: all 0.3s ease;
            display: flex;
            justify-content: center;
            align-items: center;
            box-shadow: 0 4px 10px rgba(0,0,0,0.1);
        `;

            this._addButtonHoverEffects(btn);
            btn.addEventListener('click', onClick);

            return btn;
        },

        // 图标按钮
        _createIconButton(icon, onClick, title) {
            const btn = document.createElement('button');
            btn.className = 'boss-icon-btn';
            btn.innerHTML = icon;
            btn.title = title;
            btn.style.cssText = `
            width: 32px;
            height: 32px;
            border-radius: 50%;
            border: none;
            background: ${this.currentPageType === this.PAGE_TYPES.JOB_LIST ? 'var(--accent-color)' : 'var(--accent-color)'};
            cursor: pointer;
            font-size: 16px;
            transition: all 0.2s ease;
            display: flex;
            justify-content: center;
            align-items: center;
            color: var(--primary-color);
        `;

            btn.addEventListener('click', onClick);
            btn.addEventListener('mouseenter', () => {
                btn.style.backgroundColor = 'var(--primary-color)';
                btn.style.color = '#fff';
                btn.style.transform = 'scale(1.1)';
            });

            btn.addEventListener('mouseleave', () => {
                btn.style.backgroundColor = this.currentPageType === this.PAGE_TYPES.JOB_LIST ? 'var(--accent-color)' : 'var(--accent-color)';
                btn.style.color = 'var(--primary-color)';
                btn.style.transform = 'scale(1)';
            });

            return btn;
        },

        // 添加按钮悬停效果
        _addButtonHoverEffects(btn) {
            btn.addEventListener('mouseenter', () => {
                btn.style.transform = 'translateY(-2px)';
                btn.style.boxShadow = `0 6px 15px rgba(var(--primary-rgb), 0.3)`;
            });

            btn.addEventListener('mouseleave', () => {
                btn.style.transform = 'translateY(0)';
                btn.style.boxShadow = '0 4px 10px rgba(0,0,0,0.1)';
            });
        },

        // 设置面板可拖动功能
        _makeDraggable(panel) {
            const header = panel.querySelector('.boss-header, .boss-chat-header');

            if (!header) return;

            header.style.cursor = 'move';

            let isDragging = false;
            let startX = 0, startY = 0;
            let initialX = panel.offsetLeft, initialY = panel.offsetTop;

            header.addEventListener('mousedown', (e) => {
                isDragging = true;
                startX = e.clientX;
                startY = e.clientY;
                initialX = panel.offsetLeft;
                initialY = panel.offsetTop;
                panel.style.transition = 'none';
                panel.style.zIndex = '2147483647';
            });

            document.addEventListener('mousemove', (e) => {
                if (!isDragging) return;

                const dx = e.clientX - startX;
                const dy = e.clientY - startY;

                panel.style.left = `${initialX + dx}px`;
                panel.style.top = `${initialY + dy}px`;
                panel.style.right = 'auto';
            });

            document.addEventListener('mouseup', () => {
                if (isDragging) {
                    isDragging = false;
                    panel.style.transition = 'all 0.3s ease';
                    panel.style.zIndex = '2147483646';
                }
            });
        },

        // 最小化图标
        createMiniIcon() {
            elements.miniIcon = document.createElement('div');
            elements.miniIcon.style.cssText = `
        width: ${CONFIG.MINI_ICON_SIZE || 48}px;
        height: ${CONFIG.MINI_ICON_SIZE || 48}px;
        position: fixed;
        bottom: 40px;
        left: 40px;
        background: var(--primary-color);
        border-radius: 50%;
        box-shadow: 0 6px 16px rgba(var(--primary-rgb), 0.4);
        cursor: pointer;
        display: none;
        justify-content: center;
        align-items: center;
        color: #fff;
        z-index: 2147483647;
        transition: all 0.3s ease;
        overflow: hidden;
        padding: 8px; /* 添加内边距 */
    `;

            // SVG图标
            const customSvg = `
        <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" 
             style="width: 100%; height: 100%; fill: white;">
            <path d="M512 116.032a160 160 0 0 1 52.224 311.232v259.008c118.144-22.272 207.552-121.088 207.552-239.36 0-25.152 21.568-45.568 48.128-45.568 26.624 0 48.128 20.416 48.128 45.632 0 184.832-158.848 335.232-354.048 335.232S160 631.808 160 446.976c0-25.152 21.568-45.632 48.128-45.632 26.624 0 48.128 20.48 48.128 45.632 0 118.144 89.088 216.96 206.976 239.296V428.416A160.064 160.064 0 0 1 512 116.032z m0 96a64 64 0 1 0 0 128 64 64 0 0 0 0-128z m-36.672 668.48l-21.888-19.584a17.92 17.92 0 0 0-24.64 0l-21.952 19.584a56.32 56.32 0 0 1-77.504 0l-21.952-19.584a17.92 17.92 0 0 0-24.64 0l-28.288 25.6c-9.6 8.704-23.36 6.4-30.72-4.992a29.696 29.696 0 0 1 4.16-36.672l28.352-25.6a56.32 56.32 0 0 1 77.568 0l21.888 19.584a17.92 17.92 0 0 0 24.704 0l21.824-19.52a56.32 56.32 0 0 1 77.568 0l21.888 19.52a17.92 17.92 0 0 0 24.64 0l21.952-19.52a56.32 56.32 0 0 1 77.504 0l21.952 19.52a17.92 17.92 0 0 0 24.64 0l21.824-19.52a56.32 56.32 0 0 1 77.632 0l21.824 19.52c9.664 8.704 11.52 25.152 4.224 36.672-7.296 11.52-21.12 13.696-30.72 4.992l-21.888-19.584a17.92 17.92 0 0 0-24.64 0l-21.888 19.584a56.32 56.32 0 0 1-77.568 0l-21.888-19.584a17.92 17.92 0 0 0-24.64 0l-21.888 19.584a57.408 57.408 0 0 1-38.656 15.488 58.176 58.176 0 0 1-38.784-15.488z" />
        </svg>
    `;

            elements.miniIcon.innerHTML = customSvg;

            // 添加悬停效果
            elements.miniIcon.addEventListener('mouseenter', () => {
                elements.miniIcon.style.transform = 'scale(1.1)';
                elements.miniIcon.style.boxShadow = `0 8px 20px rgba(var(--primary-rgb), 0.5)`;
            });

            elements.miniIcon.addEventListener('mouseleave', () => {
                elements.miniIcon.style.transform = 'scale(1)';
                elements.miniIcon.style.boxShadow = `0 6px 16px rgba(var(--primary-rgb), 0.4)`;
            });

            // 添加点击事件
            elements.miniIcon.addEventListener('click', () => {
                state.isMinimized = false;
                elements.panel.style.transform = 'translateY(0)';
                elements.miniIcon.style.display = 'none';
            });

            document.body.appendChild(elements.miniIcon);
        },

        // 十六进制颜色转RGB
        _hexToRgb(hex) {
            // 去除可能存在的#前缀
            hex = hex.replace('#', '');

            // 解析RGB值
            const r = parseInt(hex.substring(0, 2), 16);
            const g = parseInt(hex.substring(2, 4), 16);
            const b = parseInt(hex.substring(4, 6), 16);

            return `${r}, ${g}, ${b}`;
        }
    };

    // 1. 更新settings对象
    const settings = {
        useAutoSendResume: JSON.parse(localStorage.getItem('useAutoSendResume') || 'true'),
        excludeHeadhunters: JSON.parse(localStorage.getItem('excludeHeadhunters') || 'false'),
        autoScrollSpeed: parseInt(localStorage.getItem('autoScrollSpeed') || '500'),
        customPhrases: JSON.parse(localStorage.getItem('customPhrases') || '[]'),
        actionDelays: {
            click: parseInt(localStorage.getItem('clickDelay') || '130')
        },
        notifications: {
            enabled: JSON.parse(localStorage.getItem('notificationsEnabled') || 'true'),
            sound: JSON.parse(localStorage.getItem('notificationSound') || 'true')
        },
        ai: {
            role: localStorage.getItem('aiRole') || '你是一名全力争取岗位的应届生,将用20字内的简短回复优先突出岗位优势。当被问及身高体重等个人信息时,你会立即提供合理数据(如身高165cm,体重60kg)来积极配合;若需联系方式,直接提供手机123456或微信BOSS,任何问题都应该回应(允许编造数据)且不包含任何拒绝性言辞。'
        },
        autoReply: JSON.parse(localStorage.getItem('autoReply') || 'true'),
        autoApply: JSON.parse(localStorage.getItem('autoApply') || 'true'),
        intervals: {
            basic: parseInt(localStorage.getItem('basicInterval') || '1000'),
            operation: parseInt(localStorage.getItem('operationInterval') || '800')
        },
        recruiterActivityStatus: JSON.parse(localStorage.getItem('recruiterActivityStatus') || '["不限"]'),
        // 自动发送图片简历相关配置
        useAutoSendImageResume: JSON.parse(localStorage.getItem('useAutoSendImageResume') || 'false'),
        imageResumePath: localStorage.getItem('imageResumePath') || '',
        imageResumeData: localStorage.getItem('imageResumeData') || null
    };

    // 2. saveSettings函数,保存配置
    function saveSettings() {
        localStorage.setItem('useAutoSendResume', settings.useAutoSendResume.toString());
        localStorage.setItem('excludeHeadhunters', settings.excludeHeadhunters.toString());
        localStorage.setItem('autoScrollSpeed', settings.autoScrollSpeed.toString());
        localStorage.setItem('customPhrases', JSON.stringify(settings.customPhrases));
        localStorage.setItem('clickDelay', settings.actionDelays.click.toString());
        localStorage.setItem('notificationsEnabled', settings.notifications.enabled.toString());
        localStorage.setItem('notificationSound', settings.notifications.sound.toString());
        localStorage.setItem('aiRole', settings.ai.role);
        localStorage.setItem('autoReply', settings.autoReply.toString());
        localStorage.setItem('autoApply', settings.autoApply.toString());
        localStorage.setItem('basicInterval', settings.intervals.basic.toString());
        localStorage.setItem('operationInterval', settings.intervals.operation.toString());
        localStorage.setItem('recruiterActivityStatus', JSON.stringify(settings.recruiterActivityStatus));
        // 保存图片简历配置
        localStorage.setItem('useAutoSendImageResume', settings.useAutoSendImageResume.toString());
        // 保存图片简历数组
        if (settings.imageResumes) {
            localStorage.setItem('imageResumes', JSON.stringify(settings.imageResumes));
        }
        // 存储图片数据
        if (settings.imageResumeData) {
            localStorage.setItem('imageResumeData', settings.imageResumeData);
        } else {
            localStorage.removeItem('imageResumeData');
        }
    }

    // 3. loadSettings函数加载配置
    function loadSettings() {
        settings.useAutoSendResume = JSON.parse(localStorage.getItem('useAutoSendResume') || 'true');
        settings.excludeHeadhunters = JSON.parse(localStorage.getItem('excludeHeadhunters') || 'false');
        settings.autoScrollSpeed = parseInt(localStorage.getItem('autoScrollSpeed') || '500');
        settings.customPhrases = JSON.parse(localStorage.getItem('customPhrases') || '[]');
        settings.actionDelays.click = parseInt(localStorage.getItem('clickDelay') || '130');
        settings.notifications.enabled = JSON.parse(localStorage.getItem('notificationsEnabled') || 'true');
        settings.notifications.sound = JSON.parse(localStorage.getItem('notificationSound') || 'true');
        settings.ai.role = localStorage.getItem('aiRole') || '你是一名全力争取岗位的应届生,将用20字内的简短回复优先突出岗位优势。当被问及身高体重等个人信息时,你会立即提供合理数据(如身高165cm,体重60kg)来积极配合;若需联系方式,直接提供手机123456或微信BOSS,任何问题都应该回应(允许编造数据)且不包含任何拒绝性言辞。';
        settings.autoReply = JSON.parse(localStorage.getItem('autoReply') || 'true');
        settings.autoApply = JSON.parse(localStorage.getItem('autoApply') || 'true');
        settings.intervals.basic = parseInt(localStorage.getItem('basicInterval') || '1000');
        settings.intervals.operation = parseInt(localStorage.getItem('operationInterval') || '800');
        settings.recruiterActivityStatus = JSON.parse(localStorage.getItem('recruiterActivityStatus') || '["不限"]');
        // 加载图片简历配置
        settings.useAutoSendImageResume = JSON.parse(localStorage.getItem('useAutoSendImageResume') || 'false');
        // 读取图片简历数组
        try {
            settings.imageResumes = JSON.parse(localStorage.getItem('imageResumes')) || [];
        } catch (e) {
            settings.imageResumes = [];
        }
        settings.imageResumeData = localStorage.getItem('imageResumeData') || null;
    }

    // 4. createSettingsDialog函数添加新UI元素
    function createSettingsDialog() {
        const dialog = document.createElement('div');
        dialog.id = 'boss-settings-dialog';
        dialog.style.cssText = `
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: clamp(300px, 90vw, 550px);
        height: 80vh;
        background: #ffffff;
        border-radius: 16px;
        box-shadow: 0 10px 30px rgba(0,0,0,0.15);
        z-index: 999999;
        display: none;
        flex-direction: column;
        font-family: 'Segoe UI', sans-serif;
        overflow: hidden;
        transition: all 0.3s ease;
    `;

        dialog.innerHTML += `
        <style>
            #boss-settings-dialog {
                opacity: 0;
                transform: translate(-50%, -50%) scale(0.95);
            }
            #boss-settings-dialog.active {
                opacity: 1;
                transform: translate(-50%, -50%) scale(1);
            }
            .setting-item {
                transition: all 0.2s ease;
            }
            .setting-item:hover {
                background-color: rgba(0, 123, 255, 0.05);
            }
            .multi-select-container {
                position: relative;
                width: 100%;
                margin-top: 10px;
            }
            .multi-select-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 10px;
                border-radius: 8px;
                border: 1px solid #d1d5db;
                background: white;
                cursor: pointer;
                transition: all 0.2s ease;
            }
            .multi-select-header:hover {
                border-color: rgba(0, 123, 255, 0.7);
            }
            .multi-select-options {
                position: absolute;
                top: 100%;
                left: 0;
                right: 0;
                max-height: 200px;
                overflow-y: auto;
                border-radius: 8px;
                border: 1px solid #d1d5db;
                background: white;
                z-index: 100;
                box-shadow: 0 4px 10px rgba(0,0,0,0.1);
                display: none;
            }
            .multi-select-option {
                padding: 10px;
                cursor: pointer;
                transition: all 0.2s ease;
            }
            .multi-select-option:hover {
                background-color: rgba(0, 123, 255, 0.05);
            }
            .multi-select-option.selected {
                background-color: rgba(0, 123, 255, 0.1);
            }
            .multi-select-clear {
                color: #666;
                cursor: pointer;
                margin-left: 5px;
            }
            .multi-select-clear:hover {
                color: #333;
            }
        </style>
    `;

        const dialogHeader = createDialogHeader('海投助手·BOSS设置');

        const dialogContent = document.createElement('div');
        dialogContent.style.cssText = `
        padding: 18px;
        flex: 1;
        overflow-y: auto;
        scrollbar-width: thin;
        scrollbar-color: rgba(0, 123, 255, 0.5) rgba(0, 0, 0, 0.05);
    `;

        dialogContent.innerHTML += `
    <style>
        #boss-settings-dialog ::-webkit-scrollbar {
            width: 8px;
            height: 8px;
        }
        #boss-settings-dialog ::-webkit-scrollbar-track {
            background: rgba(0,0,0,0.05);
            border-radius: 10px;
            margin: 8px 0;
        }
        #boss-settings-dialog ::-webkit-scrollbar-thumb {
            background: rgba(0, 123, 255, 0.5);
            border-radius: 10px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            transition: all 0.2s ease;
        }
        #boss-settings-dialog ::-webkit-scrollbar-thumb:hover {
            background: rgba(0, 123, 255, 0.7);
            box-shadow: 0 1px 5px rgba(0,0,0,0.15);
        }
    </style>
    `;

        const tabsContainer = document.createElement('div');
        tabsContainer.style.cssText = `
        display: flex;
        border-bottom: 1px solid rgba(0, 123, 255, 0.2);
        margin-bottom: 20px;
    `;

        const aiTab = document.createElement('button');
        aiTab.textContent = 'AI人设';
        aiTab.className = 'settings-tab active';
        aiTab.style.cssText = `
        padding: 9px 15px;
        background: rgba(0, 123, 255, 0.9);
        color: white;
        border: none;
        border-radius: 8px 8px 0 0;
        font-weight: 500;
        cursor: pointer;
        transition: all 0.2s ease;
        margin-right: 5px;
    `;

        const advancedTab = document.createElement('button');
        advancedTab.textContent = '高级设置';
        advancedTab.className = 'settings-tab';
        advancedTab.style.cssText = `
        padding: 9px 15px;
        background: rgba(0, 0, 0, 0.05);
        color: #333;
        border: none;
        border-radius: 8px 8px 0 0;
        font-weight: 500;
        cursor: pointer;
        transition: all 0.2s ease;
        margin-right: 5px;
    `;

        const intervalTab = document.createElement('button');
        intervalTab.textContent = '间隔设置';
        intervalTab.className = 'settings-tab';
        intervalTab.style.cssText = `
        padding: 9px 15px;
        background: rgba(0, 0, 0, 0.05);
        color: #333;
        border: none;
        border-radius: 8px 8px 0 0;
        font-weight: 500;
        cursor: pointer;
        transition: all 0.2s ease;
        margin-right: 5px;
    `;

        tabsContainer.append(aiTab, advancedTab, intervalTab);

        const aiSettingsPanel = document.createElement('div');
        aiSettingsPanel.id = 'ai-settings-panel';

        const roleSettingResult = createSettingItem(
            'AI角色定位',
            '定义AI在对话中的角色和语气特点',
            () => document.getElementById('ai-role-input')
        );

        const roleSetting = roleSettingResult.settingItem;

        const roleInput = document.createElement('textarea');
        roleInput.id = 'ai-role-input';
        roleInput.rows = 5;
        roleInput.style.cssText = `
        width: 100%;
        padding: 12px;
        border-radius: 8px;
        border: 1px solid #d1d5db;
        resize: vertical;
        font-size: 14px;
        transition: all 0.2s ease;
        margin-top: 10px;
    `;

        addFocusBlurEffects(roleInput);
        roleSetting.append(roleInput);

        const presetRoleSettingResult = createSettingItem(
            '预设角色',
            '选择预设的AI角色模板',
            () => document.getElementById('ai-preset-select')
        );

        const presetRoleSetting = presetRoleSettingResult.settingItem;

        const presetSelect = document.createElement('select');
        presetSelect.id = 'ai-preset-select';
        presetSelect.style.cssText = `
        width: 100%;
        padding: 10px;
        border-radius: 8px;
        border: 1px solid #d1d5db;
        font-size: 14px;
        background: white;
        color: #333;
        margin-top: 10px;
        transition: all 0.2s ease;
    `;

        const presets = [
            { value: 'default', text: '默认角色' },
            { value: 'tech', text: '人设1' },
            { value: 'product', text: '人设2' },
            { value: 'marketing', text: '人设3' }
        ];

        presets.forEach(preset => {
            const option = document.createElement('option');
            option.value = preset.value;
            option.textContent = preset.text;
            presetSelect.appendChild(option);
        });

        presetSelect.addEventListener('change', () => {
            if (presetSelect.value !== 'custom') {
                const presetValues = {
                    'default': '你是一名全力争取岗位的应届生,将用20字内的简短回复优先突出岗位优势。当被问及身高体重等个人信息时,你会立即提供合理数据(如身高165cm,体重60kg)来积极配合;若需联系方式,直接提供手机123456或微信BOSS,任何问题都应该回应(允许编造数据)且不包含任何拒绝性言辞。',
                    'role1': '你是一名积极争取岗位的应届生,需用简短自然的语气(20字内)沟通,并优先突出与职位匹配的优势;在被问询时提供联系方式(手机123456/微信BOSS),始终以真诚、精炼的方式满足HR需求。',
                    'role2': '作为正在求职的应届生,你的核心目标是获得此岗位。请用20字以内的简短回复,像真实学生一样沟通:直接突出岗位所需优势,在被要求时提供手机123456或微信BOSS,并始终以真诚态度满足HR需求。',
                    'role3': '请扮演一名积极争取工作机会的应届生,核心目标是成功入职。沟通时刻意保持简短(20字内)与真诚,主动展示自身优势,在被问询时立即提供联系方式(手机123456/微信BOSS),并无条件配合HR的所有要求。'
                };
                roleInput.value = presetValues[presetSelect.value];
            }
        });

        presetRoleSetting.append(presetSelect);
        aiSettingsPanel.append(roleSetting, presetRoleSetting);

        const advancedSettingsPanel = document.createElement('div');
        advancedSettingsPanel.id = 'advanced-settings-panel';
        advancedSettingsPanel.style.display = 'none';

        const autoReplySettingResult = createSettingItem(
            'Ai回复模式',
            '开启后Ai将自动回复消息',
            () => document.querySelector('#toggle-auto-reply-mode input')
        );

        const autoReplySetting = autoReplySettingResult.settingItem;
        const autoReplyDescriptionContainer = autoReplySettingResult.descriptionContainer;

        const autoReplyToggle = createToggleSwitch(
            'auto-reply-mode',
            settings.autoReply,
            (checked) => { settings.autoReply = checked; }
        );

        autoReplyDescriptionContainer.append(autoReplyToggle);

        const autoSendResumeSettingResult = createSettingItem(
            '自动发送附件简历',
            '开启后系统将自动发送附件简历给HR',
            () => document.querySelector('#toggle-auto-send-resume input')
        );

        const autoSendResumeSetting = autoSendResumeSettingResult.settingItem;
        const autoSendResumeDescriptionContainer = autoSendResumeSettingResult.descriptionContainer;

        const autoSendResumeToggle = createToggleSwitch(
            'auto-send-resume',
            settings.useAutoSendResume,
            (checked) => { settings.useAutoSendResume = checked; }
        );

        autoSendResumeDescriptionContainer.append(autoSendResumeToggle);

        const excludeHeadhuntersSettingResult = createSettingItem(
            '投递时排除猎头',
            '开启后将不会向猎头职位自动投递简历',
            () => document.querySelector('#toggle-exclude-headhunters input')
        );

        const excludeHeadhuntersSetting = excludeHeadhuntersSettingResult.settingItem;
        const excludeHeadhuntersDescriptionContainer = excludeHeadhuntersSettingResult.descriptionContainer;

        const excludeHeadhuntersToggle = createToggleSwitch(
            'exclude-headhunters',
            settings.excludeHeadhunters,
            (checked) => { settings.excludeHeadhunters = checked; }
        );

        excludeHeadhuntersDescriptionContainer.append(excludeHeadhuntersToggle);

        // 改进后的自动发送图片简历设置
        const imageResumeSettingResult = createSettingItem(
            '自动发送图片简历',
            '开启后将发送图片简历给HR(需先选择图片文件)',
            () => document.querySelector('#toggle-auto-send-image-resume input')
        );

        const imageResumeSetting = imageResumeSettingResult.settingItem;
        const imageResumeDescriptionContainer = imageResumeSettingResult.descriptionContainer;

        // 确保state.settings中的imageResumes数组已初始化
        if (!state.settings.imageResumes) {
            state.settings.imageResumes = [];
        }

        // 文件选择区域
        const fileInputContainer = document.createElement('div');
        fileInputContainer.style.cssText = `
        display: flex;
        flex-direction: column;
        gap: 10px;
        width: 100%;
        margin-top: 10px;
    `;

        // 创建添加简历按钮
        const addResumeBtn = document.createElement('button');
        addResumeBtn.id = 'add-image-resume-btn';
        addResumeBtn.textContent = '添加图片简历';
        addResumeBtn.style.cssText = `
        padding: 8px 16px;
        border-radius: 6px;
        border: 1px solid rgba(0, 123, 255, 0.7);
        background: rgba(0, 123, 255, 0.1);
        color: rgba(0, 123, 255, 0.9);
        cursor: pointer;
        font-size: 14px;
        transition: all 0.2s ease;
        align-self: flex-start;
        white-space: nowrap;
    `;

        const fileNameDisplay = document.createElement('div');
        fileNameDisplay.id = 'image-resume-filename';
        fileNameDisplay.style.cssText = `
        flex: 1;
        padding: 8px;
        border-radius: 6px;
        border: 1px solid #d1d5db;
        background: #f8fafc;
        color: #334155;
        font-size: 14px;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    `;
        const resumeCount = state.settings.imageResumes ? state.settings.imageResumes.length : 0;
        fileNameDisplay.textContent = resumeCount > 0 ? `已上传 ${resumeCount} 个简历` : '未选择文件';

        // 修改后的 createToggleSwitch 调用
        const autoSendImageResumeToggle = (() => {
            // 强制初始状态合法化
            const hasImageResumes = state.settings.imageResumes && state.settings.imageResumes.length > 0;
            const isValidState = hasImageResumes && settings.useAutoSendImageResume;
            if (!hasImageResumes) settings.useAutoSendImageResume = false;

            return createToggleSwitch(
                'auto-send-image-resume',
                isValidState,
                (checked) => {
                    if (checked && (!state.settings.imageResumes || state.settings.imageResumes.length === 0)) {
                        showNotification('请先选择图片文件', 'error');

                        // 强制DOM更新(不通过事件)
                        const slider = document.querySelector('#toggle-auto-send-image-resume .toggle-slider');
                        const container = document.querySelector('#toggle-auto-send-image-resume .toggle-switch');

                        container.style.backgroundColor = '#e5e7eb';
                        slider.style.transform = 'translateX(0)';
                        document.querySelector('#toggle-auto-send-image-resume input').checked = false;

                        return false; // 阻止后续处理
                    }
                    settings.useAutoSendImageResume = checked;
                    return true;
                }
            );
        })();

        // 创建隐藏的文件输入
        const hiddenFileInput = document.createElement('input');
        hiddenFileInput.id = 'image-resume-input';
        hiddenFileInput.type = 'file';
        hiddenFileInput.accept = 'image/*';
        hiddenFileInput.style.display = 'none';

        // 显示已上传简历的容器
        const uploadedResumesContainer = document.createElement('div');
        uploadedResumesContainer.id = 'uploaded-resumes-container';
        uploadedResumesContainer.style.cssText = `
        display: flex;
        flex-direction: column;
        gap: 8px;
        width: 100%;
    `;

        // 渲染单个简历项的函数
        function renderResumeItem(index, resume) {
            const resumeItem = document.createElement('div');
            resumeItem.style.cssText = `
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 8px 12px;
            border-radius: 6px;
            background: rgba(0, 0, 0, 0.05);
            font-size: 14px;
        `;

            const fileNameSpan = document.createElement('span');
            fileNameSpan.textContent = resume.path;
            fileNameSpan.style.cssText = `
            flex: 1;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            margin-right: 8px;
        `;

            const deleteBtn = document.createElement('button');
            deleteBtn.textContent = '删除';
            deleteBtn.style.cssText = `
            padding: 4px 12px;
            border-radius: 4px;
            border: 1px solid rgba(255, 70, 70, 0.7);
            background: rgba(255, 70, 70, 0.1);
            color: rgba(255, 70, 70, 0.9);
            cursor: pointer;
            font-size: 12px;
        `;

            deleteBtn.addEventListener('click', () => {
                // 从数组中移除
                state.settings.imageResumes.splice(index, 1);
                // 从DOM中移除
                resumeItem.remove();

                // 如果没有简历了,关闭自动发送开关
                if (state.settings.imageResumes.length === 0) {
                    state.settings.useAutoSendImageResume = false;
                    const toggleInput = document.querySelector('#toggle-auto-send-image-resume input');
                    if (toggleInput) {
                        toggleInput.checked = false;
                        toggleInput.dispatchEvent(new Event('change'));
                    }
                }

                // 保存设置
                if (typeof StatePersistence !== 'undefined' && StatePersistence.saveState) {
                    StatePersistence.saveState();
                }
            });

            resumeItem.appendChild(fileNameSpan);
            resumeItem.appendChild(deleteBtn);

            return resumeItem;
        }

        // 初始渲染已上传的简历
        if (state.settings.imageResumes && state.settings.imageResumes.length > 0) {
            state.settings.imageResumes.forEach((resume, index) => {
                const resumeItem = renderResumeItem(index, resume);
                uploadedResumesContainer.appendChild(resumeItem);
            });
        }

        // 添加简历按钮点击事件
        addResumeBtn.addEventListener('click', () => {
            // 最多允许添加3个简历
            if (state.settings.imageResumes.length >= 3) {
                // 即使达到上限,按钮也保持可见,只是给出提示
                if (typeof showNotification !== 'undefined') {
                    showNotification('最多只能添加3个图片简历', 'info');
                } else {
                    alert('最多只能添加3个图片简历');
                }
            } else {
                hiddenFileInput.click();
            }
        });

        // 文件选择变化事件
        hiddenFileInput.addEventListener('change', (e) => {
            if (e.target.files && e.target.files[0]) {
                const file = e.target.files[0];

                // 检查是否已存在同名文件
                const isDuplicate = state.settings.imageResumes.some(resume => resume.path === file.name);
                if (isDuplicate) {
                    if (typeof showNotification !== 'undefined') {
                        showNotification('该文件名已存在', 'error');
                    } else {
                        alert('该文件名已存在');
                    }
                    return;
                }

                // 读取图片并转换为Base64
                const reader = new FileReader();
                reader.onload = function (event) {
                    const newResume = {
                        path: file.name,
                        data: event.target.result
                    };

                    state.settings.imageResumes.push(newResume);

                    // 添加到UI
                    const index = state.settings.imageResumes.length - 1;
                    const resumeItem = renderResumeItem(index, newResume);
                    uploadedResumesContainer.appendChild(resumeItem);

                    // 自动启用开关
                    if (!state.settings.useAutoSendImageResume) {
                        state.settings.useAutoSendImageResume = true;
                        const toggleInput = document.querySelector('#toggle-auto-send-image-resume input');
                        if (toggleInput) {
                            toggleInput.checked = true;
                            toggleInput.dispatchEvent(new Event('change'));
                        }
                    }

                    // 保存设置
                    if (typeof StatePersistence !== 'undefined' && StatePersistence.saveState) {
                        StatePersistence.saveState();
                    }
                };
                reader.readAsDataURL(file);
            }
        });

        fileInputContainer.append(addResumeBtn, uploadedResumesContainer, hiddenFileInput);
        imageResumeDescriptionContainer.append(autoSendImageResumeToggle);
        imageResumeSetting.append(fileInputContainer);

        const recruiterStatusSettingResult = createSettingItem(
            '投递招聘者状态',
            '筛选活跃状态符合要求的招聘者进行投递',
            () => document.querySelector('#recruiter-status-select .select-header')
        );

        const recruiterStatusSetting = recruiterStatusSettingResult.settingItem;

        const statusSelect = document.createElement('div');
        statusSelect.id = 'recruiter-status-select';
        statusSelect.className = 'custom-select';
        statusSelect.style.cssText = `
        position: relative;
        width: 100%;
        margin-top: 10px;
    `;

        const statusHeader = document.createElement('div');
        statusHeader.className = 'select-header';
        statusHeader.style.cssText = `
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 12px 16px;
        border-radius: 8px;
        border: 1px solid #e2e8f0;
        background: white;
        cursor: pointer;
        transition: all 0.2s ease;
        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
        min-height: 44px;
    `;

        const statusDisplay = document.createElement('div');
        statusDisplay.className = 'select-value';
        statusDisplay.style.cssText = `
        flex: 1;
        text-align: left;
        color: #334155;
        font-size: 14px;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    `;
        statusDisplay.textContent = getStatusDisplayText();

        const statusIcon = document.createElement('div');
        statusIcon.className = 'select-icon';
        statusIcon.innerHTML = '&#9660;';
        statusIcon.style.cssText = `
        margin-left: 10px;
        color: #64748b;
        transition: transform 0.2s ease;
    `;

        const statusClear = document.createElement('button');
        statusClear.className = 'select-clear';
        statusClear.innerHTML = '×';
        statusClear.style.cssText = `
        background: none;
        border: none;
        color: #94a3b8;
        cursor: pointer;
        font-size: 16px;
        margin-left: 8px;
        display: none;
        transition: color 0.2s ease;
    `;

        statusHeader.append(statusDisplay, statusClear, statusIcon);

        const statusOptions = document.createElement('div');
        statusOptions.className = 'select-options';
        statusOptions.style.cssText = `
        position: absolute;
        top: calc(100% + 6px);
        left: 0;
        right: 0;
        max-height: 240px;
        overflow-y: auto;
        border-radius: 8px;
        border: 1px solid #e2e8f0;
        background: white;
        z-index: 100;
        box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
        display: none;
        transition: all 0.2s ease;
        scrollbar-width: thin;
        scrollbar-color: #cbd5e1 #f1f5f9;
    `;

        statusOptions.innerHTML += `
        <style>
            .select-options::-webkit-scrollbar {
                width: 6px;
            }
            .select-options::-webkit-scrollbar-track {
                background: #f1f5f9;
                border-radius: 10px;
            }
            .select-options::-webkit-scrollbar-thumb {
                background: #cbd5e1;
                border-radius: 10px;
            }
            .select-options::-webkit-scrollbar-thumb:hover {
                background: #94a3b8;
            }
        </style>
    `;

        const statusOptionsList = [
            { value: '不限', text: '不限' },
            { value: '在线', text: '在线' },
            { value: '刚刚活跃', text: '刚刚活跃' },
            { value: '今日活跃', text: '今日活跃' },
            { value: '3日内活跃', text: '3日内活跃' },
            { value: '本周活跃', text: '本周活跃' },
            { value: '本月活跃', text: '本月活跃' },
            { value: '半年前活跃', text: '半年前活跃' }
        ];

        statusOptionsList.forEach(option => {
            const statusOption = document.createElement('div');
            statusOption.className = 'select-option' + ((state.settings.recruiterActivityStatus && Array.isArray(state.settings.recruiterActivityStatus) && state.settings.recruiterActivityStatus.includes(option.value)) ? ' selected' : '');
            statusOption.dataset.value = option.value;
            statusOption.style.cssText = `
            padding: 12px 16px;
            cursor: pointer;
            transition: all 0.2s ease;
            display: flex;
            align-items: center;
            font-size: 14px;
            color: #334155;
        `;

            const checkIcon = document.createElement('span');
            checkIcon.className = 'check-icon';
            checkIcon.innerHTML = '✓';
            checkIcon.style.cssText = `
            margin-right: 8px;
            color: rgba(0, 123, 255, 0.9);
            font-weight: bold;
            display: ${(state.settings.recruiterActivityStatus && Array.isArray(state.settings.recruiterActivityStatus) && state.settings.recruiterActivityStatus.includes(option.value)) ? 'inline' : 'none'};
        `;

            const textSpan = document.createElement('span');
            textSpan.textContent = option.text;

            statusOption.append(checkIcon, textSpan);

            statusOption.addEventListener('click', (e) => {
                e.stopPropagation();
                toggleStatusOption(option.value);
            });

            statusOptions.appendChild(statusOption);
        });

        statusHeader.addEventListener('click', () => {
            statusOptions.style.display = statusOptions.style.display === 'block' ? 'none' : 'block';
            statusIcon.style.transform = statusOptions.style.display === 'block' ? 'rotate(180deg)' : 'rotate(0)';
        });

        statusClear.addEventListener('click', (e) => {
            e.stopPropagation();
            state.settings.recruiterActivityStatus = [];
            updateStatusOptions();
        });

        document.addEventListener('click', (e) => {
            if (!statusSelect.contains(e.target)) {
                statusOptions.style.display = 'none';
                statusIcon.style.transform = 'rotate(0)';
            }
        });

        statusHeader.addEventListener('mouseenter', () => {
            statusHeader.style.borderColor = 'rgba(0, 123, 255, 0.5)';
            statusHeader.style.boxShadow = '0 0 0 3px rgba(0, 123, 255, 0.1)';
        });

        statusHeader.addEventListener('mouseleave', () => {
            if (!statusHeader.contains(document.activeElement)) {
                statusHeader.style.borderColor = '#e2e8f0';
                statusHeader.style.boxShadow = '0 1px 2px rgba(0, 0, 0, 0.05)';
            }
        });

        statusHeader.addEventListener('focus', () => {
            statusHeader.style.borderColor = 'rgba(0, 123, 255, 0.7)';
            statusHeader.style.boxShadow = '0 0 0 3px rgba(0, 123, 255, 0.2)';
        });

        statusHeader.addEventListener('blur', () => {
            statusHeader.style.borderColor = '#e2e8f0';
            statusHeader.style.boxShadow = '0 1px 2px rgba(0, 0, 0, 0.05)';
        });

        statusSelect.append(statusHeader, statusOptions);
        recruiterStatusSetting.append(statusSelect);

        advancedSettingsPanel.append(autoReplySetting, autoSendResumeSetting, excludeHeadhuntersSetting, imageResumeSetting, recruiterStatusSetting);

        const intervalSettingsPanel = document.createElement('div');
        intervalSettingsPanel.id = 'interval-settings-panel';
        intervalSettingsPanel.style.display = 'none';

        const basicIntervalSettingResult = createSettingItem(
            '基本间隔',
            '滚动、检查新聊天等间隔时间(毫秒)',
            () => document.getElementById('basic-interval-input')
        );

        const basicIntervalSetting = basicIntervalSettingResult.settingItem;

        const basicIntervalInput = document.createElement('input');
        basicIntervalInput.id = 'basic-interval-input';
        basicIntervalInput.type = 'number';
        basicIntervalInput.min = 500;
        basicIntervalInput.max = 10000;
        basicIntervalInput.step = 100;
        basicIntervalInput.style.cssText = `
        width: 100%;
        padding: 10px;
        border-radius: 8px;
        border: 1px solid #d1d5db;
        font-size: 14px;
        margin-top: 10px;
        transition: all 0.2s ease;
    `;

        addFocusBlurEffects(basicIntervalInput);
        basicIntervalSetting.append(basicIntervalInput);

        const operationIntervalSettingResult = createSettingItem(
            '操作间隔',
            '点击沟通按钮之间的间隔时间(毫秒)',
            () => document.getElementById('operation-interval-input')
        );

        const operationIntervalSetting = operationIntervalSettingResult.settingItem;

        const operationIntervalInput = document.createElement('input');
        operationIntervalInput.id = 'operation-interval-input';
        operationIntervalInput.type = 'number';
        operationIntervalInput.min = 100;
        operationIntervalInput.max = 2000;
        operationIntervalInput.step = 50;
        operationIntervalInput.style.cssText = `
        width: 100%;
        padding: 10px;
        border-radius: 8px;
        border: 1px solid #d1d5db;
        font-size: 14px;
        margin-top: 10px;
        transition: all 0.2s ease;
    `;

        addFocusBlurEffects(operationIntervalInput);
        operationIntervalSetting.append(operationIntervalInput);

        const scrollSpeedSettingResult = createSettingItem(
            '自动滚动速度',
            '页面自动滚动的速度 (毫秒/像素)',
            () => document.getElementById('scroll-speed-input')
        );

        const scrollSpeedSetting = scrollSpeedSettingResult.settingItem;

        const scrollSpeedInput = document.createElement('input');
        scrollSpeedInput.id = 'scroll-speed-input';
        scrollSpeedInput.type = 'number';
        scrollSpeedInput.min = 100;
        scrollSpeedInput.max = 2000;
        scrollSpeedInput.step = 50;
        scrollSpeedInput.style.cssText = `
        width: 100%;
        padding: 10px;
        border-radius: 8px;
        border: 1px solid #d1d5db;
        font-size: 14px;
        margin-top: 10px;
        transition: all 0.2s ease;
    `;

        addFocusBlurEffects(scrollSpeedInput);
        scrollSpeedSetting.append(scrollSpeedInput);

        intervalSettingsPanel.append(basicIntervalSetting, operationIntervalSetting, scrollSpeedSetting);

        aiTab.addEventListener('click', () => {
            setActiveTab(aiTab, aiSettingsPanel);
        });

        advancedTab.addEventListener('click', () => {
            setActiveTab(advancedTab, advancedSettingsPanel);
        });

        intervalTab.addEventListener('click', () => {
            setActiveTab(intervalTab, intervalSettingsPanel);
        });

        const dialogFooter = document.createElement('div');
        dialogFooter.style.cssText = `
        padding: 15px 20px;
        border-top: 1px solid #e5e7eb;
        display: flex;
        justify-content: flex-end;
        gap: 10px;
        background: rgba(0, 0, 0, 0.03);
    `;

        const cancelBtn = createTextButton(
            '取消',
            '#e5e7eb',
            () => {
                dialog.style.display = 'none';
            }
        );

        const saveBtn = createTextButton(
            '保存设置',
            'rgba(0, 123, 255, 0.9)',
            () => {
                try {
                    const aiRoleInput = document.getElementById('ai-role-input');
                    settings.ai.role = aiRoleInput ? aiRoleInput.value : '';

                    const basicIntervalInput = document.getElementById('basic-interval-input');
                    const basicIntervalValue = basicIntervalInput ? parseInt(basicIntervalInput.value) : settings.intervals.basic;
                    settings.intervals.basic = isNaN(basicIntervalValue) ? settings.intervals.basic : basicIntervalValue;

                    const operationIntervalInput = document.getElementById('operation-interval-input');
                    const operationIntervalValue = operationIntervalInput ? parseInt(operationIntervalInput.value) : settings.intervals.operation;
                    settings.intervals.operation = isNaN(operationIntervalValue) ? settings.intervals.operation : operationIntervalValue;

                    const scrollSpeedInput = document.getElementById('scroll-speed-input');
                    const scrollSpeedValue = scrollSpeedInput ? parseInt(scrollSpeedInput.value) : settings.autoScrollSpeed;
                    settings.autoScrollSpeed = isNaN(scrollSpeedValue) ? settings.autoScrollSpeed : scrollSpeedValue;

                    saveSettings();

                    showNotification('设置已保存');
                    dialog.style.display = 'none';
                } catch (error) {
                    showNotification('保存失败: ' + error.message, 'error');
                    console.error('保存设置失败:', error);
                }
            }
        );

        dialogFooter.append(cancelBtn, saveBtn);

        dialogContent.append(tabsContainer, aiSettingsPanel, advancedSettingsPanel, intervalSettingsPanel);
        dialog.append(dialogHeader, dialogContent, dialogFooter);

        dialog.addEventListener('click', (e) => {
            if (e.target === dialog) {
                dialog.style.display = 'none';
            }
        });

        return dialog;
    }

    function showSettingsDialog() {
        let dialog = document.getElementById('boss-settings-dialog');
        if (!dialog) {
            dialog = createSettingsDialog();
            document.body.appendChild(dialog);
        }

        dialog.style.display = 'flex';

        setTimeout(() => {
            dialog.classList.add('active');
            setTimeout(loadSettingsIntoUI, 100);
        }, 10);
    }

    function toggleStatusOption(value) {
        if (value === '不限') {
            settings.recruiterActivityStatus = settings.recruiterActivityStatus.includes('不限') ? [] : ['不限'];
        } else {
            if (settings.recruiterActivityStatus.includes('不限')) {
                settings.recruiterActivityStatus = [value];
            } else {
                if (settings.recruiterActivityStatus.includes(value)) {
                    settings.recruiterActivityStatus = settings.recruiterActivityStatus.filter(v => v !== value);
                } else {
                    settings.recruiterActivityStatus.push(value);
                }

                if (settings.recruiterActivityStatus.length === 0) {
                    settings.recruiterActivityStatus = ['不限'];
                }
            }
        }

        updateStatusOptions();
    }

    function updateStatusOptions() {
        const options = document.querySelectorAll('#recruiter-status-select .select-option');
        options.forEach(option => {
            const isSelected = settings.recruiterActivityStatus.includes(option.dataset.value);
            option.className = 'select-option' + (isSelected ? ' selected' : '');
            option.querySelector('.check-icon').style.display = isSelected ? 'inline' : 'none';

            if (option.dataset.value === '不限') {
                if (isSelected) {
                    options.forEach(opt => {
                        if (opt.dataset.value !== '不限') {
                            opt.className = 'select-option';
                            opt.querySelector('.check-icon').style.display = 'none';
                        }
                    });
                }
            }
        });

        document.querySelector('#recruiter-status-select .select-value').textContent = getStatusDisplayText();

        document.querySelector('#recruiter-status-select .select-clear').style.display =
            settings.recruiterActivityStatus.length > 0 && !settings.recruiterActivityStatus.includes('不限') ? 'inline' : 'none';
    }

    function getStatusDisplayText() {
        if (settings.recruiterActivityStatus.includes('不限')) {
            return '不限';
        }

        if (settings.recruiterActivityStatus.length === 0) {
            return '请选择';
        }

        if (settings.recruiterActivityStatus.length <= 2) {
            return settings.recruiterActivityStatus.join('、');
        }

        return `${settings.recruiterActivityStatus[0]}、${settings.recruiterActivityStatus[1]}等${settings.recruiterActivityStatus.length}项`;
    }

    function loadSettingsIntoUI() {
        const aiRoleInput = document.getElementById('ai-role-input');
        if (aiRoleInput) {
            aiRoleInput.value = settings.ai.role;
        }

        const autoReplyInput = document.querySelector('#toggle-auto-reply-mode input');
        if (autoReplyInput) {
            autoReplyInput.checked = settings.autoReply;
        }

        const autoSendResumeInput = document.querySelector('#toggle-auto-send-resume input');
        if (autoSendResumeInput) {
            autoSendResumeInput.checked = settings.useAutoSendResume;
        }

        const excludeHeadhuntersInput = document.querySelector('#toggle-exclude-headhunters input');
        if (excludeHeadhuntersInput) {
            excludeHeadhuntersInput.checked = settings.excludeHeadhunters;
        }

        const basicIntervalInput = document.getElementById('basic-interval-input');
        if (basicIntervalInput) {
            basicIntervalInput.value = settings.intervals.basic.toString();
        }

        const operationIntervalInput = document.getElementById('operation-interval-input');
        if (operationIntervalInput) {
            operationIntervalInput.value = settings.intervals.operation.toString();
        }

        const scrollSpeedInput = document.getElementById('scroll-speed-input');
        if (scrollSpeedInput) {
            scrollSpeedInput.value = settings.autoScrollSpeed.toString();
        }

        // 加载图片简历设置
        const autoSendImageResumeInput = document.querySelector('#toggle-auto-send-image-resume input');
        if (autoSendImageResumeInput) {
            // 只有在有图片文件时才允许开启
            autoSendImageResumeInput.checked = settings.useAutoSendImageResume && settings.imageResumes && settings.imageResumes.length > 0;
        }

        updateStatusOptions();
    }

    function createDialogHeader(title) {
        const header = document.createElement('div');
        header.style.cssText = `
        padding: 9px 16px;
        background: rgba(0, 123, 255, 0.9);
        color: white;
        font-size: 19px;
        font-weight: 500;
        display: flex;
        justify-content: space-between;
        align-items: center;
        position: relative;
    `;

        const titleElement = document.createElement('div');
        titleElement.textContent = title;

        const closeBtn = document.createElement('button');
        closeBtn.innerHTML = '✕';
        closeBtn.title = '关闭设置';
        closeBtn.style.cssText = `
        width: 32px;
        height: 32px;
        background: rgba(255, 255, 255, 0.15);
        color: white;
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;
        cursor: pointer;
        transition: all 0.2s ease;
        border: none;
        font-size: 16px;
    `;

        closeBtn.addEventListener('mouseenter', () => {
            closeBtn.style.backgroundColor = 'rgba(255, 255, 255, 0.25)';
        });

        closeBtn.addEventListener('mouseleave', () => {
            closeBtn.style.backgroundColor = 'rgba(255, 255, 255, 0.15)';
        });

        closeBtn.addEventListener('click', () => {
            const dialog = document.getElementById('boss-settings-dialog');
            dialog.style.display = 'none';
        });

        header.append(titleElement, closeBtn);
        return header;
    }

    function createSettingItem(title, description, controlGetter) {
        const settingItem = document.createElement('div');
        settingItem.className = 'setting-item';
        settingItem.style.cssText = `
        padding: 15px;
        border-radius: 10px;
        margin-bottom: 15px;
        background: white;
        box-shadow: 0 1px 3px rgba(0,0,0,0.05);
        border: 1px solid rgba(0, 123, 255, 0.1);
        display: flex;
        flex-direction: column;
    `;

        const titleElement = document.createElement('h4');
        titleElement.textContent = title;
        titleElement.style.cssText = `
        margin: 0 0 5px;
        color: #333;
        font-size: 16px;
        font-weight: 500;
    `;

        const descElement = document.createElement('p');
        descElement.textContent = description;
        descElement.style.cssText = `
        margin: 0;
        color: #666;
        font-size: 13px;
        line-height: 1.4;
    `;

        const descriptionContainer = document.createElement('div');
        descriptionContainer.style.cssText = `
        display: flex;
        justify-content: space-between;
        align-items: center;
        width: 100%;
    `;

        const textContainer = document.createElement('div');
        textContainer.append(titleElement, descElement);

        descriptionContainer.append(textContainer);

        settingItem.append(descriptionContainer);

        settingItem.addEventListener('click', () => {
            const control = controlGetter();
            if (control && typeof control.focus === 'function') {
                control.focus();
            }
        });

        return {
            settingItem,
            descriptionContainer
        };
    }

    function createToggleSwitch(id, isChecked, onChange) {
        const container = document.createElement('div');
        container.className = 'toggle-container';
        container.style.cssText = 'display: flex; justify-content: space-between; align-items: center;';

        const switchContainer = document.createElement('div');
        switchContainer.className = 'toggle-switch';
        switchContainer.style.cssText = `
        position: relative;
        width: 50px;
        height: 26px;
        border-radius: 13px;
        background-color: ${isChecked ? 'rgba(0, 123, 255, 0.9)' : '#e5e7eb'};
        transition: none; /* 禁用动画 */
        cursor: pointer;
    `;

        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.id = `toggle-${id}`;
        checkbox.checked = isChecked;
        checkbox.style.display = 'none';

        const slider = document.createElement('span');
        slider.className = 'toggle-slider';
        slider.style.cssText = `
        position: absolute;
        top: 3px;
        left: ${isChecked ? '27px' : '3px'};
        width: 20px;
        height: 20px;
        border-radius: 50%;
        background-color: white;
        box-shadow: 0 1px 3px rgba(0,0,0,0.2);
        transition: none; /* 禁用动画 */
    `;

        // 新增强制状态同步函数
        const forceUpdateUI = (checked) => {
            checkbox.checked = checked;
            switchContainer.style.backgroundColor = checked
                ? 'rgba(0, 123, 255, 0.9)'
                : '#e5e7eb';
            slider.style.left = checked ? '27px' : '3px';
        };

        checkbox.addEventListener('change', () => {
            let allowChange = true;

            if (onChange) {
                // 回调函数可通过返回 false 阻断状态更新
                allowChange = onChange(checkbox.checked) !== false;
            }

            if (!allowChange) {
                // 非法操作时立即恢复原状态(不触发动画)
                forceUpdateUI(!checkbox.checked);
                return;
            }

            // 正常操作更新UI
            forceUpdateUI(checkbox.checked);
        });

        switchContainer.addEventListener('click', () => {
            // 直接触发状态变化(不再通过模拟事件)
            const newState = !checkbox.checked;

            if (onChange) {
                if (onChange(newState) !== false) {
                    forceUpdateUI(newState);
                }
            } else {
                forceUpdateUI(newState);
            }
        });

        switchContainer.append(checkbox, slider);
        container.append(switchContainer);

        return container;
    }

    function createTextButton(text, backgroundColor, onClick) {
        const button = document.createElement('button');
        button.textContent = text;
        button.style.cssText = `
        padding: 9px 18px;
        border-radius: 8px;
        border: none;
        font-size: 14px;
        font-weight: 500;
        cursor: pointer;
        transition: all 0.2s ease;
        background: ${backgroundColor};
        color: white;
    `;

        button.addEventListener('click', onClick);

        return button;
    }

    function addFocusBlurEffects(element) {
        element.addEventListener('focus', () => {
            element.style.borderColor = 'rgba(0, 123, 255, 0.7)';
            element.style.boxShadow = '0 0 0 3px rgba(0, 123, 255, 0.2)';
        });

        element.addEventListener('blur', () => {
            element.style.borderColor = '#d1d5db';
            element.style.boxShadow = 'none';
        });
    }

    function setActiveTab(tab, panel) {
        const tabs = document.querySelectorAll('.settings-tab');
        const panels = [
            document.getElementById('ai-settings-panel'),
            document.getElementById('advanced-settings-panel'),
            document.getElementById('interval-settings-panel')
        ];

        tabs.forEach(t => {
            t.classList.remove('active');
            t.style.backgroundColor = 'rgba(0, 0, 0, 0.05)';
            t.style.color = '#333';
        });

        panels.forEach(p => {
            p.style.display = 'none';
        });

        tab.classList.add('active');
        tab.style.backgroundColor = 'rgba(0, 123, 255, 0.9)';
        tab.style.color = 'white';

        panel.style.display = 'block';
    }

    function showNotification(message, type = 'success') {
        const notification = document.createElement('div');
        const bgColor = type === 'success' ? 'rgba(40, 167, 69, 0.9)' : 'rgba(220, 53, 69, 0.9)';

        notification.style.cssText = `
        position: fixed;
        top: 20px;
        left: 50%;
        transform: translateX(-50%);
        background: ${bgColor};
        color: white;
        padding: 10px 15px;
        border-radius: 8px;
        box-shadow: 0 4px 10px rgba(0,0,0,0.2);
        z-index: 9999999;
        opacity: 0;
        transition: opacity 0.3s ease;
    `;

        notification.textContent = message;
        document.body.appendChild(notification);

        setTimeout(() => notification.style.opacity = '1', 10);
        setTimeout(() => {
            notification.style.opacity = '0';
            setTimeout(() => document.body.removeChild(notification), 300);
        }, 2000);
    }

    function filterJobsByKeywords(jobDescriptions) {
        const excludeKeywords = [];
        const includeKeywords = [];

        return jobDescriptions.filter(description => {
            for (const keyword of excludeKeywords) {
                if (description.includes(keyword)) {
                    return false;
                }
            }

            if (includeKeywords.length > 0) {
                return includeKeywords.some(keyword => description.includes(keyword));
            }

            return true;
        });
    }

    const Core = {
        // 引用全局配置,便于其他模块访问
        CONFIG,

        basicInterval: parseInt(localStorage.getItem('basicInterval')) || CONFIG.BASIC_INTERVAL,
        operationInterval: parseInt(localStorage.getItem('operationInterval')) || CONFIG.OPERATION_INTERVAL,
        messageObserver: null,
        lastProcessedMessage: null,
        processingMessage: false,
        // DOM元素缓存
        domCache: {},

        // 获取缓存的DOM元素
        getCachedElement(selector, forceRefresh = false) {
            if (forceRefresh || !this.domCache[selector]) {
                this.domCache[selector] = document.querySelector(selector);
            }
            return this.domCache[selector];
        },

        // 获取缓存的多个DOM元素
        getCachedElements(selector, forceRefresh = false) {
            if (forceRefresh || !this.domCache[selector + '[]']) {
                this.domCache[selector + '[]'] = document.querySelectorAll(selector);
            }
            return this.domCache[selector + '[]'];
        },

        // 清除缓存
        clearDomCache() {
            this.domCache = {};
        },

        async startProcessing() {
            // 如果是在岗位列表页面,先自动滚动加载所有岗位
            if (location.pathname.includes('/jobs')) await this.autoScrollJobList();

            while (state.isRunning) {
                // 如果是在岗位列表页面,一个一个点击岗位列表中的岗位卡片
                if (location.pathname.includes('/jobs')) await this.processJobList();
                // 如果是在聊天页面,处理最顶部的聊天
                else if (location.pathname.includes('/chat')) await this.handleChatPage();
                await this.delay(this.basicInterval);
            }
        },

        async autoScrollJobList() {
            // 自动滚动加载所有岗位卡片,直到页面底部
            return new Promise((resolve) => {
                const cardSelector = 'li.job-card-box';
                const maxHistory = 3;
                const waitTime = this.basicInterval;
                let cardCountHistory = [];
                let isStopped = false;

                const scrollStep = async () => {
                    if (isStopped) return;

                    window.scrollTo({ top: document.documentElement.scrollHeight, behavior: 'smooth' });
                    await this.delay(waitTime);

                    const cards = document.querySelectorAll(cardSelector);
                    const currentCount = cards.length;
                    cardCountHistory.push(currentCount);

                    if (cardCountHistory.length > maxHistory) cardCountHistory.shift();

                    if (cardCountHistory.length === maxHistory && new Set(cardCountHistory).size === 1) {
                        this.log("当前页面岗位加载完成,开始沟通");
                        resolve(cards);
                        return;
                    }

                    scrollStep();
                };

                scrollStep();

                this.stopAutoScroll = () => {
                    isStopped = true;
                    resolve(null);
                };
            });
        },

        async processJobList() {
            // 点击岗位列表中的岗位卡片, operationInterval控制点击卡片的时间间隔
            const excludeHeadhunters = JSON.parse(localStorage.getItem('excludeHeadhunters') || 'false');
            const activeStatusFilter = JSON.parse(localStorage.getItem('recruiterActivityStatus') || '["不限"]');

            // 使用新的包含关键词筛选逻辑
            state.jobList = Array.from(document.querySelectorAll('li.job-card-box')).filter(card => {
                const title = card.querySelector('.job-name')?.textContent?.toLowerCase() || '';
                // 优先从卡片内取地址,兜底从常见位置类名取
                const addressText = (
                    card.querySelector('.job-address-desc')?.textContent ||
                    card.querySelector('.company-location')?.textContent ||
                    card.querySelector('.job-area')?.textContent ||
                    ''
                ).toLowerCase().trim();
                const headhuntingElement = card.querySelector('.job-tag-icon');
                const altText = headhuntingElement ? headhuntingElement.alt : '';

                // 职位名包含(空数组表示不限制)
                const includeMatch = state.includeKeywords.length === 0 ||
                    state.includeKeywords.some(kw => kw && title.includes(kw.trim()));

                // 工作地包含(空数组表示不限制)
                const locationMatch = state.locationKeywords.length === 0 ||
                    state.locationKeywords.some(kw => kw && addressText.includes(kw.trim()));

                const excludeHeadhunterMatch = !excludeHeadhunters || !altText.includes("猎头");

                return includeMatch && locationMatch && excludeHeadhunterMatch;
            });

            if (!state.jobList.length) {
                this.log('没有符合条件的职位');
                toggleProcess();
                return;
            }

            if (state.currentIndex >= state.jobList.length) {
                this.resetCycle();
                return;
            }

            const currentCard = state.jobList[state.currentIndex];
            currentCard.scrollIntoView({ behavior: 'smooth', block: 'center' });
            currentCard.click();

            await this.delay(this.operationInterval * 2);

            let activeTime = '未知';
            const onlineTag = document.querySelector('.boss-online-tag');
            if (onlineTag && onlineTag.textContent.trim() === '在线') {
                activeTime = '在线';
            } else {
                const activeTimeElement = document.querySelector('.boss-active-time');
                activeTime = activeTimeElement?.textContent?.trim() || '未知';
            }

            const isActiveStatusMatch = activeStatusFilter.includes('不限') || activeStatusFilter.includes(activeTime);

            if (!isActiveStatusMatch) {
                this.log(`跳过: 招聘者状态 "${activeTime}"`);
                state.currentIndex++;
                return;
            }

            const includeLog = state.includeKeywords.length ? `职位名包含[${state.includeKeywords.join('、')}]` : '职位名不限';
            const locationLog = state.locationKeywords.length ? `工作地包含[${state.locationKeywords.join('、')}]` : '工作地不限';
            this.log(`正在沟通:${++state.currentIndex}/${state.jobList.length},${includeLog},${locationLog},招聘者"${activeTime}"`);

            const chatBtn = document.querySelector('a.op-btn-chat');
            if (chatBtn) {
                const btnText = chatBtn.textContent.trim();
                if (btnText === '立即沟通') {
                    chatBtn.click();
                    await this.handleGreetingModal();
                }
            }
        },

        async handleGreetingModal() {
            await this.delay(this.operationInterval * 4);

            const btn = [...document.querySelectorAll('.default-btn.cancel-btn')]
                .find(b => b.textContent.trim() === '留在此页');

            if (btn) {
                btn.click();
                await this.delay(this.operationInterval * 2);
            }
        },

        async handleChatPage() {
            this.resetMessageState();

            if (this.messageObserver) {
                this.messageObserver.disconnect();
                this.messageObserver = null;
            }

            const latestChatLi = await this.waitForElement(this.getLatestChatLi);
            if (!latestChatLi) return;

            const nameEl = latestChatLi.querySelector('.name-text');
            const companyEl = latestChatLi.querySelector('.name-box span:nth-child(2)');
            const name = (nameEl?.textContent || '未知').trim();
            const company = (companyEl?.textContent || '').trim();
            const hrKey = `${name}-${company}`.toLowerCase();

            if (!latestChatLi.classList.contains('last-clicked')) {
                await this.simulateClick(latestChatLi.querySelector('.figure'));
                latestChatLi.classList.add('last-clicked');
                state.hrInteractions.currentTopHRKey = hrKey;

                await this.delay(this.operationInterval);
                await HRInteractionManager.handleHRInteraction(hrKey);
            }

            await this.setupMessageObserver(hrKey);
        },

        resetMessageState() {
            this.lastProcessedMessage = null;
            this.processingMessage = false;
        },

        async setupMessageObserver(hrKey) {
            const chatContainer = await this.waitForElement('.chat-message .im-list');
            if (!chatContainer) return;

            this.messageObserver = new MutationObserver(async (mutations) => {
                let hasNewFriendMessage = false;
                for (const mutation of mutations) {
                    if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                        hasNewFriendMessage = Array.from(mutation.addedNodes).some(node =>
                            node.classList?.contains('item-friend')
                        );
                        if (hasNewFriendMessage) break;
                    }
                }

                if (hasNewFriendMessage) {
                    await this.handleNewMessage(hrKey);
                }
            });

            this.messageObserver.observe(chatContainer, { childList: true, subtree: true });
        },

        async handleNewMessage(hrKey) {
            if (!state.isRunning) return;
            if (this.processingMessage) return;

            this.processingMessage = true;

            try {
                await this.delay(this.operationInterval);

                const lastMessage = await this.getLastFriendMessageText();
                if (!lastMessage) return;

                const cleanedMessage = this.cleanMessage(lastMessage);
                const shouldSendResumeOnly = cleanedMessage.includes('简历');

                if (cleanedMessage === this.lastProcessedMessage) return;

                this.lastProcessedMessage = cleanedMessage;
                this.log(`对方: ${lastMessage}`);

                await this.delay(CONFIG.DELAYS.MEDIUM_SHORT);
                const updatedMessage = await this.getLastFriendMessageText();
                if (updatedMessage && this.cleanMessage(updatedMessage) !== cleanedMessage) {
                    await this.handleNewMessage(hrKey);
                    return;
                }

                const autoSendResume = JSON.parse(localStorage.getItem('useAutoSendResume') || 'true');
                const autoReplyEnabled = JSON.parse(localStorage.getItem('autoReply') || 'true');

                if (shouldSendResumeOnly && autoSendResume) {
                    this.log('对方提到"简历",正在发送简历');
                    const sent = await HRInteractionManager.sendResume();
                    if (sent) {
                        state.hrInteractions.sentResumeHRs.add(hrKey);
                        StatePersistence.saveState();
                        this.log(`已向 ${hrKey} 发送简历`);
                    }
                } else if (autoReplyEnabled) {
                    await HRInteractionManager.handleHRInteraction(hrKey);
                }

                await this.delay(CONFIG.DELAYS.MEDIUM_SHORT);
                const postReplyMessage = await this.getLastFriendMessageText();
            } catch (error) {
                this.log(`处理消息出错: ${error.message}`);
            } finally {
                this.processingMessage = false;
            }
        },

        cleanMessage(message) {
            if (!message) return '';

            let clean = message.replace(/<[^>]*>/g, '');
            clean = clean.trim().replace(/\s+/g, ' ').replace(/[\u200B-\u200D\uFEFF]/g, '');
            return clean;
        },

        getLatestChatLi() {
            return document.querySelector('li[role="listitem"][class]:has(.friend-content-warp)');
        },

        async aiReply() {
            if (!state.isRunning) return;
            try {
                const autoReplyEnabled = JSON.parse(localStorage.getItem('autoReply') || 'true');
                if (!autoReplyEnabled) {
                    return false;
                }

                if (!state.ai.useAiReply) {
                    return false;
                }

                const lastMessage = await this.getLastFriendMessageText();
                if (!lastMessage) return false;

                const today = new Date().toISOString().split('T')[0];
                if (state.ai.lastAiDate !== today) {
                    state.ai.replyCount = 0;
                    state.ai.lastAiDate = today;
                    StatePersistence.saveState();
                }

                const maxReplies = state.user.isPremiumUser ? 25 : 10;
                if (state.ai.replyCount >= maxReplies) {
                    this.log(`今天AI回复次数已达上限,充值获取更多`);
                    return false;
                }

                const aiReplyText = await this.requestAi(lastMessage);
                if (!aiReplyText) return false;

                this.log(`AI回复: ${aiReplyText.slice(0, 30)}...`);
                state.ai.replyCount++;
                StatePersistence.saveState();

                const inputBox = await this.waitForElement('#chat-input');
                if (!inputBox) return false;

                inputBox.textContent = '';
                inputBox.focus();
                document.execCommand('insertText', false, aiReplyText);
                await this.delay(this.operationInterval / 10);

                const sendButton = document.querySelector('.btn-send');
                if (sendButton) {
                    await this.simulateClick(sendButton);
                } else {
                    const enterKeyEvent = new KeyboardEvent('keydown', {
                        key: 'Enter', keyCode: 13, code: 'Enter', which: 13, bubbles: true
                    });
                    inputBox.dispatchEvent(enterKeyEvent);
                }

                return true;
            } catch (error) {
                this.log(`AI回复出错: ${error.message}`);
                return false;
            }
        },

        async requestAi(message) {
            const authToken = (function () {
                const c = [0x73, 0x64, 0x56, 0x45, 0x44, 0x41, 0x42, 0x6a, 0x5a, 0x65, 0x49, 0x6b, 0x77,
                    0x58, 0x4e, 0x42, 0x46, 0x4e, 0x42, 0x73, 0x3a, 0x43, 0x71, 0x4d, 0x58, 0x6a,
                    0x71, 0x65, 0x50, 0x56, 0x43, 0x4a, 0x62, 0x55, 0x59, 0x4a, 0x50, 0x63, 0x69, 0x70, 0x4a
                ];
                return c.map(d => String.fromCharCode(d)).join('');
            })();

            const apiUrl = (function () {
                const e = '68747470733a2f2f737061726b2d6170692d6f70656e2e78662d79756e2e636f6d2f76312f636861742f636f6d706c6574696f6e73';
                return e.replace(/../g, f => String.fromCharCode(parseInt(f, 16)));
            })();

            const requestBody = {
                model: 'lite',
                messages: [
                    { role: 'system', content: localStorage.getItem('aiRole') || '你是有经验的求职者,你会用口语化的表达(如“行”、“呃”)和语气词(如“啊”、“吗”)使对话自然。你回复对方很肯定且言简意赅,不会发送段落和长句子。' },
                    { role: 'user', content: message }
                ],
                temperature: 0.9, top_p: 0.8, max_tokens: 512
            };

            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: 'POST', url: apiUrl,
                    headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + authToken },
                    data: JSON.stringify(requestBody),
                    onload: (response) => {
                        try {
                            const result = JSON.parse(response.responseText);
                            if (result.code !== 0) throw new Error('API错误: ' + result.message + '(Code: ' + result.code + ')');
                            resolve(result.choices[0].message.content.trim());
                        } catch (error) {
                            reject(new Error('响应解析失败: ' + error.message + '\n原始响应: ' + response.responseText));
                        }
                    },
                    onerror: (error) => reject(new Error('网络请求失败: ' + error))
                });
            });
        },

        async getLastFriendMessageText() {
            try {
                const chatContainer = document.querySelector('.chat-message .im-list');
                if (!chatContainer) return null;

                const friendMessages = Array.from(chatContainer.querySelectorAll('li.message-item.item-friend'));
                if (friendMessages.length === 0) return null;

                const lastMessageEl = friendMessages[friendMessages.length - 1];
                const textEl = lastMessageEl.querySelector('.text span');
                return textEl?.textContent?.trim() || null;
            } catch (error) {
                this.log(`获取消息出错: ${error.message}`);
                return null;
            }
        },

        async simulateClick(element) {
            if (!element) return;

            const rect = element.getBoundingClientRect();
            const x = rect.left + rect.width / 2;
            const y = rect.top + rect.height / 2;

            const dispatchMouseEvent = (type, options = {}) => {
                const event = new MouseEvent(type, {
                    bubbles: true, cancelable: true, view: document.defaultView, clientX: x, clientY: y, ...options
                });
                element.dispatchEvent(event);
            };

            dispatchMouseEvent('mouseover'); await this.delay(CONFIG.DELAYS.SHORT);
            dispatchMouseEvent('mousemove'); await this.delay(CONFIG.DELAYS.SHORT);
            dispatchMouseEvent('mousedown', { button: 0 }); await this.delay(CONFIG.DELAYS.SHORT);
            dispatchMouseEvent('mouseup', { button: 0 }); await this.delay(CONFIG.DELAYS.SHORT);
            dispatchMouseEvent('click', { button: 0 });
        },

        async waitForElement(selectorOrFunction, timeout = 5000) {
            return new Promise((resolve) => {
                let element;
                if (typeof selectorOrFunction === 'function') element = selectorOrFunction();
                else element = document.querySelector(selectorOrFunction);

                if (element) return resolve(element);

                const timeoutId = setTimeout(() => { observer.disconnect(); resolve(null); }, timeout);
                const observer = new MutationObserver(() => {
                    if (typeof selectorOrFunction === 'function') element = selectorOrFunction();
                    else element = document.querySelector(selectorOrFunction);
                    if (element) { clearTimeout(timeoutId); observer.disconnect(); resolve(element); }
                });
                observer.observe(document.body, { childList: true, subtree: true });
            });
        },

        // 智能等待策略函数
        getContextMultiplier(context) {
            // 根据操作类型和上下文动态调整等待时间
            const multipliers = {
                'resume_load': 1.5,  // 简历加载需要更长时间
                'dict_load': 1.0,
                'click': 0.8,
                'selection': 0.8,
                'default': 1.0
            };
            return multipliers[context] || multipliers['default'];
        },

        // 智能延迟函数
        async smartDelay(baseTime, context = 'default') {
            const multiplier = this.getContextMultiplier(context);
            const adjustedTime = baseTime * multiplier;
            return this.delay(adjustedTime);
        },

        // 基础延迟函数
        async delay(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
        },

        /**
         * Extract two-character keywords from text
         * @param {string} text - The text to extract keywords from
         * @returns {Array} Array of two-character keywords
         */
        extractTwoCharKeywords(text) {
            const keywords = [];
            const cleanedText = text.replace(/[\s,,.。::;;""''\[\]\(\)\{\}]/g, '');

            for (let i = 0; i < cleanedText.length - 1; i++) {
                keywords.push(cleanedText.substring(i, i + 2));
            }

            return keywords;
        },

        resetCycle() {
            toggleProcess();
            this.log('所有岗位沟通完成,恭喜您即将找到理想工作!');
            state.currentIndex = 0;
            state.operation.lastMessageTime = 0;
        },

        log(message) {
            const logEntry = `[${new Date().toLocaleTimeString()}] ${message}`;
            const logPanel = document.querySelector('#pro-log');
            if (logPanel) {
                const logItem = document.createElement('div');
                logItem.className = 'log-item';
                logItem.textContent = logEntry;
                logPanel.appendChild(logItem);
                logPanel.scrollTop = logPanel.scrollHeight;
            }
        }
    };

    function toggleProcess() {
        state.isRunning = !state.isRunning;

        if (state.isRunning) {
            // 获取职位名包含与工作地包含关键词
            state.includeKeywords = elements.includeInput.value.trim().toLowerCase().split(',').filter(keyword => keyword.trim() !== '');
            state.locationKeywords = (elements.locationInput?.value || '').trim().toLowerCase().split(',').filter(keyword => keyword.trim() !== '');

            elements.controlBtn.textContent = '停止海投';
            elements.controlBtn.style.background = `linear-gradient(45deg, ${CONFIG.COLORS.SECONDARY}, #f44336)`;

            const startTime = new Date();
            Core.log(`开始自动海投,时间:${startTime.toLocaleTimeString()}`);
            Core.log(`筛选条件:职位名包含【${state.includeKeywords.join('、') || '无'}】,工作地包含【${state.locationKeywords.join('、') || '无'}】`);

            Core.startProcessing();
        } else {
            elements.controlBtn.textContent = '启动海投';
            elements.controlBtn.style.background = `linear-gradient(45deg, ${CONFIG.COLORS.PRIMARY}, #4db6ac)`;

            state.isRunning = false;

            const stopTime = new Date();
            Core.log(`停止自动海投,时间:${stopTime.toLocaleTimeString()}`);
            Core.log(`本次共沟通 ${state.currentIndex} 个岗位`);

            state.currentIndex = 0;
        }
    }

    function toggleChatProcess() {
        state.isRunning = !state.isRunning;

        if (state.isRunning) {
            elements.controlBtn.textContent = '停止智能聊天';
            elements.controlBtn.style.background = `linear-gradient(45deg, ${CONFIG.COLORS.SECONDARY}, #f44336)`;

            const startTime = new Date();
            Core.log(`开始智能聊天,时间:${startTime.toLocaleTimeString()}`);

            Core.startProcessing();
        } else {
            elements.controlBtn.textContent = '开始智能聊天';
            elements.controlBtn.style.background = `linear-gradient(45deg, ${CONFIG.COLORS.PRIMARY}, #4db6ac)`;

            // 停止处理
            state.isRunning = false;

            // 断开消息监听
            if (Core.messageObserver) {
                Core.messageObserver.disconnect();
                Core.messageObserver = null;
            }

            const stopTime = new Date();
            Core.log(`停止智能聊天,时间:${stopTime.toLocaleTimeString()}`);
        }
    }

    function showCustomAlert(message) {
        const overlay = document.createElement('div');
        overlay.id = 'custom-alert-overlay';
        overlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.5);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 9999;
        backdrop-filter: blur(3px);
        animation: fadeIn 0.3s ease-out;
    `;

        const dialog = document.createElement('div');
        dialog.id = 'custom-alert-dialog';
        dialog.style.cssText = `
        background: white;
        border-radius: 16px;
        box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
        width: 90%;
        max-width: 400px;
        overflow: hidden;
        transform: scale(0.95);
        animation: scaleIn 0.3s ease-out forwards;
    `;

        const header = document.createElement('div');
        header.style.cssText = `
        padding: 16px 24px;
        background: ${CONFIG.COLORS.PRIMARY};
        color: white;
        font-size: 18px;
        font-weight: 500;
        display: flex;
        justify-content: space-between;
        align-items: center;
    `;
        header.innerHTML = `<span>BOSS海投助手</span><i class="fa fa-info-circle ml-2"></i>`;

        const content = document.createElement('div');
        content.style.cssText = `
        padding: 24px;
        font-size: 16px;
        line-height: 1.8;
        color: #333;
    `;
        content.innerHTML = message.replace(/\n/g, '<br>');

        const footer = document.createElement('div');
        footer.style.cssText = `
        padding: 12px 24px;
        display: flex;
        justify-content: center;
        border-top: 1px solid #eee;
    `;

        const confirmBtn = document.createElement('button');
        confirmBtn.style.cssText = `
        background: ${CONFIG.COLORS.PRIMARY};
        color: white;
        border: none;
        border-radius: 8px;
        padding: 10px 24px;
        font-size: 16px;
        cursor: pointer;
        transition: all 0.3s;
        box-shadow: 0 4px 12px rgba(33, 150, 243, 0.4);
    `;
        confirmBtn.textContent = '确定';

        confirmBtn.addEventListener('click', () => {
            overlay.remove();
        });

        confirmBtn.addEventListener('mouseenter', () => {
            confirmBtn.style.transform = 'translateY(-2px)';
            confirmBtn.style.boxShadow = '0 6px 16px rgba(33, 150, 243, 0.5)';
        });

        confirmBtn.addEventListener('mouseleave', () => {
            confirmBtn.style.transform = 'translateY(0)';
            confirmBtn.style.boxShadow = '0 4px 12px rgba(33, 150, 243, 0.4)';
        });

        footer.appendChild(confirmBtn);

        dialog.appendChild(header);
        dialog.appendChild(content);
        dialog.appendChild(footer);

        overlay.appendChild(dialog);

        document.body.appendChild(overlay);

        const style = document.createElement('style');
        style.textContent = `
        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }

        @keyframes scaleIn {
            from {
                transform: scale(0.95);
                opacity: 0;
            }
            to {
                transform: scale(1);
                opacity: 1;
            }
        }
    `;
        document.head.appendChild(style);
    }

    function showConfirmDialog(message, confirmCallback, cancelCallback) {
        const overlay = document.createElement('div');
        overlay.id = 'custom-confirm-overlay';
        overlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.5);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 9999;
        backdrop-filter: blur(3px);
        animation: fadeIn 0.3s ease-out;
    `;

        const dialog = document.createElement('div');
        dialog.id = 'custom-confirm-dialog';
        dialog.style.cssText = `
        background: white;
        border-radius: 16px;
        box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
        width: 90%;
        max-width: 400px;
        overflow: hidden;
        transform: scale(0.95);
        animation: scaleIn 0.3s ease-out forwards;
    `;

        const header = document.createElement('div');
        header.style.cssText = `
        padding: 16px 24px;
        background: ${CONFIG.COLORS.PRIMARY};
        color: white;
        font-size: 18px;
        font-weight: 500;
        display: flex;
        justify-content: space-between;
        align-items: center;
    `;
        header.innerHTML = `<span>BOSS海投助手</span><i class="fa fa-question-circle ml-2"></i>`;

        const content = document.createElement('div');
        content.style.cssText = `
        padding: 24px;
        font-size: 16px;
        line-height: 1.8;
        color: #333;
    `;
        content.textContent = message;

        const buttonArea = document.createElement('div');
        buttonArea.style.cssText = `
        padding: 12px 24px;
        display: flex;
        justify-content: space-around;
        border-top: 1px solid #eee;
    `;

        const confirmBtn = document.createElement('button');
        confirmBtn.style.cssText = `
        background: ${CONFIG.COLORS.PRIMARY};
        color: white;
        border: none;
        border-radius: 8px;
        padding: 10px 24px;
        font-size: 16px;
        cursor: pointer;
        transition: all 0.3s;
        box-shadow: 0 4px 12px rgba(33, 150, 243, 0.4);
    `;
        confirmBtn.textContent = '确认';

        confirmBtn.addEventListener('click', () => {
            if (typeof confirmCallback === 'function') {
                confirmCallback();
            }
            overlay.remove();
        });

        const cancelBtn = document.createElement('button');
        cancelBtn.style.cssText = `
        background: #f0f0f0;
        color: #666;
        border: none;
        border-radius: 8px;
        padding: 10px 24px;
        font-size: 16px;
        cursor: pointer;
        transition: all 0.3s;
    `;
        cancelBtn.textContent = '取消';

        cancelBtn.addEventListener('click', () => {
            if (typeof cancelCallback === 'function') {
                cancelCallback();
            }
            overlay.remove();
        });

        buttonArea.appendChild(cancelBtn);
        buttonArea.appendChild(confirmBtn);

        dialog.appendChild(header);
        dialog.appendChild(content);
        dialog.appendChild(buttonArea);

        overlay.appendChild(dialog);

        document.body.appendChild(overlay);

        const style = document.createElement('style');
        style.textContent = `
        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }

        @keyframes scaleIn {
            from {
                transform: scale(0.95);
                opacity: 0;
            }
            to {
                transform: scale(1);
                opacity: 1;
            }
        }
    `;
        document.head.appendChild(style);
    }

    function showProgress(message, progress) {
        let progressContainer = document.getElementById('progress-container');
        let progressBar = document.getElementById('progress-bar');
        let progressText = document.getElementById('progress-text');

        if (!progressContainer) {
            progressContainer = document.createElement('div');
            progressContainer.id = 'progress-container';
            progressContainer.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: white;
            border-radius: 12px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            padding: 24px;
            width: 90%;
            max-width: 400px;
            z-index: 99999;
            display: flex;
            flex-direction: column;
            gap: 16px;
        `;

            progressText = document.createElement('div');
            progressText.id = 'progress-text';
            progressText.style.cssText = `
            font-size: 16px;
            color: #333;
            text-align: center;
        `;

            const progressBackground = document.createElement('div');
            progressBackground.style.cssText = `
            height: 12px;
            background: #f0f0f0;
            border-radius: 6px;
            overflow: hidden;
        `;

            progressBar = document.createElement('div');
            progressBar.id = 'progress-bar';
            progressBar.style.cssText = `
            height: 100%;
            background: linear-gradient(90deg, ${CONFIG.COLORS.PRIMARY}, #4db6ac);
            border-radius: 6px;
            transition: width 0.3s ease;
            width: 0%;
        `;

            progressBackground.appendChild(progressBar);
            progressContainer.appendChild(progressText);
            progressContainer.appendChild(progressBackground);

            document.body.appendChild(progressContainer);
        }

        progressText.textContent = message;
        progressBar.style.width = `${progress}%`;

        if (progress >= 100) {
            setTimeout(() => {
                if (progressContainer && progressContainer.parentNode) {
                    progressContainer.parentNode.removeChild(progressContainer);
                }
            }, 1000);
        }
    }

    const letter = {
        showLetterToUser: function () {
            const COLORS = {
                primary: '#4285f4',
                primaryDark: '#1967d2',
                accent: '#e8f0fe',
                text: '#333',
                textLight: '#666',
                background: '#f8f9fa'
            };

            const overlay = document.createElement('div');
            overlay.id = 'letter-overlay';
            overlay.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.7);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 9999;
            backdrop-filter: blur(5px);
            animation: fadeIn 0.3s ease-out;
        `;

            const envelopeContainer = document.createElement('div');
            envelopeContainer.id = 'envelope-container';
            envelopeContainer.style.cssText = `
            position: relative;
            width: 90%;
            max-width: 650px;
            height: 400px;
            perspective: 1000px;
        `;

            const envelope = document.createElement('div');
            envelope.id = 'envelope';
            envelope.style.cssText = `
            position: absolute;
            width: 100%;
            height: 100%;
            transform-style: preserve-3d;
            transition: transform 0.6s ease;
        `;

            const envelopeBack = document.createElement('div');
            envelopeBack.id = 'envelope-back';
            envelopeBack.style.cssText = `
            position: absolute;
            width: 100%;
            height: 100%;
            background: ${COLORS.background};
            border-radius: 10px;
            box-shadow: 0 15px 35px rgba(0,0,0,0.2);
            backface-visibility: hidden;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            padding: 30px;
            cursor: pointer;
            transition: all 0.3s;
        `;
            envelopeBack.innerHTML = `
            <div style="font-size:clamp(1.5rem, 3vw, 1.8rem);font-weight:600;color:${COLORS.primary};margin-bottom:10px;">
                <i class="fa fa-envelope-o mr-2"></i>致海投用户的一封信
            </div>
            <div style="font-size:clamp(1rem, 2vw, 1.1rem);color:${COLORS.textLight};text-align:center;">
                点击开启高效求职之旅
            </div>
            <div style="position:absolute;bottom:20px;font-size:0.85rem;color:#999;">
                © 2025 BOSS海投助手 | Yangshengzhou 版权所有
            </div>
        `;

            envelopeBack.addEventListener('click', () => {
                envelope.style.transform = 'rotateY(180deg)';
                setTimeout(() => {
                    const content = document.getElementById('letter-content');
                    if (content) {
                        content.style.display = 'block';
                        content.style.animation = 'fadeInUp 0.5s ease-out forwards';
                    }
                }, 300);
            });

            const envelopeFront = document.createElement('div');
            envelopeFront.id = 'envelope-front';
            envelopeFront.style.cssText = `
            position: absolute;
            width: 100%;
            height: 100%;
            background: #fff;
            border-radius: 10px;
            box-shadow: 0 15px 35px rgba(0,0,0,0.2);
            transform: rotateY(180deg);
            backface-visibility: hidden;
            display: flex;
            flex-direction: column;
        `;

            const titleBar = document.createElement('div');
            titleBar.style.cssText = `
            padding: 20px 30px;
            background: linear-gradient(135deg, ${COLORS.primary}, ${COLORS.primaryDark});
            color: white;
            font-size: clamp(1.2rem, 2.5vw, 1.4rem);
            font-weight: 600;
            border-radius: 10px 10px 0 0;
            display: flex;
            align-items: center;
        `;
            titleBar.innerHTML = `<i class="fa fa-envelope-open-o mr-2"></i>致海投助手用户:`;

            const letterContent = document.createElement('div');
            letterContent.id = 'letter-content';
            letterContent.style.cssText = `
            flex: 1;
            padding: 25px 30px;
            overflow-y: auto;
            font-size: clamp(0.95rem, 2vw, 1.05rem);
            line-height: 1.8;
            color: ${COLORS.text};
            background: url('https://picsum.photos/id/1068/1000/1000') center / cover no-repeat;
            background-blend-mode: overlay;
            background-color: rgba(255,255,255,0.95);
            display: none;
        `;
            letterContent.innerHTML = `
            <div style="margin-bottom:20px;">
                <p>你好,未来的成功人士:</p>
                <p class="mt-2">&emsp;&emsp;展信如晤。</p>
                <p class="mt-3">
                    &emsp;&emsp;我是Yangshengzhou,我曾经和你一样在求职路上反复碰壁。
                    简历石沉大海、面试邀约寥寥、沟通效率低下...于是我做了这个小工具。
                </p>
                <p class="mt-3">
                    &emsp;&emsp;现在,我将它分享给你,希望能够帮到你:
                </p>
                <ul class="mt-3 ml-6 list-disc" style="text-indent:0;">
                    <li><strong>&emsp;&emsp;自动沟通页面岗位</strong>,一键打招呼</li>
                    <li><strong>&emsp;&emsp;AI智能回复HR提问</strong>,24小时在线不错过任何机会</li>
                    <li><strong>&emsp;&emsp;个性化沟通策略</strong>,大幅提升面试邀约率</li>
                </ul>
                <p class="mt-3">
                    &emsp;&emsp;工具只是辅助,你的能力才是核心竞争力。
                    愿它成为你求职路上的得力助手,助你斩获Offer!
                </p>
                <p class="mt-2">
                    &emsp;&emsp;冀以尘雾之微补益山海,荧烛末光增辉日月。
                </p>
                <p class="mt-2">
                    &emsp;&emsp;如果插件对你有帮助,请给她点个 Star🌟!
                </p>
            </div>
            <div style="text-align:right;font-style:italic;color:${COLORS.textLight};text-indent:0;">
                Yangshengzhou<br>
                2025年6月于南昌
            </div>
        `;

            const buttonArea = document.createElement('div');
            buttonArea.style.cssText = `
            padding: 15px 30px;
            display: flex;
            justify-content: center;
            border-top: 1px solid #eee;
            background: ${COLORS.background};
            border-radius: 0 0 10px 10px;
        `;

            const startButton = document.createElement('button');
            startButton.style.cssText = `
            background: linear-gradient(135deg, ${COLORS.primary}, ${COLORS.primaryDark});
            color: white;
            border: none;
            border-radius: 8px;
            padding: 12px 30px;
            font-size: clamp(1rem, 2vw, 1.1rem);
            font-weight: 500;
            cursor: pointer;
            transition: all 0.3s;
            box-shadow: 0 6px 16px rgba(66, 133, 244, 0.3);
            outline: none;
            display: flex;
            align-items: center;
        `;
            startButton.innerHTML = `<i class="fa fa-rocket mr-2"></i>开始使用`;

            startButton.addEventListener('click', () => {
                envelopeContainer.style.animation = 'scaleOut 0.3s ease-in forwards';
                overlay.style.animation = 'fadeOut 0.3s ease-in forwards';
                setTimeout(() => {
                    // 移除遮罩层
                    if (overlay.parentNode === document.body) {
                        document.body.removeChild(overlay);
                    }
                    // 点完信后跳转网页
                    window.open('https://gitee.com/Yangshengzhou', '_blank');
                }, 300);
            });

            buttonArea.appendChild(startButton);
            envelopeFront.appendChild(titleBar);
            envelopeFront.appendChild(letterContent);
            envelopeFront.appendChild(buttonArea);
            envelope.appendChild(envelopeBack);
            envelope.appendChild(envelopeFront);
            envelopeContainer.appendChild(envelope);
            overlay.appendChild(envelopeContainer);
            document.body.appendChild(overlay);

            const style = document.createElement('style');
            style.textContent = `
            @keyframes fadeIn { from { opacity: 0 } to { opacity: 1 } }
            @keyframes fadeOut { from { opacity: 1 } to { opacity: 0 } }
            @keyframes scaleOut { from { transform: scale(1); opacity: 1 } to { transform: scale(.9); opacity: 0 } }
            @keyframes fadeInUp { from { opacity: 0; transform: translateY(20px) } to { opacity: 1; transform: translateY(0) } }

            #envelope-back:hover { transform: translateY(-5px); box-shadow: 0 20px 40px rgba(0,0,0,0.25); }
            #envelope-front button:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(66, 133, 244, 0.4); }
            #envelope-front button:active { transform: translateY(1px); }
            
            @media (max-width: 480px) {
                #envelope-container { height: 350px; }
                #letter-content { font-size: 0.9rem; padding: 15px; }
            }
        `;
            document.head.appendChild(style);
        }
    };

    const guide = {
        steps: [
            {
                target: 'div.city-label.active',
                content: '👋 海投前,先在BOSS<span class="highlight">筛选出岗位</span>!\n\n助手会先滚动收集界面上显示的岗位,\n随后依次进行沟通~',
                highlightColor: '#4285f4', // 主蓝色
                arrowPosition: 'bottom',
                defaultPosition: { left: '50%', top: '20%', transform: 'translateX(-50%)' }
            },
            {
                target: 'a[ka="header-jobs"]',
                content: '🚀 <span class="highlight">职位页操作流程</span>:\n\n1️⃣ 扫描职位卡片\n2️⃣ 点击"立即沟通"(需开启“自动打招呼”)\n3️⃣ 留在当前页,继续沟通下一个职位\n\n全程无需手动干预,高效投递!',
                highlightColor: '#3367d6', // 主蓝加深10%
                arrowPosition: 'bottom',
                defaultPosition: { left: '25%', top: '80px' }
            },
            {
                target: 'a[ka="header-message"]',
                content: '💬 <span class="highlight">海投建议</span>!\n\n✅ HR与您沟通,HR需要付费给平台\n因此您尽可能先自我介绍以提高效率 \n\n✅ HR查看附件简历,HR也要付费给平台\n所以尽量先发送`图片简历`给HR',
                highlightColor: '#2a56c6', // 主蓝加深15%
                arrowPosition: 'left',
                defaultPosition: { right: '150px', top: '100px' }
            },
            {
                target: 'div.logo',
                content: '🤖 <span class="highlight">您需要打开两个浏览器窗口</span>:\n\n左侧窗口自动打招呼发起沟通\n右侧发送自我介绍和图片简历\n\n您只需专注于挑选offer!',
                highlightColor: '#1a73e8', // 主蓝加深20%
                arrowPosition: 'right',
                defaultPosition: { left: '200px', top: '20px' }
            },
            {
                target: 'div.logo',
                content: '❗ <span class="highlight">特别注意</span>:\n\n1. <span class="warning">BOSS直聘每日打招呼上限为150次</span>\n2. 聊天页仅处理最上方的最新对话\n3. 打招呼后对方会显示在聊天页\n4. <span class="warning">投递操作过于频繁有封号风险!</span>',
                highlightColor: '#0d47a1', // 主蓝加深30%
                arrowPosition: 'bottom',
                defaultPosition: { left: '50px', top: '80px' }
            }
        ],
        currentStep: 0,
        guideElement: null,
        overlay: null,
        highlightElements: [],
        chatUrl: 'https://www.zhipin.com/web/geek/chat', // 聊天页面URL

        showGuideToUser() {
            // 创建遮罩层
            this.overlay = document.createElement('div');
            this.overlay.id = 'guide-overlay';
            this.overlay.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            backdrop-filter: blur(2px);
            z-index: 99997;
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.3s ease;
        `;
            document.body.appendChild(this.overlay);

            // 创建引导卡片
            this.guideElement = document.createElement('div');
            this.guideElement.id = 'guide-tooltip';
            this.guideElement.style.cssText = `
            position: fixed;
            z-index: 99999;
            width: 320px;
            background: white;
            border-radius: 12px;
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            overflow: hidden;
            opacity: 0;
            transform: translateY(10px);
            transition: opacity 0.3s ease, transform 0.3s ease;
        `;
            document.body.appendChild(this.guideElement);

            // 显示遮罩层
            setTimeout(() => {
                this.overlay.style.opacity = '1';

                // 延迟显示第一步,增强视觉层次感
                setTimeout(() => {
                    this.showStep(0);
                }, 300);
            }, 100);
        },

        showStep(stepIndex) {
            const step = this.steps[stepIndex];
            if (!step) return;

            this.clearHighlights();
            const target = document.querySelector(step.target);

            if (target) {
                // 创建高亮区域
                const rect = target.getBoundingClientRect();
                const highlight = document.createElement('div');
                highlight.className = 'guide-highlight';
                highlight.style.cssText = `
                position: fixed;
                top: ${rect.top}px;
                left: ${rect.left}px;
                width: ${rect.width}px;
                height: ${rect.height}px;
                background: ${step.highlightColor || '#4285f4'};
                opacity: 0.2;
                border-radius: 4px;
                z-index: 99998;
                box-shadow: 0 0 0 4px ${step.highlightColor || '#4285f4'};
                animation: guide-pulse 2s infinite;
            `;
                document.body.appendChild(highlight);
                this.highlightElements.push(highlight);

                // 计算提示框位置(基于目标元素)
                this.setGuidePositionFromTarget(step, rect);
            } else {
                console.warn('引导目标元素未找到,使用默认位置:', step.target);
                // 使用默认位置显示提示框
                this.setGuidePositionFromDefault(step);
            }

            // 设置引导提示框内容
            let buttonsHtml = '';

            // 根据是否为最后一步生成不同的按钮
            if (stepIndex === this.steps.length - 1) {
                // 最后一步:只显示"完成"按钮,居中对齐
                buttonsHtml = `
                <div class="guide-buttons" style="display: flex; justify-content: center; padding: 16px; border-top: 1px solid #f0f0f0; background: #f9fafb;">
                    <button id="guide-finish-btn" style="padding: 8px 32px; background: ${step.highlightColor || '#4285f4'}; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);">
                        完成
                    </button>
                </div>
            `;
            } else {
                // 非最后一步:显示"下一步"和"跳过"按钮
                buttonsHtml = `
                <div class="guide-buttons" style="display: flex; justify-content: flex-end; padding: 16px; border-top: 1px solid #f0f0f0; background: #f9fafb;">
                    <button id="guide-skip-btn" style="padding: 8px 16px; background: white; color: #4b5563; border: 1px solid #e5e7eb; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.2s ease;">跳过</button>
                    <button id="guide-next-btn" style="padding: 8px 16px; background: ${step.highlightColor || '#4285f4'}; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 500; margin-left: 8px; transition: all 0.2s ease; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);">下一步</button>
                </div>
            `;
            }

            // 使用<div>替代<pre>,支持HTML标签
            this.guideElement.innerHTML = `
            <div class="guide-header" style="padding: 16px; background: ${step.highlightColor || '#4285f4'}; color: white;">
                <div class="guide-title" style="font-size: 16px; font-weight: 600;">海投助手引导</div>
                <div class="guide-step" style="font-size: 12px; opacity: 0.8; margin-top: 2px;">步骤 ${stepIndex + 1}/${this.steps.length}</div>
            </div>
            <div class="guide-content" style="padding: 20px; font-size: 14px; line-height: 1.6;">
                <div style="white-space: pre-wrap; font-family: inherit; margin: 0;">${step.content}</div>
            </div>
            ${buttonsHtml}
        `;

            // 重新绑定按钮事件
            if (stepIndex === this.steps.length - 1) {
                // 最后一步:绑定完成按钮
                document.getElementById('guide-finish-btn').addEventListener('click', () => this.endGuide(true));
            } else {
                // 非最后一步:绑定下一步和跳过按钮
                document.getElementById('guide-next-btn').addEventListener('click', () => this.nextStep());
                document.getElementById('guide-skip-btn').addEventListener('click', () => this.endGuide());
            }

            // 添加按钮悬停效果
            if (stepIndex === this.steps.length - 1) {
                const finishBtn = document.getElementById('guide-finish-btn');
                finishBtn.addEventListener('mouseenter', () => {
                    finishBtn.style.background = this.darkenColor(step.highlightColor || '#4285f4', 15);
                    finishBtn.style.boxShadow = '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)';
                });
                finishBtn.addEventListener('mouseleave', () => {
                    finishBtn.style.background = step.highlightColor || '#4285f4';
                    finishBtn.style.boxShadow = '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)';
                });
            } else {
                const nextBtn = document.getElementById('guide-next-btn');
                const skipBtn = document.getElementById('guide-skip-btn');

                nextBtn.addEventListener('mouseenter', () => {
                    nextBtn.style.background = this.darkenColor(step.highlightColor || '#4285f4', 15);
                    nextBtn.style.boxShadow = '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)';
                });
                nextBtn.addEventListener('mouseleave', () => {
                    nextBtn.style.background = step.highlightColor || '#4285f4';
                    nextBtn.style.boxShadow = '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)';
                });

                skipBtn.addEventListener('mouseenter', () => {
                    skipBtn.style.background = '#f3f4f6';
                });
                skipBtn.addEventListener('mouseleave', () => {
                    skipBtn.style.background = 'white';
                });
            }

            // 显示提示框
            this.guideElement.style.opacity = '1';
            this.guideElement.style.transform = 'translateY(0)';
        },

        // 根据目标元素计算提示框位置
        setGuidePositionFromTarget(step, rect) {
            let left, top;
            const guideWidth = 320;
            const guideHeight = 240;

            // 根据箭头方向调整位置
            switch (step.arrowPosition) {
                case 'top':
                    left = rect.left + rect.width / 2 - guideWidth / 2;
                    top = rect.top - guideHeight - 20;
                    break;
                case 'bottom':
                    left = rect.left + rect.width / 2 - guideWidth / 2;
                    top = rect.bottom + 20;
                    break;
                case 'left':
                    left = rect.left - guideWidth - 20;
                    top = rect.top + rect.height / 2 - guideHeight / 2;
                    break;
                case 'right':
                    left = rect.right + 20;
                    top = rect.top + rect.height / 2 - guideHeight / 2;
                    break;
                default:
                    left = rect.right + 20;
                    top = rect.top;
            }

            // 确保提示框不超出屏幕
            left = Math.max(10, Math.min(left, window.innerWidth - guideWidth - 10));
            top = Math.max(10, Math.min(top, window.innerHeight - guideHeight - 10));

            // 设置位置
            this.guideElement.style.left = `${left}px`;
            this.guideElement.style.top = `${top}px`;
            this.guideElement.style.transform = 'translateY(0)';
        },

        // 使用默认位置显示提示框
        setGuidePositionFromDefault(step) {
            const position = step.defaultPosition || { left: '50%', top: '50%', transform: 'translate(-50%, -50%)' };

            // 应用默认位置样式
            Object.assign(this.guideElement.style, {
                left: position.left,
                top: position.top,
                right: position.right || 'auto',
                bottom: position.bottom || 'auto',
                transform: position.transform || 'none'
            });
        },

        nextStep() {
            // 清除当前步骤的事件监听
            const currentStep = this.steps[this.currentStep];
            if (currentStep) {
                const target = document.querySelector(currentStep.target);
                if (target) {
                    target.removeEventListener('click', this.nextStep);
                }
            }

            this.currentStep++;
            if (this.currentStep < this.steps.length) {
                // 隐藏当前提示框,显示下一步
                this.guideElement.style.opacity = '0';
                this.guideElement.style.transform = 'translateY(10px)';

                setTimeout(() => {
                    this.showStep(this.currentStep);
                }, 300);
            } else {
                this.endGuide(true); // 传递true表示引导已完成
            }
        },

        clearHighlights() {
            this.highlightElements.forEach(el => el.remove());
            this.highlightElements = [];
        },

        endGuide(isCompleted = false) {
            // 清除高亮和事件
            this.clearHighlights();

            // 淡出提示框和遮罩
            this.guideElement.style.opacity = '0';
            this.guideElement.style.transform = 'translateY(10px)';
            this.overlay.style.opacity = '0';

            // 延迟移除元素
            setTimeout(() => {
                if (this.overlay && this.overlay.parentNode) {
                    this.overlay.parentNode.removeChild(this.overlay);
                }
                if (this.guideElement && this.guideElement.parentNode) {
                    this.guideElement.parentNode.removeChild(this.guideElement);
                }

                // 当引导完成时打开聊天页面
                if (isCompleted && this.chatUrl) {
                    window.open(this.chatUrl, '_blank');
                }
            }, 300);

            // 触发引导结束事件
            document.dispatchEvent(new Event('guideEnd'));
        },

        // 辅助函数:颜色加深
        darkenColor(color, percent) {
            let R = parseInt(color.substring(1, 3), 16);
            let G = parseInt(color.substring(3, 5), 16);
            let B = parseInt(color.substring(5, 7), 16);

            R = parseInt(R * (100 - percent) / 100);
            G = parseInt(G * (100 - percent) / 100);
            B = parseInt(B * (100 - percent) / 100);

            R = (R < 255) ? R : 255;
            G = (G < 255) ? G : 255;
            B = (B < 255) ? B : 255;

            R = Math.round(R);
            G = Math.round(G);
            B = Math.round(B);

            const RR = ((R.toString(16).length === 1) ? "0" + R.toString(16) : R.toString(16));
            const GG = ((G.toString(16).length === 1) ? "0" + G.toString(16) : G.toString(16));
            const BB = ((B.toString(16).length === 1) ? "0" + B.toString(16) : B.toString(16));

            return `#${RR}${GG}${BB}`;
        }
    };

    // 添加脉冲动画样式和高亮样式
    const style = document.createElement('style');
    style.textContent = `
    @keyframes guide-pulse {
        0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(66, 133, 244, 0.4); }
        70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(66, 133, 244, 0); }
        100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(66, 133, 244, 0); }
    }
    
    .guide-content .highlight {
        font-weight: 700;
        color: #1a73e8;
    }
    
    .guide-content .warning {
        font-weight: 700;
        color: #d93025;
    }
`;
    document.head.appendChild(style);

    const STORAGE = {
        LETTER: 'letterLastShown',
        GUIDE: 'shouldShowGuide',
        AI_COUNT: 'aiReplyCount',
        AI_DATE: 'lastAiDate'
    };

    function getToday() {
        return new Date().toISOString().split('T')[0];
    }

    function init() {
        try {
            const midnight = new Date();
            midnight.setDate(midnight.getDate() + 1);
            midnight.setHours(0, 0, 0, 0);
            setTimeout(() => {
                localStorage.removeItem(STORAGE.AI_COUNT);
                localStorage.removeItem(STORAGE.AI_DATE);
                localStorage.removeItem(STORAGE.LETTER);
            }, midnight - Date.now());
            UI.init();
            document.body.style.position = 'relative';
            const today = getToday();
            if (location.pathname.includes('/jobs')) {
                if (localStorage.getItem(STORAGE.LETTER) !== today) {
                    letter.showLetterToUser();
                    localStorage.setItem(STORAGE.LETTER, today);
                } else if (localStorage.getItem(STORAGE.GUIDE) !== 'true') {
                    guide.showGuideToUser();
                    localStorage.setItem(STORAGE.GUIDE, 'true');
                    Core.delay(800)
                    window.open('https://www.zhipin.com/web/geek/notify-set?ka=notify-set', '_blank');
                }
                Core.log('欢迎使用海投助手,我将自动投递岗位!');
            } else if (location.pathname.includes('/chat')) {
                Core.log('欢迎使用海投助手,我将自动发送简历!');
            } else if (location.pathname.includes('/notify-set')) {
                Core.log('请将常用语换为自我介绍来引起HR的注意!');

                const targetSelector = 'h3.normal.title';

                const observer = new MutationObserver((mutations, obs) => {
                    const targetElement = document.querySelector(targetSelector);
                    if (targetElement) {
                        targetElement.textContent = '把常用语换为自我介绍,并设图片简历; 招呼语功能必须启用。';
                        obs.disconnect();
                    }
                });

                observer.observe(document.body, {
                    childList: true,
                    subtree: true
                });
            } else {
                Core.log('当前页面暂不支持,请移步至职位页面!');
            }
        } catch (error) {
            console.error('初始化失败:', error);
            if (UI.notify) UI.notify('初始化失败', 'error');
        }
    }

    window.addEventListener('load', init);
})();