From d144cb592a1fece32b121983e4b77bbc21b3e7d3 Mon Sep 17 00:00:00 2001 From: dekun Date: Fri, 22 May 2026 10:51:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=85=B3=E9=94=AE=E4=BD=8D?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manual_trading_hub/hub.py | 10 ++++++++ manual_trading_hub/static/app.js | 35 ++++++++++++++++++++-------- manual_trading_hub/static/index.html | 4 ++++ manual_trading_hub/使用说明.md | 3 ++- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/manual_trading_hub/hub.py b/manual_trading_hub/hub.py index 165f855..772fbb4 100644 --- a/manual_trading_hub/hub.py +++ b/manual_trading_hub/hub.py @@ -206,11 +206,21 @@ async def api_monitor_board(): snap = await _fetch_flask_json(client, ex, "/api/price_snapshot") if isinstance(snap, dict): key_prices = snap.get("key_prices") + flask_ok = isinstance(hub_mon, dict) and hub_mon.get("ok") is not False + flask_err = None + if isinstance(hub_mon, dict) and hub_mon.get("ok") is False: + flask_err = ( + hub_mon.get("msg") + or hub_mon.get("error") + or (str(hub_mon.get("text") or "")[:200] or None) + ) out.append( { **agent_row, "review_url": ex.get("review_url") or "", "hub_monitor": hub_mon, + "flask_ok": flask_ok, + "flask_error": flask_err, "meta": (meta or {}).get("meta") if isinstance(meta, dict) else meta, "key_prices": key_prices, } diff --git a/manual_trading_hub/static/app.js b/manual_trading_hub/static/app.js index 96902c3..75097f0 100644 --- a/manual_trading_hub/static/app.js +++ b/manual_trading_hub/static/app.js @@ -97,9 +97,10 @@ const ag = row.agent || {}; const pos = Array.isArray(ag.positions) ? ag.positions : []; const hm = row.hub_monitor || {}; - const keys = hm.keys || []; - const orders = hm.orders || []; - const trends = hm.trends || []; + const flaskOk = row.flask_ok !== false && hm.ok !== false; + const keys = flaskOk ? hm.keys || [] : []; + const orders = flaskOk ? hm.orders || [] : []; + const trends = flaskOk ? hm.trends || [] : []; const kmap = {}; (row.key_prices || []).forEach((k) => { kmap[k.id] = k; @@ -129,12 +130,26 @@ inner += `
${esc(o.symbol)} ${o.direction} 成交${o.trigger_price}
`; }); } - if ((row.capabilities || []).includes("key") && keys.length) { - inner += `
关键位 ${keys.length} 条
`; - keys.slice(0, 6).forEach((k) => { - const kp = kmap[k.id] || {}; - inner += `
${esc(k.symbol)} ${esc(k.monitor_type)} 上${k.upper}/下${k.lower} 门控:${esc(kp.gate_summary || "-")}
`; - }); + if ((row.capabilities || []).includes("key")) { + if (!flaskOk) { + inner += `
关键位/机器人:策略 Flask 未连通
`; + inner += `
${esc(row.flask_error || hm.msg || "请确认实例 app 已启动,且 HUB_BRIDGE_TOKEN 与实例一致或 APP_AUTH_DISABLED=true")}
`; + } else if (!keys.length) { + inner += `
关键位:当前无记录(在下单区或实例首页添加)
`; + } else { + inner += `
关键位 ${keys.length} 条
`; + keys.slice(0, 8).forEach((k) => { + const kp = kmap[k.id] || kmap[String(k.id)] || {}; + const mt = k.monitor_type || k.type || ""; + inner += `
${esc(k.symbol)} ${esc(mt)} 上${k.upper}/下${k.lower}`; + if (kp.price_display != null || kp.price != null) { + inner += ` · 现价 ${esc(kp.price_display != null ? kp.price_display : kp.price)}`; + } + inner += ` · 门控 ${esc(kp.gate_summary || "-")}
`; + }); + } + } else if ((row.capabilities || []).includes("trend")) { + inner += `
该账户为趋势户,无关键位(见趋势计划或下单区)
`; } if (trends.length) { inner += `
趋势计划 ${trends.length} 个运行中
`; @@ -144,7 +159,7 @@ } } const review = row.review_url - ? `复盘` + ? `交易复盘` : ""; return `
diff --git a/manual_trading_hub/static/index.html b/manual_trading_hub/static/index.html index 6ab07f3..fbe408e 100644 --- a/manual_trading_hub/static/index.html +++ b/manual_trading_hub/static/index.html @@ -15,6 +15,10 @@

监控区

+

+ 持仓/余额来自子代理;关键位、机器人单来自各实例 Flask(须 PM2 跑着 crypto_*)。 + 卡片右上角「交易复盘」= 打开该所交易记录页,不在中控里做复盘。 +