754 lines
30 KiB
HTML
754 lines
30 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="es">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<title>Generador HC Ingreso – Santojanni</title>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf-lib/1.17.1/pdf-lib.min.js"></script>
|
||
<style>
|
||
body { font-family: Arial, sans-serif; background: #f0f4f8; display: flex;
|
||
flex-direction: column; align-items: center; padding: 40px; }
|
||
h1 { font-size: 1.2rem; color: #1a3a5c; margin-bottom: 8px; }
|
||
p { color: #555; font-size: .9rem; margin-bottom: 24px; }
|
||
button { background: #1a3a5c; color: #fff; border: none; padding: 14px 36px;
|
||
font-size: 1rem; border-radius: 6px; cursor: pointer; }
|
||
button:hover { background: #25547a; }
|
||
#status { margin-top: 16px; font-size: .85rem; color: #444; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>Historia Clínica de Ingreso – Hospital Donación F. Santojanni</h1>
|
||
<p>Hace clic en el botón para generar el PDF con las 5 páginas del formulario en blanco.</p>
|
||
<button onclick="generarPDF()">Generar PDF</button>
|
||
<div id="status"></div>
|
||
|
||
<script>
|
||
/* ============================================================
|
||
CONSTANTES GLOBALES
|
||
============================================================ */
|
||
const A4W = 595.28;
|
||
const A4H = 841.89;
|
||
const ML = 25; // margen izquierdo
|
||
const MR = 25; // margen derecho
|
||
const INNER = A4W - ML - MR; // ancho útil: 545.28
|
||
|
||
// Colores
|
||
const NEGRO = PDFLib.rgb(0, 0, 0);
|
||
const GRIS_HEAD = PDFLib.rgb(0.82, 0.82, 0.82); // fondo encabezados de sección
|
||
const GRIS_LABEL = PDFLib.rgb(0.93, 0.93, 0.93); // fondo celdas etiqueta
|
||
const BLANCO = PDFLib.rgb(1, 1, 1);
|
||
|
||
/* ============================================================
|
||
HELPERS
|
||
============================================================ */
|
||
|
||
/** Dibuja un rectángulo con borde negro (relleno opcional). */
|
||
function rect(page, x, y, w, h, { fill = null, borderWidth = 0.5 } = {}) {
|
||
if (fill) page.drawRectangle({ x, y, width: w, height: h, color: fill });
|
||
page.drawRectangle({ x, y, width: w, height: h,
|
||
borderColor: NEGRO, borderWidth, color: fill ?? PDFLib.rgb(1,1,1) });
|
||
}
|
||
|
||
/** Dibuja texto centrado horizontalmente en un rango x→x+w. */
|
||
function textCenter(page, txt, x, y, w, { font, size = 8, color = NEGRO } = {}) {
|
||
const tw = font.widthOfTextAtSize(txt, size);
|
||
page.drawText(txt, { x: x + (w - tw) / 2, y, size, font, color });
|
||
}
|
||
|
||
/** Caja de sección con fondo gris y título centrado en negrita. */
|
||
function sectionHeader(page, label, x, y, w, h = 14, { bold, regular } = {}) {
|
||
rect(page, x, y, w, h, { fill: GRIS_HEAD });
|
||
textCenter(page, label, x, y + 3, w, { font: bold, size: 8 });
|
||
return y - h; // retorna la Y del borde inferior de la caja
|
||
}
|
||
|
||
/** Celda con etiqueta izquierda (gris) y área de escritura (blanca). */
|
||
function labelCell(page, label, x, y, labelW, totalW, h, { regular, bold, fontSize = 7 } = {}) {
|
||
// fondo etiqueta
|
||
page.drawRectangle({ x, y, width: labelW, height: h, color: GRIS_LABEL });
|
||
page.drawRectangle({ x, y, width: labelW, height: h,
|
||
borderColor: NEGRO, borderWidth: 0.4, color: GRIS_LABEL });
|
||
// área escribible
|
||
page.drawRectangle({ x: x + labelW, y, width: totalW - labelW, height: h,
|
||
borderColor: NEGRO, borderWidth: 0.4, color: BLANCO });
|
||
page.drawText(label, { x: x + 2, y: y + 2.5, size: fontSize, font: regular, color: NEGRO });
|
||
}
|
||
|
||
/** Línea horizontal simple. */
|
||
function hLine(page, x, y, w) {
|
||
page.drawLine({ start: { x, y }, end: { x: x + w, y }, thickness: 0.4, color: NEGRO });
|
||
}
|
||
|
||
/** Línea vertical simple. */
|
||
function vLine(page, x, y1, y2) {
|
||
page.drawLine({ start: { x, y: y1 }, end: { x, y: y2 }, thickness: 0.4, color: NEGRO });
|
||
}
|
||
|
||
/* ============================================================
|
||
CABECERA COMÚN (páginas 1-5)
|
||
============================================================ */
|
||
function drawPageHeader(page, pageNum, bold, regular) {
|
||
const top = A4H - 18;
|
||
|
||
// Logo placeholder izquierdo (círculo con "BA")
|
||
page.drawCircle({ x: ML + 12, y: top, size: 11, color: PDFLib.rgb(0.2, 0.4, 0.7) });
|
||
page.drawText("BA", { x: ML + 6, y: top - 4, size: 7, font: bold, color: BLANCO });
|
||
|
||
// Texto central
|
||
const titulo1 = "HOSPITAL DONACIÓN F. SANTOJANNI – DIVISIÓN CLÍNICA MÉDICA";
|
||
const titulo2 = "HISTORIA CLÍNICA DE INGRESO";
|
||
const tw1 = bold.widthOfTextAtSize(titulo1, 9);
|
||
const tw2 = bold.widthOfTextAtSize(titulo2, 9);
|
||
page.drawText(titulo1, { x: (A4W - tw1) / 2, y: top + 4, size: 9, font: bold, color: NEGRO });
|
||
page.drawText(titulo2, { x: (A4W - tw2) / 2, y: top - 6, size: 9, font: bold, color: NEGRO });
|
||
|
||
// Logo placeholder derecho
|
||
page.drawCircle({ x: A4W - ML - 12, y: top, size: 11, color: PDFLib.rgb(0.2, 0.4, 0.7) });
|
||
page.drawText("H", { x: A4W - ML - 15, y: top - 4, size: 7, font: bold, color: BLANCO });
|
||
|
||
// Número de página
|
||
const pTxt = `${pageNum}`;
|
||
page.drawText(pTxt, { x: (A4W - regular.widthOfTextAtSize(pTxt, 8)) / 2,
|
||
y: 15, size: 8, font: regular, color: NEGRO });
|
||
|
||
// Línea separadora
|
||
hLine(page, ML, A4H - 30, INNER);
|
||
|
||
return A4H - 38; // Y de inicio del contenido
|
||
}
|
||
|
||
/* ============================================================
|
||
PÁGINA 1 – Datos filiatorios / Motivo / Enfermedad actual
|
||
============================================================ */
|
||
async function buildPage1(pdfDoc, bold, regular) {
|
||
const page = pdfDoc.addPage([A4W, A4H]);
|
||
let y = drawPageHeader(page, 1, bold, regular);
|
||
|
||
/* --- DATOS FILIATORIOS --- */
|
||
y = sectionHeader(page, "DATOS FILIATORIOS", ML, y, INNER, 14, { bold, regular });
|
||
|
||
// Fila 1: fecha ingreso hospital | fecha ingreso clínica médica | habitación
|
||
const colW = [INNER * 0.30, INNER * 0.42, INNER * 0.28];
|
||
const rowH = 12;
|
||
let cx = ML;
|
||
["FECHA DE INGRESO AL HOSPITAL (DD/MM/AA)", "FECHA DE INGRESO A CLÍNICA MÉDICA (DD/MM/AA)", "HABITACIÓN"].forEach((lbl, i) => {
|
||
rect(page, cx, y - rowH, colW[i], rowH);
|
||
page.drawText(lbl, { x: cx + 2, y: y - rowH + 3.5, size: 5.5, font: regular, color: NEGRO });
|
||
cx += colW[i];
|
||
});
|
||
// Fecha clínica médica pre-cargada (16/04/2026)
|
||
const fechaTxt = "16/04/2026";
|
||
const mid = ML + colW[0];
|
||
page.drawText(fechaTxt, { x: mid + (colW[1] - bold.widthOfTextAtSize(fechaTxt, 9)) / 2,
|
||
y: y - rowH + 3, size: 9, font: bold, color: NEGRO });
|
||
y -= rowH;
|
||
|
||
// Fila 2: Apellido y nombre | DNI/CI
|
||
const mitad = INNER / 2;
|
||
labelCell(page, "APELLIDO y NOMBRE", ML, y - rowH, 45, mitad, rowH, { regular, bold });
|
||
labelCell(page, "DNI / C.I", ML + mitad, y - rowH, 30, mitad, rowH, { regular, bold });
|
||
y -= rowH;
|
||
|
||
// Fila 3
|
||
labelCell(page, "FECHA DE NACIMIENTO", ML, y - rowH, 50, mitad, rowH, { regular, bold });
|
||
labelCell(page, "HISTORIA CLINICA", ML + mitad, y - rowH, 42, mitad, rowH, { regular, bold });
|
||
y -= rowH;
|
||
|
||
// Fila 4
|
||
labelCell(page, "EDAD", ML, y - rowH, 22, mitad, rowH, { regular, bold });
|
||
labelCell(page, "OBRA SOCIAL", ML + mitad, y - rowH, 42, mitad, rowH, { regular, bold });
|
||
y -= rowH;
|
||
|
||
// Fila 5
|
||
labelCell(page, "NACIONALIDAD", ML, y - rowH, 42, mitad, rowH, { regular, bold });
|
||
// DERIVADO DE: con valor "Guardia Externa"
|
||
labelCell(page, "DERIVADO DE:", ML + mitad, y - rowH, 42, mitad, rowH, { regular, bold });
|
||
page.drawText("Guardia Externa", { x: ML + mitad + 44, y: y - rowH + 3,
|
||
size: 7, font: regular, color: NEGRO });
|
||
y -= rowH;
|
||
|
||
// Fila 6
|
||
labelCell(page, "DIRECCIÓN", ML, y - rowH, 30, mitad, rowH, { regular, bold });
|
||
labelCell(page, "APACHE / MORTALIDAD", ML + mitad, y - rowH, 55, mitad, rowH, { regular, bold });
|
||
y -= rowH;
|
||
|
||
// Fila 7: Teléfono de contacto (ancho completo)
|
||
labelCell(page, "Teléfono de contacto:", ML, y - rowH, 60, INNER, rowH, { regular, bold });
|
||
y -= rowH + 4;
|
||
|
||
/* --- MOTIVO DE CONSULTA --- */
|
||
y = sectionHeader(page, "MOTIVO DE CONSULTA", ML, y, INNER, 13, { bold, regular });
|
||
const motivoH = 24;
|
||
rect(page, ML, y - motivoH, INNER, motivoH);
|
||
y -= motivoH + 4;
|
||
|
||
/* --- ENFERMEDAD ACTUAL --- */
|
||
y = sectionHeader(page, "ENFERMEDAD ACTUAL", ML, y, INNER, 13, { bold, regular });
|
||
const eaH = 220;
|
||
rect(page, ML, y - eaH, INNER, eaH);
|
||
y -= eaH + 4;
|
||
|
||
/* --- ANTECEDENTES DE ENFERMEDAD ACTUAL --- */
|
||
y = sectionHeader(page, "ANTECEDENTES DE ENFERMEDAD ACTUAL", ML, y, INNER, 13, { bold, regular });
|
||
const antH = Math.max(y - 30, 40); // lo que quede en la página
|
||
rect(page, ML, y - antH, INNER, antH);
|
||
}
|
||
|
||
/* ============================================================
|
||
PÁGINA 2 – Antecedentes personales / Medicación / Hábitos
|
||
============================================================ */
|
||
async function buildPage2(pdfDoc, bold, regular) {
|
||
const page = pdfDoc.addPage([A4W, A4H]);
|
||
let y = drawPageHeader(page, 2, bold, regular);
|
||
|
||
/* --- ANTECEDENTES PERSONALES --- */
|
||
y = sectionHeader(page, "ANTECEDENTES PERSONALES", ML, y, INNER, 13, { bold, regular });
|
||
|
||
const apSections = [
|
||
{ label: "CLÍNICOS", h: 38 },
|
||
{ label: "QUIRÚRGICOS /\nTRAUMATOLÓGICOS", h: 38 },
|
||
{ label: "GINECO-OBSTÉTRICOS", h: 38 },
|
||
{ label: "ALÉRGICOS /\nTRANSFUSIONALES", h: 38 },
|
||
];
|
||
const labelW = 80;
|
||
apSections.forEach(sec => {
|
||
rect(page, ML, y - sec.h, labelW, sec.h, { fill: GRIS_LABEL });
|
||
rect(page, ML + labelW, y - sec.h, INNER - labelW, sec.h);
|
||
// texto label multilinea centrado verticalmente
|
||
sec.label.split("\n").forEach((ln, i) => {
|
||
page.drawText(ln, { x: ML + 2, y: y - sec.h / 2 + (sec.label.includes("\n") ? (i === 0 ? 5 : -4) : -2),
|
||
size: 7, font: regular, color: NEGRO });
|
||
});
|
||
y -= sec.h;
|
||
});
|
||
y -= 4;
|
||
|
||
/* --- MEDICACIÓN HABITUAL --- */
|
||
y = sectionHeader(page, "MEDICACIÓN HABITUAL", ML, y, INNER, 13, { bold, regular });
|
||
const medH = 9;
|
||
const medColW = INNER / 2;
|
||
for (let i = 1; i <= 20; i++) {
|
||
const col = i <= 10 ? 0 : 1;
|
||
const row = i <= 10 ? i - 1 : i - 11;
|
||
const cx2 = ML + col * medColW;
|
||
const cy = y - row * medH - medH;
|
||
// número
|
||
rect(page, cx2, cy, 10, medH);
|
||
page.drawText(`${i}`, { x: cx2 + 2, y: cy + 2, size: 6.5, font: regular, color: NEGRO });
|
||
// área
|
||
rect(page, cx2 + 10, cy, medColW - 10, medH);
|
||
}
|
||
y -= 10 * medH + 4;
|
||
|
||
/* --- HÁBITOS + ANTECEDENTES HEREDOFAMILIARES (lado a lado) --- */
|
||
const halfW = INNER / 2 - 2;
|
||
const habX = ML;
|
||
const aheX = ML + halfW + 4;
|
||
|
||
// Hábitos
|
||
y = sectionHeader(page, "HÁBITOS", habX, y, halfW, 13, { bold, regular });
|
||
// tabla de hábitos
|
||
const habRows = [
|
||
["Apetito", "Conservado", "Sí"],
|
||
["Sueño", "Conservado", "Sí"],
|
||
["Catarsis", "Conservado", "Sí"],
|
||
["Diuresis", "Conservado", "Sí"],
|
||
];
|
||
let hy = y;
|
||
const hRowH = 9;
|
||
habRows.forEach(([item, val, check]) => {
|
||
const widths = [35, 40, 12, halfW - 87];
|
||
let hx = habX;
|
||
[item, val, check, "Aclare:"].forEach((txt, i) => {
|
||
rect(page, hx, hy - hRowH, widths[i], hRowH);
|
||
page.drawText(txt, { x: hx + 2, y: hy - hRowH + 2.5, size: 6, font: regular, color: NEGRO });
|
||
hx += widths[i];
|
||
});
|
||
hy -= hRowH;
|
||
});
|
||
hy -= 2;
|
||
// Tabaquismo / Alcoholismo / Drogas
|
||
const addictionRows = [
|
||
{ label: "Tabaquismo", check: "Sí", unit: "paq/y" },
|
||
{ label: "Alcoholismo", check: "No", unit: "gr/d" },
|
||
{ label: "Drogas\nilícitas", check: "No", unit: "Cuales" },
|
||
];
|
||
addictionRows.forEach(row => {
|
||
const aw = [40, 14, halfW - 54];
|
||
let ax = habX;
|
||
[row.label, row.check, row.unit + " Desde/Hasta"].forEach((txt, i) => {
|
||
rect(page, ax, hy - hRowH * 1.5, aw[i], hRowH * 1.5);
|
||
page.drawText(txt.split("\n")[0], { x: ax + 2, y: hy - hRowH * 1.5 + 6, size: 6, font: regular, color: NEGRO });
|
||
if (txt.includes("\n")) page.drawText(txt.split("\n")[1], { x: ax + 2, y: hy - hRowH * 1.5 + 1, size: 6, font: regular, color: NEGRO });
|
||
ax += aw[i];
|
||
});
|
||
hy -= hRowH * 1.5;
|
||
});
|
||
|
||
// Antecedentes heredofamiliares (misma Y de inicio)
|
||
let aheY = y + 13; // misma línea que "HÁBITOS" header
|
||
aheY = sectionHeader(page, "ANTECEDENTES HEREDOFAMILIARES", aheX, aheY, halfW, 13, { bold, regular });
|
||
|
||
const aheRows = [
|
||
{ label: "Madre", extra: ["Vive", "No", "Años:"] },
|
||
{ label: "Patología:" },
|
||
{ label: "Padre", extra: ["Vive", "No", "Años:"] },
|
||
{ label: "Patología:" },
|
||
{ label: "Hermanos", extra: ["N.º", "", "Años:"] },
|
||
{ label: "Patología:" },
|
||
{ label: "Hijos", extra: ["N.º", "", "Años:"] },
|
||
{ label: "Patología:" },
|
||
{ label: "Comentarios" },
|
||
];
|
||
const aRowH = 10;
|
||
aheRows.forEach(row => {
|
||
rect(page, aheX, aheY - aRowH, halfW, aRowH);
|
||
page.drawText(row.label, { x: aheX + 2, y: aheY - aRowH + 2.5, size: 6.5, font: regular, color: NEGRO });
|
||
if (row.extra) {
|
||
const ex = row.extra;
|
||
const ew = [(halfW - 50) / 3, (halfW - 50) / 3, (halfW - 50) / 3];
|
||
let ex2 = aheX + 50;
|
||
ex.forEach((txt, i) => {
|
||
rect(page, ex2, aheY - aRowH, ew[i], aRowH);
|
||
page.drawText(txt, { x: ex2 + 2, y: aheY - aRowH + 2.5, size: 6, font: regular, color: NEGRO });
|
||
ex2 += ew[i];
|
||
});
|
||
}
|
||
aheY -= aRowH;
|
||
});
|
||
}
|
||
|
||
/* ============================================================
|
||
PÁGINA 3 – Contactos / Vacunas / Determinantes / Examen físico
|
||
============================================================ */
|
||
async function buildPage3(pdfDoc, bold, regular) {
|
||
const page = pdfDoc.addPage([A4W, A4H]);
|
||
let y = drawPageHeader(page, 3, bold, regular);
|
||
|
||
const halfW = INNER / 2 - 2;
|
||
/* --- CONTACTOS + VACUNACIÓN (lado a lado) --- */
|
||
// Headers a la misma Y
|
||
const yStart = y;
|
||
sectionHeader(page, "CONTACTOS", ML, yStart, halfW, 13, { bold, regular });
|
||
sectionHeader(page, "VACUNACIÓN/SEROLOGÍAS", ML + halfW + 4, yStart, halfW, 13, { bold, regular });
|
||
y -= 13;
|
||
|
||
// Contactos
|
||
const contactos = [
|
||
{ label: "Animales", val: "No", extra: "Cuáles?" },
|
||
{ label: "TBC", val: "No", extra: "Cuándo?" },
|
||
{ label: "Chagas", val: "No", extra: "Cómo?" },
|
||
{ label: "HIV", val: "No", extra: "Conducta\nriesgo?" },
|
||
{ label: "Otros", val: "No", extra: "Cuál/es?" },
|
||
];
|
||
let cy2 = y;
|
||
const cRowH = 16;
|
||
contactos.forEach(c => {
|
||
const cw = [40, 18, halfW - 58];
|
||
let cx2 = ML;
|
||
[c.label, c.val, c.extra].forEach((txt, i) => {
|
||
rect(page, cx2, cy2 - cRowH, cw[i], cRowH);
|
||
txt.split("\n").forEach((ln, li) => {
|
||
page.drawText(ln, { x: cx2 + 2, y: cy2 - cRowH + (cRowH / 2) + 1 - li * 7, size: 6.5, font: regular, color: NEGRO });
|
||
});
|
||
cx2 += cw[i];
|
||
});
|
||
cy2 -= cRowH;
|
||
});
|
||
|
||
// Vacunación
|
||
const vacX = ML + halfW + 4;
|
||
let vy = y;
|
||
// cabecera sub
|
||
const vacHeaders = ["Dosis", "Ultima", "Nombre comercial"];
|
||
const vacW = [halfW * 0.22, halfW * 0.22, halfW * 0.56];
|
||
// fila "Vacuna COVID" + sub-encabezados
|
||
const vacRowH = 10;
|
||
rect(page, vacX, vy - vacRowH, halfW * 0.3, vacRowH, { fill: GRIS_LABEL });
|
||
page.drawText("Vacuna COVID", { x: vacX + 2, y: vy - vacRowH + 2.5, size: 6.5, font: regular, color: NEGRO });
|
||
let vx = vacX + halfW * 0.3;
|
||
vacHeaders.forEach((h, i) => {
|
||
rect(page, vx, vy - vacRowH, vacW[i], vacRowH, { fill: GRIS_LABEL });
|
||
page.drawText(h, { x: vx + 2, y: vy - vacRowH + 2.5, size: 6, font: regular, color: NEGRO });
|
||
vx += vacW[i];
|
||
});
|
||
vy -= vacRowH;
|
||
// valor dosis 3
|
||
rect(page, vacX, vy - vacRowH, halfW * 0.3, vacRowH, { fill: GRIS_LABEL });
|
||
rect(page, vacX + halfW * 0.3, vy - vacRowH, vacW[0], vacRowH);
|
||
page.drawText("3", { x: vacX + halfW * 0.3 + 4, y: vy - vacRowH + 2.5, size: 7, font: bold, color: NEGRO });
|
||
rect(page, vacX + halfW * 0.3 + vacW[0], vy - vacRowH, vacW[1] + vacW[2], vacRowH);
|
||
vy -= vacRowH;
|
||
|
||
const vacRows = [
|
||
{ label: "Antigripal", check: "No" },
|
||
{ label: "Antineumocócica", check: "No" },
|
||
{ label: "Doble Adultos", check: "No" },
|
||
{ label: "Otras", check: "" },
|
||
];
|
||
const vacRH = 10;
|
||
vacRows.forEach(row => {
|
||
rect(page, vacX, vy - vacRH, halfW * 0.3, vacRH, { fill: GRIS_LABEL });
|
||
page.drawText(row.label, { x: vacX + 2, y: vy - vacRH + 2.5, size: 6.5, font: regular, color: NEGRO });
|
||
rect(page, vacX + halfW * 0.3, vy - vacRH, vacW[0], vacRH);
|
||
page.drawText(row.check, { x: vacX + halfW * 0.3 + 2, y: vy - vacRH + 2.5, size: 7, font: regular, color: NEGRO });
|
||
rect(page, vacX + halfW * 0.3 + vacW[0], vy - vacRH, vacW[1] + vacW[2], vacRH);
|
||
vy -= vacRH;
|
||
});
|
||
// Serologías
|
||
rect(page, vacX, vy - vacRH, halfW * 0.3, vacRH, { fill: GRIS_LABEL });
|
||
page.drawText("Serologías", { x: vacX + 2, y: vy - vacRH + 2.5, size: 6.5, font: regular, color: NEGRO });
|
||
rect(page, vacX + halfW * 0.3, vy - vacRH, halfW * 0.7, vacRH);
|
||
const resultTxt = "Resultado";
|
||
page.drawText(resultTxt, { x: vacX + halfW * 0.3 + (halfW * 0.7 - regular.widthOfTextAtSize(resultTxt, 7)) / 2, y: vy - vacRH + 2.5, size: 7, font: regular, color: NEGRO });
|
||
vy -= vacRH;
|
||
// 2 filas vacías de serologías
|
||
for (let i = 0; i < 2; i++) {
|
||
rect(page, vacX, vy - vacRH, halfW, vacRH);
|
||
vy -= vacRH;
|
||
}
|
||
|
||
y = Math.min(cy2, vy) - 4;
|
||
|
||
/* --- DETERMINANTES SOCIO-EPIDEMIOLÓGICOS --- */
|
||
y = sectionHeader(page, "DETERMINANTES SOCIO-EPIDEMIOLÓGICOS", ML, y, INNER, 13, { bold, regular });
|
||
|
||
const detRows = [
|
||
{ label: "LUGAR DE NACIMIENTO" },
|
||
{ label: "RESIDENCIA PASADA Y ACTUAL" },
|
||
{ label: "VIVIENDA", special: "vivienda" },
|
||
{ label: "NIVEL DE ESCOLARIDAD ALCANZADO" },
|
||
{ label: "OCUPACIÓN/OFICIO/PROFESIÓN" },
|
||
{ label: "VIAJES RECIENTES" },
|
||
];
|
||
const detH = 12;
|
||
const detLW = 90;
|
||
detRows.forEach(row => {
|
||
if (row.special === "vivienda") {
|
||
// dos sub-filas: Material/Sanitarios + Agua/Cloacas
|
||
rect(page, ML, y - detH, detLW, detH * 2);
|
||
page.drawText(row.label, { x: ML + 2, y: y - detH + 2.5, size: 7, font: regular, color: NEGRO });
|
||
// sub-fila 1
|
||
const subW = (INNER - detLW) / 4;
|
||
const subLabels1 = ["Material", "No", "Sanitarios completos", "No"];
|
||
let sx = ML + detLW;
|
||
subLabels1.forEach((lbl, i) => {
|
||
const fill = (i % 2 === 0) ? GRIS_LABEL : null;
|
||
rect(page, sx, y - detH, subW, detH, { fill: fill || BLANCO });
|
||
page.drawText(lbl, { x: sx + 2, y: y - detH + 3, size: 6.5, font: regular, color: NEGRO });
|
||
sx += subW;
|
||
});
|
||
y -= detH;
|
||
// sub-fila 2
|
||
const subLabels2 = ["Agua Potable", "No", "Cloacas", "No"];
|
||
sx = ML + detLW;
|
||
subLabels2.forEach((lbl, i) => {
|
||
const fill = (i % 2 === 0) ? GRIS_LABEL : null;
|
||
rect(page, sx, y - detH, subW, detH, { fill: fill || BLANCO });
|
||
page.drawText(lbl, { x: sx + 2, y: y - detH + 3, size: 6.5, font: regular, color: NEGRO });
|
||
sx += subW;
|
||
});
|
||
y -= detH;
|
||
} else {
|
||
rect(page, ML, y - detH, detLW, detH, { fill: GRIS_LABEL });
|
||
page.drawText(row.label, { x: ML + 2, y: y - detH + 3, size: 7, font: regular, color: NEGRO });
|
||
rect(page, ML + detLW, y - detH, INNER - detLW, detH);
|
||
y -= detH;
|
||
}
|
||
});
|
||
y -= 4;
|
||
|
||
/* --- EXAMEN FÍSICO --- */
|
||
y = sectionHeader(page, "EXAMEN FÍSICO", ML, y, INNER, 13, { bold, regular });
|
||
|
||
// Fila 1: TA / FC / FR / Temp / Sat / FiO2
|
||
const efRow1 = [
|
||
{ label: "TENSIÓN ARTERIAL", w: INNER * 0.18 },
|
||
{ label: "FRECUENCIA\nCARDÍACA", w: INNER * 0.14 },
|
||
{ label: "FRECUENCIA\nRESPIRATORIA", w: INNER * 0.14 },
|
||
{ label: "TEMPERATURA\nAXILAR", w: INNER * 0.14 },
|
||
{ label: "SATUROMETRÍA", w: INNER * 0.14 },
|
||
{ label: "FIO2(FRACCIÓN\nINSPIRADA DE OXIGENO)", w: INNER * 0.26 },
|
||
];
|
||
const efH1 = 22;
|
||
const efH1b = 12;
|
||
let ex = ML;
|
||
efRow1.forEach(col => {
|
||
rect(page, ex, y - efH1, col.w, efH1 / 2, { fill: GRIS_LABEL });
|
||
col.label.split("\n").forEach((ln, i) => {
|
||
page.drawText(ln, { x: ex + 2, y: y - efH1 / 2 + (col.label.includes("\n") ? (i === 0 ? 3 : -4) : -1),
|
||
size: 5.5, font: regular, color: NEGRO });
|
||
});
|
||
rect(page, ex, y - efH1, col.w, efH1);
|
||
ex += col.w;
|
||
});
|
||
y -= efH1 + 2;
|
||
|
||
// Fila 2: SNG / SV / AVP / AVC / Peso-Talla-IMC
|
||
const efRow2 = [
|
||
{ label: "SONDA\nNASOGÁSTRICA", val: "No", w: INNER * 0.14 },
|
||
{ label: "SONDA\nVESICAL", val: "Sonda Vesical",w: INNER * 0.16 },
|
||
{ label: "ACCESO VENOSO\nPERIFÉRICO", val: "Si - MSI", w: INNER * 0.16 },
|
||
{ label: "ACCESO VENOSO CENTRAL", val: "No", w: INNER * 0.27 },
|
||
{ label: "PESO / TALLA / IMC", val: "", w: INNER * 0.27 },
|
||
];
|
||
const ef2H = 18;
|
||
ex = ML;
|
||
efRow2.forEach(col => {
|
||
rect(page, ex, y - ef2H, col.w, ef2H / 2, { fill: GRIS_LABEL });
|
||
col.label.split("\n").forEach((ln, li) => {
|
||
page.drawText(ln, { x: ex + 2, y: y - ef2H / 2 + (col.label.includes("\n") ? (li === 0 ? 3 : -4) : -1),
|
||
size: 5.5, font: regular, color: NEGRO });
|
||
});
|
||
rect(page, ex, y - ef2H, col.w, ef2H);
|
||
page.drawText(col.val, { x: ex + 2, y: y - ef2H + 3, size: 6.5, font: regular, color: NEGRO });
|
||
ex += col.w;
|
||
});
|
||
y -= ef2H + 2;
|
||
|
||
// Sistemas
|
||
const sistemas = [
|
||
"SISTEMA\nNERVIOSO\nCENTRAL",
|
||
"CARDIOVASCULAR",
|
||
"RESPIRATORIO",
|
||
"DIGESTIVO",
|
||
"GENITO/URINARIO",
|
||
"SISTEMA OSTEO –\nMUSCULO -\nARTICULAR",
|
||
];
|
||
const sysLW = 60;
|
||
const sysH = 28;
|
||
sistemas.forEach(sis => {
|
||
rect(page, ML, y - sysH, sysLW, sysH, { fill: GRIS_LABEL });
|
||
sis.split("\n").forEach((ln, i) => {
|
||
const lines = sis.split("\n").length;
|
||
const baseY = y - sysH + sysH / 2 - 3;
|
||
page.drawText(ln, { x: ML + 2, y: baseY + (lines - 1 - i) * 7, size: 6.5, font: regular, color: NEGRO });
|
||
});
|
||
rect(page, ML + sysLW, y - sysH, INNER - sysLW, sysH);
|
||
y -= sysH;
|
||
});
|
||
}
|
||
|
||
/* ============================================================
|
||
PÁGINA 4 – Laboratorio / Bacteriología / ECG / Estudios
|
||
============================================================ */
|
||
async function buildPage4(pdfDoc, bold, regular) {
|
||
const page = pdfDoc.addPage([A4W, A4H]);
|
||
let y = drawPageHeader(page, 4, bold, regular);
|
||
|
||
/* --- LABORATORIO --- */
|
||
y = sectionHeader(page, "LABORATORIO", ML, y, INNER, 13, { bold, regular });
|
||
|
||
// Parámetros en columnas de 3 grupos (label + espacio)
|
||
const labParams = [
|
||
["HTO (%)", "GLUC (mg/dl)", "Na+ (mEq/L)", "BT (mg/dl)", "TP (%)"],
|
||
["HB (G/DL)", "UREA (mg/dl)", "K+ (mEq/L)", "BD (mg/dl)", "KPTT (seg)"],
|
||
["GB (X10⁹/L)", "CREAT (mg/dl)", "Cl- (mEq/L)", "GOT (UI/L)", "RIN"],
|
||
["PQ (X10⁹/L)", "", "P- (mEq/L)", "GPT (UI/L)", "PROT (g/dL)"],
|
||
["", "", "Mg+ (mEq/L)", "FAL (UI/L)", "ALB (g/dL)"],
|
||
];
|
||
const labCols = 5;
|
||
const labColW = INNER / labCols;
|
||
const labRowH = 11;
|
||
const labLabelW = labColW * 0.55;
|
||
|
||
labParams.forEach((row, ri) => {
|
||
let lx = ML;
|
||
row.forEach((param, ci) => {
|
||
if (param) {
|
||
rect(page, lx, y - labRowH, labLabelW, labRowH, { fill: GRIS_LABEL });
|
||
page.drawText(param, { x: lx + 2, y: y - labRowH + 3, size: 5.5, font: regular, color: NEGRO });
|
||
rect(page, lx + labLabelW, y - labRowH, labColW - labLabelW, labRowH);
|
||
}
|
||
lx += labColW;
|
||
});
|
||
y -= labRowH;
|
||
});
|
||
|
||
// EAB
|
||
y -= 2;
|
||
const eabLabels = ["EAB", "PH", "CO2", "O2", "HCO3", "EB", "SAT", "A.L", "FIO2"];
|
||
const eabW = [28, 30, 30, 30, 35, 30, 30, 30, 30];
|
||
const eabH = 11;
|
||
let eabX = ML;
|
||
eabLabels.forEach((lbl, i) => {
|
||
rect(page, eabX, y - eabH, eabW[i], eabH / 2, { fill: GRIS_LABEL });
|
||
page.drawText(lbl, { x: eabX + 2, y: y - eabH / 2 + 1, size: 6, font: bold, color: NEGRO });
|
||
rect(page, eabX, y - eabH, eabW[i], eabH);
|
||
eabX += eabW[i];
|
||
});
|
||
y -= eabH + 2;
|
||
|
||
// OTROS / FENA
|
||
rect(page, ML, y, INNER, 13, { fill: GRIS_LABEL });
|
||
page.drawText("OTROS (INCLUYE LÍQUIDOS)", { x: ML + 2, y: y + 4, size: 7, font: bold, color: NEGRO });
|
||
y -= 0;
|
||
rect(page, ML, y - 36, INNER, 36);
|
||
page.drawText("FENA", { x: ML + 2, y: y - 8, size: 7, font: regular, color: NEGRO });
|
||
y -= 36 + 13 + 4;
|
||
|
||
/* --- BACTERIOLOGÍA --- */
|
||
y = sectionHeader(page, "BACTERIOLOGÍA", ML, y, INNER, 13, { bold, regular });
|
||
const bactHeaders = ["Fecha", "Cultivo", "Resultado", "Sensibilidad"];
|
||
const bactW = [INNER * 0.18, INNER * 0.27, INNER * 0.27, INNER * 0.28];
|
||
const bactH = 10;
|
||
let bx = ML;
|
||
bactHeaders.forEach((h, i) => {
|
||
rect(page, bx, y - bactH, bactW[i], bactH, { fill: GRIS_LABEL });
|
||
textCenter(page, h, bx, y - bactH + 2, bactW[i], { font: bold, size: 7 });
|
||
bx += bactW[i];
|
||
});
|
||
y -= bactH;
|
||
for (let i = 0; i < 5; i++) {
|
||
bx = ML;
|
||
bactHeaders.forEach((_, j) => { rect(page, bx, y - bactH, bactW[j], bactH); bx += bactW[j]; });
|
||
y -= bactH;
|
||
}
|
||
y -= 4;
|
||
|
||
/* --- ECG --- */
|
||
y = sectionHeader(page, "ELECTROCARDIOGRAMA", ML, y, INNER, 13, { bold, regular });
|
||
|
||
// Fila con fecha + interpretación
|
||
const ecgH = 10;
|
||
const ecgLW = 28;
|
||
const ecgRW = INNER / 2;
|
||
const ecgParams = [
|
||
["FECHA", "", ecgRW],
|
||
["Ritmo", "PR"],
|
||
["FC", "Onda T"],
|
||
["Eje", "QT"],
|
||
["Onda P",""],
|
||
["QRS", ""],
|
||
];
|
||
// Primera fila: fecha + "INTERPRETACIÓN DIAGNÓSTICA:" (columna derecha grande)
|
||
rect(page, ML, y - ecgH, ecgLW, ecgH, { fill: GRIS_LABEL });
|
||
page.drawText("FECHA", { x: ML + 2, y: y - ecgH + 3, size: 7, font: bold, color: NEGRO });
|
||
rect(page, ML + ecgLW, y - ecgH, ecgRW - ecgLW, ecgH);
|
||
rect(page, ML + ecgRW, y - ecgH, INNER - ecgRW, ecgH, { fill: GRIS_LABEL });
|
||
page.drawText("INTERPRETACIÓN DIAGNÓSTICA:", { x: ML + ecgRW + 2, y: y - ecgH + 3, size: 7, font: bold, color: NEGRO });
|
||
y -= ecgH;
|
||
|
||
const ecgLeft = [["Ritmo"],["FC"],["Eje"],["Onda P"],["QRS"]];
|
||
const ecgRight = [["PR"],["Onda T"],["QT"],[""],[""]];
|
||
const ecgDataH = 10;
|
||
const lhW = INNER / 4;
|
||
// zona interpretación (rectángulo derecho que abarca todas las filas)
|
||
rect(page, ML + ecgRW, y - ecgDataH * 5, INNER - ecgRW, ecgDataH * 5);
|
||
ecgLeft.forEach((row, i) => {
|
||
rect(page, ML, y - ecgDataH, lhW * 0.5, ecgDataH, { fill: GRIS_LABEL });
|
||
page.drawText(row[0], { x: ML + 2, y: y - ecgDataH + 3, size: 7, font: regular, color: NEGRO });
|
||
rect(page, ML + lhW * 0.5, y - ecgDataH, lhW - lhW * 0.5, ecgDataH);
|
||
if (ecgRight[i][0]) {
|
||
rect(page, ML + lhW, y - ecgDataH, lhW * 0.5, ecgDataH, { fill: GRIS_LABEL });
|
||
page.drawText(ecgRight[i][0], { x: ML + lhW + 2, y: y - ecgDataH + 3, size: 7, font: regular, color: NEGRO });
|
||
rect(page, ML + lhW * 1.5, y - ecgDataH, lhW - lhW * 0.5, ecgDataH);
|
||
}
|
||
y -= ecgDataH;
|
||
});
|
||
y -= 4;
|
||
|
||
/* --- ESTUDIOS COMPLEMENTARIOS --- */
|
||
y = sectionHeader(page, "ESTUDIOS COMPLEMENTARIOS", ML, y, INNER, 13, { bold, regular });
|
||
const estHeaders = ["Fecha", "Estudio", "Descripción"];
|
||
const estW = [INNER * 0.14, INNER * 0.16, INNER * 0.70];
|
||
let estX = ML;
|
||
estHeaders.forEach((h, i) => {
|
||
rect(page, estX, y - ecgH, estW[i], ecgH, { fill: GRIS_LABEL });
|
||
page.drawText(h, { x: estX + 2, y: y - ecgH + 3, size: 7, font: bold, color: NEGRO });
|
||
estX += estW[i];
|
||
});
|
||
y -= ecgH;
|
||
const estRowH = 22;
|
||
for (let i = 0; i < 4; i++) {
|
||
estX = ML;
|
||
estHeaders.forEach((_, j) => { rect(page, estX, y - estRowH, estW[j], estRowH); estX += estW[j]; });
|
||
// Fecha marcadas: /03/ y /04/
|
||
if (i < 2) {
|
||
page.drawText(i === 0 ? "/03/." : "/04/.", { x: ML + 2, y: y - estRowH + 8, size: 10, font: bold, color: NEGRO });
|
||
}
|
||
y -= estRowH;
|
||
}
|
||
}
|
||
|
||
/* ============================================================
|
||
PÁGINA 5 – Diagnóstico / Plan diagnóstico / Plan terapéutico
|
||
============================================================ */
|
||
async function buildPage5(pdfDoc, bold, regular) {
|
||
const page = pdfDoc.addPage([A4W, A4H]);
|
||
let y = drawPageHeader(page, 5, bold, regular);
|
||
|
||
/* --- IMPRESIÓN DIAGNÓSTICA POR SINDROME --- */
|
||
y = sectionHeader(page, "IMPRESIÓN DIAGNÓSTICA POR SINDROME", ML, y, INNER, 13, { bold, regular });
|
||
const idH = 200;
|
||
rect(page, ML, y - idH, INNER, idH);
|
||
y -= idH + 4;
|
||
|
||
/* --- PLAN DIAGNÓSTICO --- */
|
||
y = sectionHeader(page, "PLAN DIAGNÓSTICO", ML, y, INNER, 13, { bold, regular });
|
||
const pdH = 40;
|
||
rect(page, ML, y - pdH, INNER, pdH);
|
||
y -= pdH + 4;
|
||
|
||
/* --- DIAGNÓSTICO AL INGRESO --- */
|
||
y = sectionHeader(page, "DIAGNÓSTICO AL INGRESO", ML, y, INNER, 13, { bold, regular });
|
||
const diH = 40;
|
||
rect(page, ML, y - diH, INNER, diH);
|
||
y -= diH + 4;
|
||
|
||
/* --- PLAN TERAPÉUTICO --- */
|
||
y = sectionHeader(page, "PLAN TERAPÈUTICO", ML, y, INNER, 13, { bold, regular });
|
||
const ptH = 9;
|
||
const ptColW = INNER / 2;
|
||
for (let i = 1; i <= 20; i++) {
|
||
const col = i <= 10 ? 0 : 1;
|
||
const row = i <= 10 ? i - 1 : i - 11;
|
||
const ptX = ML + col * ptColW;
|
||
const ptY = y - row * ptH - ptH;
|
||
rect(page, ptX, ptY, 10, ptH);
|
||
page.drawText(`${i}`, { x: ptX + 2, y: ptY + 2, size: 6.5, font: regular, color: NEGRO });
|
||
rect(page, ptX + 10, ptY, ptColW - 10, ptH);
|
||
}
|
||
|
||
// Firma
|
||
const firmaY = y - 10 * ptH - 20;
|
||
page.drawText("......................................", {
|
||
x: A4W - ML - 120, y: firmaY, size: 8, font: regular, color: NEGRO
|
||
});
|
||
}
|
||
|
||
/* ============================================================
|
||
MAIN – ensambla todo y descarga
|
||
============================================================ */
|
||
async function generarPDF() {
|
||
const status = document.getElementById("status");
|
||
status.textContent = "Generando PDF...";
|
||
try {
|
||
const pdfDoc = await PDFLib.PDFDocument.create();
|
||
const regular = await pdfDoc.embedFont(PDFLib.StandardFonts.Helvetica);
|
||
const bold = await pdfDoc.embedFont(PDFLib.StandardFonts.HelveticaBold);
|
||
const fonts = { regular, bold };
|
||
|
||
await buildPage1(pdfDoc, bold, regular);
|
||
await buildPage2(pdfDoc, bold, regular);
|
||
await buildPage3(pdfDoc, bold, regular);
|
||
await buildPage4(pdfDoc, bold, regular);
|
||
await buildPage5(pdfDoc, bold, regular);
|
||
|
||
const pdfBytes = await pdfDoc.save();
|
||
const blob = new Blob([pdfBytes], { type: "application/pdf" });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement("a");
|
||
a.href = url;
|
||
a.download = "HC_Ingreso_Santojanni.pdf";
|
||
a.click();
|
||
URL.revokeObjectURL(url);
|
||
status.textContent = "✅ PDF generado y descargado correctamente.";
|
||
} catch (e) {
|
||
console.error(e);
|
||
status.textContent = "❌ Error al generar el PDF. Ver consola para detalles.";
|
||
}
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|