diff --git a/manual_trading_hub/hub.py b/manual_trading_hub/hub.py index 1d5f3c4..d694bf2 100644 --- a/manual_trading_hub/hub.py +++ b/manual_trading_hub/hub.py @@ -62,7 +62,7 @@ _allow_pub_raw = (os.getenv("HUB_ALLOW_PUBLIC") or "").strip().lower() # 云服务器 + 域名反代时设为 true:不做 IP 限制,仅靠 HUB_PASSWORD / 登录页保护 HUB_ALLOW_PUBLIC = _allow_pub_raw in ("1", "true", "yes", "on") DIR = Path(__file__).resolve().parent -HUB_BUILD = "20260525-hub-sso" +HUB_BUILD = "20260525-ui-dir" HUB_AGENT_TIMEOUT = float(os.getenv("HUB_AGENT_TIMEOUT", "8")) HUB_FLASK_TIMEOUT = float(os.getenv("HUB_FLASK_TIMEOUT", "10")) _board_key_prices_raw = (os.getenv("HUB_BOARD_KEY_PRICES", "true") or "").strip().lower() diff --git a/manual_trading_hub/static/app.css b/manual_trading_hub/static/app.css index ed77791..da4c12d 100644 --- a/manual_trading_hub/static/app.css +++ b/manual_trading_hub/static/app.css @@ -710,14 +710,35 @@ body.hub-fullscreen-open { font-weight: 500; } -.hub-pos-card .pos-side-long { - background: rgba(37, 58, 110, 0.9); - color: #6eb5ff; +.hub-pos-card .pos-side-long, +.hub-pos-card .pos-side-badge.side-long { + background: rgba(0, 255, 157, 0.12); + color: var(--green); + border: 1px solid rgba(0, 255, 157, 0.35); } -.hub-pos-card .pos-side-short { - background: rgba(74, 34, 48, 0.9); - color: #ff8a8a; +.hub-pos-card .pos-side-short, +.hub-pos-card .pos-side-badge.side-short { + background: rgba(255, 77, 109, 0.12); + color: var(--red); + border: 1px solid rgba(255, 77, 109, 0.35); +} + +.side-long { + color: var(--green); + font-weight: 600; + text-shadow: 0 0 10px rgba(0, 255, 157, 0.25); +} + +.side-short { + color: var(--red); + font-weight: 600; + text-shadow: 0 0 10px rgba(255, 77, 109, 0.25); +} + +.data-table td.side-long, +.data-table td.side-short { + font-weight: 600; } .hub-pos-card .pos-head-actions { @@ -890,6 +911,31 @@ body.hub-fullscreen-open { border-radius: 8px; } +.hub-mini-card.hub-key-pending, +.list-line.hub-key-pending { + border-color: rgba(0, 212, 255, 0.55); + background: rgba(0, 212, 255, 0.08); + box-shadow: 0 0 16px rgba(0, 212, 255, 0.12); +} + +.hub-key-pending-tag { + display: inline-block; + margin-left: 6px; + padding: 1px 7px; + font-size: 10px; + font-weight: 600; + color: var(--accent); + background: rgba(0, 212, 255, 0.15); + border: 1px solid rgba(0, 212, 255, 0.45); + border-radius: 4px; + vertical-align: middle; +} + +.hub-key-pending .hub-key-status-line, +.list-line.hub-key-pending { + color: var(--text); +} + .hub-mini-title { font-size: 12px; font-weight: 600; diff --git a/manual_trading_hub/static/app.js b/manual_trading_hub/static/app.js index 7d495b8..2f0fe0e 100644 --- a/manual_trading_hub/static/app.js +++ b/manual_trading_hub/static/app.js @@ -77,6 +77,45 @@ return n > 0 ? "pnl-pos" : "pnl-neg"; } + function normSide(side) { + const s = (side || "").toLowerCase(); + if (s === "buy") return "long"; + if (s === "sell") return "short"; + return s; + } + + function sideDirCls(side) { + const s = normSide(side); + if (s === "long") return "side-long"; + if (s === "short") return "side-short"; + return ""; + } + + function sideDirLabel(side) { + const s = normSide(side); + if (s === "long") return "做多"; + if (s === "short") return "做空"; + return side || "—"; + } + + function renderDirectionHtml(side) { + const cls = sideDirCls(side); + const label = sideDirLabel(side); + if (!cls) return esc(String(label)); + return `${esc(label)}`; + } + + function keyHasPendingOrder(keyRow, keyPrice) { + const kp = keyPrice || {}; + const oid = keyRow.fib_limit_order_id; + if (oid != null && String(oid).trim() !== "") return true; + const gm = String(kp.gate_metrics || ""); + if (gm.includes("限价单") || gm.includes("挂单")) return true; + const gs = String(kp.gate_summary || ""); + if (/挂|限价|等待成交/.test(gs)) return true; + return false; + } + /** 全屏持仓区:按仓位数量附加布局 class(1~6 固定列数,7+ 自动填充) */ function hubPosListCountClass(n) { const c = Math.max(0, parseInt(n, 10) || 0); @@ -499,8 +538,8 @@ function renderLivePositionCard(exchangeId, pos, monitorOrder) { const symbol = pos.symbol || ""; const side = (pos.side || "long").toLowerCase(); - const sideCn = side === "long" ? "做多" : "做空"; - const sideCls = side === "long" ? "pos-side-long" : "pos-side-short"; + const sideCn = sideDirLabel(side); + const sideCls = sideDirCls(side) || "side-long"; const mo = monitorOrder || {}; const cond = condOrdersFromPosition(pos); const reg = Array.isArray(pos.regular_orders) ? pos.regular_orders : []; @@ -584,10 +623,16 @@ .map((k) => { const kp = kmap[k.id] || kmap[String(k.id)] || {}; const mt = k.monitor_type || k.type || ""; - return `
| 合约 | 方向 | 张数 | 浮盈 | 操作 | |
|---|---|---|---|---|---|
| ${esc(x.symbol)} | -${esc(x.side)} | +${renderDirectionHtml(x.side)} | ${fmt(x.contracts, 4)} | ${fmt(x.unrealized_pnl, 4)} |
@@ -673,7 +718,7 @@
if (orders.length) {
inner += ` 下单监控 · ${orders.length} `;
orders.forEach((o) => {
- inner += `${esc(o.symbol || o.exchange_symbol)} · ${esc(o.direction)} · 触发 ${fmt(o.trigger_price, 4)} `;
+ inner += `${esc(o.symbol || o.exchange_symbol)} · ${renderDirectionHtml(o.direction)} · 触发 ${fmt(o.trigger_price, 4)} `;
});
}
if ((row.capabilities || []).includes("key")) {
@@ -687,19 +732,24 @@
keys.forEach((k) => {
const kp = kmap[k.id] || kmap[String(k.id)] || {};
const mt = k.monitor_type || k.type || "";
- let line = `${esc(k.symbol)} · ${esc(mt)} · ${k.upper} / ${k.lower}`;
+ const pending = keyHasPendingOrder(k, kp);
+ const lineCls = pending ? "list-line hub-key-pending" : "list-line";
+ let line = `${esc(k.symbol)} · ${esc(mt)}`;
+ if (k.direction) line += ` · ${renderDirectionHtml(k.direction)}`;
+ if (pending) line += ` · 挂单`;
+ line += ` · ${esc(k.upper)} / ${esc(k.lower)}`;
if (kp.price_display != null || kp.price != null) {
line += ` · ${esc(kp.price_display != null ? kp.price_display : kp.price)}`;
}
line += ` · ${esc(kp.gate_summary || "-")}`;
- inner += `${line} `;
+ inner += `${line} `;
});
}
}
if ((row.capabilities || []).includes("trend") && trends.length) {
inner += `趋势回调 · ${trends.length} `;
trends.forEach((t) => {
- inner += `#${t.id} ${esc(t.symbol)} ${t.direction} · SL ${t.stop_loss} · TP ${t.take_profit} `;
+ inner += `#${t.id} ${esc(t.symbol)} ${renderDirectionHtml(t.direction)} · SL ${t.stop_loss} · TP ${t.take_profit} `;
});
}
if (rolls.length) {
diff --git a/manual_trading_hub/static/index.html b/manual_trading_hub/static/index.html
index 575f39e..d315fc6 100644
--- a/manual_trading_hub/static/index.html
+++ b/manual_trading_hub/static/index.html
@@ -8,7 +8,7 @@
-
+
@@ -109,6 +109,6 @@
-
+
|