This commit is contained in:
2026-01-02 22:18:09 +09:00
parent a7b04d0be8
commit dc2b9286f4
7 changed files with 595 additions and 581 deletions

View File

@@ -36,86 +36,86 @@ public class LabelAllocateApiController {
@Operation(summary = "배정 가능한 사용자 목록 조회", description = "라벨링 작업 배정을 위한 활성 상태의 사용자 목록을 조회합니다.") @Operation(summary = "배정 가능한 사용자 목록 조회", description = "라벨링 작업 배정을 위한 활성 상태의 사용자 목록을 조회합니다.")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse(responseCode = "200", description = "조회 성공"), @ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음"), @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음"),
@ApiResponse(responseCode = "500", description = "서버 오류") @ApiResponse(responseCode = "500", description = "서버 오류")
}) })
@GetMapping("/avail-user") @GetMapping("/avail-user")
public ApiResponseDto<List<LabelAllocateDto.UserList>> availUserList( public ApiResponseDto<List<LabelAllocateDto.UserList>> availUserList(
@Parameter( @Parameter(
description = "사용자 역할", description = "사용자 역할",
example = "LABELER", example = "LABELER",
schema = @Schema(allowableValues = {"LABELER", "REVIEWER"})) schema = @Schema(allowableValues = {"LABELER", "REVIEWER"}))
@RequestParam @RequestParam
String role) { String role) {
return ApiResponseDto.ok(labelAllocateService.availUserList(role)); return ApiResponseDto.ok(labelAllocateService.availUserList(role));
} }
@Operation(summary = "작업현황관리(작업자 목록 및 3일치 통계 조회)", description = "학습데이터 제작 현황 조회 API입니다.") @Operation(summary = "작업현황관리(작업자 목록 및 3일치 통계 조회)", description = "학습데이터 제작 현황 조회 API입니다.")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse(responseCode = "200", description = "조회 성공"), @ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음"), @ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음"),
@ApiResponse(responseCode = "500", description = "서버 오류") @ApiResponse(responseCode = "500", description = "서버 오류")
}) })
@GetMapping("/admin/workers") @GetMapping("/admin/workers")
public ApiResponseDto<WorkerListResponse> getWorkerStatistics( public ApiResponseDto<WorkerListResponse> getWorkerStatistics(
@Parameter(description = "분석 ID (필수)", required = true, example = "3") @RequestParam @Parameter(description = "분석 ID (필수)", required = true, example = "3") @RequestParam
Long analUid, Long analUid,
@Parameter( @Parameter(
description = "작업자 유형 (선택) - 미입력 시 LABELER로 조회", description = "작업자 유형 (선택) - 미입력 시 LABELER로 조회",
example = "LABELER", example = "LABELER",
schema = schema =
@Schema( @Schema(
allowableValues = {"LABELER", "REVIEWER"}, allowableValues = {"LABELER", "REVIEWER"},
defaultValue = "LABELER")) defaultValue = "LABELER"))
@RequestParam(required = false) @RequestParam(required = false)
String type, String type,
@Parameter(description = "작업자 이름 검색 (부분 일치)", example = "김라벨") @RequestParam(required = false) @Parameter(description = "작업자 이름 검색 (부분 일치)", example = "김라벨") @RequestParam(required = false)
String searchName, String searchName,
@Parameter(description = "작업자 사번 검색 (부분 일치)", example = "1234567") @Parameter(description = "작업자 사번 검색 (부분 일치)", example = "1234567")
@RequestParam(required = false) @RequestParam(required = false)
String searchEmployeeNo, String searchEmployeeNo,
@Parameter( @Parameter(
description = "정렬 조건 (선택) - 미입력 시 이름 오름차순", description = "정렬 조건 (선택) - 미입력 시 이름 오름차순",
example = "REMAINING_DESC", example = "REMAINING_DESC",
schema = schema =
@Schema( @Schema(
allowableValues = { allowableValues = {
"REMAINING_DESC", "REMAINING_DESC",
"REMAINING_ASC", "REMAINING_ASC",
"NAME_ASC", "NAME_ASC",
"NAME_DESC" "NAME_DESC"
}, },
defaultValue = "NAME_ASC")) defaultValue = "NAME_ASC"))
@RequestParam(required = false) @RequestParam(required = false)
String sort) { String sort) {
// type이 null이면 기본값으로 LABELER 설정 // type이 null이면 기본값으로 LABELER 설정
String workerType = (type == null || type.isEmpty()) ? RoleType.LABELER.name() : type; String workerType = (type == null || type.isEmpty()) ? RoleType.LABELER.name() : type;
return ApiResponseDto.ok( return ApiResponseDto.ok(
labelAllocateService.getWorkerStatistics( labelAllocateService.getWorkerStatistics(
analUid, workerType, searchName, searchEmployeeNo, sort)); analUid, workerType, searchName, searchEmployeeNo, sort));
} }
@Operation(summary = "작업 배정", description = "작업 배정") @Operation(summary = "작업 배정", description = "작업 배정")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse( @ApiResponse(
responseCode = "201", responseCode = "201",
description = "등록 성공", description = "등록 성공",
content = content =
@Content( @Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = Long.class), schema = @Schema(implementation = Long.class),
examples = { examples = {
@ExampleObject( @ExampleObject(
name = "라벨러 할당 예시", name = "라벨러 할당 예시",
description = "라벨러 할당 예시", description = "라벨러 할당 예시",
value = value =
""" """
{ {
"autoType": "AUTO", "autoType": "AUTO",
"stage": 4, "stage": 4,
@@ -150,67 +150,71 @@ public class LabelAllocateApiController {
] ]
} }
""") """)
})), })),
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@PostMapping("/allocate") @PostMapping("/allocate")
public ApiResponseDto<Void> labelAllocate(@RequestBody LabelAllocateDto.AllocateDto dto) { public ApiResponseDto<Void> labelAllocate(@RequestBody LabelAllocateDto.AllocateDto dto) {
labelAllocateService.allocateAsc( labelAllocateService.allocateAsc(
dto.getAutoType(), dto.getAutoType(),
dto.getStage(), dto.getStage(),
dto.getLabelers(), dto.getLabelers(),
dto.getInspectors(), dto.getInspectors(),
dto.getCompareYyyy(), dto.getCompareYyyy(),
dto.getTargetYyyy() dto.getTargetYyyy());
);
return ApiResponseDto.ok(null); return ApiResponseDto.ok(null);
} }
@Operation(summary = "추론 상세 조회", description = "분석 ID에 해당하는 추론 상세 정보를 조회합니다.") @Operation(summary = "추론 상세 조회", description = "분석 ID에 해당하는 추론 상세 정보를 조회합니다.")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse(responseCode = "200", description = "조회 성공"), @ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음"), @ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음"),
@ApiResponse(responseCode = "500", description = "서버 오류") @ApiResponse(responseCode = "500", description = "서버 오류")
}) })
@GetMapping("/stage-detail") @GetMapping("/stage-detail")
public ApiResponseDto<InferenceDetail> findInferenceDetail( public ApiResponseDto<InferenceDetail> findInferenceDetail(
@Parameter(description = "비교년도", required = true, example = "2022") @RequestParam Integer compareYyyy, @Parameter(description = "비교년도", required = true, example = "2022") @RequestParam
@Parameter(description = "기준년도", required = true, example = "2024") @RequestParam Integer targetYyyy, Integer compareYyyy,
@Parameter(description = "회차", required = true, example = "4") @RequestParam Integer stage @Parameter(description = "기준년도", required = true, example = "2024") @RequestParam
) { Integer targetYyyy,
return ApiResponseDto.ok(labelAllocateService.findInferenceDetail(compareYyyy, targetYyyy, stage)); @Parameter(description = "회차", required = true, example = "4") @RequestParam Integer stage) {
return ApiResponseDto.ok(
labelAllocateService.findInferenceDetail(compareYyyy, targetYyyy, stage));
} }
@Operation(summary = "작업이관 > 라벨러 상세 정보", description = "작업이관 > 라벨러 상세 정보") @Operation(summary = "작업이관 > 라벨러 상세 정보", description = "작업이관 > 라벨러 상세 정보")
@GetMapping("/labeler-detail") @GetMapping("/labeler-detail")
public ApiResponseDto<LabelerDetail> findLabelerDetail( public ApiResponseDto<LabelerDetail> findLabelerDetail(
@RequestParam(defaultValue = "01022223333") String userId, @RequestParam(defaultValue = "01022223333") String userId,
@Parameter(description = "비교년도", required = true, example = "2022") @RequestParam Integer compareYyyy, @Parameter(description = "비교년도", required = true, example = "2022") @RequestParam
@Parameter(description = "기준년도", required = true, example = "2024") @RequestParam Integer targetYyyy, Integer compareYyyy,
@Parameter(description = "회차", required = true, example = "4") @RequestParam Integer stage) { @Parameter(description = "기준년도", required = true, example = "2024") @RequestParam
return ApiResponseDto.ok(labelAllocateService.findLabelerDetail(userId, compareYyyy, targetYyyy, stage)); Integer targetYyyy,
@Parameter(description = "회차", required = true, example = "4") @RequestParam Integer stage) {
return ApiResponseDto.ok(
labelAllocateService.findLabelerDetail(userId, compareYyyy, targetYyyy, stage));
} }
@Operation(summary = "작업 이관", description = "작업 이관") @Operation(summary = "작업 이관", description = "작업 이관")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse( @ApiResponse(
responseCode = "201", responseCode = "201",
description = "등록 성공", description = "등록 성공",
content = content =
@Content( @Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = Long.class), schema = @Schema(implementation = Long.class),
examples = { examples = {
@ExampleObject( @ExampleObject(
name = "라벨러 할당 예시", name = "라벨러 할당 예시",
description = "라벨러 할당 예시", description = "라벨러 할당 예시",
value = value =
""" """
{ {
"autoType": "AUTO", "autoType": "AUTO",
"stage": 4, "stage": 4,
@@ -226,24 +230,29 @@ public class LabelAllocateApiController {
] ]
} }
""") """)
})), })),
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@PostMapping("/allocate-move") @PostMapping("/allocate-move")
public ApiResponseDto<Void> labelAllocateMove( public ApiResponseDto<Void> labelAllocateMove(
@io.swagger.v3.oas.annotations.parameters.RequestBody( @io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "라벨링 이관", description = "라벨링 이관",
required = true, required = true,
content = content =
@Content( @Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = LabelAllocateDto.AllocateMoveDto.class))) schema = @Schema(implementation = LabelAllocateDto.AllocateMoveDto.class)))
@RequestBody @RequestBody
LabelAllocateDto.AllocateMoveDto dto) { LabelAllocateDto.AllocateMoveDto dto) {
labelAllocateService.allocateMove(dto.getAutoType(), dto.getStage(), dto.getLabelers(), dto.getCompareYyyy(), dto.getTargetYyyy()); labelAllocateService.allocateMove(
dto.getAutoType(),
dto.getStage(),
dto.getLabelers(),
dto.getCompareYyyy(),
dto.getTargetYyyy());
return ApiResponseDto.ok(null); return ApiResponseDto.ok(null);
} }

