Tomas: panel de ciclos dinámico activado al seleccionar tipo de examen
- Panel ya no se renderiza server-side, sino que JS lo muestra al instante cuando el usuario selecciona un tipo de examen del selector _c8j2g16 - _mpGetGroupsForExam() filtra los grupos correspondientes al examen elegido - Si solo hay 1 toma por grupo, auto-guarda sin mostrar panel - Si al cargar ya hay examen seleccionado y sin _tomas_config, muestra panel - configurar_tomas.php: guarda también _c8j2g16 (exam_type) en datos_respuestas Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
f0fb0c7492
commit
da2b67589e
@@ -11,9 +11,10 @@
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('POST');
|
||||
|
||||
$body = inputJson();
|
||||
$token = trim($body['token'] ?? '');
|
||||
$cfg = $body['tomas_config'] ?? null;
|
||||
$body = inputJson();
|
||||
$token = trim($body['token'] ?? '');
|
||||
$cfg = $body['tomas_config'] ?? null;
|
||||
$examType = trim($body['exam_type'] ?? '');
|
||||
|
||||
if (!$token) jsonError('token requerido.');
|
||||
if (!is_array($cfg) || empty($cfg)) jsonError('tomas_config requerido.');
|
||||
@@ -40,6 +41,7 @@ if ($tc['datos_respuestas']) {
|
||||
}
|
||||
|
||||
$dr['_tomas_config'] = $cfg;
|
||||
if ($examType !== '') $dr['_c8j2g16'] = $examType;
|
||||
|
||||
$pdo->prepare("UPDATE turnero_consentimientos SET datos_respuestas = ? WHERE id = ?")
|
||||
->execute([json_encode($dr, JSON_UNESCAPED_UNICODE), $tc['id']]);
|
||||
|
||||
+115
-107
@@ -685,40 +685,17 @@ function _addExamWizardHtml(string $cid): string {
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// ── Panel de configuración de ciclos (se muestra antes de iniciar el protocolo) ──
|
||||
// Datos para el panel de ciclos dinámico (renderizado por JS al seleccionar examen)
|
||||
$_examOptions = [];
|
||||
foreach ($esquema as $_oc) {
|
||||
if (($_oc['id'] ?? '') === '_c8j2g16') { $_examOptions = $_oc['options'] ?? []; break; }
|
||||
}
|
||||
$_examSel = (array)($datosCliente['_c8j2g16'] ?? []);
|
||||
$_gruposConfig = [];
|
||||
foreach ($_mpGroupsFull as $_gk => $_gsecs) {
|
||||
if (empty($_gsecs)) continue;
|
||||
$__parts = array_values(array_filter(explode('|', $_gk)));
|
||||
$__isCond = !empty(array_intersect($__parts, $_examOptions));
|
||||
$__matchSel = !empty(array_intersect($__parts, $_examSel));
|
||||
if (!$__isCond || $__matchSel) {
|
||||
$__title = implode(' / ', array_intersect($__parts, $_examSel));
|
||||
if (!$__title) $__title = $_gsecs[0]['display'] ?? $_gk;
|
||||
$_gruposConfig[$_gk] = ['title' => $__title, 'secs' => $_gsecs];
|
||||
}
|
||||
}
|
||||
// Mostrar panel solo si al menos un grupo tiene >= 2 tomas (hay algo que configurar).
|
||||
// Si todos los grupos tienen 1 sola toma, el JS auto-guarda la config sin preguntar.
|
||||
$_hasMulTomas = array_reduce($_gruposConfig, fn($c, $g) => $c || count($g['secs']) >= 2, false);
|
||||
$_showCfgPanel = $modoTurnero && $embebido && !empty($_gruposConfig) && $_tomasConfig === null && $_hasMulTomas;
|
||||
$_autoSaveCfg = $modoTurnero && $embebido && !empty($_gruposConfig) && $_tomasConfig === null && !$_hasMulTomas;
|
||||
// Config por defecto (todas las tomas) — usada tanto por auto-save como por "Usar todas"
|
||||
$_cfgDefault = [];
|
||||
foreach ($_gruposConfig as $_cgk => $_cg) {
|
||||
$_cfgDefault[$_cgk] = array_column($_cg['secs'], 'firma');
|
||||
}
|
||||
?>
|
||||
<?php if ($_showCfgPanel): ?>
|
||||
<div class="mp-cfg-overlay" id="mp-cfg-overlay">
|
||||
<!-- Panel de ciclos — renderizado dinámicamente por JS al seleccionar tipo de examen -->
|
||||
<div class="mp-cfg-overlay d-none" id="mp-cfg-overlay">
|
||||
<div class="mp-cfg-card">
|
||||
<div class="mp-cfg-head d-flex align-items-center justify-content-between">
|
||||
<span><i class="fas fa-sliders-h me-2"></i>Configurar protocolo de tomas</span>
|
||||
<span id="mp-cfg-title"><i class="fas fa-sliders-h me-2"></i>Configurar protocolo de tomas</span>
|
||||
<button id="mp-cfg-todas" type="button"
|
||||
title="Usar todas las tomas sin configurar"
|
||||
style="background:rgba(255,255,255,.2);border:none;color:#fff;border-radius:6px;
|
||||
@@ -730,27 +707,7 @@ function _addExamWizardHtml(string $cid): string {
|
||||
<p class="text-muted small mb-3">
|
||||
Seleccione las tomas a realizar. Desmárquelas si el médico indicó un protocolo reducido.
|
||||
</p>
|
||||
<?php foreach ($_gruposConfig as $_cgk => $_cg): ?>
|
||||
<div class="mb-3">
|
||||
<div class="mp-cfg-gtitle"><?= esc2($_cg['title']) ?></div>
|
||||
<div class="row g-2">
|
||||
<?php foreach ($_cg['secs'] as $_cs): ?>
|
||||
<div class="col-6 col-sm-4">
|
||||
<div class="mp-cfg-item form-check">
|
||||
<input class="form-check-input mp-cfg-chk" type="checkbox"
|
||||
id="cfg-<?= esc2($_cs['firma']) ?>"
|
||||
value="<?= esc2($_cs['firma']) ?>"
|
||||
data-group="<?= esc2($_cgk) ?>"
|
||||
checked>
|
||||
<label class="form-check-label small" for="cfg-<?= esc2($_cs['firma']) ?>">
|
||||
<?= esc2($_cs['label']) ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<div id="mp-cfg-grupos"></div>
|
||||
</div>
|
||||
<div class="mp-cfg-foot">
|
||||
<button class="btn btn-success btn-lg w-100" id="mp-cfg-iniciar">
|
||||
@@ -760,7 +717,6 @@ function _addExamWizardHtml(string $cid): string {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="doc-body">
|
||||
|
||||
@@ -1266,79 +1222,131 @@ function _addExamWizardHtml(string $cid): string {
|
||||
|
||||
<script>
|
||||
<?php if (!empty($_mpMap)): ?>
|
||||
/* ── Panel configuración de ciclos + auto-save ── */
|
||||
<?php if (($_showCfgPanel || $_autoSaveCfg) ?? false): ?>
|
||||
var _mpCfgDefault = <?= json_encode($_cfgDefault, JSON_UNESCAPED_UNICODE) ?>;
|
||||
var _mpCfgToken = <?= json_encode($tokenTurnero) ?>;
|
||||
/* ── Panel de ciclos dinámico ── */
|
||||
var _mpAllGroups = <?= json_encode($_mpGroupsFull, JSON_UNESCAPED_UNICODE) ?>;
|
||||
var _mpExamOptions = <?= json_encode($_examOptions, JSON_UNESCAPED_UNICODE) ?>;
|
||||
var _mpTomasConfig = <?= json_encode($_tomasConfig, JSON_UNESCAPED_UNICODE) ?>;
|
||||
var _mpCfgToken = <?= json_encode($tokenTurnero, JSON_UNESCAPED_UNICODE) ?>;
|
||||
var _mpModoTurnero = <?= json_encode($modoTurnero && $embebido) ?>;
|
||||
|
||||
function _mpGuardarConfig(config, onOk, onErr) {
|
||||
function _mpGuardarConfig(config, examType, onOk, onErr) {
|
||||
var base = window.location.href.split('/ver_formulario_enviado.php')[0];
|
||||
fetch(base + '/modules/turnero/api/configurar_tomas.php', {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ token: _mpCfgToken, tomas_config: config })
|
||||
body: JSON.stringify({ token: _mpCfgToken, tomas_config: config, exam_type: examType })
|
||||
})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(d) { d.ok ? onOk() : onErr(d.error || 'Error desconocido'); })
|
||||
.catch(function() { onErr('Error de conexión.'); });
|
||||
}
|
||||
|
||||
<?php if ($_autoSaveCfg ?? false): ?>
|
||||
// Todos los grupos tienen una sola toma → guardar config default sin mostrar panel
|
||||
function _mpShowCfgPanel(examName, groups) {
|
||||
// Construir checkboxes
|
||||
var html = '';
|
||||
for (var gk in groups) {
|
||||
var secs = groups[gk];
|
||||
var title = secs[0] ? (secs[0].display || gk) : gk;
|
||||
html += '<div class="mb-3"><div class="mp-cfg-gtitle">' + title + '</div><div class="row g-2">';
|
||||
for (var i = 0; i < secs.length; i++) {
|
||||
var s = secs[i];
|
||||
html += '<div class="col-6 col-sm-4"><div class="mp-cfg-item form-check">'
|
||||
+ '<input class="form-check-input mp-cfg-chk" type="checkbox"'
|
||||
+ ' id="cfg-' + s.firma + '" value="' + s.firma + '" data-group="' + gk + '" checked>'
|
||||
+ '<label class="form-check-label small" for="cfg-' + s.firma + '">'
|
||||
+ (s.label || ('Toma ' + (i+1))) + '</label>'
|
||||
+ '</div></div>';
|
||||
}
|
||||
html += '</div></div>';
|
||||
}
|
||||
document.getElementById('mp-cfg-grupos').innerHTML = html;
|
||||
document.getElementById('mp-cfg-title').innerHTML =
|
||||
'<i class="fas fa-sliders-h me-2"></i>' + examName;
|
||||
|
||||
// Si solo hay 1 toma por grupo, auto-guardar sin mostrar panel
|
||||
var hasMul = Object.keys(groups).some(function(k) { return groups[k].length >= 2; });
|
||||
if (!hasMul) {
|
||||
var cfg = {};
|
||||
for (var gk in groups) cfg[gk] = groups[gk].map(function(s){return s.firma;});
|
||||
_mpGuardarConfig(cfg, examName, function() { location.reload(); }, function(e) {
|
||||
console.warn('mp-cfg auto:', e);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('mp-cfg-overlay').classList.remove('d-none');
|
||||
}
|
||||
|
||||
function _mpGetGroupsForExam(examName) {
|
||||
var result = {};
|
||||
for (var gk in _mpAllGroups) {
|
||||
var parts = gk.split('|').filter(Boolean);
|
||||
var isCond = parts.some(function(p) { return _mpExamOptions.indexOf(p) !== -1; });
|
||||
if (!isCond || parts.indexOf(examName) !== -1) {
|
||||
result[gk] = _mpAllGroups[gk];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Escuchar selección de tipo de examen
|
||||
document.addEventListener('change', function(e) {
|
||||
if (!_mpModoTurnero) return;
|
||||
if (_mpTomasConfig !== null) return; // ya configurado
|
||||
var el = e.target;
|
||||
if (el.type !== 'radio' || el.name !== '_c8j2g16') return;
|
||||
var examName = el.value;
|
||||
var groups = _mpGetGroupsForExam(examName);
|
||||
if (!Object.keys(groups).length) return;
|
||||
_mpShowCfgPanel(examName, groups);
|
||||
});
|
||||
|
||||
// Si al cargar ya hay examen seleccionado pero sin _tomas_config → mostrar panel
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
_mpGuardarConfig(_mpCfgDefault, function() { location.reload(); }, function(e) {
|
||||
console.warn('mp-cfg auto-save:', e);
|
||||
if (!_mpModoTurnero || _mpTomasConfig !== null) return;
|
||||
var radio = document.querySelector('[name="_c8j2g16"]:checked');
|
||||
if (!radio) return;
|
||||
var groups = _mpGetGroupsForExam(radio.value);
|
||||
if (Object.keys(groups).length) _mpShowCfgPanel(radio.value, groups);
|
||||
});
|
||||
|
||||
// Botón "Usar todas"
|
||||
document.getElementById('mp-cfg-todas').addEventListener('click', function() {
|
||||
var examName = (document.querySelector('[name="_c8j2g16"]:checked') || {}).value || '';
|
||||
var cfg = {};
|
||||
document.querySelectorAll('.mp-cfg-chk').forEach(function(chk) {
|
||||
if (!cfg[chk.dataset.group]) cfg[chk.dataset.group] = [];
|
||||
cfg[chk.dataset.group].push(chk.value);
|
||||
});
|
||||
var btn = this;
|
||||
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Guardando...';
|
||||
_mpGuardarConfig(cfg, examName, function() { location.reload(); }, function(e) {
|
||||
document.getElementById('mp-cfg-msg').innerHTML = '<span class="text-danger">' + e + '</span>';
|
||||
btn.disabled = false; btn.innerHTML = '<i class="fas fa-forward me-1"></i>Usar todas';
|
||||
});
|
||||
});
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($_showCfgPanel ?? false): ?>
|
||||
(function() {
|
||||
function showMsg(msg) {
|
||||
var el = document.getElementById('mp-cfg-msg');
|
||||
if (el) el.innerHTML = '<span class="text-danger"><i class="fas fa-exclamation-circle me-1"></i>' + msg + '</span>';
|
||||
// Botón "Iniciar protocolo"
|
||||
document.getElementById('mp-cfg-iniciar').addEventListener('click', function() {
|
||||
var examName = (document.querySelector('[name="_c8j2g16"]:checked') || {}).value || '';
|
||||
var byGroup = {};
|
||||
document.querySelectorAll('.mp-cfg-chk').forEach(function(chk) {
|
||||
if (!byGroup[chk.dataset.group]) byGroup[chk.dataset.group] = [];
|
||||
if (chk.checked) byGroup[chk.dataset.group].push(chk.value);
|
||||
});
|
||||
for (var g in byGroup) {
|
||||
if (!byGroup[g].length) {
|
||||
document.getElementById('mp-cfg-msg').innerHTML =
|
||||
'<span class="text-danger"><i class="fas fa-exclamation-circle me-1"></i>Seleccione al menos una toma por protocolo.</span>';
|
||||
return;
|
||||
}
|
||||
}
|
||||
function setBtnLoading(btn) {
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Guardando...';
|
||||
}
|
||||
|
||||
// Botón "Usar todas" → guarda config default y recarga
|
||||
var btnTodas = document.getElementById('mp-cfg-todas');
|
||||
if (btnTodas) {
|
||||
btnTodas.addEventListener('click', function() {
|
||||
setBtnLoading(this);
|
||||
_mpGuardarConfig(_mpCfgDefault, function() { location.reload(); }, function(e) {
|
||||
showMsg(e);
|
||||
btnTodas.disabled = false;
|
||||
btnTodas.innerHTML = '<i class="fas fa-forward me-1"></i>Usar todas';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Botón "Iniciar protocolo" → lee selección actual
|
||||
var btnIniciar = document.getElementById('mp-cfg-iniciar');
|
||||
if (btnIniciar) {
|
||||
btnIniciar.addEventListener('click', function() {
|
||||
var byGroup = {};
|
||||
document.querySelectorAll('.mp-cfg-chk').forEach(function(chk) {
|
||||
var g = chk.dataset.group;
|
||||
if (!byGroup[g]) byGroup[g] = [];
|
||||
if (chk.checked) byGroup[g].push(chk.value);
|
||||
});
|
||||
for (var g in byGroup) {
|
||||
if (!byGroup[g].length) { showMsg('Seleccione al menos una toma por protocolo.'); return; }
|
||||
}
|
||||
setBtnLoading(this);
|
||||
_mpGuardarConfig(byGroup, function() { location.reload(); }, function(e) {
|
||||
showMsg(e);
|
||||
btnIniciar.disabled = false;
|
||||
btnIniciar.innerHTML = '<i class="fas fa-play-circle me-2"></i>Iniciar protocolo';
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
var btn = this;
|
||||
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Guardando...';
|
||||
_mpGuardarConfig(byGroup, examName, function() { location.reload(); }, function(e) {
|
||||
document.getElementById('mp-cfg-msg').innerHTML = '<span class="text-danger">' + e + '</span>';
|
||||
btn.disabled = false; btn.innerHTML = '<i class="fas fa-play-circle me-2"></i>Iniciar protocolo';
|
||||
});
|
||||
});
|
||||
/* ── Wizard: añadir tipo de examen ── */
|
||||
var _aewState = {}; // {cid: {count, rows}}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user