import { getTranslations } from "next-intl/server" import { requirePermission } from "@/shared/lib/auth-guard" import { Permissions } from "@/shared/types/permissions" import { getStudentGradeSummary } from "@/modules/grades/data-access" import { getRankingTrend, getClassAverageTrend } from "@/modules/grades/data-access-ranking" import { getStudentPositionInClassDistribution, getStudentGrowthArchive } from "@/modules/grades/data-access-analytics" import { getSubjectOptions } from "@/modules/school/data-access" import { StudentGradeSummary } from "@/modules/grades/components/student-grade-summary" import { GradeFilters } from "@/modules/grades/components/grade-filters" import { GradeTrendCard } from "@/modules/grades/components/grade-trend-card" import { RankingTrendCard } from "@/modules/grades/components/ranking-trend-card" import { GradeDistributionChart } from "@/modules/grades/components/grade-distribution-chart" import { GrowthArchiveChart } from "@/modules/grades/components/growth-archive-chart" import { EmptyState } from "@/shared/components/ui/empty-state" import { UserX } from "lucide-react" import { getParam, type SearchParams } from "@/shared/lib/search-params" export const dynamic = "force-dynamic" export default async function StudentGradesPage({ searchParams, }: { searchParams: Promise }) { const ctx = await requirePermission(Permissions.GRADE_RECORD_READ) const t = await getTranslations("grades") const [sp, summary, rankingTrend, classAverageTrend, subjectOptions, classDistribution, growthArchive] = await Promise.all([ searchParams, getStudentGradeSummary(ctx.userId, ctx.dataScope), // v3-P1-3:接入排名趋势图 getRankingTrend(ctx.userId, undefined, undefined, ctx.dataScope), // v3-P2-2:接入班级平均趋势对比线 getClassAverageTrend(ctx.userId, undefined, undefined, ctx.dataScope), // v3-P2-1:获取科目列表用于过滤器 getSubjectOptions(), // P3-9:获取学生所在班级的分布 + 本人位置标注 getStudentPositionInClassDistribution(ctx.userId, ctx.dataScope), // P3-4:获取学生纵向成长档案(跨学年/学期聚合) getStudentGrowthArchive(ctx.userId, ctx.dataScope), ]) if (!summary) { return (

{t("title.myGrades")}

{t("summary.noDataDescription")}

) } // 应用筛选 const q = (getParam(sp, "q") || "").toLowerCase().trim() const subjectFilter = getParam(sp, "subject") || "all" const typeFilter = getParam(sp, "type") || "all" const semesterFilter = getParam(sp, "semester") || "all" const filteredRecords = summary.records.filter((r) => { if (q && !r.title.toLowerCase().includes(q)) return false // v3-P2-1 修复:按 subjectId 而非 subjectName 过滤 if (subjectFilter !== "all" && r.subjectId !== subjectFilter) return false if (typeFilter !== "all" && r.type !== typeFilter) return false if (semesterFilter !== "all" && r.semester !== semesterFilter) return false return true }) const filteredSummary = { ...summary, records: filteredRecords, } return (

{summary.studentName}

{t("summary.recordCount", { count: summary.records.length })}

({ id: s.id, name: s.name }))} /> {filteredSummary.records.length > 0 && (
)} {/* P3-9:班级分布 + 学生位置标注(隐私保护视图) */} {classDistribution && ( )} {/* P3-4:学生纵向成长档案(跨学年/学期聚合) */}
) }