feat: 研究Tab加子Tab(📋策略/📈策略进化)——进化子Tab表格展示AB路线每日研究成果(strategy_research_log), 新增/api/research/log
This commit is contained in:
@@ -2237,6 +2237,25 @@ def api_prd():
|
||||
register_routes(app)
|
||||
|
||||
|
||||
@app.route("/api/research/log")
|
||||
def api_research_log():
|
||||
"""AB路线每日研究日志(2026-08-18)"""
|
||||
try:
|
||||
_c = sqlite3.connect(str(DATA_DIR / "mofin.db"), timeout=10)
|
||||
_c.execute("PRAGMA busy_timeout=30000")
|
||||
rows = _c.execute(
|
||||
"SELECT log_date, market, weak_regime, finding, experiment, result, "
|
||||
"produced_strategy, produced_verified FROM strategy_research_log "
|
||||
"ORDER BY log_date DESC LIMIT 50").fetchall()
|
||||
_c.close()
|
||||
log = [{"log_date": r[0], "market": r[1], "weak_regime": r[2], "finding": r[3],
|
||||
"experiment": r[4], "result": r[5], "produced_strategy": r[6],
|
||||
"produced_verified": r[7]} for r in rows]
|
||||
return jsonify({"log": log})
|
||||
except Exception as e:
|
||||
return jsonify({"log": [], "error": str(e)})
|
||||
|
||||
|
||||
@app.route("/api/evolution/dashboard")
|
||||
def api_evolution_dashboard():
|
||||
"""进化模块 Dashboard"""
|
||||
|
||||
@@ -2179,6 +2179,11 @@ function renderResearch() {
|
||||
'<span class="spec-btns"><span class="spec-btn help" onclick="showModuleHelp(\'strategy\',\'human\')">?</span><span class="spec-btn ai" onclick="showModuleHelp(\'strategy\',\'ai\')">§</span></span>' +
|
||||
'<span class="text-xs text-slate-500">按市场×温区分组 · 每表格=该市该温区所有可用策略 · 🟢=当前市激活 · 温度=当前温区</span>' +
|
||||
'</div>' +
|
||||
'<div class="flex gap-2 items-center mb-3">' +
|
||||
'<button onclick="switchRsub(\'strategy\')" id="rsubtab-strategy" class="px-3 py-1 rounded text-sm bg-emerald-600/40 border border-emerald-600/60">📋 策略</button>' +
|
||||
'<button onclick="switchRsub(\'evo\')" id="rsubtab-evo" class="px-3 py-1 rounded text-sm bg-slate-800 border border-slate-700">📈 策略进化</button>' +
|
||||
'<span class="text-xs text-slate-500">策略进化=AB路线每日研究成果记录</span>' +
|
||||
'</div>' +
|
||||
'<div id="rsub-strategy">' +
|
||||
'<div id="evo-box" class="mb-3 bg-slate-800/60 border border-slate-700 rounded-lg p-3"><div class="text-xs text-slate-500">🧬 进化模块加载中...</div></div>' +
|
||||
'<div class="flex gap-2 items-center mb-3 flex-wrap">' +
|
||||
@@ -2191,11 +2196,46 @@ function renderResearch() {
|
||||
'<span class="text-xs text-slate-500">每版策略基于上一版归因分析迭代 · 点击行展开明细</span></div>' +
|
||||
'<div id="strategyList"><div class="text-slate-500 text-sm">加载中...</div></div>' +
|
||||
'<div id="strategyDetail" class="mt-4"></div>' +
|
||||
'</div>' +
|
||||
'<div id="rsub-evo" class="hidden">' +
|
||||
'<div class="text-xs text-slate-500 mb-2">📈 策略进化 — AB路线每日研究成果(LLM主导研究,产出策略默认不激活待审查)</div>' +
|
||||
'<div id="evo-log-list"><div class="text-slate-500 text-sm">加载中...</div></div>' +
|
||||
'</div>';
|
||||
// 首次渲染即加载策略列表(无子Tab切换)。
|
||||
// 2026-08-15 修复:不能在此直接 loadStrategyList()——此时 btPeriod.value 还是初始默认 '1m',
|
||||
// 与下方恢复 savedPt='2y' 后的调用并发竞态,1m 响应后到会覆盖 2y 渲染(周期错乱+综合分被小样本置信打崩)。
|
||||
loadEvolutionBox();
|
||||
// 2026-08-18 子Tab切换 + 进化日志
|
||||
window.switchRsub = function(name) {
|
||||
const isStr = name === 'strategy';
|
||||
document.getElementById('rsub-strategy').classList.toggle('hidden', !isStr);
|
||||
document.getElementById('rsub-evo').classList.toggle('hidden', isStr);
|
||||
const bs = document.getElementById('rsubtab-strategy'), be = document.getElementById('rsubtab-evo');
|
||||
if (bs) bs.className = 'px-3 py-1 rounded text-sm ' + (isStr ? 'bg-emerald-600/40 border border-emerald-600/60' : 'bg-slate-800 border border-slate-700');
|
||||
if (be) be.className = 'px-3 py-1 rounded text-sm ' + (isStr ? 'bg-slate-800 border border-slate-700' : 'bg-emerald-600/40 border border-emerald-600/60');
|
||||
if (!isStr) loadEvoLog();
|
||||
};
|
||||
window.loadEvoLog = function() {
|
||||
const el = document.getElementById('evo-log-list');
|
||||
if (!el) return;
|
||||
fetch('/api/research/log').then(r => r.json()).then(data => {
|
||||
const rows = data.log || [];
|
||||
if (!rows.length) { el.innerHTML = '<div class="text-slate-500 text-sm">暂无研究记录(每日AB研究任务运行后出现)</div>'; return; }
|
||||
let html = '<table class="w-full text-xs"><thead><tr class="text-slate-500 border-b border-slate-700">' +
|
||||
'<th class="text-left px-2 py-1">日期</th><th class="text-left px-2 py-1">市场/温区</th>' +
|
||||
'<th class="text-left px-2 py-1">发现薄弱点</th><th class="text-left px-2 py-1">尝试</th>' +
|
||||
'<th class="text-left px-2 py-1">结果</th><th class="text-left px-2 py-1">产出策略</th></tr></thead><tbody>';
|
||||
rows.forEach(r => {
|
||||
html += '<tr class="border-b border-slate-800/40"><td class="px-2 py-1">' + (r.log_date||'') + '</td>' +
|
||||
'<td class="px-2 py-1">' + (r.market||'') + '/' + (r.weak_regime||'') + '</td>' +
|
||||
'<td class="px-2 py-1 whitespace-normal">' + (r.finding||'') + '</td>' +
|
||||
'<td class="px-2 py-1">' + (r.experiment||'') + '</td>' +
|
||||
'<td class="px-2 py-1">' + (r.result||'') + '</td>' +
|
||||
'<td class="px-2 py-1">' + (r.produced_strategy||'') + (r.produced_verified ? ' <span class="text-green-400">✅</span>' : '') + '</td></tr>';
|
||||
});
|
||||
el.innerHTML = html + '</tbody></table>';
|
||||
}).catch(e => { el.innerHTML = '<div class="text-red-400 text-sm">加载失败: ' + e + '</div>'; });
|
||||
};
|
||||
// 恢复用户上次选择的周期(防自动刷新重置,2026-07-30老爸抓包)
|
||||
const savedPt = window._btPeriodVal || '2y';
|
||||
const ptSel = document.getElementById('btPeriod');
|
||||
|
||||
Reference in New Issue
Block a user