mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-14 02:37:55 +02:00
feat: Implement dashboard layout, shared sidebar, AI copilot analysis and scoring engines, and a grid floating summary bar.
This commit is contained in:
1 parent
a092572829
commit
9d8ef0e4db
5 files changed
+100
-27
No files matched your search
@@ -15,13 +15,14 @@ Le score (0 à 100) est une mesure de performance RELATIVE au sein du rayon.
|
||||
--- TON RÔLE ---
|
||||
1. JUSTIFIER : Explique le score de manière purement factuelle, "ligne par ligne", en te basant UNIQUEMENT sur : le CA, la Quantité vendue, la Marge, le Poids Fournisseur (importance du produit pour ce fournisseur) et le Poids Rayon / Nomenclature (importance du produit dans le rayon).
|
||||
2. EXPLIQUER LE VERDICT [A] : Si le verdict est [A] malgré un score faible, c'est une PROTECTION MÉTIER (ex: Produit Récent, Leader Fournisseur, Dernier Produit). Explique cette protection avec bienveillance.
|
||||
3. INTERDICTION : Ne mentionne JAMAIS de tendances mensuelles, historiques, prédictions ou notions de temps. Ne calcule pas de variations. Reste strictement concentrée sur la photographie des indicateurs globaux fournis.
|
||||
4. CONCISE : 2 phrases maximum. Évite le jargon de data-scientist.
|
||||
3. EXPLIQUER LE VERDICT [Z] : Si le verdict est [Z] malgré de bons KPIs, c'est souvent dû à une RÈGLE D'EXCLUSION ABSOLUE (ex: Note Globale < 20). Justifie dans ce cas par l'insuffisance critique de la performance globale du produit.
|
||||
4. INTERDICTION : Ne mentionne JAMAIS de tendances mensuelles, historiques, prédictions ou notions de temps. Ne calcule pas de variations. Reste strictement concentrée sur la photographie des indicateurs globaux fournis.
|
||||
5. CONCISE : 2 phrases maximum. Évite le jargon de data-scientist.
|
||||
|
||||
--- FORMAT ATTENDU ---
|
||||
"[Recommandation] : [Justification factuelle incluant le Score et les poids/axes clés]"
|
||||
Exemple : "[A] : Score de 85/100 porté par une forte marge (45%) et un poids important dans le rayon (15% des quantités)."
|
||||
Exemple : "[Z] : Score très faible (12/100) en raison d'un CA marginal malgré un bon taux de marge, le produit pesant moins de 1% chez son fournisseur."`;
|
||||
Exemple : "[Z] : Rétrogradé car la note globale (15/100) est critique, malgré un volume de vente acceptable au sein du rayon."`;
|
||||
}
|
||||
|
||||
static generateUserMessage(p: ProductAnalysisInput): string {
|
||||
|
||||
@@ -106,6 +106,12 @@ export class ScoringEngine {
|
||||
finalLabel = "Dernière Réf Fournisseur (Protégée)";
|
||||
}
|
||||
|
||||
// Règle d'exclusion absolue (Demande Utilisateur) : Aucun produit de note < 20 en Gamme A
|
||||
if (target.score !== undefined && target.score < 20) {
|
||||
recommendation = "Z";
|
||||
finalLabel = "Note Globale Critique (< 20)";
|
||||
}
|
||||
|
||||
return {
|
||||
compositeScore: Math.round(compositeScore * 100),
|
||||
percentiles: { ca: pCa, volume: pVol, marge: pMarge },
|
||||
|
||||
@@ -114,28 +114,33 @@ export function FloatingSummaryBar() {
|
||||
borderColor: hasDrafts ? "rgba(234, 179, 8, 0.5)" : "var(--border-strong)",
|
||||
}}
|
||||
>
|
||||
<div className="text-xs font-bold px-4 py-2 rounded-full border flex items-center bg-white dark:bg-slate-900 border-slate-200 dark:border-slate-800 text-slate-500">
|
||||
<div className="flex items-center bg-white dark:bg-slate-900 shadow-sm border border-slate-200 dark:border-slate-800 rounded-full px-1.5 py-1.5 h-10">
|
||||
<button
|
||||
onClick={handleReset}
|
||||
className="p-1.5 hover:bg-rose-50 dark:hover:bg-rose-900/20 text-slate-400 hover:text-rose-500 transition-colors rounded-lg border border-transparent hover:border-rose-200"
|
||||
className="w-7 h-7 flex items-center justify-center text-slate-400 hover:text-slate-600 dark:hover:text-slate-300 transition-colors rounded-full"
|
||||
title="Réinitialiser la page"
|
||||
>
|
||||
<RotateCcw className="w-4 h-4" />
|
||||
</button>
|
||||
<div className="w-[1px] h-4 bg-slate-200 dark:bg-slate-800 mx-1.5" />
|
||||
|
||||
<div className="w-px h-4 bg-slate-200 dark:bg-slate-700 mx-1" />
|
||||
|
||||
<button
|
||||
onClick={() => handleSnapshot()}
|
||||
disabled={isSavingSnapshot}
|
||||
className="p-1.5 hover:bg-indigo-50 dark:hover:bg-indigo-900/20 text-slate-400 hover:text-indigo-500 transition-colors rounded-lg border border-transparent hover:border-indigo-200 disabled:opacity-50"
|
||||
className="w-7 h-7 flex items-center justify-center text-slate-400 hover:text-slate-600 dark:hover:text-slate-300 transition-colors rounded-full disabled:opacity-50"
|
||||
title="Prendre un snapshot de la session"
|
||||
>
|
||||
{isSavingSnapshot ? <Loader2 className="w-4 h-4 animate-spin" /> : <Camera className="w-4 h-4" />}
|
||||
</button>
|
||||
<div className="w-[1px] h-4 bg-slate-200 dark:bg-slate-800 mx-1.5" />
|
||||
|
||||
{hasDrafts && (
|
||||
<span className="text-[12px] font-black tracking-tight text-[#b45309] bg-[#fef08a] px-3 py-1 rounded-md border border-[#fde047] ml-2">
|
||||
{count} MODIF.
|
||||
</span>
|
||||
<>
|
||||
<div className="w-px h-4 bg-slate-200 dark:bg-slate-700 mx-1" />
|
||||
<span className="ml-1 px-3 h-7 flex items-center justify-center rounded-full text-[11px] font-black tracking-wide text-[#b45309] dark:text-[#78350f] bg-[#fdf08a] hover:bg-[#fde047] transition-colors border border-[#fde047]/50 shadow-sm uppercase">
|
||||
{count} MODIF.
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in new issue
Block a user