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):
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):
"""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"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
_HTML_BEGIN = """<!DOCTYPE html>
<html lang="fr">
<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-Style-Type" content="text/css" />
<meta name="LANG" content="fr" />
<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" />

View File

@ -38,6 +38,7 @@ from app.scodoc.sco_utils import ModuleType
def html_edit_formation_apc(
formation,
semestre_idx=None,
editable=True,
tag_editable=True,
):
@ -48,75 +49,84 @@ def html_edit_formation_apc(
"""
parcours = formation.get_parcours()
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)
if semestre_idx is None:
semestre_ids = range(1, parcours.NB_SEM + 1)
else:
semestre_ids = [semestre_idx]
other_modules = formation.modules.filter(
Module.module_type != ModuleType.SAE
and Module.module_type != ModuleType.RESSOURCE
Module.module_type != ModuleType.SAE, Module.module_type != ModuleType.RESSOURCE
)
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"
)
delete_disabled_icon = scu.icontag(
"delete_small_dis_img", title="Suppression impossible (module utilisé)"
)
icons = {
"arrow_up": arrow_up,
"arrow_down": arrow_down,
"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 = [
render_template(
"pn/form_ues.html",
formation=formation,
semestre_ids=semestre_ids,
editable=editable,
arrow_up=arrow_up,
arrow_down=arrow_down,
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,
tag_editable=tag_editable,
icons=icons,
),
]
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)

View File

@ -124,15 +124,25 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
object_name = "Module"
H = [
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(
"scodoc/help/modules.html",
is_apc=is_apc,
ue=ue,
semestre_id=semestre_id,
),
)
]
# cherche le numero adéquat (pour placer le module en fin de liste)
modules = Matiere.query.get(1).modules.all()
@ -145,15 +155,43 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
"code",
{
"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,
"validator": lambda val, field, formation_id=ue.formation_id: check_module_code_unicity(
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",
{
@ -166,22 +204,29 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
),
(
"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",
{
"title": "Heures de TD",
"size": 4,
"type": "float",
"explanation": "nombre d'heures de Travaux Dirigés",
"explanation": "nombre d'heures de Travaux Dirigés (optionnel)",
},
),
(
"heures_tp",
{
"title": "Heures de TP",
"size": 4,
"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:
semestres_indices = list(range(1, parcours.NB_SEM + 1))
descr += [
(
"coefficient",
@ -209,19 +253,8 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
"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 += [
# ('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"}),

View File

@ -29,7 +29,8 @@
"""
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 app.models.formations import Formation, UniteEns
@ -260,7 +261,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None):
{
"input_type": "menu",
"type": "int",
"allow_null": True,
"allow_null": False,
"title": parcours.SESSION_NAME.capitalize(),
"explanation": "%s de l'UE dans la formation" % parcours.SESSION_NAME,
"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(
(
"create_matiere",
@ -357,7 +358,9 @@ def ue_edit(ue_id=None, create=False, formation_id=None):
formation_id, int(tf[2]["semestre_idx"])
)
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(
{"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)
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
éditer (si non verrouillée).
"""
@ -459,7 +462,11 @@ def ue_table(formation_id=None, msg=""): # was ue_list
parcours = formation.get_parcours()
is_apc = parcours.APC_SAE
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_externes = ue_list(args={"formation_id": formation_id, "is_external": True})
# tri par semestre et numero:
@ -538,54 +545,33 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
)
# Description de la formation
H.append('<div class="formation_descr">')
H.append(
f"""<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>
"""
render_template(
"pn/form_descr.html",
formation=formation,
parcours=parcours,
editable=editable,
)
)
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) ?
if is_apc:
H.append(
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>
<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>
</ul>
</div>"""
"""
)
# Description des UE/matières/modules
H.append(
@ -600,7 +586,10 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
if is_apc:
H.append(
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:
@ -726,7 +715,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
<li><a class="stdlink" href="{
url_for('notes.formsemestre_createwithmodules', scodoc_dept=g.scodoc_dept,
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>
</ul>"""
)
@ -739,6 +728,30 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
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(
parcours,
ues,
@ -833,12 +846,8 @@ def _ue_table_ues(
)
else:
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(
func_html_list(
_ue_table_matieres(
parcours,
ue,
editable,
@ -848,7 +857,6 @@ def _ue_table_ues(
arrow_none,
delete_icon,
delete_disabled_icon,
module_type=module_type,
)
)
return "\n".join(H)
@ -864,7 +872,6 @@ def _ue_table_matieres(
arrow_none,
delete_icon,
delete_disabled_icon,
module_type=None,
):
"""Édition de programme: liste des matières (et leurs modules) d'une UE."""
H = []

View File

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

View File

@ -11,6 +11,9 @@ body {
display: grid;
grid-auto-rows: minmax(24px, auto);
gap: 2px;
margin-top: 5px;
background: #fffefa;
margin: 10px;
}
.entete{
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 %}
<a href="{{ url_for('notes.module_move',
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 %}
{{arrow_none|safe}}
{{icons.arrow_none|safe}}
{% endif %}
{% if editable and not loop.last %}
<a href="{{ url_for('notes.module_move',
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 %}
{{arrow_none|safe}}
{{icons.arrow_none|safe}}
{% endif %}
</span>
{% if editable and not mod.modimpls.count() %}
<a class="smallbutton" href="{{ url_for('notes.module_delete',
scodoc_dept=g.scodoc_dept, module_id=mod.id)
}}">{{delete_icon|safe}}</a>
}}">{{icons.delete|safe}}</a>
{% else %}
{{delete_disabled_icon|safe}}
{{icons.delete_disabled|safe}}
{% endif %}
{% if editable %}
@ -48,7 +48,7 @@
{{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 %}"
data-url="edit_module_set_code_apogee"
@ -63,16 +63,17 @@
</span>
<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>
{% endfor %}
{% if editable %}
{% if editable and formation.ues.count() and formation.ues[0].matieres.count() %}
<li><a class="stdlink" href="{{
url_for("notes.module_create",
scodoc_dept=g.scodoc_dept,
module_type=module_type|int,
matiere_id=formation.ues[0].matieres.first().id
)}}"
>{{create_element_msg}}</a>
</li>

