- Клиентская часть Vue 3 + Vite - Серверная часть Node.js + WebSocket - Система авторизации и смен - Управление игровыми портами - Поддержка тем (светлая/темная) - Адаптивный дизайн 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
11 KiB
11 KiB
План 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().
- Единая обертка над WebSocket‑вызовами, скрывает
Файловая структура (предлагаемая)
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
Детали реализации (ключевые моменты)
- WS URL и поведение по умолчанию: читать
import.meta.env.VITE_WS_URL || 'ws://localhost:9000'в низком слое (не в UI). - Убрать
window.systemMessageHandler: организовать подписки внутриuseWebSocketGlobal(или локальная шина событий) и передавать уведомления вuseIndicators. - Ошибки: единый helper
notifyError(message)(позже заменить на toast), безalertдля прод. - Логи: в прод режиме (
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 строк<script setup>. - Критерий: сборка
npm run buildуспешна, консоль без новых ошибок.
Спецификации props/emit (выдержки)
- HeaderBar.vue
- Props:
{ isPaused: Boolean } - Emits:
toggle-pause,request-shutdown,request-logout,open-shift-modal
- Props:
- FooterBar.vue
- Props:
{ indicators: Object }
- Props:
- PortsGrid.vue
- Props:
{ ports: Array, selectedId?: Number } - Emits:
click-port(id: Number)
- Props:
- ConfirmDialog.vue
- v-model:
modelValue:Boolean; Emits:update:modelValue,confirm,cancel
- v-model:
Пример wsApi (псевдокод)
// client/src/api/wsApi.js
import { useWebSocketGlobal } from '@/composables/useWebSocketGlobal'
const request = async (doName, payload = {}, timeout = 10000) => {
const { getGlobalSocket } = useWebSocketGlobal()
const socket = await getGlobalSocket()
const message = { do: doName, ...payload }
return await socket.sendMessage(message, timeout)
}
export const wsApi = {
info: () => request('info'),
smenaOpen: () => request('smena', { enable: true }),
smenaClose: (closed) => request('smena', { enable: false, closed }),
tehOpen: () => request('teh-smena', { enable: true }),
tehClose: (closeObj) => request('teh-smena', { enable: false, closeObj }),
ping: () => request('ping', {}, 1000),
}
Acceptance (приемка)
- Функциональные потоки: вход → открытие смены → работа с портами → закрытие смены; тех. смена — без регрессий.
- HomePage не содержит прямых WS‑вызовов, только обращения к composables/API.
- Визуальное поведение/верстка без отличий.
- Консоль без ошибок, DEV‑логи выключаемы в PROD.
Риски и смягчение
- Риск рассинхронизации протокола WS: сначала вводим
wsApi, затем переносим логику — минимальные изменения UI. - Риск утраты поведения в модалках: сначала выделяем ConfirmDialog и покрываем кейсы выход/выключение, затем переносим формы смен.
- Риск сбоев из‑за «битых» строк: поэтапная замена строк UTF‑8 в изменяемых файлах.
План отката
- Каждая итерация — отдельный коммит/PR. При регрессии — revert последней итерации.
Оценка трудозатрат (грубая)
- Итерация 0–1: 4–6 часов (wsApi + PortsGrid).
- Итерация 2–3: 6–8 часов (Header/Footer + модалки).
- Итерация 4–6: 10–14 часов (composables, перенос логики).
- Итерация 7: 2–4 часа (полировка/приемка).