Feat: add class page
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify, current_app
|
||||
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify, current_app, abort
|
||||
from models import db, ClassGroup, Student, Assessment
|
||||
from forms import ClassGroupForm
|
||||
from utils import handle_db_errors, ValidationError
|
||||
@@ -148,16 +148,105 @@ def delete(id):
|
||||
|
||||
return redirect(url_for('classes'))
|
||||
|
||||
@bp.route('/<int:id>/details')
|
||||
@bp.route('/<int:id>', methods=['GET'])
|
||||
@handle_db_errors
|
||||
def details(id):
|
||||
"""Page de détail d'une classe avec ses étudiants et évaluations."""
|
||||
"""Redirection transparente vers le dashboard de classe."""
|
||||
return redirect(url_for('classes.dashboard', id=id))
|
||||
|
||||
@bp.route('/<int:id>/dashboard')
|
||||
@handle_db_errors
|
||||
def dashboard(id):
|
||||
"""Page de présentation de classe avec statistiques."""
|
||||
# Récupération paramètre trimestre
|
||||
trimester = request.args.get('trimestre', type=int)
|
||||
if trimester and trimester not in [1, 2, 3]:
|
||||
trimester = None
|
||||
|
||||
# Repository optimisé
|
||||
class_repo = ClassRepository()
|
||||
class_group = class_repo.find_with_statistics(id, trimester)
|
||||
|
||||
if not class_group:
|
||||
abort(404)
|
||||
|
||||
current_app.logger.debug(f'Dashboard classe {id} affiché pour trimestre {trimester}')
|
||||
|
||||
return render_template('class_dashboard.html',
|
||||
class_group=class_group,
|
||||
selected_trimester=trimester)
|
||||
|
||||
@bp.route('/<int:id>/stats')
|
||||
@handle_db_errors
|
||||
def get_stats_api(id):
|
||||
"""API JSON pour statistiques dynamiques (AJAX)."""
|
||||
# Récupération paramètre trimestre
|
||||
trimester = request.args.get('trimestre', type=int)
|
||||
if trimester and trimester not in [1, 2, 3]:
|
||||
trimester = None
|
||||
|
||||
# Repository optimisé
|
||||
class_repo = ClassRepository()
|
||||
class_group = class_repo.find_with_statistics(id, trimester)
|
||||
|
||||
if not class_group:
|
||||
abort(404)
|
||||
|
||||
try:
|
||||
# Construction de la réponse JSON avec les nouvelles méthodes du modèle
|
||||
quantity_stats = class_group.get_trimester_statistics(trimester)
|
||||
domain_analysis = class_group.get_domain_analysis(trimester)
|
||||
competence_analysis = class_group.get_competence_analysis(trimester)
|
||||
class_results = class_group.get_class_results(trimester)
|
||||
|
||||
# Compter le nombre d'évaluations selon le trimestre
|
||||
if hasattr(class_group, '_filtered_assessments'):
|
||||
assessments_count = len(class_group._filtered_assessments)
|
||||
current_app.logger.debug(f'Assessments count from _filtered_assessments: {assessments_count}')
|
||||
else:
|
||||
# Fallback si _filtered_assessments n'existe pas
|
||||
if trimester:
|
||||
assessments_count = len([a for a in class_group.assessments if a.trimester == trimester])
|
||||
else:
|
||||
assessments_count = len(class_group.assessments)
|
||||
current_app.logger.debug(f'Assessments count from fallback: {assessments_count}')
|
||||
|
||||
current_app.logger.debug(f'Final assessments_count value: {assessments_count}, type: {type(assessments_count)}')
|
||||
|
||||
stats = {
|
||||
"quantity": {
|
||||
"total": quantity_stats["total"],
|
||||
"completed": quantity_stats["completed"],
|
||||
"in_progress": quantity_stats["in_progress"],
|
||||
"not_started": quantity_stats["not_started"]
|
||||
},
|
||||
"domains": domain_analysis["domains"], # Extraire directement le tableau
|
||||
"competences": competence_analysis["competences"], # Extraire directement le tableau
|
||||
"results": {
|
||||
"average": class_results["overall_statistics"]["mean"],
|
||||
"min": class_results["overall_statistics"]["min"],
|
||||
"max": class_results["overall_statistics"]["max"],
|
||||
"median": class_results["overall_statistics"]["median"],
|
||||
"std_dev": class_results["overall_statistics"]["std_dev"],
|
||||
"assessments_count": assessments_count
|
||||
}
|
||||
}
|
||||
|
||||
current_app.logger.debug(f'Statistiques API générées pour classe {id}, trimestre {trimester}')
|
||||
return jsonify(stats)
|
||||
|
||||
except Exception as e:
|
||||
current_app.logger.error(f'Erreur génération statistiques API classe {id}: {e}')
|
||||
return jsonify({"error": "Erreur lors de la génération des statistiques"}), 500
|
||||
|
||||
@bp.route('/<int:id>/details')
|
||||
@handle_db_errors
|
||||
def details_legacy(id):
|
||||
"""Page de détail d'une classe avec ses étudiants et évaluations (legacy)."""
|
||||
class_repo = ClassRepository()
|
||||
class_group = class_repo.find_with_full_details(id)
|
||||
|
||||
if not class_group:
|
||||
# Gestion manuelle du 404 car find_with_full_details retourne None
|
||||
from flask import abort
|
||||
abort(404)
|
||||
|
||||
# Trier les étudiants par nom (optimisé en Python car déjà chargés)
|
||||
|
||||
Reference in New Issue
Block a user