diff --git a/static/hub.css b/static/hub.css
index 3956181..ba0a6eb 100644
--- a/static/hub.css
+++ b/static/hub.css
@@ -382,6 +382,15 @@ input.readonly {
.pnl-up { color: var(--ok); font-weight: 600; }
.pnl-down { color: var(--bad); font-weight: 600; }
.pnl-flat { color: var(--muted); }
+.liq-ok { color: var(--text); }
+.liq-warn {
+ color: #fbbf24;
+ font-weight: 600;
+}
+.liq-brief--warn {
+ border-left: 2px solid rgba(251, 191, 36, 0.7);
+ padding-left: 8px;
+}
@media (max-width: 800px) {
.desk,
diff --git a/static/hub.js b/static/hub.js
index 175143e..16b10fa 100644
--- a/static/hub.js
+++ b/static/hub.js
@@ -39,6 +39,55 @@
return "
" + items.join("") + more + "
";
}
+ function fmtBidPx(v) {
+ if (v == null || v === "") return "—";
+ const n = Number(v);
+ if (!Number.isFinite(n)) return "—";
+ let s = n.toFixed(4).replace(/\.?0+$/, "");
+ return s || "0";
+ }
+
+ function isLiquidityWeak(p) {
+ if (!p) return false;
+ if (p.liquidity_ok === false || p.bid_invalid) return true;
+ const uncovered = Number(p.uncovered_sheets);
+ return Number.isFinite(uncovered) && uncovered > 0;
+ }
+
+ function bidLiquidityLine(p) {
+ if (p.bid_invalid || (p.bid_px == null && (p.bid_sz == null || p.bid_sz === ""))) {
+ const reason = (p.bid_invalid_reason || "无买一/残档").toString();
+ const short = reason.length > 18 ? reason.slice(0, 18) + "…" : reason;
+ return { text: short, weak: true };
+ }
+ const px = fmtBidPx(p.bid_px);
+ const sz = p.bid_sz != null ? String(p.bid_sz) : "—";
+ const uncovered = Number(p.uncovered_sheets);
+ let text = px + " / " + sz + "张";
+ const weak = isLiquidityWeak(p);
+ if (Number.isFinite(uncovered) && uncovered > 0) {
+ text += "(差" + uncovered + ")";
+ }
+ return { text: text, weak: weak };
+ }
+
+ function bidLiquiditySummary(brief) {
+ const list = brief || [];
+ if (!list.length) return '—';
+ const items = list.slice(0, 8).map(function (p) {
+ const line = bidLiquidityLine(p);
+ const cls = line.weak ? "liq-warn" : "liq-ok";
+ return '' + escapeHtml(line.text) + "";
+ });
+ const more =
+ list.length > 8
+ ? '…共 ' + list.length + " 笔"
+ : "";
+ const anyWeak = list.some(isLiquidityWeak);
+ const wrapCls = anyWeak ? "pos-brief liq-brief liq-brief--warn" : "pos-brief liq-brief";
+ return '' + items.join("") + more + "
";
+ }
+
function renderRow(row) {
const snap = row.snapshot || {};
const inst = snap.instance || {};
@@ -73,6 +122,9 @@
"" +
positionSummary(brief) +
" | " +
+ "" +
+ bidLiquiditySummary(brief) +
+ " | " +
'' +
escapeHtml(row.pulled_at || "—") +
" | " +
@@ -105,7 +157,7 @@
grid.innerHTML =
'' +
"" +
- "| 名称 | 状态 | 模式 | 浮盈 | 持仓 | 拉取时间 | 操作 | " +
+ "名称 | 状态 | 模式 | 浮盈 | 持仓 | 买一/流动性 | 拉取时间 | 操作 | " +
"
" +
list.map(renderRow).join("") +
"
";