Alignement design systeme OK

This commit is contained in:
DahoudG
2025-09-20 03:56:11 +00:00
parent a1214bc116
commit 96a17eadbd
34 changed files with 11720 additions and 766 deletions

View File

@@ -0,0 +1,69 @@
/// Modèle de données pour un membre
class MembreModel {
final String id;
final String nom;
final String prenom;
final String email;
final String? telephone;
final String? statut;
final String? role;
final OrganisationModel? organisation;
const MembreModel({
required this.id,
required this.nom,
required this.prenom,
required this.email,
this.telephone,
this.statut,
this.role,
this.organisation,
});
factory MembreModel.fromJson(Map<String, dynamic> json) {
return MembreModel(
id: json['id'] as String,
nom: json['nom'] as String,
prenom: json['prenom'] as String,
email: json['email'] as String,
telephone: json['telephone'] as String?,
statut: json['statut'] as String?,
role: json['role'] as String?,
organisation: json['organisation'] != null
? OrganisationModel.fromJson(json['organisation'] as Map<String, dynamic>)
: null,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'nom': nom,
'prenom': prenom,
'email': email,
'telephone': telephone,
'statut': statut,
'role': role,
'organisation': organisation?.toJson(),
};
}
}
/// Modèle pour une organisation
class OrganisationModel {
final String? nom;
const OrganisationModel({this.nom});
factory OrganisationModel.fromJson(Map<String, dynamic> json) {
return OrganisationModel(
nom: json['nom'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
'nom': nom,
};
}
}

View File

@@ -0,0 +1,278 @@
import 'package:dio/dio.dart';
import '../../../../core/models/membre_search_criteria.dart';
import '../../../../core/models/membre_search_result.dart';
/// Service pour la recherche avancée de membres
/// Gère les appels API vers l'endpoint de recherche sophistiquée
class MembreSearchService {
final Dio _dio;
MembreSearchService(this._dio);
/// Effectue une recherche avancée de membres
///
/// [criteria] Critères de recherche
/// [page] Numéro de page (0-based)
/// [size] Taille de la page
/// [sortField] Champ de tri
/// [sortDirection] Direction du tri (asc/desc)
///
/// Returns [MembreSearchResult] avec les résultats paginés
Future<MembreSearchResult> searchMembresAdvanced({
required MembreSearchCriteria criteria,
int page = 0,
int size = 20,
String sortField = 'nom',
String sortDirection = 'asc',
}) async {
print('Recherche avancée de membres: ${criteria.description}');
try {
// Validation des critères
if (!criteria.hasAnyCriteria) {
throw Exception('Au moins un critère de recherche doit être spécifié');
}
if (!criteria.isValid) {
throw Exception('Critères de recherche invalides');
}
// Préparation des paramètres de requête
final queryParams = {
'page': page.toString(),
'size': size.toString(),
'sort': sortField,
'direction': sortDirection,
};
// Appel API
final response = await _dio.post(
'/api/membres/search/advanced',
data: criteria.toJson(),
queryParameters: queryParams,
);
// Parsing de la réponse
final result = MembreSearchResult.fromJson(response.data);
print('Recherche terminée: ${result.totalElements} résultats en ${result.executionTimeMs}ms');
return result;
} on DioException catch (e) {
print('Erreur lors de la recherche avancée: $e');
rethrow;
} catch (e) {
print('Erreur inattendue lors de la recherche: $e');
rethrow;
}
}
/// Recherche rapide par terme général
///
/// [query] Terme de recherche
/// [page] Numéro de page
/// [size] Taille de la page
///
/// Returns [MembreSearchResult] avec les résultats
Future<MembreSearchResult> quickSearch({
required String query,
int page = 0,
int size = 20,
}) async {
final criteria = MembreSearchCriteria.quickSearch(query);
return searchMembresAdvanced(
criteria: criteria,
page: page,
size: size,
);
}
/// Recherche des membres actifs uniquement
///
/// [page] Numéro de page
/// [size] Taille de la page
///
/// Returns [MembreSearchResult] avec les membres actifs
Future<MembreSearchResult> searchActiveMembers({
int page = 0,
int size = 20,
}) async {
return searchMembresAdvanced(
criteria: MembreSearchCriteria.activeMembers,
page: page,
size: size,
);
}
/// Recherche des membres du bureau
///
/// [page] Numéro de page
/// [size] Taille de la page
///
/// Returns [MembreSearchResult] avec les membres du bureau
Future<MembreSearchResult> searchBureauMembers({
int page = 0,
int size = 20,
}) async {
return searchMembresAdvanced(
criteria: MembreSearchCriteria.bureauMembers,
page: page,
size: size,
);
}
/// Recherche par organisation
///
/// [organisationIds] Liste des IDs d'organisations
/// [page] Numéro de page
/// [size] Taille de la page
///
/// Returns [MembreSearchResult] avec les membres des organisations
Future<MembreSearchResult> searchByOrganisations({
required List<String> organisationIds,
int page = 0,
int size = 20,
}) async {
final criteria = MembreSearchCriteria(
organisationIds: organisationIds,
statut: 'ACTIF',
);
return searchMembresAdvanced(
criteria: criteria,
page: page,
size: size,
);
}
/// Recherche par tranche d'âge
///
/// [ageMin] Âge minimum
/// [ageMax] Âge maximum
/// [page] Numéro de page
/// [size] Taille de la page
///
/// Returns [MembreSearchResult] avec les membres dans la tranche d'âge
Future<MembreSearchResult> searchByAgeRange({
int? ageMin,
int? ageMax,
int page = 0,
int size = 20,
}) async {
final criteria = MembreSearchCriteria(
ageMin: ageMin,
ageMax: ageMax,
statut: 'ACTIF',
);
return searchMembresAdvanced(
criteria: criteria,
page: page,
size: size,
);
}
/// Recherche par région
///
/// [region] Nom de la région
/// [page] Numéro de page
/// [size] Taille de la page
///
/// Returns [MembreSearchResult] avec les membres de la région
Future<MembreSearchResult> searchByRegion({
required String region,
int page = 0,
int size = 20,
}) async {
final criteria = MembreSearchCriteria(
region: region,
statut: 'ACTIF',
);
return searchMembresAdvanced(
criteria: criteria,
page: page,
size: size,
);
}
/// Recherche par rôles
///
/// [roles] Liste des rôles
/// [page] Numéro de page
/// [size] Taille de la page
///
/// Returns [MembreSearchResult] avec les membres ayant ces rôles
Future<MembreSearchResult> searchByRoles({
required List<String> roles,
int page = 0,
int size = 20,
}) async {
final criteria = MembreSearchCriteria(
roles: roles,
statut: 'ACTIF',
);
return searchMembresAdvanced(
criteria: criteria,
page: page,
size: size,
);
}
/// Recherche par période d'adhésion
///
/// [dateMin] Date minimum (ISO 8601)
/// [dateMax] Date maximum (ISO 8601)
/// [page] Numéro de page
/// [size] Taille de la page
///
/// Returns [MembreSearchResult] avec les membres adhérés dans la période
Future<MembreSearchResult> searchByAdhesionPeriod({
String? dateMin,
String? dateMax,
int page = 0,
int size = 20,
}) async {
final criteria = MembreSearchCriteria(
dateAdhesionMin: dateMin,
dateAdhesionMax: dateMax,
statut: 'ACTIF',
);
return searchMembresAdvanced(
criteria: criteria,
page: page,
size: size,
);
}
/// Valide les critères de recherche avant envoi
bool validateCriteria(MembreSearchCriteria criteria) {
if (!criteria.hasAnyCriteria) {
print('Aucun critère de recherche spécifié');
return false;
}
if (!criteria.isValid) {
print('Critères de recherche invalides: ${criteria.description}');
return false;
}
return true;
}
/// Estime le temps de recherche basé sur les critères
Duration estimateSearchTime(MembreSearchCriteria criteria) {
// Estimation basique - peut être améliorée avec des métriques réelles
int complexityScore = 0;
if (criteria.query?.isNotEmpty == true) complexityScore += 2;
if (criteria.organisationIds?.isNotEmpty == true) complexityScore += 1;
if (criteria.roles?.isNotEmpty == true) complexityScore += 1;
if (criteria.ageMin != null || criteria.ageMax != null) complexityScore += 1;
if (criteria.dateAdhesionMin != null || criteria.dateAdhesionMax != null) complexityScore += 1;
// Temps de base + complexité
final baseTime = 100; // 100ms de base
final additionalTime = complexityScore * 50; // 50ms par critère
return Duration(milliseconds: baseTime + additionalTime);
}
}