Code Inspection Tool - Copy this Html, Bootstrap Component to your project
Kiểm tra và sửa lỗi "Kiểm tra mã CSS và JavaScript này để tìm và sửa các lỗi hiển thị trên trình duyệt." "Tối ưu hóa tốc độ tải trang cho mã code này và giảm bớt thời gian tải tài nguyên." "Thêm hiệu ứng cuộn mượt mà khi người dùng chuyển từ phần này sang phần khác." "Kiểm tra các lỗi về tính tương thích trình duyệt trong mã HTML và CSS này." <!DOCTYPE html> <html lang="vi"> <head> <meta charset="UTF 8"> <meta name="viewport" content="width=device width, initial scale=1.0"> <title>Bảng điều khiển phân tích kỳ thi</title> <link rel="stylesheet" href="styles/style.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font awesome/6.0.0 beta3/css/all.min.css"> <script src="https://code.jquery.com/jquery 3.6.0.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <style> /* Reset & Base Styles */ * { box sizing: border box; margin: 0; padding: 0; font family: Arial, sans serif; } /* Fullscreen Setup */ body, html { width: 100vw; height: 100vh; overflow: hidden; } /* Top Navigation Bar */ .top bar { display: flex; justify content: space between; align items: center; background color: #e4e4e4ee; padding: 10px 20px; box shadow: 0 4px 8px rgba(0, 0, 0, 0.1); width: 100%; z index: 1; } .top bar left { display: flex; align items: center; gap: 10px; } .top bar left h2 { margin left: 10px; color: #333; } .top bar right { display: flex; align items: center; gap: 20px; } .logo { width: 50px; height: auto; } /* Main Container */ .container { display: flex; width: 100%; height: calc(100% 60px); /* Subtract Top Bar Height */ background color: #f8f9fa; } /* Sidebar */ .sidebar { width: 250px; background color: #4CAF50; color: white; padding: 20px; display: flex; flex direction: column; align items: center; transition: width 0.3s; position: relative; } .sidebar.collapsed { width: 80px; } .sidebar ul { list style type: none; width: 100%; padding: 0; } .sidebar li { padding: 15px; cursor: pointer; display: flex; align items: center; transition: background color 0.3s; } .sidebar li i { font size: 1.2em; } .sidebar li span { margin left: 10px; transition: opacity 0.3s; } .sidebar.collapsed li span { display: none; } .sidebar li:hover { background color: #077e0b; } /* Main Content */ .main content { flex: 1; padding: 20px; overflow y: auto; } header { display: flex; justify content: space between; align items: center; margin bottom: 20px; } header h1 { font size: 1.8em; color: #333; } /* User Info */ .user info { display: flex; align items: center; font size: 1em; color: #333; } .user info i { font size: 1.5em; margin right: 5px; } /* Exam Details Section */ #exam details { background color: #fff; padding: 20px; border radius: 8px; box shadow: 0 4px 8px rgba(0, 0, 0, 0.1); margin top: 20px; } #exam details h2 { font size: 1.5em; color: #333; margin bottom: 15px; } #exam list body { display: flex; flex wrap: wrap; gap: 20px; } /* Styling Each Exam Card */ .exam card { border: 1px solid #ddd; padding: 20px; width: auto fit; text align: left; border radius: 8px; box shadow: 0 4px 8px rgba(0, 0, 0, 0.1); background color: #f3f3f3; transition: background color 0.3s ease; } .exam card:hover { background color: #e9ecef; } .exam card h3 { font size: 1.4em; margin bottom: 10px; font weight: bold; color: #0056b3; } .exam card p { margin: 8px 0; font size: 1em; color: #333; } .exam card .detail button { align self: center; margin top: 10px; padding: 8px 12px; background color: #d9534f; color: white; border: none; border radius: 4px; cursor: pointer; transition: background color 0.3s; } .exam card .detail button:hover { background color: #c9302c; } /* Room Details */ #quiz details { display: none; background color: #f8f9fa; padding: 20px; border radius: 8px; margin top: 20px; } .room card { border: 1px solid #ddd; border radius: 8px; padding: 16px; width: 80%; margin: 15px auto; text align: left; background color: #f9f9f9; box shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .progress bar { display: flex; height: 30px; margin top: 8px; border radius: 5px; overflow: hidden; background color: #e0e0e0; } .progress bar .completed { background color: #4caf50; color: white; display: flex; align items: center; justify content: center; font size: 14px; } .progress bar .in progress { background color: #ffc107; color: black; display: flex; align items: center; justify content: center; font size: 14px; } .progress bar .not started { background color: #f44336; color: white; display: flex; align items: center; justify content: center; font size: 14px; } .room card h3 { font size: 18px; margin bottom: 8px; color: #333; } .room card p { margin: 5px 0; font size: 14px; color: #333; } </style> </head> <body> <! Thanh ngang trên cùng > <div class="top bar"> <div class="top bar left"> <img src="https://cdn.haitrieu.com/wp content/uploads/2022/08/logo dai hoc tai nguyen va moi truong ha noi.png" alt="Logo" class="logo"> <h2>Quản lý thi</h2> </div> <div class="top bar right"> <div class="user info"> <i class="fas fa user circle"></i> <span>Người dùng</span> </div> </div> </div> <div class="container"> <! Thanh điều hướng bên trái > <aside class="sidebar"> <button class="toggle btn" onclick="toggleSidebar()"> <i class="fas fa bars"></i> </button> <ul> <li id="dashboardNav"><i class="fas fa tachometer alt"></i> <span>Bảng điều khiển</span></li> <li id="questionBankNav"><i class="fas fa book"></i> <span>Ngân hàng câu hỏi</span></li> <li id="examNav"><i class="fas fa pencil alt"></i> <span>Kỳ thi</span></li> <li id="reportNav"><i class="fas fa chart line"></i> <span>Báo cáo</span></li> </ul> </aside> <! Nội dung chính > <main class="main content"> <header id="exam header"> <h1>Phân tích kỳ thi</h1> <div class="exam select"> <label for="exam">Chọn kỳ thi:</label> <select id="exam"> <option value="" disabled selected>Chọn kỳ thi</option> </select> </div> </header> <! Các ô thống kê > <div class="cards"> <div class="card green" id="total students"><i class="fas fa user check"></i>Thí sinh đăng ký: <span id="total students count">0</span></div> <div class="card orange" id="attendance rate"><i class="fas fa chart pie"></i>Đã đăng nhập: <span id="total students with access">0</span></div> <div class="card red" id="not logged in"><i class="fas fa user times"></i>Chưa đăng nhập: <span id="not logged in count">0</span></div> </div> <! Chi tiết môn thi > <section id="exam details"> <h2>Chi tiết môn thi</h2> <div id="exam list body"> <! Dữ liệu chi tiết môn thi sẽ được thêm vào đây > </div> </section> <! Phần chi tiết phòng thi (chỉ hiển thị khi nhấn "Chi tiết") > <section id="quiz details" style="display: none;"> <h3>Danh sách phòng thi</h3> <div id="quiz list body"> <! Nội dung phòng thi sẽ được thêm vào động bởi JavaScript > </div> </section> </main> </div> <script> // Toggle sidebar function function toggleSidebar() { const sidebar = document.querySelector('.sidebar'); sidebar.classList.toggle('collapsed'); } // API URL và token const apiUrl = "https://sathach.hunre.edu.vn/webservice/rest/server.php"; const token = "35e6058fd071f6428e7b9b2bf51e8436"; // Hàm lấy danh sách khóa học và cập nhật vào dropdown function fetchCourseList() { $.ajax({ url: apiUrl, type: "GET", data: { wstoken: token, wsfunction: "core_course_get_courses", moodlewsrestformat: "json" }, success: function(response) { const courseSelect = document.getElementById('exam'); courseSelect.innerHTML = `<option value="" disabled selected>Chọn kỳ thi</option>`; const filteredCourses = response.filter(course => course.id > 1); // Thêm khóa học đã lọc vào dropdown filteredCourses.forEach(course => { const option = document.createElement('option'); option.value = course.id; option.textContent = course.displayname || course.fullname; courseSelect.appendChild(option); }); // Thêm sự kiện khi chọn khóa học courseSelect.addEventListener('change', function() { const selectedCourseId = courseSelect.value; if (selectedCourseId) { fetchTotalStudents(selectedCourseId); fetchQuizList(selectedCourseId); updateQuizListPeriodically(selectedCourseId); // Bắt đầu cập nhật tự động } }); }, error: function(error) { console.error("Lỗi khi gọi API:", error); } }); } // Hàm lấy danh sách quiz trong kỳ thi đã chọn function fetchQuizList(courseId) { console.log("Gọi fetchQuizList", courseId); $.ajax({ url: apiUrl, type: "GET", data: { wstoken: token, wsfunction: "core_course_get_contents", courseid: courseId, moodlewsrestformat: "json", }, success: function(response) { console.log("Danh sách quiz trong kỳ thi:", response); const examListBody = document.getElementById('exam list body'); examListBody.innerHTML = ''; // Xóa dữ liệu cũ nếu có const quizzes = response.flatMap(section => section.modules) .filter(module => module.modname === 'quiz'); quizzes.forEach(quiz => { const quizCard = document.createElement('div'); quizCard.className = 'exam card'; const quizName = document.createElement('h3'); quizName.textContent = quiz.name || 'N/A'; const startDateObj = quiz.dates.find(date => date.dataid === 'timeopen'); const endDateObj = quiz.dates.find(date => date.dataid === 'timeclose'); const startTime = document.createElement('p'); startTime.textContent = 'Thời gian bắt đầu: ' + (startDateObj ? new Date(startDateObj.timestamp * 1000).toLocaleDateString('vi VN', { day: '2 digit', month: '2 digit', year: 'numeric' }) : 'N/A'); const endTime = document.createElement('p'); endTime.textContent = 'Thời gian kết thúc: ' + (endDateObj ? new Date(endDateObj.timestamp * 1000).toLocaleDateString('vi VN', { day: '2 digit', month: '2 digit', year: 'numeric' }) : 'N/A'); const status = document.createElement('p'); const now = new Date().getTime(); let statusText; if (startDateObj && now < startDateObj.timestamp * 1000) { statusText = 'Chưa bắt đầu'; } else if (endDateObj && now > endDateObj.timestamp * 1000) { statusText = 'Đã kết thúc'; } else { statusText = 'Đang diễn ra'; } status.textContent = 'Trạng thái: ' + statusText; const detailButton = document.createElement('button'); detailButton.textContent = 'Chi tiết'; detailButton.classList.add('detail button'); detailButton.onclick = function() { showRoomDetails(quiz.id); }; quizCard.appendChild(quizName); quizCard.appendChild(startTime); quizCard.appendChild(endTime); quizCard.appendChild(status); quizCard.appendChild(detailButton); examListBody.appendChild(quizCard); }); }, error: function(error) { console.error("Lỗi khi gọi API để lấy danh sách quiz:", error); } }); } function showRoomDetails(quizId) { // Hiển thị phần quiz details const quizDetailsSection = document.getElementById('quiz details'); quizDetailsSection.style.display = 'block'; const roomListContainer = document.getElementById('quiz list body'); roomListContainer.innerHTML = ''; // Xóa nội dung cũ nếu có // Gọi API để lấy danh sách phòng thi (nhóm) theo quizId $.ajax({ url: apiUrl, type: "GET", data: { wstoken: "2d34540397cf85bcac6b40d927dbdc6a", wsfunction: "local_activitygroups_get_allowed_groups", activityid: quizId, // ID của quiz để lấy các nhóm phòng thi moodlewsrestformat: "json" }, success: function(response) { console.log("Danh sách phòng thi (nhóm):", response); // Xử lý và hiển thị danh sách phòng thi (nhóm) const rooms = response; // API trả về một mảng các nhóm rooms.forEach(room => { const roomCard = document.createElement('div'); roomCard.className = 'room card'; const roomName = document.createElement('h3'); roomName.textContent = room.name; // Tên nhóm đại diện cho phòng thi const totalCandidates = document.createElement('p'); totalCandidates.textContent = `Tổng số thí sinh: ${room.count || 'N/A'}`; // Tạo thanh tiến trình đơn giản để hiển thị tỷ lệ hoàn thành const progressBar = document.createElement('div'); progressBar.className = 'progress bar'; const completedDiv = document.createElement('div'); completedDiv.className = 'completed'; completedDiv.style.width = `${(room.completed / room.count) * 100}%`; completedDiv.textContent = `Đã thi xong: ${room.completed}`; const inProgressDiv = document.createElement('div'); inProgressDiv.className = 'in progress'; inProgressDiv.style.width = `${(room.inProgress / room.count) * 100}%`; inProgressDiv.textContent = `Đang thi: ${room.inProgress}`; const notStartedDiv = document.createElement('div'); notStartedDiv.className = 'not started'; notStartedDiv.style.width = `${(room.notStarted / room.count) * 100}%`; notStartedDiv.textContent = `Chưa vào thi: ${room.notStarted}`; // Thêm các phần tử vào thanh tiến trình progressBar.appendChild(completedDiv); progressBar.appendChild(inProgressDiv); progressBar.appendChild(notStartedDiv); // Thêm các phần tử vào roomCard roomCard.appendChild(roomName); roomCard.appendChild(totalCandidates); roomCard.appendChild(progressBar); // Thêm roomCard vào container của danh sách phòng thi roomListContainer.appendChild(roomCard); }); }, error: function(error) { console.error("Lỗi khi gọi API để lấy danh sách phòng thi:", error); } }); } function fetchTotalStudents(courseId) { console.log("Gọi fetchTotalStudents", courseId); document.getElementById('total students count').textContent = "..."; document.getElementById('total students with access').textContent = "..."; document.getElementById('not logged in count').textContent = "..."; $.ajax({ url: apiUrl, type: "GET", data: { wstoken: "360880ac1bc5a1c97588ec7c6ef71d33", wsfunction: "local_course_lastaccess_get_last_logins", courseid: courseId, moodlewsrestformat: "json" }, success: function(response) { const total_students = response.total_students; const total_students_with_access = response.total_students_with_access; const notLoggedIn = total_students total_students_with_access; document.getElementById('total students count').textContent = total_students; document.getElementById('total students with access').textContent = total_students_with_access; document.getElementById('not logged in count').textContent = notLoggedIn; }, error: function(error) { console.error("Lỗi khi gọi API để lấy danh sách thí sinh:", error); document.getElementById('total students count').textContent = "Không tải được"; document.getElementById('total students with access').textContent = "Không tải được"; document.getElementById('not logged in count').textContent = "Không tải được"; } }); } // Hàm để cập nhật danh sách quiz và thí sinh định kỳ mỗi 5 giây function updateQuizListPeriodically(courseId) { if (window.quizUpdateInterval) { clearInterval(window.quizUpdateInterval); } window.quizUpdateInterval = setInterval(() => { fetchQuizList(courseId); fetchTotalStudents(courseId); showRoomDetails(quizId); }, 5000); // Cập nhật mỗi 5 giây } // Gọi hàm để lấy danh sách khóa học khi trang được tải document.addEventListener('DOMContentLoaded', fetchCourseList); </script> </body> </html>
