feat: 完成 P1 全部功能 + 修复 proxy 导出 + 切换 MySQL 端口至 14013
## P1 功能(20 项) - 站内消息系统、家长仪表盘、学生考勤管理 - Excel 导入导出、用户批量导入、成绩导出 - 排课规则+自动排课+课表调整 - 成绩趋势+对比分析、密码安全策略、速率限制 - 数据变更日志、文件预览+存储策略、全文检索 - 依赖审计集成 CI、数据库定时备份、E2E 测试完善 - 通知偏好管理 ## 基础设施修复 - src/proxy.ts: 将 middleware 导出重命名为 proxy(Next.js 16 要求) - .env: MySQL 端口从 13002 切换至 14013 - scripts/create-db.ts: 新增数据库初始化脚本 ## 架构文档同步 - 004_architecture_impact_map.md 和 005_architecture_data.json 完整记录所有新增表、模块、路由、权限、依赖关系
This commit is contained in:
149
src/modules/course-plans/schema.ts
Normal file
149
src/modules/course-plans/schema.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { z } from "zod"
|
||||
|
||||
export const CreateCoursePlanSchema = z
|
||||
.object({
|
||||
classId: z.string().trim().min(1),
|
||||
subjectId: z.string().trim().min(1),
|
||||
teacherId: z.string().trim().min(1),
|
||||
academicYearId: z.string().trim().optional().nullable(),
|
||||
semester: z.enum(["1", "2"]).optional(),
|
||||
totalHours: z.coerce.number().int().min(0).optional(),
|
||||
weeklyHours: z.coerce.number().int().min(0).optional(),
|
||||
startDate: z.string().trim().optional().nullable(),
|
||||
endDate: z.string().trim().optional().nullable(),
|
||||
syllabus: z.string().trim().optional().nullable(),
|
||||
objectives: z.string().trim().optional().nullable(),
|
||||
status: z.enum(["planning", "active", "completed", "paused"]).optional(),
|
||||
})
|
||||
.transform((v) => ({
|
||||
classId: v.classId,
|
||||
subjectId: v.subjectId,
|
||||
teacherId: v.teacherId,
|
||||
academicYearId: v.academicYearId && v.academicYearId.length > 0 ? v.academicYearId : null,
|
||||
semester: v.semester ?? "1",
|
||||
totalHours: v.totalHours ?? 0,
|
||||
weeklyHours: v.weeklyHours ?? 0,
|
||||
startDate: v.startDate && v.startDate.length > 0 ? v.startDate : null,
|
||||
endDate: v.endDate && v.endDate.length > 0 ? v.endDate : null,
|
||||
syllabus: v.syllabus && v.syllabus.length > 0 ? v.syllabus : null,
|
||||
objectives: v.objectives && v.objectives.length > 0 ? v.objectives : null,
|
||||
status: v.status ?? "planning",
|
||||
}))
|
||||
|
||||
export type CreateCoursePlanInput = z.infer<typeof CreateCoursePlanSchema>
|
||||
|
||||
export const UpdateCoursePlanSchema = z
|
||||
.object({
|
||||
classId: z.string().trim().min(1).optional(),
|
||||
subjectId: z.string().trim().min(1).optional(),
|
||||
teacherId: z.string().trim().min(1).optional(),
|
||||
academicYearId: z.string().trim().optional().nullable(),
|
||||
semester: z.enum(["1", "2"]).optional(),
|
||||
totalHours: z.coerce.number().int().min(0).optional(),
|
||||
completedHours: z.coerce.number().int().min(0).optional(),
|
||||
weeklyHours: z.coerce.number().int().min(0).optional(),
|
||||
startDate: z.string().trim().optional().nullable(),
|
||||
endDate: z.string().trim().optional().nullable(),
|
||||
syllabus: z.string().trim().optional().nullable(),
|
||||
objectives: z.string().trim().optional().nullable(),
|
||||
status: z.enum(["planning", "active", "completed", "paused"]).optional(),
|
||||
})
|
||||
.transform((v) => ({
|
||||
...v,
|
||||
academicYearId:
|
||||
v.academicYearId !== undefined
|
||||
? v.academicYearId && v.academicYearId.length > 0
|
||||
? v.academicYearId
|
||||
: null
|
||||
: undefined,
|
||||
startDate:
|
||||
v.startDate !== undefined
|
||||
? v.startDate && v.startDate.length > 0
|
||||
? v.startDate
|
||||
: null
|
||||
: undefined,
|
||||
endDate:
|
||||
v.endDate !== undefined
|
||||
? v.endDate && v.endDate.length > 0
|
||||
? v.endDate
|
||||
: null
|
||||
: undefined,
|
||||
syllabus:
|
||||
v.syllabus !== undefined
|
||||
? v.syllabus && v.syllabus.length > 0
|
||||
? v.syllabus
|
||||
: null
|
||||
: undefined,
|
||||
objectives:
|
||||
v.objectives !== undefined
|
||||
? v.objectives && v.objectives.length > 0
|
||||
? v.objectives
|
||||
: null
|
||||
: undefined,
|
||||
}))
|
||||
|
||||
export type UpdateCoursePlanInput = z.infer<typeof UpdateCoursePlanSchema>
|
||||
|
||||
export const CreateCoursePlanItemSchema = z
|
||||
.object({
|
||||
planId: z.string().trim().min(1),
|
||||
week: z.coerce.number().int().min(1),
|
||||
topic: z.string().trim().min(1).max(255),
|
||||
content: z.string().trim().optional().nullable(),
|
||||
hours: z.coerce.number().int().min(1).optional(),
|
||||
textbookChapter: z.string().trim().optional().nullable(),
|
||||
notes: z.string().trim().optional().nullable(),
|
||||
})
|
||||
.transform((v) => ({
|
||||
planId: v.planId,
|
||||
week: v.week,
|
||||
topic: v.topic,
|
||||
content: v.content && v.content.length > 0 ? v.content : null,
|
||||
hours: v.hours ?? 2,
|
||||
textbookChapter:
|
||||
v.textbookChapter && v.textbookChapter.length > 0 ? v.textbookChapter : null,
|
||||
notes: v.notes && v.notes.length > 0 ? v.notes : null,
|
||||
}))
|
||||
|
||||
export type CreateCoursePlanItemInput = z.infer<typeof CreateCoursePlanItemSchema>
|
||||
|
||||
export const UpdateCoursePlanItemSchema = z
|
||||
.object({
|
||||
week: z.coerce.number().int().min(1).optional(),
|
||||
topic: z.string().trim().min(1).max(255).optional(),
|
||||
content: z.string().trim().optional().nullable(),
|
||||
hours: z.coerce.number().int().min(1).optional(),
|
||||
textbookChapter: z.string().trim().optional().nullable(),
|
||||
notes: z.string().trim().optional().nullable(),
|
||||
isCompleted: z.boolean().optional(),
|
||||
completedAt: z.string().trim().optional().nullable(),
|
||||
})
|
||||
.transform((v) => ({
|
||||
...v,
|
||||
content:
|
||||
v.content !== undefined
|
||||
? v.content && v.content.length > 0
|
||||
? v.content
|
||||
: null
|
||||
: undefined,
|
||||
textbookChapter:
|
||||
v.textbookChapter !== undefined
|
||||
? v.textbookChapter && v.textbookChapter.length > 0
|
||||
? v.textbookChapter
|
||||
: null
|
||||
: undefined,
|
||||
notes:
|
||||
v.notes !== undefined
|
||||
? v.notes && v.notes.length > 0
|
||||
? v.notes
|
||||
: null
|
||||
: undefined,
|
||||
completedAt:
|
||||
v.completedAt !== undefined
|
||||
? v.completedAt && v.completedAt.length > 0
|
||||
? v.completedAt
|
||||
: null
|
||||
: undefined,
|
||||
}))
|
||||
|
||||
export type UpdateCoursePlanItemInput = z.infer<typeof UpdateCoursePlanItemSchema>
|
||||
Reference in New Issue
Block a user