Files
whatsapp/lab_domicilios.php
T
Lizandro Guarnizo eaebda9fe7 feat: edición completa de domicilio desde panel detalle
- Modal expandido: tipo_cliente, seguro, autorizacion, valor_domicilio, valor_copago, copago_laboratorio, indicaciones, fecha, hora, tipo_servicio, notas
- Botón Editar en header del panel detalle (aparece al seleccionar un domicilio)
- editarDomicilio(id): carga y pre-rellena todos los campos del modal
- toggleSeguro(): muestra/oculta campo seguro_nombre según tipo_cliente
- Tras guardar, el detalle se refresca automáticamente
2026-03-12 23:00:25 -05:00

665 lines
37 KiB
PHP

<?php
/**
* Gestión de Domicilios — Módulo Administrativo de Laboratorio
*/
require_once 'config/config.php';
if (!isUserLoggedIn()) {
header('Location: login.php');
exit;
}
if (isEnfermero()) { header('Location: enfermero_portal.php'); exit; }
$adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['username'] ?? 'Admin';
$ordenIdParam = (int)($_GET['orden_id'] ?? 0);
$pacIdParam = (int)($_GET['paciente_id']?? 0);
$domIdParam = (int)($_GET['id'] ?? 0);
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Domicilios — Módulo Lab</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="./assets/css/styles.css?v=12" rel="stylesheet">
<style>
.dom-row { cursor:pointer; }
.estado-badge { font-size:.72rem; }
.agenda-card { border-left: 4px solid #dee2e6; padding: 8px 12px; margin-bottom: 8px; border-radius: 0 8px 8px 0; }
.agenda-card.programado { border-left-color: #6c757d; }
.agenda-card.en_camino { border-left-color: #0d6efd; }
.agenda-card.completado { border-left-color: #198754; }
.agenda-card.cancelado { border-left-color: #dc3545; }
</style>
</head>
<body>
<nav class="sidebar">
<div class="sidebar-header"><h4><i class="fas fa-flask"></i> Módulo Lab</h4></div>
<ul class="sidebar-menu">
<li><a href="lab_dashboard.php" class="nav-link"><i class="fas fa-tachometer-alt"></i> Dashboard</a></li>
<li><a href="lab_ordenes.php" class="nav-link"><i class="fas fa-file-medical"></i> Órdenes</a></li>
<li><a href="lab_pacientes.php" class="nav-link"><i class="fas fa-users"></i> Pacientes</a></li>
<li><a href="lab_domicilios.php" class="nav-link active"><i class="fas fa-house-medical"></i> Domicilios</a></li>
<li><a href="lab_enfermeras.php" class="nav-link"><i class="fas fa-user-nurse"></i> Enfermeras</a></li>
<li><a href="lab_formularios.php" class="nav-link"><i class="fas fa-wpforms"></i> Formularios</a></li>
<li><a href="lab_reportes.php" class="nav-link"><i class="fas fa-chart-bar"></i> Reportes</a></li>
<li><a href="lab_configuracion.php" class="nav-link"><i class="fas fa-sliders-h"></i> Configuración</a></li>
<li><a href="lab_usuarios.php" class="nav-link"><i class="fas fa-users-cog"></i> Usuarios</a></li>
<li class="sidebar-divider"></li>
<li><a href="index.php" class="nav-link"><i class="fas fa-arrow-left"></i> Volver al Bot</a></li>
<li><a href="logout.php" class="nav-link logout-link" onclick="return confirm('¿Cerrar sesión?')"><i class="fas fa-sign-out-alt"></i> Cerrar Sesión</a></li>
</ul>
</nav>
<main class="main-content">
<header class="content-header d-flex align-items-center justify-content-between">
<div>
<h1><i class="fas fa-house-medical text-primary"></i> Domicilios</h1>
<small class="text-muted"><?= htmlspecialchars($adminNombre) ?></small>
</div>
<button class="btn btn-primary btn-sm" onclick="abrirFormulario()">
<i class="fas fa-plus me-1"></i> Nuevo Domicilio
</button>
</header>
<div class="container-fluid py-3">
<!-- Filtros -->
<div class="row g-2 mb-3">
<div class="col-md-2">
<input type="date" id="filtro-fecha" class="form-control form-control-sm"
value="<?= date('Y-m-d') ?>" onchange="cargarLista()">
</div>
<div class="col-md-2">
<select id="filtro-estado" class="form-select form-select-sm" onchange="cargarLista()">
<option value="">Todos los estados</option>
<option>programado</option><option>confirmado</option><option>en_camino</option>
<option>en_domicilio</option><option>completado</option><option>cancelado</option>
</select>
</div>
<div class="col-md-2">
<select id="filtro-enfermera" class="form-select form-select-sm" onchange="cargarLista()">
<option value="">Todas las enfermeras</option>
</select>
</div>
<div class="col-md-2">
<button class="btn btn-sm btn-secondary w-100" onclick="verHoy()">
<i class="fas fa-calendar-day me-1"></i> Hoy
</button>
</div>
</div>
<!-- Resumen del día -->
<div class="row g-2 mb-3" id="resumen-hoy"></div>
<div class="row g-3">
<!-- Tabla -->
<div class="col-lg-5">
<div class="card border-0 shadow-sm">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr><th>Hora</th><th>Paciente</th><th>Enfermera</th><th>Estado</th></tr>
</thead>
<tbody id="tabla-body">
<tr><td colspan="4" class="text-center py-4 text-muted"><i class="fas fa-spinner fa-spin"></i></td></tr>
</tbody>
</table>
</div>
<div class="d-flex align-items-center justify-content-between px-3 py-2 border-top" id="paginacion"></div>
</div>
</div>
</div>
<!-- Detalle -->
<div class="col-lg-7">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white border-0 d-flex justify-content-between align-items-center">
<h6 class="mb-0 fw-semibold">Detalle <span id="detail-id" class="text-muted"></span></h6>
<div class="d-flex gap-2">
<button class="btn btn-sm btn-outline-primary d-none" id="btn-editar-dom"
onclick="editarDomicilio(domSeleccionado)">
<i class="fas fa-edit me-1"></i>Editar
</button>
<button class="btn-close" onclick="cerrarDetalle()"></button>
</div>
</div>
<div class="card-body" id="detail-body">
<div class="text-center py-5 text-muted">
<i class="fas fa-arrow-left me-2"></i>Selecciona un domicilio
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- Modal Formulario (Nuevo / Editar) -->
<div class="modal fade" id="modalDomicilio" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="fas fa-house-medical me-2"></i><span id="modal-titulo">Nuevo Domicilio</span></h5>
<button class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="form-domicilio">
<input type="hidden" name="id" id="dom-id">
<input type="hidden" name="orden_id" id="dom-orden-id" value="<?= $ordenIdParam ?>">
<!-- ── Paciente ── -->
<h6 class="text-muted text-uppercase small fw-semibold border-bottom pb-1 mb-3">
<i class="fas fa-user me-1"></i> Paciente y servicio
</h6>
<div class="row g-3 mb-3">
<div class="col-md-8">
<label class="form-label">Paciente <span class="text-danger">*</span></label>
<input type="hidden" name="paciente_id" id="dom-paciente-id" value="<?= $pacIdParam ?>">
<input type="text" class="form-control" id="dom-paciente-nombre" placeholder="Buscar paciente…" autocomplete="off">
<div class="list-group mt-1 shadow-sm" id="pac-suggest" style="position:absolute;z-index:1000;max-height:200px;overflow-y:auto;display:none"></div>
</div>
<div class="col-md-4">
<label class="form-label">Tipo de servicio</label>
<input type="text" class="form-control" name="tipo_servicio" id="dom-tipo" placeholder="Ej: toma de muestras">
</div>
<div class="col-md-4">
<label class="form-label">Tipo de cliente</label>
<select class="form-select" name="tipo_cliente" id="dom-tipo-cliente" onchange="toggleSeguro(this.value)">
<option value="particular">Particular</option>
<option value="seguro">Seguro / EPS</option>
</select>
</div>
<div class="col-md-4" id="bloque-seguro" style="display:none">
<label class="form-label">Nombre del seguro / EPS</label>
<input type="text" class="form-control" name="seguro_nombre" id="dom-seguro-nombre" placeholder="Ej: Sura, Nueva EPS…">
</div>
<div class="col-md-4">
<label class="form-label">N° de autorización</label>
<input type="text" class="form-control" name="autorizacion" id="dom-autorizacion" placeholder="Número de autorización">
</div>
</div>
<!-- ── Dirección ── -->
<h6 class="text-muted text-uppercase small fw-semibold border-bottom pb-1 mb-3">
<i class="fas fa-map-marker-alt me-1"></i> Dirección
</h6>
<div class="row g-3 mb-3">
<div class="col-md-12">
<label class="form-label">Dirección completa <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="direccion" id="dom-dir" required>
</div>
<div class="col-md-4">
<label class="form-label">Ciudad</label>
<input type="text" class="form-control" name="ciudad" id="dom-ciudad">
</div>
<div class="col-md-4">
<label class="form-label">Barrio</label>
<input type="text" class="form-control" name="barrio" id="dom-barrio">
</div>
<div class="col-md-4">
<label class="form-label">Indicaciones adicionales</label>
<input type="text" class="form-control" name="indicaciones_dir" id="dom-indic" placeholder="Ej: apto 302, tocar campanilla">
</div>
</div>
<!-- ── Fecha / hora ── -->
<h6 class="text-muted text-uppercase small fw-semibold border-bottom pb-1 mb-3">
<i class="fas fa-calendar-alt me-1"></i> Programación
</h6>
<div class="row g-3 mb-3">
<div class="col-md-4">
<label class="form-label">Fecha programada <span class="text-danger">*</span></label>
<input type="date" class="form-control" name="fecha_programada" id="dom-fecha" required>
</div>
<div class="col-md-4">
<label class="form-label">Hora</label>
<input type="time" class="form-control" name="hora_programada" id="dom-hora">
</div>
</div>
<!-- ── Cobros ── -->
<h6 class="text-muted text-uppercase small fw-semibold border-bottom pb-1 mb-3">
<i class="fas fa-cash-register me-1"></i> Cobros
</h6>
<div class="row g-3 mb-3">
<div class="col-md-4">
<label class="form-label">Valor domicilio</label>
<div class="input-group">
<span class="input-group-text">$</span>
<input type="number" class="form-control" name="valor_domicilio" id="dom-valor-dom"
min="0" step="1000" placeholder="0">
</div>
</div>
<div class="col-md-4">
<label class="form-label">Copago cliente</label>
<div class="input-group">
<span class="input-group-text">$</span>
<input type="number" class="form-control" name="valor_copago" id="dom-valor-cop"
min="0" step="1000" placeholder="0">
</div>
</div>
<div class="col-md-4">
<label class="form-label">Copago laboratorio</label>
<div class="input-group">
<span class="input-group-text">$</span>
<input type="number" class="form-control" name="copago_laboratorio" id="dom-copago-lab"
min="0" step="1000" placeholder="0">
</div>
</div>
</div>
<!-- ── Notas ── -->
<div class="mb-2">
<label class="form-label">Notas internas</label>
<textarea class="form-control" name="notas_admin" id="dom-notas" rows="2"
placeholder="Observaciones para el equipo…"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
<button class="btn btn-primary" onclick="guardarDomicilio()"><i class="fas fa-save me-1"></i> Guardar</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
const modal = new bootstrap.Modal('#modalDomicilio');
const COLOR_DOM = { programado:'secondary', confirmado:'info', en_camino:'primary', en_domicilio:'warning', completado:'success', cancelado:'danger', reprogramado:'dark' };
let domSeleccionado = <?= $domIdParam ?: 'null' ?>;
let paginaActual = 1;
let _listaToken = 0; // anti race-condition
// ── Init ───────────────────────────────────────────────────────────────────
(async function init() {
await cargarEnfermeras();
await cargarLista();
if (domSeleccionado) verDomicilio(domSeleccionado);
if (<?= $ordenIdParam ?> && <?= $pacIdParam ?>) abrirFormulario();
})();
async function cargarEnfermeras() {
const r = await fetch('api/lab/get_enfermeras.php');
const d = await r.json();
const sel = document.getElementById('filtro-enfermera');
(d.data||[]).forEach(e => {
sel.insertAdjacentHTML('beforeend', `<option value="${e.id}">${esc(e.nombre_completo)}</option>`);
});
}
// ── Lista ──────────────────────────────────────────────────────────────────
async function cargarLista(pag = 1) {
paginaActual = pag;
const miToken = ++_listaToken; // capturar token antes del await
const params = new URLSearchParams({
fecha: document.getElementById('filtro-fecha').value || '',
estado: document.getElementById('filtro-estado').value,
enfermera_id: document.getElementById('filtro-enfermera').value,
page: pag, limit: 25,
});
const r = await fetch(`api/lab/get_domicilios.php?${params}`);
const d = await r.json();
if (miToken !== _listaToken) return; // respuesta desactualizada, ignorar
renderResumen(d.estadisticas_hoy, d.domicilios?.sin_asignar ?? d.sin_asignar_hoy);
const tbody = document.getElementById('tabla-body');
if (!d.data?.length) {
tbody.innerHTML = '<tr><td colspan="4" class="text-center py-4 text-muted">Sin domicilios</td></tr>';
document.getElementById('paginacion').innerHTML = '';
return;
}
tbody.innerHTML = d.data.map(dom => `
<tr class="dom-row ${domSeleccionado===dom.id?'table-active':''}" id="row-${dom.id}" onclick="verDomicilio(${dom.id})">
<td>${dom.hora_programada||'—'}</td>
<td>
<div class="fw-semibold">${esc(dom.paciente_nombre)}</div>
<small class="text-muted">${esc(dom.barrio||'')}</small>
</td>
<td>${dom.enfermera_nombre ? `<small>${esc(dom.enfermera_nombre)}</small>` : '<span class="text-danger small"><i class="fas fa-exclamation-triangle me-1"></i>Sin asignar</span>'}</td>
<td>
<span class="badge bg-${COLOR_DOM[dom.estado]||'secondary'} estado-badge">${esc(dom.estado)}</span>
${(dom.pago_estado === 'pagado')
? '<span class="badge rounded-pill ms-1" style="background:#d1fae5;color:#065f46;border:1px solid #34d399">✅ Pagado</span>'
: (dom.pago_estado === 'exento'
? '<span class="badge rounded-pill ms-1" style="background:#e0e7ff;color:#3730a3;border:1px solid #818cf8">🔵 Exento</span>'
: ((parseFloat(dom.valor_domicilio)||0)+(parseFloat(dom.valor_copago)||0) > 0
? '<span class="badge rounded-pill ms-1" style="background:#fff3cd;color:#664d03;border:1px solid #ffc107">⏳ Cobro</span>'
: ''))}
</td>
</tr>
`).join('');
const el = document.getElementById('paginacion');
if (d.paginas > 1) {
el.innerHTML = `
<small class="text-muted">${d.total} domicilio(s)</small>
<div class="btn-group btn-group-sm">
${pag>1?`<button class="btn btn-outline-secondary" onclick="cargarLista(${pag-1})"><i class="fas fa-chevron-left"></i></button>`:''}
<button class="btn btn-secondary disabled">${pag}/${d.paginas}</button>
${pag<d.paginas?`<button class="btn btn-outline-secondary" onclick="cargarLista(${pag+1})"><i class="fas fa-chevron-right"></i></button>`:''}
</div>`;
} else {
el.innerHTML = `<small class="text-muted">${d.total} domicilio(s)</small>`;
}
}
function renderResumen(stats, sinAsignar) {
if (!stats) return;
const items = [
{ label:'Programados', val: stats.programado||0, color:'secondary' },
{ label:'En camino', val: stats.en_camino||0, color:'primary' },
{ label:'Completados', val: stats.completado||0, color:'success' },
{ label:'Sin enfermera',val: sinAsignar||0, color:'danger' },
];
document.getElementById('resumen-hoy').innerHTML = items.map(i =>
`<div class="col-6 col-md-3">
<div class="card border-0 shadow-sm text-center py-2">
<div class="fs-4 fw-bold text-${i.color}">${i.val}</div>
<div class="text-muted small">${i.label}</div>
</div>
</div>`
).join('');
}
// ── Detalle ────────────────────────────────────────────────────────────────
async function verDomicilio(id) {
domSeleccionado = id;
document.querySelectorAll('.dom-row').forEach(r => r.classList.remove('table-active'));
const rowEl = document.getElementById(`row-${id}`);
if (rowEl) rowEl.classList.add('table-active');
document.getElementById('detail-id').textContent = `#${id}`;
document.getElementById('detail-body').innerHTML = '<div class="text-center py-3"><i class="fas fa-spinner fa-spin"></i></div>';
document.getElementById('btn-editar-dom').classList.remove('d-none');
const r = await fetch(`api/lab/get_domicilios.php?id=${id}&no_stats=1`);
const d = await r.json();
const dom = d.domicilio;
if (!dom) return;
// Botones de estado
const SIGUIENTES = {
programado: [['confirmado','Confirmar','info'],['cancelado','Cancelar','danger']],
confirmado: [['en_camino','En camino','primary'],['cancelado','Cancelar','danger']],
en_camino: [['en_domicilio','En domicilio','warning']],
en_domicilio:[['completado','Completar','success']],
};
const btns = (SIGUIENTES[dom.estado]||[]).map(([e,lbl,col]) =>
`<button class="btn btn-sm btn-${col}" onclick="cambiarEstado(${dom.id},'${e}')">
<i class="fas fa-arrow-right me-1"></i>${lbl}
</button>`
).join('');
document.getElementById('detail-body').innerHTML = `
<div class="row g-3">
<div class="col-md-6">
<dl class="row small">
<dt class="col-5 text-muted">Paciente</dt><dd class="col-7 fw-semibold">${esc(dom.paciente_nombre)}</dd>
<dt class="col-5 text-muted">Teléfono</dt><dd class="col-7">${esc(dom.paciente_telefono||'—')}</dd>
<dt class="col-5 text-muted">Dirección</dt><dd class="col-7">${esc(dom.direccion)}</dd>
<dt class="col-5 text-muted">Barrio</dt><dd class="col-7">${esc(dom.barrio||'—')}</dd>
<dt class="col-5 text-muted">Indicaciones</dt><dd class="col-7">${esc(dom.indicaciones_dir||'—')}</dd>
<dt class="col-5 text-muted">Fecha</dt><dd class="col-7">${esc(dom.fecha_programada)} ${esc(dom.hora_programada||'')}</dd>
<dt class="col-5 text-muted">Servicio</dt><dd class="col-7">${esc(dom.tipo_servicio||'—')}</dd>
<dt class="col-5 text-muted">Tipo cliente</dt><dd class="col-7">
${dom.tipo_cliente === 'seguro'
? `<span class="badge bg-info text-dark"><i class="fas fa-shield-alt me-1"></i>Seguro${dom.seguro_nombre ? ' — '+esc(dom.seguro_nombre) : ''}</span>`
: `<span class="badge bg-secondary"><i class="fas fa-wallet me-1"></i>Particular</span>`}
</dd>
${dom.autorizacion ? `<dt class="col-5 text-muted">Autorización</dt><dd class="col-7">${esc(dom.autorizacion)}</dd>` : ''}
${dom.copago_laboratorio ? `<dt class="col-5 text-muted">Copago lab.</dt><dd class="col-7">$${Number(dom.copago_laboratorio).toLocaleString('es-CO')}</dd>` : ''}
</dl>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label small text-muted text-uppercase">Estado actual</label><br>
<span class="badge bg-${COLOR_DOM[dom.estado]||'secondary'} fs-6">${esc(dom.estado)}</span>
</div>
<!-- Enfermera asignada -->
<div class="mb-3">
<label class="form-label small text-muted text-uppercase">Enfermera</label>
${dom.enfermera_nombre
? `<div class="d-flex align-items-center gap-2">
<span><i class="fas fa-user-nurse text-success me-1"></i>${esc(dom.enfermera_nombre)}</span>
<button class="btn btn-xs btn-outline-secondary py-0 px-2" onclick="mostrarAsignacion(${dom.id})">Reasignar</button>
</div>`
: `<div class="alert alert-warning py-2 small d-flex align-items-center justify-content-between mb-0">
<span><i class="fas fa-exclamation-triangle me-2"></i>Sin enfermera asignada</span>
<button class="btn btn-sm btn-warning" onclick="mostrarAsignacion(${dom.id})"><i class="fas fa-user-plus me-1"></i>Asignar</button>
</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>
<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>` : ''}
<!-- Botones de flujo -->
<div class="d-flex gap-2 flex-wrap">${btns}</div>
</div>
</div>
<div class="row mt-3">
<div class="col-12">
<label class="form-label small text-muted text-uppercase">Exámenes de la orden</label>
<div class="bg-light p-2 rounded small">${esc(dom.examenes_solicitados||'—')}</div>
</div>
</div>
${(dom.valor_domicilio || dom.valor_copago) ? (() => {
const totalC = (parseFloat(dom.valor_domicilio)||0)+(parseFloat(dom.valor_copago)||0);
const PAGO_INFO = {
pendiente: { bg:'#fff3cd', color:'#664d03', border:'#ffc107', icon:'⏳', txt:'Pago pendiente' },
pagado: { bg:'#d1fae5', color:'#065f46', border:'#34d399', icon:'✅', txt:'Pagado' },
exento: { bg:'#e0e7ff', color:'#3730a3', border:'#818cf8', icon:'🔵', txt:'Exento' },
};
const pEst = dom.pago_estado || 'pendiente';
const pInfo = PAGO_INFO[pEst] || PAGO_INFO.pendiente;
const MODO_LABEL = { efectivo:'💵 Efectivo', transferencia:'📲 Transferencia', otro:'📋 Otro' };
return `
<div class="row mt-3">
<div class="col-12">
<div class="p-2 rounded" style="background:#d1fae5;border:1px solid #6ee7b7">
<div class="d-flex justify-content-between align-items-center mb-1">
<span class="small fw-semibold text-success"><i class="fas fa-cash-register me-1"></i>Cobro al cliente</span>
<span class="badge rounded-pill small" style="background:${pInfo.bg};color:${pInfo.color};border:1px solid ${pInfo.border}">${pInfo.icon} ${pInfo.txt}</span>
</div>
<div class="d-flex gap-3 flex-wrap">
${dom.valor_domicilio ? `<span class="small">Domicilio: <strong>$${Number(dom.valor_domicilio).toLocaleString('es-CO')}</strong></span>` : ''}
${dom.valor_copago ? `<span class="small">Copago: <strong>$${Number(dom.valor_copago).toLocaleString('es-CO')}</strong></span>` : ''}
${totalC > 0 ? `<span class="small fw-bold text-success">Total: $${totalC.toLocaleString('es-CO')}</span>` : ''}
</div>
${dom.pago_estado === 'pagado' ? `
<div class="small mt-1 text-success">
${MODO_LABEL[dom.pago_modo] || (dom.pago_modo||'')}
${dom.pago_monto ? ` · $${Number(dom.pago_monto).toLocaleString('es-CO')} cobrado` : ''}
${dom.pago_notas ? ` · <em>${esc(dom.pago_notas)}</em>` : ''}
</div>` : ''}
</div>
</div>
</div>`;
})() : ''}
${dom.notas_admin ? `
<div class="row mt-2">
<div class="col-12">
<label class="form-label small text-muted text-uppercase">Notas internas</label>
<div class="bg-light p-2 rounded small">${esc(dom.notas_admin)}</div>
</div>
</div>` : ''}
`;
}
function cerrarDetalle() {
domSeleccionado = null;
document.querySelectorAll('.dom-row').forEach(r => r.classList.remove('table-active'));
document.getElementById('detail-id').textContent = '';
document.getElementById('btn-editar-dom').classList.add('d-none');
document.getElementById('detail-body').innerHTML = '<div class="text-center py-5 text-muted"><i class="fas fa-arrow-left me-2"></i>Selecciona un domicilio</div>';
}
// ── Asignación rápida ──────────────────────────────────────────────────────
async function mostrarAsignacion(domId) {
const re = await fetch('api/lab/get_enfermeras.php');
const de = await re.json();
const opts = (de.data||[]).map(e => `<option value="${e.id}">${esc(e.nombre_completo)} (${e.domicilios_hoy||0} hoy)</option>`).join('');
if (!confirm('¿Asignar enfermera?')) return;
const sel = prompt(`Selecciona el ID de la enfermera:\n${(de.data||[]).map(e=>`${e.id}: ${e.nombre_completo}`).join('\n')}`);
if (!sel) return;
const rr = await fetch('api/lab/save_asignacion.php', {
method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({ domicilio_id: domId, enfermera_id: parseInt(sel) }),
});
const dd = await rr.json();
mostrarToast(dd.success ? dd.message : (dd.error||'Error'), dd.success?'success':'danger');
if (dd.success) { cargarLista(paginaActual); verDomicilio(domId); }
}
// ── Cambio de estado ───────────────────────────────────────────────────────
async function cambiarEstado(id, estado) {
if (!confirm(`¿Cambiar estado a "${estado}"?`)) return;
const r = await fetch('api/lab/save_domicilio.php', {
method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({ id, solo_estado:true, nuevo_estado:estado }),
});
const d = await r.json();
mostrarToast(d.success ? d.message : (d.error||'Error'), d.success?'success':'danger');
if (d.success) { cargarLista(paginaActual); verDomicilio(id); }
}
// ── Formulario nuevo ───────────────────────────────────────────────────────
function abrirFormulario() {
document.getElementById('form-domicilio').reset();
document.getElementById('dom-id').value = '';
document.getElementById('dom-fecha').value = document.getElementById('filtro-fecha').value || '<?= date('Y-m-d') ?>';
document.getElementById('dom-tipo-cliente').value = 'particular';
toggleSeguro('particular');
document.getElementById('modal-titulo').textContent = 'Nuevo Domicilio';
modal.show();
// Autocompletar paciente desde parámetros URL
<?php if ($pacIdParam): ?>
document.getElementById('dom-paciente-id').value = '<?= $pacIdParam ?>';
document.getElementById('dom-paciente-nombre').value = 'Paciente #<?= $pacIdParam ?>';
<?php endif; ?>
}
// ── Editar domicilio existente ─────────────────────────────────────────────
async function editarDomicilio(id) {
if (!id) return;
const r = await fetch(`api/lab/get_domicilios.php?id=${id}&no_stats=1`);
const d = await r.json();
const dom = d.domicilio;
if (!dom) { mostrarToast('No se pudo cargar el domicilio', 'danger'); return; }
document.getElementById('modal-titulo').textContent = `Editar Domicilio #${dom.id}`;
document.getElementById('dom-id').value = dom.id;
document.getElementById('dom-orden-id').value = dom.orden_id || '';
document.getElementById('dom-paciente-id').value = dom.paciente_id;
document.getElementById('dom-paciente-nombre').value = dom.paciente_nombre || '';
document.getElementById('dom-tipo').value = dom.tipo_servicio || '';
document.getElementById('dom-dir').value = dom.direccion || '';
document.getElementById('dom-ciudad').value = dom.ciudad || '';
document.getElementById('dom-barrio').value = dom.barrio || '';
document.getElementById('dom-indic').value = dom.indicaciones_dir || '';
document.getElementById('dom-fecha').value = dom.fecha_programada || '';
document.getElementById('dom-hora').value = (dom.hora_programada || '').slice(0, 5);
document.getElementById('dom-tipo-cliente').value = dom.tipo_cliente || 'particular';
toggleSeguro(dom.tipo_cliente || 'particular');
document.getElementById('dom-seguro-nombre').value = dom.seguro_nombre || '';
document.getElementById('dom-autorizacion').value = dom.autorizacion || '';
document.getElementById('dom-valor-dom').value = dom.valor_domicilio || '';
document.getElementById('dom-valor-cop').value = dom.valor_copago || '';
document.getElementById('dom-copago-lab').value = dom.copago_laboratorio || '';
document.getElementById('dom-notas').value = dom.notas_admin || '';
modal.show();
}
// Mostrar/ocultar campo seguro según tipo_cliente
function toggleSeguro(val) {
document.getElementById('bloque-seguro').style.display = val === 'seguro' ? '' : 'none';
}
async function guardarDomicilio() {
const form = document.getElementById('form-domicilio');
if (!form.checkValidity()) { form.reportValidity(); return; }
if (!document.getElementById('dom-paciente-id').value) {
alert('Debes seleccionar un paciente'); return;
}
const datos = Object.fromEntries(new FormData(form).entries());
if (!datos.id) delete datos.id;
if (!datos.orden_id) delete datos.orden_id;
const r = await fetch('api/lab/save_domicilio.php', {
method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify(datos),
});
const d = await r.json();
if (d.success) {
modal.hide();
mostrarToast(d.message, 'success');
const editadoId = datos.id ? parseInt(datos.id) : null;
await cargarLista(paginaActual);
if (editadoId) verDomicilio(editadoId);
} else {
mostrarToast(d.error||'Error', 'danger');
}
}
// Autocompletado de paciente
let pacTimer;
document.getElementById('dom-paciente-nombre').addEventListener('input', function() {
clearTimeout(pacTimer);
const v = this.value.trim();
if (v.length < 2) { document.getElementById('pac-suggest').style.display='none'; return; }
pacTimer = setTimeout(async () => {
const r = await fetch(`api/lab/get_pacientes.php?busqueda=${encodeURIComponent(v)}&limit=8`);
const d = await r.json();
const list = document.getElementById('pac-suggest');
if (!d.data?.length) { list.style.display='none'; return; }
list.innerHTML = d.data.map(p =>
`<button type="button" class="list-group-item list-group-item-action small py-1"
onclick="selPaciente(${p.id},'${esc(p.nombre_completo)}')">${esc(p.nombre_completo)} — ${esc(p.numero_documento||p.telefono||'')}</button>`
).join('');
list.style.display = 'block';
}, 300);
});
function selPaciente(id, nombre) {
document.getElementById('dom-paciente-id').value = id;
document.getElementById('dom-paciente-nombre').value= nombre;
document.getElementById('pac-suggest').style.display = 'none';
}
function verHoy() {
document.getElementById('filtro-fecha').value = '<?= date('Y-m-d') ?>';
cargarLista();
}
// ── Utils ──────────────────────────────────────────────────────────────────
const esc = s => String(s||'').replace(/[<>&"]/g, c => ({'<':'&lt;','>':'&gt;','&':'&amp;','"':'&quot;'}[c]));
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`;
div.style.zIndex = 9999;
div.innerHTML = `${esc(msg)}<button type="button" class="btn-close" data-bs-dismiss="alert"></button>`;
document.body.appendChild(div);
setTimeout(() => div.remove(), 4000);
}
</script>
</body>
</html>