View File

@@ -34,24 +34,24 @@ public class LabelAllocateService {
/** /**
* 도엽 기준 asc sorting 해서 할당 수만큼 배정하는 로직 * 도엽 기준 asc sorting 해서 할당 수만큼 배정하는 로직
* *
* @param autoType 자동/수동 배정 타입 * @param autoType 자동/수동 배정 타입
* @param stage 회차 * @param stage 회차
* @param targetUsers 라벨러 목록 * @param targetUsers 라벨러 목록
* @param targetInspectors 검수자 목록 * @param targetInspectors 검수자 목록
*/ */
@Transactional @Transactional
public void allocateAsc( public void allocateAsc(
String autoType, String autoType,
Integer stage, Integer stage,
List<TargetUser> targetUsers, List<TargetUser> targetUsers,
List<TargetInspector> targetInspectors, List<TargetInspector> targetInspectors,
Integer compareYyyy, Integer compareYyyy,
Integer targetYyyy Integer targetYyyy) {
) {
Long lastId = null; Long lastId = null;
// geom 잔여건수 조회 // geom 잔여건수 조회
Long chargeCnt = labelAllocateCoreService.findLabelUnAssignedCnt(stage, compareYyyy, targetYyyy); Long chargeCnt =
labelAllocateCoreService.findLabelUnAssignedCnt(stage, compareYyyy, targetYyyy);
// Long totalDemand = targetUsers.stream().mapToLong(TargetUser::getDemand).sum(); // Long totalDemand = targetUsers.stream().mapToLong(TargetUser::getDemand).sum();
// if (!Objects.equals(chargeCnt, totalDemand)) { // if (!Objects.equals(chargeCnt, totalDemand)) {
// log.info("chargeCnt != totalDemand"); // log.info("chargeCnt != totalDemand");
@@ -62,7 +62,8 @@ public class LabelAllocateService {
return; return;
} }
List<Long> allIds = labelAllocateCoreService.fetchNextIds(lastId, chargeCnt, compareYyyy, targetYyyy, stage); List<Long> allIds =
labelAllocateCoreService.fetchNextIds(lastId, chargeCnt, compareYyyy, targetYyyy, stage);
int index = 0; int index = 0;
for (TargetUser target : targetUsers) { for (TargetUser target : targetUsers) {
int end = index + target.getDemand(); int end = index + target.getDemand();
@@ -73,7 +74,8 @@ public class LabelAllocateService {
} }
// 검수자에게 userCount명 만큼 할당 // 검수자에게 userCount명 만큼 할당
List<LabelAllocateDto.Basic> list = labelAllocateCoreService.findAssignedLabelerList(compareYyyy, targetYyyy, stage); List<LabelAllocateDto.Basic> list =
labelAllocateCoreService.findAssignedLabelerList(compareYyyy, targetYyyy, stage);
int from = 0; int from = 0;
for (TargetInspector inspector : targetInspectors) { for (TargetInspector inspector : targetInspectors) {
@@ -84,7 +86,7 @@ public class LabelAllocateService {
} }
List<UUID> assignmentUids = List<UUID> assignmentUids =
list.subList(from, to).stream().map(LabelAllocateDto.Basic::getAssignmentUid).toList(); list.subList(from, to).stream().map(LabelAllocateDto.Basic::getAssignmentUid).toList();
labelAllocateCoreService.assignInspectorBulk(assignmentUids, inspector.getInspectorUid()); labelAllocateCoreService.assignInspectorBulk(assignmentUids, inspector.getInspectorUid());
@@ -99,50 +101,50 @@ public class LabelAllocateService {
/** /**
* 작업자 목록 및 3일치 통계 조회 * 작업자 목록 및 3일치 통계 조회
* *
* @param analUid 분석 ID * @param analUid 분석 ID
* @param workerType 작업자 유형 (LABELER/INSPECTOR) * @param workerType 작업자 유형 (LABELER/INSPECTOR)
* @param searchName 이름 검색 * @param searchName 이름 검색
* @param searchEmployeeNo 사번 검색 * @param searchEmployeeNo 사번 검색
* @param sortType 정렬 조건 * @param sortType 정렬 조건
* @return 작업자 목록 및 통계 * @return 작업자 목록 및 통계
*/ */
public WorkerListResponse getWorkerStatistics( public WorkerListResponse getWorkerStatistics(
Long analUid, Long analUid,
String workerType, String workerType,
String searchName, String searchName,
String searchEmployeeNo, String searchEmployeeNo,
String sortType) { String sortType) {
// 작업 진행 현황 조회 // 작업 진행 현황 조회
var progressInfo = labelAllocateCoreService.findWorkProgressInfo(analUid); var progressInfo = labelAllocateCoreService.findWorkProgressInfo(analUid);
// 작업자 통계 조회 // 작업자 통계 조회
List<WorkerStatistics> workers = List<WorkerStatistics> workers =
labelAllocateCoreService.findWorkerStatistics( labelAllocateCoreService.findWorkerStatistics(
analUid, workerType, searchName, searchEmployeeNo, sortType); analUid, workerType, searchName, searchEmployeeNo, sortType);
// 각 작업자별 3일치 처리량 조회 // 각 작업자별 3일치 처리량 조회
LocalDate today = LocalDate.now(); LocalDate today = LocalDate.now();
for (WorkerStatistics worker : workers) { for (WorkerStatistics worker : workers) {
Long day1Count = Long day1Count =
labelAllocateCoreService.findDailyProcessedCount( labelAllocateCoreService.findDailyProcessedCount(
worker.getWorkerId(), workerType, today.minusDays(1), analUid); worker.getWorkerId(), workerType, today.minusDays(1), analUid);
Long day2Count = Long day2Count =
labelAllocateCoreService.findDailyProcessedCount( labelAllocateCoreService.findDailyProcessedCount(
worker.getWorkerId(), workerType, today.minusDays(2), analUid); worker.getWorkerId(), workerType, today.minusDays(2), analUid);
Long day3Count = Long day3Count =
labelAllocateCoreService.findDailyProcessedCount( labelAllocateCoreService.findDailyProcessedCount(
worker.getWorkerId(), workerType, today.minusDays(3), analUid); worker.getWorkerId(), workerType, today.minusDays(3), analUid);
long average = (day1Count + day2Count + day3Count) / 3; long average = (day1Count + day2Count + day3Count) / 3;
DailyHistory history = DailyHistory history =
DailyHistory.builder() DailyHistory.builder()
.day1Ago(day1Count) .day1Ago(day1Count)
.day2Ago(day2Count) .day2Ago(day2Count)
.day3Ago(day3Count) .day3Ago(day3Count)
.average(average) .average(average)
.build(); .build();
worker.setHistory(history); worker.setHistory(history);
@@ -155,12 +157,17 @@ public class LabelAllocateService {
return WorkerListResponse.builder().progressInfo(progressInfo).workers(workers).build(); return WorkerListResponse.builder().progressInfo(progressInfo).workers(workers).build();
} }
public InferenceDetail findInferenceDetail(Integer compareYyyy, Integer targetYyyy, Integer stage) { public InferenceDetail findInferenceDetail(
Integer compareYyyy, Integer targetYyyy, Integer stage) {
return labelAllocateCoreService.findInferenceDetail(compareYyyy, targetYyyy, stage); return labelAllocateCoreService.findInferenceDetail(compareYyyy, targetYyyy, stage);
} }
public void allocateMove(String autoType, Integer stage, List<TargetUser> targetUsers, Integer compareYyyy, public void allocateMove(
Integer targetYyyy) { String autoType,
Integer stage,
List<TargetUser> targetUsers,
Integer compareYyyy,
Integer targetYyyy) {
Long lastId = null; Long lastId = null;
Long chargeCnt = targetUsers.stream().mapToLong(TargetUser::getDemand).sum(); Long chargeCnt = targetUsers.stream().mapToLong(TargetUser::getDemand).sum();
@@ -169,7 +176,9 @@ public class LabelAllocateService {
return; return;
} }
List<Long> allIds = labelAllocateCoreService.fetchNextMoveIds(lastId, chargeCnt, compareYyyy, targetYyyy, stage); List<Long> allIds =
labelAllocateCoreService.fetchNextMoveIds(
lastId, chargeCnt, compareYyyy, targetYyyy, stage);
int index = 0; int index = 0;
for (TargetUser target : targetUsers) { for (TargetUser target : targetUsers) {
int end = index + target.getDemand(); int end = index + target.getDemand();
@@ -180,7 +189,8 @@ public class LabelAllocateService {
} }
} }
public LabelerDetail findLabelerDetail(String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) { public LabelerDetail findLabelerDetail(
String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) {
return labelAllocateCoreService.findLabelerDetail(userId, compareYyyy, targetYyyy, stage); return labelAllocateCoreService.findLabelerDetail(userId, compareYyyy, targetYyyy, stage);
} }
} }

View File

@@ -20,18 +20,21 @@ public class LabelAllocateCoreService {
private final LabelAllocateRepository labelAllocateRepository; private final LabelAllocateRepository labelAllocateRepository;
public List<Long> fetchNextIds(Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) { public List<Long> fetchNextIds(
Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) {
return labelAllocateRepository.fetchNextIds(lastId, batchSize, compareYyyy, targetYyyy, stage); return labelAllocateRepository.fetchNextIds(lastId, batchSize, compareYyyy, targetYyyy, stage);
} }
public void assignOwner(List<Long> ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) { public void assignOwner(
List<Long> ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) {
labelAllocateRepository.assignOwner(ids, userId, compareYyyy, targetYyyy, stage); labelAllocateRepository.assignOwner(ids, userId, compareYyyy, targetYyyy, stage);
} }
public List<LabelAllocateDto.Basic> findAssignedLabelerList(Integer compareYyyy, Integer targetYyyy, Integer stage) { public List<LabelAllocateDto.Basic> findAssignedLabelerList(
Integer compareYyyy, Integer targetYyyy, Integer stage) {
return labelAllocateRepository.findAssignedLabelerList(compareYyyy, targetYyyy, stage).stream() return labelAllocateRepository.findAssignedLabelerList(compareYyyy, targetYyyy, stage).stream()
.map(LabelingAssignmentEntity::toDto) .map(LabelingAssignmentEntity::toDto)
.toList(); .toList();
} }
public Long findLabelUnAssignedCnt(Integer stage, Integer compareYyyy, Integer targetYyyy) { public Long findLabelUnAssignedCnt(Integer stage, Integer compareYyyy, Integer targetYyyy) {
@@ -47,13 +50,13 @@ public class LabelAllocateCoreService {
} }
public List<WorkerStatistics> findWorkerStatistics( public List<WorkerStatistics> findWorkerStatistics(
Long analUid, Long analUid,
String workerType, String workerType,
String searchName, String searchName,
String searchEmployeeNo, String searchEmployeeNo,
String sortType) { String sortType) {
return labelAllocateRepository.findWorkerStatistics( return labelAllocateRepository.findWorkerStatistics(
analUid, workerType, searchName, searchEmployeeNo, sortType); analUid, workerType, searchName, searchEmployeeNo, sortType);
} }
public WorkProgressInfo findWorkProgressInfo(Long analUid) { public WorkProgressInfo findWorkProgressInfo(Long analUid) {
@@ -61,7 +64,7 @@ public class LabelAllocateCoreService {
} }
public Long findDailyProcessedCount( public Long findDailyProcessedCount(
String workerId, String workerType, LocalDate date, Long analUid) { String workerId, String workerType, LocalDate date, Long analUid) {
return labelAllocateRepository.findDailyProcessedCount(workerId, workerType, date, analUid); return labelAllocateRepository.findDailyProcessedCount(workerId, workerType, date, analUid);
} }
@@ -69,7 +72,8 @@ public class LabelAllocateCoreService {
labelAllocateRepository.assignInspectorBulk(assignmentUids, inspectorUid); labelAllocateRepository.assignInspectorBulk(assignmentUids, inspectorUid);
} }
public InferenceDetail findInferenceDetail(Integer compareYyyy, Integer targetYyyy, Integer stage) { public InferenceDetail findInferenceDetail(
Integer compareYyyy, Integer targetYyyy, Integer stage) {
return labelAllocateRepository.findInferenceDetail(compareYyyy, targetYyyy, stage); return labelAllocateRepository.findInferenceDetail(compareYyyy, targetYyyy, stage);
} }
@@ -77,15 +81,18 @@ public class LabelAllocateCoreService {
return labelAllocateRepository.findLabelUnCompleteCnt(analUid); return labelAllocateRepository.findLabelUnCompleteCnt(analUid);
} }
public List<Long> fetchNextMoveIds(Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) { public List<Long> fetchNextMoveIds(
return labelAllocateRepository.fetchNextMoveIds(lastId, batchSize, compareYyyy, targetYyyy, stage); Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) {
return labelAllocateRepository.fetchNextMoveIds(
lastId, batchSize, compareYyyy, targetYyyy, stage);
} }
public void assignOwnerMove(List<Long> sub, String userId) { public void assignOwnerMove(List<Long> sub, String userId) {
labelAllocateRepository.assignOwnerMove(sub, userId); labelAllocateRepository.assignOwnerMove(sub, userId);
} }
public LabelerDetail findLabelerDetail(String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) { public LabelerDetail findLabelerDetail(
String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) {
return labelAllocateRepository.findLabelerDetail(userId, compareYyyy, targetYyyy, stage); return labelAllocateRepository.findLabelerDetail(userId, compareYyyy, targetYyyy, stage);
} }
} }

View File

@@ -12,11 +12,14 @@ import java.util.UUID;
public interface LabelAllocateRepositoryCustom { public interface LabelAllocateRepositoryCustom {
List<Long> fetchNextIds(Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage); List<Long> fetchNextIds(
Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage);
void assignOwner(List<Long> ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage); void assignOwner(
List<Long> ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage);
List<LabelingAssignmentEntity> findAssignedLabelerList(Integer compareYyyy, Integer targetYyyy, Integer stage); List<LabelingAssignmentEntity> findAssignedLabelerList(
Integer compareYyyy, Integer targetYyyy, Integer stage);
Long findLabelUnAssignedCnt(Integer stage, Integer compareYyyy, Integer targetYyyy); Long findLabelUnAssignedCnt(Integer stage, Integer compareYyyy, Integer targetYyyy);
@@ -26,7 +29,7 @@ public interface LabelAllocateRepositoryCustom {
// 작업자 통계 조회 // 작업자 통계 조회
List<WorkerStatistics> findWorkerStatistics( List<WorkerStatistics> findWorkerStatistics(
Long analUid, String workerType, String searchName, String searchEmployeeNo, String sortType); Long analUid, String workerType, String searchName, String searchEmployeeNo, String sortType);
// 작업 진행 현황 조회 // 작업 진행 현황 조회
WorkProgressInfo findWorkProgressInfo(Long analUid); WorkProgressInfo findWorkProgressInfo(Long analUid);
@@ -38,11 +41,13 @@ public interface LabelAllocateRepositoryCustom {
InferenceDetail findInferenceDetail(Integer compareYyyy, Integer targetYyyy, Integer stage); InferenceDetail findInferenceDetail(Integer compareYyyy, Integer targetYyyy, Integer stage);
public List<Long> fetchNextMoveIds(Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage); public List<Long> fetchNextMoveIds(
Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage);
Long findLabelUnCompleteCnt(Long analUid); Long findLabelUnCompleteCnt(Long analUid);
void assignOwnerMove(List<Long> sub, String userId); void assignOwnerMove(List<Long> sub, String userId);
LabelerDetail findLabelerDetail(String userId, Integer compareYyyy, Integer targetYyyy, Integer stage); LabelerDetail findLabelerDetail(
String userId, Integer compareYyyy, Integer targetYyyy, Integer stage);
} }

View File

@@ -46,40 +46,41 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
private final JPAQueryFactory queryFactory; private final JPAQueryFactory queryFactory;
@PersistenceContext @PersistenceContext private EntityManager em;
private EntityManager em;
@Override @Override
public List<Long> fetchNextIds(Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) { public List<Long> fetchNextIds(
Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) {
return queryFactory return queryFactory
.select(mapSheetAnalDataInferenceGeomEntity.geoUid) .select(mapSheetAnalDataInferenceGeomEntity.geoUid)
.from(mapSheetAnalDataInferenceGeomEntity) .from(mapSheetAnalDataInferenceGeomEntity)
.where( .where(
lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId), lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId),
mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(compareYyyy), mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(compareYyyy),
mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(targetYyyy), mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(targetYyyy),
mapSheetAnalDataInferenceGeomEntity.stage.eq(stage), mapSheetAnalDataInferenceGeomEntity.stage.eq(stage),
mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) mapSheetAnalDataInferenceGeomEntity.labelState.isNull())
.orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc()) .orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc())
.limit(batchSize) .limit(batchSize)
.fetch(); .fetch();
} }
@Override @Override
public void assignOwner(List<Long> ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) { public void assignOwner(
List<Long> ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) {
// analUid로 분석 정보 조회 // analUid로 분석 정보 조회
MapSheetAnalDataInferenceEntity analEntity = MapSheetAnalDataInferenceEntity analEntity =
queryFactory queryFactory
.selectFrom(mapSheetAnalDataInferenceEntity) .selectFrom(mapSheetAnalDataInferenceEntity)
.where(mapSheetAnalDataInferenceEntity.compareYyyy.eq(compareYyyy), .where(
mapSheetAnalDataInferenceEntity.targetYyyy.eq(targetYyyy), mapSheetAnalDataInferenceEntity.compareYyyy.eq(compareYyyy),
mapSheetAnalDataInferenceEntity.stage.eq(stage) mapSheetAnalDataInferenceEntity.targetYyyy.eq(targetYyyy),
) mapSheetAnalDataInferenceEntity.stage.eq(stage))
.orderBy(mapSheetAnalDataInferenceEntity.analUid.asc()) .orderBy(mapSheetAnalDataInferenceEntity.analUid.asc())
.limit(1) .limit(1)
.fetchOne(); .fetchOne();
if (Objects.isNull(analEntity)) { if (Objects.isNull(analEntity)) {
throw new EntityNotFoundException("MapSheetAnalEntity not found for analUid: "); throw new EntityNotFoundException("MapSheetAnalEntity not found for analUid: ");
@@ -87,17 +88,17 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
// data_geom 테이블에 label state 를 ASSIGNED 로 update // data_geom 테이블에 label state 를 ASSIGNED 로 update
queryFactory queryFactory
.update(mapSheetAnalDataInferenceGeomEntity) .update(mapSheetAnalDataInferenceGeomEntity)
.set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId()) .set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId())
.set(mapSheetAnalDataInferenceGeomEntity.labelStateDttm, ZonedDateTime.now()) .set(mapSheetAnalDataInferenceGeomEntity.labelStateDttm, ZonedDateTime.now())
.set(mapSheetAnalDataInferenceGeomEntity.testState, InspectState.UNCONFIRM.getId()) .set(mapSheetAnalDataInferenceGeomEntity.testState, InspectState.UNCONFIRM.getId())
.set(mapSheetAnalDataInferenceGeomEntity.testStateDttm, ZonedDateTime.now()) .set(mapSheetAnalDataInferenceGeomEntity.testStateDttm, ZonedDateTime.now())
.where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(ids)) .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(ids))
.execute(); .execute();
// 라벨러 할당 테이블에 insert // 라벨러 할당 테이블에 insert
String sql = String sql =
""" """
insert into tb_labeling_assignment insert into tb_labeling_assignment
(assignment_uid, inference_geom_uid, worker_uid, (assignment_uid, inference_geom_uid, worker_uid,
work_state, assign_group_id, anal_uid) work_state, assign_group_id, anal_uid)
@@ -106,13 +107,13 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
for (Long geoUid : ids) { for (Long geoUid : ids) {
em.createNativeQuery(sql) em.createNativeQuery(sql)
.setParameter(1, UUID.randomUUID()) .setParameter(1, UUID.randomUUID())
.setParameter(2, geoUid) .setParameter(2, geoUid)
.setParameter(3, userId) .setParameter(3, userId)
.setParameter(4, LabelState.ASSIGNED.getId()) .setParameter(4, LabelState.ASSIGNED.getId())
.setParameter(5, "") .setParameter(5, "")
.setParameter(6, analEntity.getAnalUid()) .setParameter(6, analEntity.getAnalUid())
.executeUpdate(); .executeUpdate();
} }
em.flush(); em.flush();
@@ -120,91 +121,92 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
} }
@Override @Override
public List<LabelingAssignmentEntity> findAssignedLabelerList(Integer compareYyyy, Integer targetYyyy, Integer stage) { public List<LabelingAssignmentEntity> findAssignedLabelerList(
Integer compareYyyy, Integer targetYyyy, Integer stage) {
// analUid로 분석 정보 조회 // analUid로 분석 정보 조회
MapSheetAnalDataInferenceEntity analEntity = MapSheetAnalDataInferenceEntity analEntity =
queryFactory queryFactory
.selectFrom(mapSheetAnalDataInferenceEntity) .selectFrom(mapSheetAnalDataInferenceEntity)
.where(mapSheetAnalDataInferenceEntity.compareYyyy.eq(compareYyyy), .where(
mapSheetAnalDataInferenceEntity.targetYyyy.eq(targetYyyy), mapSheetAnalDataInferenceEntity.compareYyyy.eq(compareYyyy),
mapSheetAnalDataInferenceEntity.stage.eq(stage) mapSheetAnalDataInferenceEntity.targetYyyy.eq(targetYyyy),
) mapSheetAnalDataInferenceEntity.stage.eq(stage))
.orderBy(mapSheetAnalDataInferenceEntity.analUid.asc()) .orderBy(mapSheetAnalDataInferenceEntity.analUid.asc())
.limit(1) .limit(1)
.fetchOne(); .fetchOne();
if (Objects.isNull(analEntity)) { if (Objects.isNull(analEntity)) {
throw new EntityNotFoundException("MapSheetAnalEntity not found for analUid: "); throw new EntityNotFoundException("MapSheetAnalEntity not found for analUid: ");
} }
return queryFactory return queryFactory
.selectFrom(labelingAssignmentEntity) .selectFrom(labelingAssignmentEntity)
.where( .where(
labelingAssignmentEntity.analUid.eq(analEntity.getAnalUid()), labelingAssignmentEntity.analUid.eq(analEntity.getAnalUid()),
labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()), labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()),
labelingAssignmentEntity.inspectorUid.isNull()) labelingAssignmentEntity.inspectorUid.isNull())
.orderBy(labelingAssignmentEntity.workerUid.asc()) .orderBy(labelingAssignmentEntity.workerUid.asc())
.fetch(); .fetch();
} }
@Override @Override
public Long findLabelUnAssignedCnt(Integer stage, Integer compareYyyy, Integer targetYyyy) { public Long findLabelUnAssignedCnt(Integer stage, Integer compareYyyy, Integer targetYyyy) {
return queryFactory return queryFactory
.select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count())
.from(mapSheetAnalDataInferenceGeomEntity) .from(mapSheetAnalDataInferenceGeomEntity)
.where( .where(
mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(compareYyyy), mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(compareYyyy),
mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(targetYyyy), mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(targetYyyy),
mapSheetAnalDataInferenceGeomEntity.stage.eq(stage), mapSheetAnalDataInferenceGeomEntity.stage.eq(stage),
mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) mapSheetAnalDataInferenceGeomEntity.labelState.isNull())
.fetchOne(); .fetchOne();
} }
@Override @Override
public void assignInspector(UUID assignmentUid, String inspectorUid) { public void assignInspector(UUID assignmentUid, String inspectorUid) {
queryFactory queryFactory
.update(labelingAssignmentEntity) .update(labelingAssignmentEntity)
.set(labelingAssignmentEntity.inspectorUid, inspectorUid) .set(labelingAssignmentEntity.inspectorUid, inspectorUid)
.where(labelingAssignmentEntity.assignmentUid.eq(assignmentUid)) .where(labelingAssignmentEntity.assignmentUid.eq(assignmentUid))
.execute(); .execute();
} }
@Override @Override
public List<UserList> availUserList(String role) { public List<UserList> availUserList(String role) {
return queryFactory return queryFactory
.select( .select(
Projections.constructor( Projections.constructor(
LabelAllocateDto.UserList.class, LabelAllocateDto.UserList.class,
memberEntity.userRole, memberEntity.userRole,
memberEntity.employeeNo, memberEntity.employeeNo,
memberEntity.name)) memberEntity.name))
.from(memberEntity) .from(memberEntity)
.where( .where(
memberEntity.userRole.eq(role), memberEntity.userRole.eq(role),
memberEntity.status.eq(com.kamco.cd.kamcoback.common.enums.StatusType.ACTIVE.getId())) memberEntity.status.eq(com.kamco.cd.kamcoback.common.enums.StatusType.ACTIVE.getId()))
.orderBy(memberEntity.name.asc()) .orderBy(memberEntity.name.asc())
.fetch(); .fetch();
} }
@Override @Override
public List<WorkerStatistics> findWorkerStatistics( public List<WorkerStatistics> findWorkerStatistics(
Long analUid, Long analUid,
String workerType, String workerType,
String searchName, String searchName,
String searchEmployeeNo, String searchEmployeeNo,
String sortType) { String sortType) {
// 작업자 유형에 따른 필드 선택 // 작업자 유형에 따른 필드 선택
StringExpression workerIdField = StringExpression workerIdField =
"REVIEWER".equals(workerType) "REVIEWER".equals(workerType)
? labelingAssignmentEntity.inspectorUid ? labelingAssignmentEntity.inspectorUid
: labelingAssignmentEntity.workerUid; : labelingAssignmentEntity.workerUid;
BooleanExpression workerCondition = BooleanExpression workerCondition =
"REVIEWER".equals(workerType) "REVIEWER".equals(workerType)
? labelingAssignmentEntity.inspectorUid.isNotNull() ? labelingAssignmentEntity.inspectorUid.isNotNull()
: labelingAssignmentEntity.workerUid.isNotNull(); : labelingAssignmentEntity.workerUid.isNotNull();
// 검색 조건 // 검색 조건
BooleanExpression searchCondition = null; BooleanExpression searchCondition = null;
@@ -218,49 +220,49 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
// 완료, 스킵, 남은 작업 계산 // 완료, 스킵, 남은 작업 계산
NumberExpression<Long> completedSum = NumberExpression<Long> completedSum =
new CaseBuilder() new CaseBuilder()
.when(labelingAssignmentEntity.workState.eq("DONE")) .when(labelingAssignmentEntity.workState.eq("DONE"))
.then(1L) .then(1L)
.otherwise(0L) .otherwise(0L)
.sum(); .sum();
NumberExpression<Long> skippedSum = NumberExpression<Long> skippedSum =
new CaseBuilder() new CaseBuilder()
.when(labelingAssignmentEntity.workState.eq("SKIP")) .when(labelingAssignmentEntity.workState.eq("SKIP"))
.then(1L) .then(1L)
.otherwise(0L) .otherwise(0L)
.sum(); .sum();
NumberExpression<Long> remainingSum = NumberExpression<Long> remainingSum =
new CaseBuilder() new CaseBuilder()
.when( .when(
labelingAssignmentEntity labelingAssignmentEntity
.workState .workState
.notIn("DONE", "SKIP") .notIn("DONE", "SKIP")
.and(labelingAssignmentEntity.workState.isNotNull())) .and(labelingAssignmentEntity.workState.isNotNull()))
.then(1L) .then(1L)
.otherwise(0L) .otherwise(0L)
.sum(); .sum();
// 기본 통계 조회 쿼리 // 기본 통계 조회 쿼리
var baseQuery = var baseQuery =
queryFactory queryFactory
.select( .select(
workerIdField, workerIdField,
memberEntity.name, memberEntity.name,
workerIdField.count(), workerIdField.count(),
completedSum, completedSum,
skippedSum, skippedSum,
remainingSum, remainingSum,
labelingAssignmentEntity.stagnationYn.max()) labelingAssignmentEntity.stagnationYn.max())
.from(labelingAssignmentEntity) .from(labelingAssignmentEntity)
.leftJoin(memberEntity) .leftJoin(memberEntity)
.on( .on(
"REVIEWER".equals(workerType) "REVIEWER".equals(workerType)
? memberEntity.employeeNo.eq(labelingAssignmentEntity.inspectorUid) ? memberEntity.employeeNo.eq(labelingAssignmentEntity.inspectorUid)
: memberEntity.employeeNo.eq(labelingAssignmentEntity.workerUid)) : memberEntity.employeeNo.eq(labelingAssignmentEntity.workerUid))
.where(labelingAssignmentEntity.analUid.eq(analUid), workerCondition, searchCondition) .where(labelingAssignmentEntity.analUid.eq(analUid), workerCondition, searchCondition)
.groupBy(workerIdField, memberEntity.name); .groupBy(workerIdField, memberEntity.name);
// 정렬 조건 적용 // 정렬 조건 적용
if (sortType != null) { if (sortType != null) {
@@ -286,132 +288,132 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
// 결과를 DTO로 변환 // 결과를 DTO로 변환
return baseQuery.fetch().stream() return baseQuery.fetch().stream()
.map( .map(
tuple -> { tuple -> {
Character maxStagnationYn = tuple.get(labelingAssignmentEntity.stagnationYn.max()); Character maxStagnationYn = tuple.get(labelingAssignmentEntity.stagnationYn.max());
return WorkerStatistics.builder() return WorkerStatistics.builder()
.workerId(tuple.get(workerIdField)) .workerId(tuple.get(workerIdField))
.workerName(tuple.get(memberEntity.name)) .workerName(tuple.get(memberEntity.name))
.workerType(workerType) .workerType(workerType)
.totalAssigned(tuple.get(workerIdField.count())) .totalAssigned(tuple.get(workerIdField.count()))
.completed(tuple.get(completedSum)) .completed(tuple.get(completedSum))
.skipped(tuple.get(skippedSum)) .skipped(tuple.get(skippedSum))
.remaining(tuple.get(remainingSum)) .remaining(tuple.get(remainingSum))
.history(null) // 3일 이력은 Service에서 채움 .history(null) // 3일 이력은 Service에서 채움
.isStagnated(maxStagnationYn != null && maxStagnationYn == 'Y') .isStagnated(maxStagnationYn != null && maxStagnationYn == 'Y')
.build(); .build();
}) })
.toList(); .toList();
} }
@Override @Override
public WorkProgressInfo findWorkProgressInfo(Long analUid) { public WorkProgressInfo findWorkProgressInfo(Long analUid) {
// 전체 배정 건수 // 전체 배정 건수
Long totalAssigned = Long totalAssigned =
queryFactory queryFactory
.select(labelingAssignmentEntity.count()) .select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity) .from(labelingAssignmentEntity)
.where(labelingAssignmentEntity.analUid.eq(analUid)) .where(labelingAssignmentEntity.analUid.eq(analUid))
.fetchOne(); .fetchOne();
// 완료 + 스킵 건수 // 완료 + 스킵 건수
Long completedCount = Long completedCount =
queryFactory queryFactory
.select(labelingAssignmentEntity.count()) .select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity) .from(labelingAssignmentEntity)
.where( .where(
labelingAssignmentEntity.analUid.eq(analUid), labelingAssignmentEntity.analUid.eq(analUid),
labelingAssignmentEntity.workState.in("DONE", "SKIP")) labelingAssignmentEntity.workState.in("DONE", "SKIP"))
.fetchOne(); .fetchOne();
// 투입된 라벨러 수 (고유한 worker_uid 수) // 투입된 라벨러 수 (고유한 worker_uid 수)
Long labelerCount = Long labelerCount =
queryFactory queryFactory
.select(labelingAssignmentEntity.workerUid.countDistinct()) .select(labelingAssignmentEntity.workerUid.countDistinct())
.from(labelingAssignmentEntity) .from(labelingAssignmentEntity)
.where( .where(
labelingAssignmentEntity.analUid.eq(analUid), labelingAssignmentEntity.analUid.eq(analUid),
labelingAssignmentEntity.workerUid.isNotNull()) labelingAssignmentEntity.workerUid.isNotNull())
.fetchOne(); .fetchOne();
// 남은 라벨링 작업 데이터 수 // 남은 라벨링 작업 데이터 수
Long remainingLabelCount = Long remainingLabelCount =
queryFactory queryFactory
.select(labelingAssignmentEntity.count()) .select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity) .from(labelingAssignmentEntity)
.where( .where(
labelingAssignmentEntity.analUid.eq(analUid), labelingAssignmentEntity.analUid.eq(analUid),
labelingAssignmentEntity.workerUid.isNotNull(), labelingAssignmentEntity.workerUid.isNotNull(),
labelingAssignmentEntity.workState.notIn("DONE", "SKIP")) labelingAssignmentEntity.workState.notIn("DONE", "SKIP"))
.fetchOne(); .fetchOne();
// 투입된 검수자 수 (고유한 inspector_uid 수) // 투입된 검수자 수 (고유한 inspector_uid 수)
Long inspectorCount = Long inspectorCount =
queryFactory queryFactory
.select(labelingAssignmentEntity.inspectorUid.countDistinct()) .select(labelingAssignmentEntity.inspectorUid.countDistinct())
.from(labelingAssignmentEntity) .from(labelingAssignmentEntity)
.where( .where(
labelingAssignmentEntity.analUid.eq(analUid), labelingAssignmentEntity.analUid.eq(analUid),
labelingAssignmentEntity.inspectorUid.isNotNull()) labelingAssignmentEntity.inspectorUid.isNotNull())
.fetchOne(); .fetchOne();
// 남은 검수 작업 데이터 수 // 남은 검수 작업 데이터 수
Long remainingInspectCount = Long remainingInspectCount =
queryFactory queryFactory
.select(labelingAssignmentEntity.count()) .select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity) .from(labelingAssignmentEntity)
.where( .where(
labelingAssignmentEntity.analUid.eq(analUid), labelingAssignmentEntity.analUid.eq(analUid),
labelingAssignmentEntity.inspectorUid.isNotNull(), labelingAssignmentEntity.inspectorUid.isNotNull(),
labelingAssignmentEntity.workState.notIn("DONE")) labelingAssignmentEntity.workState.notIn("DONE"))
.fetchOne(); .fetchOne();
// 진행률 계산 // 진행률 계산
double progressRate = 0.0; double progressRate = 0.0;
if (totalAssigned != null && totalAssigned > 0) { if (totalAssigned != null && totalAssigned > 0) {
progressRate = progressRate =
(completedCount != null ? completedCount.doubleValue() : 0.0) / totalAssigned * 100; (completedCount != null ? completedCount.doubleValue() : 0.0) / totalAssigned * 100;
} }
// 작업 상태 판단 (간단하게 진행률 100%면 종료, 아니면 진행중) // 작업 상태 판단 (간단하게 진행률 100%면 종료, 아니면 진행중)
String workStatus = (progressRate >= 100.0) ? "종료" : "진행중"; String workStatus = (progressRate >= 100.0) ? "종료" : "진행중";
return WorkProgressInfo.builder() return WorkProgressInfo.builder()
.labelingProgressRate(progressRate) .labelingProgressRate(progressRate)
.workStatus(workStatus) .workStatus(workStatus)
.completedCount(completedCount != null ? completedCount : 0L) .completedCount(completedCount != null ? completedCount : 0L)
.totalAssignedCount(totalAssigned != null ? totalAssigned : 0L) .totalAssignedCount(totalAssigned != null ? totalAssigned : 0L)
.labelerCount(labelerCount != null ? labelerCount : 0L) .labelerCount(labelerCount != null ? labelerCount : 0L)
.remainingLabelCount(remainingLabelCount != null ? remainingLabelCount : 0L) .remainingLabelCount(remainingLabelCount != null ? remainingLabelCount : 0L)
.inspectorCount(inspectorCount != null ? inspectorCount : 0L) .inspectorCount(inspectorCount != null ? inspectorCount : 0L)
.remainingInspectCount(remainingInspectCount != null ? remainingInspectCount : 0L) .remainingInspectCount(remainingInspectCount != null ? remainingInspectCount : 0L)
.build(); .build();
} }
@Override @Override
public Long findDailyProcessedCount( public Long findDailyProcessedCount(
String workerId, String workerType, LocalDate date, Long analUid) { String workerId, String workerType, LocalDate date, Long analUid) {
// 해당 날짜의 시작과 끝 시간 // 해당 날짜의 시작과 끝 시간
ZonedDateTime startOfDay = date.atStartOfDay(ZoneId.systemDefault()); ZonedDateTime startOfDay = date.atStartOfDay(ZoneId.systemDefault());
ZonedDateTime endOfDay = date.atTime(LocalTime.MAX).atZone(ZoneId.systemDefault()); ZonedDateTime endOfDay = date.atTime(LocalTime.MAX).atZone(ZoneId.systemDefault());
BooleanExpression workerCondition = BooleanExpression workerCondition =
"REVIEWER".equals(workerType) "REVIEWER".equals(workerType)
? labelingAssignmentEntity.inspectorUid.eq(workerId) ? labelingAssignmentEntity.inspectorUid.eq(workerId)
: labelingAssignmentEntity.workerUid.eq(workerId); : labelingAssignmentEntity.workerUid.eq(workerId);
Long count = Long count =
queryFactory queryFactory
.select(labelingAssignmentEntity.count()) .select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity) .from(labelingAssignmentEntity)
.where( .where(
labelingAssignmentEntity.analUid.eq(analUid), labelingAssignmentEntity.analUid.eq(analUid),
workerCondition, workerCondition,
labelingAssignmentEntity.workState.in( labelingAssignmentEntity.workState.in(
LabelState.DONE.getId(), LabelState.SKIP.getId()), LabelState.DONE.getId(), LabelState.SKIP.getId()),
labelingAssignmentEntity.modifiedDate.between(startOfDay, endOfDay)) labelingAssignmentEntity.modifiedDate.between(startOfDay, endOfDay))
.fetchOne(); .fetchOne();
return count != null ? count : 0L; return count != null ? count : 0L;
} }
@@ -419,172 +421,175 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
@Override @Override
public void assignInspectorBulk(List<UUID> assignmentUids, String inspectorUid) { public void assignInspectorBulk(List<UUID> assignmentUids, String inspectorUid) {
queryFactory queryFactory
.update(labelingAssignmentEntity) .update(labelingAssignmentEntity)
.set(labelingAssignmentEntity.inspectorUid, inspectorUid) .set(labelingAssignmentEntity.inspectorUid, inspectorUid)
.where(labelingAssignmentEntity.assignmentUid.in(assignmentUids)) .where(labelingAssignmentEntity.assignmentUid.in(assignmentUids))
.execute(); .execute();
em.clear(); em.clear();
} }
@Override @Override
public InferenceDetail findInferenceDetail(Integer compareYyyy, Integer targetYyyy, Integer stage) { public InferenceDetail findInferenceDetail(
Integer compareYyyy, Integer targetYyyy, Integer stage) {
// analUid로 분석 정보 조회 // analUid로 분석 정보 조회
MapSheetAnalDataInferenceEntity analEntity = MapSheetAnalDataInferenceEntity analEntity =
queryFactory queryFactory
.selectFrom(mapSheetAnalDataInferenceEntity) .selectFrom(mapSheetAnalDataInferenceEntity)
.where(mapSheetAnalDataInferenceEntity.compareYyyy.eq(compareYyyy), .where(
mapSheetAnalDataInferenceEntity.targetYyyy.eq(targetYyyy), mapSheetAnalDataInferenceEntity.compareYyyy.eq(compareYyyy),
mapSheetAnalDataInferenceEntity.stage.eq(stage) mapSheetAnalDataInferenceEntity.targetYyyy.eq(targetYyyy),
) mapSheetAnalDataInferenceEntity.stage.eq(stage))
.orderBy(mapSheetAnalDataInferenceEntity.analUid.asc()) .orderBy(mapSheetAnalDataInferenceEntity.analUid.asc())
.limit(1) .limit(1)
.fetchOne(); .fetchOne();
return queryFactory return queryFactory
.select( .select(
Projections.constructor( Projections.constructor(
InferenceDetail.class, InferenceDetail.class,
mapSheetAnalEntity.analTitle, mapSheetAnalEntity.analTitle,
Expressions.numberTemplate(Integer.class, "{0}", 4), Expressions.numberTemplate(Integer.class, "{0}", 4),
mapSheetAnalEntity.gukyuinApplyDttm, mapSheetAnalEntity.gukyuinApplyDttm,
mapSheetAnalEntity.detectingCnt, mapSheetAnalEntity.detectingCnt,
labelingAssignmentEntity.workerUid.countDistinct(), labelingAssignmentEntity.workerUid.countDistinct(),
labelingAssignmentEntity.inspectorUid.countDistinct())) labelingAssignmentEntity.inspectorUid.countDistinct()))
.from(mapSheetAnalEntity) .from(mapSheetAnalEntity)
.innerJoin(labelingAssignmentEntity) .innerJoin(labelingAssignmentEntity)
.on(mapSheetAnalEntity.id.eq(labelingAssignmentEntity.analUid)) .on(mapSheetAnalEntity.id.eq(labelingAssignmentEntity.analUid))
.where(mapSheetAnalEntity.id.eq(analEntity.getAnalUid())) .where(mapSheetAnalEntity.id.eq(analEntity.getAnalUid()))
.groupBy( .groupBy(
mapSheetAnalEntity.analTitle, mapSheetAnalEntity.analTitle,
mapSheetAnalEntity.gukyuinApplyDttm, mapSheetAnalEntity.gukyuinApplyDttm,
mapSheetAnalEntity.detectingCnt) mapSheetAnalEntity.detectingCnt)
.fetchOne(); .fetchOne();
} }
@Override @Override
public List<Long> fetchNextMoveIds(Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) { public List<Long> fetchNextMoveIds(
Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) {
return queryFactory return queryFactory
.select(mapSheetAnalDataInferenceGeomEntity.geoUid) .select(mapSheetAnalDataInferenceGeomEntity.geoUid)
.from(mapSheetAnalDataInferenceGeomEntity) .from(mapSheetAnalDataInferenceGeomEntity)
.where( .where(
// mapSheetAnalDataGeomEntity.pnu.isNotNull(), //TODO: Mockup 진행 이후 확인하기 // mapSheetAnalDataGeomEntity.pnu.isNotNull(), //TODO: Mockup 진행 이후 확인하기
lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId), lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId),
mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(compareYyyy), mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(compareYyyy),
mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(targetYyyy), mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(targetYyyy),
mapSheetAnalDataInferenceGeomEntity.stage.eq(stage), mapSheetAnalDataInferenceGeomEntity.stage.eq(stage),
mapSheetAnalDataInferenceGeomEntity.labelState.in( mapSheetAnalDataInferenceGeomEntity.labelState.in(
LabelState.ASSIGNED.getId(), LabelState.SKIP.getId())) LabelState.ASSIGNED.getId(), LabelState.SKIP.getId()))
.orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc()) .orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc())
.limit(batchSize) .limit(batchSize)
.fetch(); .fetch();
} }
@Override @Override
public Long findLabelUnCompleteCnt(Long analUid) { public Long findLabelUnCompleteCnt(Long analUid) {
MapSheetAnalEntity entity = MapSheetAnalEntity entity =
queryFactory queryFactory
.selectFrom(mapSheetAnalEntity) .selectFrom(mapSheetAnalEntity)
.where(mapSheetAnalEntity.id.eq(analUid)) .where(mapSheetAnalEntity.id.eq(analUid))
.fetchOne(); .fetchOne();
if (Objects.isNull(entity)) { if (Objects.isNull(entity)) {
throw new EntityNotFoundException(); throw new EntityNotFoundException();
} }
return queryFactory return queryFactory
.select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count())
.from(mapSheetAnalDataInferenceGeomEntity) .from(mapSheetAnalDataInferenceGeomEntity)
.where( .where(
mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(entity.getCompareYyyy()), mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(entity.getCompareYyyy()),
mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(entity.getTargetYyyy()), mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(entity.getTargetYyyy()),
mapSheetAnalDataInferenceGeomEntity.stage.eq(4), // TODO: 회차 컬럼을 가져와야 할 듯? mapSheetAnalDataInferenceGeomEntity.stage.eq(4), // TODO: 회차 컬럼을 가져와야 할 듯?
mapSheetAnalDataInferenceGeomEntity.labelState.in( mapSheetAnalDataInferenceGeomEntity.labelState.in(
LabelState.ASSIGNED.getId(), LabelState.SKIP.getId())) LabelState.ASSIGNED.getId(), LabelState.SKIP.getId()))
.fetchOne(); .fetchOne();
} }
@Transactional @Transactional
@Override @Override
public void assignOwnerMove(List<Long> sub, String userId) { public void assignOwnerMove(List<Long> sub, String userId) {
queryFactory queryFactory
.update(labelingAssignmentEntity) .update(labelingAssignmentEntity)
.set(labelingAssignmentEntity.workerUid, userId) .set(labelingAssignmentEntity.workerUid, userId)
.where(labelingAssignmentEntity.inferenceGeomUid.in(sub)) .where(labelingAssignmentEntity.inferenceGeomUid.in(sub))
.execute(); .execute();
em.clear(); em.clear();
} }
@Override @Override
public LabelerDetail findLabelerDetail(String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) { public LabelerDetail findLabelerDetail(
String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) {
NumberExpression<Long> assignedCnt = NumberExpression<Long> assignedCnt =
new CaseBuilder() new CaseBuilder()
.when(labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId())) .when(labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()))
.then(1L) .then(1L)
.otherwise((Long) null) .otherwise((Long) null)
.count(); .count();
NumberExpression<Long> skipCnt = NumberExpression<Long> skipCnt =
new CaseBuilder() new CaseBuilder()
.when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId()))
.then(1L) .then(1L)
.otherwise((Long) null) .otherwise((Long) null)
.count(); .count();
NumberExpression<Long> completeCnt = NumberExpression<Long> completeCnt =
new CaseBuilder() new CaseBuilder()
.when(labelingAssignmentEntity.workState.eq(LabelState.COMPLETE.getId())) .when(labelingAssignmentEntity.workState.eq(LabelState.COMPLETE.getId()))
.then(1L) .then(1L)
.otherwise((Long) null) .otherwise((Long) null)
.count(); .count();
NumberExpression<Double> percent = NumberExpression<Double> percent =
new CaseBuilder() new CaseBuilder()
.when(completeCnt.eq(0L)) .when(completeCnt.eq(0L))
.then(0.0) .then(0.0)
.otherwise( .otherwise(
Expressions.numberTemplate( Expressions.numberTemplate(
Double.class, Double.class,
"round({0} / {1}, 2)", "round({0} / {1}, 2)",
labelingAssignmentEntity.count(), labelingAssignmentEntity.count(),
completeCnt)); completeCnt));
// analUid로 분석 정보 조회 // analUid로 분석 정보 조회
MapSheetAnalDataInferenceEntity analEntity = MapSheetAnalDataInferenceEntity analEntity =
queryFactory queryFactory
.selectFrom(mapSheetAnalDataInferenceEntity) .selectFrom(mapSheetAnalDataInferenceEntity)
.where(mapSheetAnalDataInferenceEntity.compareYyyy.eq(compareYyyy), .where(
mapSheetAnalDataInferenceEntity.targetYyyy.eq(targetYyyy), mapSheetAnalDataInferenceEntity.compareYyyy.eq(compareYyyy),
mapSheetAnalDataInferenceEntity.stage.eq(stage) mapSheetAnalDataInferenceEntity.targetYyyy.eq(targetYyyy),
) mapSheetAnalDataInferenceEntity.stage.eq(stage))
.orderBy(mapSheetAnalDataInferenceEntity.analUid.asc()) .orderBy(mapSheetAnalDataInferenceEntity.analUid.asc())
.limit(1) .limit(1)
.fetchOne(); .fetchOne();
if (Objects.isNull(analEntity)) { if (Objects.isNull(analEntity)) {
throw new EntityNotFoundException("MapSheetAnalEntity not found for analUid: "); throw new EntityNotFoundException("MapSheetAnalEntity not found for analUid: ");
} }
return queryFactory return queryFactory
.select( .select(
Projections.constructor( Projections.constructor(
LabelerDetail.class, LabelerDetail.class,
memberEntity.userRole, memberEntity.userRole,
memberEntity.name, memberEntity.name,
memberEntity.employeeNo, memberEntity.employeeNo,
assignedCnt, assignedCnt,
skipCnt, skipCnt,
completeCnt, completeCnt,
percent)) percent))
.from(memberEntity) .from(memberEntity)
.innerJoin(labelingAssignmentEntity) .innerJoin(labelingAssignmentEntity)
.on( .on(
memberEntity.employeeNo.eq(labelingAssignmentEntity.workerUid), memberEntity.employeeNo.eq(labelingAssignmentEntity.workerUid),
labelingAssignmentEntity.analUid.eq(analEntity.getAnalUid())) labelingAssignmentEntity.analUid.eq(analEntity.getAnalUid()))
.where(memberEntity.employeeNo.eq(userId)) .where(memberEntity.employeeNo.eq(userId))
.groupBy(memberEntity.userRole, memberEntity.name, memberEntity.employeeNo) .groupBy(memberEntity.userRole, memberEntity.name, memberEntity.employeeNo)
.fetchOne(); .fetchOne();
} }
} }

