feat(frontend): surface scenario version across dropdowns and views
Some checks failed
CI / test (push) Failing after 43s

场景启动下拉、报告页运行下拉(A/B)、场景筛选(版本范围 v1/v2)、
仪表盘最近评测行、场景预览与编辑弹窗标题统一带上考纲版本标识。
This commit is contained in:
sinohqb 2026-07-29 14:20:09 +08:00
parent 770d260750
commit 8e3cf82fcc
4 changed files with 27 additions and 9 deletions

View File

@ -216,6 +216,11 @@ function RecentRunRow({ run, onOpen }: { run: Run; onOpen: () => void }) {
<span style={{ fontWeight: 500 }}>{run.scenario_name || run.scenario_id.slice(0, 8)}</span>
<span style={{ color: colors.textMuted }}> · {run.target_name || run.target_id.slice(0, 8)}</span>
</div>
{run.scenario_version != null && (
<Tag style={{ margin: 0, fontSize: 10, lineHeight: '16px', padding: '0 4px' }}>
v{run.scenario_version}
</Tag>
)}
{trigger !== 'manual' && (
<Tag color={triggerColors[trigger] ?? 'default'} style={{ margin: 0, fontSize: 10, lineHeight: '16px', padding: '0 4px' }}>
{triggerLabels[trigger] ?? trigger}

View File

@ -159,15 +159,26 @@ export default function ReportsPage() {
clearSelection()
}
// 场景筛选项:从 run 列表聚合(含各场景 run 数量
// 场景筛选项:从 run 列表聚合(含各场景 run 数量与出现过的考纲版本
const scenarioOptions = useMemo(() => {
const map = new Map<string, { name: string; count: number }>()
const map = new Map<string, { name: string; count: number; versions: Set<number> }>()
for (const r of runs) {
const entry = map.get(r.scenario_id)
if (entry) entry.count += 1
else map.set(r.scenario_id, { name: r.scenario_name || r.scenario_id.slice(0, 8), count: 1 })
if (entry) {
entry.count += 1
entry.versions.add(r.scenario_version ?? 1)
} else {
map.set(r.scenario_id, {
name: r.scenario_name || r.scenario_id.slice(0, 8),
count: 1,
versions: new Set([r.scenario_version ?? 1]),
})
}
return [...map.entries()].map(([id, s]) => ({ value: id, label: `${s.name}${s.count}` }))
}
return [...map.entries()].map(([id, s]) => {
const versions = [...s.versions].sort((a, b) => a - b).map((v) => `v${v}`).join('/')
return { value: id, label: `${s.name}${s.count} · ${versions}` }
})
}, [runs])
const filteredRuns = useMemo(
@ -179,15 +190,17 @@ export default function ReportsPage() {
const passRate = (r.summary as Record<string, unknown>)?.pass_rate as number | undefined
const pct = passRate != null ? `${Math.round(passRate * 100)}%` : '-'
const scenario = r.scenario_name || r.scenario_id.slice(0, 8)
const version = `v${r.scenario_version ?? 1}`
const target = r.target_name || r.target_id.slice(0, 8)
const time = r.started_at ? formatDateTime(r.started_at) : ''
const trigger = r.triggered_by ?? 'manual'
return {
value: r.id,
searchText: `${scenario} ${target} ${time} ${r.id} ${triggerLabels[trigger] ?? trigger}`.toLowerCase(),
searchText: `${scenario} ${version} ${target} ${time} ${r.id} ${triggerLabels[trigger] ?? trigger}`.toLowerCase(),
label: (
<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
<span style={{ fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis' }}>{scenario}</span>
<Tag color="geekblue" style={{ marginRight: 0, fontSize: 10, lineHeight: '16px', padding: '0 4px' }}>{version}</Tag>
<span style={{ color: colors.textMuted }}>· {target}</span>
<span style={{ color: colors.textMuted, fontSize: 12 }}>{time}</span>
<span style={{

View File

@ -163,7 +163,7 @@ export default function RunsPage() {
filterOption={(input, opt) =>
(opt?.label as string ?? '').toLowerCase().includes(input.toLowerCase())}
placeholder="选择评测场景"
options={scenarios.map((s) => ({ label: s.name, value: s.id }))}
options={scenarios.map((s) => ({ label: `${s.name}v${s.version ?? 1}`, value: s.id }))}
style={{ flex: 1 }}
size="middle"
/>

View File

@ -248,7 +248,7 @@ export default function ScenariosPage() {
</div>
<Drawer
title={editingScenario ? '编辑评测场景' : '新增评测场景'}
title={editingScenario ? `编辑评测场景(当前 v${editingScenario.version ?? 1}` : '新增评测场景'}
open={drawerOpen}
onClose={() => setDrawerOpen(false)}
width={720}
@ -329,7 +329,7 @@ export default function ScenariosPage() {
</Drawer>
<Modal
title={`场景预览: ${previewData?.name || ''}`}
title={`场景预览: ${previewData?.name || ''}${previewData?.version != null ? `v${previewData.version}` : ''}`}
open={previewOpen}
onCancel={() => setPreviewOpen(false)}
footer={null}