feat(turnero): selector de médico tratante en recepción, visible en toma de muestras
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
ec614c2a89
commit
d3826972ad
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE turnero_solicitudes
|
||||||
|
ADD COLUMN medico_id INT UNSIGNED DEFAULT NULL
|
||||||
|
COMMENT 'FK medicos.id — médico tratante seleccionado en recepción'
|
||||||
|
AFTER solo_muestras;
|
||||||
@@ -11,6 +11,7 @@ $pendientes = [
|
|||||||
'20260703_solo_muestras.sql',
|
'20260703_solo_muestras.sql',
|
||||||
'20260703_medicos.sql',
|
'20260703_medicos.sql',
|
||||||
'20260703_medicos_seed.sql',
|
'20260703_medicos_seed.sql',
|
||||||
|
'20260703_solicitud_medico.sql',
|
||||||
];
|
];
|
||||||
|
|
||||||
$pdo = Database::getInstance()->getConnection();
|
$pdo = Database::getInstance()->getConnection();
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ $obs = isset($datos['observaciones']) ? trim((string) $datos['observac
|
|||||||
$numOrden = isset($datos['numero_orden']) ? trim((string) $datos['numero_orden']) : null;
|
$numOrden = isset($datos['numero_orden']) ? trim((string) $datos['numero_orden']) : null;
|
||||||
$embarazada = !empty($datos['embarazada']) ? 1 : 0;
|
$embarazada = !empty($datos['embarazada']) ? 1 : 0;
|
||||||
$soloMuestras = !empty($datos['solo_muestras']) ? 1 : 0;
|
$soloMuestras = !empty($datos['solo_muestras']) ? 1 : 0;
|
||||||
|
$medicoId = !empty($datos['medico_id']) ? (int)$datos['medico_id'] : null;
|
||||||
$pagosDetalle = null;
|
$pagosDetalle = null;
|
||||||
if ($metodoPago === 'combinado' && isset($datos['pagos_detalle']) && is_array($datos['pagos_detalle'])) {
|
if ($metodoPago === 'combinado' && isset($datos['pagos_detalle']) && is_array($datos['pagos_detalle'])) {
|
||||||
$pd = $datos['pagos_detalle'];
|
$pd = $datos['pagos_detalle'];
|
||||||
@@ -114,12 +115,12 @@ try {
|
|||||||
|
|
||||||
$stmt = $pdo->prepare(
|
$stmt = $pdo->prepare(
|
||||||
"INSERT INTO turnero_solicitudes
|
"INSERT INTO turnero_solicitudes
|
||||||
(turno_id, paciente_id, lugar_id, numero_orden, total_cobrado, metodo_pago, pagos_detalle, observaciones, embarazada, solo_muestras, creado_por)
|
(turno_id, paciente_id, lugar_id, numero_orden, total_cobrado, metodo_pago, pagos_detalle, observaciones, embarazada, solo_muestras, medico_id, creado_por)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
||||||
);
|
);
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
$turnoId, $pacienteId, $lugarId, $numOrden,
|
$turnoId, $pacienteId, $lugarId, $numOrden,
|
||||||
$total, $metodoPago ?: null, $pagosDetalle, $obs ?: null, $embarazada, $soloMuestras, adminId(),
|
$total, $metodoPago ?: null, $pagosDetalle, $obs ?: null, $embarazada, $soloMuestras, $medicoId, adminId(),
|
||||||
]);
|
]);
|
||||||
$solicitudId = (int) $pdo->lastInsertId();
|
$solicitudId = (int) $pdo->lastInsertId();
|
||||||
|
|
||||||
|
|||||||
@@ -56,10 +56,14 @@ $respuesta = [
|
|||||||
if ($incluirSolicitud) {
|
if ($incluirSolicitud) {
|
||||||
$stmt = $pdo->prepare(
|
$stmt = $pdo->prepare(
|
||||||
"SELECT s.id, s.turno_id, s.paciente_id, s.lugar_id,
|
"SELECT s.id, s.turno_id, s.paciente_id, s.lugar_id,
|
||||||
s.total_cobrado, s.metodo_pago, s.observaciones, s.embarazada, s.creado_at,
|
s.total_cobrado, s.metodo_pago, s.observaciones, s.embarazada, s.solo_muestras, s.medico_id, s.creado_at,
|
||||||
l.nombre AS lugar_nombre
|
l.nombre AS lugar_nombre,
|
||||||
|
CONCAT(m.nombres, ' ', m.apellidos) AS medico_nombre,
|
||||||
|
m.cod_especialidad AS medico_especialidad,
|
||||||
|
m.codigo AS medico_codigo
|
||||||
FROM turnero_solicitudes s
|
FROM turnero_solicitudes s
|
||||||
LEFT JOIN turnero_lugares l ON l.id = s.lugar_id
|
LEFT JOIN turnero_lugares l ON l.id = s.lugar_id
|
||||||
|
LEFT JOIN medicos m ON m.id = s.medico_id
|
||||||
WHERE s.turno_id = ?
|
WHERE s.turno_id = ?
|
||||||
LIMIT 1"
|
LIMIT 1"
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -299,6 +299,12 @@ require_once __DIR__ . '/../../../shared/components/sidebar.php';
|
|||||||
<i class="fas fa-baby me-1"></i>Paciente embarazada
|
<i class="fas fa-baby me-1"></i>Paciente embarazada
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="pac-medico" class="d-none mt-2">
|
||||||
|
<div class="pac-dato">
|
||||||
|
<span class="lbl">Médico</span>
|
||||||
|
<span class="val" id="pac-medico-nombre" style="color:#4f46e5"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="bloque-pac-sin" class="text-muted small">
|
<div id="bloque-pac-sin" class="text-muted small">
|
||||||
<i class="fas fa-info-circle me-1"></i>Sin paciente vinculado
|
<i class="fas fa-info-circle me-1"></i>Sin paciente vinculado
|
||||||
@@ -610,6 +616,16 @@ async function cargarFichaSolicitud(turnoId) {
|
|||||||
const badgeEmb = document.getElementById('pac-embarazada');
|
const badgeEmb = document.getElementById('pac-embarazada');
|
||||||
if (badgeEmb) badgeEmb.classList.toggle('d-none', !(sol && sol.embarazada == 1));
|
if (badgeEmb) badgeEmb.classList.toggle('d-none', !(sol && sol.embarazada == 1));
|
||||||
|
|
||||||
|
const medDiv = document.getElementById('pac-medico');
|
||||||
|
if (medDiv) {
|
||||||
|
const tieneMedico = sol && sol.medico_nombre;
|
||||||
|
medDiv.classList.toggle('d-none', !tieneMedico);
|
||||||
|
if (tieneMedico) {
|
||||||
|
const esp = sol.medico_especialidad ? ' · ' + sol.medico_especialidad : '';
|
||||||
|
document.getElementById('pac-medico-nombre').textContent = sol.medico_nombre + esp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (pac) {
|
if (pac) {
|
||||||
document.getElementById('bloque-pac-info').style.display = '';
|
document.getElementById('bloque-pac-info').style.display = '';
|
||||||
document.getElementById('bloque-pac-sin').classList.add('d-none');
|
document.getElementById('bloque-pac-sin').classList.add('d-none');
|
||||||
|
|||||||
@@ -448,6 +448,27 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Médico tratante -->
|
||||||
|
<div class="mt-2" id="bloque-medico">
|
||||||
|
<div class="small fw-semibold text-secondary mb-1">
|
||||||
|
<i class="fas fa-user-md me-1"></i>Médico tratante <span class="text-muted fw-normal">(opcional)</span>
|
||||||
|
</div>
|
||||||
|
<div id="medico-seleccionado" class="d-none mb-1">
|
||||||
|
<span class="badge text-bg-light border" style="font-size:.8rem;padding:5px 9px" id="medico-badge-txt"></span>
|
||||||
|
<button type="button" class="btn btn-link btn-sm p-0 ms-1 text-danger" onclick="quitarMedico()" title="Quitar médico"><i class="fas fa-times"></i></button>
|
||||||
|
</div>
|
||||||
|
<div id="medico-buscador">
|
||||||
|
<input type="text" id="inp-buscar-medico" class="form-control form-control-sm"
|
||||||
|
placeholder="Buscar por nombre, código o doc…"
|
||||||
|
autocomplete="off" oninput="buscarMedico()">
|
||||||
|
<div id="medico-dropdown" class="position-relative">
|
||||||
|
<ul id="medico-resultados" class="list-unstyled mb-0 border rounded bg-white shadow-sm position-absolute w-100 d-none"
|
||||||
|
style="z-index:200;max-height:180px;overflow-y:auto;top:2px"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" id="inp-medico-id">
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Historial colapsable del paciente -->
|
<!-- Historial colapsable del paciente -->
|
||||||
<div id="sec-historial-pac" class="d-none">
|
<div id="sec-historial-pac" class="d-none">
|
||||||
<button class="hist-toggle-btn" id="btn-hist-toggle" onclick="toggleHistorialPaciente()">
|
<button class="hist-toggle-btn" id="btn-hist-toggle" onclick="toggleHistorialPaciente()">
|
||||||
@@ -1328,6 +1349,7 @@ async function guardarSolicitud() {
|
|||||||
observaciones: document.getElementById('inp-obs').value.trim() || null,
|
observaciones: document.getElementById('inp-obs').value.trim() || null,
|
||||||
embarazada: document.getElementById('chk-embarazada').checked ? 1 : 0,
|
embarazada: document.getElementById('chk-embarazada').checked ? 1 : 0,
|
||||||
solo_muestras: soloMuestras ? 1 : 0,
|
solo_muestras: soloMuestras ? 1 : 0,
|
||||||
|
medico_id: parseInt(document.getElementById('inp-medico-id').value) || null,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
@@ -1672,6 +1694,53 @@ async function soltarTurno() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Helpers ───────────────────────────────────────────────────
|
// ── Helpers ───────────────────────────────────────────────────
|
||||||
|
// ── Médico tratante ─────────────────────────────────────────────
|
||||||
|
let _medicoTimer = null;
|
||||||
|
const API_MEDICOS = '<?= BASE_URL ?>modules/medicos/api/list.php';
|
||||||
|
|
||||||
|
function buscarMedico() {
|
||||||
|
clearTimeout(_medicoTimer);
|
||||||
|
const q = document.getElementById('inp-buscar-medico').value.trim();
|
||||||
|
const ul = document.getElementById('medico-resultados');
|
||||||
|
if (q.length < 2) { ul.classList.add('d-none'); ul.innerHTML = ''; return; }
|
||||||
|
_medicoTimer = setTimeout(async () => {
|
||||||
|
const res = await fetch(API_MEDICOS + '?q=' + encodeURIComponent(q));
|
||||||
|
const json = await res.json();
|
||||||
|
const rows = (json.data || []).slice(0, 8);
|
||||||
|
if (!rows.length) { ul.innerHTML = '<li class="px-3 py-2 text-muted small">Sin resultados</li>'; ul.classList.remove('d-none'); return; }
|
||||||
|
ul.innerHTML = rows.map(m =>
|
||||||
|
`<li class="px-3 py-2 small" style="cursor:pointer;border-bottom:1px solid #f1f5f9"
|
||||||
|
onmousedown="seleccionarMedico(${m.id},'${escJs(m.codigo)}','${escJs(m.nombres)} ${escJs(m.apellidos)}','${escJs(m.cod_especialidad||'')}')">
|
||||||
|
<span class="fw-semibold">${esc(m.nombres)} ${esc(m.apellidos)}</span>
|
||||||
|
<span class="text-muted ms-1">[${esc(m.codigo)}]</span>
|
||||||
|
${m.cod_especialidad ? `<span class="badge text-bg-light ms-1" style="font-size:.7rem">${esc(m.cod_especialidad)}</span>` : ''}
|
||||||
|
</li>`
|
||||||
|
).join('');
|
||||||
|
ul.classList.remove('d-none');
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
function seleccionarMedico(id, codigo, nombre, esp) {
|
||||||
|
document.getElementById('inp-medico-id').value = id;
|
||||||
|
document.getElementById('medico-badge-txt').textContent = nombre + (esp ? ' · ' + esp : '') + ' [' + codigo + ']';
|
||||||
|
document.getElementById('medico-seleccionado').classList.remove('d-none');
|
||||||
|
document.getElementById('medico-buscador').classList.add('d-none');
|
||||||
|
document.getElementById('medico-resultados').classList.add('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
function quitarMedico() {
|
||||||
|
document.getElementById('inp-medico-id').value = '';
|
||||||
|
document.getElementById('medico-seleccionado').classList.add('d-none');
|
||||||
|
document.getElementById('medico-buscador').classList.remove('d-none');
|
||||||
|
document.getElementById('inp-buscar-medico').value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetMedico() {
|
||||||
|
quitarMedico();
|
||||||
|
}
|
||||||
|
|
||||||
|
function escJs(s) { return String(s||'').replace(/\\/g,'\\\\').replace(/'/g,"\\'"); }
|
||||||
|
|
||||||
function toggleSoloMuestras() {
|
function toggleSoloMuestras() {
|
||||||
const solo = document.getElementById('chk-solo-muestras').checked;
|
const solo = document.getElementById('chk-solo-muestras').checked;
|
||||||
document.querySelectorAll('.exam-chk').forEach(c => { c.checked = false; c.disabled = solo; });
|
document.querySelectorAll('.exam-chk').forEach(c => { c.checked = false; c.disabled = solo; });
|
||||||
@@ -1686,6 +1755,7 @@ function resetCheckboxes() {
|
|||||||
document.getElementById('inp-total').value = '';
|
document.getElementById('inp-total').value = '';
|
||||||
document.getElementById('inp-obs').value = '';
|
document.getElementById('inp-obs').value = '';
|
||||||
resetPagoCombinado();
|
resetPagoCombinado();
|
||||||
|
resetMedico();
|
||||||
}
|
}
|
||||||
function toggleTodosExamenes(val) {
|
function toggleTodosExamenes(val) {
|
||||||
document.querySelectorAll('.exam-chk').forEach(c => c.checked = val);
|
document.querySelectorAll('.exam-chk').forEach(c => c.checked = val);
|
||||||
|
|||||||
Reference in New Issue
Block a user