Приложение бригады
Приложение бригады: наряды, обходы по формам, дефекты на месте, фото и трек. Работает без связи и отправляет накопленное, когда связь появится.
Возможности
- Список открытых нарядов: всех или одной бригады («Бригада» — «Все бригады» или конкретная). Сначала более срочные, при равной срочности — по плановому сроку; просроченный помечен «· просрочен».
- Карточка наряда: что сделать, место, описание, карта места работ с сетью в радиусе 300 м, «Маршрут» в навигатор телефона, «На карте сети» — то же место в основном приложении.
- «Начать работу» и «Выполнено» с текстом «Что сделано»; фото с подписью («Снять»); комментарий для диспетчера; история наряда.
- Обход по контуру осмотра: узлы по порядку, отметка «осмотрен» или «с дефектом», ссылка до следующего узла, «Итог обхода» — готовый текст для «Что сделано».
- Форма обхода, если она назначена наряду: раз на наряд или на каждом узле.
- «Дефект на обходе» — дефект в журнал нарушений с точкой телефона и фото; по нему сервер сам создаёт заявку.
- «Передавать местоположение» — трек бригады для диспетчера; у места наряда наряд сам отмечает «на месте с …».
- Всё перечисленное работает без связи и уходит на сервер, когда связь вернётся.
Как это работает
Без связи. Каждое действие бригады («Начать работу», «Выполнено», комментарий, фото, отметка узла, форма, дефект) сначала записывается в очередь на телефоне (IndexedDB браузера, своя база на каждый город), затем отправляется. Пока очередь не пуста, вверху раздел «Ждут отправки: N. Уйдут сами, когда появится связь.», а у кнопки обновления — счётчик. Карточка сразу показывает результат: после «Начать работу» без связи наряд уже «В работе» и видна кнопка «Выполнено».
Отправка запускается сразу после действия, при появлении сети, при возврате на вкладку и каждые 30 секунд, пока есть неотправленное. Действия уходят строго по времени создания: «Выполнено» не обгонит «Начать работу». У каждого действия свой ключ: если связь оборвалась после записи на сервере, повтор не создаст дубль.
Что делает отправка с ответом сервера:
| Ответ | Что происходит |
|---|---|
| нет сети, 408, 425, 429, 5xx | отправка останавливается, действие ждёт следующей попытки |
| 401 (нужен вход) | отправка останавливается, открывается вход; очередь не трогается |
| 409 (наряд изменил диспетчер) | действие помечается конфликтом; у перехода — кнопка «Ещё раз» |
| другие ошибки (422, 413, 415 …) | действие помечается «не принято» с текстом сервера; повтор не поможет |
Если переход наряда упёрся в конфликт, остальные переходы этого наряда тоже не уходят («Предыдущий переход этого наряда не прошёл»), а комментарии и фото уходят. «Ещё раз» загружает свежий наряд: если переход ещё возможен — шлёт его заново, если нет — пишет «Наряд уже «…» — этот переход больше не нужен, уберите его.». Действия с ошибкой удаляются из очереди кнопкой «Убрать из очереди».
Что хранится на телефоне. Последний загруженный список нарядов (без связи — «Без связи — список от …»), справочники нарядов и журнала дефектов, действующие формы обходов, сеть вокруг каждого открытого наряда и маршрут обхода. Сеть (участки и узлы в радиусе 300 м, только фрагмент наряда, до 2000 объектов) скачивается при загрузке списка и обновляется, если ей больше 12 часов. Подложка карты без связи не грузится — на карте подпись «без связи — без подложки». Последнее известное право отмечать работу тоже запоминается: без связи кнопки остаются, а сервер проверит право при отправке.
Страница без связи. Service worker (field-sw.js) обслуживает только страницу /field и её файлы: сначала сеть,
без сети — сохранённая копия. Поэтому после выкатки бригада сразу получает новую версию. Чтобы страница открылась без
связи, её нужно хотя бы раз открыть при связи (лучше дважды: при первом заходе service worker только ставится).
Основное приложение, API и тайлы идут мимо него.
Переходы наряда. Бригаде доступна цепочка вперёд: «Начать работу» — только из «Назначен», «Выполнено» — из «В работе» и только с заполненным «Что сделано». Наряд в статусе «Заявка» бригада не начинает: сначала диспетчер назначает бригаду. Если наряд создан по дефекту, «Начать работу» ставит дефекту состояние «Ремонт» и дату начала ремонта, «Выполнено» — «После ремонта» и дату завершения. Закрывает наряд диспетчер («Выполнено. Закроет диспетчер.»). После обновления выполненный наряд из списка уходит: список показывает только открытые.
Фото. Снимок уменьшается на телефоне: длинная сторона — до 1600 пикселей, JPEG с качеством 0,82, 0,7 или 0,55 —
первое, что укладывается в 2 МБ. Поворот берётся из EXIF. Сервер принимает JPEG, PNG и WebP до 2 МБ (тип проверяет
по содержимому файла) и не больше 30 фото на наряд. Фото и координаты хранятся в базе (tgid_work_order_photo).
Координаты действия. К каждому действию добавляется точка GPS: замер ждёт до 8 секунд, годится замер не старше минуты. Нет разрешения или спутников — действие уходит без координат.
Дефект на обходе. Окно ждёт координаты телефона: без них кнопка «Записать дефект» недоступна. Описание обязательно; есть готовые фразы («Парение», «Течь», «Открыт люк» …). Источник по умолчанию — «Осмотр», если он есть в справочнике. Сервер пишет запись в журнал нарушений десктопа в состоянии «Нарушение» и привязывает её к ближайшему участку не дальше 30 м от точки (дефект с узла обхода — к участку контура у этого узла). Тут же создаётся заявка «Дефект: …» в статусе «Заявка» с выбранной срочностью; узел обхода отмечается «с дефектом».
Трек. Пока включено «Передавать местоположение», телефон пишет точку не чаще раза в 5 секунд — после сдвига на 25 м или через минуту стоянки. Точки с точностью хуже 100 м не пишутся. Накопленное уходит пачками до 500 точек раз в минуту. Браузер даёт координаты, только пока страница открыта и экран включён — в фоне трек прерывается. Если на телефоне выбрана конкретная бригада и её точка оказалась в 100 м от места открытого наряда этой бригады («Назначен» или «В работе»; у обхода — от любого участка контура), в наряде появляется «на месте с ЧЧ:ММ». Сервер хранит трек 90 дней.
Выход. «Выйти» предупреждает о неотправленном: оно ушло бы от имени того, кто войдёт следующим. Точки трека при выходе отправляются, если есть связь, остальные удаляются с телефона; сохранённый список нарядов тоже удаляется.
Что нужно для работы
- Права: смотреть наряды — любой вошедший. Отмечать работу, фото, комментарии, формы, дефект на обходе и трек — право «Журналы» (есть у ролей «Редактор» и «Администратор») при включённой записи на сервере. Без права в карточке — «Отмечать работу может пользователь с правом «Журналы».»; с правом, но при выключенной записи — «Запись выключена на сервере (MUTATIONS_ENABLED).». В обоих случаях кнопок действий и переключателя «Передавать местоположение» нет.
- Данные: справочник бригад и наряды с назначенной бригадой (окно «Наряды и заявки»); для обхода — контур осмотра; для формы — форма, назначенная наряду.
- Телефон и браузер: современный браузер с IndexedDB и service worker, адрес по HTTPS (service worker, камера и геолокация в браузере работают только на защищённом адресе). Разрешения на камеру и геолокацию. Для работы без связи — открыть страницу хотя бы раз при связи. В приватном режиме очередь может жить только до закрытия вкладки — тогда предупреждение «Браузер не даёт хранилище…».
- Страницу можно добавить на главный экран телефона: у неё свой manifest, ярлык открывает сразу наряды бригады.
Шаги
Главный экран: открытые наряды бригады (выбор бригады — сверху), кнопка «Дефект на обходе» — записать дефект с места с фото и координатами, переключатель «Передавать местоположение» — диспетчер увидит бригаду на карте.

