## 처리시간 지표 - 업무시간 기준(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>
86 lines
3.1 KiB
Python
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}
|