Agregar tabla interconsultas: DB, store, UI con CRUD completo
This commit is contained in:
@@ -0,0 +1,753 @@
|
|||||||
|
<!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>
|
||||||
@@ -157,6 +157,22 @@ try {
|
|||||||
// La columna ya existe
|
// La columna ya existe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS interconsultas (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
pacienteId TEXT NOT NULL,
|
||||||
|
internacionId TEXT NOT NULL,
|
||||||
|
fecha TEXT,
|
||||||
|
servicioInterconsultado TEXT,
|
||||||
|
realizada INTEGER DEFAULT 0,
|
||||||
|
respuestaInterconsulta TEXT
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Tabla interconsultas ya existe o error:', e.message);
|
||||||
|
}
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
app.use(express.json({ limit: '50mb' }));
|
app.use(express.json({ limit: '50mb' }));
|
||||||
@@ -206,6 +222,7 @@ app.get('/api/state', (req, res) => {
|
|||||||
acidosBase: queryAll('SELECT * FROM acidosbase'),
|
acidosBase: queryAll('SELECT * FROM acidosbase'),
|
||||||
cultivos: queryAll('SELECT * FROM cultivos'),
|
cultivos: queryAll('SELECT * FROM cultivos'),
|
||||||
estudiosComplementarios: queryAll('SELECT * FROM estudiosComplementarios'),
|
estudiosComplementarios: queryAll('SELECT * FROM estudiosComplementarios'),
|
||||||
|
interconsultas: queryAll('SELECT * FROM interconsultas').map(ic => ({ ...ic, realizada: !!ic.realizada })),
|
||||||
vistaActual: 'dashboard',
|
vistaActual: 'dashboard',
|
||||||
currentInternacionId: null
|
currentInternacionId: null
|
||||||
};
|
};
|
||||||
@@ -288,6 +305,14 @@ if (state.laboratorios?.length) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run('DELETE FROM interconsultas');
|
||||||
|
if (state.interconsultas?.length) {
|
||||||
|
const stmt = db.prepare('INSERT INTO interconsultas (id, pacienteId, internacionId, fecha, servicioInterconsultado, realizada, respuestaInterconsulta) VALUES (?, ?, ?, ?, ?, ?, ?)');
|
||||||
|
for (const ic of state.interconsultas) {
|
||||||
|
stmt.run(ic.id, ic.pacienteId, ic.internacionId, ic.fecha, ic.servicioInterconsultado, ic.realizada ? 1 : 0, ic.respuestaInterconsulta || null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res.json({ ok: true });
|
res.json({ ok: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ function AppContent() {
|
|||||||
acidosBase={store.getAcidosBaseByPaciente(paciente.id)}
|
acidosBase={store.getAcidosBaseByPaciente(paciente.id)}
|
||||||
cultivos={store.getCultivosByPaciente(paciente.id)}
|
cultivos={store.getCultivosByPaciente(paciente.id)}
|
||||||
estudiosComplementarios={store.estudiosComplementarios.filter(e => e.pacienteId === paciente.id)}
|
estudiosComplementarios={store.estudiosComplementarios.filter(e => e.pacienteId === paciente.id)}
|
||||||
|
interconsultas={store.interconsultas.filter(ic => ic.internacionId === internacion.id)}
|
||||||
onAgregarEvolucion={store.agregarEvolucion}
|
onAgregarEvolucion={store.agregarEvolucion}
|
||||||
onActualizarEvolucion={store.actualizarEvolucion}
|
onActualizarEvolucion={store.actualizarEvolucion}
|
||||||
onEliminarEvolucion={store.eliminarEvolucion}
|
onEliminarEvolucion={store.eliminarEvolucion}
|
||||||
@@ -159,6 +160,9 @@ function AppContent() {
|
|||||||
onAgregarEstudioComplementario={(e) => store.agregarEstudioComplementario({ ...e, internacionId: internacion.id })}
|
onAgregarEstudioComplementario={(e) => store.agregarEstudioComplementario({ ...e, internacionId: internacion.id })}
|
||||||
onActualizarEstudioComplementario={store.actualizarEstudioComplementario}
|
onActualizarEstudioComplementario={store.actualizarEstudioComplementario}
|
||||||
onEliminarEstudioComplementario={store.eliminarEstudioComplementario}
|
onEliminarEstudioComplementario={store.eliminarEstudioComplementario}
|
||||||
|
onAgregarInterconsulta={(ic) => store.agregarInterconsulta({ ...ic, internacionId: internacion.id })}
|
||||||
|
onActualizarInterconsulta={store.actualizarInterconsulta}
|
||||||
|
onEliminarInterconsulta={store.eliminarInterconsulta}
|
||||||
onActualizarInternacion={store.actualizarInternacion}
|
onActualizarInternacion={store.actualizarInternacion}
|
||||||
onActualizarCama={store.actualizarCama}
|
onActualizarCama={store.actualizarCama}
|
||||||
onVolver={() => store.setVista('internaciones')}
|
onVolver={() => store.setVista('internaciones')}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import type {
|
|||||||
AcidoBase,
|
AcidoBase,
|
||||||
Cultivo,
|
Cultivo,
|
||||||
EstudioComplementario,
|
EstudioComplementario,
|
||||||
|
Interconsulta,
|
||||||
Vista
|
Vista
|
||||||
} from '@/types';
|
} from '@/types';
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ interface HospitalState {
|
|||||||
acidosBase: AcidoBase[];
|
acidosBase: AcidoBase[];
|
||||||
cultivos: Cultivo[];
|
cultivos: Cultivo[];
|
||||||
estudiosComplementarios: EstudioComplementario[];
|
estudiosComplementarios: EstudioComplementario[];
|
||||||
|
interconsultas: Interconsulta[];
|
||||||
vistaActual: Vista;
|
vistaActual: Vista;
|
||||||
currentInternacionId?: string | null;
|
currentInternacionId?: string | null;
|
||||||
}
|
}
|
||||||
@@ -51,6 +53,7 @@ const defaultState = (): HospitalState => ({
|
|||||||
acidosBase: [],
|
acidosBase: [],
|
||||||
cultivos: [],
|
cultivos: [],
|
||||||
estudiosComplementarios: [],
|
estudiosComplementarios: [],
|
||||||
|
interconsultas: [],
|
||||||
vistaActual: 'dashboard',
|
vistaActual: 'dashboard',
|
||||||
camas: []
|
camas: []
|
||||||
});
|
});
|
||||||
@@ -349,6 +352,30 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
|
|||||||
}));
|
}));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Acciones de interconsultas
|
||||||
|
const agregarInterconsulta = useCallback((interconsulta: Omit<Interconsulta, 'id'>) => {
|
||||||
|
const nuevaInterconsulta: Interconsulta = { ...interconsulta, id: generateUUID() };
|
||||||
|
setState(prev => ({
|
||||||
|
...prev,
|
||||||
|
interconsultas: [...prev.interconsultas, nuevaInterconsulta],
|
||||||
|
}));
|
||||||
|
return nuevaInterconsulta.id;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const actualizarInterconsulta = useCallback((id: string, datos: Partial<Interconsulta>) => {
|
||||||
|
setState(prev => ({
|
||||||
|
...prev,
|
||||||
|
interconsultas: prev.interconsultas.map(ic => ic.id === id ? { ...ic, ...datos } : ic),
|
||||||
|
}));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const eliminarInterconsulta = useCallback((id: string) => {
|
||||||
|
setState(prev => ({
|
||||||
|
...prev,
|
||||||
|
interconsultas: prev.interconsultas.filter(ic => ic.id !== id),
|
||||||
|
}));
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Acciones de areas
|
// Acciones de areas
|
||||||
const agregarArea = useCallback((area: Omit<Area, 'id'>) => {
|
const agregarArea = useCallback((area: Omit<Area, 'id'>) => {
|
||||||
const nuevaArea: Area = { ...area, id: generateUUID() };
|
const nuevaArea: Area = { ...area, id: generateUUID() };
|
||||||
@@ -472,6 +499,9 @@ const getEstadisticas = useCallback(() => {
|
|||||||
agregarEstudioComplementario,
|
agregarEstudioComplementario,
|
||||||
actualizarEstudioComplementario,
|
actualizarEstudioComplementario,
|
||||||
eliminarEstudioComplementario,
|
eliminarEstudioComplementario,
|
||||||
|
agregarInterconsulta,
|
||||||
|
actualizarInterconsulta,
|
||||||
|
eliminarInterconsulta,
|
||||||
agregarArea,
|
agregarArea,
|
||||||
actualizarArea,
|
actualizarArea,
|
||||||
eliminarArea,
|
eliminarArea,
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
|
||||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
|
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
|
||||||
import type { Laboratorio, AcidoBase, Cultivo, Paciente, ResultadoLaboratorio, Internacion, Evolucion, Cama, EstudioComplementario } from '@/types';
|
import type { Laboratorio, AcidoBase, Cultivo, Paciente, ResultadoLaboratorio, Internacion, Evolucion, Cama, EstudioComplementario, Interconsulta } from '@/types';
|
||||||
import { formatDateDDMMYYYY } from '@/lib/utils';
|
import { formatDateDDMMYYYY } from '@/lib/utils';
|
||||||
|
|
||||||
interface HistoriaClinicaProps {
|
interface HistoriaClinicaProps {
|
||||||
@@ -63,6 +63,7 @@ interface HistoriaClinicaProps {
|
|||||||
acidosBase: AcidoBase[];
|
acidosBase: AcidoBase[];
|
||||||
cultivos: Cultivo[];
|
cultivos: Cultivo[];
|
||||||
estudiosComplementarios: EstudioComplementario[];
|
estudiosComplementarios: EstudioComplementario[];
|
||||||
|
interconsultas: Interconsulta[];
|
||||||
onAgregarEvolucion: (evolucion: Omit<Evolucion, 'id'>) => void;
|
onAgregarEvolucion: (evolucion: Omit<Evolucion, 'id'>) => void;
|
||||||
onActualizarEvolucion: (id: string, datos: Partial<Evolucion>) => void;
|
onActualizarEvolucion: (id: string, datos: Partial<Evolucion>) => void;
|
||||||
onEliminarEvolucion: (id: string) => void;
|
onEliminarEvolucion: (id: string) => void;
|
||||||
@@ -79,6 +80,9 @@ interface HistoriaClinicaProps {
|
|||||||
onAgregarEstudioComplementario: (estudio: Omit<EstudioComplementario, 'id'>) => void;
|
onAgregarEstudioComplementario: (estudio: Omit<EstudioComplementario, 'id'>) => void;
|
||||||
onActualizarEstudioComplementario: (id: string, datos: Partial<EstudioComplementario>) => void;
|
onActualizarEstudioComplementario: (id: string, datos: Partial<EstudioComplementario>) => void;
|
||||||
onEliminarEstudioComplementario: (id: string) => void;
|
onEliminarEstudioComplementario: (id: string) => void;
|
||||||
|
onAgregarInterconsulta: (interconsulta: Omit<Interconsulta, 'id'>) => void;
|
||||||
|
onActualizarInterconsulta: (id: string, datos: Partial<Interconsulta>) => void;
|
||||||
|
onEliminarInterconsulta: (id: string) => void;
|
||||||
onActualizarInternacion: (id: string, datos: Partial<Internacion>) => void;
|
onActualizarInternacion: (id: string, datos: Partial<Internacion>) => void;
|
||||||
onActualizarCama: (id: string, datos: Partial<Cama>) => void;
|
onActualizarCama: (id: string, datos: Partial<Cama>) => void;
|
||||||
onVolver: () => void;
|
onVolver: () => void;
|
||||||
@@ -168,6 +172,7 @@ export function HistoriaClinica({
|
|||||||
acidosBase,
|
acidosBase,
|
||||||
cultivos,
|
cultivos,
|
||||||
estudiosComplementarios,
|
estudiosComplementarios,
|
||||||
|
interconsultas,
|
||||||
onAgregarEvolucion,
|
onAgregarEvolucion,
|
||||||
onActualizarEvolucion,
|
onActualizarEvolucion,
|
||||||
onEliminarEvolucion,
|
onEliminarEvolucion,
|
||||||
@@ -183,6 +188,9 @@ export function HistoriaClinica({
|
|||||||
onAgregarEstudioComplementario,
|
onAgregarEstudioComplementario,
|
||||||
onActualizarEstudioComplementario,
|
onActualizarEstudioComplementario,
|
||||||
onEliminarEstudioComplementario,
|
onEliminarEstudioComplementario,
|
||||||
|
onAgregarInterconsulta,
|
||||||
|
onActualizarInterconsulta,
|
||||||
|
onEliminarInterconsulta,
|
||||||
onActualizarInternacion,
|
onActualizarInternacion,
|
||||||
onActualizarCama,
|
onActualizarCama,
|
||||||
onVolver,
|
onVolver,
|
||||||
@@ -538,10 +546,14 @@ export function HistoriaClinica({
|
|||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="interconsultas" className="mt-4">
|
<TabsContent value="interconsultas" className="mt-4">
|
||||||
<div className="text-center py-8 text-gray-400">
|
<SeccionInterconsultas
|
||||||
<Users className="h-12 w-12 mx-auto mb-2 opacity-50" />
|
interconsultas={interconsultas as Interconsulta[]}
|
||||||
<p>Sección Interconsultas en desarrollo</p>
|
pacienteId={paciente.id}
|
||||||
</div>
|
internacionId={internacion.id}
|
||||||
|
add={onAgregarInterconsulta}
|
||||||
|
update={onActualizarInterconsulta}
|
||||||
|
del={onEliminarInterconsulta}
|
||||||
|
/>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
@@ -2006,4 +2018,148 @@ function SeccionEstudiosComplementarios({ estudios, internacionId, pacienteId, a
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SeccionInterconsultas({ interconsultas, pacienteId, internacionId, add, update, del }: {
|
||||||
|
interconsultas: Interconsulta[];
|
||||||
|
pacienteId: string;
|
||||||
|
internacionId: string;
|
||||||
|
add: (ic: Omit<Interconsulta, 'id'>) => void;
|
||||||
|
update: (id: string, datos: Partial<Interconsulta>) => void;
|
||||||
|
del: (id: string) => void;
|
||||||
|
}) {
|
||||||
|
const [dialog, setDialog] = useState(false);
|
||||||
|
const [fecha, setFecha] = useState(new Date().toISOString().split('T')[0]);
|
||||||
|
const [servicioInterconsultado, setServicioInterconsultado] = useState('');
|
||||||
|
const [realizada, setRealizada] = useState(false);
|
||||||
|
const [respuestaInterconsulta, setRespuestaInterconsulta] = useState('');
|
||||||
|
const [edit, setEdit] = useState<Interconsulta | null>(null);
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
setFecha(new Date().toISOString().split('T')[0]);
|
||||||
|
setServicioInterconsultado('');
|
||||||
|
setRealizada(false);
|
||||||
|
setRespuestaInterconsulta('');
|
||||||
|
setEdit(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleGuardar = () => {
|
||||||
|
if (!servicioInterconsultado) return;
|
||||||
|
if (edit) {
|
||||||
|
update(edit.id, { fecha, servicioInterconsultado, realizada, respuestaInterconsulta });
|
||||||
|
} else {
|
||||||
|
add({ pacienteId, internacionId, fecha, servicioInterconsultado, realizada, respuestaInterconsulta });
|
||||||
|
}
|
||||||
|
setDialog(false);
|
||||||
|
reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadEdit = (ic: Interconsulta) => {
|
||||||
|
setEdit(ic);
|
||||||
|
setFecha(ic.fecha);
|
||||||
|
setServicioInterconsultado(ic.servicioInterconsultado);
|
||||||
|
setRealizada(ic.realizada);
|
||||||
|
setRespuestaInterconsulta(ic.respuestaInterconsulta || '');
|
||||||
|
setDialog(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const icsFiltrados = interconsultas.filter(ic => ic.internacionId === internacionId);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<Button variant="outline" onClick={() => { reset(); setDialog(true); }}>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
|
Nueva IC
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Dialog open={dialog} onOpenChange={setDialog}>
|
||||||
|
<DialogContent className="sm:max-w-lg">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>{edit ? 'Editar' : 'Nueva'} Interconsulta</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<Label>Fecha</Label>
|
||||||
|
<Input type="date" value={fecha} onChange={e => setFecha(e.target.value)} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label>Servicio Interconsultado</Label>
|
||||||
|
<Input
|
||||||
|
value={servicioInterconsultado}
|
||||||
|
onChange={e => setServicioInterconsultado(e.target.value)}
|
||||||
|
placeholder="Ej: Cardiología, Neurología, Infectología, etc."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="realizada"
|
||||||
|
checked={realizada}
|
||||||
|
onChange={e => setRealizada(e.target.checked)}
|
||||||
|
className="w-4 h-4"
|
||||||
|
/>
|
||||||
|
<Label htmlFor="realizada">Realizada</Label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label>Respuesta</Label>
|
||||||
|
<textarea
|
||||||
|
className="w-full p-2 border rounded-md text-sm min-h-[100px]"
|
||||||
|
value={respuestaInterconsulta}
|
||||||
|
onChange={e => setRespuestaInterconsulta(e.target.value)}
|
||||||
|
placeholder="Ingrese la respuesta de la interconsulta..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end gap-2 mt-4">
|
||||||
|
<Button variant="outline" onClick={() => setDialog(false)}>Cancelar</Button>
|
||||||
|
<Button onClick={handleGuardar} disabled={!servicioInterconsultado}>
|
||||||
|
<Save className="h-4 w-4 mr-2" />
|
||||||
|
Guardar
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
{icsFiltrados.length === 0 ? (
|
||||||
|
<div className="text-center py-8 text-gray-400">
|
||||||
|
<Users className="h-12 w-12 mx-auto mb-2 opacity-50" />
|
||||||
|
<p>No hay interconsultas</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-3">
|
||||||
|
{icsFiltrados.sort((a, b) => new Date(b.fecha).getTime() - new Date(a.fecha).getTime()).map(ic => (
|
||||||
|
<Card key={ic.id} className="hover:shadow-md transition-shadow">
|
||||||
|
<CardContent className="p-4">
|
||||||
|
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3">
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-2 mb-2">
|
||||||
|
<Calendar className="h-4 w-4 text-gray-500" />
|
||||||
|
<span className="text-sm font-medium">{ic.fecha}</span>
|
||||||
|
{ic.realizada && (
|
||||||
|
<Badge variant="secondary" className="ml-2">Realizada</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<h4 className="font-semibold text-gray-900 dark:text-white">{ic.servicioInterconsultado}</h4>
|
||||||
|
{ic.respuestaInterconsulta && (
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-300 mt-1 whitespace-pre-wrap">{ic.respuestaInterconsulta}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-1 self-start">
|
||||||
|
<Button size="sm" variant="outline" onClick={() => loadEdit(ic)}>
|
||||||
|
<Pencil className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
<Button size="sm" variant="outline" className="text-red-600" onClick={() => del(ic.id)}>
|
||||||
|
<Trash2 className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -152,4 +152,14 @@ export interface EstudioComplementario {
|
|||||||
resultado: string;
|
resultado: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Interconsulta {
|
||||||
|
id: string;
|
||||||
|
pacienteId: string;
|
||||||
|
internacionId: string;
|
||||||
|
fecha: string;
|
||||||
|
servicioInterconsultado: string;
|
||||||
|
realizada: boolean;
|
||||||
|
respuestaInterconsulta?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type Vista = 'dashboard' | 'camas' | 'pacientes' | 'internaciones' | 'evoluciones' | 'laboratorios' | 'acidobase' | 'cultivos' | 'historiaclinica' | 'nuevoingreso' | 'editaringreso';
|
export type Vista = 'dashboard' | 'camas' | 'pacientes' | 'internaciones' | 'evoluciones' | 'laboratorios' | 'acidobase' | 'cultivos' | 'historiaclinica' | 'nuevoingreso' | 'editaringreso';
|
||||||
|
|||||||
Reference in New Issue
Block a user