Files
ev-charger-as/backend/routers/manufacturers.py
byun 2e8751ea6c 기능 추가 및 버그 수정 — 처리시간 지표, 대시보드 차트, UI 개선
## 처리시간 지표
- 업무시간 기준(09-18 평일) / 공휴일 제외 24h / 달력 기준 3가지 모드 선택
- 공휴일 DB 관리 (holidays 테이블, 수동 등록·삭제·일괄 추가)
- 2026년 공휴일 등록 지원
- 설정 페이지에서 라디오 버튼으로 모드 선택

## 대시보드 차트
- 월별 평균 처리시간 막대 차트 추가
- 월별 신고 접수 건수 누적 막대 차트 추가
- 월별 → 일별 드릴다운 (막대 클릭 시 해당 월의 일별 차트로 전환)
- 일별 막대 클릭 시 처리 완료/신고 접수 상세 내역 모달
- 충전기별 누적 고장 건수 Top 10 수평 막대 차트 추가

## 신고 목록
- # 컬럼을 DB PK 대신 현재 목록 순서(1, 2, 3…)로 표시
- 엑셀 export 접수번호도 순차번호로 변경

## 모바일 네비게이션 버그 수정
- 모바일에서 가로 오버플로우 시 nav가 body 넓이로 늘어나
  햄버거 버튼이 화면 밖으로 밀리는 문제 수정
- nav를 position:fixed + body padding-top:54px 로 변경 (전체 페이지 적용)
- 충전기 관리·신고 목록 페이지 지도 컨테이너에 isolation:isolate 적용

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 06:52:56 +09:00

86 lines
3.1 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, Form
from sqlalchemy.orm import Session
from typing import Optional
from database import get_db
import models
from auth import require_admin
router = APIRouter(prefix="/api/manufacturers", tags=["manufacturers"])
def _fmt(m: models.Manufacturer) -> dict:
return {
"id": m.id, "name": m.name,
"representative_name": m.representative_name,
"business_number": m.business_number,
"phone": m.phone, "address": m.address,
"is_active": m.is_active,
"created_at": m.created_at.isoformat() if m.created_at else None,
}
@router.get("/public")
def list_public(db: Session = Depends(get_db)):
"""인증 없이 활성 제조사 목록 반환 (회원가입 화면용)"""
rows = db.query(models.Manufacturer).filter_by(is_active=True).order_by(models.Manufacturer.name).all()
return [{"id": m.id, "name": m.name} for m in rows]
@router.get("")
def list_manufacturers(db: Session = Depends(get_db), _=Depends(require_admin)):
rows = db.query(models.Manufacturer).order_by(models.Manufacturer.name).all()
return [_fmt(m) for m in rows]
@router.post("")
def create_manufacturer(
name: str = Form(...),
representative_name: str = Form(""),
business_number: str = Form(""),
phone: str = Form(""),
address: str = Form(""),
db: Session = Depends(get_db),
_=Depends(require_admin)
):
if db.query(models.Manufacturer).filter_by(name=name).first():
raise HTTPException(400, "이미 등록된 회사명입니다.")
m = models.Manufacturer(
name=name,
representative_name=representative_name or None,
business_number=business_number or None,
phone=phone or None,
address=address or None,
)
db.add(m); db.commit(); db.refresh(m)
return _fmt(m)
@router.put("/{mfr_id}")
def update_manufacturer(
mfr_id: int,
name: str = Form(...),
representative_name: str = Form(""),
business_number: str = Form(""),
phone: str = Form(""),
address: str = Form(""),
is_active: str = Form("true"),
db: Session = Depends(get_db),
_=Depends(require_admin)
):
m = db.query(models.Manufacturer).filter_by(id=mfr_id).first()
if not m: raise HTTPException(404)
dup = db.query(models.Manufacturer).filter(
models.Manufacturer.name == name, models.Manufacturer.id != mfr_id
).first()
if dup: raise HTTPException(400, "이미 사용 중인 회사명입니다.")
m.name = name
m.representative_name = representative_name or None
m.business_number = business_number or None
m.phone = phone or None
m.address = address or None
m.is_active = is_active == "true"
db.commit()
return _fmt(m)
@router.delete("/{mfr_id}")
def delete_manufacturer(mfr_id: int, db: Session = Depends(get_db), _=Depends(require_admin)):
m = db.query(models.Manufacturer).filter_by(id=mfr_id).first()
if not m: raise HTTPException(404)
db.delete(m); db.commit()
return {"ok": True}