formsemestre_status: refonte cadre groupes/assiduité

This commit is contained in:
Emmanuel Viennet 2023-09-19 21:39:36 +02:00
parent b124468399
commit 3bf36c1119
5 changed files with 151 additions and 103 deletions

View File

@ -771,6 +771,15 @@ class FormSemestre(db.Model):
etuds.sort(key=lambda e: e.sort_key) etuds.sort(key=lambda e: e.sort_key)
return etuds return etuds
def get_partitions_list(self, with_default=True) -> list[Partition]:
"""Liste des partitions pour ce semestre (list of dicts),
triées par numéro, avec la partition par défaut en fin de liste.
"""
partitions = [p for p in self.partitions if p.partition_name is not None]
if with_default:
partitions += [p for p in partitions if p.partition_name is None]
return partitions
@cached_property @cached_property
def etudids_actifs(self) -> set: def etudids_actifs(self) -> set:
"Set des etudids inscrits non démissionnaires et non défaillants" "Set des etudids inscrits non démissionnaires et non défaillants"

View File

@ -818,101 +818,113 @@ def _make_listes_sem(formsemestre: FormSemestre) -> str:
can_edit_abs = current_user.has_permission(Permission.ScoAbsChange) can_edit_abs = current_user.has_permission(Permission.ScoAbsChange)
# #
H.append( H.append(
f"""<h3>Listes de {formsemestre.titre} f"""<h3>Groupes et absences de {formsemestre.titre}
<span class="infostitresem">({formsemestre.mois_debut()} - {formsemestre.mois_fin()})</span></h3>""" <span class="infostitresem">({
formsemestre.mois_debut()} - {formsemestre.mois_fin()
})</span></h3>"""
) )
form_abs_tmpl = f"""
<td>
<a class="btn" href="{
url_for("assiduites.visu_assi_group",
scodoc_dept=g.scodoc_dept,
date_debut=formsemestre.date_debut.isoformat(),
date_fin=formsemestre.date_fin.isoformat()
)}&group_ids=%(group_id)s">
<button>Bilan assiduité</button></a>
"""
if can_edit_abs:
form_abs_tmpl += f"""
<a class="btn" href="{
url_for("assiduites.visu_assiduites_group",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id,
jour = datetime.date.today().isoformat()
)}&group_ids=%(group_id)s">
<button>Visualiser l'assiduité</button></a>
<a class="btn" href="{
url_for("assiduites.signal_assiduites_group",
scodoc_dept=g.scodoc_dept,
jour=datetime.date.today().isoformat(),
formsemestre_id=formsemestre.id,
)}&group_ids=%(group_id)s">
<button>Saisie journalière</button></a>
<a class="btn" href="{
url_for("assiduites.signal_assiduites_diff",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id,
)}&group_ids=%(group_id)s">
<button>Saisie différée</button></a>
<a class="btn" href="{
url_for("assiduites.bilan_dept",
scodoc_dept=g.scodoc_dept,
formsemestre=formsemestre.id,
)}&group_id=%(group_id)s">
<button>Justificatifs en attente</button></a>
"""
form_abs_tmpl += "</td>"
# #
H.append('<div id="grouplists">') H.append('<div class="sem-groups-abs">')
# Genere liste pour chaque partition (categorie de groupes) # Genere liste pour chaque partition (categorie de groupes)
for partition in sco_groups.get_partitions_list(formsemestre.id): for partition in formsemestre.get_partitions_list():
if not partition["partition_name"]: groups = partition.groups.all()
H.append("<h4>Tous les étudiants</h4>") effectifs = {g.id: g.etuds.count() for g in groups}
else: partition_is_empty = sum(effectifs.values()) == 0
H.append(f"""<h4>Groupes de {partition["partition_name"]}</h4>""") H.append(
partition_is_empty = True f"""
groups = sco_groups.get_partition_groups(partition) <div class="sem-groups-partition">
<div class="sem-groups-partition-titre">{
'Groupes de ' + partition.partition_name
if partition.partition_name else
'Tous les étudiants'}
</div>
<div class="sem-groups-partition-titre">{
"Gestion de l'assiduité" if not partition_is_empty else ""
}</div>
"""
)
if groups: if groups:
H.append("<table>")
for group in groups: for group in groups:
n_members = len(sco_groups.get_group_members(group["group_id"])) n_members = effectifs[group.id]
if n_members == 0: if n_members == 0:
continue # skip empty groups continue # skip empty groups
partition_is_empty = False partition_is_empty = False
group["url_etat"] = url_for( group_label = f"{group.group_name}" if group.group_name else "liste"
"assiduites.visu_assi_group",
scodoc_dept=g.scodoc_dept,
group_ids=group["id"],
date_debut=formsemestre.date_debut.isoformat(),
date_fin=formsemestre.date_fin.isoformat(),
)
if group["group_name"]:
group["label"] = "groupe %(group_name)s" % group
else:
group["label"] = "liste"
H.append( H.append(
f""" f"""
<tr class="listegroupelink"> <div class="sem-groups-list">
<td> <div>
<a href="{ <a href="{
url_for("scolar.groups_view", url_for("scolar.groups_view",
group_ids=group["group_id"], group_ids=group.id,
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
) )
}">{group["label"]}</a> }">{group_label}
</td><td> - {n_members} étudiants</a>
</td> </div>
<td>({n_members} étudiants)</td> </div>
<div class="sem-groups-assi">
<div>
<a class="btn" href="{
url_for("assiduites.visu_assi_group",
scodoc_dept=g.scodoc_dept,
date_debut=formsemestre.date_debut.isoformat(),
date_fin=formsemestre.date_fin.isoformat(),
group_ids=group.id,
)}">
<button>Bilan assiduité</button></a>
</div>
""" """
) )
if can_edit_abs:
H.append(
f"""
<div>
<a class="btn" href="{
url_for("assiduites.visu_assiduites_group",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id,
jour = datetime.date.today().isoformat(),
group_ids=group.id,
)}">
<button>Visualiser l'assiduité</button></a>
</div>
<div>
<a class="btn" href="{
url_for("assiduites.signal_assiduites_group",
scodoc_dept=g.scodoc_dept,
jour=datetime.date.today().isoformat(),
formsemestre_id=formsemestre.id,
group_ids=group.id,
)}">
<button>Saisie journalière</button></a>
</div>
<div>
<a class="btn" href="{
url_for("assiduites.signal_assiduites_diff",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id,
group_ids=group.id,
)}">
<button>Saisie différée</button></a>
</div>
<div>
<a class="btn" href="{
url_for("assiduites.bilan_dept",
scodoc_dept=g.scodoc_dept,
formsemestre=formsemestre.id,
group_ids=group.id,
)}">
<button>Justificatifs en attente</button></a>
</div>
"""
)
H.append(form_abs_tmpl % group) H.append("</div>") # /sem-groups-assi
H.append("</tr>")
H.append("</table>")
if partition_is_empty: if partition_is_empty:
H.append('<p class="help indent">Aucun groupe peuplé dans cette partition') H.append(
'<div class="help sem-groups-none">Aucun groupe peuplé dans cette partition'
)
if formsemestre.can_change_groups(): if formsemestre.can_change_groups():
H.append( H.append(
f""" (<a href="{url_for("scolar.partition_editor", f""" (<a href="{url_for("scolar.partition_editor",
@ -921,7 +933,9 @@ def _make_listes_sem(formsemestre: FormSemestre) -> str:
edit_partition=1) edit_partition=1)
}" class="stdlink">créer</a>)""" }" class="stdlink">créer</a>)"""
) )
H.append("</p>") H.append("</div>")
H.append("</div>") # /sem-groups-partition
if formsemestre.can_change_groups(): if formsemestre.can_change_groups():
H.append( H.append(
f"""<h4><a class="stdlink" f"""<h4><a class="stdlink"
@ -1180,7 +1194,7 @@ def formsemestre_status(formsemestre_id=None, check_parcours=True):
) )
# --- LISTE DES ETUDIANTS # --- LISTE DES ETUDIANTS
H += [ H += [
'<div id="groupes">', '<div class="formsemestre-groupes">',
_make_listes_sem(formsemestre), _make_listes_sem(formsemestre),
"</div>", "</div>",
] ]

