fix(gps): отсев устаревших копий и LBS-телепортов (stale/jump фильтры), настройка maxJumpSpeedKmh, фильтрация трека при выдаче
This commit is contained in:
@@ -332,6 +332,12 @@ export function GpsRoutesTab() {
|
||||
{trackData?.sampled && ` (всего ${trackData.total}, показана каждая N-я)`}
|
||||
{pointsThinned && `, маркеров на карте: ${displayedPoints.length}`}
|
||||
</span>
|
||||
{(trackData?.filteredCount ?? 0) > 0 && (
|
||||
<span>
|
||||
Отфильтровано мусорных точек:{' '}
|
||||
<span className="text-foreground font-medium">{trackData!.filteredCount}</span>
|
||||
</span>
|
||||
)}
|
||||
<span>
|
||||
Пробег: <span className="text-foreground font-medium">{stats.distance.toFixed(1)} км</span>
|
||||
</span>
|
||||
|
||||
@@ -11,12 +11,13 @@ import { useToast } from '@/hooks/use-toast';
|
||||
interface GpsSettings {
|
||||
success: boolean;
|
||||
jitterMeters: number;
|
||||
maxJumpSpeedKmh: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Таб «Настройки» GPS-модуля.
|
||||
* Секция «Трекинг»: фильтр дрожания позиции (джиттер) — сервер не записывает
|
||||
* точки ближе N метров при скорости < 5 км/ч. Сюда же позже добавятся
|
||||
* Секция «Трекинг»: фильтры входящих точек — дрожание позиции (джиттер)
|
||||
* и максимальный скачок скорости (LBS-прыжки). Сюда же позже добавятся
|
||||
* другие настройки модуля — структура секций-Card под это готова.
|
||||
*/
|
||||
export function GpsSettingsTab() {
|
||||
@@ -26,15 +27,22 @@ export function GpsSettingsTab() {
|
||||
});
|
||||
|
||||
const [jitterMeters, setJitterMeters] = useState('0');
|
||||
const [maxJumpSpeedKmh, setMaxJumpSpeedKmh] = useState('0');
|
||||
|
||||
useEffect(() => {
|
||||
if (data) setJitterMeters(String(data.jitterMeters));
|
||||
if (data) {
|
||||
setJitterMeters(String(data.jitterMeters));
|
||||
setMaxJumpSpeedKmh(String(data.maxJumpSpeedKmh));
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
const value = Number(jitterMeters);
|
||||
const res = await apiRequest('PUT', '/api/gps/settings', { jitterMeters: value });
|
||||
// Оба поля сохраняются одним PUT (непереданные на сервере сохраняются)
|
||||
const res = await apiRequest('PUT', '/api/gps/settings', {
|
||||
jitterMeters: Number(jitterMeters),
|
||||
maxJumpSpeedKmh: Number(maxJumpSpeedKmh),
|
||||
});
|
||||
return res.json();
|
||||
},
|
||||
onSuccess: () => {
|
||||
@@ -49,7 +57,9 @@ export function GpsSettingsTab() {
|
||||
},
|
||||
});
|
||||
|
||||
const jitterValid = /^\d+$/.test(jitterMeters.trim()) && Number(jitterMeters) >= 0 && Number(jitterMeters) <= 1000;
|
||||
const isIntInRange = (v: string, max: number) => /^\d+$/.test(v.trim()) && Number(v) >= 0 && Number(v) <= max;
|
||||
const jitterValid = isIntInRange(jitterMeters, 1000);
|
||||
const jumpValid = isIntInRange(maxJumpSpeedKmh, 5000);
|
||||
|
||||
return (
|
||||
<div className="max-w-2xl space-y-4">
|
||||
@@ -84,10 +94,29 @@ export function GpsSettingsTab() {
|
||||
<p className="text-xs text-destructive">Целое число от 0 до 1000</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">Максимальный скачок, км/ч</Label>
|
||||
<Input
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
className="h-8 w-32"
|
||||
value={maxJumpSpeedKmh}
|
||||
onChange={(e) => setMaxJumpSpeedKmh(e.target.value)}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
0 = выключен. Точки, требующие перемещения быстрее N км/ч от предыдущей,
|
||||
отбрасываются — отсекает LBS-прыжки на вышки при потере GPS. Действует на новые точки.
|
||||
</p>
|
||||
{!jumpValid && (
|
||||
<p className="text-xs text-destructive">Целое число от 0 до 5000</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
size="sm"
|
||||
className="h-8"
|
||||
disabled={saveMutation.isPending || !jitterValid}
|
||||
disabled={saveMutation.isPending || !jitterValid || !jumpValid}
|
||||
onClick={() => saveMutation.mutate()}
|
||||
>
|
||||
{saveMutation.isPending ? (
|
||||
|
||||
@@ -64,6 +64,8 @@ export interface GpsTrackResponse {
|
||||
success: boolean;
|
||||
points: GpsTrackPoint[];
|
||||
total: number;
|
||||
/** Число отброшенных сервером устаревших/телепорт-точек */
|
||||
filteredCount?: number;
|
||||
sampled: boolean;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user