diff --git a/ExamCloudSchedule/index.html b/ExamCloudSchedule/index.html new file mode 100644 index 0000000..f2d8014 --- /dev/null +++ b/ExamCloudSchedule/index.html @@ -0,0 +1,58 @@ + + + + + + Exam Schedule + + + + + + +
+

+ 考试安排 + +

+

+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + +
科目开始时间结束时间
+
+
+
+ +
+
+ + + + + + + + +
+
+ + + diff --git a/ExamCloudSchedule/script.js b/ExamCloudSchedule/script.js new file mode 100644 index 0000000..527351c --- /dev/null +++ b/ExamCloudSchedule/script.js @@ -0,0 +1,230 @@ +document.addEventListener("DOMContentLoaded", () => { + const examNameElem = document.getElementById("examName"); + const messageElem = document.getElementById("message"); + const currentTimeElem = document.getElementById("current-time"); + const currentSubjectElem = document.getElementById("current-subject"); + const examTimingElem = document.getElementById("exam-timing"); + const remainingTimeElem = document.getElementById("remaining-time"); + const statusElem = document.getElementById("status"); + const examTableBodyElem = document.getElementById("exam-table-body"); + const fullscreenBtn = document.getElementById("fullscreen-btn"); + const settingsBtn = document.getElementById("settings-btn"); + const settingsModal = document.getElementById("settings-modal"); + const closeSettingsBtn = document.getElementById("close-settings-btn"); + const saveSettingsBtn = document.getElementById("save-settings-btn"); + const offsetTimeInput = document.getElementById("offset-time"); + const roomInput = document.getElementById("room-input"); + const roomElem = document.getElementById("room"); + const zoomInput = document.getElementById("zoom-input"); + + let offsetTime = getCookie("offsetTime") || 0; + let room = getCookie("room") || ""; + let zoomLevel = getCookie("zoomLevel") || 1; + + offsetTime = parseInt(offsetTime); + roomElem.textContent = room; + + function fetchData() { + const urlParams = new URLSearchParams(window.location.search); + const configId = urlParams.get('configId'); + if (!configId) { + console.error('No configId provided'); + return; + } + + return fetch(`/get_config.php?id=${encodeURIComponent(configId)}`, { cache: "no-store" }) // 不保留缓存 + .then(response => response.json()) + .then(data => { + displayExamInfo(data); + updateCurrentTime(); + updateExamInfo(data); + setInterval(() => updateCurrentTime(), 1000); // Update current time every second + setInterval(() => updateExamInfo(data), 1000); // Update exam info every second + }) + .catch(error => console.error('Error fetching exam data:', error)); + } + + function displayExamInfo(data) { + // Display exam name + const examNameText = data.examName; + const roomText = roomElem.textContent; + examNameElem.innerHTML = `${examNameText} ${roomText}`; + // Display message + messageElem.textContent = data.message; + } + + function updateCurrentTime() { + const now = new Date(new Date().getTime() + offsetTime * 1000); + currentTimeElem.textContent = now.toLocaleTimeString('zh-CN', { hour12: false }); + } + + function formatTimeWithoutSeconds(time) { + // Convert time to string and remove seconds if present + return time.slice(0, -3); + } + + function updateExamInfo(data) { + const now = new Date(new Date().getTime() + offsetTime * 1000); + let currentExam = null; + let nextExam = null; + let lastExam = null; + + data.examInfos.forEach(exam => { + const start = new Date(exam.start); + const end = new Date(exam.end); + if (now >= start && now <= end) { + currentExam = exam; + } + if (!currentExam && !nextExam && now < start) { + nextExam = exam; + } + if (now > end && (!lastExam || end > new Date(lastExam.end))) { + lastExam = exam; + } + }); + + if (currentExam) { + currentSubjectElem.textContent = `当前科目: ${currentExam.name}`; + examTimingElem.textContent = `起止时间: ${formatTimeWithoutSeconds(new Date(currentExam.start).toLocaleTimeString('zh-CN', { hour12: false }))} - ${formatTimeWithoutSeconds(new Date(currentExam.end).toLocaleTimeString('zh-CN', { hour12: false }))}`; + const remainingTime = (new Date(currentExam.end).getTime() - now.getTime() + 1000) / 1000; + const remainingHours = Math.floor(remainingTime / 3600); + const remainingMinutes = Math.floor((remainingTime % 3600) / 60); + const remainingSeconds = Math.floor(remainingTime % 60); + const remainingTimeText = `${remainingHours}时 ${remainingMinutes}分 ${remainingSeconds}秒`; + + if (remainingHours === 0 && remainingMinutes <= 14) { + remainingTimeElem.textContent = `倒计时: ${remainingTimeText}`; + remainingTimeElem.style.color = "red"; + remainingTimeElem.style.fontWeight = "bold"; + } else { + remainingTimeElem.textContent = `剩余时间: ${remainingTimeText}`; + remainingTimeElem.style.color = "#93b4f7"; + remainingTimeElem.style.fontWeight = "normal"; + } + + statusElem.textContent = "状态: 进行中"; + statusElem.style.color = "#5ba838"; + } else if (lastExam && now < new Date(lastExam.end).getTime() + 60000) { + const timeSinceEnd = (now.getTime() - new Date(lastExam.end).getTime()) / 1000; + currentSubjectElem.textContent = `上场科目: ${lastExam.name}`; + examTimingElem.textContent = ""; + remainingTimeElem.textContent = ``; + statusElem.textContent = "状态: 已结束"; + statusElem.style.color = "red"; + } else if (nextExam) { + const timeUntilStart = ((new Date(nextExam.start).getTime() - now.getTime()) / 1000) + 1; + const remainingHours = Math.floor(timeUntilStart / 3600); + const remainingMinutes = Math.floor((timeUntilStart % 3600) / 60); + const remainingSeconds = Math.floor(timeUntilStart % 60); + const remainingTimeText = `${remainingHours}时 ${remainingMinutes}分 ${remainingSeconds}秒`; + + if (timeUntilStart <= 15 * 60) { + currentSubjectElem.textContent = `即将开始: ${nextExam.name}`; + remainingTimeElem.textContent = `倒计时: ${remainingTimeText}`; + remainingTimeElem.style.color = "orange"; + remainingTimeElem.style.fontWeight = "bold"; + statusElem.textContent = "状态: 即将开始"; + statusElem.style.color = "#DBA014"; + } else { + currentSubjectElem.textContent = `下一场科目: ${nextExam.name}`; + remainingTimeElem.textContent = ""; + statusElem.textContent = "状态: 未开始"; + remainingTimeElem.style.fontWeight = "normal"; + statusElem.style.color = "#EAEE5B"; + } + + examTimingElem.textContent = `起止时间: ${formatTimeWithoutSeconds(new Date(nextExam.start).toLocaleTimeString('zh-CN', { hour12: false }))} - ${formatTimeWithoutSeconds(new Date(nextExam.end).toLocaleTimeString('zh-CN', { hour12: false }))}`; + } else { + currentSubjectElem.textContent = "考试均已结束"; + examTimingElem.textContent = ""; + remainingTimeElem.textContent = ""; + statusElem.textContent = "状态: 空闲"; + statusElem.style.color = "#3946AF"; + } + + // Update next exams table + examTableBodyElem.innerHTML = ""; + data.examInfos.forEach(exam => { + const start = new Date(exam.start); + const end = new Date(exam.end); + let status = ""; + if (now < start) { + status = "即将开始"; + } else if (now > end) { + status = "已结束"; + } else { + status = "进行中"; + } + + const row = document.createElement("tr"); + row.className = `exam-status-${status}`; + row.innerHTML = ` + ${exam.name} + ${formatTimeWithoutSeconds(new Date(exam.start).toLocaleTimeString('zh-CN', { hour12: false }))} + ${formatTimeWithoutSeconds(new Date(exam.end).toLocaleTimeString('zh-CN', { hour12: false }))} + `; + examTableBodyElem.appendChild(row); + }); + } + + // Fullscreen functionality + fullscreenBtn.addEventListener("click", () => { + if (!document.fullscreenElement) { + document.documentElement.requestFullscreen(); + } else { + if (document.exitFullscreen) { + document.exitFullscreen(); + } + } + }); + + // Open settings modal + settingsBtn.addEventListener("click", () => { + offsetTimeInput.value = offsetTime; + roomInput.value = room; + zoomInput.value = zoomLevel; + settingsModal.style.display = "block"; + }); + + // Close settings modal + closeSettingsBtn.addEventListener("click", () => { + settingsModal.style.display = "none"; + }); + + // Save settings + saveSettingsBtn.addEventListener("click", () => { + offsetTime = parseInt(offsetTimeInput.value); + room = roomInput.value; + zoomLevel = parseFloat(zoomInput.value); + setCookie("offsetTime", offsetTime, 365); + setCookie("room", room, 365); + setCookie("zoomLevel", zoomLevel, 365); + roomElem.textContent = room; + document.body.style.zoom = zoomLevel; + settingsModal.style.display = "none"; + }); + + document.body.style.zoom = zoomLevel; + + // Utility function to set a cookie + function setCookie(name, value, days) { + const d = new Date(); + d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000)); + const expires = "expires=" + d.toUTCString(); + document.cookie = name + "=" + value + ";" + expires + ";path=/"; + } + + // Utility function to get a cookie + function getCookie(name) { + const nameEQ = name + "="; + const ca = document.cookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) === ' ') c = c.substring(1, c.length); + if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); + } + return null; + } + + fetchData(); +}); diff --git a/ExamCloudSchedule/styles.css b/ExamCloudSchedule/styles.css new file mode 100644 index 0000000..57f31a4 --- /dev/null +++ b/ExamCloudSchedule/styles.css @@ -0,0 +1,260 @@ +body { + font-family: 'HarmonyOS Sans SC Regular', 'Roboto', Arial, sans-serif; + margin: 0; + padding: 0; + background: url('../background.jpg') no-repeat center center fixed; + background-size: cover; + animation: fadeIn 1s; + color: #e0e0e0; + overflow: auto; /* 允许页面滚动 */ +} + +/* 隐藏滚动条 */ +body::-webkit-scrollbar { + display: none; +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +#fullscreen-btn { + position: absolute; + top: 20px; + right: 20px; + padding: 10px 20px; + font-size: 1rem; + cursor: pointer; + background-color: #1f1f1f; + color: #e0e0e0; + border: 1px solid #333; + border-radius: 5px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); + transition: background-color 0.3s ease, transform 0.3s ease; + z-index: 1001; +} + +#settings-btn { + position: absolute; + top: 20px; + right: 120px; /* Fullscreen button's left */ + padding: 10px 20px; + font-size: 1rem; + cursor: pointer; + background-color: #1f1f1f; + color: #e0e0e0; + border: 1px solid #333; + border-radius: 5px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); + transition: background-color 0.3s ease, transform 0.3s ease; + z-index: 1001; +} + +#settings-btn:hover { + background-color: #333; + transform: scale(1.05); +} + +#fullscreen-btn:hover { + background-color: #333; + transform: scale(1.05); +} + +.container { + padding: 20px; + max-width: 1400px; /* 增加主体部分宽度 */ + margin: auto; + background-color: rgba(31, 31, 31, 0.5); /* 使用rgba设置背景透明度 */ + border-radius: 8px; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.3); +} + +h1 { + font-size: 3.5rem; + font-weight: bold; + text-align: left; + margin-bottom: 10px; + color: #e0e0e0; + display: flex; + align-items: center; + justify-content: space-between; +} + +#room { + font-size: 3.5rem; + font-weight: bold; + color: #e0e0e0; + position: relative; + right: 0; + margin-left: 20px; /* 调整位置使其保持在container中 */ +} + +#message { + font-size: 1.5rem; + color: #16a3d1; + margin-bottom: 20px; +} + +.content { + display: flex; + justify-content: space-between; +} + +.left-column, .right-column { + width: 48%; + background-color: rgba(31, 31, 31, 0.2); + padding: 20px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + border-radius: 8px; +} + +#current-time { + font-size: 10rem; + font-weight: bold; + text-align: center; + margin-bottom: 20px; + color: #7cc3fb; +} + +#current-subject, #exam-timing, #remaining-time, #status { + font-size: 3rem; + margin: 10px 0; + text-align: left; + color: #e0e0e0; +} + +table { + width: 100%; + border-collapse: collapse; + margin-top: 20px; + border: 1px solid #333; + background-color: rgba(31, 31, 31, 0.5); +} + +th, td { + border: 1px solid #333; + padding: 8px; /* 缩短行高 */ + font-size: 2rem; + text-align: center; +} + +th { + background-color: #333; + color: #7cc3fb; + font-weight: bold; + border-bottom: 2px solid #2b71ad; +} + +.exam-status-进行中 td { + color: #5ba838 !important; /* 绿色字体 */ +} + +.exam-status-即将开始 td { + color: #fe9901 !important; /* 橙色字体 */ +} + +.exam-status-已结束 td { + color: #ec0434 !important; /* 红色字体 */ +} + +.exam-status-空闲 td { + color: blue !important; /* 蓝色字体 */ +} + +tr:hover { + background-color: #333; +} + +table { + border-radius: 8px; + overflow: hidden; +} + +td { + border-bottom: 1px solid #333; +} + +td:first-child { + border-top-left-radius: 8px; + border-bottom-left-radius: 8px; +} + +td:last-child { + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; +} + +#settings-modal { + display: none; + position: fixed; + z-index: 1000; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgb(0, 0, 0); + background-color: rgba(0, 0, 0, 0.4); + padding-top: 60px; +} + +#settings-modal-content { + background-color: #1f1f1f; + margin: 5% auto; + padding: 20px; + border: 1px solid #888; + width: 80%; + max-width: 600px; + border-radius: 10px; +} + +#settings-modal-content label { + font-size: 2rem; +} + +#settings-modal-content input[type="number"], +#settings-modal-content input[type="text"] { + font-size: 2rem; + padding: 10px; + margin-top: 10px; + margin-bottom: 20px; + width: 100%; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 5px; + background-color: #121212; + color: #e0e0e0; +} + +#settings-modal-content button { + padding: 10px 20px; + font-size: 2rem; + cursor: pointer; + background-color: #93b4f7; + color: white; + border: none; + border-radius: 5px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); + transition: background-color 0.3s ease; +} + +#settings-modal-content button:hover { + background-color: #45a049; +} + +#close-settings-btn { + padding: 10px 20px; + font-size: 2rem; + cursor: pointer; + background-color: #d9534f; + color: white; + border: none; + border-radius: 5px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); + transition: background-color 0.3s ease; +} + +#close-settings-btn:hover { + background-color: #c9302c; +} diff --git a/background.jpg b/background.jpg new file mode 100644 index 0000000..3da109e Binary files /dev/null and b/background.jpg differ diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..596edad Binary files /dev/null and b/favicon.ico differ diff --git a/index.php b/index.php index a7d26e3..7bb135e 100644 --- a/index.php +++ b/index.php @@ -74,6 +74,7 @@ header('Content-Type: text/html; charset=utf-8'); +
@@ -86,10 +87,12 @@ header('Content-Type: text/html; charset=utf-8'); function loadConfig() { const configId = document.getElementById('configId').value.trim(); const resultDiv = document.getElementById('result'); + const enterButton = document.getElementById('enterButton'); resultDiv.innerHTML = '加载中...'; if(!configId) { resultDiv.innerHTML = '请输入配置ID'; + enterButton.style.display = 'none'; return; } @@ -102,12 +105,19 @@ header('Content-Type: text/html; charset=utf-8'); }) .then(data => { resultDiv.innerHTML = `
${syntaxHighlight(JSON.stringify(data, null, 4))}
`; + enterButton.style.display = 'inline-block'; }) .catch(error => { resultDiv.innerHTML = `错误:${error.error || '获取配置失败'}`; + enterButton.style.display = 'none'; }); } + function enterSchedule() { + const configId = document.getElementById('configId').value.trim(); + window.location.href = `/ExamCloudSchedule/index.html?configId=${encodeURIComponent(configId)}`; + } + // JSON高亮显示 function syntaxHighlight(json) { json = json.replace(/&/g, '&').replace(//g, '>');