forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -127,8 +127,7 @@ def sidebar(etudid: int = None):
|
|||||||
H.append(
|
H.append(
|
||||||
f"""
|
f"""
|
||||||
<li><a href="{ url_for('assiduites.signal_assiduites_etud', scodoc_dept=g.scodoc_dept, etudid=etudid) }">Ajouter</a></li>
|
<li><a href="{ url_for('assiduites.signal_assiduites_etud', scodoc_dept=g.scodoc_dept, etudid=etudid) }">Ajouter</a></li>
|
||||||
<li><a href="{ url_for('absences.JustifAbsenceEtud', scodoc_dept=g.scodoc_dept, etudid=etudid) }">Justifier</a></li>
|
<li><a href="{ url_for('assiduites.ajout_justificatif_etud', scodoc_dept=g.scodoc_dept, etudid=etudid) }">Justifier</a></li>
|
||||||
<li><a href="{ url_for('absences.AnnuleAbsenceEtud', scodoc_dept=g.scodoc_dept, etudid=etudid) }">Supprimer</a></li>
|
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
if sco_preferences.get_preference("handle_billets_abs"):
|
if sco_preferences.get_preference("handle_billets_abs"):
|
||||||
|
@ -1536,22 +1536,12 @@ function justifyAssiduite(assiduite_id, justified) {
|
|||||||
return bool;
|
return bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createJustificatif(justif) {
|
function createJustificatif(justif, success = () => {}) {
|
||||||
const path = getUrl() + `/api/justificatif/${etudid}/create`;
|
const path = getUrl() + `/api/justificatif/${etudid}/create`;
|
||||||
sync_post(
|
sync_post(path, [justif], success, (data, status) => {
|
||||||
path,
|
|
||||||
[justif],
|
|
||||||
(data, status) => {
|
|
||||||
//success
|
|
||||||
if (data.success.length > 0) {
|
|
||||||
console.table(data[0]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(data, status) => {
|
|
||||||
//error
|
//error
|
||||||
console.error(data, status);
|
console.error(data, status);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAllJustificatifsFromEtud(etudid, action) {
|
function getAllJustificatifsFromEtud(etudid, action) {
|
||||||
|
206
app/templates/assiduites/pages/ajout_justificatif.j2
Normal file
206
app/templates/assiduites/pages/ajout_justificatif.j2
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
{% block pageContent %}
|
||||||
|
|
||||||
|
<div class="pageContent">
|
||||||
|
<h3>Justifier</h3>
|
||||||
|
{% include "assiduites/widgets/tableau_base.j2" %}
|
||||||
|
<section class="liste">
|
||||||
|
<a class="icon filter" onclick="filter(false)"></a>
|
||||||
|
{% include "assiduites/widgets/tableau_justi.j2" %}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="justi-form">
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<div class="justi-row">
|
||||||
|
<button onclick="validerFormulaire()">Créer le justificatif</button>
|
||||||
|
<button onclick="effacerFormulaire()">Remettre à zero</button>
|
||||||
|
</div>
|
||||||
|
<div class="justi-row">
|
||||||
|
<div class="justi-label">
|
||||||
|
<legend for="justi_date_debut" required>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" required>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" required>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>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="legende">
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.justi-row {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justi-form fieldset {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pageContent {
|
||||||
|
max-width: var(--sco-content-max-width);
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justi-label {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[required]::after {
|
||||||
|
content: "*";
|
||||||
|
color: crimson;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
function validateFields() {
|
||||||
|
const field = document.querySelector('.justi-form')
|
||||||
|
const in_date_debut = field.querySelector('#justi_date_debut');
|
||||||
|
const in_date_fin = field.querySelector('#justi_date_fin');
|
||||||
|
|
||||||
|
if (in_date_debut.value == "" || in_date_fin.value == "") {
|
||||||
|
openAlertModal("Erreur détéctée", document.createTextNode("Il faut indiquer une date de début et une date de fin."), "", color = "crimson");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const date_debut = moment.tz(in_date_debut.value, TIMEZONE);
|
||||||
|
const date_fin = moment.tz(in_date_fin.value, TIMEZONE);
|
||||||
|
|
||||||
|
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");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function fieldsToJustificatif() {
|
||||||
|
const field = document.querySelector('.justi-form')
|
||||||
|
|
||||||
|
const date_debut = field.querySelector('#justi_date_debut').value;
|
||||||
|
const date_fin = field.querySelector('#justi_date_fin').value;
|
||||||
|
const etat = field.querySelector('#justi_etat').value;
|
||||||
|
const raison = field.querySelector('#justi_raison').value;
|
||||||
|
|
||||||
|
return {
|
||||||
|
date_debut: date_debut,
|
||||||
|
date_fin: date_fin,
|
||||||
|
etat: etat,
|
||||||
|
raison: raison,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function importFiles(justif_id) {
|
||||||
|
const field = document.querySelector('.justi-form')
|
||||||
|
|
||||||
|
const in_files = field.querySelector('#justi_fich');
|
||||||
|
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(() => {
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function validerFormulaire() {
|
||||||
|
if (!validateFields()) return
|
||||||
|
|
||||||
|
const justificatif = fieldsToJustificatif();
|
||||||
|
let justif_id = null;
|
||||||
|
let couverture = null;
|
||||||
|
|
||||||
|
createJustificatif(justificatif, (data) => {
|
||||||
|
console.log(data);
|
||||||
|
if (Object.keys(data.errors).length > 0) {
|
||||||
|
console.error(data.errors);
|
||||||
|
}
|
||||||
|
if (Object.keys(data.success).length > 0) {
|
||||||
|
couverture = data.success[0].couverture
|
||||||
|
justif_id = data.success[0].justif_id;
|
||||||
|
importFiles(justif_id);
|
||||||
|
loadAll();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function effacerFormulaire() {
|
||||||
|
const field = document.querySelector('.justi-form')
|
||||||
|
|
||||||
|
field.querySelector('#justi_date_debut').value = "";
|
||||||
|
field.querySelector('#justi_date_fin').value = "";
|
||||||
|
field.querySelector('#justi_etat').value = "attente";
|
||||||
|
field.querySelector('#justi_raison').value = "";
|
||||||
|
field.querySelector('#justi_fich').value = "";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const etudid = {{ sco.etud.id }};
|
||||||
|
window.onload = () => {
|
||||||
|
loadAll();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock pageContent %}
|
@ -1,89 +1,14 @@
|
|||||||
{% include "assiduites/widgets/alert.j2" %}
|
|
||||||
{% include "assiduites/prompt.j2" %}
|
|
||||||
{% block app_content %}
|
{% block app_content %}
|
||||||
|
|
||||||
<div class="pageContent">
|
<div class="pageContent">
|
||||||
|
|
||||||
<h2>Liste de l'assiduité et des justificatifs de <span class="rouge">{{sco.etud.nomprenom}}</span></h2>
|
<h2>Liste de l'assiduité et des justificatifs de <span class="rouge">{{sco.etud.nomprenom}}</span></h2>
|
||||||
|
{% include "assiduites/widgets/tableau_base.j2" %}
|
||||||
<h3>Assiduités :</h3>
|
<h3>Assiduités :</h3>
|
||||||
<a class="icon filter" onclick="filter()"></a>
|
<a class="icon filter" onclick="filter()"></a>
|
||||||
<table id="assiduiteTable">
|
{% include "assiduites/widgets/tableau_assi.j2" %}
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
<div>
|
|
||||||
<span>Début</span>
|
|
||||||
<a class="icon order" onclick="order('date_debut', assiduiteCallBack, this)"></a>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<div>
|
|
||||||
<span>Fin</span>
|
|
||||||
<a class="icon order" onclick="order('date_fin', assiduiteCallBack, this)"></a>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<div>
|
|
||||||
<span>État</span>
|
|
||||||
<a class="icon order" onclick="order('etat', assiduiteCallBack, this)"></a>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<div>
|
|
||||||
<span>Module</span>
|
|
||||||
<a class="icon order" onclick="order('moduleimpl_id', assiduiteCallBack, this)"></a>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<div>
|
|
||||||
<span>Justifiée</span>
|
|
||||||
<a class="icon order" onclick="order('est_just', assiduiteCallBack, this)"></a>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="tableBodyAssiduites">
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div id="paginationContainerAssiduites" class="pagination-container">
|
|
||||||
</div>
|
|
||||||
<h3>Justificatifs :</h3>
|
<h3>Justificatifs :</h3>
|
||||||
<a class="icon filter" onclick="filter(false)"></a>
|
<a class="icon filter" onclick="filter(false)"></a>
|
||||||
<table id="justificatifTable">
|
{% include "assiduites/widgets/tableau_justi.j2" %}
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
<div>
|
|
||||||
<span>Début</span>
|
|
||||||
<a class="icon order" onclick="order('date_debut', justificatifCallBack, this, false)"></a>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<div>
|
|
||||||
<span>Fin</span>
|
|
||||||
<a class="icon order" onclick="order('date_fin', justificatifCallBack, this, false)"></a>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<div>
|
|
||||||
<span>État</span>
|
|
||||||
<a class="icon order" onclick="order('etat', justificatifCallBack, this, false)"></a>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<div>
|
|
||||||
<span>Raison</span>
|
|
||||||
<a class="icon order" onclick="order('raison', justificatifCallBack, this, false)"></a>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="tableBodyJustificatifs">
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div id="paginationContainerJustificatifs" class="pagination-container">
|
|
||||||
</div>
|
|
||||||
<ul id="contextMenu" class="context-menu">
|
<ul id="contextMenu" class="context-menu">
|
||||||
<li id="detailOption">Detail</li>
|
<li id="detailOption">Detail</li>
|
||||||
<li id="editOption">Editer</li>
|
<li id="editOption">Editer</li>
|
||||||
@ -93,851 +18,8 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock app_content %}
|
{% endblock app_content %}
|
||||||
|
|
||||||
<style>
|
|
||||||
.pageContent {
|
|
||||||
width: 100%;
|
|
||||||
max-width: var(--sco-content-max-width);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
|
|
||||||
text-align: left;
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
th,
|
|
||||||
td {
|
|
||||||
border: 1px solid #dddddd;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
background-color: #f2f2f2;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:hover {
|
|
||||||
filter: brightness(1.2)
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 10px 0;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li {
|
|
||||||
padding: 8px 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li:hover {
|
|
||||||
background-color: #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-present {
|
|
||||||
background-color: #9CF1AF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-absent,
|
|
||||||
.l-invalid {
|
|
||||||
background-color: #F1A69C;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-valid {
|
|
||||||
background-color: #8f7eff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-retard {
|
|
||||||
background-color: #F1D99C;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ajoutez des styles pour le conteneur de pagination et les boutons */
|
|
||||||
.pagination-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination-button {
|
|
||||||
padding: 10px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
margin: 0 5px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination-button:hover {
|
|
||||||
background-color: #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination-button.active {
|
|
||||||
background-color: #007bff;
|
|
||||||
color: #fff;
|
|
||||||
border-color: #007bff;
|
|
||||||
}
|
|
||||||
|
|
||||||
th>div {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-head {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-line {
|
|
||||||
display: flex;
|
|
||||||
justify-content: start;
|
|
||||||
align-items: center;
|
|
||||||
margin: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-line>* {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.rbtn {
|
|
||||||
width: 35px;
|
|
||||||
height: 35px;
|
|
||||||
margin: 0 5px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.f-label {
|
|
||||||
margin: 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chk {
|
|
||||||
margin-left: 2px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const etudid = {{ sco.etud.id }};
|
const etudid = {{ sco.etud.id }}
|
||||||
const paginationContainerAssiduites = document.getElementById("paginationContainerAssiduites");
|
|
||||||
const paginationContainerJustificatifs = document.getElementById("paginationContainerJustificatifs");
|
|
||||||
const itemsPerPage = 10;
|
|
||||||
let currentPageAssiduites = 1;
|
|
||||||
let currentPageJustificatifs = 1;
|
|
||||||
let orderAssiduites = true;
|
|
||||||
let orderJustificatifs = true;
|
|
||||||
|
|
||||||
let filterAssiduites = {
|
|
||||||
columns: [
|
|
||||||
"entry_date", "date_debut", "date_fin", "etat", "moduleimpl_id", "est_just"
|
|
||||||
],
|
|
||||||
filters: {}
|
|
||||||
}
|
|
||||||
let filterJustificatifs = {
|
|
||||||
columns: [
|
|
||||||
"entry_date", "date_debut", "date_fin", "etat", "raison"
|
|
||||||
],
|
|
||||||
filters: {}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tableBodyAssiduites = document.getElementById("tableBodyAssiduites");
|
|
||||||
const tableBodyJustificatifs = document.getElementById("tableBodyJustificatifs");
|
|
||||||
|
|
||||||
const contextMenu = document.getElementById("contextMenu");
|
|
||||||
const editOption = document.getElementById("editOption");
|
|
||||||
const deleteOption = document.getElementById("deleteOption");
|
|
||||||
let selectedRow;
|
|
||||||
|
|
||||||
document.addEventListener("click", () => {
|
|
||||||
contextMenu.style.display = "none";
|
|
||||||
});
|
|
||||||
|
|
||||||
editOption.addEventListener("click", () => {
|
|
||||||
if (selectedRow) {
|
|
||||||
// Code pour éditer la ligne sélectionnée
|
|
||||||
console.debug("Éditer :", selectedRow);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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") {
|
|
||||||
deleteAssiduite(obj_id);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
deleteJustificatif(obj_id);
|
|
||||||
}
|
|
||||||
loadAll();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function assiduiteCallBack(assi) {
|
|
||||||
assi = filterArray(assi, filterAssiduites.filters)
|
|
||||||
renderTableAssiduites(currentPageAssiduites, assi);
|
|
||||||
renderPaginationButtons(assi);
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterArray(array, f) {
|
|
||||||
return array.filter((el) => {
|
|
||||||
let t = Object.keys(f).every((k) => {
|
|
||||||
if (k == "etat") {
|
|
||||||
return f.etat.includes(el.etat.toLowerCase())
|
|
||||||
};
|
|
||||||
if (k == "est_just") {
|
|
||||||
if (f.est_just != "") {
|
|
||||||
return `${el.est_just}` == f.est_just;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (k.indexOf('date') != -1) {
|
|
||||||
const assi_time = moment.tz(el[k], TIMEZONE);
|
|
||||||
const filter_time = f[k].time;
|
|
||||||
switch (f[k].pref) {
|
|
||||||
|
|
||||||
case "0":
|
|
||||||
return assi_time.isSame(filter_time, 'minute');
|
|
||||||
case "-1":
|
|
||||||
return assi_time.isBefore(filter_time, 'minutes');
|
|
||||||
case "1":
|
|
||||||
return assi_time.isAfter(filter_time, 'minutes');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (k == "moduleimpl_id") {
|
|
||||||
const m = el[k] == undefined || el[k] == null ? "null" : el[k];
|
|
||||||
if (f.moduleimpl_id != '') {
|
|
||||||
return m == f.moduleimpl_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
})
|
|
||||||
|
|
||||||
return t;
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function justificatifCallBack(justi) {
|
|
||||||
justi = filterArray(justi, filterJustificatifs.filters)
|
|
||||||
renderTableJustificatifs(currentPageJustificatifs, justi);
|
|
||||||
renderPaginationButtons(justi, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const moduleimpls = {}
|
|
||||||
|
|
||||||
function getModuleImpl(id) {
|
|
||||||
if (id == null || id == undefined) {
|
|
||||||
moduleimpls[id] = "Pas de module"
|
|
||||||
}
|
|
||||||
if (id in moduleimpls) {
|
|
||||||
return moduleimpls[id];
|
|
||||||
}
|
|
||||||
const url_api = getUrl() + `/api/moduleimpl/${id}`;
|
|
||||||
sync_get(url_api, (data) => {
|
|
||||||
moduleimpls[id] = `${data.module.code} ${data.module.abbrev}`;
|
|
||||||
}, (data) => { moduleimpls[id] = "Pas de module" });
|
|
||||||
|
|
||||||
return moduleimpls[id];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateTableHead(columns, assi = true) {
|
|
||||||
const table = assi ? "#assiduiteTable" : "#justificatifTable"
|
|
||||||
const call = assi ? [assiduiteCallBack, true] : [justificatifCallBack, false]
|
|
||||||
const tr = document.querySelector(`${table} thead tr`);
|
|
||||||
|
|
||||||
tr.innerHTML = ""
|
|
||||||
|
|
||||||
columns.forEach((c) => {
|
|
||||||
const th = document.createElement('th');
|
|
||||||
const div = document.createElement('div');
|
|
||||||
|
|
||||||
const span = document.createElement('span');
|
|
||||||
span.textContent = columnTranslator(c);
|
|
||||||
|
|
||||||
const a = document.createElement('a');
|
|
||||||
a.classList.add('icon', "order");
|
|
||||||
a.onclick = () => { order(c, call[0], a, call[1]) }
|
|
||||||
|
|
||||||
div.appendChild(span)
|
|
||||||
div.appendChild(a)
|
|
||||||
|
|
||||||
th.appendChild(div);
|
|
||||||
|
|
||||||
tr.appendChild(th);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderTableAssiduites(page, assiduités) {
|
|
||||||
|
|
||||||
generateTableHead(filterAssiduites.columns, true)
|
|
||||||
|
|
||||||
tableBodyAssiduites.innerHTML = "";
|
|
||||||
const start = (page - 1) * itemsPerPage;
|
|
||||||
const end = start + itemsPerPage;
|
|
||||||
|
|
||||||
assiduités.slice(start, end).forEach((assiduite) => {
|
|
||||||
const row = document.createElement("tr");
|
|
||||||
row.setAttribute('type', "assiduite");
|
|
||||||
row.setAttribute('obj_id', assiduite.assiduite_id);
|
|
||||||
|
|
||||||
const etat = assiduite.etat.toLowerCase();
|
|
||||||
row.classList.add(`l-${etat}`);
|
|
||||||
filterAssiduites.columns.forEach((k) => {
|
|
||||||
const td = document.createElement('td');
|
|
||||||
if (k.indexOf('date') != -1) {
|
|
||||||
td.textContent = moment.tz(assiduite[k], TIMEZONE).format(`DD/MM/Y HH:mm`)
|
|
||||||
} else if (k.indexOf("module") != -1) {
|
|
||||||
td.textContent = getModuleImpl(assiduite.moduleimpl_id);
|
|
||||||
} else if (k.indexOf('est_just') != -1) {
|
|
||||||
td.textContent = assiduite[k] ? "Oui" : "Non"
|
|
||||||
} else {
|
|
||||||
td.textContent = assiduite[k].capitalize()
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
tableBodyAssiduites.appendChild(row);
|
|
||||||
});
|
|
||||||
updateActivePaginationButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderTableJustificatifs(page, justificatifs) {
|
|
||||||
generateTableHead(filterJustificatifs.columns, false)
|
|
||||||
|
|
||||||
tableBodyJustificatifs.innerHTML = "";
|
|
||||||
const start = (page - 1) * itemsPerPage;
|
|
||||||
const end = start + itemsPerPage;
|
|
||||||
|
|
||||||
justificatifs.slice(start, end).forEach((justificatif) => {
|
|
||||||
const row = document.createElement("tr");
|
|
||||||
row.setAttribute('type', "justificatif");
|
|
||||||
row.setAttribute('obj_id', justificatif.justif_id);
|
|
||||||
|
|
||||||
const etat = justificatif.etat.toLowerCase();
|
|
||||||
|
|
||||||
if (etat == "valide") {
|
|
||||||
row.classList.add(`l-valid`);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
row.classList.add(`l-invalid`);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
filterJustificatifs.columns.forEach((k) => {
|
|
||||||
const td = document.createElement('td');
|
|
||||||
if (k.indexOf('date') != -1) {
|
|
||||||
td.textContent = moment.tz(justificatif[k], TIMEZONE).format(`DD/MM/Y HH:mm`)
|
|
||||||
} else {
|
|
||||||
td.textContent = justificatif[k].capitalize()
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
tableBodyJustificatifs.appendChild(row);
|
|
||||||
});
|
|
||||||
updateActivePaginationButton(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderPaginationButtons(array, assi = true) {
|
|
||||||
const totalPages = Math.ceil(array.length / itemsPerPage);
|
|
||||||
|
|
||||||
if (assi) {
|
|
||||||
paginationContainerAssiduites.innerHTML = ""
|
|
||||||
} else {
|
|
||||||
paginationContainerJustificatifs.innerHTML = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
renderTableAssiduites(currentPageAssiduites, array);
|
|
||||||
});
|
|
||||||
paginationContainerAssiduites.appendChild(paginationButton);
|
|
||||||
} else {
|
|
||||||
paginationButton.addEventListener("click", () => {
|
|
||||||
currentPageJustificatifs = i;
|
|
||||||
renderTableAssiduites(currentPageJustificatifs, array);
|
|
||||||
});
|
|
||||||
paginationContainerJustificatifs.appendChild(paginationButton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateActivePaginationButton(assi);
|
|
||||||
}
|
|
||||||
function updateActivePaginationButton(assi = true) {
|
|
||||||
if (assi) {
|
|
||||||
const paginationButtons =
|
|
||||||
paginationContainerAssiduites.querySelectorAll("#paginationContainerAssiduites .pagination-button");
|
|
||||||
paginationButtons.forEach((button) => {
|
|
||||||
if (parseInt(button.textContent) === currentPageAssiduites) {
|
|
||||||
button.classList.add("active");
|
|
||||||
} else {
|
|
||||||
button.classList.remove("active");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const paginationButtons =
|
|
||||||
paginationContainerJustificatifs.querySelectorAll("#paginationContainerJustificatifs .pagination-button");
|
|
||||||
paginationButtons.forEach((button) => {
|
|
||||||
if (parseInt(button.textContent) === currentPageJustificatifs) {
|
|
||||||
button.classList.add("active");
|
|
||||||
} else {
|
|
||||||
button.classList.remove("active");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadAll() {
|
|
||||||
getAllAssiduitesFromEtud(etudid, assiduiteCallBack)
|
|
||||||
|
|
||||||
getAllJustificatifsFromEtud(etudid, justificatifCallBack)
|
|
||||||
}
|
|
||||||
|
|
||||||
function order(keyword, callback = () => { }, el, assi = true) {
|
|
||||||
const call = (array, ordered) => {
|
|
||||||
const sorted = array.sort((a, b) => {
|
|
||||||
let keyValueA = a[keyword];
|
|
||||||
let keyValueB = b[keyword];
|
|
||||||
|
|
||||||
if (keyword.indexOf("date") != -1) {
|
|
||||||
keyValueA = moment.tz(keyValueA, TIMEZONE)
|
|
||||||
keyValueB = moment.tz(keyValueB, TIMEZONE)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyword.indexOf("module") != -1) {
|
|
||||||
keyValueA = getModuleImpl(keyValueA);
|
|
||||||
keyValueB = getModuleImpl(keyValueB);
|
|
||||||
}
|
|
||||||
|
|
||||||
let orderDertermined = keyValueA > keyValueB;
|
|
||||||
|
|
||||||
if (!ordered) {
|
|
||||||
orderDertermined = keyValueA < keyValueB;
|
|
||||||
}
|
|
||||||
return orderDertermined
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
callback(sorted);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
if (assi) {
|
|
||||||
orderAssiduites = !orderAssiduites;
|
|
||||||
getAllAssiduitesFromEtud(etudid, (a) => { call(a, orderAssiduites) })
|
|
||||||
} else {
|
|
||||||
orderJustificatifs = !orderJustificatifs;
|
|
||||||
getAllJustificatifsFromEtud(etudid, (a) => { call(a, orderJustificatifs) })
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function filter(assi = true) {
|
|
||||||
if (assi) {
|
|
||||||
let html = `
|
|
||||||
<div class="filter-body">
|
|
||||||
<h3>Affichage des colonnes:</h3>
|
|
||||||
<div class="filter-head">
|
|
||||||
<label>
|
|
||||||
Date de saisie
|
|
||||||
<input class="chk" type="checkbox" name="entry_date" id="entry_date">
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Date de Début
|
|
||||||
<input class="chk" type="checkbox" name="date_debut" id="date_debut" checked>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Date de Fin
|
|
||||||
<input class="chk" type="checkbox" name="date_fin" id="date_fin" checked>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Etat
|
|
||||||
<input class="chk" type="checkbox" name="etat" id="etat" checked>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Module
|
|
||||||
<input class="chk" type="checkbox" name="moduleimpl_id" id="moduleimpl_id" checked>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Justifiée
|
|
||||||
<input class="chk" type="checkbox" name="est_just" id="est_just" checked>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<h3>Filtrage des colonnes:</h3>
|
|
||||||
<span class="filter-line">
|
|
||||||
<span class="filter-title" for="entry_date">Date de saisie</span>
|
|
||||||
<select name="entry_date_pref" id="entry_date_pref">
|
|
||||||
<option value="-1">Avant</option>
|
|
||||||
<option value="0">Égal</option>
|
|
||||||
<option value="1">Après</option>
|
|
||||||
</select>
|
|
||||||
<input type="datetime-local" name="entry_date_time" id="entry_date_time">
|
|
||||||
</span>
|
|
||||||
<span class="filter-line">
|
|
||||||
<span class="filter-title" for="date_debut">Date de début</span>
|
|
||||||
<select name="date_debut_pref" id="date_debut_pref">
|
|
||||||
<option value="-1">Avant</option>
|
|
||||||
<option value="0">Égal</option>
|
|
||||||
<option value="1">Après</option>
|
|
||||||
</select>
|
|
||||||
<input type="datetime-local" name="date_debut_time" id="date_debut_time">
|
|
||||||
</span>
|
|
||||||
<span class="filter-line">
|
|
||||||
<span class="filter-title" for="date_fin">Date de fin</span>
|
|
||||||
<select name="date_fin_pref" id="date_fin_pref">
|
|
||||||
<option value="-1">Avant</option>
|
|
||||||
<option value="0">Égal</option>
|
|
||||||
<option value="1">Après</option>
|
|
||||||
</select>
|
|
||||||
<input type="datetime-local" name="date_fin_time" id="date_fin_time">
|
|
||||||
</span>
|
|
||||||
<span class="filter-line">
|
|
||||||
<span class="filter-title" for="etat">Etat</span>
|
|
||||||
<input checked type="checkbox" name="etat_present" id="etat_present" class="rbtn present" value="present">
|
|
||||||
<input checked type="checkbox" name="etat_retard" id="etat_retard" class="rbtn retard" value="retard">
|
|
||||||
<input checked type="checkbox" name="etat_absent" id="etat_absent" class="rbtn absent" value="absent">
|
|
||||||
</span>
|
|
||||||
<span class="filter-line">
|
|
||||||
<span class="filter-title" for="moduleimpl_id">Module</span>
|
|
||||||
<select id="moduleimpl_id">
|
|
||||||
<option value="">Pas de filtre</option>
|
|
||||||
</select>
|
|
||||||
</span>
|
|
||||||
<span class="filter-line">
|
|
||||||
<span class="filter-title" for="est_just">Est Justifiée</span>
|
|
||||||
<select id="est_just">
|
|
||||||
<option value="">Pas de filtre</option>
|
|
||||||
<option value="true">Oui</option>
|
|
||||||
<option value="false">Non</option>
|
|
||||||
</select>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
const span = document.createElement('span');
|
|
||||||
span.innerHTML = html
|
|
||||||
html = span.firstElementChild
|
|
||||||
|
|
||||||
const filterHead = html.querySelector('.filter-head');
|
|
||||||
filterHead.innerHTML = ""
|
|
||||||
let cols = ["entry_date", "date_debut", "date_fin", "etat", "moduleimpl_id", "est_just"];
|
|
||||||
|
|
||||||
cols.forEach((k) => {
|
|
||||||
const label = document.createElement('label')
|
|
||||||
label.classList.add('f-label')
|
|
||||||
const s = document.createElement('span');
|
|
||||||
s.textContent = columnTranslator(k);
|
|
||||||
|
|
||||||
|
|
||||||
const input = document.createElement('input');
|
|
||||||
input.classList.add('chk')
|
|
||||||
input.type = "checkbox"
|
|
||||||
input.name = k
|
|
||||||
input.id = k;
|
|
||||||
input.checked = filterAssiduites.columns.includes(k)
|
|
||||||
|
|
||||||
label.appendChild(s)
|
|
||||||
label.appendChild(input)
|
|
||||||
filterHead.appendChild(label)
|
|
||||||
})
|
|
||||||
|
|
||||||
const sl = html.querySelector('.filter-line #moduleimpl_id');
|
|
||||||
let opts = []
|
|
||||||
Object.keys(moduleimpls).forEach((k) => {
|
|
||||||
const opt = document.createElement('option');
|
|
||||||
opt.value = k == null ? "null" : k;
|
|
||||||
opt.textContent = moduleimpls[k];
|
|
||||||
opts.push(opt);
|
|
||||||
})
|
|
||||||
|
|
||||||
opts = opts.sort((a, b) => {
|
|
||||||
return a.value < b.value
|
|
||||||
})
|
|
||||||
|
|
||||||
sl.append(...opts);
|
|
||||||
|
|
||||||
// Mise à jour des filtres
|
|
||||||
|
|
||||||
Object.keys(filterAssiduites.filters).forEach((key) => {
|
|
||||||
const l = html.querySelector(`.filter-title[for="${key}"]`).parentElement;
|
|
||||||
if (key.indexOf('date') != -1) {
|
|
||||||
l.querySelector(`#${key}_pref`).value = filterAssiduites.filters[key].pref;
|
|
||||||
l.querySelector(`#${key}_time`).value = filterAssiduites.filters[key].time.format("YYYY-MM-DDTHH:mm");
|
|
||||||
|
|
||||||
} else if (key.indexOf('etat') != -1) {
|
|
||||||
l.querySelectorAll('input').forEach((e) => {
|
|
||||||
e.checked = filterAssiduites.filters[key].includes(e.value)
|
|
||||||
})
|
|
||||||
} else if (key.indexOf("module") != -1) {
|
|
||||||
l.querySelector('#moduleimpl_id').value = filterAssiduites.filters[key];
|
|
||||||
} else if (key.indexOf("est_just") != -1) {
|
|
||||||
l.querySelector('#est_just').value = filterAssiduites.filters[key];
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
openPromptModal("Filtrage des assiduités", html, () => {
|
|
||||||
|
|
||||||
const columns = [...document.querySelectorAll('.chk')]
|
|
||||||
.map((el) => { if (el.checked) return el.id })
|
|
||||||
.filter((el) => el)
|
|
||||||
|
|
||||||
filterAssiduites.columns = columns
|
|
||||||
filterAssiduites.filters = {}
|
|
||||||
//reste des filtres
|
|
||||||
|
|
||||||
const lines = [...document.querySelectorAll('.filter-line')];
|
|
||||||
|
|
||||||
lines.forEach((l) => {
|
|
||||||
const key = l.querySelector('.filter-title').getAttribute('for');
|
|
||||||
|
|
||||||
if (key.indexOf('date') != -1) {
|
|
||||||
const pref = l.querySelector(`#${key}_pref`).value;
|
|
||||||
const time = l.querySelector(`#${key}_time`).value;
|
|
||||||
if (l.querySelector(`#${key}_time`).value != "") {
|
|
||||||
filterAssiduites.filters[key] = {
|
|
||||||
pref: pref,
|
|
||||||
time: new moment.tz(time, TIMEZONE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (key.indexOf('etat') != -1) {
|
|
||||||
filterAssiduites.filters[key] = [...l.querySelectorAll("input:checked")].map((e) => e.value);
|
|
||||||
} else if (key.indexOf("module") != -1) {
|
|
||||||
filterAssiduites.filters[key] = l.querySelector('#moduleimpl_id').value;
|
|
||||||
} else if (key.indexOf("est_just") != -1) {
|
|
||||||
filterAssiduites.filters[key] = l.querySelector('#est_just').value;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
getAllAssiduitesFromEtud(etudid, assiduiteCallBack)
|
|
||||||
|
|
||||||
}, () => { }, "#7059FF");
|
|
||||||
} else {
|
|
||||||
let html = `
|
|
||||||
<div class="filter-body">
|
|
||||||
<h3>Affichage des colonnes:</h3>
|
|
||||||
<div class="filter-head">
|
|
||||||
<label>
|
|
||||||
Date de saisie
|
|
||||||
<input class="chk" type="checkbox" name="entry_date" id="entry_date">
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Date de Début
|
|
||||||
<input class="chk" type="checkbox" name="date_debut" id="date_debut" checked>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Date de Fin
|
|
||||||
<input class="chk" type="checkbox" name="date_fin" id="date_fin" checked>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Etat
|
|
||||||
<input class="chk" type="checkbox" name="etat" id="etat" checked>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Raison
|
|
||||||
<input class="chk" type="checkbox" name="raison" id="raison" checked>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<h3>Filtrage des colonnes:</h3>
|
|
||||||
<span class="filter-line">
|
|
||||||
<span class="filter-title" for="entry_date">Date de saisie</span>
|
|
||||||
<select name="entry_date_pref" id="entry_date_pref">
|
|
||||||
<option value="-1">Avant</option>
|
|
||||||
<option value="0">Égal</option>
|
|
||||||
<option value="1">Après</option>
|
|
||||||
</select>
|
|
||||||
<input type="datetime-local" name="entry_date_time" id="entry_date_time">
|
|
||||||
</span>
|
|
||||||
<span class="filter-line">
|
|
||||||
<span class="filter-title" for="date_debut">Date de début</span>
|
|
||||||
<select name="date_debut_pref" id="date_debut_pref">
|
|
||||||
<option value="-1">Avant</option>
|
|
||||||
<option value="0">Égal</option>
|
|
||||||
<option value="1">Après</option>
|
|
||||||
</select>
|
|
||||||
<input type="datetime-local" name="date_debut_time" id="date_debut_time">
|
|
||||||
</span>
|
|
||||||
<span class="filter-line">
|
|
||||||
<span class="filter-title" for="date_fin">Date de fin</span>
|
|
||||||
<select name="date_fin_pref" id="date_fin_pref">
|
|
||||||
<option value="-1">Avant</option>
|
|
||||||
<option value="0">Égal</option>
|
|
||||||
<option value="1">Après</option>
|
|
||||||
</select>
|
|
||||||
<input type="datetime-local" name="date_fin_time" id="date_fin_time">
|
|
||||||
</span>
|
|
||||||
<span class="filter-line">
|
|
||||||
<span class="filter-title" for="etat">Etat</span>
|
|
||||||
<label>
|
|
||||||
Valide
|
|
||||||
<input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="valide">
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Non Valide
|
|
||||||
<input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="non_valide">
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
En Attente
|
|
||||||
<input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="attente">
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Modifié
|
|
||||||
<input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="modifie">
|
|
||||||
</label>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
const span = document.createElement('span');
|
|
||||||
span.innerHTML = html
|
|
||||||
html = span.firstElementChild
|
|
||||||
|
|
||||||
const filterHead = html.querySelector('.filter-head');
|
|
||||||
filterHead.innerHTML = ""
|
|
||||||
let cols = ["entry_date", "date_debut", "date_fin", "etat", "raison"];
|
|
||||||
|
|
||||||
cols.forEach((k) => {
|
|
||||||
const label = document.createElement('label')
|
|
||||||
label.classList.add('f-label')
|
|
||||||
const s = document.createElement('span');
|
|
||||||
s.textContent = columnTranslator(k);
|
|
||||||
|
|
||||||
|
|
||||||
const input = document.createElement('input');
|
|
||||||
input.classList.add('chk')
|
|
||||||
input.type = "checkbox"
|
|
||||||
input.name = k
|
|
||||||
input.id = k;
|
|
||||||
input.checked = filterJustificatifs.columns.includes(k)
|
|
||||||
|
|
||||||
label.appendChild(s)
|
|
||||||
label.appendChild(input)
|
|
||||||
filterHead.appendChild(label)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Mise à jour des filtres
|
|
||||||
|
|
||||||
Object.keys(filterJustificatifs.filters).forEach((key) => {
|
|
||||||
const l = html.querySelector(`.filter-title[for="${key}"]`).parentElement;
|
|
||||||
if (key.indexOf('date') != -1) {
|
|
||||||
l.querySelector(`#${key}_pref`).value = filterJustificatifs.filters[key].pref;
|
|
||||||
l.querySelector(`#${key}_time`).value = filterJustificatifs.filters[key].time.format("YYYY-MM-DDTHH:mm");
|
|
||||||
|
|
||||||
} else if (key.indexOf('etat') != -1) {
|
|
||||||
l.querySelectorAll('input').forEach((e) => {
|
|
||||||
e.checked = filterJustificatifs.filters[key].includes(e.value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
openPromptModal("Filtrage des Justificatifs", html, () => {
|
|
||||||
|
|
||||||
const columns = [...document.querySelectorAll('.chk')]
|
|
||||||
.map((el) => { if (el.checked) return el.id })
|
|
||||||
.filter((el) => el)
|
|
||||||
|
|
||||||
filterJustificatifs.columns = columns
|
|
||||||
filterJustificatifs.filters = {}
|
|
||||||
//reste des filtres
|
|
||||||
|
|
||||||
const lines = [...document.querySelectorAll('.filter-line')];
|
|
||||||
|
|
||||||
lines.forEach((l) => {
|
|
||||||
const key = l.querySelector('.filter-title').getAttribute('for');
|
|
||||||
|
|
||||||
if (key.indexOf('date') != -1) {
|
|
||||||
const pref = l.querySelector(`#${key}_pref`).value;
|
|
||||||
const time = l.querySelector(`#${key}_time`).value;
|
|
||||||
if (l.querySelector(`#${key}_time`).value != "") {
|
|
||||||
filterJustificatifs.filters[key] = {
|
|
||||||
pref: pref,
|
|
||||||
time: new moment.tz(time, TIMEZONE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (key.indexOf('etat') != -1) {
|
|
||||||
filterJustificatifs.filters[key] = [...l.querySelectorAll("input:checked")].map((e) => e.value);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
getAllJustificatifsFromEtud(etudid, justificatifCallBack)
|
|
||||||
|
|
||||||
}, () => { }, "#7059FF");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function columnTranslator(colName) {
|
|
||||||
switch (colName) {
|
|
||||||
case "date_debut":
|
|
||||||
return "Début";
|
|
||||||
case "entry_date":
|
|
||||||
return "Saisie le";
|
|
||||||
case "date_fin":
|
|
||||||
return "Fin";
|
|
||||||
case "etat":
|
|
||||||
return "État";
|
|
||||||
case "moduleimpl_id":
|
|
||||||
return "Module";
|
|
||||||
case "est_just":
|
|
||||||
return "Justifiée";
|
|
||||||
case "raison":
|
|
||||||
return "Raison";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onload = () => {
|
window.onload = () => {
|
||||||
loadAll();
|
loadAll();
|
||||||
}
|
}
|
||||||
|
122
app/templates/assiduites/widgets/tableau_assi.j2
Normal file
122
app/templates/assiduites/widgets/tableau_assi.j2
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
<table id="assiduiteTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<div>
|
||||||
|
<span>Début</span>
|
||||||
|
<a class="icon order" onclick="order('date_debut', assiduiteCallBack, this)"></a>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<div>
|
||||||
|
<span>Fin</span>
|
||||||
|
<a class="icon order" onclick="order('date_fin', assiduiteCallBack, this)"></a>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<div>
|
||||||
|
<span>État</span>
|
||||||
|
<a class="icon order" onclick="order('etat', assiduiteCallBack, this)"></a>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<div>
|
||||||
|
<span>Module</span>
|
||||||
|
<a class="icon order" onclick="order('moduleimpl_id', assiduiteCallBack, this)"></a>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<div>
|
||||||
|
<span>Justifiée</span>
|
||||||
|
<a class="icon order" onclick="order('est_just', assiduiteCallBack, this)"></a>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="tableBodyAssiduites">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div id="paginationContainerAssiduites" class="pagination-container">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const paginationContainerAssiduites = document.getElementById("paginationContainerAssiduites");
|
||||||
|
let currentPageAssiduites = 1;
|
||||||
|
let orderAssiduites = true;
|
||||||
|
let filterAssiduites = {
|
||||||
|
columns: [
|
||||||
|
"entry_date", "date_debut", "date_fin", "etat", "moduleimpl_id", "est_just"
|
||||||
|
],
|
||||||
|
filters: {}
|
||||||
|
}
|
||||||
|
const tableBodyAssiduites = document.getElementById("tableBodyAssiduites");
|
||||||
|
|
||||||
|
function assiduiteCallBack(assi) {
|
||||||
|
assi = filterArray(assi, filterAssiduites.filters)
|
||||||
|
renderTableAssiduites(currentPageAssiduites, assi);
|
||||||
|
renderPaginationButtons(assi);
|
||||||
|
}
|
||||||
|
|
||||||
|
const moduleimpls = {}
|
||||||
|
|
||||||
|
function getModuleImpl(id) {
|
||||||
|
if (id == null || id == undefined) {
|
||||||
|
moduleimpls[id] = "Pas de module"
|
||||||
|
}
|
||||||
|
if (id in moduleimpls) {
|
||||||
|
return moduleimpls[id];
|
||||||
|
}
|
||||||
|
const url_api = getUrl() + `/api/moduleimpl/${id}`;
|
||||||
|
sync_get(url_api, (data) => {
|
||||||
|
moduleimpls[id] = `${data.module.code} ${data.module.abbrev}`;
|
||||||
|
}, (data) => { moduleimpls[id] = "Pas de module" });
|
||||||
|
|
||||||
|
return moduleimpls[id];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTableAssiduites(page, assiduités) {
|
||||||
|
|
||||||
|
generateTableHead(filterAssiduites.columns, true)
|
||||||
|
|
||||||
|
tableBodyAssiduites.innerHTML = "";
|
||||||
|
const start = (page - 1) * itemsPerPage;
|
||||||
|
const end = start + itemsPerPage;
|
||||||
|
|
||||||
|
assiduités.slice(start, end).forEach((assiduite) => {
|
||||||
|
const row = document.createElement("tr");
|
||||||
|
row.setAttribute('type', "assiduite");
|
||||||
|
row.setAttribute('obj_id', assiduite.assiduite_id);
|
||||||
|
|
||||||
|
const etat = assiduite.etat.toLowerCase();
|
||||||
|
row.classList.add(`l-${etat}`);
|
||||||
|
filterAssiduites.columns.forEach((k) => {
|
||||||
|
const td = document.createElement('td');
|
||||||
|
if (k.indexOf('date') != -1) {
|
||||||
|
td.textContent = moment.tz(assiduite[k], TIMEZONE).format(`DD/MM/Y HH:mm`)
|
||||||
|
} else if (k.indexOf("module") != -1) {
|
||||||
|
td.textContent = getModuleImpl(assiduite.moduleimpl_id);
|
||||||
|
} else if (k.indexOf('est_just') != -1) {
|
||||||
|
td.textContent = assiduite[k] ? "Oui" : "Non"
|
||||||
|
} else {
|
||||||
|
td.textContent = assiduite[k].capitalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
tableBodyAssiduites.appendChild(row);
|
||||||
|
});
|
||||||
|
updateActivePaginationButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
724
app/templates/assiduites/widgets/tableau_base.j2
Normal file
724
app/templates/assiduites/widgets/tableau_base.j2
Normal file
@ -0,0 +1,724 @@
|
|||||||
|
<ul id="contextMenu" class="context-menu">
|
||||||
|
<li id="detailOption">Detail</li>
|
||||||
|
<li id="editOption">Editer</li>
|
||||||
|
<li id="deleteOption">Supprimer</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% include "assiduites/widgets/alert.j2" %}
|
||||||
|
{% include "assiduites/widgets/prompt.j2" %}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const itemsPerPage = 10;
|
||||||
|
const contextMenu = document.getElementById("contextMenu");
|
||||||
|
const editOption = document.getElementById("editOption");
|
||||||
|
const deleteOption = document.getElementById("deleteOption");
|
||||||
|
|
||||||
|
let selectedRow;
|
||||||
|
|
||||||
|
document.addEventListener("click", () => {
|
||||||
|
contextMenu.style.display = "none";
|
||||||
|
});
|
||||||
|
|
||||||
|
editOption.addEventListener("click", () => {
|
||||||
|
if (selectedRow) {
|
||||||
|
// Code pour éditer la ligne sélectionnée
|
||||||
|
console.debug("Éditer :", selectedRow);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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") {
|
||||||
|
deleteAssiduite(obj_id);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
deleteJustificatif(obj_id);
|
||||||
|
}
|
||||||
|
loadAll();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function filterArray(array, f) {
|
||||||
|
return array.filter((el) => {
|
||||||
|
let t = Object.keys(f).every((k) => {
|
||||||
|
if (k == "etat") {
|
||||||
|
return f.etat.includes(el.etat.toLowerCase())
|
||||||
|
};
|
||||||
|
if (k == "est_just") {
|
||||||
|
if (f.est_just != "") {
|
||||||
|
return `${el.est_just}` == f.est_just;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (k.indexOf('date') != -1) {
|
||||||
|
const assi_time = moment.tz(el[k], TIMEZONE);
|
||||||
|
const filter_time = f[k].time;
|
||||||
|
switch (f[k].pref) {
|
||||||
|
|
||||||
|
case "0":
|
||||||
|
return assi_time.isSame(filter_time, 'minute');
|
||||||
|
case "-1":
|
||||||
|
return assi_time.isBefore(filter_time, 'minutes');
|
||||||
|
case "1":
|
||||||
|
return assi_time.isAfter(filter_time, 'minutes');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k == "moduleimpl_id") {
|
||||||
|
const m = el[k] == undefined || el[k] == null ? "null" : el[k];
|
||||||
|
if (f.moduleimpl_id != '') {
|
||||||
|
return m == f.moduleimpl_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
|
||||||
|
return t;
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateTableHead(columns, assi = true) {
|
||||||
|
const table = assi ? "#assiduiteTable" : "#justificatifTable"
|
||||||
|
const call = assi ? [assiduiteCallBack, true] : [justificatifCallBack, false]
|
||||||
|
const tr = document.querySelector(`${table} thead tr`);
|
||||||
|
|
||||||
|
tr.innerHTML = ""
|
||||||
|
|
||||||
|
columns.forEach((c) => {
|
||||||
|
const th = document.createElement('th');
|
||||||
|
const div = document.createElement('div');
|
||||||
|
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.textContent = columnTranslator(c);
|
||||||
|
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.classList.add('icon', "order");
|
||||||
|
a.onclick = () => { order(c, call[0], a, call[1]) }
|
||||||
|
|
||||||
|
div.appendChild(span)
|
||||||
|
div.appendChild(a)
|
||||||
|
|
||||||
|
th.appendChild(div);
|
||||||
|
|
||||||
|
tr.appendChild(th);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPaginationButtons(array, assi = true) {
|
||||||
|
const totalPages = Math.ceil(array.length / itemsPerPage);
|
||||||
|
|
||||||
|
if (assi) {
|
||||||
|
paginationContainerAssiduites.innerHTML = ""
|
||||||
|
} else {
|
||||||
|
paginationContainerJustificatifs.innerHTML = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
renderTableAssiduites(currentPageAssiduites, array);
|
||||||
|
});
|
||||||
|
paginationContainerAssiduites.appendChild(paginationButton);
|
||||||
|
} else {
|
||||||
|
paginationButton.addEventListener("click", () => {
|
||||||
|
currentPageJustificatifs = i;
|
||||||
|
renderTableAssiduites(currentPageJustificatifs, array);
|
||||||
|
});
|
||||||
|
paginationContainerJustificatifs.appendChild(paginationButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateActivePaginationButton(assi);
|
||||||
|
}
|
||||||
|
function updateActivePaginationButton(assi = true) {
|
||||||
|
if (assi) {
|
||||||
|
const paginationButtons =
|
||||||
|
paginationContainerAssiduites.querySelectorAll("#paginationContainerAssiduites .pagination-button");
|
||||||
|
paginationButtons.forEach((button) => {
|
||||||
|
if (parseInt(button.textContent) === currentPageAssiduites) {
|
||||||
|
button.classList.add("active");
|
||||||
|
} else {
|
||||||
|
button.classList.remove("active");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const paginationButtons =
|
||||||
|
paginationContainerJustificatifs.querySelectorAll("#paginationContainerJustificatifs .pagination-button");
|
||||||
|
paginationButtons.forEach((button) => {
|
||||||
|
if (parseInt(button.textContent) === currentPageJustificatifs) {
|
||||||
|
button.classList.add("active");
|
||||||
|
} else {
|
||||||
|
button.classList.remove("active");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadAll() {
|
||||||
|
try { getAllAssiduitesFromEtud(etudid, assiduiteCallBack) } catch (_) { }
|
||||||
|
try { getAllJustificatifsFromEtud(etudid, justificatifCallBack) } catch (_) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
function order(keyword, callback = () => { }, el, assi = true) {
|
||||||
|
const call = (array, ordered) => {
|
||||||
|
const sorted = array.sort((a, b) => {
|
||||||
|
let keyValueA = a[keyword];
|
||||||
|
let keyValueB = b[keyword];
|
||||||
|
|
||||||
|
if (keyword.indexOf("date") != -1) {
|
||||||
|
keyValueA = moment.tz(keyValueA, TIMEZONE)
|
||||||
|
keyValueB = moment.tz(keyValueB, TIMEZONE)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyword.indexOf("module") != -1) {
|
||||||
|
keyValueA = getModuleImpl(keyValueA);
|
||||||
|
keyValueB = getModuleImpl(keyValueB);
|
||||||
|
}
|
||||||
|
|
||||||
|
let orderDertermined = keyValueA > keyValueB;
|
||||||
|
|
||||||
|
if (!ordered) {
|
||||||
|
orderDertermined = keyValueA < keyValueB;
|
||||||
|
}
|
||||||
|
return orderDertermined
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
callback(sorted);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if (assi) {
|
||||||
|
orderAssiduites = !orderAssiduites;
|
||||||
|
getAllAssiduitesFromEtud(etudid, (a) => { call(a, orderAssiduites) })
|
||||||
|
} else {
|
||||||
|
orderJustificatifs = !orderJustificatifs;
|
||||||
|
getAllJustificatifsFromEtud(etudid, (a) => { call(a, orderJustificatifs) })
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter(assi = true) {
|
||||||
|
if (assi) {
|
||||||
|
let html = `
|
||||||
|
<div class="filter-body">
|
||||||
|
<h3>Affichage des colonnes:</h3>
|
||||||
|
<div class="filter-head">
|
||||||
|
<label>
|
||||||
|
Date de saisie
|
||||||
|
<input class="chk" type="checkbox" name="entry_date" id="entry_date">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Date de Début
|
||||||
|
<input class="chk" type="checkbox" name="date_debut" id="date_debut" checked>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Date de Fin
|
||||||
|
<input class="chk" type="checkbox" name="date_fin" id="date_fin" checked>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Etat
|
||||||
|
<input class="chk" type="checkbox" name="etat" id="etat" checked>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Module
|
||||||
|
<input class="chk" type="checkbox" name="moduleimpl_id" id="moduleimpl_id" checked>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Justifiée
|
||||||
|
<input class="chk" type="checkbox" name="est_just" id="est_just" checked>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<h3>Filtrage des colonnes:</h3>
|
||||||
|
<span class="filter-line">
|
||||||
|
<span class="filter-title" for="entry_date">Date de saisie</span>
|
||||||
|
<select name="entry_date_pref" id="entry_date_pref">
|
||||||
|
<option value="-1">Avant</option>
|
||||||
|
<option value="0">Égal</option>
|
||||||
|
<option value="1">Après</option>
|
||||||
|
</select>
|
||||||
|
<input type="datetime-local" name="entry_date_time" id="entry_date_time">
|
||||||
|
</span>
|
||||||
|
<span class="filter-line">
|
||||||
|
<span class="filter-title" for="date_debut">Date de début</span>
|
||||||
|
<select name="date_debut_pref" id="date_debut_pref">
|
||||||
|
<option value="-1">Avant</option>
|
||||||
|
<option value="0">Égal</option>
|
||||||
|
<option value="1">Après</option>
|
||||||
|
</select>
|
||||||
|
<input type="datetime-local" name="date_debut_time" id="date_debut_time">
|
||||||
|
</span>
|
||||||
|
<span class="filter-line">
|
||||||
|
<span class="filter-title" for="date_fin">Date de fin</span>
|
||||||
|
<select name="date_fin_pref" id="date_fin_pref">
|
||||||
|
<option value="-1">Avant</option>
|
||||||
|
<option value="0">Égal</option>
|
||||||
|
<option value="1">Après</option>
|
||||||
|
</select>
|
||||||
|
<input type="datetime-local" name="date_fin_time" id="date_fin_time">
|
||||||
|
</span>
|
||||||
|
<span class="filter-line">
|
||||||
|
<span class="filter-title" for="etat">Etat</span>
|
||||||
|
<input checked type="checkbox" name="etat_present" id="etat_present" class="rbtn present" value="present">
|
||||||
|
<input checked type="checkbox" name="etat_retard" id="etat_retard" class="rbtn retard" value="retard">
|
||||||
|
<input checked type="checkbox" name="etat_absent" id="etat_absent" class="rbtn absent" value="absent">
|
||||||
|
</span>
|
||||||
|
<span class="filter-line">
|
||||||
|
<span class="filter-title" for="moduleimpl_id">Module</span>
|
||||||
|
<select id="moduleimpl_id">
|
||||||
|
<option value="">Pas de filtre</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
<span class="filter-line">
|
||||||
|
<span class="filter-title" for="est_just">Est Justifiée</span>
|
||||||
|
<select id="est_just">
|
||||||
|
<option value="">Pas de filtre</option>
|
||||||
|
<option value="true">Oui</option>
|
||||||
|
<option value="false">Non</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.innerHTML = html
|
||||||
|
html = span.firstElementChild
|
||||||
|
|
||||||
|
const filterHead = html.querySelector('.filter-head');
|
||||||
|
filterHead.innerHTML = ""
|
||||||
|
let cols = ["entry_date", "date_debut", "date_fin", "etat", "moduleimpl_id", "est_just"];
|
||||||
|
|
||||||
|
cols.forEach((k) => {
|
||||||
|
const label = document.createElement('label')
|
||||||
|
label.classList.add('f-label')
|
||||||
|
const s = document.createElement('span');
|
||||||
|
s.textContent = columnTranslator(k);
|
||||||
|
|
||||||
|
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.classList.add('chk')
|
||||||
|
input.type = "checkbox"
|
||||||
|
input.name = k
|
||||||
|
input.id = k;
|
||||||
|
input.checked = filterAssiduites.columns.includes(k)
|
||||||
|
|
||||||
|
label.appendChild(s)
|
||||||
|
label.appendChild(input)
|
||||||
|
filterHead.appendChild(label)
|
||||||
|
})
|
||||||
|
|
||||||
|
const sl = html.querySelector('.filter-line #moduleimpl_id');
|
||||||
|
let opts = []
|
||||||
|
Object.keys(moduleimpls).forEach((k) => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = k == null ? "null" : k;
|
||||||
|
opt.textContent = moduleimpls[k];
|
||||||
|
opts.push(opt);
|
||||||
|
})
|
||||||
|
|
||||||
|
opts = opts.sort((a, b) => {
|
||||||
|
return a.value < b.value
|
||||||
|
})
|
||||||
|
|
||||||
|
sl.append(...opts);
|
||||||
|
|
||||||
|
// Mise à jour des filtres
|
||||||
|
|
||||||
|
Object.keys(filterAssiduites.filters).forEach((key) => {
|
||||||
|
const l = html.querySelector(`.filter-title[for="${key}"]`).parentElement;
|
||||||
|
if (key.indexOf('date') != -1) {
|
||||||
|
l.querySelector(`#${key}_pref`).value = filterAssiduites.filters[key].pref;
|
||||||
|
l.querySelector(`#${key}_time`).value = filterAssiduites.filters[key].time.format("YYYY-MM-DDTHH:mm");
|
||||||
|
|
||||||
|
} else if (key.indexOf('etat') != -1) {
|
||||||
|
l.querySelectorAll('input').forEach((e) => {
|
||||||
|
e.checked = filterAssiduites.filters[key].includes(e.value)
|
||||||
|
})
|
||||||
|
} else if (key.indexOf("module") != -1) {
|
||||||
|
l.querySelector('#moduleimpl_id').value = filterAssiduites.filters[key];
|
||||||
|
} else if (key.indexOf("est_just") != -1) {
|
||||||
|
l.querySelector('#est_just').value = filterAssiduites.filters[key];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
openPromptModal("Filtrage des assiduités", html, () => {
|
||||||
|
|
||||||
|
const columns = [...document.querySelectorAll('.chk')]
|
||||||
|
.map((el) => { if (el.checked) return el.id })
|
||||||
|
.filter((el) => el)
|
||||||
|
|
||||||
|
filterAssiduites.columns = columns
|
||||||
|
filterAssiduites.filters = {}
|
||||||
|
//reste des filtres
|
||||||
|
|
||||||
|
const lines = [...document.querySelectorAll('.filter-line')];
|
||||||
|
|
||||||
|
lines.forEach((l) => {
|
||||||
|
const key = l.querySelector('.filter-title').getAttribute('for');
|
||||||
|
|
||||||
|
if (key.indexOf('date') != -1) {
|
||||||
|
const pref = l.querySelector(`#${key}_pref`).value;
|
||||||
|
const time = l.querySelector(`#${key}_time`).value;
|
||||||
|
if (l.querySelector(`#${key}_time`).value != "") {
|
||||||
|
filterAssiduites.filters[key] = {
|
||||||
|
pref: pref,
|
||||||
|
time: new moment.tz(time, TIMEZONE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (key.indexOf('etat') != -1) {
|
||||||
|
filterAssiduites.filters[key] = [...l.querySelectorAll("input:checked")].map((e) => e.value);
|
||||||
|
} else if (key.indexOf("module") != -1) {
|
||||||
|
filterAssiduites.filters[key] = l.querySelector('#moduleimpl_id').value;
|
||||||
|
} else if (key.indexOf("est_just") != -1) {
|
||||||
|
filterAssiduites.filters[key] = l.querySelector('#est_just').value;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
getAllAssiduitesFromEtud(etudid, assiduiteCallBack)
|
||||||
|
|
||||||
|
}, () => { }, "#7059FF");
|
||||||
|
} else {
|
||||||
|
let html = `
|
||||||
|
<div class="filter-body">
|
||||||
|
<h3>Affichage des colonnes:</h3>
|
||||||
|
<div class="filter-head">
|
||||||
|
<label>
|
||||||
|
Date de saisie
|
||||||
|
<input class="chk" type="checkbox" name="entry_date" id="entry_date">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Date de Début
|
||||||
|
<input class="chk" type="checkbox" name="date_debut" id="date_debut" checked>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Date de Fin
|
||||||
|
<input class="chk" type="checkbox" name="date_fin" id="date_fin" checked>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Etat
|
||||||
|
<input class="chk" type="checkbox" name="etat" id="etat" checked>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Raison
|
||||||
|
<input class="chk" type="checkbox" name="raison" id="raison" checked>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Fichier
|
||||||
|
<input class="chk" type="checkbox" name="fichier" id="fichier" checked>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<h3>Filtrage des colonnes:</h3>
|
||||||
|
<span class="filter-line">
|
||||||
|
<span class="filter-title" for="entry_date">Date de saisie</span>
|
||||||
|
<select name="entry_date_pref" id="entry_date_pref">
|
||||||
|
<option value="-1">Avant</option>
|
||||||
|
<option value="0">Égal</option>
|
||||||
|
<option value="1">Après</option>
|
||||||
|
</select>
|
||||||
|
<input type="datetime-local" name="entry_date_time" id="entry_date_time">
|
||||||
|
</span>
|
||||||
|
<span class="filter-line">
|
||||||
|
<span class="filter-title" for="date_debut">Date de début</span>
|
||||||
|
<select name="date_debut_pref" id="date_debut_pref">
|
||||||
|
<option value="-1">Avant</option>
|
||||||
|
<option value="0">Égal</option>
|
||||||
|
<option value="1">Après</option>
|
||||||
|
</select>
|
||||||
|
<input type="datetime-local" name="date_debut_time" id="date_debut_time">
|
||||||
|
</span>
|
||||||
|
<span class="filter-line">
|
||||||
|
<span class="filter-title" for="date_fin">Date de fin</span>
|
||||||
|
<select name="date_fin_pref" id="date_fin_pref">
|
||||||
|
<option value="-1">Avant</option>
|
||||||
|
<option value="0">Égal</option>
|
||||||
|
<option value="1">Après</option>
|
||||||
|
</select>
|
||||||
|
<input type="datetime-local" name="date_fin_time" id="date_fin_time">
|
||||||
|
</span>
|
||||||
|
<span class="filter-line">
|
||||||
|
<span class="filter-title" for="etat">Etat</span>
|
||||||
|
<label>
|
||||||
|
Valide
|
||||||
|
<input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="valide">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Non Valide
|
||||||
|
<input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="non_valide">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
En Attente
|
||||||
|
<input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="attente">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Modifié
|
||||||
|
<input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="modifie">
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.innerHTML = html
|
||||||
|
html = span.firstElementChild
|
||||||
|
|
||||||
|
const filterHead = html.querySelector('.filter-head');
|
||||||
|
filterHead.innerHTML = ""
|
||||||
|
let cols = ["entry_date", "date_debut", "date_fin", "etat", "raison"];
|
||||||
|
|
||||||
|
cols.forEach((k) => {
|
||||||
|
const label = document.createElement('label')
|
||||||
|
label.classList.add('f-label')
|
||||||
|
const s = document.createElement('span');
|
||||||
|
s.textContent = columnTranslator(k);
|
||||||
|
|
||||||
|
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.classList.add('chk')
|
||||||
|
input.type = "checkbox"
|
||||||
|
input.name = k
|
||||||
|
input.id = k;
|
||||||
|
input.checked = filterJustificatifs.columns.includes(k)
|
||||||
|
|
||||||
|
label.appendChild(s)
|
||||||
|
label.appendChild(input)
|
||||||
|
filterHead.appendChild(label)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Mise à jour des filtres
|
||||||
|
|
||||||
|
Object.keys(filterJustificatifs.filters).forEach((key) => {
|
||||||
|
const l = html.querySelector(`.filter-title[for="${key}"]`).parentElement;
|
||||||
|
if (key.indexOf('date') != -1) {
|
||||||
|
l.querySelector(`#${key}_pref`).value = filterJustificatifs.filters[key].pref;
|
||||||
|
l.querySelector(`#${key}_time`).value = filterJustificatifs.filters[key].time.format("YYYY-MM-DDTHH:mm");
|
||||||
|
|
||||||
|
} else if (key.indexOf('etat') != -1) {
|
||||||
|
l.querySelectorAll('input').forEach((e) => {
|
||||||
|
e.checked = filterJustificatifs.filters[key].includes(e.value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
openPromptModal("Filtrage des Justificatifs", html, () => {
|
||||||
|
|
||||||
|
const columns = [...document.querySelectorAll('.chk')]
|
||||||
|
.map((el) => { if (el.checked) return el.id })
|
||||||
|
.filter((el) => el)
|
||||||
|
|
||||||
|
filterJustificatifs.columns = columns
|
||||||
|
filterJustificatifs.filters = {}
|
||||||
|
//reste des filtres
|
||||||
|
|
||||||
|
const lines = [...document.querySelectorAll('.filter-line')];
|
||||||
|
|
||||||
|
lines.forEach((l) => {
|
||||||
|
const key = l.querySelector('.filter-title').getAttribute('for');
|
||||||
|
|
||||||
|
if (key.indexOf('date') != -1) {
|
||||||
|
const pref = l.querySelector(`#${key}_pref`).value;
|
||||||
|
const time = l.querySelector(`#${key}_time`).value;
|
||||||
|
if (l.querySelector(`#${key}_time`).value != "") {
|
||||||
|
filterJustificatifs.filters[key] = {
|
||||||
|
pref: pref,
|
||||||
|
time: new moment.tz(time, TIMEZONE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (key.indexOf('etat') != -1) {
|
||||||
|
filterJustificatifs.filters[key] = [...l.querySelectorAll("input:checked")].map((e) => e.value);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
getAllJustificatifsFromEtud(etudid, justificatifCallBack)
|
||||||
|
|
||||||
|
}, () => { }, "#7059FF");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function columnTranslator(colName) {
|
||||||
|
switch (colName) {
|
||||||
|
case "date_debut":
|
||||||
|
return "Début";
|
||||||
|
case "entry_date":
|
||||||
|
return "Saisie le";
|
||||||
|
case "date_fin":
|
||||||
|
return "Fin";
|
||||||
|
case "etat":
|
||||||
|
return "État";
|
||||||
|
case "moduleimpl_id":
|
||||||
|
return "Module";
|
||||||
|
case "est_just":
|
||||||
|
return "Justifiée";
|
||||||
|
case "raison":
|
||||||
|
return "Raison";
|
||||||
|
case "fichier":
|
||||||
|
return "Fichier";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.pageContent {
|
||||||
|
width: 100%;
|
||||||
|
max-width: var(--sco-content-max-width);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
text-align: left;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid #dddddd;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:hover {
|
||||||
|
filter: brightness(1.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-menu {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 10px 0;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-menu li {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-menu li:hover {
|
||||||
|
filter: brightness(0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#deleteOption {
|
||||||
|
background-color: #F1A69C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-present {
|
||||||
|
background-color: #9CF1AF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-absent,
|
||||||
|
.l-invalid {
|
||||||
|
background-color: #F1A69C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-valid {
|
||||||
|
background-color: #8f7eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-retard {
|
||||||
|
background-color: #F1D99C;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ajoutez des styles pour le conteneur de pagination et les boutons */
|
||||||
|
.pagination-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-button {
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
margin: 0 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-button:hover {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-button.active {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
th>div {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-head {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-line {
|
||||||
|
display: flex;
|
||||||
|
justify-content: start;
|
||||||
|
align-items: center;
|
||||||
|
margin: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-line>* {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.rbtn {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
margin: 0 5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.f-label {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chk {
|
||||||
|
margin-left: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
111
app/templates/assiduites/widgets/tableau_justi.j2
Normal file
111
app/templates/assiduites/widgets/tableau_justi.j2
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<table id="justificatifTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<div>
|
||||||
|
<span>Début</span>
|
||||||
|
<a class="icon order" onclick="order('date_debut', justificatifCallBack, this, false)"></a>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<div>
|
||||||
|
<span>Fin</span>
|
||||||
|
<a class="icon order" onclick="order('date_fin', justificatifCallBack, this, false)"></a>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<div>
|
||||||
|
<span>État</span>
|
||||||
|
<a class="icon order" onclick="order('etat', justificatifCallBack, this, false)"></a>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<div>
|
||||||
|
<span>Raison</span>
|
||||||
|
<a class="icon order" onclick="order('raison', justificatifCallBack, this, false)"></a>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<div>
|
||||||
|
<span>Fichier</span>
|
||||||
|
<a class="icon order" onclick="order('fichier', justificatifCallBack, this, false)"></a>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="tableBodyJustificatifs">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div id="paginationContainerJustificatifs" class="pagination-container">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const paginationContainerJustificatifs = document.getElementById("paginationContainerJustificatifs");
|
||||||
|
let currentPageJustificatifs = 1;
|
||||||
|
let orderJustificatifs = true;
|
||||||
|
let filterJustificatifs = {
|
||||||
|
columns: [
|
||||||
|
"entry_date", "date_debut", "date_fin", "etat", "raison", "fichier"
|
||||||
|
],
|
||||||
|
filters: {}
|
||||||
|
}
|
||||||
|
const tableBodyJustificatifs = document.getElementById("tableBodyJustificatifs");
|
||||||
|
|
||||||
|
function justificatifCallBack(justi) {
|
||||||
|
justi = filterArray(justi, filterJustificatifs.filters)
|
||||||
|
renderTableJustificatifs(currentPageJustificatifs, justi);
|
||||||
|
renderPaginationButtons(justi, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTableJustificatifs(page, justificatifs) {
|
||||||
|
generateTableHead(filterJustificatifs.columns, false)
|
||||||
|
|
||||||
|
tableBodyJustificatifs.innerHTML = "";
|
||||||
|
const start = (page - 1) * itemsPerPage;
|
||||||
|
const end = start + itemsPerPage;
|
||||||
|
|
||||||
|
justificatifs.slice(start, end).forEach((justificatif) => {
|
||||||
|
const row = document.createElement("tr");
|
||||||
|
row.setAttribute('type', "justificatif");
|
||||||
|
row.setAttribute('obj_id', justificatif.justif_id);
|
||||||
|
|
||||||
|
const etat = justificatif.etat.toLowerCase();
|
||||||
|
|
||||||
|
if (etat == "valide") {
|
||||||
|
row.classList.add(`l-valid`);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
row.classList.add(`l-invalid`);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
filterJustificatifs.columns.forEach((k) => {
|
||||||
|
const td = document.createElement('td');
|
||||||
|
if (k.indexOf('date') != -1) {
|
||||||
|
td.textContent = moment.tz(justificatif[k], TIMEZONE).format(`DD/MM/Y HH:mm`)
|
||||||
|
} else if (k.indexOf('fichier') != -1) {
|
||||||
|
td.textContent = justificatif.fichier ? "Oui" : "Non";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
td.textContent = justificatif[k].capitalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
tableBodyJustificatifs.appendChild(row);
|
||||||
|
});
|
||||||
|
updateActivePaginationButton(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
@ -62,10 +62,8 @@
|
|||||||
{% if current_user.has_permission(sco.Permission.ScoAbsChange) %}
|
{% if current_user.has_permission(sco.Permission.ScoAbsChange) %}
|
||||||
<li><a href="{{ url_for('assiduites.signal_assiduites_etud', scodoc_dept=g.scodoc_dept,
|
<li><a href="{{ url_for('assiduites.signal_assiduites_etud', scodoc_dept=g.scodoc_dept,
|
||||||
etudid=sco.etud.id) }}">Ajouter</a></li>
|
etudid=sco.etud.id) }}">Ajouter</a></li>
|
||||||
<li><a href="{{ url_for('absences.JustifAbsenceEtud', scodoc_dept=g.scodoc_dept,
|
<li><a href="{{ url_for('assiduites.ajout_justificatif_etud', scodoc_dept=g.scodoc_dept,
|
||||||
etudid=sco.etud.id) }}">Justifier</a></li>
|
etudid=sco.etud.id) }}">Justifier</a></li>
|
||||||
<li><a href="{{ url_for('absences.AnnuleAbsenceEtud', scodoc_dept=g.scodoc_dept,
|
|
||||||
etudid=sco.etud.id) }}">Supprimer</a></li>
|
|
||||||
{% if sco.prefs["handle_billets_abs"] %}
|
{% if sco.prefs["handle_billets_abs"] %}
|
||||||
<li><a href="{{ url_for('absences.billets_etud', scodoc_dept=g.scodoc_dept,
|
<li><a href="{{ url_for('absences.billets_etud', scodoc_dept=g.scodoc_dept,
|
||||||
etudid=sco.etud.id) }}">Billets</a></li>
|
etudid=sco.etud.id) }}">Billets</a></li>
|
||||||
|
@ -269,6 +269,47 @@ def liste_assiduites_etud():
|
|||||||
).build()
|
).build()
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/AjoutJustificatifEtud")
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoAbsChange)
|
||||||
|
def ajout_justificatif_etud():
|
||||||
|
"""
|
||||||
|
ajout_justificatif_etud : Affichage et création/modification des justificatifs de l'étudiant
|
||||||
|
Args:
|
||||||
|
etudid (int): l'identifiant de l'étudiant
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: l'html généré
|
||||||
|
"""
|
||||||
|
|
||||||
|
etudid = request.args.get("etudid", -1)
|
||||||
|
etud: Identite = Identite.query.get_or_404(etudid)
|
||||||
|
if etud.dept_id != g.scodoc_dept_id:
|
||||||
|
abort(404, "étudiant inexistant dans ce département")
|
||||||
|
|
||||||
|
header: str = html_sco_header.sco_header(
|
||||||
|
page_title="Justificatifs",
|
||||||
|
init_qtip=True,
|
||||||
|
javascripts=[
|
||||||
|
"js/assiduites.js",
|
||||||
|
"libjs/moment.new.min.js",
|
||||||
|
"libjs/moment-timezone.js",
|
||||||
|
],
|
||||||
|
cssstyles=CSSSTYLES
|
||||||
|
+ [
|
||||||
|
"css/assiduites.css",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
return HTMLBuilder(
|
||||||
|
header,
|
||||||
|
render_template(
|
||||||
|
"assiduites/pages/ajout_justificatif.j2",
|
||||||
|
sco=ScoData(etud),
|
||||||
|
),
|
||||||
|
).build()
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/SignalAssiduiteGr")
|
@bp.route("/SignalAssiduiteGr")
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoAbsChange)
|
@permission_required(Permission.ScoAbsChange)
|
||||||
|
@ -11,7 +11,7 @@ from sqlalchemy.orm import sessionmaker # added by ev
|
|||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = "c701224fa255"
|
revision = "c701224fa255"
|
||||||
down_revision = "d84bc592584e"
|
down_revision = "b555390780b2"
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = "dbcf2175e87f"
|
revision = "dbcf2175e87f"
|
||||||
down_revision = "c701224fa255"
|
down_revision = "d84bc592584e"
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user