Competencias con saltos de línea (tratamientos)
This commit is contained in:
parent
20c618ab73
commit
0c8c0202b3
|
@ -53,14 +53,16 @@ switch ($method) {
|
|||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO cursos (nombre, descripcion, tipo, competencias, estado, profesor_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO cursos (nombre, descripcion, tipo, competencias, docente, horas_trabajadas, estado, profesor_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
");
|
||||
$stmt->execute([
|
||||
$data['nombre'],
|
||||
$data['descripcion'] ?? null,
|
||||
$data['tipo'],
|
||||
$data['competencias'] ?? null,
|
||||
$data['docente'] ?? null,
|
||||
$data['horas_trabajadas'] ?? null,
|
||||
$data['estado'],
|
||||
$profesorId
|
||||
]);
|
||||
|
@ -110,6 +112,8 @@ switch ($method) {
|
|||
descripcion = ?,
|
||||
tipo = ?,
|
||||
competencias = ?,
|
||||
docente = ?,
|
||||
horas_trabajadas = ?,
|
||||
estado = ?
|
||||
WHERE id = ?
|
||||
");
|
||||
|
@ -118,6 +122,8 @@ switch ($method) {
|
|||
$data['descripcion'] ?? null,
|
||||
$data['tipo'],
|
||||
$data['competencias'] ?? null,
|
||||
$data['docente'] ?? null,
|
||||
$data['horas_trabajadas'] ?? null,
|
||||
$data['estado'],
|
||||
$data['id']
|
||||
]);
|
||||
|
|
|
@ -119,6 +119,77 @@ function getProfesorId() {
|
|||
}
|
||||
}
|
||||
|
||||
async function renderCursosGenerablesPorTipo(tipo) {
|
||||
const container = document.getElementById("cursos-generar-diplomas");
|
||||
container.innerHTML = `<div class="loader">Cargando cursos...</div>`;
|
||||
|
||||
try {
|
||||
const resCursos = await fetch(`api/cursos.php?profesor_id=${getProfesorId()}`);
|
||||
const cursosData = await resCursos.json();
|
||||
|
||||
if (!cursosData.success) throw new Error("Error al cargar cursos");
|
||||
|
||||
const cursosFiltrados = cursosData.data.filter(
|
||||
(c) => c.estado === "completado" && c.tipo === tipo
|
||||
);
|
||||
|
||||
if (cursosFiltrados.length === 0) {
|
||||
container.innerHTML = `<div class="no-data"><h3>No hay cursos completados de este tipo</h3></div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const allAlumnos = await fetch("api/alumnos.php").then((r) => r.json());
|
||||
const vinculos = await fetch("api/alumnos-cursos.php").then((r) => r.json());
|
||||
|
||||
const cursosConAlumnos = cursosFiltrados.map((curso) => {
|
||||
const alumnosDelCurso = vinculos.data
|
||||
.filter((ac) => ac.curso_id == curso.id)
|
||||
.map((ac) => {
|
||||
const alumno = allAlumnos.data.find((a) => a.id == ac.alumno_id);
|
||||
return alumno ? { ...alumno, alumno_curso_id: ac.id } : null;
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
return { ...curso, alumnos: alumnosDelCurso };
|
||||
});
|
||||
|
||||
container.innerHTML = cursosConAlumnos
|
||||
.map((curso) => {
|
||||
const alumnosHtml = curso.alumnos.length
|
||||
? curso.alumnos
|
||||
.map(
|
||||
(al) => `
|
||||
<tr>
|
||||
<td>${al.nombre}</td>
|
||||
<td>${al.email}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm" onclick="generateDiploma(${al.alumno_curso_id})">Generar Diploma</button>
|
||||
<button class="btn btn-sm btn-outline" disabled>Enviar Diploma</button>
|
||||
</td>
|
||||
</tr>`
|
||||
)
|
||||
.join("")
|
||||
: `<tr><td colspan="3" class="text-muted">No hay alumnos inscritos</td></tr>`;
|
||||
|
||||
return `
|
||||
<div class="card">
|
||||
<h3>${curso.nombre} <span class="badge ${getCourseTypeClass(curso.tipo)}">${formatCourseType(curso.tipo)}</span></h3>
|
||||
<div class="table-container">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr><th>Alumno</th><th>Email</th><th>Acciones</th></tr>
|
||||
</thead>
|
||||
<tbody>${alumnosHtml}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>`;
|
||||
})
|
||||
.join("");
|
||||
} catch (err) {
|
||||
container.innerHTML = `<div class="card error-card"><p>${err.message}</p></div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function showModal(title, content, buttons = []) {
|
||||
// Remover modal existente si hay
|
||||
const existing = document.getElementById("modal-overlay");
|
||||
|
@ -373,6 +444,12 @@ function loadProfessorCourses(container) {
|
|||
<option value="tratamiento">Tratamiento</option>
|
||||
</select>
|
||||
|
||||
<label>Docente que imparte (Opcional)</label>
|
||||
<input type="text" name="docente" style="margin-bottom: 1rem;">
|
||||
|
||||
<label>Horas trabajadas (Opcional)</label>
|
||||
<input type="number" name="horas_trabajadas" min="0" step="1" style="margin-bottom: 1rem;">
|
||||
|
||||
<div id="competencesField" class="oculto">
|
||||
<label>Competencias Asociadas *</label>
|
||||
<small style="display:block; margin-bottom: 0.5rem; color: #64748b;">
|
||||
|
@ -415,51 +492,57 @@ function loadProfessorCourses(container) {
|
|||
|
||||
<div class="table-container" style="margin-top: 1rem;">
|
||||
<table class="courses-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nombre</th>
|
||||
<th>Descripción</th>
|
||||
<th>Tipo</th>
|
||||
<th>Estado</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${courses
|
||||
.map((course) => {
|
||||
const desc = course.descripcion || "-";
|
||||
const safeDesc = desc.replace(/"/g, """).replace(/'/g, "\\'");
|
||||
return `
|
||||
<tr>
|
||||
<td>${course.nombre}</td>
|
||||
<td class="description-cell">
|
||||
<span class="truncated-text" id="desc-${course.id}">
|
||||
${desc}
|
||||
</span>
|
||||
<span class="read-more-container" id="readmore-${course.id}"></span>
|
||||
</td>
|
||||
<td><span class="badge ${getCourseTypeClass(course.tipo)}">${formatCourseType(course.tipo)}</span></td>
|
||||
<td>
|
||||
<span class="badge ${
|
||||
course.estado === "activo"
|
||||
? "active"
|
||||
: course.estado === "completado"
|
||||
? "completed"
|
||||
: course.estado === "archivado"
|
||||
? "archived"
|
||||
: "inactive"
|
||||
}">${course.estado}</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="action-buttons">
|
||||
<button class="btn btn-sm" onclick="editCourse(${course.id})">Editar</button>
|
||||
<button class="btn btn-sm btn-danger" onclick="confirmDeleteCourse(${course.id})">Eliminar</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>`;
|
||||
})
|
||||
.join("")}
|
||||
</tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nombre</th>
|
||||
<th>Descripción</th>
|
||||
<th>Tipo</th>
|
||||
<th>Docente</th>
|
||||
<th>Horas</th>
|
||||
<th>Estado</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${courses
|
||||
.map((course) => {
|
||||
const desc = course.descripcion || "-";
|
||||
const safeDesc = desc.replace(/"/g, """).replace(/'/g, "\\'");
|
||||
const docente = course.docente || "-";
|
||||
const horas = course.horas_trabajadas || "-";
|
||||
return `
|
||||
<tr>
|
||||
<td>${course.nombre}</td>
|
||||
<td class="description-cell">
|
||||
<span class="truncated-text" id="desc-${course.id}">
|
||||
${desc}
|
||||
</span>
|
||||
<span class="read-more-container" id="readmore-${course.id}"></span>
|
||||
</td>
|
||||
<td><span class="badge ${getCourseTypeClass(course.tipo)}">${formatCourseType(course.tipo)}</span></td>
|
||||
<td>${docente}</td>
|
||||
<td>${horas}</td>
|
||||
<td>
|
||||
<span class="badge ${
|
||||
course.estado === "activo"
|
||||
? "active"
|
||||
: course.estado === "completado"
|
||||
? "completed"
|
||||
: course.estado === "archivado"
|
||||
? "archived"
|
||||
: "inactive"
|
||||
}">${course.estado}</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="action-buttons">
|
||||
<button class="btn btn-sm" onclick="editCourse(${course.id})">Editar</button>
|
||||
<button class="btn btn-sm btn-danger" onclick="confirmDeleteCourse(${course.id})">Eliminar</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>`;
|
||||
})
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="emptyCourseMessage" style="display: none; padding: 1rem; text-align: center; color: #64748b;">
|
||||
Cuando haya cursos en esta categoría, se mostrarán aquí.
|
||||
|
@ -492,7 +575,7 @@ function loadProfessorCourses(container) {
|
|||
let visibles = 0;
|
||||
|
||||
filas.forEach(fila => {
|
||||
const badgeEstado = fila.querySelector("td:nth-child(4) .badge");
|
||||
const badgeEstado = fila.querySelector("td:nth-child(6) .badge");
|
||||
const estado = badgeEstado?.textContent.toLowerCase() || "";
|
||||
if (estadoSeleccionado === "todos" || estado === estadoSeleccionado) {
|
||||
fila.style.display = "";
|
||||
|
@ -572,15 +655,16 @@ function setupCourseForm() {
|
|||
const courseTypeSelect = document.getElementById('courseType');
|
||||
const competencesField = document.getElementById('competencesField');
|
||||
const competenciasInput = competencesField
|
||||
? competencesField.querySelector('textarea[name="competencias"]')
|
||||
: null;
|
||||
? competencesField.querySelector('textarea[name="competencias"]')
|
||||
: null;
|
||||
|
||||
if (competenciasInput) {
|
||||
competenciasInput.addEventListener("keydown", function (e) {
|
||||
if (e.key === "Enter") {
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (courseTypeSelect && competenciasInput) {
|
||||
courseTypeSelect.addEventListener('change', function () {
|
||||
|
@ -605,7 +689,6 @@ function setupCourseForm() {
|
|||
const submitText = document.getElementById("submitCourseText");
|
||||
const spinner = document.getElementById("submitCourseSpinner");
|
||||
|
||||
// Cargar dinámicamente opciones del select de estado
|
||||
const estadoSelect = form.querySelector('select[name="estado"]');
|
||||
if (estadoSelect) {
|
||||
estadoSelect.innerHTML = "";
|
||||
|
@ -627,42 +710,37 @@ function setupCourseForm() {
|
|||
});
|
||||
}
|
||||
|
||||
// ✅ Botón Cancelar: volver a modo "Crear"
|
||||
if (cancelBtn) {
|
||||
cancelBtn.addEventListener("click", function () {
|
||||
form.reset();
|
||||
form.dataset.editing = "false";
|
||||
delete form.dataset.courseId;
|
||||
submitText.textContent = "Guardar";
|
||||
spinner.style.display = "none";
|
||||
submitBtn.disabled = false;
|
||||
cancelBtn.style.display = "none";
|
||||
if (cancelBtn) {
|
||||
cancelBtn.addEventListener("click", function () {
|
||||
form.reset();
|
||||
form.dataset.editing = "false";
|
||||
delete form.dataset.courseId;
|
||||
submitText.textContent = "Guardar";
|
||||
spinner.style.display = "none";
|
||||
submitBtn.disabled = false;
|
||||
cancelBtn.style.display = "none";
|
||||
|
||||
// Restaurar opciones del select estado
|
||||
if (estadoSelect) {
|
||||
estadoSelect.innerHTML = "";
|
||||
["activo", "archivado"].forEach(val => {
|
||||
const opt = document.createElement("option");
|
||||
opt.value = val;
|
||||
opt.textContent = val.charAt(0).toUpperCase() + val.slice(1);
|
||||
estadoSelect.appendChild(opt);
|
||||
});
|
||||
}
|
||||
if (estadoSelect) {
|
||||
estadoSelect.innerHTML = "";
|
||||
["activo", "archivado"].forEach(val => {
|
||||
const opt = document.createElement("option");
|
||||
opt.value = val;
|
||||
opt.textContent = val.charAt(0).toUpperCase() + val.slice(1);
|
||||
estadoSelect.appendChild(opt);
|
||||
});
|
||||
}
|
||||
|
||||
// 🔄 Forzar reactivación lógica por cambio de tipo de curso
|
||||
const tipoCurso = document.getElementById("courseType");
|
||||
if (tipoCurso) {
|
||||
tipoCurso.value = "inyeccion"; // por defecto
|
||||
tipoCurso.dispatchEvent(new Event("change")); // 👈 esto ejecuta tu lógica oculta
|
||||
}
|
||||
const tipoCurso = document.getElementById("courseType");
|
||||
if (tipoCurso) {
|
||||
tipoCurso.value = "inyeccion";
|
||||
tipoCurso.dispatchEvent(new Event("change"));
|
||||
}
|
||||
|
||||
// Restaurar orden visual de los botones
|
||||
const actions = form.querySelector(".form-actions");
|
||||
if (actions) actions.appendChild(cancelBtn);
|
||||
});
|
||||
}
|
||||
const actions = form.querySelector(".form-actions");
|
||||
if (actions) actions.appendChild(cancelBtn);
|
||||
});
|
||||
}
|
||||
|
||||
// Envío del formulario
|
||||
form.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
|
@ -677,6 +755,8 @@ if (cancelBtn) {
|
|||
competencias: formData.get("competencias"),
|
||||
tipo: formData.get("tipo"),
|
||||
estado: formData.get("estado"),
|
||||
docente: formData.get("docente") || null,
|
||||
horas_trabajadas: formData.get("horas_trabajadas") || null,
|
||||
profesor_id: getProfesorId(),
|
||||
};
|
||||
|
||||
|
@ -702,7 +782,6 @@ if (cancelBtn) {
|
|||
}
|
||||
});
|
||||
|
||||
// Autoajuste dinámico del campo Descripción
|
||||
const descripcionTextarea = form.querySelector('textarea[name="descripcion"]');
|
||||
if (descripcionTextarea) {
|
||||
const autoResize = () => {
|
||||
|
@ -725,8 +804,10 @@ window.editCourse = function (id) {
|
|||
form.nombre.value = course.nombre;
|
||||
form.descripcion.value = course.descripcion || "";
|
||||
form.tipo.value = course.tipo;
|
||||
form.docente.value = course.docente || "";
|
||||
form.horas_trabajadas.value = course.horas_trabajadas || "";
|
||||
|
||||
// 🟦 Mostrar/ocultar campo de competencias según tipo
|
||||
// Mostrar/ocultar campo de competencias
|
||||
const competencesField = document.getElementById("competencesField");
|
||||
const competenciasInput = competencesField.querySelector('textarea[name="competencias"]');
|
||||
if (course.tipo === "tratamiento") {
|
||||
|
@ -739,36 +820,25 @@ window.editCourse = function (id) {
|
|||
competenciasInput.required = false;
|
||||
}
|
||||
|
||||
// 🟦 Cargar opciones de estado incluyendo "completado"
|
||||
// Estado del curso
|
||||
const estadoSelect = form.querySelector('select[name="estado"]');
|
||||
if (estadoSelect) {
|
||||
estadoSelect.innerHTML = "";
|
||||
|
||||
const opciones = [
|
||||
{ value: "activo", label: "Activo" },
|
||||
{ value: "archivado", label: "Archivado" },
|
||||
{ value: "completado", label: "Completado" }
|
||||
];
|
||||
|
||||
opciones.forEach(opt => {
|
||||
["activo", "archivado", "completado"].forEach((estado) => {
|
||||
const option = document.createElement("option");
|
||||
option.value = opt.value;
|
||||
option.textContent = opt.label;
|
||||
option.value = estado;
|
||||
option.textContent = estado.charAt(0).toUpperCase() + estado.slice(1);
|
||||
estadoSelect.appendChild(option);
|
||||
});
|
||||
|
||||
estadoSelect.value = course.estado || "activo";
|
||||
}
|
||||
|
||||
// 🟦 Marcar modo edición
|
||||
form.dataset.editing = "true";
|
||||
form.dataset.courseId = id;
|
||||
|
||||
// ✅ Solo actualizamos el texto del span, no todo el botón
|
||||
const submitText = document.getElementById("submitCourseText");
|
||||
if (submitText) submitText.textContent = "Actualizar";
|
||||
|
||||
// ✅ Mostrar el botón de cancelar
|
||||
const cancelBtn = document.getElementById("cancelCourseBtn");
|
||||
if (cancelBtn) cancelBtn.style.display = "inline-block";
|
||||
|
||||
|
@ -877,10 +947,6 @@ function renderStudentForm() {
|
|||
<div class="card-header" style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<h2>Gestión de Alumnos</h2>
|
||||
<div style="display: flex; align-items: center; gap: 0.5rem; position: relative;">
|
||||
<label class="btn btn-primary" style="margin: 0;">
|
||||
Importar CSV
|
||||
<input type="file" accept=".csv" onchange="handleCSVUpload(event)" style="display: none;">
|
||||
</label>
|
||||
<div style="position: relative;">
|
||||
<svg onclick="downloadCSVTemplate()"
|
||||
xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
|
||||
|
@ -894,8 +960,14 @@ function renderStudentForm() {
|
|||
Descargar formato CSV
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="btn btn-primary" style="margin: 0;">
|
||||
Importar CSV
|
||||
<input type="file" accept=".csv" onchange="handleCSVUpload(event)" style="display: none;">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="studentForm">
|
||||
<div class="form-grid">
|
||||
<div class="form-group">
|
||||
|
@ -931,20 +1003,19 @@ function renderStudentForm() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="button" class="btn btn-outline" onclick="resetStudentForm()" id="cancelBtn" style="display:none;">
|
||||
Cancelar
|
||||
</button>
|
||||
<div class="form-actions" id="studentFormActions">
|
||||
<button type="submit" class="btn">
|
||||
<span id="submitText">Guardar</span>
|
||||
<span class="spinner-border spinner-border-sm" id="submitSpinner" style="display:none;"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline" onclick="resetStudentForm()" id="cancelBtn" style="display:none;">
|
||||
Cancelar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
|
||||
function setupStudentForm() {
|
||||
const form = document.getElementById("studentForm");
|
||||
if (!form) return;
|
||||
|
@ -1099,6 +1170,17 @@ window.editStudent = function (id) {
|
|||
form.dataset.studentId = id;
|
||||
|
||||
document.getElementById("submitText").textContent = "Actualizar";
|
||||
const formActions = document.getElementById("studentFormActions");
|
||||
const submitBtn = formActions.querySelector("button[type='submit']");
|
||||
const cancelBtn = document.getElementById("cancelBtn");
|
||||
|
||||
// Asegura que el botón Actualizar esté primero, Cancelar después
|
||||
if (submitBtn && cancelBtn) {
|
||||
formActions.innerHTML = "";
|
||||
formActions.appendChild(submitBtn);
|
||||
formActions.appendChild(cancelBtn);
|
||||
}
|
||||
|
||||
document.getElementById("cancelBtn").style.display = "inline-block";
|
||||
|
||||
// 👇 Precargar tipo y curso si el alumno tiene asignación
|
||||
|
@ -1175,9 +1257,29 @@ window.resetStudentForm = function () {
|
|||
form.dataset.editing = "false";
|
||||
delete form.dataset.studentId;
|
||||
|
||||
document.getElementById("submitText").textContent = "Guardar";
|
||||
document.getElementById("cancelBtn").style.display = "none";
|
||||
const submitText = document.getElementById("submitText");
|
||||
const cancelBtn = document.getElementById("cancelBtn");
|
||||
const formActions = document.getElementById("studentFormActions");
|
||||
const submitBtn = formActions.querySelector("button[type='submit']");
|
||||
|
||||
// Restaurar texto y ocultar cancelar
|
||||
if (submitText) submitText.textContent = "Guardar";
|
||||
if (cancelBtn) cancelBtn.style.display = "none";
|
||||
|
||||
// Reordenar botones (Actualizar primero, luego Cancelar)
|
||||
if (submitBtn && cancelBtn) {
|
||||
formActions.innerHTML = "";
|
||||
formActions.appendChild(submitBtn);
|
||||
formActions.appendChild(cancelBtn);
|
||||
}
|
||||
|
||||
// Reiniciar selects
|
||||
const tipoCurso = document.getElementById("tipoCurso");
|
||||
const curso = document.getElementById("curso");
|
||||
if (tipoCurso) tipoCurso.selectedIndex = 0;
|
||||
if (curso) curso.innerHTML = '<option value="">Selecciona primero un tipo</option>';
|
||||
};
|
||||
|
||||
function filterStudents(searchTerm) {
|
||||
const rows = document.querySelectorAll(".students-table tbody tr");
|
||||
|
||||
|
@ -1469,89 +1571,122 @@ window.unassignStudent = async function (alumnoId, cursoId) {
|
|||
|
||||
// Gestión de diplomas
|
||||
function loadDiplomasSection(container) {
|
||||
container.innerHTML = '<div class="loader">Cargando diplomas...</div>';
|
||||
container.innerHTML = `
|
||||
<div class="card">
|
||||
<div class="tab-header" style="display: flex; gap: 1rem; border-bottom: 2px solid #e2e8f0;">
|
||||
<button class="tab-btn active" data-tab="generar" onclick="switchDiplomaTab('generar')">Generar Diplomas</button>
|
||||
<button class="tab-btn" data-tab="emitidos" onclick="switchDiplomaTab('emitidos')">Diplomas Emitidos</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="diploma-tab-generar" class="diploma-tab-content active">
|
||||
<div class="card">
|
||||
<h2 style="margin-bottom: 1rem;">Generar Diplomas</h2>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 1rem;">
|
||||
<label for="tipoCursoSelector"><strong>Tipo de Curso:</strong></label>
|
||||
<select id="tipoCursoSelector" class="form-control" style="margin-top: 0.5rem; padding: 0.5rem; border-radius: 6px;">
|
||||
<option value="">Selecciona un tipo...</option>
|
||||
<option value="inyeccion">Inyección</option>
|
||||
<option value="pildora">Píldora</option>
|
||||
<option value="tratamiento">Tratamiento</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="cursos-generar-diplomas">
|
||||
<div class="no-data">
|
||||
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#64748b">
|
||||
<path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
|
||||
<circle cx="8.5" cy="7" r="4"></circle>
|
||||
<line x1="18" y1="8" x2="23" y2="13"></line>
|
||||
<line x1="23" y1="8" x2="18" y2="13"></line>
|
||||
</svg>
|
||||
<h3>Selecciona un tipo de curso</h3>
|
||||
<p>Los cursos completados con alumnos aparecerán aquí</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="diploma-tab-emitidos" class="diploma-tab-content" style="display:none;">
|
||||
<div class="card">
|
||||
<h2>Diplomas Emitidos</h2>
|
||||
<div class="loader">Cargando diplomas...</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Inicializar contenido emitido
|
||||
fetch(`api/diploma.php?profesor_id=${getProfesorId()}`)
|
||||
.then((response) => {
|
||||
if (!response.ok) throw new Error("Error en la respuesta del servidor");
|
||||
return response.json();
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
if (!data.success)
|
||||
throw new Error(data.error || "Error al obtener diplomas");
|
||||
|
||||
if (data.data.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="card">
|
||||
<h2>Diplomas Emitidos</h2>
|
||||
<p>No hay diplomas registrados aún</p>
|
||||
</div>`;
|
||||
const emitidosContainer = document.querySelector("#diploma-tab-emitidos .card");
|
||||
if (!data.success || data.data.length === 0) {
|
||||
emitidosContainer.innerHTML = `
|
||||
<h2>Diplomas Emitidos</h2>
|
||||
<p>No hay diplomas registrados aún</p>`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="card">
|
||||
<h2>Diplomas Emitidos</h2>
|
||||
<div class="table-container">
|
||||
<table class="diplomas-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Alumno</th>
|
||||
<th>Email</th>
|
||||
<th>Curso</th>
|
||||
<th>Tipo</th>
|
||||
<th>Fecha</th>
|
||||
<th>Código</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${data.data
|
||||
.map(
|
||||
(diploma) => `
|
||||
emitidosContainer.innerHTML = `
|
||||
<h2>Diplomas Emitidos</h2>
|
||||
<div class="table-container">
|
||||
<table class="diplomas-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Alumno</th>
|
||||
<th>Email</th>
|
||||
<th>Curso</th>
|
||||
<th>Tipo</th>
|
||||
<th>Fecha</th>
|
||||
<th>Código</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${data.data
|
||||
.map((diploma) => `
|
||||
<tr>
|
||||
<td>${diploma.alumno_nombre}</td>
|
||||
<td>${diploma.alumno_email}</td>
|
||||
<td>${diploma.curso_nombre}</td>
|
||||
<td><span class="badge ${getCourseTypeClass(
|
||||
diploma.curso_tipo
|
||||
)}">${diploma.curso_tipo}</span></td>
|
||||
<td><span class="badge ${getCourseTypeClass(diploma.curso_tipo)}">${formatCourseType(diploma.curso_tipo)}</span></td>
|
||||
<td>${diploma.fecha_formateada}</td>
|
||||
<td class="code">${diploma.codigo_unico}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm" onclick="downloadDiploma('${
|
||||
diploma.codigo_unico
|
||||
}')">
|
||||
Descargar
|
||||
</button>
|
||||
<button class="btn btn-sm" onclick="resendDiploma('${
|
||||
diploma.codigo_unico
|
||||
}')">
|
||||
Reenviar
|
||||
</button>
|
||||
<button class="btn btn-sm" onclick="downloadDiploma('${diploma.codigo_unico}')">Descargar</button>
|
||||
<button class="btn btn-sm" onclick="resendDiploma('${diploma.codigo_unico}')">Reenviar</button>
|
||||
</td>
|
||||
</tr>
|
||||
`
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>`;
|
||||
`)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error:", error);
|
||||
container.innerHTML = `
|
||||
<div class="card error-card">
|
||||
<h2>Error al cargar diplomas</h2>
|
||||
<p>${error.message}</p>
|
||||
<button class="btn" onclick="loadDiplomasSection(this.parentElement)">
|
||||
Reintentar
|
||||
</button>
|
||||
</div>`;
|
||||
const emitidosContainer = document.querySelector("#diploma-tab-emitidos .card");
|
||||
emitidosContainer.innerHTML = `
|
||||
<h2>Error al cargar diplomas</h2>
|
||||
<p>${error.message}</p>
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
function switchDiplomaTab(tabName) {
|
||||
document.querySelectorAll(".tab-btn").forEach((btn) => {
|
||||
btn.classList.toggle("active", btn.dataset.tab === tabName);
|
||||
});
|
||||
|
||||
document.querySelectorAll(".diploma-tab-content").forEach((tab) => {
|
||||
tab.style.display = "none";
|
||||
});
|
||||
|
||||
const activeTab = document.getElementById(`diploma-tab-${tabName}`);
|
||||
if (activeTab) activeTab.style.display = "block";
|
||||
}
|
||||
|
||||
// Funciones auxiliares
|
||||
function generateCoursesPreview(courses) {
|
||||
if (!courses.length) return "<p>No tienes cursos activos</p>";
|
||||
|
|
Loading…
Reference in New Issue