(function (root, factory) { if (typeof module === 'object' && module.exports) { module.exports = factory(root); return; } root.AppPromotionPages = factory(root); if (root.document) { root.document.addEventListener('DOMContentLoaded', function () { root.AppPromotionPages.init(); }); } })(typeof globalThis !== 'undefined' ? globalThis : window, function (root) { 'use strict'; function escapeHtml(value) { return String(value === undefined || value === null ? '' : value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function normalizeId(value) { var normalized; if (typeof value === 'number' && !Number.isSafeInteger(value)) return ''; if (value === undefined || value === null) return ''; normalized = String(value).trim(); return /^[1-9][0-9]*$/.test(normalized) ? normalized : ''; } function text(value) { return value === undefined || value === null ? '' : String(value).trim(); } function normalizeTargetUrl(value) { var normalized = text(value); var parsed; if (!normalized) return ''; try { parsed = new URL(normalized); } catch (error) { return ''; } return parsed.protocol === 'http:' || parsed.protocol === 'https:' ? parsed.href : ''; } function normalizePromotion(item) { var source = item || {}; var promotionId = normalizeId(source.promotionId); var promotionTitle = text(source.promotionTitle); if (!promotionId || !promotionTitle || String(source.status) !== '0') return null; return { promotionId: promotionId, promotionTitle: promotionTitle, promotionDesc: text(source.promotionDesc), targetUrl: normalizeTargetUrl(source.targetUrl) }; } function normalizePromotionList(data) { var items; if (!Array.isArray(data)) return []; items = data.map(normalizePromotion); return items.some(function (item) { return !item; }) ? [] : items; } function renderPromotionCard(item) { var content = '

' + escapeHtml(item.promotionTitle) + '

' + '

' + escapeHtml(item.promotionDesc) + '

'; if (!item.targetUrl) { return '
' + content + '
'; } return '' + content + ''; } function renderPromotionList(data) { var items = normalizePromotionList(data); if (!items.length) return '
当前暂无应用推广
'; return items.map(renderPromotionCard).join(''); } function renderPromotionLoginRequired() { return '
登录后可查看应用推广,立即登录
'; } async function loadPromotions(api) { var data; var items; if (!api || typeof api.promotions !== 'function') throw new Error('应用推广接口不可用'); data = await api.promotions({ platform: 'pc' }); items = normalizePromotionList(data); if (!Array.isArray(data) || items.length !== data.length) { throw new Error('推广列表响应无效'); } return items; } function isUnauthorized(error) { return Number(error && (error.status || error.code)) === 401; } async function init() { var page = root.document && root.document.querySelector('[data-promotion-page]'); var list = root.document && root.document.querySelector('[data-promotion-list]'); var api = root.GenealogyApi && root.GenealogyApi.defaultClient; if (!page || !list) return; if (!api || !api.getToken || !api.getToken()) { list.innerHTML = renderPromotionLoginRequired(); return; } try { list.classList.add('is-loading'); list.innerHTML = renderPromotionList(await loadPromotions(api)); } catch (error) { if (isUnauthorized(error)) { if (api.clearToken) api.clearToken(); list.innerHTML = renderPromotionLoginRequired(); return; } list.innerHTML = '
应用推广读取失败,请稍后重试
'; } finally { list.classList.remove('is-loading'); } } return { normalizePromotion: normalizePromotion, normalizePromotionList: normalizePromotionList, normalizeTargetUrl: normalizeTargetUrl, renderPromotionList: renderPromotionList, renderPromotionLoginRequired: renderPromotionLoginRequired, loadPromotions: loadPromotions, isUnauthorized: isUnauthorized, init: init }; });