tyt-api-nest/prisma/schema.prisma
EL 73082225f6 "1. 新增系统字典与全局植入目录相关表结构及迁移
2. 扩展患者手术与材料模型,更新种子数据
3. 新增字典模块,增强设备植入目录管理能力
4. 重构患者后台服务与表单链路,统一权限与参数校验
5. 管理台新增字典页面并改造患者/设备页面与路由权限
6. 补充字典及相关领域 e2e 测试并更新文档"
2026-03-19 20:42:17 +08:00

251 lines
8.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
}
// 兼容 seed 脚本在 Node.js 直接运行时使用 @prisma/client runtime。
generator seed_client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
}
// 角色枚举:用于鉴权与数据可见性控制。
enum Role {
SYSTEM_ADMIN
HOSPITAL_ADMIN
DIRECTOR
LEADER
DOCTOR
ENGINEER
}
// 设备状态枚举:表示设备是否处于使用中。
enum DeviceStatus {
ACTIVE
INACTIVE
}
// 任务状态枚举:定义任务流转状态机。
enum TaskStatus {
PENDING
ACCEPTED
COMPLETED
CANCELLED
}
// 医学字典类型:驱动患者手术表单中的单选/多选项。
enum DictionaryType {
PRIMARY_DISEASE
HYDROCEPHALUS_TYPE
SHUNT_MODE
PROXIMAL_PUNCTURE_AREA
VALVE_PLACEMENT_SITE
DISTAL_SHUNT_DIRECTION
}
// 医院主表:多租户顶层实体。
model Hospital {
id Int @id @default(autoincrement())
name String
departments Department[]
users User[]
patients Patient[]
tasks Task[]
}
// 科室表:归属于医院。
model Department {
id Int @id @default(autoincrement())
name String
hospitalId Int
hospital Hospital @relation(fields: [hospitalId], references: [id])
groups Group[]
users User[]
@@index([hospitalId])
}
// 小组表:归属于科室。
model Group {
id Int @id @default(autoincrement())
name String
departmentId Int
department Department @relation(fields: [departmentId], references: [id])
users User[]
@@index([departmentId])
}
// 用户表:支持后台密码登录与小程序 openId。
model User {
id Int @id @default(autoincrement())
name String
phone String
// 后台登录密码哈希bcrypt
passwordHash String?
// 该时间点之前签发的 token 一律失效。
tokenValidAfter DateTime @default(now())
openId String? @unique
role Role
hospitalId Int?
departmentId Int?
groupId Int?
hospital Hospital? @relation(fields: [hospitalId], references: [id])
department Department? @relation(fields: [departmentId], references: [id])
// 小组删除必须先清理成员,避免静默把用户 groupId 置空。
group Group? @relation(fields: [groupId], references: [id], onDelete: Restrict)
doctorPatients Patient[] @relation("DoctorPatients")
createdTasks Task[] @relation("TaskCreator")
acceptedTasks Task[] @relation("TaskEngineer")
@@unique([phone, role, hospitalId])
@@index([phone])
@@index([hospitalId, role])
@@index([departmentId, role])
@@index([groupId, role])
}
// 患者表:院内患者档案,按医院隔离。
model Patient {
id Int @id @default(autoincrement())
name String
// 住院号:用于院内患者检索与病案关联。
inpatientNo String?
// 项目名称:用于区分患者所属项目/课题。
projectName String?
phone String
// 患者身份证号,录入与查询都使用原始证件号。
idCard String
hospitalId Int
doctorId Int
hospital Hospital @relation(fields: [hospitalId], references: [id])
doctor User @relation("DoctorPatients", fields: [doctorId], references: [id])
surgeries PatientSurgery[]
devices Device[]
@@index([phone, idCard])
@@index([hospitalId, doctorId])
@@index([inpatientNo])
}
// 患者手术表:保存每次分流/复手术档案。
model PatientSurgery {
id Int @id @default(autoincrement())
patientId Int
surgeryDate DateTime
surgeryName String
surgeonName String
// 术前测压:部分患者可为空。
preOpPressure Int?
// 原发病:前端单选,后端先按字符串存储,方便后续补字典。
primaryDisease String
// 脑积水类型:前端多选。
hydrocephalusTypes String[] @default([])
// 上次分流手术时间:无既往分流史时为空。
previousShuntSurgeryDate DateTime?
// 术前影像/资料:支持图片、视频等附件元数据。
preOpMaterials Json?
notes String?
createdAt DateTime @default(now())
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
devices Device[]
@@index([patientId, surgeryDate])
}
// 植入物型号字典:供前端单选型号后自动回填厂家与名称。
model ImplantCatalog {
id Int @id @default(autoincrement())
modelCode String @unique
manufacturer String
name String
// 可调压器械的可选挡位,由系统管理员维护。
pressureLevels Int[] @default([])
isPressureAdjustable Boolean @default(true)
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
devices Device[]
}
// 系统级字典项:由系统管理员维护,供患者手术表单选择使用。
model DictionaryItem {
id Int @id @default(autoincrement())
type DictionaryType
label String
sortOrder Int @default(0)
enabled Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([type, label])
@@index([type, enabled, sortOrder])
}
// 设备表:每次手术植入的设备实例,保留当前压力与历史调压记录。
model Device {
id Int @id @default(autoincrement())
snCode String @unique
currentPressure Int
status DeviceStatus @default(ACTIVE)
patientId Int
surgeryId Int?
implantCatalogId Int?
// 植入物快照:避免型号字典修改后影响历史病历。
implantModel String?
implantManufacturer String?
implantName String?
isPressureAdjustable Boolean @default(true)
// 二次手术后旧设备可标记弃用,但历史调压任务仍需保留。
isAbandoned Boolean @default(false)
shuntMode String?
proximalPunctureAreas String[] @default([])
valvePlacementSites String[] @default([])
distalShuntDirection String?
initialPressure Int?
implantNotes String?
labelImageUrl String?
patient Patient @relation(fields: [patientId], references: [id])
surgery PatientSurgery? @relation(fields: [surgeryId], references: [id], onDelete: SetNull)
implantCatalog ImplantCatalog? @relation(fields: [implantCatalogId], references: [id], onDelete: SetNull)
taskItems TaskItem[]
@@index([patientId, status])
@@index([surgeryId])
@@index([implantCatalogId])
@@index([patientId, isAbandoned])
}
// 主任务表:记录调压任务主单。
model Task {
id Int @id @default(autoincrement())
status TaskStatus @default(PENDING)
creatorId Int
engineerId Int?
hospitalId Int
createdAt DateTime @default(now())
creator User @relation("TaskCreator", fields: [creatorId], references: [id])
engineer User? @relation("TaskEngineer", fields: [engineerId], references: [id])
hospital Hospital @relation(fields: [hospitalId], references: [id])
items TaskItem[]
@@index([hospitalId, status, createdAt])
}
// 任务明细表:一个任务可包含多个设备调压项。
model TaskItem {
id Int @id @default(autoincrement())
taskId Int
deviceId Int
oldPressure Int
targetPressure Int
task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
device Device @relation(fields: [deviceId], references: [id])
@@index([taskId])
@@index([deviceId])
}