Assiduites : Gestion des justificatifs (rapide) WIP
Assiduites : ajout style justifié (minitimeline)
This commit is contained in:
parent
35646a934b
commit
d796c7db93
@ -316,10 +316,10 @@ def compute_assiduites_justified(
|
||||
for justi in justificatifs:
|
||||
assiduites: Assiduite = (
|
||||
Assiduite.query.join(Justificatif, Justificatif.etudid == Assiduite.etudid)
|
||||
.filter(Assiduite.etat != EtatAssiduite.PRESENT)
|
||||
.filter(justi.etat == EtatJustificatif.VALIDE)
|
||||
.filter(
|
||||
Assiduite.date_debut <= justi.date_fin,
|
||||
Assiduite.date_fin >= justi.date_debut,
|
||||
Assiduite.date_debut < justi.date_fin,
|
||||
Assiduite.date_fin > justi.date_debut,
|
||||
)
|
||||
)
|
||||
|
||||
@ -329,11 +329,9 @@ def compute_assiduites_justified(
|
||||
db.session.add(assi)
|
||||
|
||||
if reset:
|
||||
un_justified: Assiduite = (
|
||||
Assiduite.query.filter(Assiduite.id.not_in(list_assiduites_id))
|
||||
.filter(Assiduite.etat != EtatAssiduite.PRESENT)
|
||||
.join(Justificatif, Justificatif.etudid == Assiduite.etudid)
|
||||
)
|
||||
un_justified: Assiduite = Assiduite.query.filter(
|
||||
Assiduite.id.not_in(list_assiduites_id)
|
||||
).join(Justificatif, Justificatif.etudid == Assiduite.etudid)
|
||||
|
||||
for assi in un_justified:
|
||||
assi.est_just = False
|
||||
|
@ -20,7 +20,6 @@ class CountCalculator:
|
||||
evening: time = time(18, 0),
|
||||
skip_saturday: bool = True,
|
||||
) -> None:
|
||||
|
||||
self.morning: time = morning
|
||||
self.noon: time = noon
|
||||
self.after_noon: time = after_noon
|
||||
@ -318,13 +317,11 @@ def justifies(justi: Justificatif, obj: bool = False) -> list[int]:
|
||||
if justi.etat != scu.EtatJustificatif.VALIDE:
|
||||
return []
|
||||
|
||||
assiduites_query: Assiduite = (
|
||||
Assiduite.query.join(Justificatif, Assiduite.etudid == Justificatif.etudid)
|
||||
.filter(Assiduite.etat != scu.EtatAssiduite.PRESENT)
|
||||
.filter(
|
||||
Assiduite.date_debut <= justi.date_fin,
|
||||
Assiduite.date_fin >= justi.date_debut,
|
||||
)
|
||||
assiduites_query: Assiduite = Assiduite.query.join(
|
||||
Justificatif, Assiduite.etudid == Justificatif.etudid
|
||||
).filter(
|
||||
Assiduite.date_debut <= justi.date_fin,
|
||||
Assiduite.date_fin >= justi.date_debut,
|
||||
)
|
||||
|
||||
if not obj:
|
||||
|
@ -192,6 +192,14 @@
|
||||
background-color: #F1D99C !important;
|
||||
}
|
||||
|
||||
.etud_row .assiduites_bar .justified {
|
||||
background-image: repeating-linear-gradient(135deg, transparent, transparent 4px, #7059FF 4px, #7059FF 8px);
|
||||
}
|
||||
|
||||
.etud_row .assiduites_bar .invalid_justified {
|
||||
background-image: repeating-linear-gradient(135deg, transparent, transparent 4px, #d61616 4px, #d61616 8px);
|
||||
}
|
||||
|
||||
|
||||
/* --- Boutons assiduités --- */
|
||||
.etud_row .btns_field {
|
||||
|
@ -16,6 +16,7 @@ let currentValues = [8.0, 10.0];
|
||||
//Objet stockant les étudiants et les assiduités
|
||||
let etuds = {};
|
||||
let assiduites = {};
|
||||
let justificatifs = {};
|
||||
|
||||
// Variable qui définit si le processus d'action de masse est lancé
|
||||
let currentMassAction = false;
|
||||
@ -1094,12 +1095,40 @@ function createMiniTimeline(assiduitesArray) {
|
||||
|
||||
setPeriodValues(deb, fin);
|
||||
updateSelectedSelect(getCurrentAssiduiteModuleImplId());
|
||||
updateJustifyBtn();
|
||||
});
|
||||
}
|
||||
//ajouter affichage assiduites on over
|
||||
setupAssiduiteBuble(block, assiduité);
|
||||
|
||||
if (assiduité.est_just) {
|
||||
block.classList.add("justified");
|
||||
}
|
||||
}
|
||||
|
||||
const action = (justificatifs) => {
|
||||
if (justificatifs.length > 0) {
|
||||
let j = "invalid_justified";
|
||||
|
||||
justificatifs.forEach((ju) => {
|
||||
if (ju.etat == "VALIDE") {
|
||||
j = "justified";
|
||||
}
|
||||
});
|
||||
|
||||
block.classList.add(j);
|
||||
}
|
||||
};
|
||||
|
||||
getJustificatifFromPeriod(
|
||||
{
|
||||
deb: new moment.tz(assiduité.date_debut, TIMEZONE),
|
||||
fin: new moment.tz(assiduité.date_fin, TIMEZONE),
|
||||
},
|
||||
assiduité.etudid,
|
||||
action
|
||||
);
|
||||
|
||||
switch (assiduité.etat) {
|
||||
case "PRESENT":
|
||||
block.classList.add("present");
|
||||
@ -1773,31 +1802,33 @@ function getCurrentAssiduite(etudid) {
|
||||
|
||||
// <<== Gestion de la justification ==>>
|
||||
|
||||
function getJustificatifFromPeriod(date) {
|
||||
let justifs = [];
|
||||
sync_get(
|
||||
getUrl() +
|
||||
`/api/justificatifs/${etudid}/query?date_debut=${date.deb.format()}&date_fin=${date.fin.format()}`,
|
||||
(data) => {
|
||||
justifs = data;
|
||||
}
|
||||
);
|
||||
|
||||
return justifs;
|
||||
function getJustificatifFromPeriod(date, etudid, update) {
|
||||
$.ajax({
|
||||
async: true,
|
||||
type: "GET",
|
||||
url:
|
||||
getUrl() +
|
||||
`/api/justificatifs/${etudid}/query?date_debut=${date.deb
|
||||
.add(1, "s")
|
||||
.format()}&date_fin=${date.fin.subtract(1, "s").format()}`,
|
||||
success: (data) => {
|
||||
update(data);
|
||||
},
|
||||
error: () => {},
|
||||
});
|
||||
}
|
||||
|
||||
function updateJustifieButton(isJustified, isDisabled = true) {
|
||||
const btn = document.getElementById("justif-rapide");
|
||||
if (isJustified) {
|
||||
btn.classList.add("justifie");
|
||||
} else {
|
||||
btn.classList.remove("justifie");
|
||||
}
|
||||
function updateJustifyBtn() {
|
||||
if (isSingleEtud()) {
|
||||
const assi = getCurrentAssiduite(etudid);
|
||||
|
||||
if (isDisabled) {
|
||||
btn.setAttribute("disabled", "true");
|
||||
} else {
|
||||
btn.removeAttribute("disabled");
|
||||
const just = assi ? !assi.est_just : false;
|
||||
const btn = document.getElementById("justif-rapide");
|
||||
if (!just) {
|
||||
btn.setAttribute("disabled", "true");
|
||||
} else {
|
||||
btn.removeAttribute("disabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1806,12 +1837,100 @@ function fastJustify(assiduite) {
|
||||
deb: new moment.tz(assiduite.date_debut, TIMEZONE),
|
||||
fin: new moment.tz(assiduite.date_fin, TIMEZONE),
|
||||
};
|
||||
const justifs = getJustificatifFromPeriod(period);
|
||||
const action = (justifs) => {
|
||||
if (justifs.length > 0) {
|
||||
justifyAssiduite(assiduite.assiduite_id, !assiduite.est_just);
|
||||
} else {
|
||||
console.debug("WIP");
|
||||
//créer un nouveau justificatif
|
||||
// Afficher prompt -> demander raison et état
|
||||
|
||||
if (justifs.length > 0) {
|
||||
//modifier l'assiduité
|
||||
} else {
|
||||
//créer un nouveau justificatif
|
||||
// Afficher prompt -> demander raison et état
|
||||
}
|
||||
const success = () => {
|
||||
const raison = document.getElementById("promptText").value;
|
||||
const etat = document.getElementById("promptSelect").value;
|
||||
|
||||
//créer justificatif
|
||||
|
||||
const justif = {
|
||||
date_debut: new moment.tz(assiduite.date_debut, TIMEZONE)
|
||||
.add(1, "s")
|
||||
.format(),
|
||||
date_fin: new moment.tz(assiduite.date_fin, TIMEZONE)
|
||||
.subtract(1, "s")
|
||||
.format(),
|
||||
raison: raison,
|
||||
etat: etat,
|
||||
};
|
||||
|
||||
createJustificatif(justif);
|
||||
|
||||
// justifyAssiduite(assiduite.assiduite_id, true);
|
||||
generateAllEtudRow();
|
||||
};
|
||||
|
||||
const content = document.createElement("fieldset");
|
||||
|
||||
const htmlPrompt = `<legend>Entrez l'état du justificatif :</legend>
|
||||
<select name="promptSelect" id="promptSelect" required>
|
||||
<option value="valide">Valide</option>
|
||||
<option value="attente">En Attente de validation</option>
|
||||
<option value="non_valide">Non Valide</option>
|
||||
<option value="modifie">Modifié</option>
|
||||
</select>
|
||||
<legend>Raison:</legend>
|
||||
<textarea type="text" placeholder="Explication du justificatif (non obligatoire)" id="promptText" style="width:100%;"></textarea>
|
||||
`;
|
||||
|
||||
content.innerHTML = htmlPrompt;
|
||||
|
||||
openPromptModal(
|
||||
"Nouveau justificatif (Rapide)",
|
||||
content,
|
||||
success,
|
||||
() => {},
|
||||
"#7059FF"
|
||||
);
|
||||
}
|
||||
};
|
||||
getJustificatifFromPeriod(period, assiduite.etudid, action);
|
||||
}
|
||||
|
||||
function justifyAssiduite(assiduite_id, justified) {
|
||||
const assiduite = {
|
||||
est_just: justified,
|
||||
};
|
||||
const path = getUrl() + `/api/assiduite/${assiduite_id}/edit`;
|
||||
let bool = false;
|
||||
sync_post(
|
||||
path,
|
||||
assiduite,
|
||||
(data, status) => {
|
||||
bool = true;
|
||||
},
|
||||
(data, status) => {
|
||||
//error
|
||||
console.error(data, status);
|
||||
}
|
||||
);
|
||||
|
||||
return bool;
|
||||
}
|
||||
|
||||
function createJustificatif(justif) {
|
||||
const path = getUrl() + `/api/justificatif/${etudid}/create`;
|
||||
sync_post(
|
||||
path,
|
||||
[justif],
|
||||
(data, status) => {
|
||||
//success
|
||||
if (data.success.length > 0) {
|
||||
console.table(data[0]);
|
||||
}
|
||||
console.warn(data);
|
||||
},
|
||||
(data, status) => {
|
||||
//error
|
||||
console.error(data, status);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -29,6 +29,8 @@
|
||||
</div>
|
||||
</div>
|
||||
{% include "assiduites/toast.j2" %}
|
||||
{% include "assiduites/alert.j2" %}
|
||||
{% include "assiduites/prompt.j2" %}
|
||||
<div id="page-assiduite-content">
|
||||
{% block content %}
|
||||
<h2>Signalement de l'assiduité de <span class="rouge">{{sco.etud.nomprenom}}</span></h2>
|
||||
@ -43,13 +45,13 @@
|
||||
|
||||
<div>
|
||||
{% include "assiduites/moduleimpl_dynamic_selector.j2" %}
|
||||
<button class="btn" onclick="justify()" disabled id="justif-rapide">Justifier</button>
|
||||
<button class="btn" onclick="fastJustify(getCurrentAssiduite(etudid))" id="justif-rapide">Justifier</button>
|
||||
</div>
|
||||
|
||||
<div class="btn_group">
|
||||
<button class="btn" onclick="setPeriodValues(8,18)">Journée</button>
|
||||
<button class="btn" onclick="setPeriodValues(8,13)">Matin</button>
|
||||
<button class="btn" onclick="setPeriodValues(13,18)">Après-midi</button>
|
||||
<button class="btn" onclick="setTimeLineTimes(8,18)">Journée</button>
|
||||
<button class="btn" onclick="setTimeLineTimes(8,13)">Matin</button>
|
||||
<button class="btn" onclick="setTimeLineTimes(13,18)">Après-midi</button>
|
||||
</div>
|
||||
|
||||
<div class="etud_holder">
|
||||
@ -64,8 +66,7 @@
|
||||
<div class="loader"></div>
|
||||
</div>
|
||||
|
||||
{% include "assiduites/alert.j2" %}
|
||||
{% include "assiduites/prompt.j2" %}
|
||||
|
||||
|
||||
<script>
|
||||
const etudid = {{ sco.etud.id }};
|
||||
@ -74,20 +75,29 @@
|
||||
updateSelect()
|
||||
});
|
||||
|
||||
setupTimeLine(() => {
|
||||
updateJustifyBtn();
|
||||
});
|
||||
|
||||
updateDate();
|
||||
|
||||
getSingleEtud({{ sco.etud.id }});
|
||||
actualizeEtud({{ sco.etud.id }});
|
||||
updateSelect()
|
||||
|
||||
updateJustifyBtn();
|
||||
|
||||
|
||||
function setTimeLineTimes(a, b) {
|
||||
setPeriodValues(a, b);
|
||||
updateJustifyBtn();
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
.rouge {
|
||||
color: crimson;
|
||||
}
|
||||
|
||||
.justifie {
|
||||
background-color: rgb(104, 104, 252);
|
||||
color: whitesmoke;
|
||||
|
@ -72,5 +72,6 @@
|
||||
<script>
|
||||
updateDate();
|
||||
setupDate();
|
||||
setupTimeLine();
|
||||
</script>
|
||||
</section>
|
@ -38,62 +38,69 @@
|
||||
return Math.round(value * 4) / 4;
|
||||
}
|
||||
|
||||
timelineContainer.addEventListener("mousedown", (event) => {
|
||||
const startX = event.clientX;
|
||||
function setupTimeLine(callback) {
|
||||
const func_call = callback ? callback : () => { }
|
||||
timelineContainer.addEventListener("mousedown", (event) => {
|
||||
const startX = event.clientX;
|
||||
|
||||
if (event.target === periodTimeLine) {
|
||||
const startLeft = parseFloat(periodTimeLine.style.left);
|
||||
if (event.target === periodTimeLine) {
|
||||
const startLeft = parseFloat(periodTimeLine.style.left);
|
||||
|
||||
const onMouseMove = (moveEvent) => {
|
||||
const deltaX = moveEvent.clientX - startX;
|
||||
const containerWidth = timelineContainer.clientWidth;
|
||||
const newLeft = startLeft + (deltaX / containerWidth) * 100;
|
||||
|
||||
adjustPeriodPosition(newLeft, parseFloat(periodTimeLine.style.width));
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", onMouseMove);
|
||||
document.addEventListener(
|
||||
"mouseup",
|
||||
() => {
|
||||
generateAllEtudRow();
|
||||
snapHandlesToQuarters()
|
||||
document.removeEventListener("mousemove", onMouseMove);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
} else if (event.target.classList.contains("period-handle")) {
|
||||
const startWidth = parseFloat(periodTimeLine.style.width);
|
||||
const startLeft = parseFloat(periodTimeLine.style.left);
|
||||
const isLeftHandle = event.target.classList.contains("left");
|
||||
|
||||
const onMouseMove = (moveEvent) => {
|
||||
const deltaX = moveEvent.clientX - startX;
|
||||
const containerWidth = timelineContainer.clientWidth;
|
||||
const newWidth =
|
||||
startWidth + ((isLeftHandle ? -deltaX : deltaX) / containerWidth) * 100;
|
||||
|
||||
if (isLeftHandle) {
|
||||
const onMouseMove = (moveEvent) => {
|
||||
const deltaX = moveEvent.clientX - startX;
|
||||
const containerWidth = timelineContainer.clientWidth;
|
||||
const newLeft = startLeft + (deltaX / containerWidth) * 100;
|
||||
adjustPeriodPosition(newLeft, newWidth);
|
||||
} else {
|
||||
adjustPeriodPosition(parseFloat(periodTimeLine.style.left), newWidth);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", onMouseMove);
|
||||
document.addEventListener(
|
||||
"mouseup",
|
||||
() => {
|
||||
snapHandlesToQuarters()
|
||||
generateAllEtudRow();
|
||||
adjustPeriodPosition(newLeft, parseFloat(periodTimeLine.style.width));
|
||||
};
|
||||
|
||||
document.removeEventListener("mousemove", onMouseMove);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
document.addEventListener("mousemove", onMouseMove);
|
||||
document.addEventListener(
|
||||
"mouseup",
|
||||
() => {
|
||||
generateAllEtudRow();
|
||||
snapHandlesToQuarters()
|
||||
document.removeEventListener("mousemove", onMouseMove);
|
||||
func_call()
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
} else if (event.target.classList.contains("period-handle")) {
|
||||
const startWidth = parseFloat(periodTimeLine.style.width);
|
||||
const startLeft = parseFloat(periodTimeLine.style.left);
|
||||
const isLeftHandle = event.target.classList.contains("left");
|
||||
|
||||
const onMouseMove = (moveEvent) => {
|
||||
const deltaX = moveEvent.clientX - startX;
|
||||
const containerWidth = timelineContainer.clientWidth;
|
||||
const newWidth =
|
||||
startWidth + ((isLeftHandle ? -deltaX : deltaX) / containerWidth) * 100;
|
||||
|
||||
if (isLeftHandle) {
|
||||
const newLeft = startLeft + (deltaX / containerWidth) * 100;
|
||||
adjustPeriodPosition(newLeft, newWidth);
|
||||
} else {
|
||||
adjustPeriodPosition(parseFloat(periodTimeLine.style.left), newWidth);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", onMouseMove);
|
||||
document.addEventListener(
|
||||
"mouseup",
|
||||
() => {
|
||||
snapHandlesToQuarters()
|
||||
generateAllEtudRow();
|
||||
|
||||
document.removeEventListener("mousemove", onMouseMove);
|
||||
|
||||
func_call()
|
||||
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function adjustPeriodPosition(newLeft, newWidth) {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user