From 6432f2da7c73480719bae54e6ef0715330128968 Mon Sep 17 00:00:00 2001 From: MKStoler1024 <158786854+MKStoler1024@users.noreply.github.com> Date: Sat, 26 Apr 2025 17:54:53 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=90=88=E5=B9=B6=E7=9C=8B=E6=9D=BF?= =?UTF-8?q?=E5=92=8C=E5=B9=BF=E6=92=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .devcontainer/devcontainer.json | 27 + .github/dependabot.yml | 12 + .../Scripts}/audioController.js | 1 + exam/Scripts/examInfo.js | 2 + exam/Scripts/reminderModal.js | 26 + .../scripts => exam/Scripts}/reminderQueue.js | 1 + exam/Scripts/reminderSettings.js | 155 ++++++ exam/Scripts/utils.js | 2 + exam/Styles/ealg/dark.css | 450 ++++++++++++++-- exam/Styles/ealg/light.css | 262 +++++++++- {notification => exam}/audio/15min_left.mp3 | Bin {notification => exam}/audio/30min_left.mp3 | Bin {notification => exam}/audio/classstart.mp3 | Bin {notification => exam}/audio/end.mp3 | Bin {notification => exam}/audio/hedui_eng.mp3 | Bin {notification => exam}/audio/hedui_noeng.mp3 | Bin {notification => exam}/audio/jinchang.mp3 | Bin {notification => exam}/audio/start.mp3 | Bin .../audio/zhanshikemudai.mp3 | Bin {notification => exam}/audio_files.json | 0 exam/exam_config.json | 2 +- exam/index.html | 33 +- index.html | 22 +- notification/course_schedule.json | 47 -- notification/index.html | 90 ---- notification/scripts/config.js | 138 ----- notification/scripts/courseSchedule.js | 172 ------- notification/scripts/display.js | 56 -- notification/scripts/errorSystem.js | 17 - notification/scripts/script.js | 210 -------- notification/scripts/settings.js | 149 ------ notification/scripts/utils.js | 48 -- notification/styles/action-btn.css | 20 - notification/styles/base.css | 12 - notification/styles/control-btn.css | 24 - notification/styles/dark-mode.css | 138 ----- notification/styles/file-input-label.css | 15 - notification/styles/fullscreen-mode.css | 40 -- notification/styles/info-error.css | 69 --- notification/styles/reminder-table.css | 55 -- notification/styles/schedule-table.css | 42 -- notification/styles/settings-panel.css | 60 --- notification/styles/status-box.css | 24 - notification/styles/style.css | 479 ------------------ notification/styles/switch.css | 44 -- 45 files changed, 923 insertions(+), 2021 deletions(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .github/dependabot.yml rename {notification/scripts => exam/Scripts}/audioController.js (98%) create mode 100644 exam/Scripts/reminderModal.js rename {notification/scripts => exam/Scripts}/reminderQueue.js (94%) create mode 100644 exam/Scripts/reminderSettings.js rename {notification => exam}/audio/15min_left.mp3 (100%) rename {notification => exam}/audio/30min_left.mp3 (100%) rename {notification => exam}/audio/classstart.mp3 (100%) rename {notification => exam}/audio/end.mp3 (100%) rename {notification => exam}/audio/hedui_eng.mp3 (100%) rename {notification => exam}/audio/hedui_noeng.mp3 (100%) rename {notification => exam}/audio/jinchang.mp3 (100%) rename {notification => exam}/audio/start.mp3 (100%) rename {notification => exam}/audio/zhanshikemudai.mp3 (100%) rename {notification => exam}/audio_files.json (100%) delete mode 100644 notification/course_schedule.json delete mode 100644 notification/index.html delete mode 100644 notification/scripts/config.js delete mode 100644 notification/scripts/courseSchedule.js delete mode 100644 notification/scripts/display.js delete mode 100644 notification/scripts/errorSystem.js delete mode 100644 notification/scripts/script.js delete mode 100644 notification/scripts/settings.js delete mode 100644 notification/scripts/utils.js delete mode 100644 notification/styles/action-btn.css delete mode 100644 notification/styles/base.css delete mode 100644 notification/styles/control-btn.css delete mode 100644 notification/styles/dark-mode.css delete mode 100644 notification/styles/file-input-label.css delete mode 100644 notification/styles/fullscreen-mode.css delete mode 100644 notification/styles/info-error.css delete mode 100644 notification/styles/reminder-table.css delete mode 100644 notification/styles/schedule-table.css delete mode 100644 notification/styles/settings-panel.css delete mode 100644 notification/styles/status-box.css delete mode 100644 notification/styles/style.css delete mode 100644 notification/styles/switch.css diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..53cbd50 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,27 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/php +{ + "name": "PHP", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/php:1-8.2-bullseye", + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + "extensions": [ + "ikappas.composer" + ] + } + }, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [ + 8080 + ], + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "sudo chmod a+x \"$(pwd)\" && sudo rm -rf /var/www/html && sudo ln -s \"$(pwd)\" /var/www/html; if [ -f composer.json ];then composer install;fi" + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..f33a02c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for more information: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +# https://containers.dev/guide/dependabot + +version: 2 +updates: + - package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: weekly diff --git a/notification/scripts/audioController.js b/exam/Scripts/audioController.js similarity index 98% rename from notification/scripts/audioController.js rename to exam/Scripts/audioController.js index c2fd514..2b24de8 100644 --- a/notification/scripts/audioController.js +++ b/exam/Scripts/audioController.js @@ -1,3 +1,4 @@ +// ...复制 notification/scripts/audioController.js 的全部内容... var audioController = (function() { var audioPool = []; var maxPoolSize = 3; diff --git a/exam/Scripts/examInfo.js b/exam/Scripts/examInfo.js index 0cc15ee..c9d7c8f 100644 --- a/exam/Scripts/examInfo.js +++ b/exam/Scripts/examInfo.js @@ -42,6 +42,7 @@ document.addEventListener("DOMContentLoaded", () => { if (localConfig) { try { const data = JSON.parse(localConfig); + window.examConfigData = data; // 暴露全局变量供提醒队列使用 displayExamInfo(data); updateCurrentTime(); updateExamInfo(data); @@ -58,6 +59,7 @@ document.addEventListener("DOMContentLoaded", () => { return fetch('exam_config.json', { cache: "no-store" }) .then(response => response.json()) .then(data => { + window.examConfigData = data; // 暴露全局变量供提醒队列使用 displayExamInfo(data); updateCurrentTime(); updateExamInfo(data); diff --git a/exam/Scripts/reminderModal.js b/exam/Scripts/reminderModal.js new file mode 100644 index 0000000..8a56674 --- /dev/null +++ b/exam/Scripts/reminderModal.js @@ -0,0 +1,26 @@ +document.addEventListener("DOMContentLoaded", function() { + const reminderBtn = document.getElementById("reminder-settings-btn"); + const reminderModal = document.getElementById("reminder-modal"); + const closeReminderBtn = document.getElementById("close-reminder-btn"); + const saveReminderBtn = document.getElementById("save-reminder-btn"); + + reminderBtn.addEventListener("click", function() { + reminderModal.style.display = "block"; + }); + + closeReminderBtn.addEventListener("click", function() { + reminderModal.style.display = "none"; + }); + + saveReminderBtn.addEventListener("click", function() { + saveConfig(); + reminderModal.style.display = "none"; + }); + + // 点击弹窗外部关闭 + window.addEventListener("click", function(event) { + if (event.target === reminderModal) { + reminderModal.style.display = "none"; + } + }); +}); diff --git a/notification/scripts/reminderQueue.js b/exam/Scripts/reminderQueue.js similarity index 94% rename from notification/scripts/reminderQueue.js rename to exam/Scripts/reminderQueue.js index 3e07e74..b53df31 100644 --- a/notification/scripts/reminderQueue.js +++ b/exam/Scripts/reminderQueue.js @@ -1,3 +1,4 @@ +// ...复制 notification/scripts/reminderQueue.js 的全部内容... var reminderQueue = (function() { var queue = []; var audioCache = {}; diff --git a/exam/Scripts/reminderSettings.js b/exam/Scripts/reminderSettings.js new file mode 100644 index 0000000..e8dcbbd --- /dev/null +++ b/exam/Scripts/reminderSettings.js @@ -0,0 +1,155 @@ +// 提醒设置相关函数,适配exam页面 + +function addReminder() { + var table = document.getElementById('reminderTable'); + var row = table.insertRow(table.rows.length - 1); + row.innerHTML = ` + + + + + + + + + `; + 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('请添加至少一个提醒策略'); + return; + } + // 保存到 Cookie 并更新提醒队列 + setCookie("examReminders", encodeURIComponent(JSON.stringify(reminders)), 365); + loadRemindersToQueue(reminders); + errorSystem.show('提醒设置已保存'); + } catch (e) { + errorSystem.show('保存设置失败: ' + e.message); + } +} + +function loadRemindersToQueue(reminders) { + // 获取当前或下一个考试 + const examConfig = window.examConfigData; + if (!examConfig || !Array.isArray(examConfig.examInfos)) return; + const now = Date.now(); + let targetExam = null; + for (const exam of examConfig.examInfos) { + const start = new Date(exam.start).getTime(); + const end = new Date(exam.end).getTime(); + if (now < end) { + targetExam = exam; + break; + } + } + if (!targetExam) return; + reminders.forEach(function(reminder) { + let reminderTime; + switch (reminder.condition) { + case 'beforeStart': + reminderTime = new Date(targetExam.start).getTime() - reminder.time * 60000; + break; + case 'beforeEnd': + reminderTime = new Date(targetExam.end).getTime() - reminder.time * 60000; + break; + case 'afterEnd': + reminderTime = new Date(targetExam.end).getTime() + reminder.time * 60000; + break; + case 'start': + reminderTime = new Date(targetExam.start).getTime(); + break; + case 'end': + reminderTime = new Date(targetExam.end).getTime(); + break; + } + if (reminderTime > now) { + reminderQueue.addReminder({ time: reminderTime, condition: reminder.condition, audio: reminder.audio }); + } + }); +} + +// 页面加载时自动填充提醒表格 +document.addEventListener("DOMContentLoaded", () => { + // 加载提醒设置 + const reminderCookie = getCookie("examReminders"); + if (reminderCookie) { + const reminders = JSON.parse(decodeURIComponent(reminderCookie)); + if (Array.isArray(reminders)) { + var table = document.getElementById('reminderTable'); + while (table.rows.length > 2) { + table.deleteRow(1); + } + 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 => ``) + .join(''); + row.innerHTML = ` + + + + + + + + + `; + 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); + }); + } + } +}); diff --git a/exam/Scripts/utils.js b/exam/Scripts/utils.js index 68e8cb9..4d0d303 100644 --- a/exam/Scripts/utils.js +++ b/exam/Scripts/utils.js @@ -16,6 +16,8 @@ function getCookie(name) { return null; } +// 保持 setCookie/getCookie 兼容提醒设置 + function formatTimeWithoutSeconds(time) { return time.slice(0, -3); } diff --git a/exam/Styles/ealg/dark.css b/exam/Styles/ealg/dark.css index 0a7bd17..2cfac16 100644 --- a/exam/Styles/ealg/dark.css +++ b/exam/Styles/ealg/dark.css @@ -33,51 +33,6 @@ 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%; @@ -667,4 +622,409 @@ input:checked + .slider:before { .count-btn .material-icons { font-size: 16px; +} + +.settings-modal { + display: none; + position: fixed; + z-index: 2000; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0,0,0,0.6); + backdrop-filter: blur(8px); + display: flex; + align-items: center; + justify-content: center; +} + +#reminder-modal-content { + background: #404040; + padding: 32px 48px 32px 32px; + border-radius: 28px; + width: 600px; + max-height: 60vh; + overflow-y: auto; + box-shadow: 0 8px 24px rgba(0,0,0,0.4); + z-index: 2100; +} + +@media (max-width: 700px) { + #reminder-modal-content { + width: 95vw; + padding: 16px; + } +} + +/* 补全提醒设置弹窗样式 */ +.reminder-modal { + display: none; + position: fixed; + z-index: 2000; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0,0,0,0.6); + backdrop-filter: blur(8px); + display: flex; + align-items: center; + justify-content: center; +} + +.reminder-modal.show { + display: flex; +} + +#reminder-modal-content { + background: #404040; + padding: 32px 48px 32px 32px; + border-radius: 28px; + width: 800px; + max-width: 90vw; + max-height: 60vh; + overflow-y: auto; + box-shadow: 0 8px 24px rgba(0,0,0,0.4); + z-index: 2100; +} + +#reminder-modal-content::-webkit-scrollbar { + width: 8px; +} + +#reminder-modal-content::-webkit-scrollbar-track { + background: transparent; + margin: 4px; +} + +#reminder-modal-content::-webkit-scrollbar-thumb { + background: #4A4458; + border-radius: 8px; + border: 2px solid #2B2930; +} + +#reminder-modal-content::-webkit-scrollbar-thumb:hover { + background: #635B70; +} + +#reminder-modal-content h3 { + margin: 0 0 24px; + color: #E6E1E5; + font-size: 24px; + font-weight: 400; +} + +#reminder-modal-content label { + display: flex; + align-items: center; + gap: 16px; + margin: 16px 0; + font-size: 16px; + color: #E6E1E5; +} + +#reminder-modal-content input[type="number"], +#reminder-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; +} + +#reminder-modal-content input:focus { + outline: none; + border-color: #D0BCFF; + background-color: #4A4458; +} + +.reminder-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-reminder-btn, #close-reminder-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; + background-color: #404040; + color: #E6E1E5; +} + +#save-reminder-btn::before { + content: "✓"; + font-size: 18px; +} + +#close-reminder-btn::before { + content: "✕"; + font-size: 18px; +} + +#save-reminder-btn:hover, #close-reminder-btn:hover { + background-color: #4A4A4A; + transform: translateY(-1px); + box-shadow: 0 2px 6px rgba(0,0,0,0.4); +} + +@media (max-width: 700px) { + #reminder-modal-content { + width: 95vw; + padding: 16px; + } +} + +.top-btn-group { + position: fixed; + top: 20px; + right: 20px; + display: flex; + flex-direction: row; + gap: 16px; + z-index: 1002; +} + +.top-btn-group button { + 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; + display: flex; + align-items: center; + white-space: nowrap; +} + +.top-btn-group button::before { + font-family: 'Material Icons'; + font-size: 20px; + margin-right: 8px; +} + +.top-btn-group button:hover { + background-color: #4A4A4A; + transform: translateY(-1px); + box-shadow: 0 2px 6px rgba(0,0,0,0.4); +} + +#fullscreen-btn::before { + content: "fullscreen"; +} + +#reminder-settings-btn::before { + content: "notifications"; +} + +#settings-btn::before { + content: "settings"; +} + +/* 修改提醒弹窗样式 */ +.reminder-modal { + display: none; + position: fixed; + z-index: 2000; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0,0,0,0.6); + backdrop-filter: blur(8px); +} + +#reminder-modal-content { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: #404040; + padding: 32px 48px 32px 32px; + border-radius: 28px; + width: 800px; + max-width: 90vw; + max-height: 80vh; + overflow-y: auto; + box-shadow: 0 8px 24px rgba(0,0,0,0.4); +} + +/* 提醒表格样式 */ +.reminder-table { + width: 100%; + border-collapse: collapse; + margin-bottom: 20px; +} + +.reminder-table th, +.reminder-table td { + padding: 12px; + text-align: left; + border-bottom: 1px solid #555555; + font-size: 14px; + line-height: 36px; + vertical-align: middle; +} + +.reminder-table th { + font-weight: 500; + color: #E6E1E5; + font-size: 14px; +} + +.reminder-table select, +.reminder-table input { + width: 100%; + height: 36px; + padding: 0 12px; + font-size: 14px; + background-color: #332D41; + color: #E6E1E5; + border: 2px solid #4A4458; + border-radius: 8px; + transition: all 0.2s ease; + box-sizing: border-box; +} + +/* 提醒时间输入框独立样式 */ +.reminder-table .reminder-time-input { + width: 30px; + height: 36px; + padding: 0 12px; + font-size: 14px; + background-color: #332D41; + color: #E6E1E5; + border: 2px solid #4A4458; + border-radius: 8px; + transition: all 0.2s ease; + box-sizing: border-box; + text-align: center; +} + +.reminder-table .reminder-time-input:focus { + outline: none; + border-color: #D0BCFF; + background-color: #4A4458; +} + +.reminder-table button { + height: 36px; + min-width: 80px; + padding: 0 16px; + font-size: 14px; + background-color: #404040; + color: #E6E1E5; + border: none; + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; +} + +.reminder-table select:focus, +.reminder-table input:focus { + outline: none; + border-color: #D0BCFF; + background-color: #4A4458; +} + +.reminder-table button { + padding: 8px 16px; + font-size: 14px; + background-color: #404040; + color: #E6E1E5; + border: none; + border-radius: 16px; + cursor: pointer; + transition: all 0.2s ease; +} + +.reminder-table button:hover { + background-color: #4A4A4A; + transform: translateY(-1px); + box-shadow: 0 2px 6px rgba(0,0,0,0.4); +} + +.action-btn { + width: 100%; + padding: 12px; + font-size: 14px; + background-color: #404040; + color: #E6E1E5; + border: none; + border-radius: 16px; + cursor: pointer; + transition: all 0.2s ease; + margin-top: 12px; +} + +.action-btn:hover { + background-color: #4A4A4A; + transform: translateY(-1px); + box-shadow: 0 2px 6px rgba(0,0,0,0.4); +} + +.action-btn { + height: 36px; + font-size: 14px; + line-height: 36px; + padding: 0 16px; +} + +/* 提醒表格的时间输入框样式 */ +.reminder-table td input[type="number"] { + width: 80px !important; + text-align: center !important; + padding: 0 8px !important; + margin: 0 auto !important; + display: block !important; + -moz-appearance: textfield !important; +} + +.reminder-table td input[type="number"]::-webkit-outer-spin-button, +.reminder-table td input[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* 确保修改其他输入框和选择框不受影响 */ +.reminder-table td select { + min-width: 200px; +} + +.reminder-table td:nth-child(1) { + width: 50%; +} + +.reminder-table td:nth-child(2) { + width: 15%; +} + +.reminder-table td:nth-child(3) { + width: 25%; +} + +.reminder-table td:nth-child(4) { + width: 10%; } \ No newline at end of file diff --git a/exam/Styles/ealg/light.css b/exam/Styles/ealg/light.css index dfe585a..510d322 100644 --- a/exam/Styles/ealg/light.css +++ b/exam/Styles/ealg/light.css @@ -33,9 +33,27 @@ body::-webkit-scrollbar { display: none; } -#fullscreen-btn, #settings-btn { - position: absolute; +/* 删除这些样式 +#fullscreen-btn, #settings-btn { ... } +#fullscreen-btn { ... } +#settings-btn { ... } +#settings-btn:hover, #fullscreen-btn:hover { ... } +#settings-btn::before { ... } +#fullscreen-btn::before { ... } +*/ + +/* 新的按钮组样式 */ +.top-btn-group { + position: fixed; top: 20px; + right: 20px; + display: flex; + flex-direction: row; + gap: 16px; + z-index: 1002; +} + +.top-btn-group button { padding: 12px 24px; font-size: 1rem; cursor: pointer; @@ -45,37 +63,33 @@ body::-webkit-scrollbar { 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; + white-space: nowrap; } -#fullscreen-btn { - right: 20px; +.top-btn-group button::before { + font-family: 'Material Icons'; + font-size: 20px; + margin-right: 8px; } -#settings-btn { - right: 140px; -} - -#settings-btn:hover, #fullscreen-btn:hover { +.top-btn-group button: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; +} + +#reminder-settings-btn::before { + content: "notifications"; +} + +#settings-btn::before { + content: "settings"; } .container { @@ -667,4 +681,212 @@ input:checked + .slider:before { color: #1C1B1F; border: 2px solid #E8DEF8; border-radius: 8px; +} + +.settings-modal { + display: none; + position: fixed; + z-index: 2000; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0,0,0,0.3); + backdrop-filter: blur(8px); + display: flex; + align-items: center; + justify-content: center; +} + +#reminder-modal-content { + background: #FFFFFF; + padding: 32px 48px 32px 32px; + border-radius: 28px; + width: 600px; + max-height: 60vh; + overflow-y: auto; + box-shadow: 0 8px 24px rgba(0,0,0,0.2); + z-index: 2100; +} + +#reminder-modal-content { + width: 800px; + max-width: 90vw; +} + +@media (max-width: 700px) { + #reminder-modal-content { + width: 95vw; + padding: 16px; + } +} + +.top-btn-group { + position: fixed; + top: 20px; + right: 20px; + display: flex; + gap: 16px; + z-index: 1002; +} + +.top-btn-group button { + 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; + display: flex; + align-items: center; +} + +.top-btn-group button:hover { + background-color: #D0BCFF; + transform: translateY(-1px); + box-shadow: 0 2px 6px rgba(0,0,0,0.2); +} + +/* 按钮图标 */ +.top-btn-group button::before { + font-family: 'Material Icons'; + font-size: 20px; + margin-right: 8px; +} + +#fullscreen-btn::before { + content: "fullscreen"; +} + +#reminder-settings-btn::before { + content: "notifications"; +} + +#settings-btn::before { + content: "settings"; +} + +/* 提醒表格样式 */ +.reminder-table { + width: 100%; + border-collapse: collapse; + margin-bottom: 20px; +} + +.reminder-table th, +.reminder-table td { + padding: 12px; + text-align: left; + border-bottom: 1px solid #E8DEF8; + font-size: 14px; + line-height: 36px; + vertical-align: middle; +} + +.reminder-table th { + font-weight: 500; + color: #1C1B1F; + font-size: 14px; +} + +.reminder-table select, +.reminder-table input { + width: 100%; + height: 36px; + padding: 0 12px; + font-size: 14px; + background-color: #FFFFFF; + color: #1C1B1F; + border: 2px solid #E8DEF8; + border-radius: 8px; + transition: all 0.2s ease; + box-sizing: border-box; +} + +.reminder-table button { + height: 36px; + min-width: 80px; + padding: 0 16px; + font-size: 14px; + background-color: #E8DEF8; + color: #1C1B1F; + border: none; + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; +} + +.action-btn { + height: 36px; + font-size: 14px; + line-height: 36px; + padding: 0 16px; +} + +.action-btn:hover { + background-color: #D0BCFF; + transform: translateY(-1px); + box-shadow: 0 2px 6px rgba(0,0,0,0.2); +} + +/* 提醒时间输入框独立样式 */ +.reminder-table .reminder-time-input { + width: 80px; + height: 36px; + padding: 0 12px; + font-size: 14px; + background-color: #FFFFFF; + color: #1C1B1F; + border: 2px solid #E8DEF8; + border-radius: 8px; + transition: all 0.2s ease; + box-sizing: border-box; + text-align: center; +} + +.reminder-table .reminder-time-input:focus { + outline: none; + border-color: #6750A4; + background-color: #F7F2FA; +} + +/* 提醒表格的时间输入框样式 */ +.reminder-table td input[type="number"] { + width: 80px !important; + text-align: center !important; + padding: 0 8px !important; + -moz-appearance: textfield !important; + margin: 0 auto !important; + display: block !important; +} + +.reminder-table td input[type="number"]::-webkit-outer-spin-button, +.reminder-table td input[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* 确保修改其他输入框和选择框不受影响 */ +.reminder-table td select { + min-width: 200px; +} + +.reminder-table td:nth-child(1) { + width: 50%; +} + +.reminder-table td:nth-child(2) { + width: 15%; +} + +.reminder-table td:nth-child(3) { + width: 25%; +} + +.reminder-table td:nth-child(4) { + width: 10%; } \ No newline at end of file diff --git a/notification/audio/15min_left.mp3 b/exam/audio/15min_left.mp3 similarity index 100% rename from notification/audio/15min_left.mp3 rename to exam/audio/15min_left.mp3 diff --git a/notification/audio/30min_left.mp3 b/exam/audio/30min_left.mp3 similarity index 100% rename from notification/audio/30min_left.mp3 rename to exam/audio/30min_left.mp3 diff --git a/notification/audio/classstart.mp3 b/exam/audio/classstart.mp3 similarity index 100% rename from notification/audio/classstart.mp3 rename to exam/audio/classstart.mp3 diff --git a/notification/audio/end.mp3 b/exam/audio/end.mp3 similarity index 100% rename from notification/audio/end.mp3 rename to exam/audio/end.mp3 diff --git a/notification/audio/hedui_eng.mp3 b/exam/audio/hedui_eng.mp3 similarity index 100% rename from notification/audio/hedui_eng.mp3 rename to exam/audio/hedui_eng.mp3 diff --git a/notification/audio/hedui_noeng.mp3 b/exam/audio/hedui_noeng.mp3 similarity index 100% rename from notification/audio/hedui_noeng.mp3 rename to exam/audio/hedui_noeng.mp3 diff --git a/notification/audio/jinchang.mp3 b/exam/audio/jinchang.mp3 similarity index 100% rename from notification/audio/jinchang.mp3 rename to exam/audio/jinchang.mp3 diff --git a/notification/audio/start.mp3 b/exam/audio/start.mp3 similarity index 100% rename from notification/audio/start.mp3 rename to exam/audio/start.mp3 diff --git a/notification/audio/zhanshikemudai.mp3 b/exam/audio/zhanshikemudai.mp3 similarity index 100% rename from notification/audio/zhanshikemudai.mp3 rename to exam/audio/zhanshikemudai.mp3 diff --git a/notification/audio_files.json b/exam/audio_files.json similarity index 100% rename from notification/audio_files.json rename to exam/audio_files.json diff --git a/exam/exam_config.json b/exam/exam_config.json index a1f5016..d0a5242 100644 --- a/exam/exam_config.json +++ b/exam/exam_config.json @@ -5,7 +5,7 @@ "examInfos": [ { "name": "语文", - "start": "2025-05-06T07:30:00", + "start": "2025-04-27T01:20:00", "end": "2025-05-06T10:00:00" }, { diff --git a/exam/index.html b/exam/index.html index 8a43305..6f37cdc 100644 --- a/exam/index.html +++ b/exam/index.html @@ -12,9 +12,13 @@
+ +
+ + + +
- -

考试安排 @@ -156,9 +160,34 @@

+ + + + + + diff --git a/index.html b/index.html index 4a9c5e0..8e9baa1 100644 --- a/index.html +++ b/index.html @@ -29,10 +29,12 @@ list-style: none; padding: 0; margin: 0; - display: grid; - grid-template-columns: repeat(3, 1fr); + display: flex; + justify-content: center; gap: 24px; animation: fadeInUp 1s ease-in-out; + width: 100%; + max-width: 800px; } /* 主导航按钮样式 */ @@ -51,6 +53,8 @@ gap: 16px; min-width: 200px; text-align: center; + min-height: 140px; /* 增加高度以适应副标题 */ + flex: 1; } ul a:hover { @@ -155,6 +159,15 @@ .about-link .material-icons { font-size: 18px; } + + /* 添加新样式 */ + .subtitle { + font-size: 14px; + color: #CAC4D0; + margin-top: 4px; + width: 100%; + text-align: center; + } @@ -164,8 +177,9 @@ diff --git a/notification/course_schedule.json b/notification/course_schedule.json deleted file mode 100644 index 7737044..0000000 --- a/notification/course_schedule.json +++ /dev/null @@ -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" - } - ] -} diff --git a/notification/index.html b/notification/index.html deleted file mode 100644 index 4bb2528..0000000 --- a/notification/index.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - 考试看板—广播适配 - - - - - - - - - - - - - - - -
-
-
-
-
-
- -
-
-

考试看板

-
-
-
- -
- -
- -
-
正在初始化...
-
--:--
-
-
- -
-

系统设置

-
- - -
-

提醒设置

- - - - - - - - - - -
提醒条件时间(分钟)音频选择操作
- -
- - - - - - - -
科目时间段状态
-
- - - - - - - - - - - - \ No newline at end of file diff --git a/notification/scripts/config.js b/notification/scripts/config.js deleted file mode 100644 index e2b2d65..0000000 --- a/notification/scripts/config.js +++ /dev/null @@ -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 => ``) - .join(''); - - row.innerHTML = ` - - - - - - - - - `; - 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(); -} diff --git a/notification/scripts/courseSchedule.js b/notification/scripts/courseSchedule.js deleted file mode 100644 index 9e189a9..0000000 --- a/notification/scripts/courseSchedule.js +++ /dev/null @@ -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 => ``) - .join(''); - - row.innerHTML = ` - - - - - - - - - `; - - 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 = '' + course.name + '' + - '' + formatDateTime(course.start) + ' - ' + formatDateTime(course.end) + '' + - ''; - - 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'); - } -} diff --git a/notification/scripts/display.js b/notification/scripts/display.js deleted file mode 100644 index 34b848f..0000000 --- a/notification/scripts/display.js +++ /dev/null @@ -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' - }); -} diff --git a/notification/scripts/errorSystem.js b/notification/scripts/errorSystem.js deleted file mode 100644 index 8eb2a44..0000000 --- a/notification/scripts/errorSystem.js +++ /dev/null @@ -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'; - } -}; diff --git a/notification/scripts/script.js b/notification/scripts/script.js deleted file mode 100644 index e9aa76c..0000000 --- a/notification/scripts/script.js +++ /dev/null @@ -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 = ` - - - - - - - - - `; - 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 = ` - - - - - - - - - `; - 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(); \ No newline at end of file diff --git a/notification/scripts/settings.js b/notification/scripts/settings.js deleted file mode 100644 index f41390e..0000000 --- a/notification/scripts/settings.js +++ /dev/null @@ -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 => ``) - .join(''); - - row.innerHTML = ` - - - - - - - - - `; - - 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=/"; -} \ No newline at end of file diff --git a/notification/scripts/utils.js b/notification/scripts/utils.js deleted file mode 100644 index 596e588..0000000 --- a/notification/scripts/utils.js +++ /dev/null @@ -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'; - } -}; diff --git a/notification/styles/action-btn.css b/notification/styles/action-btn.css deleted file mode 100644 index 44fce6f..0000000 --- a/notification/styles/action-btn.css +++ /dev/null @@ -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); -} diff --git a/notification/styles/base.css b/notification/styles/base.css deleted file mode 100644 index eeb6c68..0000000 --- a/notification/styles/base.css +++ /dev/null @@ -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; -} diff --git a/notification/styles/control-btn.css b/notification/styles/control-btn.css deleted file mode 100644 index dd34b0d..0000000 --- a/notification/styles/control-btn.css +++ /dev/null @@ -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); -} diff --git a/notification/styles/dark-mode.css b/notification/styles/dark-mode.css deleted file mode 100644 index b62e5ff..0000000 --- a/notification/styles/dark-mode.css +++ /dev/null @@ -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; /* 更浅的暗色模式悬停背景颜色 */ -} \ No newline at end of file diff --git a/notification/styles/file-input-label.css b/notification/styles/file-input-label.css deleted file mode 100644 index 3e8a1e8..0000000 --- a/notification/styles/file-input-label.css +++ /dev/null @@ -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; -} diff --git a/notification/styles/fullscreen-mode.css b/notification/styles/fullscreen-mode.css deleted file mode 100644 index 5b97db7..0000000 --- a/notification/styles/fullscreen-mode.css +++ /dev/null @@ -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; -} diff --git a/notification/styles/info-error.css b/notification/styles/info-error.css deleted file mode 100644 index a839488..0000000 --- a/notification/styles/info-error.css +++ /dev/null @@ -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; -} diff --git a/notification/styles/reminder-table.css b/notification/styles/reminder-table.css deleted file mode 100644 index 8839630..0000000 --- a/notification/styles/reminder-table.css +++ /dev/null @@ -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; -} diff --git a/notification/styles/schedule-table.css b/notification/styles/schedule-table.css deleted file mode 100644 index e1b3e15..0000000 --- a/notification/styles/schedule-table.css +++ /dev/null @@ -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; -} diff --git a/notification/styles/settings-panel.css b/notification/styles/settings-panel.css deleted file mode 100644 index 046b2b3..0000000 --- a/notification/styles/settings-panel.css +++ /dev/null @@ -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; -} diff --git a/notification/styles/status-box.css b/notification/styles/status-box.css deleted file mode 100644 index cf29f97..0000000 --- a/notification/styles/status-box.css +++ /dev/null @@ -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; -} diff --git a/notification/styles/style.css b/notification/styles/style.css deleted file mode 100644 index f8ac5ed..0000000 --- a/notification/styles/style.css +++ /dev/null @@ -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; -} diff --git a/notification/styles/switch.css b/notification/styles/switch.css deleted file mode 100644 index 802bf42..0000000 --- a/notification/styles/switch.css +++ /dev/null @@ -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); -}