UI 개선 — 모바일 사진 업로드 카메라/갤러리 버튼 분리, 에러코드 차트 단순화
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -543,77 +543,22 @@ def stats_top_chargers(limit: int = 10):
|
||||
|
||||
|
||||
@app.get("/api/stats/charger-error-codes")
|
||||
def stats_charger_error_codes(code_limit: int = 10, charger_limit: int = 5):
|
||||
"""에러코드별 누적 건수 Top N (어느 충전기에서 발생했는지 함께 반환)."""
|
||||
def stats_charger_error_codes(code_limit: int = 10):
|
||||
"""에러코드별 누적 건수 Top N (단순 순위)."""
|
||||
from database import SessionLocal
|
||||
from sqlalchemy import text
|
||||
from collections import defaultdict
|
||||
db = SessionLocal()
|
||||
try:
|
||||
rows = db.execute(text("""
|
||||
SELECT TRIM(rep.error_code) AS error_code,
|
||||
rep.charger_id,
|
||||
COALESCE(c.station_name, rep.charger_id) AS station_name,
|
||||
COALESCE(c.name, '') AS charger_name,
|
||||
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 TRIM(rep.error_code), rep.charger_id, c.station_name, c.name
|
||||
""")).fetchall()
|
||||
|
||||
if not rows:
|
||||
return {"error_codes": [], "charger_labels": {}}
|
||||
|
||||
# error_code → {total, chargers: {cid: cnt}}
|
||||
code_info = {}
|
||||
# charger_id → label, total across all codes
|
||||
charger_info = {}
|
||||
|
||||
for ecode, cid, sname, cname, cnt in rows:
|
||||
cnt = int(cnt)
|
||||
if ecode not in code_info:
|
||||
code_info[ecode] = {"total": 0, "chargers": {}}
|
||||
code_info[ecode]["total"] += cnt
|
||||
code_info[ecode]["chargers"][cid] = cnt
|
||||
|
||||
if cid not in charger_info:
|
||||
label = sname + (f" ({cname})" if cname else "")
|
||||
if len(label) > 20: label = label[:18] + "…"
|
||||
charger_info[cid] = {"label": label, "total": 0}
|
||||
charger_info[cid]["total"] += cnt
|
||||
|
||||
# Top N error codes by total
|
||||
top_codes = sorted(code_info.items(), key=lambda x: -x[1]["total"])[:code_limit]
|
||||
|
||||
# Top M chargers across all top codes
|
||||
top_cids = [cid for cid, _ in
|
||||
sorted(charger_info.items(), key=lambda x: -x[1]["total"])[:charger_limit]]
|
||||
|
||||
result = []
|
||||
for ecode, info in reversed(top_codes): # 역순: 차트에서 1위가 위에
|
||||
entry = {"error_code": ecode, "total": info["total"]}
|
||||
other = 0
|
||||
for cid, cnt in info["chargers"].items():
|
||||
if cid in top_cids:
|
||||
entry[cid] = cnt
|
||||
else:
|
||||
other += cnt
|
||||
if other:
|
||||
entry["__other__"] = other
|
||||
result.append(entry)
|
||||
|
||||
has_other = any(r.get("__other__", 0) > 0 for r in result)
|
||||
charger_labels = {cid: charger_info[cid]["label"] for cid in top_cids}
|
||||
if has_other:
|
||||
charger_labels["__other__"] = "기타"
|
||||
|
||||
dataset_keys = top_cids + (["__other__"] if has_other else [])
|
||||
return {
|
||||
"error_codes": result, # 에러코드별 집계 (역순)
|
||||
"charger_labels": charger_labels, # charger_id → 표시명
|
||||
"dataset_keys": dataset_keys, # 차트 dataset 순서
|
||||
}
|
||||
SELECT TRIM(error_code) AS error_code, COUNT(*) AS cnt
|
||||
FROM reports
|
||||
WHERE error_code IS NOT NULL AND TRIM(error_code) != ''
|
||||
GROUP BY TRIM(error_code)
|
||||
ORDER BY cnt DESC
|
||||
LIMIT :limit
|
||||
"""), {"limit": code_limit}).fetchall()
|
||||
# 역순: 차트 Y축에서 1위가 맨 위
|
||||
result = [{"error_code": r[0], "total": int(r[1])} for r in reversed(rows)]
|
||||
return {"error_codes": result}
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
Reference in New Issue
Block a user