라벨러,검수자 상세 정보, 일자별 목록 쿼리 추가

This commit is contained in:
2026-01-05 13:25:38 +09:00
parent 6f089decf9
commit f5fcc2a9e3
7 changed files with 948 additions and 521 deletions

View File

@@ -5,6 +5,7 @@ import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail; 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.WorkerStatsDto.WorkerListResponse; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerListResponse;
import com.kamco.cd.kamcoback.label.service.LabelAllocateService; import com.kamco.cd.kamcoback.label.service.LabelAllocateService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@@ -18,6 +19,7 @@ import jakarta.validation.Valid;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@@ -36,168 +38,204 @@ public class LabelAllocateApiController {
@Operation(summary = "배정 가능한 사용자 목록 조회", description = "라벨링 작업 배정을 위한 활성 상태의 사용자 목록을 조회합니다.") @Operation(summary = "배정 가능한 사용자 목록 조회", description = "라벨링 작업 배정을 위한 활성 상태의 사용자 목록을 조회합니다.")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse(responseCode = "200", description = "조회 성공"), @ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음"), @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음"),
@ApiResponse(responseCode = "500", description = "서버 오류") @ApiResponse(responseCode = "500", description = "서버 오류")
}) })
@GetMapping("/avail-user") @GetMapping("/avail-user")
public ApiResponseDto<List<LabelAllocateDto.UserList>> availUserList( public ApiResponseDto<List<LabelAllocateDto.UserList>> availUserList(
@Parameter( @Parameter(
description = "사용자 역할", description = "사용자 역할",
example = "LABELER", example = "LABELER",
schema = @Schema(allowableValues = {"LABELER", "REVIEWER"})) schema = @Schema(allowableValues = {"LABELER", "REVIEWER"}))
@RequestParam @RequestParam
String role) { String role) {
return ApiResponseDto.ok(labelAllocateService.availUserList(role)); return ApiResponseDto.ok(labelAllocateService.availUserList(role));
} }
@Operation( @Operation(
summary = "작업현황 관리 (라벨링, 검수 진행률 요약정보, 작업자 목록)", summary = "작업현황 관리 (라벨링, 검수 진행률 요약정보, 작업자 목록)",
description = "작업현황 관리 (라벨링, 검수 진행률 요약정보, 작업자 목록)") description = "작업현황 관리 (라벨링, 검수 진행률 요약정보, 작업자 목록)")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse(responseCode = "200", description = "조회 성공"), @ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음"), @ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음"),
@ApiResponse(responseCode = "500", description = "서버 오류") @ApiResponse(responseCode = "500", description = "서버 오류")
}) })
@GetMapping("/admin/workers") @GetMapping("/admin/workers")
public ApiResponseDto<WorkerListResponse> getWorkerStatistics( public ApiResponseDto<WorkerListResponse> getWorkerStatistics(
@Parameter(description = "분석 ID (선택)", example = "3") @RequestParam(required = false) @Parameter(description = "분석 ID (선택)", example = "3") @RequestParam(required = false)
Long analUid, Long analUid,
@Parameter( @Parameter(
description = "작업자 유형 (선택) - 미입력 시 LABELER로 조회", description = "작업자 유형 (선택) - 미입력 시 LABELER로 조회",
example = "LABELER", example = "LABELER",
schema = schema =
@Schema( @Schema(
allowableValues = {"LABELER", "REVIEWER"}, allowableValues = {"LABELER", "REVIEWER"},
defaultValue = "LABELER")) defaultValue = "LABELER"))
@RequestParam(required = false) @RequestParam(required = false)
String type, String type,
@Parameter(description = "검색어 (작업자 이름 또는 사번으로 검색, 부분 일치)", example = "김라벨") @Parameter(description = "검색어 (작업자 이름 또는 사번으로 검색, 부분 일치)", example = "김라벨")
@RequestParam(required = false) @RequestParam(required = false)
String search, String search,
@Parameter( @Parameter(
description = "정렬 조건 (선택) - 미입력 시 이름 오름차순", description = "정렬 조건 (선택) - 미입력 시 이름 오름차순",
example = "REMAINING_DESC", example = "REMAINING_DESC",
schema = schema =
@Schema( @Schema(
allowableValues = { allowableValues = {
"REMAINING_DESC", "REMAINING_DESC",
"REMAINING_ASC", "REMAINING_ASC",
"NAME_ASC", "NAME_ASC",
"NAME_DESC" "NAME_DESC"
}, },
defaultValue = "NAME_ASC")) defaultValue = "NAME_ASC"))
@RequestParam(required = false) @RequestParam(required = false)
String sort, String sort,
@Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @Parameter(description = "페이지 번호 (0부터 시작)", example = "0")
@RequestParam(defaultValue = "0") @RequestParam(defaultValue = "0")
Integer page, Integer page,
@Parameter(description = "페이지 크기", example = "20") @Parameter(description = "페이지 크기", example = "20")
@RequestParam(defaultValue = "20") @RequestParam(defaultValue = "20")
Integer size) { Integer size) {
// type이 null이면 기본값으로 LABELER 설정 // type이 null이면 기본값으로 LABELER 설정
String workerType = (type == null || type.isEmpty()) ? RoleType.LABELER.name() : type; String workerType = (type == null || type.isEmpty()) ? RoleType.LABELER.name() : type;
return ApiResponseDto.ok( return ApiResponseDto.ok(
labelAllocateService.getWorkerStatistics( labelAllocateService.getWorkerStatistics(
analUid, workerType, search, sort, page, size)); analUid, workerType, search, sort, page, size));
} }
@Operation(summary = "라벨링작업 관리 > 작업 배정", description = "라벨링작업 관리 > 작업 배정") @Operation(summary = "라벨링작업 관리 > 작업 배정", description = "라벨링작업 관리 > 작업 배정")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse( @ApiResponse(
responseCode = "201", responseCode = "201",
description = "등록 성공", description = "등록 성공",
content = content =
@Content( @Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = Long.class))), schema = @Schema(implementation = Long.class))),
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@PostMapping("/allocate") @PostMapping("/allocate")
public ApiResponseDto<ApiResponseDto.ResponseObj> labelAllocate( public ApiResponseDto<ApiResponseDto.ResponseObj> labelAllocate(
@RequestBody @Valid LabelAllocateDto.AllocateDto dto) { @RequestBody @Valid LabelAllocateDto.AllocateDto dto) {
return ApiResponseDto.okObject( return ApiResponseDto.okObject(
labelAllocateService.allocateAsc( labelAllocateService.allocateAsc(
dto.getStage(), dto.getStage(),
dto.getLabelers(), dto.getLabelers(),
dto.getInspectors(), dto.getInspectors(),
dto.getCompareYyyy(), dto.getCompareYyyy(),
dto.getTargetYyyy())); dto.getTargetYyyy()));
} }
@Operation(summary = "작업현황 관리 > 변화탐지 회차 정보", description = "작업현황 관리 > 변화탐지 회차 정보") @Operation(summary = "작업현황 관리 > 변화탐지 회차 정보", description = "작업현황 관리 > 변화탐지 회차 정보")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse(responseCode = "200", description = "조회 성공"), @ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음"), @ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음"),
@ApiResponse(responseCode = "500", description = "서버 오류") @ApiResponse(responseCode = "500", description = "서버 오류")
}) })
@GetMapping("/stage-detail") @GetMapping("/stage-detail")
public ApiResponseDto<InferenceDetail> findInferenceDetail( public ApiResponseDto<InferenceDetail> findInferenceDetail(
@Parameter( @Parameter(
description = "회차 마스터 key", description = "회차 마스터 key",
required = true, required = true,
example = "8584e8d4-53b3-4582-bde2-28a81495a626") example = "8584e8d4-53b3-4582-bde2-28a81495a626")
@RequestParam @RequestParam
String uuid) { String uuid) {
return ApiResponseDto.ok(labelAllocateService.findInferenceDetail(uuid)); return ApiResponseDto.ok(labelAllocateService.findInferenceDetail(uuid));
} }
@Operation( @Operation(
summary = "작업현황 관리 > 라벨러 상세 정보, 작업이관 팝업 내 라벨러 상세 정보 동일", summary = "작업현황 관리 > 라벨러/검수자 상세 정보, 작업이관 팝업 내 라벨러 상세 정보 동일",
description = "작업현황 관리 > 라벨러 상세 정보, 작업이관 팝업 내 라벨러 상세 정보 동일") description = "작업현황 관리 > 라벨러/검수자 상세 정보, 작업이관 팝업 내 라벨러 상세 정보 동일")
@GetMapping("/labeler-detail") @GetMapping("/user-detail")
public ApiResponseDto<LabelerDetail> findLabelerDetail( public ApiResponseDto<LabelerDetail> findUserDetail(
@RequestParam(defaultValue = "01022223333", required = true) String userId, @RequestParam(defaultValue = "01022223333", required = true) String userId,
@Parameter( @Parameter(
description = "회차 마스터 key", description = "회차 마스터 key",
required = true, required = true,
example = "8584e8d4-53b3-4582-bde2-28a81495a626") example = "8584e8d4-53b3-4582-bde2-28a81495a626")
@RequestParam @RequestParam
String uuid) { String uuid,
return ApiResponseDto.ok(labelAllocateService.findLabelerDetail(userId, uuid)); @Schema(
allowableValues = {"LABELER", "REVIEWER"},
defaultValue = "LABELER")
@Parameter(
description = "라벨러/검수자(LABELER/REVIEWER)",
required = true) @RequestParam String type
) {
return ApiResponseDto.ok(labelAllocateService.findUserDetail(userId, uuid, type));
} }
@Operation(summary = "작업현황 관리 > 상세 > 작업 이관", description = "작업현황 관리 > 상세 > 작업 이관") @Operation(summary = "작업현황 관리 > 상세 > 작업 이관", description = "작업현황 관리 > 상세 > 작업 이관")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse( @ApiResponse(
responseCode = "201", responseCode = "201",
description = "등록 성공", description = "등록 성공",
content = content =
@Content( @Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = Long.class))), schema = @Schema(implementation = Long.class))),
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@PostMapping("/allocate-move") @PostMapping("/allocate-move")
public ApiResponseDto<ApiResponseDto.ResponseObj> labelAllocateMove( public ApiResponseDto<ApiResponseDto.ResponseObj> labelAllocateMove(
@io.swagger.v3.oas.annotations.parameters.RequestBody( @io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "라벨링 이관", description = "라벨링 이관",
required = true, required = true,
content = content =
@Content( @Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = LabelAllocateDto.AllocateMoveDto.class))) schema = @Schema(implementation = LabelAllocateDto.AllocateMoveDto.class)))
@RequestBody @RequestBody
LabelAllocateDto.AllocateMoveDto dto) { LabelAllocateDto.AllocateMoveDto dto) {
return ApiResponseDto.okObject( return ApiResponseDto.okObject(
labelAllocateService.allocateMove( labelAllocateService.allocateMove(
dto.getAutoType(), dto.getAutoType(),
dto.getStage(), dto.getStage(),
dto.getLabelers(), dto.getLabelers(),
dto.getCompareYyyy(), dto.getCompareYyyy(),
dto.getTargetYyyy())); dto.getTargetYyyy()));
}
@Operation(
summary = "라벨링작업 관리 > 상세 > 라벨러/검수자 일별 작업량 목록",
description = "라벨링작업 관리 > 상세 > 라벨러/검수자 일별 작업량 목록")
@GetMapping("/daily-list")
public ApiResponseDto<Page<LabelingStatDto>> findDaliyList(
@RequestParam(defaultValue = "0", required = true) int page,
@RequestParam(defaultValue = "20", required = true) int size,
@Parameter(
description = "회차 마스터 key",
required = true,
example = "8584e8d4-53b3-4582-bde2-28a81495a626")
@RequestParam
String uuid,
@Parameter(
description = "사번",
required = true,
example = "123456")
@RequestParam String userId,
@Schema(
allowableValues = {"LABELER", "REVIEWER"},
defaultValue = "LABELER")
@Parameter(
description = "라벨러/검수자(LABELER/REVIEWER)",
required = true) @RequestParam String type
) {
LabelAllocateDto.searchReq searchReq = new LabelAllocateDto.searchReq(page, size, "");
return ApiResponseDto.ok(labelAllocateService.findDaliyList(searchReq, uuid, userId, type));
} }
} }

