feat(gps): вкладка «Инструкции» со справочником настройки трекеров + открыты порты протоколов (Teltonika, GPS103, H02, Suntech)
This commit is contained in:
212
client/src/pages/gps/GuidesTab.tsx
Normal file
212
client/src/pages/gps/GuidesTab.tsx
Normal file
@@ -0,0 +1,212 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { ChevronDown, ChevronRight, Copy, Info, Search } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { resolveGuideHost, TRACKER_GUIDES, type TrackerGuideItem } from './tracker-guides';
|
||||
|
||||
/**
|
||||
* Таб «Инструкции»: справочник по настройке GPS-трекеров.
|
||||
* Слева — поиск и дерево категорий/устройств, справа — карточка выбранного
|
||||
* устройства с шагами настройки, SMS-командами и примечаниями.
|
||||
* Адрес сервера ({host}) подставляется из window.location.hostname.
|
||||
*/
|
||||
export function GpsGuidesTab() {
|
||||
const { toast } = useToast();
|
||||
const [search, setSearch] = useState('');
|
||||
// Раскрытые категории дерева (при поиске раскрываются все с совпадениями)
|
||||
const [expanded, setExpanded] = useState<Set<string>>(() => new Set([TRACKER_GUIDES[0]?.id].filter(Boolean) as string[]));
|
||||
// По умолчанию выбран первый элемент первой категории
|
||||
const [selectedId, setSelectedId] = useState<string>(TRACKER_GUIDES[0]?.items[0]?.id ?? '');
|
||||
|
||||
const query = search.trim().toLowerCase();
|
||||
|
||||
// Фильтрация дерева: поиск по названию устройства, категории и протоколу
|
||||
const filtered = useMemo(() => {
|
||||
if (!query) return TRACKER_GUIDES.map((c) => ({ ...c, matchedItems: c.items }));
|
||||
return TRACKER_GUIDES.map((category) => {
|
||||
const categoryMatch = category.name.toLowerCase().includes(query);
|
||||
const matchedItems = category.items.filter(
|
||||
(item) =>
|
||||
categoryMatch ||
|
||||
item.name.toLowerCase().includes(query) ||
|
||||
item.protocol.toLowerCase().includes(query)
|
||||
);
|
||||
return { ...category, matchedItems };
|
||||
}).filter((c) => c.matchedItems.length > 0);
|
||||
}, [query]);
|
||||
|
||||
const isExpanded = (categoryId: string) => (query ? true : expanded.has(categoryId));
|
||||
|
||||
const toggleCategory = (categoryId: string) => {
|
||||
setExpanded((prev) => {
|
||||
const next = new Set(prev);
|
||||
if (next.has(categoryId)) next.delete(categoryId);
|
||||
else next.add(categoryId);
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
const selected: TrackerGuideItem | undefined = useMemo(
|
||||
() => TRACKER_GUIDES.flatMap((c) => c.items).find((i) => i.id === selectedId),
|
||||
[selectedId]
|
||||
);
|
||||
|
||||
const copyCommand = async (command: string) => {
|
||||
const text = resolveGuideHost(command);
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
toast({ title: 'Скопировано', description: text });
|
||||
} catch {
|
||||
toast({ title: 'Не удалось скопировать', description: text, variant: 'destructive' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Общий шаг для всех устройств */}
|
||||
<Alert>
|
||||
<Info className="h-4 w-4" />
|
||||
<AlertTitle>Сначала создайте объект в CRM</AlertTitle>
|
||||
<AlertDescription className="text-xs">
|
||||
/gps → Объекты → Добавить: в поле «IMEI / ID трекера» укажите идентификатор устройства
|
||||
(для GT06 — IMEI с наклейки; для Traccar Client — придуманный ID). В командах ниже адрес
|
||||
сервера уже подставлен — можно использовать доменное имя или IP сервера.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-[280px_1fr] gap-4">
|
||||
{/* Дерево устройств + поиск */}
|
||||
<Card>
|
||||
<CardContent className="p-3 space-y-2">
|
||||
<div className="relative">
|
||||
<Search className="absolute left-2 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground" />
|
||||
<Input
|
||||
className="h-8 pl-7 text-xs"
|
||||
placeholder="Поиск по названию, бренду, протоколу…"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
{filtered.length === 0 ? (
|
||||
<p className="text-xs text-muted-foreground py-4 text-center">Ничего не найдено</p>
|
||||
) : (
|
||||
<div className="space-y-1">
|
||||
{filtered.map((category) => (
|
||||
<div key={category.id}>
|
||||
<button
|
||||
type="button"
|
||||
className="w-full flex items-center gap-1 px-1.5 py-1.5 rounded text-xs font-medium text-foreground hover:bg-muted/50 transition-colors text-left"
|
||||
onClick={() => toggleCategory(category.id)}
|
||||
>
|
||||
{isExpanded(category.id) ? (
|
||||
<ChevronDown className="w-3.5 h-3.5 shrink-0 text-muted-foreground" />
|
||||
) : (
|
||||
<ChevronRight className="w-3.5 h-3.5 shrink-0 text-muted-foreground" />
|
||||
)}
|
||||
<span className="truncate">{category.name}</span>
|
||||
</button>
|
||||
{isExpanded(category.id) && (
|
||||
<div className="ml-4 space-y-0.5">
|
||||
{category.matchedItems.map((item) => (
|
||||
<button
|
||||
key={item.id}
|
||||
type="button"
|
||||
onClick={() => setSelectedId(item.id)}
|
||||
className={cn(
|
||||
'w-full text-left px-2 py-1 rounded text-xs transition-colors truncate',
|
||||
selectedId === item.id
|
||||
? 'bg-muted text-foreground font-medium'
|
||||
: 'text-muted-foreground hover:bg-muted/50 hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
{item.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Карточка выбранного устройства */}
|
||||
<Card>
|
||||
{selected ? (
|
||||
<>
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<CardTitle className="text-base">{selected.name}</CardTitle>
|
||||
<Badge variant="outline" className="text-[10px]">
|
||||
Порт {selected.port}
|
||||
</Badge>
|
||||
<Badge variant="secondary" className="text-[10px]">
|
||||
{selected.protocol}
|
||||
</Badge>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div>
|
||||
<h4 className="text-xs font-semibold mb-2">Шаги настройки</h4>
|
||||
<ol className="list-decimal list-inside space-y-1.5 text-xs text-muted-foreground">
|
||||
{selected.steps.map((step, idx) => (
|
||||
<li key={idx}>{resolveGuideHost(step)}</li>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{selected.sms && selected.sms.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-xs font-semibold mb-2">SMS-команды</h4>
|
||||
<div className="space-y-2">
|
||||
{selected.sms.map((sms, idx) => (
|
||||
<div key={idx} className="border border-border rounded p-2 space-y-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<code className="flex-1 text-xs font-mono bg-muted rounded px-1.5 py-1 break-all">
|
||||
{resolveGuideHost(sms.command)}
|
||||
</code>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 w-7 p-0 shrink-0"
|
||||
title="Скопировать команду"
|
||||
onClick={() => copyCommand(sms.command)}
|
||||
>
|
||||
<Copy className="w-3.5 h-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-[11px] text-muted-foreground">{resolveGuideHost(sms.description)}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selected.notes && selected.notes.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-xs font-semibold mb-1.5">Примечания</h4>
|
||||
<ul className="list-disc list-inside space-y-1 text-[11px] text-muted-foreground">
|
||||
{selected.notes.map((note, idx) => (
|
||||
<li key={idx}>{resolveGuideHost(note)}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</>
|
||||
) : (
|
||||
<CardContent className="p-8 text-center text-sm text-muted-foreground">
|
||||
Выберите устройство в дереве слева
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useLocation } from 'wouter';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Map, Truck, Hexagon, Route, Folder } from 'lucide-react';
|
||||
import { Map, Truck, Hexagon, Route, Folder, BookOpen } from 'lucide-react';
|
||||
import Layout from '@/components/Layout';
|
||||
import { GpsMapTab } from './MapTab';
|
||||
import { GpsAssetsTab } from './AssetsTab';
|
||||
import { GpsGeozonesTab } from './GeozonesTab';
|
||||
import { GpsRoutesTab } from './RoutesTab';
|
||||
import { GpsGroupsTab } from './GroupsTab';
|
||||
import { GpsGuidesTab } from './GuidesTab';
|
||||
|
||||
const TABS = [
|
||||
{ value: 'map', label: 'Карта', icon: Map },
|
||||
@@ -14,6 +15,7 @@ const TABS = [
|
||||
{ value: 'geozones', label: 'Геозоны', icon: Hexagon },
|
||||
{ value: 'routes', label: 'Маршруты', icon: Route },
|
||||
{ value: 'groups', label: 'Группы', icon: Folder },
|
||||
{ value: 'guides', label: 'Инструкции', icon: BookOpen },
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -57,6 +59,9 @@ export default function GpsPage() {
|
||||
<TabsContent value="groups">
|
||||
<GpsGroupsTab />
|
||||
</TabsContent>
|
||||
<TabsContent value="guides">
|
||||
<GpsGuidesTab />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
344
client/src/pages/gps/tracker-guides.ts
Normal file
344
client/src/pages/gps/tracker-guides.ts
Normal file
@@ -0,0 +1,344 @@
|
||||
/**
|
||||
* Статический справочник по настройке GPS-трекеров (вкладка «Инструкции»).
|
||||
* Дерево: категории → устройства/протоколы. Порты соответствуют реально
|
||||
* открытым на сервере портам Traccar (5023 GT06, 5027 Teltonika, 5001 GPS103,
|
||||
* 5013 H02, 5036 Suntech, 5055 OsmAnd/HTTP).
|
||||
*
|
||||
* В текстах и SMS-командах плейсхолдер {host} заменяется в UI на
|
||||
* window.location.hostname (для iistwin.ru резолвится в IP сервера).
|
||||
*/
|
||||
|
||||
export interface TrackerGuideSms {
|
||||
/** Текст SMS-команды (с плейсхолдером {host}) */
|
||||
command: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface TrackerGuideItem {
|
||||
id: string;
|
||||
/** Название устройства/протокола */
|
||||
name: string;
|
||||
/** Порт сервера Traccar */
|
||||
port: number;
|
||||
/** Протокол Traccar */
|
||||
protocol: string;
|
||||
/** Шаги настройки (нумерованный список) */
|
||||
steps: string[];
|
||||
/** SMS-команды (опционально) */
|
||||
sms?: TrackerGuideSms[];
|
||||
/** Примечания (muted-текст) */
|
||||
notes?: string[];
|
||||
}
|
||||
|
||||
export interface TrackerGuideCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
items: TrackerGuideItem[];
|
||||
}
|
||||
|
||||
const APN_NOTE =
|
||||
'APN оператора: internet.mts.ru (МТС), internet.beeline.ru (Билайн), internet.tele2.ru (Tele2), internet.megafon.ru (МегаФон)';
|
||||
|
||||
export const TRACKER_GUIDES: TrackerGuideCategory[] = [
|
||||
{
|
||||
id: 'gt06',
|
||||
name: 'Автомобильные трекеры (GT06)',
|
||||
description: 'Самый массовый протокол китайских трекеров — Concox, Coban, Jimi и клоны',
|
||||
items: [
|
||||
{
|
||||
id: 'concox-gt06n',
|
||||
name: 'Concox GT06N / GT06E',
|
||||
port: 5023,
|
||||
protocol: 'GT06',
|
||||
steps: [
|
||||
'Вставьте в трекер SIM-карту с отключённым PIN-кодом и включённым мобильным интернетом',
|
||||
'Узнайте IMEI устройства (наклейка на корпусе или команда check123456)',
|
||||
'Настройте трекер SMS-командами ниже: APN → сервер → включение GPRS',
|
||||
'В CRM создайте объект (/gps → Объекты → Добавить) и укажите IMEI в поле «IMEI / ID трекера»',
|
||||
'Подайте питание на трекер — через 1–2 минуты объект появится на карте',
|
||||
],
|
||||
sms: [
|
||||
{ command: 'apn123456 {apn}', description: 'Установить APN оператора (например: apn123456 internet.mts.ru)' },
|
||||
{ command: 'adminip123456 {host} 5023', description: 'Сервер и порт (вместо {host} — адрес сервера или IP)' },
|
||||
{ command: 'gprs123456', description: 'Включить передачу по GPRS' },
|
||||
{ command: 'check123456', description: 'Проверка настроек: ответ содержит IMEI, APN, сервер' },
|
||||
],
|
||||
notes: [
|
||||
'123456 — заводской SMS-пароль по умолчанию; если меняли — подставьте свой',
|
||||
APN_NOTE,
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'coban-gps303',
|
||||
name: 'Coban GPS303',
|
||||
port: 5023,
|
||||
protocol: 'GT06',
|
||||
steps: [
|
||||
'Вставьте SIM-карту без PIN-кода',
|
||||
'Отправьте SMS-команды настройки APN и сервера',
|
||||
'Создайте объект в CRM с IMEI трекера',
|
||||
'Проверьте статус командой check123456 — в ответе должен быть адрес сервера',
|
||||
],
|
||||
sms: [
|
||||
{ command: 'apn123456 {apn}', description: 'Установить APN оператора' },
|
||||
{ command: 'adminip123456 {host} 5023', description: 'Сервер и порт' },
|
||||
{ command: 'gprs123456', description: 'Включить GPRS-режим' },
|
||||
{ command: 'check123456', description: 'Проверка текущих настроек' },
|
||||
],
|
||||
notes: [
|
||||
'У Coban встречаются прошивки с другим набором команд — если apn123456 не принимается, попробуйте формат APN,123456,{apn}#',
|
||||
APN_NOTE,
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'jimi-jm01',
|
||||
name: 'Jimi / Concox JM01',
|
||||
port: 5023,
|
||||
protocol: 'GT06',
|
||||
steps: [
|
||||
'Вставьте SIM-карту, включите трекер',
|
||||
'Настройте APN и сервер SMS-командами',
|
||||
'Создайте объект в CRM с IMEI трекера',
|
||||
],
|
||||
sms: [
|
||||
{ command: 'apn123456 {apn}', description: 'Установить APN оператора' },
|
||||
{ command: 'adminip123456 {host} 5023', description: 'Сервер и порт' },
|
||||
{ command: 'gprs123456', description: 'Включить GPRS' },
|
||||
{ command: 'check123456', description: 'Проверка настроек' },
|
||||
],
|
||||
notes: ['JM01 — видеотрекер; по GT06 передаются координаты, видео настраивается отдельно', APN_NOTE],
|
||||
},
|
||||
{
|
||||
id: 'gt06-generic',
|
||||
name: 'Любой GT06-совместимый трекер',
|
||||
port: 5023,
|
||||
protocol: 'GT06',
|
||||
steps: [
|
||||
'Узнайте IMEI устройства',
|
||||
'По инструкции вендора задайте APN и адрес сервера {host}, порт 5023',
|
||||
'Включите передачу данных по GPRS/TCP',
|
||||
'Создайте объект в CRM с этим IMEI',
|
||||
],
|
||||
notes: [
|
||||
'GT06 — протокол сотен безымянных китайских трекеров; SMS-команды у каждого вендора свои, смотрите документацию устройства',
|
||||
'Частые варианты команд сервера: adminip123456, IP123456, pw,123456,ip,...# (формат H02)',
|
||||
APN_NOTE,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'teltonika',
|
||||
name: 'Teltonika',
|
||||
description: 'Профессиональные трекеры, настройка через Teltonika Configurator',
|
||||
items: [
|
||||
{
|
||||
id: 'teltonika-fmb920',
|
||||
name: 'Teltonika FMB920',
|
||||
port: 5027,
|
||||
protocol: 'Teltonika (FMB)',
|
||||
steps: [
|
||||
'Подключите трекер к ПК и откройте Teltonika Configurator',
|
||||
'Перейдите на вкладку GPRS',
|
||||
'Domain: {host} (или IP сервера), Port: 5027, Protocol: TCP',
|
||||
'APN: APN вашего оператора (internet.mts.ru / internet.beeline.ru / ...)',
|
||||
'Сохраните конфигурацию в устройство (Save to device)',
|
||||
'Создайте объект в CRM с IMEI трекера',
|
||||
],
|
||||
notes: [APN_NOTE, 'Записи сначала накапливаются во флэш-памяти и выгружаются пачками — первая точка может появиться с задержкой'],
|
||||
},
|
||||
{
|
||||
id: 'teltonika-fmb125',
|
||||
name: 'Teltonika FMB125',
|
||||
port: 5027,
|
||||
protocol: 'Teltonika (FMB)',
|
||||
steps: [
|
||||
'Откройте Teltonika Configurator, вкладка GPRS',
|
||||
'Domain: {host}, Port: 5027, Protocol: TCP',
|
||||
'Укажите APN оператора и сохраните в устройство',
|
||||
'Создайте объект в CRM с IMEI трекера',
|
||||
],
|
||||
notes: [APN_NOTE],
|
||||
},
|
||||
{
|
||||
id: 'teltonika-fmc130',
|
||||
name: 'Teltonika FMC130',
|
||||
port: 5027,
|
||||
protocol: 'Teltonika (FMB)',
|
||||
steps: [
|
||||
'Откройте Teltonika Configurator, вкладка GPRS',
|
||||
'Domain: {host}, Port: 5027, Protocol: TCP',
|
||||
'Укажите APN оператора и сохраните в устройство',
|
||||
'Создайте объект в CRM с IMEI трекера',
|
||||
],
|
||||
notes: [APN_NOTE, 'FMC130 — 4G/LTE: убедитесь, что SIM поддерживает LTE-данные'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'gps103',
|
||||
name: 'GPS103 / TK-серия',
|
||||
description: 'TK-102/103, Xexun и совместимые',
|
||||
items: [
|
||||
{
|
||||
id: 'tk103',
|
||||
name: 'TK-102 / TK-103',
|
||||
port: 5001,
|
||||
protocol: 'GPS103',
|
||||
steps: [
|
||||
'Вставьте SIM-карту без PIN-кода',
|
||||
'Отправьте SMS-команды: begin → APN → сервер',
|
||||
'Создайте объект в CRM с IMEI трекера',
|
||||
],
|
||||
sms: [
|
||||
{ command: 'begin123456', description: 'Сброс к заводским настройкам' },
|
||||
{ command: 'apn123456 {apn}', description: 'Установить APN оператора' },
|
||||
{ command: 'adminip123456 {host} 5001', description: 'Сервер и порт' },
|
||||
],
|
||||
notes: ['123456 — пароль по умолчанию', APN_NOTE],
|
||||
},
|
||||
{
|
||||
id: 'xexun',
|
||||
name: 'Xexun (TK-совместимые)',
|
||||
port: 5001,
|
||||
protocol: 'GPS103',
|
||||
steps: [
|
||||
'Настройте APN и сервер SMS-командами',
|
||||
'Создайте объект в CRM с IMEI трекера',
|
||||
],
|
||||
sms: [
|
||||
{ command: 'begin123456', description: 'Сброс к заводским настройкам' },
|
||||
{ command: 'apn123456 {apn}', description: 'Установить APN оператора' },
|
||||
{ command: 'adminip123456 {host} 5001', description: 'Сервер и порт' },
|
||||
],
|
||||
notes: [APN_NOTE],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'h02',
|
||||
name: 'H02-совместимые',
|
||||
description: 'Китайские трекеры и часы с протоколом H02',
|
||||
items: [
|
||||
{
|
||||
id: 'h02-generic',
|
||||
name: 'H02-совместимый трекер / часы',
|
||||
port: 5013,
|
||||
protocol: 'H02',
|
||||
steps: [
|
||||
'Вставьте SIM-карту с мобильным интернетом',
|
||||
'Отправьте SMS с адресом сервера в формате ниже',
|
||||
'Создайте объект в CRM с IMEI устройства',
|
||||
],
|
||||
sms: [
|
||||
{ command: 'pw,123456,ip,{host},5013#', description: 'Сервер и порт (пароль 123456)' },
|
||||
],
|
||||
notes: [
|
||||
'Формат SMS зависит от прошивки: у части устройств команда выглядит как pw,123456,ip,{host},5013# — у других иначе, сверяйтесь с документацией',
|
||||
APN_NOTE,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'suntech',
|
||||
name: 'Suntech',
|
||||
description: 'ST300/ST310 и совместимые',
|
||||
items: [
|
||||
{
|
||||
id: 'suntech-st300',
|
||||
name: 'Suntech ST300 / ST310',
|
||||
port: 5036,
|
||||
protocol: 'Suntech',
|
||||
steps: [
|
||||
'Откройте Suntech-конфигуратор (или настройте по SMS по документации вендора)',
|
||||
'Укажите сервер: {host}, порт 5036',
|
||||
'Укажите APN оператора',
|
||||
'Создайте объект в CRM с идентификатором устройства',
|
||||
],
|
||||
notes: [APN_NOTE, 'Идентификатор Suntech — Device ID из конфигуратора (обычно совпадает с IMEI)'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'smartphone',
|
||||
name: 'Смартфон как трекер',
|
||||
description: 'Приложения, шлющие координаты по HTTP (порт 5055, протокол OsmAnd)',
|
||||
items: [
|
||||
{
|
||||
id: 'traccar-client',
|
||||
name: 'Traccar Client (Android / iOS)',
|
||||
port: 5055,
|
||||
protocol: 'OsmAnd (HTTP)',
|
||||
steps: [
|
||||
'Установите Traccar Client из магазина приложений',
|
||||
'Server URL: http://{host}:5055',
|
||||
'Device identifier: IMEI/ID из карточки объекта в CRM (сначала создайте объект и задайте ID)',
|
||||
'Частота отправки (Frequency): 60 секунд',
|
||||
'Включите сервис в приложении — точки пойдут на карту',
|
||||
],
|
||||
notes: [
|
||||
'Рекомендуемый способ для смартфона: работает в фоне',
|
||||
'Device identifier придумываете сами (например, ivan-phone) — он же указывается в поле «IMEI / ID трекера» объекта в CRM',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'gpslogger',
|
||||
name: 'GPSLogger (Android)',
|
||||
port: 5055,
|
||||
protocol: 'OsmAnd (HTTP)',
|
||||
steps: [
|
||||
'Установите GPSLogger, откройте настройки отправки (Logging → Custom URL)',
|
||||
'Custom URL: http://{host}:5055/?id=<ID>&lat=%LAT&lon=%LON&speed=%SPD&bearing=%BRR×tamp=%TIMESTAMP',
|
||||
'<ID> — идентификатор объекта в CRM (поле «IMEI / ID трекера»)',
|
||||
'Включите запись трека в приложении',
|
||||
],
|
||||
notes: ['Бесплатный, open source; работает в фоне'],
|
||||
},
|
||||
{
|
||||
id: 'owntracks',
|
||||
name: 'OwnTracks',
|
||||
port: 5055,
|
||||
protocol: 'OsmAnd (HTTP)',
|
||||
steps: [
|
||||
'Переведите OwnTracks в режим HTTP',
|
||||
'URL: http://{host}:5055/?id=<ID>',
|
||||
'<ID> — идентификатор объекта в CRM',
|
||||
],
|
||||
notes: [
|
||||
'Совместим частично (шлёт не все поля OsmAnd-формата) — приоритет у Traccar Client',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'pwa',
|
||||
name: 'Без устройства (PWA)',
|
||||
description: 'Встроенный трекинг прямо из браузера/PWA — ничего устанавливать не нужно',
|
||||
items: [
|
||||
{
|
||||
id: 'pwa-tracking',
|
||||
name: 'Встроенный трекинг (профиль пользователя)',
|
||||
port: 443,
|
||||
protocol: 'Внутренний (HTTPS, POST /api/gps/my-position)',
|
||||
steps: [
|
||||
'Откройте свой профиль: /profile → вкладка «GPS»',
|
||||
'Включите переключатель «Отслеживать мою геолокацию»',
|
||||
'Разрешите браузеру доступ к геолокации',
|
||||
'Объект появится на карте автоматически (создаётся сам при первой точке)',
|
||||
],
|
||||
notes: [
|
||||
'Координаты отправляются, пока открыто приложение (не чаще раза в 60 сек)',
|
||||
'Для фонового отслеживания используйте Traccar Client (раздел «Смартфон как трекер»)',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
/** Подстановка адреса сервера вместо плейсхолдера {host} */
|
||||
export function resolveGuideHost(text: string): string {
|
||||
const host = typeof window !== 'undefined' ? window.location.hostname : 'iistwin.ru';
|
||||
return text.replaceAll('{host}', host);
|
||||
}
|
||||
@@ -143,7 +143,16 @@ services:
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5055:5055" # OsmAnd/HTTP — приём точек с трекеров/приложений
|
||||
- "5023:5023" # GT06
|
||||
- "5023:5023" # GT06 (Concox, Coban, Jimi)
|
||||
- "5023:5023/udp"
|
||||
- "5027:5027" # Teltonika (FMB920/FMB125/FMC130)
|
||||
- "5027:5027/udp"
|
||||
- "5001:5001" # GPS103 / TK-102/103
|
||||
- "5001:5001/udp"
|
||||
- "5013:5013" # H02
|
||||
- "5013:5013/udp"
|
||||
- "5036:5036" # Suntech
|
||||
- "5036:5036/udp"
|
||||
# Web UI Traccar наружу не публикуем — только внутренняя Docker-сеть.
|
||||
# При необходимости доступа извне раскомментируйте:
|
||||
# - "5082:8082" # web UI
|
||||
|
||||
Reference in New Issue
Block a user