mirror of
https://github.com/Silentely/eSIM-Tools.git
synced 2026-09-03 06:24:20 +08:00
- 将 giffgaff 和 Simyo 页面的国际化初始化内联脚本提取为独立的 `init-i18n.js` 模块 - 将通知系统初始化内联脚本提取为独立的 `init-notification.js` 模块 - 移除 docs 目录下的 ARCHITECTURE.md 和 FUTURE_ARCHITECTURE.md 过期架构文档 - 更新 giffgaff_modular.html 和 simyo_modular.html 以引用新的独立脚本模块
890 lines
54 KiB
HTML
890 lines
54 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN" data-page="giffgaff">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<meta name="color-scheme" content="light dark" />
|
||
<meta name="description" content="Giffgaff eSIM 工具,支持 OAuth 登录、MFA 验证、二维码生成与设备更换。">
|
||
|
||
<!-- Sentry 错误监控配置(必须在其他脚本之前) -->
|
||
<!-- 使用外链脚本以符合 CSP 策略 -->
|
||
<script src="/src/js/sentry-config.js"></script>
|
||
<script src="/src/js/sentry-loader.js"></script>
|
||
|
||
<!-- 预连接优化 -->
|
||
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
|
||
<link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin>
|
||
<link rel="preconnect" href="https://browser.sentry-cdn.com" crossorigin>
|
||
<link rel="preconnect" href="https://qrcode.show" crossorigin>
|
||
<link rel="preconnect" href="https://api.giffgaff.com" crossorigin>
|
||
<link rel="preconnect" href="https://id.giffgaff.com" crossorigin>
|
||
<link rel="preconnect" href="https://publicapi.giffgaff.com" crossorigin>
|
||
|
||
<!-- CSP策略 -->
|
||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-eval' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://browser.sentry-cdn.com https://www.google.com https://www.gstatic.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://fonts.googleapis.com; font-src 'self' data: https://cdnjs.cloudflare.com https://fonts.gstatic.com; connect-src 'self' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://browser.sentry-cdn.com https://www.google-analytics.com https://www.googletagmanager.com https://qrcode.show https://api.qrserver.com https://appapi.simyo.nl https://api.giffgaff.com https://id.giffgaff.com https://publicapi.giffgaff.com https://www.google.com https://www.gstatic.com https://*.sentry.io; img-src 'self' data: https:; frame-src 'self' https://www.google.com;">
|
||
|
||
<title>Giffgaff eSIM 工具</title>
|
||
<link rel="manifest" href="/manifest.webmanifest">
|
||
<meta name="theme-color" content="#ffcc00">
|
||
<link rel="icon" href="/src/assets/favicon.ico" type="image/x-icon">
|
||
|
||
<!-- 外部样式 -->
|
||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
|
||
<link rel="stylesheet" href="/src/assets/fontawesome/all.min.css">
|
||
|
||
<!-- 共享设计系统 -->
|
||
<link rel="stylesheet" href="/src/styles/design-system.css">
|
||
<link rel="stylesheet" href="/src/styles/animations.css">
|
||
|
||
<!-- Giffgaff专用样式 -->
|
||
<link rel="stylesheet" href="/src/giffgaff/styles/giffgaff-base.css">
|
||
<link rel="stylesheet" href="/src/giffgaff/styles/giffgaff-components.css">
|
||
<link rel="stylesheet" href="/src/giffgaff/styles/giffgaff-service-time.css">
|
||
<link rel="stylesheet" href="/src/giffgaff/styles/giffgaff-animations.css">
|
||
<link rel="stylesheet" href="/src/giffgaff/styles/giffgaff-responsive.css">
|
||
<link rel="stylesheet" href="/src/styles/notification.css">
|
||
|
||
</head>
|
||
<body aria-label="Giffgaff eSIM 工具">
|
||
<div class="container main-container">
|
||
<!-- 应用头部 -->
|
||
<div class="app-header">
|
||
<div class="logo-container">
|
||
<i class="fas fa-sim-card app-icon" aria-hidden="true"></i>
|
||
<div class="app-title">
|
||
<span class="lang-zh">Giffgaff eSIM工具</span>
|
||
<span class="lang-en">Giffgaff eSIM Tool</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="header-buttons">
|
||
<div class="language-switcher">
|
||
<button id="languageSwitcher" class="lang-switch" type="button" aria-label="切换语言到英文">🌐 English</button>
|
||
</div>
|
||
<a id="tutorialBtn" class="login-btn" href="https://github.com/Silentely/eSIM-Tools/blob/main/docs/User_Guide.md" target="_blank" rel="noopener noreferrer" aria-label="查看教程">
|
||
<i class="fas fa-book" aria-hidden="true"></i>
|
||
<span class="lang-zh">查看教程</span>
|
||
<span class="lang-en">View Tutorial</span>
|
||
</a>
|
||
<a href="https://github.com/Silentely/eSIM-Tools" target="_blank" class="github-btn" aria-label="打开GitHub仓库">
|
||
<i class="fab fa-github" aria-hidden="true"></i> GitHub
|
||
</a>
|
||
<a href="https://ko-fi.com/debug402" target="_blank" rel="noopener noreferrer" class="kofi-btn" aria-label="通过 Ko-fi 赞助我">
|
||
<i class="fas fa-coffee" aria-hidden="true"></i> <span>赞助我</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 新用户提示 -->
|
||
<div class="new-user-notice reveal">
|
||
<span class="lang-zh">
|
||
<span class="notice-line1"><i class="fas fa-exclamation-circle" aria-hidden="true"></i> 本工具仅支持已有 Giffgaff 号码的用户,</span>
|
||
<span class="notice-line2">支持实体卡转 eSIM、eSIM 换设备、已支付 £10 直取 eSIM。新用户(未有号码)无法使用,如需开卡请点击下方链接。</span>
|
||
</span>
|
||
<span class="lang-en">
|
||
<span class="notice-line1"><i class="fas fa-exclamation-circle" aria-hidden="true"></i> This tool supports existing Giffgaff users only:</span>
|
||
<span class="notice-line2">SIM-to-eSIM conversion, eSIM device change, and direct eSIM fetch for £10 paid users. New users without a number cannot use it. Click the link below to get started.</span>
|
||
</span>
|
||
</div>
|
||
|
||
<!-- 开卡推广 -->
|
||
<div class="promo-banner reveal">
|
||
<div class="promo-content">
|
||
<i class="fas fa-gift promo-icon"></i>
|
||
<span class="promo-text">
|
||
<span class="lang-zh">
|
||
如果您还没有Giffgaff账户,可以
|
||
<a href="https://www.giffgaff.com/orders/affiliate/mowal44_1653194386268" target="_blank" class="promo-link">
|
||
点击这里开卡
|
||
</a>
|
||
,享受额外5英镑话费赠送!
|
||
</span>
|
||
<span class="lang-en">
|
||
New to Giffgaff?
|
||
<a href="https://www.giffgaff.com/orders/affiliate/mowal44_1653194386268" target="_blank" class="promo-link">
|
||
order here
|
||
</a>
|
||
to receive an extra £5 credit!
|
||
</span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 页面标题 -->
|
||
<div class="page-title reveal">
|
||
<h1>
|
||
<span class="lang-zh">Giffgaff eSIM 工具</span>
|
||
<span class="lang-en">Giffgaff eSIM Tool</span>
|
||
</h1>
|
||
<p>
|
||
<span class="lang-zh">将您的实体 SIM 卡转换为 eSIM,或在设备间切换 eSIM</span>
|
||
<span class="lang-en">Convert your physical SIM to eSIM, or switch eSIM between devices</span>
|
||
</p>
|
||
<div id="modeBadge" class="mode-badge" style="display:none" aria-live="polite">
|
||
<i class="fas fa-exchange-alt" aria-hidden="true"></i>
|
||
<span class="lang-zh">设备更换模式</span>
|
||
<span class="lang-en">Device change mode</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 服务时间提示 -->
|
||
<div id="serviceTimeAlert" class="alert mb-4 service-time-alert">
|
||
<div class="service-time-grid">
|
||
<div class="service-time-left">
|
||
<div class="service-time-header">
|
||
<div id="actionMessage" class="service-time-action-badge" style="display: none;"></div>
|
||
</div>
|
||
<div class="service-time-body">
|
||
<div class="service-time-layout">
|
||
<div class="service-time-icon-section">
|
||
<i id="serviceTimeIcon" class="fas" aria-hidden="true"></i>
|
||
</div>
|
||
<div class="service-time-content-section">
|
||
<div class="service-time-title">
|
||
<span class="lang-zh">服务时间提醒:</span>
|
||
<span class="lang-en">Service window reminder:</span>
|
||
</div>
|
||
<div id="serviceTimeMessage" class="service-time-message">
|
||
<span class="lang-zh">当前时间在服务时间外,Giffgaff官方在英国时间04:30至21:30之间提供SIM交换服务。</span>
|
||
<span class="lang-en">Outside of service hours. Giffgaff processes SIM swaps between 04:30 and 21:30 UK time.</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="current-time-card" aria-label="当前时间">
|
||
<div class="time-card-icon">
|
||
<i class="fas fa-clock" aria-hidden="true"></i>
|
||
</div>
|
||
<div class="time-card-text">
|
||
<div class="time-card-label">
|
||
<span class="lang-zh">当前时间</span>
|
||
<span class="lang-en">Current time</span>
|
||
</div>
|
||
<div id="currentTime" class="time-card-value">--:--</div>
|
||
<div id="ukTimeHint" class="time-card-hint">
|
||
<span class="lang-zh">英国时间 --:--</span>
|
||
<span class="lang-en">UK time --:--</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 状态显示面板 -->
|
||
<div class="status-panel card-elevated reveal" role="status" aria-live="polite">
|
||
<details open>
|
||
<summary class="d-flex align-items-center justify-content-between" style="cursor: pointer; list-style: none;">
|
||
<h3>
|
||
<i class="fas fa-info-circle" aria-hidden="true"></i>
|
||
<span class="lang-zh">当前状态</span>
|
||
<span class="lang-en">Current status</span>
|
||
</h3>
|
||
<i class="fas fa-chevron-down text-muted"></i>
|
||
</summary>
|
||
<div class="status-grid mt-3">
|
||
<div class="status-item">
|
||
<span class="status-label">
|
||
<span class="lang-zh">当前模式:</span>
|
||
<span class="lang-en">Current mode:</span>
|
||
</span>
|
||
<span id="statusMode" class="status-value connected">标准流程</span>
|
||
</div>
|
||
<div class="status-item">
|
||
<span class="status-label">
|
||
<span class="lang-zh">Access Token:</span>
|
||
<span class="lang-en">Access Token:</span>
|
||
</span>
|
||
<span id="statusAccessToken" class="status-value disconnected">未登录</span>
|
||
</div>
|
||
<div class="status-item">
|
||
<span class="status-label">
|
||
<span class="lang-zh">MFA 签名:</span>
|
||
<span class="lang-en">MFA signature:</span>
|
||
</span>
|
||
<span id="statusMfaSignature" class="status-value disconnected">未验证</span>
|
||
</div>
|
||
<div class="status-item">
|
||
<span class="status-label">
|
||
<span class="lang-zh">会员ID:</span>
|
||
<span class="lang-en">Member ID:</span>
|
||
</span>
|
||
<span id="statusMemberId" class="status-value disconnected">未获取</span>
|
||
</div>
|
||
<div class="status-item">
|
||
<span class="status-label">
|
||
<span class="lang-zh">eSIM状态:</span>
|
||
<span class="lang-en">eSIM status:</span>
|
||
</span>
|
||
<span id="statusEsimStatus" class="status-value disconnected">
|
||
<span id="esimStatusValue"></span><br>
|
||
<span id="esimStatusPhoneSuffix"></span>
|
||
</span>
|
||
</div>
|
||
<div class="status-item">
|
||
<span class="status-label">
|
||
<span class="lang-zh">激活码:</span>
|
||
<span class="lang-en">Activation code:</span>
|
||
</span>
|
||
<span id="statusActivationCode" class="status-value disconnected">
|
||
<span id="activationCodeValue"></span><br>
|
||
<span id="activationCodeSSN"></span>
|
||
</span>
|
||
</div>
|
||
<div class="status-item">
|
||
<span class="status-label">
|
||
<span class="lang-zh">LPA字符串:</span>
|
||
<span class="lang-en">LPA string:</span>
|
||
</span>
|
||
<span id="statusLpaString" class="status-value disconnected">未生成</span>
|
||
</div>
|
||
</div>
|
||
<button id="clearSessionBtn" class="clear-session-btn" aria-label="清除会话并重置所有进度">
|
||
<i class="fas fa-trash-alt" aria-hidden="true"></i>
|
||
<span class="lang-zh">清除会话</span>
|
||
<span class="lang-en">Clear session</span>
|
||
</button>
|
||
</details>
|
||
</div>
|
||
|
||
<!-- 步骤指示器 -->
|
||
<div class="step-indicator reveal" role="list" aria-label="进度步骤">
|
||
<div class="step active" role="listitem" aria-current="step" data-step="1">
|
||
<div class="step-number" aria-hidden="true">1</div>
|
||
<div class="step-text">
|
||
<span class="lang-zh">OAuth登录</span>
|
||
<span class="lang-en">OAuth login</span>
|
||
</div>
|
||
</div>
|
||
<div class="step" data-step="2">
|
||
<div class="step-number">2</div>
|
||
<div class="step-text">
|
||
<span class="lang-zh">邮件验证</span>
|
||
<span class="lang-en">Email verification</span>
|
||
</div>
|
||
</div>
|
||
<div class="step" data-step="3">
|
||
<div class="step-number">3</div>
|
||
<div class="step-text">
|
||
<span class="lang-zh">会员信息</span>
|
||
<span class="lang-en">Member info</span>
|
||
</div>
|
||
</div>
|
||
<div class="step" data-step="4">
|
||
<div class="step-number">4</div>
|
||
<div class="step-text">
|
||
<span class="lang-zh">转换 eSIM</span>
|
||
<span class="lang-en">Reserve eSIM</span>
|
||
</div>
|
||
</div>
|
||
<div class="step" data-step="5">
|
||
<div class="step-number">5</div>
|
||
<div class="step-text">
|
||
<span class="lang-zh">获取二维码</span>
|
||
<span class="lang-en">Get QR code</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 步骤1: 选择登录方式 -->
|
||
<div id="step1" class="section active reveal">
|
||
<div class="card card-elevated">
|
||
<div class="card-header">
|
||
<i class="fas fa-key"></i>
|
||
<span class="lang-zh"> 第一步:选择登录方式</span>
|
||
<span class="lang-en"> Step 1: Choose a login method</span>
|
||
</div>
|
||
<div class="card-body">
|
||
<p class="mb-4 lang-zh" style="font-size: 17px; color: #212529;">
|
||
请选择您偏好的登录方式:
|
||
</p>
|
||
<p class="mb-4 lang-en" style="font-size: 17px; color: #212529;">
|
||
Pick the login method you prefer:
|
||
</p>
|
||
|
||
<div class="row row-cols-1 row-cols-md-2 g-3">
|
||
<div class="col">
|
||
<div id="oauthCard" class="card h-100" style="cursor: pointer;" role="button" tabindex="0" aria-label="选择 OAuth 登录">
|
||
<div class="card-body text-center">
|
||
<i class="fas fa-shield-alt fa-3x mb-3" style="color: var(--primary);"></i>
|
||
<h5>
|
||
<span class="lang-zh">OAuth 2.0 登录</span>
|
||
<span class="lang-en">OAuth 2.0 login</span>
|
||
</h5>
|
||
<p class="text-muted">
|
||
<span class="lang-zh">安全的官方认证方式</span>
|
||
<span class="lang-en">Secure official authentication</span>
|
||
</p>
|
||
<small class="text-success">
|
||
<span class="lang-zh">✓ 推荐使用</span>
|
||
<span class="lang-en">✓ Recommended</span>
|
||
</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col">
|
||
<div id="cookieCard" class="card h-100 disabled" style="cursor: not-allowed; opacity: 0.5; pointer-events: none; background-color: #f8f9fa;" aria-label="Cookie 登录暂不可用" aria-disabled="true">
|
||
<div class="card-body text-center">
|
||
<i class="fas fa-cookie-bite fa-3x mb-3" style="color: #adb5bd;"></i>
|
||
<h5 style="color: #6c757d;">
|
||
<span class="lang-zh">Cookie 登录</span>
|
||
<span class="lang-en">Cookie login</span>
|
||
</h5>
|
||
<p class="text-muted">
|
||
<span class="lang-zh">使用已有登录Cookie</span>
|
||
<span class="lang-en">Use an existing session cookie</span>
|
||
</p>
|
||
<small class="text-danger">
|
||
<span class="lang-zh">⚠ 暂无法使用</span>
|
||
<span class="lang-en">⚠ Temporarily unavailable</span>
|
||
</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="loginMethodStatus" class="status"></div>
|
||
|
||
<!-- OAuth登录区域 -->
|
||
<div id="oauthLoginSection" class="mt-4" style="display: none;">
|
||
<h5 class="mb-3">
|
||
<span class="lang-zh">OAuth 2.0 登录</span>
|
||
<span class="lang-en">OAuth 2.0 login</span>
|
||
</h5>
|
||
|
||
<div class="alert alert-danger mb-4">
|
||
<h6 class="lang-zh"><i class="fas fa-exclamation-triangle me-2"></i>⚠️ 重要:OAuth 登录前置条件</h6>
|
||
<h6 class="lang-en"><i class="fas fa-exclamation-triangle me-2"></i>⚠️ Important: OAuth Login Prerequisites</h6>
|
||
<div class="lang-zh">
|
||
<p class="mb-2"><strong>在点击下方"开始OAuth登录"按钮之前,您必须先完成以下步骤:</strong></p>
|
||
<ol class="mb-2">
|
||
<li><strong>访问 <a href="https://www.giffgaff.com" target="_blank" rel="noopener noreferrer" class="text-dark text-decoration-underline">giffgaff.com</a></strong> 并登录您的账户</li>
|
||
<li><strong>确保登录状态有效</strong>(可以看到您的账户信息)</li>
|
||
<li><strong>保持该标签页打开</strong>,然后返回本页面</li>
|
||
</ol>
|
||
<p class="mb-0"><small><i class="fas fa-info-circle me-1"></i><strong>为什么需要这样做?</strong> Giffgaff 现在要求用户必须先在官网登录,才能通过 OAuth 授权。如果未登录就点击 OAuth 登录,将无法获取回调 URL。</small></p>
|
||
</div>
|
||
<div class="lang-en">
|
||
<p class="mb-2"><strong>Before clicking "Start OAuth Login" below, you MUST complete these steps first:</strong></p>
|
||
<ol class="mb-2">
|
||
<li><strong>Visit <a href="https://www.giffgaff.com" target="_blank" rel="noopener noreferrer" class="text-dark text-decoration-underline">giffgaff.com</a></strong> and log in to your account</li>
|
||
<li><strong>Ensure your login session is active</strong> (you can see your account info)</li>
|
||
<li><strong>Keep that tab open</strong>, then return to this page</li>
|
||
</ol>
|
||
<p class="mb-0"><small><i class="fas fa-info-circle me-1"></i><strong>Why is this required?</strong> Giffgaff now requires users to be logged in on their website before OAuth authorization. Without prior login, you won't be able to capture the callback URL.</small></p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="alert alert-warning mb-4">
|
||
<h6 class="lang-zh"><i class="fas fa-laptop-code me-2"></i>如何获取回调URL:</h6>
|
||
<h6 class="lang-en"><i class="fas fa-laptop-code me-2"></i>How to capture the callback URL:</h6>
|
||
<ol class="mb-2 lang-zh">
|
||
<li><strong>打开开发者工具</strong>:按 F12 或右键选择"检查"</li>
|
||
<li><strong>切换到"控制台"(Console)标签页</strong></li>
|
||
<li><strong>点击下方"开始OAuth登录"按钮</strong>,新窗口打开后切换回本页面(eSIM-Tools 工具页面)</li>
|
||
<li><strong>在控制台中查找</strong>错误信息:<code>Failed to launch 'giffgaff://auth/callback/...'</code></li>
|
||
<li><strong>复制完整的回调URL</strong>(从 <code>giffgaff://</code> 开始到末尾)并粘贴到下方输入框</li>
|
||
</ol>
|
||
<ol class="mb-2 lang-en">
|
||
<li><strong>Open DevTools</strong>: press F12 or right-click → "Inspect"</li>
|
||
<li><strong>Switch to the "Console" tab</strong></li>
|
||
<li><strong>Click "Start OAuth Login" below</strong> After the new window opens, switch back to this page (the eSIM-Tools page).</li>
|
||
<li><strong>Look for the error message</strong> in Console: <code>Failed to launch 'giffgaff://auth/callback/...'</code></li>
|
||
<li><strong>Copy the full callback URL</strong> (from <code>giffgaff://</code> to the end) and paste it into the input field below</li>
|
||
</ol>
|
||
<p class="mb-0 lang-zh"><small class="text-muted">💡 提示:如果控制台没有显示回调URL,说明您未在 giffgaff.com 登录。请退出并重新登录 giffgaff.com,然后重新开始 OAuth 流程。</small></p>
|
||
<p class="mb-0 lang-en"><small class="text-muted">💡 Tip: If the callback URL doesn't appear in Console, you're not logged in at giffgaff.com. Please log out and log back in at giffgaff.com, then restart the OAuth flow.</small></p>
|
||
</div>
|
||
|
||
<div class="alert alert-info mb-4">
|
||
<h6 class="lang-zh"><i class="fas fa-info-circle me-2"></i>回调URL格式示例:</h6>
|
||
<h6 class="lang-en"><i class="fas fa-info-circle me-2"></i>Example callback URL:</h6>
|
||
<div class="lang-zh">
|
||
<p class="mb-2"><strong>控制台错误信息示例:</strong></p>
|
||
<p class="mb-2"><code>Failed to launch 'giffgaff://auth/callback/?code=Na22kPkMt3JoLW-w&state=TGo2ljM-2HRt21DaVBxYuw' because the scheme does not have a registered handler.</code></p>
|
||
<p class="mb-2"><strong>您需要复制的部分:</strong></p>
|
||
<p class="mb-2"><code>giffgaff://auth/callback/?code=Na22kPkMt3JoLW-w&state=TGo2ljM-2HRt21DaVBxYuw</code></p>
|
||
<p class="mb-0"><small class="text-muted">✓ 确保URL包含 <code>code</code> 和 <code>state</code> 参数</small></p>
|
||
</div>
|
||
<div class="lang-en">
|
||
<p class="mb-2"><strong>Example Console error message:</strong></p>
|
||
<p class="mb-2"><code>Failed to launch 'giffgaff://auth/callback/?code=Na22kPkMt3JoLW-w&state=TGo2ljM-2HRt21DaVBxYuw' because the scheme does not have a registered handler.</code></p>
|
||
<p class="mb-2"><strong>What you need to copy:</strong></p>
|
||
<p class="mb-2"><code>giffgaff://auth/callback/?code=Na22kPkMt3JoLW-w&state=TGo2ljM-2HRt21DaVBxYuw</code></p>
|
||
<p class="mb-0"><small class="text-muted">✓ Make sure the URL includes the <code>code</code> and <code>state</code> parameters</small></p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="btn-group">
|
||
<button id="oauthLoginBtn" class="btn btn-primary">
|
||
<i class="fas fa-sign-in-alt me-2"></i>
|
||
<span class="lang-zh">开始OAuth登录</span>
|
||
<span class="lang-en">Start OAuth login</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div id="oauthStatus" class="status" role="status" aria-live="polite"></div>
|
||
|
||
<!-- OAuth回调处理区域 -->
|
||
<div id="oauthCallbackSection" class="verification-section">
|
||
<div class="form-floating mb-4">
|
||
<textarea id="callbackUrl" class="form-control" placeholder="粘贴从控制台复制的完整回调URL..." style="height: 100px;"></textarea>
|
||
<label for="callbackUrl">
|
||
<span class="lang-zh">回调URL(从控制台复制)</span>
|
||
<span class="lang-en">Callback URL (from Console)</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="btn-group">
|
||
<button id="processCallbackBtn" class="btn btn-primary">
|
||
<i class="fas fa-check me-2"></i>
|
||
<span class="lang-zh">处理回调</span>
|
||
<span class="lang-en">Process callback</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div id="callbackStatus" class="status mt-4" role="status" aria-live="polite"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Cookie登录区域 -->
|
||
<div id="cookieLoginSection" class="mt-4" style="display: none;">
|
||
<h5 class="mb-3">Cookie 登录</h5>
|
||
|
||
<div class="alert alert-info mb-4">
|
||
<h6><i class="fas fa-info-circle me-2"></i>如何获取Cookie:</h6>
|
||
<ol class="mb-2">
|
||
<li><strong>访问</strong> <a href="https://www.giffgaff.com" target="_blank" rel="noopener">giffgaff.com</a> 并登录您的账户</li>
|
||
<li><strong>打开开发者工具</strong>(Chrome:F12 或 右键→检查)</li>
|
||
<li>切换到 <strong>Application</strong>(应用)/ <strong>Storage</strong>(存储)标签页</li>
|
||
<li>在左侧选择 <strong>Cookies</strong> → <code>https://www.giffgaff.com</code></li>
|
||
<li>复制右侧所有条目,拼成 <code>name=value; name2=value2; ...</code> 格式</li>
|
||
</ol>
|
||
<div class="mt-2">
|
||
<strong>或</strong> 在已登录的 <code>giffgaff.com</code> 页签,打开控制台(Console)粘贴以下代码并回车:
|
||
<pre id="cookieConsoleSnippet" class="mt-2 p-2 bg-light border rounded" style="white-space:pre-wrap;word-break:break-all;">
|
||
;(() => {
|
||
try {
|
||
const out = document.cookie.split('; ').filter(Boolean).join('; ');
|
||
console.log(out);
|
||
if (navigator.clipboard && window.isSecureContext) {
|
||
navigator.clipboard.writeText(out)
|
||
.then(() => console.log('Cookie 已复制到剪贴板'))
|
||
.catch(() => {});
|
||
}
|
||
} catch (e) {
|
||
console.log('读取 Cookie 失败:', e);
|
||
}
|
||
})();
|
||
</pre>
|
||
<div class="text-end mt-2">
|
||
<button id="copyConsoleSnippetBtn" type="button" class="btn btn-sm btn-warning text-dark">
|
||
<i class="fas fa-copy me-1"></i> 复制上方代码
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="alert alert-warning p-2 mt-2">
|
||
<small>
|
||
<i class="fas fa-exclamation-triangle me-1"></i>
|
||
安全提示:仅在可信设备上粘贴 Cookie。本工具不会存储您的 Cookie。
|
||
</small>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-floating mb-4">
|
||
<textarea id="cookieInput" class="form-control" placeholder="输入完整的Cookie字符串" style="height: 120px;"></textarea>
|
||
<label for="cookieInput">Cookie 字符串</label>
|
||
</div>
|
||
|
||
<div class="btn-group">
|
||
<button id="verifyCookieBtn" class="btn btn-warning">
|
||
<i class="fas fa-check-circle me-2"></i> 验证Cookie
|
||
</button>
|
||
</div>
|
||
|
||
<div id="cookieStatus" class="status"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 步骤2: 邮件验证 -->
|
||
<div id="step2" class="section reveal">
|
||
<div class="card card-elevated">
|
||
<div class="card-header">
|
||
<i class="fas fa-envelope"></i> 第二步:验证码验证(邮件/短信)
|
||
</div>
|
||
<div class="card-body">
|
||
<p class="mb-4" style="font-size: 17px; color: #212529;">
|
||
我们需要发送验证码到您的邮箱或手机进行身份验证:
|
||
</p>
|
||
|
||
<div class="row g-3 align-items-end mb-2">
|
||
<div class="col-sm-6">
|
||
<label for="mfaChannelSelect" class="form-label">验证码接收方式</label>
|
||
<select id="mfaChannelSelect" class="form-select">
|
||
<option value="EMAIL" selected>邮箱(EMAIL)</option>
|
||
<option value="TEXT">短信(TEXT)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="btn-group">
|
||
<button id="sendEmailBtn" class="btn btn-primary">
|
||
<i class="fas fa-paper-plane me-2"></i> 发送验证码
|
||
</button>
|
||
</div>
|
||
|
||
<div id="emailStatus" class="status" role="status" aria-live="polite"></div>
|
||
|
||
<!-- 验证码输入区域 -->
|
||
<div id="emailVerificationSection" class="verification-section">
|
||
<p class="mb-4" style="font-size: 17px; color: #212529; margin-top: 25px;">
|
||
请检查您的邮箱或短信并输入收到的6位验证码:
|
||
</p>
|
||
|
||
<div class="form-floating mb-4">
|
||
<input type="text" id="emailCode" class="form-control" placeholder="输入6位验证码" maxlength="6">
|
||
<label for="emailCode">验证码</label>
|
||
</div>
|
||
|
||
<div class="btn-group">
|
||
<button id="verifyEmailBtn" class="btn btn-primary">
|
||
<i class="fas fa-check me-2"></i> 验证验证码
|
||
</button>
|
||
</div>
|
||
|
||
<div id="emailVerifyStatus" class="status mt-4" role="status" aria-live="polite"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 步骤3: 获取会员信息 -->
|
||
<div id="step3" class="section reveal">
|
||
<div class="card card-elevated">
|
||
<div class="card-header">
|
||
<i class="fas fa-user"></i> 第三步:获取会员信息
|
||
</div>
|
||
<div class="card-body">
|
||
<!-- 操作前必读提示 -->
|
||
<div class="alert alert-danger mb-4" style="text-align: left; line-height: 1.8; border-left: 4px solid #dc2626; background-color: #fef2f2;">
|
||
<p class="mb-2" style="margin-bottom: 8px; font-weight: bold; font-size: 16px; color: #dc2626;">
|
||
<i class="fas fa-exclamation-circle me-2"></i>
|
||
操作前请确认
|
||
</p>
|
||
<p class="mb-2" style="margin-bottom: 8px;">本工具<strong>仅支持已有 Giffgaff 号码</strong>的用户,请在点击下方按钮前确认:</p>
|
||
<ul class="mb-2" style="margin-left: 20px; margin-bottom: 8px;">
|
||
<li><strong>实体卡转 eSIM</strong>(需已有实体 SIM 卡)</li>
|
||
<li><strong>eSIM 更换设备</strong>(需已有 eSIM 或实体卡号码)</li>
|
||
<li><strong>已支付 £10 直取 eSIM</strong>(已在官方 App 完成付款,直接拉取)</li>
|
||
</ul>
|
||
<p class="mb-2" style="margin-bottom: 8px; padding: 8px 12px; background: rgba(220, 38, 38, 0.1); border-radius: 4px;">
|
||
<i class="fas fa-times-circle me-2" style="color: #dc2626;"></i>
|
||
<strong>新用户(未有号码)无法使用本工具</strong>
|
||
</p>
|
||
<p class="mb-0">如果您还没有 Giffgaff 号码,可以
|
||
<a href="https://www.giffgaff.com/orders/affiliate/mowal44_1653194386268" target="_blank" rel="noopener noreferrer"
|
||
style="color: #dc2626; text-decoration: underline; font-weight: bold;">
|
||
点击这里开卡 <i class="fas fa-external-link-alt" style="font-size: 0.85em;"></i>
|
||
</a>
|
||
,享受额外5英镑话费赠送!
|
||
</p>
|
||
</div>
|
||
|
||
<p class="mb-4" style="font-size: 17px; color: #212529;">
|
||
获取您的Giffgaff会员信息:
|
||
</p>
|
||
|
||
<div class="btn-group">
|
||
<button id="getMemberBtn" class="btn btn-primary">
|
||
<i class="fas fa-user-circle me-2"></i> 获取会员信息
|
||
</button>
|
||
</div>
|
||
|
||
<div id="memberStatus" class="status" role="status" aria-live="polite"></div>
|
||
<div id="memberInfo" class="mt-4"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 步骤4: 转换 eSIM -->
|
||
<div id="step4" class="section reveal">
|
||
<div class="card card-elevated">
|
||
<div class="card-header">
|
||
<i class="fas fa-sim-card"></i> 第四步:转换/激活 eSIM
|
||
</div>
|
||
<div class="card-body">
|
||
<p class="mb-4" style="font-size: 17px; color: #212529;">
|
||
请选择一种方式完成 eSIM 激活:
|
||
</p>
|
||
|
||
<div class="row row-cols-1 row-cols-md-3 g-3">
|
||
<div class="col">
|
||
<div id="manualActivateCard" class="card h-100" style="cursor:not-allowed; opacity: 0.6;" role="button" tabindex="-1" aria-label="手动激活(已停用)">
|
||
<div class="card-body text-center">
|
||
<i class="fas fa-hand-point-up fa-2x mb-2"></i>
|
||
<h5 class="fw-bold">手动激活</h5>
|
||
<p class="small text-muted mb-0">实体卡转 eSIM 或设备更换,此为预订空eSIM,需手动前往官网确认激活。</p>
|
||
<div class="text-center mt-3 badge-spacer">
|
||
<span class="badge bg-danger badge-pill-cta" style="pointer-events: none;">暂停使用</span>
|
||
<div class="mt-2 small text-danger">
|
||
<i class="fas fa-info-circle me-1"></i>
|
||
<span class="lang-zh">官方已暂停此通道,请使用短信激活</span>
|
||
<span class="lang-en">Channel paused by official, use SMS activation</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col">
|
||
<div id="smsActivateCard" class="card h-100" style="cursor:pointer;" role="button" tabindex="0" aria-label="选择短信验证码激活">
|
||
<div class="card-body text-center">
|
||
<i class="fas fa-sms fa-2x mb-2"></i>
|
||
<h5 class="fw-bold">短信验证码激活</h5>
|
||
<p class="small text-muted mb-0">实体卡转 eSIM 或设备更换,输入验证码即可完成。</p>
|
||
<div class="text-center mt-3 badge-spacer">
|
||
<span class="badge bg-success text-white badge-pill-cta">✓ 推荐使用</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col">
|
||
<div id="directFetchCard" class="card h-100" style="cursor:pointer;" role="button" tabindex="0"
|
||
aria-label="已支付直取 eSIM">
|
||
<div class="card-body text-center">
|
||
<i class="fas fa-bolt fa-2x mb-2"></i>
|
||
<h5 class="fw-bold">
|
||
<span class="lang-zh">已支付直取 eSIM</span>
|
||
<span class="lang-en">Fetch eSIM directly</span>
|
||
</h5>
|
||
<p class="small text-muted mb-0">
|
||
<span class="lang-zh">已在官方 App 完成 £10 付款但未收到 eSIM,可直接拉取。</span>
|
||
<span class="lang-en">Paid £10 in the official app but no eSIM received? Fetch it directly.</span>
|
||
</p>
|
||
<div class="text-center mt-3 badge-spacer">
|
||
<span class="badge bg-info badge-pill-cta">
|
||
<span class="lang-zh">已付款用户专用</span>
|
||
<span class="lang-en">For paid users</span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 短信激活内联区域 -->
|
||
<div id="smsInlineSection" style="display:none;">
|
||
<div class="card card-body mt-3">
|
||
<div class="d-flex justify-content-between align-items-end flex-wrap gap-3">
|
||
<div style="min-width:260px;">
|
||
<label for="smsInlineChannel" class="form-label">验证码接收方式</label>
|
||
<select id="smsInlineChannel" class="form-select">
|
||
<option value="TEXT" selected>短信(TEXT)</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<button id="smsInlineSendBtn" class="btn btn-primary">
|
||
<i class="fas fa-paper-plane me-2"></i> 发送验证码
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="smsInlineStatus" class="status mt-2" role="status" aria-live="polite"></div>
|
||
|
||
<div id="smsCodeInputSection" class="mt-3" style="display:none;">
|
||
<div style="max-width:420px;">
|
||
<div class="form-floating">
|
||
<input id="smsInlineCode" type="text" class="form-control" placeholder="输入6位验证码" maxlength="6" />
|
||
<label for="smsInlineCode">短信验证码</label>
|
||
</div>
|
||
</div>
|
||
<div class="btn-group mt-3">
|
||
<button id="smsInlineVerifyBtn" class="btn btn-primary">
|
||
<i class="fas fa-check me-2"></i> 验证并继续激活
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 直取 eSIM 内联区域 -->
|
||
<div id="directFetchSection" style="display:none;">
|
||
<div class="card card-body mt-3">
|
||
<div class="alert alert-info">
|
||
<i class="fas fa-info-circle me-2"></i>
|
||
<span class="lang-zh">此选项适用于在官方 Giffgaff App 已完成 10 英镑付款,但 App 未成功生成 eSIM 的用户。将直接拉取账户上现存的 eSIM 并生成二维码(无需 reserveESim / swapSim)。</span>
|
||
<span class="lang-en">Use this option if you have already paid £10 in the official Giffgaff app but did not receive an eSIM. We will fetch any existing eSIM on the account directly and generate a QR code (no reserveESim / swapSim).</span>
|
||
</div>
|
||
<div class="alert alert-warning py-2 px-3 mb-3" style="font-size: 0.82rem; border-left: 3px solid #f72585;">
|
||
<i class="fas fa-exclamation-triangle me-1" style="color: #f72585;"></i>
|
||
<span class="lang-zh" style="color: #6c3a00;">
|
||
⚠️ 作者因条件不符未能实测此功能。如使用中遇到问题,请打开浏览器开发者工具(F12 → Console),复制完整日志后<a href="https://github.com/Silentely/eSIM-Tools/issues" target="_blank" rel="noopener noreferrer" style="color: #d63384; text-decoration: underline;">提交 Issue</a>,非常感谢!
|
||
</span>
|
||
<span class="lang-en" style="color: #6c3a00;">
|
||
⚠️ This feature could not be fully tested by the author. If you encounter issues, please open the browser console (F12 → Console), copy the full log, and <a href="https://github.com/Silentely/eSIM-Tools/issues" target="_blank" rel="noopener noreferrer" style="color: #d63384; text-decoration: underline;">open an Issue</a>. Thank you!
|
||
</span>
|
||
</div>
|
||
<button id="directFetchPullBtn" class="btn btn-info">
|
||
<i class="fas fa-bolt me-2"></i>
|
||
<span class="lang-zh">拉取我的 eSIM</span>
|
||
<span class="lang-en">Fetch my eSIM</span>
|
||
</button>
|
||
<div id="directFetchStatus" class="status mt-2" role="status" aria-live="polite"></div>
|
||
<div id="directFetchSsnPicker" class="mt-3" style="display:none;"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 手动激活区块 -->
|
||
<div id="manualBlock" class="mt-3" style="display:none;">
|
||
<div class="btn-group">
|
||
<button id="reserveESimBtn" class="btn btn-primary">
|
||
<i class="fas fa-bookmark me-2"></i> 预订eSIM
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 已有激活码快捷入口 -->
|
||
<div class="mt-3">
|
||
<button id="manualEsimInputToggle" class="btn btn-link p-0" type="button">
|
||
我已完成 eSIM 预订(已有激活码/SSN)
|
||
</button>
|
||
<div id="manualEsimInputSection" class="card card-body mt-2" style="display: none;">
|
||
<a href="https://www.giffgaff.com/activate" target="_blank" class="btn btn-link p-0 ms-2 mb-3" style="font-size: 0.9rem;">
|
||
前往激活页面
|
||
</a>
|
||
<div class="row g-2">
|
||
<div class="col-md-6">
|
||
<div class="form-floating">
|
||
<input id="manualActivationCode" class="form-control" placeholder="如:Y6GKL6" />
|
||
<label for="manualActivationCode">激活码</label>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="form-floating">
|
||
<input id="manualSSN" class="form-control" placeholder="如:8944…" />
|
||
<label for="manualSSN">SSN</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<button id="manualSaveAndNextBtn" class="btn btn-success mt-3" type="button">
|
||
<i class="fas fa-check me-2"></i>保存并进入下一步
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="esimReserveStatus" class="status mt-2" role="status" aria-live="polite"></div>
|
||
|
||
<!-- eSIM信息显示区域 -->
|
||
<div id="esimInfoDisplay" class="mt-4" style="display: none;">
|
||
<div class="card border-warning">
|
||
<div class="card-header bg-warning text-dark">
|
||
<i class="fas fa-exclamation-triangle me-2"></i>
|
||
<strong>重要:eSIM已预订成功,请立即手动激活</strong>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="alert alert-danger">
|
||
<i class="fas fa-warning me-2"></i>
|
||
<strong>请保持此网页开启状态!</strong>
|
||
</div>
|
||
|
||
<h5 class="text-success mb-3 text-center" id="esimStatusTitle">您的eSIM信息</h5>
|
||
<div class="row text-center">
|
||
<div class="col-md-6">
|
||
<p class="mb-2"><strong>激活码:</strong></p>
|
||
<div class="border p-3 mb-3 bg-light">
|
||
<code id="displayActivationCode" class="text-break fs-4"></code>
|
||
<button id="copyActivationCodeBtn" class="btn btn-sm btn-outline-primary mt-2" data-target="displayActivationCode">
|
||
<i class="fas fa-copy"></i> 复制
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<p class="mb-2"><strong>SSN:</strong></p>
|
||
<div class="border p-3 mb-3 bg-light">
|
||
<code id="displaySSN" class="text-break fs-5"></code>
|
||
<button id="copySSNBtn" class="btn btn-sm btn-outline-primary mt-2" data-target="displaySSN">
|
||
<i class="fas fa-copy"></i> 复制
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mt-4">
|
||
<button id="confirmActivationBtn" class="btn btn-success btn-lg">
|
||
<i class="fas fa-check-circle me-2"></i>我已完成手动激活,继续下一步
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 步骤5: 获取eSIM -->
|
||
<div id="step5" class="section reveal">
|
||
<div class="card card-elevated">
|
||
<div class="card-header">
|
||
<i class="fas fa-qrcode"></i> 第五步:获取eSIM二维码
|
||
</div>
|
||
<div class="card-body">
|
||
<p class="mb-4" style="font-size: 17px; color: #212529;">
|
||
获取您的eSIM下载代码和二维码:
|
||
</p>
|
||
|
||
<div class="btn-group">
|
||
<button id="getESimTokenBtn" class="btn btn-primary">
|
||
<i class="fas fa-download me-2"></i> 获取eSIM Token
|
||
</button>
|
||
</div>
|
||
|
||
<div id="tokenStatus" class="status" role="status" aria-live="polite"></div>
|
||
|
||
<!-- eSIM结果显示 -->
|
||
<div id="resultContainer" class="mt-4">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<i class="fas fa-qrcode me-2"></i> 您的eSIM信息
|
||
</div>
|
||
<div class="card-body text-center">
|
||
<div id="qrcode" class="mt-4"></div>
|
||
<div id="esimInfo" class="mt-4"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 外部脚本 -->
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
|
||
|
||
<!-- Bootstrap 错误守卫 -->
|
||
<script src="/src/giffgaff/js/bootstrap-guard.js"></script>
|
||
|
||
<!-- 入场动效 -->
|
||
<script src="/src/giffgaff/js/reveal-animation.js"></script>
|
||
|
||
<!-- 验证码加载脚本 -->
|
||
<script type="module" src="/src/js/captcha-client.js"></script>
|
||
|
||
<!-- 性能优化脚本 -->
|
||
<script src="/src/js/performance.js"></script>
|
||
|
||
<!-- 国际化初始化 -->
|
||
<script type="module" src="/src/giffgaff/js/init-i18n.js"></script>
|
||
|
||
<!-- 通知系统初始化 -->
|
||
<script type="module" src="/src/giffgaff/js/init-notification.js"></script>
|
||
|
||
<!-- 主应用脚本(模块化) -->
|
||
<script type="module" src="/src/giffgaff/js/giffgaff-app.js"></script>
|
||
|
||
<!-- 统一版权页脚 -->
|
||
<script type="module" src="/src/js/bootstrap-footer.js"></script>
|
||
</body>
|
||
</html>
|