WIP: Edition formations

This commit is contained in:
Emmanuel Viennet 2021-11-18 00:24:56 +01:00
parent 8f4299e880
commit e3219a6b0c
13 changed files with 417 additions and 271 deletions

View File

@ -86,6 +86,15 @@ class UniteEns(db.Model):
def __repr__(self): def __repr__(self):
return f"<{self.__class__.__name__}(id={self.id}, formation_id={self.formation_id}, acronyme='{self.acronyme}')>" return f"<{self.__class__.__name__}(id={self.id}, formation_id={self.formation_id}, acronyme='{self.acronyme}')>"
def is_locked(self):
"""True if UE should not be modified
(contains modules used in a locked formsemestre)
"""
# XXX todo : à ré-écrire avec SQLAlchemy
from app.scodoc import sco_edit_ue
return sco_edit_ue.ue_is_locked(self.id)
class Matiere(db.Model): class Matiere(db.Model):
"""Matières: regroupe les modules d'une UE """Matières: regroupe les modules d'une UE

View File

@ -87,15 +87,18 @@ Problème de connexion (identifiant, mot de passe): <em>contacter votre responsa
) )
_HTML_BEGIN = """<?xml version="1.0" encoding="%(encoding)s"?> _HTML_BEGIN = """<!DOCTYPE html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html lang="fr">
<html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<title>%(page_title)s</title> <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=%(encoding)s" /> <meta http-equiv="Content-Type" content="text/html; charset=%(encoding)s" />
<meta http-equiv="Content-Style-Type" content="text/css" /> <meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="LANG" content="fr" /> <meta name="LANG" content="fr" />
<meta name="DESCRIPTION" content="ScoDoc" /> <meta name="DESCRIPTION" content="ScoDoc" />
<title>%(page_title)s</title>
<link type="text/css" rel="stylesheet" href="/ScoDoc/static/libjs/jquery-ui-1.10.4.custom/css/smoothness/jquery-ui-1.10.4.custom.min.css" /> <link type="text/css" rel="stylesheet" href="/ScoDoc/static/libjs/jquery-ui-1.10.4.custom/css/smoothness/jquery-ui-1.10.4.custom.min.css" />

View File

