feat(map): focus selected marker at max zoom and tighten collapsed device panel
All checks were successful
Deploy to Production / deploy (push) Successful in 1m51s

This commit is contained in:
魏风
2026-03-24 23:31:30 +08:00
parent e195b26b5a
commit 89c13e8cad

View File

@@ -67,6 +67,10 @@ type TelemetrySnapshot = {
type ConnectionState = "connecting" | "live" | "retrying"
type BaseMapType = "osm" | "amap" | "amap-satellite"
type MapControlBridge = {
__mapFitAll?: () => void
__mapFocusDevice?: (coordinate: [number, number]) => void
}
/* ---------- constants ---------- */
@@ -338,17 +342,38 @@ function FitBoundsControl({
coordinates: Array<[number, number]>
}) {
const map = useMap()
const fitAll = () => {
const fitAll = useCallback(() => {
if (!coordinates.length) return
if (coordinates.length === 1) {
map.setView(coordinates[0], 14, { animate: true })
} else {
map.fitBounds(coordinates, { padding: [40, 40] })
}
}
// expose via a ref so the outside button can call it
const ref = window as unknown as Record<string, () => void>
ref.__mapFitAll = fitAll
}, [coordinates, map])
const focusDevice = useCallback(
(coordinate: [number, number]) => {
const maxZoom = map.getMaxZoom()
const targetZoom = Number.isFinite(maxZoom) ? maxZoom : 18
map.setView(coordinate, targetZoom, { animate: true })
},
[map],
)
useEffect(() => {
const ref = window as unknown as MapControlBridge
ref.__mapFitAll = fitAll
ref.__mapFocusDevice = focusDevice
return () => {
if (ref.__mapFitAll === fitAll) {
delete ref.__mapFitAll
}
if (ref.__mapFocusDevice === focusDevice) {
delete ref.__mapFocusDevice
}
}
}, [fitAll, focusDevice])
return null
}
@@ -490,9 +515,14 @@ function Dashboard() {
[devicesWithCoords, isGcj02],
)
const handleDeviceClick = useCallback((deviceId: string) => {
setActiveDeviceId(deviceId)
}, [])
const handleDeviceClick = useCallback(
(deviceId: string, coordinate: [number, number]) => {
setActiveDeviceId(deviceId)
const mapBridge = window as unknown as MapControlBridge
mapBridge.__mapFocusDevice?.(coordinate)
},
[],
)
const isLive = status === "live"
@@ -574,11 +604,12 @@ function Dashboard() {
{devicesWithCoords.map((device) => {
const isOffline = checkIsOffline(device.last_event_time)
const isSelected = activeDeviceId === device.device_id
const [projLat, projLon] = projectCoord(
const projectedCoordinate = projectCoord(
device.lat as number,
device.lon as number,
isGcj02,
)
const [projLat, projLon] = projectedCoordinate
const color = deviceMarkerColor(device.fix_status, isOffline)
const icon = buildDeviceIcon(color, isSelected, isOffline)
@@ -587,7 +618,8 @@ function Dashboard() {
position={[projLat, projLon]}
icon={icon}
eventHandlers={{
click: () => handleDeviceClick(device.device_id),
click: () =>
handleDeviceClick(device.device_id, projectedCoordinate),
}}
key={device.device_id}
>
@@ -639,12 +671,14 @@ function Dashboard() {
<div
className={`absolute bottom-6 right-6 z-9999 w-80 max-w-[calc(100%-3rem)] transition-all duration-300 ${isPanelExpanded ? "opacity-80" : "opacity-100"}`}
>
<Card className="shadow-lg border bg-background/50 backdrop-blur-md overflow-hidden">
<Card className="shadow-lg border bg-background/50 backdrop-blur-md overflow-hidden py-0 gap-0">
<CardHeader
className="p-3 flex flex-row items-center justify-between space-y-0 cursor-pointer select-none"
className={`flex flex-row items-center justify-between space-y-0 cursor-pointer select-none transition-all duration-300 ${
isPanelExpanded ? "p-3 min-h-11" : "px-3 py-0 min-h-0"
}`}
onClick={() => setIsPanelExpanded(!isPanelExpanded)}
>
<CardTitle className="text-sm font-semibold flex items-center gap-2">
<CardTitle className="font-semibold flex items-center gap-2 text-sm">
Selected Device
{activeDevice?.signal_health &&
!isPanelExpanded &&