forked from ScoDoc/ScoDoc
Editeur de partitions: liens vers outil de répartition
This commit is contained in:
parent
6c6d1103e6
commit
04a8177d12
@ -1332,17 +1332,6 @@ def groups_auto_repartition(partition: Partition):
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
H = [
|
|
||||||
f"""<h2>Répartition des groupes de {partition.partition_name}</h2>
|
|
||||||
<p>Semestre {formsemestre.titre_annee()}</p>
|
|
||||||
<p class="help">Les groupes existants seront <b>effacés</b> et remplacés par
|
|
||||||
ceux créés ici. La répartition aléatoire tente d'uniformiser le niveau
|
|
||||||
des groupes (en utilisant la dernière moyenne générale disponible pour
|
|
||||||
chaque étudiant) et de maximiser la mixité de chaque groupe.
|
|
||||||
</p>
|
|
||||||
""",
|
|
||||||
]
|
|
||||||
|
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
request.base_url,
|
request.base_url,
|
||||||
scu.get_request_args(),
|
scu.get_request_args(),
|
||||||
@ -1354,58 +1343,59 @@ def groups_auto_repartition(partition: Partition):
|
|||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return render_template(
|
return render_template(
|
||||||
"sco_page.j2",
|
"formsemestre/groups_auto_repartition.j2",
|
||||||
title="Répartition des groupes",
|
title="Répartition dans des groupes",
|
||||||
content="\n".join(H) + "\n" + tf[1],
|
form_html=tf[1],
|
||||||
|
partition=partition,
|
||||||
sco=ScoData(formsemestre=formsemestre),
|
sco=ScoData(formsemestre=formsemestre),
|
||||||
)
|
)
|
||||||
elif tf[0] == -1:
|
if tf[0] == -1:
|
||||||
return flask.redirect(dest_url)
|
return flask.redirect(dest_url)
|
||||||
else:
|
|
||||||
# form submission
|
# form submission
|
||||||
log(f"groups_auto_repartition({partition})")
|
log(f"groups_auto_repartition({partition})")
|
||||||
group_names = tf[2]["groupNames"]
|
group_names = tf[2]["groupNames"]
|
||||||
group_names = sorted({x.strip() for x in group_names.split(",")})
|
group_names = sorted({x.strip() for x in group_names.split(",")})
|
||||||
# Détruit les groupes existant de cette partition
|
# Détruit les groupes existant de cette partition
|
||||||
for group in partition.groups:
|
for group in partition.groups:
|
||||||
db.session.delete(group)
|
db.session.delete(group)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
# Crée les nouveaux groupes
|
# Crée les nouveaux groupes
|
||||||
groups = []
|
groups = []
|
||||||
for group_name in group_names:
|
for group_name in group_names:
|
||||||
if group_name.strip():
|
if group_name.strip():
|
||||||
groups.append(partition.create_group(group_name))
|
groups.append(partition.create_group(group_name))
|
||||||
#
|
#
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
identdict = nt.identdict
|
identdict = nt.identdict
|
||||||
# build: { civilite : liste etudids trie par niveau croissant }
|
# build: { civilite : liste etudids trie par niveau croissant }
|
||||||
civilites = {x["civilite"] for x in identdict.values()}
|
civilites = {x["civilite"] for x in identdict.values()}
|
||||||
listes = {}
|
listes = {}
|
||||||
|
for civilite in civilites:
|
||||||
|
listes[civilite] = [
|
||||||
|
(_get_prev_moy(x["etudid"], formsemestre.id), x["etudid"])
|
||||||
|
for x in identdict.values()
|
||||||
|
if x["civilite"] == civilite
|
||||||
|
]
|
||||||
|
listes[civilite].sort()
|
||||||
|
log("listes[%s] = %s" % (civilite, listes[civilite]))
|
||||||
|
# affect aux groupes:
|
||||||
|
n = len(identdict)
|
||||||
|
igroup = 0
|
||||||
|
nbgroups = len(groups)
|
||||||
|
while n > 0:
|
||||||
|
log(f"n={n}")
|
||||||
for civilite in civilites:
|
for civilite in civilites:
|
||||||
listes[civilite] = [
|
log(f"civilite={civilite}")
|
||||||
(_get_prev_moy(x["etudid"], formsemestre.id), x["etudid"])
|
if len(listes[civilite]):
|
||||||
for x in identdict.values()
|
n -= 1
|
||||||
if x["civilite"] == civilite
|
etudid = listes[civilite].pop()[1]
|
||||||
]
|
group = groups[igroup]
|
||||||
listes[civilite].sort()
|
igroup = (igroup + 1) % nbgroups
|
||||||
log("listes[%s] = %s" % (civilite, listes[civilite]))
|
log(f"in {etudid} in group {group.id}")
|
||||||
# affect aux groupes:
|
change_etud_group_in_partition(etudid, group)
|
||||||
n = len(identdict)
|
log(f"{etudid} in group {group.id}")
|
||||||
igroup = 0
|
return flask.redirect(dest_url)
|
||||||
nbgroups = len(groups)
|
|
||||||
while n > 0:
|
|
||||||
log(f"n={n}")
|
|
||||||
for civilite in civilites:
|
|
||||||
log(f"civilite={civilite}")
|
|
||||||
if len(listes[civilite]):
|
|
||||||
n -= 1
|
|
||||||
etudid = listes[civilite].pop()[1]
|
|
||||||
group = groups[igroup]
|
|
||||||
igroup = (igroup + 1) % nbgroups
|
|
||||||
log(f"in {etudid} in group {group.id}")
|
|
||||||
change_etud_group_in_partition(etudid, group)
|
|
||||||
log(f"{etudid} in group {group.id}")
|
|
||||||
return flask.redirect(dest_url)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_prev_moy(etudid: int, formsemestre_id: int) -> float | str:
|
def _get_prev_moy(etudid: int, formsemestre_id: int) -> float | str:
|
||||||
|
@ -309,7 +309,7 @@ body.editionActivated .filtres>div>div>div>div {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#zonePartitions span.editing a {
|
#zonePartitions span.editing a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,7 +400,7 @@ body.editionActivated .filtres .nonEditable .move {
|
|||||||
/*****************************/
|
/*****************************/
|
||||||
/* Zone Etudiants */
|
/* Zone Etudiants */
|
||||||
/*****************************/
|
/*****************************/
|
||||||
#zoneChoix summary{
|
#zoneChoix summary {
|
||||||
margin: 0 0 16px;
|
margin: 0 0 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
@ -450,6 +450,7 @@ body.editionActivated .filtres .nonEditable .move {
|
|||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
#zoneChoix .autoAffectation .progress {
|
#zoneChoix .autoAffectation .progress {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
@ -524,7 +525,8 @@ body.editionActivated .filtres .nonEditable .move {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#zoneChoix .etudiants .partition>div,
|
#zoneChoix .etudiants .partition>div,
|
||||||
#zoneChoix .etudiants .partition span {
|
#zoneChoix .etudiants .partition span,
|
||||||
|
div.partition-name {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border: 1px solid #aaa;
|
border: 1px solid #aaa;
|
||||||
@ -541,12 +543,22 @@ body.editionActivated .filtres .nonEditable .move {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#zoneChoix .etudiants .partition>:nth-child(1) {
|
#zoneChoix .etudiants .partition>:nth-child(1),
|
||||||
|
div.partition-name {
|
||||||
background: #09c;
|
background: #09c;
|
||||||
border-color: #09c;
|
border-color: #09c;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.partition-name {
|
||||||
|
display: inline-block;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.partition-name a {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
section:not(#zonePartitions) .hide {
|
section:not(#zonePartitions) .hide {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
30
app/templates/formsemestre/groups_auto_repartition.j2
Normal file
30
app/templates/formsemestre/groups_auto_repartition.j2
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{# Formulaire répartition auto dans les groupes #}
|
||||||
|
|
||||||
|
{% extends "sco_page.j2" %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
|
||||||
|
<h2>Répartition des groupes de {{partition.partition_name}}</h2>
|
||||||
|
|
||||||
|
<div class="scobox">
|
||||||
|
<div class="scobox-title">Semestre {{sco.formsemestre.titre_annee()}}</div>
|
||||||
|
|
||||||
|
<div class="help space-after-24 space-before-24">
|
||||||
|
💡Les groupes existants dans cette partition seront <b>effacés</b> et remplacés
|
||||||
|
par ceux créés ici. La répartition aléatoire tente d'uniformiser le niveau des
|
||||||
|
groupes (en utilisant la dernière moyenne générale disponible pour chaque
|
||||||
|
étudiant) et de maximiser la mixité de chaque groupe.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{form_html|safe}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a class="stdlink" href="{{
|
||||||
|
url_for('scolar.partition_editor',
|
||||||
|
scodoc_dept=g.scodoc_dept, formsemestre_id=sco.formsemestre.id)
|
||||||
|
}}">Retour à l'éditeur de partitions</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -52,7 +52,23 @@
|
|||||||
<details>
|
<details>
|
||||||
<summary>Outils d'affectation</summary>
|
<summary>Outils d'affectation</summary>
|
||||||
<div class="autoAffectation">
|
<div class="autoAffectation">
|
||||||
<a href="students_groups_auto_assignment?formsemestre_id={{formsemestre.id}}"><svg
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
|
||||||
|
stroke="#0b0b0b" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4M10 17l5-5-5-5M13.8 12H3" />
|
||||||
|
</svg> Répartir les étudiants dans les groupes
|
||||||
|
<div id="partitionsARepartir">
|
||||||
|
{# peuplé en js par listeGroupesRepartition()
|
||||||
|
<div class="partition-name"><a href="">TD</a></div>
|
||||||
|
<div class="partition-name"><a href="">groupes de projets</a></div>
|
||||||
|
#}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="autoAffectation">
|
||||||
|
<a href="{{
|
||||||
|
url_for('scolar.students_groups_auto_assignment',
|
||||||
|
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id
|
||||||
|
)}}"><svg
|
||||||
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
|
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
|
||||||
stroke="#0b0b0b" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
stroke="#0b0b0b" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4M10 17l5-5-5-5M13.8 12H3" />
|
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4M10 17l5-5-5-5M13.8 12H3" />
|
||||||
@ -134,6 +150,7 @@
|
|||||||
processDatas(partitions, etudiants);
|
processDatas(partitions, etudiants);
|
||||||
processEvents();
|
processEvents();
|
||||||
listeGroupesAutoaffectation();
|
listeGroupesAutoaffectation();
|
||||||
|
listeGroupesRepartition();
|
||||||
|
|
||||||
document.querySelector("body").classList.add("loaded");
|
document.querySelector("body").classList.add("loaded");
|
||||||
document.querySelector('.wait').style.display = "none";
|
document.querySelector('.wait').style.display = "none";
|
||||||
@ -354,6 +371,19 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function listeGroupesRepartition() { // peuple la liste des partitions pour répartition auto
|
||||||
|
let output = '';
|
||||||
|
document.querySelectorAll('#zonePartitions .filtres>[data-idpartition]').forEach(partition => {
|
||||||
|
if (!partition.classList.contains('nonEditable')) {
|
||||||
|
output += `
|
||||||
|
<div class="partition-name">
|
||||||
|
<a href="groups_auto_repartition/${partition.dataset.idpartition}">${partition.children[0].children[1].innerText}
|
||||||
|
</a></div>`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.querySelector("#partitionsARepartir").innerHTML = output;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************/
|
/******************************/
|
||||||
/* Gestionnaire d'événements */
|
/* Gestionnaire d'événements */
|
||||||
/******************************/
|
/******************************/
|
||||||
@ -677,6 +707,7 @@
|
|||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
listeGroupesAutoaffectation();
|
listeGroupesAutoaffectation();
|
||||||
|
listeGroupesRepartition();
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (1).</h2>";
|
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (1).</h2>";
|
||||||
@ -730,6 +761,7 @@
|
|||||||
// divGroupe.querySelector(".modif").click();
|
// divGroupe.querySelector(".modif").click();
|
||||||
|
|
||||||
listeGroupesAutoaffectation();
|
listeGroupesAutoaffectation();
|
||||||
|
listeGroupesRepartition();
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (4).</h2>";
|
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (4).</h2>";
|
||||||
@ -811,6 +843,7 @@
|
|||||||
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (2).</h2>";
|
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (2).</h2>";
|
||||||
}
|
}
|
||||||
listeGroupesAutoaffectation();
|
listeGroupesAutoaffectation();
|
||||||
|
listeGroupesRepartition();
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (3).</h2>";
|
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (3).</h2>";
|
||||||
@ -924,6 +957,7 @@
|
|||||||
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (6).</h2>";
|
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (6).</h2>";
|
||||||
}
|
}
|
||||||
listeGroupesAutoaffectation();
|
listeGroupesAutoaffectation();
|
||||||
|
listeGroupesRepartition();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1038,6 +1072,7 @@
|
|||||||
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (6).</h2>";
|
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (6).</h2>";
|
||||||
}
|
}
|
||||||
listeGroupesAutoaffectation();
|
listeGroupesAutoaffectation();
|
||||||
|
listeGroupesRepartition();
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (7).</h2>";
|
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données (7).</h2>";
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
{%- extends 'sco_page.j2' -%}
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
{{super()}}
|
||||||
<style>
|
<style>
|
||||||
.wait {
|
.wait {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@ -212,7 +216,10 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
<main class="moitemoite">
|
<main class="moitemoite">
|
||||||
<div class="wait"></div>
|
<div class="wait"></div>
|
||||||
<section>
|
<section>
|
||||||
@ -249,6 +256,11 @@
|
|||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{{ super() }}
|
||||||
|
|
||||||
<script src="{{scu.STATIC_DIR}}/libjs/xlsx-populate-1.21.0.min.js"></script>
|
<script src="{{scu.STATIC_DIR}}/libjs/xlsx-populate-1.21.0.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
/************************/
|
/************************/
|
||||||
@ -858,3 +870,4 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
{% endblock %}
|
@ -1003,15 +1003,12 @@ def partition_editor(formsemestre_id: int, edit_partition=False):
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def students_groups_auto_assignment(formsemestre_id: int):
|
def students_groups_auto_assignment(formsemestre_id: int):
|
||||||
"""Répartition auto des groupes"""
|
"""Répartition auto des groupes"""
|
||||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
H = [
|
|
||||||
render_template(
|
|
||||||
"scolar/students_groups_auto_assignment.j2",
|
|
||||||
formsemestre=formsemestre,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"sco_page.j2", title="Répartition des groupes", content="\n".join(H)
|
"scolar/students_groups_auto_assignment.j2",
|
||||||
|
formsemestre=formsemestre,
|
||||||
|
title="Répartition des groupes",
|
||||||
|
sco=ScoData(formsemestre=formsemestre),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.7.13"
|
SCOVERSION = "9.7.14"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user