feat: 작업보고서 시스템 완성
- 일일 공수 입력 기능 - 부적합 사항 등록 (이미지 선택사항) - 날짜별 부적합 조회 (시간순 나열) - 목록 관리 (인라인 편집, 작업시간 확인 버튼) - 보고서 생성 (총 공수/부적합 시간 분리) - JWT 인증 및 권한 관리 - Docker 기반 배포 환경 구성
This commit is contained in:
130
backend/routers/reports.py
Normal file
130
backend/routers/reports.py
Normal file
@@ -0,0 +1,130 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import func
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
|
||||
from database.database import get_db
|
||||
from database.models import Issue, DailyWork, IssueStatus, IssueCategory, User, UserRole
|
||||
from database import schemas
|
||||
from routers.auth import get_current_user
|
||||
|
||||
router = APIRouter(prefix="/api/reports", tags=["reports"])
|
||||
|
||||
@router.post("/summary", response_model=schemas.ReportSummary)
|
||||
async def generate_report_summary(
|
||||
report_request: schemas.ReportRequest,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""보고서 요약 생성"""
|
||||
start_date = report_request.start_date
|
||||
end_date = report_request.end_date
|
||||
|
||||
# 일일 공수 합계
|
||||
daily_works = db.query(DailyWork).filter(
|
||||
DailyWork.date >= start_date.date(),
|
||||
DailyWork.date <= end_date.date()
|
||||
).all()
|
||||
total_hours = sum(w.total_hours for w in daily_works)
|
||||
|
||||
# 이슈 통계
|
||||
issues_query = db.query(Issue).filter(
|
||||
Issue.report_date >= start_date,
|
||||
Issue.report_date <= end_date
|
||||
)
|
||||
|
||||
# 일반 사용자는 자신의 이슈만
|
||||
if current_user.role == UserRole.USER:
|
||||
issues_query = issues_query.filter(Issue.reporter_id == current_user.id)
|
||||
|
||||
issues = issues_query.all()
|
||||
|
||||
# 카테고리별 통계
|
||||
category_stats = schemas.CategoryStats()
|
||||
completed_issues = 0
|
||||
total_resolution_time = 0
|
||||
resolved_count = 0
|
||||
|
||||
for issue in issues:
|
||||
# 카테고리별 카운트
|
||||
if issue.category == IssueCategory.MATERIAL_MISSING:
|
||||
category_stats.material_missing += 1
|
||||
elif issue.category == IssueCategory.DIMENSION_DEFECT:
|
||||
category_stats.dimension_defect += 1
|
||||
elif issue.category == IssueCategory.INCOMING_DEFECT:
|
||||
category_stats.incoming_defect += 1
|
||||
|
||||
# 완료된 이슈
|
||||
if issue.status == IssueStatus.COMPLETE:
|
||||
completed_issues += 1
|
||||
if issue.work_hours > 0:
|
||||
total_resolution_time += issue.work_hours
|
||||
resolved_count += 1
|
||||
|
||||
# 평균 해결 시간
|
||||
average_resolution_time = total_resolution_time / resolved_count if resolved_count > 0 else 0
|
||||
|
||||
return schemas.ReportSummary(
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
total_hours=total_hours,
|
||||
total_issues=len(issues),
|
||||
category_stats=category_stats,
|
||||
completed_issues=completed_issues,
|
||||
average_resolution_time=average_resolution_time
|
||||
)
|
||||
|
||||
@router.get("/issues")
|
||||
async def get_report_issues(
|
||||
start_date: datetime,
|
||||
end_date: datetime,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""보고서용 이슈 상세 목록"""
|
||||
query = db.query(Issue).filter(
|
||||
Issue.report_date >= start_date,
|
||||
Issue.report_date <= end_date
|
||||
)
|
||||
|
||||
# 일반 사용자는 자신의 이슈만
|
||||
if current_user.role == UserRole.USER:
|
||||
query = query.filter(Issue.reporter_id == current_user.id)
|
||||
|
||||
issues = query.order_by(Issue.report_date).all()
|
||||
|
||||
return [{
|
||||
"id": issue.id,
|
||||
"photo_path": issue.photo_path,
|
||||
"category": issue.category,
|
||||
"description": issue.description,
|
||||
"status": issue.status,
|
||||
"reporter_name": issue.reporter.full_name or issue.reporter.username,
|
||||
"report_date": issue.report_date,
|
||||
"work_hours": issue.work_hours,
|
||||
"detail_notes": issue.detail_notes
|
||||
} for issue in issues]
|
||||
|
||||
@router.get("/daily-works")
|
||||
async def get_report_daily_works(
|
||||
start_date: datetime,
|
||||
end_date: datetime,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""보고서용 일일 공수 목록"""
|
||||
works = db.query(DailyWork).filter(
|
||||
DailyWork.date >= start_date.date(),
|
||||
DailyWork.date <= end_date.date()
|
||||
).order_by(DailyWork.date).all()
|
||||
|
||||
return [{
|
||||
"date": work.date,
|
||||
"worker_count": work.worker_count,
|
||||
"regular_hours": work.regular_hours,
|
||||
"overtime_workers": work.overtime_workers,
|
||||
"overtime_hours": work.overtime_hours,
|
||||
"overtime_total": work.overtime_total,
|
||||
"total_hours": work.total_hours
|
||||
} for work in works]
|
||||
Reference in New Issue
Block a user