Refactoring - Version OK
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
import 'membre_search_criteria.dart';
|
||||
import '../../features/members/data/models/membre_complete_model.dart';
|
||||
|
||||
/// Modèle pour les résultats de recherche avancée des membres
|
||||
/// Correspond au DTO Java MembreSearchResultDTO
|
||||
class MembreSearchResult {
|
||||
/// Liste des membres trouvés
|
||||
final List<MembreCompletModel> membres;
|
||||
|
||||
/// Nombre total de résultats (toutes pages confondues)
|
||||
final int totalElements;
|
||||
|
||||
/// Nombre total de pages
|
||||
final int totalPages;
|
||||
|
||||
/// Numéro de la page actuelle (0-based)
|
||||
final int currentPage;
|
||||
|
||||
/// Taille de la page
|
||||
final int pageSize;
|
||||
|
||||
/// Nombre d'éléments sur la page actuelle
|
||||
final int numberOfElements;
|
||||
|
||||
/// Indique s'il y a une page suivante
|
||||
final bool hasNext;
|
||||
|
||||
/// Indique s'il y a une page précédente
|
||||
final bool hasPrevious;
|
||||
|
||||
/// Indique si c'est la première page
|
||||
final bool isFirst;
|
||||
|
||||
/// Indique si c'est la dernière page
|
||||
final bool isLast;
|
||||
|
||||
/// Critères de recherche utilisés
|
||||
final MembreSearchCriteria criteria;
|
||||
|
||||
/// Temps d'exécution de la recherche en millisecondes
|
||||
final int executionTimeMs;
|
||||
|
||||
/// Statistiques de recherche
|
||||
final SearchStatistics? statistics;
|
||||
|
||||
const MembreSearchResult({
|
||||
required this.membres,
|
||||
required this.totalElements,
|
||||
required this.totalPages,
|
||||
required this.currentPage,
|
||||
required this.pageSize,
|
||||
required this.numberOfElements,
|
||||
required this.hasNext,
|
||||
required this.hasPrevious,
|
||||
required this.isFirst,
|
||||
required this.isLast,
|
||||
required this.criteria,
|
||||
required this.executionTimeMs,
|
||||
this.statistics,
|
||||
});
|
||||
|
||||
/// Factory constructor pour créer depuis JSON
|
||||
factory MembreSearchResult.fromJson(Map<String, dynamic> json) {
|
||||
return MembreSearchResult(
|
||||
membres: (json['membres'] as List<dynamic>?)
|
||||
?.map((e) => MembreCompletModel.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ?? [],
|
||||
totalElements: json['totalElements'] as int? ?? 0,
|
||||
totalPages: json['totalPages'] as int? ?? 0,
|
||||
currentPage: json['currentPage'] as int? ?? 0,
|
||||
pageSize: json['pageSize'] as int? ?? 20,
|
||||
numberOfElements: json['numberOfElements'] as int? ?? 0,
|
||||
hasNext: json['hasNext'] as bool? ?? false,
|
||||
hasPrevious: json['hasPrevious'] as bool? ?? false,
|
||||
isFirst: json['isFirst'] as bool? ?? true,
|
||||
isLast: json['isLast'] as bool? ?? true,
|
||||
criteria: MembreSearchCriteria.fromJson(json['criteria'] as Map<String, dynamic>? ?? {}),
|
||||
executionTimeMs: json['executionTimeMs'] as int? ?? 0,
|
||||
statistics: json['statistics'] != null
|
||||
? SearchStatistics.fromJson(json['statistics'] as Map<String, dynamic>)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
/// Convertit vers JSON
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'membres': membres.map((e) => e.toJson()).toList(),
|
||||
'totalElements': totalElements,
|
||||
'totalPages': totalPages,
|
||||
'currentPage': currentPage,
|
||||
'pageSize': pageSize,
|
||||
'numberOfElements': numberOfElements,
|
||||
'hasNext': hasNext,
|
||||
'hasPrevious': hasPrevious,
|
||||
'isFirst': isFirst,
|
||||
'isLast': isLast,
|
||||
'criteria': criteria.toJson(),
|
||||
'executionTimeMs': executionTimeMs,
|
||||
'statistics': statistics?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Vérifie si les résultats sont vides
|
||||
bool get isEmpty => membres.isEmpty;
|
||||
|
||||
/// Vérifie si les résultats ne sont pas vides
|
||||
bool get isNotEmpty => membres.isNotEmpty;
|
||||
|
||||
/// Retourne le numéro de la page suivante (1-based pour affichage)
|
||||
int get nextPageNumber => hasNext ? currentPage + 2 : -1;
|
||||
|
||||
/// Retourne le numéro de la page précédente (1-based pour affichage)
|
||||
int get previousPageNumber => hasPrevious ? currentPage : -1;
|
||||
|
||||
/// Retourne une description textuelle des résultats
|
||||
String get resultDescription {
|
||||
if (isEmpty) {
|
||||
return 'Aucun membre trouvé';
|
||||
}
|
||||
|
||||
if (totalElements == 1) {
|
||||
return '1 membre trouvé';
|
||||
}
|
||||
|
||||
if (totalPages == 1) {
|
||||
return '$totalElements membres trouvés';
|
||||
}
|
||||
|
||||
final startElement = currentPage * pageSize + 1;
|
||||
final endElement = (startElement + numberOfElements - 1).clamp(1, totalElements);
|
||||
|
||||
return 'Membres $startElement-$endElement sur $totalElements (page ${currentPage + 1}/$totalPages)';
|
||||
}
|
||||
|
||||
/// Résultat vide
|
||||
static MembreSearchResult empty(MembreSearchCriteria criteria) {
|
||||
return MembreSearchResult(
|
||||
membres: const [],
|
||||
totalElements: 0,
|
||||
totalPages: 0,
|
||||
currentPage: 0,
|
||||
pageSize: 20,
|
||||
numberOfElements: 0,
|
||||
hasNext: false,
|
||||
hasPrevious: false,
|
||||
isFirst: true,
|
||||
isLast: true,
|
||||
criteria: criteria,
|
||||
executionTimeMs: 0,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => 'MembreSearchResult($resultDescription, ${executionTimeMs}ms)';
|
||||
}
|
||||
|
||||
/// Statistiques sur les résultats de recherche
|
||||
class SearchStatistics {
|
||||
/// Nombre de membres actifs dans les résultats
|
||||
final int membresActifs;
|
||||
|
||||
/// Nombre de membres inactifs dans les résultats
|
||||
final int membresInactifs;
|
||||
|
||||
/// Âge moyen des membres trouvés
|
||||
final double ageMoyen;
|
||||
|
||||
/// Âge minimum des membres trouvés
|
||||
final int ageMin;
|
||||
|
||||
/// Âge maximum des membres trouvés
|
||||
final int ageMax;
|
||||
|
||||
/// Nombre d'organisations représentées
|
||||
final int nombreOrganisations;
|
||||
|
||||
/// Nombre de régions représentées
|
||||
final int nombreRegions;
|
||||
|
||||
/// Ancienneté moyenne en années
|
||||
final double ancienneteMoyenne;
|
||||
|
||||
const SearchStatistics({
|
||||
required this.membresActifs,
|
||||
required this.membresInactifs,
|
||||
required this.ageMoyen,
|
||||
required this.ageMin,
|
||||
required this.ageMax,
|
||||
required this.nombreOrganisations,
|
||||
required this.nombreRegions,
|
||||
required this.ancienneteMoyenne,
|
||||
});
|
||||
|
||||
/// Factory constructor pour créer depuis JSON
|
||||
factory SearchStatistics.fromJson(Map<String, dynamic> json) {
|
||||
return SearchStatistics(
|
||||
membresActifs: json['membresActifs'] as int? ?? 0,
|
||||
membresInactifs: json['membresInactifs'] as int? ?? 0,
|
||||
ageMoyen: (json['ageMoyen'] as num?)?.toDouble() ?? 0.0,
|
||||
ageMin: json['ageMin'] as int? ?? 0,
|
||||
ageMax: json['ageMax'] as int? ?? 0,
|
||||
nombreOrganisations: json['nombreOrganisations'] as int? ?? 0,
|
||||
nombreRegions: json['nombreRegions'] as int? ?? 0,
|
||||
ancienneteMoyenne: (json['ancienneteMoyenne'] as num?)?.toDouble() ?? 0.0,
|
||||
);
|
||||
}
|
||||
|
||||
/// Convertit vers JSON
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'membresActifs': membresActifs,
|
||||
'membresInactifs': membresInactifs,
|
||||
'ageMoyen': ageMoyen,
|
||||
'ageMin': ageMin,
|
||||
'ageMax': ageMax,
|
||||
'nombreOrganisations': nombreOrganisations,
|
||||
'nombreRegions': nombreRegions,
|
||||
'ancienneteMoyenne': ancienneteMoyenne,
|
||||
};
|
||||
}
|
||||
|
||||
/// Nombre total de membres
|
||||
int get totalMembres => membresActifs + membresInactifs;
|
||||
|
||||
/// Pourcentage de membres actifs
|
||||
double get pourcentageActifs {
|
||||
if (totalMembres == 0) return 0.0;
|
||||
return (membresActifs / totalMembres) * 100;
|
||||
}
|
||||
|
||||
/// Pourcentage de membres inactifs
|
||||
double get pourcentageInactifs {
|
||||
if (totalMembres == 0) return 0.0;
|
||||
return (membresInactifs / totalMembres) * 100;
|
||||
}
|
||||
|
||||
/// Tranche d'âge
|
||||
String get trancheAge {
|
||||
if (ageMin == ageMax) return '$ageMin ans';
|
||||
return '$ageMin-$ageMax ans';
|
||||
}
|
||||
|
||||
/// Description textuelle des statistiques
|
||||
String get description {
|
||||
final parts = <String>[];
|
||||
|
||||
if (totalMembres > 0) {
|
||||
parts.add('$totalMembres membres');
|
||||
if (membresActifs > 0) {
|
||||
parts.add('${pourcentageActifs.toStringAsFixed(1)}% actifs');
|
||||
}
|
||||
if (ageMoyen > 0) {
|
||||
parts.add('âge moyen: ${ageMoyen.toStringAsFixed(1)} ans');
|
||||
}
|
||||
if (nombreOrganisations > 0) {
|
||||
parts.add('$nombreOrganisations organisations');
|
||||
}
|
||||
if (ancienneteMoyenne > 0) {
|
||||
parts.add('ancienneté: ${ancienneteMoyenne.toStringAsFixed(1)} ans');
|
||||
}
|
||||
}
|
||||
|
||||
return parts.join(' • ');
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => 'SearchStatistics($description)';
|
||||
}
|
||||
Reference in New Issue
Block a user