'use client'; import React, { useState, useEffect } from 'react'; import { Card } from 'primereact/card'; import { Button } from 'primereact/button'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Tag } from 'primereact/tag'; import { Badge } from 'primereact/badge'; import { Toolbar } from 'primereact/toolbar'; import { ProgressBar } from 'primereact/progressbar'; import { Calendar } from 'primereact/calendar'; import { Dropdown } from 'primereact/dropdown'; import { InputNumber } from 'primereact/inputnumber'; import { Dialog } from 'primereact/dialog'; import { useRouter } from 'next/navigation'; import { apiClient } from '../../../../services/api-client'; interface PlanificationMaintenance { materielId: number; materielNom: string; materielType: string; derniereMaintenance?: string; prochaineMaintenance: string; frequenceMaintenance: number; // en jours heuresUtilisation: number; seuilMaintenanceHeures: number; pourcentageUsure: number; prioriteRecommandee: 'BASSE' | 'NORMALE' | 'HAUTE' | 'CRITIQUE'; typeMaintenanceRecommande: 'PREVENTIVE' | 'CORRECTIVE'; coutEstime: number; dureeEstimee: number; technicienRecommande?: { id: number; nom: string; specialites: string[]; disponibilite: boolean; }; risqueDefaillance: number; // pourcentage impactArret: 'FAIBLE' | 'MOYEN' | 'ELEVE' | 'CRITIQUE'; } interface ConfigurationPlanification { periodeAnalyse: number; // en mois seuilUrgence: number; // pourcentage d'usure optimiserCouts: boolean; optimiserDisponibilite: boolean; prendreCompteMeteo: boolean; grouperMaintenances: boolean; } const PlanificationMaintenancePage = () => { const [planifications, setPlanifications] = useState([]); const [loading, setLoading] = useState(true); const [configuration, setConfiguration] = useState({ periodeAnalyse: 6, seuilUrgence: 80, optimiserCouts: true, optimiserDisponibilite: true, prendreCompteMeteo: false, grouperMaintenances: true }); const [configDialog, setConfigDialog] = useState(false); const [selectedMateriels, setSelectedMateriels] = useState([]); const [dateDebutPlanification, setDateDebutPlanification] = useState(new Date()); const [dateFinPlanification, setDateFinPlanification] = useState( new Date(Date.now() + 6 * 30 * 24 * 60 * 60 * 1000) // +6 mois ); const router = useRouter(); useEffect(() => { loadPlanificationMaintenance(); }, [configuration]); const loadPlanificationMaintenance = async () => { try { setLoading(true); console.log('🔄 Chargement de la planification maintenance...'); const params = new URLSearchParams(); params.append('periodeAnalyse', configuration.periodeAnalyse.toString()); params.append('seuilUrgence', configuration.seuilUrgence.toString()); params.append('optimiserCouts', configuration.optimiserCouts.toString()); params.append('optimiserDisponibilite', configuration.optimiserDisponibilite.toString()); params.append('grouper', configuration.grouperMaintenances.toString()); const response = await apiClient.get(`/api/maintenances/planification-automatique?${params.toString()}`); console.log('✅ Planification chargée:', response.data); setPlanifications(response.data || []); } catch (error) { console.error('❌ Erreur lors du chargement de la planification:', error); setPlanifications([]); } finally { setLoading(false); } }; const genererPlanningOptimal = async () => { try { console.log('🔄 Génération du planning optimal...'); const params = { materiels: selectedMateriels.map(m => m.materielId), dateDebut: dateDebutPlanification.toISOString().split('T')[0], dateFin: dateFinPlanification.toISOString().split('T')[0], configuration }; const response = await apiClient.post('/api/maintenances/generer-planning-optimal', params); console.log('✅ Planning optimal généré:', response.data); // Rediriger vers le calendrier avec le nouveau planning router.push('/maintenance/calendrier?planning=optimal'); } catch (error) { console.error('❌ Erreur lors de la génération du planning:', error); } }; const planifierMaintenanceAutomatique = async (materielId: number) => { try { await apiClient.post(`/api/maintenances/planifier-automatique/${materielId}`); console.log('✅ Maintenance planifiée automatiquement'); loadPlanificationMaintenance(); } catch (error) { console.error('❌ Erreur lors de la planification automatique:', error); } }; const planifierToutesMaintenances = async () => { try { console.log('🔄 Planification de toutes les maintenances...'); await apiClient.post('/api/maintenances/planifier-toutes-automatique', configuration); console.log('✅ Toutes les maintenances planifiées'); loadPlanificationMaintenance(); } catch (error) { console.error('❌ Erreur lors de la planification globale:', error); } }; const materielBodyTemplate = (rowData: PlanificationMaintenance) => { return (
{rowData.materielNom} {rowData.materielType}
); }; const usureBodyTemplate = (rowData: PlanificationMaintenance) => { const couleur = rowData.pourcentageUsure > 80 ? 'danger' : rowData.pourcentageUsure > 60 ? 'warning' : 'success'; return (
{rowData.pourcentageUsure}%
{rowData.heuresUtilisation}h / {rowData.seuilMaintenanceHeures}h
); }; const risqueBodyTemplate = (rowData: PlanificationMaintenance) => { const couleur = rowData.risqueDefaillance > 70 ? 'danger' : rowData.risqueDefaillance > 40 ? 'warning' : 'success'; return (
{rowData.risqueDefaillance}%
); }; const prioriteBodyTemplate = (rowData: PlanificationMaintenance) => { const getPrioriteSeverity = (priorite: string) => { switch (priorite) { case 'BASSE': return 'info'; case 'NORMALE': return 'success'; case 'HAUTE': return 'warning'; case 'CRITIQUE': return 'danger'; default: return 'secondary'; } }; return ; }; const impactBodyTemplate = (rowData: PlanificationMaintenance) => { const getImpactSeverity = (impact: string) => { switch (impact) { case 'FAIBLE': return 'info'; case 'MOYEN': return 'warning'; case 'ELEVE': return 'danger'; case 'CRITIQUE': return 'danger'; default: return 'secondary'; } }; return ; }; const dateBodyTemplate = (rowData: PlanificationMaintenance) => { const prochaineMaintenance = new Date(rowData.prochaineMaintenance); const joursRestants = Math.ceil((prochaineMaintenance.getTime() - new Date().getTime()) / (1000 * 3600 * 24)); const isUrgent = joursRestants <= 7; const isRetard = joursRestants < 0; return (
{prochaineMaintenance.toLocaleDateString('fr-FR')} {isRetard ? `Retard: ${Math.abs(joursRestants)} j` : isUrgent ? `Urgent: ${joursRestants} j` : `Dans ${joursRestants} jours`} {rowData.derniereMaintenance && ( Dernière: {new Date(rowData.derniereMaintenance).toLocaleDateString('fr-FR')} )}
); }; const technicienBodyTemplate = (rowData: PlanificationMaintenance) => { if (rowData.technicienRecommande) { return (
{rowData.technicienRecommande.nom}
{rowData.technicienRecommande.specialites.slice(0, 2).map((spec, index) => ( ))}
{rowData.technicienRecommande.disponibilite ? ( ) : ( )}
); } return À assigner; }; const coutBodyTemplate = (rowData: PlanificationMaintenance) => { return (
{rowData.coutEstime.toLocaleString('fr-FR')} € {rowData.dureeEstimee}h estimées
); }; const actionBodyTemplate = (rowData: PlanificationMaintenance) => { return (
); }; const leftToolbarTemplate = () => { return (
); }; const rightToolbarTemplate = () => { return (
); }; const header = (

Planification Automatique de Maintenance

p.prioriteRecommandee === 'CRITIQUE').length} severity="danger" /> Critiques p.pourcentageUsure > 80).length} severity="warning" /> Usure élevée p.risqueDefaillance > 70).length} severity="info" /> Risque élevé
); return (
{/* Paramètres de planification */}
setConfiguration({ ...configuration, periodeAnalyse: e.value })} />
setDateDebutPlanification(e.value as Date)} showIcon dateFormat="dd/mm/yy" />
setDateFinPlanification(e.value as Date)} showIcon dateFormat="dd/mm/yy" />
setConfiguration({ ...configuration, seuilUrgence: e.value || 80 })} min={50} max={95} suffix="%" />
{/* Tableau de planification */}
setSelectedMateriels(e.value)} selectionMode="checkbox" responsiveLayout="scroll" >
{/* Dialog Configuration */} setConfigDialog(false)} footer={
} >

Optimisations

setConfiguration({ ...configuration, optimiserCouts: e.target.checked })} />
setConfiguration({ ...configuration, optimiserDisponibilite: e.target.checked })} />
setConfiguration({ ...configuration, grouperMaintenances: e.target.checked })} />
setConfiguration({ ...configuration, prendreCompteMeteo: e.target.checked })} />
); }; export default PlanificationMaintenancePage;