View File

@@ -1,23 +1,11 @@
package com.kamco.cd.kamcoback.postgres.repository.label; package com.kamco.cd.kamcoback.postgres.repository.label;
import static com.kamco.cd.kamcoback.postgres.entity.QLabelingAssignmentEntity.labelingAssignmentEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity.mapInkx5kEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceEntity.mapSheetAnalDataInferenceEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceEntity.mapSheetAnalDataInferenceEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalEntity.mapSheetAnalEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngEntity.mapSheetMngEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngHstEntity.mapSheetMngHstEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMemberEntity.memberEntity;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList;
import com.kamco.cd.kamcoback.label.dto.LabelWorkDto; import com.kamco.cd.kamcoback.label.dto.LabelWorkDto;
import com.kamco.cd.kamcoback.label.dto.LabelWorkDto.LabelWorkMng; import com.kamco.cd.kamcoback.label.dto.LabelWorkDto.LabelWorkMng;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.ErrorDataDto;
import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataGeomEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataGeomEntity;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalEntity;
import com.querydsl.core.BooleanBuilder; import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections; import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.CaseBuilder; import com.querydsl.core.types.dsl.CaseBuilder;
@@ -25,16 +13,9 @@ import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.StringExpression; import com.querydsl.core.types.dsl.StringExpression;
import com.querydsl.jpa.impl.JPAQueryFactory; import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import jakarta.validation.Valid;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageImpl;
@@ -58,7 +39,6 @@ public class LabelWorkRepositoryImpl extends QuerydslRepositorySupport
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
} }
@Override @Override
public Page<LabelWorkMng> labelWorkMngList(LabelWorkDto.LabelWorkMngSearchReq searchReq) { public Page<LabelWorkMng> labelWorkMngList(LabelWorkDto.LabelWorkMngSearchReq searchReq) {
@@ -72,69 +52,67 @@ public class LabelWorkRepositoryImpl extends QuerydslRepositorySupport
whereBuilder.and(mapSheetAnalDataInferenceEntity.targetYyyy.eq(searchReq.getDetectYyyy())); whereBuilder.and(mapSheetAnalDataInferenceEntity.targetYyyy.eq(searchReq.getDetectYyyy()));
} }
//mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id) // mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id)
whereSubBuilder.and(mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id)); whereSubBuilder.and(
mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id));
if (searchReq.getStrtDttm() != null && ! searchReq.getStrtDttm().isEmpty() if (searchReq.getStrtDttm() != null
&& searchReq.getEndDttm() != null && ! searchReq.getEndDttm().isEmpty()) { && !searchReq.getStrtDttm().isEmpty()
&& searchReq.getEndDttm() != null
&& !searchReq.getEndDttm().isEmpty()) {
//whereSubBuilder.and(mapSheetAnalDataInferenceGeomEntity.labelStateDttm.isNotNull()); // whereSubBuilder.and(mapSheetAnalDataInferenceGeomEntity.labelStateDttm.isNotNull());
whereSubBuilder.and( whereSubBuilder.and(
Expressions.stringTemplate("to_char({0}, 'YYYYMMDD')", mapSheetAnalDataInferenceGeomEntity.labelStateDttm) Expressions.stringTemplate(
.between(searchReq.getStrtDttm(), searchReq.getEndDttm()) "to_char({0}, 'YYYYMMDD')", mapSheetAnalDataInferenceGeomEntity.labelStateDttm)
); .between(searchReq.getStrtDttm(), searchReq.getEndDttm()));
//whereBuilder.and(mapSheetAnalDataInferenceGeomEntity.labelStateDttm.min().isNotNull()); // whereBuilder.and(mapSheetAnalDataInferenceGeomEntity.labelStateDttm.min().isNotNull());
} }
List<LabelWorkMng> foundContent = List<LabelWorkMng> foundContent =
queryFactory queryFactory
.select( .select(
Projections.constructor( Projections.constructor(
LabelWorkMng.class, LabelWorkMng.class,
mapSheetAnalDataInferenceEntity.compareYyyy, mapSheetAnalDataInferenceEntity.compareYyyy,
mapSheetAnalDataInferenceEntity.targetYyyy, mapSheetAnalDataInferenceEntity.targetYyyy,
mapSheetAnalDataInferenceEntity.stage, mapSheetAnalDataInferenceEntity.stage,
mapSheetAnalDataInferenceEntity.createdDttm.min(), mapSheetAnalDataInferenceEntity.createdDttm.min(),
mapSheetAnalDataInferenceGeomEntity.dataUid.count(), mapSheetAnalDataInferenceGeomEntity.dataUid.count(),
mapSheetAnalDataInferenceGeomEntity.dataUid.count(), mapSheetAnalDataInferenceGeomEntity.dataUid.count(),
new CaseBuilder()
new CaseBuilder() .when(mapSheetAnalDataInferenceGeomEntity.labelState.eq("STOP"))
.when(mapSheetAnalDataInferenceGeomEntity.labelState.eq("STOP")) .then(1L)
.then(1L) .otherwise(0L)
.otherwise(0L) .sum(),
.sum(), new CaseBuilder()
new CaseBuilder() .when(mapSheetAnalDataInferenceGeomEntity.labelState.eq("LABEL_ING"))
.when(mapSheetAnalDataInferenceGeomEntity.labelState.eq("LABEL_ING")) .then(1L)
.then(1L) .otherwise(0L)
.otherwise(0L) .sum(),
.sum(), new CaseBuilder()
new CaseBuilder() .when(mapSheetAnalDataInferenceGeomEntity.labelState.eq("LABEL_COMPLETE"))
.when(mapSheetAnalDataInferenceGeomEntity.labelState.eq("LABEL_COMPLETE")) .then(1L)
.then(1L) .otherwise(0L)
.otherwise(0L) .sum(),
.sum(), mapSheetAnalDataInferenceGeomEntity.labelStateDttm.min()))
.from(mapSheetAnalDataInferenceEntity)
mapSheetAnalDataInferenceGeomEntity.labelStateDttm.min() .innerJoin(mapSheetAnalDataInferenceGeomEntity)
)) .on(whereSubBuilder)
.from(mapSheetAnalDataInferenceEntity) .where(whereBuilder)
.innerJoin(mapSheetAnalDataInferenceGeomEntity) .groupBy(
.on(whereSubBuilder) mapSheetAnalDataInferenceEntity.compareYyyy,
.where(whereBuilder) mapSheetAnalDataInferenceEntity.targetYyyy,
.groupBy( mapSheetAnalDataInferenceEntity.stage)
mapSheetAnalDataInferenceEntity.compareYyyy, .orderBy(
mapSheetAnalDataInferenceEntity.targetYyyy, mapSheetAnalDataInferenceEntity.targetYyyy.desc(),
mapSheetAnalDataInferenceEntity.stage mapSheetAnalDataInferenceEntity.stage.desc())
) .offset(pageable.getOffset())
.orderBy(mapSheetAnalDataInferenceEntity.targetYyyy.desc() .limit(pageable.getPageSize())
,mapSheetAnalDataInferenceEntity.stage.desc()) .fetch();
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
/* /*
Long countQuery = Long countQuery =