Initial commit: Sistema de Gestión Hospitalaria

This commit is contained in:
Santiago Lavaise
2026-04-12 20:52:43 -03:00
commit 78577ec922
93 changed files with 24674 additions and 0 deletions
+252
View File
@@ -0,0 +1,252 @@
import express from 'express';
import cors from 'cors';
import http from 'http';
import Database from 'better-sqlite3';
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const DB_PATH = join(__dirname, 'data', 'hospital.db');
const DIST_PATH = join(__dirname, '..', 'dist');
if (!existsSync(join(__dirname, 'data'))) {
mkdirSync(join(__dirname, 'data'));
}
const db = new Database(DB_PATH);
db.exec(`
CREATE TABLE IF NOT EXISTS pacientes (
id TEXT PRIMARY KEY,
apellido TEXT NOT NULL,
nombre TEXT NOT NULL,
dni TEXT NOT NULL UNIQUE,
fechaNacimiento TEXT,
sexo TEXT,
telefono TEXT,
email TEXT,
direccion TEXT,
fechaIngreso TEXT
);
CREATE TABLE IF NOT EXISTS areas (
id TEXT PRIMARY KEY,
nombre TEXT NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS camas (
id TEXT PRIMARY KEY,
numero TEXT NOT NULL,
areaId TEXT,
tipo TEXT DEFAULT 'Estándar',
estado TEXT DEFAULT 'Disponible'
);
CREATE TABLE IF NOT EXISTS internaciones (
id TEXT PRIMARY KEY,
pacienteId TEXT NOT NULL,
camaId TEXT,
fechaIngreso TEXT NOT NULL,
fechaEgreso TEXT,
diagnosticoIngreso TEXT,
motivoConsulta TEXT,
enfermedadActual TEXT,
antecedentesEnfermedadActual TEXT,
diagnosticoEgreso TEXT,
medicoIngresante TEXT,
motivoEgreso TEXT,
activa INTEGER DEFAULT 1
);
CREATE TABLE IF NOT EXISTS evoluciones (
id TEXT PRIMARY KEY,
internacionId TEXT NOT NULL,
fecha TEXT NOT NULL,
hora TEXT,
medico TEXT,
signosVitales TEXT,
examenFisico TEXT,
novedades TEXT,
comentarios TEXT,
pendientes TEXT
);
CREATE TABLE IF NOT EXISTS laboratorios (
id TEXT PRIMARY KEY,
pacienteId TEXT NOT NULL,
fecha TEXT NOT NULL,
tipo TEXT,
resultados TEXT,
observaciones TEXT
);
CREATE TABLE IF NOT EXISTS acidosbase (
id TEXT PRIMARY KEY,
pacienteId TEXT NOT NULL,
fecha TEXT NOT NULL,
hora TEXT NOT NULL,
ph REAL,
pco2 REAL,
po2 REAL,
hco3 REAL,
be REAL,
statO2 REAL,
lactato REAL,
interpretacion TEXT
);
CREATE TABLE IF NOT EXISTS cultivos (
id TEXT PRIMARY KEY,
pacienteId TEXT NOT NULL,
internacionId TEXT,
fechaToma TEXT NOT NULL,
protocolo TEXT,
tipoMuestra TEXT,
observaciones TEXT,
estado TEXT DEFAULT 'Pendiente',
fechaResultado TEXT,
germen TEXT,
sensible TEXT,
resistente TEXT
);
`);
const app = express();
app.use(cors());
app.use(express.json({ limit: '50mb' }));
function rowToObj(row) {
if (!row) return row;
const obj = {};
for (const key in row) {
const val = row[key];
try {
obj[key] = typeof val === 'string' && (val.startsWith('[') || val.startsWith('{')) ? JSON.parse(val) : val;
} catch {
obj[key] = val;
}
}
return obj;
}
function queryAll(sql, params = []) {
const stmt = db.prepare(sql);
const rows = params.length ? stmt.all(...params) : stmt.all();
return rows.map(rowToObj);
}
function queryOne(sql, params = []) {
const stmt = db.prepare(sql);
const row = params.length ? stmt.get(...params) : stmt.get();
return rowToObj(row);
}
function run(sql, params = []) {
const stmt = db.prepare(sql);
return params.length ? stmt.run(...params) : stmt.run();
}
app.get('/api/state', (req, res) => {
const state = {
pacientes: queryAll('SELECT * FROM pacientes'),
areas: queryAll('SELECT * FROM areas'),
camas: queryAll('SELECT * FROM camas'),
internaciones: queryAll('SELECT * FROM internaciones').map(i => ({ ...i, activa: !!i.activa })),
evoluciones: queryAll('SELECT * FROM evoluciones').map(e => ({ ...e,
signosVitales: typeof e.signosVitales === 'string' ? JSON.parse(e.signosVitales) : e.signosVitales,
examenFisico: typeof e.examenFisico === 'string' ? JSON.parse(e.examenFisico) : e.examenFisico
})),
laboratorios: queryAll('SELECT * FROM laboratorios').map(l => ({ ...l, resultados: typeof l.resultados === 'string' ? JSON.parse(l.resultados) : l.resultados })),
acidosBase: queryAll('SELECT * FROM acidosbase'),
cultivos: queryAll('SELECT * FROM cultivos'),
vistaActual: 'dashboard',
currentInternacionId: null
};
res.json(state);
});
app.put('/api/state', (req, res) => {
const state = req.body;
run('DELETE FROM evoluciones');
run('DELETE FROM acidosbase');
run('DELETE FROM cultivos');
run('DELETE FROM laboratorios');
run('DELETE FROM internaciones');
run('DELETE FROM camas');
run('DELETE FROM areas');
run('DELETE FROM pacientes');
if (state.pacientes?.length) {
const stmt = db.prepare('INSERT INTO pacientes (id, apellido, nombre, dni, fechaNacimiento, sexo, telefono, email, direccion, fechaIngreso) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
for (const p of state.pacientes) {
stmt.run(p.id, p.apellido, p.nombre, p.dni, p.fechaNacimiento, p.sexo, p.telefono, p.email, p.direccion, p.fechaIngreso);
}
}
if (state.areas?.length) {
const stmt = db.prepare('INSERT INTO areas (id, nombre) VALUES (?, ?)');
for (const a of state.areas) {
stmt.run(a.id, a.nombre);
}
}
if (state.camas?.length) {
const stmt = db.prepare('INSERT INTO camaS (id, numero, areaId, tipo, estado) VALUES (?, ?, ?, ?, ?)');
for (const c of state.camas) {
stmt.run(c.id, c.numero, c.areaId, c.tipo, c.estado);
}
}
if (state.internaciones?.length) {
const stmt = db.prepare('INSERT INTO internaciones (id, pacienteId, camaId, fechaIngreso, fechaEgreso, diagnosticoIngreso, motivoConsulta, enfermedadActual, antecedentesEnfermedadActual, diagnosticoEgreso, medicoIngresante, motivoEgreso, activa) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
for (const i of state.internaciones) {
stmt.run(i.id, i.pacienteId, i.camaId, i.fechaIngreso, i.fechaEgreso || null, i.diagnosticoIngreso || null, i.motivoConsulta || null, i.enfermedadActual || null, i.antecedentesEnfermedadActual || null, i.diagnosticoEgreso || null, i.medicoIngresante || null, i.motivoEgreso || null, i.activa ? 1 : 0);
}
}
if (state.evoluciones?.length) {
const stmt = db.prepare('INSERT INTO evoluciones (id, internacionId, fecha, hora, medico, signosVitales, examenFisico, novedades, comentarios, pendientes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
for (const e of state.evoluciones) {
stmt.run(e.id, e.internacionId, e.fecha, e.hora || '', e.medico || '', JSON.stringify(e.signosVitales || {}), JSON.stringify(e.examenFisico || {}), e.novedades || '', e.comentario || '', e.pendientes || '');
}
}
if (state.laboratorios?.length) {
const stmt = db.prepare('INSERT INTO laboratorios (id, pacienteId, fecha, tipo, resultados, observaciones) VALUES (?, ?, ?, ?, ?, ?)');
for (const l of state.laboratorios) {
stmt.run(l.id, l.pacienteId, l.fecha, l.tipo, JSON.stringify(l.resultados), l.observaciones);
}
}
if (state.acidosBase?.length) {
const stmt = db.prepare('INSERT INTO acidosbase (id, pacienteId, fecha, hora, ph, pco2, po2, hco3, be, statO2, lactato, interpretacion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
for (const a of state.acidosBase) {
stmt.run(a.id, a.pacienteId, a.fecha, a.hora, a.ph, a.pco2, a.po2, a.hco3, a.be, a.sato2, a.lactato, a.interpretacion);
}
}
if (state.cultivos?.length) {
const stmt = db.prepare('INSERT INTO cultivos (id, pacienteId, internacionId, fechaToma, protocolo, tipoMuestra, observaciones, estado, fechaResultado, germen, sensible, resistente) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
for (const c of state.cultivos) {
stmt.run(c.id, c.pacienteId, c.internacionId, c.fechaToma, c.protocolo, c.tipoMuestra, c.observaciones, c.estado, c.fechaResultado, c.germen, c.sensible, c.resistente);
}
}
res.json({ ok: true });
});
if (existsSync(DIST_PATH)) {
app.use(express.static(DIST_PATH));
}
app.get('*', (req, res) => {
res.sendFile(join(DIST_PATH, 'index.html'));
});
const PORT = process.env.PORT || 4000;
const HOST = process.env.HOST || '0.0.0.0';
app.listen(Number(PORT), HOST, () => {
console.log(`Server running on http://${HOST}:${PORT}`);
});