Meta Description" name="description" />
{% extends 'base.html' %}
{% load static %}
{% block title %}Tableau de Bord{% endblock %}
{% block extra_css %}
<style>
.stat-card {
border-radius: 10px;
padding: 20px;
color: white;
margin-bottom: 20px;
transition: transform 0.3s;
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
.stat-card.blue {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.stat-card.green {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.stat-card.orange {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.stat-card.purple {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
.stat-icon {
font-size: 48px;
opacity: 0.8;
}
.stat-number {
font-size: 36px;
font-weight: bold;
margin: 10px 0;
}
.stat-label {
font-size: 14px;
opacity: 0.9;
}
.quick-action-btn {
height: 120px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 10px;
transition: all 0.3s;
}
.quick-action-btn:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
.quick-action-btn i {
font-size: 36px;
margin-bottom: 10px;
}
.recent-activity {
max-height: 400px;
overflow-y: auto;
}
.activity-item {
border-left: 3px solid #667eea;
padding: 10px;
margin-bottom: 10px;
background: #f8f9fa;
border-radius: 5px;
}
.activity-time {
font-size: 12px;
color: #6c757d;
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<!-- En-tête -->
<div class="row mb-4">
<div class="col-md-8">
<h2><i class="bi bi-speedometer2"></i> Tableau de Bord</h2>
<p class="text-muted">Bienvenue, {{ request.user.agent.nom_complet }}</p>
</div>
<div class="col-md-4 text-end">
<div class="btn-group">
<button class="btn btn-outline-primary active">Aujourd'hui</button>
<button class="btn btn-outline-primary">Ce mois</button>
<button class="btn btn-outline-primary">Cette année</button>
</div>
</div>
</div>
<!-- Statistiques -->
<div class="row">
<div class="col-md-3">
<div class="stat-card blue">
<i class="bi bi-file-earmark-text stat-icon float-end"></i>
<div class="stat-number">{{ stats.documents_today }}</div>
<div class="stat-label">Documents Délivrés Aujourd'hui</div>
</div>
</div>
<div class="col-md-3">
<div class="stat-card green">
<i class="bi bi-people stat-icon float-end"></i>
<div class="stat-number">{{ stats.citoyens_today }}</div>
<div class="stat-label">Nouveaux Citoyens</div>
</div>
</div>
<div class="col-md-3">
<div class="stat-card orange">
<i class="bi bi-calendar-check stat-icon float-end"></i>
<div class="stat-number">{{ stats.documents_month }}</div>
<div class="stat-label">Documents ce Mois</div>
</div>
</div>
<div class="col-md-3">
<div class="stat-card purple">
<i class="bi bi-graph-up stat-icon float-end"></i>
<div class="stat-number">{{ stats.total_citoyens }}</div>
<div class="stat-label">Total Citoyens</div>
</div>
</div>
</div>
<!-- Actions rapides -->
<div class="row mt-4">
<div class="col-12">
<h5 class="mb-3"><i class="bi bi-lightning"></i> Actions Rapides</h5>
</div>
<div class="col-md-3">
<a href="{% url 'citoyens:nouveau' %}" class="btn btn-primary quick-action-btn w-100">
<i class="bi bi-person-plus"></i>
<span>Nouveau Citoyen</span>
</a>
</div>
<div class="col-md-3">
<a href="{% url 'citoyens:recherche' %}" class="btn btn-info quick-action-btn w-100">
<i class="bi bi-search"></i>
<span>Rechercher Citoyen</span>
</a>
</div>
<div class="col-md-3">
<a href="{% url 'documents:delivrance' %}" class="btn btn-success quick-action-btn w-100">
<i class="bi bi-file-earmark-plus"></i>
<span>Délivrer Document</span>
</a>
</div>
<div class="col-md-3">
<a href="{% url 'historique:liste' %}" class="btn btn-warning quick-action-btn w-100">
<i class="bi bi-clock-history"></i>
<span>Historique</span>
</a>
</div>
</div>
<!-- Graphiques et activités récentes -->
<div class="row mt-4">
<!-- Graphique -->
<div class="col-md-8">
<div class="card">
<div class="card-header bg-white">
<h5 class="mb-0"><i class="bi bi-bar-chart"></i> Documents Délivrés (7 derniers jours)</h5>
</div>
<div class="card-body">
<canvas id="documentsChart" height="80"></canvas>
</div>
</div>
</div>
<!-- Activités récentes -->
<div class="col-md-4">
<div class="card">
<div class="card-header bg-white">
<h5 class="mb-0"><i class="bi bi-activity"></i> Activités Récentes</h5>
</div>
<div class="card-body recent-activity">
{% for activite in activites_recentes %}
<div class="activity-item">
<div class="d-flex justify-content-between">
<strong>{{ activite.action }}</strong>
<span class="activity-time">{{ activite.timestamp|timesince }}</span>
</div>
<small class="text-muted">
Par {{ activite.agent.nom_complet }}
</small>
</div>
{% empty %}
<p class="text-muted text-center">Aucune activité récente</p>
{% endfor %}
</div>
</div>
</div>
</div>
<!-- Répartition par type de document -->
<div class="row mt-4">
<div class="col-md-6">
<div class="card">
<div class="card-header bg-white">
<h5 class="mb-0"><i class="bi bi-pie-chart"></i> Répartition par Type</h5>
</div>
<div class="card-body">
<canvas id="typeDocumentChart" height="100"></canvas>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header bg-white">
<h5 class="mb-0"><i class="bi bi-trophy"></i> Top 5 Documents</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Type de Document</th>
<th>Nombre</th>
</tr>
</thead>
<tbody>
{% for doc in top_documents %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ doc.type_document__nom }}</td>
<td><span class="badge bg-primary">{{ doc.count }}</span></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script>
// Graphique des documents par jour
const ctx1 = document.getElementById('documentsChart').getContext('2d');
new Chart(ctx1, {
type: 'line',
data: {
labels: {{ chart_labels|safe }},
datasets: [{
label: 'Documents Délivrés',
data: {{ chart_data|safe }},
borderColor: 'rgb(102, 126, 234)',
backgroundColor: 'rgba(102, 126, 234, 0.1)',
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
stepSize: 1
}
}
}
}
});
// Graphique répartition par type
const ctx2 = document.getElementById('typeDocumentChart').getContext('2d');
new Chart(ctx2, {
type: 'doughnut',
data: {
labels: {{ pie_labels|safe }},
datasets: [{
data: {{ pie_data|safe }},
backgroundColor: [
'rgba(102, 126, 234, 0.8)',
'rgba(118, 75, 162, 0.8)',
'rgba(240, 147, 251, 0.8)',
'rgba(245, 87, 108, 0.8)',
'rgba(79, 172, 254, 0.8)',
]
}]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'bottom'
}
}
}
});
</script>
{% endblock %}2
2
80KB
211KB
132.0ms
200.0ms
132.0ms