网页定时管理器

网页定时关闭和定时跳转

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         网页定时管理器
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  网页定时关闭和定时跳转
// @author       huihuia24
// @homepage     https://github.com/huihuia24
// @source       https://github.com/huihuia24/-/tree/main
// @match        *://*/*
// @grant        GM_openInTab
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// @grant        GM_registerMenuCommand
// @run-at       document-idle
// @icon         https://github.com/huihuia24/Web-Timer-Manager/blob/28a6ac6404aa154168b731a7d632b306febdc7d2/%E7%BD%91%E9%A1%B5%E5%AE%9A%E6%97%B6%E7%AE%A1%E7%90%86%E5%99%A8.png?raw=true
// @noframes     // 禁止在iframe中执行
// ==/UserScript==
(function() {
    'use strict';
    
    // 全局单例检测:若已有实例则直接退出
    if (window.timerManagerInstance) {
        return;
    }
    window.timerManagerInstance = true;
    
    // 修复 UI 重复问题:初始化前移除已存在的管理器元素
    function cleanDuplicateUI() {
        const existingMain = document.getElementById('timer-manager');
        const existingMini = document.getElementById('timer-mini');
        const existingThemeStyle = document.getElementById('timer-theme-styles');
        
        // 移除重复的主界面、最小化界面和主题样式
        if (existingMain) existingMain.remove();
        if (existingMini) existingMini.remove();
        if (existingThemeStyle) existingThemeStyle.remove();
    }
    // 执行清理
    cleanDuplicateUI();
    
    // 加载Font Awesome
    function loadFontAwesome() {
        if (document.querySelector('link[href*="font-awesome"]')) return;
        
        const link = document.createElement('link');
        link.rel = 'stylesheet';
        link.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css';
        document.head.appendChild(link);
    }
    loadFontAwesome();
    
    // 存储管理模块
    const Storage = {
        get(key, defaultValue) {
            const value = GM_getValue(key);
            return value === undefined ? defaultValue : value;
        },
        set(key, value) {
            GM_setValue(key, value);
        },
        savePos(elementId, x, y) {
            this.set(`${elementId}_x`, x);
            this.set(`${elementId}_y`, y);
        },
        getPos(elementId, defaultX, defaultY) {
            return {
                x: this.get(`${elementId}_x`, defaultX),
                y: this.get(`${elementId}_y`, defaultY)
            };
        },
        saveTasks(tasks) {
            this.set('timer_tasks', JSON.stringify(tasks));
        },
        getTasks() {
            try {
                return JSON.parse(this.get('timer_tasks', '[]'));
            } catch (e) {
                return [];
            }
        },
        saveMultiState(state) {
            this.set('multi_state', JSON.stringify(state));
        },
        getMultiState() {
            try {
                return JSON.parse(this.get('multi_state', '{"running":false,"index":0,"remaining":0}'));
            } catch (e) {
                return { running: false, index: 0, remaining: 0 };
            }
        },
        getTheme() {
            return this.get('timer_theme', 'light'); // light/dark
        },
        setTheme(theme) {
            this.set('timer_theme', theme);
        }
    };
    
    // 基础样式定义(核心修改:提升层级并隔离层叠上下文)
    GM_addStyle(`
        #timer-manager {
            position: fixed;
            width: 380px;
            max-width: calc(100% - 40px);
            border-radius: 10px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.15);
            z-index: 9999999; /* 超高层级确保置顶 */
            padding: 15px;
            display: none;
            transition: all 0.3s ease;
            box-sizing: border-box;
            will-change: transform, z-index; /* 强制创建独立层叠上下文 */
            transform: translateZ(0); /* 硬件加速渲染,避免被网页遮挡 */
        }
        
        #timer-mini {
            position: fixed;
            border-radius: 8px;
            padding: 8px 15px;
            font-size: 20px;
            font-weight: bold;
            box-shadow: 0 3px 12px rgba(0,0,0,0.2);
            z-index: 9999999; /* 超高层级确保置顶 */
            cursor: pointer;
            user-select: none;
            transition: all 0.2s ease;
            white-space: nowrap;
            display: flex;
            align-items: center;
            gap: 8px;
            will-change: transform, z-index; /* 强制创建独立层叠上下文 */
            transform: translateZ(0); /* 硬件加速渲染 */
        }
        
        .timer-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 1px solid;
        }
        
        .timer-title {
            font-size: 18px;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .timer-controls {
            display: flex;
            gap: 8px;
        }
        
        .timer-btn {
            cursor: pointer;
            width: 28px;
            height: 28px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
            font-size: 16px;
            transition: all 0.2s;
        }
        
        .timer-btn:hover {
            transform: scale(1.1);
        }
        
        .timer-tabs {
            display: flex;
            margin-bottom: 15px;
            border-radius: 6px;
            overflow: hidden;
        }
        
        .timer-tab {
            flex: 1;
            padding: 10px 0;
            text-align: center;
            cursor: pointer;
            transition: all 0.3s;
            font-weight: 500;
            font-size: 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
        }
        
        .timer-tab.active {
            font-weight: 600;
        }
        
        .timer-tab-content {
            display: none;
            animation: fadeIn 0.3s ease;
        }
        
        .timer-tab-content.active {
            display: block;
        }
        
        .form-group {
            margin-bottom: 15px;
        }
        
        .form-label {
            display: block;
            margin-bottom: 6px;
            font-weight: 500;
            font-size: 14px;
            display: flex;
            align-items: center;
            gap: 6px;
        }
        
        .form-control {
            width: 100%;
            padding: 9px 12px;
            border: 1px solid;
            border-radius: 6px;
            box-sizing: border-box;
            font-size: 14px;
            transition: border-color 0.2s, box-shadow 0.2s;
            pointer-events: auto !important;
            user-select: text !important;
        }
        
        .form-control:focus {
            outline: none;
            box-shadow: 0 0 0 3px;
        }
        
        .time-inputs {
            display: flex;
            gap: 8px;
        }
        
        .time-input-group {
            flex: 1;
        }
        
        .time-label {
            display: block;
            margin-bottom: 4px;
            font-size: 13px;
            text-align: center;
        }
        
        .time-input {
            width: 100%;
            padding: 10px 5px;
            border: 1px solid;
            border-radius: 6px;
            font-size: 22px;
            text-align: center;
            transition: border-color 0.2s;
            -moz-appearance: textfield;
            pointer-events: auto !important;
            user-select: text !important;
            box-sizing: border-box;
        }
        
        .time-input::-webkit-outer-spin-button,
        .time-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        
        .time-input:focus {
            outline: none;
        }
        
        .btn {
            padding: 8px 16px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            transition: all 0.2s;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
        }
        
        .btn-primary:hover, .btn-secondary:hover {
            transform: translateY(-1px);
        }
        
        .task-list {
            margin: 15px 0;
            max-height: 200px;
            overflow-y: auto;
            border: 1px solid;
            border-radius: 6px;
        }
        
        .task-item {
            display: flex;
            align-items: center;
            padding: 10px 12px;
            border-bottom: 1px solid;
            flex-wrap: nowrap;
        }
        
        .task-item:last-child {
            border-bottom: none;
        }
        
        .task-item:hover {
            transition: background-color 0.2s;
        }
        
        .task-url {
            flex: 1;
            word-break: break-all;
            font-size: 13px;
            min-width: 0;
            display: flex;
            align-items: center;
            gap: 6px;
        }
        
        .task-time {
            margin: 0 8px;
            font-size: 14px;
            min-width: 80px;
            text-align: center;
            display: flex;
            align-items: center;
            gap: 4px;
        }
        
        .task-remove {
            cursor: pointer;
            width: 24px;
            height: 24px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
            flex-shrink: 0;
            transition: all 0.2s;
        }
        
        .task-remove:hover {
            transform: scale(1.1);
        }
        
        .actions {
            display: flex;
            gap: 10px;
            margin-top: 10px;
            flex-wrap: wrap;
        }
        
        .status {
            margin-top: 12px;
            padding: 8px;
            border-radius: 6px;
            font-size: 13px;
            text-align: center;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
            border: 1px solid;
        }
        
        .radio-group {
            display: flex;
            gap: 12px;
            margin-top: 6px;
            flex-wrap: wrap;
        }
        
        .radio-item {
            display: flex;
            align-items: center;
            gap: 5px;
            cursor: pointer;
            white-space: nowrap;
        }
        
        .radio-item input {
            margin: 0;
            width: 14px;
            height: 14px;
        }
        
        .checkbox-item {
            display: flex;
            align-items: center;
            gap: 6px;
            margin-top: 10px;
            cursor: pointer;
            font-size: 14px;
        }
        
        .checkbox-item input {
            width: 14px;
            height: 14px;
        }
        
        #target-url {
            margin-top: 10px;
            display: none;
        }
        .overflow-ellipsis {
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
    `);
    
    // 创建主题样式
    function createThemeStyles() {
        const style = document.createElement('style');
        style.id = 'timer-theme-styles';
        style.textContent = `
            /* 浅色主题 */
            .timer-light {
                --bg-primary: #ffffff;
                --bg-secondary: #f8f9fa;
                --bg-tertiary: #ecf0f1;
                --text-primary: #2c3e50;
                --text-secondary: #7f8c8d;
                --border-color: #ddd;
                --border-dark: #ccc;
                --accent-color: #3498db;
                --accent-hover: #2980b9;
                --accent-light: rgba(52, 152, 219, 0.1);
                --danger-color: #e74c3c;
                --danger-light: rgba(231, 76, 60, 0.1);
                --shadow: 0 4px 20px rgba(0,0,0,0.15);
            }
            /* 深色主题 */
            .timer-dark {
                --bg-primary: #1e1e1e;
                --bg-secondary: #2d2d2d;
                --bg-tertiary: #3a3a3a;
                --text-primary: #f0f0f0;
                --text-secondary: #ccc;
                --border-color: #444;
                --border-dark: #555;
                --accent-color: #3498db;
                --accent-hover: #2980b9;
                --accent-light: rgba(52, 152, 219, 0.2);
                --danger-color: #e74c3c;
                --danger-light: rgba(231, 76, 60, 0.2);
                --shadow: 0 4px 20px rgba(0,0,0,0.5);
            }
            /* 主题应用 */
            .timer-theme {
                background: var(--bg-primary);
                color: var(--text-primary);
                border-color: var(--border-color);
                box-shadow: var(--shadow);
            }
            #timer-manager.timer-theme {
                border: 1px solid var(--border-color);
            }
            #timer-mini.timer-theme {
                background: var(--bg-secondary);
                color: var(--text-primary);
            }
            .timer-header.timer-theme {
                border-bottom-color: var(--border-color);
            }
            .timer-btn.timer-theme {
                background: var(--bg-secondary);
                color: var(--text-secondary);
            }
            .timer-btn.timer-theme:hover {
                background: var(--bg-tertiary);
                color: var(--text-primary);
            }
            .timer-tabs.timer-theme {
                background: var(--bg-secondary);
            }
            .timer-tab.timer-theme {
                color: var(--text-secondary);
            }
            .timer-tab.timer-theme.active {
                background: var(--accent-color);
                color: white;
            }
            .form-label.timer-theme {
                color: var(--text-primary);
            }
            .form-control.timer-theme {
                background: var(--bg-secondary);
                color: var(--text-primary);
                border-color: var(--border-color);
            }
            .form-control.timer-theme:focus {
                border-color: var(--accent-color);
                box-shadow: 0 0 0 3px var(--accent-light);
            }
            .time-label.timer-theme {
                color: var(--text-secondary);
            }
            .time-input.timer-theme {
                background: var(--bg-secondary);
                color: var(--text-primary);
                border-color: var(--border-color);
            }
            .time-input.timer-theme:focus {
                border-color: var(--accent-color);
            }
            .btn-primary.timer-theme {
                background: var(--accent-color);
                color: white;
            }
            .btn-primary.timer-theme:hover {
                background: var(--accent-hover);
            }
            .btn-secondary.timer-theme {
                background: var(--bg-secondary);
                color: var(--text-primary);
                border: 1px solid var(--border-color);
            }
            .btn-secondary.timer-theme:hover {
                background: var(--bg-tertiary);
            }
            .task-list.timer-theme {
                background: var(--bg-secondary);
                border-color: var(--border-color);
            }
            .task-item.timer-theme {
                border-bottom-color: var(--border-color);
            }
            .task-item.timer-theme:hover {
                background: var(--bg-tertiary);
            }
            .task-url.timer-theme {
                color: var(--text-primary);
            }
            .task-time.timer-theme {
                color: var(--text-secondary);
            }
            .task-remove.timer-theme {
                color: var(--danger-color);
                background: var(--bg-secondary);
            }
            .task-remove.timer-theme:hover {
                background: var(--danger-light);
            }
            .status.timer-theme {
                background: var(--bg-secondary);
                color: var(--text-secondary);
                border-color: var(--border-color);
            }
            .radio-item.timer-theme input,
            .checkbox-item.timer-theme input {
                accent-color: var(--accent-color);
            }
        `;
        document.head.appendChild(style);
    }
    createThemeStyles();
    
    // 创建UI元素
    function createUI(theme) {
        // 主界面
        const mainUI = document.createElement('div');
        mainUI.id = 'timer-manager';
        mainUI.className = `timer-theme timer-${theme}`;
        mainUI.innerHTML = `
            <div class="timer-header timer-theme">
                <div class="timer-title timer-theme">
                    <i class="fas fa-clock"></i> 网页定时管理器
                </div>
                <div class="timer-controls">
                    <div class="timer-btn timer-theme" id="theme-toggle">
                        <i class="fas ${theme === 'light' ? 'fa-moon' : 'fa-sun'}"></i>
                    </div>
                    <div class="timer-btn timer-theme" id="minimize-btn">
                        <i class="fas fa-compress"></i>
                    </div>
                </div>
            </div>
            <div class="timer-tabs timer-theme">
                <div class="timer-tab timer-theme active" data-tab="current">
                    <i class="fas fa-window-maximize"></i> 当前网页定时
                </div>
                <div class="timer-tab timer-theme" data-tab="multi">
                    <i class="fas fa-exchange-alt"></i> 多网址定时跳转
                </div>
            </div>
            <div class="timer-contents">
                <!-- 当前网页定时 -->
                <div class="timer-tab-content active" id="current-tab">
                    <div class="form-group">
                        <div class="form-label timer-theme">
                            <i class="fas fa-hourglass-half"></i> 定时时长
                        </div>
                        <div class="time-inputs">
                            <div class="time-input-group">
                                <div class="time-label timer-theme">小时</div>
                                <input type="number" id="current-hours" class="time-input timer-theme" min="0" value="0">
                            </div>
                            <div class="time-input-group">
                                <div class="time-label timer-theme">分</div>
                                <input type="number" id="current-minutes" class="time-input timer-theme" min="0" max="59" value="0">
                            </div>
                            <div class="time-input-group">
                                <div class="time-label timer-theme">秒</div>
                                <input type="number" id="current-seconds" class="time-input timer-theme" min="0" max="59" value="30">
                            </div>
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="form-label timer-theme">
                            <i class="fas fa-sign-out-alt"></i> 定时结束后操作
                        </div>
                        <div class="radio-group">
                            <div class="radio-item timer-theme">
                                <input type="radio" id="action-blank" name="end-action" value="blank" checked>
                                <label for="action-blank">
                                    <i class="fas fa-file"></i> 跳转至空白页
                                </label>
                            </div>
                            <div class="radio-item timer-theme">
                                <input type="radio" id="action-url" name="end-action" value="url">
                                <label for="action-url">
                                    <i class="fas fa-link"></i> 跳转至指定网页
                                </label>
                            </div>
                        </div>
                        <input type="text" id="target-url" class="form-control timer-theme" placeholder="请输入目标网址">
                    </div>
                    <div class="actions">
                        <button class="btn btn-primary timer-theme" id="start-current">
                            <i class="fas fa-play"></i> 开始定时
                        </button>
                        <button class="btn btn-secondary timer-theme" id="stop-current">
                            <i class="fas fa-stop"></i> 停止定时
                        </button>
                    </div>
                    <div class="status timer-theme" id="current-status">
                        <i class="fas fa-info-circle"></i> 未开始定时
                    </div>
                </div>
                
                <!-- 多网址定时跳转 -->
                <div class="timer-tab-content" id="multi-tab">
                    <div class="form-group">
                        <div class="form-label timer-theme">
                            <i class="fas fa-globe"></i> 网址
                        </div>
                        <input type="text" id="multi-url" class="form-control timer-theme overflow-ellipsis" placeholder="请输入网址">
                    </div>
                    <div class="form-group">
                        <div class="form-label timer-theme">
                            <i class="fas fa-clock"></i> 停留时长(跳转后开始计时)
                        </div>
                        <div class="time-inputs">
                            <div class="time-input-group">
                                <div class="time-label timer-theme">小时</div>
                                <input type="number" id="multi-hours" class="time-input timer-theme" min="0" value="0">
                            </div>
                            <div class="time-input-group">
                                <div class="time-label timer-theme">分</div>
                                <input type="number" id="multi-minutes" class="time-input timer-theme" min="0" max="59" value="0">
                            </div>
                            <div class="time-input-group">
                                <div class="time-label timer-theme">秒</div>
                                <input type="number" id="multi-seconds" class="time-input timer-theme" min="0" max="59" value="30">
                            </div>
                        </div>
                        <div class="checkbox-item timer-theme">
                            <input type="checkbox" id="no-close" name="no-close">
                            <label for="no-close">
                                <i class="fas fa-external-link-alt"></i> 在新标签页打开(不关闭当前页)
                            </label>
                        </div>
                    </div>
                    <div class="actions">
                        <button class="btn btn-primary timer-theme" id="add-task">
                            <i class="fas fa-plus"></i> 添加到列表
                        </button>
                        <button class="btn btn-secondary timer-theme" id="clear-tasks">
                            <i class="fas fa-trash"></i> 清空列表
                        </button>
                    </div>
                    <div class="task-list timer-theme" id="task-list"></div>
                    <div class="actions">
                        <button class="btn btn-primary timer-theme" id="start-multi">
                            <i class="fas fa-play"></i> 开始执行任务
                        </button>
                        <button class="btn btn-secondary timer-theme" id="stop-multi">
                            <i class="fas fa-stop"></i> 停止执行
                        </button>
                    </div>
                    <div class="status timer-theme" id="multi-status">
                        <i class="fas fa-info-circle"></i> 未开始执行
                    </div>
                </div>
            </div>
        `;
        
        // 最小化界面
        const miniUI = document.createElement('div');
        miniUI.id = 'timer-mini';
        miniUI.className = `timer-theme timer-${theme}`;
        miniUI.innerHTML = '<i class="fas fa-hourglass"></i> <span id="mini-time">00:00:00</span>';
        
        document.body.appendChild(mainUI);
        document.body.appendChild(miniUI);
        
        // 定位UI(基于浏览器视口,不受网页布局影响)
        const mainPos = Storage.getPos('timer_manager', window.innerWidth - 410, 20);
        mainUI.style.left = `${mainPos.x}px`;
        mainUI.style.top = `${mainPos.y}px`;
        
        const miniPos = Storage.getPos('timer_mini', window.innerWidth - 180, 20);
        miniUI.style.left = `${miniPos.x}px`;
        miniUI.style.top = `${miniPos.y}px`;
        
        return { mainUI, miniUI };
    }
    
    // 定时器控制器
    class TimerController {
        constructor(ui) {
            this.ui = ui;
            this.currentTimer = null;
            this.multiTimer = null;
            this.remainingTime = 0;
            this.currentTaskIndex = -1;
            this.tasks = Storage.getTasks();
            this.isMinimized = true;
            this.isMultiRunning = false;
            this.lastUpdateTime = 0;
            this.isCurrentTimerRunning = false;
            this.miniTimeElement = document.getElementById('mini-time');
            this.currentTheme = Storage.getTheme();
            this.doubleClickDelay = 300; // 双击检测延迟
            this.lastClickTime = 0;
            
            // 恢复多任务状态
            const savedState = Storage.getMultiState();
            if (savedState.running && savedState.index >= 0 && this.tasks.length > savedState.index) {
                this.isMultiRunning = true;
                this.currentTaskIndex = savedState.index;
                this.remainingTime = savedState.remaining;
                this.startTaskTimer();
            }
            
            this.initEvents();
            this.renderTasks();
            this.fixInputFields();
        }
        
        // 切换主题
        toggleTheme() {
            const newTheme = this.currentTheme === 'light' ? 'dark' : 'light';
            
            // 更新存储的主题
            Storage.setTheme(newTheme);
            this.currentTheme = newTheme;
            
            // 更新所有主题相关元素的类
            document.querySelectorAll('.timer-theme').forEach(el => {
                el.classList.remove(`timer-${this.currentTheme === 'light' ? 'dark' : 'light'}`);
                el.classList.add(`timer-${newTheme}`);
            });
            
            // 更新主题图标
            const themeIcon = document.querySelector('#theme-toggle i');
            themeIcon.className = `fas ${newTheme === 'light' ? 'fa-moon' : 'fa-sun'}`;
        }
        
        // 修复输入框交互
        fixInputFields() {
            const inputs = document.querySelectorAll('.time-input, .form-control');
            inputs.forEach(input => {
                input.readOnly = false;
                input.disabled = false;
                input.style.pointerEvents = 'auto';
                input.style.fontSize = input.classList.contains('time-input') ? '22px' : '14px';
                
                input.addEventListener('focus', () => {
                    input.style.borderColor = 'var(--accent-color)';
                });
                
                if (input.type === 'number') {
                    input.addEventListener('input', (e) => {
                        const value = parseInt(e.target.value) || 0;
                        if (e.target.max) e.target.value = Math.min(value, parseInt(e.target.max));
                        if (e.target.min) e.target.value = Math.max(value, parseInt(e.target.min));
                    });
                }
            });
        }
        
        initEvents() {
            // 主题切换
            document.getElementById('theme-toggle').addEventListener('click', (e) => {
                e.stopPropagation();
                this.toggleTheme();
            });
            
            // 标签页切换
            document.querySelectorAll('.timer-tab').forEach(tab => {
                tab.addEventListener('click', (e) => {
                    e.stopPropagation();
                    const tabId = tab.getAttribute('data-tab');
                    
                    document.querySelectorAll('.timer-tab').forEach(t => t.classList.remove('active'));
                    document.querySelectorAll('.timer-tab-content').forEach(c => c.classList.remove('active'));
                    
                    tab.classList.add('active');
                    document.getElementById(`${tabId}-tab`).classList.add('active');
                });
            });
            
            // 结束操作选择
            const actionUrl = document.getElementById('action-url');
            const targetUrl = document.getElementById('target-url');
            
            document.getElementById('action-blank').addEventListener('change', () => {
                targetUrl.style.display = 'none';
            });
            
            actionUrl.addEventListener('change', () => {
                targetUrl.style.display = 'block';
            });
            
            // 当前网页定时控制
            document.getElementById('start-current').addEventListener('click', () => this.startCurrentTimer());
            document.getElementById('stop-current').addEventListener('click', () => this.stopCurrentTimer());
            
            // 多网址任务控制
            document.getElementById('add-task').addEventListener('click', () => this.addTask());
            document.getElementById('clear-tasks').addEventListener('click', () => this.clearTasks());
            document.getElementById('start-multi').addEventListener('click', () => this.startMultiTimer());
            document.getElementById('stop-multi').addEventListener('click', () => this.stopMultiTimer());
            
            // 最小化/恢复 - 单击最小化,双击恢复
            document.getElementById('minimize-btn').addEventListener('click', () => this.minimize());
            
            // 双击最小化界面打开UI
            this.ui.miniUI.addEventListener('click', (e) => {
                const now = Date.now();
                // 检测双击(300ms内连续点击)
                if (now - this.lastClickTime < this.doubleClickDelay) {
                    this.restore();
                    this.lastClickTime = 0; // 重置双击检测
                } else {
                    this.lastClickTime = now;
                }
            });
            
            // 使UI可拖动
            this.makeDraggable(this.ui.mainUI, 'timer_manager');
            this.makeDraggable(this.ui.miniUI, 'timer_mini');
            
            // 防止拖动事件影响输入框
            const inputs = document.querySelectorAll('input, button, .timer-btn');
            inputs.forEach(input => {
                input.addEventListener('mousedown', (e) => e.stopPropagation());
                input.addEventListener('touchstart', (e) => e.stopPropagation());
            });
        }
        
        // 优化拖动性能
        makeDraggable(element, storageKey) {
            let isDragging = false;
            let offsetX, offsetY;
            const originalZIndex = element.style.zIndex;
            let dragStartX, dragStartY;
            let lastDragTime = 0;
            
            element.addEventListener('pointerdown', startDrag);
            document.addEventListener('pointermove', drag);
            document.addEventListener('pointerup', endDrag);
            document.addEventListener('pointercancel', endDrag);
            
            function startDrag(e) {
                // 忽略按钮元素的拖动
                if (e.target.closest('.timer-btn, button, input')) return;
                
                e.preventDefault();
                const rect = element.getBoundingClientRect();
                offsetX = e.clientX - rect.left;
                offsetY = e.clientY - rect.top;
                dragStartX = e.clientX;
                dragStartY = e.clientY;
                isDragging = true;
                element.style.zIndex = '9999999'; // 拖动时临时提升层级
                element.style.transition = 'none';
                lastDragTime = Date.now();
            }
            
            function drag(e) {
                if (!isDragging) return;
                
                // 限制拖动频率,提升性能
                const now = Date.now();
                if (now - lastDragTime < 16) return; // 约60fps
                lastDragTime = now;
                
                requestAnimationFrame(() => {
                    const x = e.clientX - offsetX;
                    const y = e.clientY - offsetY;
                    
                    const maxX = window.innerWidth - element.offsetWidth;
                    const maxY = window.innerHeight - element.offsetHeight;
                    const constrainedX = Math.max(0, Math.min(x, maxX));
                    const constrainedY = Math.max(0, Math.min(y, maxY));
                    
                    element.style.left = `${constrainedX}px`;
                    element.style.top = `${constrainedY}px`;
                });
            }
            
            function endDrag() {
                if (!isDragging) return;
                
                isDragging = false;
                element.style.zIndex = originalZIndex;
                element.style.transition = '';
                
                // 只有明显移动后才保存位置(防止误触)
                Storage.savePos(
                    storageKey,
                    parseInt(element.style.left),
                    parseInt(element.style.top)
                );
            }
        }
        
        // 格式化时间
        formatTime(seconds) {
            const h = Math.floor(seconds / 3600);
            const m = Math.floor((seconds % 3600) / 60);
            const s = seconds % 60;
            return [
                h.toString().padStart(2, '0'),
                m.toString().padStart(2, '0'),
                s.toString().padStart(2, '0')
            ].join(':');
        }
        
        // 开始当前网页定时
        startCurrentTimer() {
            this.stopCurrentTimer();
            this.stopMultiTimer();
            
            const hours = Math.max(0, parseInt(document.getElementById('current-hours').value) || 0);
            const minutes = Math.max(0, Math.min(59, parseInt(document.getElementById('current-minutes').value) || 0));
            const seconds = Math.max(0, Math.min(59, parseInt(document.getElementById('current-seconds').value) || 0));
            
            this.remainingTime = hours * 3600 + minutes * 60 + seconds;
            
            if (this.remainingTime <= 0) {
                document.getElementById('current-status').innerHTML = '<i class="fas fa-exclamation-triangle"></i> 请设置有效的时间(大于0秒)';
                return;
            }
            
            this.isCurrentTimerRunning = true;
            const timeStr = this.formatTime(this.remainingTime);
            document.getElementById('current-status').innerHTML = `<i class="fas fa-hourglass-start"></i> 定时中: ${timeStr}`;
            this.miniTimeElement.textContent = timeStr;
            
            this.lastUpdateTime = Date.now();
            this.currentTimer = requestAnimationFrame(this.updateCurrentTimer.bind(this));
        }
        
        // 更新当前定时器
        updateCurrentTimer() {
            if (!this.currentTimer || !this.isCurrentTimerRunning) return;
            
            const now = Date.now();
            const elapsed = Math.floor((now - this.lastUpdateTime) / 1000);
            
            if (elapsed >= 1) {
                this.remainingTime -= elapsed;
                this.lastUpdateTime = now;
                
                if (this.remainingTime <= 0) {
                    this.stopCurrentTimer();
                    this.executeCurrentAction();
                    document.getElementById('current-status').innerHTML = '<i class="fas fa-check-circle"></i> 定时结束';
                    this.miniTimeElement.textContent = '00:00:00';
                    return;
                }
                
                const timeStr = this.formatTime(this.remainingTime);
                document.getElementById('current-status').innerHTML = `<i class="fas fa-hourglass-start"></i> 定时中: ${timeStr}`;
                this.miniTimeElement.textContent = timeStr;
            }
            
            this.currentTimer = requestAnimationFrame(this.updateCurrentTimer.bind(this));
        }
        
        // 停止当前定时器
        stopCurrentTimer() {
            if (this.currentTimer) {
                cancelAnimationFrame(this.currentTimer);
                this.currentTimer = null;
            }
            this.isCurrentTimerRunning = false;
            document.getElementById('current-status').innerHTML = '<i class="fas fa-stop-circle"></i> 已停止';
        }
        
        // 执行当前定时结束操作
        executeCurrentAction() {
            const action = document.querySelector('input[name="end-action"]:checked').value;
            
            if (action === 'blank') {
                window.location.href = 'about:blank';
            } else if (action === 'url') {
                const url = document.getElementById('target-url').value.trim();
                if (url) {
                    this.navigateToUrl(url, false);
                }
            }
        }
        
        // 添加多网址任务
        addTask() {
            const url = document.getElementById('multi-url').value.trim();
            if (!url) {
                document.getElementById('multi-status').innerHTML = '<i class="fas fa-exclamation-triangle"></i> 请输入有效的网址';
                return;
            }
            
            const hours = Math.max(0, parseInt(document.getElementById('multi-hours').value) || 0);
            const minutes = Math.max(0, Math.min(59, parseInt(document.getElementById('multi-minutes').value) || 0));
            const seconds = Math.max(0, Math.min(59, parseInt(document.getElementById('multi-seconds').value) || 0));
            
            if (hours === 0 && minutes === 0 && seconds === 0) {
                document.getElementById('multi-status').innerHTML = '<i class="fas fa-exclamation-triangle"></i> 请设置有效的停留时间(大于0秒)';
                return;
            }
            
            const noClose = document.getElementById('no-close').checked;
            
            this.tasks.push({
                url,
                time: hours * 3600 + minutes * 60 + seconds,
                noClose
            });
            
            Storage.saveTasks(this.tasks);
            this.renderTasks();
            
            // 清空输入
            document.getElementById('multi-url').value = '';
            document.getElementById('multi-hours').value = '0';
            document.getElementById('multi-minutes').value = '0';
            document.getElementById('multi-seconds').value = '30';
            
            document.getElementById('multi-status').innerHTML = '<i class="fas fa-check-circle"></i> 任务已添加';
        }
        
        // 渲染任务列表
        renderTasks() {
            const taskList = document.getElementById('task-list');
            taskList.innerHTML = '';
            
            if (this.tasks.length === 0) {
                taskList.innerHTML = '<div style="padding: 15px; text-align: center;" class="timer-theme"><i class="fas fa-list"></i> 任务列表为空</div>';
                return;
            }
            
            this.tasks.forEach((task, index) => {
                const taskItem = document.createElement('div');
                taskItem.className = 'task-item timer-theme';
                taskItem.innerHTML = `
                    <div class="task-url overflow-ellipsis timer-theme">
                        <i class="fas fa-link"></i> ${task.url}
                    </div>
                    <div class="task-time timer-theme">
                        <i class="fas fa-clock"></i> ${this.formatTime(task.time)}
                    </div>
                    <div class="task-remove timer-theme" data-index="${index}">
                        <i class="fas fa-times"></i>
                    </div>
                `;
                taskList.appendChild(taskItem);
            });
            
            // 添加删除事件
            document.querySelectorAll('.task-remove').forEach(btn => {
                btn.addEventListener('click', (e) => {
                    const index = parseInt(e.currentTarget.getAttribute('data-index'));
                    this.tasks.splice(index, 1);
                    Storage.saveTasks(this.tasks);
                    this.renderTasks();
                });
            });
        }
        
        // 清空任务列表
        clearTasks() {
            this.tasks = [];
            Storage.saveTasks(this.tasks);
            this.renderTasks();
            document.getElementById('multi-status').innerHTML = '<i class="fas fa-trash"></i> 任务列表已清空';
        }
        
        // 开始多网址定时跳转
        startMultiTimer() {
            this.stopCurrentTimer();
            this.stopMultiTimer();
            
            if (this.tasks.length === 0) {
                document.getElementById('multi-status').innerHTML = '<i class="fas fa-exclamation-triangle"></i> 任务列表为空';
                return;
            }
            
            this.isMultiRunning = true;
            this.currentTaskIndex = 0;
            this.navigateToCurrentTaskUrl();
        }
        
        // 跳转到当前任务的URL
        navigateToCurrentTaskUrl() {
            if (this.currentTaskIndex >= this.tasks.length || !this.isMultiRunning) {
                this.finishMultiTasks();
                return;
            }
            
            const task = this.tasks[this.currentTaskIndex];
            document.getElementById('multi-status').innerHTML = 
                `<i class="fas fa-sign-out-alt"></i> 正在跳转到: ${task.url}(第 ${this.currentTaskIndex + 1}/${this.tasks.length} 个任务)`;
            
            // 保存状态
            Storage.saveMultiState({
                running: this.isMultiRunning,
                index: this.currentTaskIndex,
                remaining: task.time
            });
            
            // 执行跳转
            this.navigateToUrl(task.url, task.noClose, () => {
                if (task.noClose) {
                    this.startTaskTimer();
                }
            });
        }
        
        // 开始当前任务的倒计时
        startTaskTimer() {
            if (this.currentTaskIndex >= this.tasks.length || !this.isMultiRunning) {
                this.finishMultiTasks();
                return;
            }
            
            const task = this.tasks[this.currentTaskIndex];
            this.remainingTime = this.remainingTime > 0 ? this.remainingTime : task.time;
            
            const timeStr = this.formatTime(this.remainingTime);
            document.getElementById('multi-status').innerHTML = 
                `<i class="fas fa-hourglass-half"></i> 停留中: ${timeStr}(第 ${this.currentTaskIndex + 1}/${this.tasks.length} 个任务)`;
            this.miniTimeElement.textContent = timeStr;
            
            Storage.saveMultiState({
                running: this.isMultiRunning,
                index: this.currentTaskIndex,
                remaining: this.remainingTime
            });
            
            this.lastUpdateTime = Date.now();
            this.multiTimer = requestAnimationFrame(this.updateMultiTimer.bind(this));
        }
        
        // 更新多任务定时器
        updateMultiTimer() {
            if (!this.multiTimer || !this.isMultiRunning) return;
            
            const now = Date.now();
            const elapsed = Math.floor((now - this.lastUpdateTime) / 1000);
            
            if (elapsed >= 1) {
                this.remainingTime -= elapsed;
                this.lastUpdateTime = now;
                
                Storage.saveMultiState({
                    running: this.isMultiRunning,
                    index: this.currentTaskIndex,
                    remaining: this.remainingTime
                });
                
                if (this.remainingTime <= 0) {
                    cancelAnimationFrame(this.multiTimer);
                    this.multiTimer = null;
                    this.currentTaskIndex++;
                    this.navigateToCurrentTaskUrl();
                    return;
                }
                
                const timeStr = this.formatTime(this.remainingTime);
                document.getElementById('multi-status').innerHTML = 
                    `<i class="fas fa-hourglass-half"></i> 停留中: ${timeStr}(第 ${this.currentTaskIndex + 1}/${this.tasks.length} 个任务)`;
                this.miniTimeElement.textContent = timeStr;
            }
            
            this.multiTimer = requestAnimationFrame(this.updateMultiTimer.bind(this));
        }
        
        // 完成所有多任务
        finishMultiTasks() {
            document.getElementById('multi-status').innerHTML = '<i class="fas fa-check-circle"></i> 所有任务执行完毕';
            this.miniTimeElement.textContent = '00:00:00';
            this.isMultiRunning = false;
            Storage.saveMultiState({ running: false, index: 0, remaining: 0 });
        }
        
        // 跳转至URL
        navigateToUrl(url, noClose = false, callback) {
            try {
                let targetUrl = url;
                // 简单补全协议
                if (!targetUrl.startsWith('http://') && !targetUrl.startsWith('https://')) {
                    targetUrl = 'https://' + targetUrl;
                }
                
                if (noClose) {
                    const newTab = GM_openInTab(targetUrl, { active: true });
                    if (callback) callback();
                } else {
                    window.location.href = targetUrl;
                }
            } catch (e) {
                console.error('跳转失败,尝试备用方法:', e);
                if (noClose) {
                    window.open(url, '_blank');
                    if (callback) callback();
                } else {
                    window.location.href = url;
                }
            }
        }
        
        // 停止多任务定时器
        stopMultiTimer() {
            if (this.multiTimer) {
                cancelAnimationFrame(this.multiTimer);
                this.multiTimer = null;
            }
            this.isMultiRunning = false;
            document.getElementById('multi-status').innerHTML = '<i class="fas fa-stop-circle"></i> 已停止';
            this.miniTimeElement.textContent = '00:00:00';
            Storage.saveMultiState({ running: false, index: 0, remaining: 0 });
        }
        
        // 最小化
        minimize() {
            this.ui.mainUI.style.display = 'none';
            this.ui.miniUI.style.display = 'flex';
            this.isMinimized = true;
        }
        
        // 恢复
        restore() {
            this.ui.mainUI.style.display = 'block';
            this.ui.miniUI.style.display = 'none';
            this.isMinimized = false;
        }
    }
    
    // 初始化应用
    function initApp() {
        const theme = Storage.getTheme();
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', () => {
                const ui = createUI(theme);
                new TimerController(ui);
            });
        } else {
            const ui = createUI(theme);
            const controller = new TimerController(ui);
            controller.minimize();
        }
    }
    
    // 添加菜单命令
    GM_registerMenuCommand("显示定时管理器", () => {
        const miniUI = document.getElementById('timer-mini');
        if (miniUI) {
            // 模拟双击打开
            miniUI.click();
            setTimeout(() => miniUI.click(), 100);
        } else {
            const theme = Storage.getTheme();
            const ui = createUI(theme);
            const controller = new TimerController(ui);
            controller.restore();
        }
    });
    
    initApp();
})();