{# templates/timesheet/index.html.twig #}
{% extends 'admin/baseAdmin.html.twig' %}
{% block title %}Feuille d'heures - Recherche{% endblock %}
{% block stylesheets %}
{{ parent() }}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.14/dist/css/bootstrap-select.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #4361ee;
--primary-light: #eef2ff;
--secondary-color: #3a0ca3;
--success-color: #06d6a0;
--warning-color: #ffd166;
--info-color: #118ab2;
--dark-color: #2b2d42;
--light-color: #f8f9fa;
}
body {
background-color: #f5f7fb;
}
.page-header {
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: white;
padding: 2rem 0;
margin-bottom: 2rem;
border-radius: 0 0 15px 15px;
box-shadow: 0 4px 20px rgba(67, 97, 238, 0.15);
}
.page-header h1 {
font-weight: 700;
margin-bottom: 0.5rem;
text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.page-header .subtitle {
opacity: 0.9;
font-size: 1.1rem;
}
.card {
border: none;
border-radius: 12px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
transition: transform 0.3s ease, box-shadow 0.3s ease;
overflow: hidden;
}
.card:hover {
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.card-header {
background: linear-gradient(to right, var(--primary-light), white);
border-bottom: 2px solid var(--primary-light);
padding: 1.25rem 1.5rem;
font-weight: 600;
color: var(--dark-color);
position: relative;
}
.card-header::before {
content: '';
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 4px;
background: var(--primary-color);
border-radius: 0 3px 3px 0;
}
.card-header h5 {
margin: 0;
font-weight: 700;
font-size: 1.1rem;
}
.form-section {
padding: 1.5rem;
}
.form-label {
font-weight: 600;
color: var(--dark-color);
margin-bottom: 0.5rem;
display: flex;
align-items: center;
}
.form-label i {
margin-right: 8px;
color: var(--primary-color);
}
.form-control {
border: 2px solid #e2e8f0;
border-radius: 8px;
padding: 0.75rem 1rem;
font-size: 0.95rem;
transition: all 0.3s ease;
background-color: white;
}
.form-control:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1);
background-color: white;
}
.input-group-text {
background-color: var(--primary-light);
border: 2px solid #e2e8f0;
border-right: none;
color: var(--primary-color);
font-weight: 600;
}
.btn {
border-radius: 8px;
padding: 0.75rem 1.5rem;
font-weight: 600;
transition: all 0.3s ease;
border: none;
display: inline-flex;
align-items: center;
justify-content: center;
}
.btn-primary {
background: linear-gradient(135deg, var(--primary-color), #5a6ff0);
color: white;
box-shadow: 0 4px 12px rgba(67, 97, 238, 0.25);
}
.btn-primary:hover {
background: linear-gradient(135deg, #3a56e9, #4a5fed);
transform: translateY(-2px);
box-shadow: 0 6px 18px rgba(67, 97, 238, 0.35);
}
.btn-success {
background: linear-gradient(135deg, var(--success-color), #1bdecb);
color: white;
box-shadow: 0 4px 12px rgba(6, 214, 160, 0.25);
}
.btn-success:hover {
background: linear-gradient(135deg, #05c896, #16d9c5);
transform: translateY(-2px);
box-shadow: 0 6px 18px rgba(6, 214, 160, 0.35);
}
/* Table styles */
.results-card {
border-radius: 12px;
overflow: hidden;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.08);
margin-bottom: 2rem;
}
.table-container {
max-height: 600px;
overflow-y: auto;
border-radius: 8px;
}
.table {
margin-bottom: 0;
font-size: 0.9rem;
}
.table thead {
background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
color: white;
position: sticky;
top: 0;
z-index: 10;
}
.table th {
border: none;
padding: 1rem 0.75rem;
font-weight: 600;
text-transform: uppercase;
font-size: 0.8rem;
letter-spacing: 0.5px;
white-space: nowrap;
}
.table td {
padding: 0.85rem 0.75rem;
vertical-align: middle;
border-bottom: 1px solid #f1f5f9;
transition: background-color 0.2s ease;
}
.table-striped tbody tr:nth-of-type(odd) {
background-color: rgba(67, 97, 238, 0.02);
}
.table-hover tbody tr:hover {
background-color: rgba(67, 97, 238, 0.08);
}
.total-row {
background: linear-gradient(to right, #f8fafc, #e2e8f0) !important;
font-weight: 700;
}
.total-row td {
border-top: 2px solid var(--primary-color);
border-bottom: none;
padding: 1rem 0.75rem;
}
/* Cell styles */
.date-cell {
font-weight: 600;
color: var(--dark-color);
min-width: 100px;
}
.date-cell .weekday {
display: block;
font-size: 0.75rem;
color: #64748b;
font-weight: normal;
margin-top: 2px;
}
.time-cell {
text-align: center;
font-family: 'Courier New', 'SF Mono', monospace;
font-weight: 600;
background-color: var(--primary-light);
border-radius: 6px;
padding: 0.4rem 0.6rem;
min-width: 75px;
color: var(--primary-color);
border: 1px solid rgba(67, 97, 238, 0.1);
}
.number-cell {
text-align: right;
font-family: 'Courier New', 'SF Mono', monospace;
font-weight: 600;
min-width: 85px;
color: #334155;
}
.highlight-cell {
background-color: rgba(255, 209, 102, 0.15);
border: 1px solid rgba(255, 209, 102, 0.2);
}
/* Vacation badges */
.vacation-badge {
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: 50%;
font-weight: 700;
font-size: 0.85rem;
box-shadow: 0 3px 8px rgba(0,0,0,0.1);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.vacation-badge:hover {
transform: scale(1.1);
box-shadow: 0 5px 12px rgba(0,0,0,0.15);
}
.vacation-1 {
background: linear-gradient(135deg, #a5b4fc, #818cf8);
color: white;
}
.vacation-2 {
background: linear-gradient(135deg, #34d399, #10b981);
color: white;
}
.vacation-3 {
background: linear-gradient(135deg, #fbbf24, #f59e0b);
color: white;
}
.vacation-4 {
background: linear-gradient(135deg, #f87171, #ef4444);
color: white;
}
/* Stats cards */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1.5rem;
margin-top: 2rem;
}
.stat-card {
background: white;
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
border-top: 4px solid;
position: relative;
overflow: hidden;
}
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.5), transparent);
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}
.stat-icon {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1rem;
font-size: 1.5rem;
}
.stat-title {
font-size: 0.85rem;
font-weight: 600;
color: #64748b;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 0.5rem;
}
.stat-value {
font-size: 1.8rem;
font-weight: 700;
margin-bottom: 0.25rem;
}
.stat-subtitle {
font-size: 0.85rem;
color: #94a3b8;
}
.work-hours .stat-icon { background: rgba(67, 97, 238, 0.1); color: var(--primary-color); }
.work-hours { border-top-color: var(--primary-color); }
.paid-hours .stat-icon { background: rgba(6, 214, 160, 0.1); color: var(--success-color); }
.paid-hours { border-top-color: var(--success-color); }
.vacations .stat-icon { background: rgba(255, 209, 102, 0.1); color: #f59e0b; }
.vacations { border-top-color: #f59e0b; }
.delta .stat-icon { background: rgba(17, 138, 178, 0.1); color: var(--info-color); }
.delta { border-top-color: var(--info-color); }
/* Alert */
.alert {
border-radius: 10px;
border: none;
padding: 1.25rem 1.5rem;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
}
.alert-warning {
background: linear-gradient(135deg, #fffbeb, #fef3c7);
border-left: 4px solid #f59e0b;
color: #92400e;
}
/* Footer */
.card-footer {
background-color: #f8fafc;
border-top: 1px solid #e2e8f0;
padding: 1rem 1.5rem;
font-size: 0.85rem;
color: #64748b;
}
/* Action buttons */
.action-buttons {
display: flex;
gap: 0.75rem;
align-items: center;
}
.action-btn {
width: 40px;
height: 40px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
background: var(--primary-light);
color: var(--primary-color);
border: none;
transition: all 0.3s ease;
}
.action-btn:hover {
background: var(--primary-color);
color: white;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(67, 97, 238, 0.2);
}
/* Results count badge */
.results-badge {
background: linear-gradient(135deg, var(--success-color), #1bdecb);
color: white;
padding: 0.5rem 1rem;
border-radius: 20px;
font-weight: 600;
font-size: 0.9rem;
box-shadow: 0 3px 10px rgba(6, 214, 160, 0.2);
}
/* Delta styling */
.delta-positive {
color: #10b981;
font-weight: 700;
background-color: rgba(16, 185, 129, 0.1);
border-radius: 4px;
padding: 2px 6px;
}
.delta-negative {
color: #ef4444;
font-weight: 700;
background-color: rgba(239, 68, 68, 0.1);
border-radius: 4px;
padding: 2px 6px;
}
/* Responsive */
@media (max-width: 768px) {
.stats-grid {
grid-template-columns: 1fr;
}
.table-container {
font-size: 0.8rem;
}
.table th, .table td {
padding: 0.6rem 0.5rem;
}
.time-cell, .number-cell {
min-width: 60px;
}
.action-buttons {
flex-wrap: wrap;
}
}
/* Animation */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.fade-in {
animation: fadeIn 0.5s ease forwards;
}
/* Print styles */
@media print {
.page-header, .btn, .action-buttons, .card-footer {
display: none;
}
.table thead {
background: #f1f5f9 !important;
color: var(--dark-color) !important;
}
}
</style>
{% endblock %}
{% block body %}
<!-- Page Header -->
<div class="page-header">
<div class="container-fluid">
<div class="row align-items-center">
<div class="col-md-8">
<h1><i class="fas fa-chart-line me-2"></i>Feuille d'heures</h1>
<p class="subtitle mb-0">Analyse complète des heures travaillées et payées</p>
</div>
<div class="col-md-4 text-end">
<span class="results-badge">
<i class="fas fa-calendar-alt me-1"></i>
{{ "now"|date('F Y')|capitalize }}
</span>
</div>
</div>
</div>
</div>
<div class="container-fluid pb-5">
<!-- Search Form -->
<div class="card fade-in mb-4">
<div class="card-header">
<h5><i class="fas fa-search me-2"></i>Recherche avancée</h5>
</div>
<div class="form-section">
{{ form_start(form, {'attr': {'class': 'row g-4', 'id': 'search-form'}}) }}
<div class="col-lg-3 col-md-6">
{{ form_label(form.nom_client) }}
<div class="input-group">
<span class="input-group-text"><i class="fas fa-user"></i></span>
{{ form_widget(form.nom_client, {'attr': {
'class': 'form-control',
'list': 'conducteurs-list',
'placeholder': 'Sélectionnez un conducteur'
}}) }}
</div>
<datalist id="conducteurs-list">
{% for conducteur in conducteurs %}
<option value="{{ conducteur }}">
{% endfor %}
</datalist>
</div>
<div class="col-lg-3 col-md-6">
{{ form_label(form.immatriculation) }}
<div class="input-group">
<span class="input-group-text"><i class="fas fa-car"></i></span>
{{ form_widget(form.immatriculation, {'attr': {
'class': 'form-control',
'list': 'immatriculations-list',
'placeholder': 'Toutes les immatriculations'
}}) }}
</div>
<datalist id="immatriculations-list">
{% for immat in immatriculations %}
<option value="{{ immat }}">
{% endfor %}
</datalist>
</div>
<div class="col-lg-3 col-md-6">
{{ form_label(form.agence) }}
<div class="input-group">
<span class="input-group-text"><i class="fas fa-building"></i></span>
{{ form_widget(form.agence, {'attr': {
'class': 'form-control',
'list': 'agences-list',
'placeholder': 'Toutes les agences'
}}) }}
</div>
<datalist id="agences-list">
{% for agence in agences %}
<option value="{{ agence }}">
{% endfor %}
</datalist>
</div>
<div class="col-lg-3 col-md-6">
{{ form_label(form.date_debut) }}
<div class="input-group">
<span class="input-group-text"><i class="fas fa-calendar-day"></i></span>
{{ form_widget(form.date_debut, {'attr': {
'class': 'form-control'
}}) }}
</div>
</div>
<div class="col-lg-3 col-md-6">
{{ form_label(form.date_fin) }}
<div class="input-group">
<span class="input-group-text"><i class="fas fa-calendar-week"></i></span>
{{ form_widget(form.date_fin, {'attr': {
'class': 'form-control'
}}) }}
</div>
</div>
<div class="col-12 mt-2">
<div class="d-flex flex-wrap align-items-center justify-content-between">
<div class="action-buttons">
{{ form_widget(form.rechercher, {'attr': {
'class': 'btn btn-primary',
'value': '🔍 Rechercher'
}}) }}
<button type="submit"
name="export"
class="btn btn-success"
formaction="{{ export_url }}"
formnovalidate="true">
<i class="fas fa-file-excel me-2"></i> Exporter
</button>
{# <button type="button" class="action-btn" id="print-btn" title="Imprimer">
<i class="fas fa-print"></i>
</button> #}
<button type="button" class="action-btn" id="help-btn" title="Aide">
<i class="fas fa-question-circle"></i>
</button>
</div>
<a href="javascript:void(0)" class="text-primary" id="reset-form">
<i class="fas fa-redo-alt me-1"></i> Réinitialiser
</a>
</div>
</div>
{# Champs cachés pour l'export #}
<input type="hidden" name="immatriculation" value="{{ search_params.immatriculation ?? '' }}">
<input type="hidden" name="nom_client" value="{{ search_params.nom_client ?? '' }}">
<input type="hidden" name="agence" value="{{ search_params.agence ?? '' }}">
<input type="hidden" name="date_debut" value="{% if search_params.date_debut is defined and search_params.date_debut %}{{ search_params.date_debut|date('Y-m-d') }}{% endif %}">
<input type="hidden" name="date_fin" value="{% if search_params.date_fin is defined and search_params.date_fin %}{{ search_params.date_fin|date('Y-m-d') }}{% endif %}">
{{ form_end(form) }}
</div>
</div>
<!-- Results -->
{% if results is not empty %}
<div class="results-card fade-in" style="animation-delay: 0.1s">
<div class="card-header d-flex justify-content-between align-items-center">
<h5><i class="fas fa-list-check me-2"></i>Résultats de la recherche</h5>
<div class="d-flex align-items-center">
<span class="me-3" style="color: var(--primary-color); font-weight: 600;">
<i class="fas fa-calendar-check me-1"></i>
{{ results|length }} jour{{ results|length > 1 ? 's' : '' }}
</span>
<div class="action-buttons">
{# <button type="button" class="action-btn" id="export-pdf" title="Exporter PDF">
<i class="fas fa-file-pdf"></i>
</button>
<button type="button" class="action-btn" id="copy-data" title="Copier les données">
<i class="fas fa-copy"></i>
</button> #}
</div>
</div>
</div>
<div class="table-container">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>Date</th>
<th>Conducteur</th>
<th>Véhicule</th>
<th colspan="2" class="text-center">Tranche 1</th>
<th colspan="2" class="text-center">Tranche 2</th>
<th colspan="2" class="text-center">Tranche 3</th>
<th colspan="2" class="text-center">Tranche 4</th>
<th>Total</th>
<th>Centièmes</th>
<th>Vac.</th>
<th>Forfait</th>
<th>Déduc.</th>
<th>Δ Delta</th>
<th>Payé</th>
<th>Centièmes payés</th>
</tr>
</thead>
<tbody>
{% for day in results %}
<tr>
<td class="date-cell">
{{ day.date|date('d/m/Y') }}
<span class="weekday">{{ day.date|date('D')|trans }}</span>
</td>
<td><strong>{{ day.nom_client }}</strong></td>
<td><span class="badge bg-secondary">{{ day.immatriculation }}</span></td>
{# Tranches horaires #}
{% for tranche in day.tranches %}
<td class="time-cell">{{ tranche.debut ?? '-' }}</td>
<td class="time-cell">{{ tranche.fin ?? '-' }}</td>
{% endfor %}
{# Si moins de 4 tranches, ajouter des cellules vides #}
{% for i in day.tranches|length..3 %}
<td class="time-cell text-muted">-</td>
<td class="time-cell text-muted">-</td>
{% endfor %}
{# Calculs #}
<td class="time-cell highlight-cell"><strong>{{ day.total_worked }}</strong></td>
<td class="number-cell">{{ day.total_centièmes|number_format(2, ',', ' ') }}</td>
<td class="text-center">
<span class="vacation-badge vacation-{{ day.nb_vacations }}"
title="{{ day.nb_vacations }} vacation(s)">
{{ day.nb_vacations }}
</span>
</td>
<td class="time-cell">{{ day.forfait }}</td>
<td class="time-cell">{{ day.deduction }}</td>
<td class="time-cell">
<span class="{% if day.delta|replace({':': ''})|default(0) > 0 %}delta-positive{% else %}delta-negative{% endif %}">
{{ day.delta }}
</span>
</td>
<td class="time-cell highlight-cell"><strong>{{ day.paid_hours }}</strong></td>
<td class="number-cell">{{ day.paid_centièmes|number_format(2, ',', ' ') }}</td>
</tr>
{% endfor %}
{# Ligne des totaux #}
{% if totals is not empty %}
<tr class="total-row">
<td colspan="11" class="text-end fw-bold">TOTAUX :</td>
<td class="time-cell fw-bold">{{ totals.total_worked }}</td>
<td class="number-cell fw-bold">{{ totals.total_centièmes|number_format(2, ',', ' ') }}</td>
<td class="text-center fw-bold">{{ totals.total_vacations }}</td>
<td class="time-cell fw-bold">{{ totals.total_forfait }}</td>
<td class="time-cell fw-bold">{{ totals.total_deduction }}</td>
<td class="time-cell fw-bold">
<span class="{% if totals.total_delta|replace({':': ''})|default(0) > 0 %}delta-positive{% else %}delta-negative{% endif %}">
{{ totals.total_delta }}
</span>
</td>
<td class="time-cell fw-bold">{{ totals.total_paid }}</td>
<td class="number-cell fw-bold">{{ totals.total_paid_centièmes|number_format(2, ',', ' ') }}</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
<div class="card-footer">
<div class="row align-items-center">
<div class="col-md-8">
<small class="text-muted">
<i class="fas fa-circle-info me-1"></i>
Système de calcul avancé • Δ Delta = Différence heures travaillées/payées
</small>
</div>
<div class="col-md-4 text-end">
<small class="text-muted">
<i class="fas fa-clock me-1"></i>
Généré le {{ "now"|date('d/m/Y à H:i') }}
</small>
</div>
</div>
</div>
</div>
<!-- Stats Cards -->
<div class="stats-grid fade-in" style="animation-delay: 0.2s">
<div class="stat-card work-hours">
<div class="stat-icon">
<i class="fas fa-clock"></i>
</div>
<div class="stat-title">Heures travaillées</div>
<div class="stat-value text-primary">{{ totals.total_worked }}</div>
<div class="stat-subtitle">{{ totals.total_centièmes|number_format(2, ',', ' ') }} centièmes</div>
</div>
<div class="stat-card paid-hours">
<div class="stat-icon">
<i class="fas fa-money-bill-wave"></i>
</div>
<div class="stat-title">Heures payées</div>
<div class="stat-value text-success">{{ totals.total_paid }}</div>
<div class="stat-subtitle">{{ totals.total_paid_centièmes|number_format(2, ',', ' ') }} centièmes</div>
</div>
<div class="stat-card vacations">
<div class="stat-icon">
<i class="fas fa-calendar-alt"></i>
</div>
<div class="stat-title">Total vacations</div>
<div class="stat-value" style="color: #f59e0b;">{{ totals.total_vacations }}</div>
<div class="stat-subtitle">Réparties sur {{ results|length }} jour{{ results|length > 1 ? 's' : '' }}</div>
</div>
<div class="stat-card delta">
<div class="stat-icon">
<i class="fas fa-balance-scale"></i>
</div>
<div class="stat-title">Balance Δ</div>
<div class="stat-value {% if totals.total_delta|replace({':': ''})|default(0) > 0 %}text-success{% else %}text-danger{% endif %}">
{{ totals.total_delta }}
</div>
<div class="stat-subtitle">
{% if totals.total_delta|replace({':': ''})|default(0) > 0 %}
<i class="fas fa-arrow-up me-1"></i> Excédent favorable
{% elseif totals.total_delta|replace({':': ''})|default(0) < 0 %}
<i class="fas fa-arrow-down me-1"></i> Déficit à combler
{% else %}
<i class="fas fa-equals me-1"></i> Équilibre parfait
{% endif %}
</div>
</div>
</div>
<!-- Summary Note -->
<div class="alert alert-info mt-4 fade-in" style="animation-delay: 0.3s">
<div class="d-flex">
<i class="fas fa-chart-pie me-3 fs-4" style="color: var(--info-color);"></i>
<div>
<h6 class="alert-heading mb-2">Synthèse de l'analyse</h6>
<p class="mb-0">
L'analyse révèle un taux d'efficacité de
<strong>
{% if totals.total_worked|replace({':': ''})|default(0) > 0 %}
{{ ((totals.total_paid|replace({':': ''}) / totals.total_worked|replace({':': ''})) * 100)|number_format(1) }}%
{% else %}
0%
{% endif %}
</strong>
entre les heures travaillées et payées.
{% if totals.total_delta|replace({':': ''})|default(0) > 0 %}
<span class="text-success">Excellent résultat avec un excédent favorable.</span>
{% elseif totals.total_delta|replace({':': ''})|default(0) < 0 %}
<span class="text-danger">Attention au déficit qui nécessite une attention particulière.</span>
{% else %}
<span class="text-info">Équilibre parfait entre travail et rémunération.</span>
{% endif %}
</p>
</div>
</div>
</div>
{% elseif form_submitted %}
<div class="alert alert-warning fade-in">
<div class="d-flex align-items-center">
<i class="fas fa-search-minus me-3 fs-4"></i>
<div>
<h6 class="alert-heading mb-1">Aucun résultat trouvé</h6>
<p class="mb-0">Modifiez vos critères de recherche ou élargissez la période pour obtenir des résultats.</p>
</div>
</div>
</div>
<div class="text-center mt-4">
<button class="btn btn-outline-primary" id="show-all-data">
<i class="fas fa-eye me-2"></i>Afficher toutes les données
</button>
</div>
{% endif %}
</div>
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script src="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.14/dist/js/bootstrap-select.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Réinitialisation du formulaire
document.getElementById('reset-form').addEventListener('click', function(e) {
e.preventDefault();
document.getElementById('search-form').reset();
// Mettre les dates par défaut
const today = new Date();
const firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
document.querySelector('#{{ form.date_debut.vars.id }}').value =
firstDay.toISOString().split('T')[0];
document.querySelector('#{{ form.date_fin.vars.id }}').value =
today.toISOString().split('T')[0];
});
// Afficher toutes les données
const showAllBtn = document.getElementById('show-all-data');
if (showAllBtn) {
showAllBtn.addEventListener('click', function() {
document.getElementById('search-form').reset();
document.getElementById('search-form').submit();
});
}
// Impression
document.getElementById('print-btn').addEventListener('click', function() {
window.print();
});
// Copie des données
document.getElementById('copy-data').addEventListener('click', function() {
const table = document.querySelector('.table');
let text = '';
// En-têtes
const headers = table.querySelectorAll('thead th');
const headerText = Array.from(headers).map(th => th.textContent.trim()).join('\t');
text += headerText + '\n';
// Données
const rows = table.querySelectorAll('tbody tr');
rows.forEach(row => {
const cells = row.querySelectorAll('td');
const rowText = Array.from(cells).map(cell => cell.textContent.trim()).join('\t');
text += rowText + '\n';
});
// Copie dans le presse-papier
navigator.clipboard.writeText(text).then(() => {
const originalHTML = this.innerHTML;
this.innerHTML = '<i class="fas fa-check"></i>';
this.style.background = 'var(--success-color)';
this.style.color = 'white';
setTimeout(() => {
this.innerHTML = originalHTML;
this.style.background = '';
this.style.color = '';
}, 2000);
});
});
// Bouton d'aide
document.getElementById('help-btn').addEventListener('click', function() {
alert("ℹ️ AIDE\n\n• Utilisez les filtres pour affiner votre recherche\n• Le delta (Δ) montre la différence entre heures travaillées et payées\n• Exportez les données en Excel pour analyse approfondie\n• Les vacations sont colorées pour une lecture rapide");
});
// Export PDF (simulé)
document.getElementById('export-pdf').addEventListener('click', function() {
alert("📄 La fonction d'export PDF sera bientôt disponible !");
});
// Mise à jour des champs cachés pour l'export
document.getElementById('search-form').addEventListener('submit', function() {
this.querySelector('input[name="immatriculation"]').value =
this.querySelector('#{{ form.immatriculation.vars.id }}').value;
this.querySelector('input[name="nom_client"]').value =
this.querySelector('#{{ form.nom_client.vars.id }}').value;
this.querySelector('input[name="agence"]').value =
this.querySelector('#{{ form.agence.vars.id }}').value;
this.querySelector('input[name="date_debut"]').value =
this.querySelector('#{{ form.date_debut.vars.id }}').value;
this.querySelector('input[name="date_fin"]').value =
this.querySelector('#{{ form.date_fin.vars.id }}').value;
});
// Animation des cartes au survol
const statCards = document.querySelectorAll('.stat-card');
statCards.forEach(card => {
card.addEventListener('mouseenter', function() {
this.style.transform = 'translateY(-8px) scale(1.02)';
});
card.addEventListener('mouseleave', function() {
this.style.transform = 'translateY(0) scale(1)';
});
});
// Animation des badges de vacations
const vacationBadges = document.querySelectorAll('.vacation-badge');
vacationBadges.forEach(badge => {
badge.addEventListener('mouseenter', function() {
this.style.transform = 'scale(1.15) rotate(5deg)';
});
badge.addEventListener('mouseleave', function() {
this.style.transform = 'scale(1) rotate(0)';
});
});
// Effet de focus sur les champs de formulaire
const formInputs = document.querySelectorAll('.form-control');
formInputs.forEach(input => {
input.addEventListener('focus', function() {
this.parentElement.style.transform = 'translateY(-2px)';
});
input.addEventListener('blur', function() {
this.parentElement.style.transform = 'translateY(0)';
});
});
});
</script>
{% endblock %}