diff --git a/eslint.config.js b/eslint.config.js
index 944e82b..837b651 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -16,6 +16,29 @@ export default [
...pluginVue.configs['flat/recommended'],
{
+ languageOptions: {
+ globals: {
+ window: 'readonly',
+ document: 'readonly',
+ navigator: 'readonly',
+ location: 'readonly',
+ localStorage: 'readonly',
+ URL: 'readonly',
+ URLSearchParams: 'readonly',
+ CSS: 'readonly',
+ Notification: 'readonly',
+ requestAnimationFrame: 'readonly',
+ setTimeout: 'readonly',
+ clearTimeout: 'readonly',
+ setInterval: 'readonly',
+ clearInterval: 'readonly',
+ console: 'readonly',
+ require: 'readonly',
+ self: 'readonly',
+ caches: 'readonly',
+ Blob: 'readonly',
+ },
+ },
rules: {
'vue/multi-word-component-names': 'off',
},
diff --git a/src/components/settings/cards/DisplaySettingsCard.vue b/src/components/settings/cards/DisplaySettingsCard.vue
index b8bb090..ff168ee 100644
--- a/src/components/settings/cards/DisplaySettingsCard.vue
+++ b/src/components/settings/cards/DisplaySettingsCard.vue
@@ -19,6 +19,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/index.vue b/src/pages/index.vue
index a674d50..5d5608d 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -1,4 +1,16 @@
+
+
{{ titleText }}
@@ -657,6 +669,48 @@ export default {
return `${deviceName} - ${currentDateStr}的作业`;
}
},
+ hasBackgroundImage() {
+ return !!this.backgroundImageUrl;
+ },
+ backgroundImageUrl() {
+ void this.settingsTick;
+ return (getSetting("display.backgroundImage") || "").trim();
+ },
+ backgroundBlurAmount() {
+ void this.settingsTick;
+ const value = Number(getSetting("display.backgroundBlur"));
+ return Number.isFinite(value) ? value : 0;
+ },
+ backgroundDimAmount() {
+ void this.settingsTick;
+ const value = Number(getSetting("display.backgroundDim"));
+ return Number.isFinite(value) ? value : 0;
+ },
+ backgroundImageStyle() {
+ const url = this.backgroundImageUrl;
+ if (!this.isSafeBackgroundUrl(url)) return { display: "none" };
+ const safeUrl = this.sanitizeBackgroundUrl(url);
+ if (!safeUrl) return { display: "none" };
+
+ const blur = Math.min(Math.max(this.backgroundBlurAmount, 0), 50);
+ const escaped = this.cssEscape(safeUrl);
+ return {
+ backgroundImage: `url("${escaped}")`,
+ filter: `blur(${blur}px)`,
+ };
+ },
+ backgroundOverlayStyle() {
+ if (!this.hasBackgroundImage) return { display: "none" };
+
+ const dim = Math.min(Math.max(this.backgroundDimAmount, 0), 90);
+ // Slightly reduce overlay blur to avoid overwhelming foreground
+ const overlayBlur =
+ Math.min(Math.max(this.backgroundBlurAmount, 0), 50) / 3;
+ return {
+ backgroundColor: `rgba(0, 0, 0, ${dim / 100})`,
+ backdropFilter: `blur(${overlayBlur}px)`,
+ };
+ },
sortedItems() {
const items = [];
@@ -2156,6 +2210,36 @@ export default {
return nameMap[lastPart] || lastPart;
},
+ isSafeBackgroundUrl(url) {
+ if (!url) return false;
+ const trimmed = url.trim();
+ if (/^(javascript|data|vbscript):/i.test(trimmed)) return false;
+
+ try {
+ const parsed = new URL(trimmed, window.location.origin);
+ const protocol = parsed.protocol.replace(":", "");
+ if (!["http", "https"].includes(protocol)) return false;
+ if (parsed.pathname.includes("..")) return false;
+ return true;
+ } catch (e) {
+ return false;
+ }
+ },
+ sanitizeBackgroundUrl(url) {
+ if (!this.isSafeBackgroundUrl(url)) return "";
+ try {
+ const parsed = new URL(url, window.location.origin);
+ return parsed.href;
+ } catch (e) {
+ return "";
+ }
+ },
+ cssEscape(value) {
+ if (typeof CSS !== "undefined" && CSS.escape) {
+ return CSS.escape(value);
+ }
+ return encodeURI(value);
+ },
safeBase64Decode(base64String) {
try {
@@ -2353,3 +2437,20 @@ export default {
},
};
+
+
diff --git a/src/pages/settings.vue b/src/pages/settings.vue
index cebe40e..711aa8d 100644
--- a/src/pages/settings.vue
+++ b/src/pages/settings.vue
@@ -305,8 +305,6 @@ export default {
return {isMobile: mobile};
},
data() {
- const provider = getSetting("server.provider");
-
const settings = {
server: {
domain: getSetting("server.domain"),
diff --git a/src/pages/socket-debugger.vue b/src/pages/socket-debugger.vue
index 1e1f288..d236a8f 100644
--- a/src/pages/socket-debugger.vue
+++ b/src/pages/socket-debugger.vue
@@ -339,7 +339,7 @@