Fix: PDF generado dinámicamente con diseño congruente a la app
This commit is contained in:
@@ -112,6 +112,25 @@ function calcularEstadoLaboratorio(parametro: string, valor: string): 'Normal' |
|
||||
return 'Normal';
|
||||
}
|
||||
|
||||
function wrapText(text: string, font: any, fontSize: number, maxWidth: number): string[] {
|
||||
const words = text.split(' ');
|
||||
const lines: string[] = [];
|
||||
let currentLine = '';
|
||||
|
||||
for (const word of words) {
|
||||
const testLine = currentLine ? `${currentLine} ${word}` : word;
|
||||
const testWidth = font.widthOfTextAtSize(testLine, fontSize);
|
||||
if (testWidth > maxWidth && currentLine) {
|
||||
lines.push(currentLine);
|
||||
currentLine = word;
|
||||
} else {
|
||||
currentLine = testLine;
|
||||
}
|
||||
}
|
||||
if (currentLine) lines.push(currentLine);
|
||||
return lines;
|
||||
}
|
||||
|
||||
export function HistoriaClinica({
|
||||
internacion,
|
||||
paciente,
|
||||
@@ -311,28 +330,104 @@ export function HistoriaClinica({
|
||||
<Button variant="outline" className="bg-blue-50 border-blue-300 text-blue-700 hover:bg-blue-100" onClick={async (e) => {
|
||||
e.stopPropagation();
|
||||
try {
|
||||
const existingPdfBytes = await fetch('/MODELO_INGRESO.pdf').then(res => res.arrayBuffer());
|
||||
const pdfDoc = await PDFDocument.load(existingPdfBytes);
|
||||
const form = pdfDoc.getForm();
|
||||
const { PDFDocument, StandardFonts, rgb } = await import('pdf-lib');
|
||||
const pdfDoc = await PDFDocument.create();
|
||||
const page = pdfDoc.addPage([595, 842]);
|
||||
const { width, height } = page.getSize();
|
||||
|
||||
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
|
||||
const fontBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
|
||||
|
||||
const colorPrimary = rgb(0.18, 0.34, 0.55);
|
||||
const colorText = rgb(0.13, 0.13, 0.13);
|
||||
const colorGray = rgb(0.45, 0.45, 0.45);
|
||||
const colorLightGray = rgb(0.92, 0.92, 0.92);
|
||||
|
||||
const edad = paciente.fechaNacimiento ? calcularEdad(paciente.fechaNacimiento) : '';
|
||||
const fields = [
|
||||
{ name: 'cama', value: String(cama?.numero || '') },
|
||||
{ name: 'apellido', value: String(paciente.apellido || '') },
|
||||
{ name: 'nombre', value: String(paciente.nombre || '') },
|
||||
{ name: 'edad', value: String(edad) },
|
||||
{ name: 'dni', value: String(paciente.dni || '') },
|
||||
{ name: 'fechaIngreso', value: String(internacion.fechaIngreso || '') },
|
||||
{ name: 'motivoConsulta', value: String(internacion.motivoConsulta || '') },
|
||||
{ name: 'enfermedadActual', value: String(internacion.enfermedadActual || '') },
|
||||
{ name: 'antecedentes', value: String(internacion.antecedentesEnfermedadActual || '') },
|
||||
{ name: 'diagnostico', value: String(internacion.diagnosticoIngreso || '') },
|
||||
];
|
||||
for (const field of fields) {
|
||||
try {
|
||||
const formField = form.getTextField(field.name);
|
||||
if (formField) formField.setText(field.value);
|
||||
} catch (e) { }
|
||||
const fechaFormateada = formatDateDDMMYYYY(internacion.fechaIngreso);
|
||||
|
||||
// Header
|
||||
page.drawRectangle({ x: 0, y: height - 80, width, height: 80, color: colorPrimary });
|
||||
page.drawText('FORMULARIO DE INGRESO', { x: 180, y: height - 45, size: 20, font: fontBold, color: rgb(1, 1, 1) });
|
||||
page.drawText('Historia Clínica Electrónica - Servicio de Clínica Médica', { x: 110, y: height - 65, size: 10, font, color: rgb(0.85, 0.85, 0.85) });
|
||||
page.drawText('Hospital Santojanni', { x: 50, y: height - 90, size: 9, font, color: colorGray });
|
||||
|
||||
let y = height - 125;
|
||||
|
||||
// Datos del Paciente
|
||||
page.drawRectangle({ x: 45, y: y - 8, width: 505, height: 24, color: colorLightGray });
|
||||
page.drawText('DATOS DEL PACIENTE', { x: 50, y: y, size: 12, font: fontBold, color: colorPrimary });
|
||||
y -= 35;
|
||||
|
||||
page.drawText('Cama:', { x: 50, y, size: 10, font: fontBold, color: colorGray });
|
||||
page.drawText(cama?.numero || 'N/A', { x: 120, y, size: 10, font, color: colorText });
|
||||
page.drawText('Fecha de Ingreso:', { x: 280, y, size: 10, font: fontBold, color: colorGray });
|
||||
page.drawText(fechaFormateada, { x: 390, y, size: 10, font, color: colorText });
|
||||
y -= 25;
|
||||
|
||||
page.drawText('Apellido:', { x: 50, y, size: 10, font: fontBold, color: colorGray });
|
||||
page.drawText(paciente.apellido || '', { x: 120, y, size: 10, font, color: colorText });
|
||||
page.drawText('Nombre:', { x: 280, y, size: 10, font: fontBold, color: colorGray });
|
||||
page.drawText(paciente.nombre || '', { x: 350, y, size: 10, font, color: colorText });
|
||||
y -= 25;
|
||||
|
||||
page.drawText('DNI:', { x: 50, y, size: 10, font: fontBold, color: colorGray });
|
||||
page.drawText(paciente.dni || '', { x: 120, y, size: 10, font, color: colorText });
|
||||
page.drawText('Edad:', { x: 280, y, size: 10, font: fontBold, color: colorGray });
|
||||
page.drawText(edad ? `${edad} años` : '', { x: 330, y, size: 10, font, color: colorText });
|
||||
y -= 40;
|
||||
|
||||
// Datos Clínicos
|
||||
page.drawRectangle({ x: 45, y: y - 8, width: 505, height: 24, color: colorLightGray });
|
||||
page.drawText('DATOS CLÍNICOS', { x: 50, y: y, size: 12, font: fontBold, color: colorPrimary });
|
||||
y -= 35;
|
||||
|
||||
page.drawText('Motivo de Consulta:', { x: 50, y, size: 10, font: fontBold, color: colorGray });
|
||||
y -= 18;
|
||||
const motivoLines = wrapText(internacion.motivoConsulta || 'Sin información', font, 10, 480);
|
||||
for (const line of motivoLines.slice(0, 4)) {
|
||||
page.drawText(line, { x: 50, y, size: 10, font, color: colorText });
|
||||
y -= 14;
|
||||
}
|
||||
y -= 10;
|
||||
if (motivoLines.length > 4) y -= (motivoLines.length - 4) * 14;
|
||||
|
||||
page.drawText('Enfermedad Actual:', { x: 50, y, size: 10, font: fontBold, color: colorGray });
|
||||
y -= 18;
|
||||
const enfermedadLines = wrapText(internacion.enfermedadActual || 'Sin información', font, 10, 480);
|
||||
for (const line of enfermedadLines.slice(0, 4)) {
|
||||
page.drawText(line, { x: 50, y, size: 10, font, color: colorText });
|
||||
y -= 14;
|
||||
}
|
||||
y -= 10;
|
||||
if (enfermedadLines.length > 4) y -= (enfermedadLines.length - 4) * 14;
|
||||
|
||||
page.drawText('Antecedentes de la Enfermedad Actual:', { x: 50, y, size: 10, font: fontBold, color: colorGray });
|
||||
y -= 18;
|
||||
const antecedentesLines = wrapText(internacion.antecedentesEnfermedadActual || 'Sin antecedentes registrados', font, 10, 480);
|
||||
for (const line of antecedentesLines.slice(0, 4)) {
|
||||
page.drawText(line, { x: 50, y, size: 10, font, color: colorText });
|
||||
y -= 14;
|
||||
}
|
||||
y -= 10;
|
||||
if (antecedentesLines.length > 4) y -= (antecedentesLines.length - 4) * 14;
|
||||
|
||||
page.drawText('Diagnóstico de Ingreso:', { x: 50, y, size: 10, font: fontBold, color: colorGray });
|
||||
y -= 18;
|
||||
const diagnosticoLines = wrapText(internacion.diagnosticoIngreso || 'Sin diagnóstico', font, 10, 480);
|
||||
for (const line of diagnosticoLines.slice(0, 3)) {
|
||||
page.drawText(line, { x: 50, y, size: 10, font, color: colorText });
|
||||
y -= 14;
|
||||
}
|
||||
|
||||
// Footer
|
||||
y -= 20;
|
||||
page.drawLine({ start: { x: 50, y }, end: { x: 250, y }, thickness: 0.5, color: colorGray });
|
||||
page.drawText('Firma del Médico', { x: 50, y: y - 15, size: 9, font, color: colorGray });
|
||||
page.drawLine({ start: { x: 320, y }, end: { x: 520, y }, thickness: 0.5, color: colorGray });
|
||||
page.drawText('Aclaración / Sello', { x: 320, y: y - 15, size: 9, font, color: colorGray });
|
||||
page.drawText('v1.0.0', { x: width - 60, y: 30, size: 8, font, color: colorGray });
|
||||
|
||||
const pdfBytes = await pdfDoc.save();
|
||||
const blob = new Blob([new Uint8Array(pdfBytes)], { type: 'application/pdf' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
Reference in New Issue
Block a user