387 lines
11 KiB
Markdown
387 lines
11 KiB
Markdown
# Perspective Enseignant - Domaines et Compétences
|
||
|
||
**Date**: 3 décembre 2025
|
||
**Type**: Changement de perspective - Ce qui a été évalué vs Résultats des élèves
|
||
|
||
## 🎯 Objectif du Changement
|
||
|
||
Passer d'une **perspective centrée sur les résultats des élèves** à une **perspective centrée sur ce qui a été évalué par l'enseignant**.
|
||
|
||
### Avant (Perspective Élèves)
|
||
```
|
||
Domaine Algèbre:
|
||
- 75 évaluations (25 élèves × 3 questions)
|
||
- 187.5 / 250 points
|
||
```
|
||
→ **Difficile à interpréter** : mélange le nombre d'élèves et les évaluations
|
||
|
||
### Après (Perspective Enseignant)
|
||
```
|
||
Domaine Algèbre:
|
||
- 3 éléments de notation
|
||
- 10 points maximum
|
||
```
|
||
→ **Clair et actionnable** : l'enseignant voit ce qu'il a créé
|
||
|
||
---
|
||
|
||
## 📊 Cas d'Usage Concrets
|
||
|
||
### Scénario 1: Vérifier l'équilibre d'un trimestre
|
||
|
||
**Données affichées**:
|
||
```
|
||
Domaines:
|
||
- Algèbre : 8 éléments, 25 points
|
||
- Géométrie : 3 éléments, 12 points ← Sous-représenté
|
||
- Probabilités : 2 éléments, 8 points ← Sous-représenté
|
||
- Calcul : 6 éléments, 18 points
|
||
```
|
||
|
||
**Action enseignant**: Créer plus d'évaluations sur Géométrie et Probabilités pour le prochain contrôle.
|
||
|
||
### Scénario 2: Analyser une évaluation
|
||
|
||
**Données affichées**:
|
||
```
|
||
Compétences:
|
||
- Calculer : 5 éléments, 15 points
|
||
- Raisonner : 3 éléments, 12 points
|
||
- Communiquer : 1 élément, 5 points ← Sous-représenté
|
||
```
|
||
|
||
**Action enseignant**: Ajouter des questions de communication dans la prochaine évaluation.
|
||
|
||
### Scénario 3: Comparer les trimestres
|
||
|
||
| Domaine | T1 | T2 | T3 |
|
||
|---------|----|----|-----|
|
||
| Algèbre | 8 éléments, 25pts | 6 éléments, 18pts | 10 éléments, 30pts |
|
||
| Géométrie | 3 éléments, 12pts | 7 éléments, 20pts | 5 éléments, 15pts |
|
||
|
||
**Insight**: L'enseignant voit qu'il a moins travaillé la géométrie au T3, peut ajuster pour l'année suivante.
|
||
|
||
---
|
||
|
||
## 🔧 Modifications Techniques
|
||
|
||
### Backend
|
||
|
||
#### 1. Nouveau Service (`backend/domain/services/class_statistics_service.py`)
|
||
|
||
**Méthode ajoutée**: `calculate_domain_competence_from_elements()`
|
||
|
||
**Logique**:
|
||
```python
|
||
for assessment in assessments:
|
||
for exercise in assessment.exercises:
|
||
for element in exercise.grading_elements:
|
||
# Compter par domaine
|
||
if element.domain_id:
|
||
domain_count[element.domain_id] += 1
|
||
domain_points[element.domain_id] += element.max_points
|
||
|
||
# Compter par compétence (via skill)
|
||
if element.skill:
|
||
competence = find_competence_by_name(element.skill)
|
||
if competence:
|
||
competence_count[competence.id] += 1
|
||
competence_points[competence.id] += element.max_points
|
||
```
|
||
|
||
**Retourne**:
|
||
- `evaluation_count`: Nombre de GradingElements utilisant ce domaine/compétence
|
||
- `total_points_possible`: Somme des max_points de ces éléments
|
||
- `total_points_obtained`: 0 (non pertinent dans cette perspective)
|
||
|
||
#### 2. Endpoint modifié (`backend/api/routes/classes.py`)
|
||
|
||
**Chargement des relations**:
|
||
```python
|
||
assessments_query = (
|
||
select(Assessment)
|
||
.options(
|
||
selectinload(Assessment.exercises).selectinload(Exercise.grading_elements)
|
||
)
|
||
.where(...)
|
||
)
|
||
```
|
||
|
||
**Utilisation du nouveau service**:
|
||
```python
|
||
# AVANT
|
||
domains_stats, competences_stats = stats_service.aggregate_domain_competence_stats(
|
||
student_averages=student_averages,
|
||
domains=domains,
|
||
competences=competences,
|
||
)
|
||
|
||
# APRÈS
|
||
domains_stats, competences_stats = stats_service.calculate_domain_competence_from_elements(
|
||
assessments=assessments, # Avec exercises et grading_elements chargés
|
||
domains=domains,
|
||
competences=competences,
|
||
)
|
||
```
|
||
|
||
### Frontend
|
||
|
||
#### 1. Affichage modifié (`frontend/src/views/ClassDashboardView.vue`)
|
||
|
||
**Template**:
|
||
```vue
|
||
<!-- AVANT -->
|
||
<div>
|
||
<span>{{ domain.name }}</span>
|
||
<span>{{ domain.total_points_obtained }}/{{ domain.total_points_possible }}</span>
|
||
<p>{{ domain.evaluation_count }} évaluations</p>
|
||
</div>
|
||
|
||
<!-- APRÈS -->
|
||
<div>
|
||
<span>{{ domain.name }}</span>
|
||
<span>{{ domain.total_points_possible }} points</span>
|
||
<p>{{ domain.evaluation_count }} élément(s) de notation</p>
|
||
</div>
|
||
```
|
||
|
||
**Titres modifiés**:
|
||
- "Statistiques par domaine" → "Évaluations par domaine"
|
||
- "Statistiques par compétence" → "Évaluations par compétence"
|
||
|
||
**Sous-titre ajouté**:
|
||
- "Perspective enseignant : ce qui a été évalué"
|
||
|
||
#### 2. Barre de progression relative
|
||
|
||
**Nouvelle logique**:
|
||
```javascript
|
||
function getRelativeWidth(item, allItems) {
|
||
const maxPoints = Math.max(...allItems.map(d => d.total_points_possible || 0))
|
||
if (maxPoints === 0) return 0
|
||
return ((item.total_points_possible || 0) / maxPoints) * 100
|
||
}
|
||
```
|
||
|
||
**Utilisation**:
|
||
```vue
|
||
<div class="progress-bar">
|
||
<div :style="{ width: `${getRelativeWidth(domain, stats.domains_stats)}%` }"></div>
|
||
</div>
|
||
```
|
||
|
||
La barre montre **la proportion relative** par rapport au domaine le plus évalué, pas un pourcentage absolu.
|
||
|
||
---
|
||
|
||
## 📈 Comparaison Avant/Après
|
||
|
||
### Exemple avec une classe de 25 élèves, 2 contrôles
|
||
|
||
**Contrôle 1** (Trimestre 1):
|
||
- Q1: Algèbre, 5 points
|
||
- Q2: Algèbre, 3 points
|
||
- Q3: Géométrie, 4 points
|
||
|
||
**Contrôle 2** (Trimestre 1):
|
||
- Q1: Algèbre, 2 points
|
||
- Q2: Probabilités, 5 points
|
||
|
||
### Avant (Perspective Élèves)
|
||
|
||
**Domaine Algèbre**:
|
||
- `evaluation_count`: 75 (3 questions × 25 élèves)
|
||
- `total_points_obtained`: 187.5 (moyenne hypothétique)
|
||
- `total_points_possible`: 250 ((5+3+2) × 25)
|
||
|
||
**Affichage**: "75 évaluations - 187.5/250"
|
||
→ **Illisible** pour l'enseignant
|
||
|
||
### Après (Perspective Enseignant)
|
||
|
||
**Domaine Algèbre**:
|
||
- `evaluation_count`: 3 (nombre de questions posées)
|
||
- `total_points_possible`: 10 (5+3+2)
|
||
|
||
**Affichage**: "3 éléments de notation - 10 points"
|
||
→ **Très lisible** et actionnable
|
||
|
||
---
|
||
|
||
## 🎓 Avantages Pédagogiques
|
||
|
||
### 1. Clarté
|
||
- **Indépendant du nombre d'élèves**: 3 éléments restent 3 éléments
|
||
- **Unité cohérente**: Points = barème défini par l'enseignant
|
||
|
||
### 2. Planification
|
||
- **Voir rapidement** quels domaines ont été peu évalués
|
||
- **Équilibrer** les évaluations entre domaines
|
||
- **Comparer** les trimestres facilement
|
||
|
||
### 3. Réflexivité
|
||
- **Analyse de pratique**: "Ai-je trop évalué l'algèbre ?"
|
||
- **Diversification**: "Dois-je ajouter plus de géométrie ?"
|
||
- **Cohérence**: "Mon programme est-il équilibré ?"
|
||
|
||
### 4. Communication
|
||
- **Conseil de classe**: "J'ai évalué 8 fois l'algèbre ce trimestre"
|
||
- **Parents**: "Voici la répartition de mes évaluations"
|
||
- **Équipe pédagogique**: "Comparons nos pratiques d'évaluation"
|
||
|
||
---
|
||
|
||
## 🔍 Détails d'Implémentation
|
||
|
||
### Gestion des Compétences
|
||
|
||
**Mapping via `element.skill`**:
|
||
```python
|
||
if element.skill:
|
||
matching_competence = next(
|
||
(c for c in competences if c.name == element.skill),
|
||
None
|
||
)
|
||
```
|
||
|
||
**Logique**:
|
||
- Les compétences sont stockées dans `GradingElement.skill` (champ texte libre)
|
||
- Le matching se fait par nom de compétence
|
||
- Si aucune correspondance: la compétence n'est pas comptée
|
||
|
||
**Amélioration future**: Ajouter `competence_id` dans `GradingElement` pour éviter le matching par nom.
|
||
|
||
### Performance
|
||
|
||
**Requête optimisée**:
|
||
```python
|
||
# Un seul trip à la base de données
|
||
assessments = session.execute(
|
||
select(Assessment)
|
||
.options(selectinload(Assessment.exercises).selectinload(Exercise.grading_elements))
|
||
.where(...)
|
||
).scalars().all()
|
||
```
|
||
|
||
**Complexité**: O(n) où n = nombre total de GradingElements du trimestre
|
||
|
||
**Charge typique**:
|
||
- 5 évaluations × 15 éléments/évaluation = 75 éléments à parcourir
|
||
- Temps: < 10ms
|
||
|
||
### Données Retournées
|
||
|
||
**Structure JSON**:
|
||
```json
|
||
{
|
||
"domains_stats": [
|
||
{
|
||
"id": 1,
|
||
"name": "Algèbre",
|
||
"color": "#3B82F6",
|
||
"evaluation_count": 3,
|
||
"total_points_obtained": 0.0,
|
||
"total_points_possible": 10.0
|
||
}
|
||
],
|
||
"competences_stats": [
|
||
{
|
||
"id": 1,
|
||
"name": "Calculer",
|
||
"color": "#10B981",
|
||
"evaluation_count": 5,
|
||
"total_points_obtained": 0.0,
|
||
"total_points_possible": 15.0
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**Note**: `total_points_obtained` est à 0 car non pertinent dans cette perspective.
|
||
|
||
---
|
||
|
||
## 📁 Fichiers Modifiés
|
||
|
||
### Backend (2 fichiers)
|
||
|
||
1. **`backend/domain/services/class_statistics_service.py`**
|
||
- Ajout: `calculate_domain_competence_from_elements()`
|
||
- Logique: Parcours des GradingElements
|
||
- Retour: DomainStats et CompetenceStats
|
||
|
||
2. **`backend/api/routes/classes.py`**
|
||
- Modification: Chargement des assessments avec relations
|
||
- Modification: Appel de la nouvelle méthode de calcul
|
||
|
||
### Frontend (1 fichier)
|
||
|
||
3. **`frontend/src/views/ClassDashboardView.vue`**
|
||
- Modification: Titres ("Évaluations par..." au lieu de "Statistiques par...")
|
||
- Modification: Affichage (points seuls au lieu de obtained/possible)
|
||
- Modification: Texte ("élément(s) de notation" au lieu de "évaluations")
|
||
- Ajout: Fonction `getRelativeWidth()` pour barre proportionnelle
|
||
- Ajout: Sous-titre explicatif "Perspective enseignant : ce qui a été évalué"
|
||
|
||
---
|
||
|
||
## ✅ Tests Suggérés
|
||
|
||
### 1. Vérifier le comptage
|
||
- Créer 3 évaluations avec 2, 3, 4 éléments respectivement
|
||
- Vérifier: `evaluation_count = 9`
|
||
|
||
### 2. Vérifier les points
|
||
- Élément 1: 5 points
|
||
- Élément 2: 3 points
|
||
- Élément 3: 2 points
|
||
- Vérifier: `total_points_possible = 10`
|
||
|
||
### 3. Vérifier le filtrage par domaine
|
||
- 3 éléments Algèbre, 2 éléments Géométrie
|
||
- Vérifier: Algèbre montre 3, Géométrie montre 2
|
||
|
||
### 4. Vérifier les compétences
|
||
- Créer des éléments avec `skill = "Calculer"`
|
||
- Vérifier: Compétence "Calculer" affiche le bon nombre
|
||
|
||
### 5. Vérifier l'absence de données
|
||
- Domaine sans éléments: `evaluation_count = 0, total_points_possible = 0`
|
||
- Affichage: "0 élément(s) de notation - 0 points"
|
||
|
||
---
|
||
|
||
## 🚀 Utilisation
|
||
|
||
### Accéder au Dashboard
|
||
```
|
||
http://localhost:5173/classes/{id}
|
||
```
|
||
|
||
### Vérifier l'affichage
|
||
1. Sélectionner un trimestre
|
||
2. Scroller jusqu'aux sections "Évaluations par domaine/compétence"
|
||
3. Vérifier:
|
||
- ✅ Titre: "Évaluations par domaine/compétence"
|
||
- ✅ Sous-titre: "Perspective enseignant : ce qui a été évalué"
|
||
- ✅ Affichage: "X points" (pas de fraction)
|
||
- ✅ Texte: "X élément(s) de notation"
|
||
- ✅ Barre proportionnelle au domaine le plus évalué
|
||
|
||
---
|
||
|
||
## 🎯 Conclusion
|
||
|
||
Cette modification transforme le dashboard d'une **vue résultats** (complexe, orientée élèves) en une **vue enseignant** (simple, orientée pratique pédagogique).
|
||
|
||
**Impact pédagogique**:
|
||
- ✅ Meilleure visibilité sur la répartition des évaluations
|
||
- ✅ Aide à l'équilibrage du programme
|
||
- ✅ Facilite la réflexion sur les pratiques d'évaluation
|
||
- ✅ Indépendant du nombre d'élèves (plus cohérent)
|
||
|
||
**Impact technique**:
|
||
- ✅ Code plus simple (pas de double comptage élèves × éléments)
|
||
- ✅ Requêtes optimisées avec selectinload
|
||
- ✅ Données plus claires et exploitables
|