diff --git a/frontend/admin/css/department.css b/frontend/admin/css/department.css
index 691860e..d39a250 100644
--- a/frontend/admin/css/department.css
+++ b/frontend/admin/css/department.css
@@ -1,235 +1,236 @@
-.wrap{
- max-width: 900px;
- margin: 0 auto;
- background: var(--bg-card);
- border: 1px solid var(--bg-card-border);
- border-radius: 12px;
- overflow: hidden;
- box-shadow: 0 6px 20px rgba(0,0,0,.06);
-}
-
-.header{
- padding: 14px 16px;
- border-bottom: 1px solid var(--bg-card-border);
- font-weight: 700;
- color: var(--text-primary);
-}
-
-details.table-item{
- border-top: 1px solid var(--bg-card-border);
-}
-details.table-item:first-of-type{ border-top:none; }
-
-summary{
- list-style: none;
- cursor: pointer;
- user-select: none;
- padding: 12px 16px;
- display: flex;
- align-items: center;
- gap: 10px;
-}
-summary::-webkit-details-marker{ display:none; }
-
-.chev{
- width: 28px;
- height: 28px;
- border: 1px solid var(--bg-card-border);
- border-radius: 10px;
- display: grid;
- place-items: center;
- flex: 0 0 auto;
-
- color: var(--text-secondary);
- background: var(--bg-input);
-
- transition: transform .18s ease, color .18s ease, border-color .18s ease, background .18s ease;
-}
-
-.chev-icon{
- width: 16px;
- height: 16px;
- display: block;
-}
-
-summary:hover .chev{
- background: var(--bg-hover);
- border-color: color-mix(in srgb, var(--accent) 22%, var(--bg-card-border));
- color: var(--text-primary);
-}
-
-details[open] .chev{
- transform: rotate(180deg);
- color: var(--accent);
- border-color: color-mix(in srgb, var(--accent) 35%, var(--bg-card-border));
- background: color-mix(in srgb, var(--accent) 10%, var(--bg-input));
-}
-
-.meta{ color: var(--text-secondary); font-size: 12px; }
-
-.content{ padding: 0 16px 16px 16px; }
-
-.wrap table{
- width: 100%;
- border-collapse: collapse;
- border: 1px solid var(--bg-card-border);
- border-radius: 10px;
- overflow: hidden;
- background: var(--bg-card);
-}
-
-.wrap thead th{
- text-align: left;
- font-size: 13px;
- color: var(--text-secondary);
- background: var(--bg-input);
- border-bottom: 1px solid var(--bg-card-border);
- padding: 10px 12px;
-}
-
-.wrap tbody td{
- padding: 10px 12px;
- border-bottom: 1px solid var(--bg-card-border);
- font-size: 14px;
- color: var(--text-primary);
-}
-
-.wrap tbody tr:hover{ background: var(--bg-hover); }
-
-.title-multiline{
- display: flex;
- flex-direction: column;
- gap: 2px;
- line-height: 1.2;
-}
-
-.title-multiline .title-main{
- font-weight: 700;
- color: var(--text-primary);
-}
-
-.title-multiline .title-sub{
- font-weight: 500;
- font-size: 12px;
- color: var(--text-secondary);
-}
-
-.title-multiline b{
- font-weight: 700;
- color: var(--text-primary);
-}
-
-/* summary = 3 колонки: [chev] [title] [meta] */
-details.table-item > summary{
- display: grid;
- grid-template-columns: 28px 1fr auto;
- gap: 12px;
- align-items: start; /* важно: всё прижимаем к верху */
- padding: 12px 16px;
-}
-
-/* чтобы текст нормально переносился и не растягивал мету */
-details.table-item > summary .title{
- min-width: 0; /* важно для grid, иначе может распирать */
-}
-
-/* "2 записи" всегда справа и сверху, аккуратно */
-details.table-item > summary .meta{
- justify-self: end;
- align-self: start;
- white-space: nowrap;
- padding-top: 4px; /* чуть опустить относительно первой строки */
- font-size: 12px;
- color: var(--text-secondary);
-}
-
-/* стрелка тоже сверху */
-details.table-item > summary .chev{
- align-self: start;
- margin-top: 2px;
-}
-
-.records-search{
- width: min(360px, 60vw);
- padding: 0.45rem 0.7rem;
- background: var(--bg-input);
- border: 1px solid var(--bg-card-border);
- border-radius: var(--radius-sm);
- color: var(--text-primary);
- font-size: 0.9rem;
- outline: none;
- transition: border-color .2s ease, box-shadow .2s ease, background .2s ease;
-}
-
-.records-search::placeholder{ color: var(--text-placeholder); }
-
-.records-search:focus{
- background: var(--bg-input-focus);
- border-color: var(--accent);
- box-shadow: 0 0 0 3px var(--accent-glow);
-}
-/* Таблица внутри раскрывающегося блока */
-details.table-item .content table{
- width: 100%;
- border-collapse: separate; /* нужно для красивых линий */
- border-spacing: 0;
- border: 1px solid var(--bg-card-border);
- border-radius: 12px;
- overflow: hidden;
- background: var(--bg-card);
-}
-
-/* Шапка */
-details.table-item .content thead th{
- position: sticky; /* опционально: шапка прилипает при скролле */
- top: 0;
- z-index: 1;
-
- background: var(--bg-input);
- color: var(--text-secondary);
- border-bottom: 1px solid var(--bg-card-border);
-}
-
-/* Ячейки: одинаковые отступы */
-details.table-item .content th,
-details.table-item .content td{
- padding: 0.75rem 0.85rem;
- vertical-align: top;
-}
-
-/* Вертикальные разделители между колонками */
-details.table-item .content th:not(:last-child),
-details.table-item .content td:not(:last-child){
- border-right: 1px solid var(--bg-card-border);
-}
-
-/* Горизонтальные разделители между строками */
-details.table-item .content tbody td{
- border-bottom: 1px solid var(--bg-card-border);
- color: var(--text-primary);
-}
-
-/* У последней строки нет нижней линии */
-details.table-item .content tbody tr:last-child td{
- border-bottom: none;
-}
-
-/* "Зебра" для читабельности */
-details.table-item .content tbody tr:nth-child(even){
- background: color-mix(in srgb, var(--bg-card) 70%, var(--bg-hover));
-}
-
-/* Ховер по строке */
-details.table-item .content tbody tr:hover{
- background: var(--bg-hover);
-}
-
-/* (Опционально) Чтобы длинный текст не ломал ширину */
-details.table-item .content td{
- word-break: break-word;
-}
-
-/* (Опционально) если таблица широкая — пусть скроллится горизонтально */
-details.table-item .content{
- overflow-x: auto;
-}
\ No newline at end of file
+.wrap{
+ max-width: 900px;
+ margin: 0 auto;
+ background: var(--bg-card);
+ border: 1px solid var(--bg-card-border);
+ border-radius: 12px;
+ overflow: hidden;
+ box-shadow: 0 6px 20px rgba(0,0,0,.06);
+}
+
+.header{
+ padding: 14px 16px;
+ border-bottom: 1px solid var(--bg-card-border);
+ font-weight: 700;
+ color: var(--text-primary);
+}
+
+details.table-item{
+ border-top: 1px solid var(--bg-card-border);
+}
+details.table-item:first-of-type{ border-top:none; }
+
+summary{
+ list-style: none;
+ cursor: pointer;
+ user-select: none;
+ padding: 12px 16px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+summary::-webkit-details-marker{ display:none; }
+
+.chev{
+ width: 28px;
+ height: 28px;
+ border: 1px solid var(--bg-card-border);
+ border-radius: 10px;
+ display: grid;
+ place-items: center;
+ flex: 0 0 auto;
+
+ color: var(--text-secondary);
+ background: var(--bg-input);
+
+ transition: transform .18s ease, color .18s ease, border-color .18s ease, background .18s ease;
+}
+
+.chev-icon{
+ width: 16px;
+ height: 16px;
+ display: block;
+}
+
+summary:hover .chev{
+ background: var(--bg-hover);
+ border-color: color-mix(in srgb, var(--accent) 22%, var(--bg-card-border));
+ color: var(--text-primary);
+}
+
+details[open] .chev{
+ transform: rotate(180deg);
+ color: var(--accent);
+ border-color: color-mix(in srgb, var(--accent) 35%, var(--bg-card-border));
+ background: color-mix(in srgb, var(--accent) 10%, var(--bg-input));
+}
+
+.meta{ color: var(--text-secondary); font-size: 12px; }
+
+.content{ padding: 0 16px 16px 16px; }
+
+.wrap table{
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid var(--bg-card-border);
+ border-radius: 10px;
+ overflow: hidden;
+ background: var(--bg-card);
+}
+
+.wrap thead th{
+ text-align: left;
+ font-size: 13px;
+ color: var(--text-secondary);
+ background: var(--bg-input);
+ border-bottom: 1px solid var(--bg-card-border);
+ padding: 10px 12px;
+}
+
+.wrap tbody td{
+ padding: 10px 12px;
+ border-bottom: 1px solid var(--bg-card-border);
+ font-size: 14px;
+ color: var(--text-primary);
+}
+
+.wrap tbody tr:hover{ background: var(--bg-hover); }
+
+.title-multiline{
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ line-height: 1.2;
+}
+
+.title-multiline .title-main{
+ font-weight: 700;
+ color: var(--text-primary);
+}
+
+.title-multiline .title-sub{
+ font-weight: 500;
+ font-size: 12px;
+ color: var(--text-secondary);
+}
+
+.title-multiline b{
+ font-weight: 700;
+ color: var(--text-primary);
+}
+
+/* summary = 3 колонки: [chev] [title] [meta] */
+details.table-item > summary{
+ display: grid;
+ grid-template-columns: 28px 1fr auto;
+ gap: 12px;
+ align-items: start; /* важно: всё прижимаем к верху */
+ padding: 12px 16px;
+}
+
+/* чтобы текст нормально переносился и не растягивал мету */
+details.table-item > summary .title{
+ min-width: 0; /* важно для grid, иначе может распирать */
+}
+
+/* "2 записи" всегда справа и сверху, аккуратно */
+details.table-item > summary .meta{
+ justify-self: end;
+ align-self: start;
+ white-space: nowrap;
+ padding-top: 4px; /* чуть опустить относительно первой строки */
+ font-size: 12px;
+ color: var(--text-secondary);
+}
+
+/* стрелка тоже сверху */
+details.table-item > summary .chev{
+ align-self: start;
+ margin-top: 2px;
+}
+
+.records-search{
+ width: min(360px, 60vw);
+ padding: 0.45rem 0.7rem;
+ background: var(--bg-input);
+ border: 1px solid var(--bg-card-border);
+ border-radius: var(--radius-sm);
+ color: var(--text-primary);
+ font-size: 0.9rem;
+ outline: none;
+ transition: border-color .2s ease, box-shadow .2s ease, background .2s ease;
+}
+
+.records-search::placeholder{ color: var(--text-placeholder); }
+
+.records-search:focus{
+ background: var(--bg-input-focus);
+ border-color: var(--accent);
+ box-shadow: 0 0 0 3px var(--accent-glow);
+}
+/* Таблица внутри раскрывающегося блока */
+details.table-item .content table{
+ width: 100%;
+ border-collapse: separate; /* нужно для красивых линий */
+ border-spacing: 0;
+ border: 1px solid var(--bg-card-border);
+ border-radius: 12px;
+ overflow: hidden;
+ background: var(--bg-card);
+}
+
+/* Шапка */
+details.table-item .content thead th{
+ position: sticky; /* опционально: шапка прилипает при скролле */
+ top: 0;
+ z-index: 1;
+
+ background: var(--bg-input);
+ color: var(--text-secondary);
+ border-bottom: 1px solid var(--bg-card-border);
+}
+
+/* Ячейки: одинаковые отступы */
+details.table-item .content th,
+details.table-item .content td{
+ padding: 0.75rem 0.85rem;
+ vertical-align: top;
+}
+
+/* Вертикальные разделители между колонками */
+details.table-item .content th:not(:last-child),
+details.table-item .content td:not(:last-child){
+ border-right: 1px solid var(--bg-card-border);
+}
+
+/* Горизонтальные разделители между строками */
+details.table-item .content tbody td{
+ border-bottom: 1px solid var(--bg-card-border);
+ color: var(--text-primary);
+}
+
+/* У последней строки нет нижней линии */
+details.table-item .content tbody tr:last-child td{
+ border-bottom: none;
+}
+
+/* "Зебра" для читабельности */
+details.table-item .content tbody tr:nth-child(even){
+ background: color-mix(in srgb, var(--bg-card) 70%, var(--bg-hover));
+}
+
+/* Ховер по строке */
+details.table-item .content tbody tr:hover{
+ background: var(--bg-hover);
+}
+
+/* (Опционально) Чтобы длинный текст не ломал ширину */
+details.table-item .content td{
+ word-break: break-word;
+}
+
+/* (Опционально) если таблица широкая — пусть скроллится горизонтально */
+details.table-item .content{
+ overflow-x: auto;
+}
+
\ No newline at end of file
diff --git a/frontend/admin/js/views/department.js b/frontend/admin/js/views/department.js
index b7c3711..9b0a1c0 100644
--- a/frontend/admin/js/views/department.js
+++ b/frontend/admin/js/views/department.js
@@ -1,4 +1,121 @@
import { api } from '../api.js';
-import { escapeHtml } from '../utils.js';
+import { escapeHtml, showAlert, hideAlert } from '../utils.js';
-export async function initDepartment() { }
\ No newline at end of file
+export async function initDepartment() {
+ const form = document.getElementById('department-schedule-form');
+ const departmentSelect = document.getElementById('filter-department');
+ const container = document.getElementById('schedule-blocks-container');
+
+ let departments = [];
+
+ // Загрузка кафедр
+ try {
+ departments = await api.get('/api/departments');
+ departmentSelect.innerHTML = '' +
+ departments.map(d => ``).join('');
+ } catch (e) {
+ departmentSelect.innerHTML = '';
+ }
+
+ form.addEventListener('submit', async (e) => {
+ e.preventDefault();
+ hideAlert('schedule-form-alert');
+
+ const departmentId = departmentSelect.value;
+ const period = document.getElementById('filter-period').value;
+ const semesterType = document.querySelector('input[name="semesterType"]:checked')?.value;
+
+ if (!departmentId || !period || !semesterType) {
+ showAlert('schedule-form-alert', 'Заполните все поля', 'error');
+ return;
+ }
+
+ const deptName = departmentSelect.options[departmentSelect.selectedIndex].text;
+
+ try {
+ const params = new URLSearchParams({
+ departmentId,
+ semesterType,
+ period
+ });
+
+ // Запрос на бэк
+ const data = await api.get(`/api/department/schedule?${params.toString()}`);
+
+ const semesterName = semesterType === 'spring' ? 'весенний' : (semesterType === 'autumn' ? 'осенний' : semesterType);
+ const periodName = period.replace('-', '/'); // Display 2024-2025 as 2024/2025
+
+ renderScheduleBlock(deptName, semesterName, periodName, data);
+
+ form.reset();
+
+ } catch (err) {
+ showAlert('schedule-form-alert', err.message || 'Ошибка загрузки данных', 'error');
+ }
+ });
+
+ function renderScheduleBlock(deptName, semester, period, schedule) {
+ const details = document.createElement('details');
+ details.className = 'table-item';
+ details.open = true; // Сразу открываем новый блок
+
+ details.innerHTML = `
+
+
+
+ Данные к составлению расписания
+ Кафедра: ${escapeHtml(deptName)}
+ Семестр: ${escapeHtml(semester)}
+ Уч. год: ${escapeHtml(period)}
+
+ ${schedule ? schedule.length : 0} записей
+
+
+
+
+
+
+ | Специальность |
+ Курс/семестр |
+ Группа |
+ Дисциплина |
+ Вид занятий |
+ Часов в неделю |
+ Аудитория |
+ Фамилия преподавателя |
+
+
+
+ ${renderRows(schedule)}
+
+
+
+ `;
+
+ container.prepend(details);
+ }
+
+ function renderRows(schedule) {
+ if (!schedule || schedule.length === 0) {
+ return '| Нет данных |
';
+ }
+
+ return schedule.map(r => `
+
+ | ${escapeHtml(r.specialty || '-')} |
+ ${escapeHtml(r.courseSemester || '-')} |
+ ${escapeHtml(r.groupName || '-')} |
+ ${escapeHtml(r.subjectName || '-')} |
+ ${escapeHtml(r.lessonType || '-')} |
+ ${escapeHtml(r.hours || '-')} |
+ ${escapeHtml(r.classroom || '-')} |
+ ${escapeHtml(r.teacherName || '-')} |
+
+ `).join('');
+ }
+}
\ No newline at end of file
diff --git a/frontend/admin/views/department.html b/frontend/admin/views/department.html
index 74dc1bf..c86cb66 100644
--- a/frontend/admin/views/department.html
+++ b/frontend/admin/views/department.html
@@ -1,193 +1,46 @@
-
-
Кафедра
+
+
Запрос расписания кафедры
+
-
-
-
-
-
-
-
-
- Данные к составлению расписания
- Кафедра: Информационная безопасность
- Факультет: ФиПИ
- Семестр: весенний
- Уч. год: 2024/2025
-
- 3 записи
-
-
-
-
-
-
- | Специальность |
- Курс и семестр |
- Группа |
- Дисциплина |
- Вид занятий |
- Часов в неделю |
- Деление на подгруппы |
- Фамилия преподавателя |
-
-
-
-
-
-
- | 09.02.07 |
- 2 курс, 4 семестр |
- ИС-21 |
- Базы данных |
- Лабораторная |
- 2 |
- Да |
- Иванов |
-
-
-
- | 09.02.07 |
- 2 курс, 4 семестр |
- ИС-22 |
- Операционные системы |
- Практика |
- 1 |
- Нет |
- Смирнов |
-
-
-
- | 09.02.07 |
- 1 курс, 2 семестр |
- ИС-12 |
- Алгоритмы |
- Лекция |
- 2 |
- Нет |
- Кузнецов |
-
-
-
-
-
-
-
-
-
-
- orders
- 1 запись
-
-
-
-
-
-
- | Специальность |
- Курс и семестр |
- Группа |
- Дисциплина |
- Вид занятий |
- Часов в неделю |
- Деление на подгруппы |
- Фамилия преподавателя |
-
-
-
-
-
- | 38.02.01 |
- 1 курс, 1 семестр |
- ЭК-11 |
- Экономика |
- Лекция |
- 1 |
- Нет |
- Петров |
-
-
-
-
-
-
-
-
-
-
- products
- 2 записи
-
-
-
-
-
-
- | Специальность |
- Курс и семестр |
- Группа |
- Дисциплина |
- Вид занятий |
- Часов в неделю |
- Деление на подгруппы |
- Фамилия преподавателя |
-
-
-
-
-
- | 15.02.08 |
- 3 курс, 6 семестр |
- МС-31 |
- Материаловедение |
- Практика |
- 3 |
- Да |
- Сидоров |
-
-
-
- | 15.02.08 |
- 3 курс, 6 семестр |
- МС-32 |
- Технология металлов |
- Лабораторная |
- 2 |
- Да |
- Орлов |
-
-
-
-
-
-
-
+
+
\ No newline at end of file