Files
qiming/qiming-mobile/hooks/useEventPolling.uts

203 lines
5.2 KiB
Plaintext
Raw Permalink 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.
/**
* 事件轮询 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
}