From 7564f429182d27fb968de0fbd296b201cf98f683 Mon Sep 17 00:00:00 2001 From: Nan Kyung Lee Date: Tue, 17 Mar 2026 10:20:10 +0900 Subject: [PATCH] =?UTF-8?q?feat(aerial):=20=EC=9C=84=EC=84=B1=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EB=AA=A9=EB=A1=9D/=ED=9E=88=EC=8A=A4=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=20=EC=A7=80=EB=8F=84=20=ED=83=AD=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - πŸ“‹ μš”μ²­ λͺ©λ‘ / πŸ—Ί 촬영 νžˆμŠ€ν† λ¦¬ 지도 νƒ­ ν† κΈ€ - 지도 λ·°: MapLibre에 촬영 ꡬ역 μ‚¬κ°ν˜• 폴리곀 ν‘œμ‹œ μƒνƒœλ³„ 색상 (μ΄¬μ˜μ€‘=λ…Έλž‘, λŒ€κΈ°=νŒŒλž‘, μ™„λ£Œ=초둝, μ·¨μ†Œ=λΉ¨κ°•) - 쒌츑 μ˜€λ²„λ ˆμ΄: μš”μ²­ 리슀트 (ID, ꡬ역, μœ„μ„±, 해상도, μƒνƒœ) - 우츑 μ˜€λ²„λ ˆμ΄: μƒνƒœλ³„ λ²”λ‘€ + 총 건수 - parseCoord 헬퍼: "33.24Β°N 126.50Β°E" β†’ {lat, lon} νŒŒμ‹± Co-Authored-By: Claude Opus 4.6 (1M context) --- .../aerial/components/SatelliteRequest.tsx | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/frontend/src/tabs/aerial/components/SatelliteRequest.tsx b/frontend/src/tabs/aerial/components/SatelliteRequest.tsx index 2edead9..1baf214 100644 --- a/frontend/src/tabs/aerial/components/SatelliteRequest.tsx +++ b/frontend/src/tabs/aerial/components/SatelliteRequest.tsx @@ -82,10 +82,18 @@ const SAT_MAP_STYLE: StyleSpecification = { layers: [{ id: 'carto-dark-layer', type: 'raster', source: 'carto-dark', minzoom: 0, maxzoom: 22 }], } +/** μ’Œν‘œ λ¬Έμžμ—΄ νŒŒμ‹± ("33.24Β°N 126.50Β°E" β†’ {lat, lon}) */ +function parseCoord(coordStr: string): { lat: number; lon: number } | null { + const m = coordStr.match(/([\d.]+)Β°N\s+([\d.]+)Β°E/) + if (!m) return null + return { lat: parseFloat(m[1]), lon: parseFloat(m[2]) } +} + type SatModalPhase = 'none' | 'provider' | 'blacksky' | 'up42' export function SatelliteRequest() { const [requests, setRequests] = useState(satRequests) + const [mainTab, setMainTab] = useState<'list' | 'map'>('list') const [statusFilter, setStatusFilter] = useState('전체') const [modalPhase, setModalPhase] = useState('none') const [selectedRequest, setSelectedRequest] = useState(null) @@ -190,6 +198,27 @@ export function SatelliteRequest() { + {/* μš”μ²­λͺ©λ‘ / 지도 λ·° νƒ­ */} +
+ + +
+ + {mainTab === 'list' && (<> {/* μš”μ•½ 톡계 */}
{stats.map((s, i) => ( @@ -337,6 +366,78 @@ export function SatelliteRequest() {
+ )} + + {/* ═══ 촬영 νžˆμŠ€ν† λ¦¬ 지도 λ·° ═══ */} + {mainTab === 'map' && ( +
+ + {/* 촬영 ꡬ역 폴리곀 + 마컀 */} + {requests.map(r => { + const coord = parseCoord(r.zoneCoord) + if (!coord) return null + const areaKm = parseFloat(r.zoneArea) || 10 + const delta = Math.sqrt(areaKm) * 0.005 + const statusColor = r.status === 'μ΄¬μ˜μ€‘' ? '#eab308' : r.status === 'μ™„λ£Œ' ? '#22c55e' : r.status === 'μ·¨μ†Œ' ? '#ef4444' : '#3b82f6' + return ( + + + + + ) + })} + + + {/* 지도 μœ„ λ²”λ‘€ */} +
+
촬영 이λ ₯
+ {[ + { label: 'μ΄¬μ˜μ€‘', color: '#eab308' }, + { label: 'λŒ€κΈ°', color: '#3b82f6' }, + { label: 'μ™„λ£Œ', color: '#22c55e' }, + { label: 'μ·¨μ†Œ', color: '#ef4444' }, + ].map(item => ( +
+
+ {item.label} +
+ ))} +
총 {requests.length}건
+
+ + {/* 지도 μœ„ μš”μ²­ 리슀트 (쒌츑) */} +
+
πŸ“‹ 촬영 μš”μ²­ ({requests.length})
+ {requests.map(r => { + const statusColor = r.status === 'μ΄¬μ˜μ€‘' ? '#eab308' : r.status === 'μ™„λ£Œ' ? '#22c55e' : r.status === 'μ·¨μ†Œ' ? '#ef4444' : '#3b82f6' + return ( +
+
+ {r.id} + {r.status} +
+
{r.zone}
+
{r.satellite} Β· {r.resolution}
+
+ ) + })} +
+
+ )} {/* ═══ λͺ¨λ‹¬: 제곡자 선택 ═══ */} {modalPhase !== 'none' && (