Файловый менеджер - Редактировать - /home/gqdcvggs/izhak.me/school/dashboard.php
Назад
<?php require_once 'config.php'; requireAuth(); $stmt = $pdo->query("SELECT * FROM matieres ORDER BY nom"); $matieres = $stmt->fetchAll(); $stmt = $pdo->query("SELECT * FROM trimestres ORDER BY numero"); $trimestres = $stmt->fetchAll(); $trimestre_actuel = 1; if (!empty($_GET['trimestre'])) { $trimestre_actuel = (int)$_GET['trimestre']; } $stmt = $pdo->prepare("SELECT * FROM trimestres WHERE numero = ?"); $stmt->execute([$trimestre_actuel]); $trim_info = $stmt->fetch(); $onglet_actif = $_GET['tab'] ?? 'tableau-de-bord'; if ($_POST && isset($_POST['action'])) { $action = $_POST['action']; if ($action === 'upload_document' && isStudent()) { $titre = $_POST['titre']; $type = $_POST['type']; $matiere_id = $_POST['matiere_id']; $date_cours = $_POST['date_cours']; $trimestre = $_POST['trimestre']; $note = null; $pas_de_fichier = isset($_POST['pas_de_fichier']) ? 1 : 0; if ($type === 'controle' && isset($_POST['note']) && !empty($_POST['note'])) { $note = $_POST['note']; } $filePath = null; $images_paths = ''; if (!$pas_de_fichier && isset($_FILES['fichier']) && $_FILES['fichier']['error'] === 0) { $uploadDir = 'uploads/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0777, true); } $fileName = time() . '_' . $_FILES['fichier']['name']; $filePath = $uploadDir . $fileName; if (move_uploaded_file($_FILES['fichier']['tmp_name'], $filePath)) { if (!empty($_FILES['images']['name'][0])) { $images = []; foreach ($_FILES['images']['tmp_name'] as $key => $tmp_name) { $img_name = time() . '_' . $key . '_' . $_FILES['images']['name'][$key]; $img_path = $uploadDir . $img_name; if (move_uploaded_file($tmp_name, $img_path)) { $images[] = $img_path; } } $images_paths = implode(',', $images); } } } $stmt = $pdo->prepare("INSERT INTO documents (titre, type, matiere_id, trimestre, fichier_path, images_paths, note, date_cours, pas_de_fichier) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([$titre, $type, $matiere_id, $trimestre, $filePath, $images_paths, $note, $date_cours, $pas_de_fichier]); calculerMoyennesTrimestre($pdo, $trimestre); $matiere_nom = ''; $stmt = $pdo->prepare("SELECT nom FROM matieres WHERE id = ?"); $stmt->execute([$matiere_id]); $matiere = $stmt->fetch(); if ($matiere) { $matiere_nom = $matiere['nom']; } $status_text = $pas_de_fichier ? "Note ajoutée" : "Document uploadé"; sendSMS("Hey Fouad ! $status_text par Izhak : $titre ($type) - $matiere_nom. https://izhak.me/school"); $success = $status_text . " avec succès"; } if ($action === 'approve_document' && isTeacher()) { $doc_id = $_POST['doc_id']; $stmt = $pdo->prepare("UPDATE documents SET approuve = 1 WHERE id = ?"); $stmt->execute([$doc_id]); $success = "Document approuvé"; } if ($action === 'comment_document' && isTeacher()) { $doc_id = $_POST['doc_id']; $commentaire = $_POST['commentaire']; $stmt = $pdo->prepare("UPDATE documents SET commentaire_prof = ? WHERE id = ?"); $stmt->execute([$commentaire, $doc_id]); $success = "Commentaire ajouté avec succès"; } if ($action === 'cloturer_trimestre' && isTeacher()) { $trimestre_id = $_POST['trimestre_id']; $stmt = $pdo->prepare("SELECT numero FROM trimestres WHERE id = ?"); $stmt->execute([$trimestre_id]); $trim = $stmt->fetch(); $stmt = $pdo->prepare(" SELECT AVG(CASE WHEN note = 'excellent' THEN 20 WHEN note = 'parfait' THEN 18 WHEN note = 'tres_bien' THEN 16 WHEN note = 'bien' THEN 14 WHEN note = 'assez_bien' THEN 12 WHEN note = 'suffisant' THEN 10 WHEN note = 'insuffisant' THEN 8 WHEN note = 'echec' THEN 6 WHEN note = 'faible' THEN 4 ELSE NULL END) as moyenne FROM documents WHERE trimestre = ? AND note IS NOT NULL "); $stmt->execute([$trim['numero']]); $result = $stmt->fetch(); $moyenne_figee = round($result['moyenne'], 2); $stmt = $pdo->prepare("UPDATE trimestres SET statut = 'ferme', moyenne_figee = ? WHERE id = ?"); $stmt->execute([$moyenne_figee, $trimestre_id]); $success = "Trimestre clôturé avec succès"; } if ($action === 'update_horaire') { $horaire_data = json_decode($_POST['horaire_data'], true); $pdo->exec("DELETE FROM horaire"); $stmt = $pdo->prepare("INSERT INTO horaire (jour, heure_debut, heure_fin, matiere_id) VALUES (?, ?, ?, ?)"); foreach ($horaire_data as $cours) { $stmt->execute([$cours['jour'], $cours['heure_debut'], $cours['heure_fin'], $cours['matiere_id']]); } $success = "Horaire mis à jour avec succès"; } } function calculerMoyennesTrimestre($pdo, $trimestre) { $stmt = $pdo->prepare("SELECT id FROM matieres"); $stmt->execute(); $matieres = $stmt->fetchAll(); foreach ($matieres as $matiere) { $stmt = $pdo->prepare(" SELECT COUNT(*) as total, AVG(CASE WHEN note = 'excellent' THEN 20 WHEN note = 'parfait' THEN 18 WHEN note = 'tres_bien' THEN 16 WHEN note = 'bien' THEN 14 WHEN note = 'assez_bien' THEN 12 WHEN note = 'suffisant' THEN 10 WHEN note = 'insuffisant' THEN 8 WHEN note = 'echec' THEN 6 WHEN note = 'faible' THEN 4 ELSE NULL END) as moyenne FROM documents WHERE trimestre = ? AND matiere_id = ? AND note IS NOT NULL "); $stmt->execute([$trimestre, $matiere['id']]); $result = $stmt->fetch(); if ($result['total'] > 0) { $stmt = $pdo->prepare(" SELECT id FROM moyennes_trimestre WHERE trimestre_id = (SELECT id FROM trimestres WHERE numero = ?) AND matiere_id = ? "); $stmt->execute([$trimestre, $matiere['id']]); $exists = $stmt->fetch(); if ($exists) { $stmt = $pdo->prepare(" UPDATE moyennes_trimestre SET moyenne = ?, nombre_notes = ? WHERE trimestre_id = (SELECT id FROM trimestres WHERE numero = ?) AND matiere_id = ? "); $stmt->execute([$result['moyenne'], $result['total'], $trimestre, $matiere['id']]); } else { $stmt = $pdo->prepare(" INSERT INTO moyennes_trimestre (trimestre_id, matiere_id, moyenne, nombre_notes) SELECT id, ?, ?, ? FROM trimestres WHERE numero = ? "); $stmt->execute([$matiere['id'], $result['moyenne'], $result['total'], $trimestre]); } } } } $stmt = $pdo->query(" SELECT d.*, m.nom as matiere_nom, m.couleur as matiere_couleur FROM documents d LEFT JOIN matieres m ON d.matiere_id = m.id ORDER BY d.date_upload DESC "); $documents = $stmt->fetchAll(); $stmt = $pdo->query(" SELECT h.*, m.nom as matiere_nom, m.couleur as matiere_couleur FROM horaire h LEFT JOIN matieres m ON h.matiere_id = m.id ORDER BY FIELD(h.jour, 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi'), h.heure_debut "); $horaire = $stmt->fetchAll(); $jours = ['lundi' => 'Lun', 'mardi' => 'Mar', 'mercredi' => 'Mer', 'jeudi' => 'Jeu', 'vendredi' => 'Ven']; $horaire_organise = []; foreach ($horaire as $cours) { $horaire_organise[$cours['jour']][] = $cours; } $stats = []; $graph_data = []; $semestre_stats = []; foreach ($matieres as $matiere) { $stmt = $pdo->prepare(" SELECT COUNT(*) as total, AVG(CASE WHEN note = 'excellent' THEN 20 WHEN note = 'parfait' THEN 18 WHEN note = 'tres_bien' THEN 16 WHEN note = 'bien' THEN 14 WHEN note = 'assez_bien' THEN 12 WHEN note = 'suffisant' THEN 10 WHEN note = 'insuffisant' THEN 8 WHEN note = 'echec' THEN 6 WHEN note = 'faible' THEN 4 ELSE NULL END) as moyenne FROM documents WHERE trimestre = ? AND matiere_id = ? AND note IS NOT NULL "); $stmt->execute([$trimestre_actuel, $matiere['id']]); $stat = $stmt->fetch(); $stats[$matiere['id']] = $stat; $stmt = $pdo->prepare(" SELECT date_cours, CASE WHEN note = 'excellent' THEN 20 WHEN note = 'parfait' THEN 18 WHEN note = 'tres_bien' THEN 16 WHEN note = 'bien' THEN 14 WHEN note = 'assez_bien' THEN 12 WHEN note = 'suffisant' THEN 10 WHEN note = 'insuffisant' THEN 8 WHEN note = 'echec' THEN 6 WHEN note = 'faible' THEN 4 ELSE NULL END as note_val FROM documents WHERE trimestre = ? AND matiere_id = ? AND note IS NOT NULL ORDER BY date_cours ASC "); $stmt->execute([$trimestre_actuel, $matiere['id']]); $notes_timeline = $stmt->fetchAll(); $graph_data[$matiere['id']] = [ 'nom' => $matiere['nom'], 'couleur' => $matiere['couleur'], 'notes' => $notes_timeline ]; } $semestre_actuel = $trim_info['semestre']; $stmt = $pdo->prepare("SELECT * FROM trimestres WHERE semestre = ? AND statut = 'ferme'"); $stmt->execute([$semestre_actuel]); $trimestres_fermes = $stmt->fetchAll(); foreach ($trimestres_fermes as $trim_ferme) { $semestre_stats[$trim_ferme['numero']] = [ 'moyenne' => $trim_ferme['moyenne_figee'], 'statut' => 'ferme' ]; } $total_super = 0; $total_stable = 0; $total_peril = 0; $total_matieres = 0; $moyenne_generale = 0; $total_notes = 0; foreach ($stats as $stat) { if ($stat['moyenne']) { $moyenne = round($stat['moyenne'], 1); $total_matieres++; $moyenne_generale += $moyenne; $total_notes++; if ($moyenne >= 14) { $total_super++; } elseif ($moyenne >= 10) { $total_stable++; } else { $total_peril++; } } } $constat_global = null; if ($total_notes > 0) { $moyenne_generale = round($moyenne_generale / $total_notes, 1); $constat_global = [ 'super' => $total_super, 'stable' => $total_stable, 'peril' => $total_peril, 'moyenne' => $moyenne_generale ]; if ($total_super > $total_matieres / 2) { $constat_global['verdict'] = 'excellent'; $constat_global['message'] = 'Brillant parcours ! Continue sur cette lancée magnifique.'; $constat_global['conseil'] = 'Maintiens cette rigueur tout en préservant ton équilibre personnel.'; } elseif ($total_peril > $total_matieres / 2) { $constat_global['verdict'] = 'critique'; $constat_global['message'] = 'Ton bulletin nécessite une attention immédiate.'; $constat_global['conseil'] = 'Concentre-toi sur les fondamentaux et n\'hésite pas à solliciter de l\'aide.'; } elseif ($moyenne_generale >= 12) { $constat_global['verdict'] = 'correct'; $constat_global['message'] = 'Ton bulletin sera honorable, mais tu peux viser plus haut.'; $constat_global['conseil'] = 'Identifie tes matières fragiles et renforce-les méthodiquement.'; } else { $constat_global['verdict'] = 'fragile'; $constat_global['message'] = 'Ton bulletin sera juste, mais demande davantage d\'engagement.'; $constat_global['conseil'] = 'Établis un planning de travail régulier et cible tes lacunes.'; } } function getNoteColor($note) { $colors = [ 'excellent' => '#10b981', 'parfait' => '#3b82f6', 'tres_bien' => '#8b5cf6', 'bien' => '#06b6d4', 'assez_bien' => '#f59e0b', 'suffisant' => '#f97316', 'insuffisant' => '#ef4444', 'echec' => '#dc2626', 'faible' => '#7f1d1d' ]; return $colors[$note] ?? '#6b7280'; } ?> <!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>Dashboard - Tracking Scolaire</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <style> * { margin: 0; padding: 0; box-sizing: border-box; } :root { color-scheme: light dark; } @media (prefers-color-scheme: light) { :root { --bg: #fafafa; --bg-card: #fff; --border: #e5e5e5; --text: #333; --text-secondary: #666; --text-tertiary: #999; --accent: #333; } } @media (prefers-color-scheme: dark) { :root { --bg: #0f0f0f; --bg-card: #1a1a1a; --border: #2a2a2a; --text: #e5e5e5; --text-secondary: #b3b3b3; --text-tertiary: #808080; --accent: #fff; } } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: var(--bg); color: var(--text); line-height: 1.5; transition: background 0.3s, color 0.3s; } .header { background: var(--bg-card); border-bottom: 1px solid var(--border); padding: 1rem 2rem; display: flex; justify-content: space-between; align-items: center; } .logo { font-size: 1.25rem; font-weight: 600; color: var(--text); } .user-info { display: flex; align-items: center; gap: 1rem; font-size: 0.9rem; color: var(--text-secondary); } .logout-btn { background: var(--border); color: var(--text); border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; text-decoration: none; font-size: 0.85rem; transition: all 0.2s; } .logout-btn:hover { background: var(--text-tertiary); } .container { max-width: 1200px; margin: 0 auto; padding: 2rem; } .trim-selector { display: flex; gap: 0.5rem; margin-bottom: 2rem; background: var(--bg-card); padding: 1rem; border-radius: 4px; border-bottom: 1px solid var(--border); } .trim-selector button { padding: 0.5rem 1rem; border: 1px solid var(--border); background: var(--bg-card); color: var(--text); cursor: pointer; border-radius: 4px; transition: all 0.2s; } .trim-selector button.active { background: var(--text); color: var(--bg); border-color: var(--text); } .trim-selector button:hover { border-color: var(--text); } .trim-info { background: var(--bg-card); padding: 1rem 1.5rem; border-radius: 4px; margin-bottom: 1.5rem; display: flex; justify-content: space-between; align-items: center; border: 1px solid var(--border); } .trim-info-left h3 { font-size: 1rem; margin-bottom: 0.25rem; color: var(--text); } .trim-info-left p { font-size: 0.85rem; color: var(--text-secondary); } .trim-status { display: inline-block; padding: 0.4rem 0.8rem; border-radius: 20px; font-size: 0.8rem; font-weight: 600; } .trim-status.ouvert { background: rgba(16, 185, 129, 0.15); color: #10b981; } .trim-status.ferme { background: rgba(239, 68, 68, 0.15); color: #ef4444; } .btn-cloturer { padding: 0.5rem 1rem; background: #ef4444; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 0.85rem; transition: all 0.2s; } .btn-cloturer:hover { background: #dc2626; } .mobile-nav { display: none; position: fixed; bottom: 0; left: 0; right: 0; background: var(--bg-card); border-top: 1px solid var(--border); padding: 0.5rem; z-index: 1000; box-shadow: 0 -2px 10px rgba(0,0,0,0.05); } .mobile-nav-content { display: flex; justify-content: space-around; } .mobile-tab { display: flex; flex-direction: column; align-items: center; padding: 0.5rem; border: none; background: none; color: var(--text-secondary); cursor: pointer; font-size: 0.75rem; transition: all 0.2s; } .mobile-tab.active { color: var(--text); } .mobile-tab i { font-size: 1.2rem; margin-bottom: 0.25rem; } .tabs { display: flex; background: var(--bg-card); border-bottom: 1px solid var(--border); margin-bottom: 2rem; } .tab { padding: 1rem 1.5rem; cursor: pointer; border: none; background: none; font-size: 0.9rem; color: var(--text-secondary); border-bottom: 2px solid transparent; transition: all 0.2s; } .tab:hover { color: var(--text); } .tab.active { color: var(--text); border-bottom-color: var(--text); } .tab-content { display: none; } .tab-content.active { display: block; animation: fadeIn 0.3s ease-in; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; margin-bottom: 2rem; } .stat-card { background: var(--bg-card); padding: 1.5rem; border-radius: 4px; border: 1px solid var(--border); transition: all 0.2s; } .stat-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.08); } .stat-label { font-size: 0.85rem; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.5rem; } .stat-value { font-size: 2.5rem; font-weight: 700; margin-bottom: 0.5rem; color: var(--text); } .stat-desc { font-size: 0.9rem; color: var(--text-tertiary); } .semestre-historique { background: var(--bg-card); padding: 1.5rem; border-radius: 4px; border: 1px solid var(--border); margin-bottom: 2rem; } .semestre-historique h4 { margin-bottom: 1rem; font-size: 0.95rem; color: var(--text); } .trim-closed-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem; } .trim-closed { padding: 1rem; background: var(--bg); border-left: 3px solid #ef4444; border-radius: 4px; } .trim-closed strong { display: block; margin-bottom: 0.25rem; font-size: 0.9rem; color: var(--text); } .trim-closed span { font-size: 1.5rem; font-weight: 700; color: var(--text); } .chart-container { background: var(--bg-card); padding: 1.5rem; border-radius: 4px; border: 1px solid var(--border); margin-bottom: 2rem; height: 400px; position: relative; } .form-section { background: var(--bg-card); padding: 2rem; border-radius: 4px; border: 1px solid var(--border); margin-bottom: 2rem; } .form-section h4 { margin-bottom: 1.5rem; font-size: 0.95rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text); } .form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.5rem; margin-bottom: 1.5rem; } .form-group { display: flex; flex-direction: column; } .form-group label { font-size: 0.85rem; font-weight: 500; margin-bottom: 0.5rem; color: var(--text); } .form-group input, .form-group select, .form-group textarea { padding: 0.75rem; border: 1px solid var(--border); border-radius: 4px; font-family: inherit; font-size: 0.9rem; background: var(--bg); color: var(--text); transition: all 0.2s; } .form-group input:focus, .form-group select:focus, .form-group textarea:focus { outline: none; border-color: var(--text); box-shadow: 0 0 0 2px rgba(0,0,0,0.05); } .checkbox-group { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1.5rem; } .checkbox-group input { width: 18px; height: 18px; cursor: pointer; } .checkbox-group label { margin: 0; cursor: pointer; color: var(--text); } .btn { padding: 0.75rem 1.5rem; border: none; border-radius: 4px; font-weight: 500; cursor: pointer; transition: all 0.2s; font-size: 0.9rem; } .btn-primary { background: var(--text); color: var(--bg); } .btn-primary:hover { opacity: 0.8; } .btn-secondary { background: var(--border); color: var(--text); font-size: 0.85rem; padding: 0.5rem 1rem; } .btn-secondary:hover { background: var(--text-tertiary); } .documents-section { background: var(--bg-card); padding: 2rem; border-radius: 4px; border: 1px solid var(--border); } .documents-section h4 { margin-bottom: 1.5rem; font-size: 0.95rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text); } .documents-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; } .document-item { background: var(--bg); padding: 1rem; border: 1px solid var(--border); border-radius: 4px; transition: all 0.2s; display: flex; flex-direction: column; } .document-item:hover { border-color: var(--text); box-shadow: 0 4px 12px rgba(0,0,0,0.08); } .doc-title { font-weight: 600; margin-bottom: 0.75rem; word-break: break-word; color: var(--text); } .doc-meta { display: flex; flex-direction: column; gap: 0.5rem; font-size: 0.8rem; color: var(--text-secondary); margin-bottom: 0.75rem; } .doc-badge { display: inline-block; padding: 0.25rem 0.5rem; background: var(--border); border-radius: 4px; width: fit-content; } .doc-note-badge { display: inline-block; padding: 0.5rem; border-radius: 4px; color: white; text-align: center; font-weight: 600; margin-top: auto; } .doc-comment { margin-top: 0.75rem; padding: 0.75rem; background: var(--bg-card); border-left: 2px solid #0066ff; border-radius: 3px; font-size: 0.8rem; color: var(--text-secondary); } .comment-form { display: none; margin-top: 0.75rem; } .comment-form.active { display: flex; flex-direction: column; gap: 0.5rem; } .comment-form textarea { width: 100%; padding: 0.5rem; border: 1px solid var(--border); border-radius: 4px; background: var(--bg); color: var(--text); font-family: inherit; font-size: 0.85rem; } .comment-buttons { display: flex; gap: 0.5rem; } .success-message { background: rgba(16, 185, 129, 0.15); color: #10b981; padding: 1rem; border-radius: 4px; margin-bottom: 1.5rem; border-left: 3px solid #10b981; } .horaire-section { background: var(--bg-card); padding: 2rem; border-radius: 4px; border: 1px solid var(--border); } .horaire-section h4 { margin-bottom: 1.5rem; font-size: 0.95rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text); } .timetable { width: 100%; border-collapse: collapse; margin-bottom: 1.5rem; } .timetable th, .timetable td { padding: 1rem; text-align: left; border: 1px solid var(--border); font-size: 0.9rem; color: var(--text); } .timetable th { background: var(--bg); font-weight: 600; } .time-slot { font-weight: 600; color: var(--text-secondary); } .course-slot { padding: 0.5rem; border-radius: 4px; color: #fff; font-size: 0.85rem; position: relative; display: flex; justify-content: space-between; align-items: center; } .delete-course { cursor: pointer; margin-left: 0.5rem; } .add-course-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem; margin-bottom: 1rem; } @media (max-width: 768px) { .mobile-nav { display: block; } .tabs { display: none; } .container { padding-bottom: 80px; } .form-grid { grid-template-columns: 1fr; } .stats-grid { grid-template-columns: 1fr; } .documents-grid { grid-template-columns: 1fr; } } </style> </head> <body> <div class="header"> <div class="logo">SlySchool</div> <div class="user-info"> <span><?= $_SESSION['nom'] ?? 'Utilisateur' ?></span> <a href="logout.php" class="logout-btn">Déconnexion</a> </div> </div> <div class="container"> <?php if (isset($success)): ?> <div class="success-message"> <i class="fas fa-check-circle"></i> <?= $success ?> </div> <?php endif; ?> <div class="trim-selector"> <?php foreach ($trimestres as $trim): ?> <button class="<?= $trim['numero'] === $trimestre_actuel ? 'active' : '' ?>" onclick="window.location.href='?trimestre=<?= $trim['numero'] ?>&tab=<?= $onglet_actif ?>'"> T<?= $trim['numero'] ?> </button> <?php endforeach; ?> </div> <div class="trim-info"> <div class="trim-info-left"> <h3>Trimestre <?= $trimestre_actuel ?></h3> <p><?= date('d M Y', strtotime($trim_info['date_debut'])) ?> - <?= date('d M Y', strtotime($trim_info['date_fin'])) ?></p> <span class="trim-status <?= $trim_info['statut'] ?>"> <?= ucfirst($trim_info['statut']) ?> </span> </div> <?php if ($trim_info['statut'] === 'ouvert' && isTeacher()): ?> <form method="POST" style="display: inline;"> <input type="hidden" name="action" value="cloturer_trimestre"> <input type="hidden" name="trimestre_id" value="<?= $trim_info['id'] ?>"> <button type="submit" class="btn-cloturer">Clôturer</button> </form> <?php endif; ?> </div> <div class="tabs"> <button class="tab <?= $onglet_actif === 'tableau-de-bord' ? 'active' : '' ?>" onclick="switchTab('tableau-de-bord')"> <i class="fas fa-chart-line"></i> Tableau de bord </button> <button class="tab <?= $onglet_actif === 'documents' ? 'active' : '' ?>" onclick="switchTab('documents')"> <i class="fas fa-file"></i> Documents </button> <button class="tab <?= $onglet_actif === 'emploi-temps' ? 'active' : '' ?>" onclick="switchTab('emploi-temps')"> <i class="fas fa-calendar"></i> Emploi du temps </button> </div> <div id="tableau-de-bord" class="tab-content <?= $onglet_actif === 'tableau-de-bord' ? 'active' : '' ?>"> <div class="stats-grid"> <?php if ($constat_global): ?> <div class="stat-card"> <div class="stat-label">Moyenne générale</div> <div class="stat-value"><?= $constat_global['moyenne'] ?></div> <div class="stat-desc">/20</div> </div> <div class="stat-card"> <div class="stat-label">Matières excellentes</div> <div class="stat-value"><?= $constat_global['super'] ?></div> <div class="stat-desc">≥ 14/20</div> </div> <div class="stat-card"> <div class="stat-label">Matières stables</div> <div class="stat-value"><?= $constat_global['stable'] ?></div> <div class="stat-desc">10-14/20</div> </div> <div class="stat-card"> <div class="stat-label">Matières en péril</div> <div class="stat-value"><?= $constat_global['peril'] ?></div> <div class="stat-desc">< 10/20</div> </div> <?php endif; ?> </div> <?php if (!empty($semestre_stats)): ?> <div class="semestre-historique"> <h4>Historique du Semestre <?= $semestre_actuel ?></h4> <div class="trim-closed-grid"> <?php foreach ($semestre_stats as $num_trim => $data): ?> <div class="trim-closed"> <strong>Trimestre <?= $num_trim ?></strong> <span><?= round($data['moyenne'], 2) ?></span>/20 </div> <?php endforeach; ?> </div> </div> <?php endif; ?> <div class="chart-container"> <canvas id="evolutionChart"></canvas> </div> <?php if ($constat_global): ?> <div class="stat-card"> <h4 style="margin-bottom: 1rem;"><?= ucfirst($constat_global['verdict']) ?></h4> <p style="margin-bottom: 1rem;"><?= $constat_global['message'] ?></p> <p style="font-size: 0.9rem; color: var(--text-secondary);"><?= $constat_global['conseil'] ?></p> </div> <?php endif; ?> </div> <div id="documents" class="tab-content <?= $onglet_actif === 'documents' ? 'active' : '' ?>"> <?php if (isStudent()): ?> <div class="form-section"> <h4>Ajouter un document</h4> <form method="POST" enctype="multipart/form-data"> <input type="hidden" name="action" value="upload_document"> <div class="form-grid"> <div class="form-group"> <label for="titre">Titre *</label> <input type="text" id="titre" name="titre" required> </div> <div class="form-group"> <label for="type">Type *</label> <select id="type" name="type" onchange="toggleNoteField()" required> <option value="">Sélectionner</option> <option value="cours">Cours</option> <option value="exercice">Exercice</option> <option value="controle">Contrôle</option> </select> </div> <div class="form-group"> <label for="matiere_id">Matière *</label> <select id="matiere_id" name="matiere_id" required> <option value="">Sélectionner</option> <?php foreach ($matieres as $m): ?> <option value="<?= $m['id'] ?>"><?= $m['nom'] ?></option> <?php endforeach; ?> </select> </div> <div class="form-group"> <label for="trimestre">Trimestre *</label> <select id="trimestre" name="trimestre" required> <?php foreach ($trimestres as $t): ?> <option value="<?= $t['numero'] ?>" <?= $t['numero'] === $trimestre_actuel ? 'selected' : '' ?>> Trimestre <?= $t['numero'] ?> </option> <?php endforeach; ?> </select> </div> <div class="form-group"> <label for="date_cours">Date du cours *</label> <input type="date" id="date_cours" name="date_cours" required> </div> <div class="form-group" id="note-field" style="display: none;"> <label for="note">Note</label> <select id="note" name="note"> <option value="">Aucune</option> <option value="excellent">Excellent (20)</option> <option value="parfait">Parfait (18)</option> <option value="tres_bien">Très bien (16)</option> <option value="bien">Bien (14)</option> <option value="assez_bien">Assez bien (12)</option> <option value="suffisant">Suffisant (10)</option> <option value="insuffisant">Insuffisant (8)</option> <option value="echec">Échec (6)</option> <option value="faible">Faible (4)</option> </select> </div> </div> <div class="checkbox-group"> <input type="checkbox" id="pas_de_fichier" name="pas_de_fichier" onchange="toggleFileUpload(this.checked)"> <label for="pas_de_fichier">Sans fichier</label> </div> <div id="file-upload-section"> <div class="form-grid"> <div class="form-group"> <label for="fichier">Fichier *</label> <input type="file" id="fichier" name="fichier" required> </div> <div class="form-group"> <label for="images">Images additionnelles</label> <input type="file" id="images" name="images[]" multiple accept="image/*"> </div> </div> </div> <button type="submit" class="btn btn-primary">Ajouter</button> </form> </div> <?php endif; ?> <div class="documents-section"> <h4>Documents</h4> <div class="documents-grid"> <?php foreach ($documents as $doc): ?> <div class="document-item"> <div class="doc-title"><?= $doc['titre'] ?></div> <div class="doc-meta"> <span class="doc-badge"><?= $doc['matiere_nom'] ?></span> <span class="doc-badge"><?= ucfirst($doc['type']) ?></span> <span class="doc-badge">T<?= $doc['trimestre'] ?></span> </div> <?php if ($doc['commentaire_prof']): ?> <div class="doc-comment"> <strong>Prof :</strong> <?= $doc['commentaire_prof'] ?> </div> <?php endif; ?> <?php if (isTeacher()): ?> <button class="btn btn-secondary" onclick="toggleCommentForm(<?= $doc['id'] ?>)" style="margin-top: auto;"> <i class="fas fa-comment"></i> Commenter </button> <div class="comment-form" id="comment-form-<?= $doc['id'] ?>"> <form method="POST"> <input type="hidden" name="action" value="comment_document"> <input type="hidden" name="doc_id" value="<?= $doc['id'] ?>"> <textarea name="commentaire" rows="2" placeholder="Votre commentaire..."><?= $doc['commentaire_prof'] ?? '' ?></textarea> <div class="comment-buttons"> <button type="submit" class="btn btn-primary" style="padding: 0.4rem 0.8rem; font-size: 0.8rem;">OK</button> <button type="button" class="btn btn-secondary" onclick="toggleCommentForm(<?= $doc['id'] ?>)" style="padding: 0.4rem 0.8rem; font-size: 0.8rem;">X</button> </div> </form> </div> <?php endif; ?> <?php if ($doc['note']): ?> <div class="doc-note-badge" style="background-color: <?= getNoteColor($doc['note']) ?>;"> <?= $doc['note'] ?> </div> <?php endif; ?> </div> <?php endforeach; ?> </div> </div> </div> <div id="emploi-temps" class="tab-content <?= $onglet_actif === 'emploi-temps' ? 'active' : '' ?>"> <div class="horaire-section"> <h4>Emploi du temps</h4> <?php if (isTeacher()): ?> <div class="add-course-form"> <div class="form-group"> <label for="add-jour">Jour</label> <select id="add-jour"> <option value="">Sélectionner</option> <option value="lundi">Lundi</option> <option value="mardi">Mardi</option> <option value="mercredi">Mercredi</option> <option value="jeudi">Jeudi</option> <option value="vendredi">Vendredi</option> </select> </div> <div class="form-group"> <label for="add-heure-debut">Heure début</label> <input type="time" id="add-heure-debut"> </div> <div class="form-group"> <label for="add-heure-fin">Heure fin</label> <input type="time" id="add-heure-fin"> </div> <div class="form-group"> <label for="add-matiere">Matière</label> <select id="add-matiere"> <option value="">Sélectionner</option> <?php foreach ($matieres as $m): ?> <option value="<?= $m['id'] ?>"><?= $m['nom'] ?></option> <?php endforeach; ?> </select> </div> </div> <button class="btn btn-primary" onclick="addCourse()" style="margin-bottom: 1rem;">Ajouter cours</button> <button class="btn btn-primary" onclick="saveHoraire()">Enregistrer</button> <?php endif; ?> <table class="timetable" style="margin-top: 1rem;"> <thead> <tr> <th>Horaire</th> <th>Lundi</th> <th>Mardi</th> <th>Mercredi</th> <th>Jeudi</th> <th>Vendredi</th> </tr> </thead> <tbody id="timetable-body"></tbody> </table> </div> </div> </div> <div class="mobile-nav"> <div class="mobile-nav-content"> <button class="mobile-tab <?= $onglet_actif === 'tableau-de-bord' ? 'active' : '' ?>" onclick="switchTab('tableau-de-bord')"> <i class="fas fa-chart-line"></i> <span>Tableau</span> </button> <button class="mobile-tab <?= $onglet_actif === 'documents' ? 'active' : '' ?>" onclick="switchTab('documents')"> <i class="fas fa-file"></i> <span>Documents</span> </button> <button class="mobile-tab <?= $onglet_actif === 'emploi-temps' ? 'active' : '' ?>" onclick="switchTab('emploi-temps')"> <i class="fas fa-calendar"></i> <span>Horaire</span> </button> </div> </div> <script> function switchTab(tabName) { document.querySelectorAll('.tab-content').forEach(tab => { tab.classList.remove('active'); }); document.getElementById(tabName).classList.add('active'); document.querySelectorAll('.tab').forEach(tab => { tab.classList.remove('active'); }); document.querySelectorAll('.mobile-tab').forEach(tab => { tab.classList.remove('active'); }); event.target.closest('.tab, .mobile-tab')?.classList.add('active'); const url = new URL(window.location); url.searchParams.set('tab', tabName); window.history.replaceState({}, '', url); } function toggleNoteField() { const type = document.getElementById('type').value; const noteField = document.getElementById('note-field'); noteField.style.display = type === 'controle' ? 'flex' : 'none'; } function toggleFileUpload(isChecked) { const fileSection = document.getElementById('file-upload-section'); const fichierInput = document.getElementById('fichier'); if (isChecked) { fileSection.style.display = 'none'; fichierInput.removeAttribute('required'); } else { fileSection.style.display = 'block'; fichierInput.setAttribute('required', ''); } } function toggleCommentForm(docId) { const form = document.getElementById('comment-form-' + docId); form.classList.toggle('active'); } let horaireData = <?= json_encode($horaire) ?>; let matieres = <?= json_encode($matieres) ?>; let jours = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi']; function renderTimetable() { const tbody = document.getElementById('timetable-body'); tbody.innerHTML = ''; const allHours = new Set(); horaireData.forEach(cours => { allHours.add(cours.heure_debut); }); const sortedHours = Array.from(allHours).sort(); sortedHours.forEach(heure => { const row = document.createElement('tr'); const timeCell = document.createElement('td'); timeCell.className = 'time-slot'; const heureFin = horaireData.find(c => c.heure_debut === heure)?.heure_fin || ''; timeCell.textContent = `${heure.substring(0, 5)}-${heureFin.substring(0, 5)}`; row.appendChild(timeCell); jours.forEach(jour => { const cell = document.createElement('td'); const cours = horaireData.find(c => c.jour === jour && c.heure_debut === heure); if (cours) { const matiere = matieres.find(m => m.id == cours.matiere_id); const slot = document.createElement('div'); slot.className = 'course-slot'; slot.style.backgroundColor = matiere.couleur; slot.textContent = matiere.nom; const deleteBtn = document.createElement('span'); deleteBtn.className = 'delete-course'; deleteBtn.innerHTML = '<i class="fas fa-times"></i>'; deleteBtn.onclick = () => deleteCourse(cours); slot.appendChild(deleteBtn); cell.appendChild(slot); } else { cell.innerHTML = '<div style="color: var(--text-tertiary);">-</div>'; } row.appendChild(cell); }); tbody.appendChild(row); }); } function addCourse() { const jour = document.getElementById('add-jour').value; const heureDebut = document.getElementById('add-heure-debut').value; const heureFin = document.getElementById('add-heure-fin').value; const matiereId = document.getElementById('add-matiere').value; if (!jour || !heureDebut || !heureFin || !matiereId) { alert('Remplis tous les champs'); return; } const matiere = matieres.find(m => m.id == matiereId); horaireData.push({ jour: jour, heure_debut: heureDebut + ':00', heure_fin: heureFin + ':00', matiere_id: matiereId, matiere_nom: matiere.nom, matiere_couleur: matiere.couleur }); document.getElementById('add-jour').value = ''; document.getElementById('add-heure-debut').value = ''; document.getElementById('add-heure-fin').value = ''; document.getElementById('add-matiere').value = ''; renderTimetable(); } function deleteCourse(cours) { horaireData = horaireData.filter(c => !(c.jour === cours.jour && c.heure_debut === cours.heure_debut && c.matiere_id == cours.matiere_id) ); renderTimetable(); } function saveHoraire() { const form = document.createElement('form'); form.method = 'POST'; form.innerHTML = ` <input type="hidden" name="action" value="update_horaire"> <input type="hidden" name="horaire_data" value='${JSON.stringify(horaireData)}'> `; document.body.appendChild(form); form.submit(); } renderTimetable(); const graphData = <?= json_encode($graph_data) ?>; const ctx = document.getElementById('evolutionChart'); if (ctx) { const datasets = []; const allDates = new Set(); Object.values(graphData).forEach(matiere => { if (matiere.notes && matiere.notes.length > 0) { matiere.notes.forEach(note => { allDates.add(note.date_cours); }); } }); const sortedDates = Array.from(allDates).sort(); Object.values(graphData).forEach(matiere => { if (matiere.notes && matiere.notes.length > 0) { const data = sortedDates.map(date => { const note = matiere.notes.find(n => n.date_cours === date); return note ? note.note_val : null; }); datasets.push({ label: matiere.nom, data: data, borderColor: matiere.couleur, backgroundColor: matiere.couleur + '33', tension: 0.3, spanGaps: true }); } }); new Chart(ctx, { type: 'line', data: { labels: sortedDates.map(date => { const d = new Date(date); return d.toLocaleDateString('fr-FR', { day: '2-digit', month: 'short' }); }), datasets: datasets }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top', }, title: { display: true, text: 'Évolution des notes par matière' } }, scales: { y: { beginAtZero: true, max: 20, ticks: { stepSize: 2 }, grid: { color: function(context) { if (context.tick.value === 10) { return '#ffc107'; } else if (context.tick.value === 14) { return '#28a745'; } return 'var(--border)'; }, lineWidth: function(context) { if (context.tick.value === 10 || context.tick.value === 14) { return 2; } return 1; } } } } } }); } </script> </body> </html>
| ver. 1.6 |
Github
|
.
| PHP 8.1.33 | Генерация страницы: 0.01 |
proxy
|
phpinfo
|
Настройка