360 lines
9.1 KiB
Dart
360 lines
9.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'common/section_header.dart';
|
|
import 'common/stat_card.dart';
|
|
|
|
/// Section des statistiques rapides du dashboard
|
|
///
|
|
/// Widget réutilisable pour afficher les KPIs et métriques principales
|
|
/// avec différents layouts et styles selon le contexte.
|
|
class QuickStatsSection extends StatelessWidget {
|
|
/// Titre de la section
|
|
final String title;
|
|
|
|
/// Sous-titre optionnel
|
|
final String? subtitle;
|
|
|
|
/// Liste des statistiques à afficher
|
|
final List<QuickStat> stats;
|
|
|
|
/// Layout des cartes (grid, row, column)
|
|
final StatsLayout layout;
|
|
|
|
/// Nombre de colonnes pour le layout grid
|
|
final int gridColumns;
|
|
|
|
/// Style des cartes de statistiques
|
|
final StatCardStyle cardStyle;
|
|
|
|
/// Taille des cartes
|
|
final StatCardSize cardSize;
|
|
|
|
/// Callback lors du tap sur une statistique
|
|
final Function(QuickStat)? onStatTap;
|
|
|
|
/// Afficher ou non l'en-tête de section
|
|
final bool showHeader;
|
|
|
|
const QuickStatsSection({
|
|
super.key,
|
|
required this.title,
|
|
this.subtitle,
|
|
required this.stats,
|
|
this.layout = StatsLayout.grid,
|
|
this.gridColumns = 2,
|
|
this.cardStyle = StatCardStyle.elevated,
|
|
this.cardSize = StatCardSize.compact,
|
|
this.onStatTap,
|
|
this.showHeader = true,
|
|
});
|
|
|
|
/// Constructeur pour les KPIs système (Super Admin)
|
|
const QuickStatsSection.systemKPIs({
|
|
super.key,
|
|
this.onStatTap,
|
|
}) : title = 'Métriques Système',
|
|
subtitle = null,
|
|
stats = const [
|
|
QuickStat(
|
|
title: 'Organisations',
|
|
value: '247',
|
|
subtitle: '+12 ce mois',
|
|
icon: Icons.business,
|
|
color: Color(0xFF0984E3),
|
|
),
|
|
QuickStat(
|
|
title: 'Utilisateurs',
|
|
value: '15,847',
|
|
subtitle: '+1,234 ce mois',
|
|
icon: Icons.people,
|
|
color: Color(0xFF00B894),
|
|
),
|
|
QuickStat(
|
|
title: 'Uptime',
|
|
value: '99.97%',
|
|
subtitle: '30 derniers jours',
|
|
icon: Icons.trending_up,
|
|
color: Color(0xFF00CEC9),
|
|
),
|
|
QuickStat(
|
|
title: 'Temps Réponse',
|
|
value: '1.2s',
|
|
subtitle: 'Moyenne 24h',
|
|
icon: Icons.speed,
|
|
color: Color(0xFFE17055),
|
|
),
|
|
],
|
|
layout = StatsLayout.grid,
|
|
gridColumns = 2,
|
|
cardStyle = StatCardStyle.elevated,
|
|
cardSize = StatCardSize.compact,
|
|
showHeader = true;
|
|
|
|
/// Constructeur pour les statistiques d'organisation
|
|
const QuickStatsSection.organizationStats({
|
|
super.key,
|
|
this.onStatTap,
|
|
}) : title = 'Vue d\'ensemble',
|
|
subtitle = null,
|
|
stats = const [
|
|
QuickStat(
|
|
title: 'Membres',
|
|
value: '156',
|
|
subtitle: '+12 ce mois',
|
|
icon: Icons.people,
|
|
color: Color(0xFF00B894),
|
|
),
|
|
QuickStat(
|
|
title: 'Événements',
|
|
value: '23',
|
|
subtitle: '8 à venir',
|
|
icon: Icons.event,
|
|
color: Color(0xFFE17055),
|
|
),
|
|
QuickStat(
|
|
title: 'Projets',
|
|
value: '8',
|
|
subtitle: '3 actifs',
|
|
icon: Icons.work,
|
|
color: Color(0xFF0984E3),
|
|
),
|
|
QuickStat(
|
|
title: 'Taux engagement',
|
|
value: '78%',
|
|
subtitle: '+5% ce mois',
|
|
icon: Icons.trending_up,
|
|
color: Color(0xFF6C5CE7),
|
|
),
|
|
],
|
|
layout = StatsLayout.grid,
|
|
gridColumns = 2,
|
|
cardStyle = StatCardStyle.elevated,
|
|
cardSize = StatCardSize.compact,
|
|
showHeader = true;
|
|
|
|
/// Constructeur pour les métriques de performance
|
|
const QuickStatsSection.performanceMetrics({
|
|
super.key,
|
|
this.onStatTap,
|
|
}) : title = 'Performance',
|
|
subtitle = 'Métriques temps réel',
|
|
stats = const [
|
|
QuickStat(
|
|
title: 'CPU',
|
|
value: '23%',
|
|
subtitle: 'Normal',
|
|
icon: Icons.memory,
|
|
color: Color(0xFF00B894),
|
|
),
|
|
QuickStat(
|
|
title: 'RAM',
|
|
value: '67%',
|
|
subtitle: 'Élevé',
|
|
icon: Icons.storage,
|
|
color: Color(0xFFE17055),
|
|
),
|
|
QuickStat(
|
|
title: 'Réseau',
|
|
value: '12 MB/s',
|
|
subtitle: 'Stable',
|
|
icon: Icons.network_check,
|
|
color: Color(0xFF0984E3),
|
|
),
|
|
],
|
|
layout = StatsLayout.row,
|
|
gridColumns = 3,
|
|
cardStyle = StatCardStyle.outlined,
|
|
cardSize = StatCardSize.normal,
|
|
showHeader = true;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
if (showHeader) ...[
|
|
SectionHeader.section(
|
|
title: title,
|
|
subtitle: subtitle,
|
|
),
|
|
],
|
|
_buildStatsLayout(),
|
|
],
|
|
);
|
|
}
|
|
|
|
/// Construction du layout des statistiques
|
|
Widget _buildStatsLayout() {
|
|
switch (layout) {
|
|
case StatsLayout.grid:
|
|
return _buildGridLayout();
|
|
case StatsLayout.row:
|
|
return _buildRowLayout();
|
|
case StatsLayout.column:
|
|
return _buildColumnLayout();
|
|
case StatsLayout.wrap:
|
|
return _buildWrapLayout();
|
|
}
|
|
}
|
|
|
|
/// Layout en grille
|
|
Widget _buildGridLayout() {
|
|
return GridView.builder(
|
|
shrinkWrap: true,
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
|
crossAxisCount: gridColumns,
|
|
crossAxisSpacing: 8,
|
|
mainAxisSpacing: 8,
|
|
childAspectRatio: _getChildAspectRatio(),
|
|
),
|
|
itemCount: stats.length,
|
|
itemBuilder: (context, index) => _buildStatCard(stats[index]),
|
|
);
|
|
}
|
|
|
|
/// Layout en ligne
|
|
Widget _buildRowLayout() {
|
|
return Row(
|
|
children: stats.map((stat) => Expanded(
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
|
child: _buildStatCard(stat),
|
|
),
|
|
)).toList(),
|
|
);
|
|
}
|
|
|
|
/// Layout en colonne
|
|
Widget _buildColumnLayout() {
|
|
return Column(
|
|
children: stats.map((stat) => Padding(
|
|
padding: const EdgeInsets.only(bottom: 8),
|
|
child: _buildStatCard(stat),
|
|
)).toList(),
|
|
);
|
|
}
|
|
|
|
/// Layout wrap (adaptatif)
|
|
Widget _buildWrapLayout() {
|
|
return LayoutBuilder(
|
|
builder: (context, constraints) {
|
|
return Wrap(
|
|
spacing: 8,
|
|
runSpacing: 8,
|
|
children: stats.map((stat) => SizedBox(
|
|
width: (constraints.maxWidth - 8) / 2, // 2 colonnes avec espacement
|
|
child: _buildStatCard(stat),
|
|
)).toList(),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
/// Construction d'une carte de statistique
|
|
Widget _buildStatCard(QuickStat stat) {
|
|
return StatCard(
|
|
title: stat.title,
|
|
value: stat.value,
|
|
subtitle: stat.subtitle,
|
|
icon: stat.icon,
|
|
color: stat.color,
|
|
size: cardSize,
|
|
style: cardStyle,
|
|
onTap: onStatTap != null ? () => onStatTap!(stat) : null,
|
|
);
|
|
}
|
|
|
|
/// Ratio d'aspect selon la taille des cartes
|
|
double _getChildAspectRatio() {
|
|
switch (cardSize) {
|
|
case StatCardSize.compact:
|
|
return 1.4;
|
|
case StatCardSize.normal:
|
|
return 1.2;
|
|
case StatCardSize.large:
|
|
return 1.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Modèle de données pour une statistique rapide
|
|
class QuickStat {
|
|
final String title;
|
|
final String value;
|
|
final String subtitle;
|
|
final IconData icon;
|
|
final Color color;
|
|
final Map<String, dynamic>? metadata;
|
|
|
|
const QuickStat({
|
|
required this.title,
|
|
required this.value,
|
|
required this.subtitle,
|
|
required this.icon,
|
|
required this.color,
|
|
this.metadata,
|
|
});
|
|
|
|
/// Constructeur pour une métrique système
|
|
const QuickStat.system({
|
|
required this.title,
|
|
required this.value,
|
|
required this.subtitle,
|
|
required this.icon,
|
|
}) : color = const Color(0xFF6C5CE7),
|
|
metadata = null;
|
|
|
|
/// Constructeur pour une métrique utilisateur
|
|
const QuickStat.user({
|
|
required this.title,
|
|
required this.value,
|
|
required this.subtitle,
|
|
required this.icon,
|
|
}) : color = const Color(0xFF00B894),
|
|
metadata = null;
|
|
|
|
/// Constructeur pour une métrique d'organisation
|
|
const QuickStat.organization({
|
|
required this.title,
|
|
required this.value,
|
|
required this.subtitle,
|
|
required this.icon,
|
|
}) : color = const Color(0xFF0984E3),
|
|
metadata = null;
|
|
|
|
/// Constructeur pour une métrique d'événement
|
|
const QuickStat.event({
|
|
required this.title,
|
|
required this.value,
|
|
required this.subtitle,
|
|
required this.icon,
|
|
}) : color = const Color(0xFFE17055),
|
|
metadata = null;
|
|
|
|
/// Constructeur pour une alerte
|
|
const QuickStat.alert({
|
|
required this.title,
|
|
required this.value,
|
|
required this.subtitle,
|
|
required this.icon,
|
|
}) : color = Colors.orange,
|
|
metadata = null;
|
|
|
|
/// Constructeur pour une erreur
|
|
const QuickStat.error({
|
|
required this.title,
|
|
required this.value,
|
|
required this.subtitle,
|
|
required this.icon,
|
|
}) : color = Colors.red,
|
|
metadata = null;
|
|
}
|
|
|
|
/// Types de layout pour les statistiques
|
|
enum StatsLayout {
|
|
grid,
|
|
row,
|
|
column,
|
|
wrap,
|
|
}
|