/** * M12 代课教师机制 - Server Actions */ "use server"; import { getTranslations } from "next-intl/server"; import { revalidatePath } from "next/cache"; import { z } from "zod"; import { getSubstitutesByPlanId, getActiveSubstitutesByTeacherId, createSubstitute, updateSubstituteStatus, deleteSubstitute, canTeacherAccessPlan, } from "./data-access-substitutes"; import type { LessonPlanSubstitute } from "./data-access-substitutes"; import type { ActionState } from "@/shared/types/action-state"; import { getAuthContext, requirePermission } from "@/shared/lib/auth-guard"; import { handleActionError } from "@/shared/lib/action-utils"; import { Permissions } from "@/shared/types/permissions"; const createSubstituteSchema = z.object({ planId: z.string().min(1, "error.planIdRequired"), originalTeacherId: z.string().min(1, "error.teacherIdRequired"), substituteTeacherId: z.string().min(1, "error.teacherIdRequired"), startDate: z.string().refine((v) => !Number.isNaN(new Date(v).getTime()), "error.invalidDate"), endDate: z.string().refine((v) => !Number.isNaN(new Date(v).getTime()), "error.invalidDate").optional(), reason: z.string().max(255, "error.reasonTooLong").optional(), }); const updateSubstituteStatusSchema = z.object({ substituteId: z.string().min(1, "error.substituteIdRequired"), status: z.enum(["active", "expired", "cancelled"]), }); /** * 查询课案代课教师列表 */ export async function getLessonPlanSubstitutesAction( planId: string, ): Promise> { try { await requirePermission(Permissions.LESSON_PLAN_READ); const items = await getSubstitutesByPlanId(planId); return { success: true, data: { items } }; } catch (e) { return handleActionError(e); } } /** * 查询当前教师的代课任务 */ export async function getMySubstitutesAction(): Promise< ActionState<{ items: LessonPlanSubstitute[] }> > { try { await requirePermission(Permissions.LESSON_PLAN_READ); const auth = await getAuthContext(); if (!auth.userId) { return { success: false, message: "Unauthorized" }; } const items = await getActiveSubstitutesByTeacherId(auth.userId); return { success: true, data: { items } }; } catch (e) { return handleActionError(e); } } /** * 创建代课教师映射 */ export async function createSubstituteAction( input: Record, ): Promise> { try { await requirePermission(Permissions.LESSON_PLAN_UPDATE); const t = await getTranslations("lessonPreparation"); const parseResult = createSubstituteSchema.safeParse(input); if (!parseResult.success) { return { success: false, message: t("error.invalidInput"), errors: Object.fromEntries( Object.entries(parseResult.error.flatten().fieldErrors), ), }; } const auth = await getAuthContext(); if (!auth.userId) { return { success: false, message: t("error.unauthorized") }; } const substitute = await createSubstitute( { planId: parseResult.data.planId, originalTeacherId: parseResult.data.originalTeacherId, substituteTeacherId: parseResult.data.substituteTeacherId, startDate: new Date(parseResult.data.startDate), endDate: parseResult.data.endDate ? new Date(parseResult.data.endDate) : undefined, reason: parseResult.data.reason, }, auth.userId, ); revalidatePath(`/teacher/lesson-plans/${parseResult.data.planId}/edit`); return { success: true, data: { substitute } }; } catch (e) { return handleActionError(e); } } /** * 更新代课教师状态 */ export async function updateSubstituteStatusAction( input: Record, ): Promise> { try { await requirePermission(Permissions.LESSON_PLAN_UPDATE); const parseResult = updateSubstituteStatusSchema.safeParse(input); if (!parseResult.success) { return { success: false, message: "Invalid input" }; } await updateSubstituteStatus(parseResult.data.substituteId, parseResult.data.status); return { success: true, data: null }; } catch (e) { return handleActionError(e); } } /** * 删除代课教师映射 */ export async function deleteSubstituteAction( substituteId: string, ): Promise> { try { await requirePermission(Permissions.LESSON_PLAN_UPDATE); await deleteSubstitute(substituteId); return { success: true, data: null }; } catch (e) { return handleActionError(e); } } /** * 检查当前教师对某课案的访问权限(用于路由层校验) */ export async function canAccessPlanAction( planId: string, ): Promise> { try { await requirePermission(Permissions.LESSON_PLAN_READ); const auth = await getAuthContext(); if (!auth.userId) { return { success: false, message: "Unauthorized" }; } const canAccess = await canTeacherAccessPlan(planId, auth.userId); return { success: true, data: { canAccess } }; } catch (e) { return handleActionError(e); } }