Nouvelle page /dashboard/repartition, renomme "Dashboard" en "SAS" dans le menu
Nouvelle page "Répartition/Soldes" entre "SAS" (ex-"Dashboard") et "Par compte" dans le menu : reprend "Solde par compte" et "Évolution du solde par compte", retirés du dashboard général pour le recentrer sur l'activité/CA/type/client. Mêmes données déjà exposées par /dashboard/api/stats (solde_par_compte, solde_par_compte_par_annee), aucun changement backend nécessaire pour cette page. js/dashboard-repartition.js reprend le HBarChart/MiniTrend de dashboard.js -- dupliqués plutôt que partagés, même convention que dashboard-compte.js. Racine Vue volontairement le même id #figli-dashboard-app que les deux autres pages dashboard (pas un id dédié) : dashboard.css scope ses variables CSS (thème clair/sombre) sur ce sélecteur, réutiliser le même id est comment les trois pages héritent du même thème sans feuille de style séparée -- vérifié en dark mode. Le lien de menu "Dashboard" devient "SAS" partout (les 3 templates Twig + le nav en render array de HistoryController, qui n'a pas de template Twig propre). dashboard.js : MiniTrend/soldeParCompteItems/comptesOrdonnes/ trendValues supprimés (code mort après le déplacement, plus rien ne les utilise sur le dashboard général).
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
/**
|
||||
* @file
|
||||
* Dashboard: charts and aggregate totals (solde par compte, chiffre
|
||||
* d'affaires par année, répartition par type, top clients), computed
|
||||
* server-side (DashboardStatsController -- plain SQL GROUP BY, not Entity
|
||||
* API) and rendered here as small dependency-free div/CSS bar charts. No
|
||||
* charting library: this project vendors its own JS (see js/vendor/), and
|
||||
* a handful of bar/line charts don't warrant pulling one in.
|
||||
* Dashboard: charts and aggregate totals (chiffre d'affaires par année,
|
||||
* répartition par type, top clients), computed server-side
|
||||
* (DashboardStatsController -- plain SQL GROUP BY, not Entity API) and
|
||||
* rendered here as small dependency-free div/CSS bar charts. No charting
|
||||
* library: this project vendors its own JS (see js/vendor/), and a
|
||||
* handful of bar/line charts don't warrant pulling one in. Solde par
|
||||
* compte lives on its own page (js/dashboard-repartition.js).
|
||||
*/
|
||||
(function (Drupal, Vue) {
|
||||
'use strict';
|
||||
@@ -125,41 +126,8 @@
|
||||
'</div>',
|
||||
};
|
||||
|
||||
// Small multiples: one compact zero-centered bar-per-year trend per
|
||||
// compte, instead of a single 8-series line chart -- eight overlapping
|
||||
// lines sharing one small area is hard to read; eight small independent
|
||||
// trends, each answering "is this person's balance growing or
|
||||
// shrinking", is not.
|
||||
const MiniTrend = {
|
||||
props: {
|
||||
annees: { type: Array, required: true },
|
||||
values: { type: Array, required: true },
|
||||
formatValue: { type: Function, required: true },
|
||||
},
|
||||
computed: {
|
||||
maxAbs() {
|
||||
return Math.max(1, ...this.values.filter((v) => v !== null).map((v) => Math.abs(v)));
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
barHeight(v) {
|
||||
if (v === null) return '0%';
|
||||
return Math.max(3, (Math.abs(v) / this.maxAbs) * 100) + '%';
|
||||
},
|
||||
},
|
||||
template:
|
||||
'<div class="figli-mini-trend">' +
|
||||
'<div class="figli-mini-bar-col" v-for="(v, i) in values" :key="annees[i]" :title="annees[i] + \' : \' + (v === null ? \'—\' : formatValue(v))">' +
|
||||
'<div class="figli-mini-bar-track">' +
|
||||
'<div class="figli-mini-bar-fill" :class="v !== null && v < 0 ? \'is-negative\' : \'is-positive\'" :style="{height: barHeight(v)}"></div>' +
|
||||
'</div>' +
|
||||
'<div class="figli-mini-bar-label">{{ annees[i].slice(2) }}</div>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
};
|
||||
|
||||
const App = {
|
||||
components: { HBarChart, ColumnChart: VBarChart, MiniTrend },
|
||||
components: { HBarChart, ColumnChart: VBarChart },
|
||||
data() {
|
||||
return { loading: true, error: null, stats: null };
|
||||
},
|
||||
@@ -168,12 +136,6 @@
|
||||
if (!this.stats) return [];
|
||||
return this.stats.annees.map((y) => ({ label: y, value: this.stats.ca_par_annee[y] || 0 }));
|
||||
},
|
||||
soldeParCompteItems() {
|
||||
if (!this.stats) return [];
|
||||
return Object.entries(this.stats.solde_par_compte)
|
||||
.map(([label, value]) => ({ label, value }))
|
||||
.sort((a, b) => b.value - a.value);
|
||||
},
|
||||
typeItems() {
|
||||
if (!this.stats) return [];
|
||||
return Object.entries(this.stats.total_par_type)
|
||||
@@ -214,13 +176,6 @@
|
||||
return { annee, items };
|
||||
}).filter((y) => y.items.length);
|
||||
},
|
||||
// Comptes ordered by all-time solde (richest first) -- same order
|
||||
// as soldeParCompteItems, so the trend grid below reads as a
|
||||
// continuation of the bar chart above it rather than an unrelated
|
||||
// shuffle.
|
||||
comptesOrdonnes() {
|
||||
return this.soldeParCompteItems.map((i) => i.label);
|
||||
},
|
||||
totalCA() {
|
||||
if (!this.stats) return 0;
|
||||
return Object.values(this.stats.ca_par_annee).reduce((a, b) => a + b, 0);
|
||||
@@ -242,12 +197,6 @@
|
||||
formatEurRound(v) {
|
||||
return EUR_ROUND.format(v);
|
||||
},
|
||||
trendValues(compte) {
|
||||
return this.stats.annees.map((y) => {
|
||||
const parAnnee = this.stats.solde_par_compte_par_annee[y];
|
||||
return parAnnee && parAnnee[compte] !== undefined ? parAnnee[compte] : null;
|
||||
});
|
||||
},
|
||||
typeColor(item) {
|
||||
return TYPE_COLORS[item.type] || '#6b7280';
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user