function toLocalInputValue(d) { const pad = (n) => String(n).padStart(2, "0"); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`; } function localInputToIso(value) { if (!value) return undefined; const d = new Date(value); return Number.isNaN(d.getTime()) ? undefined : d.toISOString(); } function formatAt(iso) { if (!iso) return "—"; const d = new Date(iso); if (Number.isNaN(d.getTime())) return iso; return d.toLocaleString("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false, }); } function formatNum(n) { if (n == null || Number.isNaN(Number(n))) return "—"; return Number(n).toLocaleString("zh-CN"); } function setStatus(text, state = "idle") { const status = document.getElementById("status"); status.textContent = text; status.dataset.state = state; } function setRangeActive(id) { for (const btn of document.querySelectorAll(".stats-range .btn-secondary")) { btn.classList.toggle("is-active", btn.id === id); } } async function loadStats() { const from = localInputToIso(document.getElementById("from").value); const to = localInputToIso(document.getElementById("to").value); const limit = Number(document.getElementById("limit").value) || 200; const qs = new URLSearchParams(); if (from) qs.set("from", from); if (to) qs.set("to", to); qs.set("limit", String(limit)); setStatus("加载中…", "loading"); try { const res = await fetch(`/api/stats/tokens?${qs}`); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); const records = data.records || []; renderSummary(data.summary); renderRows(records); const totalCalls = data.summary?.totalCalls ?? 0; setStatus( `共 ${formatNum(totalCalls)} 次调用 · 显示 ${formatNum(records.length)} 条`, "idle", ); } catch (err) { renderSummary(null); renderRows([]); setStatus( `加载失败:${err instanceof Error ? err.message : String(err)}`, "error", ); } } function renderSummary(summary) { const el = document.getElementById("summary"); if (!summary) { el.innerHTML = ""; return; } const metrics = [ ["调用次数", summary.totalCalls, null], ["总 token", summary.totalTokens, "total"], ["prompt", summary.promptTokens, null], ["completion", summary.completionTokens, null], ["cached", summary.totalCached, null], ]; el.innerHTML = metrics .map( ([label, value, emphasis]) => `