refactor(formularios): split 'calculado' into two direct field types
Instead of one field with a sub-option, there are now two independent palette items under a 'Calculados' section: - fecha_hoy: renders type=date pre-filled with today's date (YYYY-MM-DD) - edad: renders type=number pre-filled with age calculated from paciente.fecha_nacimiento Both are editable by the patient and have a yellow tint. Preview in the builder also shows the live date value for fecha_hoy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
f8245b4d6f
commit
e1f0fe3450
+11
-10
@@ -555,16 +555,21 @@ function renderCampos(esquema, prefilled) {
|
||||
<label class="form-check-label">${esc(o)}</label>
|
||||
</div>`).join('');
|
||||
html += wrapOpen + `<div class="mb-3">${lbl}${opts}${linkedNote}</div>` + wrapClose;
|
||||
} else if (c.tipo === 'calculado') {
|
||||
// Pre-calcular valor según sub-tipo
|
||||
} else if (c.tipo === 'fecha_hoy') {
|
||||
let calcVal = pad[c.id] || '';
|
||||
if (!calcVal) {
|
||||
if ((c.calc_tipo || 'fecha_hoy') === 'fecha_hoy') {
|
||||
const now = new Date();
|
||||
calcVal = now.getFullYear() + '-'
|
||||
+ String(now.getMonth()+1).padStart(2,'0') + '-'
|
||||
+ String(now.getDate()).padStart(2,'0');
|
||||
} else if (c.calc_tipo === 'edad') {
|
||||
}
|
||||
html += wrapOpen + `<div class="mb-3">${lbl}
|
||||
<input type="date" class="form-control" style="background:#fff9e6;border-color:#ffc107"
|
||||
name="${c.id}" value="${esc(calcVal)}" ${req}>
|
||||
</div>` + wrapClose;
|
||||
} else if (c.tipo === 'edad') {
|
||||
let calcVal = pad[c.id] || '';
|
||||
if (!calcVal) {
|
||||
const fnac = pad['__paciente']?.fecha_nacimiento || pad.fecha_nacimiento || '';
|
||||
if (fnac) {
|
||||
const hoy = new Date();
|
||||
@@ -575,13 +580,9 @@ function renderCampos(esquema, prefilled) {
|
||||
calcVal = edad >= 0 ? String(edad) : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
const inputType = c.calc_tipo === 'edad' ? 'number' : 'date';
|
||||
html += wrapOpen + `<div class="mb-3">${lbl}
|
||||
<input type="${inputType}" class="form-control" style="background:#fff9e6;border-color:#ffc107"
|
||||
name="${c.id}" value="${esc(calcVal)}" ${req}
|
||||
placeholder="${c.calc_tipo === 'edad' ? 'Edad en años' : 'Fecha'}">
|
||||
<small class="text-warning-emphasis"><i class="fas fa-calculator me-1"></i>Prellenado automáticamente — puedes modificarlo</small>
|
||||
<input type="number" min="0" max="120" class="form-control" style="background:#fff9e6;border-color:#ffc107"
|
||||
name="${c.id}" value="${esc(calcVal)}" ${req} placeholder="Edad en años">
|
||||
</div>` + wrapClose;
|
||||
} else {
|
||||
const t = c.tipo === 'numero' ? 'number'
|
||||
|
||||
+40
-38
@@ -332,6 +332,8 @@ $formId = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||
<div id="palette"></div>
|
||||
<div class="palette-group-title" style="margin-top:12px">Vinculados al paciente</div>
|
||||
<div id="palette-linked"></div>
|
||||
<div class="palette-group-title" style="margin-top:12px">Calculados</div>
|
||||
<div id="palette-calc"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -515,7 +517,10 @@ const TIPOS_CAMPO = [
|
||||
{ tipo:'parrafo', label:'Párrafo de texto', icon:'fa-paragraph' },
|
||||
{ tipo:'parrafo_inline', label:'Párrafo con campos', icon:'fa-align-left' },
|
||||
{ tipo:'lista_marcable', label:'Lista marcable', icon:'fa-list-ol' },
|
||||
{ tipo:'calculado', label:'Campo calculado', icon:'fa-calculator' },
|
||||
];
|
||||
const TIPOS_CALC = [
|
||||
{ tipo:'fecha_hoy', label:'Fecha actual', icon:'fa-calendar-day' },
|
||||
{ tipo:'edad', label:'Edad del paciente', icon:'fa-user-clock' },
|
||||
];
|
||||
const TIPOS_LINKED = [
|
||||
{ key:'nombre_completo', label:'Nombre completo', icon:'fa-user' },
|
||||
@@ -574,20 +579,20 @@ function renderPalette() {
|
||||
|
||||
$('palette-linked').innerHTML = TIPOS_LINKED.map(t => `
|
||||
<div class="palette-item linked" draggable="true"
|
||||
data-linked="${t.key}"
|
||||
data-tipo="linked" data-linked="${t.key}"
|
||||
ondragstart="palDragStart(event,'linked','${t.key}')"
|
||||
onclick="agregarCampo({tipo:'linked',linked:'${t.key}'})"
|
||||
onclick="agregarCampo({tipo:'linked',linked:'${t.key}'})">
|
||||
<i class="fas ${t.icon}"></i>${t.label}
|
||||
</div>`).join('');
|
||||
|
||||
// Click también agrega campo (además del drag)
|
||||
document.querySelectorAll('.palette-item').forEach(el => {
|
||||
el.addEventListener('click', () => {
|
||||
const tipo = el.dataset.tipo || 'linked';
|
||||
const linked = el.dataset.linked || null;
|
||||
agregarCampo({ tipo, linked });
|
||||
});
|
||||
});
|
||||
$('palette-calc').innerHTML = TIPOS_CALC.map(t => `
|
||||
<div class="palette-item" draggable="true"
|
||||
data-tipo="${t.tipo}"
|
||||
ondragstart="palDragStart(event,'${t.tipo}')"
|
||||
onclick="agregarCampo({tipo:'${t.tipo}',linked:null})"
|
||||
style="color:#856404">
|
||||
<i class="fas ${t.icon}"></i>${t.label}
|
||||
</div>`).join('');
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════
|
||||
@@ -635,6 +640,10 @@ function agregarCampo({ tipo, linked }) {
|
||||
campo = { id, tipo:'parrafo_inline', contenido:'Yo, {nombre_completo}, con N.º de identificación {numero_documento}, declaro que…' };
|
||||
} else if (tipo === 'lista_marcable') {
|
||||
campo = { id, tipo:'lista_marcable', label:'Marque con X la prueba solicitada', items:['Opción 1','Opción 2'], required:false };
|
||||
} else if (tipo === 'fecha_hoy') {
|
||||
campo = { id, tipo:'fecha_hoy', label:'Fecha', required:false };
|
||||
} else if (tipo === 'edad') {
|
||||
campo = { id, tipo:'edad', label:'Edad', required:false };
|
||||
} else {
|
||||
campo = { id, tipo, label:'Campo sin título', placeholder:'', required:false };
|
||||
}
|
||||
@@ -651,7 +660,7 @@ const TIPO_ICON = {
|
||||
fecha:'fa-calendar', hora:'fa-clock', select:'fa-list', radio:'fa-dot-circle',
|
||||
checkbox:'fa-check-square', firma:'fa-signature', firma_profesional:'fa-user-md', separador:'fa-minus', linked:'fa-link',
|
||||
parrafo:'fa-paragraph', parrafo_inline:'fa-align-left', lista_marcable:'fa-list-ol',
|
||||
calculado:'fa-calculator'
|
||||
fecha_hoy:'fa-calendar-day', edad:'fa-user-clock'
|
||||
};
|
||||
|
||||
function renderCanvas() {
|
||||
@@ -916,14 +925,18 @@ function renderCampoPreview(c) {
|
||||
).join('');
|
||||
return `<div class="preview-field">${lbl}${items}</div>`;
|
||||
}
|
||||
if (c.tipo === 'calculado') {
|
||||
const subLabel = c.calc_tipo === 'edad' ? 'Edad (años) — calculada del paciente'
|
||||
: 'Fecha de hoy — prellenada y editable';
|
||||
const t = c.calc_tipo === 'edad' ? 'number' : 'date';
|
||||
return `<div class="preview-field">
|
||||
${lbl}
|
||||
<input type="${t}" disabled placeholder="${subLabel}" style="background:#fff9e6;border-color:#ffc107">
|
||||
<small style="color:#856404;font-size:9px"><i class="fas fa-calculator"></i> Campo calculado — editable por el paciente</small>
|
||||
if (c.tipo === 'fecha_hoy') {
|
||||
const hoy = new Date();
|
||||
const val = hoy.getFullYear()+'-'+String(hoy.getMonth()+1).padStart(2,'0')+'-'+String(hoy.getDate()).padStart(2,'0');
|
||||
return `<div class="preview-field">${lbl}
|
||||
<input type="date" value="${val}" disabled style="background:#fff9e6;border-color:#ffc107">
|
||||
<small style="color:#856404;font-size:9px"><i class="fas fa-calendar-day"></i> Fecha actual — editable</small>
|
||||
</div>`;
|
||||
}
|
||||
if (c.tipo === 'edad') {
|
||||
return `<div class="preview-field">${lbl}
|
||||
<input type="number" placeholder="Ej: 34" disabled style="background:#fff9e6;border-color:#ffc107">
|
||||
<small style="color:#856404;font-size:9px"><i class="fas fa-user-clock"></i> Edad calculada del paciente — editable</small>
|
||||
</div>`;
|
||||
}
|
||||
const t = c.tipo==='numero'?'number':c.tipo==='fecha'?'date':c.tipo==='hora'?'time':'text';
|
||||
@@ -1039,21 +1052,13 @@ function abrirEditorCampo(idx) {
|
||||
<input class="form-check-input" type="checkbox" id="ce-required" ${c.required?'checked':''}>
|
||||
<label class="form-check-label small" for="ce-required">Requiere al menos una selección</label>
|
||||
</div>`;
|
||||
} else if (c.tipo === 'calculado') {
|
||||
const isFecha = (c.calc_tipo || 'fecha_hoy') === 'fecha_hoy';
|
||||
html += `<div class="mb-3">
|
||||
<label class="form-label small fw-semibold">Tipo de cálculo</label>
|
||||
<div class="d-flex gap-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="ce-calc-tipo" id="ce-calc-fecha" value="fecha_hoy" ${isFecha?'checked':''}>
|
||||
<label class="form-check-label small" for="ce-calc-fecha"><i class="fas fa-calendar-day text-warning me-1"></i>Fecha de hoy</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="ce-calc-tipo" id="ce-calc-edad" value="edad" ${!isFecha?'checked':''}>
|
||||
<label class="form-check-label small" for="ce-calc-edad"><i class="fas fa-user-clock text-warning me-1"></i>Edad del paciente</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-text mt-1">El campo se pre-llena automáticamente pero el paciente puede editarlo.</div>
|
||||
} else if (c.tipo === 'fecha_hoy' || c.tipo === 'edad') {
|
||||
html += `<div class="alert alert-warning py-2 small mb-2">
|
||||
<i class="fas fa-calculator me-1"></i>
|
||||
${c.tipo === 'fecha_hoy'
|
||||
? 'Se pre-llenará con la fecha actual al abrir el formulario.'
|
||||
: 'Se pre-llenará con la edad calculada a partir de la fecha de nacimiento del paciente.'}
|
||||
El paciente puede editarlo.
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="ce-required" ${c.required?'checked':''}>
|
||||
@@ -1145,9 +1150,6 @@ function aplicarCampo() {
|
||||
const items = document.getElementById('ce-items');
|
||||
if (items) c.items = items.value.split('\n').map(s=>s.trim()).filter(Boolean);
|
||||
|
||||
const calcTipo = document.querySelector('input[name="ce-calc-tipo"]:checked');
|
||||
if (calcTipo) c.calc_tipo = calcTipo.value;
|
||||
|
||||
const modoCanvas = document.getElementById('ce-modo-canvas');
|
||||
const modoFoto = document.getElementById('ce-modo-foto');
|
||||
if (modoCanvas !== null || modoFoto !== null) {
|
||||
|
||||
Reference in New Issue
Block a user