v0.11.1: 权限体系重构 + AI管线优化 + 内容整理
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE `categories` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(50) NOT NULL,
|
||||
`slug` VARCHAR(50) NOT NULL,
|
||||
`icon` VARCHAR(100) NULL,
|
||||
`parent_id` INTEGER NULL,
|
||||
`sort_order` INTEGER NOT NULL DEFAULT 0,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `categories_slug_key`(`slug`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `tools` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`slug` VARCHAR(100) NOT NULL,
|
||||
`category_id` INTEGER NOT NULL,
|
||||
`description` TEXT NOT NULL,
|
||||
`logo_url` VARCHAR(255) NULL,
|
||||
`website_url` VARCHAR(255) NOT NULL,
|
||||
`pricing_model` ENUM('free', 'freemium', 'paid', 'subscription') NOT NULL DEFAULT 'freemium',
|
||||
`pricing_detail` VARCHAR(200) NULL,
|
||||
`features` JSON NULL,
|
||||
`tags` JSON NULL,
|
||||
`view_count` INTEGER NOT NULL DEFAULT 0,
|
||||
`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 `tools_slug_key`(`slug`),
|
||||
INDEX `tools_category_id_status_idx`(`category_id`, `status`),
|
||||
FULLTEXT INDEX `tools_name_description_idx`(`name`, `description`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `pending_tools` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`slug` VARCHAR(100) NULL,
|
||||
`category_id` INTEGER NULL,
|
||||
`description` TEXT NULL,
|
||||
`logo_url` VARCHAR(255) NULL,
|
||||
`website_url` VARCHAR(255) NULL,
|
||||
`pricing_model` ENUM('free', 'freemium', 'paid', 'subscription') NULL DEFAULT 'freemium',
|
||||
`pricing_detail` VARCHAR(200) NULL,
|
||||
`features` JSON NULL,
|
||||
`tags` JSON NULL,
|
||||
`source_url` VARCHAR(255) NULL,
|
||||
`scraped_at` DATETIME(3) NULL,
|
||||
`status` ENUM('pending', 'approved', 'rejected') NOT NULL DEFAULT 'pending',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `categories` ADD CONSTRAINT `categories_parent_id_fkey` FOREIGN KEY (`parent_id`) REFERENCES `categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `tools` ADD CONSTRAINT `tools_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `scraped_at` on the `pending_tools` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE `pending_tools` DROP COLUMN `scraped_at`;
|
||||
@@ -0,0 +1,13 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE `discovery_configs` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`category_id` INTEGER NULL,
|
||||
`prompt` TEXT NOT NULL,
|
||||
`tagPool` JSON NULL,
|
||||
`temperature` DOUBLE NOT NULL DEFAULT 0.7,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `discovery_configs_category_id_key`(`category_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `tagPool` on the `discovery_configs` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE `discovery_configs` DROP COLUMN `tagPool`,
|
||||
ADD COLUMN `tag_pool` JSON NULL;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE `discovery_configs` ADD COLUMN `apiBaseUrl` VARCHAR(255) NULL,
|
||||
ADD COLUMN `apiKey` VARCHAR(255) NULL,
|
||||
ADD COLUMN `modelName` VARCHAR(100) NULL;
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `apiBaseUrl` on the `discovery_configs` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `apiKey` on the `discovery_configs` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `modelName` on the `discovery_configs` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE `discovery_configs` DROP COLUMN `apiBaseUrl`,
|
||||
DROP COLUMN `apiKey`,
|
||||
DROP COLUMN `modelName`,
|
||||
ADD COLUMN `api_provider_id` INTEGER NULL;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `skills` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`slug` VARCHAR(100) NOT NULL,
|
||||
`category_id` INTEGER NOT NULL,
|
||||
`description` TEXT NOT NULL,
|
||||
`logo_url` VARCHAR(255) NULL,
|
||||
`source_url` VARCHAR(255) NOT NULL,
|
||||
`source_type` VARCHAR(20) NOT NULL DEFAULT 'github',
|
||||
`features` JSON NULL,
|
||||
`tags` JSON NULL,
|
||||
`view_count` INTEGER NOT NULL DEFAULT 0,
|
||||
`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 `skills_slug_key`(`slug`),
|
||||
INDEX `skills_category_id_status_idx`(`category_id`, `status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `pending_skills` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`slug` VARCHAR(100) NULL,
|
||||
`category_id` INTEGER NULL,
|
||||
`description` TEXT NULL,
|
||||
`logo_url` VARCHAR(255) NULL,
|
||||
`source_url` VARCHAR(255) NULL,
|
||||
`source_type` VARCHAR(20) NULL,
|
||||
`features` JSON NULL,
|
||||
`tags` JSON NULL,
|
||||
`status` ENUM('pending', 'approved', 'rejected') NOT NULL DEFAULT 'pending',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `api_providers` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(50) NOT NULL,
|
||||
`baseUrl` VARCHAR(255) NOT NULL,
|
||||
`apiKey` VARCHAR(255) NOT NULL,
|
||||
`model` VARCHAR(100) NOT NULL,
|
||||
`isDefault` BOOLEAN NOT NULL DEFAULT false,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `skills` ADD CONSTRAINT `skills_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,23 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `skills` DROP FOREIGN KEY `skills_category_id_fkey`;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `skill_categories` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(50) NOT NULL,
|
||||
`slug` VARCHAR(50) NOT NULL,
|
||||
`icon` VARCHAR(100) NULL,
|
||||
`parent_id` INTEGER NULL,
|
||||
`sort_order` INTEGER NOT NULL DEFAULT 0,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `skill_categories_slug_key`(`slug`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `skill_categories` ADD CONSTRAINT `skill_categories_parent_id_fkey` FOREIGN KEY (`parent_id`) REFERENCES `skill_categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `skills` ADD CONSTRAINT `skills_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `skill_categories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `pending_tools` ADD CONSTRAINT `pending_tools_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `daily_report_items` ADD COLUMN `hot_score` INT NOT NULL DEFAULT 0;
|
||||
@@ -0,0 +1,44 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE `skills` ADD COLUMN `last_reviewed_at` DATETIME(3) NULL,
|
||||
ADD COLUMN `github_stars_history` JSON NULL;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `skill_reviews` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`skill_id` INTEGER NOT NULL,
|
||||
`capability` DOUBLE NOT NULL,
|
||||
`dev_exp` DOUBLE NOT NULL,
|
||||
`cost_license` DOUBLE NOT NULL,
|
||||
`community` DOUBLE NOT NULL,
|
||||
`performance` DOUBLE NOT NULL,
|
||||
`overall` DOUBLE NOT NULL,
|
||||
`reviews` JSON NOT NULL,
|
||||
`long_article` TEXT NULL,
|
||||
`video_script` TEXT NULL,
|
||||
`social_cards` JSON NULL,
|
||||
`status` ENUM('DRAFT', 'PUBLISHED', 'REJECTED', 'OUTDATED') NOT NULL DEFAULT 'DRAFT',
|
||||
`reviewed_at` DATETIME(3) NOT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
UNIQUE INDEX `skill_reviews_skill_id_key`(`skill_id`),
|
||||
INDEX `skill_reviews_skill_id_idx`(`skill_id`),
|
||||
INDEX `skill_reviews_overall_idx`(`overall`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `review_generation_logs` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`skill_id` INTEGER NOT NULL,
|
||||
`status` VARCHAR(20) NOT NULL,
|
||||
`prompt` TEXT NOT NULL,
|
||||
`response` TEXT NULL,
|
||||
`error` TEXT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `review_generation_logs_skill_id_idx`(`skill_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `skill_reviews` ADD CONSTRAINT `skill_reviews_skill_id_fkey` FOREIGN KEY (`skill_id`) REFERENCES `skills`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "mysql"
|
||||
@@ -0,0 +1,404 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "mysql"
|
||||
}
|
||||
|
||||
model Category {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @db.VarChar(50)
|
||||
slug String @unique @db.VarChar(50)
|
||||
icon String? @db.VarChar(100)
|
||||
parentId Int? @map("parent_id")
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
tools Tool[]
|
||||
pendingTools PendingTool[]
|
||||
parent Category? @relation("CategoryToCategory", fields: [parentId], references: [id])
|
||||
children Category[] @relation("CategoryToCategory")
|
||||
|
||||
@@map("categories")
|
||||
}
|
||||
|
||||
model SkillCategory {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @db.VarChar(50)
|
||||
slug String @unique @db.VarChar(50)
|
||||
icon String? @db.VarChar(100)
|
||||
parentId Int? @map("parent_id")
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
skills Skill[]
|
||||
pendingSkills PendingSkill[]
|
||||
parent SkillCategory? @relation("SkillCategoryToSkillCategory", fields: [parentId], references: [id])
|
||||
children SkillCategory[] @relation("SkillCategoryToSkillCategory")
|
||||
|
||||
@@map("skill_categories")
|
||||
}
|
||||
|
||||
model Tool {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @db.VarChar(100)
|
||||
slug String @unique @db.VarChar(100)
|
||||
categoryId Int @map("category_id")
|
||||
description String @db.Text
|
||||
logoUrl String? @map("logo_url") @db.VarChar(255)
|
||||
websiteUrl String @map("website_url") @db.VarChar(255)
|
||||
pricingModel PricingModel @default(freemium) @map("pricing_model")
|
||||
pricingDetail String? @map("pricing_detail") @db.VarChar(200)
|
||||
features Json?
|
||||
tags Json?
|
||||
viewCount Int @default(0) @map("view_count")
|
||||
status Status @default(draft)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
category Category @relation(fields: [categoryId], references: [id])
|
||||
favorites Favorite[]
|
||||
browsingHistory BrowsingHistory[]
|
||||
reviews Review[]
|
||||
collectionItems CollectionItem[]
|
||||
|
||||
@@index([categoryId, status])
|
||||
@@fulltext([name, description])
|
||||
@@map("tools")
|
||||
}
|
||||
|
||||
model PendingTool {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @db.VarChar(100)
|
||||
slug String? @db.VarChar(100)
|
||||
categoryId Int? @map("category_id")
|
||||
description String? @db.Text
|
||||
logoUrl String? @map("logo_url") @db.VarChar(255)
|
||||
websiteUrl String? @map("website_url") @db.VarChar(255)
|
||||
pricingModel PricingModel? @default(freemium) @map("pricing_model")
|
||||
pricingDetail String? @map("pricing_detail") @db.VarChar(200)
|
||||
features Json?
|
||||
tags Json?
|
||||
sourceUrl String? @map("source_url") @db.VarChar(255)
|
||||
status PendingStatus @default(pending)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
category Category? @relation(fields: [categoryId], references: [id])
|
||||
|
||||
@@map("pending_tools")
|
||||
}
|
||||
|
||||
model Skill {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @db.VarChar(100)
|
||||
slug String @unique @db.VarChar(100)
|
||||
categoryId Int @map("category_id")
|
||||
description String @db.Text
|
||||
logoUrl String? @map("logo_url") @db.VarChar(255)
|
||||
sourceUrl String @map("source_url") @db.VarChar(255)
|
||||
sourceType String @default("gitee") @map("source_type") @db.VarChar(20)
|
||||
rating Float @default(0) @db.Float
|
||||
features Json?
|
||||
tags Json?
|
||||
viewCount Int @default(0) @map("view_count")
|
||||
status Status @default(draft)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
category SkillCategory @relation(fields: [categoryId], references: [id])
|
||||
favorites Favorite[]
|
||||
browsingHistory BrowsingHistory[]
|
||||
reviews Review[]
|
||||
collectionItems CollectionItem[]
|
||||
skillReview SkillReview?
|
||||
|
||||
lastReviewedAt DateTime? @map("last_reviewed_at")
|
||||
githubStarsHistory Json? @map("github_stars_history")
|
||||
|
||||
@@index([categoryId, status])
|
||||
@@map("skills")
|
||||
}
|
||||
|
||||
model PendingSkill {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @db.VarChar(100)
|
||||
slug String? @db.VarChar(100)
|
||||
categoryId Int? @map("category_id")
|
||||
description String? @db.Text
|
||||
logoUrl String? @map("logo_url") @db.VarChar(255)
|
||||
sourceUrl String? @map("source_url") @db.VarChar(255)
|
||||
sourceType String? @map("source_type") @db.VarChar(20)
|
||||
rating Float @default(0) @db.Float
|
||||
features Json?
|
||||
tags Json?
|
||||
status PendingStatus @default(pending)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
category SkillCategory? @relation(fields: [categoryId], references: [id])
|
||||
|
||||
@@map("pending_skills")
|
||||
}
|
||||
|
||||
enum PricingModel {
|
||||
free
|
||||
freemium
|
||||
paid
|
||||
subscription
|
||||
}
|
||||
|
||||
enum Status {
|
||||
draft
|
||||
published
|
||||
}
|
||||
|
||||
enum PendingStatus {
|
||||
pending
|
||||
approved
|
||||
rejected
|
||||
}
|
||||
|
||||
model SystemConfig {
|
||||
id Int @id @default(autoincrement())
|
||||
key String @unique @db.VarChar(50)
|
||||
value Json
|
||||
@@map("system_configs")
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
email String @unique @db.VarChar(255)
|
||||
passwordHash String? @db.VarChar(255)
|
||||
name String? @db.VarChar(100)
|
||||
avatarUrl String?
|
||||
oauthProvider String? @db.VarChar(50)
|
||||
oauthId String? @unique @db.VarChar(255)
|
||||
role String @default("user") @db.VarChar(20)
|
||||
roleId Int? @map("role_id")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
assignedRole Role? @relation(fields: [roleId], references: [id])
|
||||
favorites Favorite[]
|
||||
browsingHistory BrowsingHistory[]
|
||||
reviews Review[]
|
||||
collections Collection[]
|
||||
|
||||
@@unique([oauthProvider, oauthId])
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
model Role {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @db.VarChar(50)
|
||||
slug String @unique @db.VarChar(50)
|
||||
isSystem Boolean @default(false) @map("is_system")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
permissions RolePermission[]
|
||||
users User[]
|
||||
|
||||
@@map("roles")
|
||||
}
|
||||
|
||||
model Permission {
|
||||
id Int @id @default(autoincrement())
|
||||
groupName String @map("group_name") @db.VarChar(50)
|
||||
name String @db.VarChar(50)
|
||||
key String @unique @db.VarChar(80)
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
rolePermissions RolePermission[]
|
||||
|
||||
@@index([groupName, sortOrder])
|
||||
@@map("permissions")
|
||||
}
|
||||
|
||||
model RolePermission {
|
||||
roleId Int @map("role_id")
|
||||
permissionId Int @map("permission_id")
|
||||
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@id([roleId, permissionId])
|
||||
@@map("role_permissions")
|
||||
}
|
||||
|
||||
model Favorite {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int @map("user_id")
|
||||
toolId Int? @map("tool_id")
|
||||
skillId Int? @map("skill_id")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
tool Tool? @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
||||
skill Skill? @relation(fields: [skillId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, toolId])
|
||||
@@unique([userId, skillId])
|
||||
@@index([userId])
|
||||
@@map("favorites")
|
||||
}
|
||||
|
||||
model BrowsingHistory {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int @map("user_id")
|
||||
toolId Int? @map("tool_id")
|
||||
skillId Int? @map("skill_id")
|
||||
viewedAt DateTime @default(now()) @updatedAt @map("viewed_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
tool Tool? @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
||||
skill Skill? @relation(fields: [skillId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, toolId])
|
||||
@@unique([userId, skillId])
|
||||
@@index([userId, viewedAt])
|
||||
@@map("browsing_histories")
|
||||
}
|
||||
|
||||
model Review {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int @map("user_id")
|
||||
toolId Int? @map("tool_id")
|
||||
skillId Int? @map("skill_id")
|
||||
rating Int?
|
||||
comment String @db.Text
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
tool Tool? @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
||||
skill Skill? @relation(fields: [skillId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, toolId])
|
||||
@@unique([userId, skillId])
|
||||
@@index([toolId, createdAt])
|
||||
@@index([skillId, createdAt])
|
||||
@@map("reviews")
|
||||
}
|
||||
|
||||
model Collection {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int @map("user_id")
|
||||
name String @db.VarChar(50)
|
||||
description String? @db.Text
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
items CollectionItem[]
|
||||
|
||||
@@index([userId])
|
||||
@@map("collections")
|
||||
}
|
||||
|
||||
model CollectionItem {
|
||||
id Int @id @default(autoincrement())
|
||||
collectionId Int @map("collection_id")
|
||||
toolId Int? @map("tool_id")
|
||||
skillId Int? @map("skill_id")
|
||||
addedAt DateTime @default(now()) @map("added_at")
|
||||
|
||||
collection Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)
|
||||
tool Tool? @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
||||
skill Skill? @relation(fields: [skillId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([collectionId, toolId])
|
||||
@@unique([collectionId, skillId])
|
||||
@@index([collectionId])
|
||||
@@map("collection_items")
|
||||
}
|
||||
|
||||
model DailyReport {
|
||||
id Int @id @default(autoincrement())
|
||||
date DateTime @unique @db.Date
|
||||
title String @db.VarChar(200)
|
||||
summary String? @db.Text
|
||||
hotCount Int @default(0) @map("hot_count")
|
||||
coverUrl String? @map("cover_url") @db.VarChar(255)
|
||||
status Status @default(draft)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
items DailyReportItem[]
|
||||
|
||||
@@index([date])
|
||||
@@index([status])
|
||||
@@map("daily_reports")
|
||||
}
|
||||
|
||||
model DailyReportItem {
|
||||
id Int @id @default(autoincrement())
|
||||
reportId Int @map("report_id")
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
category String @default("tech") @db.VarChar(20)
|
||||
title String @db.VarChar(200)
|
||||
summary String? @db.Text
|
||||
detail String? @db.Text
|
||||
sourceUrl String? @map("source_url") @db.VarChar(500)
|
||||
imageUrl String? @map("image_url") @db.VarChar(255)
|
||||
hotScore Int @default(0) @map("hot_score")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
report DailyReport @relation(fields: [reportId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([reportId, sortOrder])
|
||||
@@map("daily_report_items")
|
||||
}
|
||||
|
||||
model SkillReview {
|
||||
id Int @id @default(autoincrement())
|
||||
skillId Int @unique @map("skill_id")
|
||||
skill Skill @relation(fields: [skillId], references: [id])
|
||||
|
||||
capability Float
|
||||
devExp Float @map("dev_exp")
|
||||
costLicense Float @map("cost_license")
|
||||
community Float
|
||||
performance Float
|
||||
overall Float
|
||||
|
||||
reviews Json
|
||||
|
||||
longArticle String? @map("long_article") @db.Text
|
||||
videoScript String? @map("video_script") @db.Text
|
||||
socialCards Json? @map("social_cards")
|
||||
|
||||
status ReviewStatus @default(DRAFT)
|
||||
reviewedAt DateTime @updatedAt @map("reviewed_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
@@index([skillId])
|
||||
@@index([overall])
|
||||
@@map("skill_reviews")
|
||||
}
|
||||
|
||||
model ReviewGenerationLog {
|
||||
id Int @id @default(autoincrement())
|
||||
skillId Int @map("skill_id")
|
||||
status String @db.VarChar(20)
|
||||
prompt String @db.Text
|
||||
response String? @db.Text
|
||||
error String? @db.Text
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
@@index([skillId])
|
||||
@@map("review_generation_logs")
|
||||
}
|
||||
|
||||
enum ReviewStatus {
|
||||
DRAFT
|
||||
PUBLISHED
|
||||
REJECTED
|
||||
OUTDATED
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
|
||||
|
||||
const adapter = new PrismaMariaDb(process.env.DATABASE_URL!);
|
||||
const prisma = new PrismaClient({ adapter });
|
||||
|
||||
const categories = [
|
||||
{ name: "文本生成", slug: "text-generation", icon: "", sortOrder: 1 },
|
||||
{ name: "图像生成", slug: "image-generation", icon: "", sortOrder: 2 },
|
||||
{ name: "视频生成", slug: "video-generation", icon: "", sortOrder: 3 },
|
||||
{ name: "音频处理", slug: "audio-processing", icon: "", sortOrder: 4 },
|
||||
{ name: "代码助手", slug: "code-assistant", icon: "", sortOrder: 5 },
|
||||
{ name: "办公效率", slug: "office-efficiency", icon: "", sortOrder: 6 },
|
||||
{ name: "AI 角色", slug: "ai-character", icon: "", sortOrder: 7 },
|
||||
{ name: "设计工具", slug: "design-tools", icon: "", sortOrder: 8 },
|
||||
{ name: "数据分析", slug: "data-analysis", icon: "", sortOrder: 9 },
|
||||
{ name: "内容检测", slug: "content-detection", icon: "", sortOrder: 10 },
|
||||
];
|
||||
|
||||
async function main() {
|
||||
console.log("Seeding categories...");
|
||||
|
||||
for (const category of categories) {
|
||||
await prisma.category.upsert({
|
||||
where: { slug: category.slug },
|
||||
update: { name: category.name, sortOrder: category.sortOrder },
|
||||
create: category,
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`Seeded ${categories.length} categories.`);
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user