tyt-api-nest/src/patients/patient-lifecycle.util.ts

164 lines
4.6 KiB
TypeScript

import { Prisma } from '../generated/prisma/client.js';
const IMPLANT_CATALOG_SELECT = {
id: true,
modelCode: true,
manufacturer: true,
name: true,
isValve: true,
pressureLevels: true,
isPressureAdjustable: true,
notes: true,
} as const;
export const PATIENT_LIFECYCLE_INCLUDE = {
hospital: { select: { id: true, name: true } },
doctor: { select: { departmentId: true, groupId: true } },
surgeries: {
include: {
devices: {
include: {
implantCatalog: {
select: IMPLANT_CATALOG_SELECT,
},
},
},
},
orderBy: { surgeryDate: 'desc' },
},
devices: {
include: {
surgery: {
select: {
id: true,
surgeryDate: true,
surgeryName: true,
},
},
implantCatalog: {
select: IMPLANT_CATALOG_SELECT,
},
taskItems: {
include: {
task: true,
},
},
},
},
} as const satisfies Prisma.PatientInclude;
export type PatientLifecycleSource = Prisma.PatientGetPayload<{
include: typeof PATIENT_LIFECYCLE_INCLUDE;
}>;
export function buildPatientLifecyclePayload(patient: PatientLifecycleSource) {
return {
patient: buildPatientLifecyclePatient(patient),
lifecycle: buildPatientLifecycleEvents(patient),
};
}
export function buildPatientLifecyclePatient(patient: PatientLifecycleSource) {
return {
id: toJsonNumber(patient.id),
name: patient.name,
inpatientNo: patient.inpatientNo,
phone: patient.phone,
projectName: patient.projectName,
};
}
export function buildPatientLifecycleEvents(patient: PatientLifecycleSource) {
const surgeryEvents = patient.surgeries.map((surgery, index, surgeries) => ({
eventType: 'SURGERY' as const,
occurredAt: surgery.surgeryDate,
hospital: patient.hospital,
surgery: {
id: toJsonNumber(surgery.id),
surgeryDate: surgery.surgeryDate,
surgeryName: surgery.surgeryName,
surgeonName: surgery.surgeonName,
primaryDisease: surgery.primaryDisease,
hydrocephalusTypes: surgery.hydrocephalusTypes,
previousShuntSurgeryDate: surgery.previousShuntSurgeryDate,
shuntSurgeryCount: surgeries.length - index,
},
devices: surgery.devices.map((device) => ({
id: toJsonNumber(device.id),
status: device.status,
isAbandoned: device.isAbandoned,
currentPressure: device.currentPressure,
initialPressure: device.initialPressure,
implantModel: device.implantModel,
implantManufacturer: device.implantManufacturer,
implantName: device.implantName,
isValve: device.isValve,
isPressureAdjustable: device.isPressureAdjustable,
shuntMode: device.shuntMode,
distalShuntDirection: device.distalShuntDirection,
proximalPunctureAreas: device.proximalPunctureAreas,
valvePlacementSites: device.valvePlacementSites,
implantCatalog: device.implantCatalog,
})),
}));
const taskEvents = patient.devices.flatMap((device) =>
device.taskItems.flatMap((taskItem) => {
if (!taskItem.task) {
return [];
}
const task = taskItem.task;
return [
{
eventType: 'TASK_PRESSURE_ADJUSTMENT' as const,
occurredAt: task.createdAt,
hospital: patient.hospital,
device: {
id: toJsonNumber(device.id),
status: device.status,
isAbandoned: device.isAbandoned,
currentPressure: device.currentPressure,
implantModel: device.implantModel,
implantManufacturer: device.implantManufacturer,
implantName: device.implantName,
isValve: device.isValve,
isPressureAdjustable: device.isPressureAdjustable,
},
surgery: device.surgery
? {
id: toJsonNumber(device.surgery.id),
surgeryDate: device.surgery.surgeryDate,
surgeryName: device.surgery.surgeryName,
}
: null,
task: {
id: toJsonNumber(task.id),
status: task.status,
createdAt: task.createdAt,
},
taskItem: {
id: toJsonNumber(taskItem.id),
oldPressure: taskItem.oldPressure,
targetPressure: taskItem.targetPressure,
},
},
];
}),
);
return [...surgeryEvents, ...taskEvents].sort(
(left, right) =>
new Date(right.occurredAt).getTime() -
new Date(left.occurredAt).getTime(),
);
}
function toJsonNumber(value: number | bigint | null | undefined) {
if (value == null) {
return null;
}
return typeof value === 'bigint' ? Number(value) : value;
}