BUT: édition des coefs: filtre par parcours

This commit is contained in:
Emmanuel Viennet 2022-10-31 09:38:39 +01:00 committed by iziram
parent cc674b4e65
commit 979359257b
5 changed files with 125 additions and 51 deletions

View File

@ -33,7 +33,7 @@ def form_ue_choix_niveau(ue: UniteEns) -> str:
parcours_options.append( parcours_options.append(
f"""<option value="{parcour.id}" { f"""<option value="{parcour.id}" {
'selected' if ue.parcour == parcour else ''} 'selected' if ue.parcour == parcour else ''}
>{parcour.libelle} >{parcour.libelle} ({parcour.code})
</option>""" </option>"""
) )

View File

@ -24,15 +24,12 @@
"""Édition formation APC (BUT) """Édition formation APC (BUT)
""" """
import flask
from flask import url_for
from flask.templating import render_template from flask.templating import render_template
from flask import g, request
from flask_login import current_user
from app import db from app import db
from app.but import apc_edit_ue from app.but import apc_edit_ue
from app.models import Formation, UniteEns, Matiere, Module, FormSemestre, ModuleImpl from app.models import UniteEns, Matiere, Module, FormSemestre, ModuleImpl
from app.models.validations import ScolarFormSemestreValidation from app.models.validations import ScolarFormSemestreValidation
from app.scodoc.sco_codes_parcours import UE_SPORT from app.scodoc.sco_codes_parcours import UE_SPORT
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu

View File

