maj
This commit is contained in:
+64
-54
@@ -1,34 +1,35 @@
|
|||||||
export function buildURL(query, limit = 20, offset = 0, filters = {}) {
|
// Construire l'URL de requête vers l'API Parcoursup
|
||||||
let url =
|
export function construireURL(requete, limite = 20, decalage = 0, filtres = {}) {
|
||||||
"https://data.enseignementsup-recherche.gouv.fr/api/explore/v2.1/catalog/datasets/fr-esr-parcoursup/records?"
|
|
||||||
|
|
||||||
url += "limit=" + limit
|
var url = "https://data.enseignementsup-recherche.gouv.fr/api/explore/v2.1/catalog/datasets/fr-esr-parcoursup/records?"
|
||||||
url += "&offset=" + offset
|
|
||||||
|
url += "limit=" + limite
|
||||||
|
url += "&offset=" + decalage
|
||||||
|
|
||||||
var conditions = []
|
var conditions = []
|
||||||
|
|
||||||
if (query && query.trim() !== "") {
|
if (requete && requete.trim() !== "") {
|
||||||
conditions.push("search(lib_for_voe_ins, '" + query + "')")
|
conditions.push("search(lib_for_voe_ins, '" + requete + "')")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.filiere && filters.filiere !== "") {
|
if (filtres.filiere && filtres.filiere !== "") {
|
||||||
conditions.push("fili='" + filters.filiere + "'")
|
conditions.push("fili='" + filtres.filiere + "'")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.selectivite && filters.selectivite !== "") {
|
if (filtres.selectivite && filtres.selectivite !== "") {
|
||||||
conditions.push("select_form='" + filters.selectivite + "'")
|
conditions.push("select_form='" + filtres.selectivite + "'")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.region && filters.region !== "") {
|
if (filtres.region && filtres.region !== "") {
|
||||||
conditions.push("region_etab_aff='" + filters.region + "'")
|
conditions.push("region_etab_aff='" + filtres.region + "'")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.tauxMin && filters.tauxMin > 0) {
|
if (filtres.tauxMin && filtres.tauxMin > 0) {
|
||||||
conditions.push("taux_acces_ens>=" + filters.tauxMin)
|
conditions.push("taux_acces_ens>=" + filtres.tauxMin)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.tauxMax && filters.tauxMax < 100) {
|
if (filtres.tauxMax && filtres.tauxMax < 100) {
|
||||||
conditions.push("taux_acces_ens<=" + filters.tauxMax)
|
conditions.push("taux_acces_ens<=" + filtres.tauxMax)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conditions.length > 0) {
|
if (conditions.length > 0) {
|
||||||
@@ -38,19 +39,23 @@ export function buildURL(query, limit = 20, offset = 0, filters = {}) {
|
|||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchFormations(query, limit = 20, offset = 0, filters = {}) {
|
// Charger les formations depuis l'API Parcoursup
|
||||||
const url = buildURL(query, limit, offset, filters)
|
export async function chargerFormations(requete, limite = 20, decalage = 0, filtres = {}) {
|
||||||
const response = await fetch(url)
|
|
||||||
|
|
||||||
if (!response.ok) {
|
var url = construireURL(requete, limite, decalage, filtres)
|
||||||
|
var reponse = await fetch(url)
|
||||||
|
|
||||||
|
if (!reponse.ok) {
|
||||||
throw new Error("Erreur HTTP")
|
throw new Error("Erreur HTTP")
|
||||||
}
|
}
|
||||||
|
|
||||||
return await response.json()
|
return await reponse.json()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchFormationHistory(codUai, nomFormation) {
|
// Charger l'historique d'une formation sur plusieurs années
|
||||||
var datasets = {
|
export async function chargerHistoriqueFormation(codUai, nomFormation) {
|
||||||
|
|
||||||
|
var jeuDeDonnees = {
|
||||||
2020: "fr-esr-parcoursup_2020",
|
2020: "fr-esr-parcoursup_2020",
|
||||||
2021: "fr-esr-parcoursup_2021",
|
2021: "fr-esr-parcoursup_2021",
|
||||||
2022: "fr-esr-parcoursup_2022",
|
2022: "fr-esr-parcoursup_2022",
|
||||||
@@ -59,54 +64,59 @@ export async function fetchFormationHistory(codUai, nomFormation) {
|
|||||||
2025: "fr-esr-parcoursup"
|
2025: "fr-esr-parcoursup"
|
||||||
}
|
}
|
||||||
|
|
||||||
var history = []
|
var historique = []
|
||||||
var searchName = nomFormation.substring(0, 40).replace(/'/g, "\\'")
|
var nomCourt = nomFormation.substring(0, 40).replace(/'/g, "\\'")
|
||||||
var years = [2020, 2021, 2022, 2023, 2024, 2025]
|
var annees = [2020, 2021, 2022, 2023, 2024, 2025]
|
||||||
|
|
||||||
for (var i = 0; i < years.length; i++) {
|
for (var i = 0; i < annees.length; i++) {
|
||||||
var year = years[i]
|
|
||||||
var dataset = datasets[year]
|
var annee = annees[i]
|
||||||
|
var dataset = jeuDeDonnees[annee]
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
var url = "https://data.enseignementsup-recherche.gouv.fr/api/explore/v2.1/catalog/datasets/"
|
var url = "https://data.enseignementsup-recherche.gouv.fr/api/explore/v2.1/catalog/datasets/"
|
||||||
+ dataset + "/records?"
|
+ dataset + "/records?"
|
||||||
+ "limit=5"
|
+ "limit=5"
|
||||||
+ "&where=cod_uai%3D'" + codUai + "' AND search(lib_for_voe_ins, '" + searchName + "')"
|
+ "&where=cod_uai%3D'" + codUai + "' AND search(lib_for_voe_ins, '" + nomCourt + "')"
|
||||||
+ "&select=cod_uai,lib_for_voe_ins,voe_tot,acc_tot,pct_sansmention,pct_ab,pct_b,pct_tb,pct_tbf,pct_bg,pct_bt,pct_bp"
|
+ "&select=cod_uai,lib_for_voe_ins,voe_tot,acc_tot,pct_sansmention,pct_ab,pct_b,pct_tb,pct_tbf,pct_bg,pct_bt,pct_bp"
|
||||||
|
|
||||||
var response = await fetch(url)
|
var reponse = await fetch(url)
|
||||||
|
|
||||||
if (response.ok) {
|
if (reponse.ok) {
|
||||||
var data = await response.json()
|
|
||||||
|
|
||||||
if (data.results && data.results.length > 0) {
|
var donnees = await reponse.json()
|
||||||
var r = data.results[0]
|
|
||||||
var taux = 0
|
|
||||||
|
|
||||||
if (r.voe_tot && r.voe_tot > 0) {
|
if (donnees.results && donnees.results.length > 0) {
|
||||||
taux = Math.round((r.acc_tot / r.voe_tot) * 100)
|
|
||||||
|
var ligne = donnees.results[0]
|
||||||
|
var taux = 0
|
||||||
|
|
||||||
|
if (ligne.voe_tot && ligne.voe_tot > 0) {
|
||||||
|
taux = Math.round((ligne.acc_tot / ligne.voe_tot) * 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
history.push({
|
historique.push({
|
||||||
annee: year,
|
annee: annee,
|
||||||
tauxAcces: taux,
|
tauxAcces: taux,
|
||||||
candidats: r.voe_tot || 0,
|
candidats: ligne.voe_tot || 0,
|
||||||
admis: r.acc_tot || 0,
|
admis: ligne.acc_tot || 0,
|
||||||
pctSansMention: r.pct_sansmention || 0,
|
pctSansMention: ligne.pct_sansmention || 0,
|
||||||
pctAB: r.pct_ab || 0,
|
pctAB: ligne.pct_ab || 0,
|
||||||
pctB: r.pct_b || 0,
|
pctB: ligne.pct_b || 0,
|
||||||
pctTB: r.pct_tb || 0,
|
pctTB: ligne.pct_tb || 0,
|
||||||
pctTBF: r.pct_tbf || 0,
|
pctTBF: ligne.pct_tbf || 0,
|
||||||
pctGeneral: r.pct_bg || 0,
|
pctGeneral: ligne.pct_bg || 0,
|
||||||
pctTechno: r.pct_bt || 0,
|
pctTechno: ligne.pct_bt || 0,
|
||||||
pctPro: r.pct_bp || 0
|
pctPro: ligne.pct_bp || 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("Erreur pour " + year + ":", e)
|
console.warn("Erreur pour l'année " + annee + " :", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return history
|
return historique
|
||||||
}
|
}
|
||||||
|
|||||||
+204
-142
File diff suppressed because it is too large
Load Diff
@@ -2,37 +2,37 @@
|
|||||||
|
|
||||||
<!-- Bouton connexion dans le header (utilisateur non connecté) -->
|
<!-- Bouton connexion dans le header (utilisateur non connecté) -->
|
||||||
<div class="auth-header-btn" if={ !props.user }>
|
<div class="auth-header-btn" if={ !props.user }>
|
||||||
<button class="btn btn-auth" onclick={ openModal }>
|
<button class="btn btn-auth" onclick={ ouvrirModale }>
|
||||||
<span class="auth-icon">👤</span> Connexion
|
<span class="auth-icon"></span> Connexion
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Email + bouton déconnexion dans le header (utilisateur connecté) -->
|
<!-- Email + bouton déconnexion dans le header (utilisateur connecté) -->
|
||||||
<div class="auth-user-info" if={ props.user }>
|
<div class="auth-user-info" if={ props.user }>
|
||||||
<span class="auth-email">{ props.user.email }</span>
|
<span class="auth-email">{ props.user.email }</span>
|
||||||
<button class="btn btn-auth-logout" onclick={ handleLogout }>Déconnexion</button>
|
<button class="btn btn-auth-logout" onclick={ seDeconnecter }>Déconnexion</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Modale d'authentification -->
|
<!-- Modale d'authentification -->
|
||||||
<div class="auth-modal-overlay" if={ state.open } onclick={ closeOnOverlay }>
|
<div class="auth-modal-overlay" if={ state.visible } onclick={ cliquerFond }>
|
||||||
<div class="auth-modal">
|
<div class="auth-modal">
|
||||||
|
|
||||||
<button class="auth-modal-close" onclick={ closeModal }>✕</button>
|
<button class="auth-modal-close" onclick={ fermerModale }>✕</button>
|
||||||
|
|
||||||
<h2 class="auth-modal-title">{ state.titre }</h2>
|
<h2 class="auth-modal-title">{ state.titre }</h2>
|
||||||
|
|
||||||
<!-- Onglets Connexion / Inscription -->
|
<!-- Onglets Connexion / Inscription -->
|
||||||
<div class="auth-tabs">
|
<div class="auth-tabs">
|
||||||
<button class={ state.classBtnLogin } onclick={ switchToLogin }>
|
<button class={ state.classBtnConnexion } onclick={ afficherConnexion }>
|
||||||
Connexion
|
Connexion
|
||||||
</button>
|
</button>
|
||||||
<button class={ state.classBtnRegister } onclick={ switchToRegister }>
|
<button class={ state.classBtnInscription } onclick={ afficherInscription }>
|
||||||
Inscription
|
Inscription
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Formulaire -->
|
<!-- Formulaire -->
|
||||||
<form onsubmit={ handleSubmit } class="auth-form">
|
<form onsubmit={ validerFormulaire } class="auth-form">
|
||||||
|
|
||||||
<div class="auth-field">
|
<div class="auth-field">
|
||||||
<label>Adresse e-mail</label>
|
<label>Adresse e-mail</label>
|
||||||
@@ -56,11 +56,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Message d'erreur -->
|
<!-- Message d'erreur -->
|
||||||
<div class="auth-error" if={ state.error }>
|
<div class="auth-error" if={ state.erreur }>
|
||||||
{ state.error }
|
{ state.erreur }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary auth-submit" disabled={ state.loading }>
|
<button type="submit" class="btn btn-primary auth-submit" disabled={ state.chargement }>
|
||||||
{ state.labelBouton }
|
{ state.labelBouton }
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -72,93 +72,94 @@
|
|||||||
export default {
|
export default {
|
||||||
|
|
||||||
state: {
|
state: {
|
||||||
open: false,
|
visible: false,
|
||||||
mode: 'login',
|
mode: 'connexion',
|
||||||
loading: false,
|
chargement: false,
|
||||||
error: null,
|
erreur: null,
|
||||||
titre: 'Connexion',
|
titre: 'Connexion',
|
||||||
labelBouton: 'Se connecter',
|
labelBouton: 'Se connecter',
|
||||||
classBtnLogin: 'auth-tab active',
|
classBtnConnexion: 'auth-tab active',
|
||||||
classBtnRegister: 'auth-tab'
|
classBtnInscription: 'auth-tab'
|
||||||
},
|
},
|
||||||
|
|
||||||
openModal() {
|
ouvrirModale() {
|
||||||
this.update({ open: true, error: null })
|
this.update({ visible: true, erreur: null })
|
||||||
},
|
},
|
||||||
|
|
||||||
closeModal() {
|
fermerModale() {
|
||||||
this.update({ open: false, error: null })
|
this.update({ visible: false, erreur: null })
|
||||||
},
|
},
|
||||||
|
|
||||||
closeOnOverlay(e) {
|
// Fermer si l'utilisateur clique en dehors de la modale
|
||||||
|
cliquerFond(e) {
|
||||||
if (e.target === e.currentTarget) {
|
if (e.target === e.currentTarget) {
|
||||||
this.closeModal()
|
this.fermerModale()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
switchToLogin() {
|
afficherConnexion() {
|
||||||
this.update({
|
this.update({
|
||||||
mode: 'login',
|
mode: 'connexion',
|
||||||
error: null,
|
erreur: null,
|
||||||
titre: 'Connexion',
|
titre: 'Connexion',
|
||||||
labelBouton: 'Se connecter',
|
labelBouton: 'Se connecter',
|
||||||
classBtnLogin: 'auth-tab active',
|
classBtnConnexion: 'auth-tab active',
|
||||||
classBtnRegister: 'auth-tab'
|
classBtnInscription: 'auth-tab'
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
switchToRegister() {
|
afficherInscription() {
|
||||||
this.update({
|
this.update({
|
||||||
mode: 'register',
|
mode: 'inscription',
|
||||||
error: null,
|
erreur: null,
|
||||||
titre: 'Créer un compte',
|
titre: 'Créer un compte',
|
||||||
labelBouton: 'Créer le compte',
|
labelBouton: 'Créer le compte',
|
||||||
classBtnLogin: 'auth-tab',
|
classBtnConnexion: 'auth-tab',
|
||||||
classBtnRegister: 'auth-tab active'
|
classBtnInscription: 'auth-tab active'
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleSubmit(e) {
|
async validerFormulaire(e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
var email = e.target.email.value.trim()
|
var email = e.target.email.value.trim()
|
||||||
var password = e.target.password.value
|
var password = e.target.password.value
|
||||||
var services = window.firebaseServices
|
var services = window.firebaseServices
|
||||||
|
|
||||||
this.update({ loading: true, error: null })
|
this.update({ chargement: true, erreur: null })
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (this.state.mode === 'register') {
|
if (this.state.mode === 'inscription') {
|
||||||
await services.createAccount(email, password)
|
await services.createAccount(email, password)
|
||||||
} else {
|
} else {
|
||||||
await services.login(email, password)
|
await services.login(email, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.update({ open: false, loading: false })
|
this.update({ visible: false, chargement: false })
|
||||||
this.props.onauth && this.props.onauth()
|
this.props.onauth && this.props.onauth()
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
||||||
var message = 'Une erreur est survenue.'
|
var messageErreur = 'Une erreur est survenue.'
|
||||||
|
|
||||||
if (err.code === 'auth/email-already-in-use') {
|
if (err.code === 'auth/email-already-in-use') {
|
||||||
message = 'Cet e-mail est déjà utilisé.'
|
messageErreur = 'Cet e-mail est déjà utilisé.'
|
||||||
} else if (err.code === 'auth/invalid-email') {
|
} else if (err.code === 'auth/invalid-email') {
|
||||||
message = 'Adresse e-mail invalide.'
|
messageErreur = 'Adresse e-mail invalide.'
|
||||||
} else if (err.code === 'auth/wrong-password' || err.code === 'auth/invalid-credential') {
|
} else if (err.code === 'auth/wrong-password' || err.code === 'auth/invalid-credential') {
|
||||||
message = 'E-mail ou mot de passe incorrect.'
|
messageErreur = 'E-mail ou mot de passe incorrect.'
|
||||||
} else if (err.code === 'auth/weak-password') {
|
} else if (err.code === 'auth/weak-password') {
|
||||||
message = 'Le mot de passe doit faire au moins 6 caractères.'
|
messageErreur = 'Le mot de passe doit faire au moins 6 caractères.'
|
||||||
} else if (err.code === 'auth/user-not-found') {
|
} else if (err.code === 'auth/user-not-found') {
|
||||||
message = 'Aucun compte trouvé avec cet e-mail.'
|
messageErreur = 'Aucun compte trouvé avec cet e-mail.'
|
||||||
}
|
}
|
||||||
|
|
||||||
this.update({ loading: false, error: message })
|
this.update({ chargement: false, erreur: messageErreur })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleLogout() {
|
async seDeconnecter() {
|
||||||
try {
|
try {
|
||||||
await window.firebaseServices.logout()
|
await window.firebaseServices.logout()
|
||||||
this.props.onlogout && this.props.onlogout()
|
this.props.onlogout && this.props.onlogout()
|
||||||
|
|||||||
@@ -141,257 +141,288 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<!-- ===================== GRAPHIQUES CHARTS.CSS ===================== -->
|
<!-- ==================== GRAPHIQUES CHARTS.CSS ==================== -->
|
||||||
|
|
||||||
<h2 class="charts-heading">Profil des admis</h2>
|
<h2 class="charts-heading">Profil des admis</h2>
|
||||||
|
|
||||||
<div class="charts-section">
|
<div class="charts-section">
|
||||||
<div class="chart-wrapper">
|
<div class="chart-wrapper">
|
||||||
<h3>Répartition par type de bac</h3>
|
<h3>Répartition par type de bac</h3>
|
||||||
<div id="chart-bac" ref="chartBac"></div>
|
<div id="chart-bac" ref="graphBac"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chart-wrapper">
|
<div class="chart-wrapper">
|
||||||
<h3>Mentions au bac des admis</h3>
|
<h3>Mentions au bac des admis</h3>
|
||||||
<div id="chart-mentions" ref="chartMentions"></div>
|
<div id="chart-mentions" ref="graphMentions"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chart-wrapper chart-full">
|
<div class="chart-wrapper chart-full">
|
||||||
<h3>Profil sociologique</h3>
|
<h3>Profil sociologique</h3>
|
||||||
<div id="chart-profil" ref="chartProfil"></div>
|
<div id="chart-profil" ref="graphProfil"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ===================== ÉVOLUTION HISTORIQUE ===================== -->
|
<!-- ==================== ÉVOLUTION HISTORIQUE ==================== -->
|
||||||
|
|
||||||
<h2 class="charts-heading">Évolution depuis 2020</h2>
|
<h2 class="charts-heading">Évolution depuis 2020</h2>
|
||||||
|
|
||||||
<div if={ state.loadingHistory } class="message">
|
<div if={ state.chargementHistorique } class="message">
|
||||||
Chargement de l'historique...
|
Chargement de l'historique...
|
||||||
</div>
|
</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.
|
Aucune donnée historique disponible pour cette formation.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="charts-section" if={ state.history.length > 0 }>
|
<div class="charts-section" if={ state.historique.length > 0 }>
|
||||||
<div class="chart-wrapper">
|
<div class="chart-wrapper">
|
||||||
<h3>Taux d'accès par année</h3>
|
<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>
|
||||||
|
|
||||||
<div class="chart-wrapper">
|
<div class="chart-wrapper">
|
||||||
<h3>Nombre de candidats et admis</h3>
|
<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>
|
||||||
|
|
||||||
<div class="chart-wrapper chart-full">
|
<div class="chart-wrapper chart-full">
|
||||||
<h3>Évolution des mentions au bac</h3>
|
<h3>Évolution des mentions au bac</h3>
|
||||||
<div ref="chartMentionsHist"></div>
|
<div ref="graphMentionsHist"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button onclick={ goBack } class="btn-retour">Retour à la liste</button>
|
<button onclick={ retourListe } class="btn-retour">Retour à la liste</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
state: {
|
|
||||||
history: [],
|
|
||||||
loadingHistory: false
|
|
||||||
},
|
|
||||||
|
|
||||||
safe(val) {
|
state: {
|
||||||
if (val === null || val === undefined || isNaN(val)) return 0
|
historique: [],
|
||||||
var v = val / 100
|
chargementHistorique: false
|
||||||
if (v > 1) return 1
|
|
||||||
if (v < 0) return 0
|
|
||||||
return Math.round(v * 100) / 100
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onMounted() {
|
onMounted() {
|
||||||
this.renderCharts()
|
this.afficherGraphiques()
|
||||||
this.loadHistory()
|
this.chargerHistorique()
|
||||||
},
|
},
|
||||||
|
|
||||||
onUpdated() {
|
onUpdated() {
|
||||||
this.renderCharts()
|
this.afficherGraphiques()
|
||||||
if (this.state.history.length > 0) {
|
|
||||||
this.renderHistoryCharts()
|
if (this.state.historique.length > 0) {
|
||||||
|
this.afficherGraphiquesHistoriques()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Retour à la liste des résultats
|
// Retour à la liste des résultats
|
||||||
goBack() {
|
retourListe() {
|
||||||
this.props.onback()
|
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
|
var f = this.props.formation
|
||||||
if (!f) return
|
if (!f) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var chartBac = this.$('[ref="chartBac"]')
|
var graphBac = this.$('[ref="graphBac"]')
|
||||||
var chartMentions = this.$('[ref="chartMentions"]')
|
var graphMentions = this.$('[ref="graphMentions"]')
|
||||||
var chartProfil = this.$('[ref="chartProfil"]')
|
var graphProfil = this.$('[ref="graphProfil"]')
|
||||||
|
|
||||||
if (chartBac) {
|
if (graphBac) {
|
||||||
chartBac.innerHTML = this.buildColumnChart([
|
graphBac.innerHTML = this.construireGraphiqueColonnes([
|
||||||
{ label: 'Général', value: f.pctGeneral, color: '#3d7fff' },
|
{ label: 'Général', valeur: f.pctGeneral, couleur: '#3d7fff' },
|
||||||
{ label: 'Techno', value: f.pctTechno, color: '#f59e0b' },
|
{ label: 'Techno', valeur: f.pctTechno, couleur: '#f59e0b' },
|
||||||
{ label: 'Pro', value: f.pctPro, color: '#10b981' }
|
{ label: 'Pro', valeur: f.pctPro, couleur: '#10b981' }
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chartMentions) {
|
if (graphMentions) {
|
||||||
chartMentions.innerHTML = this.buildColumnChart([
|
graphMentions.innerHTML = this.construireGraphiqueColonnes([
|
||||||
{ label: 'Sans', value: f.pctSansMention, color: '#94a3b8' },
|
{ label: 'Sans', valeur: f.pctSansMention, couleur: '#94a3b8' },
|
||||||
{ label: 'AB', value: f.pctAB, color: '#60a5fa' },
|
{ label: 'AB', valeur: f.pctAB, couleur: '#60a5fa' },
|
||||||
{ label: 'Bien', value: f.pctB, color: '#34d399' },
|
{ label: 'Bien', valeur: f.pctB, couleur: '#34d399' },
|
||||||
{ label: 'TB', value: f.pctTB, color: '#fbbf24' },
|
{ label: 'TB', valeur: f.pctTB, couleur: '#fbbf24' },
|
||||||
{ label: 'TB Féli.', value: f.pctTBF, color: '#f472b6' }
|
{ label: 'TB Féli.', valeur: f.pctTBF, couleur: '#f472b6' }
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chartProfil) {
|
if (graphProfil) {
|
||||||
chartProfil.innerHTML = this.buildBarChart([
|
graphProfil.innerHTML = this.construireGraphiqueBarres([
|
||||||
{ label: 'Femmes', value: f.pctFemmes, color: '#a78bfa' },
|
{ label: 'Femmes', valeur: f.pctFemmes, couleur: '#a78bfa' },
|
||||||
{ label: 'Boursiers', value: f.pctBoursiers, color: '#fb923c' },
|
{ label: 'Boursiers', valeur: f.pctBoursiers, couleur: '#fb923c' },
|
||||||
{ label: 'Néo-bac', value: f.pctNeoBac, color: '#2dd4bf' }
|
{ label: 'Néo-bac', valeur: f.pctNeoBac, couleur: '#2dd4bf' }
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadHistory() {
|
async chargerHistorique() {
|
||||||
var f = this.props.formation
|
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]
|
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 {
|
try {
|
||||||
var history = await window.fetchFormationHistory(codUai, f.nom)
|
var historique = await window.chargerHistoriqueFormation(codUai, f.nom)
|
||||||
this.update({ history: history, loadingHistory: false })
|
this.update({ historique: historique, chargementHistorique: false })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Erreur historique:', e)
|
console.error('Erreur chargement historique :', e)
|
||||||
this.update({ history: [], loadingHistory: false })
|
this.update({ historique: [], chargementHistorique: false })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
renderHistoryCharts() {
|
afficherGraphiquesHistoriques() {
|
||||||
var hist = this.state.history
|
var historique = this.state.historique
|
||||||
if (!hist || hist.length === 0) return
|
if (!historique || historique.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)
|
var graphTaux = this.$('[ref="graphTaux"]')
|
||||||
if (chartCandidats) {
|
var graphCandidats = this.$('[ref="graphCandidats"]')
|
||||||
var maxCandidats = 0
|
var graphMentionsHist = this.$('[ref="graphMentionsHist"]')
|
||||||
for (var i = 0; i < hist.length; i++) {
|
|
||||||
if (hist[i].candidats > maxCandidats) maxCandidats = hist[i].candidats
|
// 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 = ''
|
graphTaux.innerHTML = this.construireGraphiqueColonnes(elementsAnnee)
|
||||||
for (var i = 0; i < hist.length; i++) {
|
}
|
||||||
var h = hist[i]
|
|
||||||
var sizeCand = 0
|
// Graphique : candidats vs admis
|
||||||
var sizeAdmis = 0
|
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) {
|
if (maxCandidats > 0) {
|
||||||
sizeCand = Math.round((h.candidats / maxCandidats) * 100) / 100
|
tailleCand = Math.round((h.candidats / maxCandidats) * 100) / 100
|
||||||
sizeAdmis = Math.round((h.admis / maxCandidats) * 100) / 100
|
tailleAdmis = Math.round((h.admis / maxCandidats) * 100) / 100
|
||||||
}
|
}
|
||||||
|
|
||||||
rows += '<tr>'
|
lignes += '<tr>'
|
||||||
rows += '<th scope="row">' + h.annee + '</th>'
|
lignes += '<th scope="row">' + h.annee + '</th>'
|
||||||
rows += '<td style="--size: ' + sizeCand + '; --color: #2a5298;">'
|
lignes += '<td style="--size: ' + tailleCand + '; --color: #2a5298;">'
|
||||||
rows += '<span class="data">' + h.candidats + '</span></td>'
|
lignes += '<span class="data">' + h.candidats + '</span></td>'
|
||||||
rows += '<td style="--size: ' + sizeAdmis + '; --color: #1a936f;">'
|
lignes += '<td style="--size: ' + tailleAdmis + '; --color: #1a936f;">'
|
||||||
rows += '<span class="data">' + h.admis + '</span></td>'
|
lignes += '<span class="data">' + h.admis + '</span></td>'
|
||||||
rows += '</tr>'
|
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>'
|
+ '<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
|
// Tableau : évolution des mentions
|
||||||
if (chartMentionsHist) {
|
if (graphMentionsHist) {
|
||||||
var table = '<table class="detail-table">'
|
var tableau = '<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>'
|
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>'
|
||||||
table += '<tbody>'
|
tableau += '<tbody>'
|
||||||
|
|
||||||
for (var i = 0; i < hist.length; i++) {
|
for (var i = 0; i < historique.length; i++) {
|
||||||
var h = hist[i]
|
var h = historique[i]
|
||||||
table += '<tr>'
|
tableau += '<tr>'
|
||||||
table += '<td><b>' + h.annee + '</b></td>'
|
tableau += '<td><b>' + h.annee + '</b></td>'
|
||||||
table += '<td>' + h.pctSansMention + '%</td>'
|
tableau += '<td>' + h.pctSansMention + '%</td>'
|
||||||
table += '<td>' + h.pctAB + '%</td>'
|
tableau += '<td>' + h.pctAB + '%</td>'
|
||||||
table += '<td>' + h.pctB + '%</td>'
|
tableau += '<td>' + h.pctB + '%</td>'
|
||||||
table += '<td>' + h.pctTB + '%</td>'
|
tableau += '<td>' + h.pctTB + '%</td>'
|
||||||
table += '<td>' + h.pctTBF + '%</td>'
|
tableau += '<td>' + h.pctTBF + '%</td>'
|
||||||
table += '</tr>'
|
tableau += '</tr>'
|
||||||
}
|
}
|
||||||
|
|
||||||
table += '</tbody></table>'
|
tableau += '</tbody></table>'
|
||||||
chartMentionsHist.innerHTML = table
|
graphMentionsHist.innerHTML = tableau
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
buildColumnChart(items) {
|
construireGraphiqueColonnes(elements) {
|
||||||
var rows = ''
|
var lignes = ''
|
||||||
for (var i = 0; i < items.length; i++) {
|
|
||||||
var item = items[i]
|
for (var i = 0; i < elements.length; i++) {
|
||||||
var val = this.safe(item.value)
|
var el = elements[i]
|
||||||
var display = item.value || 0
|
var taille = this.limiterValeur(el.valeur)
|
||||||
rows += '<tr>'
|
var affiche = el.valeur || 0
|
||||||
rows += '<th scope="row">' + item.label + '</th>'
|
|
||||||
rows += '<td style="--size: ' + val + '; --color: ' + item.color + ';">'
|
lignes += '<tr>'
|
||||||
rows += '<span class="data">' + display + '%</span>'
|
lignes += '<th scope="row">' + el.label + '</th>'
|
||||||
rows += '</td></tr>'
|
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">'
|
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>'
|
+ '<thead><tr><th scope="col">Type</th><th scope="col">%</th></tr></thead>'
|
||||||
+ '<tbody>' + rows + '</tbody></table>'
|
+ '<tbody>' + lignes + '</tbody></table>'
|
||||||
},
|
},
|
||||||
|
|
||||||
buildBarChart(items) {
|
construireGraphiqueBarres(elements) {
|
||||||
var rows = ''
|
var lignes = ''
|
||||||
for (var i = 0; i < items.length; i++) {
|
|
||||||
var item = items[i]
|
for (var i = 0; i < elements.length; i++) {
|
||||||
var val = this.safe(item.value)
|
var el = elements[i]
|
||||||
var display = item.value || 0
|
var taille = this.limiterValeur(el.valeur)
|
||||||
rows += '<tr>'
|
var affiche = el.valeur || 0
|
||||||
rows += '<th scope="row">' + item.label + '</th>'
|
|
||||||
rows += '<td style="--size: ' + val + '; --color: ' + item.color + ';">'
|
lignes += '<tr>'
|
||||||
rows += '<span class="data">' + display + '%</span>'
|
lignes += '<th scope="row">' + el.label + '</th>'
|
||||||
rows += '</td></tr>'
|
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">'
|
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>'
|
+ '<thead><tr><th scope="col">Catégorie</th><th scope="col">%</th></tr></thead>'
|
||||||
+ '<tbody>' + rows + '</tbody></table>'
|
+ '<tbody>' + lignes + '</tbody></table>'
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</detail-view>
|
</detail-view>
|
||||||
|
|||||||
@@ -1,112 +1,120 @@
|
|||||||
<map-view>
|
<map-view>
|
||||||
<div class="map-box">
|
<div class="map-box">
|
||||||
<h3>Carte des formations</h3>
|
<h3>Carte des formations</h3>
|
||||||
<div class="map" ref="map"></div>
|
<div class="map" ref="carte"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
onMounted() {
|
|
||||||
var mapElement = this.$('div[ref="map"]')
|
|
||||||
|
|
||||||
this.map = L.map(mapElement).setView([46.8, 2.5], 6)
|
onMounted() {
|
||||||
|
var divCarte = this.$('div[ref="carte"]')
|
||||||
|
|
||||||
|
this.carte = L.map(divCarte).setView([46.8, 2.5], 6)
|
||||||
|
this.groupeMarqueurs = L.layerGroup().addTo(this.carte)
|
||||||
|
this.marqueursIndex = {}
|
||||||
|
|
||||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
attribution: '© OpenStreetMap contributors'
|
attribution: '© OpenStreetMap contributors'
|
||||||
}).addTo(this.map)
|
}).addTo(this.carte)
|
||||||
|
|
||||||
this.markersLayer = L.layerGroup().addTo(this.map)
|
this.afficherMarqueurs()
|
||||||
this.markersById = {}
|
|
||||||
this.refreshMarkers()
|
|
||||||
|
|
||||||
var self = this
|
var composant = this
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
if (self.map) self.map.invalidateSize()
|
if (composant.carte) {
|
||||||
|
composant.carte.invalidateSize()
|
||||||
|
}
|
||||||
}, 200)
|
}, 200)
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
if (self.map) self.map.invalidateSize()
|
if (composant.carte) {
|
||||||
|
composant.carte.invalidateSize()
|
||||||
|
}
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
window.mapFocus = function(id) {
|
window.mapFocus = function(id) {
|
||||||
self.focusFormation(id)
|
composant.centrerSurFormation(id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onUpdated() {
|
onUpdated() {
|
||||||
this.refreshMarkers()
|
this.afficherMarqueurs()
|
||||||
|
|
||||||
var self = this
|
var composant = this
|
||||||
|
|
||||||
if (this.map) {
|
if (this.carte) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
self.map.invalidateSize()
|
composant.carte.invalidateSize()
|
||||||
}, 100)
|
}, 100)
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
self.map.invalidateSize()
|
composant.carte.invalidateSize()
|
||||||
}, 300)
|
}, 300)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onBeforeUnmount() {
|
onBeforeUnmount() {
|
||||||
if (this.map) {
|
if (this.carte) {
|
||||||
this.map.remove()
|
this.carte.remove()
|
||||||
this.map = null
|
this.carte = null
|
||||||
}
|
}
|
||||||
window.mapFocus = null
|
window.mapFocus = null
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshMarkers() {
|
afficherMarqueurs() {
|
||||||
if (!this.map || !this.markersLayer) {
|
if (!this.carte || !this.groupeMarqueurs) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.markersLayer.clearLayers()
|
this.groupeMarqueurs.clearLayers()
|
||||||
this.markersById = {}
|
this.marqueursIndex = {}
|
||||||
|
|
||||||
var points = []
|
var coordonnees = []
|
||||||
var results = this.props.results || []
|
var formations = this.props.results || []
|
||||||
|
|
||||||
for (var i = 0; i < results.length; i++) {
|
for (var i = 0; i < formations.length; i++) {
|
||||||
var f = results[i]
|
var f = formations[i]
|
||||||
|
|
||||||
if (f.latitude != null && f.longitude != null) {
|
if (f.latitude != null && f.longitude != null) {
|
||||||
var marker = L.marker([f.latitude, f.longitude])
|
var marqueur = L.marker([f.latitude, f.longitude])
|
||||||
marker.bindPopup('<b>' + f.nom + '</b><br>' + f.ville)
|
marqueur.bindPopup('<b>' + f.nom + '</b><br>' + f.ville)
|
||||||
marker.addTo(this.markersLayer)
|
marqueur.addTo(this.groupeMarqueurs)
|
||||||
|
|
||||||
this.markersById[f.id] = marker
|
this.marqueursIndex[f.id] = marqueur
|
||||||
points.push([f.latitude, f.longitude])
|
coordonnees.push([f.latitude, f.longitude])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (points.length > 0) {
|
if (coordonnees.length > 0) {
|
||||||
this.map.fitBounds(points, { padding: [20, 20] })
|
this.carte.fitBounds(coordonnees, { padding: [20, 20] })
|
||||||
} else {
|
} else {
|
||||||
this.map.setView([46.8, 2.5], 6)
|
this.carte.setView([46.8, 2.5], 6)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
focusFormation(id) {
|
centrerSurFormation(id) {
|
||||||
var marker = this.markersById[id]
|
var marqueur = this.marqueursIndex[id]
|
||||||
|
|
||||||
if (marker && this.map) {
|
if (marqueur && this.carte) {
|
||||||
var mapEl = this.$('div[ref="map"]')
|
var divCarte = this.$('div[ref="carte"]')
|
||||||
if (mapEl) {
|
|
||||||
mapEl.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
if (divCarte) {
|
||||||
|
divCarte.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this
|
var composant = this
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
self.map.invalidateSize()
|
composant.carte.invalidateSize()
|
||||||
self.map.setView(marker.getLatLng(), 13, { animate: true })
|
composant.carte.setView(marqueur.getLatLng(), 13, { animate: true })
|
||||||
marker.openPopup()
|
marqueur.openPopup()
|
||||||
}, 400)
|
}, 400)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</map-view>
|
</map-view>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<result-list>
|
<result-list>
|
||||||
<div class="results">
|
<div class="results">
|
||||||
|
|
||||||
<div class="message" if={ props.results.length === 0 && props.hasSearched && !props.loading }>
|
<div class="message" if={ props.results.length === 0 && props.hasSearched && !props.loading }>
|
||||||
Aucun résultat trouvé
|
Aucun résultat trouvé
|
||||||
</div>
|
</div>
|
||||||
@@ -8,26 +9,41 @@
|
|||||||
Chargement...
|
Chargement...
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div each={ (f, i) in props.results } key={ f.id } class="card">
|
<div each={ (formation, index) in props.results } key={ formation.id } class="card">
|
||||||
<h3>{ f.nom }</h3>
|
<h3>{ formation.nom }</h3>
|
||||||
<p><b>Établissement :</b> { f.etablissement }</p>
|
<p><b>Établissement :</b> { formation.etablissement }</p>
|
||||||
<p><b>Ville :</b> { f.ville } ({ f.departement })</p>
|
<p><b>Ville :</b> { formation.ville } ({ formation.departement })</p>
|
||||||
<p><b>Filière :</b> { f.filiere }</p>
|
<p><b>Filière :</b> { formation.filiere }</p>
|
||||||
<p><b>Taux d'accès :</b> { f.tauxAcces }%</p>
|
<p><b>Taux d'accès :</b> { formation.tauxAcces }%</p>
|
||||||
|
|
||||||
<button onclick={ () => props.ondetail(i) }>Voir détail</button>
|
<button onclick={ afficherDetail.bind(this, index) }>Voir détail</button>
|
||||||
<button onclick={ () => props.onselect(i) }>Ajouter à la sélection</button>
|
<button onclick={ ajouterALaSelection.bind(this, index) }>Ajouter à la sélection</button>
|
||||||
<button onclick={ () => locateOnMap(f) } if={ f.latitude != null }>Localiser</button>
|
<button onclick={ localiserSurCarte.bind(this, formation) } if={ formation.latitude != null }>Localiser</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
locateOnMap(f) {
|
|
||||||
|
// Déclencher l'affichage du détail d'une formation
|
||||||
|
afficherDetail(index) {
|
||||||
|
this.props.ondetail(index)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Ajouter une formation à la sélection
|
||||||
|
ajouterALaSelection(index) {
|
||||||
|
this.props.onselect(index)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Centrer la carte sur la formation
|
||||||
|
localiserSurCarte(formation) {
|
||||||
if (window.mapFocus) {
|
if (window.mapFocus) {
|
||||||
window.mapFocus(f.id)
|
window.mapFocus(formation.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</result-list>
|
</result-list>
|
||||||
|
|||||||
+71
-69
@@ -1,95 +1,97 @@
|
|||||||
export function createFormation(raw) {
|
// Créer un objet formation à partir des données brutes de l'API
|
||||||
|
export function creerFormation(brut) {
|
||||||
|
|
||||||
var taux = 0
|
var taux = 0
|
||||||
var latitude = null
|
var latitude = null
|
||||||
var longitude = null
|
var longitude = null
|
||||||
|
|
||||||
if (raw.voe_tot && raw.voe_tot > 0) {
|
if (brut.voe_tot && brut.voe_tot > 0) {
|
||||||
taux = Math.round((raw.acc_tot / raw.voe_tot) * 100)
|
taux = Math.round((brut.acc_tot / brut.voe_tot) * 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raw.g_olocalisation_des_formations) {
|
if (brut.g_olocalisation_des_formations) {
|
||||||
latitude = raw.g_olocalisation_des_formations.lat
|
latitude = brut.g_olocalisation_des_formations.lat
|
||||||
longitude = raw.g_olocalisation_des_formations.lon
|
longitude = brut.g_olocalisation_des_formations.lon
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: raw.cod_uai + "-" + raw.lib_for_voe_ins,
|
id: brut.cod_uai + "-" + brut.lib_for_voe_ins,
|
||||||
|
|
||||||
nom: raw.lib_for_voe_ins,
|
nom: brut.lib_for_voe_ins,
|
||||||
etablissement: raw.g_ea_lib_vx,
|
etablissement: brut.g_ea_lib_vx,
|
||||||
ville: raw.ville_etab,
|
ville: brut.ville_etab,
|
||||||
departement: raw.dep,
|
departement: brut.dep,
|
||||||
departementLib: raw.dep_lib,
|
departementLib: brut.dep_lib,
|
||||||
region: raw.region_etab_aff,
|
region: brut.region_etab_aff,
|
||||||
academie: raw.acad_mies,
|
academie: brut.acad_mies,
|
||||||
contrat: raw.contrat_etab,
|
contrat: brut.contrat_etab,
|
||||||
|
|
||||||
filiere: raw.fili,
|
filiere: brut.fili,
|
||||||
selectivite: raw.select_form,
|
selectivite: brut.select_form,
|
||||||
|
|
||||||
capacite: raw.capa_fin,
|
capacite: brut.capa_fin,
|
||||||
candidats: raw.voe_tot,
|
candidats: brut.voe_tot,
|
||||||
admis: raw.acc_tot,
|
admis: brut.acc_tot,
|
||||||
tauxAcces: taux,
|
tauxAcces: taux,
|
||||||
|
|
||||||
latitude: latitude,
|
latitude: latitude,
|
||||||
longitude: longitude,
|
longitude: longitude,
|
||||||
|
|
||||||
pctFemmes: raw.pct_f,
|
pctFemmes: brut.pct_f,
|
||||||
pctBoursiers: raw.pct_bours,
|
pctBoursiers: brut.pct_bours,
|
||||||
pctNeoBac: raw.pct_neobac,
|
pctNeoBac: brut.pct_neobac,
|
||||||
|
|
||||||
pctGeneral: raw.pct_bg,
|
pctGeneral: brut.pct_bg,
|
||||||
pctTechno: raw.pct_bt,
|
pctTechno: brut.pct_bt,
|
||||||
pctPro: raw.pct_bp,
|
pctPro: brut.pct_bp,
|
||||||
|
|
||||||
pctSansMention: raw.pct_sansmention,
|
pctSansMention: brut.pct_sansmention,
|
||||||
pctAB: raw.pct_ab,
|
pctAB: brut.pct_ab,
|
||||||
pctB: raw.pct_b,
|
pctB: brut.pct_b,
|
||||||
pctTB: raw.pct_tb,
|
pctTB: brut.pct_tb,
|
||||||
pctTBF: raw.pct_tbf,
|
pctTBF: brut.pct_tbf,
|
||||||
|
|
||||||
pctDebutPhase: raw.pct_acc_debutpp,
|
pctDebutPhase: brut.pct_acc_debutpp,
|
||||||
pctDateBac: raw.pct_acc_datebac,
|
pctDateBac: brut.pct_acc_datebac,
|
||||||
pctFinPhase: raw.pct_acc_finpp,
|
pctFinPhase: brut.pct_acc_finpp,
|
||||||
|
|
||||||
admisDebutPhase: raw.acc_debutpp,
|
admisDebutPhase: brut.acc_debutpp,
|
||||||
admisDateBac: raw.acc_datebac,
|
admisDateBac: brut.acc_datebac,
|
||||||
admisFinPhase: raw.acc_finpp,
|
admisFinPhase: brut.acc_finpp,
|
||||||
|
|
||||||
// phase principale
|
// Phase principale
|
||||||
voePPGeneral: raw.nb_voe_pp_bg,
|
voePPGeneral: brut.nb_voe_pp_bg,
|
||||||
voePPTechno: raw.nb_voe_pp_bt,
|
voePPTechno: brut.nb_voe_pp_bt,
|
||||||
voePPPro: raw.nb_voe_pp_bp,
|
voePPPro: brut.nb_voe_pp_bp,
|
||||||
voePPAutres: raw.nb_voe_pp_at,
|
voePPAutres: brut.nb_voe_pp_at,
|
||||||
voePPTotal: raw.nb_voe_pp,
|
voePPTotal: brut.nb_voe_pp,
|
||||||
|
|
||||||
classesPPGeneral: raw.nb_cla_pp_bg,
|
classesPPGeneral: brut.nb_cla_pp_bg,
|
||||||
classesPPTechno: raw.nb_cla_pp_bt,
|
classesPPTechno: brut.nb_cla_pp_bt,
|
||||||
classesPPPro: raw.nb_cla_pp_bp,
|
classesPPPro: brut.nb_cla_pp_bp,
|
||||||
classesPPAutres: raw.nb_cla_pp_at,
|
classesPPAutres: brut.nb_cla_pp_at,
|
||||||
classesPPTotal: raw.nb_cla_pp,
|
classesPPTotal: brut.nb_cla_pp,
|
||||||
|
|
||||||
propositionsPPGeneral: raw.prop_tot_bg,
|
propositionsPPGeneral: brut.prop_tot_bg,
|
||||||
propositionsPPTechno: raw.prop_tot_bt,
|
propositionsPPTechno: brut.prop_tot_bt,
|
||||||
propositionsPPPro: raw.prop_tot_bp,
|
propositionsPPPro: brut.prop_tot_bp,
|
||||||
propositionsPPAutres: raw.prop_tot_at,
|
propositionsPPAutres: brut.prop_tot_at,
|
||||||
propositionsPPTotal: raw.prop_tot,
|
propositionsPPTotal: brut.prop_tot,
|
||||||
|
|
||||||
acceptesPPGeneral: raw.acc_bg,
|
acceptesPPGeneral: brut.acc_bg,
|
||||||
acceptesPPTechno: raw.acc_bt,
|
acceptesPPTechno: brut.acc_bt,
|
||||||
acceptesPPPro: raw.acc_bp,
|
acceptesPPPro: brut.acc_bp,
|
||||||
acceptesPPAutres: raw.acc_at,
|
acceptesPPAutres: brut.acc_at,
|
||||||
acceptesPPTotal: raw.acc_pp,
|
acceptesPPTotal: brut.acc_pp,
|
||||||
|
|
||||||
// phase complémentaire
|
// Phase complémentaire
|
||||||
voePCGeneral: raw.nb_voe_pc_bg,
|
voePCGeneral: brut.nb_voe_pc_bg,
|
||||||
voePCTechno: raw.nb_voe_pc_bt,
|
voePCTechno: brut.nb_voe_pc_bt,
|
||||||
voePCPro: raw.nb_voe_pc_bp,
|
voePCPro: brut.nb_voe_pc_bp,
|
||||||
voePCAutres: raw.nb_voe_pc_at,
|
voePCAutres: brut.nb_voe_pc_at,
|
||||||
voePCTotal: raw.nb_voe_pc,
|
voePCTotal: brut.nb_voe_pc,
|
||||||
|
|
||||||
classesPCTotal: raw.nb_cla_pc,
|
classesPCTotal: brut.nb_cla_pc,
|
||||||
acceptesPCTotal: raw.acc_pc
|
acceptesPCTotal: brut.acc_pc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
<script src="./app.riot" type="riot"></script>
|
<script src="./app.riot" type="riot"></script>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { fetchFormations, fetchFormationHistory } from './api.js'
|
import { chargerFormations, chargerHistoriqueFormation } from './api.js'
|
||||||
import { createFormation } from './formation.js'
|
import { creerFormation } from './formation.js'
|
||||||
import {
|
import {
|
||||||
auth,
|
auth,
|
||||||
db,
|
db,
|
||||||
@@ -36,9 +36,9 @@
|
|||||||
loadUserData
|
loadUserData
|
||||||
} from './firebase.js'
|
} from './firebase.js'
|
||||||
|
|
||||||
window.fetchFormations = fetchFormations
|
window.chargerFormations = chargerFormations
|
||||||
window.createFormation = createFormation
|
window.creerFormation = creerFormation
|
||||||
window.fetchFormationHistory = fetchFormationHistory
|
window.chargerHistoriqueFormation = chargerHistoriqueFormation
|
||||||
|
|
||||||
window.firebaseServices = {
|
window.firebaseServices = {
|
||||||
auth,
|
auth,
|
||||||
|
|||||||
Reference in New Issue
Block a user