{% extends '@App/app.html.twig' %} {% macro avatar(employee, size = 'md') %} {% set photo = employee.photo ? employee.photo|trim : null %} {% set src = photo ? (photo starts with 'http://' or photo starts with 'https://' ? photo : asset(photo starts with '/' ? photo|slice(1) : photo)) : null %} {% if not src %}{{ employee.prenom|default('')|first|upper }}{{ employee.nom|default('')|first|upper }}{% endif %} {% endmacro %} {% macro employee_meta(employee) %} {{ employee.service ?: employee.poste ?: 'Service non renseigné' }}{% if employee.typeCollaborateur %} · {{ employee.typeCollaborateur }}{% endif %} {% endmacro %} {% import _self as health %} {% block title %}Tableau de bord santé au travail{% endblock %} {% block stylesheets %} {{ parent() }} {% endblock %} {% block page_header %}{% endblock %} {% block content %} {% set visit_statuses = { draft: ['À préparer', 'warning'], to_schedule: ['À planifier', 'warning'], scheduled: ['Planifiée', 'success'], overdue: ['En retard', 'danger'], completed: ['Terminée', 'success'], cancelled: ['Annulée', 'secondary'] } %} {% set leave_statuses = { declared: ['Déclaré', 'info'], waiting_document: ['Document manquant', 'warning'], document_received: ['Justificatif reçu', 'success'], validated: ['En cours', 'purple'], extended: ['Prolongé', 'warning'], return_pending: ['Reprise à préparer', 'info'] } %} {% set activity_labels = { medical_visit_created: 'Visite créée', medical_visit_updated: 'Visite mise à jour', medical_visit_scheduled: 'Visite planifiée', medical_visit_completed: 'Visite terminée', medical_visit_cancelled: 'Visite annulée', medical_visit_document_uploaded: 'Document téléversé', follow_up_created: 'Action de suivi créée', follow_up_completed: 'Action de suivi terminée' } %} {% set kpi_cards = [ {value: kpis.to_schedule, label: 'Visites à planifier', badge: 'À planifier', icon: 'solar:calendar-add-bold-duotone', tone: 'orange'}, {value: kpis.scheduled, label: 'Visites à venir', badge: 'Planifiées', icon: 'solar:calendar-mark-bold-duotone', tone: 'blue'}, {value: kpis.overdue, label: 'Visites en retard', badge: 'Critique', icon: 'solar:danger-triangle-bold-duotone', tone: 'red'}, {value: kpis.active_sick_leaves, label: 'Arrêts en cours', badge: 'En cours', icon: 'solar:bed-bold-duotone', tone: 'purple'}, {value: kpis.returns, label: 'Reprises à préparer', badge: 'À préparer', icon: 'solar:walking-round-bold-duotone', tone: 'teal'}, {value: kpis.missing_documents, label: 'Documents manquants', badge: 'Manquants', icon: 'solar:documents-minimalistic-bold-duotone', tone: 'amber'} ] %}
Santé au travailTableau de bord

Tableau de bord santé au travail

Suivi opérationnel des visites médicales, arrêts et reprises

{% for card in kpi_cards %}
{{ card.badge }}
{{ card.value }} {{ card.label }}
{% endfor %}

Visites médicales à traiter

{{ visits_to_handle_count }} visite{{ visits_to_handle_count > 1 ? 's' : '' }} nécessite{{ visits_to_handle_count > 1 ? 'nt' : '' }} une action

Voir tout
{% for visit in visits_to_handle %} {% set status_data = visit_statuses[visit.status]|default([visit.status, 'secondary']) %} {% set is_late = visit.status == 'overdue' or (visit.dueDate and visit.dueDate < today and visit.status not in ['completed', 'cancelled']) %} {% set filter_status = is_late ? 'overdue' : visit.status %} {% else %} {% endfor %}
SalariéTypeÉchéanceStatutPrioritéAction
{{ health.avatar(visit.salarie) }}
{{ visit.salarie }}{{ health.employee_meta(visit.salarie) }}
{{ visit.visitType.nom }} {{ visit.dueDate ? visit.dueDate|date('d/m/Y') : (visit.scheduledAt ? visit.scheduledAt|date('d/m/Y') : 'À définir') }} {{ status_data[0] }} {{ is_late ? 'Bloquante' : (visit.dueDate and visit.dueDate <= today|date_modify('+7 days') ? 'Urgente' : 'Normale') }} {{ visit.status in ['draft', 'to_schedule'] ? 'Planifier' : 'Voir' }}
Aucune visite ne nécessite d’action.
Aucune visite pour ce filtre.

Arrêts maladie en cours

{{ kpis.active_sick_leaves }} arrêt{{ kpis.active_sick_leaves > 1 ? 's' : '' }} actif{{ kpis.active_sick_leaves > 1 ? 's' : '' }} · Suivi administratif uniquement

Voir tout ({{ kpis.active_sick_leaves }})
{% for leave in active_sick_leaves %} {% set status_data = leave_statuses[leave.status]|default([leave.status, 'secondary']) %} {% set late = leave.endDate and leave.endDate < today %} {% else %}{% endfor %}
SalariéType administratifDébutFin prévueStatutAction
{{ health.avatar(leave.salarie) }}
{{ leave.salarie }}{{ health.employee_meta(leave.salarie) }}
{{ leave.isExtension ? 'Prolongation' : leave.type.nom }} {{ leave.startDate|date('d/m/Y') }} {{ leave.endDate ? leave.endDate|date('d/m/Y') : 'Non définie' }}{% if late %} dépassée{% endif %} {{ status_data[0] }} {{ late ? 'Traiter' : 'Gérer' }}
Aucun arrêt en cours.

Activité récente

Journal des actions RH santé

{% for item in recent_activity %}
{{ activity_labels[item.action]|default(item.action|replace({'_': ' '})|capitalize) }}

{{ item.message ?: 'Action enregistrée dans le dossier administratif.' }}

{% if item.user %}{{ item.user.prenom }} {{ item.user.nom }}{% else %}Système{% endif %}
{% else %}

Aucune activité récente.

{% endfor %}
{% endblock %}