Files
aiagent/frontend/public/sw.js

109 lines
3.3 KiB
JavaScript
Raw Permalink Normal View History

/**
* 天工智能体平台 — Service Worker
*
* - 离线缓存:静态资源 + API 响应
* - 推送通知
* - 安装后激活
*/
const CACHE_NAME = 'aiagent-v1.0.0';
const RUNTIME_CACHE = 'aiagent-runtime';
const PRECACHE_URLS = [
'/',
'/index.html',
'/manifest.json',
];
// ─── Install: 预缓存关键资源 ───────────────────────────────────
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(PRECACHE_URLS);
}).then(() => self.skipWaiting())
);
});
// ─── Activate: 清理旧缓存 ──────────────────────────────────────
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((names) => {
return Promise.all(
names
.filter((n) => n !== CACHE_NAME && n !== RUNTIME_CACHE)
.map((n) => caches.delete(n))
);
}).then(() => self.clients.claim())
);
});
// ─── Fetch: 网络优先 + 缓存回退 ────────────────────────────────
self.addEventListener('fetch', (event) => {
const { request } = event;
if (request.method !== 'GET') return;
// API 请求:网络优先
if (request.url.includes('/api/')) {
event.respondWith(
fetch(request)
.then((response) => {
const clone = response.clone();
caches.open(RUNTIME_CACHE).then((cache) => {
cache.put(request, clone);
});
return response;
})
.catch(() => caches.match(request))
);
return;
}
// 静态资源:缓存优先
event.respondWith(
caches.match(request).then((cached) => {
const fetched = fetch(request).then((response) => {
const clone = response.clone();
caches.open(RUNTIME_CACHE).then((cache) => {
cache.put(request, clone);
});
return response;
});
return cached || fetched;
})
);
});
// ─── Push: 浏览器推送通知 ──────────────────────────────────────
self.addEventListener('push', (event) => {
if (!event.data) return;
const data = event.data.json().catch(() => ({ title: '天工智能体', body: event.data.text() }));
const options = {
body: data.body || '',
icon: '/icons/icon-192.png',
badge: '/icons/icon-192.png',
data: data.data || {},
vibrate: [200, 100, 200],
requireInteraction: data.requireInteraction || false,
};
event.waitUntil(
self.registration.showNotification(data.title || '天工智能体', options)
);
});
// ─── Notification Click ─────────────────────────────────────────
self.addEventListener('notificationclick', (event) => {
event.notification.close();
const url = event.notification.data?.url || '/';
event.waitUntil(
self.clients.matchAll({ type: 'window' }).then((clients) => {
for (const client of clients) {
if (client.url.includes(url) && 'focus' in client) {
return client.focus();
}
}
return self.clients.openWindow(url);
})
);
});