diff --git a/manual_trading_hub/static/app.css b/manual_trading_hub/static/app.css index 1773796..801e2d0 100644 --- a/manual_trading_hub/static/app.css +++ b/manual_trading_hub/static/app.css @@ -2060,6 +2060,31 @@ body.login-page { margin-right: 4px; } +.sym-link { + background: none; + border: none; + padding: 0; + margin: 0; + font: inherit; + color: var(--accent); + cursor: pointer; + text-align: left; + text-decoration: underline; + text-underline-offset: 2px; +} + +.sym-link:hover { + color: #00ff9d; +} + +.pos-symbol-link { + display: inline; +} + +.pos-symbol-link strong { + font-weight: inherit; +} + .market-price-tag { position: absolute; right: 0; diff --git a/manual_trading_hub/static/app.js b/manual_trading_hub/static/app.js index 488a79f..dfcc1ca 100644 --- a/manual_trading_hub/static/app.js +++ b/manual_trading_hub/static/app.js @@ -491,7 +491,47 @@ } } + function normalizeMarketSymbol(raw) { + let s = (raw || "").trim().toUpperCase(); + if (!s) return ""; + if (s.includes(":")) { + const base = s.split(":")[0]; + if (base.includes("/")) return base; + } + return s; + } + + function resolveExchangeKey(exchangeId) { + const row = (lastMonitorRows || []).find((r) => String(r.id) === String(exchangeId)); + return (row && (row.key || row.id)) || exchangeId; + } + + function openMarketForPosition(exchangeId, symbol, exchangeKey) { + const exKey = exchangeKey || resolveExchangeKey(exchangeId); + const sym = normalizeMarketSymbol(symbol); + if (!exKey || !sym) { + showToast("无法打开行情:缺少交易所或合约", true); + return; + } + if (expandedExchangeId) { + closeExchangeFullscreen(); + } + const qs = new URLSearchParams({ exchange_key: exKey, symbol: sym }); + history.pushState({}, "", "/market?" + qs.toString()); + setActiveNav(); + if (window.hubMarketChart && window.hubMarketChart.openWith) { + window.hubMarketChart.openWith(exKey, sym); + } + } + function bindMonitorInteractions(box) { + box.querySelectorAll(".btn-open-market").forEach((btn) => { + btn.onclick = (ev) => { + ev.preventDefault(); + ev.stopPropagation(); + openMarketForPosition(btn.dataset.exId, btn.dataset.symbol, btn.dataset.exKey); + }; + }); box.querySelectorAll(".btn-open-instance").forEach((btn) => { btn.onclick = (ev) => { ev.preventDefault(); @@ -662,8 +702,9 @@ return row("止损", sl) + row("止盈", tp); } - function renderLivePositionCard(exchangeId, pos, monitorOrder) { + function renderLivePositionCard(exchangeId, exchangeKey, pos, monitorOrder) { const symbol = pos.symbol || ""; + const exKeyAttr = esc(exchangeKey || exchangeId || "").replace(/"/g, """); const side = (pos.side || "long").toLowerCase(); const sideCn = sideDirLabel(side); const sideCls = sideDirCls(side) || "side-long"; @@ -706,7 +747,7 @@ return `
| 合约 | 方向 | 张数 | 浮盈 | 操作 |
|---|---|---|---|---|
| ${esc(x.symbol)} | +${renderDirectionHtml(x.side)} | ${fmt(x.contracts, 4)} | ${fmt(x.unrealized_pnl, 2)} | @@ -844,7 +886,7 @@ `; inner += `