Наряд открыт: что сделать, участок и фрагмент, описание, карта с местом работ и сетью рядом; «Маршрут» строит путь до места, «На карте сети» открывает его на основной карте. Ниже — фото с подписью, комментарий для диспетчера и история наряда. Без связи действия копятся на телефоне и уходят, когда связь появится.

Примеры
Копия Алматы на стенде инструкции. Справочник бригад пуст, поэтому в «Бригада» — только «Все бригады». Открытых нарядов нет (в базе 5 нарядов, все «Отменён»), страница пишет «Открытых нарядов нет.». Чтобы попробовать приложение, диспетчер создаёт наряд в «Наряды и заявки» и назначает бригаду. Источник «Осмотр» в справочнике журнала есть (запись № 6) — «Дефект на обходе» подставит его сам.
Фото с камеры 4000 × 3000. Телефон уменьшит его до 1600 × 1200 и сохранит JPEG с качеством 0,82; если файл всё ещё больше 2 МБ — 0,7, затем 0,55. Если и так не уложится — «Фото слишком большое даже после уменьшения».
Смена без связи. Бригада в подвале нажала «Начать работу», сделала два фото и «Выполнено». На экране наряд сразу «Выполнен», вверху — «Ждут отправки: 4». Связь появилась — действия уходят по порядку. «Выполнено» записано с той же версией наряда, что и «Начать работу», и получает новую версию из ответа на «Начать». Если диспетчер за это время изменил наряд, «Начать работу» получит конфликт, а «Выполнено» — «Предыдущий переход этого наряда не прошёл»; оба фото уйдут.
Если не получается
- «Список не загрузился: …» — сервер не ответил, а сохранённого списка на телефоне нет.
- «Список не сохранился на телефоне: …» — браузер не дал записать в хранилище; без связи список не откроется.
- «Не сохранилось на телефоне: … Повторите.» — браузер не дал положить действие в очередь. Оно не записано и не уйдёт; текст комментария или «Что сделано» остаётся в поле — нажмите кнопку ещё раз.
- «Работа без связи недоступна: …» — service worker не зарегистрировался (адрес не HTTPS или браузер запрещает).
- «Сеть вокруг не сохранена — откройте наряд при связи» — карта наряда не скачалась до потери связи.
- «Нет координат: разрешите геолокацию и выйдите на открытое место.» — в окне дефекта нет точки; без неё дефект не записать. Кнопка «Уточнить» повторяет замер.
- «Дефект записан на телефоне — уйдёт, когда появится связь.» — это не ошибка: сервер недоступен, дефект в очереди.
- «Не удалось открыть фото — снимите ещё раз или выберите JPEG» — браузер не прочитал файл (например, HEIC), а сам файл не JPEG, PNG или WebP до 2 МБ.
- «Нет разрешения на геолокацию — включите его в настройках браузера» — трек выключился сам.
- «Нет сигнала GPS — трек продолжится, когда он появится».
- «Трек не принят: …» — сервер отказал в пачке точек; эта пачка удаляется с телефона.
- Действие с ошибкой «Наряд уже изменили — обновите карточку» — диспетчер изменил наряд; нажмите «Ещё раз».
- «У наряда уже 30 фото» — больше фото к наряду не добавить.
- Нет кнопки «Начать работу» — наряд в статусе «Заявка»: диспетчер ещё не назначил бригаду.
- Нет отметки «на месте» — на телефоне выбрано «Все бригады» или наряд не назначен этой бригаде.
Для администратора
- Запись нарядов, фото, форм, дефекта с обхода и трека — при
MUTATIONS_ENABLED=true; без этого бригада только смотрит, аPOST /api/v1/field/trackотвечает 503, как и запись журналов. - Таблицы:
tgid_work_order,tgid_work_order_event(история и ключи действийclient_id),tgid_work_order_photo(фото в базе, bytea),tgid_work_order_check(отметки обхода),tgid_field_track(трек, хранится 90 дней), журнал нарушенийdefect. Запись дефекта с обхода попадает вaudit_log. - Service worker
field-sw.jsиfield.webmanifestлежат вpublic/веба и отдаются по пути приложения (NUXT_APP_BASE_URL). Кеш называетсяtgid-field-v1; при смене имени старый кеш удаляется сам. - Адрес для бригады —
<адрес веба>/field. Нужен HTTPS.
Для разработчика
- Страница:
pages/field.vue(без общего макета). Компоненты:FieldOrderMap.vue,FieldDefectDialog.vue,FieldFormDialog.vue; трек —composables/useFieldTrack.ts. - Правила:
utils/fieldQueue.ts(очередь,classifySendError,flushQueue),utils/fieldStore.ts(IndexedDB),utils/fieldPhoto.ts(уменьшение фото, GPS, ссылка «Маршрут»),utils/fieldNetwork.ts(сеть 300 м, 12 ч),utils/fieldRoute.ts(обход),utils/fieldDefect.ts,utils/fieldTrack.ts. Service worker —public/field-sw.js. - API:
GET /api/v1/work-orders?open_only=true&brigade_id=,GET /api/v1/work-orders/lookups,GET /api/v1/work-orders/{id},POST /api/v1/work-orders/{id}/transition,POST …/{id}/comments,POST …/{id}/photos(multipart),GET /api/v1/work-orders/photos/{photo_id},GET …/{id}/route,POST …/{id}/checks,POST /api/v1/work-orders/field-defect,POST /api/v1/field/track,POST /api/v1/forms/submissions,GET /api/v1/work-orders/{id}/forms,POST /api/v1/network-select,GET /api/defects/lookups. Код —routers/work_orders.py,database/work_orders.py,database/work_order_route.py,routers/field_track.py,database/field_track.py. - Тесты: vitest —
tests/utils/fieldQueue.spec.ts,fieldNetwork.spec.ts,fieldRoute.spec.ts,fieldDefect.spec.ts,fieldTrack.spec.ts,workOrders.spec.ts; API —tests/test_work_orders.py,tests/test_work_order_route.py,tests/test_field_track.py,tests/test_forms.py. Отдельного e2e у страницы нет.
