feat: multi-archivo órdenes visible en enfermero, domicilios y órdenes médicas

- OrdenMedica::filtrarCampos(): agrega domicilio_id al whitelist
- Domicilio::obtener(): consulta secundaria archivos_ordenes[] con fallback
- Enfermera::agenda(): bulk-query archivos_ordenes[] por domicilio_id
- api/lab/link_ordenes_domicilio.php: API POST vincula orden_ids a domicilio_id
- conversations.php guardar(): trackea allOrdenIds[], llama link API post-save
- lab_domicilios.php: renderOrdenesDetail() multi-archivo en detalle
- enfermero_portal.php: renderOrdenesEnfermero() multi-archivo en cards
- lab_ordenes.php: botón 'Ver domicilio' cuando domicilio_id está vinculado
- migrations/: ALTER TABLE lab_ordenes_medicas ADD domicilio_id + índice
This commit is contained in:
Lizandro Guarnizo
2026-03-24 21:51:29 -05:00
parent aa17dc299b
commit 2abce6d4c2
10 changed files with 262 additions and 51 deletions
+45 -28
View File
@@ -685,34 +685,7 @@ async function verDomicilio(id) {
</div>`}
</div>
<!-- Orden médica -->
${dom.orden_id ? `
<div class="mb-3">
<label class="form-label small text-muted text-uppercase">Orden médica</label>
${(() => {
const lf = dom.orden_local_file || '';
const isImg = /\.(jpe?g|png|gif|webp)$/i.test(lf);
const url = lf ? 'uploads/media/' + encodeURIComponent(lf) : '';
if (lf && isImg) return `
<a href="${url}" target="_blank" title="Ver imagen completa">
<img src="${url}" alt="Orden médica"
style="max-width:100%;max-height:180px;object-fit:contain;border-radius:6px;border:1px solid #dee2e6;display:block;cursor:zoom-in">
</a>
<a href="lab_ordenes.php?id=${dom.orden_id}" class="d-block small mt-1 text-muted">
<i class="fas fa-external-link-alt me-1"></i>Ver ficha orden #${dom.orden_id}
</a>`;
if (lf) return `
<a href="api/lab/descargar_orden.php?file=${encodeURIComponent(lf)}" target="_blank"
class="btn btn-sm btn-outline-secondary w-100 mb-1">
<i class="fas fa-file-download me-1"></i>Abrir / Descargar archivo
</a>
<a href="lab_ordenes.php?id=${dom.orden_id}" class="d-block small text-muted">
<i class="fas fa-external-link-alt me-1"></i>Ver ficha orden #${dom.orden_id}
</a>`;
return `<a href="lab_ordenes.php?id=${dom.orden_id}" class="d-block small">
<i class="fas fa-file-medical me-1"></i>Ver orden #${dom.orden_id}
</a>`;
})()}
</div>` : ''}
${renderOrdenesDetail(dom)}
<!-- Botones de flujo -->
<div class="d-flex gap-2 flex-wrap">${btns}</div>
</div>
@@ -998,6 +971,50 @@ function verHoy() {
// ── Utils ──────────────────────────────────────────────────────────────────
const esc = s => String(s||'').replace(/[<>&"]/g, c => ({'<':'&lt;','>':'&gt;','&':'&amp;','"':'&quot;'}[c]));
/**
* Renderiza el bloque de órdenes médicas (multi-archivo) en el detalle de domicilio.
*/
function renderOrdenesDetail(dom) {
const archivos = dom.archivos_ordenes || [];
if (!archivos.length && !dom.orden_id) return '';
// Si no hay archivos cargados pero sí hay orden_id, mostramos solo el link
if (!archivos.length) {
return `<div class="mb-3">
<label class="form-label small text-muted text-uppercase">Órdenes médicas</label>
<a href="lab_ordenes.php?id=${dom.orden_id}" class="d-block small">
<i class="fas fa-file-medical me-1"></i>Ver orden #${dom.orden_id}
</a>
</div>`;
}
const items = archivos.map(a => {
const lf = a.local_file || '';
const isImg = /\.(jpe?g|png|gif|webp)$/i.test(lf);
const url = lf ? ('uploads/media/' + encodeURIComponent(lf)) : '';
const ficha = `<a href="lab_ordenes.php?id=${a.orden_id}" class="d-block small text-muted mt-1">
<i class="fas fa-external-link-alt me-1"></i>Orden #${a.orden_id}
</a>`;
if (lf && isImg) return `
<div class="mb-2">
<a href="${url}" target="_blank" title="Ver imagen completa">
<img src="${url}" alt="Orden médica"
style="max-width:100%;max-height:180px;object-fit:contain;border-radius:6px;border:1px solid #dee2e6;display:block;cursor:zoom-in">
</a>${ficha}
</div>`;
if (lf) return `
<div class="mb-2">
<a href="api/lab/descargar_orden.php?file=${encodeURIComponent(lf)}" target="_blank"
class="btn btn-sm btn-outline-secondary w-100 mb-1">
<i class="fas fa-file-download me-1"></i>Abrir / Descargar archivo
</a>${ficha}
</div>`;
return `<div class="mb-2">${ficha}</div>`;
}).join('');
return `<div class="mb-3">
<label class="form-label small text-muted text-uppercase">Órdenes médicas (${archivos.length})</label>
${items}
</div>`;
}
function mostrarToast(msg, tipo='success') {
const div = document.createElement('div');
div.className = `alert alert-${tipo} alert-dismissible position-fixed bottom-0 end-0 m-3`;