484 lines
19 KiB
Plaintext
484 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"
|
||
}
|
||
|
||
// generator zod {
|
||
// provider = "zod-prisma-types"
|
||
// output = "../src/generated" // (default) the directory where generated zod schemas will be saved
|
||
// createModelTypes = true
|
||
// createRelationValuesTypes = true
|
||
// writeNullishInModelTypes = true
|
||
// createPartialTypes = false
|
||
// useMultipleFiles = false
|
||
// useTypeAssertions = true
|
||
// }
|
||
|
||
datasource db {
|
||
provider = "postgresql"
|
||
url = env("DATABASE_URL")
|
||
}
|
||
|
||
model Taxonomy {
|
||
id String @id @default(cuid())
|
||
name String @unique
|
||
slug String @unique @map("slug")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
terms Term[]
|
||
objectType String[] @map("object_type")
|
||
order Float? @map("order")
|
||
|
||
@@index([order, deletedAt])
|
||
@@map("taxonomy")
|
||
}
|
||
|
||
model Term {
|
||
id String @id @default(cuid())
|
||
name String
|
||
taxonomy Taxonomy? @relation(fields: [taxonomyId], references: [id])
|
||
taxonomyId String? @map("taxonomy_id")
|
||
order Float? @map("order")
|
||
description String?
|
||
parentId String? @map("parent_id")
|
||
parent Term? @relation("ChildParent", fields: [parentId], references: [id], onDelete: Cascade)
|
||
children Term[] @relation("ChildParent")
|
||
ancestors TermAncestry[] @relation("DescendantToAncestor")
|
||
descendants TermAncestry[] @relation("AncestorToDescendant")
|
||
domainId String? @map("domain_id")
|
||
domain Department? @relation("TermDom", fields: [domainId], references: [id])
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
createdBy String? @map("created_by")
|
||
depts Department[] @relation("department_term")
|
||
hasChildren Boolean? @default(false) @map("has_children")
|
||
courses Course[] @relation("course_term")
|
||
|
||
@@index([name]) // 对name字段建立索引,以加快基于name的查找速度
|
||
@@index([parentId]) // 对parentId字段建立索引,以加快基于parentId的查找速度
|
||
@@map("term")
|
||
}
|
||
|
||
model TermAncestry {
|
||
id String @id @default(cuid())
|
||
ancestorId String? @map("ancestor_id")
|
||
descendantId String @map("descendant_id")
|
||
relDepth Int @map("rel_depth")
|
||
ancestor Term? @relation("AncestorToDescendant", fields: [ancestorId], references: [id])
|
||
descendant Term @relation("DescendantToAncestor", fields: [descendantId], references: [id])
|
||
|
||
// 索引建议
|
||
@@index([ancestorId]) // 针对祖先的查询
|
||
@@index([descendantId]) // 针对后代的查询
|
||
@@index([ancestorId, descendantId]) // 组合索引,用于查询特定的祖先-后代关系
|
||
@@index([relDepth]) // 根据关系深度的查询
|
||
@@map("term_ancestry")
|
||
}
|
||
|
||
model Staff {
|
||
id String @id @default(cuid())
|
||
showname String? @map("showname")
|
||
username String @unique @map("username")
|
||
avatar String? @map("avatar")
|
||
password String? @map("password")
|
||
phoneNumber String? @unique @map("phone_number")
|
||
|
||
domainId String? @map("domain_id")
|
||
deptId String? @map("dept_id")
|
||
|
||
domain Department? @relation("DomainStaff", fields: [domainId], references: [id])
|
||
department Department? @relation("DeptStaff", fields: [deptId], references: [id])
|
||
order Float?
|
||
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
enabled Boolean? @default(true)
|
||
deletedAt DateTime? @map("deleted_at")
|
||
officerId String? @map("officer_id")
|
||
|
||
watchedPost Post[] @relation("post_watch_staff")
|
||
visits Visit[]
|
||
posts Post[]
|
||
sentMsgs Message[] @relation("message_sender")
|
||
receivedMsgs Message[] @relation("message_receiver")
|
||
registerToken String?
|
||
enrollments Enrollment[]
|
||
teachedCourses CourseInstructor[]
|
||
|
||
@@index([officerId])
|
||
@@index([deptId])
|
||
@@index([domainId])
|
||
@@index([username])
|
||
@@index([order])
|
||
@@map("staff")
|
||
}
|
||
|
||
model Department {
|
||
id String @id @default(cuid())
|
||
name String
|
||
order Float?
|
||
ancestors DeptAncestry[] @relation("DescendantToAncestor")
|
||
descendants DeptAncestry[] @relation("AncestorToDescendant")
|
||
parentId String? @map("parent_id")
|
||
parent Department? @relation("ChildParent", fields: [parentId], references: [id])
|
||
children Department[] @relation("ChildParent")
|
||
domainId String? @map("domain_id")
|
||
domainTerms Term[] @relation("TermDom")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
isDomain Boolean? @default(false) @map("is_domain")
|
||
domainStaffs Staff[] @relation("DomainStaff")
|
||
deptStaffs Staff[] @relation("DeptStaff")
|
||
terms Term[] @relation("department_term")
|
||
|
||
watchedPost Post[] @relation("post_watch_dept")
|
||
hasChildren Boolean? @default(false) @map("has_children")
|
||
|
||
@@index([parentId])
|
||
@@index([isDomain])
|
||
@@index([name])
|
||
@@index([order])
|
||
@@map("department")
|
||
}
|
||
|
||
model DeptAncestry {
|
||
id String @id @default(cuid())
|
||
ancestorId String? @map("ancestor_id")
|
||
descendantId String @map("descendant_id")
|
||
relDepth Int @map("rel_depth")
|
||
ancestor Department? @relation("AncestorToDescendant", fields: [ancestorId], references: [id])
|
||
descendant Department @relation("DescendantToAncestor", fields: [descendantId], references: [id])
|
||
|
||
// 索引建议
|
||
@@index([ancestorId]) // 针对祖先的查询
|
||
@@index([descendantId]) // 针对后代的查询
|
||
@@index([ancestorId, descendantId]) // 组合索引,用于查询特定的祖先-后代关系
|
||
@@index([relDepth]) // 根据关系深度的查询
|
||
@@map("dept_ancestry")
|
||
}
|
||
|
||
model RoleMap {
|
||
id String @id @default(cuid())
|
||
objectId String @map("object_id")
|
||
roleId String @map("role_id")
|
||
domainId String? @map("domain_id")
|
||
objectType String @map("object_type")
|
||
role Role @relation(fields: [roleId], references: [id])
|
||
|
||
@@index([domainId])
|
||
@@index([objectId])
|
||
@@map("rolemap")
|
||
}
|
||
|
||
model Role {
|
||
id String @id @default(cuid())
|
||
name String @unique @map("name")
|
||
permissions String[] @default([]) @map("permissions")
|
||
roleMaps RoleMap[]
|
||
system Boolean? @default(false) @map("system")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
@@map("role")
|
||
}
|
||
|
||
model AppConfig {
|
||
id String @id @default(cuid())
|
||
slug String @unique
|
||
title String?
|
||
description String?
|
||
meta Json?
|
||
|
||
@@map("app_config")
|
||
}
|
||
|
||
model Post {
|
||
// 字符串类型字段
|
||
id String @id @default(cuid()) // 帖子唯一标识,使用 cuid() 生成默认值
|
||
type String? // 帖子类型,可为空
|
||
title String? // 帖子标题,可为空
|
||
content String? // 帖子内容,可为空
|
||
domainId String? @map("domain_id")
|
||
// 日期时间类型字段
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at") // 删除时间,可为空
|
||
|
||
// 整数类型字段
|
||
rating Int // 评分(1-5星)
|
||
|
||
// 关系类型字段
|
||
authorId String? @map("author_id")
|
||
author Staff? @relation(fields: [authorId], references: [id]) // 帖子作者,关联 Staff 模型
|
||
|
||
visits Visit[] // 访问记录,关联 Visit 模型
|
||
|
||
courseId String @map("course_id")
|
||
course Course @relation(fields: [courseId], references: [id]) // 关联课程,关联 Course 模型
|
||
|
||
parentId String? @map("parent_id")
|
||
parent Post? @relation("PostChildren", fields: [parentId], references: [id]) // 父级帖子,关联 Post 模型
|
||
children Post[] @relation("PostChildren") // 子级帖子列表,关联 Post 模型
|
||
|
||
lectureId String? @map("lecture_id")
|
||
lecture Lecture? @relation(fields: [lectureId], references: [id]) // 关联讲座,关联 Lecture 模型
|
||
resources Resource[] // 附件列表
|
||
|
||
watchableStaffs Staff[] @relation("post_watch_staff") // 可观看的员工列表,关联 Staff 模型
|
||
watchableDepts Department[] @relation("post_watch_dept") // 可观看的部门列表,关联 Department 模型
|
||
|
||
// 复合索引
|
||
@@index([type, domainId]) // 类型和域组合查询
|
||
@@index([authorId, type]) // 作者和类型组合查询
|
||
@@index([parentId, type]) // 父级帖子和创建时间索引
|
||
// 时间相关索引
|
||
@@index([createdAt]) // 按创建时间倒序索引
|
||
@@index([updatedAt]) // 按更新时间倒序索引
|
||
}
|
||
|
||
model Message {
|
||
id String @id @default(cuid())
|
||
url String?
|
||
intent String?
|
||
option Json?
|
||
senderId String? @map("sender_id")
|
||
type String?
|
||
sender Staff? @relation(name: "message_sender", fields: [senderId], references: [id])
|
||
title String?
|
||
content String?
|
||
receivers Staff[] @relation("message_receiver")
|
||
visits Visit[]
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime? @updatedAt @map("updated_at")
|
||
|
||
@@index([type, createdAt])
|
||
@@map("message")
|
||
}
|
||
|
||
model Visit {
|
||
id String @id @default(cuid()) @map("id")
|
||
type String?
|
||
views Int @default(1) @map("views")
|
||
sourceIP String? @map("source_ip")
|
||
// 关联关系
|
||
visitorId String @map("visitor_id")
|
||
visitor Staff @relation(fields: [visitorId], references: [id])
|
||
postId String? @map("post_id")
|
||
post Post? @relation(fields: [postId], references: [id])
|
||
message Message? @relation(fields: [messageId], references: [id])
|
||
messageId String? @map("message_id")
|
||
enrollment Enrollment? @relation(fields: [enrollmentId], references: [id], onDelete: Cascade)
|
||
enrollmentId String? @map("enrollment_id") // 报名记录ID
|
||
lecture Lecture? @relation(fields: [lectureId], references: [id], onDelete: Cascade)
|
||
lectureId String? @map("lecture_id") // 课时ID
|
||
|
||
// 学习数据
|
||
progress Float? @default(0) @map("progress") // 完成进度(0-100%)
|
||
isCompleted Boolean? @default(false) @map("is_completed") // 是否完成
|
||
lastPosition Int? @default(0) @map("last_position") // 视频播放位置(秒)
|
||
totalWatchTime Int? @default(0) @map("total_watch_time") // 总观看时长(秒)
|
||
// 时间记录
|
||
lastWatchedAt DateTime? @map("last_watched_at") // 最后观看时间
|
||
createdAt DateTime @default(now()) @map("created_at") // 创建时间
|
||
updatedAt DateTime @updatedAt @map("updated_at") // 更新时间
|
||
|
||
@@unique([enrollmentId, lectureId]) // 确保每个报名只有一条课时进度
|
||
@@index([isCompleted]) // 完成状态索引
|
||
@@index([lastWatchedAt]) // 最后观看时间索引
|
||
@@index([postId, type, visitorId])
|
||
@@index([messageId, type, visitorId])
|
||
@@map("visit")
|
||
}
|
||
|
||
model Course {
|
||
id String @id @default(cuid()) @map("id") // 课程唯一标识符
|
||
title String? @map("title") // 课程标题
|
||
subTitle String? @map("sub_title") // 课程副标题(可选)
|
||
description String? @map("description") // 课程详细描述
|
||
thumbnail String? @map("thumbnail") // 课程封面图片URL(可选)
|
||
level String? @map("level") // 课程难度等级
|
||
|
||
// 课程内容组织结构
|
||
terms Term[] @relation("course_term") // 课程学期
|
||
instructors CourseInstructor[] // 课程讲师团队
|
||
sections Section[] // 课程章节结构
|
||
enrollments Enrollment[] // 学生报名记录
|
||
reviews Post[] // 学员课程评价
|
||
|
||
// 课程规划与目标设定
|
||
requirements String[] @map("requirements") // 课程学习前置要求
|
||
objectives String[] @map("objectives") // 具体的学习目标
|
||
skills String[] @map("skills") // 课程结束后可掌握的技能
|
||
audiences String[] @map("audiences") // 目标受众群体描述
|
||
|
||
// 课程统计指标
|
||
totalDuration Int? @default(0) @map("total_duration") // 课程总时长(分钟)
|
||
totalLectures Int? @default(0) @map("total_lectures") // 总课时数
|
||
averageRating Float? @default(0) @map("average_rating") // 平均评分(1-5分)
|
||
numberOfReviews Int? @default(0) @map("number_of_reviews") // 评价总数
|
||
numberOfStudents Int? @default(0) @map("number_of_students") // 学习人数
|
||
completionRate Float? @default(0) @map("completion_rate") // 完课率(0-100%)
|
||
|
||
// 课程状态管理
|
||
status String? @map("status") // 课程状态(如:草稿/已发布/已归档)
|
||
isFeatured Boolean? @default(false) @map("is_featured") // 是否为精选推荐课程
|
||
|
||
// 生命周期时间戳
|
||
createdAt DateTime? @default(now()) @map("created_at") // 创建时间
|
||
updatedAt DateTime? @updatedAt @map("updated_at") // 最后更新时间
|
||
publishedAt DateTime? @map("published_at") // 发布时间
|
||
archivedAt DateTime? @map("archived_at") // 归档时间
|
||
deletedAt DateTime? @map("deleted_at") // 软删除时间
|
||
|
||
// 数据库索引优化
|
||
@@index([status]) // 课程状态索引,用于快速筛选
|
||
@@index([level]) // 难度等级索引,用于分类查询
|
||
@@index([isFeatured]) // 精选标记索引,用于首页推荐
|
||
@@map("course")
|
||
}
|
||
|
||
model Section {
|
||
id String @id @default(cuid()) @map("id")
|
||
title String @map("title")
|
||
description String? @map("description")
|
||
objectives String[] @map("objectives")
|
||
order Float? @default(0) @map("order")
|
||
totalDuration Int @default(0) @map("total_duration")
|
||
totalLectures Int @default(0) @map("total_lectures")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
// 关联关系
|
||
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
|
||
courseId String @map("course_id")
|
||
lectures Lecture[]
|
||
|
||
@@index([courseId, order])
|
||
@@map("section")
|
||
}
|
||
|
||
model Lecture {
|
||
id String @id @default(cuid()) @map("id")
|
||
title String @map("title")
|
||
description String? @map("description")
|
||
order Float? @default(0) @map("order")
|
||
duration Int @map("duration")
|
||
type String @map("type")
|
||
content String? @map("content")
|
||
videoUrl String? @map("video_url")
|
||
videoThumbnail String? @map("video_thumbnail")
|
||
publishedAt DateTime? @map("published_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
// 关联关系
|
||
resources Resource[]
|
||
section Section @relation(fields: [sectionId], references: [id], onDelete: Cascade)
|
||
sectionId String @map("section_id")
|
||
comments Post[]
|
||
visits Visit[]
|
||
|
||
@@index([sectionId, order])
|
||
@@index([type, publishedAt])
|
||
@@map("lecture")
|
||
}
|
||
|
||
model Enrollment {
|
||
id String @id @default(cuid()) @map("id")
|
||
status String @map("status")
|
||
completionRate Float @default(0) @map("completion_rate")
|
||
|
||
lastAccessedAt DateTime? @map("last_accessed_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
completedAt DateTime? @map("completed_at")
|
||
|
||
// 关联关系
|
||
student Staff @relation(fields: [studentId], references: [id])
|
||
studentId String @map("student_id")
|
||
course Course @relation(fields: [courseId], references: [id])
|
||
courseId String @map("course_id")
|
||
visits Visit[]
|
||
|
||
@@unique([studentId, courseId])
|
||
@@index([status])
|
||
@@index([completedAt])
|
||
@@map("enrollment")
|
||
}
|
||
|
||
model CourseInstructor {
|
||
courseId String @map("course_id")
|
||
instructorId String @map("instructor_id")
|
||
role String @map("role")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
order Float? @default(0) @map("order")
|
||
|
||
course Course @relation(fields: [courseId], references: [id])
|
||
instructor Staff @relation(fields: [instructorId], references: [id])
|
||
|
||
@@id([courseId, instructorId])
|
||
@@map("course_instructor")
|
||
}
|
||
|
||
model Resource {
|
||
id String @id @default(cuid()) @map("id")
|
||
title String @map("title")
|
||
description String? @map("description")
|
||
type String @map("type")
|
||
url String @map("url")
|
||
fileType String? @map("file_type")
|
||
fileSize Int? @map("file_size")
|
||
downloadCount Int @default(0) @map("download_count")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
lectures Lecture[]
|
||
posts Post[]
|
||
|
||
@@index([type])
|
||
@@map("resource")
|
||
}
|
||
|
||
model Node {
|
||
id String @id @default(cuid()) @map("id")
|
||
title String @map("title")
|
||
description String? @map("description")
|
||
type String @map("type")
|
||
style Json? @map("style")
|
||
position Json? @map("position")
|
||
data Json? @map("data")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// 关联关系
|
||
sourceEdges NodeEdge[] @relation("source_node")
|
||
targetEdges NodeEdge[] @relation("target_node")
|
||
|
||
@@map("node")
|
||
}
|
||
|
||
model NodeEdge {
|
||
id String @id @default(cuid()) @map("id")
|
||
type String? @map("type")
|
||
label String? @map("label")
|
||
description String? @map("description")
|
||
style Json? @map("style")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
source Node @relation("source_node", fields: [sourceId], references: [id], onDelete: Cascade)
|
||
sourceId String @map("source_id")
|
||
target Node @relation("target_node", fields: [targetId], references: [id], onDelete: Cascade)
|
||
targetId String @map("target_id")
|
||
|
||
@@unique([sourceId, targetId, type])
|
||
@@index([sourceId])
|
||
@@index([targetId])
|
||
@@map("node_edge")
|
||
}
|