ship-gis/src/api/aisTargetApi.js
htlee 2d871306ed feat: 선종 필터 패널 재구현 + signalKindCode 백엔드 응답 우선
- ShipFilterPanel: 선종별 표시/숨김 토글 (전체 ON/OFF 포함)
- Sidebar gnb1에 ShipFilterPanel 연결
- aisTargetApi: 백엔드 signalKindCode 필드 우선, 없으면 vesselType fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 07:21:37 +09:00

138 lines
3.7 KiB
JavaScript

/**
* AIS Target API 클라이언트
* SNP-Batch 서버의 AIS 데이터를 HTTP 폴링으로 조회
*/
import axios from 'axios';
// dev: Vite 프록시 (/snp-api → 211.208.115.83:8041)
// prod: 환경변수로 직접 지정
const BASE_URL = import.meta.env.VITE_API_URL || '/snp-api';
/**
* AIS 타겟 검색 (최근 N분 데이터)
* @param {number} minutes - 조회 기간 (분)
* @returns {Promise<Array>} AIS 타겟 데이터 배열
*/
export async function searchAisTargets(minutes = 60) {
const res = await axios.get(`${BASE_URL}/api/ais-target/search`, {
params: { minutes },
timeout: 30000,
});
return res.data.data || [];
}
/**
* AIS API 응답 → shipStore feature 객체로 변환
*
* API 응답 필드:
* mmsi, imo, name, callsign, vesselType, lat, lon,
* heading, sog, cog, rot, length, width, draught,
* destination, eta, status, messageTimestamp, receivedDate,
* source, classType
*
* @param {Object} aisTarget - API 응답 단건
* @returns {Object} shipStore 호환 feature 객체
*/
export function aisTargetToFeature(aisTarget) {
const mmsi = String(aisTarget.mmsi || '');
// 백엔드에서 signalKindCode를 직접 제공, 없으면 vesselType 기반 fallback
const signalKindCode = aisTarget.signalKindCode || mapVesselTypeToKindCode(aisTarget.vesselType);
return {
// 고유 식별자 (AIS 신호원 코드 + MMSI)
featureId: `000001${mmsi}`,
// 기본 식별 정보
targetId: mmsi,
originalTargetId: mmsi,
signalSourceCode: '000001', // AIS
shipName: aisTarget.name || '',
shipType: aisTarget.vesselType || '',
// 위치 정보
longitude: aisTarget.lon || 0,
latitude: aisTarget.lat || 0,
// 항해 정보
sog: aisTarget.sog || 0,
cog: aisTarget.cog || 0,
// 시간 정보
receivedTime: formatTimestamp(aisTarget.messageTimestamp),
// 선종 코드
signalKindCode,
// 상태 플래그
lost: false,
integrate: false,
isPriority: true,
// 위험물 카테고리
hazardousCategory: '',
// 국적 코드
nationalCode: '',
// IMO 번호
imo: String(aisTarget.imo || ''),
// 흘수
draught: String(aisTarget.draught || ''),
// 선박 크기
dimA: '',
dimB: '',
dimC: '',
dimD: '',
// AVETDR 신호장비 플래그
ais: '1',
vpass: '',
enav: '',
vtsAis: '',
dMfHf: '',
vtsRadar: '',
// 추가 메타데이터
callsign: aisTarget.callsign || '',
heading: aisTarget.heading || 0,
destination: aisTarget.destination || '',
status: aisTarget.status || '',
length: aisTarget.length || 0,
width: aisTarget.width || 0,
_raw: null,
};
}
/**
* vesselType 문자열 → 선종 코드 매핑
*/
function mapVesselTypeToKindCode(vesselType) {
if (!vesselType) return '000027'; // 일반
const vt = vesselType.toLowerCase();
if (vt.includes('fishing')) return '000020'; // 어선
if (vt.includes('passenger')) return '000022'; // 여객선
if (vt.includes('cargo')) return '000023'; // 화물선
if (vt.includes('tanker')) return '000024'; // 유조선
if (vt.includes('military') || vt.includes('law enforcement')) return '000025'; // 관공선
if (vt.includes('tug') || vt.includes('pilot') || vt.includes('search')) return '000025'; // 관공선
return '000027'; // 일반
}
/**
* ISO 타임스탬프 → "YYYYMMDDHHmmss" 형식 변환
*/
function formatTimestamp(isoString) {
if (!isoString) return '';
try {
const d = new Date(isoString);
const pad = (n) => String(n).padStart(2, '0');
return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
} catch {
return '';
}
}