import { apiClient } from './api-client'; export interface DashboardMetrics { totalChantiers: number; chantiersActifs: number; chantiersEnRetard: number; chantiersTermines: number; totalEquipes: number; equipesDisponibles: number; totalMateriel: number; materielDisponible: number; materielEnMaintenance: number; totalDocuments: number; totalPhotos: number; budgetTotal: number; coutReel: number; chiffreAffaires: number; objectifCA: number; tauxReussite: number; satisfactionClient: number; } export interface ChantierActif { id: string; nom: string; client: string; avancement: number; dateDebut: string; dateFin: string; statut: 'EN_COURS' | 'EN_RETARD' | 'PLANIFIE' | 'TERMINE'; budget: number; coutReel: number; equipe?: { id: string; nom: string; nombreMembres: number; }; } export interface ActiviteRecente { id: string; type: 'CHANTIER' | 'MAINTENANCE' | 'DOCUMENT' | 'EQUIPE'; titre: string; description: string; date: string; utilisateur: string; statut: 'SUCCESS' | 'WARNING' | 'ERROR' | 'INFO'; } export interface TacheUrgente { id: string; titre: string; description: string; priorite: 'HAUTE' | 'MOYENNE' | 'BASSE'; echeance: string; assignee: string; statut: 'A_FAIRE' | 'EN_COURS' | 'TERMINEE'; chantier?: { id: string; nom: string; }; } export interface StatistiquesMaintenance { totalEquipements: number; maintenancesPreventives: number; maintenancesCorrectives: number; equipementsEnPanne: number; tauxDisponibilite: number; } export interface DashboardData { metrics: DashboardMetrics; chantiersActifs: ChantierActif[]; activitesRecentes: ActiviteRecente[]; tachesUrgentes: TacheUrgente[]; statistiquesMaintenance: StatistiquesMaintenance; graphiques: { chiffreAffaires: { labels: string[]; objectifs: number[]; realisations: number[]; }; avancementPhases: { labels: string[]; pourcentages: number[]; }; }; } class DashboardService { private readonly baseUrl = '/api'; async getDashboardData(periode: 'semaine' | 'mois' | 'trimestre' | 'annee' = 'mois'): Promise { try { console.log('🏗️ DashboardService: Récupération des données depuis les endpoints réels...'); // Récupérer les données depuis les différents endpoints réels const [chantiers, clients, materiels, employes] = await Promise.all([ apiClient.get('/api/v1/chantiers').catch(() => ({ data: [] })), apiClient.get('/api/v1/clients').catch(() => ({ data: [] })), apiClient.get('/api/v1/materiels').catch(() => ({ data: [] })), apiClient.get('/api/v1/employes').catch(() => ({ data: [] })) ]); console.log('🏗️ DashboardService: Données récupérées:', { chantiers: chantiers.data.length, clients: clients.data.length, materiels: materiels.data.length, employes: employes.data.length }); // Calculer les métriques à partir des données réelles const metrics = this.calculateMetrics(chantiers.data, clients.data, materiels.data, employes.data); const chantiersActifs = this.filterChantiersActifs(chantiers.data); return { metrics, chantiersActifs, activitesRecentes: [], // TODO: Implémenter avec les vraies données tachesUrgentes: [], // TODO: Implémenter avec les vraies données statistiquesMaintenance: this.calculateMaintenanceStats(materiels.data), graphiques: { chiffreAffaires: { labels: [], objectifs: [], realisations: [] }, avancementPhases: { labels: [], pourcentages: [] } } }; } catch (error) { console.error('Erreur lors de la récupération des données du dashboard:', error); throw error; } } async getMetrics(periode: 'semaine' | 'mois' | 'trimestre' | 'annee' = 'mois'): Promise { try { // Utiliser les endpoints réels pour calculer les métriques const [chantiers, employes, materiels] = await Promise.all([ apiClient.get('/api/chantiers').catch(() => ({ data: [] })), apiClient.get('/api/employes').catch(() => ({ data: [] })), apiClient.get('/api/materiels').catch(() => ({ data: [] })) ]); return this.calculateMetrics(chantiers.data, [], materiels.data, employes.data); } catch (error) { console.error('Erreur lors de la récupération des métriques:', error); throw error; } } async getChantiersActifs(limit: number = 10): Promise { try { const response = await apiClient.get('/api/v1/chantiers'); const chantiers = response.data || []; return this.filterChantiersActifs(chantiers).slice(0, limit); } catch (error) { console.error('Erreur lors de la récupération des chantiers actifs:', error); return []; // Retourner un tableau vide en cas d'erreur } } async getActivitesRecentes(limit: number = 20): Promise { try { const response = await apiClient.get(`${this.baseUrl}/activites-recentes?limit=${limit}`); return response.data; } catch (error) { console.error('Erreur lors de la récupération des activités récentes:', error); throw error; } } async getTachesUrgentes(limit: number = 10): Promise { try { const response = await apiClient.get(`${this.baseUrl}/taches-urgentes?limit=${limit}`); return response.data; } catch (error) { console.error('Erreur lors de la récupération des tâches urgentes:', error); throw error; } } async getStatistiquesMaintenance(): Promise { try { const response = await apiClient.get(`${this.baseUrl}/statistiques-maintenance`); return response.data; } catch (error) { console.error('Erreur lors de la récupération des statistiques de maintenance:', error); throw error; } } async exportDashboard(format: 'pdf' | 'excel' = 'pdf', periode: string = 'mois'): Promise { try { const response = await apiClient.get(`${this.baseUrl}/export`, { params: { format, periode }, responseType: 'blob' }); return response.data; } catch (error) { console.error('Erreur lors de l\'export du dashboard:', error); throw error; } } // Méthodes utilitaires pour calculer les métriques à partir des données réelles private calculateMetrics(chantiers: any[], clients: any[], materiels: any[], employes: any[]): DashboardMetrics { const chantiersActifs = chantiers.filter(c => c.statut === 'EN_COURS' || c.statut === 'ACTIF'); const chantiersEnRetard = chantiers.filter(c => c.statut === 'EN_RETARD'); const chantiersTermines = chantiers.filter(c => c.statut === 'TERMINE'); const equipesDisponibles = employes.filter(e => e.statut === 'DISPONIBLE' || e.statut === 'ACTIF'); const materielDisponible = materiels.filter(m => m.statut === 'DISPONIBLE'); const materielEnMaintenance = materiels.filter(m => m.statut === 'MAINTENANCE'); return { totalChantiers: chantiers.length, chantiersActifs: chantiersActifs.length, chantiersEnRetard: chantiersEnRetard.length, chantiersTermines: chantiersTermines.length, totalEquipes: employes.length, equipesDisponibles: equipesDisponibles.length, totalMateriel: materiels.length, materielDisponible: materielDisponible.length, materielEnMaintenance: materielEnMaintenance.length, totalDocuments: 0, // TODO: Implémenter quand l'endpoint sera disponible totalPhotos: 0, // TODO: Implémenter quand l'endpoint sera disponible budgetTotal: chantiers.reduce((sum, c) => sum + (c.budget || 0), 0), coutReel: chantiers.reduce((sum, c) => sum + (c.coutReel || 0), 0), chiffreAffaires: chantiersTermines.reduce((sum, c) => sum + (c.budget || 0), 0), objectifCA: 1000000, // TODO: Récupérer depuis la configuration tauxReussite: chantiers.length > 0 ? (chantiersTermines.length / chantiers.length) * 100 : 0, satisfactionClient: 85 // TODO: Calculer depuis les évaluations clients }; } private filterChantiersActifs(chantiers: any[]): ChantierActif[] { return chantiers .filter(c => c.statut === 'EN_COURS' || c.statut === 'ACTIF') .map(c => ({ id: c.id, nom: c.nom || c.titre, client: c.client?.nom || c.clientNom || 'Client non défini', avancement: c.avancement || 0, dateDebut: c.dateDebut, dateFin: c.dateFin, statut: c.statut, budget: c.budget || 0, coutReel: c.coutReel || 0, equipe: c.equipe ? { id: c.equipe.id, nom: c.equipe.nom, nombreMembres: c.equipe.nombreMembres || 0 } : undefined })); } private calculateMaintenanceStats(materiels: any[]): StatistiquesMaintenance { const materielEnMaintenance = materiels.filter(m => m.statut === 'MAINTENANCE'); const materielDisponible = materiels.filter(m => m.statut === 'DISPONIBLE'); const equipementsEnPanne = materiels.filter(m => m.statut === 'HORS_SERVICE' || m.statut === 'PANNE'); return { totalEquipements: materiels.length, maintenancesPreventives: 0, // TODO: Implémenter avec les vraies données maintenancesCorrectives: materielEnMaintenance.length, equipementsEnPanne: equipementsEnPanne.length, tauxDisponibilite: materiels.length > 0 ? (materielDisponible.length / materiels.length) * 100 : 0 }; } // Méthodes utilitaires pour formatter les données static formatCurrency(amount: number): string { return new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' }).format(amount); } static formatPercentage(value: number): string { return new Intl.NumberFormat('fr-FR', { style: 'percent', minimumFractionDigits: 1, maximumFractionDigits: 1 }).format(value / 100); } static formatDate(dateString: string): string { return new Date(dateString).toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit', year: 'numeric' }); } static getStatutColor(statut: string): string { const colors: Record = { 'EN_COURS': 'success', 'EN_RETARD': 'danger', 'PLANIFIE': 'info', 'TERMINE': 'secondary', 'SUCCESS': 'success', 'WARNING': 'warning', 'ERROR': 'danger', 'INFO': 'info', 'HAUTE': 'danger', 'MOYENNE': 'warning', 'BASSE': 'info', 'A_FAIRE': 'secondary', 'TERMINEE': 'success' }; return colors[statut] || 'secondary'; } static getStatutIcon(statut: string): string { const icons: Record = { 'EN_COURS': 'pi-play', 'EN_RETARD': 'pi-exclamation-triangle', 'PLANIFIE': 'pi-calendar', 'TERMINE': 'pi-check', 'SUCCESS': 'pi-check-circle', 'WARNING': 'pi-exclamation-triangle', 'ERROR': 'pi-times-circle', 'INFO': 'pi-info-circle', 'CHANTIER': 'pi-building', 'MAINTENANCE': 'pi-cog', 'DOCUMENT': 'pi-file', 'EQUIPE': 'pi-users' }; return icons[statut] || 'pi-circle'; } } export const dashboardService = new DashboardService();