// 更新日志弹层:点右栏底部版本号打开。数据 GET /v1/changelog(公开端点,直接 fetch, // 不走 api() 免绑登录态)。红点:localStorage 记 last seen 版本,与 /healthz 版本不一致 // → 版本号旁亮小红点提示"有更新",打开弹层即视为已看、红点清除。 import { $ } from "./dom.js"; import { escapeHtml } from "./format.js"; import { renderMd, highlightIn } from "./markdown.js"; const SEEN_KEY = "zcbot_seen_version"; let _current = ""; // /healthz 返回的当前版本(main.js loadVersion 灌入) // main.js loadVersion 拿到版本号后调:决定红点亮不亮(localStorage 不可用时静默不亮) export function markVersion(v) { _current = v || ""; const el = $("app-version"); if (!el) return; let seen = ""; try { seen = localStorage.getItem(SEEN_KEY) || ""; } catch (e) {} el.classList.toggle("hasnew", !!_current && seen !== _current); } export function closeChangelogModal() { $("changelog-modal").classList.remove("show"); } async function openChangelogModal() { const body = $("cl-body"); $("changelog-modal").classList.add("show"); body.innerHTML = '
加载中…
'; // 打开即视为"看过":记住当前版本 + 清红点 if (_current) { try { localStorage.setItem(SEEN_KEY, _current); } catch (e) {} $("app-version").classList.remove("hasnew"); } let d; try { const r = await fetch("/v1/changelog?limit=50"); if (!r.ok) throw new Error("HTTP " + r.status); d = await r.json(); } catch (e) { body.innerHTML = `
加载失败: ${escapeHtml(e.message)}
`; return; } $("cl-cur").textContent = d.current ? "当前 v" + d.current : ""; const entries = d.entries || []; if (!entries.length) { body.innerHTML = '
暂无更新说明。
'; return; } body.innerHTML = entries.map((e, i) => `
v${escapeHtml(e.version)} ${i === 0 ? '最新' : ""} ${e.date ? `${escapeHtml(e.date)}` : ""}
${renderMd(e.body_md)}
`).join(""); highlightIn(body); } // ───── 顶层绑定 ───── $("app-version").onclick = openChangelogModal; $("cl-close").onclick = closeChangelogModal; $("changelog-modal").addEventListener("click", (e) => { if (e.target.id === "changelog-modal") closeChangelogModal(); // 点遮罩关闭 });