2. 扩展患者手术与材料模型,更新种子数据 3. 新增字典模块,增强设备植入目录管理能力 4. 重构患者后台服务与表单链路,统一权限与参数校验 5. 管理台新增字典页面并改造患者/设备页面与路由权限 6. 补充字典及相关领域 e2e 测试并更新文档"
251 lines
8.0 KiB
Plaintext
251 lines
8.0 KiB
Plaintext
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])
|
||
}
|