gongxiangp2/prisma/schema.prisma
2026-07-03 15:12:20 +08:00

748 lines
31 KiB
Plaintext

generator client {
provider = "prisma-client-js"
previewFeatures = []
binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
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
role Role @default(USER)
isActive Boolean @default(false)
canDownload Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
department String @default("")
dingtalkUserId String?
loginType String @default("normal")
realName String?
phone String?
avatar String?
managedDepartment String?
isSuperAdmin Boolean @default(false)
departmentId String?
employmentStatus String? @default("active")
resignationDate DateTime?
transferDate DateTime?
transferToDeptId String?
employmentNote String?
statusChangedBy String?
statusChangedAt DateTime?
status String @default("pending")
lastLoginAt DateTime?
lastLoginIp String?
loginCount Int @default(0)
archivedAt DateTime?
managedDepartments Department[] @relation("DepartmentManager")
downloadLogs MaterialDownloadLog[]
favorites MaterialFavorite[]
likes MaterialLike[]
materialLogs MaterialLog[]
materialTransfersFrom MaterialTransfer[] @relation("MaterialTransferFromUser")
materialTransfersTo MaterialTransfer[] @relation("MaterialTransferToUser")
materialTransfersAsOperator MaterialTransfer[] @relation("MaterialTransferOperator")
materials Material[]
departmentRef Department? @relation("UserDepartment", fields: [departmentId], references: [id])
transferToDept Department? @relation("UserTransferDepartment", fields: [transferToDeptId], references: [id])
@@index([status])
@@index([archivedAt])
@@index([departmentId])
@@index([employmentStatus])
@@index([transferToDeptId])
@@map("users")
}
model Material {
id String @id @default(uuid())
previewUrl String
productModel String
reportTitle String? @map("report_title")
categoryName String
sceneName String
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)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
userId String
displayImages String[] @default([])
platformName String @default("")
uploadId String?
videoSourceUrl String?
videoPreview540Url String?
videoPreviewClipUrl String?
videoCoverUrl String?
videoDuration Int?
videoProcessingStatus String?
transcodeLastError String? @map("transcodelasterror")
transcodeAttempts Int? @map("transcodeattempts")
deletedAt DateTime?
productCategoryName String @default("")
originalOwnerId String?
transferredAt DateTime?
transferredBy String?
transferNote String?
taskNo String? @map("task_no")
taskStatus String? @map("task_status")
taskFetchedAt DateTime? @map("task_fetched_at")
isFullSet Boolean @default(false) @map("is_full_set")
isAiGenerated Boolean @default(false) @map("is_ai_generated")
taskDetailSourceType String? @map("task_detail_source_type")
assets MaterialAsset[]
downloadLogs MaterialDownloadLog[]
favorites MaterialFavorite[]
likes MaterialLike[]
logs MaterialLog[]
skus MaterialSku[]
transfers MaterialTransfer[]
transcodeProgresses VideoTranscodeProgress[] @relation("MaterialTranscodeProgress")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([createdAt])
@@index([categoryName])
@@index([sceneName])
@@index([platformName])
@@index([productCategoryName])
@@index([materialType])
@@index([downloadCount])
@@index([likeCount])
@@index([deletedAt])
@@index([originalOwnerId])
@@index([transferredAt])
@@index([taskNo])
@@index([taskStatus])
@@index([isFullSet])
@@index([productModel])
@@index([reportTitle])
@@index([authorName])
@@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
changes String?
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")
}
model MaterialSku {
id String @id @default(uuid())
materialId String @map("material_id")
skuName String @map("sku_name")
filePath String @map("file_path")
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")
fileName String? @map("file_name")
previewUrl String? @map("preview_url")
deletedAt DateTime? @map("deleted_at")
whiteBackgroundSourceType String? @map("white_background_source_type")
whiteBackgroundUploadedBy String? @map("white_background_uploaded_by")
whiteBackgroundUploadedAt DateTime? @map("white_background_uploaded_at")
barcodes MaterialSkuBarcode[]
material Material @relation(fields: [materialId], references: [id], onDelete: Cascade)
@@index([materialId])
@@index([skuName, deletedAt])
@@index([sortOrder])
@@index([deletedAt])
@@index([whiteBackgroundSourceType])
@@index([whiteBackgroundUploadedBy])
@@index([whiteBackgroundUploadedAt])
@@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")
siteName String @default("由壹点3D素材")
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
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")
s3AccessKey String @default("")
s3Bucket String @default("")
s3Endpoint String @default("")
s3PublicUrl String @default("")
s3Region String @default("us-east-1")
s3SecretKey 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")
@@map("system_settings")
}
model Department {
id String @id @default(uuid())
name String @unique
createdAt DateTime @default(now())
parentId String?
level Int @default(1)
status String @default("active")
managerId String?
code String? @unique
description String?
sortOrder Int @default(0)
updatedAt DateTime @updatedAt
manager User? @relation("DepartmentManager", fields: [managerId], references: [id])
parent Department? @relation("DepartmentHierarchy", fields: [parentId], references: [id])
children Department[] @relation("DepartmentHierarchy")
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)
linkedToDepartment String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
canDownloadSource Boolean @default(false) @map("can_download_source")
@@unique([department, materialType])
@@index([department])
@@index([materialType])
@@index([linkedToDepartment])
@@map("department_material_permissions")
}
model MaterialTransfer {
id String @id @default(uuid())
materialId String
fromUserId String
toUserId String
transferredBy String
transferNote String?
transferredAt DateTime @default(now())
fromUser User @relation("MaterialTransferFromUser", fields: [fromUserId], references: [id])
material Material @relation(fields: [materialId], references: [id], onDelete: Cascade)
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")
fileUrl String @map("file_url")
fileName String? @map("file_name")
fileSize BigInt @default(0) @map("file_size")
sortOrder Int @default(0) @map("sort_order")
skuCode String? @map("sku_code")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
material Material @relation(fields: [materialId], references: [id], onDelete: Cascade)
barcodes MaterialAssetBarcode[]
@@index([materialId])
@@index([assetType])
@@index([sortOrder])
@@map("material_assets")
}
model MaterialAssetBarcode {
id String @id @default(uuid())
assetId String @map("asset_id")
barcode String
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
asset MaterialAsset @relation(fields: [assetId], references: [id], onDelete: Cascade)
@@unique([assetId, barcode])
@@index([barcode])
@@index([assetId])
@@map("material_asset_barcodes")
}
model MaterialSkuBarcode {
id String @id @default(uuid())
skuId String @map("sku_id")
barcode String
deletedAt DateTime? @map("deleted_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
sku MaterialSku @relation(fields: [skuId], references: [id], onDelete: Cascade)
@@index([barcode])
@@index([skuId])
@@index([deletedAt])
@@map("material_sku_barcodes")
}
model ApiKey {
id String @id @default(uuid())
name String
key String @unique
isActive Boolean @default(true) @map("is_active")
createdBy String @map("created_by")
lastUsedAt DateTime? @map("last_used_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
callLogs ApiCallLog[]
externalMaterialImportJobs ExternalMaterialImportJob[]
idempotencyRecords ExternalApiIdempotencyRecord[]
@@index([key])
@@index([isActive])
@@map("api_keys")
}
model ExternalApiIdempotencyRecord {
id String @id @default(uuid())
apiKeyId String @map("api_key_id")
operationType String @map("operation_type")
clientRequestId String @map("client_request_id")
requestHash String @map("request_hash")
status String
responseStatus Int? @map("response_status")
responseBody Json? @map("response_body")
completedAt DateTime? @map("completed_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
apiKey ApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
@@unique([apiKeyId, operationType, clientRequestId])
@@index([apiKeyId])
@@index([operationType])
@@index([clientRequestId])
@@index([status])
@@index([createdAt])
@@map("external_api_idempotency_records")
}
model ApiCallLog {
id String @id @default(uuid())
apiKeyId String @map("api_key_id")
endpoint String
method String
taskNo String? @map("task_no")
queryType String? @map("query_type")
queryValue String? @map("query_value")
statusCode Int @map("status_code")
duration Int
ipAddress String? @map("ip_address")
userAgent String? @map("user_agent")
createdAt DateTime @default(now()) @map("created_at")
apiKey ApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
@@index([apiKeyId])
@@index([taskNo])
@@index([queryType])
@@index([queryValue])
@@index([createdAt])
@@map("api_call_logs")
}
model ExternalMaterialImportJob {
id String @id @default(uuid())
apiKeyId String @map("api_key_id")
clientRequestId String @map("client_request_id")
materialType String @map("material_type")
taskNo String @map("task_no")
status String
resolvedUserId String? @map("resolved_user_id")
requestPayload Json @map("request_payload")
submissionSnapshot Json @map("submission_snapshot")
resultMaterialId String? @map("result_material_id")
errorCode String? @map("error_code")
errorMessage String? @map("error_message")
completedAt DateTime? @map("completed_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
apiKey ApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
@@unique([apiKeyId, clientRequestId])
@@index([taskNo, status])
@@index([status])
@@index([createdAt])
@@map("external_material_import_jobs")
}
model PerformanceSurveyEmployeeProfile {
id String @id @default(uuid())
dingtalkUserId String? @unique @map("dingtalk_user_id")
dingEmail String? @map("ding_email")
jobNumber String? @unique @map("job_number")
flowerName String? @map("flower_name")
realName String? @map("real_name")
displayName String @map("display_name")
departmentName String? @map("department_name")
departmentPath String? @map("department_path")
positionTitle String? @map("position_title")
positionLevel String? @map("position_level")
levelType String? @map("level_type")
isLeadership Boolean @default(false) @map("is_leadership")
managerDingtalkUserId String? @map("manager_dingtalk_user_id")
managerJobNumber String? @map("manager_job_number")
managerName String? @map("manager_name")
employmentStatus String? @map("employment_status")
workPlace String? @map("work_place")
sourcePayload Json? @map("source_payload")
syncedAt DateTime? @map("synced_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
evaluatorAssignments PerformanceSurveyAssignment[] @relation("PerformanceSurveyEvaluator")
targetRecords PerformanceSurveyTarget[] @relation("PerformanceSurveyTargetEmployee")
responses PerformanceSurveyResponse[] @relation("PerformanceSurveyRespondentEmployee")
notifications PerformanceSurveyNotification[]
@@index([displayName])
@@index([dingEmail])
@@index([departmentName])
@@index([positionLevel])
@@index([levelType])
@@index([isLeadership])
@@index([managerDingtalkUserId])
@@index([employmentStatus])
@@map("performance_survey_employee_profiles")
}
model PerformanceSurveyDepartmentProfile {
id String @id @default(uuid())
name String @unique
parentName String? @map("parent_name")
sourceDeptId String? @map("source_dept_id")
sortOrder Int @default(0) @map("sort_order")
employeeCount Int @default(0) @map("employee_count")
syncedAt DateTime? @map("synced_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([parentName])
@@index([sourceDeptId])
@@map("performance_survey_department_profiles")
}
model PerformanceSurveyTemplate {
id String @id @default(uuid())
code String @unique
name String
description String?
surveyType String @default("person_period") @map("survey_type")
weight Float @default(1)
questions Json
scoreBands Json @map("score_bands")
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([surveyType])
@@index([isActive])
@@map("performance_survey_templates")
}
model PerformanceSurvey {
id String @id @default(uuid())
title String
description String?
surveyKind String @default("person_period") @map("survey_kind")
templateCode String @map("template_code")
templateSnapshot Json @map("template_snapshot")
status String @default("draft")
creatorUserId String @map("creator_user_id")
creatorName String @map("creator_name")
creatorEmployeeId String? @map("creator_employee_id")
departmentName String? @map("department_name")
dueAt DateTime? @map("due_at")
openedAt DateTime? @map("opened_at")
closedAt DateTime? @map("closed_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
targets PerformanceSurveyTarget[]
assignments PerformanceSurveyAssignment[]
responses PerformanceSurveyResponse[]
notifications PerformanceSurveyNotification[]
@@index([status])
@@index([surveyKind])
@@index([templateCode])
@@index([creatorUserId])
@@index([departmentName])
@@index([dueAt])
@@map("performance_surveys")
}
model PerformanceSurveyTarget {
id String @id @default(uuid())
surveyId String @map("survey_id")
targetType String @default("employee") @map("target_type")
employeeProfileId String? @map("employee_profile_id")
targetName String @map("target_name")
targetSnapshot Json @map("target_snapshot")
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
survey PerformanceSurvey @relation(fields: [surveyId], references: [id], onDelete: Cascade)
employeeProfile PerformanceSurveyEmployeeProfile? @relation("PerformanceSurveyTargetEmployee", fields: [employeeProfileId], references: [id])
assignments PerformanceSurveyAssignment[]
responses PerformanceSurveyResponse[]
notifications PerformanceSurveyNotification[]
@@index([surveyId])
@@index([targetType])
@@index([employeeProfileId])
@@map("performance_survey_targets")
}
model PerformanceSurveyAssignment {
id String @id @default(uuid())
surveyId String @map("survey_id")
targetId String @map("target_id")
evaluatorEmployeeId String? @map("evaluator_employee_id")
evaluatorUserId String? @map("evaluator_user_id")
evaluatorDingtalkUserId String? @map("evaluator_dingtalk_user_id")
evaluatorKey String @map("evaluator_key")
evaluatorName String @map("evaluator_name")
evaluatorSnapshot Json @map("evaluator_snapshot")
status String @default("pending")
submittedAt DateTime? @map("submitted_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
survey PerformanceSurvey @relation(fields: [surveyId], references: [id], onDelete: Cascade)
target PerformanceSurveyTarget @relation(fields: [targetId], references: [id], onDelete: Cascade)
evaluatorEmployee PerformanceSurveyEmployeeProfile? @relation("PerformanceSurveyEvaluator", fields: [evaluatorEmployeeId], references: [id])
response PerformanceSurveyResponse?
notifications PerformanceSurveyNotification[]
@@unique([targetId, evaluatorKey], map: "performance_survey_assignment_target_evaluator_key")
@@index([surveyId])
@@index([targetId])
@@index([evaluatorEmployeeId])
@@index([evaluatorUserId])
@@index([evaluatorDingtalkUserId])
@@index([evaluatorKey])
@@index([status])
@@map("performance_survey_assignments")
}
model PerformanceSurveyResponse {
id String @id @default(uuid())
surveyId String @map("survey_id")
targetId String @map("target_id")
assignmentId String @unique @map("assignment_id")
respondentUserId String @map("respondent_user_id")
respondentEmployeeId String? @map("respondent_employee_id")
respondentName String @map("respondent_name")
respondentSnapshot Json @map("respondent_snapshot")
scores Json
comment String?
totalScore Float @map("total_score")
achievementScore Float @map("achievement_score")
kpiScore Float @map("kpi_score")
weightedScore Float @map("weighted_score")
createdAt DateTime @default(now()) @map("created_at")
survey PerformanceSurvey @relation(fields: [surveyId], references: [id], onDelete: Cascade)
target PerformanceSurveyTarget @relation(fields: [targetId], references: [id], onDelete: Cascade)
assignment PerformanceSurveyAssignment @relation(fields: [assignmentId], references: [id], onDelete: Cascade)
respondentEmployee PerformanceSurveyEmployeeProfile? @relation("PerformanceSurveyRespondentEmployee", fields: [respondentEmployeeId], references: [id])
@@index([surveyId])
@@index([targetId])
@@index([respondentUserId])
@@index([respondentEmployeeId])
@@index([createdAt])
@@map("performance_survey_responses")
}
model PerformanceSurveyNotification {
id String @id @default(uuid())
surveyId String? @map("survey_id")
targetId String? @map("target_id")
assignmentId String? @map("assignment_id")
recipientEmployeeId String? @map("recipient_employee_id")
recipientUserId String? @map("recipient_user_id")
dingtalkUserId String? @map("dingtalk_user_id")
recipientName String @map("recipient_name")
eventType String @map("event_type")
businessKey String @map("business_key")
title String
content String
actionUrl String? @map("action_url")
status String @default("pending")
attemptCount Int @default(0) @map("attempt_count")
maxAttempts Int @default(5) @map("max_attempts")
nextRetryAt DateTime? @map("next_retry_at")
lastStatusCode Int? @map("last_status_code")
lastResponseBody String? @map("last_response_body")
lastError String? @map("last_error")
providerMessageId String? @map("provider_message_id")
sentAt DateTime? @map("sent_at")
completedAt DateTime? @map("completed_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
survey PerformanceSurvey? @relation(fields: [surveyId], references: [id], onDelete: Cascade)
target PerformanceSurveyTarget? @relation(fields: [targetId], references: [id], onDelete: Cascade)
assignment PerformanceSurveyAssignment? @relation(fields: [assignmentId], references: [id], onDelete: Cascade)
recipientEmployee PerformanceSurveyEmployeeProfile? @relation(fields: [recipientEmployeeId], references: [id])
@@unique([eventType, businessKey], map: "performance_survey_notification_event_key")
@@index([surveyId])
@@index([targetId])
@@index([assignmentId])
@@index([recipientEmployeeId])
@@index([recipientUserId])
@@index([dingtalkUserId])
@@index([status, nextRetryAt])
@@index([createdAt])
@@map("performance_survey_notifications")
}
model VideoTranscodeProgress {
id String @id @default(uuid())
materialId String @map("material_id")
stage String
progress Int @default(0)
status String @default("waiting") @map("status")
priority Int @default(0)
startedAt DateTime @default(now()) @map("started_at")
completedAt DateTime? @map("completed_at")
errorMessage String? @map("error_message")
retryCount Int @default(0) @map("retry_count")
lastHeartbeat DateTime? @map("last_heartbeat")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
material Material @relation("MaterialTranscodeProgress", fields: [materialId], references: [id], onDelete: Cascade)
@@unique([materialId, stage])
@@index([status])
@@index([priority, status])
@@index([materialId])
@@index([lastHeartbeat])
@@map("video_transcode_progresses")
}
enum Role {
USER
ADMIN
DEPT_ADMIN
SYSTEM_ADMIN
}