forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -599,7 +599,7 @@ def assiduite_edit(assiduite_id: int):
|
||||
moduleimpl: ModuleImpl = None
|
||||
|
||||
if moduleimpl_id is not False:
|
||||
if moduleimpl_id is not None:
|
||||
if moduleimpl_id is not None and moduleimpl_id != "":
|
||||
moduleimpl = ModuleImpl.query.filter_by(id=int(moduleimpl_id)).first()
|
||||
if moduleimpl is None:
|
||||
errors.append("param 'moduleimpl_id': invalide")
|
||||
@ -611,7 +611,7 @@ def assiduite_edit(assiduite_id: int):
|
||||
else:
|
||||
assiduite_unique.moduleimpl_id = moduleimpl_id
|
||||
else:
|
||||
assiduite_unique.moduleimpl_id = moduleimpl_id
|
||||
assiduite_unique.moduleimpl_id = None
|
||||
|
||||
# Cas 3 : desc
|
||||
desc = data.get("desc", False)
|
||||
|
@ -272,9 +272,6 @@ def justif_edit(justif_id: int):
|
||||
if deb is None:
|
||||
errors.append("param 'date_debut': format invalide")
|
||||
|
||||
if justificatif_unique.date_fin >= deb:
|
||||
errors.append("param 'date_debut': date de début située après date de fin ")
|
||||
|
||||
# cas 4 : date_fin
|
||||
date_fin = data.get("date_fin", False)
|
||||
if date_fin is not False:
|
||||
@ -283,13 +280,14 @@ def justif_edit(justif_id: int):
|
||||
fin = scu.is_iso_formated(date_fin.replace(" ", "+"), convert=True)
|
||||
if fin is None:
|
||||
errors.append("param 'date_fin': format invalide")
|
||||
if justificatif_unique.date_debut <= fin:
|
||||
errors.append("param 'date_fin': date de fin située avant date de début ")
|
||||
|
||||
# Mise à jour des dates
|
||||
deb = deb if deb is not None else justificatif_unique.date_debut
|
||||
fin = fin if fin is not None else justificatif_unique.date_fin
|
||||
|
||||
if fin <= deb:
|
||||
errors.append("param 'dates' : Date de début après date de fin")
|
||||
|
||||
justificatif_unique.date_debut = deb
|
||||
justificatif_unique.date_fin = fin
|
||||
|
||||
|
@ -54,8 +54,8 @@ class Trace:
|
||||
lines: list[str] = []
|
||||
for fname, traced in self.content.items():
|
||||
date_fin: datetime or None = traced[1].isoformat() if traced[1] else "None"
|
||||
|
||||
lines.append(f"{fname},{traced[0].isoformat()},{date_fin}")
|
||||
if traced[0] is not None:
|
||||
lines.append(f"{fname},{traced[0].isoformat()},{date_fin}")
|
||||
with open(self.path, "w", encoding="utf-8") as file:
|
||||
file.write("\n".join(lines))
|
||||
|
||||
|
@ -517,14 +517,25 @@
|
||||
background-image: url(../icons/filter.svg);
|
||||
}
|
||||
|
||||
[name='destroyFile'] {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
background-image: url(../icons/trash.svg);
|
||||
}
|
||||
|
||||
[name='destroyFile']:checked {
|
||||
background-image: url(../icons/remove_circle.svg);
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
outline: none;
|
||||
border: none;
|
||||
outline: none !important;
|
||||
border: none !important;
|
||||
cursor: pointer;
|
||||
margin: 0 2px;
|
||||
margin: 0 2px !important;
|
||||
}
|
||||
|
||||
.icon:focus {
|
||||
|
1
app/static/icons/remove_circle.svg
Normal file
1
app/static/icons/remove_circle.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M9.172 14.828L12.001 12m2.828-2.828L12.001 12m0 0L9.172 9.172M12.001 12l2.828 2.828M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z" stroke="#fe4217" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
|
After Width: | Height: | Size: 434 B |
1
app/static/icons/trash.svg
Normal file
1
app/static/icons/trash.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M20 9l-1.995 11.346A2 2 0 0116.035 22h-8.07a2 2 0 01-1.97-1.654L4 9M21 6h-5.625M3 6h5.625m0 0V4a2 2 0 012-2h2.75a2 2 0 012 2v2m-6.75 0h6.75" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
|
After Width: | Height: | Size: 418 B |
@ -159,6 +159,7 @@
|
||||
$.when(
|
||||
requests
|
||||
).done(() => {
|
||||
loadAll();
|
||||
})
|
||||
|
||||
}
|
||||
@ -171,7 +172,6 @@
|
||||
let couverture = null;
|
||||
|
||||
createJustificatif(justificatif, (data) => {
|
||||
console.log(data);
|
||||
if (Object.keys(data.errors).length > 0) {
|
||||
console.error(data.errors);
|
||||
}
|
||||
@ -179,7 +179,6 @@
|
||||
couverture = data.success[0].couverture
|
||||
justif_id = data.success[0].justif_id;
|
||||
importFiles(justif_id);
|
||||
loadAll();
|
||||
return;
|
||||
}
|
||||
})
|
||||
|
@ -246,7 +246,7 @@
|
||||
|
||||
day.textContent = `${dayOfWeek} ${dayOfMonth}`;
|
||||
|
||||
if (!nonWorkdays.includes(dayOfWeek.toLowerCase())) {
|
||||
if (!nonWorkdays.includes(dayOfWeek.toLowerCase()) && dayAssiduities.length > 0) {
|
||||
const cache = document.createElement('div')
|
||||
cache.classList.add('dayline');
|
||||
cache.appendChild(
|
||||
@ -304,7 +304,6 @@
|
||||
let dates = getDaysBetweenDates(bornes.deb, bornes.fin);
|
||||
let datesByMonth = organizeByMonth(dates);
|
||||
const justifs = getEtudJustificatifs(bornes.deb, bornes.fin);
|
||||
console.log(justifs)
|
||||
let assiduitiesByDay = organizeAssiduitiesByDay(datesByMonth, data, justifs);
|
||||
generateCalendar(assiduitiesByDay, nonwork);
|
||||
});
|
||||
|
@ -24,7 +24,7 @@
|
||||
/* Hidden by default */
|
||||
position: fixed;
|
||||
/* Stay in place */
|
||||
z-index: 750;
|
||||
z-index: 850;
|
||||
/* Sit on top */
|
||||
padding-top: 100px;
|
||||
/* Location of the box */
|
||||
|
@ -26,7 +26,7 @@
|
||||
/* Stay in place */
|
||||
z-index: 750;
|
||||
/* Sit on top */
|
||||
padding-top: 100px;
|
||||
padding-top: 3vh;
|
||||
/* Location of the box */
|
||||
left: 0;
|
||||
top: 0;
|
||||
@ -181,8 +181,10 @@
|
||||
succBtn.classList.add("btnPrompt")
|
||||
succBtn.textContent = "Valider"
|
||||
succBtn.addEventListener('click', () => {
|
||||
success();
|
||||
closePromptModal();
|
||||
const retour = success();
|
||||
if (retour == null || retour == false || retour == undefined) {
|
||||
closePromptModal();
|
||||
}
|
||||
})
|
||||
const cancelBtn = document.createElement('button')
|
||||
cancelBtn.classList.add("btnPrompt")
|
||||
|
@ -39,6 +39,10 @@
|
||||
<div id="paginationContainerAssiduites" class="pagination-container">
|
||||
</div>
|
||||
|
||||
<div style="display: none;" id="cache-module">
|
||||
{% include "assiduites/widgets/moduleimpl_dynamic_selector.j2" %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const paginationContainerAssiduites = document.getElementById("paginationContainerAssiduites");
|
||||
let currentPageAssiduites = 1;
|
||||
@ -105,18 +109,160 @@
|
||||
row.appendChild(td)
|
||||
})
|
||||
|
||||
row.addEventListener("contextmenu", (e) => {
|
||||
e.preventDefault();
|
||||
selectedRow = e.target.parentElement;
|
||||
contextMenu.style.top = `${e.clientY}px`;
|
||||
contextMenu.style.left = `${e.clientX}px`;
|
||||
contextMenu.style.display = "block";
|
||||
console.log(selectedRow);
|
||||
});
|
||||
row.addEventListener("contextmenu", openContext);
|
||||
|
||||
tableBodyAssiduites.appendChild(row);
|
||||
});
|
||||
updateActivePaginationButton();
|
||||
}
|
||||
|
||||
function detailAssiduites(assiduite_id) {
|
||||
const path = getUrl() + `/api/assiduite/${assiduite_id}`;
|
||||
async_get(
|
||||
path,
|
||||
(data) => {
|
||||
const user = getUserFromId(data.user_id);
|
||||
const module = getModuleImpl(data.moduleimpl_id);
|
||||
|
||||
const date_debut = moment.tz(data.date_debut, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
||||
const date_fin = moment.tz(data.date_fin, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
||||
const entry_date = moment.tz(data.entry_date, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
||||
|
||||
const etat = data.etat.capitalize();
|
||||
const desc = data.desc == null ? "" : data.desc;
|
||||
const id = data.assiduite_id;
|
||||
const est_just = data.est_just ? "Oui" : "Non";
|
||||
|
||||
const html = `
|
||||
<div class="obj-detail">
|
||||
<div class="obj-dates">
|
||||
<div id="date_debut" class="obj-part">
|
||||
<span class="obj-title">Date de début</span>
|
||||
<span class="obj-content">${date_debut}</span>
|
||||
</div>
|
||||
<div id="date_fin" class="obj-part">
|
||||
<span class="obj-title">Date de fin</span>
|
||||
<span class="obj-content">${date_fin}</span>
|
||||
</div>
|
||||
<div id="entry_date" class="obj-part">
|
||||
<span class="obj-title">Date de saisie</span>
|
||||
<span class="obj-content">${entry_date}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="obj-mod">
|
||||
<div id="module" class="obj-part">
|
||||
<span class="obj-title">Module</span>
|
||||
<span class="obj-content">${module}</span>
|
||||
</div>
|
||||
<div id="etat" class="obj-part">
|
||||
<span class="obj-title">Etat</span>
|
||||
<span class="obj-content">${etat}</span>
|
||||
</div>
|
||||
<div id="user" class="obj-part">
|
||||
<span class="obj-title">Créer par</span>
|
||||
<span class="obj-content">${user}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="obj-rest">
|
||||
<div id="est_just" class="obj-part">
|
||||
<span class="obj-title">Justifié</span>
|
||||
<span class="obj-content">${est_just}</span>
|
||||
</div>
|
||||
<div id="desc" class="obj-part">
|
||||
<span class="obj-title">Description</span>
|
||||
<p class="obj-content">${desc}</p>
|
||||
</div>
|
||||
<div id="id" class="obj-part">
|
||||
<span class="obj-title">Identifiant de l'assiduité</span>
|
||||
<span class="obj-content">${id}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
`
|
||||
|
||||
const el = document.createElement('div');
|
||||
el.innerHTML = html;
|
||||
|
||||
openAlertModal("Détails", el.firstElementChild, null, "green")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function editionAssiduites(assiduite_id) {
|
||||
const path = getUrl() + `/api/assiduite/${assiduite_id}`;
|
||||
async_get(
|
||||
path,
|
||||
(data) => {
|
||||
const module = data.moduleimpl_id;
|
||||
const etat = data.etat;
|
||||
const desc = data.desc;
|
||||
|
||||
const html = `
|
||||
<div class="assi-edit">
|
||||
<div class="assi-edit-part">
|
||||
<legend>État de l'assiduité</legend>
|
||||
<select name="etat" id="etat">
|
||||
<option value="present">Présent</option>
|
||||
<option value="retard">En Retard</option>
|
||||
<option value="absent">Absent</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="assi-edit-part">
|
||||
<legend>Module</legend>
|
||||
<select name="module" id="module">
|
||||
</select>
|
||||
</div>
|
||||
<div class="assi-edit-part">
|
||||
<legend>Description</legend>
|
||||
<textarea name="desc" id="desc" cols="50" rows="10" maxlength="500"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
`
|
||||
|
||||
const el = document.createElement('div')
|
||||
el.innerHTML = html;
|
||||
const assiEdit = el.firstElementChild;
|
||||
|
||||
assiEdit.querySelector('#etat').value = etat.toLowerCase();
|
||||
assiEdit.querySelector('#desc').value = desc != null ? desc : "";
|
||||
updateSelect(module, '#moduleimpl_select', "2022-09-04")
|
||||
assiEdit.querySelector('#module').replaceWith(document.querySelector('#moduleimpl_select').cloneNode(true));
|
||||
openPromptModal("Modification de l'assiduité", assiEdit, () => {
|
||||
const prompt = document.querySelector('.assi-edit');
|
||||
const etat = prompt.querySelector('#etat').value;
|
||||
const desc = prompt.querySelector('#desc').value;
|
||||
const module = prompt.querySelector('#moduleimpl_select').value;
|
||||
|
||||
const edit = {
|
||||
"etat": etat,
|
||||
"desc": desc,
|
||||
"moduleimpl_id": module,
|
||||
}
|
||||
|
||||
fullEditAssiduites(data.assiduite_id, edit, () => {
|
||||
try { getAllAssiduitesFromEtud(etudid, assiduiteCallBack) } catch (_) { }
|
||||
})
|
||||
|
||||
|
||||
}, () => { }, "green");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function fullEditAssiduites(assiduite_id, obj, call = () => { }) {
|
||||
const path = getUrl() + `/api/assiduite/${assiduite_id}/edit`;
|
||||
async_post(
|
||||
path,
|
||||
obj,
|
||||
call,
|
||||
(data, status) => {
|
||||
//error
|
||||
console.error(data, status);
|
||||
}
|
||||
);
|
||||
}
|
||||
</script>
|
@ -11,6 +11,7 @@
|
||||
const itemsPerPage = 10;
|
||||
const contextMenu = document.getElementById("contextMenu");
|
||||
const editOption = document.getElementById("editOption");
|
||||
const detailOption = document.getElementById("detailOption");
|
||||
const deleteOption = document.getElementById("deleteOption");
|
||||
|
||||
let selectedRow;
|
||||
@ -21,14 +22,32 @@
|
||||
|
||||
editOption.addEventListener("click", () => {
|
||||
if (selectedRow) {
|
||||
// Code pour éditer la ligne sélectionnée
|
||||
console.debug("Éditer :", selectedRow);
|
||||
const type = selectedRow.getAttribute('type');
|
||||
const obj_id = selectedRow.getAttribute('obj_id');
|
||||
|
||||
if (type == "assiduite") {
|
||||
editionAssiduites(obj_id);
|
||||
} else {
|
||||
editionJustificatifs(obj_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
detailOption.addEventListener("click", () => {
|
||||
if (selectedRow) {
|
||||
const type = selectedRow.getAttribute('type');
|
||||
const obj_id = selectedRow.getAttribute('obj_id');
|
||||
|
||||
if (type == "assiduite") {
|
||||
detailAssiduites(obj_id);
|
||||
} else {
|
||||
detailJustificatifs(obj_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
deleteOption.addEventListener("click", () => {
|
||||
if (selectedRow) {
|
||||
// Code pour supprimer la ligne sélectionnée
|
||||
const type = selectedRow.getAttribute('type');
|
||||
const obj_id = selectedRow.getAttribute('obj_id');
|
||||
if (type == "assiduite") {
|
||||
@ -112,33 +131,70 @@
|
||||
|
||||
function renderPaginationButtons(array, assi = true) {
|
||||
const totalPages = Math.ceil(array.length / itemsPerPage);
|
||||
|
||||
if (assi) {
|
||||
paginationContainerAssiduites.innerHTML = ""
|
||||
} else {
|
||||
paginationContainerJustificatifs.innerHTML = ""
|
||||
}
|
||||
|
||||
if (totalPages == 1) {
|
||||
if (totalPages <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const paginationButton = document.createElement("a");
|
||||
paginationButton.textContent = i;
|
||||
paginationButton.classList.add("pagination-button");
|
||||
if (assi) {
|
||||
paginationButton.addEventListener("click", () => {
|
||||
currentPageAssiduites = i;
|
||||
if (assi) {
|
||||
paginationContainerAssiduites.innerHTML = "<span class='liste_pagination'><button class='pagination_moins'><</button><select id='paginationAssi'></select><button class='pagination_plus'>></button></span>"
|
||||
paginationContainerAssiduites.querySelector('#paginationAssi')?.addEventListener('change', (e) => {
|
||||
currentPageAssiduites = e.target.value;
|
||||
renderTableAssiduites(currentPageAssiduites, array);
|
||||
})
|
||||
|
||||
paginationContainerAssiduites.querySelector('.pagination_moins').addEventListener('click', () => {
|
||||
if (currentPageAssiduites > 1) {
|
||||
currentPageAssiduites--;
|
||||
paginationContainerAssiduites.querySelector('#paginationAssi').value = currentPageAssiduites
|
||||
renderTableAssiduites(currentPageAssiduites, array);
|
||||
});
|
||||
paginationContainerAssiduites.appendChild(paginationButton);
|
||||
}
|
||||
})
|
||||
|
||||
paginationContainerAssiduites.querySelector('.pagination_plus').addEventListener('click', () => {
|
||||
if (currentPageAssiduites < totalPages) {
|
||||
currentPageAssiduites++;
|
||||
paginationContainerAssiduites.querySelector('#paginationAssi').value = currentPageAssiduites
|
||||
renderTableAssiduites(currentPageAssiduites, array);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
paginationContainerJustificatifs.innerHTML = "<span class='liste_pagination'><button class='pagination_moins'><</button><select id='paginationJusti'></select><button class='pagination_plus'>></button></span>"
|
||||
paginationContainerJustificatifs.querySelector('#paginationJusti')?.addEventListener('change', (e) => {
|
||||
currentPageJustificatifs = e.target.value;
|
||||
renderTableJustificatifs(currentPageJustificatifs, array);
|
||||
})
|
||||
|
||||
paginationContainerJustificatifs.querySelector('.pagination_moins').addEventListener('click', () => {
|
||||
if (currentPageJustificatifs > 1) {
|
||||
currentPageJustificatifs--;
|
||||
paginationContainerJustificatifs.querySelector('#paginationJusti').value = currentPageAssiduites
|
||||
renderTableJustificatifs(currentPageJustificatifs, array);
|
||||
}
|
||||
})
|
||||
|
||||
paginationContainerJustificatifs.querySelector('.pagination_plus').addEventListener('click', () => {
|
||||
if (currentPageJustificatifs < totalPages) {
|
||||
currentPageJustificatifs++;
|
||||
paginationContainerJustificatifs.querySelector('#paginationJusti').value = currentPageAssiduites
|
||||
renderTableJustificatifs(currentPageJustificatifs, array);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const paginationButton = document.createElement("option");
|
||||
paginationButton.textContent = i;
|
||||
paginationButton.value = i;
|
||||
|
||||
if (assi) {
|
||||
paginationContainerAssiduites.querySelector('#paginationAssi').appendChild(paginationButton)
|
||||
} else {
|
||||
paginationButton.addEventListener("click", () => {
|
||||
currentPageJustificatifs = i;
|
||||
renderTableAssiduites(currentPageJustificatifs, array);
|
||||
});
|
||||
paginationContainerJustificatifs.appendChild(paginationButton);
|
||||
paginationContainerJustificatifs.querySelector('#paginationJusti').appendChild(paginationButton)
|
||||
}
|
||||
}
|
||||
updateActivePaginationButton(assi);
|
||||
@ -571,7 +627,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function openContext(e) {
|
||||
e.preventDefault();
|
||||
selectedRow = e.target.parentElement;
|
||||
contextMenu.style.top = `${e.clientY - contextMenu.offsetHeight}px`;
|
||||
contextMenu.style.left = `${e.clientX}px`;
|
||||
contextMenu.style.display = "block";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@ -608,7 +670,7 @@
|
||||
|
||||
.context-menu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
list-style-type: none;
|
||||
padding: 10px 0;
|
||||
background-color: #f9f9f9;
|
||||
@ -721,4 +783,34 @@
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.obj-title {
|
||||
text-decoration: underline #bbb;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.obj-part {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 33%;
|
||||
padding: 5px;
|
||||
border: 1px solid #bbb;
|
||||
}
|
||||
|
||||
.obj-dates,
|
||||
.obj-mod,
|
||||
.obj-rest {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.liste_pagination {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
</style>
|
@ -93,19 +93,360 @@
|
||||
row.appendChild(td)
|
||||
})
|
||||
|
||||
row.addEventListener("contextmenu", (e) => {
|
||||
e.preventDefault();
|
||||
selectedRow = e.target.parentElement;
|
||||
contextMenu.style.top = `${e.clientY}px`;
|
||||
contextMenu.style.left = `${e.clientX}px`;
|
||||
contextMenu.style.display = "block";
|
||||
console.log(selectedRow);
|
||||
});
|
||||
|
||||
row.addEventListener("contextmenu", openContext);
|
||||
tableBodyJustificatifs.appendChild(row);
|
||||
});
|
||||
updateActivePaginationButton(false);
|
||||
}
|
||||
|
||||
function detailJustificatifs(justi_id) {
|
||||
const path = getUrl() + `/api/justificatif/${justi_id}`;
|
||||
async_get(
|
||||
path,
|
||||
(data) => {
|
||||
const user = getUserFromId(data.user_id);
|
||||
const date_debut = moment.tz(data.date_debut, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
||||
const date_fin = moment.tz(data.date_fin, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
||||
const entry_date = moment.tz(data.entry_date, TIMEZONE).format("DD/MM/YYYY HH:mm");
|
||||
|
||||
</script>
|
||||
const etat = data.etat.capitalize();
|
||||
const desc = data.raison == null ? "" : data.raison;
|
||||
const id = data.justif_id;
|
||||
const fichier = data.fichier != null ? "Oui" : "Non";
|
||||
let filenames = []
|
||||
if (fichier) {
|
||||
sync_get(path + "/list", (data2) => {
|
||||
filenames = data2;
|
||||
})
|
||||
}
|
||||
|
||||
const html = `
|
||||
<div class="obj-detail">
|
||||
<div class="obj-dates">
|
||||
<div id="date_debut" class="obj-part">
|
||||
<span class="obj-title">Date de début</span>
|
||||
<span class="obj-content">${date_debut}</span>
|
||||
</div>
|
||||
<div id="date_fin" class="obj-part">
|
||||
<span class="obj-title">Date de fin</span>
|
||||
<span class="obj-content">${date_fin}</span>
|
||||
</div>
|
||||
<div id="entry_date" class="obj-part">
|
||||
<span class="obj-title">Date de saisie</span>
|
||||
<span class="obj-content">${entry_date}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="obj-mod">
|
||||
<div id="module" class="obj-part">
|
||||
<span class="obj-title">Raison</span>
|
||||
<span class="obj-content">${desc}</span>
|
||||
</div>
|
||||
<div id="etat" class="obj-part">
|
||||
<span class="obj-title">Etat</span>
|
||||
<span class="obj-content">${etat}</span>
|
||||
</div>
|
||||
<div id="user" class="obj-part">
|
||||
<span class="obj-title">Créer par</span>
|
||||
<span class="obj-content">${user}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="obj-rest">
|
||||
<div id="est_just" class="obj-part obj-66">
|
||||
<span class="obj-title">Fichier(s)</span>
|
||||
<div class="obj-content" id="fich-content"></div>
|
||||
</div>
|
||||
<div id="id" class="obj-part">
|
||||
<span class="obj-title">Identifiant du justificatif</span>
|
||||
<span class="obj-content">${id}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
`
|
||||
|
||||
const el = document.createElement('div');
|
||||
el.innerHTML = html;
|
||||
|
||||
const fichContent = el.querySelector('#fich-content');
|
||||
|
||||
filenames.forEach((name) => {
|
||||
const a = document.createElement('a');
|
||||
a.textContent = name
|
||||
a.classList.add("fich-file")
|
||||
|
||||
a.onclick = () => { downloadFile(id, name) };
|
||||
|
||||
fichContent.appendChild(a);
|
||||
})
|
||||
|
||||
openAlertModal("Détails", el.firstElementChild, null, "green")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function downloadFile(id, name) {
|
||||
const path = getUrl() + `/api/justificatif/${id}/export/${name}`;
|
||||
|
||||
fetch(path, {
|
||||
method: "POST"
|
||||
|
||||
})
|
||||
// This returns a promise inside of which we are checking for errors from the server.
|
||||
// The catch promise at the end of the call does not getting called when the server returns an error.
|
||||
// More information about the error catching can be found here: https://www.tjvantoll.com/2015/09/13/fetch-and-errors/.
|
||||
.then((result) => {
|
||||
if (!result.ok) {
|
||||
throw Error(result.statusText);
|
||||
}
|
||||
|
||||
// We are reading the *Content-Disposition* header for getting the original filename given from the server
|
||||
const header = result.headers.get('Content-Disposition');
|
||||
const parts = header.split(';');
|
||||
filename = parts[1].split('=')[1].replaceAll("\"", "");
|
||||
|
||||
return result.blob();
|
||||
})
|
||||
// We use the download property for triggering the download of the file from our browser.
|
||||
// More information about the following code can be found here: https://stackoverflow.com/questions/32545632/how-can-i-download-a-file-using-window-fetch.
|
||||
// The filename from the first promise is used as name of the file.
|
||||
.then((blob) => {
|
||||
if (blob != null) {
|
||||
var url = window.URL.createObjectURL(blob);
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
}
|
||||
})
|
||||
// The catch is getting called only for client-side errors.
|
||||
// For example the throw in the first then-promise, which is the error that came from the server.
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
|
||||
function editionJustificatifs(justif_id) {
|
||||
const path = getUrl() + `/api/justificatif/${justif_id}`;
|
||||
async_get(
|
||||
path,
|
||||
(data) => {
|
||||
const html = `
|
||||
<div class="assi-edit">
|
||||
<div class="justi-row">
|
||||
<div class="justi-label">
|
||||
<legend for="justi_date_debut">Date de début</legend>
|
||||
<input type="datetime-local" name="justi_date_debut" id="justi_date_debut">
|
||||
</div>
|
||||
<div class="justi-label">
|
||||
<legend for="justi_date_fin">Date de fin</legend>
|
||||
<input type="datetime-local" name="justi_date_fin" id="justi_date_fin">
|
||||
</div>
|
||||
</div>
|
||||
<div class="justi-row">
|
||||
<div class="justi-label">
|
||||
<legend for="justi_etat">Etat du justificatif</legend>
|
||||
<select name="justi_etat" id="justi_etat">
|
||||
<option value="attente" selected>En Attente de validation</option>
|
||||
<option value="non_valide">Non Valide</option>
|
||||
<option value="modifie">Modifié</option>
|
||||
<option value="valide">Valide</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="justi-row">
|
||||
<div class="justi-label">
|
||||
<legend for="justi_raison">Raison</legend>
|
||||
<textarea name="justi_raison" id="justi_raison" cols="50" rows="10" maxlength="500"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="justi-row">
|
||||
<div class="justi-sect">
|
||||
</div>
|
||||
<div class="justi-label">
|
||||
<legend for="justi_fich">Importer un fichier</legend>
|
||||
<input type="file" name="justi_fich" id="justi_fich" multiple>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
const desc = data.raison
|
||||
const fichier = data.fichier != null ? "Oui" : "Non";
|
||||
|
||||
|
||||
const el = document.createElement('div')
|
||||
el.innerHTML = html;
|
||||
const assiEdit = el.firstElementChild;
|
||||
|
||||
assiEdit.querySelector('#justi_etat').value = data.etat.toLowerCase();
|
||||
assiEdit.querySelector('#justi_raison').value = desc != null ? desc : "";
|
||||
|
||||
assiEdit.querySelector('#justi_date_debut').value = moment.tz(data.date_debut, TIMEZONE).format("YYYY-MM-DDTHH:MM")
|
||||
assiEdit.querySelector('#justi_date_fin').value = moment.tz(data.date_fin, TIMEZONE).format("YYYY-MM-DDTHH:MM")
|
||||
|
||||
const fichContent = assiEdit.querySelector('.justi-sect');
|
||||
|
||||
let filenames = []
|
||||
if (data.fichier) {
|
||||
sync_get(path + "/list", (data2) => {
|
||||
filenames = data2;
|
||||
})
|
||||
|
||||
fichContent.insertAdjacentHTML('beforeend', "<legend>Fichier(s)</legend>")
|
||||
}
|
||||
|
||||
|
||||
filenames.forEach((name) => {
|
||||
const a = document.createElement('a');
|
||||
a.textContent = name
|
||||
a.classList.add("fich-file")
|
||||
|
||||
a.onclick = () => { downloadFile(id, name) };
|
||||
|
||||
const input = document.createElement('input')
|
||||
input.type = "checkbox"
|
||||
input.name = "destroyFile";
|
||||
input.classList.add('icon')
|
||||
|
||||
const span = document.createElement('span');
|
||||
span.classList.add('file-line')
|
||||
span.appendChild(input)
|
||||
span.appendChild(a)
|
||||
|
||||
|
||||
fichContent.appendChild(span);
|
||||
})
|
||||
|
||||
openPromptModal("Modification du justificatif", assiEdit, () => {
|
||||
const prompt = document.querySelector('.assi-edit');
|
||||
|
||||
let date_debut = prompt.querySelector('#justi_date_debut').value;
|
||||
let date_fin = prompt.querySelector('#justi_date_fin').value;
|
||||
|
||||
if (date_debut == "" || date_fin == "") {
|
||||
openAlertModal("Dates erronées", document.createTextNode('Les dates sont invalides'));
|
||||
return true
|
||||
}
|
||||
date_debut = moment.tz(date_debut, TIMEZONE)
|
||||
date_fin = moment.tz(date_fin, TIMEZONE)
|
||||
|
||||
if (date_debut >= date_fin) {
|
||||
openAlertModal("Dates erronées", document.createTextNode('La date de fin doit être après la date de début'));
|
||||
return true
|
||||
}
|
||||
|
||||
const edit = {
|
||||
date_debut: date_debut.format(),
|
||||
date_fin: date_fin.format(),
|
||||
raison: prompt.querySelector('#justi_raison').value,
|
||||
etat: prompt.querySelector('#justi_etat').value,
|
||||
}
|
||||
|
||||
const toRemoveFiles = [...prompt.querySelectorAll('[name="destroyFile"]:checked')]
|
||||
|
||||
if (toRemoveFiles.length > 0) {
|
||||
removeFiles(justif_id, toRemoveFiles);
|
||||
}
|
||||
|
||||
const in_files = prompt.querySelector('#justi_fich');
|
||||
|
||||
if (in_files.files.length > 0) {
|
||||
importNewFiles(justif_id, in_files);
|
||||
}
|
||||
|
||||
fullEditJustificatifs(data.justif_id, edit, () => {
|
||||
loadAll();
|
||||
})
|
||||
|
||||
|
||||
}, () => { }, "green");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function fullEditJustificatifs(justif_id, obj, call = () => { }) {
|
||||
const path = getUrl() + `/api/justificatif/${justif_id}/edit`;
|
||||
async_post(
|
||||
path,
|
||||
obj,
|
||||
call,
|
||||
(data, status) => {
|
||||
//error
|
||||
console.error(data, status);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function removeFiles(justif_id, files = []) {
|
||||
const path = getUrl() + `/api/justificatif/${justif_id}/remove`;
|
||||
files = files.map((el) => {
|
||||
return el.parentElement.querySelector('a').textContent;
|
||||
});
|
||||
|
||||
console.log(justif_id, files);
|
||||
sync_post(
|
||||
path,
|
||||
{
|
||||
"remove": "list",
|
||||
"filenames": files,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function importNewFiles(justif_id, in_files) {
|
||||
const path = getUrl() + `/api/justificatif/${justif_id}/import`;
|
||||
|
||||
const requests = []
|
||||
Array.from(in_files.files).forEach((f) => {
|
||||
const fd = new FormData();
|
||||
fd.append('file', f);
|
||||
requests.push(
|
||||
$.ajax(
|
||||
{
|
||||
url: path,
|
||||
type: 'POST',
|
||||
data: fd,
|
||||
dateType: 'json',
|
||||
contentType: false,
|
||||
processData: false,
|
||||
success: () => { },
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
});
|
||||
|
||||
$.when(
|
||||
requests
|
||||
).done(() => {
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
.fich-file {
|
||||
cursor: pointer;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
#fich-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.obj-66 {
|
||||
width: 66%;
|
||||
}
|
||||
|
||||
.file-line {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user