forked from ScoDoc/ScoDoc
[WIP] Assiduité : saisie_assiduites_hebdo
This commit is contained in:
parent
7042650fd9
commit
eb88a8ca83
212
app/templates/assiduites/pages/signal_assiduites_hebdo.j2
Normal file
212
app/templates/assiduites/pages/signal_assiduites_hebdo.j2
Normal file
@ -0,0 +1,212 @@
|
||||
{% extends "sco_page.j2" %}
|
||||
|
||||
{% block styles %}
|
||||
{{ super() }}
|
||||
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/assiduites.css">
|
||||
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/minitimeline.css">
|
||||
|
||||
<style>
|
||||
.rbtn::before {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.ui-timepicker-container,
|
||||
#ui-datepicker-div {
|
||||
z-index: 5 !important;
|
||||
}
|
||||
|
||||
#new_periode,
|
||||
#actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: fit-content;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
#actions {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
#actions label {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#fix {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 1em;
|
||||
justify-content: space-between;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
#fix>.box {
|
||||
border: 1px solid #444;
|
||||
border-radius: 0.5em;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.timepicker {
|
||||
width: 5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#moduleimpl_select {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#tableau-periode {
|
||||
overflow-x: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
th {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.premier th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.second th {
|
||||
position: sticky;
|
||||
top: 38px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
||||
.sticky-col {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
td.active>.rbtn:not(:checked)::before {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
{% endblock styles %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="{{scu.STATIC_DIR}}/js/etud_info.js"></script>
|
||||
<script src="{{scu.STATIC_DIR}}/js/assiduites.js"></script>
|
||||
<script src="{{scu.STATIC_DIR}}/js/date_utils.js"></script>
|
||||
{% include "sco_timepicker.j2" %}
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
document.querySelectorAll(".rbtn").forEach((el)=>{
|
||||
el.addEventListener("click", (e)=>{
|
||||
let target = e.target;
|
||||
let parent = target.parentElement;
|
||||
let inputs = parent.querySelectorAll(".rbtn");
|
||||
|
||||
inputs.forEach((input)=>{
|
||||
if (input != target){
|
||||
input.checked = false;
|
||||
}
|
||||
});
|
||||
|
||||
if(!target.checked && parent.classList.contains("active")){
|
||||
parent.classList.remove("active");
|
||||
}else{
|
||||
parent.classList.add("active");
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock scripts %}
|
||||
|
||||
{% block title %}
|
||||
{{ title }}
|
||||
{% endblock title %}
|
||||
|
||||
{% block app_content %}
|
||||
|
||||
<h2>Signalement hebdomadaire de l'assiduité {{ gr | safe }}</h2>
|
||||
<br>
|
||||
<div id="actions" class="flex">
|
||||
<button>Semaine précédente</button>
|
||||
<label for="moduleimpl_select">
|
||||
Module:
|
||||
{{moduleimpl_select | safe}}
|
||||
</label>
|
||||
<button>Semaine suivante</button>
|
||||
</div>
|
||||
|
||||
<h3 id="tableau-dates">
|
||||
Le matin <a href="#" id="text-matin">9h à 12h</a> et l'après-midi de <a href="#" id="text-apresmidi">13h à 17h</a>
|
||||
</h3>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr class="premier">
|
||||
<th rowspan="2">Étudiants</th>
|
||||
<th colspan="2">Lundi</th>
|
||||
<th colspan="2">Mardi</th>
|
||||
<th colspan="2">Mercredi</th>
|
||||
<th colspan="2">Jeudi</th>
|
||||
<th colspan="2">Vendredi</th>
|
||||
</tr>
|
||||
<tr class="second">
|
||||
<th>Matin</th>
|
||||
<th>Après-midi</th>
|
||||
<th>Matin</th>
|
||||
<th>Après-midi</th>
|
||||
<th>Matin</th>
|
||||
<th>Après-midi</th>
|
||||
<th>Matin</th>
|
||||
<th>Après-midi</th>
|
||||
<th>Matin</th>
|
||||
<th>Après-midi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for etud in etudiants %}
|
||||
<tr>
|
||||
<td class="etudinfo" id="etud-{{etud.etudid}}">{{ etud.nomprenom }}</td>
|
||||
{# à changer par jour travaillés (sco pref) #}
|
||||
{% for day in ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi'] %}
|
||||
<td>
|
||||
<input type="checkbox" name="" id="" class="rbtn present">
|
||||
<input type="checkbox" name="" id="" class="rbtn retard">
|
||||
<input type="checkbox" name="" id="" class="rbtn absent">
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="" id="" class="rbtn present">
|
||||
<input type="checkbox" name="" id="" class="rbtn retard">
|
||||
<input type="checkbox" name="" id="" class="rbtn absent">
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% include "assiduites/widgets/alert.j2" %}
|
||||
{% endblock app_content %}
|
@ -1987,6 +1987,107 @@ def traitement_justificatifs():
|
||||
)
|
||||
|
||||
|
||||
@bp.route("signal_assiduites_hebdo")
|
||||
@scodoc
|
||||
@permission_required(Permission.AbsChange)
|
||||
def signal_assiduites_hebdo():
|
||||
"""
|
||||
signal_assiduites_hebdo
|
||||
|
||||
paramètres obligatoires :
|
||||
- formsemestre_id : id du formsemestre
|
||||
- semaine : date semaine (iso 8601 -> 20XX-WXX)
|
||||
- groups_id : id des groupes (séparés par des virgules -> 1,2,3)
|
||||
|
||||
paramètres optionnels :
|
||||
- moduleimpl_id : id du moduleimpl (par défaut None)
|
||||
"""
|
||||
|
||||
# Récupération des paramètres
|
||||
moduleimpl_id: int = request.args.get("moduleimpl_id", None)
|
||||
semaine: str = request.args.get("semaine", None)
|
||||
group_ids: list[int] = request.args.get("group_ids", None)
|
||||
formsemestre_id: int = request.args.get("formsemestre_id", -1)
|
||||
|
||||
# Vérification des paramètres
|
||||
if semaine is None or group_ids is None or formsemestre_id is None:
|
||||
raise ScoValueError("Paramètres manquants", dest_url=request.referrer)
|
||||
|
||||
# Récupération du moduleimpl
|
||||
moduleimpl: ModuleImpl | None = ModuleImpl.query.get(moduleimpl_id)
|
||||
module_text: str = "Non spécifié"
|
||||
if moduleimpl is not None:
|
||||
module_text = f"{moduleimpl.code} {moduleimpl.titre}"
|
||||
else:
|
||||
if moduleimpl_id == "autre":
|
||||
module_text = "Autre module (pas dans la liste)"
|
||||
moduleimpl_id = None if moduleimpl_id != "autre" else moduleimpl_id
|
||||
|
||||
# Récupération du formsemestre
|
||||
formsemestre: FormSemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||
|
||||
# vérification semaine dans format iso 8601 et formsemestre
|
||||
try:
|
||||
lundi_semaine = datetime.datetime.strptime(semaine + "-1", "%G-W%V-%u")
|
||||
if (
|
||||
lundi_semaine.date() < formsemestre.date_debut
|
||||
or lundi_semaine.date() > formsemestre.date_fin
|
||||
):
|
||||
raise ScoValueError(
|
||||
"Semaine en dehors du semestre", dest_url=request.referrer
|
||||
)
|
||||
|
||||
except (ValueError, TypeError) as exc:
|
||||
raise ScoValueError("Semaine invalide", dest_url=request.referrer) from exc
|
||||
except ScoValueError as exc:
|
||||
raise exc
|
||||
|
||||
etudiants: list[Identite] = []
|
||||
|
||||
# Vérification des groupes
|
||||
if group_ids is None:
|
||||
group_ids = []
|
||||
else:
|
||||
group_ids = group_ids.split(",")
|
||||
map(str, group_ids)
|
||||
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
||||
group_ids, formsemestre_id=formsemestre.id, select_all_when_unspecified=True
|
||||
)
|
||||
if not groups_infos.members:
|
||||
return (
|
||||
html_sco_header.sco_header(page_title="Assiduité: saisie hébdomadaire")
|
||||
+ "<h3>Aucun étudiant ! </h3>"
|
||||
+ html_sco_header.sco_footer()
|
||||
)
|
||||
|
||||
# Récupération des étudiants
|
||||
etudiants.extend(
|
||||
[Identite.get_etud(etudid=m["etudid"]) for m in groups_infos.members]
|
||||
)
|
||||
etudiants = list(sorted(etudiants, key=lambda etud: etud.sort_key))
|
||||
|
||||
if groups_infos.tous_les_etuds_du_sem:
|
||||
gr_tit = "en"
|
||||
else:
|
||||
if len(groups_infos.group_ids) > 1:
|
||||
grp = "des groupes"
|
||||
else:
|
||||
grp = "du groupe"
|
||||
gr_tit = (
|
||||
grp + ' <span class="fontred">' + groups_infos.groups_titles + "</span>"
|
||||
)
|
||||
|
||||
return render_template(
|
||||
"assiduites/pages/signal_assiduites_hebdo.j2",
|
||||
gr=gr_tit,
|
||||
module=module_text,
|
||||
etudiants=etudiants,
|
||||
moduleimpl_select=_module_selector(
|
||||
formsemestre=formsemestre, moduleimpl_id=moduleimpl_id
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def generate_bul_list(etud: Identite, semestre: FormSemestre) -> str:
|
||||
"""Génère la liste des assiduités d'un étudiant pour le bulletin mail"""
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user