LMS Этап 1 MVP - Laravel 13
✅ Базовая функциональность: - Аутентификация (вход/выход/регистрация) - Роли и разрешения (Administrator, Manager, Curator, Student) - Панель управления (dashboard) для разных ролей ✅ База данных (23 миграции): - users, organizations, groups, user_groups - course_categories, courses, course_modules - tests, questions, answers, question_matching_pairs - test_attempts, test_responses - course_requests, course_request_items, course_assignments - scorm_data, user_course_progress, logs - permission tables ✅ Модели (15 моделей с отношениями): - User, Organization, Group - CourseCategory, Course, CourseModule - Test, Question, Answer, QuestionMatchingPair - TestAttempt, TestResponse - CourseRequest, CourseRequestItem, CourseAssignment - ScormData, UserCourseProgress, Log ✅ Seeders: - RoleSeeder (роли и разрешения) - UserSeeder (тестовые пользователи) ✅ Контроллеры: - LoginController, RegisterController, DashboardController ✅ Blade-шаблоны: - layouts/app.blade.php - auth/login.blade.php, auth/register.blade.php - dashboard/admin.blade.php, dashboard/curator.blade.php, dashboard/student.blade.php 📦 Пакеты: - Laravel 13 (dev-master) - spatie/laravel-permission - laravel/sanctum 🔧 Инфраструктура: - Nginx конфигурация - PHP 8.4-FPM - MariaDB Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
import './bootstrap';
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* We'll load the axios HTTP library which allows us to easily issue requests
|
||||
* to our Laravel back-end. This library automatically handles sending the
|
||||
* CSRF token as a header based on the value of the "XSRF" token cookie.
|
||||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
window.axios = axios;
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
/**
|
||||
* Echo exposes an expressive API for subscribing to channels and listening
|
||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
||||
* allows your team to easily build robust real-time web applications.
|
||||
*/
|
||||
|
||||
// import Echo from 'laravel-echo';
|
||||
|
||||
// import Pusher from 'pusher-js';
|
||||
// window.Pusher = Pusher;
|
||||
|
||||
// window.Echo = new Echo({
|
||||
// broadcaster: 'pusher',
|
||||
// key: import.meta.env.VITE_PUSHER_APP_KEY,
|
||||
// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
|
||||
// wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
|
||||
// wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
|
||||
// wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
|
||||
// forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
|
||||
// enabledTransports: ['ws', 'wss'],
|
||||
// });
|
||||
@@ -0,0 +1,63 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Вход в систему')
|
||||
|
||||
@section('content')
|
||||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-5">
|
||||
<div class="card shadow">
|
||||
<div class="card-header bg-primary text-white text-center">
|
||||
<h4 class="mb-0"><i class="bi bi-box-arrow-in-right"></i> Вход в систему</h4>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<ul class="mb-0">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('login') }}" method="POST">
|
||||
@csrf
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" class="form-control @error('email') is-invalid @enderror"
|
||||
id="email" name="email" value="{{ old('email') }}" required autofocus>
|
||||
@error('email')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Пароль</label>
|
||||
<input type="password" class="form-control @error('password') is-invalid @enderror"
|
||||
id="password" name="password" required>
|
||||
@error('password')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="remember" name="remember">
|
||||
<label class="form-check-label" for="remember">Запомнить меня</label>
|
||||
</div>
|
||||
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-box-arrow-in-right"></i> Войти
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-footer text-center">
|
||||
<small>Нет учетной записи? <a href="{{ route('register') }}">Зарегистрироваться</a></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,82 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Регистрация')
|
||||
|
||||
@section('content')
|
||||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-5">
|
||||
<div class="card shadow">
|
||||
<div class="card-header bg-success text-white text-center">
|
||||
<h4 class="mb-0"><i class="bi bi-person-plus"></i> Регистрация</h4>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<ul class="mb-0">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('register') }}" method="POST">
|
||||
@csrf
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">ФИО</label>
|
||||
<input type="text" class="form-control @error('name') is-invalid @enderror"
|
||||
id="name" name="name" value="{{ old('name') }}" required autofocus>
|
||||
@error('name')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" class="form-control @error('email') is-invalid @enderror"
|
||||
id="email" name="email" value="{{ old('email') }}" required>
|
||||
@error('email')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="phone" class="form-label">Телефон</label>
|
||||
<input type="tel" class="form-control @error('phone') is-invalid @enderror"
|
||||
id="phone" name="phone" value="{{ old('phone') }}">
|
||||
@error('phone')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Пароль</label>
|
||||
<input type="password" class="form-control @error('password') is-invalid @enderror"
|
||||
id="password" name="password" required>
|
||||
@error('password')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password_confirmation" class="form-label">Подтверждение пароля</label>
|
||||
<input type="password" class="form-control"
|
||||
id="password_confirmation" name="password_confirmation" required>
|
||||
</div>
|
||||
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-person-check"></i> Зарегистрироваться
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-footer text-center">
|
||||
<small>Уже есть учетная запись? <a href="{{ route('login') }}">Войти</a></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,92 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'LMS - Система управления обучением')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar -->
|
||||
<nav class="col-md-3 col-lg-2 d-md-block sidebar collapse">
|
||||
<div class="position-sticky pt-3">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="{{ route('dashboard') }}">
|
||||
<i class="bi bi-speedometer2"></i> Панель управления
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-book"></i> Мои курсы
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-file-earmark-text"></i> Тесты
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-graph-up"></i> Прогресс
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main content -->
|
||||
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">Добро пожаловать, {{ Auth::user()->name }}!</h1>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card card-stat shadow-sm">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Курсов доступно</h6>
|
||||
<h2 class="mb-0">0</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card card-stat shadow-sm" style="border-left-color: #28a745;">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Завершено</h6>
|
||||
<h2 class="mb-0">0</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card card-stat shadow-sm" style="border-left-color: #ffc107;">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">В процессе</h6>
|
||||
<h2 class="mb-0">0</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card card-stat shadow-sm" style="border-left-color: #dc3545;">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Тестов пройдено</h6>
|
||||
<h2 class="mb-0">0</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0"><i class="bi bi-book-half"></i> Доступные курсы</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted">У вас пока нет назначенных курсов.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,121 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Панель администратора')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar -->
|
||||
<nav class="col-md-3 col-lg-2 d-md-block sidebar collapse">
|
||||
<div class="position-sticky pt-3">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="{{ route('dashboard') }}">
|
||||
<i class="bi bi-speedometer2"></i> Панель управления
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-people"></i> Пользователи
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-building"></i> Организации
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-book"></i> Курсы
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-file-earmark-text"></i> Отчёты
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main content -->
|
||||
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">Панель администратора</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<span class="text-muted">{{ Auth::user()->name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card card-stat shadow-sm">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Пользователей</h6>
|
||||
<h2 class="mb-0">{{ $stats['users_count'] }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card card-stat shadow-sm" style="border-left-color: #28a745;">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Курсов</h6>
|
||||
<h2 class="mb-0">{{ $stats['courses_count'] }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card card-stat shadow-sm" style="border-left-color: #17a2b8;">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Организаций</h6>
|
||||
<h2 class="mb-0">{{ $stats['organizations_count'] }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card card-stat shadow-sm" style="border-left-color: #ffc107;">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Назначений</h6>
|
||||
<h2 class="mb-0">{{ $stats['active_assignments'] }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0"><i class="bi bi-graph-up"></i> Быстрые действия</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<a href="#" class="btn btn-outline-primary w-100">
|
||||
<i class="bi bi-person-plus"></i> Добавить пользователя
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="#" class="btn btn-outline-success w-100">
|
||||
<i class="bi bi-book"></i> Создать курс
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="#" class="btn btn-outline-info w-100">
|
||||
<i class="bi bi-building"></i> Добавить организацию
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="#" class="btn btn-outline-warning w-100">
|
||||
<i class="bi bi-file-earmark-spreadsheet"></i> Экспорт отчёта
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,85 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Панель куратора')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar -->
|
||||
<nav class="col-md-3 col-lg-2 d-md-block sidebar collapse">
|
||||
<div class="position-sticky pt-3">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="{{ route('dashboard') }}">
|
||||
<i class="bi bi-speedometer2"></i> Панель управления
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-people"></i> Пользователи
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-people-fill"></i> Группы
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-book"></i> Курсы
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-calendar-check"></i> Назначения
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main content -->
|
||||
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">Панель куратора</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<span class="text-muted">{{ Auth::user()->name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($organization)
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-building"></i> Организация: <strong>{{ $organization->name }}</strong>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card card-stat shadow-sm">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Пользователей в организации</h6>
|
||||
<h2 class="mb-0">{{ $stats['users_count'] }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card card-stat shadow-sm" style="border-left-color: #28a745;">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Доступно курсов</h6>
|
||||
<h2 class="mb-0">{{ $stats['courses_count'] }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card card-stat shadow-sm" style="border-left-color: #17a2b8;">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted">Групп</h6>
|
||||
<h2 class="mb-0">{{ $stats['groups_count'] }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,82 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Мои курсы')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar -->
|
||||
<nav class="col-md-3 col-lg-2 d-md-block sidebar collapse">
|
||||
<div class="position-sticky pt-3">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="{{ route('dashboard') }}">
|
||||
<i class="bi bi-speedometer2"></i> Панель управления
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-book"></i> Мои курсы
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-file-earmark-text"></i> Тесты
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<i class="bi bi-graph-up"></i> Прогресс
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main content -->
|
||||
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">Мои курсы</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<span class="text-muted">{{ Auth::user()->name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($courses->count() > 0)
|
||||
<div class="row">
|
||||
@foreach($courses as $course)
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
@if($course->thumbnail)
|
||||
<img src="{{ asset('storage/' . $course->thumbnail) }}" class="card-img-top" alt="{{ $course->title }}">
|
||||
@else
|
||||
<div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" style="height: 200px;">
|
||||
<i class="bi bi-book text-white" style="font-size: 4rem;"></i>
|
||||
</div>
|
||||
@endif
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ $course->title }}</h5>
|
||||
<p class="card-text text-muted">{{ Str::limit($course->description, 100) }}</p>
|
||||
<div class="progress mb-3" style="height: 10px;">
|
||||
<div class="progress-bar" role="progressbar" style="width: {{ $progress[$course->id] ?? 0 }}%"></div>
|
||||
</div>
|
||||
<small class="text-muted">Прогресс: {{ $progress[$course->id] ?? 0 }}%</small>
|
||||
</div>
|
||||
<div class="card-footer bg-white">
|
||||
<a href="#" class="btn btn-primary w-100">
|
||||
<i class="bi bi-play-fill"></i> Продолжить
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i> У вас пока нет назначенных курсов.
|
||||
</div>
|
||||
@endif
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,113 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<title>@yield('title', config('app.name', 'LMS'))</title>
|
||||
|
||||
<!-- Bootstrap 5 CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #0d6efd;
|
||||
--secondary-color: #6c757d;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
min-height: calc(100vh - 56px);
|
||||
background-color: #f8f9fa;
|
||||
border-right: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.sidebar .nav-link {
|
||||
color: #333;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.sidebar .nav-link:hover,
|
||||
.sidebar .nav-link.active {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.card-stat {
|
||||
border-left: 4px solid var(--primary-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
@stack('styles')
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navbar -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="{{ url('/dashboard') }}">
|
||||
<i class="bi bi-mortarboard-fill"></i> LMS
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto">
|
||||
@auth
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('dashboard') }}">
|
||||
<i class="bi bi-speedometer2"></i> Панель управления
|
||||
</a>
|
||||
</li>
|
||||
@endauth
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
@auth
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-person-circle"></i> {{ Auth::user()->name }}
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><span class="dropdown-item-text text-muted small">{{ Auth::user()->email }}</span></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li>
|
||||
<form action="{{ route('logout') }}" method="POST">
|
||||
@csrf
|
||||
<button type="submit" class="dropdown-item">
|
||||
<i class="bi bi-box-arrow-right"></i> Выйти
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
@else
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('login') }}">Войти</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('register') }}">Регистрация</a>
|
||||
</li>
|
||||
@endauth
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@yield('content')
|
||||
|
||||
<!-- Bootstrap 5 JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
@stack('scripts')
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user