kindergarten_java/reading-platform-backend/prisma/schema-v2.prisma
2026-02-28 16:41:39 +08:00

1130 lines
38 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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")
}