feat(gps): кнопка «Названия» для слоя объектов (по умолчанию скрыты); подписи сокращены до «объект · заказчик» (≤40 символов)
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user