Files
NextEdu/src/modules/classes/actions-admin.ts
SpecialX 15aa84b72c refactor(school,classes): 完成 school/grade/class 审计全量改进项
P0-1/P0-2: 删除 grade-management 死模块,年级 CRUD 统一由 school 模块负责

P0-3: classes/actions.ts 从 974 行拆分为 6 个职责文件 + barrel re-export

P0-5: 13 个页面 i18n 全量接入(grades/departments/academic-year/classes/insights)

P1-1: 角色硬编码改为 hasAdminScope/hasTeacherScope/hasStudentScope 基于 dataScope.type

P1-3: 新增 SchoolErrorBoundary + SchoolListSkeleton/SchoolCardSkeleton,4 个页面包裹 Error Boundary

P1-4: classes/types.ts 跨领域类型添加归属决策注释

P1-5: schools-view.tsx 拆分为组合模式(SchoolFormDialog + SchoolDeleteDialog + SchoolListToolbar)

P1-6: 新增 getSchoolsForUser/getGradesForUser 权限感知查询函数

P2-1: 抽取 useSchoolData hook,对话框状态管理与 UI 分离

同步更新架构图文档 004/005
2026-06-22 18:54:01 +08:00

152 lines
4.9 KiB
TypeScript

"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 {
createAdminClass,
deleteAdminClass,
setClassSubjectTeachers,
updateAdminClass,
} from "./data-access"
import {
CreateAdminClassSchema,
UpdateAdminClassSchema,
DeleteAdminClassSchema,
} from "./schema"
import { parseSubjectTeachers } from "./actions-shared"
export async function createAdminClassAction(
prevState: ActionState<string> | undefined,
formData: FormData
): Promise<ActionState<string>> {
try {
await requirePermission(Permissions.CLASS_CREATE)
const parsed = CreateAdminClassSchema.safeParse({
name: formData.get("name"),
grade: formData.get("grade"),
teacherId: formData.get("teacherId"),
schoolName: formData.get("schoolName"),
schoolId: formData.get("schoolId"),
gradeId: formData.get("gradeId"),
homeroom: formData.get("homeroom"),
room: formData.get("room"),
})
if (!parsed.success) {
return { success: false, message: "Class name, grade and teacher are required" }
}
const { name, grade, teacherId, schoolName, schoolId, gradeId, homeroom, room } = parsed.data
try {
const id = await createAdminClass({
schoolName: schoolName ?? null,
schoolId: schoolId ?? null,
name,
grade,
gradeId: gradeId ?? null,
teacherId,
homeroom: homeroom ?? null,
room: room ?? null,
})
revalidatePath("/admin/school/classes")
revalidatePath("/teacher/classes/my")
revalidatePath("/teacher/classes/students")
revalidatePath("/teacher/classes/schedule")
return { success: true, message: "Class created successfully", data: id }
} catch (error) {
return { success: false, message: error instanceof Error ? error.message : "Failed to create class" }
}
} catch (e) {
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
throw e
}
}
export async function updateAdminClassAction(
classId: string,
prevState: ActionState | undefined,
formData: FormData
): Promise<ActionState> {
try {
await requirePermission(Permissions.CLASS_UPDATE)
const parsed = UpdateAdminClassSchema.safeParse({
classId,
schoolName: formData.get("schoolName"),
schoolId: formData.get("schoolId"),
name: formData.get("name"),
grade: formData.get("grade"),
gradeId: formData.get("gradeId"),
teacherId: formData.get("teacherId"),
homeroom: formData.get("homeroom"),
room: formData.get("room"),
})
if (!parsed.success) {
return { success: false, message: "Missing class id" }
}
const { classId: validatedClassId, schoolName, schoolId, name, grade, gradeId, teacherId, homeroom, room } = parsed.data
const subjectTeachers = parseSubjectTeachers(formData.get("subjectTeachers") as string | null)
try {
await updateAdminClass(validatedClassId, {
schoolName: schoolName ?? undefined,
schoolId: schoolId ?? undefined,
name: name ?? undefined,
grade: grade ?? undefined,
gradeId: gradeId ?? undefined,
teacherId: teacherId ?? undefined,
homeroom: homeroom ?? undefined,
room: room ?? undefined,
})
if (subjectTeachers) {
await setClassSubjectTeachers({
classId: validatedClassId,
assignments: subjectTeachers,
})
}
revalidatePath("/admin/school/classes")
revalidatePath("/teacher/classes/my")
revalidatePath("/teacher/classes/students")
revalidatePath("/teacher/classes/schedule")
return { success: true, message: "Class updated successfully" }
} catch (error) {
return { success: false, message: error instanceof Error ? error.message : "Failed to update class" }
}
} catch (e) {
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
throw e
}
}
export async function deleteAdminClassAction(classId: string): Promise<ActionState> {
try {
await requirePermission(Permissions.CLASS_DELETE)
const parsed = DeleteAdminClassSchema.safeParse({ classId })
if (!parsed.success) {
return { success: false, message: "Missing class id" }
}
try {
await deleteAdminClass(parsed.data.classId)
revalidatePath("/admin/school/classes")
revalidatePath("/teacher/classes/my")
revalidatePath("/teacher/classes/students")
revalidatePath("/teacher/classes/schedule")
return { success: true, message: "Class deleted successfully" }
} catch (error) {
return { success: false, message: error instanceof Error ? error.message : "Failed to delete class" }
}
} catch (e) {
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
throw e
}
}