diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/InnopamApiController.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/InnopamApiController.java index e547f1b8..e266552e 100644 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/InnopamApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/Innopam/InnopamApiController.java @@ -7,6 +7,7 @@ import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch; import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.FeaturePnuDto; import com.kamco.cd.kamcoback.Innopam.service.DetectMastService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -14,6 +15,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import java.util.List; +import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -123,32 +125,42 @@ public class InnopamApiController { content = @Content( mediaType = "application/json", - schema = @Schema(implementation = Basic.class))), + schema = @Schema(implementation = FeaturePnuDto.class))), @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) }) @GetMapping("/pnu/{cprsBfYr}/{cprsAfYr}/{dtctSno}") public List selectPnuList( - @PathVariable String cprsBfYr, @PathVariable String cprsAfYr, @PathVariable String dtctSno) { + @PathVariable String cprsBfYr, @PathVariable String cprsAfYr, @PathVariable Integer dtctSno) { DetectMastSearch detectMastSearch = new DetectMastSearch(); detectMastSearch.setCprsAdYr(cprsAfYr); detectMastSearch.setCprsBfYr(cprsBfYr); - detectMastSearch.setDtctSno(Integer.parseInt(dtctSno)); + detectMastSearch.setDtctSno(dtctSno); return detectMastService.findPnuData(detectMastSearch); } + @Operation(summary = "탐지객체 랜덤 PNU 상세 조회", description = "탐지객체 PNU 랜덤값을 생성해서 보여준다") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "목록 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = FeaturePnuDto.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) @GetMapping("/pnu/{cprsBfYr}/{cprsAfYr}/{dtctSno}/{featureId}") public FeaturePnuDto selectPnuDetail( - @PathVariable String cprsBfYr, - @PathVariable String cprsAfYr, - @PathVariable String dtctSno, - @PathVariable String featureId) { - DetectMastSearch detectMastSearch = new DetectMastSearch(); - detectMastSearch.setCprsAdYr(cprsAfYr); - detectMastSearch.setCprsBfYr(cprsBfYr); - detectMastSearch.setDtctSno(Integer.parseInt(dtctSno)); - detectMastSearch.setFeatureId(featureId); - return new FeaturePnuDto(); + @Parameter(description = "이전년도", example = "2022") @PathVariable String cprsBfYr, + @Parameter(description = "기준년도", example = "2024") @PathVariable String cprsAfYr, + @Parameter(description = "회차", example = "4") @PathVariable Integer dtctSno, + @Parameter(description = "featureId", example = "000e161b-1955-4c89-ad87-0b3b4a91d00f") + @PathVariable + UUID featureId) { + return detectMastService.selectPnuDetail(featureId); } @Operation( @@ -168,11 +180,11 @@ public class InnopamApiController { }) @PutMapping("/pnu/{cprsBfYr}/{cprsAfYr}/{dtctSno}") public Integer updatePnuList( - @PathVariable String cprsBfYr, @PathVariable String cprsAfYr, @PathVariable String dtctSno) { + @PathVariable String cprsBfYr, @PathVariable String cprsAfYr, @PathVariable Integer dtctSno) { DetectMastSearch detectMastSearch = new DetectMastSearch(); detectMastSearch.setCprsAdYr(cprsAfYr); detectMastSearch.setCprsBfYr(cprsBfYr); - detectMastSearch.setDtctSno(Integer.parseInt(dtctSno)); + detectMastSearch.setDtctSno(dtctSno); return detectMastService.updatePnuData(detectMastSearch); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/service/DetectMastService.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/service/DetectMastService.java index a2f41dfe..f4485d20 100644 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/service/DetectMastService.java +++ b/src/main/java/com/kamco/cd/kamcoback/Innopam/service/DetectMastService.java @@ -14,6 +14,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Stream; import lombok.RequiredArgsConstructor; @@ -68,6 +69,13 @@ public class DetectMastService { return extractFeaturePnusRandom(dirPath); } + public FeaturePnuDto selectPnuDetail(UUID uuid) { + FeaturePnuDto dto = new FeaturePnuDto(); + dto.setPnu(randomPnu()); + dto.setFeatureId(uuid.toString()); + return dto; + } + @Transactional public Integer updatePnuData(DetectMastSearch detectMast) { 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 f0b65270..02788cc2 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java @@ -54,9 +54,7 @@ public class LabelAllocateApiController { return ApiResponseDto.ok(labelAllocateService.availUserList(role)); } - @Operation( - summary = "작업현황 관리 (라벨링, 검수 진행률 요약정보)", - description = "작업현황 관리 (라벨링, 검수 진행률 요약정보)") + @Operation(summary = "작업현황 관리 (라벨링, 검수 진행률 요약정보)", description = "작업현황 관리 (라벨링, 검수 진행률 요약정보)") @ApiResponses( value = { @ApiResponse(responseCode = "200", description = "조회 성공"), @@ -121,13 +119,11 @@ public class LabelAllocateApiController { public ApiResponseDto labelAllocate( @RequestBody @Valid LabelAllocateDto.AllocateDto dto) { + int compareYyyy = Integer.parseInt(dto.getYyyy().split("-")[0]); + int targetYyyy = Integer.parseInt(dto.getYyyy().split("-")[1]); return ApiResponseDto.okObject( labelAllocateService.allocateAsc( - dto.getStage(), - dto.getLabelers(), - dto.getInspectors(), - dto.getCompareYyyy(), - dto.getTargetYyyy())); + dto.getStage(), dto.getLabelers(), dto.getInspectors(), compareYyyy, targetYyyy)); } @Operation(summary = "작업현황 관리 > 변화탐지 회차 정보", description = "작업현황 관리 > 변화탐지 회차 정보") @@ -195,13 +191,12 @@ public class LabelAllocateApiController { @RequestBody LabelAllocateDto.AllocateMoveDto dto) { + int compareYyyy = Integer.parseInt(dto.getYyyy().split("-")[0]); + int targetYyyy = Integer.parseInt(dto.getYyyy().split("-")[1]); + return ApiResponseDto.okObject( labelAllocateService.allocateMove( - dto.getStage(), - dto.getLabelers(), - dto.getCompareYyyy(), - dto.getTargetYyyy(), - dto.getUserId())); + dto.getStage(), dto.getLabelers(), compareYyyy, targetYyyy, dto.getUserId())); } @Operation( diff --git a/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java b/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java index 3d85d264..4a1fc508 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java @@ -71,8 +71,10 @@ public class LabelWorkerApiController { public ApiResponseDto> labelWorkMngList( @Parameter(description = "변화탐지년도", example = "2022-2024") @RequestParam(required = false) String detectYear, - @Parameter(description = "시작일", example = "20220101") @RequestParam String strtDttm, - @Parameter(description = "종료일", example = "20261201") @RequestParam String endDttm, + @Parameter(description = "시작일", example = "20220101") @RequestParam(required = false) + String strtDttm, + @Parameter(description = "종료일", example = "20261201") @RequestParam(required = false) + String endDttm, @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0") int page, @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20") 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 12c95bb7..3bbc7aab 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 @@ -91,11 +91,14 @@ public class LabelAllocateDto { @AllArgsConstructor public static class AllocateDto { - @Schema(description = "비교년도", example = "2022", required = true) - private Integer compareYyyy; + @Schema(description = "비교년도-기준년도", example = "2022-2024", required = true) + private String yyyy; - @Schema(description = "기준년도", example = "2024", required = true) - private Integer targetYyyy; + // @Schema(description = "비교년도", example = "2022", required = true) + // private Integer compareYyyy; + // + // @Schema(description = "기준년도", example = "2024", required = true) + // private Integer targetYyyy; @Schema(description = "회차", example = "4", required = true) private Integer stage; @@ -218,6 +221,7 @@ public class LabelAllocateDto { private Integer ranking; private ZonedDateTime createdDttm; private String ownerName; + private Long remainCnt; } @Getter @@ -245,11 +249,14 @@ public class LabelAllocateDto { """) private List labelers; - @Schema(description = "비교년도", example = "2022") - private Integer compareYyyy; + @Schema(description = "비교년도-기준년도", example = "2022-2024") + private String yyyy; - @Schema(description = "기준년도", example = "2024") - private Integer targetYyyy; + // @Schema(description = "비교년도", example = "2022") + // private Integer compareYyyy; + // + // @Schema(description = "기준년도", example = "2024") + // private Integer targetYyyy; @Schema(description = "대상 사번", example = "01022223333") private String userId; 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 63a286cd..cdd0f1c0 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 @@ -40,6 +40,7 @@ public class LabelWorkDto { @JsonFormatDttm private ZonedDateTime createdDttm; private Long detectionTotCnt; private Long labelTotCnt; + private Long labelAssignCnt; private Long labelStopTotCnt; private Long labelIngTotCnt; private Long labelCompleteTotCnt; @@ -59,7 +60,7 @@ public class LabelWorkDto { if (this.labelTotCnt == 0) { mngState = "PENDING"; - }else if(this.labelTotCnt > 0 && this.labelIngTotCnt == 0 ){ + } else if (this.labelTotCnt > 0 && this.labelAssignCnt > 0 && this.labelIngTotCnt == 0) { mngState = "ASSIGNED"; } else if (this.labelIngTotCnt > 0) { mngState = "LABEL_ING"; diff --git a/src/main/java/com/kamco/cd/kamcoback/label/dto/WorkerStatsDto.java b/src/main/java/com/kamco/cd/kamcoback/label/dto/WorkerStatsDto.java index 9d03e89e..e7a3e035 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/dto/WorkerStatsDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/dto/WorkerStatsDto.java @@ -1,6 +1,8 @@ package com.kamco.cd.kamcoback.label.dto; +import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm; import io.swagger.v3.oas.annotations.media.Schema; +import java.time.ZonedDateTime; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -21,13 +23,15 @@ public class WorkerStatsDto { private String detectionYear; @Schema(description = "회차 (예: 8)") - private String round; + private String stage; @Schema(description = "국유인 반영일 (예: 2026-03-31)") - private String reflectionDate; + @JsonFormatDttm + private ZonedDateTime gukyuinApplyDttm; @Schema(description = "작업 시작일 (예: 2026-04-06)") - private String startDate; + @JsonFormatDttm + private ZonedDateTime startDttm; @Schema(description = "프로젝트 UUID") private String uuid; 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 8d3211ac..8b6b82b9 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 @@ -119,9 +119,10 @@ public class LabelAllocateService { Long analUid, String workerType, String search, String sortType) { // 프로젝트 정보 조회 (analUid가 없으면 최신 프로젝트 정보 조회) - var projectInfo = analUid != null - ? labelAllocateCoreService.findProjectInfo(analUid) - : labelAllocateCoreService.findLatestProjectInfo(); + var projectInfo = + analUid != null + ? labelAllocateCoreService.findProjectInfo(analUid) + : labelAllocateCoreService.findLatestProjectInfo(); // 작업 진행 현황 조회 var progressInfo = labelAllocateCoreService.findWorkProgressInfo(analUid); 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 ca31c812..d7e68d77 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 @@ -60,6 +60,10 @@ public class LabelAllocateCoreService { return labelAllocateRepository.findLatestProjectInfo(); } + public UUID findLastLabelWorkState() { + return labelAllocateRepository.findLastLabelWorkState(); + } + public List findWorkerStatistics( Long analUid, String workerType, String search, String sortType) { return labelAllocateRepository.findWorkerStatistics(analUid, workerType, search, sortType); 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 187ded4d..4f296843 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 @@ -36,6 +36,9 @@ public interface LabelAllocateRepositoryCustom { // 최신 프로젝트 정보 조회 (analUid 없이) ProjectInfo findLatestProjectInfo(); + // 최신 작업 상태의 UUID 조회 + UUID findLastLabelWorkState(); + // 작업자 통계 조회 List findWorkerStatistics( Long analUid, String workerType, String search, String sortType); 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 1e68e5a9..05b09d26 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 @@ -21,6 +21,7 @@ import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics; import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalInferenceEntity; import com.kamco.cd.kamcoback.postgres.entity.QMemberEntity; +import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Expression; import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.BooleanExpression; @@ -37,12 +38,9 @@ import java.time.LocalDate; import java.time.LocalTime; import java.time.ZoneId; import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Objects; import java.util.UUID; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; @@ -72,6 +70,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto .from(mapSheetAnalDataInferenceGeomEntity) .where( lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId), + mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(compareYyyy), mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(targetYyyy), mapSheetAnalDataInferenceGeomEntity.stage.eq(stage), @@ -160,6 +159,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) .from(mapSheetAnalDataInferenceGeomEntity) .where( + mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(), mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(compareYyyy), mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(targetYyyy), mapSheetAnalDataInferenceGeomEntity.stage.eq(stage), @@ -584,6 +584,11 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto QMemberEntity worker = QMemberEntity.memberEntity; QMemberEntity inspector = new QMemberEntity("inspector"); + // remainCnt + Expression remainCnt = + Expressions.numberTemplate( + Long.class, "({0} - {1} - {2})", assignedCnt, skipCnt, completeCnt); + return queryFactory .select( Projections.constructor( @@ -597,7 +602,8 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto percent, Expressions.constant(0), // TODO: 순위, 꼭 해야할지? labelingAssignmentEntity.workStatDttm.min(), - inspector.name.min())) + inspector.name.min(), + remainCnt)) .from(worker) .innerJoin(labelingAssignmentEntity) .on( @@ -648,9 +654,9 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto .select( mapSheetAnalInferenceEntity.compareYyyy, mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.analTitle, + mapSheetAnalInferenceEntity.stage, mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.analStrtDttm, + mapSheetAnalInferenceEntity.createdDttm, mapSheetAnalInferenceEntity.uuid) .from(mapSheetAnalInferenceEntity) .where(mapSheetAnalInferenceEntity.id.eq(analUid)) @@ -662,45 +668,48 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto Integer compareYyyy = result.get(mapSheetAnalInferenceEntity.compareYyyy); Integer targetYyyy = result.get(mapSheetAnalInferenceEntity.targetYyyy); - String analTitle = result.get(mapSheetAnalInferenceEntity.analTitle); + Integer stage = result.get(mapSheetAnalInferenceEntity.stage); ZonedDateTime gukyuinApplyDttm = result.get(mapSheetAnalInferenceEntity.gukyuinApplyDttm); - ZonedDateTime analStrtDttm = result.get(mapSheetAnalInferenceEntity.analStrtDttm); + ZonedDateTime createdDttm = result.get(mapSheetAnalInferenceEntity.createdDttm); UUID uuid = result.get(mapSheetAnalInferenceEntity.uuid); // 변화탐지년도 생성 String detectionYear = (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; - // 회차 추출 (예: "8회차" → "8") - String round = extractRoundFromTitle(analTitle); + // 회차를 stage 컬럼에서 가져옴 + String round = stage != null ? String.valueOf(stage) : null; return ProjectInfo.builder() .detectionYear(detectionYear) - .round(round) - .reflectionDate(formatDate(gukyuinApplyDttm)) - .startDate(formatDate(analStrtDttm)) + .stage(round) + .gukyuinApplyDttm(gukyuinApplyDttm) + .startDttm(createdDttm) .uuid(uuid != null ? uuid.toString() : null) .build(); } @Override public ProjectInfo findLatestProjectInfo() { - // 최신 target_yyyy를 기준으로 프로젝트 정보 조회 + // 최근 집계용 UUID 조회 - 작업이 할당된 최신 프로젝트 우선 + UUID uuid = findLastLabelWorkState(); + + if (uuid == null) { + return null; + } + + // UUID로 프로젝트 정보 조회 var result = queryFactory .select( mapSheetAnalInferenceEntity.compareYyyy, mapSheetAnalInferenceEntity.targetYyyy, - mapSheetAnalInferenceEntity.analTitle, + mapSheetAnalInferenceEntity.stage, mapSheetAnalInferenceEntity.gukyuinApplyDttm, - mapSheetAnalInferenceEntity.analStrtDttm, + mapSheetAnalInferenceEntity.createdDttm, mapSheetAnalInferenceEntity.uuid) .from(mapSheetAnalInferenceEntity) - .orderBy( - mapSheetAnalInferenceEntity.targetYyyy.desc(), - mapSheetAnalInferenceEntity.compareYyyy.desc(), - mapSheetAnalInferenceEntity.createdDttm.desc()) - .limit(1) + .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) .fetchOne(); if (result == null) { @@ -709,45 +718,59 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto Integer compareYyyy = result.get(mapSheetAnalInferenceEntity.compareYyyy); Integer targetYyyy = result.get(mapSheetAnalInferenceEntity.targetYyyy); - String analTitle = result.get(mapSheetAnalInferenceEntity.analTitle); + Integer stage = result.get(mapSheetAnalInferenceEntity.stage); ZonedDateTime gukyuinApplyDttm = result.get(mapSheetAnalInferenceEntity.gukyuinApplyDttm); - ZonedDateTime analStrtDttm = result.get(mapSheetAnalInferenceEntity.analStrtDttm); - UUID uuid = result.get(mapSheetAnalInferenceEntity.uuid); + ZonedDateTime createdDttm = result.get(mapSheetAnalInferenceEntity.createdDttm); // 변화탐지년도 생성 String detectionYear = (compareYyyy != null && targetYyyy != null) ? compareYyyy + "-" + targetYyyy : null; - // 회차 추출 (예: "8회차" → "8") - String round = extractRoundFromTitle(analTitle); + // 회차를 stage 컬럼에서 가져옴 + String round = stage != null ? String.valueOf(stage) : null; return ProjectInfo.builder() .detectionYear(detectionYear) - .round(round) - .reflectionDate(formatDate(gukyuinApplyDttm)) - .startDate(formatDate(analStrtDttm)) - .uuid(uuid != null ? uuid.toString() : null) + .stage(round) + .gukyuinApplyDttm(gukyuinApplyDttm) + .startDttm(createdDttm) + .uuid(uuid.toString()) .build(); } - /** 제목에서 회차 숫자 추출 예: "8회차", "제8회차" → "8" */ - private String extractRoundFromTitle(String title) { - if (title == null || title.isEmpty()) { - return null; + @Override + public UUID findLastLabelWorkState() { + BooleanBuilder whereBuilder = new BooleanBuilder(); + + // 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(); + + // 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(); } - Pattern pattern = Pattern.compile("(\\d+)회차"); - Matcher matcher = pattern.matcher(title); - - return matcher.find() ? matcher.group(1) : null; - } - - /** ZonedDateTime을 "yyyy-MM-dd" 형식으로 변환 */ - private String formatDate(ZonedDateTime dateTime) { - if (dateTime == null) { - return null; - } - return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + return uuid; } @Override @@ -966,6 +989,11 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto QMemberEntity inspector = QMemberEntity.memberEntity; QMemberEntity worker = new QMemberEntity("worker"); + // remainCnt + Expression remainCnt = + Expressions.numberTemplate( + Long.class, "({0} - {1} - {2})", assignedCnt, skipCnt, completeCnt); + return queryFactory .select( Projections.constructor( @@ -979,7 +1007,8 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto percent, Expressions.constant(0), // TODO: 순위, 꼭 해야할지? labelingAssignmentEntity.inspectStatDttm.min(), - worker.name.min())) + worker.name.min(), + remainCnt)) .from(inspector) .innerJoin(labelingAssignmentEntity) .on( 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 a7de04c2..5fa407e1 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 @@ -23,6 +23,8 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.UUID; @@ -111,10 +113,23 @@ public class LabelWorkRepositoryImpl extends QuerydslRepositorySupport && !searchReq.getStrtDttm().isEmpty() && searchReq.getEndDttm() != null && !searchReq.getEndDttm().isEmpty()) { + + ZoneId zoneId = ZoneId.of("Asia/Seoul"); + + ZonedDateTime start = + LocalDate.parse(searchReq.getStrtDttm(), DateTimeFormatter.BASIC_ISO_DATE) + .atStartOfDay(zoneId); + + ZonedDateTime end = + LocalDate.parse(searchReq.getEndDttm(), DateTimeFormatter.BASIC_ISO_DATE) + .plusDays(1) + .atStartOfDay(zoneId); + whereSubBuilder.and( - Expressions.stringTemplate( - "to_char({0}, 'YYYYMMDD')", mapSheetAnalDataInferenceGeomEntity.labelStateDttm) - .between(searchReq.getStrtDttm(), searchReq.getEndDttm())); + mapSheetAnalDataInferenceGeomEntity + .labelStateDttm + .goe(start) + .and(mapSheetAnalDataInferenceGeomEntity.labelStateDttm.lt(end))); } List foundContent = @@ -137,6 +152,11 @@ public class LabelWorkRepositoryImpl extends QuerydslRepositorySupport .then(1L) .otherwise(0L) .sum(), + new CaseBuilder() + .when(mapSheetAnalDataInferenceGeomEntity.labelState.eq("ASSIGNED")) + .then(1L) + .otherwise(0L) + .sum(), new CaseBuilder() .when(mapSheetAnalDataInferenceGeomEntity.labelState.eq("STOP")) .then(1L) @@ -172,23 +192,6 @@ public class LabelWorkRepositoryImpl extends QuerydslRepositorySupport .limit(pageable.getPageSize()) .fetch(); - /* - Long countQuery = - queryFactory - .select(mapSheetAnalDataInferenceEntity.count()) - .from(mapSheetAnalDataInferenceEntity) - .leftJoin(mapSheetAnalDataInferenceGeomEntity) - .on(whereSubBuilder) - .where(whereBuilder) - .groupBy( - mapSheetAnalDataInferenceEntity.compareYyyy, - mapSheetAnalDataInferenceEntity.targetYyyy, - mapSheetAnalDataInferenceEntity.stage - ) - .fetchOne(); - - */ - Long total = queryFactory .select(mapSheetAnalInferenceEntity.uuid.countDistinct())