316 lines
9.3 KiB
Django/Jinja
316 lines
9.3 KiB
Django/Jinja
{% extends "sco_page.j2" %}
|
|
|
|
{% block title %}
|
|
Bilan assiduité de {{sco.etud.nomprenom}}
|
|
{% endblock title %}
|
|
|
|
{% block styles %}
|
|
{{ super() }}
|
|
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/assiduites.css">
|
|
<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>
|
|
{% endblock styles %}
|
|
|
|
{% 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 %}
|
|
|
|
|
|
{% block scripts %}
|
|
{{ super() }}
|
|
<script src="{{scu.STATIC_DIR}}/js/assiduites.js"></script>
|
|
<script src="{{scu.STATIC_DIR}}/js/date_utils.js"></script>
|
|
|
|
<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.toFixed(2)} 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>
|
|
{% endblock %}
|
|
|
|
|