feat(P2): 实现选课管理、考试监考、学情诊断三大功能模块
## 新增功能模块 ### 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 警告
This commit is contained in:
148
src/modules/diagnostic/actions.ts
Normal file
148
src/modules/diagnostic/actions.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
import { requirePermission, PermissionDeniedError } from "@/shared/lib/auth-guard"
|
||||
import { Permissions } from "@/shared/types/permissions"
|
||||
import type { ActionState } from "@/shared/types/action-state"
|
||||
|
||||
import {
|
||||
generateDiagnosticReport,
|
||||
generateClassDiagnosticReport,
|
||||
getDiagnosticReports,
|
||||
getDiagnosticReportById,
|
||||
publishDiagnosticReport,
|
||||
deleteDiagnosticReport,
|
||||
} from "./data-access-reports"
|
||||
import type { DiagnosticReportQueryParams } from "./types"
|
||||
|
||||
/** 生成学生个人诊断报告 */
|
||||
export async function generateStudentReportAction(
|
||||
prevState: ActionState<string> | null,
|
||||
formData: FormData
|
||||
): Promise<ActionState<string>> {
|
||||
try {
|
||||
const ctx = await requirePermission(Permissions.DIAGNOSTIC_MANAGE)
|
||||
|
||||
const studentId = formData.get("studentId")
|
||||
const period = formData.get("period")
|
||||
if (typeof studentId !== "string" || studentId.length === 0) {
|
||||
return { success: false, message: "Missing studentId" }
|
||||
}
|
||||
if (typeof period !== "string" || period.length === 0) {
|
||||
return { success: false, message: "Missing period" }
|
||||
}
|
||||
|
||||
const id = await generateDiagnosticReport(studentId, period, ctx.userId)
|
||||
revalidatePath("/teacher/diagnostic")
|
||||
revalidatePath(`/teacher/diagnostic/student/${studentId}`)
|
||||
return { success: true, message: "Diagnostic report generated", data: id }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
if (e instanceof Error) return { success: false, message: e.message }
|
||||
return { success: false, message: "Unexpected error" }
|
||||
}
|
||||
}
|
||||
|
||||
/** 生成班级诊断报告 */
|
||||
export async function generateClassReportAction(
|
||||
prevState: ActionState<string> | null,
|
||||
formData: FormData
|
||||
): Promise<ActionState<string>> {
|
||||
try {
|
||||
const ctx = await requirePermission(Permissions.DIAGNOSTIC_MANAGE)
|
||||
|
||||
const classId = formData.get("classId")
|
||||
const period = formData.get("period")
|
||||
if (typeof classId !== "string" || classId.length === 0) {
|
||||
return { success: false, message: "Missing classId" }
|
||||
}
|
||||
if (typeof period !== "string" || period.length === 0) {
|
||||
return { success: false, message: "Missing period" }
|
||||
}
|
||||
|
||||
const id = await generateClassDiagnosticReport(classId, period, ctx.userId)
|
||||
revalidatePath("/teacher/diagnostic")
|
||||
revalidatePath(`/teacher/diagnostic/class/${classId}`)
|
||||
return { success: true, message: "Class diagnostic report generated", data: id }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
if (e instanceof Error) return { success: false, message: e.message }
|
||||
return { success: false, message: "Unexpected error" }
|
||||
}
|
||||
}
|
||||
|
||||
/** 发布诊断报告 */
|
||||
export async function publishReportAction(
|
||||
prevState: ActionState<string> | null,
|
||||
formData: FormData
|
||||
): Promise<ActionState<string>> {
|
||||
try {
|
||||
await requirePermission(Permissions.DIAGNOSTIC_MANAGE)
|
||||
|
||||
const id = formData.get("id")
|
||||
if (typeof id !== "string" || id.length === 0) {
|
||||
return { success: false, message: "Missing report id" }
|
||||
}
|
||||
|
||||
await publishDiagnosticReport(id)
|
||||
revalidatePath("/teacher/diagnostic")
|
||||
return { success: true, message: "Report published" }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
if (e instanceof Error) return { success: false, message: e.message }
|
||||
return { success: false, message: "Unexpected error" }
|
||||
}
|
||||
}
|
||||
|
||||
/** 删除诊断报告 */
|
||||
export async function deleteReportAction(
|
||||
prevState: ActionState<string> | null,
|
||||
formData: FormData
|
||||
): Promise<ActionState<string>> {
|
||||
try {
|
||||
await requirePermission(Permissions.DIAGNOSTIC_MANAGE)
|
||||
|
||||
const id = formData.get("id")
|
||||
if (typeof id !== "string" || id.length === 0) {
|
||||
return { success: false, message: "Missing report id" }
|
||||
}
|
||||
|
||||
await deleteDiagnosticReport(id)
|
||||
revalidatePath("/teacher/diagnostic")
|
||||
return { success: true, message: "Report deleted" }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
if (e instanceof Error) return { success: false, message: e.message }
|
||||
return { success: false, message: "Unexpected error" }
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询诊断报告列表(读权限) */
|
||||
export async function getDiagnosticReportsAction(
|
||||
params: DiagnosticReportQueryParams
|
||||
): Promise<ActionState<Awaited<ReturnType<typeof getDiagnosticReports>>>> {
|
||||
try {
|
||||
await requirePermission(Permissions.DIAGNOSTIC_READ)
|
||||
const reports = await getDiagnosticReports(params)
|
||||
return { success: true, data: reports }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
if (e instanceof Error) return { success: false, message: e.message }
|
||||
return { success: false, message: "Unexpected error" }
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取诊断报告详情(读权限) */
|
||||
export async function getDiagnosticReportByIdAction(
|
||||
id: string
|
||||
): Promise<ActionState<Awaited<ReturnType<typeof getDiagnosticReportById>>>> {
|
||||
try {
|
||||
await requirePermission(Permissions.DIAGNOSTIC_READ)
|
||||
const report = await getDiagnosticReportById(id)
|
||||
return { success: true, data: report }
|
||||
} catch (e) {
|
||||
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
|
||||
if (e instanceof Error) return { success: false, message: e.message }
|
||||
return { success: false, message: "Unexpected error" }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user