diff --git a/frontend/admin/css/department.css b/frontend/admin/css/department.css
index 93c8913..88b83c9 100644
--- a/frontend/admin/css/department.css
+++ b/frontend/admin/css/department.css
@@ -312,4 +312,33 @@ details.table-item .content td{
details.table-item .content{
overflow-x: auto;
}
+
+/* ===== Контейнер занятий преподавателя в модалках ===== */
+.cs-modal-table .lessons-container {
+ max-height: 50vh;
+ overflow-y: auto;
+ padding-right: 0.5rem;
+ scrollbar-width: thin;
+ scrollbar-color: rgba(99, 102, 241, 0.55) rgba(255, 255, 255, 0.06);
+}
+
+.cs-modal-table .lessons-container::-webkit-scrollbar {
+ width: 10px;
+}
+
+.cs-modal-table .lessons-container::-webkit-scrollbar-track {
+ background: rgba(255, 255, 255, 0.06);
+ border-radius: 10px;
+}
+
+.cs-modal-table .lessons-container::-webkit-scrollbar-thumb {
+ background: rgba(99, 102, 241, 0.55);
+ border-radius: 10px;
+ border: 2px solid rgba(0, 0, 0, 0);
+ background-clip: padding-box;
+}
+
+.cs-modal-table .lessons-container::-webkit-scrollbar-thumb:hover {
+ background: rgba(99, 102, 241, 0.75);
+}
\ No newline at end of file
diff --git a/frontend/admin/js/views/schedule.js b/frontend/admin/js/views/schedule.js
index 03c2950..57ca394 100755
--- a/frontend/admin/js/views/schedule.js
+++ b/frontend/admin/js/views/schedule.js
@@ -1,5 +1,5 @@
import { api } from '../api.js';
-import { escapeHtml } from '../utils.js';
+import { escapeHtml, showAlert, hideAlert } from '../utils.js';
export async function initSchedule() {
const tbody = document.getElementById('schedule-tbody');
@@ -20,7 +20,6 @@ export async function initSchedule() {
// ===================== Фильтрация =====================
- // Извлечение отображаемого значения поля для фильтрации
function getDisplayValue(lesson, key) {
switch (key) {
case 'teacher':
@@ -38,20 +37,17 @@ export async function initSchedule() {
}
}
- // Собрать уникальные значения из данных
function getUniqueValues(key) {
const vals = new Set();
lessonsData.forEach(lesson => {
vals.add(getDisplayValue(lesson, key));
});
- // Для дней — сортируем по порядку
if (key === 'day') {
return [...vals].sort((a, b) => (dayOrder[a.toLowerCase()] ?? 99) - (dayOrder[b.toLowerCase()] ?? 99));
}
return [...vals].sort((a, b) => a.localeCompare(b, 'ru'));
}
- // Применить все фильтры
function applyFilters(lessons) {
return lessons.filter(lesson => {
for (const key of Object.keys(activeFilters)) {
@@ -79,7 +75,6 @@ export async function initSchedule() {
function onDocumentClick(e) {
if (currentPopup && !currentPopup.contains(e.target)) {
- // Проверяем, не кликнули ли по иконке фильтра
if (!e.target.closest('.filter-icon')) {
closePopup();
}
@@ -87,7 +82,6 @@ export async function initSchedule() {
}
function openFilterPopup(th, filterKey) {
- // Если уже открыт этот же — закрыть
if (currentPopup && currentPopup.dataset.filterKey === filterKey) {
closePopup();
return;
@@ -97,19 +91,16 @@ export async function initSchedule() {
const uniqueValues = getUniqueValues(filterKey);
const currentFilter = activeFilters[filterKey];
- // Создаём попап
const popup = document.createElement('div');
popup.className = 'filter-popup';
popup.dataset.filterKey = filterKey;
- // Поисковое поле
const searchInput = document.createElement('input');
searchInput.type = 'text';
searchInput.className = 'filter-search';
searchInput.placeholder = 'Поиск...';
popup.appendChild(searchInput);
- // Кнопки «Выбрать все» / «Сбросить»
const btnRow = document.createElement('div');
btnRow.className = 'filter-btn-row';
@@ -133,7 +124,6 @@ export async function initSchedule() {
btnRow.appendChild(btnNone);
popup.appendChild(btnRow);
- // Список чекбоксов
const listWrap = document.createElement('div');
listWrap.className = 'filter-list';
@@ -146,7 +136,6 @@ export async function initSchedule() {
const cb = document.createElement('input');
cb.type = 'checkbox';
cb.value = val;
- // Если фильтр активен — отмечаем только выбранные; если нет — все отмечены
cb.checked = currentFilter ? currentFilter.has(val) : true;
const span = document.createElement('span');
@@ -160,7 +149,6 @@ export async function initSchedule() {
popup.appendChild(listWrap);
- // Кнопка «Применить»
const btnApply = document.createElement('button');
btnApply.className = 'filter-btn-apply';
btnApply.textContent = 'Применить';
@@ -171,7 +159,6 @@ export async function initSchedule() {
if (cb.checked) selected.add(cb.value);
});
- // Если все выбраны — снимаем фильтр
if (selected.size === uniqueValues.length) {
delete activeFilters[filterKey];
th.classList.remove('filter-active');
@@ -185,7 +172,6 @@ export async function initSchedule() {
});
popup.appendChild(btnApply);
- // Поиск по чекбоксам
searchInput.addEventListener('input', () => {
const query = searchInput.value.toLowerCase();
listWrap.querySelectorAll('.filter-item').forEach(item => {
@@ -194,28 +180,22 @@ export async function initSchedule() {
});
});
- // Предотвращаем всплытие кликов внутри попапа (чтобы не срабатывала сортировка th)
popup.addEventListener('click', (e) => e.stopPropagation());
searchInput.addEventListener('click', (e) => e.stopPropagation());
- // Позиционируем попап под th
th.style.position = 'relative';
th.appendChild(popup);
currentPopup = popup;
- // Фокус на поиск
setTimeout(() => searchInput.focus(), 50);
- // Закрытие по клику вне
setTimeout(() => {
document.addEventListener('click', onDocumentClick, true);
}, 10);
}
- // Обработчики кликов по заголовкам с фильтрами (клик по всей ячейке)
table.querySelectorAll('thead th.filterable').forEach(th => {
th.addEventListener('click', (e) => {
- // Не открываем попап при клике внутри самого попапа
if (e.target.closest('.filter-popup')) return;
const filterKey = th.dataset.filterKey;
openFilterPopup(th, filterKey);
@@ -249,7 +229,6 @@ export async function initSchedule() {
case 'week':
return (lesson.week || '').toLowerCase();
case 'time': {
- // Составной ключ: день + время для правильной сортировки
const d = (lesson.day || '').toLowerCase();
const dayNum = dayOrder[d] ?? 99;
const t = lesson.time || '99:99';
@@ -287,10 +266,8 @@ export async function initSchedule() {
});
}
- // Навешиваем обработчики клика на заголовки (сортировка)
table.querySelectorAll('thead th.sortable').forEach(th => {
th.addEventListener('click', (e) => {
- // Не сортируем, если кликнули по иконке фильтра или внутри попапа
if (e.target.closest('.filter-icon') || e.target.closest('.filter-popup')) return;
const key = th.dataset.sortKey;
@@ -310,7 +287,7 @@ export async function initSchedule() {
});
});
- // ===================== Загрузка и рендер =====================
+ // ===================== Загрузка и рендер таблицы =====================
async function loadSchedule() {
try {
@@ -318,21 +295,20 @@ export async function initSchedule() {
lessonsData = lessons;
renderSchedule(lessons);
} catch (e) {
- tbody.innerHTML = `
Ошибка загрузки: ${escapeHtml(e.message)} `;
+ tbody.innerHTML = `Ошибка загрузки: ${escapeHtml(e.message)} `;
}
}
function renderSchedule(lessons) {
if (!lessons || !lessons.length) {
- tbody.innerHTML = 'Нет занятий ';
+ tbody.innerHTML = 'Нет занятий ';
return;
}
- // Сначала фильтруем, потом сортируем
const filtered = applyFilters(lessons);
if (!filtered.length) {
- tbody.innerHTML = 'Нет занятий по выбранным фильтрам ';
+ tbody.innerHTML = 'Нет занятий по выбранным фильтрам ';
return;
}
@@ -366,5 +342,343 @@ export async function initSchedule() {
}).join('');
}
- await loadSchedule();
+ // ===================== Модалки добавления занятия =====================
+
+ const overlay = document.getElementById('sch-overlay');
+ const modalForm = document.getElementById('sch-modal-form');
+ const modalLessons = document.getElementById('sch-modal-lessons');
+ const btnAddLesson = document.getElementById('sch-btn-add-lesson');
+ const btnClose = document.getElementById('sch-modal-close');
+ const addForm = document.getElementById('sch-add-lesson-form');
+
+ const schTeacherSelect = document.getElementById('sch-teacher');
+ const schGroupSelect = document.getElementById('sch-group');
+ const schDisciplineSelect = document.getElementById('sch-discipline');
+ const schClassroomSelect = document.getElementById('sch-classroom');
+ const schDaySelect = document.getElementById('sch-day');
+ const schTimeSelect = document.getElementById('sch-time');
+ const schTypeSelect = document.getElementById('sch-type');
+ const schWeekUpper = document.getElementById('sch-week-upper');
+ const schWeekLower = document.getElementById('sch-week-lower');
+ const schFormatOffline = document.getElementById('sch-format-offline');
+
+ const schTeacherName = document.getElementById('sch-teacher-name');
+ const schLessonsContainer = document.getElementById('sch-lessons-container');
+
+ let groups = [];
+ let subjects = [];
+ let classrooms = [];
+ let teachers = [];
+
+ const weekdaysTimes = [
+ "8:00-9:30", "9:40-11:10", "11:40-13:10",
+ "13:20-14:50", "15:00-16:30", "16:50-18:20", "18:30-19:00"
+ ];
+ const saturdayTimes = [
+ "8:20-9:50", "10:00-11:30", "11:40-13:10", "13:20-14:50"
+ ];
+
+ // ===== Загрузка справочников =====
+ async function loadGroups() {
+ try {
+ groups = await api.get('/api/groups');
+ schGroupSelect.innerHTML = 'Выберите группу ' +
+ groups.map(g => {
+ let text = escapeHtml(g.name);
+ if (g.groupSize) text += ` (числ: ${g.groupSize} чел.)`;
+ return `${text} `;
+ }).join('');
+ } catch (e) { console.error('Ошибка загрузки групп:', e); }
+ }
+
+ async function loadSubjects() {
+ try {
+ subjects = await api.get('/api/subjects');
+ schDisciplineSelect.innerHTML = 'Выберите дисциплину ' +
+ subjects.map(s => `${escapeHtml(s.name)} `).join('');
+ } catch (e) { console.error('Ошибка загрузки дисциплин:', e); }
+ }
+
+ async function loadClassrooms() {
+ try {
+ classrooms = await api.get('/api/classrooms');
+ renderClassroomOptions();
+ } catch (e) { console.error('Ошибка загрузки аудиторий:', e); }
+ }
+
+ async function loadTeachers() {
+ try {
+ teachers = await api.get('/api/users/teachers');
+ schTeacherSelect.innerHTML = 'Выберите преподавателя ' +
+ teachers.map(t => `${escapeHtml(t.fullName || t.username)} `).join('');
+ } catch (e) { console.error('Ошибка загрузки преподавателей:', e); }
+ }
+
+ function renderClassroomOptions() {
+ if (!classrooms || classrooms.length === 0) {
+ schClassroomSelect.innerHTML = 'Нет доступных аудиторий ';
+ return;
+ }
+ const selectedGroupId = schGroupSelect.value;
+ const selectedGroup = groups?.find(g => g.id == selectedGroupId);
+ const groupSize = selectedGroup?.groupSize || 0;
+
+ schClassroomSelect.innerHTML = 'Выберите аудиторию ' +
+ classrooms.map(c => {
+ let text = escapeHtml(c.name);
+ if (c.capacity) text += ` (вместимость: ${c.capacity} чел.)`;
+ if (c.isAvailable === false) {
+ text += ` ❌ Занята`;
+ } else if (selectedGroupId && groupSize > 0 && c.capacity && groupSize > c.capacity) {
+ text += ` ⚠️ Недостаточно места`;
+ }
+ return `${text} `;
+ }).join('');
+ }
+
+ schGroupSelect.addEventListener('change', () => renderClassroomOptions());
+
+ function updateTimeOptions(dayValue) {
+ let times = [];
+ if (dayValue === "Суббота") {
+ times = saturdayTimes;
+ } else if (dayValue && dayValue !== '') {
+ times = weekdaysTimes;
+ } else {
+ schTimeSelect.innerHTML = 'Сначала выберите день ';
+ schTimeSelect.disabled = true;
+ return;
+ }
+ schTimeSelect.innerHTML = 'Выберите время ' +
+ times.map(t => `${t} `).join('');
+ schTimeSelect.disabled = false;
+ }
+
+ schDaySelect.addEventListener('change', function () {
+ updateTimeOptions(this.value);
+ });
+
+ // ===== Автозаполнение преподавателя из фильтра =====
+ function getFilteredTeacherId() {
+ const teacherFilter = activeFilters['teacher'];
+ if (teacherFilter && teacherFilter.size === 1) {
+ const teacherName = [...teacherFilter][0];
+ // Сопоставляем по username, fullName и их комбинациям
+ const match = teachers.find(t =>
+ t.username === teacherName ||
+ t.fullName === teacherName ||
+ (t.fullName || t.username) === teacherName
+ );
+ return match ? String(match.id) : '';
+ }
+ return '';
+ }
+
+ // ===== Загрузка занятий преподавателя =====
+ async function loadTeacherLessons(teacherId) {
+ const teacher = teachers.find(t => t.id == teacherId);
+ const name = teacher ? (teacher.fullName || teacher.username) : '';
+ schTeacherName.textContent = name
+ ? `Занятия преподавателя: ${name}`
+ : 'Занятия преподавателя';
+
+ modalLessons.style.display = '';
+ schLessonsContainer.innerHTML = 'Загрузка занятий...
';
+
+ try {
+ const lessons = await api.get(`/api/users/lessons/${teacherId}`);
+
+ if (!lessons || !Array.isArray(lessons) || lessons.length === 0) {
+ schLessonsContainer.innerHTML = 'У преподавателя пока нет занятий
';
+ return;
+ }
+
+ const daysOrder = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'];
+ const lessonsByDay = {};
+ lessons.forEach(l => {
+ if (!lessonsByDay[l.day]) lessonsByDay[l.day] = [];
+ lessonsByDay[l.day].push(l);
+ });
+ Object.keys(lessonsByDay).forEach(day => {
+ lessonsByDay[day].sort((a, b) => a.time.localeCompare(b.time));
+ });
+
+ let html = '';
+ daysOrder.forEach(day => {
+ if (!lessonsByDay[day]) return;
+ html += `${day}
`;
+ lessonsByDay[day].forEach(lesson => {
+ html += `
+
+
+
+
${escapeHtml(lesson.subjectName)}
+
+ ${escapeHtml(lesson.typeLesson)}
+ ${escapeHtml(lesson.lessonFormat)}
+ ${escapeHtml(lesson.week)}
+ ${escapeHtml(lesson.classroomName)}
+
+
+
`;
+ });
+ });
+
+ schLessonsContainer.innerHTML = html;
+ } catch (e) {
+ schLessonsContainer.innerHTML = `Ошибка загрузки: ${escapeHtml(e.message)}
`;
+ }
+ }
+
+ // ===== При смене преподавателя — подгрузить его занятия =====
+ schTeacherSelect.addEventListener('change', function () {
+ const teacherId = this.value;
+ if (teacherId) {
+ loadTeacherLessons(teacherId);
+ } else {
+ modalLessons.style.display = 'none';
+ schLessonsContainer.innerHTML = 'Выберите преподавателя для просмотра занятий
';
+ }
+ });
+
+ // ===== Открытие / закрытие оверлея =====
+ function openOverlay() {
+ // Автозаполнение преподавателя из фильтра таблицы
+ const autoTeacherId = getFilteredTeacherId();
+ if (autoTeacherId) {
+ schTeacherSelect.value = autoTeacherId;
+ loadTeacherLessons(autoTeacherId);
+ }
+
+ overlay.classList.add('open');
+ }
+
+ function closeOverlay() {
+ overlay.classList.remove('open');
+ resetForm();
+ }
+
+ function resetForm() {
+ addForm.reset();
+ schTeacherSelect.value = '';
+ schGroupSelect.value = '';
+ schDisciplineSelect.value = '';
+ schClassroomSelect.value = '';
+ schDaySelect.value = '';
+ schTypeSelect.value = '';
+ schTimeSelect.innerHTML = 'Сначала выберите день ';
+ schTimeSelect.disabled = true;
+ if (schWeekUpper) schWeekUpper.checked = false;
+ if (schWeekLower) schWeekLower.checked = false;
+ if (schFormatOffline) schFormatOffline.checked = true;
+ modalLessons.style.display = 'none';
+ schLessonsContainer.innerHTML = 'Выберите преподавателя для просмотра занятий
';
+ hideAlert('sch-add-alert');
+ }
+
+ btnAddLesson.addEventListener('click', openOverlay);
+ btnClose.addEventListener('click', closeOverlay);
+
+ // Закрытие по клику на оверлей (мимо модалок)
+ overlay.addEventListener('click', (e) => {
+ if (e.target === overlay || e.target.classList.contains('cs-overlay-scroll')) {
+ closeOverlay();
+ }
+ });
+
+ // Закрытие по Escape
+ document.addEventListener('keydown', (e) => {
+ if (e.key === 'Escape' && overlay.classList.contains('open')) {
+ closeOverlay();
+ }
+ });
+
+ // ===== Отправка формы =====
+ addForm.addEventListener('submit', async (e) => {
+ e.preventDefault();
+ hideAlert('sch-add-alert');
+
+ const teacherId = schTeacherSelect.value;
+ const groupId = schGroupSelect.value;
+ const subjectId = schDisciplineSelect.value;
+ const classroomId = schClassroomSelect.value;
+ const lessonType = schTypeSelect.value;
+ const dayOfWeek = schDaySelect.value;
+ const timeSlot = schTimeSelect.value;
+ const lessonFormat = document.querySelector('input[name="schLessonFormat"]:checked')?.value;
+
+ if (!teacherId) { showAlert('sch-add-alert', 'Выберите преподавателя', 'error'); return; }
+ if (!groupId) { showAlert('sch-add-alert', 'Выберите группу', 'error'); return; }
+ if (!subjectId) { showAlert('sch-add-alert', 'Выберите дисциплину', 'error'); return; }
+ if (!classroomId) { showAlert('sch-add-alert', 'Выберите аудиторию', 'error'); return; }
+ if (!dayOfWeek) { showAlert('sch-add-alert', 'Выберите день недели', 'error'); return; }
+ if (!timeSlot) { showAlert('sch-add-alert', 'Выберите время', 'error'); return; }
+
+ const weekUpperChecked = schWeekUpper?.checked || false;
+ const weekLowerChecked = schWeekLower?.checked || false;
+
+ if (!weekUpperChecked && !weekLowerChecked) {
+ showAlert('sch-add-alert', 'Не выбран тип недели', 'error');
+ return;
+ }
+
+ let weekType = null;
+ if (weekUpperChecked && weekLowerChecked) weekType = 'Обе';
+ else if (weekUpperChecked) weekType = 'Верхняя';
+ else if (weekLowerChecked) weekType = 'Нижняя';
+
+ try {
+ await api.post('/api/users/lessons/create', {
+ teacherId: parseInt(teacherId),
+ groupId: parseInt(groupId),
+ subjectId: parseInt(subjectId),
+ classroomId: parseInt(classroomId),
+ typeLesson: lessonType,
+ lessonFormat: lessonFormat,
+ day: dayOfWeek,
+ week: weekType,
+ time: timeSlot
+ });
+
+ showAlert('sch-add-alert', 'Занятие добавлено ✓', 'success');
+
+ // Очистить все поля кроме преподавателя (для массового добавления)
+ schGroupSelect.selectedIndex = 0;
+ schDisciplineSelect.selectedIndex = 0;
+ schClassroomSelect.selectedIndex = 0;
+ schTypeSelect.selectedIndex = 0;
+ schDaySelect.selectedIndex = 0;
+ schTimeSelect.innerHTML = 'Сначала выберите день ';
+ schTimeSelect.disabled = true;
+ schWeekUpper.checked = false;
+ schWeekLower.checked = false;
+ document.querySelector('input[name="schLessonFormat"][value="Очно"]').checked = true;
+
+ // Обновить занятия преподавателя в модалке 2
+ if (teacherId) {
+ await loadTeacherLessons(teacherId);
+ }
+
+ // Обновить основную таблицу
+ await loadSchedule();
+
+ setTimeout(() => {
+ hideAlert('sch-add-alert');
+ }, 4000);
+ } catch (err) {
+ showAlert('sch-add-alert', err.message || 'Ошибка добавления занятия', 'error');
+ }
+ });
+
+ // ===================== Инициализация =====================
+ await Promise.all([
+ loadSchedule(),
+ loadGroups(),
+ loadSubjects(),
+ loadClassrooms(),
+ loadTeachers()
+ ]);
}
\ No newline at end of file
diff --git a/frontend/admin/js/views/users.js b/frontend/admin/js/views/users.js
index e77ee8c..2189442 100755
--- a/frontend/admin/js/views/users.js
+++ b/frontend/admin/js/views/users.js
@@ -7,7 +7,9 @@ const ROLE_BADGE = { ADMIN: 'badge-admin', TEACHER: 'badge-teacher', STUDENT: 'b
export async function initUsers() {
const usersTbody = document.getElementById('users-tbody');
const createForm = document.getElementById('create-form');
- const modalBackdrop = document.getElementById('modal-backdrop');
+
+ // ===== Оверлей (cs-overlay) =====
+ const usersOverlay = document.getElementById('users-overlay');
// ===== 1-е модальное окно: Добавить занятие =====
const modalAddLesson = document.getElementById('modal-add-lesson');
@@ -28,7 +30,6 @@ export async function initUsers() {
// ===== 2-е модальное окно: Просмотр занятий =====
const modalViewLessons = document.getElementById('modal-view-lessons');
- const modalViewLessonsClose = document.getElementById('modal-view-lessons-close');
const lessonsContainer = document.getElementById('lessons-container');
const modalTeacherName = document.getElementById('modal-teacher-name');
@@ -56,36 +57,6 @@ export async function initUsers() {
"13:20-14:50"
];
- // =========================================================
- // СИНХРОНИЗАЦИЯ ВЫСОТЫ 1-й МОДАЛКИ -> CSS переменная
- // =========================================================
- const addLessonContent = document.querySelector('#modal-add-lesson .modal-content');
-
- function setAddLessonHeightVar(px) {
- const h = Math.max(0, Math.ceil(px || 0));
- document.documentElement.style.setProperty('--add-lesson-height', `${h}px`);
- }
-
- function syncAddLessonHeight() {
- if (!addLessonContent) return;
-
- if (!modalAddLesson?.classList.contains('open')) {
- // если первая модалка закрыта — "шапки" нет
- setAddLessonHeightVar(0);
- return;
- }
-
- setAddLessonHeightVar(addLessonContent.getBoundingClientRect().height);
- }
-
- // Авто-обновление при любом изменении размеров первой модалки
- if (addLessonContent && 'ResizeObserver' in window) {
- const ro = new ResizeObserver(() => syncAddLessonHeight());
- ro.observe(addLessonContent);
- }
-
- window.addEventListener('resize', () => syncAddLessonHeight());
-
// =========================================================
// Загрузка справочников
// =========================================================
@@ -225,25 +196,15 @@ export async function initUsers() {
`).join('');
}
- function updateBackdrop() {
- if(!modalBackdrop) return;
- const anyOpen =
- modalAddLesson?.classList.contains('open') ||
- modalViewLessons?.classList.contains('open');
-
- modalBackdrop.classList.toggle('open', anyOpen);
+ // ===== Открытие / закрытие оверлея =====
+ function openOverlay() {
+ if (usersOverlay) usersOverlay.classList.add('open');
}
- // Клик мимо модалок закроет их, если не надо, то закомментить этот код
- modalBackdrop?.addEventListener('click', () => {
- if (modalAddLesson?.classList.contains('open')) {
- modalAddLesson.classList.remove('open');
+ function closeOverlay() {
+ if (usersOverlay) usersOverlay.classList.remove('open');
+ if (modalViewLessons) modalViewLessons.style.display = 'none';
resetLessonForm();
- syncAddLessonHeight();
- }
- if (modalViewLessons?.classList.contains('open')) {
- closeViewLessonsModal();
- }
- });
+ }
// =========================================================
// 1-я модалка: добавление занятия
@@ -270,9 +231,7 @@ export async function initUsers() {
lessonDaySelect.value = '';
updateTimeOptions('');
- modalAddLesson.classList.add('open');
- updateBackdrop();
- requestAnimationFrame(() => syncAddLessonHeight());
+ openOverlay();
}
addLessonForm.addEventListener('submit', async (e) => {
@@ -289,15 +248,20 @@ export async function initUsers() {
const lessonFormat = document.querySelector('input[name="lessonFormat"]:checked')?.value;
- if (!groupId) { showAlert('add-lesson-alert', 'Выберите группу', 'error'); requestAnimationFrame(() => syncAddLessonHeight()); return; }
- if (!subjectId) { showAlert('add-lesson-alert', 'Выберите дисциплину', 'error'); requestAnimationFrame(() => syncAddLessonHeight()); return; }
- if (!classroomId) { showAlert('add-lesson-alert', 'Выберите аудиторию', 'error'); requestAnimationFrame(() => syncAddLessonHeight()); return; }
- if (!dayOfWeek) { showAlert('add-lesson-alert', 'Выберите день недели', 'error'); requestAnimationFrame(() => syncAddLessonHeight()); return; }
- if (!timeSlot) { showAlert('add-lesson-alert', 'Выберите время', 'error'); requestAnimationFrame(() => syncAddLessonHeight()); return; }
+ if (!groupId) { showAlert('add-lesson-alert', 'Выберите группу', 'error'); return; }
+ if (!subjectId) { showAlert('add-lesson-alert', 'Выберите дисциплину', 'error'); return; }
+ if (!classroomId) { showAlert('add-lesson-alert', 'Выберите аудиторию', 'error'); return; }
+ if (!dayOfWeek) { showAlert('add-lesson-alert', 'Выберите день недели', 'error'); return; }
+ if (!timeSlot) { showAlert('add-lesson-alert', 'Выберите время', 'error'); return; }
const weekUpperChecked = weekUpper?.checked || false;
const weekLowerChecked = weekLower?.checked || false;
+ if (!weekUpperChecked && !weekLowerChecked) {
+ showAlert('add-lesson-alert', 'Не выбран тип недели', 'error');
+ return;
+ }
+
let weekType = null;
if (weekUpperChecked && weekLowerChecked) weekType = 'Обе';
else if (weekUpperChecked) weekType = 'Верхняя';
@@ -316,57 +280,45 @@ export async function initUsers() {
time: timeSlot
});
- if (modalViewLessons?.classList.contains('open') && currentLessonsTeacherId == userId) {
+ if (modalViewLessons?.style.display !== 'none' && currentLessonsTeacherId == userId) {
await loadTeacherLessons(currentLessonsTeacherId, currentLessonsTeacherName);
}
- showAlert('add-lesson-alert', 'Занятие добавлено', 'success');
+ showAlert('add-lesson-alert', 'Занятие добавлено ✓', 'success');
- lessonGroupSelect.value = '';
- lessonDisciplineSelect.value = '';
- lessonClassroomSelect.value = '';
- lessonTypeSelect.value = '';
- lessonDaySelect.value = '';
- lessonTimeSelect.value = '';
+ lessonGroupSelect.selectedIndex = 0;
+ lessonDisciplineSelect.selectedIndex = 0;
+ lessonClassroomSelect.selectedIndex = 0;
+ lessonTypeSelect.selectedIndex = 0;
+ lessonDaySelect.selectedIndex = 0;
+ lessonTimeSelect.innerHTML = 'Сначала выберите день ';
lessonTimeSelect.disabled = true;
weekUpper.checked = false;
weekLower.checked = false;
document.querySelector('input[name="lessonFormat"][value="Очно"]').checked = true;
- requestAnimationFrame(() => syncAddLessonHeight());
-
setTimeout(() => {
hideAlert('add-lesson-alert');
- syncAddLessonHeight();
}, 3000);
} catch (err) {
showAlert('add-lesson-alert', err.message || 'Ошибка добавления занятия', 'error');
- requestAnimationFrame(() => syncAddLessonHeight());
}
});
lessonDaySelect.addEventListener('change', function () {
updateTimeOptions(this.value);
- requestAnimationFrame(() => syncAddLessonHeight());
});
if (modalAddLessonClose) {
- modalAddLessonClose.addEventListener('click', () => {
- modalAddLesson.classList.remove('open');
- resetLessonForm();
- syncAddLessonHeight();
- updateBackdrop();
- });
+ modalAddLessonClose.addEventListener('click', () => closeOverlay());
}
- if (modalAddLesson) {
- modalAddLesson.addEventListener('click', (e) => {
- if (e.target === modalAddLesson) {
- modalAddLesson.classList.remove('open');
- resetLessonForm();
- syncAddLessonHeight();
- updateBackdrop();
+ // Клик по оверлею (мимо модалок) закрывает всё
+ if (usersOverlay) {
+ usersOverlay.querySelector('.cs-overlay-scroll')?.addEventListener('click', (e) => {
+ if (e.target.classList.contains('cs-overlay-scroll')) {
+ closeOverlay();
}
});
}
@@ -481,48 +433,20 @@ export async function initUsers() {
currentLessonsTeacherId = teacherId;
currentLessonsTeacherName = teacherName || '';
+ if (modalViewLessons) modalViewLessons.style.display = '';
loadTeacherLessons(teacherId, teacherName);
-
- requestAnimationFrame(() => syncAddLessonHeight());
-
- modalViewLessons.classList.add('open');
- updateBackdrop();
-// document.body.style.overflow = 'hidden';
}
function closeViewLessonsModal() {
- modalViewLessons.classList.remove('open');
- updateBackdrop();
-// document.body.style.overflow = '';
-
+ if (modalViewLessons) modalViewLessons.style.display = 'none';
currentLessonsTeacherId = null;
currentLessonsTeacherName = '';
}
- if (modalViewLessonsClose) {
- modalViewLessonsClose.addEventListener('click', closeViewLessonsModal);
- }
-
- if (modalViewLessons) {
- modalViewLessons.addEventListener('click', (e) => {
- if (e.target === modalViewLessons) closeViewLessonsModal();
- });
- }
-
document.addEventListener('keydown', (e) => {
if (e.key !== 'Escape') return;
-
- if (modalAddLesson?.classList.contains('open')) {
- modalAddLesson.classList.remove('open');
- resetLessonForm();
- syncAddLessonHeight();
- updateBackdrop();
- return;
- }
-
- if (modalViewLessons?.classList.contains('open')) {
- closeViewLessonsModal();
- return;
+ if (usersOverlay?.classList.contains('open')) {
+ closeOverlay();
}
});
diff --git a/frontend/admin/views/schedule.html b/frontend/admin/views/schedule.html
index 35d4701..8104356 100755
--- a/frontend/admin/views/schedule.html
+++ b/frontend/admin/views/schedule.html
@@ -1,5 +1,8 @@
-
Расписание занятий
+
@@ -35,9 +38,142 @@
- Загрузка...
+ Загрузка...
+
+
+
+
\ No newline at end of file
diff --git a/frontend/admin/views/users.html b/frontend/admin/views/users.html
index 199750e..bf282f3 100755
--- a/frontend/admin/views/users.html
+++ b/frontend/admin/views/users.html
@@ -1,187 +1,189 @@
-
-
-
-
-
Все пользователи
-
-
-
-
- ID
- Имя пользователя
- ФИО
- Должность
- Кафедра
- Роль
- Действия
-
-
-
-
- Загрузка...
-
-
-
-
-
-
-
-
-
-
Добавить занятие
-
×
-
-
-
-
-
-
-
-
-
-
Загрузка занятий...
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
Все пользователи
+
+
+
+
+ ID
+ Имя пользователя
+ ФИО
+ Должность
+ Кафедра
+ Роль
+ Действия
+
+
+
+
+ Загрузка...
+
+
+
+
+
+
+
+
\ No newline at end of file