// 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" } 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") posts Post[] @relation("post_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 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? // Post类型,课程、章节、小节、讨论都用Post实现 level String? state String? title String? // 帖子标题,可为空 subTitle String? content String? // 帖子内容,可为空 important Boolean? //是否重要/精选/突出 domainId String? @map("domain_id") terms Term[] @relation("post_term") order Float? @default(0) @map("order") duration Int? rating Int? @default(0) students Staff[] @relation("post_student") depts Department[] @relation("post_dept") views Int @default(0) @map("views") hates Int @default(0) @map("hates") likes Int @default(0) @map("likes") // 索引 // 日期时间类型字段 createdAt DateTime @default(now()) @map("created_at") publishedAt DateTime? @map("published_at") // 发布时间 updatedAt DateTime @map("updated_at") deletedAt DateTime? @map("deleted_at") // 删除时间,可为空 instructors PostInstructor[] // 关系类型字段 authorId String? @map("author_id") author Staff? @relation(fields: [authorId], references: [id]) // 帖子作者,关联 Staff 模型 enrollments Enrollment[] // 学生报名记录 visits Visit[] // 访问记录,关联 Visit 模型 parentId String? @map("parent_id") parent Post? @relation("PostChildren", fields: [parentId], references: [id]) // 父级帖子,关联 Post 模型 children Post[] @relation("PostChildren") // 子级帖子列表,关联 Post 模型 hasChildren Boolean? @default(false) @map("has_children") // 闭包表关系 ancestors PostAncestry[] @relation("DescendantPosts") descendants PostAncestry[] @relation("AncestorPosts") resources Resource[] // 附件列表 meta Json? // 封面url 视频url objectives具体的学习目标 rating评分Int // 索引 @@index([type, domainId]) @@index([authorId, type]) @@index([parentId, type]) @@index([parentId, order]) @@index([createdAt]) @@index([updatedAt]) @@index([type, publishedAt]) @@index([state]) @@index([level]) @@index([views]) @@index([important]) @@map("post") } model PostAncestry { id String @id @default(cuid()) ancestorId String? @map("ancestor_id") descendantId String @map("descendant_id") relDepth Int @map("rel_depth") ancestor Post? @relation("AncestorPosts", fields: [ancestorId], references: [id]) descendant Post @relation("DescendantPosts", fields: [descendantId], references: [id]) // 复合索引优化 // 索引建议 @@index([ancestorId]) // 针对祖先的查询 @@index([descendantId]) // 针对后代的查询 @@index([ancestorId, descendantId]) // 组合索引,用于查询特定的祖先-后代关系 @@index([relDepth]) // 根据关系深度的查询 @@map("post_ancestry") } 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") lectureId String? @map("lecture_id") // 课时ID createdAt DateTime @default(now()) @map("created_at") // 创建时间 updatedAt DateTime @updatedAt @map("updated_at") // 更新时间 deletedAt DateTime? @map("deleted_at") // 删除时间,可为空 meta Json? @@index([postId, type, visitorId]) @@index([messageId, type, visitorId]) @@map("visit") } model Enrollment { id String @id @default(cuid()) @map("id") status String @map("status") completionRate Float @default(0) @map("completion_rate") 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") post Post @relation(fields: [postId], references: [id]) postId String @map("post_id") @@unique([studentId, postId]) @@index([status]) @@index([completedAt]) @@map("enrollment") } model PostInstructor { postId String @map("post_id") instructorId String @map("instructor_id") role String @map("role") createdAt DateTime @default(now()) @map("created_at") order Float? @default(0) @map("order") post Post @relation(fields: [postId], references: [id]) instructor Staff @relation(fields: [instructorId], references: [id]) @@id([postId, instructorId]) @@map("post_instructor") } model Resource { id String @id @default(cuid()) @map("id") title String? @map("title") description String? @map("description") type String? @map("type") fileId String? @unique url String? // 元数据 meta Json? @map("meta") // 处理状态控制 status String? createdAt DateTime? @default(now()) @map("created_at") updatedAt DateTime? @updatedAt @map("updated_at") createdBy String? @map("created_by") updatedBy String? @map("updated_by") deletedAt DateTime? @map("deleted_at") isPublic Boolean? @default(true) @map("is_public") owner Staff? @relation(fields: [ownerId], references: [id]) ownerId String? @map("owner_id") post Post? @relation(fields: [postId], references: [id]) postId String? @map("post_id") // 索引 @@index([type]) @@index([createdAt]) @@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") } model TrainContent { id String @id @default(cuid()) title String @map("title") trainSituations TrainSituation[] trainPlans TrainPlan[] @relation("TrainPlanContent") type String @map("type") parentId String? @map("parent_id") parent TrainContent? @relation("ContentParent", fields: [parentId], references: [id]) // 指向自身 children TrainContent[] @relation("ContentParent") // 指向自身 deletedAt DateTime? @map("deleted_at") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("train_content") } model TrainSituation { id String @id @default(cuid()) staffId String @map("staff_id") staff Staff @relation(fields: [staffId], references: [id]) trainContentId String @map("train_content_id") trainContent TrainContent @relation(fields: [trainContentId], references: [id]) score Float @default(0.0) @map("score") mustTrainTime Float @map("must_train_time") alreadyTrainTime Float @map("already_train_time") dailyTrainTime DailyTrainTime[] @relation("DailyTrainSituation") @@map("train_situation") } model DailyTrainTime { id String @id @default(cuid()) trainSituationId String @map("train_situatio_id") trainSituation TrainSituation @relation("DailyTrainSituation", fields: [trainSituationId], references: [id]) trainTime Float @default(0.0) @map("trainTime") createdAt DateTime @default(now()) @map("created_at") @@map("daily_train_situation") } model Position { id String @id @default(cuid()) @map("id") type String @map("type") staff Staff[] @relation("StaffPosition") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("position") } model Department { id String @id @default(cuid()) name String order Float? posts Post[] @relation("post_dept") 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") trainPlans TrainPlan[] @relation("TrainPlanDept") // watchedPost Post[] @relation("post_watch_dept") hasChildren Boolean? @default(false) @map("has_children") logs SystemLog[] @@index([parentId]) @@index([isDomain]) @@index([name]) @@index([order]) @@map("department") } model StaffField { id String @id @default(cuid()) name String @unique // 字段名称 label String? // 字段显示名称 type String // 字段类型 (text, number, date, select 等) required Boolean? @default(false) order Float? // 显示顺序 options Json? // 对于选择类型字段的可选值 group String? // 字段分组 (基本信息、工作信息等) createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") deletedAt DateTime? @map("deleted_at") StaffFieldValue StaffFieldValue[] @relation("StaffFieldToValue") // 添加级联删除 @@index([group]) @@index([order]) @@map("staff_field") } model StaffFieldValue { id String @id @default(cuid()) staffId String @map("staff_id") fieldId String @map("field_id") value String? // 字段值 staff Staff @relation(fields: [staffId], references: [id]) field StaffField @relation("StaffFieldToValue",fields: [fieldId], references: [id], onDelete: Cascade) // 添加级联删除 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@unique([staffId, fieldId]) @@index([staffId]) @@index([fieldId]) @@map("staff_field_value") } model Staff { // 基础信息 id String @id @default(cuid()) username String? @unique @map("username") password String? @map("password") showname String? @map("showname") avatar String? @map("avatar") enabled Boolean? @default(true) officerId String? @map("officer_id") phoneNumber String? @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? // 关联关系 trainSituations TrainSituation[] visits Visit[] posts Post[] learningPosts Post[] @relation("post_student") sentMsgs Message[] @relation("message_sender") receivedMsgs Message[] @relation("message_receiver") enrollments Enrollment[] teachedPosts PostInstructor[] ownedResources Resource[] position Position? @relation("StaffPosition", fields: [positionId], references: [id]) positionId String? @map("position_id") // 系统信息 registerToken String? createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") deletedAt DateTime? @map("deleted_at") absent Boolean? @default(false) @map("absent") // 系统日志 logs SystemLog[] @relation("log_operator") // 添加自定义字段值关联 fieldValues StaffFieldValue[] @@index([officerId]) @@index([deptId]) @@index([domainId]) @@index([username]) @@index([order]) @@map("staff") } model TrainPlan { id String @id @default(cuid()) trainDate DateTime @map("train_date") trainTime DateTime @map("train_time") trainType String @map("train_type") trainContext String @map("train_context") trainContents TrainContent[] @relation("TrainPlanContent") departmentId String? @map("department_id") department Department? @relation("TrainPlanDept", fields: [departmentId], references: [id]) createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") deletedAt DateTime? @map("deleted_at") @@map("train_plan") } model ShareCode { id String @id @default(cuid()) code String? @unique fileId String? @unique createdAt DateTime @default(now()) expiresAt DateTime? @map("expires_at") isUsed Boolean? @default(false) fileName String? @map("file_name") @@index([code]) @@index([fileId]) @@index([expiresAt]) } model SystemLog { id String @id @default(cuid()) timestamp DateTime @default(now()) @map("timestamp") level String? @map("level") // info, warning, error, debug module String? @map("module") // 操作模块,如"人员管理" action String? @map("action") // 具体操作,如"新增人员"、"修改人员" // 操作人信息 operatorId String? @map("operator_id") operator Staff? @relation("log_operator", fields: [operatorId], references: [id]) ipAddress String? @map("ip_address") // 操作对象信息 targetId String? @map("target_id") // 操作对象ID targetType String? @map("target_type") // 操作对象类型,如"staff"、"department" targetName String? @map("target_name") // 操作对象名称 // 详细信息 details Json? @map("details") // 详细变更信息,存储为JSON beforeData Json? @map("before_data") // 操作前数据 afterData Json? @map("after_data") // 操作后数据 // 操作结果 status String? @map("status") // success, failure errorMessage String? @map("error_message") // 如果操作失败,记录错误信息 // 关联部门 departmentId String? @map("department_id") department Department? @relation(fields: [departmentId], references: [id]) // 优化索引 @@index([timestamp]) @@index([level]) @@index([module, action]) @@index([operatorId]) @@index([targetId, targetType]) @@index([status]) @@index([departmentId]) @@map("system_log") }