445 lines
16 KiB
Plaintext
445 lines
16 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"
|
||
binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
|
||
previewFeatures = []
|
||
engineType = "library"
|
||
}
|
||
|
||
datasource db {
|
||
provider = "postgresql"
|
||
url = env("DATABASE_URL")
|
||
}
|
||
|
||
model User {
|
||
id String @id @default(uuid())
|
||
email String @unique
|
||
username String @unique
|
||
password String
|
||
department String @default("") // 用户部门(保留,向后兼容)
|
||
departmentId String? // 部门ID(外键关联,阶段二新增)
|
||
departmentRef Department? @relation("UserDepartment", fields: [departmentId], references: [id])
|
||
managedDepartment String? // 管理员负责的部门(如果是部门管理员)
|
||
role Role @default(USER)
|
||
isActive Boolean @default(false) // 是否激活,默认未激活(保留,向后兼容)
|
||
canDownload Boolean @default(true) // 是否允许下载,默认允许
|
||
isSuperAdmin Boolean @default(false) // 是否是超级管理员(最多4个)
|
||
|
||
// 钉钉登录相关字段
|
||
dingtalkUserId String? @unique // 钉钉userId
|
||
loginType String @default("normal") // 登录类型:normal/dingtalk
|
||
realName String? // 真实姓名
|
||
phone String? @unique // 手机号
|
||
avatar String? // 头像URL
|
||
|
||
// 用户状态管理(阶段一新增)
|
||
status String @default("pending") // pending/active/suspended/archived
|
||
lastLoginAt DateTime? // 最后登录时间
|
||
lastLoginIp String? // 最后登录IP
|
||
loginCount Int @default(0) // 登录次数
|
||
archivedAt DateTime? // 归档时间(软删除标记)
|
||
|
||
// 人员状态管理(新增:在职/离职/转岗等)
|
||
employmentStatus String? @default("active") // active/on_leave/resigned/transferred(在职/请假/离职/转岗)
|
||
resignationDate DateTime? // 离职日期
|
||
transferDate DateTime? // 转岗日期
|
||
transferToDeptId String? // 转岗目标部门ID
|
||
transferToDept Department? @relation("UserTransferDepartment", fields: [transferToDeptId], references: [id])
|
||
employmentNote String? // 人员状态备注(离职原因、转岗说明等)
|
||
statusChangedBy String? // 状态变更操作人ID
|
||
statusChangedAt DateTime? // 状态变更时间
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
materials Material[]
|
||
likes MaterialLike[]
|
||
favorites MaterialFavorite[]
|
||
downloadLogs MaterialDownloadLog[]
|
||
materialLogs MaterialLog[]
|
||
|
||
// 部门管理关联(阶段三新增)
|
||
managedDepartments Department[] @relation("DepartmentManager")
|
||
|
||
// 素材移交关联(新增)
|
||
materialTransfersFrom MaterialTransfer[] @relation("MaterialTransferFromUser")
|
||
materialTransfersTo MaterialTransfer[] @relation("MaterialTransferToUser")
|
||
materialTransfersAsOperator MaterialTransfer[] @relation("MaterialTransferOperator")
|
||
|
||
@@index([status])
|
||
@@index([isActive])
|
||
@@index([archivedAt])
|
||
@@index([departmentId])
|
||
@@index([employmentStatus])
|
||
@@index([transferToDeptId])
|
||
@@map("users")
|
||
}
|
||
|
||
model Material {
|
||
id String @id @default(uuid())
|
||
previewUrl String // S3 URL for preview image
|
||
productModel String // SPU
|
||
categoryName String // 使用店铺
|
||
sceneName String // 场景类别
|
||
platformName String @default("") // 平台分类(可选)
|
||
productCategoryName String @default("") // 品类分类(可选)
|
||
materialType String @default("3DMAX") // 素材类型
|
||
renderer String @default("CR") // 渲染器
|
||
authorName String // 作者花名
|
||
zipFileName String @default("") // 压缩包文件名
|
||
zipFilePath String @default("") // 本地压缩包路径
|
||
zipFileSize BigInt @default(0) // 压缩包文件大小(字节)
|
||
downloadCount Int @default(0) // 下载次数
|
||
likeCount Int @default(0) // 点赞次数
|
||
displayImages String[] @default([]) // 展示图片URLs数组
|
||
deletedAt DateTime? // 软删除时间戳
|
||
uploadId String? @unique // 上传ID(唯一约束,用于分片上传)
|
||
|
||
// 视频相关字段(2.2.3版本新增)
|
||
videoSourceUrl String? // 原始视频URL
|
||
videoPreview540Url String? // 540p预览视频URL
|
||
videoPreviewClipUrl String? // 视频片段URL
|
||
videoCoverUrl String? // 视频封面URL
|
||
videoProcessingStatus String? // 视频处理状态:pending/processing/completed/failed(可为空)
|
||
videoDuration Int? // 视频时长(秒)
|
||
transcodeLastError String? @map("transcodelasterror") // 转码最后一次错误信息
|
||
transcodeAttempts Int? @map("transcodeattempts") // 转码尝试次数
|
||
|
||
// 任务-详情相关字段(新增)
|
||
taskNo String? @unique @map("task_no") // 任务号(唯一,格式:TASK+12-18位数字,或 TASK+12-18位数字-2位子任务号)
|
||
taskStatus String? @map("task_status") // 任务状态:uploading/completed/fetched
|
||
taskFetchedAt DateTime? @map("task_fetched_at") // 外部系统获取时间
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
userId String
|
||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
|
||
// 素材移交相关(新增)
|
||
originalOwnerId String? // 原始所有者ID(移交后保留记录)
|
||
transferredAt DateTime? // 移交时间
|
||
transferredBy String? // 移交操作人ID
|
||
transferNote String? // 移交备注说明
|
||
|
||
likes MaterialLike[]
|
||
favorites MaterialFavorite[]
|
||
downloadLogs MaterialDownloadLog[]
|
||
logs MaterialLog[]
|
||
skus MaterialSku[]
|
||
transfers MaterialTransfer[] // 移交历史记录
|
||
assets MaterialAsset[] // 产品全案资产
|
||
|
||
@@index([userId])
|
||
@@index([createdAt])
|
||
@@index([categoryName])
|
||
@@index([sceneName])
|
||
@@index([platformName])
|
||
@@index([productCategoryName])
|
||
@@index([materialType])
|
||
@@index([downloadCount])
|
||
@@index([likeCount])
|
||
@@index([deletedAt])
|
||
@@index([videoProcessingStatus])
|
||
@@index([originalOwnerId])
|
||
@@index([transferredAt])
|
||
@@index([taskNo])
|
||
@@index([taskStatus])
|
||
@@map("materials")
|
||
}
|
||
|
||
model MaterialLike {
|
||
id String @id @default(uuid())
|
||
materialId String
|
||
userId String
|
||
createdAt DateTime @default(now())
|
||
|
||
material Material @relation(fields: [materialId], references: [id], onDelete: Cascade)
|
||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([materialId, userId])
|
||
@@index([materialId])
|
||
@@index([userId])
|
||
@@map("material_likes")
|
||
}
|
||
|
||
model MaterialFavorite {
|
||
id String @id @default(uuid())
|
||
materialId String
|
||
userId String
|
||
createdAt DateTime @default(now())
|
||
|
||
material Material @relation(fields: [materialId], references: [id], onDelete: Cascade)
|
||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([materialId, userId])
|
||
@@index([materialId])
|
||
@@index([userId])
|
||
@@map("material_favorites")
|
||
}
|
||
|
||
model MaterialDownloadLog {
|
||
id String @id @default(uuid())
|
||
materialId String
|
||
userId String
|
||
downloadedAt DateTime @default(now())
|
||
|
||
material Material @relation(fields: [materialId], references: [id], onDelete: Cascade)
|
||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([materialId])
|
||
@@index([userId])
|
||
@@index([downloadedAt])
|
||
@@index([materialId, userId, downloadedAt])
|
||
@@map("material_download_logs")
|
||
}
|
||
|
||
model MaterialLog {
|
||
id String @id @default(uuid())
|
||
materialId String
|
||
userId String
|
||
action String // UPLOAD, UPDATE, DELETE 等
|
||
changes String? // JSON 格式的变更记录
|
||
timestamp DateTime @default(now())
|
||
|
||
material Material @relation(fields: [materialId], references: [id], onDelete: Cascade)
|
||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([materialId])
|
||
@@index([userId])
|
||
@@index([timestamp])
|
||
@@map("material_logs")
|
||
}
|
||
|
||
// SKU 表(用于标准模型类型)
|
||
model MaterialSku {
|
||
id String @id @default(uuid())
|
||
materialId String @map("material_id")
|
||
skuName String @map("sku_name")
|
||
previewUrl String? @map("preview_url") // 预览图URL(可选)
|
||
filePath String @map("file_path") // 压缩包文件路径
|
||
fileName String? @map("file_name") // 压缩包文件名(可选,用于显示)
|
||
fileSize BigInt @default(0) @map("file_size")
|
||
sortOrder Int @default(0) @map("sort_order")
|
||
deletedAt DateTime? @map("deleted_at") // 软删除时间戳
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
material Material @relation(fields: [materialId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([materialId])
|
||
@@index([sortOrder])
|
||
@@index([deletedAt])
|
||
@@map("material_skus")
|
||
}
|
||
|
||
model ProductCategory {
|
||
id String @id @default(uuid())
|
||
name String @unique
|
||
createdAt DateTime @default(now())
|
||
|
||
@@map("product_categories")
|
||
}
|
||
|
||
model Category {
|
||
id String @id @default(uuid())
|
||
name String @unique
|
||
createdAt DateTime @default(now())
|
||
|
||
@@map("categories")
|
||
}
|
||
|
||
model Scene {
|
||
id String @id @default(uuid())
|
||
name String @unique
|
||
createdAt DateTime @default(now())
|
||
|
||
@@map("scenes")
|
||
}
|
||
|
||
model Platform {
|
||
id String @id @default(uuid())
|
||
name String @unique
|
||
createdAt DateTime @default(now())
|
||
|
||
@@map("platforms")
|
||
}
|
||
|
||
model SystemSettings {
|
||
id String @id @default(uuid())
|
||
headerBgColor String @default("#1f2937")
|
||
headerLogoUrl String @default("http://s3.1080p.hk/shuzhou/2025/05/18/8ebadf0a7cc34eaea00e8619b8efb827.png")
|
||
loginLogoUrl String @default("http://s3.1080p.hk/shuzhou/2025/05/18/8ebadf0a7cc34eaea00e8619b8efb827.png")
|
||
siteName String @default("由壹点3D素材")
|
||
s3Endpoint String @default("")
|
||
s3AccessKey String @default("")
|
||
s3SecretKey String @default("")
|
||
s3Bucket String @default("")
|
||
s3Region String @default("us-east-1")
|
||
s3PublicUrl String @default("")
|
||
// 系统维护通知
|
||
maintenanceEnabled Boolean @default(false) @map("maintenance_enabled") // 是否启用维护通知
|
||
maintenanceMessage String? @map("maintenance_message") // 维护通知内容
|
||
maintenanceStartTime DateTime? @map("maintenance_start_time") // 维护开始时间
|
||
maintenanceEndTime DateTime? @map("maintenance_end_time") // 维护结束时间
|
||
updatedAt DateTime @updatedAt
|
||
createdAt DateTime @default(now())
|
||
|
||
@@map("system_settings")
|
||
}
|
||
|
||
model Department {
|
||
id String @id @default(uuid())
|
||
name String @unique // 部门名称(保留,向后兼容)
|
||
createdAt DateTime @default(now())
|
||
|
||
// 部门层级结构(阶段三新增)
|
||
code String? @unique // 部门编码(可选,如:DEPT-001)
|
||
parentId String? // 父部门ID(支持层级结构)
|
||
parent Department? @relation("DepartmentHierarchy", fields: [parentId], references: [id])
|
||
children Department[] @relation("DepartmentHierarchy")
|
||
|
||
level Int @default(1) // 层级:1=一级部门,2=二级部门,3=三级部门
|
||
managerId String? // 部门负责人ID(部门管理员)
|
||
manager User? @relation("DepartmentManager", fields: [managerId], references: [id])
|
||
|
||
status String @default("active") // active/disabled/archived(部门状态)
|
||
description String? // 部门描述
|
||
sortOrder Int @default(0) // 排序字段
|
||
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// 关联用户(阶段二新增)
|
||
users User[] @relation("UserDepartment")
|
||
|
||
// 转岗用户关联(新增)
|
||
transferredUsers User[] @relation("UserTransferDepartment")
|
||
|
||
@@index([parentId])
|
||
@@index([status])
|
||
@@index([level])
|
||
@@index([managerId])
|
||
@@map("departments")
|
||
}
|
||
|
||
model Danmaku {
|
||
id String @id @default(uuid())
|
||
content String
|
||
username String
|
||
userId String
|
||
createdAt DateTime @default(now())
|
||
|
||
@@index([createdAt])
|
||
@@map("danmakus")
|
||
}
|
||
|
||
model DepartmentMaterialPermission {
|
||
id String @id @default(uuid())
|
||
department String // 部门名称(保留,向后兼容)
|
||
materialType String // 素材类型
|
||
canView Boolean @default(false) // 是否可见(默认不允许)
|
||
canDownload Boolean @default(false) // 是否可下载(默认不允许)
|
||
canShare Boolean @default(true) // 是否可分享(默认允许)
|
||
canDownloadSource Boolean @default(false) @map("can_download_source") // 是否可下载源文件(PSD)
|
||
linkedToDepartment String? // 关联到的部门(如果有关联,则从关联部门读取权限)
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
@@unique([department, materialType])
|
||
@@index([department])
|
||
@@index([materialType])
|
||
@@index([linkedToDepartment])
|
||
@@map("department_material_permissions")
|
||
}
|
||
|
||
enum Role {
|
||
USER // 普通用户
|
||
ADMIN // 管理员(保留,向后兼容,建议迁移到SYSTEM_ADMIN)
|
||
DEPT_ADMIN // 部门管理员(阶段四新增)
|
||
SYSTEM_ADMIN // 系统管理员(阶段四新增)
|
||
}
|
||
|
||
// 素材移交历史记录表(新增)
|
||
model MaterialTransfer {
|
||
id String @id @default(uuid())
|
||
materialId String // 素材ID
|
||
fromUserId String // 移交前所有者ID
|
||
toUserId String // 移交后所有者ID
|
||
transferredBy String // 移交操作人ID
|
||
transferNote String? // 移交备注说明
|
||
transferredAt DateTime @default(now()) // 移交时间
|
||
|
||
material Material @relation(fields: [materialId], references: [id], onDelete: Cascade)
|
||
fromUser User @relation("MaterialTransferFromUser", fields: [fromUserId], references: [id])
|
||
toUser User @relation("MaterialTransferToUser", fields: [toUserId], references: [id])
|
||
operator User @relation("MaterialTransferOperator", fields: [transferredBy], references: [id])
|
||
|
||
@@index([materialId])
|
||
@@index([fromUserId])
|
||
@@index([toUserId])
|
||
@@index([transferredAt])
|
||
@@map("material_transfers")
|
||
}
|
||
|
||
// 产品全案资产表(新增)
|
||
model MaterialAsset {
|
||
id String @id @default(uuid())
|
||
materialId String @map("material_id")
|
||
assetType String @map("asset_type") // main/sku/detail/psd/preview/zip(产品全案:main主图/sku/detail详情页/psd;3D原图:preview预览图/sku/zip压缩包)
|
||
fileUrl String @map("file_url") // S3 URL 或本地路径
|
||
fileName String? @map("file_name") // 原始文件名
|
||
fileSize BigInt @default(0) @map("file_size")
|
||
sortOrder Int @default(0) @map("sort_order")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
material Material @relation(fields: [materialId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([materialId])
|
||
@@index([assetType])
|
||
@@index([sortOrder])
|
||
@@map("material_assets")
|
||
}
|
||
|
||
// API 密钥表(新增)
|
||
model ApiKey {
|
||
id String @id @default(uuid())
|
||
name String // 密钥名称(如:任务系统)
|
||
key String @unique // 密钥值(32位随机字符串)
|
||
isActive Boolean @default(true) @map("is_active") // 是否启用
|
||
createdBy String @map("created_by") // 创建人ID
|
||
lastUsedAt DateTime? @map("last_used_at") // 最后使用时间
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
callLogs ApiCallLog[]
|
||
|
||
@@index([key])
|
||
@@index([isActive])
|
||
@@map("api_keys")
|
||
}
|
||
|
||
// API 调用日志表(新增)
|
||
model ApiCallLog {
|
||
id String @id @default(uuid())
|
||
apiKeyId String @map("api_key_id")
|
||
endpoint String // 调用的接口路径
|
||
method String // HTTP 方法
|
||
taskNo String? @map("task_no") // 任务号(如有)
|
||
statusCode Int @map("status_code") // 响应状态码
|
||
duration Int // 耗时(毫秒)
|
||
ipAddress String? @map("ip_address") // 调用方IP
|
||
userAgent String? @map("user_agent") // User-Agent
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
apiKey ApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([apiKeyId])
|
||
@@index([taskNo])
|
||
@@index([createdAt])
|
||
@@map("api_call_logs")
|
||
}
|