Greasy Fork

VPS续期提醒

VPS续期提醒工具,支持自定义提醒周期和单个VPS续期

当前为 2025-05-31 提交的版本,查看 最新版本

// ==UserScript==
// @name         VPS续期提醒
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  VPS续期提醒工具,支持自定义提醒周期和单个VPS续期
// @author    You
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addSty
// @license      MIT  // <--- 添加许可证声明le
// ==/UserScript==

(function() {
    'use strict';

    // 添加样式
    GM_addStyle(`
        #vps-reminder-container {
            position: fixed;
            right: 20px;
            bottom: 20px;
            width: 300px;
            background-color: #fff;
            border: 1px solid #ccc;
            border-radius: 5px;
            box-shadow: 0 0 10px rgba(0,0,0,0.2);
            padding: 15px;
            z-index: 9999;
            font-family: Arial, sans-serif;
            display: none;
        }
        #vps-reminder-title {
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 10px;
            color: #333;
        }
        #vps-reminder-content {
            margin-bottom: 15px;
            color: #555;
            max-height: 200px;
            overflow-y: auto;
        }
        .vps-item {
            margin-bottom: 8px;
            padding-bottom: 8px;
            border-bottom: 1px solid #eee;
            position: relative;
        }
        .vps-item:last-child {
            border-bottom: none;
        }
        .vps-item-renew {
            position: absolute;
            right: 0;
            top: 0;
            padding: 3px 8px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            font-size: 12px;
        }
        #vps-reminder-buttons {
            display: flex;
            justify-content: space-between;
            flex-wrap: wrap;
            gap: 10px;
        }
        #vps-reminder-renew-all, #vps-reminder-settings, #vps-reminder-dismiss {
            padding: 8px 15px;
            border: none;
            border-radius: 3px;
            cursor: pointer;
        }
        #vps-reminder-renew-all {
            background-color: #4CAF50;
            color: white;
        }
        #vps-reminder-settings {
            background-color: #f1f1f1;
            color: #333;
        }
        #vps-reminder-dismiss {
            background-color: #ff9800;
            color: white;
            flex: 1;
            margin-top: 10px;
        }
        #vps-settings-container {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 500px;
            max-height: 80vh;
            overflow-y: auto;
            background-color: #fff;
            border: 1px solid #ccc;
            border-radius: 5px;
            box-shadow: 0 0 10px rgba(0,0,0,0.3);
            padding: 20px;
            z-index: 10000;
            font-family: Arial, sans-serif;
            display: none;
        }
        #vps-settings-title {
            font-size: 18px;
            font-weight: bold;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 1px solid #eee;
        }
        .vps-settings-item {
            margin-bottom: 15px;
            position: relative;
        }
        .vps-settings-item label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        .vps-settings-item input, .vps-settings-item select {
            width: 100%;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 3px;
        }
        .vps-delete-btn {
            position: absolute;
            right: 0;
            top: 0;
            background-color: #f44336;
            color: white;
            border: none;
            border-radius: 3px;
            padding: 3px 8px;
            cursor: pointer;
            font-size: 12px;
        }
        #vps-settings-buttons {
            display: flex;
            justify-content: space-between;
            margin-top: 15px;
        }
        #vps-settings-save {
            padding: 8px 15px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 3px;
            cursor: pointer;
        }
        #vps-settings-cancel {
            padding: 8px 15px;
            background-color: #f1f1f1;
            color: #333;
            border: none;
            border-radius: 3px;
            cursor: pointer;
        }
        #vps-add-new {
            padding: 8px 15px;
            background-color: #2196F3;
            color: white;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            margin-top: 15px;
            width: 100%;
        }
    `);

    // 默认VPS数据
    const defaultVpsData = [
        { id: 1, name: 'VPS 1', cycle: 3, nextDate: '', needRemind: false },
        { id: 2, name: 'VPS 2', cycle: 3, nextDate: '', needRemind: false },
        { id: 3, name: 'VPS 3', cycle: 3, nextDate: '', needRemind: false },
        { id: 4, name: 'VPS 4', cycle: 3, nextDate: '', needRemind: false },
        { id: 5, name: 'VPS 5', cycle: 30, nextDate: '', needRemind: false }
    ];

    // 获取VPS数据
    let vpsData = GM_getValue('vpsData', defaultVpsData);
    
    // 用于记录今天是否已经关闭过提醒
    let dismissedForToday = false;

    // 创建提醒容器
    function createReminderContainer() {
        const container = document.createElement('div');
        container.id = 'vps-reminder-container';
        
        const title = document.createElement('div');
        title.id = 'vps-reminder-title';
        title.textContent = 'VPS续期提醒';
        
        const content = document.createElement('div');
        content.id = 'vps-reminder-content';
        
        const buttons = document.createElement('div');
        buttons.id = 'vps-reminder-buttons';
        
        const renewAllButton = document.createElement('button');
        renewAllButton.id = 'vps-reminder-renew-all';
        renewAllButton.textContent = '全部已续期';
        renewAllButton.addEventListener('click', handleRenewAll);
        
        const settingsButton = document.createElement('button');
        settingsButton.id = 'vps-reminder-settings';
        settingsButton.textContent = '设置';
        settingsButton.addEventListener('click', showSettings);
        
        const dismissButton = document.createElement('button');
        dismissButton.id = 'vps-reminder-dismiss';
        dismissButton.textContent = '今天不再提醒';
        dismissButton.addEventListener('click', dismissForToday);
        
        buttons.appendChild(renewAllButton);
        buttons.appendChild(settingsButton);
        buttons.appendChild(dismissButton);
        
        container.appendChild(title);
        container.appendChild(content);
        container.appendChild(buttons);
        
        document.body.appendChild(container);
    }

    // 创建设置容器
    function createSettingsContainer() {
        const container = document.createElement('div');
        container.id = 'vps-settings-container';
        
        const title = document.createElement('div');
        title.id = 'vps-settings-title';
        title.textContent = 'VPS提醒设置';
        
        container.appendChild(title);
        
        const settingsContent = document.createElement('div');
        settingsContent.id = 'vps-settings-content';
        container.appendChild(settingsContent);
        
        // 创建添加新VPS按钮
        const addNewButton = document.createElement('button');
        addNewButton.id = 'vps-add-new';
        addNewButton.textContent = '添加新VPS';
        addNewButton.addEventListener('click', addNewVps);
        container.appendChild(addNewButton);
        
        const buttons = document.createElement('div');
        buttons.id = 'vps-settings-buttons';
        
        const cancelButton = document.createElement('button');
        cancelButton.id = 'vps-settings-cancel';
        cancelButton.textContent = '取消';
        cancelButton.addEventListener('click', () => {
            document.getElementById('vps-settings-container').style.display = 'none';
        });
        
        const saveButton = document.createElement('button');
        saveButton.id = 'vps-settings-save';
        saveButton.textContent = '保存';
        saveButton.addEventListener('click', saveSettings);
        
        buttons.appendChild(cancelButton);
        buttons.appendChild(saveButton);
        
        container.appendChild(buttons);
        
        document.body.appendChild(container);
        
        // 更新设置内容
        updateSettingsContent();
    }
    
    // 更新设置内容
    function updateSettingsContent() {
        const settingsContent = document.getElementById('vps-settings-content');
        settingsContent.innerHTML = '';
        
        // 为每个VPS创建设置项
        vpsData.forEach(vps => {
            const item = document.createElement('div');
            item.className = 'vps-settings-item';
            item.dataset.id = vps.id;
            
            // 删除按钮
            if (vpsData.length > 1) {
                const deleteBtn = document.createElement('button');
                deleteBtn.className = 'vps-delete-btn';
                deleteBtn.textContent = '删除';
                deleteBtn.addEventListener('click', function() {
                    deleteVps(vps.id);
                });
                item.appendChild(deleteBtn);
            }
            
            const nameLabel = document.createElement('label');
            nameLabel.textContent = `${vps.name} 名称`;
            
            const nameInput = document.createElement('input');
            nameInput.type = 'text';
            nameInput.id = `vps-name-${vps.id}`;
            nameInput.value = vps.name;
            
            const cycleLabel = document.createElement('label');
            cycleLabel.textContent = `${vps.name} 提醒周期(天)`;
            
            const cycleInput = document.createElement('input');
            cycleInput.type = 'number';
            cycleInput.id = `vps-cycle-${vps.id}`;
            cycleInput.value = vps.cycle;
            cycleInput.min = 1;
            
            const dateLabel = document.createElement('label');
            dateLabel.textContent = `${vps.name} 下次提醒日期`;
            
            const dateInput = document.createElement('input');
            dateInput.type = 'date';
            dateInput.id = `vps-date-${vps.id}`;
            dateInput.value = vps.nextDate || formatDate(new Date());
            
            item.appendChild(nameLabel);
            item.appendChild(nameInput);
            item.appendChild(cycleLabel);
            item.appendChild(cycleInput);
            item.appendChild(dateLabel);
            item.appendChild(dateInput);
            
            settingsContent.appendChild(item);
        });
    }
    
    // 添加新VPS
    function addNewVps() {
        // 生成新ID
        let maxId = 0;
        vpsData.forEach(vps => {
            if (vps.id > maxId) maxId = vps.id;
        });
        
        // 添加新VPS数据
        const newVps = {
            id: maxId + 1,
            name: `VPS ${maxId + 1}`,
            cycle: 3,
            nextDate: formatDate(new Date()),
            needRemind: false
        };
        
        vpsData.push(newVps);
        
        // 更新设置内容
        updateSettingsContent();
    }
    
    // 删除VPS
    function deleteVps(id) {
        vpsData = vpsData.filter(vps => vps.id !== id);
        updateSettingsContent();
    }

    // 显示设置界面
    function showSettings() {
        document.getElementById('vps-settings-container').style.display = 'block';
    }

    // 保存设置
    function saveSettings() {
        const newVpsData = [];
        
        // 获取所有设置项
        const settingsItems = document.querySelectorAll('.vps-settings-item');
        
        settingsItems.forEach(item => {
            const id = parseInt(item.dataset.id);
            const name = document.getElementById(`vps-name-${id}`).value;
            const cycle = parseInt(document.getElementById(`vps-cycle-${id}`).value);
            const nextDate = document.getElementById(`vps-date-${id}`).value;
            
            // 查找原始数据中的needRemind状态
            const originalVps = vpsData.find(vps => vps.id === id);
            const needRemind = originalVps ? originalVps.needRemind : false;
            
            newVpsData.push({
                id,
                name,
                cycle,
                nextDate,
                needRemind
            });
        });
        
        vpsData = newVpsData;
        GM_setValue('vpsData', vpsData);
        document.getElementById('vps-settings-container').style.display = 'none';
        
        // 重新检查提醒
        checkReminders();
    }

    // 格式化日期为YYYY-MM-DD
    function formatDate(date) {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        return `${year}-${month}-${day}`;
    }

    // 解析日期字符串为Date对象
    function parseDate(dateString) {
        return new Date(dateString);
    }

    // 计算两个日期之间的天数差
    function daysBetween(date1, date2) {
        const oneDay = 24 * 60 * 60 * 1000; // 一天的毫秒数
        const diffTime = Math.abs(date2 - date1);
        return Math.floor(diffTime / oneDay);
    }

    // 处理"今天不再提醒"按钮点击
    function dismissForToday() {
        dismissedForToday = true;
        document.getElementById('vps-reminder-container').style.display = 'none';
    }

    // 检查是否需要提醒
    function checkReminders() {
        // 如果今天已经关闭过提醒,则不再显示
        if (dismissedForToday) {
            return;
        }
        
        const today = new Date();
        today.setHours(0, 0, 0, 0);
        
        let hasRemindersNeedAttention = false; // 是否有VPS需要立即提醒
        let allVpsNeedingAttention = []; // 所有需要提醒的VPS
        
        // 第一次遍历:检查是否有VPS需要立即提醒
        vpsData.forEach(vps => {
            if (!vps.nextDate) return;
            
            const nextDate = parseDate(vps.nextDate);
            nextDate.setHours(0, 0, 0, 0);
            
            const daysUntil = daysBetween(today, nextDate);
            
            // 只有当前日期已超过到期日期,或者距离到期日期还有1天或2天时才提醒
            if (today >= nextDate || daysUntil === 1 || daysUntil === 2) {
                hasRemindersNeedAttention = true;
                vps.needRemind = true;
                allVpsNeedingAttention.push(vps);
            } else {
                vps.needRemind = false;
            }
        });
        
        // 如果有需要提醒的VPS,显示所有VPS的信息
        if (hasRemindersNeedAttention) {
            let reminderContent = '';
            
            // 添加需要提醒的VPS
            allVpsNeedingAttention.forEach(vps => {
                reminderContent += `<div class="vps-item">
                    <strong>${vps.name}</strong>: 需要续期
                    <div>下次提醒日期: ${vps.nextDate}</div>
                    <button class="vps-item-renew" data-id="${vps.id}">已续期</button>
                </div>`;
            });
            
            // 添加其他VPS的状态信息(可选)
            vpsData.forEach(vps => {
                if (!vps.needRemind) {
                    const nextDate = parseDate(vps.nextDate);
                    const daysUntil = daysBetween(today, nextDate);
                    reminderContent += `<div class="vps-item" style="opacity: 0.6;">
                        <strong>${vps.name}</strong>: 还有 ${daysUntil} 天到期
                        <div>下次提醒日期: ${vps.nextDate}</div>
                    </div>`;
                }
            });
            
            document.getElementById('vps-reminder-content').innerHTML = reminderContent;
            document.getElementById('vps-reminder-container').style.display = 'block';
            
            // 为每个单独的续期按钮添加事件
            document.querySelectorAll('.vps-item-renew').forEach(button => {
                button.addEventListener('click', function(e) {
                    e.stopPropagation();
                    handleRenewSingle(parseInt(this.dataset.id));
                });
            });
        }
        
        // 更新存储的数据
        GM_setValue('vpsData', vpsData);
    }

    // 处理单个VPS续期
    function handleRenewSingle(id) {
        const today = new Date();
        
        vpsData.forEach(vps => {
            if (vps.id === id && vps.needRemind) {
                // 计算新的提醒日期
                const newDate = new Date(today);
                newDate.setDate(today.getDate() + vps.cycle);
                vps.nextDate = formatDate(newDate);
                vps.needRemind = false;
            }
        });
        
        // 更新存储的数据
        GM_setValue('vpsData', vpsData);
        
        // 重新检查是否还有需要提醒的VPS
        checkReminders();
    }

    // 处理全部已续期按钮点击
    function handleRenewAll() {
        const today = new Date();
        
        vpsData.forEach(vps => {
            if (vps.needRemind) {
                // 计算新的提醒日期
                const newDate = new Date(today);
                newDate.setDate(today.getDate() + vps.cycle);
                vps.nextDate = formatDate(newDate);
                vps.needRemind = false;
            }
        });
        
        // 更新存储的数据
        GM_setValue('vpsData', vpsData);
        
        // 隐藏提醒
        document.getElementById('vps-reminder-container').style.display = 'none';
    }

    // 初始化
    function init() {
        createReminderContainer();
        createSettingsContainer();
        
        // 如果是首次使用,显示设置界面
        if (!GM_getValue('initialized', false)) {
            showSettings();
            GM_setValue('initialized', true);
        } else {
            // 检查是否需要提醒
            checkReminders();
        }
    }

    // 等待页面加载完成后初始化
    window.addEventListener('load', init);
})();