/
erioxis
/
web-nodejs
Обзор
Документация
Войти
/
erioxis
/
web-nodejs
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
public/lab11/task3/script.js
1 785 строк
79 KB
erioxis
lab11fix
15 дек 2025, 23:21
15 дек 2025, 23:21
70dc7ba
Код
Авторство
О чём код?
// public/lab11/task3/script.js // --- Глобальные переменные --- let authToken = localStorage.getItem('jwt_token'); let currentUser = null; let allProducts = []; let allCategories = []; let allOrders = []; let cart = []; let currentProductDetails = null; let allSchedule = []; let allGroups = []; let allTeachers = []; let allDisciplines = []; let allRooms = []; // --- Функции UI --- function showContent(contentId) { document.querySelectorAll('.content').forEach(el => el.classList.remove('active')); document.getElementById(contentId).classList.add('active'); // Загружаем данные при отображении соответствующей вкладки if (contentId === 'store') { showStoreTab('store-view'); } else if (contentId === 'schedule') { showScheduleTab('schedule-view'); } } function showStoreTab(tabId) { document.querySelectorAll('#store-view, #store-management').forEach(el => el.style.display = 'none'); document.getElementById(tabId).style.display = 'block'; if (tabId === 'store-view') { loadStoreViewData(); } else if (tabId === 'store-management' && currentUser && currentUser.role === 'admin') { loadStoreManagementData(); } } function showScheduleTab(tabId) { document.querySelectorAll('#schedule-view, #schedule-management').forEach(el => el.style.display = 'none'); document.getElementById(tabId).style.display = 'block'; if (tabId === 'schedule-view') { loadScheduleViewData(); } else if (tabId === 'schedule-management' && currentUser && currentUser.role === 'admin') { loadScheduleManagementData(); } } function showManagementTab(tabId) { // Скрываем все вкладки управления расписанием document.querySelectorAll('#schedule-management .management-tab').forEach(el => { el.classList.remove('active'); el.style.display = 'none'; // Добавляем скрытие через display }); // Активируем нужную вкладку const targetTab = document.getElementById(tabId); if (targetTab) { targetTab.classList.add('active'); targetTab.style.display = 'block'; // Перезагружаем данные только для активной вкладки if (tabId === 'schedule-records-management') { loadScheduleRecords(); // Загружаем список записей расписания populateDropdowns(); // Для формы добавления } else if (tabId === 'groups-management') { loadGroups(); } else if (tabId === 'teachers-management') { loadTeachers(); } else if (tabId === 'disciplines-management') { loadDisciplines(); } else if (tabId === 'rooms-management') { loadRooms(); } } else { console.error(`Вкладка управления с ID '${tabId}' не найдена.`); } } // Специальные функции для навигации по вкладкам управления расписанием function showScheduleRecordsManagement() { showManagementTab('schedule-records-management'); } function showGroupsManagement() { showManagementTab('groups-management'); } function showTeachersManagement() { showManagementTab('teachers-management'); } function showDisciplinesManagement() { showManagementTab('disciplines-management'); } function showRoomsManagement() { showManagementTab('rooms-management'); } function updateAuthStatus() { const userStatusEl = document.getElementById('user-status'); const logoutBtn = document.getElementById('logout-btn'); const loginBtn = document.getElementById('login-btn'); if (currentUser) { userStatusEl.textContent = `${currentUser.login} (Роль: ${currentUser.role}) | `; logoutBtn.style.display = 'inline-block'; loginBtn.style.display = 'none'; // Показываем вкладки управления только админу if (currentUser.role === 'admin') { document.querySelectorAll('.management-tab').forEach(el => el.style.display = 'block'); // Показываем все management-tab } } else { userStatusEl.textContent = 'Гость | '; logoutBtn.style.display = 'none'; loginBtn.style.display = 'inline-block'; // Скрываем вкладки управления для гостей и обычных пользователей document.querySelectorAll('.management-tab').forEach(el => el.style.display = 'none'); // Скрываем все management-tab } } function goToAuth() { window.location.href = '../task1/'; // Перенаправляем на страницу авторизации LR11 } function logout() { localStorage.removeItem('jwt_token'); authToken = null; currentUser = null; updateAuthStatus(); // После выхода снова проверим статус, чтобы обновить UI checkAuthAndLoad(); } // --- Функция проверки аутентификации и загрузки --- async function checkAuthAndLoad() { if (authToken) { try { const response = await fetch('/api/lab11/profile', { headers: { 'Authorization': `Bearer ${authToken}` } }); if (response.ok) { const data = await response.json(); currentUser = data.user; updateAuthStatus(); // Теперь, когда пользователь известен, показываем основной интерфейс // и загружаем данные для открытой вкладки const activeContent = document.querySelector('.content.active'); if (activeContent) { showContent(activeContent.id); } } else { throw new Error('Токен недействителен'); } } catch (err) { console.error('Ошибка проверки токена:', err); localStorage.removeItem('jwt_token'); authToken = null; currentUser = null; updateAuthStatus(); } } else { updateAuthStatus(); } } // --- Функция API с авторизацией --- async function apiCall(url, method = 'GET', body = null, requiresAuth = false, requiresAdmin = false) { const headers = { 'Content-Type': 'application/json' }; if (authToken) { headers['Authorization'] = `Bearer ${authToken}`; } if (requiresAuth && !authToken) { alert('Сначала войдите в систему.'); goToAuth(); return null; } const response = await fetch(url, { method, headers, body: body ? JSON.stringify(body) : undefined }); if (response.status === 401) { alert('Сессия истекла. Пожалуйста, войдите снова.'); logout(); return null; } if (requiresAdmin && response.status === 403) { alert('Доступ запрещен. Требуется роль администратора.'); return null; } return response; } // --- Загрузка данных для просмотра --- async function loadStoreViewData() { await loadCategoriesForFilters(); await loadAllProducts(); displayProducts(allProducts); updateCartDisplay(); // Обновляем отображение корзины при загрузке магазина } async function loadScheduleViewData() { await Promise.all([ loadGroupsForFilters(), loadTeachersForFilters(), loadDisciplinesForFilters(), loadRoomsForFilters() ]); await loadSchedule(); } // --- Загрузка данных для управления (только админ) --- async function loadStoreManagementData() { if (currentUser && currentUser.role === 'admin') { await loadCategoriesForManagement(); await loadProductsForManagement(); } else { alert('Доступ запрещен. Требуется роль администратора.'); showStoreTab('store-view'); // Переключаемся обратно на просмотр } } async function loadScheduleManagementData() { if (currentUser && currentUser.role === 'admin') { // Загрузка данных для списков и форм управления расписанием await Promise.all([ loadGroupsForForm(), loadTeachersForForm(), loadDisciplinesForForm(), loadRoomsForForm() ]); // Загружаем данные для активной вкладки const activeTab = document.querySelector('#schedule-management .management-tab.active'); if (activeTab) { showManagementTab(activeTab.id); } else { // По умолчанию показываем расписание showManagementTab('schedule-records-management'); } } else { alert('Доступ запрещен. Требуется роль администратора.'); showScheduleTab('schedule-view'); // Переключаемся обратно на просмотр } } // --- Функции магазина (с авторизацией) --- async function loadAllProducts() { try { const response = await apiCall('/api/lab10/task1/all-products', 'GET', null, true /* requiresAuth */); if (response && response.ok) { allProducts = await response.json(); } else if (response) { console.error('Ошибка при загрузке товаров:', response.status); } } catch (error) { console.error('Ошибка при загрузке товаров:', error); showError('products-container', 'Ошибка при загрузке товаров: ' + error.message); } } async function loadCategoriesForFilters() { try { // GET запрос не требует авторизации const response = await fetch('/api/lab10/categories'); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); const categories = await response.json(); populateCategoryFilter(categories); } catch (error) { console.error('Ошибка при загрузке категорий для фильтра:', error); populateCategoryFilter([]); } } async function loadCategoriesForManagement() { try { const response = await apiCall('/api/lab10/categories', 'GET', null, true, true); if (response && response.ok) { allCategories = await response.json(); populateCategoryForForm(allCategories); populateCategoryForFormModal(allCategories); } else if (response) { // Ошибка будет обработана в apiCall } } catch (error) { console.error('Ошибка при загрузке категорий для управления:', error); } } async function loadProductsForManagement() { if (currentUser && currentUser.role === 'admin') { try { const response = await apiCall('/api/lab10/task1/all-products', 'GET', null, true, true); if (response && response.ok) { allProducts = await response.json(); displayProductsForManagement(allProducts); } else if (response) { // Ошибка будет обработана в apiCall } } catch (error) { console.error('Ошибка при загрузке товаров для управления:', error); } } } // --- НОВАЯ ФУНКЦИЯ getDayNumberByName --- function getDayNumberByName(dayName) { const dayMap = { 'Понедельник': 1, 'Вторник': 2, 'Среда': 3, 'Четверг': 4, 'Пятница': 5, 'Суббота': 6 }; return dayMap[dayName] || null; } function getDayName(dayValue) { // Если dayValue это объект или undefined, возвращаем "Неизвестный день" if (!dayValue) return 'Неизвестный день'; // Если это число или строка-число const dayNum = parseInt(dayValue); if (!isNaN(dayNum)) { const daysMap = { 1: 'Понедельник', 2: 'Вторник', 3: 'Среда', 4: 'Четверг', 5: 'Пятница', 6: 'Суббота' }; return daysMap[dayNum] || 'Неизвестный день'; } // Если это строка с названием дня const dayString = String(dayValue).trim(); const validDays = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота']; if (validDays.includes(dayString)) { return dayString; } return 'Неизвестный день'; } // --- Загрузка расписания --- async function loadSchedule() { const group = document.getElementById('group-filter').value; const teacher = document.getElementById('teacher-filter').value; const discipline = document.getElementById('discipline-filter').value; const room = document.getElementById('room-filter').value; const day = document.getElementById('day-filter').value; const week = document.getElementById('week-filter').value; showLoading('schedule-container'); try { const params = new URLSearchParams(); if (group && group !== '') params.append('group_id', group); if (teacher && teacher !== '') params.append('teacher_id', teacher); if (discipline && discipline !== '') params.append('discipline_id', discipline); if (room && room !== '') params.append('room_id', room); // ВАЖНО: Преобразуем число в название дня if (day && day !== '') { const dayMap = { '1': 'Понедельник', '2': 'Вторник', '3': 'Среда', '4': 'Четверг', '5': 'Пятница', '6': 'Суббота' }; const dayName = dayMap[day]; if (dayName) { params.append('day_of_week', dayName); } } if (week && week !== '') params.append('week_number', week); const response = await fetch(`/api/lab10/task2/schedule?${params.toString()}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); displaySchedule(data); } catch (error) { showError('schedule-container', 'Ошибка при загрузке расписания: ' + error.message); } } // --- ИСПРАВЛЕННАЯ ФУНКЦИЯ: displaySchedule для просмотра --- function displaySchedule(schedule) { const container = document.getElementById('schedule-container'); if (schedule.length === 0) { container.innerHTML = '<div class="error">Расписание не найдено по заданным фильтрам.</div>'; return; } const dayOrder = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота']; schedule.sort((a, b) => { if (a.week_number !== b.week_number) return a.week_number - b.week_number; const dayAIndex = dayOrder.indexOf(getDayName(a.day_of_week)); const dayBIndex = dayOrder.indexOf(getDayName(b.day_of_week)); if (dayAIndex !== dayBIndex) return dayAIndex - dayBIndex; if (a.start_time !== b.start_time) return a.start_time.localeCompare(b.start_time); return a.id - b.id; }); let tableHtml = ` <table class="schedule-table"> <thead> <tr> <th>Неделя</th> <th>День недели</th> <th>Время</th> <th>Группа</th> <th>Преподаватель</th> <th>Дисциплина</th> <th>Аудитория</th> <th>Тип занятия</th> </tr> </thead> <tbody> `; schedule.forEach(item => { const dayName = getDayName(item.day_of_week); // Используем данные из item, которые уже содержат имена из JOIN запроса const groupName = item.group_name || 'Неизвестная группа'; const teacherName = item.teacher_name || item.teacher_full_name || 'Неизвестный преподаватель'; const disciplineName = item.discipline_name || 'Неизвестная дисциплина'; const roomName = item.room_name || 'Неизвестная аудитория'; const lessonType = item.lesson_type || item.type || 'Неизвестный тип'; tableHtml += ` <tr> <td>${item.week_number}</td> <td>${dayName}</td> <td>${item.start_time} - ${item.end_time}</td> <td>${groupName}</td> <td>${teacherName}</td> <td>${disciplineName}</td> <td>${roomName}</td> <td>${lessonType}</td> </tr> `; }); tableHtml += ` </tbody> </table> `; container.innerHTML = tableHtml; } async function loadGroupsForFilters() { try { const response = await fetch('/api/lab10/task2/groups'); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); const groups = await response.json(); allGroups = groups; // Сохраняем в глобальную переменную populateSelect('group-filter', groups, 'id', 'name', 'Все группы'); } catch (error) { console.error('Ошибка при загрузке групп для фильтра:', error); populateSelect('group-filter', [], 'id', 'name', 'Все группы'); } } async function loadTeachersForFilters() { try { const response = await fetch('/api/lab10/task2/teachers'); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); const teachers = await response.json(); allTeachers = teachers; // Сохраняем в глобальную переменную populateSelect('teacher-filter', teachers, 'id', 'full_name', 'Все преподаватели'); } catch (error) { console.error('Ошибка при загрузке преподавателей для фильтра:', error); populateSelect('teacher-filter', [], 'id', 'full_name', 'Все преподаватели'); } } async function loadDisciplinesForFilters() { try { const response = await fetch('/api/lab10/task2/disciplines'); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); const disciplines = await response.json(); allDisciplines = disciplines; // Сохраняем в глобальную переменную populateSelect('discipline-filter', disciplines, 'id', 'name', 'Все дисциплины'); } catch (error) { console.error('Ошибка при загрузке дисциплин для фильтра:', error); populateSelect('discipline-filter', [], 'id', 'name', 'Все дисциплины'); } } async function loadRoomsForFilters() { try { const response = await fetch('/api/lab10/task2/rooms'); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); const rooms = await response.json(); allRooms = rooms; // Сохраняем в глобальную переменную populateSelect('room-filter', rooms, 'id', 'name', 'Все аудитории'); } catch (error) { console.error('Ошибка при загрузке аудиторий для фильтра:', error); populateSelect('room-filter', [], 'id', 'name', 'Все аудитории'); } } // --- Функции управления (только админ) --- async function addProduct() { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } const title = document.getElementById('product-title').value.trim(); const price = parseFloat(document.getElementById('product-price').value); const amount = parseInt(document.getElementById('product-amount').value); const categoryId = document.getElementById('product-category-id').value || null; const image = document.getElementById('product-image').value.trim(); if (!title || isNaN(price) || isNaN(amount) || price < 0 || amount < 0) { alert('Пожалуйста, заполните все поля корректно. Цена и количество должны быть числами >= 0.'); return; } try { const response = await apiCall('/api/lab10/task1/products', 'POST', { title, price, amount, category_id: categoryId, image }, true /* requiresAuth */, true /* requiresAdmin */); if (response && response.ok) { const data = await response.json(); document.getElementById('product-title').value = ''; document.getElementById('product-price').value = ''; document.getElementById('product-amount').value = ''; document.getElementById('product-category-id').value = ''; document.getElementById('product-image').value = ''; await loadProductsForManagement(); // Обновляем список управления await loadAllProducts(); // Обновляем список для просмотра filterProducts(); // Применяем фильтрацию } else if (response) { const data = await response.json(); alert('Не удалось добавить товар: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при добавлении товара: ' + error.message); } } async function addCategory() { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } const name = document.getElementById('category-name').value.trim(); if (!name) { alert('Пожалуйста, введите название категории.'); return; } try { const response = await apiCall('/api/lab10/task1/categories', 'POST', { name }, true /* requiresAuth */, true /* requiresAdmin */); if (response && response.ok) { const data = await response.json(); document.getElementById('category-name').value = ''; await loadCategoriesForManagement(); // Обновляем список и форму await loadCategoriesForFilters(); // Обновляем фильтр в просмотре await loadAllProducts(); // Перезагрузим товары, так как могли измениться связи filterProducts(); } else if (response) { const data = await response.json(); alert('Не удалось добавить категорию: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при добавлении категории: ' + error.message); } } async function addScheduleRecord() { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } const weekNumber = parseInt(document.getElementById('schedule-week-number').value); const dayOfWeek = parseInt(document.getElementById('schedule-day-of-week').value); const startTime = document.getElementById('schedule-start-time').value; const endTime = document.getElementById('schedule-end-time').value; const groupId = parseInt(document.getElementById('schedule-group-id').value); const teacherId = parseInt(document.getElementById('schedule-teacher-id').value); const disciplineId = parseInt(document.getElementById('schedule-discipline-id').value); const roomId = parseInt(document.getElementById('schedule-room-id').value); const type = document.getElementById('schedule-type').value; // Валидация полей if (!startTime || !endTime) { alert('Пожалуйста, введите время начала и окончания.'); return; } if (!groupId || !teacherId || !disciplineId || !roomId) { alert('Пожалуйста, выберите группу, преподавателя, дисциплину и аудиторию.'); return; } try { const response = await apiCall('/api/lab10/task2/schedule', 'POST', { week_number: weekNumber, day_of_week: dayOfWeek, start_time: startTime, end_time: endTime, group_id: groupId, teacher_id: teacherId, discipline_id: disciplineId, room_id: roomId, type }, true /* requiresAuth */, true /* requiresAdmin */); if (response && response.ok) { const data = await response.json(); // Очищаем форму (оставим значения по умолчанию) document.getElementById('schedule-week-number').value = 1; document.getElementById('schedule-day-of-week').value = 1; document.getElementById('schedule-start-time').value = ''; document.getElementById('schedule-end-time').value = ''; document.getElementById('schedule-group-id').value = ''; document.getElementById('schedule-teacher-id').value = ''; document.getElementById('schedule-discipline-id').value = ''; document.getElementById('schedule-room-id').value = ''; document.getElementById('schedule-type').value = 'лекция'; await loadScheduleRecords(); // Обновляем список управления расписанием if (document.getElementById('schedule-view').classList.contains('active')) { loadSchedule(); // Обновляем отображение расписания } alert('Запись успешно добавлена!'); } else if (response) { const data = await response.json(); alert('Не удалось добавить запись: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при добавлении записи: ' + error.message); } } async function addGroup() { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } const name = document.getElementById('group-name').value.trim(); if (!name) { alert('Пожалуйста, введите название группы.'); return; } try { const response = await apiCall('/api/lab10/task2/groups', 'POST', { name }, true /* requiresAuth */, true /* requiresAdmin */); if (response && response.ok) { document.getElementById('group-name').value = ''; await loadGroups(); // Обновляем список управления await loadGroupsForFilters(); // Обновляем фильтр в просмотре await loadGroupsForForm(); // Обновляем форму в управлении расписанием // Обновляем все вкладки если они активны if (document.getElementById('schedule-view').classList.contains('active')) { loadSchedule(); // Обновляем отображение расписания } if (document.getElementById('schedule-management').classList.contains('active')) { populateDropdowns(); // Обновляем выпадающие списки } alert('Группа успешно добавлена!'); } else if (response) { const data = await response.json(); alert('Не удалось добавить группу: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при добавлении группы: ' + error.message); } } async function addTeacher() { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } const fullName = document.getElementById('teacher-full-name').value.trim(); const position = document.getElementById('teacher-position').value.trim(); const department = document.getElementById('teacher-department').value.trim(); if (!fullName) { alert('Пожалуйста, введите ФИО преподавателя.'); return; } try { const response = await apiCall('/api/lab10/task2/teachers', 'POST', { full_name: fullName, position, department }, true /* requiresAuth */, true /* requiresAdmin */); if (response && response.ok) { document.getElementById('teacher-full-name').value = ''; document.getElementById('teacher-position').value = ''; document.getElementById('teacher-department').value = ''; await loadTeachers(); // Обновляем список управления await loadTeachersForFilters(); // Обновляем фильтр в просмотре await loadTeachersForForm(); // Обновляем форму в управлении расписанием // Обновляем все вкладки если они активны if (document.getElementById('schedule-view').classList.contains('active')) { loadSchedule(); // Обновляем отображение расписания } if (document.getElementById('schedule-management').classList.contains('active')) { populateDropdowns(); // Обновляем выпадающие списки } alert('Преподаватель успешно добавлен!'); } else if (response) { const data = await response.json(); alert('Не удалось добавить преподавателя: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при добавлении преподавателя: ' + error.message); } } async function addDiscipline() { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } const name = document.getElementById('discipline-name').value.trim(); const hours = parseInt(document.getElementById('discipline-hours').value); if (!name) { alert('Пожалуйста, введите название дисциплины.'); return; } if (isNaN(hours) || hours < 0) { alert('Пожалуйста, введите корректное количество часов.'); return; } try { const response = await apiCall('/api/lab10/task2/disciplines', 'POST', { name, hours }, true /* requiresAuth */, true /* requiresAdmin */); if (response && response.ok) { document.getElementById('discipline-name').value = ''; document.getElementById('discipline-hours').value = ''; await loadDisciplines(); // Обновляем список управления await loadDisciplinesForFilters(); // Обновляем фильтр в просмотре await loadDisciplinesForForm(); // Обновляем форму в управлении расписанием // Обновляем все вкладки если они активны if (document.getElementById('schedule-view').classList.contains('active')) { loadSchedule(); // Обновляем отображение расписания } if (document.getElementById('schedule-management').classList.contains('active')) { populateDropdowns(); // Обновляем выпадающие списки } alert('Дисциплина успешно добавлена!'); } else if (response) { const data = await response.json(); alert('Не удалось добавить дисциплину: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при добавлении дисциплины: ' + error.message); } } async function addRoom() { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } const name = document.getElementById('room-name').value.trim(); const building = document.getElementById('room-building').value.trim(); const capacity = parseInt(document.getElementById('room-capacity').value); if (!name) { alert('Пожалуйста, введите название аудитории.'); return; } if (isNaN(capacity) || capacity < 1) { alert('Пожалуйста, введите корректную вместимость.'); return; } try { const response = await apiCall('/api/lab10/task2/rooms', 'POST', { name, building, capacity }, true /* requiresAuth */, true /* requiresAdmin */); if (response && response.ok) { document.getElementById('room-name').value = ''; document.getElementById('room-building').value = ''; document.getElementById('room-capacity').value = ''; await loadRooms(); // Обновляем список управления await loadRoomsForFilters(); // Обновляем фильтр в просмотре await loadRoomsForForm(); // Обновляем форму в управлении расписанием // Обновляем все вкладки если они активны if (document.getElementById('schedule-view').classList.contains('active')) { loadSchedule(); // Обновляем отображение расписания } if (document.getElementById('schedule-management').classList.contains('active')) { populateDropdowns(); // Обновляем выпадающие списки } alert('Аудитория успешно добавлена!'); } else if (response) { const data = await response.json(); alert('Не удалось добавить аудиторию: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при добавлении аудитории: ' + error.message); } } function showError(containerId, message) { const container = document.getElementById(containerId); if (container) { container.innerHTML = `<div class="error">${message}</div>`; } else { console.error(`Элемент с ID '${containerId}' не найден. Ошибка: ${message}`); } } function showLoading(containerId) { const container = document.getElementById(containerId); if (container) { // Убедимся, что контейнер очищен перед вставкой сообщения о загрузке container.innerHTML = ''; const loadingDiv = document.createElement('div'); loadingDiv.className = 'loading'; loadingDiv.textContent = 'Загрузка...'; container.appendChild(loadingDiv); } else { console.error(`Элемент с ID '${containerId}' не найден.`); } } function populateCategoryFilter(categories) { const select = document.getElementById('category-filter'); select.innerHTML = '<option value="">Все категории</option>'; categories.forEach(cat => { const option = document.createElement('option'); option.value = cat.id; option.textContent = cat.name; select.appendChild(option); }); } function populateCategoryForForm(categories) { const select = document.getElementById('product-category-id'); select.innerHTML = '<option value="">Без категории</option>'; categories.forEach(cat => { const option = document.createElement('option'); option.value = cat.id; option.textContent = cat.name; select.appendChild(option); }); } function populateCategoryForFormModal(categories) { const select = document.getElementById('edit-product-category-id'); if (select) { // Проверяем, существует ли элемент select.innerHTML = '<option value="">Без категории</option>'; categories.forEach(cat => { const option = document.createElement('option'); option.value = cat.id; option.textContent = cat.name; select.appendChild(option); }); } } function populateSelect(elementId, data, valueField, textField, defaultOption) { const select = document.getElementById(elementId); if (select) { select.innerHTML = `<option value="">${defaultOption}</option>`; data.forEach(item => { const option = document.createElement('option'); option.value = item[valueField]; option.textContent = item[textField]; select.appendChild(option); }); } } // Функции для заполнения выпадающих списков в форме управления расписанием async function populateDropdowns() { await Promise.all([ loadGroupsForForm(), loadTeachersForForm(), loadDisciplinesForForm(), loadRoomsForForm() ]); } async function loadGroupsForForm() { try { const response = await apiCall('/api/lab10/task2/groups', 'GET', null, true, true); if (response && response.ok) { const groups = await response.json(); allGroups = groups; // Сохраняем в глобальную переменную populateSelect('schedule-group-id', groups, 'id', 'name', 'Выберите группу'); } else if (response) { // Ошибка будет обработана в apiCall } } catch (error) { console.error('Ошибка при загрузке групп для формы:', error); populateSelect('schedule-group-id', [], 'id', 'name', 'Выберите группу'); } } async function loadTeachersForForm() { try { const response = await apiCall('/api/lab10/task2/teachers', 'GET', null, true, true); if (response && response.ok) { const teachers = await response.json(); // ПРАВИЛЬНО сохраняем данные с полными полями allTeachers = teachers.map(teacher => ({ id: teacher.id, full_name: teacher.full_name || teacher.fullName || 'Неизвестно', position: teacher.position || 'Не указано', department: teacher.department || 'Не указано' })); populateSelect('schedule-teacher-id', allTeachers, 'id', 'full_name', 'Выберите преподавателя'); } else if (response) { // Обработка ошибок } } catch (error) { console.error('Ошибка при загрузке преподавателей для формы:', error); populateSelect('schedule-teacher-id', [], 'id', 'full_name', 'Выберите преподавателя'); } } // Аналогично исправьте другие функции загрузки справочников: async function loadDisciplinesForForm() { try { const response = await apiCall('/api/lab10/task2/disciplines', 'GET', null, true, true); if (response && response.ok) { const disciplines = await response.json(); allDisciplines = disciplines.map(discipline => ({ id: discipline.id, name: discipline.name || 'Неизвестно', hours: discipline.hours || 'Не указано' })); populateSelect('schedule-discipline-id', allDisciplines, 'id', 'name', 'Выберите дисциплину'); } } catch (error) { console.error('Ошибка при загрузке дисциплин для формы:', error); populateSelect('schedule-discipline-id', [], 'id', 'name', 'Выберите дисциплину'); } } async function loadRoomsForForm() { try { const response = await apiCall('/api/lab10/task2/rooms', 'GET', null, true, true); if (response && response.ok) { const rooms = await response.json(); allRooms = rooms.map(room => ({ id: room.id, name: room.name || 'Неизвестно', building: room.building || 'Не указано', capacity: room.capacity || 'Не указано' })); populateSelect('schedule-room-id', allRooms, 'id', 'name', 'Выберите аудиторию'); } } catch (error) { console.error('Ошибка при загрузке аудиторий для формы:', error); populateSelect('schedule-room-id', [], 'id', 'name', 'Выберите аудиторию'); } } // Функции загрузки списков для управления (только админ) async function loadGroups() { if (currentUser && currentUser.role === 'admin') { showLoading('groups-list'); try { const response = await apiCall('/api/lab10/task2/groups', 'GET', null, true, true); if (response && response.ok) { const groups = await response.json(); displayGroups(groups); } else if (response) { // Ошибка будет обработана в apiCall } } catch (error) { showError('groups-list', 'Ошибка при загрузке групп: ' + error.message); } } } async function loadTeachers() { if (currentUser && currentUser.role === 'admin') { showLoading('teachers-list'); try { const response = await apiCall('/api/lab10/task2/teachers', 'GET', null, true, true); if (response && response.ok) { const teachers = await response.json(); displayTeachers(teachers); } else if (response) { // Ошибка будет обработана в apiCall } } catch (error) { showError('teachers-list', 'Ошибка при загрузке преподавателей: ' + error.message); } } } async function loadDisciplines() { if (currentUser && currentUser.role === 'admin') { showLoading('disciplines-list'); try { const response = await apiCall('/api/lab10/task2/disciplines', 'GET', null, true, true); if (response && response.ok) { const disciplines = await response.json(); displayDisciplines(disciplines); } else if (response) { // Ошибка будет обработана в apiCall } } catch (error) { showError('disciplines-list', 'Ошибка при загрузке дисциплин: ' + error.message); } } } async function loadRooms() { if (currentUser && currentUser.role === 'admin') { showLoading('rooms-list'); try { const response = await apiCall('/api/lab10/task2/rooms', 'GET', null, true, true); if (response && response.ok) { const rooms = await response.json(); displayRooms(rooms); } else if (response) { // Ошибка будет обработана в apiCall } } catch (error) { showError('rooms-list', 'Ошибка при загрузке аудиторий: ' + error.message); } } } async function loadScheduleRecords() { if (currentUser && currentUser.role === 'admin') { showLoading('schedule-records-list'); try { // Загружаем справочники для отображения имен await Promise.all([ loadGroupsForForm(), loadTeachersForForm(), loadDisciplinesForForm(), loadRoomsForForm() ]); // Теперь загружаем записи расписания const response = await apiCall('/api/lab10/task2/schedule', 'GET', null, true, true); if (response && response.ok) { const records = await response.json(); displayScheduleRecords(records); } else if (response) { const errorData = await response.json(); showError('schedule-records-list', 'Ошибка при загрузке расписания: ' + (errorData.error || 'Неизвестная ошибка')); } } catch (error) { showError('schedule-records-list', 'Ошибка при загрузке расписания: ' + error.message); } } } function displayProducts(products) { const container = document.getElementById('products-container'); if (products.length === 0) { container.innerHTML = '<p>Товары не найдены.</p>'; return; } let html = ''; products.forEach(product => { html += ` <div class="product-card"> <img src="${product.image || 'placeholder.jpg'}" alt="${product.title}"> <h3>${product.title}</h3> <p class="price">Цена: ${product.price} руб.</p> <p class="amount">Количество: ${product.amount}</p> <p>Категория: ${product.category_title || 'Без категории'}</p> <button class="btn" onclick="showProductDetails(${product.id})">Подробнее</button> <button class="btn" onclick="buySingleItem(${product.id})">Купить</button> </div> `; }); container.innerHTML = html; } // --- ИСПРАВЛЕНО: Улучшенная функция отображения товаров для управления --- function displayProductsForManagement(products) { const container = document.getElementById('products-list'); if (products.length === 0) { container.innerHTML = '<p>Товары не найдены.</p>'; return; } let html = '<table><tr><th>ID</th><th>Название</th><th>Цена</th><th>Количество</th><th>Категория</th><th>Действия</th></tr>'; products.forEach(product => { html += ` <tr> <td>${product.id}</td> <td>${product.title}</td> <td>${product.price}</td> <td>${product.amount}</td> <td>${product.category_title || 'Без категории'}</td> <td> <button class="btn" onclick="editProduct(${product.id})">Редактировать</button> <button class="btn" onclick="deleteProduct(${product.id})">Удалить</button> </td> </tr> `; }); html += '</table>'; container.innerHTML = html; } // --- ИСПРАВЛЕНО: Улучшенная функция отображения групп --- function displayGroups(groups) { const container = document.getElementById('groups-list'); if (groups.length === 0) { container.innerHTML = '<p>Группы не найдены.</p>'; return; } let html = '<table><tr><th>ID</th><th>Название</th><th>Действия</th></tr>'; groups.forEach(group => { html += ` <tr> <td>${group.id}</td> <td>${group.name}</td> <td> <button class="btn" onclick="editGroup(${group.id})">Редактировать</button> <button class="btn" onclick="deleteGroup(${group.id})">Удалить</button> </td> </tr> `; }); html += '</table>'; container.innerHTML = html; } // --- ИСПРАВЛЕННЫЕ ФУНКЦИИ отображения для управления --- function displayTeachers(teachers) { const container = document.getElementById('teachers-list'); if (teachers.length === 0) { container.innerHTML = '<p>Преподаватели не найдены.</p>'; return; } let html = '<table class="schedule-records-table"><tr><th>ID</th><th>ФИО</th><th>Должность</th><th>Кафедра</th><th>Действия</th></tr>'; teachers.forEach(teacher => { html += ` <tr> <td>${teacher.id}</td> <td>${teacher.full_name || 'Не указано'}</td> <td>${teacher.position || 'Не указано'}</td> <td>${teacher.department || 'Не указано'}</td> <td> <button class="btn" onclick="editTeacher(${teacher.id})">Редактировать</button> <button class="btn" onclick="deleteTeacher(${teacher.id})">Удалить</button> </td> </tr> `; }); html += '</table>'; container.innerHTML = html; } function displayDisciplines(disciplines) { const container = document.getElementById('disciplines-list'); if (disciplines.length === 0) { container.innerHTML = '<p>Дисциплины не найдены.</p>'; return; } let html = '<table class="schedule-records-table"><tr><th>ID</th><th>Название</th><th>Часы</th><th>Действия</th></tr>'; disciplines.forEach(discipline => { html += ` <tr> <td>${discipline.id}</td> <td>${discipline.name || 'Не указано'}</td> <td>${discipline.hours || 'Не указано'}</td> <td> <button class="btn" onclick="editDiscipline(${discipline.id})">Редактировать</button> <button class="btn" onclick="deleteDiscipline(${discipline.id})">Удалить</button> </td> </tr> `; }); html += '</table>'; container.innerHTML = html; } function displayRooms(rooms) { const container = document.getElementById('rooms-list'); if (rooms.length === 0) { container.innerHTML = '<p>Аудитории не найдены.</p>'; return; } let html = '<table class="schedule-records-table"><tr><th>ID</th><th>Название</th><th>Корпус</th><th>Вместимость</th><th>Действия</th></tr>'; rooms.forEach(room => { html += ` <tr> <td>${room.id}</td> <td>${room.name || 'Не указано'}</td> <td>${room.building || 'Не указано'}</td> <td>${room.capacity || 'Не указано'}</td> <td> <button class="btn" onclick="editRoom(${room.id})">Редактировать</button> <button class="btn" onclick="deleteRoom(${room.id})">Удалить</button> </td> </tr> `; }); html += '</table>'; container.innerHTML = html; } function displayScheduleRecords(records) { const container = document.getElementById('schedule-records-list'); if (records.length === 0) { container.innerHTML = '<p>Записей в расписании не найдено.</p>'; return; } // Сортируем записи по неделе, дню недели и времени records.sort((a, b) => { if (a.week_number !== b.week_number) return a.week_number - b.week_number; if (a.day_of_week !== b.day_of_week) return a.day_of_week - b.day_of_week; if (a.start_time !== b.start_time) return a.start_time.localeCompare(b.start_time); return a.id - b.id; }); let tableHtml = ` <table class="schedule-records-table"> <thead> <tr> <th>ID</th> <th>Неделя</th> <th>День</th> <th>Время</th> <th>Группа</th> <th>Преподаватель</th> <th>Дисциплина</th> <th>Аудитория</th> <th>Тип</th> <th>Действия</th> </tr> </thead> <tbody> `; records.forEach(record => { const dayName = getDayName(record.day_of_week); // ВАЖНО: Используем данные из record напрямую, а не из глобальных массивов // В record уже должны быть поля из JOIN: group_name, teacher_name, discipline_name, room_name const groupName = record.group_name || `Неизвестная группа`; const teacherName = record.teacher_name || `Неизвестный преподаватель`; const disciplineName = record.discipline_name || `Неизвестная дисциплина`; const roomName = record.room_name || `Неизвестная аудитория`; // Тип занятия const lessonType = record.lesson_type || record.type || 'Неизвестный тип'; tableHtml += ` <tr> <td>${record.id}</td> <td>${record.week_number}</td> <td>${dayName}</td> <td>${record.start_time} - ${record.end_time}</td> <td>${groupName}</td> <td>${teacherName}</td> <td>${disciplineName}</td> <td>${roomName}</td> <td>${lessonType}</td> <td> <button class="btn" onclick="editScheduleRecord(${record.id})">Редактировать</button> <button class="btn" onclick="deleteScheduleRecord(${record.id})">Удалить</button> </td> </tr> `; }); tableHtml += ` </tbody> </table> `; container.innerHTML = tableHtml; } // --- ИСПРАВЛЕНО: Добавлена функция для отображения корзины --- function updateCartDisplay() { const cartItemsContainer = document.getElementById('cart-items'); const cartTotalElement = document.getElementById('cart-total'); if (cart.length === 0) { cartItemsContainer.innerHTML = '<p>Корзина пуста.</p>'; cartTotalElement.textContent = 'Итого: 0 руб.'; return; } let html = '<ul>'; let total = 0; for (const item of cart) { // Находим товар в allProducts по id const product = allProducts.find(p => p.id === item.productId); if (product) { const itemTotal = product.price * item.quantity; total += itemTotal; html += ` <li> ${product.title} - ${item.quantity} шт. x ${product.price} руб. = ${itemTotal} руб. <button class="btn" onclick="removeFromCart(${item.productId})">Удалить</button> </li> `; } else { // Если товар не найден, просто показываем ID и количество html += ` <li> Товар ID: ${item.productId} - ${item.quantity} шт. (информация недоступна) <button class="btn" onclick="removeFromCart(${item.productId})">Удалить</button> </li> `; } } html += '</ul>'; cartItemsContainer.innerHTML = html; cartTotalElement.textContent = `Итого: ${total} руб.`; } // --- ИСПРАВЛЕНО: Добавлена функция для открытия модального окна корзины --- function showCartModal() { updateCartDisplay(); // Обновляем отображение корзины перед открытием document.getElementById('cart-modal').style.display = 'block'; } // --- ИСПРАВЛЕНО: Добавлена функция для удаления товара из корзины --- function removeFromCart(productId) { const index = cart.findIndex(item => item.productId === productId); if (index !== -1) { cart.splice(index, 1); updateCartCountBadge(); updateCartDisplay(); // Обновляем отображение } } // --- ИСПРАВЛЕНО: Добавлена функция для закрытия модального окна корзины --- function closeCartModal() { document.getElementById('cart-modal').style.display = 'none'; } function addToCart(productId, quantity = 1) { if (!authToken) { alert('Сначала войдите в систему.'); goToAuth(); return; } const existingItem = cart.find(item => item.productId === productId); if (existingItem) { existingItem.quantity += quantity; } else { cart.push({ productId, quantity }); } updateCartCountBadge(); // Обновляем отображение корзины, если она открыта if (document.getElementById('cart-modal').style.display === 'block') { updateCartDisplay(); } } function updateCartCountBadge() { const count = cart.reduce((sum, item) => sum + item.quantity, 0); // В этом упрощенном примере мы не добавляем бейдж на кнопку корзины // В реальном приложении это делается отдельно console.log('Товаров в корзине:', count); } function showProductDetails(productId) { // Открываем модальное окно с подробной информацией о товаре // Загружаем данные через API fetch(`/api/lab10/task1/product/${productId}`) .then(response => response.json()) .then(product => { if (product) { document.getElementById('modal-product-title').textContent = product.title; document.getElementById('modal-product-image').src = product.image || 'placeholder.jpg'; document.getElementById('modal-product-description').textContent = product.description || 'Описание отсутствует'; document.getElementById('modal-product-price').textContent = `Цена: ${product.price} руб.`; document.getElementById('modal-product-amount').textContent = `Количество: ${product.amount}`; document.getElementById('modal-product-category').textContent = `Категория: ${product.category_title || 'Без категории'}`; currentProductDetails = product; document.getElementById('product-modal').style.display = 'block'; } }) .catch(error => console.error('Ошибка при загрузке деталей товара:', error)); } function closeProductModal() { document.getElementById('product-modal').style.display = 'none'; currentProductDetails = null; } function addToCartFromModal() { if (currentProductDetails) { addToCart(currentProductDetails.id, 1); closeProductModal(); } } async function buySingleItem(productId) { if (!authToken) { alert('Сначала войдите в систему.'); goToAuth(); return; } if (!confirm('Вы уверены, что хотите купить этот товар?')) { return; } try { const response = await apiCall(`/api/lab10/products/${productId}/buy`, 'POST', { quantity: 1 }, true /* requiresAuth */); if (response && response.ok) { const data = await response.json(); alert(`Покупка успешна! ID заказа: ${data.orderId}`); // Обновим список товаров await loadAllProducts(); filterProducts(); // Применяем текущую фильтрацию } else if (response) { const errorData = await response.json(); alert('Ошибка при покупке: ' + (errorData.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при оформлении покупки: ' + error.message); } } async function checkoutCart() { if (!authToken) { alert('Сначала войдите в систему.'); goToAuth(); return; } if (cart.length === 0) { alert('Корзина пуста.'); return; } if (!confirm('Вы уверены, что хотите оформить заказ?')) { return; } try { for (const cartItem of cart) { const response = await apiCall(`/api/lab10/products/${cartItem.productId}/buy`, 'POST', { quantity: cartItem.quantity }, true /* requiresAuth */); if (!response || !response.ok) { const errorData = await response.json(); throw new Error(errorData.error || `Ошибка покупки товара с ID ${cartItem.productId}`); } } alert('Покупка успешно оформлена!'); cart = []; // Очищаем корзину updateCartCountBadge(); closeCartModal(); // Обновим список товаров в магазине await loadAllProducts(); filterProducts(); // Применяем фильтрацию } catch (error) { alert('Ошибка при оформлении заказа: ' + error.message); } } // --- Функции фильтрации --- function filterProducts() { const searchTerm = document.getElementById('search-input').value.toLowerCase(); const categoryId = document.getElementById('category-filter').value; const filtered = allProducts.filter(product => { const matchesSearch = product.title.toLowerCase().includes(searchTerm); const matchesCategory = !categoryId || product.category_id == categoryId; return matchesSearch && matchesCategory; }); displayProducts(filtered); } // --- Функции редактирования --- // Функция для открытия модального окна редактирования товара async function editProduct(productId) { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } try { const response = await fetch(`/api/lab10/task1/product/${productId}`); const product = await response.json(); if (response.ok && product) { // Заполняем поля модального окна document.getElementById('edit-product-id').value = product.id; document.getElementById('edit-product-title').value = product.title; document.getElementById('edit-product-price').value = product.price; document.getElementById('edit-product-amount').value = product.amount; document.getElementById('edit-product-category-id').value = product.category_id || ''; document.getElementById('edit-product-image').value = product.image || ''; document.getElementById('edit-product-description').value = product.description || ''; // Показываем модальное окно document.getElementById('editProductModal').style.display = 'block'; } else { alert('Товар не найден или произошла ошибка: ' + (product.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при загрузке данных товара для редактирования: ' + error.message); } } // Функция для сохранения изменений товара async function saveProductEdit() { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } const id = document.getElementById('edit-product-id').value; const title = document.getElementById('edit-product-title').value.trim(); const price = parseFloat(document.getElementById('edit-product-price').value); const amount = parseInt(document.getElementById('edit-product-amount').value); const categoryId = document.getElementById('edit-product-category-id').value || null; const image = document.getElementById('edit-product-image').value.trim(); const description = document.getElementById('edit-product-description').value; if (!title || isNaN(price) || isNaN(amount) || price < 0 || amount < 0) { alert('Пожалуйста, заполните все поля корректно. Цена и количество должны быть числами >= 0.'); return; } try { const response = await apiCall(`/api/lab10/task1/products/${id}`, 'PUT', { title, price, amount, category_id: categoryId, image, description }, true /* requiresAuth */, true /* requiresAdmin */); if (response && response.ok) { const data = await response.json(); closeEditModal(); await loadProductsForManagement(); // Обновляем список управления await loadAllProducts(); // Обновляем список для просмотра filterProducts(); // Применяем фильтрацию } else if (response) { const data = await response.json(); alert('Не удалось сохранить изменения: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при сохранении изменений: ' + error.message); } } // Функция для закрытия модального окна редактирования function closeEditModal() { document.getElementById('editProductModal').style.display = 'none'; } // --- Функции удаления --- async function deleteProduct(id) { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } if (!confirm('Вы уверены, что хотите удалить этот товар?')) { return; } try { const response = await apiCall(`/api/lab10/task1/products/${id}`, 'DELETE', null, true, true); if (response && response.ok) { await loadProductsForManagement(); // Обновляем список управления await loadAllProducts(); // Обновляем список для просмотра filterProducts(); // Применяем фильтрацию } else if (response) { const data = await response.json(); alert('Не удалось удалить товар: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при удалении товара: ' + error.message); } } async function deleteCategory(id) { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } if (!confirm('Вы уверены, что хотите удалить эту категорию? Все товары в этой категории и связанные с ними заказы будут удалены.')) { return; } try { const response = await apiCall(`/api/lab10/task1/categories/${id}`, 'DELETE', null, true, true); if (response && response.ok) { await loadCategoriesForManagement(); // Обновляем список и форму await loadCategoriesForFilters(); // Обновляем фильтр в просмотре await loadAllProducts(); // Перезагрузим товары, так как могли измениться связи filterProducts(); } else if (response) { const data = await response.json(); alert('Не удалось удалить категорию: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при удалении категории: ' + error.message); } } async function deleteScheduleRecord(id) { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } if (!confirm('Вы уверены, что хотите удалить эту запись?')) { return; } try { const response = await apiCall(`/api/lab10/task2/schedule/${id}`, 'DELETE', null, true, true); if (response && response.ok) { await loadScheduleRecords(); // Обновляем список управления расписанием if (document.getElementById('schedule-view').classList.contains('active')) { loadSchedule(); // Обновляем отображение расписания } alert('Запись успешно удалена!'); } else if (response) { const data = await response.json(); alert('Не удалось удалить запись: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при удалении записи: ' + error.message); } } async function deleteGroup(id) { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } if (!confirm('Вы уверены, что хотите удалить эту группу?')) { return; } try { const response = await apiCall(`/api/lab10/task2/groups/${id}`, 'DELETE', null, true, true); if (response && response.ok) { await loadGroups(); // Обновляем список управления await loadGroupsForFilters(); // Обновляем фильтр в просмотре await loadGroupsForForm(); // Обновляем форму в управлении расписанием // Обновляем все вкладки если они активны if (document.getElementById('schedule-view').classList.contains('active')) { loadSchedule(); // Обновляем отображение расписания } if (document.getElementById('schedule-management').classList.contains('active')) { populateDropdowns(); // Обновляем выпадающие списки } alert('Группа успешно удалена!'); } else if (response) { const data = await response.json(); alert('Не удалось удалить группу: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при удалении группы: ' + error.message); } } async function deleteTeacher(id) { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } if (!confirm('Вы уверены, что хотите удалить этого преподавателя?')) { return; } try { const response = await apiCall(`/api/lab10/task2/teachers/${id}`, 'DELETE', null, true, true); if (response && response.ok) { await loadTeachers(); // Обновляем список управления await loadTeachersForFilters(); // Обновляем фильтр в просмотре await loadTeachersForForm(); // Обновляем форму в управлении расписанием // Обновляем все вкладки если они активны if (document.getElementById('schedule-view').classList.contains('active')) { loadSchedule(); // Обновляем отображение расписания } if (document.getElementById('schedule-management').classList.contains('active')) { populateDropdowns(); // Обновляем выпадающие списки } alert('Преподаватель успешно удален!'); } else if (response) { const data = await response.json(); alert('Не удалось удалить преподавателя: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при удалении преподавателя: ' + error.message); } } async function deleteDiscipline(id) { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } if (!confirm('Вы уверены, что хотите удалить эту дисциплину?')) { return; } try { const response = await apiCall(`/api/lab10/task2/disciplines/${id}`, 'DELETE', null, true, true); if (response && response.ok) { await loadDisciplines(); // Обновляем список управления await loadDisciplinesForFilters(); // Обновляем фильтр в просмотре await loadDisciplinesForForm(); // Обновляем форму в управлении расписанием // Обновляем все вкладки если они активны if (document.getElementById('schedule-view').classList.contains('active')) { loadSchedule(); // Обновляем отображение расписания } if (document.getElementById('schedule-management').classList.contains('active')) { populateDropdowns(); // Обновляем выпадающие списки } alert('Дисциплина успешно удалена!'); } else if (response) { const data = await response.json(); alert('Не удалось удалить дисциплину: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при удалении дисциплины: ' + error.message); } } async function deleteRoom(id) { if (!(currentUser && currentUser.role === 'admin')) { alert('Доступ запрещен.'); return; } if (!confirm('Вы уверены, что хотите удалить эту аудиторию?')) { return; } try { const response = await apiCall(`/api/lab10/task2/rooms/${id}`, 'DELETE', null, true, true); if (response && response.ok) { await loadRooms(); // Обновляем список управления await loadRoomsForFilters(); // Обновляем фильтр в просмотре await loadRoomsForForm(); // Обновляем форму в управлении расписанием // Обновляем все вкладки если они активны if (document.getElementById('schedule-view').classList.contains('active')) { loadSchedule(); // Обновляем отображение расписания } if (document.getElementById('schedule-management').classList.contains('active')) { populateDropdowns(); // Обновляем выпадающие списки } alert('Аудитория успешно удалена!'); } else if (response) { const data = await response.json(); alert('Не удалось удалить аудиторию: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка при удалении аудитории: ' + error.message); } } // --- Инициализация --- document.addEventListener('DOMContentLoaded', function() { checkAuthAndLoad(); // Проверяем аутентификацию при загрузке showContent('store'); // Показываем вкладку магазина по умолчанию }); // --- Заглушка для функций редактирования --- // В реальном приложении здесь были бы вызовы apiCall с методами PUT/DELETE async function editCategory(categoryId) { alert('Редактирование категории с ID: ' + categoryId + '. В реальном приложении здесь была бы форма для редактирования.'); } async function editScheduleRecord(recordId) { alert('Редактирование записи расписания с ID: ' + recordId + '. В реальном приложении здесь была бы форма для редактирования.'); } async function editGroup(groupId) { alert('Редактирование группы с ID: ' + groupId + '. В реальном приложении здесь была бы форма для редактирования.'); } async function editTeacher(teacherId) { alert('Редактирование преподавателя с ID: ' + teacherId + '. В реальном приложении здесь была бы форма для редактирования.'); } async function editDiscipline(disciplineId) { alert('Редактирование дисциплины с ID: ' + disciplineId + '. В реальном приложении здесь была бы форма для редактирования.'); } async function editRoom(roomId) { alert('Редактирование аудитории с ID: ' + roomId + '. В реальном приложении здесь была бы форма для редактирования.'); }