Merge pull request 'feat(ui): 배치 작업 목록 한글 표시명 추가 (#40)' (#43) from feature/ISSUE-40-job-display-name into develop
This commit is contained in:
커밋
a9e8df7e89
@ -28,6 +28,7 @@
|
||||
- 배치 작업 목록 UX 개선: 상태 필터, 카드/테이블 뷰, 정렬, 실행 중 강조 (#33)
|
||||
- 재시도 초과 레코드 초기화 API/UI 추가
|
||||
- IMO 기반 Risk 상세 조회 bypass API 추가 (#39)
|
||||
- 배치 작업 목록 한글 표시명 추가 (#40)
|
||||
|
||||
### 수정
|
||||
- 자동 재수집 JobParameter 오버플로우 수정 (VARCHAR 2500 제한 해결)
|
||||
|
||||
@ -235,6 +235,7 @@ export interface LastExecution {
|
||||
|
||||
export interface JobDetailDto {
|
||||
jobName: string;
|
||||
displayName: string | null;
|
||||
lastExecution: LastExecution | null;
|
||||
scheduleCron: string | null;
|
||||
}
|
||||
|
||||
@ -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<Record<StatusFilterKey, number>>(
|
||||
@ -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' : ''}`}
|
||||
>
|
||||
<div className="flex items-start justify-between mb-3">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-wing-text break-all leading-tight">
|
||||
{job.jobName}
|
||||
{getJobLabel(job)}
|
||||
</h3>
|
||||
{job.displayName && (
|
||||
<p className="text-xs text-wing-muted mt-0.5">{job.jobName}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 ml-2 shrink-0">
|
||||
{isRunning && (
|
||||
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
|
||||
@ -421,7 +436,12 @@ export default function Jobs() {
|
||||
{isRunning && (
|
||||
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse shrink-0" />
|
||||
)}
|
||||
{job.jobName}
|
||||
<div>
|
||||
<span>{getJobLabel(job)}</span>
|
||||
{job.displayName && (
|
||||
<p className="text-xs text-wing-muted font-normal">{job.jobName}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
@ -489,7 +509,7 @@ export default function Jobs() {
|
||||
>
|
||||
<h3 className="text-lg font-semibold text-wing-text mb-2">작업 실행 확인</h3>
|
||||
<p className="text-wing-muted text-sm mb-4">
|
||||
"{targetJob}" 작업을 실행하시겠습니까?
|
||||
"{jobs.find((j) => j.jobName === targetJob)?.displayName || targetJob}" 작업을 실행하시겠습니까?
|
||||
</p>
|
||||
|
||||
<div className="flex justify-end gap-3 mt-6">
|
||||
|
||||
@ -14,6 +14,7 @@ import java.time.LocalDateTime;
|
||||
public class JobDetailDto {
|
||||
|
||||
private String jobName;
|
||||
private String displayName;
|
||||
private LastExecution lastExecution;
|
||||
private String scheduleCron;
|
||||
|
||||
|
||||
@ -37,6 +37,40 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class BatchService {
|
||||
|
||||
/** Job Bean 이름 → 한글 표시명 매핑 */
|
||||
private static final Map<String, String> 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();
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user