From 7471322664172ed82a324cc72f1747e9de4dec1d Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 20 Jan 2026 10:17:06 +0900 Subject: [PATCH 01/20] =?UTF-8?q?=EC=B6=94=EB=A1=A0=EC=A7=84=ED=96=89=20?= =?UTF-8?q?=EB=B0=B0=EC=B9=98=20=EC=8B=9C=EA=B0=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cd/kamcoback/mapsheet/service/MapSheetMngService.java | 3 ++- .../scheduler/service/MapSheetInferenceJobService.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java index fba8c0d9..15d57ae6 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java @@ -350,7 +350,8 @@ public class MapSheetMngService { List mngList = mapSheetMngCoreService.findMapSheetMngList(); List yearList = mngList.stream() - .filter(dto -> "DONE".equals(dto.getMngState()) || "TAKINGERROR".equals(dto.getMngState())) + .filter( + dto -> "DONE".equals(dto.getMngState()) || "TAKINGERROR".equals(dto.getMngState())) .map(dto -> new MngYyyyDto(dto.getMngYyyy(), dto.getMngPath())) .toList(); diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java index bc4e1cf7..27ac1cf2 100644 --- a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java @@ -53,8 +53,8 @@ public class MapSheetInferenceJobService { @Value("${inference.jar-path}") private String jarPath; - /** 추론 진행 배치 1분 */ - @Scheduled(fixedDelay = 60_000) + /** 추론 진행 배치 1분 60_000 */ + @Scheduled(fixedDelay = 30_000) public void runBatch() { if (isLocalProfile()) { return; From 9090c94611fc0533b8937580ea21ef1c871130bf Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 10:19:41 +0900 Subject: [PATCH 02/20] =?UTF-8?q?=EB=9D=BC=EB=B2=A8=EB=A7=81=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=ED=95=A0=EB=8B=B9=20stage=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../label/LabelAllocateApiController.java | 2 +- .../kamcoback/label/dto/LabelAllocateDto.java | 8 +++- .../label/service/LabelAllocateService.java | 14 +++---- .../core/LabelAllocateCoreService.java | 13 +++---- .../label/LabelAllocateRepositoryCustom.java | 7 ++-- .../label/LabelAllocateRepositoryImpl.java | 39 ++++++++++--------- .../label/LabelWorkRepositoryImpl.java | 4 +- 7 files changed, 46 insertions(+), 41 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 040c0e96..ffdca9fd 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java @@ -123,7 +123,7 @@ public class LabelAllocateApiController { int targetYyyy = Integer.parseInt(dto.getYyyy().split("-")[1]); return ApiResponseDto.okObject( labelAllocateService.allocateAsc( - dto.getStage(), dto.getLabelers(), dto.getInspectors(), compareYyyy, targetYyyy)); + dto.getUuid(), dto.getLabelers(), dto.getInspectors(), compareYyyy, targetYyyy)); } @Operation(summary = "작업현황 관리 > 변화탐지 회차 정보", description = "작업현황 관리 > 변화탐지 회차 정보") diff --git a/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java index fef1c33e..f07f34ca 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java @@ -86,6 +86,12 @@ public class LabelAllocateDto { @AllArgsConstructor public static class AllocateDto { + @Schema( + description = "회차 마스터 key", + example = "f97dc186-e6d3-4645-9737-3173dde8dc64", + required = true) + private UUID uuid; + @Schema(description = "비교년도-기준년도", example = "2022-2024", required = true) private String yyyy; @@ -95,7 +101,7 @@ public class LabelAllocateDto { // @Schema(description = "기준년도", example = "2024", required = true) // private Integer targetYyyy; - @Schema(description = "회차", example = "4", required = true) + @Schema(description = "회차", example = "4") private Integer stage; @Schema( 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 3b070eb6..594972fe 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 @@ -18,6 +18,7 @@ import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerListResponse; import com.kamco.cd.kamcoback.postgres.core.LabelAllocateCoreService; import java.util.List; import java.util.Objects; +import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; @@ -37,13 +38,13 @@ public class LabelAllocateService { /** * 도엽 기준 asc sorting 해서 할당 수만큼 배정하는 로직 * - * @param stage 회차 + * @param uuid 회차 key * @param targetUsers 라벨러 목록 * @param targetInspectors 검수자 목록 */ @Transactional public ApiResponseDto.ResponseObj allocateAsc( - Integer stage, + UUID uuid, List targetUsers, List targetInspectors, Integer compareYyyy, @@ -51,8 +52,7 @@ public class LabelAllocateService { Long lastId = null; // geom 잔여건수 조회 - Long chargeCnt = - labelAllocateCoreService.findLabelUnAssignedCnt(stage, compareYyyy, targetYyyy); + Long chargeCnt = labelAllocateCoreService.findLabelUnAssignedCnt(uuid); if (chargeCnt <= 0) { return new ApiResponseDto.ResponseObj(ApiResponseCode.DUPLICATE_DATA, "이미 배정완료된 회차 입니다."); } @@ -63,12 +63,10 @@ public class LabelAllocateService { ApiResponseCode.BAD_REQUEST, "총 잔여건수와 요청 값의 합계가 맞지 않습니다."); } - List allIds = - labelAllocateCoreService.fetchNextIds(lastId, chargeCnt, compareYyyy, targetYyyy, stage); + List allIds = labelAllocateCoreService.fetchNextIds(lastId, chargeCnt, uuid); // MapSheetAnalInferenceEntity analUid 가져오기 - Long analUid = - labelAllocateCoreService.findMapSheetAnalInferenceUid(compareYyyy, targetYyyy, stage); + Long analUid = labelAllocateCoreService.findMapSheetAnalInferenceUid(uuid); int index = 0; for (TargetUser target : targetUsers) { 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 a5cd7f07..02073b62 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 @@ -27,9 +27,8 @@ public class LabelAllocateCoreService { private final LabelAllocateRepository labelAllocateRepository; - public List fetchNextIds( - Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) { - return labelAllocateRepository.fetchNextIds(lastId, batchSize, compareYyyy, targetYyyy, stage); + public List fetchNextIds(Long lastId, Long batchSize, UUID uuid) { + return labelAllocateRepository.fetchNextIds(lastId, batchSize, uuid); } public void assignOwner(List ids, String userId, Long analUid) { @@ -42,8 +41,8 @@ public class LabelAllocateCoreService { .toList(); } - public Long findLabelUnAssignedCnt(Integer stage, Integer compareYyyy, Integer targetYyyy) { - return labelAllocateRepository.findLabelUnAssignedCnt(stage, compareYyyy, targetYyyy); + public Long findLabelUnAssignedCnt(UUID uuid) { + return labelAllocateRepository.findLabelUnAssignedCnt(uuid); } public void assignInspector(UUID assignmentUid, String inspectorUid) { @@ -144,8 +143,8 @@ public class LabelAllocateCoreService { return detail; } - public Long findMapSheetAnalInferenceUid(Integer compareYyyy, Integer targetYyyy, Integer stage) { - return labelAllocateRepository.findMapSheetAnalInferenceUid(compareYyyy, targetYyyy, stage); + public Long findMapSheetAnalInferenceUid(UUID uuid) { + return labelAllocateRepository.findMapSheetAnalInferenceUid(uuid); } public void insertInspector(Long analUid, String inspector) { 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 bc05fe58..478c1613 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 @@ -20,14 +20,13 @@ import org.springframework.data.domain.Page; public interface LabelAllocateRepositoryCustom { - List fetchNextIds( - Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage); + List fetchNextIds(Long lastId, Long batchSize, UUID uuid); void assignOwner(List ids, String userId, Long analUid); List findAssignedLabelerList(Long analUid); - Long findLabelUnAssignedCnt(Integer stage, Integer compareYyyy, Integer targetYyyy); + Long findLabelUnAssignedCnt(UUID uuid); void assignInspector(UUID assignmentUid, String userId); @@ -74,7 +73,7 @@ public interface LabelAllocateRepositoryCustom { /** UUID로 analUid 조회 */ Long findAnalUidByUuid(String uuid); - Long findMapSheetAnalInferenceUid(Integer compareYyyy, Integer targetYyyy, Integer stage); + Long findMapSheetAnalInferenceUid(UUID uuid); void insertInspector(Long analUid, String inspector); 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 c340eb55..040dfcf7 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 @@ -66,8 +66,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @PersistenceContext private EntityManager em; @Override - public List fetchNextIds( - Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) { + public List fetchNextIds(Long lastId, Long batchSize, UUID uuid) { return queryFactory .select( @@ -76,14 +75,17 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto mapSheetAnalDataInferenceGeomEntity.geoUid, mapSheetAnalDataInferenceGeomEntity.mapSheetNum, mapSheetAnalDataInferenceGeomEntity.pnu)) - .from(mapSheetAnalDataInferenceGeomEntity) - .where( - lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId), + .from(mapSheetAnalInferenceEntity) + .innerJoin(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) + .innerJoin(mapSheetAnalDataInferenceGeomEntity) + .on( + mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid), mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), - mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(compareYyyy), - mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(targetYyyy), - mapSheetAnalDataInferenceGeomEntity.stage.eq(stage), mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) + .where( + mapSheetAnalInferenceEntity.uuid.eq(uuid), + lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId)) .orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc()) .limit(batchSize) .fetch(); @@ -177,17 +179,19 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } @Override - public Long findLabelUnAssignedCnt(Integer stage, Integer compareYyyy, Integer targetYyyy) { + public Long findLabelUnAssignedCnt(UUID uuid) { return queryFactory .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) - .from(mapSheetAnalDataInferenceGeomEntity) - .where( + .from(mapSheetAnalInferenceEntity) + .innerJoin(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) + .innerJoin(mapSheetAnalDataInferenceGeomEntity) + .on( + mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid), mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), - mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(compareYyyy), - mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(targetYyyy), - mapSheetAnalDataInferenceGeomEntity.stage.eq(stage), mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) + .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) .fetchOne(); } @@ -912,14 +916,11 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } @Override - public Long findMapSheetAnalInferenceUid(Integer compareYyyy, Integer targetYyyy, Integer stage) { + public Long findMapSheetAnalInferenceUid(UUID uuid) { return queryFactory .select(mapSheetAnalInferenceEntity.id) .from(mapSheetAnalInferenceEntity) - .where( - mapSheetAnalInferenceEntity.compareYyyy.eq(compareYyyy), - mapSheetAnalInferenceEntity.targetYyyy.eq(targetYyyy), - mapSheetAnalInferenceEntity.stage.eq(stage)) + .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) .fetchOne(); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java index 99bcb8ae..03aacd43 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java @@ -138,7 +138,9 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom { mapSheetAnalDataInferenceGeomEntity .pnu .isNotNull() - .and(mapSheetAnalDataInferenceGeomEntity.pnu.ne(0L)) + .and( + mapSheetAnalDataInferenceGeomEntity.pnu + .isNotNull()) // TODO: 이노팸 연동 후 0 이상이라고 해야할 듯 .and(mapSheetAnalDataInferenceGeomEntity.passYn.eq(Boolean.FALSE))) .then(1L) .otherwise(0L) From d4b4ffc5e99f1a6c2f70eebafa089e0eeffca726 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 10:55:40 +0900 Subject: [PATCH 03/20] =?UTF-8?q?=EB=B3=80=ED=99=94=ED=83=90=EC=A7=80=20CO?= =?UTF-8?q?G=20URL=20API=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChangeDetectionApiController.java | 7 +++++- .../dto/ChangeDetectionDto.java | 1 + .../ChangeDetectionRepositoryImpl.java | 24 ++++++++++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/changedetection/ChangeDetectionApiController.java b/src/main/java/com/kamco/cd/kamcoback/changedetection/ChangeDetectionApiController.java index be9cdeb0..e674655f 100644 --- a/src/main/java/com/kamco/cd/kamcoback/changedetection/ChangeDetectionApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/changedetection/ChangeDetectionApiController.java @@ -74,11 +74,16 @@ public class ChangeDetectionApiController { @Parameter(description = "5k/50k 구분(SCALE_5K/SCALE_50K))", required = true) @RequestParam(defaultValue = "SCALE_50K") MapScaleType scale, + @Parameter( + description = "변화탐지 년도(차수) /year-list 의 uuid", + example = "8584e8d4-53b3-4582-bde2-28a81495a626") + @RequestParam + UUID uuid, @Parameter(description = "이전 년도", example = "2023") @RequestParam Integer beforeYear, @Parameter(description = "이후 년도", example = "2024") @RequestParam Integer afterYear, @Parameter(description = "도엽번호(5k)", example = "35905086") @RequestParam String mapSheetNum) { ChangeDetectionDto.CogUrlReq req = - new ChangeDetectionDto.CogUrlReq(beforeYear, afterYear, mapSheetNum, type, scale); + new ChangeDetectionDto.CogUrlReq(uuid, beforeYear, afterYear, mapSheetNum, type, scale); return ApiResponseDto.ok(changeDetectionService.getChangeDetectionCogUrl(req)); } diff --git a/src/main/java/com/kamco/cd/kamcoback/changedetection/dto/ChangeDetectionDto.java b/src/main/java/com/kamco/cd/kamcoback/changedetection/dto/ChangeDetectionDto.java index fb5953f9..a82113bf 100644 --- a/src/main/java/com/kamco/cd/kamcoback/changedetection/dto/ChangeDetectionDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/changedetection/dto/ChangeDetectionDto.java @@ -86,6 +86,7 @@ public class ChangeDetectionDto { @AllArgsConstructor public static class CogUrlReq { + private UUID uuid; private Integer beforeYear; private Integer afterYear; private String mapSheetNum; diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java index 4c8191a7..890a5c4d 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto; +import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.DetectSearchType; import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.MapScaleType; import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto.MapSheetList; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataInferenceGeomEntity; @@ -111,6 +112,26 @@ public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport @Override public ChangeDetectionDto.CogUrlDto getChangeDetectionCogUrl(ChangeDetectionDto.CogUrlReq req) { + String mapSheetNum = req.getMapSheetNum(); + + if (req.getType().equals(DetectSearchType.MAPSHEET) + && req.getScale().equals(MapScaleType.SCALE_50K)) { + mapSheetNum = + queryFactory + .select(mapSheetAnalDataInferenceEntity.mapSheetNum.stringValue()) + .from(mapSheetAnalInferenceEntity) + .innerJoin(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid)) + .where( + mapSheetAnalInferenceEntity.uuid.eq(req.getUuid()), + mapSheetAnalDataInferenceEntity + .mapSheetNum + .stringValue() + .like("%" + req.getMapSheetNum() + "%")) + .orderBy(mapSheetAnalDataInferenceEntity.mapSheetNum.asc()) + .fetchFirst(); + } + ChangeDetectionDto.CogUrlData data = queryFactory .select( @@ -128,7 +149,7 @@ public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport .year .eq(req.getBeforeYear()) .or(imageryEntity.year.eq(req.getAfterYear())), - imageryEntity.scene5k.eq(req.getMapSheetNum())) + imageryEntity.scene5k.eq(mapSheetNum)) .groupBy(mapInkx5kEntity.geom) .fetchOne(); @@ -191,6 +212,7 @@ public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport .where( mapSheetAnalInferenceEntity.uuid.eq(uuid), mapScaleTypeAnalDataSearchExpression(scale, mapSheetNum)) + .orderBy(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.asc()) .fetch(); ObjectMapper mapper = new ObjectMapper(); From 3e8fd8e6a14848d8898297d1dae007d0526db60b Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 11:00:59 +0900 Subject: [PATCH 04/20] =?UTF-8?q?=EA=B2=80=EC=88=98=ED=95=A0=EB=8B=B9=20?= =?UTF-8?q?=EC=8B=9C,=20updated=5Fdttm=20=EB=8F=84=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scheduler/TrainingDataReviewJobRepositoryImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryImpl.java index d7f22994..a4cf4f63 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryImpl.java @@ -99,6 +99,7 @@ public class TrainingDataReviewJobRepositoryImpl extends QuerydslRepositorySuppo .update(labelingAssignmentEntity) .set(labelingAssignmentEntity.inspectorUid, reviewerId) .set(labelingAssignmentEntity.inspectState, InspectState.UNCONFIRM.getId()) + .set(labelingAssignmentEntity.modifiedDate, ZonedDateTime.now()) .where(labelingAssignmentEntity.assignmentUid.eq(assignmentUid)) .execute(); } @@ -115,6 +116,7 @@ public class TrainingDataReviewJobRepositoryImpl extends QuerydslRepositorySuppo .update(labelingAssignmentEntity) .set(labelingAssignmentEntity.inspectorUid, reviewerId) .set(labelingAssignmentEntity.inspectState, InspectState.UNCONFIRM.getId()) + .set(labelingAssignmentEntity.modifiedDate, ZonedDateTime.now()) .where(labelingAssignmentEntity.assignmentUid.in(assignmentUids)) .execute(); } From 2343a154dcc5051879765e59ad90628f53dd07f6 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 11:21:48 +0900 Subject: [PATCH 05/20] =?UTF-8?q?=EB=B3=80=ED=99=94=ED=83=90=EC=A7=80=20?= =?UTF-8?q?=EB=8F=84=EC=97=BD50k=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20groupBy?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../changedetection/ChangeDetectionRepositoryImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java index 890a5c4d..7397864e 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java @@ -335,7 +335,8 @@ public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport .on(mapSheetAnalDataInferenceEntity.mapSheetNum.stringValue().eq(mapInkx5kEntity.mapidcdNo)) .innerJoin(mapInkx5kEntity.mapInkx50k, mapInkx50kEntity) .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) - .orderBy(mapInkx5kEntity.mapidcdNo.asc()) + .groupBy(mapInkx50kEntity.mapidcdNo, mapInkx50kEntity.mapidNm) + .orderBy(mapInkx50kEntity.mapidcdNo.asc()) .fetch(); } From 71de307ad7db240380fb8669b20e6e8dede6fd5b Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 20 Jan 2026 11:21:49 +0900 Subject: [PATCH 06/20] =?UTF-8?q?=EC=B6=94=EB=A1=A0=EC=A7=84=ED=96=89=20?= =?UTF-8?q?=EB=8F=84=EC=97=BD=20=EB=AA=A9=EB=A1=9D=20api=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InferenceResultApiController.java | 20 ++++++++++++++++ .../service/InferenceResultService.java | 10 ++++++++ .../core/InferenceResultCoreService.java | 10 ++++++++ .../MapSheetLearn5kRepositoryCustom.java | 2 ++ .../MapSheetLearn5kRepositoryImpl.java | 23 +++++++++++++++++++ 5 files changed, 65 insertions(+) diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java b/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java index 5ffd1496..e607e403 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java @@ -490,4 +490,24 @@ public class InferenceResultApiController { return ApiResponseDto.ok(inferenceResultService.getDownloadAudit(searchReq, downloadReq)); } + + @Operation(summary = "추론 실행중인 도엽 목록", description = "추론관리 실행중인 도엽명 5k 목록") + @ApiResponses({ + @ApiResponse( + responseCode = "200", + description = "검색 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiResponseDto.class))), + @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping(value = "/running-map/{uuid}") + public ApiResponseDto> getInferenceRunMapName( + @Parameter(description = "uuid", example = "9d213416-0e9e-429a-b037-070e6a29946e") + @PathVariable + UUID uuid) { + return ApiResponseDto.ok(inferenceResultService.getInferenceRunMapId(uuid)); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java index 356242aa..29807785 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java @@ -595,4 +595,14 @@ public class InferenceResultService { AuditLogDto.searchReq searchReq, DownloadReq downloadReq) { return auditLogCoreService.findLogByAccount(searchReq, downloadReq); } + + /** + * 실행중인 추론 도엽명 목록 + * + * @param uuid uuid + * @return + */ + public List getInferenceRunMapId(UUID uuid) { + return inferenceResultCoreService.getInferenceRunMapId(uuid); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java index a788bea1..db1dbf79 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java @@ -476,4 +476,14 @@ public class InferenceResultCoreService { dto.setUid(entity.getUid()); return dto; } + + /** + * 실행중인 추론 도엽명 목록 + * + * @param uuid 추론 실행중인 uuid + * @return + */ + public List getInferenceRunMapId(UUID uuid) { + return mapSheetLearn5kRepository.getInferenceRunMapId(uuid); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearn5kRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearn5kRepositoryCustom.java index c3783621..2b17132a 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearn5kRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearn5kRepositoryCustom.java @@ -6,4 +6,6 @@ import java.util.UUID; public interface MapSheetLearn5kRepositoryCustom { void saveFail5k(UUID uuid, List failMapIds, String type); + + List getInferenceRunMapId(UUID uuid); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearn5kRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearn5kRepositoryImpl.java index 437abf06..665a7979 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearn5kRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearn5kRepositoryImpl.java @@ -1,9 +1,11 @@ package com.kamco.cd.kamcoback.postgres.repository.Inference; +import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity.mapInkx5kEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearn5kEntity.mapSheetLearn5kEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnEntity.mapSheetLearnEntity; import com.querydsl.core.types.dsl.BooleanPath; +import com.querydsl.core.types.dsl.Expressions; import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; import java.util.UUID; @@ -59,4 +61,25 @@ public class MapSheetLearn5kRepositoryImpl implements MapSheetLearn5kRepositoryC .and(mapSheetLearn5kEntity.mapSheetNum.in(failMapIds))) .execute(); } + + @Override + public List getInferenceRunMapId(UUID uuid) { + return queryFactory + .select(mapInkx5kEntity.mapidNm) + .from(mapSheetLearnEntity) + .innerJoin(mapSheetLearn5kEntity) + .on(mapSheetLearn5kEntity.learn.id.eq(mapSheetLearnEntity.id)) + .innerJoin(mapInkx5kEntity) + .on( + Expressions.booleanTemplate( + "function('regexp_match', {0}, '^[0-9]+$') is not null", + mapInkx5kEntity.mapidcdNo) + .and( + mapSheetLearn5kEntity.mapSheetNum.eq( + Expressions.numberTemplate( + Long.class, "cast({0} as long)", mapInkx5kEntity.mapidcdNo)))) + .where(mapSheetLearnEntity.uuid.eq(uuid)) + .groupBy(mapInkx5kEntity.mapidNm) + .fetch(); + } } From b28d95111f32cb6f2e24387f117fd205c84d02d6 Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 20 Jan 2026 11:44:12 +0900 Subject: [PATCH 07/20] =?UTF-8?q?=EC=B6=94=EB=A1=A0=20=EA=B2=B0=EA=B3=BC?= =?UTF-8?q?=20geom=20=ED=85=8C=EC=9D=B4=EB=B8=94=EC=A0=80=EC=9E=A5=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Inference/InferenceResultRepositoryImpl.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 3d51412b..c2449f2b 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 @@ -217,11 +217,15 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC msl.m2_model_batch_id, msl.m3_model_batch_id ) - inner join tb_map_sheet_anal_data_inference msadi - on msadi.anal_uid = msl.anal_uid + INNER JOIN tb_map_sheet_anal_data_inference msadi + ON msadi.anal_uid = msl.anal_uid AND r.map_id ~ '^[0-9]+$' - AND r.map_id::bigint = msadi.map_sheet_num - where msl.anal_uid = :analUid + AND r.map_id::bigint = msadi.map_sheet_num + WHERE msl.anal_uid = :analUid + AND r.before_c is not null + AND r.before_p is not null + AND r.after_c is not null + AND r.after_p is not null ORDER BY r.uid, r.created_date DESC NULLS LAST ) x ON CONFLICT (result_uid) From f857ec0f256f25cacf4ff518accafb592e6dd559 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 11:54:43 +0900 Subject: [PATCH 08/20] =?UTF-8?q?=EA=B2=80=EC=88=98=ED=95=A0=20=EB=95=8C?= =?UTF-8?q?=20geom=20=ED=85=8C=EC=9D=B4=EB=B8=94=EB=8F=84=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trainingdata/TrainingDataReviewRepositoryImpl.java | 9 +++++++++ 1 file changed, 9 insertions(+) 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 94358faf..cd3259fa 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 @@ -209,6 +209,15 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport @Override public void updateReviewPolygonClass( Long inferenceGeomUid, Geometry geometry, Properties properties, String status) { + + // inference_geom 테이블에 상태 업데이트 + queryFactory + .update(mapSheetAnalDataInferenceGeomEntity) + .set(mapSheetAnalDataInferenceGeomEntity.testStateDttm, ZonedDateTime.now()) + .set(mapSheetAnalDataInferenceGeomEntity.testState, status) + .where(mapSheetAnalDataInferenceGeomEntity.geoUid.eq(inferenceGeomUid)) + .execute(); + // inference_geom 테이블 정보 가져오기 MapSheetAnalDataInferenceGeomEntity entity = queryFactory From 91c5c0c116d887f5ebcd906ac4c28af5a2e1ef9a Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 12:15:26 +0900 Subject: [PATCH 09/20] =?UTF-8?q?=EA=B2=80=EC=88=98=ED=95=A0=EB=8B=B9=20?= =?UTF-8?q?=EC=8B=9C,=20geom=20=ED=85=8C=EC=9D=B4=EB=B8=94=EB=8F=84=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/TrainingDataReviewJobCoreService.java | 4 ++++ .../TrainingDataReviewJobRepositoryCustom.java | 2 ++ .../TrainingDataReviewJobRepositoryImpl.java | 11 +++++++++++ .../service/TrainingDataReviewJobService.java | 8 +++++++- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataReviewJobCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataReviewJobCoreService.java index 5260f7af..bc47eeff 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataReviewJobCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/TrainingDataReviewJobCoreService.java @@ -37,4 +37,8 @@ public class TrainingDataReviewJobCoreService { public void lockInspectors(Long analUid, List reviewerIds) { trainingDataReviewJobRepository.lockInspectors(analUid, reviewerIds); } + + public void updateGeomUidTestState(List geomUids) { + trainingDataReviewJobRepository.updateGeomUidTestState(geomUids); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryCustom.java index f83b2f77..f3030013 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryCustom.java @@ -16,4 +16,6 @@ public interface TrainingDataReviewJobRepositoryCustom { void assignReviewerBatch(List assignmentUids, String reviewerId); Tasks findAssignmentTask(String assignmentUid); + + void updateGeomUidTestState(List geomUids); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryImpl.java index a4cf4f63..a7316cee 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scheduler/TrainingDataReviewJobRepositoryImpl.java @@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.postgres.repository.scheduler; import static com.kamco.cd.kamcoback.postgres.entity.QLabelingAssignmentEntity.labelingAssignmentEntity; import static com.kamco.cd.kamcoback.postgres.entity.QLabelingInspectorEntity.labelingInspectorEntity; +import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InspectState; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState; @@ -134,4 +135,14 @@ public class TrainingDataReviewJobRepositoryImpl extends QuerydslRepositorySuppo .where(labelingAssignmentEntity.assignmentUid.eq(UUID.fromString(assignmentUid))) .fetchOne(); } + + @Override + public void updateGeomUidTestState(List geomUids) { + queryFactory + .update(mapSheetAnalDataInferenceGeomEntity) + .set(mapSheetAnalDataInferenceGeomEntity.testState, InspectState.UNCONFIRM.getId()) + .set(mapSheetAnalDataInferenceGeomEntity.updatedDttm, ZonedDateTime.now()) + .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(geomUids)) + .execute(); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/TrainingDataReviewJobService.java b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/TrainingDataReviewJobService.java index 25bf791b..6b2dc85a 100644 --- a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/TrainingDataReviewJobService.java +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/TrainingDataReviewJobService.java @@ -80,8 +80,10 @@ public class TrainingDataReviewJobService { List assignmentUids = assignedTasks.stream().map(Tasks::getAssignmentUid).toList(); - trainingDataReviewJobCoreService.assignReviewerBatch(assignmentUids, reviewerId); + + List geomUids = assignedTasks.stream().map(Tasks::getInferenceUid).toList(); + trainingDataReviewJobCoreService.updateGeomUidTestState(geomUids); }); } } catch (Exception e) { @@ -127,5 +129,9 @@ public class TrainingDataReviewJobService { trainingDataReviewJobCoreService.lockInspectors(analUid, order); trainingDataReviewJobCoreService.assignReviewer(task.getAssignmentUid(), order.getFirst()); + + List geomUids = new ArrayList<>(); + geomUids.add(task.getInferenceUid()); + trainingDataReviewJobCoreService.updateGeomUidTestState(geomUids); } } From 1fc8552e2678a2dc4f71374c4fe42ddcf4fac1c7 Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 20 Jan 2026 14:22:51 +0900 Subject: [PATCH 10/20] =?UTF-8?q?=EC=B6=94=EB=A1=A0=20=EA=B2=B0=EA=B3=BC?= =?UTF-8?q?=20geom=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 --- .../MapSheetLearnRepositoryImpl.java | 71 +++++++++---------- 1 file changed, 34 insertions(+), 37 deletions(-) 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 7c249633..48ba9e7f 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 @@ -24,6 +24,7 @@ import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnEntity; import com.kamco.cd.kamcoback.postgres.entity.QModelMngEntity; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.CaseBuilder; import com.querydsl.core.types.dsl.Expressions; import com.querydsl.core.types.dsl.NumberExpression; @@ -360,42 +361,51 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto @Override public Page getInferenceGeomList(UUID uuid, SearchGeoReq searchGeoReq) { Pageable pageable = searchGeoReq.toPageable(); - BooleanBuilder builder = new BooleanBuilder(); + BooleanBuilder where = new BooleanBuilder(); - // analUid로 분석 정보 조회 + // 1) 분석 엔티티 조회 MapSheetLearnEntity analEntity = queryFactory .selectFrom(mapSheetLearnEntity) .where(mapSheetLearnEntity.uuid.eq(uuid)) .fetchOne(); - if (Objects.isNull(analEntity)) { + if (analEntity == null) { throw new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND); } - // 추론결과 id - builder.and(mapSheetAnalInferenceEntity.learnId.eq(analEntity.getId())); + // 2) where 조건 + where.and(mapSheetAnalInferenceEntity.learnId.eq(analEntity.getId())); - // 기준년도 분류 - if (searchGeoReq.getTargetClass() != null && !searchGeoReq.getTargetClass().equals("")) { - builder.and( + if (searchGeoReq.getTargetClass() != null && !searchGeoReq.getTargetClass().isBlank()) { + where.and( mapSheetAnalDataInferenceGeomEntity.classAfterCd.eq( searchGeoReq.getTargetClass().toLowerCase())); } - // 비교년도 분류 - if (searchGeoReq.getCompareClass() != null && !searchGeoReq.getCompareClass().equals("")) { - builder.and( + if (searchGeoReq.getCompareClass() != null && !searchGeoReq.getCompareClass().isBlank()) { + where.and( mapSheetAnalDataInferenceGeomEntity.classBeforeCd.eq( searchGeoReq.getCompareClass().toLowerCase())); } - // 분석도엽 if (searchGeoReq.getMapSheetNum() != null) { - Long mapSheetNum = searchGeoReq.getMapSheetNum(); - builder.and(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.like("%" + mapSheetNum + "%")); + // + // where.and(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.eq(searchGeoReq.getMapSheetNum())); + where.and( + mapSheetAnalDataInferenceGeomEntity.mapSheetNum.like( + "%" + searchGeoReq.getMapSheetNum() + "%")); } + // 3) inkx 조인 조건: JPQL/HQL에서 '~' 불가 → function('regexp_match', ...) 사용 + BooleanExpression inkxIsNumeric = + Expressions.booleanTemplate( + "function('regexp_match', {0}, '^[0-9]+$') is not null", mapInkx5kEntity.mapidcdNo); + + NumberExpression inkxNoAsLong = + Expressions.numberTemplate(Long.class, "cast({0} as long)", mapInkx5kEntity.mapidcdNo); + + // 4) content List content = queryFactory .select( @@ -411,45 +421,32 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto mapSheetAnalDataInferenceGeomEntity.classAfterCd, mapSheetAnalDataInferenceGeomEntity.classAfterProb, mapSheetAnalDataInferenceGeomEntity.mapSheetNum, - mapInkx5kEntity.mapidNm - // Expressions.stringTemplate( - // "ST_AsGeoJSON({0})", - // mapSheetAnalDataInferenceGeomEntity.geom), - // Expressions.stringTemplate( - // "ST_AsGeoJSON({0})", - // mapSheetAnalDataInferenceGeomEntity.geomCenter) - )) + mapInkx5kEntity.mapidNm)) .from(mapSheetAnalInferenceEntity) .join(mapSheetAnalDataInferenceEntity) .on(mapSheetAnalDataInferenceEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) .join(mapSheetAnalDataInferenceGeomEntity) .on(mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id)) .join(mapInkx5kEntity) - .on( - mapSheetAnalDataInferenceGeomEntity.mapSheetNum.eq( - Expressions.numberTemplate( - Long.class, "CAST({0} AS long)", mapInkx5kEntity.mapidcdNo))) - .where(builder) + .on(inkxIsNumeric.and(mapSheetAnalDataInferenceGeomEntity.mapSheetNum.eq(inkxNoAsLong))) + .where(where) + .orderBy(mapSheetAnalDataInferenceGeomEntity.geoUid.desc()) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) .fetch(); - long total = + // 5) total (조인 최소화 유지) + Long total = queryFactory - .select(mapSheetAnalDataInferenceGeomEntity.geoUid) + .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) .from(mapSheetAnalInferenceEntity) .join(mapSheetAnalDataInferenceEntity) .on(mapSheetAnalDataInferenceEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) .join(mapSheetAnalDataInferenceGeomEntity) .on(mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id)) - .join(mapInkx5kEntity) - .on( - mapSheetAnalDataInferenceGeomEntity.mapSheetNum.eq( - Expressions.numberTemplate( - Long.class, "CAST({0} AS long)", mapInkx5kEntity.mapidcdNo))) - .where(builder) - .fetchCount(); + .where(where) + .fetchOne(); - return new PageImpl<>(content, pageable, total); + return new PageImpl<>(content, pageable, total == null ? 0L : total); } } From cc4a0c024c6f78ebc784e64caa3c31adfc727d9a Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 20 Jan 2026 14:34:45 +0900 Subject: [PATCH 11/20] =?UTF-8?q?=EC=B6=94=EB=A1=A0=20=EA=B2=B0=EA=B3=BC?= =?UTF-8?q?=20geom=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 12/20] =?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 13/20] 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(); } } From af75c2b8d5d538a0e8afdf5530cd9a7c7470a3ae Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 15:19:09 +0900 Subject: [PATCH 14/20] =?UTF-8?q?=ED=95=99=EC=8A=B5=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EB=AA=A9=EB=A1=9D=20analState=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kamco/cd/kamcoback/label/dto/LabelWorkDto.java | 14 +++++++------- .../repository/label/LabelWorkRepositoryImpl.java | 5 ++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelWorkDto.java b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelWorkDto.java index 2fd6f313..03280382 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelWorkDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelWorkDto.java @@ -46,8 +46,8 @@ public class LabelWorkDto { private Long labelCompleteTotCnt; @JsonFormatDttm private ZonedDateTime labelStartDttm; - // tb_map_sheet_anal_inference.anal_state 컬럼 값 -> 미사용 - // private String analState; + // tb_map_sheet_anal_inference.anal_state 컬럼 값 + private String analState; // tb_labeling_assignment 테이블에서 stagnation_yn = 'N'인 정상 진행 건수 private Long normalProgressCnt; @@ -73,9 +73,9 @@ public class LabelWorkDto { /** 라벨링 상태 반환 (tb_map_sheet_anal_inference.anal_state 기준) */ public String getLabelState() { // anal_state 값이 있으면 해당 값 사용 -> 우선은 미사용 - // if (this.analState != null && !this.analState.isEmpty()) { - // return this.analState; - // } + if (this.analState != null && !this.analState.isEmpty()) { + return this.analState; + } // anal_state 값이 없으면 기존 로직으로 폴백 String mngState = LabelMngState.PENDING.getId(); @@ -84,10 +84,10 @@ public class LabelWorkDto { mngState = LabelMngState.PENDING.getId(); } else if (this.labelTotCnt > 0 && this.labelAssignCnt > 0 && this.labelCompleteTotCnt == 0) { mngState = LabelMngState.ASSIGNED.getId(); - } else if (this.labelCompleteTotCnt > 0) { - mngState = LabelMngState.ING.getId(); } else if (this.labelingClosedYn.equals("Y") && this.inspectionClosedYn.equals("Y")) { mngState = LabelMngState.FINISH.getId(); + } else if (this.labelCompleteTotCnt > 0) { + mngState = LabelMngState.ING.getId(); } return mngState; diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java index 03aacd43..664a5ccc 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java @@ -200,9 +200,8 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom { .otherwise(0L) .sum(), mapSheetAnalDataInferenceGeomEntity.labelStateDttm.min(), - // analState: tb_map_sheet_anal_inference.anal_state -> 우선은 미사용, java 단에서 로직화 해서 - // 내려줌 - // mapSheetAnalInferenceEntity.analState, + // analState: tb_map_sheet_anal_inference.anal_state + mapSheetAnalInferenceEntity.analState, // normalProgressCnt: stagnation_yn = 'N'인 건수 (서브쿼리) normalProgressCntSubQuery, // totalAssignmentCnt: 총 배정 건수 (서브쿼리) From fcf44bb0fbf7a5f8c9f98a31c2fc176892a405b9 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 15:27:20 +0900 Subject: [PATCH 15/20] =?UTF-8?q?=EC=83=81=ED=83=9C=EA=B0=92=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/InferenceResultRepositoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 71278059..b95e21c3 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 @@ -66,7 +66,7 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC r.m2_model_batch_id, r.m3_model_batch_id, r.id, - LabelState.PENDING.getId(), + LabelMngState.PENDING.getId(), FROM tb_map_sheet_learn r WHERE r.id = :id ON CONFLICT (stage, compare_yyyy, target_yyyy) From 87dd14e6c8f96269b73bd9e56b8022bd72f356ec Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 20 Jan 2026 15:38:19 +0900 Subject: [PATCH 16/20] =?UTF-8?q?AI=20=EC=B6=94=EB=A1=A0=20=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EB=B8=94=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/InferenceResultsTestingEntity.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/InferenceResultsTestingEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/InferenceResultsTestingEntity.java index 0fb8c2f8..6202c399 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/InferenceResultsTestingEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/InferenceResultsTestingEntity.java @@ -30,12 +30,6 @@ public class InferenceResultsTestingEntity { @Column(name = "map_id", length = Integer.MAX_VALUE) private String mapId; - @Column(name = "source_1", length = Integer.MAX_VALUE) - private String source1; - - @Column(name = "source_2", length = Integer.MAX_VALUE) - private String source2; - @Column(name = "model_version", length = Integer.MAX_VALUE) private String modelVersion; @@ -60,9 +54,6 @@ public class InferenceResultsTestingEntity { @Column(name = "area") private Double area; - @Column(name = "cd_prob") - private Double cdProb; - @Column(name = "before_c", length = Integer.MAX_VALUE) private String beforeC; @@ -75,12 +66,6 @@ public class InferenceResultsTestingEntity { @Column(name = "after_p") private Double afterP; - @Column(name = "input1") - private Long input1; - - @Column(name = "input2") - private Long input2; - @Id @NotNull @ColumnDefault("nextval('inference_results_testing_seq_seq')") From d3fc6d7ba18beb98c66932f088a7a6f102482a1d Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 20 Jan 2026 15:58:27 +0900 Subject: [PATCH 17/20] =?UTF-8?q?shp=20=ED=8C=8C=EC=9D=BC=20geosjon=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=EC=B6=94=EA=B0=80,=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EB=8B=A4=EC=9A=B4=EB=A1=9C=EB=93=9C=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EB=AA=85=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/service/ExternalJarRunner.java | 58 ++++++++++++++----- .../InferenceResultApiController.java | 28 ++++----- .../service/InferenceResultService.java | 10 +++- .../postgres/entity/MapSheetLearnEntity.java | 2 +- .../service/MapSheetInferenceJobService.java | 7 +++ 5 files changed, 75 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/common/service/ExternalJarRunner.java b/src/main/java/com/kamco/cd/kamcoback/common/service/ExternalJarRunner.java index 8c665423..c0d97073 100644 --- a/src/main/java/com/kamco/cd/kamcoback/common/service/ExternalJarRunner.java +++ b/src/main/java/com/kamco/cd/kamcoback/common/service/ExternalJarRunner.java @@ -6,17 +6,50 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; -import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Component; @Log4j2 @Component -@RequiredArgsConstructor public class ExternalJarRunner { - public void run(String jarPath, String batchIds, String inferenceId, String mapIds) { + private static final long TIMEOUT_MINUTES = 30; + /** + * shp 파일 생성 + * + * @param jarPath jar 경로 + * @param batchIds 배치 아이디 + * @param inferenceId uid + * @param mapIds 도엽 Id + */ + public void run(String jarPath, String batchIds, String inferenceId, String mapIds) { + List args = new ArrayList<>(); + + addArg(args, "converter.inference-id", inferenceId); + addArg(args, "converter.map-ids", mapIds); + addArg(args, "converter.batch-ids", batchIds); + + execJar(jarPath, args); + } + + /** + * geoserver 등록 + * + * @param jarPath jar 파일경로 + * @param register shp 경로 + * @param layer geoserver에 등록될 레이어 이름 + */ + public void run(String jarPath, String register, String layer) { + List args = new ArrayList<>(); + + addArg(args, "register", register); + addArg(args, "layer", layer); + + execJar(jarPath, args); + } + + private void execJar(String jarPath, List args) { StringBuilder out = new StringBuilder(); try { @@ -24,16 +57,7 @@ public class ExternalJarRunner { cmd.add("java"); cmd.add("-jar"); cmd.add(jarPath); - - if (inferenceId != null && !inferenceId.isBlank()) { - cmd.add("--converter.inference-id=" + inferenceId); - } - if (mapIds != null && !mapIds.isBlank()) { - cmd.add("--converter.map-ids=" + mapIds); - } - if (batchIds != null && !batchIds.isBlank()) { - cmd.add("--converter.batch-ids=" + batchIds); - } + cmd.addAll(args); ProcessBuilder pb = new ProcessBuilder(cmd); pb.redirectErrorStream(true); @@ -49,7 +73,7 @@ public class ExternalJarRunner { } } - boolean finished = p.waitFor(30, TimeUnit.MINUTES); + boolean finished = p.waitFor(TIMEOUT_MINUTES, TimeUnit.MINUTES); if (!finished) { p.destroyForcibly(); throw new RuntimeException("jar timeout\n" + out); @@ -66,4 +90,10 @@ public class ExternalJarRunner { log.error("jar execution error. output=\n{}", out, e); } } + + private void addArg(List args, String key, String value) { + if (value != null && !value.isBlank()) { + args.add("--" + key + "=" + value); + } + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java b/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java index e607e403..2c977bef 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java @@ -25,10 +25,11 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import java.io.IOException; -import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDate; import java.util.List; +import java.util.Map; import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.core.io.FileSystemResource; @@ -45,7 +46,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.util.UriUtils; @Tag(name = "추론관리", description = "추론관리 API") @RequestMapping("/api/inference") @@ -423,30 +423,32 @@ public class InferenceResultApiController { throws IOException { String path; + String uid; try { - path = String.valueOf(inferenceResultService.shpDownloadPath(uuid)); + Map map = inferenceResultService.shpDownloadPath(uuid); + path = String.valueOf(map.get("path")); + uid = String.valueOf(map.get("uid")); } catch (CustomApiException e) { - // 데이터 없음 등 404 return ResponseEntity.status(e.getStatus()).build(); } Path zipPath = Path.of(path); - FileSystemResource resource = new FileSystemResource(zipPath); - if (!resource.exists() || !resource.isReadable()) { + if (!Files.exists(zipPath) || !Files.isReadable(zipPath)) { return ResponseEntity.notFound().build(); } - String filename = zipPath.getFileName().toString(); - String encodedFilename = UriUtils.encode(filename, StandardCharsets.UTF_8); + FileSystemResource resource = new FileSystemResource(zipPath); + + String filename = uid + ".zip"; + + long fileSize = Files.size(zipPath); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_OCTET_STREAM) - .header( - HttpHeaders.CONTENT_DISPOSITION, - "attachment; filename=\"" + filename + "\"; filename*=UTF-8''" + encodedFilename) - .contentLength(resource.contentLength()) - .body((Resource) resource); + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"") + .contentLength(fileSize) + .body(resource); } @Operation(summary = "shp 파일 다운로드 이력", description = "추론관리 분석결과 shp 파일 다운로드 이력") diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java index 29807785..8e4d4fdf 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java @@ -41,6 +41,7 @@ import jakarta.validation.constraints.NotNull; import java.nio.file.Path; import java.time.ZonedDateTime; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -578,11 +579,16 @@ public class InferenceResultService { * @param uuid * @return */ - public Path shpDownloadPath(UUID uuid) { + public Map shpDownloadPath(UUID uuid) { InferenceLearnDto dto = inferenceResultCoreService.getInferenceUid(uuid); String uid = dto.getUid(); + Path path = Path.of(datasetDir).resolve(uid).resolve("merge").resolve(uid + ".zip"); - return Path.of(datasetDir).resolve(uid).resolve("merge").resolve(uid + ".zip"); + Map downloadMap = new HashMap<>(); + downloadMap.put("uid", uid); + downloadMap.put("path", path); + + return downloadMap; } /** diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java index 0d50601a..c3b85779 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java @@ -187,7 +187,7 @@ public class MapSheetLearnEntity { private int m3FailedJobs = 0; @Column(name = "uid", nullable = false) - private String uid = UUID.randomUUID().toString().replace("-", ""); + private String uid = UUID.randomUUID().toString().replace("-", "").toUpperCase(); public InferenceResultDto.ResultList toDto() { return new InferenceResultDto.ResultList( diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java index 27ac1cf2..3ac33839 100644 --- a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java @@ -53,6 +53,9 @@ public class MapSheetInferenceJobService { @Value("${inference.jar-path}") private String jarPath; + @Value("${file.dataset-dir}") + private String datasetDir; + /** 추론 진행 배치 1분 60_000 */ @Scheduled(fixedDelay = 30_000) public void runBatch() { @@ -242,6 +245,10 @@ public class MapSheetInferenceJobService { // uid 기준 merge shp, geojson 파일 생성 externalJarRunner.run(jarPath, batchId, inferenceId, ""); + + // uid 기준 도엽별 shp 파일 geoserver 등록 + String register = datasetDir + "/" + inferenceId + "/" + "merge" + "/" + inferenceId + ".shp"; + externalJarRunner.run(jarPath, register, inferenceId); } /** From 5381138cf50d4a6d32f0325e67d3e22aecf6b177 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 16:04:40 +0900 Subject: [PATCH 18/20] =?UTF-8?q?=EB=9D=BC=EB=B2=A8=EB=A7=81=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trainingdata/service/TrainingDataLabelService.java | 3 --- 1 file changed, 3 deletions(-) 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 2d4430dd..789fb4b6 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 @@ -60,9 +60,6 @@ public class TrainingDataLabelService { inferenceGeomUid, request.getGeometry(), request.getProperties(), status); } - // 라벨링 완료하면 실시간 검수 할당 (1건) - trainingDataReviewJobService.assignRealtime(assignmentUid); - // 회차 진행 상태 update trainingDataLabelCoreService.updateAnalInferenceMngState( info.getAnalUid(), LabelMngState.ING.getId()); From b7fe6ee28fe6ee5f5341254620ec45192eda7cc3 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 16:10:19 +0900 Subject: [PATCH 19/20] =?UTF-8?q?=EB=9D=BC=EB=B2=A8=EB=A7=81=20=EA=B2=80?= =?UTF-8?q?=EC=88=98=20=EC=8A=A4=EC=BC=80=EC=A4=84=EB=A7=81=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 --- .../scheduler/service/TrainingDataReviewJobService.java | 2 +- .../trainingdata/TrainingDataReviewApiController.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/TrainingDataReviewJobService.java b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/TrainingDataReviewJobService.java index 6b2dc85a..6618278d 100644 --- a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/TrainingDataReviewJobService.java +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/TrainingDataReviewJobService.java @@ -110,7 +110,7 @@ public class TrainingDataReviewJobService { return result; } - // 라벨러 완료,SKIP 시 호출 + // 라벨러 완료,SKIP 시 호출 -> 미사용 @Transactional public void assignRealtime(String assignmentUid) { Tasks task = trainingDataReviewJobCoreService.findAssignmentTask(assignmentUid); diff --git a/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataReviewApiController.java b/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataReviewApiController.java index 18ead37a..bf9318b5 100644 --- a/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataReviewApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataReviewApiController.java @@ -557,7 +557,9 @@ public class TrainingDataReviewApiController { trainingDataReviewService.getCogImageUrl(mapSheetNum, beforeYear, afterYear)); } - @Hidden + @Operation( + summary = "검수할당 스케줄링(수동 호출)", + description = "스케줄링이 실패한 경우 수동 호출하는 API, 어제 라벨링 완료된 것을 해당 검수자들에게 할당함") @GetMapping("/run-schedule") public ApiResponseDto runTrainingReviewSchedule() { trainingDataReviewJobService.assignReviewerYesterdayLabelComplete(); From 19954e3b2f0bf6e11a116725266d448dd3a7059c Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 20 Jan 2026 16:12:59 +0900 Subject: [PATCH 20/20] =?UTF-8?q?=EC=83=81=ED=83=9C=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EC=BF=BC=EB=A6=AC=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/Inference/InferenceResultRepositoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b95e21c3..d040b74b 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 @@ -66,7 +66,7 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC r.m2_model_batch_id, r.m3_model_batch_id, r.id, - LabelMngState.PENDING.getId(), + LabelMngState.PENDING.getId() FROM tb_map_sheet_learn r WHERE r.id = :id ON CONFLICT (stage, compare_yyyy, target_yyyy)