| | <!DOCTYPE html> |
| | <html lang="en"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>教师课表</title> |
| | <style> |
| | |
| | body { |
| | font-family: 'Roboto', Arial, sans-serif; |
| | margin: 0; |
| | padding: 0; |
| | background-color: #f4f6f9; |
| | color: #333; |
| | } |
| | |
| | h1 { |
| | text-align: center; |
| | margin: 20px 0; |
| | font-size: 28px; |
| | font-weight: bold; |
| | color: #0078d4; |
| | letter-spacing: 1.2px; |
| | } |
| | |
| | |
| | .controls { |
| | display: flex; |
| | justify-content: space-between; |
| | align-items: center; |
| | padding: 15px 20px; |
| | background-color: #0078d4; |
| | color: white; |
| | border-radius: 10px; |
| | margin: 10px 20px; |
| | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); |
| | } |
| | |
| | .controls > div { |
| | flex: 1; |
| | text-align: center; |
| | } |
| | |
| | .nav-button { |
| | padding: 10px 15px; |
| | font-size: 14px; |
| | border: none; |
| | border-radius: 5px; |
| | background-color: #fff; |
| | color: #0078d4; |
| | font-weight: bold; |
| | cursor: pointer; |
| | transition: all 0.3s ease; |
| | } |
| | .nav-button:hover { |
| | background-color: #eaf4fc; |
| | } |
| | .nav-button:focus { |
| | outline: none; |
| | box-shadow: 0 0 5px rgba(0, 120, 212, 0.8); |
| | } |
| | |
| | |
| | .controls label { |
| | font-weight: bold; |
| | margin-right: 10px; |
| | } |
| | |
| | .controls select, .controls button { |
| | padding: 8px 12px; |
| | font-size: 14px; |
| | border: none; |
| | border-radius: 5px; |
| | background-color: #fff; |
| | color: #0078d4; |
| | font-weight: bold; |
| | cursor: pointer; |
| | transition: all 0.3s ease; |
| | } |
| | |
| | .controls select:hover, .controls button:hover { |
| | background-color: #eaf4fc; |
| | } |
| | |
| | .controls select:focus, .controls button:focus { |
| | outline: none; |
| | box-shadow: 0 0 5px rgba(0, 120, 212, 0.8); |
| | } |
| | |
| | |
| | .time-header { |
| | display: grid; |
| | grid-template-columns: 70px repeat(7, 1fr); |
| | background: linear-gradient(135deg, #0078d4 0%, #0056a6 100%); |
| | color: white; |
| | text-align: center; |
| | margin: 10px 20px; |
| | font-size: 14px; |
| | font-weight: bold; |
| | padding: 10px 0; |
| | border-radius: 8px; |
| | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
| | } |
| | |
| | .time-header div { |
| | border-right: 1px solid #f0f0f0; |
| | padding: 5px; |
| | transition: transform 0.2s ease-in-out, background-color 0.2s; |
| | } |
| | |
| | .time-header div:last-child { |
| | border-right: none; |
| | } |
| | |
| | |
| | .time-header div:hover { |
| | transform: translateY(-2px); |
| | background-color: rgba(255, 255, 255, 0.2); |
| | cursor: pointer; |
| | } |
| | |
| | |
| | |
| | .time-column { |
| | background-color: #f8f9fa; |
| | text-align: center; |
| | font-size: 14px; |
| | display: flex; |
| | flex-direction: column; |
| | border-right: 1px solid #ddd; |
| | } |
| | |
| | .time-column div { |
| | flex: 1; |
| | padding: 10px 0; |
| | border-top: 1px solid #ddd; |
| | font-weight: bold; |
| | } |
| | |
| | .time-column div:first-child { |
| | border-top: none; |
| | } |
| | |
| | |
| | .day { |
| | background-color: white; |
| | border: 1px solid #ddd; |
| | padding: 5px; |
| | height: 500px; |
| | display: flex; |
| | flex-direction: column; |
| | position: relative; |
| | border-radius: 0 0 8px 8px; |
| | overflow: hidden; |
| | transition: transform 0.3s ease, box-shadow 0.3s ease; |
| | } |
| | |
| | .day:hover { |
| | transform: translateY(-5px); |
| | box-shadow: 0 8px 15px rgba(0, 0, 0, 0.15); |
| | } |
| | |
| | |
| | .time-slot { |
| | flex: 1; |
| | position: relative; |
| | border-top: 1px solid #eee; |
| | overflow: hidden; |
| | } |
| | |
| | .time-slot:first-child { |
| | border-top: none; |
| | } |
| | |
| | |
| | .time-slot .course { |
| | position: absolute; |
| | background-color: #a7d8de; |
| | color: #333; |
| | border-radius: 5px; |
| | padding: 25px; |
| | font-size: 15px; |
| | font-weight: bold; |
| | text-align: center; |
| | margin: 5px; |
| | width: 75%; |
| | |
| | box-shadow: 2px 4px 8px rgba(0, 0, 0, 0.1); |
| | transition: transform 0.3s ease, background-color 0.3s ease; |
| | height: 50%; |
| | } |
| | |
| | |
| | .search-container { |
| | |
| | |
| | position: relative; |
| | } |
| | |
| | .teacher-search { |
| | width: 150px; |
| | padding: 8px 12px; |
| | font-size: 14px; |
| | border: 1px solid #0078d4; |
| | border-radius: 5px; |
| | color: #333; |
| | box-sizing: border-box; |
| | } |
| | |
| | .search-results { |
| | position: absolute; |
| | top: calc(100% + 4px); |
| | left: 42.5%; |
| | width: 150px; |
| | background: #f0f8ff; |
| | border: 1px solid #0078d4; |
| | max-height: 150px; |
| | overflow-y: auto; |
| | z-index: 1000; |
| | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
| | border-radius: 5px; |
| | } |
| | |
| | .search-results div { |
| | padding: 8px 12px; |
| | font-size: 14px; |
| | color: #333; |
| | cursor: pointer; |
| | transition: background 0.3s, color 0.3s; |
| | } |
| | |
| | .search-results div:hover { |
| | background-color: #0078d4; |
| | color: #fff; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | .schedule-container { |
| | display: grid; |
| | grid-template-columns: 70px repeat(7, 1fr); |
| | gap: 2px; |
| | margin: 10px 20px; |
| | background-color: #fff; |
| | border-radius: 10px; |
| | overflow: hidden; |
| | box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); |
| | } |
| | @media (max-width: 768px) { |
| | body { |
| | font-size: 14px; |
| | padding: 5px; |
| | } |
| | h1 { |
| | font-size: 20px; |
| | margin: 15px 0; |
| | } |
| | .controls { |
| | display: flex; |
| | flex-direction: row; |
| | flex-wrap: nowrap; |
| | justify-content: space-around; |
| | align-items: center; |
| | padding: 10px 5px; |
| | margin: 5px; |
| | gap: 5px; |
| | } |
| | .controls select, |
| | .controls button { |
| | padding: 6px; |
| | font-size: 12px; |
| | margin: 2px; |
| | min-width: 80px; |
| | } |
| | |
| | .time-header { |
| | grid-template-columns: 25px repeat(7, 1fr); |
| | font-size: 12px; |
| | padding: 12px 5px; |
| | width: 95%; |
| | margin: 10px 5px; |
| | } |
| | .schedule-container { |
| | grid-template-columns: 22px repeat(7, minmax(0, 1fr)); |
| | margin: 3px; |
| | display: grid; |
| | gap: 1px; |
| | |
| | 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: 15px; |
| | display: flex; |
| | flex-direction: column; |
| | justify-content: center; |
| | line-height: 1.2; |
| | |
| | } |
| | .time-slot .course { |
| | font-size: 12px; |
| | padding: 1px; |
| | |
| | width: auto; |
| | word-break: break-word; |
| | white-space: normal; |
| | overflow-wrap: break-word; |
| | margin: 1px; |
| | height: 90%; |
| | } |
| | .teacher-search { |
| | width: 100%; |
| | padding: 8px 12px; |
| | font-size: 14px; |
| | border: 1px solid #0078d4; |
| | border-radius: 5px; |
| | color: #333; |
| | box-sizing: border-box; |
| | } |
| | .search-results { |
| | position: absolute; |
| | top: calc(100% + 2px); |
| | left: 0%; |
| | width: 100%; |
| | background: #f0f8ff; |
| | border: 1px solid #0078d4; |
| | max-height: 150px; |
| | overflow-y: auto; |
| | z-index: 1000; |
| | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
| | border-radius: 5px; |
| | box-sizing: border-box; |
| | } |
| | } |
| | </style> |
| | </head> |
| | <body> |
| | <h1>学生课表</h1> |
| | <div class="controls"> |
| |
|
| |
|
| | <div class="search-container"> |
| | <label for="teacher-search">学生:</label> |
| | <input type="text" id="teacher-search" class="teacher-search" placeholder="搜索学生名字"> |
| | <div id="search-results" class="search-results"></div> |
| | </div> |
| |
|
| | <div> |
| | <button class="nav-button" onclick="navigateToSection_01()">班级查询</button> |
| | <button class="nav-button" onclick="navigateToSection_02()">教师查询</button> |
| | </div> |
| | <div> |
| | <label for="week-select">周次:</label> |
| | <select id="week-select"></select> |
| | </div> |
| | </div> |
| |
|
| | <div class="time-header" id="time-header"> |
| | <div>时间</div> |
| | <div>周一</div> |
| | <div>周二</div> |
| | <div>周三</div> |
| | <div>周四</div> |
| | <div>周五</div> |
| | <div>周六</div> |
| | <div>周日</div> |
| | </div> |
| |
|
| | <div class="schedule-container" id="schedule"> |
| | <div class="time-column"> |
| | <div>1-3节</div> |
| | <div>4-5节</div> |
| | <div>6-8节</div> |
| | <div>9-11节</div> |
| | </div> |
| | </div> |
| |
|
| | <script> |
| | let currentWeek = getCurrentWeek(); |
| | let teacherList = []; |
| | 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("2024-09-02"); |
| | const today = new Date(); |
| | const timeDifference = today - firstWeekStartDate; |
| | const daysDifference = Math.floor(timeDifference / (1000 * 60 * 60 * 24)); |
| | return Math.floor(daysDifference / 7) + 1; |
| | } |
| | function loadTeachers() { |
| | fetch("/api/students") |
| | .then(response => response.json()) |
| | .then(teachers => { |
| | teacherList = teachers.sort((a, b) => { |
| | if (a === "秦振凯") return -1; |
| | if (b === "秦振凯") return 1; |
| | return a.localeCompare(b); |
| | }); |
| | }) |
| | .catch(error => console.error("加载学生列表出错:", error)); |
| | } |
| | |
| | function searchTeachers() { |
| | const searchInput = document.getElementById("teacher-search").value.toLowerCase(); |
| | const searchResults = document.getElementById("search-results"); |
| | searchResults.innerHTML = ""; |
| | |
| | if (searchInput.trim() === "") { |
| | return; |
| | } |
| | |
| | const filteredTeachers = teacherList.filter(teacher => |
| | teacher.toLowerCase().includes(searchInput) |
| | ); |
| | |
| | filteredTeachers.forEach(teacher => { |
| | const resultDiv = document.createElement("div"); |
| | resultDiv.textContent = teacher; |
| | resultDiv.onclick = () => selectTeacher(teacher); |
| | searchResults.appendChild(resultDiv); |
| | }); |
| | } |
| | |
| | function selectTeacher(teacher) { |
| | document.getElementById("teacher-search").value = teacher; |
| | document.getElementById("search-results").innerHTML = ""; |
| | loadSchedule(); |
| | } |
| | |
| | function loadSchedule() { |
| | const teacherSearch = document.getElementById("teacher-search").value; |
| | const weekSelect = document.getElementById("week-select"); |
| | const selectedWeek = parseInt(weekSelect.value); |
| | const apiUrl = `/api/student_courses_v2?week=${selectedWeek}&student_name=${encodeURIComponent(teacherSearch)}`; |
| | |
| | |
| | document.getElementById("time-header").innerHTML = ''; |
| | document.getElementById("schedule").innerHTML = ` |
| | <div class='time-column'> |
| | <div>1-3节</div> |
| | <div>4-5节</div> |
| | <div>6-8节</div> |
| | <div>9-11节</div> |
| | </div> |
| | `; |
| | |
| | |
| | const firstWeekStartDate = new Date("2024-09-02"); |
| | const selectedWeekStartDate = new Date(firstWeekStartDate); |
| | selectedWeekStartDate.setDate(firstWeekStartDate.getDate() + (selectedWeek - 1) * 7); |
| | |
| | |
| | updateTimeHeader(selectedWeekStartDate); |
| | |
| | fetch(apiUrl) |
| | .then(response => response.json()) |
| | .then(data => { |
| | if (data.length === 0) { |
| | console.warn("未获取到课程数据"); |
| | return; |
| | } |
| | |
| | |
| | const groupedByDay = Array.from({ length: 7 }, () => ({ |
| | intervals: Array.from({ length: 4 }, () => []) |
| | })); |
| | |
| | |
| | data.forEach(course => { |
| | const dayIndex = course.星期 - 1; |
| | const startPeriod = course.节次[0]; |
| | |
| | let intervalIndex = 0; |
| | if (startPeriod >= 1 && startPeriod <= 3) intervalIndex = 0; |
| | else if (startPeriod >= 4 && startPeriod <= 5) intervalIndex = 1; |
| | else if (startPeriod >= 6 && startPeriod <= 8) intervalIndex = 2; |
| | else if (startPeriod >= 9 && startPeriod <= 11) intervalIndex = 3; |
| | |
| | groupedByDay[dayIndex].intervals[intervalIndex].push(course); |
| | }); |
| | |
| | |
| | const scheduleContainer = document.getElementById("schedule"); |
| | groupedByDay.forEach((dayData, dayIndex) => { |
| | const dayDiv = document.createElement("div"); |
| | dayDiv.className = "day"; |
| | |
| | dayData.intervals.forEach((intervalCourses, intervalIndex) => { |
| | const intervalDiv = document.createElement("div"); |
| | intervalDiv.className = "time-slot"; |
| | |
| | if (intervalCourses.length > 0) { |
| | const course = intervalCourses[0]; |
| | const courseDiv = document.createElement("div"); |
| | courseDiv.className = "course"; |
| | courseDiv.innerText = `${course.课程} ${course.地点}`; |
| | courseDiv.style.backgroundColor = randomColor(); |
| | intervalDiv.appendChild(courseDiv); |
| | } |
| | |
| | dayDiv.appendChild(intervalDiv); |
| | }); |
| | |
| | scheduleContainer.appendChild(dayDiv); |
| | }); |
| | }) |
| | .catch(error => console.error("加载课程表出错:", error)); |
| | } |
| | |
| | function updateTimeHeader(weekStartDate) { |
| | const timeHeader = document.getElementById("time-header"); |
| | const weekDates = generateWeekDates(weekStartDate); |
| | |
| | |
| | timeHeader.innerHTML = ` |
| | <div>时间</div> |
| | `; |
| | weekDates.forEach((date, index) => { |
| | const dayOfWeek = "一二三四五六日"[index]; |
| | const formattedDate = date.toLocaleDateString("zh-CN", { month: "2-digit", day: "2-digit" }); |
| | |
| | const headerDiv = document.createElement("div"); |
| | headerDiv.innerHTML = ` |
| | <span>${formattedDate}</span> |
| | <br /> |
| | <span>周${dayOfWeek}</span> |
| | `; |
| | timeHeader.appendChild(headerDiv); |
| | }); |
| | } |
| | |
| | function generateWeekDates(startDate) { |
| | const dates = []; |
| | for (let i = 0; i < 7; i++) { |
| | const date = new Date(startDate); |
| | date.setDate(date.getDate() + i); |
| | dates.push(date); |
| | } |
| | return dates; |
| | } |
| | |
| | function navigateToSection_01() { |
| | window.location.href = "/"; |
| | } |
| | function navigateToSection_02() { |
| | window.location.href = "/teachers"; |
| | } |
| | function randomColor() { |
| | const colors = ["#ffcccb", "#c6e2ff", "#d5f5e3", "#f7dc6f", "#f1948a", "#aed6f1", "#d7bde2"]; |
| | return colors[Math.floor(Math.random() * colors.length)]; |
| | } |
| | |
| | document.getElementById("week-select").addEventListener("change", loadSchedule); |
| | document.getElementById("teacher-search").addEventListener("input", searchTeachers); |
| | |
| | initializeWeeks(); |
| | loadTeachers(); |
| | </script> |
| | </body> |
| | </html> |
| |
|