mirror of
https://github.com/Silentely/eSIM-Tools.git
synced 2026-09-03 06:24:20 +08:00
- 通知服务新增页面可见性监听:标签页隐藏时暂停轮询,回到前台后恢复定时,离开期间超过检查周期则立即补查,节省 Netlify Function 配额 - 性能监控改为批量缓冲写入 sessionStorage,达到 1 秒间隔或 20 条上限自动落盘,并在页面隐藏/卸载时冲刷剩余缓冲,避免逐条读写开销 - 通知管理器改用原生 DOM API 构建节点并以 textContent 渲染消息,移除 innerHTML 与 escapeHtml 方法,从结构上杜绝 XSS 注入 - 新增 notification-service、notification-manager、performance-monitor 三组单元测试,覆盖后台暂停恢复、缓冲落盘、XSS 防护与空消息容错等场景 - 合并共享 Toast 样式至 design-system.css 并支持主题色定制,入场动画改为渐进增强,清理废弃请求日志中间件、SW 预缓存路径等冗余代码
985 lines
44 KiB
HTML
985 lines
44 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN" data-page="home">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||
<meta name="color-scheme" content="light dark">
|
||
<meta name="description" content="eSIM 设备管理工具集,支持已有 Giffgaff 与 Simyo 号码的 eSIM 转换、设备更换、二维码生成及验证码处理。">
|
||
|
||
<!-- Sentry 错误监控配置(必须在其他脚本之前) -->
|
||
<!-- 使用外链脚本以符合 CSP 策略 -->
|
||
<script src="/src/js/sentry-config.js"></script>
|
||
<script src="/src/js/sentry-loader.js"></script>
|
||
|
||
<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://sentry.io https://*.sentry.io https://www.googletagmanager.com https://challenges.cloudflare.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://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://analytics.google.com https://stats.g.doubleclick.net https://www.googletagmanager.com https://appapi.simyo.nl https://api.giffgaff.com https://id.giffgaff.com https://publicapi.giffgaff.com https://challenges.cloudflare.com https://www.google.com https://www.gstatic.com https://sentry.io https://*.sentry.io; img-src 'self' data: https:; frame-src 'self' https://challenges.cloudflare.com https://www.google.com https://*.sentry.io; worker-src 'self' blob:; child-src 'self' blob:;">
|
||
<title>eSIM Tools - Giffgaff & Simyo eSIM 在线管理工具 | 设备更换、激活与二维码生成</title>
|
||
<link rel="canonical" href="https://esim.cosr.eu.org/">
|
||
<meta name="robots" content="index, follow">
|
||
<link rel="manifest" href="/manifest.webmanifest">
|
||
<meta name="theme-color" content="#6366f1">
|
||
|
||
<!-- Open Graph / Facebook -->
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://esim.cosr.eu.org/">
|
||
<meta property="og:title" content="eSIM Tools - Giffgaff & Simyo eSIM 在线管理工具">
|
||
<meta property="og:description" content="免费在线 eSIM 管理工具,支持已有 Giffgaff 与 Simyo 号码的 eSIM 转换、OAuth 认证、设备更换、QR 码生成及激活,浏览器端操作无需安装 App。">
|
||
<meta property="og:image" content="https://esim.cosr.eu.org/og-image.png">
|
||
<meta property="og:locale" content="zh_CN">
|
||
<meta property="og:site_name" content="eSIM Tools">
|
||
|
||
<!-- Twitter Card -->
|
||
<meta name="twitter:card" content="summary_large_image">
|
||
<meta name="twitter:title" content="eSIM Tools - Giffgaff & Simyo eSIM 在线管理工具">
|
||
<meta name="twitter:description" content="免费在线 eSIM 管理工具,支持已有 Giffgaff 与 Simyo 号码的 eSIM 转换、设备更换、QR 码生成及激活。">
|
||
<meta name="twitter:image" content="https://esim.cosr.eu.org/og-image.png">
|
||
|
||
<!-- JSON-LD 结构化数据 -->
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@type": "WebApplication",
|
||
"name": "eSIM Tools",
|
||
"url": "https://esim.cosr.eu.org",
|
||
"description": "免费在线 eSIM 管理工具,支持已有 Giffgaff 与 Simyo 号码的 eSIM 转换、OAuth 认证、设备更换、QR 码生成及激活。",
|
||
"applicationCategory": "UtilitiesApplication",
|
||
"operatingSystem": "Web Browser",
|
||
"offers": {
|
||
"@type": "Offer",
|
||
"price": "0",
|
||
"priceCurrency": "GBP"
|
||
},
|
||
"featureList": [
|
||
"Giffgaff eSIM OAuth 认证与激活",
|
||
"Simyo eSIM 设备更换与管理",
|
||
"自动生成 eSIM QR 码",
|
||
"支持 MFA 多因素认证",
|
||
"浏览器端本地处理,保护隐私"
|
||
],
|
||
"inLanguage": ["zh", "en"],
|
||
"softwareHelp": {
|
||
"@type": "CreativeWork",
|
||
"url": "https://github.com/Silentely/eSIM-Tools"
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<!-- 性能优化:预连接与预加载关键资源 -->
|
||
<link rel="preconnect" href="https://browser.sentry-cdn.com" crossorigin>
|
||
<link rel="preconnect" href="https://www.googletagmanager.com" crossorigin>
|
||
<link rel="preconnect" href="https://api.giffgaff.com" crossorigin>
|
||
<link rel="preconnect" href="https://appapi.simyo.nl" crossorigin>
|
||
|
||
<!-- Favicon -->
|
||
<link rel="icon" href="/src/assets/favicon.ico" type="image/x-icon">
|
||
|
||
<!-- 关键CSS优先:直接加载,避免 onload 违反 CSP -->
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
|
||
<!-- Font Awesome:直接引入,避免 onload 触发器被 CSP 阻断导致样式未生效 -->
|
||
<link rel="stylesheet" href="/src/assets/fontawesome/all.min.css">
|
||
<!-- Font Awesome 资源路径(woff2)在 /src/assets/fontawesome/,确保已发布且 CSP 允许 font-src 'self' -->
|
||
|
||
<!-- 本地样式文件 -->
|
||
<link rel="stylesheet" href="/src/styles/design-system.css">
|
||
<link rel="stylesheet" href="/src/styles/animations.css">
|
||
<link rel="stylesheet" href="/src/styles/fa-local.css">
|
||
<link rel="stylesheet" href="/src/styles/notification.css">
|
||
|
||
<meta name="build-rev" content="v1">
|
||
|
||
<style>
|
||
/* Design System: 语义化令牌与统一规范 */
|
||
:root{
|
||
/* Brand */
|
||
--brand-start:#6366f1; /* indigo-500 */
|
||
--brand-end:#8b5cf6; /* violet-500 */
|
||
--accent-ok:#10b981; /* emerald-500 */
|
||
--accent-warn:#f59e0b; /* amber-500 */
|
||
--accent-danger:#ef4444; /* red-500 */
|
||
|
||
/* Surface & Text:中性 indigo/slate,替代旧黄绿背景 */
|
||
--bg-grad-start:#eef2ff;
|
||
--bg-grad-end:#f8fafc;
|
||
--surface:#ffffff;
|
||
--surface-alpha:94%;
|
||
--text-primary:#1f2937; /* slate-800 */
|
||
--text-secondary:#374151; /* gray-700 */
|
||
--text-muted:#6b7280; /* gray-500 */
|
||
|
||
/* Radius & Elevation & Spacing */
|
||
--radius-lg:18px;
|
||
--shadow-sm:0 4px 12px rgba(15,23,42,.06);
|
||
--shadow-md:0 10px 28px rgba(15,23,42,.08);
|
||
--shadow-lg:0 22px 50px rgba(15,23,42,.10);
|
||
--ring:0 0 0 3px rgba(99,102,241,.35);
|
||
|
||
--s1:8px; --s2:12px; --s3:16px; --s4:20px; --s5:24px; --s6:32px;
|
||
|
||
/* Motion:与 design-system 对齐 */
|
||
--ease-standard:cubic-bezier(.2,.8,.2,1);
|
||
--duration-fast:160ms;
|
||
--duration-normal:240ms;
|
||
}
|
||
|
||
*{margin:0;padding:0;box-sizing:border-box}
|
||
|
||
body{
|
||
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", Arial, "Noto Sans", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
||
background:
|
||
radial-gradient(1100px 560px at 8% -8%, rgba(99,102,241,.14), transparent 58%),
|
||
radial-gradient(900px 480px at 100% 0%, rgba(139,92,246,.10), transparent 52%),
|
||
linear-gradient(160deg, var(--bg-grad-start) 0%, var(--bg-grad-end) 100%);
|
||
min-height: 100vh;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: var(--s5);
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.main-container{
|
||
background: color-mix(in oklab, white var(--surface-alpha), transparent);
|
||
-webkit-backdrop-filter: blur(14px);
|
||
backdrop-filter: blur(14px);
|
||
border-radius: var(--radius-lg);
|
||
padding: clamp(20px, 4vw, 40px);
|
||
box-shadow: var(--shadow-lg);
|
||
max-width: 960px;
|
||
width: 100%;
|
||
text-align: center;
|
||
border: 1px solid color-mix(in oklab, white 78%, rgba(99,102,241,.18));
|
||
}
|
||
|
||
.language-switcher{
|
||
display:flex;
|
||
justify-content:flex-end;
|
||
width:100%;
|
||
margin-bottom: var(--s3);
|
||
}
|
||
.lang-switch{
|
||
display:inline-flex;
|
||
align-items:center;
|
||
gap:6px;
|
||
padding:6px 16px;
|
||
border-radius:999px;
|
||
border:1px solid rgba(99,102,241,.25);
|
||
background: rgba(255,255,255,.75);
|
||
color: var(--text-primary);
|
||
font-weight:600;
|
||
cursor:pointer;
|
||
transition: transform var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard), background-color var(--duration-fast) var(--ease-standard);
|
||
}
|
||
@media (hover: hover){
|
||
.lang-switch:hover{
|
||
transform: translateY(-1px);
|
||
box-shadow: var(--shadow-sm);
|
||
background: rgba(255,255,255,.92);
|
||
}
|
||
}
|
||
.lang-switch:focus-visible{
|
||
outline:none;
|
||
box-shadow: var(--ring);
|
||
}
|
||
|
||
.header{ margin-bottom: var(--s6); }
|
||
.header h1{
|
||
font-size: clamp(1.9rem, 3vw, 2.6rem);
|
||
font-weight: 800;
|
||
color: var(--text-primary);
|
||
margin-bottom: var(--s2);
|
||
letter-spacing: .2px;
|
||
display:flex;align-items:center;justify-content:center;gap:10px;
|
||
}
|
||
.header .subtitle{
|
||
font-size: clamp(.95rem, 1.9vw, 1.12rem);
|
||
color: var(--text-muted);
|
||
margin: 0;
|
||
}
|
||
|
||
.header-actions{
|
||
display: flex;
|
||
gap: var(--s2);
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
margin-top: var(--s3);
|
||
}
|
||
|
||
.github-btn, .kofi-btn{
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
padding: 10px 18px;
|
||
display:inline-flex;
|
||
align-items:center;
|
||
justify-content:center;
|
||
border-radius: 999px;
|
||
transition: transform var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard), background-color var(--duration-fast) var(--ease-standard);
|
||
gap: 8px;
|
||
box-shadow: var(--shadow-sm);
|
||
text-decoration: none !important;
|
||
outline: none;
|
||
border: 1px solid rgba(255,255,255,.18);
|
||
}
|
||
.github-btn{ background: #24292e; color:#fff !important; }
|
||
.kofi-btn{ background: #FF5E5B; color:#fff !important; }
|
||
@media (hover: hover){
|
||
.github-btn:hover{ transform: translateY(-1px); box-shadow: var(--shadow-md); background:#111; }
|
||
.kofi-btn:hover{ transform: translateY(-1px); box-shadow: var(--shadow-md); background:#e64a47; }
|
||
}
|
||
|
||
.github-btn:focus-visible, .kofi-btn:focus-visible{ outline: none; box-shadow: var(--ring); }
|
||
|
||
.tools-grid{
|
||
display:grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: clamp(16px, 3vw, 28px);
|
||
margin-top: var(--s6);
|
||
}
|
||
@media (max-width: 720px){ .tools-grid{ grid-template-columns: 1fr; } }
|
||
|
||
.tool-card{
|
||
background: color-mix(in oklab, var(--surface) 96%, transparent);
|
||
border-radius: var(--radius-lg);
|
||
padding: clamp(20px, 3.2vw, 28px);
|
||
box-shadow: var(--shadow-md);
|
||
transition: transform var(--duration-normal) var(--ease-standard), box-shadow var(--duration-normal) var(--ease-standard), border-color var(--duration-normal) var(--ease-standard);
|
||
border: 1px solid color-mix(in oklab, var(--primary) 12%, transparent);
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.tool-card::before{
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0 0 auto 0;
|
||
height: 4px;
|
||
background: linear-gradient(90deg, var(--primary), var(--secondary));
|
||
}
|
||
@media (hover: hover){
|
||
.tool-card:hover{
|
||
transform: translateY(-4px);
|
||
box-shadow: var(--shadow-lg);
|
||
border-color: color-mix(in oklab, var(--primary) 36%, transparent);
|
||
}
|
||
}
|
||
.tool-card:focus-within{ box-shadow: var(--ring), var(--shadow-md); }
|
||
|
||
/* 品牌色注入 */
|
||
.giffgaff-card{ --primary:#ff6b00; --secondary:#ff8c42; }
|
||
.simyo-card{ --primary:#e74c3c; --secondary:#c0392b; }
|
||
|
||
.tool-icon{
|
||
font-size: clamp(2.2rem, 3.2vw, 2.8rem);
|
||
color: var(--primary);
|
||
margin-bottom: var(--s3);
|
||
}
|
||
.tool-title{
|
||
font-size: clamp(1.2rem, 2.2vw, 1.4rem);
|
||
font-weight: 800;
|
||
color: var(--text-primary);
|
||
margin-bottom: var(--s2);
|
||
}
|
||
.tool-description{
|
||
color: var(--text-muted);
|
||
margin-bottom: var(--s4);
|
||
line-height: 1.65;
|
||
}
|
||
|
||
.tool-features{
|
||
list-style: none;
|
||
padding: 0;
|
||
margin-bottom: var(--s4);
|
||
text-align: left;
|
||
}
|
||
.tool-features li{
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 10px;
|
||
padding: 6px 0;
|
||
color: var(--text-secondary);
|
||
}
|
||
.tool-features li i{ color: var(--primary); flex: 0 0 auto; }
|
||
.tool-features li span{ flex: 1 1 auto; }
|
||
|
||
.tool-btn{
|
||
background: linear-gradient(135deg, var(--primary), var(--secondary));
|
||
color: #fff;
|
||
border: none;
|
||
padding: 12px 22px;
|
||
border-radius: 999px;
|
||
font-size: 1rem;
|
||
font-weight: 800;
|
||
text-decoration: none;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
transition: transform var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard), filter var(--duration-fast) var(--ease-standard);
|
||
box-shadow: 0 6px 16px color-mix(in oklab, var(--primary) 32%, transparent);
|
||
outline: none;
|
||
}
|
||
@media (hover: hover){
|
||
.tool-btn:hover{ transform: translateY(-2px); text-decoration: none; color: #fff; filter: brightness(1.04); box-shadow: 0 10px 22px color-mix(in oklab, var(--primary) 38%, transparent); }
|
||
}
|
||
.tool-btn:focus-visible{ box-shadow: var(--ring); }
|
||
.tool-btn:active{ transform: scale(0.98); }
|
||
|
||
.footer{
|
||
margin-top: var(--s6);
|
||
padding-top: var(--s5);
|
||
border-top: 1px solid color-mix(in oklab, #ecf0f1 85%, transparent);
|
||
color: #6b7280;
|
||
font-size: .94rem;
|
||
line-height: 1.6;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 入场动画:IntersectionObserver 触发,避免 setTimeout 抖动
|
||
仅在 JS 正常运行(html.js)时隐藏,避免脚本加载失败导致内容永久不可见 */
|
||
html.js .reveal{ opacity: 0; transform: translateY(12px); transition: opacity var(--duration-normal) var(--ease-standard), transform var(--duration-normal) var(--ease-standard); }
|
||
html.js .reveal.show{ opacity: 1; transform: translateY(0); }
|
||
|
||
/* 降低动效:尊重用户的减少动态偏好 */
|
||
@media (prefers-reduced-motion: reduce){
|
||
html.js .reveal{ transition: none; transform: none; opacity: 1; }
|
||
.tool-card, .github-btn, .kofi-btn, .tool-btn, .lang-switch{ transition: none!important; }
|
||
}
|
||
|
||
/* 小屏进一步优化 */
|
||
@media (max-width: 360px){
|
||
.github-btn{ padding: 9px 14px; font-size: 14px; }
|
||
.tool-btn{ padding: 10px 18px; font-size: .95rem; }
|
||
}
|
||
|
||
/* GEO 优化内容区块 */
|
||
.info-section{
|
||
margin-top: var(--s6);
|
||
text-align: left;
|
||
}
|
||
.section-title{
|
||
font-size: clamp(1.3rem, 2.5vw, 1.6rem);
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
margin-bottom: var(--s3);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--s2);
|
||
}
|
||
.section-title i{ color: var(--primary, var(--brand-start)); }
|
||
.section-desc{
|
||
color: var(--text-muted);
|
||
margin-bottom: var(--s4);
|
||
}
|
||
|
||
/* 设备兼容性 */
|
||
.compat-grid{
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: var(--s3);
|
||
margin-bottom: var(--s3);
|
||
}
|
||
@media (max-width: 600px){ .compat-grid{ grid-template-columns: 1fr; } }
|
||
.compat-card{
|
||
background: color-mix(in oklab, var(--surface) 95%, transparent);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--s4);
|
||
border: 1px solid color-mix(in oklab, var(--brand-start) 20%, transparent);
|
||
}
|
||
.compat-card h3{
|
||
font-size: 1rem;
|
||
font-weight: 700;
|
||
margin-bottom: var(--s2);
|
||
color: var(--text-primary);
|
||
}
|
||
.compat-card p{
|
||
font-size: .9rem;
|
||
color: var(--text-secondary);
|
||
line-height: 1.6;
|
||
}
|
||
.compat-check{
|
||
background: color-mix(in oklab, var(--accent-ok) 10%, transparent);
|
||
padding: var(--s3);
|
||
border-radius: var(--radius-lg);
|
||
font-size: .9rem;
|
||
}
|
||
.compat-check code{
|
||
background: rgba(0,0,0,.06);
|
||
padding: 2px 6px;
|
||
border-radius: 4px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* 使用教程 */
|
||
.tutorial-grid{
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: var(--s4);
|
||
}
|
||
@media (max-width: 700px){ .tutorial-grid{ grid-template-columns: 1fr; } }
|
||
.tutorial-card{
|
||
background: var(--surface);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--s4);
|
||
border-left: 4px solid;
|
||
}
|
||
.giffgaff-tutorial{ border-left-color: #ff6b00; }
|
||
.simyo-tutorial{ border-left-color: #e74c3c; }
|
||
.tutorial-card h3{
|
||
font-size: 1.05rem;
|
||
font-weight: 700;
|
||
margin-bottom: var(--s3);
|
||
color: var(--text-primary);
|
||
}
|
||
.tutorial-steps{
|
||
padding-left: var(--s4);
|
||
margin-bottom: var(--s3);
|
||
}
|
||
.tutorial-steps li{
|
||
font-size: .9rem;
|
||
color: var(--text-secondary);
|
||
margin-bottom: var(--s1);
|
||
line-height: 1.5;
|
||
}
|
||
.tutorial-note{
|
||
font-size: .85rem;
|
||
color: var(--text-muted);
|
||
background: color-mix(in oklab, var(--accent-warn) 10%, transparent);
|
||
padding: var(--s2) var(--s3);
|
||
border-radius: var(--radius-lg);
|
||
}
|
||
|
||
/* 对比表格 */
|
||
.compare-table-wrapper{
|
||
overflow-x: auto;
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
.compare-table{
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
background: var(--surface);
|
||
font-size: .9rem;
|
||
}
|
||
.compare-table th{
|
||
background: color-mix(in oklab, var(--brand-start) 10%, transparent);
|
||
padding: var(--s3);
|
||
font-weight: 700;
|
||
text-align: left;
|
||
color: var(--text-primary);
|
||
}
|
||
.compare-table td{
|
||
padding: var(--s3);
|
||
border-bottom: 1px solid color-mix(in oklab, #ecf0f1 80%, transparent);
|
||
color: var(--text-secondary);
|
||
}
|
||
.compare-table tr:last-child td{ border-bottom: none; }
|
||
.text-success{ color: var(--accent-ok); }
|
||
.text-warning{ color: var(--accent-warn); }
|
||
|
||
/* 地区限制 */
|
||
.region-grid{
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: var(--s3);
|
||
}
|
||
@media (max-width: 600px){ .region-grid{ grid-template-columns: 1fr; } }
|
||
.region-card{
|
||
background: var(--surface);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--s4);
|
||
border: 1px solid color-mix(in oklab, var(--brand-start) 15%, transparent);
|
||
}
|
||
.region-card h3{
|
||
font-size: 1rem;
|
||
font-weight: 700;
|
||
margin-bottom: var(--s2);
|
||
color: var(--text-primary);
|
||
}
|
||
.region-card p{
|
||
font-size: .9rem;
|
||
color: var(--text-secondary);
|
||
margin-bottom: var(--s1);
|
||
}
|
||
.region-card strong{ color: var(--text-primary); }
|
||
|
||
/* 术语表 */
|
||
.glossary-grid{
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: var(--s3);
|
||
}
|
||
@media (max-width: 800px){ .glossary-grid{ grid-template-columns: repeat(2, 1fr); } }
|
||
@media (max-width: 500px){ .glossary-grid{ grid-template-columns: 1fr; } }
|
||
.glossary-item{
|
||
background: var(--surface);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--s3) var(--s4);
|
||
}
|
||
.glossary-term{
|
||
font-weight: 700;
|
||
font-size: .9rem;
|
||
color: var(--brand-start);
|
||
margin-bottom: var(--s1);
|
||
}
|
||
.glossary-desc{
|
||
font-size: .85rem;
|
||
color: var(--text-muted);
|
||
line-height: 1.5;
|
||
margin: 0;
|
||
}
|
||
|
||
/* FAQ */
|
||
.faq-list{
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--s2);
|
||
}
|
||
.faq-item{
|
||
background: var(--surface);
|
||
border-radius: var(--radius-lg);
|
||
overflow: hidden;
|
||
border: 1px solid color-mix(in oklab, var(--brand-start) 10%, transparent);
|
||
transition: box-shadow var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard);
|
||
}
|
||
.faq-item[open]{
|
||
border-color: color-mix(in oklab, var(--brand-start) 22%, transparent);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
.faq-item summary{
|
||
padding: var(--s3) var(--s4);
|
||
font-weight: 600;
|
||
font-size: .95rem;
|
||
color: var(--text-primary);
|
||
cursor: pointer;
|
||
list-style: none;
|
||
transition: background-color var(--duration-fast) var(--ease-standard);
|
||
}
|
||
.faq-item summary::-webkit-details-marker{ display: none; }
|
||
@media (hover: hover){
|
||
.faq-item summary:hover{
|
||
background: color-mix(in oklab, var(--brand-start) 6%, transparent);
|
||
}
|
||
}
|
||
.faq-item p{
|
||
padding: 0 var(--s4) var(--s3);
|
||
font-size: .9rem;
|
||
color: var(--text-secondary);
|
||
line-height: 1.6;
|
||
animation: section-enter var(--duration-normal) var(--ease-standard) both;
|
||
}
|
||
@keyframes section-enter{
|
||
from{ opacity: 0; transform: translateY(8px); }
|
||
to{ opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
/* 安全声明 */
|
||
.disclaimer-content{
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--s3);
|
||
}
|
||
.disclaimer-item{
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: var(--s3);
|
||
padding: var(--s4);
|
||
border-radius: var(--radius-lg);
|
||
background: var(--surface);
|
||
}
|
||
.disclaimer-item i{
|
||
font-size: 1.5rem;
|
||
flex-shrink: 0;
|
||
margin-top: 2px;
|
||
}
|
||
.disclaimer-item.warning{ border-left: 4px solid var(--accent-warn); }
|
||
.disclaimer-item.warning i{ color: var(--accent-warn); }
|
||
.disclaimer-item.info{ border-left: 4px solid var(--brand-start); }
|
||
.disclaimer-item.info i{ color: var(--brand-start); }
|
||
.disclaimer-item.success{ border-left: 4px solid var(--accent-ok); }
|
||
.disclaimer-item.success i{ color: var(--accent-ok); }
|
||
.disclaimer-item strong{
|
||
display: block;
|
||
font-size: .95rem;
|
||
margin-bottom: var(--s1);
|
||
color: var(--text-primary);
|
||
}
|
||
.disclaimer-item p{
|
||
font-size: .9rem;
|
||
color: var(--text-secondary);
|
||
margin: 0;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
/* ===== 暗色模式 ===== */
|
||
@media (prefers-color-scheme: dark){
|
||
:root{
|
||
--bg-grad-start:#0f1220;
|
||
--bg-grad-end:#0b0d14;
|
||
--surface:#1a1d2a;
|
||
--surface-alpha:88%;
|
||
--text-primary:#e8eaf0;
|
||
--text-secondary:#c4c9d4;
|
||
--text-muted:#9aa3b2;
|
||
--shadow-sm:0 4px 12px rgba(0,0,0,.35);
|
||
--shadow-md:0 10px 28px rgba(0,0,0,.4);
|
||
--shadow-lg:0 22px 50px rgba(0,0,0,.5);
|
||
--ring:0 0 0 3px rgba(129,140,248,.4);
|
||
}
|
||
|
||
body{
|
||
background:
|
||
radial-gradient(1100px 560px at 8% -8%, rgba(99,102,241,.18), transparent 58%),
|
||
radial-gradient(900px 480px at 100% 0%, rgba(139,92,246,.12), transparent 52%),
|
||
linear-gradient(160deg, var(--bg-grad-start) 0%, var(--bg-grad-end) 100%);
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.main-container{
|
||
background: color-mix(in oklab, #161926 var(--surface-alpha), transparent);
|
||
border-color: color-mix(in oklab, white 12%, rgba(99,102,241,.2));
|
||
}
|
||
|
||
.lang-switch{
|
||
background: rgba(255,255,255,.08);
|
||
border-color: rgba(165,180,252,.3);
|
||
color: var(--text-primary);
|
||
}
|
||
@media (hover: hover){
|
||
.lang-switch:hover{ background: rgba(255,255,255,.12); }
|
||
}
|
||
|
||
.tool-card{
|
||
background: color-mix(in oklab, var(--surface) 96%, transparent);
|
||
border-color: color-mix(in oklab, var(--primary) 22%, transparent);
|
||
}
|
||
|
||
.compat-card,
|
||
.tutorial-card,
|
||
.region-card,
|
||
.glossary-item,
|
||
.faq-item,
|
||
.disclaimer-item{
|
||
background: var(--surface);
|
||
border-color: color-mix(in oklab, var(--brand-start) 18%, transparent);
|
||
}
|
||
|
||
.compat-check{
|
||
background: color-mix(in oklab, var(--accent-ok) 14%, transparent);
|
||
}
|
||
.compat-check code{
|
||
background: rgba(255,255,255,.08);
|
||
color: #e2e8f0;
|
||
}
|
||
|
||
.compare-table{
|
||
background: var(--surface);
|
||
}
|
||
.compare-table th{
|
||
background: color-mix(in oklab, var(--brand-start) 18%, transparent);
|
||
color: var(--text-primary);
|
||
}
|
||
.compare-table td{
|
||
border-bottom-color: rgba(255,255,255,.06);
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.footer{
|
||
border-top-color: rgba(255,255,255,.08);
|
||
color: #94a3b8;
|
||
}
|
||
|
||
.tutorial-note{
|
||
background: color-mix(in oklab, var(--accent-warn) 14%, transparent);
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<!-- Google tag (gtag.js) 延迟加载 -->
|
||
<script type="module" src="/src/js/captcha-client.js"></script>
|
||
<script defer src="https://www.googletagmanager.com/gtag/js?id=G-HGX38HMNL1" crossorigin="anonymous"></script>
|
||
</head>
|
||
<body aria-label="eSIM 工具选择">
|
||
<div class="main-container" role="region" aria-label="eSIM 工具选择">
|
||
<div class="language-switcher">
|
||
<button id="languageSwitcher" class="lang-switch" type="button" aria-label="切换语言到英文">🌐 English</button>
|
||
</div>
|
||
<div class="header">
|
||
<h1><i class="fas fa-sim-card" aria-hidden="true"></i> <span class="header-title-text">eSIM 工具集</span></h1>
|
||
<p class="subtitle">轻松管理您的 Giffgaff 与 Simyo eSIM 配置</p>
|
||
<div class="header-actions">
|
||
<a href="https://github.com/Silentely/eSIM-Tools" target="_blank" rel="noopener noreferrer" 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="Buy me a coffee on Ko-fi">
|
||
<i class="fas fa-coffee" aria-hidden="true"></i> <span>Buy Me a Coffee</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tools-grid" aria-live="polite">
|
||
<!-- Giffgaff工具卡片 -->
|
||
<section class="tool-card giffgaff-card reveal" tabindex="-1" aria-labelledby="giffgaff-title" aria-describedby="giffgaff-desc">
|
||
<div class="tool-icon" aria-hidden="true">
|
||
<i class="fas fa-mobile-alt"></i>
|
||
</div>
|
||
<h2 id="giffgaff-title" class="tool-title"><span class="tool-title-text">Giffgaff eSIM 工具</span></h2>
|
||
<p id="giffgaff-desc" class="tool-description">
|
||
<span class="tool-description-text">完整的 Giffgaff eSIM 转换与管理,支持 OAuth 认证、MFA 验证与 GraphQL API 调用</span>
|
||
</p>
|
||
<ul class="tool-features">
|
||
<li><i class="fa-solid fa-check" aria-hidden="true"></i><span>OAuth 2.0 PKCE 认证</span></li>
|
||
<li><i class="fa-solid fa-check" aria-hidden="true"></i><span>邮件验证码与 MFA 支持</span></li>
|
||
<li><i class="fa-solid fa-check" aria-hidden="true"></i><span>GraphQL API 集成</span></li>
|
||
<li><i class="fa-solid fa-check" aria-hidden="true"></i><span>自动生成 eSIM 二维码</span></li>
|
||
<li><i class="fa-solid fa-check" aria-hidden="true"></i><span>完善的错误处理</span></li>
|
||
</ul>
|
||
<a href="/giffgaff" class="tool-btn" aria-describedby="giffgaff-desc">
|
||
<i class="fas fa-arrow-right" aria-hidden="true"></i><span>使用 Giffgaff 工具</span>
|
||
</a>
|
||
</section>
|
||
|
||
<!-- Simyo工具卡片 -->
|
||
<section class="tool-card simyo-card reveal" tabindex="-1" aria-labelledby="simyo-title" aria-describedby="simyo-desc">
|
||
<div class="tool-icon" aria-hidden="true">
|
||
<i class="fas fa-sim-card"></i>
|
||
</div>
|
||
<h2 id="simyo-title" class="tool-title"><span class="tool-title-text">Simyo eSIM 工具</span></h2>
|
||
<p id="simyo-desc" class="tool-description">
|
||
<span class="tool-description-text">专为 Simyo NL 用户的 eSIM 管理,支持设备更换与短信验证码处理</span>
|
||
</p>
|
||
<ul class="tool-features">
|
||
<li><i class="fa-solid fa-check" aria-hidden="true"></i><span>简单快捷的登录验证</span></li>
|
||
<li><i class="fa-solid fa-check" aria-hidden="true"></i><span>设备更换完整流程</span></li>
|
||
<li><i class="fa-solid fa-check" aria-hidden="true"></i><span>短信验证码支持</span></li>
|
||
<li><i class="fa-solid fa-check" aria-hidden="true"></i><span>一键生成二维码</span></li>
|
||
<li><i class="fa-solid fa-check" aria-hidden="true"></i><span>安装确认功能</span></li>
|
||
</ul>
|
||
<a href="/simyo" class="tool-btn" aria-describedby="simyo-desc">
|
||
<i class="fas fa-arrow-right" aria-hidden="true"></i><span>使用 Simyo 工具</span>
|
||
</a>
|
||
</section>
|
||
</div>
|
||
|
||
<!-- 设备兼容性 -->
|
||
<section class="info-section reveal" aria-labelledby="compat-title">
|
||
<h2 id="compat-title" class="section-title"><i class="fas fa-mobile-alt" aria-hidden="true"></i> <span class="compat-title-text">设备兼容性</span></h2>
|
||
<p class="section-desc">使用前请确认您的设备支持 eSIM 功能</p>
|
||
<div class="compat-grid">
|
||
<div class="compat-card">
|
||
<h3><i class="fab fa-apple" aria-hidden="true"></i> Apple</h3>
|
||
<p>iPhone XS / XR 及更新机型<br>iPhone SE 2 及更新机型</p>
|
||
</div>
|
||
<div class="compat-card">
|
||
<h3><i class="fab fa-android" aria-hidden="true"></i> Android</h3>
|
||
<p>Samsung Galaxy S20 及更新<br>Google Pixel 3 及更新<br>部分 OnePlus、华为机型</p>
|
||
</div>
|
||
</div>
|
||
<p class="compat-check"><strong>检查方法:</strong>在手机拨号盘输入 <code>*#06#</code>,如显示 EID 号码则支持 eSIM</p>
|
||
</section>
|
||
|
||
<!-- 使用教程 -->
|
||
<section class="info-section reveal" aria-labelledby="tutorial-title">
|
||
<h2 id="tutorial-title" class="section-title"><i class="fas fa-book-open" aria-hidden="true"></i> <span class="tutorial-title-text">使用教程</span></h2>
|
||
<div class="tutorial-grid">
|
||
<div class="tutorial-card giffgaff-tutorial">
|
||
<h3>Giffgaff eSIM 激活流程</h3>
|
||
<ol class="tutorial-steps">
|
||
<li>点击「使用 Giffgaff 工具」进入工具页面</li>
|
||
<li>使用 Giffgaff 账号完成 OAuth 登录授权</li>
|
||
<li>输入邮箱验证码完成身份验证</li>
|
||
<li>完成 MFA 多因素认证(如已启用)</li>
|
||
<li>查询会员资格并选择 eSIM 操作</li>
|
||
<li>获取 eSIM 下载码或扫描 QR 码激活</li>
|
||
</ol>
|
||
<p class="tutorial-note"><i class="fas fa-clock" aria-hidden="true"></i> 激活时间窗口:UK 时间 4:30am - 9:30pm</p>
|
||
</div>
|
||
<div class="tutorial-card simyo-tutorial">
|
||
<h3>Simyo eSIM 管理流程</h3>
|
||
<ol class="tutorial-steps">
|
||
<li>点击「使用 Simyo 工具」进入工具页面</li>
|
||
<li>使用 Simyo 账号完成登录验证</li>
|
||
<li>选择设备更换或 eSIM 激活</li>
|
||
<li>通过 SMS 短信或 iDEAL 支付验证身份</li>
|
||
<li>确认新设备并生成 eSIM 配置</li>
|
||
</ol>
|
||
<p class="tutorial-note"><i class="fas fa-info-circle" aria-hidden="true"></i> 本工具支持生成 eSIM QR 码,简化激活流程</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 与官方流程对比 -->
|
||
<section class="info-section reveal" aria-labelledby="compare-title">
|
||
<h2 id="compare-title" class="section-title"><i class="fas fa-balance-scale" aria-hidden="true"></i> <span class="compare-title-text">与官方 App 对比</span></h2>
|
||
<div class="compare-table-wrapper">
|
||
<table class="compare-table">
|
||
<thead>
|
||
<tr>
|
||
<th>对比项</th>
|
||
<th>本工具</th>
|
||
<th>官方 App</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>操作平台</td>
|
||
<td><i class="fas fa-check text-success"></i> 浏览器 Web 端</td>
|
||
<td>仅移动端 App</td>
|
||
</tr>
|
||
<tr>
|
||
<td>QR 码生成</td>
|
||
<td><i class="fas fa-check text-success"></i> 自动生成</td>
|
||
<td>Simyo 不支持(本工具可生成)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>认证方式</td>
|
||
<td>OAuth 2.0 PKCE</td>
|
||
<td>App 内置登录</td>
|
||
</tr>
|
||
<tr>
|
||
<td>官方支持</td>
|
||
<td><i class="fas fa-exclamation-triangle text-warning"></i> 非官方</td>
|
||
<td><i class="fas fa-check text-success"></i> 官方支持</td>
|
||
</tr>
|
||
<tr>
|
||
<td>服务条款</td>
|
||
<td><i class="fas fa-exclamation-triangle text-warning"></i> 可能违反</td>
|
||
<td><i class="fas fa-check text-success"></i> 符合条款</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 地区与时间限制 -->
|
||
<section class="info-section reveal" aria-labelledby="region-title">
|
||
<h2 id="region-title" class="section-title"><i class="fas fa-globe-europe" aria-hidden="true"></i> <span class="region-title-text">地区与时间限制</span></h2>
|
||
<div class="region-grid">
|
||
<div class="region-card">
|
||
<h3><i class="fas fa-clock" aria-hidden="true"></i> Giffgaff</h3>
|
||
<p>激活时间窗口:<strong>UK 时间 4:30am - 9:30pm</strong></p>
|
||
<p>请在非工作时间内尝试激活可能失败</p>
|
||
</div>
|
||
<div class="region-card">
|
||
<h3><i class="fas fa-map-marker-alt" aria-hidden="true"></i> Simyo</h3>
|
||
<p>服务地区:<strong>荷兰 (NL)</strong></p>
|
||
<p>仅支持荷兰本地 SIM 卡用户</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 技术术语解释 -->
|
||
<section class="info-section reveal" aria-labelledby="glossary-title">
|
||
<h2 id="glossary-title" class="section-title"><i class="fas fa-book" aria-hidden="true"></i> <span class="glossary-title-text">技术术语说明</span></h2>
|
||
<div class="glossary-grid">
|
||
<div class="glossary-item">
|
||
<p class="glossary-term">OAuth 2.0 PKCE</p>
|
||
<p class="glossary-desc">一种安全的授权协议,允许第三方应用在无需存储密钥的情况下访问用户数据</p>
|
||
</div>
|
||
<div class="glossary-item">
|
||
<p class="glossary-term">GraphQL</p>
|
||
<p class="glossary-desc">一种 API 查询语言,比 REST 更灵活高效地获取所需数据</p>
|
||
</div>
|
||
<div class="glossary-item">
|
||
<p class="glossary-term">LPA String</p>
|
||
<p class="glossary-desc">本地配置文件激活字符串,包含 eSIM 下载所需的服务器地址和激活码</p>
|
||
</div>
|
||
<div class="glossary-item">
|
||
<p class="glossary-term">SM-DP+</p>
|
||
<p class="glossary-desc">订阅管理数据准备服务器,负责安全地存储和分发 eSIM 配置文件</p>
|
||
</div>
|
||
<div class="glossary-item">
|
||
<p class="glossary-term">MFA</p>
|
||
<p class="glossary-desc">多因素认证,通过多种方式验证用户身份,提高账户安全性</p>
|
||
</div>
|
||
<div class="glossary-item">
|
||
<p class="glossary-term">EID</p>
|
||
<p class="glossary-desc">eSIM 的唯一标识号码,可在拨号盘输入 *#06# 查看</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- FAQ 常见问题 -->
|
||
<section class="info-section reveal" aria-labelledby="faq-title">
|
||
<h2 id="faq-title" class="section-title"><i class="fas fa-question-circle" aria-hidden="true"></i> <span class="faq-title-text">常见问题</span></h2>
|
||
<div class="faq-list">
|
||
<details class="faq-item">
|
||
<summary>无法接收 SMS 短信验证码怎么办?</summary>
|
||
<p>对于 Simyo 用户,可以选择 iDEAL 支付方式作为替代验证方案。如果仍然无法接收短信,请检查手机号码是否正确,或联系运营商确认短信服务状态。</p>
|
||
</details>
|
||
<details class="faq-item">
|
||
<summary>eSIM 激活需要多长时间?</summary>
|
||
<p>通常在几分钟内完成,最长可能需要 1 小时。如果超过 1 小时仍未激活成功,请检查网络连接或重新尝试。</p>
|
||
</details>
|
||
<details class="faq-item">
|
||
<summary>是否支持在海外激活 eSIM?</summary>
|
||
<p>Giffgaff 的 eSIM 激活有 UK 时间窗口限制(4:30am - 9:30pm UK 时间)。Simyo 主要面向荷兰本地用户,海外激活可能受限。</p>
|
||
</details>
|
||
<details class="faq-item">
|
||
<summary>Simyo 支持 QR 码激活吗?</summary>
|
||
<p>Simyo 官方 App 不支持 QR 码激活,但本工具可以生成 eSIM QR 码,让您通过扫描方式快速完成激活,无需在 App 内操作。</p>
|
||
</details>
|
||
<details class="faq-item">
|
||
<summary>使用这个工具安全吗?</summary>
|
||
<p>本工具在本地浏览器运行,所有数据处理均在本地进行。但请注意:使用第三方工具可能违反运营商服务条款,建议使用非主力号码进行测试。</p>
|
||
</details>
|
||
<details class="faq-item">
|
||
<summary>激活失败怎么办?</summary>
|
||
<p>请检查:1) 设备是否支持 eSIM;2) 网络连接是否正常;3) 是否在运营商服务时间内;4) 账号状态是否正常。如问题持续,请联系运营商客服。</p>
|
||
</details>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 安全声明 -->
|
||
<section class="info-section reveal" aria-labelledby="disclaimer-title">
|
||
<h2 id="disclaimer-title" class="section-title"><i class="fas fa-shield-alt" aria-hidden="true"></i> <span class="disclaimer-title-text">安全声明</span></h2>
|
||
<div class="disclaimer-content">
|
||
<div class="disclaimer-item warning">
|
||
<i class="fas fa-exclamation-triangle" aria-hidden="true"></i>
|
||
<div>
|
||
<strong>第三方工具风险</strong>
|
||
<p>本工具为非官方第三方工具,使用可能违反运营商服务条款。请自行评估风险。</p>
|
||
</div>
|
||
</div>
|
||
<div class="disclaimer-item info">
|
||
<i class="fas fa-info-circle" aria-hidden="true"></i>
|
||
<div>
|
||
<strong>建议使用非主力号码</strong>
|
||
<p>为避免影响正常通信,建议使用备用号码进行测试和激活操作。</p>
|
||
</div>
|
||
</div>
|
||
<div class="disclaimer-item success">
|
||
<i class="fas fa-lock" aria-hidden="true"></i>
|
||
<div>
|
||
<strong>数据安全</strong>
|
||
<p>所有数据处理均在本地浏览器完成,不上传任何敏感信息到服务器。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<footer class="footer" aria-label="免责声明与隐私说明">
|
||
<p>
|
||
<i class="fas fa-info-circle me-2" aria-hidden="true"></i>
|
||
本工具仅供个人使用,请遵守相关服务条款。<br>
|
||
<i class="fas fa-shield-alt me-2" aria-hidden="true"></i>
|
||
所有数据处理均在本地进行,保护您的隐私安全。
|
||
</p>
|
||
</footer>
|
||
</div>
|
||
|
||
<!-- 将 bootstrap 脚本 defer,减少阻塞 -->
|
||
<script defer src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||
<!-- 首页逻辑脚本(无内联) -->
|
||
<script defer src="/src/js/home.js"></script>
|
||
<!-- 统一版权页脚(自动注入年份/品牌) -->
|
||
<script type="module" src="/src/js/bootstrap-footer.js"></script>
|
||
|
||
<!-- 国际化初始化 -->
|
||
<script type="module" src="/src/js/init-home-i18n.js"></script>
|
||
|
||
<!-- 通知系统初始化 -->
|
||
<script type="module" src="/src/js/init-notification.js"></script>
|
||
|
||
<!-- 性能优化脚本 -->
|
||
<script defer src="/src/js/performance.js"></script>
|
||
<!-- WebMCP: 向 AI Agent 暴露站点工具 -->
|
||
<script src="/src/js/webmcp.js" defer></script>
|
||
</body>
|
||
</html>
|