Files
NextEdu/src/modules/classes/actions-schedule.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

125 lines
4.2 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 {
createClassScheduleItem,
updateClassScheduleItem,
deleteClassScheduleItem,
} from "@/modules/scheduling/data-access-class-schedule"
import {
CreateClassScheduleItemSchema,
UpdateClassScheduleItemSchema,
DeleteClassScheduleItemSchema,
} from "./schema"
import { toWeekday } from "./actions-shared"
export async function createClassScheduleItemAction(
prevState: ActionState<string> | null,
formData: FormData
): Promise<ActionState<string>> {
try {
await requirePermission(Permissions.CLASS_SCHEDULE)
const parsed = CreateClassScheduleItemSchema.safeParse({
classId: formData.get("classId"),
weekday: formData.get("weekday"),
course: formData.get("course"),
startTime: formData.get("startTime"),
endTime: formData.get("endTime"),
location: formData.get("location"),
})
if (!parsed.success) {
return { success: false, message: "Invalid schedule item data" }
}
const { classId, weekday, course, startTime, endTime, location } = parsed.data
try {
const id = await createClassScheduleItem({
classId,
weekday: toWeekday(weekday),
startTime,
endTime,
course,
location: location ?? null,
})
revalidatePath("/teacher/classes/schedule")
return { success: true, message: "Schedule item created successfully", data: id }
} catch (error) {
return { success: false, message: error instanceof Error ? error.message : "Failed to create schedule item" }
}
} catch (e) {
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
throw e
}
}
export async function updateClassScheduleItemAction(
scheduleId: string,
prevState: ActionState | null,
formData: FormData
): Promise<ActionState> {
try {
await requirePermission(Permissions.CLASS_SCHEDULE)
const parsed = UpdateClassScheduleItemSchema.safeParse({
scheduleId,
classId: formData.get("classId"),
weekday: formData.get("weekday") || undefined,
course: formData.get("course"),
startTime: formData.get("startTime"),
endTime: formData.get("endTime"),
location: formData.get("location"),
})
if (!parsed.success) {
return { success: false, message: "Missing or invalid schedule id" }
}
const { scheduleId: validatedScheduleId, classId, weekday, course, startTime, endTime, location } = parsed.data
try {
await updateClassScheduleItem(validatedScheduleId, {
classId: classId ?? undefined,
weekday: typeof weekday === "number" ? toWeekday(weekday) : undefined,
startTime: startTime ?? undefined,
endTime: endTime ?? undefined,
course: course ?? undefined,
location: location ?? undefined,
})
revalidatePath("/teacher/classes/schedule")
return { success: true, message: "Schedule item updated successfully" }
} catch (error) {
return { success: false, message: error instanceof Error ? error.message : "Failed to update schedule item" }
}
} catch (e) {
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
throw e
}
}
export async function deleteClassScheduleItemAction(scheduleId: string): Promise<ActionState> {
try {
await requirePermission(Permissions.CLASS_SCHEDULE)
const parsed = DeleteClassScheduleItemSchema.safeParse({ scheduleId })
if (!parsed.success) {
return { success: false, message: "Missing schedule id" }
}
try {
await deleteClassScheduleItem(parsed.data.scheduleId)
revalidatePath("/teacher/classes/schedule")
return { success: true, message: "Schedule item deleted successfully" }
} catch (error) {
return { success: false, message: error instanceof Error ? error.message : "Failed to delete schedule item" }
}
} catch (e) {
if (e instanceof PermissionDeniedError) return { success: false, message: e.message }
throw e
}
}