diff --git a/src/simyo/js/modules/auth-handler.js b/src/simyo/js/modules/auth-handler.js index bc52a97..b6c16b3 100644 --- a/src/simyo/js/modules/auth-handler.js +++ b/src/simyo/js/modules/auth-handler.js @@ -49,11 +49,10 @@ export class AuthHandler { throw new Error(data.message || t('simyo.auth.loginMissingToken')); } - // 仅保存会话令牌与手机号;密码不落内存状态,降低调试/快照泄露面 + // 仅保存会话令牌与手机号;密码不进入状态 stateManager.setState({ sessionToken: sessionToken, - phoneNumber: phoneNumber, - password: '' + phoneNumber: phoneNumber }); return { diff --git a/src/simyo/js/modules/state-manager.js b/src/simyo/js/modules/state-manager.js index f685e48..f3144fc 100644 --- a/src/simyo/js/modules/state-manager.js +++ b/src/simyo/js/modules/state-manager.js @@ -10,10 +10,9 @@ import Logger from '../../../js/modules/logger.js'; export class StateManager { constructor() { this.state = { - // 认证相关 + // 认证相关(密码仅在登录请求时使用,不进入状态) sessionToken: "", phoneNumber: "", - password: "", // eSIM相关 activationCode: "", @@ -155,7 +154,6 @@ export class StateManager { this.state = { sessionToken: "", phoneNumber: "", - password: "", activationCode: "", validationCode: "", isDeviceChange: false, diff --git a/src/simyo/js/modules/utils.js b/src/simyo/js/modules/utils.js index c9f5049..fd6353e 100644 --- a/src/simyo/js/modules/utils.js +++ b/src/simyo/js/modules/utils.js @@ -66,39 +66,76 @@ export function showToast(message) { /** * 打开帮助对话框 + * 使用 DOM + textContent,避免 i18n 文案经 innerHTML 注入 */ export function openHelp() { - const helpContent = ` -
-

${t('simyo.help.title')}

- -
${t('simyo.help.setup.heading')}
-

${t('simyo.help.setup.content')}

- -
${t('simyo.help.device.heading')}
-

${t('simyo.help.device.content')}

- -
${t('simyo.help.keep.heading')}
-

${t('simyo.help.keep.content')}

- - -
- `; - const overlay = document.createElement('div'); overlay.dataset.helpOverlay = 'simyo-help'; - overlay.style.cssText = ` - position: fixed; top: 0; left: 0; width: 100%; height: 100%; - background: rgba(0,0,0,0.7); z-index: 1000; display: flex; - align-items: center; justify-content: center; padding: 20px; - `; - overlay.innerHTML = helpContent; - const closeBtn = overlay.querySelector('[data-action="close-help"]'); - if (closeBtn) closeBtn.addEventListener('click', () => { - overlay.remove(); + overlay.style.cssText = [ + 'position: fixed', + 'top: 0', + 'left: 0', + 'width: 100%', + 'height: 100%', + 'background: rgba(0,0,0,0.7)', + 'z-index: 1000', + 'display: flex', + 'align-items: center', + 'justify-content: center', + 'padding: 20px' + ].join('; '); + + const card = document.createElement('div'); + card.style.cssText = [ + 'max-width: 600px', + 'margin: 20px auto', + 'padding: 20px', + 'background: white', + 'border-radius: 12px', + 'box-shadow: 0 4px 20px rgba(0,0,0,0.1)' + ].join('; '); + + const title = document.createElement('h3'); + title.style.cssText = 'color: #ff6b00; margin-bottom: 20px;'; + const titleIcon = document.createElement('i'); + titleIcon.className = 'fas fa-question-circle'; + titleIcon.setAttribute('aria-hidden', 'true'); + title.appendChild(titleIcon); + title.appendChild(document.createTextNode(' ' + t('simyo.help.title'))); + + const sections = [ + ['simyo.help.setup.heading', 'simyo.help.setup.content'], + ['simyo.help.device.heading', 'simyo.help.device.content'], + ['simyo.help.keep.heading', 'simyo.help.keep.content'] + ]; + + card.appendChild(title); + sections.forEach(([headingKey, contentKey]) => { + const h5 = document.createElement('h5'); + h5.textContent = t(headingKey); + const p = document.createElement('p'); + p.textContent = t(contentKey); + card.appendChild(h5); + card.appendChild(p); }); + + const closeBtn = document.createElement('button'); + closeBtn.type = 'button'; + closeBtn.dataset.action = 'close-help'; + closeBtn.style.cssText = [ + 'margin-top: 20px', + 'padding: 10px 20px', + 'background: #ff6b00', + 'color: white', + 'border: none', + 'border-radius: 8px', + 'cursor: pointer' + ].join('; '); + closeBtn.textContent = t('simyo.help.close'); + closeBtn.addEventListener('click', () => overlay.remove()); + card.appendChild(closeBtn); + + overlay.appendChild(card); overlay.addEventListener('click', (e) => { if (e.target === overlay) overlay.remove(); });