Merge branch 'dynamic_schedule' of https://gitea.zuev.company/Zuev/magistr into dynamic_schedule

This commit is contained in:
dipatrik10
2026-05-25 13:40:30 +03:00
93 changed files with 5291 additions and 699 deletions

View File

@@ -29,7 +29,7 @@ frontend/
│ │ ├── layout.css # Раскладка (sidebar, topbar, content)
│ │ ├── components.css # Кнопки, таблицы, карточки, формы
│ │ ├── modals.css # Модальные окна
│ │ ├── auditorium-workload.css # Таблицы загруженности аудиторий
│ │ ├── auditorium-workload.css # Таблицы расписаний и загруженности
│ │ └── departments-data.css # Стили создания кафедры/специальности
│ ├── js/
│ │ ├── main.js # Инициализация, маршрутизация, навигация
@@ -44,9 +44,11 @@ frontend/
│ │ ├── equipments.js # Управление оборудованием
│ │ ├── edu-forms.js # Формы обучения
│ │ ├── profiles.js # Профили обучения специальностей
│ │ ├── department-workspace.js # Кабинет кафедры в общей панели
│ │ ├── schedule-view.js # Read-only просмотр расписаний в матрицах
│ │ ├── schedule.js # Конструктор правил расписания
│ │ ├── academic-calendar.js # Календарные учебные графики
│ │ ├── auditorium-workload.js # Загруженность аудиторий
│ │ ├── auditorium-workload.js # Загруженность аудиторий, преподавателей и кафедр
│ │ ├── database.js # Управление тенантами
│ │ └── departments-data.js # Создание кафедры/специальности
│ ├── views/ # HTML-шаблоны представлений
@@ -57,6 +59,8 @@ frontend/
│ │ ├── equipments.html
│ │ ├── edu-forms.html
│ │ ├── profiles.html
│ │ ├── department-workspace.html
│ │ ├── schedule-view.html
│ │ ├── schedule.html
│ │ ├── academic-calendar.html
│ │ ├── auditorium-workload.html
@@ -78,6 +82,10 @@ frontend/
├── teacher/ # 👩‍🏫 Интерфейс преподавателя
│ └── index.html # Недельный просмотр динамического расписания преподавателя
├── department/ # 🏛 Кабинет кафедры
│ └── index.html # Redirect в `/admin/#department-workspace`
├── edu-office/ # 🗓 Кабинет учебного отдела
│ └── index.html # Redirect в `/admin/#schedule-view`
└── student/ # 🎓 Интерфейс студента
└── index.html # Недельный просмотр динамического расписания группы
@@ -104,6 +112,19 @@ frontend/
3. Подключает соответствующий JS-модуль из `js/views/{tab}.js`
4. Обновляет заголовок страницы (`#page-title`)
`main.js` также фильтрует вкладки по роли:
| Роль | Доступные вкладки |
|------|-------------------|
| `ADMIN` | Все вкладки |
| `EDUCATION_OFFICE` | Просмотр расписаний, конструктор расписания, календарный график, загруженность, аудитории, оборудование |
| `DEPARTMENT` | Кабинет кафедры, просмотр расписаний |
| `SCHEDULE_VIEWER` | Только просмотр расписаний |
Пути `/department/` и `/edu-office/` оставлены как входные redirect-страницы в общую панель. Отдельные кабинеты не дублируют UI админ-панели.
Пункты меню, недоступные роли, не отображаются в sidebar: `main.js` выставляет `hidden`, а `layout.css` явно скрывает такие элементы, чтобы базовый `display: flex` у `.nav-item` не возвращал их на экран.
### Разделы админ-панели
| Tab | Описание | API |
@@ -115,30 +136,35 @@ frontend/
| `equipments` | Оборудование | `/api/equipments` |
| `classrooms` | Аудитории | `/api/classrooms` |
| `subjects` | Дисциплины | `/api/subjects` |
| `department-workspace` | Кабинет кафедры: дисциплины, импорт, комментарии, преподаватели и нагрузка | `/api/department/*`, `/api/workload/teachers` |
| `schedule-view` | Read-only просмотр расписаний: по одной выбранной дате строится двухнедельный диапазон, найденные расписания выбираются в переключателе, а на экране отображается одна активная совмещённая таблица чётной/нечётной недели | `/api/schedule/search` |
| `schedule` | Конструктор правил динамического расписания | `/api/admin/schedule-rules`, `/api/admin/time-slots`, `/api/admin/calendar/years`, `/api/lesson-types`, `/api/subgroups` |
| `academic-calendar` | Учебные годы, семестры, создание календарных графиков и Excel-подобный редактор дневной сетки | `/api/admin/calendar`, `/api/admin/academic-calendars`, `/api/admin/calendar/activity-types`, `/api/education-forms` |
| `auditorium-workload` | Динамическая загруженность аудиторий: сводная матрица по дате или совмещённая таблица выбранной аудитории по чётной/нечётной неделе | `/api/classrooms`, `/api/admin/time-slots`, `/api/equipments`, `/api/groups`, `/api/schedule`, `/api/admin/calendar/years` |
| `auditorium-workload` | Динамическая загруженность аудиторий, преподавателей и кафедр: сводная матрица по дате или совмещённая таблица выбранной сущности по чётной/нечётной неделе | `/api/classrooms`, `/api/users/teachers`, `/api/departments`, `/api/admin/time-slots`, `/api/equipments`, `/api/groups`, `/api/schedule`, `/api/admin/calendar/years` |
| `database` | Тенанты | `/api/database` |
| `departments-data` | Создание, редактирование и удаление кафедр/специальностей | `/api/departments`, `/api/specialties` |
### Особенности админских вкладок
- Вкладка `groups` загружает кафедры, специальности, профили, учебные годы и календарные графики. Группа создаётся через `/api/groups` с `specialtyId` и `specialtyProfileId`, блок подгрупп использует `/api/subgroups` и `/api/groups/{id}/subgroups`, а блок назначений использует `/api/groups/{id}/calendar-assignments`.
- Вкладка `auditorium-workload` показывает матрицу загруженности по выбранной дате: строки — реальные аудитории из `/api/classrooms`, столбцы — эффективные временные слоты выбранного дня из `/api/admin/time-slots/effective`, занятость собирается из динамического расписания `/api/schedule` по группам. Фильтры корпуса, вместимости и оборудования заполняются из API. В поле «Отображение» можно выбрать конкретную аудиторию; тогда сводная матрица заменяется одной таблицей по дням недели и времени для двухнедельного периода от выбранной даты. Таблица выбранной аудитории растягивается до нижней части экрана. Ячейка делится вертикально только если верхняя и нижняя недели отличаются: нечётная неделя отображается сверху, чётная — снизу. Если состояние или занятие одинаковое, ячейка остаётся цельной. Чётность берётся из расписания, а для свободных дней рассчитывается по семестрам из `/api/admin/calendar/years`.
- Вкладка `schedule-view` показывает найденные занятия в режиме одной активной таблицы. Пользователь выбирает, что смотреть: группу, преподавателя, аудиторию или кафедру; frontend запрашивает двухнедельный диапазон от понедельника выбранной даты и собирает найденные расписания в переключатель результатов. На странице не выводится стек таблиц: виден один выбранный результат, а остальные доступны через чипы и кнопки предыдущего/следующего расписания. Для режима кафедры и роли `DEPARTMENT` расписание ограничивается кафедрой пользователя; преподавательские и студенческие отдельные страницы пока остаются самостоятельными. Таблица строится как строки пар и столбцы дней недели. Нечётная неделя отображается в верхней половине ячейки, чётная — в нижней, а одинаковые занятия в обе недели схлопываются в цельную ячейку. На мобильной ширине вместо широкой недельной матрицы показывается один день активного расписания с переключателем дней.
- Вкладка `auditorium-workload` стала общей вкладкой `Загруженность`: в поле «Что смотреть» выбираются аудитории, преподаватели или кафедры. Сводная матрица по выбранной дате использует одинаковую структуру: строки — выбранный тип сущности, столбцы — эффективные временные слоты дня из `/api/admin/time-slots/effective`, занятость собирается из динамического расписания `/api/schedule` по группам. Кафедральная матрица группирует занятия по кафедре преподавателя. Для аудиторий доступны фильтры корпуса, вместимости и оборудования. В поле «Отображение» можно выбрать конкретную аудиторию, преподавателя или кафедру; тогда сводная матрица заменяется одной таблицей по дням недели и времени для двухнедельного периода от выбранной даты. Таблица выбранной сущности растягивается до нижней части экрана. Ячейка делится вертикально только если верхняя и нижняя недели отличаются: нечётная неделя отображается сверху, чётная — снизу. Если состояние или занятие одинаковое, ячейка остаётся цельной. Чётность берётся из расписания, а для свободных дней рассчитывается по семестрам из `/api/admin/calendar/years`.
- Вкладка `profiles` выделена под профили обучения: администратор выбирает специальность, создаёт профиль, редактирует описание и удаляет неиспользуемые профили.
- Вкладка `schedule` не обращается к старым `lessons` API. Создание и редактирование расписания выполняется через правила `/api/admin/schedule-rules`, где каждое правило содержит группы, отдельные часы и недели начала для лекций, лабораторных и практик, а также набор базовых слотов. Группы выбираются через выпадающий мультиселект. Поле подгруппы появляется только при выборе лабораторной работы; для лекций и практик оно не отображается. Если в правиле выбрана одна группа, селект подгруппы содержит пункт `Вся группа`; если выбрано несколько групп, лабораторный слот показывает мультиселект подгрупп, чтобы выбрать разные подгруппы разных групп. Из календарной системы здесь используется список семестров для выбора периода действия правила.
- Вкладка `academic-calendar` полностью отделяет календарную систему от расписания занятий: администратор создаёт учебные годы и семестры, заводит календарные графики, выбирает форму обучения из общего справочника `/api/education-forms`, заполняет дневную сетку по курсам и кодам активностей, назначает ручную временную сетку на конкретную дату, а сохранение сетки идёт через `/api/admin/academic-calendars/{id}/grid`.
- Редактор годового графика во вкладке `academic-calendar` показывает компактную табличную сетку: курсы раскрываются отдельными секциями со стрелкой, семестры внутри курса идут вертикально друг под другом, столбцы подписаны номерами недель учебного года, строки — днями недели, а ячейки содержат буквенный код активности. Подробная расшифровка и изменение кода открываются в компактном модальном окне по клику на ячейку; выбранная ячейка и её код дополнительно подсвечиваются в общей сводке.
- Вкладка `departments-data` использует модальные формы редактирования и маршруты `PUT/DELETE /api/departments/{id}` и `PUT/DELETE /api/specialties/{id}`.
- Вкладка `classrooms` теперь показывает архивные аудитории через `includeArchived=true`. Кнопка удаления заменена на архивирование: аудитория выводится из эксплуатации, но остаётся в историческом расписании. Для архивных аудиторий доступно восстановление.
- Вкладка `users` поддерживает роли `EDUCATION_OFFICE`, `DEPARTMENT` и `SCHEDULE_VIEWER`; удаление пользователя работает как архивирование.
### Страница настроек (`/admin/settings/`)
Настройки — это **отдельный SPA** со своей боковой панелью и вкладками, не связанными с основной админ-панелью.
- Доступ: через dropdown «Настройки» в footer боковой панели админки
- Доступ: через dropdown «Настройки» в footer боковой панели админки для `ADMIN` и `EDUCATION_OFFICE`
- Кнопка «Назад в панель» для возврата в `/admin/`
- Текущие вкладки:
- **Общие настройки** — заглушка (в разработке)
- **Общие настройки** — заглушка (только `ADMIN`)
- **Временные слоты** — выбор сетки через выпадающий список, CRUD слотов выбранной сетки, добавление ручных сеток через модальное окно и удаление выбранной ручной сетки. Базовая сетка применяется по умолчанию, субботняя — автоматически по субботам; ручное применение выполняется в сетке календарного графика.
---
@@ -191,6 +217,9 @@ export const api = {
- `userId` — ID пользователя для личного расписания преподавателя
4. Перенаправляет на соответствующий интерфейс:
- `ADMIN``/admin/`
- `EDUCATION_OFFICE``/admin/#schedule-view`
- `DEPARTMENT``/admin/#department-workspace`
- `SCHEDULE_VIEWER``/admin/#schedule-view`
- `TEACHER``/teacher/`
- `STUDENT``/student/`
@@ -213,6 +242,30 @@ export function isAuthenticatedAsAdmin() {
## Кабинеты расписания
### Учебный отдел (`/admin/#schedule-view`)
Учебный отдел работает в общей админ-панели с ограниченным набором вкладок:
- расширенный поиск `/api/schedule/search` по дате в периоде, преподавателю, аудитории и кафедре;
- конструктор расписания через `/api/admin/schedule-rules`;
- создание точечного изменения пары через `/api/edu-office/schedule/overrides` на уровне API;
- матричный просмотр загруженности аудиторий, преподавателей и кафедр через общую вкладку `Загруженность`;
- аудитории, оборудование, календарный график и загруженность.
### Кафедра (`/admin/#department-workspace`)
Кабинет кафедры встроен в общую панель и работает в контексте `departmentId` текущего пользователя:
- список дисциплин кафедры через `/api/department/subjects`;
- загрузка дисциплин из текстового списка в формате `код; название`;
- комментарии к дисциплинам;
- просмотр расписания кафедры через вкладку `schedule-view`;
- загруженность преподавателей кафедры.
### Просмотр расписаний (`/admin/#schedule-view`)
Роль `SCHEDULE_VIEWER` видит только read-only вкладку просмотра расписаний. Доступны фильтры по дате в периоде, группе, преподавателю, аудитории, кафедре, дисциплине, типу занятия, чётности и разрезу таблиц. Найденные занятия отображаются отдельными совмещёнными таблицами чётной/нечётной недели с парами по строкам и днями недели по столбцам.
### Преподаватель (`/teacher/`)
Страница показывает недельную сетку занятий преподавателя. ID преподавателя берётся из `localStorage.userId`, который сохраняется после `POST /api/auth/login`.