Améliorer les couleurs et la vue du calendrier
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run

This commit is contained in:
root 2026-08-20 20:25:52 +00:00
parent 3527adb175
commit 84b4f1326c
2 changed files with 44 additions and 16 deletions

View file

@ -23,10 +23,22 @@ def index():
from datetime import date, timedelta from datetime import date, timedelta
from calendar import monthrange from calendar import monthrange
from ..core.services.planning_service import PlanningService from ..core.services.planning_service import PlanningService
from ..core.models.planning import PlanningDay, PlanningItem from ..core.models.planning import PlanningDay, PlanningItem, ClosureWorkDay
from ..core.models.settings import AppSettings
from ..core.services.planning_service import get_french_public_holidays
# Récupérer l'année demandée ou année courante # Récupérer l'année demandée ou année courante
mode = request.args.get('mode')
saved_mode = AppSettings.get(f'planning_calendar_mode_{current_user.id}', 'calendar')
if mode not in ('calendar', 'school'):
mode = saved_mode if saved_mode in ('calendar', 'school') else 'calendar'
else:
AppSettings.set(f'planning_calendar_mode_{current_user.id}', mode)
year = request.args.get('year', date.today().year, type=int) year = request.args.get('year', date.today().year, type=int)
if mode == 'school' and 'year' not in request.args:
year = date.today().year if date.today().month >= 9 else date.today().year - 1
display_start = date(year, 9, 1) if mode == 'school' else date(year, 1, 1)
display_end = date(year + 1, 8, 31) if mode == 'school' else date(year, 12, 31)
# Préparer les données du calendrier. Le calendrier principal est la # Préparer les données du calendrier. Le calendrier principal est la
# source unique : il rassemble les interventions et les échéances # source unique : il rassemble les interventions et les échéances
@ -37,9 +49,13 @@ def index():
# Récupérer les vacances # Récupérer les vacances
closures = CollegeClosure.query.filter( closures = CollegeClosure.query.filter(
CollegeClosure.start_date <= date(year, 12, 31), CollegeClosure.start_date <= display_end,
CollegeClosure.end_date >= date(year, 1, 1) CollegeClosure.end_date >= display_start
).all() ).all()
permanence_dates = {item.work_date for item in ClosureWorkDay.query.filter(ClosureWorkDay.work_date >= display_start, ClosureWorkDay.work_date <= display_end).all()}
holiday_dates = {item[0] for item in get_french_public_holidays(year)}
if mode == 'school':
holiday_dates |= {item[0] for item in get_french_public_holidays(year + 1)}
# Fonction pour vérifier si une date est en vacances # Fonction pour vérifier si une date est en vacances
def is_vacation(d): def is_vacation(d):
@ -50,13 +66,13 @@ def index():
# Récupérer les congés personnels # Récupérer les congés personnels
leaves = TechnicianAvailability.query.filter( leaves = TechnicianAvailability.query.filter(
TechnicianAvailability.date >= date(year, 1, 1), TechnicianAvailability.date >= display_start,
TechnicianAvailability.date <= date(year, 12, 31) TechnicianAvailability.date <= display_end
).all() ).all()
leave_dates = {l.date: l for l in leaves} leave_dates = {l.date: l for l in leaves}
year_start = date(year, 1, 1) year_start = display_start
year_end = date(year, 12, 31) year_end = display_end
terminal_intervention_statuses = ('terminee', 'cloturee', 'annulee', 'ignoree') terminal_intervention_statuses = ('terminee', 'cloturee', 'annulee', 'ignoree')
interventions = Intervention.query.filter( interventions = Intervention.query.filter(
Intervention.scheduled_date >= year_start, Intervention.scheduled_date >= year_start,
@ -108,18 +124,20 @@ def index():
'color': 'info', 'color': 'info',
}) })
for month in range(1, 13): month_order = list(range(9, 13)) + list(range(1, 9)) if mode == 'school' else list(range(1, 13))
for month in month_order:
actual_year = year if mode != 'school' or month >= 9 else year + 1
# Nombre de jours dans le mois # Nombre de jours dans le mois
days_in_month = monthrange(year, month)[1] days_in_month = monthrange(actual_year, month)[1]
# Jour de la semaine du premier jour (0=lundi, 6=dimanche) # Jour de la semaine du premier jour (0=lundi, 6=dimanche)
first_weekday = date(year, month, 1).weekday() first_weekday = date(actual_year, month, 1).weekday()
weeks = [] weeks = []
week = [None] * first_weekday # Cases vides avant le 1er jour week = [None] * first_weekday # Cases vides avant le 1er jour
for day in range(1, days_in_month + 1): for day in range(1, days_in_month + 1):
d = date(year, month, day) d = date(actual_year, month, day)
vacation = is_vacation(d) vacation = is_vacation(d)
leave = leave_dates.get(d) leave = leave_dates.get(d)
weekday = d.weekday() weekday = d.weekday()
@ -130,6 +148,8 @@ def index():
'is_weekend': weekday >= 5, 'is_weekend': weekday >= 5,
'is_vacation': vacation is not None, 'is_vacation': vacation is not None,
'vacation_name': vacation, 'vacation_name': vacation,
'is_holiday': d in holiday_dates,
'is_permanence': d in permanence_dates,
'is_leave': leave is not None, 'is_leave': leave is not None,
'leave_type': leave.availability_type if leave else None, 'leave_type': leave.availability_type if leave else None,
'events': events_by_date.get(d, []), 'events': events_by_date.get(d, []),
@ -145,6 +165,7 @@ def index():
months_data.append({ months_data.append({
'name': months_names[month - 1], 'name': months_names[month - 1],
'year': actual_year,
'weeks': weeks 'weeks': weeks
}) })
@ -158,6 +179,7 @@ def index():
return render_template('planning/calendar.html', return render_template('planning/calendar.html',
year=year, year=year,
mode=mode,
months=months_data, months=months_data,
stats=stats stats=stats
) )

