Files
jiapu/public/js/app-promotion-pages.js
T
2026-08-29 19:06:07 +08:00

177 lines
5.6 KiB
JavaScript

(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';
var MediaDisplay = root.MediaDisplay || (typeof require === 'function' ? require('./media-display.js') : null);
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 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);
var coverFile = MediaDisplay && MediaDisplay.normalizeFileAccess(source.coverFile);
var promotion;
if (!promotionId || !promotionTitle || String(source.status) !== '0') return null;
if (source.coverFile !== undefined && source.coverFile !== null && !coverFile) return null;
promotion = {
promotionId: promotionId,
promotionTitle: promotionTitle,
promotionDesc: text(source.promotionDesc),
targetUrl: normalizeTargetUrl(source.targetUrl)
};
if (coverFile) promotion.coverFile = coverFile;
return promotion;
}
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 = (MediaDisplay ? MediaDisplay.renderImage(item.coverFile, {
alt: item.promotionTitle + '封面', className: 'promotion-cover-media'
}) : '') + '<div><h3>' + escapeHtml(item.promotionTitle) + '</h3>' +
'<p>' + escapeHtml(item.promotionDesc) + '</p></div>';
if (!item.targetUrl) {
return '<article class="promotion-card" data-promotion-id="' +
escapeHtml(item.promotionId) + '">' + content + '</article>';
}
return '<a class="promotion-card" data-promotion-id="' + escapeHtml(item.promotionId) +
'" href="' + escapeHtml(item.targetUrl) +
'" target="_blank" rel="noopener noreferrer">' + content + '</a>';
}
function renderPromotionList(data) {
var items = normalizePromotionList(data);
return items.map(renderPromotionCard).join('');
}
function setPromotionState(container, type, message) {
if (!container) return;
if (root.ProfileUI && root.ProfileUI.setApiState) {
root.ProfileUI.setApiState(container, type, message);
return;
}
container.textContent = message;
}
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;
}
function isForbidden(error) {
return Number(error && (error.status || error.code)) === 403;
}
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()) {
setPromotionState(list, 'forbidden', '登录后可查看应用推广。');
return;
}
setPromotionState(list, 'loading', '正在读取应用推广…');
try {
var items = await loadPromotions(api);
if (!items.length) {
setPromotionState(list, 'empty', '当前暂无应用推广。');
return;
}
list.innerHTML = items.map(renderPromotionCard).join('');
} catch (error) {
if (isUnauthorized(error)) {
if (api.clearToken) api.clearToken();
setPromotionState(list, 'forbidden', '登录后可查看应用推广。');
return;
}
setPromotionState(
list,
isForbidden(error) ? 'forbidden' : 'error',
isForbidden(error) ? '当前账号无权查看应用推广。' : '应用推广读取失败,请稍后重试。'
);
}
}
return {
normalizePromotion: normalizePromotion,
normalizePromotionList: normalizePromotionList,
normalizeTargetUrl: normalizeTargetUrl,
renderPromotionList: renderPromotionList,
setPromotionState: setPromotionState,
loadPromotions: loadPromotions,
isUnauthorized: isUnauthorized,
isForbidden: isForbidden,
init: init
};
});