From cc4a0c024c6f78ebc784e64caa3c31adfc727d9a Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 20 Jan 2026 14:34:45 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=EC=B6=94=EB=A1=A0=20=EA=B2=B0=EA=B3=BC=20g?= =?UTF-8?q?eom=20=EC=A1=B0=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/Inference/MapSheetLearnRepositoryImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java index 48ba9e7f..56091dc9 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java @@ -397,6 +397,11 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto "%" + searchGeoReq.getMapSheetNum() + "%")); } + where.and(mapSheetAnalDataInferenceGeomEntity.classAfterCd.isNotNull()); + where.and(mapSheetAnalDataInferenceGeomEntity.classAfterProb.isNotNull()); + where.and(mapSheetAnalDataInferenceGeomEntity.classBeforeCd.isNotNull()); + where.and(mapSheetAnalDataInferenceGeomEntity.classBeforeProb.isNotNull()); + // 3) inkx 조인 조건: JPQL/HQL에서 '~' 불가 → function('regexp_match', ...) 사용 BooleanExpression inkxIsNumeric = Expressions.booleanTemplate( From ab39ce5e850bed6c269ea5c23037e80d3ad6075c Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 14:50:46 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=ED=95=99=EC=8A=B5=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=EC=A0=9C=EC=9E=91=20=EC=83=81=ED=83=9C=20update,=20IN?= =?UTF-8?q?G=20=EC=9D=B8=20=EA=B1=B4=EC=88=98=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../label/LabelAllocateApiController.java | 12 + .../label/service/LabelAllocateService.java | 11 +- .../core/LabelAllocateCoreService.java | 8 + .../core/TrainingDataLabelCoreService.java | 7 +- .../core/TrainingDataReviewCoreService.java | 7 +- .../InferenceResultRepositoryImpl.java | 6 +- .../label/LabelAllocateRepositoryCustom.java | 4 + .../label/LabelAllocateRepositoryImpl.java | 1928 +++++++++-------- .../TrainingDataLabelRepositoryCustom.java | 5 +- .../TrainingDataLabelRepositoryImpl.java | 20 +- .../TrainingDataReviewRepositoryCustom.java | 5 +- .../TrainingDataReviewRepositoryImpl.java | 20 +- .../dto/TrainingDataLabelDto.java | 13 + .../service/TrainingDataLabelService.java | 10 +- .../service/TrainingDataReviewService.java | 10 +- 15 files changed, 1102 insertions(+), 964 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java index ffdca9fd..56d3f9ad 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java @@ -318,4 +318,16 @@ public class LabelAllocateApiController { LabelAllocateDto.searchReq searchReq = new LabelAllocateDto.searchReq(page, size, ""); return ApiResponseDto.ok(labelAllocateService.findWorkHistoryList(searchReq, userId, type)); } + + @Operation(summary = "라벨링 작업 중인 회차 있는지 여부", description = "라벨링 작업 중인 회차 있는지 여부") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "조회 성공"), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음"), + @ApiResponse(responseCode = "500", description = "서버 오류") + }) + @GetMapping("/ing-process-cnt") + public ApiResponseDto labelingIngProcessCnt() { + return ApiResponseDto.ok(labelAllocateService.findLabelingIngProcessCnt()); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java index 594972fe..2cb5401d 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java @@ -5,6 +5,7 @@ import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.AllocateInfoDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelMngState; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelingStatDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.MoveInfo; @@ -80,11 +81,13 @@ public class LabelAllocateService { labelAllocateCoreService.insertLabelerUser(analUid, target.getUserId(), target.getDemand()); } - // 검수자 할당 테이블에 insert. TODO: 익일 배치로 라벨링 완료된 내역을 검수자에게 할당해야 함 + // 검수자 할당 테이블에 insert. for (String inspector : targetInspectors) { labelAllocateCoreService.insertInspector(analUid, inspector); } + labelAllocateCoreService.updateAnalInferenceMngState(uuid, LabelMngState.ASSIGNED.getId()); + return new ApiResponseDto.ResponseObj(ApiResponseCode.OK, "배정이 완료되었습니다."); } @@ -255,6 +258,8 @@ public class LabelAllocateService { } labelAllocateCoreService.updateClosedYnByUuid(targetUuid, closedType, closedYn); + labelAllocateCoreService.updateAnalInferenceMngState( + UUID.fromString(targetUuid), LabelMngState.FINISH.getId()); } public Page findWorkHistoryList(searchReq searchReq, String userId, String type) { @@ -264,4 +269,8 @@ public class LabelAllocateService { return labelAllocateCoreService.workReviewerHistoryList(searchReq, userId); } } + + public Long findLabelingIngProcessCnt() { + return labelAllocateCoreService.findLabelingIngProcessCnt(); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java index 02073b62..1ee3838b 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java @@ -226,4 +226,12 @@ public class LabelAllocateCoreService { public Page workReviewerHistoryList(searchReq searchReq, String userId) { return labelAllocateRepository.workReviewerHistoryList(searchReq, userId); } + + public void updateAnalInferenceMngState(UUID uuid, String status) { + labelAllocateRepository.updateAnalInferenceMngState(uuid, status); + } + + public Long findLabelingIngProcessCnt() { + return labelAllocateRepository.findLabelingIngProcessCnt(); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataLabelCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataLabelCoreService.java index 08dc40f8..21d3189f 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataLabelCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataLabelCoreService.java @@ -4,6 +4,7 @@ import com.kamco.cd.kamcoback.postgres.repository.trainingdata.TrainingDataLabel import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.DefaultPaging; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.DetailRes; +import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.InferenceIdInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.LabelFeatureRequest.LabelProperties; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.LabelingGeometryInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.LabelingListDto; @@ -29,7 +30,7 @@ public class TrainingDataLabelCoreService { return trainingDataLabelRepository.findLabelingAssignedGeom(assignmentUid); } - public Long findLabelingAssignmentGeoUid(String assignmentUid) { + public InferenceIdInfo findLabelingAssignmentGeoUid(String assignmentUid) { return trainingDataLabelRepository.findLabelingAssignmentGeoUid(assignmentUid); } @@ -89,4 +90,8 @@ public class TrainingDataLabelCoreService { String mapSheetNum, Integer beforeYear, Integer afterYear) { return trainingDataLabelRepository.getCogImageUrl(mapSheetNum, beforeYear, afterYear); } + + public void updateAnalInferenceMngState(Long analUid, String status) { + trainingDataLabelRepository.updateAnalInferenceMngState(analUid, status); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataReviewCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataReviewCoreService.java index 0dceee4e..22b9b8f3 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataReviewCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataReviewCoreService.java @@ -1,6 +1,7 @@ package com.kamco.cd.kamcoback.postgres.core; import com.kamco.cd.kamcoback.postgres.repository.trainingdata.TrainingDataReviewRepository; +import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.InferenceIdInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.DefaultPaging; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.DetailRes; @@ -29,7 +30,7 @@ public class TrainingDataReviewCoreService { return trainingDataReviewRepository.findReviewAssignedGeom(operatorUid); } - public Long findReviewOperatorGeoUid(String operatorUid) { + public InferenceIdInfo findReviewOperatorGeoUid(String operatorUid) { return trainingDataReviewRepository.findReviewOperatorGeoUid(operatorUid); } @@ -89,4 +90,8 @@ public class TrainingDataReviewCoreService { String mapSheetNum, Integer beforeYear, Integer afterYear) { return trainingDataReviewRepository.getCogImageUrl(mapSheetNum, beforeYear, afterYear); } + + public void updateAnalInferenceMngState(Long analUid, String status) { + trainingDataReviewRepository.updateAnalInferenceMngState(analUid, status); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java index c2449f2b..71278059 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java @@ -52,7 +52,8 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC m1_model_batch_id, m2_model_batch_id, m3_model_batch_id, - learn_id + learn_id, + anal_state ) SELECT r.stage, @@ -64,7 +65,8 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC r.m1_model_batch_id, r.m2_model_batch_id, r.m3_model_batch_id, - r.id + r.id, + LabelState.PENDING.getId(), FROM tb_map_sheet_learn r WHERE r.id = :id ON CONFLICT (stage, compare_yyyy, target_yyyy) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java index 478c1613..c5d5aba3 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java @@ -100,4 +100,8 @@ public interface LabelAllocateRepositoryCustom { Page workLabelHistoryList(LabelAllocateDto.searchReq searchReq, String userId); Page workReviewerHistoryList(searchReq searchReq, String userId); + + void updateAnalInferenceMngState(UUID uuid, String status); + + Long findLabelingIngProcessCnt(); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java index 040dfcf7..d8e01a6d 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java @@ -13,6 +13,7 @@ import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.AllocateInfoDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InspectState; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelMngState; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelingStatDto; @@ -63,32 +64,33 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto private final JPAQueryFactory queryFactory; - @PersistenceContext private EntityManager em; + @PersistenceContext + private EntityManager em; @Override public List fetchNextIds(Long lastId, Long batchSize, UUID uuid) { return queryFactory - .select( - Projections.constructor( - AllocateInfoDto.class, - mapSheetAnalDataInferenceGeomEntity.geoUid, - mapSheetAnalDataInferenceGeomEntity.mapSheetNum, - mapSheetAnalDataInferenceGeomEntity.pnu)) - .from(mapSheetAnalInferenceEntity) - .innerJoin(mapSheetAnalDataInferenceEntity) - .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) - .innerJoin(mapSheetAnalDataInferenceGeomEntity) - .on( - mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid), - mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), - mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) - .where( - mapSheetAnalInferenceEntity.uuid.eq(uuid), - lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId)) - .orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc()) - .limit(batchSize) - .fetch(); + .select( + Projections.constructor( + AllocateInfoDto.class, + mapSheetAnalDataInferenceGeomEntity.geoUid, + mapSheetAnalDataInferenceGeomEntity.mapSheetNum, + mapSheetAnalDataInferenceGeomEntity.pnu)) + .from(mapSheetAnalInferenceEntity) + .innerJoin(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) + .innerJoin(mapSheetAnalDataInferenceGeomEntity) + .on( + mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid), + mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), + mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) + .where( + mapSheetAnalInferenceEntity.uuid.eq(uuid), + lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId)) + .orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc()) + .limit(batchSize) + .fetch(); } @Override @@ -96,10 +98,10 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.id.eq(analUid)) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.id.eq(analUid)) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); @@ -107,190 +109,190 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // data_geom 테이블에 label state 를 ASSIGNED 로 update List geoUidList = - ids.stream().map(AllocateInfoDto::getGeoUid).filter(Objects::nonNull).toList(); + ids.stream().map(AllocateInfoDto::getGeoUid).filter(Objects::nonNull).toList(); queryFactory - .update(mapSheetAnalDataInferenceGeomEntity) - .set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId()) - .set(mapSheetAnalDataInferenceGeomEntity.labelStateDttm, ZonedDateTime.now()) - .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(geoUidList)) - .execute(); + .update(mapSheetAnalDataInferenceGeomEntity) + .set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId()) + .set(mapSheetAnalDataInferenceGeomEntity.labelStateDttm, ZonedDateTime.now()) + .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(geoUidList)) + .execute(); // 라벨러 할당 테이블에 insert Session session = em.unwrap(Session.class); session.doWork( - connection -> { - String sql = - """ + connection -> { + String sql = + """ insert into tb_labeling_assignment (assignment_uid, inference_geom_uid, worker_uid, work_state, assign_group_id, anal_uid, pnu) values (?, ?, ?, ?, ?, ?, ?) """; - try (PreparedStatement ps = connection.prepareStatement(sql)) { - int batchSize = 0; + try (PreparedStatement ps = connection.prepareStatement(sql)) { + int batchSize = 0; - for (AllocateInfoDto info : ids) { - ps.setObject(1, UUID.randomUUID()); - ps.setLong(2, info.getGeoUid()); - ps.setString(3, userId); - ps.setString(4, LabelState.ASSIGNED.getId()); - ps.setString(5, String.valueOf(info.getMapSheetNum())); - ps.setLong(6, analEntity.getId()); - ps.setLong(7, info.getPnu()); + for (AllocateInfoDto info : ids) { + ps.setObject(1, UUID.randomUUID()); + ps.setLong(2, info.getGeoUid()); + ps.setString(3, userId); + ps.setString(4, LabelState.ASSIGNED.getId()); + ps.setString(5, String.valueOf(info.getMapSheetNum())); + ps.setLong(6, analEntity.getId()); + ps.setLong(7, info.getPnu()); - ps.addBatch(); - batchSize++; + ps.addBatch(); + batchSize++; - if (batchSize % 1000 == 0) { - ps.executeBatch(); - ps.clearBatch(); - } + if (batchSize % 1000 == 0) { + ps.executeBatch(); + ps.clearBatch(); } - - ps.executeBatch(); } - }); + + ps.executeBatch(); + } + }); } @Override public List findAssignedLabelerList(Long analUid) { // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.id.eq(analUid)) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.id.eq(analUid)) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("mapSheetAnalInferenceEntity not found for analUid: "); } return queryFactory - .selectFrom(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.analUid.eq(analEntity.getId()), - labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()), - labelingAssignmentEntity.inspectorUid.isNull()) - .orderBy(labelingAssignmentEntity.workerUid.asc()) - .fetch(); + .selectFrom(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.analUid.eq(analEntity.getId()), + labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()), + labelingAssignmentEntity.inspectorUid.isNull()) + .orderBy(labelingAssignmentEntity.workerUid.asc()) + .fetch(); } @Override public Long findLabelUnAssignedCnt(UUID uuid) { return queryFactory - .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) - .from(mapSheetAnalInferenceEntity) - .innerJoin(mapSheetAnalDataInferenceEntity) - .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) - .innerJoin(mapSheetAnalDataInferenceGeomEntity) - .on( - mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid), - mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), - mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) - .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) - .fetchOne(); + .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) + .from(mapSheetAnalInferenceEntity) + .innerJoin(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) + .innerJoin(mapSheetAnalDataInferenceGeomEntity) + .on( + mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid), + mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), + mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) + .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) + .fetchOne(); } @Override public void assignInspector(UUID assignmentUid, String inspectorUid) { queryFactory - .update(labelingAssignmentEntity) - .set(labelingAssignmentEntity.inspectorUid, inspectorUid) - .where(labelingAssignmentEntity.assignmentUid.eq(assignmentUid)) - .execute(); + .update(labelingAssignmentEntity) + .set(labelingAssignmentEntity.inspectorUid, inspectorUid) + .where(labelingAssignmentEntity.assignmentUid.eq(assignmentUid)) + .execute(); } @Override public List availUserList(String role) { return queryFactory - .select( - Projections.constructor( - LabelAllocateDto.UserList.class, - memberEntity.userRole, - memberEntity.employeeNo, - memberEntity.name)) - .from(memberEntity) - .where( - memberEntity.userRole.eq(role), - memberEntity.status.eq(com.kamco.cd.kamcoback.common.enums.StatusType.ACTIVE.getId())) - .orderBy(memberEntity.name.asc()) - .fetch(); + .select( + Projections.constructor( + LabelAllocateDto.UserList.class, + memberEntity.userRole, + memberEntity.employeeNo, + memberEntity.name)) + .from(memberEntity) + .where( + memberEntity.userRole.eq(role), + memberEntity.status.eq(com.kamco.cd.kamcoback.common.enums.StatusType.ACTIVE.getId())) + .orderBy(memberEntity.name.asc()) + .fetch(); } @Override public List findWorkerStatistics( - Long analUid, String workerType, String search, String sortType) { + Long analUid, String workerType, String search, String sortType) { // 작업자 유형에 따른 필드 선택 StringExpression workerIdField = - "REVIEWER".equals(workerType) - ? labelingAssignmentEntity.inspectorUid - : labelingAssignmentEntity.workerUid; + "REVIEWER".equals(workerType) + ? labelingAssignmentEntity.inspectorUid + : labelingAssignmentEntity.workerUid; BooleanExpression workerCondition = - "REVIEWER".equals(workerType) - ? labelingAssignmentEntity.inspectorUid.isNotNull() - : labelingAssignmentEntity.workerUid.isNotNull(); + "REVIEWER".equals(workerType) + ? labelingAssignmentEntity.inspectorUid.isNotNull() + : labelingAssignmentEntity.workerUid.isNotNull(); // 검색 조건 (이름 또는 사번으로 검색) BooleanExpression searchCondition = null; if (search != null && !search.isEmpty()) { searchCondition = - memberEntity.name.contains(search).or(memberEntity.employeeNo.contains(search)); + memberEntity.name.contains(search).or(memberEntity.employeeNo.contains(search)); } // 완료, 스킵, 남은 작업 계산 NumberExpression completedSum = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq("DONE")) - .then(1L) - .otherwise(0L) - .sum(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq("DONE")) + .then(1L) + .otherwise(0L) + .sum(); NumberExpression skippedSum = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq("SKIP")) - .then(1L) - .otherwise(0L) - .sum(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq("SKIP")) + .then(1L) + .otherwise(0L) + .sum(); NumberExpression remainingSum = - new CaseBuilder() - .when( - labelingAssignmentEntity - .workState - .notIn("DONE", "SKIP") - .and(labelingAssignmentEntity.workState.isNotNull())) - .then(1L) - .otherwise(0L) - .sum(); + new CaseBuilder() + .when( + labelingAssignmentEntity + .workState + .notIn("DONE", "SKIP") + .and(labelingAssignmentEntity.workState.isNotNull())) + .then(1L) + .otherwise(0L) + .sum(); // 기본 통계 조회 쿼리 BooleanExpression analUidCondition = - analUid != null ? labelingAssignmentEntity.analUid.eq(analUid) : null; + analUid != null ? labelingAssignmentEntity.analUid.eq(analUid) : null; var baseQuery = - queryFactory - .select( - workerIdField, - memberEntity.name, - workerIdField.count(), - completedSum, - skippedSum, - remainingSum, - labelingAssignmentEntity.stagnationYn.max()) - .from(labelingAssignmentEntity) - .leftJoin(memberEntity) - .on( - "REVIEWER".equals(workerType) - ? memberEntity.employeeNo.eq(labelingAssignmentEntity.inspectorUid) - : memberEntity.employeeNo.eq(labelingAssignmentEntity.workerUid)) - .where(analUidCondition, workerCondition, searchCondition) - .groupBy(workerIdField, memberEntity.name); + queryFactory + .select( + workerIdField, + memberEntity.name, + workerIdField.count(), + completedSum, + skippedSum, + remainingSum, + labelingAssignmentEntity.stagnationYn.max()) + .from(labelingAssignmentEntity) + .leftJoin(memberEntity) + .on( + "REVIEWER".equals(workerType) + ? memberEntity.employeeNo.eq(labelingAssignmentEntity.inspectorUid) + : memberEntity.employeeNo.eq(labelingAssignmentEntity.workerUid)) + .where(analUidCondition, workerCondition, searchCondition) + .groupBy(workerIdField, memberEntity.name); // 정렬 조건 적용 if (sortType != null) { @@ -322,22 +324,22 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 결과를 DTO로 변환 return baseQuery.fetch().stream() - .map( - tuple -> { - Character maxStagnationYn = tuple.get(labelingAssignmentEntity.stagnationYn.max()); - return WorkerStatistics.builder() - .workerId(tuple.get(workerIdField)) - .workerName(tuple.get(memberEntity.name)) - .workerType(workerType) - .totalAssigned(tuple.get(workerIdField.count())) - .completed(tuple.get(completedSum)) - .skipped(tuple.get(skippedSum)) - .remaining(tuple.get(remainingSum)) - .history(null) // 3일 이력은 Service에서 채움 - .isStagnated(maxStagnationYn != null && maxStagnationYn == 'Y') - .build(); - }) - .toList(); + .map( + tuple -> { + Character maxStagnationYn = tuple.get(labelingAssignmentEntity.stagnationYn.max()); + return WorkerStatistics.builder() + .workerId(tuple.get(workerIdField)) + .workerName(tuple.get(memberEntity.name)) + .workerType(workerType) + .totalAssigned(tuple.get(workerIdField.count())) + .completed(tuple.get(completedSum)) + .skipped(tuple.get(skippedSum)) + .remaining(tuple.get(remainingSum)) + .history(null) // 3일 이력은 Service에서 채움 + .isStagnated(maxStagnationYn != null && maxStagnationYn == 'Y') + .build(); + }) + .toList(); } @Override @@ -348,94 +350,94 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto UUID latestUuid = findLastLabelWorkState(); if (latestUuid != null) { effectiveAnalUid = - queryFactory - .select(mapSheetAnalInferenceEntity.id) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(latestUuid)) - .fetchOne(); + queryFactory + .select(mapSheetAnalInferenceEntity.id) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(latestUuid)) + .fetchOne(); } } BooleanExpression analUidCondition = - effectiveAnalUid != null ? labelingAssignmentEntity.analUid.eq(effectiveAnalUid) : null; + effectiveAnalUid != null ? labelingAssignmentEntity.analUid.eq(effectiveAnalUid) : null; // analUid로 분석 정보(compareYyyy, targetYyyy, stage) 조회 MapSheetAnalInferenceEntity analEntity = null; if (effectiveAnalUid != null) { analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.id.eq(effectiveAnalUid)) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.id.eq(effectiveAnalUid)) + .fetchOne(); } // 라벨링 대상 건수: tb_map_sheet_anal_data_inference_geom에서 pnu > 0 AND pass_yn = false(부적합)인 건수 Long labelingTargetCount = 0L; if (analEntity != null) { labelingTargetCount = - queryFactory - .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) - .from(mapSheetAnalDataInferenceGeomEntity) - .where( - mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(analEntity.getCompareYyyy()), - mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(analEntity.getTargetYyyy()), - mapSheetAnalDataInferenceGeomEntity.stage.eq(analEntity.getStage()), - mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L), - mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) - .fetchOne(); + queryFactory + .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) + .from(mapSheetAnalDataInferenceGeomEntity) + .where( + mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(analEntity.getCompareYyyy()), + mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(analEntity.getTargetYyyy()), + mapSheetAnalDataInferenceGeomEntity.stage.eq(analEntity.getStage()), + mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L), + mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) + .fetchOne(); } // 전체 배정 건수 (tb_labeling_assignment 기준) Long totalAssigned = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition) + .fetchOne(); // === 라벨링 통계 === // 라벨링 완료: LABEL_FIN, TEST_ING, DONE (검수 포함) Long labelingCompleted = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where( - analUidCondition, - labelingAssignmentEntity.workState.in("LABEL_FIN", "TEST_ING", "DONE")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where( + analUidCondition, + labelingAssignmentEntity.workState.in("LABEL_FIN", "TEST_ING", "DONE")) + .fetchOne(); // 스킵 건수 Long skipCount = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.workState.eq("SKIP")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.workState.eq("SKIP")) + .fetchOne(); // 투입된 라벨러 수 Long labelerCount = - queryFactory - .select(labelingAssignmentEntity.workerUid.countDistinct()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.workerUid.isNotNull()) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.workerUid.countDistinct()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.workerUid.isNotNull()) + .fetchOne(); // === 검수 통계 === // 검수 완료: DONE만 Long inspectionCompleted = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.workState.eq("DONE")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.workState.eq("DONE")) + .fetchOne(); // 투입된 검수자 수 Long inspectorCount = - queryFactory - .select(labelingAssignmentEntity.inspectorUid.countDistinct()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.inspectorUid.isNotNull()) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.inspectorUid.countDistinct()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.inspectorUid.isNotNull()) + .fetchOne(); // 라벨링 대상 건수 (pass_yn = false인 부적합 데이터 기준) long labelingTotal = labelingTargetCount != null ? labelingTargetCount : 0L; @@ -461,7 +463,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 진행률 계산 (라벨링 대상 건수 기준) double labelingRate = labelingTotal > 0 ? (double) labelCompleted / labelingTotal * 100 : 0.0; double inspectionRate = - inspectionTotal > 0 ? (double) inspectCompleted / inspectionTotal * 100 : 0.0; + inspectionTotal > 0 ? (double) inspectCompleted / inspectionTotal * 100 : 0.0; // 상태 판단 (각각의 closedYn이 "Y"이면 "종료", 아니면 진행중/완료) String labelingStatus; @@ -482,29 +484,29 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } return WorkProgressInfo.builder() - // 라벨링 (pass_yn = false인 부적합 데이터 기준) - .labelingProgressRate(labelingRate) - .labelingStatus(labelingStatus) - .labelingTotalCount(labelingTotal) - .labelingCompletedCount(labelCompleted) - .labelingSkipCount(skipped) - .labelingRemainingCount(labelingRemaining) - .labelerCount(labelerCount != null ? labelerCount : 0L) - // 검수 (라벨링 완료 건수 기준) - .inspectionProgressRate(inspectionRate) - .inspectionStatus(inspectionStatus) - .inspectionTotalCount(inspectionTotal) - .inspectionCompletedCount(inspectCompleted) - .inspectionSkipCount(skipped) - .inspectionRemainingCount(inspectionRemaining) - .inspectorCount(inspectorCount != null ? inspectorCount : 0L) - // 레거시 호환 필드 (Deprecated) - .progressRate(labelingRate) - .totalAssignedCount(labelingTotal) - .completedCount(labelCompleted) - .remainingLabelCount(labelingRemaining) - .remainingInspectCount(inspectionRemaining) - .build(); + // 라벨링 (pass_yn = false인 부적합 데이터 기준) + .labelingProgressRate(labelingRate) + .labelingStatus(labelingStatus) + .labelingTotalCount(labelingTotal) + .labelingCompletedCount(labelCompleted) + .labelingSkipCount(skipped) + .labelingRemainingCount(labelingRemaining) + .labelerCount(labelerCount != null ? labelerCount : 0L) + // 검수 (라벨링 완료 건수 기준) + .inspectionProgressRate(inspectionRate) + .inspectionStatus(inspectionStatus) + .inspectionTotalCount(inspectionTotal) + .inspectionCompletedCount(inspectCompleted) + .inspectionSkipCount(skipped) + .inspectionRemainingCount(inspectionRemaining) + .inspectorCount(inspectorCount != null ? inspectorCount : 0L) + // 레거시 호환 필드 (Deprecated) + .progressRate(labelingRate) + .totalAssignedCount(labelingTotal) + .completedCount(labelCompleted) + .remainingLabelCount(labelingRemaining) + .remainingInspectCount(inspectionRemaining) + .build(); } @Override @@ -517,11 +519,11 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // UUID로 analUid 조회 Long effectiveAnalUid = - queryFactory - .select(mapSheetAnalInferenceEntity.id) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(targetUuid)) - .fetchOne(); + queryFactory + .select(mapSheetAnalInferenceEntity.id) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(targetUuid)) + .fetchOne(); if (effectiveAnalUid == null) { return null; @@ -531,76 +533,76 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // analUid로 분석 정보(compareYyyy, targetYyyy, stage) 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.id.eq(effectiveAnalUid)) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.id.eq(effectiveAnalUid)) + .fetchOne(); // 라벨링 대상 건수: tb_map_sheet_anal_data_inference_geom에서 pnu > 0 AND pass_yn = false(부적합)인 건수 Long labelingTargetCount = 0L; if (analEntity != null) { labelingTargetCount = - queryFactory - .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) - .from(mapSheetAnalInferenceEntity) - .innerJoin(mapSheetAnalDataInferenceEntity) - .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) - .innerJoin(mapSheetAnalDataInferenceGeomEntity) - .on( - mapSheetAnalDataInferenceEntity.id.eq( - mapSheetAnalDataInferenceGeomEntity.dataUid)) - .where( - mapSheetAnalInferenceEntity.uuid.eq(targetUuid), - mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L), - mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) - .fetchOne(); + queryFactory + .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) + .from(mapSheetAnalInferenceEntity) + .innerJoin(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) + .innerJoin(mapSheetAnalDataInferenceGeomEntity) + .on( + mapSheetAnalDataInferenceEntity.id.eq( + mapSheetAnalDataInferenceGeomEntity.dataUid)) + .where( + mapSheetAnalInferenceEntity.uuid.eq(targetUuid), + mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L), + mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) + .fetchOne(); } // 전체 배정 건수 (tb_labeling_assignment 기준) Long totalAssigned = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition) + .fetchOne(); // === 라벨링 통계 === Long labelingCompleted = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where( - analUidCondition, labelingAssignmentEntity.workState.in("ASSIGNED", "SKIP", "DONE")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where( + analUidCondition, labelingAssignmentEntity.workState.in("ASSIGNED", "SKIP", "DONE")) + .fetchOne(); Long skipCount = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.workState.eq("SKIP")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.workState.eq("SKIP")) + .fetchOne(); Long labelerCount = - queryFactory - .select(labelingAssignmentEntity.workerUid.countDistinct()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.workerUid.isNotNull()) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.workerUid.countDistinct()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.workerUid.isNotNull()) + .fetchOne(); // === 검수 통계 === Long inspectionCompleted = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.inspectState.eq("COMPLETE")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.inspectState.eq("COMPLETE")) + .fetchOne(); Long inspectorCount = - queryFactory - .select(labelingAssignmentEntity.inspectorUid.countDistinct()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.inspectorUid.isNotNull()) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.inspectorUid.countDistinct()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.inspectorUid.isNotNull()) + .fetchOne(); // 계산 long labelingTotal = labelingTargetCount != null ? labelingTargetCount : 0L; @@ -621,7 +623,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto double labelingRate = labelingTotal > 0 ? (double) labelCompleted / labelingTotal * 100 : 0.0; double inspectionRate = - inspectionTotal > 0 ? (double) inspectCompleted / inspectionTotal * 100 : 0.0; + inspectionTotal > 0 ? (double) inspectCompleted / inspectionTotal * 100 : 0.0; // 상태 판단 String labelingStatus; @@ -640,55 +642,55 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } return WorkProgressInfo.builder() - .labelingProgressRate(labelingRate) - .labelingStatus(labelingStatus) - .labelingTotalCount(labelingTotal) - .labelingCompletedCount(labelCompleted) - .labelingSkipCount(skipped) - .labelingRemainingCount(labelingRemaining) - .labelerCount(labelerCount != null ? labelerCount : 0L) - .inspectionProgressRate(inspectionRate) - .inspectionStatus(inspectionStatus) - .inspectionTotalCount(inspectionTotal) - .inspectionCompletedCount(inspectCompleted) - .inspectionSkipCount(skipped) // TODO - .inspectionRemainingCount(inspectionRemaining) - .inspectorCount(inspectorCount != null ? inspectorCount : 0L) - .progressRate(labelingRate) - .totalAssignedCount(labelingTotal) - .completedCount(labelCompleted) - .remainingLabelCount(labelingRemaining) - .remainingInspectCount(inspectionRemaining) - .build(); + .labelingProgressRate(labelingRate) + .labelingStatus(labelingStatus) + .labelingTotalCount(labelingTotal) + .labelingCompletedCount(labelCompleted) + .labelingSkipCount(skipped) + .labelingRemainingCount(labelingRemaining) + .labelerCount(labelerCount != null ? labelerCount : 0L) + .inspectionProgressRate(inspectionRate) + .inspectionStatus(inspectionStatus) + .inspectionTotalCount(inspectionTotal) + .inspectionCompletedCount(inspectCompleted) + .inspectionSkipCount(skipped) // TODO + .inspectionRemainingCount(inspectionRemaining) + .inspectorCount(inspectorCount != null ? inspectorCount : 0L) + .progressRate(labelingRate) + .totalAssignedCount(labelingTotal) + .completedCount(labelCompleted) + .remainingLabelCount(labelingRemaining) + .remainingInspectCount(inspectionRemaining) + .build(); } @Override 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 endOfDay = date.atTime(LocalTime.MAX).atZone(ZoneId.systemDefault()); BooleanExpression workerCondition = - "REVIEWER".equals(workerType) - ? labelingAssignmentEntity.inspectorUid.eq(workerId) - : labelingAssignmentEntity.workerUid.eq(workerId); + "REVIEWER".equals(workerType) + ? labelingAssignmentEntity.inspectorUid.eq(workerId) + : labelingAssignmentEntity.workerUid.eq(workerId); BooleanExpression analUidCondition = - analUid != null ? labelingAssignmentEntity.analUid.eq(analUid) : null; + analUid != null ? labelingAssignmentEntity.analUid.eq(analUid) : null; Long count = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where( - analUidCondition, - workerCondition, - labelingAssignmentEntity.workState.in( - LabelState.DONE.getId(), LabelState.SKIP.getId()), - labelingAssignmentEntity.modifiedDate.between(startOfDay, endOfDay)) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where( + analUidCondition, + workerCondition, + labelingAssignmentEntity.workState.in( + LabelState.DONE.getId(), LabelState.SKIP.getId()), + labelingAssignmentEntity.modifiedDate.between(startOfDay, endOfDay)) + .fetchOne(); return count != null ? count : 0L; } @@ -696,10 +698,10 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @Override public void assignInspectorBulk(List assignmentUids, String inspectorUid) { queryFactory - .update(labelingAssignmentEntity) - .set(labelingAssignmentEntity.inspectorUid, inspectorUid) - .where(labelingAssignmentEntity.assignmentUid.in(assignmentUids)) - .execute(); + .update(labelingAssignmentEntity) + .set(labelingAssignmentEntity.inspectorUid, inspectorUid) + .where(labelingAssignmentEntity.assignmentUid.in(assignmentUids)) + .execute(); em.clear(); } @@ -708,78 +710,78 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto public InferenceDetail findInferenceDetail(String uuid) { // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); } return queryFactory - .select( - Projections.constructor( - InferenceDetail.class, - mapSheetAnalInferenceEntity.analTitle, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalDataInferenceGeomEntity.geoUid.count())) - .from(mapSheetAnalInferenceEntity) - .leftJoin(mapSheetAnalDataInferenceGeomEntity) - .on( - mapSheetAnalInferenceEntity.compareYyyy.eq( - mapSheetAnalDataInferenceGeomEntity.compareYyyy), - mapSheetAnalInferenceEntity.targetYyyy.eq( - mapSheetAnalDataInferenceGeomEntity.targetYyyy), - mapSheetAnalInferenceEntity.stage.eq(mapSheetAnalDataInferenceGeomEntity.stage), - mapSheetAnalDataInferenceGeomEntity.pnu.gt(0), - mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) - .where(mapSheetAnalInferenceEntity.id.eq(analEntity.getId())) - .groupBy( - mapSheetAnalInferenceEntity.analTitle, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.detectingCnt) - .fetchOne(); + .select( + Projections.constructor( + InferenceDetail.class, + mapSheetAnalInferenceEntity.analTitle, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalDataInferenceGeomEntity.geoUid.count())) + .from(mapSheetAnalInferenceEntity) + .leftJoin(mapSheetAnalDataInferenceGeomEntity) + .on( + mapSheetAnalInferenceEntity.compareYyyy.eq( + mapSheetAnalDataInferenceGeomEntity.compareYyyy), + mapSheetAnalInferenceEntity.targetYyyy.eq( + mapSheetAnalDataInferenceGeomEntity.targetYyyy), + mapSheetAnalInferenceEntity.stage.eq(mapSheetAnalDataInferenceGeomEntity.stage), + mapSheetAnalDataInferenceGeomEntity.pnu.gt(0), + mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) + .where(mapSheetAnalInferenceEntity.id.eq(analEntity.getId())) + .groupBy( + mapSheetAnalInferenceEntity.analTitle, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.detectingCnt) + .fetchOne(); } @Override public List fetchNextMoveIds(Long lastId, Long batchSize, String uuid, String userId) { MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); } return queryFactory - .select(labelingAssignmentEntity.inferenceGeomUid) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.workerUid.eq(userId), - labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()), - labelingAssignmentEntity.analUid.eq(analEntity.getId()), - lastId == null ? null : labelingAssignmentEntity.inferenceGeomUid.gt(lastId)) - .orderBy( - labelingAssignmentEntity.assignGroupId.asc(), - labelingAssignmentEntity.inferenceGeomUid.asc()) - .limit(batchSize) - .fetch(); + .select(labelingAssignmentEntity.inferenceGeomUid) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.workerUid.eq(userId), + labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()), + labelingAssignmentEntity.analUid.eq(analEntity.getId()), + lastId == null ? null : labelingAssignmentEntity.inferenceGeomUid.gt(lastId)) + .orderBy( + labelingAssignmentEntity.assignGroupId.asc(), + labelingAssignmentEntity.inferenceGeomUid.asc()) + .limit(batchSize) + .fetch(); } @Transactional @Override public void assignOwnerMove(List sub, String userId) { queryFactory - .update(labelingAssignmentEntity) - .set(labelingAssignmentEntity.workerUid, userId) - .where(labelingAssignmentEntity.inferenceGeomUid.in(sub)) - .execute(); + .update(labelingAssignmentEntity) + .set(labelingAssignmentEntity.workerUid, userId) + .where(labelingAssignmentEntity.inferenceGeomUid.in(sub)) + .execute(); em.clear(); } @@ -788,10 +790,10 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto public LabelerDetail findLabelerDetail(String userId, String uuid) { // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for uuid: " + uuid); @@ -803,137 +805,141 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto NumberExpression totalCnt = labelingAssignmentEntity.assignmentUid.count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression percent = - new CaseBuilder() - .when(completeCnt.eq(0L)) - .then(0.0) - .otherwise( - Expressions.numberTemplate( - Double.class, - "ROUND(({0} * 1.0 / NULLIF({1}, 0)) * 100, 2)", - completeCnt, - totalCnt)); + new CaseBuilder() + .when(completeCnt.eq(0L)) + .then(0.0) + .otherwise( + Expressions.numberTemplate( + Double.class, + "ROUND(({0} * 1.0 / NULLIF({1}, 0)) * 100, 2)", + completeCnt, + totalCnt)); Expression remainCnt = - Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); + Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); return queryFactory - .select( - Projections.constructor( - LabelerDetail.class, - worker.userRole, - worker.name, - worker.employeeNo, - totalCnt, - completeCnt, - skipCnt, - percent, - Expressions.constant(0), // 순위는 Service 레이어에서 계산 - labelingAssignmentEntity.workStatDttm.min(), - inspector.name.min(), - remainCnt)) - .from(worker) - .innerJoin(labelingAssignmentEntity) - .on( - worker.employeeNo.eq(labelingAssignmentEntity.workerUid), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .leftJoin(inspector) - .on(labelingAssignmentEntity.inspectorUid.eq(inspector.employeeNo)) - .where(worker.employeeNo.eq(userId)) - .groupBy(worker.userRole, worker.name, worker.employeeNo) - .fetchOne(); + .select( + Projections.constructor( + LabelerDetail.class, + worker.userRole, + worker.name, + worker.employeeNo, + totalCnt, + completeCnt, + skipCnt, + percent, + Expressions.constant(0), // 순위는 Service 레이어에서 계산 + labelingAssignmentEntity.workStatDttm.min(), + inspector.name.min(), + remainCnt)) + .from(worker) + .innerJoin(labelingAssignmentEntity) + .on( + worker.employeeNo.eq(labelingAssignmentEntity.workerUid), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .leftJoin(inspector) + .on(labelingAssignmentEntity.inspectorUid.eq(inspector.employeeNo)) + .where(worker.employeeNo.eq(userId)) + .groupBy(worker.userRole, worker.name, worker.employeeNo) + .fetchOne(); } - /** 특정 회차의 모든 라벨러 통계 조회 (순위 계산용) */ + /** + * 특정 회차의 모든 라벨러 통계 조회 (순위 계산용) + */ public List findAllLabelersForRanking(Long analUid) { QMemberEntity worker = QMemberEntity.memberEntity; NumberExpression totalCnt = labelingAssignmentEntity.assignmentUid.count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) + .then(1L) + .otherwise((Long) null) + .count(); Expression remainCnt = - Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); + Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); return queryFactory - .select( - Projections.constructor( - LabelerDetail.class, - worker.userRole, - worker.name, - worker.employeeNo, - totalCnt, - completeCnt, - skipCnt, - Expressions.constant(0.0), // percent - Expressions.constant(0), // ranking - labelingAssignmentEntity.workStatDttm.min(), - Expressions.nullExpression(String.class), // ownerName - remainCnt)) - .from(worker) - .innerJoin(labelingAssignmentEntity) - .on( - worker.employeeNo.eq(labelingAssignmentEntity.workerUid), - labelingAssignmentEntity.analUid.eq(analUid)) - .groupBy(worker.userRole, worker.name, worker.employeeNo) - .orderBy(completeCnt.desc()) // 완료 건수 내림차순 - .fetch(); + .select( + Projections.constructor( + LabelerDetail.class, + worker.userRole, + worker.name, + worker.employeeNo, + totalCnt, + completeCnt, + skipCnt, + Expressions.constant(0.0), // percent + Expressions.constant(0), // ranking + labelingAssignmentEntity.workStatDttm.min(), + Expressions.nullExpression(String.class), // ownerName + remainCnt)) + .from(worker) + .innerJoin(labelingAssignmentEntity) + .on( + worker.employeeNo.eq(labelingAssignmentEntity.workerUid), + labelingAssignmentEntity.analUid.eq(analUid)) + .groupBy(worker.userRole, worker.name, worker.employeeNo) + .orderBy(completeCnt.desc()) // 완료 건수 내림차순 + .fetch(); } - /** UUID로 analUid 조회 */ + /** + * UUID로 analUid 조회 + */ @Override public Long findAnalUidByUuid(String uuid) { return queryFactory - .select(mapSheetAnalInferenceEntity.id) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + .select(mapSheetAnalInferenceEntity.id) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); } @Override public Long findMapSheetAnalInferenceUid(UUID uuid) { return queryFactory - .select(mapSheetAnalInferenceEntity.id) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) - .fetchOne(); + .select(mapSheetAnalInferenceEntity.id) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) + .fetchOne(); } @Override public void insertInspector(Long analUid, String inspector) { queryFactory - .insert(labelingInspectorEntity) - .columns( - labelingInspectorEntity.operatorUid, - labelingInspectorEntity.analUid, - labelingInspectorEntity.inspectorUid) - .values(UUID.randomUUID(), analUid, inspector) - .execute(); + .insert(labelingInspectorEntity) + .columns( + labelingInspectorEntity.operatorUid, + labelingInspectorEntity.analUid, + labelingInspectorEntity.inspectorUid) + .values(UUID.randomUUID(), analUid, inspector) + .execute(); em.flush(); em.clear(); @@ -946,19 +952,19 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } var result = - queryFactory - .select( - mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.uuid, - mapSheetAnalInferenceEntity.labelingClosedYn, - mapSheetAnalInferenceEntity.inspectionClosedYn) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.id.eq(analUid)) - .fetchOne(); + queryFactory + .select( + mapSheetAnalInferenceEntity.compareYyyy, + mapSheetAnalInferenceEntity.targetYyyy, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.createdDttm, + mapSheetAnalInferenceEntity.uuid, + mapSheetAnalInferenceEntity.labelingClosedYn, + mapSheetAnalInferenceEntity.inspectionClosedYn) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.id.eq(analUid)) + .fetchOne(); if (result == null) { return null; @@ -975,20 +981,20 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 변화탐지년도 생성 String detectionYear = - (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; + (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; // 회차를 stage 컬럼에서 가져옴 String round = stage != null ? String.valueOf(stage) : null; return ProjectInfo.builder() - .detectionYear(detectionYear) - .stage(round) - .gukyuinApplyDttm(gukyuinApplyDttm) - .startDttm(createdDttm) - .uuid(uuid != null ? uuid.toString() : null) - .labelingClosedYn(labelingClosedYn) - .inspectionClosedYn(inspectionClosedYn) - .build(); + .detectionYear(detectionYear) + .stage(round) + .gukyuinApplyDttm(gukyuinApplyDttm) + .startDttm(createdDttm) + .uuid(uuid != null ? uuid.toString() : null) + .labelingClosedYn(labelingClosedYn) + .inspectionClosedYn(inspectionClosedYn) + .build(); } @Override @@ -1002,19 +1008,19 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // UUID로 프로젝트 정보 조회 var result = - queryFactory - .select( - mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.uuid, - mapSheetAnalInferenceEntity.labelingClosedYn, - mapSheetAnalInferenceEntity.inspectionClosedYn) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) - .fetchOne(); + queryFactory + .select( + mapSheetAnalInferenceEntity.compareYyyy, + mapSheetAnalInferenceEntity.targetYyyy, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.createdDttm, + mapSheetAnalInferenceEntity.uuid, + mapSheetAnalInferenceEntity.labelingClosedYn, + mapSheetAnalInferenceEntity.inspectionClosedYn) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) + .fetchOne(); if (result == null) { return null; @@ -1030,20 +1036,20 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 변화탐지년도 생성 String detectionYear = - (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; + (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; // 회차를 stage 컬럼에서 가져옴 String round = stage != null ? String.valueOf(stage) : null; return ProjectInfo.builder() - .detectionYear(detectionYear) - .stage(round) - .gukyuinApplyDttm(gukyuinApplyDttm) - .startDttm(createdDttm) - .uuid(uuid.toString()) - .labelingClosedYn(labelingClosedYn) - .inspectionClosedYn(inspectionClosedYn) - .build(); + .detectionYear(detectionYear) + .stage(round) + .gukyuinApplyDttm(gukyuinApplyDttm) + .startDttm(createdDttm) + .uuid(uuid.toString()) + .labelingClosedYn(labelingClosedYn) + .inspectionClosedYn(inspectionClosedYn) + .build(); } @Override @@ -1055,19 +1061,19 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto UUID targetUuid = UUID.fromString(uuid); var result = - queryFactory - .select( - mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.uuid, - mapSheetAnalInferenceEntity.labelingClosedYn, - mapSheetAnalInferenceEntity.inspectionClosedYn) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(targetUuid)) - .fetchOne(); + queryFactory + .select( + mapSheetAnalInferenceEntity.compareYyyy, + mapSheetAnalInferenceEntity.targetYyyy, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.createdDttm, + mapSheetAnalInferenceEntity.uuid, + mapSheetAnalInferenceEntity.labelingClosedYn, + mapSheetAnalInferenceEntity.inspectionClosedYn) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(targetUuid)) + .fetchOne(); if (result == null) { return null; @@ -1082,18 +1088,18 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto String inspectionClosedYn = result.get(mapSheetAnalInferenceEntity.inspectionClosedYn); String detectionYear = - (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; + (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; String round = stage != null ? String.valueOf(stage) : null; return ProjectInfo.builder() - .detectionYear(detectionYear) - .stage(round) - .gukyuinApplyDttm(gukyuinApplyDttm) - .startDttm(createdDttm) - .uuid(uuid) - .labelingClosedYn(labelingClosedYn) - .inspectionClosedYn(inspectionClosedYn) - .build(); + .detectionYear(detectionYear) + .stage(round) + .gukyuinApplyDttm(gukyuinApplyDttm) + .startDttm(createdDttm) + .uuid(uuid) + .labelingClosedYn(labelingClosedYn) + .inspectionClosedYn(inspectionClosedYn) + .build(); } @Override @@ -1102,30 +1108,30 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 1. 작업이 할당된 프로젝트 중 최신 UUID 조회 UUID uuid = - queryFactory - .select(mapSheetAnalInferenceEntity.uuid) - .from(mapSheetAnalInferenceEntity) - .innerJoin(labelingAssignmentEntity) - .on(mapSheetAnalInferenceEntity.id.eq(labelingAssignmentEntity.analUid)) - .where(whereBuilder) - .orderBy( - mapSheetAnalInferenceEntity.compareYyyy.desc(), - mapSheetAnalInferenceEntity.targetYyyy.desc(), - mapSheetAnalInferenceEntity.stage.desc()) - .fetchFirst(); + queryFactory + .select(mapSheetAnalInferenceEntity.uuid) + .from(mapSheetAnalInferenceEntity) + .innerJoin(labelingAssignmentEntity) + .on(mapSheetAnalInferenceEntity.id.eq(labelingAssignmentEntity.analUid)) + .where(whereBuilder) + .orderBy( + mapSheetAnalInferenceEntity.compareYyyy.desc(), + mapSheetAnalInferenceEntity.targetYyyy.desc(), + mapSheetAnalInferenceEntity.stage.desc()) + .fetchFirst(); // 2. 작업이 할당된 프로젝트가 없으면 전체 프로젝트 중 최신 UUID 조회 if (uuid == null) { uuid = - queryFactory - .select(mapSheetAnalInferenceEntity.uuid) - .from(mapSheetAnalInferenceEntity) - .where(whereBuilder) - .orderBy( - mapSheetAnalInferenceEntity.compareYyyy.desc(), - mapSheetAnalInferenceEntity.targetYyyy.desc(), - mapSheetAnalInferenceEntity.stage.desc()) - .fetchFirst(); + queryFactory + .select(mapSheetAnalInferenceEntity.uuid) + .from(mapSheetAnalInferenceEntity) + .where(whereBuilder) + .orderBy( + mapSheetAnalInferenceEntity.compareYyyy.desc(), + mapSheetAnalInferenceEntity.targetYyyy.desc(), + mapSheetAnalInferenceEntity.stage.desc()) + .fetchFirst(); } return uuid; @@ -1133,11 +1139,11 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @Override public Page findLabelerDailyStat( - LabelAllocateDto.searchReq searchReq, String uuid, String userId) { + LabelAllocateDto.searchReq searchReq, String uuid, String userId) { // 날짜 포맷 Expression workDate = - Expressions.stringTemplate( - "TO_CHAR({0}, 'YYYY-MM-DD')", labelingAssignmentEntity.workStatDttm); + Expressions.stringTemplate( + "TO_CHAR({0}, 'YYYY-MM-DD')", labelingAssignmentEntity.workStatDttm); // 날짜별 전체 건수 Expression dailyTotalCnt = Expressions.numberTemplate(Long.class, "COUNT(*)"); @@ -1147,28 +1153,28 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 상태별 카운트 (Postgres FILTER 사용) Expression assignedCnt = - Expressions.numberTemplate( - Long.class, - "COUNT(*) FILTER (WHERE {0} = 'ASSIGNED')", - labelingAssignmentEntity.workState); + Expressions.numberTemplate( + Long.class, + "COUNT(*) FILTER (WHERE {0} = 'ASSIGNED')", + labelingAssignmentEntity.workState); Expression skipCnt = - Expressions.numberTemplate( - Long.class, "COUNT(*) FILTER (WHERE {0} = 'SKIP')", labelingAssignmentEntity.workState); + Expressions.numberTemplate( + Long.class, "COUNT(*) FILTER (WHERE {0} = 'SKIP')", labelingAssignmentEntity.workState); Expression completeCnt = - Expressions.numberTemplate( - Long.class, "COUNT(*) FILTER (WHERE {0} = 'DONE')", labelingAssignmentEntity.workState); + Expressions.numberTemplate( + Long.class, "COUNT(*) FILTER (WHERE {0} = 'DONE')", labelingAssignmentEntity.workState); Expression remainCnt = - Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); + Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); @@ -1176,49 +1182,49 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto Pageable pageable = searchReq.toPageable(); List foundContent = - queryFactory - .select( - Projections.constructor( - LabelingStatDto.class, - workDate, - dailyTotalCnt, - totalCnt, // ⭐ 전체 일자 배정 건수 - assignedCnt, - skipCnt, - completeCnt, - remainCnt)) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.workerUid.eq(userId), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .groupBy(workDate) - .orderBy(labelingAssignmentEntity.workStatDttm.min().asc()) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .fetch(); + queryFactory + .select( + Projections.constructor( + LabelingStatDto.class, + workDate, + dailyTotalCnt, + totalCnt, // ⭐ 전체 일자 배정 건수 + assignedCnt, + skipCnt, + completeCnt, + remainCnt)) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.workerUid.eq(userId), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .groupBy(workDate) + .orderBy(labelingAssignmentEntity.workStatDttm.min().asc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); Long countQuery = - queryFactory - .select(workDate) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.workerUid.eq(userId), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .distinct() - .fetch() - .stream() - .count(); + queryFactory + .select(workDate) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.workerUid.eq(userId), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .distinct() + .fetch() + .stream() + .count(); return new PageImpl<>(foundContent, pageable, countQuery); } @Override public Page findInspectorDailyStat( - LabelAllocateDto.searchReq searchReq, String uuid, String userId) { + LabelAllocateDto.searchReq searchReq, String uuid, String userId) { // 날짜 포맷 Expression workDate = - Expressions.stringTemplate( - "TO_CHAR({0}, 'YYYY-MM-DD')", labelingAssignmentEntity.inspectStatDttm); + Expressions.stringTemplate( + "TO_CHAR({0}, 'YYYY-MM-DD')", labelingAssignmentEntity.inspectStatDttm); // 날짜별 전체 건수 Expression dailyTotalCnt = Expressions.numberTemplate(Long.class, "COUNT(*)"); @@ -1228,32 +1234,32 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 상태별 카운트 (Postgres FILTER 사용) Expression assignedCnt = - Expressions.numberTemplate( - Long.class, - "COUNT(*) FILTER (WHERE {0} = 'UNCONFIRM')", - labelingAssignmentEntity.inspectState); + Expressions.numberTemplate( + Long.class, + "COUNT(*) FILTER (WHERE {0} = 'UNCONFIRM')", + labelingAssignmentEntity.inspectState); Expression skipCnt = - Expressions.numberTemplate( - Long.class, - "COUNT(*) FILTER (WHERE {0} = 'EXCEPT')", - labelingAssignmentEntity.inspectState); + Expressions.numberTemplate( + Long.class, + "COUNT(*) FILTER (WHERE {0} = 'EXCEPT')", + labelingAssignmentEntity.inspectState); Expression completeCnt = - Expressions.numberTemplate( - Long.class, - "COUNT(*) FILTER (WHERE {0} = 'COMPLETE')", - labelingAssignmentEntity.inspectState); + Expressions.numberTemplate( + Long.class, + "COUNT(*) FILTER (WHERE {0} = 'COMPLETE')", + labelingAssignmentEntity.inspectState); Expression remainCnt = - Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); + Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); @@ -1261,38 +1267,38 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto Pageable pageable = searchReq.toPageable(); List foundContent = - queryFactory - .select( - Projections.constructor( - LabelingStatDto.class, - workDate, - dailyTotalCnt, - totalCnt, // ⭐ 전체 일자 배정 건수 - assignedCnt, - skipCnt, - completeCnt, - remainCnt)) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.inspectorUid.eq(userId), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .groupBy(workDate) - .orderBy(labelingAssignmentEntity.inspectStatDttm.min().asc()) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .fetch(); + queryFactory + .select( + Projections.constructor( + LabelingStatDto.class, + workDate, + dailyTotalCnt, + totalCnt, // ⭐ 전체 일자 배정 건수 + assignedCnt, + skipCnt, + completeCnt, + remainCnt)) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.inspectorUid.eq(userId), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .groupBy(workDate) + .orderBy(labelingAssignmentEntity.inspectStatDttm.min().asc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); Long countQuery = - queryFactory - .select(workDate) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.inspectorUid.eq(userId), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .distinct() - .fetch() - .stream() - .count(); + queryFactory + .select(workDate) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.inspectorUid.eq(userId), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .distinct() + .fetch() + .stream() + .count(); return new PageImpl<>(foundContent, pageable, countQuery); } @@ -1300,43 +1306,43 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @Override public LabelerDetail findInspectorDetail(String userId, String uuid) { NumberExpression assignedCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.UNCONFIRM.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.UNCONFIRM.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression percent = - new CaseBuilder() - .when(completeCnt.eq(0L)) - .then(0.0) - .otherwise( - Expressions.numberTemplate( - Double.class, - "round({0} / {1}, 2)", - completeCnt, - labelingAssignmentEntity.count())); + new CaseBuilder() + .when(completeCnt.eq(0L)) + .then(0.0) + .otherwise( + Expressions.numberTemplate( + Double.class, + "round({0} / {1}, 2)", + completeCnt, + labelingAssignmentEntity.count())); // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); @@ -1347,88 +1353,90 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // remainCnt Expression remainCnt = - Expressions.numberTemplate( - Long.class, "({0} - {1} - {2})", assignedCnt, skipCnt, completeCnt); + Expressions.numberTemplate( + Long.class, "({0} - {1} - {2})", assignedCnt, skipCnt, completeCnt); return queryFactory - .select( - Projections.constructor( - LabelerDetail.class, - inspector.userRole, - inspector.name, - inspector.employeeNo, - assignedCnt, // count (총 배정 건수) - completeCnt, // completeCnt (완료 건수) - skipCnt, // skipCnt (스킵 건수) - percent, - Expressions.constant(0), // 순위는 Service 레이어에서 계산 - labelingAssignmentEntity.inspectStatDttm.min(), - worker.name.min(), - remainCnt)) - .from(inspector) - .innerJoin(labelingAssignmentEntity) - .on( - inspector.employeeNo.eq(labelingAssignmentEntity.inspectorUid), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .leftJoin(worker) - .on(labelingAssignmentEntity.workerUid.eq(worker.employeeNo)) - .where(inspector.employeeNo.eq(userId)) - .groupBy(inspector.userRole, inspector.name, inspector.employeeNo) - .fetchOne(); + .select( + Projections.constructor( + LabelerDetail.class, + inspector.userRole, + inspector.name, + inspector.employeeNo, + assignedCnt, // count (총 배정 건수) + completeCnt, // completeCnt (완료 건수) + skipCnt, // skipCnt (스킵 건수) + percent, + Expressions.constant(0), // 순위는 Service 레이어에서 계산 + labelingAssignmentEntity.inspectStatDttm.min(), + worker.name.min(), + remainCnt)) + .from(inspector) + .innerJoin(labelingAssignmentEntity) + .on( + inspector.employeeNo.eq(labelingAssignmentEntity.inspectorUid), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .leftJoin(worker) + .on(labelingAssignmentEntity.workerUid.eq(worker.employeeNo)) + .where(inspector.employeeNo.eq(userId)) + .groupBy(inspector.userRole, inspector.name, inspector.employeeNo) + .fetchOne(); } - /** 순위 계산용 - 특정 회차의 모든 검수자 통계 조회 */ + /** + * 순위 계산용 - 특정 회차의 모든 검수자 통계 조회 + */ public List findAllInspectorsForRanking(Long analUid) { QMemberEntity inspector = QMemberEntity.memberEntity; NumberExpression assignedCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.UNCONFIRM.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.UNCONFIRM.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); Expression remainCnt = - Expressions.numberTemplate( - Long.class, "({0} - {1} - {2})", assignedCnt, skipCnt, completeCnt); + Expressions.numberTemplate( + Long.class, "({0} - {1} - {2})", assignedCnt, skipCnt, completeCnt); return queryFactory - .select( - Projections.constructor( - LabelerDetail.class, - inspector.userRole, - inspector.name, - inspector.employeeNo, - assignedCnt, // count (총 배정 건수) - completeCnt, // completeCnt (완료 건수) - skipCnt, // skipCnt (스킵 건수) - Expressions.constant(0.0), // percent - Expressions.constant(0), // ranking - labelingAssignmentEntity.inspectStatDttm.min(), - Expressions.nullExpression(String.class), // ownerName - remainCnt)) - .from(inspector) - .innerJoin(labelingAssignmentEntity) - .on( - inspector.employeeNo.eq(labelingAssignmentEntity.inspectorUid), - labelingAssignmentEntity.analUid.eq(analUid)) - .groupBy(inspector.userRole, inspector.name, inspector.employeeNo) - .orderBy(completeCnt.desc()) // 완료 건수 내림차순 - .fetch(); + .select( + Projections.constructor( + LabelerDetail.class, + inspector.userRole, + inspector.name, + inspector.employeeNo, + assignedCnt, // count (총 배정 건수) + completeCnt, // completeCnt (완료 건수) + skipCnt, // skipCnt (스킵 건수) + Expressions.constant(0.0), // percent + Expressions.constant(0), // ranking + labelingAssignmentEntity.inspectStatDttm.min(), + Expressions.nullExpression(String.class), // ownerName + remainCnt)) + .from(inspector) + .innerJoin(labelingAssignmentEntity) + .on( + inspector.employeeNo.eq(labelingAssignmentEntity.inspectorUid), + labelingAssignmentEntity.analUid.eq(analUid)) + .groupBy(inspector.userRole, inspector.name, inspector.employeeNo) + .orderBy(completeCnt.desc()) // 완료 건수 내림차순 + .fetch(); } @Override @@ -1436,79 +1444,79 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto NumberExpression totalCnt = labelingAssignmentEntity.count(); NumberExpression completeCnt = - new CaseBuilder() - .when( - labelingAssignmentEntity - .workState - .eq(LabelState.DONE.getId()) - .or(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId()))) - .then(1L) - .otherwise(0L) - .sum(); + new CaseBuilder() + .when( + labelingAssignmentEntity + .workState + .eq(LabelState.DONE.getId()) + .or(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId()))) + .then(1L) + .otherwise(0L) + .sum(); NumberExpression percent = - new CaseBuilder() - .when(completeCnt.eq(0L)) - .then(0.0) - .otherwise( - Expressions.numberTemplate( - Double.class, - "round(({0} * 100.0) / nullif({1}, 0), 2)", - completeCnt, - totalCnt)); + new CaseBuilder() + .when(completeCnt.eq(0L)) + .then(0.0) + .otherwise( + Expressions.numberTemplate( + Double.class, + "round(({0} * 100.0) / nullif({1}, 0), 2)", + completeCnt, + totalCnt)); // remainCnt Expression remainCnt = totalCnt.subtract(completeCnt); // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); } Long userChargeCnt = - queryFactory - .select(labelingAssignmentEntity.inferenceGeomUid.count()) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.analUid.eq(analEntity.getId()), - labelingAssignmentEntity.workerUid.eq(userId), - labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId())) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.inferenceGeomUid.count()) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.analUid.eq(analEntity.getId()), + labelingAssignmentEntity.workerUid.eq(userId), + labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId())) + .fetchOne(); List list = - queryFactory - .select( - Projections.constructor( - MoveUserList.class, - memberEntity.userRole, - memberEntity.employeeNo, - memberEntity.name, - remainCnt, - percent)) - .from(labelingAssignmentEntity) - .innerJoin(memberEntity) - .on( - labelingAssignmentEntity.workerUid.eq(memberEntity.employeeNo), - memberEntity.status.eq(StatusType.ACTIVE.getId())) - .where( - labelingAssignmentEntity.analUid.eq(analEntity.getId()), - labelingAssignmentEntity.workerUid.ne(userId)) - .groupBy(memberEntity.userRole, memberEntity.employeeNo, memberEntity.name) - .having( - completeCnt - .multiply(2) - .goe(totalCnt)) // 진행률 평균 이상인 것들만 조회 => percent 를 바로 쓰면 having절에 무리가 갈 수 있다고 함 - .orderBy( - completeCnt - .desc()) // TODO: 현재는 잔여건수가 제일 적은(=완료건수가 높은) 순서로 desc, 추후 도엽번호? PNU? 로 정렬하여 - // 보여주기? - .fetch(); + queryFactory + .select( + Projections.constructor( + MoveUserList.class, + memberEntity.userRole, + memberEntity.employeeNo, + memberEntity.name, + remainCnt, + percent)) + .from(labelingAssignmentEntity) + .innerJoin(memberEntity) + .on( + labelingAssignmentEntity.workerUid.eq(memberEntity.employeeNo), + memberEntity.status.eq(StatusType.ACTIVE.getId())) + .where( + labelingAssignmentEntity.analUid.eq(analEntity.getId()), + labelingAssignmentEntity.workerUid.ne(userId)) + .groupBy(memberEntity.userRole, memberEntity.employeeNo, memberEntity.name) + .having( + completeCnt + .multiply(2) + .goe(totalCnt)) // 진행률 평균 이상인 것들만 조회 => percent 를 바로 쓰면 having절에 무리가 갈 수 있다고 함 + .orderBy( + completeCnt + .desc()) // TODO: 현재는 잔여건수가 제일 적은(=완료건수가 높은) 순서로 desc, 추후 도엽번호? PNU? 로 정렬하여 + // 보여주기? + .fetch(); return new MoveInfo(userChargeCnt, list); } @@ -1516,39 +1524,39 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @Override public void insertLabelerUser(Long analUid, String userId, int demand) { queryFactory - .insert(labelingLabelerEntity) - .columns( - labelingLabelerEntity.lbUsrUid, - labelingLabelerEntity.analUid, - labelingLabelerEntity.workerUid, - labelingLabelerEntity.allocateCnt) - .values(UUID.randomUUID(), analUid, userId, demand) - .execute(); + .insert(labelingLabelerEntity) + .columns( + labelingLabelerEntity.lbUsrUid, + labelingLabelerEntity.analUid, + labelingLabelerEntity.workerUid, + labelingLabelerEntity.allocateCnt) + .values(UUID.randomUUID(), analUid, userId, demand) + .execute(); } @Override public void assignOwnerReAllocate( - String uuid, String userId, String paramUserId, Long assignCount) { + String uuid, String userId, String paramUserId, Long assignCount) { // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); } queryFactory - .update(labelingLabelerEntity) - .set(labelingLabelerEntity.reAllocateYn, true) - .set(labelingLabelerEntity.reAllocateWorkerUid, userId) - .set(labelingLabelerEntity.reAllocateCnt, assignCount) - .where( - labelingLabelerEntity.analUid.eq(analEntity.getId()), - labelingLabelerEntity.workerUid.eq(paramUserId)) - .execute(); + .update(labelingLabelerEntity) + .set(labelingLabelerEntity.reAllocateYn, true) + .set(labelingLabelerEntity.reAllocateWorkerUid, userId) + .set(labelingLabelerEntity.reAllocateCnt, assignCount) + .where( + labelingLabelerEntity.analUid.eq(analEntity.getId()), + labelingLabelerEntity.workerUid.eq(paramUserId)) + .execute(); } @Override @@ -1561,85 +1569,85 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto updateQuery.set(mapSheetAnalInferenceEntity.inspectionClosedYn, closedYn); } else if ("BOTH".equals(closedType)) { updateQuery - .set(mapSheetAnalInferenceEntity.labelingClosedYn, closedYn) - .set(mapSheetAnalInferenceEntity.inspectionClosedYn, closedYn); + .set(mapSheetAnalInferenceEntity.labelingClosedYn, closedYn) + .set(mapSheetAnalInferenceEntity.inspectionClosedYn, closedYn); } updateQuery - .set(mapSheetAnalInferenceEntity.updatedDttm, ZonedDateTime.now()) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .execute(); + .set(mapSheetAnalInferenceEntity.updatedDttm, ZonedDateTime.now()) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .execute(); em.flush(); em.clear(); } public Page workLabelHistoryList( - LabelAllocateDto.searchReq searchReq, String userId) { + LabelAllocateDto.searchReq searchReq, String userId) { NumberExpression totalCnt = labelingAssignmentEntity.assignmentUid.count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); Pageable pageable = searchReq.toPageable(); List list = - queryFactory - .select( - Projections.bean( - WorkHistoryDto.class, - Expressions.stringTemplate( - "concat({0}, '-', {1})", - mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy) - .as("changeDetectionYear"), - mapSheetAnalInferenceEntity.stage.longValue().as("stage"), - mapSheetAnalInferenceEntity.gukyuinApplyDttm.as("gukyuinApplyDttm"), - totalCnt.as("assignedCnt"), - completeCnt.as("completeCnt"), - skipCnt.as("skipCnt"), - mapSheetAnalInferenceEntity.createdDttm.as("createdDttm"), - new CaseBuilder() - .when(mapSheetAnalInferenceEntity.inspectionClosedYn.eq("Y")) - .then(mapSheetAnalInferenceEntity.updatedDttm) - .otherwise((ZonedDateTime) null) - .as("projectCloseDttm"))) - .from(labelingAssignmentEntity) - .innerJoin(mapSheetAnalInferenceEntity) - .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) - .where(labelingAssignmentEntity.workerUid.eq(userId)) - .groupBy( - mapSheetAnalInferenceEntity.id, + queryFactory + .select( + Projections.bean( + WorkHistoryDto.class, + Expressions.stringTemplate( + "concat({0}, '-', {1})", mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.inspectionClosedYn, - mapSheetAnalInferenceEntity.updatedDttm) - .orderBy( - // 진행중인 작업이 최상단 (remainCnt > 0) - new CaseBuilder() - .when(totalCnt.subtract(completeCnt).subtract(skipCnt).gt(0L)) - .then(0) - .otherwise(1) - .asc(), - // 최신 작업순 (반영일 기준) - mapSheetAnalInferenceEntity.gukyuinApplyDttm.desc()) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .fetch(); + mapSheetAnalInferenceEntity.targetYyyy) + .as("changeDetectionYear"), + mapSheetAnalInferenceEntity.stage.longValue().as("stage"), + mapSheetAnalInferenceEntity.gukyuinApplyDttm.as("gukyuinApplyDttm"), + totalCnt.as("assignedCnt"), + completeCnt.as("completeCnt"), + skipCnt.as("skipCnt"), + mapSheetAnalInferenceEntity.createdDttm.as("createdDttm"), + new CaseBuilder() + .when(mapSheetAnalInferenceEntity.inspectionClosedYn.eq("Y")) + .then(mapSheetAnalInferenceEntity.updatedDttm) + .otherwise((ZonedDateTime) null) + .as("projectCloseDttm"))) + .from(labelingAssignmentEntity) + .innerJoin(mapSheetAnalInferenceEntity) + .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) + .where(labelingAssignmentEntity.workerUid.eq(userId)) + .groupBy( + mapSheetAnalInferenceEntity.id, + mapSheetAnalInferenceEntity.compareYyyy, + mapSheetAnalInferenceEntity.targetYyyy, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.createdDttm, + mapSheetAnalInferenceEntity.inspectionClosedYn, + mapSheetAnalInferenceEntity.updatedDttm) + .orderBy( + // 진행중인 작업이 최상단 (remainCnt > 0) + new CaseBuilder() + .when(totalCnt.subtract(completeCnt).subtract(skipCnt).gt(0L)) + .then(0) + .otherwise(1) + .asc(), + // 최신 작업순 (반영일 기준) + mapSheetAnalInferenceEntity.gukyuinApplyDttm.desc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); // rowNum, remainCnt, percent, status를 Java에서 계산 int startRow = (int) pageable.getOffset() + 1; @@ -1669,13 +1677,13 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } Long countQuery = - queryFactory - .select(mapSheetAnalInferenceEntity.id.countDistinct()) - .from(labelingAssignmentEntity) - .innerJoin(mapSheetAnalInferenceEntity) - .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) - .where(labelingAssignmentEntity.workerUid.eq(userId)) - .fetchOne(); + queryFactory + .select(mapSheetAnalInferenceEntity.id.countDistinct()) + .from(labelingAssignmentEntity) + .innerJoin(mapSheetAnalInferenceEntity) + .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) + .where(labelingAssignmentEntity.workerUid.eq(userId)) + .fetchOne(); return new PageImpl<>(list, pageable, countQuery != null ? countQuery : 0L); } @@ -1686,66 +1694,66 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto NumberExpression totalCnt = labelingAssignmentEntity.assignmentUid.count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); Pageable pageable = searchReq.toPageable(); List list = - queryFactory - .select( - Projections.bean( - WorkHistoryDto.class, - Expressions.stringTemplate( - "concat({0}, '-', {1})", - mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy) - .as("changeDetectionYear"), - mapSheetAnalInferenceEntity.stage.longValue().as("stage"), - mapSheetAnalInferenceEntity.gukyuinApplyDttm.as("gukyuinApplyDttm"), - totalCnt.as("assignedCnt"), - completeCnt.as("completeCnt"), - skipCnt.as("skipCnt"), - mapSheetAnalInferenceEntity.createdDttm.as("createdDttm"), - new CaseBuilder() - .when(mapSheetAnalInferenceEntity.inspectionClosedYn.eq("Y")) - .then(mapSheetAnalInferenceEntity.updatedDttm) - .otherwise((ZonedDateTime) null) - .as("projectCloseDttm"))) - .from(labelingAssignmentEntity) - .innerJoin(mapSheetAnalInferenceEntity) - .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) - .where(labelingAssignmentEntity.inspectorUid.eq(userId)) - .groupBy( - mapSheetAnalInferenceEntity.id, + queryFactory + .select( + Projections.bean( + WorkHistoryDto.class, + Expressions.stringTemplate( + "concat({0}, '-', {1})", mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.inspectionClosedYn, - mapSheetAnalInferenceEntity.updatedDttm) - .orderBy( - // 진행중인 작업이 최상단 (remainCnt > 0) - new CaseBuilder() - .when(totalCnt.subtract(completeCnt).subtract(skipCnt).gt(0L)) - .then(0) - .otherwise(1) - .asc(), - // 최신 작업순 (반영일 기준) - mapSheetAnalInferenceEntity.gukyuinApplyDttm.desc()) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .fetch(); + mapSheetAnalInferenceEntity.targetYyyy) + .as("changeDetectionYear"), + mapSheetAnalInferenceEntity.stage.longValue().as("stage"), + mapSheetAnalInferenceEntity.gukyuinApplyDttm.as("gukyuinApplyDttm"), + totalCnt.as("assignedCnt"), + completeCnt.as("completeCnt"), + skipCnt.as("skipCnt"), + mapSheetAnalInferenceEntity.createdDttm.as("createdDttm"), + new CaseBuilder() + .when(mapSheetAnalInferenceEntity.inspectionClosedYn.eq("Y")) + .then(mapSheetAnalInferenceEntity.updatedDttm) + .otherwise((ZonedDateTime) null) + .as("projectCloseDttm"))) + .from(labelingAssignmentEntity) + .innerJoin(mapSheetAnalInferenceEntity) + .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) + .where(labelingAssignmentEntity.inspectorUid.eq(userId)) + .groupBy( + mapSheetAnalInferenceEntity.id, + mapSheetAnalInferenceEntity.compareYyyy, + mapSheetAnalInferenceEntity.targetYyyy, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.createdDttm, + mapSheetAnalInferenceEntity.inspectionClosedYn, + mapSheetAnalInferenceEntity.updatedDttm) + .orderBy( + // 진행중인 작업이 최상단 (remainCnt > 0) + new CaseBuilder() + .when(totalCnt.subtract(completeCnt).subtract(skipCnt).gt(0L)) + .then(0) + .otherwise(1) + .asc(), + // 최신 작업순 (반영일 기준) + mapSheetAnalInferenceEntity.gukyuinApplyDttm.desc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); // rowNum, remainCnt, percent, status를 Java에서 계산 int startRow = (int) pageable.getOffset() + 1; @@ -1775,14 +1783,34 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } Long countQuery = - queryFactory - .select(mapSheetAnalInferenceEntity.id.countDistinct()) - .from(labelingAssignmentEntity) - .innerJoin(mapSheetAnalInferenceEntity) - .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) - .where(labelingAssignmentEntity.inspectorUid.eq(userId)) - .fetchOne(); + queryFactory + .select(mapSheetAnalInferenceEntity.id.countDistinct()) + .from(labelingAssignmentEntity) + .innerJoin(mapSheetAnalInferenceEntity) + .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) + .where(labelingAssignmentEntity.inspectorUid.eq(userId)) + .fetchOne(); return new PageImpl<>(list, pageable, countQuery != null ? countQuery : 0L); } + + @Override + public void updateAnalInferenceMngState(UUID uuid, String status) { + queryFactory + .update(mapSheetAnalInferenceEntity) + .set(mapSheetAnalInferenceEntity.analState, status) + .set(mapSheetAnalInferenceEntity.updatedDttm, ZonedDateTime.now()) + .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) + .execute(); + } + + @Override + public Long findLabelingIngProcessCnt() { + return queryFactory + .select(mapSheetAnalInferenceEntity.id.count()) + .from(mapSheetAnalInferenceEntity) + .where( + mapSheetAnalInferenceEntity.analState.eq(LabelMngState.ING.getId())) + .fetchOne(); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryCustom.java index d6cf2458..6012a7d3 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryCustom.java @@ -3,6 +3,7 @@ package com.kamco.cd.kamcoback.postgres.repository.trainingdata; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.DefaultPaging; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.DetailRes; +import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.InferenceIdInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.LabelFeatureRequest.LabelProperties; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.LabelingGeometryInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.LabelingListDto; @@ -18,7 +19,7 @@ public interface TrainingDataLabelRepositoryCustom { LabelingGeometryInfo findLabelingAssignedGeom(String assignmentUid); - Long findLabelingAssignmentGeoUid(String assignmentUid); + InferenceIdInfo findLabelingAssignmentGeoUid(String assignmentUid); void updateLabelingStateAssignment(String assignmentUid, String status); @@ -37,4 +38,6 @@ public interface TrainingDataLabelRepositoryCustom { TrainingDataLabelDto.CogImageResponse getCogImageUrl( String mapSheetNum, Integer beforeYear, Integer afterYear); + + void updateAnalInferenceMngState(Long analUid, String status); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryImpl.java index e3eb797e..c67abff1 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryImpl.java @@ -4,6 +4,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QImageryEntity.imageryEntit 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.QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity; +import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity.mapSheetAnalInferenceEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnDataGeomEntity.mapSheetLearnDataGeomEntity; import com.fasterxml.jackson.databind.JsonNode; @@ -19,6 +20,7 @@ import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.DefaultPagin import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.DetailRes; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.InferenceDataGeometry; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.InferenceDataGeometry.InferenceProperties; +import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.InferenceIdInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.InspectionResultInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.LabelFeatureRequest.LabelProperties; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.LabelingGeometryInfo; @@ -174,9 +176,13 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport } @Override - public Long findLabelingAssignmentGeoUid(String assignmentUid) { + public InferenceIdInfo findLabelingAssignmentGeoUid(String assignmentUid) { return queryFactory - .select(labelingAssignmentEntity.inferenceGeomUid) + .select( + Projections.constructor( + InferenceIdInfo.class, + labelingAssignmentEntity.inferenceGeomUid, + labelingAssignmentEntity.analUid)) .from(labelingAssignmentEntity) .where(labelingAssignmentEntity.assignmentUid.eq(UUID.fromString(assignmentUid))) .fetchOne(); @@ -838,6 +844,16 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport } } + @Override + public void updateAnalInferenceMngState(Long analUid, String status) { + queryFactory + .update(mapSheetAnalInferenceEntity) + .set(mapSheetAnalInferenceEntity.analState, status) + .set(mapSheetAnalInferenceEntity.updatedDttm, ZonedDateTime.now()) + .where(mapSheetAnalInferenceEntity.id.eq(analUid)) + .execute(); + } + private StringExpression makeCogUrl(NumberPath year) { return new CaseBuilder() .when(imageryEntity.year.eq(year)) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryCustom.java index 2476f931..2c96638e 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryCustom.java @@ -1,5 +1,6 @@ package com.kamco.cd.kamcoback.postgres.repository.trainingdata; +import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.InferenceIdInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.DefaultPaging; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.DetailRes; @@ -18,7 +19,7 @@ public interface TrainingDataReviewRepositoryCustom { ReviewGeometryInfo findReviewAssignedGeom(String operatorUid); - Long findReviewOperatorGeoUid(String operatorUid); + InferenceIdInfo findReviewOperatorGeoUid(String operatorUid); void updateReviewStateOperator(String operatorUid, String status); @@ -37,4 +38,6 @@ public interface TrainingDataReviewRepositoryCustom { TrainingDataReviewDto.CogImageResponse getCogImageUrl( String mapSheetNum, Integer beforeYear, Integer afterYear); + + void updateAnalInferenceMngState(Long analUid, String status); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryImpl.java index cd3259fa..566e6fab 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryImpl.java @@ -4,6 +4,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QImageryEntity.imageryEntit 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.QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity; +import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity.mapSheetAnalInferenceEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnDataGeomEntity.mapSheetLearnDataGeomEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMemberEntity.memberEntity; @@ -12,6 +13,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InspectState; import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataInferenceGeomEntity; +import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.InferenceIdInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.ChangeDetectionInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.ClassificationInfo; @@ -177,9 +179,13 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport } @Override - public Long findReviewOperatorGeoUid(String operatorUid) { + public InferenceIdInfo findReviewOperatorGeoUid(String operatorUid) { return queryFactory - .select(labelingAssignmentEntity.inferenceGeomUid) + .select( + Projections.constructor( + InferenceIdInfo.class, + labelingAssignmentEntity.inferenceGeomUid, + labelingAssignmentEntity.analUid)) .from(labelingAssignmentEntity) .where(labelingAssignmentEntity.assignmentUid.eq(UUID.fromString(operatorUid))) .fetchOne(); @@ -868,6 +874,16 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport } } + @Override + public void updateAnalInferenceMngState(Long analUid, String status) { + queryFactory + .update(mapSheetAnalInferenceEntity) + .set(mapSheetAnalInferenceEntity.analState, status) + .set(mapSheetAnalInferenceEntity.updatedDttm, ZonedDateTime.now()) + .where(mapSheetAnalInferenceEntity.id.eq(analUid)) + .execute(); + } + private StringExpression makeCogUrl(NumberPath year) { return new CaseBuilder() .when(imageryEntity.year.eq(year)) diff --git a/src/main/java/com/kamco/cd/kamcoback/trainingdata/dto/TrainingDataLabelDto.java b/src/main/java/com/kamco/cd/kamcoback/trainingdata/dto/TrainingDataLabelDto.java index b45f2c1c..fe6113c3 100644 --- a/src/main/java/com/kamco/cd/kamcoback/trainingdata/dto/TrainingDataLabelDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/trainingdata/dto/TrainingDataLabelDto.java @@ -204,6 +204,19 @@ public class TrainingDataLabelDto { } } + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class InferenceIdInfo { + + @Schema(description = "inferenceGeomUid") + private Long inferenceGeomUid; + + @Schema(description = "analUid") + private Long analUid; + } + @Schema(name = "LearnDataGeometry", description = "LearnDataGeometry") @Getter @Setter diff --git a/src/main/java/com/kamco/cd/kamcoback/trainingdata/service/TrainingDataLabelService.java b/src/main/java/com/kamco/cd/kamcoback/trainingdata/service/TrainingDataLabelService.java index b7af6862..2d4430dd 100644 --- a/src/main/java/com/kamco/cd/kamcoback/trainingdata/service/TrainingDataLabelService.java +++ b/src/main/java/com/kamco/cd/kamcoback/trainingdata/service/TrainingDataLabelService.java @@ -2,11 +2,13 @@ package com.kamco.cd.kamcoback.trainingdata.service; import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode; import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelMngState; import com.kamco.cd.kamcoback.postgres.core.TrainingDataLabelCoreService; import com.kamco.cd.kamcoback.scheduler.service.TrainingDataReviewJobService; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.DefaultPaging; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.DetailRes; +import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.InferenceIdInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.LabelFeatureRequest; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.LabelingGeometryInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.LabelingListDto; @@ -44,8 +46,8 @@ public class TrainingDataLabelService { public String saveLabelingFeature(LabelFeatureRequest request) { String status = ""; String assignmentUid = request.getAssignmentUid(); - Long inferenceGeomUid = - trainingDataLabelCoreService.findLabelingAssignmentGeoUid(assignmentUid); + InferenceIdInfo info = trainingDataLabelCoreService.findLabelingAssignmentGeoUid(assignmentUid); + Long inferenceGeomUid = info.getInferenceGeomUid(); if (request.getGeometry() == null || request.getGeometry().isEmpty()) { // SKIP 상태만 업데이트 status = "SKIP"; @@ -61,6 +63,10 @@ public class TrainingDataLabelService { // 라벨링 완료하면 실시간 검수 할당 (1건) trainingDataReviewJobService.assignRealtime(assignmentUid); + // 회차 진행 상태 update + trainingDataLabelCoreService.updateAnalInferenceMngState( + info.getAnalUid(), LabelMngState.ING.getId()); + return status; } diff --git a/src/main/java/com/kamco/cd/kamcoback/trainingdata/service/TrainingDataReviewService.java b/src/main/java/com/kamco/cd/kamcoback/trainingdata/service/TrainingDataReviewService.java index 3343bdb6..ebf50c53 100644 --- a/src/main/java/com/kamco/cd/kamcoback/trainingdata/service/TrainingDataReviewService.java +++ b/src/main/java/com/kamco/cd/kamcoback/trainingdata/service/TrainingDataReviewService.java @@ -2,7 +2,9 @@ package com.kamco.cd.kamcoback.trainingdata.service; import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode; import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelMngState; import com.kamco.cd.kamcoback.postgres.core.TrainingDataReviewCoreService; +import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataLabelDto.InferenceIdInfo; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.DefaultPaging; import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.DetailRes; @@ -39,7 +41,8 @@ public class TrainingDataReviewService { public String saveReviewFeature(GeoFeatureRequest request) { String status = ""; String operatorUid = request.getOperatorUid(); - Long inferenceGeomUid = trainingDataReviewCoreService.findReviewOperatorGeoUid(operatorUid); + InferenceIdInfo info = trainingDataReviewCoreService.findReviewOperatorGeoUid(operatorUid); + Long inferenceGeomUid = info.getInferenceGeomUid(); if (request.getGeometry() == null || request.getGeometry().isEmpty()) { // EXCEPT 상태만 업데이트 @@ -52,6 +55,11 @@ public class TrainingDataReviewService { trainingDataReviewCoreService.updateReviewPolygonClass( inferenceGeomUid, request.getGeometry(), request.getProperties(), status); } + + // 회차 진행 상태 update + trainingDataReviewCoreService.updateAnalInferenceMngState( + info.getAnalUid(), LabelMngState.ING.getId()); + return status; } From 07e4f1b052581f11db31cba8846422119102d244 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 14:52:53 +0900 Subject: [PATCH 3/3] spotless --- .../label/LabelAllocateRepositoryImpl.java | 1926 ++++++++--------- 1 file changed, 959 insertions(+), 967 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java index d8e01a6d..0bf68180 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java @@ -64,33 +64,32 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto private final JPAQueryFactory queryFactory; - @PersistenceContext - private EntityManager em; + @PersistenceContext private EntityManager em; @Override public List fetchNextIds(Long lastId, Long batchSize, UUID uuid) { return queryFactory - .select( - Projections.constructor( - AllocateInfoDto.class, - mapSheetAnalDataInferenceGeomEntity.geoUid, - mapSheetAnalDataInferenceGeomEntity.mapSheetNum, - mapSheetAnalDataInferenceGeomEntity.pnu)) - .from(mapSheetAnalInferenceEntity) - .innerJoin(mapSheetAnalDataInferenceEntity) - .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) - .innerJoin(mapSheetAnalDataInferenceGeomEntity) - .on( - mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid), - mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), - mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) - .where( - mapSheetAnalInferenceEntity.uuid.eq(uuid), - lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId)) - .orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc()) - .limit(batchSize) - .fetch(); + .select( + Projections.constructor( + AllocateInfoDto.class, + mapSheetAnalDataInferenceGeomEntity.geoUid, + mapSheetAnalDataInferenceGeomEntity.mapSheetNum, + mapSheetAnalDataInferenceGeomEntity.pnu)) + .from(mapSheetAnalInferenceEntity) + .innerJoin(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) + .innerJoin(mapSheetAnalDataInferenceGeomEntity) + .on( + mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid), + mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), + mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) + .where( + mapSheetAnalInferenceEntity.uuid.eq(uuid), + lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId)) + .orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc()) + .limit(batchSize) + .fetch(); } @Override @@ -98,10 +97,10 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.id.eq(analUid)) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.id.eq(analUid)) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); @@ -109,190 +108,190 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // data_geom 테이블에 label state 를 ASSIGNED 로 update List geoUidList = - ids.stream().map(AllocateInfoDto::getGeoUid).filter(Objects::nonNull).toList(); + ids.stream().map(AllocateInfoDto::getGeoUid).filter(Objects::nonNull).toList(); queryFactory - .update(mapSheetAnalDataInferenceGeomEntity) - .set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId()) - .set(mapSheetAnalDataInferenceGeomEntity.labelStateDttm, ZonedDateTime.now()) - .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(geoUidList)) - .execute(); + .update(mapSheetAnalDataInferenceGeomEntity) + .set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId()) + .set(mapSheetAnalDataInferenceGeomEntity.labelStateDttm, ZonedDateTime.now()) + .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(geoUidList)) + .execute(); // 라벨러 할당 테이블에 insert Session session = em.unwrap(Session.class); session.doWork( - connection -> { - String sql = - """ + connection -> { + String sql = + """ insert into tb_labeling_assignment (assignment_uid, inference_geom_uid, worker_uid, work_state, assign_group_id, anal_uid, pnu) values (?, ?, ?, ?, ?, ?, ?) """; - try (PreparedStatement ps = connection.prepareStatement(sql)) { - int batchSize = 0; + try (PreparedStatement ps = connection.prepareStatement(sql)) { + int batchSize = 0; - for (AllocateInfoDto info : ids) { - ps.setObject(1, UUID.randomUUID()); - ps.setLong(2, info.getGeoUid()); - ps.setString(3, userId); - ps.setString(4, LabelState.ASSIGNED.getId()); - ps.setString(5, String.valueOf(info.getMapSheetNum())); - ps.setLong(6, analEntity.getId()); - ps.setLong(7, info.getPnu()); + for (AllocateInfoDto info : ids) { + ps.setObject(1, UUID.randomUUID()); + ps.setLong(2, info.getGeoUid()); + ps.setString(3, userId); + ps.setString(4, LabelState.ASSIGNED.getId()); + ps.setString(5, String.valueOf(info.getMapSheetNum())); + ps.setLong(6, analEntity.getId()); + ps.setLong(7, info.getPnu()); - ps.addBatch(); - batchSize++; + ps.addBatch(); + batchSize++; - if (batchSize % 1000 == 0) { - ps.executeBatch(); - ps.clearBatch(); + if (batchSize % 1000 == 0) { + ps.executeBatch(); + ps.clearBatch(); + } } - } - ps.executeBatch(); - } - }); + ps.executeBatch(); + } + }); } @Override public List findAssignedLabelerList(Long analUid) { // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.id.eq(analUid)) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.id.eq(analUid)) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("mapSheetAnalInferenceEntity not found for analUid: "); } return queryFactory - .selectFrom(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.analUid.eq(analEntity.getId()), - labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()), - labelingAssignmentEntity.inspectorUid.isNull()) - .orderBy(labelingAssignmentEntity.workerUid.asc()) - .fetch(); + .selectFrom(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.analUid.eq(analEntity.getId()), + labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()), + labelingAssignmentEntity.inspectorUid.isNull()) + .orderBy(labelingAssignmentEntity.workerUid.asc()) + .fetch(); } @Override public Long findLabelUnAssignedCnt(UUID uuid) { return queryFactory - .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) - .from(mapSheetAnalInferenceEntity) - .innerJoin(mapSheetAnalDataInferenceEntity) - .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) - .innerJoin(mapSheetAnalDataInferenceGeomEntity) - .on( - mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid), - mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), - mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) - .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) - .fetchOne(); + .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) + .from(mapSheetAnalInferenceEntity) + .innerJoin(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) + .innerJoin(mapSheetAnalDataInferenceGeomEntity) + .on( + mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid), + mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), + mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) + .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) + .fetchOne(); } @Override public void assignInspector(UUID assignmentUid, String inspectorUid) { queryFactory - .update(labelingAssignmentEntity) - .set(labelingAssignmentEntity.inspectorUid, inspectorUid) - .where(labelingAssignmentEntity.assignmentUid.eq(assignmentUid)) - .execute(); + .update(labelingAssignmentEntity) + .set(labelingAssignmentEntity.inspectorUid, inspectorUid) + .where(labelingAssignmentEntity.assignmentUid.eq(assignmentUid)) + .execute(); } @Override public List availUserList(String role) { return queryFactory - .select( - Projections.constructor( - LabelAllocateDto.UserList.class, - memberEntity.userRole, - memberEntity.employeeNo, - memberEntity.name)) - .from(memberEntity) - .where( - memberEntity.userRole.eq(role), - memberEntity.status.eq(com.kamco.cd.kamcoback.common.enums.StatusType.ACTIVE.getId())) - .orderBy(memberEntity.name.asc()) - .fetch(); + .select( + Projections.constructor( + LabelAllocateDto.UserList.class, + memberEntity.userRole, + memberEntity.employeeNo, + memberEntity.name)) + .from(memberEntity) + .where( + memberEntity.userRole.eq(role), + memberEntity.status.eq(com.kamco.cd.kamcoback.common.enums.StatusType.ACTIVE.getId())) + .orderBy(memberEntity.name.asc()) + .fetch(); } @Override public List findWorkerStatistics( - Long analUid, String workerType, String search, String sortType) { + Long analUid, String workerType, String search, String sortType) { // 작업자 유형에 따른 필드 선택 StringExpression workerIdField = - "REVIEWER".equals(workerType) - ? labelingAssignmentEntity.inspectorUid - : labelingAssignmentEntity.workerUid; + "REVIEWER".equals(workerType) + ? labelingAssignmentEntity.inspectorUid + : labelingAssignmentEntity.workerUid; BooleanExpression workerCondition = - "REVIEWER".equals(workerType) - ? labelingAssignmentEntity.inspectorUid.isNotNull() - : labelingAssignmentEntity.workerUid.isNotNull(); + "REVIEWER".equals(workerType) + ? labelingAssignmentEntity.inspectorUid.isNotNull() + : labelingAssignmentEntity.workerUid.isNotNull(); // 검색 조건 (이름 또는 사번으로 검색) BooleanExpression searchCondition = null; if (search != null && !search.isEmpty()) { searchCondition = - memberEntity.name.contains(search).or(memberEntity.employeeNo.contains(search)); + memberEntity.name.contains(search).or(memberEntity.employeeNo.contains(search)); } // 완료, 스킵, 남은 작업 계산 NumberExpression completedSum = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq("DONE")) - .then(1L) - .otherwise(0L) - .sum(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq("DONE")) + .then(1L) + .otherwise(0L) + .sum(); NumberExpression skippedSum = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq("SKIP")) - .then(1L) - .otherwise(0L) - .sum(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq("SKIP")) + .then(1L) + .otherwise(0L) + .sum(); NumberExpression remainingSum = - new CaseBuilder() - .when( - labelingAssignmentEntity - .workState - .notIn("DONE", "SKIP") - .and(labelingAssignmentEntity.workState.isNotNull())) - .then(1L) - .otherwise(0L) - .sum(); + new CaseBuilder() + .when( + labelingAssignmentEntity + .workState + .notIn("DONE", "SKIP") + .and(labelingAssignmentEntity.workState.isNotNull())) + .then(1L) + .otherwise(0L) + .sum(); // 기본 통계 조회 쿼리 BooleanExpression analUidCondition = - analUid != null ? labelingAssignmentEntity.analUid.eq(analUid) : null; + analUid != null ? labelingAssignmentEntity.analUid.eq(analUid) : null; var baseQuery = - queryFactory - .select( - workerIdField, - memberEntity.name, - workerIdField.count(), - completedSum, - skippedSum, - remainingSum, - labelingAssignmentEntity.stagnationYn.max()) - .from(labelingAssignmentEntity) - .leftJoin(memberEntity) - .on( - "REVIEWER".equals(workerType) - ? memberEntity.employeeNo.eq(labelingAssignmentEntity.inspectorUid) - : memberEntity.employeeNo.eq(labelingAssignmentEntity.workerUid)) - .where(analUidCondition, workerCondition, searchCondition) - .groupBy(workerIdField, memberEntity.name); + queryFactory + .select( + workerIdField, + memberEntity.name, + workerIdField.count(), + completedSum, + skippedSum, + remainingSum, + labelingAssignmentEntity.stagnationYn.max()) + .from(labelingAssignmentEntity) + .leftJoin(memberEntity) + .on( + "REVIEWER".equals(workerType) + ? memberEntity.employeeNo.eq(labelingAssignmentEntity.inspectorUid) + : memberEntity.employeeNo.eq(labelingAssignmentEntity.workerUid)) + .where(analUidCondition, workerCondition, searchCondition) + .groupBy(workerIdField, memberEntity.name); // 정렬 조건 적용 if (sortType != null) { @@ -324,22 +323,22 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 결과를 DTO로 변환 return baseQuery.fetch().stream() - .map( - tuple -> { - Character maxStagnationYn = tuple.get(labelingAssignmentEntity.stagnationYn.max()); - return WorkerStatistics.builder() - .workerId(tuple.get(workerIdField)) - .workerName(tuple.get(memberEntity.name)) - .workerType(workerType) - .totalAssigned(tuple.get(workerIdField.count())) - .completed(tuple.get(completedSum)) - .skipped(tuple.get(skippedSum)) - .remaining(tuple.get(remainingSum)) - .history(null) // 3일 이력은 Service에서 채움 - .isStagnated(maxStagnationYn != null && maxStagnationYn == 'Y') - .build(); - }) - .toList(); + .map( + tuple -> { + Character maxStagnationYn = tuple.get(labelingAssignmentEntity.stagnationYn.max()); + return WorkerStatistics.builder() + .workerId(tuple.get(workerIdField)) + .workerName(tuple.get(memberEntity.name)) + .workerType(workerType) + .totalAssigned(tuple.get(workerIdField.count())) + .completed(tuple.get(completedSum)) + .skipped(tuple.get(skippedSum)) + .remaining(tuple.get(remainingSum)) + .history(null) // 3일 이력은 Service에서 채움 + .isStagnated(maxStagnationYn != null && maxStagnationYn == 'Y') + .build(); + }) + .toList(); } @Override @@ -350,94 +349,94 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto UUID latestUuid = findLastLabelWorkState(); if (latestUuid != null) { effectiveAnalUid = - queryFactory - .select(mapSheetAnalInferenceEntity.id) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(latestUuid)) - .fetchOne(); + queryFactory + .select(mapSheetAnalInferenceEntity.id) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(latestUuid)) + .fetchOne(); } } BooleanExpression analUidCondition = - effectiveAnalUid != null ? labelingAssignmentEntity.analUid.eq(effectiveAnalUid) : null; + effectiveAnalUid != null ? labelingAssignmentEntity.analUid.eq(effectiveAnalUid) : null; // analUid로 분석 정보(compareYyyy, targetYyyy, stage) 조회 MapSheetAnalInferenceEntity analEntity = null; if (effectiveAnalUid != null) { analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.id.eq(effectiveAnalUid)) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.id.eq(effectiveAnalUid)) + .fetchOne(); } // 라벨링 대상 건수: tb_map_sheet_anal_data_inference_geom에서 pnu > 0 AND pass_yn = false(부적합)인 건수 Long labelingTargetCount = 0L; if (analEntity != null) { labelingTargetCount = - queryFactory - .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) - .from(mapSheetAnalDataInferenceGeomEntity) - .where( - mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(analEntity.getCompareYyyy()), - mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(analEntity.getTargetYyyy()), - mapSheetAnalDataInferenceGeomEntity.stage.eq(analEntity.getStage()), - mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L), - mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) - .fetchOne(); + queryFactory + .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) + .from(mapSheetAnalDataInferenceGeomEntity) + .where( + mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(analEntity.getCompareYyyy()), + mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(analEntity.getTargetYyyy()), + mapSheetAnalDataInferenceGeomEntity.stage.eq(analEntity.getStage()), + mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L), + mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) + .fetchOne(); } // 전체 배정 건수 (tb_labeling_assignment 기준) Long totalAssigned = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition) + .fetchOne(); // === 라벨링 통계 === // 라벨링 완료: LABEL_FIN, TEST_ING, DONE (검수 포함) Long labelingCompleted = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where( - analUidCondition, - labelingAssignmentEntity.workState.in("LABEL_FIN", "TEST_ING", "DONE")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where( + analUidCondition, + labelingAssignmentEntity.workState.in("LABEL_FIN", "TEST_ING", "DONE")) + .fetchOne(); // 스킵 건수 Long skipCount = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.workState.eq("SKIP")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.workState.eq("SKIP")) + .fetchOne(); // 투입된 라벨러 수 Long labelerCount = - queryFactory - .select(labelingAssignmentEntity.workerUid.countDistinct()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.workerUid.isNotNull()) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.workerUid.countDistinct()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.workerUid.isNotNull()) + .fetchOne(); // === 검수 통계 === // 검수 완료: DONE만 Long inspectionCompleted = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.workState.eq("DONE")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.workState.eq("DONE")) + .fetchOne(); // 투입된 검수자 수 Long inspectorCount = - queryFactory - .select(labelingAssignmentEntity.inspectorUid.countDistinct()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.inspectorUid.isNotNull()) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.inspectorUid.countDistinct()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.inspectorUid.isNotNull()) + .fetchOne(); // 라벨링 대상 건수 (pass_yn = false인 부적합 데이터 기준) long labelingTotal = labelingTargetCount != null ? labelingTargetCount : 0L; @@ -463,7 +462,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 진행률 계산 (라벨링 대상 건수 기준) double labelingRate = labelingTotal > 0 ? (double) labelCompleted / labelingTotal * 100 : 0.0; double inspectionRate = - inspectionTotal > 0 ? (double) inspectCompleted / inspectionTotal * 100 : 0.0; + inspectionTotal > 0 ? (double) inspectCompleted / inspectionTotal * 100 : 0.0; // 상태 판단 (각각의 closedYn이 "Y"이면 "종료", 아니면 진행중/완료) String labelingStatus; @@ -484,29 +483,29 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } return WorkProgressInfo.builder() - // 라벨링 (pass_yn = false인 부적합 데이터 기준) - .labelingProgressRate(labelingRate) - .labelingStatus(labelingStatus) - .labelingTotalCount(labelingTotal) - .labelingCompletedCount(labelCompleted) - .labelingSkipCount(skipped) - .labelingRemainingCount(labelingRemaining) - .labelerCount(labelerCount != null ? labelerCount : 0L) - // 검수 (라벨링 완료 건수 기준) - .inspectionProgressRate(inspectionRate) - .inspectionStatus(inspectionStatus) - .inspectionTotalCount(inspectionTotal) - .inspectionCompletedCount(inspectCompleted) - .inspectionSkipCount(skipped) - .inspectionRemainingCount(inspectionRemaining) - .inspectorCount(inspectorCount != null ? inspectorCount : 0L) - // 레거시 호환 필드 (Deprecated) - .progressRate(labelingRate) - .totalAssignedCount(labelingTotal) - .completedCount(labelCompleted) - .remainingLabelCount(labelingRemaining) - .remainingInspectCount(inspectionRemaining) - .build(); + // 라벨링 (pass_yn = false인 부적합 데이터 기준) + .labelingProgressRate(labelingRate) + .labelingStatus(labelingStatus) + .labelingTotalCount(labelingTotal) + .labelingCompletedCount(labelCompleted) + .labelingSkipCount(skipped) + .labelingRemainingCount(labelingRemaining) + .labelerCount(labelerCount != null ? labelerCount : 0L) + // 검수 (라벨링 완료 건수 기준) + .inspectionProgressRate(inspectionRate) + .inspectionStatus(inspectionStatus) + .inspectionTotalCount(inspectionTotal) + .inspectionCompletedCount(inspectCompleted) + .inspectionSkipCount(skipped) + .inspectionRemainingCount(inspectionRemaining) + .inspectorCount(inspectorCount != null ? inspectorCount : 0L) + // 레거시 호환 필드 (Deprecated) + .progressRate(labelingRate) + .totalAssignedCount(labelingTotal) + .completedCount(labelCompleted) + .remainingLabelCount(labelingRemaining) + .remainingInspectCount(inspectionRemaining) + .build(); } @Override @@ -519,11 +518,11 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // UUID로 analUid 조회 Long effectiveAnalUid = - queryFactory - .select(mapSheetAnalInferenceEntity.id) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(targetUuid)) - .fetchOne(); + queryFactory + .select(mapSheetAnalInferenceEntity.id) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(targetUuid)) + .fetchOne(); if (effectiveAnalUid == null) { return null; @@ -533,76 +532,76 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // analUid로 분석 정보(compareYyyy, targetYyyy, stage) 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.id.eq(effectiveAnalUid)) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.id.eq(effectiveAnalUid)) + .fetchOne(); // 라벨링 대상 건수: tb_map_sheet_anal_data_inference_geom에서 pnu > 0 AND pass_yn = false(부적합)인 건수 Long labelingTargetCount = 0L; if (analEntity != null) { labelingTargetCount = - queryFactory - .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) - .from(mapSheetAnalInferenceEntity) - .innerJoin(mapSheetAnalDataInferenceEntity) - .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) - .innerJoin(mapSheetAnalDataInferenceGeomEntity) - .on( - mapSheetAnalDataInferenceEntity.id.eq( - mapSheetAnalDataInferenceGeomEntity.dataUid)) - .where( - mapSheetAnalInferenceEntity.uuid.eq(targetUuid), - mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L), - mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) - .fetchOne(); + queryFactory + .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) + .from(mapSheetAnalInferenceEntity) + .innerJoin(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) + .innerJoin(mapSheetAnalDataInferenceGeomEntity) + .on( + mapSheetAnalDataInferenceEntity.id.eq( + mapSheetAnalDataInferenceGeomEntity.dataUid)) + .where( + mapSheetAnalInferenceEntity.uuid.eq(targetUuid), + mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L), + mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) + .fetchOne(); } // 전체 배정 건수 (tb_labeling_assignment 기준) Long totalAssigned = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition) + .fetchOne(); // === 라벨링 통계 === Long labelingCompleted = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where( - analUidCondition, labelingAssignmentEntity.workState.in("ASSIGNED", "SKIP", "DONE")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where( + analUidCondition, labelingAssignmentEntity.workState.in("ASSIGNED", "SKIP", "DONE")) + .fetchOne(); Long skipCount = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.workState.eq("SKIP")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.workState.eq("SKIP")) + .fetchOne(); Long labelerCount = - queryFactory - .select(labelingAssignmentEntity.workerUid.countDistinct()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.workerUid.isNotNull()) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.workerUid.countDistinct()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.workerUid.isNotNull()) + .fetchOne(); // === 검수 통계 === Long inspectionCompleted = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.inspectState.eq("COMPLETE")) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.inspectState.eq("COMPLETE")) + .fetchOne(); Long inspectorCount = - queryFactory - .select(labelingAssignmentEntity.inspectorUid.countDistinct()) - .from(labelingAssignmentEntity) - .where(analUidCondition, labelingAssignmentEntity.inspectorUid.isNotNull()) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.inspectorUid.countDistinct()) + .from(labelingAssignmentEntity) + .where(analUidCondition, labelingAssignmentEntity.inspectorUid.isNotNull()) + .fetchOne(); // 계산 long labelingTotal = labelingTargetCount != null ? labelingTargetCount : 0L; @@ -623,7 +622,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto double labelingRate = labelingTotal > 0 ? (double) labelCompleted / labelingTotal * 100 : 0.0; double inspectionRate = - inspectionTotal > 0 ? (double) inspectCompleted / inspectionTotal * 100 : 0.0; + inspectionTotal > 0 ? (double) inspectCompleted / inspectionTotal * 100 : 0.0; // 상태 판단 String labelingStatus; @@ -642,55 +641,55 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } return WorkProgressInfo.builder() - .labelingProgressRate(labelingRate) - .labelingStatus(labelingStatus) - .labelingTotalCount(labelingTotal) - .labelingCompletedCount(labelCompleted) - .labelingSkipCount(skipped) - .labelingRemainingCount(labelingRemaining) - .labelerCount(labelerCount != null ? labelerCount : 0L) - .inspectionProgressRate(inspectionRate) - .inspectionStatus(inspectionStatus) - .inspectionTotalCount(inspectionTotal) - .inspectionCompletedCount(inspectCompleted) - .inspectionSkipCount(skipped) // TODO - .inspectionRemainingCount(inspectionRemaining) - .inspectorCount(inspectorCount != null ? inspectorCount : 0L) - .progressRate(labelingRate) - .totalAssignedCount(labelingTotal) - .completedCount(labelCompleted) - .remainingLabelCount(labelingRemaining) - .remainingInspectCount(inspectionRemaining) - .build(); + .labelingProgressRate(labelingRate) + .labelingStatus(labelingStatus) + .labelingTotalCount(labelingTotal) + .labelingCompletedCount(labelCompleted) + .labelingSkipCount(skipped) + .labelingRemainingCount(labelingRemaining) + .labelerCount(labelerCount != null ? labelerCount : 0L) + .inspectionProgressRate(inspectionRate) + .inspectionStatus(inspectionStatus) + .inspectionTotalCount(inspectionTotal) + .inspectionCompletedCount(inspectCompleted) + .inspectionSkipCount(skipped) // TODO + .inspectionRemainingCount(inspectionRemaining) + .inspectorCount(inspectorCount != null ? inspectorCount : 0L) + .progressRate(labelingRate) + .totalAssignedCount(labelingTotal) + .completedCount(labelCompleted) + .remainingLabelCount(labelingRemaining) + .remainingInspectCount(inspectionRemaining) + .build(); } @Override 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 endOfDay = date.atTime(LocalTime.MAX).atZone(ZoneId.systemDefault()); BooleanExpression workerCondition = - "REVIEWER".equals(workerType) - ? labelingAssignmentEntity.inspectorUid.eq(workerId) - : labelingAssignmentEntity.workerUid.eq(workerId); + "REVIEWER".equals(workerType) + ? labelingAssignmentEntity.inspectorUid.eq(workerId) + : labelingAssignmentEntity.workerUid.eq(workerId); BooleanExpression analUidCondition = - analUid != null ? labelingAssignmentEntity.analUid.eq(analUid) : null; + analUid != null ? labelingAssignmentEntity.analUid.eq(analUid) : null; Long count = - queryFactory - .select(labelingAssignmentEntity.count()) - .from(labelingAssignmentEntity) - .where( - analUidCondition, - workerCondition, - labelingAssignmentEntity.workState.in( - LabelState.DONE.getId(), LabelState.SKIP.getId()), - labelingAssignmentEntity.modifiedDate.between(startOfDay, endOfDay)) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.count()) + .from(labelingAssignmentEntity) + .where( + analUidCondition, + workerCondition, + labelingAssignmentEntity.workState.in( + LabelState.DONE.getId(), LabelState.SKIP.getId()), + labelingAssignmentEntity.modifiedDate.between(startOfDay, endOfDay)) + .fetchOne(); return count != null ? count : 0L; } @@ -698,10 +697,10 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @Override public void assignInspectorBulk(List assignmentUids, String inspectorUid) { queryFactory - .update(labelingAssignmentEntity) - .set(labelingAssignmentEntity.inspectorUid, inspectorUid) - .where(labelingAssignmentEntity.assignmentUid.in(assignmentUids)) - .execute(); + .update(labelingAssignmentEntity) + .set(labelingAssignmentEntity.inspectorUid, inspectorUid) + .where(labelingAssignmentEntity.assignmentUid.in(assignmentUids)) + .execute(); em.clear(); } @@ -710,78 +709,78 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto public InferenceDetail findInferenceDetail(String uuid) { // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); } return queryFactory - .select( - Projections.constructor( - InferenceDetail.class, - mapSheetAnalInferenceEntity.analTitle, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalDataInferenceGeomEntity.geoUid.count())) - .from(mapSheetAnalInferenceEntity) - .leftJoin(mapSheetAnalDataInferenceGeomEntity) - .on( - mapSheetAnalInferenceEntity.compareYyyy.eq( - mapSheetAnalDataInferenceGeomEntity.compareYyyy), - mapSheetAnalInferenceEntity.targetYyyy.eq( - mapSheetAnalDataInferenceGeomEntity.targetYyyy), - mapSheetAnalInferenceEntity.stage.eq(mapSheetAnalDataInferenceGeomEntity.stage), - mapSheetAnalDataInferenceGeomEntity.pnu.gt(0), - mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) - .where(mapSheetAnalInferenceEntity.id.eq(analEntity.getId())) - .groupBy( - mapSheetAnalInferenceEntity.analTitle, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.detectingCnt) - .fetchOne(); + .select( + Projections.constructor( + InferenceDetail.class, + mapSheetAnalInferenceEntity.analTitle, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalDataInferenceGeomEntity.geoUid.count())) + .from(mapSheetAnalInferenceEntity) + .leftJoin(mapSheetAnalDataInferenceGeomEntity) + .on( + mapSheetAnalInferenceEntity.compareYyyy.eq( + mapSheetAnalDataInferenceGeomEntity.compareYyyy), + mapSheetAnalInferenceEntity.targetYyyy.eq( + mapSheetAnalDataInferenceGeomEntity.targetYyyy), + mapSheetAnalInferenceEntity.stage.eq(mapSheetAnalDataInferenceGeomEntity.stage), + mapSheetAnalDataInferenceGeomEntity.pnu.gt(0), + mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) + .where(mapSheetAnalInferenceEntity.id.eq(analEntity.getId())) + .groupBy( + mapSheetAnalInferenceEntity.analTitle, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.detectingCnt) + .fetchOne(); } @Override public List fetchNextMoveIds(Long lastId, Long batchSize, String uuid, String userId) { MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); } return queryFactory - .select(labelingAssignmentEntity.inferenceGeomUid) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.workerUid.eq(userId), - labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()), - labelingAssignmentEntity.analUid.eq(analEntity.getId()), - lastId == null ? null : labelingAssignmentEntity.inferenceGeomUid.gt(lastId)) - .orderBy( - labelingAssignmentEntity.assignGroupId.asc(), - labelingAssignmentEntity.inferenceGeomUid.asc()) - .limit(batchSize) - .fetch(); + .select(labelingAssignmentEntity.inferenceGeomUid) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.workerUid.eq(userId), + labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()), + labelingAssignmentEntity.analUid.eq(analEntity.getId()), + lastId == null ? null : labelingAssignmentEntity.inferenceGeomUid.gt(lastId)) + .orderBy( + labelingAssignmentEntity.assignGroupId.asc(), + labelingAssignmentEntity.inferenceGeomUid.asc()) + .limit(batchSize) + .fetch(); } @Transactional @Override public void assignOwnerMove(List sub, String userId) { queryFactory - .update(labelingAssignmentEntity) - .set(labelingAssignmentEntity.workerUid, userId) - .where(labelingAssignmentEntity.inferenceGeomUid.in(sub)) - .execute(); + .update(labelingAssignmentEntity) + .set(labelingAssignmentEntity.workerUid, userId) + .where(labelingAssignmentEntity.inferenceGeomUid.in(sub)) + .execute(); em.clear(); } @@ -790,10 +789,10 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto public LabelerDetail findLabelerDetail(String userId, String uuid) { // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for uuid: " + uuid); @@ -805,141 +804,137 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto NumberExpression totalCnt = labelingAssignmentEntity.assignmentUid.count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression percent = - new CaseBuilder() - .when(completeCnt.eq(0L)) - .then(0.0) - .otherwise( - Expressions.numberTemplate( - Double.class, - "ROUND(({0} * 1.0 / NULLIF({1}, 0)) * 100, 2)", - completeCnt, - totalCnt)); + new CaseBuilder() + .when(completeCnt.eq(0L)) + .then(0.0) + .otherwise( + Expressions.numberTemplate( + Double.class, + "ROUND(({0} * 1.0 / NULLIF({1}, 0)) * 100, 2)", + completeCnt, + totalCnt)); Expression remainCnt = - Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); + Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); return queryFactory - .select( - Projections.constructor( - LabelerDetail.class, - worker.userRole, - worker.name, - worker.employeeNo, - totalCnt, - completeCnt, - skipCnt, - percent, - Expressions.constant(0), // 순위는 Service 레이어에서 계산 - labelingAssignmentEntity.workStatDttm.min(), - inspector.name.min(), - remainCnt)) - .from(worker) - .innerJoin(labelingAssignmentEntity) - .on( - worker.employeeNo.eq(labelingAssignmentEntity.workerUid), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .leftJoin(inspector) - .on(labelingAssignmentEntity.inspectorUid.eq(inspector.employeeNo)) - .where(worker.employeeNo.eq(userId)) - .groupBy(worker.userRole, worker.name, worker.employeeNo) - .fetchOne(); + .select( + Projections.constructor( + LabelerDetail.class, + worker.userRole, + worker.name, + worker.employeeNo, + totalCnt, + completeCnt, + skipCnt, + percent, + Expressions.constant(0), // 순위는 Service 레이어에서 계산 + labelingAssignmentEntity.workStatDttm.min(), + inspector.name.min(), + remainCnt)) + .from(worker) + .innerJoin(labelingAssignmentEntity) + .on( + worker.employeeNo.eq(labelingAssignmentEntity.workerUid), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .leftJoin(inspector) + .on(labelingAssignmentEntity.inspectorUid.eq(inspector.employeeNo)) + .where(worker.employeeNo.eq(userId)) + .groupBy(worker.userRole, worker.name, worker.employeeNo) + .fetchOne(); } - /** - * 특정 회차의 모든 라벨러 통계 조회 (순위 계산용) - */ + /** 특정 회차의 모든 라벨러 통계 조회 (순위 계산용) */ public List findAllLabelersForRanking(Long analUid) { QMemberEntity worker = QMemberEntity.memberEntity; NumberExpression totalCnt = labelingAssignmentEntity.assignmentUid.count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) + .then(1L) + .otherwise((Long) null) + .count(); Expression remainCnt = - Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); + Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); return queryFactory - .select( - Projections.constructor( - LabelerDetail.class, - worker.userRole, - worker.name, - worker.employeeNo, - totalCnt, - completeCnt, - skipCnt, - Expressions.constant(0.0), // percent - Expressions.constant(0), // ranking - labelingAssignmentEntity.workStatDttm.min(), - Expressions.nullExpression(String.class), // ownerName - remainCnt)) - .from(worker) - .innerJoin(labelingAssignmentEntity) - .on( - worker.employeeNo.eq(labelingAssignmentEntity.workerUid), - labelingAssignmentEntity.analUid.eq(analUid)) - .groupBy(worker.userRole, worker.name, worker.employeeNo) - .orderBy(completeCnt.desc()) // 완료 건수 내림차순 - .fetch(); + .select( + Projections.constructor( + LabelerDetail.class, + worker.userRole, + worker.name, + worker.employeeNo, + totalCnt, + completeCnt, + skipCnt, + Expressions.constant(0.0), // percent + Expressions.constant(0), // ranking + labelingAssignmentEntity.workStatDttm.min(), + Expressions.nullExpression(String.class), // ownerName + remainCnt)) + .from(worker) + .innerJoin(labelingAssignmentEntity) + .on( + worker.employeeNo.eq(labelingAssignmentEntity.workerUid), + labelingAssignmentEntity.analUid.eq(analUid)) + .groupBy(worker.userRole, worker.name, worker.employeeNo) + .orderBy(completeCnt.desc()) // 완료 건수 내림차순 + .fetch(); } - /** - * UUID로 analUid 조회 - */ + /** UUID로 analUid 조회 */ @Override public Long findAnalUidByUuid(String uuid) { return queryFactory - .select(mapSheetAnalInferenceEntity.id) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + .select(mapSheetAnalInferenceEntity.id) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); } @Override public Long findMapSheetAnalInferenceUid(UUID uuid) { return queryFactory - .select(mapSheetAnalInferenceEntity.id) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) - .fetchOne(); + .select(mapSheetAnalInferenceEntity.id) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) + .fetchOne(); } @Override public void insertInspector(Long analUid, String inspector) { queryFactory - .insert(labelingInspectorEntity) - .columns( - labelingInspectorEntity.operatorUid, - labelingInspectorEntity.analUid, - labelingInspectorEntity.inspectorUid) - .values(UUID.randomUUID(), analUid, inspector) - .execute(); + .insert(labelingInspectorEntity) + .columns( + labelingInspectorEntity.operatorUid, + labelingInspectorEntity.analUid, + labelingInspectorEntity.inspectorUid) + .values(UUID.randomUUID(), analUid, inspector) + .execute(); em.flush(); em.clear(); @@ -952,19 +947,19 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } var result = - queryFactory - .select( - mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.uuid, - mapSheetAnalInferenceEntity.labelingClosedYn, - mapSheetAnalInferenceEntity.inspectionClosedYn) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.id.eq(analUid)) - .fetchOne(); + queryFactory + .select( + mapSheetAnalInferenceEntity.compareYyyy, + mapSheetAnalInferenceEntity.targetYyyy, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.createdDttm, + mapSheetAnalInferenceEntity.uuid, + mapSheetAnalInferenceEntity.labelingClosedYn, + mapSheetAnalInferenceEntity.inspectionClosedYn) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.id.eq(analUid)) + .fetchOne(); if (result == null) { return null; @@ -981,20 +976,20 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 변화탐지년도 생성 String detectionYear = - (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; + (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; // 회차를 stage 컬럼에서 가져옴 String round = stage != null ? String.valueOf(stage) : null; return ProjectInfo.builder() - .detectionYear(detectionYear) - .stage(round) - .gukyuinApplyDttm(gukyuinApplyDttm) - .startDttm(createdDttm) - .uuid(uuid != null ? uuid.toString() : null) - .labelingClosedYn(labelingClosedYn) - .inspectionClosedYn(inspectionClosedYn) - .build(); + .detectionYear(detectionYear) + .stage(round) + .gukyuinApplyDttm(gukyuinApplyDttm) + .startDttm(createdDttm) + .uuid(uuid != null ? uuid.toString() : null) + .labelingClosedYn(labelingClosedYn) + .inspectionClosedYn(inspectionClosedYn) + .build(); } @Override @@ -1008,19 +1003,19 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // UUID로 프로젝트 정보 조회 var result = - queryFactory - .select( - mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.uuid, - mapSheetAnalInferenceEntity.labelingClosedYn, - mapSheetAnalInferenceEntity.inspectionClosedYn) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) - .fetchOne(); + queryFactory + .select( + mapSheetAnalInferenceEntity.compareYyyy, + mapSheetAnalInferenceEntity.targetYyyy, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.createdDttm, + mapSheetAnalInferenceEntity.uuid, + mapSheetAnalInferenceEntity.labelingClosedYn, + mapSheetAnalInferenceEntity.inspectionClosedYn) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) + .fetchOne(); if (result == null) { return null; @@ -1036,20 +1031,20 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 변화탐지년도 생성 String detectionYear = - (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; + (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; // 회차를 stage 컬럼에서 가져옴 String round = stage != null ? String.valueOf(stage) : null; return ProjectInfo.builder() - .detectionYear(detectionYear) - .stage(round) - .gukyuinApplyDttm(gukyuinApplyDttm) - .startDttm(createdDttm) - .uuid(uuid.toString()) - .labelingClosedYn(labelingClosedYn) - .inspectionClosedYn(inspectionClosedYn) - .build(); + .detectionYear(detectionYear) + .stage(round) + .gukyuinApplyDttm(gukyuinApplyDttm) + .startDttm(createdDttm) + .uuid(uuid.toString()) + .labelingClosedYn(labelingClosedYn) + .inspectionClosedYn(inspectionClosedYn) + .build(); } @Override @@ -1061,19 +1056,19 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto UUID targetUuid = UUID.fromString(uuid); var result = - queryFactory - .select( - mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.uuid, - mapSheetAnalInferenceEntity.labelingClosedYn, - mapSheetAnalInferenceEntity.inspectionClosedYn) - .from(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(targetUuid)) - .fetchOne(); + queryFactory + .select( + mapSheetAnalInferenceEntity.compareYyyy, + mapSheetAnalInferenceEntity.targetYyyy, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.createdDttm, + mapSheetAnalInferenceEntity.uuid, + mapSheetAnalInferenceEntity.labelingClosedYn, + mapSheetAnalInferenceEntity.inspectionClosedYn) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(targetUuid)) + .fetchOne(); if (result == null) { return null; @@ -1088,18 +1083,18 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto String inspectionClosedYn = result.get(mapSheetAnalInferenceEntity.inspectionClosedYn); String detectionYear = - (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; + (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; String round = stage != null ? String.valueOf(stage) : null; return ProjectInfo.builder() - .detectionYear(detectionYear) - .stage(round) - .gukyuinApplyDttm(gukyuinApplyDttm) - .startDttm(createdDttm) - .uuid(uuid) - .labelingClosedYn(labelingClosedYn) - .inspectionClosedYn(inspectionClosedYn) - .build(); + .detectionYear(detectionYear) + .stage(round) + .gukyuinApplyDttm(gukyuinApplyDttm) + .startDttm(createdDttm) + .uuid(uuid) + .labelingClosedYn(labelingClosedYn) + .inspectionClosedYn(inspectionClosedYn) + .build(); } @Override @@ -1108,30 +1103,30 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 1. 작업이 할당된 프로젝트 중 최신 UUID 조회 UUID uuid = - queryFactory - .select(mapSheetAnalInferenceEntity.uuid) - .from(mapSheetAnalInferenceEntity) - .innerJoin(labelingAssignmentEntity) - .on(mapSheetAnalInferenceEntity.id.eq(labelingAssignmentEntity.analUid)) - .where(whereBuilder) - .orderBy( - mapSheetAnalInferenceEntity.compareYyyy.desc(), - mapSheetAnalInferenceEntity.targetYyyy.desc(), - mapSheetAnalInferenceEntity.stage.desc()) - .fetchFirst(); + queryFactory + .select(mapSheetAnalInferenceEntity.uuid) + .from(mapSheetAnalInferenceEntity) + .innerJoin(labelingAssignmentEntity) + .on(mapSheetAnalInferenceEntity.id.eq(labelingAssignmentEntity.analUid)) + .where(whereBuilder) + .orderBy( + mapSheetAnalInferenceEntity.compareYyyy.desc(), + mapSheetAnalInferenceEntity.targetYyyy.desc(), + mapSheetAnalInferenceEntity.stage.desc()) + .fetchFirst(); // 2. 작업이 할당된 프로젝트가 없으면 전체 프로젝트 중 최신 UUID 조회 if (uuid == null) { uuid = - queryFactory - .select(mapSheetAnalInferenceEntity.uuid) - .from(mapSheetAnalInferenceEntity) - .where(whereBuilder) - .orderBy( - mapSheetAnalInferenceEntity.compareYyyy.desc(), - mapSheetAnalInferenceEntity.targetYyyy.desc(), - mapSheetAnalInferenceEntity.stage.desc()) - .fetchFirst(); + queryFactory + .select(mapSheetAnalInferenceEntity.uuid) + .from(mapSheetAnalInferenceEntity) + .where(whereBuilder) + .orderBy( + mapSheetAnalInferenceEntity.compareYyyy.desc(), + mapSheetAnalInferenceEntity.targetYyyy.desc(), + mapSheetAnalInferenceEntity.stage.desc()) + .fetchFirst(); } return uuid; @@ -1139,11 +1134,11 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @Override public Page findLabelerDailyStat( - LabelAllocateDto.searchReq searchReq, String uuid, String userId) { + LabelAllocateDto.searchReq searchReq, String uuid, String userId) { // 날짜 포맷 Expression workDate = - Expressions.stringTemplate( - "TO_CHAR({0}, 'YYYY-MM-DD')", labelingAssignmentEntity.workStatDttm); + Expressions.stringTemplate( + "TO_CHAR({0}, 'YYYY-MM-DD')", labelingAssignmentEntity.workStatDttm); // 날짜별 전체 건수 Expression dailyTotalCnt = Expressions.numberTemplate(Long.class, "COUNT(*)"); @@ -1153,28 +1148,28 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 상태별 카운트 (Postgres FILTER 사용) Expression assignedCnt = - Expressions.numberTemplate( - Long.class, - "COUNT(*) FILTER (WHERE {0} = 'ASSIGNED')", - labelingAssignmentEntity.workState); + Expressions.numberTemplate( + Long.class, + "COUNT(*) FILTER (WHERE {0} = 'ASSIGNED')", + labelingAssignmentEntity.workState); Expression skipCnt = - Expressions.numberTemplate( - Long.class, "COUNT(*) FILTER (WHERE {0} = 'SKIP')", labelingAssignmentEntity.workState); + Expressions.numberTemplate( + Long.class, "COUNT(*) FILTER (WHERE {0} = 'SKIP')", labelingAssignmentEntity.workState); Expression completeCnt = - Expressions.numberTemplate( - Long.class, "COUNT(*) FILTER (WHERE {0} = 'DONE')", labelingAssignmentEntity.workState); + Expressions.numberTemplate( + Long.class, "COUNT(*) FILTER (WHERE {0} = 'DONE')", labelingAssignmentEntity.workState); Expression remainCnt = - Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); + Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); @@ -1182,49 +1177,49 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto Pageable pageable = searchReq.toPageable(); List foundContent = - queryFactory - .select( - Projections.constructor( - LabelingStatDto.class, - workDate, - dailyTotalCnt, - totalCnt, // ⭐ 전체 일자 배정 건수 - assignedCnt, - skipCnt, - completeCnt, - remainCnt)) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.workerUid.eq(userId), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .groupBy(workDate) - .orderBy(labelingAssignmentEntity.workStatDttm.min().asc()) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .fetch(); + queryFactory + .select( + Projections.constructor( + LabelingStatDto.class, + workDate, + dailyTotalCnt, + totalCnt, // ⭐ 전체 일자 배정 건수 + assignedCnt, + skipCnt, + completeCnt, + remainCnt)) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.workerUid.eq(userId), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .groupBy(workDate) + .orderBy(labelingAssignmentEntity.workStatDttm.min().asc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); Long countQuery = - queryFactory - .select(workDate) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.workerUid.eq(userId), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .distinct() - .fetch() - .stream() - .count(); + queryFactory + .select(workDate) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.workerUid.eq(userId), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .distinct() + .fetch() + .stream() + .count(); return new PageImpl<>(foundContent, pageable, countQuery); } @Override public Page findInspectorDailyStat( - LabelAllocateDto.searchReq searchReq, String uuid, String userId) { + LabelAllocateDto.searchReq searchReq, String uuid, String userId) { // 날짜 포맷 Expression workDate = - Expressions.stringTemplate( - "TO_CHAR({0}, 'YYYY-MM-DD')", labelingAssignmentEntity.inspectStatDttm); + Expressions.stringTemplate( + "TO_CHAR({0}, 'YYYY-MM-DD')", labelingAssignmentEntity.inspectStatDttm); // 날짜별 전체 건수 Expression dailyTotalCnt = Expressions.numberTemplate(Long.class, "COUNT(*)"); @@ -1234,32 +1229,32 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 상태별 카운트 (Postgres FILTER 사용) Expression assignedCnt = - Expressions.numberTemplate( - Long.class, - "COUNT(*) FILTER (WHERE {0} = 'UNCONFIRM')", - labelingAssignmentEntity.inspectState); + Expressions.numberTemplate( + Long.class, + "COUNT(*) FILTER (WHERE {0} = 'UNCONFIRM')", + labelingAssignmentEntity.inspectState); Expression skipCnt = - Expressions.numberTemplate( - Long.class, - "COUNT(*) FILTER (WHERE {0} = 'EXCEPT')", - labelingAssignmentEntity.inspectState); + Expressions.numberTemplate( + Long.class, + "COUNT(*) FILTER (WHERE {0} = 'EXCEPT')", + labelingAssignmentEntity.inspectState); Expression completeCnt = - Expressions.numberTemplate( - Long.class, - "COUNT(*) FILTER (WHERE {0} = 'COMPLETE')", - labelingAssignmentEntity.inspectState); + Expressions.numberTemplate( + Long.class, + "COUNT(*) FILTER (WHERE {0} = 'COMPLETE')", + labelingAssignmentEntity.inspectState); Expression remainCnt = - Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); + Expressions.numberTemplate(Long.class, "({0} - {1} - {2})", totalCnt, skipCnt, completeCnt); // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); @@ -1267,38 +1262,38 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto Pageable pageable = searchReq.toPageable(); List foundContent = - queryFactory - .select( - Projections.constructor( - LabelingStatDto.class, - workDate, - dailyTotalCnt, - totalCnt, // ⭐ 전체 일자 배정 건수 - assignedCnt, - skipCnt, - completeCnt, - remainCnt)) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.inspectorUid.eq(userId), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .groupBy(workDate) - .orderBy(labelingAssignmentEntity.inspectStatDttm.min().asc()) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .fetch(); + queryFactory + .select( + Projections.constructor( + LabelingStatDto.class, + workDate, + dailyTotalCnt, + totalCnt, // ⭐ 전체 일자 배정 건수 + assignedCnt, + skipCnt, + completeCnt, + remainCnt)) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.inspectorUid.eq(userId), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .groupBy(workDate) + .orderBy(labelingAssignmentEntity.inspectStatDttm.min().asc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); Long countQuery = - queryFactory - .select(workDate) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.inspectorUid.eq(userId), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .distinct() - .fetch() - .stream() - .count(); + queryFactory + .select(workDate) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.inspectorUid.eq(userId), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .distinct() + .fetch() + .stream() + .count(); return new PageImpl<>(foundContent, pageable, countQuery); } @@ -1306,43 +1301,43 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @Override public LabelerDetail findInspectorDetail(String userId, String uuid) { NumberExpression assignedCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.UNCONFIRM.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.UNCONFIRM.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression percent = - new CaseBuilder() - .when(completeCnt.eq(0L)) - .then(0.0) - .otherwise( - Expressions.numberTemplate( - Double.class, - "round({0} / {1}, 2)", - completeCnt, - labelingAssignmentEntity.count())); + new CaseBuilder() + .when(completeCnt.eq(0L)) + .then(0.0) + .otherwise( + Expressions.numberTemplate( + Double.class, + "round({0} / {1}, 2)", + completeCnt, + labelingAssignmentEntity.count())); // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); @@ -1353,90 +1348,88 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // remainCnt Expression remainCnt = - Expressions.numberTemplate( - Long.class, "({0} - {1} - {2})", assignedCnt, skipCnt, completeCnt); + Expressions.numberTemplate( + Long.class, "({0} - {1} - {2})", assignedCnt, skipCnt, completeCnt); return queryFactory - .select( - Projections.constructor( - LabelerDetail.class, - inspector.userRole, - inspector.name, - inspector.employeeNo, - assignedCnt, // count (총 배정 건수) - completeCnt, // completeCnt (완료 건수) - skipCnt, // skipCnt (스킵 건수) - percent, - Expressions.constant(0), // 순위는 Service 레이어에서 계산 - labelingAssignmentEntity.inspectStatDttm.min(), - worker.name.min(), - remainCnt)) - .from(inspector) - .innerJoin(labelingAssignmentEntity) - .on( - inspector.employeeNo.eq(labelingAssignmentEntity.inspectorUid), - labelingAssignmentEntity.analUid.eq(analEntity.getId())) - .leftJoin(worker) - .on(labelingAssignmentEntity.workerUid.eq(worker.employeeNo)) - .where(inspector.employeeNo.eq(userId)) - .groupBy(inspector.userRole, inspector.name, inspector.employeeNo) - .fetchOne(); + .select( + Projections.constructor( + LabelerDetail.class, + inspector.userRole, + inspector.name, + inspector.employeeNo, + assignedCnt, // count (총 배정 건수) + completeCnt, // completeCnt (완료 건수) + skipCnt, // skipCnt (스킵 건수) + percent, + Expressions.constant(0), // 순위는 Service 레이어에서 계산 + labelingAssignmentEntity.inspectStatDttm.min(), + worker.name.min(), + remainCnt)) + .from(inspector) + .innerJoin(labelingAssignmentEntity) + .on( + inspector.employeeNo.eq(labelingAssignmentEntity.inspectorUid), + labelingAssignmentEntity.analUid.eq(analEntity.getId())) + .leftJoin(worker) + .on(labelingAssignmentEntity.workerUid.eq(worker.employeeNo)) + .where(inspector.employeeNo.eq(userId)) + .groupBy(inspector.userRole, inspector.name, inspector.employeeNo) + .fetchOne(); } - /** - * 순위 계산용 - 특정 회차의 모든 검수자 통계 조회 - */ + /** 순위 계산용 - 특정 회차의 모든 검수자 통계 조회 */ public List findAllInspectorsForRanking(Long analUid) { QMemberEntity inspector = QMemberEntity.memberEntity; NumberExpression assignedCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.UNCONFIRM.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.UNCONFIRM.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); Expression remainCnt = - Expressions.numberTemplate( - Long.class, "({0} - {1} - {2})", assignedCnt, skipCnt, completeCnt); + Expressions.numberTemplate( + Long.class, "({0} - {1} - {2})", assignedCnt, skipCnt, completeCnt); return queryFactory - .select( - Projections.constructor( - LabelerDetail.class, - inspector.userRole, - inspector.name, - inspector.employeeNo, - assignedCnt, // count (총 배정 건수) - completeCnt, // completeCnt (완료 건수) - skipCnt, // skipCnt (스킵 건수) - Expressions.constant(0.0), // percent - Expressions.constant(0), // ranking - labelingAssignmentEntity.inspectStatDttm.min(), - Expressions.nullExpression(String.class), // ownerName - remainCnt)) - .from(inspector) - .innerJoin(labelingAssignmentEntity) - .on( - inspector.employeeNo.eq(labelingAssignmentEntity.inspectorUid), - labelingAssignmentEntity.analUid.eq(analUid)) - .groupBy(inspector.userRole, inspector.name, inspector.employeeNo) - .orderBy(completeCnt.desc()) // 완료 건수 내림차순 - .fetch(); + .select( + Projections.constructor( + LabelerDetail.class, + inspector.userRole, + inspector.name, + inspector.employeeNo, + assignedCnt, // count (총 배정 건수) + completeCnt, // completeCnt (완료 건수) + skipCnt, // skipCnt (스킵 건수) + Expressions.constant(0.0), // percent + Expressions.constant(0), // ranking + labelingAssignmentEntity.inspectStatDttm.min(), + Expressions.nullExpression(String.class), // ownerName + remainCnt)) + .from(inspector) + .innerJoin(labelingAssignmentEntity) + .on( + inspector.employeeNo.eq(labelingAssignmentEntity.inspectorUid), + labelingAssignmentEntity.analUid.eq(analUid)) + .groupBy(inspector.userRole, inspector.name, inspector.employeeNo) + .orderBy(completeCnt.desc()) // 완료 건수 내림차순 + .fetch(); } @Override @@ -1444,79 +1437,79 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto NumberExpression totalCnt = labelingAssignmentEntity.count(); NumberExpression completeCnt = - new CaseBuilder() - .when( - labelingAssignmentEntity - .workState - .eq(LabelState.DONE.getId()) - .or(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId()))) - .then(1L) - .otherwise(0L) - .sum(); + new CaseBuilder() + .when( + labelingAssignmentEntity + .workState + .eq(LabelState.DONE.getId()) + .or(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId()))) + .then(1L) + .otherwise(0L) + .sum(); NumberExpression percent = - new CaseBuilder() - .when(completeCnt.eq(0L)) - .then(0.0) - .otherwise( - Expressions.numberTemplate( - Double.class, - "round(({0} * 100.0) / nullif({1}, 0), 2)", - completeCnt, - totalCnt)); + new CaseBuilder() + .when(completeCnt.eq(0L)) + .then(0.0) + .otherwise( + Expressions.numberTemplate( + Double.class, + "round(({0} * 100.0) / nullif({1}, 0), 2)", + completeCnt, + totalCnt)); // remainCnt Expression remainCnt = totalCnt.subtract(completeCnt); // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); } Long userChargeCnt = - queryFactory - .select(labelingAssignmentEntity.inferenceGeomUid.count()) - .from(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.analUid.eq(analEntity.getId()), - labelingAssignmentEntity.workerUid.eq(userId), - labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId())) - .fetchOne(); + queryFactory + .select(labelingAssignmentEntity.inferenceGeomUid.count()) + .from(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.analUid.eq(analEntity.getId()), + labelingAssignmentEntity.workerUid.eq(userId), + labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId())) + .fetchOne(); List list = - queryFactory - .select( - Projections.constructor( - MoveUserList.class, - memberEntity.userRole, - memberEntity.employeeNo, - memberEntity.name, - remainCnt, - percent)) - .from(labelingAssignmentEntity) - .innerJoin(memberEntity) - .on( - labelingAssignmentEntity.workerUid.eq(memberEntity.employeeNo), - memberEntity.status.eq(StatusType.ACTIVE.getId())) - .where( - labelingAssignmentEntity.analUid.eq(analEntity.getId()), - labelingAssignmentEntity.workerUid.ne(userId)) - .groupBy(memberEntity.userRole, memberEntity.employeeNo, memberEntity.name) - .having( - completeCnt - .multiply(2) - .goe(totalCnt)) // 진행률 평균 이상인 것들만 조회 => percent 를 바로 쓰면 having절에 무리가 갈 수 있다고 함 - .orderBy( - completeCnt - .desc()) // TODO: 현재는 잔여건수가 제일 적은(=완료건수가 높은) 순서로 desc, 추후 도엽번호? PNU? 로 정렬하여 - // 보여주기? - .fetch(); + queryFactory + .select( + Projections.constructor( + MoveUserList.class, + memberEntity.userRole, + memberEntity.employeeNo, + memberEntity.name, + remainCnt, + percent)) + .from(labelingAssignmentEntity) + .innerJoin(memberEntity) + .on( + labelingAssignmentEntity.workerUid.eq(memberEntity.employeeNo), + memberEntity.status.eq(StatusType.ACTIVE.getId())) + .where( + labelingAssignmentEntity.analUid.eq(analEntity.getId()), + labelingAssignmentEntity.workerUid.ne(userId)) + .groupBy(memberEntity.userRole, memberEntity.employeeNo, memberEntity.name) + .having( + completeCnt + .multiply(2) + .goe(totalCnt)) // 진행률 평균 이상인 것들만 조회 => percent 를 바로 쓰면 having절에 무리가 갈 수 있다고 함 + .orderBy( + completeCnt + .desc()) // TODO: 현재는 잔여건수가 제일 적은(=완료건수가 높은) 순서로 desc, 추후 도엽번호? PNU? 로 정렬하여 + // 보여주기? + .fetch(); return new MoveInfo(userChargeCnt, list); } @@ -1524,39 +1517,39 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @Override public void insertLabelerUser(Long analUid, String userId, int demand) { queryFactory - .insert(labelingLabelerEntity) - .columns( - labelingLabelerEntity.lbUsrUid, - labelingLabelerEntity.analUid, - labelingLabelerEntity.workerUid, - labelingLabelerEntity.allocateCnt) - .values(UUID.randomUUID(), analUid, userId, demand) - .execute(); + .insert(labelingLabelerEntity) + .columns( + labelingLabelerEntity.lbUsrUid, + labelingLabelerEntity.analUid, + labelingLabelerEntity.workerUid, + labelingLabelerEntity.allocateCnt) + .values(UUID.randomUUID(), analUid, userId, demand) + .execute(); } @Override public void assignOwnerReAllocate( - String uuid, String userId, String paramUserId, Long assignCount) { + String uuid, String userId, String paramUserId, Long assignCount) { // analUid로 분석 정보 조회 MapSheetAnalInferenceEntity analEntity = - queryFactory - .selectFrom(mapSheetAnalInferenceEntity) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .fetchOne(); + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .fetchOne(); if (Objects.isNull(analEntity)) { throw new EntityNotFoundException("MapSheetAnalInferenceEntity not found for analUid: "); } queryFactory - .update(labelingLabelerEntity) - .set(labelingLabelerEntity.reAllocateYn, true) - .set(labelingLabelerEntity.reAllocateWorkerUid, userId) - .set(labelingLabelerEntity.reAllocateCnt, assignCount) - .where( - labelingLabelerEntity.analUid.eq(analEntity.getId()), - labelingLabelerEntity.workerUid.eq(paramUserId)) - .execute(); + .update(labelingLabelerEntity) + .set(labelingLabelerEntity.reAllocateYn, true) + .set(labelingLabelerEntity.reAllocateWorkerUid, userId) + .set(labelingLabelerEntity.reAllocateCnt, assignCount) + .where( + labelingLabelerEntity.analUid.eq(analEntity.getId()), + labelingLabelerEntity.workerUid.eq(paramUserId)) + .execute(); } @Override @@ -1569,85 +1562,85 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto updateQuery.set(mapSheetAnalInferenceEntity.inspectionClosedYn, closedYn); } else if ("BOTH".equals(closedType)) { updateQuery - .set(mapSheetAnalInferenceEntity.labelingClosedYn, closedYn) - .set(mapSheetAnalInferenceEntity.inspectionClosedYn, closedYn); + .set(mapSheetAnalInferenceEntity.labelingClosedYn, closedYn) + .set(mapSheetAnalInferenceEntity.inspectionClosedYn, closedYn); } updateQuery - .set(mapSheetAnalInferenceEntity.updatedDttm, ZonedDateTime.now()) - .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) - .execute(); + .set(mapSheetAnalInferenceEntity.updatedDttm, ZonedDateTime.now()) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .execute(); em.flush(); em.clear(); } public Page workLabelHistoryList( - LabelAllocateDto.searchReq searchReq, String userId) { + LabelAllocateDto.searchReq searchReq, String userId) { NumberExpression totalCnt = labelingAssignmentEntity.assignmentUid.count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); Pageable pageable = searchReq.toPageable(); List list = - queryFactory - .select( - Projections.bean( - WorkHistoryDto.class, - Expressions.stringTemplate( - "concat({0}, '-', {1})", + queryFactory + .select( + Projections.bean( + WorkHistoryDto.class, + Expressions.stringTemplate( + "concat({0}, '-', {1})", + mapSheetAnalInferenceEntity.compareYyyy, + mapSheetAnalInferenceEntity.targetYyyy) + .as("changeDetectionYear"), + mapSheetAnalInferenceEntity.stage.longValue().as("stage"), + mapSheetAnalInferenceEntity.gukyuinApplyDttm.as("gukyuinApplyDttm"), + totalCnt.as("assignedCnt"), + completeCnt.as("completeCnt"), + skipCnt.as("skipCnt"), + mapSheetAnalInferenceEntity.createdDttm.as("createdDttm"), + new CaseBuilder() + .when(mapSheetAnalInferenceEntity.inspectionClosedYn.eq("Y")) + .then(mapSheetAnalInferenceEntity.updatedDttm) + .otherwise((ZonedDateTime) null) + .as("projectCloseDttm"))) + .from(labelingAssignmentEntity) + .innerJoin(mapSheetAnalInferenceEntity) + .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) + .where(labelingAssignmentEntity.workerUid.eq(userId)) + .groupBy( + mapSheetAnalInferenceEntity.id, mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy) - .as("changeDetectionYear"), - mapSheetAnalInferenceEntity.stage.longValue().as("stage"), - mapSheetAnalInferenceEntity.gukyuinApplyDttm.as("gukyuinApplyDttm"), - totalCnt.as("assignedCnt"), - completeCnt.as("completeCnt"), - skipCnt.as("skipCnt"), - mapSheetAnalInferenceEntity.createdDttm.as("createdDttm"), - new CaseBuilder() - .when(mapSheetAnalInferenceEntity.inspectionClosedYn.eq("Y")) - .then(mapSheetAnalInferenceEntity.updatedDttm) - .otherwise((ZonedDateTime) null) - .as("projectCloseDttm"))) - .from(labelingAssignmentEntity) - .innerJoin(mapSheetAnalInferenceEntity) - .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) - .where(labelingAssignmentEntity.workerUid.eq(userId)) - .groupBy( - mapSheetAnalInferenceEntity.id, - mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.inspectionClosedYn, - mapSheetAnalInferenceEntity.updatedDttm) - .orderBy( - // 진행중인 작업이 최상단 (remainCnt > 0) - new CaseBuilder() - .when(totalCnt.subtract(completeCnt).subtract(skipCnt).gt(0L)) - .then(0) - .otherwise(1) - .asc(), - // 최신 작업순 (반영일 기준) - mapSheetAnalInferenceEntity.gukyuinApplyDttm.desc()) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .fetch(); + mapSheetAnalInferenceEntity.targetYyyy, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.createdDttm, + mapSheetAnalInferenceEntity.inspectionClosedYn, + mapSheetAnalInferenceEntity.updatedDttm) + .orderBy( + // 진행중인 작업이 최상단 (remainCnt > 0) + new CaseBuilder() + .when(totalCnt.subtract(completeCnt).subtract(skipCnt).gt(0L)) + .then(0) + .otherwise(1) + .asc(), + // 최신 작업순 (반영일 기준) + mapSheetAnalInferenceEntity.gukyuinApplyDttm.desc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); // rowNum, remainCnt, percent, status를 Java에서 계산 int startRow = (int) pageable.getOffset() + 1; @@ -1677,13 +1670,13 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } Long countQuery = - queryFactory - .select(mapSheetAnalInferenceEntity.id.countDistinct()) - .from(labelingAssignmentEntity) - .innerJoin(mapSheetAnalInferenceEntity) - .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) - .where(labelingAssignmentEntity.workerUid.eq(userId)) - .fetchOne(); + queryFactory + .select(mapSheetAnalInferenceEntity.id.countDistinct()) + .from(labelingAssignmentEntity) + .innerJoin(mapSheetAnalInferenceEntity) + .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) + .where(labelingAssignmentEntity.workerUid.eq(userId)) + .fetchOne(); return new PageImpl<>(list, pageable, countQuery != null ? countQuery : 0L); } @@ -1694,66 +1687,66 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto NumberExpression totalCnt = labelingAssignmentEntity.assignmentUid.count(); NumberExpression skipCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId())) + .then(1L) + .otherwise((Long) null) + .count(); NumberExpression completeCnt = - new CaseBuilder() - .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) - .then(1L) - .otherwise((Long) null) - .count(); + new CaseBuilder() + .when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId())) + .then(1L) + .otherwise((Long) null) + .count(); Pageable pageable = searchReq.toPageable(); List list = - queryFactory - .select( - Projections.bean( - WorkHistoryDto.class, - Expressions.stringTemplate( - "concat({0}, '-', {1})", + queryFactory + .select( + Projections.bean( + WorkHistoryDto.class, + Expressions.stringTemplate( + "concat({0}, '-', {1})", + mapSheetAnalInferenceEntity.compareYyyy, + mapSheetAnalInferenceEntity.targetYyyy) + .as("changeDetectionYear"), + mapSheetAnalInferenceEntity.stage.longValue().as("stage"), + mapSheetAnalInferenceEntity.gukyuinApplyDttm.as("gukyuinApplyDttm"), + totalCnt.as("assignedCnt"), + completeCnt.as("completeCnt"), + skipCnt.as("skipCnt"), + mapSheetAnalInferenceEntity.createdDttm.as("createdDttm"), + new CaseBuilder() + .when(mapSheetAnalInferenceEntity.inspectionClosedYn.eq("Y")) + .then(mapSheetAnalInferenceEntity.updatedDttm) + .otherwise((ZonedDateTime) null) + .as("projectCloseDttm"))) + .from(labelingAssignmentEntity) + .innerJoin(mapSheetAnalInferenceEntity) + .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) + .where(labelingAssignmentEntity.inspectorUid.eq(userId)) + .groupBy( + mapSheetAnalInferenceEntity.id, mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy) - .as("changeDetectionYear"), - mapSheetAnalInferenceEntity.stage.longValue().as("stage"), - mapSheetAnalInferenceEntity.gukyuinApplyDttm.as("gukyuinApplyDttm"), - totalCnt.as("assignedCnt"), - completeCnt.as("completeCnt"), - skipCnt.as("skipCnt"), - mapSheetAnalInferenceEntity.createdDttm.as("createdDttm"), - new CaseBuilder() - .when(mapSheetAnalInferenceEntity.inspectionClosedYn.eq("Y")) - .then(mapSheetAnalInferenceEntity.updatedDttm) - .otherwise((ZonedDateTime) null) - .as("projectCloseDttm"))) - .from(labelingAssignmentEntity) - .innerJoin(mapSheetAnalInferenceEntity) - .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) - .where(labelingAssignmentEntity.inspectorUid.eq(userId)) - .groupBy( - mapSheetAnalInferenceEntity.id, - mapSheetAnalInferenceEntity.compareYyyy, - mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.stage, - mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.inspectionClosedYn, - mapSheetAnalInferenceEntity.updatedDttm) - .orderBy( - // 진행중인 작업이 최상단 (remainCnt > 0) - new CaseBuilder() - .when(totalCnt.subtract(completeCnt).subtract(skipCnt).gt(0L)) - .then(0) - .otherwise(1) - .asc(), - // 최신 작업순 (반영일 기준) - mapSheetAnalInferenceEntity.gukyuinApplyDttm.desc()) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .fetch(); + mapSheetAnalInferenceEntity.targetYyyy, + mapSheetAnalInferenceEntity.stage, + mapSheetAnalInferenceEntity.gukyuinApplyDttm, + mapSheetAnalInferenceEntity.createdDttm, + mapSheetAnalInferenceEntity.inspectionClosedYn, + mapSheetAnalInferenceEntity.updatedDttm) + .orderBy( + // 진행중인 작업이 최상단 (remainCnt > 0) + new CaseBuilder() + .when(totalCnt.subtract(completeCnt).subtract(skipCnt).gt(0L)) + .then(0) + .otherwise(1) + .asc(), + // 최신 작업순 (반영일 기준) + mapSheetAnalInferenceEntity.gukyuinApplyDttm.desc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); // rowNum, remainCnt, percent, status를 Java에서 계산 int startRow = (int) pageable.getOffset() + 1; @@ -1783,13 +1776,13 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } Long countQuery = - queryFactory - .select(mapSheetAnalInferenceEntity.id.countDistinct()) - .from(labelingAssignmentEntity) - .innerJoin(mapSheetAnalInferenceEntity) - .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) - .where(labelingAssignmentEntity.inspectorUid.eq(userId)) - .fetchOne(); + queryFactory + .select(mapSheetAnalInferenceEntity.id.countDistinct()) + .from(labelingAssignmentEntity) + .innerJoin(mapSheetAnalInferenceEntity) + .on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) + .where(labelingAssignmentEntity.inspectorUid.eq(userId)) + .fetchOne(); return new PageImpl<>(list, pageable, countQuery != null ? countQuery : 0L); } @@ -1797,20 +1790,19 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @Override public void updateAnalInferenceMngState(UUID uuid, String status) { queryFactory - .update(mapSheetAnalInferenceEntity) - .set(mapSheetAnalInferenceEntity.analState, status) - .set(mapSheetAnalInferenceEntity.updatedDttm, ZonedDateTime.now()) - .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) - .execute(); + .update(mapSheetAnalInferenceEntity) + .set(mapSheetAnalInferenceEntity.analState, status) + .set(mapSheetAnalInferenceEntity.updatedDttm, ZonedDateTime.now()) + .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) + .execute(); } @Override public Long findLabelingIngProcessCnt() { return queryFactory - .select(mapSheetAnalInferenceEntity.id.count()) - .from(mapSheetAnalInferenceEntity) - .where( - mapSheetAnalInferenceEntity.analState.eq(LabelMngState.ING.getId())) - .fetchOne(); + .select(mapSheetAnalInferenceEntity.id.count()) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.analState.eq(LabelMngState.ING.getId())) + .fetchOne(); } }