/** * 事件轮询 Hook * * 全局事件轮询逻辑,与 PC 端 useEventPolling.ts 功能一致 * 适配 uni-app x 框架,使用 setInterval 实现轮询 * 使用 eventBus 封装层发布事件(内部基于 uni.$emit) * * 自动处理的场景: * - H5:页面切换到后台(visibilitychange)或切换标签页时暂停,回来后恢复 * - 小程序:需要在 App.uvue 的 onHide/onShow 中手动调用 stop/start * * 使用方式: * - 在 App.uvue 的 onLaunch 中调用 initEventPolling() 初始化 * - 在 App.uvue 的 onHide 中调用 stopEventPolling()(小程序需要) * - 在 App.uvue 的 onShow 中调用 startEventPolling()(小程序需要) * * 订阅事件: * - eventBus.on(EVENT_TYPE.RefreshFileList, handler) * - eventBus.off(EVENT_TYPE.RefreshFileList, handler) */ import { apiCollectEvent, apiClearEvent, ApiCollectEventResponse } from '@/servers/event'; import eventBus from '@/utils/eventBus'; import { SUCCESS_CODE } from '@/constants/codes.constants'; import { ACCESS_TOKEN } from '@/constants/home.constants'; // 轮询间隔(毫秒) const POLLING_INTERVAL = 5000; // 轮询定时器 ID let pollingTimerId: number | null = null; // 是否正在处理事件(避免并发处理) let isProcessing = false; // 是否已初始化 H5 可见性监听 let isVisibilityListenerInitialized = false; // 是否已登录(未登录不轮询) // function isLoggedIn(): boolean { // const token = uni.getStorageSync(ACCESS_TOKEN); // return !!token; // } /** * 执行一次轮询 */ async function pollOnce(): Promise { // 未登录不轮询 // if (!isLoggedIn()) { // return; // } // 如果正在处理,跳过本次 if (isProcessing) { console.log('[EventPolling] 跳过重复的事件处理'); return; } try { const response = await apiCollectEvent(); const data = response as any; // 检查响应是否有效 if (!data || data.code !== SUCCESS_CODE) { return; } const result: ApiCollectEventResponse = data.data; // 如果有事件需要处理 if (result?.hasEvent && result?.eventList?.length > 0) { try { // 标记开始处理 isProcessing = true; // 暂停轮询 stopEventPolling(); // 遍历所有事件,使用 eventBus 发布事件 for (const event of result.eventList) { // console.log('[EventPolling] 发布事件:', event.type, event.event); eventBus.emit(event.type, event.event); } // 清除已处理的事件 await apiClearEvent(); } catch (error) { console.error('[EventPolling] 处理事件时出错:', error); } finally { // 重新开始轮询 startEventPolling(); // 处理完成 isProcessing = false; } } } catch (error) { console.error('[EventPolling] 轮询请求失败:', error); } } /** * 处理 H5 页面可见性变化 * 切换标签页或最小化时暂停轮询,回来后恢复 */ function handleVisibilityChange(): void { // #ifdef H5 || WEB if (document.hidden) { console.log('[EventPolling] H5 页面不可见,暂停轮询'); stopEventPolling(); } else { console.log('[EventPolling] H5 页面可见,恢复轮询'); startEventPolling(); } // #endif } /** * 初始化 H5 可见性监听 */ function initVisibilityListener(): void { // #ifdef H5 || WEB if (isVisibilityListenerInitialized) { return; } document.addEventListener('visibilitychange', handleVisibilityChange); isVisibilityListenerInitialized = true; console.log('[EventPolling] H5 可见性监听已初始化'); // #endif } /** * 初始化事件轮询(在 App.uvue onLaunch 中调用) * - H5:自动监听 visibilitychange,自动处理暂停/恢复 * - 小程序:需要在 onHide/onShow 中手动调用 stop/start */ export function initEventPolling(): void { // 初始化 H5 可见性监听 initVisibilityListener(); // 启动轮询 startEventPolling(); } /** * 启动事件轮询 */ export function startEventPolling(): void { // 如果已经在轮询,不重复启动 if (pollingTimerId !== null) { return; } // 未登录不启动 // if (!isLoggedIn()) { // console.log('[EventPolling] 未登录,跳过启动轮询'); // return; // } console.log('[EventPolling] 启动事件轮询'); // 立即执行一次 pollOnce(); // 设置定时轮询 pollingTimerId = setInterval(() => { pollOnce(); }, POLLING_INTERVAL) as unknown as number; } /** * 停止事件轮询 */ export function stopEventPolling(): void { if (pollingTimerId !== null) { console.log('[EventPolling] 停止事件轮询'); clearInterval(pollingTimerId); pollingTimerId = null; } } /** * 检查轮询状态 */ export function isPollingActive(): boolean { return pollingTimerId !== null; } /** * 销毁事件轮询(移除监听器) */ export function destroyEventPolling(): void { stopEventPolling(); // #ifdef H5 || WEB if (isVisibilityListenerInitialized) { document.removeEventListener('visibilitychange', handleVisibilityChange); isVisibilityListenerInitialized = false; console.log('[EventPolling] H5 可见性监听已移除'); } // #endif }