| <!DOCTYPE html> |
| <html lang="en"> |
|
|
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> |
| <title>课表叠加查询</title> |
| <style> |
| |
| body { |
| font-family: 'Roboto', Arial, sans-serif; |
| margin: 0; |
| padding: 0; |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 25%, #f093fb 50%, #f5576c 75%, #4facfe 100%); |
| background-size: 400% 400%; |
| animation: gradientShift 15s ease infinite; |
| color: #333; |
| position: relative; |
| overflow-x: hidden; |
| } |
| |
| @keyframes gradientShift { |
| 0% { background-position: 0% 50%; } |
| 50% { background-position: 100% 50%; } |
| 100% { background-position: 0% 50%; } |
| } |
| |
| body::before { |
| content: ''; |
| position: fixed; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| background: rgba(255, 255, 255, 0.1); |
| backdrop-filter: blur(10px); |
| z-index: -1; |
| pointer-events: none; |
| } |
| |
| h1 { |
| text-align: center; |
| color: #fff; |
| font-size: 28px; |
| margin: 20px 0; |
| text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); |
| font-weight: 700; |
| } |
| |
| .controls { |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| margin: 20px; |
| padding: 15px; |
| background: rgba(255, 255, 255, 0.15); |
| backdrop-filter: blur(15px); |
| border-radius: 15px; |
| box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); |
| border: 1px solid rgba(255, 255, 255, 0.2); |
| gap: 20px; |
| flex-wrap: wrap; |
| } |
| |
| .controls label { |
| font-weight: bold; |
| color: #fff; |
| text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); |
| } |
| |
| .controls select, |
| .controls button { |
| padding: 10px 15px; |
| font-size: 14px; |
| border: 1px solid rgba(255, 255, 255, 0.3); |
| border-radius: 8px; |
| background: rgba(255, 255, 255, 0.9); |
| color: #333; |
| font-weight: bold; |
| cursor: pointer; |
| transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); |
| backdrop-filter: blur(10px); |
| box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| } |
| |
| .controls select:hover, |
| .controls button:hover { |
| background: rgba(255, 255, 255, 0.95); |
| transform: translateY(-1px); |
| box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15); |
| } |
| |
| .nav-button { |
| background: rgba(255, 255, 255, 0.2) !important; |
| color: #fff !important; |
| border: 1px solid rgba(255, 255, 255, 0.3) !important; |
| } |
| |
| .nav-button:hover { |
| background: rgba(255, 255, 255, 0.3) !important; |
| } |
| |
| .class-legend { |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| margin: 20px; |
| padding: 15px; |
| background: rgba(255, 255, 255, 0.15); |
| backdrop-filter: blur(15px); |
| border-radius: 15px; |
| box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); |
| border: 1px solid rgba(255, 255, 255, 0.2); |
| gap: 20px; |
| flex-wrap: wrap; |
| } |
| |
| .legend-item { |
| display: flex; |
| align-items: center; |
| gap: 8px; |
| color: #fff; |
| font-weight: bold; |
| text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); |
| } |
| |
| .legend-color { |
| width: 20px; |
| height: 20px; |
| border-radius: 4px; |
| border: 2px solid rgba(255, 255, 255, 0.3); |
| } |
| |
| .time-header { |
| display: grid; |
| grid-template-columns: 80px repeat(7, 1fr); |
| gap: 2px; |
| margin: 20px; |
| padding: 15px; |
| background: rgba(255, 255, 255, 0.9); |
| border-radius: 10px; |
| box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); |
| font-weight: bold; |
| text-align: center; |
| } |
| |
| .schedule-container { |
| display: grid; |
| grid-template-columns: 80px repeat(7, 1fr); |
| gap: 2px; |
| margin: 20px; |
| background: rgba(255, 255, 255, 0.9); |
| border-radius: 10px; |
| overflow: hidden; |
| box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); |
| } |
| |
| .time-column { |
| display: flex; |
| flex-direction: column; |
| background: #f8f9fa; |
| font-weight: bold; |
| text-align: center; |
| } |
| |
| .time-slot { |
| padding: 10px 5px; |
| border-bottom: 1px solid #ddd; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| height: 80px; |
| font-size: 12px; |
| } |
| |
| .day { |
| display: flex; |
| flex-direction: column; |
| } |
| |
| .day-slot { |
| height: 90px; |
| border-bottom: 1px solid #ddd; |
| position: relative; |
| padding: 5px; |
| display: flex; |
| flex-direction: column; |
| gap: 1px; |
| overflow: hidden; |
| } |
| |
| .course { |
| background: rgba(167, 216, 222, 0.8); |
| color: #333; |
| border-radius: 4px; |
| padding: 10px 5px; |
| font-size: 16px; |
| font-weight: bold; |
| text-align: center; |
| margin: 1px; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| border: 1px solid rgba(0, 0, 0, 0.1); |
| flex: 1; |
| display: flex; |
| flex-direction: column; |
| justify-content: center; |
| height: 80px; |
| overflow: hidden; |
| word-wrap: break-word; |
| } |
| |
| .course:hover { |
| transform: scale(1.05); |
| box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); |
| z-index: 10; |
| } |
| |
| .course-23 { background: rgba(255, 182, 193, 0.8); } |
| .course-24-1 { background: rgba(173, 216, 230, 0.8); } |
| .course-24-2 { background: rgba(144, 238, 144, 0.8); } |
| .course-24-3 { background: rgba(255, 218, 185, 0.8); } |
| .course-24-info { background: rgba(221, 160, 221, 0.8); } |
| |
| .free-slot { |
| background: rgba(144, 238, 144, 0.3); |
| color: #2d5a2d; |
| border-radius: 4px; |
| padding: 4px; |
| font-size: 14px; |
| font-weight: bold; |
| text-align: center; |
| margin: 1px; |
| flex: 1; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| border: 1px dashed #90ee90; |
| min-height: 0; |
| word-wrap: break-word; |
| white-space: normal; |
| line-height: 1.2; |
| } |
| |
| |
| .modal { |
| display: none; |
| position: fixed; |
| z-index: 1000; |
| left: 0; |
| top: 0; |
| width: 100%; |
| height: 100%; |
| background-color: rgba(0, 0, 0, 0.5); |
| backdrop-filter: blur(5px); |
| } |
| |
| .modal-content { |
| background: linear-gradient(135deg, #fff 0%, #f8f9fa 100%); |
| margin: 5% auto; |
| padding: 0; |
| border-radius: 15px; |
| width: 90%; |
| max-width: 600px; |
| box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); |
| animation: modalSlideIn 0.3s ease-out; |
| } |
| |
| @keyframes modalSlideIn { |
| from { |
| opacity: 0; |
| transform: translateY(-50px) scale(0.9); |
| } |
| to { |
| opacity: 1; |
| transform: translateY(0) scale(1); |
| } |
| } |
| |
| .modal-header { |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| color: white; |
| padding: 20px; |
| border-radius: 15px 15px 0 0; |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| } |
| |
| .modal-title { |
| font-size: 20px; |
| font-weight: bold; |
| margin: 0; |
| } |
| |
| .close { |
| color: white; |
| font-size: 28px; |
| font-weight: bold; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| } |
| |
| .close:hover { |
| transform: scale(1.1); |
| text-shadow: 0 0 10px rgba(255, 255, 255, 0.5); |
| } |
| |
| #courseDetails { |
| padding: 20px; |
| max-height: 400px; |
| overflow-y: auto; |
| } |
| |
| .course-info { |
| margin: 10px 0; |
| padding: 10px; |
| background: rgba(0, 0, 0, 0.05); |
| border-radius: 8px; |
| border-left: 4px solid #667eea; |
| } |
| |
| |
| @media (max-width: 768px) { |
| body { |
| font-size: 14px; |
| padding: 5px; |
| } |
| |
| h1 { |
| font-size: 20px; |
| margin: 15px 0; |
| } |
| |
| .controls { |
| display: flex; |
| flex-direction: column; |
| gap: 10px; |
| padding: 10px; |
| margin: 5px; |
| } |
| |
| .controls div { |
| flex: none; |
| width: 100%; |
| text-align: center; |
| } |
| |
| .controls select, |
| .controls button { |
| padding: 8px 12px; |
| font-size: 14px; |
| margin: 2px; |
| min-width: 80px; |
| } |
| |
| .time-header { |
| grid-template-columns: 50px repeat(7, minmax(0, 1fr)); |
| margin: 5px; |
| gap: 1px; |
| font-size: 12px; |
| padding: 12px 5px; |
| } |
| |
| .schedule-container { |
| grid-template-columns: 50px repeat(7, minmax(0, 1fr)); |
| margin: 5px; |
| gap: 1px; |
| display: grid; |
| background-color: #fff; |
| border-radius: 10px; |
| overflow: hidden; |
| box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); |
| } |
| |
| .day { |
| padding: 3px; |
| border: 1px solid #ccc; |
| border-radius: 5px; |
| } |
| |
| .time-column { |
| grid-column: 1; |
| text-align: center; |
| font-size: 12px; |
| padding: 15px 2px; |
| display: flex; |
| flex-direction: column; |
| justify-content: center; |
| line-height: 1.2; |
| } |
| |
| .time-slot { |
| height: 152px; |
| font-size: 12px; |
| padding: 3px; |
| min-height: 100px; |
| } |
| |
| .day-slot { |
| min-height: 160px; |
| padding: 0px; |
| } |
| |
| .course { |
| font-size: 14px; |
| padding: 0px; |
| margin: 1px; |
| height: auto; |
| width: auto; |
| word-break: break-word; |
| white-space: normal; |
| overflow-wrap: break-word; |
| } |
| |
| .free-slot { |
| background: rgba(144, 238, 144, 0.3); |
| color: #2d5a2d; |
| border-radius: 4px; |
| padding: 0px; |
| font-size: 14px; |
| font-weight: bold; |
| text-align: center; |
| margin: 0px; |
| flex: 1; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| border: 1px dashed #90ee90; |
| min-height: 0; |
| word-wrap: break-word; |
| white-space: normal; |
| line-height: 1.1; |
| } |
| |
| .course strong { |
| font-size: 11px; |
| } |
| |
| .course .teacher, |
| .course .class, |
| .course .period { |
| font-size: 11px; |
| } |
| |
| |
| .modal-content { |
| width: 95%; |
| margin: 5% auto; |
| padding: 15px; |
| } |
| |
| .modal-title { |
| font-size: 18px; |
| } |
| |
| .course-detail { |
| margin: 8px 0; |
| padding: 8px; |
| } |
| |
| .course-detail .course-name { |
| font-size: 16px; |
| } |
| |
| .course-detail .course-info { |
| font-size: 14px; |
| } |
| } |
| |
| |
| .course-name { |
| font-size: 16px; |
| font-weight: bold; |
| color: #333; |
| margin-bottom: 10px; |
| text-shadow: 0 0 10px rgba(255, 255, 255, 0.3); |
| } |
| |
| .course-info { |
| margin: 8px 0; |
| padding: 5px 0; |
| color: #555; |
| border-bottom: 1px solid #eee; |
| text-shadow: 0 0 5px rgba(255, 255, 255, 0.2); |
| } |
| |
| .course-info:last-child { |
| border-bottom: none; |
| } |
| |
| .course-section { |
| background: #f8f9fa; |
| border-radius: 8px; |
| padding: 15px; |
| margin: 10px 0; |
| border-left: 4px solid #007bff; |
| display: flex; |
| flex-direction: column; |
| min-height: 120px; |
| } |
| |
| |
| .course .course-name { |
| font-size: 9px; |
| line-height: 1.1; |
| margin-bottom: 2px; |
| overflow: hidden; |
| text-overflow: ellipsis; |
| white-space: nowrap; |
| } |
| |
| .course .course-info { |
| font-size: 8px; |
| line-height: 1.0; |
| margin: 1px 0; |
| overflow: hidden; |
| text-overflow: ellipsis; |
| display: -webkit-box; |
| -webkit-line-clamp: 2; |
| -webkit-box-orient: vertical; |
| } |
| |
| .free-section { |
| background: #d4edda; |
| border-radius: 8px; |
| padding: 15px; |
| margin: 10px 0; |
| border-left: 4px solid #28a745; |
| display: flex; |
| flex-direction: column; |
| min-height: 100px; |
| } |
| |
| .student-list { |
| background: #fff; |
| border-radius: 5px; |
| padding: 10px; |
| margin-top: auto; |
| border: 1px solid #dee2e6; |
| font-size: 14px; |
| line-height: 1.4; |
| flex-grow: 1; |
| } |
| |
| .course-info { |
| margin: 3px 0; |
| line-height: 1.4; |
| } |
| |
| .course-name { |
| font-weight: bold; |
| font-size: 1.1em; |
| margin-bottom: 8px; |
| padding-bottom: 5px; |
| border-bottom: 1px solid #eee; |
| } |
| </style> |
| </head> |
|
|
| <body> |
| <h1>大数据专业课表叠加查询</h1> |
| |
| <div class="controls"> |
| <div> |
| <label for="week-select">周次:</label> |
| <select id="week-select"></select> |
| </div> |
| <div> |
| <button class="nav-button" onclick="window.location.href='/'">返回主页</button> |
| <button class="nav-button" onclick="window.location.href='/students'">学生查询</button> |
| <button class="nav-button" onclick="window.location.href='/teachers'">教师查询</button> |
| <button class="nav-button" onclick="window.location.href='/classrooms'">教室查询</button> |
| </div> |
| </div> |
| |
|
|
| |
| <div class="time-header" id="time-header"> |
| <div>时间</div> |
| <div><span>09/02</span><br><span>周一</span></div> |
| <div><span>09/03</span><br><span>周二</span></div> |
| <div><span>09/04</span><br><span>周三</span></div> |
| <div><span>09/05</span><br><span>周四</span></div> |
| <div><span>09/06</span><br><span>周五</span></div> |
| <div><span>09/07</span><br><span>周六</span></div> |
| <div><span>09/08</span><br><span>周日</span></div> |
| </div> |
| |
| <div class="schedule-container" id="schedule"> |
| <div class="time-column"> |
| <div class="time-slot">1-3节</div> |
| <div class="time-slot">4-5节</div> |
| <div class="time-slot">6-8节</div> |
| <div class="time-slot">9-11节</div> |
| </div> |
| </div> |
| |
| |
| <div id="courseModal" class="modal"> |
| <div class="modal-content"> |
| <div class="modal-header"> |
| <div class="modal-title">时间段详情</div> |
| <span class="close" onclick="closeModal()">×</span> |
| </div> |
| <div id="courseDetails"> |
| |
| </div> |
| </div> |
| </div> |
| |
| <script> |
| let currentWeek = getCurrentWeek(); |
| |
| function initializeWeeks() { |
| const weekSelect = document.getElementById("week-select"); |
| for (let i = 1; i <= 18; i++) { |
| const option = document.createElement("option"); |
| option.value = i; |
| option.textContent = `第${i}周`; |
| if (i === currentWeek) { |
| option.selected = true; |
| } |
| weekSelect.appendChild(option); |
| } |
| } |
| |
| function getCurrentWeek() { |
| const firstWeekStartDate = new Date("2025-09-01"); |
| const today = new Date(); |
| const timeDifference = today - firstWeekStartDate; |
| const daysDifference = Math.floor(timeDifference / (1000 * 60 * 60 * 24)); |
| return Math.floor(daysDifference / 7) + 1; |
| } |
| |
| function updateTimeHeader(firstDayDate) { |
| const timeHeader = document.getElementById("time-header"); |
| const dayNames = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]; |
| |
| |
| const mondayDate = new Date(firstDayDate); |
| const dayOfWeek = mondayDate.getDay(); |
| const daysToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; |
| mondayDate.setDate(mondayDate.getDate() + daysToMonday); |
| |
| for (let i = 1; i <= 7; i++) { |
| const dayDate = new Date(mondayDate); |
| dayDate.setDate(mondayDate.getDate() + i - 1); |
| const dayDiv = timeHeader.children[i]; |
| dayDiv.innerHTML = `<span>${(dayDate.getMonth() + 1).toString().padStart(2, '0')}/${dayDate.getDate().toString().padStart(2, '0')}</span><br><span>${dayNames[i - 1]}</span>`; |
| } |
| } |
| |
| function getClassColor(className) { |
| if (className === "23大数据1区") return "course-23"; |
| if (className === "24大数据1区") return "course-24-1"; |
| if (className === "24大数据2区") return "course-24-2"; |
| if (className === "24大数据3区") return "course-24-3"; |
| if (className === "24信息安全技术应用1区") return "course-24-info"; |
| return "course"; |
| } |
| |
| function formatFreeClasses(freeClasses) { |
| if (freeClasses.length === 0) return ''; |
| |
| |
| const allClasses = ["23大数据1区", "24大数据1区", "24大数据2区", "24大数据3区", "24信息安全技术应用1区"]; |
| if (freeClasses.length === allClasses.length) { |
| return '实验室都没课'; |
| } |
| |
| |
| const class23 = freeClasses.filter(cls => cls.includes('23')); |
| const class24Data = freeClasses.filter(cls => cls.includes('24') && cls.includes('大数据')); |
| const class24Info = freeClasses.filter(cls => cls.includes('24') && cls.includes('信息安全')); |
| |
| let result = []; |
| |
| |
| if (class23.length > 0) { |
| result.push(class23.join('、')); |
| } |
| |
| |
| if (class24Data.length > 0) { |
| if (class24Data.length >= 3) { |
| result.push('24级大数据全区'); |
| } else if (class24Data.length === 2) { |
| const regions = class24Data.map(cls => cls.match(/\d+区/)[0]); |
| result.push(`24级大数据${regions.join('、')}`); |
| } else { |
| result.push(class24Data[0]); |
| } |
| } |
| |
| |
| if (class24Info.length > 0) { |
| result.push(class24Info.join('、')); |
| } |
| |
| return result.join('、'); |
| } |
| |
| function loadScheduleOverlap() { |
| const selectedWeek = document.getElementById("week-select").value; |
| const apiUrl = `/api/schedule_overlap?week=${selectedWeek}`; |
| |
| fetch(apiUrl) |
| .then(response => response.json()) |
| .then(data => { |
| const scheduleContainer = document.getElementById("schedule"); |
| |
| |
| scheduleContainer.innerHTML = ` |
| <div class='time-column'> |
| <div class='time-slot'>1-3节</div> |
| <div class='time-slot'>4-5节</div> |
| <div class='time-slot'>6-8节</div> |
| <div class='time-slot'>9-11节</div> |
| </div> |
| `; |
| |
| |
| const firstDayDate = new Date(data[0]?.日期 || "2025-09-01"); |
| updateTimeHeader(firstDayDate); |
| |
| |
| const scheduleData = {}; |
| for (let day = 1; day <= 7; day++) { |
| scheduleData[day] = { |
| 1: [], |
| 2: [], |
| 3: [], |
| 4: [] |
| }; |
| } |
| |
| |
| data.forEach(course => { |
| const day = course.星期; |
| const startPeriod = course.节次[0]; |
| let timeSlot = 1; |
| |
| if (startPeriod >= 1 && startPeriod <= 3) timeSlot = 1; |
| else if (startPeriod >= 4 && startPeriod <= 5) timeSlot = 2; |
| else if (startPeriod >= 6 && startPeriod <= 8) timeSlot = 3; |
| else if (startPeriod >= 9 && startPeriod <= 11) timeSlot = 4; |
| |
| scheduleData[day][timeSlot].push(course); |
| }); |
| |
| |
| for (let day = 1; day <= 7; day++) { |
| const dayDiv = document.createElement("div"); |
| dayDiv.className = "day"; |
| |
| for (let timeSlot = 1; timeSlot <= 4; timeSlot++) { |
| const slotDiv = document.createElement("div"); |
| slotDiv.className = "day-slot"; |
| |
| const courses = scheduleData[day][timeSlot]; |
| |
| |
| const allClasses = ["23大数据1区", "24大数据1区", "24大数据2区", "24大数据3区", "24信息安全技术应用1区"]; |
| const classesWithCourse = courses.map(c => c.班级); |
| const freeClasses = allClasses.filter(cls => !classesWithCourse.includes(cls)); |
| |
| if (freeClasses.length > 0) { |
| |
| const freeDiv = document.createElement("div"); |
| freeDiv.className = "free-slot"; |
| const freeText = formatFreeClasses(freeClasses); |
| |
| if (freeText.includes('没课')) { |
| freeDiv.innerHTML = freeText; |
| } else { |
| freeDiv.innerHTML = freeText + "没课"; |
| } |
| freeDiv.onclick = () => showTimeSlotDetails(courses, freeClasses, day, timeSlot); |
| slotDiv.appendChild(freeDiv); |
| } else { |
| |
| const busyDiv = document.createElement("div"); |
| busyDiv.className = "course"; |
| busyDiv.innerHTML = "全部有课"; |
| busyDiv.onclick = () => showTimeSlotDetails(courses, freeClasses, day, timeSlot); |
| slotDiv.appendChild(busyDiv); |
| } |
| |
| dayDiv.appendChild(slotDiv); |
| } |
| |
| scheduleContainer.appendChild(dayDiv); |
| } |
| }) |
| .catch(error => { |
| console.error('加载课表数据失败:', error); |
| alert('加载课表数据失败,请稍后重试'); |
| }); |
| } |
| |
| |
| const studentCache = new Map(); |
| |
| async function getStudentList(className) { |
| if (studentCache.has(className)) { |
| return studentCache.get(className); |
| } |
| |
| try { |
| const response = await fetch(`/api/class_students?class_name=${encodeURIComponent(className)}`); |
| const students = await response.json(); |
| studentCache.set(className, students); |
| return students; |
| } catch (error) { |
| console.error('获取学生名单失败:', error); |
| return []; |
| } |
| } |
| |
| async function showTimeSlotDetails(courses, freeClasses, day, timeSlot) { |
| const dayNames = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]; |
| const timeSlotNames = ["1-3节", "4-5节", "6-8节", "9-11节"]; |
| |
| let detailsHtml = `<h3>${dayNames[day-1]} ${timeSlotNames[timeSlot-1]}</h3>`; |
| |
| |
| if (freeClasses.length > 0) { |
| detailsHtml += `<h4 style="color: #28a745; margin-bottom: 15px;">🟢 没有课的区队:</h4>`; |
| |
| for (const freeClass of freeClasses) { |
| const students = await getStudentList(freeClass); |
| |
| detailsHtml += ` |
| <div class="free-section"> |
| <div class="course-name" style="color: #28a745;">${freeClass}</div> |
| <div class="student-list"> |
| <strong>空闲学生名单:</strong><br> |
| ${students.length > 0 ? students.join('、') : '暂无学生信息'} |
| </div> |
| </div> |
| `; |
| } |
| } |
| |
| |
| if (courses.length > 0) { |
| detailsHtml += `<h4 style="color: #dc3545; margin-top: 20px; margin-bottom: 15px;">📚 有课的区队:</h4>`; |
| |
| |
| const classCourses = {}; |
| courses.forEach(course => { |
| if (!classCourses[course.班级]) { |
| classCourses[course.班级] = []; |
| } |
| classCourses[course.班级].push(course); |
| }); |
| |
| for (const [className, classCourseList] of Object.entries(classCourses)) { |
| |
| const students = await getStudentList(className); |
| |
| |
| const courseNames = classCourseList.map(course => { |
| |
| let courseName = course.课程; |
| |
| const match = courseName.match(/\[[^\]]+\]\[([^\]]+)\]/); |
| if (match) { |
| courseName = match[1]; |
| } else { |
| |
| courseName = courseName.replace(/\[[^\]]*\]/g, ''); |
| } |
| |
| courseName = courseName.replace(/-\d+$/, ''); |
| return courseName.trim(); |
| }); |
| const uniqueCourseNames = [...new Set(courseNames)]; |
| |
| let courseListHtml; |
| if (uniqueCourseNames.length <= 3) { |
| courseListHtml = uniqueCourseNames.join('、'); |
| } else { |
| const firstThree = uniqueCourseNames.slice(0, 3); |
| courseListHtml = firstThree.join('、') + `等${uniqueCourseNames.length}门课程`; |
| } |
| |
| detailsHtml += ` |
| <div class="course-section"> |
| <div class="course-name">${className}</div> |
| <div class="course-info"> |
| ${courseListHtml} |
| </div> |
| <div class="student-list"> |
| <strong>学生名单:</strong><br> |
| ${students.length > 0 ? students.join('、') : '暂无学生信息'} |
| </div> |
| </div> |
| `; |
| } |
| } |
| |
| document.getElementById("courseDetails").innerHTML = detailsHtml; |
| document.getElementById("courseModal").style.display = "block"; |
| } |
| |
| function closeModal() { |
| document.getElementById("courseModal").style.display = "none"; |
| } |
| |
| |
| window.onclick = function(event) { |
| const modal = document.getElementById("courseModal"); |
| if (event.target === modal) { |
| modal.style.display = "none"; |
| } |
| } |
| |
| |
| document.getElementById("week-select").addEventListener("change", loadScheduleOverlap); |
| |
| |
| initializeWeeks(); |
| loadScheduleOverlap(); |
| </script> |
| </body> |
|
|
| </html> |