up
This commit is contained in:
+939
-1
@@ -907,6 +907,10 @@ if (!isset($_SESSION['user_id'])) {
|
||||
<div class="chat-header-info">
|
||||
<h6 id="chat-name"><span id="chat-name-text">Usuario</span> <button class="btn btn-sm btn-link" id="edit-user-btn" title="Editar usuario"><i class="fas fa-user-edit"></i></button>
|
||||
<span id="hold-indicator" style="display:none; margin-left:8px; color:#b85; font-weight:600">EN ESPERA</span>
|
||||
<span id="terms-pending-badge" title="Este usuario aún no ha aceptado los Términos y Condiciones"
|
||||
style="display:none; margin-left:8px; background:#dc3545; color:#fff; font-size:10px; font-weight:600; padding:2px 7px; border-radius:10px; vertical-align:middle; cursor:default;">
|
||||
<i class="fas fa-file-contract me-1"></i>T&C Pendiente
|
||||
</span>
|
||||
</h6>
|
||||
<small id="chat-phone">+1234567890</small>
|
||||
<div style="font-size:12px; margin-top:4px;">
|
||||
@@ -919,6 +923,18 @@ if (!isset($_SESSION['user_id'])) {
|
||||
<div id="bot-toggle-container" style="display:flex;align-items:center;gap:6px;margin-right:8px;">
|
||||
<button class="btn btn-sm btn-outline-secondary" id="bot-toggle">Bot: On</button>
|
||||
</div>
|
||||
<!-- Botón ver citas del paciente -->
|
||||
<button class="btn btn-sm btn-outline-warning" id="ver-citas-btn" title="Ver citas de este paciente" onclick="citasModal.abrir()">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
</button>
|
||||
<!-- Botón agendar domicilio rápido (sin imagen) -->
|
||||
<button class="btn btn-sm btn-outline-success" id="agendar-rapido-btn" title="Agendar domicilio" onclick="labDomicilio.abrirRapido()">
|
||||
<i class="fas fa-house-medical"></i>
|
||||
</button>
|
||||
<!-- Botón ir a gestión de domicilios (asignar enfermeras) -->
|
||||
<a href="lab_domicilios.php" target="_blank" class="btn btn-sm btn-outline-primary" title="Gestión de domicilios — asignar enfermeras">
|
||||
<i class="fas fa-user-nurse"></i>
|
||||
</a>
|
||||
<!-- Botón solicitar archivo grande -->
|
||||
<button class="btn btn-sm btn-outline-info" id="request-large-file-btn" title="Solicitar archivo grande al cliente">
|
||||
<i class="fas fa-cloud-upload-alt"></i>
|
||||
@@ -1037,7 +1053,7 @@ if (!isset($_SESSION['user_id'])) {
|
||||
console.log('%c═══════════════════════════════════════════', 'color: #25d366; font-weight: bold;');
|
||||
console.log('%c🚀 WHATSAPP BOT v1.4.0 - Desarrollado por U-Site.app', 'background: #25d366; color: white; padding: 10px 20px; font-size: 18px; font-weight: bold; border-radius: 5px;');
|
||||
console.log('%c═══════════════════════════════════════════', 'color: #25d366; font-weight: bold;');
|
||||
window.__APP_VERSION__ = '1.4.0';
|
||||
window.__APP_VERSION__ = '2.0.0';
|
||||
</script>
|
||||
|
||||
<?php
|
||||
@@ -2964,6 +2980,12 @@ if (!isset($_SESSION['user_id'])) {
|
||||
console.warn('holdIndicator element not found in DOM');
|
||||
}
|
||||
|
||||
// Badge T&C pendiente
|
||||
const termsBadge = document.getElementById('terms-pending-badge');
|
||||
if (termsBadge) {
|
||||
termsBadge.style.display = conv.terms_pending ? 'inline' : 'none';
|
||||
}
|
||||
|
||||
if (releaseBtn) {
|
||||
// show button only when conversation is explicitly 'on_hold' (do NOT show during advisor request)
|
||||
releaseBtn.style.display = (conv.on_hold) ? 'inline-block' : 'none';
|
||||
@@ -3980,6 +4002,7 @@ if (!isset($_SESSION['user_id'])) {
|
||||
<div class="message-actions mt-1">
|
||||
<button class="btn btn-sm btn-link" onclick="chat.promptReply('${window.escapeHtml(msg.message_id || msg.id || '')}')" title="Responder"><i class="fas fa-reply"></i></button>
|
||||
<button class="btn btn-sm btn-link" onclick="chat.openReactionPicker(event, '${window.escapeHtml(msg.message_id || msg.id || '')}')" title="Reaccionar"><i class="far fa-grin"></i></button>
|
||||
${(msg.message_type === 'image' && msg.direction !== 'outgoing') ? `<button class="btn btn-sm btn-link text-primary" data-msg-id="${msg.id||0}" data-local-file="${msg.local_file||msg.local_thumb||''}" data-conv-id="${chat ? chat.currentConversationId : 0}" onclick="labDomicilio.abrir(+this.dataset.msgId, this.dataset.localFile, +this.dataset.convId)" title="Agendar domicilio (con imagen)"><i class="fas fa-house-medical"></i></button>` : ''}${window._labAddrBtn ? window._labAddrBtn(msg, chat ? chat.currentConversationId : 0) : ''}
|
||||
</div>
|
||||
<div class="message-time">${time} ${msg.direction === 'outgoing' ? `<span class="message-status">${statusIcon}</span>` : ''}</div>
|
||||
</div>
|
||||
@@ -6395,5 +6418,920 @@ if (!isset($_SESSION['user_id'])) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════════════════
|
||||
MÓDULO LAB — Modal "Agendar Domicilio"
|
||||
════════════════════════════════════════════════════════════════════════ -->
|
||||
<style>
|
||||
#modalAgendarDomicilio .addr-chip {
|
||||
cursor:pointer; border:1px solid #0d6efd; color:#0d6efd;
|
||||
background:#f0f4ff; border-radius:20px; padding:3px 10px;
|
||||
font-size:.78rem; white-space:nowrap; transition:background .15s;
|
||||
}
|
||||
#modalAgendarDomicilio .addr-chip:hover { background:#0d6efd; color:#fff; }
|
||||
#modalAgendarDomicilio .field-err { display:none; font-size:.8rem; color:#dc3545; margin-top:3px; }
|
||||
#modalAgendarDomicilio .is-invalid ~ .field-err,
|
||||
#modalAgendarDomicilio .is-invalid + .field-err { display:block; }
|
||||
</style>
|
||||
|
||||
<div class="modal fade" id="modalAgendarDomicilio" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header bg-primary text-white py-2">
|
||||
<div>
|
||||
<h5 class="modal-title mb-0"><i class="fas fa-house-medical me-2"></i>Agendar Domicilio</h5>
|
||||
<small id="labdom-header-pac" class="opacity-75"></small>
|
||||
</div>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<!-- ── PANEL ÉXITO (se muestra al guardar) ── -->
|
||||
<div id="labdom-ok-panel" class="d-none">
|
||||
<div class="text-center py-4 px-3">
|
||||
<div class="mb-3" style="font-size:3rem">✅</div>
|
||||
<h5 class="fw-bold text-success" id="labdom-ok-msg">Domicilio agendado</h5>
|
||||
<p class="text-muted mb-4" id="labdom-ok-sub"></p>
|
||||
<div class="d-flex justify-content-center gap-2 flex-wrap">
|
||||
<a id="labdom-ok-asignar" href="lab_domicilios.php" target="_blank" class="btn btn-warning">
|
||||
<i class="fas fa-user-nurse me-1"></i>Asignar enfermera
|
||||
</a>
|
||||
<a id="labdom-ok-ver" href="#" target="_blank" class="btn btn-outline-primary">
|
||||
<i class="fas fa-external-link-alt me-1"></i>Ver domicilio
|
||||
</a>
|
||||
<button type="button" class="btn btn-success" onclick="labDomicilio.agendarOtro()">
|
||||
<i class="fas fa-plus me-1"></i>Agendar otro
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── FORMULARIO ── -->
|
||||
<div id="labdom-form-panel" class="modal-body pb-2">
|
||||
|
||||
<!-- Imagen adjunta -->
|
||||
<div id="labdom-img-prev" class="mb-3 d-flex align-items-center gap-3 p-2 bg-light rounded border" style="display:none!important">
|
||||
<img id="labdom-img-el" src="" class="rounded border" style="max-height:80px;max-width:110px;object-fit:cover">
|
||||
<div>
|
||||
<p class="mb-0 fw-semibold small text-secondary">Orden médica adjunta</p>
|
||||
<span class="badge bg-primary-subtle text-primary border border-primary-subtle"><i class="fas fa-image me-1"></i>Foto de la conversación</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── TIPO (particular/seguro) — PRIMERO y llamativo ── -->
|
||||
<div class="mb-3 p-2 rounded border bg-light">
|
||||
<label class="fw-semibold small text-secondary mb-2 d-block">
|
||||
<i class="fas fa-id-card me-1"></i>¿ES PARTICULAR O POR SEGURO?
|
||||
</label>
|
||||
<div class="d-flex gap-2">
|
||||
<input type="radio" class="btn-check" name="labdom-tipo-cliente" id="tc-particular" value="particular" autocomplete="off"
|
||||
onchange="labDomicilio._toggleSeguro()">
|
||||
<label class="btn btn-sm btn-outline-secondary" for="tc-particular">
|
||||
<i class="fas fa-wallet me-1"></i>Particular
|
||||
</label>
|
||||
|
||||
<input type="radio" class="btn-check" name="labdom-tipo-cliente" id="tc-seguro" value="seguro" autocomplete="off"
|
||||
onchange="labDomicilio._toggleSeguro()">
|
||||
<label class="btn btn-sm btn-outline-info" for="tc-seguro">
|
||||
<i class="fas fa-shield-alt me-1"></i>Seguro
|
||||
</label>
|
||||
</div>
|
||||
<!-- Campos seguro (visibles solo cuando se elige Seguro) -->
|
||||
<div id="labdom-seguro-row" class="mt-2 d-none">
|
||||
<div class="mb-2">
|
||||
<label class="form-label small mb-1">¿Qué seguro? <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control form-control-sm" id="labdom-seguro-nombre"
|
||||
placeholder="Ej: Sura, Colsanitas, Compensar, Póliza SOAT…" autocomplete="off">
|
||||
<div class="field-err" id="labdom-seguro-err">Indica el nombre del seguro</div>
|
||||
</div>
|
||||
<div class="row g-2">
|
||||
<div class="col-6">
|
||||
<label class="form-label small mb-1"><i class="fas fa-hashtag me-1 text-muted"></i>N.° de autorización <span class="text-muted">(opcional)</span></label>
|
||||
<input type="text" class="form-control form-control-sm" id="labdom-autorizacion"
|
||||
placeholder="Ej: 12345678" autocomplete="off">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small mb-1"><i class="fas fa-hand-holding-usd me-1 text-muted"></i>Copago asume el laboratorio <span class="text-muted">(opcional)</span></label>
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" min="0" step="1" class="form-control form-control-sm" id="labdom-copago"
|
||||
placeholder="0">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── PACIENTE ── -->
|
||||
<div class="card border-0 bg-light mb-3 p-2">
|
||||
<div class="d-flex align-items-center justify-content-between mb-1">
|
||||
<span class="fw-semibold small text-secondary"><i class="fas fa-user me-1"></i>PACIENTE</span>
|
||||
<button id="labdom-btn-cambiar-pac" class="btn btn-xs btn-link text-primary p-0 small d-none" onclick="labDomicilio.limpiarPaciente()">Cambiar</button>
|
||||
</div>
|
||||
|
||||
<!-- Buscador (visible cuando NO hay paciente seleccionado) -->
|
||||
<div id="labdom-pac-buscar">
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" id="labdom-pac-busq" class="form-control" placeholder="Buscar por nombre o documento…" autocomplete="off">
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="labDomicilio.buscarPaciente()"><i class="fas fa-search"></i></button>
|
||||
</div>
|
||||
<div id="labdom-pac-list" class="list-group mt-1 shadow" style="position:relative;z-index:1060;max-height:165px;overflow-y:auto;display:none"></div>
|
||||
<div class="mt-2">
|
||||
<button id="labdom-btn-contacto" class="btn btn-sm btn-outline-success w-100" type="button" onclick="labDomicilio.usarContacto()">
|
||||
<i class="fab fa-whatsapp me-1"></i> Usar contacto de la conversación
|
||||
</button>
|
||||
<div id="labdom-contacto-spin" class="text-center py-1 d-none">
|
||||
<span class="spinner-border spinner-border-sm text-success"></span>
|
||||
<span class="small text-muted ms-1">Buscando contacto…</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tarjeta paciente seleccionado (visible cuando SÍ hay paciente) -->
|
||||
<div id="labdom-pac-card" class="d-none">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center flex-shrink-0" style="width:36px;height:36px;font-size:1rem">
|
||||
<i class="fas fa-user"></i>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-0 fw-bold" id="labdom-pac-nombre"></p>
|
||||
<small id="labdom-pac-info" class="text-muted"></small>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Datos de contacto del paciente -->
|
||||
<div id="labdom-pac-contacto" class="mt-2 d-none">
|
||||
<div class="row g-1 small">
|
||||
<div class="col-6">
|
||||
<span class="text-muted"><i class="fas fa-phone me-1"></i></span>
|
||||
<span id="labdom-pac-tel" class="fw-semibold">—</span>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<span class="text-muted"><i class="fas fa-envelope me-1"></i></span>
|
||||
<span id="labdom-pac-email" class="fw-semibold">—</span>
|
||||
</div>
|
||||
<div class="col-12" id="labdom-pac-eps-row" style="display:none">
|
||||
<span class="text-muted small"><i class="fas fa-hospital me-1"></i>EPS: </span>
|
||||
<span id="labdom-pac-eps" class="small fw-semibold"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Historial de domicilios previos -->
|
||||
<div id="labdom-hist-cont" class="mt-2 d-none">
|
||||
<p class="mb-1 small text-muted"><i class="fas fa-history me-1"></i>Direcciones usadas anteriormente — toca para reusar:</p>
|
||||
<div id="labdom-hist-chips" class="d-flex flex-wrap gap-1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── FECHA · HORA · TIPO ── -->
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-5">
|
||||
<label class="form-label fw-semibold small mb-1">Fecha <span class="text-danger">*</span></label>
|
||||
<input type="date" class="form-control form-control-sm" id="labdom-fecha">
|
||||
<div class="field-err" id="labdom-fecha-err">Selecciona una fecha</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<label class="form-label small mb-1">Hora</label>
|
||||
<input type="time" class="form-control form-control-sm" id="labdom-hora">
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<label class="form-label small mb-1">Tipo</label>
|
||||
<select class="form-select form-select-sm" id="labdom-tipo">
|
||||
<option value="domicilio">🏠 Domicilio</option>
|
||||
<option value="urgencia">🚨 Urgencia</option>
|
||||
<option value="control">🔬 Control</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── DIRECCIÓN ── -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold small mb-1">Dirección <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control form-control-sm" id="labdom-direccion" placeholder="Ej: Cra 15 # 32-10">
|
||||
<div class="field-err" id="labdom-dir-err">Ingresa la dirección</div>
|
||||
|
||||
<div class="row g-2 mt-1">
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control form-control-sm" id="labdom-barrio" placeholder="Barrio">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control form-control-sm" id="labdom-ciudad" placeholder="Ciudad">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<input type="text" class="form-control form-control-sm" id="labdom-indicaciones" placeholder="Indicaciones: piso, apto, portero, referencias…">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── EXÁMENES SOLICITADOS ── -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold small mb-1">
|
||||
<i class="fas fa-flask me-1 text-primary"></i>Exámenes solicitados
|
||||
<span class="badge bg-secondary ms-1" style="font-size:.65rem">si no hay foto de orden</span>
|
||||
</label>
|
||||
<textarea class="form-control form-control-sm" id="labdom-examenes" rows="2"
|
||||
placeholder="Ej: Hemograma completo, glucosa en ayunas, parcial de orina…"></textarea>
|
||||
<div class="form-text text-muted" style="font-size:.73rem">
|
||||
<i class="fas fa-info-circle me-1"></i>Si el cliente envió foto de la orden, este campo es opcional.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── INFORMACIÓN DE COBRO ── -->
|
||||
<div class="mb-3 p-2 rounded border bg-light">
|
||||
<label class="fw-semibold small text-secondary mb-2 d-block">
|
||||
<i class="fas fa-file-invoice-dollar me-1"></i>Información de cobro <span class="fw-normal text-muted">(opcional)</span>
|
||||
</label>
|
||||
<div class="row g-2">
|
||||
<div class="col-6">
|
||||
<label class="form-label small mb-1">Valor del domicilio</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" min="0" step="1" class="form-control form-control-sm" id="labdom-valor-domicilio"
|
||||
placeholder="0" oninput="labDomicilio._calcTotal()">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small mb-1">Valor del copago</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" min="0" step="1" class="form-control form-control-sm" id="labdom-valor-copago"
|
||||
placeholder="0" oninput="labDomicilio._calcTotal()">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Total a cobrar al cliente -->
|
||||
<div class="col-12" id="labdom-total-row" style="display:none">
|
||||
<div class="d-flex align-items-center justify-content-between rounded px-3 py-2 mt-1"
|
||||
style="background:#d1fae5;border:1px solid #6ee7b7">
|
||||
<span class="fw-semibold small text-success">
|
||||
<i class="fas fa-cash-register me-1"></i>Total a cobrar al cliente
|
||||
</span>
|
||||
<span class="fw-bold text-success" id="labdom-total-valor" style="font-size:1rem">$0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── NOTAS ADMIN ── -->
|
||||
<div class="mb-2">
|
||||
<label class="form-label small mb-1"><i class="fas fa-sticky-note me-1"></i>Notas internas del agendamiento</label>
|
||||
<textarea class="form-control form-control-sm" id="labdom-notas" rows="2"
|
||||
placeholder="Indicaciones especiales, observaciones del operador…"></textarea>
|
||||
</div>
|
||||
|
||||
</div><!-- /form-panel -->
|
||||
|
||||
<div id="labdom-footer" class="modal-footer py-2">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancelar</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="labdom-btn-guardar" onclick="labDomicilio.guardar()">
|
||||
<i class="fas fa-calendar-check me-1"></i> Agendar Domicilio
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// Módulo Lab — Agendar Domicilio desde conversations.php
|
||||
// Soporta múltiples domicilios al mismo paciente en la misma sesión.
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
const labDomicilio = (() => {
|
||||
// Estado interno
|
||||
let _msgId = null;
|
||||
let _localFile = null;
|
||||
let _convId = null;
|
||||
let _pacienteId = null;
|
||||
let _pacNombre = '';
|
||||
let _histDirs = []; // direcciones únicas previas del paciente
|
||||
let _bsModal = null;
|
||||
|
||||
// ── helpers DOM ──────────────────────────────────────────────────────────
|
||||
const $ = id => document.getElementById(id);
|
||||
const fv = id => $( id).value.trim();
|
||||
|
||||
function fechaManana() {
|
||||
const d = new Date();
|
||||
d.setDate(d.getDate() + 1);
|
||||
return d.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
function mostrarFormulario() {
|
||||
$('labdom-ok-panel').classList.add('d-none');
|
||||
$('labdom-form-panel').style.display = '';
|
||||
$('labdom-footer').style.display = '';
|
||||
}
|
||||
|
||||
function limpiarValidacion() {
|
||||
['labdom-fecha','labdom-direccion'].forEach(id => $(id).classList.remove('is-invalid'));
|
||||
}
|
||||
|
||||
function validar() {
|
||||
let ok = true;
|
||||
limpiarValidacion();
|
||||
if (!fv('labdom-fecha')) { $('labdom-fecha').classList.add('is-invalid'); ok = false; }
|
||||
if (!fv('labdom-direccion')){ $('labdom-direccion').classList.add('is-invalid'); ok = false; }
|
||||
const esSeguro = document.getElementById('tc-seguro')?.checked;
|
||||
if (esSeguro && !fv('labdom-seguro-nombre')) {
|
||||
$('labdom-seguro-nombre').classList.add('is-invalid');
|
||||
ok = false;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
// ── cargar historial de direcciones del paciente ─────────────────────────
|
||||
async function cargarHistorial(pacienteId) {
|
||||
$('labdom-hist-cont').classList.add('d-none');
|
||||
$('labdom-hist-chips').innerHTML = '';
|
||||
_histDirs = [];
|
||||
try {
|
||||
const r = await fetch(`api/lab/get_domicilios.php?paciente_id=${pacienteId}&limit=30&no_stats=1`);
|
||||
const d = await r.json();
|
||||
if (!d.data?.length) return;
|
||||
|
||||
// Deduplicar por dirección+barrio, mantener las más recientes primero
|
||||
const vistas = new Set();
|
||||
const dirs = [];
|
||||
for (const dom of d.data) {
|
||||
const key = (dom.direccion||'').toLowerCase().trim();
|
||||
if (!key || vistas.has(key)) continue;
|
||||
vistas.add(key);
|
||||
dirs.push({
|
||||
direccion: dom.direccion || '',
|
||||
barrio: dom.barrio || '',
|
||||
ciudad: dom.ciudad || '',
|
||||
indicaciones_dir: dom.indicaciones_dir || '',
|
||||
});
|
||||
if (dirs.length >= 4) break; // máximo 4 chips
|
||||
}
|
||||
if (!dirs.length) return;
|
||||
|
||||
_histDirs = dirs;
|
||||
const chips = $('labdom-hist-chips');
|
||||
dirs.forEach((dir, i) => {
|
||||
const label = dir.barrio ? `${dir.direccion} (${dir.barrio})` : dir.direccion;
|
||||
const btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
btn.className = 'addr-chip';
|
||||
btn.title = [dir.direccion, dir.barrio, dir.ciudad].filter(Boolean).join(' · ');
|
||||
btn.innerHTML = `<i class="fas fa-map-marker-alt me-1"></i>${escLab(label)}`;
|
||||
btn.onclick = () => labDomicilio.usarDireccion(i);
|
||||
chips.appendChild(btn);
|
||||
});
|
||||
$('labdom-hist-cont').classList.remove('d-none');
|
||||
} catch (_) { /* silencioso */ }
|
||||
}
|
||||
|
||||
// ── API pública ──────────────────────────────────────────────────────────
|
||||
return {
|
||||
|
||||
/* Abre el modal desde el botón del mensaje imagen */
|
||||
abrir(msgId, localFile, convId) {
|
||||
_msgId = msgId || null;
|
||||
_localFile = localFile|| null;
|
||||
_convId = convId ? parseInt(convId) : null;
|
||||
// Guardar también el userId actual para usarContacto cuando convId no esté disponible
|
||||
if (!_convId && typeof chatApp !== 'undefined' && chatApp.currentUserId) {
|
||||
_convId = '__user:' + chatApp.currentUserId;
|
||||
}
|
||||
|
||||
mostrarFormulario();
|
||||
labDomicilio._resetFull();
|
||||
|
||||
if (_localFile) {
|
||||
$('labdom-img-el').src = `uploads/media/${_localFile}`;
|
||||
$('labdom-img-prev').style.cssText = ''; // quita display:none!important
|
||||
} else {
|
||||
$('labdom-img-prev').style.display = 'none';
|
||||
}
|
||||
|
||||
if (!_bsModal) _bsModal = new bootstrap.Modal('#modalAgendarDomicilio');
|
||||
_bsModal.show();
|
||||
|
||||
// Pre-cargar contacto de la conversación de forma silenciosa
|
||||
if (_convId) labDomicilio.usarContacto();
|
||||
},
|
||||
|
||||
/* Reset completo (nombre paciente + todos los campos) */
|
||||
_resetFull() {
|
||||
_pacienteId = null;
|
||||
_pacNombre = '';
|
||||
_histDirs = [];
|
||||
$('labdom-pac-busq').value = '';
|
||||
$('labdom-pac-list').style.display = 'none';
|
||||
$('labdom-pac-buscar').classList.remove('d-none');
|
||||
$('labdom-pac-card').classList.add('d-none');
|
||||
$('labdom-btn-cambiar-pac').classList.add('d-none');
|
||||
$('labdom-pac-contacto').classList.add('d-none');
|
||||
$('labdom-hist-cont').classList.add('d-none');
|
||||
$('labdom-hist-chips').innerHTML = '';
|
||||
$('labdom-header-pac').textContent = '';
|
||||
// Resetear tipo cliente a "particular" por defecto
|
||||
const tc = document.getElementById('tc-particular');
|
||||
if (tc) tc.checked = true;
|
||||
labDomicilio._toggleSeguro();
|
||||
labDomicilio._resetDomicilio();
|
||||
},
|
||||
|
||||
/* Muestra/oculta el campo «nombre del seguro» según la selección */
|
||||
_toggleSeguro() {
|
||||
const esSeguro = document.getElementById('tc-seguro')?.checked;
|
||||
const row = $('labdom-seguro-row');
|
||||
if (!row) return;
|
||||
if (esSeguro) {
|
||||
row.classList.remove('d-none');
|
||||
} else {
|
||||
row.classList.add('d-none');
|
||||
if ($('labdom-seguro-nombre')) $('labdom-seguro-nombre').value = '';
|
||||
}
|
||||
},
|
||||
|
||||
/* Calcula y muestra el total a cobrar al cliente */
|
||||
_calcTotal() {
|
||||
const dom = parseFloat($('labdom-valor-domicilio')?.value) || 0;
|
||||
const copago = parseFloat($('labdom-valor-copago')?.value) || 0;
|
||||
const total = dom + copago;
|
||||
const row = $('labdom-total-row');
|
||||
const label = $('labdom-total-valor');
|
||||
if (!row || !label) return;
|
||||
if (total > 0) {
|
||||
label.textContent = '$' + total.toLocaleString('es-CO');
|
||||
row.style.display = '';
|
||||
} else {
|
||||
row.style.display = 'none';
|
||||
}
|
||||
},
|
||||
|
||||
/* Reset solo los campos del domicilio (mantiene paciente) */
|
||||
_resetDomicilio() {
|
||||
$('labdom-fecha').value = fechaManana();
|
||||
$('labdom-hora').value = '07:00';
|
||||
$('labdom-tipo').value = 'domicilio';
|
||||
$('labdom-direccion').value = '';
|
||||
$('labdom-barrio').value = '';
|
||||
$('labdom-ciudad').value = '';
|
||||
$('labdom-indicaciones').value= '';
|
||||
$('labdom-examenes').value = '';
|
||||
$('labdom-notas').value = '';
|
||||
if ($('labdom-seguro-nombre')) $('labdom-seguro-nombre').value = '';
|
||||
if ($('labdom-autorizacion')) $('labdom-autorizacion').value = '';
|
||||
if ($('labdom-copago')) $('labdom-copago').value = '';
|
||||
if ($('labdom-valor-domicilio')) $('labdom-valor-domicilio').value = '';
|
||||
if ($('labdom-valor-copago')) $('labdom-valor-copago').value = '';
|
||||
labDomicilio._calcTotal();
|
||||
limpiarValidacion();
|
||||
},
|
||||
|
||||
/* ── Buscar paciente ── */
|
||||
async buscarPaciente() {
|
||||
const q = fv('labdom-pac-busq');
|
||||
if (!q) return;
|
||||
const r = await fetch(`api/lab/get_pacientes.php?busqueda=${encodeURIComponent(q)}&limit=8`);
|
||||
const d = await r.json();
|
||||
const list = $('labdom-pac-list');
|
||||
if (!d.data?.length) {
|
||||
list.innerHTML = '<a class="list-group-item list-group-item-action text-muted disabled small py-2">Sin resultados</a>';
|
||||
list.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
list.innerHTML = d.data.map(p =>
|
||||
`<button type="button" class="list-group-item list-group-item-action py-2"
|
||||
data-pid="${p.id}"
|
||||
data-nombre="${escAtr(p.nombre_completo)}"
|
||||
data-dir="${escAtr(p.direccion||'')}"
|
||||
data-ciudad="${escAtr(p.ciudad||'')}"
|
||||
data-info="${escAtr((p.tipo_documento||'') + ' ' + (p.numero_documento||''))}"
|
||||
data-tel="${escAtr(p.telefono||'')}"
|
||||
data-email="${escAtr(p.email||'')}"
|
||||
data-eps="${escAtr(p.eps||'')}"
|
||||
onclick="labDomicilio._clickPaciente(this)">
|
||||
<strong class="small">${escLab(p.nombre_completo)}</strong>
|
||||
<span class="text-muted ms-2 small">${escLab(p.tipo_documento||'')} ${escLab(p.numero_documento||'')}</span>
|
||||
${p.telefono ? `<span class="ms-2 small text-success"><i class="fas fa-phone me-1"></i>${escLab(p.telefono)}</span>` : ''}
|
||||
${p.direccion ? `<br><small class="text-primary"><i class="fas fa-map-marker-alt me-1"></i>${escLab(p.direccion)}</small>` : ''}
|
||||
</button>`
|
||||
).join('');
|
||||
list.style.display = 'block';
|
||||
},
|
||||
|
||||
_clickPaciente(btn) {
|
||||
labDomicilio.selPaciente(
|
||||
+btn.dataset.pid,
|
||||
btn.dataset.nombre,
|
||||
btn.dataset.dir,
|
||||
btn.dataset.ciudad,
|
||||
btn.dataset.info,
|
||||
btn.dataset.tel || '',
|
||||
btn.dataset.email || '',
|
||||
btn.dataset.eps || ''
|
||||
);
|
||||
},
|
||||
|
||||
selPaciente(id, nombre, direccion, ciudad, info, tel = '', email = '', eps = '') {
|
||||
_pacienteId = id;
|
||||
_pacNombre = nombre;
|
||||
|
||||
// Ocultar buscador, mostrar tarjeta
|
||||
$('labdom-pac-list').style.display = 'none';
|
||||
$('labdom-pac-buscar').classList.add('d-none');
|
||||
$('labdom-pac-card').classList.remove('d-none');
|
||||
$('labdom-btn-cambiar-pac').classList.remove('d-none');
|
||||
$('labdom-pac-nombre').textContent = nombre;
|
||||
$('labdom-pac-info').textContent = info || '';
|
||||
$('labdom-header-pac').textContent = nombre;
|
||||
|
||||
// Mostrar datos de contacto
|
||||
if (tel || email) {
|
||||
$('labdom-pac-tel').textContent = tel || '—';
|
||||
$('labdom-pac-email').textContent = email || '—';
|
||||
if (eps) {
|
||||
$('labdom-pac-eps').textContent = eps;
|
||||
$('labdom-pac-eps-row').style.display = '';
|
||||
} else {
|
||||
$('labdom-pac-eps-row').style.display = 'none';
|
||||
}
|
||||
$('labdom-pac-contacto').classList.remove('d-none');
|
||||
} else {
|
||||
$('labdom-pac-contacto').classList.add('d-none');
|
||||
}
|
||||
|
||||
// Pre-llenar campos solo si están vacíos
|
||||
if (direccion && !fv('labdom-direccion')) $('labdom-direccion').value = direccion;
|
||||
if (ciudad && !fv('labdom-ciudad')) $('labdom-ciudad').value = ciudad;
|
||||
|
||||
// Cargar historial de domicilios previos
|
||||
cargarHistorial(id);
|
||||
},
|
||||
|
||||
limpiarPaciente() {
|
||||
_pacienteId = null;
|
||||
_pacNombre = '';
|
||||
$('labdom-pac-buscar').classList.remove('d-none');
|
||||
$('labdom-pac-card').classList.add('d-none');
|
||||
$('labdom-btn-cambiar-pac').classList.add('d-none');
|
||||
$('labdom-pac-busq').value = '';
|
||||
$('labdom-pac-contacto').classList.add('d-none');
|
||||
$('labdom-hist-cont').classList.add('d-none');
|
||||
$('labdom-header-pac').textContent = '';
|
||||
// Mantener dirección/notas para no perder lo escrito
|
||||
},
|
||||
|
||||
/* Aplica una dirección histórica al formulario */
|
||||
usarDireccion(idx) {
|
||||
const dir = _histDirs[idx];
|
||||
if (!dir) return;
|
||||
$('labdom-direccion').value = dir.direccion;
|
||||
$('labdom-barrio').value = dir.barrio;
|
||||
$('labdom-ciudad').value = dir.ciudad;
|
||||
$('labdom-indicaciones').value = dir.indicaciones_dir;
|
||||
limpiarValidacion();
|
||||
// Resaltar brevemente el campo
|
||||
$('labdom-direccion').classList.add('border-primary');
|
||||
setTimeout(() => $('labdom-direccion').classList.remove('border-primary'), 1200);
|
||||
},
|
||||
|
||||
/* Contacto de WhatsApp → paciente automático */
|
||||
async usarContacto() {
|
||||
// Obtener convId o userId del contexto actual
|
||||
let effectiveConvId = _convId;
|
||||
if (!effectiveConvId && typeof chatApp !== 'undefined' && chatApp.currentUserId) {
|
||||
effectiveConvId = '__user:' + chatApp.currentUserId;
|
||||
}
|
||||
if (!effectiveConvId) return;
|
||||
|
||||
const spin = $('labdom-contacto-spin');
|
||||
const btn = $('labdom-btn-contacto');
|
||||
try {
|
||||
spin.classList.remove('d-none');
|
||||
btn.classList.add('d-none');
|
||||
// Determinar si es user_id o conversation_id
|
||||
let qparam;
|
||||
if (String(effectiveConvId).startsWith('__user:')) {
|
||||
qparam = `user_id=${String(effectiveConvId).slice(7)}`;
|
||||
} else {
|
||||
qparam = `conversation_id=${effectiveConvId}`;
|
||||
}
|
||||
const r = await fetch(`api/lab/crear_desde_whatsapp.php?solo_paciente=1&${qparam}`);
|
||||
const d = await r.json();
|
||||
if (d.success && d.paciente) {
|
||||
labDomicilio.selPaciente(
|
||||
d.paciente.id,
|
||||
d.paciente.nombre_completo,
|
||||
d.paciente.direccion || '',
|
||||
d.paciente.ciudad || '',
|
||||
[(d.paciente.tipo_documento||''), (d.paciente.numero_documento||'')].filter(Boolean).join(' '),
|
||||
d.paciente.telefono || '',
|
||||
d.paciente.email || '',
|
||||
d.paciente.eps || ''
|
||||
);
|
||||
return;
|
||||
}
|
||||
} catch (_) { /* silencioso */ } finally {
|
||||
spin.classList.add('d-none');
|
||||
if (!_pacienteId) btn.classList.remove('d-none');
|
||||
}
|
||||
},
|
||||
|
||||
/* ── Guardar domicilio ── */
|
||||
async guardar() {
|
||||
if (!_pacienteId) {
|
||||
$('labdom-pac-busq').focus();
|
||||
$('labdom-pac-busq').classList.add('is-invalid');
|
||||
setTimeout(() => $('labdom-pac-busq').classList.remove('is-invalid'), 2000);
|
||||
return;
|
||||
}
|
||||
if (!validar()) return;
|
||||
|
||||
const btn = $('labdom-btn-guardar');
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Guardando…';
|
||||
|
||||
const datos = {
|
||||
paciente_id: _pacienteId,
|
||||
fecha_programada: fv('labdom-fecha'),
|
||||
hora_programada: fv('labdom-hora') || null,
|
||||
tipo_servicio: fv('labdom-tipo'),
|
||||
tipo_cliente: (document.querySelector('input[name="labdom-tipo-cliente"]:checked')?.value) || 'particular',
|
||||
seguro_nombre: (document.querySelector('input[name="labdom-tipo-cliente"]:checked')?.value === 'seguro') ? (fv('labdom-seguro-nombre') || null) : null,
|
||||
autorizacion: (document.querySelector('input[name="labdom-tipo-cliente"]:checked')?.value === 'seguro') ? (fv('labdom-autorizacion') || null) : null,
|
||||
copago_laboratorio: (document.querySelector('input[name="labdom-tipo-cliente"]:checked')?.value === 'seguro') ? ($('labdom-copago').value || null) : null,
|
||||
valor_domicilio: $('labdom-valor-domicilio').value || null,
|
||||
valor_copago: $('labdom-valor-copago').value || null,
|
||||
examenes_solicitados: fv('labdom-examenes') || null,
|
||||
direccion: fv('labdom-direccion'),
|
||||
barrio: fv('labdom-barrio') || null,
|
||||
ciudad: fv('labdom-ciudad') || null,
|
||||
indicaciones_dir: fv('labdom-indicaciones') || null,
|
||||
notas_admin: fv('labdom-notas') || null,
|
||||
};
|
||||
|
||||
try {
|
||||
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) {
|
||||
// Mostrar panel de éxito DENTRO del modal (no cierra)
|
||||
$('labdom-form-panel').style.display = 'none';
|
||||
$('labdom-footer').style.display = 'none';
|
||||
const horaStr = datos.hora_programada ? ` a las ${datos.hora_programada}` : '';
|
||||
$('labdom-ok-msg').textContent = `✅ Domicilio #${d.id} agendado`;
|
||||
const tipoLabel = { particular:'👤 Particular', seguro:'🛡️ Seguro' };
|
||||
if (datos.tipo_cliente === 'seguro' && datos.seguro_nombre) tipoLabel.seguro = `🛡️ Seguro — ${datos.seguro_nombre}`;
|
||||
const examStr = datos.examenes_solicitados ? `<br><small class="text-muted">${escLab(datos.examenes_solicitados)}</small>` : '';
|
||||
$('labdom-ok-sub').innerHTML =
|
||||
`<strong>${escLab(_pacNombre)}</strong> · <span class="badge bg-secondary">${tipoLabel[datos.tipo_cliente]||datos.tipo_cliente}</span><br>${escLab(datos.direccion)}${examStr}<br><span class="badge bg-primary">${datos.fecha_programada}${horaStr}</span>`;
|
||||
$('labdom-ok-ver').href = `lab_domicilios.php?id=${d.id}`;
|
||||
$('labdom-ok-asignar').href = `lab_domicilios.php?id=${d.id}`;
|
||||
$('labdom-ok-panel').classList.remove('d-none');
|
||||
|
||||
// Actualizar historial (puede haber nueva dirección)
|
||||
if (_pacienteId) cargarHistorial(_pacienteId);
|
||||
} else {
|
||||
// Error inline
|
||||
const errDiv = document.createElement('div');
|
||||
errDiv.className = 'alert alert-danger alert-dismissible mt-2 py-2';
|
||||
errDiv.innerHTML = `<i class="fas fa-exclamation-circle me-1"></i>${escLab(d.error||'Error al guardar')}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>`;
|
||||
$('labdom-form-panel').prepend(errDiv);
|
||||
}
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '<i class="fas fa-calendar-check me-1"></i> Agendar Domicilio';
|
||||
}
|
||||
},
|
||||
|
||||
/* "Agendar otro" → mantiene paciente, resetea solo el domicilio */
|
||||
agendarOtro() {
|
||||
mostrarFormulario();
|
||||
labDomicilio._resetDomicilio();
|
||||
// Si hay historial, enfocar notas (la dirección ya tiene chips para elegir)
|
||||
if (_histDirs.length) {
|
||||
$('labdom-notas').focus();
|
||||
} else {
|
||||
$('labdom-direccion').focus();
|
||||
}
|
||||
},
|
||||
|
||||
/* Cierra el modal de citas si está visible y llama cb() al terminar */
|
||||
_cerrarCitas(cb) {
|
||||
const elC = document.getElementById('modalCitasPaciente');
|
||||
if (elC && elC.classList.contains('show')) {
|
||||
const inst = bootstrap.Modal.getInstance(elC);
|
||||
if (inst) {
|
||||
elC.addEventListener('hidden.bs.modal', cb, { once: true });
|
||||
inst.hide();
|
||||
return;
|
||||
}
|
||||
}
|
||||
cb();
|
||||
},
|
||||
|
||||
/* Abrir modal sin imagen (botón header o "nueva cita" desde citasModal) */
|
||||
abrirRapido() {
|
||||
// currentConversationId no siempre está disponible; usamos currentUserId como fallback
|
||||
const convId = (typeof chatApp !== 'undefined' && chatApp.currentConversationId)
|
||||
? chatApp.currentConversationId : 0;
|
||||
this._cerrarCitas(() => labDomicilio.abrir(0, '', convId));
|
||||
},
|
||||
|
||||
/* Abrir modal y pre-rellenar dirección detectada en un mensaje */
|
||||
abrirConTexto(convId, address) {
|
||||
this._cerrarCitas(() => {
|
||||
labDomicilio.abrir(0, '', convId);
|
||||
setTimeout(() => {
|
||||
const inp = document.getElementById('labdom-direccion');
|
||||
if (inp && address) { inp.value = address; inp.dispatchEvent(new Event('input')); }
|
||||
}, 140);
|
||||
});
|
||||
},
|
||||
|
||||
/* Usar una dirección del historial de citas (desde citasModal) */
|
||||
_usarDirHistorial(dir) {
|
||||
this._cerrarCitas(() => {
|
||||
const inp = document.getElementById('labdom-direccion');
|
||||
if (inp) { inp.value = dir; inp.dispatchEvent(new Event('input')); }
|
||||
const el = document.getElementById('modalAgendarDomicilio');
|
||||
if (el) bootstrap.Modal.getOrCreateInstance(el).show();
|
||||
});
|
||||
},
|
||||
|
||||
/* Devuelve el ID del paciente actualmente seleccionado */
|
||||
getPacienteId() { return _pacienteId || 0; },
|
||||
getPacienteNombre() {
|
||||
const el = document.getElementById('labdom-pac-nombre');
|
||||
return el ? el.textContent.trim() : '';
|
||||
},
|
||||
|
||||
};
|
||||
})();
|
||||
|
||||
// Enter en el buscador de paciente
|
||||
document.addEventListener('keydown', e => {
|
||||
if (e.target.id === 'labdom-pac-busq' && e.key === 'Enter') labDomicilio.buscarPaciente();
|
||||
});
|
||||
// Cerrar dropdown de paciente al hacer clic afuera
|
||||
document.addEventListener('click', e => {
|
||||
const list = document.getElementById('labdom-pac-list');
|
||||
if (list && !list.contains(e.target) && e.target.id !== 'labdom-pac-busq') {
|
||||
list.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
const escLab = s => String(s||'').replace(/[<>&"'`]/g, c =>({'<':'<','>':'>','&':'&','"':'"',"'":''','`':'`'}[c]));
|
||||
const escAtr = s => String(s||'').replace(/"/g, '"');
|
||||
|
||||
/* ─── Detección de direcciones colombianas en mensajes ─── */
|
||||
window._detectAddr = function(text) {
|
||||
if (!text) return null;
|
||||
const re = /(calle|cl\.?|carrera|cra\.?|kr\.?|avenida|av\.?|diagonal|dg\.?|transversal|tv\.?|manzana|mz\.?)\s*[\d\w#\-\.]+[\s,][\s\d\w#\-\.°barrioaptolocalnorte sur este oeste]{4,60}/gi;
|
||||
const m = String(text).match(re);
|
||||
return (m && m.length) ? m[0].trim() : null;
|
||||
};
|
||||
|
||||
window._labAddrBtn = function(msg, convId) {
|
||||
if (msg.direction === 'outgoing') return '';
|
||||
const addr = window._detectAddr(msg.body || msg.message || '');
|
||||
if (!addr) return '';
|
||||
const safeAddr = addr.replace(/'/g, "\\'").replace(/"/g, '"');
|
||||
return `<button class="btn btn-sm btn-link text-success" title="Agendar domicilio en esta dirección"
|
||||
onclick="labDomicilio.abrirConTexto(${convId}, '${safeAddr}')"
|
||||
><i class="fas fa-map-marker-alt"></i> Agendar</button>`;
|
||||
};
|
||||
|
||||
/* ─── Modal "Ver citas del paciente" ─── */
|
||||
const citasModal = (() => {
|
||||
let _pacId = 0;
|
||||
|
||||
function abrir() {
|
||||
/* Obtener paciente del contexto actual de la conversación */
|
||||
const convId = (typeof chatApp !== 'undefined' && chatApp.currentConversationId)
|
||||
? chatApp.currentConversationId : 0;
|
||||
|
||||
const el = document.getElementById('modalCitasPaciente');
|
||||
if (!el) return;
|
||||
const bsM = bootstrap.Modal.getOrCreateInstance(el);
|
||||
bsM.show();
|
||||
|
||||
/* Usar el paciente activo en labDomicilio si existe */
|
||||
_pacId = (typeof labDomicilio !== 'undefined' && labDomicilio.getPacienteId)
|
||||
? labDomicilio.getPacienteId() : 0;
|
||||
if (_pacId) {
|
||||
const nom = labDomicilio.getPacienteNombre ? labDomicilio.getPacienteNombre() : '';
|
||||
const h = document.getElementById('citas-pac-nombre');
|
||||
if (h && nom) h.textContent = nom;
|
||||
cargar(_pacId);
|
||||
} else {
|
||||
/* Si no hay paciente seleccionado, obtenerlo desde la conversación o usuario activo */
|
||||
const userId = typeof chatApp !== 'undefined' ? (chatApp.currentUserId || 0) : 0;
|
||||
const qparam = convId ? `conversation_id=${convId}` : (userId ? `user_id=${userId}` : '');
|
||||
if (!qparam) { mostrarVacio('Abre una conversación primero.'); return; }
|
||||
fetch(`api/lab/crear_desde_whatsapp.php?solo_paciente=1&${qparam}`)
|
||||
.then(r => r.json())
|
||||
.then(d => {
|
||||
if (d.success && d.paciente && d.paciente.id) {
|
||||
_pacId = d.paciente.id;
|
||||
document.getElementById('citas-pac-nombre').textContent = d.paciente.nombre_completo || '';
|
||||
cargar(_pacId);
|
||||
} else {
|
||||
mostrarVacio('No se encontró paciente asociado a esta conversación.');
|
||||
}
|
||||
})
|
||||
.catch(() => mostrarVacio('Error al obtener datos del paciente.'));
|
||||
}
|
||||
}
|
||||
|
||||
function cargar(pacId) {
|
||||
const tbody = document.getElementById('citas-tbody');
|
||||
const header = document.getElementById('citas-pac-nombre');
|
||||
if (!tbody) return;
|
||||
tbody.innerHTML = `<tr><td colspan="5" class="text-center py-3"><div class="spinner-border spinner-border-sm text-primary" role="status"></div> Cargando…</td></tr>`;
|
||||
|
||||
fetch(`api/lab/get_domicilios.php?paciente_id=${pacId}&limit=20`)
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
const rows = (data.data || data.domicilios || data || []);
|
||||
if (!rows.length) { mostrarVacio('Este paciente no tiene citas registradas.'); return; }
|
||||
if (rows[0] && rows[0].paciente_nombre && header) header.textContent = rows[0].paciente_nombre;
|
||||
tbody.innerHTML = rows.map(c => {
|
||||
const estado = c.estado || 'pendiente';
|
||||
const colorMap = {pendiente:'warning',confirmado:'info',en_camino:'primary',completado:'success',cancelado:'danger'};
|
||||
const badge = `<span class="badge bg-${colorMap[estado]||'secondary'}">${estado}</span>`;
|
||||
const tipo = c.tipo_cliente ? `<span class="badge bg-light text-dark border">${c.tipo_cliente}</span>` : '';
|
||||
const dir = escLab(c.direccion || '');
|
||||
const fecha = c.fecha_programada ? c.fecha_programada.substring(0,16).replace('T',' ') : (c.fecha || '—');
|
||||
return `<tr>
|
||||
<td class="text-nowrap small">${escLab(fecha)}</td>
|
||||
<td class="small">${dir}</td>
|
||||
<td>${badge}</td>
|
||||
<td>${tipo}</td>
|
||||
<td class="text-nowrap">
|
||||
<button class="btn btn-xs btn-outline-success py-0 px-2 small" title="Agendar con esta dirección"
|
||||
onclick="labDomicilio._usarDirHistorial('${dir.replace(/'/g,"\\'")}')">
|
||||
<i class="fas fa-location-arrow me-1"></i>Usar
|
||||
</button>
|
||||
</td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
})
|
||||
.catch(() => mostrarVacio('Error al cargar las citas.'));
|
||||
}
|
||||
|
||||
function recargar() { if (_pacId) cargar(_pacId); }
|
||||
|
||||
function mostrarVacio(msg) {
|
||||
const tbody = document.getElementById('citas-tbody');
|
||||
if (tbody) tbody.innerHTML = `<tr><td colspan="5" class="text-center text-muted py-3">${escLab(msg)}</td></tr>`;
|
||||
}
|
||||
|
||||
return { abrir, recargar };
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- Modal: Citas del paciente -->
|
||||
<div class="modal fade" id="modalCitasPaciente" tabindex="-1" aria-labelledby="modalCitasPacienteTitulo" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-warning bg-opacity-10">
|
||||
<h5 class="modal-title" id="modalCitasPacienteTitulo">
|
||||
<i class="fas fa-calendar-alt me-2 text-warning"></i>
|
||||
Citas — <span id="citas-pac-nombre" class="text-primary">paciente</span>
|
||||
</h5>
|
||||
<div class="ms-auto d-flex gap-2 me-2">
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="citasModal.recargar()" title="Recargar">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-success" onclick="labDomicilio.abrirRapido()" title="Nueva cita">
|
||||
<i class="fas fa-plus"></i> Nueva
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
|
||||
</div>
|
||||
<div class="modal-body p-0">
|
||||
<table class="table table-sm table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Fecha / Hora</th>
|
||||
<th>Dirección</th>
|
||||
<th>Estado</th>
|
||||
<th>Tipo</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="citas-tbody">
|
||||
<tr><td colspan="5" class="text-center text-muted py-4">–</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user