WIP: Affichage validation cursus BUT sur page etudiant.
This commit is contained in:
parent
03faa90177
commit
cada9c24d0
@ -13,7 +13,7 @@ Classe raccordant avec ScoDoc 7:
|
|||||||
avec la même interface.
|
avec la même interface.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import collections
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from flask import g, url_for
|
from flask import g, url_for
|
||||||
@ -47,12 +47,14 @@ from app.models.validations import ScolarFormSemestreValidation
|
|||||||
from app.scodoc import sco_codes_parcours as sco_codes
|
from app.scodoc import sco_codes_parcours as sco_codes
|
||||||
from app.scodoc.sco_codes_parcours import RED, UE_STANDARD
|
from app.scodoc.sco_codes_parcours import RED, UE_STANDARD
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc.sco_exceptions import ScoException, ScoValueError
|
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError
|
||||||
|
|
||||||
from app.scodoc import sco_cursus_dut
|
from app.scodoc import sco_cursus_dut
|
||||||
|
|
||||||
|
|
||||||
class SituationEtudCursusBUT(sco_cursus_dut.SituationEtudCursusClassic):
|
class SituationEtudCursusBUT(sco_cursus_dut.SituationEtudCursusClassic):
|
||||||
|
"""Pour compat ScoDoc 7: à revoir pour le BUT"""
|
||||||
|
|
||||||
def __init__(self, etud: dict, formsemestre_id: int, res: ResultatsSemestreBUT):
|
def __init__(self, etud: dict, formsemestre_id: int, res: ResultatsSemestreBUT):
|
||||||
super().__init__(etud, formsemestre_id, res)
|
super().__init__(etud, formsemestre_id, res)
|
||||||
# Ajustements pour le BUT
|
# Ajustements pour le BUT
|
||||||
@ -65,3 +67,114 @@ class SituationEtudCursusBUT(sco_cursus_dut.SituationEtudCursusClassic):
|
|||||||
def parcours_validated(self):
|
def parcours_validated(self):
|
||||||
"True si le parcours est validé"
|
"True si le parcours est validé"
|
||||||
return False # XXX TODO
|
return False # XXX TODO
|
||||||
|
|
||||||
|
|
||||||
|
class EtudCursusBUT:
|
||||||
|
"""L'état de l'étudiant dans son cursus BUT
|
||||||
|
Liste des niveaux validés/à valider
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, etud: Identite, formation: Formation):
|
||||||
|
"""formation indique la spécialité préparée"""
|
||||||
|
# Vérifie que l'étudiant est bien inscrit à un sem. de cette formation
|
||||||
|
if formation.id not in (
|
||||||
|
ins.formsemestre.formation.id for ins in etud.formsemestre_inscriptions
|
||||||
|
):
|
||||||
|
raise ScoValueError(
|
||||||
|
f"{etud.nomprenom} non inscrit dans {formation.titre} v{formation.version}"
|
||||||
|
)
|
||||||
|
if not formation.referentiel_competence:
|
||||||
|
raise ScoNoReferentielCompetences(formation=formation)
|
||||||
|
#
|
||||||
|
self.etud = etud
|
||||||
|
self.formation = formation
|
||||||
|
self.inscriptions = sorted(
|
||||||
|
[
|
||||||
|
ins
|
||||||
|
for ins in etud.formsemestre_inscriptions
|
||||||
|
if ins.formsemestre.formation.referentiel_competence.id
|
||||||
|
== formation.referentiel_competence.id
|
||||||
|
],
|
||||||
|
key=lambda s: (s.formsemestre.semestre_id, s.formsemestre.date_debut),
|
||||||
|
)
|
||||||
|
"Liste des inscriptions aux sem. de la formation, triées par indice et chronologie"
|
||||||
|
self.parcour: ApcParcours = self.inscriptions[-1].parcour
|
||||||
|
"Le parcour à valider: celui du DERNIER semestre suivi (peut être None)"
|
||||||
|
self.niveaux_by_annee = {}
|
||||||
|
"{ annee : liste des niveaux à valider }"
|
||||||
|
self.niveaux: dict[int, ApcNiveau] = {}
|
||||||
|
"cache les niveaux"
|
||||||
|
for annee in (1, 2, 3):
|
||||||
|
niveaux_d = formation.referentiel_competence.get_niveaux_by_parcours(
|
||||||
|
annee, self.parcour
|
||||||
|
)[1]
|
||||||
|
# groupe les niveaux de tronc commun et ceux spécifiques au parcour
|
||||||
|
self.niveaux_by_annee[annee] = niveaux_d["TC"] + (
|
||||||
|
niveaux_d[self.parcour.id] if self.parcour else []
|
||||||
|
)
|
||||||
|
self.niveaux.update(
|
||||||
|
{niveau.id: niveau for niveau in self.niveaux_by_annee[annee]}
|
||||||
|
)
|
||||||
|
# Probablement inutile:
|
||||||
|
# # Cherche les validations de jury enregistrées pour chaque niveau
|
||||||
|
# self.validations_by_niveau = collections.defaultdict(lambda: [])
|
||||||
|
# " { niveau_id : [ ApcValidationRCUE ] }"
|
||||||
|
# for validation_rcue in ApcValidationRCUE.query.filter_by(etud=etud):
|
||||||
|
# self.validations_by_niveau[validation_rcue.niveau().id].append(
|
||||||
|
# validation_rcue
|
||||||
|
# )
|
||||||
|
# self.validation_by_niveau = {
|
||||||
|
# niveau_id: sorted(
|
||||||
|
# validations, key=lambda v: sco_codes.BUT_CODES_ORDERED[v.code]
|
||||||
|
# )[0]
|
||||||
|
# for niveau_id, validations in self.validations_by_niveau.items()
|
||||||
|
# }
|
||||||
|
# "{ niveau_id : meilleure validation pour ce niveau }"
|
||||||
|
|
||||||
|
self.validation_par_competence_et_annee = {}
|
||||||
|
"{ competence_id : { 'BUT1' : validation_rcue, ... } }"
|
||||||
|
for validation_rcue in ApcValidationRCUE.query.filter_by(etud=etud):
|
||||||
|
niveau = validation_rcue.niveau()
|
||||||
|
if not niveau.competence.id in self.validation_par_competence_et_annee:
|
||||||
|
self.validation_par_competence_et_annee[niveau.competence.id] = {}
|
||||||
|
previous_validation = self.validation_par_competence_et_annee.get(
|
||||||
|
niveau.competence.id
|
||||||
|
)
|
||||||
|
# prend la "meilleure" validation
|
||||||
|
if (not previous_validation) or (
|
||||||
|
sco_codes.BUT_CODES_ORDERED[validation_rcue.code]
|
||||||
|
> sco_codes.BUT_CODES_ORDERED[previous_validation.code]
|
||||||
|
):
|
||||||
|
self.validation_par_competence_et_annee[niveau.competence.id][
|
||||||
|
niveau.annee
|
||||||
|
] = validation_rcue
|
||||||
|
|
||||||
|
self.competences = {
|
||||||
|
competence.id: competence
|
||||||
|
for competence in (
|
||||||
|
self.parcour.query_competences()
|
||||||
|
if self.parcour
|
||||||
|
else self.formation.referentiel_competence.get_competences_tronc_commun()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"cache { competence_id : competence }"
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
competence_id : {
|
||||||
|
annee : meilleure_validation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
competence.id: {
|
||||||
|
annee: {
|
||||||
|
self.validation_par_competence_et_annee.get(competence.id, {}).get(
|
||||||
|
annee
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for annee in ("BUT1", "BUT2", "BUT3")
|
||||||
|
}
|
||||||
|
for competence in self.competences.values()
|
||||||
|
}
|
||||||
|
@ -94,9 +94,10 @@ class ApcReferentielCompetences(db.Model, XMLModel):
|
|||||||
return ""
|
return ""
|
||||||
return self.version_orebut.split()[0]
|
return self.version_orebut.split()[0]
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self, parcours: list["ApcParcours"] = None, with_app_critiques=True):
|
||||||
"""Représentation complète du ref. de comp.
|
"""Représentation complète du ref. de comp.
|
||||||
comme un dict.
|
comme un dict.
|
||||||
|
Si parcours est une liste de parcours, restreint l'export aux parcours listés.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
"dept_id": self.dept_id,
|
"dept_id": self.dept_id,
|
||||||
@ -111,8 +112,14 @@ class ApcReferentielCompetences(db.Model, XMLModel):
|
|||||||
if self.scodoc_date_loaded
|
if self.scodoc_date_loaded
|
||||||
else "",
|
else "",
|
||||||
"scodoc_orig_filename": self.scodoc_orig_filename,
|
"scodoc_orig_filename": self.scodoc_orig_filename,
|
||||||
"competences": {x.titre: x.to_dict() for x in self.competences},
|
"competences": {
|
||||||
"parcours": {x.code: x.to_dict() for x in self.parcours},
|
x.titre: x.to_dict(with_app_critiques=with_app_critiques)
|
||||||
|
for x in self.competences
|
||||||
|
},
|
||||||
|
"parcours": {
|
||||||
|
x.code: x.to_dict()
|
||||||
|
for x in (self.parcours if parcours is None else parcours)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_niveaux_by_parcours(
|
def get_niveaux_by_parcours(
|
||||||
@ -174,6 +181,27 @@ class ApcReferentielCompetences(db.Model, XMLModel):
|
|||||||
niveaux_by_parcours_no_tc["TC"] = niveaux_tc
|
niveaux_by_parcours_no_tc["TC"] = niveaux_tc
|
||||||
return parcours, niveaux_by_parcours_no_tc
|
return parcours, niveaux_by_parcours_no_tc
|
||||||
|
|
||||||
|
def get_competences_tronc_commun(self) -> list["ApcCompetence"]:
|
||||||
|
"""Liste des compétences communes à tous les parcours du référentiel."""
|
||||||
|
parcours = self.parcours.all()
|
||||||
|
if not parcours:
|
||||||
|
return []
|
||||||
|
|
||||||
|
ids = set.intersection(
|
||||||
|
*[
|
||||||
|
{competence.id for competence in parcour.query_competences()}
|
||||||
|
for parcour in parcours
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return sorted(
|
||||||
|
[
|
||||||
|
competence
|
||||||
|
for competence in parcours[0].query_competences()
|
||||||
|
if competence.id in ids
|
||||||
|
],
|
||||||
|
key=lambda c: c.numero or 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ApcCompetence(db.Model, XMLModel):
|
class ApcCompetence(db.Model, XMLModel):
|
||||||
"Compétence"
|
"Compétence"
|
||||||
@ -215,7 +243,7 @@ class ApcCompetence(db.Model, XMLModel):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<ApcCompetence {self.id} {self.titre!r}>"
|
return f"<ApcCompetence {self.id} {self.titre!r}>"
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self, with_app_critiques=True):
|
||||||
"repr dict recursive sur situations, composantes, niveaux"
|
"repr dict recursive sur situations, composantes, niveaux"
|
||||||
return {
|
return {
|
||||||
"id_orebut": self.id_orebut,
|
"id_orebut": self.id_orebut,
|
||||||
@ -227,7 +255,10 @@ class ApcCompetence(db.Model, XMLModel):
|
|||||||
"composantes_essentielles": [
|
"composantes_essentielles": [
|
||||||
x.to_dict() for x in self.composantes_essentielles
|
x.to_dict() for x in self.composantes_essentielles
|
||||||
],
|
],
|
||||||
"niveaux": {x.annee: x.to_dict() for x in self.niveaux},
|
"niveaux": {
|
||||||
|
x.annee: x.to_dict(with_app_critiques=with_app_critiques)
|
||||||
|
for x in self.niveaux
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def to_dict_bul(self) -> dict:
|
def to_dict_bul(self) -> dict:
|
||||||
@ -293,13 +324,15 @@ class ApcNiveau(db.Model, XMLModel):
|
|||||||
return f"""<{self.__class__.__name__} {self.id} ordre={self.ordre!r} annee={
|
return f"""<{self.__class__.__name__} {self.id} ordre={self.ordre!r} annee={
|
||||||
self.annee!r} {self.competence!r}>"""
|
self.annee!r} {self.competence!r}>"""
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self, with_app_critiques=True):
|
||||||
"as a dict, recursif sur les AC"
|
"as a dict, recursif (ou non) sur les AC"
|
||||||
return {
|
return {
|
||||||
"libelle": self.libelle,
|
"libelle": self.libelle,
|
||||||
"annee": self.annee,
|
"annee": self.annee,
|
||||||
"ordre": self.ordre,
|
"ordre": self.ordre,
|
||||||
"app_critiques": {x.code: x.to_dict() for x in self.app_critiques},
|
"app_critiques": {x.code: x.to_dict() for x in self.app_critiques}
|
||||||
|
if with_app_critiques
|
||||||
|
else {},
|
||||||
}
|
}
|
||||||
|
|
||||||
def to_dict_bul(self):
|
def to_dict_bul(self):
|
||||||
@ -471,6 +504,14 @@ class ApcParcours(db.Model, XMLModel):
|
|||||||
d["annees"] = {x.ordre: x.to_dict() for x in self.annees}
|
d["annees"] = {x.ordre: x.to_dict() for x in self.annees}
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def query_competences(self) -> flask_sqlalchemy.BaseQuery:
|
||||||
|
"Les compétences associées à ce parcours"
|
||||||
|
return (
|
||||||
|
ApcCompetence.query.join(ApcParcoursNiveauCompetence, ApcAnneeParcours)
|
||||||
|
.filter_by(parcours_id=self.id)
|
||||||
|
.order_by(ApcCompetence.numero)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ApcAnneeParcours(db.Model, XMLModel):
|
class ApcAnneeParcours(db.Model, XMLModel):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
@ -76,6 +76,12 @@ class ApcValidationRCUE(db.Model):
|
|||||||
# Par convention, il est donné par la seconde UE
|
# Par convention, il est donné par la seconde UE
|
||||||
return self.ue2.niveau_competence
|
return self.ue2.niveau_competence
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
"as a dict"
|
||||||
|
d = dict(self.__dict__)
|
||||||
|
d.pop("_sa_instance_state", None)
|
||||||
|
return d
|
||||||
|
|
||||||
def to_dict_bul(self) -> dict:
|
def to_dict_bul(self) -> dict:
|
||||||
"Export dict pour bulletins: le code et le niveau de compétence"
|
"Export dict pour bulletins: le code et le niveau de compétence"
|
||||||
niveau = self.niveau()
|
niveau = self.niveau()
|
||||||
|
@ -30,14 +30,15 @@
|
|||||||
Fiche description d'un étudiant et de son parcours
|
Fiche description d'un étudiant et de son parcours
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from flask import abort, url_for, g, request
|
from flask import abort, url_for, g, render_template, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log
|
||||||
from app.but import jury_but_view
|
from app.but import cursus_but, jury_but_view
|
||||||
from app.models.etudiants import make_etud_args
|
from app.models.etudiants import Identite, make_etud_args
|
||||||
|
from app.models.formsemestre import FormSemestre
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import htmlutils
|
from app.scodoc import htmlutils
|
||||||
from app.scodoc import sco_archives_etud
|
from app.scodoc import sco_archives_etud
|
||||||
@ -169,11 +170,12 @@ def ficheEtud(etudid=None):
|
|||||||
if not etuds:
|
if not etuds:
|
||||||
log(f"ficheEtud: etudid={etudid!r} request.args={request.args!r}")
|
log(f"ficheEtud: etudid={etudid!r} request.args={request.args!r}")
|
||||||
raise ScoValueError("Étudiant inexistant !")
|
raise ScoValueError("Étudiant inexistant !")
|
||||||
etud = etuds[0]
|
etud_ = etuds[0] # transition: etud_ à éliminer et remplacer par etud
|
||||||
etudid = etud["etudid"]
|
etudid = etud_["etudid"]
|
||||||
sco_etud.fill_etuds_info([etud])
|
etud = Identite.query.get(etudid)
|
||||||
|
sco_etud.fill_etuds_info([etud_])
|
||||||
#
|
#
|
||||||
info = etud
|
info = etud_
|
||||||
info["ScoURL"] = scu.ScoURL()
|
info["ScoURL"] = scu.ScoURL()
|
||||||
info["authuser"] = authuser
|
info["authuser"] = authuser
|
||||||
info["info_naissance"] = info["date_naissance"]
|
info["info_naissance"] = info["date_naissance"]
|
||||||
@ -181,7 +183,7 @@ def ficheEtud(etudid=None):
|
|||||||
info["info_naissance"] += " à " + info["lieu_naissance"]
|
info["info_naissance"] += " à " + info["lieu_naissance"]
|
||||||
if info["dept_naissance"]:
|
if info["dept_naissance"]:
|
||||||
info["info_naissance"] += f" ({info['dept_naissance']})"
|
info["info_naissance"] += f" ({info['dept_naissance']})"
|
||||||
info["etudfoto"] = sco_photos.etud_photo_html(etud)
|
info["etudfoto"] = sco_photos.etud_photo_html(etud_)
|
||||||
if (
|
if (
|
||||||
(not info["domicile"])
|
(not info["domicile"])
|
||||||
and (not info["codepostaldomicile"])
|
and (not info["codepostaldomicile"])
|
||||||
@ -206,7 +208,7 @@ def ficheEtud(etudid=None):
|
|||||||
info["emaillink"] = ", ".join(
|
info["emaillink"] = ", ".join(
|
||||||
[
|
[
|
||||||
'<a class="stdlink" href="mailto:%s">%s</a>' % (m, m)
|
'<a class="stdlink" href="mailto:%s">%s</a>' % (m, m)
|
||||||
for m in [etud["email"], etud["emailperso"]]
|
for m in [etud_["email"], etud_["emailperso"]]
|
||||||
if m
|
if m
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -277,7 +279,7 @@ def ficheEtud(etudid=None):
|
|||||||
sem_info[sem["formsemestre_id"]] = grlink
|
sem_info[sem["formsemestre_id"]] = grlink
|
||||||
|
|
||||||
if info["sems"]:
|
if info["sems"]:
|
||||||
Se = sco_cursus.get_situation_etud_cursus(etud, info["last_formsemestre_id"])
|
Se = sco_cursus.get_situation_etud_cursus(etud_, info["last_formsemestre_id"])
|
||||||
info["liste_inscriptions"] = formsemestre_recap_parcours_table(
|
info["liste_inscriptions"] = formsemestre_recap_parcours_table(
|
||||||
Se,
|
Se,
|
||||||
etudid,
|
etudid,
|
||||||
@ -454,6 +456,18 @@ def ficheEtud(etudid=None):
|
|||||||
# raccordement provisoire pour juillet 2022, avant refonte complète de cette fiche...
|
# raccordement provisoire pour juillet 2022, avant refonte complète de cette fiche...
|
||||||
info["but_infos_mkup"] = jury_but_view.infos_fiche_etud_html(etudid)
|
info["but_infos_mkup"] = jury_but_view.infos_fiche_etud_html(etudid)
|
||||||
|
|
||||||
|
# XXX dev
|
||||||
|
info["but_cursus_mkup"] = ""
|
||||||
|
if info["sems"]:
|
||||||
|
last_sem = FormSemestre.query.get_or_404(info["sems"][-1]["formsemestre_id"])
|
||||||
|
if last_sem.formation.is_apc():
|
||||||
|
but_cursus = cursus_but.EtudCursusBUT(etud, last_sem.formation)
|
||||||
|
info["but_cursus_mkup"] = render_template(
|
||||||
|
"but/cursus_etud.j2",
|
||||||
|
cursus=but_cursus,
|
||||||
|
scu=scu,
|
||||||
|
)
|
||||||
|
|
||||||
tmpl = """<div class="menus_etud">%(menus_etud)s</div>
|
tmpl = """<div class="menus_etud">%(menus_etud)s</div>
|
||||||
<div class="ficheEtud" id="ficheEtud"><table>
|
<div class="ficheEtud" id="ficheEtud"><table>
|
||||||
<tr><td>
|
<tr><td>
|
||||||
@ -488,6 +502,8 @@ def ficheEtud(etudid=None):
|
|||||||
|
|
||||||
%(but_infos_mkup)s
|
%(but_infos_mkup)s
|
||||||
|
|
||||||
|
%(but_cursus_mkup)s
|
||||||
|
|
||||||
<div class="ficheadmission">
|
<div class="ficheadmission">
|
||||||
%(adm_data)s
|
%(adm_data)s
|
||||||
|
|
||||||
@ -524,7 +540,11 @@ def ficheEtud(etudid=None):
|
|||||||
"""
|
"""
|
||||||
header = html_sco_header.sco_header(
|
header = html_sco_header.sco_header(
|
||||||
page_title="Fiche étudiant %(prenom)s %(nom)s" % info,
|
page_title="Fiche étudiant %(prenom)s %(nom)s" % info,
|
||||||
cssstyles=["libjs/jQuery-tagEditor/jquery.tag-editor.css", "css/jury_but.css"],
|
cssstyles=[
|
||||||
|
"libjs/jQuery-tagEditor/jquery.tag-editor.css",
|
||||||
|
"css/jury_but.css",
|
||||||
|
"css/cursus_but.css",
|
||||||
|
],
|
||||||
javascripts=[
|
javascripts=[
|
||||||
"libjs/jinplace-1.2.1.min.js",
|
"libjs/jinplace-1.2.1.min.js",
|
||||||
"js/ue_list.js",
|
"js/ue_list.js",
|
||||||
|
42
app/static/css/cursus_but.css
Normal file
42
app/static/css/cursus_but.css
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/* Affichage cursus BUT étudiant (sur sa fiche) */
|
||||||
|
|
||||||
|
|
||||||
|
.cursus_but {
|
||||||
|
margin-left: 32px;
|
||||||
|
display: inline-grid;
|
||||||
|
grid-template-columns: repeat(4, auto);
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursus_but>* {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 0px;
|
||||||
|
|
||||||
|
background: #FFF;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursus_but>div.cb_head {
|
||||||
|
background: rgb(242, 242, 238);
|
||||||
|
border: none;
|
||||||
|
border-radius: 0px;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.cb_titre_competence {
|
||||||
|
background: #09c !important;
|
||||||
|
color: #FFF;
|
||||||
|
padding: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.code_rcue {
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
position: relative;
|
||||||
|
}
|
@ -1,24 +1,27 @@
|
|||||||
:host{
|
:host {
|
||||||
font-family: Verdana;
|
font-family: Verdana;
|
||||||
background: #222;
|
background: rgb(14, 5, 73);
|
||||||
display: block;
|
display: block;
|
||||||
padding: 12px 32px;
|
padding: 12px 32px;
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
h1{
|
|
||||||
|
h1 {
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************/
|
/**********************/
|
||||||
/* Zone parcours */
|
/* Zone parcours */
|
||||||
/**********************/
|
/**********************/
|
||||||
.parcours{
|
.parcours {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
.parcours>div{
|
|
||||||
|
.parcours>div {
|
||||||
background: #09c;
|
background: #09c;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -29,65 +32,89 @@ h1{
|
|||||||
transition: 0.1s;
|
transition: 0.1s;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.parcours>div:hover,
|
.parcours>div:hover,
|
||||||
.competence>div:hover{
|
.competence>div:hover {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
.parcours>.focus{
|
|
||||||
|
.parcours>.focus {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************/
|
/**********************/
|
||||||
/* Zone compétences */
|
/* Zone compétences */
|
||||||
/**********************/
|
/**********************/
|
||||||
.competences{
|
.competences {
|
||||||
display: grid;
|
display: grid;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
row-gap: 4px;
|
row-gap: 4px;
|
||||||
}
|
}
|
||||||
.competences>div{
|
|
||||||
|
.competences>div {
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: var(--competence-size);
|
width: var(--competence-size);
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comp1{background:#a44}
|
.comp1 {
|
||||||
.comp2{background:#84a}
|
background: #a44
|
||||||
.comp3{background:#a84}
|
}
|
||||||
.comp4{background:#8a4}
|
|
||||||
.comp5{background:#4a8}
|
|
||||||
.comp6{background:#48a}
|
|
||||||
|
|
||||||
.competences>.focus{
|
.comp2 {
|
||||||
|
background: #84a
|
||||||
|
}
|
||||||
|
|
||||||
|
.comp3 {
|
||||||
|
background: #a84
|
||||||
|
}
|
||||||
|
|
||||||
|
.comp4 {
|
||||||
|
background: #8a4
|
||||||
|
}
|
||||||
|
|
||||||
|
.comp5 {
|
||||||
|
background: #4a8
|
||||||
|
}
|
||||||
|
|
||||||
|
.comp6 {
|
||||||
|
background: #48a
|
||||||
|
}
|
||||||
|
|
||||||
|
.competences>.focus {
|
||||||
outline: 2px solid;
|
outline: 2px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************/
|
/**********************/
|
||||||
/* Zone AC */
|
/* Zone AC */
|
||||||
/**********************/
|
/**********************/
|
||||||
h2{
|
h2 {
|
||||||
display: table;
|
display: table;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
border-radius: 16px 0;
|
border-radius: 16px 0;
|
||||||
}
|
}
|
||||||
.ACs{
|
|
||||||
|
.ACs {
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
.AC li{
|
|
||||||
|
.AC li {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto 1fr;
|
grid-template-columns: auto 1fr;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
border-bottom: 1px solid;
|
border-bottom: 1px solid;
|
||||||
}
|
}
|
||||||
.AC li>div:nth-child(1){
|
|
||||||
|
.AC li>div:nth-child(1) {
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
.AC li>div:nth-child(2){
|
|
||||||
|
.AC li>div:nth-child(2) {
|
||||||
padding-bottom: 2px;
|
padding-bottom: 2px;
|
||||||
}
|
}
|
26
app/templates/but/cursus_etud.j2
Normal file
26
app/templates/but/cursus_etud.j2
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{# Affichage cursus BUT fiche étudiant #}
|
||||||
|
|
||||||
|
<div class="cursus_but">
|
||||||
|
<div class="cb_head"></div>
|
||||||
|
<div class="cb_head">BUT 1</div>
|
||||||
|
<div class="cb_head">BUT 2</div>
|
||||||
|
<div class="cb_head">BUT 3</div>
|
||||||
|
{% for competence_id in cursus.to_dict() %}
|
||||||
|
<div class="cb_titre_competence">{{ cursus.competences[competence_id].titre }}</div>
|
||||||
|
{% for annee in ('BUT1', 'BUT2', 'BUT3') %}
|
||||||
|
{% set validation = cursus.validation_par_competence_et_annee.get(competence_id, {}).get(annee) %}
|
||||||
|
<div>
|
||||||
|
{% if validation %}
|
||||||
|
<div class="code_rcue with_scoplement">
|
||||||
|
<div>{{validation.code}}</div>
|
||||||
|
<div class="scoplement">Validé le {{
|
||||||
|
validation.date.strftime("%d/%m/%Y à %H:%M")
|
||||||
|
}}</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{%endif%}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
19
scodoc.py
19
scodoc.py
@ -33,6 +33,13 @@ from app.models import Identite
|
|||||||
from app.models import ModuleImpl, ModuleImplInscription
|
from app.models import ModuleImpl, ModuleImplInscription
|
||||||
from app.models import Partition
|
from app.models import Partition
|
||||||
from app.models import ScolarFormSemestreValidation
|
from app.models import ScolarFormSemestreValidation
|
||||||
|
from app.models.but_refcomp import (
|
||||||
|
ApcCompetence,
|
||||||
|
ApcNiveau,
|
||||||
|
ApcParcours,
|
||||||
|
ApcReferentielCompetences,
|
||||||
|
)
|
||||||
|
from app.models.but_validations import ApcValidationAnnee, ApcValidationRCUE
|
||||||
from app.models.evaluations import Evaluation
|
from app.models.evaluations import Evaluation
|
||||||
from app.scodoc.sco_logos import make_logo_local
|
from app.scodoc.sco_logos import make_logo_local
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
@ -57,6 +64,12 @@ def make_shell_context():
|
|||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
"ApcCompetence": ApcCompetence,
|
||||||
|
"ApcNiveau": ApcNiveau,
|
||||||
|
"ApcParcours": ApcParcours,
|
||||||
|
"ApcReferentielCompetences": ApcReferentielCompetences,
|
||||||
|
"ApcValidationRCUE": ApcValidationRCUE,
|
||||||
|
"ApcValidationAnnee": ApcValidationAnnee,
|
||||||
"ctx": app.test_request_context(),
|
"ctx": app.test_request_context(),
|
||||||
"current_app": flask.current_app,
|
"current_app": flask.current_app,
|
||||||
"current_user": current_user,
|
"current_user": current_user,
|
||||||
@ -71,21 +84,21 @@ def make_shell_context():
|
|||||||
"login_user": login_user,
|
"login_user": login_user,
|
||||||
"logout_user": logout_user,
|
"logout_user": logout_user,
|
||||||
"mapp": mapp,
|
"mapp": mapp,
|
||||||
"models": models,
|
|
||||||
"Matiere": Matiere,
|
"Matiere": Matiere,
|
||||||
|
"models": models,
|
||||||
"Module": Module,
|
"Module": Module,
|
||||||
"ModuleImpl": ModuleImpl,
|
"ModuleImpl": ModuleImpl,
|
||||||
"ModuleImplInscription": ModuleImplInscription,
|
"ModuleImplInscription": ModuleImplInscription,
|
||||||
"Partition": Partition,
|
|
||||||
"ndb": ndb,
|
"ndb": ndb,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
"np": np,
|
"np": np,
|
||||||
|
"Partition": Partition,
|
||||||
"pd": pd,
|
"pd": pd,
|
||||||
"Permission": Permission,
|
"Permission": Permission,
|
||||||
"pp": pp,
|
"pp": pp,
|
||||||
"Role": Role,
|
|
||||||
"res_sem": res_sem,
|
"res_sem": res_sem,
|
||||||
"ResultatsSemestreBUT": ResultatsSemestreBUT,
|
"ResultatsSemestreBUT": ResultatsSemestreBUT,
|
||||||
|
"Role": Role,
|
||||||
"scolar": scolar,
|
"scolar": scolar,
|
||||||
"ScolarFormSemestreValidation": ScolarFormSemestreValidation,
|
"ScolarFormSemestreValidation": ScolarFormSemestreValidation,
|
||||||
"ScolarNews": models.ScolarNews,
|
"ScolarNews": models.ScolarNews,
|
||||||
|
Loading…
Reference in New Issue
Block a user