@ -38,6 +38,7 @@ from app.scodoc.sco_utils import ModuleType
def html_edit_formation_apc( def html_edit_formation_apc(
formation, formation,
semestre_idx=None,
editable=True, editable=True,
tag_editable=True, tag_editable=True,
): ):
@ -48,75 +49,84 @@ def html_edit_formation_apc(
""" """
parcours = formation.get_parcours() parcours = formation.get_parcours()
assert parcours.APC_SAE assert parcours.APC_SAE
ressources = formation.modules.filter_by(module_type=ModuleType.RESSOURCE) ressources = formation.modules.filter_by(module_type=ModuleType.RESSOURCE).order_by(
Module.semestre_id, Module.numero
)
saes = formation.modules.filter_by(module_type=ModuleType.SAE) saes = formation.modules.filter_by(module_type=ModuleType.SAE)
if semestre_idx is None:
semestre_ids = range(1, parcours.NB_SEM + 1)
else:
semestre_ids = [semestre_idx]
other_modules = formation.modules.filter( other_modules = formation.modules.filter(
Module.module_type != ModuleType.SAE Module.module_type != ModuleType.SAE, Module.module_type != ModuleType.RESSOURCE
and Module.module_type != ModuleType.RESSOURCE
) )
arrow_up, arrow_down, arrow_none = sco_groups.get_arrow_icons_tags() arrow_up, arrow_down, arrow_none = sco_groups.get_arrow_icons_tags()
delete_icon = scu.icontag(
"delete_small_img", title="Supprimer (module inutilisé)", alt="supprimer" icons = {
) "arrow_up": arrow_up,
delete_disabled_icon = scu.icontag( "arrow_down": arrow_down,
"delete_small_dis_img", title="Suppression impossible (module utilisé)" "arrow_none": arrow_none,
) "delete": scu.icontag(
"delete_small_img",
title="Supprimer (module inutilisé)",
alt="supprimer",
),
"delete_disabled": scu.icontag(
"delete_small_dis_img", title="Suppression impossible (module utilisé)"
),
}
H = [ H = [
render_template( render_template(
"pn/form_ues.html", "pn/form_ues.html",
formation=formation, formation=formation,
semestre_ids=semestre_ids,
editable=editable, editable=editable,
arrow_up=arrow_up, tag_editable=tag_editable,
arrow_down=arrow_down, icons=icons,
arrow_none=arrow_none,
delete_icon=delete_icon,
delete_disabled_icon=delete_disabled_icon,
),
render_template(
"pn/form_mods.html",
formation=formation,
titre="Ressources",
create_element_msg="créer une nouvelle ressource",
modules=ressources,
module_type=ModuleType.RESSOURCE,
editable=editable,
arrow_up=arrow_up,
arrow_down=arrow_down,
arrow_none=arrow_none,
delete_icon=delete_icon,
delete_disabled_icon=delete_disabled_icon,
scu=scu,
),
render_template(
"pn/form_mods.html",
formation=formation,
titre="Situations d'Apprentissage et d'Évaluation (SAÉs)",
create_element_msg="créer une nouvelle SAÉ",
modules=saes,
module_type=ModuleType.SAE,
editable=editable,
arrow_up=arrow_up,
arrow_down=arrow_down,
arrow_none=arrow_none,
delete_icon=delete_icon,
delete_disabled_icon=delete_disabled_icon,
scu=scu,
),
render_template(
"pn/form_mods.html",
formation=formation,
titre="Autres modules (non BUT)",
create_element_msg="créer un nouveau module",
modules=other_modules,
module_type=ModuleType.STANDARD,
editable=editable,
arrow_up=arrow_up,
arrow_down=arrow_down,
arrow_none=arrow_none,
delete_icon=delete_icon,
delete_disabled_icon=delete_disabled_icon,
scu=scu,
), ),
] ]
for semestre_idx in semestre_ids:
ressources_in_sem = ressources.filter_by(semestre_id=semestre_idx)
saes_in_sem = saes.filter_by(semestre_id=semestre_idx)
other_modules_in_sem = other_modules.filter_by(semestre_id=semestre_idx)
H += [
render_template(
"pn/form_mods.html",
formation=formation,
titre=f"Ressources du S{semestre_idx}",
create_element_msg="créer une nouvelle ressource",
modules=ressources_in_sem,
module_type=ModuleType.RESSOURCE,
editable=editable,
tag_editable=tag_editable,
icons=icons,
scu=scu,
),
render_template(
"pn/form_mods.html",
formation=formation,
titre=f"Situations d'Apprentissage et d'Évaluation (SAÉs) S{semestre_idx}",
create_element_msg="créer une nouvelle SAÉ",
modules=saes_in_sem,
module_type=ModuleType.SAE,
editable=editable,
tag_editable=tag_editable,
icons=icons,
scu=scu,
),
render_template(
"pn/form_mods.html",
formation=formation,
titre=f"Autres modules (non BUT) du S{semestre_idx}",
create_element_msg="créer un nouveau module",
modules=other_modules_in_sem,
module_type=ModuleType.STANDARD,
editable=editable,
tag_editable=tag_editable,
icons=icons,
scu=scu,
),
]
return "\n".join(H) return "\n".join(H)

View File

@ -124,15 +124,25 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
object_name = "Module" object_name = "Module"
H = [ H = [
html_sco_header.sco_header(page_title=f"Création {object_name}"), html_sco_header.sco_header(page_title=f"Création {object_name}"),
f"""<h2>Création {object_name} dans la matière {matiere.titre}, ]
(UE {ue.acronyme})</h2> if is_apc:
""", H += [
f"""<h2>Création {object_name} dans la formation {ue.formation.acronyme}</h2>"""
]
else:
H += [
f"""<h2>Création {object_name} dans la matière {matiere.titre},
(UE {ue.acronyme})</h2>
"""
]
H += [
render_template( render_template(
"scodoc/help/modules.html", "scodoc/help/modules.html",
is_apc=is_apc, is_apc=is_apc,
ue=ue, ue=ue,
semestre_id=semestre_id, semestre_id=semestre_id,
), )
] ]
# cherche le numero adéquat (pour placer le module en fin de liste) # cherche le numero adéquat (pour placer le module en fin de liste)
modules = Matiere.query.get(1).modules.all() modules = Matiere.query.get(1).modules.all()
@ -145,15 +155,43 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
"code", "code",
{ {
"size": 10, "size": 10,
"explanation": "code du module (doit être unique dans la formation)", "explanation": "code du module, ressource ou SAÉ. Exemple M1203, R2.01, ou SAÉ 3.4. Ce code doit être unique dans la formation.",
"allow_null": False, "allow_null": False,
"validator": lambda val, field, formation_id=ue.formation_id: check_module_code_unicity( "validator": lambda val, field, formation_id=ue.formation_id: check_module_code_unicity(
val, field, formation_id val, field, formation_id
), ),
}, },
), ),
("titre", {"size": 30, "explanation": "nom du module"}), (
("abbrev", {"size": 20, "explanation": "nom abrégé (pour bulletins)"}), "titre",
{
"size": 30,
"explanation": "nom du module. Exemple: <em>Introduction à la démarche ergonomique</em>",
},
),
(
"abbrev",
{
"size": 20,
"explanation": "nom abrégé (pour les bulletins). Exemple: <em>Intro. à l'ergonomie</em>",
},
),
]
semestres_indices = list(range(1, parcours.NB_SEM + 1))
descr += [
(
"semestre_id",
{
"input_type": "menu",
"type": "int",
"title": parcours.SESSION_NAME.capitalize(),
"explanation": "%s du module" % parcours.SESSION_NAME,
"labels": [str(x) for x in semestres_indices],
"allowed_values": semestres_indices,
},
),
]
descr += [
( (
"module_type", "module_type",
{ {
@ -166,22 +204,29 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
), ),
( (
"heures_cours", "heures_cours",
{"size": 4, "type": "float", "explanation": "nombre d'heures de cours"}, {
"title": "Heures de cours",
"size": 4,
"type": "float",
"explanation": "nombre d'heures de cours (optionnel)",
},
), ),
( (
"heures_td", "heures_td",
{ {
"title": "Heures de TD",
"size": 4, "size": 4,
"type": "float", "type": "float",
"explanation": "nombre d'heures de Travaux Dirigés", "explanation": "nombre d'heures de Travaux Dirigés (optionnel)",
}, },
), ),
( (
"heures_tp", "heures_tp",
{ {
"title": "Heures de TP",
"size": 4, "size": 4,
"type": "float", "type": "float",
"explanation": "nombre d'heures de Travaux Pratiques", "explanation": "nombre d'heures de Travaux Pratiques (optionnel)",
}, },
), ),
] ]
@ -198,7 +243,6 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
), ),
] ]
else: else:
semestres_indices = list(range(1, parcours.NB_SEM + 1))
descr += [ descr += [
( (
"coefficient", "coefficient",
@ -209,19 +253,8 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
"allow_null": False, "allow_null": False,
}, },
), ),
(
"semestre_id",
{
"input_type": "menu",
"type": "int",
"title": parcours.SESSION_NAME.capitalize(),
"explanation": "%s de début du module dans la formation standard"
% parcours.SESSION_NAME,
"labels": [str(x) for x in semestres_indices],
"allowed_values": semestres_indices,
},
),
] ]
descr += [ descr += [
# ('ects', { 'size' : 4, 'type' : 'float', 'title' : 'ECTS', 'explanation' : 'nombre de crédits ECTS (inutilisés: les crédits sont associés aux UE)' }), # ('ects', { 'size' : 4, 'type' : 'float', 'title' : 'ECTS', 'explanation' : 'nombre de crédits ECTS (inutilisés: les crédits sont associés aux UE)' }),
("formation_id", {"default": ue.formation_id, "input_type": "hidden"}), ("formation_id", {"default": ue.formation_id, "input_type": "hidden"}),

View File

@ -29,7 +29,8 @@
""" """
import flask import flask
from flask import g, url_for, request from flask import url_for, render_template
from flask import g, request
from flask_login import current_user from flask_login import current_user
from app.models.formations import Formation, UniteEns from app.models.formations import Formation, UniteEns
@ -260,7 +261,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None):
{ {
"input_type": "menu", "input_type": "menu",
"type": "int", "type": "int",
"allow_null": True, "allow_null": False,
"title": parcours.SESSION_NAME.capitalize(), "title": parcours.SESSION_NAME.capitalize(),
"explanation": "%s de l'UE dans la formation" % parcours.SESSION_NAME, "explanation": "%s de l'UE dans la formation" % parcours.SESSION_NAME,
"labels": ["non spécifié"] + [str(x) for x in semestres_indices], "labels": ["non spécifié"] + [str(x) for x in semestres_indices],
@ -324,7 +325,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None):
}, },
), ),
] ]
if create and not parcours.UE_IS_MODULE: if create and not parcours.UE_IS_MODULE and not is_apc:
fw.append( fw.append(
( (
"create_matiere", "create_matiere",
@ -357,7 +358,9 @@ def ue_edit(ue_id=None, create=False, formation_id=None):
formation_id, int(tf[2]["semestre_idx"]) formation_id, int(tf[2]["semestre_idx"])
) )
ue_id = do_ue_create(tf[2]) ue_id = do_ue_create(tf[2])
if parcours.UE_IS_MODULE or tf[2]["create_matiere"]: if is_apc or parcours.UE_IS_MODULE or tf[2]["create_matiere"]:
# rappel: en APC, toutes les UE ont une matière, créée ici
# (inutilisée mais à laquelle les modules sont rattachés)
matiere_id = sco_edit_matiere.do_matiere_create( matiere_id = sco_edit_matiere.do_matiere_create(
{"ue_id": ue_id, "titre": tf[2]["titre"], "numero": 1}, {"ue_id": ue_id, "titre": tf[2]["titre"], "numero": 1},
) )
@ -446,7 +449,7 @@ def ue_delete(ue_id=None, delete_validations=False, dialog_confirmed=False):
return do_ue_delete(ue_id, delete_validations=delete_validations) return do_ue_delete(ue_id, delete_validations=delete_validations)
def ue_table(formation_id=None, msg=""): # was ue_list def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list
"""Liste des matières et modules d'une formation, avec liens pour """Liste des matières et modules d'une formation, avec liens pour
éditer (si non verrouillée). éditer (si non verrouillée).
""" """
@ -459,7 +462,11 @@ def ue_table(formation_id=None, msg=""): # was ue_list
parcours = formation.get_parcours() parcours = formation.get_parcours()
is_apc = parcours.APC_SAE is_apc = parcours.APC_SAE
locked = sco_formations.formation_has_locked_sems(formation_id) locked = sco_formations.formation_has_locked_sems(formation_id)
if semestre_idx == "all":
semestre_idx = None
else:
semestre_idx = int(semestre_idx)
semestre_ids = range(1, parcours.NB_SEM + 1)
ues = ue_list(args={"formation_id": formation_id, "is_external": False}) ues = ue_list(args={"formation_id": formation_id, "is_external": False})
ues_externes = ue_list(args={"formation_id": formation_id, "is_external": True}) ues_externes = ue_list(args={"formation_id": formation_id, "is_external": True})
# tri par semestre et numero: # tri par semestre et numero:
@ -538,54 +545,33 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
) )
# Description de la formation # Description de la formation
H.append('<div class="formation_descr">')
H.append( H.append(
f"""<div class="fd_d"><span class="fd_t">Titre: render_template(
</span><span class="fd_v">{formation.titre}</span> "pn/form_descr.html",
</div> formation=formation,
<div class="fd_d"><span class="fd_t">Titre officiel:</span> parcours=parcours,
<span class="fd_v">{formation.titre_officiel}</span> editable=editable,
</div> )
<div class="fd_d"><span class="fd_t">Acronyme:</span>
<span class="fd_v">{formation.acronyme}</span>
</div>
<div class="fd_d"><span class="fd_t">Code:</span>
<span class="fd_v">{formation.formation_code}</span>
</div>
<div class="fd_d"><span class="fd_t">Version:</span>
<span class="fd_v">{formation.version}</span>
</div>
<div class="fd_d"><span class="fd_t">Type parcours:</span>
<span class="fd_v">{parcours.__doc__}</span>
</div>
"""
) )
if parcours.UE_IS_MODULE:
H.append(
"""<div class="fd_d"><span class="fd_t"> </span>
<span class="fd_n">(Chaque module est une UE)</span></div>"""
)
if editable:
H.append(
f"""<div><a href="{
url_for('notes.formation_edit', scodoc_dept=g.scodoc_dept,
formation_id=formation_id)
}" class="stdlink">modifier ces informations</a></div>"""
)
H.append("</div>")
# Formation APC (BUT) ? # Formation APC (BUT) ?
if is_apc: if is_apc:
H.append( H.append(
f"""<div class="formation_apc_infos"> f"""<div class="formation_apc_infos">
<div class="ue_list_tit">Formation par compétences (BUT)</div> <div class="ue_list_tit">Formation par compétences (BUT)
- Semestre {_html_select_semestre_idx(formation_id, semestre_ids, semestre_idx)}
</form>
</div>
"""
)
H.append(
f"""
<ul> <ul>
<li><a class="stdlink" href="{ <li><a class="stdlink" href="{
url_for('notes.edit_modules_ue_coefs', scodoc_dept=g.scodoc_dept, formation_id=formation_id, semestre_idx=None) url_for('notes.edit_modules_ue_coefs', scodoc_dept=g.scodoc_dept, formation_id=formation_id, semestre_idx=semestre_idx)
}">éditer les coefficients des ressources et SAÉs</a></li> }">éditer les coefficients des ressources et SAÉs</a></li>
</ul> </ul>
</div>""" """
) )
# Description des UE/matières/modules # Description des UE/matières/modules
H.append( H.append(
@ -600,7 +586,10 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
if is_apc: if is_apc:
H.append( H.append(
sco_edit_apc.html_edit_formation_apc( sco_edit_apc.html_edit_formation_apc(
formation, editable=editable, tag_editable=tag_editable formation,
semestre_idx=semestre_idx,
editable=editable,
tag_editable=tag_editable,
) )
) )
else: else:
@ -726,7 +715,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
<li><a class="stdlink" href="{ <li><a class="stdlink" href="{
url_for('notes.formsemestre_createwithmodules', scodoc_dept=g.scodoc_dept, url_for('notes.formsemestre_createwithmodules', scodoc_dept=g.scodoc_dept,
formation_id=formation_id, semestre_id=1) formation_id=formation_id, semestre_id=1)
}">Mettre en place un nouveau semestre de formation %(acronyme)s</a> }">Mettre en place un nouveau semestre de formation {formation.acronyme}</a>
</li> </li>
</ul>""" </ul>"""
) )
@ -739,6 +728,30 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
return "".join(H) return "".join(H)
def _html_select_semestre_idx(formation_id, semestre_ids, semestre_idx):
htm = """<form method="get">Semestre:
<select onchange="this.form.submit()" name="semestre_idx" id="semestre_idx" >
"""
for i in list(semestre_ids) + ["all"]:
if i == "all":
label = "tous"
else:
label = f"S{i}"
htm += f"""<option value="{i}" {
'selected'
if (semestre_idx == i)
or (i == "all" and semestre_idx is None)
else ''
}>{label}</option>
"""
htm += f"""
</select>
<input type="hidden" name="formation_id" value="{formation_id}"></input>
</form>"""
return htm
def _ue_table_ues( def _ue_table_ues(
parcours, parcours,
ues, ues,
@ -833,12 +846,8 @@ def _ue_table_ues(
) )
else: else:
H.append('<span class="locked">[verrouillé]</span>') H.append('<span class="locked">[verrouillé]</span>')
if parcours.APC_SAE:
func_html_list = _ue_table_ressources_saes
else:
func_html_list = _ue_table_matieres
H.append( H.append(
func_html_list( _ue_table_matieres(
parcours, parcours,
ue, ue,
editable, editable,
@ -848,7 +857,6 @@ def _ue_table_ues(
arrow_none, arrow_none,
delete_icon, delete_icon,
delete_disabled_icon, delete_disabled_icon,
module_type=module_type,
) )
) )
return "\n".join(H) return "\n".join(H)
@ -864,7 +872,6 @@ def _ue_table_matieres(
arrow_none, arrow_none,
delete_icon, delete_icon,
delete_disabled_icon, delete_disabled_icon,
module_type=None,
): ):
"""Édition de programme: liste des matières (et leurs modules) d'une UE.""" """Édition de programme: liste des matières (et leurs modules) d'une UE."""
H = [] H = []

View File

@ -1485,20 +1485,22 @@ div.formation_list_ues_titre {
padding-left: 24px; padding-left: 24px;
padding-right: 24px; padding-right: 24px;
font-size: 120%; font-size: 120%;
font-weight: bold;
} }
div.formation_list_modules { div.formation_list_modules, div.formation_list_ues {
border-radius: 18px; border-radius: 18px;
margin-left: 10px; margin-left: 10px;
margin-right: 10px; margin-right: 10px;
margin-bottom: 10px; margin-bottom: 10px;
padding-bottom: 1px; padding-bottom: 1px;
} }
div.formation_list_modules_titre { div.formation_list_ues {
padding-left: 24px; background-color: #b7d2fa;
padding-right: 24px; margin-top: 20px
font-weight: bold; }
font-size: 120%; div.formation_list_modules {
margin-top: 20px;
} }
div.formation_list_modules_RESSOURCE { div.formation_list_modules_RESSOURCE {
background-color: #f8c844; background-color: #f8c844;
@ -1509,12 +1511,25 @@ div.formation_list_modules_SAE {
div.formation_list_modules_STANDARD { div.formation_list_modules_STANDARD {
background-color: #afafc2; background-color: #afafc2;
} }
div.formation_list_modules_titre {
padding-left: 24px;
padding-right: 24px;
font-weight: bold;
font-size: 120%;
}
div.formation_list_ues ul.notes_module_list {
margin-top: 0px;
margin-bottom: -1px;
padding-top: 5px;
padding-bottom: 5px;
}
div.formation_list_modules ul.notes_module_list { div.formation_list_modules ul.notes_module_list {
margin-top: 0px; margin-top: 0px;
margin-bottom: -1px; margin-bottom: -1px;
padding-top: 5px; padding-top: 5px;
padding-bottom: 5px; padding-bottom: 5px;
} }
li.module_malus span.formation_module_tit { li.module_malus span.formation_module_tit {
color: red; color: red;
font-weight: bold; font-weight: bold;
@ -1530,14 +1545,23 @@ div.ue_list_tit {
margin-top: 5px; margin-top: 5px;
} }
ul.apc_ue_list {
background-color: rgba(180, 189, 191, 0.14);
margin-left: 8px;
margin-right: 8px;
}
ul.notes_ue_list { ul.notes_ue_list {
background-color: rgb(240,240,240);
margin-top: 4px; margin-top: 4px;
margin-right: 1em; margin-right: 1em;
margin-left: 1em;
padding-top: 1em;
padding-bottom: 1em;
font-weight: bold;
} }
li.notes_ue_list { li.notes_ue_list {
margin-top: 9px; margin-top: 9px;
list-style-type: none;
} }
span.ue_code { span.ue_code {

View File

@ -11,6 +11,9 @@ body {
display: grid; display: grid;
grid-auto-rows: minmax(24px, auto); grid-auto-rows: minmax(24px, auto);
gap: 2px; gap: 2px;
margin-top: 5px;
background: #fffefa;
margin: 10px;
} }
.entete{ .entete{
background: #09c; background: #09c;

View File

@ -0,0 +1,36 @@
{# Chapeau description d'une formation #}
<div class="formation_descr">
<div class="fd_d"><span class="fd_t">Titre:
</span><span class="fd_v">{{formation.titre}}</span>
</div>
<div class="fd_d"><span class="fd_t">Titre officiel:</span>
<span class="fd_v">{{formation.titre_officiel}}</span>
</div>
<div class="fd_d"><span class="fd_t">Acronyme:</span>
<span class="fd_v">{{formation.acronyme}}</span>
</div>
<div class="fd_d"><span class="fd_t">Code:</span>
<span class="fd_v">{{formation.formation_code}}</span>
</div>
<div class="fd_d"><span class="fd_t">Version:</span>
<span class="fd_v">{{formation.version}}</span>
</div>
<div class="fd_d"><span class="fd_t">Type parcours:</span>
<span class="fd_v">{{parcours.__doc__}}</span>
</div>
{% if parcours.UE_IS_MODULE %}
<div class="fd_d"><span class="fd_t"> </span>
<span class="fd_n">(Chaque module est une UE)</span>
</div>
{% endif %}
{% if editable %}
<div><a href="{{
url_for('notes.formation_edit', scodoc_dept=g.scodoc_dept,
formation_id=formation_id)
}}" class="stdlink">modifier ces informations</a>
</div>
{% endif %}
</div>

View File

@ -14,24 +14,24 @@
{% if editable and not loop.first %} {% if editable and not loop.first %}
<a href="{{ url_for('notes.module_move', <a href="{{ url_for('notes.module_move',
scodoc_dept=g.scodoc_dept, module_id=mod.id, after=0 ) scodoc_dept=g.scodoc_dept, module_id=mod.id, after=0 )
}}" class="aud">{{arrow_up|safe}}</a> }}" class="aud">{{icons.arrow_up|safe}}</a>
{% else %} {% else %}
{{arrow_none|safe}} {{icons.arrow_none|safe}}
{% endif %} {% endif %}
{% if editable and not loop.last %} {% if editable and not loop.last %}
<a href="{{ url_for('notes.module_move', <a href="{{ url_for('notes.module_move',
scodoc_dept=g.scodoc_dept, module_id=mod.id, after=1 ) scodoc_dept=g.scodoc_dept, module_id=mod.id, after=1 )
}}" class="aud">{{arrow_down|safe}}</a> }}" class="aud">{{icons.arrow_down|safe}}</a>
{% else %} {% else %}
{{arrow_none|safe}} {{icons.arrow_none|safe}}
{% endif %} {% endif %}
</span> </span>
{% if editable and not mod.modimpls.count() %} {% if editable and not mod.modimpls.count() %}
<a class="smallbutton" href="{{ url_for('notes.module_delete', <a class="smallbutton" href="{{ url_for('notes.module_delete',
scodoc_dept=g.scodoc_dept, module_id=mod.id) scodoc_dept=g.scodoc_dept, module_id=mod.id)
}}">{{delete_icon|safe}}</a> }}">{{icons.delete|safe}}</a>
{% else %} {% else %}
{{delete_disabled_icon|safe}} {{icons.delete_disabled|safe}}
{% endif %} {% endif %}
{% if editable %} {% if editable %}
@ -48,7 +48,7 @@
{{formation.get_parcours().SESSION_NAME}} {{mod.semestre_id}} {{formation.get_parcours().SESSION_NAME}} {{mod.semestre_id}}
({{mod.heures_cours}}/{{mod.heures_td}}/{{mod.heures_tp}}, ({{mod.heures_cours|default("&nbsp;",true)|safe}}/{{mod.heures_td|default("&nbsp;",true)|safe}}/{{mod.heures_tp|default("&nbsp;",true)|safe}},
Apo:<span class="{% if editable %}span_apo_edit{% endif %}" Apo:<span class="{% if editable %}span_apo_edit{% endif %}"
data-url="edit_module_set_code_apogee" data-url="edit_module_set_code_apogee"
@ -63,16 +63,17 @@
</span> </span>
<span class="sco_tag_edit"><form><textarea data-module_id="{{mod.id}}" <span class="sco_tag_edit"><form><textarea data-module_id="{{mod.id}}"
class="{% if editable %}module_tag_editor{% else %}module_tag_editor_ro{% endif %}">{{mod.tags|join(', ', attribute='title')}}</textarea></form></span> class="{% if tag_editable %}module_tag_editor{% else %}module_tag_editor_ro{% endif %}">{{mod.tags|join(', ', attribute='title')}}</textarea></form></span>
</li> </li>
{% endfor %} {% endfor %}
{% if editable %} {% if editable and formation.ues.count() and formation.ues[0].matieres.count() %}
<li><a class="stdlink" href="{{ <li><a class="stdlink" href="{{
url_for("notes.module_create", url_for("notes.module_create",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
module_type=module_type|int, module_type=module_type|int,
matiere_id=formation.ues[0].matieres.first().id
)}}" )}}"
>{{create_element_msg}}</a> >{{create_element_msg}}</a>
</li> </li>

View File

@ -1,94 +1,84 @@
<!DOCTYPE html> <form onchange="change_semestre()">Semestre:
<html lang="fr"> <select name="semestre_idx" id="semestre_idx">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="/ScoDoc/static/jQuery/jquery.js"></script>
<script src="/ScoDoc/static/js/table_editor.js"></script>
<link href="/ScoDoc/static/css/table_editor.css" rel="stylesheet" type="text/css" />
<title>Édition coef. formation</title>
</head>
<body>
<h2>Formation {{formation.titre}} ({{formation.acronyme}})
[version {{formation.version}}] code {{formation.code}}</h2>
<form onchange="change_semestre()">Semestre:
<select name="semestre_idx" id="semestre_idx" >
{% for i in semestre_ids %} {% for i in semestre_ids %}
<option value="{{i}}" {%if semestre_idx == i%}selected{%endif%}>{{i}}</option> <option value="{{i}}" {%if semestre_idx==i%}selected{%endif%}>{{i}}</option>
{% endfor %} {% endfor %}
</select> </select>
</form> <span><a class="stdlink" href="{{
url_for('notes.ue_table', scodoc_dept=g.scodoc_dept,
formation_id=formation.id, semestre_idx=semestre_idx)
}}">revenir à la formation</a></span>
</form>
<div class="tableau"></div> <div class="tableau"></div>
<script> <div class="help">
function change_semestre() { Édition des coefficients des modules veers les UE du semestre courant.
let semestre_idx = $("#semestre_idx")[0].value; Double-cliquer pour changer une valeur.
let url = window.location.href.replace( /\/[\-0-9]*$/, "/" + semestre_idx); Les valeurs sont automatiquement enregistrées au fur et à mesure.
window.location.href = url; </div>
};
<script>
function change_semestre() {
let semestre_idx = $("#semestre_idx")[0].value;
let url = window.location.href.replace(/\/[\-0-9]*$/, "/" + semestre_idx);
window.location.href = url;
};
$(function () { $(function () {
let semestre_idx = $("#semestre_idx")[0].value; let semestre_idx = $("#semestre_idx")[0].value;
if (semestre_idx > -10) { if (semestre_idx > -10) {
let base_url = "{{data_source}}"; let base_url = "{{data_source}}";
let data_url = base_url.replace( /\/[\-0-9]*$/, "/" + semestre_idx); let data_url = base_url.replace(/\/[\-0-9]*$/, "/" + semestre_idx);
console.log("data_url=", data_url ); console.log("data_url=", data_url);
$.getJSON(data_url, function (data) { $.getJSON(data_url, function (data) {
console.log("build_table") console.log("build_table")
build_table(data); build_table(data);
}); });
}
});
function save(obj) {
var value = obj.innerText.trim();
if (value.length == 0) {
value = "0";
}
if (!/^[\d.,]+$/.test(value)) {
message("Il est attendu un nombre");
return false;
}
if (value == obj.dataset.data) {
return true; // Aucune modification, pas d'enregistrement mais on continue normalement
}
obj.dataset.data = value;
obj.classList.add("wait");
// XXX DEBUG
// console.log(`
// x : ${getComputedStyle(obj).getPropertyValue("--x")}
// y : ${getComputedStyle(obj).getPropertyValue("--y")}
// data : ${value}
// ue_id: ${obj.dataset.ue_id}
// module_id : ${obj.dataset.module_id}
// `);
$.post("{{data_save}}",
{
module_id: obj.dataset.module_id,
ue_id: obj.dataset.ue_id,
coef: value
},
function (result) {
obj.classList.remove("wait");
if (obj.dataset.orig != value)
obj.classList.add("modified");
else
obj.classList.remove("modified");
// Lorsque les données sont bien enregistrées, on enlève
// l'indication que c'est bon au bout d'un temps
//setTimeout(() => {
// obj.classList.remove("modified");
//}, 1000);
}
);
return true;
} }
</script> });
</body> function save(obj) {
var value = obj.innerText.trim();
</html> if (value.length == 0) {
value = "0";
}
if (!/^[\d.,]+$/.test(value)) {
message("Il est attendu un nombre");
return false;
}
if (value == obj.dataset.data) {
return true; // Aucune modification, pas d'enregistrement mais on continue normalement
}
obj.dataset.data = value;
obj.classList.add("wait");
// XXX DEBUG
// console.log(`
// x : ${getComputedStyle(obj).getPropertyValue("--x")}
// y : ${getComputedStyle(obj).getPropertyValue("--y")}
// data : ${value}
// ue_id: ${obj.dataset.ue_id}
// module_id : ${obj.dataset.module_id}
// `);
$.post("{{data_save}}",
{
module_id: obj.dataset.module_id,
ue_id: obj.dataset.ue_id,
coef: value
},
function (result) {
obj.classList.remove("wait");
if (obj.dataset.orig != value)
obj.classList.add("modified");
else
obj.classList.remove("modified");
// Lorsque les données sont bien enregistrées, on enlève
// l'indication que c'est bon au bout d'un temps
//setTimeout(() => {
// obj.classList.remove("modified");
//}, 1000);
}
);
return true;
}
</script>

View File

@ -1,49 +1,54 @@
{# Édition liste UEs APC #} {# Édition liste UEs APC #}
<div class="formation_list_ues"> <div class="formation_list_ues">
<div class="formation_list_ues_titre">Unités d'Enseignement (UEs)</div> <div class="formation_list_ues_titre">Unités d'Enseignement (UEs)</div>
<ul class="notes_ue_list"> {% for semestre_idx in semestre_ids %}
{% if not formation.ues.count() %} <div class="formation_list_ues_sem">Semestre S{{semestre_idx}}</div>
<li class="notes_ue_list"><em>aucune UE</em></li> <ul class="apc_ue_list">
{% else %} {% for ue in formation.ues.filter_by(semestre_idx=semestre_idx) %}
{% for ue in formation.ues %}
<li class="notes_ue_list"> <li class="notes_ue_list">
{% if editable and not loop.first %} {% if editable and not loop.first %}
<a href="{{ url_for('notes.ue_move', <a href="{{ url_for('notes.ue_move',
scodoc_dept=g.scodoc_dept, ue_id=ue.id, after=0 ) scodoc_dept=g.scodoc_dept, ue_id=ue.id, after=0 )
}}" class="aud">{{arrow_up|safe}}</a> }}" class="aud">{{icons.arrow_up|safe}}</a>
{% else %} {% else %}
{{arrow_none|safe}} {{icons.arrow_none|safe}}
{% endif %} {% endif %}
{% if editable and not loop.last %} {% if editable and not loop.last %}
<a href="{{ url_for('notes.ue_move', <a href="{{ url_for('notes.ue_move',
scodoc_dept=g.scodoc_dept, ue_id=ue.id, after=1 ) scodoc_dept=g.scodoc_dept, ue_id=ue.id, after=1 )
}}" class="aud">{{arrow_down|safe}}</a> }}" class="aud">{{icons.arrow_down|safe}}</a>
{% else %} {% else %}
{{arrow_none|safe}} {{icons.arrow_none|safe}}
{% endif %} {% endif %}
</span> </span>
{% if editable and not ue.modules.count() %} {% if editable and not ue.modules.count() %}
<a class="smallbutton" href="{{ url_for('notes.ue_delete', <a class="smallbutton" href="{{ url_for('notes.ue_delete',
scodoc_dept=g.scodoc_dept, ue_id=ue.id) scodoc_dept=g.scodoc_dept, ue_id=ue.id)
}}">{{delete_icon|safe}}</a> }}">{{icons.delete|safe}}</a>
{% else %} {% else %}
{{delete_disabled_icon|safe}} {{icons.delete_disabled|safe}}
{% endif %} {% endif %}
<b>{{ue.acronyme}}</b> {{ue.titre}} <b>{{ue.acronyme}}</b> {{ue.titre}}
{% if editable and not ue.is_locked() %}
<a class="stdlink" href="{{ url_for('notes.ue_edit',
scodoc_dept=g.scodoc_dept, ue_id=ue.id)
}}">modifier</a>
{% endif %}
</li> </li>
{% endfor %} {% endfor %}
{% endif %} </ul>
{% endfor %}
{% if editable %} {% if editable %}
<li><a class="stdlink" href="{{ <ul>
<li class="notes_ue_list notes_ue_list_add"><a class="stdlink" href="{{
url_for("notes.ue_create", url_for("notes.ue_create",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
formation_id=formation.id, formation_id=formation.id,
)}}" )}}"
>ajouter une UE</a> >ajouter une UE</a>
</li> </li>
</ul>
{% endif %} {% endif %}
</ul>
</div> </div>

