This commit is contained in:
2026-04-02 00:12:35 +02:00
parent 20e8944d8c
commit 160d292e99
3 changed files with 237 additions and 247 deletions
+6 -235
View File
@@ -66,81 +66,12 @@
<button class="btn btn-outline" onclick={ retourRecherche } style="margin-bottom: 16px;">← Retour à la recherche</button>
<div class="detail-card comparateur-card" if={ state.selectedFormations.length > 0 }>
<h2>Comparateur de formations</h2>
<comparateur-view
formations={ state.selectedFormations }
onretirer={ retirerSelection }
onvider={ viderSelection }>
</comparateur-view>
<p>Choisis ton profil pour estimer tes chances d'intégration.</p>
<div class="compare-controls">
<div>
<label><b>Note moyenne :</b></label><br />
<input
type="number"
min="0"
max="20"
step="0.1"
value={ state.note }
oninput={ mettreAJourNote }
/>
</div>
<div>
<label><b>Série :</b></label><br />
<select onchange={ mettreAJourSerie }>
<option value="general" selected={ state.serie === 'general' }>Général</option>
<option value="techno" selected={ state.serie === 'techno' }>Technologique</option>
<option value="pro" selected={ state.serie === 'pro' }>Professionnel</option>
</select>
</div>
<div>
<label><b>Trier par :</b></label><br />
<select onchange={ mettreAJourTri }>
<option value="nom" selected={ state.sortBy === 'nom' }>Nom</option>
<option value="ville" selected={ state.sortBy === 'ville' }>Ville</option>
<option value="taux" selected={ state.sortBy === 'taux' }>Taux d'accès</option>
<option value="estimation" selected={ state.sortBy === 'estimation' }>Estimation</option>
</select>
</div>
</div>
<button class="btn btn-danger" onclick={ viderSelection }>Vider la sélection</button>
<hr />
<div each={ f in obtenirSelectionTriee() } key={ f.id } class={ classeCarte(f) }>
<h4>{ f.nom }</h4>
<p><b>Établissement :</b> { f.etablissement }</p>
<p><b>Ville :</b> { f.ville }</p>
<p><b>Filière :</b> { f.filiere }</p>
<p><b>Capacité :</b> { f.capacite }</p>
<p><b>Taux d'accès :</b> { f.tauxAcces }%</p>
<p>
<b>Intégrés :</b>
Général { f.pctGeneral }% /
Techno { f.pctTechno }% /
Pro { f.pctPro }%
</p>
<p class="estimation-result">
<span class={ classeEstimation(f) }>
{ estimerFormation(f) }
</span>
<span class="estimation-detail">{ detailEstimation(f) }</span>
</p>
<button class="btn btn-small btn-outline" onclick={ retirerSelection.bind(this, f.id) }>
Retirer
</button>
</div>
</div>
<div class="message" if={ state.selectedFormations.length === 0 }>
<h3>Aucune formation sélectionnée</h3>
<p>Retourne à la <a href="#/">recherche</a> et clique sur "Ajouter à la sélection" pour comparer des formations.</p>
</div>
</div>
</div>
@@ -154,9 +85,6 @@
results: [],
selected: null,
selectedFormations: [],
note: 12,
serie: 'general',
sortBy: 'nom',
query: '',
filters: {},
page: 1,
@@ -409,166 +337,9 @@
viderSelection() {
this.update({ selectedFormations: [] });
this.sauvegarderSelection([]);
},
mettreAJourNote(e) {
this.update({ note: Number(e.target.value) });
},
mettreAJourSerie(e) {
this.update({ serie: e.target.value });
},
mettreAJourTri(e) {
this.update({ sortBy: e.target.value });
},
obtenirSelectionTriee() {
var selection = this.state.selectedFormations.slice();
var soi = this;
if (this.state.sortBy === 'taux') {
selection.sort(function(a, b) { return b.tauxAcces - a.tauxAcces; });
} else if (this.state.sortBy === 'ville') {
selection.sort(function(a, b) { return a.ville.localeCompare(b.ville); });
} else if (this.state.sortBy === 'estimation') {
selection.sort(function(a, b) { return soi.calculerScore(b) - soi.calculerScore(a); });
} else {
selection.sort(function(a, b) { return a.nom.localeCompare(b.nom); });
}
return selection;
},
pourcentageSerie(f) {
if (this.state.serie === 'general') {
return f.pctGeneral || 0;
}
if (this.state.serie === 'techno') {
return f.pctTechno || 0;
}
if (this.state.serie === 'pro') {
return f.pctPro || 0;
}
return 0;
},
calculerScore(f) {
var score = 0;
var note = this.state.note;
var tauxAcces = f.tauxAcces || 0;
var pctSerie = this.pourcentageSerie(f);
if (tauxAcces >= 80) {
score += 30;
} else if (tauxAcces >= 50) {
score += 24;
} else if (tauxAcces >= 30) {
score += 16;
} else if (tauxAcces >= 15) {
score += 8;
} else {
score += 2;
}
if (note >= 17) {
score += 40;
} else if (note >= 15) {
score += 32;
} else if (note >= 13) {
score += 22;
} else if (note >= 11) {
score += 14;
} else if (note >= 9) {
score += 6;
} else {
score += 0;
}
if (pctSerie >= 60) {
score += 30;
} else if (pctSerie >= 40) {
score += 24;
} else if (pctSerie >= 20) {
score += 16;
} else if (pctSerie >= 5) {
score += 8;
} else {
score += 0;
}
return score;
},
estimerFormation(f) {
var score = this.calculerScore(f);
if (score >= 85) {
return 'Très favorable';
}
if (score >= 65) {
return 'Favorable';
}
if (score >= 45) {
return 'Possible';
}
if (score >= 25) {
return 'Difficile';
}
return 'Très difficile';
},
classeEstimation(f) {
var resultat = this.estimerFormation(f);
if (resultat === 'Très favorable') {
return 'estimate tres-favorable';
}
if (resultat === 'Favorable') {
return 'estimate favorable';
}
if (resultat === 'Possible') {
return 'estimate possible';
}
if (resultat === 'Difficile') {
return 'estimate difficile';
}
return 'estimate tres-difficile';
},
classeCarte(f) {
var resultat = this.estimerFormation(f);
if (resultat === 'Très favorable') {
return 'card card-tres-favorable';
}
if (resultat === 'Favorable') {
return 'card card-favorable';
}
if (resultat === 'Possible') {
return 'card card-possible';
}
if (resultat === 'Difficile') {
return 'card card-difficile';
}
return 'card card-tres-difficile';
},
detailEstimation(f) {
var tauxAcces = f.tauxAcces || 0;
var pctSerie = this.pourcentageSerie(f);
var nomSerie = '';
if (this.state.serie === 'general') {
nomSerie = 'Gén';
} else if (this.state.serie === 'techno') {
nomSerie = 'Techno';
} else {
nomSerie = 'Pro';
}
return 'Taux ' + tauxAcces + '% · ' + nomSerie + ' ' + pctSerie + '% · Note ' + this.state.note + '/20';
}
};
</script>
</app>
+218
View File
@@ -0,0 +1,218 @@
<comparateur-view>
<!-- ============== CAS : des formations sont sélectionnées ============== -->
<div class="detail-card comparateur-card" if={ props.formations.length > 0 }>
<h2>Comparateur de formations</h2>
<p>Choisis ton profil pour estimer tes chances d'intégration.</p>
<div class="compare-controls">
<div>
<label><b>Note moyenne :</b></label><br />
<input
type="number"
min="0"
max="20"
step="0.1"
value={ state.note }
oninput={ mettreAJourNote }
/>
</div>
<div>
<label><b>Série :</b></label><br />
<select onchange={ mettreAJourSerie }>
<option value="general" selected={ state.serie === 'general' }>Général</option>
<option value="techno" selected={ state.serie === 'techno' }>Technologique</option>
<option value="pro" selected={ state.serie === 'pro' }>Professionnel</option>
</select>
</div>
<div>
<label><b>Trier par :</b></label><br />
<select onchange={ mettreAJourTri }>
<option value="nom" selected={ state.sortBy === 'nom' }>Nom</option>
<option value="ville" selected={ state.sortBy === 'ville' }>Ville</option>
<option value="taux" selected={ state.sortBy === 'taux' }>Taux d'accès</option>
<option value="estimation" selected={ state.sortBy === 'estimation' }>Estimation</option>
</select>
</div>
</div>
<button class="btn btn-danger" onclick={ viderSelection }>Vider la sélection</button>
<hr />
<div each={ f in obtenirSelectionTriee() } key={ f.id } class={ classeCarte(f) }>
<h4>{ f.nom }</h4>
<p><b>Établissement :</b> { f.etablissement }</p>
<p><b>Ville :</b> { f.ville }</p>
<p><b>Filière :</b> { f.filiere }</p>
<p><b>Capacité :</b> { f.capacite }</p>
<p><b>Taux d'accès :</b> { f.tauxAcces }%</p>
<p>
<b>Intégrés :</b>
Général { f.pctGeneral }% /
Techno { f.pctTechno }% /
Pro { f.pctPro }%
</p>
<p class="estimation-result">
<span class={ classeEstimation(f) }>
{ estimerFormation(f) }
</span>
<span class="estimation-detail">{ detailEstimation(f) }</span>
</p>
<button class="btn btn-small btn-outline" onclick={ retirerSelection.bind(this, f.id) }>
Retirer
</button>
</div>
</div>
<!-- ============== CAS : aucune formation sélectionnée ============== -->
<div class="message" if={ props.formations.length === 0 }>
<h3>Aucune formation sélectionnée</h3>
<p>Retourne à la <a href="#/">recherche</a> et clique sur "Ajouter à la sélection" pour comparer des formations.</p>
</div>
<script>
export default {
// État local au comparateur (note, série, tri)
state: {
note: 12,
serie: 'general',
sortBy: 'nom'
},
// ----- Mise à jour du profil utilisateur -----
mettreAJourNote(e) {
this.update({ note: Number(e.target.value) });
},
mettreAJourSerie(e) {
this.update({ serie: e.target.value });
},
mettreAJourTri(e) {
this.update({ sortBy: e.target.value });
},
// ----- Actions sur la sélection (déléguées au parent via props) -----
retirerSelection(id) {
this.props.onretirer(id);
},
viderSelection() {
this.props.onvider();
},
// ----- Tri des formations -----
obtenirSelectionTriee() {
var selection = (this.props.formations || []).slice();
var soi = this;
if (this.state.sortBy === 'taux') {
selection.sort(function(a, b) { return b.tauxAcces - a.tauxAcces; });
} else if (this.state.sortBy === 'ville') {
selection.sort(function(a, b) { return a.ville.localeCompare(b.ville); });
} else if (this.state.sortBy === 'estimation') {
selection.sort(function(a, b) { return soi.calculerScore(b) - soi.calculerScore(a); });
} else {
selection.sort(function(a, b) { return a.nom.localeCompare(b.nom); });
}
return selection;
},
// ----- Calcul d'estimation -----
pourcentageSerie(f) {
if (this.state.serie === 'general') { return f.pctGeneral || 0; }
if (this.state.serie === 'techno') { return f.pctTechno || 0; }
if (this.state.serie === 'pro') { return f.pctPro || 0; }
return 0;
},
calculerScore(f) {
var score = 0;
var note = this.state.note;
var tauxAcces = f.tauxAcces || 0;
var pctSerie = this.pourcentageSerie(f);
// Critère 1 : taux d'accès de la formation
if (tauxAcces >= 80) { score += 30; }
else if (tauxAcces >= 50) { score += 24; }
else if (tauxAcces >= 30) { score += 16; }
else if (tauxAcces >= 15) { score += 8; }
else { score += 2; }
// Critère 2 : note de l'étudiant
if (note >= 17) { score += 40; }
else if (note >= 15) { score += 32; }
else if (note >= 13) { score += 22; }
else if (note >= 11) { score += 14; }
else if (note >= 9) { score += 6; }
else { score += 0; }
// Critère 3 : proportion de bacheliers de la même série acceptés
if (pctSerie >= 60) { score += 30; }
else if (pctSerie >= 40) { score += 24; }
else if (pctSerie >= 20) { score += 16; }
else if (pctSerie >= 5) { score += 8; }
else { score += 0; }
return score;
},
estimerFormation(f) {
var score = this.calculerScore(f);
if (score >= 85) { return 'Très favorable'; }
if (score >= 65) { return 'Favorable'; }
if (score >= 45) { return 'Possible'; }
if (score >= 25) { return 'Difficile'; }
return 'Très difficile';
},
// ----- Classes CSS selon l'estimation -----
classeEstimation(f) {
var r = this.estimerFormation(f);
if (r === 'Très favorable') { return 'estimate tres-favorable'; }
if (r === 'Favorable') { return 'estimate favorable'; }
if (r === 'Possible') { return 'estimate possible'; }
if (r === 'Difficile') { return 'estimate difficile'; }
return 'estimate tres-difficile';
},
classeCarte(f) {
var r = this.estimerFormation(f);
if (r === 'Très favorable') { return 'card card-tres-favorable'; }
if (r === 'Favorable') { return 'card card-favorable'; }
if (r === 'Possible') { return 'card card-possible'; }
if (r === 'Difficile') { return 'card card-difficile'; }
return 'card card-tres-difficile';
},
detailEstimation(f) {
var tauxAcces = f.tauxAcces || 0;
var pctSerie = this.pourcentageSerie(f);
var nomSerie = '';
if (this.state.serie === 'general') { nomSerie = 'Gén'; }
else if (this.state.serie === 'techno') { nomSerie = 'Techno'; }
else { nomSerie = 'Pro'; }
return 'Taux ' + tauxAcces + '% · ' + nomSerie + ' ' + pctSerie + '% · Note ' + this.state.note + '/20';
}
};
</script>
</comparateur-view>
+1
View File
@@ -20,6 +20,7 @@
<script src="./components/detail-view.riot" type="riot"></script>
<script src="./components/map-view.riot" type="riot"></script>
<script src="./components/auth-panel.riot" type="riot"></script>
<script src="./components/comparateur.riot" type="riot"></script>
<script src="./app.riot" type="riot"></script>
<script type="module">