Merge branch 'feat/infer_dev_260107' of https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice into feat/infer_dev_260107

# Conflicts:
#	src/main/resources/application-local.yml
This commit is contained in:
Moon
2026-01-22 21:09:15 +09:00
51 changed files with 1694 additions and 1176 deletions

View File

@@ -0,0 +1,24 @@
package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkFacts;
import com.kamco.cd.kamcoback.postgres.repository.Inference.MapSheetLearnRepository;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class GukYuinCoreService {
private final MapSheetLearnRepository mapSheetLearnRepository;
/**
* 국유in연동 가능여부 확인
*
* @param uuid uuid
* @return
*/
public GukYuinLinkFacts findLinkFacts(UUID uuid) {
return mapSheetLearnRepository.findLinkFacts(uuid);
}
}

View File

@@ -4,6 +4,7 @@ import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.common.utils.UserUtil;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.AnalResultInfo;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.BboxPointDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Dashboard;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Geom;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.InferenceBatchSheet;
@@ -409,8 +410,18 @@ public class InferenceResultCoreService {
return dto;
}
/**
* 추론결과 기본정보
*
* @param uuid uuid
* @return
*/
public AnalResultInfo getInferenceResultInfo(UUID uuid) {
return mapSheetLearnRepository.getInferenceResultInfo(uuid);
AnalResultInfo resultInfo = mapSheetLearnRepository.getInferenceResultInfo(uuid);
BboxPointDto bboxPointDto = mapSheetLearnRepository.getBboxPoint(uuid);
resultInfo.setBboxGeom(bboxPointDto.getBboxGeom());
resultInfo.setBboxCenterPoint(bboxPointDto.getBboxCenterPoint());
return resultInfo;
}
public List<Dashboard> getInferenceClassCountList(UUID uuid) {

View File

@@ -12,6 +12,7 @@ import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
@@ -51,6 +52,12 @@ public class AuditLogEntity extends CommonCreateEntity {
@Column(name = "error_log_uid")
private Long errorLogUid;
@Column(name = "download_uuid")
private UUID downloadUuid;
@Column(name = "login_attempt_id")
private String loginAttemptId;
public AuditLogEntity(
Long userUid,
EventType eventType,
@@ -59,7 +66,9 @@ public class AuditLogEntity extends CommonCreateEntity {
String ipAddress,
String requestUri,
String requestBody,
Long errorLogUid) {
Long errorLogUid,
UUID downloadUuid,
String loginAttemptId) {
this.userUid = userUid;
this.eventType = eventType;
this.eventStatus = eventStatus;
@@ -68,11 +77,18 @@ public class AuditLogEntity extends CommonCreateEntity {
this.requestUri = requestUri;
this.requestBody = requestBody;
this.errorLogUid = errorLogUid;
this.downloadUuid = downloadUuid;
this.loginAttemptId = loginAttemptId;
}
/** 파일 다운로드 이력 생성 */
public static AuditLogEntity forFileDownload(
Long userId, String requestUri, String menuUid, String ip, int httpStatus) {
Long userId,
String requestUri,
String menuUid,
String ip,
int httpStatus,
UUID downloadUuid) {
return new AuditLogEntity(
userId,
@@ -82,7 +98,9 @@ public class AuditLogEntity extends CommonCreateEntity {
ip,
requestUri,
null, // requestBody 없음
null // errorLogUid 없음
null, // errorLogUid 없음
downloadUuid,
null // loginAttemptId 없음
);
}

View File

@@ -90,7 +90,6 @@ public class MapSheetAnalDataInferenceGeomEntity {
private Long pnu;
@Size(max = 20)
@ColumnDefault("'0'")
@Column(name = "fit_state", length = 20)
private String fitState;
@@ -150,12 +149,6 @@ public class MapSheetAnalDataInferenceGeomEntity {
@Column(name = "file_created_dttm")
private ZonedDateTime fileCreatedDttm;
@Column(name = "pass_yn")
private String passYn;
@Column(name = "pass_yn_dttm")
private ZonedDateTime passYnDttm;
@Column(name = "result_uid")
private String resultUid;

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.postgres.entity;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@@ -186,6 +187,12 @@ public class MapSheetLearnEntity {
@Column(name = "m3_failed_jobs", nullable = false)
private int m3FailedJobs = 0;
@Column(name = "apply_status")
private String applyStatus = GukYuinStatus.PENDING.getId();
@Column(name = "apply_status_dttm")
private ZonedDateTime applyStatusDttm;
@Column(name = "uid", nullable = false)
private String uid = UUID.randomUUID().toString().replace("-", "").toUpperCase();

View File

@@ -1,6 +1,8 @@
package com.kamco.cd.kamcoback.postgres.repository.Inference;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkFacts;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.AnalResultInfo;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.BboxPointDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Dashboard;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Geom;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.SearchGeoReq;
@@ -34,7 +36,11 @@ public interface MapSheetLearnRepositoryCustom {
AnalResultInfo getInferenceResultInfo(UUID uuid);
BboxPointDto getBboxPoint(UUID uuid);
List<Dashboard> getInferenceClassCountList(UUID uuid);
Page<Geom> getInferenceGeomList(UUID uuid, SearchGeoReq searchGeoReq);
GukYuinLinkFacts findLinkFacts(UUID uuid);
}

View File

@@ -12,7 +12,10 @@ import static com.kamco.cd.kamcoback.postgres.entity.QSystemMetricEntity.systemM
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.common.utils.DateRange;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkFacts;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.AnalResultInfo;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.BboxPointDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Dashboard;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Geom;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.SearchGeoReq;
@@ -20,10 +23,14 @@ import com.kamco.cd.kamcoback.inference.dto.InferenceProgressDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceStatusDetailDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheetScope;
import com.kamco.cd.kamcoback.model.service.ModelMngService;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnEntity;
import com.kamco.cd.kamcoback.postgres.entity.QModelMngEntity;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.CaseBuilder;
@@ -319,7 +326,9 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
mapSheetLearnEntity.inferStartDttm,
mapSheetLearnEntity.inferEndDttm,
mapSheetLearnEntity.stage,
Expressions.stringTemplate("substring({0} from 1 for 8)", mapSheetLearnEntity.uid)))
Expressions.stringTemplate("substring({0} from 1 for 8)", mapSheetLearnEntity.uid),
mapSheetLearnEntity.applyYn,
mapSheetLearnEntity.applyDttm))
.from(mapSheetLearnEntity)
.leftJoin(m1)
.on(mapSheetLearnEntity.m1ModelUuid.eq(m1.uuid))
@@ -331,6 +340,30 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
.fetchOne();
}
@Override
public BboxPointDto getBboxPoint(UUID uuid) {
Expression<String> bboxGeom =
Expressions.stringTemplate(
"ST_AsGeoJSON(ST_Envelope(ST_Collect({0})))", mapSheetAnalDataInferenceGeomEntity.geom);
Expression<String> bboxCenterPoint =
Expressions.stringTemplate(
"ST_AsGeoJSON(ST_Centroid(ST_Envelope(ST_Collect({0}))))",
mapSheetAnalDataInferenceGeomEntity.geom);
return queryFactory
.select(Projections.constructor(BboxPointDto.class, bboxGeom, bboxCenterPoint))
.from(mapSheetLearnEntity)
.join(mapSheetAnalInferenceEntity)
.on(mapSheetAnalInferenceEntity.learnId.eq(mapSheetLearnEntity.id))
.join(mapSheetAnalDataInferenceEntity)
.on(mapSheetAnalDataInferenceEntity.analUid.eq(mapSheetAnalInferenceEntity.id))
.join(mapSheetAnalDataInferenceGeomEntity)
.on(mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id))
.where(mapSheetLearnEntity.uuid.eq(uuid))
.fetchOne();
}
@Override
public List<Dashboard> getInferenceClassCountList(UUID uuid) {
@@ -420,7 +453,7 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
StringExpression pnu =
Expressions.stringTemplate(
"coalesce(({0}), '')",
"nullif(({0}), '')",
JPAExpressions.select(Expressions.stringTemplate("string_agg({0}, ',')", pnuEntity.pnu))
.from(pnuEntity)
.where(pnuEntity.geo.geoUid.eq(mapSheetAnalDataInferenceGeomEntity.geoUid)));
@@ -446,7 +479,7 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
"substring({0} from 1 for 8)",
mapSheetAnalDataInferenceGeomEntity.resultUid),
pnu,
mapSheetAnalDataInferenceGeomEntity.passYn))
mapSheetAnalDataInferenceGeomEntity.fitState))
.from(mapSheetAnalInferenceEntity)
.join(mapSheetAnalDataInferenceEntity)
.on(mapSheetAnalDataInferenceEntity.analUid.eq(mapSheetAnalInferenceEntity.id))
@@ -474,4 +507,57 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
return new PageImpl<>(content, pageable, total == null ? 0L : total);
}
/**
* 국유in연동 가능여부 확인
*
* @param uuid uuid
* @return
*/
@Override
public GukYuinLinkFacts findLinkFacts(UUID uuid) {
MapSheetLearnEntity learn =
queryFactory
.selectFrom(QMapSheetLearnEntity.mapSheetLearnEntity)
.where(QMapSheetLearnEntity.mapSheetLearnEntity.uuid.eq(uuid))
.fetchOne();
if (learn == null) {
return new GukYuinLinkFacts(false, false, false, false);
}
boolean isPartScope = MapSheetScope.PART.getId().equals(learn.getMapSheetScope());
QMapSheetAnalInferenceEntity inf = QMapSheetAnalInferenceEntity.mapSheetAnalInferenceEntity;
QMapSheetLearnEntity learn2 = new QMapSheetLearnEntity("learn2");
QMapSheetLearnEntity learnQ = QMapSheetLearnEntity.mapSheetLearnEntity;
boolean hasRunningInference =
queryFactory
.selectOne()
.from(inf)
.join(learn2)
.on(inf.learnId.eq(learn2.id))
.where(
learn2.compareYyyy.eq(learn.getCompareYyyy()),
learn2.targetYyyy.eq(learn.getTargetYyyy()),
inf.analState.in("ASSIGNED", "ING"))
.fetchFirst()
!= null;
boolean hasOtherUnfinishedGukYuin =
queryFactory
.selectOne()
.from(learnQ)
.where(
learnQ.compareYyyy.eq(learn.getCompareYyyy()),
learnQ.targetYyyy.eq(learn.getTargetYyyy()),
learnQ.applyStatus.eq(GukYuinStatus.IN_PROGRESS.getId()),
learnQ.uuid.ne(learn.getUuid()))
.fetchFirst()
!= null;
return new GukYuinLinkFacts(true, isPartScope, hasRunningInference, hasOtherUnfinishedGukYuin);
}
}

