gestion alumnos actualizado
This commit is contained in:
parent
45368a331f
commit
5cda47e50b
|
@ -14,27 +14,27 @@ $profesorId = $_SESSION['profesor']['id'] ?? null;
|
|||
try {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$alumnoId = $_GET['alumno_id'] ?? null;
|
||||
|
||||
$alumnoId = $_GET['alumno_id'] ?? null;
|
||||
|
||||
if ($alumnoId) {
|
||||
// Obtener cursos de un alumno específico
|
||||
$query = "SELECT c.* FROM cursos c
|
||||
JOIN alumnos_cursos ac ON c.id = ac.curso_id
|
||||
WHERE ac.alumno_id = ? AND c.profesor_id = ?";
|
||||
// Obtener cursos de un alumno específico (con tipo)
|
||||
$query = "SELECT c.id, c.nombre, c.tipo FROM cursos c
|
||||
JOIN alumnos_cursos ac ON c.id = ac.curso_id
|
||||
WHERE ac.alumno_id = ? AND c.profesor_id = ?";
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute([$alumnoId, $profesorId]);
|
||||
} else {
|
||||
// Obtener todos los alumnos
|
||||
$query = "SELECT * FROM alumnos";
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'data' => $stmt->fetchAll(PDO::FETCH_ASSOC)
|
||||
]);
|
||||
break;
|
||||
// Obtener todos los alumnos
|
||||
$query = "SELECT * FROM alumnos";
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'data' => $stmt->fetchAll(PDO::FETCH_ASSOC)
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
|
|
@ -27,31 +27,51 @@ try {
|
|||
]);
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
case 'POST':
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (empty($data['nombre']) || empty($data['email'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'Nombre y email son requeridos']);
|
||||
exit;
|
||||
}
|
||||
if (empty($data['nombre']) || empty($data['email'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'Nombre y email son requeridos']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO alumnos (nombre, email, telefono)
|
||||
VALUES (?, ?, ?)
|
||||
");
|
||||
$stmt->execute([
|
||||
$data['nombre'],
|
||||
$data['email'],
|
||||
$data['telefono'] ?? null
|
||||
]);
|
||||
$pdo->beginTransaction();
|
||||
try {
|
||||
// Insertar alumno
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO alumnos (nombre, email, telefono)
|
||||
VALUES (?, ?, ?)
|
||||
");
|
||||
$stmt->execute([
|
||||
$data['nombre'],
|
||||
$data['email'],
|
||||
$data['telefono'] ?? null
|
||||
]);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => $pdo->lastInsertId(),
|
||||
'message' => 'Alumno creado exitosamente'
|
||||
]);
|
||||
break;
|
||||
$alumnoId = $pdo->lastInsertId();
|
||||
|
||||
// Si viene curso_id, asignar también a curso
|
||||
if (!empty($data['curso_id'])) {
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO alumnos_cursos (alumno_id, curso_id, estado)
|
||||
VALUES (?, ?, 'cursando')
|
||||
");
|
||||
$stmt->execute([$alumnoId, $data['curso_id']]);
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => $alumnoId,
|
||||
'message' => 'Alumno creado y asignado exitosamente'
|
||||
]);
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => 'Error al registrar: ' . $e->getMessage()]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PUT':
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
@ -75,6 +95,30 @@ try {
|
|||
$data['telefono'] ?? null,
|
||||
$data['id']
|
||||
]);
|
||||
|
||||
// Si curso_id viene en la actualización, actualizar también el curso
|
||||
if (!empty($data['curso_id'])) {
|
||||
// Verifica si ya tiene una relación previa
|
||||
$check = $pdo->prepare("SELECT id FROM alumnos_cursos WHERE alumno_id = ?");
|
||||
$check->execute([$data['id']]);
|
||||
|
||||
if ($check->fetch()) {
|
||||
// Si ya tiene relación, actualizamos el curso asignado
|
||||
$updateCurso = $pdo->prepare("
|
||||
UPDATE alumnos_cursos SET curso_id = ?, estado = 'cursando'
|
||||
WHERE alumno_id = ?
|
||||
");
|
||||
$updateCurso->execute([$data['curso_id'], $data['id']]);
|
||||
} else {
|
||||
// Si no tiene relación previa, la insertamos
|
||||
$insertCurso = $pdo->prepare("
|
||||
INSERT INTO alumnos_cursos (alumno_id, curso_id, estado)
|
||||
VALUES (?, ?, 'cursando')
|
||||
");
|
||||
$insertCurso->execute([$data['id'], $data['curso_id']]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
|
|
|
@ -14,15 +14,22 @@ $profesorId = $_SESSION['profesor']['id'];
|
|||
switch ($method) {
|
||||
case 'GET':
|
||||
try {
|
||||
$query = "SELECT * FROM cursos WHERE profesor_id = ?";
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute([$profesorId]);
|
||||
echo json_encode($stmt->fetchAll());
|
||||
$tipo = $_GET['tipo'] ?? null;
|
||||
if ($tipo) {
|
||||
$query = "SELECT * FROM cursos WHERE profesor_id = ? AND tipo = ?";
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute([$profesorId, $tipo]);
|
||||
} else {
|
||||
$query = "SELECT * FROM cursos WHERE profesor_id = ?";
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute([$profesorId]);
|
||||
}
|
||||
echo json_encode(['success' => true, 'data' => $stmt->fetchAll()]);
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Error al cargar cursos']);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
@ -50,8 +57,9 @@ switch ($method) {
|
|||
echo json_encode(['success' => true, 'id' => $pdo->lastInsertId()]);
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Error al crear curso']);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'PUT':
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require '../includes/config.php';
|
||||
|
||||
if (!is_logged_in()) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['success' => false, 'error' => 'No autenticado']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$alumnos = $data['alumnos'] ?? [];
|
||||
|
||||
if (empty($alumnos)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'No se enviaron alumnos']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Paso 1: Validar todos los cursos
|
||||
$errores = [];
|
||||
$profesorId = $_SESSION['profesor']['id'] ?? null;
|
||||
|
||||
foreach ($alumnos as $index => $alumno) {
|
||||
$nombreCurso = trim($alumno['nombreCurso']);
|
||||
$tipoCurso = trim($alumno['tipoCurso']);
|
||||
|
||||
$stmt = $pdo->prepare("SELECT id FROM cursos WHERE nombre = ? AND tipo = ? AND profesor_id = ?");
|
||||
$stmt->execute([$nombreCurso, $tipoCurso, $profesorId]);
|
||||
$curso = $stmt->fetch();
|
||||
|
||||
if (!$curso) {
|
||||
$errores[] = "El curso \"{$nombreCurso}\" de tipo \"{$tipoCurso}\" en {$alumno['nombre']} ({$alumno['email']}) es inválido.";
|
||||
} else {
|
||||
$alumnos[$index]['curso_id'] = $curso['id']; // Guardamos para usar después
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($errores)) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => "Error en cursos: " . count($errores) . " conflictos encontrados",
|
||||
'conflicts' => $errores
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Paso 2: Insertar alumnos
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
foreach ($alumnos as $a) {
|
||||
$stmt = $pdo->prepare("INSERT INTO alumnos (nombre, email, telefono) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$a['nombre'], $a['email'], $a['telefono'] ?? null]);
|
||||
$alumnoId = $pdo->lastInsertId();
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO alumnos_cursos (alumno_id, curso_id, estado) VALUES (?, ?, 'cursando')");
|
||||
$stmt->execute([$alumnoId, $a['curso_id']]);
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
echo json_encode(['success' => true, 'message' => 'Todos los alumnos fueron importados correctamente.']);
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => 'Error al guardar en la base de datos: ' . $e->getMessage()]);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -331,7 +331,10 @@ function renderDashboard(container, data) {
|
|||
function loadProfessorCourses(container) {
|
||||
fetch(`api/cursos.php?profesor_id=${getProfesorId()}`)
|
||||
.then((response) => response.json())
|
||||
.then((courses) => {
|
||||
.then((res) => {
|
||||
if (!res.success) throw new Error("No se pudieron cargar los cursos");
|
||||
const courses = res.data;
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="card">
|
||||
<h2>Mis Cursos</h2>
|
||||
|
@ -388,12 +391,8 @@ function loadProfessorCourses(container) {
|
|||
(course) => `
|
||||
<tr>
|
||||
<td>${course.nombre}</td>
|
||||
<td class="description-cell">${
|
||||
course.descripcion || "-"
|
||||
}</td>
|
||||
<td><span class="badge ${getCourseTypeClass(
|
||||
course.tipo
|
||||
)}">${course.tipo}</span></td>
|
||||
<td class="description-cell">${course.descripcion || "-"}</td>
|
||||
<td><span class="badge ${getCourseTypeClass(course.tipo)}">${formatCourseType(course.tipo)}</span></td>
|
||||
<td>
|
||||
<span class="badge ${
|
||||
course.estado === "activo"
|
||||
|
@ -407,12 +406,8 @@ function loadProfessorCourses(container) {
|
|||
</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="deleteCourse(${
|
||||
course.id
|
||||
})">Eliminar</button>
|
||||
<button class="btn btn-sm" onclick="editCourse(${course.id})">Editar</button>
|
||||
<button class="btn btn-sm btn-danger" onclick="deleteCourse(${course.id})">Eliminar</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -425,14 +420,18 @@ function loadProfessorCourses(container) {
|
|||
</div>`;
|
||||
|
||||
setupCourseForm();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Error al cargar cursos:", err);
|
||||
container.innerHTML = `<div class="card error-card">No se pudieron cargar los cursos</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
function formatCourseType(type) {
|
||||
const types = {
|
||||
'pildora': 'Píldora',
|
||||
'inyeccion': 'Inyección',
|
||||
'tratamiento': 'Tratamiento'
|
||||
pildora: "Píldora",
|
||||
inyeccion: "Inyección",
|
||||
tratamiento: "Tratamiento"
|
||||
};
|
||||
return types[type] || type;
|
||||
}
|
||||
|
@ -445,7 +444,7 @@ function setupCourseForm() {
|
|||
: null;
|
||||
|
||||
if (courseTypeSelect && competenciasInput) {
|
||||
courseTypeSelect.addEventListener('change', function() {
|
||||
courseTypeSelect.addEventListener('change', function () {
|
||||
const isTratamiento = this.value === 'tratamiento';
|
||||
competencesField.classList.toggle('oculto', !isTratamiento);
|
||||
competenciasInput.required = isTratamiento;
|
||||
|
@ -458,7 +457,7 @@ function setupCourseForm() {
|
|||
competencesField.classList.toggle('oculto', !isTratamiento);
|
||||
competenciasInput.required = isTratamiento;
|
||||
}
|
||||
|
||||
|
||||
const form = document.getElementById("courseForm");
|
||||
if (!form) return;
|
||||
|
||||
|
@ -482,7 +481,7 @@ function setupCourseForm() {
|
|||
descripcion: formData.get("descripcion"),
|
||||
competencias: formData.get("competencias"),
|
||||
tipo: formData.get("tipo"),
|
||||
estado: formData.get("estado"),
|
||||
estado: formData.get("estado"),
|
||||
profesor_id: getProfesorId(),
|
||||
};
|
||||
|
||||
|
@ -532,8 +531,8 @@ window.updateCourse = function (id, data) {
|
|||
window.editCourse = function (id) {
|
||||
fetch(`api/cursos.php?profesor_id=${getProfesorId()}`)
|
||||
.then((response) => response.json())
|
||||
.then((courses) => {
|
||||
const course = courses.find((c) => c.id == id);
|
||||
.then((res) => {
|
||||
const course = res.data.find((c) => c.id == id);
|
||||
if (!course) return;
|
||||
|
||||
const form = document.getElementById("courseForm");
|
||||
|
@ -562,6 +561,7 @@ window.editCourse = function (id) {
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
window.deleteCourse = function (id) {
|
||||
if (!confirm("¿Estás seguro de eliminar este curso?")) return;
|
||||
|
||||
|
@ -613,48 +613,104 @@ function loadStudentsManagement(container) {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
function renderStudentForm() {
|
||||
return `
|
||||
<div class="card">
|
||||
<h2>Gestión de Alumnos</h2>
|
||||
<form id="studentForm">
|
||||
<div class="form-grid">
|
||||
<div class="form-group">
|
||||
<label for="nombre">Nombre*</label>
|
||||
<input type="text" id="nombre" name="nombre" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email*</label>
|
||||
<input type="email" id="email" name="email" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="telefono">Teléfono</label>
|
||||
<input type="tel" id="telefono" name="telefono">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="button" class="btn btn-outline" onclick="resetStudentForm()" id="cancelBtn" style="display:none;">
|
||||
Cancelar
|
||||
</button>
|
||||
<button type="submit" class="btn">
|
||||
<span id="submitText">Guardar</span>
|
||||
<span class="spinner-border spinner-border-sm" id="submitSpinner" style="display:none;"></span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>`;
|
||||
<div class="card">
|
||||
<div class="card-header" style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<h2>Gestión de Alumnos</h2>
|
||||
<label class="btn btn-primary" style="margin: 0;">
|
||||
Importar CSV
|
||||
<input type="file" accept=".csv" onchange="handleCSVUpload(event)" style="display: none;">
|
||||
</label>
|
||||
</div>
|
||||
<form id="studentForm">
|
||||
<div class="form-grid">
|
||||
<div class="form-group">
|
||||
<label for="nombre">Nombre*</label>
|
||||
<input type="text" id="nombre" name="nombre" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email*</label>
|
||||
<input type="email" id="email" name="email" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="telefono">Teléfono</label>
|
||||
<input type="tel" id="telefono" name="telefono">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-grid">
|
||||
<div class="form-group">
|
||||
<label for="tipoCurso">Tipo de Curso*</label>
|
||||
<select id="tipoCurso" required>
|
||||
<option value="">Seleccionar tipo</option>
|
||||
<option value="inyeccion">Inyección</option>
|
||||
<option value="pildora">Píldora</option>
|
||||
<option value="tratamiento">Tratamiento</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="curso">Curso*</label>
|
||||
<select id="curso" required>
|
||||
<option value="">Selecciona primero un tipo</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="button" class="btn btn-outline" onclick="resetStudentForm()" id="cancelBtn" style="display:none;">
|
||||
Cancelar
|
||||
</button>
|
||||
<button type="submit" class="btn">
|
||||
<span id="submitText">Guardar</span>
|
||||
<span class="spinner-border spinner-border-sm" id="submitSpinner" style="display:none;"></span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
|
||||
function setupStudentForm() {
|
||||
const form = document.getElementById("studentForm");
|
||||
if (!form) return;
|
||||
|
||||
form.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
submitStudentForm();
|
||||
// Referencias a selects
|
||||
const tipoCurso = document.getElementById("tipoCurso");
|
||||
const curso = document.getElementById("curso");
|
||||
|
||||
// Cargar cursos dinámicamente
|
||||
tipoCurso.addEventListener("change", () => {
|
||||
const tipo = tipoCurso.value;
|
||||
curso.innerHTML = '<option value="">Cargando...</option>';
|
||||
fetch(`api/cursos.php?tipo=${tipo}`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
curso.innerHTML = '<option value="">Seleccionar curso</option>';
|
||||
data.data.forEach((c) => {
|
||||
const opt = document.createElement("option");
|
||||
opt.value = c.id;
|
||||
opt.textContent = c.nombre;
|
||||
curso.appendChild(opt);
|
||||
});
|
||||
} else {
|
||||
curso.innerHTML = '<option value="">Sin resultados</option>';
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
curso.innerHTML = '<option value="">Error al cargar</option>';
|
||||
});
|
||||
});
|
||||
|
||||
// Configurar búsqueda
|
||||
// Guardar alumno
|
||||
form.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
submitStudentForm(); // ✅ Usa función unificada que detecta si es edición o nuevo
|
||||
});
|
||||
|
||||
const searchInput = document.getElementById("studentSearch");
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener("input", function () {
|
||||
|
@ -662,6 +718,7 @@ function setupStudentForm() {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
function submitStudentForm() {
|
||||
const form = document.getElementById("studentForm");
|
||||
const submitBtn = form.querySelector('button[type="submit"]');
|
||||
|
@ -678,12 +735,12 @@ function submitStudentForm() {
|
|||
nombre: formData.get("nombre"),
|
||||
email: formData.get("email"),
|
||||
telefono: formData.get("telefono"),
|
||||
curso_id: document.getElementById("curso").value, // ✅ Cambio aquí
|
||||
};
|
||||
|
||||
const isEdit = form.dataset.editing === "true";
|
||||
const studentId = form.dataset.studentId;
|
||||
|
||||
const url = "api/alumnos.php" + (isEdit ? "" : "");
|
||||
const url = "api/alumnos.php";
|
||||
const method = isEdit ? "PUT" : "POST";
|
||||
|
||||
if (isEdit) {
|
||||
|
@ -772,6 +829,24 @@ window.editStudent = function (id) {
|
|||
document.getElementById("submitText").textContent = "Actualizar";
|
||||
document.getElementById("cancelBtn").style.display = "inline-block";
|
||||
|
||||
// 👇 Precargar tipo y curso si el alumno tiene asignación
|
||||
fetch(`api/alumnos-cursos.php?alumno_id=${id}`)
|
||||
.then((res) => res.json())
|
||||
.then((asignaciones) => {
|
||||
if (asignaciones.success && asignaciones.data.length > 0) {
|
||||
const curso = asignaciones.data[0];
|
||||
const tipoCursoSelect = document.getElementById("tipoCurso");
|
||||
const cursoSelect = document.getElementById("curso");
|
||||
|
||||
tipoCursoSelect.value = curso.tipo;
|
||||
tipoCursoSelect.dispatchEvent(new Event("change"));
|
||||
|
||||
setTimeout(() => {
|
||||
cursoSelect.value = curso.id;
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
|
||||
form.scrollIntoView({ behavior: "smooth" });
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -780,6 +855,11 @@ window.editStudent = function (id) {
|
|||
};
|
||||
|
||||
window.deleteStudent = function (id) {
|
||||
if (!id) {
|
||||
showToast("error", "ID de alumno no proporcionado");
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`api/alumnos.php?id=${id}`, {
|
||||
method: "DELETE",
|
||||
})
|
||||
|
@ -796,6 +876,8 @@ window.deleteStudent = function (id) {
|
|||
showToast("error", error.message || "Error al eliminar alumno");
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
window.confirmDeleteStudent = function (id) {
|
||||
showModal(
|
||||
"Confirmar eliminación",
|
||||
|
@ -809,11 +891,12 @@ window.confirmDeleteStudent = function (id) {
|
|||
{
|
||||
text: "Eliminar",
|
||||
class: "btn-danger",
|
||||
handler: () => deleteStudent(id),
|
||||
handler: "deleteStudent(" + id + ")"
|
||||
},
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
window.resetStudentForm = function () {
|
||||
const form = document.getElementById("studentForm");
|
||||
form.reset();
|
||||
|
@ -870,13 +953,13 @@ function renderStudentsTable(alumnos) {
|
|||
<div class="search-box">
|
||||
<input type="text" id="studentSearch" placeholder="Buscar alumno...">
|
||||
</div>
|
||||
<button class="btn btn-sm btn-primary" onclick="showAssignStudentModal()">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||||
<path d="M12 5v14"></path>
|
||||
<path d="M5 12h14"></path>
|
||||
</svg>
|
||||
Vincular a Curso
|
||||
|
||||
<input type="file" id="csvInput" accept=".csv" style="display:none;" onchange="handleCSVUpload(event)">
|
||||
<button class="btn btn-sm btn-primary" onclick="document.getElementById('csvInput').click()">
|
||||
Importar CSV
|
||||
</button>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
|
@ -1260,4 +1343,51 @@ window.resendDiploma = function (codigo) {
|
|||
console.error("Error:", error);
|
||||
alert("Error al reenviar el diploma");
|
||||
});
|
||||
|
||||
window.handleCSVUpload = function (event) {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
const lines = e.target.result.split("\n").map(line => line.trim()).filter(Boolean);
|
||||
const alumnos = [];
|
||||
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
const [nombre, email, telefono, tipoCurso, nombreCurso] = lines[i].split(",").map(s => s.trim());
|
||||
|
||||
// Validación básica de columnas mínimas
|
||||
if (!nombre || !email || !tipoCurso || !nombreCurso) continue;
|
||||
|
||||
alumnos.push({ nombre, email, telefono, tipoCurso, nombreCurso });
|
||||
}
|
||||
|
||||
fetch("api/importar_csv.php", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ alumnos }),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showToast("success", data.message || "Alumnos importados correctamente");
|
||||
loadStudentsManagement(document.querySelector("#students-content"));
|
||||
} else {
|
||||
// Si vienen errores detallados, los mostramos
|
||||
if (data.conflicts && data.conflicts.length > 0) {
|
||||
const list = `<ul>${data.conflicts.map(msg => `<li>${msg}</li>`).join("")}</ul>`;
|
||||
showModal("Errores en Importación CSV", `<p>No se importaron alumnos por los siguientes errores:</p>${list}`);
|
||||
} else {
|
||||
showToast("error", data.error || "Error al importar alumnos");
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
showToast("error", "Error al procesar el archivo");
|
||||
});
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ session_start();
|
|||
$host = 'localhost';
|
||||
$db = 'diplomaster';
|
||||
$user = 'root';
|
||||
$pass = '';
|
||||
$pass = 'root';
|
||||
$charset = 'utf8mb4';
|
||||
|
||||
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
|
||||
|
|
Loading…
Reference in New Issue