Compare commits

..

No commits in common. "main" and "v1.0.1" have entirely different histories.
main ... v1.0.1

69 changed files with 716 additions and 7543 deletions

View File

@ -1,56 +1,46 @@
# ExamSchedule
**不只是考试看板。**
![es](./doc/es.png)
网页版ExamShowboard
![iis-10](https://github.com/user-attachments/assets/a667fc3b-4b9e-4882-9329-fc36786f1980)
## 功能
- 考试看板
- 实时显示当前时间、当前考试科目、考试起止时间、剩余时间及考试状态。
- 支持全屏显示。
- 支持设置时间偏移和考场信息并保存到浏览器Cookie中。
- 支持临时编辑消息并保存到浏览器Cookie中3天后到期
- 时间广播
- 支持自定义广播配置。
- 支持打开本地json配置
- 实时显示当前时间、当前考试科目、考试起止时间、剩余时间及考试状态。
- 支持全屏显示。
- 支持设置时间偏移和考场信息并保存到浏览器Cookie中。
- 支持临时编辑消息并保存到浏览器Cookie中3天后到期
### 考试看板设置说明
### 设置说明
点击设置按钮可以打开设置窗口,进行以下配置:
- **时间偏移**:用于调整显示的时间,单位为秒。
- **考场信息**:用于显示当前考场的名称。
- **页面缩放倍数**:用于调整页面显示的缩放倍数。
- **亮/暗色模式**:用于切换页面的亮/暗色模式背景。
配置完成后点击保存按钮设置将会保存到浏览器的Cookie中并立即生效。
### 编辑消息
点击编辑消息按钮可以打开消息编辑窗口,进行以下操作:
- **消息内容**:用于临时编辑显示的消息。
编辑完成后点击保存按钮消息将会保存到浏览器的Cookie中并立即生效3天内有效
## 软件截图
### 主界面
![es](./doc/es.png)
![main](https://github.com/user-attachments/assets/c41991d9-b169-4b7b-8de5-6192f34ec8c8)
#### 考试展板界面
![exam](https://github.com/user-attachments/assets/0bcf81f7-956b-4bf5-9354-a282d168e972)
![exam](./doc/exam.png)
#### 电子钟表界面
![time](https://github.com/user-attachments/assets/79624458-c76b-4008-b010-754a7c971a60)
#### 电子钟表界面
![time](./doc/time.png)
#### 考试广播界面
![notification](./doc/notification.png)
## 如何部署?
您可以点击查看 [部署教程](https://docs.examaware.tech/app/web/web-deploy.html)了解详细的部署教程。
> [!WARNING]
>
> 注意,广播与看板的配置文件是**分开存储于两个文件夹之下的**。
## 如何部署?
您可以点击查看 [ExamShowboard网页端 部署文档](https://github.com/fhzit/ExamSchedule/wiki)了解详细的部署教程。
## 开发说明

View File

@ -1,212 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>关于 ExamSchedule</title>
<link href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
body {
background: #2C2B30;
margin: 0;
font-family: 'Google Sans', 'Roboto', sans-serif;
color: #E6E1E5;
padding: 40px;
line-height: 1.6;
}
.container {
max-width: 800px;
margin: 0 auto;
animation: fadeInUp 1s ease-in-out;
}
h1 {
color: #E6E1E5;
font-size: 48px;
margin-bottom: 30px;
font-weight: 500;
}
.section {
background: #49454F;
padding: 24px;
border-radius: 16px;
margin-bottom: 24px;
}
h2 {
color: #E6E1E5;
font-size: 24px;
margin-top: 0;
}
.feature-list {
list-style: none;
padding: 0;
}
.feature-list li {
margin-bottom: 12px;
display: flex;
align-items: center; /* 修改为center保证图标和文字垂直居中 */
}
.feature-list .material-icons {
margin-right: 12px;
color: #D0BCFF;
flex-shrink: 0; /* 防止图标被压缩 */
align-self: center; /* 保证图标始终居中 */
}
.back-btn {
position: fixed;
top: 20px;
left: 20px;
color: #E6E1E5;
text-decoration: none;
font-size: 16px;
font-weight: 500;
padding: 12px 24px;
border-radius: 100px;
background-color: #49454F;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
}
.back-btn:hover {
background-color: #605D64;
transform: translateY(-2px);
}
@keyframes fadeInUp {
0% {
opacity: 0;
transform: translateY(20px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
#license-content {
font-size: 0.9em;
color: #CAC4D0;
white-space: pre-wrap;
max-height: 400px;
overflow-y: auto;
padding: 16px;
background: #1C1B1F;
border-radius: 8px;
scrollbar-width: thin;
scrollbar-color: #49454F #1C1B1F;
}
#license-content::-webkit-scrollbar {
width: 8px;
}
#license-content::-webkit-scrollbar-track {
background: #1C1B1F;
border-radius: 8px;
}
#license-content::-webkit-scrollbar-thumb {
background-color: #49454F;
border-radius: 8px;
border: 2px solid #1C1B1F;
}
#license-content::-webkit-scrollbar-thumb:hover {
background-color: #605D64;
}
</style>
</head>
<body>
<a href="../" class="back-btn">
<span class="material-icons">arrow_back</span>
返回
</a>
<div class="container">
<h1>关于 ExamSchedule</h1>
<div class="section">
<h2>功能特点</h2>
<ul class="feature-list">
<li>
<span class="material-icons">dashboard</span>
<div>
<strong>考试看板</strong>
<ul>
<li>实时显示当前时间、考试科目、时间及状态</li>
<li>支持全屏显示</li>
<li>支持设置时间偏移和考场信息</li>
<li>支持临时编辑消息</li>
</ul>
</div>
</li>
<li>
<span class="material-icons">schedule</span>
<div>
<strong>时间广播</strong>
<ul>
<li>支持自定义广播配置</li>
<li>支持打开本地json配置</li>
</ul>
</div>
</li>
</ul>
</div>
<div class="section">
<h2>部署说明</h2>
<p>您可以访问 <a href="https://docs.examaware.tech/app/web/web-deploy.html" style="color: #D0BCFF;">部署教程</a> 了解详细的部署方法。</p>
<p>注意:广播与看板的配置文件是分开存储于两个文件夹之下的。</p>
</div>
<div class="section">
<h2>开发信息</h2>
<ul class="feature-list">
<li>
<span class="material-icons">code</span>
<div>主分支 (main) 提供稳定版本</div>
</li>
<li>
<span class="material-icons">bug_report</span>
<div>开发分支 (dev) 进行新功能开发</div>
</li>
</ul>
</div>
<div class="section">
<h2>许可证</h2>
<ul class="feature-list">
<li>
<span class="material-icons" style="font-size:24px;">gavel</span>
<div>
<p>本项目采用 GNU General Public License v3.0</p>
<pre id="license-content" style="font-size: 0.9em; color: #CAC4D0; white-space: pre-wrap; max-height: 400px; overflow-y: auto; padding: 16px; background: #1C1B1F; border-radius: 8px;">正在加载许可证内容...</pre>
</div>
</li>
</ul>
</div>
</div>
<script>
// 加载LICENSE文件内容
fetch('../LICENSE')
.then(response => response.text())
.then(content => {
document.getElementById('license-content').textContent = content;
})
.catch(error => {
document.getElementById('license-content').textContent = '加载许可证内容失败:' + error;
});
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 939 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 974 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

BIN
background.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

View File

@ -1,370 +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 roomElem = document.getElementById("room");
const infoToggleBtn = document.getElementById("info-toggle-btn");
const paperInfoElem = document.getElementById("paper-info");
const examPapersElem = document.getElementById("exam-papers");
const answerSheetsElem = document.getElementById("answer-sheets");
let offsetTime = getCookie("offsetTime") || 0;
let showPaperInfo = getCookie("showPaperInfo") === "true";
let autoToggle = getCookie("autoToggle") === "true";
// 初始化显示状态
if (showPaperInfo) {
paperInfoElem.style.display = "block";
}
// 更新显示内容
function updateDisplay(isExamTime) {
if (autoToggle) {
paperInfoElem.style.display = isExamTime ? "block" : "none";
}
}
infoToggleBtn.addEventListener("click", () => {
if (!autoToggle) {
showPaperInfo = !showPaperInfo;
paperInfoElem.style.display = showPaperInfo ? "block" : "none";
setCookie("showPaperInfo", showPaperInfo, 365);
}
});
function fetchData() {
// 优先使用本地配置
const localConfig = localStorage.getItem('localExamConfig');
if (localConfig) {
try {
const data = JSON.parse(localConfig);
displayExamInfo(data);
updateCurrentTime();
updateExamInfo(data);
setInterval(() => updateCurrentTime(), 1000);
setInterval(() => updateExamInfo(data), 1000);
return Promise.resolve();
} catch (error) {
localStorage.removeItem('localExamConfig');
errorSystem.show('本地配置无效,已清除并切换至默认配置');
}
}
// 使用默认配置
return fetch('exam_config.json', { cache: "no-store" })
.then(response => 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} <span id="room">${roomText}</span>`;
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 (paperInfoElem) paperInfoElem.style.display = showPaperInfo ? "block" : "none";
if (currentExam) {
const currentStatus = `当前科目: ${currentExam.name}`;
currentSubjectElem.textContent = currentStatus;
paperInfoElem.style.display = showPaperInfo ? "block" : "none";
// 加载本地存储的页数信息
if (showPaperInfo) {
// 加载本地保存的页数信息
const paperCount = document.getElementById('paper-count');
const paperPages = document.getElementById('paper-pages');
const sheetCount = document.getElementById('sheet-count');
const sheetPages = document.getElementById('sheet-pages');
if (paperCount && paperPages && sheetCount && sheetPages) {
try {
const savedInfo = localStorage.getItem('paperInfo');
if (savedInfo) {
const info = JSON.parse(savedInfo);
paperCount.value = info.paperCount || 0;
paperPages.value = info.paperPages || 0;
sheetCount.value = info.sheetCount || 0;
sheetPages.value = info.sheetPages || 0;
}
} catch (e) {
console.error('加载页数信息失败:', e);
}
}
}
if (examTimingElem) {
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);
let remainingTimeText = '';
if (remainingHours > 0) {
remainingTimeText = `${remainingHours}${String(remainingMinutes).padStart(2, '0')}${String(remainingSeconds).padStart(2, '0')}`;
} else {
remainingTimeText = `${String(remainingMinutes).padStart(2, '0')}${String(remainingSeconds).padStart(2, '0')}`;
}
if (remainingHours === 0 && remainingMinutes <= 14) {
if (remainingTimeElem) {
remainingTimeElem.textContent = `剩余时间: ${remainingTimeText}`;
remainingTimeElem.style.color = "#93b4f7";
remainingTimeElem.style.fontWeight = "normal";
}
if (statusElem) {
statusElem.textContent = "状态: 即将结束";
statusElem.style.color = "red";
}
// 在剩余15分钟时显示提醒
if (remainingMinutes === 14 && remainingSeconds === 59) {
const overlay = document.getElementById('reminder-overlay');
if (overlay) {
overlay.classList.add('show');
setTimeout(() => {
overlay.classList.remove('show');
}, 5000);
}
}
} else {
if (remainingTimeElem) {
remainingTimeElem.textContent = `剩余时间: ${remainingTimeText}`;
remainingTimeElem.style.color = "#93b4f7";
remainingTimeElem.style.fontWeight = "normal";
}
if (statusElem) {
statusElem.textContent = "状态: 进行中";
statusElem.style.color = "#5ba838";
}
}
} else {
updateDisplay(false);
if (lastExam && now < new Date(lastExam.end).getTime() + 60000) {
if (currentSubjectElem) currentSubjectElem.textContent = `上场科目: ${lastExam.name}`;
if (examTimingElem) examTimingElem.textContent = "";
if (remainingTimeElem) remainingTimeElem.textContent = "";
if (statusElem) {
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);
let remainingTimeText = '';
if (remainingHours > 0) {
remainingTimeText = `${remainingHours}${String(remainingMinutes).padStart(2, '0')}${String(remainingSeconds).padStart(2, '0')}`;
} else {
remainingTimeText = `${String(remainingMinutes).padStart(2, '0')}${String(remainingSeconds).padStart(2, '0')}`;
}
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 {
if (currentSubjectElem) {
currentSubjectElem.textContent = "考试均已结束";
currentSubjectElem.style.color = "#aaaaaa";
currentSubjectElem.style.textAlign = "center";
}
if (examTimingElem) examTimingElem.textContent = "";
if (remainingTimeElem) remainingTimeElem.textContent = "";
if (statusElem) {
statusElem.textContent = " ";
statusElem.style.color = "#000000";
}
}
}
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()}日<br>${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 = `<td rowspan="${totalRows}">${dateStr}</td>`;
isFirstRow = false;
}
// 仅在第一个科目行添加时间和状态
if (index === 0) {
cells += `
<td>${subject.trim()}</td>
<td rowspan="${subjects.length}">${formatTimeWithoutSeconds(start.toLocaleTimeString('zh-CN', { hour12: false }))}</td>
<td rowspan="${subjects.length}">${formatTimeWithoutSeconds(end.toLocaleTimeString('zh-CN', { hour12: false }))}</td>
<td rowspan="${subjects.length}"><span class="exam-status-tag exam-status-${status}">${status}</span></td>
`;
} else {
cells += `<td>${subject.trim()}</td>`;
}
row.innerHTML = cells;
examTableBodyElem.appendChild(row);
});
});
});
} catch (e) {
console.error('更新考试信息失败:', e);
errorSystem.show('更新考试信息失败: ' + e.message);
}
}
// 添加页数控制处理
document.querySelectorAll('.count-btn').forEach(btn => {
btn.addEventListener('click', () => {
const target = document.getElementById(btn.dataset.target);
const action = btn.dataset.action;
const currentValue = parseInt(target.value) || 0;
if (action === 'increase') {
target.value = currentValue + 1;
} else if (action === 'decrease' && currentValue > 0) {
target.value = currentValue - 1;
}
// 保存到localStorage
updatePaperInfo();
});
});
// 监听输入框直接输入
['paper-count', 'paper-pages', 'sheet-count', 'sheet-pages'].forEach(id => {
const input = document.getElementById(id);
input.addEventListener('change', () => {
const value = parseInt(input.value) || 0;
input.value = Math.max(0, value); // 确保不小于0
updatePaperInfo();
});
});
function updatePaperInfo() {
const paperInfo = {
paperCount: parseInt(document.getElementById('paper-count').value) || 0,
paperPages: parseInt(document.getElementById('paper-pages').value) || 0,
sheetCount: parseInt(document.getElementById('sheet-count').value) || 0,
sheetPages: parseInt(document.getElementById('sheet-pages').value) || 0
};
localStorage.setItem('paperInfo', JSON.stringify(paperInfo));
}
// 初始化加载保存的页数信息
function loadPaperInfo() {
try {
const savedInfo = localStorage.getItem('paperInfo');
if (savedInfo) {
const info = JSON.parse(savedInfo);
document.getElementById('paper-count').value = info.paperCount || 0;
document.getElementById('paper-pages').value = info.paperPages || 0;
document.getElementById('sheet-count').value = info.sheetCount || 0;
document.getElementById('sheet-pages').value = info.sheetPages || 0;
}
} catch (e) {
console.error('加载页数信息失败:', e);
}
}
loadPaperInfo();
fetchData();
});

View File

@ -1,17 +0,0 @@
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);
}
});
});

View File

@ -1,175 +0,0 @@
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");
const configFileInput = document.getElementById("config-file");
const clearConfigBtn = document.getElementById("clear-config-btn");
const themeSelect = document.getElementById("theme-select");
const autoToggle = document.getElementById("auto-toggle");
let offsetTime = getCookie("offsetTime") || 0;
let room = getCookie("room") || "";
let zoomLevel = getCookie("zoomLevel") || 1;
let currentTheme = getCookie("currentTheme") || "ealg";
let theme = getCookie("theme") || "dark";
let isAutoToggle = getCookie("autoToggle") || false;
let themeConfig = [];
offsetTime = parseInt(offsetTime);
roomElem.textContent = room;
autoToggle.checked = isAutoToggle === "true";
// 初始化主题
const currentThemePath = `Styles/${currentTheme}/${theme}.css`;
themeLink.href = currentThemePath;
themeToggle.checked = theme === "light";
// 加载主题配置
fetch('Styles/profile.json')
.then(response => response.json())
.then(data => {
themeConfig = data.theme;
// 填充主题选择下拉框
themeConfig.forEach(theme => {
const option = document.createElement('option');
option.value = theme.path || theme.type;
option.textContent = theme.name;
themeSelect.appendChild(option);
});
themeSelect.value = currentTheme;
updateThemeLink();
})
.catch(error => errorSystem.show('加载主题配置失败: ' + error.message));
function updateThemeLink() {
const themePath = currentTheme;
const isDark = !themeToggle.checked;
themeLink.href = `Styles/${themePath}/${isDark ? 'dark' : 'light'}.css`;
}
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";
currentTheme = themeSelect.value;
isAutoToggle = autoToggle.checked;
setCookie("offsetTime", offsetTime, 365);
setCookie("room", room, 365);
setCookie("zoomLevel", zoomLevel, 365);
setCookie("theme", theme, 365);
setCookie("currentTheme", currentTheme, 365);
setCookie("autoToggle", isAutoToggle, 365);
roomElem.textContent = room;
document.body.style.zoom = zoomLevel;
updateThemeLink();
settingsModal.classList.add("fade-out");
setTimeout(() => {
settingsModal.style.display = "none";
settingsModal.classList.remove("fade-out");
}, 300);
// 立即生效时间偏移
location.reload();
} catch (e) {
errorSystem.show('保存设置失败: ' + e.message);
}
});
themeSelect.addEventListener("change", () => {
currentTheme = themeSelect.value;
updateThemeLink();
});
themeToggle.addEventListener("change", () => {
updateThemeLink();
});
configFileInput.addEventListener("change", (event) => {
try {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
try {
const config = JSON.parse(e.target.result);
// 验证配置文件格式
if (!config.examInfos || !Array.isArray(config.examInfos)) {
throw new Error("无效的配置文件格式");
}
// 验证每个考试信息
config.examInfos.forEach(exam => {
if (!exam.name || !exam.start || !exam.end) {
throw new Error("考试信息不完整");
}
// 验证日期格式
if (isNaN(new Date(exam.start).getTime()) || isNaN(new Date(exam.end).getTime())) {
throw new Error("无效的日期格式");
}
});
// 保存配置到本地存储
localStorage.setItem('localExamConfig', JSON.stringify(config));
errorSystem.show('配置文件已加载,将在下次启动时生效');
} catch (error) {
errorSystem.show('配置文件格式错误: ' + error.message);
}
};
reader.readAsText(file);
} catch (e) {
errorSystem.show('读取文件失败: ' + e.message);
}
});
clearConfigBtn.addEventListener("click", () => {
try {
if (confirm("确定要清除本地配置吗?这将恢复使用默认配置文件。")) {
localStorage.removeItem('localExamConfig');
configFileInput.value = ''; // 清空文件选择
errorSystem.show('本地配置已清除,将在下次启动时生效');
}
} catch (e) {
errorSystem.show('清除配置失败: ' + e.message);
}
});
try {
document.body.style.zoom = zoomLevel;
} catch (e) {
errorSystem.show('初始化缩放失败: ' + e.message);
}
});

View File

@ -1,39 +0,0 @@
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';
}
};

View File

@ -1,670 +0,0 @@
#return-btn {
position: absolute; /* 绝对定位 */
top: 20px; /* 距离顶部 20px */
left: 20px; /* 距离左侧 20px */
padding: 12px 24px; /* 内边距 */
font-size: 1rem; /* 字体大小 */
cursor: pointer; /* 鼠标悬停时显示为手型 */
background-color: #404040; /* 修改为统一的灰色背景 */
color: #E6E1E5; /* 按钮文字颜色 */
border: none; /* 按钮边框样式 */
border-radius: 20px; /* 按钮圆角大小 */
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); /* 按钮阴影 */
transition: all 0.2s ease; /* 背景颜色和缩放的过渡效果 */
z-index: 1001; /* 按钮层级 */
}
#return-btn:hover {
background-color: #4A4A4A; /* 统一的灰色悬停背景 */
transform: translateY(-1px); /* 悬停时向上移动 1px */
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4); /* 悬停时的阴影效果 */
}
body {
font-family: 'Roboto', 'HarmonyOS Sans SC', sans-serif;
margin: 0;
padding: 0;
background: #121212;
color: #E6E1E5;
overflow: auto;
}
body::-webkit-scrollbar {
display: none;
}
#fullscreen-btn, #settings-btn {
position: absolute;
top: 20px;
padding: 12px 24px;
font-size: 1rem;
cursor: pointer;
background-color: #404040;
color: #E6E1E5;
border: none;
border-radius: 20px;
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
transition: all 0.2s ease;
z-index: 1001;
display: flex;
align-items: center;
}
#fullscreen-btn::before {
content: "fullscreen";
font-family: 'Material Icons';
font-size: 20px;
margin-right: 4px;
}
#settings-btn::before {
content: "settings";
font-family: 'Material Icons';
font-size: 20px;
margin-right: 4px;
}
#fullscreen-btn {
right: 20px;
}
#settings-btn {
right: 140px;
}
#settings-btn:hover, #fullscreen-btn:hover {
background-color: #4A4A4A;
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0,0,0,0.4);
}
.container {
padding: 24px;
max-width: 90%;
margin: auto;
background-color: #121212;
}
h1 {
font-size: 3.5rem;
font-weight: 400;
text-align: left;
margin-bottom: 16px;
color: #E6E1E5;
display: flex;
align-items: center;
justify-content: space-between;
}
#room {
font-size: 3.5rem;
font-weight: 400;
color: #E6E1E5;
margin-left: 20px;
}
#message {
font-size: 1.8rem;
color: #aaaaaa;
margin-bottom: 24px;
}
.content {
display: flex;
justify-content: space-between;
gap: 24px;
}
.left-column, .right-column {
display: flex;
flex-direction: column;
gap: 24px;
}
.left-column {
width: 50%;
}
.right-column {
width: 50%;
}
.clock-section, .info-section, .right-column {
background-color: #212121;
padding: 24px;
border-radius: 14px;
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}
#current-time {
font-size: 8rem;
text-align: center;
color: #FFFFFF;
margin: 0;
font-weight: 400;
}
#current-subject, #exam-timing, #remaining-time, #status {
font-size: 3rem;
margin: 16px 0;
text-align: left;
color: #FFFFFF;
}
table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
margin-top: 24px;
background-color: #212121;
border-radius: 14px;
overflow: hidden;
}
th, td {
padding: 3px;
font-size: 1.8rem;
text-align: center;
border-bottom: 1px solid #555555;
}
th {
background-color: transparent;
color: #FFFFFF;
font-weight: 500;
}
tr:hover {
background-color: #555555;
}
.exam-status-tag {
padding: 2px 4px;
border-radius: 3px;
font-size: 1.2rem;
font-weight: 500;
}
.exam-status-进行中 {
background-color: #263227;
color: green;
}
.exam-status-即将开始 {
background-color: #594300;
color: #FFB960;
}
.exam-status-已结束 {
background-color: #3a2523;
color: red;
}
.exam-status-未开始 {
background-color: #3c2f1d;
color: orange;
}
#settings-modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.6);
backdrop-filter: blur(8px);
}
#settings-modal-content {
background: #404040;
padding: 32px 48px 32px 32px;
margin: 32px auto;
border-radius: 28px;
width: 600px;
max-height: 60vh;
overflow-y: auto;
box-shadow: 0 8px 24px rgba(0,0,0,0.4);
}
#settings-modal-content::-webkit-scrollbar {
width: 8px;
}
#settings-modal-content::-webkit-scrollbar-track {
background: transparent;
margin: 4px;
}
#settings-modal-content::-webkit-scrollbar-thumb {
background: #4A4458;
border-radius: 8px;
border: 2px solid #2B2930;
}
#settings-modal-content::-webkit-scrollbar-thumb:hover {
background: #635B70;
}
#settings-modal-content h3 {
margin: 0 0 24px;
color: #E6E1E5;
font-size: 24px;
font-weight: 400;
}
#settings-modal-content label {
display: flex;
align-items: center;
gap: 16px;
margin: 16px 0;
font-size: 16px;
color: #E6E1E5;
}
#settings-modal-content input[type="number"],
#settings-modal-content input[type="text"] {
font-size: 1.8rem;
padding: 12px 16px;
margin: 8px 0 24px;
width: 100%;
box-sizing: border-box;
border: 2px solid #4A4458;
border-radius: 12px;
background-color: #332D41;
color: #E6E1E5;
transition: all 0.2s ease;
}
#settings-modal-content input:focus {
outline: none;
border-color: #D0BCFF;
background-color: #4A4458;
}
.button-group {
display: flex;
justify-content: flex-end;
gap: 16px;
margin-top: 32px;
position: relative;
background-color: #404040;
padding: 16px 0;
border-top: 1px solid #555555;
}
#save-settings-btn, #close-settings-btn {
padding: 12px 24px;
border-radius: 20px;
font-size: 16px;
font-weight: 500;
border: none;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 8px;
}
#save-settings-btn {
background-color: #404040;
color: #E6E1E5;
}
#save-settings-btn::before {
content: "✓";
font-size: 18px;
}
#close-settings-btn {
background-color: #404040;
color: #E6E1E5;
}
#close-settings-btn::before {
content: "✕";
font-size: 18px;
}
#save-settings-btn:hover, #close-settings-btn:hover {
background-color: #4A4A4A;
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0,0,0,0.4);
}
.error-container {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%);
background: #5C1130;
color: #FFB3B3;
padding: 16px 24px;
border-radius: 16px;
display: none;
z-index: 10001;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
animation: slideUp 0.3s ease;
}
.switch {
position: relative;
display: inline-block;
width: 52px;
height: 32px;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #4A4458;
transition: .3s;
border-radius: 16px;
}
.slider:before {
position: absolute;
content: "";
height: 24px;
width: 24px;
left: 4px;
bottom: 4px;
background-color: #E6E1E5;
transition: .3s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #D0BCFF;
}
input:checked + .slider:before {
transform: translateX(20px);
background-color: #1C1B1F;
}
.config-file-container {
margin: 24px 0;
padding: 24px;
border: 2px solid #555555;
border-radius: 20px;
background-color: #4A4A4A;
transition: all 0.2s ease;
}
.config-file-container:hover {
border-color: #D0BCFF;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.config-file-container input[type="file"] {
max-width: 100%;
width: auto;
box-sizing: border-box;
padding: 12px;
border: 2px dashed #4A4458;
border-radius: 16px;
background-color: #332D41;
color: #E6E1E5;
cursor: pointer;
transition: all 0.2s ease;
}
.config-file-container input[type="file"]::-webkit-file-upload-button {
padding: 8px 16px;
margin-right: 12px;
background-color: #404040;
color: #E6E1E5;
border: none;
border-radius: 12px;
cursor: pointer;
transition: all 0.2s ease;
}
.config-file-container input[type="file"]::-webkit-file-upload-button:hover {
background-color: #4A4A4A;
}
.file-hint {
margin-top: 12px;
font-size: 14px;
color: #CAC4D0;
line-height: 1.5;
}
.config-control-btn {
margin-top: 20px;
padding: 12px 28px;
background-color: #404040;
color: #E6E1E5;
border: none;
border-radius: 24px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
justify-content: center;
}
.config-control-btn:hover {
background-color: #4A4A4A;
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0,0,0,0.4);
}
.theme-toggle-container {
margin: 24px 0;
display: flex;
flex-direction: column;
gap: 16px;
}
#theme-select {
width: 100%;
padding: 12px 16px;
font-size: 1.2rem;
background-color: #404040;
color: #FFFFFF;
border: 2px solid #555555;
border-radius: 12px;
cursor: pointer;
appearance: none;
-webkit-appearance: none;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right 16px center;
background-size: 16px;
}
#theme-select:hover {
background-color: #4A4A4A;
border-color: #666666;
}
#theme-select:focus {
outline: none;
border-color: #D0BCFF;
background-color: #4A4A4A;
}
#theme-select option {
background-color: #404040;
color: #FFFFFF;
padding: 12px;
}
#theme-select option:hover,
#theme-select option:focus {
background-color: #4A4A4A;
}
.theme-toggle-container label {
font-size: 16px;
color: #E6E1E5;
margin-bottom: 8px;
}
.reminder-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.95);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all 0.5s ease;
backdrop-filter: blur(8px);
z-index: 9999;
}
.reminder-overlay.show {
opacity: 1;
visibility: visible;
}
.reminder-content {
text-align: center;
animation: fadeIn 0.5s ease;
}
.reminder-title {
font-size: 5rem;
color: white;
margin-bottom: 2rem;
}
.reminder-subtitle {
font-size: 3rem;
color: #FFD60A;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.info-section {
position: relative;
}
.info-toggle-btn {
position: absolute;
right: 0;
top: 0;
background-color: #404040;
color: #E6E1E5;
border: none;
border-radius: 50%;
width: 48px;
height: 48px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
z-index: 2;
}
.info-toggle-btn:hover {
background-color: #4A4A4A;
transform: translateY(-1px);
}
.info-toggle-btn .material-icons {
font-size: 24px;
}
.paper-count-container {
margin: 20px 0;
}
.paper-input-group {
display: flex;
align-items: center;
gap: 10px;
margin: 10px 0;
font-size: 2.5rem;
}
.count-control {
display: flex;
align-items: center;
gap: 5px;
}
.count-control input {
width: 60px;
padding: 5px;
font-size: 2rem;
text-align: center;
background-color: #212121;
color: #E6E1E5;
border: 2px solid #404040;
border-radius: 8px;
}
.count-btn {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border: none;
border-radius: 50%;
background-color: #404040;
color: #E6E1E5;
cursor: pointer;
transition: all 0.2s ease;
}
.count-btn:hover {
background-color: #4A4A4A;
transform: translateY(-1px);
}
.count-btn .material-icons {
font-size: 20px;
}
.count-btn-group {
display: flex;
flex-direction: column;
gap: 2px;
margin-right: 8px;
}
.count-control {
display: flex;
align-items: center;
gap: 5px;
}
.count-btn {
width: 24px;
height: 24px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
}
.count-btn .material-icons {
font-size: 16px;
}

View File

@ -1,670 +0,0 @@
#return-btn {
position: absolute; /* 绝对定位 */
top: 20px; /* 距离顶部 20px */
left: 20px; /* 距离左侧 20px */
padding: 12px 24px; /* 内边距 */
font-size: 1rem; /* 字体大小 */
cursor: pointer; /* 鼠标悬停时显示为手型 */
background-color: #E8DEF8; /* 按钮背景颜色 */
color: #1C1B1F; /* 按钮文字颜色 */
border: none; /* 按钮边框样式 */
border-radius: 20px; /* 按钮圆角大小 */
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); /* 按钮阴影 */
transition: all 0.2s ease; /* 背景颜色和缩放的过渡效果 */
z-index: 1001; /* 按钮层级 */
}
#return-btn:hover {
background-color: #D0BCFF; /* 悬停时的背景颜色 */
transform: translateY(-1px); /* 悬停时向上移动 1px */
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); /* 悬停时的阴影效果 */
}
body {
font-family: 'Roboto', 'HarmonyOS Sans SC', sans-serif;
margin: 0;
padding: 0;
background: #FFFBFE;
color: #1C1B1F;
overflow: auto;
}
body::-webkit-scrollbar {
display: none;
}
#fullscreen-btn, #settings-btn {
position: absolute;
top: 20px;
padding: 12px 24px;
font-size: 1rem;
cursor: pointer;
background-color: #E8DEF8;
color: #1C1B1F;
border: none;
border-radius: 20px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
transition: all 0.2s ease;
z-index: 1001;
display: flex;
align-items: center;
}
#fullscreen-btn {
right: 20px;
}
#settings-btn {
right: 140px;
}
#settings-btn:hover, #fullscreen-btn:hover {
background-color: #D0BCFF;
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}
#settings-btn::before {
content: "settings";
font-family: 'Material Icons';
font-size: 20px;
margin-right: 4px;
}
#fullscreen-btn::before {
content: "fullscreen";
font-family: 'Material Icons';
font-size: 20px;
margin-right: 4px;
}
.container {
padding: 24px;
max-width: 100%;
margin: auto;
background-color: #FFFFFF;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
h1 {
font-size: 3.5rem;
font-weight: 400;
text-align: left;
margin-bottom: 16px;
color: #1C1B1F;
display: flex;
align-items: center;
justify-content: space-between;
}
#room {
font-size: 3.5rem;
font-weight: 400;
color: #1C1B1F;
margin-left: 20px;
}
#message {
font-size: 1.8rem;
color: #6750A4;
margin-bottom: 24px;
}
.content {
display: flex;
justify-content: space-between;
gap: 24px;
}
.left-column, .right-column {
display: flex;
flex-direction: column;
gap: 24px;
}
.left-column {
width: 45%;
}
.right-column {
width: 50%;
}
.clock-section, .info-section, .right-column {
background-color: #FFFFFF;
padding: 24px;
border-radius: 28px;
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
}
#current-time {
font-size: 8rem;
text-align: center;
color: #000000;
margin: 0;
font-weight: 400;
}
#current-subject, #exam-timing, #remaining-time, #status {
font-size: 3rem;
margin: 16px 0;
text-align: left;
color: #000000;
}
table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
margin-top: 24px;
background-color: #FFFFFF;
border-radius: 16px;
overflow: hidden;
}
th, td {
padding: 3px; /* 修改padding值以匹配dark主题 */
font-size: 1.8rem;
text-align: center;
border-bottom: 1px solid #E8DEF8; /* 修改边框颜色 */
}
th {
background-color: #ffffff;
color: #1C1B1F;
font-weight: 500;
}
tr:hover {
background-color: #F7F2FA;
}
.exam-status-tag {
padding: 2px 4px; /* 修改padding值以匹配dark主题 */
border-radius: 3px; /* 修改圆角大小 */
font-size: 1.2rem; /* 修改字体大小 */
font-weight: 500;
}
.exam-status-进行中 {
background-color: #DDF4D7;
color: #365534;
}
.exam-status-即将开始 {
background-color: #FFF2D6;
color: #594300;
}
.exam-status-已结束 {
background-color: #FFDAD6;
color: #5C1130;
}
.exam-status-未开始 {
background-color: #E8DEF8;
color: #1C1B1F;
}
#settings-modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.3);
backdrop-filter: blur(8px);
}
#settings-modal-content {
background: #FFFFFF;
padding: 32px 48px 32px 32px;
margin: 32px auto;
border-radius: 28px;
width: 600px;
max-height: 60vh;
overflow-y: auto;
box-shadow: 0 8px 24px rgba(0,0,0,0.2);
}
#settings-modal-content::-webkit-scrollbar {
width: 8px;
}
#settings-modal-content::-webkit-scrollbar-track {
background: transparent;
margin: 4px;
}
#settings-modal-content::-webkit-scrollbar-thumb {
background: #E8DEF8;
border-radius: 8px;
border: 2px solid #FFFFFF;
}
#settings-modal-content::-webkit-scrollbar-thumb:hover {
background: #D0BCFF;
}
#settings-modal-content h3 {
margin: 0 0 24px;
color: #1C1B1F;
font-size: 24px;
font-weight: 400;
}
#settings-modal-content label {
display: flex;
align-items: center;
gap: 16px;
margin: 16px 0;
font-size: 16px;
color: #1C1B1F;
}
#settings-modal-content input[type="number"],
#settings-modal-content input[type="text"] {
font-size: 1.8rem;
padding: 12px 16px;
margin: 8px 0 24px;
width: 100%;
box-sizing: border-box;
border: 2px solid #E8DEF8;
border-radius: 12px;
background-color: #FFFFFF;
color: #1C1B1F;
transition: all 0.2s ease;
}
#settings-modal-content input:focus {
outline: none;
border-color: #6750A4;
background-color: #F7F2FA;
}
.button-group {
display: flex;
justify-content: flex-end;
gap: 16px;
margin-top: 32px;
position: relative;
background-color: #FFFFFF;
padding: 16px 0;
border-top: 1px solid #E8DEF8;
}
#save-settings-btn, #close-settings-btn {
padding: 12px 24px;
border-radius: 20px;
font-size: 16px;
font-weight: 500;
border: none;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 8px;
}
#save-settings-btn {
background-color: #6750A4;
color: #FFFFFF;
}
#close-settings-btn {
background-color: #E8DEF8;
color: #1C1B1F;
}
#save-settings-btn:hover, #close-settings-btn:hover {
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}
#save-settings-btn::before {
content: "✓";
font-size: 18px;
}
#close-settings-btn::before {
content: "✕";
font-size: 18px;
}
.error-container {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%);
background: #FFDAD6;
color: #5C1130;
padding: 16px 24px;
border-radius: 16px;
display: none;
z-index: 10001;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
animation: slideUp 0.3s ease;
}
.switch {
position: relative;
display: inline-block;
width: 52px;
height: 32px;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #E8DEF8;
transition: .3s;
border-radius: 16px;
}
.slider:before {
position: absolute;
content: "";
height: 24px;
width: 24px;
left: 4px;
bottom: 4px;
background-color: #FFFFFF;
transition: .3s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #6750A4;
}
input:checked + .slider:before {
transform: translateX(20px);
background-color: #FFFFFF;
}
.config-file-container {
margin: 24px 0;
padding: 24px;
border: 2px solid #E8DEF8;
border-radius: 20px;
background-color: #F7F2FA;
transition: all 0.2s ease;
}
.config-file-container:hover {
border-color: #6750A4;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.config-file-container input[type="file"] {
max-width: 100%;
width: auto;
box-sizing: border-box;
padding: 12px;
border: 2px dashed #E8DEF8;
border-radius: 16px;
background-color: #FFFFFF;
color: #1C1B1F;
cursor: pointer;
transition: all 0.2s ease;
}
.config-file-container input[type="file"]::-webkit-file-upload-button {
padding: 8px 16px;
margin-right: 12px;
background-color: #E8DEF8;
color: #1C1B1F;
border: none;
border-radius: 12px;
cursor: pointer;
transition: all 0.2s ease;
}
.config-file-container input[type="file"]::-webkit-file-upload-button:hover {
background-color: #D0BCFF;
}
.file-hint {
margin-top: 12px;
font-size: 14px;
color: #49454F;
line-height: 1.5;
}
.config-control-btn {
margin-top: 20px;
padding: 12px 28px;
background-color: #E8DEF8;
color: #1C1B1F;
border: none;
border-radius: 24px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
justify-content: center;
}
.config-control-btn:hover {
background-color: #D0BCFF;
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
.theme-toggle-container {
margin: 24px 0;
display: flex;
flex-direction: column;
gap: 16px;
}
#theme-select {
width: 100%;
padding: 12px 16px;
font-size: 1.2rem;
background-color: #FFFFFF;
color: #1C1B1F;
border: 2px solid #E8DEF8;
border-radius: 12px;
cursor: pointer;
appearance: none;
-webkit-appearance: none;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right 16px center;
background-size: 16px;
}
#theme-select:hover {
background-color: #F7F2FA;
border-color: #D0BCFF;
}
#theme-select:focus {
outline: none;
border-color: #6750A4;
background-color: #F7F2FA;
}
#theme-select option {
background-color: #FFFFFF;
color: #1C1B1F;
padding: 12px;
}
#theme-select option:hover,
#theme-select option:focus {
background-color: #F7F2FA;
}
.theme-toggle-container label {
font-size: 16px;
color: #1C1B1F;
margin-bottom: 8px;
}
.reminder-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.95);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all 0.5s ease;
backdrop-filter: blur(8px);
z-index: 9999;
}
.reminder-overlay.show {
opacity: 1;
visibility: visible;
}
.reminder-content {
text-align: center;
animation: fadeIn 0.5s ease;
}
.reminder-title {
font-size: 5rem;
color: #FF3B30;
margin-bottom: 2rem;
}
.reminder-subtitle {
font-size: 3rem;
color: #FF9500;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.info-section {
position: relative;
}
.info-toggle-btn {
position: absolute;
right: 0;
top: 0;
background-color: #E8DEF8;
color: #1C1B1F;
border: none;
border-radius: 50%;
width: 48px;
height: 48px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
z-index: 2;
}
.info-toggle-btn:hover {
background-color: #D0BCFF;
transform: translateY(-1px);
}
.info-toggle-btn .material-icons {
font-size: 24px;
}
.paper-count-container {
margin: 20px 0;
}
.paper-input-group {
display: flex;
align-items: center;
gap: 10px;
margin: 10px 0;
font-size: 2.5rem;
}
.count-control {
display: flex;
align-items: center;
gap: 5px;
}
.count-btn {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border: none;
border-radius: 50%;
background-color: #E8DEF8;
color: #1C1B1F;
cursor: pointer;
transition: all 0.2s ease;
}
.count-btn:hover {
background-color: #D0BCFF;
transform: translateY(-1px);
}
.count-btn .material-icons {
font-size: 20px;
}
.count-btn-group {
display: flex;
flex-direction: column;
gap: 2px;
margin-right: 8px;
}
.count-control {
display: flex;
align-items: center;
gap: 5px;
}
.count-btn {
width: 24px;
height: 24px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
}
.count-btn .material-icons {
font-size: 16px;
}
.count-control input {
width: 60px;
padding: 5px;
font-size: 2rem;
text-align: center;
background-color: #FFFFFF;
color: #1C1B1F;
border: 2px solid #E8DEF8;
border-radius: 8px;
}

View File

@ -1,703 +0,0 @@
#return-btn {
position: absolute; /* 绝对定位 */
top: 20px; /* 距离顶部 20px */
left: 20px; /* 距离左侧 20px */
padding: 12px 24px; /* 内边距 */
font-size: 1rem; /* 字体大小 */
cursor: pointer; /* 鼠标悬停时显示为手型 */
background-color: #4A4458; /* 按钮背景颜色 */
color: #E6E1E5; /* 按钮文字颜色 */
border: none; /* 按钮边框样式 */
border-radius: 20px; /* 按钮圆角大小 */
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); /* 按钮阴影 */
transition: all 0.2s ease; /* 背景颜色和缩放的过渡效果 */
z-index: 1001; /* 按钮层级 */
}
#return-btn:hover {
background-color: #635B70; /* 悬停时的背景颜色 */
transform: translateY(-1px); /* 悬停时向上移动 1px */
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4); /* 悬停时的阴影效果 */
}
body {
font-family: 'Roboto', 'HarmonyOS Sans SC', sans-serif;
margin: 0;
padding: 0;
background: #1C1B1F;
color: #E6E1E5;
overflow: auto;
}
body::-webkit-scrollbar {
display: none;
}
#fullscreen-btn, #settings-btn {
position: absolute;
top: 20px;
padding: 12px 24px;
font-size: 1rem;
cursor: pointer;
background-color: #4A4458;
color: #E6E1E5;
border: none;
border-radius: 20px;
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
transition: all 0.2s ease;
z-index: 1001;
display: flex;
align-items: center;
}
#fullscreen-btn::before {
content: "fullscreen";
font-family: 'Material Icons';
font-size: 20px;
margin-right: 4px;
}
#settings-btn::before {
content: "settings";
font-family: 'Material Icons';
font-size: 20px;
margin-right: 4px;
}
#fullscreen-btn {
right: 20px;
}
#settings-btn {
right: 140px;
}
#settings-btn:hover, #fullscreen-btn:hover {
background-color: #635B70;
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0,0,0,0.4);
}
.container {
padding: 24px;
max-width: 1400px;
margin: auto;
background-color: #2B2930;
border-radius: 28px;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
h1 {
font-size: 3.5rem;
font-weight: 400;
text-align: left;
margin-bottom: 16px;
color: #E6E1E5;
display: flex;
align-items: center;
justify-content: space-between;
}
#room {
font-size: 3.5rem;
font-weight: 400;
color: #E6E1E5;
margin-left: 20px;
}
#message {
font-size: 1.8rem;
color: #D0BCFF;
margin-bottom: 24px;
}
.content {
display: flex;
justify-content: space-between;
gap: 24px;
}
.left-column, .right-column {
display: flex;
flex-direction: column;
gap: 24px;
}
.left-column {
width: 45%;
}
.right-column {
width: 50%;
}
.clock-section, .info-section, .right-column {
background-color: #332D41;
padding: 24px;
border-radius: 28px;
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}
#current-time {
font-size: 8rem;
text-align: center;
color: #D0BCFF;
margin: 0;
font-weight: 400;
}
#current-subject, #exam-timing, #remaining-time, #status {
font-size: 3rem;
margin: 16px 0;
text-align: left;
color: #E6E1E5;
}
table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
margin-top: 24px;
background-color: #332D41;
border-radius: 16px;
overflow: hidden;
}
th, td {
padding: 1px;
font-size: 1.8rem;
text-align: center;
border-bottom: 1px solid #4A4458;
}
th {
background-color: #4A4458;
color: #D0BCFF;
font-weight: 500;
}
tr:hover {
background-color: #4A4458;
}
.exam-status-tag {
padding: 2px 4px;
border-radius: 3px;
font-size: 1.2rem;
font-weight: 500;
}
.exam-status-进行中 {
background-color: #263227;
color: green;
}
.exam-status-即将开始 {
background-color: #594300;
color: #FFB960;
}
.exam-status-已结束 {
background-color: #3a2523;
color: red;
}
.exam-status-未开始 {
background-color: #3c2f1d;
color: orange;
}
#settings-modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.6);
backdrop-filter: blur(8px);
}
#settings-modal-content {
background: #2B2930;
padding: 32px 48px 32px 32px;
margin: 32px auto;
border-radius: 28px;
width: 600px;
max-height: 60vh;
overflow-y: auto;
box-shadow: 0 8px 24px rgba(0,0,0,0.4);
}
#settings-modal-content::-webkit-scrollbar {
width: 8px;
}
#settings-modal-content::-webkit-scrollbar-track {
background: transparent;
margin: 4px;
}
#settings-modal-content::-webkit-scrollbar-thumb {
background: #4A4458;
border-radius: 8px;
border: 2px solid #2B2930;
}
#settings-modal-content::-webkit-scrollbar-thumb:hover {
background: #635B70;
}
#settings-modal-content h3 {
margin: 0 0 24px;
color: #E6E1E5;
font-size: 24px;
font-weight: 400;
}
#settings-modal-content label {
display: flex;
align-items: center;
gap: 16px;
margin: 16px 0;
font-size: 16px;
color: #E6E1E5;
}
#settings-modal-content input[type="number"],
#settings-modal-content input[type="text"] {
font-size: 1.8rem;
padding: 12px 16px;
margin: 8px 0 24px;
width: 100%;
box-sizing: border-box;
border: 2px solid #4A4458;
border-radius: 12px;
background-color: #332D41;
color: #E6E1E5;
transition: all 0.2s ease;
}
#settings-modal-content input:focus {
outline: none;
border-color: #D0BCFF;
background-color: #4A4458;
}
.button-group {
display: flex;
justify-content: flex-end;
gap: 16px;
margin-top: 32px;
position: relative;
background-color: #2B2930;
padding: 16px 0;
border-top: 1px solid #4A4458;
}
#save-settings-btn, #close-settings-btn {
padding: 12px 24px;
border-radius: 20px;
font-size: 16px;
font-weight: 500;
border: none;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 8px;
}
#save-settings-btn {
background-color: #D0BCFF;
color: #1C1B1F;
}
#close-settings-btn {
background-color: #4A4458;
color: #E6E1E5;
}
#save-settings-btn:hover, #close-settings-btn:hover {
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0,0,0,0.4);
}
#save-settings-btn::before {
content: "✓";
font-size: 18px;
}
#close-settings-btn::before {
content: "✕";
font-size: 18px;
}
.error-container {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%);
background: #5C1130;
color: #FFB3B3;
padding: 16px 24px;
border-radius: 16px;
display: none;
z-index: 10001;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
animation: slideUp 0.3s ease;
}
.switch {
position: relative;
display: inline-block;
width: 52px;
height: 32px;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #4A4458;
transition: .3s;
border-radius: 16px;
}
.slider:before {
position: absolute;
content: "";
height: 24px;
width: 24px;
left: 4px;
bottom: 4px;
background-color: #E6E1E5;
transition: .3s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #D0BCFF;
}
input:checked + .slider:before {
transform: translateX(20px);
background-color: #1C1B1F;
}
.config-file-container {
margin: 24px 0;
padding: 24px;
border: 2px solid #4A4458;
border-radius: 20px;
background-color: #2B2930;
transition: all 0.2s ease;
}
.config-file-container:hover {
border-color: #D0BCFF;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.config-file-container input[type="file"] {
max-width: 100%;
width: auto;
box-sizing: border-box;
padding: 12px;
border: 2px dashed #4A4458;
border-radius: 16px;
background-color: #332D41;
color: #E6E1E5;
cursor: pointer;
transition: all 0.2s ease;
}
.config-file-container input[type="file"]::-webkit-file-upload-button {
padding: 8px 16px;
margin-right: 12px;
background-color: #4A4458;
color: #E6E1E5;
border: none;
border-radius: 12px;
cursor: pointer;
transition: all 0.2s ease;
}
.config-file-container input[type="file"]::-webkit-file-upload-button:hover {
background-color: #635B70;
}
.file-hint {
margin-top: 12px;
font-size: 14px;
color: #CAC4D0;
line-height: 1.5;
}
.config-control-btn {
margin-top: 20px;
padding: 12px 28px;
background-color: #4A4458;
color: #E6E1E5;
border: none;
border-radius: 24px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
justify-content: center;
}
.config-control-btn:hover {
background-color: #635B70;
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0,0,0,0.4);
}
.theme-toggle-container {
margin: 24px 0;
display: flex;
flex-direction: column;
gap: 16px;
}
#theme-select {
width: 100%;
padding: 12px 16px;
font-size: 1.2rem;
background-color: #332D41;
color: #E6E1E5;
border: 2px solid #4A4458;
border-radius: 12px;
cursor: pointer;
appearance: none;
-webkit-appearance: none;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right 16px center;
background-size: 16px;
}
#theme-select:hover {
background-color: #4A4458;
border-color: #635B70;
}
#theme-select:focus {
outline: none;
border-color: #D0BCFF;
background-color: #4A4458;
}
#theme-select option {
background-color: #332D41;
color: #E6E1E5;
padding: 12px;
}
#theme-select option:hover,
#theme-select option:focus {
background-color: #4A4458;
}
.theme-toggle-container label {
font-size: 16px;
color: #E6E1E5;
margin-bottom: 8px;
}
.reminder-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.95);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all 0.5s ease;
backdrop-filter: blur(8px);
z-index: 9999;
}
.reminder-overlay.show {
opacity: 1;
visibility: visible;
}
.reminder-content {
text-align: center;
animation: fadeIn 0.5s ease;
}
.reminder-title {
font-size: 5rem;
color: #FF453A;
margin-bottom: 2rem;
}
.reminder-subtitle {
font-size: 3rem;
color: #FFD60A;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.info-toggle-btn {
position: absolute;
right: 20px;
top: 20px;
background-color: #4A4458;
color: #E6E1E5;
border: none;
border-radius: 50%;
width: 48px;
height: 48px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
z-index: 1;
}
.info-toggle-btn:hover {
background-color: #635B70;
transform: translateY(-1px);
}
.info-toggle-btn .material-icons {
font-size: 24px;
}
#paper-info {
font-size: 3rem;
margin: 16px 0;
text-align: left;
color: #E6E1E5;
}
#exam-papers, #answer-sheets {
margin: 10px 0;
}
.paper-count-container {
margin: 20px 0;
}
.paper-input-group {
display: flex;
align-items: center;
gap: 10px;
margin: 10px 0;
font-size: 2.5rem;
}
.count-btn-group {
display: flex;
flex-direction: column;
gap: 2px;
margin-right: 8px;
}
.count-control {
display: flex;
align-items: center;
gap: 5px;
}
.count-control input {
width: 60px;
padding: 5px;
font-size: 2rem;
text-align: center;
background-color: #332D41;
color: #E6E1E5;
border: 2px solid #4A4458;
border-radius: 8px;
}
.count-btn {
width: 24px;
height: 24px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
}
.count-btn .material-icons {
font-size: 16px;
}
.count-btn {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border: none;
border-radius: 50%;
background-color: #4A4458;
color: #E6E1E5;
cursor: pointer;
transition: all 0.2s ease;
}
.count-btn:hover {
background-color: #635B70;
transform: translateY(-1px);
}
.count-btn .material-icons {
font-size: 20px;
}
.info-section {
position: relative;
}
.info-toggle-btn {
position: absolute;
right: 0;
top: 0;
background-color: #4A4458;
color: #E6E1E5;
border: none;
border-radius: 50%;
width: 48px;
height: 48px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
z-index: 2;
}
.info-toggle-btn:hover {
background-color: #635B70;
transform: translateY(-1px);
}
.info-toggle-btn .material-icons {
font-size: 24px;
}

View File

@ -1,662 +0,0 @@
#return-btn {
position: absolute; /* 绝对定位 */
top: 20px; /* 距离顶部 20px */
left: 20px; /* 距离左侧 20px */
padding: 12px 24px; /* 内边距 */
font-size: 1rem; /* 字体大小 */
cursor: pointer; /* 鼠标悬停时显示为手型 */
background-color: #E8DEF8; /* 按钮背景颜色 */
color: #000000; /* 按钮文字颜色 */
border: none; /* 按钮边框样式 */
border-radius: 20px; /* 按钮圆角大小 */
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); /* 按钮阴影 */
transition: all 0.2s ease; /* 背景颜色和缩放的过渡效果 */
z-index: 1001; /* 按钮层级 */
}
#return-btn:hover {
background-color: #D0BCFF; /* 悬停时的背景颜色 */
transform: translateY(-1px); /* 悬停时向上移动 1px */
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); /* 悬停时的阴影效果 */
}
body {
font-family: 'Roboto', 'HarmonyOS Sans SC', sans-serif;
margin: 0;
padding: 0;
background: #FFFBFE;
color: #1C1B1F;
overflow: auto;
}
body::-webkit-scrollbar {
display: none;
}
#fullscreen-btn, #settings-btn {
position: absolute;
top: 20px;
padding: 12px 24px;
font-size: 1rem;
cursor: pointer;
background-color: #E8DEF8;
color: #1C1B1F;
border: none;
border-radius: 20px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
transition: all 0.2s ease;
z-index: 1001;
display: flex;
align-items: center;
}
#fullscreen-btn::before {
content: "fullscreen";
font-family: 'Material Icons';
font-size: 20px;
margin-right: 4px;
}
#settings-btn::before {
content: "settings";
font-family: 'Material Icons';
font-size: 20px;
margin-right: 4px;
}
#fullscreen-btn {
right: 20px;
}
#settings-btn {
right: 140px;
}
#settings-btn:hover, #fullscreen-btn:hover {
background-color: #D0BCFF;
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}
.container {
padding: 24px;
max-width: 1400px;
margin: auto;
background-color: #F7F2FA;
border-radius: 28px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
h1 {
font-size: 3.5rem;
font-weight: 400;
text-align: left;
margin-bottom: 16px;
color: #1C1B1F;
display: flex;
align-items: center;
justify-content: space-between;
}
#room {
font-size: 3.5rem;
font-weight: 400;
color: #1C1B1F;
margin-left: 20px;
}
#message {
font-size: 1.8rem;
color: #6750A4;
margin-bottom: 24px;
}
.content {
display: flex;
justify-content: space-between;
gap: 24px;
}
.left-column, .right-column {
display: flex;
flex-direction: column;
gap: 24px;
}
.left-column {
width: 45%;
}
.right-column {
width: 50%;
}
.clock-section, .info-section, .right-column {
background-color: #FFFFFF;
padding: 24px;
border-radius: 28px;
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
}
.info-section {
position: relative;
}
#current-time {
font-size: 8rem;
text-align: center;
color: #6750A4;
margin: 0;
font-weight: 400;
}
#current-subject, #exam-timing, #remaining-time, #status {
font-size: 3rem;
margin: 16px 0;
text-align: left;
color: #1C1B1F;
}
#paper-info {
font-size: 3rem;
margin: 16px 0;
text-align: left;
color: #1C1B1F;
}
#exam-papers, #answer-sheets {
margin: 10px 0;
}
table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
margin-top: 24px;
background-color: #FFFFFF;
border-radius: 16px;
overflow: hidden;
}
th, td {
padding: 1px;
font-size: 1.8rem;
text-align: center;
border-bottom: 1px solid #E8DEF8;
}
th {
background-color: #E8DEF8;
color: #1C1B1F;
font-weight: 500;
}
tr:hover {
background-color: #F7F2FA;
}
.exam-status-tag {
padding: 2px 4px;
border-radius: 3px;
font-size: 1.2rem;
font-weight: 500;
}
.exam-status-进行中 {
background-color: #DDF4D7;
color: #365534;
}
.exam-status-即将开始 {
background-color: #FFF2D6;
color: #594300;
}
.exam-status-已结束 {
background-color: #FFDAD6;
color: #5C1130;
}
.exam-status-未开始 {
background-color: #E8DEF8;
color: #1C1B1F;
}
#settings-modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.3);
backdrop-filter: blur(8px);
}
#settings-modal-content {
background: #FFFFFF;
padding: 32px 48px 32px 32px;
margin: 32px auto;
border-radius: 28px;
width: 600px;
max-height: 60vh;
overflow-y: auto;
box-shadow: 0 8px 24px rgba(0,0,0,0.2);
}
#settings-modal-content::-webkit-scrollbar {
width: 8px;
}
#settings-modal-content::-webkit-scrollbar-track {
background: transparent;
margin: 4px;
}
#settings-modal-content::-webkit-scrollbar-thumb {
background: #E8DEF8;
border-radius: 8px;
border: 2px solid #FFFFFF;
}
#settings-modal-content::-webkit-scrollbar-thumb:hover {
background: #D0BCFF;
}
#settings-modal-content h3 {
margin: 0 0 24px;
color: #1C1B1F;
font-size: 24px;
font-weight: 400;
}
#settings-modal-content label {
display: flex;
align-items: center;
gap: 16px;
margin: 16px 0;
font-size: 16px;
color: #1C1B1F;
}
#settings-modal-content input[type="number"],
#settings-modal-content input[type="text"] {
font-size: 1.8rem;
padding: 12px 16px;
margin: 8px 0 24px;
width: 100%;
box-sizing: border-box;
border: 2px solid #E8DEF8;
border-radius: 12px;
background-color: #FFFFFF;
color: #1C1B1F;
transition: all 0.2s ease;
}
#settings-modal-content input:focus {
outline: none;
border-color: #6750A4;
background-color: #F7F2FA;
}
.button-group {
display: flex;
justify-content: flex-end;
gap: 16px;
margin-top: 32px;
position: relative;
background-color: #FFFFFF;
padding: 16px 0;
border-top: 1px solid #E8DEF8;
}
#save-settings-btn, #close-settings-btn {
display: flex;
align-items: center;
gap: 12px;
}
#save-settings-btn::before {
content: "✓";
font-size: 18px;
}
#close-settings-btn::before {
content: "✕";
font-size: 18px;
}
#save-settings-btn, #close-settings-btn {
padding: 12px 24px;
border-radius: 20px;
font-size: 16px;
font-weight: 500;
border: none;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 8px;
}
#save-settings-btn {
background-color: #6750A4;
color: #FFFFFF;
}
#close-settings-btn {
background-color: #E8DEF8;
color: #1C1B1F;
}
#save-settings-btn:hover, #close-settings-btn:hover {
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}
.error-container {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%);
background: #FFDAD6;
color: #5C1130;
padding: 16px 24px;
border-radius: 16px;
display: none;
z-index: 10001;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
animation: slideUp 0.3s ease;
}
.switch {
position: relative;
display: inline-block;
width: 52px;
height: 32px;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #E8DEF8;
transition: .3s;
border-radius: 16px;
}
.slider:before {
position: absolute;
content: "";
height: 24px;
width: 24px;
left: 4px;
bottom: 4px;
background-color: #FFFFFF;
transition: .3s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #6750A4;
}
input:checked + .slider:before {
transform: translateX(20px);
background-color: #FFFFFF;
}
.config-file-container {
margin: 24px 0;
padding: 24px;
border: 2px solid #E8DEF8;
border-radius: 20px;
background-color: #F7F2FA;
transition: all 0.2s ease;
}
.config-file-container:hover {
border-color: #6750A4;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.config-file-container input[type="file"] {
max-width: 100%;
width: auto;
box-sizing: border-box;
padding: 12px;
border: 2px dashed #E8DEF8;
border-radius: 16px;
background-color: #FFFFFF;
color: #1C1B1F;
cursor: pointer;
transition: all 0.2s ease;
}
.config-file-container input[type="file"]::-webkit-file-upload-button {
padding: 8px 16px;
margin-right: 12px;
background-color: #E8DEF8;
color: #1C1B1F;
border: none;
border-radius: 12px;
cursor: pointer;
transition: all 0.2s ease;
}
.config-file-container input[type="file"]::-webkit-file-upload-button:hover {
background-color: #D0BCFF;
}
.file-hint {
margin-top: 12px;
font-size: 14px;
color: #49454F;
line-height: 1.5;
}
.config-control-btn {
margin-top: 20px;
padding: 12px 28px;
background-color: #E8DEF8;
color: #1C1B1F;
border: none;
border-radius: 24px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
justify-content: center;
}
.config-control-btn:hover {
background-color: #D0BCFF;
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
.theme-toggle-container {
margin: 24px 0;
display: flex;
flex-direction: column;
gap: 16px;
}
#theme-select {
width: 100%;
padding: 12px 16px;
font-size: 1.2rem;
background-color: #FFFFFF;
color: #1C1B1F;
border: 2px solid #E8DEF8;
border-radius: 12px;
cursor: pointer;
appearance: none;
-webkit-appearance: none;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right 16px center;
background-size: 16px;
}
#theme-select:hover {
background-color: #F7F2FA;
border-color: #D0BCFF;
}
#theme-select:focus {
outline: none;
border-color: #6750A4;
background-color: #F7F2FA;
}
#theme-select option {
background-color: #FFFFFF;
color: #1C1B1F;
padding: 12px;
}
#theme-select option:hover,
#theme-select option:focus {
background-color: #F7F2FA;
}
.theme-toggle-container label {
font-size: 16px;
color: #1C1B1F;
margin-bottom: 8px;
}
.reminder-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.95);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all 0.5s ease;
backdrop-filter: blur(8px);
z-index: 9999;
}
.reminder-overlay.show {
opacity: 1;
visibility: visible;
}
.reminder-content {
text-align: center;
animation: fadeIn 0.5s ease;
}
.reminder-title {
font-size: 5rem;
color: #FF3B30;
margin-bottom: 2rem;
}
.reminder-subtitle {
font-size: 3rem;
color: #FF9500;
}
.info-toggle-btn {
position: absolute;
right: 0;
top: 0;
background-color: #E8DEF8;
color: #1C1B1F;
border: none;
border-radius: 50%;
width: 48px;
height: 48px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
z-index: 2;
}
.info-toggle-btn:hover {
background-color: #D0BCFF;
transform: translateY(-1px);
}
.info-toggle-btn .material-icons {
font-size: 24px;
}
.paper-count-container {
margin: 20px 0;
}
.paper-input-group {
display: flex;
align-items: center;
gap: 10px;
margin: 10px 0;
font-size: 2.5rem;
}
.count-control {
display: flex;
align-items: center;
gap: 5px;
}
.count-control input {
width: 60px;
padding: 5px;
font-size: 2rem;
text-align: center;
background-color: #FFFFFF;
color: #1C1B1F;
border: 2px solid #E8DEF8;
border-radius: 8px;
}
.count-btn {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border: none;
border-radius: 50%;
background-color: #E8DEF8;
color: #1C1B1F;
cursor: pointer;
transition: all 0.2s ease;
}
.count-btn:hover {
background-color: #D0BCFF;
transform: translateY(-1px);
}
.count-btn .material-icons {
font-size: 20px;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

View File

@ -1,697 +0,0 @@
#return-btn {
position: absolute; /* 绝对定位 */
top: 20px; /* 距离顶部 20px */
left: 20px; /* 距离左侧 20px */
background-color: #1f1f1f; /* 按钮背景颜色 */
color: #e0e0e0; /* 按钮文字颜色 */
border: 1px solid #333333; /* 按钮边框样式 */
border-radius: 4px; /* 按钮圆角大小 */
padding: 8px 16px; /* 按钮内边距 */
font-size: 14px; /* 按钮字体大小 */
cursor: pointer; /* 鼠标悬停时显示为手型 */
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); /* 按钮阴影 */
transition: background-color 0.3s ease, transform 0.3s ease; /* 背景颜色和缩放的过渡效果 */
z-index: 1001; /* 按钮层级 */
}
#return-btn:hover {
background-color: #2a2a2a; /* 按钮悬停时的背景颜色 */
transform: scale(1.05); /* 悬停时放大 5% */
}
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.8rem;
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;
max-height: 60vh; /* 限制最大高度 */
overflow-y: auto; /* 允许垂直滚动 */
animation: fadeIn 0.5s ease;
}
/* 设置滚动条样式 */
#settings-modal-content::-webkit-scrollbar {
width: 8px;
}
#settings-modal-content::-webkit-scrollbar-track {
background: rgba(31, 31, 31, 0.5);
border-radius: 4px;
}
#settings-modal-content::-webkit-scrollbar-thumb {
background: #666;
border-radius: 4px;
}
#settings-modal-content::-webkit-scrollbar-thumb:hover {
background: #888;
}
@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.8rem;
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;
}
#theme-select {
padding: 8px 12px;
font-size: 14px;
border: 1px solid #555;
border-radius: 4px;
background-color: #222;
color: #e0e0e0;
cursor: pointer;
outline: none;
width: 120px;
}
#theme-select:hover {
border-color: #666;
}
#theme-select:focus {
border-color: #007acc;
box-shadow: 0 0 0 1px #007acc;
}
#theme-select option {
background-color: #222;
color: #e0e0e0;
padding: 8px;
}
.config-file-container {
margin: 12px 0;
padding: 10px;
border: 1px solid #555;
border-radius: 5px;
background-color: rgba(31, 31, 31, 0.5);
box-sizing: border-box;
max-width: 100%;
}
.config-file-container label {
display: block;
margin-bottom: 8px;
color: #e0e0e0;
}
.config-file-container input[type="file"] {
display: block;
width: calc(100% - 16px); /* 减去padding的宽度 */
padding: 8px;
border: 1px solid #555;
border-radius: 4px;
background-color: #222;
color: #e0e0e0;
cursor: pointer;
box-sizing: border-box;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.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;
}
.reminder-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.95);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all 0.5s ease;
backdrop-filter: blur(8px);
z-index: 9999;
}
.reminder-overlay.show {
opacity: 1;
visibility: visible;
}
.reminder-content {
text-align: center;
animation: fadeIn 0.5s ease;
}
.reminder-title {
font-size: 5rem;
color: #FF453A;
margin-bottom: 2rem;
}
.reminder-subtitle {
font-size: 3rem;
color: #FFD60A;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.info-section {
position: relative;
}
.info-toggle-btn {
position: absolute;
right: 0;
top: 0;
background-color: #1f1f1f;
color: #e0e0e0;
border: none;
border-radius: 50%;
width: 48px;
height: 48px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
z-index: 2;
}
.info-toggle-btn:hover {
background-color: #333;
transform: translateY(-1px);
}
.info-toggle-btn .material-icons {
font-size: 24px;
}
.paper-count-container {
margin: 20px 0;
}
.paper-input-group {
display: flex;
align-items: center;
gap: 10px;
margin: 10px 0;
font-size: 2.5rem;
}
.count-control {
display: flex;
align-items: center;
gap: 5px;
}
.count-control input {
width: 60px;
padding: 5px;
font-size: 2rem;
text-align: center;
background-color: #1f1f1f;
color: #e0e0e0;
border: 2px solid #333;
border-radius: 8px;
}
.count-btn {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border: none;
border-radius: 50%;
background-color: #1f1f1f;
color: #e0e0e0;
cursor: pointer;
transition: all 0.2s ease;
}
.count-btn:hover {
background-color: #333;
transform: translateY(-1px);
}
.count-btn .material-icons {
font-size: 20px;
}
.count-btn-group {
display: flex;
flex-direction: column;
gap: 2px;
margin-right: 8px;
}
.count-control {
display: flex;
align-items: center;
gap: 5px;
}
.count-btn {
width: 24px;
height: 24px;
padding: 0;
border: 1px solid #333;
display: flex;
align-items: center;
justify-content: center;
}
.count-btn .material-icons {
font-size: 16px;
}

View File

@ -1,694 +0,0 @@
#return-btn {
position: absolute; /* 绝对定位 */
top: 20px; /* 距离顶部 20px */
left: 20px; /* 距离左侧 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; /* 设置按钮的层级,确保在其他元素之上 */
}
#return-btn:hover {
background-color: #ccc; /* 悬停时的背景颜色 */
transform: scale(1.05); /* 悬停时放大 5% */
}
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; /* 距离顶部 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; /* 距离右侧 20px */
}
#settings-btn {
right: 120px; /* 距离右侧 120px */
}
#settings-btn:hover, #fullscreen-btn:hover {
background-color: #ccc; /* 悬停时的背景颜色 */
transform: scale(1.05); /* 悬停时放大 5% */
}
.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; /* 使用 flex 布局 */
align-items: center; /* 垂直居中 */
justify-content: space-between; /* 两端对齐 */
}
#room {
font-size: 3.5rem; /* 字体大小 */
font-weight: bold; /* 字体加粗 */
color: #333; /* 文字颜色 */
position: relative; /* 相对定位 */
right: 0; /* 向右移动 0 */
margin-left: 20px; /* 左边距 */
}
#message {
font-size: 1.8rem; /* 字体大小 */
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; /* 下边框 */
padding: 0px; /* 内边距 */
font-size: 1.8rem; /* 字体大小 */
text-align: center; /* 居中对齐 */
}
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;
max-height: 60vh; /* 限制最大高度 */
overflow-y: auto; /* 允许垂直滚动 */
animation: fadeIn 0.5s ease;
}
/* 设置滚动条样式 */
#settings-modal-content::-webkit-scrollbar {
width: 8px;
}
#settings-modal-content::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
border-radius: 4px;
}
#settings-modal-content::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 4px;
}
#settings-modal-content::-webkit-scrollbar-thumb:hover {
background: #999;
}
@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.8rem;
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;
}
#theme-select {
padding: 8px 12px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
background-color: #fff;
color: #333;
cursor: pointer;
outline: none;
width: 120px;
}
#theme-select:hover {
border-color: #999;
}
#theme-select:focus {
border-color: #007acc;
box-shadow: 0 0 0 1px #007acc;
}
#theme-select option {
background-color: #fff;
color: #333;
padding: 8px;
}
.config-file-container {
margin: 12px 0;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
background-color: rgba(255, 255, 255, 0.5);
box-sizing: border-box;
max-width: 100%;
}
.config-file-container label {
display: block;
margin-bottom: 8px;
color: #333;
}
.config-file-container input[type="file"] {
display: block;
width: calc(100% - 16px); /* 减去padding的宽度 */
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
background-color: #fff;
color: #333;
cursor: pointer;
box-sizing: border-box;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.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;
}
.reminder-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.95);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all 0.5s ease;
backdrop-filter: blur(8px);
z-index: 9999;
}
.reminder-overlay.show {
opacity: 1;
visibility: visible;
}
.reminder-content {
text-align: center;
animation: fadeIn 0.5s ease;
}
.reminder-title {
font-size: 5rem;
color: #FF3B30;
margin-bottom: 2rem;
}
.reminder-subtitle {
font-size: 3rem;
color: #FF9500;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.info-section {
position: relative;
}
.info-toggle-btn {
position: absolute;
right: 0;
top: 0;
background-color: #f0f0f0;
color: #333;
border: none;
border-radius: 50%;
width: 48px;
height: 48px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
z-index: 2;
}
.info-toggle-btn:hover {
background-color: #ccc;
transform: translateY(-1px);
}
.info-toggle-btn .material-icons {
font-size: 24px;
}
.paper-count-container {
margin: 20px 0;
}
.paper-input-group {
display: flex;
align-items: center;
gap: 10px;
margin: 10px 0;
font-size: 2.5rem;
}
.count-control {
display: flex;
align-items: center;
gap: 5px;
}
.count-btn {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border: none;
border-radius: 50%;
background-color: #f0f0f0;
color: #333;
cursor: pointer;
transition: all 0.2s ease;
}
.count-btn:hover {
background-color: #ccc;
transform: translateY(-1px);
}
.count-btn .material-icons {
font-size: 20px;
}
.count-btn-group {
display: flex;
flex-direction: column;
gap: 2px;
margin-right: 8px;
}
.count-control {
display: flex;
align-items: center;
gap: 5px;
}
.count-btn {
width: 24px;
height: 24px;
padding: 0;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
}
.count-btn .material-icons {
font-size: 16px;
}

View File

@ -1,16 +0,0 @@
{
"theme":[
{
"name": "ExamAware旧版",
"path": "ealg"
},
{
"name": "ExamSchedule旧版",
"path": "old"
},
{
"name": "Material Design 3",
"path": "md3"
}
]
}

View File

@ -1,47 +1,47 @@
{
"examName": "淄博齐盛高级中学第一次模块考试",
"message": "请保持安静,认真答题",
"room": "",
"examName": "开学检测",
"message": "沉着考试,冷静应对",
"room": " ",
"examInfos": [
{
"name": "语文",
"start": "2025-05-06T07:30:00",
"end": "2025-05-06T10:00:00"
},
{
"name": "物理",
"start": "2025-05-06T10:20:00",
"end": "2025-05-06T11:50:00"
},
{
"name": "数学",
"start": "2025-05-06T14:10:00",
"end": "2025-05-06T16:10:00"
},
{
"name": "政治",
"start": "2025-05-06T16:30:00",
"end": "2025-05-06T18:00:00"
},
{
"name": "生物/地理",
"start": "2025-05-07T08:00:00",
"end": "2025-05-07T09:30:00"
"start": "2025-02-14T07:20:00",
"end": "2025-02-14T09:50:00"
},
{
"name": "化学",
"start": "2025-05-07T10:00:00",
"end": "2025-05-07T11:30:00"
"start": "2025-02-14T10:20:00",
"end": "2025-02-14T11:50:00"
},
{
"name": "政治/生物",
"start": "2025-02-14T14:10:00",
"end": "2025-02-14T15:40:00"
},
{
"name": "地理",
"start": "2025-02-14T16:10:00",
"end": "2025-02-14T17:40:00"
},
{
"name": "英语",
"start": "2025-05-07T14:10:00",
"end": "2025-05-07T16:10:00"
"start": "2025-02-15T07:50:00",
"end": "2025-02-15T09:50:00"
},
{
"name": "物理",
"start": "2025-02-15T10:20:00",
"end": "2025-02-15T11:50:00"
},
{
"name": "数学",
"start": "2025-02-15T14:10:00",
"end": "2025-02-15T16:10:00"
},
{
"name": "历史",
"start": "2025-05-07T16:30:00",
"end": "2025-05-07T18:00:00"
"start": "2025-02-15T16:30:00",
"end": "2025-02-15T18:00:00"
}
]
}

View File

@ -4,15 +4,10 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exam Schedule</title>
<link id="theme-link" rel="stylesheet" href="Styles/md3/dark.css">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="styles.css">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
</head>
<body>
<div class="error-container">
<div class="error-content" id="errorMessage"></div>
</div>
<button id="return-btn" onclick="window.location.href = '../'">返回</button>
<button id="settings-btn">设置</button>
<button id="fullscreen-btn">全屏</button>
<div class="container">
@ -27,69 +22,8 @@
<div id="current-time"></div>
</div>
<div class="info-section">
<button id="info-toggle-btn" class="info-toggle-btn" title="切换显示模式">
<span class="material-icons">swap_horiz</span>
</button>
<div id="current-subject"></div>
<div id="exam-timing"></div>
<div id="paper-info" style="display: none;">
<div class="paper-count-container">
<div class="paper-input-group">
<label>试卷:</label>
<div class="count-control">
<div class="count-btn-group">
<button class="count-btn" data-target="paper-count" data-action="decrease">
<span class="material-icons">remove</span>
</button>
<button class="count-btn" data-target="paper-count" data-action="increase">
<span class="material-icons">add</span>
</button>
</div>
<input type="number" id="paper-count" min="0" value="0">
</div>
<span></span>
<div class="count-control">
<div class="count-btn-group">
<button class="count-btn" data-target="paper-pages" data-action="decrease">
<span class="material-icons">remove</span>
</button>
<button class="count-btn" data-target="paper-pages" data-action="increase">
<span class="material-icons">add</span>
</button>
</div>
<input type="number" id="paper-pages" min="0" value="0">
</div>
<span></span>
</div>
<div class="paper-input-group">
<label>答题卡:</label>
<div class="count-control">
<div class="count-btn-group">
<button class="count-btn" data-target="sheet-count" data-action="decrease">
<span class="material-icons">remove</span>
</button>
<button class="count-btn" data-target="sheet-count" data-action="increase">
<span class="material-icons">add</span>
</button>
</div>
<input type="number" id="sheet-count" min="0" value="0">
</div>
<span></span>
<div class="count-control">
<div class="count-btn-group">
<button class="count-btn" data-target="sheet-pages" data-action="decrease">
<span class="material-icons">remove</span>
</button>
<button class="count-btn" data-target="sheet-pages" data-action="increase">
<span class="material-icons">add</span>
</button>
</div>
<input type="number" id="sheet-pages" min="0" value="0">
</div>
<span></span>
</div>
</div>
</div>
<div id="remaining-time"></div>
<div id="status"></div>
</div>
@ -98,11 +32,9 @@
<table>
<thead>
<tr>
<th>时间</th>
<th>科目</th>
<th>开始</th>
<th>结束</th>
<th>状态</th>
<th>开始时间</th>
<th>结束时间</th>
</tr>
</thead>
<tbody id="exam-table-body">
@ -112,12 +44,6 @@
</div>
</div>
</div>
<div id="reminder-overlay" class="reminder-overlay">
<div class="reminder-content">
<h1 class="reminder-title">距离考试结束还有 15 分钟</h1>
<h2 class="reminder-subtitle">注意掌握时间</h2>
</div>
</div>
<!-- Settings Modal -->
<div id="settings-modal">
<div id="settings-modal-content" class="settings-panel dark-theme">
@ -128,37 +54,12 @@
<input type="text" id="room-input" name="room-input" value="">
<label for="zoom-input">页面缩放倍数:</label>
<input type="number" id="zoom-input" step="0.1" min="0.5" max="2">
<div class="config-file-container">
<label for="config-file">配置文件:</label>
<input type="file" id="config-file" accept=".json">
<div class="file-hint">支持.json格式文件</div>
<button id="clear-config-btn" class="config-control-btn">清除本地配置</button>
</div>
<div class="theme-toggle-container">
<label for="theme-select">主题:</label>
<select id="theme-select">
<!-- 动态填充主题选项 -->
</select>
<label for="theme-toggle">亮/暗色模式:</label>
<label class="switch">
<input type="checkbox" id="theme-toggle">
<span class="slider round"></span>
</label>
<label for="auto-toggle">自动切换显示:</label>
<label class="switch">
<input type="checkbox" id="auto-toggle">
<span class="slider round"></span>
</label>
</div>
<div class="button-group">
<button id="save-settings-btn" class="control-btn">确定</button>
<button id="close-settings-btn" class="control-btn">关闭</button>
</div>
</div>
</div>
<script src="Scripts/utils.js"></script>
<script src="Scripts/settings.js"></script>
<script src="Scripts/examInfo.js"></script>
<script src="Scripts/main.js"></script>
<script src="script.js"></script>
</body>
</html>

223
exam/script.js Normal file
View File

@ -0,0 +1,223 @@
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() {
return fetch('exam_config.json', { 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} <span id="room">${roomText}</span>`;
// 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 = `
<td>${exam.name}</td>
<td>${formatTimeWithoutSeconds(new Date(exam.start).toLocaleTimeString('zh-CN', { hour12: false }))}</td>
<td>${formatTimeWithoutSeconds(new Date(exam.end).toLocaleTimeString('zh-CN', { hour12: false }))}</td>
`;
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();
});

283
exam/styles.css Normal file
View File

@ -0,0 +1,283 @@
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(255, 255, 255, 0); /* 使用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 {
width: 48%;
display: flex;
flex-direction: column;
gap: 3px; /* 板块间隔3px */
}
.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;
}
#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 #333;
background-color: rgba(31, 31, 31, 0.5);
}
th, td {
border: 1px solid #333;
padding: 2px; /* 缩短行高 */
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: 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); }
}
#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 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 #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;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

View File

@ -1,68 +1,79 @@
<!--
_ooOoo_
o8888888o
88" . "88
(| -_- |)
O\ = /O
____/---\____
.' \\| |// '.
/ \\||| : |||// \
/ _||||| -:- |||||- \
| | \\\ - /// | |
| _| ''---/'' | |
\ .-\__ `-` ___/-. /
___`. .' /--.--\ `. . __
."" '< `.___\_<|>_/___.' >'"".
| | : `- \.;`\ _ /';.\ - ` : | |
\ \ `-. \_ __\ /__ _/ .-\ / /
======`-.____`-.___\_____/___.-`____.-'======
`=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
佛祖保佑 永无BUG
-->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<link rel="shortcut icon" href="./favicon.ico">
<link rel="shortcut icon" href="./favicon.ico">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>选择页面</title>
<link href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
body {
background: #2C2B30;
background-image: url('./background.jpg');
background-size: cover;
background-repeat: no-repeat;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
font-family: 'Google Sans', 'Roboto', sans-serif;
color: #E6E1E5;
backdrop-filter: blur(10px);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; /* 使用更现代的字体 */
color: #fff;
background-color: rgba(0, 0, 0, 0.5); /* 添加半透明背景 */
backdrop-filter: blur(5px); /* 添加背景模糊效果 */
}
h1 {
display: none; /* 隐藏选择版本标题 */
color: #fff;
font-size: 48px;
text-align: center;
margin-bottom: 30px;
animation: fadeInUp 1s ease-in-out;
}
/* 只针对主导航按钮的样式 */
ul {
list-style: none;
padding: 0;
margin: 0;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
animation: fadeInUp 1s ease-in-out;
}
/* 主导航按钮样式 */
ul a {
color: #E6E1E5;
li {
margin-bottom: 30px;
}
a {
color: #fff;
text-decoration: none;
font-size: 20px;
font-weight: 500;
padding: 32px;
border-radius: 24px;
background-color: #49454F;
font-size: 24px;
font-weight: bold;
padding: 15px 30px;
border-radius: 8px;
background-color: rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
min-width: 200px;
text-align: center;
display: inline-block;
}
ul a:hover {
background-color: #605D64;
transform: translateY(-4px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
a:hover {
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(-3px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
ul .material-icons {
font-size: 32px;
}
@keyframes fadeInUp {
0% {
opacity: 0;
@ -73,128 +84,18 @@
transform: translateY(0);
}
}
.copyright {
position: absolute;
bottom: 16px;
width: 100%;
text-align: center;
font-size: 14px;
color: #CAC4D0;
animation: fadeInUp 1s ease-in-out;
}
.github-link {
position: static;
}
.github-link:hover {
background-color: rgba(255, 255, 255, 0.1);
transform: none;
box-shadow: none;
}
.github-link img {
width: 24px;
height: 24px;
filter: invert(1);
}
.project-title {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
font-size: 24px;
font-weight: 500;
color: #E6E1E5;
animation: fadeInUp 1s ease-in-out;
display: flex;
align-items: center;
gap: 12px;
}
.project-logo {
width: 32px;
height: 32px;
object-fit: contain;
}
.material-icons {
font-size: 20px;
}
.top-right-links {
position: absolute;
top: 16px;
right: 16px;
display: flex;
gap: 16px;
align-items: center;
}
.about-link {
background-color: transparent;
padding: 8px 16px;
border-radius: 100px;
font-size: 14px;
text-decoration: none;
color: rgba(255, 255, 255, 1);
display: flex; /* 新增使用flex布局 */
align-items: center; /* 新增:垂直居中对齐 */
gap: 6px; /* 新增:图标与文字间距 */
}
.about-link:hover {
background-color: transparent;
transform: none;
box-shadow: none;
color: rgba(255, 255, 255, 0.7);
}
.about-link .material-icons {
font-size: 18px;
}
</style>
</head>
<body>
<div class="project-title">
<img src="./icon.png" alt="ExamSchedule Logo" class="project-logo">
ExamSchedule
</div>
<h1>选择版本:</h1>
<ul>
<li><a href="./time/"><span class="material-icons">schedule</span>电子钟表</a></li>
<li><a href="./exam/"><span class="material-icons">dashboard</span>考试看板</a></li>
<li><a href="./notification/"><span class="material-icons">campaign</span>考试广播</a></li>
<li><a href="./time/">电子钟表</a></li>
<li><a href="./exam/">考试看板</a></li>
</ul>
<!-- 添加关于链接和GitHub图标 -->
<div class="top-right-links">
<a href="./about/" class="about-link">
<span class="material-icons">info</span>
关于
</a>
<a href="https://github.com/ExamAware/ExamSchedule" target="_blank" class="github-link">
<img src="./github-icon.png" alt="GitHub" title="在GitHub上查看源代码">
</a>
</div>
<!-- 新增版权信息 -->
<div class="copyright">&copy; 2024-2025 ExamAware开发团队 版权所有</div>
<script>
// 愚人节彩蛋
function checkAprilFools() {
const today = new Date();
if(today.getMonth() === 3 && today.getDate() === 1) { // 4月1日
if(Math.random() <= 0.75) { // 75%的概率
window.location.href = 'https://www.bilibili.com/video/BV1GJ411x7h7/';
}
}
}
// 页面加载时执行检查
window.onload = checkAprilFools;
</script>
<!-- 添加GitHub图标跳转项目地址 -->
<a href="https://github.com/ExamAware/ExamSchedule" target="_blank" style="position: absolute; top: 10px; right: 10px; z-index: 1000;">
<img src="./github-icon.png" alt="GitHub" style="width: 30px; height: 30px;" title="在GitHub上查看源代码">
</a>
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,10 +0,0 @@
{
"上课铃": "audio/classstart.mp3",
"距离结束还有15分钟": "audio/15min_left.mp3",
"距离结束还有30分钟": "audio/30min_left.mp3",
"考试开始": "audio/start.mp3",
"考试结束": "audio/end.mp3",
"核对信息": "audio/hedui_noeng.mp3",
"检场": "audio/jinchang.mp3",
"展示科目袋": "audio/zhanshikemudai.mp3"
}

View File

@ -1,47 +0,0 @@
{
"examName": "限时训练",
"message": "请保持安静,认真答题",
"room": "",
"examInfos": [
{
"name": "语文",
"start": "2025-03-27T07:20:00",
"end": "2025-03-27T09:50:00"
},
{
"name": "物理",
"start": "2025-03-27T10:20:00",
"end": "2025-03-27T11:50:00"
},
{
"name": "英语",
"start": "2025-03-27T14:10:00",
"end": "2025-03-27T16:10:00"
},
{
"name": "历史",
"start": "2025-03-27T16:30:00",
"end": "2025-03-27T18:00:00"
},
{
"name": "数学",
"start": "2025-03-28T07:50:00",
"end": "2025-03-28T09:50:00"
},
{
"name": "化学",
"start": "2025-03-28T10:20:00",
"end": "2025-03-28T11:50:00"
},
{
"name": "生物、政治",
"start": "2025-03-28T14:10:00",
"end": "2025-03-28T15:40:00"
},
{
"name": "地理",
"start": "2025-03-28T16:10:00",
"end": "2025-03-28T17:40:00"
}
]
}

View File

@ -1,90 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>考试看板—广播适配</title>
<link rel="stylesheet" href="styles/base.css">
<link rel="stylesheet" href="styles/status-box.css">
<link rel="stylesheet" href="styles/schedule-table.css">
<link rel="stylesheet" href="styles/fullscreen-mode.css">
<link rel="stylesheet" href="styles/control-btn.css">
<link rel="stylesheet" href="styles/settings-panel.css">
<link rel="stylesheet" href="styles/info-error.css">
<link rel="stylesheet" href="styles/reminder-table.css">
<link rel="stylesheet" href="styles/file-input-label.css">
<link rel="stylesheet" href="styles/action-btn.css">
<link rel="stylesheet" href="styles/dark-mode.css">
<link rel="stylesheet" href="styles/switch.css">
</head>
<body class="light-mode">
<button id="return-btn" onclick="goBack()">返回</button>
<div class="info-container">
<div class="info-content" id="infoMessage"></div>
</div>
<div class="error-container">
<div class="error-content" id="errorMessage"></div>
</div>
<div class="container">
<div class="exam-info">
<h1 id="examTitle">考试看板</h1>
<div id="examMessage" class="exam-message"></div>
<div id="examRoom" class="exam-room"></div>
</div>
<div class="control-bar">
<label class="switch">
<input type="checkbox" id="theme-toggle">
<span class="slider round"></span>
</label>
</div>
<div class="status-box">
<div class="status-label" id="statusLabel">正在初始化...</div>
<div class="time-display" id="timeDisplay" onclick="adjustCountdownFontSize()">--:--</div>
<div id="timeDescription" style="text-align:center;color:#a4b0be;"></div>
</div>
<div class="settings-panel">
<h3>系统设置</h3>
<div class="button-group">
<label class="file-input-label">
<input type="file" id="importJson" accept=".json" multiple> 导入考试配置
</label>
<button class="action-btn" onclick="exportConfig()">导出配置</button>
</div>
<h3>提醒设置</h3>
<table class="reminder-table" id="reminderTable">
<tr>
<th>提醒条件</th>
<th>时间(分钟)</th>
<th>音频选择</th>
<th>操作</th>
</tr>
<tr>
<td colspan="4"><button class="action-btn" onclick="addReminder()">添加提醒</button></td>
</tr>
</table>
<button class="action-btn" onclick="saveConfig()">保存提醒设置</button>
</div>
<table class="schedule-table" id="scheduleTable">
<tr>
<th>科目</th>
<th>时间段</th>
<th>状态</th>
</tr>
</table>
</div>
<script src="scripts/errorSystem.js"></script>
<script src="scripts/audioController.js"></script>
<script src="scripts/courseSchedule.js"></script>
<script src="scripts/display.js"></script>
<script src="scripts/config.js"></script>
<script src="scripts/settings.js"></script>
<script src="scripts/reminderQueue.js"></script>
<script src="scripts/script.js"></script>
<script src="scripts/utils.js"></script>
</body>
</html>

View File

@ -1,134 +0,0 @@
var audioController = (function() {
var audioPool = [];
var maxPoolSize = 3;
var soundFiles = {};
var audioSelectPopulated = false;
function init() {
fetch('audio_files.json')
.then(response => response.json())
.then(data => {
soundFiles = data;
Object.keys(soundFiles).forEach(function(type) {
for (var i = 0; i < 2; i++) {
createAudio(type);
}
});
if (!audioSelectPopulated) {
populateAudioSelect();
audioSelectPopulated = true;
}
removeInvalidAudioOptions();
})
.catch(e => errorSystem.show('音频文件加载失败: ' + e.message, 'error'));
}
function createAudio(type) {
var audio = document.createElement('audio');
audio.style.display = 'none';
audio.preload = 'auto';
audio.src = soundFiles[type];
var retryCount = 0;
function loadAudio() {
try {
audio.load();
} catch(e) {
if (retryCount++ < 3) {
setTimeout(loadAudio, 1000);
}
}
}
audio.addEventListener('error', function() {
if (retryCount++ < 3) {
setTimeout(loadAudio, 1000);
}
});
document.body.appendChild(audio);
loadAudio();
audioPool.push(audio);
return audio;
}
function play(type) {
try {
var audio = audioPool.find(function(a) { return a.paused; });
if (!audio) {
if (audioPool.length < maxPoolSize) {
audio = createAudio(type);
} else {
return errorSystem.show('系统繁忙,请稍后再试', 'error');
}
}
audio.src = soundFiles[type];
try {
audio.play();
} catch(e) {
errorSystem.show('播放失败: ' + e.message, 'error');
}
} catch(e) {
errorSystem.show('音频系统错误: ' + e.message, 'error');
}
}
function getAudioSrc(type) {
return soundFiles[type];
}
function populateAudioSelect() {
if (!Object.keys(soundFiles).length) {
// 如果音频文件还没加载完成,等待加载
fetch('audio_files.json')
.then(response => response.json())
.then(data => {
soundFiles = data;
_populateSelectOptions();
})
.catch(e => errorSystem.show('音频选项加载失败: ' + e.message, 'error'));
} else {
_populateSelectOptions();
}
}
function _populateSelectOptions() {
var selects = document.querySelectorAll('select[name="audioSelect"]');
selects.forEach(select => {
// 保存当前选中的值
var currentValue = select.value;
// 清空现有选项
select.innerHTML = '';
// 添加新选项
Object.keys(soundFiles).forEach(function(type) {
var option = document.createElement('option');
option.value = type;
option.textContent = type;
select.appendChild(option);
});
// 恢复之前选中的值(如果该值仍然有效)
if (currentValue && soundFiles[currentValue]) {
select.value = currentValue;
}
});
}
function removeInvalidAudioOptions() {
var selects = document.querySelectorAll('select[name="audioSelect"]');
selects.forEach(select => {
Array.from(select.options).forEach(option => {
if (!soundFiles[option.value]) {
option.remove();
}
});
});
}
return {
init: init,
play: play,
getAudioSrc: getAudioSrc,
populateAudioSelect: populateAudioSelect,
removeInvalidAudioOptions: removeInvalidAudioOptions,
_populateSelectOptions: _populateSelectOptions
};
})();
audioController.init();

View File

@ -1,138 +0,0 @@
document.getElementById('importJson').addEventListener('change', function(event) {
var files = event.target.files;
if (files.length > 0) {
Array.from(files).forEach(file => {
var reader = new FileReader();
reader.onload = function(e) {
try {
var config = JSON.parse(e.target.result);
applyConfig(config);
} catch (err) {
errorSystem.show('导入配置失败: ' + err.message, 'error');
}
};
reader.readAsText(file);
});
}
});
function applyConfig(config) {
try {
fetch('audio_files.json')
.then(response => response.json())
.then(audioFiles => {
const reminderCookie = getCookie("reminders");
// 获取有效的音频列表和默认音频
let validAudioTypes = Object.keys(audioFiles);
let defaultAudio = validAudioTypes[0];
if (config.examInfos) {
courseSchedule = config.examInfos;
updateScheduleTable();
}
if (config.examName) {
document.title = config.examName;
document.getElementById('examTitle').textContent = config.examName;
}
if (config.message) {
document.getElementById('examMessage').textContent = config.message;
}
if (config.room) {
document.getElementById('timeDescription').textContent = '考场: ' + config.room;
}
// 验证并修复提醒中的音频设置
if (config.reminders) {
config.reminders = config.reminders.map(reminder => {
if (!validAudioTypes.includes(reminder.audio)) {
errorSystem.show(`音频"${reminder.audio}"不存在,已替换为"${defaultAudio}"`, 'info');
reminder.audio = defaultAudio;
}
return reminder;
});
// 清空现有提醒表
var table = document.getElementById('reminderTable');
while (table.rows.length > 2) {
table.deleteRow(1);
}
// 添加新的提醒设置
config.reminders.forEach(function(reminder) {
var row = table.insertRow(table.rows.length - 1);
let audioOptions = validAudioTypes
.map(audio => `<option value="${audio}" ${reminder.audio === audio ? 'selected' : ''}>${audio}</option>`)
.join('');
row.innerHTML = `
<td>
<select>
<option value="beforeStart" ${reminder.condition === 'beforeStart' ? 'selected' : ''}>当距离考试开始时间还有</option>
<option value="beforeEnd" ${reminder.condition === 'beforeEnd' ? 'selected' : ''}>当距离考试结束时间还有</option>
<option value="afterEnd" ${reminder.condition === 'afterEnd' ? 'selected' : ''}>当考试结束后</option>
<option value="start" ${reminder.condition === 'start' ? 'selected' : ''}>当考试开始时</option>
<option value="end" ${reminder.condition === 'end' ? 'selected' : ''}>当考试结束时</option>
</select>
</td>
<td><input type="number" value="${reminder.time}" placeholder="${reminder.condition === 'start' || reminder.condition === 'end' ? '-' : '分钟'}" ${reminder.condition === 'start' || reminder.condition === 'end' ? 'disabled' : ''}></td>
<td>
<select name="audioSelect">
${audioOptions}
</select>
</td>
<td><button onclick="removeReminder(this)">删除</button></td>
`;
row.cells[0].querySelector('select').addEventListener('change', function() {
row.cells[1].querySelector('input').disabled = this.value === 'start' || this.value === 'end';
row.cells[1].querySelector('input').placeholder = this.value === 'start' || this.value === 'end' ? '-' : '分钟';
});
});
// 只更新提醒队列,不保存到 Cookie
loadRemindersToQueue(config.reminders);
}
errorSystem.show('配置导入成功(临时生效)', 'info');
})
.catch(err => {
errorSystem.show('获取音频列表失败: ' + err.message, 'error');
});
} catch (err) {
errorSystem.show('应用配置失败: ' + err.message, 'error');
}
}
function exportConfig() {
var table = document.getElementById('reminderTable');
var reminders = [];
for (var i = 1; i < table.rows.length - 1; i++) {
var row = table.rows[i];
var condition = row.cells[0].querySelector('select').value;
var timeInput = row.cells[1].querySelector('input');
var audioSelect = row.cells[2].querySelector('select');
if (timeInput && audioSelect) {
reminders.push({
condition: condition,
time: timeInput.value || 0,
audio: audioSelect.value || 'classStart'
});
}
}
var config = {
examInfos: courseSchedule,
examName: document.title,
message: document.getElementById('examMessage').textContent || "诚信考试,禁止作弊",
room: document.getElementById('timeDescription').textContent.replace('考场: ', ''),
reminders: reminders
};
var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(config));
var downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute("href", dataStr);
downloadAnchorNode.setAttribute("download", "exam_config.json");
document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click();
downloadAnchorNode.remove();
}

View File

@ -1,172 +0,0 @@
var courseSchedule = [];
// 将fetch移动到函数中以便控制初始化顺序
function loadCourseSchedule() {
return fetch('course_schedule.json')
.then(response => response.json())
.then(data => {
courseSchedule = data.examInfos || [];
document.title = data.examName || '考试看板';
document.getElementById('examTitle').textContent = data.examName || '考试看板';
document.getElementById('examMessage').textContent = data.message || '';
document.getElementById('timeDescription').textContent = data.room ? '考场: ' + data.room : '';
updateScheduleTable();
// 检查Cookie是否存在
const reminderCookie = getCookie("reminders");
if (!reminderCookie && data.reminders && Array.isArray(data.reminders)) {
// 如果Cookie不存在加载配置文件中的提醒设置
fetch('audio_files.json')
.then(response => response.json())
.then(audioFiles => {
const validAudioTypes = Object.keys(audioFiles);
const defaultAudio = validAudioTypes[0];
// 验证并修复音频设置
const reminders = data.reminders.map(reminder => {
if (!validAudioTypes.includes(reminder.audio)) {
reminder.audio = defaultAudio;
}
return reminder;
});
// 填充提醒表格
var table = document.getElementById('reminderTable');
while (table.rows.length > 2) {
table.deleteRow(1);
}
reminders.forEach(reminder => {
var row = table.insertRow(table.rows.length - 1);
let audioOptions = validAudioTypes
.map(audio => `<option value="${audio}" ${reminder.audio === audio ? 'selected' : ''}>${audio}</option>`)
.join('');
row.innerHTML = `
<td>
<select>
<option value="beforeStart" ${reminder.condition === 'beforeStart' ? 'selected' : ''}>当距离考试开始时间还有</option>
<option value="beforeEnd" ${reminder.condition === 'beforeEnd' ? 'selected' : ''}>当距离考试结束时间还有</option>
<option value="afterEnd" ${reminder.condition === 'afterEnd' ? 'selected' : ''}>当考试结束后</option>
<option value="start" ${reminder.condition === 'start' ? 'selected' : ''}>当考试开始时</option>
<option value="end" ${reminder.condition === 'end' ? 'selected' : ''}>当考试结束时</option>
</select>
</td>
<td><input type="number" value="${reminder.time}" placeholder="${reminder.condition === 'start' || reminder.condition === 'end' ? '-' : '分钟'}" ${reminder.condition === 'start' || reminder.condition === 'end' ? 'disabled' : ''}></td>
<td>
<select name="audioSelect">
${audioOptions}
</select>
</td>
<td><button onclick="removeReminder(this)">删除</button></td>
`;
row.cells[0].querySelector('select').addEventListener('change', function() {
row.cells[1].querySelector('input').disabled = this.value === 'start' || this.value === 'end';
row.cells[1].querySelector('input').placeholder = this.value === 'start' || this.value === 'end' ? '-' : '分钟';
});
});
// 更新提醒队列并保存到Cookie
loadRemindersToQueue(reminders);
saveSettingsToCookies();
});
}
return courseSchedule;
})
.catch(error => {
errorSystem.show('加载课程表失败: ' + error.message, 'error');
return [];
});
}
function parseTime(timeStr) {
try {
return new Date(timeStr);
} catch (e) {
errorSystem.show('时间解析错误: ' + e.message, 'info', 'error');
return new Date();
}
}
function updateCourseStatus() {
try {
var now = new Date();
currentCourse = null;
for (var i = 0; i < courseSchedule.length; i++) {
var course = courseSchedule[i],
start = parseTime(course.start),
end = parseTime(course.end);
if (end < start) end.setDate(end.getDate() + 1);
if (now >= start && now <= end) {
currentCourse = course;
break;
}
}
if (currentCourse !== lastCourse) {
handleStatusChange();
lastCourse = currentCourse;
}
} catch (e) {
errorSystem.show('课程状态更新失败: ' + e.message, 'error');
}
}
function handleStatusChange() {
// 处理状态变化的逻辑
console.log('课程状态已更改:', currentCourse);
}
function getNextCourse() {
try {
var now = new Date();
for (var i = 0; i < courseSchedule.length; i++) {
var start = parseTime(courseSchedule[i].start);
if (start > now) return courseSchedule[i];
}
return null;
} catch (e) {
errorSystem.show('获取下一节课失败: ' + e.message, 'error');
return null;
}
}
// 修改更新表格函数,增加数据检查
function updateScheduleTable() {
try {
if (!Array.isArray(courseSchedule)) {
errorSystem.show('课程表数据格式错误', 'error');
return;
}
var now = new Date();
var table = document.getElementById('scheduleTable');
// 清空现有行,保留表头
while (table.rows.length > 1) {
table.deleteRow(1);
}
courseSchedule.forEach(function(course) {
var row = table.insertRow(-1);
row.innerHTML = '<td>' + course.name + '</td>' +
'<td>' + formatDateTime(course.start) + ' - ' + formatDateTime(course.end) + '</td>' +
'<td></td>';
var start = parseTime(course.start);
var end = parseTime(course.end);
if (now >= start && now <= end) {
row.className = 'current-class';
row.cells[2].textContent = '进行中';
} else if (now < start) {
row.className = 'future-class';
row.cells[2].textContent = '即将开始';
} else {
row.className = 'past-class';
row.cells[2].textContent = '已结束';
}
});
} catch (e) {
errorSystem.show('课程表更新失败: ' + e.message, 'error');
}
}

View File

@ -1,56 +0,0 @@
function updateDisplay() {
try {
var now = new Date(),
timeDisplay = document.getElementById('timeDisplay'),
statusLabel = document.getElementById('statusLabel'),
timeDesc = document.getElementById('timeDescription');
if (currentCourse) {
var endTime = parseTime(currentCourse.end),
remain = endTime - now;
statusLabel.textContent = currentCourse.name + ' 进行中';
timeDisplay.textContent = formatTime(remain);
timeDesc.textContent = '剩余时间';
} else {
statusLabel.textContent = '休息中';
var nextCourse = getNextCourse();
if (nextCourse) {
var startTime = parseTime(nextCourse.start),
remain = startTime - now;
timeDisplay.textContent = formatTime(remain);
timeDesc.textContent = '距离 ' + nextCourse.name;
} else {
timeDisplay.textContent = '00:00';
timeDesc.textContent = '今日课程已结束';
}
}
updateScheduleTable();
} catch (e) {
errorSystem.show('界面更新失败: ' + e.message, 'error');
}
}
function formatTime(ms) {
try {
if (ms < 0) return '00:00:00';
var totalSeconds = Math.floor(ms / 1000),
hours = Math.floor(totalSeconds / 3600),
minutes = Math.floor((totalSeconds % 3600) / 60),
seconds = totalSeconds % 60;
return (hours < 10 ? '0' : '') + hours + ':' +
(minutes < 10 ? '0' : '') + minutes + ':' +
(seconds < 10 ? '0' : '') + seconds;
} catch (e) {
return '--:--:--';
}
}
function formatDateTime(dateTimeStr) {
var date = new Date(dateTimeStr);
return date.toLocaleString('zh-CN', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}

View File

@ -1,17 +0,0 @@
var errorSystem = {
show: function(message, type = 'error') {
try {
var container = document.querySelector(type === 'info' ? '.info-container' : '.error-container');
var content = document.getElementById(type === 'info' ? 'infoMessage' : 'errorMessage');
content.textContent = message;
container.style.display = 'flex';
setTimeout(() => this.hide(type), 5000);
} catch(e) {
console.error('错误提示系统异常:', e);
}
},
hide: function(type = 'error') {
var container = document.querySelector(type === 'info' ? '.info-container' : '.error-container');
if (container) container.style.display = 'none';
}
};

View File

@ -1,45 +0,0 @@
var reminderQueue = (function() {
var queue = [];
var audioCache = {};
function addReminder(reminder) {
queue.push(reminder);
queue.sort(function(a, b) {
return a.time - b.time;
});
preloadAudio(reminder.audio);
}
function processQueue() {
var now = Date.now();
while (queue.length > 0 && queue[0].time <= now) {
var reminder = queue.shift();
executeReminder(reminder);
}
setTimeout(processQueue, 1000);
}
function executeReminder(reminder) {
if (audioCache[reminder.audio]) {
audioCache[reminder.audio].play();
} else if (audioController.getAudioSrc(reminder.audio)) {
audioController.play(reminder.audio);
} else {
errorSystem.show('音频文件不存在: ' + reminder.audio, 'error');
}
}
function preloadAudio(audioType) {
if (!audioCache[audioType] && audioController.getAudioSrc(audioType)) {
var audio = new Audio(audioController.getAudioSrc(audioType));
audioCache[audioType] = audio;
}
}
return {
addReminder: addReminder,
processQueue: processQueue
};
})();
reminderQueue.processQueue();

View File

@ -1,210 +0,0 @@
// 全局状态变量
var lastCourse = null, timer = null, lastUpdate = Date.now();
// 新增:安全更新循环函数
function safeUpdate() {
try {
var now = Date.now();
updateCourseStatus();
updateDisplay();
var nextTick = Math.max(1000 - (Date.now() - now), 50);
timer = setTimeout(safeUpdate, nextTick);
lastUpdate = now;
} catch (e) {
errorSystem.show('更新循环错误: ' + e.message, 'error');
}
}
function adjustFontSize() {
var elements = document.querySelectorAll('.time-display, .status-label');
elements.forEach(element => {
if (isFullscreen) {
element.style.fontSize = '10vw';
} else {
element.style.fontSize = '';
}
});
var countdownElement = document.getElementById('timeDisplay');
if (isFullscreen) {
countdownElement.style.fontSize = '20vw';
} else {
countdownElement.style.fontSize = '';
}
}
function adjustCountdownFontSize() {
var countdownElement = document.getElementById('timeDisplay');
var currentSize = parseFloat(window.getComputedStyle(countdownElement).fontSize);
countdownElement.style.fontSize = (currentSize + 5) + 'px';
}
function addReminder() {
var table = document.getElementById('reminderTable');
var row = table.insertRow(table.rows.length - 1);
row.innerHTML = `
<td>
<select>
<option value="beforeStart">当距离考试开始时间还有</option>
<option value="beforeEnd">当距离考试结束时间还有</option>
<option value="afterEnd">当考试结束后</option>
<option value="start">当考试开始时</option>
<option value="end">当考试结束时</option>
</select>
</td>
<td><input type="number" placeholder="分钟" disabled></td>
<td>
<select name="audioSelect"></select>
</td>
<td><button onclick="removeReminder(this)">删除</button></td>
`;
row.cells[0].querySelector('select').addEventListener('change', function() {
row.cells[1].querySelector('input').disabled = this.value === 'start' || this.value === 'end';
row.cells[1].querySelector('input').placeholder = this.value === 'start' || this.value === 'end' ? '-' : '分钟';
});
audioController.populateAudioSelect();
}
function removeReminder(button) {
var row = button.parentNode.parentNode;
row.parentNode.removeChild(row);
}
function saveConfig() {
try {
var table = document.getElementById('reminderTable');
var reminders = [];
for (var i = 1; i < table.rows.length - 1; i++) {
var row = table.rows[i];
var condition = row.cells[0].querySelector('select').value;
var timeInput = row.cells[1].querySelector('input');
var audioSelect = row.cells[2].querySelector('select');
if (timeInput && audioSelect) {
reminders.push({
condition: condition,
time: timeInput.value || 0,
audio: audioSelect.value
});
}
}
if (reminders.length === 0) {
errorSystem.show('请添加至少一个提醒策略', 'error');
return;
}
// 保存到 Cookie 并更新提醒队列
saveSettingsToCookies();
loadRemindersToQueue(reminders);
} catch (e) {
errorSystem.show('保存设置失败: ' + e.message, 'error');
}
}
function loadRemindersToQueue(reminders) {
var now = Date.now();
reminders.forEach(function(reminder) {
var reminderTime;
var targetCourse;
if (currentCourse) {
targetCourse = currentCourse;
}
else if (getNextCourse()) {
targetCourse = getNextCourse();
}
else {
errorSystem.show('当前没有课程信息', 'info');
return;
}
switch (reminder.condition) {
case 'beforeStart':
reminderTime = new Date(targetCourse .start).getTime() - reminder.time * 60000;
break;
case 'beforeEnd':
reminderTime = new Date(targetCourse .end).getTime() - reminder.time * 60000;
break;
case 'afterEnd':
reminderTime = new Date(targetCourse .end).getTime() + reminder.time * 60000;
break;
case 'start':
reminderTime = new Date(targetCourse .start).getTime();
break;
case 'end':
reminderTime = new Date(targetCourse .end).getTime();
break;
default:
//console.error('未知的提醒条件:', reminder.condition);
//return;
}
if (reminderTime > now) {
reminderQueue.addReminder({ time: reminderTime, condition: reminder.condition, audio: reminder.audio });
}
});
}
// 修改:系统初始化函数
function init() {
try {
// 先加载课程表,然后再初始化其他内容
loadCourseSchedule().then(() => {
// 加载配置
var config = JSON.parse(localStorage.getItem('config') || '{}');
// 加载提醒设置
var reminders = config.reminders || [];
var table = document.getElementById('reminderTable');
reminders.forEach(function(reminder) {
var row = table.insertRow(table.rows.length - 1);
row.innerHTML = `
<td>
<select>
<option value="beforeStart" ${reminder.condition === 'beforeStart' ? 'selected' : ''}>当距离考试开始时间还有</option>
<option value="beforeEnd" ${reminder.condition === 'beforeEnd' ? 'selected' : ''}>当距离考试结束时间还有</option>
<option value="afterEnd" ${reminder.condition === 'afterEnd' ? 'selected' : ''}>当考试结束后</option>
<option value="start" ${reminder.condition === 'start' ? 'selected' : ''}>当考试开始时</option>
<option value="end" ${reminder.condition === 'end' ? 'selected' : ''}>当考试结束时</option>
</select>
</td>
<td><input type="number" value="${reminder.time}" placeholder="${reminder.condition === 'start' || reminder.condition === 'end' ? '-' : '分钟'}" ${reminder.condition === 'start' || reminder.condition === 'end' ? 'disabled' : ''}></td>
<td>
<select name="audioSelect">
<option value="classStart" ${reminder.audio === 'classStart' ? 'selected' : ''}>考试开始铃声</option>
<option value="classEnd" ${reminder.audio === 'classEnd' ? 'selected' : ''}>考试结束铃声</option>
</select>
</td>
<td><button onclick="removeReminder(this)">删除</button></td>
`;
row.cells[0].querySelector('select').addEventListener('change', function() {
row.cells[1].querySelector('input').disabled = this.value === 'start' || this.value === 'end';
row.cells[1].querySelector('input').placeholder = this.value === 'start' || this.value === 'end' ? '-' : '分钟';
});
});
// 启动安全更新循环
safeUpdate();
// 加载设置从Cookies
loadSettingsFromCookies();
// 加载提醒到队列
loadRemindersToQueue(reminders);
});
} catch (e) {
errorSystem.show('系统初始化失败: ' + e.message);
}
}
window.onbeforeunload = function () {
if (timer) clearTimeout(timer);
};
function goBack() {
window.history.back(); // 返回上一页
}
// 监听主题切换
document.getElementById('theme-toggle').addEventListener('change', function () {
const body = document.body;
if (this.checked) {
body.classList.remove('light-mode');
body.classList.add('dark-mode');
} else {
body.classList.remove('dark-mode');
body.classList.add('light-mode');
}
});
init();

View File

@ -1,149 +0,0 @@
function saveSettingsToCookies() {
try {
var table = document.getElementById('reminderTable');
var reminders = [];
for (var i = 1; i < table.rows.length - 1; i++) {
var row = table.rows[i];
var condition = row.cells[0].querySelector('select').value;
var timeInput = row.cells[1].querySelector('input');
var audioSelect = row.cells[2].querySelector('select');
if (timeInput && audioSelect) {
var time = timeInput.value || 0;
var audio = audioSelect.value;
reminders.push({ condition: condition, time: time, audio: audio });
}
}
if (reminders.length === 0) {
errorSystem.show('请添加至少一个提醒策略', 'error');
return false;
}
// 编码并保存到 Cookie
const remindersStr = encodeURIComponent(JSON.stringify(reminders));
setCookie("reminders", remindersStr, 365);
// 更新提醒队列
loadRemindersToQueue(reminders);
errorSystem.show('提醒设置已保存', 'info');
return true;
} catch (e) {
errorSystem.show('保存设置失败: ' + e.message, 'error');
return false;
}
}
function loadSettingsFromCookies() {
try {
const reminderCookie = getCookie("reminders");
if (reminderCookie) {
// 解码并解析 Cookie 值
const reminders = JSON.parse(decodeURIComponent(reminderCookie));
if (Array.isArray(reminders)) {
// 清空现有提醒
var table = document.getElementById('reminderTable');
while (table.rows.length > 2) {
table.deleteRow(1);
}
// 使用 audio_files.json 的数据填充提醒表
fetch('audio_files.json')
.then(response => response.json())
.then(audioFiles => {
const validAudioTypes = Object.keys(audioFiles);
const defaultAudio = validAudioTypes[0];
reminders.forEach(function(reminder) {
// 检查音频是否有效
if (!validAudioTypes.includes(reminder.audio)) {
reminder.audio = defaultAudio;
}
var row = table.insertRow(table.rows.length - 1);
let audioOptions = validAudioTypes
.map(audio => `<option value="${audio}" ${reminder.audio === audio ? 'selected' : ''}>${audio}</option>`)
.join('');
row.innerHTML = `
<td>
<select>
<option value="beforeStart" ${reminder.condition === 'beforeStart' ? 'selected' : ''}>当距离考试开始时间还有</option>
<option value="beforeEnd" ${reminder.condition === 'beforeEnd' ? 'selected' : ''}>当距离考试结束时间还有</option>
<option value="afterEnd" ${reminder.condition === 'afterEnd' ? 'selected' : ''}>当考试结束后</option>
<option value="start" ${reminder.condition === 'start' ? 'selected' : ''}>当考试开始时</option>
<option value="end" ${reminder.condition === 'end' ? 'selected' : ''}>当考试结束时</option>
</select>
</td>
<td><input type="number" value="${reminder.time}" placeholder="${reminder.condition === 'start' || reminder.condition === 'end' ? '-' : '分钟'}" ${reminder.condition === 'start' || reminder.condition === 'end' ? 'disabled' : ''}></td>
<td>
<select name="audioSelect">
${audioOptions}
</select>
</td>
<td><button onclick="removeReminder(this)">删除</button></td>
`;
row.cells[0].querySelector('select').addEventListener('change', function() {
row.cells[1].querySelector('input').disabled = this.value === 'start' || this.value === 'end';
row.cells[1].querySelector('input').placeholder = this.value === 'start' || this.value === 'end' ? '-' : '分钟';
});
});
// 更新提醒队列
loadRemindersToQueue(reminders);
})
.catch(error => {
errorSystem.show('加载音频文件列表失败: ' + error.message, 'error');
});
}
}
} catch (e) {
errorSystem.show('加载设置失败: ' + e.message, 'error');
}
}
document.addEventListener("DOMContentLoaded", () => {
const themeToggle = document.getElementById("theme-toggle");
let theme = getCookie("theme") || "light";
if (theme === "light") {
document.body.classList.remove("dark-mode");
themeToggle.checked = false;
} else {
document.body.classList.add("dark-mode");
themeToggle.checked = true;
}
themeToggle.addEventListener("change", () => {
const theme = themeToggle.checked ? "dark" : "light";
if (theme === "light") {
document.body.classList.remove("dark-mode");
} else {
document.body.classList.add("dark-mode");
}
setCookie("theme", theme, 365);
});
});
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 setCookie(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}

View File

@ -1,48 +0,0 @@
function setCookie(name, value, days) {
try {
const d = new Date();
d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
const expires = "expires=" + d.toUTCString();
document.cookie = name + "=" + value + ";" + expires + ";path=/;SameSite=Strict";
} catch (e) {
console.error('设置 Cookie 失败:', e);
}
}
function getCookie(name) {
try {
const nameEQ = name + "=";
const cookies = document.cookie.split(';');
for (let cookie of cookies) {
cookie = cookie.trim();
if (cookie.indexOf(nameEQ) === 0) {
return cookie.substring(nameEQ.length);
}
}
} catch (e) {
console.error('读取 Cookie 失败:', e);
}
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';
}
};

View File

@ -1,20 +0,0 @@
.action-btn {
background: #27ae60;
color: white;
border: none;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
font-size: 15px;
font-weight: 500;
transition: all 0.2s ease;
box-shadow: 0 4px 12px rgba(39, 174, 96, 0.25);
margin-top: 10px;
margin: 0;
height: 38px;
line-height: 18px;
}
.action-btn:hover {
transform: translateY(-1px);
box-shadow: 0 6px 16px rgba(39, 174, 96, 0.35);
}

View File

@ -1,12 +0,0 @@
body {
font-family: 'Segoe UI', Arial, sans-serif;
margin: 0;
padding: 20px;
background: #f5f7fa;
color: #2d3436;
}
.container {
max-width: 800px;
margin: 0 auto;
position: relative;
}

View File

@ -1,24 +0,0 @@
.control-bar {
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
display: flex;
gap: 10px;
}
.control-btn {
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);
}
.control-btn:hover {
transform: translateY(-1px);
box-shadow: 0 6px 16px rgba(52,152,219,0.35);
}

View File

@ -1,138 +0,0 @@
body.dark-mode {
background: #2d3436;
color: #e0e0e0;
}
body.dark-mode .status-box {
background: linear-gradient(145deg, #2d3436, #3a3a3a);
border: 1px solid #444;
}
body.dark-mode .time-display {
color: #ecf0f1;
}
body.dark-mode .status-label {
color: #bdc3c7;
}
body.dark-mode .schedule-table {
background: #3a3a3a;
}
body.dark-mode .schedule-table th {
background: #444;
color: #ecf0f1;
}
body.dark-mode .schedule-table td {
border-bottom: 1px solid #555;
}
body.dark-mode .current-class {
background: #34495e !important;
}
body.dark-mode .future-class {
background: #3a3a3a !important;
}
body.dark-mode .past-class {
background: #2d3436 !important;
color: #7f8c8d;
}
body.dark-mode .control-btn {
background: linear-gradient(135deg, #2980b9, #3498db);
}
body.dark-mode .control-btn:hover {
box-shadow: 0 6px 16px rgba(52, 152, 219, 0.35);
}
body.dark-mode .settings-panel {
background: rgba(45, 52, 54, 0.95);
border: 1px solid #444;
}
body.dark-mode .settings-panel h3 {
color: #ecf0f1;
}
body.dark-mode .settings-panel label {
color: #bdc3c7;
}
body.dark-mode .settings-panel input[type="number"] {
background: #3a3a3a;
color: #ecf0f1;
border: 1px solid #555;
}
body.dark-mode .settings-panel input[type="file"] {
background: #3a3a3a;
color: #ecf0f1;
border: 1px solid #555;
}
body.dark-mode .file-input-label {
background: #27ae60;
}
body.dark-mode .file-input-label:hover {
background: #219150;
}
body.dark-mode .info-container {
background: #2980b9;
}
body.dark-mode .info-content:before {
color: #2980b9;
}
body.dark-mode .error-container {
background: #c0392b;
}
body.dark-mode .error-content:before {
color: #c0392b;
}
body.dark-mode .reminder-table {
background: #3a3a3a;
}
body.dark-mode .reminder-table th {
background: #444;
color: #ecf0f1;
}
body.dark-mode .reminder-table td {
border-bottom: 1px solid #555;
}
body.dark-mode .reminder-table td input,
body.dark-mode .reminder-table td select {
background: #3a3a3a;
color: #ecf0f1;
border: 1px solid #555;
}
body.dark-mode .reminder-table td button {
background: #e74c3c;
}
body.dark-mode .reminder-table td button:hover {
background: #c0392b;
}
body.dark-mode .action-btn {
background: #27ae60;
}
body.dark-mode .action-btn:hover {
box-shadow: 0 6px 16px rgba(39, 174, 96, 0.35);
}
#return-btn {
position: absolute; /* 绝对定位 */
top: 20px; /* 距离顶部 20px */
left: 20px; /* 距离左侧 20px */
background-color: #f5f7fa; /* 默认亮色模式背景颜色 */
color: #333333; /* 默认亮色模式文字颜色 */
border: 1px solid #cccccc; /* 默认亮色模式边框颜色 */
border-radius: 16px; /* 按钮圆角大小 */
padding: 10px 18px; /* 按钮内边距 */
font-size: 14px; /* 按钮字体大小 */
cursor: pointer; /* 鼠标悬停时显示为手型 */
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); /* 按钮阴影 */
transition: background-color 0.3s ease, transform 0.3s ease; /* 背景颜色和缩放的过渡效果 */
z-index: 1001; /* 按钮层级 */
}
#return-btn:hover {
background-color: #e0e4e8; /* 默认亮色模式悬停背景颜色 */
transform: scale(1.05); /* 悬停时放大 5% */
}
/* 暗色模式 */
body.dark-mode #return-btn {
background-color: #4a4f55; /* 更浅的暗色模式背景颜色 */
color: #e0e0e0; /* 暗色模式文字颜色 */
border: 1px solid #555555; /* 更浅的暗色模式边框颜色 */
}
body.dark-mode #return-btn:hover {
background-color: #3b4046; /* 更浅的暗色模式悬停背景颜色 */
}

View File

@ -1,15 +0,0 @@
.file-input-label {
display: inline-block;
padding: 10px 20px;
background: #27ae60;
color: white;
border-radius: 8px;
cursor: pointer;
transition: background 0.3s ease;
}
.file-input-label:hover {
background: #219150;
}
.file-input-label input[type="file"] {
display: none;
}

View File

@ -1,40 +0,0 @@
.fullscreen-mode {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #ffffff;
z-index: 9999;
padding: 0;
margin: 0;
overflow: hidden;
}
.fullscreen-mode .status-box {
width: 100%;
height: 100%;
border: none;
box-shadow: none;
border-radius: 0;
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: none;
}
.fullscreen-mode .time-display {
font-size: 25vw;
line-height: 0.9;
color: #2c3e50;
}
.fullscreen-mode .status-label {
font-size: 6vw;
margin-top: 4vw;
color: #57606f;
}
.fullscreen-mode .control-bar,
.fullscreen-mode .settings-panel,
.fullscreen-mode .schedule-table {
display: none !important;
}

View File

@ -1,69 +0,0 @@
.info-container {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #3498db;
color: white;
padding: 16px;
display: none;
z-index: 10001;
animation: slideUp 0.3s ease;
}
@keyframes slideUp {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
.info-content {
max-width: 800px;
margin: 0 auto;
font-size: 15px;
display: flex;
align-items: center;
gap: 12px;
}
.info-content:before {
content: 'i';
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
background: white;
color: #3498db;
border-radius: 50%;
font-weight: bold;
}
.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;
}
.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;
}

View File

@ -1,55 +0,0 @@
.reminder-table {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}
.reminder-table th, .reminder-table td {
padding: 12px;
border-bottom: 1px solid #f1f3f6;
text-align: left;
}
.reminder-table th {
background: #f8f9fa;
color: #57606f;
font-weight: 600;
}
.reminder-table td {
padding: 12px;
border-bottom: 1px solid #f1f3f6;
text-align: left;
cursor: move; /* 添加拖拽光标 */
}
.reminder-table td.drag-handle {
cursor: grab; /* 添加拖拽光标 */
}
.reminder-table tr.dragging {
opacity: 0.5; /* 拖拽时透明度 */
}
.reminder-table td input, .reminder-table td select {
width: 100%;
padding: 8px;
border: 1px solid #e0e6ed;
border-radius: 4px;
font-size: 14px;
color: #2d3436;
}
.reminder-table td button {
background: #e74c3c;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s ease;
}
.reminder-table td button:hover {
background: #c0392b;
}
.reminder-table td:last-child {
text-align: center;
}

View File

@ -1,42 +0,0 @@
.schedule-table {
width: 100%;
border-collapse: collapse;
margin: 25px 0;
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}
.schedule-table th, .schedule-table td {
padding: 14px 16px;
text-align: left;
}
.schedule-table th {
background: #f8f9fa;
color: #57606f;
font-weight: 600;
border-bottom: 2px solid #e0e6ed;
}
.schedule-table td {
border-bottom: 1px solid #f1f3f6;
}
.current-class {
background: #e8f5e9 !important;
position: relative;
}
.current-class:after {
content: '';
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 4px;
background: #2ecc71;
}
.future-class {
background: #f8f9fa !important;
}
.past-class {
background: #fafafa !important;
color: #a4b0be;
}

View File

@ -1,60 +0,0 @@
.settings-panel {
background: rgba(255,255,255,0.95);
padding: 25px;
margin: 25px 0;
border-radius: 12px;
border: 1px solid #e0e6ed;
backdrop-filter: blur(8px);
}
.settings-panel h3 {
margin: 0 0 20px;
color: #2c3e50;
font-size: 20px;
}
.settings-panel label {
display: flex;
align-items: center;
gap: 10px;
margin: 12px 0;
font-size: 16px;
color: #57606f;
flex-wrap: wrap; /* 解决文本框显示在页面外的问题 */
}
.settings-panel input[type="checkbox"] {
width: 18px;
height: 18px;
accent-color: #3498db;
}
.settings-panel input[type="number"] {
width: 60px;
padding: 5px;
border: 1px solid #e0e6ed;
border-radius: 4px;
font-size: 14px;
color: #2d3436;
margin-right: 10px;
}
.settings-panel input[type="file"] {
margin-top: 10px;
}
.file-input-label {
display: inline-block;
padding: 10px 20px;
background: #27ae60;
color: white;
border-radius: 8px;
cursor: pointer;
transition: background 0.3s ease;
}
.file-input-label:hover {
background: #219150;
}
.file-input-label input[type="file"] {
display: none;
}
.button-group {
display: flex;
justify-content: space-between;
gap: 10px;
margin-top: 20px;
}

View File

@ -1,24 +0,0 @@
.status-box {
background: linear-gradient(145deg, #ffffff, #f8f9fa);
border: 1px solid #e0e6ed;
padding: 30px;
margin: 20px 0;
border-radius: 16px;
box-shadow: 0 8px 24px rgba(0,0,0,0.06);
transition: all 0.3s ease;
}
.time-display {
font-size: 48px;
color: #2c3e50;
font-weight: 700;
margin: 15px 0;
text-align: center;
letter-spacing: 2px;
text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.status-label {
font-size: 28px;
text-align: center;
margin: 15px 0;
color: #57606f;
}

View File

@ -1,479 +0,0 @@
/* 基础样式 */
body {
font-family: 'Segoe UI', Arial, sans-serif;
margin: 0;
padding: 20px;
background: #f5f7fa;
color: #2d3436;
}
.container {
max-width: 800px;
margin: 0 auto;
position: relative;
}
/* 考试信息板块 */
.exam-info {
text-align: center;
margin-bottom: 30px;
padding: 20px;
background: white;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}
.exam-info h1 {
margin: 0;
font-size: 32px;
color: #2c3e50;
margin-bottom: 10px;
}
.exam-room {
font-size: 18px;
color: #57606f;
}
.exam-message {
font-size: 20px;
color: #57606f;
margin-top: 10px;
}
/* 状态显示框 */
.status-box {
background: linear-gradient(145deg, #ffffff, #f8f9fa);
border: 1px solid #e0e6ed;
padding: 30px;
margin: 20px 0;
border-radius: 16px;
box-shadow: 0 8px 24px rgba(0,0,0,0.06);
transition: all 0.3s ease;
}
.time-display {
font-size: 48px;
color: #2c3e50;
font-weight: 700;
margin: 15px 0;
text-align: center;
letter-spacing: 2px;
text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.status-label {
font-size: 28px;
text-align: center;
margin: 15px 0;
color: #57606f;
}
/* 课程表格 */
.schedule-table {
width: 100%;
border-collapse: collapse;
margin: 25px 0;
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}
.schedule-table th {
background: #f8f9fa;
padding: 16px;
color: #57606f;
font-weight: 600;
border-bottom: 2px solid #e0e6ed;
}
.schedule-table td {
padding: 14px;
border-bottom: 1px solid #f1f3f6;
}
.current-class {
background: #e8f5e9 !important;
position: relative;
}
.current-class:after {
content: '';
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 4px;
background: #2ecc71;
}
.future-class {
background: #f8f9fa !important;
}
.past-class {
background: #fafafa !important;
color: #a4b0be;
}
/* 移除全屏模式相关样式 */
.fullscreen-mode {
display: none;
}
/* 控制按钮 */
.control-bar {
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
display: flex;
gap: 10px;
}
.control-btn {
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);
}
.control-btn:hover {
transform: translateY(-1px);
box-shadow: 0 6px 16px rgba(52,152,219,0.35);
}
/* 设置面板 */
.settings-panel {
background: rgba(255,255,255,0.95);
padding: 25px;
margin: 25px 0;
border-radius: 12px;
border: 1px solid #e0e6ed;
backdrop-filter: blur(8px);
}
.settings-panel h3 {
margin: 0 0 20px;
color: #2c3e50;
font-size: 20px;
}
.settings-panel label {
display: flex;
align-items: center;
gap: 10px;
margin: 12px 0;
font-size: 16px;
color: #57606f;
flex-wrap: wrap; /* 解决文本框显示在页面外的问题 */
}
.settings-panel input[type="checkbox"] {
width: 18px;
height: 18px;
accent-color: #3498db;
}
.settings-panel input[type="number"] {
width: 60px;
padding: 5px;
border: 1px solid #e0e6ed;
border-radius: 4px;
font-size: 14px;
color: #2d3436;
margin-right: 10px;
}
.settings-panel input[type="file"] {
margin-top: 10px;
}
.file-input-label {
display: inline-block;
padding: 10px 20px;
background: #27ae60;
color: white;
border-radius: 8px;
cursor: pointer;
transition: background 0.3s ease;
}
.file-input-label:hover {
background: #219150;
}
.file-input-label input[type="file"] {
display: none;
}
.button-group {
display: flex;
justify-content: space-between;
gap: 10px;
margin-top: 20px;
}
/* 信息提示 */
.info-container {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #3498db;
color: white;
padding: 16px;
display: none;
z-index: 10001;
animation: slideUp 0.3s ease;
}
@keyframes slideUp {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
.info-content {
max-width: 800px;
margin: 0 auto;
font-size: 15px;
display: flex;
align-items: center;
gap: 12px;
}
.info-content:before {
content: 'i';
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
background: white;
color: #3498db;
border-radius: 50%;
font-weight: bold;
}
/* 错误提示 */
.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;
}
.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;
}
/* 提醒表格 */
.reminder-table {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}
.reminder-table th, .reminder-table td {
padding: 12px;
border-bottom: 1px solid #f1f3f6;
text-align: left;
}
.reminder-table th {
background: #f8f9fa;
color: #57606f;
font-weight: 600;
}
.reminder-table td {
padding: 12px;
border-bottom: 1px solid #f1f3f6;
text-align: left;
cursor: move; /* 添加拖拽光标 */
}
.reminder-table td.drag-handle {
cursor: grab; /* 添加拖拽光标 */
}
.reminder-table tr.dragging {
opacity: 0.5; /* 拖拽时透明度 */
}
.reminder-table td input, .reminder-table td select {
width: 100%;
padding: 8px;
border: 1px solid #e0e6ed;
border-radius: 4px;
font-size: 14px;
color: #2d3436;
}
.reminder-table td button {
background: #e74c3c;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s ease;
}
.reminder-table td button:hover {
background: #c0392b;
}
.reminder-table td:last-child {
text-align: center;
}
/* 文件输入标签 */
.file-input-label {
display: inline-block;
padding: 10px 20px;
background: #27ae60;
color: white;
border-radius: 8px;
cursor: pointer;
transition: background 0.3s ease;
}
.file-input-label:hover {
background: #219150;
}
.file-input-label input[type="file"] {
display: none;
}
/* 动作按钮 */
.action-btn {
background: #27ae60;
color: white;
border: none;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
font-size: 15px;
font-weight: 500;
transition: all 0.2s ease;
box-shadow: 0 4px 12px rgba(39, 174, 96, 0.25);
margin-top: 10px;
}
.action-btn:hover {
transform: translateY(-1px);
box-shadow: 0 6px 16px rgba(39, 174, 96, 0.35);
}
/* 明暗色切换 */
body.dark-mode {
background: #2d3436;
color: #e0e0e0;
}
body.dark-mode .status-box {
background: linear-gradient(145deg, #2d3436, #3a3a3a);
border: 1px solid #444;
}
body.dark-mode .time-display {
color: #ecf0f1;
}
body.dark-mode .status-label {
color: #bdc3c7;
}
body.dark-mode .schedule-table {
background: #3a3a3a;
}
body.dark-mode .schedule-table th {
background: #444;
color: #ecf0f1;
}
body.dark-mode .schedule-table td {
border-bottom: 1px solid #555;
}
body.dark-mode .current-class {
background: #34495e !important;
}
body.dark-mode .future-class {
background: #3a3a3a !important;
}
body.dark-mode .past-class {
background: #2d3436 !important;
color: #7f8c8d;
}
body.dark-mode .control-btn {
background: linear-gradient(135deg, #2980b9, #3498db);
}
body.dark-mode .control-btn:hover {
box-shadow: 0 6px 16px rgba(52, 152, 219, 0.35);
}
body.dark-mode .settings-panel {
background: rgba(45, 52, 54, 0.95);
border: 1px solid #444;
}
body.dark-mode .settings-panel h3 {
color: #ecf0f1;
}
body.dark-mode .settings-panel label {
color: #bdc3c7;
}
body.dark-mode .settings-panel input[type="number"] {
background: #3a3a3a;
color: #ecf0f1;
border: 1px solid #555;
}
body.dark-mode .settings-panel input[type="file"] {
background: #3a3a3a;
color: #ecf0f1;
border: 1px solid #555;
}
body.dark-mode .file-input-label {
background: #27ae60;
}
body.dark-mode .file-input-label:hover {
background: #219150;
}
body.dark-mode .info-container {
background: #2980b9;
}
body.dark-mode .info-content:before {
color: #2980b9;
}
body.dark-mode .error-container {
background: #c0392b;
}
body.dark-mode .error-content:before {
color: #c0392b;
}
body.dark-mode .reminder-table {
background: #3a3a3a;
}
body.dark-mode .reminder-table th {
background: #444;
color: #ecf0f1;
}
body.dark-mode .reminder-table td {
border-bottom: 1px solid #555;
}
body.dark-mode .reminder-table td input,
body.dark-mode .reminder-table td select {
background: #3a3a3a;
color: #ecf0f1;
border: 1px solid #555;
}
body.dark-mode .reminder-table td button {
background: #e74c3c;
}
body.dark-mode .reminder-table td button:hover {
background: #c0392b;
}
body.dark-mode .action-btn {
background: #27ae60;
}
body.dark-mode .action-btn:hover {
box-shadow: 0 6px 16px rgba(39, 174, 96, 0.35);
}
body.dark-mode .exam-message {
color: #bdc3c7;
}

View File

@ -1,44 +0,0 @@
.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);
}

View File

@ -27,19 +27,108 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>当前时间</title>
<link rel="shortcut icon" href="../favicon.ico">
<link rel="shortcut icon" href="../favicon.png">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=DM+Sans|Inter|Space+Mono|Work+Sans|Libre+Franklin&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css"> <!-- 引入单独的 CSS 文件 -->
<style>
/* 基础样式 */
body {
font-family: 'Segoe UI', Arial, sans-serif;
margin: 0;
padding: 20px;
background: url('../background.jpg') no-repeat center center fixed;
background-size: cover;
color: #ecf0f1;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #2c3e50;
}
.container {
text-align: center;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
padding: 30px;
border-radius: 16px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(10px);
animation: fadeIn 2s ease-in-out;
}
.time {
font-size: 10rem;
margin: 0;
color: #ecf0f1;
font-weight: 700;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
animation: glow 1s ease-in-out infinite alternate;
}
.text {
font-size: 1.5rem;
margin-bottom: 20px;
color: #bdc3c7;
}
.btn {
padding: 10px 25px;
margin: 10px;
border: none;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: 500;
background: linear-gradient(135deg, #3498db, #2980b9);
color: white;
box-shadow: 0 4px 12px rgba(52, 152, 219, 0.25);
}
.btn:hover {
transform: translateY(-1px);
box-shadow: 0 6px 16px rgba(52, 152, 219, 0.35);
}
.controls {
margin-top: 30px;
}
.btn.fullscreen {
background: linear-gradient(135deg, #e74c3c, #c0392b);
color: #fff;
}
/* 动画效果 */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes glow {
from {
text-shadow: 0 0 10px #222;
}
to {
text-shadow: 0 0 20px #000;
}
}
</style>
</head>
<body>
<button id="return-btn" onclick="goBack()">返回</button> <!-- 新增返回按钮 -->
<div class="container">
<div class="text">当前时间:</div>
<div class="time" id="time"></div>
<div class="controls">
<select id="fontSelector" class="btn" onchange="changeFontFamily()">
<select id="fontSelector" class="btn">
<!-- 新增的Google字体选项 -->
<option value="Roboto">Roboto在线</option>
<option value="DM Sans">DM Sans在线</option>
<option value="Inter">Inter在线</option>
@ -50,10 +139,7 @@
<option value="黑体">黑体</option>
<option value="宋体">宋体</option>
</select>
<div class="font-size-control">
<input type="number" id="fontSizeInput" class="btn" value="160" min="10" max="500" step="5">
<span class="unit">px</span>
</div>
<button class="btn" onclick="changeFontFamily()">更改字体</button>
<button class="btn" onclick="changeFontSize(-5)">减小字号</button>
<button class="btn" onclick="changeFontSize(5)">增大字号</button>
<button class="btn fullscreen" onclick="toggleFullScreen()">全屏/还原</button>
@ -61,11 +147,6 @@
</div>
<script>
// 返回上级目录的函数
function goBack() {
window.history.back();
}
setInterval(() => {
const date = new Date();
const time = date.toLocaleTimeString('zh-CN', {
@ -76,17 +157,9 @@
function changeFontSize(change) {
const elements = document.querySelectorAll('.time');
const input = document.getElementById('fontSizeInput');
elements.forEach(element => {
let newSize;
if (typeof change === 'number') {
const currentSize = parseFloat(window.getComputedStyle(element).fontSize);
newSize = currentSize + change;
input.value = newSize;
} else {
newSize = parseInt(input.value);
}
element.style.fontSize = `${newSize}px`;
const currentSize = parseFloat(window.getComputedStyle(element).fontSize);
element.style.fontSize = `${currentSize + change}px`;
});
}
@ -107,12 +180,6 @@
}
}
}
// 监听字号输入框变化
document.getElementById('fontSizeInput').addEventListener('input', () => changeFontSize());
// 初始化默认字号
window.addEventListener('load', () => changeFontSize());
</script>
</body>

View File

@ -1,129 +0,0 @@
/* 基础样式 */
body {
font-family: 'Roboto', 'HarmonyOS Sans SC', sans-serif;
margin: 0;
padding: 20px;
background: #1C1B1F;
color: #E6E1E5;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
text-align: center;
background: #2B2930;
padding: 48px;
border-radius: 28px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
animation: fadeIn 0.3s ease-in-out;
}
.time {
font-size: 160px; /* 更新默认字号 */
margin: 0;
color: #D0BCFF;
font-weight: 400;
text-shadow: none;
}
.text {
font-size: 1.8rem;
margin-bottom: 32px;
color: #E6E1E5;
}
.controls {
margin-top: 40px;
display: flex;
gap: 12px;
flex-wrap: wrap;
justify-content: center;
}
.btn,
#fontSelector {
padding: 12px 24px;
border: none;
border-radius: 20px;
cursor: pointer;
transition: all 0.2s ease;
font-size: 1rem;
font-weight: 500;
background-color: #4A4458;
color: #E6E1E5;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.btn:hover,
#fontSelector:hover {
background-color: #635B70;
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
}
#fontSelector {
padding: 10px 20px;
}
.btn.fullscreen {
background-color: #5C1130;
color: #FFB3B3;
}
.btn.fullscreen:hover {
background-color: #7D2046;
}
/* 返回按钮样式 */
#return-btn {
position: absolute; /* 绝对定位 */
top: 20px; /* 距离顶部 20px */
left: 20px; /* 距离左侧 20px */
padding: 12px 24px; /* 内边距 */
font-size: 1rem; /* 字体大小 */
cursor: pointer; /* 鼠标悬停时显示为手型 */
background-color: #2b2b2b; /* 按钮背景颜色 */
color: #ffffff; /* 按钮文字颜色 */
border: 1px solid #444444; /* 按钮边框样式 */
border-radius: 20px; /* 按钮圆角大小 */
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); /* 按钮阴影 */
transition: all 0.2s ease; /* 背景颜色和缩放的过渡效果 */
z-index: 1001; /* 按钮层级 */
}
#return-btn:hover {
background-color: #3c3c3c; /* 悬停时的背景颜色 */
transform: translateY(-1px); /* 悬停时向上移动 1px */
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4); /* 悬停时的阴影效果 */
}
/* 简化动画效果 */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.font-size-control {
display: flex;
align-items: center;
gap: 4px;
}
#fontSizeInput {
width: 70px;
text-align: center;
padding: 12px 8px;
}
.unit {
color: #E6E1E5;
font-size: 0.9rem;
}