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