203 lines
5.2 KiB
Plaintext
203 lines
5.2 KiB
Plaintext
/**
|
||
* 事件轮询 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<void> {
|
||
// 未登录不轮询
|
||
// 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
|
||
}
|