feat: 研究Tab加子Tab(📋策略/📈策略进化)——进化子Tab表格展示AB路线每日研究成果(strategy_research_log), 新增/api/research/log

This commit is contained in:
xxm
2026-08-18 01:59:35 +08:00
parent 4568877154
commit 255d901270
2 changed files with 59 additions and 0 deletions
+40
View File
@@ -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');