Theory Management Dashboard - Copy this Html, Bootstrap Component to your project
<!DOCTYPE html> <html lang="vi"> <head> <meta charset="UTF 8" /> <meta name="viewport" content="width=device width, initial scale=1.0"/> <title>Quản lý Lý Thuyết</title> <link rel="icon" type="image/x icon" href="https://res.cloudinary.com/dsuav027e/image/upload/v1740393796/favicon_llcueu.ico"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <style> body { background color: #f8f9fa; } .btn custom { background color: #007bff; color: white; border radius: 8px; transition: all 0.3s ease in out; } .btn custom:hover { background color: #0056b3; transform: scale(1.05); } .details container { background: white; border radius: 10px; padding: 20px; box shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .chapter container, .lesson container { background: #f1f1f1; padding: 15px; border radius: 10px; margin top: 10px; } </style> </head> <body> <div th:insert="fragments/header :: header"></div> <div class="container mt 4"> <h1 class="text center text primary mb 4">Lý Thuyết</h1> <div class="row"> <div class="col md 3"> <div class="card p 3"> <h5 class="text center">Danh sách Lớp</h5> <div id="class list"></div> </div> </div> <div class="col md 9"> <div id="details container" class="details container"></div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const classList = document.getElementById('class list'); const detailsContainer = document.getElementById('details container'); let currentClass = null, currentSubject = null, currentChapter = null, currentChapterDiv = null; function loadClasses() { fetch('/api/theory/classes') .then(response => response.json()) .then(classes => { classes.sort((a, b) => a.name.localeCompare(b.name, undefined, { numeric: true })); classList.innerHTML = ''; classes.forEach(cls => { const classDiv = document.createElement('button'); classDiv.classList.add('btn', 'btn custom', 'mb 2', 'w 100'); classDiv.textContent = cls.name; classDiv.onclick = (event) => { event.stopPropagation(); detailsContainer.innerHTML = currentClass === cls.id ? '' : loadSubjects(cls.id); currentClass = currentClass === cls.id ? null : cls.id; }; classList.appendChild(classDiv); }); }) .catch(err => console.error('Lỗi khi tải danh sách Lớp:', err)); } function loadSubjects(classId) { fetch(`/api/theory/subjects/${classId}`) .then(response => response.json()) .then(subjects => { detailsContainer.innerHTML = ''; const subjectContainer = document.createElement('div'); subjectContainer.classList.add('d flex', 'flex wrap', 'gap 2'); subjects.forEach(subject => { const subjectDiv = document.createElement('button'); subjectDiv.classList.add('btn', 'btn custom', 'p 2', 'flex grow 1'); subjectDiv.textContent = subject.name; subjectDiv.onclick = (event) => { event.stopPropagation(); detailsContainer.querySelector('.chapter container')?.remove(); if (currentSubject !== subject.id) { loadChapters(classId, subject.id, subjectDiv); currentSubject = subject.id; } else currentSubject = null; }; subjectContainer.appendChild(subjectDiv); }); detailsContainer.appendChild(subjectContainer); }) .catch(err => console.error('Lỗi khi tải danh sách Môn:', err)); } function loadChapters(classId, subjectId, subjectItem) { fetch(`/api/theory/chapters/${classId}/${subjectId}`) .then(response => response.json()) .then(chapters => { let chapterContainer = document.createElement('div'); chapterContainer.classList.add('chapter container', 'mt 3'); chapters.forEach(chapter => { const chapterDiv = document.createElement('button'); chapterDiv.classList.add('btn', 'btn custom', 'mb 2', 'w 100'); chapterDiv.textContent = chapter.name; chapterDiv.onclick = (event) => { event.stopPropagation(); chapterDiv.querySelector('.lesson container')?.remove(); if (currentChapter !== chapter.id) { loadLessons(classId, subjectId, chapter.id, chapterDiv); currentChapter = chapter.id; } else currentChapter = null; }; chapterContainer.appendChild(chapterDiv); }); detailsContainer.appendChild(chapterContainer); }) .catch(err => console.error('Lỗi khi tải danh sách Chương:', err)); } function loadLessons(classId, subjectId, chapterId, chapterDiv) { fetch(`/api/theory/lessons/${classId}/${subjectId}/${chapterId}`) .then(response => response.json()) .then(lessons => { let lessonContainer = document.createElement('div'); lessonContainer.classList.add('lesson container', 'mt 2', 'ms 3'); lessons.forEach(lesson => { const lessonDiv = document.createElement('button'); lessonDiv.classList.add('btn', 'btn custom', 'mb 2', 'w 100'); lessonDiv.textContent = lesson.name; lessonDiv.onclick = (event) => { event.stopPropagation(); window.location.href = `/lesson?classId=${classId}&subjectId=${subjectId}&chapterId=${chapterId}&lessonId=${lesson.id}`; }; lessonContainer.appendChild(lessonDiv); }); chapterDiv.appendChild(lessonContainer); }) .catch(error => console.error('Lỗi khi tải danh sách bài học:', error)); } loadClasses(); }); </script> <div th:replace="fragments/footer :: footer"></div> </body> </html> Thiết kế lại giao diện trang sau không sửa các chức năng
