задачи 2 и 8
This commit is contained in:
114
docs/API.md
114
docs/API.md
@@ -623,6 +623,7 @@ GET /api/schedule?groupId=1&startDate=2026-04-27&endDate=2026-05-03
|
||||
|
||||
```json
|
||||
{
|
||||
"scheduleVersionId": 7,
|
||||
"subjectId": 1,
|
||||
"semesterId": 1,
|
||||
"lectureAcademicHours": 32,
|
||||
@@ -652,7 +653,7 @@ CRUD доступен по:
|
||||
|
||||
| Метод | URL | Назначение |
|
||||
|-------|-----|------------|
|
||||
| `GET` | `/api/admin/schedule-rules` | Список правил, фильтры `semesterId`, `groupId` |
|
||||
| `GET` | `/api/admin/schedule-rules` | Список правил, фильтры `semesterId`, `groupId`, `versionId` |
|
||||
| `GET` | `/api/admin/schedule-rules/{id}` | Одно правило |
|
||||
| `POST` | `/api/admin/schedule-rules` | Создать правило |
|
||||
| `PUT` | `/api/admin/schedule-rules/{id}` | Обновить правило |
|
||||
@@ -660,6 +661,11 @@ CRUD доступен по:
|
||||
|
||||
`timeSlotId` должен ссылаться на базовый слот (`scopeApplyMode = DEFAULT`). Субботняя и ручные сетки не выбираются в правиле напрямую.
|
||||
|
||||
Создание, изменение и архивирование правил разрешены только внутри версии со статусом
|
||||
`DRAFT`; `scheduleVersionId` обязателен в payload. Версия должна относиться к указанному
|
||||
семестру. Без `versionId` список возвращает только правила текущей опубликованной версии,
|
||||
а конструктор всегда передаёт ID выбранного черновика.
|
||||
|
||||
`subgroupIds` можно передавать только для лабораторного слота. Каждая подгруппа должна относиться к одной из групп правила. Если лабораторная проводится у нескольких групп одновременно, в одном слоте можно передать разные подгруппы этих групп, например `[10, 22]`. Для совместимости одиночный `subgroupId` тоже принимается, но новый формат — `subgroupIds`. Для лекций и практик оба поля должны быть пустыми, иначе API вернёт ошибку валидации. В одном слоте нельзя выбрать больше одной подгруппы одной и той же группы.
|
||||
|
||||
Часы и недели начала задаются отдельно для лекций, лабораторных и практик. Каждый лимит
|
||||
@@ -841,6 +847,112 @@ API возвращает `409 Conflict`; соседние интервалы и
|
||||
}
|
||||
```
|
||||
|
||||
### Версии и публикация расписания
|
||||
|
||||
| Метод | URL | Назначение |
|
||||
|-------|-----|------------|
|
||||
| `GET` | `/api/edu-office/schedule/versions?semesterId=` | Версии семестра с авторами, датами и количеством правил |
|
||||
| `GET` | `/api/edu-office/schedule/versions/{id}` | Одна версия |
|
||||
| `POST` | `/api/edu-office/schedule/versions` | Создать пустой черновик или копию выбранной версии |
|
||||
| `GET` | `/api/edu-office/schedule/versions/{id}/validate` | Полная проверка правил черновика |
|
||||
| `GET` | `/api/edu-office/schedule/versions/{id}/diff?baseVersionId=` | Сравнение правил и сформированных занятий |
|
||||
| `POST` | `/api/edu-office/schedule/versions/{id}/publish` | Атомарно опубликовать проверенный черновик |
|
||||
| `POST` | `/api/edu-office/schedule/versions/{id}/restore` | Восстановить ранее опубликованную архивную версию |
|
||||
| `GET` | `/api/edu-office/schedule/versions/history?semesterId=` | Хронология создания, публикации, архивации и восстановления |
|
||||
|
||||
Доступ имеют только `ADMIN` и `EDUCATION_OFFICE`. Для семестра допускается ровно одна
|
||||
версия со статусом `PUBLISHED`; остальные имеют статус `DRAFT` или `ARCHIVED`. Создание
|
||||
копии переносит правила, группы, слоты и подгруппы, сохраняя `versionGroupId` для diff.
|
||||
|
||||
```json
|
||||
{
|
||||
"semesterId": 3,
|
||||
"name": "Расписание после распределения аудиторий",
|
||||
"basedOnVersionId": 11
|
||||
}
|
||||
```
|
||||
|
||||
Публикация и восстановление принимают обязательную причину:
|
||||
|
||||
```json
|
||||
{ "reason": "Согласовано учебным отделом 11.08.2026" }
|
||||
```
|
||||
|
||||
Перед публикацией backend блокирует версию, повторно проверяет весь набор активных правил,
|
||||
архивирует текущую публикацию и переводит черновик в `PUBLISHED` одной транзакцией. При
|
||||
ошибке ни один статус не меняется. Обычные endpoints просмотра и генерации выбирают только
|
||||
опубликованную версию; overrides архивных версий не попадают в актуальное расписание и
|
||||
операционный реестр.
|
||||
|
||||
### Анализ качества расписания
|
||||
|
||||
| Метод | URL | Назначение |
|
||||
|-------|-----|------------|
|
||||
| `GET` | `/api/edu-office/schedule/quality?semesterId=&versionId=` | Итоговая оценка, метрики и объяснимый список проблем выбранной версии |
|
||||
| `GET` | `/api/edu-office/schedule/quality/recommendations?semesterId=&versionId=&scheduleRuleSlotId=&lessonDate=` | Проверенные локальные варианты улучшения опубликованного занятия |
|
||||
|
||||
Доступ имеют только `ADMIN` и `EDUCATION_OFFICE`. `versionId` необязателен: без него
|
||||
анализируется текущая публикация. Для опубликованной версии анализатор рассматривает
|
||||
фактическое расписание всего семестра, включая уже применённые `schedule_overrides`, и учитывает окна
|
||||
групп и преподавателей, перегруженные дни, вместимость и избыточный размер аудитории,
|
||||
согласованные пожелания и недоступность преподавателей, а также равномерность нагрузки.
|
||||
Длинный семестр загружается внутренними интервалами не более 120 дней, поэтому публичный
|
||||
запрос не требует диапазона дат.
|
||||
|
||||
Черновик и архивная версия генерируются напрямую по собственным правилам, без подмешивания
|
||||
override текущей публикации. Для них доступны оценка, метрики и проблемы, но не локальные
|
||||
рекомендации: исправления черновика выполняются в конструкторе до публикации, архив остаётся
|
||||
только для чтения.
|
||||
|
||||
```json
|
||||
{
|
||||
"semesterId": 3,
|
||||
"semesterLabel": "2026/2027 · осенний семестр",
|
||||
"scheduleVersionId": 12,
|
||||
"scheduleVersionNumber": 2,
|
||||
"scheduleVersionName": "Расписание после распределения аудиторий",
|
||||
"scheduleVersionStatus": "DRAFT",
|
||||
"score": 84,
|
||||
"rawPenalty": 17,
|
||||
"lessonCount": 36,
|
||||
"totalProblemCount": 5,
|
||||
"problemsTruncated": false,
|
||||
"metrics": [
|
||||
{
|
||||
"code": "GROUP_GAPS",
|
||||
"label": "Окна у групп",
|
||||
"value": 3,
|
||||
"unit": "окон",
|
||||
"penalty": 6,
|
||||
"explanation": "Промежутки между занятиями одной группы"
|
||||
}
|
||||
],
|
||||
"problems": [
|
||||
{
|
||||
"id": "GROUP_GAP:2026-09-14:31:18",
|
||||
"type": "GROUP_GAP",
|
||||
"severity": "MEDIUM",
|
||||
"title": "Окно в расписании группы",
|
||||
"penalty": 2,
|
||||
"scheduleRuleSlotId": 31,
|
||||
"lessonDate": "2026-09-14",
|
||||
"optimizable": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`score` находится в диапазоне от 0 до 100 и нормализует сумму объяснимых штрафов
|
||||
относительно числа занятий. Поле `totalProblemCount` содержит полный размер результата,
|
||||
а массив `problems` ограничен 300 элементами; `problemsTruncated` сообщает об усечении.
|
||||
|
||||
Рекомендации подбирают другой эффективный временной слот того же учебного дня либо
|
||||
подходящую активную аудиторию. Занятия, уже закреплённые ручным override, исключаются.
|
||||
Каждый кандидат до выдачи проходит `ScheduleOverrideService`, содержит готовый payload
|
||||
`override`, ожидаемые `scoreDelta`, `penaltyDelta`, улучшения и компромиссы. API ничего не
|
||||
изменяет автоматически: после подтверждения пользователь применяет payload обычным
|
||||
`POST /api/edu-office/schedule/overrides`.
|
||||
|
||||
### Отсутствия преподавателей и мастер замены
|
||||
|
||||
| Метод | URL | Назначение |
|
||||
|
||||
Reference in New Issue
Block a user