kindergarten/reading-platform-backend/prisma/schema.prisma
tonytech f056bf72a2 fix(backend): 修复 Prisma 在 Alpine Linux 容器中的 OpenSSL 兼容性问题
在 generator client 中添加 binaryTargets,显式指定
linux-musl-openssl-3.0.x,解决 Alpine Linux 3.18+ 使用
OpenSSL 3.x 时 Prisma 引擎无法加载的问题。
2026-02-28 19:32:03 +08:00

1074 lines
39 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.prisma - SQLite版本快速启动
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
// ==================== 租户 ====================
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[]
schoolCourses SchoolCourse[]
tenantPackages TenantPackage[]
@@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())
name String
description String?
themeId Int? @map("theme_id")
// 新增字段 - 课程包重构
coreContent String? @map("core_content")
// 课程介绍8个字段
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")
// 环创建设
environmentConstruction String? @map("environment_construction")
// 是否有集体课
hasCollectiveLesson Boolean @default(false) @map("has_collective_lesson")
pictureBookId Int? @map("picture_book_id")
pictureBookName String? @map("picture_book_name")
// 封面图片 - 存储文件路径(不再是 base64
coverImagePath String? @map("cover_image_path")
// 数字资源 - 存储多文件路径JSON数组 [{path, name}]
ebookPaths String? @map("ebook_paths")
audioPaths String? @map("audio_paths")
videoPaths String? @map("video_paths")
otherResources String? @map("other_resources") // JSON数组存储多个资源 {path, name}
// 教学材料 - 存储文件路径(不再是 base64
pptPath String? @map("ppt_path")
pptName String? @map("ppt_name")
posterPaths String? @map("poster_paths") // JSON数组存储多个挂图 {path, name}
// 实体教具和学生材料
tools String? @map("tools") // JSON数组存储教具列表 [{name, quantity}]
studentMaterials String? @map("student_materials") // 学生材料文本
// 课堂计划
lessonPlanData String? @map("lesson_plan_data") // JSON存储课堂计划数据
// 延伸活动
activitiesData String? @map("activities_data") // JSON存储延伸活动数据
// 测评工具
assessmentData String? @map("assessment_data") // JSON存储测评工具数据
gradeTags String @default("[]") @map("grade_tags")
domainTags String @default("[]") @map("domain_tags")
duration Int @default(25)
status String @default("DRAFT") // DRAFT, PENDING, REJECTED, PUBLISHED, ARCHIVED
version String @default("1.0")
// 审核相关字段
submittedAt DateTime? @map("submitted_at") // 提交审核时间
submittedBy Int? @map("submitted_by") // 提交人ID
reviewedAt DateTime? @map("reviewed_at") // 审核时间
reviewedBy Int? @map("reviewed_by") // 审核人ID
reviewComment String? @map("review_comment") // 审核意见
reviewChecklist String? @map("review_checklist") // 审核检查项结果 JSON
// 版本相关字段
parentId Int? @map("parent_id") // 父版本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")
resources CourseResource[]
scripts CourseScript[]
activities CourseActivity[]
lessons Lesson[]
tenantCourses TenantCourse[]
versions CourseVersion[]
tasks Task[]
taskTemplates TaskTemplate[]
schedulePlans SchedulePlan[]
scheduleTemplates ScheduleTemplate[]
// V2 关联
theme Theme? @relation(fields: [themeId], references: [id])
packageCourses CoursePackageCourse[]
courseLessons CourseLesson[]
schoolCourses SchoolCourse[]
@@index([status])
@@map("courses")
}
// ==================== 课程版本历史 ====================
model CourseVersion {
id Int @id @default(autoincrement())
courseId Int @map("course_id")
version String // 版本号
snapshotData String // JSON快照完整课程内容
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 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") // 关联资源ID列表JSON数组
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 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") // STUDENT, CLASS
title String
content String?
images String? @map("images") // JSON: ["path1", "path2"]
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") // READING, ACTIVITY, HOMEWORK
targetType String @map("target_type") // CLASS, STUDENT
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") // DRAFT, PUBLISHED, ARCHIVED
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") // PENDING, IN_PROGRESS, COMPLETED
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") // READING, ACTIVITY, HOMEWORK
// 关联课程(可选)
relatedCourseId Int? @map("related_course_id")
// 默认时间设置
defaultDuration Int @default(7) @map("default_duration") // 默认任务天数
// 模板状态
isDefault Boolean @default(false) @map("is_default")
status String @default("ACTIVE") // ACTIVE, ARCHIVED
// 创建者
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") // PICTURE_BOOK, MATERIAL, TEMPLATE
description String?
coverImage String? @map("cover_image")
tenantId Int? @map("tenant_id") // NULL = 公共资源
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") // IMAGE, PDF, VIDEO, AUDIO, PPT, OTHER
filePath String @map("file_path")
fileSize Int? @map("file_size")
tags String? // JSON: ["tag1", "tag2"]
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 // FATHER, MOTHER, GRANDFATHER, GRANDMOTHER, OTHER
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") // TEACHER, SCHOOL, PARENT
recipientId Int @map("recipient_id")
title String
content String
notificationType String @map("notification_type") // SYSTEM, TASK, LESSON, GROWTH
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") // MAIN主班, ASSIST配班, CARE保育员
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") // 操作人(教师ID),可选
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") // 时间段 "09:00-09:30"
weekDay Int? @map("week_day") // 周几 (0-6),用于重复排课
// 重复规则
repeatType String @default("NONE") @map("repeat_type") // NONE, DAILY, WEEKLY
repeatEndDate DateTime? @map("repeat_end_date")
// 排课来源
source String @default("SCHOOL") // SCHOOL(学校排课), TEACHER(教师预约)
createdBy Int @map("created_by") // 创建人ID
// 状态
status String @default("ACTIVE") // ACTIVE, CANCELLED
// 备注
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") // 时间段 "09:00-09:30"
weekDay Int? @map("week_day") // 周几 (0-6)
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") // SCHOOL, TEACHER, PARENT, ADMIN
action String // CREATE, UPDATE, DELETE, LOGIN, etc.
module String // 教师管理, 学生管理, 排课管理, etc.
description String
targetId Int? @map("target_id") // 操作对象ID
oldValue String? @map("old_value") // JSON格式
newValue String? @map("new_value") // JSON格式
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")
}
// ==================== 主题字典V2新增 ====================
model Theme {
id Int @id @default(autoincrement())
name String @unique
description String?
sortOrder Int @default(0) @map("sort_order")
status String @default("ACTIVE")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
courses Course[]
@@index([sortOrder])
@@map("themes")
}
// ==================== 课程套餐V2新增 ====================
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")
}
// ==================== 套餐-课程包关联V2新增 ====================
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")
}
// ==================== 租户-套餐授权V2新增 ====================
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")
}
// ==================== 课程V2新增 ====================
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")
}
// ==================== 教学环节V2新增 ====================
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")
}
// ==================== 环节资源关联V2新增 ====================
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")
}
// ==================== 校本课程包V2新增 ====================
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")
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])
@@map("school_courses")
}
// ==================== 校本课程V2新增 ====================
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)
@@index([schoolCourseId])
@@map("school_course_lessons")
}
// ==================== 校本课程预约V2新增 ====================
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")
schoolCourse SchoolCourse @relation(fields: [schoolCourseId], references: [id], onDelete: Cascade)
@@index([schoolCourseId, scheduledDate])
@@map("school_course_reservations")
}