diff --git a/frontend/web/src/components/intelligent_eval/EvalReport.tsx b/frontend/web/src/components/intelligent_eval/EvalReport.tsx index 3096f34..a089844 100644 --- a/frontend/web/src/components/intelligent_eval/EvalReport.tsx +++ b/frontend/web/src/components/intelligent_eval/EvalReport.tsx @@ -1,8 +1,11 @@ import { useEffect, useState } from 'react' import { - Button, Card, Col, Collapse, Empty, Row, Space, Spin, Statistic, Tag, message, + Button, Card, Col, Collapse, Empty, Row, Space, Spin, Tag, message, } from 'antd' -import { ArrowLeftOutlined, DownloadOutlined } from '@ant-design/icons' +import { + ArrowLeftOutlined, BulbOutlined, DownloadOutlined, MessageOutlined, + StarOutlined, WarningOutlined, +} from '@ant-design/icons' import { Bar } from '@ant-design/charts' import ChatBubble from '../ChatBubble' import { @@ -125,16 +128,28 @@ export default function EvalReport({ ev, onBack }: EvalReportProps) { const findings = [...(report?.findings ?? [])] .sort((a, b) => 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 + // report.scores 是嵌套结构:{ overall: number, dimensions: { 维度: 分 } } + // 只把 dimensions 的值当作数字维度,overall 单独取,避免 Number(对象) 产生 NaN。 + const rawScores = report?.scores ?? {} + const dimScores = Object.entries(rawScores.dimensions ?? {}).filter( + ([, v]) => typeof v === 'number', + ) + const rawOverall = rawScores.overall + const overall = typeof rawOverall === 'number' + ? rawOverall.toFixed(1) + : dimScores.length > 0 + ? (dimScores.reduce((sum, [, v]) => sum + Number(v), 0) / dimScores.length).toFixed(1) + : null + const overallNum = overall != null ? Number(overall) : null + const overallColor = overallNum == null ? colors.textMuted + : overallNum >= 0.8 ? '#52c41a' + : overallNum >= 0.6 ? colors.warning : '#ff4d4f' 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 scoreData = dimScores.map(([dimension, score]) => ({ dimension, score: Number(score) })) const scoreConfig = { data: scoreData, xField: 'dimension', @@ -144,6 +159,19 @@ export default function EvalReport({ ev, onBack }: EvalReportProps) { color: colors.primary, } + const summaryCard: React.CSSProperties = { + display: 'flex', alignItems: 'center', gap: 10, + border: `1px solid ${colors.border}`, + borderRadius: 10, padding: '14px 16px', background: colors.bgContainer, + boxShadow: '0 1px 3px rgba(0,0,0,0.06)', + height: '100%', + } + const summaryIcon = (color: string): React.CSSProperties => ({ + width: 42, height: 42, borderRadius: 10, flexShrink: 0, + display: 'flex', alignItems: 'center', justifyContent: 'center', + background: `${color}1a`, color, fontSize: 20, + }) + return (
@@ -167,23 +195,53 @@ export default function EvalReport({ ev, onBack }: EvalReportProps) { {report && ( <> - - - - - - - -
- 高 {sevCounts.high ?? 0} · 中 {sevCounts.medium ?? 0} · 低 {sevCounts.low ?? 0} + + +
+
+
+
综合评分
+
+ {overall ?? '—'} +
- +
- - + +
+
+
+
问题发现
+
+ {findings.length} +
+
+ 高 {sevCounts.high ?? 0} · 中 {sevCounts.medium ?? 0} · 低 {sevCounts.low ?? 0} +
+
+
- - + +
+
+
+
亮点
+
+ {report.highlights.length} +
+
+
+ + +
+
+
+
会话数
+
+ {ev.session_count} +
+
+