feat(student): 完成 student 模块 v4 剩余修复

- P1-4.2: 新增班级详情页 courses/[classId],展示教师/学校/教室信息与课表

- P2-2.5: 今日课表卡片高亮当前/下一节课(useMemo 实时计算)

- P2-3.9: 作业作答进度网格支持点击跳转题目(scrollIntoView)

- P2-3.10: 作业复习视图显示正确答案(选择/判断/文本题)

- P2-4.4: 课程列表支持按班级名/教师/学校搜索

- P2-5.2: 成绩页新增趋势折线图组件 GradeTrendCard

- P2-9.2/9.3: 诊断报告新增历史记录卡片与弱点练习入口

- P2-10.2: 选课列表支持搜索与选课模式筛选

- P2-11.3: 修复教材阅读页全屏溢出

- P3-1.5: 面包屑保留首个角色段作为根上下文

- P3-7.3: 课表项支持点击跳转至班级详情页(ScheduleList href)
This commit is contained in:
SpecialX
2026-06-22 14:08:34 +08:00
parent c90748124d
commit 30f4983d49
18 changed files with 912 additions and 137 deletions

View File

@@ -0,0 +1,57 @@
"use client"
import { useMemo } from "react"
import { BarChart3 } from "lucide-react"
import { ChartCardShell } from "@/shared/components/charts/chart-card-shell"
import { TrendLineChart } from "@/shared/components/charts/trend-line-chart"
import { formatDate } from "@/shared/lib/utils"
import type { StudentGradeSummary } from "../types"
export function GradeTrendCard({ summary }: { summary: StudentGradeSummary }) {
const chartData = useMemo(() => {
return [...summary.records]
.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())
.map((r) => ({
title: r.title,
score: Math.round((r.score / r.fullScore) * 100),
fullTitle: r.title,
submittedAt: formatDate(r.createdAt),
rawScore: r.score,
maxScore: r.fullScore,
}))
}, [summary.records])
const hasData = chartData.length > 0
return (
<ChartCardShell
title="Grade Trend"
icon={BarChart3}
iconClassName="text-muted-foreground"
isEmpty={!hasData}
emptyTitle="No grade records yet"
emptyDescription="Your grade trend will appear here once records are added."
emptyClassName="h-64"
>
<div className="rounded-md border bg-card p-4">
<TrendLineChart
data={chartData}
series={[
{
dataKey: "score",
name: "Score (%)",
color: "hsl(var(--primary))",
dotRadius: 4,
activeDotRadius: 6,
},
]}
heightClassName="h-[240px]"
margin={{ left: 12, right: 12, top: 12, bottom: 12 }}
yWidth={30}
tooltipClassName="w-[200px]"
/>
</div>
</ChartCardShell>
)
}