feat(turnero): anexar formulario adicional a turno desde lugar.php
Permite al operador agregar un consentimiento informado extra (fuera de los asignados por defecto) mientras el turno está en servicio. - PHP: consulta lab_formularios activos al cargar lugar.php - JS: modal de selección con lista de formularios - Botón visible solo cuando turno está en_servicio, oculto en resetFicha - API: modules/turnero/api/anexar_formulario.php crea el consentimiento y notifica SSE para que el dispositivo lo vea inmediatamente - Fix: _olvidarConsentimiento usaba cargarConsentimientos() inexistente; corregido a actualizarConsentimientos(turnoActivo.id) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
ff52fa5ba7
commit
afa7cc6812
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* POST /modules/turnero/api/anexar_formulario.php
|
||||
* Crea un consentimiento adicional para un turno activo.
|
||||
* Body JSON: { turno_id: int, formulario_id: int }
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
requireTurnero();
|
||||
|
||||
$body = inputJson();
|
||||
$turnoId = (int)($body['turno_id'] ?? 0);
|
||||
$formularioId = (int)($body['formulario_id'] ?? 0);
|
||||
|
||||
if (!$turnoId) jsonError('turno_id requerido.');
|
||||
if (!$formularioId) jsonError('formulario_id requerido.');
|
||||
|
||||
$pdo = db();
|
||||
|
||||
// Verificar que el turno existe y está activo
|
||||
$turno = $pdo->prepare("SELECT id, sesion_id, estado FROM turnero_turnos WHERE id = ? LIMIT 1");
|
||||
$turno->execute([$turnoId]);
|
||||
$t = $turno->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$t) jsonError('Turno no encontrado.', 404);
|
||||
if (!in_array($t['estado'], ['en_espera_lugar', 'en_servicio'])) jsonError('El turno no está activo.');
|
||||
|
||||
// Verificar que el formulario existe
|
||||
$form = $pdo->prepare("SELECT id, nombre FROM lab_formularios WHERE id = ? AND is_active = 1 LIMIT 1");
|
||||
$form->execute([$formularioId]);
|
||||
if (!$form->fetch()) jsonError('Formulario no encontrado o inactivo.', 404);
|
||||
|
||||
// Crear el consentimiento con token único
|
||||
$token = bin2hex(random_bytes(16));
|
||||
|
||||
$ins = $pdo->prepare(
|
||||
"INSERT INTO turnero_consentimientos (turno_id, formulario_id, token, estado, datos_respuestas)
|
||||
VALUES (?, ?, ?, 'enviado', '{}')"
|
||||
);
|
||||
$ins->execute([$turnoId, $formularioId, $token]);
|
||||
$newId = (int)$pdo->lastInsertId();
|
||||
|
||||
notificarSSE((int)$t['sesion_id']);
|
||||
jsonOk(['id' => $newId, 'token' => $token], 'Formulario agregado.');
|
||||
@@ -92,6 +92,13 @@ foreach ($lugares as $_el) {
|
||||
$especialidades[] = $_el;
|
||||
}
|
||||
}
|
||||
|
||||
$formulariosList = [];
|
||||
try {
|
||||
$formulariosList = Database::getInstance()->getConnection()
|
||||
->query("SELECT id, nombre FROM lab_formularios WHERE is_active = 1 ORDER BY nombre ASC")
|
||||
->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (\Throwable $_) {}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
@@ -836,6 +843,11 @@ require_once __DIR__ . '/../../../shared/components/sidebar.php';
|
||||
<div id="sin-consent" class="text-muted small">
|
||||
<i class="fas fa-check-circle text-success me-1"></i>No se requieren consentimientos
|
||||
</div>
|
||||
<div id="btn-anexar-wrap" class="d-none mt-2">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm w-100" onclick="_abrirAnexarFormulario()">
|
||||
<i class="fas fa-plus me-1"></i>Agregar formulario adicional
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Muestras (solo estaciones tipo muestras) ── -->
|
||||
@@ -1027,6 +1039,7 @@ let _tomaProgresivaActiva = false;
|
||||
let hayMuestrasPendientes = false;
|
||||
let _solicitudActiva = null;
|
||||
let _muestrasActivas = [];
|
||||
const _formulariosList = <?= json_encode($formulariosList, JSON_UNESCAPED_UNICODE) ?>;
|
||||
|
||||
const API = '<?= BASE_URL ?>modules/turnero/api/';
|
||||
const BASE_WA = '<?= BASE_URL ?>';
|
||||
@@ -1667,7 +1680,7 @@ async function _olvidarConsentimiento(token, nombre) {
|
||||
});
|
||||
const j = await r.json();
|
||||
if (!j.ok) { mostrarError(j.error || 'Error al resetear'); return; }
|
||||
cargarConsentimientos();
|
||||
if (turnoActivo?.id) actualizarConsentimientos(turnoActivo.id);
|
||||
} catch(e) { mostrarError(e.message); }
|
||||
}
|
||||
|
||||
@@ -2061,10 +2074,45 @@ function resetFicha() {
|
||||
document.getElementById('btn-regresar').classList.add('d-none');
|
||||
document.getElementById('btn-rellamar').classList.add('d-none');
|
||||
document.getElementById('btn-devolver').classList.add('d-none');
|
||||
document.getElementById('btn-anexar-wrap')?.classList.add('d-none');
|
||||
|
||||
volverACola();
|
||||
}
|
||||
|
||||
// ── Anexar formulario ─────────────────────────────────────────
|
||||
function _abrirAnexarFormulario() {
|
||||
const sel = document.getElementById('sel-anexar-form');
|
||||
sel.innerHTML = '<option value="">— Seleccionar formulario —</option>';
|
||||
_formulariosList.forEach(f => {
|
||||
const o = document.createElement('option');
|
||||
o.value = f.id; o.textContent = f.nombre;
|
||||
sel.appendChild(o);
|
||||
});
|
||||
document.getElementById('anexar-form-msg').style.display = 'none';
|
||||
document.getElementById('btn-guardar-anexar').disabled = false;
|
||||
document.getElementById('modal-anexar-form').style.display = 'flex';
|
||||
}
|
||||
function _cerrarAnexarFormulario() {
|
||||
document.getElementById('modal-anexar-form').style.display = 'none';
|
||||
}
|
||||
async function _guardarAnexarFormulario() {
|
||||
const fId = parseInt(document.getElementById('sel-anexar-form').value);
|
||||
const msg = document.getElementById('anexar-form-msg');
|
||||
if (!fId) { msg.textContent = 'Selecciona un formulario.'; msg.style.display=''; return; }
|
||||
const btn = document.getElementById('btn-guardar-anexar');
|
||||
btn.disabled = true;
|
||||
try {
|
||||
const r = await fetch('modules/turnero/api/anexar_formulario.php', {
|
||||
method: 'POST', headers: {'Content-Type':'application/json'},
|
||||
body: JSON.stringify({ turno_id: turnoActivo.id, formulario_id: fId })
|
||||
});
|
||||
const j = await r.json();
|
||||
if (!j.ok) { msg.textContent = j.error || 'Error al agregar.'; msg.style.display=''; btn.disabled=false; return; }
|
||||
_cerrarAnexarFormulario();
|
||||
actualizarConsentimientos(turnoActivo.id);
|
||||
} catch(e) { msg.textContent = e.message; msg.style.display=''; btn.disabled=false; }
|
||||
}
|
||||
|
||||
// ── Mobile ────────────────────────────────────────────────────
|
||||
function esMobile() { return window.innerWidth <= 680; }
|
||||
|
||||
@@ -2099,6 +2147,7 @@ function actualizarEstadoBadge(estado) {
|
||||
const btnDev = document.getElementById('btn-devolver');
|
||||
|
||||
const btnEsp = document.getElementById('btn-espera');
|
||||
const btnAnexar = document.getElementById('btn-anexar-wrap');
|
||||
if (estado === 'en_espera_lugar') {
|
||||
btnIni.classList.remove('d-none'); btnIni.disabled = false;
|
||||
btnFin.classList.add('d-none');
|
||||
@@ -2106,6 +2155,7 @@ function actualizarEstadoBadge(estado) {
|
||||
btnRellamar.classList.add('d-none');
|
||||
btnDev.classList.remove('d-none');
|
||||
if (btnEsp) btnEsp.classList.add('d-none');
|
||||
if (btnAnexar) btnAnexar.classList.add('d-none');
|
||||
} else if (estado === 'en_servicio') {
|
||||
btnIni.classList.add('d-none');
|
||||
btnFin.classList.remove('d-none');
|
||||
@@ -2114,6 +2164,7 @@ function actualizarEstadoBadge(estado) {
|
||||
btnDev.classList.remove('d-none');
|
||||
// btn-espera: solo si hay toma progresiva activa (sincronizado desde renderConsentimientos)
|
||||
if (btnEsp) btnEsp.classList.add('d-none');
|
||||
if (btnAnexar) btnAnexar.classList.remove('d-none');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2864,6 +2915,26 @@ function _renderEspecialidades(grupos) {
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- ── Modal: Anexar formulario ──────────────────────────────── -->
|
||||
<div id="modal-anexar-form" style="display:none;position:fixed;inset:0;z-index:9000;background:rgba(0,0,0,.5);align-items:center;justify-content:center;">
|
||||
<div style="background:var(--bs-body-bg,#fff);border-radius:10px;padding:1.25rem;width:min(380px,92vw);box-shadow:0 8px 32px rgba(0,0,0,.25)">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem;">
|
||||
<strong><i class="fas fa-file-plus me-2"></i>Agregar formulario adicional</strong>
|
||||
<button type="button" onclick="_cerrarAnexarFormulario()" style="background:none;border:none;font-size:1.2rem;cursor:pointer;opacity:.6">×</button>
|
||||
</div>
|
||||
<select id="sel-anexar-form" class="form-select mb-3">
|
||||
<option value="">— Seleccionar formulario —</option>
|
||||
</select>
|
||||
<div id="anexar-form-msg" class="small text-danger mb-2" style="display:none"></div>
|
||||
<div style="display:flex;gap:.5rem;justify-content:flex-end">
|
||||
<button type="button" class="btn btn-secondary btn-sm" onclick="_cerrarAnexarFormulario()">Cancelar</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="btn-guardar-anexar" onclick="_guardarAnexarFormulario()">
|
||||
<i class="fas fa-plus me-1"></i>Agregar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="<?= defined('APP_URL') ? rtrim(APP_URL,'/') : '' ?>/assets/js/lab-sidebar.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user