获取确认ID免登录GM版

获取微软激活确认ID,带悬浮面板,支持剪贴板操作和精准IID合法性校验*://visualsupport.microsoft.com/*

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

Advertisement:

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

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

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

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

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

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

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

Advertisement:

// ==UserScript==
// @name         获取确认ID免登录GM版
// @namespace    http://tampermonkey.net/
// @version      2026-05-17 v1
// @description  获取微软激活确认ID,带悬浮面板,支持剪贴板操作和精准IID合法性校验*://visualsupport.microsoft.com/*
// @author       福建-兮
// @match        *://visualsupport.microsoft.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=microsoft.com
// @grant        GM_xmlhttpRequest
// @grant        GM_setClipboard
// @connect      visualsupport.microsoft.com
// @connect      cidtoken.x2ray.cfd
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    /**
     * 校验IID区块合法性
     * @param {string} block - IID的单个区块
     * @returns {boolean} 区块是否合法
     */
    function checkBlock(block) {
        if (!/^\d+$/.test(block) || block.length < 2) return false;

        const check = Number(block.at(-1));
        let sum = 0;

        for (let i = 0; i < block.length - 1; i++) {
            const d = Number(block[i]);
            sum += i % 2 === 0 ? d : d * 2;
        }

        return sum % 7 === check;
    }

    /**
     * 校验整个IID的合法性(增强版,返回具体错误信息)
     * @param {string} iid - 待校验的IID字符串
     * @returns {object} 校验结果 {valid: boolean, error?: string, failedBlocks?: array}
     */
    function validateIID(iid) {
        // 检查是否全为数字
        if (!/^\d+$/.test(iid))
            return { valid: false, error: "not_numeric" };

        // 检查长度是否为54或63位
        if (iid.length !== 54 && iid.length !== 63)
            return { valid: false, error: "invalid_length", length: iid.length };

        // 检查每个区块的合法性
        const blockSize = iid.length / 9;
        const failedBlocks = [];

        for (let i = 0; i < 9; i++) {
            const block = iid.slice(i * blockSize, (i + 1) * blockSize);

            if (!checkBlock(block)) {
                failedBlocks.push({
                    index: i + 1,
                    value: block
                });
            }
        }

        return {
            valid: failedBlocks.length === 0,
            failedBlocks
        };
    }

    /**
     * 创建悬浮提示框(通用,支持成功/错误提示)
     * @param {string} mainText - 主要提示文本
     * @param {string} detailText - 详细错误/成功信息
     * @param {string} content - 额外展示的内容(IID/响应结果)
     * @param {string} type - 提示类型(error/success)
     * @param {number} duration - 显示时长(毫秒)
     */
    function showFloatTip(mainText, detailText = "", content = "", type = "error", duration = 5000) {
        // 移除已存在的提示框
        const oldTip = document.getElementById("ms-iid-tip");
        if (oldTip) oldTip.remove();

        // 创建新提示框容器
        const tipContainer = document.createElement("div");
        tipContainer.id = "ms-iid-tip";
        tipContainer.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            padding: 20px;
            background: ${type === "error" ? "#f8d7da" : "#d4edda"};
            color: ${type === "error" ? "#721c24" : "#155724"};
            border: 1px solid ${type === "error" ? "#f5c6cb" : "#c3e6cb"};
            border-radius: 8px;
            font-size: 16px;
            z-index: 9999999;
            box-shadow: 0 4px 20px rgba(0,0,0,0.15);
            opacity: 0;
            transition: opacity 0.3s ease;
            max-width: 80%;
            max-height: 80vh;
            overflow-y: auto;
            word-break: break-all;
            text-align: left;
        `;

        // 1. 主要提示文本
        const tipTitle = document.createElement("div");
        tipTitle.style.cssText = `
            margin-bottom: 12px;
            font-weight: bold;
            font-size: 16px;
        `;
        tipTitle.textContent = mainText;
        tipContainer.appendChild(tipTitle);

        // 2. 详细信息(如有)
        if (detailText) {
            const tipDetail = document.createElement("div");
            tipDetail.style.cssText = `
                margin-bottom: 10px;
                font-size: 14px;
                line-height: 1.5;
            `;
            tipDetail.textContent = type === "error" ? `错误详情:${detailText}` : `响应信息:${detailText}`;
            tipContainer.appendChild(tipDetail);
        }

        // 3. 显示额外内容(IID/响应结果)
        if (content) {
            const contentWrapper = document.createElement("div");
            contentWrapper.style.cssText = `
                margin-top: 10px;
            `;

            const contentLabel = document.createElement("div");
            contentLabel.style.cssText = `
                font-size: 14px;
                margin-bottom: 5px;
                font-weight: bold;
            `;
            contentLabel.textContent = type === "error" ? "校验的IID:" : "响应结果:";
            contentWrapper.appendChild(contentLabel);

            const contentDisplay = document.createElement("div");
            contentDisplay.style.cssText = `
                font-size: 13px;
                padding: 8px;
                background: rgba(255,255,255,0.8);
                border-radius: 4px;
                white-space: pre-wrap;
                line-height: 1.4;
                font-family: Consolas, monospace;
            `;
            // 格式化展示内容
            let displayContent = content;
            try {
                // 如果是JSON字符串,格式化显示
                if (type === "success" && typeof content === "object") {
                    displayContent = JSON.stringify(content, null, 2);
                } else if (typeof content === "string" && content.startsWith("{")) {
                    displayContent = JSON.stringify(JSON.parse(content), null, 2);
                }
            } catch (e) {
                // 非JSON格式则原样显示
                displayContent = content;
            }

            // 超长内容换行处理
            if (displayContent.length > 60) {
                displayContent = displayContent.match(/.{1,60}/g)?.join('\n') || displayContent;
            }

            contentDisplay.textContent = displayContent;
            contentWrapper.appendChild(contentDisplay);

            tipContainer.appendChild(contentWrapper);
        }

        document.body.appendChild(tipContainer);

        // 显示提示框(淡入效果)
        setTimeout(() => {
            tipContainer.style.opacity = "1";
        }, 10);

        // 自动隐藏(淡出效果)
        setTimeout(() => {
            tipContainer.style.opacity = "0";
            setTimeout(() => {
                tipContainer.remove();
            }, 300);
        }, duration);
    }

    /**
     * 错误码转中文提示
     * @param {object} validateResult - 校验结果对象
     * @returns {object} {mainText: string, detailText: string}
     */
    function getErrorText(validateResult) {
        let mainText = "IID格式不合法";
        let detailText = "";

        if (validateResult.error === "not_numeric") {
            mainText = "⚠️ IID包含非数字字符";
            detailText = "IID必须全部由数字组成,不能包含字母、符号或空格";
        } else if (validateResult.error === "invalid_length") {
            mainText = "⚠️ IID长度不正确";
            detailText = `当前长度:${validateResult.length}位,合法长度应为54位或63位`;
        } else if (validateResult.failedBlocks && validateResult.failedBlocks.length > 0) {
            mainText = `⚠️ IID不合法,有${validateResult.failedBlocks.length}个区块校验失败`;
            const failedBlockStr = validateResult.failedBlocks.map(block =>
                                                                   `第${block.index}区块 (${block.value})`
            ).join("、");
            detailText = `失败的区块:${failedBlockStr}(区块校验位计算错误)`;
        }

        return { mainText, detailText };
    }

    /**
     * 获取微软激活配置项(改用GM_xmlhttpRequest)
     * @returns {Promise<any>} 返回服务器响应的 JSON 数据
     */
    async function getGovUrlConfig() {
        const url = "https://visualsupport.microsoft.com/api/configuration/govUrlID";

        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: url,
                headers: {
                    "accept": "application/json",
                    "cache-control": "no-cache"
                },
                onload: function (response) {
                    if (response.status >= 200 && response.status < 300) {
                        try {
                            resolve(JSON.parse(response.responseText));
                        } catch (e) {
                            reject(new Error("解析配置数据失败: " + e.message));
                        }
                    } else {
                        reject(new Error(`HTTP 错误! 状态码: ${response.status}`));
                    }
                },
                onerror: function (error) {
                    reject(new Error("请求配置失败: " + error.message));
                }
            });
        });
    }

    // 1. Base64URL编码函数(eI):JWT/DPoP标准编码方式
    function eI(t) {
        let e = t instanceof ArrayBuffer ? new Uint8Array(t) : new TextEncoder().encode(t);
        let n = "";
        for (let o of e) {
            n += String.fromCharCode(o);
        }
        return btoa(n).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
    }

    // 2. 全局缓存密钥对的变量(单例模式)
    let tI = null;

    // 3. 生成/获取ECDSA P-256密钥对(yT)
    async function yT() {
        if (!tI) {
            tI = await crypto.subtle.generateKey({
                name: "ECDSA",
                namedCurve: "P-256"
            }, true,
                                                 ["sign", "verify"]
                                                );
        }
        return tI;
    }

    // 4. 核心:生成DPoP令牌(c1e)
    async function c1e(t, e) {
        try {
            const { privateKey: n, publicKey: o } = await yT();

            const i = {
                alg: "ES256",
                typ: "dpop+jwt",
                jwk: await crypto.subtle.exportKey("jwk", o)
            };

            const a = {
                htu: t,
                htm: e,
                jti: crypto.randomUUID(),
                iat: Math.floor(Date.now() / 1000)
            };

            const s = eI(JSON.stringify(i));
            const l = eI(JSON.stringify(a));
            const u = `${s}.${l}`;

            const p = await crypto.subtle.sign({
                name: "ECDSA",
                hash: "SHA-256"
            }, n, new TextEncoder().encode(u));

            const g = eI(p);
            return `${s}.${l}.${g}`;
        } catch (error) {
            console.error("生成DPoP令牌失败:", error);
            throw error;
        }
    }

    // 生成DPoP令牌
    async function testGenerateDPoP() {
        const dpopToken = await c1e(
            "/api/productActivation/validateIID",
            "POST"
        );
        return dpopToken;
    }

    //生成x-session-id app_mmsj2c31_x1nrlz06b
    function GenerateSessionId() {
        const t = Date.now().toString(36);
        const e = Math.random().toString(36).substr(2, 9);
        return `app_${t}_${e}`;
    }

    /**
     * ✅ 获取 Token JSON 数据(可返回,供全局使用)
     * @returns {Promise<Object>}
     */
    function getTokenData() {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: "https://cidtoken.x2ray.cfd",
                timeout: 10000,
                responseType: "json",
                onload: (res) => {
                    try {
                        const data = res.response;
                        if (!data || !data.access_token) {
                            reject("无效的 Token 数据");
                            return;
                        }
                        resolve(data);
                    } catch (err) {
                        reject("解析 JSON 失败:" + err);
                    }
                },
                onerror: (err) => reject("网络请求失败:" + err),
                ontimeout: () => reject("请求超时")
            });
        });
    }

    /**
     * 发送激活请求(改用GM_xmlhttpRequest)- 移除内部的IID校验
     * @param {string} iid - 从剪贴板获取的IID参数
     * @returns {Promise<any>} 响应结果
     */
    async function sendActivationRequest(iid) {
        if (!iid || iid.trim() === "") {
            throw new Error("剪贴板中未获取到有效的IID参数");
        }

        try {
            const dpopToken = await testGenerateDPoP();
            const govUrlConfig = await getGovUrlConfig();
            const numberOfDigits = Math.floor(iid.length / 9);
            const sid = GenerateSessionId();

            // ✅ 这里正确获取 token
            const tokenJson = await getTokenData();
            if (!tokenJson || !tokenJson.access_token) {
                throw new Error("获取 AccessToken 失败,请检查网络或接口");
            }

            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: "POST",
                    url: "https://visualsupport.microsoft.com/api/productActivation/validateIID",
                    headers: {
                        "content-type": "application/json",
                        //"authorization": "Bearer govUrlID",
                        "authorization": "Bearer " + tokenJson.access_token, // ✅ 已修复
                        "dpop": dpopToken,
                        "x-session-id": sid,
                        "referrer": `https://visualsupport.microsoft.com/${govUrlConfig}/activate`,
                    },
                    data: JSON.stringify({
                        IID: iid,
                        ProductType: "windows",
                        productGroup: "Windows",
                        productName: "Windows 11",
                        numberOfDigits: numberOfDigits,
                        Country: "CHN",
                        Region: "APGC",
                        InstalledDevices: 1,
                        OverrideStatusCode: "MUL",
                        InitialReasonCode: "45164"
                    }),
                    onload: function (response) {
                        if (response.status >= 200 && response.status < 300) {
                            try {
                                const result = JSON.parse(response.responseText);
                                resolve(result);
                            } catch (e) {
                                reject(new Error("解析响应数据失败: " + e.message));
                            }
                        } else {
                            reject(new Error(`请求失败! 状态码: ${response.status}, 响应: ${response.responseText}`));
                        }
                    },
                    onerror: function (error) {
                        reject(new Error("请求发送失败: " + error.message));
                    }
                });
            });
        } catch (error) {
            console.error("请求失败:", error);
            throw error;
        }
    }

    /**
     * 创建可拖拽的悬浮面板(美化版)
     */
    function createFloatPanel() {
        // 1. 创建面板容器(美化样式)
        const panel = document.createElement("div");
        panel.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 220px; /* 加宽一点更美观 */
            background: rgba(255,255,255,0.95); /* 半透明背景 */
            border: 1px solid #e5e7eb;
            border-radius: 12px; /* 更大圆角 */
            box-shadow: 0 8px 24px rgba(0,0,0,0.12); /* 更柔和的阴影 */
            z-index: 999999;
            padding: 16px;
            transition: background 0.3s, transform 0.2s; /* 过渡动画 */
            backdrop-filter: blur(8px); /* 毛玻璃效果 */
            cursor: move; /* 提示整个面板可拖拽 */
            user-select: none; /* 禁止选中文字 */
        `;
        panel.id = "ms-activation-panel";

        // 2. 创建标题
        const panelTitle = document.createElement("div");
        panelTitle.style.cssText = `
            font-size: 15px;
            font-weight: 600;
            margin-bottom: 12px;
            color: #1f2937;
            text-align: center;
            padding-bottom: 8px;
            border-bottom: 1px solid #f3f4f6; /* 分割线样式 */
        `;
        panelTitle.textContent = "微软激活ID获取 · 免登录版";
        panel.appendChild(panelTitle);

        // 3. 创建按钮(美化样式)
        const btn = document.createElement("button");
        btn.style.cssText = `
            width: 100%;
            padding: 10px;
            background: #0078d4;
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer; /* 按钮保持点击光标 */
            font-size: 14px;
            margin-bottom: 10px;
            transition: background 0.2s, transform 0.1s; /* 交互动画 */
            font-weight: 500;
        `;
        // 按钮hover/active效果
        btn.addEventListener("mouseenter", () => {
            btn.style.background = "#0086e5";
        });
        btn.addEventListener("mouseleave", () => {
            btn.style.background = "#0078d4";
        });
        btn.addEventListener("mousedown", () => {
            btn.style.transform = "scale(0.98)";
        });
        btn.addEventListener("mouseup", () => {
            btn.style.transform = "scale(1)";
        });
        btn.textContent = "获取确认ID";
        panel.appendChild(btn);

        // 4. 创建状态提示(美化样式)
        const status = document.createElement("div");
        status.style.cssText = `
            font-size: 13px;
            color: #4b5563;
            text-align: center;
            min-height: 18px;
            line-height: 1.4;
            padding: 4px 0;
            border-radius: 6px;
        `;
        status.textContent = "✅ 就绪";
        panel.appendChild(status);

        // ===================== 悬浮面板拖拽(PC + Android + 防止出屏) =====================
        // 是否正在拖拽
        let isDragging = false;
        // 鼠标 / 手指 与 面板左上角 的偏移量
        let offsetX = 0;
        let offsetY = 0;

        /**
         * 开始拖拽
         * @param {number} clientX 鼠标/手指的 X 坐标
         * @param {number} clientY 鼠标/手指的 Y 坐标
         */
        function startDrag(clientX, clientY) {
            // 如果点击的是按钮,不触发拖拽
            if (event.target === btn) return;

            isDragging = true;
            // 获取面板当前在视口中的位置和尺寸
            const rect = panel.getBoundingClientRect();
            // ★ 关键:将 right/bottom 转换为 left/top,否则拖拽时位置会错乱
            panel.style.left = rect.left + "px";
            panel.style.top = rect.top + "px";
            panel.style.right = "auto";
            panel.style.bottom = "auto";
            // 计算鼠标 / 手指 与 面板左上角 的偏移量
            offsetX = clientX - rect.left;
            offsetY = clientY - rect.top;
            // 拖动时取消动画,保证跟手
            panel.style.transition = "none";
            // 拖动时轻微放大,提升交互感
            panel.style.transform = "scale(1.02)";
        }

        /**
         * 限制数值在 min ~ max 之间,防止面板被拖出屏幕
         */
        function clamp(value, min, max) {
            return Math.min(Math.max(value, min), max);
        }

        /**
         * 拖拽移动
         * @param {number} clientX
         * @param {number} clientY
         */
        function moveDrag(clientX, clientY) {
            if (!isDragging) return;
            // 计算屏幕最大可移动范围
            const maxX = window.innerWidth - panel.offsetWidth;
            const maxY = window.innerHeight - panel.offsetHeight;
            // 计算新位置,并限制在屏幕内
            const newLeft = clamp(clientX - offsetX, 0, maxX);
            const newTop = clamp(clientY - offsetY, 0, maxY);
            // 应用位置
            panel.style.left = newLeft + "px";
            panel.style.top = newTop + "px";
        }

        /**
         * 结束拖拽
         */
        function endDrag() {
            if (!isDragging) return;
            isDragging = false;
            // 恢复过渡动画
            panel.style.transition = "background 0.3s, transform 0.2s";
            // 恢复缩放
            panel.style.transform = "scale(1)";
        }

        /* ===================== PC 鼠标事件 ===================== */
        // 鼠标按下(整个面板监听)
        panel.addEventListener("mousedown", (e) => {
            e.preventDefault(); // 防止选中文字
            startDrag(e.clientX, e.clientY);
        });
        // 鼠标移动
        document.addEventListener("mousemove", (e) => {
            moveDrag(e.clientX, e.clientY);
        });
        // 鼠标松开
        document.addEventListener("mouseup", endDrag);

        /* ===================== Android 触摸事件 ===================== */
        // 手指按下
        panel.addEventListener("touchstart", (e) => {
            const touch = e.touches[0]; // 第一个触摸点
            startDrag(touch.clientX, touch.clientY);
        }, { passive: false }); // ★ 必须 passive:false
        // 手指移动
        document.addEventListener("touchmove", (e) => {
            if (!isDragging) return;
            e.preventDefault(); // ★ 关键:阻止页面滚动
            const touch = e.touches[0];
            moveDrag(touch.clientX, touch.clientY);
        }, { passive: false });
        // 手指松开 / 被打断
        document.addEventListener("touchend", endDrag);
        document.addEventListener("touchcancel", endDrag);

        // ===================== 页面悬浮提示(Toast) =====================
        function showToast(message, type = "info", duration = 5000) {
            const toast = document.createElement("div");
            const colors = {
                success: "rgba(40,167,69,0.9)", // 绿
                warning: "rgba(255,193,7,0.9)", // 黄
                error: "rgba(220,53,69,0.9)", // 红
                info: "rgba(0,0,0,0.85)"     // 黑
            };
            toast.textContent = message;
            toast.style.cssText = `
                position: fixed;
                top: 20px;
                left: 50%;
                transform: translateX(-50%) translateY(-10px);
                background: ${colors[type] || colors.info};
                color: #fff;
                padding: 10px 16px;
                border-radius: 6px;
                font-size: 14px;
                z-index: 10000;
                box-shadow: 0 4px 12px rgba(0,0,0,0.3);
                opacity: 0;
                transition: opacity 0.3s, transform 0.3s;
                pointer-events: none;
                white-space: nowrap;
            `;
            document.body.appendChild(toast);
            // 淡入
            requestAnimationFrame(() => {
                toast.style.opacity = "1";
                toast.style.transform = "translateX(-50%) translateY(0)";
            });
            // 到时间淡出并移除
            setTimeout(() => {
                toast.style.opacity = "0";
                toast.style.transform = "translateX(-50%) translateY(-10px)";
                setTimeout(() => toast.remove(), 300);
            }, duration);
        }

        // 6. 按钮点击事件 - 保留原有逻辑,替换提示方式为Toast
        btn.addEventListener("click", async () => {
            // 定义恢复按钮状态的通用函数
            const resetButton = (text = "获取确认ID", statusText = "✅ 就绪") => {
                btn.disabled = false;
                btn.textContent = text;
                status.textContent = statusText;
            };

            try {
                // 禁用按钮防止重复点击
                btn.disabled = true;
                btn.textContent = "处理中...";
                status.textContent = "🔍 读取剪贴板中...";
                showToast("正在读取剪贴板内容", "info");

                // 从剪贴板获取IID(处理权限拒绝)
                let clipboardText;
                try {
                    clipboardText = await navigator.clipboard.readText();
                } catch (clipboardError) {
                    throw new Error("剪贴板访问被拒绝,请允许页面访问剪贴板权限");
                }

                if (!clipboardText) {
                    throw new Error("剪贴板为空,请先复制IID内容");
                }
                const original_iid = clipboardText.trim();
                status.textContent = "✅ 校验IID合法性...";
                showToast("正在校验IID合法性", "info");

                // 修复:兼容旧版JS的空值处理
                let aB = t => (t == null ? "" : t.replace(/[^a-zA-Z0-9]/g, "")) || "";
                const iid = aB(original_iid);

                // 第一步:校验IID合法性
                const validateResult = validateIID(iid);
                if (!validateResult.valid) {
                    // 获取错误提示文本
                    const errorInfo = getErrorText(validateResult);
                    // 显示精准的错误提示
                    showFloatTip(errorInfo.mainText, errorInfo.detailText, original_iid);
                    showToast(errorInfo.mainText, "error");
                    // 恢复按钮状态
                    resetButton();
                    return; // 终止后续流程
                }

                // IID合法,继续发送请求
                status.textContent = "📡 发送请求中...";
                showToast("IID验证通过,正在发送请求", "info");
                const result = await sendActivationRequest(iid);

                // 显示成功提示
                showToast("请求成功!结果已复制到剪贴板", "success");
                showFloatTip(
                    "✅ 请求成功!结果已复制到剪贴板",
                    "响应数据如下,已自动复制到剪贴板",
                    result,
                    "success",
                    5000
                );

                // 将结果复制到剪贴板
                GM_setClipboard(JSON.stringify(result, null, 2), "text");

                // 更新状态提示并恢复按钮
                resetButton("获取确认ID", "✅ 结果已复制到剪贴板");
                // 延迟重置状态(仅成功场景)
                setTimeout(() => {
                    status.textContent = "✅ 就绪";
                }, 3000);

            } catch (error) {
                // 处理所有类型的错误,确保按钮恢复
                console.error("操作失败:", error);
                // 显示错误提示
                showToast(error.message, "error");
                showFloatTip(
                    "❌ 操作失败",
                    error.message,
                    "",
                    "error",
                    5000
                );
                // 恢复按钮状态
                resetButton("重新获取", `❌ 失败: ${error.message}`);
            } finally {
                // 仅在错误状态下延迟重置(避免覆盖成功提示)
                if (btn.textContent.includes("重新获取")) {
                    setTimeout(() => {
                        status.textContent = "✅ 就绪";
                    }, 5000);
                }
            }
        });

        // 7. 将面板添加到页面
        document.body.appendChild(panel);
        console.info("✅ 微软激活ID获取面板已启用(美化版)");
    }

    // 页面加载完成后创建悬浮面板
    if (document.readyState === "complete" || document.readyState === "interactive") {
        createFloatPanel();
    } else {
        document.addEventListener("DOMContentLoaded", createFloatPanel);
    }

})();