kindergarten_java/reading-platform-backend/prisma/schema-v2.prisma

1130 lines
38 KiB
Plaintext
Raw Permalink Normal View History

2026-02-28 16:41:39 +08:00
// prisma/schema-v2.prisma - 重构版数据模型
// 创建时间2026-02-27
// 基于设计文档21-数据模型重构设计.md
//
// 迁移说明:
// 1. 本文件为新版数据模型,与原 schema.prisma 共存
// 2. 采用渐进式迁移策略,保留旧表以确保向后兼容
// 3. 迁移完成后可将旧表标记为废弃
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
// ==================== 主题字典(新增) ====================
model Theme {
id Int @id @default(autoincrement())
name String @unique
description String?
sortOrder Int @default(0) @map("sort_order")
status String @default("ACTIVE") // ACTIVE, ARCHIVED
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
courses Course[]
@@index([sortOrder])
@@map("themes")
}
// ==================== 课程套餐(新增) ====================
model CoursePackage {
id Int @id @default(autoincrement())
name String
description String?
price Int @default(0)
discountPrice Int? @map("discount_price")
discountType String? @map("discount_type")
gradeLevels String @default("[]") @map("grade_levels")
status String @default("DRAFT")
submittedAt DateTime? @map("submitted_at")
submittedBy Int? @map("submitted_by")
reviewedAt DateTime? @map("reviewed_at")
reviewedBy Int? @map("reviewed_by")
reviewComment String? @map("review_comment")
courseCount Int @default(0) @map("course_count")
tenantCount Int @default(0) @map("tenant_count")
createdBy Int? @map("created_by")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
publishedAt DateTime? @map("published_at")
courses CoursePackageCourse[]
tenantPackages TenantPackage[]
@@index([status])
@@map("course_packages")
}
// ==================== 套餐-课程包关联(新增) ====================
model CoursePackageCourse {
id Int @id @default(autoincrement())
packageId Int @map("package_id")
courseId Int @map("course_id")
gradeLevel String @map("grade_level")
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
package CoursePackage @relation(fields: [packageId], references: [id], onDelete: Cascade)
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
@@unique([packageId, courseId])
@@index([packageId, gradeLevel])
@@map("course_package_courses")
}
// ==================== 租户-套餐授权(新增) ====================
model TenantPackage {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
packageId Int @map("package_id")
startDate String @map("start_date")
endDate String @map("end_date")
status String @default("ACTIVE")
pricePaid Int @default(0) @map("price_paid")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
package CoursePackage @relation(fields: [packageId], references: [id], onDelete: Cascade)
@@unique([tenantId, packageId])
@@index([tenantId, status])
@@map("tenant_packages")
}
// ==================== 租户 ====================
model Tenant {
id Int @id @default(autoincrement())
name String
loginAccount String? @unique @map("login_account")
passwordHash String? @map("password_hash")
address String?
contactPerson String? @map("contact_person")
contactPhone String? @map("contact_phone")
logoUrl String? @map("logo_url")
packageType String @default("STANDARD") @map("package_type")
teacherQuota Int @default(20) @map("teacher_quota")
studentQuota Int @default(200) @map("student_quota")
storageQuota BigInt @default(5368709120) @map("storage_quota")
startDate String @map("start_date")
expireDate String @map("expire_date")
teacherCount Int @default(0) @map("teacher_count")
studentCount Int @default(0) @map("student_count")
storageUsed BigInt @default(0) @map("storage_used")
status String @default("ACTIVE")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
teachers Teacher[]
students Student[]
classes Class[]
lessons Lesson[]
tenantCourses TenantCourse[]
growthRecords GrowthRecord[]
tasks Task[]
taskTemplates TaskTemplate[]
parents Parent[]
notifications Notification[]
settings SystemSettings?
schedulePlans SchedulePlan[]
scheduleTemplates ScheduleTemplate[]
operationLogs OperationLog[]
// 新增关联
packages TenantPackage[]
schoolCourses SchoolCourse[]
@@map("tenants")
}
// ==================== 教师 ====================
model Teacher {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
name String
phone String
email String?
loginAccount String @unique @map("login_account")
passwordHash String @map("password_hash")
classIds String? @default("[]") @map("class_ids")
status String @default("ACTIVE")
lessonCount Int @default(0) @map("lesson_count")
feedbackCount Int @default(0) @map("feedback_count")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
lastLoginAt DateTime? @map("last_login_at")
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
classes Class[]
lessons Lesson[]
feedbacks LessonFeedback[]
classTeachers ClassTeacher[]
schedulePlans SchedulePlan[]
scheduleTemplates ScheduleTemplate[]
@@map("teachers")
}
// ==================== 班级 ====================
model Class {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
name String
grade String
teacherId Int? @map("teacher_id")
studentCount Int @default(0) @map("student_count")
lessonCount Int @default(0) @map("lesson_count")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
teacher Teacher? @relation(fields: [teacherId], references: [id])
students Student[]
lessons Lesson[]
growthRecords GrowthRecord[]
classTeachers ClassTeacher[]
studentHistory StudentClassHistory[] @relation("ToClass")
fromHistory StudentClassHistory[] @relation("FromClass")
schedulePlans SchedulePlan[]
scheduleTemplates ScheduleTemplate[]
@@map("classes")
}
// ==================== 学生 ====================
model Student {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
classId Int @map("class_id")
name String
gender String?
birthDate DateTime? @map("birth_date")
parentPhone String? @map("parent_phone")
parentName String? @map("parent_name")
readingCount Int @default(0) @map("reading_count")
lessonCount Int @default(0) @map("lesson_count")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
records StudentRecord[]
growthRecords GrowthRecord[]
taskCompletions TaskCompletion[]
parents ParentStudent[]
classHistory StudentClassHistory[]
@@map("students")
}
// ==================== 课程包(重构) ====================
model Course {
id Int @id @default(autoincrement())
// 新增字段
themeId Int? @map("theme_id")
coreContent String? @map("core_content")
introSummary String? @map("intro_summary")
introHighlights String? @map("intro_highlights")
introGoals String? @map("intro_goals")
introSchedule String? @map("intro_schedule")
introKeyPoints String? @map("intro_key_points")
introMethods String? @map("intro_methods")
introEvaluation String? @map("intro_evaluation")
introNotes String? @map("intro_notes")
scheduleRefData String? @map("schedule_ref_data")
hasCollectiveLesson Boolean @default(false) @map("has_collective_lesson")
// 保留字段
name String
description String?
pictureBookId Int? @map("picture_book_id")
pictureBookName String? @map("picture_book_name")
coverImagePath String? @map("cover_image_path")
ebookPaths String? @map("ebook_paths")
audioPaths String? @map("audio_paths")
videoPaths String? @map("video_paths")
otherResources String? @map("other_resources")
pptPath String? @map("ppt_path")
pptName String? @map("ppt_name")
posterPaths String? @map("poster_paths")
tools String? @map("tools")
studentMaterials String? @map("student_materials")
lessonPlanData String? @map("lesson_plan_data")
activitiesData String? @map("activities_data")
assessmentData String? @map("assessment_data")
gradeTags String @default("[]") @map("grade_tags")
domainTags String @default("[]") @map("domain_tags")
duration Int @default(25)
status String @default("DRAFT")
version String @default("1.0")
submittedAt DateTime? @map("submitted_at")
submittedBy Int? @map("submitted_by")
reviewedAt DateTime? @map("reviewed_at")
reviewedBy Int? @map("reviewed_by")
reviewComment String? @map("review_comment")
reviewChecklist String? @map("review_checklist")
parentId Int? @map("parent_id")
isLatest Boolean @default(true)
usageCount Int @default(0) @map("usage_count")
teacherCount Int @default(0) @map("teacher_count")
avgRating Float @default(0) @map("avg_rating")
createdBy Int? @map("created_by")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
publishedAt DateTime? @map("published_at")
// 关联
theme Theme? @relation(fields: [themeId], references: [id])
packageCourses CoursePackageCourse[]
courseLessons CourseLesson[]
schoolCourses SchoolCourse[]
resources CourseResource[]
scripts CourseScript[]
activities CourseActivity[]
lessons Lesson[]
tenantCourses TenantCourse[]
versions CourseVersion[]
tasks Task[]
taskTemplates TaskTemplate[]
schedulePlans SchedulePlan[]
scheduleTemplates ScheduleTemplate[]
@@index([themeId])
@@index([status])
@@map("courses")
}
// ==================== 课程(新增) ====================
model CourseLesson {
id Int @id @default(autoincrement())
courseId Int @map("course_id")
lessonType String @map("lesson_type")
name String
description String?
duration Int @default(25)
videoPath String? @map("video_path")
videoName String? @map("video_name")
pptPath String? @map("ppt_path")
pptName String? @map("ppt_name")
pdfPath String? @map("pdf_path")
pdfName String? @map("pdf_name")
objectives String?
preparation String?
extension String?
reflection String?
assessmentData String? @map("assessment_data")
useTemplate Boolean @default(false) @map("use_template")
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
steps LessonStep[]
@@unique([courseId, lessonType])
@@index([courseId])
@@map("course_lessons")
}
// ==================== 教学环节(新增) ====================
model LessonStep {
id Int @id @default(autoincrement())
lessonId Int @map("lesson_id")
name String
content String?
duration Int @default(5)
objective String?
resourceIds String? @map("resource_ids")
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
lesson CourseLesson @relation(fields: [lessonId], references: [id], onDelete: Cascade)
stepResources LessonStepResource[]
@@index([lessonId])
@@map("lesson_steps")
}
// ==================== 环节资源关联(新增) ====================
model LessonStepResource {
id Int @id @default(autoincrement())
stepId Int @map("step_id")
resourceId Int @map("resource_id")
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
step LessonStep @relation(fields: [stepId], references: [id], onDelete: Cascade)
resource CourseResource @relation(fields: [resourceId], references: [id], onDelete: Cascade)
@@unique([stepId, resourceId])
@@map("lesson_step_resources")
}
// ==================== 校本课程包(新增) ====================
model SchoolCourse {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
sourceCourseId Int @map("source_course_id")
name String
description String?
createdBy Int @map("created_by")
changesSummary String? @map("changes_summary")
changesData String? @map("changes_data")
usageCount Int @default(0) @map("usage_count")
status String @default("ACTIVE")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
sourceCourse Course @relation(fields: [sourceCourseId], references: [id])
lessons SchoolCourseLesson[]
reservations SchoolCourseReservation[]
@@index([tenantId])
@@index([sourceCourseId])
@@map("school_courses")
}
// ==================== 校本课程(新增) ====================
model SchoolCourseLesson {
id Int @id @default(autoincrement())
schoolCourseId Int @map("school_course_id")
sourceLessonId Int @map("source_lesson_id")
lessonType String @map("lesson_type")
objectives String?
preparation String?
extension String?
reflection String?
changeNote String? @map("change_note")
stepsData String? @map("steps_data")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
schoolCourse SchoolCourse @relation(fields: [schoolCourseId], references: [id], onDelete: Cascade)
@@unique([schoolCourseId, lessonType])
@@map("school_course_lessons")
}
// ==================== 校本课程预约(新增) ====================
model SchoolCourseReservation {
id Int @id @default(autoincrement())
schoolCourseId Int @map("school_course_id")
teacherId Int @map("teacher_id")
classId Int @map("class_id")
scheduledDate String @map("scheduled_date")
scheduledTime String? @map("scheduled_time")
status String @default("PENDING")
note String?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
schoolCourse SchoolCourse @relation(fields: [schoolCourseId], references: [id], onDelete: Cascade)
@@index([schoolCourseId, scheduledDate])
@@map("school_course_reservations")
}
// ==================== 课程资源 ====================
model CourseResource {
id Int @id @default(autoincrement())
courseId Int @map("course_id")
resourceType String @map("resource_type")
resourceName String @map("resource_name")
fileUrl String @map("file_url")
fileSize Int? @map("file_size")
mimeType String? @map("mime_type")
metadata String?
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
stepResources LessonStepResource[]
@@map("course_resources")
}
// ==================== 课程脚本(废弃但保留) ====================
model CourseScript {
id Int @id @default(autoincrement())
courseId Int @map("course_id")
stepIndex Int @map("step_index")
stepName String @map("step_name")
stepType String @map("step_type")
duration Int
objective String?
teacherScript String? @map("teacher_script")
interactionPoints String? @map("interaction_points")
resourceIds String? @map("resource_ids")
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
pages CourseScriptPage[]
@@unique([courseId, stepIndex])
@@map("course_scripts")
}
// ==================== 逐页配置(废弃但保留) ====================
model CourseScriptPage {
id Int @id @default(autoincrement())
scriptId Int @map("script_id")
pageNumber Int @map("page_number")
questions String?
interactionComponent String? @map("interaction_component")
teacherNotes String? @map("teacher_notes")
resourceIds String? @map("resource_ids")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
script CourseScript @relation(fields: [scriptId], references: [id], onDelete: Cascade)
@@unique([scriptId, pageNumber])
@@map("course_script_pages")
}
// ==================== 延伸活动(废弃但保留) ====================
model CourseActivity {
id Int @id @default(autoincrement())
courseId Int @map("course_id")
name String
domain String?
domainTagId Int? @map("domain_tag_id")
activityType String @map("activity_type")
duration Int?
onlineMaterials String? @map("online_materials")
offlineMaterials String?
activityGuide String?
objectives String?
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
@@map("course_activities")
}
// ==================== 课程版本历史 ====================
model CourseVersion {
id Int @id @default(autoincrement())
courseId Int @map("course_id")
version String
snapshotData String
changeLog String?
publishedAt DateTime @default(now()) @map("published_at")
publishedBy Int @map("published_by")
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
@@index([courseId])
@@map("course_versions")
}
// ==================== 授课记录 ====================
model Lesson {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
teacherId Int @map("teacher_id")
classId Int @map("class_id")
courseId Int @map("course_id")
schedulePlanId Int? @map("schedule_plan_id")
plannedDatetime DateTime? @map("planned_datetime")
startDatetime DateTime? @map("start_datetime")
endDatetime DateTime? @map("end_datetime")
actualDuration Int? @map("actual_duration")
status String @default("PLANNED")
overallRating String? @map("overall_rating")
participationRating String? @map("participation_rating")
completionNote String? @map("completion_note")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
tenant Tenant @relation(fields: [tenantId], references: [id])
teacher Teacher @relation(fields: [teacherId], references: [id])
class Class @relation(fields: [classId], references: [id])
course Course @relation(fields: [courseId], references: [id])
schedulePlan SchedulePlan? @relation(fields: [schedulePlanId], references: [id])
feedbacks LessonFeedback[]
records StudentRecord[]
@@map("lessons")
}
// ==================== 课程反馈 ====================
model LessonFeedback {
id Int @id @default(autoincrement())
lessonId Int @map("lesson_id")
teacherId Int @map("teacher_id")
designQuality Int? @map("design_quality")
participation Int?
goalAchievement Int? @map("goal_achievement")
stepFeedbacks String? @map("step_feedbacks")
pros String?
suggestions String?
activitiesDone String? @map("activities_done")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade)
teacher Teacher @relation(fields: [teacherId], references: [id])
@@unique([lessonId, teacherId])
@@map("lesson_feedbacks")
}
// ==================== 学生测评记录 ====================
model StudentRecord {
id Int @id @default(autoincrement())
lessonId Int @map("lesson_id")
studentId Int @map("student_id")
focus Int?
participation Int?
interest Int?
understanding Int?
domainAchievements String?
notes String?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade)
student Student @relation(fields: [studentId], references: [id])
@@unique([lessonId, studentId])
@@map("student_records")
}
// ==================== 标签体系 ====================
model Tag {
id Int @id @default(autoincrement())
level Int
code String @unique
name String
parentId Int? @map("parent_id")
description String?
metadata String?
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
@@map("tags")
}
// ==================== 租户课程授权 ====================
model TenantCourse {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
courseId Int @map("course_id")
authorized Boolean @default(true)
authorizedAt DateTime? @map("authorized_at")
createdAt DateTime @default(now()) @map("created_at")
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
@@unique([tenantId, courseId])
@@map("tenant_courses")
}
// ==================== 成长档案 ====================
model GrowthRecord {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
studentId Int @map("student_id")
classId Int? @map("class_id")
recordType String @map("record_type")
title String
content String?
images String? @map("images")
recordDate DateTime @map("record_date")
createdBy Int @map("created_by")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
student Student @relation(fields: [studentId], references: [id], onDelete: Cascade)
class Class? @relation(fields: [classId], references: [id], onDelete: SetNull)
@@index([tenantId, studentId])
@@index([tenantId, classId])
@@map("growth_records")
}
// ==================== 阅读任务 ====================
model Task {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
title String
description String?
taskType String @map("task_type")
targetType String @map("target_type")
relatedCourseId Int? @map("related_course_id")
createdBy Int @map("created_by")
startDate DateTime @map("start_date")
endDate DateTime @map("end_date")
status String @default("PUBLISHED")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
course Course? @relation(fields: [relatedCourseId], references: [id], onDelete: SetNull)
targets TaskTarget[]
completions TaskCompletion[]
@@index([tenantId, status])
@@map("tasks")
}
model TaskTarget {
id Int @id @default(autoincrement())
taskId Int @map("task_id")
classId Int? @map("class_id")
studentId Int? @map("student_id")
task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
@@index([taskId, classId])
@@index([taskId, studentId])
@@map("task_targets")
}
model TaskCompletion {
id Int @id @default(autoincrement())
taskId Int @map("task_id")
studentId Int @map("student_id")
status String @default("PENDING")
completedAt DateTime? @map("completed_at")
feedback String?
parentFeedback String? @map("parent_feedback")
createdAt DateTime @default(now())
task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
student Student @relation(fields: [studentId], references: [id], onDelete: Cascade)
@@unique([taskId, studentId])
@@map("task_completions")
}
// ==================== 任务模板 ====================
model TaskTemplate {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
name String
description String?
taskType String @map("task_type")
relatedCourseId Int? @map("related_course_id")
defaultDuration Int @default(7) @map("default_duration")
isDefault Boolean @default(false) @map("is_default")
status String @default("ACTIVE")
createdBy Int @map("created_by")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
course Course? @relation(fields: [relatedCourseId], references: [id], onDelete: SetNull)
@@index([tenantId, status])
@@map("task_templates")
}
// ==================== 资源库 ====================
model ResourceLibrary {
id Int @id @default(autoincrement())
name String
libraryType String @map("library_type")
description String?
coverImage String? @map("cover_image")
tenantId Int? @map("tenant_id")
createdBy Int @map("created_by")
status String @default("PUBLISHED")
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
items ResourceItem[]
@@index([libraryType, status])
@@map("resource_libraries")
}
model ResourceItem {
id Int @id @default(autoincrement())
libraryId Int @map("library_id")
title String
description String?
fileType String @map("file_type")
filePath String @map("file_path")
fileSize Int? @map("file_size")
tags String?
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now())
library ResourceLibrary @relation(fields: [libraryId], references: [id], onDelete: Cascade)
@@index([libraryId])
@@map("resource_items")
}
// ==================== 系统设置 ====================
model SystemSettings {
id Int @id @default(autoincrement())
tenantId Int @unique @map("tenant_id")
schoolName String? @map("school_name")
schoolLogo String? @map("school_logo")
address String?
notifyOnLesson Boolean @default(true) @map("notify_on_lesson")
notifyOnTask Boolean @default(true) @map("notify_on_task")
notifyOnGrowth Boolean @default(false) @map("notify_on_growth")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
@@map("system_settings")
}
// ==================== 家长 ====================
model Parent {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
name String
phone String
email String?
loginAccount String @unique @map("login_account")
passwordHash String @map("password_hash")
status String @default("ACTIVE")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
lastLoginAt DateTime? @map("last_login_at")
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
children ParentStudent[]
@@map("parents")
}
// ==================== 家长-学生关联 ====================
model ParentStudent {
id Int @id @default(autoincrement())
parentId Int @map("parent_id")
studentId Int @map("student_id")
relationship String
createdAt DateTime @default(now()) @map("created_at")
parent Parent @relation(fields: [parentId], references: [id], onDelete: Cascade)
student Student @relation(fields: [studentId], references: [id], onDelete: Cascade)
@@unique([parentId, studentId])
@@map("parent_students")
}
// ==================== 通知 ====================
model Notification {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
recipientType String @map("recipient_type")
recipientId Int @map("recipient_id")
title String
content String
notificationType String @map("notification_type")
relatedType String? @map("related_type")
relatedId Int? @map("related_id")
isRead Boolean @default(false) @map("is_read")
readAt DateTime? @map("read_at")
createdAt DateTime @default(now()) @map("created_at")
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
@@index([tenantId, recipientType, recipientId])
@@map("notifications")
}
// ==================== 班级教师关联 ====================
model ClassTeacher {
id Int @id @default(autoincrement())
classId Int @map("class_id")
teacherId Int @map("teacher_id")
role String @default("MAIN")
isPrimary Boolean @default(false)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
teacher Teacher @relation(fields: [teacherId], references: [id], onDelete: Cascade)
@@unique([classId, teacherId])
@@map("class_teachers")
}
// ==================== 学生调班历史 ====================
model StudentClassHistory {
id Int @id @default(autoincrement())
studentId Int @map("student_id")
fromClassId Int? @map("from_class_id")
toClassId Int @map("to_class_id")
reason String?
operatedBy Int? @map("operated_by")
createdAt DateTime @default(now()) @map("created_at")
student Student @relation(fields: [studentId], references: [id])
fromClass Class? @relation("FromClass", fields: [fromClassId], references: [id])
toClass Class @relation("ToClass", fields: [toClassId], references: [id])
@@map("student_class_history")
}
// ==================== 排课计划 ====================
model SchedulePlan {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
classId Int @map("class_id")
courseId Int @map("course_id")
teacherId Int? @map("teacher_id")
scheduledDate DateTime? @map("scheduled_date")
scheduledTime String? @map("scheduled_time")
weekDay Int? @map("week_day")
repeatType String @default("NONE") @map("repeat_type")
repeatEndDate DateTime? @map("repeat_end_date")
source String @default("SCHOOL")
createdBy Int @map("created_by")
status String @default("ACTIVE")
note String?
reminderSent Boolean @default(false) @map("reminder_sent")
reminderSentAt DateTime? @map("reminder_sent_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
tenant Tenant @relation(fields: [tenantId], references: [id])
class Class @relation(fields: [classId], references: [id])
course Course @relation(fields: [courseId], references: [id])
teacher Teacher? @relation(fields: [teacherId], references: [id])
lessons Lesson[]
@@index([tenantId, classId])
@@index([tenantId, teacherId])
@@index([tenantId, scheduledDate])
@@map("schedule_plans")
}
// ==================== 排课模板 ====================
model ScheduleTemplate {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
name String
courseId Int @map("course_id")
classId Int? @map("class_id")
teacherId Int? @map("teacher_id")
scheduledTime String? @map("scheduled_time")
weekDay Int? @map("week_day")
duration Int @default(25)
isDefault Boolean @default(false) @map("is_default")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
course Course @relation(fields: [courseId], references: [id])
class Class? @relation(fields: [classId], references: [id])
teacher Teacher? @relation(fields: [teacherId], references: [id])
@@index([tenantId])
@@index([tenantId, courseId])
@@map("schedule_templates")
}
// ==================== 操作日志 ====================
model OperationLog {
id Int @id @default(autoincrement())
tenantId Int? @map("tenant_id")
userId Int @map("user_id")
userType String @map("user_type")
action String
module String
description String
targetId Int? @map("target_id")
oldValue String? @map("old_value")
newValue String? @map("new_value")
ipAddress String? @map("ip_address")
userAgent String? @map("user_agent")
createdAt DateTime @default(now()) @map("created_at")
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)
@@index([tenantId, userId])
@@index([tenantId, createdAt])
@@index([action, module])
@@map("operation_logs")
}