View File

@@ -67,10 +67,8 @@ public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport
mapSheetAnalSttcEntity.id.classAfterCd.as("classNm"), // 앞단 CoreService 에서 한글명으로 변환
mapSheetAnalSttcEntity.classAfterCnt.sum()))
.from(mapSheetAnalInferenceEntity)
.innerJoin(mapSheetAnalDataInferenceEntity)
.on(mapSheetAnalDataInferenceEntity.analUid.eq(mapSheetAnalInferenceEntity.id))
.innerJoin(mapSheetAnalSttcEntity)
.on(mapSheetAnalSttcEntity.id.dataUid.eq(mapSheetAnalDataInferenceEntity.id))
.on(mapSheetAnalSttcEntity.id.analUid.eq(mapSheetAnalInferenceEntity.id))
.where(
mapSheetAnalInferenceEntity.uuid.eq(uuid),
mapScaleTypeSearchExpression(scale, mapSheetNum))

View File

@@ -1152,7 +1152,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
// 날짜별 전체 건수
Expression<Long> dailyTotalCnt = Expressions.numberTemplate(Long.class, "COUNT(*)");
// 전체 기간 총 건수 (윈도우 함수)
// 전체 기간 총 건수 (윈도우 함수)
Expression<Long> totalCnt = Expressions.numberTemplate(Long.class, "SUM(COUNT(*)) OVER ()");
// 상태별 카운트 (Postgres FILTER 사용)
@@ -1192,7 +1192,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
LabelingStatDto.class,
workDate,
dailyTotalCnt,
totalCnt, // 전체 일자 배정 건수
totalCnt, // 전체 일자 배정 건수
assignedCnt,
skipCnt,
completeCnt,
@@ -1233,7 +1233,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
// 날짜별 전체 건수
Expression<Long> dailyTotalCnt = Expressions.numberTemplate(Long.class, "COUNT(*)");
// 전체 기간 총 건수 (윈도우 함수)
// 전체 기간 총 건수 (윈도우 함수)
Expression<Long> totalCnt = Expressions.numberTemplate(Long.class, "SUM(COUNT(*)) OVER ()");
// 상태별 카운트 (Postgres FILTER 사용)
@@ -1277,7 +1277,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
LabelingStatDto.class,
workDate,
dailyTotalCnt,
totalCnt, // 전체 일자 배정 건수
totalCnt, // 전체 일자 배정 건수
assignedCnt,
skipCnt,
completeCnt,

