From 73995f86f8b9f6254410bcc93f8667c29d40573f Mon Sep 17 00:00:00 2001 From: Zuev Date: Tue, 31 Mar 2026 15:00:38 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=D1=83=D1=8E=20=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D1=83=20=D0=B7=D0=B0=D0=B3=D1=80?= =?UTF-8?q?=D1=83=D0=B6=D0=B5=D0=BD=D0=BD=D0=BE=D1=81=D1=82=D0=B8=20=D0=B0?= =?UTF-8?q?=D1=83=D0=B4=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/admin/css/auditorium-workload.css | 154 ++++++++++++++++++ frontend/admin/index.html | 9 + frontend/admin/js/main.js | 2 + .../admin/js/views/auditorium-workload.js | 153 +++++++++++++++++ frontend/admin/views/auditorium-workload.html | 75 +++++++++ 5 files changed, 393 insertions(+) create mode 100644 frontend/admin/css/auditorium-workload.css create mode 100644 frontend/admin/js/views/auditorium-workload.js create mode 100644 frontend/admin/views/auditorium-workload.html diff --git a/frontend/admin/css/auditorium-workload.css b/frontend/admin/css/auditorium-workload.css new file mode 100644 index 0000000..c43f42d --- /dev/null +++ b/frontend/admin/css/auditorium-workload.css @@ -0,0 +1,154 @@ +/* ===== Auditorium Workload Specific Styles ===== */ + +.workload-grid-container { + width: 100%; + max-height: 600px; + overflow: auto; + border-radius: var(--radius-sm); + border: 1px solid var(--bg-card-border); + position: relative; +} + +.workload-table { + width: 100%; + border-collapse: collapse; + min-width: 800px; + table-layout: fixed; +} + +.workload-table th, .workload-table td { + border: 1px solid var(--bg-card-border); + padding: 0.5rem; + vertical-align: top; + position: relative; + min-width: 150px; + height: 80px; +} + +.workload-table th { + background: var(--bg-input); + color: var(--text-secondary); + font-weight: 500; + text-align: center; + position: sticky; + top: 0; + z-index: 10; + padding: 1rem 0.5rem; + box-shadow: 0 1px 0 var(--bg-card-border); +} + +.workload-table .time-cell { + background: var(--bg-input); + color: var(--text-secondary); + font-weight: 500; + text-align: center; + vertical-align: middle; + width: 120px; + min-width: 120px; + position: sticky; + left: 0; + z-index: 5; + box-shadow: 1px 0 0 var(--bg-card-border); +} + +.workload-table .top-left-cell { + position: sticky; + top: 0; + left: 0; + z-index: 20; + background: var(--bg-input); + min-width: 120px; + width: 120px; + box-shadow: 1px 1px 0 var(--bg-card-border); +} + +/* Diagonal line using SVG or linear-gradient */ +.workload-table .top-left-cell::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: linear-gradient( + to bottom right, + transparent calc(50% - 1px), + var(--bg-card-border) 50%, + transparent calc(50% + 1px) + ); + pointer-events: none; +} + +.top-left-cell span.top-label { + position: absolute; + top: 0.5rem; + right: 0.5rem; + font-size: 0.75rem; + color: var(--text-secondary); +} + +.top-left-cell span.bottom-label { + position: absolute; + bottom: 0.5rem; + left: 0.5rem; + font-size: 0.75rem; + color: var(--text-secondary); +} + +/* Lesson Cards inside grid cells */ +.lesson-card { + background: var(--bg-card); + border: 1px solid var(--bg-card-border); + border-radius: var(--radius-sm); + padding: 0.5rem; + font-size: 0.8rem; + margin-bottom: 0.25rem; + transition: all 0.2s cubic-bezier(0.25, 0.8, 0.25, 1); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +[data-theme="light"] .lesson-card { + background: rgba(255, 255, 255, 0.9); +} + +.lesson-card:hover { + background: var(--bg-hover); + transform: translateY(-2px); + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15); + border-color: var(--accent); +} + +.lesson-subject { + font-weight: 600; + color: var(--text-primary); + margin-bottom: 0.2rem; + line-height: 1.2; +} + +.lesson-group { + font-weight: 700; /* Bolder specific for groups request mockup */ + color: var(--text-primary); + margin-bottom: 0.1rem; + font-size: 0.75rem; +} + +.lesson-teacher { + color: var(--text-secondary); + font-size: 0.75rem; +} + +/* Custom scrollbar adjustments for grid container */ +.workload-grid-container::-webkit-scrollbar { + width: 8px; + height: 8px; +} +.workload-grid-container::-webkit-scrollbar-track { + background: transparent; +} +.workload-grid-container::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.15); + border-radius: 8px; +} +[data-theme="light"] .workload-grid-container::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.15); +} diff --git a/frontend/admin/index.html b/frontend/admin/index.html index e56a9eb..d499948 100755 --- a/frontend/admin/index.html +++ b/frontend/admin/index.html @@ -16,6 +16,7 @@ + @@ -121,6 +122,14 @@ Расписание занятий + + + + + + + Загруженность аудиторий + diff --git a/frontend/admin/js/main.js b/frontend/admin/js/main.js index 3dff1b2..7fa36c4 100755 --- a/frontend/admin/js/main.js +++ b/frontend/admin/js/main.js @@ -28,6 +28,7 @@ import {initSchedule} from "./views/schedule.js"; import {initDatabase} from "./views/database.js"; import {initDepartment} from "./views/department.js"; import {initDepartmentsData} from "./views/departments-data.js"; +import {initAuditoriumWorkload} from "./views/auditorium-workload.js"; // Configuration const ROUTES = { @@ -38,6 +39,7 @@ const ROUTES = { classrooms: { title: 'Аудитории', file: 'views/classrooms.html', init: initClassrooms }, subjects: { title: 'Дисциплины и преподаватели', file: 'views/subjects.html', init: initSubjects }, schedule: { title: 'Расписание занятий', file: 'views/schedule.html', init: initSchedule }, + 'auditorium-workload': { title: 'Загруженность аудиторий', file: 'views/auditorium-workload.html', init: initAuditoriumWorkload }, database: { title: 'База данных', file: 'views/database.html', init: initDatabase }, department: { title: 'Кафедры', file: 'views/department.html', init: initDepartment }, 'departments-data': { title: 'Создание кафедры/специальности', file: 'views/departments-data.html', init: initDepartmentsData }, diff --git a/frontend/admin/js/views/auditorium-workload.js b/frontend/admin/js/views/auditorium-workload.js new file mode 100644 index 0000000..f7c7629 --- /dev/null +++ b/frontend/admin/js/views/auditorium-workload.js @@ -0,0 +1,153 @@ +import { initMultiSelect } from '../utils.js'; + +export function initAuditoriumWorkload() { + // Initialize date input with current date + const dateInput = document.getElementById('workload-date'); + if (dateInput) { + const today = new Date(); + const yyyy = today.getFullYear(); + const mm = String(today.getMonth() + 1).padStart(2, '0'); + const dd = String(today.getDate()).padStart(2, '0'); + dateInput.value = `${yyyy}-${mm}-${dd}`; + } + + // Initialize Multi-Selects + initMultiSelect('building-box', 'building-menu', 'building-text', 'building-checkboxes'); + initMultiSelect('capacity-box', 'capacity-menu', 'capacity-text', 'capacity-checkboxes'); + initMultiSelect('equipment-box', 'equipment-menu', 'equipment-text', 'equipment-checkboxes'); + + // Populate Filters with Mock/Initial Data + populateFilters(); + + // Render Mock Data for the Grid based on the UI requested layout + renderMockGrid(); +} + +function populateFilters() { + // Buildings + const buildingsContainer = document.getElementById('building-checkboxes'); + const buildings = [ + { id: 1, name: "Корпус 1 (Главный)" }, + { id: 2, name: "Корпус 2 (Физ-мат)" }, + { id: 3, name: "Корпус 3 (Гуманитарный)" } + ]; + buildingsContainer.innerHTML = buildings.map(item => ` + + ${item.name} + + `).join(''); + + // Capacities + const capacityContainer = document.getElementById('capacity-checkboxes'); + const capacities = [ + { id: 'small', name: "До 30 мест" }, + { id: 'medium', name: "30 - 60 мест" }, + { id: 'large', name: "60 - 100 мест" }, + { id: 'xlarge', name: "Более 100 мест" } + ]; + capacityContainer.innerHTML = capacities.map(item => ` + + `).join(''); + + // Equipment + const equipmentContainer = document.getElementById('equipment-checkboxes'); + const equipmentList = [ + { id: 1, name: "Проектор" }, + { id: 2, name: "Компьютерные места" }, + { id: 3, name: "Интерактивная доска" }, + { id: 4, name: "Микрофон" } + ]; + equipmentContainer.innerHTML = equipmentList.map(item => ` + + `).join(''); +} + +function renderMockGrid() { + // In future this will be loaded from API + const timeslots = [ + "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:50", + "20:00-21:20" + ]; + + const auditoriums = [ + "201", "202", "204", "205", "206", "207", "208" + ]; + + // Mock schedule data mapped by room and time + // Key: "roomId_timeSlotId", Value: Lesson object + const mockSchedule = { + "201_8:00-9:30": { subject: "Физика", group: "ИБ-41м", teacher: "Атлетов А.Р." }, + "201_9:40-11:10": { subject: "Физика", group: "ИВТ-21-1", teacher: "Атлетов А.Р." }, + "201_11:40-13:10": { subject: "Физика", group: "ИБ-41м", teacher: "Физик В.Г." }, + "201_13:20-14:50": { subject: "Физика", group: "ИБ-41м", teacher: "Физик В.Г." }, + + "202_9:40-11:10": { subject: "Химия", group: "ИВТ-21-1", teacher: "Химоза Я.В." }, + "202_13:20-14:50": { subject: "Математика", group: "ИВТ-21-1", teacher: "Рутина Л.П." }, + "202_15:00-16:30": { subject: "Химия", group: "ИВТ-21-1", teacher: "Химоза Я.В." }, + "202_16:50-18:20": { subject: "Физика", group: "ИВТ-21-1", teacher: "Атлетов А.Р." }, + + "205_9:40-11:10": { subject: "Организация аудита ИБ", group: "ИБ-41м", teacher: "Таныгин М.О." }, + }; + + // Render Headers + const headerRow = document.getElementById('workload-header-row'); + // Start after the first fixed cell (which is already in HTML) + + auditoriums.forEach(room => { + const th = document.createElement('th'); + th.textContent = room; + headerRow.appendChild(th); + }); + + // Render Body Rows + const tbody = document.getElementById('workload-tbody'); + + timeslots.forEach((time) => { + const tr = document.createElement('tr'); + + // Add Time Cell + const tdTime = document.createElement('td'); + tdTime.className = 'time-cell'; + tdTime.textContent = time; + tr.appendChild(tdTime); + + // Add Room Cells for this Time + auditoriums.forEach(room => { + const td = document.createElement('td'); + + const scheduleKey = `${room}_${time}`; + const lesson = mockSchedule[scheduleKey]; + + if (lesson) { + // Render lesson card + td.innerHTML = ` +
+
${lesson.subject}
+
${lesson.group}
+
${lesson.teacher}
+
+ `; + } + + tr.appendChild(td); + }); + + tbody.appendChild(tr); + }); +} diff --git a/frontend/admin/views/auditorium-workload.html b/frontend/admin/views/auditorium-workload.html new file mode 100644 index 0000000..8671b26 --- /dev/null +++ b/frontend/admin/views/auditorium-workload.html @@ -0,0 +1,75 @@ +
+
+

Загруженность аудиторий

+
+ +
+
+ +
+
+ Выберите корпуса... + + + +
+ +
+
+ +
+ +
+
+ Выберите вместимость... + + + +
+ +
+
+ +
+ +
+
+ Выберите оборудование... + + + +
+ +
+
+ +
+ + +
+
+ + +
+ + + + + + + + + + +
+ Аудитория + Время +
+
+