forked from ScoDoc/ScoDoc
Assiduité: signal_assiduites_diff OK
This commit is contained in:
parent
c617ee321a
commit
b74d525c28
@ -25,8 +25,8 @@
|
|||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
"""Tableau de bord module
|
"""Tableau de bord module"""
|
||||||
"""
|
|
||||||
import math
|
import math
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
@ -329,8 +329,6 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
>Saisie Absences journée</a></span>
|
>Saisie Absences journée</a></span>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
year, week, day = datetime.date.today().isocalendar()
|
|
||||||
semaine: str = f"{year}-W{week}"
|
|
||||||
H.append(
|
H.append(
|
||||||
f"""
|
f"""
|
||||||
<span class="moduleimpl_abs_link"><a class="stdlink" href="{
|
<span class="moduleimpl_abs_link"><a class="stdlink" href="{
|
||||||
@ -338,11 +336,10 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
"assiduites.signal_assiduites_diff",
|
"assiduites.signal_assiduites_diff",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
group_ids=group_id,
|
group_ids=group_id,
|
||||||
semaine=semaine,
|
|
||||||
formsemestre_id=formsemestre.id,
|
formsemestre_id=formsemestre.id,
|
||||||
moduleimpl_id="" if moduleimpl_id is None else moduleimpl_id
|
moduleimpl_id="" if moduleimpl_id is None else moduleimpl_id
|
||||||
)}"
|
)}"
|
||||||
>Saisie Absences hebdo</a></span>
|
>Saisie Absences Différée</a></span>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -440,12 +440,6 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
border: 5px solid var(--color-primary);
|
border: 5px solid var(--color-primary);
|
||||||
/* background-color: rgba(36, 36, 36, 0.25);
|
|
||||||
background-image: repeating-linear-gradient(135deg,
|
|
||||||
transparent,
|
|
||||||
transparent 5px,
|
|
||||||
rgba(81, 81, 81, 0.61) 5px,
|
|
||||||
rgba(81, 81, 81, 0.61) 10px); */
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,6 +449,15 @@
|
|||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.assiduite-infos {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
margin: 5px;
|
||||||
|
top: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -855,6 +855,16 @@ function setupAssiduiteBubble(el, assiduite) {
|
|||||||
bubble.className = "assiduite-bubble";
|
bubble.className = "assiduite-bubble";
|
||||||
bubble.classList.add(assiduite.etat.toLowerCase());
|
bubble.classList.add(assiduite.etat.toLowerCase());
|
||||||
|
|
||||||
|
// Ajout d'un lien pour plus d'informations
|
||||||
|
const infos = document.createElement("a");
|
||||||
|
infos.className = "assiduite-infos";
|
||||||
|
infos.textContent = `ℹ️`;
|
||||||
|
infos.title = "Cliquez pour plus d'informations";
|
||||||
|
infos.target = "_blank";
|
||||||
|
infos.href = `tableau_assiduite_actions?type=assiduite&action=details&obj_id=${assiduite.assiduite_id}`;
|
||||||
|
|
||||||
|
bubble.appendChild(infos);
|
||||||
|
|
||||||
const idDiv = document.createElement("div");
|
const idDiv = document.createElement("div");
|
||||||
idDiv.className = "assiduite-id";
|
idDiv.className = "assiduite-id";
|
||||||
getModuleImpl(assiduite).then((modImpl) => {
|
getModuleImpl(assiduite).then((modImpl) => {
|
||||||
|
@ -255,6 +255,13 @@ Object.defineProperty(Date.prototype, "format", {
|
|||||||
value: function (formatString) {
|
value: function (formatString) {
|
||||||
let iso = this.toIsoUtcString();
|
let iso = this.toIsoUtcString();
|
||||||
switch (formatString) {
|
switch (formatString) {
|
||||||
|
case "DD/MM/YYYY":
|
||||||
|
return this.toLocaleString("fr-FR", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
timeZone: SCO_TIMEZONE,
|
||||||
|
});
|
||||||
case "DD/MM/Y HH:mm":
|
case "DD/MM/Y HH:mm":
|
||||||
return this.toLocaleString("fr-FR", {
|
return this.toLocaleString("fr-FR", {
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
@ -275,6 +282,8 @@ Object.defineProperty(Date.prototype, "format", {
|
|||||||
hour12: false,
|
hour12: false,
|
||||||
timeZone: SCO_TIMEZONE,
|
timeZone: SCO_TIMEZONE,
|
||||||
});
|
});
|
||||||
|
case "HH:mm":
|
||||||
|
return iso.slice(11, 16);
|
||||||
|
|
||||||
case "YYYY-MM-DDTHH:mm":
|
case "YYYY-MM-DDTHH:mm":
|
||||||
// slice : YYYY-MM-DDTHH
|
// slice : YYYY-MM-DDTHH
|
||||||
|
@ -97,19 +97,12 @@
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pointer{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
{# Temporaire #}
|
|
||||||
<style>
|
|
||||||
.wip::before{
|
|
||||||
content: "WIP 🚧";
|
|
||||||
font-size: 1.5em;
|
|
||||||
margin: 2px;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
{% endblock styles %}
|
{% endblock styles %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
@ -121,142 +114,375 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
function afficherPDP(checked) {
|
/**
|
||||||
if (checked) {
|
* Permet d'afficher ou non les photos des étudiants
|
||||||
gtrcontent.setAttribute("data-pdp", "true");
|
* @param {boolean} checked
|
||||||
} else {
|
*/
|
||||||
gtrcontent.removeAttribute("data-pdp");
|
function afficherPDP(checked) {
|
||||||
}
|
if (checked) {
|
||||||
|
gtrcontent.setAttribute("data-pdp", "true");
|
||||||
|
} else {
|
||||||
|
gtrcontent.removeAttribute("data-pdp");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permet d'ajouter une nouvelle période au tableau
|
||||||
|
* Par défaut la période est générèe avec les valeurs des inputs
|
||||||
|
* Si une période est passée en paramètre, alors on utilise ses valeurs
|
||||||
|
* @param {Object} period - La période à ajouter
|
||||||
|
*/
|
||||||
|
async function nouvellePeriode(period = null) {
|
||||||
|
// On récupère l'id de la période
|
||||||
|
let periodId;
|
||||||
|
if (period) {
|
||||||
|
periodId = period.periodId;
|
||||||
|
} else {
|
||||||
|
periodId = currentPeriodId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On récupère les valeurs des inputs
|
||||||
|
let date = document.getElementById("date").value;
|
||||||
|
let debut = document.getElementById("debut").value;
|
||||||
|
let fin = document.getElementById("fin").value;
|
||||||
|
let moduleimpl_id = document.getElementById("moduleimpl_select").value;
|
||||||
|
const moduleimpl = await getModuleImpl({ moduleimpl_id: moduleimpl_id });
|
||||||
|
|
||||||
|
// Si une période est passée en paramètre, on utilise ses valeurs
|
||||||
|
if (period) {
|
||||||
|
date = period.date_debut.format("DD/MM/YYYY");
|
||||||
|
debut = period.date_debut.format("HH:mm");
|
||||||
|
fin = period.date_fin.format("HH:mm");
|
||||||
|
moduleimpl_id = period.moduleimpl_id;
|
||||||
|
}else{
|
||||||
|
//Sinon on vérifie qu'on a bien des valeurs
|
||||||
|
const text = document.createTextNode("Veuillez remplir tous les champs pour ajouter une période.")
|
||||||
|
if (date == "" || debut == "" || fin == "" || moduleimpl_id == "") {
|
||||||
|
openAlertModal(
|
||||||
|
"Erreur",
|
||||||
|
text
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function nouvellePeriode(){
|
// On ajoute la nouvelle période au tableau
|
||||||
periodeId++;
|
let periodeDiv = document.createElement("div");
|
||||||
|
periodeDiv.classList.add("cell", "sticky");
|
||||||
|
periodeDiv.id = `periode-${periodId}`;
|
||||||
|
const periodP = document.createElement("p");
|
||||||
|
periodP.textContent = `Période du ${date} de ${debut} à ${fin}`;
|
||||||
|
|
||||||
// On récupère les valeurs des inputs
|
// On ajoute le moduleimpl
|
||||||
let date = document.getElementById("date").value;
|
const modP = document.createElement("p");
|
||||||
let debut = document.getElementById("debut").value;
|
modP.textContent = moduleimpl;
|
||||||
let fin = document.getElementById("fin").value;
|
|
||||||
let moduleimpl_id = document.getElementById("moduleimpl_select").value;
|
|
||||||
const moduleimpl = await getModuleImpl({moduleimpl_id: moduleimpl_id});
|
|
||||||
|
|
||||||
// On ajoute la nouvelle période au tableau
|
// On ajoute le bouton pour supprimer la période
|
||||||
let periodeDiv = document.createElement("div");
|
const close = document.createElement("button");
|
||||||
periodeDiv.classList.add("cell", "sticky");
|
close.textContent = "❌";
|
||||||
const periodP = document.createElement("p");
|
close.addEventListener("click", () => {
|
||||||
periodP.textContent = `Période du ${date} de ${debut} à ${fin}`;
|
// On supprime toutes les cases du tableau correspondant à cette période
|
||||||
|
document
|
||||||
|
.querySelectorAll(
|
||||||
|
`.cell[data-periodeid="${periodeDiv.getAttribute("data-periodeid")}"]`
|
||||||
|
)
|
||||||
|
.forEach((e) => e.remove());
|
||||||
|
// On supprime la période de la Map periodes
|
||||||
|
periodes.delete(Number(periodeDiv.getAttribute("data-periodeid")));
|
||||||
|
});
|
||||||
|
//On ajoute les éléments au DOM
|
||||||
|
periodeDiv.appendChild(periodP);
|
||||||
|
periodeDiv.appendChild(modP);
|
||||||
|
periodeDiv.appendChild(close);
|
||||||
|
periodeDiv.setAttribute("data-periodeid", periodId);
|
||||||
|
document.getElementById("tableau-periode").appendChild(periodeDiv);
|
||||||
|
|
||||||
const modP = document.createElement("p");
|
// On récupère les étudiants (etudids)
|
||||||
modP.textContent = moduleimpl;
|
let etudids = [
|
||||||
|
...document.querySelectorAll("#tableau-periode .header[data-etudid]"),
|
||||||
|
].map((e) => e.getAttribute("data-etudid"));
|
||||||
|
|
||||||
const close = document.createElement("button");
|
// On génère une date de début et de fin de la période
|
||||||
close.textContent = "❌";
|
const date_debut = new Date(
|
||||||
close.addEventListener("click", (event)=>{
|
$("#date").datepicker("getDate").format("YYYY-MM-DD") + "T" + debut
|
||||||
document.querySelectorAll(`.cell[data-periodeid="${periodeDiv.getAttribute('data-periodeid')}"]`).forEach((e)=>e.remove());
|
);
|
||||||
});
|
const date_fin = new Date(
|
||||||
|
$("#date").datepicker("getDate").format("YYYY-MM-DD") + "T" + fin
|
||||||
|
);
|
||||||
|
date_debut.add(1, "seconds");
|
||||||
|
|
||||||
periodeDiv.appendChild(periodP);
|
// Préparation de la requête
|
||||||
periodeDiv.appendChild(modP);
|
const url =
|
||||||
periodeDiv.appendChild(close);
|
`../../api/assiduites/group/query?date_debut=${date_debut.toFakeIso()}` +
|
||||||
periodeDiv.setAttribute("data-periodeid", periodeId);
|
`&date_fin=${date_fin.toFakeIso()}&etudids=${etudids.join(
|
||||||
document.getElementById("tableau-periode").appendChild(periodeDiv);
|
","
|
||||||
|
)}&with_justifs`;
|
||||||
let etudids = [...document
|
|
||||||
.querySelectorAll("#tableau-periode .header[data-etudid]")]
|
|
||||||
.map((e)=>e.getAttribute("data-etudid"));
|
|
||||||
|
|
||||||
const date_debut = new Date($("#date").datepicker("getDate").format("YYYY-MM-DD") + "T" + debut);
|
|
||||||
const date_fin = new Date($("#date").datepicker("getDate").format("YYYY-MM-DD") + "T" + fin);
|
|
||||||
date_debut.add(1, "seconds")
|
|
||||||
const url =
|
|
||||||
`../../api/assiduites/group/query?date_debut=${date_debut.toFakeIso()}` +
|
|
||||||
`&date_fin=${date_fin.toFakeIso()}&etudids=${etudids.join(',')}&with_justifs`;
|
|
||||||
|
|
||||||
|
|
||||||
await fetch(url)
|
//Si la période n'existait pas, alors on l'ajoute à la Map
|
||||||
.then((res) => {
|
if (!period) {
|
||||||
if (!res.ok) {
|
periodes.set(periodId, {
|
||||||
throw new Error("Network response was not ok");
|
date_debut: date_debut.clone().add(-1, "seconds"),
|
||||||
|
date_fin: date_fin,
|
||||||
|
moduleimpl_id: moduleimpl_id,
|
||||||
|
periodId: periodId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// On récupère les incriptions au module
|
||||||
|
const inscriptions = await getInscriptionModule(moduleimpl_id);
|
||||||
|
|
||||||
|
// On récupère les assiduités
|
||||||
|
await fetch(url)
|
||||||
|
// On convertit la réponse en JSON
|
||||||
|
.then((res) => {
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error("Network response was not ok");
|
||||||
|
}
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
// On traite les données
|
||||||
|
.then((data) => {
|
||||||
|
for (let etudid of etudids) {
|
||||||
|
// On crée une case pour chaque étudiant
|
||||||
|
let cell = document.createElement("div");
|
||||||
|
cell.classList.add("cell");
|
||||||
|
cell.setAttribute("data-etudid", etudid);
|
||||||
|
cell.setAttribute("data-periodeid", periodId);
|
||||||
|
cell.id = `cell-${etudid}-${periodId}`;
|
||||||
|
document.getElementById("tableau-periode").appendChild(cell);
|
||||||
|
|
||||||
|
//Vérification inscription au module
|
||||||
|
// Si l'étudiant n'est pas inscrit, on le notifie et on passe à l'étudiant suivant
|
||||||
|
const inscrit =
|
||||||
|
inscriptions == null ? true : inscriptions.find((e) => e == etudid);
|
||||||
|
if (!inscrit) {
|
||||||
|
cell.textContent = "Non inscrit";
|
||||||
|
cell.classList.add("non-inscrit");
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
return res.json();
|
|
||||||
})
|
|
||||||
.then((data)=>{
|
|
||||||
Object.entries(data).forEach(([etudid, assiduites]) => {
|
|
||||||
let cell = document.createElement("div");
|
|
||||||
cell.classList.add("cell");
|
|
||||||
cell.setAttribute("data-etudid", etudid);
|
|
||||||
cell.setAttribute("data-periodeid", periodeId);
|
|
||||||
|
|
||||||
if (assiduites.length == 0) {
|
//Gestion des assiduités déjà existantes
|
||||||
["present", "retard", "absent"].forEach((value) => {
|
const assiduites = data[etudid];
|
||||||
const cbox = document.createElement('input');
|
// Si l'étudiant n'a pas d'assiduité, on crée les boutons assiduité
|
||||||
cbox.type = "checkbox";
|
if (assiduites.length == 0) {
|
||||||
cbox.value = value;
|
["present", "retard", "absent"].forEach((value) => {
|
||||||
cbox.name = `rbtn_${etudid}_${periodeId}`
|
const cbox = document.createElement("input");
|
||||||
cbox.classList.add("rbtn", value);
|
cbox.type = "checkbox";
|
||||||
|
cbox.value = value;
|
||||||
|
cbox.name = `rbtn_${etudid}_${periodId}`;
|
||||||
|
cbox.classList.add("rbtn", value);
|
||||||
|
|
||||||
cbox.addEventListener('click', (event)=>{
|
// Event pour être sur qu'un seul bouton est coché à la fois
|
||||||
const parent = event.target.parentElement;
|
cbox.addEventListener("click", (event) => {
|
||||||
parent.querySelectorAll(".rbtn").forEach((ele)=>{
|
const parent = event.target.parentElement;
|
||||||
if(ele.value != value){
|
parent.querySelectorAll(".rbtn").forEach((ele) => {
|
||||||
ele.checked = false;
|
if (ele.value != value) {
|
||||||
}
|
ele.checked = false;
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
cbox.checked = etatDef.value == value
|
|
||||||
|
|
||||||
cell.appendChild(cbox);
|
|
||||||
});
|
|
||||||
}else{
|
|
||||||
setupAssiduiteBubble(cell, assiduites[0])
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
document.getElementById("tableau-periode").appendChild(cell);
|
|
||||||
});
|
});
|
||||||
}).catch((error)=>{
|
// Si une valeur par défaut est donnée alors on l'applique
|
||||||
console.error('Error:', error);
|
cbox.checked = etatDef.value == value;
|
||||||
|
|
||||||
|
cell.appendChild(cbox);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Si une (ou plus) assiduité sont trouvée pour la période
|
||||||
|
// alors on affiche les informations de la première assiduité
|
||||||
|
setupAssiduiteBubble(cell, assiduites[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//Si jamais la requête échoue, on affiche un message d'erreur dans la console
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Error:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Permet de récupérer la saisie puis créer les assiduités grâce à l'api
|
||||||
|
*/
|
||||||
|
function sauvegarderAssiduites() {
|
||||||
|
// Initialisation de la liste des assiduités à créer
|
||||||
|
let assiduitesData = [];
|
||||||
|
// Pour chaque période, on récupère les assiduités saisies
|
||||||
|
for (let [periodeId, periode] of periodes.entries()) {
|
||||||
|
// On prend chaque cellule correspondant à la période
|
||||||
|
const cells = document.querySelectorAll(
|
||||||
|
`.cell[data-periodeid="${periodeId}"][data-etudid]`
|
||||||
|
);
|
||||||
|
// Pour chaque cellule, on récupère l'état de l'assiduité
|
||||||
|
cells.forEach((cell) => {
|
||||||
|
const etudid = cell.getAttribute("data-etudid");
|
||||||
|
const etat = cell.querySelector(".rbtn:checked")?.value;
|
||||||
|
// Il est possible que l'état soit null
|
||||||
|
// - Cas où l'étudiant n'est pas inscrit
|
||||||
|
// - Cas où l'étudiant avait déjà une assiduité
|
||||||
|
if (etat) {
|
||||||
|
// On génère un objet "assiduité"
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
etudid: <int>,
|
||||||
|
etat: <string>,
|
||||||
|
date_debut: <string>,
|
||||||
|
date_fin: <string>,
|
||||||
|
moduleimpl_id: <int>,
|
||||||
|
periodId: <int>
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
assiduitesData.push({
|
||||||
|
etudid: etudid,
|
||||||
|
etat: etat,
|
||||||
|
...periode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Une fois les assiduités générées, on les envoie à l'api
|
||||||
|
async_post(
|
||||||
|
"../../api/assiduites/create",
|
||||||
|
assiduitesData,
|
||||||
|
// Si la requête passe
|
||||||
|
async (data) => {
|
||||||
|
// On supprime toutes les cases du tableau pour le mettre à jour
|
||||||
|
document.querySelectorAll(".cell").forEach((e) => e.remove());
|
||||||
|
|
||||||
|
// On recrée les périodes
|
||||||
|
// (cela permet de redemander les assiduités, donc mettre à jour les cases)
|
||||||
|
for (let periode of periodes.values()) {
|
||||||
|
await nouvellePeriode(periode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si il y n'a pas d'erreur, on affiche un message de succès
|
||||||
|
if (data.errors.length == 0) {
|
||||||
|
const span = document.createElement("span");
|
||||||
|
span.textContent = "Les assiduités ont bien été sauvegardées.";
|
||||||
|
openAlertModal(
|
||||||
|
"Sauvegarde des assiduités",
|
||||||
|
span,
|
||||||
|
null,
|
||||||
|
"var(--color-present)"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Si il y a des erreurs, on les affiche
|
||||||
|
if (data.errors.length > 0) {
|
||||||
|
// On crée une map pour regrouper les erreurs par période
|
||||||
|
const erreurs = new Map();
|
||||||
|
data.errors.forEach((err) => {
|
||||||
|
// Pour chaque période on créer une liste d'erreurs
|
||||||
|
// format : [message, etudid]
|
||||||
|
const assi = assiduitesData[err.indice];
|
||||||
|
const msg = err.message;
|
||||||
|
const periodErrors = erreurs.get(assi.periodId) || [];
|
||||||
|
|
||||||
|
// Récupération du nom de l'étudiant
|
||||||
|
const etud = document.querySelector(
|
||||||
|
`#head-${assi.etudid} span`
|
||||||
|
).textContent;
|
||||||
|
periodErrors.push([`Erreur pour ${etud} : ${msg}`, assi.etudid]);
|
||||||
|
erreurs.set(assi.periodId, periodErrors);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
// Création du DOM
|
||||||
|
/*
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Période du ... de ... à ...
|
||||||
|
<ul>
|
||||||
|
<li>Erreur pour ...</li>
|
||||||
|
<li>Erreur pour ...</li>
|
||||||
|
</ul>
|
||||||
|
/li>
|
||||||
|
</ul>
|
||||||
|
*/
|
||||||
|
|
||||||
|
const ul = document.createElement("ul");
|
||||||
|
//Pour chaque période on créer un titre "periode du ... de ... à ..."
|
||||||
|
for (let [periodeId, periodErrors] of erreurs.entries()) {
|
||||||
|
const period = periodes.get(periodeId);
|
||||||
|
const li = document.createElement("li");
|
||||||
|
// On affiche la période
|
||||||
|
li.textContent = `Période du ${period.date_debut.format(
|
||||||
|
"DD/MM/YYYY HH:mm"
|
||||||
|
)} à ${period.date_fin.format("HH:mm")}`;
|
||||||
|
|
||||||
|
// Nous emmène à la période lorsqu'on clique dessus
|
||||||
|
li.addEventListener("click", () => {
|
||||||
|
location.href = `#periode-${periodeId}`;
|
||||||
|
});
|
||||||
|
li.classList.add("pointer");
|
||||||
|
|
||||||
let periodeId = 0;
|
// Pour chaque erreur, on créer un élément de liste
|
||||||
const moduleimpls = new Map();
|
const ul2 = document.createElement("ul");
|
||||||
const nonWorkDays = [{{ nonworkdays| safe }}];
|
periodErrors.forEach((err) => {
|
||||||
|
const li2 = document.createElement("li");
|
||||||
|
li2.textContent = err[0];
|
||||||
window.forceModule = "{{ forcer_module }}" == "True"
|
li2.classList.add("pointer");
|
||||||
if (window.forceModule) {
|
|
||||||
if (moduleimpl_select.value == "") {
|
|
||||||
document.getElementById('forcemodule').style.display = "block";
|
|
||||||
add_periode.disabled = true;
|
|
||||||
|
|
||||||
|
// Nous emmène à la case de l'étudiant lorsqu'on clique dessus
|
||||||
|
li2.addEventListener("click", () => {
|
||||||
|
location.href = `#cell-${err[1]}-${periodeId}`;
|
||||||
|
});
|
||||||
|
ul2.appendChild(li2);
|
||||||
|
});
|
||||||
|
li.appendChild(ul2);
|
||||||
|
ul.appendChild(li);
|
||||||
}
|
}
|
||||||
|
|
||||||
moduleimpl_select?.addEventListener('change', (e) => {
|
openAlertModal(
|
||||||
if (e.target.value != "") {
|
"Erreurs lors de la sauvegarde des assiduités",
|
||||||
document.getElementById('forcemodule').style.display = "none";
|
ul,
|
||||||
add_periode.disabled = false;
|
"Les autres assiduités ont bien été sauvegardées."
|
||||||
|
);
|
||||||
} else {
|
}
|
||||||
document.getElementById('forcemodule').style.display = "block";
|
},
|
||||||
add_periode.disabled = true;
|
(e) => {
|
||||||
|
console.error("Erreur lors de la création des assiduités", e);
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async function main(){
|
// Mis en place des variables globales
|
||||||
afficherPDP(pdp.checked);
|
let currentPeriodId = 0;
|
||||||
$('#date').on('change', async function(d) {
|
const periodes = new Map();
|
||||||
// On vérifie si la date est un jour travaillé
|
const moduleimpls = new Map();
|
||||||
dateCouranteEstTravaillee();
|
const inscriptionsModules = new Map();
|
||||||
});
|
const nonWorkDays = [{{ nonworkdays| safe }}];
|
||||||
|
|
||||||
|
// Vérification du forçage de module
|
||||||
|
window.forceModule = "{{ forcer_module }}" == "True";
|
||||||
|
if (window.forceModule) {
|
||||||
|
if (moduleimpl_select.value == "") {
|
||||||
|
document.getElementById("forcemodule").style.display = "block";
|
||||||
|
add_periode.disabled = true;
|
||||||
|
}
|
||||||
|
// Désactivation du bouton d'ajout de période si aucun module n'est sélectionné
|
||||||
|
// et affichage du message de forçage de module
|
||||||
|
moduleimpl_select?.addEventListener("change", (e) => {
|
||||||
|
if (e.target.value != "") {
|
||||||
|
document.getElementById("forcemodule").style.display = "none";
|
||||||
|
add_periode.disabled = false;
|
||||||
|
} else {
|
||||||
|
document.getElementById("forcemodule").style.display = "block";
|
||||||
|
add_periode.disabled = true;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Fonction exécutée au lancement de la page
|
||||||
|
* - On affiche ou non les photos des étudiants
|
||||||
|
* - On vérifie si la date est un jour travaillé
|
||||||
|
*/
|
||||||
|
async function main() {
|
||||||
|
afficherPDP(pdp.checked);
|
||||||
|
$("#date").on("change", async function (d) {
|
||||||
|
// On vérifie si la date est un jour travaillé
|
||||||
|
dateCouranteEstTravaillee();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
||||||
main();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock scripts %}
|
{% endblock scripts %}
|
||||||
@ -311,8 +537,6 @@
|
|||||||
- Sauvegarder
|
- Sauvegarder
|
||||||
- Afficher la photo de profil
|
- Afficher la photo de profil
|
||||||
- Assiduité par défaut (aucune, present, retard, absent)
|
- Assiduité par défaut (aucune, present, retard, absent)
|
||||||
? - Import Excel (fournie un fichier excel
|
|
||||||
avec les étudiants et les périodes préremplis)
|
|
||||||
--->
|
--->
|
||||||
|
|
||||||
<div id="actions" class="box">
|
<div id="actions" class="box">
|
||||||
@ -330,12 +554,8 @@
|
|||||||
<option value="absent">Absence</option>
|
<option value="absent">Absence</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="excel" class="wip">
|
<button id="save" onclick="sauvegarderAssiduites()">Sauvegarder l'assiduité</button>
|
||||||
Importer Excel :
|
|
||||||
<input type="file" name="excel" id="excel" accept=".xlsx, .xls, .csv">
|
|
||||||
</label>
|
|
||||||
<button class="wip" id="save wip">Sauvegarder l'assiduité</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1848,10 +1848,18 @@ def signal_assiduites_diff():
|
|||||||
grp + ' <span class="fontred">' + groups_infos.groups_titles + "</span>"
|
grp + ' <span class="fontred">' + groups_infos.groups_titles + "</span>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
moduleimpl_id = request.args.get("moduleimpl_id", -1)
|
||||||
|
try:
|
||||||
|
moduleimpl_id = int(moduleimpl_id)
|
||||||
|
except ValueError:
|
||||||
|
moduleimpl_id = -1
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"assiduites/pages/signal_assiduites_diff.j2",
|
"assiduites/pages/signal_assiduites_diff.j2",
|
||||||
etudiants=etudiants,
|
etudiants=etudiants,
|
||||||
moduleimpl_select=_module_selector(formsemestre=formsemestre),
|
moduleimpl_select=_module_selector(
|
||||||
|
formsemestre=formsemestre, moduleimpl_id=moduleimpl_id
|
||||||
|
),
|
||||||
gr=gr_tit,
|
gr=gr_tit,
|
||||||
nonworkdays=_non_work_days(),
|
nonworkdays=_non_work_days(),
|
||||||
sco=ScoData(formsemestre=formsemestre),
|
sco=ScoData(formsemestre=formsemestre),
|
||||||
|
Loading…
Reference in New Issue
Block a user