Initial commit
This commit is contained in:
328
services/dashboard.ts
Normal file
328
services/dashboard.ts
Normal file
@@ -0,0 +1,328 @@
|
||||
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<DashboardData> {
|
||||
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)
|
||||
};
|
||||
} 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<DashboardMetrics> {
|
||||
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<ChantierActif[]> {
|
||||
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<ActiviteRecente[]> {
|
||||
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<TacheUrgente[]> {
|
||||
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<StatistiquesMaintenance> {
|
||||
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<Blob> {
|
||||
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');
|
||||
|
||||
return {
|
||||
materielEnMaintenance: materielEnMaintenance.length,
|
||||
materielDisponible: materielDisponible.length,
|
||||
maintenancesPrevues: 0, // TODO: Implémenter avec les vraies données
|
||||
maintenancesEnRetard: 0, // TODO: Implémenter avec les vraies données
|
||||
coutMaintenance: 0, // TODO: Calculer depuis les coûts de maintenance
|
||||
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<string, string> = {
|
||||
'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<string, string> = {
|
||||
'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();
|
||||
Reference in New Issue
Block a user