feat(gps): кнопка «Названия» для слоя объектов (по умолчанию скрыты); подписи сокращены до «объект · заказчик» (≤40 символов)

This commit is contained in:
2026-09-22 21:15:31 +03:00
parent 42894aaf8f
commit fe174535b7

View File

@@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from 'react';
import { Card } from '@/components/ui/card'; import { Card } from '@/components/ui/card';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { X, Route, Ruler, MapPinPlus } from 'lucide-react'; import { X, Route, Ruler, MapPinPlus, Tag } from 'lucide-react';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { useLocation } from 'wouter'; import { useLocation } from 'wouter';
@@ -132,6 +132,9 @@ export function GpsMapTab({ onShowRoute }: { onShowRoute: (assetId: number) => v
// === Слой задач формы: выбранная форма + её geo-поле → задачи на карте === // === Слой задач формы: выбранная форма + её geo-поле → задачи на карте ===
const [, setLocation] = useLocation(); const [, setLocation] = useLocation();
const [tasksLayer, setTasksLayer] = useState(false); const [tasksLayer, setTasksLayer] = useState(false);
// Отображение названий объектов на карте (по умолчанию скрыты — длинные
// заголовки перекрывают друг друга; включаем кнопкой «Названия»)
const [showLabels, setShowLabels] = useState(false);
const [mapFormId, setMapFormId] = useState<number | null>(null); const [mapFormId, setMapFormId] = useState<number | null>(null);
const [mapFieldId, setMapFieldId] = useState<number | null>(null); const [mapFieldId, setMapFieldId] = useState<number | null>(null);
const [createAt, setCreateAt] = useState<{ lat: number; lng: number } | null>(null); const [createAt, setCreateAt] = useState<{ lat: number; lng: number } | null>(null);
@@ -183,6 +186,15 @@ export function GpsMapTab({ onShowRoute }: { onShowRoute: (assetId: number) => v
return { lat, lng }; return { lat, lng };
}; };
// Короткое название для подписи: «объект · заказчик» (первая и последняя
// части заголовка через «;»), длину ограничиваем, иначе подписи перекрывают карту
const shortTitle = (title: string): string => {
const parts = title.split(';').map((x) => x.trim()).filter(Boolean);
let text = parts.length > 1 ? `${parts[0]} · ${parts[parts.length - 1]}` : (parts[0] ?? title);
if (text.length > 40) text = `${text.slice(0, 39)}…`;
return text;
};
const taskMarkers: GpsMapMarker[] = useMemo(() => { const taskMarkers: GpsMapMarker[] = useMemo(() => {
if (!tasksLayer || mapFieldId === null) return []; if (!tasksLayer || mapFieldId === null) return [];
const markers: GpsMapMarker[] = []; const markers: GpsMapMarker[] = [];
@@ -195,14 +207,15 @@ export function GpsMapTab({ onShowRoute }: { onShowRoute: (assetId: number) => v
lng: geo.lng, lng: geo.lng,
kind: 'dot', kind: 'dot',
color: '#8b5cf6', color: '#8b5cf6',
label: t.title, // Подпись — только при включённом режиме «Названия»
label: showLabels ? shortTitle(t.title) : undefined,
noCluster: true, noCluster: true,
zIndex: 40, zIndex: 40,
onClick: rulerMode ? undefined : () => setLocation(`/forms/${mapFormId}/tasks/${t.id}`), onClick: rulerMode ? undefined : () => setLocation(`/forms/${mapFormId}/tasks/${t.id}`),
}); });
} }
return markers; return markers;
}, [tasksLayer, mapFieldId, tasksData, rulerMode, setLocation, mapFormId]); }, [tasksLayer, mapFieldId, tasksData, rulerMode, setLocation, mapFormId, showLabels]);
// Правый клик по карте — создать объект выбранной формы с этими координатами // Правый клик по карте — создать объект выбранной формы с этими координатами
const handleMapContextMenu = (lat: number, lng: number) => { const handleMapContextMenu = (lat: number, lng: number) => {
@@ -339,6 +352,15 @@ export function GpsMapTab({ onShowRoute }: { onShowRoute: (assetId: number) => v
</SelectContent> </SelectContent>
</Select> </Select>
)} )}
<Button
size="sm"
variant={showLabels ? 'default' : 'outline'}
className="h-7 text-xs"
onClick={() => setShowLabels((v) => !v)}
>
<Tag className="w-3.5 h-3.5 mr-1" />
Названия
</Button>
<span className="text-xs text-muted-foreground"> <span className="text-xs text-muted-foreground">
Правый клик по карте — новый объект здесь Правый клик по карте — новый объект здесь
</span> </span>