/** * 导航栏 BTC/ETH 现货报价:相对北京 08:00 开盘涨跌. */ (function (global) { "use strict"; const DEFAULT_POLL_MS = 5000; let timer = null; let inflight = false; function pollMs() { const raw = (document.body && document.body.getAttribute("data-price-refresh-ms")) || ""; const n = Number(raw); return Number.isFinite(n) && n >= 2000 ? n : DEFAULT_POLL_MS; } function fmtPrice(n) { const v = Number(n); if (!Number.isFinite(v)) return "—"; const abs = Math.abs(v); let digits = 2; if (abs >= 10000) digits = 1; else if (abs >= 1000) digits = 2; else if (abs >= 100) digits = 2; else if (abs >= 1) digits = 3; else digits = 4; try { return v.toLocaleString("en-US", { minimumFractionDigits: digits, maximumFractionDigits: digits, }); } catch (_) { return v.toFixed(digits); } } function fmtSigned(n, isPct) { const v = Number(n); if (!Number.isFinite(v)) return "—"; const abs = Math.abs(v); let digits = isPct ? 2 : abs >= 100 ? 1 : 2; if (!isPct && abs < 1) digits = 3; const body = abs.toLocaleString("en-US", { minimumFractionDigits: digits, maximumFractionDigits: digits, }); const sign = v > 0 ? "" : v < 0 ? "-" : ""; return sign + body + (isPct ? "%" : ""); } function dirClass(n) { const v = Number(n); if (!Number.isFinite(v) || v === 0) return "nav-spot--flat"; return v > 0 ? "nav-spot--up" : "nav-spot--down"; } function paintRow(row, t) { if (!row || !t) return; const lastEl = row.querySelector('[data-field="last"]'); const chgEl = row.querySelector('[data-field="change"]'); const pctEl = row.querySelector('[data-field="change_pct"]'); const dir = dirClass(t.change); row.classList.remove("nav-spot--up", "nav-spot--down", "nav-spot--flat"); row.classList.add(dir); if (lastEl) lastEl.textContent = fmtPrice(t.last); if (chgEl) chgEl.textContent = fmtSigned(t.change, false); if (pctEl) pctEl.textContent = fmtSigned(t.change_pct, true); const openHint = t.open != null ? "开盘 " + fmtPrice(t.open) + " (" + (t.anchor || "BJ 08:00") + ")" : t.anchor || "BJ 08:00"; row.title = (t.symbol || "") + " " + openHint; } function apply(data) { const root = document.getElementById("nav-spot-tickers"); if (!root) return; const list = (data && data.tickers) || []; list.forEach(function (t) { const base = (t.base || "").toUpperCase(); if (!base) return; const row = root.querySelector('.nav-spot-row[data-base="' + base + '"]'); paintRow(row, t); }); } function refresh() { const root = document.getElementById("nav-spot-tickers"); if (!root || inflight) return; inflight = true; fetch("/api/nav_spot_tickers") .then(function (r) { return r.json(); }) .then(function (data) { if (data && data.ok !== false) apply(data); }) .catch(function () {}) .finally(function () { inflight = false; }); } function start() { if (!document.getElementById("nav-spot-tickers")) return; refresh(); if (timer) clearInterval(timer); timer = setInterval(refresh, pollMs()); } global.refreshNavSpotTickers = refresh; global.startNavSpotTickers = start; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", start); } else { start(); } })(window);