@ -3,10 +3,19 @@
form.semestre_selector { form.semestre_selector {
margin-top: 2ex; margin-top: 2ex;
} }
form.semestre_selector>div {
display: inline-flex;
}
form.semestre_selector>div>div {
margin-left: 16px;
}
/***************************/ /***************************/
/* Le tableau */ /* Le tableau */
/***************************/ /***************************/
.tableau{ .tableau {
display: inline-grid; display: inline-grid;
grid-auto-rows: minmax(24px, auto); grid-auto-rows: minmax(24px, auto);
grid-template-columns: fit-content(50px); grid-template-columns: fit-content(50px);
@ -15,11 +24,13 @@ form.semestre_selector {
background: #fffefa; background: #fffefa;
margin: 10px; margin: 10px;
} }
.entete{
.entete {
background: #09c; background: #09c;
font-weight: bold; font-weight: bold;
} }
.tableau>div{
.tableau>div {
padding: 4px 8px; padding: 4px 8px;
border-radius: 4px; border-radius: 4px;
border: 1px solid #999; border: 1px solid #999;
@ -27,46 +38,69 @@ form.semestre_selector {
grid-row: var(--y) / span var(--nbY); grid-row: var(--y) / span var(--nbY);
} }
[data-editable="true"]{ [data-editable="true"] {
cursor: pointer; cursor: pointer;
} }
/*****************/ /*****************/
/* Styles ScoDoc */ /* Styles ScoDoc */
/*****************/ /*****************/
div.title_ue { div.title_ue {
background-color: #b7d2fa; background-color: #b7d2fa;
} }
.tableau>div.title_mod {
.tableau>div.title_mod {}
}
div.title_RESSOURCE { div.title_RESSOURCE {
background-color: #f8c844; background-color: #f8c844;
} }
div.title_SAE { div.title_SAE {
background-color: #c6ffab; background-color: #c6ffab;
} }
div.title_STANDARD, .champs_STANDARD {
div.title_STANDARD,
.champs_STANDARD {
background-color: #fefefe; background-color: #fefefe;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='32' viewBox='0 0 16 32'%3E%3Cg fill='%239C92AC' fill-opacity='0.21'%3E%3Cpath fill-rule='evenodd' d='M0 24h4v2H0v-2zm0 4h6v2H0v-2zm0-8h2v2H0v-2zM0 0h4v2H0V0zm0 4h2v2H0V4zm16 20h-6v2h6v-2zm0 4H8v2h8v-2zm0-8h-4v2h4v-2zm0-20h-6v2h6V0zm0 4h-4v2h4V4zm-2 12h2v2h-2v-2zm0-8h2v2h-2V8zM2 8h10v2H2V8zm0 8h10v2H2v-2zm-2-4h14v2H0v-2zm4-8h6v2H4V4zm0 16h6v2H4v-2zM6 0h2v2H6V0zm0 24h2v2H6v-2z'/%3E%3C/g%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='32' viewBox='0 0 16 32'%3E%3Cg fill='%239C92AC' fill-opacity='0.21'%3E%3Cpath fill-rule='evenodd' d='M0 24h4v2H0v-2zm0 4h6v2H0v-2zm0-8h2v2H0v-2zM0 0h4v2H0V0zm0 4h2v2H0V4zm16 20h-6v2h6v-2zm0 4H8v2h8v-2zm0-8h-4v2h4v-2zm0-20h-6v2h6V0zm0 4h-4v2h4V4zm-2 12h2v2h-2v-2zm0-8h2v2h-2V8zM2 8h10v2H2V8zm0 8h10v2H2v-2zm-2-4h14v2H0v-2zm4-8h6v2H4V4zm0 16h6v2H4v-2zM6 0h2v2H6V0zm0 24h2v2H6v-2z'/%3E%3C/g%3E%3C/svg%3E");
} }
div.title_MALUS { div.title_MALUS {
background-color: #ff4700; background-color: #ff4700;
} }
.sums { .sums {
background: #ddd; background: #ddd;
} }
/***************************/ /***************************/
/* Statut des cellules */ /* Statut des cellules */
/***************************/ /***************************/
.selected{ outline: 1px solid #c09; } .selected {
.modifying{ outline: 2px dashed #c09; } outline: 1px solid #c09;
.wait{ outline: 2px solid #c90; } }
.good{ outline: 2px solid #9c0; }
.modified { font-weight: bold; color:indigo} .modifying {
outline: 2px dashed #c09;
}
.wait {
outline: 2px solid #c90;
}
.good {
outline: 2px solid #9c0;
}
.modified {
font-weight: bold;
color: indigo
}
/***************************/ /***************************/
/* Message */ /* Message */
/***************************/ /***************************/
.message{ .message {
position: fixed; position: fixed;
bottom: 100%; bottom: 100%;
left: 50%; left: 50%;
@ -80,7 +114,13 @@ div.title_MALUS {
animation: message 3s; animation: message 3s;
transform: translate(-50%, 0); transform: translate(-50%, 0);
} }
@keyframes message{
20%{transform: translate(-50%, 100%)} @keyframes message {
80%{transform: translate(-50%, 100%)} 20% {
} transform: translate(-50%, 100%)
}
80% {
transform: translate(-50%, 100%)
}
}

View File

@ -1,32 +1,50 @@
{# -*- mode: jinja-html -*- #} {# -*- mode: jinja-html -*- #}
<h2>{% if not read_only %}Édition des c{% else %}C{%endif%}oefficients des modules vers les UEs</h2> <h2>{% if not read_only %}Édition des c{% else %}C{%endif%}oefficients des modules vers les UEs</h2>
<div class="help"> <div class="help">
{% if not read_only %} {% if not read_only %}
<p>Double-cliquer pour changer une valeur. <p>Double-cliquer pour changer une valeur.
Les valeurs sont automatiquement enregistrées au fur et à mesure. Les valeurs sont automatiquement enregistrées au fur et à mesure.
</p>
{% endif %}
<p>Chaque ligne représente une ressource ou SAÉ, et chaque colonne une Unité d'Enseignement (UE).
</p> </p>
{% endif %}
<p>Chaque ligne représente une ressource ou SAÉ, et chaque colonne une Unité d'Enseignement (UE).
</p>
</div> </div>
<form class="semestre_selector">Semestre: <form class="semestre_selector">
<select onchange="this.form.submit()"" name="semestre_idx" id="semestre_idx">
{% for i in semestre_ids %}
<option value="{{i}}" {%if semestre_idx==i%}selected{%endif%}>{{i}}</option>
{% endfor %}
<option value="" {%if semestre_idx is none%}selected{%endif%}>tous</option>
</select>
<input type="hidden" name="formation_id" value="{{formation.id}}"></input> <input type="hidden" name="formation_id" value="{{formation.id}}"></input>
<span><a class="stdlink" href="{{ <div>
<div>Semestre:
<select onchange="this.form.submit()" name="semestre_idx" id="semestre_idx">
{% for i in semestre_ids %}
<option value="{{i}}" {%if semestre_idx==i%}selected{%endif%}>{{i}}</option>
{% endfor %}
<option value="" {%if semestre_idx is none%}selected{%endif%}>Tous</option>
</select>
</div>
{% if formation.referentiel_competence %}
<div>Parcours:
<select onchange="this.form.submit()" name="parcours_id" id="semestre_idx">
<option value="" {%if parcours_id is none%}selected{%endif%}>Tous</option>
{% for parcour in formation.referentiel_competence.parcours %}
<option value="{{parcour.id}}" {%if parcours_id==parcour.id%}selected{%endif%}> {{parcour.libelle}}
({{parcour.code}})
</option>
{% endfor %}
</select>
</div>
{% endif %}
<div>
<a class="stdlink" href="{{
url_for('notes.ue_table', scodoc_dept=g.scodoc_dept, url_for('notes.ue_table', scodoc_dept=g.scodoc_dept,
formation_id=formation.id, semestre_idx=semestre_idx) formation_id=formation.id, semestre_idx=semestre_idx)
}}">revenir à la formation</a></span> }}">revenir à la formation</a>
</div>
</div>
</form> </form>
<div class="tableau"></div> <div class="tableau"></div>
<script> <script>
var read_only={{"true" if read_only else "false"}}; var read_only = {{ "true" if read_only else "false"}};
$(function () { $(function () {
let data_url = "{{data_source}}"; let data_url = "{{data_source}}";
$.getJSON(data_url, function (data) { $.getJSON(data_url, function (data) {

View File

@ -47,37 +47,49 @@ from app.auth.models import User
from app.comp import moy_ue from app.comp import moy_ue
from app.decorators import scodoc, permission_required from app.decorators import scodoc, permission_required
from app.scodoc import sco_edit_formation
from app.views import notes_bp as bp 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 sco_formations from app.scodoc import sco_formations
from app import log from app import log
from app.models import Formation, UniteEns, Module from app.models import ApcParcours, Formation, UniteEns, Module
from app.scodoc.sco_exceptions import (
ScoValueError,
ScoLockedFormError,
ScoGenError,
AccessDenied,
)
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
@bp.route("/table_modules_ue_coefs/<int:formation_id>") @bp.route("/table_modules_ue_coefs/<int:formation_id>")
@bp.route("/table_modules_ue_coefs/<int:formation_id>/<int:semestre_idx>") @bp.route("/table_modules_ue_coefs/<int:formation_id>/<int:semestre_idx>")
@bp.route(
"/table_modules_ue_coefs/<int:formation_id>/<int:semestre_idx>/<int:parcours_id>"
)
@scodoc @scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
def table_modules_ue_coefs(formation_id, semestre_idx=None): def table_modules_ue_coefs(formation_id, semestre_idx=None, parcours_id: int = None):
"""Description JSON de la table des coefs modules/UE dans une formation""" """Description JSON de la table des coefs modules/UE dans une formation
_ = models.Formation.query.get_or_404(formation_id) # check
Si le parcours est indiqué et que la formation a un référentiel de compétence,
restreint l'affichage aux UE et modules de ce parcours.
"""
formation: Formation = models.Formation.query.get_or_404(formation_id) # check
if semestre_idx == "": if semestre_idx == "":
semestre_idx = None semestre_idx = None
if parcours_id == "":
parcours_id = None
if parcours_id is not None and formation.referentiel_competence is not None:
parcour: ApcParcours = ApcParcours.query.get_or_404(parcours_id)
else:
parcour = None
df, ues, modules = moy_ue.df_load_module_coefs(formation_id, semestre_idx) df, ues, modules = moy_ue.df_load_module_coefs(formation_id, semestre_idx)
# Filtrage par parcours
if parcour is not None:
ues = [ue for ue in ues if parcours_id == ue.parcour_id]
modules = [
mod for mod in modules if parcours_id in (p.id for p in mod.parcours)
]
# Titre des modules, en ligne # Titre des modules, en ligne
col_titres_mods = [ col_titres_mods = [
{ {
@ -157,6 +169,11 @@ def edit_modules_ue_coefs():
"""Formulaire édition grille coefs EU/modules""" """Formulaire édition grille coefs EU/modules"""
formation_id = int(request.args["formation_id"]) formation_id = int(request.args["formation_id"])
semestre_idx = request.args.get("semestre_idx", "") semestre_idx = request.args.get("semestre_idx", "")
parcours_id = request.args.get("parcours_id")
if parcours_id == "":
parcours_id = None
if parcours_id is not None:
parcours_id = int(parcours_id)
if len(semestre_idx.strip()) > 0: if len(semestre_idx.strip()) > 0:
semestre_idx = int(semestre_idx) semestre_idx = int(semestre_idx)
else: else:
@ -190,6 +207,7 @@ def edit_modules_ue_coefs():
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
formation_id=formation_id, formation_id=formation_id,
semestre_idx=semestre_idx, semestre_idx=semestre_idx,
parcours_id=parcours_id,
), ),
data_save=url_for( data_save=url_for(
"notes.set_module_ue_coef", "notes.set_module_ue_coef",
@ -198,6 +216,7 @@ def edit_modules_ue_coefs():
read_only=not current_user.has_permission(Permission.ScoChangeFormation), read_only=not current_user.has_permission(Permission.ScoChangeFormation),
semestre_idx=semestre_idx, semestre_idx=semestre_idx,
semestre_ids=range(1, formation.get_parcours().NB_SEM + 1), semestre_ids=range(1, formation.get_parcours().NB_SEM + 1),
parcours_id=parcours_id,
), ),
html_sco_header.sco_footer(), html_sco_header.sco_footer(),
] ]