diff --git a/frontend/admin/css/components.css b/frontend/admin/css/components.css index 6f55d8d..4084a73 100755 --- a/frontend/admin/css/components.css +++ b/frontend/admin/css/components.css @@ -860,4 +860,199 @@ tbody tr:hover { /* используем success или зелёный */ border-color: var(--success, #10b981); color: white; +} + +/* ===== View Lessons Modal ===== */ +.view-lessons-modal { + width: 50% !important; /* Половина экрана */ + max-width: 50% !important; + background: var(--bg-primary); + border: 1px solid var(--bg-card-border); + border-radius: var(--radius-md); + padding: 2rem; + position: relative; + box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5); + margin: 0; + transform: none; +} + +.modal-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 2rem; + padding-right: 2rem; +} + +.modal-header h2 { + margin: 0; + font-size: 1.3rem; + color: var(--text-primary); +} + +/* Контейнер для занятий */ +.lessons-container { + max-height: 70vh; + overflow-y: auto; + padding-right: 0.5rem; +} + +/* Карточка занятия */ +.lesson-card { + background: var(--bg-card); + border: 1px solid var(--bg-card-border); + border-radius: var(--radius-sm); + padding: 1.2rem; + margin-bottom: 1rem; + transition: all 0.2s ease; +} + +.lesson-card:hover { + transform: translateY(-2px); + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15); + border-color: var(--accent); +} + +.lesson-card-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 0.8rem; + padding-bottom: 0.5rem; + border-bottom: 1px dashed var(--bg-card-border); +} + +.lesson-group { + font-weight: 700; + color: var(--accent); + font-size: 1rem; + background: rgba(99, 102, 241, 0.1); + padding: 0.3rem 0.8rem; + border-radius: 20px; +} + +.lesson-time { + color: var(--text-secondary); + font-size: 0.9rem; + display: flex; + align-items: center; + gap: 0.3rem; +} + +.lesson-time::before { + content: "🕒"; + font-size: 0.9rem; + opacity: 0.7; +} + +.lesson-card-body { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.lesson-subject { + font-weight: 600; + color: var(--text-primary); + font-size: 1.1rem; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.lesson-subject::before { + content: "📚"; + font-size: 1rem; + opacity: 0.7; +} + +.lesson-details { + display: flex; + flex-wrap: wrap; + gap: 0.8rem; + margin-top: 0.5rem; +} + +.lesson-detail-item { + background: var(--bg-input); + padding: 0.3rem 0.8rem; + border-radius: 15px; + font-size: 0.85rem; + color: var(--text-secondary); + border: 1px solid var(--bg-card-border); +} + +/* День недели как разделитель */ +.lesson-day-divider { + margin: 1.5rem 0 1rem 0; + font-weight: 700; + color: var(--accent); + font-size: 1.1rem; + text-transform: uppercase; + letter-spacing: 0.05em; + border-bottom: 2px solid var(--accent-glow); + padding-bottom: 0.3rem; +} + +.lesson-day-divider:first-of-type { + margin-top: 0; +} + +/* Загрузка и пустые состояния */ +.loading-lessons, .no-lessons { + text-align: center; + color: var(--text-secondary); + padding: 3rem; + font-size: 1rem; + background: var(--bg-card); + border-radius: var(--radius-sm); +} + +/* Светлая тема */ +[data-theme="light"] .lesson-card { + background: white; + border-color: rgba(0, 0, 0, 0.1); +} + +[data-theme="light"] .lesson-group { + background: rgba(99, 102, 241, 0.05); +} + +/* Адаптивность */ +@media (max-width: 1200px) { + .view-lessons-modal { + width: 70% !important; + max-width: 70% !important; + } +} + +@media (max-width: 768px) { + .view-lessons-modal { + width: 90% !important; + max-width: 90% !important; + } + + .lesson-card-header { + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + } +} + +.btn-view-lessons { + padding: 0.35rem 0.7rem; + background: rgba(99, 102, 241, 0.1); + border: 1px solid rgba(99, 102, 241, 0.2); + border-radius: var(--radius-sm); + color: var(--accent); + font-family: inherit; + font-size: 0.8rem; + cursor: pointer; + transition: all var(--transition); + white-space: nowrap; +} + +.btn-view-lessons:hover { + background: rgba(99, 102, 241, 0.2); + transform: translateY(-1px); } \ No newline at end of file diff --git a/frontend/admin/js/views/users.js b/frontend/admin/js/views/users.js index 57991c4..ef01e89 100755 --- a/frontend/admin/js/views/users.js +++ b/frontend/admin/js/views/users.js @@ -172,8 +172,13 @@ export async function initUsers() { ${u.id} ${escapeHtml(u.username)} ${ROLE_LABELS[u.role] || escapeHtml(u.role)} - - + + + + + + + `).join(''); } @@ -351,4 +356,158 @@ export async function initUsers() { // Загружаем все данные при инициализации await Promise.all([loadUsers(), loadGroups(), loadSubjects(), loadClassrooms()]); -} \ No newline at end of file + + +// Элементы второго модального окна + 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'); + +// Функция для загрузки и отображения занятий преподавателя + async function loadTeacherLessons(teacherId, teacherName) { + try { + lessonsContainer.innerHTML = '
Загрузка занятий...
'; + + // Устанавливаем имя преподавателя в заголовок + if (teacherName) { + modalTeacherName.textContent = `Занятия преподавателя: ${teacherName}`; + } else { + modalTeacherName.textContent = 'Занятия преподавателя'; + } + + // Загружаем занятия + const lessons = await api.get(`/api/users/lessons/${teacherId}`); + + if (!lessons || lessons.length === 0) { + lessonsContainer.innerHTML = '
У преподавателя пока нет занятий
'; + return; + } + + // Группируем занятия по дням недели + const daysOrder = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота']; + const lessonsByDay = {}; + + lessons.forEach(lesson => { + if (!lessonsByDay[lesson.day]) { + lessonsByDay[lesson.day] = []; + } + lessonsByDay[lesson.day].push(lesson); + }); + + // Сортируем занятия в каждом дне по времени + Object.keys(lessonsByDay).forEach(day => { + lessonsByDay[day].sort((a, b) => { + // Простая сортировка по времени (можно улучшить) + return a.time.localeCompare(b.time); + }); + }); + + // Формируем HTML + let html = ''; + + daysOrder.forEach(day => { + if (lessonsByDay[day]) { + html += `
${day}
`; + + lessonsByDay[day].forEach(lesson => { + html += ` +
+
+ ${escapeHtml(lesson.groupName)} + ${escapeHtml(lesson.time)} +
+
+
${escapeHtml(lesson.subjectName)}
+
+ ${escapeHtml(lesson.typeLesson)} + ${escapeHtml(lesson.lessonFormat)} + ${escapeHtml(lesson.week)} + ${escapeHtml(lesson.classroomName)} +
+
+
+ `; + }); + } + }); + + lessonsContainer.innerHTML = html; + + } catch (e) { + lessonsContainer.innerHTML = `
Ошибка загрузки: ${escapeHtml(e.message)}
`; + console.error('Ошибка загрузки занятий:', e); + } + } + +// Функция открытия модального окна + function openViewLessonsModal(teacherId, teacherName) { + loadTeacherLessons(teacherId, teacherName); + modalViewLessons.classList.add('open'); + // Блокируем скролл страницы + document.body.style.overflow = 'hidden'; + } + +// Функция закрытия модального окна + function closeViewLessonsModal() { + modalViewLessons.classList.remove('open'); + document.body.style.overflow = ''; + } + +// Обработчик кликов по таблице (добавляем в существующий) +// Найдите в коде usersTbody.addEventListener('click', ...) и добавьте в него: + +// ДОЛЖНО ПОЛУЧИТЬСЯ ТАК: + usersTbody.addEventListener('click', async (e) => { + 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); + } + return; + } + + // НОВЫЙ ОБРАБОТЧИК для кнопки просмотра занятий + const viewLessonsBtn = e.target.closest('.btn-view-lessons'); + if (viewLessonsBtn) { + e.preventDefault(); + const teacherId = viewLessonsBtn.dataset.id; + const teacherName = viewLessonsBtn.dataset.name; + openViewLessonsModal(teacherId, teacherName); + } + }); + +// Обработчики закрытия модального окна + if (modalViewLessonsClose) { + modalViewLessonsClose.addEventListener('click', closeViewLessonsModal); + } + +// Закрытие по клику на overlay + if (modalViewLessons) { + modalViewLessons.addEventListener('click', (e) => { + if (e.target === modalViewLessons) { + closeViewLessonsModal(); + } + }); + } + +// Закрытие по Escape + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && modalViewLessons?.classList.contains('open')) { + closeViewLessonsModal(); + } + }); +} diff --git a/frontend/admin/views/users.html b/frontend/admin/views/users.html index 826aebc..3eb70b2 100755 --- a/frontend/admin/views/users.html +++ b/frontend/admin/views/users.html @@ -154,5 +154,18 @@ + + \ No newline at end of file