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

This commit is contained in:
Moon
2025-12-31 09:43:35 +09:00
4 changed files with 192 additions and 1 deletions

View File

@@ -0,0 +1,67 @@
package com.kamco.cd.kamcoback.label;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.Sheet;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetUser;
import com.kamco.cd.kamcoback.label.service.LabelAllocateService;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.RestController;
@Slf4j
@Tag(name = "라벨링 작업 관리", description = "라벨링 작업 관리")
@RequestMapping({"/api/label/mng"})
@RequiredArgsConstructor
@RestController
public class LabelAllocateApiController {
// 라벨링 수량 할당하는 로직 테스트
@PostMapping("/allocate")
public ApiResponseDto<Void> labelAllocate(@RequestBody LabelAllocateDto dto) {
// 도엽별 카운트 쿼리
List<Sheet> sheets =
List.of(
new Sheet("1", 261),
new Sheet("2", 500),
new Sheet("3", 350),
new Sheet("4", 250),
new Sheet("5", 380),
new Sheet("6", 459));
// 사용자별 할당 입력한 값
List<TargetUser> targets =
List.of(new TargetUser("A", 1000), new TargetUser("B", 500), new TargetUser("C", 700));
LabelAllocateService.allocate(new ArrayList<>(sheets), new ArrayList<>(targets));
targets.forEach(
t -> {
log.info("[" + t.getUserId() + "]");
t.getAssigned()
.forEach(
u -> {
log.info(" - 도엽: " + u.getSheetId() + " (" + u.getCount() + ")");
});
});
/**
* [A] 입력한 수 : 1000 - 도엽: 2 (500) - 도엽: 6 (459) - 도엽: 5 (41)
*
* <p>[B] 입력한 수 : 500 - 도엽: 5 (339) - 도엽: 3 (161)
*
* <p>[C] 입력한 수 : 700 - 도엽: 3 (189) - 도엽: 1 (261) - 도엽: 4 (250)
*/
// A 에게 도엽 2 asc 해서 500건 할당 -> 도엽 6 asc 해서 459 할당 -> 도엽 5 asc 해서 41건 할당 -> insert
// B 에게 도엽 5 위에 41건 할당한 것 빼고 asc 해서 339건 할당 -> 도엽 3 asc 해서 161건 할당 -> insert
// .... for문에서 할당한 것 빼고 asc 해서 건수만큼 할당 insert 하고 다음 으로 넘어가기
return ApiResponseDto.ok(null);
}
}

View File

@@ -0,0 +1,46 @@
package com.kamco.cd.kamcoback.label.dto;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
public class LabelAllocateDto {
@Getter
@AllArgsConstructor
public static class Sheet {
private final String sheetId;
private int count;
public void decrease(int amount) {
this.count -= amount;
}
}
@Getter
public static class TargetUser {
private final String userId;
private final int demand;
private final List<Sheet> assigned = new ArrayList<>();
private int allocated = 0;
@Setter private int shortage = 0;
public TargetUser(String userId, int demand) {
this.userId = userId;
this.demand = demand;
}
public int getRemainDemand() {
return demand - allocated;
}
public void assign(String sheetId, int count) {
assigned.add(new Sheet(sheetId, count));
allocated += count;
}
}
}

View File

@@ -0,0 +1,78 @@
package com.kamco.cd.kamcoback.label.service;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.Sheet;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetUser;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class LabelAllocateService {
public static void allocate(List<Sheet> sheets, List<TargetUser> targetUsers) {
// 1⃣ 실제 도엽 기준 할당
allocateSheets(sheets, targetUsers);
// 2⃣ 전체 부족분 비율 계산
distributeShortage(targetUsers); // 항상 마지막에 한 번만 호출해야함
}
public static void allocateSheets(List<Sheet> sheets, List<TargetUser> targets) {
// 도엽 큰 것부터 (선택 사항)
sheets.sort(Comparator.comparingInt(Sheet::getCount).reversed());
for (TargetUser target : targets) {
Iterator<Sheet> it = sheets.iterator();
while (it.hasNext() && target.getRemainDemand() > 0) {
Sheet sheet = it.next();
int assignable = Math.min(sheet.getCount(), target.getRemainDemand());
if (assignable > 0) {
target.assign(sheet.getSheetId(), assignable);
sheet.decrease(assignable);
}
if (sheet.getCount() == 0) {
it.remove();
}
}
}
}
public static void distributeShortage(List<TargetUser> targets) {
int totalDemand = targets.stream().mapToInt(TargetUser::getDemand).sum();
int totalAllocated = targets.stream().mapToInt(t -> t.getAllocated()).sum();
int shortage = totalDemand - totalAllocated;
if (shortage <= 0) {
return;
}
int distributed = 0;
for (int i = 0; i < targets.size(); i++) {
TargetUser t = targets.get(i);
// 마지막 타겟이 나머지 가져가게 (반올림 오차 방지)
int share;
if (i == targets.size() - 1) {
share = shortage - distributed;
} else {
double ratio = (double) t.getDemand() / totalDemand;
share = (int) Math.round(shortage * ratio);
distributed += share;
}
t.setShortage(share);
}
}
}

View File

@@ -74,5 +74,5 @@ mapsheet:
upload:
skipGdalValidation: true
shp:
baseurl: /app/detect/result
baseurl: /app/tmp/detect/result