Mejoras de diseño responsive en Sistema y Configuración, gestor de parser de laboratorio y tipos de cultivo

This commit is contained in:
2026-08-16 22:29:34 +00:00
parent 5b51e4e8eb
commit 770a4ea426
9 changed files with 2132 additions and 441 deletions
+257 -5
View File
@@ -67,7 +67,7 @@ const memStore = {
movimientos_indicaciones: [],
pendientes: [],
tipos_cultivo: [],
otrosLaboratorios: [],
grupos_laboratorio: [],
kv: {}
};
@@ -859,6 +859,258 @@ export async function restablecerTiposCultivo() {
}
}
// ========== GRUPOS DE DETERMINACIONES DE LABORATORIO ==========
export const DEFAULT_GRUPOS_LABORATORIO = [
{
id: 'grp-lipidos',
nombreGrupo: 'Perfil Lipídico',
descripcion: 'Determinaciones del metabolismo lipídico y riesgo aterogénico',
activo: true,
orden: 1,
determinaciones: [
{ id: 'lip-1', nombre: 'Colesterol Total', claves: ['colesterol total', 'colesterol', 'colest. total', 'col. total', 'colest total'], unidad: 'mg/dL', rangoReferencia: '< 200 mg/dL', esAdicional: true },
{ id: 'lip-2', nombre: 'Colesterol LDL', claves: ['colesterol ldl', 'ldl-c', 'ldl', 'colest. ldl', 'colest ldl'], unidad: 'mg/dL', rangoReferencia: '< 100 mg/dL', esAdicional: true },
{ id: 'lip-3', nombre: 'Colesterol No HDL', claves: ['colesterol no-hdl', 'colesterol no hdl', 'no-hdl', 'no hdl', 'no_hdl'], unidad: 'mg/dL', rangoReferencia: '< 130 mg/dL', esAdicional: true },
{ id: 'lip-4', nombre: 'Colesterol HDL', claves: ['colesterol hdl', 'hdl-c', 'hdl', 'colest. hdl', 'colest hdl'], unidad: 'mg/dL', rangoReferencia: '> 40 mg/dL', esAdicional: true },
{ id: 'lip-5', nombre: 'Triglicéridos', claves: ['triglicéridos', 'trigliceridos', 'tg', 'triglicérido', 'triglicerido'], unidad: 'mg/dL', rangoReferencia: '< 150 mg/dL', esAdicional: true }
]
},
{
id: 'grp-ferrico',
nombreGrupo: 'Perfil Férrico',
descripcion: 'Metabolismo del hierro, transferrina, ferritina y vitaminas hematopoyéticas',
activo: true,
orden: 2,
determinaciones: [
{ id: 'fer-1', nombre: 'Hierro', claves: ['hierro', 'sideremia', 'fe'], unidad: 'µg/dL', rangoReferencia: '60 - 170 µg/dL', esAdicional: true },
{ id: 'fer-2', nombre: 'Transferrina', claves: ['transferrina', 'transferrin'], unidad: 'mg/dL', rangoReferencia: '200 - 360 mg/dL', esAdicional: true },
{ id: 'fer-3', nombre: 'Porcentaje de Saturación de Transferrina', claves: ['porcentaje de saturacion de transferrina', 'porcentaje de saturación de transferrina', 'saturacion de transferrina', 'saturación de transferrina', 'sat. transferrina', 'sat transferrina', '% sat', '% de sat', '% saturacion', '% saturación'], unidad: '%', rangoReferencia: '20 - 50 %', esAdicional: true },
{ id: 'fer-4', nombre: 'Ferritina', claves: ['ferritina', 'ferritin'], unidad: 'ng/mL', rangoReferencia: '30 - 400 ng/mL', esAdicional: true },
{ id: 'fer-5', nombre: 'Ácido Fólico', claves: ['acido folico', 'ácido fólico', 'folato', 'folatos', 'folico', 'fólico'], unidad: 'ng/mL', rangoReferencia: '3.0 - 17.0 ng/mL', esAdicional: true },
{ id: 'fer-6', nombre: 'Vitamina B12', claves: ['vitamina b12', 'b12', 'vit. b12'], unidad: 'pg/mL', rangoReferencia: '200 - 900 pg/mL', esAdicional: true }
]
},
{
id: 'grp-fosfocalcico',
nombreGrupo: 'Metabolismo Fosfocálcico y Medio Interno Extra',
descripcion: 'Calcio total, calcio iónico, fósforo y magnesio sérico',
activo: true,
orden: 3,
determinaciones: [
{ id: 'fcal-1', nombre: 'Calcio Total', claves: ['calcio total', 'calcio', 'ca total', 'ca+', 'ca++'], unidad: 'mg/dL', rangoReferencia: '8.5 - 10.5 mg/dL', esAdicional: true },
{ id: 'fcal-2', nombre: 'Calcio Iónico', claves: ['calcio ionico', 'calcio iónico', 'ca ionico', 'ca iónico', 'ca++ ionico', 'ca++ iónico', 'calcio_ionico'], unidad: 'mmol/L', rangoReferencia: '1.15 - 1.33 mmol/L', esAdicional: true },
{ id: 'fcal-3', nombre: 'Fósforo', claves: ['fósforo', 'fosforo', 'fosfemia'], unidad: 'mg/dL', rangoReferencia: '2.5 - 4.5 mg/dL', esAdicional: true },
{ id: 'fcal-4', nombre: 'Magnesio', claves: ['magnesio', 'magnesemia', 'mg++', 'mg+', 'mg2+', 'mg 2+', 'mg.', 'magnesio plasmatico', 'magnesio plasmático', 'magnesio serico', 'magnesio sérico', 'magnesio en sangre', 'mg serico', 'mg sérico', 'mg plasmatico', 'mg plasmático', 'mg'], unidad: 'mg/dL', rangoReferencia: '1.7 - 2.4 mg/dL', esAdicional: true }
]
},
{
id: 'grp-enzimas-inflamacion',
nombreGrupo: 'Enzimas, Proteínas e Inflamación',
descripcion: 'Albúmina, FAL, LDH, Procalcitonina, PCR, eritrosedimentación y enzimas',
activo: true,
orden: 4,
determinaciones: [
{ id: 'enz-1', nombre: 'Albúmina', claves: ['albúmina', 'albumina'], unidad: 'g/dL', rangoReferencia: '3.5 - 5.0 g/dL', esAdicional: true },
{ id: 'enz-2', nombre: 'Fosfatasa Alcalina', claves: ['fosfatasa alcalina', 'fal'], unidad: 'U/L', rangoReferencia: '40 - 130 U/L', esAdicional: true },
{ id: 'enz-3', nombre: 'LDH', claves: ['ldh', 'lactato deshidrogenasa', 'lactatodeshidrogenasa'], unidad: 'U/L', rangoReferencia: '135 - 225 U/L', esAdicional: true },
{ id: 'enz-4', nombre: 'Procalcitonina', claves: ['procalcitonina', 'pct'], unidad: 'ng/mL', rangoReferencia: '< 0.5 ng/mL', esAdicional: true },
{ id: 'enz-5', nombre: 'Proteína C Reactiva', claves: ['proteina c reactiva', 'proteína c reactiva', 'pcr cuantitativa', 'pcr ultrasensible', 'pcr'], unidad: 'mg/L', rangoReferencia: '< 5 mg/L', esAdicional: true },
{ id: 'enz-6', nombre: 'Eritrosedimentación', claves: ['eritrosedimentacion', 'eritrosedimentación', 'vsg', 'esr', 'eritro'], unidad: 'mm/h', rangoReferencia: '< 20 mm/h', esAdicional: true },
{ id: 'enz-7', nombre: 'CPK', claves: ['cpk', 'creatinfosfoquinasa', 'creatin fosfoquinasa', 'ck total', 'ck'], unidad: 'U/L', rangoReferencia: '20 - 200 U/L', esAdicional: true },
{ id: 'enz-8', nombre: 'Amilasa', claves: ['amilasa', 'amilasemia'], unidad: 'U/L', rangoReferencia: '28 - 100 U/L', esAdicional: true },
{ id: 'enz-9', nombre: 'Lipasa', claves: ['lipasa', 'lipasemia'], unidad: 'U/L', rangoReferencia: '13 - 60 U/L', esAdicional: true }
]
},
{
id: 'grp-tiroideo',
nombreGrupo: 'Perfil Tiroideo',
descripcion: 'Hormonas tiroideas e hipofisarias (TSH, T4L, T4, T3)',
activo: true,
orden: 5,
determinaciones: [
{ id: 'tir-1', nombre: 'TSH', claves: ['tsh', 'tirotrofina', 'tirotropina', 'tsh ultrasensible'], unidad: 'uUI/mL', rangoReferencia: '0.4 - 4.0 uUI/mL', esAdicional: true },
{ id: 'tir-2', nombre: 'T4 Libre', claves: ['t4 libre', 't4l', 't4-l', 'tiroxina libre'], unidad: 'ng/dL', rangoReferencia: '0.8 - 1.8 ng/dL', esAdicional: true },
{ id: 'tir-3', nombre: 'T4 Total', claves: ['t4 total', 't4', 'tiroxina'], unidad: 'µg/dL', rangoReferencia: '4.5 - 12.0 µg/dL', esAdicional: true },
{ id: 'tir-4', nombre: 'T3 Total', claves: ['t3 total', 't3', 'triyodotironina'], unidad: 'ng/dL', rangoReferencia: '80 - 200 ng/dL', esAdicional: true }
]
},
{
id: 'grp-cardiacos',
nombreGrupo: 'Biomarcadores Cardíacos',
descripcion: 'Péptidos natriuréticos, troponinas y marcadores de isquemia/falla',
activo: true,
orden: 6,
determinaciones: [
{ id: 'car-1', nombre: 'NT-proBNP', claves: ['nt-probnp', 'nt probnp', 'nt_probnp', 'probnp', 'pro-bnp', 'pro bnp'], unidad: 'pg/mL', rangoReferencia: '< 125 pg/mL', esAdicional: true },
{ id: 'car-2', nombre: 'Troponina T / I', claves: ['troponina t', 'troponina i', 'troponina ultrasensible', 'troponina', 'tn-t', 'tn-i', 'tnt', 'tni'], unidad: 'ng/mL', rangoReferencia: '< 0.014 ng/mL', esAdicional: true },
{ id: 'car-3', nombre: 'CK-MB', claves: ['ck-mb', 'ckmb', 'ck mb'], unidad: 'U/L', rangoReferencia: '< 25 U/L', esAdicional: true }
]
},
{
id: 'grp-hemograma-indices',
nombreGrupo: 'Hemograma - Índices y Fórmula',
descripcion: 'Constantes corpusculares e índices hematimétricos adicionales',
activo: true,
orden: 7,
determinaciones: [
{ id: 'hem-1', nombre: 'VCM', claves: ['volumen corpuscular medio', 'vcm'], unidad: 'fL', rangoReferencia: '80 - 100 fL', esAdicional: true },
{ id: 'hem-2', nombre: 'HCM', claves: ['hemoglobina corpuscular media', 'hcm'], unidad: 'pg', rangoReferencia: '27 - 33 pg', esAdicional: true },
{ id: 'hem-3', nombre: 'CHCM', claves: ['concentracion de hemoglobina corpuscular media', 'chcm'], unidad: 'g/dL', rangoReferencia: '32 - 36 g/dL', esAdicional: true },
{ id: 'hem-4', nombre: 'RDW', claves: ['rdw', 'ide', 'ancho de distribucion eritrocitaria'], unidad: '%', rangoReferencia: '11.5 - 14.5 %', esAdicional: true },
{ id: 'hem-5', nombre: 'Neutrófilos', claves: ['neutrófilos', 'neutrofilos', 'neutrofilos segmentados', 'segmentados'], unidad: '%', rangoReferencia: '45 - 70 %', esAdicional: true },
{ id: 'hem-6', nombre: 'Linfocitos', claves: ['linfocitos', 'linfo'], unidad: '%', rangoReferencia: '20 - 45 %', esAdicional: true },
{ id: 'hem-7', nombre: 'Monocitos', claves: ['monocitos', 'mono'], unidad: '%', rangoReferencia: '2 - 10 %', esAdicional: true },
{ id: 'hem-8', nombre: 'Eosinófilos', claves: ['eosinófilos', 'eosinofilos', 'eosino'], unidad: '%', rangoReferencia: '1 - 4 %', esAdicional: true },
{ id: 'hem-9', nombre: 'Basófilos', claves: ['basófilos', 'basofilos'], unidad: '%', rangoReferencia: '0 - 1 %', esAdicional: true },
{ id: 'hem-10', nombre: 'Eritroblastos', claves: ['eritroblastos'], unidad: '%', rangoReferencia: '0 %', esAdicional: true },
{ id: 'hem-11', nombre: 'VPM', claves: ['volumen plaquetario medio', 'vpm'], unidad: 'fL', rangoReferencia: '7.5 - 11.5 fL', esAdicional: true }
]
}
];
export async function getAllGruposLaboratorio() {
let list = [];
if (db) {
const raw = await db.collection('grupos_laboratorio').find().sort({ orden: 1, nombreGrupo: 1 }).toArray();
list = cleanDocs(raw);
if (list.length === 0) {
for (const item of DEFAULT_GRUPOS_LABORATORIO) {
await db.collection('grupos_laboratorio').insertOne({ ...item });
}
list = [...DEFAULT_GRUPOS_LABORATORIO];
}
return list;
} else {
if (!memStore.grupos_laboratorio || memStore.grupos_laboratorio.length === 0) {
memStore.grupos_laboratorio = DEFAULT_GRUPOS_LABORATORIO.map(item => JSON.parse(JSON.stringify(item)));
}
return [...memStore.grupos_laboratorio];
}
}
export async function createGrupoLaboratorio(grupo) {
const doc = {
id: grupo.id || generateUUID(),
nombreGrupo: (grupo.nombreGrupo || '').trim(),
descripcion: (grupo.descripcion || '').trim(),
activo: grupo.activo !== false,
orden: typeof grupo.orden === 'number' ? grupo.orden : 99,
determinaciones: Array.isArray(grupo.determinaciones) ? grupo.determinaciones.map(d => ({
id: d.id || generateUUID(),
nombre: (d.nombre || '').trim(),
claves: Array.isArray(d.claves) ? d.claves.map(c => (c || '').trim().toLowerCase()).filter(Boolean) : [],
unidad: (d.unidad || '').trim(),
esPrincipal: Boolean(d.esPrincipal),
esAdicional: d.esAdicional !== false,
rangoReferencia: (d.rangoReferencia || '').trim(),
descripcion: (d.descripcion || '').trim()
})) : [],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
if (!doc.nombreGrupo) {
throw new Error('El nombre del grupo de laboratorio es requerido');
}
if (db) {
const existing = await db.collection('grupos_laboratorio').findOne({ nombreGrupo: doc.nombreGrupo });
if (existing) {
throw new Error(`Ya existe un grupo de determinaciones con el nombre "${doc.nombreGrupo}"`);
}
await db.collection('grupos_laboratorio').insertOne(doc);
} else {
if (!memStore.grupos_laboratorio) memStore.grupos_laboratorio = [];
const exists = memStore.grupos_laboratorio.some(g => g.nombreGrupo.toLowerCase() === doc.nombreGrupo.toLowerCase());
if (exists) {
throw new Error(`Ya existe un grupo de determinaciones con el nombre "${doc.nombreGrupo}"`);
}
memStore.grupos_laboratorio.push(doc);
}
return doc;
}
export async function updateGrupoLaboratorio(id, datos) {
const updateDoc = { ...datos, updatedAt: new Date().toISOString() };
delete updateDoc._id;
delete updateDoc.id;
if (datos.nombreGrupo) {
updateDoc.nombreGrupo = datos.nombreGrupo.trim();
}
if (datos.descripcion !== undefined) {
updateDoc.descripcion = datos.descripcion.trim();
}
if (datos.activo !== undefined) {
updateDoc.activo = Boolean(datos.activo);
}
if (datos.orden !== undefined) {
updateDoc.orden = Number(datos.orden);
}
if (Array.isArray(datos.determinaciones)) {
updateDoc.determinaciones = datos.determinaciones.map(d => ({
id: d.id || generateUUID(),
nombre: (d.nombre || '').trim(),
claves: Array.isArray(d.claves) ? d.claves.map(c => (c || '').trim().toLowerCase()).filter(Boolean) : [],
unidad: (d.unidad || '').trim(),
esPrincipal: Boolean(d.esPrincipal),
esAdicional: d.esAdicional !== false,
rangoReferencia: (d.rangoReferencia || '').trim(),
descripcion: (d.descripcion || '').trim()
}));
}
if (db) {
if (updateDoc.nombreGrupo) {
const existing = await db.collection('grupos_laboratorio').findOne({
id: { $ne: id },
nombreGrupo: updateDoc.nombreGrupo
});
if (existing) {
throw new Error(`Ya existe otro grupo de determinaciones con el nombre "${updateDoc.nombreGrupo}"`);
}
}
await db.collection('grupos_laboratorio').updateOne({ id }, { $set: updateDoc });
} else {
if (!memStore.grupos_laboratorio) memStore.grupos_laboratorio = [];
if (updateDoc.nombreGrupo) {
const exists = memStore.grupos_laboratorio.some(g => g.id !== id && g.nombreGrupo.toLowerCase() === updateDoc.nombreGrupo.toLowerCase());
if (exists) {
throw new Error(`Ya existe otro grupo de determinaciones con el nombre "${updateDoc.nombreGrupo}"`);
}
}
const idx = memStore.grupos_laboratorio.findIndex(g => g.id === id);
if (idx !== -1) {
memStore.grupos_laboratorio[idx] = { ...memStore.grupos_laboratorio[idx], ...updateDoc };
}
}
return { id, ...updateDoc };
}
export async function deleteGrupoLaboratorio(id) {
if (db) {
await db.collection('grupos_laboratorio').deleteOne({ id });
} else {
if (memStore.grupos_laboratorio) {
memStore.grupos_laboratorio = memStore.grupos_laboratorio.filter(g => g.id !== id);
}
}
return { success: true };
}
export async function restablecerGruposLaboratorio() {
if (db) {
await db.collection('grupos_laboratorio').deleteMany({});
for (const item of DEFAULT_GRUPOS_LABORATORIO) {
await db.collection('grupos_laboratorio').insertOne({ ...item });
}
return await getAllGruposLaboratorio();
} else {
memStore.grupos_laboratorio = DEFAULT_GRUPOS_LABORATORIO.map(item => JSON.parse(JSON.stringify(item)));
return [...memStore.grupos_laboratorio];
}
}
// ========== ESTUDIOS COMPLEMENTARIOS ==========
export async function getAllEstudiosComplementarios() {
if (db) {
@@ -1158,8 +1410,8 @@ export function getDb() {
export async function exportAllData() {
const collections = [
'usuarios', 'pacientes', 'areas', 'camas', 'internaciones',
'evoluciones', 'laboratorios', 'glucemias', 'acidosbase',
'cultivos', 'tipos_cultivo', 'estudiosComplementarios', 'interconsultas', 'atb',
'evoluciones', 'laboratorios', 'otrosLaboratorios', 'glucemias', 'acidosbase',
'cultivos', 'tipos_cultivo', 'grupos_laboratorio', 'estudiosComplementarios', 'interconsultas', 'atb',
'indicaciones', 'movimientos_indicaciones', 'pendientes', 'kv'
];
const dump = {};
@@ -1179,8 +1431,8 @@ export async function exportAllData() {
export async function importAllData(dump) {
const collections = [
'usuarios', 'pacientes', 'areas', 'camas', 'internaciones',
'evoluciones', 'laboratorios', 'glucemias', 'acidosbase',
'cultivos', 'tipos_cultivo', 'estudiosComplementarios', 'interconsultas', 'atb',
'evoluciones', 'laboratorios', 'otrosLaboratorios', 'glucemias', 'acidosbase',
'cultivos', 'tipos_cultivo', 'grupos_laboratorio', 'estudiosComplementarios', 'interconsultas', 'atb',
'indicaciones', 'movimientos_indicaciones', 'pendientes', 'kv'
];
if (db) {