# 🎨 Frontend ## Общая информация | Параметр | Значение | |----------|----------| | **Фреймворк** | Нет (Vanilla JavaScript) | | **Модульная система** | ES6 Modules (`import`/`export`) | | **Стили** | CSS (модульный подход) | | **Шрифт** | [Inter](https://fonts.google.com/specimen/Inter) (Google Fonts) | | **Веб-сервер** | Apache httpd:alpine | --- ## Структура файлов ``` frontend/ ├── index.html # 🔐 Страница авторизации (общая) ├── script.js # Логика авторизации ├── style.css # Стили страницы авторизации ├── theme-toggle.js # Переключение светлой/тёмной темы ├── Dockerfile # httpd:alpine │ ├── admin/ # 👨‍💼 Интерфейс администратора │ ├── index.html # SPA-оболочка с sidebar │ ├── css/ │ │ ├── main.css # CSS-переменные, цвета, типографика │ │ ├── layout.css # Раскладка (sidebar, topbar, content) │ │ ├── components.css # Кнопки, таблицы, карточки, формы │ │ └── modals.css # Модальные окна │ ├── js/ │ │ ├── main.js # Инициализация, маршрутизация, навигация │ │ ├── api.js # HTTP-обёртка (fetch + Authorization) │ │ ├── utils.js # Утилиты │ │ ├── otel.js # OpenTelemetry (клиентская телеметрия) │ │ └── views/ # Модули представлений │ │ ├── users.js # Управление пользователями │ │ ├── groups.js # Управление группами │ │ ├── classrooms.js # Управление аудиториями │ │ ├── subjects.js # Управление дисциплинами │ │ ├── equipments.js # Управление оборудованием │ │ ├── edu-forms.js # Формы обучения │ │ ├── schedule.js # Расписание занятий │ │ └── database.js # Управление тенантами │ └── views/ # HTML-шаблоны представлений │ ├── users.html │ ├── groups.html │ ├── classrooms.html │ ├── subjects.html │ ├── equipments.html │ ├── edu-forms.html │ ├── schedule.html │ └── database.html │ ├── teacher/ # 👩‍🏫 Интерфейс преподавателя │ └── index.html # Просмотр расписания │ └── student/ # 🎓 Интерфейс студента └── index.html # Просмотр расписания (read-only) ``` --- ## Система маршрутизации (Admin SPA) Админ-панель работает как **Single Page Application** без фреймворка. Навигация реализована через `data-tab` атрибуты на элементах sidebar: ```html Пользователи Группы Расписание занятий ``` При клике на пункт меню `main.js`: 1. Загружает HTML-шаблон из `views/{tab}.html` через `fetch()` 2. Вставляет его в `#app-content` 3. Подключает соответствующий JS-модуль из `js/views/{tab}.js` 4. Обновляет заголовок страницы (`#page-title`) ### Разделы админ-панели | Tab | Описание | API | |-----|----------|-----| | `users` | CRUD пользователей | `/api/users` | | `groups` | CRUD групп | `/api/groups` | | `edu-forms` | Формы обучения | `/api/education-forms` | | `equipments` | Оборудование | `/api/equipments` | | `classrooms` | Аудитории | `/api/classrooms` | | `subjects` | Дисциплины | `/api/subjects` | | `schedule` | Расписание | `/api/users/lessons` | | `database` | Тенанты | `/api/database` | --- ## API-клиент (`api.js`) Все HTTP-запросы проходят через обёртку `apiFetch()`: ```javascript export async function apiFetch(endpoint, method = 'GET', body = null) { const response = await fetch(endpoint, { method, headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: body ? JSON.stringify(body) : null }); if (!response.ok) { throw new Error(data?.message || `Ошибка HTTP: ${response.status}`); } return await response.json(); } // Shortcut-методы export const api = { get: (url) => apiFetch(url, 'GET'), post: (url, body) => apiFetch(url, 'POST', body), put: (url, body) => apiFetch(url, 'PUT', body), delete: (url, body) => apiFetch(url, 'DELETE', body) }; ``` Токен берётся из `localStorage.getItem('token')`. --- ## Аутентификация (Frontend) ### Страница входа (`/index.html`) 1. Пользователь вводит логин/пароль 2. `script.js` отправляет `POST /api/auth/login` 3. При успехе сохраняет в `localStorage`: - `token` — UUID-токен - `role` — роль пользователя 4. Перенаправляет на соответствующий интерфейс: - `ADMIN` → `/admin/` - `TEACHER` → `/teacher/` - `STUDENT` → `/student/` ### Проверка авторизации На каждой странице проверяется наличие токена и роли: ```javascript export function isAuthenticatedAsAdmin() { const role = localStorage.getItem('role'); return token && role === 'ADMIN'; } ``` ### Выход Кнопка «Выйти» очищает `localStorage` и перенаправляет на `/`. --- ## CSS-архитектура ### Модульный подход Стили разделены на 4 файла (порядок подключения важен): 1. **`main.css`** — CSS-переменные (цвета, шрифты, отступы), глобальные стили, тёмная тема 2. **`layout.css`** — Sidebar, topbar, content area, responsive 3. **`components.css`** — Кнопки, таблицы, карточки, badge, формы 4. **`modals.css`** — Модальные окна ### Темизация CSS-переменные позволяют поддерживать светлую/тёмную тему: ```css :root { --bg-primary: #ffffff; --text-primary: #1a1a2e; --accent: #6366f1; } [data-theme="dark"] { --bg-primary: #0f0f23; --text-primary: #e2e8f0; --accent: #818cf8; } ``` Переключение — через `theme-toggle.js`. --- ## Адаптивность Интерфейс адаптирован под мобильные устройства: - Sidebar скрывается на экранах < 768px - Появляется кнопка-гамбургер (`#menu-toggle`) - Sidebar выезжает как overlay - Таблицы получают горизонтальный скролл