Fix order_popup flag through SSO and hide stats in hub order popup.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-25 23:38:21 +08:00
parent d8140c6216
commit 347e6b5545
5 changed files with 55 additions and 17 deletions
+4 -2
View File
@@ -76,14 +76,15 @@
<span style="color:#8892b0;font-size:.75rem">统计页仍按北京时间 {{ stats_bundle.stats_reset_hour|default(reset_hour) }}:00 切日</span> <span style="color:#8892b0;font-size:.75rem">统计页仍按北京时间 {{ stats_bundle.stats_reset_hour|default(reset_hour) }}:00 切日</span>
</div> </div>
{% endif %} {% endif %}
<div class="export-bar instance-desktop-only{% if order_popup %} embed-order-popup-hide{% endif %}"> {% if not order_popup %}
<div class="export-bar instance-desktop-only">
<span style="color:#9aa">数据导出(v{{ data_export_version }} CSVUTF-8;交易记录含开仓类型列,复盘单独导出):</span> <span style="color:#9aa">数据导出(v{{ data_export_version }} CSVUTF-8;交易记录含开仓类型列,复盘单独导出):</span>
<a href="/export/trade_records">交易记录</a> <a href="/export/trade_records">交易记录</a>
<a href="/export/journal_entries">复盘记录</a> <a href="/export/journal_entries">复盘记录</a>
<a href="/export/key_monitors">关键位(当前)</a> <a href="/export/key_monitors">关键位(当前)</a>
<a href="/export/key_monitor_history">关键位历史</a> <a href="/export/key_monitor_history">关键位历史</a>
</div> </div>
<div class="stat-box instance-desktop-only{% if order_popup %} embed-order-popup-hide{% endif %}"> <div class="stat-box instance-desktop-only">
<div class="stat-item"><div class="label">交易所</div><div class="value">{{ exchange_display }}</div></div> <div class="stat-item"><div class="label">交易所</div><div class="value">{{ exchange_display }}</div></div>
<div class="stat-item"><div class="label">总交易</div><div class="value" id="stat-total">{{ total }}</div></div> <div class="stat-item"><div class="label">总交易</div><div class="value" id="stat-total">{{ total }}</div></div>
<div class="stat-item"><div class="label">错过次数</div><div class="value" id="stat-miss">{{ miss_count }}</div></div> <div class="stat-item"><div class="label">错过次数</div><div class="value" id="stat-miss">{{ miss_count }}</div></div>
@@ -92,6 +93,7 @@
<div class="stat-item"><div class="label">交易日</div><div class="value">{{ trading_day }}</div></div> <div class="stat-item"><div class="label">交易日</div><div class="value">{{ trading_day }}</div></div>
<div class="stat-item"><div class="label">当日资金(交易账户)</div><div class="value" id="current-capital">{{ funds_fmt(current_capital) }}U</div></div> <div class="stat-item"><div class="label">当日资金(交易账户)</div><div class="value" id="current-capital">{{ funds_fmt(current_capital) }}U</div></div>
</div> </div>
{% endif %}
{% if include_transfer_block and not order_popup %} {% if include_transfer_block and not order_popup %}
{% include 'gate_transfer_block.html' %} {% include 'gate_transfer_block.html' %}
{% endif %} {% endif %}
+20 -6
View File
@@ -126,6 +126,10 @@ def register_embed_routes(
if tab not in EMBED_TABS: if tab not in EMBED_TABS:
tab = "trade" tab = "trade"
session["hub_embed_shell"] = True session["hub_embed_shell"] = True
if request_order_popup():
session["hub_order_popup"] = True
else:
session.pop("hub_order_popup", None)
return render_main_page_fn(tab, embed_mode="shell") return render_main_page_fn(tab, embed_mode="shell")
@login_required @login_required
@@ -140,13 +144,23 @@ def register_embed_routes(
return jsonify({"ok": True, "page": tab, "html": html}) return jsonify({"ok": True, "page": tab, "html": html})
def merge_next_query(path: str, **params: str) -> str:
"""把 query 参数合并进 next 路径(SSO / embed 跳转用)。"""
split = urlsplit(path or "/")
q = dict(parse_qsl(split.query, keep_blank_values=True))
for k, v in params.items():
val = (v or "").strip()
if val:
q[k] = val
base = split.path or "/"
return f"{base}?{urlencode(q)}" if q else base
def request_order_popup() -> bool: def request_order_popup() -> bool:
return (request.args.get("order_popup") or "").strip().lower() in ( raw = (request.args.get("order_popup") or "").strip().lower()
"1", if raw in ("1", "true", "yes", "on"):
"true", return True
"yes", return bool(session.get("hub_order_popup"))
"on",
)
def embed_context_extras(exchange_key: str) -> dict: def embed_context_extras(exchange_key: str) -> dict:
+9
View File
@@ -1900,8 +1900,12 @@ def api_instance_open_url(
next: str = "/", next: str = "/",
embed: str = "", embed: str = "",
hub_theme: str = "", hub_theme: str = "",
order_popup: str = "",
symbol: str = "",
): ):
"""已登录中控时生成实例 SSO 打开链接(2h 有效、单次使用,复用 HUB_BRIDGE_TOKEN)。""" """已登录中控时生成实例 SSO 打开链接(2h 有效、单次使用,复用 HUB_BRIDGE_TOKEN)。"""
from instance_embed_lib import merge_next_query
_require_hub_logged_in(request) _require_hub_logged_in(request)
if not HUB_BRIDGE_TOKEN: if not HUB_BRIDGE_TOKEN:
raise HTTPException(status_code=503, detail="未配置 HUB_BRIDGE_TOKEN,无法签发实例打开链接") raise HTTPException(status_code=503, detail="未配置 HUB_BRIDGE_TOKEN,无法签发实例打开链接")
@@ -1915,6 +1919,11 @@ def api_instance_open_url(
if not ex_key: if not ex_key:
raise HTTPException(status_code=400, detail="该账户缺少 key(用于 SSO 校验)") raise HTTPException(status_code=400, detail="该账户缺少 key(用于 SSO 校验)")
nxt = safe_next_path(next) nxt = safe_next_path(next)
if (order_popup or "").strip().lower() in ("1", "true", "yes", "on"):
nxt = merge_next_query(nxt, order_popup="1")
sym = (symbol or "").strip()
if sym:
nxt = merge_next_query(nxt, symbol=sym)
token = mint_hub_sso_token(ex_key, nxt) token = mint_hub_sso_token(ex_key, nxt)
if not token: if not token:
raise HTTPException(status_code=503, detail="签发 SSO 失败") raise HTTPException(status_code=503, detail="签发 SSO 失败")
+15 -9
View File
@@ -419,8 +419,12 @@
async function fetchInstanceOpenUrl(exchangeId, nextPath, opts) { async function fetchInstanceOpenUrl(exchangeId, nextPath, opts) {
const options = opts || {}; const options = opts || {};
const next = nextPath || "/"; const next = nextPath || "/";
const q = new URLSearchParams({ exchange_id: String(exchangeId), next }); const q = new URLSearchParams();
q.set("exchange_id", String(exchangeId));
q.set("next", next);
if (options.embed) q.set("embed", "1"); if (options.embed) q.set("embed", "1");
if (options.orderPopup) q.set("order_popup", "1");
if (options.symbol) q.set("symbol", String(options.symbol));
if (options.embed && globalThis.HubTheme && typeof HubTheme.get === "function") { if (options.embed && globalThis.HubTheme && typeof HubTheme.get === "function") {
q.set("hub_theme", HubTheme.get()); q.set("hub_theme", HubTheme.get());
} }
@@ -493,10 +497,12 @@
async function openOrderPopup(exchangeId, opts) { async function openOrderPopup(exchangeId, opts) {
const options = opts || {}; const options = opts || {};
const symbol = (options.symbol || "").trim(); const symbol = (options.symbol || "").trim();
let next = "/trade?order_popup=1";
if (symbol) next += "&symbol=" + encodeURIComponent(symbol);
try { try {
const url = await fetchInstanceOpenUrl(exchangeId, next, { embed: true }); const url = await fetchInstanceOpenUrl(exchangeId, "/trade", {
embed: true,
orderPopup: true,
symbol: symbol || undefined,
});
const row = lastMonitorRows.find((x) => String(x.id) === String(exchangeId)); const row = lastMonitorRows.find((x) => String(x.id) === String(exchangeId));
const title = row ? row.name : exchangeId; const title = row ? row.name : exchangeId;
orderPopupCtx = { exchangeId: String(exchangeId), title, symbol }; orderPopupCtx = { exchangeId: String(exchangeId), title, symbol };
@@ -539,11 +545,11 @@
const frame = document.getElementById("order-popup-frame"); const frame = document.getElementById("order-popup-frame");
if (!frame) return; if (!frame) return;
try { try {
let next = "/trade?order_popup=1"; const url = await fetchInstanceOpenUrl(orderPopupCtx.exchangeId, "/trade", {
if (orderPopupCtx.symbol) { embed: true,
next += "&symbol=" + encodeURIComponent(orderPopupCtx.symbol); orderPopup: true,
} symbol: orderPopupCtx.symbol || undefined,
const url = await fetchInstanceOpenUrl(orderPopupCtx.exchangeId, next, { embed: true }); });
orderPopupUrl = url; orderPopupUrl = url;
setOrderPopupLoading(true); setOrderPopupLoading(true);
frame.src = url; frame.src = url;
+7
View File
@@ -1,5 +1,6 @@
from instance_embed_lib import ( from instance_embed_lib import (
EMBED_TABS, EMBED_TABS,
merge_next_query,
path_to_embed_tab, path_to_embed_tab,
rewrite_embed_dest, rewrite_embed_dest,
) )
@@ -27,6 +28,12 @@ def test_rewrite_embed_dest_order_popup_query():
assert "symbol=BTC" in url assert "symbol=BTC" in url
def test_merge_next_query_order_popup():
url = merge_next_query("/trade", order_popup="1", symbol="BTC/USDT")
assert "order_popup=1" in url
assert "symbol=BTC" in url
def test_embed_tabs_cover_main_nav(): def test_embed_tabs_cover_main_nav():
assert "trade" in EMBED_TABS assert "trade" in EMBED_TABS
assert "key_monitor" in EMBED_TABS assert "key_monitor" in EMBED_TABS