View File

@@ -488,7 +488,7 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
private NumberExpression<Integer> readCount() {
return new CaseBuilder()
.when(auditLogEntity.eventType.eq(EventType.READ))
.when(auditLogEntity.eventType.in(EventType.LIST, EventType.DETAIL))
.then(1)
.otherwise(0)
.sum();
@@ -496,7 +496,7 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
private NumberExpression<Integer> cudCount() {
return new CaseBuilder()
.when(auditLogEntity.eventType.in(EventType.CREATE, EventType.UPDATE, EventType.DELETE))
.when(auditLogEntity.eventType.in(EventType.ADDED, EventType.MODIFIED, EventType.REMOVE))
.then(1)
.otherwise(0)
.sum();
@@ -504,7 +504,7 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
private NumberExpression<Integer> printCount() {
return new CaseBuilder()
.when(auditLogEntity.eventType.eq(EventType.PRINT))
.when(auditLogEntity.eventType.eq(EventType.OTHER))
.then(1)
.otherwise(0)
.sum();

View File

@@ -426,7 +426,7 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
"concat({0}, substring({1}, 1, 5))",
mapInkx5kEntity.mapidNm, mapSheetMngHstEntity.mapSheetNum),
// 튜플 방지: concat으로 문자열 생성
// 튜플 방지: concat으로 문자열 생성
Expressions.stringTemplate(
"concat('(', {0}, ',', {1}, ')')",
mapInkx5kEntity.mapidNm, mapSheetMngHstEntity.mapSheetNum),
@@ -437,7 +437,7 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
// fid 타입 주의 (Long이면 DTO도 Long으로 맞추는 걸 추천)
mapInkx5kEntity.fid, // 또는 mapInkx5kEntity.fid.intValue()
// createdDate 말고 ZonedDateTime으로 매핑된 필드로
// createdDate 말고 ZonedDateTime으로 매핑된 필드로
mapSheetMngHstEntity.createdDate, // (예시)
mapSheetMngHstEntity.syncState,
mapSheetMngHstEntity.syncTfwFileName,