# План 1: Рефакторинг HomePage.vue (разделение UI/бизнес/сеть) Документ описывает подробный план раскладывания `client/src/pages/HomePage.vue` (~1200 строк) на независимые компоненты и вынос бизнес‑логики/сетевых вызовов в composables. Цель — сохранить текущее поведение, повысить читаемость, переиспользуемость и упростить сопровождение. ## Текущее состояние и проблемы - В одном файле смешаны: верстка, управление модалками, работа со сменами, сетевые вызовы WebSocket, вывод ошибок и индикаторы системного состояния. - Повторяются вызовы `socket.sendMessage({ do: ... })`; протокол (`do`, `promise`) «просачивается» в UI. - Сложно тестировать и вносить изменения — любая правка затрагивает большой файл. ## Целевая архитектура Страница — тонкий контейнер, который собирает: - Отдельные UI‑компоненты (layout, grid, модалки) через props/emit. - Composables для состояния и бизнес‑логики. - Тонкий слой WS‑API вместо прямых `sendMessage`. ### Новые компоненты (директории и обязанности) - `components/layout/HeaderBar.vue` - Отвечает за кнопки: пауза, выключение, выход, переключатель темы. - Props: `isPaused: boolean`. - Emits: `toggle-pause`, `request-shutdown`, `request-logout`, `open-shift-modal`. - `components/layout/FooterBar.vue` - Отображает индикаторы (ESP, link‑to‑server, sync) и счетчики. - Props: `indicators: { esp:boolean, ext:boolean, sync:string, ... }`. - Emits: по необходимости (`open-tech-shift`, и т.п.). - `components/game/PortsGrid.vue` - Отрисовывает сетку портов. - Props: `ports: Array<{ id:number, active:boolean, occupied:boolean }>`. - Emits: `click-port(id:number)`. - `components/modals/ConfirmDialog.vue` - Универсальная модалка подтверждения. - Props: `modelValue:boolean`, `title:string`, `text:string`, `confirmLabel?:string`, `cancelLabel?:string`, `severity?:'info'|'warn'|'danger'`. - Emits: `update:modelValue`, `confirm`, `cancel`. - `components/modals/ShiftModal.vue` - Форма открытия обычной смены. - Props: `modelValue:boolean`, `form:any`. - Emits: `update:modelValue`, `submit(form)`. - `components/modals/CloseShiftModal.vue` - Форма закрытия смены; валидация данных (касса/расходы/зарплаты). - Props/Emits аналогично. - `components/modals/TechShiftModal.vue` - Открытие/закрытие тех. смены; простые поля + подтверждение. ### Новые composables - `composables/useShift.js` - Держит состояние смен: `regularShift`, `techShift`, `isPaused` и т.п. - Методы: `openRegularShift`, `closeRegularShift(closedData)`, `openTechShift`, `closeTechShift`, `fetchShiftStatus`, `togglePause`. - Обрабатывает ошибки и повторную авторизацию (если требуется) через `useAuth`. - `composables/usePorts.js` - Держит `gamePorts`, `selectedPort`, вычисления для сетки. - Методы: `loadInfo()`, `selectPort(id)`, `handlePortClick(id)`. - `composables/useIndicators.js` - Держит индикаторы: `espConnected`, `extServerConnected`, `syncState`. - Подписка на системные сообщения из слоя WS (без `window.*`). - `api/wsApi.js` - Единая обертка над WebSocket‑вызовами, скрывает `promise/do`. - Методы: `info()`, `smenaOpen()`, `smenaClose(closedData)`, `tehOpen()`, `tehClose(closeObj)`, `ping()`. ### Файловая структура (предлагаемая) ``` client/src/ api/wsApi.js components/ layout/HeaderBar.vue layout/FooterBar.vue game/PortsGrid.vue modals/ConfirmDialog.vue modals/ShiftModal.vue modals/CloseShiftModal.vue modals/TechShiftModal.vue composables/ useShift.js usePorts.js useIndicators.js ``` ## Детали реализации (ключевые моменты) 1) WS URL и поведение по умолчанию: читать `import.meta.env.VITE_WS_URL || 'ws://localhost:9000'` в низком слое (не в UI). 2) Убрать `window.systemMessageHandler`: организовать подписки внутри `useWebSocketGlobal` (или локальная шина событий) и передавать уведомления в `useIndicators`. 3) Ошибки: единый helper `notifyError(message)` (позже заменить на toast), без `alert` для прод. 4) Логи: в прод режиме (`import.meta.env.PROD`) минимизировать `console.log`. ## Пошаговый план (итерации с критерием готовности) Итерация 0 — Подготовка - Добавить `api/wsApi.js` с оберткой `request(do, payload, { timeout })` и методами `info/smenaOpen/smenaClose/tehOpen/tehClose/ping`. - Критерий: все вызовы на странице можно заменить без изменения логики. Итерация 1 — PortsGrid - Вырезать сетку портов в `components/game/PortsGrid.vue`. - Пробросить данные через props и клики через emit. - В `HomePage.vue` слушать `click-port` и вызывать логику из страницы (временный мост). - Критерий: визуально без изменений, клики работают как прежде. Итерация 2 — Header/Footer - Создать `layout/HeaderBar.vue`, `layout/FooterBar.vue`, перенести кнопки/индикаторы. - Все действия экспонировать через emit, состояние — через props. - Критерий: UI/поведение идентичны (пауза, выход/выключение, индикаторы). Итерация 3 — Модалки - Создать `ConfirmDialog.vue` и заменить подтверждения выхода/выключения. - Создать `ShiftModal.vue`, `CloseShiftModal.vue`, `TechShiftModal.vue`. - Критерий: открытие/закрытие модалок и сабмиты работают как прежде. Итерация 4 — useShift - Вынести всю логику смен (открыть/закрыть/тех) из страницы в `useShift` и перевести вызовы на `wsApi`. - Критерий: HomePage не содержит прямых `sendMessage`; все операции смен — через `useShift`. Итерация 5 — usePorts - Перенести состояние и обработчики портов в `usePorts` (загрузка `info()`, выбор порта, computed состояния). - Критерий: HomePage оперирует только вызовами `usePorts` и `PortsGrid`. Итерация 6 — useIndicators - Перенести индикаторы и подписки на системные сообщения в `useIndicators` (подключение к глобальному WS). - Критерий: индикаторы меняются корректно, без глобальных хендлеров в `window`. Итерация 7 — Уборка и полировка - Привести строки к UTF‑8, убрать «битую» кодировку, разграничить `DEV/PROD`‑логи. - Ограничить `HomePage.vue` до 150–200 строк `