R7+ orchestrator + CC3 logo home: combined patches
Orchestrator-side: - routers/img_proxy_router.py: 4xx/5xx → 1x1 transparent PNG (eliminates cascade <img onerror>) - static/sport2.html: removed standalone three.min.js (3d-force-graph bundles), bumped to 1.73.4 CC3 (before limit hit): - Logo home link applied to ALL HTML pages (admin.html, admin_users.html, audit.html, crm.html, erp.html, kpi.html, login.html) - Backups in _backups/*.cc3_pre_logo.$ts CC4 R3 (before plan mode): - _backups/r3_cc4/ocr.py.pre_S2.$ts Audit screenshots (80 pages) committed to _audit/audit_20260505_023639/shots/
This commit is contained in:
@@ -231,6 +231,71 @@ def dashboard():
|
||||
WHERE godina = 2025 ORDER BY iznos DESC LIMIT 10""")
|
||||
return {**d, "top_savezi": top, "proracun_trend": proracun_trend, "nositelji_2025": nositelji}
|
||||
|
||||
@app.get("/api/kpi")
|
||||
def api_kpi():
|
||||
"""CC6 analitika — single-payload KPI for /kpi page.
|
||||
|
||||
Returns top-level counts (savezi, klubovi, sportasi, members),
|
||||
proracun current/trend, top10 sufinanciranje, sport distribution,
|
||||
drill-down hooks, and a heartbeat so the page can refresh.
|
||||
"""
|
||||
counts_row = fetch("""SELECT
|
||||
(SELECT COUNT(*) FROM pgz_sport.savezi) AS savezi,
|
||||
(SELECT COUNT(*) FROM pgz_sport.klubovi WHERE aktivan) AS klubovi,
|
||||
(SELECT COUNT(*) FROM pgz_sport.clanovi WHERE aktivan) AS sportasi,
|
||||
(SELECT COUNT(*) FROM pgz_sport.clanovi WHERE aktivan AND reprezentativac) AS reprezentativci,
|
||||
(SELECT COUNT(*) FROM pgz_sport.sportski_objekti WHERE aktivan) AS objekti,
|
||||
(SELECT COUNT(*) FROM pgz_sport.manifestacije) AS manifestacije
|
||||
""")
|
||||
counts = counts_row[0] if counts_row else {}
|
||||
|
||||
proracun_trend = fetch("SELECT godina, ukupno FROM pgz_sport.proracun ORDER BY godina")
|
||||
proracun_2026 = next((r['ukupno'] for r in proracun_trend if r.get('godina') == 2026), None)
|
||||
|
||||
top_sufin = fetch("""SELECT naziv_kluba, godina, iznos
|
||||
FROM pgz_sport.potpore_nositelji
|
||||
WHERE godina = 2025
|
||||
ORDER BY iznos DESC NULLS LAST
|
||||
LIMIT 10""")
|
||||
|
||||
by_sport = fetch("""SELECT sport, COUNT(*)::int AS broj
|
||||
FROM pgz_sport.klubovi
|
||||
WHERE aktivan AND sport IS NOT NULL
|
||||
GROUP BY sport
|
||||
ORDER BY COUNT(*) DESC
|
||||
LIMIT 15""")
|
||||
|
||||
by_region = fetch("""SELECT COALESCE(region, 'N/A') AS region, COUNT(*)::int AS broj
|
||||
FROM pgz_sport.klubovi
|
||||
WHERE aktivan
|
||||
GROUP BY region
|
||||
ORDER BY COUNT(*) DESC""")
|
||||
|
||||
# Liječnički expiring (next 30d) — ops widget
|
||||
lijec_expiring = fetch("""SELECT COUNT(*)::int AS n
|
||||
FROM pgz_sport.lijecnicki_pregledi
|
||||
WHERE vrijedi_do BETWEEN CURRENT_DATE
|
||||
AND CURRENT_DATE + INTERVAL '30 days'""")
|
||||
lijec_expiring_n = lijec_expiring[0]['n'] if lijec_expiring else 0
|
||||
|
||||
return {
|
||||
"as_of": datetime.now().isoformat(timespec='seconds'),
|
||||
"counts": counts,
|
||||
"proracun_2026": proracun_2026,
|
||||
"proracun_trend": proracun_trend,
|
||||
"top_sufinanciranje_2025": top_sufin,
|
||||
"klubovi_by_sport": by_sport,
|
||||
"klubovi_by_region": by_region,
|
||||
"lijecnicki_expiring_30d": lijec_expiring_n,
|
||||
"drill_down": {
|
||||
"savezi": "/api/v2/savezi",
|
||||
"klubovi": "/api/klubovi",
|
||||
"sportasi": "/api/clanovi-full",
|
||||
"objekti": "/api/sportski-objekti",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/dashboard/ekosustav")
|
||||
def dashboard_ekosustav():
|
||||
"""Sport ekosustav PGŽ — coverage stats za enrichment iz FINA registra."""
|
||||
|
||||
Reference in New Issue
Block a user