forked from ScoDoc/ScoDoc
Associations UE / Parcours: UI
This commit is contained in:
parent
5f719442f0
commit
e5cdb2ef69
@ -13,15 +13,15 @@ from app.models import ApcReferentielCompetences, UniteEns
|
|||||||
from app.scodoc import codes_cursus
|
from app.scodoc import codes_cursus
|
||||||
|
|
||||||
|
|
||||||
def form_ue_choix_niveau(ue: UniteEns) -> str:
|
def form_ue_choix_parcours(ue: UniteEns) -> str:
|
||||||
"""Form. HTML pour associer une UE à un niveau de compétence.
|
"""Form. HTML pour associer une UE à ses parcours.
|
||||||
Le menu select lui même est vide et rempli en JS par appel à get_ue_niveaux_options_html
|
Le menu select lui même est vide et rempli en JS par appel à get_ue_niveaux_options_html
|
||||||
"""
|
"""
|
||||||
if ue.type != codes_cursus.UE_STANDARD:
|
if ue.type != codes_cursus.UE_STANDARD:
|
||||||
return ""
|
return ""
|
||||||
ref_comp = ue.formation.referentiel_competence
|
ref_comp = ue.formation.referentiel_competence
|
||||||
if ref_comp is None:
|
if ref_comp is None:
|
||||||
return f"""<div class="ue_choix_niveau">
|
return f"""<div class="ue_advanced">
|
||||||
<div class="warning">Pas de référentiel de compétence associé à cette formation !</div>
|
<div class="warning">Pas de référentiel de compétence associé à cette formation !</div>
|
||||||
<div><a class="stdlink" href="{ url_for('notes.refcomp_assoc_formation',
|
<div><a class="stdlink" href="{ url_for('notes.refcomp_assoc_formation',
|
||||||
scodoc_dept=g.scodoc_dept, formation_id=ue.formation.id)
|
scodoc_dept=g.scodoc_dept, formation_id=ue.formation.id)
|
||||||
@ -29,8 +29,27 @@ def form_ue_choix_niveau(ue: UniteEns) -> str:
|
|||||||
</div>
|
</div>
|
||||||
</div>"""
|
</div>"""
|
||||||
|
|
||||||
return f"""
|
H = [
|
||||||
|
"""
|
||||||
<div class="ue_advanced">
|
<div class="ue_advanced">
|
||||||
|
<h3>Parcours du BUT</h3>
|
||||||
|
"""
|
||||||
|
]
|
||||||
|
# Choix des parcours
|
||||||
|
ue_pids = [p.id for p in ue.parcours]
|
||||||
|
H.append("""<form id="choix_parcours">""")
|
||||||
|
for parcour in ref_comp.parcours:
|
||||||
|
H.append(
|
||||||
|
f"""<label><input type="checkbox" name="{parcour.id}" value="{parcour.id}"
|
||||||
|
{'checked' if parcour.id in ue_pids else ""}
|
||||||
|
onclick="set_ue_parcour(this);"
|
||||||
|
data-setter="{url_for("apiweb.set_ue_parcours", scodoc_dept=g.scodoc_dept, ue_id=ue.id)}"
|
||||||
|
>{parcour.code}</label>"""
|
||||||
|
)
|
||||||
|
H.append("""</form>""")
|
||||||
|
#
|
||||||
|
H.append(
|
||||||
|
f"""
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a class="stdlink" href="{
|
<a class="stdlink" href="{
|
||||||
@ -41,6 +60,8 @@ def form_ue_choix_niveau(ue: UniteEns) -> str:
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
)
|
||||||
|
return "\n".join(H)
|
||||||
|
|
||||||
|
|
||||||
def get_ue_niveaux_options_html(ue: UniteEns) -> str:
|
def get_ue_niveaux_options_html(ue: UniteEns) -> str:
|
||||||
|
@ -371,7 +371,7 @@ def formsemestre_warning_apc_setup(
|
|||||||
return ""
|
return ""
|
||||||
if formsemestre.formation.referentiel_competence is None:
|
if formsemestre.formation.referentiel_competence is None:
|
||||||
return f"""<div class="formsemestre_status_warning">
|
return f"""<div class="formsemestre_status_warning">
|
||||||
La <a class=stdlink" href="{
|
La <a class="stdlink" href="{
|
||||||
url_for("notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formsemestre.formation.id)
|
url_for("notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formsemestre.formation.id)
|
||||||
}">formation n'est pas associée à un référentiel de compétence.</a>
|
}">formation n'est pas associée à un référentiel de compétence.</a>
|
||||||
</div>
|
</div>
|
||||||
@ -404,12 +404,12 @@ def formsemestre_warning_apc_setup(
|
|||||||
return f"""<div class="formsemestre_status_warning">
|
return f"""<div class="formsemestre_status_warning">
|
||||||
Problème dans la configuration de la formation:
|
Problème dans la configuration de la formation:
|
||||||
<ul>
|
<ul>
|
||||||
<li>{ '<li></li>'.join(H) }</li>
|
<li>{ '</li><li>'.join(H) }</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p class="help">Vérifiez les parcours cochés pour ce semestre,
|
<p class="help">Vérifiez les parcours cochés pour ce semestre,
|
||||||
et les associations entre UE et niveaux <a class=stdlink" href="{
|
et les associations entre UE et niveaux <a class="stdlink" href="{
|
||||||
url_for("notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formsemestre.formation.id)
|
url_for("notes.parcour_formation", scodoc_dept=g.scodoc_dept, formation_id=formsemestre.formation.id)
|
||||||
}">dans la formation.
|
}">dans la formation.</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
@ -151,6 +151,7 @@ class FormSemestre(db.Model):
|
|||||||
secondary=parcours_formsemestre,
|
secondary=parcours_formsemestre,
|
||||||
lazy="subquery",
|
lazy="subquery",
|
||||||
backref=db.backref("formsemestres", lazy=True),
|
backref=db.backref("formsemestres", lazy=True),
|
||||||
|
order_by=(ApcParcours.numero, ApcParcours.code),
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
@ -317,7 +317,7 @@ class UniteEns(db.Model):
|
|||||||
if niveau.competence.referentiel.id != self.formation.referentiel_competence.id:
|
if niveau.competence.referentiel.id != self.formation.referentiel_competence.id:
|
||||||
return False, "Le niveau n'appartient pas au référentiel de la formation"
|
return False, "Le niveau n'appartient pas au référentiel de la formation"
|
||||||
if niveau.id == self.niveau_competence_id:
|
if niveau.id == self.niveau_competence_id:
|
||||||
return True # nothing to do
|
return True, "" # nothing to do
|
||||||
if (niveau is not None) and (self.niveau_competence_id is not None):
|
if (niveau is not None) and (self.niveau_competence_id is not None):
|
||||||
ok, error_message = self.check_niveau_unique_dans_parcours(
|
ok, error_message = self.check_niveau_unique_dans_parcours(
|
||||||
niveau, self.parcours
|
niveau, self.parcours
|
||||||
|
@ -476,9 +476,9 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
|
|||||||
cancelbutton="Revenir à la formation",
|
cancelbutton="Revenir à la formation",
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
niveau_competence_div = ""
|
ue_parcours_div = ""
|
||||||
if ue and is_apc:
|
if ue and is_apc:
|
||||||
niveau_competence_div = apc_edit_ue.form_ue_choix_niveau(ue)
|
ue_parcours_div = apc_edit_ue.form_ue_choix_parcours(ue)
|
||||||
if ue and ue.modules.count() and ue.semestre_idx is not None:
|
if ue and ue.modules.count() and ue.semestre_idx is not None:
|
||||||
modules_div = f"""<div id="ue_list_modules">
|
modules_div = f"""<div id="ue_list_modules">
|
||||||
<div><b>{ue.modules.count()} modules sont rattachés
|
<div><b>{ue.modules.count()} modules sont rattachés
|
||||||
@ -508,7 +508,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
|
|||||||
"\n".join(H)
|
"\n".join(H)
|
||||||
+ tf[1]
|
+ tf[1]
|
||||||
+ clone_form
|
+ clone_form
|
||||||
+ niveau_competence_div
|
+ ue_parcours_div
|
||||||
+ modules_div
|
+ modules_div
|
||||||
+ bonus_div
|
+ bonus_div
|
||||||
+ ue_div
|
+ ue_div
|
||||||
|
@ -19,12 +19,18 @@ div.les_parcours>div.focus {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.les_parcours>div>a:hover {
|
div.les_parcours>div.link {
|
||||||
|
background-color: var(--sco-color-background);
|
||||||
|
color: navy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.les_parcours>div.parc>a:hover {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.les_parcours>div>a,
|
div.les_parcours>div.parc>a,
|
||||||
div.les_parcours>div>a:visited {
|
div.les_parcours>div.parc>a:visited {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
div.table_niveaux_parcours {
|
div.table_niveaux_parcours {
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
background: rgb(14, 5, 73);
|
background: rgb(210, 210, 210);
|
||||||
color: #eee;
|
color: #111;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
@ -47,7 +47,7 @@ table.table_niveaux_parcours th {
|
|||||||
}
|
}
|
||||||
|
|
||||||
table.table_niveaux_parcours tr.parcours_but {
|
table.table_niveaux_parcours tr.parcours_but {
|
||||||
color: white;
|
color: #111;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.table_niveaux_parcours tr.parcours_but td {
|
table.table_niveaux_parcours tr.parcours_but td {
|
||||||
@ -70,7 +70,7 @@ table.table_niveaux_parcours tr td:not(:first-child) {
|
|||||||
table.table_niveaux_parcours tr.annee_but td:first-child {
|
table.table_niveaux_parcours tr.annee_but td:first-child {
|
||||||
width: 92px;
|
width: 92px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #ddd;
|
color: #111;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.table_niveaux_parcours tr.annee_but td.empty {
|
table.table_niveaux_parcours tr.annee_but td.empty {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
--sco-content-min-width: 600px;
|
--sco-content-min-width: 600px;
|
||||||
--sco-content-max-width: 1024px;
|
--sco-content-max-width: 1024px;
|
||||||
--sco-color-explication: rgb(10, 58, 140);
|
--sco-color-explication: rgb(10, 58, 140);
|
||||||
|
--sco-color-background: rgb(242, 242, 238);
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
@ -12,7 +13,7 @@ body {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: rgb(242, 242, 238);
|
background-color: var(--sco-color-background);
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
}
|
}
|
||||||
@ -937,7 +938,7 @@ span.linktitresem a:visited {
|
|||||||
|
|
||||||
a.stdlink,
|
a.stdlink,
|
||||||
a.stdlink:visited {
|
a.stdlink:visited {
|
||||||
color: blue;
|
color: #0e0e9d;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2539,6 +2540,10 @@ div.ue_advanced {
|
|||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.ue_advanced h3 {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
div#ue_list_modules {
|
div#ue_list_modules {
|
||||||
background-color: rgb(251, 225, 165);
|
background-color: rgb(251, 225, 165);
|
||||||
border: 1px solid blue;
|
border: 1px solid blue;
|
||||||
|
@ -11,7 +11,6 @@ $().ready(function () {
|
|||||||
});
|
});
|
||||||
update_bonus_description();
|
update_bonus_description();
|
||||||
}
|
}
|
||||||
update_menus_niveau_competence();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function update_bonus_description() {
|
function update_bonus_description() {
|
||||||
@ -37,131 +36,26 @@ function update_ue_list() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_ue_parcour(elem) {
|
function set_ue_parcour(checkbox) {
|
||||||
let ue_id = elem.dataset.ue_id;
|
let url = checkbox.dataset.setter;
|
||||||
let parcour_id = elem.value;
|
const checkboxes = document.querySelectorAll('#choix_parcours input[type="checkbox"]:checked');
|
||||||
let set_ue_parcour_url = elem.dataset.setter;
|
const parcours_ids = [];
|
||||||
$.post(set_ue_parcour_url,
|
checkboxes.forEach(function (checkbox) {
|
||||||
{
|
parcours_ids.push(checkbox.value);
|
||||||
ue_id: ue_id,
|
});
|
||||||
parcour_id: parcour_id,
|
|
||||||
},
|
|
||||||
function (result) {
|
|
||||||
sco_message("UE associée au parcours");
|
|
||||||
update_menus_niveau_competence();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function set_ue_niveau_competence(elem) {
|
fetch(url, {
|
||||||
let ue_id = elem.dataset.ue_id;
|
|
||||||
let niveau_id = elem.value;
|
|
||||||
let set_ue_niveau_competence_url = elem.dataset.setter;
|
|
||||||
$.post(set_ue_niveau_competence_url,
|
|
||||||
{
|
|
||||||
ue_id: ue_id,
|
|
||||||
niveau_id: niveau_id,
|
|
||||||
},
|
|
||||||
function (result) {
|
|
||||||
sco_message("niveau de compétence enregistré");
|
|
||||||
|
|
||||||
update_menus_niveau_competence();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Met à jour les niveaux utilisés (disabled) ou non affectés
|
|
||||||
// dans les menus d'association UE <-> niveau
|
|
||||||
function update_menus_niveau_competence() {
|
|
||||||
// let selected_niveaux = [];
|
|
||||||
// document.querySelectorAll("form.form_ue_choix_niveau select").forEach(
|
|
||||||
// elem => { selected_niveaux.push(elem.value); }
|
|
||||||
// );
|
|
||||||
|
|
||||||
// document.querySelectorAll("form.form_ue_choix_niveau select").forEach(
|
|
||||||
// elem => {
|
|
||||||
// for (let i = 0; i < elem.options.length; i++) {
|
|
||||||
// elem.options[i].disabled = (i != elem.options.selectedIndex)
|
|
||||||
// && (selected_niveaux.indexOf(elem.options[i].value) != -1)
|
|
||||||
// && (elem.options[i].value != "");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
// nouveau:
|
|
||||||
document.querySelectorAll("select.niveau_select").forEach(
|
|
||||||
elem => {
|
|
||||||
let ue_id = elem.dataset.ue_id;
|
|
||||||
$.get("get_ue_niveaux_options_html",
|
|
||||||
{
|
|
||||||
ue_id: ue_id,
|
|
||||||
},
|
|
||||||
function (result) {
|
|
||||||
elem.innerHTML = result;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Nouveau formulaire choix parcours et niveau -----
|
|
||||||
//document.querySelectorAll("select.select_ue_parcours").forEach(
|
|
||||||
// elem => { elem.addEventListener('change', change_ue_parcours); }
|
|
||||||
//);
|
|
||||||
$().ready(function () {
|
|
||||||
$('select.select_ue_parcours').multiselect(
|
|
||||||
{
|
|
||||||
includeSelectAllOption: false,
|
|
||||||
nonSelectedText: 'choisir...',
|
|
||||||
// buttonContainer: '<div id="group_ids_sel_container"/>',
|
|
||||||
onChange: function (element, checked) {
|
|
||||||
var parent = element.parent();
|
|
||||||
var selectedOptions = parent.getValue().split(",");
|
|
||||||
let set_ue_parcours = element.context.dataset.set_ue_parcours;
|
|
||||||
|
|
||||||
fetch(set_ue_parcours, {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify(selectedOptions)
|
body: JSON.stringify(parcours_ids)
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!data.status) {
|
if (data.status) {
|
||||||
sco_message(data.message);
|
sco_message(data.message);
|
||||||
// get the option element corresponding to the selected value
|
|
||||||
var option = parent.find('option[value="' + element.val() + '"]');
|
|
||||||
// uncheck the option
|
|
||||||
option.prop('selected', false);
|
|
||||||
// refresh the multiselect to reflect the change
|
|
||||||
parent.multiselect('refresh');
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.catch(error => console.error('Error: ' + error));
|
|
||||||
|
|
||||||
// // referme le menu apres chaque choix:
|
|
||||||
// $("#group_selector .btn-group").removeClass('open');
|
|
||||||
|
|
||||||
// if ($("#group_ids_sel").hasClass("submit_on_change")) {
|
|
||||||
// submit_group_selector();
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function change_ue_parcours(event) {
|
|
||||||
const multiselect = event.target;
|
|
||||||
const selectedOptions = Array.from(this.selectedOptions).map(option => option.value);
|
|
||||||
fetch('/set_option/', { // XXX TODO
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(selectedOptions)
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => console.log('Success!'))
|
|
||||||
.catch(error => console.error('Error: ' + error));
|
|
||||||
};
|
|
||||||
|
@ -49,13 +49,24 @@
|
|||||||
{# Liens vers les différents parcours #}
|
{# Liens vers les différents parcours #}
|
||||||
<div class="les_parcours">
|
<div class="les_parcours">
|
||||||
{% for parc in formation.referentiel_competence.parcours %}
|
{% for parc in formation.referentiel_competence.parcours %}
|
||||||
<div class="{{'focus' if parcour and parc.id == parcour.id else ''}}">
|
<div class="parc {{'focus' if parcour and parc.id == parcour.id else ''}}">
|
||||||
<a href="{{
|
<a href="{{
|
||||||
url_for('notes.parcour_formation', scodoc_dept=g.scodoc_dept,
|
url_for('notes.parcour_formation', scodoc_dept=g.scodoc_dept,
|
||||||
parcour_id=parc.id, formation_id=formation.id )
|
parcour_id=parc.id, formation_id=formation.id )
|
||||||
}}">{{parc.code}}</a>
|
}}">{{parc.code}}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
<div class="link">
|
||||||
|
<a class="stdlink" target="_blank" href="{{
|
||||||
|
url_for('notes.refcomp_show',
|
||||||
|
scodoc_dept=g.scodoc_dept, refcomp_id=formation.referentiel_competence.id )
|
||||||
|
}}">référentiel de compétences</a>
|
||||||
|
</div>
|
||||||
|
<div class="link"><a class="stdlink" href="{{
|
||||||
|
url_for('notes.ue_table',
|
||||||
|
scodoc_dept=g.scodoc_dept, formation_id=formation.id )
|
||||||
|
}}">formation</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Description d'un parcours #}
|
{# Description d'un parcours #}
|
||||||
@ -107,19 +118,6 @@ Choisissez un parcours...
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# Liens bas de page #}
|
|
||||||
<div class="links">
|
|
||||||
<div><a class="stdlink" href="{{
|
|
||||||
url_for('notes.ue_table',
|
|
||||||
scodoc_dept=g.scodoc_dept, formation_id=formation.id )
|
|
||||||
}}">Voir la formation</a>
|
|
||||||
</div>
|
|
||||||
<div><a class="stdlink" href="{{
|
|
||||||
url_for('notes.refcomp_show',
|
|
||||||
scodoc_dept=g.scodoc_dept, refcomp_id=formation.referentiel_competence.id )
|
|
||||||
}}">Référentiel de compétences</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if parcour %}
|
{% if parcour %}
|
||||||
<div class="help">
|
<div class="help">
|
||||||
|
@ -724,4 +724,4 @@ def _compare_formsemestre_resultat(res: list[dict], ref: list[dict]):
|
|||||||
for res_d, ref_d in zip(res, ref):
|
for res_d, ref_d in zip(res, ref):
|
||||||
assert sorted(res_d.keys()) == sorted(ref_d.keys())
|
assert sorted(res_d.keys()) == sorted(ref_d.keys())
|
||||||
for k in res_d:
|
for k in res_d:
|
||||||
assert res_d[k] == ref_d[k]
|
assert res_d[k] == ref_d[k], f"values for key {k} differ."
|
||||||
|
Loading…
Reference in New Issue
Block a user