From 440ce56b0bd433a41f30c0d933a08bf648431895 Mon Sep 17 00:00:00 2001 From: hmo Date: Wed, 22 Jul 2026 23:25:34 +0800 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=E7=9B=AF=E7=9B=98=E6=8E=A8=E8=8D=90?= =?UTF-8?q?=E5=8C=BARR=E4=B8=89=E5=80=BC+=E4=B8=AA=E8=82=A1=E5=BC=B9?= =?UTF-8?q?=E7=AA=97DB=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /api/stock/: 从holding_strategies读策略/三值RR/action/full_analysis (原先只读data/stocks/{code}.json, 与DB脱节, 弹窗打开=空白) - openStock弹窗: 新增当前策略卡(信号/区间/损盈/三值RR/仓位/操作建议)+12维分析折叠区 - 盯盘推荐区RR列: 中值下方小字显示下沿~上沿(上次改错表了, renderWatchlist≠盯盘推荐区) --- server.py | 31 ++++++++++++++++++++++++++++++- static/index.html | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/server.py b/server.py index c0f34e6b..04d441bd 100644 --- a/server.py +++ b/server.py @@ -503,8 +503,37 @@ def api_report(report_id): @app.route("/api/stock/") def api_stock(code): - """个股详情 + 操作建议历史""" + """个股详情:DB策略(12维分析/action/三值RR)为主,JSON历史为辅。 + 根治:弹窗只读 data/stocks/{code}.json,与DB脱节,打开=空白。""" stock_data = _load_json(DATA_DIR / "stocks" / f"{code}.json", {}) + try: + conn = get_conn() + conn.row_factory = sqlite3.Row + r = conn.execute(""" + SELECT hs.code, hs.name, hs.timing_signal, hs.action, hs.position_advice, + hs.entry_low, hs.entry_high, hs.stop_loss, hs.take_profit, + hs.rr_ratio, hs.rr_low, hs.rr_high, hs.full_analysis, hs.reassessed_at, + hs.tag, hs.decision_type, + lp.price AS live_price, lp.change_pct + FROM holding_strategies hs + LEFT JOIN live_prices lp ON hs.code = lp.code + WHERE hs.code=? AND hs.status='active' + """, (code,)).fetchone() + conn.close() + if r: + stock_data.update({ + "code": r["code"], "name": r["name"], + "timing_signal": r["timing_signal"], "action": r["action"], + "position_advice": r["position_advice"], + "entry_low": r["entry_low"], "entry_high": r["entry_high"], + "stop_loss": r["stop_loss"], "take_profit": r["take_profit"], + "rr_ratio": r["rr_ratio"], "rr_low": r["rr_low"], "rr_high": r["rr_high"], + "full_analysis": r["full_analysis"], "reassessed_at": r["reassessed_at"], + "tag": r["tag"], "decision_type": r["decision_type"], + "price": r["live_price"], "change_pct": r["change_pct"], + }) + except Exception as _e: + stock_data.setdefault("db_error", str(_e)) return jsonify(stock_data) diff --git a/static/index.html b/static/index.html index def1cba3..e87170d6 100644 --- a/static/index.html +++ b/static/index.html @@ -159,7 +159,9 @@ body { background: #0f0f13; color: #e2e8f0; }
+
+

📜 操作建议历史

@@ -696,6 +698,40 @@ async function openStock(code) {
` : `
暂无持仓数据
`; + // ── 当前策略卡(12维参数 + 三值RR + 操作建议)── + const sd = stockData || {}; + const hasStrategy = sd.action || sd.entry_low || sd.timing_signal; + if (hasStrategy) { + const rrMid = sd.rr_ratio || 0, rrLo = sd.rr_low || 0, rrHi = sd.rr_high || 0; + const rrTxt = rrMid ? `${rrMid.toFixed(2)}${(rrHi>0)?` (下沿${rrLo.toFixed(2)} / 上沿${rrHi.toFixed(2)})`:''}` : '—'; + document.getElementById('modalStrategy').innerHTML = ` +

🎯 当前策略 ${(sd.reassessed_at||'').slice(0,16)}

+
+
+ ${sd.timing_signal?`信号 ${sd.timing_signal}`:''} + ${sd.entry_low?`区间 ${sd.entry_low}~${sd.entry_high}`:''} + ${sd.stop_loss?`损 ${sd.stop_loss}`:''} + ${sd.take_profit?`盈 ${sd.take_profit}`:''} + RR ${rrTxt} + ${sd.position_advice?`仓位 ${sd.position_advice}`:''} +
+ ${sd.action?`
${sd.action}
`:''} +
`; + } else { + document.getElementById('modalStrategy').innerHTML = ''; + } + + // ── 12维完整分析(折叠)── + if (sd.full_analysis) { + document.getElementById('modalAnalysis').innerHTML = ` +
+ 📋 12维完整分析(点击展开) +
${sd.full_analysis}
+
`; + } else { + document.getElementById('modalAnalysis').innerHTML = ''; + } + // Render recommendation history const history = stockData.history || []; document.getElementById('modalHistory').innerHTML = history.length ? history.map(h => ` @@ -1542,7 +1578,7 @@ async function renderWatch() { '' + (sig || '—') + '' + '' + buyZone + '' + '' + sltp + '' + - '' + (rr ? rr.toFixed(2) : '—') + '' + + '' + (rr ? rr.toFixed(2) : '—') + ((s.rr_high>0)?'
'+(s.rr_low||0).toFixed(2)+'~'+s.rr_high.toFixed(2)+'':'') + '' + '' + posDisplay + '' + '' + strat + '' + '' +