英国优惠码出来的也不便宜啊。你们是怎么做到的


其他人都是 11 磅,这个 18 磅的话,就等于是 170 块人民币左右了

5 个赞

老哥英国的team车停了,等下次吧

2 个赞

这就是刚才找的呀,只是和土区没有什么优势。我已经有土区 plus 了

:rofl: :rofl:刚开通成功。 我运气真好啊,11欧元开的。

2 个赞

他说的11磅的没了,那个两个位置才100

2 个赞

有码子可以分享一下吗~求求了 是一晚上了

1 个赞

老哥用了什么码呀,求求求求,急死了

相当于100两个team子号吗?一个月?连续48个月都是这个价格是吧

1 个赞

主号和一个子号,连续48个月,如果openai不改的话

哦哦哦,那如果中间有一个月断了不相续也没关系吗,反正48个月内,想续都是11刀咯

  1. 代码直接贴到油猴(tampermonkey)中
  2. 这个帖子中的优惠码还可以用,https://linux.do/t/topic/2149874
  3. IP 正确,使用优惠链接就会直接弹出付费框
// ==UserScript==
// @name         ChatGPT Team 支付长链接生成器
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  在 ChatGPT 页面右下角添加悬浮按钮,一键生成 Team 计划支付链接。左键生成,右键设置。
// @author       Qingyu
// @match        https://chatgpt.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @run-at       document-end
// ==/UserScript==


