2026-03-18 12:49:28 +01:00
|
|
|
<detail-view>
|
2026-03-18 14:54:01 +01:00
|
|
|
<div if={ props.formation } class="detail-page">
|
|
|
|
|
<h2>Formation</h2>
|
|
|
|
|
<h1 class="formation-title">{ props.formation.etablissement } - { props.formation.nom }</h1>
|
|
|
|
|
<div class="formation-meta">
|
|
|
|
|
<p><b>Ville :</b> { props.formation.ville }</p>
|
|
|
|
|
<p><b>Département :</b> { props.formation.departement } { props.formation.departementLib }</p>
|
|
|
|
|
<p><b>Académie :</b> { props.formation.academie }</p>
|
|
|
|
|
<p>{ props.formation.contrat }</p>
|
|
|
|
|
<p><b>Capacité :</b> { props.formation.capacite }</p>
|
|
|
|
|
</div>
|
2026-03-18 13:25:23 +01:00
|
|
|
|
2026-03-18 14:54:01 +01:00
|
|
|
<div class="detail-grid">
|
|
|
|
|
<div>
|
|
|
|
|
<h2>Phase principale d'admission</h2>
|
|
|
|
|
<table class="detail-table">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th>Bac</th>
|
|
|
|
|
<th>Voeux</th>
|
|
|
|
|
<th>Classés</th>
|
|
|
|
|
<th>Propositions</th>
|
|
|
|
|
<th>Acceptés</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>Gén</td>
|
|
|
|
|
<td>{ props.formation.voePPGeneral }</td>
|
|
|
|
|
<td>{ props.formation.classesPPGeneral }</td>
|
|
|
|
|
<td>{ props.formation.propositionsPPGeneral }</td>
|
|
|
|
|
<td>{ props.formation.acceptesPPGeneral }</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>Techno</td>
|
|
|
|
|
<td>{ props.formation.voePPTechno }</td>
|
|
|
|
|
<td>{ props.formation.classesPPTechno }</td>
|
|
|
|
|
<td>{ props.formation.propositionsPPTechno }</td>
|
|
|
|
|
<td>{ props.formation.acceptesPPTechno }</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>Pro</td>
|
|
|
|
|
<td>{ props.formation.voePPPro }</td>
|
|
|
|
|
<td>{ props.formation.classesPPPro }</td>
|
|
|
|
|
<td>{ props.formation.propositionsPPPro }</td>
|
|
|
|
|
<td>{ props.formation.acceptesPPPro }</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>Autres</td>
|
|
|
|
|
<td>{ props.formation.voePPAutres }</td>
|
|
|
|
|
<td>{ props.formation.classesPPAutres }</td>
|
|
|
|
|
<td>{ props.formation.propositionsPPAutres }</td>
|
|
|
|
|
<td>{ props.formation.acceptesPPAutres }</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr class="total-row">
|
|
|
|
|
<td>Total</td>
|
|
|
|
|
<td>{ props.formation.voePPTotal }</td>
|
|
|
|
|
<td>{ props.formation.classesPPTotal }</td>
|
|
|
|
|
<td>{ props.formation.propositionsPPTotal }</td>
|
|
|
|
|
<td>{ props.formation.acceptesPPTotal }</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
2026-03-18 13:25:23 +01:00
|
|
|
|
2026-03-18 14:54:01 +01:00
|
|
|
<div class="timeline-box">
|
|
|
|
|
<h3>Vitesse de remplissage</h3>
|
|
|
|
|
<div class="timeline">
|
|
|
|
|
<div class="timeline-item">
|
|
|
|
|
<div class="timeline-dot"></div>
|
|
|
|
|
<div>
|
|
|
|
|
<b>Ouverture 30 mai</b><br />
|
|
|
|
|
{ props.formation.pctDebutPhase }%
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="timeline-item">
|
|
|
|
|
<div class="timeline-dot"></div>
|
|
|
|
|
<div>
|
|
|
|
|
<b>16 juin</b><br />
|
|
|
|
|
{ props.formation.pctDateBac }%
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="timeline-item">
|
|
|
|
|
<div class="timeline-dot"></div>
|
|
|
|
|
<div>
|
|
|
|
|
<b>11 juillet</b><br />
|
|
|
|
|
{ props.formation.pctFinPhase }%
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-03-18 13:25:23 +01:00
|
|
|
|
2026-03-18 14:54:01 +01:00
|
|
|
<h2>Phase complémentaire d'admission</h2>
|
|
|
|
|
<table class="detail-table">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th>Bac</th>
|
|
|
|
|
<th>Voeux</th>
|
|
|
|
|
<th>Classés</th>
|
|
|
|
|
<th>Propositions</th>
|
|
|
|
|
<th>Acceptés</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>Gén</td>
|
|
|
|
|
<td>{ props.formation.voePCGeneral }</td>
|
|
|
|
|
<td></td>
|
|
|
|
|
<td></td>
|
|
|
|
|
<td></td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>Techno</td>
|
|
|
|
|
<td>{ props.formation.voePCTechno }</td>
|
|
|
|
|
<td></td>
|
|
|
|
|
<td></td>
|
|
|
|
|
<td></td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>Pro</td>
|
|
|
|
|
<td>{ props.formation.voePCPro }</td>
|
|
|
|
|
<td></td>
|
|
|
|
|
<td></td>
|
|
|
|
|
<td></td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>Autres</td>
|
|
|
|
|
<td>{ props.formation.voePCAutres }</td>
|
|
|
|
|
<td></td>
|
|
|
|
|
<td></td>
|
|
|
|
|
<td></td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr class="total-row">
|
|
|
|
|
<td>Total</td>
|
|
|
|
|
<td>{ props.formation.voePCTotal }</td>
|
|
|
|
|
<td>{ props.formation.classesPCTotal }</td>
|
|
|
|
|
<td>{ props.formation.acceptesPCTotal }</td>
|
|
|
|
|
<td>{ props.formation.acceptesPCTotal }</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
2026-03-18 13:25:23 +01:00
|
|
|
|
2026-03-19 14:37:08 +01:00
|
|
|
<!-- ===================== 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>
|
2026-03-20 01:51:08 +01:00
|
|
|
<div id="chart-bac" ref="chartBac"></div>
|
2026-03-19 14:37:08 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="chart-wrapper">
|
|
|
|
|
<h3>Mentions au bac des admis</h3>
|
2026-03-20 01:51:08 +01:00
|
|
|
<div id="chart-mentions" ref="chartMentions"></div>
|
2026-03-19 14:37:08 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="chart-wrapper chart-full">
|
|
|
|
|
<h3>Profil sociologique</h3>
|
2026-03-20 01:51:08 +01:00
|
|
|
<div id="chart-profil" ref="chartProfil"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-03-19 14:37:08 +01:00
|
|
|
|
2026-03-20 01:51:08 +01:00
|
|
|
<!-- ===================== ÉVOLUTION HISTORIQUE ===================== -->
|
|
|
|
|
|
|
|
|
|
<h2 class="charts-heading">Évolution depuis 2020</h2>
|
|
|
|
|
|
|
|
|
|
<div if={ state.loadingHistory } class="message">
|
|
|
|
|
Chargement de l'historique...
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div if={ !state.loadingHistory && state.history.length === 0 } class="message">
|
|
|
|
|
Aucune donnée historique disponible pour cette formation.
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="charts-section" if={ state.history.length > 0 }>
|
|
|
|
|
<div class="chart-wrapper">
|
|
|
|
|
<h3>Taux d'accès par année</h3>
|
|
|
|
|
<div id="chart-evolution-taux" ref="chartTaux"></div>
|
2026-03-19 14:37:08 +01:00
|
|
|
</div>
|
|
|
|
|
|
2026-03-20 01:51:08 +01:00
|
|
|
<div class="chart-wrapper">
|
|
|
|
|
<h3>Nombre de candidats et admis</h3>
|
|
|
|
|
<div id="chart-evolution-candidats" ref="chartCandidats"></div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="chart-wrapper chart-full">
|
|
|
|
|
<h3>Évolution des mentions au bac</h3>
|
|
|
|
|
<div ref="chartMentionsHist"></div>
|
|
|
|
|
</div>
|
2026-03-19 14:37:08 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button onclick={ () => props.onback() } class="btn-retour">Retour à la liste</button>
|
2026-03-18 12:49:28 +01:00
|
|
|
</div>
|
2026-03-19 14:37:08 +01:00
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
export default {
|
2026-03-20 01:51:08 +01:00
|
|
|
state: {
|
|
|
|
|
history: [],
|
|
|
|
|
loadingHistory: false
|
|
|
|
|
},
|
|
|
|
|
|
2026-03-19 14:37:08 +01:00
|
|
|
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
|
2026-03-20 01:51:08 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onMounted() {
|
|
|
|
|
this.renderCharts()
|
|
|
|
|
this.loadHistory()
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onUpdated() {
|
|
|
|
|
this.renderCharts()
|
|
|
|
|
if (this.state.history.length > 0) {
|
|
|
|
|
this.renderHistoryCharts()
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
renderCharts() {
|
|
|
|
|
var f = this.props.formation
|
|
|
|
|
if (!f) return
|
|
|
|
|
|
|
|
|
|
var chartBac = this.$('[ref="chartBac"]')
|
|
|
|
|
var chartMentions = this.$('[ref="chartMentions"]')
|
|
|
|
|
var chartProfil = this.$('[ref="chartProfil"]')
|
|
|
|
|
|
|
|
|
|
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 (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 (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' }
|
|
|
|
|
])
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async loadHistory() {
|
|
|
|
|
var f = this.props.formation
|
|
|
|
|
if (!f) return
|
|
|
|
|
|
|
|
|
|
// Extraire le cod_uai de l'id (format: codUai-nomFormation)
|
|
|
|
|
var codUai = f.id.split('-')[0]
|
|
|
|
|
|
|
|
|
|
if (!codUai || !window.fetchFormationHistory) return
|
|
|
|
|
|
|
|
|
|
this.update({ loadingHistory: true })
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
var history = await window.fetchFormationHistory(codUai, f.nom)
|
|
|
|
|
this.update({ history: history, loadingHistory: false })
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('Erreur historique:', e)
|
|
|
|
|
this.update({ history: [], loadingHistory: 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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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 rows = ''
|
|
|
|
|
for (var i = 0; i < hist.length; i++) {
|
|
|
|
|
var h = hist[i]
|
|
|
|
|
var sizeCand = maxCandidats > 0 ? Math.round((h.candidats / maxCandidats) * 100) / 100 : 0
|
|
|
|
|
var sizeAdmis = maxCandidats > 0 ? Math.round((h.admis / maxCandidats) * 100) / 100 : 0
|
|
|
|
|
|
|
|
|
|
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>'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chartCandidats.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>'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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>'
|
|
|
|
|
|
|
|
|
|
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>'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
table += '</tbody></table>'
|
|
|
|
|
chartMentionsHist.innerHTML = table
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
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>'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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>'
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
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>'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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>'
|
2026-03-19 14:37:08 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
</detail-view>
|