{% block app_content %} {% include "assiduites/widgets/tableau_base.j2" %} <div class="pageContent"> <h2>Bilan de l'assiduité de {{sco.etud.html_link_fiche()|safe}}</span></h2> <section class="alerte invisible"> <p>Attention, cet étudiant a trop d'absences</p> </section> <section class="stats"> <!-- Statistiques d'assiduité (nb pres, nb retard, nb absence) + nb justifié --> <h4>Statistiques d'assiduité</h4> <div class="stats-inputs"> <label class="stats-label"> Date de début<input type="text" class="datepicker" name="stats_date_debut" id="stats_date_debut" value="{{date_debut}}"></label> <label class="stats-label"> Date de fin<input type="text" class="datepicker" name="stats_date_fin" id="stats_date_fin" value="{{date_fin}}"></label> <button onclick="stats()">Actualiser</button> </div> <div class="stats-values"> </div> </section> <section class="nonvalide"> {{tableau | safe }} </section> <section class="suppr"> <h4>Boutons de suppresions (toute suppression est définitive) </h4> <button type="button" onclick="removeAllAssiduites()">Suppression des assiduités</button> <button type="button" onclick="removeAllJustificatifs()">Suppression des justificatifs</button> </section> <div class="legende"> <h3>Statistiques</h3> <p>Un message d'alerte apparait si le nombre d'absence dépasse le seuil (indiqué dans les préférences du département)</p> <p>Les statistiques sont calculées entre les deux dates sélectionnées. Après modification des dates, appuyer sur le bouton "Actualiser"</p> </div> </div> {% endblock app_content %} <script> function stats() { const dd_val = document.getElementById('stats_date_debut').value; const df_val = document.getElementById('stats_date_fin').value; let date_debut = new Date(Date.fromFRA(dd_val)); let date_fin = new Date(Date.fromFRA(df_val)); if (dd_val == "" || df_val == "" || !date_debut.isValid() || !date_debut.isValid()) { openAlertModal("Dates invalides", document.createTextNode('Les dates sélectionnées sont invalides')); return; } date_debut = date_debut.startOf("day") date_fin = date_fin.endOf("day") if (date_debut.isAfter(date_fin)) { openAlertModal("Dates invalides", document.createTextNode('La date de début se situe après la date de fin.')); return; } countAssiduites(date_debut.toFakeIso(), date_fin.toFakeIso()) } function getAssiduitesCount(dateDeb, dateFin, action) { const url_api = getUrl() + `/api/assiduites/${etudid}/count/query?date_debut=${dateDeb}&date_fin=${dateFin}&etat=absent,retard,present&split`; //Utiliser async_get au lieu de Jquery async_get( url_api, action, ()=>{}, ); } function showStats(data){ const counter = { "present": { "total": data["present"], }, "retard": { "total": data["retard"], "justi": data["retard"]["justifie"], }, "absent": { "total": data["absent"], "justi": data["absent"]["justifie"], } } const values = document.querySelector('.stats-values'); values.innerHTML = ""; Object.keys(counter).forEach((key) => { const item = document.createElement('div'); item.classList.add('stats-values-item'); const div = document.createElement('div'); div.classList.add('stats-values-part'); const withJusti = (key, metric) => { if (key == "present") return ""; return ` dont ${counter[key].justi[metric]} justifiées` } const heure = document.createElement('span'); heure.textContent = `${counter[key].total.heure} heure(s)${withJusti(key, "heure")}`; const demi = document.createElement('span'); demi.textContent = `${counter[key].total.demi} demi-journée(s)${withJusti(key, "demi")}`; const jour = document.createElement('span'); jour.textContent = `${counter[key].total.journee} journée(s)${withJusti(key, "journee")}`; div.append(jour, demi, heure); const title = document.createElement('h5'); title.textContent = key.capitalize(); item.append(title, div) values.appendChild(item); }); const nbAbs = data["absent"]["non_justifie"][assi_metric]; if (nbAbs > assi_seuil) { document.querySelector('.alerte').classList.remove('invisible'); document.querySelector('.alerte p').textContent = `Attention, cet étudiant a trop d'absences ${nbAbs} / ${assi_seuil} (${metriques[assi_metric]})` } else { document.querySelector('.alerte').classList.add('invisible'); } } function countAssiduites(dateDeb, dateFin) { getAssiduitesCount(dateDeb, dateFin, showStats); } function removeAllAssiduites() { openPromptModal( "Suppression de l'assiduité", document.createTextNode( 'Souhaitez vous réellement supprimer toutes les informations sur l\'assiduité de cet étudiant ? Cette suppression est irréversible.') , () => { getAllAssiduitesFromEtud(etudid, (data) => { const toRemove = data.map((a) => a.assiduite_id); console.log(toRemove) deleteAssiduites(toRemove); }) }) } function removeAllJustificatifs() { openPromptModal( "Suppression des justificatifs", document.createTextNode( 'Souhaitez vous réelement supprimer tous les justificatifs de cet étudiant ? Cette supression est irréversible.') , () => { getAllJustificatifsFromEtud(etudid, (data) => { const toRemove = data.map((a) => a.justif_id); deleteJustificatifs(toRemove); }) }) } /** * Suppression des assiduties */ function deleteAssiduites(assi) { const path = getUrl() + `/api/assiduite/delete`; async_post( path, assi, (data, status) => { //success if (data.success.length > 0) { } location.reload(); }, (data, status) => { //error console.error(data, status); errorAlert(); } ); } /** * Suppression des justificatifs */ function deleteJustificatifs(justis) { const path = getUrl() + `/api/justificatif/delete`; async_post( path, justis, (data, status) => { //success location.reload(); }, (data, status) => { //error console.error(data, status); errorAlert(); } ); } const metriques = { "heure": "H.", "demi": "1/2 J.", "journee": "J." } const etudid = {{ sco.etud.id }}; const assi_metric = "{{ assi_metric | safe }}"; const assi_seuil = {{ assi_seuil }}; const assi_date_debut = "{{date_debut}}"; const assi_date_fin = "{{date_fin}}"; const assi_limit_annee = "{{ assi_limit_annee }}" == "True" ? true : false; window.addEventListener('load', () => { document.getElementById('stats_date_fin').value = assi_date_fin; document.getElementById('stats_date_debut').value = assi_date_debut; stats(); }) </script> <style> .stats-values-item { display: flex; justify-content: space-evenly; align-items: center; flex-direction: column; } .stats { border: 1px solid #333; padding: 5px 2px; width: fit-content; } .stats-values { display: flex; justify-content: flex-start; gap: 15px; } .stats-values-item h5 { font-weight: bold; text-decoration-line: underline; } .stats-values-part { display: flex; flex-direction: column; } .alerte { display: flex; justify-content: center; align-items: center; padding: 10px; margin: 5px 0; border-radius: 7px; background-color: var(--color-error); } .alerte.invisible { display: none; } .alerte p { font-size: larger; color: whitesmoke; } .suppr { margin: 5px 0; } </style>