View File

@@ -8,7 +8,11 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
public class LabelAllocateDto { public class LabelAllocateDto {
@@ -97,9 +101,9 @@ public class LabelAllocateDto {
private Integer stage; private Integer stage;
@Schema( @Schema(
description = "라벨러 할당 목록", description = "라벨러 할당 목록",
example = example =
""" """
[ [
{ {
"userId": "123456", "userId": "123456",
@@ -118,9 +122,9 @@ public class LabelAllocateDto {
private List<TargetUser> labelers; private List<TargetUser> labelers;
@Schema( @Schema(
description = "검수자 할당 목록", description = "검수자 할당 목록",
example = example =
""" """
["K20251216001", ["K20251216001",
"01022225555", "01022225555",
"K20251212001" "K20251212001"
@@ -171,6 +175,9 @@ public class LabelAllocateDto {
private Long analUid; private Long analUid;
private ZonedDateTime createdDttm; private ZonedDateTime createdDttm;
private ZonedDateTime updatedDttm; private ZonedDateTime updatedDttm;
private String inspectState;
private ZonedDateTime workStatDttm;
private ZonedDateTime inspectStatDttm;
} }
@Getter @Getter
@@ -210,7 +217,7 @@ public class LabelAllocateDto {
private Double percent; private Double percent;
private Integer ranking; private Integer ranking;
private ZonedDateTime createdDttm; private ZonedDateTime createdDttm;
private String inspectorName; private String ownerName;
} }
@Getter @Getter
@@ -225,9 +232,9 @@ public class LabelAllocateDto {
private Integer stage; private Integer stage;
@Schema( @Schema(
description = "라벨러 할당 목록", description = "라벨러 할당 목록",
example = example =
""" """
[ [
{ {
"userId": "123456", "userId": "123456",
@@ -256,4 +263,43 @@ public class LabelAllocateDto {
private Long geoUid; private Long geoUid;
private Long mapSheetNum; private Long mapSheetNum;
} }
@Getter
@Setter
@AllArgsConstructor
public static class LabelingStatDto {
private String workDate;
private Long dailyTotalCnt;
private Long totalCnt;
private Long assignedCnt;
private Long skipCnt;
private Long completeCnt;
private Long remainCnt;
}
@Schema(name = "searchReq", description = "일자별 작업 목록 요청")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class searchReq {
// 페이징 파라미터
private int page = 0;
private int size = 20;
private String sort;
public Pageable toPageable() {
if (sort != null && !sort.isEmpty()) {
String[] sortParams = sort.split(",");
String property = sortParams[0];
Sort.Direction direction =
sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC;
return PageRequest.of(page, size, Sort.by(direction, property));
}
return PageRequest.of(page, size);
}
}
} }

View File

@@ -6,6 +6,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.AllocateInfoDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail; 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.TargetUser; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetUser;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.DailyHistory; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.DailyHistory;
@@ -16,6 +17,7 @@ import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -36,22 +38,22 @@ public class LabelAllocateService {
/** /**
* 도엽 기준 asc sorting 해서 할당 수만큼 배정하는 로직 * 도엽 기준 asc sorting 해서 할당 수만큼 배정하는 로직
* *
* @param stage 회차 * @param stage 회차
* @param targetUsers 라벨러 목록 * @param targetUsers 라벨러 목록
* @param targetInspectors 검수자 목록 * @param targetInspectors 검수자 목록
*/ */
@Transactional @Transactional
public ApiResponseDto.ResponseObj allocateAsc( public ApiResponseDto.ResponseObj allocateAsc(
Integer stage, Integer stage,
List<TargetUser> targetUsers, List<TargetUser> targetUsers,
List<String> targetInspectors, List<String> targetInspectors,
Integer compareYyyy, Integer compareYyyy,
Integer targetYyyy) { Integer targetYyyy) {
Long lastId = null; Long lastId = null;
// geom 잔여건수 조회 // geom 잔여건수 조회
Long chargeCnt = Long chargeCnt =
labelAllocateCoreService.findLabelUnAssignedCnt(stage, compareYyyy, targetYyyy); labelAllocateCoreService.findLabelUnAssignedCnt(stage, compareYyyy, targetYyyy);
if (chargeCnt <= 0) { if (chargeCnt <= 0) {
return new ApiResponseDto.ResponseObj(ApiResponseCode.DUPLICATE_DATA, "이미 배정완료된 회차 입니다."); return new ApiResponseDto.ResponseObj(ApiResponseCode.DUPLICATE_DATA, "이미 배정완료된 회차 입니다.");
} }
@@ -59,15 +61,15 @@ public class LabelAllocateService {
Long totalDemand = targetUsers.stream().mapToLong(TargetUser::getDemand).sum(); Long totalDemand = targetUsers.stream().mapToLong(TargetUser::getDemand).sum();
if (!Objects.equals(chargeCnt, totalDemand)) { if (!Objects.equals(chargeCnt, totalDemand)) {
return new ApiResponseDto.ResponseObj( return new ApiResponseDto.ResponseObj(
ApiResponseCode.BAD_REQUEST, "총 잔여건수와 요청 값의 합계가 맞지 않습니다."); ApiResponseCode.BAD_REQUEST, "총 잔여건수와 요청 값의 합계가 맞지 않습니다.");
} }
List<AllocateInfoDto> allIds = List<AllocateInfoDto> allIds =
labelAllocateCoreService.fetchNextIds(lastId, chargeCnt, compareYyyy, targetYyyy, stage); labelAllocateCoreService.fetchNextIds(lastId, chargeCnt, compareYyyy, targetYyyy, stage);
// MapSheetAnalInferenceEntity analUid 가져오기 // MapSheetAnalInferenceEntity analUid 가져오기
Long analUid = Long analUid =
labelAllocateCoreService.findMapSheetAnalInferenceUid(compareYyyy, targetYyyy, stage); labelAllocateCoreService.findMapSheetAnalInferenceUid(compareYyyy, targetYyyy, stage);
int index = 0; int index = 0;
for (TargetUser target : targetUsers) { for (TargetUser target : targetUsers) {
@@ -113,52 +115,52 @@ public class LabelAllocateService {
/** /**
* 작업자 통계 조회 * 작업자 통계 조회
* *
* @param analUid 분석 ID * @param analUid 분석 ID
* @param workerType 작업자 유형 (LABELER/INSPECTOR) * @param workerType 작업자 유형 (LABELER/INSPECTOR)
* @param search 검색어 (이름 또는 사번) * @param search 검색어 (이름 또는 사번)
* @param sortType 정렬 조건 * @param sortType 정렬 조건
* @param page 페이지 번호 (0부터 시작) * @param page 페이지 번호 (0부터 시작)
* @param size 페이지 크기 * @param size 페이지 크기
* @return 작업자 목록 및 통계 * @return 작업자 목록 및 통계
*/ */
public WorkerListResponse getWorkerStatistics( public WorkerListResponse getWorkerStatistics(
Long analUid, Long analUid,
String workerType, String workerType,
String search, String search,
String sortType, String sortType,
Integer page, Integer page,
Integer size) { Integer size) {
// 작업 진행 현황 조회 // 작업 진행 현황 조회
var progressInfo = labelAllocateCoreService.findWorkProgressInfo(analUid); var progressInfo = labelAllocateCoreService.findWorkProgressInfo(analUid);
// 작업자 통계 조회 // 작업자 통계 조회
List<WorkerStatistics> workers = List<WorkerStatistics> workers =
labelAllocateCoreService.findWorkerStatistics( labelAllocateCoreService.findWorkerStatistics(
analUid, workerType, search, sortType); analUid, workerType, search, sortType);
// 각 작업자별 3일치 처리량 조회 // 각 작업자별 3일치 처리량 조회
LocalDate today = LocalDate.now(); LocalDate today = LocalDate.now();
for (WorkerStatistics worker : workers) { for (WorkerStatistics worker : workers) {
Long day1Count = Long day1Count =
labelAllocateCoreService.findDailyProcessedCount( labelAllocateCoreService.findDailyProcessedCount(
worker.getWorkerId(), workerType, today.minusDays(1), analUid); worker.getWorkerId(), workerType, today.minusDays(1), analUid);
Long day2Count = Long day2Count =
labelAllocateCoreService.findDailyProcessedCount( labelAllocateCoreService.findDailyProcessedCount(
worker.getWorkerId(), workerType, today.minusDays(2), analUid); worker.getWorkerId(), workerType, today.minusDays(2), analUid);
Long day3Count = Long day3Count =
labelAllocateCoreService.findDailyProcessedCount( labelAllocateCoreService.findDailyProcessedCount(
worker.getWorkerId(), workerType, today.minusDays(3), analUid); worker.getWorkerId(), workerType, today.minusDays(3), analUid);
long average = (day1Count + day2Count + day3Count) / 3; long average = (day1Count + day2Count + day3Count) / 3;
DailyHistory history = DailyHistory history =
DailyHistory.builder() DailyHistory.builder()
.day1Ago(day1Count) .day1Ago(day1Count)
.day2Ago(day2Count) .day2Ago(day2Count)
.day3Ago(day3Count) .day3Ago(day3Count)
.average(average) .average(average)
.build(); .build();
worker.setHistory(history); worker.setHistory(history);
@@ -175,16 +177,16 @@ public class LabelAllocateService {
int toIndex = Math.min(fromIndex + size, workers.size()); int toIndex = Math.min(fromIndex + size, workers.size());
List<WorkerStatistics> pagedWorkers = List<WorkerStatistics> pagedWorkers =
(fromIndex < workers.size()) ? workers.subList(fromIndex, toIndex) : List.of(); (fromIndex < workers.size()) ? workers.subList(fromIndex, toIndex) : List.of();
return WorkerListResponse.builder() return WorkerListResponse.builder()
.progressInfo(progressInfo) .progressInfo(progressInfo)
.workers(pagedWorkers) .workers(pagedWorkers)
.currentPage(page) .currentPage(page)
.pageSize(size) .pageSize(size)
.totalElements(totalElements) .totalElements(totalElements)
.totalPages(totalPages) .totalPages(totalPages)
.build(); .build();
} }
public InferenceDetail findInferenceDetail(String uuid) { public InferenceDetail findInferenceDetail(String uuid) {
@@ -192,11 +194,11 @@ public class LabelAllocateService {
} }
public ApiResponseDto.ResponseObj allocateMove( public ApiResponseDto.ResponseObj allocateMove(
String autoType, String autoType,
Integer stage, Integer stage,
List<TargetUser> targetUsers, List<TargetUser> targetUsers,
Integer compareYyyy, Integer compareYyyy,
Integer targetYyyy) { Integer targetYyyy) {
Long lastId = null; Long lastId = null;
Long chargeCnt = targetUsers.stream().mapToLong(TargetUser::getDemand).sum(); Long chargeCnt = targetUsers.stream().mapToLong(TargetUser::getDemand).sum();
@@ -206,8 +208,8 @@ public class LabelAllocateService {
} }
List<Long> allIds = List<Long> allIds =
labelAllocateCoreService.fetchNextMoveIds( labelAllocateCoreService.fetchNextMoveIds(
lastId, chargeCnt, compareYyyy, targetYyyy, stage); lastId, chargeCnt, compareYyyy, targetYyyy, stage);
int index = 0; int index = 0;
for (TargetUser target : targetUsers) { for (TargetUser target : targetUsers) {
int end = index + target.getDemand(); int end = index + target.getDemand();
@@ -220,7 +222,19 @@ public class LabelAllocateService {
return new ApiResponseDto.ResponseObj(ApiResponseCode.OK, "이관을 완료하였습니다."); return new ApiResponseDto.ResponseObj(ApiResponseCode.OK, "이관을 완료하였습니다.");
} }
public LabelerDetail findLabelerDetail(String userId, String uuid) { public LabelerDetail findUserDetail(String userId, String uuid, String type) {
return labelAllocateCoreService.findLabelerDetail(userId, uuid); if (type.equals("LABELER")) {
return labelAllocateCoreService.findLabelerDetail(userId, uuid);
} else {
return labelAllocateCoreService.findInspectorDetail(userId, uuid);
}
}
public Page<LabelingStatDto> findDaliyList(LabelAllocateDto.searchReq searchReq, String uuid, String userId, String type) {
if (type.equals("LABELER")) {
return labelAllocateCoreService.findLabelerDailyStat(searchReq, uuid, userId);
} else {
return labelAllocateCoreService.findInspectorDailyStat(searchReq, uuid, userId);
}
} }
} }

View File

@@ -4,7 +4,9 @@ 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.AllocateInfoDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail; 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.UserList; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.searchReq;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkProgressInfo; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkProgressInfo;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics;
import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity; import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity;
@@ -13,6 +15,7 @@ import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@@ -22,7 +25,7 @@ public class LabelAllocateCoreService {
private final LabelAllocateRepository labelAllocateRepository; private final LabelAllocateRepository labelAllocateRepository;
public List<AllocateInfoDto> fetchNextIds( public List<AllocateInfoDto> fetchNextIds(
Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) { Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) {
return labelAllocateRepository.fetchNextIds(lastId, batchSize, compareYyyy, targetYyyy, stage); return labelAllocateRepository.fetchNextIds(lastId, batchSize, compareYyyy, targetYyyy, stage);
} }
@@ -32,8 +35,8 @@ public class LabelAllocateCoreService {
public List<LabelAllocateDto.Basic> findAssignedLabelerList(Long analUid) { public List<LabelAllocateDto.Basic> findAssignedLabelerList(Long analUid) {
return labelAllocateRepository.findAssignedLabelerList(analUid).stream() return labelAllocateRepository.findAssignedLabelerList(analUid).stream()
.map(LabelingAssignmentEntity::toDto) .map(LabelingAssignmentEntity::toDto)
.toList(); .toList();
} }
public Long findLabelUnAssignedCnt(Integer stage, Integer compareYyyy, Integer targetYyyy) { public Long findLabelUnAssignedCnt(Integer stage, Integer compareYyyy, Integer targetYyyy) {
@@ -49,12 +52,12 @@ public class LabelAllocateCoreService {
} }
public List<WorkerStatistics> findWorkerStatistics( public List<WorkerStatistics> findWorkerStatistics(
Long analUid, Long analUid,
String workerType, String workerType,
String search, String search,
String sortType) { String sortType) {
return labelAllocateRepository.findWorkerStatistics( return labelAllocateRepository.findWorkerStatistics(
analUid, workerType, search, sortType); analUid, workerType, search, sortType);
} }
public WorkProgressInfo findWorkProgressInfo(Long analUid) { public WorkProgressInfo findWorkProgressInfo(Long analUid) {
@@ -62,7 +65,7 @@ public class LabelAllocateCoreService {
} }
public Long findDailyProcessedCount( public Long findDailyProcessedCount(
String workerId, String workerType, LocalDate date, Long analUid) { String workerId, String workerType, LocalDate date, Long analUid) {
return labelAllocateRepository.findDailyProcessedCount(workerId, workerType, date, analUid); return labelAllocateRepository.findDailyProcessedCount(workerId, workerType, date, analUid);
} }
@@ -75,9 +78,9 @@ public class LabelAllocateCoreService {
} }
public List<Long> fetchNextMoveIds( public List<Long> fetchNextMoveIds(
Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) { Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) {
return labelAllocateRepository.fetchNextMoveIds( return labelAllocateRepository.fetchNextMoveIds(
lastId, batchSize, compareYyyy, targetYyyy, stage); lastId, batchSize, compareYyyy, targetYyyy, stage);
} }
public void assignOwnerMove(List<Long> sub, String userId) { public void assignOwnerMove(List<Long> sub, String userId) {
@@ -95,4 +98,16 @@ public class LabelAllocateCoreService {
public void insertInspector(Long analUid, String inspector) { public void insertInspector(Long analUid, String inspector) {
labelAllocateRepository.insertInspector(analUid, inspector); labelAllocateRepository.insertInspector(analUid, inspector);
} }
public Page<LabelingStatDto> findLabelerDailyStat(searchReq searchReq, String uuid, String userId) {
return labelAllocateRepository.findLabelerDailyStat(searchReq, uuid, userId);
}
public Page<LabelingStatDto> findInspectorDailyStat(searchReq searchReq, String uuid, String userId) {
return labelAllocateRepository.findInspectorDailyStat(searchReq, uuid, userId);
}
public LabelerDetail findInspectorDetail(String userId, String uuid) {
return labelAllocateRepository.findInspectorDetail(userId, uuid);
}
} }

View File

@@ -6,6 +6,7 @@ import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import java.time.ZonedDateTime;
import java.util.UUID; import java.util.UUID;
@Entity @Entity
@@ -40,18 +41,31 @@ public class LabelingAssignmentEntity extends CommonDateEntity {
@Column(name = "anal_uid") @Column(name = "anal_uid")
private Long analUid; private Long analUid;
@Column(name = "inspect_state")
private String inspectState;
@Column(name = "work_stat_dttm")
private ZonedDateTime workStatDttm;
@Column(name = "inspect_stat_dttm")
private ZonedDateTime inspectStatDttm;
public LabelAllocateDto.Basic toDto() { public LabelAllocateDto.Basic toDto() {
return new LabelAllocateDto.Basic( return new LabelAllocateDto.Basic(
this.assignmentUid, this.assignmentUid,
this.inferenceGeomUid, this.inferenceGeomUid,
this.workerUid, this.workerUid,
this.inspectorUid, this.inspectorUid,
this.workState, this.workState,
this.stagnationYn, this.stagnationYn,
this.assignGroupId, this.assignGroupId,
this.learnGeomUid, this.learnGeomUid,
this.analUid, this.analUid,
super.getCreatedDate(), super.getCreatedDate(),
super.getModifiedDate()); super.getModifiedDate(),
this.inspectState,
this.workStatDttm,
this.inspectStatDttm
);
} }
} }

View File

@@ -1,8 +1,10 @@
package com.kamco.cd.kamcoback.postgres.repository.label; package com.kamco.cd.kamcoback.postgres.repository.label;
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.AllocateInfoDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail; 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.UserList; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkProgressInfo; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkProgressInfo;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics;
@@ -10,11 +12,12 @@ import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.springframework.data.domain.Page;
public interface LabelAllocateRepositoryCustom { public interface LabelAllocateRepositoryCustom {
List<AllocateInfoDto> fetchNextIds( List<AllocateInfoDto> fetchNextIds(
Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage); Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage);
void assignOwner(List<AllocateInfoDto> ids, String userId, Long analUid); void assignOwner(List<AllocateInfoDto> ids, String userId, Long analUid);
@@ -28,7 +31,7 @@ public interface LabelAllocateRepositoryCustom {
// 작업자 통계 조회 // 작업자 통계 조회
List<WorkerStatistics> findWorkerStatistics( List<WorkerStatistics> findWorkerStatistics(
Long analUid, String workerType, String search, String sortType); Long analUid, String workerType, String search, String sortType);
// 작업 진행 현황 조회 // 작업 진행 현황 조회
WorkProgressInfo findWorkProgressInfo(Long analUid); WorkProgressInfo findWorkProgressInfo(Long analUid);
@@ -41,7 +44,7 @@ public interface LabelAllocateRepositoryCustom {
InferenceDetail findInferenceDetail(String uuid); InferenceDetail findInferenceDetail(String uuid);
List<Long> fetchNextMoveIds( List<Long> fetchNextMoveIds(
Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage); Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage);
void assignOwnerMove(List<Long> sub, String userId); void assignOwnerMove(List<Long> sub, String userId);
@@ -50,4 +53,10 @@ public interface LabelAllocateRepositoryCustom {
Long findMapSheetAnalInferenceUid(Integer compareYyyy, Integer targetYyyy, Integer stage); Long findMapSheetAnalInferenceUid(Integer compareYyyy, Integer targetYyyy, Integer stage);
void insertInspector(Long analUid, String inspector); void insertInspector(Long analUid, String inspector);
Page<LabelingStatDto> findLabelerDailyStat(LabelAllocateDto.searchReq searchReq, String uuid, String userId);
Page<LabelingStatDto> findInspectorDailyStat(LabelAllocateDto.searchReq searchReq, String uuid, String userId);
LabelerDetail findInspectorDetail(String userId, String uuid);
} }