- {{ timeString }}{{ secondsString }}
+ {{ timeString }}{{ secondsString }} {{ amPmString }}
{{ dateString }} {{ weekdayString }} {{ periodOfDay }}
@@ -677,6 +684,24 @@
/>
+
+
+
+
+ 12 小时制
+ 以 12 小时制(AM/PM)显示时间。
+
+
+
+
@@ -720,6 +745,7 @@ export default {
showFullscreen: false,
showSettings: false,
timeCardEnabled: true,
+ use12hClock: false,
// 全屏模式切换
fullscreenMode: 'clock',
// 工具栏自动隐藏
@@ -785,9 +811,16 @@ export default {
},
computed: {
timeString() {
- const h = String(this.now.getHours()).padStart(2, '0')
+ const hours = this.now.getHours()
const m = String(this.now.getMinutes()).padStart(2, '0')
- return `${h}:${m}`
+ if (this.use12hClock) {
+ const h12 = hours % 12 || 12
+ return `${h12}:${m}`
+ }
+ return `${String(hours).padStart(2, '0')}:${m}`
+ },
+ amPmString() {
+ return this.now.getHours() < 12 ? 'AM' : 'PM'
},
secondsString() {
return `:${String(this.now.getSeconds()).padStart(2, '0')}`
@@ -994,12 +1027,17 @@ export default {
loadSettings() {
this.fontSize = SettingsManager.getSetting('font.size')
this.timeCardEnabled = getSetting('timeCard.enabled')
+ this.use12hClock = getSetting('timeCard.use12h')
this.noiseEnabled = getSetting('noiseMonitor.enabled')
},
setTimeCardEnabled(val) {
this.timeCardEnabled = val
setSetting('timeCard.enabled', val)
},
+ setUse12hClock(val) {
+ this.use12hClock = val
+ setSetting('timeCard.use12h', val)
+ },
startTimer() {
this.timer = setInterval(() => {
this.now = new Date()
diff --git a/src/utils/settings.js b/src/utils/settings.js
index c475762..a7c15f0 100644
--- a/src/utils/settings.js
+++ b/src/utils/settings.js
@@ -127,6 +127,12 @@ const settingsDefinitions = {
description: "启用时间卡片",
icon: "mdi-clock-outline",
},
+ "timeCard.use12h": {
+ type: "boolean",
+ default: false,
+ description: "使用 12 小时制显示时间",
+ icon: "mdi-clock-time-six-outline",
+ },
// 一言设置
"hitokoto.enabled": {
From 6f697d0fd0a5d9f93f3b61d26db9ac79708be68d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 11 Apr 2026 13:38:31 +0000
Subject: [PATCH 04/15] Add Hitokoto API category customization support
Agent-Logs-Url: https://github.com/ZeroCatDev/Classworks/sessions/6de2bd3a-dd64-4f26-a5a5-0f7fed081fdc
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/components/HitokotoCard.vue | 14 ++++++++---
src/components/HitokotoSettings.vue | 39 +++++++++++++++++++++++++++--
2 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/src/components/HitokotoCard.vue b/src/components/HitokotoCard.vue
index 6cbf3fd..a0bf03b 100644
--- a/src/components/HitokotoCard.vue
+++ b/src/components/HitokotoCard.vue
@@ -61,7 +61,8 @@ export default {
refreshInterval: 60,
kvConfig: {
sources: ['zhaoyu'],
- sensitiveWords: []
+ sensitiveWords: [],
+ hitokotoCategories: []
},
sentence: '',
author: '',
@@ -125,7 +126,8 @@ export default {
this.kvConfig = {
sources: Array.isArray(data.sources) && data.sources.length > 0 ? data.sources : ['zhaoyu'],
sensitiveWords: data.sensitiveWords ? data.sensitiveWords.split(/[,,]/).map(w => w.trim()).filter(w => w) : [],
- jinrishiciToken: data.jinrishiciToken
+ jinrishiciToken: data.jinrishiciToken,
+ hitokotoCategories: Array.isArray(data.hitokotoCategories) ? data.hitokotoCategories : []
}
}
} catch (e) {
@@ -155,7 +157,13 @@ export default {
let origin = ''
if (source === 'hitokoto') {
- const res = await axios.get('https://v1.hitokoto.cn/')
+ const params = new URLSearchParams()
+ const categories = this.kvConfig.hitokotoCategories
+ if (Array.isArray(categories) && categories.length > 0) {
+ categories.forEach(cat => params.append('c', cat))
+ }
+ const url = 'https://v1.hitokoto.cn/' + (params.toString() ? '?' + params.toString() : '')
+ const res = await axios.get(url)
data = res.data
content = data.hitokoto
author = data.from_who
diff --git a/src/components/HitokotoSettings.vue b/src/components/HitokotoSettings.vue
index 26555e7..75efd00 100644
--- a/src/components/HitokotoSettings.vue
+++ b/src/components/HitokotoSettings.vue
@@ -47,6 +47,25 @@
+
+ 一言句子类型
+ 不选则返回所有类型;可多选。
+
+
+
+
+
Date: Sat, 11 Apr 2026 13:38:58 +0000
Subject: [PATCH 05/15] Remove trailing comma in hitokotoCategories array
Agent-Logs-Url: https://github.com/ZeroCatDev/Classworks/sessions/6de2bd3a-dd64-4f26-a5a5-0f7fed081fdc
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/components/HitokotoSettings.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/HitokotoSettings.vue b/src/components/HitokotoSettings.vue
index 75efd00..2bce7af 100644
--- a/src/components/HitokotoSettings.vue
+++ b/src/components/HitokotoSettings.vue
@@ -312,7 +312,7 @@ export default {
{ value: 'i', label: '诗词' },
{ value: 'j', label: '网易云' },
{ value: 'k', label: '哲学' },
- { value: 'l', label: '抖机灵' },
+ { value: 'l', label: '抖机灵' }
],
loading: false,
testLoading: false,
From 3f6e0b88bd8a289a42819a485235ab9caa5df056 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 11 Apr 2026 13:53:32 +0000
Subject: [PATCH 07/15] feat: add custom background image with frosted glass
effect
- Add background settings (enabled, url, imageData, blur, opacity) to settings.js
- Add watchSettings same-tab reactivity via custom DOM event dispatch
- Create BackgroundSettingsCard.vue with URL input, file upload, sliders, preview
- Apply background layer in App.vue with blur filter and dark overlay
- Add background settings tab to settings.vue navigation
Agent-Logs-Url: https://github.com/ZeroCatDev/Classworks/sessions/6dfae4c0-df49-4612-88b8-9e31287538b0
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/App.vue | 76 +++-
.../settings/cards/BackgroundSettingsCard.vue | 422 ++++++++++++++++++
src/pages/settings.vue | 12 +
src/utils/settings.js | 62 ++-
4 files changed, 566 insertions(+), 6 deletions(-)
create mode 100644 src/components/settings/cards/BackgroundSettingsCard.vue
diff --git a/src/App.vue b/src/App.vue
index cd7b1bb..1771bc8 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,5 +1,11 @@
-
+
+
+
+
+
+
+
@@ -12,24 +18,71 @@
diff --git a/src/components/settings/cards/BackgroundSettingsCard.vue b/src/components/settings/cards/BackgroundSettingsCard.vue
new file mode 100644
index 0000000..d6d0ab7
--- /dev/null
+++ b/src/components/settings/cards/BackgroundSettingsCard.vue
@@ -0,0 +1,422 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ mdi-image-search
+ 图片来源
+
+
+
+
+ 网络地址
+ 本地上传
+
+
+
+
+
+
+
+ {{ preset.label }}
+
+
+
+
+
+
+
+
mdi-image-plus
+
点击或拖拽图片到此处上传
+
支持 JPG、PNG、WebP、GIF(建议小于 2MB)
+
+
+
+
+ {{ uploadWarning }}
+
+
+
+
+ 已上传本地图片
+
+
+ 清除
+
+
+
+
+
+
+
+
+ mdi-blur
+ 毛玻璃效果
+
+
+
+
+ 模糊幅度
+ {{ localBlur }}px
+
+
+
+ mdi-blur-off
+
+
+ mdi-blur
+
+
+
+
+
+
+ 遮罩暗色程度
+ {{ localOpacity }}%
+
+
+
+ mdi-brightness-7
+
+
+ mdi-brightness-2
+
+
+
+
+
+
+
+
+
+ 重置
+
+
+ 保存设置
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/settings.vue b/src/pages/settings.vue
index 67f3148..8bfdee1 100644
--- a/src/pages/settings.vue
+++ b/src/pages/settings.vue
@@ -195,6 +195,10 @@
+
+
+
+
@@ -280,6 +284,7 @@ import KvDatabaseCard from "@/components/settings/cards/KvDatabaseCard.vue";
import HitokotoSettings from "@/components/HitokotoSettings.vue";
import NotificationSoundSettings from "@/components/settings/NotificationSoundSettings.vue";
import NoiseSettingsCard from "@/components/settings/cards/NoiseSettingsCard.vue";
+import BackgroundSettingsCard from "@/components/settings/cards/BackgroundSettingsCard.vue";
export default {
name: "Settings",
@@ -304,6 +309,7 @@ export default {
HitokotoSettings,
NotificationSoundSettings,
NoiseSettingsCard,
+ BackgroundSettingsCard,
},
setup() {
const {mobile} = useDisplay();
@@ -442,6 +448,12 @@ export default {
value: "randomPicker",
},
+ {
+ title: "背景",
+ icon: "mdi-image",
+ value: "background",
+ },
+
{
title: "开发者",
icon: "mdi-developer-board",
diff --git a/src/utils/settings.js b/src/utils/settings.js
index a7c15f0..b942ea9 100644
--- a/src/utils/settings.js
+++ b/src/utils/settings.js
@@ -441,6 +441,40 @@ const settingsDefinitions = {
// 设置应用的主题模式,可选亮色或暗色主题
},
+ // 背景设置
+ "background.enabled": {
+ type: "boolean",
+ default: false,
+ description: "启用自定义背景",
+ icon: "mdi-image",
+ },
+ "background.url": {
+ type: "string",
+ default: "",
+ description: "背景图片地址",
+ icon: "mdi-link",
+ },
+ "background.imageData": {
+ type: "string",
+ default: "",
+ description: "本地背景图片(Base64)",
+ icon: "mdi-image-area",
+ },
+ "background.blur": {
+ type: "number",
+ default: 10,
+ validate: (value) => value >= 0 && value <= 50,
+ description: "毛玻璃模糊幅度(px)",
+ icon: "mdi-blur",
+ },
+ "background.opacity": {
+ type: "number",
+ default: 30,
+ validate: (value) => value >= 0 && value <= 80,
+ description: "遮罩暗色程度(%)",
+ icon: "mdi-circle-half-full",
+ },
+
// 通知铃声设置
"notification.singleSound": {
type: "string",
@@ -674,6 +708,13 @@ class SettingsManagerClass {
this.saveSettings();
this.logSettingsChange(key, oldValue, value);
+ // 触发同标签页内的设置变化事件
+ if (typeof window !== "undefined") {
+ window.dispatchEvent(new CustomEvent("classworks-settings-changed", {
+ detail: { key, value },
+ }));
+ }
+
// 为了保持向后兼容,同时更新旧的localStorage键
const legacyKey = definition.legacyKey;
if (legacyKey && typeof localStorage !== "undefined") {
@@ -721,6 +762,13 @@ class SettingsManagerClass {
this.settingsCache[key] = definition.default;
this.saveSettings();
+
+ // 触发同标签页内的设置变化事件
+ if (typeof window !== "undefined") {
+ window.dispatchEvent(new CustomEvent("classworks-settings-changed", {
+ detail: { key, value: definition.default },
+ }));
+ }
}
/**
@@ -743,15 +791,23 @@ class SettingsManagerClass {
if (typeof window === "undefined") return () => {
};
- const handler = (event) => {
+ const storageHandler = (event) => {
if (event.key === SETTINGS_STORAGE_KEY) {
this.settingsCache = JSON.parse(event.newValue);
callback(this.settingsCache);
}
};
- window.addEventListener("storage", handler);
- return () => window.removeEventListener("storage", handler);
+ const customHandler = () => {
+ callback(this.settingsCache);
+ };
+
+ window.addEventListener("storage", storageHandler);
+ window.addEventListener("classworks-settings-changed", customHandler);
+ return () => {
+ window.removeEventListener("storage", storageHandler);
+ window.removeEventListener("classworks-settings-changed", customHandler);
+ };
}
/**
From c4279acdae78fc178685bda21ff5458eee9ac256 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 11 Apr 2026 13:56:41 +0000
Subject: [PATCH 08/15] fix: address code review feedback for background
feature
- Use SETTINGS_CHANGED_EVENT constant to prevent typos
- Enforce 2MB image size limit (block upload instead of warn)
- Fix resetAll to force re-render SettingItem for enabled toggle
- Optimize watchSettings callback to only reload on relevant key changes
Agent-Logs-Url: https://github.com/ZeroCatDev/Classworks/sessions/6dfae4c0-df49-4612-88b8-9e31287538b0
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/App.vue | 11 +++++++----
.../settings/cards/BackgroundSettingsCard.vue | 8 ++++++--
src/utils/settings.js | 17 ++++++++++-------
3 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/src/App.vue b/src/App.vue
index 1771bc8..56d4c98 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -67,10 +67,13 @@ onMounted(() => {
loadBgSettings();
- unwatchSettings = watchSettings(() => {
- loadBgSettings();
- // Reapply theme on settings change too
- theme.global.name.value = getSetting("theme.mode");
+ unwatchSettings = watchSettings((_, event) => {
+ // If event detail is available (same-tab change), only reload on background keys
+ const changedKey = event?.detail?.key;
+ if (!changedKey || changedKey.startsWith("background.") || changedKey === "theme.mode") {
+ loadBgSettings();
+ theme.global.name.value = getSetting("theme.mode");
+ }
});
window.addEventListener('beforeinstallprompt', (e) => {
diff --git a/src/components/settings/cards/BackgroundSettingsCard.vue b/src/components/settings/cards/BackgroundSettingsCard.vue
index d6d0ab7..d011b50 100644
--- a/src/components/settings/cards/BackgroundSettingsCard.vue
+++ b/src/components/settings/cards/BackgroundSettingsCard.vue
@@ -1,7 +1,7 @@
-
+
@@ -221,6 +221,7 @@ export default {
saving: false,
uploadWarning: '',
urlPresets: URL_PRESETS,
+ settingItemKey: 0,
};
},
@@ -332,7 +333,8 @@ export default {
const sizeMB = file.size / 1024 / 1024;
if (sizeMB > MAX_IMAGE_SIZE_MB) {
- this.uploadWarning = `图片大小为 ${sizeMB.toFixed(1)}MB,超过 ${MAX_IMAGE_SIZE_MB}MB 建议大小,可能影响性能`;
+ this.uploadWarning = `图片大小为 ${sizeMB.toFixed(1)}MB,超过 ${MAX_IMAGE_SIZE_MB}MB 限制,请压缩后重试`;
+ return;
}
const reader = new FileReader();
@@ -379,6 +381,8 @@ export default {
this.localOpacity = getSetting('background.opacity') ?? 30;
this.imageSource = 'url';
this.uploadWarning = '';
+ // Force re-render of SettingItem to reflect reset enabled state
+ this.settingItemKey++;
},
},
};
diff --git a/src/utils/settings.js b/src/utils/settings.js
index b942ea9..4760992 100644
--- a/src/utils/settings.js
+++ b/src/utils/settings.js
@@ -62,6 +62,9 @@ async function initializeStorage() {
// 存储所有设置的localStorage键名
const SETTINGS_STORAGE_KEY = "Classworks_settings";
+// 同标签页设置变化事件名
+const SETTINGS_CHANGED_EVENT = "classworks:settings:changed";
+
// 新增: Classworks云端存储的默认设置
const classworksCloudDefaults = {
@@ -710,7 +713,7 @@ class SettingsManagerClass {
// 触发同标签页内的设置变化事件
if (typeof window !== "undefined") {
- window.dispatchEvent(new CustomEvent("classworks-settings-changed", {
+ window.dispatchEvent(new CustomEvent(SETTINGS_CHANGED_EVENT, {
detail: { key, value },
}));
}
@@ -765,7 +768,7 @@ class SettingsManagerClass {
// 触发同标签页内的设置变化事件
if (typeof window !== "undefined") {
- window.dispatchEvent(new CustomEvent("classworks-settings-changed", {
+ window.dispatchEvent(new CustomEvent(SETTINGS_CHANGED_EVENT, {
detail: { key, value: definition.default },
}));
}
@@ -794,19 +797,19 @@ class SettingsManagerClass {
const storageHandler = (event) => {
if (event.key === SETTINGS_STORAGE_KEY) {
this.settingsCache = JSON.parse(event.newValue);
- callback(this.settingsCache);
+ callback(this.settingsCache, null);
}
};
- const customHandler = () => {
- callback(this.settingsCache);
+ const customHandler = (event) => {
+ callback(this.settingsCache, event);
};
window.addEventListener("storage", storageHandler);
- window.addEventListener("classworks-settings-changed", customHandler);
+ window.addEventListener(SETTINGS_CHANGED_EVENT, customHandler);
return () => {
window.removeEventListener("storage", storageHandler);
- window.removeEventListener("classworks-settings-changed", customHandler);
+ window.removeEventListener(SETTINGS_CHANGED_EVENT, customHandler);
};
}
From 1f33d6d6370c05036a8aac81723a4aaf2dfbbda0 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 11 Apr 2026 13:58:41 +0000
Subject: [PATCH 09/15] fix: use MAX_IMAGE_SIZE_MB constant consistently in
template and error messages
Agent-Logs-Url: https://github.com/ZeroCatDev/Classworks/sessions/6dfae4c0-df49-4612-88b8-9e31287538b0
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
src/components/settings/cards/BackgroundSettingsCard.vue | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/components/settings/cards/BackgroundSettingsCard.vue b/src/components/settings/cards/BackgroundSettingsCard.vue
index d011b50..d6363a5 100644
--- a/src/components/settings/cards/BackgroundSettingsCard.vue
+++ b/src/components/settings/cards/BackgroundSettingsCard.vue
@@ -74,7 +74,7 @@
>
mdi-image-plus
点击或拖拽图片到此处上传
- 支持 JPG、PNG、WebP、GIF(建议小于 2MB)
+ 支持 JPG、PNG、WebP、GIF(建议小于 {{ maxImageSizeMB }}MB)
Date: Sat, 11 Apr 2026 14:05:00 +0000
Subject: [PATCH 10/15] fix: update URL presets for background images
---
src/components/settings/cards/BackgroundSettingsCard.vue | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/components/settings/cards/BackgroundSettingsCard.vue b/src/components/settings/cards/BackgroundSettingsCard.vue
index d6363a5..c02650e 100644
--- a/src/components/settings/cards/BackgroundSettingsCard.vue
+++ b/src/components/settings/cards/BackgroundSettingsCard.vue
@@ -196,9 +196,10 @@ import SettingItem from '@/components/settings/SettingItem.vue';
import { getSetting, setSetting, resetSetting } from '@/utils/settings';
const URL_PRESETS = [
- { label: 'Bing 每日壁纸', url: 'https://bing.img.run/rand_uhd.php' },
+ { label: 'Bing 随机壁纸', url: 'https://bing.img.run/rand.php' },
+ { label: 'Bing 每日壁纸', url: 'https://bing.img.run/1920x1080.php' },
{ label: '随机风景', url: 'https://picsum.photos/1920/1080?random=1' },
- { label: '随机自然', url: 'https://source.unsplash.com/1920x1080/?nature' },
+ { label: '随机二次元', url: 'https://uapis.cn/api/v1/random/image?category=acg&type=pc' },
];
const MAX_IMAGE_SIZE_MB = 2;
From 3cfd47a0116290405e182e071128b240a800d4b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AD=99=E6=82=9F=E5=85=83?=
Date: Sat, 11 Apr 2026 14:05:20 +0000
Subject: [PATCH 11/15] fix: update MAX_IMAGE_SIZE_MB to 10 for background
image settings
---
src/components/settings/cards/BackgroundSettingsCard.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/settings/cards/BackgroundSettingsCard.vue b/src/components/settings/cards/BackgroundSettingsCard.vue
index c02650e..7ff1b42 100644
--- a/src/components/settings/cards/BackgroundSettingsCard.vue
+++ b/src/components/settings/cards/BackgroundSettingsCard.vue
@@ -202,7 +202,7 @@ const URL_PRESETS = [
{ label: '随机二次元', url: 'https://uapis.cn/api/v1/random/image?category=acg&type=pc' },
];
-const MAX_IMAGE_SIZE_MB = 2;
+const MAX_IMAGE_SIZE_MB = 10;
export default {
name: 'BackgroundSettingsCard',
From ef1ff7797798099e59f44e44cd43977fc2fd115c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Apr 2026 13:49:52 +0000
Subject: [PATCH 12/15] feat: optimize server selection with latency caching,
background probing, and 404-aware rotation
Agent-Logs-Url: https://github.com/Moonrend/Classworks/sessions/d254def7-bda7-413a-83b1-c553c1571523
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
---
eslint.config.js | 2 +
src/App.vue | 20 +-
src/components/AppHeader.vue | 4 +-
src/components/CacheManager.vue | 69 ++-
src/components/ExamConfigEditor.vue | 433 ++++++++++-----
src/components/FloatingToolbar.vue | 19 +-
src/components/GlobalMessage.vue | 22 +-
src/components/HelloWorld.vue | 19 +-
src/components/HitokotoSettings.vue | 244 +++++++--
src/components/HomeworkEditDialog.vue | 64 ++-
src/components/MessageLog.vue | 37 +-
src/components/NoiseMonitorCard.vue | 25 +-
src/components/PwaInstallCard.vue | 49 +-
src/components/RandomPicker.vue | 87 ++-
src/components/RateLimitModal.vue | 42 +-
src/components/ReadOnlyTokenWarning.vue | 2 +-
src/components/SettingsCard.vue | 18 +-
src/components/SettingsLinkGenerator.vue | 227 +++++---
src/components/StudentNameManager.vue | 2 -
src/components/TimeCard.vue | 5 +-
src/components/UrgentNotification.vue | 29 +-
src/components/UrgentTestDialog.vue | 120 ++--
.../attendance/AttendanceManagementDialog.vue | 61 ++-
.../attendance/AttendanceSidebar.vue | 15 +-
src/components/auth/AlternativeCodeDialog.vue | 2 +-
src/components/auth/DeviceAuthDialog.vue | 10 +-
src/components/auth/FirstTimeGuide.vue | 4 +-
.../auth/ProgressiveRegisterPage.vue | 14 +-
src/components/auth/TokenInputDialog.vue | 2 +-
.../common/AsyncLoadingPlaceholder.vue | 12 +-
src/components/common/HomeSkeleton.vue | 5 +-
src/components/error/404.vue | 33 +-
src/components/home/ConciseExamCard.vue | 30 +-
src/components/home/ExamScheduleCard.vue | 88 ++-
src/components/home/HomeActions.vue | 16 +-
src/components/home/HomeworkGrid.vue | 158 ++++--
src/components/settings/AboutCard.vue | 155 ++++--
.../settings/CloudMigrationDialog.vue | 80 ++-
.../settings/NotificationSoundSettings.vue | 31 +-
src/components/settings/SettingGroup.vue | 18 +-
src/components/settings/SettingItem.vue | 52 +-
src/components/settings/SettingsExplorer.vue | 40 +-
src/components/settings/StudentListCard.vue | 51 +-
src/components/settings/TeacherListCard.vue | 71 ++-
.../settings/cards/BackgroundSettingsCard.vue | 131 ++++-
.../settings/cards/CloudNamespaceInfoCard.vue | 16 +-
.../cards/DataProviderSettingsCard.vue | 82 ++-
.../settings/cards/DisplaySettingsCard.vue | 70 ++-
.../settings/cards/EchoChamberCard.vue | 25 +-
.../settings/cards/EditSettingsCard.vue | 28 +-
.../settings/cards/HomeworkTemplateCard.vue | 120 +++-
.../settings/cards/KvDatabaseCard.vue | 254 +++++++--
.../settings/cards/RandomPickerCard.vue | 29 +-
.../settings/cards/RefreshSettingsCard.vue | 18 +-
.../settings/cards/SubjectManagementCard.vue | 14 +-
.../settings/cards/ThemeSettingsCard.vue | 30 +-
src/pages/404.vue | 2 +-
src/pages/CacheManagement.vue | 69 ++-
src/pages/authorize.vue | 27 +-
src/pages/cses2wakeup.vue | 515 +++++++++++++-----
src/pages/debug-init.vue | 2 +-
src/pages/debug-socket.vue | 18 +-
src/pages/debug.vue | 10 +-
src/pages/exam-editor/[id].vue | 2 +-
src/pages/examschedule.vue | 206 +++++--
src/pages/index.vue | 223 ++++++--
src/pages/list/[id].vue | 154 ++++--
src/pages/list/index.vue | 80 ++-
src/pages/settings.vue | 158 ++++--
src/pages/socket-debugger.vue | 131 ++++-
src/utils/serverRotation.js | 186 +++++--
71 files changed, 3792 insertions(+), 1295 deletions(-)
diff --git a/eslint.config.js b/eslint.config.js
index 2e02a43..b70755a 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -62,6 +62,8 @@ export default [
// Web Workers
Worker: 'readonly',
SharedWorker: 'readonly',
+ // Fetch API
+ AbortController: 'readonly',
},
},
}
diff --git a/src/App.vue b/src/App.vue
index 56d4c98..af2408a 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -2,14 +2,26 @@
-
-
+
+
-
-
+
+
diff --git a/src/components/AppHeader.vue b/src/components/AppHeader.vue
index 6a62425..7e625f6 100644
--- a/src/components/AppHeader.vue
+++ b/src/components/AppHeader.vue
@@ -1,7 +1,7 @@
-
-
+
+
作业
diff --git a/src/components/CacheManager.vue b/src/components/CacheManager.vue
index 793d33d..31bec12 100644
--- a/src/components/CacheManager.vue
+++ b/src/components/CacheManager.vue
@@ -2,48 +2,85 @@
缓存管理
-
-
+
+
清除所有缓存
-
+
mdi-refresh
-
+
Service Worker 未激活,缓存管理功能不可用。
-
+
{{ message }}
-
+
{{ formatCacheName(cache.name) }}
- {{ cache.urls.length }} 个文件
+
+ {{ cache.urls.length }} 个文件
+
-
+
清除此缓存
-
+
{{ getFileName(url) }}
{{ url }}
-
-
+
+
mdi-delete
@@ -53,9 +90,15 @@
-
+
-
+
没有找到缓存数据。
diff --git a/src/components/ExamConfigEditor.vue b/src/components/ExamConfigEditor.vue
index 065e8eb..7f35252 100644
--- a/src/components/ExamConfigEditor.vue
+++ b/src/components/ExamConfigEditor.vue
@@ -11,7 +11,9 @@
@click:close="error = ''"
>
- mdi-alert-circle
+
+ mdi-alert-circle
+
{{ error }}
@@ -27,7 +29,9 @@
@click:close="success = ''"
>
- mdi-check-circle
+
+ mdi-check-circle
+
{{ success }}
@@ -43,29 +47,49 @@
配置验证失败,请检查以下问题:
-
+
-
- mdi-circle-small
+
+
+ mdi-circle-small
+
- {{ error }}
+
+ {{ error }}
+
-
+
-
+
-
+
删除配置
- 预览
- 编辑
+
+ 预览
+
+
+ 编辑
+
-
+
{{ localConfig.examName || "未设置考试名称" }}
{{ localConfig.message || "未设置考试提示" }}
-
- mdi-home
+
+
+ mdi-home
+
考场:{{ localConfig.room }}
@@ -178,20 +220,29 @@
lg="4"
md="6"
>
-
+
- mdi-book-open-page-variant
+
+ mdi-book-open-page-variant
+
{{ examInfo.name || "未设置科目" }}
- mdi-clock-start
-
+ mdi-clock-start
+
开始时间
@@ -200,10 +251,13 @@
- mdi-clock-end
-
+ mdi-clock-end
+
结束时间
@@ -215,29 +269,50 @@
-
-
+
+
mdi-calendar-blank
-
暂无考试科目安排
+
+ 暂无考试科目安排
+
点击上方"添加科目"按钮开始配置考试时间表
-
- mdi-plus
+
+
+ mdi-plus
+
立即添加
-
+
- mdi-code-json
+
+ mdi-code-json
+
配置预览
-
+
-
+ />
-
-
+
+
{{ formattedStorageJson }}
@@ -271,14 +351,23 @@
-
+
- mdi-information
+
+ mdi-information
+
基本信息
-
+
+ />
-
+
+ />
- mdi-message-text
+ mdi-message-text
考试提示
+ />
-
+
- mdi-plus
+
+ mdi-plus
+
{{ tip.substring(0, 20) }}...
- mdi-lightbulb-outline
+
+ mdi-lightbulb-outline
+
点击上方选项快速添加常用考试提示
@@ -358,11 +466,17 @@
-
+
- mdi-format-list-bulleted
+
+ mdi-format-list-bulleted
+
考试科目安排
-
+
@@ -373,7 +487,7 @@
hide-details
@change="toggleAlertTimeMode"
>
-
+
自定义提醒时间
@@ -408,14 +522,19 @@
variant="tonal"
class="mr-3"
>
- mdi-numeric-{{ index + 1 }}-circle
+
+ mdi-numeric-{{ index + 1 }}-circle
+
第 {{ index + 1 }} 科目
-
+
- 上移
+
+ 上移
+
- 下移
+
+ 下移
+
- 删除
+
+ 删除
+
-
+
-
+
-
+
{{ customSubjectInput }}
-
+
-
+
-
+
-
+
mdi-calendar-clock
- mdi-clock-start
+
+ mdi-clock-start
+
选择开始时间
-
+
+ />
+ />
-
+
-
+
-
+
-
+
mdi-calendar-clock
- mdi-clock-end
+
+ mdi-clock-end
+
选择结束时间
-
+
+ />
+ />
-
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
mdi-calendar-blank
-
暂无考试科目安排
+
+ 暂无考试科目安排
+
点击上方"添加科目"按钮开始配置
@@ -695,10 +870,18 @@
-
+
- mdi-delete-alert
+
+ mdi-delete-alert
+
确认删除配置
@@ -706,7 +889,7 @@
此操作不可撤销,将会删除所有相关数据
-
+
-
+
-
+
-
+
复制到今天
+ >
+ 复制到今天
+
diff --git a/src/components/GlobalMessage.vue b/src/components/GlobalMessage.vue
index 73518f5..57d7649 100644
--- a/src/components/GlobalMessage.vue
+++ b/src/components/GlobalMessage.vue
@@ -8,14 +8,28 @@
variant="tonal"
>
-
+
-
{{ message?.title }}
-
{{ message?.content }}
+
+ {{ message?.title }}
+
+
+ {{ message?.content }}
+
-
+
diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue
index 79b3ce0..0fc7f78 100644
--- a/src/components/HelloWorld.vue
+++ b/src/components/HelloWorld.vue
@@ -11,12 +11,16 @@
/>
-
Welcome to
+
+ Welcome to
+
-
Vuetify
+
+ Vuetify
+
-
+
@@ -29,17 +33,20 @@
variant="outlined"
>
-
+
- Get started
+
+ Get started
+
Replace this page by removing
-
{{ `
+
+ {{ `
` }}
diff --git a/src/components/HitokotoSettings.vue b/src/components/HitokotoSettings.vue
index 2bce7af..839a2cd 100644
--- a/src/components/HitokotoSettings.vue
+++ b/src/components/HitokotoSettings.vue
@@ -1,15 +1,26 @@
-
+
-
- 以下配置将同步到云端,对所有连接此班级的设备生效。
+
+
+ 以下配置将同步到云端,对所有连接此班级的设备生效。
+
- 启用数据源
+
+ 启用数据源
+
- mdi-alert
+
+ mdi-alert
+
一言(Hitokoto)数据源已收到关于存在负面内容的大量反馈,请用户谨慎启用。
- 一言句子类型
- 不选则返回所有类型;可多选。
+
+ 一言句子类型
+
+
+ 不选则返回所有类型;可多选。
+
- 已启用的数据源将在获取一言时随机尝试,直到成功获取内容为止。
- 敏感词过滤会将包含任意敏感词的句子过滤掉,避免显示不当内容。
+ 已启用的数据源将在获取一言时随机尝试,直到成功获取内容为止。
+ 敏感词过滤会将包含任意敏感词的句子过滤掉,避免显示不当内容。
-
+
-
-
+
+
正在同步配置...
-
-
-
-
+
+
-
+
-
-
+
+
- Token
-
+
+ Token
+
+
{{ testResultData.data.token }}
@@ -160,20 +204,36 @@
-
-
+
+
- IP 地址
- {{ testResultData.data.ip }}
+
+ IP 地址
+
+
+ {{ testResultData.data.ip }}
+
-
-
+
+
- 地区
- {{ testResultData.data.region }}
+
+ 地区
+
+
+ {{ testResultData.data.region }}
+
@@ -184,59 +244,123 @@
-
+
-
+
-
温度
-
{{ testResultData.data.weatherData.temperature }}°C
+
+ 温度
+
+
+ {{ testResultData.data.weatherData.temperature }}°C
+
-
+
-
+
-
天气
-
{{ testResultData.data.weatherData.weather }}
+
+ 天气
+
+
+ {{ testResultData.data.weatherData.weather }}
+
-
+
-
+
-
湿度
-
{{ testResultData.data.weatherData.humidity }}%
+
+ 湿度
+
+
+ {{ testResultData.data.weatherData.humidity }}%
+
-
+
-
+
-
风向/风力
+
+ 风向/风力
+
{{ testResultData.data.weatherData.windDirection }} {{ testResultData.data.weatherData.windPower }}级
-
+
-
+
-
PM2.5
-
{{ testResultData.data.weatherData.pm25 }}
+
+ PM2.5
+
+
+ {{ testResultData.data.weatherData.pm25 }}
+
-
+
-
+
-
能见度
-
{{ testResultData.data.weatherData.visibility }}
+
+ 能见度
+
+
+ {{ testResultData.data.weatherData.visibility }}
+
@@ -246,7 +370,9 @@
-
环境标签
+
+ 环境标签
+
-
-
+
+
北京时间: {{ new Date(testResultData.data.beijingTime).toLocaleString() }}
@@ -273,8 +403,6 @@
-
-
diff --git a/src/components/HomeworkEditDialog.vue b/src/components/HomeworkEditDialog.vue
index 8d5ec17..3b1bbba 100644
--- a/src/components/HomeworkEditDialog.vue
+++ b/src/components/HomeworkEditDialog.vue
@@ -11,7 +11,11 @@
{{ title }}
-
+
{{ autoSave ? autoSavePromptText : manualSavePromptText }}
@@ -31,13 +35,21 @@
/>
-