Files
jiapu/public/js/help-pages.js
T
2026-08-03 16:49:38 +08:00

244 lines
8.5 KiB
JavaScript

(function (root, factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.HelpPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.HelpPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
function escapeHtml(value) {
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function normalizeId(value) {
var text;
if (typeof value === 'number' && !Number.isSafeInteger(value)) return '';
if (value === undefined || value === null) return '';
text = String(value).trim();
return /^[1-9][0-9]*$/.test(text) ? text : '';
}
function normalizeCount(value) {
var text;
if (value === undefined || value === null || value === '') return '0';
if (typeof value === 'number' && (!Number.isSafeInteger(value) || value < 0)) return '';
text = String(value).trim();
return /^(?:0|[1-9][0-9]*)$/.test(text) ? text : '';
}
function text(value) {
return value === undefined || value === null ? '' : String(value).trim();
}
function normalizeHelpArticle(item) {
var source = item || {};
var helpId = normalizeId(source.helpId);
var helpTitle = text(source.helpTitle);
var helpContent = text(source.helpContent);
var viewCount = normalizeCount(source.viewCount);
if (!helpId || !helpTitle || !helpContent || !viewCount || String(source.status) !== '0') {
return null;
}
return {
helpId: helpId,
helpCategory: text(source.helpCategory),
helpTitle: helpTitle,
helpContent: helpContent,
viewCount: viewCount
};
}
function normalizeHelpArticleList(data) {
var items;
if (!Array.isArray(data)) return [];
items = data.map(normalizeHelpArticle);
return items.some(function (item) { return !item; }) ? [] : items;
}
function renderHelpArticleList(data) {
var items = normalizeHelpArticleList(data);
if (!items.length) return '<div class="api-empty">当前暂无帮助文章</div>';
return items.map(function (item) {
var meta = [item.helpCategory, '浏览 ' + item.viewCount + ' 次'].filter(Boolean).join(' · ');
return '<details class="tilt-card" data-help-article-id="' + escapeHtml(item.helpId) + '">' +
'<summary>' + escapeHtml(item.helpTitle) + '</summary>' +
'<p>' + escapeHtml(meta) + '</p>' +
'<div class="help-detail" data-help-detail-panel="' + escapeHtml(item.helpId) + '">' +
'<button class="btn ghost" type="button" data-help-detail-id="' +
escapeHtml(item.helpId) + '">查看完整解答</button></div></details>';
}).join('');
}
function renderHelpArticleDetail(item) {
var article = normalizeHelpArticle(item);
var meta;
if (!article) return '<div class="api-empty">帮助文章不存在或已停用</div>';
meta = [article.helpCategory, '浏览 ' + article.viewCount + ' 次'].filter(Boolean).join(' · ');
return '<div class="help-detail-content"><p class="module-meta">' + escapeHtml(meta) +
'</p><p>' + escapeHtml(article.helpContent).replace(/\r?\n/g, '<br />') + '</p></div>';
}
async function loadHelpArticleDetail(api, helpId) {
var targetId = normalizeId(helpId);
var article;
if (!api || typeof api.helpArticleDetail !== 'function') throw new Error('帮助文章接口不可用');
if (!targetId) throw new Error('帮助文章编号无效');
article = normalizeHelpArticle(await api.helpArticleDetail(targetId));
if (!article) throw new Error('帮助文章详情响应无效');
if (article.helpId !== targetId) throw new Error('详情响应与请求编号不一致');
return article;
}
async function loadHelpArticles(api) {
var data;
var items;
if (!api || typeof api.helpArticles !== 'function') throw new Error('帮助文章接口不可用');
data = await api.helpArticles();
items = normalizeHelpArticleList(data);
if (!Array.isArray(data) || items.length !== data.length) throw new Error('帮助文章列表响应无效');
return items;
}
function shouldRedirectToLogin(api, error) {
var status = error && (error.status || error.code);
return !api || !api.getToken || !api.getToken() || Number(status) === 401;
}
function redirectToLogin(api) {
if (api && api.clearToken) api.clearToken();
if (!root.location) return;
if (typeof root.location.replace === 'function') root.location.replace('login.html');
else root.location.href = 'login.html';
}
function isForbidden(error) {
return Number(error && (error.status || error.code)) === 403;
}
async function init() {
var list = root.document && root.document.querySelector('[data-help-list]');
var status = root.document && root.document.querySelector('[data-help-status]');
var refresh = root.document && root.document.querySelector('[data-help-refresh]');
var api = root.GenealogyApi && root.GenealogyApi.defaultClient;
if (!list) return;
if (shouldRedirectToLogin(api)) {
redirectToLogin(api);
return;
}
function setApiState(target, type, message) {
if (!target) return;
if (root.ProfileUI && root.ProfileUI.setApiState && type) {
root.ProfileUI.setApiState(target, type, message);
return;
}
target.textContent = message || '';
}
function setStatus(type, message) {
setApiState(status, type, message);
}
function setHelpList(items) {
if (!items.length) {
setApiState(list, 'empty', '当前暂无帮助文章。');
return;
}
list.innerHTML = renderHelpArticleList(items);
}
function setPendingButton(button, pending, label) {
if (!button) return;
if (!button.dataset.defaultLabel) button.dataset.defaultLabel = button.textContent;
button.disabled = pending;
button.textContent = pending ? label : button.dataset.defaultLabel;
}
async function refreshList() {
try {
list.classList.add('is-loading');
setApiState(list, 'loading', '正在读取帮助文章…');
setStatus('loading', '正在读取帮助文章…');
setHelpList(await loadHelpArticles(api));
setStatus('', '');
} catch (error) {
if (shouldRedirectToLogin(api, error)) {
redirectToLogin(api);
return;
}
setApiState(list, isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '暂无权限查看帮助文章。' : '帮助文章读取失败,请稍后重试。');
setStatus(isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '暂无权限查看帮助文章。' : (error.message || '帮助文章读取失败,请稍后重试。'));
} finally {
list.classList.remove('is-loading');
}
}
list.addEventListener('click', async function (event) {
var button = event.target.closest('[data-help-detail-id]');
var helpId;
var panel;
if (!button || button.disabled) return;
helpId = button.getAttribute('data-help-detail-id');
panel = list.querySelector('[data-help-detail-panel="' + helpId + '"]');
if (!panel) return;
button.disabled = true;
setApiState(panel, 'loading', '正在读取完整解答…');
try {
panel.innerHTML = renderHelpArticleDetail(await loadHelpArticleDetail(api, helpId));
} catch (error) {
if (shouldRedirectToLogin(api, error)) {
redirectToLogin(api);
return;
}
setApiState(panel, isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '暂无权限查看该帮助文章。' : (error.message || '帮助文章详情读取失败,请稍后重试。'));
}
});
if (refresh) refresh.addEventListener('click', async function () {
setPendingButton(refresh, true, '正在刷新…');
try {
await refreshList();
} finally {
setPendingButton(refresh, false, '正在刷新…');
}
});
await refreshList();
}
return {
normalizeHelpArticle: normalizeHelpArticle,
normalizeHelpArticleList: normalizeHelpArticleList,
renderHelpArticleList: renderHelpArticleList,
renderHelpArticleDetail: renderHelpArticleDetail,
loadHelpArticleDetail: loadHelpArticleDetail,
loadHelpArticles: loadHelpArticles,
isForbidden: isForbidden,
shouldRedirectToLogin: shouldRedirectToLogin,
init: init
};
});