(function (root, factory) { // 账号安全模块同时支持浏览器页面和 Node 单元测试。 if (typeof module === 'object' && module.exports) { module.exports = factory(root); return; } root.SecurityPages = factory(root); if (root.document) { root.document.addEventListener('DOMContentLoaded', function () { root.SecurityPages.init(); }); } })(typeof globalThis !== 'undefined' ? globalThis : window, function (root) { 'use strict'; var documentRef = root.document; function hashPassword(value) { // 接口文档要求密码提交 32 位 MD5,测试环境可传入 hashFn 替代。 if (root.hex_md5) return root.hex_md5(value); if (root.md5) return root.md5(value); return value; } function trimOrUndefined(value) { var text = String(value === undefined || value === null ? '' : value).trim(); return text || undefined; } function buildPasswordChangeBody(values, hashFn) { var source = values || {}; var hash = hashFn || hashPassword; return { oldPassword: hash(String(source.oldPassword || '').trim()), newPassword: hash(String(source.newPassword || '').trim()) }; } function buildPhoneChangeBody(values) { var source = values || {}; return { newPhone: String(source.newPhone || '').trim(), smsCode: String(source.smsCode || '').trim(), validToken: trimOrUndefined(source.validToken) }; } function buildDeactivateBody(values, hashFn) { var source = values || {}; var hash = hashFn || hashPassword; return { password: hash(String(source.password || '').trim()), reason: trimOrUndefined(source.reason) }; } function isDangerConfirmed(value) { return String(value || '').trim() === '确认注销'; } function getApi() { return root.GenealogyApi && root.GenealogyApi.defaultClient; } function query(selector, rootNode) { return (rootNode || documentRef).querySelector(selector); } function queryAll(selector, rootNode) { return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector)); } function showMessage(message) { if (root.layui && root.layui.layer) { root.layui.layer.msg(message); return; } root.alert(message); } function getFormValues(form) { var values = {}; queryAll('[name]', form).forEach(function (field) { values[field.name] = field.value; }); return values; } function setStatus(form, message) { var status = query('[data-security-status]', form); if (status) status.textContent = message; } async function submitPassword(form) { var api = getApi(); var values = getFormValues(form); if (!api) return; if (!values.oldPassword || !values.newPassword) { showMessage('请填写原密码和新密码'); return; } if (values.newPassword !== values.confirmPassword) { showMessage('两次新密码不一致'); return; } try { await api.changePassword(buildPasswordChangeBody(values)); setStatus(form, '密码已修改'); showMessage('密码已修改'); form.reset(); } catch (error) { showMessage(error.message || '密码修改失败'); } } async function submitPhone(form) { var api = getApi(); var body = buildPhoneChangeBody(getFormValues(form)); if (!api) return; if (!body.newPhone || !body.smsCode) { showMessage('请填写新手机号和验证码'); return; } try { await api.changePhone(body); setStatus(form, '手机号已换绑'); showMessage('手机号已换绑'); form.reset(); } catch (error) { showMessage(error.message || '手机号换绑失败'); } } async function submitDeactivate(form) { var api = getApi(); var values = getFormValues(form); if (!api) return; if (!values.password) { showMessage('请填写当前密码'); return; } if (!isDangerConfirmed(values.confirmText)) { showMessage('请完整输入“确认注销”'); return; } if (root.confirm && !root.confirm('账号注销后将退出登录,确认继续?')) return; try { await api.deactivateAccount(buildDeactivateBody(values)); showMessage('账号已提交注销'); root.location.href = 'index.html'; } catch (error) { showMessage(error.message || '账号注销失败'); } } async function logout() { var api = getApi(); if (root.confirm && !root.confirm('确认退出当前账号?')) return; try { if (api) await api.logout(); } catch (error) { // ApiClient.logout 会在请求失败时清理本地 token,页面仍应离开受保护区域。 } finally { root.location.href = 'index.html'; } } function bindActions() { if (!documentRef) return; documentRef.addEventListener('submit', function (event) { var form = event.target.closest('[data-security-form]'); var formType; if (!form) return; event.preventDefault(); formType = form.getAttribute('data-security-form'); if (formType === 'password') submitPassword(form); if (formType === 'phone') submitPhone(form); if (formType === 'deactivate') submitDeactivate(form); }); documentRef.addEventListener('click', function (event) { var button = event.target.closest('[data-security-logout]'); if (!button) return; event.preventDefault(); logout(); }); } function init() { if (!documentRef || !query('[data-security-page]')) return; bindActions(); } return { buildPasswordChangeBody: buildPasswordChangeBody, buildPhoneChangeBody: buildPhoneChangeBody, buildDeactivateBody: buildDeactivateBody, isDangerConfirmed: isDangerConfirmed, init: init }; });