feat: завершить миграцию фронтенда на React (этапы 1-5)
Админка, настройки, логин, кабинеты преподавателя и студента полностью переведены на React 19 (модель strangler, docs/REACT_MIGRATION.md). - 15 вкладок админки: lazy-загрузка, общий error boundary, сервисный слой - Удалены legacy-views и переходный слой LegacyTabView (45 файлов) - Сборка esbuild (frontend/scripts/build-react.mjs) с бюджетами gzip на чанки - CSP-хэши, кэширование: chunk'и immutable, CSS/HTML no-cache (react-cache.conf) - Фиксы: lazy-импорт именованных экспортов (краш после авторизации), растяжение #admin-root/#settings-root на всю ширину, возврат subjects/lessonTypes из справочников (краш просмотра расписаний), отказ от заведомо широкого поиска расписания без выбранной цели, центрирование карточки логина - Тесты: 237/237 (npm run check), регрессионные на lazy-вкладки и ширину - Документация: REACT_MIGRATION.md, REACT_MIGRATION_RESULT.md, FRONTEND.md
This commit is contained in:
280
docs/FRONTEND.md
280
docs/FRONTEND.md
@@ -4,12 +4,16 @@
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|----------|
|
||||
| **Фреймворк** | Нет (Vanilla JavaScript) |
|
||||
| **Фреймворк** | Переходный режим: React 19 для страницы входа, кабинетов студента и преподавателя, страницы настроек и общего слоя `react/shared`, Vanilla JavaScript для остальных разделов |
|
||||
| **Модульная система** | ES6 Modules (`import`/`export`) |
|
||||
| **Стили** | CSS (модульный подход) |
|
||||
| **Шрифт** | Системный стек без внешних font-CDN |
|
||||
| **Веб-сервер** | Apache httpd на Alpine со строгим CSP |
|
||||
|
||||
Пошаговый план и актуальная точка продолжения находятся в
|
||||
[`REACT_MIGRATION.md`](REACT_MIGRATION.md). Миграция выполняется по целым страницам и
|
||||
разделам без изменения действующих URL и REST-контрактов.
|
||||
|
||||
---
|
||||
|
||||
## Структура файлов
|
||||
@@ -23,10 +27,90 @@ frontend/
|
||||
├── schedule-overview.js # Общий расчёт и рендер «Сегодня / Следующая пара»
|
||||
├── schedule-overview.css # Общие карточки ближайших занятий и поискового выбора группы
|
||||
├── security.conf # CSP и защитные HTTP-заголовки Apache
|
||||
├── react-cache.conf # Cache-Control: immutable для chunk'ов, no-cache для entrypoint, CSS и HTML
|
||||
├── telemetry/
|
||||
│ └── otel-entry.js # Исходная точка сборки OpenTelemetry
|
||||
├── scripts/
|
||||
│ ├── build-react.mjs # Production-сборка React entrypoint и проверка gzip-бюджета
|
||||
│ ├── build-react-tests.mjs # Сборка компонентных проверок для node:test
|
||||
│ └── build-vendor.mjs # Сборка `/vendor/otel.js` через esbuild
|
||||
├── react/
|
||||
│ ├── login/
|
||||
│ │ ├── LoginApp.jsx # React-компонент страницы входа
|
||||
│ │ ├── login-service.js # Валидация и контракт POST /api/auth/login
|
||||
│ │ └── main.jsx # React entrypoint для `/`
|
||||
│ ├── student/ # Кабинет студента на React
|
||||
│ │ ├── StudentApp.jsx # Сессия, выбор группы, неделя и состояния
|
||||
│ │ ├── WeekGrid.jsx # Недельная сетка дней и занятий
|
||||
│ │ ├── student-service.js # Чипы, статусы и контракты API кабинета студента
|
||||
│ │ ├── main.jsx # React entrypoint для `/student/`
|
||||
│ │ └── testing/ # render-student.jsx для DOM-проверок
|
||||
│ ├── teacher/ # Кабинет преподавателя на React
|
||||
│ │ ├── TeacherApp.jsx # Сессия, вкладки, неделя и состояния
|
||||
│ │ ├── TeacherWeekGrid.jsx # Матрица слотов и мобильный список дней
|
||||
│ │ ├── AbsencePanel.jsx # Заявки об отсутствии
|
||||
│ │ ├── PreferencesTab.jsx # Семестровый календарь доступности
|
||||
│ │ ├── RequestsTab.jsx # Журнал заявок на изменение пар
|
||||
│ │ ├── RequestDialog.jsx # Диалог переноса/аудитории/отмены
|
||||
│ │ ├── teacher-service.js # Слоты, матрица недели, метки и контракты API
|
||||
│ │ ├── main.jsx # React entrypoint для `/teacher/`
|
||||
│ │ └── testing/ # render-teacher.jsx для DOM-проверок
|
||||
│ ├── settings/ # Страница настроек на React
|
||||
│ │ ├── SettingsApp.jsx # Сессия, боковая панель, вкладки и тема
|
||||
│ │ ├── GeneralTab.jsx # Заглушка общих настроек
|
||||
│ │ ├── TimeSlotsTab.jsx # Сетки времени и CRUD временных слотов
|
||||
│ │ ├── EduFormsTab.jsx # Формы обучения
|
||||
│ │ ├── DatabaseTab.jsx # Статус подключения и тенанты
|
||||
│ │ ├── settings-service.js # Метки сеток, валидация и контракты API
|
||||
│ │ ├── main.jsx # React entrypoint для `/admin/settings/`
|
||||
│ │ └── testing/ # render-settings.jsx для DOM-проверок
|
||||
│ ├── admin/ # Оболочка основной админ-панели на React
|
||||
│ │ ├── AdminApp.jsx # Сессия, sidebar с секциями, topbar, hash-router
|
||||
│ │ ├── react-tabs.js # Реестр всех вкладок админ-панели (lazy + Suspense)
|
||||
│ │ ├── admin-service.js # Маршруты, секции навигации, склонения, контракты API
|
||||
│ │ ├── classrooms-service.js # Статусы, оборудование и контракты API аудиторий
|
||||
│ │ ├── subjects-service.js # Состояние реестра, URL-параметры и контракты API дисциплин
|
||||
│ │ ├── dashboard-service.js # Метрики, слоты, свободные аудитории и конфликты Red Zone
|
||||
│ │ ├── users-service.js # Роли, состояние реестра и контракты API пользователей
|
||||
│ │ ├── groups-service.js # Подгруппы, календарные графики и контракты API групп
|
||||
│ │ ├── university-structure-service.js # Фильтрация списков и контракты API кафедр/специальностей/профилей
|
||||
│ │ ├── teacher-requests-service.js # Состояние реестра, валидация одобрения и контракты API заявок
|
||||
│ │ ├── department-workspace-service.js # Нагрузка, payload-валидация и контракты API кабинета кафедры
|
||||
│ │ ├── auditorium-workload-service.js # Дедупликация занятий, чётность недель и контракты API загруженности
|
||||
│ │ ├── academic-calendar-service.js # Учебные годы, сетка графика, диалог ячейки и контракты API календаря
|
||||
│ │ ├── schedule-view-service.js # Разделы расписания, семестровая матрица и контракты API просмотра
|
||||
│ │ ├── schedule-service.js # Слоты правил, payload-валидация, визуальная матрица и контракты API конструктора
|
||||
│ │ ├── schedule-override-service.js # Источник правки, календарь семестра и контракты API разовых правок
|
||||
│ │ ├── schedule-versions-service.js # Группировка версий, подписи журнала и контракты API контура публикаций
|
||||
│ │ ├── schedule-quality-service.js # Диапазоны оценки, фильтры проблем и контракт API анализа качества
|
||||
│ │ ├── teacher-absences-service.js # Решения мастера замены, подписи статусов и контракты API отсутствий
|
||||
│ │ ├── tabs/ # Вкладки админ-панели (волны 1–6, все вкладки на React)
|
||||
│ │ │ ├── DashboardTab.jsx # Метрики, мониторинг пар, Red Zone
|
||||
│ │ │ ├── ClassroomsTab.jsx # Аудиторный фонд с мультиселектом оборудования
|
||||
│ │ │ ├── SubjectsTab.jsx # Реестр дисциплин с пагинацией и преподавателями
|
||||
│ │ │ ├── UsersTab.jsx # Реестр пользователей с фильтром роли и архивированием
|
||||
│ │ │ ├── GroupsTab.jsx # Реестр групп, подгруппы и календарные графики
|
||||
│ │ │ ├── UniversityStructureTab.jsx # Кафедры, специальности и профили обучения
|
||||
│ │ │ ├── TeacherRequestsTab.jsx # Реестр заявок с редактируемыми строками и отклонением через PromptDialog
|
||||
│ │ │ ├── DepartmentWorkspaceTab.jsx # Кабинет кафедры: дисциплины, преподаватели, нагрузка, заявки
|
||||
│ │ │ ├── AuditoriumWorkloadTab.jsx # Загруженность: сводная матрица и двухнедельная сводка сущности
|
||||
│ │ │ ├── AcademicCalendarTab.jsx # Календарные графики: годы, сетки, дисциплины (MaskedDateInput)
|
||||
│ │ │ ├── ScheduleViewTab.jsx # Просмотр расписаний: фильтры, разделы, матрица и панель правок
|
||||
│ │ │ ├── ScheduleTab.jsx # Конструктор правил: каскад версий, форма правила и визуальная матрица
|
||||
│ │ │ ├── ScheduleVersionsTab.jsx # Контур публикаций: черновики, diff, архив, журнал и модальные операции
|
||||
│ │ │ ├── ScheduleQualityTab.jsx # Анализ качества: скорборд, метрики, карта проблем и панель правила
|
||||
│ │ │ └── TeacherAbsencesTab.jsx # Отсутствия: реестр, мастер замены, пожелания и заявки на изменение
|
||||
│ │ ├── main.jsx # React entrypoint для `/admin/`
|
||||
│ │ └── testing/ # render-admin.jsx для DOM-проверок
|
||||
│ └── shared/ # Общий React-слой для следующих переносимых страниц
|
||||
│ ├── api-client.js # requestJson/apiClient поверх auth-транспорта
|
||||
│ ├── auth-client.js # Восстановление сессии и logout с redirect
|
||||
│ ├── dates.js # Дата-математика (недели, ISO, форматирование)
|
||||
│ ├── session-policy.js # Фазы loading/ready/unauthorized/error и русские тексты
|
||||
│ ├── use-authorized-session.js # Хук проверки роли при монтировании страницы
|
||||
│ ├── runtime-entry.jsx # Единая точка экспорта общего runtime-chunk
|
||||
│ ├── ui/ # AppErrorBoundary, AsyncState, FormAlert, AsyncCombobox, ScheduleOverview, ConfirmDialog, Pagination
|
||||
│ └── testing/ # render-shared.jsx для DOM-проверок через renderToStaticMarkup
|
||||
├── tests/
|
||||
│ ├── academic-calendar-grid.test.mjs # Неполная первая неделя календарного графика
|
||||
│ ├── academic-calendar-title.test.mjs # Составное название календарного графика
|
||||
@@ -34,6 +118,13 @@ frontend/
|
||||
│ ├── schedule-overview.test.mjs # Текущее занятие, список на сегодня и следующая пара
|
||||
│ ├── admin-ui-regressions.test.mjs # Заголовки, меню, действия слотов и компоновка вкладок
|
||||
│ ├── auth-session.test.mjs # Login/refresh/reload/logout и single-flight refresh
|
||||
│ ├── react-login.test.mjs # Валидация и API-контракт React-формы входа
|
||||
│ ├── react-shared.test.mjs # Общая политика сессии, API-клиент и DOM-проверки состояний
|
||||
│ ├── react-student.test.mjs # Дата-математика, чипы, контракты API и DOM-проверки кабинета студента
|
||||
│ ├── react-teacher.test.mjs # Слоты, матрица недели, метки, payload заявок и DOM-проверки кабинета преподавателя
|
||||
│ ├── react-settings.test.mjs # Вкладки по ролям, метки сеток, валидация и контракты API страницы настроек
|
||||
│ ├── react-admin.test.mjs # Навигация по ролям, hash-маршруты, склонения и DOM-проверки оболочки админки
|
||||
│ ├── react-admin-tabs.test.mjs # Сервисы и DOM-проверки вкладок волн 1–5 (дашборд, аудитории, дисциплины, пользователи, группы, структура вуза, заявки, кабинет кафедры, загруженность, календарные графики, вкладки расписания)
|
||||
│ ├── dashboard-conflicts.test.mjs # Регрессии дат и состояний проверки конфликтов
|
||||
│ ├── schedule-overrides.test.mjs # Действия, роли, недельный выбор и подбор времени разовой правки
|
||||
│ ├── schedule-quality.test.mjs # Метрики качества, фильтры проблем и доступность вкладки
|
||||
@@ -43,13 +134,12 @@ frontend/
|
||||
│ ├── teacher-preferences.test.mjs # Календарь пожеланий, заявки и подсказки конструктора
|
||||
│ └── security-policy.test.mjs # Web Storage, XSS, пароли, язык, CSP и Dockerfile
|
||||
├── index.html # 🔐 Страница авторизации (общая)
|
||||
├── script.js # Логика авторизации
|
||||
├── style.css # Стили страницы авторизации
|
||||
├── theme-toggle.js # Переключение светлой/тёмной темы
|
||||
├── Dockerfile # Multi-stage: npm bundle → Apache httpd
|
||||
│
|
||||
├── admin/ # 👨💼 Интерфейс администратора
|
||||
│ ├── index.html # SPA-оболочка с sidebar
|
||||
│ ├── index.html # Монтирует React-оболочку `/react/admin.js`
|
||||
│ ├── css/
|
||||
│ │ ├── main.css # CSS-переменные, цвета, типографика
|
||||
│ │ ├── layout.css # Раскладка (sidebar, topbar, content)
|
||||
@@ -61,81 +151,37 @@ frontend/
|
||||
│ │ ├── schedule-quality.css # Диагностический экран качества расписания
|
||||
│ │ └── schedule-versions.css # Контур публикации, diff и журнал версий
|
||||
│ ├── js/
|
||||
│ │ ├── main.js # Инициализация, маршрутизация, навигация
|
||||
│ │ ├── role-capabilities.js # Единая матрица вкладок admin/settings по ролям
|
||||
│ │ ├── api.js # HTTP-обёртка (fetch + Authorization)
|
||||
│ │ ├── dashboard-conflicts.js # Чистые функции дат, загрузки и состояний Red Zone
|
||||
│ │ ├── date-input.js # Маска ДД.ММ.ГГГГ и преобразование дат в ISO
|
||||
│ │ ├── async-combobox.js # Асинхронный поиск больших справочников
|
||||
│ │ ├── dialog.js # Доступные подтверждения, сообщения и ввод причины
|
||||
│ │ ├── dirty-state.js # Защита несохранённых изменений
|
||||
│ │ ├── pagination.js # Общая панель серверной пагинации
|
||||
│ │ ├── url-state.js # Чтение и запись фильтров в query string
|
||||
│ │ ├── view-state.js # Единые loading/empty/error-состояния таблиц
|
||||
│ │ ├── academic-period.js # Каскад учебного года и семестра в профильных вкладках
|
||||
│ │ ├── utils.js # Утилиты
|
||||
│ │ ├── schedule-period.js # Выбор ближайшего учебного периода для расписаний и нагрузки
|
||||
│ │ └── views/ # Модули представлений
|
||||
│ │ ├── dashboard.js # Дашборд
|
||||
│ │ ├── users.js # Управление пользователями
|
||||
│ │ ├── teacher-requests.js # Заявки кафедр на преподавателей
|
||||
│ │ ├── groups.js # Управление группами
|
||||
│ │ ├── classrooms.js # Управление аудиториями
|
||||
│ │ ├── subjects.js # Управление дисциплинами
|
||||
│ │ ├── university-structure.js # Кафедры, специальности и профили обучения
|
||||
│ │ ├── department-workspace.js # Кабинет кафедры в общей панели
|
||||
│ │ ├── schedule-view.js # Просмотр расписаний и запуск разовой правки из карточки
|
||||
│ │ ├── schedule-override-panel.js # Боковая панель и реестр разовых изменений
|
||||
│ │ ├── teacher-absences.js # Отсутствия, согласование пожеланий и заявок на изменение
|
||||
│ │ ├── schedule-quality.js # Оценка, фильтры и переход к редактированию правил
|
||||
│ │ ├── schedule-versions.js # Черновики, публикация, восстановление, diff и аудит
|
||||
│ │ ├── schedule.js # Конструктор правил и подсказки пожеланий преподавателей
|
||||
│ │ ├── academic-calendar-grid.js # Расчёт ISO-недели дневной сетки
|
||||
│ │ ├── academic-calendar-title.js # Название из кода, профиля, формы и года
|
||||
│ │ ├── academic-calendar.js # Календарные учебные графики
|
||||
│ │ └── auditorium-workload.js # Загруженность аудиторий, преподавателей и кафедр
|
||||
│ ├── views/ # HTML-шаблоны представлений
|
||||
│ │ ├── dashboard.html
|
||||
│ │ ├── users.html
|
||||
│ │ ├── teacher-requests.html
|
||||
│ │ ├── groups.html
|
||||
│ │ ├── classrooms.html
|
||||
│ │ ├── subjects.html
|
||||
│ │ ├── university-structure.html
|
||||
│ │ ├── department-workspace.html
|
||||
│ │ ├── schedule-view.html
|
||||
│ │ ├── teacher-absences.html
|
||||
│ │ ├── schedule-quality.html
|
||||
│ │ ├── schedule-versions.html
|
||||
│ │ ├── schedule.html
|
||||
│ │ ├── academic-calendar.html
|
||||
│ │ └── auditorium-workload.html
|
||||
│ │ └── views/ # Общие чистые хелперы (используются React-сервисами)
|
||||
│ │ ├── academic-calendar-grid.js # Расчёт ISO-недели дневной сетки (общий с React-сервисом)
|
||||
│ │ └── academic-calendar-title.js # Название из кода, профиля, формы и года (общий с React-сервисом)
|
||||
│ │
|
||||
│ └── settings/ # ⚙️ Страница настроек (отдельный SPA)
|
||||
│ ├── index.html # Оболочка с собственной sidebar
|
||||
│ ├── css/
|
||||
│ │ ├── main.css # CSS-переменные, базовые стили
|
||||
│ │ └── layout.css # Sidebar, topbar, content
|
||||
│ ├── js/
|
||||
│ │ ├── main.js # Навигация по вкладкам настроек
|
||||
│ │ └── views/
|
||||
│ │ └── time-slots.js # Настройка временных слотов
|
||||
│ └── views/
|
||||
│ ├── general.html # Общие настройки (заглушка)
|
||||
│ └── time-slots.html # Базовая, субботняя и ручные сетки времени
|
||||
│ └── settings/ # ⚙️ Страница настроек (отдельный SPA на React)
|
||||
│ ├── index.html # Оболочка с корневым элементом settings-root
|
||||
│ └── css/
|
||||
│ ├── main.css # CSS-переменные, базовые стили
|
||||
│ └── layout.css # Sidebar, topbar, content
|
||||
│
|
||||
├── teacher/ # 👩🏫 Интерфейс преподавателя
|
||||
│ ├── index.html # Расписание, календарь доступности и журнал заявок
|
||||
│ ├── app.js # Пожелания, переносы и недельный просмотр через общий auth-session
|
||||
├── teacher/ # 👩🏫 Интерфейс преподавателя (React)
|
||||
│ ├── index.html # Оболочка с корневым элементом teacher-root
|
||||
│ └── style.css # Адаптивный кабинет в стиле диспетчерского журнала
|
||||
├── department/ # 🏛 Кабинет кафедры
|
||||
│ └── index.html # Redirect в `/admin/#department-workspace`
|
||||
├── edu-office/ # 🗓 Кабинет учебного отдела
|
||||
│ └── index.html # Redirect в `/admin/#schedule-view`
|
||||
│
|
||||
└── student/ # 🎓 Интерфейс студента
|
||||
├── index.html # CSP-совместимая HTML-оболочка
|
||||
├── app.js # Недельный просмотр и общий auth-session
|
||||
└── student/ # 🎓 Интерфейс студента (React)
|
||||
├── index.html # Оболочка с корневым элементом student-root
|
||||
└── style.css # Стили кабинета без inline-блока
|
||||
```
|
||||
|
||||
@@ -143,24 +189,36 @@ frontend/
|
||||
|
||||
## Система маршрутизации (Admin SPA)
|
||||
|
||||
Админ-панель работает как **Single Page Application** без фреймворка.
|
||||
Оболочка админ-панели работает на **React** (`react/admin/AdminApp.jsx`, entrypoint
|
||||
`/react/admin.js`): sidebar с секциями, topbar с заголовком вкладки и счётчиком заявок,
|
||||
тема, сворачивание панели, настройки с выходом и hash-router.
|
||||
|
||||
Навигация реализована через `data-tab` атрибуты на элементах sidebar:
|
||||
Навигация реализована через hash-адреса вкладок (`#users`, `#schedule` и т. д.):
|
||||
|
||||
```html
|
||||
<a href="#" class="nav-item" data-tab="users">Пользователи</a>
|
||||
<a href="#" class="nav-item" data-tab="groups">Группы</a>
|
||||
<a href="#" class="nav-item" data-tab="schedule">Расписание занятий</a>
|
||||
<a href="#" class="nav-item" data-tab="academic-calendar">Календарный график</a>
|
||||
```
|
||||
- при старте активная вкладка читается из `location.hash` (неразрешённые роли
|
||||
значения заменяются вкладкой по умолчанию);
|
||||
- слушатель `hashchange` синхронизирует вкладку с адресной строкой (работают
|
||||
кнопки «назад/вперёд» и ссылки из других кабинетов);
|
||||
- переключение идёт через `requestTabSwitch` с guard'ом несохранённых изменений
|
||||
из общего модуля `admin/js/dirty-state.js`.
|
||||
|
||||
При клике на пункт меню `main.js`:
|
||||
1. Загружает HTML-шаблон из `views/{tab}.html` через `fetch()`
|
||||
2. Вставляет его в `#app-content`
|
||||
3. Подключает соответствующий JS-модуль из `js/views/{tab}.js`
|
||||
4. Обновляет заголовок страницы (`#page-title`)
|
||||
Содержимое вкладки выбирается по реестру `react/admin/react-tabs.js`:
|
||||
|
||||
`main.js` и отдельный settings SPA получают разрешённые вкладки из единого
|
||||
- **все 15 вкладок админ-панели** (волна 1: `dashboard`, `classrooms`, `subjects`;
|
||||
волна 2: `users`, `groups`, `university-structure`; волна 3:
|
||||
`teacher-requests`, `department-workspace`; волна 4: `auditorium-workload`,
|
||||
`academic-calendar`; волна 5: `schedule-view`, `schedule-versions`,
|
||||
`schedule-quality`, `teacher-absences`; волна 6: `schedule`)
|
||||
рендерятся React-компонентами из `react/admin/tabs/`, каждый загружается
|
||||
отдельным lazy-chunk'ом (`React.lazy` + `Suspense`, fallback — индикатор
|
||||
`tab-loading`);
|
||||
- переходный слой `LegacyTabView` + `legacy-views.js` и каталоги
|
||||
`admin/views/*.html` / `admin/js/views/{tab}.js` удалены после волны 6 —
|
||||
HTML-фрагменты больше не загружаются через `fetch`, в `admin/js/views/`
|
||||
остались только общие чистые хелперы календарных графиков.
|
||||
|
||||
React-оболочка админки (`react/admin/admin-service.js`) и React-оболочка настроек
|
||||
(`react/settings/SettingsApp.jsx`) получают разрешённые вкладки из единого
|
||||
`admin/js/role-capabilities.js`; локальные дубли `ROLE_NAVIGATION`/`ROLE_TABS` удалены.
|
||||
|
||||
| Роль | Доступные вкладки |
|
||||
@@ -172,10 +230,11 @@ frontend/
|
||||
|
||||
Пути `/department/` и `/edu-office/` оставлены как входные redirect-страницы в общую панель. Отдельные кабинеты не дублируют UI админ-панели.
|
||||
|
||||
Пункты меню, недоступные роли, не отображаются в sidebar: `main.js` выставляет `hidden`, а `layout.css` явно скрывает такие элементы, чтобы базовый `display: flex` у `.nav-item` не возвращал их на экран.
|
||||
Верхние панели основной админки и settings SPA не содержат неработающей кнопки
|
||||
бургер-меню. В светлой теме пункты и заголовки sidebar получают контрастные тёмные цвета
|
||||
для всех ролей, включая `DEPARTMENT`.
|
||||
Пункты меню, недоступные роли, не попадают в sidebar: React-оболочка фильтрует
|
||||
секции навигации по матрице ролей до рендера. Верхние панели основной админки и
|
||||
settings SPA не содержат неработающей кнопки бургер-меню. В светлой теме пункты и
|
||||
заголовки sidebar получают контрастные тёмные цвета для всех ролей, включая
|
||||
`DEPARTMENT`.
|
||||
|
||||
### Разделы админ-панели
|
||||
|
||||
@@ -267,9 +326,9 @@ frontend/
|
||||
восстанавливают поиск, фильтры, сортировку, номер и размер страницы после reload или
|
||||
возврата по ссылке. Просмотр расписания сохраняет вид сущности, выбранную сущность, дату,
|
||||
учебный год, семестр и дополнительные фильтры; конечные кабинеты сохраняют неделю, вкладку и группу.
|
||||
- `pagination.js` работает с общим ответом `PageResponse`; размер страницы — 25, 50 или
|
||||
100. `view-state.js` унифицирует загрузку со spinner, пустой результат и ошибку с кнопкой
|
||||
повторного запроса.
|
||||
- Общий React-компонент `react/shared/ui/Pagination.jsx` работает с общим ответом
|
||||
`PageResponse`; размер страницы — 25, 50 или 100. `view-state.js` унифицирует
|
||||
загрузку со spinner, пустой результат и ошибку с кнопкой повторного запроса.
|
||||
- `AsyncCombobox` загружает варианты с сервера, сохраняет выбранный ID, поддерживает
|
||||
клавиатуру и роли `combobox/listbox`. Он используется для групп, преподавателей,
|
||||
аудиторий и совместимых календарных графиков; предварительная загрузка вариантов не
|
||||
@@ -288,13 +347,26 @@ frontend/
|
||||
|
||||
### Страница настроек (`/admin/settings/`)
|
||||
|
||||
Настройки — это **отдельный SPA** со своей боковой панелью и вкладками, не связанными с основной админ-панелью.
|
||||
Страница переведена на React (`react/settings/`, entrypoint `dist/react/settings.js`) и использует
|
||||
общий слой `react/shared`: `useAuthorizedSession(SETTINGS_ROLES)`, `apiClient`, `AsyncState`,
|
||||
`AppErrorBoundary` и общий `ConfirmDialog`/`PromptDialog` (классы `.project-dialog*`,
|
||||
закрытие по Escape и клику по фону; `PromptDialog` — реплика legacy `promptAction`
|
||||
с обязательным текстовым полем и ошибкой внутри диалога). Настройки — **отдельный SPA** со своей боковой панелью и вкладками, не связанными с
|
||||
основной админ-панелью; как и в legacy-версии, hash-навигации нет — активная вкладка живёт
|
||||
в состоянии React.
|
||||
|
||||
- Доступ: через dropdown «Настройки» в footer боковой панели админки для `ADMIN` и `EDUCATION_OFFICE`
|
||||
- Кнопка «Назад в панель» для возврата в `/admin/`
|
||||
- Доступ: через dropdown «Настройки» в footer боковой панели админки для `ADMIN` и `EDUCATION_OFFICE`;
|
||||
список и вкладка по умолчанию фильтруются единой матрицей `admin/js/role-capabilities.js`
|
||||
- Кнопка «Назад в панель» для возврата в `/admin/`, кнопка выхода через общий `logoutAndRedirect`
|
||||
- Сворачивание боковой панели сохраняется в `localStorage.sidebar-collapsed`; тема управляется
|
||||
в React (кнопка в topbar), `theme-toggle.js` на странице больше не подключается
|
||||
- Текущие вкладки:
|
||||
- **Общие настройки** — заглушка (только `ADMIN`)
|
||||
- **Временные слоты** — выбор сетки через выпадающий список, CRUD слотов выбранной сетки, добавление ручных сеток через модальное окно и удаление выбранной ручной сетки. Поле длительности доступно только для чтения и пересчитывается при изменении времени начала или окончания; в API отправляются только границы, а окончательное значение вычисляет backend. Базовая сетка применяется по умолчанию, субботняя — автоматически по субботам; ручное применение выполняется в сетке календарного графика.
|
||||
- **Формы обучения** — создание и удаление форм обучения
|
||||
- **База данных** — статус текущего подключения, реестр тенантов, проверка и добавление нового
|
||||
подключения (пароль помечен `autocomplete="new-password"`); inline-стили legacy заменены
|
||||
классами `.db-status-grid`/`.form-group-wide`/`.form-row-actions`
|
||||
|
||||
---
|
||||
|
||||
@@ -339,11 +411,15 @@ SHA-256 style-хэшей с CSP. Там же закреплены безопас
|
||||
Команды выполняются из каталога `frontend/`:
|
||||
|
||||
```bash
|
||||
npm run build # собрать локальный dist/vendor/otel.js
|
||||
npm run build # собрать dist/vendor/otel.js и dist/react/login.js
|
||||
npm test # frontend unit/static tests
|
||||
npm run check # синтаксис auth/UI-модулей + все frontend-тесты
|
||||
npm run check # React-сборка, синтаксис auth/UI-модулей + все frontend-тесты
|
||||
```
|
||||
|
||||
React-сборка выполняется существующим esbuild без отдельного dev-сервера. Для страницы
|
||||
входа установлен лимит 75 000 байт gzip; превышение завершает сборку ошибкой. При появлении
|
||||
нескольких React entrypoint общий runtime будет вынесен в отдельный кэшируемый chunk.
|
||||
|
||||
---
|
||||
|
||||
## Аутентификация (Frontend)
|
||||
@@ -351,7 +427,7 @@ npm run check # синтаксис auth/UI-модулей + все frontend-т
|
||||
### Страница входа (`/index.html`)
|
||||
|
||||
1. Пользователь вводит логин/пароль
|
||||
2. `script.js` отправляет `POST /api/auth/login`
|
||||
2. `react/login/LoginApp.jsx` через `login-service.js` отправляет `POST /api/auth/login`
|
||||
3. При успехе кладёт access JWT и профиль пользователя только в память текущей страницы.
|
||||
4. Refresh-токен сохраняется браузером как `HttpOnly` cookie и недоступен JavaScript.
|
||||
5. После перехода новый документ восстанавливает память через `POST /api/auth/refresh`.
|
||||
@@ -409,25 +485,31 @@ if (!session || !AUTHORIZED_ROLES.includes(session.role)) {
|
||||
|
||||
### Преподаватель (`/teacher/`)
|
||||
|
||||
Страница объединяет недельную сетку занятий, семестровый календарь доступности и журнал
|
||||
заявок на изменение пар. ID преподавателя берётся из восстановленного в памяти профиля
|
||||
сессии.
|
||||
Страница переведена на React (`react/teacher/`, entrypoint `dist/react/teacher.js`) и использует
|
||||
общий слой `react/shared`: `useAuthorizedSession(['TEACHER'])`, `apiClient`, `AsyncState`,
|
||||
`AppErrorBoundary`, дата-математику `dates.js` и общий `ScheduleOverview` с ролью `teacher`.
|
||||
ID преподавателя берётся из восстановленного в памяти профиля сессии.
|
||||
|
||||
Кабинет объединяет недельную сетку занятий, семестровый календарь доступности и журнал
|
||||
заявок на изменение пар в трёх вкладках; активная вкладка и дата недели сохраняются
|
||||
в query-параметрах `teacherTab`/`teacherDate` через общий `url-state.js`.
|
||||
|
||||
Основные элементы:
|
||||
- общий блок «Сегодня» и карточка «Следующая пара»; отдельный запрос покрывает ближайшие
|
||||
14 дней, поэтому следующая пара находится и за границей текущей недели;
|
||||
- навигация по неделям: предыдущая, текущая, следующая;
|
||||
- выбор даты через `input[type="date"]`;
|
||||
- навигация по неделям: предыдущая, текущая, следующая; выбор даты через `input[type="date"]`;
|
||||
- запрос `GET /api/schedule?teacherId={userId}&startDate={YYYY-MM-DD}&endDate={YYYY-MM-DD}`;
|
||||
- матрица «слоты × дни недели» на десктопе и дневной список на мобильных (переключение
|
||||
через `matchMedia` с живым откликом на смену ширины);
|
||||
- отображение дисциплины, времени, типа занятия, лабораторных подгрупп, аудитории и всех групп правила;
|
||||
- вкладка «Мои пожелания» с выбором семестра, режимом отметки строгих, предпочтительных и
|
||||
нежелательных интервалов, полностью недоступных дат, пар подряд и расписания без окон;
|
||||
- цветовые статусы `PENDING`, `APPROVED`, `REJECTED`, `CANCELLED`; ожидающее пожелание можно
|
||||
отозвать кликом по отмеченной ячейке или кнопкой в списке дат;
|
||||
- кнопка «Заявка на изменение» в карточке фактического занятия и модальное окно переноса,
|
||||
- кнопка «Запросить изменение» в карточке занятия из правила и модальное окно переноса,
|
||||
смены аудитории или отмены. Недоступные кандидаты отфильтрованы после проверки backend;
|
||||
- вкладка журнала заявок с причиной, решением, ссылкой на применённый override и историей
|
||||
статусов; ожидающую заявку можно отозвать;
|
||||
- вкладка журнала заявок с причиной, решением и историей статусов; ожидающую заявку можно
|
||||
отозвать; счётчик ожидающих заявок выводится прямо на вкладке навигации;
|
||||
- форма собственной заявки на отсутствие через `POST /api/teacher-absences`;
|
||||
- список статусов заявок и отмена ещё не подтверждённой записи через
|
||||
`DELETE /api/teacher-absences/{id}`.
|
||||
@@ -436,6 +518,11 @@ if (!session || !AUTHORIZED_ROLES.includes(session.role)) {
|
||||
|
||||
### Студент (`/student/`)
|
||||
|
||||
Страница переведена на React (`react/student/`, entrypoint `dist/react/student.js`) и использует
|
||||
общий слой `react/shared`: `useAuthorizedSession(['STUDENT'])`, `apiClient`, `AsyncState`,
|
||||
`AppErrorBoundary` и React-версия поискового списка `AsyncCombobox`. Модель обзора «Сегодня /
|
||||
Следующая пара» переиспользует чистые функции `schedule-overview.js`.
|
||||
|
||||
В текущей модели студент не связан с конкретной группой, поэтому страница использует
|
||||
асинхронный поиск группы через `/api/groups/options`.
|
||||
|
||||
@@ -443,9 +530,10 @@ if (!session || !AUTHORIZED_ROLES.includes(session.role)) {
|
||||
- поисковый combobox группы с подсказками по специальности, профилю и курсу; выбор хранится
|
||||
в `localStorage.studentGroupId` и `studentGroup` query string;
|
||||
- общий блок «Сегодня» и карточка «Следующая пара», рассчитанные по ближайшим 14 дням;
|
||||
- недельная сетка по дням;
|
||||
- недельная сетка по дням с навигацией «Предыдущая/Следующая неделя», «Сегодня» и выбором даты;
|
||||
- запрос `GET /api/schedule?groupId={groupId}&startDate={YYYY-MM-DD}&endDate={YYYY-MM-DD}`;
|
||||
- отображение дисциплины, времени, преподавателя, аудитории, формата, типа занятия и лабораторных подгрупп.
|
||||
- отображение дисциплины, времени, преподавателя, аудитории, формата, типа занятия и лабораторных подгрупп;
|
||||
- URL-параметры `studentGroup` и `studentDate` сохраняются через общий `url-state.js`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user