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
|
||||
|
||||
|
||||
def form_ue_choix_niveau(ue: UniteEns) -> str:
|
||||
"""Form. HTML pour associer une UE à un niveau de compétence.
|
||||
def form_ue_choix_parcours(ue: UniteEns) -> str:
|
||||
"""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
|
||||
"""
|
||||
if ue.type != codes_cursus.UE_STANDARD:
|
||||
return ""
|
||||
ref_comp = ue.formation.referentiel_competence
|
||||
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><a class="stdlink" href="{ url_for('notes.refcomp_assoc_formation',
|
||||
scodoc_dept=g.scodoc_dept, formation_id=ue.formation.id)
|
||||
@ -29,8 +29,27 @@ def form_ue_choix_niveau(ue: UniteEns) -> str:
|
||||
</div>
|
||||
</div>"""
|
||||
|
||||
return f"""
|
||||
H = [
|
||||
"""
|
||||
<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>
|
||||
<li>
|
||||
<a class="stdlink" href="{
|
||||
@ -41,6 +60,8 @@ def form_ue_choix_niveau(ue: UniteEns) -> str:
|
||||
</ul>
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def get_ue_niveaux_options_html(ue: UniteEns) -> str:
|
||||
|
@ -371,7 +371,7 @@ def formsemestre_warning_apc_setup(
|
||||
return ""
|
||||
if formsemestre.formation.referentiel_competence is None:
|
||||
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)
|
||||
}">formation n'est pas associée à un référentiel de compétence.</a>
|
||||
</div>
|
||||
@ -404,12 +404,12 @@ def formsemestre_warning_apc_setup(
|
||||
return f"""<div class="formsemestre_status_warning">
|
||||
Problème dans la configuration de la formation:
|
||||
<ul>
|
||||
<li>{ '<li></li>'.join(H) }</li>
|
||||
<li>{ '</li><li>'.join(H) }</li>
|
||||
</ul>
|
||||
<p class="help">Vérifiez les parcours cochés pour ce semestre,
|
||||
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)
|
||||
}">dans la formation.
|
||||
et les associations entre UE et niveaux <a class="stdlink" href="{
|
||||
url_for("notes.parcour_formation", scodoc_dept=g.scodoc_dept, formation_id=formsemestre.formation.id)
|
||||
}">dans la formation.</a>
|
||||
</p>
|
||||
</div>
|
||||
"""
|
||||
|
@ -151,6 +151,7 @@ class FormSemestre(db.Model):
|
||||
secondary=parcours_formsemestre,
|
||||
lazy="subquery",
|
||||
backref=db.backref("formsemestres", lazy=True),
|
||||
order_by=(ApcParcours.numero, ApcParcours.code),
|
||||
)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
@ -317,7 +317,7 @@ class UniteEns(db.Model):
|
||||
if niveau.competence.referentiel.id != self.formation.referentiel_competence.id:
|
||||
return False, "Le niveau n'appartient pas au référentiel de la formation"
|
||||
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):
|
||||
ok, error_message = self.check_niveau_unique_dans_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",
|
||||
)
|
||||
if tf[0] == 0:
|
||||
niveau_competence_div = ""
|
||||
ue_parcours_div = ""
|
||||
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:
|
||||
modules_div = f"""<div id="ue_list_modules">
|
||||
<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)
|
||||
+ tf[1]
|
||||
+ clone_form
|
||||
+ niveau_competence_div
|
||||
+ ue_parcours_div
|
||||
+ modules_div
|
||||
+ bonus_div
|
||||
+ ue_div
|
||||
|
@ -19,12 +19,18 @@ div.les_parcours>div.focus {
|
||||
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;
|
||||
}
|
||||
|
||||
div.les_parcours>div>a,
|
||||
div.les_parcours>div>a:visited {
|
||||
div.les_parcours>div.parc>a,
|
||||
div.les_parcours>div.parc>a:visited {
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
@ -22,8 +22,8 @@
|
||||
div.table_niveaux_parcours {
|
||||
margin-left: 12px;
|
||||
margin-top: 12px;
|
||||
background: rgb(14, 5, 73);
|
||||
color: #eee;
|
||||
background: rgb(210, 210, 210);
|
||||
color: #111;
|
||||
border-radius: 8px;
|
||||
width: fit-content;
|
||||
padding: 8px;
|
||||
@ -47,7 +47,7 @@ table.table_niveaux_parcours th {
|
||||
}
|
||||
|
||||
table.table_niveaux_parcours tr.parcours_but {
|
||||
color: white;
|
||||
color: #111;
|
||||
}
|
||||
|
||||
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 {
|
||||
width: 92px;
|
||||
font-weight: bold;
|
||||
color: #ddd;
|
||||
color: #111;
|
||||
}
|
||||
|
||||
table.table_niveaux_parcours tr.annee_but td.empty {
|
||||
|
@ -5,6 +5,7 @@
|
||||
--sco-content-min-width: 600px;
|
||||
--sco-content-max-width: 1024px;
|
||||
--sco-color-explication: rgb(10, 58, 140);
|
||||
--sco-color-background: rgb(242, 242, 238);
|
||||
}
|
||||
|
||||
html,
|
||||
@ -12,7 +13,7 @@ body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
background-color: rgb(242, 242, 238);
|
||||
background-color: var(--sco-color-background);
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 12pt;
|
||||
}
|
||||
@ -937,7 +938,7 @@ span.linktitresem a:visited {
|
||||
|
||||
a.stdlink,
|
||||
a.stdlink:visited {
|
||||
color: blue;
|
||||
color: #0e0e9d;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@ -2539,6 +2540,10 @@ div.ue_advanced {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
div.ue_advanced h3 {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
div#ue_list_modules {
|
||||
background-color: rgb(251, 225, 165);
|
||||
border: 1px solid blue;
|
||||
|
@ -11,7 +11,6 @@ $().ready(function () {
|
||||
});
|
||||
update_bonus_description();
|
||||
}
|
||||
update_menus_niveau_competence();
|
||||
});
|
||||
|
||||
function update_bonus_description() {
|
||||
@ -37,131 +36,26 @@ function update_ue_list() {
|
||||
});
|
||||
}
|
||||
|
||||
function set_ue_parcour(elem) {
|
||||
let ue_id = elem.dataset.ue_id;
|
||||
let parcour_id = elem.value;
|
||||
let set_ue_parcour_url = elem.dataset.setter;
|
||||
$.post(set_ue_parcour_url,
|
||||
{
|
||||
ue_id: ue_id,
|
||||
parcour_id: parcour_id,
|
||||
},
|
||||
function (result) {
|
||||
sco_message("UE associée au parcours");
|
||||
update_menus_niveau_competence();
|
||||
}
|
||||
);
|
||||
}
|
||||
function set_ue_parcour(checkbox) {
|
||||
let url = checkbox.dataset.setter;
|
||||
const checkboxes = document.querySelectorAll('#choix_parcours input[type="checkbox"]:checked');
|
||||
const parcours_ids = [];
|
||||
checkboxes.forEach(function (checkbox) {
|
||||
parcours_ids.push(checkbox.value);
|
||||
});
|
||||
|
||||
function set_ue_niveau_competence(elem) {
|
||||
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',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(selectedOptions)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (!data.status) {
|
||||
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
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(selectedOptions)
|
||||
body: JSON.stringify(parcours_ids)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => console.log('Success!'))
|
||||
.catch(error => console.error('Error: ' + error));
|
||||
};
|
||||
.then(data => {
|
||||
if (data.status) {
|
||||
sco_message(data.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -49,13 +49,24 @@
|
||||
{# Liens vers les différents parcours #}
|
||||
<div class="les_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="{{
|
||||
url_for('notes.parcour_formation', scodoc_dept=g.scodoc_dept,
|
||||
parcour_id=parc.id, formation_id=formation.id )
|
||||
}}">{{parc.code}}</a>
|
||||
</div>
|
||||
{% 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>
|
||||
|
||||
{# Description d'un parcours #}
|
||||
@ -107,19 +118,6 @@ Choisissez un parcours...
|
||||
</div>
|
||||
{% 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 %}
|
||||
<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):
|
||||
assert sorted(res_d.keys()) == sorted(ref_d.keys())
|
||||
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