Кривая модалка занятий по teacherId добавлена, требует доработки, также код users.js требует унификации+оптимизации(новая модалка вкинута в конец)
This commit is contained in:
@@ -860,4 +860,199 @@ tbody tr:hover {
|
|||||||
/* используем success или зелёный */
|
/* используем success или зелёный */
|
||||||
border-color: var(--success, #10b981);
|
border-color: var(--success, #10b981);
|
||||||
color: white;
|
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);
|
||||||
}
|
}
|
||||||
@@ -172,8 +172,13 @@ export async function initUsers() {
|
|||||||
<td>${u.id}</td>
|
<td>${u.id}</td>
|
||||||
<td>${escapeHtml(u.username)}</td>
|
<td>${escapeHtml(u.username)}</td>
|
||||||
<td><span class="badge ${ROLE_BADGE[u.role] || ''}">${ROLE_LABELS[u.role] || escapeHtml(u.role)}</span></td>
|
<td><span class="badge ${ROLE_BADGE[u.role] || ''}">${ROLE_LABELS[u.role] || escapeHtml(u.role)}</span></td>
|
||||||
<td><button class="btn-delete" data-id="${u.id}">Удалить</button></td>
|
<td>
|
||||||
<td><button class="btn-add-lesson" data-id="${u.id}">Добавить занятие</button></td>
|
<button class="btn-delete" data-id="${u.id}">Удалить</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn-add-lesson" data-id="${u.id}">Добавить занятие</button>
|
||||||
|
<button class="btn-view-lessons" data-id="${u.id}" data-name="${escapeHtml(u.username)}" style="margin-left: 0.5rem;">👁️ Занятия</button>
|
||||||
|
</td>
|
||||||
</tr>`).join('');
|
</tr>`).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,4 +356,158 @@ export async function initUsers() {
|
|||||||
|
|
||||||
// Загружаем все данные при инициализации
|
// Загружаем все данные при инициализации
|
||||||
await Promise.all([loadUsers(), loadGroups(), loadSubjects(), loadClassrooms()]);
|
await Promise.all([loadUsers(), loadGroups(), loadSubjects(), loadClassrooms()]);
|
||||||
}
|
|
||||||
|
|
||||||
|
// Элементы второго модального окна
|
||||||
|
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 = '<div class="loading-lessons">Загрузка занятий...</div>';
|
||||||
|
|
||||||
|
// Устанавливаем имя преподавателя в заголовок
|
||||||
|
if (teacherName) {
|
||||||
|
modalTeacherName.textContent = `Занятия преподавателя: ${teacherName}`;
|
||||||
|
} else {
|
||||||
|
modalTeacherName.textContent = 'Занятия преподавателя';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Загружаем занятия
|
||||||
|
const lessons = await api.get(`/api/users/lessons/${teacherId}`);
|
||||||
|
|
||||||
|
if (!lessons || lessons.length === 0) {
|
||||||
|
lessonsContainer.innerHTML = '<div class="no-lessons">У преподавателя пока нет занятий</div>';
|
||||||
|
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 += `<div class="lesson-day-divider">${day}</div>`;
|
||||||
|
|
||||||
|
lessonsByDay[day].forEach(lesson => {
|
||||||
|
html += `
|
||||||
|
<div class="lesson-card">
|
||||||
|
<div class="lesson-card-header">
|
||||||
|
<span class="lesson-group">${escapeHtml(lesson.groupName)}</span>
|
||||||
|
<span class="lesson-time">${escapeHtml(lesson.time)}</span>
|
||||||
|
</div>
|
||||||
|
<div class="lesson-card-body">
|
||||||
|
<div class="lesson-subject">${escapeHtml(lesson.subjectName)}</div>
|
||||||
|
<div class="lesson-details">
|
||||||
|
<span class="lesson-detail-item">${escapeHtml(lesson.typeLesson)}</span>
|
||||||
|
<span class="lesson-detail-item">${escapeHtml(lesson.lessonFormat)}</span>
|
||||||
|
<span class="lesson-detail-item">${escapeHtml(lesson.week)}</span>
|
||||||
|
<span class="lesson-detail-item">${escapeHtml(lesson.classroomName)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
lessonsContainer.innerHTML = html;
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
lessonsContainer.innerHTML = `<div class="no-lessons">Ошибка загрузки: ${escapeHtml(e.message)}</div>`;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -154,5 +154,18 @@
|
|||||||
<div class="form-alert" id="add-lesson-alert" role="alert" style="margin-top: 1rem;"></div>
|
<div class="form-alert" id="add-lesson-alert" role="alert" style="margin-top: 1rem;"></div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- View Teacher Lessons Modal -->
|
||||||
|
<div class="modal-overlay" id="modal-view-lessons">
|
||||||
|
<div class="modal-content view-lessons-modal">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2 id="modal-teacher-name">Занятия преподавателя</h2>
|
||||||
|
<button class="modal-close" id="modal-view-lessons-close">×</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lessons-container" id="lessons-container">
|
||||||
|
<!-- Фильтры по дням (добавим позже) -->
|
||||||
|
<div class="loading-lessons">Загрузка занятий...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user