diff --git a/client/src/pages/DsiOpex.tsx b/client/src/pages/DsiOpex.tsx index d5daa77..9f4f3fd 100644 --- a/client/src/pages/DsiOpex.tsx +++ b/client/src/pages/DsiOpex.tsx @@ -1159,101 +1159,125 @@ export default function DsiOpex() { - {/* Répartition par catégorie */} -
-

- - Répartition par catégorie — {annee} -

-
- {Object.entries(totalParCategorie) - .filter(([, v]) => v > 0) - .sort(([, a], [, b]) => b - a) - .map(([cat, montant]) => { - const pct = totalGlobal > 0 ? (montant / totalGlobal) * 100 : 0; - const colors = getCatColors(cat); - return ( -
- - {cat} - -
-
-
- - {formatEuros(montant)} - - - {pct.toFixed(1)}% - -
- ); - })} -
-
+
)} {/* === VUE PAR ÉTABLISSEMENT === */} {viewMode === 'etablissements' && ( -
- - - - - - - {opexData2026.postes.slice(0, showDetails ? 8 : 4).map(p => ( - - ))} - - - - - {sortedEtabs.map((etab, idx) => ( - - - - - {opexData2026.postes.slice(0, showDetails ? 8 : 4).map(p => ( - +
+ {/* Légende code couleur */} +
+
+ + Calcul automatique (prorata classe 6) +
+
+ + Saisie manuelle +
+
+ + {/* Tableau scrollable horizontalement avec tous les postes */} +
+
+
Code - - Base répartition - {p.libelle.split(' ').slice(0, 3).join(' ')} - - -
- {etab.code} - {etab.nom} - {etab.base_repartition > 0 - ? new Intl.NumberFormat('fr-FR', { maximumFractionDigits: 0 }).format(etab.base_repartition) + ' €' - : '—'} - - {etab.montants[p.libelle] > 0 - ? new Intl.NumberFormat('fr-FR', { maximumFractionDigits: 0 }).format(Math.round(etab.montants[p.libelle])) + ' €' - : '—'} -
+ + + + + {/* Colonnes postes — vert = prorata auto, bleu = manuel */} + {opexState.lignes.map(ligne => { + const srcPoste = getOpexDataForAnnee(annee).postes.find(p => p.libelle === ligne.libelle); + const isManuel = srcPoste?.mode_ventilation === 'Manuel' || ligne.isCustom; + return ( + + ); + })} + + + + + {sortedEtabs.map((etab, idx) => ( + + + + {opexState.lignes.map(ligne => { + const srcPoste = getOpexDataForAnnee(annee).postes.find(p => p.libelle === ligne.libelle); + const isManuel = srcPoste?.mode_ventilation === 'Manuel' || ligne.isCustom; + const montant = etab.montants[ligne.libelle] ?? 0; + return ( + + ); + })} + + ))} - - - ))} - - - - - - - - -
Code + + + + {ligne.libelle.length > 18 ? ligne.libelle.slice(0, 16) + '…' : ligne.libelle} + + {formatEuros(ligne.montant)} + + +
+ {etab.code} + {etab.nom} + {montant > 0 + ? new Intl.NumberFormat('fr-FR', { maximumFractionDigits: 0 }).format(montant) + ' €' + : } + + 0 ? 'text-orange-600' : 'text-muted-foreground'}> + {etab.total > 0 ? formatEuros(etab.total) : '—'} + +
- 0 ? 'text-orange-600' : 'text-muted-foreground'}> - {etab.total > 0 ? formatEuros(etab.total) : '—'} - -
- TOTAL — {sortedEtabs.length} établissements - TOTAL - {formatEuros(sortedEtabs.reduce((s, e) => s + e.total, 0))} -
+ + + + + TOTAL — {sortedEtabs.length} établissements + + {opexState.lignes.map(ligne => { + const srcPoste = getOpexDataForAnnee(annee).postes.find(p => p.libelle === ligne.libelle); + const isManuel = srcPoste?.mode_ventilation === 'Manuel' || ligne.isCustom; + const totalColonne = sortedEtabs.reduce((s, e) => s + (e.montants[ligne.libelle] ?? 0), 0); + return ( + + {totalColonne > 0 + ? new Intl.NumberFormat('fr-FR', { maximumFractionDigits: 0 }).format(totalColonne) + ' €' + : '—'} + + ); + })} + + {formatEuros(sortedEtabs.reduce((s, e) => s + e.total, 0))} + + + + +
+ )}