From fd5d0976fc38c4dc5f06bda7403bcfdc95ba16ca Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Fri, 2 Jan 2026 18:17:46 +0900 Subject: [PATCH] =?UTF-8?q?=ED=95=A0=EB=8B=B9=20=EA=B0=80=EB=8A=A5?= =?UTF-8?q?=ED=95=9C=20=EB=9D=BC=EB=B2=A8=EB=9F=AC,=20=EA=B2=80=EC=88=98?= =?UTF-8?q?=EC=9E=90=20=EB=AA=A9=EB=A1=9D=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../label/LabelAllocateApiController.java | 37 ++++- .../kamcoback/label/dto/LabelAllocateDto.java | 10 ++ .../label/service/LabelAllocateService.java | 18 ++- .../core/LabelAllocateCoreService.java | 9 +- .../entity/LabelingAssignmentEntity.java | 22 +-- .../label/LabelAllocateRepositoryCustom.java | 3 + .../label/LabelAllocateRepositoryImpl.java | 141 ++++++++++-------- 7 files changed, 156 insertions(+), 84 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 243965a2..868cd29c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java @@ -1,17 +1,25 @@ package com.kamco.cd.kamcoback.label; +import com.kamco.cd.kamcoback.code.dto.CommonCodeDto; import com.kamco.cd.kamcoback.config.api.ApiResponseDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetInspector; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetUser; import com.kamco.cd.kamcoback.label.service.LabelAllocateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; 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; @Slf4j @@ -23,13 +31,38 @@ public class LabelAllocateApiController { private final LabelAllocateService labelAllocateService; + @Operation(summary = "배정 가능한 사용자 목록 조회", description = "배정 가능한 사용자 목록 조회") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = CommonCodeDto.Basic.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/avail-user") + public ApiResponseDto> availUserList(@RequestParam @Schema() String role) { + return ApiResponseDto.ok(labelAllocateService.availUserList(role)); + } + // 라벨링 수량 할당하는 로직 테스트 @PostMapping("/allocate") public ApiResponseDto labelAllocate(@RequestBody LabelAllocateDto dto) { List targets = - List.of(new TargetUser("1234567", 1000), new TargetUser("2345678", 400), new TargetUser("3456789", 440)); - List inspectors = List.of(new TargetInspector("9876543", 1000), new TargetInspector("8765432", 340), new TargetInspector("98765432", 500)); + List.of( + new TargetUser("1234567", 1000), + new TargetUser("2345678", 400), + new TargetUser("3456789", 440)); + List inspectors = + List.of( + new TargetInspector("9876543", 1000), + new TargetInspector("8765432", 340), + new TargetInspector("98765432", 500)); labelAllocateService.allocateAsc(targets, inspectors); return ApiResponseDto.ok(null); 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 b3509a38..d1705e92 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 @@ -115,4 +115,14 @@ public class LabelAllocateDto { private ZonedDateTime createdDttm; private ZonedDateTime updatedDttm; } + + @Getter + @Setter + @AllArgsConstructor + public static class UserList { + + private String userRole; + private String employeeNo; + private String name; + } } 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 28dfa8ad..6d273a95 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 @@ -3,6 +3,7 @@ package com.kamco.cd.kamcoback.label.service; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetInspector; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetUser; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList; import com.kamco.cd.kamcoback.postgres.core.LabelAllocateCoreService; import jakarta.transaction.Transactional; import java.util.List; @@ -29,15 +30,15 @@ public class LabelAllocateService { public void allocateAsc(List targetUsers, List targetInspectors) { Long lastId = null; - //geom 잔여건수 != 프론트에서 넘어 온 총 건수 -> return - Long chargeCnt = labelAllocateCoreService.findLabelUnAssignedCnt(3L); //TODO + // geom 잔여건수 != 프론트에서 넘어 온 총 건수 -> return + Long chargeCnt = labelAllocateCoreService.findLabelUnAssignedCnt(3L); // TODO Long totalDemand = targetUsers.stream().mapToLong(TargetUser::getDemand).sum(); if (!Objects.equals(chargeCnt, totalDemand)) { log.info("chargeCnt != totalDemand"); return; } - //라벨러에게 건수만큼 할당 + // 라벨러에게 건수만큼 할당 for (TargetUser target : targetUsers) { int remaining = target.getDemand(); @@ -50,15 +51,14 @@ public class LabelAllocateService { return; // 더이상 할당할 데이터가 없으면 return } - labelAllocateCoreService.assignOwner( - ids, target.getUserId()); + labelAllocateCoreService.assignOwner(ids, target.getUserId()); remaining -= ids.size(); lastId = ids.get(ids.size() - 1); } } - //검수자에게 userCount명 만큼 할당 + // 검수자에게 userCount명 만큼 할당 List list = labelAllocateCoreService.findAssignedLabelerList(3L); int reviewerIndex = 0; int count = 0; @@ -66,7 +66,8 @@ public class LabelAllocateService { for (LabelAllocateDto.Basic labeler : list) { TargetInspector inspector = targetInspectors.get(reviewerIndex); - labelAllocateCoreService.assignInspector(labeler.getAssignmentUid(), inspector.getInspectorUid()); + labelAllocateCoreService.assignInspector( + labeler.getAssignmentUid(), inspector.getInspectorUid()); count++; if (count == inspector.getUserCount()) { @@ -74,6 +75,9 @@ public class LabelAllocateService { count = 0; } } + } + public List availUserList(String role) { + return labelAllocateCoreService.availUserList(role); } } 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 3d7ce013..1d8fa075 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 @@ -1,6 +1,7 @@ package com.kamco.cd.kamcoback.postgres.core; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList; import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity; import com.kamco.cd.kamcoback.postgres.repository.label.LabelAllocateRepository; import java.util.List; @@ -23,7 +24,9 @@ public class LabelAllocateCoreService { } public List findAssignedLabelerList(Long analUid) { - return labelAllocateRepository.findAssignedLabelerList(analUid).stream().map(LabelingAssignmentEntity::toDto).toList(); + return labelAllocateRepository.findAssignedLabelerList(analUid).stream() + .map(LabelingAssignmentEntity::toDto) + .toList(); } public Long findLabelUnAssignedCnt(Long analUid) { @@ -33,4 +36,8 @@ public class LabelAllocateCoreService { public void assignInspector(UUID assignmentUid, String inspectorUid) { labelAllocateRepository.assignInspector(assignmentUid, inspectorUid); } + + public List availUserList(String role) { + return labelAllocateRepository.availUserList(role); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/LabelingAssignmentEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/LabelingAssignmentEntity.java index 513b513e..22afd4aa 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/LabelingAssignmentEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/LabelingAssignmentEntity.java @@ -42,16 +42,16 @@ public class LabelingAssignmentEntity extends CommonDateEntity { public LabelAllocateDto.Basic toDto() { return new LabelAllocateDto.Basic( - this.assignmentUid, - this.inferenceGeomUid, - this.workerUid, - this.inspectorUid, - this.workState, - this.stagnationYn, - this.assignGroupId, - this.learnGeomUid, - this.analUid, - super.getCreatedDate(), - super.getModifiedDate()); + this.assignmentUid, + this.inferenceGeomUid, + this.workerUid, + this.inspectorUid, + this.workState, + this.stagnationYn, + this.assignGroupId, + this.learnGeomUid, + this.analUid, + super.getCreatedDate(), + super.getModifiedDate()); } } 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 0fed2538..659f5c7b 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 @@ -1,5 +1,6 @@ package com.kamco.cd.kamcoback.postgres.repository.label; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList; import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity; import java.util.List; import java.util.UUID; @@ -15,4 +16,6 @@ public interface LabelAllocateRepositoryCustom { Long findLabelUnAssignedCnt(Long analUid); void assignInspector(UUID assignmentUid, String userId); + + List availUserList(String role); } 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 6b33ad4e..f9e419d2 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 @@ -3,11 +3,15 @@ package com.kamco.cd.kamcoback.postgres.repository.label; import static com.kamco.cd.kamcoback.postgres.entity.QLabelingAssignmentEntity.labelingAssignmentEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalEntity.mapSheetAnalEntity; +import static com.kamco.cd.kamcoback.postgres.entity.QMemberEntity.memberEntity; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList; import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataGeomEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalEntity; +import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.Expressions; import com.querydsl.core.types.dsl.StringExpression; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -24,13 +28,12 @@ import org.springframework.stereotype.Repository; @Slf4j @Repository public class LabelAllocateRepositoryImpl extends QuerydslRepositorySupport - implements LabelAllocateRepositoryCustom { + implements LabelAllocateRepositoryCustom { private final JPAQueryFactory queryFactory; private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)"); - @PersistenceContext - private EntityManager em; + @PersistenceContext private EntityManager em; public LabelAllocateRepositoryImpl(JPAQueryFactory queryFactory) { super(MapSheetAnalDataGeomEntity.class); @@ -41,50 +44,48 @@ public class LabelAllocateRepositoryImpl extends QuerydslRepositorySupport public List fetchNextIds(Long lastId, int batchSize) { return queryFactory - .select(mapSheetAnalDataInferenceGeomEntity.geoUid) - .from(mapSheetAnalDataInferenceGeomEntity) - .where( - // mapSheetAnalDataGeomEntity.pnu.isNotNull(), //TODO: Mockup 진행 이후 확인하기 - lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId), - mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(2022), - mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(2024), - mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) - .orderBy(mapSheetAnalDataInferenceGeomEntity.geoUid.asc()) - .limit(batchSize) - .fetch(); + .select(mapSheetAnalDataInferenceGeomEntity.geoUid) + .from(mapSheetAnalDataInferenceGeomEntity) + .where( + // mapSheetAnalDataGeomEntity.pnu.isNotNull(), //TODO: Mockup 진행 이후 확인하기 + lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId), + mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(2022), + mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(2024), + mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) + .orderBy(mapSheetAnalDataInferenceGeomEntity.geoUid.asc()) + .limit(batchSize) + .fetch(); } @Override public void assignOwner(List ids, String userId) { - //data_geom 테이블에 label state 를 ASSIGNED 로 update + // data_geom 테이블에 label state 를 ASSIGNED 로 update queryFactory - .update(mapSheetAnalDataInferenceGeomEntity) - .set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId()) - .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(ids)) - .execute(); + .update(mapSheetAnalDataInferenceGeomEntity) + .set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId()) + .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(ids)) + .execute(); - //라벨러 할당 테이블에 insert + // 라벨러 할당 테이블에 insert for (Long geoUid : ids) { queryFactory - .insert(labelingAssignmentEntity) - .columns( - labelingAssignmentEntity.assignmentUid, - labelingAssignmentEntity.inferenceGeomUid, - labelingAssignmentEntity.workerUid, - labelingAssignmentEntity.workState, - labelingAssignmentEntity.assignGroupId, - labelingAssignmentEntity.analUid - ) - .values( - UUID.randomUUID(), - geoUid, - userId, - LabelState.ASSIGNED.getId(), - "", //TODO: 도엽번호 - 3 - ) - .execute(); + .insert(labelingAssignmentEntity) + .columns( + labelingAssignmentEntity.assignmentUid, + labelingAssignmentEntity.inferenceGeomUid, + labelingAssignmentEntity.workerUid, + labelingAssignmentEntity.workState, + labelingAssignmentEntity.assignGroupId, + labelingAssignmentEntity.analUid) + .values( + UUID.randomUUID(), + geoUid, + userId, + LabelState.ASSIGNED.getId(), + "", // TODO: 도엽번호 + 3) + .execute(); } em.flush(); @@ -94,45 +95,59 @@ public class LabelAllocateRepositoryImpl extends QuerydslRepositorySupport @Override public List findAssignedLabelerList(Long analUid) { return queryFactory - .selectFrom(labelingAssignmentEntity) - .where( - labelingAssignmentEntity.analUid.eq(analUid), - labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()), - labelingAssignmentEntity.inspectorUid.isNull() - ) - .orderBy(labelingAssignmentEntity.workerUid.asc()) - .fetch(); + .selectFrom(labelingAssignmentEntity) + .where( + labelingAssignmentEntity.analUid.eq(analUid), + labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()), + labelingAssignmentEntity.inspectorUid.isNull()) + .orderBy(labelingAssignmentEntity.workerUid.asc()) + .fetch(); } @Override public Long findLabelUnAssignedCnt(Long analUid) { - MapSheetAnalEntity entity = queryFactory.selectFrom(mapSheetAnalEntity).where(mapSheetAnalEntity.id.eq(analUid)).fetchOne(); + MapSheetAnalEntity entity = + queryFactory + .selectFrom(mapSheetAnalEntity) + .where(mapSheetAnalEntity.id.eq(analUid)) + .fetchOne(); if (Objects.isNull(entity)) { throw new EntityNotFoundException(); } return queryFactory - .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) - .from(mapSheetAnalDataInferenceGeomEntity) - .where( - mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(entity.getCompareYyyy()), - mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(entity.getTargetYyyy()), - mapSheetAnalDataInferenceGeomEntity.stage.eq(4), //TODO: 회차 컬럼을 가져와야 할 듯? - mapSheetAnalDataInferenceGeomEntity.labelState.isNull() - ) - .fetchOne() - ; + .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) + .from(mapSheetAnalDataInferenceGeomEntity) + .where( + mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(entity.getCompareYyyy()), + mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(entity.getTargetYyyy()), + mapSheetAnalDataInferenceGeomEntity.stage.eq(4), // TODO: 회차 컬럼을 가져와야 할 듯? + mapSheetAnalDataInferenceGeomEntity.labelState.isNull()) + .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("ACTIVE")) + .orderBy(memberEntity.name.asc()) + .fetch(); } }