Turnero: mejoras UI, historial detallado, kiosko scanner, firma por turno
- Kiosko: detector scanner (gap < 80ms), iconos 90px, fa-person-pregnant, ticket Arial - Recepción: vincular_paciente.php para persistir paciente_id antes de firmar consentimiento - Historial y dashboard: recepción desk, empleado recepción/muestras, exámenes y comentarios - display_global: turno más pequeño, lugar-nombre más grande - lab_pacientes: modal compacta con form-sm - Configuración: icono embarazada fa-person-pregnant en prioridades - ver_formulario_enviado: firma por campo (fix doble firma) - docker-compose.local.yml: override BD producción para dev local Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
ebbf4ac6cf
commit
f363631b32
@@ -0,0 +1,5 @@
|
|||||||
|
# Override local: usa BD de producción directamente, sin mysql local
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
environment:
|
||||||
|
- DB_HOST=${DB_HOST} # toma el host real del .env (46.202.93.92)
|
||||||
+63
-54
@@ -103,88 +103,97 @@ require_once __DIR__ . '/shared/components/sidebar.php';
|
|||||||
<div class="modal fade" id="modalPaciente" tabindex="-1">
|
<div class="modal fade" id="modalPaciente" tabindex="-1">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header py-2">
|
||||||
<h5 class="modal-title" id="modal-titulo"><i class="fas fa-user me-2"></i>Nuevo Paciente</h5>
|
<h6 class="modal-title" id="modal-titulo"><i class="fas fa-user me-2 text-primary"></i>Nuevo Paciente</h6>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body py-3">
|
||||||
<form id="form-paciente">
|
<form id="form-paciente">
|
||||||
<input type="hidden" name="id" id="pac-id">
|
<input type="hidden" name="id" id="pac-id">
|
||||||
<div class="row g-3">
|
<div class="row g-2">
|
||||||
<div class="col-md-8">
|
|
||||||
<label class="form-label">Nombre completo <span class="text-danger">*</span></label>
|
{{-- Nombre completo --}}
|
||||||
<input type="text" class="form-control" name="nombre_completo" id="pac-nombre" required>
|
<div class="col-12">
|
||||||
|
<label class="form-label small fw-semibold mb-1">Nombre completo <span class="text-danger">*</span></label>
|
||||||
|
<input type="text" class="form-control form-control-sm" name="nombre_completo" id="pac-nombre" required placeholder="Ej: Juan Pérez">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
|
||||||
<label class="form-label">Tipo doc.</label>
|
{{-- Documento --}}
|
||||||
<select class="form-select" name="tipo_documento" id="pac-tipo-doc">
|
<div class="col-4">
|
||||||
<option value="CC">CC — Cédula de Ciudadanía</option>
|
<label class="form-label small fw-semibold mb-1">Tipo doc.</label>
|
||||||
<option value="CE">CE — Cédula de Extranjería</option>
|
<select class="form-select form-select-sm" name="tipo_documento" id="pac-tipo-doc">
|
||||||
<option value="TI">TI — Tarjeta de Identidad</option>
|
<option value="CC">CC — Cédula</option>
|
||||||
|
<option value="CE">CE — Extranjería</option>
|
||||||
|
<option value="TI">TI — Tarjeta Identidad</option>
|
||||||
<option value="PA">PA — Pasaporte</option>
|
<option value="PA">PA — Pasaporte</option>
|
||||||
<option value="DE">DE — Documento Extranjero</option>
|
<option value="DE">DE — Doc. Extranjero</option>
|
||||||
<option value="NIT">NIT — NIT</option>
|
<option value="NIT">NIT</option>
|
||||||
<option value="RC">RC — Registro Civil</option>
|
<option value="RC">RC — Reg. Civil</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-4">
|
||||||
<label class="form-label">Número de documento</label>
|
<label class="form-label small fw-semibold mb-1">Número documento</label>
|
||||||
<input type="text" class="form-control" name="numero_documento" id="pac-doc">
|
<input type="text" class="form-control form-control-sm" name="numero_documento" id="pac-doc" placeholder="123456789">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-4">
|
||||||
<label class="form-label">Teléfono</label>
|
<label class="form-label small fw-semibold mb-1">Fecha nacimiento</label>
|
||||||
<div class="input-group">
|
<input type="date" class="form-control form-control-sm" name="fecha_nacimiento" id="pac-fnac">
|
||||||
<select id="pac-tel-prefijo" class="form-select" style="max-width:80px">
|
</div>
|
||||||
<option value="57" selected>🇨🇴 57</option>
|
|
||||||
<option value="58">🇻🇪 58</option>
|
{{-- Contacto --}}
|
||||||
<option value="1">🇺🇸 1</option>
|
<div class="col-5">
|
||||||
</select>
|
<label class="form-label small fw-semibold mb-1">Teléfono</label>
|
||||||
<input type="tel" class="form-control" name="telefono" id="pac-tel" placeholder="3001234567">
|
<div class="input-group input-group-sm">
|
||||||
|
<select id="pac-tel-prefijo" class="form-select form-select-sm" style="max-width:72px">
|
||||||
|
<option value="57" selected>🇨🇴 57</option>
|
||||||
|
<option value="58">🇻🇪 58</option>
|
||||||
|
<option value="1">🇺🇸 1</option>
|
||||||
|
</select>
|
||||||
|
<input type="tel" class="form-control form-control-sm" name="telefono" id="pac-tel" placeholder="3001234567">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-4">
|
||||||
<label class="form-label">Email</label>
|
<label class="form-label small fw-semibold mb-1">Email</label>
|
||||||
<input type="email" class="form-control" name="email" id="pac-email">
|
<input type="email" class="form-control form-control-sm" name="email" id="pac-email" placeholder="correo@ejemplo.com">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-3">
|
||||||
<label class="form-label">Fecha nacimiento</label>
|
<label class="form-label small fw-semibold mb-1">Género</label>
|
||||||
<input type="date" class="form-control" name="fecha_nacimiento" id="pac-fnac">
|
<select class="form-select form-select-sm" name="genero" id="pac-genero">
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label class="form-label">Género</label>
|
|
||||||
<select class="form-select" name="genero" id="pac-genero">
|
|
||||||
<option value="">—</option>
|
<option value="">—</option>
|
||||||
<option value="M">Masculino</option>
|
<option value="M">Masculino</option>
|
||||||
<option value="F">Femenino</option>
|
<option value="F">Femenino</option>
|
||||||
<option value="O">Otro</option>
|
<option value="O">Otro</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
|
||||||
<label class="form-label">EPS</label>
|
{{-- Ubicación --}}
|
||||||
<input type="text" class="form-control" name="eps" id="pac-eps">
|
<div class="col-4">
|
||||||
|
<label class="form-label small fw-semibold mb-1">EPS</label>
|
||||||
|
<input type="text" class="form-control form-control-sm" name="eps" id="pac-eps" placeholder="EPS del paciente">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-4">
|
||||||
<label class="form-label">Ciudad</label>
|
<label class="form-label small fw-semibold mb-1">Ciudad</label>
|
||||||
<input type="text" class="form-control" name="ciudad" id="pac-ciudad">
|
<input type="text" class="form-control form-control-sm" name="ciudad" id="pac-ciudad">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-4">
|
||||||
<label class="form-label">Barrio</label>
|
<label class="form-label small fw-semibold mb-1">Barrio</label>
|
||||||
<input type="text" class="form-control" name="barrio" id="pac-barrio">
|
<input type="text" class="form-control form-control-sm" name="barrio" id="pac-barrio">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label class="form-label">Dirección</label>
|
<label class="form-label small fw-semibold mb-1">Dirección</label>
|
||||||
<input type="text" class="form-control" name="direccion" id="pac-dir">
|
<input type="text" class="form-control form-control-sm" name="direccion" id="pac-dir">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label class="form-label">Notas internas</label>
|
<label class="form-label small fw-semibold mb-1">Notas internas</label>
|
||||||
<textarea class="form-control" name="notas_admin" id="pac-notas" rows="2"></textarea>
|
<textarea class="form-control form-control-sm" name="notas_admin" id="pac-notas" rows="2" placeholder="Observaciones o notas adicionales…"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer py-2">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||||
<button type="button" class="btn btn-primary" onclick="guardarPaciente()">
|
<button type="button" class="btn btn-sm btn-primary" onclick="guardarPaciente()">
|
||||||
<i class="fas fa-save me-1"></i> Guardar
|
<i class="fas fa-save me-1"></i> Guardar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -124,13 +124,20 @@ $stmtTurnos = $pdo->prepare(
|
|||||||
t.creado_at, t.inicio_recepcion_at, t.fin_recepcion_at,
|
t.creado_at, t.inicio_recepcion_at, t.fin_recepcion_at,
|
||||||
t.inicio_lugar_at, t.fin_lugar_at,
|
t.inicio_lugar_at, t.fin_lugar_at,
|
||||||
p.codigo AS prioridad_codigo, p.nombre AS prioridad_nombre, p.color AS prioridad_color,
|
p.codigo AS prioridad_codigo, p.nombre AS prioridad_nombre, p.color AS prioridad_color,
|
||||||
l.nombre AS lugar_nombre,
|
l.nombre AS lugar_nombre,
|
||||||
s.nombre_completo AS paciente_bd,
|
s.nombre_completo AS paciente_bd,
|
||||||
|
rd.nombre AS recepcion_desk_nombre,
|
||||||
|
ur.full_name AS atendido_recepcion_nombre,
|
||||||
|
ul.full_name AS atendido_lugar_nombre,
|
||||||
|
ts.observaciones AS notas,
|
||||||
ROUND(TIMESTAMPDIFF(SECOND, t.creado_at, COALESCE(t.inicio_recepcion_at, NOW())) / 60.0, 1) AS espera_min,
|
ROUND(TIMESTAMPDIFF(SECOND, t.creado_at, COALESCE(t.inicio_recepcion_at, NOW())) / 60.0, 1) AS espera_min,
|
||||||
ROUND(TIMESTAMPDIFF(SECOND, t.inicio_lugar_at, COALESCE(t.fin_lugar_at, NOW())) / 60.0, 1) AS servicio_min
|
ROUND(TIMESTAMPDIFF(SECOND, t.inicio_lugar_at, COALESCE(t.fin_lugar_at, NOW())) / 60.0, 1) AS servicio_min
|
||||||
FROM turnero_turnos t
|
FROM turnero_turnos t
|
||||||
JOIN turnero_prioridades p ON p.id = t.prioridad_id
|
JOIN turnero_prioridades p ON p.id = t.prioridad_id
|
||||||
LEFT JOIN turnero_lugares l ON l.id = t.lugar_destino_id
|
LEFT JOIN turnero_lugares l ON l.id = t.lugar_destino_id
|
||||||
|
LEFT JOIN turnero_lugares rd ON rd.id = t.recepcion_desk_id
|
||||||
|
LEFT JOIN admin_users ur ON ur.id = t.atendido_recepcion_por
|
||||||
|
LEFT JOIN admin_users ul ON ul.id = t.atendido_lugar_por
|
||||||
LEFT JOIN turnero_solicitudes ts ON ts.turno_id = t.id
|
LEFT JOIN turnero_solicitudes ts ON ts.turno_id = t.id
|
||||||
LEFT JOIN lab_pacientes s ON s.id = ts.paciente_id
|
LEFT JOIN lab_pacientes s ON s.id = ts.paciente_id
|
||||||
WHERE t.sesion_id = ?
|
WHERE t.sesion_id = ?
|
||||||
@@ -139,6 +146,25 @@ $stmtTurnos = $pdo->prepare(
|
|||||||
$stmtTurnos->execute([$sesionId]);
|
$stmtTurnos->execute([$sesionId]);
|
||||||
$turnos = $stmtTurnos->fetchAll(PDO::FETCH_ASSOC);
|
$turnos = $stmtTurnos->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Enriquecer con exámenes y comentarios
|
||||||
|
foreach ($turnos as &$turno) {
|
||||||
|
$stmtEx = $pdo->prepare(
|
||||||
|
"SELECT DISTINCT et.nombre FROM turnero_examen_items tei
|
||||||
|
JOIN exam_tipos et ON et.id = tei.exam_tipo_id
|
||||||
|
WHERE tei.solicitud_id = (SELECT id FROM turnero_solicitudes WHERE turno_id = ? LIMIT 1)"
|
||||||
|
);
|
||||||
|
$stmtEx->execute([$turno['id']]);
|
||||||
|
$turno['examenes'] = $stmtEx->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$stmtCom = $pdo->prepare(
|
||||||
|
"SELECT usuario_nombre, comentario, tipo, creado_at
|
||||||
|
FROM turnero_comentarios WHERE turno_id = ? ORDER BY creado_at ASC"
|
||||||
|
);
|
||||||
|
$stmtCom->execute([$turno['id']]);
|
||||||
|
$turno['comentarios'] = $stmtCom->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
unset($turno);
|
||||||
|
|
||||||
// ── 6. Consentimientos del día ────────────────────────────────
|
// ── 6. Consentimientos del día ────────────────────────────────
|
||||||
$stmtcons = $pdo->prepare(
|
$stmtcons = $pdo->prepare(
|
||||||
"SELECT tc.estado, COUNT(*) AS cnt
|
"SELECT tc.estado, COUNT(*) AS cnt
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ $sqlTurnos = "
|
|||||||
p.color AS prioridad_color,
|
p.color AS prioridad_color,
|
||||||
l.nombre AS lugar_nombre,
|
l.nombre AS lugar_nombre,
|
||||||
s2.nombre_completo AS paciente_bd,
|
s2.nombre_completo AS paciente_bd,
|
||||||
|
rd.nombre AS recepcion_desk_nombre,
|
||||||
|
ur.full_name AS atendido_recepcion_nombre,
|
||||||
|
ul.full_name AS atendido_lugar_nombre,
|
||||||
ROUND(TIMESTAMPDIFF(SECOND, t.creado_at,
|
ROUND(TIMESTAMPDIFF(SECOND, t.creado_at,
|
||||||
COALESCE(t.inicio_recepcion_at, t.fin_recepcion_at)) / 60.0, 1)
|
COALESCE(t.inicio_recepcion_at, t.fin_recepcion_at)) / 60.0, 1)
|
||||||
AS espera_min,
|
AS espera_min,
|
||||||
@@ -118,6 +121,9 @@ $sqlTurnos = "
|
|||||||
JOIN turnero_sesiones s ON s.id = t.sesion_id
|
JOIN turnero_sesiones s ON s.id = t.sesion_id
|
||||||
JOIN turnero_prioridades p ON p.id = t.prioridad_id
|
JOIN turnero_prioridades p ON p.id = t.prioridad_id
|
||||||
LEFT JOIN turnero_lugares l ON l.id = t.lugar_destino_id
|
LEFT JOIN turnero_lugares l ON l.id = t.lugar_destino_id
|
||||||
|
LEFT JOIN turnero_lugares rd ON rd.id = t.recepcion_desk_id
|
||||||
|
LEFT JOIN admin_users ur ON ur.id = t.atendido_recepcion_por
|
||||||
|
LEFT JOIN admin_users ul ON ul.id = t.atendido_lugar_por
|
||||||
LEFT JOIN turnero_solicitudes ts2 ON ts2.turno_id = t.id
|
LEFT JOIN turnero_solicitudes ts2 ON ts2.turno_id = t.id
|
||||||
LEFT JOIN lab_pacientes s2 ON s2.id = ts2.paciente_id
|
LEFT JOIN lab_pacientes s2 ON s2.id = ts2.paciente_id
|
||||||
$whereStr
|
$whereStr
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* POST { turno_id, paciente_id }
|
||||||
|
* Vincula un paciente al turno para que los consentimientos puedan crearse.
|
||||||
|
*/
|
||||||
|
require_once __DIR__ . '/_helpers.php';
|
||||||
|
requireMethod('POST');
|
||||||
|
requireTurnero();
|
||||||
|
|
||||||
|
$d = inputJson();
|
||||||
|
$turnoId = (int)($d['turno_id'] ?? 0);
|
||||||
|
$pacienteId = (int)($d['paciente_id'] ?? 0);
|
||||||
|
|
||||||
|
if (!$turnoId || !$pacienteId) jsonError('turno_id y paciente_id requeridos.');
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare('UPDATE turnero_turnos SET paciente_id = ? WHERE id = ?');
|
||||||
|
$stmt->execute([$pacienteId, $turnoId]);
|
||||||
|
|
||||||
|
if (!$stmt->rowCount()) jsonError('Turno no encontrado.', 404);
|
||||||
|
|
||||||
|
jsonOk(['turno_id' => $turnoId, 'paciente_id' => $pacienteId]);
|
||||||
@@ -623,7 +623,8 @@ $tab = $_GET['tab'] ?? 'lugares';
|
|||||||
<select id="edit-pr-icono" class="form-select form-select-sm">
|
<select id="edit-pr-icono" class="form-select form-select-sm">
|
||||||
<option value="">— Sin icono —</option>
|
<option value="">— Sin icono —</option>
|
||||||
<option value="fas fa-child">👶 Niños (fas fa-child)</option>
|
<option value="fas fa-child">👶 Niños (fas fa-child)</option>
|
||||||
<option value="fas fa-heart">❤ Embarazada (fas fa-heart)</option>
|
<option value="fa-solid fa-person-pregnant">🤰 Embarazada (fa-person-pregnant)</option>
|
||||||
|
<option value="fas fa-heart">❤ Embarazada alt (fas fa-heart)</option>
|
||||||
<option value="fas fa-person-cane">🦯 Adulto mayor (fas fa-person-cane)</option>
|
<option value="fas fa-person-cane">🦯 Adulto mayor (fas fa-person-cane)</option>
|
||||||
<option value="fas fa-wheelchair">♿ Discapacidad (fas fa-wheelchair)</option>
|
<option value="fas fa-wheelchair">♿ Discapacidad (fas fa-wheelchair)</option>
|
||||||
<option value="fas fa-user">👤 Paciente general (fas fa-user)</option>
|
<option value="fas fa-user">👤 Paciente general (fas fa-user)</option>
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ Layout::open('Dashboard Turnero', 'fas fa-chart-bar');
|
|||||||
<th>Espera</th>
|
<th>Espera</th>
|
||||||
<th>Servicio</th>
|
<th>Servicio</th>
|
||||||
<th>Entrada</th>
|
<th>Entrada</th>
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="tbodyTurnos">
|
<tbody id="tbodyTurnos">
|
||||||
@@ -324,7 +325,8 @@ function renderTabla(turnos) {
|
|||||||
const hora = t.creado_at ? new Date(t.creado_at.replace(' ', 'T')).toLocaleTimeString('es-CO', {hour:'2-digit',minute:'2-digit'}) : '—';
|
const hora = t.creado_at ? new Date(t.creado_at.replace(' ', 'T')).toLocaleTimeString('es-CO', {hour:'2-digit',minute:'2-digit'}) : '—';
|
||||||
const espMin = t.espera_min !== null ? t.espera_min + ' m' : '—';
|
const espMin = t.espera_min !== null ? t.espera_min + ' m' : '—';
|
||||||
const srvMin = t.servicio_min !== null ? t.servicio_min + ' m' : '—';
|
const srvMin = t.servicio_min !== null ? t.servicio_min + ' m' : '—';
|
||||||
return `<tr>
|
const rowId = `dash-det-${t.id}`;
|
||||||
|
return `<tr style="cursor:pointer" onclick="toggleDashDetalle('${rowId}', this)">
|
||||||
<td><span class="fw-bold" style="color:${escHtml(t.prioridad_color || '#333')}">${escHtml(t.codigo)}</span></td>
|
<td><span class="fw-bold" style="color:${escHtml(t.prioridad_color || '#333')}">${escHtml(t.codigo)}</span></td>
|
||||||
<td><span class="estado-badge" style="background:${escHtml(t.prioridad_color+'22'||'#eee')};color:${escHtml(t.prioridad_color||'#333')}">${escHtml(t.prioridad_codigo)}</span></td>
|
<td><span class="estado-badge" style="background:${escHtml(t.prioridad_color+'22'||'#eee')};color:${escHtml(t.prioridad_color||'#333')}">${escHtml(t.prioridad_codigo)}</span></td>
|
||||||
<td>${nombrePac}</td>
|
<td>${nombrePac}</td>
|
||||||
@@ -333,10 +335,77 @@ function renderTabla(turnos) {
|
|||||||
<td>${espMin}</td>
|
<td>${espMin}</td>
|
||||||
<td>${srvMin}</td>
|
<td>${srvMin}</td>
|
||||||
<td>${hora}</td>
|
<td>${hora}</td>
|
||||||
|
<td><i class="fas fa-chevron-down text-muted" style="font-size:.65rem"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr id="${rowId}" style="display:none;background:#f8fafc">
|
||||||
|
<td colspan="9" style="padding:0">
|
||||||
|
<div style="padding:12px 16px;border-top:1px solid #e2e8f0">
|
||||||
|
${renderDashDetalle(t)}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleDashDetalle(rowId, tr) {
|
||||||
|
const det = document.getElementById(rowId);
|
||||||
|
const icon = tr.querySelector('.fa-chevron-down, .fa-chevron-up');
|
||||||
|
if (!det) return;
|
||||||
|
const open = det.style.display !== 'none';
|
||||||
|
det.style.display = open ? 'none' : '';
|
||||||
|
if (icon) icon.className = open ? 'fas fa-chevron-down text-muted' : 'fas fa-chevron-up text-muted';
|
||||||
|
if (icon) icon.style.fontSize = '.65rem';
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderDashDetalle(t) {
|
||||||
|
const e = s => escHtml(s || '—');
|
||||||
|
const fmt = dt => dt ? new Date(dt.replace(' ','T')).toLocaleString('es-CO',{dateStyle:'short',timeStyle:'short'}) : '—';
|
||||||
|
|
||||||
|
const chips = [
|
||||||
|
{ lbl:'Recepción (desk)', val: e(t.recepcion_desk_nombre) },
|
||||||
|
{ lbl:'Atendió recepción', val: e(t.atendido_recepcion_nombre) },
|
||||||
|
{ lbl:'Atendió muestras', val: e(t.atendido_lugar_nombre) },
|
||||||
|
{ lbl:'Inicio recepción', val: fmt(t.inicio_recepcion_at) },
|
||||||
|
{ lbl:'Fin recepción', val: fmt(t.fin_recepcion_at) },
|
||||||
|
{ lbl:'Inicio servicio', val: fmt(t.inicio_lugar_at) },
|
||||||
|
{ lbl:'Fin servicio', val: fmt(t.fin_lugar_at) },
|
||||||
|
];
|
||||||
|
|
||||||
|
let grid = `<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:8px;margin-bottom:10px">
|
||||||
|
${chips.map(c=>`<div style="background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:7px 11px">
|
||||||
|
<div style="font-size:.63rem;text-transform:uppercase;letter-spacing:.07em;color:#94a3b8">${c.lbl}</div>
|
||||||
|
<div style="font-size:.82rem;font-weight:600;color:#1e293b">${c.val}</div>
|
||||||
|
</div>`).join('')}
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
// Notas
|
||||||
|
if (t.notas) {
|
||||||
|
grid += `<div style="margin-bottom:8px;font-size:.82rem"><span style="font-size:.67rem;text-transform:uppercase;letter-spacing:.07em;color:#94a3b8">📝 Notas: </span>${e(t.notas)}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exámenes
|
||||||
|
if (t.examenes && t.examenes.length) {
|
||||||
|
grid += `<div style="margin-bottom:8px">
|
||||||
|
<span style="font-size:.67rem;text-transform:uppercase;letter-spacing:.07em;color:#94a3b8"><i class="fas fa-vials me-1"></i>Exámenes (${t.examenes.length}): </span>
|
||||||
|
${t.examenes.map(ex=>`<span class="badge" style="background:#dcfce7;color:#166534;margin:1px 2px">${e(ex.nombre)}</span>`).join('')}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comentarios
|
||||||
|
if (t.comentarios && t.comentarios.length) {
|
||||||
|
grid += `<div style="border-top:1px solid #e2e8f0;padding-top:8px">
|
||||||
|
<div style="font-size:.67rem;text-transform:uppercase;letter-spacing:.07em;color:#94a3b8;margin-bottom:5px"><i class="fas fa-comments me-1"></i>Comentarios</div>
|
||||||
|
${t.comentarios.map(c=>`<div style="font-size:.8rem;padding:4px 0;border-bottom:1px solid #f1f5f9">
|
||||||
|
<strong>${e(c.usuario_nombre)}</strong>
|
||||||
|
<span style="color:#94a3b8;font-size:.72rem;margin-left:6px">${fmt(c.creado_at)}</span>
|
||||||
|
<div style="color:#475569">${e(c.comentario)}</div>
|
||||||
|
</div>`).join('')}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
|
||||||
function filtrarTabla() {
|
function filtrarTabla() {
|
||||||
const q = document.getElementById('filtroBusqueda').value.toLowerCase().trim();
|
const q = document.getElementById('filtroBusqueda').value.toLowerCase().trim();
|
||||||
if (!q) { renderTabla(_turnos); return; }
|
if (!q) { renderTabla(_turnos); return; }
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ $_hasVideo = (bool)$_tvVideo;
|
|||||||
margin-bottom: .2rem;
|
margin-bottom: .2rem;
|
||||||
}
|
}
|
||||||
.turno-activo .codigo {
|
.turno-activo .codigo {
|
||||||
font-size: clamp(5rem, 22vw, 16rem);
|
font-size: clamp(4rem, 14vw, 10rem);
|
||||||
font-weight: 900; line-height: 1;
|
font-weight: 900; line-height: 1;
|
||||||
letter-spacing: -4px;
|
letter-spacing: -4px;
|
||||||
color: var(--brand);
|
color: var(--brand);
|
||||||
@@ -160,13 +160,13 @@ $_hasVideo = (bool)$_tvVideo;
|
|||||||
100% { transform: translate(-50%, -50%) scale(.75); opacity: .15; }
|
100% { transform: translate(-50%, -50%) scale(.75); opacity: .15; }
|
||||||
}
|
}
|
||||||
.turno-activo .lugar-label {
|
.turno-activo .lugar-label {
|
||||||
font-size: clamp(1.35rem, 3vw, 2.15rem);
|
font-size: clamp(1.5rem, 3vw, 2.5rem);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
margin-top: .3rem;
|
margin-top: .3rem;
|
||||||
}
|
}
|
||||||
.turno-activo .lugar-nombre {
|
.turno-activo .lugar-nombre {
|
||||||
font-size: clamp(1.75rem, 4vw, 3.05rem);
|
font-size: clamp(3rem, 10vw, 8rem);
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: #1e293b;
|
color: #1e293b;
|
||||||
margin-top: .1rem;
|
margin-top: .1rem;
|
||||||
|
|||||||
@@ -95,6 +95,12 @@ Layout::open('Historial de Turnos', 'fas fa-history');
|
|||||||
.detail-item .d-lbl { font-size:.67rem; text-transform:uppercase; letter-spacing:.07em; color:#94a3b8; }
|
.detail-item .d-lbl { font-size:.67rem; text-transform:uppercase; letter-spacing:.07em; color:#94a3b8; }
|
||||||
.detail-item .d-val { font-size:.85rem; font-weight:600; color:#1e293b; }
|
.detail-item .d-val { font-size:.85rem; font-weight:600; color:#1e293b; }
|
||||||
|
|
||||||
|
/* ── Exámenes y comentarios ── */
|
||||||
|
.detail-extra { margin-top:10px; padding-top:10px; border-top:1px solid #e2e8f0; }
|
||||||
|
.detail-extra .d-lbl { font-size:.67rem; text-transform:uppercase; letter-spacing:.07em; color:#94a3b8; margin-bottom:5px; }
|
||||||
|
.detail-comment { padding:5px 0; border-bottom:1px solid #f1f5f9; font-size:.82rem; }
|
||||||
|
.detail-comment:last-child { border-bottom:none; }
|
||||||
|
|
||||||
/* ── Documentos firmados ── */
|
/* ── Documentos firmados ── */
|
||||||
.docs-section { margin-top:10px; padding-top:10px; border-top:1px solid #e2e8f0; }
|
.docs-section { margin-top:10px; padding-top:10px; border-top:1px solid #e2e8f0; }
|
||||||
.docs-lbl { font-size:.65rem; font-weight:700; text-transform:uppercase; letter-spacing:.07em; color:#94a3b8; margin-bottom:5px; }
|
.docs-lbl { font-size:.65rem; font-weight:700; text-transform:uppercase; letter-spacing:.07em; color:#94a3b8; margin-bottom:5px; }
|
||||||
@@ -448,15 +454,42 @@ function renderDetalle(t) {
|
|||||||
return d.toLocaleString('es-CO',{dateStyle:'short',timeStyle:'short'});
|
return d.toLocaleString('es-CO',{dateStyle:'short',timeStyle:'short'});
|
||||||
};
|
};
|
||||||
const items = [
|
const items = [
|
||||||
{ lbl:'Creado', val: fmt(t.creado_at) },
|
{ lbl:'Creado', val: fmt(t.creado_at) },
|
||||||
{ lbl:'Inicio recepción', val: fmt(t.inicio_recepcion_at) },
|
{ lbl:'Inicio recepción', val: fmt(t.inicio_recepcion_at) },
|
||||||
{ lbl:'Fin recepción', val: fmt(t.fin_recepcion_at) },
|
{ lbl:'Fin recepción', val: fmt(t.fin_recepcion_at) },
|
||||||
{ lbl:'Inicio servicio', val: fmt(t.inicio_lugar_at) },
|
{ lbl:'Inicio servicio', val: fmt(t.inicio_lugar_at) },
|
||||||
{ lbl:'Fin servicio', val: fmt(t.fin_lugar_at) },
|
{ lbl:'Fin servicio', val: fmt(t.fin_lugar_at) },
|
||||||
{ lbl:'Código completo', val: esc(t.codigo) },
|
{ lbl:'Código completo', val: esc(t.codigo) },
|
||||||
{ lbl:'Número en cola', val: t.numero ?? '—' },
|
{ lbl:'Número en cola', val: t.numero ?? '—' },
|
||||||
{ lbl:'Teléfono', val: esc(t.paciente_cel || '—') },
|
{ lbl:'Teléfono', val: esc(t.paciente_cel || '—') },
|
||||||
|
{ lbl:'Recepción (desk)', val: esc(t.recepcion_desk_nombre || '—') },
|
||||||
|
{ lbl:'Atendió recepción', val: esc(t.atendido_recepcion_nombre || '—') },
|
||||||
|
{ lbl:'Atendió muestras', val: esc(t.atendido_lugar_nombre || '—') },
|
||||||
];
|
];
|
||||||
|
// Exámenes
|
||||||
|
let examHtml = '';
|
||||||
|
if (t.examenes && t.examenes.length) {
|
||||||
|
examHtml = `<div class="detail-extra">
|
||||||
|
<div class="d-lbl"><i class="fas fa-vials me-1 text-success"></i>Exámenes (${t.examenes.length})</div>
|
||||||
|
<div class="d-val">${t.examenes.map(e => `<span class="badge bg-success-subtle text-success me-1 mb-1">${esc(e.nombre)}</span>`).join('')}</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comentarios
|
||||||
|
let comHtml = '';
|
||||||
|
if (t.comentarios && t.comentarios.length) {
|
||||||
|
comHtml = `<div class="detail-extra">
|
||||||
|
<div class="d-lbl"><i class="fas fa-comments me-1 text-primary"></i>Comentarios</div>
|
||||||
|
<div>${t.comentarios.map(c => `
|
||||||
|
<div class="detail-comment">
|
||||||
|
<span class="fw-semibold">${esc(c.usuario_nombre)}</span>
|
||||||
|
<span class="text-muted small ms-1">${c.creado_at ? new Date(c.creado_at.replace(' ','T')).toLocaleString('es-CO',{dateStyle:'short',timeStyle:'short'}) : ''}</span>
|
||||||
|
<div class="text-secondary">${esc(c.comentario)}</div>
|
||||||
|
</div>`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
return `<div class="detail-grid">
|
return `<div class="detail-grid">
|
||||||
${items.map(it=>`
|
${items.map(it=>`
|
||||||
<div class="detail-item">
|
<div class="detail-item">
|
||||||
@@ -464,6 +497,7 @@ function renderDetalle(t) {
|
|||||||
<div class="d-val">${it.val}</div>
|
<div class="d-val">${it.val}</div>
|
||||||
</div>`).join('')}
|
</div>`).join('')}
|
||||||
</div>
|
</div>
|
||||||
|
${examHtml}${comHtml}
|
||||||
<div class="docs-section" id="docs-${t.id}">
|
<div class="docs-section" id="docs-${t.id}">
|
||||||
<div class="docs-lbl"><i class="fas fa-file-signature me-1"></i>Documentos</div>
|
<div class="docs-lbl"><i class="fas fa-file-signature me-1"></i>Documentos</div>
|
||||||
<span class="text-muted small"><i class="fas fa-spinner fa-spin me-1"></i>Cargando…</span>
|
<span class="text-muted small"><i class="fas fa-spinner fa-spin me-1"></i>Cargando…</span>
|
||||||
|
|||||||
@@ -207,10 +207,10 @@ unset($p);
|
|||||||
.btn-prioridad:active { transform: scale(.95); filter: brightness(.93); }
|
.btn-prioridad:active { transform: scale(.95); filter: brightness(.93); }
|
||||||
.btn-prioridad:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0,0,0,.13); }
|
.btn-prioridad:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0,0,0,.13); }
|
||||||
.btn-prioridad .icon-wrap {
|
.btn-prioridad .icon-wrap {
|
||||||
width: 62px; height: 62px;
|
width: 90px; height: 90px;
|
||||||
border-radius: 14px;
|
border-radius: 16px;
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
font-size: 2.04rem;
|
font-size: 3rem;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
margin-bottom: .2rem;
|
margin-bottom: .2rem;
|
||||||
}
|
}
|
||||||
@@ -265,7 +265,7 @@ unset($p);
|
|||||||
/* ── Print: ticket para impresora térmica SRP-B300 ── */
|
/* ── Print: ticket para impresora térmica SRP-B300 ── */
|
||||||
@media print {
|
@media print {
|
||||||
@page { margin: 1mm 2mm; size: 80mm auto; }
|
@page { margin: 1mm 2mm; size: 80mm auto; }
|
||||||
body { background: #fff !important; font-family: 'Courier New', Courier, 'Lucida Console', monospace !important; -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }
|
body { background: #fff !important; font-family: Arial, Helvetica, sans-serif !important; -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; -webkit-font-smoothing: antialiased !important; }
|
||||||
.kiosko-topbar, .kiosko-footer, .spinner-overlay, .toast-error,
|
.kiosko-topbar, .kiosko-footer, .spinner-overlay, .toast-error,
|
||||||
.btn-nuevo, #screen-prio, #screen-datos { display: none !important; }
|
.btn-nuevo, #screen-prio, #screen-datos { display: none !important; }
|
||||||
#screen-ticket { display: block !important; opacity: 1 !important; position: static !important; }
|
#screen-ticket { display: block !important; opacity: 1 !important; position: static !important; }
|
||||||
@@ -278,13 +278,13 @@ unset($p);
|
|||||||
border-top: none !important; border-radius: 0 !important;
|
border-top: none !important; border-radius: 0 !important;
|
||||||
text-align: center !important;
|
text-align: center !important;
|
||||||
}
|
}
|
||||||
.ticket-label { font-size: 8pt !important; letter-spacing: 0.03em !important; margin-bottom: 0 !important; padding-top: 2pt !important; }
|
.ticket-label { font-size: 10pt !important; font-weight: 600 !important; letter-spacing: 0.03em !important; margin-bottom: 0 !important; padding-top: 2pt !important; }
|
||||||
.ticket-codigo { font-size: 22pt !important; font-weight: 700 !important; letter-spacing: 0 !important; line-height: 1 !important; padding: 0 !important; }
|
.ticket-codigo { font-size: 22pt !important; font-weight: 700 !important; letter-spacing: 0 !important; line-height: 1 !important; padding: 0 !important; }
|
||||||
.ticket-prio-badge { font-size: 8pt !important; padding: 0 !important; margin: 0 !important; background: transparent !important; color: #000 !important; }
|
.ticket-prio-badge { font-size: 10pt !important; font-weight: 600 !important; padding: 0 !important; margin: 0 !important; background: transparent !important; color: #000 !important; }
|
||||||
.ticket-pos { margin: 2pt 0 !important; padding: 0 !important; border-radius: 0 !important; background: transparent !important; }
|
.ticket-pos { margin: 2pt 0 !important; padding: 0 !important; border-radius: 0 !important; background: transparent !important; }
|
||||||
.ticket-pos .lbl { font-size: 7pt !important; letter-spacing: 0.03em !important; }
|
.ticket-pos .lbl { font-size: 9pt !important; font-weight: 600 !important; letter-spacing: 0.03em !important; }
|
||||||
.ticket-pos .num { font-size: 11pt !important; font-weight: 700 !important; color: #000 !important; }
|
.ticket-pos .num { font-size: 12pt !important; font-weight: 700 !important; color: #000 !important; }
|
||||||
.ticket-instruc { font-size: 7pt !important; margin: 2pt 0 !important; line-height: 1.15 !important; padding-bottom: 2pt !important; }
|
.ticket-instruc { font-size: 9pt !important; font-weight: 500 !important; margin: 2pt 0 !important; line-height: 1.3 !important; padding-bottom: 2pt !important; }
|
||||||
.ticket-codigo, .ticket-label, .ticket-prio-badge,
|
.ticket-codigo, .ticket-label, .ticket-prio-badge,
|
||||||
.ticket-pos, .ticket-pos .lbl, .ticket-pos .num,
|
.ticket-pos, .ticket-pos .lbl, .ticket-pos .num,
|
||||||
.ticket-instruc { color: #000 !important; }
|
.ticket-instruc { color: #000 !important; }
|
||||||
@@ -517,16 +517,20 @@ unset($p);
|
|||||||
inpCedula.focus();
|
inpCedula.focus();
|
||||||
inpCedula.value = '';
|
inpCedula.value = '';
|
||||||
|
|
||||||
// Detector de scanner: cuando se pega/escribe rápido una cédula válida
|
// Detector de scanner: auto-submit solo si los dígitos llegan rápido (< 80ms entre cada uno)
|
||||||
let _timerAutoSubmit = null;
|
let _timerAutoSubmit = null;
|
||||||
|
let _lastKeyAt = 0;
|
||||||
inpCedula.addEventListener('input', () => {
|
inpCedula.addEventListener('input', () => {
|
||||||
clearTimeout(_timerAutoSubmit);
|
clearTimeout(_timerAutoSubmit);
|
||||||
|
const now = Date.now();
|
||||||
|
const gap = now - _lastKeyAt;
|
||||||
|
_lastKeyAt = now;
|
||||||
const val = inpCedula.value.trim();
|
const val = inpCedula.value.trim();
|
||||||
if (/^\d{5,15}$/.test(val)) {
|
// Scanner envía dígitos en ráfaga; teclado humano siempre > 80ms entre teclas
|
||||||
// Cédula válida: auto-submit en 300ms (tiempo para que termine el scanner)
|
if (/^\d{5,15}$/.test(val) && gap < 80) {
|
||||||
_timerAutoSubmit = setTimeout(() => confirmarTurno(), 300);
|
_timerAutoSubmit = setTimeout(() => confirmarTurno(), 300);
|
||||||
}
|
}
|
||||||
}, { once: false });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function volverPrioridades() { mostrar('screen-prio'); }
|
function volverPrioridades() { mostrar('screen-prio'); }
|
||||||
|
|||||||
@@ -846,6 +846,14 @@ async function buscarPaciente() {
|
|||||||
|
|
||||||
function seleccionarPaciente(pac) {
|
function seleccionarPaciente(pac) {
|
||||||
pacienteActivo = pac;
|
pacienteActivo = pac;
|
||||||
|
// Persistir vínculo en BD para que create_consent_token pueda verificar paciente_id
|
||||||
|
if (turnoActivo?.id && pac?.id) {
|
||||||
|
fetch(API + 'vincular_paciente.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ turno_id: turnoActivo.id, paciente_id: pac.id }),
|
||||||
|
}).catch(() => {});
|
||||||
|
}
|
||||||
document.getElementById('bloque-pac-no-vinculado').classList.add('d-none');
|
document.getElementById('bloque-pac-no-vinculado').classList.add('d-none');
|
||||||
document.getElementById('bloque-pac-seleccionado').classList.remove('d-none');
|
document.getElementById('bloque-pac-seleccionado').classList.remove('d-none');
|
||||||
document.getElementById('lbl-pac-nombre').textContent =
|
document.getElementById('lbl-pac-nombre').textContent =
|
||||||
@@ -959,17 +967,6 @@ function renderHistorialTimeline(turnos, total) {
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consentimientos
|
|
||||||
let consStr = '';
|
|
||||||
if (t.consentimientos && t.consentimientos.length) {
|
|
||||||
consStr = `<div style="margin-top:6px;font-size:.75rem">
|
|
||||||
<strong style="color:#64748b">Consentimientos:</strong>
|
|
||||||
<div>${t.consentimientos.map(c =>
|
|
||||||
`<span style="display:inline-block;margin-right:6px">${CONS_ICON[c.estado]||'?'} ${escHtml(c.nombre||'Consentimiento')}</span>`
|
|
||||||
).join('')}</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comentarios
|
// Comentarios
|
||||||
let comStr = '';
|
let comStr = '';
|
||||||
if (t.comentarios && t.comentarios.length) {
|
if (t.comentarios && t.comentarios.length) {
|
||||||
@@ -988,7 +985,7 @@ function renderHistorialTimeline(turnos, total) {
|
|||||||
<div class="timeline-codigo" style="color:${color}">${escHtml(t.codigo)}</div>
|
<div class="timeline-codigo" style="color:${color}">${escHtml(t.codigo)}</div>
|
||||||
<div class="timeline-lugar">${lugar}</div>
|
<div class="timeline-lugar">${lugar}</div>
|
||||||
<span class="timeline-eb" style="${eStyle}">${escHtml(eLbl)}</span>${mins}
|
<span class="timeline-eb" style="${eStyle}">${escHtml(eLbl)}</span>${mins}
|
||||||
${examStr}${consStr}${comStr}
|
${examStr}${comStr}
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|||||||
@@ -494,10 +494,14 @@ function esc2(mixed $v): string {
|
|||||||
<img src="<?= htmlspecialchars($fFoto) ?>" alt="Foto - <?= $fLabel ?>">
|
<img src="<?= htmlspecialchars($fFoto) ?>" alt="Foto - <?= $fLabel ?>">
|
||||||
</div>
|
</div>
|
||||||
<?php elseif ($isPro): ?>
|
<?php elseif ($isPro): ?>
|
||||||
<?php if (!$modoPublico && !$yaHayCanvasPro): ?>
|
<?php if (($modoTurnero && isUserLoggedIn()) || (!$modoPublico && !$yaHayCanvasPro)): ?>
|
||||||
<!-- Canvas del profesional: solo aparece una vez -->
|
<!-- Canvas del profesional: solo aparece una vez -->
|
||||||
<div class="firma-pro-widget no-print" id="fpw-<?= htmlspecialchars($cid) ?>"
|
<div class="firma-pro-widget no-print" id="fpw-<?= htmlspecialchars($cid) ?>"
|
||||||
data-envio="<?= (int)$envio['id'] ?>" data-campo="<?= htmlspecialchars($cid) ?>">
|
data-envio="<?= (int)$envio['id'] ?>" data-campo="<?= htmlspecialchars($cid) ?>"
|
||||||
|
<?php if ($modoTurnero): ?>
|
||||||
|
data-turno="<?= (int)$tcRow['turno_id'] ?>"
|
||||||
|
data-formulario="<?= (int)$tcRow['formulario_id'] ?>"
|
||||||
|
<?php endif; ?>>
|
||||||
<p class="text-muted small mb-2"><i class="fas fa-pen me-1"></i>Dibuje su firma en el recuadro:</p>
|
<p class="text-muted small mb-2"><i class="fas fa-pen me-1"></i>Dibuje su firma en el recuadro:</p>
|
||||||
<canvas class="fpw-canvas" width="500" height="150"></canvas>
|
<canvas class="fpw-canvas" width="500" height="150"></canvas>
|
||||||
<div class="mt-2 d-flex gap-2">
|
<div class="mt-2 d-flex gap-2">
|
||||||
@@ -807,10 +811,20 @@ function esc2(mixed $v): string {
|
|||||||
btnSave.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Guardando...';
|
btnSave.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Guardando...';
|
||||||
msg.textContent = '';
|
msg.textContent = '';
|
||||||
|
|
||||||
fetch('api/lab/firmar_profesional.php', {
|
const turnoId = widget.dataset.turno;
|
||||||
|
const formularioId = widget.dataset.formulario;
|
||||||
|
const isTurnero = !!(turnoId && formularioId);
|
||||||
|
const saveUrl = isTurnero
|
||||||
|
? 'modules/turnero/api/firmar_profesional_consentimiento.php'
|
||||||
|
: 'api/lab/firmar_profesional.php';
|
||||||
|
const savePayload = isTurnero
|
||||||
|
? { turno_id: parseInt(turnoId), formulario_id: parseInt(formularioId), svg: svg }
|
||||||
|
: { envio_id: envioId, campo_id: campoId, svg: svg };
|
||||||
|
|
||||||
|
fetch(saveUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ envio_id: envioId, campo_id: campoId, svg: svg })
|
body: JSON.stringify(savePayload)
|
||||||
})
|
})
|
||||||
.then(function(r){ return r.json(); })
|
.then(function(r){ return r.json(); })
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
|
|||||||
Reference in New Issue
Block a user