253 lines
8.1 KiB
JavaScript
253 lines
8.1 KiB
JavaScript
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}`);
|
|
});
|