feat: Phase 1-3 全部完成 — 沙盒增强、学情分析、学习路径
This commit is contained in:
@@ -0,0 +1,511 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "mysql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum UserStatus {
|
||||
ACTIVE
|
||||
INACTIVE
|
||||
BANNED
|
||||
}
|
||||
|
||||
enum ContentStatus {
|
||||
DRAFT
|
||||
PUBLISHED
|
||||
ARCHIVED
|
||||
}
|
||||
|
||||
enum OrderStatus {
|
||||
PENDING
|
||||
PAID
|
||||
CANCELLED
|
||||
REFUNDED
|
||||
}
|
||||
|
||||
enum MemberPlan {
|
||||
FREE
|
||||
MONTHLY
|
||||
YEARLY
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
phone String? @unique
|
||||
email String? @unique
|
||||
passwordHash String?
|
||||
nickname String?
|
||||
avatar String?
|
||||
bio String?
|
||||
status UserStatus @default(ACTIVE)
|
||||
memberPlan MemberPlan @default(FREE)
|
||||
memberExpire DateTime?
|
||||
sandboxDaily Int @default(10)
|
||||
followerCount Int @default(0)
|
||||
followingCount Int @default(0)
|
||||
postCount Int @default(0)
|
||||
lastLoginAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
|
||||
learnRecords LearnRecord[]
|
||||
promptFavorites PromptFavorite[]
|
||||
prompts Prompt[]
|
||||
sandboxSessions SandboxSession[]
|
||||
orders Order[]
|
||||
subscriptions Subscription[]
|
||||
posts Post[]
|
||||
comments Comment[]
|
||||
postLikes PostLike[]
|
||||
followers Follow[] @relation("Following")
|
||||
following Follow[] @relation("Follower")
|
||||
createdCircles Circle[] @relation("CircleCreator")
|
||||
circleMemberships CircleMember[]
|
||||
organizationMemberships OrganizationMember[]
|
||||
notifications Notification[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
model Category {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
slug String @unique
|
||||
description String?
|
||||
sortOrder Int @default(0)
|
||||
parentId Int?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
parent Category? @relation("CategoryTree", fields: [parentId], references: [id])
|
||||
children Category[] @relation("CategoryTree")
|
||||
|
||||
courses Course[]
|
||||
prompts Prompt[]
|
||||
contents Content[]
|
||||
tools Tool[]
|
||||
|
||||
@@map("categories")
|
||||
}
|
||||
|
||||
model Course {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
description String?
|
||||
cover String?
|
||||
categoryId Int?
|
||||
price Float @default(0)
|
||||
isFree Boolean @default(true)
|
||||
status ContentStatus @default(DRAFT)
|
||||
sortOrder Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
|
||||
category Category? @relation(fields: [categoryId], references: [id])
|
||||
chapters Chapter[]
|
||||
progress LearnRecord[]
|
||||
assignments CourseAssignment[]
|
||||
|
||||
@@map("courses")
|
||||
}
|
||||
|
||||
model Chapter {
|
||||
id Int @id @default(autoincrement())
|
||||
courseId Int
|
||||
title String
|
||||
sortOrder Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
|
||||
lessons Lesson[]
|
||||
|
||||
@@map("chapters")
|
||||
}
|
||||
|
||||
model Lesson {
|
||||
id Int @id @default(autoincrement())
|
||||
chapterId Int
|
||||
title String
|
||||
content String?
|
||||
videoUrl String?
|
||||
duration Int?
|
||||
sortOrder Int @default(0)
|
||||
status ContentStatus @default(DRAFT)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
chapter Chapter @relation(fields: [chapterId], references: [id], onDelete: Cascade)
|
||||
progress LearnRecord[]
|
||||
|
||||
@@map("lessons")
|
||||
}
|
||||
|
||||
model LearnRecord {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
courseId Int
|
||||
lessonId Int
|
||||
completed Boolean @default(false)
|
||||
progress Float @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
|
||||
lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, lessonId])
|
||||
@@map("learn_records")
|
||||
}
|
||||
|
||||
model Prompt {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
content String
|
||||
description String?
|
||||
categoryId Int?
|
||||
tags String?
|
||||
authorId Int?
|
||||
model String?
|
||||
isPublic Boolean @default(true)
|
||||
status ContentStatus @default(PUBLISHED)
|
||||
viewCount Int @default(0)
|
||||
likeCount Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
|
||||
category Category? @relation(fields: [categoryId], references: [id])
|
||||
author User? @relation(fields: [authorId], references: [id])
|
||||
favorites PromptFavorite[]
|
||||
|
||||
@@map("prompts")
|
||||
}
|
||||
|
||||
model PromptFavorite {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
promptId Int
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, promptId])
|
||||
@@map("prompt_favorites")
|
||||
}
|
||||
|
||||
model Tool {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
description String?
|
||||
url String
|
||||
icon String?
|
||||
categoryId Int?
|
||||
tags String?
|
||||
isFeatured Boolean @default(false)
|
||||
status ContentStatus @default(PUBLISHED)
|
||||
viewCount Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
|
||||
category Category? @relation(fields: [categoryId], references: [id])
|
||||
|
||||
@@map("tools")
|
||||
}
|
||||
|
||||
model Content {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
summary String?
|
||||
content String?
|
||||
cover String?
|
||||
categoryId Int?
|
||||
tags String?
|
||||
authorName String?
|
||||
contentType String @default("article")
|
||||
status ContentStatus @default(DRAFT)
|
||||
viewCount Int @default(0)
|
||||
isAiGenerated Boolean @default(false)
|
||||
publishedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
|
||||
category Category? @relation(fields: [categoryId], references: [id])
|
||||
|
||||
@@map("contents")
|
||||
}
|
||||
|
||||
model AiModel {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
provider String
|
||||
description String?
|
||||
capabilities String?
|
||||
contextWindow Int?
|
||||
maxTokens Int?
|
||||
pricing String?
|
||||
isFree Boolean @default(false)
|
||||
isFeatured Boolean @default(false)
|
||||
icon String?
|
||||
sortOrder Int @default(0)
|
||||
status String @default("ACTIVE")
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@map("ai_models")
|
||||
}
|
||||
|
||||
model SandboxSession {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
conversationId String @default("")
|
||||
model String
|
||||
title String @default("AI 对话")
|
||||
messages String @db.Text
|
||||
feedback String?
|
||||
tokens Int @default(0)
|
||||
duration Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, conversationId])
|
||||
@@index([userId, createdAt])
|
||||
@@map("sandbox_sessions")
|
||||
}
|
||||
|
||||
model Order {
|
||||
id Int @id @default(autoincrement())
|
||||
orderNo String @unique
|
||||
userId Int
|
||||
amount Float
|
||||
planType String
|
||||
status OrderStatus @default(PENDING)
|
||||
payChannel String?
|
||||
paidAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@index([userId, status])
|
||||
@@index([status, createdAt])
|
||||
@@map("orders")
|
||||
}
|
||||
|
||||
model Subscription {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
plan MemberPlan
|
||||
startDate DateTime
|
||||
endDate DateTime
|
||||
status String @default("ACTIVE")
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@index([userId, status])
|
||||
@@map("subscriptions")
|
||||
}
|
||||
|
||||
model AdminUser {
|
||||
id Int @id @default(autoincrement())
|
||||
username String @unique
|
||||
passwordHash String
|
||||
nickname String?
|
||||
role String @default("editor")
|
||||
status String @default("ACTIVE")
|
||||
lastLoginAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@map("admin_users")
|
||||
}
|
||||
|
||||
model AdminLog {
|
||||
id Int @id @default(autoincrement())
|
||||
adminId Int
|
||||
action String
|
||||
target String?
|
||||
detail String?
|
||||
ip String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@map("admin_logs")
|
||||
}
|
||||
|
||||
model Post {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
title String
|
||||
content String
|
||||
tags String?
|
||||
circleId Int?
|
||||
status String @default("PUBLISHED")
|
||||
viewCount Int @default(0)
|
||||
likeCount Int @default(0)
|
||||
commentCount Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
comments Comment[]
|
||||
likes PostLike[]
|
||||
circle Circle? @relation(fields: [circleId], references: [id])
|
||||
|
||||
@@index([userId])
|
||||
@@index([status, createdAt])
|
||||
@@index([circleId])
|
||||
@@map("posts")
|
||||
}
|
||||
|
||||
model Comment {
|
||||
id Int @id @default(autoincrement())
|
||||
postId Int
|
||||
userId Int
|
||||
content String
|
||||
parentId Int?
|
||||
status String @default("PUBLISHED")
|
||||
reviewNote String?
|
||||
reviewedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
parent Comment? @relation("CommentReply", fields: [parentId], references: [id])
|
||||
replies Comment[] @relation("CommentReply")
|
||||
|
||||
@@index([postId])
|
||||
@@index([status])
|
||||
@@map("comments")
|
||||
}
|
||||
|
||||
model PostLike {
|
||||
id Int @id @default(autoincrement())
|
||||
postId Int
|
||||
userId Int
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([postId, userId])
|
||||
@@map("post_likes")
|
||||
}
|
||||
|
||||
model Circle {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
description String?
|
||||
tags String?
|
||||
creatorId Int
|
||||
isPublic Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
creator User @relation("CircleCreator", fields: [creatorId], references: [id])
|
||||
members CircleMember[]
|
||||
posts Post[]
|
||||
|
||||
@@map("circles")
|
||||
}
|
||||
|
||||
model CircleMember {
|
||||
id Int @id @default(autoincrement())
|
||||
circleId Int
|
||||
userId Int
|
||||
role String @default("member")
|
||||
joinedAt DateTime @default(now())
|
||||
|
||||
circle Circle @relation(fields: [circleId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([circleId, userId])
|
||||
@@map("circle_members")
|
||||
}
|
||||
|
||||
model Follow {
|
||||
id Int @id @default(autoincrement())
|
||||
followerId Int
|
||||
followingId Int
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
follower User @relation("Follower", fields: [followerId], references: [id], onDelete: Cascade)
|
||||
following User @relation("Following", fields: [followingId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([followerId, followingId])
|
||||
@@map("follows")
|
||||
}
|
||||
|
||||
model Organization {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
description String?
|
||||
contactName String?
|
||||
contactPhone String?
|
||||
logo String?
|
||||
memberCount Int @default(0)
|
||||
status String @default("ACTIVE")
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
members OrganizationMember[]
|
||||
assignments CourseAssignment[]
|
||||
|
||||
@@map("organizations")
|
||||
}
|
||||
|
||||
model OrganizationMember {
|
||||
id Int @id @default(autoincrement())
|
||||
organizationId Int
|
||||
userId Int
|
||||
role String @default("MEMBER")
|
||||
status String @default("ACTIVE")
|
||||
joinedAt DateTime @default(now())
|
||||
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([organizationId, userId])
|
||||
@@map("organization_members")
|
||||
}
|
||||
|
||||
model CourseAssignment {
|
||||
id Int @id @default(autoincrement())
|
||||
organizationId Int
|
||||
courseId Int
|
||||
assignedBy Int
|
||||
deadline DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@map("course_assignments")
|
||||
}
|
||||
|
||||
model Notification {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
type String // 'like', 'comment', 'follow', 'system'
|
||||
title String
|
||||
content String?
|
||||
link String?
|
||||
relatedId Int?
|
||||
isRead Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId, isRead])
|
||||
@@map("notifications")
|
||||
}
|
||||
Reference in New Issue
Block a user