View File

@ -344,8 +344,10 @@ sco_publish(
@scodoc @scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func @scodoc7func
def ue_table(formation_id=None, msg=""): def ue_table(formation_id=None, semestre_idx=1, msg=""):
return sco_edit_ue.ue_table(formation_id=formation_id, msg=msg) return sco_edit_ue.ue_table(
formation_id=formation_id, semestre_idx=semestre_idx, msg=msg
)
@bp.route("/ue_set_internal", methods=["GET", "POST"]) @bp.route("/ue_set_internal", methods=["GET", "POST"])

View File

@ -53,6 +53,7 @@ from app.views import notes_bp as bp
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
from app.scodoc import notesdb as ndb from app.scodoc import notesdb as ndb
from app.scodoc import sco_formations
from app import log from app import log
from app.models.formations import Formation, UniteEns, Module from app.models.formations import Formation, UniteEns, Module
@ -159,19 +160,41 @@ def edit_modules_ue_coefs(formation_id, semestre_idx=None):
formation = models.Formation.query.filter_by( formation = models.Formation.query.filter_by(
formation_id=formation_id formation_id=formation_id
).first_or_404() ).first_or_404()
return render_template( locked = sco_formations.formation_has_locked_sems(formation_id)
"pn/form_modules_ue_coefs.html", if locked:
formation=formation, lockicon = scu.icontag("lock32_img", title="verrouillé")
data_source=url_for( else:
"notes.table_modules_ue_coefs", lockicon = ""
scodoc_dept=g.scodoc_dept, H = [
formation_id=formation_id, html_sco_header.sco_header(
semestre_idx=semestre_idx or "", cssstyles=["css/table_editor.css"],
javascripts=[
"js/table_editor.js",
],
page_title=f"Coefs programme {formation.acronyme}",
), ),
data_save=url_for( f"""<h2>Formation {formation.titre} ({formation.acronyme})
"notes.set_module_ue_coef", [version {formation.version}] code {formation.formation_code}
scodoc_dept=g.scodoc_dept, {lockicon}
</h2>
""",
render_template(
"pn/form_modules_ue_coefs.html",
formation=formation,
data_source=url_for(
"notes.table_modules_ue_coefs",
scodoc_dept=g.scodoc_dept,
formation_id=formation_id,
semestre_idx=semestre_idx or "",
),
data_save=url_for(
"notes.set_module_ue_coef",
scodoc_dept=g.scodoc_dept,
),
semestre_idx=int(semestre_idx),
semestre_ids=range(1, formation.get_parcours().NB_SEM + 1),
), ),
semestre_idx=int(semestre_idx), html_sco_header.sco_footer(),
semestre_ids=range(1, formation.get_parcours().NB_SEM + 1), ]
)
return "\n".join(H)