## 新增功能模块 ### 1. 选课管理(elective) - 新增表:electiveCourses、courseSelections - 新增权限:ELECTIVE_MANAGE/ELECTIVE_READ/ELECTIVE_SELECT - 支持先到先得 + 抽签两种选课模式 - admin/teacher/student 三端页面 ### 2. 考试监考(proctoring) - exams 表扩展:examMode/durationMinutes/antiCheatEnabled 等字段 - 新增表:examProctoringEvents - 新增权限:EXAM_PROCTOR/EXAM_PROCTOR_READ - 教师监考面板 + 学生端防作弊监控 - API:/api/proctoring/event 接收事件上报 ### 3. 学情诊断报告(diagnostic) - 新增表:knowledgePointMastery、learningDiagnosticReports - 新增权限:DIAGNOSTIC_MANAGE/DIAGNOSTIC_READ - 基于提交答案自动计算知识点掌握度 - 生成个人/班级诊断报告(强项/弱项/建议) - 雷达图可视化 ## 其他改动 - 项目规则:单文件行数限制从 300 行调整为企业级规范(组件≤500/Actions≤800/硬上限1000) - scripts/seed.ts:消除全部 any 类型,定义内部类型,0 lint 错误 - 架构文档 004/005 同步更新三个新模块 - 迁移文件 0001_heavy_sage.sql 生成 ## 验证 - npx tsc --noEmit:0 错误 - npm run lint:0 错误 0 警告
49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
import { getAuthContext } from "@/shared/lib/auth-guard"
|
|
import { getDiagnosticReports } from "@/modules/diagnostic/data-access-reports"
|
|
import { ReportList } from "@/modules/diagnostic/components/report-list"
|
|
import type { DiagnosticReportType, DiagnosticReportStatus } from "@/modules/diagnostic/types"
|
|
|
|
export const dynamic = "force-dynamic"
|
|
|
|
type SearchParams = { [key: string]: string | string[] | undefined }
|
|
|
|
const getParam = (params: SearchParams, key: string) => {
|
|
const v = params[key]
|
|
return Array.isArray(v) ? v[0] : v
|
|
}
|
|
|
|
export default async function TeacherDiagnosticPage({
|
|
searchParams,
|
|
}: {
|
|
searchParams: Promise<SearchParams>
|
|
}) {
|
|
const sp = await searchParams
|
|
const ctx = await getAuthContext()
|
|
|
|
const reportType = getParam(sp, "reportType")
|
|
const status = getParam(sp, "status")
|
|
|
|
const reports = await getDiagnosticReports({
|
|
reportType: reportType && reportType !== "all" ? (reportType as DiagnosticReportType) : undefined,
|
|
status: status && status !== "all" ? (status as DiagnosticReportStatus) : undefined,
|
|
})
|
|
|
|
// 学生角色仅查看自己的报告;其他角色查看全部
|
|
const visibleReports =
|
|
ctx.dataScope.type === "class_members"
|
|
? reports.filter((r) => r.studentId === ctx.userId)
|
|
: reports
|
|
|
|
return (
|
|
<div className="h-full flex-1 flex-col space-y-8 p-8 md:flex">
|
|
<div>
|
|
<h2 className="text-2xl font-bold tracking-tight">Learning Diagnostic</h2>
|
|
<p className="text-muted-foreground">
|
|
View and manage diagnostic reports based on knowledge point mastery.
|
|
</p>
|
|
</div>
|
|
<ReportList reports={visibleReports} />
|
|
</div>
|
|
)
|
|
}
|