1130 lines
38 KiB
Plaintext
1130 lines
38 KiB
Plaintext
// 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")
|
||
}
|