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();
});