feat(ui): widen drawer and restructure overview tab layout

- Drawer width: 1000px → 1200px for more content space
- Overview tab: move user input to full-width bottom section
- Seeds JSON area: maxHeight 160px → 300px with better padding
- Unify font sizes: 13px body, 12px labels/tags throughout
- Fix progress calculation to use estimated_sessions consistently
This commit is contained in:
sinohqb 2026-08-20 18:08:03 +08:00
parent af8c7d6810
commit 63e96c2bf2
2 changed files with 121 additions and 117 deletions

View File

@ -19,18 +19,18 @@ function PlanView({ ev }: { ev: IntelligentEval }) {
if (!plan) return <Empty description="暂无粗计划" image={Empty.PRESENTED_IMAGE_SIMPLE} /> if (!plan) return <Empty description="暂无粗计划" image={Empty.PRESENTED_IMAGE_SIMPLE} />
return ( return (
<div> <div>
<Descriptions column={3} size="small" bordered style={{ marginBottom: 12 }}> <Descriptions column={3} size="small" bordered style={{ marginBottom: 12 }} labelStyle={{ fontSize: 12 }} contentStyle={{ fontSize: 13 }}>
<Descriptions.Item label="预估会话数">{plan.estimated_sessions}</Descriptions.Item> <Descriptions.Item label="预估会话数">{plan.estimated_sessions}</Descriptions.Item>
<Descriptions.Item label="单会话最大轮数">{plan.budget?.max_turns_per_session ?? '—'}</Descriptions.Item> <Descriptions.Item label="单会话最大轮数">{plan.budget?.max_turns_per_session ?? '—'}</Descriptions.Item>
<Descriptions.Item label="总轮数上限">{plan.budget?.total_max_turns ?? '—'}</Descriptions.Item> <Descriptions.Item label="总轮数上限">{plan.budget?.total_max_turns ?? '—'}</Descriptions.Item>
</Descriptions> </Descriptions>
<div style={{ fontWeight: 500, marginBottom: 6 }}></div> <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 6 }}></div>
<Space size={6} wrap style={{ marginBottom: 12 }}> <Space size={6} wrap style={{ marginBottom: 12 }}>
{(plan.dimensions ?? []).map((d) => <Tag key={d} color="blue">{d}</Tag>)} {(plan.dimensions ?? []).map((d) => <Tag key={d} color="blue" style={{ fontSize: 12 }}>{d}</Tag>)}
</Space> </Space>
<div style={{ fontWeight: 500, marginBottom: 6 }}></div> <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 6 }}></div>
<Space direction="vertical" size={4} style={{ width: '100%', marginBottom: 12 }}> <Space direction="vertical" size={4} style={{ width: '100%', marginBottom: 12 }}>
{(plan.virtual_users ?? []).map((u, i) => ( {(plan.virtual_users ?? []).map((u, i) => (
<div key={i} style={{ fontSize: 13, color: colors.textSecondary }}> <div key={i} style={{ fontSize: 13, color: colors.textSecondary }}>
@ -39,11 +39,11 @@ function PlanView({ ev }: { ev: IntelligentEval }) {
))} ))}
</Space> </Space>
<div style={{ fontWeight: 500, marginBottom: 6 }}></div> <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 6 }}></div>
<Space direction="vertical" size={4} style={{ width: '100%', marginBottom: 12 }}> <Space direction="vertical" size={4} style={{ width: '100%', marginBottom: 12 }}>
{(plan.time_distribution ?? []).map((t, i) => ( {(plan.time_distribution ?? []).map((t, i) => (
<div key={i} style={{ fontSize: 13, color: colors.textSecondary }}> <div key={i} style={{ fontSize: 13, color: colors.textSecondary }}>
<Tag style={{ margin: 0 }}>{t.time_slot}</Tag> {t.sessions} · {t.scenario} <Tag style={{ margin: 0, fontSize: 12 }}>{t.time_slot}</Tag> {t.sessions} · {t.scenario}
</div> </div>
))} ))}
</Space> </Space>
@ -72,25 +72,103 @@ export default function EvalOverview({ ev, targetName }: EvalOverviewProps) {
const sessions = showSessions ? ev.sessions ?? [] : [] const sessions = showSessions ? ev.sessions ?? [] : []
return ( return (
<Row gutter={16}> <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<Col span={9}> <Row gutter={16}>
<Card size="small" title="基本信息" style={sectionCard}> <Col span={8}>
<Descriptions column={1} size="small"> <Card size="small" title="基本信息" style={sectionCard}>
<Descriptions.Item label="评测对象">{targetName}</Descriptions.Item> <Descriptions column={1} size="small" labelStyle={{ fontSize: 12, color: colors.textSecondary }} contentStyle={{ fontSize: 13 }}>
<Descriptions.Item label="状态"> <Descriptions.Item label="评测对象">{targetName}</Descriptions.Item>
<Tag color={meta.color}>{meta.label}</Tag> <Descriptions.Item label="状态">
</Descriptions.Item> <Tag color={meta.color}>{meta.label}</Tag>
<Descriptions.Item label="时间窗口">{ev.time_window_hours} </Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="创建时间">{formatDateTime(ev.created_at)}</Descriptions.Item> <Descriptions.Item label="时间窗口">{ev.time_window_hours} </Descriptions.Item>
<Descriptions.Item label="开始时间">{formatDateTime(ev.started_at)}</Descriptions.Item> <Descriptions.Item label="创建时间">{formatDateTime(ev.created_at)}</Descriptions.Item>
<Descriptions.Item label="完成时间">{formatDateTime(ev.completed_at)}</Descriptions.Item> <Descriptions.Item label="开始时间">{formatDateTime(ev.started_at)}</Descriptions.Item>
<Descriptions.Item label="会话进度">{ev.completed_sessions}/{ev.session_count}</Descriptions.Item> <Descriptions.Item label="完成时间">{formatDateTime(ev.completed_at)}</Descriptions.Item>
</Descriptions> <Descriptions.Item label="会话进度">{ev.completed_sessions}/{ev.plan?.estimated_sessions ?? ev.session_count}</Descriptions.Item>
</Card> </Descriptions>
</Card>
</Col>
<Card size="small" title="用户输入" style={sectionCard}> <Col span={16}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}> {ev.status === 'planning' && (
<div> ev.plan_feedback ? (
<Alert
style={sectionCard}
type="warning"
showIcon
message="计划已打回OpenClaw 正在根据反馈重新规划"
description={ev.plan_feedback}
/>
) : (
<Card size="small" style={sectionCard}>
<Spin size="small" />
<span style={{ marginLeft: 10, fontSize: 13, color: colors.textSecondary }}>
OpenClaw
</span>
</Card>
)
)}
{(ev.status === 'pending_approval' || ev.status === 'executing' || ev.status === 'completed') && (
<Card size="small" title="粗计划" style={sectionCard}>
<PlanView ev={ev} />
</Card>
)}
{showSessions && (
<Card
size="small"
title={`会话进度(${ev.completed_sessions}/${ev.plan?.estimated_sessions ?? ev.session_count}`}
style={sectionCard}
extra={(
<Progress
percent={(ev.plan?.estimated_sessions ?? ev.session_count) ? Math.round((ev.completed_sessions / (ev.plan?.estimated_sessions ?? ev.session_count)) * 100) : 0}
size="small"
style={{ width: 140 }}
/>
)}
>
{sessions.length === 0 && (
<div style={{ fontSize: 13, color: colors.textSecondary }}>
OpenClaw
</div>
)}
{sessions.map((s) => {
const sMeta = SESSION_STATUS[s.status]
return (
<div
key={s.id}
style={{
display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap',
padding: '8px 0', borderBottom: `1px solid ${colors.border}`,
}}
>
<b style={{ fontSize: 13, color: colors.text }}>{personaLabel(s.persona)}</b>
<Tag color={sMeta.color} style={{ margin: 0, fontSize: 12 }}>{sMeta.label}</Tag>
{s.dimension && <Tag style={{ margin: 0, fontSize: 12 }}>{s.dimension}</Tag>}
<span style={{ fontSize: 13, color: colors.textSecondary, flex: 1, minWidth: 120 }}>{s.goal}</span>
<span style={{ fontSize: 12, color: colors.textMuted }}>{s.turn_count} </span>
{s.created_at && (
<span style={{ fontSize: 12, color: colors.textMuted }}>{shortDateTime(s.created_at)}</span>
)}
</div>
)
})}
{ev.status === 'executing' && (
<div style={{ fontSize: 12, color: colors.textMuted, marginTop: 8 }}>
OpenClaw 5
</div>
)}
</Card>
)}
</Col>
</Row>
<Card size="small" title="用户输入">
<Row gutter={16}>
<Col span={8}>
<div style={{ marginBottom: 12 }}>
<div style={{ fontSize: 12, color: colors.textSecondary, marginBottom: 4 }}></div> <div style={{ fontSize: 12, color: colors.textSecondary, marginBottom: 4 }}></div>
<div style={{ <div style={{
fontSize: 13, padding: '8px 12px', background: colors.bgSubtle, fontSize: 13, padding: '8px 12px', background: colors.bgSubtle,
@ -99,7 +177,7 @@ export default function EvalOverview({ ev, targetName }: EvalOverviewProps) {
{ev.goal || '—'} {ev.goal || '—'}
</div> </div>
</div> </div>
<div> <div style={{ marginBottom: 12 }}>
<div style={{ fontSize: 12, color: colors.textSecondary, marginBottom: 4 }}></div> <div style={{ fontSize: 12, color: colors.textSecondary, marginBottom: 4 }}></div>
<div style={{ <div style={{
fontSize: 13, padding: '8px 12px', background: colors.bgSubtle, fontSize: 13, padding: '8px 12px', background: colors.bgSubtle,
@ -117,97 +195,23 @@ export default function EvalOverview({ ev, targetName }: EvalOverviewProps) {
{ev.role_description || '—'} {ev.role_description || '—'}
</div> </div>
</div> </div>
<div> </Col>
<div style={{ fontSize: 12, color: colors.textSecondary, marginBottom: 4 }}></div> <Col span={16}>
{Object.keys(ev.seeds ?? {}).length === 0 ? ( <div style={{ fontSize: 12, color: colors.textSecondary, marginBottom: 4 }}></div>
<div style={{ fontSize: 13, padding: '8px 12px', background: colors.bgSubtle, borderRadius: 6 }}></div> {Object.keys(ev.seeds ?? {}).length === 0 ? (
) : ( <div style={{ fontSize: 13, padding: '8px 12px', background: colors.bgSubtle, borderRadius: 6 }}></div>
<pre style={{ ) : (
margin: 0, fontSize: 12, background: colors.bgSubtle, <pre style={{
padding: '8px 12px', borderRadius: 6, overflowX: 'auto', margin: 0, fontSize: 12, background: colors.bgSubtle,
maxHeight: 160, overflowY: 'auto', padding: '12px 16px', borderRadius: 6, overflowX: 'auto',
}}> maxHeight: 300, overflowY: 'auto', lineHeight: 1.6,
{JSON.stringify(ev.seeds, null, 2)} }}>
</pre> {JSON.stringify(ev.seeds, null, 2)}
)} </pre>
</div>
</div>
</Card>
</Col>
<Col span={15}>
{ev.status === 'planning' && (
ev.plan_feedback ? (
<Alert
style={sectionCard}
type="warning"
showIcon
message="计划已打回OpenClaw 正在根据反馈重新规划"
description={ev.plan_feedback}
/>
) : (
<Card size="small" style={sectionCard}>
<Spin size="small" />
<span style={{ marginLeft: 10, color: colors.textSecondary }}>
OpenClaw
</span>
</Card>
)
)}
{(ev.status === 'pending_approval' || ev.status === 'executing' || ev.status === 'completed') && (
<Card size="small" title="粗计划" style={sectionCard}>
<PlanView ev={ev} />
</Card>
)}
{showSessions && (
<Card
size="small"
title={`会话进度(${ev.completed_sessions}/${ev.session_count}`}
style={sectionCard}
extra={(
<Progress
percent={ev.session_count ? Math.round((ev.completed_sessions / ev.session_count) * 100) : 0}
size="small"
style={{ width: 140 }}
/>
)} )}
> </Col>
{sessions.length === 0 && ( </Row>
<div style={{ fontSize: 13, color: colors.textSecondary }}> </Card>
OpenClaw </div>
</div>
)}
{sessions.map((s) => {
const sMeta = SESSION_STATUS[s.status]
return (
<div
key={s.id}
style={{
display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap',
padding: '6px 0', borderBottom: `1px solid ${colors.border}`, fontSize: 13,
}}
>
<b style={{ color: colors.text }}>{personaLabel(s.persona)}</b>
<Tag color={sMeta.color} style={{ margin: 0 }}>{sMeta.label}</Tag>
{s.dimension && <Tag style={{ margin: 0 }}>{s.dimension}</Tag>}
<span style={{ color: colors.textSecondary, flex: 1, minWidth: 120 }}>{s.goal}</span>
<span style={{ color: colors.textMuted }}>{s.turn_count} </span>
{s.created_at && (
<span style={{ color: colors.textMuted }}>{shortDateTime(s.created_at)}</span>
)}
</div>
)
})}
{ev.status === 'executing' && (
<div style={{ fontSize: 12, color: colors.textMuted, marginTop: 8 }}>
OpenClaw 5
</div>
)}
</Card>
)}
</Col>
</Row>
) )
} }

View File

@ -274,7 +274,7 @@ export default function IntelligentEvalsPage() {
title={selected?.name ?? '评估详情'} title={selected?.name ?? '评估详情'}
open={selectedId != null} open={selectedId != null}
onClose={closeDrawer} onClose={closeDrawer}
width={1000} width={1200}
destroyOnClose destroyOnClose
styles={{ body: { padding: 0, display: 'flex', flexDirection: 'column' } }} styles={{ body: { padding: 0, display: 'flex', flexDirection: 'column' } }}
extra={selected && ( extra={selected && (