diff --git a/src/app/monitoring/page.tsx b/src/app/monitoring/page.tsx index ae345cc..c66e978 100644 --- a/src/app/monitoring/page.tsx +++ b/src/app/monitoring/page.tsx @@ -5,6 +5,7 @@ import { useRouter, useSearchParams } from 'next/navigation'; import { useAuthStore } from '@/lib/authStore'; import { useTheme } from '@/contexts/ThemeContext'; import { useVehicleStore, Vehicle } from '@/lib/vehicleStore'; +import { useCompanyStore } from '@/lib/companyStore'; import { MinusIcon, PlusIcon, @@ -14,7 +15,10 @@ import { TruckIcon, ChartBarIcon, ExclamationCircleIcon, - MagnifyingGlassIcon + MagnifyingGlassIcon, + MapIcon, + MagnifyingGlassPlusIcon, + MagnifyingGlassMinusIcon } from '@heroicons/react/24/outline'; import PageHeader from '@/components/common/PageHeader'; import CarMap from '@/components/map/CarMap'; @@ -126,14 +130,9 @@ function VehicleSidebar({ useEffect(() => { if (selectedVehicle) { - console.log('선택된 차량:', selectedVehicle); - console.log('차량 상세 정보:', selectedVehicleDetails); - console.log('스토어의 모든 차량:', storeVehicles); - const matchingVehicle = storeVehicles.find(v => v.id === selectedVehicle || v.mdn === selectedVehicle ); - console.log('스토어에서 찾은 차량:', matchingVehicle); } }, [selectedVehicle, selectedVehicleDetails, storeVehicles]); @@ -151,16 +150,6 @@ function VehicleSidebar({ -
@@ -217,7 +206,7 @@ function VehicleSidebar({ )}
- {selectedVehicleData && ( + {selectedVehicleData && selectedCars.length > 0 && (

@@ -279,21 +268,25 @@ interface RouteGroup { function MonitoringContent() { const router = useRouter(); const searchParams = useSearchParams(); - const { isAuthenticated } = useAuthStore(); + const { isAuthenticated, userProfile } = useAuthStore(); + const { companyId } = useCompanyStore(); const { currentTheme } = useTheme(); const [wsConnected, setWsConnected] = useState(false); + const [wsConnectingState, setWsConnectingState] = useState<'connecting' | 'connected' | 'disconnected'>('disconnected'); const [carLocations, setCarLocations] = useState([]); const [currentPositions, setCurrentPositions] = useState([]); const [showRoute, setShowRoute] = useState(false); const [routePoints, setRoutePoints] = useState([]); const wsRef = useRef(null); - const [companyId, setCompanyId] = useState('1'); + const [currentCompanyId, setCurrentCompanyId] = useState(companyId || '1'); const [selectedCars, setSelectedCars] = useState([]); const [showAllCars, setShowAllCars] = useState(true); const animationRef = useRef(null); const [dataReceived, setDataReceived] = useState(false); const [lastUpdateTime, setLastUpdateTime] = useState(''); const [error, setError] = useState(null); + const [selectedCarsOrder, setSelectedCarsOrder] = useState([]); + const [lastSelectedCar, setLastSelectedCar] = useState(null); const [mapSettings, setMapSettings] = useState({ latitude: 36.5, @@ -321,6 +314,9 @@ function MonitoringContent() { const [selectedVehicleDetails, setSelectedVehicleDetails] = useState(null); + // 선택된 차량의 상세 정보만 표시할 차량 ID + const [displayVehicleId, setDisplayVehicleId] = useState(null); + const handleMapDrag = (center: {lat: number, lng: number}, zoom: number) => { setMapSettings(prev => ({ ...prev, @@ -364,7 +360,6 @@ function MonitoringContent() { const initialPositions = assignCarColors(carLocations); setCurrentPositions(initialPositions); - console.log('초기 위치 설정 완료', initialPositions); animationRef.current = setInterval(() => { setCurrentPositions(prev => { @@ -393,6 +388,12 @@ function MonitoringContent() { } }, [carLocations]); + useEffect(() => { + if (companyId) { + setCurrentCompanyId(companyId); + } + }, [companyId]); + useEffect(() => { connectWebSocket(); @@ -407,12 +408,12 @@ function MonitoringContent() { }, []); const handleSubscribe = useCallback(() => { - if (wsRef.current && companyId && wsConnected) { - console.log('구독 요청 전송:', companyId); + if (wsRef.current && currentCompanyId && wsConnected) { + console.log('구독 요청 전송:', currentCompanyId); const subscribeMsg = JSON.stringify({ type: 'subscribe', - companyId: companyId + companyId: currentCompanyId }); wsRef.current.send(subscribeMsg); @@ -420,35 +421,32 @@ function MonitoringContent() { console.warn('WebSocket이 연결되지 않았거나 회사 ID가 없습니다'); setError('WebSocket이 연결되지 않았거나 회사 ID가 없습니다'); } - }, [companyId, wsConnected]); + }, [currentCompanyId, wsConnected]); useEffect(() => { - if (wsConnected && companyId) { - console.log('WebSocket 연결됨, 자동 구독 시도:', companyId); + if (wsConnected && currentCompanyId) { + console.log('WebSocket 연결됨, 자동 구독 시도:', currentCompanyId); handleSubscribe(); } - }, [wsConnected, companyId, handleSubscribe]); + }, [wsConnected, currentCompanyId, handleSubscribe]); const connectWebSocket = () => { try { - const wsUrl = `${process.env.NEXT_PUBLIC_API_WEBSOKET_URL}/ws`; + const wsUrl = `${process.env.NEXT_PUBLIC_API_WEBSOCKET_URL}/ws`; - console.log(`WebSocket 연결 시도: ${wsUrl}`); + setWsConnectingState('connecting'); const ws = new WebSocket(wsUrl); wsRef.current = ws; ws.onopen = () => { - console.log('WebSocket 연결됨', new Date().toLocaleString()); setWsConnected(true); + setWsConnectingState('connected'); setError(null); }; ws.onmessage = (event) => { try { - console.log('데이터 수신:', new Date().toLocaleString()); - const data = JSON.parse(event.data); - console.log('파싱된 데이터:', data); if (Array.isArray(data)) { const isValidData = data.every(item => @@ -466,50 +464,32 @@ function MonitoringContent() { if (isValidData) { processReceivedData(data); - } else { - console.error('데이터 형식이 올바르지 않습니다:', data); - setError('데이터 형식이 올바르지 않습니다'); } - } else { - console.error('데이터가 배열이 아닙니다:', data); - setError('데이터가 배열이 아닙니다'); } } catch (error) { - console.error('메시지 파싱 에러:', error); - setError(`메시지 파싱 에러: ${error}`); } }; ws.onclose = () => { setWsConnected(false); - console.log('WebSocket 연결 종료', new Date().toLocaleString()); - setTimeout(connectWebSocket, 5000); + setWsConnectingState('disconnected'); }; ws.onerror = (error) => { - console.error('WebSocket 에러:', error); - setError(`WebSocket 에러: ${error}`); + setWsConnectingState('disconnected'); }; } catch (error) { - console.error('WebSocket 연결 시도 중 예외 발생:', error); - setError(`WebSocket 연결 시도 중 예외 발생: ${error}`); + setWsConnectingState('disconnected'); } }; const processReceivedData = (data: CarLocation[]) => { try { - console.log('데이터 처리 중...', { - 차량수: data.length, - 첫차량: data[0]?.carId, - 데이터포인트: data[0]?.locations.length - }); - setCarLocations(data); setDataReceived(true); setLastUpdateTime(new Date().toLocaleString()); setError(null); } catch (error) { - console.error('데이터 처리 중 오류:', error); setError(`데이터 처리 중 오류: ${error}`); } }; @@ -543,12 +523,25 @@ function MonitoringContent() { const toggleCarSelection = useCallback((carId: string) => { setSelectedCars(prev => { if (prev.includes(carId)) { - setSelectedVehicleDetails(null); - return prev.filter(id => id !== carId); + // 차량 선택 취소 + const newSelectedCars = prev.filter(id => id !== carId); + + // 현재 표시 중인 차량이 취소되는 차량이라면 + if (displayVehicleId === carId) { + setDisplayVehicleId(null); + setSelectedVehicleDetails(null); + } + + return newSelectedCars; } else { + // 차량 선택 - 항상 새 차량 정보를 표시 + setDisplayVehicleId(carId); + + // 현재 차량의 정보를 상세 정보로 설정 const vehicleInfo = storeVehicles.find(v => v.id === carId || v.mdn === carId); setSelectedVehicleDetails(vehicleInfo || null); - return [carId]; + + return [...prev, carId]; // 기존 선택 유지하고 새 차량 추가 } }); }, [storeVehicles]); @@ -629,16 +622,27 @@ function MonitoringContent() {
- - - {wsConnected ? '연결됨' : '연결 끊김'} - + {wsConnectingState === 'connecting' ? ( + <> +
+ 연결 중 + + ) : ( + <> + + + {wsConnectingState === 'connected' ? '연결됨' : '연결 끊김'} + + + )}
@@ -686,7 +690,7 @@ function MonitoringContent() { className={`w-7 h-7 flex items-center justify-center rounded-md ${currentTheme.hoverBg} transition-colors`} title="축소" > - + {mapSettings.zoom}
@@ -722,7 +726,24 @@ function MonitoringContent() {

-
+
+ +