대시보드 — 충전기별 에러코드 누적 순위 차트 추가
- /api/stats/charger-error-codes 엔드포인트 추가 (Top 10 충전기 × Top 6 에러코드 stacked bar, 나머지 기타로 합산) - dashboard.html: 에러코드 누적 순위 가로 스택 바 차트 카드 추가 (클릭 시 해당 충전기 신고 목록으로 이동) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -540,3 +540,66 @@ def stats_top_chargers(limit: int = 10):
|
||||
]
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@app.get("/api/stats/charger-error-codes")
|
||||
def stats_charger_error_codes(charger_limit: int = 10, code_limit: int = 6):
|
||||
"""충전기별 에러코드 누적 건수 Top N (에러코드 입력된 신고 기준)."""
|
||||
from database import SessionLocal
|
||||
from sqlalchemy import text
|
||||
from collections import defaultdict
|
||||
db = SessionLocal()
|
||||
try:
|
||||
rows = db.execute(text("""
|
||||
SELECT rep.charger_id,
|
||||
COALESCE(c.station_name, rep.charger_id) AS station_name,
|
||||
COALESCE(c.name, '') AS charger_name,
|
||||
TRIM(rep.error_code) AS error_code,
|
||||
COUNT(*) AS cnt
|
||||
FROM reports rep
|
||||
LEFT JOIN chargers c ON c.id = rep.charger_id
|
||||
WHERE rep.error_code IS NOT NULL
|
||||
AND TRIM(rep.error_code) != ''
|
||||
GROUP BY rep.charger_id, c.station_name, c.name, TRIM(rep.error_code)
|
||||
""")).fetchall()
|
||||
|
||||
if not rows:
|
||||
return {"chargers": [], "error_codes": []}
|
||||
|
||||
charger_info = {}
|
||||
code_totals = defaultdict(int)
|
||||
|
||||
for row in rows:
|
||||
cid, sname, cname, ecode, cnt = row
|
||||
cnt = int(cnt)
|
||||
if cid not in charger_info:
|
||||
charger_info[cid] = {"station_name": sname, "charger_name": cname,
|
||||
"total": 0, "errors": {}}
|
||||
charger_info[cid]["total"] += cnt
|
||||
charger_info[cid]["errors"][ecode] = cnt
|
||||
code_totals[ecode] += cnt
|
||||
|
||||
top_chargers = sorted(charger_info.items(), key=lambda x: -x[1]["total"])[:charger_limit]
|
||||
top_codes = [c for c, _ in sorted(code_totals.items(), key=lambda x: -x[1])[:code_limit]]
|
||||
|
||||
result = []
|
||||
for cid, info in reversed(top_chargers): # 역순: 차트에서 1위가 위에
|
||||
label = info["station_name"]
|
||||
if info["charger_name"]:
|
||||
label += f" ({info['charger_name']})"
|
||||
if len(label) > 22:
|
||||
label = label[:20] + "…"
|
||||
errors = info["errors"]
|
||||
other = sum(cnt for code, cnt in errors.items() if code not in top_codes)
|
||||
entry = {"charger_id": cid, "label": label, "total": info["total"]}
|
||||
for code in top_codes:
|
||||
entry[code] = errors.get(code, 0)
|
||||
if other:
|
||||
entry["기타"] = other
|
||||
result.append(entry)
|
||||
|
||||
has_other = any(r.get("기타", 0) > 0 for r in result)
|
||||
all_codes = top_codes + (["기타"] if has_other else [])
|
||||
return {"chargers": result, "error_codes": all_codes}
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
Reference in New Issue
Block a user