From b4df6e5e18d2cd41d9be045f63710e7265f52e41 Mon Sep 17 00:00:00 2001 From: dekun Date: Sun, 28 Jun 2026 17:17:15 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=B7=B2=E5=BA=9F=E5=BC=83?= =?UTF-8?q?=E7=9A=84=20ReviewTreeChart=20=E7=BB=84=E4=BB=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- frontend/src/components/ReviewTreeChart.tsx | 122 -------------------- 1 file changed, 122 deletions(-) delete mode 100644 frontend/src/components/ReviewTreeChart.tsx diff --git a/frontend/src/components/ReviewTreeChart.tsx b/frontend/src/components/ReviewTreeChart.tsx deleted file mode 100644 index 5249971..0000000 --- a/frontend/src/components/ReviewTreeChart.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import ReactECharts from 'echarts-for-react' -import type { Exam, ReviewStatus } from '../types' -import { REVIEW_STATUS_LABELS } from '../types' - -interface Props { - exams: Exam[] -} - -const STATUS_ORDER: ReviewStatus[] = ['careless', 'unknown', 'nervous', 'normal'] - -const STATUS_COLORS: Record = { - careless: '#fa8c16', - unknown: '#ff4d4f', - nervous: '#722ed1', - normal: '#52c41a', -} - -function buildTreeData(exams: Exam[]) { - const byStatus: Record> = { - careless: {}, - unknown: {}, - nervous: {}, - normal: {}, - } - - for (const exam of exams) { - for (const score of exam.scores) { - const subjectName = score.subject_name || `科目${score.subject_id}` - for (const status of score.review_statuses || []) { - byStatus[status][subjectName] = (byStatus[status][subjectName] || 0) + 1 - } - } - } - - const children = STATUS_ORDER.map((status) => { - const subjectMap = byStatus[status] - const subjectChildren = Object.entries(subjectMap).map(([name, value]) => ({ - name: `${name} (${value})`, - value, - itemStyle: { color: STATUS_COLORS[status] }, - })) - const total = subjectChildren.reduce((sum, item) => sum + item.value, 0) - if (total === 0) return null - return { - name: `${REVIEW_STATUS_LABELS[status]} (${total})`, - value: total, - itemStyle: { color: STATUS_COLORS[status] }, - children: subjectChildren, - } - }).filter(Boolean) - - return { name: '复盘统计', children: children.length ? children : [{ name: '暂无数据', value: 0 }] } -} - -export default function ReviewTreeChart({ exams }: Props) { - const treeData = buildTreeData(exams) - const hasData = STATUS_ORDER.some((status) => - exams.some((exam) => - exam.scores.some((score) => (score.review_statuses || []).includes(status)), - ), - ) - - if (!hasData) { - return ( -
- 暂无复盘数据,请在录入成绩或下方复盘中填写考试状态 -
- ) - } - - const option = { - tooltip: { - trigger: 'item', - formatter: (params: { name: string; value?: number }) => { - if (params.value != null && params.value > 0) { - return `${params.name}
次数: ${params.value}` - } - return params.name - }, - }, - series: [ - { - type: 'tree', - data: [treeData], - top: 20, - left: 40, - bottom: 20, - right: 120, - symbolSize: 10, - orient: 'LR', - label: { - position: 'left', - verticalAlign: 'middle', - align: 'right', - fontSize: 13, - }, - leaves: { - label: { - position: 'right', - verticalAlign: 'middle', - align: 'left', - }, - }, - emphasis: { - focus: 'descendant', - }, - expandAndCollapse: true, - animationDuration: 400, - animationDurationUpdate: 400, - }, - ], - } - - return ( -
- -

- 树状图按「状态 → 科目」统计次数;同一科可多选状态,分别计数 -

-
- ) -}