作品审核: - 批量通过/批量拒绝 + 撤销审核机制 - 默认筛选待审核,表格加描述预览+审核时间列 - 详情Drawer加上一个/下一个导航,审核后自动跳下一个 - 操作日志时间线展示,筛选下拉自动查询 作品管理: - 修复筛选/排序失效,新增推荐中筛选 - 下架改为弹窗选择原因,取消推荐二次确认 - 详情Drawer补全描述/标签/操作按钮/操作日志 - 统计卡片可点击筛选,下架自动取消推荐 标签管理: - 按分类分组卡片式展示,分类改为下拉选择 - 新增标签颜色字段(预设色+自定义) - 上移/下移排序按钮,使用次数可点击跳转作品管理 - 新增/编辑时实时预览用户端标签效果 广场推荐: - 新增推荐作品列表接口 GET /public/gallery/recommended - 广场顶部新增「编辑推荐」横向滚动栏 文档更新:内容管理设计文档补充实施记录,UGC开发计划P1-1标记已完成 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1395 lines
75 KiB
Plaintext
1395 lines
75 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"
|
||
}
|
||
|
||
datasource db {
|
||
provider = "mysql"
|
||
url = env("DATABASE_URL")
|
||
}
|
||
|
||
/// 租户表
|
||
model Tenant {
|
||
id Int @id @default(autoincrement())
|
||
name String /// 租户名称
|
||
code String @unique /// 租户编码(唯一,用于访问链接)
|
||
domain String? @unique /// 租户域名(可选,用于子域名访问)
|
||
description String? /// 租户描述
|
||
isSuper Int @default(0) @map("is_super") /// 是否为超级租户:0-否,1-是
|
||
tenantType String @default("other") @map("tenant_type") /// 租户类型:platform/library/kindergarten/school/institution/other
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? /// 创建人ID(超级租户的用户ID)
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
users User[]
|
||
roles Role[]
|
||
menus TenantMenu[]
|
||
permissions Permission[]
|
||
dicts Dict[]
|
||
configs Config[]
|
||
school School? /// 学校信息(一对一)
|
||
grades Grade[] /// 年级
|
||
departments Department[] /// 部门
|
||
classes Class[] /// 班级
|
||
teachers Teacher[] /// 教师
|
||
students Student[] /// 学生
|
||
contestTeams ContestTeam[] /// 赛事团队
|
||
contestTeamMembers ContestTeamMember[] /// 团队成员
|
||
contestRegistrations ContestRegistration[] /// 赛事报名
|
||
contestRegistrationTeachers ContestRegistrationTeacher[] /// 报名指导老师关联
|
||
contestWorks ContestWork[] /// 参赛作品
|
||
contestWorkAttachments ContestWorkAttachment[] /// 作品附件
|
||
contestWorkScores ContestWorkScore[] /// 作品评分
|
||
contestReviewRules ContestReviewRule[] /// 评审规则
|
||
// 作业管理关联
|
||
homeworks Homework[] /// 作业
|
||
homeworkSubmissions HomeworkSubmission[] /// 作业提交记录
|
||
homeworkReviewRules HomeworkReviewRule[] /// 作业评审规则
|
||
homeworkScores HomeworkScore[] /// 作业评分
|
||
// AI 3D 生成关联
|
||
ai3dTasks AI3DTask[] /// AI 3D 生成任务
|
||
creatorUser User? @relation("TenantCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("TenantModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@index([tenantType])
|
||
@@map("tenants")
|
||
}
|
||
|
||
/// 用户表
|
||
model User {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
username String /// 用户名(在租户内唯一)
|
||
password String /// 密码(加密存储)
|
||
nickname String /// 昵称
|
||
email String? /// 邮箱(在租户内唯一,可选)
|
||
phone String? @unique /// 手机号(全局唯一,用于手机号登录)
|
||
wxOpenid String? @unique @map("wx_openid") /// 微信OpenID
|
||
wxUnionid String? @map("wx_unionid") /// 微信UnionID
|
||
userSource String @default("admin_created") @map("user_source") /// 用户来源:admin_created/self_registered/child_migrated
|
||
userType String @default("adult") @map("user_type") /// 用户类型:adult/child
|
||
city String? /// 所在城市
|
||
birthday DateTime? @db.Date /// 出生日期
|
||
gender String? /// 性别:male-男,female-女
|
||
avatar String? /// 头像URL
|
||
organization String? /// 所属单位(用于评委等独立用户)
|
||
status String @default("enabled") /// 账号状态:enabled-启用,disabled-停用
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? @map("creator") /// 创建人ID
|
||
modifier Int? @map("modifier") /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
roles UserRole[]
|
||
logs Log[]
|
||
createdBy User? @relation("UserCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifiedBy User? @relation("UserModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
createdUsers User[] @relation("UserCreator")
|
||
modifiedUsers User[] @relation("UserModifier")
|
||
createdRoles Role[] @relation("RoleCreator")
|
||
modifiedRoles Role[] @relation("RoleModifier")
|
||
createdPermissions Permission[] @relation("PermissionCreator")
|
||
modifiedPermissions Permission[] @relation("PermissionModifier")
|
||
createdMenus Menu[] @relation("MenuCreator")
|
||
modifiedMenus Menu[] @relation("MenuModifier")
|
||
createdDicts Dict[] @relation("DictCreator")
|
||
modifiedDicts Dict[] @relation("DictModifier")
|
||
createdDictItems DictItem[] @relation("DictItemCreator")
|
||
modifiedDictItems DictItem[] @relation("DictItemModifier")
|
||
createdConfigs Config[] @relation("ConfigCreator")
|
||
modifiedConfigs Config[] @relation("ConfigModifier")
|
||
createdTenants Tenant[] @relation("TenantCreator")
|
||
modifiedTenants Tenant[] @relation("TenantModifier")
|
||
teacher Teacher? /// 教师信息(一对一)
|
||
student Student? /// 学生信息(一对一)
|
||
createdSchools School[] @relation("SchoolCreator")
|
||
modifiedSchools School[] @relation("SchoolModifier")
|
||
createdGrades Grade[] @relation("GradeCreator")
|
||
modifiedGrades Grade[] @relation("GradeModifier")
|
||
createdDepartments Department[] @relation("DepartmentCreator")
|
||
modifiedDepartments Department[] @relation("DepartmentModifier")
|
||
createdClasses Class[] @relation("ClassCreator")
|
||
modifiedClasses Class[] @relation("ClassModifier")
|
||
createdTeachers Teacher[] @relation("TeacherCreator")
|
||
modifiedTeachers Teacher[] @relation("TeacherModifier")
|
||
createdStudents Student[] @relation("StudentCreator")
|
||
modifiedStudents Student[] @relation("StudentModifier")
|
||
// 赛事相关关联
|
||
createdContests Contest[] @relation("ContestCreator")
|
||
modifiedContests Contest[] @relation("ContestModifier")
|
||
createdContestAttachments ContestAttachment[] @relation("ContestAttachmentCreator")
|
||
modifiedContestAttachments ContestAttachment[] @relation("ContestAttachmentModifier")
|
||
createdContestReviewRules ContestReviewRule[] @relation("ContestReviewRuleCreator")
|
||
modifiedContestReviewRules ContestReviewRule[] @relation("ContestReviewRuleModifier")
|
||
createdContestTeams ContestTeam[] @relation("ContestTeamCreator")
|
||
modifiedContestTeams ContestTeam[] @relation("ContestTeamModifier")
|
||
ledContestTeams ContestTeam[] @relation("ContestTeamLeader")
|
||
createdContestTeamMembers ContestTeamMember[] @relation("ContestTeamMemberCreator")
|
||
modifiedContestTeamMembers ContestTeamMember[] @relation("ContestTeamMemberModifier")
|
||
contestTeamMembers ContestTeamMember[] @relation("ContestTeamMemberUser")
|
||
createdContestRegistrations ContestRegistration[] @relation("ContestRegistrationCreator")
|
||
modifiedContestRegistrations ContestRegistration[] @relation("ContestRegistrationModifier")
|
||
contestRegistrations ContestRegistration[] @relation("ContestRegistrationUser")
|
||
createdContestWorks ContestWork[] @relation("ContestWorkCreator")
|
||
modifiedContestWorks ContestWork[] @relation("ContestWorkModifier")
|
||
createdContestWorkAttachments ContestWorkAttachment[] @relation("ContestWorkAttachmentCreator")
|
||
modifiedContestWorkAttachments ContestWorkAttachment[] @relation("ContestWorkAttachmentModifier")
|
||
createdContestWorkJudgeAssignments ContestWorkJudgeAssignment[] @relation("ContestWorkJudgeAssignmentCreator")
|
||
modifiedContestWorkJudgeAssignments ContestWorkJudgeAssignment[] @relation("ContestWorkJudgeAssignmentModifier")
|
||
assignedContestWorks ContestWorkJudgeAssignment[] @relation("ContestWorkJudgeAssignmentJudge")
|
||
createdContestWorkScores ContestWorkScore[] @relation("ContestWorkScoreCreator")
|
||
modifiedContestWorkScores ContestWorkScore[] @relation("ContestWorkScoreModifier")
|
||
scoredContestWorks ContestWorkScore[] @relation("ContestWorkScoreJudge")
|
||
createdContestNotices ContestNotice[] @relation("ContestNoticeCreator")
|
||
modifiedContestNotices ContestNotice[] @relation("ContestNoticeModifier")
|
||
contestJudges ContestJudge[] @relation("ContestJudgeUser")
|
||
createdContestJudges ContestJudge[] @relation("ContestJudgeCreator")
|
||
modifiedContestJudges ContestJudge[] @relation("ContestJudgeModifier")
|
||
contestRegistrationTeachers ContestRegistrationTeacher[] @relation("ContestRegistrationTeacherUser")
|
||
createdContestRegistrationTeachers ContestRegistrationTeacher[] @relation("ContestRegistrationTeacherCreator")
|
||
modifiedContestRegistrationTeachers ContestRegistrationTeacher[] @relation("ContestRegistrationTeacherModifier")
|
||
// 作业管理关联
|
||
createdHomeworks Homework[] @relation("HomeworkCreator")
|
||
modifiedHomeworks Homework[] @relation("HomeworkModifier")
|
||
homeworkSubmissions HomeworkSubmission[] @relation("HomeworkSubmissionStudent")
|
||
createdHomeworkSubmissions HomeworkSubmission[] @relation("HomeworkSubmissionCreator")
|
||
modifiedHomeworkSubmissions HomeworkSubmission[] @relation("HomeworkSubmissionModifier")
|
||
createdHomeworkReviewRules HomeworkReviewRule[] @relation("HomeworkReviewRuleCreator")
|
||
modifiedHomeworkReviewRules HomeworkReviewRule[] @relation("HomeworkReviewRuleModifier")
|
||
homeworkScoresAsReviewer HomeworkScore[] @relation("HomeworkScoreReviewer")
|
||
createdHomeworkScores HomeworkScore[] @relation("HomeworkScoreCreator")
|
||
modifiedHomeworkScores HomeworkScore[] @relation("HomeworkScoreModifier")
|
||
// AI 3D 生成关联
|
||
ai3dTasks AI3DTask[] @relation("AI3DTaskUser") /// 用户的 AI 3D 生成任务
|
||
// 预设评语关联
|
||
presetComments PresetComment[] @relation("PresetCommentJudge") /// 评委的预设评语
|
||
// 子女关联
|
||
children Child[] @relation("ChildParent") /// 子女信息
|
||
// 家长-子女账号关系
|
||
parentRelations UserParentChild[] @relation("ParentUser") /// 作为家长关联的子女
|
||
childRelations UserParentChild[] @relation("ChildUser") /// 作为子女关联的家长
|
||
// UGC 作品关联
|
||
userWorks UserWork[] @relation("UserWorkCreator") /// 用户创作的作品
|
||
userWorkLikes UserWorkLike[] @relation("UserWorkLikeUser")
|
||
userWorkFavorites UserWorkFavorite[] @relation("UserWorkFavoriteUser")
|
||
userWorkComments UserWorkComment[] @relation("UserWorkCommentUser")
|
||
contentReviewLogs ContentReviewLog[] @relation("ContentReviewLogOperator")
|
||
// 举报关联
|
||
reportsMade UserWorkReport[] @relation("UserWorkReportReporter")
|
||
reportsReceived UserWorkReport[] @relation("UserWorkReportTarget")
|
||
|
||
@@unique([tenantId, username])
|
||
@@unique([tenantId, email])
|
||
@@map("users")
|
||
}
|
||
|
||
/// 角色表
|
||
model Role {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
name String /// 角色名称(在租户内唯一)
|
||
code String /// 角色编码(在租户内唯一)
|
||
description String? /// 角色描述
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
users UserRole[]
|
||
permissions RolePermission[]
|
||
creatorUser User? @relation("RoleCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("RoleModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, name])
|
||
@@unique([tenantId, code])
|
||
@@map("roles")
|
||
}
|
||
|
||
/// 用户角色关联表
|
||
model UserRole {
|
||
id Int @id @default(autoincrement())
|
||
userId Int @map("user_id") /// 用户ID
|
||
roleId Int @map("role_id") /// 角色ID
|
||
|
||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([userId, roleId])
|
||
@@map("user_roles")
|
||
}
|
||
|
||
/// 权限表
|
||
model Permission {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
name String /// 权限名称
|
||
code String /// 权限编码(在租户内唯一)
|
||
resource String /// 资源名称,如 user, role, menu
|
||
action String /// 操作类型,如 create, read, update, delete
|
||
description String? /// 权限描述
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
roles RolePermission[]
|
||
creatorUser User? @relation("PermissionCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("PermissionModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, resource, action])
|
||
@@unique([tenantId, code])
|
||
@@map("permissions")
|
||
}
|
||
|
||
/// 角色权限关联表
|
||
model RolePermission {
|
||
id Int @id @default(autoincrement())
|
||
roleId Int @map("role_id") /// 角色ID
|
||
permissionId Int @map("permission_id") /// 权限ID
|
||
|
||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([roleId, permissionId])
|
||
@@map("role_permissions")
|
||
}
|
||
|
||
/// 菜单表(全局菜单模板,超级租户管理)
|
||
model Menu {
|
||
id Int @id @default(autoincrement())
|
||
name String /// 菜单名称
|
||
path String? /// 路由路径
|
||
icon String? /// 图标
|
||
component String? /// 组件路径
|
||
parentId Int? @map("parent_id") /// 父菜单ID
|
||
permission String? /// 权限编码(用于控制菜单显示,如:menu:read)
|
||
sort Int @default(0) /// 排序
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? @map("creator") /// 创建人ID
|
||
modifier Int? @map("modifier") /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
parent Menu? @relation("MenuTree", fields: [parentId], references: [id])
|
||
children Menu[] @relation("MenuTree")
|
||
tenantMenus TenantMenu[] /// 租户菜单关联
|
||
creatorUser User? @relation("MenuCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("MenuModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@map("menus")
|
||
}
|
||
|
||
/// 租户菜单关联表(租户分配的菜单)
|
||
model TenantMenu {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
menuId Int @map("menu_id") /// 菜单ID
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
menu Menu @relation(fields: [menuId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([tenantId, menuId])
|
||
@@map("tenant_menus")
|
||
}
|
||
|
||
/// 数据字典表
|
||
model Dict {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
name String /// 字典名称
|
||
code String /// 字典编码(在租户内唯一)
|
||
description String? /// 字典描述
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
items DictItem[]
|
||
creatorUser User? @relation("DictCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("DictModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, code])
|
||
@@map("dicts")
|
||
}
|
||
|
||
/// 字典项表
|
||
model DictItem {
|
||
id Int @id @default(autoincrement())
|
||
dictId Int @map("dict_id") /// 字典ID
|
||
label String /// 标签
|
||
value String /// 值
|
||
sort Int @default(0) /// 排序
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? @map("creator") /// 创建人ID
|
||
modifier Int? @map("modifier") /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
dict Dict @relation(fields: [dictId], references: [id], onDelete: Cascade)
|
||
creatorUser User? @relation("DictItemCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("DictItemModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@map("dict_items")
|
||
}
|
||
|
||
/// 系统配置表
|
||
model Config {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
key String /// 配置键(在租户内唯一)
|
||
value String /// 配置值
|
||
description String? /// 配置描述
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
creatorUser User? @relation("ConfigCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ConfigModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, key])
|
||
@@map("configs")
|
||
}
|
||
|
||
/// 日志记录表
|
||
model Log {
|
||
id Int @id @default(autoincrement())
|
||
userId Int? @map("user_id") /// 用户ID
|
||
action String /// 操作类型
|
||
content String? @db.Text /// 操作内容(使用 TEXT 类型支持长文本)
|
||
ip String? /// IP地址
|
||
userAgent String? @map("user_agent") /// 用户代理
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
|
||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
||
|
||
@@map("logs")
|
||
}
|
||
|
||
/// 学校信息表(扩展租户信息)
|
||
model School {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @unique @map("tenant_id") /// 租户ID(一对一)
|
||
address String? /// 学校地址
|
||
phone String? /// 联系电话
|
||
principal String? /// 校长姓名
|
||
established DateTime? /// 建校时间
|
||
description String? @db.Text /// 学校描述
|
||
logo String? /// 学校Logo URL
|
||
website String? /// 学校网站
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
creatorUser User? @relation("SchoolCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("SchoolModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@map("schools")
|
||
}
|
||
|
||
/// 年级表
|
||
model Grade {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
name String /// 年级名称(如:一年级、二年级)
|
||
code String /// 年级编码(在租户内唯一,如:grade_1, grade_2)
|
||
level Int /// 年级级别(用于排序,如:1, 2, 3)
|
||
description String? /// 年级描述
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
classes Class[] /// 班级
|
||
creatorUser User? @relation("GradeCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("GradeModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, code])
|
||
@@unique([tenantId, level])
|
||
@@map("grades")
|
||
}
|
||
|
||
/// 部门表(支持树形结构)
|
||
model Department {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
name String /// 部门名称
|
||
code String /// 部门编码(在租户内唯一)
|
||
parentId Int? @map("parent_id") /// 父部门ID(支持树形结构)
|
||
description String? /// 部门描述
|
||
sort Int @default(0) /// 排序
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
parent Department? @relation("DepartmentTree", fields: [parentId], references: [id])
|
||
children Department[] @relation("DepartmentTree")
|
||
teachers Teacher[] /// 教师
|
||
creatorUser User? @relation("DepartmentCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("DepartmentModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, code])
|
||
@@map("departments")
|
||
}
|
||
|
||
/// 班级表
|
||
model Class {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
gradeId Int @map("grade_id") /// 年级ID
|
||
name String /// 班级名称(如:一年级1班、二年级2班)
|
||
code String /// 班级编码(在租户内唯一)
|
||
type Int @default(1) @map("type") /// 班级类型:1-行政班级(教学班级),2-兴趣班
|
||
capacity Int? /// 班级容量(可选)
|
||
description String? /// 班级描述
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
grade Grade @relation(fields: [gradeId], references: [id], onDelete: Cascade)
|
||
students Student[] /// 学生(行政班级)
|
||
studentInterestClasses StudentInterestClass[] /// 学生兴趣班关联
|
||
creatorUser User? @relation("ClassCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ClassModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, code])
|
||
@@map("classes")
|
||
}
|
||
|
||
/// 教师表
|
||
model Teacher {
|
||
id Int @id @default(autoincrement())
|
||
userId Int @unique @map("user_id") /// 用户ID(一对一)
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
departmentId Int @map("department_id") /// 部门ID
|
||
employeeNo String? @map("employee_no") /// 工号(在租户内唯一)
|
||
phone String? /// 联系电话
|
||
idCard String? @map("id_card") /// 身份证号
|
||
gender Int? /// 性别:1-男,2-女
|
||
birthDate DateTime? @map("birth_date") /// 出生日期
|
||
hireDate DateTime? @map("hire_date") /// 入职日期
|
||
subject String? /// 任教科目(可选,如:语文、数学)
|
||
title String? /// 职称(可选,如:高级教师、一级教师)
|
||
description String? @db.Text /// 教师描述
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
department Department @relation(fields: [departmentId], references: [id], onDelete: Restrict)
|
||
creatorUser User? @relation("TeacherCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("TeacherModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, employeeNo])
|
||
@@map("teachers")
|
||
}
|
||
|
||
/// 学生表
|
||
model Student {
|
||
id Int @id @default(autoincrement())
|
||
userId Int @unique @map("user_id") /// 用户ID(一对一)
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
classId Int @map("class_id") /// 行政班级ID
|
||
studentNo String? @map("student_no") /// 学号(在租户内唯一)
|
||
phone String? /// 联系电话
|
||
idCard String? @map("id_card") /// 身份证号
|
||
gender Int? /// 性别:1-男,2-女
|
||
birthDate DateTime? @map("birth_date") /// 出生日期
|
||
enrollmentDate DateTime? @map("enrollment_date") /// 入学日期
|
||
parentName String? @map("parent_name") /// 家长姓名
|
||
parentPhone String? @map("parent_phone") /// 家长电话
|
||
address String? /// 家庭地址
|
||
description String? @db.Text /// 学生描述
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
class Class @relation(fields: [classId], references: [id], onDelete: Restrict)
|
||
interestClasses StudentInterestClass[] /// 兴趣班关联
|
||
creatorUser User? @relation("StudentCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("StudentModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, studentNo])
|
||
@@map("students")
|
||
}
|
||
|
||
/// 学生兴趣班关联表(多对多)
|
||
model StudentInterestClass {
|
||
id Int @id @default(autoincrement())
|
||
studentId Int @map("student_id") /// 学生ID
|
||
classId Int @map("class_id") /// 兴趣班ID
|
||
|
||
student Student @relation(fields: [studentId], references: [id], onDelete: Cascade)
|
||
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([studentId, classId])
|
||
@@map("student_interest_classes")
|
||
}
|
||
|
||
// ============================================
|
||
// 赛事管理模块
|
||
// ============================================
|
||
|
||
/// 赛事表
|
||
model Contest {
|
||
id Int @id @default(autoincrement())
|
||
contestName String @map("contest_name") /// 赛事名称
|
||
contestType String @map("contest_type") /// 赛事类型:individual/team
|
||
contestState String @default("unpublished") @map("contest_state") /// 赛事状态:unpublished/published
|
||
status String @default("ongoing") /// 赛事进度状态:ongoing/finished
|
||
startTime DateTime @map("start_time") /// 赛事开始时间
|
||
endTime DateTime @map("end_time") /// 赛事结束时间
|
||
address String? /// 线下地址
|
||
content String? @db.Text /// 赛事详情
|
||
contestTenants Json? @map("contest_tenants") /// 授权租户ID数组
|
||
coverUrl String? @map("cover_url") /// 封面url
|
||
posterUrl String? @map("poster_url") /// 海报url
|
||
contactName String? @map("contact_name") /// 联系人
|
||
contactPhone String? @map("contact_phone") /// 联系电话
|
||
contactQrcode String? @map("contact_qrcode") /// 联系人二维码
|
||
organizers Json? /// 主办单位数组
|
||
coOrganizers Json? @map("co_organizers") /// 协办单位数组
|
||
sponsors Json? /// 赞助单位数组
|
||
// 报名配置
|
||
registerStartTime DateTime @map("register_start_time") /// 报名开始时间
|
||
registerEndTime DateTime @map("register_end_time") /// 报名结束时间
|
||
registerState String? @map("register_state") /// 报名任务状态:started/closed
|
||
requireAudit Boolean @default(true) @map("require_audit") /// 报名是否需要审核
|
||
allowedGrades Json? @map("allowed_grades") /// 允许报名的年级ID数组
|
||
allowedClasses Json? @map("allowed_classes") /// 允许报名的班级ID数组
|
||
teamMinMembers Int? @map("team_min_members") /// 团队最少成员数
|
||
teamMaxMembers Int? @map("team_max_members") /// 团队最多成员数
|
||
// 定向推送条件(visibility='targeted'时使用)
|
||
targetCities Json? @map("target_cities") /// 目标城市列表
|
||
ageMin Int? @map("age_min") /// 最小年龄限制
|
||
ageMax Int? @map("age_max") /// 最大年龄限制
|
||
// 作品配置
|
||
submitRule String @default("once") @map("submit_rule") /// 提交规则:once/resubmit
|
||
submitStartTime DateTime @map("submit_start_time") /// 作品提交开始时间
|
||
submitEndTime DateTime @map("submit_end_time") /// 作品提交结束时间
|
||
workType String? @map("work_type") /// 作品类型(如:image/video/document/code)
|
||
workRequirement String? @map("work_requirement") @db.Text /// 作品要求说明
|
||
// 评审配置
|
||
reviewRuleId Int? @map("review_rule_id") /// 评审规则id
|
||
reviewStartTime DateTime @map("review_start_time") /// 评审开始时间
|
||
reviewEndTime DateTime @map("review_end_time") /// 评审结束时间
|
||
// 赛果配置
|
||
resultState String @default("unpublished") @map("result_state") /// 赛果状态:unpublished/published
|
||
resultPublishTime DateTime? @map("result_publish_time") /// 结果发布时间
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
visibility String @default("designated") /// 可见范围:public-公开/designated-指定机构/internal-仅内部
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
attachments ContestAttachment[] /// 赛事附件
|
||
reviewRule ContestReviewRule? @relation("ContestReviewRuleContest", fields: [reviewRuleId], references: [id], onDelete: SetNull)
|
||
teams ContestTeam[] /// 赛事团队
|
||
registrations ContestRegistration[] /// 报名记录
|
||
works ContestWork[] /// 参赛作品
|
||
judges ContestJudge[] /// 比赛评委
|
||
workAssignments ContestWorkJudgeAssignment[] @relation("ContestWorkJudgeAssignmentContest") /// 作品分配
|
||
workScores ContestWorkScore[] @relation("ContestWorkScoreContest") /// 作品评分
|
||
notices ContestNotice[] /// 赛事公告
|
||
presetComments PresetComment[] /// 预设评语
|
||
creatorUser User? @relation("ContestCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([contestName])
|
||
@@index([contestState])
|
||
@@index([startTime, endTime])
|
||
@@index([reviewRuleId])
|
||
@@map("t_contest")
|
||
}
|
||
|
||
/// 赛事附件表
|
||
model ContestAttachment {
|
||
id Int @id @default(autoincrement())
|
||
contestId Int @map("contest_id") /// 赛事id
|
||
fileName String @map("file_name") /// 文件名
|
||
fileUrl String @map("file_url") /// 文件路径
|
||
format String? /// 文件类型(png,mp4)
|
||
fileType String? @map("file_type") /// 素材类型(image,video)
|
||
size String @default("0") /// 文件大小
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
contest Contest @relation(fields: [contestId], references: [id], onDelete: Cascade)
|
||
creatorUser User? @relation("ContestAttachmentCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestAttachmentModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@index([contestId])
|
||
@@map("t_contest_attachment")
|
||
}
|
||
|
||
/// 评审规则表(独立存在,可被多个赛事使用)
|
||
model ContestReviewRule {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
ruleName String @map("rule_name") /// 规则名称
|
||
ruleDescription String? @map("rule_description") @db.Text /// 规则说明
|
||
judgeCount Int? @map("judge_count") /// 评委数量
|
||
dimensions Json /// 评分维度配置JSON
|
||
calculationRule String @default("average") @map("calculation_rule") /// 计算规则:average/remove_max_min/remove_min
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
contests Contest[] @relation("ContestReviewRuleContest") /// 使用此规则的赛事列表
|
||
creatorUser User? @relation("ContestReviewRuleCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestReviewRuleModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@index([tenantId])
|
||
@@map("t_contest_review_rule")
|
||
}
|
||
|
||
/// 赛事团队表
|
||
model ContestTeam {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 团队所属租户ID
|
||
contestId Int @map("contest_id") /// 赛事id
|
||
teamName String @map("team_name") /// 团队名称(租户内唯一)
|
||
leaderUserId Int @map("leader_user_id") /// 团队负责人用户id
|
||
maxMembers Int? @map("max_members") /// 团队最大成员数
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
contest Contest @relation(fields: [contestId], references: [id], onDelete: Cascade)
|
||
leader User @relation("ContestTeamLeader", fields: [leaderUserId], references: [id], onDelete: Restrict)
|
||
members ContestTeamMember[] /// 团队成员
|
||
registrations ContestRegistration[] /// 报名记录
|
||
creatorUser User? @relation("ContestTeamCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestTeamModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, contestId, teamName])
|
||
@@index([contestId])
|
||
@@index([leaderUserId])
|
||
@@map("t_contest_team")
|
||
}
|
||
|
||
/// 团队成员表
|
||
model ContestTeamMember {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 成员所属租户ID
|
||
teamId Int @map("team_id") /// 团队id
|
||
userId Int @map("user_id") /// 成员用户id
|
||
role String @default("member") /// 成员角色:member/leader/mentor
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
team ContestTeam @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
||
user User @relation("ContestTeamMemberUser", fields: [userId], references: [id], onDelete: Cascade)
|
||
creatorUser User? @relation("ContestTeamMemberCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestTeamMemberModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, teamId, userId])
|
||
@@index([teamId])
|
||
@@index([userId])
|
||
@@map("t_contest_team_member")
|
||
}
|
||
|
||
/// 赛事报名表
|
||
model ContestRegistration {
|
||
id Int @id @default(autoincrement())
|
||
contestId Int @map("contest_id") /// 赛事id
|
||
tenantId Int @map("tenant_id") /// 所属租户ID
|
||
registrationType String? @map("registration_type") /// 报名类型:individual/team
|
||
teamId Int? @map("team_id") /// 团队id
|
||
teamName String? @map("team_name") /// 团队名称快照(团队赛)
|
||
userId Int @map("user_id") /// 账号id
|
||
accountNo String @map("account_no") /// 报名账号(记录报名快照)
|
||
accountName String @map("account_name") /// 报名账号名称(记录报名快照)
|
||
role String? /// 报名角色快照:leader/member/mentor
|
||
registrationState String @default("pending") @map("registration_state") /// 报名状态:pending/passed/rejected/withdrawn
|
||
participantType String @default("self") @map("participant_type") /// 参与者类型:self-自己/child-代子女报名
|
||
childId Int? @map("child_id") /// 子女ID,代子女报名时填写
|
||
registrant Int? /// 实际报名人用户ID
|
||
registrationTime DateTime @map("registration_time") /// 报名时间
|
||
reason String? @db.VarChar(1023) /// 审核理由
|
||
operator Int? /// 审核人用户ID
|
||
operationDate DateTime? @map("operation_date") /// 审核时间
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
|
||
contest Contest @relation(fields: [contestId], references: [id], onDelete: Cascade)
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
team ContestTeam? @relation(fields: [teamId], references: [id], onDelete: SetNull)
|
||
user User @relation("ContestRegistrationUser", fields: [userId], references: [id], onDelete: Restrict)
|
||
child Child? @relation("ContestRegistrationChild", fields: [childId], references: [id], onDelete: SetNull)
|
||
works ContestWork[] /// 参赛作品
|
||
creatorUser User? @relation("ContestRegistrationCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestRegistrationModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
teachers ContestRegistrationTeacher[] /// 指导老师关联
|
||
|
||
@@index([contestId, tenantId])
|
||
@@index([userId, contestId])
|
||
@@index([teamId])
|
||
@@index([registrationState])
|
||
@@index([participantType])
|
||
@@index([childId])
|
||
@@map("t_contest_registration")
|
||
}
|
||
|
||
/// 报名指导老师关联表
|
||
model ContestRegistrationTeacher {
|
||
id Int @id @default(autoincrement())
|
||
registrationId Int @map("registration_id") /// 报名记录ID
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
userId Int @map("user_id") /// 指导老师用户ID
|
||
isDefault Boolean @default(false) @map("is_default") /// 是否为默认指导老师(报名时自动添加的,不能移除)
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
|
||
registration ContestRegistration @relation(fields: [registrationId], references: [id], onDelete: Cascade)
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
user User @relation("ContestRegistrationTeacherUser", fields: [userId], references: [id], onDelete: Cascade)
|
||
creatorUser User? @relation("ContestRegistrationTeacherCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestRegistrationTeacherModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([tenantId, registrationId, userId])
|
||
@@index([registrationId])
|
||
@@index([userId])
|
||
@@map("t_contest_registration_teacher")
|
||
}
|
||
|
||
/// 参赛作品表
|
||
model ContestWork {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 作品所属租户ID
|
||
contestId Int @map("contest_id") /// 赛事id
|
||
registrationId Int @map("registration_id") /// 报名记录id
|
||
workNo String? @unique @map("work_no") /// 作品编号(展示用唯一编号)
|
||
title String /// 作品标题
|
||
description String? @db.Text /// 作品说明
|
||
files Json? /// 作品文件列表(简易场景)
|
||
version Int @default(1) /// 作品版本号(递增)
|
||
isLatest Boolean @default(true) @map("is_latest") /// 是否最新版本
|
||
status String @default("submitted") /// 作品状态:submitted/locked/reviewing/rejected/accepted
|
||
submitTime DateTime @default(now()) @map("submit_time") /// 提交时间
|
||
submitterUserId Int? @map("submitter_user_id") /// 提交人用户id
|
||
submitterAccountNo String? @map("submitter_account_no") /// 提交人账号
|
||
submitSource String @default("teacher") @map("submit_source") /// 提交来源:teacher/student/team_leader
|
||
previewUrl String? @map("preview_url") @db.Text /// 作品预览URL(兼容单预览图)
|
||
previewUrls Json? @map("preview_urls") /// 作品预览图URL列表(多模型场景)
|
||
aiModelMeta Json? @map("ai_model_meta") /// AI建模元数据
|
||
userWorkId Int? @map("user_work_id") /// 关联用户作品库(从作品库选择提交时)
|
||
// 赛果相关字段
|
||
finalScore Decimal? @map("final_score") @db.Decimal(10, 2) /// 最终得分(根据规则计算)
|
||
rank Int? /// 排名
|
||
awardLevel String? @map("award_level") /// 奖项等级:first/second/third/excellent/none
|
||
awardName String? @map("award_name") /// 奖项名称(如:一等奖、金奖)
|
||
certificateUrl String? @map("certificate_url") /// 证书URL
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
contest Contest @relation(fields: [contestId], references: [id], onDelete: Cascade)
|
||
registration ContestRegistration @relation(fields: [registrationId], references: [id], onDelete: Restrict)
|
||
userWork UserWork? @relation("ContestWorkUserWork", fields: [userWorkId], references: [id], onDelete: SetNull)
|
||
attachments ContestWorkAttachment[] /// 作品附件
|
||
assignments ContestWorkJudgeAssignment[] /// 作品分配
|
||
scores ContestWorkScore[] /// 作品评分
|
||
creatorUser User? @relation("ContestWorkCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestWorkModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@index([tenantId, contestId, isLatest])
|
||
@@index([registrationId])
|
||
@@index([tenantId, contestId, submitTime, status])
|
||
@@index([contestId, status])
|
||
@@map("t_contest_work")
|
||
}
|
||
|
||
/// 作品附件文件表
|
||
model ContestWorkAttachment {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 所属租户ID
|
||
contestId Int @map("contest_id") /// 赛事id
|
||
workId Int @map("work_id") /// 作品id
|
||
fileName String @map("file_name") /// 文件名
|
||
fileUrl String @map("file_url") /// 文件路径
|
||
format String? /// 文件类型(png,mp4)
|
||
fileType String? @map("file_type") /// 素材类型(image,video)
|
||
size String @default("0") /// 文件大小
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
|
||
work ContestWork @relation(fields: [workId], references: [id], onDelete: Cascade)
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
creatorUser User? @relation("ContestWorkAttachmentCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestWorkAttachmentModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@index([tenantId, contestId, workId])
|
||
@@map("t_contest_work_attachment")
|
||
}
|
||
|
||
/// 比赛评委关联表(比赛与评委的多对多关系)
|
||
model ContestJudge {
|
||
id Int @id @default(autoincrement())
|
||
contestId Int @map("contest_id") /// 比赛id
|
||
judgeId Int @map("judge_id") /// 评委用户id
|
||
specialty String? /// 评审专业领域(可选)
|
||
weight Decimal? @db.Decimal(3, 2) /// 评审权重(可选,用于加权平均计算)
|
||
description String? @db.Text /// 评委在该比赛中的说明
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
contest Contest @relation(fields: [contestId], references: [id], onDelete: Cascade)
|
||
judge User @relation("ContestJudgeUser", fields: [judgeId], references: [id], onDelete: Cascade)
|
||
creatorUser User? @relation("ContestJudgeCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestJudgeModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([contestId, judgeId])
|
||
@@index([contestId])
|
||
@@index([judgeId])
|
||
@@map("t_contest_judge")
|
||
}
|
||
|
||
/// 作品分配表(评委分配作品)
|
||
model ContestWorkJudgeAssignment {
|
||
id Int @id @default(autoincrement())
|
||
contestId Int @map("contest_id") /// 赛事id
|
||
workId Int @map("work_id") /// 作品id
|
||
judgeId Int @map("judge_id") /// 评委用户id
|
||
assignmentTime DateTime @default(now()) @map("assignment_time") /// 分配时间
|
||
status String @default("assigned") /// 分配状态:assigned/reviewing/completed
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
|
||
contest Contest @relation("ContestWorkJudgeAssignmentContest", fields: [contestId], references: [id], onDelete: Cascade)
|
||
work ContestWork @relation(fields: [workId], references: [id], onDelete: Cascade)
|
||
judge User @relation("ContestWorkJudgeAssignmentJudge", fields: [judgeId], references: [id], onDelete: Restrict)
|
||
scores ContestWorkScore[] /// 评分记录
|
||
creatorUser User? @relation("ContestWorkJudgeAssignmentCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestWorkJudgeAssignmentModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([workId, judgeId])
|
||
@@index([contestId, judgeId])
|
||
@@index([workId])
|
||
@@index([status])
|
||
@@map("t_contest_work_judge_assignment")
|
||
}
|
||
|
||
/// 作品评分表
|
||
model ContestWorkScore {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 所属租户ID
|
||
contestId Int @map("contest_id") /// 赛事id
|
||
workId Int @map("work_id") /// 作品id
|
||
assignmentId Int @map("assignment_id") /// 分配记录id
|
||
judgeId Int @map("judge_id") /// 评委用户id
|
||
judgeName String @map("judge_name") /// 评委姓名
|
||
dimensionScores Json @map("dimension_scores") /// 各维度评分JSON
|
||
totalScore Decimal @map("total_score") @db.Decimal(10, 2) /// 总分
|
||
comments String? @db.Text /// 评语
|
||
scoreTime DateTime @map("score_time") /// 评分时间
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
contest Contest @relation("ContestWorkScoreContest", fields: [contestId], references: [id], onDelete: Cascade)
|
||
work ContestWork @relation(fields: [workId], references: [id], onDelete: Cascade)
|
||
assignment ContestWorkJudgeAssignment @relation(fields: [assignmentId], references: [id], onDelete: Restrict)
|
||
judge User @relation("ContestWorkScoreJudge", fields: [judgeId], references: [id], onDelete: Restrict)
|
||
creatorUser User? @relation("ContestWorkScoreCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestWorkScoreModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@index([contestId, workId, judgeId])
|
||
@@index([workId])
|
||
@@index([assignmentId])
|
||
@@map("t_contest_work_score")
|
||
}
|
||
|
||
/// 赛事公告表
|
||
model ContestNotice {
|
||
id Int @id @default(autoincrement())
|
||
contestId Int @map("contest_id") /// 赛事id
|
||
title String /// 公告标题
|
||
content String @db.Text /// 公告内容
|
||
noticeType String @default("manual") @map("notice_type") /// 公告类型:system/manual/urgent
|
||
priority Int @default(0) /// 优先级(数字越大优先级越高)
|
||
publishTime DateTime? @map("publish_time") /// 发布时间
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
contest Contest @relation(fields: [contestId], references: [id], onDelete: Cascade)
|
||
creatorUser User? @relation("ContestNoticeCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("ContestNoticeModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@index([contestId])
|
||
@@index([publishTime])
|
||
@@index([noticeType])
|
||
@@map("t_contest_notice")
|
||
}
|
||
|
||
// ============================================
|
||
// 作业管理模块
|
||
// ============================================
|
||
|
||
/// 作业表
|
||
model Homework {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
name String /// 作业名称
|
||
content String? @db.Text /// 作业内容(富文本)
|
||
status String @default("unpublished") /// 作业状态:unpublished/published
|
||
publishTime DateTime? @map("publish_time") /// 发布时间
|
||
submitStartTime DateTime @map("submit_start_time") /// 提交开始时间
|
||
submitEndTime DateTime @map("submit_end_time") /// 提交结束时间
|
||
attachments Json? /// 附件列表 [{fileName, fileUrl, size}]
|
||
publishScope Json? @map("publish_scope") /// 公开范围(班级ID数组)
|
||
reviewRuleId Int? @map("review_rule_id") /// 评审规则ID
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
reviewRule HomeworkReviewRule? @relation(fields: [reviewRuleId], references: [id], onDelete: SetNull)
|
||
submissions HomeworkSubmission[] /// 作业提交记录
|
||
creatorUser User? @relation("HomeworkCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("HomeworkModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@index([tenantId, status])
|
||
@@index([tenantId, submitStartTime, submitEndTime])
|
||
@@map("t_homework")
|
||
}
|
||
|
||
/// 作业提交表
|
||
model HomeworkSubmission {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
homeworkId Int @map("homework_id") /// 作业ID
|
||
studentId Int @map("student_id") /// 学生用户ID
|
||
workNo String? @map("work_no") /// 作品编号
|
||
workName String @map("work_name") /// 作品名称
|
||
workDescription String? @map("work_description") @db.Text /// 作品介绍
|
||
files Json? /// 作品文件列表
|
||
attachments Json? /// 附件列表
|
||
submitTime DateTime @default(now()) @map("submit_time") /// 提交时间
|
||
status String @default("pending") /// 状态:pending/reviewed/rejected
|
||
totalScore Decimal? @map("total_score") @db.Decimal(10, 2) /// 总分
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
homework Homework @relation(fields: [homeworkId], references: [id], onDelete: Cascade)
|
||
student User @relation("HomeworkSubmissionStudent", fields: [studentId], references: [id], onDelete: Cascade)
|
||
scores HomeworkScore[] /// 评分记录
|
||
creatorUser User? @relation("HomeworkSubmissionCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("HomeworkSubmissionModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([homeworkId, studentId])
|
||
@@index([tenantId, homeworkId])
|
||
@@index([studentId])
|
||
@@index([status])
|
||
@@map("t_homework_submission")
|
||
}
|
||
|
||
/// 作业评审规则表
|
||
model HomeworkReviewRule {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
name String /// 规则名称
|
||
description String? @db.Text /// 规则描述
|
||
criteria Json /// 评分标准 [{name, maxScore, description}]
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
homeworks Homework[] /// 关联的作业
|
||
creatorUser User? @relation("HomeworkReviewRuleCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("HomeworkReviewRuleModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@index([tenantId])
|
||
@@map("t_homework_review_rule")
|
||
}
|
||
|
||
/// 作业评分表
|
||
model HomeworkScore {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
submissionId Int @map("submission_id") /// 提交记录ID
|
||
reviewerId Int @map("reviewer_id") /// 评审人ID
|
||
dimensionScores Json @map("dimension_scores") /// 各维度评分
|
||
totalScore Decimal @map("total_score") @db.Decimal(10, 2) /// 总分
|
||
comments String? @db.Text /// 评语
|
||
scoreTime DateTime @default(now()) @map("score_time") /// 评分时间
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 更新时间
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
submission HomeworkSubmission @relation(fields: [submissionId], references: [id], onDelete: Cascade)
|
||
reviewer User @relation("HomeworkScoreReviewer", fields: [reviewerId], references: [id], onDelete: Restrict)
|
||
creatorUser User? @relation("HomeworkScoreCreator", fields: [creator], references: [id], onDelete: SetNull)
|
||
modifierUser User? @relation("HomeworkScoreModifier", fields: [modifier], references: [id], onDelete: SetNull)
|
||
|
||
@@unique([submissionId, reviewerId])
|
||
@@index([tenantId, submissionId])
|
||
@@index([reviewerId])
|
||
@@map("t_homework_score")
|
||
}
|
||
|
||
// ============================================
|
||
// AI 3D 模型生成模块
|
||
// ============================================
|
||
|
||
/// AI 3D 生成任务表
|
||
model AI3DTask {
|
||
id Int @id @default(autoincrement())
|
||
tenantId Int @map("tenant_id") /// 租户ID
|
||
userId Int @map("user_id") /// 用户ID(任务归属用户)
|
||
inputType String @map("input_type") /// 输入类型:text | image
|
||
inputContent String @map("input_content") @db.Text /// 输入内容:文字描述或图片URL
|
||
generateType String @default("Normal") @map("generate_type") /// 生成类型:Normal(带纹理) | Geometry(白模) | LowPoly(低多边形) | Sketch(草图)
|
||
status String @default("pending") /// 任务状态:pending | processing | completed | failed | timeout
|
||
resultUrl String? @map("result_url") @db.Text /// 生成的3D模型URL(单个结果,兼容旧数据)
|
||
previewUrl String? @map("preview_url") @db.Text /// 预览图URL(单个结果,兼容旧数据)
|
||
resultUrls Json? @map("result_urls") /// 生成的3D模型URL数组(多个结果,文生3D生成4个)
|
||
previewUrls Json? @map("preview_urls") /// 预览图URL数组(多个结果)
|
||
errorMessage String? @map("error_message") @db.Text /// 失败时的错误信息
|
||
externalTaskId String? @map("external_task_id") /// 外部AI服务的任务ID
|
||
retryCount Int @default(0) @map("retry_count") /// 已重试次数
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
completeTime DateTime? @map("complete_time") /// 完成时间
|
||
|
||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||
user User @relation("AI3DTaskUser", fields: [userId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([userId])
|
||
@@index([tenantId])
|
||
@@index([status])
|
||
@@index([createTime])
|
||
@@map("t_ai_3d_task")
|
||
}
|
||
|
||
/// 预设评语表
|
||
model PresetComment {
|
||
id Int @id @default(autoincrement())
|
||
contestId Int @map("contest_id") /// 赛事ID
|
||
judgeId Int @map("judge_id") /// 评委用户ID
|
||
content String @db.Text /// 评语内容
|
||
score Decimal? @db.Decimal(10, 2) /// 关联评审分数
|
||
sortOrder Int @default(0) @map("sort_order") /// 排序顺序
|
||
useCount Int @default(0) @map("use_count") /// 使用次数
|
||
validState Int @default(1) @map("valid_state") /// 有效状态:1-有效,2-失效
|
||
creator Int? /// 创建人ID
|
||
modifier Int? /// 修改人ID
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
contest Contest @relation(fields: [contestId], references: [id], onDelete: Cascade)
|
||
judge User @relation("PresetCommentJudge", fields: [judgeId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([contestId, judgeId])
|
||
@@map("t_preset_comment")
|
||
}
|
||
|
||
/// 子女信息表
|
||
model Child {
|
||
id Int @id @default(autoincrement())
|
||
parentId Int @map("parent_id") /// 家长用户ID
|
||
name String @db.VarChar(50) /// 子女姓名
|
||
gender String? @db.VarChar(10) /// 性别:male/female
|
||
birthday DateTime? @db.Date /// 出生日期
|
||
grade String? @db.VarChar(20) /// 年级
|
||
city String? @db.VarChar(50) /// 所在城市
|
||
schoolName String? @map("school_name") @db.VarChar(100) /// 学校/幼儿园名称
|
||
avatar String? @db.VarChar(500) /// 头像URL
|
||
isDeleted Int @default(0) @map("is_deleted") /// 软删除标记
|
||
createTime DateTime @default(now()) @map("create_time") /// 创建时间
|
||
modifyTime DateTime @updatedAt @map("modify_time") /// 修改时间
|
||
|
||
parent User @relation("ChildParent", fields: [parentId], references: [id], onDelete: Cascade)
|
||
registrations ContestRegistration[] @relation("ContestRegistrationChild")
|
||
|
||
@@index([parentId])
|
||
@@map("children")
|
||
}
|
||
|
||
// ==================== 家长-子女账号关系 ====================
|
||
|
||
/// 家长-子女独立账号管理关系
|
||
model UserParentChild {
|
||
id Int @id @default(autoincrement())
|
||
parentUserId Int @map("parent_user_id") /// 家长 User.id
|
||
childUserId Int @map("child_user_id") /// 子女 User.id
|
||
relationship String? @db.VarChar(20) /// 关系:father/mother/guardian
|
||
controlMode String @default("open") @map("control_mode") /// 管控模式:open(子女自主)/restricted(需家长确认)
|
||
createTime DateTime @default(now()) @map("create_time")
|
||
|
||
parent User @relation("ParentUser", fields: [parentUserId], references: [id], onDelete: Cascade)
|
||
child User @relation("ChildUser", fields: [childUserId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([parentUserId, childUserId])
|
||
@@index([childUserId])
|
||
@@map("user_parent_child")
|
||
}
|
||
|
||
// ==================== UGC 用户作品 ====================
|
||
|
||
/// 用户作品主表
|
||
model UserWork {
|
||
id Int @id @default(autoincrement())
|
||
userId Int @map("user_id") /// 创作者 User.id
|
||
title String @db.VarChar(200) /// 作品名称
|
||
coverUrl String? @map("cover_url") @db.Text /// 封面图 URL
|
||
description String? @db.Text /// 作品简介
|
||
visibility String @default("private") /// 可见性:public/private/friends
|
||
status String @default("draft") /// 状态:draft/pending_review/published/rejected/taken_down
|
||
reviewNote String? @map("review_note") @db.Text /// 审核备注/拒绝原因
|
||
reviewTime DateTime? @map("review_time") /// 审核时间
|
||
reviewerId Int? @map("reviewer_id") /// 审核人 ID
|
||
machineReviewResult String? @map("machine_review_result") /// 机器预审结果:safe/suspicious
|
||
machineReviewNote String? @map("machine_review_note") @db.Text /// 机器预审备注
|
||
isRecommended Boolean @default(false) @map("is_recommended") /// 是否推荐
|
||
// 统计字段(冗余,提升查询性能)
|
||
viewCount Int @default(0) @map("view_count")
|
||
likeCount Int @default(0) @map("like_count")
|
||
favoriteCount Int @default(0) @map("favorite_count")
|
||
commentCount Int @default(0) @map("comment_count")
|
||
shareCount Int @default(0) @map("share_count")
|
||
// AI 创作元数据
|
||
originalImageUrl String? @map("original_image_url") @db.Text /// 用户原画 URL
|
||
voiceInputUrl String? @map("voice_input_url") @db.Text /// 语音输入 URL
|
||
textInput String? @map("text_input") @db.Text /// 文字描述输入
|
||
aiMeta Json? @map("ai_meta") /// AI 生成的元数据(模型/参数等)
|
||
// 通用字段
|
||
publishTime DateTime? @map("publish_time") /// 发布时间
|
||
isDeleted Int @default(0) @map("is_deleted") /// 软删除标记
|
||
createTime DateTime @default(now()) @map("create_time")
|
||
modifyTime DateTime @updatedAt @map("modify_time")
|
||
|
||
creator User @relation("UserWorkCreator", fields: [userId], references: [id], onDelete: Cascade)
|
||
pages UserWorkPage[] @relation("UserWorkPages")
|
||
tags WorkTagRelation[] @relation("UserWorkTags")
|
||
likes UserWorkLike[] @relation("UserWorkLikes")
|
||
favorites UserWorkFavorite[] @relation("UserWorkFavorites")
|
||
comments UserWorkComment[] @relation("UserWorkComments")
|
||
reports UserWorkReport[] @relation("UserWorkReports")
|
||
reviewLogs ContentReviewLog[] @relation("ContentReviewLogWork")
|
||
contestWorks ContestWork[] @relation("ContestWorkUserWork") /// 关联的活动参赛作品
|
||
|
||
@@index([userId, status])
|
||
@@index([status, publishTime])
|
||
@@index([isRecommended, publishTime])
|
||
@@map("user_works")
|
||
}
|
||
|
||
/// 绘本分页内容
|
||
model UserWorkPage {
|
||
id Int @id @default(autoincrement())
|
||
workId Int @map("work_id") /// 作品 ID
|
||
pageNo Int @map("page_no") /// 页码(从 1 开始)
|
||
imageUrl String? @map("image_url") @db.Text /// 页面插图 URL
|
||
text String? @db.Text /// 页面文字
|
||
audioUrl String? @map("audio_url") @db.Text /// 页面配音 URL
|
||
|
||
work UserWork @relation("UserWorkPages", fields: [workId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([workId, pageNo])
|
||
@@map("user_work_pages")
|
||
}
|
||
|
||
// ==================== 标签体系 ====================
|
||
|
||
/// 作品标签
|
||
model WorkTag {
|
||
id Int @id @default(autoincrement())
|
||
name String @unique @db.VarChar(50) /// 标签名称
|
||
category String? @db.VarChar(50) /// 所属分类(如:主题/风格/情感)
|
||
color String? @db.VarChar(20) /// 标签颜色(如:#6366f1)
|
||
sort Int @default(0) /// 排序权重
|
||
status String @default("enabled") /// 状态:enabled/disabled
|
||
usageCount Int @default(0) @map("usage_count") /// 使用次数(冗余)
|
||
createTime DateTime @default(now()) @map("create_time")
|
||
modifyTime DateTime @updatedAt @map("modify_time")
|
||
|
||
works WorkTagRelation[] @relation("WorkTagRelations")
|
||
|
||
@@index([category, sort])
|
||
@@map("work_tags")
|
||
}
|
||
|
||
/// 作品-标签关联
|
||
model WorkTagRelation {
|
||
id Int @id @default(autoincrement())
|
||
workId Int @map("work_id")
|
||
tagId Int @map("tag_id")
|
||
|
||
work UserWork @relation("UserWorkTags", fields: [workId], references: [id], onDelete: Cascade)
|
||
tag WorkTag @relation("WorkTagRelations", fields: [tagId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([workId, tagId])
|
||
@@map("work_tag_relations")
|
||
}
|
||
|
||
// ==================== 社区互动 ====================
|
||
|
||
/// 作品点赞
|
||
model UserWorkLike {
|
||
id Int @id @default(autoincrement())
|
||
userId Int @map("user_id")
|
||
workId Int @map("work_id")
|
||
createTime DateTime @default(now()) @map("create_time")
|
||
|
||
user User @relation("UserWorkLikeUser", fields: [userId], references: [id], onDelete: Cascade)
|
||
work UserWork @relation("UserWorkLikes", fields: [workId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([userId, workId])
|
||
@@map("user_work_likes")
|
||
}
|
||
|
||
/// 作品收藏
|
||
model UserWorkFavorite {
|
||
id Int @id @default(autoincrement())
|
||
userId Int @map("user_id")
|
||
workId Int @map("work_id")
|
||
createTime DateTime @default(now()) @map("create_time")
|
||
|
||
user User @relation("UserWorkFavoriteUser", fields: [userId], references: [id], onDelete: Cascade)
|
||
work UserWork @relation("UserWorkFavorites", fields: [workId], references: [id], onDelete: Cascade)
|
||
|
||
@@unique([userId, workId])
|
||
@@map("user_work_favorites")
|
||
}
|
||
|
||
/// 作品评论
|
||
model UserWorkComment {
|
||
id Int @id @default(autoincrement())
|
||
workId Int @map("work_id")
|
||
userId Int @map("user_id")
|
||
parentId Int? @map("parent_id") /// 父评论 ID(支持回复嵌套)
|
||
content String @db.Text /// 评论内容
|
||
status String @default("pending") /// 状态:pending/approved/rejected
|
||
createTime DateTime @default(now()) @map("create_time")
|
||
|
||
user User @relation("UserWorkCommentUser", fields: [userId], references: [id], onDelete: Cascade)
|
||
work UserWork @relation("UserWorkComments", fields: [workId], references: [id], onDelete: Cascade)
|
||
parent UserWorkComment? @relation("CommentReplies", fields: [parentId], references: [id], onDelete: SetNull)
|
||
replies UserWorkComment[] @relation("CommentReplies")
|
||
|
||
@@index([workId, status, createTime])
|
||
@@map("user_work_comments")
|
||
}
|
||
|
||
/// 作品举报
|
||
model UserWorkReport {
|
||
id Int @id @default(autoincrement())
|
||
reporterId Int @map("reporter_id") /// 举报人
|
||
targetType String @map("target_type") /// 举报类型:work/comment/user
|
||
targetId Int @map("target_id") /// 被举报对象 ID
|
||
targetUserId Int? @map("target_user_id") /// 被举报人 User.id
|
||
reason String @db.VarChar(200) /// 举报原因
|
||
description String? @db.Text /// 详细描述
|
||
status String @default("pending") /// 状态:pending/handled/ignored
|
||
handleAction String? @map("handle_action") /// 处理操作:takedown/warn/ban/ignore
|
||
handleNote String? @map("handle_note") @db.Text /// 处理备注
|
||
handlerId Int? @map("handler_id") /// 处理人 ID
|
||
handleTime DateTime? @map("handle_time") /// 处理时间
|
||
createTime DateTime @default(now()) @map("create_time")
|
||
|
||
reporter User @relation("UserWorkReportReporter", fields: [reporterId], references: [id], onDelete: Cascade)
|
||
targetUser User? @relation("UserWorkReportTarget", fields: [targetUserId], references: [id], onDelete: SetNull)
|
||
work UserWork? @relation("UserWorkReports", fields: [targetId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([status, createTime])
|
||
@@index([targetType, targetId])
|
||
@@map("user_work_reports")
|
||
}
|
||
|
||
// ==================== 内容审核日志 ====================
|
||
|
||
/// 审核操作日志
|
||
model ContentReviewLog {
|
||
id Int @id @default(autoincrement())
|
||
targetType String @map("target_type") /// 审核类型:work/comment
|
||
targetId Int @map("target_id") /// 审核对象 ID
|
||
workId Int? @map("work_id") /// 关联作品 ID(方便查询)
|
||
action String /// 操作:approve/reject/takedown/restore
|
||
reason String? @db.Text /// 原因
|
||
note String? @db.Text /// 备注
|
||
operatorId Int @map("operator_id") /// 操作人 ID
|
||
createTime DateTime @default(now()) @map("create_time")
|
||
|
||
operator User @relation("ContentReviewLogOperator", fields: [operatorId], references: [id], onDelete: Cascade)
|
||
work UserWork? @relation("ContentReviewLogWork", fields: [workId], references: [id], onDelete: SetNull)
|
||
|
||
@@index([targetType, targetId])
|
||
@@index([workId])
|
||
@@map("content_review_logs")
|
||
}
|