fix: 5 bugs en modal de tomas progresivas F-LAB-28
- Fix 1: countdown se recupera al reabrir el modal (lee siguiente_toma_at de BD)
- Fix 2: _mpIniciarCountdown recibe timestamp exacto en vez de minutos redondeados
- Fix 3: window._fpwPreFirma se emite una sola vez (no N veces por campo firma)
- Fix 4: postMessage('turneroFirmado') unificado a 2000ms en todos los paths
- Fix 5: resumen de tomas usa hora cacheada al guardar; elimina traversal DOM frágil
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
388f6ff7c9
commit
34a0ae2c35
+46
-29
@@ -31,6 +31,7 @@ if ($modoTurnero) {
|
||||
"SELECT tc.id, tc.turno_id, tc.formulario_id, tc.token, tc.estado,
|
||||
tc.enviado_at, tc.firmado_at, tc.ip_firma, tc.ua_firma, tc.firma_svg,
|
||||
tc.firma_profesional_svg, tc.firmado_profesional_at, tc.datos_respuestas,
|
||||
tc.siguiente_toma_at, tc.toma_inicio_at,
|
||||
f.nombre AS form_nombre, f.categoria, f.descripcion AS form_descripcion,
|
||||
f.esquema, f.es_toma_progresiva, f.doc_encabezado, f.doc_subtitulo, f.doc_logo_base64, f.doc_color, f.doc_pie_pagina,
|
||||
p.nombre_completo AS paciente_nombre,
|
||||
@@ -321,6 +322,7 @@ if ($modoTurnero && $embebido && $_soloFirmaPro) {
|
||||
for ($i = 0, $n = count($_secs); $i < $n; $i++) {
|
||||
$_s = $_secs[$i]; $_nx = $_secs[$i + 1] ?? null;
|
||||
$_mpMap[$_s['firma']] = [
|
||||
'label' => $_s['label'],
|
||||
'hora_campo' => $_s['hora'],
|
||||
'next_label' => $_nx ? $_nx['label'] : null,
|
||||
'next_firma_id' => $_nx ? $_nx['firma'] : null,
|
||||
@@ -342,6 +344,15 @@ if (!empty($_mpMap)) {
|
||||
}
|
||||
}
|
||||
|
||||
// siguiente_toma_at para recuperar countdown si el modal fue cerrado y reabierto
|
||||
$_mpSiguienteTomAt = null;
|
||||
if ($modoTurnero && $embebido && !empty($_mpMap) && $_mpPrimeraPendiente !== null) {
|
||||
$raw = $tcRow['siguiente_toma_at'] ?? null;
|
||||
if ($raw && $raw > date('Y-m-d H:i:s')) {
|
||||
$_mpSiguienteTomAt = $raw;
|
||||
}
|
||||
}
|
||||
|
||||
// Mapa id → label
|
||||
$labelMap = [];
|
||||
foreach ($esquema as $c) {
|
||||
@@ -880,9 +891,6 @@ function _addExamWizardHtml(string $cid): string {
|
||||
($modoTurnero && $embebido && isUserLoggedIn())
|
||||
);
|
||||
if ($_mostrarCanvasPro): ?>
|
||||
<?php if ($firmaProfPreguardada): ?>
|
||||
<script>window._fpwPreFirma = <?= json_encode($firmaProfPreguardada) ?>;</script>
|
||||
<?php endif; ?>
|
||||
<!-- Canvas del profesional -->
|
||||
<?php
|
||||
$_mpBloqueado = !empty($_mpMap)
|
||||
@@ -1506,8 +1514,9 @@ function aewSave(cid) {
|
||||
} catch(e) {}
|
||||
})();
|
||||
|
||||
window._muestrasMap = <?= json_encode($_mpMap, JSON_UNESCAPED_UNICODE) ?>;
|
||||
window._muestrasMap = <?= json_encode($_mpMap, JSON_UNESCAPED_UNICODE) ?>;
|
||||
window._mpSavedFirmas = {};
|
||||
window._mpTomaData = {};
|
||||
|
||||
function _mpAutoFillHora(firmaId) {
|
||||
var entry = window._muestrasMap && window._muestrasMap[firmaId];
|
||||
@@ -1529,6 +1538,19 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}, 350);
|
||||
});
|
||||
<?php endif; ?>
|
||||
window._fpwPreFirma = <?= json_encode($firmaProfPreguardada) ?>;
|
||||
<?php if (!empty($_mpSiguienteTomAt)): ?>
|
||||
// Fix 1: recuperar countdown si el modal fue cerrado y reabierto mientras una toma estaba en curso
|
||||
(function() {
|
||||
var targetMs = new Date('<?= str_replace(' ', 'T', $_mpSiguienteTomAt) ?>').getTime();
|
||||
if (targetMs <= Date.now()) return;
|
||||
var pendingId = <?= json_encode($_mpPrimeraPendiente) ?>;
|
||||
var entry = window._muestrasMap && window._muestrasMap[pendingId];
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
_mpIniciarCountdown(targetMs, entry ? (entry.label || null) : null, pendingId);
|
||||
});
|
||||
})();
|
||||
<?php endif; ?>
|
||||
/* ── Firma del profesional: función compartida canvas/1-clic ────── */
|
||||
function _guardarFirmaPro(widget, svg, msgEl) {
|
||||
const turnoId = widget.dataset.turno;
|
||||
@@ -1605,6 +1627,10 @@ function _guardarFirmaMP(widget, svg, msgEl, entry, campoId) {
|
||||
// Guardar con campoId directo (sin _svg) para que get_consentimientos lo cuente
|
||||
dr[campoId] = svg;
|
||||
(window._mpSavedFirmas = window._mpSavedFirmas||{})[campoId] = svg;
|
||||
// Fix 5: cachear hora en el momento de guardar para el resumen final
|
||||
(window._mpTomaData = window._mpTomaData||{})[campoId] = {
|
||||
hora: entry.hora_campo ? (dr[entry.hora_campo] || '') : ''
|
||||
};
|
||||
|
||||
var turnoId = parseInt(widget.dataset.turno, 10);
|
||||
var formularioId = parseInt(widget.dataset.formulario, 10);
|
||||
@@ -1644,11 +1670,11 @@ function _guardarFirmaMP(widget, svg, msgEl, entry, campoId) {
|
||||
_mpMostrarResumen(entry.exam_type || 'Examen');
|
||||
setTimeout(function() {
|
||||
try { window.parent.postMessage({ type: 'turneroFirmado' }, '*'); } catch(e) {}
|
||||
}, 2200);
|
||||
}, 2000);
|
||||
} else if (data.siguiente_toma_at) {
|
||||
// Fix 2: pasar timestamp exacto; evita el redondeo de Math.round
|
||||
var targetMs = new Date(data.siguiente_toma_at.replace(' ', 'T')).getTime();
|
||||
var minsLeft = Math.max(1, Math.round((targetMs - Date.now()) / 60000));
|
||||
_mpIniciarCountdown(minsLeft, entry.next_label, entry.next_firma_id);
|
||||
_mpIniciarCountdown(targetMs, entry.next_label, entry.next_firma_id);
|
||||
} else if (!entry.is_last) {
|
||||
var nw = entry.next_firma_id ? document.getElementById('fpw-' + entry.next_firma_id) : null;
|
||||
if (!nw) nw = document.querySelector('.firma-pro-widget:not([style*="display:none"])');
|
||||
@@ -1662,9 +1688,10 @@ function _guardarFirmaMP(widget, svg, msgEl, entry, campoId) {
|
||||
_mpAutoFillHora(nw.dataset.campo);
|
||||
} else {
|
||||
// Sin más firmas pendientes → cerrar
|
||||
// Fix 4: unificar delay con el caso data.completado (ambos 2000ms)
|
||||
setTimeout(function() {
|
||||
try { window.parent.postMessage({ type: 'turneroFirmado' }, '*'); } catch(e) {}
|
||||
}, 1200);
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1688,8 +1715,9 @@ function _mpPlayBeep() {
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
function _mpIniciarCountdown(minutos, nextLabel, nextFirmaId) {
|
||||
var targetMs = Date.now() + minutos * 60000;
|
||||
// Fix 2: acepta timestamp (ms > 1e10) o minutos (número pequeño)
|
||||
function _mpIniciarCountdown(targetMsOrMins, nextLabel, nextFirmaId) {
|
||||
var targetMs = targetMsOrMins > 1e10 ? targetMsOrMins : Date.now() + targetMsOrMins * 60000;
|
||||
var box = document.getElementById('mp-countdown');
|
||||
if (!box) {
|
||||
box = document.createElement('div');
|
||||
@@ -1747,24 +1775,14 @@ function _mpMostrarResumen(examType) {
|
||||
Object.keys(window._muestrasMap).forEach(function(fid) {
|
||||
var entry = window._muestrasMap[fid];
|
||||
if (!entry || entry.exam_type !== examType) return;
|
||||
var horaEl = entry.hora_campo ? document.querySelector('[name="' + entry.hora_campo + '"]') : null;
|
||||
var horaVal = horaEl ? horaEl.value : '';
|
||||
// Buscar campo resultado adyacente (previo al firma widget)
|
||||
var fpw = document.getElementById('fpw-' + fid);
|
||||
var resVal = '';
|
||||
if (fpw) {
|
||||
var prev = fpw.previousElementSibling;
|
||||
while (prev) {
|
||||
var inp = prev.querySelector && prev.querySelector('input[type="number"],input[type="text"]');
|
||||
if (inp) { resVal = inp.value; break; }
|
||||
prev = prev.previousElementSibling;
|
||||
}
|
||||
// Fix 5: usar hora cacheada al momento de guardar; evita traversal DOM frágil
|
||||
var cached = window._mpTomaData && window._mpTomaData[fid];
|
||||
var horaVal = (cached && cached.hora) || '';
|
||||
if (!horaVal && entry.hora_campo) {
|
||||
var horaEl = document.querySelector('[name="' + entry.hora_campo + '"]');
|
||||
horaVal = horaEl ? horaEl.value : '';
|
||||
}
|
||||
// Separador label para esta firma
|
||||
var secLabel = entry.next_label || ('Toma ' + fid);
|
||||
// Si tiene next_label del ANTERIOR, buscamos la label de esta entrada en el DOM
|
||||
var sepEl = document.querySelector('[data-campo-id]');
|
||||
rows.push({ hora: horaVal, resultado: resVal, firmado: !!(window._mpSavedFirmas && window._mpSavedFirmas[fid]) });
|
||||
rows.push({ hora: horaVal, firmado: !!(window._mpSavedFirmas && window._mpSavedFirmas[fid]) });
|
||||
});
|
||||
}
|
||||
var wrap = document.createElement('div');
|
||||
@@ -1772,10 +1790,9 @@ function _mpMostrarResumen(examType) {
|
||||
wrap.className = 'alert alert-success mt-4';
|
||||
var rowsHtml = rows.length
|
||||
? '<table class="table table-sm mt-2 mb-0" style="font-size:.82rem"><thead><tr>'
|
||||
+ '<th>Hora</th><th>Resultado</th><th></th></tr></thead><tbody>'
|
||||
+ '<th>Hora</th><th></th></tr></thead><tbody>'
|
||||
+ rows.map(function(r) {
|
||||
return '<tr><td>' + (r.hora || '—') + '</td>'
|
||||
+ '<td>' + (r.resultado || '—') + '</td>'
|
||||
+ '<td style="color:#198754"><i class="fas fa-check-circle"></i></td></tr>';
|
||||
}).join('') + '</tbody></table>' : '';
|
||||
wrap.innerHTML = '<div class="d-flex align-items-center gap-2"><i class="fas fa-check-double fs-5"></i>'
|
||||
|
||||
Reference in New Issue
Block a user