97 lines
3.1 KiB
JavaScript
97 lines
3.1 KiB
JavaScript
const EARTH_ABOUT_API = "/api/v1/earth/about";
|
|
|
|
const DEFAULT_ABOUT = {
|
|
logo_src: "./assets/brand/lim-logo.png",
|
|
kicker: "About",
|
|
title: "智能星球计划",
|
|
version: "v0.64.0",
|
|
description:
|
|
"面向临空场景下的智能媒体研究、全球态势感知与多源开放数据巡航,提供可视化观测、事件聚合与交互式探索能力。",
|
|
meta: [
|
|
{ label: "出品方", value: "浙江大学临空智能媒体研究院" },
|
|
{ label: "策划人", value: "黄柳青" },
|
|
{ label: "产品兼开发者", value: "钱坤、张鸽、齐鹏" },
|
|
],
|
|
};
|
|
|
|
function escapeHtml(value = "") {
|
|
return String(value)
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
}
|
|
|
|
function escapeAttribute(value = "") {
|
|
return escapeHtml(value);
|
|
}
|
|
|
|
function normalizeAbout(payload) {
|
|
const about = payload && typeof payload === "object" ? payload : {};
|
|
const meta = Array.isArray(about.meta) ? about.meta : DEFAULT_ABOUT.meta;
|
|
return {
|
|
...DEFAULT_ABOUT,
|
|
...about,
|
|
logo_src: about.logo_src || DEFAULT_ABOUT.logo_src,
|
|
kicker: about.kicker || DEFAULT_ABOUT.kicker,
|
|
title: about.title || DEFAULT_ABOUT.title,
|
|
version: about.version || DEFAULT_ABOUT.version,
|
|
description: about.description || DEFAULT_ABOUT.description,
|
|
meta: meta
|
|
.map((item) => ({
|
|
label: String(item?.label || "").trim(),
|
|
value: String(item?.value || "").trim(),
|
|
}))
|
|
.filter((item) => item.label || item.value),
|
|
};
|
|
}
|
|
|
|
function renderAboutCard(about, isMobile = false) {
|
|
const metaClass = isMobile ? "earth-about-meta-list" : "earth-about-grid";
|
|
const metaMarkup = about.meta
|
|
.map(
|
|
(item) => `
|
|
<div class="earth-about-meta">
|
|
<span>${escapeHtml(item.label)}</span>
|
|
<strong>${escapeHtml(item.value)}</strong>
|
|
</div>
|
|
`,
|
|
)
|
|
.join("");
|
|
|
|
return `
|
|
<div class="earth-about-logo-frame">
|
|
<img class="earth-about-logo" src="${escapeAttribute(about.logo_src)}" alt="${escapeAttribute(about.title)} Logo">
|
|
</div>
|
|
<div class="earth-about-heading">
|
|
<span class="earth-about-kicker">${escapeHtml(about.kicker)}</span>
|
|
<strong>${escapeHtml(about.title)}</strong>
|
|
<span>${escapeHtml(about.version)}</span>
|
|
</div>
|
|
<p class="earth-about-copy">${escapeHtml(about.description)}</p>
|
|
<div class="${metaClass}">
|
|
${metaMarkup}
|
|
</div>
|
|
`.trim();
|
|
}
|
|
|
|
function applyAboutConfig(about) {
|
|
document.querySelectorAll(".earth-about-card").forEach((card) => {
|
|
const isMobile = card.classList.contains("earth-about-card--mobile");
|
|
card.innerHTML = renderAboutCard(about, isMobile);
|
|
});
|
|
}
|
|
|
|
export async function initEarthAbout() {
|
|
applyAboutConfig(normalizeAbout(DEFAULT_ABOUT));
|
|
try {
|
|
const response = await fetch(EARTH_ABOUT_API, { cache: "no-store" });
|
|
if (!response.ok) throw new Error(`Earth about request failed: ${response.status}`);
|
|
const payload = await response.json();
|
|
applyAboutConfig(normalizeAbout(payload?.about));
|
|
} catch (error) {
|
|
console.warn("Earth about config unavailable, using defaults.", error);
|
|
}
|
|
}
|