Merge remote-tracking branch 'origin/feat/dev_251201' into feat/dev_251201

This commit is contained in:
2026-01-05 10:05:05 +09:00
6 changed files with 107 additions and 63 deletions

View File

@@ -150,8 +150,8 @@ public class LabelAllocateApiController {
} }
@Operation( @Operation(
summary = "작업현황 관리 > 상세 > 작업 이관 > 팝업 내 라벨러 상세 정보", summary = "작업현황 관리 > 라벨러 상세 정보, 작업이관 팝업 내 라벨러 상세 정보 동일",
description = "작업현황 관리 > 상세 > 작업 이관 > 팝업 내 라벨러 상세 정보") description = "작업현황 관리 > 라벨러 상세 정보, 작업이관 팝업 내 라벨러 상세 정보 동일")
@GetMapping("/labeler-detail") @GetMapping("/labeler-detail")
public ApiResponseDto<LabelerDetail> findLabelerDetail( public ApiResponseDto<LabelerDetail> findLabelerDetail(
@RequestParam(defaultValue = "01022223333") String userId, @RequestParam(defaultValue = "01022223333") String userId,

View File

@@ -109,42 +109,42 @@ public class LabelAllocateDto {
description = "라벨러 할당 목록", description = "라벨러 할당 목록",
example = example =
""" """
[ [
{ {
"userId": "123456", "userId": "123456",
"demand": 1000 "demand": 1000
}, },
{ {
"userId": "010222297501", "userId": "010222297501",
"demand": 400 "demand": 400
}, },
{ {
"userId": "01022223333", "userId": "01022223333",
"demand": 440 "demand": 440
} }
] ]
""") """)
private List<TargetUser> labelers; private List<TargetUser> labelers;
@Schema( @Schema(
description = "검수자 할당 목록", description = "검수자 할당 목록",
example = example =
""" """
[ [
{ {
"inspectorUid": "K20251216001", "inspectorUid": "K20251216001",
"userCount": 1000 "userCount": 1000
},
{
"inspectorUid": "01022225555",
"userCount": 340
}, },
{ {
"inspectorUid": "K20251212001", "inspectorUid": "01022225555",
"userCount": 500 "userCount": 340
} },
] {
""") "inspectorUid": "K20251212001",
"userCount": 500
}
]
""")
private List<TargetInspector> inspectors; private List<TargetInspector> inspectors;
} }
@@ -227,6 +227,9 @@ public class LabelAllocateDto {
private Long completeCnt; private Long completeCnt;
private Long skipCnt; private Long skipCnt;
private Double percent; private Double percent;
private Integer ranking;
private ZonedDateTime createdDttm;
private String inspectorName;
} }
@Getter @Getter
@@ -244,17 +247,17 @@ public class LabelAllocateDto {
description = "라벨러 할당 목록", description = "라벨러 할당 목록",
example = example =
""" """
[ [
{ {
"userId": "123456", "userId": "123456",
"demand": 10 "demand": 10
}, },
{ {
"userId": "010222297501", "userId": "010222297501",
"demand": 5 "demand": 5
} }
] ]
""") """)
private List<TargetUser> labelers; private List<TargetUser> labelers;
@Schema(description = "비교년도", example = "2022") @Schema(description = "비교년도", example = "2022")
@@ -263,4 +266,13 @@ public class LabelAllocateDto {
@Schema(description = "기준년도", example = "2024") @Schema(description = "기준년도", example = "2024")
private Integer targetYyyy; private Integer targetYyyy;
} }
@Getter
@Setter
@AllArgsConstructor
public static class AllocateInfoDto {
private Long geoUid;
private String mapSheetNum;
}
} }

View File

