Checkpoint: Ajout d'un tableau de bord détaillé avec statistiques avancées et graphiques.

Nouvelles fonctionnalités :
- Cartes de statistiques : Factures traitées, Montant total, Score moyen, Dernière activité
- Graphique en barres : Évolution des factures par semaine (30 derniers jours)
- Graphique circulaire : Top 10 fournisseurs avec pourcentages
- Liste détaillée : Tous les fournisseurs avec nombre de factures et montants
- Bouton "Voir les statistiques détaillées" pour afficher/masquer les graphiques
- Calculs automatiques : montant moyen par facture, score de qualité avec label (Excellent/Bon/Moyen/Faible)

Le dashboard utilise Recharts pour les visualisations et offre une vue complète de l'activité de traitement des factures.
This commit is contained in:
Manus
2026-01-08 08:56:35 -05:00
parent a56e6c58f4
commit a237057b77
3 changed files with 320 additions and 84 deletions

View File

@@ -252,14 +252,97 @@ export async function searchInvoices(userId: number, query: string): Promise<Inv
export async function getInvoiceStats(userId: number) {
const db = await getDb();
if (!db) return { total: 0, completed: 0, processing: 0, error: 0 };
if (!db) return {
total: 0,
completed: 0,
processing: 0,
error: 0,
totalAmount: 0,
averageScore: 0,
lastActivity: null,
weeklyData: [],
topSuppliers: [],
suppliersList: []
};
const allInvoices = await getInvoicesByUserId(userId);
// Calculate basic stats
const completed = allInvoices.filter(i => i.status === "completed");
const totalAmount = completed.reduce((sum, inv) => sum + (Number(inv.totalAmount) || 0), 0);
const averageScore = completed.length > 0
? completed.reduce((sum, inv) => sum + (inv.qualityScore || 0), 0) / completed.length
: 0;
// Get last activity
const sortedByDate = [...allInvoices].sort((a, b) =>
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
);
const lastActivity = sortedByDate[0]?.createdAt || null;
// Calculate weekly data (last 30 days)
const now = new Date();
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
const weeklyMap = new Map<string, number>();
allInvoices.forEach(inv => {
const date = new Date(inv.createdAt);
if (date >= thirtyDaysAgo) {
const weekStart = new Date(date);
weekStart.setDate(date.getDate() - date.getDay()); // Start of week
const weekKey = `${weekStart.getDate().toString().padStart(2, '0')}/${(weekStart.getMonth() + 1).toString().padStart(2, '0')}`;
weeklyMap.set(weekKey, (weeklyMap.get(weekKey) || 0) + 1);
}
});
const weeklyData = Array.from(weeklyMap.entries())
.map(([week, count]) => ({ week, count }))
.sort((a, b) => {
const [dayA, monthA] = a.week.split('/').map(Number);
const [dayB, monthB] = b.week.split('/').map(Number);
return (monthA! * 100 + dayA!) - (monthB! * 100 + dayB!);
});
// Calculate top suppliers
const supplierMap = new Map<string, { count: number; amount: number }>();
completed.forEach(inv => {
const supplier = inv.supplierName || 'Inconnu';
const current = supplierMap.get(supplier) || { count: 0, amount: 0 };
supplierMap.set(supplier, {
count: current.count + 1,
amount: current.amount + (Number(inv.totalAmount) || 0)
});
});
const topSuppliers = Array.from(supplierMap.entries())
.map(([name, data]) => ({
name,
count: data.count,
amount: data.amount,
percentage: completed.length > 0 ? (data.count / completed.length * 100) : 0
}))
.sort((a, b) => b.count - a.count)
.slice(0, 10);
const suppliersList = Array.from(supplierMap.entries())
.map(([name, data]) => ({
name,
count: data.count,
amount: data.amount
}))
.sort((a, b) => b.count - a.count);
return {
total: allInvoices.length,
completed: allInvoices.filter(i => i.status === "completed").length,
completed: completed.length,
processing: allInvoices.filter(i => i.status === "processing").length,
error: allInvoices.filter(i => i.status === "error").length,
totalAmount,
averageScore: Math.round(averageScore),
lastActivity,
weeklyData,
topSuppliers,
suppliersList
};
}