(function (global) { function fmtPnl(v) { if (v == null || v === "") return "—"; const n = Number(v); if (!Number.isFinite(n)) return "—"; return (n > 0 ? "+" : "") + n.toFixed(2) + " U"; } function pnlClass(v) { const n = Number(v); if (!Number.isFinite(n) || n === 0) return "pnl-flat"; return n > 0 ? "pnl-up" : "pnl-down"; } function fmtPnlHtml(v) { return '' + escapeHtml(fmtPnl(v)) + ""; } function escapeHtml(s) { return String(s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } function positionSummary(brief) { const list = brief || []; if (!list.length) return '暂无持仓'; const items = list.slice(0, 8).map(function (p) { const id = escapeHtml(p.inst_id || ""); const sheets = escapeHtml(String(p.sheets != null ? p.sheets : "—")); return "
  • " + id + " · " + sheets + "张 · " + fmtPnlHtml(p.pnl_usdt) + "
  • "; }); const more = list.length > 8 ? '
  • …共 ' + list.length + " 笔
  • " : ""; return ""; } function renderRow(row) { const snap = row.snapshot || {}; const inst = snap.instance || {}; const pnl = snap.pnl && snap.pnl.unrealized_usdt != null ? snap.pnl.unrealized_usdt : snap.upl_total_usdc; const brief = snap.positions_brief || snap.positions || []; const online = !!row.online; const status = online ? '在线' : '离线'; const err = row.error ? '
    错误: ' + escapeHtml(row.error) + "
    " : ""; return ( "" + "" + escapeHtml(row.name || "") + "" + err + "" + "" + status + "" + "" + escapeHtml(inst.mode || "—") + "" + "" + fmtPnlHtml(pnl) + "" + "" + positionSummary(brief) + "" + '' + escapeHtml(row.pulled_at || "—") + "" + '
    ' + '内嵌打开' + '' + "
    " + "" ); } async function refresh() { const status = document.getElementById("overview-status"); const grid = document.getElementById("overview-grid"); if (!grid) return; if (status) status.textContent = "刷新中…"; try { const r = await fetch("/api/overview"); const d = await r.json(); if (!d.ok) throw new Error(d.msg || "失败"); const list = d.instances || []; if (!list.length) { grid.innerHTML = '

    暂无启用实例,请先到「实例」添加.

    '; } else { grid.innerHTML = '
    ' + "" + "" + "" + list.map(renderRow).join("") + "
    名称状态模式浮盈持仓拉取时间操作
    "; grid.querySelectorAll("[data-open-tab]").forEach(function (btn) { btn.addEventListener("click", async function () { const id = btn.getAttribute("data-open-tab"); const rr = await fetch("/api/instances/" + id + "/open_url"); const dd = await rr.json(); if (dd.ok && dd.url) window.open(dd.url, "_blank", "noopener"); else alert(dd.msg || "无法打开"); }); }); } if (status) status.textContent = "已更新 · 共 " + list.length + " 台"; } catch (e) { if (status) status.textContent = e.message || "加载失败"; } } function boot() { const btn = document.getElementById("btn-refresh"); if (btn) btn.addEventListener("click", refresh); refresh(); setInterval(refresh, 10000); } global.HubOverview = { boot: boot, refresh: refresh }; })(window);