2026-08-23 12:13:47 +02:00
|
|
|
|
{% extends "base.html" %}
|
|
|
|
|
|
{% block title %}Ma journée{% endblock %}
|
|
|
|
|
|
{% block content %}
|
|
|
|
|
|
<div class="container-fluid py-3">
|
|
|
|
|
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<h1 class="h3 mb-1"><i class="bi bi-calendar2-week"></i> Ma journée</h1>
|
|
|
|
|
|
<p class="text-muted mb-0">Une proposition de tâches pour le {{ target_date.strftime('%d/%m/%Y') }}. Vous gardez la main sur les changements.</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="btn-group" role="group" aria-label="Navigation entre les jours">
|
|
|
|
|
|
<a class="btn btn-outline-secondary" href="{{ url_for('planning.my_day', date=previous_date.isoformat()) }}">← Jour précédent</a>
|
|
|
|
|
|
<a class="btn btn-outline-primary" href="{{ url_for('planning.my_day') }}">Aujourd'hui</a>
|
|
|
|
|
|
<a class="btn btn-outline-secondary" href="{{ url_for('planning.my_day', date=next_date.isoformat()) }}">Jour suivant →</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{% if not hours_configured %}
|
|
|
|
|
|
<div class="alert alert-warning" role="alert">
|
|
|
|
|
|
<strong>Horaires de travail non configurés pour cette journée.</strong>
|
|
|
|
|
|
La proposition automatique reste désactivée. Configurez les horaires du
|
|
|
|
|
|
technicien ou utilisez la planification manuelle existante.
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
|
|
{% if candidates %}
|
2026-08-23 13:05:31 +02:00
|
|
|
|
<div class="d-flex flex-wrap gap-2 mb-3" aria-label="Résumé de la journée">
|
|
|
|
|
|
<span class="badge text-bg-primary">{{ candidates|length }} tâche(s)</span>
|
|
|
|
|
|
<span class="badge text-bg-warning">{{ candidates|selectattr('status', 'equalto', 'à replanifier')|list|length }} à replanifier</span>
|
|
|
|
|
|
<span class="badge text-bg-danger">{{ candidates|selectattr('task_type', 'equalto', 'emergency')|list|length }} urgence(s)</span>
|
|
|
|
|
|
<span class="badge text-bg-danger">{{ candidates|selectattr('status', 'equalto', 'conflit')|list|length }} conflit(s)</span>
|
|
|
|
|
|
</div>
|
2026-08-23 12:13:47 +02:00
|
|
|
|
<div class="timeline d-grid gap-3" aria-label="Tâches proposées">
|
|
|
|
|
|
{% for item in candidates %}
|
|
|
|
|
|
<article class="card shadow-sm border-start border-{{ 'danger' if item.task_type == 'emergency' else 'primary' }} border-4">
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<div class="d-flex flex-wrap justify-content-between gap-2">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="text-muted small">
|
|
|
|
|
|
{% if item.proposed_start and item.proposed_end %}
|
|
|
|
|
|
{{ item.proposed_start.strftime('%H:%M') }} – {{ item.proposed_end.strftime('%H:%M') }}
|
|
|
|
|
|
{% else %}Horaire à définir{% endif %}
|
|
|
|
|
|
· {{ item.duration_minutes }} min
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<h2 class="h5 mb-1 mt-1">{{ item.title }}</h2>
|
|
|
|
|
|
<div class="small text-muted">{{ item.location_label }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="text-end">
|
|
|
|
|
|
<span class="badge text-bg-secondary">{{ item.type_label }}</span>
|
|
|
|
|
|
<span class="badge text-bg-light border">{{ item.constraint_label }}</span>
|
|
|
|
|
|
<div class="small mt-1">{{ item.status|capitalize }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{% if item.explanation %}<p class="mb-0 mt-2 small"><i class="bi bi-info-circle"></i> {{ item.explanation }}</p>{% endif %}
|
2026-08-23 13:05:31 +02:00
|
|
|
|
{% set item_alternatives = alternatives.get((item.source_type, item.source_id), []) %}
|
|
|
|
|
|
{% if item_alternatives and item.status != 'conflit' %}
|
|
|
|
|
|
<details class="mt-2">
|
|
|
|
|
|
<summary class="small text-primary" style="cursor:pointer">Replanifier cette tâche</summary>
|
|
|
|
|
|
<form method="post" action="{{ url_for('planning.my_day_reschedule') }}" class="row g-2 mt-1 align-items-end">
|
|
|
|
|
|
<input type="hidden" name="source_type" value="{{ item.source_type }}">
|
|
|
|
|
|
<input type="hidden" name="source_id" value="{{ item.source_id }}">
|
|
|
|
|
|
<input type="hidden" name="date" value="{{ target_date.isoformat() }}">
|
|
|
|
|
|
<div class="col-8 col-sm-5"><label class="form-label small" for="slot-{{ item.source_type }}-{{ item.source_id }}">Créneau compatible</label>
|
|
|
|
|
|
<select class="form-select form-select-sm" id="slot-{{ item.source_type }}-{{ item.source_id }}" name="slot" required>
|
|
|
|
|
|
{% for start, end in item_alternatives %}<option value="{{ start.strftime('%H:%M') }}|{{ end.strftime('%H:%M') }}">{{ start.strftime('%H:%M') }} – {{ end.strftime('%H:%M') }}</option>{% endfor %}
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="col-auto"><button class="btn btn-sm btn-outline-primary" type="submit">Enregistrer</button></div>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</details>
|
|
|
|
|
|
{% endif %}
|
2026-08-23 12:13:47 +02:00
|
|
|
|
</div>
|
|
|
|
|
|
</article>
|
|
|
|
|
|
{% endfor %}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{% else %}
|
|
|
|
|
|
<div class="card border-0 bg-light">
|
|
|
|
|
|
<div class="card-body py-5 text-center">
|
|
|
|
|
|
<i class="bi bi-calendar-check fs-1 text-muted"></i>
|
|
|
|
|
|
<h2 class="h5 mt-3">Aucune tâche à afficher</h2>
|
|
|
|
|
|
<p class="text-muted mb-0">Les interventions, maintenances préventives et tâches administratives du jour apparaîtront ici.</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{% endblock %}
|