feat: intégrer la configuration des compétences dans la gestion des assessments
- Remplacer le champ texte libre par une liste déroulante des compétences configurées - Charger dynamiquement les compétences dans les routes d'assessments (new/edit) - Moderniser le calcul des scores pour utiliser l'échelle de compétences configurable - Adapter la logique de scoring aux valeurs personnalisées (0-3 ou autres) - Respecter le paramètre 'included_in_total' de chaque valeur de l'échelle - Maintenir la compatibilité descendante avec l'ancienne formule 🎯 Améliore l'intégration entre la configuration système et l'interface utilisateur 📊 Rend les calculs de scores plus flexibles et cohérents avec la configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
46
models.py
46
models.py
@@ -112,6 +112,10 @@ class Assessment(db.Model):
|
||||
Retourne un dictionnaire avec les scores par élève et par exercice."""
|
||||
from collections import defaultdict
|
||||
import statistics
|
||||
from app_config import config_manager
|
||||
|
||||
# Récupérer l'échelle des compétences configurée
|
||||
competence_scale = config_manager.get_competence_scale_values()
|
||||
|
||||
students_scores = {}
|
||||
exercise_scores = defaultdict(lambda: defaultdict(float))
|
||||
@@ -144,16 +148,44 @@ class Assessment(db.Model):
|
||||
exercise_max_points += element.max_points
|
||||
except ValueError:
|
||||
pass
|
||||
else: # compétences
|
||||
if grade.value == '.':
|
||||
# '.' signifie non évalué = 0 point mais on compte le max
|
||||
exercise_score += 0
|
||||
exercise_max_points += (1/3) * 3 * element.max_points # Score max de 3
|
||||
else: # compétences - utiliser la nouvelle échelle
|
||||
grade_value = grade.value.strip()
|
||||
|
||||
# Gérer les valeurs numériques et string
|
||||
scale_key = int(grade_value) if grade_value.isdigit() else grade_value
|
||||
|
||||
if scale_key in competence_scale:
|
||||
scale_config = competence_scale[scale_key]
|
||||
|
||||
if scale_config['included_in_total']:
|
||||
# Calculer le score selon l'échelle configurée
|
||||
if grade_value == '.':
|
||||
# Non évalué = 0 point
|
||||
exercise_score += 0
|
||||
else:
|
||||
# Calculer le score proportionnel
|
||||
# Trouver la valeur maximale de l'échelle
|
||||
max_scale_value = max([
|
||||
int(k) if str(k).isdigit() else 0
|
||||
for k in competence_scale.keys()
|
||||
if competence_scale[k]['included_in_total'] and k != '.'
|
||||
])
|
||||
|
||||
if max_scale_value > 0:
|
||||
if grade_value.isdigit():
|
||||
score_ratio = int(grade_value) / max_scale_value
|
||||
exercise_score += score_ratio * element.max_points
|
||||
|
||||
# Compter les points maximum (sauf pour '.')
|
||||
if grade_value != '.':
|
||||
exercise_max_points += element.max_points
|
||||
# Si not included_in_total, on ne compte ni score ni max
|
||||
else:
|
||||
# Valeur non reconnue, utiliser l'ancienne logique par défaut
|
||||
try:
|
||||
score_value = float(grade.value)
|
||||
score_value = float(grade_value)
|
||||
exercise_score += (1/3) * score_value * element.max_points
|
||||
exercise_max_points += (1/3) * 3 * element.max_points # Score max de 3
|
||||
exercise_max_points += element.max_points
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
@@ -160,23 +160,35 @@ def edit(id):
|
||||
exercise_data['grading_elements'].append(element_data)
|
||||
exercises_data.append(exercise_data)
|
||||
|
||||
# Récupérer les compétences configurées
|
||||
from app_config import config_manager
|
||||
competences = config_manager.get_competences_list()
|
||||
|
||||
return render_template('assessment_form_unified.html',
|
||||
form=form,
|
||||
title='Modifier l\'évaluation complète',
|
||||
assessment=assessment,
|
||||
exercises_json=exercises_data,
|
||||
is_edit=True)
|
||||
is_edit=True,
|
||||
competences=competences)
|
||||
|
||||
@bp.route('/new', methods=['GET', 'POST'])
|
||||
@handle_db_errors
|
||||
def new():
|
||||
from app_config import config_manager
|
||||
form = AssessmentForm()
|
||||
|
||||
result = _handle_unified_assessment_request(form, is_edit=False)
|
||||
if result:
|
||||
return result
|
||||
|
||||
return render_template('assessment_form_unified.html', form=form, title='Nouvelle évaluation complète')
|
||||
# Récupérer les compétences configurées
|
||||
competences = config_manager.get_competences_list()
|
||||
|
||||
return render_template('assessment_form_unified.html',
|
||||
form=form,
|
||||
title='Nouvelle évaluation complète',
|
||||
competences=competences)
|
||||
|
||||
@bp.route('/<int:id>/results')
|
||||
@handle_db_errors
|
||||
|
||||
@@ -241,7 +241,14 @@
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-700 mb-1">Compétence</label>
|
||||
<input type="text" class="element-skill block w-full border border-gray-300 rounded-md px-2 py-1 text-sm focus:ring-purple-500 focus:border-purple-500">
|
||||
<select class="element-skill block w-full border border-gray-300 rounded-md px-2 py-1 text-sm focus:ring-purple-500 focus:border-purple-500">
|
||||
<option value="">Non spécifiée</option>
|
||||
{% for competence in competences %}
|
||||
<option value="{{ competence.name }}" data-color="{{ competence.color }}" data-icon="{{ competence.icon }}">
|
||||
{{ competence.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-700 mb-1">Points max</label>
|
||||
|
||||
Reference in New Issue
Block a user