diff --git a/client/src/pages/gps/GuidesTab.tsx b/client/src/pages/gps/GuidesTab.tsx new file mode 100644 index 0000000..93135ce --- /dev/null +++ b/client/src/pages/gps/GuidesTab.tsx @@ -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>(() => new Set([TRACKER_GUIDES[0]?.id].filter(Boolean) as string[])); + // По умолчанию выбран первый элемент первой категории + const [selectedId, setSelectedId] = useState(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 ( +
+ {/* Общий шаг для всех устройств */} + + + Сначала создайте объект в CRM + + /gps → Объекты → Добавить: в поле «IMEI / ID трекера» укажите идентификатор устройства + (для GT06 — IMEI с наклейки; для Traccar Client — придуманный ID). В командах ниже адрес + сервера уже подставлен — можно использовать доменное имя или IP сервера. + + + +
+ {/* Дерево устройств + поиск */} + + +
+ + setSearch(e.target.value)} + /> +
+ {filtered.length === 0 ? ( +

Ничего не найдено

+ ) : ( +
+ {filtered.map((category) => ( +
+ + {isExpanded(category.id) && ( +
+ {category.matchedItems.map((item) => ( + + ))} +
+ )} +
+ ))} +
+ )} +
+
+ + {/* Карточка выбранного устройства */} + + {selected ? ( + <> + +
+ {selected.name} + + Порт {selected.port} + + + {selected.protocol} + +
+
+ +
+

Шаги настройки

+
    + {selected.steps.map((step, idx) => ( +
  1. {resolveGuideHost(step)}
  2. + ))} +
+
+ + {selected.sms && selected.sms.length > 0 && ( +
+

SMS-команды

+
+ {selected.sms.map((sms, idx) => ( +
+
+ + {resolveGuideHost(sms.command)} + + +
+

{resolveGuideHost(sms.description)}

+
+ ))} +
+
+ )} + + {selected.notes && selected.notes.length > 0 && ( +
+

Примечания

+
    + {selected.notes.map((note, idx) => ( +
  • {resolveGuideHost(note)}
  • + ))} +
+
+ )} +
+ + ) : ( + + Выберите устройство в дереве слева + + )} +
+
+
+ ); +} diff --git a/client/src/pages/gps/index.tsx b/client/src/pages/gps/index.tsx index 4ff5572..9f8ec83 100644 --- a/client/src/pages/gps/index.tsx +++ b/client/src/pages/gps/index.tsx @@ -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() { + + + diff --git a/client/src/pages/gps/tracker-guides.ts b/client/src/pages/gps/tracker-guides.ts new file mode 100644 index 0000000..7aa36a7 --- /dev/null +++ b/client/src/pages/gps/tracker-guides.ts @@ -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=&lat=%LAT&lon=%LON&speed=%SPD&bearing=%BRR×tamp=%TIMESTAMP', + ' — идентификатор объекта в CRM (поле «IMEI / ID трекера»)', + 'Включите запись трека в приложении', + ], + notes: ['Бесплатный, open source; работает в фоне'], + }, + { + id: 'owntracks', + name: 'OwnTracks', + port: 5055, + protocol: 'OsmAnd (HTTP)', + steps: [ + 'Переведите OwnTracks в режим HTTP', + 'URL: http://{host}:5055/?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); +} diff --git a/docker-compose.yml b/docker-compose.yml index 6c9cafb..f220518 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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