diff --git a/frontend/admin/css/components.css b/frontend/admin/css/components.css index 35eb3cd..34af449 100644 --- a/frontend/admin/css/components.css +++ b/frontend/admin/css/components.css @@ -584,4 +584,50 @@ tbody tr:hover { .modal-close:hover { color: var(--error); +} + +.btn-add-lesson { + padding: 0.35rem 0.7rem; + background: rgba(16, 185, 129, 0.1); + border: 1px solid rgba(16, 185, 129, 0.2); + border-radius: var(--radius-sm); + color: var(--success); + font-family: inherit; + font-size: 0.8rem; + cursor: pointer; + transition: background var(--transition), transform var(--transition); + position: relative; + overflow: hidden; +} + +.btn-add-lesson:hover { + background: rgba(16, 185, 129, 0.2); + transform: scale(1.05); +} + +/* Кнопки-переключатели для недели */ +.btn-checkbox { + display: inline-block; + cursor: pointer; +} +.btn-checkbox input { + position: absolute; + opacity: 0; + width: 0; + height: 0; +} +.checkbox-btn { + display: inline-block; + padding: 0.5rem 1rem; + background: var(--bg-secondary); + border: 1px solid var(--bg-card-border); + border-radius: var(--radius-sm); + color: var(--text-primary); + transition: all var(--transition); + user-select: none; +} +.btn-checkbox input:checked + .checkbox-btn { + background: var(--success, #10b981); /* используем success или зелёный */ + border-color: var(--success, #10b981); + color: white; } \ No newline at end of file diff --git a/frontend/admin/js/views/users.js b/frontend/admin/js/views/users.js index 3b96f3a..b0621f3 100644 --- a/frontend/admin/js/views/users.js +++ b/frontend/admin/js/views/users.js @@ -7,7 +7,91 @@ 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 createAlert = document.getElementById('create-alert'); + + // Элементы модального окна добавления занятия + const modalAddLesson = document.getElementById('modal-add-lesson'); + const modalAddLessonClose = document.getElementById('modal-add-lesson-close'); + const addLessonForm = document.getElementById('add-lesson-form'); + const lessonGroupSelect = document.getElementById('lesson-group'); + const lessonDisciplineSelect = document.getElementById('lesson-discipline'); + const lessonUserId = document.getElementById('lesson-user-id'); + const lessonDaySelect = document.getElementById('lesson-day'); + const weekUpper = document.getElementById('week-upper'); + const weekLower = document.getElementById('week-lower'); + // NEW: получаем элемент выбора времени + const lessonTimeSelect = document.getElementById('lesson-time'); + + // Переменные для хранения загруженных данных + let groups = []; + let subjects = []; + + // NEW: массивы с временными слотами + 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'); + renderGroupOptions(); + } catch (e) { + console.error('Ошибка загрузки групп:', e); + } + } + + // Загрузка дисциплин + async function loadSubjects() { + try { + subjects = await api.get('/api/subjects'); + renderSubjectOptions(); + } catch (e) { + console.error('Ошибка загрузки дисциплин:', e); + } + } + + // Заполнение select группами + function renderGroupOptions() { + lessonGroupSelect.innerHTML = '' + + groups.map(g => ``).join(''); + } + + // Заполнение select дисциплинами + function renderSubjectOptions() { + lessonDisciplineSelect.innerHTML = '' + + subjects.map(s => ``).join(''); + } + + // NEW: функция обновления списка времени в зависимости от дня + function updateTimeOptions(dayValue) { + let times = []; + if (dayValue === "Суббота") { + times = saturdayTimes; + } else if (dayValue && dayValue !== '') { + times = weekdaysTimes; + } else { + lessonTimeSelect.innerHTML = ''; + lessonTimeSelect.disabled = true; + return; + } + + lessonTimeSelect.innerHTML = '' + + times.map(t => ``).join(''); + lessonTimeSelect.disabled = false; + } async function loadUsers() { try { @@ -29,9 +113,93 @@ export async function initUsers() { ${escapeHtml(u.username)} ${ROLE_LABELS[u.role] || escapeHtml(u.role)} + `).join(''); } + // Сброс формы модального окна + function resetLessonForm() { + addLessonForm.reset(); + lessonUserId.value = ''; + if (weekUpper) weekUpper.checked = false; + if (weekLower) weekLower.checked = false; + // NEW: сбрасываем селект времени + lessonTimeSelect.innerHTML = ''; + lessonTimeSelect.disabled = true; + hideAlert('add-lesson-alert'); + } + + // Открытие модалки с установкой userId + function openAddLessonModal(userId) { + lessonUserId.value = userId; + // NEW: сбрасываем выбранный день и время + lessonDaySelect.value = ''; + updateTimeOptions(''); + modalAddLesson.classList.add('open'); + } + + // Обработчик отправки формы добавления занятия + addLessonForm.addEventListener('submit', async (e) => { + e.preventDefault(); + hideAlert('add-lesson-alert'); + + const userId = lessonUserId.value; + const groupId = lessonGroupSelect.value; + const subjectId = lessonDisciplineSelect.value; + const dayOfWeek = lessonDaySelect.value; + const timeSlot = lessonTimeSelect.value; // NEW: получаем выбранное время + + // Проверка обязательных полей + if (!groupId) { + showAlert('add-lesson-alert', 'Выберите группу', 'error'); + return; + } + if (!subjectId) { + showAlert('add-lesson-alert', 'Выберите дисциплину', 'error'); + return; + } + if (!dayOfWeek) { + showAlert('add-lesson-alert', 'Выберите день недели', 'error'); + return; + } + // NEW: проверка времени + if (!timeSlot) { + showAlert('add-lesson-alert', 'Выберите время', 'error'); + return; + } + + // Определяем выбранный тип недели + const weekUpperChecked = weekUpper?.checked || false; + const weekLowerChecked = weekLower?.checked || false; + let weekType = null; + if (weekUpperChecked && weekLowerChecked) { + weekType = 'Обе'; + } else if (weekUpperChecked) { + weekType = 'Верхняя'; + } else if (weekLowerChecked) { + weekType = 'Нижняя'; + } + + try { + // Отправляем данные на сервер + const response = await api.post('/api/users/lessons/create', { + teacherId: parseInt(userId), + groupId: parseInt(groupId), + lessonTypeId: parseInt(subjectId), + day: dayOfWeek, + week: weekType, + time: timeSlot // передаём время + }); + showAlert('add-lesson-alert', 'Занятие добавлено', 'success'); + setTimeout(() => { + modalAddLesson.classList.remove('open'); + resetLessonForm(); + }, 1500); + } catch (e) { + showAlert('add-lesson-alert', e.message || 'Ошибка добавления занятия', 'error'); + } + }); + createForm.addEventListener('submit', async (e) => { e.preventDefault(); hideAlert('create-alert'); @@ -50,18 +218,52 @@ export async function initUsers() { } }); + // Обработчик кликов по таблице usersTbody.addEventListener('click', async (e) => { - const btn = e.target.closest('.btn-delete'); - if (!btn) return; - if (!confirm('Удалить пользователя?')) return; - try { - await api.delete('/api/users/' + btn.dataset.id); - loadUsers(); - } catch (e) { - alert(e.message || 'Ошибка удаления'); + const deleteBtn = e.target.closest('.btn-delete'); + if (deleteBtn) { + if (!confirm('Удалить пользователя?')) return; + try { + await api.delete('/api/users/' + deleteBtn.dataset.id); + loadUsers(); + } catch (e) { + alert(e.message || 'Ошибка удаления'); + } + return; + } + + const addLessonBtn = e.target.closest('.btn-add-lesson'); + if (addLessonBtn) { + e.preventDefault(); + if (modalAddLesson) { + openAddLessonModal(addLessonBtn.dataset.id); + } } }); - // Initial load - loadUsers(); -} + // NEW: обработчик изменения дня недели для обновления списка времени + lessonDaySelect.addEventListener('change', function() { + updateTimeOptions(this.value); + }); + + // Закрытие модалки по крестику + if (modalAddLessonClose) { + modalAddLessonClose.addEventListener('click', () => { + modalAddLesson.classList.remove('open'); + resetLessonForm(); + }); + } + + // Закрытие по клику на overlay + if (modalAddLesson) { + modalAddLesson.addEventListener('click', (e) => { + if (e.target === modalAddLesson) { + modalAddLesson.classList.remove('open'); + resetLessonForm(); + } + }); + } + + // Загружаем все данные при инициализации + await Promise.all([loadUsers(), loadGroups(), loadSubjects()]); +} \ No newline at end of file diff --git a/frontend/admin/views/users.html b/frontend/admin/views/users.html index a6198d2..1303153 100644 --- a/frontend/admin/views/users.html +++ b/frontend/admin/views/users.html @@ -45,3 +45,66 @@ + + + \ No newline at end of file