kcg-monitoring/frontend/src/services/vesselTrack.ts
htlee 48c15f9c33 feat: AI 분석 패널 개선 — 항적 API + 범례 + 스크롤 + 중복 제거
- Backend: mmsi별 최신 1건만 반환 (중복 제거)
- 항적: signal-batch tracks API 호출 (6시간, 5분 캐시)
- 범례: 위험도 점수 기준 상세 (위치/조업/AIS/허가, 0~100)
- 선박 목록: maxHeight 300px 스크롤 가능
- 선박 클릭 → flyTo + 항적 표시 + 근거 상세

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 15:42:13 +09:00

40 lines
1.2 KiB
TypeScript

const SIGNAL_BATCH_BASE = '/signal-batch';
interface TrackResponse {
vesselId: string;
geometry: [number, number][];
speeds: number[];
timestamps: string[];
pointCount: number;
totalDistance: number;
shipName: string;
}
// mmsi별 캐시 (TTL 5분)
const trackCache = new Map<string, { time: number; coords: [number, number][] }>();
const CACHE_TTL = 5 * 60_000;
export async function fetchVesselTrack(mmsi: string, hours: number = 6): Promise<[number, number][]> {
const cached = trackCache.get(mmsi);
if (cached && Date.now() - cached.time < CACHE_TTL) return cached.coords;
const endTime = new Date().toISOString();
const startTime = new Date(Date.now() - hours * 3600_000).toISOString();
try {
const res = await fetch(`${SIGNAL_BATCH_BASE}/api/v2/tracks/vessels`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', accept: 'application/json' },
body: JSON.stringify({ startTime, endTime, vessels: [mmsi] }),
});
if (!res.ok) return [];
const data: TrackResponse[] = await res.json();
if (!data.length || !data[0].geometry?.length) return [];
const coords = data[0].geometry;
trackCache.set(mmsi, { time: Date.now(), coords });
return coords;
} catch {
return [];
}
}