forked from ScoDoc/ScoDoc
Assiduites : Gestion des justificatifs (rapide) WIP
Assiduites : ajout style justifié (minitimeline)
This commit is contained in:
parent
f3b540b4c1
commit
f26ecb1f8a
@ -316,10 +316,10 @@ def compute_assiduites_justified(
|
|||||||
for justi in justificatifs:
|
for justi in justificatifs:
|
||||||
assiduites: Assiduite = (
|
assiduites: Assiduite = (
|
||||||
Assiduite.query.join(Justificatif, Justificatif.etudid == Assiduite.etudid)
|
Assiduite.query.join(Justificatif, Justificatif.etudid == Assiduite.etudid)
|
||||||
.filter(Assiduite.etat != EtatAssiduite.PRESENT)
|
.filter(justi.etat == EtatJustificatif.VALIDE)
|
||||||
.filter(
|
.filter(
|
||||||
Assiduite.date_debut <= justi.date_fin,
|
Assiduite.date_debut < justi.date_fin,
|
||||||
Assiduite.date_fin >= justi.date_debut,
|
Assiduite.date_fin > justi.date_debut,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -329,11 +329,9 @@ def compute_assiduites_justified(
|
|||||||
db.session.add(assi)
|
db.session.add(assi)
|
||||||
|
|
||||||
if reset:
|
if reset:
|
||||||
un_justified: Assiduite = (
|
un_justified: Assiduite = Assiduite.query.filter(
|
||||||
Assiduite.query.filter(Assiduite.id.not_in(list_assiduites_id))
|
Assiduite.id.not_in(list_assiduites_id)
|
||||||
.filter(Assiduite.etat != EtatAssiduite.PRESENT)
|
).join(Justificatif, Justificatif.etudid == Assiduite.etudid)
|
||||||
.join(Justificatif, Justificatif.etudid == Assiduite.etudid)
|
|
||||||
)
|
|
||||||
|
|
||||||
for assi in un_justified:
|
for assi in un_justified:
|
||||||
assi.est_just = False
|
assi.est_just = False
|
||||||
|
@ -20,7 +20,6 @@ class CountCalculator:
|
|||||||
evening: time = time(18, 0),
|
evening: time = time(18, 0),
|
||||||
skip_saturday: bool = True,
|
skip_saturday: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
self.morning: time = morning
|
self.morning: time = morning
|
||||||
self.noon: time = noon
|
self.noon: time = noon
|
||||||
self.after_noon: time = after_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:
|
if justi.etat != scu.EtatJustificatif.VALIDE:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
assiduites_query: Assiduite = (
|
assiduites_query: Assiduite = Assiduite.query.join(
|
||||||
Assiduite.query.join(Justificatif, Assiduite.etudid == Justificatif.etudid)
|
Justificatif, Assiduite.etudid == Justificatif.etudid
|
||||||
.filter(Assiduite.etat != scu.EtatAssiduite.PRESENT)
|
).filter(
|
||||||
.filter(
|
Assiduite.date_debut <= justi.date_fin,
|
||||||
Assiduite.date_debut <= justi.date_fin,
|
Assiduite.date_fin >= justi.date_debut,
|
||||||
Assiduite.date_fin >= justi.date_debut,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if not obj:
|
if not obj:
|
||||||
|
@ -192,6 +192,14 @@
|
|||||||
background-color: #F1D99C !important;
|
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 --- */
|
/* --- Boutons assiduités --- */
|
||||||
.etud_row .btns_field {
|
.etud_row .btns_field {
|
||||||
|
@ -16,6 +16,7 @@ let currentValues = [8.0, 10.0];
|
|||||||
//Objet stockant les étudiants et les assiduités
|
//Objet stockant les étudiants et les assiduités
|
||||||
let etuds = {};
|
let etuds = {};
|
||||||
let assiduites = {};
|
let assiduites = {};
|
||||||
|
let justificatifs = {};
|
||||||
|
|
||||||
// Variable qui définit si le processus d'action de masse est lancé
|
// Variable qui définit si le processus d'action de masse est lancé
|
||||||
let currentMassAction = false;
|
let currentMassAction = false;
|
||||||
@ -1094,12 +1095,40 @@ function createMiniTimeline(assiduitesArray) {
|
|||||||
|
|
||||||
setPeriodValues(deb, fin);
|
setPeriodValues(deb, fin);
|
||||||
updateSelectedSelect(getCurrentAssiduiteModuleImplId());
|
updateSelectedSelect(getCurrentAssiduiteModuleImplId());
|
||||||
|
updateJustifyBtn();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//ajouter affichage assiduites on over
|
//ajouter affichage assiduites on over
|
||||||
setupAssiduiteBuble(block, assiduité);
|
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) {
|
switch (assiduité.etat) {
|
||||||
case "PRESENT":
|
case "PRESENT":
|
||||||
block.classList.add("present");
|
block.classList.add("present");
|
||||||
@ -1773,31 +1802,33 @@ function getCurrentAssiduite(etudid) {
|
|||||||
|
|
||||||
// <<== Gestion de la justification ==>>
|
// <<== Gestion de la justification ==>>
|
||||||
|
|
||||||
function getJustificatifFromPeriod(date) {
|
function getJustificatifFromPeriod(date, etudid, update) {
|
||||||
let justifs = [];
|
$.ajax({
|
||||||
sync_get(
|
async: true,
|
||||||
getUrl() +
|
type: "GET",
|
||||||
`/api/justificatifs/${etudid}/query?date_debut=${date.deb.format()}&date_fin=${date.fin.format()}`,
|
url:
|
||||||
(data) => {
|
getUrl() +
|
||||||
justifs = data;
|
`/api/justificatifs/${etudid}/query?date_debut=${date.deb
|
||||||
}
|
.add(1, "s")
|
||||||
);
|
.format()}&date_fin=${date.fin.subtract(1, "s").format()}`,
|
||||||
|
success: (data) => {
|
||||||
return justifs;
|
update(data);
|
||||||
|
},
|
||||||
|
error: () => {},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateJustifieButton(isJustified, isDisabled = true) {
|
function updateJustifyBtn() {
|
||||||
const btn = document.getElementById("justif-rapide");
|
if (isSingleEtud()) {
|
||||||
if (isJustified) {
|
const assi = getCurrentAssiduite(etudid);
|
||||||
btn.classList.add("justifie");
|
|
||||||
} else {
|
|
||||||
btn.classList.remove("justifie");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDisabled) {
|
const just = assi ? !assi.est_just : false;
|
||||||
btn.setAttribute("disabled", "true");
|
const btn = document.getElementById("justif-rapide");
|
||||||
} else {
|
if (!just) {
|
||||||
btn.removeAttribute("disabled");
|
btn.setAttribute("disabled", "true");
|
||||||
|
} else {
|
||||||
|
btn.removeAttribute("disabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1806,12 +1837,100 @@ function fastJustify(assiduite) {
|
|||||||
deb: new moment.tz(assiduite.date_debut, TIMEZONE),
|
deb: new moment.tz(assiduite.date_debut, TIMEZONE),
|
||||||
fin: new moment.tz(assiduite.date_fin, 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) {
|
const success = () => {
|
||||||
//modifier l'assiduité
|
const raison = document.getElementById("promptText").value;
|
||||||
} else {
|
const etat = document.getElementById("promptSelect").value;
|
||||||
//créer un nouveau justificatif
|
|
||||||
// Afficher prompt -> demander raison et état
|
//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>
|
||||||
</div>
|
</div>
|
||||||
{% include "assiduites/toast.j2" %}
|
{% include "assiduites/toast.j2" %}
|
||||||
|
{% include "assiduites/alert.j2" %}
|
||||||
|
{% include "assiduites/prompt.j2" %}
|
||||||
<div id="page-assiduite-content">
|
<div id="page-assiduite-content">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Signalement de l'assiduité de <span class="rouge">{{sco.etud.nomprenom}}</span></h2>
|
<h2>Signalement de l'assiduité de <span class="rouge">{{sco.etud.nomprenom}}</span></h2>
|
||||||
@ -43,13 +45,13 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
{% include "assiduites/moduleimpl_dynamic_selector.j2" %}
|
{% 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>
|
||||||
|
|
||||||
<div class="btn_group">
|
<div class="btn_group">
|
||||||
<button class="btn" onclick="setPeriodValues(8,18)">Journée</button>
|
<button class="btn" onclick="setTimeLineTimes(8,18)">Journée</button>
|
||||||
<button class="btn" onclick="setPeriodValues(8,13)">Matin</button>
|
<button class="btn" onclick="setTimeLineTimes(8,13)">Matin</button>
|
||||||
<button class="btn" onclick="setPeriodValues(13,18)">Après-midi</button>
|
<button class="btn" onclick="setTimeLineTimes(13,18)">Après-midi</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="etud_holder">
|
<div class="etud_holder">
|
||||||
@ -64,8 +66,7 @@
|
|||||||
<div class="loader"></div>
|
<div class="loader"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% include "assiduites/alert.j2" %}
|
|
||||||
{% include "assiduites/prompt.j2" %}
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const etudid = {{ sco.etud.id }};
|
const etudid = {{ sco.etud.id }};
|
||||||
@ -74,20 +75,29 @@
|
|||||||
updateSelect()
|
updateSelect()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setupTimeLine(() => {
|
||||||
|
updateJustifyBtn();
|
||||||
|
});
|
||||||
|
|
||||||
updateDate();
|
updateDate();
|
||||||
|
|
||||||
getSingleEtud({{ sco.etud.id }});
|
getSingleEtud({{ sco.etud.id }});
|
||||||
actualizeEtud({{ sco.etud.id }});
|
actualizeEtud({{ sco.etud.id }});
|
||||||
updateSelect()
|
updateSelect()
|
||||||
|
|
||||||
|
updateJustifyBtn();
|
||||||
|
|
||||||
|
|
||||||
|
function setTimeLineTimes(a, b) {
|
||||||
|
setPeriodValues(a, b);
|
||||||
|
updateJustifyBtn();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.rouge {
|
|
||||||
color: crimson;
|
|
||||||
}
|
|
||||||
|
|
||||||
.justifie {
|
.justifie {
|
||||||
background-color: rgb(104, 104, 252);
|
background-color: rgb(104, 104, 252);
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
|
@ -72,5 +72,6 @@
|
|||||||
<script>
|
<script>
|
||||||
updateDate();
|
updateDate();
|
||||||
setupDate();
|
setupDate();
|
||||||
|
setupTimeLine();
|
||||||
</script>
|
</script>
|
||||||
</section>
|
</section>
|
@ -38,62 +38,69 @@
|
|||||||
return Math.round(value * 4) / 4;
|
return Math.round(value * 4) / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
timelineContainer.addEventListener("mousedown", (event) => {
|
function setupTimeLine(callback) {
|
||||||
const startX = event.clientX;
|
const func_call = callback ? callback : () => { }
|
||||||
|
timelineContainer.addEventListener("mousedown", (event) => {
|
||||||
|
const startX = event.clientX;
|
||||||
|
|
||||||
if (event.target === periodTimeLine) {
|
if (event.target === periodTimeLine) {
|
||||||
const startLeft = parseFloat(periodTimeLine.style.left);
|
const startLeft = parseFloat(periodTimeLine.style.left);
|
||||||
|
|
||||||
const onMouseMove = (moveEvent) => {
|
const onMouseMove = (moveEvent) => {
|
||||||
const deltaX = moveEvent.clientX - startX;
|
const deltaX = moveEvent.clientX - startX;
|
||||||
const containerWidth = timelineContainer.clientWidth;
|
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 newLeft = startLeft + (deltaX / containerWidth) * 100;
|
const newLeft = startLeft + (deltaX / containerWidth) * 100;
|
||||||
adjustPeriodPosition(newLeft, newWidth);
|
|
||||||
} else {
|
|
||||||
adjustPeriodPosition(parseFloat(periodTimeLine.style.left), newWidth);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener("mousemove", onMouseMove);
|
adjustPeriodPosition(newLeft, parseFloat(periodTimeLine.style.width));
|
||||||
document.addEventListener(
|
};
|
||||||
"mouseup",
|
|
||||||
() => {
|
|
||||||
snapHandlesToQuarters()
|
|
||||||
generateAllEtudRow();
|
|
||||||
|
|
||||||
document.removeEventListener("mousemove", onMouseMove);
|
document.addEventListener("mousemove", onMouseMove);
|
||||||
},
|
document.addEventListener(
|
||||||
{ once: true }
|
"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) {
|
function adjustPeriodPosition(newLeft, newWidth) {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user