diff --git a/frontend/web/src/components/intelligent_eval/EvalDetail.tsx b/frontend/web/src/components/intelligent_eval/EvalDetail.tsx index 12811d9..a649d5e 100644 --- a/frontend/web/src/components/intelligent_eval/EvalDetail.tsx +++ b/frontend/web/src/components/intelligent_eval/EvalDetail.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useState } from 'react' import { - Alert, Button, Card, Descriptions, Empty, Input, Modal, Popconfirm, Space, Spin, Tag, message, + Alert, Button, Card, Col, Descriptions, Empty, Input, Modal, Popconfirm, Progress, Row, Space, Spin, Tag, message, } from 'antd' import { FileTextOutlined, StopOutlined } from '@ant-design/icons' import { intelligentEvalsApi, type IntelligentEval, type IntelligentEvalSession } from '../../api' @@ -125,111 +125,128 @@ export default function EvalDetail({ ev, targetName, onOpenReport, onChanged }: - - - {targetName} - {ev.time_window_hours} 小时 - {formatDateTime(ev.created_at)} - {formatDateTime(ev.started_at)} - {formatDateTime(ev.completed_at)} - {ev.completed_sessions}/{ev.session_count} - - - - - - {ev.goal || '—'} - {ev.intent || '—'} - - {ev.role_description || '—'} - - - {Object.keys(ev.seeds ?? {}).length === 0 - ? '—' - : ( - - {JSON.stringify(ev.seeds, null, 2)} - - )} - - - - - {ev.status === 'planning' && ( - ev.plan_feedback ? ( - - ) : ( - - - - OpenClaw 正在规划,产出粗计划后会自动进入待审批… - + + + + + {targetName} + {ev.time_window_hours} 小时 + {formatDateTime(ev.created_at)} + {formatDateTime(ev.started_at)} + {formatDateTime(ev.completed_at)} + {ev.completed_sessions}/{ev.session_count} + - ) - )} - {(ev.status === 'pending_approval' || ev.status === 'executing' || ev.status === 'completed') && ( - - setRejectOpen(true)}>打回 - 批准并执行 - - )} - > - - - )} + + + {ev.goal || '—'} + {ev.intent || '—'} + + {ev.role_description || '—'} + + + {Object.keys(ev.seeds ?? {}).length === 0 + ? '—' + : ( + + {JSON.stringify(ev.seeds, null, 2)} + + )} + + + + - {showSessions && ( - - {sessions === null && } - {sessions !== null && 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 === 'planning' && ( + ev.plan_feedback ? ( + + ) : ( + + + + OpenClaw 正在规划,产出粗计划后会自动进入待审批… + + ) - })} - {ev.status === 'executing' && ( - - 会话由 OpenClaw 按粗计划的时间分布自唤醒创建,本页每 5 秒自动刷新 - )} - - )} + + {(ev.status === 'pending_approval' || ev.status === 'executing' || ev.status === 'completed') && ( + + setRejectOpen(true)}>打回 + 批准并执行 + + )} + > + + + )} + + {showSessions && ( + + )} + > + {sessions === null && } + {sessions !== null && 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 秒自动刷新 + + )} + + )} + + severityOf(a.severity).order - severityOf(b.severity).order) const scores = Object.entries(report?.scores ?? {}) + const overall = scores.length > 0 + ? (scores.reduce((sum, [, v]) => sum + Number(v), 0) / scores.length).toFixed(1) + : null + const sevCounts = findings.reduce((acc, f) => { + acc[f.severity] = (acc[f.severity] ?? 0) + 1 + return acc + }, {} as Record) + + const scoreData = scores.map(([dimension, score]) => ({ dimension, score: Number(score) })) + const scoreConfig = { + data: scoreData, + xField: 'dimension', + yField: 'score', + coordinate: { transform: [{ type: 'transpose' }] }, + height: Math.max(160, scoreData.length * 44), + color: colors.primary, + } return ( @@ -167,17 +185,36 @@ export default function EvalReport({ ev, onBack }: EvalReportProps) { {report && ( <> + + + + + + + + + 高 {sevCounts.high ?? 0} · 中 {sevCounts.medium ?? 0} · 低 {sevCounts.low ?? 0} + + + + + + + + + + + + {scoreData.length > 0 && ( + + + + )} + {report.summary} - {scores.length > 0 && ( - - {scores.map(([dimension, score]) => ( - - ))} - - )}
- {JSON.stringify(ev.seeds, null, 2)} -
+ {JSON.stringify(ev.seeds, null, 2)} +