(function() {
    'use strict';

    // ================= 配置管理 =================
    const STORAGE_KEYS = { PROMO: 'team_promo_v2', CANCEL: 'team_cancel_v2' };
    const getConfig = () => ({
        promoCode: GM_getValue(STORAGE_KEYS.PROMO, 'codestonegb'),
        cancelUrl: GM_getValue(STORAGE_KEYS.CANCEL, 'https://chatgpt.com/#team-pricing')
    });

    // ================= SVG 图标 =================
    const ICONS = {
        link: '<svg size="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.812a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"></path></svg>',
        check: '<svg size="16" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24"><path d="M5 13l4 4L19 7"></path></svg>',
        x: '<svg size="16" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24"><path d="M6 18L18 6M6 6l12 12"></path></svg>',
        config: '<svg size="20" fill="none" stroke="#6e6e80" stroke-width="2" viewBox="0 0 24 24"><path d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path><circle cx="12" cy="12" r="3"></circle></svg>'
    };

    // ================= 样式注入 =================
    const injectStyles = () => {
        const style = document.createElement('style');
        style.textContent = `
            /* 主按钮 */
            #tm-pro-btn {
                position: fixed; bottom: 24px; right: 24px; z-index: 10000;
                padding: 10px 20px;
                background: linear-gradient(135deg, #10a37f 0%, #15be93 100%);
                color: white; border-radius: 20px;
                cursor: pointer; font-size: 14px; font-weight: 600;
                font-family: Söhne, ui-sans-serif, system-ui, sans-serif;
                box-shadow: 0 4px 15px rgba(16, 163, 127, 0.3);
                user-select: none; transition: all 0.2s cubic-bezier(0.2, 0, 0, 1);
                display: flex; align-items: center; gap: 8px; overflow: hidden;
            }
            #tm-pro-btn svg { width: 16px; height: 16px; transition: transform 0.2s; }
            #tm-pro-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 6px 20px rgba(16, 163, 127, 0.4);
            }
            #tm-pro-btn:hover svg { transform: rotate(15deg); }
            #tm-pro-btn:active { transform: translateY(0px) scale(0.97); }

            /* 加载动画 */
            #tm-pro-btn.loading { background: #6e6e80; cursor: not-allowed; box-shadow: none; }
            #tm-pro-btn.loading svg { animation: spin 1s linear infinite; }
            @keyframes spin { 100% { transform: rotate(360deg); } }

            #tm-pro-btn.loading::after {
                content: ''; position: absolute; top: 0; left: -100%; width: 200%; height: 100%;
                background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.2) 50%, transparent 100%);
                animation: loading-wave 1.5s infinite;
            }
            @keyframes loading-wave { 0% { left: -100%; } 100% { left: 100%; } }

            #tm-pro-btn.success { background: #19c37d; }
            #tm-pro-btn.error { background: #ef4444; }

            /* 配置模态窗 */
            #tm-config-overlay {
                position: fixed; top: 0; left: 0; width: 100%; height: 100%;
                background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(4px);
                z-index: 10001; display: none; justify-content: center; align-items: center;
                opacity: 0; transition: opacity 0.2s;
            }
            #tm-config-overlay.open { display: flex; opacity: 1; }

            #tm-config-modal {
                background: #fff; width: 400px; padding: 24px; border-radius: 12px;
                box-shadow: 0 10px 30px rgba(0,0,0,0.2);
                transform: scale(0.9); transition: transform 0.2s cubic-bezier(0.2, 0, 0, 1);
                color: #333; font-family: sans-serif;
            }
            .dark #tm-config-modal { background: #202123; color: #ececf1; }
            #tm-config-overlay.open #tm-config-modal { transform: scale(1); }

            .tm-modal-header { display: flex; align-items: center; gap: 10px; margin-bottom: 20px; font-weight: bold; font-size: 18px; }

            .tm-form-group { margin-bottom: 16px; }
            .tm-label { display: block; margin-bottom: 6px; font-size: 13px; color: #6e6e80; }
            .dark .tm-label { color: #8e8e93; }
            .tm-input {
                width: 100%; padding: 10px 12px; border: 1px solid #ddd; border-radius: 6px;
                background: #fff; color: #000; font-size: 14px; box-sizing: border-box;
            }
            .tm-input:focus { outline: 2px solid #10a37f; border-color: transparent; }
            .dark .tm-input { background: #343541; border-color: #444654; color: #fff; }

            .tm-modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 24px; }
            .tm-btn { padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 500; border: none; }
            .tm-btn-cancel { background: #eee; color: #333; }
            .tm-btn-cancel:hover { background: #ddd; }
            .dark .tm-btn-cancel { background: #444654; color: #ececf1; }
            .dark .tm-btn-cancel:hover { background: #545664; }
            .tm-btn-save { background: #10a37f; color: white; }
            .tm-btn-save:hover { background: #1a7f64; }
        `;
        document.head.appendChild(style);
    };

    // ================= UI 创建 =================
    let overlay, promoInput, cancelInput;

    const createUI = () => {
        // 1. 创建主按钮
        const btn = document.createElement('div');
        btn.id = 'tm-pro-btn';
        btn.innerHTML = `${ICONS.link}<span id="tm-pro-text">生成 Team 链接</span>`;
        document.body.appendChild(btn);

        // 2. 创建配置模态窗
        overlay = document.createElement('div');
        overlay.id = 'tm-config-overlay';
        overlay.innerHTML = `
            <div id="tm-config-modal">
                <div class="tm-modal-header">${ICONS.config} 链接参数设置</div>
                <div class="tm-form-group">
                    <label class="tm-label">优惠码</label>
                    <input type="text" id="tm-input-promo" class="tm-input" placeholder="codestonegb">
                </div>
                <div class="tm-form-group">
                    <label class="tm-label">取消支付跳转</label>
                    <input type="text" id="tm-input-cancel" class="tm-input" placeholder="https://chatgpt.com/#team-pricing">
                </div>
                <div class="tm-modal-actions">
                    <button class="tm-btn tm-btn-cancel" id="tm-config-close">取消</button>
                    <button class="tm-btn tm-btn-save" id="tm-config-save">保存</button>
                </div>
            </div>
        `;
        document.body.appendChild(overlay);

        promoInput = document.getElementById('tm-input-promo');
        cancelInput = document.getElementById('tm-input-cancel');

        return btn;
    };

    // ================= 交互逻辑 =================
    const showConfig = () => {
        const config = getConfig();
        promoInput.value = config.promoCode;
        cancelInput.value = config.cancelUrl;
        overlay.classList.add('open');
    };

    const hideConfig = () => { overlay.classList.remove('open'); };

    const saveConfig = () => {
        GM_setValue(STORAGE_KEYS.PROMO, promoInput.value.trim());
        GM_setValue(STORAGE_KEYS.CANCEL, cancelInput.value.trim());
        hideConfig();
        showStatus('success', '配置已保存');
    };

    const setButtonState = (btn, text, state) => {
        const textSpan = btn.querySelector('#tm-pro-text');
        textSpan.innerText = text;
        btn.className = ''; // 移除 loading, success, error

        if (state === 'loading') {
            btn.classList.add('loading');
            btn.innerHTML = `<svg class="animate-spin" size="16" fill="none" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" style="opacity:0.25"></circle><path fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg><span id="tm-pro-text">${text}</span>`;
        } else if (state === 'success') {
            btn.classList.add('success');
            btn.innerHTML = `${ICONS.check}<span id="tm-pro-text">${text}</span>`;
        } else if (state === 'error') {
            btn.classList.add('error');
            btn.innerHTML = `${ICONS.x}<span id="tm-pro-text">${text}</span>`;
        } else {
            btn.innerHTML = `${ICONS.link}<span id="tm-pro-text">${text}</span>`;
        }
    };

    // 临时状态显示
    const showStatus = (state, text) => {
        const btn = document.getElementById('tm-pro-btn');
        const oldText = getConfig().promoCode;
        setButtonState(btn, text, state);
        setTimeout(() => setButtonState(btn, `生成 Team 链接`, 'normal'), 2000);
    };


    // ================= 核心请求 =================
    async function run(e) {
        const btn = e.currentTarget;
        if (btn.classList.contains('loading')) return;

        const config = getConfig();
        setButtonState(btn, '正在获取 Token...', 'loading');

        try {
            const session = await fetch("/api/auth/session").then(r => r.json()).catch(()=>({}));
            const token = session?.accessToken;
            if (!token) throw new Error("请先登录 ChatGPT");

            setButtonState(btn, '正在请求 Stripe...', 'loading');

            const res = await fetch("https://chatgpt.com/backend-api/payments/checkout", {
                method: "POST",
                headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
                body: JSON.stringify({
                    plan_name: "chatgptteamplan",
                    team_plan_data: { workspace_name: "MyTeam", price_interval: "month", seat_quantity: 2 },
                    billing_details: { country: "GB", currency: "GBP" },
                    cancel_url: config.cancelUrl,
                    promo_code: config.promoCode,
                    checkout_ui_mode: "hosted",
                }),
            });

            const data = await res.json();
            const url = data?.url || data?.stripe_hosted_url || data?.checkout_url;

            if (url) {
                setButtonState(btn, '生成成功!准备跳转', 'success');
                setTimeout(() => {
                    const go = window.confirm(`✅ 生成成功!Promo: ${config.promoCode}\n\n点击“确定”将在当前页跳转至支付页面。\n点击“取消”复制链接。`);
                    if (go) window.location.href = url;
                    else window.prompt("请复制链接:", url);
                    setButtonState(btn, '生成 Team 链接', 'normal');
                }, 200);
            } else {
                throw new Error(data?.detail || "响应未包含链接");
            }
        } catch (e) {
            setButtonState(btn, '失败: ' + e.message, 'error');
            setTimeout(() => setButtonState(btn, '生成 Team 链接', 'normal'), 3000);
        }
    }

    // ================= 初始化 =================
    injectStyles();
    const proBtn = createUI();

    // 事件绑定
    proBtn.addEventListener('click', run);
    proBtn.addEventListener('contextmenu', (e) => {
        e.preventDefault();
        showConfig();
    });

    document.getElementById('tm-config-close').addEventListener('click', hideConfig);
    document.getElementById('tm-config-save').addEventListener('click', saveConfig);
    // 点击遮罩层关闭
    overlay.addEventListener('click', (e) => {
        if (e.target === overlay) hideConfig();
    });
    // 快捷键 Esc 关闭
    document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape' && overlay.classList.contains('open')) hideConfig();
    });

})();
2 个赞

11英镑的优惠码今天下午晚上用完了,我也没赶上,开了美区的。18英镑确实不划算了,不如美区20刀的

2 个赞

佬,请问按照这个搞出来,是多少钱的啊。

现在英区好像已经涨价了,昨天没有赶上可惜了