From 4e6e6392c6c0ac739a4f529bebaae54ae71211a5 Mon Sep 17 00:00:00 2001 From: htlee Date: Fri, 20 Feb 2026 15:36:42 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=ED=95=AD=EC=A0=81=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=20500=20=EC=97=90=EB=9F=AC=20+=20=EB=A6=AC=ED=94=8C=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=20=EC=BF=BC=EB=A6=AC=20=EB=AC=B4=EB=B0=98=EC=9D=91=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - gisApi: mmsiList → vessels 필드명 백엔드 DTO 일치 - ReplaySetupPanel: datetime 포맷 ISO 'T' 유지 (백엔드 @JsonFormat 호환) - replayWebSocket: STOMP 에러/응답 로깅 강화 Co-Authored-By: Claude Opus 4.6 --- frontend/src/api/gisApi.ts | 2 +- .../components/ReplaySetupPanel.tsx | 7 ++++--- .../viewport-replay/services/replayWebSocket.ts | 15 +++++++++++++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/frontend/src/api/gisApi.ts b/frontend/src/api/gisApi.ts index fd7129d..c1d260a 100644 --- a/frontend/src/api/gisApi.ts +++ b/frontend/src/api/gisApi.ts @@ -51,7 +51,7 @@ export const gisApi = { }, getVesselTracks(mmsiList: string[], startTime: string, endTime: string): Promise { - return postJson('/api/v2/tracks/vessels', { mmsiList, startTime, endTime }) + return postJson('/api/v2/tracks/vessels', { vessels: mmsiList, startTime, endTime }) }, getRecentPositions(minutes = 10): Promise { diff --git a/frontend/src/features/viewport-replay/components/ReplaySetupPanel.tsx b/frontend/src/features/viewport-replay/components/ReplaySetupPanel.tsx index d4c4199..a102561 100644 --- a/frontend/src/features/viewport-replay/components/ReplaySetupPanel.tsx +++ b/frontend/src/features/viewport-replay/components/ReplaySetupPanel.tsx @@ -40,9 +40,10 @@ export default function ReplaySetupPanel({ map }: ReplaySetupPanelProps) { const handleQuery = () => { if (!map) return const bounds = getViewportBounds(map) - const zoom = map.getZoom() - const startISO = startTime.replace('T', ' ') + ':00' - const endISO = endTime.replace('T', ' ') + ':00' + const zoom = Math.round(map.getZoom()) + // 백엔드 @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") 형식 유지 + const startISO = startTime + ':00' + const endISO = endTime + ':00' replayWebSocket.executeQuery(startISO, endISO, bounds, zoom) } diff --git a/frontend/src/features/viewport-replay/services/replayWebSocket.ts b/frontend/src/features/viewport-replay/services/replayWebSocket.ts index cc47c16..1be5ae6 100644 --- a/frontend/src/features/viewport-replay/services/replayWebSocket.ts +++ b/frontend/src/features/viewport-replay/services/replayWebSocket.ts @@ -94,12 +94,16 @@ class ReplayWebSocketService { }, onStompError: (frame) => { - console.error('[ReplayWS] STOMP error:', frame.headers.message) + console.error('[ReplayWS] STOMP error:', frame.headers.message, frame.body) + if (replayStore.querying) { + replayStore.completeQuery() + } replayStore.setConnectionState('error') reject(new Error(frame.headers.message)) }, - onWebSocketError: () => { + onWebSocketError: (evt) => { + console.error('[ReplayWS] WebSocket error:', evt) replayStore.setConnectionState('error') reject(new Error('WebSocket connection failed')) }, @@ -158,6 +162,7 @@ class ReplayWebSocketService { zoomLevel, } + console.log('[ReplayWS] Sending query:', request.startTime, '~', request.endTime, 'zoom:', request.zoomLevel) this.client.publish({ destination: '/app/tracks/query', body: JSON.stringify(request), @@ -196,9 +201,15 @@ class ReplayWebSocketService { this.client.subscribe('/user/queue/tracks/response', (msg: IMessage) => { try { const data = JSON.parse(msg.body) + console.log('[ReplayWS] Response:', data.status, data.queryId) if (data.queryId) { this.currentQueryId = data.queryId } + if (data.status === 'ERROR') { + console.error('[ReplayWS] Query error:', data.message) + this.clearQueryTimeout() + useReplayStore.getState().completeQuery() + } } catch { /* ignore */ } }) }