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 { Button } from '@/components/ui/button';
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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { useLocation } from 'wouter';
@@ -132,6 +132,9 @@ export function GpsMapTab({ onShowRoute }: { onShowRoute: (assetId: number) => v
// === Слой задач формы: выбранная форма + её geo-поле → задачи на карте ===
const [, setLocation] = useLocation();
const [tasksLayer, setTasksLayer] = useState(false);
// Отображение названий объектов на карте (по умолчанию скрыты — длинные
// заголовки перекрывают друг друга; включаем кнопкой «Названия»)
const [showLabels, setShowLabels] = useState(false);
const [mapFormId, setMapFormId] = useState<number | null>(null);
const [mapFieldId, setMapFieldId] = useState<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 };
};
// Короткое название для подписи: «объект · заказчик» (первая и последняя
// части заголовка через «;»), длину ограничиваем, иначе подписи перекрывают карту
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(() => {
if (!tasksLayer || mapFieldId === null) return [];
const markers: GpsMapMarker[] = [];
@@ -195,14 +207,15 @@ export function GpsMapTab({ onShowRoute }: { onShowRoute: (assetId: number) => v
lng: geo.lng,
kind: 'dot',
color: '#8b5cf6',
label: t.title,
// Подпись — только при включённом режиме «Названия»
label: showLabels ? shortTitle(t.title) : undefined,
noCluster: true,
zIndex: 40,
onClick: rulerMode ? undefined : () => setLocation(`/forms/${mapFormId}/tasks/${t.id}`),
});
}
return markers;
}, [tasksLayer, mapFieldId, tasksData, rulerMode, setLocation, mapFormId]);
}, [tasksLayer, mapFieldId, tasksData, rulerMode, setLocation, mapFormId, showLabels]);
// Правый клик по карте — создать объект выбранной формы с этими координатами
const handleMapContextMenu = (lat: number, lng: number) => {
@@ -339,6 +352,15 @@ export function GpsMapTab({ onShowRoute }: { onShowRoute: (assetId: number) => v
</SelectContent>
</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>