This commit is contained in:
2026-03-21 13:47:09 +01:00
parent bd20abb745
commit da383237f6
8 changed files with 650 additions and 520 deletions
+170 -139
View File
@@ -141,257 +141,288 @@
</tbody>
</table>
<!-- ===================== GRAPHIQUES CHARTS.CSS ===================== -->
<!-- ==================== GRAPHIQUES CHARTS.CSS ==================== -->
<h2 class="charts-heading">Profil des admis</h2>
<div class="charts-section">
<div class="chart-wrapper">
<h3>Répartition par type de bac</h3>
<div id="chart-bac" ref="chartBac"></div>
<div id="chart-bac" ref="graphBac"></div>
</div>
<div class="chart-wrapper">
<h3>Mentions au bac des admis</h3>
<div id="chart-mentions" ref="chartMentions"></div>
<div id="chart-mentions" ref="graphMentions"></div>
</div>
<div class="chart-wrapper chart-full">
<h3>Profil sociologique</h3>
<div id="chart-profil" ref="chartProfil"></div>
<div id="chart-profil" ref="graphProfil"></div>
</div>
</div>
<!-- ===================== ÉVOLUTION HISTORIQUE ===================== -->
<!-- ==================== ÉVOLUTION HISTORIQUE ==================== -->
<h2 class="charts-heading">Évolution depuis 2020</h2>
<div if={ state.loadingHistory } class="message">
<div if={ state.chargementHistorique } class="message">
Chargement de l'historique...
</div>
<div if={ !state.loadingHistory && state.history.length === 0 } class="message">
<div if={ !state.chargementHistorique && state.historique.length === 0 } class="message">
Aucune donnée historique disponible pour cette formation.
</div>
<div class="charts-section" if={ state.history.length > 0 }>
<div class="charts-section" if={ state.historique.length > 0 }>
<div class="chart-wrapper">
<h3>Taux d'accès par année</h3>
<div id="chart-evolution-taux" ref="chartTaux"></div>
<div id="chart-evolution-taux" ref="graphTaux"></div>
</div>
<div class="chart-wrapper">
<h3>Nombre de candidats et admis</h3>
<div id="chart-evolution-candidats" ref="chartCandidats"></div>
<div id="chart-evolution-candidats" ref="graphCandidats"></div>
</div>
<div class="chart-wrapper chart-full">
<h3>Évolution des mentions au bac</h3>
<div ref="chartMentionsHist"></div>
<div ref="graphMentionsHist"></div>
</div>
</div>
<button onclick={ goBack } class="btn-retour">Retour à la liste</button>
<button onclick={ retourListe } class="btn-retour">Retour à la liste</button>
</div>
<script>
export default {
state: {
history: [],
loadingHistory: false
},
safe(val) {
if (val === null || val === undefined || isNaN(val)) return 0
var v = val / 100
if (v > 1) return 1
if (v < 0) return 0
return Math.round(v * 100) / 100
state: {
historique: [],
chargementHistorique: false
},
onMounted() {
this.renderCharts()
this.loadHistory()
this.afficherGraphiques()
this.chargerHistorique()
},
onUpdated() {
this.renderCharts()
if (this.state.history.length > 0) {
this.renderHistoryCharts()
this.afficherGraphiques()
if (this.state.historique.length > 0) {
this.afficherGraphiquesHistoriques()
}
},
// Retour à la liste des résultats
goBack() {
retourListe() {
this.props.onback()
},
renderCharts() {
// Limiter une valeur entre 0 et 1 pour Charts.css
limiterValeur(val) {
if (val === null || val === undefined || isNaN(val)) {
return 0
}
var v = val / 100
if (v > 1) {
return 1
}
if (v < 0) {
return 0
}
return Math.round(v * 100) / 100
},
afficherGraphiques() {
var f = this.props.formation
if (!f) return
if (!f) {
return
}
var chartBac = this.$('[ref="chartBac"]')
var chartMentions = this.$('[ref="chartMentions"]')
var chartProfil = this.$('[ref="chartProfil"]')
var graphBac = this.$('[ref="graphBac"]')
var graphMentions = this.$('[ref="graphMentions"]')
var graphProfil = this.$('[ref="graphProfil"]')
if (chartBac) {
chartBac.innerHTML = this.buildColumnChart([
{ label: 'Général', value: f.pctGeneral, color: '#3d7fff' },
{ label: 'Techno', value: f.pctTechno, color: '#f59e0b' },
{ label: 'Pro', value: f.pctPro, color: '#10b981' }
if (graphBac) {
graphBac.innerHTML = this.construireGraphiqueColonnes([
{ label: 'Général', valeur: f.pctGeneral, couleur: '#3d7fff' },
{ label: 'Techno', valeur: f.pctTechno, couleur: '#f59e0b' },
{ label: 'Pro', valeur: f.pctPro, couleur: '#10b981' }
])
}
if (chartMentions) {
chartMentions.innerHTML = this.buildColumnChart([
{ label: 'Sans', value: f.pctSansMention, color: '#94a3b8' },
{ label: 'AB', value: f.pctAB, color: '#60a5fa' },
{ label: 'Bien', value: f.pctB, color: '#34d399' },
{ label: 'TB', value: f.pctTB, color: '#fbbf24' },
{ label: 'TB Féli.', value: f.pctTBF, color: '#f472b6' }
if (graphMentions) {
graphMentions.innerHTML = this.construireGraphiqueColonnes([
{ label: 'Sans', valeur: f.pctSansMention, couleur: '#94a3b8' },
{ label: 'AB', valeur: f.pctAB, couleur: '#60a5fa' },
{ label: 'Bien', valeur: f.pctB, couleur: '#34d399' },
{ label: 'TB', valeur: f.pctTB, couleur: '#fbbf24' },
{ label: 'TB Féli.', valeur: f.pctTBF, couleur: '#f472b6' }
])
}
if (chartProfil) {
chartProfil.innerHTML = this.buildBarChart([
{ label: 'Femmes', value: f.pctFemmes, color: '#a78bfa' },
{ label: 'Boursiers', value: f.pctBoursiers, color: '#fb923c' },
{ label: 'Néo-bac', value: f.pctNeoBac, color: '#2dd4bf' }
if (graphProfil) {
graphProfil.innerHTML = this.construireGraphiqueBarres([
{ label: 'Femmes', valeur: f.pctFemmes, couleur: '#a78bfa' },
{ label: 'Boursiers', valeur: f.pctBoursiers, couleur: '#fb923c' },
{ label: 'Néo-bac', valeur: f.pctNeoBac, couleur: '#2dd4bf' }
])
}
},
async loadHistory() {
async chargerHistorique() {
var f = this.props.formation
if (!f) return
if (!f) {
return
}
// Extraire le cod_uai de l'id (format: codUai-nomFormation)
var codUai = f.id.split('-')[0]
if (!codUai || !window.fetchFormationHistory) return
if (!codUai || !window.chargerHistoriqueFormation) {
return
}
this.update({ loadingHistory: true })
this.update({ chargementHistorique: true })
try {
var history = await window.fetchFormationHistory(codUai, f.nom)
this.update({ history: history, loadingHistory: false })
var historique = await window.chargerHistoriqueFormation(codUai, f.nom)
this.update({ historique: historique, chargementHistorique: false })
} catch (e) {
console.error('Erreur historique:', e)
this.update({ history: [], loadingHistory: false })
console.error('Erreur chargement historique :', e)
this.update({ historique: [], chargementHistorique: false })
}
},
renderHistoryCharts() {
var hist = this.state.history
if (!hist || hist.length === 0) return
var chartTaux = this.$('[ref="chartTaux"]')
var chartCandidats = this.$('[ref="chartCandidats"]')
var chartMentionsHist = this.$('[ref="chartMentionsHist"]')
// Graphique : taux d'accès par année
if (chartTaux) {
var items = []
for (var i = 0; i < hist.length; i++) {
items.push({
label: '' + hist[i].annee,
value: hist[i].tauxAcces,
color: '#1a936f'
})
}
chartTaux.innerHTML = this.buildColumnChart(items)
afficherGraphiquesHistoriques() {
var historique = this.state.historique
if (!historique || historique.length === 0) {
return
}
// Graphique : candidats vs admis (normalisé sur le max)
if (chartCandidats) {
var maxCandidats = 0
for (var i = 0; i < hist.length; i++) {
if (hist[i].candidats > maxCandidats) maxCandidats = hist[i].candidats
var graphTaux = this.$('[ref="graphTaux"]')
var graphCandidats = this.$('[ref="graphCandidats"]')
var graphMentionsHist = this.$('[ref="graphMentionsHist"]')
// Graphique : taux d'accès par année
if (graphTaux) {
var elementsAnnee = []
for (var i = 0; i < historique.length; i++) {
elementsAnnee.push({
label: '' + historique[i].annee,
valeur: historique[i].tauxAcces,
couleur: '#1a936f'
})
}
var rows = ''
for (var i = 0; i < hist.length; i++) {
var h = hist[i]
var sizeCand = 0
var sizeAdmis = 0
graphTaux.innerHTML = this.construireGraphiqueColonnes(elementsAnnee)
}
// Graphique : candidats vs admis
if (graphCandidats) {
var maxCandidats = 0
for (var i = 0; i < historique.length; i++) {
if (historique[i].candidats > maxCandidats) {
maxCandidats = historique[i].candidats
}
}
var lignes = ''
for (var i = 0; i < historique.length; i++) {
var h = historique[i]
var tailleCand = 0
var tailleAdmis = 0
if (maxCandidats > 0) {
sizeCand = Math.round((h.candidats / maxCandidats) * 100) / 100
sizeAdmis = Math.round((h.admis / maxCandidats) * 100) / 100
tailleCand = Math.round((h.candidats / maxCandidats) * 100) / 100
tailleAdmis = Math.round((h.admis / maxCandidats) * 100) / 100
}
rows += '<tr>'
rows += '<th scope="row">' + h.annee + '</th>'
rows += '<td style="--size: ' + sizeCand + '; --color: #2a5298;">'
rows += '<span class="data">' + h.candidats + '</span></td>'
rows += '<td style="--size: ' + sizeAdmis + '; --color: #1a936f;">'
rows += '<span class="data">' + h.admis + '</span></td>'
rows += '</tr>'
lignes += '<tr>'
lignes += '<th scope="row">' + h.annee + '</th>'
lignes += '<td style="--size: ' + tailleCand + '; --color: #2a5298;">'
lignes += '<span class="data">' + h.candidats + '</span></td>'
lignes += '<td style="--size: ' + tailleAdmis + '; --color: #1a936f;">'
lignes += '<span class="data">' + h.admis + '</span></td>'
lignes += '</tr>'
}
chartCandidats.innerHTML = '<table class="charts-css column multiple show-labels show-primary-axis show-4-secondary-axes data-spacing-10">'
graphCandidats.innerHTML = '<table class="charts-css column multiple show-labels show-primary-axis show-4-secondary-axes data-spacing-10">'
+ '<thead><tr><th scope="col">Année</th><th scope="col">Candidats</th><th scope="col">Admis</th></tr></thead>'
+ '<tbody>' + rows + '</tbody></table>'
+ '<tbody>' + lignes + '</tbody></table>'
}
// Tableau : évolution des mentions
if (chartMentionsHist) {
var table = '<table class="detail-table">'
table += '<thead><tr><th>Année</th><th>Sans mention</th><th>AB</th><th>Bien</th><th>TB</th><th>TB Féli.</th></tr></thead>'
table += '<tbody>'
if (graphMentionsHist) {
var tableau = '<table class="detail-table">'
tableau += '<thead><tr><th>Année</th><th>Sans mention</th><th>AB</th><th>Bien</th><th>TB</th><th>TB Féli.</th></tr></thead>'
tableau += '<tbody>'
for (var i = 0; i < hist.length; i++) {
var h = hist[i]
table += '<tr>'
table += '<td><b>' + h.annee + '</b></td>'
table += '<td>' + h.pctSansMention + '%</td>'
table += '<td>' + h.pctAB + '%</td>'
table += '<td>' + h.pctB + '%</td>'
table += '<td>' + h.pctTB + '%</td>'
table += '<td>' + h.pctTBF + '%</td>'
table += '</tr>'
for (var i = 0; i < historique.length; i++) {
var h = historique[i]
tableau += '<tr>'
tableau += '<td><b>' + h.annee + '</b></td>'
tableau += '<td>' + h.pctSansMention + '%</td>'
tableau += '<td>' + h.pctAB + '%</td>'
tableau += '<td>' + h.pctB + '%</td>'
tableau += '<td>' + h.pctTB + '%</td>'
tableau += '<td>' + h.pctTBF + '%</td>'
tableau += '</tr>'
}
table += '</tbody></table>'
chartMentionsHist.innerHTML = table
tableau += '</tbody></table>'
graphMentionsHist.innerHTML = tableau
}
},
buildColumnChart(items) {
var rows = ''
for (var i = 0; i < items.length; i++) {
var item = items[i]
var val = this.safe(item.value)
var display = item.value || 0
rows += '<tr>'
rows += '<th scope="row">' + item.label + '</th>'
rows += '<td style="--size: ' + val + '; --color: ' + item.color + ';">'
rows += '<span class="data">' + display + '%</span>'
rows += '</td></tr>'
construireGraphiqueColonnes(elements) {
var lignes = ''
for (var i = 0; i < elements.length; i++) {
var el = elements[i]
var taille = this.limiterValeur(el.valeur)
var affiche = el.valeur || 0
lignes += '<tr>'
lignes += '<th scope="row">' + el.label + '</th>'
lignes += '<td style="--size: ' + taille + '; --color: ' + el.couleur + ';">'
lignes += '<span class="data">' + affiche + '%</span>'
lignes += '</td></tr>'
}
return '<table class="charts-css column show-labels show-primary-axis show-4-secondary-axes data-spacing-10">'
+ '<thead><tr><th scope="col">Type</th><th scope="col">%</th></tr></thead>'
+ '<tbody>' + rows + '</tbody></table>'
+ '<tbody>' + lignes + '</tbody></table>'
},
buildBarChart(items) {
var rows = ''
for (var i = 0; i < items.length; i++) {
var item = items[i]
var val = this.safe(item.value)
var display = item.value || 0
rows += '<tr>'
rows += '<th scope="row">' + item.label + '</th>'
rows += '<td style="--size: ' + val + '; --color: ' + item.color + ';">'
rows += '<span class="data">' + display + '%</span>'
rows += '</td></tr>'
construireGraphiqueBarres(elements) {
var lignes = ''
for (var i = 0; i < elements.length; i++) {
var el = elements[i]
var taille = this.limiterValeur(el.valeur)
var affiche = el.valeur || 0
lignes += '<tr>'
lignes += '<th scope="row">' + el.label + '</th>'
lignes += '<td style="--size: ' + taille + '; --color: ' + el.couleur + ';">'
lignes += '<span class="data">' + affiche + '%</span>'
lignes += '</td></tr>'
}
return '<table class="charts-css bar show-labels show-primary-axis show-4-secondary-axes data-spacing-14">'
+ '<thead><tr><th scope="col">Catégorie</th><th scope="col">%</th></tr></thead>'
+ '<tbody>' + rows + '</tbody></table>'
+ '<tbody>' + lignes + '</tbody></table>'
}
}
</script>
</detail-view>