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'))