import { Alert, Card, Empty, Progress, Row, Col, Space, Spin, Table, Tag, } from 'antd' import type { IntelligentEval } from '../../api' import { colors } from '../../tokens' import { formatDateTime, shortDateTime } from '../../utils/date' import { EVAL_STATUS, SESSION_STATUS } from './status' function personaLabel(persona: Record): string { if (typeof persona.name === 'string' && persona.name) return persona.name if (typeof persona.background === 'string' && persona.background) return persona.background return JSON.stringify(persona) } function InfoRow({ items }: { items: [string, React.ReactNode][] }) { return (
{items.map(([k, v]) => (
{k} {v}
))}
) } function FieldBlock({ label, content }: { label: string; content: string }) { return (
{label}
{content || '—'}
) } function PlanView({ ev }: { ev: IntelligentEval }) { const plan = ev.plan if (!plan) return return (
{[ ['预估会话数', plan.estimated_sessions], ['单会话最大轮数', plan.budget?.max_turns_per_session ?? '—'], ['总轮数上限', plan.budget?.total_max_turns ?? '—'], ].map(([k, v]) => (
{k}
{v}
))}
评测维度
{(plan.dimensions ?? []).map((d) => {d})}
虚拟用户
{(plan.virtual_users ?? []).map((u, i) => (
{personaLabel(u.persona)} · {u.goal}
))}
时间分布
t.time_slot} dataSource={plan.time_distribution ?? []} pagination={false} style={{ marginBottom: 12 }} columns={[ { title: '时段', dataIndex: 'time_slot', width: 100, render: (v: string) => {v}, }, { title: '会话数', dataIndex: 'sessions', width: 70 }, { title: '场景说明', dataIndex: 'scenario', render: (v: string) => {v} }, ]} /> {plan.completion_criteria && (
完成标准:{plan.completion_criteria}
)} ) } interface EvalOverviewProps { ev: IntelligentEval targetName: string } /** * 评估详情"概览"子视图(纯展示,单列布局): * 基本信息 → 粗计划 → 用户输入(种子集独立列)→ 会话进度。 * 审批/取消等动作由评估列表页的详情抽屉头部统一管理。 */ export default function EvalOverview({ ev, targetName }: EvalOverviewProps) { const meta = EVAL_STATUS[ev.status] ?? { label: ev.status, color: 'default' } const showSessions = ev.status === 'executing' || ev.status === 'completed' const sessions = showSessions ? ev.sessions ?? [] : [] const estimated = ev.plan?.estimated_sessions ?? ev.session_count const hasSeeds = Object.keys(ev.seeds ?? {}).length > 0 return (
{/* 基本信息:两行横向描述,label 定宽右对齐 */} {meta.label}], ['时间窗口', `${ev.time_window_hours} 小时`], ['会话进度', `${ev.completed_sessions}/${estimated}`], ]} />
{/* 粗计划 */} {ev.status === 'planning' && ( ev.plan_feedback ? ( ) : ( OpenClaw 正在规划,产出粗计划后会自动进入待审批… ) )} {(ev.status === 'pending_approval' || ev.status === 'executing' || ev.status === 'completed') && ( )} {/* 用户输入:左列目标/意图/角色堆叠,右列种子集固定高度 */}
种子集
{hasSeeds ? (
                {JSON.stringify(ev.seeds, null, 2)}
              
) : (
)} {/* 会话进度(全宽) */} {showSessions && ( )} > {sessions.length === 0 && (
等待 OpenClaw 按粗计划的时间分布创建会话…
)} {sessions.map((s) => { const sMeta = SESSION_STATUS[s.status] return (
{personaLabel(s.persona)} {sMeta.label} {s.dimension && {s.dimension}} {s.goal} {s.turn_count} 轮 {s.created_at && ( {shortDateTime(s.created_at)} )}
) })} {ev.status === 'executing' && (
会话由 OpenClaw 按粗计划的时间分布自唤醒创建,本页每 5 秒自动刷新
)}
)} {/* 收尾标识:明确内容已到底,避免"看起来没显示完" */}
已显示全部内容
) }