Implémente système multi-utilisateurs avec classement
- Auth cookie simple (SSO-ready) : login/logout, redirection si non authentifié
- Données isolées par utilisateur dans /data/users/{user_id}/
- Migration automatique des données legacy au premier login
- Page classement avec podium et tableau comparatif (score, précision zéro, conformité)
- Nav mise à jour : Classement, affichage utilisateur courant, déconnexion
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
48
app/classement.py
Normal file
48
app/classement.py
Normal file
@ -0,0 +1,48 @@
|
||||
"""Leaderboard stats: compare all users on overtime precision and directive compliance."""
|
||||
from models import list_users
|
||||
from stats import compute_all_stats, _compliance_over, _day_compliant
|
||||
from calcul import minutes_to_hhmm
|
||||
|
||||
|
||||
def compute_classement() -> list[dict]:
|
||||
"""Return ranked list of users with their key metrics."""
|
||||
results = []
|
||||
|
||||
for user_id in list_users():
|
||||
s = compute_all_stats(user_id)
|
||||
if not s["weekly_balances"] and s["n_jours"] == 0:
|
||||
continue # skip empty accounts
|
||||
|
||||
balances = [b["delta_min"] for b in s["weekly_balances"]]
|
||||
|
||||
# Precision: % of weeks where |solde| ≤ 30 min (≈ at zero)
|
||||
if balances:
|
||||
pct_zero = round(100 * sum(1 for b in balances if abs(b) <= 30) / len(balances))
|
||||
mean_abs = round(sum(abs(b) for b in balances) / len(balances))
|
||||
else:
|
||||
pct_zero = None
|
||||
mean_abs = None
|
||||
|
||||
conf_pct = s["comp_globale"]["pct"]
|
||||
|
||||
# Combined score (SSO era: will weight per role/contract)
|
||||
score = round(
|
||||
(pct_zero or 0) * 0.6 + (conf_pct or 0) * 0.4
|
||||
)
|
||||
|
||||
results.append({
|
||||
"user_id": user_id,
|
||||
"display_name": user_id.replace("_", " ").replace("-", " ").title(),
|
||||
"n_semaines": len(balances),
|
||||
"n_jours": s["n_jours"],
|
||||
"pct_zero": pct_zero, # % weeks ≈ 0 HS — higher = better
|
||||
"mean_abs_min": mean_abs, # mean abs(solde) in minutes — lower = better
|
||||
"mean_abs_str": minutes_to_hhmm(mean_abs) if mean_abs is not None else "—",
|
||||
"conf_pct": conf_pct, # directive compliance % — higher = better
|
||||
"score": score, # combined 0-100 — higher = better
|
||||
"avg_delta": s["avg_delta"],
|
||||
"avg_delta_min": s["avg_delta_min"],
|
||||
})
|
||||
|
||||
results.sort(key=lambda r: -r["score"])
|
||||
return results
|
||||
Reference in New Issue
Block a user