Slika 3: Savez 3 KPI (ukupna potpora, sportaša, dokumenata)

Endpoint:
- /api/v2/savez/{id}/kpi (ukupna_potpora, broj_sportasa, broj_klubova, najvisi_rang, broj_dokumenata, broj_manifestacija)

Frontend sport2.html:
- loadSavezKpi() function
- Auto-call after openSavez(id) panel render
This commit is contained in:
2026-05-05 18:24:05 +02:00
parent 7608839473
commit 8127e2ef22
3 changed files with 31 additions and 8 deletions
+23 -1
View File
@@ -2531,7 +2531,9 @@ def sportasi_filtered(sport: str = None, klub_id: int = None, kategorija: str =
rows = fetch(f""" rows = fetch(f"""
SELECT c.id, c.ime, c.prezime, c.spol, c.datum_rodenja, c.godina_rodenja, SELECT c.id, c.ime, c.prezime, c.spol, c.datum_rodenja, c.godina_rodenja,
c.kategorija, c.pozicija, c.sport, c.klub_id, k.naziv AS klub_naziv, c.kategorija, c.pozicija, c.sport, c.klub_id, k.naziv AS klub_naziv,
c.hns_igrac_id, c.source, c.source_url c.hns_igrac_id, c.source, c.source_url, c.slika_url,
c.reprezentativac, c.kategoriziran, c.stipendiran, c.aktivan,
c.hoo_kategorija, c.broj_dresa
FROM pgz_sport.clanovi c FROM pgz_sport.clanovi c
LEFT JOIN pgz_sport.klubovi k ON k.id = c.klub_id LEFT JOIN pgz_sport.klubovi k ON k.id = c.klub_id
{where_sql} {where_sql}
@@ -2762,6 +2764,26 @@ def export_klubovi_roster_xlsx(klub_id: Optional[int] = None, sport: Optional[st
) )
@app.get("/api/v2/savez/{savez_id}/kpi")
def savez_kpi(savez_id: int, godina: int = None):
"""KPI metrike za savez: ukupna potpora, broj sportaša, najviši rang."""
rows = fetch("""
SELECT
(SELECT COALESCE(SUM(pn.iznos), 0)::numeric(12,2) FROM pgz_sport.potpore_nositelji pn
JOIN pgz_sport.klubovi k ON k.id = pn.klub_id
WHERE k.savez_id = %s) AS ukupna_potpora,
(SELECT count(DISTINCT c.id) FROM pgz_sport.clanovi c
JOIN pgz_sport.klubovi k ON k.id = c.klub_id
WHERE k.savez_id = %s AND c.aktivan = true) AS broj_sportasa,
(SELECT count(DISTINCT k.id) FROM pgz_sport.klubovi k WHERE k.savez_id = %s AND k.aktivan = true) AS broj_klubova,
(SELECT COALESCE(MIN(k.razina), 'n/a') FROM pgz_sport.klubovi k
WHERE k.savez_id = %s AND k.razina IS NOT NULL AND k.razina <> '') AS najvisi_rang,
(SELECT count(*) FROM pgz_sport.dokumenti d WHERE d.savez_id = %s) AS broj_dokumenata,
(SELECT count(*) FROM pgz_sport.manifestacije m WHERE m.savez_id = %s) AS broj_manifestacija
""", (savez_id, savez_id, savez_id, savez_id, savez_id, savez_id))
return rows[0] if rows else {}
@app.get("/") @app.get("/")
def root(request: Request): def root(request: Request):
host = request.headers.get("host", "") host = request.headers.get("host", "")
+7 -7
View File
@@ -5990,23 +5990,23 @@ def manifestacije_meta():
@router.get("/manifestacije") @router.get("/manifestacije")
def manifestacije_list(mjesto: str = None, razina: str = None, organizator: str = None, q: str = None, limit: int = 200): def manifestacije_list(mjesto: str = None, razina: str = None, organizator: str = None, q: str = None, limit: int = 200):
"""Lista manifestacija s filterima.""" """Lista manifestacija s filterima."""
where = ["aktivna = true"] where = ["m.aktivna = true"]
params = [] params = []
if mjesto: if mjesto:
where.append("mjesto = %s") where.append("m.mjesto = %s")
params.append(mjesto) params.append(mjesto)
if razina: if razina:
where.append("razina = %s") where.append("m.razina = %s")
params.append(razina) params.append(razina)
if organizator: if organizator:
where.append("organizator ILIKE %s") where.append("m.organizator ILIKE %s")
params.append(f"%{organizator}%") params.append(f"%{organizator}%")
if q: if q:
where.append("(naziv ILIKE %s OR napomena ILIKE %s)") where.append("(m.naziv ILIKE %s OR m.napomena ILIKE %s)")
params.extend([f"%{q}%", f"%{q}%"]) params.extend([f"%{q}%", f"%{q}%"])
rows = db_query(f""" rows = db_query(f"""
SELECT m.id, m.naziv, m.mjesto, m.organizator, m.razina, m.broj_ucesnika, SELECT m.id, m.naziv, m.mjesto, m.organizator, m.razina, m.broj_ucesnika,
m.godina_od, m.spol_kategorija, m.napomena, m.source_url, m.godina_od, m.spol_kategorija, m.napomena, m.source_url,
s.naziv AS savez_naziv, s.id AS savez_id s.naziv AS savez_naziv, s.id AS savez_id
FROM pgz_sport.manifestacije m FROM pgz_sport.manifestacije m
+1
View File
@@ -1466,6 +1466,7 @@ function renderSaveziTable(rows){
async function openSavez(id){ async function openSavez(id){
openPanel('Savez', '<div class="loading">Učitavanje saveza…</div>'); openPanel('Savez', '<div class="loading">Učitavanje saveza…</div>');
setTimeout(() => loadSavezKpi(id), 100);
const s = await api('/savezi/'+id); const s = await api('/savezi/'+id);
if(!s || s.detail){ if(!s || s.detail){
openPanel('Savez', '<div class="empty">Savez nije pronađen</div>'); openPanel('Savez', '<div class="empty">Savez nije pronađen</div>');