2026-05-25: 等级体系升级(20级)+论坛二级分类+会员空间

This commit is contained in:
ZhuiGuangAI Dev
2026-05-24 23:05:38 +08:00
parent 6c78c32157
commit 9bf3e7574a
118 changed files with 11842 additions and 3262 deletions
@@ -0,0 +1,35 @@
-- CreateTable
CREATE TABLE `daily_reports` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`date` DATE NOT NULL,
`title` VARCHAR(200) NOT NULL,
`summary` TEXT NULL,
`hot_count` INTEGER NOT NULL DEFAULT 0,
`cover_url` VARCHAR(255) NULL,
`status` ENUM('draft', 'published') NOT NULL DEFAULT 'draft',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
UNIQUE INDEX `daily_reports_date_key`(`date`),
INDEX `daily_reports_status_idx`(`status`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `daily_report_items` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`report_id` INTEGER NOT NULL,
`sort_order` INTEGER NOT NULL DEFAULT 0,
`category` VARCHAR(20) NOT NULL DEFAULT 'tech',
`title` VARCHAR(200) NOT NULL,
`summary` TEXT NULL,
`detail` TEXT NULL,
`source_url` VARCHAR(500) NULL,
`image_url` VARCHAR(255) NULL,
`hot_score` INTEGER NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `daily_report_items_report_id_sort_order_idx`(`report_id`, `sort_order`),
PRIMARY KEY (`id`),
CONSTRAINT `daily_report_items_report_id_fkey` FOREIGN KEY (`report_id`) REFERENCES `daily_reports`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -1 +0,0 @@
ALTER TABLE `daily_report_items` ADD COLUMN `hot_score` INT NOT NULL DEFAULT 0;
@@ -0,0 +1,16 @@
-- AlterEnum: Map old enum values to new 20-level system
-- Step 1: Change the column to VARCHAR temporarily
ALTER TABLE `users` MODIFY COLUMN `level` VARCHAR(20) NOT NULL DEFAULT 'LV01';
-- Step 2: Map old enum values to new ones
UPDATE `users` SET `level` = 'LV01' WHERE `level` = 'BRONZE';
UPDATE `users` SET `level` = 'LV03' WHERE `level` = 'SILVER';
UPDATE `users` SET `level` = 'LV06' WHERE `level` = 'GOLD';
UPDATE `users` SET `level` = 'LV10' WHERE `level` = 'PLATINUM';
-- AlterTable: Add bio field
ALTER TABLE `users` ADD COLUMN `bio` TEXT NULL;
-- AlterTable: Add parentId for ForumCategory hierarchy
ALTER TABLE `forum_categories` ADD COLUMN `parent_id` INT NULL;
ALTER TABLE `forum_categories` ADD CONSTRAINT `forum_categories_parent_id_fkey` FOREIGN KEY (`parent_id`) REFERENCES `forum_categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
+224 -1
View File
@@ -55,7 +55,12 @@ model Tool {
features Json?
tags Json?
viewCount Int @default(0) @map("view_count")
commentCount Int @default(0) @map("comment_count")
avgRating Float @default(0) @map("avg_rating")
status Status @default(draft)
lastCheckedAt DateTime? @map("last_checked_at")
websiteOk Boolean @default(true) @map("website_ok")
logoOk Boolean @default(true) @map("logo_ok")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@ -64,6 +69,7 @@ model Tool {
browsingHistory BrowsingHistory[]
reviews Review[]
collectionItems CollectionItem[]
comments Comment[]
@@index([categoryId, status])
@@fulltext([name, description])
@@ -84,6 +90,11 @@ model PendingTool {
tags Json?
sourceUrl String? @map("source_url") @db.VarChar(255)
status PendingStatus @default(pending)
checkWebsiteOk Boolean? @map("check_website_ok")
checkLogoOk Boolean? @map("check_logo_ok")
checkDescOk Boolean? @map("check_desc_ok")
checkCategoryOk Boolean? @map("check_category_ok")
checkDetail Json? @map("check_detail")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@ -115,9 +126,16 @@ model Skill {
reviews Review[]
collectionItems CollectionItem[]
skillReview SkillReview?
comments Comment[]
lastReviewedAt DateTime? @map("last_reviewed_at")
githubStarsHistory Json? @map("github_stars_history")
githubStars Int @default(0) @map("github_stars")
starsChangeDay Int @default(0) @map("stars_change_day")
starsChangeWeek Int @default(0) @map("stars_change_week")
starsChangeMonth Int @default(0) @map("stars_change_month")
commentCount Int @default(0) @map("comment_count")
avgRating Float @default(0) @map("avg_rating")
@@index([categoryId, status])
@@map("skills")
@@ -175,10 +193,13 @@ model User {
passwordHash String? @db.VarChar(255)
name String? @db.VarChar(100)
avatarUrl String?
bio String? @db.Text
oauthProvider String? @db.VarChar(50)
oauthId String? @unique @db.VarChar(255)
role String @default("user") @db.VarChar(20)
roleId Int? @map("role_id")
points Int @default(0)
level UserLevel @default(LV01)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@ -187,11 +208,55 @@ model User {
browsingHistory BrowsingHistory[]
reviews Review[]
collections Collection[]
comments Comment[]
commentLikes CommentLike[]
notifications Notification[]
forumTopics ForumTopic[]
forumPosts ForumPost[]
pointsHistory PointsHistory[]
@@unique([oauthProvider, oauthId])
@@map("users")
}
model PointsHistory {
id Int @id @default(autoincrement())
userId Int @map("user_id")
points Int
reason String @db.VarChar(50)
detail String? @db.VarChar(200)
refType String? @map("ref_type") @db.VarChar(50)
refId Int? @map("ref_id")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, createdAt])
@@map("points_history")
}
enum UserLevel {
LV01
LV02
LV03
LV04
LV05
LV06
LV07
LV08
LV09
LV10
LV11
LV12
LV13
LV14
LV15
LV16
LV17
LV18
LV19
LV20
}
model Role {
id Int @id @default(autoincrement())
name String @db.VarChar(50)
@@ -402,3 +467,161 @@ enum ReviewStatus {
OUTDATED
}
model TaskLog {
id Int @id @default(autoincrement())
taskKey String @map("task_key") @db.VarChar(50)
taskName String @map("task_name") @db.VarChar(100)
status String @db.VarChar(20)
startedAt DateTime @map("started_at")
finishedAt DateTime? @map("finished_at")
duration Int?
result Json?
error String? @db.Text
triggerBy String @default("cron") @map("trigger_by") @db.VarChar(20)
createdAt DateTime @default(now()) @map("created_at")
@@index([taskKey, startedAt])
@@map("task_logs")
}
model TaskConfig {
id Int @id @default(autoincrement())
taskKey String @unique @map("task_key") @db.VarChar(50)
taskName String @map("task_name") @db.VarChar(100)
description String? @db.VarChar(255)
enabled Boolean @default(true)
cronExpr String? @map("cron_expr") @db.VarChar(50)
config Json?
updatedAt DateTime @updatedAt @map("updated_at")
@@map("task_configs")
}
model Comment {
id Int @id @default(autoincrement())
userId Int @map("user_id")
toolId Int? @map("tool_id")
skillId Int? @map("skill_id")
parentId Int? @map("parent_id")
content String @db.Text
rating Int?
likeCount Int @default(0) @map("like_count")
isPinned Boolean @default(false) @map("is_pinned")
status CommentStatus @default(ACTIVE)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id])
tool Tool? @relation(fields: [toolId], references: [id], onDelete: Cascade)
skill Skill? @relation(fields: [skillId], references: [id], onDelete: Cascade)
parent Comment? @relation("CommentReplies", fields: [parentId], references: [id])
replies Comment[] @relation("CommentReplies")
likes CommentLike[]
@@index([toolId, createdAt])
@@index([skillId, createdAt])
@@index([userId])
@@map("comments")
}
enum CommentStatus {
ACTIVE
HIDDEN
DELETED
}
model CommentLike {
id Int @id @default(autoincrement())
commentId Int @map("comment_id")
userId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
comment Comment @relation(fields: [commentId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([commentId, userId])
@@map("comment_likes")
}
model Notification {
id Int @id @default(autoincrement())
userId Int @map("user_id")
type NotifType
title String @db.VarChar(100)
content String? @db.VarChar(255)
link String? @db.VarChar(255)
isRead Boolean @default(false) @map("is_read")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, isRead, createdAt])
@@map("notifications")
}
enum NotifType {
COMMENT_REPLY
COMMENT_LIKE
TOPIC_REPLY
SYSTEM
}
model ForumCategory {
id Int @id @default(autoincrement())
name String @db.VarChar(30)
slug String @unique @db.VarChar(30)
description String? @db.VarChar(100)
icon String? @db.VarChar(30)
parentId Int? @map("parent_id")
sortOrder Int @default(0) @map("sort_order")
topicCount Int @default(0) @map("topic_count")
createdAt DateTime @default(now()) @map("created_at")
parent ForumCategory? @relation("CategoryHierarchy", fields: [parentId], references: [id])
children ForumCategory[] @relation("CategoryHierarchy")
topics ForumTopic[]
@@map("forum_categories")
}
model ForumTopic {
id Int @id @default(autoincrement())
categoryId Int @map("category_id")
userId Int @map("user_id")
title String @db.VarChar(100)
slug String @unique @db.VarChar(120)
content String @db.Text
isPinned Boolean @default(false) @map("is_pinned")
isLocked Boolean @default(false) @map("is_locked")
viewCount Int @default(0) @map("view_count")
replyCount Int @default(0) @map("reply_count")
lastReplyAt DateTime? @map("last_reply_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
category ForumCategory @relation(fields: [categoryId], references: [id])
user User @relation(fields: [userId], references: [id])
posts ForumPost[]
@@index([categoryId, lastReplyAt])
@@index([userId])
@@fulltext([title])
@@map("forum_topics")
}
model ForumPost {
id Int @id @default(autoincrement())
topicId Int @map("topic_id")
userId Int @map("user_id")
content String @db.Text
isAnswer Boolean @default(false) @map("is_answer")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id])
@@index([topicId, createdAt])
@@map("forum_posts")
}