fix: eliminar bloque huérfano de métodos de notasManager (SyntaxError toggle)
This commit is contained in:
@@ -854,406 +854,6 @@ function renderOrdenesEnfermero(item) {
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function _fmtFechaCorta(s) {
|
||||
|
||||
// ── Toggle sección ────────────────────────────────────────────────────
|
||||
async toggle(domId, btn) {
|
||||
const body = document.getElementById(`notas-body-${domId}`);
|
||||
const chevron = btn.querySelector('.nota-chevron');
|
||||
if (!body) return;
|
||||
const abrir = body.classList.contains('d-none');
|
||||
body.classList.toggle('d-none', !abrir);
|
||||
chevron?.classList.toggle('open', abrir);
|
||||
if (abrir && !this._cache[domId]) {
|
||||
await this.cargar(domId);
|
||||
} else if (abrir) {
|
||||
this._renderBody(domId);
|
||||
}
|
||||
},
|
||||
|
||||
// ── Cargar desde API ─────────────────────────────────────────────────
|
||||
async cargar(domId) {
|
||||
const body = document.getElementById(`notas-body-${domId}`);
|
||||
if (!body) return;
|
||||
body.innerHTML = '<div class="text-center py-2 text-muted small"><i class="fas fa-spinner fa-spin me-1"></i>Cargando…</div>';
|
||||
try {
|
||||
const r = await fetch(`api/lab/get_notas_domicilio.php?domicilio_id=${domId}`);
|
||||
const d = await r.json();
|
||||
if (!d.success) throw new Error(d.error || 'Error al cargar notas');
|
||||
this._cache[domId] = {
|
||||
clinica: d.data.find(n => n.tipo === 'clinica') || null,
|
||||
libres: d.data.filter(n => n.tipo === 'libre'),
|
||||
};
|
||||
this._renderBody(domId);
|
||||
// Badge contador
|
||||
const total = d.data.length;
|
||||
const badge = document.getElementById(`nota-count-${domId}`);
|
||||
if (badge) { badge.textContent = total; badge.style.display = total ? '' : 'none'; }
|
||||
} catch (e) {
|
||||
if (body) body.innerHTML = `<div class="alert alert-danger small py-2 mt-2">${esc(e.message)}</div>`;
|
||||
}
|
||||
},
|
||||
|
||||
// ── Render cuerpo expandido ──────────────────────────────────────────
|
||||
_renderBody(domId) {
|
||||
const body = document.getElementById(`notas-body-${domId}`);
|
||||
if (!body) return;
|
||||
const pacNac = body.dataset.pacNac || '';
|
||||
const menor = this._esmenor(pacNac);
|
||||
const cache = this._cache[domId] || { clinica: null, libres: [] };
|
||||
|
||||
body.innerHTML = `
|
||||
<div style="margin-top:6px">
|
||||
${this._fichaHTML(cache.clinica, domId, menor)}
|
||||
${cache.libres.map(n => this._libreHTML(n)).join('')}
|
||||
<button style="width:100%;margin-top:6px;padding:8px;background:#f0f9ff;
|
||||
border:1px dashed #7dd3fc;border-radius:8px;color:#0369a1;
|
||||
font-size:.78rem;font-weight:700"
|
||||
onclick="notasManager.abrirLibre(${domId})">
|
||||
<i class="fas fa-plus me-1"></i>Agregar nota
|
||||
</button>
|
||||
</div>`;
|
||||
},
|
||||
|
||||
_fichaHTML(nota, domId, menor) {
|
||||
const vacio = !nota;
|
||||
const tieneAcud = nota?.acudiente_nombre || nota?.acudiente_documento;
|
||||
return `<div class="nota-ficha-card">
|
||||
<div class="ficha-header">
|
||||
<div class="ficha-titulo">
|
||||
<i class="fas fa-file-medical-alt me-1"></i>Ficha clínica
|
||||
${menor === true ? '<span style="color:#dc3545;font-size:.68rem"> · menor de edad</span>' : ''}
|
||||
</div>
|
||||
<button style="background:${vacio?'#f59e0b':'#ea580c'};color:#fff;border:none;
|
||||
border-radius:999px;padding:3px 11px;font-size:.72rem;font-weight:700"
|
||||
onclick="notasManager.abrirClinica(${domId})">
|
||||
${vacio ? '<i class="fas fa-plus me-1"></i>Completar' : '<i class="fas fa-edit me-1"></i>Editar'}
|
||||
</button>
|
||||
</div>
|
||||
${vacio
|
||||
? `<div style="color:#a16207;font-size:.75rem;text-align:center;padding:4px 0">Sin información registrada</div>`
|
||||
: `<dl style="margin:0;font-size:.78rem">
|
||||
${nota.antecedentes ? `<dt style="color:#9a3412;margin-top:4px">Antecedentes</dt><dd style="margin:0 0 2px">${esc(nota.antecedentes).replace(/\n/g,'<br>')}</dd>` : ''}
|
||||
${nota.medicamentos ? `<dt style="color:#9a3412;margin-top:4px">Medicamentos</dt><dd style="margin:0 0 2px">${esc(nota.medicamentos).replace(/\n/g,'<br>')}</dd>` : ''}
|
||||
${tieneAcud ? `<dt style="color:#9a3412;margin-top:4px">Acudiente</dt>
|
||||
<dd style="margin:0">${esc(nota.acudiente_nombre||'—')} · <span style="color:#6b7280">${esc(nota.acudiente_documento||'—')}</span></dd>` : ''}
|
||||
</dl>`}
|
||||
</div>`;
|
||||
},
|
||||
|
||||
_libreHTML(nota) {
|
||||
const domId = nota.domicilio_id;
|
||||
return `<div class="nota-libre-card">
|
||||
<div style="display:flex;justify-content:space-between;align-items:flex-start">
|
||||
<div class="nota-titulo">${esc(nota.titulo||'Nota')}</div>
|
||||
<div style="display:flex;gap:2px;flex-shrink:0;margin-left:6px">
|
||||
<button style="background:none;border:none;color:#6b7280;padding:2px 6px;font-size:.8rem"
|
||||
onclick="notasManager.abrirEditarLibre(${domId},${nota.id})"><i class="fas fa-edit"></i></button>
|
||||
<button style="background:none;border:none;color:#ef4444;padding:2px 6px;font-size:.8rem"
|
||||
onclick="notasManager.eliminar(${nota.id},${domId})"><i class="fas fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
${nota.cuerpo ? `<div class="nota-cuerpo">${nota.cuerpo}</div>` : ''}
|
||||
${nota.imagen_path ? `<img src="uploads/media/${esc(nota.imagen_path)}"
|
||||
style="max-width:100%;max-height:160px;border-radius:6px;margin-top:6px;
|
||||
border:1px solid #e5e7eb;cursor:zoom-in"
|
||||
onclick="window.open('uploads/media/${esc(nota.imagen_path)}','_blank')"
|
||||
onerror="this.style.display='none'">` : ''}
|
||||
<div class="nota-fecha">${_fmtFechaCorta(nota.created_at||'')}</div>
|
||||
</div>`;
|
||||
},
|
||||
|
||||
// ── Abrir bottom sheet: Ficha clínica ────────────────────────────────
|
||||
abrirClinica(domId) {
|
||||
this._editDomId = domId;
|
||||
this._editTipo = 'clinica';
|
||||
this._editNota = this._cache[domId]?.clinica || null;
|
||||
const bodyEl = document.getElementById(`notas-body-${domId}`);
|
||||
this._editPacNac = bodyEl?.dataset?.pacNac || '';
|
||||
const menor = this._esmenor(this._editPacNac);
|
||||
const nota = this._editNota;
|
||||
const inner = document.getElementById('nota-sheet-inner');
|
||||
|
||||
inner.innerHTML = `
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
|
||||
<div style="font-weight:800;font-size:1rem;color:#9a3412">
|
||||
<i class="fas fa-file-medical-alt me-2"></i>Ficha clínica
|
||||
</div>
|
||||
<button onclick="notasManager.cerrarSheet()"
|
||||
style="background:none;border:none;font-size:1.5rem;color:#9ca3af;line-height:1">×</button>
|
||||
</div>
|
||||
|
||||
<div class="nota-section">
|
||||
<label class="nota-label">Antecedentes</label>
|
||||
<textarea id="nc-antecedentes" class="nota-input" rows="3"
|
||||
placeholder="Enfermedades previas, alergias, cirugías, hospitalizaciones…">${esc(nota?.antecedentes||'')}</textarea>
|
||||
</div>
|
||||
<div class="nota-section">
|
||||
<label class="nota-label">Medicamentos actuales</label>
|
||||
<textarea id="nc-medicamentos" class="nota-input" rows="3"
|
||||
placeholder="Nombre del medicamento, dosis y frecuencia…">${esc(nota?.medicamentos||'')}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="nota-section nota-acudiente-bloque">
|
||||
<div style="font-size:.8rem;font-weight:700;color:#dc2626;margin-bottom:10px">
|
||||
<i class="fas fa-user-shield me-1"></i>Datos del acudiente
|
||||
${menor === true
|
||||
? '<span style="font-weight:400"> — <strong>obligatorio</strong> (paciente menor de edad)</span>'
|
||||
: '<span style="font-weight:400;color:#9ca3af"> (si aplica)</span>'}
|
||||
</div>
|
||||
<div style="margin-bottom:8px">
|
||||
<label class="nota-label">Nombre completo ${menor===true?'<span style="color:#dc2626">*</span>':''}</label>
|
||||
<input id="nc-acud-nombre" type="text" class="nota-input"
|
||||
value="${esc(nota?.acudiente_nombre||'')}" placeholder="Nombre del acudiente o responsable">
|
||||
</div>
|
||||
<div>
|
||||
<label class="nota-label">Documento de identidad ${menor===true?'<span style="color:#dc2626">*</span>':''}</label>
|
||||
<input id="nc-acud-doc" type="text" class="nota-input" inputmode="numeric"
|
||||
value="${esc(nota?.acudiente_documento||'')}" placeholder="Cédula, TI o Pasaporte">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:16px">
|
||||
<button id="nc-guardar-btn" class="nota-btn-guardar" style="background:#ea580c"
|
||||
onclick="notasManager.guardar()">
|
||||
<i class="fas fa-save me-2"></i>Guardar ficha clínica
|
||||
</button>
|
||||
</div>`;
|
||||
|
||||
this._abrirSheet();
|
||||
},
|
||||
|
||||
// ── Abrir bottom sheet: Nota libre nueva ────────────────────────────
|
||||
abrirLibre(domId) {
|
||||
const bodyEl = document.getElementById(`notas-body-${domId}`);
|
||||
this._editDomId = domId;
|
||||
this._editTipo = 'libre';
|
||||
this._editNota = null;
|
||||
this._editPacNac = bodyEl?.dataset?.pacNac || '';
|
||||
this._renderFormLibre(null);
|
||||
this._abrirSheet();
|
||||
},
|
||||
|
||||
// ── Abrir bottom sheet: Editar nota libre ───────────────────────────
|
||||
abrirEditarLibre(domId, notaId) {
|
||||
const nota = (this._cache[domId]?.libres||[]).find(n => +n.id === +notaId);
|
||||
const bodyEl = document.getElementById(`notas-body-${domId}`);
|
||||
this._editDomId = domId;
|
||||
this._editTipo = 'libre';
|
||||
this._editNota = nota || null;
|
||||
this._editPacNac = bodyEl?.dataset?.pacNac || '';
|
||||
this._renderFormLibre(nota);
|
||||
this._abrirSheet();
|
||||
},
|
||||
|
||||
_renderFormLibre(nota) {
|
||||
const inner = document.getElementById('nota-sheet-inner');
|
||||
inner.innerHTML = `
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
|
||||
<div style="font-weight:800;font-size:1rem">
|
||||
<i class="fas fa-sticky-note me-2 text-primary"></i>${nota ? 'Editar nota' : 'Nueva nota'}
|
||||
</div>
|
||||
<button onclick="notasManager.cerrarSheet()"
|
||||
style="background:none;border:none;font-size:1.5rem;color:#9ca3af;line-height:1">×</button>
|
||||
</div>
|
||||
|
||||
<div class="nota-section">
|
||||
<label class="nota-label">Título <span style="color:#dc2626">*</span></label>
|
||||
<input id="nl-titulo" type="text" class="nota-input" maxlength="200"
|
||||
value="${esc(nota?.titulo||'')}" placeholder="Ej: Observación inicial, Sangrado, Reacción…">
|
||||
</div>
|
||||
|
||||
<div class="nota-section">
|
||||
<label class="nota-label">Descripción</label>
|
||||
<div class="fmt-toolbar">
|
||||
<button class="fmt-btn" onclick="notasManager._fmt('bold')" title="Negrita"><b>B</b></button>
|
||||
<button class="fmt-btn" style="font-style:italic" onclick="notasManager._fmt('italic')" title="Cursiva">I</button>
|
||||
<button class="fmt-btn" style="text-decoration:underline" onclick="notasManager._fmt('underline')" title="Subrayado">U</button>
|
||||
<button class="fmt-btn" onclick="notasManager._fmt('strikeThrough')" title="Tachado"><s>S</s></button>
|
||||
<button class="fmt-btn" onclick="notasManager._insertLista()" title="Lista">• Lista</button>
|
||||
<button class="fmt-btn" onclick="notasManager._limpiarFormato()" title="Sin formato">✕ Formato</button>
|
||||
</div>
|
||||
<div id="nl-cuerpo" class="nota-editor" contenteditable="true"
|
||||
data-placeholder="Escribe los detalles de la nota…"></div>
|
||||
</div>
|
||||
|
||||
<div class="nota-section">
|
||||
<label class="nota-label"><i class="fas fa-camera me-1"></i>Imagen adjunta (opcional, máx. 5 MB)</label>
|
||||
<div id="nl-preview" style="margin-bottom:6px">
|
||||
${nota?.imagen_path ? `<div style="position:relative;display:inline-block">
|
||||
<img src="uploads/media/${esc(nota.imagen_path)}"
|
||||
style="max-height:100px;border-radius:6px;border:1px solid #e5e7eb">
|
||||
<button onclick="notasManager._quitarImg()"
|
||||
style="position:absolute;top:-6px;right:-6px;background:#ef4444;color:#fff;
|
||||
border:none;border-radius:50%;width:20px;height:20px;font-size:.65rem;
|
||||
display:flex;align-items:center;justify-content:center">✕</button>
|
||||
</div>` : ''}
|
||||
</div>
|
||||
<input type="file" id="nl-img-input" accept="image/jpeg,image/png,image/webp"
|
||||
capture="environment" style="width:100%;font-size:.82rem"
|
||||
onchange="notasManager._previsualizarImg(this)">
|
||||
<input type="hidden" id="nl-img-guardada" value="${esc(nota?.imagen_path||'')}">
|
||||
</div>
|
||||
|
||||
<button id="nl-guardar-btn" class="nota-btn-guardar" style="background:#0d6efd"
|
||||
onclick="notasManager.guardar()">
|
||||
<i class="fas fa-save me-2"></i>Guardar nota
|
||||
</button>`;
|
||||
|
||||
// Cargar HTML en contenteditable
|
||||
if (nota?.cuerpo) {
|
||||
requestAnimationFrame(() => {
|
||||
const el = document.getElementById('nl-cuerpo');
|
||||
if (el) el.innerHTML = nota.cuerpo;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_fmt(cmd) { document.getElementById('nl-cuerpo')?.focus(); document.execCommand(cmd, false, null); },
|
||||
_insertLista() { document.getElementById('nl-cuerpo')?.focus(); document.execCommand('insertUnorderedList', false, null); },
|
||||
_limpiarFormato() { document.getElementById('nl-cuerpo')?.focus(); document.execCommand('removeFormat', false, null); },
|
||||
|
||||
_previsualizarImg(input) {
|
||||
if (!input.files?.[0]) return;
|
||||
const reader = new FileReader();
|
||||
reader.onload = e => {
|
||||
const prev = document.getElementById('nl-preview');
|
||||
if (prev) prev.innerHTML = `<div style="position:relative;display:inline-block">
|
||||
<img src="${e.target.result}" style="max-height:100px;border-radius:6px;border:1px solid #e5e7eb">
|
||||
<button onclick="notasManager._quitarImg()"
|
||||
style="position:absolute;top:-6px;right:-6px;background:#ef4444;color:#fff;
|
||||
border:none;border-radius:50%;width:20px;height:20px;font-size:.65rem;
|
||||
display:flex;align-items:center;justify-content:center">✕</button>
|
||||
</div>`;
|
||||
};
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
},
|
||||
|
||||
_quitarImg() {
|
||||
document.getElementById('nl-preview').innerHTML = '';
|
||||
const inp = document.getElementById('nl-img-input');
|
||||
if (inp) inp.value = '';
|
||||
const h = document.getElementById('nl-img-guardada');
|
||||
if (h) h.value = '';
|
||||
},
|
||||
|
||||
// ── Guardar ──────────────────────────────────────────────────────────
|
||||
async guardar() {
|
||||
const btnId = this._editTipo === 'clinica' ? 'nc-guardar-btn' : 'nl-guardar-btn';
|
||||
const btn = document.getElementById(btnId);
|
||||
const labs = { clinica: 'Guardar ficha clínica', libre: 'Guardar nota' };
|
||||
if (btn) { btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Guardando…'; }
|
||||
|
||||
try {
|
||||
let imagenPath = null;
|
||||
|
||||
if (this._editTipo === 'libre') {
|
||||
const imgInput = document.getElementById('nl-img-input');
|
||||
if (imgInput?.files?.[0]) {
|
||||
imagenPath = await this._subirImagen(imgInput.files[0]);
|
||||
} else {
|
||||
imagenPath = document.getElementById('nl-img-guardada')?.value || null;
|
||||
}
|
||||
}
|
||||
|
||||
let payload = { domicilio_id: this._editDomId, tipo: this._editTipo };
|
||||
if (this._editNota?.id) payload.id = +this._editNota.id;
|
||||
|
||||
if (this._editTipo === 'clinica') {
|
||||
payload.antecedentes = document.getElementById('nc-antecedentes')?.value.trim() || null;
|
||||
payload.medicamentos = document.getElementById('nc-medicamentos')?.value.trim() || null;
|
||||
const menor = this._esmenor(this._editPacNac);
|
||||
const acNombre = document.getElementById('nc-acud-nombre')?.value.trim() || null;
|
||||
const acDoc = document.getElementById('nc-acud-doc')?.value.trim() || null;
|
||||
if (menor === true && (!acNombre || !acDoc)) {
|
||||
alert('El nombre y documento del acudiente son obligatorios para pacientes menores de edad.');
|
||||
if (btn) { btn.disabled = false; btn.innerHTML = `<i class="fas fa-save me-2"></i>${labs.clinica}`; }
|
||||
return;
|
||||
}
|
||||
payload.acudiente_nombre = acNombre;
|
||||
payload.acudiente_documento = acDoc;
|
||||
} else {
|
||||
const titulo = document.getElementById('nl-titulo')?.value.trim();
|
||||
if (!titulo) {
|
||||
alert('El título de la nota es obligatorio.');
|
||||
if (btn) { btn.disabled = false; btn.innerHTML = `<i class="fas fa-save me-2"></i>${labs.libre}`; }
|
||||
return;
|
||||
}
|
||||
payload.titulo = titulo;
|
||||
payload.cuerpo = document.getElementById('nl-cuerpo')?.innerHTML.trim() || null;
|
||||
payload.imagen_path = imagenPath;
|
||||
}
|
||||
|
||||
const r = await fetch('api/lab/save_nota_domicilio.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
const d = await r.json();
|
||||
if (!d.success) throw new Error(d.error || 'Error al guardar');
|
||||
|
||||
delete this._cache[this._editDomId];
|
||||
this.cerrarSheet();
|
||||
await this.cargar(this._editDomId);
|
||||
} catch (e) {
|
||||
alert('Error: ' + e.message);
|
||||
if (btn) { btn.disabled = false; btn.innerHTML = `<i class="fas fa-save me-2"></i>Reintentar`; }
|
||||
}
|
||||
},
|
||||
|
||||
async _subirImagen(file) {
|
||||
const fd = new FormData();
|
||||
fd.append('file', file);
|
||||
const r = await fetch('api/lab/upload_nota_imagen.php', { method: 'POST', body: fd });
|
||||
const d = await r.json();
|
||||
if (!d.success) throw new Error(d.error || 'Error al subir imagen');
|
||||
return d.imagen_path;
|
||||
},
|
||||
|
||||
async eliminar(notaId, domId) {
|
||||
if (!confirm('¿Eliminar esta nota?')) return;
|
||||
try {
|
||||
const r = await fetch('api/lab/delete_nota_domicilio.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id: notaId }),
|
||||
});
|
||||
const d = await r.json();
|
||||
if (!d.success) throw new Error(d.error || 'Error al eliminar');
|
||||
delete this._cache[domId];
|
||||
await this.cargar(domId);
|
||||
} catch (e) {
|
||||
alert('Error: ' + e.message);
|
||||
}
|
||||
},
|
||||
|
||||
_abrirSheet() {
|
||||
const sheet = document.getElementById('nota-sheet');
|
||||
const backdrop = document.getElementById('nota-backdrop');
|
||||
if (!sheet || !backdrop) return;
|
||||
sheet.style.transform = 'translateY(100%)';
|
||||
sheet.style.transition = '';
|
||||
sheet.style.display = 'block';
|
||||
backdrop.style.display = 'block';
|
||||
requestAnimationFrame(() => {
|
||||
sheet.style.transition = 'transform .32s cubic-bezier(.4,0,.2,1)';
|
||||
sheet.style.transform = 'translateY(0)';
|
||||
});
|
||||
},
|
||||
|
||||
cerrarSheet() {
|
||||
const sheet = document.getElementById('nota-sheet');
|
||||
const backdrop = document.getElementById('nota-backdrop');
|
||||
if (!sheet) return;
|
||||
sheet.style.transition = 'transform .28s cubic-bezier(.4,0,.2,1)';
|
||||
sheet.style.transform = 'translateY(100%)';
|
||||
setTimeout(() => {
|
||||
sheet.style.display = 'none';
|
||||
if (backdrop) backdrop.style.display = 'none';
|
||||
}, 300);
|
||||
},
|
||||
};
|
||||
|
||||
function _fmtFechaCorta(s) {
|
||||
if (!s) return '';
|
||||
return new Date(s).toLocaleString('es-CO', { day:'2-digit', month:'short', hour:'2-digit', minute:'2-digit' });
|
||||
|
||||
Reference in New Issue
Block a user