diff --git a/docs/RELEASE-NOTES.md b/docs/RELEASE-NOTES.md index ad36c9b..61c6ca5 100644 --- a/docs/RELEASE-NOTES.md +++ b/docs/RELEASE-NOTES.md @@ -28,6 +28,7 @@ - 배치 작업 목록 UX 개선: 상태 필터, 카드/테이블 뷰, 정렬, 실행 중 강조 (#33) - 재시도 초과 레코드 초기화 API/UI 추가 - IMO 기반 Risk 상세 조회 bypass API 추가 (#39) +- 배치 작업 목록 한글 표시명 추가 (#40) ### 수정 - 자동 재수집 JobParameter 오버플로우 수정 (VARCHAR 2500 제한 해결) diff --git a/frontend/src/api/batchApi.ts b/frontend/src/api/batchApi.ts index 9ccb570..30e45b4 100644 --- a/frontend/src/api/batchApi.ts +++ b/frontend/src/api/batchApi.ts @@ -235,6 +235,7 @@ export interface LastExecution { export interface JobDetailDto { jobName: string; + displayName: string | null; lastExecution: LastExecution | null; scheduleCron: string | null; } diff --git a/frontend/src/pages/Jobs.tsx b/frontend/src/pages/Jobs.tsx index 00cd8ed..e68e5a8 100644 --- a/frontend/src/pages/Jobs.tsx +++ b/frontend/src/pages/Jobs.tsx @@ -75,9 +75,16 @@ export default function Jobs() { usePoller(loadJobs, POLLING_INTERVAL); + /** displayName 우선, 없으면 jobName */ + const getJobLabel = useCallback((job: JobDetailDto) => job.displayName || job.jobName, []); + const statusCounts = useMemo(() => { const searchFiltered = searchTerm.trim() - ? jobs.filter((job) => job.jobName.toLowerCase().includes(searchTerm.toLowerCase())) + ? jobs.filter((job) => { + const term = searchTerm.toLowerCase(); + return job.jobName.toLowerCase().includes(term) + || (job.displayName?.toLowerCase().includes(term) ?? false); + }) : jobs; return STATUS_TABS.reduce>( @@ -94,14 +101,17 @@ export default function Jobs() { if (searchTerm.trim()) { const term = searchTerm.toLowerCase(); - result = result.filter((job) => job.jobName.toLowerCase().includes(term)); + result = result.filter((job) => + job.jobName.toLowerCase().includes(term) + || (job.displayName?.toLowerCase().includes(term) ?? false), + ); } result = result.filter((job) => matchesStatusFilter(job, statusFilter)); result = [...result].sort((a, b) => { if (sortKey === 'name') { - return a.jobName.localeCompare(b.jobName); + return getJobLabel(a).localeCompare(getJobLabel(b)); } if (sortKey === 'recent') { const aTime = a.lastExecution?.startTime ? new Date(a.lastExecution.startTime).getTime() : 0; @@ -302,9 +312,14 @@ export default function Jobs() { ${isRunning ? 'border-l-4 border-emerald-500' : ''}`} >
-

- {job.jobName} -

+
+

+ {getJobLabel(job)} +

+ {job.displayName && ( +

{job.jobName}

+ )} +
{isRunning && ( @@ -421,7 +436,12 @@ export default function Jobs() { {isRunning && ( )} - {job.jobName} +
+ {getJobLabel(job)} + {job.displayName && ( +

{job.jobName}

+ )} +
@@ -489,7 +509,7 @@ export default function Jobs() { >

작업 실행 확인

- "{targetJob}" 작업을 실행하시겠습니까? + "{jobs.find((j) => j.jobName === targetJob)?.displayName || targetJob}" 작업을 실행하시겠습니까?

diff --git a/src/main/java/com/snp/batch/global/dto/JobDetailDto.java b/src/main/java/com/snp/batch/global/dto/JobDetailDto.java index 9883b2a..63f96ad 100644 --- a/src/main/java/com/snp/batch/global/dto/JobDetailDto.java +++ b/src/main/java/com/snp/batch/global/dto/JobDetailDto.java @@ -14,6 +14,7 @@ import java.time.LocalDateTime; public class JobDetailDto { private String jobName; + private String displayName; private LastExecution lastExecution; private String scheduleCron; diff --git a/src/main/java/com/snp/batch/service/BatchService.java b/src/main/java/com/snp/batch/service/BatchService.java index c329c26..227b85d 100644 --- a/src/main/java/com/snp/batch/service/BatchService.java +++ b/src/main/java/com/snp/batch/service/BatchService.java @@ -37,6 +37,40 @@ import java.util.stream.Collectors; @Service public class BatchService { + /** Job Bean 이름 → 한글 표시명 매핑 */ + private static final Map JOB_DISPLAY_NAMES = Map.ofEntries( + // AIS + Map.entry("aisTargetImportJob", "AIS 선박위치 수집(1분 주기)"), + Map.entry("aisTargetDbSyncJob", "AIS 선박위치 DB 적재(15분 주기)"), + // 공통코드 + Map.entry("FlagCodeImportJob", "선박 국가코드 수집"), + Map.entry("Stat5CodeImportJob", "선박 유형코드 수집"), + // Compliance + Map.entry("ComplianceImportRangeJob", "선박 제재 정보 수집"), + Map.entry("CompanyComplianceImportRangeJob", "회사 제재 정보 수집"), + // Event + Map.entry("EventImportJob", "해양 사건/사고 수집"), + // Port + Map.entry("PortImportJob", "항구 시설 수집"), + // Movement + Map.entry("AnchorageCallsRangeImportJob", "정박지 기항 이력 수집"), + Map.entry("BerthCallsRangeImportJob", "선석 기항 이력 수집"), + Map.entry("CurrentlyAtRangeImportJob", "현재 위치 이력 수집"), + Map.entry("DestinationsRangeImportJob", "목적지 이력 수집"), + Map.entry("PortCallsRangeImportJob", "항구 기항 이력 수집"), + Map.entry("STSOperationRangeImportJob", "STS 작업 이력 수집"), + Map.entry("TerminalCallsRangeImportJob", "터미널 기항 이력 수집"), + Map.entry("TransitsRangeImportJob", "항해 이력 수집"), + // PSC + Map.entry("PSCDetailImportJob", "PSC 선박 검사 수집"), + // Risk + Map.entry("RiskRangeImportJob", "선박 위험지표 수집"), + // Ship + Map.entry("ShipDetailUpdateJob", "선박 제원정보 수집"), + // Infra + Map.entry("partitionManagerJob", "AIS 파티션 테이블 생성/관리") + ); + private final JobLauncher jobLauncher; private final JobExplorer jobExplorer; private final JobOperator jobOperator; @@ -852,6 +886,7 @@ public class BatchService { return JobDetailDto.builder() .jobName(jobName) + .displayName(JOB_DISPLAY_NAMES.get(jobName)) .lastExecution(lastExec) .scheduleCron(cronMap.get(jobName)) .build();