feat: autocomplete CIE-10 en diagnóstico y fix tab en exámenes

- buscar_cie10.php: busca por código o descripción, límite 12 resultados
- inp-diag: dropdown estilo empresa, Enter selecciona primero
- selectOnTab:false en TomSelect de exámenes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-17 15:13:48 -05:00
co-authored by Claude Sonnet 4.6
parent 4fdc8e2c13
commit c717d474f7
2 changed files with 63 additions and 2 deletions
+22
View File
@@ -0,0 +1,22 @@
<?php
require_once __DIR__ . '/_helpers.php';
requireMethod('GET');
requireTurnero();
$q = trim($_GET['q'] ?? '');
if (strlen($q) < 2) { jsonOk(['items' => []]); }
$pdo = db();
$like = '%' . $q . '%';
// Código exacto primero, luego coincidencias por descripción
$stmt = $pdo->prepare(
"SELECT cod_diag, concepto
FROM cie10_diagnosticos
WHERE cod_diag LIKE ? OR concepto LIKE ?
ORDER BY CASE WHEN cod_diag LIKE ? THEN 0 ELSE 1 END, cod_diag
LIMIT 12"
);
$stmt->execute([$like, $like, $like]);
jsonOk(['items' => $stmt->fetchAll(PDO::FETCH_ASSOC)]);
+41 -2
View File
@@ -796,7 +796,15 @@ document.addEventListener('DOMContentLoaded', function() {
<div id="wrap-diag" class="d-none mt-2">
<label class="form-label mb-1 small fw-semibold">Diagnóstico (CIE-10)</label>
<input type="text" id="inp-diag" class="form-control form-control-sm"
placeholder="Código CIE-10 diagnóstico principal" maxlength="20">
placeholder="Código o descripción CIE-10…"
autocomplete="off"
oninput="buscarDiag()"
onblur="setTimeout(()=>document.getElementById('diag-resultados').classList.add('d-none'),150)"
onkeydown="if(event.key==='Enter'&&_diagResultados.length){event.preventDefault();seleccionarDiag(_diagResultados[0].cod_diag,_diagResultados[0].concepto);}">
<div class="position-relative">
<ul id="diag-resultados" class="list-unstyled mb-0 border rounded bg-white shadow-sm position-absolute w-100 d-none"
style="z-index:200;max-height:200px;overflow-y:auto;top:2px"></ul>
</div>
</div>
<!-- Tabla de precios calculados -->
@@ -1133,7 +1141,7 @@ document.addEventListener('DOMContentLoaded', () => {
examTS = new TomSelect('#sel-examenes', {
plugins: ['remove_button'],
maxOptions: null,
selectOnTab: true,
selectOnTab: false,
onItemAdd() { recalcularPrecios(); examTS.setTextboxValue(''); examTS.refreshOptions(false); },
onItemRemove: () => recalcularPrecios(),
@@ -2355,6 +2363,37 @@ function quitarEmpresa() {
document.getElementById('inp-diag').value = '';
}
// ── CIE-10 autocomplete ───────────────────────────────────────
let _diagTimer = null, _diagResultados = [];
function buscarDiag() {
clearTimeout(_diagTimer);
_diagTimer = setTimeout(_doDiagSearch, 250);
}
async function _doDiagSearch() {
const q = document.getElementById('inp-diag').value.trim();
const ul = document.getElementById('diag-resultados');
if (q.length < 2) { ul.classList.add('d-none'); return; }
const res = await fetch(`${API}buscar_cie10.php?q=${encodeURIComponent(q)}`);
const j = await res.json();
_diagResultados = j.items || [];
if (!_diagResultados.length) {
ul.innerHTML = '<li class="px-3 py-2 text-muted small">Sin resultados</li>';
ul.classList.remove('d-none'); return;
}
ul.innerHTML = _diagResultados.map((d, i) => `
<li class="px-3 py-2" style="cursor:pointer;border-bottom:1px solid #f1f5f9"
onmousedown="seleccionarDiag(${JSON.stringify(d.cod_diag)},${JSON.stringify(d.concepto)})">
<span class="fw-semibold small">${escHtml(d.cod_diag)}</span>
<span class="text-muted small ms-2">${escHtml(d.concepto)}</span>
</li>`).join('');
ul.classList.remove('d-none');
}
function seleccionarDiag(cod, concepto) {
document.getElementById('inp-diag').value = cod;
document.getElementById('diag-resultados').classList.add('d-none');
_diagResultados = [];
}
// ── Motor de precios ──────────────────────────────────────────
let _recalcTimer;
let _preciosActivos = [];