ScoDoc/app/templates/assiduites/pages/traitement_justificatifs.j2

405 lines
12 KiB
Django/Jinja

{% extends "sco_page.j2" %}
{% block styles %}
{{ super() }}
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/assiduites.css">
<style>
.ligne.valide, .ligne.non_valide{
opacity: 0.5;
}
.ligne {
display: grid;
grid-template-columns: 1fr 0.5fr 1.5fr 2fr 1fr 1fr;
gap: 4px;
padding-bottom: 4px;
border-bottom: 1px solid #ccc;
margin-bottom: 4px;
}
.ligne.head {
font-weight: bold;
border-bottom: 2px solid #ccc;
}
.ligne>div {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
}
.ligne>div:not(:last-of-type) {
border-right: 1px solid #ccc;
}
.pdp {
width: 50px;
border-radius: 8px;
margin-right: 4px;
}
.etud {
text-align: center;
}
.validation{
flex-direction: row !important;
justify-content: space-evenly !important;
}
.ligne button[etat]{
border: 1px solid #444;
color: #444;
padding: 2px 6px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 2px 1px;
cursor: pointer;
border-radius: 8px;
}
.ligne.attente button[etat="attente"]{
color: whitesmoke;
background-color: var(--color-retard);
}
.ligne.valide button[etat="valide"]{
color: whitesmoke;
background-color: var(--color-present);
}
.ligne.non_valide button[etat="non_valide"]{
color: whitesmoke;
background-color: var(--color-absent);
}
.hint{
font-size: 0.8em;
color: #666;
}
.entry_date::before{
content: "Saisie le ";
}
.sco-drop {
border: 1px solid #e1e1e1;
/* Couleur de bordure plus douce */
border-radius: 8px;
/* Coins plus arrondis */
background-color: #fafafa;
/* Couleur de fond légère */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
/* Ombre douce pour de la profondeur */
width: 100%;
/* Adaptation à la largeur de son conteneur */
max-width: 600px;
/* Largeur maximale pour une meilleure apparence sur grands écrans */
margin: 10px auto;
/* Centrage avec une marge */
position: relative;
z-index: 1;
}
.sco-drop[open] {
z-index: 2;
/* Empilement au-dessus des autres détails */
}
.sco-drop summary {
font-weight: 600;
/* Texte plus épais */
color: #333;
/* Couleur de texte plus foncée pour le contraste */
padding: 7px 10px;
/* Plus de padding pour une meilleure ergonomie */
cursor: pointer;
list-style: none;
/* Enlève les puces */
outline: none;
/* Supprime la bordure de focus par défaut pour un look plus net */
user-select: none;
/* Empêche la sélection du texte */
text-align: center;
}
.sco-drop summary::-webkit-details-marker {
display: none;
/* Cache le triangle par défaut sur Chrome/Safari */
}
.sco-drop summary:focus {
outline: none;
/* Plus propre sans contour lors du focus */
}
.sco-drop ul {
list-style: none;
/* Enlève les puces */
margin: 5px 0;
padding: 0;
background-color: #fff;
/* Arrière-plan blanc pour le contenu */
position: absolute;
border-radius: 8px;
z-index: 1000;
border: 1px solid #e1e1e1;
/* Bordure plus douce */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
/* Ombre douce pour de la profondeur */
overflow-y: scroll;
max-height: 150px;
/* Hauteur maximale pour une meilleure apparence sur grands écrans */
}
.sco-drop li {
padding: 10px 20px;
/* Espacement intérieur pour les éléments de liste */
border-top: 1px solid #e1e1e1;
/* Séparateur subtil entre les éléments */
}
.sco-drop li:first-child {
border-top: none;
/* Pas de bordure en haut du premier élément */
}
</style>
{% endblock styles %}
{% block scripts %}
{{ super() }}
<script src="{{scu.STATIC_DIR}}/js/etud_info.js"></script>
<script src="{{scu.STATIC_DIR}}/js/assiduites.js"></script>
<script src="{{scu.STATIC_DIR}}/js/date_utils.js"></script>
<script>
function changerEtatJustificatif(justifId, etat) {
const ligne = document.getElementById("justi-" + justifId);
// Mettre à jour le justificatif
async_post(
"../../api/justificatif/" + justifId + "/edit",
{ etat: etat },
() => {
// Mettre à jour la ligne
ligne.classList.remove("attente", "modifie", "valide", "non_valide");
ligne.classList.add(etat);
// Afficher le toast
const p = document.createElement("span");
let color = "";
switch (etat) {
case "attente":
color = "var(--color-retard)";
p.textContent = "Justificatif mis en attente";
break;
case "valide":
color = "var(--color-present)";
p.textContent = "Justificatif validé";
break;
case "non_valide":
color = "var(--color-absent)";
p.textContent = "Justificatif invalidé";
break;
default:
color = "gray";
break;
}
const toast = generateToast(p, color, 3);
pushToast(toast);
},
(e) => {
console.error(e);
}
);
}
/**
* Filtre les lignes en fonction des états demandés
* @param {Array} etats
*/
function filtrerLignes() {
const etats = [
att.checked ? "attente" : null,
modif.checked ? "modifie" : null,
];
// Sauvegarde des paramètres
localStorage.setItem("scodoc-etud-att", `${att.checked}`);
localStorage.setItem("scodoc-etud-modif", `${modif.checked}`);
document.querySelectorAll(".ligne").forEach((el) => {
if ((el.id == "")) return;
// Si au moins un état se trouve dans la classe de l'élément
// Alors on laisse affiché cet élément
if (
etats.some((e) => {
return el.classList.contains(e);
})
) {
el.classList.remove("hidden");
} else {
el.classList.add("hidden");
}
});
}
function main() {
const checked = localStorage.getItem("scodoc-etud-pdp") == "true";
afficherPDP(checked);
// Gestion des filtres
att.checked = localStorage.getItem("scodoc-etud-att") == "true";
modif.checked = localStorage.getItem("scodoc-etud-modif") == "true";
att.addEventListener("change", filtrerLignes);
modif.addEventListener("change", filtrerLignes);
filtrerLignes()
// Gestion des dropdowns
document.body.addEventListener("click", (e) => {
if (!e.target.matches(".sco-drop, .sco-drop *")) {
document.querySelectorAll(".sco-drop").forEach((drop) => {
drop.removeAttribute("open");
});
}
});
}
main();
</script>
{% endblock %}
{% block app_content %}
<h2>Traitement des justificatifs <span class="rouge">{{formsemestre.titre_num()}}</span></h2>
<div class="scobox">
<label for="att">
Justificatifs en attente
<input type="checkbox" id="att" checked>
</label>
<label for="modif">
Justificatifs modifié
<input type="checkbox" id="modif" checked>
</label>
<label for="pdp">
Photo des étudiants :
<input type="checkbox" name="pdp" id="pdp" checked onclick="afficherPDP(this.checked)">
</label>
</div>
<div class="scobox">
<div class="ligne head">
<div>Etudiant</div>
<div>Abs</div>
<div>Plage</div>
<div>Description</div>
<div>Fichiers</div>
<div>Validation</div>
</div>
{% for ligne in lignes %}
<div class="ligne {{ligne.etat}}" id="justi-{{ligne.justif.justif_id}}">
<div class="etud">
<img src="../../api/etudiant/etudid/{{ligne.etud.id}}/photo?size=small" alt="{{ligne.etud.nomprenom}}"
class="pdp">
<span class="etudinfo" id="{{ligne.justif.justif_id}}-{{ligne.etud.id}}">{{ ligne.etud.nomprenom }}</span>
</div>
<div class="stats">
<span>
NJ : {{ligne.etud.stats[0]}}
</span>
<span>
J : {{ligne.etud.stats[1]}}
</span>
</div>
<div class="plage">
{% if ligne.justif.date_debut.date() == ligne.justif.date_fin.date() %}
<span class="date">
{{ligne.justif.date_debut.strftime(scu.DATE_FMT)}} de {{ligne.justif.date_debut.strftime(scu.TIME_FMT)}} à
{{ligne.justif.date_fin.strftime(scu.TIME_FMT)}}
</span>
{% else %}
<span class="date_debut">
du {{ligne.justif.date_debut.strftime(scu.DATE_FMT)}}
</span>
<span class="date_fin">
au {{ligne.justif.date_fin.strftime(scu.DATE_FMT)}}
</span>
{% endif %}
<span class="entry_date hint">
{{ligne.justif.entry_date.strftime("%d/%m/%y %Hh%M")}}
</span>
{% if ligne.assiduites.__len__() == 0 %}
<p>Aucune assiduité concernée</p>
{% else %}
<details class="sco-drop">
<summary>
Assiduités concernées
</summary>
<ul>
{% for assi in ligne.assiduites %}
<li>
{{scu.EtatAssiduite(assi.etat).version_lisible()}}
{% if assi.date_debut.date() == assi.date_fin.date() %}
du {{assi.date_debut.strftime(scu.DATE_FMT)}} de {{assi.date_debut.strftime(scu.TIME_FMT)}} à
{{assi.date_fin.strftime(scu.TIME_FMT)}}
{% else %}
du {{assi.date_debut.strftime("%d/%m/%y %Hh%M")}} au {{assi.date_fin.strftime("%d/%m/%y
%Hh%M")}}
{% endif %}
</li>
{% endfor %}
</ul>
</details>
{% endif %}
</div>
<div class="desc">
<p>{{ligne.justif.raison}}</p>
{% if ligne.etat == "modifie" %}
<p class="hint">le justificatif a été modifié</p>
{% endif %}
</div>
<div class="fichiers">
{% if ligne.fichiers.total == 0 %}
<p>Aucun fichier joint</p>
{% else %}
<details class="sco-drop">
<summary>Fichiers joints</summary>
<ul>
{% for filename in ligne.fichiers.filenames %}
<li>
<a href="{{url_for('apiweb.justif_export',justif_id=ligne.justif.justif_id,
filename=filename, scodoc_dept=g.scodoc_dept)}}">{{filename}}</a>
</li>
{% endfor %}
</ul>
</details>
{% endif %}
</div>
<div class="validation">
<button type="button" etat="valide" onclick="changerEtatJustificatif({{ligne.justif.justif_id}}, 'valide')">OUI</button>
<button type="button" etat="non_valide" onclick="changerEtatJustificatif({{ligne.justif.justif_id}}, 'non_valide')">NON</button>
<button type="button" etat="attente" onclick="changerEtatJustificatif({{ligne.justif.justif_id}}, 'attente')">ATT</button>
</div>
</div>
{% endfor %}
</div>
{% include "assiduites/widgets/toast.j2" %}
{% endblock %}