File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
package kr.itn.itnhub.dashboard;
import kr.itn.itnhub.code.CodeService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 대시보드 화면 하나가 쓰는 서비스. 집계 쿼리는 {@link DashboardMapper#findOrgRows()} 한 번이고,
* 상단 KPI는 그 결과를 Java에서 접어 만든다 - 같은 원본에서 계산해야 타일 숫자와 아래 표/칸반
* 숫자가 어긋나지 않는다(쿼리를 따로 두면 두 결과 사이에 시차가 생긴다).
*
* <p>어느 단계부터 각 KPI에 세는지는 코드표(STAGE의 kpiFrom 속성)에서 온다. 예전에는 여기
* 상수 세 개로 박혀 있어서, 기준이 바뀔 때마다 배포가 필요했다.</p>
*/
@Service
public class DashboardService {
/** KPI 이름. 코드표의 kpiFrom 값과 맞물린다. */
static final String KPI_DOC_SUBMITTED = "docSubmitted";
static final String KPI_COMPLETED = "completed";
static final String KPI_REPORT = "reportWriting";
private final DashboardMapper mapper;
private final CodeService codeService;
public DashboardService(DashboardMapper mapper, CodeService codeService) {
this.mapper = mapper;
this.codeService = codeService;
}
/**
* 이 KPI에 집계하기 시작하는 단계 번호. 코드표에 지정이 없으면 아무 기관도 세지 않도록
* {@link Integer#MAX_VALUE}를 준다 - 0을 주면 단계가 있는 모든 기관이 잘못 집계된다.
*/
private int thresholdOf(String kpi) {
return codeService.group(kr.itn.itnhub.code.Codes.STAGE).stream()
.filter(code -> kpi.equals(code.attr(kr.itn.itnhub.code.Codes.ATTR_KPI_FROM)))
.mapToInt(code -> Integer.parseInt(code.code()))
.min()
.orElse(Integer.MAX_VALUE);
}
public DashboardResponse dashboard() {
List<DashboardOrgRow> rows = mapper.findOrgRows(doneStatus());
RightsDashboardStats rights = new RightsDashboardStats(
mapper.reviewResultDistribution(),
mapper.reviewSourceKoglDistribution(),
mapper.reviewJudgedKoglDistribution(),
mapper.processTypeDistribution(),
mapper.processStatusDistribution(),
mapper.countChangedKoglTypes());
return new DashboardResponse(summarize(rows), rows, rights);
}
/**
* 권리처리 완료로 셀 상태값. 지정이 없으면 어떤 행도 완료로 세지 않도록 매칭되지 않는
* 값을 준다 - 빈 문자열을 주면 처리상태가 비어 있는 행이 전부 완료로 잡힌다.
*/
private String doneStatus() {
return codeService.group(kr.itn.itnhub.code.Codes.PROCESS_STATUS).stream()
.filter(code -> code.flag(kr.itn.itnhub.code.Codes.ATTR_DONE))
.map(kr.itn.itnhub.code.Code::code)
.findFirst()
.orElse(" ");
}
DashboardSummary summarize(List<DashboardOrgRow> rows) {
int docSubmittedFrom = thresholdOf(KPI_DOC_SUBMITTED);
int completedFrom = thresholdOf(KPI_COMPLETED);
int reportFrom = thresholdOf(KPI_REPORT);
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 >= docSubmittedFrom) {
docSubmitted++;
}
if (stage >= completedFrom) {
completed++;
}
if (stage >= reportFrom) {
reportWriting++;
}
}
// 신청 기관 수는 명부에 등록된 기관 전체다 - 명부에 올라온 것 자체가 신청이므로
// 단계값 유무와 무관하다(채널 생성 전 기관도 신청은 한 상태다).
return new DashboardSummary(rows.size(), docSubmitted, reviewTotal, reviewDone,
processTotal, processDone, unresolvedRe, reportWriting, completed);
}
}