const VERSION = '1.0.0' // Build Time: 2026-01-07 15:59:36 const CACHE_NAME = `emailbill-${VERSION}` const urlsToCache = [ '/', '/index.html', '/favicon.ico', '/manifest.json' ] // 安装 Service Worker self.addEventListener('install', (event) => { console.log('[Service Worker] 安装中...') event.waitUntil( caches.open(CACHE_NAME) .then((cache) => { console.log('[Service Worker] 缓存文件') return cache.addAll(urlsToCache) }) ) }) // 监听跳过等待消息 self.addEventListener('message', (event) => { if (event.data && event.data.type === 'SKIP_WAITING') { self.skipWaiting() } }) // 激活 Service Worker self.addEventListener('activate', (event) => { console.log('[Service Worker] 激活中...') event.waitUntil( caches.keys().then((cacheNames) => { return Promise.all( cacheNames.map((cacheName) => { if (cacheName !== CACHE_NAME) { console.log('[Service Worker] 删除旧缓存:', cacheName) return caches.delete(cacheName) } }) ) }).then(() => self.clients.claim()) ) }) // 拦截请求 self.addEventListener('fetch', (event) => { const { request } = event const url = new URL(request.url) // 跳过跨域请求 if (url.origin !== location.origin) { return } // API请求使用网络优先策略 if (url.pathname.startsWith('/api/')) { event.respondWith( fetch(request) .then((response) => { // 只针对成功的GET请求进行缓存 if (request.method === 'GET' && response.status === 200) { const responseClone = response.clone() caches.open(CACHE_NAME).then((cache) => { cache.put(request, responseClone) }) } return response }) .catch(() => { // 网络失败时尝试从缓存获取 return caches.match(request) }) ) return } // 页面请求使用网络优先策略,确保能获取到最新的 index.html if (request.mode === 'navigate') { event.respondWith( fetch(request) .then((response) => { const responseClone = response.clone() caches.open(CACHE_NAME).then((cache) => { cache.put(request, responseClone) }) return response }) .catch(() => { return caches.match('/index.html') || caches.match(request) }) ) return } // 其他静态资源使用缓存优先策略 event.respondWith( caches.match(request) .then((response) => { if (response) { return response } return fetch(request).then((response) => { // 检查是否是有效响应 if (!response || response.status !== 200 || response.type !== 'basic') { return response } const responseClone = response.clone() caches.open(CACHE_NAME).then((cache) => { cache.put(request, responseClone) }) return response }) }) .catch(() => { // 返回离线页面或默认内容 if (request.destination === 'document') { return caches.match('/index.html') } }) ) }) // 后台同步 self.addEventListener('sync', (event) => { console.log('[Service Worker] 后台同步:', event.tag) if (event.tag === 'sync-data') { event.waitUntil(syncData()) } }) // 推送通知 self.addEventListener('push', (event) => { console.log('[Service Worker] 收到推送消息') let data = { title: '账单管理', body: '您有新的消息', url: '/', icon: '/icons/icon-192x192.png' } if (event.data) { try { const json = event.data.json() data = { ...data, ...json } } catch { data.body = event.data.text() } } const options = { body: data.body, icon: data.icon, badge: '/icons/icon-72x72.png', vibrate: [200, 100, 200], tag: 'emailbill-notification', requireInteraction: false, data: { url: data.url } } event.waitUntil( self.registration.showNotification(data.title, options) ) }) // 通知点击 self.addEventListener('notificationclick', (event) => { console.log('[Service Worker] 通知被点击') event.notification.close() const urlToOpen = event.notification.data?.url || '/' event.waitUntil( clients.matchAll({ type: 'window', includeUncontrolled: true }).then((windowClients) => { // 如果已经打开了该 URL,则聚焦 for (let i = 0; i < windowClients.length; i++) { const client = windowClients[i] if (client.url === urlToOpen && 'focus' in client) { return client.focus() } } // 否则打开新窗口 if (clients.openWindow) { return clients.openWindow(urlToOpen) } }) ) }) // 数据同步函数 async function syncData () { try { // 这里添加需要同步的逻辑 console.log('[Service Worker] 执行数据同步') } catch (error) { console.error('[Service Worker] 同步失败:', error) } }