1
This commit is contained in:
parent
a32be277fb
commit
1e3cddefd1
@ -72,7 +72,7 @@ function changePage(step){if(!state.totalPages)return;var next=state.page+step;i
|
||||
function setHoursAndReload(){state.offset=0;state.page=1;resetSelection();loadRuns();}
|
||||
function renderDetail(){var d=state.detail||{},s=d.summary||{};$('detailTitle').textContent='批次 #'+(s.run_id||s.id||'--')+' · '+fmtTime(s.started_at);$('detailWindow').textContent=fmtTime(s.window_start)+' - '+fmtTime(s.window_end);var timeline=(d.timeline||[]).map(function(t){return '<div class="stage '+statusCls(t.run_status)+'"><b>'+esc(t.stage)+'</b><span>'+fmtTime(t.started_at)+' · '+fmtDur(t.duration_ms)+'</span><span>'+esc(t.result_status||t.run_status)+'</span></div>';}).join('')||'<div class="empty">暂无阶段日志</div>';var counts=d.stage_counts||{};var chips=[['all','全部',0],['universe_gate','宇宙过滤',counts.universe_gate||0],['discovery','异动发现',counts.discovery||0],['quality_filter','质量验证',(counts.quality_pass||0)+(counts.quality_reject||0)],['trade_confirm','交易确认',counts.trade_confirm||0],['tracking','跟踪',counts.tracking||0],['review','复盘',counts.review||0],['missed','漏选',counts.missed||0]];var chipHtml=chips.map(function(c){return '<button class="chip '+(state.filter===c[0]?'active':'')+'" onclick="setFilter(\''+c[0]+'\')">'+c[1]+(c[2]?(' '+c[2]):'')+'</button>';}).join('');var minis=[['覆盖漏斗',(s.usdt_pair_count||0)+' / '+(s.tradable_universe_count||0)+' / '+(s.kline_attempt_count||0)+' / '+(s.rough_candidates||0)],['缓存过滤',s.cached_exclusion_count||0],['K线成功',pct(s.kline_h1_success_count,s.kline_attempt_count)+' / '+pct(s.kline_h4_success_count,s.kline_attempt_count)],['流程漏斗',(s.rough_candidates||0)+' / '+(s.fine_qualified||0)+' / '+(s.confirm_hits||0)+' / '+(s.recommendations||0)],['推荐转化',pct(s.recommendations,s.fine_qualified)],['复盘成功/失败',(s.perf_success||0)+' / '+(s.perf_failed||0)],['漏选',s.missed_count||0]].map(function(x){return '<div class="mini"><span>'+x[0]+'</span><b>'+x[1]+'</b></div>';}).join('');$('detailBody').innerHTML='<div class="timeline">'+timeline+'</div><div class="summary-grid">'+minis+'</div><div class="chips">'+chipHtml+'</div>'+renderRows();}
|
||||
function setFilter(f){state.filter=f;renderDetail();}
|
||||
function rowStage(item){if(item.kind==='screening')return item.funnel_stage||item.layer||'discovery';if(item.kind==='recommendation')return (item.performance_status==='success'||item.performance_status==='failed')?'tracking':'trade_confirm';if(item.kind==='review')return 'review';if(item.kind==='missed')return 'discovery';return 'all';}
|
||||
function rowStage(item){if(item.kind==='missed')return 'missed';if(item.kind==='screening')return item.funnel_stage||item.layer||'discovery';if(item.kind==='recommendation')return (item.performance_status==='success'||item.performance_status==='failed')?'tracking':'trade_confirm';if(item.kind==='review')return 'review';return 'all';}
|
||||
function collectRows(){var d=state.detail||{},rows=[];(d.screening_items||[]).forEach(function(x){rows.push({kind:'screening',layer:x.layer,funnel_stage:x.funnel_stage,time:x.scan_time,symbol:x.symbol,stage:x.candidate_stage_label||x.funnel_stage_label||x.stage_label,score:x.score,price:x.price,status:x.state,signals:x.signals||[],note:(x.detail_json&&x.detail_json.reason_label)||(x.detail_json&&x.detail_json.reason)||'',stage_code:x.candidate_stage});});(d.recommendations||[]).forEach(function(x){rows.push({kind:'recommendation',time:x.rec_time,symbol:x.symbol,stage:x.stage_label||'交易推荐',score:x.rec_score,price:x.entry_price,status:x.execution_label||x.action_status||x.status,signals:x.signal_labels&&x.signal_labels.length?x.signal_labels:(x.signals||[]),note:x.execution_reason||x.state_reason||'',performance_status:x.performance_status});});(d.reviews||[]).forEach(function(x){rows.push({kind:'review',time:x.review_time,symbol:x.symbol,stage:x.outcome==='爆发'?'复盘命中':(x.outcome==='失败'?'复盘失败':'复盘未验证'),score:'',price:x.pnl_48h,status:x.outcome,signals:x.hit_signals&&x.hit_signals.length?x.hit_signals:(x.triggered_signals||[]),note:x.lesson||''});});(d.missed_explosions||[]).forEach(function(x){rows.push({kind:'missed',time:x.detect_time,symbol:x.symbol,stage:'漏选',score:'',price:x.gain_pct,status:x.reason_missed||'漏选',signals:[],note:x.lesson||''});});rows.sort(function(a,b){return String(a.time||'').localeCompare(String(b.time||''));});return rows;}
|
||||
function renderRows(){var rows=collectRows().filter(function(r){return state.filter==='all'||rowStage(r)===state.filter||(state.filter==='review'&&r.kind==='review');});if(!rows.length)return '<div class="empty">当前阶段暂无明细</div>';return '<div class="table-wrap"><table class="table"><thead><tr><th>时间</th><th>阶段</th><th>币种</th><th>分数/收益</th><th>价格/涨幅</th><th>状态</th><th>信号与说明</th></tr></thead><tbody>'+rows.map(function(r){var cls=r.kind==='recommendation'?'rec':r.stage==='复盘命中'?'win':(r.stage==='复盘失败'||r.kind==='missed')?'fail':'';var parts=uniq((r.signals||[]).slice(0,5).concat([r.note]));var desc=parts.map(friendlyReason).join(' · ');return '<tr><td>'+fmtTime(r.time)+'</td><td>'+label(r.stage,cls)+'</td><td class="sym">'+esc(r.symbol||'--')+'</td><td class="num">'+esc(r.score===''?'--':r.score)+'</td><td class="num">'+esc(r.price==null?'--':r.price)+'</td><td>'+esc(r.status||'--')+'</td><td class="signals">'+esc(desc||'--')+'</td></tr>';}).join('')+'</tbody></table></div>';}
|
||||
loadRuns();
|
||||
|
||||
@ -328,13 +328,23 @@ def test_pipeline_page_nav_hides_watchlist_entry_and_watchlist_route_survives(te
|
||||
assert pipeline_resp.status_code == 200
|
||||
html = pipeline_resp.text
|
||||
assert "链路日志" in html
|
||||
assert 'href="/pipeline"' in html
|
||||
assert 'href="/watchlist"' not in html
|
||||
|
||||
watch_resp = client.get("/watchlist")
|
||||
assert watch_resp.status_code == 200
|
||||
|
||||
|
||||
def test_pipeline_page_filters_missed_rows_as_missed(temp_db):
|
||||
client = TestClient(web_server.app)
|
||||
|
||||
resp = client.get("/pipeline")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
|
||||
assert "if(item.kind==='missed')return 'missed'" in html
|
||||
assert "['missed','漏选'" in html
|
||||
|
||||
|
||||
def test_user_nav_keeps_review_center_but_hides_legacy_research_pages(temp_db):
|
||||
client = TestClient(web_server.app)
|
||||
resp = client.get("/app")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user