mirror of
https://github.com/Silentely/eSIM-Tools.git
synced 2026-09-03 06:24:20 +08:00
🐛 fix: 兼容 Chrome 77 等旧浏览器,移除 ES2020 语法(可选链/空值合并)
- ESIM-TOOLS-G: 替换所有 ?. 和 ?? 为 ES5 兼容写法 - ESIM-TOOLS-15: 添加中国 CDN 源(unpkg.zhimg.com/bootcdn.net) - 涉及 8 个文件,覆盖 giffgaff/simyo 全部业务模块
This commit is contained in:
@@ -143,7 +143,7 @@ class GiffgaffApp {
|
||||
}
|
||||
|
||||
isIgnoredUnhandledRejection(error) {
|
||||
const payload = `${error?.message ?? ''}\n${error?.stack ?? ''}`.toLowerCase();
|
||||
const payload = `${(error && error.message) || ''}\n${(error && error.stack) || ''}`.toLowerCase();
|
||||
const ignoredKeywords = [
|
||||
'wallet must has at least one account',
|
||||
'wallet must have at least one account',
|
||||
@@ -516,7 +516,8 @@ class GiffgaffApp {
|
||||
if (!confirmBtn.__bound) {
|
||||
confirmBtn.__bound = true;
|
||||
confirmBtn.addEventListener('click', () => {
|
||||
const selected = container.querySelector('input[name="directFetchSsn"]:checked')?.value;
|
||||
const selectedEl = container.querySelector('input[name="directFetchSsn"]:checked');
|
||||
const selected = selectedEl && selectedEl.value;
|
||||
if (!selected) return;
|
||||
container.style.display = 'none';
|
||||
this.handleDirectFetchPull(selected);
|
||||
@@ -743,7 +744,7 @@ class GiffgaffApp {
|
||||
|
||||
console.log('[Giffgaff] 调用 oauthHandler.processCallback()...');
|
||||
const result = await oauthHandler.processCallback(callbackUrl);
|
||||
console.log('[Giffgaff] OAuth 回调处理成功, hasAccessToken:', !!result?.accessToken);
|
||||
console.log('[Giffgaff] OAuth 回调处理成功, hasAccessToken:', !!(result && result.accessToken));
|
||||
|
||||
uiController.showStatus(elements.callbackStatus, t('giffgaff.app.status.oauthSuccess'), "success");
|
||||
|
||||
@@ -927,7 +928,7 @@ class GiffgaffApp {
|
||||
|
||||
console.log('[Giffgaff] 调用 esimService.getMemberInfo()...');
|
||||
const result = await esimService.getMemberInfo();
|
||||
console.log('[Giffgaff] 会员信息获取成功, memberId:', result.data?.memberProfile?.id);
|
||||
console.log('[Giffgaff] 会员信息获取成功, memberId:', result.data && result.data.memberProfile && result.data.memberProfile.id);
|
||||
|
||||
uiController.showStatus(elements.memberStatus, t('giffgaff.app.status.memberFetched'), "success");
|
||||
uiController.showMemberInfo(result.data);
|
||||
@@ -939,8 +940,8 @@ class GiffgaffApp {
|
||||
console.error('[Giffgaff] 获取会员信息失败:', error.message, error);
|
||||
|
||||
// 针对"账号无号码"错误提供专门提示
|
||||
const isWalletEmpty = error.message?.includes('wallet must') ||
|
||||
error.message?.includes('at least one account') ||
|
||||
const isWalletEmpty = (error.message && error.message.includes('wallet must')) ||
|
||||
(error.message && error.message.includes('at least one account')) ||
|
||||
error.code === 4001;
|
||||
|
||||
if (isWalletEmpty) {
|
||||
@@ -998,7 +999,7 @@ class GiffgaffApp {
|
||||
|
||||
console.log('[Giffgaff] 调用 esimService.reserveESim()...');
|
||||
const result = await esimService.reserveESim();
|
||||
console.log('[Giffgaff] eSIM 预订成功, deliveryStatus:', result.data?.esim?.deliveryStatus);
|
||||
console.log('[Giffgaff] eSIM 预订成功, deliveryStatus:', result.data && result.data.esim && result.data.esim.deliveryStatus);
|
||||
|
||||
const status = result.data.esim.deliveryStatus || 'RESERVED';
|
||||
uiController.showStatus(elements.esimReserveStatus, t('giffgaff.app.status.reserveSuccess', { status }), "success");
|
||||
@@ -1054,7 +1055,7 @@ class GiffgaffApp {
|
||||
const statusEl = document.getElementById('smsInlineStatus');
|
||||
console.log('[Giffgaff] === SMS 验证码校验 ===');
|
||||
|
||||
const code = (codeInput?.value ?? '').trim();
|
||||
const code = (codeInput && codeInput.value || '').trim();
|
||||
|
||||
if (!/^\d{6}$/.test(code)) {
|
||||
console.warn('[Giffgaff] 验证码格式无效:', code.length, '位');
|
||||
@@ -1106,8 +1107,8 @@ class GiffgaffApp {
|
||||
const activationInput = document.getElementById('manualActivationCode');
|
||||
const ssnInput = document.getElementById('manualSSN');
|
||||
|
||||
const activationCode = (activationInput?.value ?? '').trim();
|
||||
const ssn = (ssnInput?.value ?? '').trim();
|
||||
const activationCode = (activationInput && activationInput.value || '').trim();
|
||||
const ssn = (ssnInput && ssnInput.value || '').trim();
|
||||
console.log('[Giffgaff] === 手动 eSIM 信息保存 ===');
|
||||
console.log('[Giffgaff] 激活码长度:', activationCode.length, ', SSN长度:', ssn.length);
|
||||
|
||||
@@ -1197,7 +1198,7 @@ class GiffgaffApp {
|
||||
console.error('[Giffgaff] eSIM Token 获取失败:', error.message, error);
|
||||
|
||||
// 根据错误类型进行差异化处理
|
||||
if (error.status === 401 || error.message?.includes('401')) {
|
||||
if (error.status === 401 || (error.message && error.message.includes('401'))) {
|
||||
uiController.showStatus(elements.tokenStatus, t('giffgaff.app.error.authExpired'), "error");
|
||||
setTimeout(() => {
|
||||
if (confirm(t('giffgaff.app.prompt.relogin'))) {
|
||||
@@ -1205,7 +1206,7 @@ class GiffgaffApp {
|
||||
uiController.showSection(1);
|
||||
}
|
||||
}, 500);
|
||||
} else if (error.status === 422 || error.message?.includes('422')) {
|
||||
} else if (error.status === 422 || (error.message && error.message.includes('422'))) {
|
||||
uiController.showStatus(elements.tokenStatus, t('giffgaff.app.error.ssnNotFound'), "error");
|
||||
setTimeout(() => uiController.showSection(4), 2000);
|
||||
} else {
|
||||
@@ -1241,7 +1242,7 @@ class GiffgaffApp {
|
||||
* 处理Cookie过期
|
||||
*/
|
||||
handleCookieExpired(event) {
|
||||
console.log('[Giffgaff] === Cookie 已过期 ===', event?.detail);
|
||||
console.log('[Giffgaff] === Cookie 已过期 ===', event && event.detail);
|
||||
uiController.showSection(1);
|
||||
uiController.selectLoginMethod('cookie');
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ export class CookieHandler {
|
||||
return { valid: false };
|
||||
} catch (err) {
|
||||
console.error(t('giffgaff.cookie.log.checkError'), err);
|
||||
return { transientError: true, error: err?.message };
|
||||
return { transientError: true, error: err && err.message };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ export class ESimService {
|
||||
|
||||
if (data.errors) {
|
||||
const errorObj = data.errors[0];
|
||||
const errorMessage = errorObj?.message || errorObj?.error || JSON.stringify(errorObj);
|
||||
const errorMessage = (errorObj && errorObj.message) || (errorObj && errorObj.error) || JSON.stringify(errorObj);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ export class ESimService {
|
||||
|
||||
if (data.errors) {
|
||||
const errorObj = data.errors[0];
|
||||
const errorMessage = errorObj?.message || errorObj?.error || JSON.stringify(errorObj);
|
||||
const errorMessage = (errorObj && errorObj.message) || (errorObj && errorObj.error) || JSON.stringify(errorObj);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ export class ESimService {
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
const newSim = swapData?.data?.swapSim?.new;
|
||||
const newSim = swapData && swapData.data && swapData.data.swapSim && swapData.data.swapSim.new;
|
||||
if (!newSim || !newSim.ssn) {
|
||||
throw new Error(t('giffgaff.esim.errors.swapMissingSim'));
|
||||
}
|
||||
@@ -245,7 +245,7 @@ export class ESimService {
|
||||
|
||||
if (data.errors) {
|
||||
const errorObj = data.errors[0];
|
||||
const errorMessage = errorObj?.message || errorObj?.error || JSON.stringify(errorObj);
|
||||
const errorMessage = (errorObj && errorObj.message) || (errorObj && errorObj.error) || JSON.stringify(errorObj);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
@@ -429,10 +429,10 @@ export class ESimService {
|
||||
const data = await response.json();
|
||||
if (data.errors) {
|
||||
const errorObj = data.errors[0];
|
||||
throw new Error(errorObj?.message || errorObj?.error || JSON.stringify(errorObj));
|
||||
throw new Error((errorObj && errorObj.message) || (errorObj && errorObj.error) || JSON.stringify(errorObj));
|
||||
}
|
||||
|
||||
return data?.data?.eSims || [];
|
||||
return (data && data.data && data.data.eSims) || [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -485,7 +485,7 @@ export class ESimService {
|
||||
// 兼容 GraphQL 错误格式 { errors: [{ message: '...' }] }
|
||||
if (parsed && typeof parsed === 'object' && Array.isArray(parsed.errors) && parsed.errors.length > 0) {
|
||||
const firstError = parsed.errors[0] || {};
|
||||
const message = firstError?.message || (typeof firstError === 'string' ? firstError : null);
|
||||
const message = (firstError && firstError.message) || (typeof firstError === 'string' ? firstError : null);
|
||||
if (message) {
|
||||
return { ...parsed, message };
|
||||
}
|
||||
@@ -503,7 +503,7 @@ export class ESimService {
|
||||
* @returns {string} 友好的错误提示
|
||||
*/
|
||||
_friendlyGraphqlError(status, parsed) {
|
||||
const msg = parsed?.message || parsed?.error || '';
|
||||
const msg = (parsed && parsed.message) || (parsed && parsed.error) || '';
|
||||
|
||||
// 401: token 过期
|
||||
if (status === 401) {
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
import { tl } from './i18n.js';
|
||||
|
||||
// CDN 多源备用列表(主源 + 备用源,任一成功即可,解决 ESIM-TOOLS-15 单一 CDN 故障问题)
|
||||
// 包含国际源 + 中国镜像源,覆盖全球用户(包括中国大陆)
|
||||
const QRCODE_CDN_URLS = [
|
||||
'https://cdn.jsdelivr.net/npm/qrcode@1.5.4/build/qrcode.min.js',
|
||||
'https://cdnjs.cloudflare.com/ajax/libs/qrcode-generator/1.4.4/qrcode.min.js'
|
||||
'https://cdnjs.cloudflare.com/ajax/libs/qrcode-generator/1.4.4/qrcode.min.js',
|
||||
'https://unpkg.zhimg.com/qrcode@1.5.4/build/qrcode.min.js',
|
||||
'https://cdn.bootcdn.net/ajax/libs/qrcodejs/1.0.0/qrcode.min.js'
|
||||
];
|
||||
const DEFAULT_QR_SIZE = 300;
|
||||
const MIN_QR_SIZE = 200;
|
||||
|
||||
@@ -12,7 +12,7 @@ export class AuthHandler {
|
||||
constructor() {
|
||||
this.apiEndpoints = getApiEndpoints();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 登录Simyo账户
|
||||
* @param {string} phoneNumber - 手机号
|
||||
@@ -24,11 +24,11 @@ export class AuthHandler {
|
||||
if (!validatePhoneNumber(phoneNumber)) {
|
||||
throw new Error(t('simyo.errors.invalidPhone'));
|
||||
}
|
||||
|
||||
|
||||
if (!password) {
|
||||
throw new Error(t('simyo.errors.requirePassword'));
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch(this.apiEndpoints.login, {
|
||||
method: 'POST',
|
||||
@@ -38,23 +38,23 @@ export class AuthHandler {
|
||||
password: password
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
const data = await handleApiResponse(response);
|
||||
|
||||
|
||||
// 提取session token
|
||||
const sessionToken = data.result?.sessionToken;
|
||||
|
||||
const sessionToken = data.result && data.result.sessionToken;
|
||||
|
||||
if (!sessionToken) {
|
||||
throw new Error(data.message || t('simyo.auth.loginMissingToken'));
|
||||
}
|
||||
|
||||
|
||||
// 保存到状态
|
||||
stateManager.setState({
|
||||
sessionToken: sessionToken,
|
||||
phoneNumber: phoneNumber,
|
||||
password: password
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: t('simyo.auth.loginSuccess'),
|
||||
@@ -65,7 +65,7 @@ export class AuthHandler {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查登录状态
|
||||
* @returns {boolean} 是否已登录
|
||||
@@ -73,7 +73,7 @@ export class AuthHandler {
|
||||
isLoggedIn() {
|
||||
return !!stateManager.get('sessionToken');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前session token
|
||||
* @returns {string} session token
|
||||
|
||||
@@ -95,7 +95,7 @@ export class DeviceChangeHandler {
|
||||
return {
|
||||
success: true,
|
||||
message: data.message || t('simyo.device.verifySuccess'),
|
||||
remainingTries: data.result?.remainingNumberOfTries
|
||||
remainingTries: data.result && data.result.remainingNumberOfTries
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(t('simyo.device.log.verifyFailed'), error);
|
||||
|
||||
@@ -104,7 +104,8 @@ export function openHelp() {
|
||||
align-items: center; justify-content: center; padding: 20px;
|
||||
`;
|
||||
overlay.innerHTML = helpContent;
|
||||
overlay.querySelector('[data-action="close-help"]')?.addEventListener('click', () => {
|
||||
const closeBtn = overlay.querySelector('[data-action="close-help"]');
|
||||
if (closeBtn) closeBtn.addEventListener('click', () => {
|
||||
overlay.remove();
|
||||
});
|
||||
overlay.addEventListener('click', (e) => {
|
||||
|
||||
@@ -77,32 +77,32 @@ class SimyoApp {
|
||||
const { elements } = uiController;
|
||||
|
||||
// ===== Step 1: 登录 =====
|
||||
elements.loginBtn?.addEventListener('click', () => this.handleLogin());
|
||||
if (elements.loginBtn) elements.loginBtn.addEventListener('click', () => this.handleLogin());
|
||||
|
||||
// ===== 设备更换流程 =====
|
||||
this.bindDeviceChangeFlow();
|
||||
|
||||
// ===== Step 2: 获取eSIM =====
|
||||
elements.getEsimBtn?.addEventListener('click', () => this.handleGetEsim());
|
||||
if (elements.getEsimBtn) elements.getEsimBtn.addEventListener('click', () => this.handleGetEsim());
|
||||
|
||||
// ===== Step 3: 生成二维码 =====
|
||||
elements.generateQrBtn?.addEventListener('click', () => this.handleGenerateQR());
|
||||
if (elements.generateQrBtn) elements.generateQrBtn.addEventListener('click', () => this.handleGenerateQR());
|
||||
|
||||
// 下一步:确认安装
|
||||
const nextToConfirmBtn = document.getElementById('nextToConfirmBtn');
|
||||
nextToConfirmBtn?.addEventListener('click', () => {
|
||||
if (nextToConfirmBtn) nextToConfirmBtn.addEventListener('click', () => {
|
||||
uiController.showSection(4);
|
||||
});
|
||||
|
||||
// ===== Step 4: 确认安装 =====
|
||||
elements.confirmInstallBtn?.addEventListener('click', () => this.handleConfirmInstall());
|
||||
if (elements.confirmInstallBtn) elements.confirmInstallBtn.addEventListener('click', () => this.handleConfirmInstall());
|
||||
|
||||
// ===== 通用操作 =====
|
||||
elements.clearSessionBtn?.addEventListener('click', () => this.handleClearSession());
|
||||
if (elements.clearSessionBtn) elements.clearSessionBtn.addEventListener('click', () => this.handleClearSession());
|
||||
|
||||
// 帮助按钮
|
||||
const helpBtn = document.getElementById('helpBtn');
|
||||
helpBtn?.addEventListener('click', () => openHelp());
|
||||
if (helpBtn) helpBtn.addEventListener('click', () => openHelp());
|
||||
|
||||
// 步骤点击跳转
|
||||
this.bindStepNavigation();
|
||||
@@ -423,7 +423,7 @@ class SimyoApp {
|
||||
|
||||
console.log('[Simyo] 步骤2: 生成 LPA 字符串...');
|
||||
const qrResult = esimService.generateLPAString();
|
||||
console.log('[Simyo] LPA 字符串生成成功, 长度:', qrResult.lpaString?.length);
|
||||
console.log('[Simyo] LPA 字符串生成成功, 长度:', qrResult.lpaString && qrResult.lpaString.length);
|
||||
|
||||
uiController.showQRResult(qrResult.lpaString);
|
||||
uiController.showStatus(elements.qrStatus, t('simyo.app.status.generateSuccess'), "success");
|
||||
|
||||
Reference in New Issue
Block a user