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

173 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# План 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 (псевдокод)
```js
// 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 часа (полировка/приемка).