diff --git a/index.html b/index.html
index 286dd6ea..f05de863 100644
--- a/index.html
+++ b/index.html
@@ -193,6 +193,35 @@
transform: rotate(1turn);
}
}
+
+ /* 超时通知样式 */
+ #loading-timeout {
+ position: absolute;
+ z-index: 2500;
+ display: none;
+ inset-block-end: 20px;
+ inset-inline-start: 50%;
+ transform: translateX(-50%);
+ background: rgba(0, 0, 0, 0.8);
+ color: #fff;
+ padding: 12px 24px;
+ border-radius: 12px;
+ font-size: 14px;
+ font-family: sans-serif;
+ text-align: center;
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
+ white-space: nowrap;
+ backdrop-filter: blur(4px);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ }
+
+ #timeout-btn {
+ color: var(--initial-loader-color, #9155FD);
+ text-decoration: none;
+ font-weight: bold;
+ margin-inline-start: 8px;
+ border-bottom: 1px solid var(--initial-loader-color, #9155FD);
+ }
@@ -257,6 +318,10 @@
+
+
diff --git a/src/App.vue b/src/App.vue
index bb42aec2..af9b50fa 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -15,7 +15,7 @@ import { themeManager } from '@/utils/themeManager'
// 生效主题
const { global: globalTheme } = useTheme()
-let themeValue = localStorage.getItem('theme') || 'light'
+let themeValue = localStorage.getItem('theme') || 'auto'
const autoTheme = checkPrefersColorSchemeIsDark() ? 'dark' : 'light'
globalTheme.name.value = themeValue === 'auto' ? autoTheme : themeValue
@@ -239,8 +239,8 @@ async function loadBackgroundImages(retryCount = 0) {
onMounted(async () => {
// 移除URL中的时间戳参数
const url = new URL(window.location.href)
- if (url.searchParams.has('t')) {
- url.searchParams.delete('t')
+ if (url.searchParams.has('_t')) {
+ url.searchParams.delete('_t')
window.history.replaceState({}, '', url.toString())
}
diff --git a/src/composables/useVersionChecker.ts b/src/composables/useVersionChecker.ts
index edc3d486..80e448d6 100644
--- a/src/composables/useVersionChecker.ts
+++ b/src/composables/useVersionChecker.ts
@@ -18,8 +18,8 @@ const needsUpdate = computed(() => {
*/
export const reloadWithTimestamp = (): void => {
const url = new URL(window.location.href)
- url.searchParams.set('t', Date.now().toString())
- window.location.href = url.toString()
+ url.searchParams.set('_t', Date.now().toString())
+ window.location.replace(url.toString());
}
/**
diff --git a/src/layouts/components/UserProfile.vue b/src/layouts/components/UserProfile.vue
index 80ad008c..b52c6c30 100644
--- a/src/layouts/components/UserProfile.vue
+++ b/src/layouts/components/UserProfile.vue
@@ -272,7 +272,7 @@ const getUIModeIcon = computed(() => {
// 主题相关功能
const { name: themeName, global: globalTheme } = useTheme()
-const savedTheme = ref(localStorage.getItem('theme') ?? themeName)
+const savedTheme = ref(localStorage.getItem('theme') ?? 'auto')
const currentThemeName = ref(savedTheme.value)
const themes: ThemeSwitcherTheme[] = [
diff --git a/src/service-worker.ts b/src/service-worker.ts
index 7217a4ce..d893411e 100644
--- a/src/service-worker.ts
+++ b/src/service-worker.ts
@@ -7,11 +7,13 @@ import * as navigationPreload from 'workbox-navigation-preload'
// Service Worker 类型声明
declare let self: ServiceWorkerGlobalScope & {
- __WB_MANIFEST: Array<{ url: string; revision?: string }>
+ readonly __WB_MANIFEST: Array<{ url: string; revision?: string }>
}
// 缓存版本控制
-const CACHE_VERSION = `${__APP_VERSION__}-${__BUILD_TIME__}`
+const RESOURCE_VERSION = 'V2'
+// 开发环境CACHE_VERSION回退到RESOURCE_VERSION
+const CACHE_VERSION = typeof __APP_VERSION__ !== 'undefined' ? `${__APP_VERSION__}-${__BUILD_TIME__}` : RESOURCE_VERSION
// 启用导航预载
navigationPreload.enable()
@@ -111,7 +113,7 @@ registerRoute(
registerRoute(
({ request }) => request.destination === 'image',
new CacheFirst({
- cacheName: `image-cache-${CACHE_VERSION}`,
+ cacheName: `image-cache-${RESOURCE_VERSION}`,
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
@@ -128,7 +130,7 @@ registerRoute(
registerRoute(
({ request }) => request.destination === 'font',
new CacheFirst({
- cacheName: `font-cache-${CACHE_VERSION}`,
+ cacheName: `font-cache-${RESOURCE_VERSION}`,
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
@@ -145,7 +147,7 @@ registerRoute(
registerRoute(
({ url }) => url.hostname === 'image.tmdb.org',
new CacheFirst({
- cacheName: `tmdb-image-cache-${CACHE_VERSION}`,
+ cacheName: `tmdb-image-cache-${RESOURCE_VERSION}`,
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
@@ -165,7 +167,8 @@ registerRoute(
request.method === 'GET' &&
!url.pathname.includes('/api/v1/system/message') && // 排除 SSE 长连接
!url.pathname.includes('/api/v1/common/message') && // 排除通用消息
- !url.pathname.includes('/api/v1/message/'), // 排除所有消息类接口
+ !url.pathname.includes('/api/v1/message/') && // 排除所有消息类接口
+ !url.pathname.includes('/api/v1/system/global'), // 排除global接口
new NetworkFirst({
cacheName: `api-cache-${CACHE_VERSION}`,
networkTimeoutSeconds: 5,
@@ -201,14 +204,23 @@ async function cleanupRuntimeCaches(onlyOld: boolean = false) {
'font-cache',
'api-cache',
'tmdb-image-cache',
- 'pages-cache',
+ ]
+
+ // 当前版本的缓存全名
+ const currentCacheNames = [
+ `app-shell-${CACHE_VERSION}`,
+ `static-resources-${CACHE_VERSION}`,
+ `image-cache-${RESOURCE_VERSION}`,
+ `font-cache-${RESOURCE_VERSION}`,
+ `tmdb-image-cache-${RESOURCE_VERSION}`,
+ `api-cache-${CACHE_VERSION}`,
]
await Promise.all(
cacheNames.map(cacheName => {
const isRuntimeCache = runtimeCachePrefixes.some(prefix => cacheName.startsWith(prefix))
if (isRuntimeCache) {
- if (!onlyOld || !cacheName.includes(CACHE_VERSION)) {
+ if (!onlyOld || !currentCacheNames.includes(cacheName)) {
console.log('[SW] Deleting runtime cache:', cacheName)
return caches.delete(cacheName)
}
@@ -285,9 +297,9 @@ async function updateBadge(count: number) {
if ('setAppBadge' in self.navigator) {
try {
if (count > 0) {
- await (self.navigator as any).setAppBadge(count)
+ await self.navigator.setAppBadge(count)
} else {
- await (self.navigator as any).clearAppBadge()
+ await self.navigator.clearAppBadge()
}
} catch (error) {
console.error('Failed to update app badge:', error)
@@ -298,7 +310,7 @@ async function updateBadge(count: number) {
async function clearBadge() {
if ('clearAppBadge' in self.navigator) {
try {
- await (self.navigator as any).clearAppBadge()
+ await self.navigator.clearAppBadge()
await setStoredUnreadCount(0)
} catch (error) {
console.error('Failed to clear app badge:', error)
diff --git a/src/views/setting/AccountSettingNotification.vue b/src/views/setting/AccountSettingNotification.vue
index b5de2856..26ba0eff 100644
--- a/src/views/setting/AccountSettingNotification.vue
+++ b/src/views/setting/AccountSettingNotification.vue
@@ -45,7 +45,7 @@ const templateTypes = ref([
// 编辑器主题
const { name: themeName, global: globalTheme } = useTheme()
-const savedTheme = ref(localStorage.getItem('theme') ?? themeName)
+const savedTheme = ref(localStorage.getItem('theme') ?? 'auto')
const currentThemeName = ref(savedTheme.value)
const editorTheme = computed(() => (currentThemeName.value === 'light' ? 'github' : 'monokai'))