@@ -3,6 +3,7 @@ package com.kamco.cd.kamcoback.label.service;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto; import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode; 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;
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.TargetInspector; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetInspector;
@@ -67,12 +68,12 @@ public class LabelAllocateService {
ApiResponseCode.BAD_REQUEST, "총 잔여건수와 요청 값의 합계가 맞지 않습니다."); ApiResponseCode.BAD_REQUEST, "총 잔여건수와 요청 값의 합계가 맞지 않습니다.");
} }
List<Long> allIds = List<AllocateInfoDto> allIds =
labelAllocateCoreService.fetchNextIds(lastId, chargeCnt, compareYyyy, targetYyyy, stage); labelAllocateCoreService.fetchNextIds(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();
List<Long> sub = allIds.subList(index, end); List<AllocateInfoDto> sub = allIds.subList(index, end);
labelAllocateCoreService.assignOwner(sub, target.getUserId(), compareYyyy, targetYyyy, stage); labelAllocateCoreService.assignOwner(sub, target.getUserId(), compareYyyy, targetYyyy, stage);
index = end; index = end;

View File

@@ -1,6 +1,7 @@
package com.kamco.cd.kamcoback.postgres.core; package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; 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.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.UserList; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList;
@@ -20,13 +21,17 @@ public class LabelAllocateCoreService {
private final LabelAllocateRepository labelAllocateRepository; private final LabelAllocateRepository labelAllocateRepository;
public List<Long> 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);
} }
public void assignOwner( public void assignOwner(
List<Long> ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) { List<AllocateInfoDto> ids,
String userId,
Integer compareYyyy,
Integer targetYyyy,
Integer stage) {
labelAllocateRepository.assignOwner(ids, userId, compareYyyy, targetYyyy, stage); labelAllocateRepository.assignOwner(ids, userId, compareYyyy, targetYyyy, stage);
} }

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.postgres.repository.label; package com.kamco.cd.kamcoback.postgres.repository.label;
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.UserList; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList;
@@ -12,11 +13,15 @@ import java.util.UUID;
public interface LabelAllocateRepositoryCustom { public interface LabelAllocateRepositoryCustom {
List<Long> 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( void assignOwner(
List<Long> ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage); List<AllocateInfoDto> ids,
String userId,
Integer compareYyyy,
Integer targetYyyy,
Integer stage);
List<LabelingAssignmentEntity> findAssignedLabelerList( List<LabelingAssignmentEntity> findAssignedLabelerList(
Integer compareYyyy, Integer targetYyyy, Integer stage); Integer compareYyyy, Integer targetYyyy, Integer stage);

View File

@@ -7,6 +7,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalEntity.mapShee
import static com.kamco.cd.kamcoback.postgres.entity.QMemberEntity.memberEntity; 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;
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.InspectState; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InspectState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState;
@@ -17,6 +18,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.LabelingAssignmentEntity;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataInferenceEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataInferenceEntity;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMemberEntity;
import com.querydsl.core.types.Projections; import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.CaseBuilder; import com.querydsl.core.types.dsl.CaseBuilder;
@@ -49,11 +51,15 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
@PersistenceContext private EntityManager em; @PersistenceContext private EntityManager em;
@Override @Override
public List<Long> 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 queryFactory return queryFactory
.select(mapSheetAnalDataInferenceGeomEntity.geoUid) .select(
Projections.constructor(
AllocateInfoDto.class,
mapSheetAnalDataInferenceGeomEntity.geoUid,
mapSheetAnalDataInferenceGeomEntity.mapSheetNum))
.from(mapSheetAnalDataInferenceGeomEntity) .from(mapSheetAnalDataInferenceGeomEntity)
.where( .where(
lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId), lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId),
@@ -68,7 +74,11 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
@Override @Override
public void assignOwner( public void assignOwner(
List<Long> ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) { List<AllocateInfoDto> ids,
String userId,
Integer compareYyyy,
Integer targetYyyy,
Integer stage) {
// analUid로 분석 정보 조회 // analUid로 분석 정보 조회
MapSheetAnalDataInferenceEntity analEntity = MapSheetAnalDataInferenceEntity analEntity =
@@ -87,13 +97,16 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
} }
// data_geom 테이블에 label state 를 ASSIGNED 로 update // data_geom 테이블에 label state 를 ASSIGNED 로 update
List<Long> geoUidList =
ids.stream().map(AllocateInfoDto::getGeoUid).filter(Objects::nonNull).toList();
queryFactory queryFactory
.update(mapSheetAnalDataInferenceGeomEntity) .update(mapSheetAnalDataInferenceGeomEntity)
.set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId()) .set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId())
.set(mapSheetAnalDataInferenceGeomEntity.labelStateDttm, ZonedDateTime.now()) .set(mapSheetAnalDataInferenceGeomEntity.labelStateDttm, ZonedDateTime.now())
.set(mapSheetAnalDataInferenceGeomEntity.testState, InspectState.UNCONFIRM.getId()) .set(mapSheetAnalDataInferenceGeomEntity.testState, InspectState.UNCONFIRM.getId())
.set(mapSheetAnalDataInferenceGeomEntity.testStateDttm, ZonedDateTime.now()) .set(mapSheetAnalDataInferenceGeomEntity.testStateDttm, ZonedDateTime.now())
.where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(ids)) .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(geoUidList))
.execute(); .execute();
// 라벨러 할당 테이블에 insert // 라벨러 할당 테이블에 insert
@@ -105,13 +118,13 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
values (?, ?, ?, ?, ?, ?) values (?, ?, ?, ?, ?, ?)
"""; """;
for (Long geoUid : ids) { for (AllocateInfoDto info : ids) {
em.createNativeQuery(sql) em.createNativeQuery(sql)
.setParameter(1, UUID.randomUUID()) .setParameter(1, UUID.randomUUID())
.setParameter(2, geoUid) .setParameter(2, info.getGeoUid())
.setParameter(3, userId) .setParameter(3, userId)
.setParameter(4, LabelState.ASSIGNED.getId()) .setParameter(4, LabelState.ASSIGNED.getId())
.setParameter(5, "") .setParameter(5, info.getMapSheetNum())
.setParameter(6, analEntity.getAnalUid()) .setParameter(6, analEntity.getAnalUid())
.executeUpdate(); .executeUpdate();
} }
@@ -572,24 +585,32 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
throw new EntityNotFoundException("MapSheetAnalEntity not found for analUid: "); throw new EntityNotFoundException("MapSheetAnalEntity not found for analUid: ");
} }
QMemberEntity worker = QMemberEntity.memberEntity;
QMemberEntity inspector = new QMemberEntity("inspector");
return queryFactory return queryFactory
.select( .select(
Projections.constructor( Projections.constructor(
LabelerDetail.class, LabelerDetail.class,
memberEntity.userRole, worker.userRole,
memberEntity.name, worker.name,
memberEntity.employeeNo, worker.employeeNo,
assignedCnt, assignedCnt,
skipCnt, skipCnt,
completeCnt, completeCnt,
percent)) percent,
.from(memberEntity) Expressions.constant(0), // TODO: 순위, 꼭 해야할지?
labelingAssignmentEntity.createdDate.min(),
inspector.name.min()))
.from(worker)
.innerJoin(labelingAssignmentEntity) .innerJoin(labelingAssignmentEntity)
.on( .on(
memberEntity.employeeNo.eq(labelingAssignmentEntity.workerUid), worker.employeeNo.eq(labelingAssignmentEntity.workerUid),
labelingAssignmentEntity.analUid.eq(analEntity.getAnalUid())) labelingAssignmentEntity.analUid.eq(analEntity.getAnalUid()))
.where(memberEntity.employeeNo.eq(userId)) .leftJoin(inspector)
.groupBy(memberEntity.userRole, memberEntity.name, memberEntity.employeeNo) .on(labelingAssignmentEntity.inspectorUid.eq(inspector.employeeNo))
.where(worker.employeeNo.eq(userId))
.groupBy(worker.userRole, worker.name, worker.employeeNo)
.fetchOne(); .fetchOne();
} }
} }