View file

@ -6,7 +6,7 @@
<div class="row mb-4"> <div class="row mb-4">
<div class="col-12"> <div class="col-12">
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
<h1><i class="bi bi-calendar3 me-2"></i>Planning {{ year }}</h1> <h1><i class="bi bi-calendar3 me-2"></i>Planning {% if mode == 'school' %}{{ year }}{{ year + 1 }}{% else %}{{ year }}{% endif %}</h1>
<div> <div>
<a href="{{ url_for('planning.index', year=year-1) }}" class="btn btn-outline-secondary"> <a href="{{ url_for('planning.index', year=year-1) }}" class="btn btn-outline-secondary">
<i class="bi bi-chevron-left"></i> {{ year-1 }} <i class="bi bi-chevron-left"></i> {{ year-1 }}
@ -14,6 +14,7 @@
<a href="{{ url_for('planning.index', year=year+1) }}" class="btn btn-outline-secondary"> <a href="{{ url_for('planning.index', year=year+1) }}" class="btn btn-outline-secondary">
{{ year+1 }} <i class="bi bi-chevron-right"></i> {{ year+1 }} <i class="bi bi-chevron-right"></i>
</a> </a>
<div class="btn-group ms-2"><a href="{{ url_for('planning.index', year=year, mode='calendar') }}" class="btn btn-outline-primary {% if mode == 'calendar' %}active{% endif %}">Année civile</a><a href="{{ url_for('planning.index', year=year, mode='school') }}" class="btn btn-outline-primary {% if mode == 'school' %}active{% endif %}">Année scolaire</a></div>
</div> </div>
</div> </div>
</div> </div>
@ -61,7 +62,8 @@
<div class="d-flex flex-wrap gap-3"> <div class="d-flex flex-wrap gap-3">
<span><span class="badge bg-secondary">Week-end</span></span> <span><span class="badge bg-secondary">Week-end</span></span>
<span><span class="badge bg-dark">Vacances</span></span> <span><span class="badge bg-dark">Vacances</span></span>
<span><span class="badge bg-warning text-dark">Congé</span></span> <span><span class="badge bg-warning text-dark">Jour férié</span></span>
<span><span class="badge" style="background:#b7e4c7;color:#14532d;">Permanence</span></span>
<span><span class="badge bg-primary">Intervention</span></span> <span><span class="badge bg-primary">Intervention</span></span>
<span><span class="badge bg-info text-dark">Échéance préventive</span></span> <span><span class="badge bg-info text-dark">Échéance préventive</span></span>
</div> </div>
@ -76,7 +78,7 @@
<div class="col-lg-4 col-md-6 mb-4"> <div class="col-lg-4 col-md-6 mb-4">
<div class="card"> <div class="card">
<div class="card-header text-center"> <div class="card-header text-center">
<strong>{{ month.name }}</strong> <strong>{{ month.name }} {{ month.year }}</strong>
</div> </div>
<div class="card-body p-1"> <div class="card-body p-1">
<table class="table table-sm table-bordered mb-0" style="font-size: 0.8rem;"> <table class="table table-sm table-bordered mb-0" style="font-size: 0.8rem;">
@ -95,14 +97,18 @@
<td class="bg-light"></td> <td class="bg-light"></td>
{% else %} {% else %}
{% set td_class = '' %} {% set td_class = '' %}
{% if day_info.is_vacation %} {% if day_info.is_permanence %}
{% set td_class = 'table-success' %}
{% elif day_info.is_holiday %}
{% set td_class = 'table-warning' %}
{% elif day_info.is_vacation %}
{% set td_class = 'table-dark' %} {% set td_class = 'table-dark' %}
{% elif day_info.is_leave %} {% elif day_info.is_leave %}
{% set td_class = 'table-warning' %} {% set td_class = 'table-warning' %}
{% elif day_info.is_weekend %} {% elif day_info.is_weekend %}
{% set td_class = 'table-secondary' %} {% set td_class = 'table-secondary' %}
{% endif %} {% endif %}
<td class="{{ td_class }} text-center"> <td class="{{ td_class }} text-center" title="{% if day_info.is_permanence %}Permanence{% elif day_info.is_holiday %}Jour férié{% elif day_info.vacation_name %}{{ day_info.vacation_name }}{% endif %}">
{% set date_str = day_info.date.strftime('%Y-%m-%d') %} {% set date_str = day_info.date.strftime('%Y-%m-%d') %}
<a href="{{ url_for('planning.day', date_str=date_str) }}" <a href="{{ url_for('planning.day', date_str=date_str) }}"
class="text-decoration-none {{ 'text-white' if td_class else '' }}" class="text-decoration-none {{ 'text-white' if td_class else '' }}"