527 lines
19 KiB
Plaintext
527 lines
19 KiB
Plaintext
// This is your Prisma schema file,
|
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
previewFeatures = ["fullTextIndex"]
|
|
}
|
|
|
|
datasource db {
|
|
provider = "mysql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// =============================================
|
|
// 基础审计字段模型
|
|
// =============================================
|
|
|
|
model ApplicationUser {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
realName String @map("real_name") @db.VarChar(50)
|
|
studentId String? @map("student_id") @db.VarChar(20)
|
|
avatarUrl String? @map("avatar_url") @db.VarChar(500)
|
|
gender Gender @default(Male)
|
|
currentSchoolId String? @map("current_school_id") @db.VarChar(36)
|
|
accountStatus AccountStatus @map("account_status") @default(Active)
|
|
email String? @db.VarChar(100)
|
|
phone String? @db.VarChar(20)
|
|
bio String? @db.Text
|
|
passwordHash String @map("password_hash") @db.VarChar(255)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
// Relations
|
|
classMemberships ClassMember[]
|
|
createdQuestions Question[] @relation("CreatedQuestions")
|
|
createdExams Exam[] @relation("CreatedExams")
|
|
submissions StudentSubmission[]
|
|
messages Message[]
|
|
|
|
@@index([studentId])
|
|
@@index([email])
|
|
@@index([phone])
|
|
@@index([currentSchoolId])
|
|
@@map("application_users")
|
|
}
|
|
|
|
enum Gender {
|
|
Male
|
|
Female
|
|
}
|
|
|
|
enum AccountStatus {
|
|
Active
|
|
Suspended
|
|
Graduated
|
|
}
|
|
|
|
// =============================================
|
|
// 组织架构模块
|
|
// =============================================
|
|
|
|
model School {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
name String @db.VarChar(100)
|
|
regionCode String @map("region_code") @db.VarChar(20)
|
|
address String? @db.VarChar(200)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
grades Grade[]
|
|
|
|
@@index([regionCode])
|
|
@@map("schools")
|
|
}
|
|
|
|
model Grade {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
schoolId String @map("school_id") @db.VarChar(36)
|
|
name String @db.VarChar(50)
|
|
sortOrder Int @map("sort_order")
|
|
enrollmentYear Int @map("enrollment_year")
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
school School @relation(fields: [schoolId], references: [id])
|
|
classes Class[]
|
|
|
|
@@index([schoolId])
|
|
@@index([enrollmentYear])
|
|
@@map("grades")
|
|
}
|
|
|
|
model Class {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
gradeId String @map("grade_id") @db.VarChar(36)
|
|
name String @db.VarChar(50)
|
|
inviteCode String @unique @map("invite_code") @db.VarChar(10)
|
|
headTeacherId String? @map("head_teacher_id") @db.VarChar(36)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
grade Grade @relation(fields: [gradeId], references: [id])
|
|
members ClassMember[]
|
|
assignments Assignment[]
|
|
schedules Schedule[]
|
|
|
|
@@index([gradeId])
|
|
@@map("classes")
|
|
}
|
|
|
|
model ClassMember {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
classId String @map("class_id") @db.VarChar(36)
|
|
userId String @map("user_id") @db.VarChar(36)
|
|
roleInClass ClassRole @map("role_in_class") @default(Student)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
user ApplicationUser @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([classId, userId])
|
|
@@index([userId])
|
|
@@map("class_members")
|
|
}
|
|
|
|
enum ClassRole {
|
|
Student
|
|
Monitor
|
|
Committee
|
|
Teacher
|
|
}
|
|
|
|
// =============================================
|
|
// 教材与知识图谱模块
|
|
// =============================================
|
|
|
|
model Subject {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
name String @db.VarChar(50)
|
|
code String @unique @db.VarChar(20)
|
|
icon String? @db.VarChar(50)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
textbooks Textbook[]
|
|
questions Question[]
|
|
exams Exam[]
|
|
|
|
@@map("subjects")
|
|
}
|
|
|
|
model Textbook {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
subjectId String @map("subject_id") @db.VarChar(36)
|
|
name String @db.VarChar(100)
|
|
publisher String @db.VarChar(100)
|
|
versionYear String @map("version_year") @db.VarChar(20)
|
|
coverUrl String? @map("cover_url") @db.VarChar(500)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
subject Subject @relation(fields: [subjectId], references: [id])
|
|
units TextbookUnit[]
|
|
|
|
@@index([subjectId])
|
|
@@map("textbooks")
|
|
}
|
|
|
|
model TextbookUnit {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
textbookId String @map("textbook_id") @db.VarChar(36)
|
|
name String @db.VarChar(100)
|
|
sortOrder Int @map("sort_order")
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
textbook Textbook @relation(fields: [textbookId], references: [id], onDelete: Cascade)
|
|
lessons TextbookLesson[]
|
|
|
|
@@index([textbookId])
|
|
@@index([sortOrder])
|
|
@@map("textbook_units")
|
|
}
|
|
|
|
model TextbookLesson {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
unitId String @map("unit_id") @db.VarChar(36)
|
|
name String @db.VarChar(100)
|
|
sortOrder Int @map("sort_order")
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
unit TextbookUnit @relation(fields: [unitId], references: [id], onDelete: Cascade)
|
|
knowledgePoints KnowledgePoint[]
|
|
|
|
@@index([unitId])
|
|
@@index([sortOrder])
|
|
@@map("textbook_lessons")
|
|
}
|
|
|
|
model KnowledgePoint {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
lessonId String @map("lesson_id") @db.VarChar(36)
|
|
parentKnowledgePointId String? @map("parent_knowledge_point_id") @db.VarChar(36)
|
|
name String @db.VarChar(200)
|
|
difficulty Int
|
|
description String? @db.Text
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
lesson TextbookLesson @relation(fields: [lessonId], references: [id], onDelete: Cascade)
|
|
parentKnowledgePoint KnowledgePoint? @relation("KnowledgePointHierarchy", fields: [parentKnowledgePointId], references: [id], onDelete: Cascade)
|
|
childKnowledgePoints KnowledgePoint[] @relation("KnowledgePointHierarchy")
|
|
questionAssociations QuestionKnowledge[]
|
|
|
|
@@index([lessonId])
|
|
@@index([parentKnowledgePointId])
|
|
@@index([difficulty])
|
|
@@map("knowledge_points")
|
|
}
|
|
|
|
// =============================================
|
|
// 题库资源模块
|
|
// =============================================
|
|
|
|
model Question {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
subjectId String @map("subject_id") @db.VarChar(36)
|
|
content String @db.Text
|
|
optionsConfig Json? @map("options_config")
|
|
questionType QuestionType @map("question_type")
|
|
answer String @db.Text
|
|
explanation String? @db.Text
|
|
difficulty Int @default(3)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
subject Subject @relation(fields: [subjectId], references: [id])
|
|
creator ApplicationUser @relation("CreatedQuestions", fields: [createdBy], references: [id])
|
|
knowledgePoints QuestionKnowledge[]
|
|
examNodes ExamNode[]
|
|
|
|
@@index([subjectId])
|
|
@@index([questionType])
|
|
@@index([difficulty])
|
|
@@fulltext([content])
|
|
@@map("questions")
|
|
}
|
|
|
|
model QuestionKnowledge {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
questionId String @map("question_id") @db.VarChar(36)
|
|
knowledgePointId String @map("knowledge_point_id") @db.VarChar(36)
|
|
weight Int @default(100)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
question Question @relation(fields: [questionId], references: [id], onDelete: Cascade)
|
|
knowledgePoint KnowledgePoint @relation(fields: [knowledgePointId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([questionId, knowledgePointId])
|
|
@@index([knowledgePointId])
|
|
@@map("question_knowledge")
|
|
}
|
|
|
|
enum QuestionType {
|
|
SingleChoice
|
|
MultipleChoice
|
|
TrueFalse
|
|
FillBlank
|
|
Subjective
|
|
}
|
|
|
|
// =============================================
|
|
// 试卷工程模块
|
|
// =============================================
|
|
|
|
model Exam {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
subjectId String @map("subject_id") @db.VarChar(36)
|
|
title String @db.VarChar(200)
|
|
totalScore Decimal @map("total_score") @default(0) @db.Decimal(5, 1)
|
|
suggestedDuration Int @map("suggested_duration")
|
|
status ExamStatus @default(Draft)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
subject Subject @relation(fields: [subjectId], references: [id])
|
|
creator ApplicationUser @relation("CreatedExams", fields: [createdBy], references: [id])
|
|
nodes ExamNode[]
|
|
assignments Assignment[]
|
|
|
|
@@index([subjectId])
|
|
@@index([status])
|
|
@@index([createdBy])
|
|
@@map("exams")
|
|
}
|
|
|
|
model ExamNode {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
examId String @map("exam_id") @db.VarChar(36)
|
|
parentNodeId String? @map("parent_node_id") @db.VarChar(36)
|
|
nodeType NodeType @map("node_type")
|
|
questionId String? @map("question_id") @db.VarChar(36)
|
|
title String? @db.VarChar(200)
|
|
description String? @db.Text
|
|
score Decimal @db.Decimal(5, 1)
|
|
sortOrder Int @map("sort_order")
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
exam Exam @relation(fields: [examId], references: [id], onDelete: Cascade)
|
|
parentNode ExamNode? @relation("ExamNodeHierarchy", fields: [parentNodeId], references: [id], onDelete: Cascade)
|
|
childNodes ExamNode[] @relation("ExamNodeHierarchy")
|
|
question Question? @relation(fields: [questionId], references: [id])
|
|
submissionDetails SubmissionDetail[]
|
|
|
|
@@index([examId])
|
|
@@index([parentNodeId])
|
|
@@index([sortOrder])
|
|
@@index([questionId])
|
|
@@map("exam_nodes")
|
|
}
|
|
|
|
enum ExamStatus {
|
|
Draft
|
|
Published
|
|
}
|
|
|
|
enum NodeType {
|
|
Group
|
|
Question
|
|
}
|
|
|
|
// =============================================
|
|
// 教学执行模块
|
|
// =============================================
|
|
|
|
model Assignment {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
examId String @map("exam_id") @db.VarChar(36)
|
|
classId String @map("class_id") @db.VarChar(36)
|
|
title String @db.VarChar(200)
|
|
startTime DateTime @map("start_time")
|
|
endTime DateTime @map("end_time")
|
|
allowLateSubmission Boolean @map("allow_late_submission") @default(false)
|
|
autoScoreEnabled Boolean @map("auto_score_enabled") @default(true)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
exam Exam @relation(fields: [examId], references: [id])
|
|
class Class @relation(fields: [classId], references: [id])
|
|
submissions StudentSubmission[]
|
|
|
|
@@index([examId])
|
|
@@index([classId])
|
|
@@index([startTime])
|
|
@@index([endTime])
|
|
@@map("assignments")
|
|
}
|
|
|
|
model StudentSubmission {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
assignmentId String @map("assignment_id") @db.VarChar(36)
|
|
studentId String @map("student_id") @db.VarChar(36)
|
|
submissionStatus SubmissionStatus @map("submission_status") @default(Pending)
|
|
submitTime DateTime? @map("submit_time")
|
|
timeSpentSeconds Int? @map("time_spent_seconds")
|
|
totalScore Decimal? @map("total_score") @db.Decimal(5, 1)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
assignment Assignment @relation(fields: [assignmentId], references: [id], onDelete: Cascade)
|
|
student ApplicationUser @relation(fields: [studentId], references: [id], onDelete: Cascade)
|
|
details SubmissionDetail[]
|
|
|
|
@@unique([assignmentId, studentId])
|
|
@@index([studentId])
|
|
@@index([submitTime])
|
|
@@index([submissionStatus])
|
|
@@map("student_submissions")
|
|
}
|
|
|
|
model SubmissionDetail {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
submissionId String @map("submission_id") @db.VarChar(36)
|
|
examNodeId String @map("exam_node_id") @db.VarChar(36)
|
|
studentAnswer String? @map("student_answer") @db.Text
|
|
gradingData Json? @map("grading_data")
|
|
score Decimal? @db.Decimal(5, 1)
|
|
judgement JudgementResult?
|
|
teacherComment String? @map("teacher_comment") @db.Text
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
createdBy String @map("created_by") @db.VarChar(36)
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
updatedBy String @map("updated_by") @db.VarChar(36)
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
|
|
submission StudentSubmission @relation(fields: [submissionId], references: [id], onDelete: Cascade)
|
|
examNode ExamNode @relation(fields: [examNodeId], references: [id])
|
|
|
|
@@unique([submissionId, examNodeId])
|
|
@@index([examNodeId])
|
|
@@index([judgement])
|
|
@@map("submission_details")
|
|
}
|
|
|
|
enum SubmissionStatus {
|
|
Pending
|
|
Submitted
|
|
Grading
|
|
Graded
|
|
}
|
|
|
|
enum JudgementResult {
|
|
Correct
|
|
Incorrect
|
|
Partial
|
|
}
|
|
|
|
// =============================================
|
|
// 辅助功能模块
|
|
// =============================================
|
|
|
|
model Message {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
userId String @map("user_id") @db.VarChar(36)
|
|
title String @db.VarChar(200)
|
|
content String @db.Text
|
|
type String @db.VarChar(20) // Announcement, Notification, Alert
|
|
senderName String @map("sender_name") @db.VarChar(50)
|
|
isRead Boolean @default(false) @map("is_read")
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
user ApplicationUser @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@map("messages")
|
|
}
|
|
|
|
model Schedule {
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
classId String @map("class_id") @db.VarChar(36)
|
|
subject String @db.VarChar(50)
|
|
room String? @db.VarChar(50)
|
|
dayOfWeek Int @map("day_of_week") // 1-7
|
|
period Int // 1-8
|
|
startTime String @map("start_time") @db.VarChar(10) // HH:mm
|
|
endTime String @map("end_time") @db.VarChar(10) // HH:mm
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([classId])
|
|
@@map("schedules")
|
|
}
|