定时关闭网页

拖拽弹窗,滑块设置分钟+秒,右上角显示剩余时间

当前为 2025-08-18 提交的版本,查看 最新版本

// ==UserScript==
// @name         定时关闭网页
// @namespace    https://github.com/yingchen6
// @version      1.8.7.3
// @description  拖拽弹窗,滑块设置分钟+秒,右上角显示剩余时间
// @author       yingchen6
// @match        *://*/*
// @grant        GM_registerMenuCommand
// @license MIT
// @require      https://unpkg.com/sweetalert/dist/sweetalert.min.js
// ==/UserScript==


(function(){
    'use strict';

    let timerId = null;
    let remainingSeconds = 0;
    let totalSeconds = 0;
    let displayBox = null;
    let canvas = null;
    let paused = false;

    function formatTime(seconds){
        const m = Math.floor(seconds/60);
        const s = seconds%60;
        return `${m.toString().padStart(2,'0')}:${s.toString().padStart(2,'0')}`;
    }

    function showDisplayBox(minutes){
        if(displayBox) displayBox.remove();
        totalSeconds = remainingSeconds = minutes*60;
        paused = false;

        displayBox = document.createElement("div");
        displayBox.id = "display-box";
        displayBox.style.position = "fixed";
        displayBox.style.top = "20px";
        displayBox.style.left = "20px";
        displayBox.style.width = "160px";
        displayBox.style.height = "160px";
        displayBox.style.background = "rgba(30,30,30,0.7)";
        displayBox.style.backdropFilter = "blur(10px)";
        displayBox.style.borderRadius = "50%";
        displayBox.style.display = "flex";
        displayBox.style.alignItems = "center";
        displayBox.style.justifyContent = "center";
        displayBox.style.boxShadow = "0 8px 30px rgba(0,0,0,0.6)";
        displayBox.style.cursor = "grab";
        displayBox.style.zIndex = "999999";
        displayBox.style.userSelect = "none";
        document.body.appendChild(displayBox);

        // Canvas环形进度
        canvas = document.createElement("canvas");
        canvas.width = 160;
        canvas.height = 160;
        canvas.style.position = "absolute";
        canvas.style.top = "0";
        canvas.style.left = "0";
        displayBox.appendChild(canvas);

        const timeLabel = document.createElement("div");
        timeLabel.id = "time-label";
        timeLabel.style.fontSize = "28px";
        timeLabel.style.fontWeight = "bold";
        timeLabel.style.color = "#00ffcc";
        timeLabel.style.zIndex = "2";
        displayBox.appendChild(timeLabel);

        const pauseBtn = document.createElement("button");
        pauseBtn.id = "pause-btn";
        pauseBtn.textContent = "暂停";
        pauseBtn.style.position = "absolute";
        pauseBtn.style.bottom = "10px";
        pauseBtn.style.fontSize = "14px";
        pauseBtn.style.padding = "4px 10px";
        pauseBtn.style.border = "none";
        pauseBtn.style.borderRadius = "8px";
        pauseBtn.style.background = "linear-gradient(135deg,#ff9a00,#ffdc00)";
        pauseBtn.style.color = "#222";
        pauseBtn.style.fontWeight = "bold";
        pauseBtn.style.cursor = "pointer";
        pauseBtn.style.boxShadow = "0 4px 12px rgba(0,0,0,0.3)";
        pauseBtn.onmouseover = ()=>{ pauseBtn.style.opacity = "0.8"; };
        pauseBtn.onmouseout = ()=>{ pauseBtn.style.opacity = "1"; };
        displayBox.appendChild(pauseBtn);

        pauseBtn.addEventListener("click",(e)=>{
            e.stopPropagation();
            paused = !paused;
            pauseBtn.textContent = paused ? "继续" : "暂停";
        });

        // 拖拽 + 双击修改
        let isDown = false;
        let startX=0,startY=0;
        let offsetX=0,offsetY=0;
        let downTime=0;
        displayBox.addEventListener("mousedown",(e)=>{
            isDown = true;
            startX = e.clientX;
            startY = e.clientY;
            offsetX = displayBox.offsetLeft;
            offsetY = displayBox.offsetTop;
            downTime = Date.now();
            displayBox.style.cursor="grabbing";
        });
        document.addEventListener("mousemove",(e)=>{
            if(!isDown) return;
            const dx = e.clientX - startX;
            const dy = e.clientY - startY;
            displayBox.style.left = offsetX+dx+"px";
            displayBox.style.top = offsetY+dy+"px";
        });
        document.addEventListener("mouseup",(e)=>{
            if(!isDown) return;
            isDown = false;
            displayBox.style.cursor="grab";
            const elapsed = Date.now()-downTime;
            if(elapsed<300){
                showTimeSetting(Math.floor(remainingSeconds/60), remainingSeconds%60);
            }
        });

        startCountdown();
    }

    function startCountdown(){
        if(timerId) clearInterval(timerId);
        const label = document.getElementById("time-label");
        timerId = setInterval(()=>{
            if(!paused){
                remainingSeconds--;
                if(remainingSeconds<=0){
                    clearInterval(timerId);
                    window.location.href = "about:blank";
                    return;
                }
                label.textContent = formatTime(remainingSeconds);

                // 绘制环形进度
                const ctx = canvas.getContext("2d");
                ctx.clearRect(0,0,canvas.width,canvas.height);
                const center = canvas.width/2;
                const radius = 70;

                // 背景环
                ctx.beginPath();
                ctx.arc(center,center,radius,0,2*Math.PI);
                ctx.strokeStyle = "rgba(255,255,255,0.2)";
                ctx.lineWidth = 12;
                ctx.stroke();

                // 渐变进度
                const fraction = remainingSeconds/totalSeconds;
                const grad = ctx.createLinearGradient(0,0,canvas.width,canvas.height);
                grad.addColorStop(0,"#ff6ec7");
                grad.addColorStop(0.5,"#00ffe0");
                grad.addColorStop(1,"#fffd00");
                ctx.beginPath();
                ctx.arc(center,center,radius,-Math.PI/2,-Math.PI/2 + 2*Math.PI*fraction);
                ctx.strokeStyle = grad;
                ctx.lineWidth = 12;
                ctx.lineCap = "round";
                ctx.shadowBlur = 10;
                ctx.shadowColor = "#00ffe0";
                ctx.stroke();
            }
        },1000);
    }

    function showTimeSetting(defaultMin=30, defaultSec=0){
        const wrapper = document.createElement("div");
        wrapper.innerHTML = `
            <div style="display:flex;flex-direction:column;align-items:center;gap:15px;padding:20px;background:rgba(20,20,20,0.9);border-radius:20px;backdrop-filter:blur(12px);">
                <h2 style="color:#ffdd55;font-size:22px;margin:0;">设置倒计时</h2>
                <div style="display:flex;gap:10px;align-items:center;">
                    <input id="minRange" type="range" min="0" max="180" value="${defaultMin}" style="width:180px;">
                    <span id="minLabel" style="color:#00ffe0;font-weight:bold;">${defaultMin} 分钟</span>
                </div>
                <div style="display:flex;gap:10px;align-items:center;">
                    <input id="secRange" type="range" min="0" max="59" value="${defaultSec}" style="width:180px;">
                    <span id="secLabel" style="color:#00ffe0;font-weight:bold;">${defaultSec} 秒</span>
                </div>
            </div>
        `;
        swal({
            content: wrapper,
            buttons: {
                cancel:{text:"取消",className:"swal-btn-cancel"},
                confirm:{text:"确定",className:"swal-btn-confirm"}
            }
        }).then((ok)=>{
            if(!ok) return;
            const minutes = parseInt(wrapper.querySelector("#minRange").value);
            const seconds = parseInt(wrapper.querySelector("#secRange").value);
            showDisplayBox(minutes+seconds/60);
        });

        const minRange = wrapper.querySelector("#minRange");
        const minLabel = wrapper.querySelector("#minLabel");
        minRange.addEventListener("input",()=>{ minLabel.textContent = minRange.value+" 分钟"; });
        const secRange = wrapper.querySelector("#secRange");
        const secLabel = wrapper.querySelector("#secLabel");
        secRange.addEventListener("input",()=>{ secLabel.textContent = secRange.value+" 秒"; });
    }

    if(typeof GM_registerMenuCommand!=="undefined"){
        GM_registerMenuCommand("开始计时",()=>{ showTimeSetting(30,0); });
    }

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址