diff --git a/server.py b/server.py index a56c909..acac27b 100644 --- a/server.py +++ b/server.py @@ -198,7 +198,59 @@ def api_market(): return jsonify(_load_json(DATA_DIR / "market.json", {})) -# ── 数据写入API(供 cron/update_data.py 调用) ────────── +# ── 信号API(新增) ───────────────────────────────────── + + +@app.route("/api/signals") +def api_signals(): + """最近信号 + 小果分析""" + try: + from mofin_db import get_conn + conn = get_conn() + signals = conn.execute(""" + SELECT sn.id, sn.sector, sn.overall_sentiment, + sn.summary, sn.source, sn.created_at, + ss.signal_type, ss.severity + FROM signal_news sn + LEFT JOIN sector_signals ss ON sn.signal_id = ss.id + ORDER BY sn.id DESC LIMIT 20 + """).fetchall() + conn.close() + return jsonify([dict(r) for r in signals]) + except Exception as e: + return jsonify({"error": str(e)}), 500 + + +@app.route("/api/xiaoguo-scan") +def api_xiaoguo_scan(): + """小果扫描统计""" + try: + from mofin_db import get_conn + conn = get_conn() + total = conn.execute("SELECT COUNT(*) FROM xiaoguo_scan_tracker").fetchone()[0] + found = conn.execute("SELECT COUNT(*) FROM xiaoguo_scan_tracker WHERE found_count>0").fetchone()[0] + recent = conn.execute(""" + SELECT code, name, last_scanned_at, found_count + FROM xiaoguo_scan_tracker + ORDER BY last_scanned_at DESC LIMIT 20 + """).fetchall() + source_count = conn.execute(""" + SELECT source, COUNT(*) as cnt FROM signal_news + WHERE datetime(created_at) > datetime('now', '-1 day') + GROUP BY source + """).fetchall() + conn.close() + return jsonify({ + "total_scanned": total, + "found_signals": found, + "recent": [dict(r) for r in recent], + "source_today": {r["source"]: r["cnt"] for r in source_count} + }) + except Exception as e: + return jsonify({"error": str(e)}), 500 + + +# ── 数据写入API ── @app.route("/api/update/portfolio", methods=["POST"]) def update_portfolio(): diff --git a/static/index.html b/static/index.html index 119a1ed..5e55ee0 100644 --- a/static/index.html +++ b/static/index.html @@ -50,6 +50,7 @@ body { background: #0f0f13; color: #e2e8f0; } + 📸 上传 @@ -62,6 +63,7 @@ body { background: #0f0f13; color: #e2e8f0; }
+ @@ -144,6 +146,7 @@ function renderTab(name) { else if (name === 'evaluation') renderEvaluation(); else if (name === 'prompts') renderPrompts(); else if (name === 'market') renderMarket(); + else if (name === 'signals') renderSignals(); } // ── Data Fetching ── @@ -1101,6 +1104,67 @@ function closePromptModal() { document.getElementById('promptModal').classList.add('hidden'); document.getElementById('promptModal').classList.remove('flex'); } + +// ── 信号页 ── +async function renderSignals() { + const el = document.getElementById('tab-signals'); + el.innerHTML = '