forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -6,7 +6,9 @@
|
|||||||
--color-justi: #29b990;
|
--color-justi: #29b990;
|
||||||
--color-justi-clair: #48f6ff;
|
--color-justi-clair: #48f6ff;
|
||||||
--color-justi-attente: yellow;
|
--color-justi-attente: yellow;
|
||||||
--color-justi-attente-stripe: #29b990; /* pink #fa25cb; */ /* #789dbb;*/
|
--color-justi-attente-stripe: #29b990;
|
||||||
|
/* pink #fa25cb; */
|
||||||
|
/* #789dbb;*/
|
||||||
--color-justi-modifie: rgb(255, 230, 0);
|
--color-justi-modifie: rgb(255, 230, 0);
|
||||||
--color-justi-invalide: #a84476;
|
--color-justi-invalide: #a84476;
|
||||||
--color-nonwork: #badfff;
|
--color-nonwork: #badfff;
|
||||||
@ -28,27 +30,23 @@
|
|||||||
--color-defaut-dark: #444;
|
--color-defaut-dark: #444;
|
||||||
--color-default-text: #1f1f1f;
|
--color-default-text: #1f1f1f;
|
||||||
|
|
||||||
--motif-justi: repeating-linear-gradient(
|
--motif-justi: repeating-linear-gradient(135deg,
|
||||||
135deg,
|
transparent,
|
||||||
transparent,
|
transparent 4px,
|
||||||
transparent 4px,
|
var(--color-justi) 4px,
|
||||||
var(--color-justi) 4px,
|
var(--color-justi) 8px);
|
||||||
var(--color-justi) 8px
|
--motif-justi-invalide: repeating-linear-gradient(-135deg,
|
||||||
);
|
transparent,
|
||||||
--motif-justi-invalide: repeating-linear-gradient(
|
transparent 4px,
|
||||||
-135deg,
|
var(--color-justi-invalide) 4px,
|
||||||
transparent,
|
var(--color-justi-invalide) 8px);
|
||||||
transparent 4px,
|
|
||||||
var(--color-justi-invalide) 4px,
|
|
||||||
var(--color-justi-invalide) 8px
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selectors > * {
|
.selectors>* {
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,6 +337,11 @@
|
|||||||
background-image: url(../icons/retard.svg);
|
background-image: url(../icons/retard.svg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rbtn.conflit::before {
|
||||||
|
background-color: var(--color-absent);
|
||||||
|
background-image: url(../icons/solveur_conflits.svg);
|
||||||
|
}
|
||||||
|
|
||||||
.rbtn:checked:before {
|
.rbtn:checked:before {
|
||||||
outline: 5px solid var(--color-primary);
|
outline: 5px solid var(--color-primary);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@ -405,29 +408,11 @@
|
|||||||
.assiduite {
|
.assiduite {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
border: 1px solid #444;
|
||||||
|
|
||||||
.assiduite-info {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.assiduite-id,
|
|
||||||
.assiduite-period,
|
|
||||||
.assiduite-state,
|
|
||||||
.assiduite-user_id {
|
|
||||||
font-size: 12px;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.assiduites-container {
|
.assiduites-container {
|
||||||
@ -438,7 +423,7 @@
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-buttons {
|
.modal-buttons {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -449,48 +434,35 @@
|
|||||||
bottom: 5%;
|
bottom: 5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ajout de la classe CSS pour la bordure en pointillés */
|
|
||||||
.assiduite.selected {
|
|
||||||
border: 2px dashed black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.assiduite-special {
|
.assiduite-special {
|
||||||
height: 120px;
|
height: 120px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
border: 2px solid #000;
|
border: 5px solid var(--color-primary);
|
||||||
background-color: rgba(36, 36, 36, 0.25);
|
/* background-color: rgba(36, 36, 36, 0.25);
|
||||||
background-image: repeating-linear-gradient(
|
background-image: repeating-linear-gradient(135deg,
|
||||||
135deg,
|
transparent,
|
||||||
transparent,
|
transparent 5px,
|
||||||
transparent 5px,
|
rgba(81, 81, 81, 0.61) 5px,
|
||||||
rgba(81, 81, 81, 0.61) 5px,
|
rgba(81, 81, 81, 0.61) 10px); */
|
||||||
rgba(81, 81, 81, 0.61) 10px
|
|
||||||
);
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*<== Info sur l'assiduité sélectionnée ==>*/
|
.assiduite .assiduite-bubble {
|
||||||
.modal-assiduite-content {
|
top: 5px;
|
||||||
background-color: #fefefe;
|
left: 50%;
|
||||||
margin: 5% auto;
|
transform: translateX(-50%);
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid #888;
|
|
||||||
width: max-content;
|
|
||||||
position: relative;
|
|
||||||
border-radius: 10px;
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-assiduite-content.show {
|
.action-buttons {
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-assiduite-content .infos {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
justify-content: center;
|
||||||
justify-content: space-evenly;
|
align-items: center;
|
||||||
align-items: flex-start;
|
flex-wrap: wrap;
|
||||||
|
gap: 2px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*<=== Mass Action ==>*/
|
/*<=== Mass Action ==>*/
|
||||||
@ -500,57 +472,16 @@
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 2% 0;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mass-selection span {
|
|
||||||
margin: 0 1%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mass-selection .rbtn {
|
.mass-selection .rbtn {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*<== Loader ==> */
|
|
||||||
|
|
||||||
.loader-container {
|
|
||||||
display: none;
|
|
||||||
/* Cacher le loader par défaut */
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
/* Fond semi-transparent pour bloquer les clics */
|
|
||||||
z-index: 9999;
|
|
||||||
/* Placer le loader au-dessus de tout le contenu */
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader {
|
|
||||||
border: 6px solid #f3f3f3;
|
|
||||||
border-radius: 50%;
|
|
||||||
border-top: 6px solid var(--color-primary);
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
animation: spin 2s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
0% {
|
|
||||||
transform: translate(-50%, -50%) rotate(0deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: translate(-50%, -50%) rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fieldsplit {
|
.fieldsplit {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
@ -569,7 +500,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
#page-assiduite-content > * {
|
#page-assiduite-content>* {
|
||||||
margin: 1.5% 0;
|
margin: 1.5% 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,6 +580,7 @@
|
|||||||
margin-right: 24px;
|
margin-right: 24px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#options-tableau label {
|
#options-tableau label {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
@ -657,15 +589,20 @@
|
|||||||
section.assi-form {
|
section.assi-form {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.liste_assi td.date {
|
table.liste_assi td.date {
|
||||||
width: 140px;
|
width: 140px;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.liste_assi.dataTable tbody td.date-debut {
|
table.liste_assi.dataTable tbody td.date-debut {
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.liste_assi td.actions {
|
table.liste_assi td.actions {
|
||||||
white-space: nowrap; /* boutons horizontalement */
|
white-space: nowrap;
|
||||||
|
/* boutons horizontalement */
|
||||||
}
|
}
|
||||||
|
|
||||||
table.liste_assi td.actions a:last-child {
|
table.liste_assi td.actions a:last-child {
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
}
|
}
|
||||||
@ -673,31 +610,154 @@ table.liste_assi td.actions a:last-child {
|
|||||||
tr.row-assiduite td {
|
tr.row-assiduite td {
|
||||||
border-bottom: 1px solid grey;
|
border-bottom: 1px solid grey;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.liste_assi tbody tr td.assi-type {
|
table.liste_assi tbody tr td.assi-type {
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.row-assiduite.absent td.assi-type {
|
tr.row-assiduite.absent td.assi-type {
|
||||||
background-color: var(--color-absent-clair);
|
background-color: var(--color-absent-clair);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.row-assiduite.absent.justifiee td.assi-type {
|
tr.row-assiduite.absent.justifiee td.assi-type {
|
||||||
background-color: var(--color-absent-justi);
|
background-color: var(--color-absent-justi);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.row-assiduite.retard td.assi-type {
|
tr.row-assiduite.retard td.assi-type {
|
||||||
background-color: var(--color-retard);
|
background-color: var(--color-retard);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.row-assiduite.present td.assi-type {
|
tr.row-assiduite.present td.assi-type {
|
||||||
background-color: var(--color-present);
|
background-color: var(--color-present);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.row-justificatif.valide td.assi-type {
|
tr.row-justificatif.valide td.assi-type {
|
||||||
background-color: var(--color-justi);
|
background-color: var(--color-justi);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.row-justificatif.attente td.assi-type {
|
tr.row-justificatif.attente td.assi-type {
|
||||||
background-color: var(--color-justi-attente);
|
background-color: var(--color-justi-attente);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.row-justificatif.modifie td.assi-type {
|
tr.row-justificatif.modifie td.assi-type {
|
||||||
background-color: var(--color-justi-modifie);
|
background-color: var(--color-justi-modifie);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.row-justificatif.non_valide td.assi-type {
|
tr.row-justificatif.non_valide td.assi-type {
|
||||||
background-color: var(--color-justi-invalide);
|
background-color: var(--color-justi-invalide);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
<== Loader ==>
|
||||||
|
|
||||||
|
*/
|
||||||
|
/* HTML: <div class="loader"></div> */
|
||||||
|
.loader {
|
||||||
|
width: 80px;
|
||||||
|
height: 70px;
|
||||||
|
border: 5px solid #000;
|
||||||
|
padding: 0 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background:
|
||||||
|
linear-gradient(#fff 0 0) 0 0/8px 20px,
|
||||||
|
linear-gradient(#fff 0 0) 100% 0/8px 20px,
|
||||||
|
radial-gradient(farthest-side, #fff 90%, #0000) 0 5px/8px 8px content-box,
|
||||||
|
#000;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
animation: l3 2s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes l3 {
|
||||||
|
25% {
|
||||||
|
background-position: 0 0, 100% 100%, 100% calc(100% - 5px)
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
background-position: 0 100%, 100% 100%, 0 calc(100% - 5px)
|
||||||
|
}
|
||||||
|
|
||||||
|
75% {
|
||||||
|
background-position: 0 100%, 100% 0, 100% 5px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 1000;
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <== Couleurs ==>
|
||||||
|
*/
|
||||||
|
|
||||||
|
.color.present {
|
||||||
|
background-color: var(--color-present) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.absent {
|
||||||
|
background-color: var(--color-absent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.absent.est_just {
|
||||||
|
background-color: var(--color-absent-justi) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.retard {
|
||||||
|
background-color: var(--color-retard) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.retard.est_just {
|
||||||
|
background-color: var(--color-retard-justi) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.nonwork {
|
||||||
|
background-color: var(--color-nonwork) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color {
|
||||||
|
background-color: var(--color-defaut) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.est_just.sans_etat::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 25%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--color-justi) !important;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.invalide::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 25%;
|
||||||
|
height: 100%;
|
||||||
|
right: 0;
|
||||||
|
background-color: var(--color-justi-invalide) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color.attente::before,
|
||||||
|
.color.modifie::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 25%;
|
||||||
|
height: 100%;
|
||||||
|
right: 0;
|
||||||
|
background: repeating-linear-gradient(to bottom,
|
||||||
|
var(--color-justi-attente-stripe) 0px,
|
||||||
|
var(--color-justi-attente-stripe) 4px,
|
||||||
|
var(--color-justi-attente) 4px,
|
||||||
|
var(--color-justi-attente) 7px) !important;
|
||||||
|
}
|
17
app/static/icons/solveur_conflits.svg
Normal file
17
app/static/icons/solveur_conflits.svg
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#000000" height="85" width="85" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 482.568 482.568" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g opacity="0.7">
|
||||||
|
<path d="M116.993,203.218c13.4-1.8,26.8,2.8,36.3,12.3l24,24l22.7-22.6l-32.8-32.7c-5.1-5.1-5.1-13.4,0-18.5s13.4-5.1,18.5,0
|
||||||
|
l32.8,32.8l22.7-22.6l-24.1-24.1c-9.5-9.5-14.1-23-12.3-36.3c4-30.4-5.7-62.2-29-85.6c-23.8-23.8-56.4-33.4-87.3-28.8
|
||||||
|
c-4.9,0.7-6.9,6.8-3.4,10.3l30.9,30.9c14.7,14.7,14.7,38.5,0,53.1l-19,19c-14.7,14.7-38.5,14.7-53.1,0l-31-30.9
|
||||||
|
c-3.5-3.5-9.5-1.5-10.3,3.4c-4.6,30.9,5,63.5,28.8,87.3C54.793,197.518,86.593,207.218,116.993,203.218z"/>
|
||||||
|
<path d="M309.193,243.918l-22.7,22.6l134.8,134.8c5.1,5.1,5.1,13.4,0,18.5s-13.4,5.1-18.5,0l-134.8-134.8l-22.7,22.6l138.9,138.9
|
||||||
|
c17.6,17.6,46.1,17.5,63.7-0.1s17.6-46.1,0.1-63.7L309.193,243.918z"/>
|
||||||
|
<path d="M361.293,153.918h59.9l59.9-119.7l-29.9-29.9l-119.8,59.8v59.9l-162.8,162.3l-29.3-29.2l-118,118
|
||||||
|
c-24.6,24.6-24.6,64.4,0,89s64.4,24.6,89,0l118-118l-29.9-29.9L361.293,153.918z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,7 @@
|
|||||||
<script src="{{scu.STATIC_DIR}}/js/groups_view.js"></script>
|
<script src="{{scu.STATIC_DIR}}/js/groups_view.js"></script>
|
||||||
<script src="{{scu.STATIC_DIR}}/js/date_utils.js"></script>
|
<script src="{{scu.STATIC_DIR}}/js/date_utils.js"></script>
|
||||||
<script src="{{scu.STATIC_DIR}}/js/assiduites.js"></script>
|
<script src="{{scu.STATIC_DIR}}/js/assiduites.js"></script>
|
||||||
|
{% include "sco_timepicker.j2" %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
@ -20,33 +21,21 @@
|
|||||||
function getPeriodValues() {
|
function getPeriodValues() {
|
||||||
return [0, 23]
|
return [0, 23]
|
||||||
}
|
}
|
||||||
|
{% else %}
|
||||||
|
setupTimeLine(()=>{creerTousLesEtudiants(etuds)})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const nonWorkDays = [{{ nonworkdays| safe }}];
|
const nonWorkDays = [{{ nonworkdays| safe }}];
|
||||||
|
|
||||||
const readOnly = {{ readonly }};
|
const readOnly = {{ readonly }};
|
||||||
|
|
||||||
|
|
||||||
setupDate();
|
|
||||||
updateDate();
|
|
||||||
if (!readOnly) {
|
|
||||||
setupTimeLine(() => {
|
|
||||||
generateAllEtudRow();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.forceModule = "{{ forcer_module }}"
|
window.forceModule = "{{ forcer_module }}"
|
||||||
window.forceModule = window.forceModule == "True" ? true : false
|
window.forceModule = window.forceModule == "True" ? true : false
|
||||||
|
|
||||||
const etudsDefDem = {{ defdem | safe }}
|
const etudsDefDem = {{ defdem | safe }}
|
||||||
|
|
||||||
const select = document.getElementById("moduleimpl_select");
|
const select = document.getElementById("moduleimpl_select");
|
||||||
|
|
||||||
select?.addEventListener('change', (e) => {
|
|
||||||
generateAllEtudRow();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (window.forceModule) {
|
if (window.forceModule) {
|
||||||
const btn = document.getElementById("validate_selectors");
|
const btn = document.getElementById("validate_selectors");
|
||||||
|
|
||||||
@ -63,12 +52,51 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.getElementById("pdp").addEventListener("change", (e) => {
|
||||||
|
creerTousLesEtudiants(etuds);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#date').on('change', async function(d) {
|
||||||
|
// On vérifie si la date est un jour travaillé
|
||||||
|
dateCouranteEstTravaillee();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
await recupAssiduites(etuds, $("#date").datepicker("getDate"));
|
||||||
|
creerTousLesEtudiants(etuds);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#moduleimpl_select").on("change", ()=>{
|
||||||
|
creerTousLesEtudiants(etuds);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#group_ids_sel").on("change", ()=>{
|
||||||
|
main();
|
||||||
|
})
|
||||||
|
|
||||||
|
const moduleimpls = {};
|
||||||
|
const inscriptionsModules = new Map();
|
||||||
|
let etuds = new Map();
|
||||||
|
|
||||||
|
async function main(){
|
||||||
|
dateCouranteEstTravaillee();
|
||||||
|
etuds = await recupEtuds($('#group_ids_sel').val());
|
||||||
|
if (etuds.size != 0){
|
||||||
|
await recupAssiduites(etuds, $("#date").datepicker("getDate"));
|
||||||
|
}
|
||||||
|
creerTousLesEtudiants(etuds);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(main, 0);
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock scripts %}
|
{% endblock scripts %}
|
||||||
|
|
||||||
{% block styles %}
|
{% block styles %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/bootstrap/css/bootstrap.min.css">
|
|
||||||
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/bootstrap/css/bootstrap-theme.min.css">
|
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/bootstrap/css/bootstrap-theme.min.css">
|
||||||
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/bootstrap-multiselect-1.1.2/bootstrap-multiselect.min.css">
|
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/bootstrap-multiselect-1.1.2/bootstrap-multiselect.min.css">
|
||||||
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/assiduites.css">
|
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/assiduites.css">
|
||||||
@ -77,14 +105,8 @@
|
|||||||
|
|
||||||
|
|
||||||
{% block app_content %}
|
{% block app_content %}
|
||||||
{% include "assiduites/widgets/toast.j2" %}
|
|
||||||
|
|
||||||
{{ minitimeline|safe }}
|
{{ minitimeline|safe }}
|
||||||
<style>
|
|
||||||
#moduleimpl_select {
|
|
||||||
max-width: 200px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<section id="content">
|
<section id="content">
|
||||||
|
|
||||||
<div class="no-display">
|
<div class="no-display">
|
||||||
@ -104,15 +126,16 @@
|
|||||||
<fieldset class="selectors">
|
<fieldset class="selectors">
|
||||||
<div class="infos">
|
<div class="infos">
|
||||||
<div class="infos-button">Groupes : {{grp|safe}}</div>
|
<div class="infos-button">Groupes : {{grp|safe}}</div>
|
||||||
<div class="infos-button" style="margin-left: 24px;">Date : <span style="margin-left: 8px;"
|
<div>
|
||||||
id="datestr"></span>
|
<input type="text" name="date" id="date" class="datepicker" value="{{date}}">
|
||||||
<input type="text" name="tl_date" id="tl_date" value="{{ date }}" onchange="updateDate()">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
<div style="display: {{'none' if readonly == 'true' else 'block'}};">
|
||||||
|
{{timeline|safe}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if readonly == "false" %}
|
{% if readonly == "false" %}
|
||||||
{{timeline|safe}}
|
|
||||||
|
|
||||||
<div style="margin: 1vh 0;">
|
<div style="margin: 1vh 0;">
|
||||||
<div id="forcemodule" style="display: none; margin:10px 0px;">
|
<div id="forcemodule" style="display: none; margin:10px 0px;">
|
||||||
@ -123,46 +146,40 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if readonly == "true" %}
|
<div>
|
||||||
<button id="validate_selectors" onclick="validateSelectors(this)">
|
<label for="pdp">
|
||||||
Voir l'assiduité
|
<span>Afficher les photos</span>
|
||||||
</button>
|
<input type="checkbox" name="pdp" id="pdp">
|
||||||
{% else %}
|
</label>
|
||||||
<button id="validate_selectors" onclick="validateSelectors(this)">
|
</div>
|
||||||
Faire la saisie
|
{% if readonly == "false" %}
|
||||||
</button>
|
<div class="mass-selection">
|
||||||
|
<span>Mettre tout le monde :</span>
|
||||||
|
<fieldset class="btns_field mass">
|
||||||
|
<input type="checkbox" value="present" name="mass_btn_assiduites" id="mass_rbtn_present"
|
||||||
|
class="rbtn present" onclick="mettreToutLeMonde('present', this)" title="Present">
|
||||||
|
<input type="checkbox" value="retard" name="mass_btn_assiduites" id="mass_rbtn_retard"
|
||||||
|
class="rbtn retard" onclick="mettreToutLeMonde('retard', this)" title="Retard">
|
||||||
|
<input type="checkbox" value="absent" name="mass_btn_assiduites" id="mass_rbtn_absent"
|
||||||
|
class="rbtn absent" onclick="mettreToutLeMonde('absent', this)" title="Absent">
|
||||||
|
<input type="checkbox" value="remove" name="mass_btn_assiduites" id="mass_rbtn_aucun"
|
||||||
|
class="rbtn aucun" onclick="mettreToutLeMonde('vide', this)" title="Supprimer">
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
<div class="etud_holder">
|
<div class="etud_holder">
|
||||||
<p class="placeholder">
|
<p class="placeholder">
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="legende">
|
|
||||||
<h3>Explication diverses</h3>
|
|
||||||
<p>
|
|
||||||
Si la période indiquée par la timeline provoque un conflit d'assiduité pour un étudiant sa ligne deviendra
|
|
||||||
rouge.
|
|
||||||
<br>
|
|
||||||
Dans ce cas il faut résoudre manuellement le conflit : cliquez sur un des boutons d'assiduités pour ouvrir
|
|
||||||
le
|
|
||||||
résolveur de conflit.
|
|
||||||
<br>
|
|
||||||
Correspondance des couleurs :
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
{% include "assiduites/widgets/legende_couleur.j2" %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<!-- Ajout d'un conteneur pour le loader -->
|
|
||||||
<div class="loader-container" id="loaderContainer">
|
|
||||||
<div class="loader"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
{% include "assiduites/widgets/toast.j2" %}
|
||||||
{% include "assiduites/widgets/alert.j2" %}
|
{% include "assiduites/widgets/alert.j2" %}
|
||||||
{% include "assiduites/widgets/prompt.j2" %}
|
{% include "assiduites/widgets/prompt.j2" %}
|
||||||
{% include "assiduites/widgets/conflict.j2" %}
|
{% include "assiduites/widgets/conflict.j2" %}
|
||||||
|
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{% endblock app_content %}
|
{% endblock app_content %}
|
||||||
|
@ -1,118 +1,100 @@
|
|||||||
<script>
|
<script>
|
||||||
/**
|
/**
|
||||||
* Transformation d'une date de début en position sur la timeline
|
* Transformation d'une date de début en position sur la timeline
|
||||||
* @param {String} start
|
* @param {String} start
|
||||||
* @returns {String} un déplacement par rapport à la gauche en %
|
* @returns {String} un déplacement par rapport à la gauche en %
|
||||||
*/
|
*/
|
||||||
function getLeftPosition(start) {
|
function getLeftPosition(start) {
|
||||||
const startTime = new Date(start);
|
const startTime = new Date(start);
|
||||||
const startMins = (startTime.getHours() - t_start) * 60 + startTime.getMinutes();
|
const startMins =
|
||||||
return (startMins / (t_end * 60 - t_start * 60)) * 100 + "%";
|
(startTime.getHours() - t_start) * 60 + startTime.getMinutes();
|
||||||
}
|
return (startMins / (t_end * 60 - t_start * 60)) * 100 + "%";
|
||||||
/**
|
}
|
||||||
* Ajustement de l'espacement vertical entre les assiduités superposées
|
/**
|
||||||
* @param {HTMLElement} container le conteneur des assiduités
|
* Ajustement de l'espacement vertical entre les assiduités superposées
|
||||||
* @param {String} start la date début de l'assiduité à placer
|
* @param {HTMLElement} container le conteneur des assiduités
|
||||||
* @param {String} end la date de fin de l'assiduité à placer
|
* @param {String} start la date début de l'assiduité à placer
|
||||||
* @returns {String} La position en px
|
* @param {String} end la date de fin de l'assiduité à placer
|
||||||
*/
|
* @returns {String} La position en px
|
||||||
function getTopPosition(container, start, end) {
|
*/
|
||||||
const overlaps = (a, b) => {
|
function getTopPosition(container, start, end) {
|
||||||
return a.start < b.end && a.end > b.start;
|
const overlaps = (a, b) => {
|
||||||
};
|
return a.start < b.end && a.end > b.start;
|
||||||
|
};
|
||||||
|
|
||||||
const startTime = new Date(start);
|
const startTime = new Date(start);
|
||||||
const endTime = new Date(end);
|
const endTime = new Date(end);
|
||||||
const assiduiteDuration = { start: startTime, end: endTime };
|
const assiduiteDuration = { start: startTime, end: endTime };
|
||||||
|
|
||||||
let position = 0;
|
let position = 0;
|
||||||
let hasOverlap = true;
|
let hasOverlap = true;
|
||||||
|
|
||||||
while (hasOverlap) {
|
while (hasOverlap) {
|
||||||
hasOverlap = false;
|
hasOverlap = false;
|
||||||
Array.from(container.children).some((el) => {
|
Array.from(container.children).some((el) => {
|
||||||
const elStart = new Date(el.getAttribute("data-start"));
|
const elStart = new Date(el.getAttribute("data-start"));
|
||||||
const elEnd = new Date(el.getAttribute("data-end"));
|
const elEnd = new Date(el.getAttribute("data-end"));
|
||||||
const elDuration = { start: elStart, end: elEnd };
|
const elDuration = { start: elStart, end: elEnd };
|
||||||
|
|
||||||
if (overlaps(assiduiteDuration, elDuration)) {
|
if (overlaps(assiduiteDuration, elDuration)) {
|
||||||
position += 25; // Pour ajuster l'espacement vertical entre les assiduités superposées
|
position += 25; // Pour ajuster l'espacement vertical entre les assiduités superposées
|
||||||
hasOverlap = true;
|
hasOverlap = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return position + "px";
|
return position + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule de la largeur de l'assiduité sur la timeline
|
||||||
|
* @param {String} start date iso de début
|
||||||
|
* @param {String} end date iso de fin
|
||||||
|
* @returns {String} la taille en %
|
||||||
|
*/
|
||||||
|
function getWidth(start, end) {
|
||||||
|
const startTime = new Date(start);
|
||||||
|
const endTime = new Date(end);
|
||||||
|
|
||||||
|
const duration = (endTime - startTime) / 1000 / 60;
|
||||||
|
|
||||||
|
const percent = (duration / (t_end * 60 - t_start * 60)) * 100;
|
||||||
|
return percent + "%";
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDateModal(date) {
|
||||||
|
return new Date(Date.removeUTC(date)).format("DD/MM/Y HH:mm");
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConflitResolver {
|
||||||
|
constructor(assiduitesList, conflictPeriod, interval) {
|
||||||
|
this.list = assiduitesList;
|
||||||
|
this.conflictPeriod = conflictPeriod;
|
||||||
|
this.interval = interval;
|
||||||
|
this.selectedAssiduite = null;
|
||||||
|
|
||||||
|
this.element = undefined;
|
||||||
|
|
||||||
|
this.callbacks = {
|
||||||
|
delete: () => {},
|
||||||
|
split: () => {},
|
||||||
|
edit: () => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh(assiduitesList, periode) {
|
||||||
|
this.list = assiduitesList;
|
||||||
|
if (periode) {
|
||||||
|
this.conflictPeriod = periode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
this.render();
|
||||||
* Transformation d'un état en couleur
|
}
|
||||||
* @param {String} state l'état
|
|
||||||
* @returns {String} la couleur correspondant à l'état
|
|
||||||
*/
|
|
||||||
function getColor(state) {
|
|
||||||
switch (state) {
|
|
||||||
case "PRESENT":
|
|
||||||
return "var(--color-present)";
|
|
||||||
case "ABSENT":
|
|
||||||
return "var(--color-absent)";
|
|
||||||
case "RETARD":
|
|
||||||
return "var(--color-retard)";
|
|
||||||
default:
|
|
||||||
return "var(--color-defaut-dark)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
open() {
|
||||||
* Calcule de la largeur de l'assiduité sur la timeline
|
const html = `
|
||||||
* @param {String} start date iso de début
|
<div id="myModal" class="modal">
|
||||||
* @param {String} end date iso de fin
|
|
||||||
* @returns {String} la taille en %
|
|
||||||
*/
|
|
||||||
function getWidth(start, end) {
|
|
||||||
const startTime = new Date(start);
|
|
||||||
const endTime = new Date(end);
|
|
||||||
|
|
||||||
const duration = (endTime - startTime) / 1000 / 60;
|
|
||||||
|
|
||||||
const percent = (duration / (t_end * 60 - t_start * 60)) * 100
|
|
||||||
return percent + "%";
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConflitResolver {
|
|
||||||
constructor(assiduitesList, conflictPeriod, interval) {
|
|
||||||
this.list = assiduitesList;
|
|
||||||
this.conflictPeriod = conflictPeriod;
|
|
||||||
this.interval = interval;
|
|
||||||
this.selectedAssiduite = null;
|
|
||||||
|
|
||||||
this.element = undefined;
|
|
||||||
|
|
||||||
this.callbacks = {
|
|
||||||
delete: () => { },
|
|
||||||
split: () => { },
|
|
||||||
edit: () => { },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
refresh(assiduitesList, periode) {
|
|
||||||
this.list = assiduitesList;
|
|
||||||
if (periode) {
|
|
||||||
this.conflictPeriod = periode;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.render()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
selectAssiduite() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
open() {
|
|
||||||
const html = `
|
|
||||||
<div id="myModal" class="modal">
|
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<span class="close">×</span>
|
<span class="close">×</span>
|
||||||
<h2>Veuillez régler le conflit pour poursuivre</h2>
|
<h2>Veuillez régler le conflit pour poursuivre</h2>
|
||||||
@ -122,201 +104,264 @@
|
|||||||
<div class="assiduites-container"></div>
|
<div class="assiduites-container"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="action-buttons">
|
<div class="modal-buttons">
|
||||||
<button id="finish" class="btnPrompt">Quitter</button>
|
<button id="finish" class="btnPrompt">Quitter</button>
|
||||||
<button id="delete" class="btnPrompt" disabled>Supprimer</button>
|
|
||||||
<button id="split" class="btnPrompt" disabled>Séparer</button>
|
|
||||||
<button id="edit" class="btnPrompt" disabled>Modifier l'état</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-assiduite-content">
|
|
||||||
<h2>Information de l'assiduité sélectionnée</h2>
|
|
||||||
<div class="infos">
|
|
||||||
<p>Assiduite id : <span id="modal-assiduite-id">A</span></p>
|
|
||||||
<p>Etat : <span id="modal-assiduite-etat">B</span></p>
|
|
||||||
<p>Date de début : <span id="modal-assiduite-deb">C</span></p>
|
|
||||||
<p>Date de fin: <span id="modal-assiduite-fin">D</span></p>
|
|
||||||
<p>Module : <span id="modal-assiduite-module">E</span></p>
|
|
||||||
<p><span id="modal-assiduite-user">F</span></p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
document.body.insertAdjacentHTML("afterbegin", html);
|
document.body.insertAdjacentHTML("afterbegin", html);
|
||||||
this.element = document.getElementById('myModal');
|
this.element = document.getElementById("myModal");
|
||||||
this.deleteBtn = document.querySelector('#myModal #delete');
|
document.querySelector("#myModal #finish").addEventListener("click", () => {
|
||||||
this.editBtn = document.querySelector('#myModal #edit');
|
this.close();
|
||||||
this.splitBtn = document.querySelector('#myModal #split');
|
});
|
||||||
this.deleteBtn.addEventListener('click', () => { this.deleteAssiduiteModal() });
|
|
||||||
this.editBtn.addEventListener('click', () => { this.editAssiduiteModal() });
|
|
||||||
this.splitBtn.addEventListener('click', () => { this.splitAssiduiteModal() });
|
|
||||||
document.querySelector("#myModal #finish").addEventListener('click', () => { this.close() })
|
|
||||||
|
|
||||||
document.querySelector('#myModal .close').addEventListener('click', () => { this.close() })
|
document.querySelector("#myModal .close").addEventListener("click", () => {
|
||||||
|
this.close();
|
||||||
|
});
|
||||||
|
|
||||||
// fermeture du modal en appuyant sur echap
|
// fermeture du modal en appuyant sur echap
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener(
|
||||||
if (e.key === 'Escape') {
|
"keydown",
|
||||||
this.close()
|
(e) => {
|
||||||
}
|
if (e.key === "Escape") {
|
||||||
}, { once: true })
|
this.close();
|
||||||
|
|
||||||
this.render()
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
if (this.element) {
|
||||||
|
this.element.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
close() {
|
/**
|
||||||
if (this.element) {
|
* Génération du modal
|
||||||
this.element.remove()
|
*/
|
||||||
|
render() {
|
||||||
|
const timeLabels = document.querySelector(".time-labels");
|
||||||
|
const assiduitesContainer = document.querySelector(".assiduites-container");
|
||||||
|
|
||||||
|
timeLabels.innerHTML = "";
|
||||||
|
assiduitesContainer.innerHTML = '<div class="assiduite-special"></div>';
|
||||||
|
|
||||||
|
// Ajout des labels d'heure sur la frise chronologique
|
||||||
|
for (let i = t_start; i <= t_end; i++) {
|
||||||
|
const timeLabel = document.createElement("div");
|
||||||
|
timeLabel.className = "time-label";
|
||||||
|
timeLabel.textContent = numberToTime(i);
|
||||||
|
timeLabels.appendChild(timeLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Placement de la période conflictuelle sur la timeline
|
||||||
|
const specialAssiduiteEl = document.querySelector(".assiduite-special");
|
||||||
|
|
||||||
|
specialAssiduiteEl.style.width = getWidth(
|
||||||
|
this.conflictPeriod.deb,
|
||||||
|
this.conflictPeriod.fin
|
||||||
|
);
|
||||||
|
specialAssiduiteEl.style.left = getLeftPosition(this.conflictPeriod.deb);
|
||||||
|
specialAssiduiteEl.style.top = "0";
|
||||||
|
specialAssiduiteEl.style.zIndex = "0"; // Place l'assiduité spéciale en arrière-plan
|
||||||
|
assiduitesContainer.appendChild(specialAssiduiteEl);
|
||||||
|
|
||||||
|
//Placement des assiduités sur la timeline
|
||||||
|
this.list.forEach((assiduite) => {
|
||||||
|
const period = {
|
||||||
|
deb: new Date(assiduite.date_debut),
|
||||||
|
fin: new Date(assiduite.date_fin),
|
||||||
|
};
|
||||||
|
if (!hasTimeConflict(period, this.interval)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const el = document.createElement("div");
|
||||||
|
el.classList.add("assiduite", "color", assiduite.etat.toLowerCase());
|
||||||
|
|
||||||
|
el.style.width = getWidth(assiduite.date_debut, assiduite.date_fin);
|
||||||
|
el.style.left = getLeftPosition(assiduite.date_debut);
|
||||||
|
el.style.top = "10px";
|
||||||
|
el.setAttribute("data-id", assiduite.assiduite_id);
|
||||||
|
el.addEventListener("click", () => {});
|
||||||
|
|
||||||
|
// Génération des boutons d'action (supprimer, éditer, diviser)
|
||||||
|
const actionButtons = document.createElement("div");
|
||||||
|
actionButtons.className = "action-buttons";
|
||||||
|
const deleteButton = document.createElement("button");
|
||||||
|
deleteButton.textContent = "🗑️";
|
||||||
|
deleteButton.addEventListener("click", () => {
|
||||||
|
this.supprimerAssiduite(assiduite);
|
||||||
|
});
|
||||||
|
const editButton = document.createElement("button");
|
||||||
|
editButton.textContent = "📝";
|
||||||
|
editButton.addEventListener("click", () => {
|
||||||
|
this.editerAssiduite(assiduite);
|
||||||
|
});
|
||||||
|
const splitButton = document.createElement("button");
|
||||||
|
splitButton.textContent = "✂️";
|
||||||
|
splitButton.addEventListener("click", () => {
|
||||||
|
this.spliterAssiduite(assiduite);
|
||||||
|
});
|
||||||
|
|
||||||
|
actionButtons.appendChild(editButton);
|
||||||
|
actionButtons.appendChild(splitButton);
|
||||||
|
actionButtons.appendChild(deleteButton);
|
||||||
|
el.appendChild(actionButtons);
|
||||||
|
|
||||||
|
setupAssiduiteBubble(el, assiduite);
|
||||||
|
assiduitesContainer.appendChild(el);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
supprimerAssiduite(assiduite) {
|
||||||
|
const html = `
|
||||||
|
<p>Êtes-vous sûr de vouloir supprimer cette assiduité ?</p>
|
||||||
|
`;
|
||||||
|
const div = document.createElement("div");
|
||||||
|
div.innerHTML = html;
|
||||||
|
|
||||||
|
openPromptModal(
|
||||||
|
"Suppression de l'assiduité",
|
||||||
|
div,
|
||||||
|
async (closePromptModal) => {
|
||||||
|
await async_post(
|
||||||
|
`../../api/assiduite/delete`,
|
||||||
|
[assiduite.assiduite_id],
|
||||||
|
async (data) => {
|
||||||
|
if (data.success.length > 0) {
|
||||||
|
const etud = etuds.get(Number(assiduite.etudid));
|
||||||
|
await MiseAJourLigneEtud(etud);
|
||||||
|
this.refresh(etud.assiduites, this.conflictPeriod);
|
||||||
|
closePromptModal();
|
||||||
|
} else {
|
||||||
|
console.error(data.errors["0"].message);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error(
|
||||||
|
"Erreur lors de la suppression de l'assiduité",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
"var(--color-error)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
editerAssiduite(assiduite) {
|
||||||
* Sélection d'une assiduité sur la timeline
|
// Select pour choisir l'état de l'assiduité
|
||||||
* @param {Assiduité} assiduite l'assiduité sélectionnée
|
|
||||||
*/
|
const html = `
|
||||||
selectAssiduite(assiduite) {
|
<select id="etat" name="etat">
|
||||||
// Désélectionner l'assiduité précédemment sélectionnée
|
<option disabled>Choisir un état</option>
|
||||||
if (this.selectedAssiduite) {
|
<option value="present">Présent</option>
|
||||||
const prevSelectedEl = document.querySelector(
|
<option value="absent">Absent</option>
|
||||||
`.assiduite[data-id="${this.selectedAssiduite.assiduite_id}"]`
|
<option value="retard">Retard</option>
|
||||||
);
|
</select>
|
||||||
if (prevSelectedEl) {
|
`;
|
||||||
prevSelectedEl.classList.remove("selected");
|
|
||||||
}
|
const div = document.createElement("div");
|
||||||
|
div.innerHTML = html;
|
||||||
|
div.style.display = "flex";
|
||||||
|
div.style.justifyContent = "center";
|
||||||
|
|
||||||
|
openPromptModal(
|
||||||
|
"Modifier l'état de l'assiduité",
|
||||||
|
div,
|
||||||
|
async (closePromptModal) => {
|
||||||
|
const etatAssi = etat.value;
|
||||||
|
if (!etat) return true;
|
||||||
|
|
||||||
|
await async_post(
|
||||||
|
`../../api/assiduite/${assiduite.assiduite_id}/edit`,
|
||||||
|
{
|
||||||
|
etat: etatAssi,
|
||||||
|
},
|
||||||
|
async (data) => {
|
||||||
|
const etud = etuds.get(Number(assiduite.etudid));
|
||||||
|
await MiseAJourLigneEtud(etud);
|
||||||
|
this.refresh(etud.assiduites, this.conflictPeriod);
|
||||||
|
closePromptModal();
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error("Erreur lors de la modification de l'assiduité", error);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Sélectionner la nouvelle assiduité
|
},
|
||||||
this.selectedAssiduite = assiduite;
|
() => {},
|
||||||
const selectedEl = document.querySelector(
|
"var(--color-present)"
|
||||||
`.assiduite[data-id="${assiduite.assiduite_id}"]`
|
);
|
||||||
);
|
}
|
||||||
if (selectedEl) {
|
|
||||||
selectedEl.classList.add("selected");
|
|
||||||
}
|
|
||||||
|
|
||||||
//Mise à jour de la partie information du modal
|
spliterAssiduite(assiduite) {
|
||||||
const selectedModal = document.querySelector(".modal-assiduite-content");
|
// Select pour choisir l'état de l'assiduité
|
||||||
|
const creneau = getPeriodAsDate()
|
||||||
|
creneau.deb = creneau.deb.format().substring(11,16)
|
||||||
|
creneau.fin = creneau.fin.format().substring(11,16)
|
||||||
|
const html = `
|
||||||
|
<p>La période conflictuelle s'étend de ${creneau.deb} à ${creneau.fin}</p>
|
||||||
|
<br>
|
||||||
|
<input type="text" id="promptTime" name="promptTime" class="timepicker"
|
||||||
|
placeholder="Cliquez pour choisir un horaire" required>
|
||||||
|
`;
|
||||||
|
|
||||||
selectedModal.classList.add("show");
|
const div = document.createElement("div");
|
||||||
|
div.innerHTML = html;
|
||||||
|
div.style.display = "flex";
|
||||||
|
div.style.justifyContent = "center";
|
||||||
|
div.style.flexDirection = "column";
|
||||||
|
|
||||||
document.getElementById("modal-assiduite-id").textContent =
|
openPromptModal(
|
||||||
assiduite.assiduite_id;
|
"Séparer l'assiduité",
|
||||||
document.getElementById(
|
div,
|
||||||
"modal-assiduite-user"
|
async (closePromptModal) => {
|
||||||
).textContent = `saisie le ${formatDateModal(
|
const separateur = promptTime.value;
|
||||||
assiduite.entry_date,
|
if (separateur === "") return true;
|
||||||
"à"
|
|
||||||
)} \npar ${assiduite.user_id}`;
|
|
||||||
document.getElementById("modal-assiduite-module").textContent =
|
|
||||||
assiduite.moduleimpl_id;
|
|
||||||
document.getElementById("modal-assiduite-deb").textContent = formatDateModal(
|
|
||||||
assiduite.date_debut
|
|
||||||
);
|
|
||||||
document.getElementById("modal-assiduite-fin").textContent = formatDateModal(
|
|
||||||
assiduite.date_fin
|
|
||||||
);
|
|
||||||
document.getElementById("modal-assiduite-etat").textContent =
|
|
||||||
assiduite.etat.capitalize();
|
|
||||||
|
|
||||||
//Activation des boutons d'actions de conflit
|
const assiduiteAvant = {...assiduite};
|
||||||
this.deleteBtn.disabled = false;
|
const assiduiteAprès = {...assiduite};
|
||||||
this.splitBtn.disabled = false;
|
|
||||||
this.editBtn.disabled = false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Suppression de l'assiduité sélectionnée
|
|
||||||
*/
|
|
||||||
deleteAssiduiteModal() {
|
|
||||||
if (!this.selectedAssiduite) return;
|
|
||||||
deleteAssiduite(this.selectedAssiduite.assiduite_id);
|
|
||||||
|
|
||||||
this.callbacks.delete(this.selectedAssiduite)
|
assiduiteAvant.date_fin = assiduite.date_fin.substring(0,11) + separateur;
|
||||||
|
assiduiteAprès.date_debut = assiduite.date_debut.substring(0,11) + separateur;
|
||||||
|
|
||||||
this.refresh(assiduites[this.selectedAssiduite.etudid]);
|
// On supprime l'assiduité actuelle
|
||||||
|
await async_post(
|
||||||
|
"../../api/assiduite/delete",
|
||||||
|
[assiduite.assiduite_id],
|
||||||
|
(data)=>{console.log(data)},
|
||||||
|
()=>{},
|
||||||
|
)
|
||||||
|
|
||||||
// Désélection de l'assiduité
|
// On ajoute les deux nouvelles assiduités
|
||||||
this.resetSelection();
|
await async_post(
|
||||||
}
|
"../../api/assiduites/create",
|
||||||
|
[assiduiteAvant, assiduiteAprès],
|
||||||
|
async (data)=>{
|
||||||
|
console.log(data);
|
||||||
|
const etud = etuds.get(Number(assiduite.etudid));
|
||||||
|
await MiseAJourLigneEtud(etud);
|
||||||
|
this.refresh(etud.assiduites, this.conflictPeriod);
|
||||||
|
closePromptModal();
|
||||||
|
},
|
||||||
|
()=>{},
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
},
|
||||||
* Division d'une assiduité
|
() => {},
|
||||||
*/
|
"var(--color-retard)"
|
||||||
splitAssiduiteModal() {
|
);
|
||||||
//Préparation du prompt
|
|
||||||
const htmlPrompt = `<legend>Entrez l'heure de séparation</legend>
|
// Initialisation du timepicker
|
||||||
<input type="text" id="promptTime" name="appt"required style="position: relative; z-index: 100000;">`;
|
const deb = assiduite.date_debut.substring(11,16);
|
||||||
|
const fin = assiduite.date_fin.substring(11,16);
|
||||||
const fieldSet = document.createElement("fieldset");
|
|
||||||
fieldSet.classList.add("fieldsplit", "timepicker");
|
|
||||||
fieldSet.innerHTML = htmlPrompt;
|
|
||||||
|
|
||||||
//Callback de division
|
|
||||||
const success = () => {
|
|
||||||
const separatorTime = document.getElementById("promptTime").value;
|
|
||||||
const dateString =
|
|
||||||
getDate().format("YYYY-MM-DD") + `T${separatorTime}`;
|
|
||||||
const separtorDate = new Date(dateString);
|
|
||||||
|
|
||||||
const assiduite_debut = new Date(this.selectedAssiduite.date_debut);
|
|
||||||
const assiduite_fin = new Date(this.selectedAssiduite.date_fin);
|
|
||||||
|
|
||||||
if (
|
|
||||||
separtorDate.isAfter(assiduite_debut) &&
|
|
||||||
separtorDate.isBefore(assiduite_fin)
|
|
||||||
) {
|
|
||||||
const assiduite_avant = {
|
|
||||||
etat: this.selectedAssiduite.etat,
|
|
||||||
date_debut: assiduite_debut.toFakeIso(),
|
|
||||||
date_fin: separtorDate.toFakeIso(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const assiduite_apres = {
|
|
||||||
etat: this.selectedAssiduite.etat,
|
|
||||||
date_debut: separtorDate.toFakeIso(),
|
|
||||||
date_fin: assiduite_fin.toFakeIso(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.selectedAssiduite.moduleimpl_id) {
|
|
||||||
assiduite_apres["moduleimpl_id"] = this.selectedAssiduite.moduleimpl_id;
|
|
||||||
assiduite_avant["moduleimpl_id"] = this.selectedAssiduite.moduleimpl_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteAssiduite(this.selectedAssiduite.assiduite_id);
|
|
||||||
|
|
||||||
const path = getUrl() + `/api/assiduite/${this.selectedAssiduite.etudid}/create`;
|
|
||||||
sync_post(
|
|
||||||
path,
|
|
||||||
[assiduite_avant, assiduite_apres],
|
|
||||||
(data, status) => {
|
|
||||||
//success
|
|
||||||
},
|
|
||||||
(data, status) => {
|
|
||||||
//error
|
|
||||||
console.error(data, status);
|
|
||||||
errorAlert();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
this.callbacks.split(this.selectedAssiduite)
|
|
||||||
this.refresh(assiduites[this.selectedAssiduite.etudid]);
|
|
||||||
this.resetSelection();
|
|
||||||
} else {
|
|
||||||
const att = document.createTextNode(
|
|
||||||
"L'heure de séparation doit être compris dans la période de l'assiduité sélectionnée."
|
|
||||||
);
|
|
||||||
|
|
||||||
openAlertModal("Attention", att, "", "var(--color-warning)");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
openPromptModal("Séparation de l'assiduité sélectionnée", fieldSet, success, () => { }, "var(--color-present)");
|
|
||||||
// Initialisation du timepicker
|
|
||||||
const deb = this.selectedAssiduite.date_debut.substring(11,16);
|
|
||||||
const fin = this.selectedAssiduite.date_fin.substring(11,16);
|
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
$('#promptTime').timepicker({
|
$('#promptTime').timepicker({
|
||||||
timeFormat: 'HH:mm',
|
timeFormat: 'HH:mm',
|
||||||
@ -331,150 +376,15 @@
|
|||||||
});
|
});
|
||||||
}, 100
|
}, 100
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Modification d'une assiduité conflictuelle
|
}
|
||||||
*/
|
|
||||||
editAssiduiteModal() {
|
|
||||||
if (!this.selectedAssiduite) return;
|
|
||||||
|
|
||||||
//Préparation du modal d'édition
|
|
||||||
const htmlPrompt = `<legend>Entrez l'état de l'assiduité :</legend>
|
|
||||||
<select name="promptSelect" id="promptSelect" required>
|
|
||||||
<option value="">Choissez l'état</option>
|
|
||||||
<option value="present">Présent</option>
|
|
||||||
<option value="retard">En Retard</option>
|
|
||||||
<option value="absent">Absent</option>
|
|
||||||
</select>`;
|
|
||||||
|
|
||||||
const fieldSet = document.createElement("fieldset");
|
|
||||||
fieldSet.classList.add("fieldsplit");
|
|
||||||
fieldSet.innerHTML = htmlPrompt;
|
|
||||||
|
|
||||||
//Callback d'action d'édition
|
|
||||||
const success = () => {
|
|
||||||
const newState = document.getElementById("promptSelect").value;
|
|
||||||
if (!["present", "absent", "retard"].includes(newState.toLowerCase())) {
|
|
||||||
const att = document.createTextNode(
|
|
||||||
"L'état doit être 'present', 'absent' ou 'retard'."
|
|
||||||
);
|
|
||||||
openAlertModal("Attention", att, "", "var(--color-warning)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actualiser l'affichage
|
|
||||||
|
|
||||||
editAssiduite(this.selectedAssiduite.assiduite_id, newState, [this.selectedAssiduite]);
|
|
||||||
this.callbacks.edit(this.selectedAssiduite)
|
|
||||||
this.refresh(assiduites[this.selectedAssiduite.etudid]);
|
|
||||||
|
|
||||||
// Désélection de l'assiduité
|
|
||||||
this.resetSelection();
|
|
||||||
};
|
|
||||||
|
|
||||||
//Affichage du prompt
|
|
||||||
openPromptModal("Modification de l'état de l'assiduité sélectionnée", fieldSet, success, () => { }, "var(--color-present)");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Génération du modal
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
const timeLabels = document.querySelector(".time-labels");
|
|
||||||
const assiduitesContainer = document.querySelector(".assiduites-container");
|
|
||||||
|
|
||||||
timeLabels.innerHTML = "";
|
|
||||||
assiduitesContainer.innerHTML = '<div class="assiduite-special"></div>';
|
|
||||||
|
|
||||||
// Ajout des labels d'heure sur la frise chronologique
|
|
||||||
for (let i = t_start; i <= t_end; i++) {
|
|
||||||
const timeLabel = document.createElement("div");
|
|
||||||
timeLabel.className = "time-label";
|
|
||||||
timeLabel.textContent = i < 10 ? `0${i}:00` : `${i}:00`;
|
|
||||||
timeLabels.appendChild(timeLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Placement de la période conflictuelle sur la timeline
|
|
||||||
const specialAssiduiteEl = document.querySelector(".assiduite-special");
|
|
||||||
|
|
||||||
specialAssiduiteEl.style.width = getWidth(
|
|
||||||
this.conflictPeriod.deb,
|
|
||||||
this.conflictPeriod.fin
|
|
||||||
);
|
|
||||||
specialAssiduiteEl.style.left = getLeftPosition(this.conflictPeriod.deb);
|
|
||||||
specialAssiduiteEl.style.top = "0";
|
|
||||||
specialAssiduiteEl.style.zIndex = "0"; // Place l'assiduité spéciale en arrière-plan
|
|
||||||
assiduitesContainer.appendChild(specialAssiduiteEl);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Placement des assiduités sur la timeline
|
|
||||||
this.list.forEach((assiduite) => {
|
|
||||||
const period = {
|
|
||||||
deb: new Date(assiduite.date_debut),
|
|
||||||
fin: new Date(assiduite.date_fin),
|
|
||||||
};
|
|
||||||
if (!hasTimeConflict(period, this.interval)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const el = document.createElement("div");
|
|
||||||
el.className = "assiduite";
|
|
||||||
el.style.backgroundColor = getColor(assiduite.etat);
|
|
||||||
|
|
||||||
|
|
||||||
el.style.width = getWidth(assiduite.date_debut, assiduite.date_fin);
|
|
||||||
el.style.left = getLeftPosition(assiduite.date_debut);
|
|
||||||
el.style.top = "10px";
|
|
||||||
el.setAttribute("data-id", assiduite.assiduite_id);
|
|
||||||
el.addEventListener("click", () => this.selectAssiduite(assiduite));
|
|
||||||
|
|
||||||
// Ajout des informations dans la visualisation d'une assiduité
|
|
||||||
const infoContainer = document.createElement("div");
|
|
||||||
infoContainer.className = "assiduite-info";
|
|
||||||
|
|
||||||
const idDiv = document.createElement("div");
|
|
||||||
idDiv.className = "assiduite-id";
|
|
||||||
idDiv.textContent = `ID: ${assiduite.assiduite_id}`;
|
|
||||||
infoContainer.appendChild(idDiv);
|
|
||||||
|
|
||||||
const periodDivDeb = document.createElement("div");
|
|
||||||
periodDivDeb.className = "assiduite-period";
|
|
||||||
periodDivDeb.textContent = `${formatDateModal(assiduite.date_debut)}`;
|
|
||||||
infoContainer.appendChild(periodDivDeb);
|
|
||||||
const periodDivFin = document.createElement("div");
|
|
||||||
periodDivFin.className = "assiduite-period";
|
|
||||||
periodDivFin.textContent = `${formatDateModal(assiduite.date_fin)}`;
|
|
||||||
infoContainer.appendChild(periodDivFin);
|
|
||||||
|
|
||||||
const stateDiv = document.createElement("div");
|
|
||||||
stateDiv.className = "assiduite-state";
|
|
||||||
stateDiv.textContent = `État: ${assiduite.etat.capitalize()}`;
|
|
||||||
infoContainer.appendChild(stateDiv);
|
|
||||||
|
|
||||||
const userIdDiv = document.createElement("div");
|
|
||||||
userIdDiv.className = "assiduite-user_id";
|
|
||||||
userIdDiv.textContent = `saisie le ${formatDateModal(
|
|
||||||
assiduite.entry_date,
|
|
||||||
"à"
|
|
||||||
)} \npar ${assiduite.user_id}`;
|
|
||||||
infoContainer.appendChild(userIdDiv);
|
|
||||||
|
|
||||||
el.appendChild(infoContainer);
|
|
||||||
assiduitesContainer.appendChild(el);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Remise à zéro de la sélection
|
|
||||||
* Désactivation des boutons d'actions de conflit
|
|
||||||
*/
|
|
||||||
resetSelection() {
|
|
||||||
this.selectedAssiduite = null;
|
|
||||||
this.deleteBtn.disabled = true;
|
|
||||||
this.splitBtn.disabled = true;
|
|
||||||
this.editBtn.disabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
.ui-timepicker-container {
|
.ui-timepicker-container {
|
||||||
|
@ -13,23 +13,18 @@
|
|||||||
*/
|
*/
|
||||||
function createMiniTimeline(assiduitesArray, day = null) {
|
function createMiniTimeline(assiduitesArray, day = null) {
|
||||||
const array = [...assiduitesArray];
|
const array = [...assiduitesArray];
|
||||||
const date = day == null ? getDate() : new Date(day);
|
const date = day == null ? $("#date").datepicker("getDate") : new Date(day);
|
||||||
const timeline = document.createElement("div");
|
const timeline = document.createElement("div");
|
||||||
timeline.className = "mini-timeline";
|
timeline.className = "mini-timeline";
|
||||||
if (isSingleEtud()) {
|
|
||||||
timeline.classList.add("single");
|
|
||||||
}
|
|
||||||
const timelineDate = date.startOf("day");
|
const timelineDate = date.startOf("day");
|
||||||
const dayStart = timelineDate.clone().add(mt_start, "hours");
|
const dayStart = new Date(`${timelineDate.format("YYYY-MM-DD").substring(0,10)}T${numberToTime(mt_start)}`);
|
||||||
const dayEnd = timelineDate.clone().add(mt_end, "hours");
|
const dayEnd = new Date(`${timelineDate.format("YYYY-MM-DD").substring(0,10)}T${numberToTime(mt_end)}`);
|
||||||
const dayDuration = new Duration(dayStart, dayEnd).minutes;
|
const dayDuration = new Duration(dayStart, dayEnd).minutes;
|
||||||
|
|
||||||
timeline.appendChild(setMiniTick(timelineDate, dayStart, dayDuration));
|
timeline.appendChild(setMiniTick(timelineDate, dayStart, dayDuration));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (day == null) {
|
if (day == null) {
|
||||||
const tlTimes = getTimeLineTimes();
|
const tlTimes = getPeriodAsDate();
|
||||||
array.push({
|
array.push({
|
||||||
date_debut: tlTimes.deb.format(),
|
date_debut: tlTimes.deb.format(),
|
||||||
date_fin: tlTimes.fin.format(),
|
date_fin: tlTimes.fin.format(),
|
||||||
@ -69,56 +64,20 @@
|
|||||||
fin = Math.min(mt_end, fin);
|
fin = Math.min(mt_end, fin);
|
||||||
|
|
||||||
if (day == null) setPeriodValues(deb, fin);
|
if (day == null) setPeriodValues(deb, fin);
|
||||||
if (isSingleEtud()) {
|
|
||||||
updateSelectedSelect(getCurrentAssiduiteModuleImplId());
|
$("#moduleimpl_select").val(getModuleImplId(assiduité))
|
||||||
updateJustifyBtn();
|
setTimeout(()=>{
|
||||||
}
|
$("#moduleimpl_select").trigger("change");
|
||||||
|
}, 0)
|
||||||
});
|
});
|
||||||
//ajouter affichage assiduites on over
|
//ajouter affichage assiduites on over
|
||||||
setupAssiduiteBuble(block, assiduité);
|
setupAssiduiteBubble(block, assiduité);
|
||||||
}
|
}
|
||||||
|
|
||||||
const action = (justificatifs) => {
|
// TODO: ajout couleur justificatif
|
||||||
if (justificatifs.length > 0) {
|
|
||||||
let j = "invalid_justified";
|
|
||||||
|
|
||||||
justificatifs.forEach((ju) => {
|
block.classList.add(assiduité.etat.toLowerCase());
|
||||||
if (ju.etat == "VALIDE") {
|
if(assiduité.etat != "CRENEAU") block.classList.add("color");
|
||||||
j = "justified";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
block.classList.add(j);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (assiduité.etudid) {
|
|
||||||
getJustificatifFromPeriod(
|
|
||||||
{
|
|
||||||
deb: new Date(assiduité.date_debut),
|
|
||||||
fin: new Date(assiduité.date_fin),
|
|
||||||
},
|
|
||||||
assiduité.etudid,
|
|
||||||
action
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (assiduité.etat) {
|
|
||||||
case "PRESENT":
|
|
||||||
block.classList.add("present");
|
|
||||||
break;
|
|
||||||
case "RETARD":
|
|
||||||
block.classList.add("retard");
|
|
||||||
break;
|
|
||||||
case "ABSENT":
|
|
||||||
block.classList.add("absent");
|
|
||||||
break;
|
|
||||||
case "CRENEAU":
|
|
||||||
block.classList.add("creneau");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
block.style.backgroundColor = "white";
|
|
||||||
}
|
|
||||||
|
|
||||||
timeline.appendChild(block);
|
timeline.appendChild(block);
|
||||||
});
|
});
|
||||||
@ -131,7 +90,13 @@
|
|||||||
* @param {HTMLElement} el l'élément survollé
|
* @param {HTMLElement} el l'élément survollé
|
||||||
* @param {Assiduité} assiduite l'assiduité représentée par l'élément
|
* @param {Assiduité} assiduite l'assiduité représentée par l'élément
|
||||||
*/
|
*/
|
||||||
function setupAssiduiteBuble(el, assiduite) {
|
function setupAssiduiteBubble(el, assiduite) {
|
||||||
|
|
||||||
|
function formatDateModal(dateStr){
|
||||||
|
const date = new Date(Date.removeUTC(dateStr));
|
||||||
|
return date.format("DD/MM/Y HH:mm");
|
||||||
|
}
|
||||||
|
|
||||||
if (!assiduite) return;
|
if (!assiduite) return;
|
||||||
|
|
||||||
const bubble = document.createElement('div');
|
const bubble = document.createElement('div');
|
||||||
@ -140,7 +105,9 @@
|
|||||||
|
|
||||||
const idDiv = document.createElement("div");
|
const idDiv = document.createElement("div");
|
||||||
idDiv.className = "assiduite-id";
|
idDiv.className = "assiduite-id";
|
||||||
idDiv.textContent = `${getModuleImpl(assiduite)}`;
|
getModuleImpl(assiduite).then((modImpl) => {
|
||||||
|
idDiv.textContent = `${modImpl}`;
|
||||||
|
});
|
||||||
bubble.appendChild(idDiv);
|
bubble.appendChild(idDiv);
|
||||||
|
|
||||||
const periodDivDeb = document.createElement("div");
|
const periodDivDeb = document.createElement("div");
|
||||||
@ -159,7 +126,8 @@
|
|||||||
|
|
||||||
const motifDiv = document.createElement("div");
|
const motifDiv = document.createElement("div");
|
||||||
stateDiv.className = "assiduite-why";
|
stateDiv.className = "assiduite-why";
|
||||||
stateDiv.textContent = `Motif: ${assiduite.desc?.capitalize()}`;
|
const motif = ["", null, undefined].includes(assiduite.desc) ? "Pas de motif" : assiduite.desc.capitalize();
|
||||||
|
stateDiv.textContent = `Motif: ${motif}`;
|
||||||
bubble.appendChild(motifDiv);
|
bubble.appendChild(motifDiv);
|
||||||
|
|
||||||
const userIdDiv = document.createElement("div");
|
const userIdDiv = document.createElement("div");
|
||||||
|
Loading…
Reference in New Issue
Block a user