Files
NextEdu/src/modules/school/schema.ts
SpecialX c766951374 feat(school,classes): 实现 P2 长期问题全量改进项
P2-2: 新增 OrgTreeNav 组件(学校→年级→班级三级树形导航,支持搜索过滤/选中高亮/展开折叠)

P2-3: 新增 promoteGradesAction 年级升级功能(中文数字/阿拉伯数字识别,按 order 降序避免冲突)

P2-4: 新增 bulkEnrollStudentsAction(CSV 批量导入学生)+ bulkAssignSubjectTeachersAction(CSV 批量分配教师)

P2-5: 为 department/academicYear/grade 的 9 个 CRUD Action 补充 logAudit 审计日志

同步更新架构图文档 004/005
2026-06-23 08:55:21 +08:00

57 lines
1.8 KiB
TypeScript

import { z } from "zod"
export const UpsertDepartmentSchema = z.object({
name: z.string().trim().min(1).max(255),
description: z.string().trim().max(5000).optional().nullable(),
})
export const UpsertAcademicYearSchema = z
.object({
name: z.string().trim().min(1).max(100),
startDate: z.string().min(1),
endDate: z.string().min(1),
isActive: z.union([z.literal("on"), z.literal("true"), z.literal("false"), z.string()]).optional(),
})
.transform((v) => ({
name: v.name,
startDate: v.startDate,
endDate: v.endDate,
isActive: v.isActive === "on" || v.isActive === "true",
}))
.refine((v) => new Date(v.startDate).getTime() <= new Date(v.endDate).getTime(), {
message: "startDate must be before endDate",
})
export const UpsertSchoolSchema = z.object({
name: z.string().trim().min(1).max(255),
code: z.string().trim().max(50).optional().nullable(),
})
export const UpsertGradeSchema = z
.object({
schoolId: z.string().trim().min(1),
name: z.string().trim().min(1).max(100),
order: z.union([z.string(), z.number()]).optional().nullable(),
gradeHeadId: z.string().trim().optional().nullable(),
teachingHeadId: z.string().trim().optional().nullable(),
})
.transform((v) => ({
schoolId: v.schoolId,
name: v.name,
order:
typeof v.order === "number"
? v.order
: typeof v.order === "string" && v.order.trim().length > 0
? Number(v.order)
: 0,
gradeHeadId: v.gradeHeadId && v.gradeHeadId.length > 0 ? v.gradeHeadId : null,
teachingHeadId: v.teachingHeadId && v.teachingHeadId.length > 0 ? v.teachingHeadId : null,
}))
.refine((v) => Number.isFinite(v.order) && Number.isInteger(v.order) && v.order >= 0, {
message: "order must be a non-negative integer",
})
export const PromoteGradesSchema = z.object({
schoolId: z.string().trim().min(1),
})