import { api } from '../api.js'; import { escapeHtml, showAlert, hideAlert } from '../utils.js'; export async function initUniversityStructure() { const deptTbody = document.getElementById('departments-tbody'); const specTbody = document.getElementById('specialties-tbody'); const createDeptForm = document.getElementById('create-department-form'); const createSpecForm = document.getElementById('create-specialty-form'); const editDeptForm = document.getElementById('edit-department-form'); const editSpecForm = document.getElementById('edit-specialty-form'); const editDeptModal = document.getElementById('modal-edit-department'); const editSpecModal = document.getElementById('modal-edit-specialty'); const editDeptClose = document.getElementById('modal-edit-department-close'); const editSpecClose = document.getElementById('modal-edit-specialty-close'); // Элементы вкладок const tabDepartments = document.getElementById('btn-tab-departments'); const tabSpecialties = document.getElementById('btn-tab-specialties'); const tabProfiles = document.getElementById('btn-tab-profiles'); const contentDepartments = document.getElementById('tab-content-departments'); const contentSpecialties = document.getElementById('tab-content-specialties'); const contentProfiles = document.getElementById('tab-content-profiles'); // Элементы модалки профилей const profilesModal = document.getElementById('modal-manage-profiles'); const profilesModalClose = document.getElementById('modal-manage-profiles-close'); const profilesSpecContext = document.getElementById('profiles-spec-context'); const profileFormTitle = document.getElementById('profile-form-title'); const manageProfileForm = document.getElementById('manage-profile-form'); const profileIdInput = document.getElementById('manage-profile-id'); const profileSpecIdInput = document.getElementById('manage-profile-spec-id'); const profileNameInput = document.getElementById('manage-profile-name'); const profileDescInput = document.getElementById('manage-profile-description'); const btnSaveProfile = document.getElementById('btn-save-profile'); const btnCancelProfileEdit = document.getElementById('btn-cancel-profile-edit'); const profilesTbody = document.getElementById('manage-profiles-tbody'); // Элементы вкладки Профилей const tabProfileTbody = document.getElementById('profiles-tbody'); const createProfileTabForm = document.getElementById('create-profile-tab-form'); const tabProfileIdInput = document.getElementById('tab-profile-id'); const tabProfileSpecSelect = document.getElementById('tab-profile-spec'); const tabProfileNameInput = document.getElementById('tab-profile-name'); const tabProfileDescInput = document.getElementById('tab-profile-description'); const mainProfileFormTitle = document.getElementById('main-profile-form-title'); const btnTabSaveProfile = document.getElementById('btn-tab-save-profile'); const btnTabCancelProfileEdit = document.getElementById('btn-tab-cancel-profile-edit'); let departments = []; let specialties = []; let currentProfiles = []; let allProfiles = []; // --- Логика переключения табов --- const structureTabs = [ { button: tabDepartments, panel: contentDepartments }, { button: tabSpecialties, panel: contentSpecialties }, { button: tabProfiles, panel: contentProfiles }, ]; function activateStructureTab(activeButton) { structureTabs.forEach(({ button, panel }) => { const active = button === activeButton; button?.classList.toggle('active', active); button?.setAttribute('aria-selected', active ? 'true' : 'false'); if (panel) { panel.classList.toggle('active', active); panel.hidden = !active; } }); } structureTabs.forEach(({ button }) => { button?.addEventListener('click', () => activateStructureTab(button)); }); // --- Загрузка данных --- async function loadData() { // Загрузка кафедр try { departments = await api.get('/api/departments'); renderDepartments(); } catch (e) { deptTbody.innerHTML = 'Ошибка загрузки'; } // Загрузка специальностей try { specialties = await api.get('/api/specialties'); renderSpecialties(); populateSpecialtiesDropdown(); } catch (e) { specTbody.innerHTML = 'Ошибка загрузки'; } // Загрузка всех профилей try { allProfiles = await api.get('/api/specialties/profiles'); renderAllProfiles(); } catch (e) { tabProfileTbody.innerHTML = 'Ошибка загрузки'; } } function renderDepartments() { if (!departments || !departments.length) { deptTbody.innerHTML = 'Кафедры не созданы'; return; } deptTbody.innerHTML = departments.map(d => ` ${d.id} ${escapeHtml(d.departmentName || d.name)} ${escapeHtml(String(d.departmentCode || d.code))} `).join(''); } function renderSpecialties() { if (!specialties || !specialties.length) { specTbody.innerHTML = 'Специальности не созданы'; return; } specTbody.innerHTML = specialties.map(s => ` ${s.id} ${escapeHtml(s.specialityName || s.name)} ${escapeHtml(s.specialityCode || s.specialtyCode || s.specialty_code)} `).join(''); } // --- Кафедры: CRUD --- createDeptForm.addEventListener('submit', async (e) => { e.preventDefault(); hideAlert('create-dept-alert'); const name = document.getElementById('dept-name').value.trim(); const code = document.getElementById('dept-code').value.trim(); if (!name || !code) { showAlert('create-dept-alert', 'Заполните все поля', 'error'); return; } try { await api.post('/api/departments', { departmentName: name, departmentCode: Number(code) }); showAlert('create-dept-alert', `Кафедра "${name}" создана`, 'success'); createDeptForm.reset(); loadData(); } catch (error) { showAlert('create-dept-alert', error.message || 'Ошибка создания кафедры', 'error'); } }); deptTbody.addEventListener('click', async (e) => { const editBtn = e.target.closest('.btn-edit-department'); const deleteBtn = e.target.closest('.btn-delete-department'); if (editBtn) { const department = departments.find(item => item.id == editBtn.dataset.id); if (!department) return; document.getElementById('edit-dept-id').value = department.id; document.getElementById('edit-dept-name').value = department.departmentName || department.name || ''; document.getElementById('edit-dept-code').value = department.departmentCode || department.code || ''; hideAlert('edit-dept-alert'); editDeptModal.classList.add('open'); return; } if (deleteBtn) { if (!confirm('Удалить кафедру?')) return; try { await api.delete('/api/departments/' + deleteBtn.dataset.id); showAlert('create-dept-alert', 'Кафедра удалена', 'success'); await loadData(); } catch (error) { showAlert('create-dept-alert', error.message || 'Ошибка удаления кафедры', 'error'); } } }); editDeptForm.addEventListener('submit', async (e) => { e.preventDefault(); hideAlert('edit-dept-alert'); const id = document.getElementById('edit-dept-id').value; const name = document.getElementById('edit-dept-name').value.trim(); const code = document.getElementById('edit-dept-code').value.trim(); if (!name || !code) { showAlert('edit-dept-alert', 'Заполните все поля', 'error'); return; } try { await api.put('/api/departments/' + id, { departmentName: name, departmentCode: Number(code) }); editDeptModal.classList.remove('open'); showAlert('create-dept-alert', `Кафедра "${name}" обновлена`, 'success'); await loadData(); } catch (error) { showAlert('edit-dept-alert', error.message || 'Ошибка обновления кафедры', 'error'); } }); // --- Специальности: CRUD --- createSpecForm.addEventListener('submit', async (e) => { e.preventDefault(); hideAlert('create-spec-alert'); const name = document.getElementById('spec-name').value.trim(); const code = document.getElementById('spec-code').value.trim(); if (!name || !code) { showAlert('create-spec-alert', 'Заполните все поля', 'error'); return; } try { await api.post('/api/specialties', { specialityName: name, specialityCode: code }); showAlert('create-spec-alert', `Специальность "${name}" создана`, 'success'); createSpecForm.reset(); loadData(); } catch (error) { showAlert('create-spec-alert', error.message || 'Ошибка создания специальности', 'error'); } }); specTbody.addEventListener('click', async (e) => { const editBtn = e.target.closest('.btn-edit-specialty'); const deleteBtn = e.target.closest('.btn-delete-specialty'); const profilesBtn = e.target.closest('.btn-manage-profiles'); if (editBtn) { const speciality = specialties.find(item => item.id == editBtn.dataset.id); if (!speciality) return; document.getElementById('edit-spec-id').value = speciality.id; document.getElementById('edit-spec-name').value = speciality.specialityName || speciality.name || ''; document.getElementById('edit-spec-code').value = speciality.specialityCode || speciality.specialtyCode || speciality.specialty_code || ''; hideAlert('edit-spec-alert'); editSpecModal.classList.add('open'); return; } if (deleteBtn) { if (!confirm('Удалить специальность?')) return; try { await api.delete('/api/specialties/' + deleteBtn.dataset.id); showAlert('create-spec-alert', 'Специальность удалена', 'success'); await loadData(); } catch (error) { showAlert('create-spec-alert', error.message || 'Ошибка удаления специальности', 'error'); } } if (profilesBtn) { const specId = profilesBtn.dataset.id; const speciality = specialties.find(item => item.id == specId); if (!speciality) return; openProfilesModal(speciality); } }); editSpecForm.addEventListener('submit', async (e) => { e.preventDefault(); hideAlert('edit-spec-alert'); const id = document.getElementById('edit-spec-id').value; const name = document.getElementById('edit-spec-name').value.trim(); const code = document.getElementById('edit-spec-code').value.trim(); if (!name || !code) { showAlert('edit-spec-alert', 'Заполните все поля', 'error'); return; } try { await api.put('/api/specialties/' + id, { specialityName: name, specialityCode: code }); editSpecModal.classList.remove('open'); showAlert('create-spec-alert', `Специальность "${name}" обновлена`, 'success'); await loadData(); } catch (error) { showAlert('edit-spec-alert', error.message || 'Ошибка обновления специальности', 'error'); } }); // --- Профили обучения: Логика --- async function openProfilesModal(speciality) { profilesSpecContext.textContent = `${speciality.specialityCode || speciality.specialtyCode || speciality.specialty_code} · ${speciality.specialityName || speciality.name}`; profileSpecIdInput.value = speciality.id; resetProfileForm(); profilesModal.classList.add('open'); await loadProfiles(speciality.id); } async function loadProfiles(specId) { profilesTbody.innerHTML = 'Загрузка...'; try { currentProfiles = await api.get(`/api/specialties/${specId}/profiles`); renderProfilesTable(); } catch (e) { profilesTbody.innerHTML = `Ошибка загрузки: ${escapeHtml(e.message)}`; } } function renderProfilesTable() { if (!currentProfiles || !currentProfiles.length) { profilesTbody.innerHTML = 'Профили не созданы'; return; } profilesTbody.innerHTML = currentProfiles.map(p => ` ${p.id} ${escapeHtml(p.name)} ${escapeHtml(p.description || '-')} `).join(''); } function resetProfileForm() { manageProfileForm.reset(); profileIdInput.value = ''; profileFormTitle.textContent = 'Создание профиля'; btnSaveProfile.textContent = 'Создать'; btnCancelProfileEdit.style.display = 'none'; hideAlert('manage-profile-alert'); } manageProfileForm.addEventListener('submit', async (e) => { e.preventDefault(); hideAlert('manage-profile-alert'); const specId = profileSpecIdInput.value; const profileId = profileIdInput.value; const name = profileNameInput.value.trim(); const description = profileDescInput.value.trim(); if (!name) { showAlert('manage-profile-alert', 'Введите название профиля', 'error'); return; } try { if (profileId) { // Обновление await api.put(`/api/specialties/${specId}/profiles/${profileId}`, { id: Number(profileId), name, description }); showAlert('manage-profile-alert', `Профиль "${name}" обновлен`, 'success'); } else { // Создание await api.post(`/api/specialties/${specId}/profiles`, { name, description }); showAlert('manage-profile-alert', `Профиль "${name}" создан`, 'success'); } resetProfileForm(); await loadProfiles(specId); } catch (error) { showAlert('manage-profile-alert', error.message || 'Ошибка сохранения профиля', 'error'); } }); profilesTbody.addEventListener('click', async (e) => { const editBtn = e.target.closest('.btn-edit-profile'); const deleteBtn = e.target.closest('.btn-delete-profile'); const specId = profileSpecIdInput.value; if (editBtn) { const profile = currentProfiles.find(item => item.id == editBtn.dataset.id); if (!profile) return; profileIdInput.value = profile.id; profileNameInput.value = profile.name || ''; profileDescInput.value = profile.description || ''; profileFormTitle.textContent = 'Редактирование профиля'; btnSaveProfile.textContent = 'Сохранить'; btnCancelProfileEdit.style.display = 'inline-block'; hideAlert('manage-profile-alert'); return; } if (deleteBtn) { if (!confirm('Удалить профиль обучения?')) return; try { await api.delete(`/api/specialties/${specId}/profiles/${deleteBtn.dataset.id}`); showAlert('manage-profile-alert', 'Профиль удален', 'success'); await loadProfiles(specId); } catch (error) { showAlert('manage-profile-alert', error.message || 'Ошибка удаления профиля', 'error'); } } }); btnCancelProfileEdit.addEventListener('click', resetProfileForm); // Закрытие модалок editDeptClose.addEventListener('click', () => editDeptModal.classList.remove('open')); editSpecClose.addEventListener('click', () => editSpecModal.classList.remove('open')); profilesModalClose.addEventListener('click', () => profilesModal.classList.remove('open')); editDeptModal.addEventListener('click', (e) => { if (e.target === editDeptModal) editDeptModal.classList.remove('open'); }); editSpecModal.addEventListener('click', (e) => { if (e.target === editSpecModal) editSpecModal.classList.remove('open'); }); profilesModal.addEventListener('click', (e) => { if (e.target === profilesModal) profilesModal.classList.remove('open'); }); // --- Дополнительные функции для вкладки Профилей --- function populateSpecialtiesDropdown() { const currentValue = tabProfileSpecSelect.value; tabProfileSpecSelect.innerHTML = '' + specialties.map(s => ``).join(''); tabProfileSpecSelect.value = currentValue; } function renderAllProfiles() { if (!allProfiles || !allProfiles.length) { tabProfileTbody.innerHTML = 'Профили не созданы'; return; } tabProfileTbody.innerHTML = allProfiles.map(p => ` ${p.id} ${escapeHtml(p.specialityCode)} · ${escapeHtml(p.specialityName)} ${escapeHtml(p.name)} ${escapeHtml(p.description || '-')} `).join(''); } function resetTabProfileForm() { createProfileTabForm.reset(); tabProfileIdInput.value = ''; tabProfileSpecSelect.disabled = false; mainProfileFormTitle.textContent = 'Создание профиля'; btnTabSaveProfile.textContent = 'Создать'; btnTabCancelProfileEdit.style.display = 'none'; hideAlert('tab-profile-alert'); tabProfileSpecSelect.dispatchEvent(new Event('change')); } createProfileTabForm.addEventListener('submit', async (e) => { e.preventDefault(); hideAlert('tab-profile-alert'); const specId = tabProfileSpecSelect.value; const profileId = tabProfileIdInput.value; const name = tabProfileNameInput.value.trim(); const description = tabProfileDescInput.value.trim(); if (!specId) { showAlert('tab-profile-alert', 'Выберите специальность', 'error'); return; } if (!name) { showAlert('tab-profile-alert', 'Введите название профиля', 'error'); return; } try { if (profileId) { await api.put(`/api/specialties/${specId}/profiles/${profileId}`, { id: Number(profileId), name, description }); showAlert('tab-profile-alert', `Профиль "${name}" обновлен`, 'success'); } else { await api.post(`/api/specialties/${specId}/profiles`, { name, description }); showAlert('tab-profile-alert', `Профиль "${name}" создан`, 'success'); } resetTabProfileForm(); await loadData(); } catch (error) { showAlert('tab-profile-alert', error.message || 'Ошибка сохранения профиля', 'error'); } }); tabProfileTbody.addEventListener('click', async (e) => { const editBtn = e.target.closest('.btn-edit-tab-profile'); const deleteBtn = e.target.closest('.btn-delete-tab-profile'); if (editBtn) { const profile = allProfiles.find(item => item.id == editBtn.dataset.id); if (!profile) return; tabProfileIdInput.value = profile.id; tabProfileSpecSelect.value = profile.specialityId; tabProfileSpecSelect.disabled = true; tabProfileSpecSelect.dispatchEvent(new Event('change')); tabProfileNameInput.value = profile.name || ''; tabProfileDescInput.value = profile.description || ''; mainProfileFormTitle.textContent = 'Редактирование профиля'; btnTabSaveProfile.textContent = 'Сохранить'; btnTabCancelProfileEdit.style.display = 'inline-block'; hideAlert('tab-profile-alert'); createProfileTabForm.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); return; } if (deleteBtn) { const profile = allProfiles.find(item => item.id == deleteBtn.dataset.id); if (!profile) return; if (!confirm('Удалить профиль обучения?')) return; try { await api.delete(`/api/specialties/${profile.specialityId}/profiles/${profile.id}`); showAlert('tab-profile-alert', 'Профиль удален', 'success'); await loadData(); } catch (error) { showAlert('tab-profile-alert', error.message || 'Ошибка удаления профиля', 'error'); } } }); btnTabCancelProfileEdit.addEventListener('click', resetTabProfileForm); await loadData(); }