import { useState } from 'react' import type { InsuranceRow } from './assetTypes' const DEFAULT_HAEWOON_API = import.meta.env.VITE_HAEWOON_API_URL || 'https://api.haewoon.or.kr/v1/insurance' // 샘플 데이터 (외부 한국해운조합 API 연동 전 데모용) const INSURANCE_DEMO_DATA: InsuranceRow[] = [ { shipName: '유조선 한라호', mmsi: '440123456', imo: '9876001', insType: 'P&I 보험', insurer: '한국P&I클럽', policyNo: 'PI-2025-1234', start: '2025-07-01', expiry: '2026-06-30', limit: '50억' }, { shipName: '화학물질운반선 제주호', mmsi: '440345678', imo: '9876002', insType: '선주책임보험', insurer: '삼성화재', policyNo: 'SF-2025-9012', start: '2025-09-16', expiry: '2026-09-15', limit: '80억' }, { shipName: '방제선 OCEAN STAR', mmsi: '440123789', imo: '9876003', insType: 'P&I 보험', insurer: '한국P&I클럽', policyNo: 'PI-2025-3456', start: '2025-11-21', expiry: '2026-11-20', limit: '120억' }, { shipName: 'LNG운반선 부산호', mmsi: '440567890', imo: '9876004', insType: '해상보험', insurer: 'DB손해보험', policyNo: 'DB-2025-7890', start: '2025-08-02', expiry: '2026-08-01', limit: '200억' }, { shipName: '유조선 백두호', mmsi: '440789012', imo: '9876005', insType: 'P&I 보험', insurer: 'SK해운보험', policyNo: 'MH-2025-5678', start: '2025-01-01', expiry: '2025-12-31', limit: '30억' }, ] function ShipInsurance() { const [apiConnected, setApiConnected] = useState(false) const [showConfig, setShowConfig] = useState(false) const [configEndpoint, setConfigEndpoint] = useState(DEFAULT_HAEWOON_API) const [configApiKey, setConfigApiKey] = useState('') const [configKeyType, setConfigKeyType] = useState('mmsi') const [configRespType, setConfigRespType] = useState('json') const [searchType, setSearchType] = useState('mmsi') const [searchVal, setSearchVal] = useState('') const [insTypeFilter, setInsTypeFilter] = useState('전체') const [viewState, setViewState] = useState<'empty' | 'loading' | 'result'>('empty') const [resultData, setResultData] = useState([]) const [lastSync, setLastSync] = useState('—') const placeholderMap: Record = { mmsi: 'MMSI 번호 입력 (예: 440123456)', imo: 'IMO 번호 입력 (예: 9876543)', shipname: '선박명 입력 (예: 한라호)', callsign: '호출부호 입력 (예: HLXX1)', } const getStatus = (expiry: string) => { const now = new Date() const exp = new Date(expiry) const daysLeft = Math.ceil((exp.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)) if (exp < now) return 'expired' as const if (daysLeft <= 30) return 'soon' as const return 'valid' as const } const handleSaveConfig = () => { if (!configApiKey) { alert('API Key를 입력하세요.'); return } setShowConfig(false) alert('API 설정이 저장되었습니다.') } const handleTestConnect = async () => { await new Promise(r => setTimeout(r, 1200)) alert('⚠ API Key가 설정되지 않았습니다.\n[API 설정] 버튼에서 한국해운조합 API Key를 먼저 등록하세요.') } const loadDemoData = () => { setResultData(INSURANCE_DEMO_DATA) setViewState('result') setApiConnected(false) setLastSync(new Date().toLocaleString('ko-KR')) } const handleQuery = async () => { if (!searchVal.trim()) { alert('조회값을 입력하세요.'); return } setViewState('loading') await new Promise(r => setTimeout(r, 900)) loadDemoData() } const handleBatchQuery = async () => { setViewState('loading') await new Promise(r => setTimeout(r, 1400)) loadDemoData() } const handleFullSync = async () => { setLastSync('동기화 중...') await new Promise(r => setTimeout(r, 1000)) setLastSync(new Date().toLocaleString('ko-KR')) alert('전체 동기화는 API 연동 후 활성화됩니다.') } // summary computation const validCount = resultData.filter(r => getStatus(r.expiry) !== 'expired').length const soonList = resultData.filter(r => getStatus(r.expiry) === 'soon') const expiredList = resultData.filter(r => getStatus(r.expiry) === 'expired') return (
{/* ── 헤더 ── */}
🛡 선박 보험정보 조회
{apiConnected ? 'API 연결됨' : 'API 미연결'}
한국해운조합(KSA) Open API 연동 · 선박 P&I 보험 및 선주 책임보험 실시간 조회
{/* ── API 설정 패널 ── */} {showConfig && (
⚙ 한국해운조합 API 연동 설정
setConfigEndpoint(e.target.value)} placeholder="https://api.haewoon.or.kr/v1/..." className="w-full px-3 py-2 bg-bg-0 border border-border rounded-sm font-mono text-xs outline-none box-border" />
setConfigApiKey(e.target.value)} placeholder="발급받은 API Key 입력" className="w-full px-3 py-2 bg-bg-0 border border-border rounded-sm font-mono text-xs outline-none box-border" />
{/* API 연동 안내 */}
📋 한국해운조합 API 발급 안내
• 한국해운조합 공공데이터포털 또는 해운조합 IT지원팀에 API 키 신청
• 해양경찰청 기관 계정으로 신청 시 전용 엔드포인트 및 키 발급
• 조회 가능 데이터: P&I 보험, 선주책임보험, 해상보험 가입 여부, 증권번호, 보험기간, 보상한도
)} {/* ── 검색 영역 ── */}
🔍 보험정보 조회
setSearchVal(e.target.value)} placeholder={placeholderMap[searchType]} className="w-full px-3.5 py-2 bg-bg-0 border border-border rounded-sm font-mono text-[13px] outline-none box-border" />
{/* ── 결과 영역 ── */} {/* 초기 안내 상태 */} {viewState === 'empty' && (
🛡
한국해운조합 API 연동 대기 중
API 설정에서 한국해운조합 API Key를 등록하거나
MMSI·IMO·선박명으로 직접 조회하세요.
자산목록 일괄조회 시 등록된 방제자산 전체의 보험 현황을 한번에 확인할 수 있습니다.
)} {/* 로딩 */} {viewState === 'loading' && (
한국해운조합 API 조회 중...
)} {/* 결과 테이블 */} {viewState === 'result' && ( <> {/* 요약 카드 */}
{[ { label: '전체', val: resultData.length, color: 'var(--cyan)', bg: 'rgba(6,182,212,.08)' }, { label: '유효', val: validCount, color: 'var(--green)', bg: 'rgba(34,197,94,.08)' }, { label: '만료임박(30일)', val: soonList.length, color: 'var(--yellow)', bg: 'rgba(234,179,8,.08)' }, { label: '만료/미가입', val: resultData.length - validCount, color: 'var(--red)', bg: 'rgba(239,68,68,.08)' }, ].map((c, i) => (
{c.val}
{c.label}
))}
{/* 테이블 */}
조회 결과 {resultData.length}
{[ { label: '선박명', align: 'left' }, { label: 'MMSI', align: 'center' }, { label: 'IMO', align: 'center' }, { label: '보험종류', align: 'center' }, { label: '보험사', align: 'center' }, { label: '증권번호', align: 'center' }, { label: '보험기간', align: 'center' }, { label: '보상한도', align: 'right' }, { label: '상태', align: 'center' }, ].map((h, i) => ( ))} {resultData.map((r, i) => { const st = getStatus(r.expiry) const isExp = st === 'expired' const isSoon = st === 'soon' return ( ) })}
{h.label}
{r.shipName} {r.mmsi || '—'} {r.imo || '—'} {r.insType} {r.insurer} {r.policyNo} {r.start} ~ {r.expiry} {r.limit} {isExp ? '만료' : isSoon ? '만료임박' : '유효'}
{/* 경고 */} {(expiredList.length > 0 || soonList.length > 0) && (
{expiredList.length > 0 && ( <>⛔ 만료 {expiredList.length}건: {expiredList.map(r => r.shipName).join(', ')}
)} {soonList.length > 0 && ( <>⚠ 만료임박(30일) {soonList.length}건: {soonList.map(r => r.shipName).join(', ')} )}
)} )} {/* ── API 연동 정보 푸터 ── */}
데이터 출처: 한국해운조합(KSA) · haewoon.or.kr
연동 방식: REST API (JSON) · 실시간 조회 · 캐시 TTL 1시간
마지막 동기화: {lastSync}
) } export default ShipInsurance