Files
EmailBill/Web/public/service-worker.js
孙诚 e250a7df2f
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 40s
Docker Build & Deploy / Deploy to Production (push) Successful in 8s
feat: 添加推送通知功能,支持订阅和发送通知
2026-01-02 12:25:44 +08:00

167 lines
4.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const CACHE_NAME = 'emailbill-v1';
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);
})
.then(() => 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) => {
// 克隆响应以便缓存
const responseClone = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(request, responseClone);
});
return response;
})
.catch(() => {
// 网络失败时尝试从缓存获取
return 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 (e) {
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);
}
}