您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
提供定时提醒、倒计时功能,并支持自定义提醒事件。用户可以设置每日重复的提醒事件,每个事件在同一时间只会提醒一次;倒计时功能允许用户设置一个倒计时,时间到后会提醒用户。
当前为
// ==UserScript== // @name 定时提醒工具 // @namespace http://tampermonkey.net/ // @version 1.21 // @description 提供定时提醒、倒计时功能,并支持自定义提醒事件。用户可以设置每日重复的提醒事件,每个事件在同一时间只会提醒一次;倒计时功能允许用户设置一个倒计时,时间到后会提醒用户。 // @author wll // @match *://*/* // @grant GM_notification // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_getValue // @grant GM_setValue // @license AGPL-3.0-or-later // ==/UserScript== (function() { 'use strict'; const defaultReminders = [ { event: '喝水', time: '09:00', type: 'daily' }, { event: '休息一下', time: '10:30', type: 'daily' }, { event: '吃午饭', time: '12:00', type: 'daily' }, { event: '喝水', time: '14:00', type: 'daily' }, { event: '休息一下', time: '15:30', type: 'daily' }, { event: '吃晚饭', time: '18:00', type: 'daily' }, { event: '运动', time: '19:00', type: 'daily' }, ]; function loadReminders() { const savedReminders = GM_getValue('reminders'); return savedReminders || defaultReminders; } function saveReminders(reminders) { GM_setValue('reminders', reminders); } function loadButtonPosition() { const position = GM_getValue('buttonPosition'); return position || { top: '10px', left: '10px' }; } function saveButtonPosition(position) { GM_setValue('buttonPosition', position); } const settingsHTML = ` <div id="reminder-settings" style="display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 350px; background: white; border: 1px solid #ccc; padding: 20px; z-index: 10000; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"> <div style="display: flex; justify-content: space-between; align-items: center;"> <h3 style="margin: 0;">定时提醒设置</h3> <button id="close-settings" style="background: none; border: none; font-size: 18px; cursor: pointer;">×</button> </div> <div id="reminder-list" style="max-height: 200px; overflow-y: auto; margin-top: 10px; padding-right: 15px;"></div> <div style="text-align: center; margin-top: 10px;"> <button id="add-reminder">添加提醒</button> </div> <hr> <h3>倒计时功能</h3> <div style="display: flex; justify-content: space-between; align-items: center;"> <input type="number" id="countdown-minutes" placeholder="分钟数" style="width: 80px;"> <button id="start-countdown">开始倒计时</button> </div> </div> <button id="open-settings" style="position: fixed; width: 60px; height: 30px; z-index: 10000;">设置</button> `; document.body.insertAdjacentHTML('beforeend', settingsHTML); const buttonPosition = loadButtonPosition(); const openSettingsButton = document.getElementById('open-settings'); openSettingsButton.style.top = buttonPosition.top; openSettingsButton.style.left = buttonPosition.left; GM_addStyle(` #reminder-settings input, #reminder-settings select, #reminder-settings button { margin: 5px 0; } #reminder-list div { display: flex; align-items: center; margin-bottom: 5px; } #reminder-list div .event, #reminder-list div .time { margin-right: 10px; flex-grow: 1; } #reminder-list div .type { flex-grow: 2; margin-right: 10px; } #reminder-list div button { flex-grow: 0; } `); function loadReminderList() { const reminders = loadReminders(); const reminderList = document.getElementById('reminder-list'); reminderList.innerHTML = ''; reminders.forEach((reminder, index) => { const reminderDiv = document.createElement('div'); reminderDiv.innerHTML = ` <input type="text" value="${reminder.event}" data-index="${index}" class="event" style="width: 80px;"> <input type="time" value="${reminder.time}" data-index="${index}" class="time" style="width: 80px;"> <select data-index="${index}" class="type" style="width: 100px;"> <option value="once" ${reminder.type === 'once' ? 'selected' : ''}>提醒一次</option> <option value="daily" ${reminder.type === 'daily' ? 'selected' : ''}>每天提醒</option> </select> <button data-index="${index}" class="delete-reminder" style="width: 50px;">删除</button> `; reminderList.appendChild(reminderDiv); }); } function autoSaveReminder() { const reminders = []; document.querySelectorAll('#reminder-list div').forEach(div => { const event = div.querySelector('.event').value; const time = div.querySelector('.time').value; const type = div.querySelector('.type').value; if (event.trim() !== '') { reminders.push({ event, time, type }); } }); saveReminders(reminders); } function showSettings() { document.getElementById('reminder-settings').style.display = 'block'; loadReminderList(); } function hideSettings() { document.getElementById('reminder-settings').style.display = 'none'; } document.getElementById('open-settings').addEventListener('click', (e) => { e.stopPropagation(); const settingsDiv = document.getElementById('reminder-settings'); if (settingsDiv.style.display === 'none') { showSettings(); } else { hideSettings(); } }); document.getElementById('close-settings').addEventListener('click', hideSettings); window.addEventListener('click', (event) => { const settingsDiv = document.getElementById('reminder-settings'); if (settingsDiv.style.display !== 'none' && !settingsDiv.contains(event.target) && event.target !== openSettingsButton) { hideSettings(); } }); GM_registerMenuCommand('显示/隐藏提醒设置', () => { const settingsDiv = document.getElementById('reminder-settings'); if (settingsDiv.style.display === 'none') { showSettings(); } else { hideSettings(); } }); function makeElementDraggable(el) { let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; el.onmousedown = dragMouseDown; function dragMouseDown(e) { e = e || window.event; e.preventDefault(); pos3 = e.clientX; pos4 = e.clientY; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; } function elementDrag(e) { e = e || window.event; e.preventDefault(); pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; el.style.top = (el.offsetTop - pos2) + "px"; el.style.left = (el.offsetLeft - pos1) + "px"; saveButtonPosition({ top: el.style.top, left: el.style.left }); } function closeDragElement() { document.onmouseup = null; document.onmousemove = null; } } makeElementDraggable(openSettingsButton); document.getElementById('add-reminder').addEventListener('click', () => { const reminders = loadReminders(); const now = new Date(); const currentTime = now.toTimeString().substr(0, 5); reminders.push({ event: '', time: currentTime, type: 'daily' }); saveReminders(reminders); loadReminderList(); }); document.getElementById('reminder-list').addEventListener('input', autoSaveReminder); document.getElementById('reminder-list').addEventListener('click', (e) => { if (e.target.classList.contains('delete-reminder')) { e.stopPropagation(); const index = e.target.getAttribute('data-index'); const reminders = loadReminders(); reminders.splice(index, 1); saveReminders(reminders); loadReminderList(); } }); const notifiedTimes = new Set(); function checkAndNotify() { const now = new Date(); const currentTime = now.toTimeString().substr(0, 5); let reminders = loadReminders(); reminders.forEach(reminder => { if (currentTime === reminder.time && !notifiedTimes.has(reminder.time + reminder.event)) { if (reminder.event.trim() !== '') { GM_notification({ title: '定时提醒', text: `该${reminder.event}了!`, timeout: 10000, onclick: () => { console.log(`你点击了${reminder.event}提醒`); } }); notifiedTimes.add(reminder.time + reminder.event); } } }); // Remove entries from notifiedTimes set to avoid memory issues notifiedTimes.forEach(key => { if (!reminders.some(reminder => reminder.time + reminder.event === key && reminder.time === currentTime)) { notifiedTimes.delete(key); } }); } setInterval(() => { notifiedTimes.clear(); }, 60000); document.getElementById('start-countdown').addEventListener('click', () => { const minutes = parseInt(document.getElementById('countdown-minutes').value, 10); if (!isNaN(minutes) && minutes > 0) { GM_notification({ title: '倒计时提醒', text: `倒计时${minutes}分钟开始!`, timeout: 5000 }); hideSettings(); setTimeout(() => { GM_notification({ title: '倒计时提醒', text: `倒计时${minutes}分钟结束!`, timeout: 10000 }); }, minutes * 60000); } else { alert('请输入有效的分钟数'); } }); setInterval(checkAndNotify, 1000); checkAndNotify(); })();