From f57ffbf36709e06920e2cdf6033cd42010e77066 Mon Sep 17 00:00:00 2001
From: MKStoler1024 <158786854+MKStoler1024@users.noreply.github.com>
Date: Wed, 2 Apr 2025 09:09:42 +0000
Subject: [PATCH] =?UTF-8?q?chore:=20=E5=90=8C=E6=AD=A5ES=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
ExamCloudSchedule/index.html | 59 -----
ExamCloudSchedule/script.js | 272 --------------------
ExamCloudSchedule/styles.css | 346 --------------------------
index.php | 2 +-
present/Scripts/examInfo.js | 211 ++++++++++++++++
present/Scripts/main.js | 17 ++
present/Scripts/settings.js | 86 +++++++
present/Scripts/utils.js | 39 +++
present/Styles/dark.css | 463 ++++++++++++++++++++++++++++++++++
present/Styles/light.css | 468 +++++++++++++++++++++++++++++++++++
present/index.html | 80 ++++++
11 files changed, 1365 insertions(+), 678 deletions(-)
delete mode 100644 ExamCloudSchedule/index.html
delete mode 100644 ExamCloudSchedule/script.js
delete mode 100644 ExamCloudSchedule/styles.css
create mode 100644 present/Scripts/examInfo.js
create mode 100644 present/Scripts/main.js
create mode 100644 present/Scripts/settings.js
create mode 100644 present/Scripts/utils.js
create mode 100644 present/Styles/dark.css
create mode 100644 present/Styles/light.css
create mode 100644 present/index.html
diff --git a/ExamCloudSchedule/index.html b/ExamCloudSchedule/index.html
deleted file mode 100644
index 9dd73f8..0000000
--- a/ExamCloudSchedule/index.html
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
- Exam Schedule
-
-
-
-
-
-
-
-
- 考试安排
-
-
-
-
-
-
-
-
-
- 科目 |
- 开始时间 |
- 结束时间 |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/ExamCloudSchedule/script.js b/ExamCloudSchedule/script.js
deleted file mode 100644
index df54025..0000000
--- a/ExamCloudSchedule/script.js
+++ /dev/null
@@ -1,272 +0,0 @@
-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;
-
- let remainingTimeColor = "#3946AF";
- let statusColor = "#225036";
- let upcomingStatusColor = "#DBA014";
-
- 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 => {
- if (!room) {
- room = data.room;
- roomElem.textContent = room;
- }
- 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 = remainingTimeColor;
- remainingTimeElem.style.fontWeight = "normal";
- }
-
- statusElem.textContent = "状态: 进行中";
- statusElem.style.color = statusColor;
- } 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 = upcomingStatusColor;
- } else {
- currentSubjectElem.textContent = `下一场科目: ${nextExam.name}`;
- remainingTimeElem.textContent = "";
- statusElem.textContent = "状态: 未开始";
- remainingTimeElem.style.fontWeight = "normal";
- statusElem.style.color = "#C6813C";
- }
-
- 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;
- }
-
- document.getElementById('theme-toggle-btn').addEventListener('click', function() {
- document.body.classList.toggle('dark-theme');
- if (document.body.classList.contains('dark-theme')) {
- remainingTimeColor = '#ADD8FB'; // 暗色主题下的颜色
- statusColor = '#A2BB7A'; // 暗色主题下的颜色
- upcomingStatusColor = '#DBA014'; // 暗色主题下的颜色
- } else {
- remainingTimeColor = '#3946AF'; // 亮色主题下的颜色
- statusColor = '#225036'; // 亮色主题下的颜色
- upcomingStatusColor = '#F26A3A'; // 亮色主题下的颜色
- }
- updateRemainingTimeColor();
- updateStatusColor();
- });
-
- function updateRemainingTimeColor() {
- const remainingTimeElement = document.getElementById('remaining-time');
- const remainingTimeText = remainingTimeElement.textContent;
- const remainingMinutes = parseInt(remainingTimeText);
-
- if (remainingMinutes > 15) {
- remainingTimeElement.style.color = remainingTimeColor;
- }
- }
-
- function updateStatusColor() {
- const statusElement = document.getElementById('status');
- if (statusElement.textContent.includes('进行中')) {
- statusElement.style.color = statusColor;
- } else if (statusElement.textContent.includes('即将开始')) {
- statusElement.style.color = upcomingStatusColor;
- }
- }
-
- fetchData();
-});
diff --git a/ExamCloudSchedule/styles.css b/ExamCloudSchedule/styles.css
deleted file mode 100644
index 1f5a192..0000000
--- a/ExamCloudSchedule/styles.css
+++ /dev/null
@@ -1,346 +0,0 @@
-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: #000000;
- 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: #ffffff;
- color: #000000;
- border: 1px solid #ccc;
- 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: #ffffff;
- color: #000000;
- border: 1px solid #ccc;
- 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: #f0f0f0;
- transform: scale(1.05);
-}
-
-#fullscreen-btn:hover {
- background-color: #f0f0f0;
- transform: scale(1.05);
-}
-
-.container {
- padding: 20px;
- max-width: 1400px; /* 增加主体部分宽度 */
- margin: auto;
- background-color: rgba(255, 255, 255, 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: #000000;
- display: flex;
- align-items: center;
- justify-content: space-between;
-}
-
-#room {
- font-size: 3.5rem;
- font-weight: bold;
- color: #000000;
- position: relative;
- right: 0;
- margin-left: 20px; /* 调整位置使其保持在container中 */
-}
-
-#message {
- font-size: 1.5rem;
- color: #134858;
- margin-bottom: 20px;
-}
-
-.content {
- display: flex;
- justify-content: space-between;
-}
-
-.left-column, .right-column {
- width: 48%;
- background-color: rgba(255, 255, 255, 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: #000000;
-}
-
-#current-subject, #exam-timing, #remaining-time, #status {
- font-size: 3rem;
- margin: 10px 0;
- text-align: left;
- color: #000000;
-}
-
-table {
- width: 100%;
- border-collapse: collapse;
- margin-top: 20px;
- border: 1px solid #ccc;
- background-color: rgba(255, 255, 255, 0.5);
-}
-
-th, td {
- border: 1px solid #ccc;
- padding: 8px; /* 缩短行高 */
- font-size: 2rem;
- text-align: center;
-}
-
-th {
- background-color: rgba(255, 255, 255, 0.5);
- color: #134858;
- font-weight: bold;
- border-bottom: 2px solid #134858;
-}
-
-.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: #f0f0f0;
-}
-
-table {
- border-radius: 8px;
- overflow: hidden;
-}
-
-td {
- border-bottom: 1px solid #ccc;
-}
-
-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: #ffffff;
- 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: #ffffff;
- color: #000000;
-}
-
-#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;
-}
-
-body.dark-theme {
- background-image: url('../background-dark.jpg');
- color: #ffffff;
-}
-
-body.dark-theme .container {
- background-color: rgba(0, 0, 0, 0.5);
-}
-
-body.dark-theme .left-column,
-body.dark-theme .right-column {
- background-color: rgba(255, 255, 255, 0.2);
-}
-
-body.dark-theme #current-time {
- color: #ffffff;
-}
-
-body.dark-theme #current-subject,
-body.dark-theme #exam-timing,
-body.dark-theme #remaining-time,
-body.dark-theme #status {
- color: #ffffff;
-}
-
-body.dark-theme h1,
-body.dark-theme #room {
- color: #ffffff;
-}
-
-body.dark-theme table {
- background-color: rgba(255, 255, 255, 0.2);
-}
-
-body.dark-theme th,
-body.dark-theme td {
- color: rgba(0, 0, 0, 0.2);
-}
-
-body.dark-theme th {
- background-color: rgba(0, 0, 0, 0.2);
- color: #7cc3fb;
- border-bottom: 2px solid #134858;
-}
-
-body.dark-theme #settings-modal-content {
- background-color: #333;
- border: 1px solid #666;
-}
-
-body.dark-theme #settings-modal-content label,
-body.dark-theme #settings-modal-content input[type="number"],
-body.dark-theme #settings-modal-content input[type="text"] {
- color: #ffffff;
- background-color: #444;
- border: 1px solid #666;
-}
-
-body.dark-theme #settings-modal-content button {
- background-color: #555;
- color: #ffffff;
- border: 1px solid #666;
-}
-
-body.dark-theme #settings-modal-content button:hover {
- background-color: #666;
-}
-
-body.dark-theme #settings-btn,
-body.dark-theme #fullscreen-btn,
-body.dark-theme #theme-toggle-btn,
-body.dark-theme #save-settings-btn,
-body.dark-theme #close-settings-btn {
- background-color: #444;
- color: #ffffff;
- border: 1px solid #666;
-}
-
-body.dark-theme #settings-btn:hover,
-body.dark-theme #fullscreen-btn:hover,
-body.dark-theme #theme-toggle-btn:hover,
-body.dark-theme #save-settings-btn:hover,
-body.dark-theme #close-settings-btn:hover {
- background-color: #666;
-}
diff --git a/index.php b/index.php
index db09a20..1034def 100644
--- a/index.php
+++ b/index.php
@@ -155,7 +155,7 @@ header('Content-Type: text/html; charset=utf-8');
function enterSchedule() {
const configId = document.getElementById('configId').value.trim();
- window.location.href = `/ExamCloudSchedule/index.html?configId=${encodeURIComponent(configId)}`;
+ window.location.href = `/present/index.html?configId=${encodeURIComponent(configId)}`;
}
// JSON高亮显示
diff --git a/present/Scripts/examInfo.js b/present/Scripts/examInfo.js
new file mode 100644
index 0000000..4d69153
--- /dev/null
+++ b/present/Scripts/examInfo.js
@@ -0,0 +1,211 @@
+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 roomElem = document.getElementById("room");
+ let offsetTime = getCookie("offsetTime") || 0;
+
+ function fetchData() {
+ const urlParams = new URLSearchParams(window.location.search);
+ const configId = urlParams.get('configId');
+
+ if (!configId) {
+ errorSystem.show('未提供配置ID,请从主页进入');
+ return;
+ }
+
+ fetch(`/get_config.php?id=${encodeURIComponent(configId)}`)
+ .then(response => {
+ if (!response.ok) {
+ return response.json().then(err => { throw err; });
+ }
+ return response.json();
+ })
+ .then(data => {
+ displayExamInfo(data);
+ updateCurrentTime();
+ updateExamInfo(data);
+ setInterval(() => updateCurrentTime(), 1000);
+ setInterval(() => updateExamInfo(data), 1000);
+ })
+ .catch(error => errorSystem.show('获取考试数据失败: ' + error.message));
+ }
+
+ function displayExamInfo(data) {
+ try {
+ const examNameText = data.examName;
+ const roomText = roomElem.textContent;
+ examNameElem.innerHTML = `${examNameText} ${roomText}`;
+ messageElem.textContent = data.message;
+ } catch (e) {
+ errorSystem.show('显示考试信息失败: ' + e.message);
+ }
+ }
+
+ function updateCurrentTime() {
+ try {
+ const now = new Date(new Date().getTime() + offsetTime * 1000);
+ currentTimeElem.textContent = now.toLocaleTimeString('zh-CN', { hour12: false });
+ } catch (e) {
+ errorSystem.show('更新时间失败: ' + e.message);
+ }
+ }
+
+ function updateExamInfo(data) {
+ try {
+ 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";
+ statusElem.textContent = "状态: 即将结束";
+ statusElem.style.color = "red";
+ } 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";
+ }
+
+ examTableBodyElem.innerHTML = "";
+
+ // 预处理日期和时间段
+ const dateGroups = {};
+ data.examInfos.forEach(exam => {
+ const start = new Date(exam.start);
+ const hour = start.getHours();
+ const dateStr = `${start.getMonth() + 1}月${start.getDate()}日
${hour < 12 ? '上午' : (hour < 18 ? '下午' : '晚上')}`;
+
+ if (!dateGroups[dateStr]) {
+ dateGroups[dateStr] = [];
+ }
+ dateGroups[dateStr].push(exam);
+ });
+
+ // 生成表格
+ Object.entries(dateGroups).forEach(([dateStr, exams]) => {
+ let isFirstRow = true;
+ // 计算实际需要的行数(考虑科目名称中的斜杠)
+ const totalRows = exams.reduce((acc, exam) => {
+ return acc + (exam.name.includes('/') ? exam.name.split('/').length : 1);
+ }, 0);
+
+ exams.forEach(exam => {
+ const start = new Date(exam.start);
+ const end = new Date(exam.end);
+ const now = new Date(new Date().getTime() + offsetTime * 1000);
+
+ let status = "未开始";
+ if (now < start) {
+ status = now > new Date(start.getTime() - 15 * 60 * 1000) ? "即将开始" : "未开始";
+ } else if (now > end) {
+ status = "已结束";
+ } else {
+ status = "进行中";
+ }
+
+ // 处理包含斜杠的科目名称
+ const subjects = exam.name.split('/');
+ subjects.forEach((subject, index) => {
+ const row = document.createElement("tr");
+ let cells = '';
+
+ if (isFirstRow) {
+ cells = `${dateStr} | `;
+ isFirstRow = false;
+ }
+
+ // 仅在第一个科目行添加时间和状态
+ if (index === 0) {
+ cells += `
+ ${subject.trim()} |
+ ${formatTimeWithoutSeconds(start.toLocaleTimeString('zh-CN', { hour12: false }))} |
+ ${formatTimeWithoutSeconds(end.toLocaleTimeString('zh-CN', { hour12: false }))} |
+ ${status} |
+ `;
+ } else {
+ cells += `${subject.trim()} | `;
+ }
+
+ row.innerHTML = cells;
+ examTableBodyElem.appendChild(row);
+ });
+ });
+ });
+ } catch (e) {
+ errorSystem.show('更新考试信息失败: ' + e.message);
+ }
+ }
+
+ fetchData();
+});
diff --git a/present/Scripts/main.js b/present/Scripts/main.js
new file mode 100644
index 0000000..09d3ec6
--- /dev/null
+++ b/present/Scripts/main.js
@@ -0,0 +1,17 @@
+document.addEventListener("DOMContentLoaded", () => {
+ const fullscreenBtn = document.getElementById("fullscreen-btn");
+
+ fullscreenBtn.addEventListener("click", () => {
+ try {
+ if (!document.fullscreenElement) {
+ document.documentElement.requestFullscreen();
+ } else {
+ if (document.exitFullscreen) {
+ document.exitFullscreen();
+ }
+ }
+ } catch (e) {
+ errorSystem.show('全屏切换失败: ' + e.message);
+ }
+ });
+});
diff --git a/present/Scripts/settings.js b/present/Scripts/settings.js
new file mode 100644
index 0000000..ec56020
--- /dev/null
+++ b/present/Scripts/settings.js
@@ -0,0 +1,86 @@
+document.addEventListener("DOMContentLoaded", () => {
+ 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");
+ const themeToggle = document.getElementById("theme-toggle");
+ const themeLink = document.getElementById("theme-link");
+
+ let offsetTime = getCookie("offsetTime") || 0;
+ let room = getCookie("room") || "";
+ let zoomLevel = getCookie("zoomLevel") || 1;
+ let theme = getCookie("theme") || "dark";
+
+ offsetTime = parseInt(offsetTime);
+ roomElem.textContent = room;
+
+ if (theme === "light") {
+ themeLink.href = "Styles/light.css";
+ themeToggle.checked = true;
+ } else {
+ themeLink.href = "Styles/dark.css";
+ themeToggle.checked = false;
+ }
+
+ settingsBtn.addEventListener("click", () => {
+ try {
+ offsetTimeInput.value = offsetTime;
+ roomInput.value = room;
+ zoomInput.value = zoomLevel;
+ settingsModal.style.display = "block";
+ } catch (e) {
+ errorSystem.show('打开设置失败: ' + e.message);
+ }
+ });
+
+ closeSettingsBtn.addEventListener("click", () => {
+ try {
+ settingsModal.classList.add("fade-out");
+ setTimeout(() => {
+ settingsModal.style.display = "none";
+ settingsModal.classList.remove("fade-out");
+ }, 300);
+ } catch (e) {
+ errorSystem.show('关闭设置失败: ' + e.message);
+ }
+ });
+
+ saveSettingsBtn.addEventListener("click", () => {
+ try {
+ offsetTime = parseInt(offsetTimeInput.value);
+ room = roomInput.value;
+ zoomLevel = parseFloat(zoomInput.value);
+ theme = themeToggle.checked ? "light" : "dark";
+ setCookie("offsetTime", offsetTime, 365);
+ setCookie("room", room, 365);
+ setCookie("zoomLevel", zoomLevel, 365);
+ setCookie("theme", theme, 365);
+ roomElem.textContent = room;
+ document.body.style.zoom = zoomLevel;
+ themeLink.href = theme === "light" ? "Styles/light.css" : "Styles/dark.css";
+ settingsModal.classList.add("fade-out");
+ setTimeout(() => {
+ settingsModal.style.display = "none";
+ settingsModal.classList.remove("fade-out");
+ }, 300);
+ location.reload();
+ } catch (e) {
+ errorSystem.show('保存设置失败: ' + e.message);
+ }
+ });
+
+ themeToggle.addEventListener("change", () => {
+ const theme = themeToggle.checked ? "light" : "dark";
+ themeLink.href = theme === "light" ? "Styles/light.css" : "Styles/dark.css";
+ });
+
+ try {
+ document.body.style.zoom = zoomLevel;
+ } catch (e) {
+ errorSystem.show('初始化缩放失败: ' + e.message);
+ }
+});
diff --git a/present/Scripts/utils.js b/present/Scripts/utils.js
new file mode 100644
index 0000000..68e8cb9
--- /dev/null
+++ b/present/Scripts/utils.js
@@ -0,0 +1,39 @@
+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=/";
+}
+
+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;
+}
+
+function formatTimeWithoutSeconds(time) {
+ return time.slice(0, -3);
+}
+
+const errorSystem = {
+ show: function(message) {
+ try {
+ const container = document.querySelector('.error-container');
+ const content = document.getElementById('errorMessage');
+ content.textContent = message;
+ container.style.display = 'flex';
+ setTimeout(this.hide, 5000);
+ } catch(e) {
+ console.error('错误提示系统异常:', e);
+ }
+ },
+ hide: function() {
+ const container = document.querySelector('.error-container');
+ if (container) container.style.display = 'none';
+ }
+};
diff --git a/present/Styles/dark.css b/present/Styles/dark.css
new file mode 100644
index 0000000..fbb0731
--- /dev/null
+++ b/present/Styles/dark.css
@@ -0,0 +1,463 @@
+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, #settings-btn {
+ position: absolute;
+ top: 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;
+}
+
+#fullscreen-btn {
+ right: 20px;
+}
+
+#settings-btn {
+ right: 120px; /* Fullscreen button's left */
+}
+
+#settings-btn:hover, #fullscreen-btn:hover {
+ background-color: #333;
+ transform: scale(1.05);
+}
+
+.container {
+ padding: 20px;
+ max-width: 1400px; /* 增加主体部分宽度 */
+ margin: auto;
+ background-color: rgba(0, 0, 0, 0.4); /* 使用rgba设置背景透明度为80% */
+}
+
+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;
+ gap: 3px; /* 板块间隔3px */
+}
+
+.left-column, .right-column {
+ display: flex;
+ flex-direction: column;
+ gap: 3px;
+}
+
+.left-column {
+ width: 45%;
+}
+
+.right-column {
+ width: 50%;
+}
+
+.clock-section, .info-section, .right-column {
+ background-color: rgba(31, 31, 31, 0.5); /* 亚克力效果 */
+ backdrop-filter: blur(10px);
+ padding: 20px;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
+ border-radius: 8px;
+ margin-bottom: 20px; /* 增加时钟和信息板块之间的间隔 */
+}
+
+#current-time {
+ font-size: 8rem;
+ text-align: center;
+ color: #7cc3fb;
+ margin: 0;
+ font-weight: bold;
+}
+
+#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 rgba(255, 255, 255, 0.75);
+ background-color: rgba(31, 31, 31, 0.5);
+}
+
+th, td {
+ border: 1px solid #fff;
+ padding: 0px; /* 缩短行高 */
+ font-size: 1.8rem;
+ text-align: center;
+}
+
+th {
+ background-color: #333;
+ color: #7cc3fb;
+ font-weight: bold;
+ border-bottom: 2px solid #fff;
+}
+
+tr:hover {
+ background-color: #333;
+}
+
+table {
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+td {
+ border-bottom: 1px solid #fff;
+}
+
+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;
+}
+
+.exam-status-tag {
+ padding: 3px 6px;
+ border-radius: 4px;
+ font-size: 1.2rem;
+ display: inline-block;
+ min-width: 60px;
+}
+
+.exam-status-进行中 {
+ background-color: rgba(91, 168, 56, 0.2);
+ color: #5ba838;
+}
+
+.exam-status-即将开始 {
+ background-color: rgba(254, 153, 1, 0.2);
+ color: #fe9901;
+}
+
+.exam-status-已结束 {
+ background-color: rgba(236, 4, 52, 0.2);
+ color: #ec0434;
+}
+
+.exam-status-未开始 {
+ background-color: rgba(238, 238, 91, 0.2);
+ color: #eeee5b;
+}
+
+#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: rgba(31, 31, 31, 0.95);
+ padding: 25px;
+ margin: 25px auto;
+ border-radius: 12px;
+ border: 1px solid #444;
+ backdrop-filter: blur(8px);
+ max-width: 600px;
+ animation: fadeIn 0.5s ease;
+}
+
+@keyframes fadeIn {
+ from { opacity: 0; transform: translateY(-20px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+@keyframes fadeOut {
+ from { opacity: 1; transform: translateY(0); }
+ to { opacity: 0; transform: translateY(-20px); }
+}
+
+.fade-out {
+ animation: fadeOut 0.3s ease;
+}
+
+#settings-modal-content h3 {
+ margin: 0 0 20px;
+ color: #e0e0e0;
+ font-size: 20px;
+}
+
+#settings-modal-content label {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin: 12px 0;
+ font-size: 16px;
+ color: #b0b0b0;
+}
+
+#settings-modal-content label[for="offset-time"],
+#settings-modal-content label[for="room-input"],
+#settings-modal-content label[for="zoom-input"] {
+ justify-content: space-between;
+}
+
+#settings-modal-content input[type="number"],
+#settings-modal-content input[type="text"] {
+ flex-grow: 1;
+ margin-left: 10px;
+ font-size: 1.5rem;
+ padding: 10px;
+ margin-top: 10px;
+ margin-bottom: 20px;
+ width: 100%;
+ box-sizing: border-box;
+ border: 1px solid #555;
+ border-radius: 5px;
+ background-color: #222;
+ color: #e0e0e0;
+}
+
+#settings-modal-content input:focus {
+ outline: none;
+ border-color: #007acc;
+ box-shadow: 0 0 0 1px #007acc;
+}
+
+.button-group {
+ display: flex;
+ justify-content: flex-end;
+ gap: 10px;
+}
+
+#settings-modal-content button {
+ background: linear-gradient(135deg, #3498db, #2980b9);
+ color: white;
+ border: none;
+ padding: 12px 24px;
+ border-radius: 8px;
+ cursor: pointer;
+ font-size: 15px;
+ font-weight: 500;
+ transition: all 0.2s ease;
+ box-shadow: 0 4px 12px rgba(52,152,219,0.25);
+}
+
+#settings-modal-content button:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 6px 16px rgba(52,152,219,0.35);
+}
+
+#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;
+}
+
+.error-container {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: #ff6b6b;
+ color: white;
+ padding: 16px;
+ display: none;
+ z-index: 10001;
+ animation: slideUp 0.3s ease;
+}
+
+@keyframes slideUp {
+ from { transform: translateY(100%); }
+ to { transform: translateY(0); }
+}
+
+.error-content {
+ max-width: 800px;
+ margin: 0 auto;
+ font-size: 15px;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.error-content:before {
+ content: '!';
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 24px;
+ height: 24px;
+ background: white;
+ color: #ff6b6b;
+ border-radius: 50%;
+ font-weight: bold;
+}
+
+.switch {
+ position: relative;
+ display: inline-block;
+ width: 60px;
+ height: 34px;
+}
+
+.switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+.slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #ccc;
+ transition: .4s;
+ border-radius: 34px;
+}
+
+.slider:before {
+ position: absolute;
+ content: "";
+ height: 26px;
+ width: 26px;
+ left: 4px;
+ bottom: 4px;
+ background-color: white;
+ transition: .4s;
+ border-radius: 50%;
+}
+
+input:checked + .slider {
+ background-color: #2196F3;
+}
+
+input:checked + .slider:before {
+ transform: translateX(26px);
+}
+
+.theme-toggle-container {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+}
+
+.config-file-container {
+ margin: 12px 0;
+ padding: 10px;
+ border: 1px solid #555;
+ border-radius: 5px;
+ background-color: rgba(31, 31, 31, 0.5);
+}
+
+.config-file-container label {
+ display: block;
+ margin-bottom: 8px;
+ color: #e0e0e0;
+}
+
+.config-file-container input[type="file"] {
+ display: block;
+ width: 100%;
+ padding: 8px;
+ border: 1px solid #555;
+ border-radius: 4px;
+ background-color: #222;
+ color: #e0e0e0;
+ cursor: pointer;
+}
+
+.config-file-container input[type="file"]:hover {
+ background-color: #333;
+}
+
+.file-hint {
+ margin-top: 4px;
+ font-size: 12px;
+ color: #888;
+}
+
+.config-control-btn {
+ margin-top: 10px;
+ padding: 8px 16px;
+ background-color: #d9534f;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ transition: background-color 0.3s ease;
+}
+
+.config-control-btn:hover {
+ background-color: #c9302c;
+}
diff --git a/present/Styles/light.css b/present/Styles/light.css
new file mode 100644
index 0000000..3c70d93
--- /dev/null
+++ b/present/Styles/light.css
@@ -0,0 +1,468 @@
+body {
+ font-family: 'HarmonyOS Sans SC Regular', 'Roboto', Arial, sans-serif;
+ margin: 0;
+ padding: 0;
+ background: url('../../background_light.jpg') no-repeat center center fixed;
+ background-size: cover;
+ animation: fadeIn 1s;
+ color: #333;
+ overflow: auto;
+}
+
+body::-webkit-scrollbar {
+ display: none;
+}
+
+@keyframes fadeIn {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+#fullscreen-btn, #settings-btn {
+ position: absolute;
+ top: 20px;
+ padding: 10px 20px;
+ font-size: 1rem;
+ cursor: pointer;
+ background-color: #f0f0f0;
+ color: #333;
+ border: 1px solid #ccc;
+ 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;
+}
+
+#fullscreen-btn {
+ right: 20px;
+}
+
+#settings-btn {
+ right: 120px;
+}
+
+#settings-btn:hover, #fullscreen-btn:hover {
+ background-color: #ccc;
+ transform: scale(1.05);
+}
+
+.container {
+ padding: 20px;
+ max-width: 1400px;
+ margin: auto;
+ background-color: rgba(255, 255, 255, 0.4);
+}
+
+h1 {
+ font-size: 3.5rem;
+ font-weight: bold;
+ text-align: left;
+ margin-bottom: 10px;
+ color: #333;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+#room {
+ font-size: 3.5rem;
+ font-weight: bold;
+ color: #333;
+ position: relative;
+ right: 0;
+ margin-left: 20px;
+}
+
+#message {
+ font-size: 1.5rem;
+ color: #16a3d1;
+ margin-bottom: 20px;
+}
+
+.content {
+ display: flex;
+ justify-content: space-between;
+ gap: 3px;
+}
+
+.left-column, .right-column {
+ display: flex;
+ flex-direction: column;
+ gap: 3px;
+}
+
+.left-column {
+ width: 45%;
+}
+
+.right-column {
+ width: 50%;
+}
+
+.clock-section, .info-section, .right-column {
+ background-color: rgba(255, 255, 255, 0.2);
+ backdrop-filter: blur(10px);
+ padding: 20px;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
+ border-radius: 8px;
+}
+
+.clock-section, .info-section {
+ margin-bottom: 20px; /* 增加时钟和信息板块之间的间隔 */
+}
+
+#current-time {
+ font-size: 8rem;
+ text-align: center;
+ color: #333;
+ margin: 0;
+ font-weight: bold;
+}
+
+#current-subject, #exam-timing, #remaining-time, #status {
+ font-size: 3rem;
+ margin: 10px 0;
+ text-align: left;
+ color: #333;
+}
+
+table {
+ width: 100%;
+ border-collapse: collapse;
+ margin-top: 20px;
+ border: 1px solid #000;
+ background-color: rgba(255, 255, 255, 0.5);
+}
+
+th, td {
+ border: 1px solid #000;
+ padding: 0px;
+ font-size: 1.8rem;
+ text-align: center;
+}
+
+th {
+ background-color: #f0f0f0;
+ color: #333;
+ font-weight: bold;
+ border-bottom: 2px solid #000;
+}
+
+tr:hover {
+ background-color: #f0f0f0;
+}
+
+table {
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+td {
+ border-bottom: 1px solid #000;
+}
+
+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;
+}
+
+.exam-status-tag {
+ padding: 3px 6px;
+ border-radius: 4px;
+ font-size: 1.2rem;
+ display: inline-block;
+ min-width: 60px;
+}
+
+.exam-status-进行中 {
+ background-color: rgba(91, 168, 56, 0.1);
+ color: #5ba838;
+}
+
+.exam-status-即将开始 {
+ background-color: rgba(254, 153, 1, 0.1);
+ color: #fe9901;
+}
+
+.exam-status-已结束 {
+ background-color: rgba(236, 4, 52, 0.1);
+ color: #ec0434;
+}
+
+.exam-status-未开始 {
+ background-color: rgba(238, 238, 91, 0.1);
+ color: #d4b106;
+}
+
+#settings-modal {
+ display: none;
+ position: fixed;
+ z-index: 1000;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ background-color: rgba(0, 0, 0, 0.4);
+ padding-top: 60px;
+}
+
+#settings-modal-content {
+ background: rgba(255, 255, 255, 0.95);
+ padding: 25px;
+ margin: 25px auto;
+ border-radius: 12px;
+ border: 1px solid #ccc;
+ backdrop-filter: blur(8px);
+ max-width: 600px;
+ animation: fadeIn 0.5s ease;
+}
+
+@keyframes fadeIn {
+ from { opacity: 0; transform: translateY(-20px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+@keyframes fadeOut {
+ from { opacity: 1; transform: translateY(0); }
+ to { opacity: 0; transform: translateY(-20px); }
+}
+
+.fade-out {
+ animation: fadeOut 0.3s ease;
+}
+
+#settings-modal-content h3 {
+ margin: 0 0 20px;
+ color: #333;
+ font-size: 20px;
+}
+
+#settings-modal-content label {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin: 12px 0;
+ font-size: 16px;
+ color: #666;
+}
+
+#settings-modal-content label[for="offset-time"],
+#settings-modal-content label[for="room-input"],
+#settings-modal-content label[for="zoom-input"] {
+ justify-content: space-between;
+}
+
+#settings-modal-content input[type="number"],
+#settings-modal-content input[type="text"] {
+ flex-grow: 1;
+ margin-left: 10px;
+}
+
+#settings-modal-content input[type="number"],
+#settings-modal-content input[type="text"] {
+ font-size: 1.5rem;
+ padding: 10px;
+ margin-top: 10px;
+ margin-bottom: 20px;
+ width: 100%;
+ box-sizing: border-box;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ background-color: #fff;
+ color: #333;
+}
+
+#settings-modal-content input:focus {
+ outline: none;
+ border-color: #007acc;
+ box-shadow: 0 0 0 1px #007acc;
+}
+
+.button-group {
+ display: flex;
+ justify-content: flex-end;
+ gap: 10px;
+}
+
+#settings-modal-content button {
+ background: linear-gradient(135deg, #3498db, #2980b9);
+ color: white;
+ border: none;
+ padding: 12px 24px;
+ border-radius: 8px;
+ cursor: pointer;
+ font-size: 15px;
+ font-weight: 500;
+ transition: all 0.2s ease;
+ box-shadow: 0 4px 12px rgba(52,152,219,0.25);
+}
+
+#settings-modal-content button:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 6px 16px rgba(52,152,219,0.35);
+}
+
+#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;
+}
+
+.error-container {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: #ff6b6b;
+ color: white;
+ padding: 16px;
+ display: none;
+ z-index: 10001;
+ animation: slideUp 0.3s ease;
+}
+
+@keyframes slideUp {
+ from { transform: translateY(100%); }
+ to { transform: translateY(0); }
+}
+
+.error-content {
+ max-width: 800px;
+ margin: 0 auto;
+ font-size: 15px;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.error-content:before {
+ content: '!';
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 24px;
+ height: 24px;
+ background: white;
+ color: #ff6b6b;
+ border-radius: 50%;
+ font-weight: bold;
+}
+
+.switch {
+ position: relative;
+ display: inline-block;
+ width: 60px;
+ height: 34px;
+}
+
+.switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+.slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #ccc;
+ transition: .4s;
+ border-radius: 34px;
+}
+
+.slider:before {
+ position: absolute;
+ content: "";
+ height: 26px;
+ width: 26px;
+ left: 4px;
+ bottom: 4px;
+ background-color: white;
+ transition: .4s;
+ border-radius: 50%;
+}
+
+input:checked + .slider {
+ background-color: #2196F3;
+}
+
+input:checked + .slider:before {
+ transform: translateX(26px);
+}
+
+.theme-toggle-container {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+}
+
+.config-file-container {
+ margin: 12px 0;
+ padding: 10px;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ background-color: rgba(255, 255, 255, 0.5);
+}
+
+.config-file-container label {
+ display: block;
+ margin-bottom: 8px;
+ color: #333;
+}
+
+.config-file-container input[type="file"] {
+ display: block;
+ width: 100%;
+ padding: 8px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ background-color: #fff;
+ color: #333;
+ cursor: pointer;
+}
+
+.config-file-container input[type="file"]:hover {
+ background-color: #f5f5f5;
+}
+
+.file-hint {
+ margin-top: 4px;
+ font-size: 12px;
+ color: #666;
+}
+
+.config-control-btn {
+ margin-top: 10px;
+ padding: 8px 16px;
+ background-color: #d9534f;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ transition: background-color 0.3s ease;
+}
+
+.config-control-btn:hover {
+ background-color: #c9302c;
+}
diff --git a/present/index.html b/present/index.html
new file mode 100644
index 0000000..606075d
--- /dev/null
+++ b/present/index.html
@@ -0,0 +1,80 @@
+
+
+
+
+
+ Exam Schedule
+
+
+
+
+
+
+
+
+
+ 考试安排
+
+
+
+
+
+
+
+
+
+ 时间 |
+ 科目 |
+ 开始 |
+ 结束 |
+ 状态 |
+
+
+
+
+
+
+
+
+
+
+
+
+
系统设置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+