package kr.itn.itnhub.dashboard; import org.springframework.stereotype.Service; import java.util.List; /** * 대시보드 화면 하나가 쓰는 서비스. 집계 쿼리는 {@link DashboardMapper#findOrgRows()} 한 번이고, * 상단 KPI는 그 결과를 Java에서 접어 만든다 - 같은 원본에서 계산해야 타일 숫자와 아래 표/칸반 * 숫자가 어긋나지 않는다(쿼리를 따로 두면 두 결과 사이에 시차가 생긴다). */ @Service public class DashboardService { /** ②목록접수. 시안 KPI "서류제출"의 기준으로 쓴다. */ private static final int STAGE_DOC_SUBMITTED = 2; /** ⑪법률검토 최종완료. 시안 KPI "완료"의 기준. */ private static final int STAGE_COMPLETED = 11; /** ⑫보고서 작성. */ private static final int STAGE_REPORT = 12; private final DashboardMapper mapper; public DashboardService(DashboardMapper mapper) { this.mapper = mapper; } public DashboardResponse dashboard() { List rows = mapper.findOrgRows(); return new DashboardResponse(summarize(rows), rows); } DashboardSummary summarize(List rows) { int docSubmitted = 0; int reviewTotal = 0; int reviewDone = 0; int processTotal = 0; int processDone = 0; int unresolvedRe = 0; int reportWriting = 0; int completed = 0; for (DashboardOrgRow row : rows) { reviewTotal += row.reviewTotal(); reviewDone += row.reviewDone(); processTotal += row.processTotal(); processDone += row.processDone(); unresolvedRe += row.reCount(); Integer stage = row.stage(); if (stage == null) { continue; } if (stage >= STAGE_DOC_SUBMITTED) { docSubmitted++; } if (stage >= STAGE_COMPLETED) { completed++; } if (stage >= STAGE_REPORT) { reportWriting++; } } // 신청 기관 수는 명부에 등록된 기관 전체다 - 명부에 올라온 것 자체가 신청이므로 // 단계값 유무와 무관하다(채널 생성 전 기관도 신청은 한 상태다). return new DashboardSummary(rows.size(), docSubmitted, reviewTotal, reviewDone, processTotal, processDone, unresolvedRe, reportWriting, completed); } }