View File

@ -1,94 +1,84 @@
<!DOCTYPE html>
<html lang="fr">
<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" >
<form onchange="change_semestre()">Semestre:
<select name="semestre_idx" id="semestre_idx">
{% 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 %}
</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>
function change_semestre() {
let semestre_idx = $("#semestre_idx")[0].value;
let url = window.location.href.replace( /\/[\-0-9]*$/, "/" + semestre_idx);
window.location.href = url;
};
<div class="help">
Édition des coefficients des modules veers les UE du semestre courant.
Double-cliquer pour changer une valeur.
Les valeurs sont automatiquement enregistrées au fur et à mesure.
</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 () {
let semestre_idx = $("#semestre_idx")[0].value;
if (semestre_idx > -10) {
let base_url = "{{data_source}}";
let data_url = base_url.replace( /\/[\-0-9]*$/, "/" + semestre_idx);
console.log("data_url=", data_url );
$.getJSON(data_url, function (data) {
console.log("build_table")
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;
$(function () {
let semestre_idx = $("#semestre_idx")[0].value;
if (semestre_idx > -10) {
let base_url = "{{data_source}}";
let data_url = base_url.replace(/\/[\-0-9]*$/, "/" + semestre_idx);
console.log("data_url=", data_url);
$.getJSON(data_url, function (data) {
console.log("build_table")
build_table(data);
});
}
</script>
</body>
</html>
});
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>

View File

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

View File

@ -344,8 +344,10 @@ sco_publish(
@scodoc
@permission_required(Permission.ScoView)
@scodoc7func
def ue_table(formation_id=None, msg=""):
return sco_edit_ue.ue_table(formation_id=formation_id, msg=msg)
def ue_table(formation_id=None, semestre_idx=1, 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"])

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 notesdb as ndb
from app.scodoc import sco_formations
from app import log
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_id=formation_id
).first_or_404()
return 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 "",
locked = sco_formations.formation_has_locked_sems(formation_id)
if locked:
lockicon = scu.icontag("lock32_img", title="verrouillé")
else:
lockicon = ""
H = [
html_sco_header.sco_header(
cssstyles=["css/table_editor.css"],
javascripts=[
"js/table_editor.js",
],
page_title=f"Coefs programme {formation.acronyme}",
),
data_save=url_for(
"notes.set_module_ue_coef",
scodoc_dept=g.scodoc_dept,
f"""<h2>Formation {formation.titre} ({formation.acronyme})
[version {formation.version}] code {formation.formation_code}
{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),
semestre_ids=range(1, formation.get_parcours().NB_SEM + 1),
)
html_sco_header.sco_footer(),
]
return "\n".join(H)