View File

@ -131,6 +131,7 @@ def get_partition(partition_id): # OBSOLETE
def get_partitions_list(formsemestre_id, with_default=True) -> list[dict]: def get_partitions_list(formsemestre_id, with_default=True) -> list[dict]:
"""Liste des partitions pour ce semestre (list of dicts), """Liste des partitions pour ce semestre (list of dicts),
triées par numéro, avec la partition par défaut en fin de liste. triées par numéro, avec la partition par défaut en fin de liste.
OBSOLETE: utiliser FormSemestre.get_partitions_list
""" """
partitions = ndb.SimpleDictFetch( partitions = ndb.SimpleDictFetch(
"""SELECT p.id AS partition_id, p.* """SELECT p.id AS partition_id, p.*

View File

@ -985,17 +985,6 @@ span.linktitresem a:visited {
color: red; color: red;
} }
.listegroupelink a:link {
color: blue;
}
.listegroupelink a:visited {
color: blue;
}
.listegroupelink a:hover {
color: red;
}
a.stdlink, a.stdlink,
a.stdlink:visited { a.stdlink:visited {
@ -1792,10 +1781,6 @@ td.formsemestre_status_inscrits {
text-align: center; text-align: center;
} }
div.formsemestre_status button {
margin-left: 12px;;
}
td.rcp_titre_sem a.jury_link { td.rcp_titre_sem a.jury_link {
margin-left: 8px; margin-left: 8px;
color: red; color: red;
@ -1857,15 +1842,54 @@ ul.ue_inscr_list li.etud {
margin-bottom: 5px; margin-bottom: 5px;
} }
#grouplists h4 { .sem-groups-abs {
background-color: rgb(137,137,137);
border-radius: 16px;
padding: 16px;
width: fit-content;
}
.sem-groups-abs h4 {
font-style: italic; font-style: italic;
margin-bottom: 0px; margin-bottom: 0px;
margin-top: 5px; margin-top: 5px;
} }
#grouplists table { .sem-groups-partition-titre {
/*border: 1px solid black;*/ margin-left: 4px;
border-spacing: 1px; font-size: 110%;
}
.sem-groups-partition {
background-color: rgb(213,203,183);
border-radius: 12px;
margin-bottom: 8px;
padding: 12px;
display: grid;
grid-template-columns: 240px auto;
}
.sem-groups-list, .sem-groups-assi {
background-color: white;
border-radius: 6px;
margin: 4px;
}
.sem-groups-list > div {
margin: 4px;
}
.sem-groups-assi > div {
margin: 6px 8px 6px 8px;
}
.sem-groups-assi {
display: flex;
flex-direction: row;
justify-content: flex-start;
flex-wrap: wrap;
align-items: center;
}
.sem-groups-none {
grid-column: 1 / span 2;
} }
/* Tableau de bord module */ /* Tableau de bord module */

View File

@ -1,7 +1,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
SCOVERSION = "9.6.30" SCOVERSION = "9.6.31"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"