Files
vue-pult/plans/plan1.md
sasha 3e90269b0b Initial commit: Vue.js тир управления система
- Клиентская часть Vue 3 + Vite
- Серверная часть Node.js + WebSocket
- Система авторизации и смен
- Управление игровыми портами
- Поддержка тем (светлая/темная)
- Адаптивный дизайн

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-19 12:24:22 +03:00

11 KiB
Raw Blame History

План 1: Рефакторинг HomePage.vue (разделение UI/бизнес/сеть)

Документ описывает подробный план раскладывания client/src/pages/HomePage.vue (~1200 строк) на независимые компоненты и вынос бизнес‑логики/сетевых вызовов в composables. Цель — сохранить текущее поведение, повысить читаемость, переиспользуемость и упростить сопровождение.

Текущее состояние и проблемы

  • В одном файле смешаны: верстка, управление модалками, работа со сменами, сетевые вызовы WebSocket, вывод ошибок и индикаторы системного состояния.
  • Повторяются вызовы socket.sendMessage({ do: ... }); протокол (do, promise) «просачивается» в UI.
  • Сложно тестировать и вносить изменения — любая правка затрагивает большой файл.

Целевая архитектура

Страница — тонкий контейнер, который собирает:

  • Отдельные UIкомпоненты (layout, grid, модалки) через props/emit.
  • Composables для состояния и бизнес‑логики.
  • Тонкий слой WSAPI вместо прямых sendMessage.

Новые компоненты (директории и обязанности)

  • components/layout/HeaderBar.vue
    • Отвечает за кнопки: пауза, выключение, выход, переключатель темы.
    • Props: isPaused: boolean.
    • Emits: toggle-pause, request-shutdown, request-logout, open-shift-modal.
  • components/layout/FooterBar.vue
    • Отображает индикаторы (ESP, linktoserver, 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 — Уборка и полировка

  • Привести строки к UTF8, убрать «битую» кодировку, разграничить DEV/PROD‑логи.
  • Ограничить HomePage.vue до 150200 строк <script setup>.
  • Критерий: сборка npm run build успешна, консоль без новых ошибок.

Спецификации props/emit (выдержки)

  • HeaderBar.vue
    • Props: { isPaused: Boolean }
    • Emits: toggle-pause, request-shutdown, request-logout, open-shift-modal
  • FooterBar.vue
    • Props: { indicators: Object }
  • PortsGrid.vue
    • Props: { ports: Array, selectedId?: Number }
    • Emits: click-port(id: Number)
  • ConfirmDialog.vue
    • v-model: modelValue:Boolean; Emits: update:modelValue, confirm, cancel

Пример 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 и покрываем кейсы выход/выключение, затем переносим формы смен.
  • Риск сбоев из‑за «битых» строк: поэтапная замена строк UTF8 в изменяемых файлах.

План отката

  • Каждая итерация — отдельный коммит/PR. При регрессии — revert последней итерации.

Оценка трудозатрат (грубая)

  • Итерация 01: 46 часов (wsApi + PortsGrid).
  • Итерация 23: 68 часов (Header/Footer + модалки).
  • Итерация 46: 1014 часов (composables, перенос логики).
  • Итерация 7: 24 часа (полировка/приемка).