forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -53,7 +53,6 @@ import requests
|
|||||||
|
|
||||||
from pytz import timezone
|
from pytz import timezone
|
||||||
|
|
||||||
import dateutil.parser as dtparser
|
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import g, request, Response
|
from flask import g, request, Response
|
||||||
@ -230,9 +229,9 @@ def is_iso_formated(date: str, convert=False) -> bool or datetime.datetime or No
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
date: datetime.datetime = dtparser.isoparse(date)
|
date: datetime.datetime = datetime.datetime.fromisoformat(date)
|
||||||
return date if convert else True
|
return date if convert else True
|
||||||
except (dtparser.ParserError, ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
return None if convert else False
|
return None if convert else False
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,10 +36,10 @@
|
|||||||
|
|
||||||
.infos {
|
.infos {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: fit-content;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-evenly;
|
justify-content: start;
|
||||||
align-content: center;
|
align-content: center;
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#datestr {
|
#datestr {
|
||||||
@ -48,7 +48,7 @@
|
|||||||
border: 1px #444 solid;
|
border: 1px #444 solid;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
min-width: 100px;
|
min-width: 250px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-height: 20px;
|
min-height: 20px;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,17 @@ Object.defineProperty(String.prototype, "capitalize", {
|
|||||||
},
|
},
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const DatePrecisions = [
|
||||||
|
"year",
|
||||||
|
"month",
|
||||||
|
"day",
|
||||||
|
"hour",
|
||||||
|
"minute",
|
||||||
|
"second",
|
||||||
|
"millisecond",
|
||||||
|
];
|
||||||
|
|
||||||
// <<== Outils ==>>
|
// <<== Outils ==>>
|
||||||
Object.defineProperty(Array.prototype, "reversed", {
|
Object.defineProperty(Array.prototype, "reversed", {
|
||||||
value: function () {
|
value: function () {
|
||||||
@ -101,6 +112,7 @@ function validateSelectors(btn) {
|
|||||||
getAssiduitesFromEtuds(true);
|
getAssiduitesFromEtuds(true);
|
||||||
|
|
||||||
document.querySelector(".selectors").disabled = true;
|
document.querySelector(".selectors").disabled = true;
|
||||||
|
$("#tl_date").datepicker("option", "disabled", true);
|
||||||
generateMassAssiduites();
|
generateMassAssiduites();
|
||||||
generateAllEtudRow();
|
generateAllEtudRow();
|
||||||
btn.remove();
|
btn.remove();
|
||||||
@ -126,7 +138,7 @@ function validateSelectors(btn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onlyAbs() {
|
function onlyAbs() {
|
||||||
if (getDate() > moment()) {
|
if (getDate() > Date.now()) {
|
||||||
document
|
document
|
||||||
.querySelectorAll(".rbtn.present, .rbtn.retard")
|
.querySelectorAll(".rbtn.present, .rbtn.retard")
|
||||||
.forEach((el) => el.remove());
|
.forEach((el) => el.remove());
|
||||||
@ -162,6 +174,7 @@ function uniqueCheckBox(box) {
|
|||||||
* @param {CallableFunction} errors fonction à effectuer en cas d'échec
|
* @param {CallableFunction} errors fonction à effectuer en cas d'échec
|
||||||
*/
|
*/
|
||||||
function sync_get(path, success, errors) {
|
function sync_get(path, success, errors) {
|
||||||
|
//TODO Optimiser : rendre asynchrone + sans jquery
|
||||||
console.log("sync_get " + path);
|
console.log("sync_get " + path);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
async: false,
|
async: false,
|
||||||
@ -177,16 +190,22 @@ function sync_get(path, success, errors) {
|
|||||||
* @param {CallableFunction} success fonction à effectuer en cas de succès
|
* @param {CallableFunction} success fonction à effectuer en cas de succès
|
||||||
* @param {CallableFunction} errors fonction à effectuer en cas d'échec
|
* @param {CallableFunction} errors fonction à effectuer en cas d'échec
|
||||||
*/
|
*/
|
||||||
function async_get(path, success, errors) {
|
async function async_get(path, success, errors) {
|
||||||
console.log("async_get " + path);
|
console.log("async_get " + path);
|
||||||
$.ajax({
|
try {
|
||||||
async: true,
|
const response = await fetch(path);
|
||||||
type: "GET",
|
if (response.ok) {
|
||||||
url: path,
|
const data = await response.json();
|
||||||
success: success,
|
success(data);
|
||||||
error: errors,
|
} else {
|
||||||
});
|
throw new Error("Network response was not ok.");
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
if (errors) errors(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fait une requête POST de façon synchrone
|
* Fait une requête POST de façon synchrone
|
||||||
* @param {String} path adresse distante
|
* @param {String} path adresse distante
|
||||||
@ -195,6 +214,7 @@ function async_get(path, success, errors) {
|
|||||||
* @param {CallableFunction} errors fonction à effectuer en cas d'échec
|
* @param {CallableFunction} errors fonction à effectuer en cas d'échec
|
||||||
*/
|
*/
|
||||||
function sync_post(path, data, success, errors) {
|
function sync_post(path, data, success, errors) {
|
||||||
|
//TODO Optimiser : rendre asynchrone + sans jquery
|
||||||
console.log("sync_post " + path);
|
console.log("sync_post " + path);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
async: false,
|
async: false,
|
||||||
@ -212,17 +232,29 @@ function sync_post(path, data, success, errors) {
|
|||||||
* @param {CallableFunction} success fonction à effectuer en cas de succès
|
* @param {CallableFunction} success fonction à effectuer en cas de succès
|
||||||
* @param {CallableFunction} errors fonction à effectuer en cas d'échec
|
* @param {CallableFunction} errors fonction à effectuer en cas d'échec
|
||||||
*/
|
*/
|
||||||
function async_post(path, data, success, errors) {
|
async function async_post(path, data, success, errors) {
|
||||||
console.log("sync_post " + path);
|
console.log("async_post " + path);
|
||||||
return $.ajax({
|
try {
|
||||||
async: true,
|
const response = await fetch(path, {
|
||||||
type: "POST",
|
method: "POST",
|
||||||
url: path,
|
headers: {
|
||||||
data: JSON.stringify(data),
|
"Content-Type": "application/json",
|
||||||
success: success,
|
},
|
||||||
error: errors,
|
body: JSON.stringify(data),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const responseData = await response.json();
|
||||||
|
success(responseData);
|
||||||
|
} else {
|
||||||
|
throw new Error("Network response was not ok.");
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
if (errors) errors(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// <<== Gestion des actions de masse ==>>
|
// <<== Gestion des actions de masse ==>>
|
||||||
const massActionQueue = new Map();
|
const massActionQueue = new Map();
|
||||||
|
|
||||||
@ -268,8 +300,8 @@ function executeMassActionQueue() {
|
|||||||
*/
|
*/
|
||||||
const tlTimes = getTimeLineTimes();
|
const tlTimes = getTimeLineTimes();
|
||||||
let assiduite = {
|
let assiduite = {
|
||||||
date_debut: tlTimes.deb.format(),
|
date_debut: tlTimes.deb.toIsoUtcString(),
|
||||||
date_fin: tlTimes.fin.format(),
|
date_fin: tlTimes.fin.toIsoUtcString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assiduite = setModuleImplId(assiduite);
|
assiduite = setModuleImplId(assiduite);
|
||||||
@ -572,10 +604,13 @@ function formatDate(date, styles = { dateStyle: "full" }) {
|
|||||||
*/
|
*/
|
||||||
function updateDate() {
|
function updateDate() {
|
||||||
const dateInput = document.querySelector("#tl_date");
|
const dateInput = document.querySelector("#tl_date");
|
||||||
|
let date = $(dateInput).datepicker("getDate");
|
||||||
|
|
||||||
|
if (date == null) {
|
||||||
|
date = new Date(Date.fromFRA(dateInput.value));
|
||||||
|
}
|
||||||
|
|
||||||
const date = dateInput.valueAsDate ?? new Date();
|
|
||||||
let dateStr = "";
|
let dateStr = "";
|
||||||
|
|
||||||
if (!verifyNonWorkDays(date.getDay(), nonWorkDays)) {
|
if (!verifyNonWorkDays(date.getDay(), nonWorkDays)) {
|
||||||
dateStr = formatDate(date).capitalize();
|
dateStr = formatDate(date).capitalize();
|
||||||
} else {
|
} else {
|
||||||
@ -595,7 +630,11 @@ function updateDate() {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
openAlertModal("Attention", div, "", "#eec660");
|
openAlertModal("Attention", div, "", "#eec660");
|
||||||
dateInput.value = lastWorkDay.toISOString().split("T")[0];
|
$(dateInput).datepicker(
|
||||||
|
"setDate",
|
||||||
|
Date.toFRA(lastWorkDay.toIsoUtcString().split("T")[0])
|
||||||
|
);
|
||||||
|
|
||||||
dateStr = formatDate(lastWorkDay).capitalize();
|
dateStr = formatDate(lastWorkDay).capitalize();
|
||||||
}
|
}
|
||||||
document.querySelector("#datestr").textContent = dateStr;
|
document.querySelector("#datestr").textContent = dateStr;
|
||||||
@ -613,19 +652,10 @@ function getNearestWorkDay(date) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function verifyDateInSemester() {
|
function verifyDateInSemester() {
|
||||||
const date = new moment.tz(
|
const date = getDate();
|
||||||
document.querySelector("#tl_date").value,
|
|
||||||
TIMEZONE
|
|
||||||
);
|
|
||||||
|
|
||||||
const periodSemester = getFormSemestreDates();
|
const periodSemester = getFormSemestreDates();
|
||||||
|
return date.isBetween(periodSemester.deb, periodSemester.fin, "[]");
|
||||||
return date.isBetween(
|
|
||||||
periodSemester.deb,
|
|
||||||
periodSemester.fin,
|
|
||||||
undefined,
|
|
||||||
"[]"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -637,15 +667,15 @@ function setupDate(onchange = null) {
|
|||||||
const input = document.querySelector("#tl_date");
|
const input = document.querySelector("#tl_date");
|
||||||
|
|
||||||
datestr.addEventListener("click", () => {
|
datestr.addEventListener("click", () => {
|
||||||
if (!input.disabled) {
|
if (!document.querySelector(".selectors").disabled) {
|
||||||
try {
|
try {
|
||||||
input.showPicker();
|
document.querySelector(".infos .ui-datepicker-trigger").click();
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (onchange != null) {
|
if (onchange != null) {
|
||||||
input.addEventListener("change", onchange);
|
$(input).change(onchange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -664,8 +694,8 @@ function getAssiduitesOnDateChange() {
|
|||||||
* @param {String} separator le séparateur de la date intelligible (01/01/2000 {separtor} 10:00)
|
* @param {String} separator le séparateur de la date intelligible (01/01/2000 {separtor} 10:00)
|
||||||
* @returns {String} la date intelligible
|
* @returns {String} la date intelligible
|
||||||
*/
|
*/
|
||||||
function formatDateModal(str, separator = "·") {
|
function formatDateModal(str, separator = " ") {
|
||||||
return new moment.tz(str, TIMEZONE).format(`DD/MM/Y ${separator} HH:mm`);
|
return new Date(str).format("DD/MM/Y HH:mm").replace(" ", separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -705,8 +735,8 @@ function verifyNonWorkDays(day, nonWorkdays) {
|
|||||||
* Fonction qui vérifie si une période est dans un interval
|
* Fonction qui vérifie si une période est dans un interval
|
||||||
* Objet période / interval
|
* Objet période / interval
|
||||||
* {
|
* {
|
||||||
* deb: moment.tz(<Date>),
|
* deb: Date,
|
||||||
* fin: moment.tz(<Date>),
|
* fin: Date,
|
||||||
* }
|
* }
|
||||||
* @param {object} period
|
* @param {object} period
|
||||||
* @param {object} interval
|
* @param {object} interval
|
||||||
@ -718,19 +748,19 @@ function hasTimeConflict(period, interval) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* On récupère la période de la timeline
|
* On récupère la période de la timeline
|
||||||
* @returns {deb : moment.tz(), fin: moment.tz()}
|
* @returns {deb : Date, fin: Date)}
|
||||||
*/
|
*/
|
||||||
function getTimeLineTimes() {
|
function getTimeLineTimes() {
|
||||||
//getPeriodValues() -> retourne la position de la timeline [a,b] avec a et b des number
|
//getPeriodValues() -> retourne la position de la timeline [a,b] avec a et b des number
|
||||||
let values = getPeriodValues();
|
let values = getPeriodValues();
|
||||||
//On récupère la date
|
//On récupère la date
|
||||||
const dateiso = document.querySelector("#tl_date").value;
|
const dateiso = getDate().format("YYYY-MM-DD");
|
||||||
|
|
||||||
//On génère des objets temps (moment.tz)
|
//On génère des objets temps
|
||||||
values = values.map((el) => {
|
values = values.map((el) => {
|
||||||
el = toTime(el).replace("h", ":");
|
el = toTime(el).replace("h", ":");
|
||||||
el = `${dateiso}T${el}`;
|
el = `${dateiso}T${el}`;
|
||||||
return moment.tz(el, TIMEZONE);
|
return new Date(el);
|
||||||
});
|
});
|
||||||
|
|
||||||
return { deb: values[0], fin: values[1] };
|
return { deb: values[0], fin: values[1] };
|
||||||
@ -744,8 +774,8 @@ function getTimeLineTimes() {
|
|||||||
function isConflictSameAsPeriod(conflict, period = undefined) {
|
function isConflictSameAsPeriod(conflict, period = undefined) {
|
||||||
const tlTimes = period == undefined ? getTimeLineTimes() : period;
|
const tlTimes = period == undefined ? getTimeLineTimes() : period;
|
||||||
const clTimes = {
|
const clTimes = {
|
||||||
deb: moment.tz(conflict.date_debut, TIMEZONE),
|
deb: new Date(conflict.date_debut),
|
||||||
fin: moment.tz(conflict.date_fin, TIMEZONE),
|
fin: new Date(conflict.date_fin),
|
||||||
};
|
};
|
||||||
return tlTimes.deb.isSame(clTimes.deb) && tlTimes.fin.isSame(clTimes.fin);
|
return tlTimes.deb.isSame(clTimes.deb) && tlTimes.fin.isSame(clTimes.fin);
|
||||||
}
|
}
|
||||||
@ -755,9 +785,10 @@ function isConflictSameAsPeriod(conflict, period = undefined) {
|
|||||||
* @returns {Date} la date sélectionnée
|
* @returns {Date} la date sélectionnée
|
||||||
*/
|
*/
|
||||||
function getDate() {
|
function getDate() {
|
||||||
const date = new Date(document.querySelector("#tl_date").value);
|
const date =
|
||||||
date.setHours(0, 0, 0, 0);
|
$("#tl_date").datepicker("getDate") ??
|
||||||
return date;
|
new Date(Date.fromFRA(document.querySelector("#tl_date").value));
|
||||||
|
return date.startOf("day");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -766,10 +797,7 @@ function getDate() {
|
|||||||
*/
|
*/
|
||||||
function getNextDate() {
|
function getNextDate() {
|
||||||
const date = getDate();
|
const date = getDate();
|
||||||
const next = new Date(date.valueOf());
|
return date.clone().add(1, "days");
|
||||||
next.setDate(date.getDate() + 1);
|
|
||||||
next.setHours(0, 0, 0, 0);
|
|
||||||
return next;
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Retourne un objet date représentant le jour précédent
|
* Retourne un objet date représentant le jour précédent
|
||||||
@ -777,10 +805,7 @@ function getNextDate() {
|
|||||||
*/
|
*/
|
||||||
function getPrevDate() {
|
function getPrevDate() {
|
||||||
const date = getDate();
|
const date = getDate();
|
||||||
const next = new Date(date.valueOf());
|
return date.clone().add(-1, "days");
|
||||||
next.setDate(date.getDate() - 1);
|
|
||||||
next.setHours(0, 0, 0, 0);
|
|
||||||
return next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -788,44 +813,19 @@ function getPrevDate() {
|
|||||||
* @param {Date} date
|
* @param {Date} date
|
||||||
* @returns {string} la date iso avec le timezone
|
* @returns {string} la date iso avec le timezone
|
||||||
*/
|
*/
|
||||||
function toIsoString(date) {
|
|
||||||
var tzo = -date.getTimezoneOffset(),
|
|
||||||
dif = tzo >= 0 ? "+" : "-",
|
|
||||||
pad = function (num) {
|
|
||||||
return (num < 10 ? "0" : "") + num;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
date.getFullYear() +
|
|
||||||
"-" +
|
|
||||||
pad(date.getMonth() + 1) +
|
|
||||||
"-" +
|
|
||||||
pad(date.getDate()) +
|
|
||||||
"T" +
|
|
||||||
pad(date.getHours()) +
|
|
||||||
":" +
|
|
||||||
pad(date.getMinutes()) +
|
|
||||||
":" +
|
|
||||||
pad(date.getSeconds()) +
|
|
||||||
dif +
|
|
||||||
pad(Math.floor(Math.abs(tzo) / 60)) +
|
|
||||||
":" +
|
|
||||||
pad(Math.abs(tzo) % 60)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforme un temps numérique en une date moment.tz
|
* Transforme un temps numérique en une date
|
||||||
* @param {number} nb
|
* @param {number} nb
|
||||||
* @returns {moment.tz} Une date formée du temps donné et de la date courante
|
* @returns {Date} Une date formée du temps donné et de la date courante
|
||||||
*/
|
*/
|
||||||
function numberTimeToDate(nb) {
|
function numberTimeToDate(nb) {
|
||||||
time = toTime(nb).replace("h", ":");
|
time = toTime(nb).replace("h", ":");
|
||||||
date = document.querySelector("#tl_date").value;
|
date = getDate().format("YYYY-MM-DD");
|
||||||
|
|
||||||
datetime = `${date}T${time}`;
|
datetime = `${date}T${time}`;
|
||||||
|
|
||||||
return moment.tz(datetime, TIMEZONE);
|
return new Date(datetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// <<== Gestion des assiduités ==>>
|
// <<== Gestion des assiduités ==>>
|
||||||
@ -841,8 +841,8 @@ function numberTimeToDate(nb) {
|
|||||||
function getAssiduitesFromEtuds(clear, deb, fin) {
|
function getAssiduitesFromEtuds(clear, deb, fin) {
|
||||||
const etudIds = Object.keys(etuds).join(",");
|
const etudIds = Object.keys(etuds).join(",");
|
||||||
|
|
||||||
const date_debut = deb ? deb : toIsoString(getPrevDate());
|
const date_debut = deb ? deb : getPrevDate().toIsoUtcString();
|
||||||
const date_fin = fin ? fin : toIsoString(getNextDate());
|
const date_fin = fin ? fin : getNextDate().toIsoUtcString();
|
||||||
|
|
||||||
if (clear) {
|
if (clear) {
|
||||||
assiduites = {};
|
assiduites = {};
|
||||||
@ -885,8 +885,8 @@ function getAssiduitesFromEtuds(clear, deb, fin) {
|
|||||||
function createAssiduite(etat, etudid) {
|
function createAssiduite(etat, etudid) {
|
||||||
const tlTimes = getTimeLineTimes();
|
const tlTimes = getTimeLineTimes();
|
||||||
let assiduite = {
|
let assiduite = {
|
||||||
date_debut: tlTimes.deb.format(),
|
date_debut: tlTimes.deb.toIsoUtcString(),
|
||||||
date_fin: tlTimes.fin.format(),
|
date_fin: tlTimes.fin.toIsoUtcString(),
|
||||||
etat: etat,
|
etat: etat,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1067,10 +1067,11 @@ function getAssiduitesConflict(etudid, periode) {
|
|||||||
|
|
||||||
return etudAssiduites.filter((assi) => {
|
return etudAssiduites.filter((assi) => {
|
||||||
const interval = {
|
const interval = {
|
||||||
deb: moment.tz(assi.date_debut, TIMEZONE),
|
deb: new Date(assi.date_debut),
|
||||||
fin: moment.tz(assi.date_fin, TIMEZONE),
|
fin: new Date(assi.date_fin),
|
||||||
};
|
};
|
||||||
return hasTimeConflict(periode, interval);
|
const test = hasTimeConflict(periode, interval);
|
||||||
|
return test;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1085,21 +1086,21 @@ function getLastAssiduiteOfPrevDate(etudid) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const period = {
|
const period = {
|
||||||
deb: moment.tz(getPrevDate(), TIMEZONE),
|
deb: getPrevDate(),
|
||||||
fin: moment.tz(getDate(), TIMEZONE),
|
fin: getDate(),
|
||||||
};
|
};
|
||||||
const prevAssiduites = etudAssiduites
|
const prevAssiduites = etudAssiduites
|
||||||
.filter((assi) => {
|
.filter((assi) => {
|
||||||
const interval = {
|
const interval = {
|
||||||
deb: moment.tz(assi.date_debut, TIMEZONE),
|
deb: new Date(assi.date_debut),
|
||||||
fin: moment.tz(assi.date_fin, TIMEZONE),
|
fin: new Date(assi.date_fin),
|
||||||
};
|
};
|
||||||
|
|
||||||
return hasTimeConflict(period, interval);
|
return hasTimeConflict(period, interval);
|
||||||
})
|
})
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
const a_fin = moment.tz(a.date_fin, TIMEZONE);
|
const a_fin = new Date(a.date_fin);
|
||||||
const b_fin = moment.tz(b.date_fin, TIMEZONE);
|
const b_fin = new Date(b.date_fin);
|
||||||
return b_fin < a_fin;
|
return b_fin < a_fin;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1134,8 +1135,8 @@ function getAssiduiteValue(field) {
|
|||||||
* @param {String | Number} etudid identifiant de l'étudiant
|
* @param {String | Number} etudid identifiant de l'étudiant
|
||||||
*/
|
*/
|
||||||
function actualizeEtudAssiduite(etudid) {
|
function actualizeEtudAssiduite(etudid) {
|
||||||
const date_debut = toIsoString(getPrevDate());
|
const date_debut = getPrevDate().toIsoUtcString();
|
||||||
const date_fin = toIsoString(getNextDate());
|
const date_fin = getNextDate().toIsoUtcString();
|
||||||
|
|
||||||
const url_api =
|
const url_api =
|
||||||
getUrl() +
|
getUrl() +
|
||||||
@ -1163,7 +1164,7 @@ function getAllAssiduitesFromEtud(
|
|||||||
.replace("°", courant ? "&courant" : "")
|
.replace("°", courant ? "&courant" : "")
|
||||||
: ""
|
: ""
|
||||||
}`;
|
}`;
|
||||||
|
//TODO Utiliser async_get au lieu de jquery
|
||||||
$.ajax({
|
$.ajax({
|
||||||
async: true,
|
async: true,
|
||||||
type: "GET",
|
type: "GET",
|
||||||
@ -1232,8 +1233,8 @@ function assiduiteAction(element) {
|
|||||||
assiduites[etudid],
|
assiduites[etudid],
|
||||||
getTimeLineTimes(),
|
getTimeLineTimes(),
|
||||||
{
|
{
|
||||||
deb: new moment.tz(getDate(), TIMEZONE),
|
deb: getDate(),
|
||||||
fin: new moment.tz(getNextDate(), TIMEZONE),
|
fin: getNextDate(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const update = (assi) => {
|
const update = (assi) => {
|
||||||
@ -1377,7 +1378,6 @@ function insertEtudRow(etud, index, output = false) {
|
|||||||
date_fin: null,
|
date_fin: null,
|
||||||
prevAssiduites: prevAssiduite,
|
prevAssiduites: prevAssiduite,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (conflict.length > 0) {
|
if (conflict.length > 0) {
|
||||||
assiduite.etatAssiduite = conflict[0].etat;
|
assiduite.etatAssiduite = conflict[0].etat;
|
||||||
|
|
||||||
@ -1545,8 +1545,8 @@ function getFormSemestreDates() {
|
|||||||
const dateFin = document.getElementById("formsemestre_date_fin").textContent;
|
const dateFin = document.getElementById("formsemestre_date_fin").textContent;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
deb: dateDeb,
|
deb: new Date(dateDeb),
|
||||||
fin: dateFin,
|
fin: new Date(dateFin),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1613,8 +1613,10 @@ function getJustificatifFromPeriod(date, etudid, update) {
|
|||||||
url:
|
url:
|
||||||
getUrl() +
|
getUrl() +
|
||||||
`/api/justificatifs/${etudid}/query?date_debut=${date.deb
|
`/api/justificatifs/${etudid}/query?date_debut=${date.deb
|
||||||
.add(1, "s")
|
.add(1, "seconds")
|
||||||
.format()}&date_fin=${date.fin.subtract(1, "s").format()}`,
|
.toIsoUtcString()}&date_fin=${date.fin
|
||||||
|
.add(-1, "seconds")
|
||||||
|
.toIsoUtcString()}`,
|
||||||
success: (data) => {
|
success: (data) => {
|
||||||
update(data);
|
update(data);
|
||||||
},
|
},
|
||||||
@ -1646,8 +1648,8 @@ function fastJustify(assiduite) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const period = {
|
const period = {
|
||||||
deb: new moment.tz(assiduite.date_debut, TIMEZONE),
|
deb: new Date(assiduite.date_debut),
|
||||||
fin: new moment.tz(assiduite.date_fin, TIMEZONE),
|
fin: new Date(assiduite.date_fin),
|
||||||
};
|
};
|
||||||
const action = (justifs) => {
|
const action = (justifs) => {
|
||||||
//créer un nouveau justificatif
|
//créer un nouveau justificatif
|
||||||
@ -1660,8 +1662,8 @@ function fastJustify(assiduite) {
|
|||||||
//créer justificatif
|
//créer justificatif
|
||||||
|
|
||||||
const justif = {
|
const justif = {
|
||||||
date_debut: new moment.tz(assiduite.date_debut, TIMEZONE).format(),
|
date_debut: new Date(assiduite.date_debut).toIsoUtcString(),
|
||||||
date_fin: new moment.tz(assiduite.date_fin, TIMEZONE).format(),
|
date_fin: new Date(assiduite.date_fin).toIsoUtcString(),
|
||||||
raison: raison,
|
raison: raison,
|
||||||
etat: etat,
|
etat: etat,
|
||||||
};
|
};
|
||||||
@ -1744,6 +1746,8 @@ function getAllJustificatifsFromEtud(
|
|||||||
`/api/justificatifs/${etudid}${
|
`/api/justificatifs/${etudid}${
|
||||||
order ? "/query?order°".replace("°", courant ? "&courant" : "") : ""
|
order ? "/query?order°".replace("°", courant ? "&courant" : "") : ""
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
//TODO Utiliser async_get au lieu de jquery
|
||||||
$.ajax({
|
$.ajax({
|
||||||
async: true,
|
async: true,
|
||||||
type: "GET",
|
type: "GET",
|
||||||
|
565
app/static/js/date_utils.js
Normal file
565
app/static/js/date_utils.js
Normal file
@ -0,0 +1,565 @@
|
|||||||
|
/**
|
||||||
|
* Transforme une date du format français (DD/MM/YYYY) au format iso (YYYY-MM-DD)
|
||||||
|
* Exemple d'utilisation :
|
||||||
|
* new Date(Date.fromFRA("30/06/2024")) -> new Date("2024-06-30")
|
||||||
|
* @param {string} dateFra
|
||||||
|
* @returns {string} dateIso
|
||||||
|
*/
|
||||||
|
Date.fromFRA = function (dateFra) {
|
||||||
|
if (dateFra == "") return "";
|
||||||
|
// Expression régulière pour valider le format de date ISO (YYYY-MM-DD)
|
||||||
|
const regexDateFra = /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[0-2])\/\d{4}$/;
|
||||||
|
|
||||||
|
// Vérification du format de la date ISO
|
||||||
|
if (!regexDateFra.test(dateFra)) {
|
||||||
|
throw new Error(
|
||||||
|
`La date (format français) passée en paramètre [${dateFra}] n'est pas valide.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion du format français (DD/MM/YYYY) au format ISO (YYYY-MM-DD)
|
||||||
|
return `${dateFra.substring(6, 10)}-${dateFra.substring(
|
||||||
|
3,
|
||||||
|
5
|
||||||
|
)}-${dateFra.substring(0, 2)}`;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Transforme une date du format iso (YYYY-MM-DD) au format français (DD/MM/YYYY)
|
||||||
|
* Exemple d'utilisation :
|
||||||
|
* Date.toFRA("2024-06-30") -> "30/06/2024"
|
||||||
|
* @param {string} dateIso
|
||||||
|
* @returns {string} dateFra
|
||||||
|
*/
|
||||||
|
Date.toFRA = function (dateIso) {
|
||||||
|
if (dateIso == "") return "";
|
||||||
|
// Expression régulière pour valider le format de date ISO (YYYY-MM-DD)
|
||||||
|
const regexDateIso = /^\d{4}-(0\d|1[0-2])-([0-2]\d|3[01])$/;
|
||||||
|
|
||||||
|
// Vérification du format de la date ISO
|
||||||
|
if (!regexDateIso.test(dateIso)) {
|
||||||
|
throw new Error(
|
||||||
|
`La date ISO passée en paramètre [${dateIso}] n'est pas valide.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion du format ISO (YYYY-MM-DD) en format français (DD/MM/YYYY)
|
||||||
|
return `${dateIso.substring(8, 10)}/${dateIso.substring(
|
||||||
|
5,
|
||||||
|
7
|
||||||
|
)}/${dateIso.substring(0, 4)}`;
|
||||||
|
};
|
||||||
|
Object.defineProperty(Date.prototype, "isValid", {
|
||||||
|
value: function () {
|
||||||
|
return !Number.isNaN(this.getTime());
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Object.defineProperty(Date.prototype, "startOf", {
|
||||||
|
/**
|
||||||
|
* Génère u la date à la plus petite valeur pour la précision donnée.
|
||||||
|
* @param {string} precision - La précision souhaitée (year, month, day, hours, minutes, seconds, milliseconds).
|
||||||
|
* @returns {Date} - Une nouvelle date ajustée.
|
||||||
|
*/
|
||||||
|
value: function (precision) {
|
||||||
|
const newDate = this.clone();
|
||||||
|
switch (precision) {
|
||||||
|
case "year":
|
||||||
|
newDate.setMonth(0);
|
||||||
|
case "month":
|
||||||
|
newDate.setDate(1);
|
||||||
|
case "day":
|
||||||
|
newDate.setHours(0);
|
||||||
|
case "hours":
|
||||||
|
newDate.setMinutes(0);
|
||||||
|
case "minutes":
|
||||||
|
newDate.setSeconds(0);
|
||||||
|
case "seconds":
|
||||||
|
newDate.setMilliseconds(0);
|
||||||
|
break;
|
||||||
|
case "milliseconds":
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Invalid precision for startOf function [${precision}]`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return newDate;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Date.prototype, "endOf", {
|
||||||
|
/**
|
||||||
|
* Ajuste la date à la plus grande valeur pour la précision donnée.
|
||||||
|
* @param {string} precision - La précision souhaitée (year, month, day, hours, minutes, seconds, milliseconds).
|
||||||
|
* @returns {Date} - Une nouvelle date ajustée.
|
||||||
|
*/
|
||||||
|
value: function (precision) {
|
||||||
|
const newDate = this.clone();
|
||||||
|
switch (precision) {
|
||||||
|
case "year":
|
||||||
|
newDate.setMonth(11); // Décembre est le 11ème mois (0-indexé)
|
||||||
|
case "month":
|
||||||
|
newDate.setDate(0); // Le jour 0 du mois suivant est le dernier jour du mois courant
|
||||||
|
newDate.setMonth(newDate.getMonth() + 1);
|
||||||
|
case "day":
|
||||||
|
newDate.setHours(23); // 23 heures est la dernière heure de la journée
|
||||||
|
case "hours":
|
||||||
|
newDate.setMinutes(59); // 59 minutes est la dernière minute de l'heure
|
||||||
|
case "minutes":
|
||||||
|
newDate.setSeconds(59); // 59 secondes est la dernière seconde de la minute
|
||||||
|
case "seconds":
|
||||||
|
newDate.setMilliseconds(999); // 999 millisecondes est la dernière milliseconde de la seconde
|
||||||
|
break;
|
||||||
|
case "milliseconds":
|
||||||
|
// Rien à faire pour les millisecondes
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Invalid precision for endOf function");
|
||||||
|
}
|
||||||
|
return newDate;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Date.prototype, "isBefore", {
|
||||||
|
/**
|
||||||
|
* Retourne vrai si la date est située avant la date fournie
|
||||||
|
* @param {Date} date
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
value: function (date) {
|
||||||
|
return this.valueOf() < date.valueOf();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Object.defineProperty(Date.prototype, "isAfter", {
|
||||||
|
/**
|
||||||
|
* Retourne vrai si la date est située après la date fournie
|
||||||
|
* @param {Date} date
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
value: function (date) {
|
||||||
|
return this.valueOf() > date.valueOf();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Date.prototype, "isSame", {
|
||||||
|
/**
|
||||||
|
* Retourne vrai si les dates sont les mêmes
|
||||||
|
* @param {Date} date
|
||||||
|
* @param {string} precision default : "milliseconds"
|
||||||
|
* @returns boolean
|
||||||
|
*/
|
||||||
|
value: function (date, precision = "milliseconds") {
|
||||||
|
return (
|
||||||
|
this.startOf(precision).valueOf() == date.startOf(precision).valueOf()
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Date.prototype, "isBetween", {
|
||||||
|
/**
|
||||||
|
* Vérifie si la date est comprise dans une période avec une précision et une inclusivité optionnelles
|
||||||
|
* @param {Date} deb - La date de début de la période
|
||||||
|
* @param {Date} fin - La date de fin de la période
|
||||||
|
* @param {String} bornes - L'inclusivité/exclusivité de la comparaison ("[]", "()", "[)", "(]")
|
||||||
|
* - bornes incluses : []
|
||||||
|
* - bornes excluses : ()
|
||||||
|
* - borne gauche incluse et borne droit excluse : [)
|
||||||
|
* - borne gauche excluse et borne droit incluse : (]
|
||||||
|
*/
|
||||||
|
value: function (deb, fin, bornes = "[]") {
|
||||||
|
// Ajuste la date actuelle, la date de début et la date de fin à la précision spécifiée
|
||||||
|
|
||||||
|
// Vérifie les bornes en fonction de l'inclusivité/exclusivité spécifiée dans 'bornes'
|
||||||
|
const check_deb =
|
||||||
|
bornes[0] === "("
|
||||||
|
? this.valueOf() > deb.valueOf()
|
||||||
|
: this.valueOf() >= deb.valueOf();
|
||||||
|
const check_fin =
|
||||||
|
bornes[1] === ")"
|
||||||
|
? fin.valueOf() > this.valueOf()
|
||||||
|
: fin.valueOf() >= this.valueOf();
|
||||||
|
|
||||||
|
return check_deb && check_fin;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Date.prototype, "toIsoUtcString", {
|
||||||
|
/**
|
||||||
|
* @returns date au format iso utc (yyyy-mm-ddThh:MM±oo:oo:oo)
|
||||||
|
*/
|
||||||
|
value: function () {
|
||||||
|
const date = this;
|
||||||
|
var tzo = -date.getTimezoneOffset(),
|
||||||
|
dif = tzo >= 0 ? "+" : "-",
|
||||||
|
pad = function (num) {
|
||||||
|
return (num < 10 ? "0" : "") + num;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
date.getFullYear() +
|
||||||
|
"-" +
|
||||||
|
pad(date.getMonth() + 1) +
|
||||||
|
"-" +
|
||||||
|
pad(date.getDate()) +
|
||||||
|
"T" +
|
||||||
|
pad(date.getHours()) +
|
||||||
|
":" +
|
||||||
|
pad(date.getMinutes()) +
|
||||||
|
":" +
|
||||||
|
pad(date.getSeconds()) +
|
||||||
|
dif +
|
||||||
|
pad(Math.floor(Math.abs(tzo) / 60)) +
|
||||||
|
":" +
|
||||||
|
pad(Math.abs(tzo) % 60)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Date.prototype, "clone", {
|
||||||
|
/**
|
||||||
|
* @returns Retourne une copie de la date (copie non liée)
|
||||||
|
*/
|
||||||
|
value: function () {
|
||||||
|
return structuredClone(this);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Date.prototype, "format", {
|
||||||
|
value: function (formatString) {
|
||||||
|
let iso = this.toIsoUtcString();
|
||||||
|
switch (formatString) {
|
||||||
|
case "DD/MM/Y HH:mm":
|
||||||
|
return this.toLocaleString("fr-FR", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "2-digit",
|
||||||
|
year: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
hour12: false,
|
||||||
|
});
|
||||||
|
case "DD/MM/YYYY HH:mm":
|
||||||
|
return this.toLocaleString("fr-FR", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
hour12: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
case "YYYY-MM-DDTHH:mm":
|
||||||
|
// slice : YYYY-MM-DDTHH
|
||||||
|
// slice + 3 : YYYY-MM-DDTHH:mm
|
||||||
|
return iso.slice(0, iso.indexOf(":") + 3);
|
||||||
|
case "YYYY-MM-DD":
|
||||||
|
return iso.slice(0, iso.indexOf("T"));
|
||||||
|
default:
|
||||||
|
return this.toIsoUtcString();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Date.prototype, "add", {
|
||||||
|
/**
|
||||||
|
* Ajoute une valeur spécifiée à un élément de la date.
|
||||||
|
* @param {number} value - La valeur à ajouter.
|
||||||
|
* @param {string} type - Le type de la valeur (year, month, day, hours, minutes, seconds).
|
||||||
|
*/
|
||||||
|
value: function (value, type) {
|
||||||
|
switch (type) {
|
||||||
|
case "years":
|
||||||
|
this.setFullYear(this.getFullYear() + value);
|
||||||
|
break;
|
||||||
|
case "months":
|
||||||
|
this.setMonth(this.getMonth() + value);
|
||||||
|
break;
|
||||||
|
case "days":
|
||||||
|
this.setDate(this.getDate() + value);
|
||||||
|
break;
|
||||||
|
case "hours":
|
||||||
|
this.setHours(this.getHours() + value);
|
||||||
|
break;
|
||||||
|
case "minutes":
|
||||||
|
this.setMinutes(this.getMinutes() + value);
|
||||||
|
break;
|
||||||
|
case "seconds":
|
||||||
|
this.setSeconds(this.getSeconds() + value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Invalid type for adding to date | type : ${type} value : ${value}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this; // Return the modified date
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
class Duration {
|
||||||
|
/**
|
||||||
|
* Constructeur de la classe Duration.
|
||||||
|
* @param {Date} start - La date de début de la période.
|
||||||
|
* @param {Date} end - La date de fin de la période.
|
||||||
|
*/
|
||||||
|
constructor(start, end) {
|
||||||
|
this.start = start; // Stocke la date de début.
|
||||||
|
this.end = end; // Stocke la date de fin.
|
||||||
|
this.duration = end - start; // Calcule la durée en millisecondes entre les deux dates.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le nombre d'années entre les deux dates et arrondit le résultat à quatre décimales.
|
||||||
|
* @return {number} Le nombre d'années arrondi à quatre décimales.
|
||||||
|
*/
|
||||||
|
get years() {
|
||||||
|
const startYear = this.start.getFullYear(); // Obtient l'année de la date de début.
|
||||||
|
const endYear = this.end.getFullYear(); // Obtient l'année de la date de fin.
|
||||||
|
// Calcule la différence en années et arrondit à quatre décimales.
|
||||||
|
return parseFloat((endYear - startYear).toFixed(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le nombre de mois entre les deux dates, en tenant compte des années et des jours, et arrondit le résultat à quatre décimales.
|
||||||
|
* @return {number} Le nombre de mois arrondi à quatre décimales.
|
||||||
|
*/
|
||||||
|
get months() {
|
||||||
|
const years = this.years; // Nombre d'années complètes.
|
||||||
|
// Calcule la différence en mois, en ajoutant la différence en jours divisée par 30 pour une approximation.
|
||||||
|
const months =
|
||||||
|
years * 12 +
|
||||||
|
(this.end.getMonth() - this.start.getMonth()) +
|
||||||
|
(this.end.getDate() - this.start.getDate()) / 30;
|
||||||
|
// Arrondit à quatre décimales.
|
||||||
|
return parseFloat(months.toFixed(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le nombre de jours entre les deux dates et arrondit le résultat à quatre décimales.
|
||||||
|
* @return {number} Le nombre de jours arrondi à quatre décimales.
|
||||||
|
*/
|
||||||
|
get days() {
|
||||||
|
// Convertit la durée en millisecondes en jours et arrondit à quatre décimales.
|
||||||
|
return parseFloat((this.duration / (24 * 60 * 60 * 1000)).toFixed(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le nombre d'heures entre les deux dates et arrondit le résultat à quatre décimales.
|
||||||
|
* @return {number} Le nombre d'heures arrondi à quatre décimales.
|
||||||
|
*/
|
||||||
|
get hours() {
|
||||||
|
// Convertit la durée en millisecondes en heures et arrondit à quatre décimales.
|
||||||
|
return parseFloat((this.duration / (60 * 60 * 1000)).toFixed(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le nombre de minutes entre les deux dates et arrondit le résultat à quatre décimales.
|
||||||
|
* @return {number} Le nombre de minutes arrondi à quatre décimales.
|
||||||
|
*/
|
||||||
|
get minutes() {
|
||||||
|
// Convertit la durée en millisecondes en minutes et arrondit à quatre décimales.
|
||||||
|
return parseFloat((this.duration / (60 * 1000)).toFixed(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule le nombre de secondes entre les deux dates et arrondit le résultat à quatre décimales.
|
||||||
|
* @return {number} Le nombre de secondes arrondi à quatre décimales.
|
||||||
|
*/
|
||||||
|
get seconds() {
|
||||||
|
// Convertit la durée en millisecondes en secondes et arrondit à quatre décimales.
|
||||||
|
return parseFloat((this.duration / 1000).toFixed(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtient le nombre de millisecondes entre les deux dates et arrondit le résultat à quatre décimales.
|
||||||
|
* @return {number} Le nombre de millisecondes arrondi à quatre décimales.
|
||||||
|
*/
|
||||||
|
get milliseconds() {
|
||||||
|
// Arrondit la durée totale en millisecondes à quatre décimales.
|
||||||
|
return parseFloat(this.duration.toFixed(4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScoDocDateTimePicker extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
// Définir si le champ est requis
|
||||||
|
this.required = this.hasAttribute("required");
|
||||||
|
|
||||||
|
// Initialiser le shadow DOM
|
||||||
|
const shadow = this.attachShadow({ mode: "open" });
|
||||||
|
|
||||||
|
// Créer l'input pour la date
|
||||||
|
const dateInput = document.createElement("input");
|
||||||
|
dateInput.type = "date";
|
||||||
|
dateInput.id = "date";
|
||||||
|
|
||||||
|
// Créer l'input pour l'heure
|
||||||
|
const timeInput = document.createElement("input");
|
||||||
|
timeInput.type = "time";
|
||||||
|
timeInput.id = "time";
|
||||||
|
timeInput.step = 60;
|
||||||
|
|
||||||
|
// Ajouter les inputs dans le shadow DOM
|
||||||
|
shadow.appendChild(dateInput);
|
||||||
|
shadow.appendChild(timeInput);
|
||||||
|
|
||||||
|
// Gestionnaires d'événements pour la mise à jour de la valeur
|
||||||
|
dateInput.addEventListener("change", () => this.updateValue());
|
||||||
|
timeInput.addEventListener("change", () => this.updateValue());
|
||||||
|
|
||||||
|
// Style CSS pour les inputs
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.textContent = `
|
||||||
|
input {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
input:invalid {
|
||||||
|
border: 1px solid red;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Ajouter le style au shadow DOM
|
||||||
|
shadow.appendChild(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ["show"]; // Ajoute 'show' à la liste des attributs observés
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
// Récupérer l'attribut 'name'
|
||||||
|
this.name = this.getAttribute("name");
|
||||||
|
|
||||||
|
// Créer un input caché pour la valeur datetime
|
||||||
|
this.hiddenInput = document.createElement("input");
|
||||||
|
this.hiddenInput.type = "hidden";
|
||||||
|
this.hiddenInput.name = this.name;
|
||||||
|
this.appendChild(this.hiddenInput);
|
||||||
|
|
||||||
|
// Gérer la soumission du formulaire
|
||||||
|
this.closest("form")?.addEventListener("submit", (e) => {
|
||||||
|
if (!this.validate()) {
|
||||||
|
e.preventDefault(); // Empêcher la soumission si non valide
|
||||||
|
this.dispatchEvent(
|
||||||
|
new Event("invalid", { bubbles: true, cancelable: true })
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Mettre à jour la valeur de l'input caché avant la soumission
|
||||||
|
this.hiddenInput.value = this.isValid()
|
||||||
|
? this.valueAsDate.toIsoUtcString()
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.updateDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldValue, newValue) {
|
||||||
|
if (name === "show") {
|
||||||
|
this.updateDisplay(); // Met à jour l'affichage si l'attribut 'show' change
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplay() {
|
||||||
|
const mode = this.getAttribute("show") || "both";
|
||||||
|
const dateInput = this.shadowRoot.querySelector("#date");
|
||||||
|
const timeInput = this.shadowRoot.querySelector("#time");
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case "date":
|
||||||
|
dateInput.style.display = "inline-block";
|
||||||
|
timeInput.style.display = "none";
|
||||||
|
break;
|
||||||
|
case "time":
|
||||||
|
dateInput.style.display = "none";
|
||||||
|
timeInput.style.display = "inline-block";
|
||||||
|
break;
|
||||||
|
case "both":
|
||||||
|
default:
|
||||||
|
dateInput.style.display = "inline-block";
|
||||||
|
timeInput.style.display = "inline-block";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier si la valeur forme une date valide
|
||||||
|
isValid() {
|
||||||
|
return !Number.isNaN(this.valueAsDate.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valider l'élément
|
||||||
|
validate() {
|
||||||
|
if (this.required && !this.isValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mettre à jour la valeur interne
|
||||||
|
updateValue() {
|
||||||
|
const dateInput = this.shadowRoot.querySelector("#date");
|
||||||
|
const timeInput = this.shadowRoot.querySelector("#time");
|
||||||
|
this._value = `${dateInput.value}T${timeInput.value}`;
|
||||||
|
this.dispatchEvent(new Event("change", { bubbles: true }));
|
||||||
|
|
||||||
|
// Appliquer le style 'invalid' si nécessaire
|
||||||
|
dateInput.classList.toggle("invalid", this.required && !this.isValid());
|
||||||
|
timeInput.classList.toggle("invalid", this.required && !this.isValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter pour obtenir la valeur actuelle.
|
||||||
|
get value() {
|
||||||
|
return this._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get valueAsObject() {
|
||||||
|
const dateInput = this.shadowRoot.querySelector("#date");
|
||||||
|
const timeInput = this.shadowRoot.querySelector("#time");
|
||||||
|
return {
|
||||||
|
date: dateInput.value,
|
||||||
|
time: timeInput.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter pour obtenir la valeur en tant qu'objet Date.
|
||||||
|
get valueAsDate() {
|
||||||
|
return new Date(this._value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setter pour définir la valeur. Sépare la valeur en date et heure et les définit individuellement.
|
||||||
|
set value(val) {
|
||||||
|
let [date, time] = val.split("T");
|
||||||
|
this.shadowRoot.querySelector("#date").value = date;
|
||||||
|
|
||||||
|
time = time.substring(0, 5);
|
||||||
|
|
||||||
|
this.shadowRoot.querySelector("#time").value = time;
|
||||||
|
this._value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setter pour définir la valeur à partir d'un objet avec les propriétés 'date' et 'time'.
|
||||||
|
set valueAsObject(obj) {
|
||||||
|
const dateInput = this.shadowRoot.querySelector("#date");
|
||||||
|
const timeInput = this.shadowRoot.querySelector("#time");
|
||||||
|
|
||||||
|
if (obj.hasOwnProperty("date")) {
|
||||||
|
dateInput.value = obj.date || ""; // Définit la valeur de l'input de date si elle est fournie
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.hasOwnProperty("time")) {
|
||||||
|
timeInput.value = obj.time.substring(0, 5) || ""; // Définit la valeur de l'input d'heure si elle est fournie
|
||||||
|
}
|
||||||
|
|
||||||
|
// Met à jour la valeur interne en fonction des nouvelles valeurs des inputs
|
||||||
|
this.updateValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setter pour définir la valeur à partir d'un objet Date.
|
||||||
|
set valueAsDate(dateVal) {
|
||||||
|
// Formatage de l'objet Date en string et mise à jour de la valeur.
|
||||||
|
this.value = `${dateVal.getFullYear()}-${String(
|
||||||
|
dateVal.getMonth() + 1
|
||||||
|
).padStart(2, "0")}-${String(dateVal.getDate()).padStart(2, "0")}T${String(
|
||||||
|
dateVal.getHours()
|
||||||
|
).padStart(2, "0")}:${String(dateVal.getMinutes()).padStart(2, "0")}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Définition du nouvel élément personnalisé 'scodoc-datetime'.
|
||||||
|
customElements.define("scodoc-datetime", ScoDocDateTimePicker);
|
2
app/static/libjs/moment-2.29.4.min.js
vendored
2
app/static/libjs/moment-2.29.4.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -11,19 +11,15 @@
|
|||||||
<section class="justi-form page">
|
<section class="justi-form page">
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<div class="justi-row">
|
|
||||||
<button onclick="validerFormulaire(this)">Créer le justificatif</button>
|
|
||||||
<button onclick="effacerFormulaire()">Remettre à zero</button>
|
|
||||||
</div>
|
|
||||||
<div class="justi-row">
|
<div class="justi-row">
|
||||||
<div class="justi-label">
|
<div class="justi-label">
|
||||||
<legend for="justi_date_debut" required>Date de début</legend>
|
<legend for="justi_date_debut" required>Date de début</legend>
|
||||||
<input type="datetime-local" name="justi_date_debut" id="justi_date_debut">
|
<scodoc-datetime name="justi_date_debut" id="justi_date_debut"> </scodoc-datetime>
|
||||||
<span>Journée(s) entière(s)</span> <input type="checkbox" name="justi_journee" id="justi_journee">
|
<span>Journée entière</span> <input type="checkbox" name="justi_journee" id="justi_journee">
|
||||||
</div>
|
</div>
|
||||||
<div class="justi-label" id="date_fin">
|
<div class="justi-label" id="date_fin">
|
||||||
<legend for="justi_date_fin" required>Date de fin</legend>
|
<legend for="justi_date_fin" required>Date de fin</legend>
|
||||||
<input type="datetime-local" name="justi_date_fin" id="justi_date_fin">
|
<scodoc-datetime name="justi_date_fin" id="justi_date_fin"></scodoc-datetime>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -55,6 +51,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="justi-row">
|
||||||
|
<button onclick="validerFormulaire(this)">Créer le justificatif</button>
|
||||||
|
<button onclick="effacerFormulaire()">Remettre à zero</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@ -112,15 +112,14 @@
|
|||||||
function validateFields() {
|
function validateFields() {
|
||||||
const field = document.querySelector('.justi-form')
|
const field = document.querySelector('.justi-form')
|
||||||
const { deb, fin } = getDates()
|
const { deb, fin } = getDates()
|
||||||
|
const date_debut = new Date(deb);
|
||||||
|
const date_fin = new Date(fin);
|
||||||
|
|
||||||
if (deb == "" || fin == "") {
|
if (deb == "" || fin == "" || !date_debut.isValid() || !date_fin.isValid()) {
|
||||||
openAlertModal("Erreur détéctée", document.createTextNode("Il faut indiquer une date de début et une date de fin valide."), "", color = "crimson");
|
openAlertModal("Erreur détéctée", document.createTextNode("Il faut indiquer une date de début et une date de fin valide."), "", color = "crimson");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const date_debut = moment.tz(deb, TIMEZONE);
|
|
||||||
const date_fin = moment.tz(fin, TIMEZONE);
|
|
||||||
|
|
||||||
if (date_fin.isBefore(date_debut)) {
|
if (date_fin.isBefore(date_debut)) {
|
||||||
openAlertModal("Erreur détéctée", document.createTextNode("La date de fin doit se trouver après la date de début."), "", color = "crimson");
|
openAlertModal("Erreur détéctée", document.createTextNode("La date de fin doit se trouver après la date de début."), "", color = "crimson");
|
||||||
return false;
|
return false;
|
||||||
@ -138,8 +137,8 @@
|
|||||||
const raison = field.querySelector('#justi_raison').value;
|
const raison = field.querySelector('#justi_raison').value;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
date_debut: moment.tz(deb, TIMEZONE).format(),
|
date_debut: new Date(deb).toIsoUtcString(),
|
||||||
date_fin: moment.tz(fin, TIMEZONE).format(),
|
date_fin: new Date(fin).toIsoUtcString(),
|
||||||
etat: etat,
|
etat: etat,
|
||||||
raison: raison,
|
raison: raison,
|
||||||
}
|
}
|
||||||
@ -219,39 +218,31 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dayOnly() {
|
function dayOnly() {
|
||||||
const { deb, fin } = getDates();
|
const date_deb = document.getElementById("justi_date_debut");
|
||||||
|
const date_fin = document.getElementById("justi_date_fin");
|
||||||
|
|
||||||
if (document.getElementById('justi_journee').checked) {
|
if (document.getElementById('justi_journee').checked) {
|
||||||
document.getElementById("justi_date_debut").type = "date"
|
date_deb.setAttribute("show", "date")
|
||||||
document.getElementById("justi_date_debut").value = deb.slice(0, deb.indexOf('T'))
|
date_fin.setAttribute("show", "date")
|
||||||
|
document.getElementById("date_fin").classList.add("hidden");
|
||||||
document.getElementById("justi_date_fin").type = "date"
|
|
||||||
document.getElementById("justi_date_fin").value = fin.slice(0, fin.indexOf('T'))
|
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("justi_date_debut").type = "datetime-local"
|
date_deb.removeAttribute("show")
|
||||||
document.getElementById("justi_date_debut").value = `${deb}T${assi_morning}`
|
date_fin.removeAttribute("show")
|
||||||
|
document.getElementById("date_fin").classList.remove("hidden");
|
||||||
|
|
||||||
document.getElementById("justi_date_fin").type = "datetime-local"
|
|
||||||
document.getElementById("justi_date_fin").value = `${fin}T${assi_evening}`
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDates() {
|
function getDates() {
|
||||||
if (document.querySelector('.page #justi_journee').checked) {
|
const date_deb = document.querySelector(".page #justi_date_debut")
|
||||||
const date_str_deb = document.querySelector(".page #justi_date_debut").value
|
const date_fin = document.querySelector(".page #justi_date_fin")
|
||||||
const date_str_fin = document.querySelector(".page #justi_date_fin").value
|
const journee = document.querySelector('.page #justi_journee').checked
|
||||||
|
const deb = date_deb.valueAsObject.date + "T" + (journee ? assi_morning : date_deb.valueAsObject.time)
|
||||||
|
const fin = (journee ? date_deb.valueAsObject.date : date_fin.valueAsObject.date) + "T" + (journee ? assi_evening : date_fin.valueAsObject.time)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"deb": date_str_deb ? `${date_str_deb}T${assi_morning}` : "",
|
"deb": deb,
|
||||||
"fin": date_str_fin ? `${date_str_fin}T${assi_evening}` : "",
|
"fin": fin,
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
"deb": document.querySelector(".page #justi_date_debut").value,
|
|
||||||
"fin": document.querySelector(".page #justi_date_fin").value,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,6 +256,9 @@
|
|||||||
loadAll();
|
loadAll();
|
||||||
document.getElementById('justi_journee').addEventListener('click', () => { dayOnly() });
|
document.getElementById('justi_journee').addEventListener('click', () => { dayOnly() });
|
||||||
dayOnly()
|
dayOnly()
|
||||||
|
|
||||||
|
document.getElementById("justi_date_debut").valueAsObject = { time: assi_morning }
|
||||||
|
document.getElementById("justi_date_fin").valueAsObject = { time: assi_evening }
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock pageContent %}
|
{% endblock pageContent %}
|
@ -12,10 +12,10 @@
|
|||||||
<!-- Statistiques d'assiduité (nb pres, nb retard, nb absence) + nb justifié -->
|
<!-- Statistiques d'assiduité (nb pres, nb retard, nb absence) + nb justifié -->
|
||||||
<h4>Statistiques d'assiduité</h4>
|
<h4>Statistiques d'assiduité</h4>
|
||||||
<div class="stats-inputs">
|
<div class="stats-inputs">
|
||||||
<label class="stats-label"> Date de début<input type="date" name="stats_date_debut" id="stats_date_debut"
|
<label class="stats-label"> Date de début<input type="text" class="datepicker" name="stats_date_debut"
|
||||||
value="{{date_debut}}"></label>
|
id="stats_date_debut" value="{{date_debut}}"></label>
|
||||||
<label class="stats-label"> Date de fin<input type="date" name="stats_date_fin" id="stats_date_fin"
|
<label class="stats-label"> Date de fin<input type="text" class="datepicker" name="stats_date_fin"
|
||||||
value="{{date_fin}}"></label>
|
id="stats_date_fin" value="{{date_fin}}"></label>
|
||||||
<button onclick="stats()">Actualiser</button>
|
<button onclick="stats()">Actualiser</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -87,27 +87,27 @@
|
|||||||
function stats() {
|
function stats() {
|
||||||
const dd_val = document.getElementById('stats_date_debut').value;
|
const dd_val = document.getElementById('stats_date_debut').value;
|
||||||
const df_val = document.getElementById('stats_date_fin').value;
|
const df_val = document.getElementById('stats_date_fin').value;
|
||||||
|
let date_debut = new Date(Date.fromFRA(dd_val));
|
||||||
if (dd_val == "" || df_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'));
|
openAlertModal("Dates invalides", document.createTextNode('Les dates sélectionnées sont invalides'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const date_debut = new moment.tz(dd_val + "T00:00", TIMEZONE);
|
date_debut = date_debut.startOf("day")
|
||||||
const date_fin = new moment.tz(df_val + "T23:59", TIMEZONE);
|
date_fin = date_fin.endOf("day")
|
||||||
|
|
||||||
if (date_debut.valueOf() > date_fin.valueOf()) {
|
if (date_debut.isAfter(date_fin)) {
|
||||||
openAlertModal("Dates invalides", document.createTextNode('La date de début se situe après la date de fin.'));
|
openAlertModal("Dates invalides", document.createTextNode('La date de début se situe après la date de fin.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
countAssiduites(date_debut.toIsoUtcString(), date_fin.toIsoUtcString())
|
||||||
|
|
||||||
countAssiduites(date_debut.format(), date_fin.format())
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAssiduitesCount(dateDeb, dateFin, query) {
|
function getAssiduitesCount(dateDeb, dateFin, query) {
|
||||||
const url_api = getUrl() + `/api/assiduites/${etudid}/count/query?date_debut=${dateDeb}&date_fin=${dateFin}&${query}`;
|
const url_api = getUrl() + `/api/assiduites/${etudid}/count/query?date_debut=${dateDeb}&date_fin=${dateFin}&${query}`;
|
||||||
|
//Utiliser async_get au lieu de Jquery
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
async: true,
|
async: true,
|
||||||
type: "GET",
|
type: "GET",
|
||||||
@ -121,6 +121,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function countAssiduites(dateDeb, dateFin) {
|
function countAssiduites(dateDeb, dateFin) {
|
||||||
|
//TODO Utiliser Fetch when plutot que jquery
|
||||||
$.when(
|
$.when(
|
||||||
getAssiduitesCount(dateDeb, dateFin, `etat=present`),
|
getAssiduitesCount(dateDeb, dateFin, `etat=present`),
|
||||||
getAssiduitesCount(dateDeb, dateFin, `etat=retard`),
|
getAssiduitesCount(dateDeb, dateFin, `etat=retard`),
|
||||||
|
@ -4,13 +4,23 @@
|
|||||||
<div class="pageContent">
|
<div class="pageContent">
|
||||||
{{minitimeline | safe }}
|
{{minitimeline | safe }}
|
||||||
<h2>Assiduité de {{sco.etud.nomprenom}}</h2>
|
<h2>Assiduité de {{sco.etud.nomprenom}}</h2>
|
||||||
|
|
||||||
|
<div class="options">
|
||||||
|
<label for="show_pres">afficher les présences</label><input type="checkbox" id="show_pres" name="show_pres">
|
||||||
|
<label for="show_reta">afficher les retards</label><input type="checkbox" name="show_reta" id="show_reta">
|
||||||
|
<label for="mode_demi">mode demi journée</label><input type="checkbox" name="mode_demi" id="mode_demi">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="calendrier">
|
<div class="calendrier">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="annee">
|
<div class="annee">
|
||||||
<span>Année scolaire 2022-2023 Changer année: </span>
|
<span id="label-annee">Année scolaire 2022-2023</span><span id="label-changer" style="margin-left: 5px;">Changer
|
||||||
|
année: </span>
|
||||||
<select name="" id="annee" onchange="setterAnnee(this.value)">
|
<select name="" id="annee" onchange="setterAnnee(this.value)">
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<span id="label-nom">Assiduité de {{sco.etud.nomprenom}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="help">
|
<div class="help">
|
||||||
@ -34,7 +44,37 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
:root {
|
||||||
|
--color-present: #6bdb83;
|
||||||
|
--color-absent: #F1A69C;
|
||||||
|
--color-retard: #f0c865;
|
||||||
|
--color-nonwork: #bd81ca;
|
||||||
|
--color-defaut: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.present {
|
||||||
|
background-color: var(--color-present);
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.absent {
|
||||||
|
background-color: var(--color-absent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.retard {
|
||||||
|
background-color: var(--color-retard);
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.nonwork {
|
||||||
|
background-color: var(--color-nonwork);
|
||||||
|
}
|
||||||
|
|
||||||
|
.color {
|
||||||
|
background-color: var(--color-defaut);
|
||||||
|
}
|
||||||
|
|
||||||
.pageContent {
|
.pageContent {
|
||||||
margin-top: 1vh;
|
margin-top: 1vh;
|
||||||
max-width: var(--sco-content-max-width);
|
max-width: var(--sco-content-max-width);
|
||||||
@ -47,27 +87,36 @@
|
|||||||
border: 1px solid #444;
|
border: 1px solid #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
.month h2 {
|
.month h3 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.day {
|
.day,
|
||||||
border: 1px solid #444;
|
.demi .day.color.color.nonwork {
|
||||||
border-radius: 8px;
|
/* border: 1px solid #444; */
|
||||||
padding: 0 5px;
|
/* border-radius: 8px; */
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
font-weight: bold;
|
||||||
|
min-width: 6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.day.est_just {
|
.demi .day {
|
||||||
border-left: 10px solid #7059FF;
|
border-radius: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.day.est_just.invalide {
|
.day.est_just,
|
||||||
border-left: 10px solid #f64e4e;
|
.demi .day span.est_just {
|
||||||
|
background-image: repeating-linear-gradient(135deg, transparent, transparent 4px, #7059FFA0 4px, #7059FFA0 8px);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.day.est_just.invalide,
|
||||||
|
.demi .day span.invalide {
|
||||||
|
background-image: repeating-linear-gradient(-135deg, transparent, transparent 4px, #d61616A0 4px, #d61616A0 8px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.day .dayline {
|
.day .dayline {
|
||||||
@ -107,14 +156,96 @@
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
transform: translateX(200%);
|
transform: translateX(200%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#label-nom {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demi .day {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demi .day>span {
|
||||||
|
display: block;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid black;
|
||||||
|
/*border-radius: 3px;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.demi .day>span:first-of-type {
|
||||||
|
width: 3em;
|
||||||
|
min-width: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options>* {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
.color.present {
|
||||||
|
background-color: var(--color-present) !important;
|
||||||
|
print-color-adjust: exact !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.absent {
|
||||||
|
background-color: var(--color-absent) !important;
|
||||||
|
print-color-adjust: exact !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.retard {
|
||||||
|
background-color: var(--color-retard) !important;
|
||||||
|
print-color-adjust: exact !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.nonwork {
|
||||||
|
background-color: var(--color-nonwork) !important;
|
||||||
|
print-color-adjust: exact !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.day.est_just,
|
||||||
|
.demi .day span.est_just {
|
||||||
|
background-image: repeating-linear-gradient(135deg, transparent, transparent 4px, #7059FFA0 4px, #7059FFA0 8px) !important;
|
||||||
|
print-color-adjust: exact !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.day.est_just.invalide,
|
||||||
|
.demi .day span.invalide {
|
||||||
|
print-color-adjust: exact !important;
|
||||||
|
background-image: repeating-linear-gradient(-135deg, transparent, transparent 4px, #d61616A0 4px, #d61616A0 8px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#sidebar,
|
||||||
|
.help,
|
||||||
|
h2,
|
||||||
|
#annee,
|
||||||
|
#label-changer,
|
||||||
|
.options {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#label-nom {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#gtrcontent {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function getDaysBetweenDates(start, end) {
|
function getDaysBetweenDates(start, end) {
|
||||||
let now = moment(start);
|
let now = new Date(start);
|
||||||
|
end = new Date(end);
|
||||||
let dates = [];
|
let dates = [];
|
||||||
|
|
||||||
while (now.isSameOrBefore(end)) {
|
while (now.isBefore(end) || now.isSame(end)) {
|
||||||
dates.push(now.clone());
|
dates.push(now.clone());
|
||||||
now.add(1, "days");
|
now.add(1, "days");
|
||||||
}
|
}
|
||||||
@ -126,7 +257,7 @@
|
|||||||
let datesByMonth = {};
|
let datesByMonth = {};
|
||||||
|
|
||||||
dates.forEach((date) => {
|
dates.forEach((date) => {
|
||||||
let month = date.format("MMMM"); // Obtenir le mois
|
let month = date.toLocaleString('fr-FR', { month: "short" }); // Obtenir le mois
|
||||||
|
|
||||||
if (!datesByMonth[month]) {
|
if (!datesByMonth[month]) {
|
||||||
datesByMonth[month] = [];
|
datesByMonth[month] = [];
|
||||||
@ -146,24 +277,22 @@
|
|||||||
|
|
||||||
datesByMonth[month].forEach((date) => {
|
datesByMonth[month].forEach((date) => {
|
||||||
let dayAssiduities = assiduities.filter((assiduity) => {
|
let dayAssiduities = assiduities.filter((assiduity) => {
|
||||||
return moment.tz(date, TIMEZONE).isBetween(
|
return new Date(date).isBetween(
|
||||||
moment.tz(assiduity.date_debut, TIMEZONE),
|
new Date(assiduity.date_debut).startOf("day"),
|
||||||
moment.tz(assiduity.date_fin, TIMEZONE),
|
new Date(assiduity.date_fin).startOf("day"),
|
||||||
"day",
|
|
||||||
"[]"
|
"[]"
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let dayJustificatifs = justificatifs.filter((justif) => {
|
let dayJustificatifs = justificatifs.filter((justif) => {
|
||||||
return moment.tz(date, TIMEZONE).isBetween(
|
return new Date(date).isBetween(
|
||||||
moment.tz(justif.date_debut, TIMEZONE),
|
new Date(justif.date_debut).startOf("day"),
|
||||||
moment.tz(justif.date_fin, TIMEZONE),
|
new Date(justif.date_fin).startOf("day"),
|
||||||
"day",
|
|
||||||
"[]"
|
"[]"
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
assiduitiesByDay[month][date.format("YYYY-MM-DD")] = {
|
assiduitiesByDay[month][date.toLocaleDateString("en-US")] = {
|
||||||
assiduites: dayAssiduities,
|
assiduites: dayAssiduities,
|
||||||
justificatifs: dayJustificatifs
|
justificatifs: dayJustificatifs
|
||||||
};
|
};
|
||||||
@ -177,7 +306,7 @@
|
|||||||
let color;
|
let color;
|
||||||
switch (etat.toUpperCase()) {
|
switch (etat.toUpperCase()) {
|
||||||
case "PRESENT":
|
case "PRESENT":
|
||||||
color = "#6bdb83";
|
color = "";
|
||||||
break;
|
break;
|
||||||
case "ABSENT":
|
case "ABSENT":
|
||||||
color = "#F1A69C";
|
color = "#F1A69C";
|
||||||
@ -197,73 +326,154 @@
|
|||||||
|
|
||||||
function generateCalendar(assiduitiesByDay, nonWorkdays = []) {
|
function generateCalendar(assiduitiesByDay, nonWorkdays = []) {
|
||||||
const calendar = document.querySelector('.calendrier')
|
const calendar = document.querySelector('.calendrier')
|
||||||
|
const options = getOptions();
|
||||||
calendar.innerHTML = ""
|
calendar.innerHTML = ""
|
||||||
|
|
||||||
const days = {
|
const days = {
|
||||||
Mon: "Lun",
|
1: "Lun",
|
||||||
Tue: "Mar",
|
2: "Mar",
|
||||||
Wed: "Mer",
|
3: "Mer",
|
||||||
Thu: "Jeu",
|
4: "Jeu",
|
||||||
Fri: "Ven",
|
5: "Ven",
|
||||||
Sat: "Sam",
|
6: "Sam",
|
||||||
Sun: "Dim",
|
0: "Dim",
|
||||||
};
|
|
||||||
|
|
||||||
const months = {
|
|
||||||
January: "Jan.",
|
|
||||||
February: "Fev.",
|
|
||||||
March: "Mar.",
|
|
||||||
April: "Avr.",
|
|
||||||
May: "Mai",
|
|
||||||
June: "Juin",
|
|
||||||
July: "Juil.",
|
|
||||||
August: "Août",
|
|
||||||
September: "Sep.",
|
|
||||||
October: "Oct.",
|
|
||||||
November: "Nov.",
|
|
||||||
December: "Déc.",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(assiduitiesByDay).forEach((month) => {
|
Object.keys(assiduitiesByDay).forEach((month) => {
|
||||||
const monthEl = document.createElement('div')
|
const monthEl = document.createElement('div')
|
||||||
monthEl.classList.add("month")
|
monthEl.classList.add("month")
|
||||||
const title = document.createElement('h2');
|
const title = document.createElement('h3');
|
||||||
title.textContent = `${months[month]}`;
|
title.textContent = `${month.capitalize()}`;
|
||||||
monthEl.appendChild(title)
|
monthEl.appendChild(title)
|
||||||
|
|
||||||
const daysEl = document.createElement('div')
|
const daysEl = document.createElement('div')
|
||||||
daysEl.classList.add('days');
|
daysEl.classList.add('days');
|
||||||
|
if (options.mode_demi) daysEl.classList.add("demi");
|
||||||
Object.keys(assiduitiesByDay[month]).forEach((date) => {
|
Object.keys(assiduitiesByDay[month]).forEach((date) => {
|
||||||
let dayAssiduities = assiduitiesByDay[month][date].assiduites;
|
let dayAssiduities = assiduitiesByDay[month][date].assiduites;
|
||||||
let dayJustificatifs = assiduitiesByDay[month][date].justificatifs;
|
let dayJustificatifs = assiduitiesByDay[month][date].justificatifs;
|
||||||
let color = "white";
|
let color = "";
|
||||||
|
|
||||||
if (dayAssiduities.some((a) => a.etat.toLowerCase() === "absent")) color = "absent";
|
if (dayAssiduities.some((a) => a.etat.toLowerCase() === "absent")) color = "absent";
|
||||||
else if (dayAssiduities.some((a) => a.etat.toLowerCase() === "retard"))
|
else if (dayAssiduities.some((a) => a.etat.toLowerCase() === "retard") && options.show_reta)
|
||||||
color = "retard";
|
color = "retard";
|
||||||
else if (dayAssiduities.some((a) => a.etat.toLowerCase() === "present"))
|
else if (dayAssiduities.some((a) => a.etat.toLowerCase() === "present") && options.show_pres)
|
||||||
color = "present";
|
color = "present";
|
||||||
|
|
||||||
|
|
||||||
let est_just = ""
|
let est_just = ""
|
||||||
if (dayJustificatifs.some((j) => j.etat.toLowerCase() === "valide")) {
|
if (dayJustificatifs.some((j) => j.etat.toLowerCase() === "valide")) {
|
||||||
est_just = "est_just";
|
est_just = "est_just";
|
||||||
} else if (dayJustificatifs.some((j) => j.etat.toLowerCase() !== "valide")) {
|
} else if (dayJustificatifs.some((j) => j.etat.toLowerCase() !== "valide")) {
|
||||||
est_just = "est_just invalide";
|
est_just = "est_just invalide";
|
||||||
}
|
}
|
||||||
const momentDate = moment.tz(date, TIMEZONE);
|
const momentDate = new Date(date);
|
||||||
let dayOfMonth = momentDate.format("D");
|
let dayOfMonth = momentDate.getDate();
|
||||||
let dayOfWeek = momentDate.format("ddd");
|
let dayOfWeek = momentDate.getDay();
|
||||||
|
|
||||||
dayOfWeek = days[dayOfWeek];
|
dayOfWeek = days[dayOfWeek];
|
||||||
|
|
||||||
if (nonWorkdays.includes(dayOfWeek.toLowerCase())) color = "nonwork";
|
let isWorkDay = nonWorkdays.includes(dayOfWeek.toLowerCase());
|
||||||
|
|
||||||
const day = document.createElement('div');
|
const day = document.createElement('div');
|
||||||
day.className = `day ${est_just}`
|
day.className = `day`;
|
||||||
|
if (isWorkDay) {
|
||||||
|
color = "nonwork";
|
||||||
|
} else if (!options.mode_demi) {
|
||||||
|
day.className = `day ${est_just}`;
|
||||||
|
}
|
||||||
|
|
||||||
day.style.backgroundColor = getDayColor(color);
|
if (options.mode_demi && !isWorkDay) {
|
||||||
|
est_just = []
|
||||||
|
// affichage n° jour + matin + aprem
|
||||||
|
|
||||||
|
const span_jour = document.createElement("span")
|
||||||
|
span_jour.textContent = dayOfMonth + dayOfWeek[0];
|
||||||
|
|
||||||
|
const span_matin = document.createElement("span");
|
||||||
|
span_matin.classList.add("color");
|
||||||
|
const matin = [new Date(date), new Date(date)]
|
||||||
|
color = ""
|
||||||
|
matin[0].setHours(0, 0, 0, 0)
|
||||||
|
matin[1].setHours(12, 59, 59)
|
||||||
|
|
||||||
|
const assiduitesMatin = dayAssiduities.filter((el) => {
|
||||||
|
const deb = new Date(el.date_debut);
|
||||||
|
const fin = new Date(el.date_fin);
|
||||||
|
return deb.isBetween(matin[0], matin[1]) || fin.isBetween(matin[0], matin[1])
|
||||||
|
})
|
||||||
|
const justificatifsMatin = dayJustificatifs.filter((el) => {
|
||||||
|
const deb = new Date(el.date_debut);
|
||||||
|
const fin = new Date(el.date_fin);
|
||||||
|
return deb.isBetween(matin[0], matin[1]) || fin.isBetween(matin[0], matin[1])
|
||||||
|
})
|
||||||
|
|
||||||
|
if (assiduitesMatin.some((a) => a.etat.toLowerCase() === "absent")) color = "absent";
|
||||||
|
else if (assiduitesMatin.some((a) => a.etat.toLowerCase() === "retard") && options.show_reta)
|
||||||
|
color = "retard";
|
||||||
|
else if (assiduitesMatin.some((a) => a.etat.toLowerCase() === "present") && options.show_pres)
|
||||||
|
color = "present";
|
||||||
|
|
||||||
|
if (color != "") {
|
||||||
|
span_matin.classList.add(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (justificatifsMatin.some((j) => j.etat.toLowerCase() === "valide")) {
|
||||||
|
est_just = ["est_just"];
|
||||||
|
} else if (justificatifsMatin.some((j) => j.etat.toLowerCase() !== "valide")) {
|
||||||
|
est_just = ["est_just", "invalide"];
|
||||||
|
}
|
||||||
|
|
||||||
|
span_matin.classList.add(...est_just)
|
||||||
|
|
||||||
|
|
||||||
|
est_just = []
|
||||||
|
const span_aprem = document.createElement("span");
|
||||||
|
span_aprem.classList.add("color");
|
||||||
|
const aprem = [new Date(date), new Date(date)]
|
||||||
|
color = ""
|
||||||
|
aprem[0].setHours(13, 0, 0, 0)
|
||||||
|
aprem[1].setHours(23, 59, 59)
|
||||||
|
|
||||||
|
const assiduitesAprem = dayAssiduities.filter((el) => {
|
||||||
|
const deb = new Date(el.date_debut);
|
||||||
|
const fin = new Date(el.date_fin);
|
||||||
|
return deb.isBetween(aprem[0], aprem[1]) || fin.isBetween(aprem[0], aprem[1])
|
||||||
|
})
|
||||||
|
|
||||||
|
const justificatifsAprem = dayJustificatifs.filter((el) => {
|
||||||
|
const deb = new Date(el.date_debut);
|
||||||
|
const fin = new Date(el.date_fin);
|
||||||
|
return deb.isBetween(aprem[0], aprem[1]) || fin.isBetween(aprem[0], aprem[1])
|
||||||
|
})
|
||||||
|
|
||||||
|
if (assiduitesAprem.some((a) => a.etat.toLowerCase() === "absent")) color = "absent";
|
||||||
|
else if (assiduitesAprem.some((a) => a.etat.toLowerCase() === "retard") && options.show_reta)
|
||||||
|
color = "retard";
|
||||||
|
else if (assiduitesAprem.some((a) => a.etat.toLowerCase() === "present") && options.show_pres)
|
||||||
|
color = "present";
|
||||||
|
|
||||||
|
if (color != "") {
|
||||||
|
span_aprem.classList.add(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (justificatifsAprem.some((j) => j.etat.toLowerCase() === "valide")) {
|
||||||
|
est_just = ["est_just"];;
|
||||||
|
} else if (justificatifsAprem.some((j) => j.etat.toLowerCase() !== "valide")) {
|
||||||
|
est_just = ["est_just", "invalide"];;
|
||||||
|
}
|
||||||
|
|
||||||
|
span_matin.classList.add(...est_just)
|
||||||
|
|
||||||
|
day.appendChild(span_jour)
|
||||||
|
day.appendChild(span_matin)
|
||||||
|
day.appendChild(span_aprem)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
day.classList.add("color")
|
||||||
|
if (color != "") {
|
||||||
|
day.classList.add(color);
|
||||||
|
}
|
||||||
day.textContent = `${dayOfWeek} ${dayOfMonth}`;
|
day.textContent = `${dayOfWeek} ${dayOfMonth}`;
|
||||||
|
}
|
||||||
|
|
||||||
if (!nonWorkdays.includes(dayOfWeek.toLowerCase()) && dayAssiduities.length > 0) {
|
if (!nonWorkdays.includes(dayOfWeek.toLowerCase()) && dayAssiduities.length > 0) {
|
||||||
const cache = document.createElement('div')
|
const cache = document.createElement('div')
|
||||||
@ -271,7 +481,6 @@
|
|||||||
cache.appendChild(
|
cache.appendChild(
|
||||||
createMiniTimeline(dayAssiduities, date)
|
createMiniTimeline(dayAssiduities, date)
|
||||||
)
|
)
|
||||||
|
|
||||||
day.appendChild(cache)
|
day.appendChild(cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,13 +496,19 @@
|
|||||||
const url_api =
|
const url_api =
|
||||||
getUrl() +
|
getUrl() +
|
||||||
`/api/assiduites/${etudid}/query?date_debut=${deb}&date_fin=${fin}`;
|
`/api/assiduites/${etudid}/query?date_debut=${deb}&date_fin=${fin}`;
|
||||||
async_get(url_api, (data, status) => {
|
async_get(url_api, (data) => {
|
||||||
if (status === "success") {
|
|
||||||
callback(data);
|
callback(data);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getOptions() {
|
||||||
|
return {
|
||||||
|
"show_pres": document.getElementById("show_pres").checked,
|
||||||
|
"show_reta": document.getElementById("show_reta").checked,
|
||||||
|
"mode_demi": document.getElementById("mode_demi").checked,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getEtudJustificatifs(deb, fin) {
|
function getEtudJustificatifs(deb, fin) {
|
||||||
let list = [];
|
let list = [];
|
||||||
const url_api =
|
const url_api =
|
||||||
@ -309,7 +524,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generate(annee) {
|
function generate(annee) {
|
||||||
|
|
||||||
if (annee < 1999 || annee > 2999) {
|
if (annee < 1999 || annee > 2999) {
|
||||||
openAlertModal("Année impossible", document.createTextNode("L'année demandé n'existe pas."));
|
openAlertModal("Année impossible", document.createTextNode("L'année demandé n'existe pas."));
|
||||||
return;
|
return;
|
||||||
@ -331,10 +545,11 @@
|
|||||||
|
|
||||||
function setterAnnee(annee) {
|
function setterAnnee(annee) {
|
||||||
annee = parseInt(annee);
|
annee = parseInt(annee);
|
||||||
document.querySelector('.annee span').textContent = `Année scolaire ${annee}-${annee + 1} Changer année: `
|
document.querySelector('.annee #label-annee').textContent = `Année scolaire ${annee}-${annee + 1}`
|
||||||
generate(annee)
|
generate(annee)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const defAnnee = {{ annee }}
|
const defAnnee = {{ annee }}
|
||||||
let annees = {{ annees | safe }}
|
let annees = {{ annees | safe }}
|
||||||
annees = annees.filter((x, i) => annees.indexOf(x) === i)
|
annees = annees.filter((x, i) => annees.indexOf(x) === i)
|
||||||
@ -351,6 +566,12 @@
|
|||||||
}
|
}
|
||||||
select.appendChild(opt)
|
select.appendChild(opt)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
document.querySelectorAll(".options input").forEach((e) => {
|
||||||
|
e.addEventListener("click", () => {
|
||||||
|
setterAnnee(select.value)
|
||||||
|
})
|
||||||
|
})
|
||||||
setterAnnee(defAnnee)
|
setterAnnee(defAnnee)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
if (defaultDates != null) {
|
if (defaultDates != null) {
|
||||||
defaultDates.forEach((dateString) => {
|
defaultDates.forEach((dateString) => {
|
||||||
|
|
||||||
d = moment(dateString).weekday();
|
d = new Date(dateString).getDay();
|
||||||
|
|
||||||
if (verifyNonWorkDays(d, nonWorkDays)) return;
|
if (verifyNonWorkDays(d, nonWorkDays)) return;
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<div class="infos">
|
<div class="infos">
|
||||||
Date: <span id="datestr"></span>
|
Date: <span id="datestr"></span>
|
||||||
<input type="date" name="tl_date" id="tl_date" value="{{ date }}">
|
<input type="text" class="datepicker" name="tl_date" id="tl_date" value="{{ date }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{timeline|safe}}
|
{{timeline|safe}}
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
<div class="infos-button">Groupes : {{grp|safe}}</div>
|
<div class="infos-button">Groupes : {{grp|safe}}</div>
|
||||||
<div class="infos-button" style="margin-left: 24px;">Date : <span style="margin-left: 8px;"
|
<div class="infos-button" style="margin-left: 24px;">Date : <span style="margin-left: 8px;"
|
||||||
id="datestr"></span>
|
id="datestr"></span>
|
||||||
<input type="date" name="tl_date" id="tl_date" value="{{ date }}" onchange="updateDate()">
|
<input type="text" class="datepicker" name="tl_date" id="tl_date" value="{{ date }}"
|
||||||
|
onchange="updateDate()">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
18
app/templates/assiduites/pages/test.j2
Normal file
18
app/templates/assiduites/pages/test.j2
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Test DateUtils</title>
|
||||||
|
<script src="{{scu.STATIC_DIR}}/js/date_utils.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<form action="" method="post">
|
||||||
|
<scodoc-datetime name="scodoc-datetime"></scodoc-datetime>
|
||||||
|
<input type="submit" value="valider">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -10,10 +10,10 @@
|
|||||||
<h2>Visualisation de l'assiduité {{gr_tit|safe}}</h2>
|
<h2>Visualisation de l'assiduité {{gr_tit|safe}}</h2>
|
||||||
|
|
||||||
<div class="stats-inputs">
|
<div class="stats-inputs">
|
||||||
<label class="stats-label"> Date de début <input type="date" name="stats_date_debut" id="stats_date_debut"
|
<label class="stats-label"> Date de début <input type="text" class="datepicker" name="stats_date_debut"
|
||||||
value="{{date_debut}}"></label>
|
id="stats_date_debut" value="{{date_debut}}"></label>
|
||||||
<label class="stats-label"> Date de fin <input type="date" name="stats_date_fin" id="stats_date_fin"
|
<label class="stats-label"> Date de fin <input type="text" class="datepicker" name="stats_date_fin"
|
||||||
value="{{date_fin}}"></label>
|
id="stats_date_fin" value="{{date_fin}}"></label>
|
||||||
<button onclick="stats()">Changer</button>
|
<button onclick="stats()">Changer</button>
|
||||||
|
|
||||||
<a style="margin-left:32px;" href="{{request.url}}&fmt=xlsx">{{scu.ICON_XLS|safe}}</a>
|
<a style="margin-left:32px;" href="{{request.url}}&fmt=xlsx">{{scu.ICON_XLS|safe}}</a>
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
* @returns {String} un déplacement par rapport à la gauche en %
|
* @returns {String} un déplacement par rapport à la gauche en %
|
||||||
*/
|
*/
|
||||||
function getLeftPosition(start) {
|
function getLeftPosition(start) {
|
||||||
const startTime = new moment.tz(start, TIMEZONE);
|
const startTime = new Date(start);
|
||||||
const startMins = (startTime.hours() - 8) * 60 + startTime.minutes();
|
const startMins = (startTime.getHours() - 8) * 60 + startTime.getMinutes();
|
||||||
return (startMins / (18 * 60 - 8 * 60)) * 100 + "%";
|
return (startMins / (18 * 60 - 8 * 60)) * 100 + "%";
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -21,8 +21,8 @@
|
|||||||
return a.start < b.end && a.end > b.start;
|
return a.start < b.end && a.end > b.start;
|
||||||
};
|
};
|
||||||
|
|
||||||
const startTime = new moment.tz(start, TIMEZONE);
|
const startTime = new Date(start);
|
||||||
const endTime = new moment.tz(end, TIMEZONE);
|
const endTime = new Date(end);
|
||||||
const assiduiteDuration = { start: startTime, end: endTime };
|
const assiduiteDuration = { start: startTime, end: endTime };
|
||||||
|
|
||||||
let position = 0;
|
let position = 0;
|
||||||
@ -31,8 +31,8 @@
|
|||||||
while (hasOverlap) {
|
while (hasOverlap) {
|
||||||
hasOverlap = false;
|
hasOverlap = false;
|
||||||
Array.from(container.children).some((el) => {
|
Array.from(container.children).some((el) => {
|
||||||
const elStart = new moment.tz(el.getAttribute("data-start"));
|
const elStart = new Date(el.getAttribute("data-start"));
|
||||||
const elEnd = new moment.tz(el.getAttribute("data-end"));
|
const elEnd = new Date(el.getAttribute("data-end"));
|
||||||
const elDuration = { start: elStart, end: elEnd };
|
const elDuration = { start: elStart, end: elEnd };
|
||||||
|
|
||||||
if (overlaps(assiduiteDuration, elDuration)) {
|
if (overlaps(assiduiteDuration, elDuration)) {
|
||||||
@ -71,8 +71,8 @@
|
|||||||
* @returns {String} la taille en %
|
* @returns {String} la taille en %
|
||||||
*/
|
*/
|
||||||
function getWidth(start, end) {
|
function getWidth(start, end) {
|
||||||
const startTime = new moment.tz(start, TIMEZONE);
|
const startTime = new Date(start);
|
||||||
const endTime = new moment.tz(end, TIMEZONE);
|
const endTime = new Date(end);
|
||||||
|
|
||||||
const duration = (endTime - startTime) / 1000 / 60;
|
const duration = (endTime - startTime) / 1000 / 60;
|
||||||
|
|
||||||
@ -258,11 +258,11 @@
|
|||||||
const success = () => {
|
const success = () => {
|
||||||
const separatorTime = document.getElementById("promptTime").value;
|
const separatorTime = document.getElementById("promptTime").value;
|
||||||
const dateString =
|
const dateString =
|
||||||
document.querySelector("#tl_date").value + `T${separatorTime}`;
|
getDate().format("YYYY-MM-DD") + `T${separatorTime}`;
|
||||||
const separtorDate = new moment.tz(dateString, TIMEZONE);
|
const separtorDate = new Date(dateString);
|
||||||
|
|
||||||
const assiduite_debut = new moment.tz(this.selectedAssiduite.date_debut, TIMEZONE);
|
const assiduite_debut = new Date(this.selectedAssiduite.date_debut);
|
||||||
const assiduite_fin = new moment.tz(this.selectedAssiduite.date_fin, TIMEZONE);
|
const assiduite_fin = new Date(this.selectedAssiduite.date_fin);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
separtorDate.isAfter(assiduite_debut) &&
|
separtorDate.isAfter(assiduite_debut) &&
|
||||||
@ -270,14 +270,14 @@
|
|||||||
) {
|
) {
|
||||||
const assiduite_avant = {
|
const assiduite_avant = {
|
||||||
etat: this.selectedAssiduite.etat,
|
etat: this.selectedAssiduite.etat,
|
||||||
date_debut: assiduite_debut.format(),
|
date_debut: assiduite_debut.toIsoUtcString()(),
|
||||||
date_fin: separtorDate.format(),
|
date_fin: separtorDate.toIsoUtcString()(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const assiduite_apres = {
|
const assiduite_apres = {
|
||||||
etat: this.selectedAssiduite.etat,
|
etat: this.selectedAssiduite.etat,
|
||||||
date_debut: separtorDate.format(),
|
date_debut: separtorDate.toIsoUtcString()(),
|
||||||
date_fin: assiduite_fin.format(),
|
date_fin: assiduite_fin.toIsoUtcString()(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.selectedAssiduite.moduleimpl_id) {
|
if (this.selectedAssiduite.moduleimpl_id) {
|
||||||
@ -396,8 +396,8 @@
|
|||||||
//Placement des assiduités sur la timeline
|
//Placement des assiduités sur la timeline
|
||||||
this.list.forEach((assiduite) => {
|
this.list.forEach((assiduite) => {
|
||||||
const period = {
|
const period = {
|
||||||
deb: new moment.tz(assiduite.date_debut, TIMEZONE),
|
deb: new Date(assiduite.date_debut),
|
||||||
fin: new moment.tz(assiduite.date_fin, TIMEZONE),
|
fin: new Date(assiduite.date_fin),
|
||||||
};
|
};
|
||||||
if (!hasTimeConflict(period, this.interval)) {
|
if (!hasTimeConflict(period, this.interval)) {
|
||||||
return;
|
return;
|
||||||
|
@ -274,17 +274,21 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
const assi_etat_defaut = "{{assi_etat_defaut}}";
|
const assi_etat_defaut = "{{assi_etat_defaut}}";
|
||||||
|
{% if scu.is_assiduites_module_forced(request.args.get('formsemestre_id', None)) %}
|
||||||
window.forceModule = "{{ forcer_module }}"
|
window.forceModule = true;
|
||||||
window.forceModule = window.forceModule == "True" ? true : false
|
{% else %}
|
||||||
|
window.forceModule = false;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
let colCount = 1;
|
let colCount = 1;
|
||||||
|
|
||||||
let currentDate = "{{date}}";
|
let currentDate = "{{date}}";
|
||||||
if (currentDate == "") {
|
if (currentDate == "") {
|
||||||
currentDate = moment().tz(TIMEZONE).format("YYYY-MM-DDTHH:mm");
|
currentDate = new Date();
|
||||||
|
currentDate = currentDate.format("YYYY-MM-DDTHH:mm");
|
||||||
} else {
|
} else {
|
||||||
currentDate = moment(currentDate).tz(TIMEZONE).format("YYYY-MM-DDTHH:mm");
|
currentDate = new Date(currentDate);
|
||||||
|
currentDate = currentDate.format("YYYY-MM-DDTHH:mm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -432,7 +436,10 @@
|
|||||||
const last = document.querySelector(`[col='${num}'] #dateEnd`);
|
const last = document.querySelector(`[col='${num}'] #dateEnd`);
|
||||||
let date = undefined;
|
let date = undefined;
|
||||||
if (last == undefined) {
|
if (last == undefined) {
|
||||||
date = currentDate;
|
date = new Date(currentDate);
|
||||||
|
const start = typeof mt_start !== 'undefined' ? mt_start : 0
|
||||||
|
date.setHours(start);
|
||||||
|
date = date.format("YYYY-MM-DDTHH:mm")
|
||||||
} else {
|
} else {
|
||||||
date = last.value;
|
date = last.value;
|
||||||
}
|
}
|
||||||
@ -444,9 +451,10 @@
|
|||||||
() => {
|
() => {
|
||||||
const el = element.parentElement.querySelector("#dateEnd");
|
const el = element.parentElement.querySelector("#dateEnd");
|
||||||
const el2 = element.parentElement.querySelector("#dateStart");
|
const el2 = element.parentElement.querySelector("#dateStart");
|
||||||
el.value = moment(el2.valueAsDate).tz(TIMEZONE).utc()
|
const newDate = new Date(el2.valueAsDate)
|
||||||
.add(2, "hours")
|
.add(2, "hours");
|
||||||
.format("YYYY-MM-DDTHH:mm");
|
el.valueAsDate = newDate;
|
||||||
|
|
||||||
const colid = element.parentElement.parentElement.getAttribute('col');
|
const colid = element.parentElement.parentElement.getAttribute('col');
|
||||||
getAndUpdateCol(colid);
|
getAndUpdateCol(colid);
|
||||||
},
|
},
|
||||||
@ -517,8 +525,8 @@
|
|||||||
const inputDeb = col.querySelector("#dateStart").value;
|
const inputDeb = col.querySelector("#dateStart").value;
|
||||||
const inputFin = col.querySelector("#dateEnd").value;
|
const inputFin = col.querySelector("#dateEnd").value;
|
||||||
const moduleSelect = col.querySelector("#moduleimpl_select,.dynaSelect").value;
|
const moduleSelect = col.querySelector("#moduleimpl_select,.dynaSelect").value;
|
||||||
const d_debut = moment(inputDeb).tz(TIMEZONE);
|
const d_debut = new Date(inputDeb);
|
||||||
const d_fin = moment(inputFin).tz(TIMEZONE);
|
const d_fin = new Date(inputFin);
|
||||||
|
|
||||||
|
|
||||||
if (inputDeb == "" || inputFin == "" || d_debut >= d_fin) {
|
if (inputDeb == "" || inputFin == "" || d_debut >= d_fin) {
|
||||||
@ -547,14 +555,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (get) {
|
if (get) {
|
||||||
getAssiduitesFromEtuds(false, d_debut.format(), d_fin.format())
|
getAssiduitesFromEtuds(false, d_debut.toIsoUtcString(), d_fin.toIsoUtcString())
|
||||||
return 0x0;
|
return 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
moduleimpl: moduleSelect,
|
moduleimpl: moduleSelect,
|
||||||
deb: d_debut.format(),
|
deb: d_debut.toIsoUtcString(),
|
||||||
fin: d_fin.format(),
|
fin: d_fin.toIsoUtcString(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -568,8 +576,8 @@
|
|||||||
|
|
||||||
const inputDeb = col.querySelector("#dateStart").value;
|
const inputDeb = col.querySelector("#dateStart").value;
|
||||||
const inputFin = col.querySelector("#dateEnd").value;
|
const inputFin = col.querySelector("#dateEnd").value;
|
||||||
const d_debut = moment(inputDeb).tz(TIMEZONE);
|
const d_debut = new Date(inputDeb);
|
||||||
const d_fin = moment(inputFin).tz(TIMEZONE);
|
const d_fin = new Date(inputFin);
|
||||||
|
|
||||||
const moduleimpl_id = col.querySelector("#moduleimpl_select,.dynaSelect").value;
|
const moduleimpl_id = col.querySelector("#moduleimpl_select,.dynaSelect").value;
|
||||||
|
|
||||||
@ -715,15 +723,27 @@
|
|||||||
assiduites[etudid].push(assiduite);
|
assiduites[etudid].push(assiduite);
|
||||||
updateAllCol()
|
updateAllCol()
|
||||||
launchToast(etudid, etat);
|
launchToast(etudid, etat);
|
||||||
|
} else {
|
||||||
|
let error = data.errors[Object.keys(data.errors)[0]];
|
||||||
|
if (error.message.indexOf("Module") != -1) {
|
||||||
|
const html = `
|
||||||
|
<h3>Aucun module n'a été spécifié (préférence du semestre concerné)</h3>
|
||||||
|
`;
|
||||||
|
const div = document.createElement("div");
|
||||||
|
div.innerHTML = html;
|
||||||
|
openAlertModal("Erreur Module", div);
|
||||||
|
rbtn.checked = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
case "conflit":
|
case "conflit":
|
||||||
// Conflit, afficher résolveur
|
// Conflit, afficher résolveur
|
||||||
const assiduitesList = assiduites[etudid];
|
const assiduitesList = assiduites[etudid];
|
||||||
const d_debut = new moment.tz(deb, TIMEZONE);
|
const d_debut = new Date(deb);
|
||||||
const d_fin = new moment.tz(fin, TIMEZONE);
|
const d_fin = new Date(fin);
|
||||||
|
|
||||||
const period = {
|
const period = {
|
||||||
deb: deb,
|
deb: deb,
|
||||||
@ -733,8 +753,8 @@
|
|||||||
assiduites[etudid],
|
assiduites[etudid],
|
||||||
period,
|
period,
|
||||||
{
|
{
|
||||||
deb: new moment.tz(d_debut.startOf('day'), TIMEZONE),
|
deb: d_debut.startOf('day'),
|
||||||
fin: new moment.tz(d_fin.endOf('day'), TIMEZONE),
|
fin: d_fin.endOf('day'),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const update = () => {
|
const update = () => {
|
||||||
@ -944,11 +964,24 @@
|
|||||||
|
|
||||||
})
|
})
|
||||||
).done((c, e) => {
|
).done((c, e) => {
|
||||||
|
let error;
|
||||||
Object.keys(c[0].success).forEach((k) => {
|
Object.keys(c[0].success).forEach((k) => {
|
||||||
const assiduite = createList[Number.parseInt(k)];
|
const assiduite = createList[Number.parseInt(k)];
|
||||||
assiduite["assiduite_id"] = c[0].success[k].message.assiduite_id;
|
assiduite["assiduite_id"] = c[0].success[k].message.assiduite_id;
|
||||||
assiduites[assiduite.etudid].push(assiduite);
|
assiduites[assiduite.etudid].push(assiduite);
|
||||||
})
|
})
|
||||||
|
if (c[0].errors.length > 0) {
|
||||||
|
error = c[0].errors[Object.keys(c[0].errors)[0]];
|
||||||
|
if (error.message.indexOf("Module") != -1) {
|
||||||
|
const html = `
|
||||||
|
<h3>Aucun module n'a été spécifié (préférence du semestre concerné)</h3>
|
||||||
|
`;
|
||||||
|
const div = document.createElement("div");
|
||||||
|
div.innerHTML = html;
|
||||||
|
openAlertModal("Erreur Module", div);
|
||||||
|
toCreate.length = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
Object.keys(e[0].success).forEach((k) => {
|
Object.keys(e[0].success).forEach((k) => {
|
||||||
const { etudid, assiduite_id, moduleimpl_id, etat } = editList[Number.parseInt(k)]
|
const { etudid, assiduite_id, moduleimpl_id, etat } = editList[Number.parseInt(k)]
|
||||||
assiduites[etudid].map((a) => {
|
assiduites[etudid].map((a) => {
|
||||||
|
@ -13,16 +13,17 @@
|
|||||||
*/
|
*/
|
||||||
function createMiniTimeline(assiduitesArray, day = null) {
|
function createMiniTimeline(assiduitesArray, day = null) {
|
||||||
const array = [...assiduitesArray];
|
const array = [...assiduitesArray];
|
||||||
const dateiso = day == null ? document.getElementById("tl_date").value : day;
|
|
||||||
|
const dateiso = day == null ? getDate().format("YYYY-MM-DD") : day;
|
||||||
const timeline = document.createElement("div");
|
const timeline = document.createElement("div");
|
||||||
timeline.className = "mini-timeline";
|
timeline.className = "mini-timeline";
|
||||||
if (isSingleEtud()) {
|
if (isSingleEtud()) {
|
||||||
timeline.classList.add("single");
|
timeline.classList.add("single");
|
||||||
}
|
}
|
||||||
const timelineDate = moment(dateiso).startOf("day");
|
const timelineDate = new Date(dateiso).startOf("day");
|
||||||
const dayStart = timelineDate.clone().add(mt_start, "hours");
|
const dayStart = timelineDate.clone().add(mt_start, "hours");
|
||||||
const dayEnd = timelineDate.clone().add(mt_end, "hours");
|
const dayEnd = timelineDate.clone().add(mt_end, "hours");
|
||||||
const dayDuration = moment.duration(dayEnd.diff(dayStart)).asMinutes();
|
const dayDuration = new Duration(dayStart, dayEnd).minutes;
|
||||||
|
|
||||||
timeline.appendChild(setMiniTick(timelineDate, dayStart, dayDuration));
|
timeline.appendChild(setMiniTick(timelineDate, dayStart, dayDuration));
|
||||||
|
|
||||||
@ -38,8 +39,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
array.forEach((assiduité) => {
|
array.forEach((assiduité) => {
|
||||||
let startDate = moment(assiduité.date_debut);
|
let startDate = new Date(assiduité.date_debut);
|
||||||
let endDate = moment(assiduité.date_fin);
|
let endDate = new Date(assiduité.date_fin);
|
||||||
|
|
||||||
if (startDate.isBefore(dayStart)) {
|
if (startDate.isBefore(dayStart)) {
|
||||||
startDate = dayEnd.clone().startOf("day").add(mt_start, "hours");
|
startDate = dayEnd.clone().startOf("day").add(mt_start, "hours");
|
||||||
@ -51,8 +52,8 @@
|
|||||||
|
|
||||||
const block = document.createElement("div");
|
const block = document.createElement("div");
|
||||||
block.className = "mini-timeline-block";
|
block.className = "mini-timeline-block";
|
||||||
const duration = moment.duration(endDate.diff(startDate)).asMinutes();
|
const duration = new Duration(startDate, endDate).minutes;
|
||||||
const startOffset = moment.duration(startDate.diff(dayStart)).asMinutes();
|
const startOffset = new Duration(dayStart, startDate).minutes;
|
||||||
const leftPercentage = (startOffset / dayDuration) * 100;
|
const leftPercentage = (startOffset / dayDuration) * 100;
|
||||||
const widthPercentage = (duration / dayDuration) * 100;
|
const widthPercentage = (duration / dayDuration) * 100;
|
||||||
|
|
||||||
@ -61,8 +62,8 @@
|
|||||||
|
|
||||||
if (assiduité.etat != "CRENEAU") {
|
if (assiduité.etat != "CRENEAU") {
|
||||||
block.addEventListener("click", () => {
|
block.addEventListener("click", () => {
|
||||||
let deb = startDate.hours() + startDate.minutes() / 60;
|
let deb = startDate.getHours() + startDate.getMinutes() / 60;
|
||||||
let fin = endDate.hours() + endDate.minutes() / 60;
|
let fin = endDate.getHours() + endDate.getMinutes() / 60;
|
||||||
deb = Math.max(mt_start, deb);
|
deb = Math.max(mt_start, deb);
|
||||||
fin = Math.min(mt_end, fin);
|
fin = Math.min(mt_end, fin);
|
||||||
|
|
||||||
@ -98,8 +99,8 @@
|
|||||||
if (assiduité.etudid) {
|
if (assiduité.etudid) {
|
||||||
getJustificatifFromPeriod(
|
getJustificatifFromPeriod(
|
||||||
{
|
{
|
||||||
deb: new moment.tz(assiduité.date_debut, TIMEZONE),
|
deb: new Date(assiduité.date_debut),
|
||||||
fin: new moment.tz(assiduité.date_fin, TIMEZONE),
|
fin: new Date(assiduité.date_fin),
|
||||||
},
|
},
|
||||||
assiduité.etudid,
|
assiduité.etudid,
|
||||||
action
|
action
|
||||||
@ -184,8 +185,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setMiniTick(timelineDate, dayStart, dayDuration) {
|
function setMiniTick(timelineDate, dayStart, dayDuration) {
|
||||||
const endDate = timelineDate.clone().set({ 'hour': 13, 'minute': 0 });
|
const endDate = timelineDate.clone().startOf("day");
|
||||||
const duration = moment.duration(endDate.diff(dayStart)).asMinutes();
|
endDate.setHours(13, 0);
|
||||||
|
const duration = new Duration(dayStart, endDate).minutes;
|
||||||
const widthPercentage = (duration / dayDuration) * 100;
|
const widthPercentage = (duration / dayDuration) * 100;
|
||||||
const tick = document.createElement('span');
|
const tick = document.createElement('span');
|
||||||
tick.className = "mini_tick"
|
tick.className = "mini_tick"
|
||||||
|
@ -21,13 +21,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function filterFormSemestres(semestres, dateIso) {
|
function filterFormSemestres(semestres, dateIso) {
|
||||||
const date = new moment.tz(
|
const date = new Date(dateIso);
|
||||||
dateIso,
|
|
||||||
TIMEZONE
|
|
||||||
);
|
|
||||||
|
|
||||||
semestres = semestres.filter((fm) => {
|
semestres = semestres.filter((fm) => {
|
||||||
return date.isBetween(fm.date_debut_iso, fm.date_fin_iso, null, '[]')
|
return date.isBetween(new Date(fm.date_debut_iso), new Date(fm.date_fin_iso), '[]');
|
||||||
})
|
})
|
||||||
|
|
||||||
return semestres;
|
return semestres;
|
||||||
@ -97,9 +93,10 @@
|
|||||||
|
|
||||||
function updateSelect(moduleimpl_id, query = "#moduleimpl_select", dateIso = null) {
|
function updateSelect(moduleimpl_id, query = "#moduleimpl_select", dateIso = null) {
|
||||||
let sem = getEtudFormSemestres()
|
let sem = getEtudFormSemestres()
|
||||||
if (dateIso == null) {
|
if (!dateIso) {
|
||||||
dateIso = document.querySelector("#tl_date").value
|
dateIso = getDate().format("YYYY-MM-DD")
|
||||||
}
|
}
|
||||||
|
|
||||||
sem = filterFormSemestres(sem, dateIso)
|
sem = filterFormSemestres(sem, dateIso)
|
||||||
const mod = getModulesImplByFormsemestre(sem)
|
const mod = getModulesImplByFormsemestre(sem)
|
||||||
populateSelect(mod, moduleimpl_id, query);
|
populateSelect(mod, moduleimpl_id, query);
|
||||||
|
@ -83,7 +83,7 @@
|
|||||||
filterAssiduites.columns.forEach((k) => {
|
filterAssiduites.columns.forEach((k) => {
|
||||||
const td = document.createElement('td');
|
const td = document.createElement('td');
|
||||||
if (k.indexOf('date') != -1) {
|
if (k.indexOf('date') != -1) {
|
||||||
td.textContent = moment.tz(assiduite[k], TIMEZONE).format(`DD/MM/Y HH:mm`)
|
td.textContent = new Date(assiduite[k]).format(`DD/MM/Y HH:mm`)
|
||||||
} else if (k.indexOf("module") != -1) {
|
} else if (k.indexOf("module") != -1) {
|
||||||
td.textContent = getModuleImpl(assiduite);
|
td.textContent = getModuleImpl(assiduite);
|
||||||
} else if (k.indexOf('est_just') != -1) {
|
} else if (k.indexOf('est_just') != -1) {
|
||||||
@ -115,9 +115,9 @@
|
|||||||
const user = getUser(data);
|
const user = getUser(data);
|
||||||
const module = getModuleImpl(data);
|
const module = getModuleImpl(data);
|
||||||
|
|
||||||
const date_debut = moment.tz(data.date_debut, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
const date_debut = new Date(data.date_debut).format("DD/MM/YYYY HH:mm");
|
||||||
const date_fin = moment.tz(data.date_fin, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
const date_fin = new Date(data.date_fin).format("DD/MM/YYYY HH:mm");
|
||||||
const entry_date = moment.tz(data.entry_date, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
const entry_date = new Date(data.entry_date).format("DD/MM/YYYY HH:mm");
|
||||||
|
|
||||||
const etat = data.etat.capitalize();
|
const etat = data.etat.capitalize();
|
||||||
const desc = data.desc == null ? "" : data.desc;
|
const desc = data.desc == null ? "" : data.desc;
|
||||||
@ -433,7 +433,7 @@
|
|||||||
if (l.querySelector(`#${key}_time`).value != "") {
|
if (l.querySelector(`#${key}_time`).value != "") {
|
||||||
filterAssiduites.filters[key] = {
|
filterAssiduites.filters[key] = {
|
||||||
pref: pref,
|
pref: pref,
|
||||||
time: new moment.tz(time, TIMEZONE)
|
time: new Date(time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (key.indexOf('etat') != -1) {
|
} else if (key.indexOf('etat') != -1) {
|
||||||
|
@ -75,7 +75,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (k.indexOf('date') != -1) {
|
if (k.indexOf('date') != -1) {
|
||||||
const assi_time = moment.tz(el[k], TIMEZONE);
|
const assi_time = new Date(el[k]);
|
||||||
const filter_time = f[k].time;
|
const filter_time = f[k].time;
|
||||||
switch (f[k].pref) {
|
switch (f[k].pref) {
|
||||||
|
|
||||||
@ -262,8 +262,8 @@
|
|||||||
let keyValueB = b[keyword];
|
let keyValueB = b[keyword];
|
||||||
|
|
||||||
if (keyword.indexOf("date") != -1) {
|
if (keyword.indexOf("date") != -1) {
|
||||||
keyValueA = moment.tz(keyValueA, TIMEZONE)
|
keyValueA = new Date(keyValueA)
|
||||||
keyValueB = moment.tz(keyValueB, TIMEZONE)
|
keyValueB = new Date(keyValueB)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyword.indexOf("module") != -1) {
|
if (keyword.indexOf("module") != -1) {
|
||||||
|
@ -82,7 +82,7 @@
|
|||||||
filterJustificatifs.columns.forEach((k) => {
|
filterJustificatifs.columns.forEach((k) => {
|
||||||
const td = document.createElement('td');
|
const td = document.createElement('td');
|
||||||
if (k.indexOf('date') != -1) {
|
if (k.indexOf('date') != -1) {
|
||||||
td.textContent = moment.tz(justificatif[k], TIMEZONE).format(`DD/MM/Y HH:mm`)
|
td.textContent = new Date(justificatif[k]).format(`DD/MM/Y HH:mm`)
|
||||||
} else if (k.indexOf('fichier') != -1) {
|
} else if (k.indexOf('fichier') != -1) {
|
||||||
td.textContent = justificatif.fichier ? "Oui" : "Non";
|
td.textContent = justificatif.fichier ? "Oui" : "Non";
|
||||||
} else if (k.indexOf('etudid') != -1) {
|
} else if (k.indexOf('etudid') != -1) {
|
||||||
@ -120,9 +120,9 @@
|
|||||||
path,
|
path,
|
||||||
(data) => {
|
(data) => {
|
||||||
const user = getUser(data);
|
const user = getUser(data);
|
||||||
const date_debut = moment.tz(data.date_debut, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
const date_debut = new Date(data.date_debut).format("DD/MM/YYYY HH:mm");
|
||||||
const date_fin = moment.tz(data.date_fin, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
const date_fin = new Date(data.date_fin).format("DD/MM/YYYY HH:mm");
|
||||||
const entry_date = moment.tz(data.entry_date, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
const entry_date = new Date(data.entry_date).format("DD/MM/YYYY HH:mm");
|
||||||
|
|
||||||
const etat = data.etat.capitalize();
|
const etat = data.etat.capitalize();
|
||||||
const desc = data.raison == null ? "" : data.raison;
|
const desc = data.raison == null ? "" : data.raison;
|
||||||
@ -305,9 +305,8 @@
|
|||||||
|
|
||||||
assiEdit.querySelector('#justi_etat').value = data.etat.toLowerCase();
|
assiEdit.querySelector('#justi_etat').value = data.etat.toLowerCase();
|
||||||
assiEdit.querySelector('#justi_raison').value = desc;
|
assiEdit.querySelector('#justi_raison').value = desc;
|
||||||
const d_deb = moment.tz(data.date_debut, TIMEZONE).format("YYYY-MM-DDTHH:mm")
|
const d_deb = new Date(data.date_debut).format("YYYY-MM-DDTHH:mm")
|
||||||
const d_fin = moment.tz(data.date_fin, TIMEZONE).format("YYYY-MM-DDTHH:mm")
|
const d_fin = new Date(data.date_fin).format("YYYY-MM-DDTHH:mm")
|
||||||
console.warn(d_deb, d_fin, data.date_debut, data.date_fin)
|
|
||||||
assiEdit.querySelector('#justi_date_debut').value = d_deb
|
assiEdit.querySelector('#justi_date_debut').value = d_deb
|
||||||
assiEdit.querySelector('#justi_date_fin').value = d_fin
|
assiEdit.querySelector('#justi_date_fin').value = d_fin
|
||||||
|
|
||||||
@ -357,8 +356,8 @@
|
|||||||
openAlertModal("Dates erronées", document.createTextNode('Les dates sont invalides'));
|
openAlertModal("Dates erronées", document.createTextNode('Les dates sont invalides'));
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
date_debut = moment.tz(date_debut, TIMEZONE)
|
date_debut = new Date(date_debut)
|
||||||
date_fin = moment.tz(date_fin, TIMEZONE)
|
date_fin = new Date(date_fin)
|
||||||
|
|
||||||
if (date_debut >= date_fin) {
|
if (date_debut >= date_fin) {
|
||||||
openAlertModal("Dates erronées", document.createTextNode('La date de fin doit être après la date de début'));
|
openAlertModal("Dates erronées", document.createTextNode('La date de fin doit être après la date de début'));
|
||||||
@ -626,7 +625,7 @@
|
|||||||
if (l.querySelector(`#${key}_time`).value != "") {
|
if (l.querySelector(`#${key}_time`).value != "") {
|
||||||
filterJustificatifs.filters[key] = {
|
filterJustificatifs.filters[key] = {
|
||||||
pref: pref,
|
pref: pref,
|
||||||
time: new moment.tz(time, TIMEZONE)
|
time: new Date(time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (key.indexOf('etat') != -1) {
|
} else if (key.indexOf('etat') != -1) {
|
||||||
|
@ -144,7 +144,6 @@
|
|||||||
const startLeft = parseFloat(periodTimeLine.style.left);
|
const startLeft = parseFloat(periodTimeLine.style.left);
|
||||||
|
|
||||||
const onMouseMove = (moveEvent) => {
|
const onMouseMove = (moveEvent) => {
|
||||||
console.warn("move Period")
|
|
||||||
if (handleMoving) return;
|
if (handleMoving) return;
|
||||||
const deltaX = (moveEvent.clientX || moveEvent.changedTouches[0].clientX) - startX;
|
const deltaX = (moveEvent.clientX || moveEvent.changedTouches[0].clientX) - startX;
|
||||||
const containerWidth = timelineContainer.clientWidth;
|
const containerWidth = timelineContainer.clientWidth;
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import re
|
||||||
|
|
||||||
from flask import g, request, render_template, flash
|
from flask import g, request, render_template, flash
|
||||||
from flask import abort, url_for, redirect
|
from flask import abort, url_for, redirect
|
||||||
@ -167,8 +168,7 @@ def bilan_dept():
|
|||||||
page_title="Saisie de l'assiduité",
|
page_title="Saisie de l'assiduité",
|
||||||
javascripts=[
|
javascripts=[
|
||||||
"js/assiduites.js",
|
"js/assiduites.js",
|
||||||
"libjs/moment-2.29.4.min.js",
|
"js/date_utils.js",
|
||||||
"libjs/moment-timezone.js",
|
|
||||||
],
|
],
|
||||||
cssstyles=[
|
cssstyles=[
|
||||||
"css/assiduites.css",
|
"css/assiduites.css",
|
||||||
@ -290,8 +290,7 @@ def signal_assiduites_etud():
|
|||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
javascripts=[
|
javascripts=[
|
||||||
"js/assiduites.js",
|
"js/assiduites.js",
|
||||||
"libjs/moment-2.29.4.min.js",
|
"js/date_utils.js",
|
||||||
"libjs/moment-timezone.js",
|
|
||||||
"js/etud_info.js",
|
"js/etud_info.js",
|
||||||
],
|
],
|
||||||
cssstyles=[
|
cssstyles=[
|
||||||
@ -321,7 +320,7 @@ def signal_assiduites_etud():
|
|||||||
render_template(
|
render_template(
|
||||||
"assiduites/pages/signal_assiduites_etud.j2",
|
"assiduites/pages/signal_assiduites_etud.j2",
|
||||||
sco=ScoData(etud),
|
sco=ScoData(etud),
|
||||||
date=date,
|
date=_dateiso_to_datefr(date),
|
||||||
morning=morning,
|
morning=morning,
|
||||||
lunch=lunch,
|
lunch=lunch,
|
||||||
timeline=_timeline(heures=",".join([f"'{s}'" for s in heures])),
|
timeline=_timeline(heures=",".join([f"'{s}'" for s in heures])),
|
||||||
@ -371,8 +370,7 @@ def liste_assiduites_etud():
|
|||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
javascripts=[
|
javascripts=[
|
||||||
"js/assiduites.js",
|
"js/assiduites.js",
|
||||||
"libjs/moment-2.29.4.min.js",
|
"js/date_utils.js",
|
||||||
"libjs/moment-timezone.js",
|
|
||||||
],
|
],
|
||||||
cssstyles=CSSSTYLES
|
cssstyles=CSSSTYLES
|
||||||
+ [
|
+ [
|
||||||
@ -419,8 +417,7 @@ def bilan_etud():
|
|||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
javascripts=[
|
javascripts=[
|
||||||
"js/assiduites.js",
|
"js/assiduites.js",
|
||||||
"libjs/moment-2.29.4.min.js",
|
"js/date_utils.js",
|
||||||
"libjs/moment-timezone.js",
|
|
||||||
],
|
],
|
||||||
cssstyles=CSSSTYLES
|
cssstyles=CSSSTYLES
|
||||||
+ [
|
+ [
|
||||||
@ -429,8 +426,8 @@ def bilan_etud():
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Gestion des dates du bilan (par défaut l'année scolaire)
|
# Gestion des dates du bilan (par défaut l'année scolaire)
|
||||||
date_debut: str = f"{scu.annee_scolaire()}-09-01"
|
date_debut: str = f"01/09/{scu.annee_scolaire()}"
|
||||||
date_fin: str = f"{scu.annee_scolaire()+1}-06-30"
|
date_fin: str = f"30/06/{scu.annee_scolaire()+1}"
|
||||||
|
|
||||||
# Récupération de la métrique d'assiduité
|
# Récupération de la métrique d'assiduité
|
||||||
assi_metric = scu.translate_assiduites_metric(
|
assi_metric = scu.translate_assiduites_metric(
|
||||||
@ -480,8 +477,7 @@ def ajout_justificatif_etud():
|
|||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
javascripts=[
|
javascripts=[
|
||||||
"js/assiduites.js",
|
"js/assiduites.js",
|
||||||
"libjs/moment-2.29.4.min.js",
|
"js/date_utils.js",
|
||||||
"libjs/moment-timezone.js",
|
|
||||||
],
|
],
|
||||||
cssstyles=CSSSTYLES
|
cssstyles=CSSSTYLES
|
||||||
+ [
|
+ [
|
||||||
@ -530,8 +526,7 @@ def calendrier_etud():
|
|||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
javascripts=[
|
javascripts=[
|
||||||
"js/assiduites.js",
|
"js/assiduites.js",
|
||||||
"libjs/moment-2.29.4.min.js",
|
"js/date_utils.js",
|
||||||
"libjs/moment-timezone.js",
|
|
||||||
],
|
],
|
||||||
cssstyles=CSSSTYLES
|
cssstyles=CSSSTYLES
|
||||||
+ [
|
+ [
|
||||||
@ -540,10 +535,12 @@ def calendrier_etud():
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Récupération des années d'étude de l'étudiant
|
# Récupération des années d'étude de l'étudiant
|
||||||
annees: list[int] = sorted(
|
annees: list[int] = []
|
||||||
[ins.formsemestre.date_debut.year for ins in etud.formsemestre_inscriptions],
|
for ins in etud.formsemestre_inscriptions:
|
||||||
reverse=True,
|
annees.extend(
|
||||||
|
(ins.formsemestre.date_debut.year, ins.formsemestre.date_fin.year)
|
||||||
)
|
)
|
||||||
|
annees = sorted(annees, reverse=True)
|
||||||
|
|
||||||
# Transformation en une liste "json"
|
# Transformation en une liste "json"
|
||||||
# (sera utilisé pour générer le selecteur d'année)
|
# (sera utilisé pour générer le selecteur d'année)
|
||||||
@ -681,12 +678,10 @@ def signal_assiduites_group():
|
|||||||
javascripts=html_sco_header.BOOTSTRAP_MULTISELECT_JS
|
javascripts=html_sco_header.BOOTSTRAP_MULTISELECT_JS
|
||||||
+ [
|
+ [
|
||||||
# Voir fonctionnement JS
|
# Voir fonctionnement JS
|
||||||
# XXX Retirer moment
|
|
||||||
"js/etud_info.js",
|
"js/etud_info.js",
|
||||||
"js/groups_view.js",
|
"js/groups_view.js",
|
||||||
"js/assiduites.js",
|
"js/assiduites.js",
|
||||||
"libjs/moment-2.29.4.min.js",
|
"js/date_utils.js",
|
||||||
"libjs/moment-timezone.js",
|
|
||||||
],
|
],
|
||||||
cssstyles=CSSSTYLES
|
cssstyles=CSSSTYLES
|
||||||
+ [
|
+ [
|
||||||
@ -705,7 +700,7 @@ def signal_assiduites_group():
|
|||||||
"assiduites/pages/signal_assiduites_group.j2",
|
"assiduites/pages/signal_assiduites_group.j2",
|
||||||
gr_tit=gr_tit,
|
gr_tit=gr_tit,
|
||||||
sem=sem["titre_num"],
|
sem=sem["titre_num"],
|
||||||
date=date,
|
date=_dateiso_to_datefr(date),
|
||||||
formsemestre_id=formsemestre_id,
|
formsemestre_id=formsemestre_id,
|
||||||
grp=sco_groups_view.menu_groups_choice(groups_infos),
|
grp=sco_groups_view.menu_groups_choice(groups_infos),
|
||||||
moduleimpl_select=_module_selector(formsemestre, moduleimpl_id),
|
moduleimpl_select=_module_selector(formsemestre, moduleimpl_id),
|
||||||
@ -833,8 +828,7 @@ def visu_assiduites_group():
|
|||||||
"js/etud_info.js",
|
"js/etud_info.js",
|
||||||
"js/groups_view.js",
|
"js/groups_view.js",
|
||||||
"js/assiduites.js",
|
"js/assiduites.js",
|
||||||
"libjs/moment-2.29.4.min.js",
|
"js/date_utils.js",
|
||||||
"libjs/moment-timezone.js",
|
|
||||||
],
|
],
|
||||||
cssstyles=CSSSTYLES
|
cssstyles=CSSSTYLES
|
||||||
+ [
|
+ [
|
||||||
@ -852,7 +846,7 @@ def visu_assiduites_group():
|
|||||||
"assiduites/pages/signal_assiduites_group.j2",
|
"assiduites/pages/signal_assiduites_group.j2",
|
||||||
gr_tit=gr_tit,
|
gr_tit=gr_tit,
|
||||||
sem=sem["titre_num"],
|
sem=sem["titre_num"],
|
||||||
date=date,
|
date=_dateiso_to_datefr(date),
|
||||||
formsemestre_id=formsemestre_id,
|
formsemestre_id=formsemestre_id,
|
||||||
grp=sco_groups_view.menu_groups_choice(groups_infos),
|
grp=sco_groups_view.menu_groups_choice(groups_infos),
|
||||||
moduleimpl_select=_module_selector(formsemestre, moduleimpl_id),
|
moduleimpl_select=_module_selector(formsemestre, moduleimpl_id),
|
||||||
@ -1024,8 +1018,8 @@ def visu_assi_group():
|
|||||||
inverse=False,
|
inverse=False,
|
||||||
short=False,
|
short=False,
|
||||||
),
|
),
|
||||||
date_debut=dates["debut"],
|
date_debut=_dateiso_to_datefr(dates["debut"]),
|
||||||
date_fin=dates["fin"],
|
date_fin=_dateiso_to_datefr(dates["debut"]),
|
||||||
gr_tit=gr_tit,
|
gr_tit=gr_tit,
|
||||||
group_ids=request.args.get("group_ids", None),
|
group_ids=request.args.get("group_ids", None),
|
||||||
sco=ScoData(formsemestre=groups_infos.get_formsemestre()),
|
sco=ScoData(formsemestre=groups_infos.get_formsemestre()),
|
||||||
@ -1113,8 +1107,7 @@ def signal_assiduites_diff():
|
|||||||
javascripts=html_sco_header.BOOTSTRAP_MULTISELECT_JS
|
javascripts=html_sco_header.BOOTSTRAP_MULTISELECT_JS
|
||||||
+ [
|
+ [
|
||||||
"js/assiduites.js",
|
"js/assiduites.js",
|
||||||
"libjs/moment-2.29.4.min.js",
|
"js/date_utils.js",
|
||||||
"libjs/moment-timezone.js",
|
|
||||||
"js/etud_info.js",
|
"js/etud_info.js",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -1315,9 +1308,44 @@ def generate_bul_list(etud: Identite, semestre: FormSemestre) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/test", methods=["GET", "POST"])
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoView)
|
||||||
|
def test():
|
||||||
|
"""XXX fonction de test a retirer"""
|
||||||
|
if request.method == "POST":
|
||||||
|
print("test date_utils : ", request.form)
|
||||||
|
return render_template("assiduites/pages/test.j2")
|
||||||
|
|
||||||
|
|
||||||
# --- Fonctions internes ---
|
# --- Fonctions internes ---
|
||||||
|
|
||||||
|
|
||||||
|
def _dateiso_to_datefr(date_iso: str) -> str:
|
||||||
|
"""
|
||||||
|
_dateiso_to_datefr Transforme une date iso en date format français
|
||||||
|
|
||||||
|
Args:
|
||||||
|
date_iso (str): date au format iso (YYYY-MM-DD)
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: Si l'argument `date_iso` n'est pas au bon format
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: date au format français (DD/MM/YYYY)
|
||||||
|
"""
|
||||||
|
|
||||||
|
regex_date_iso: str = r"^\d{4}-([0]\d|1[0-2])-([0-2]\d|3[01])$"
|
||||||
|
|
||||||
|
# Vérification de la date_iso
|
||||||
|
if not re.match(regex_date_iso, date_iso):
|
||||||
|
raise ValueError(
|
||||||
|
f"La dateiso passée en paramètre [{date_iso}] n'est pas valide."
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"{date_iso[8:10]}/{date_iso[5:7]}/{date_iso[0:4]}"
|
||||||
|
|
||||||
|
|
||||||
def _get_date_str(deb: datetime.datetime, fin: datetime.datetime) -> str:
|
def _get_date_str(deb: datetime.datetime, fin: datetime.datetime) -> str:
|
||||||
"""
|
"""
|
||||||
_get_date_str transforme une période en chaîne lisible
|
_get_date_str transforme une période en chaîne lisible
|
||||||
|
Loading…
Reference in New Issue
Block a user