feat: 本次提交更新内容如下

场景获客列表搞定
This commit is contained in:
笔记本里的永平
2025-07-07 17:08:27 +08:00
parent 6543da9167
commit 5ff15472f5
352 changed files with 24040 additions and 18575 deletions

View File

@@ -1,6 +1,6 @@
"use client"
import { useState, useEffect, useRef } from "react"
import { useState, useEffect } from "react"
import type { Device } from "@/components/device-grid"
interface DeviceStatus {
@@ -25,82 +25,22 @@ async function fetchDeviceStatuses(deviceIds: string[]): Promise<Record<string,
export function useDeviceStatusPolling(devices: Device[]) {
const [statuses, setStatuses] = useState<Record<string, DeviceStatus>>({})
// 使用ref跟踪上一次的设备ID列表
const prevDeviceIdsRef = useRef<string[]>([]);
// 使用ref跟踪组件挂载状态
const isMounted = useRef(true);
// 记录轮询错误次数,用于实现退避策略
const errorCountRef = useRef(0);
// 检查设备列表是否有实质性变化
const hasDevicesChanged = (prevIds: string[], currentIds: string[]): boolean => {
if (prevIds.length !== currentIds.length) return true;
// 使用Set检查两个数组是否包含相同的元素
const prevSet = new Set(prevIds);
return currentIds.some(id => !prevSet.has(id));
};
useEffect(() => {
// 重置组件挂载状态
isMounted.current = true;
// 获取当前设备ID列表
const deviceIds = devices.map(d => d.id);
// 检查设备列表是否有变化
const deviceListChanged = hasDevicesChanged(prevDeviceIdsRef.current, deviceIds);
// 更新设备ID引用
prevDeviceIdsRef.current = deviceIds;
const pollStatus = async () => {
try {
const newStatuses = await fetchDeviceStatuses(devices.map((d) => d.id))
// 确保组件仍然挂载
if (isMounted.current) {
setStatuses((prevStatuses) => ({ ...prevStatuses, ...newStatuses }))
// 重置错误计数
errorCountRef.current = 0;
}
setStatuses((prevStatuses) => ({ ...prevStatuses, ...newStatuses }))
} catch (error) {
console.error("Failed to fetch device statuses:", error)
// 增加错误计数
errorCountRef.current += 1;
}
}
// 仅当设备列表有变化或初始加载时才立即执行一次
if (deviceListChanged || Object.keys(statuses).length === 0) {
pollStatus();
}
// 使用基于错误次数的指数退避策略
const getPollingInterval = () => {
const baseInterval = 30000; // 基础间隔 30 秒
const maxInterval = 2 * 60 * 1000; // 最大间隔 2 分钟
if (errorCountRef.current === 0) return baseInterval;
// 计算指数退避间隔,但不超过最大间隔
const backoffInterval = Math.min(
baseInterval * Math.pow(1.5, Math.min(errorCountRef.current, 5)),
maxInterval
);
return backoffInterval;
};
// 设置轮询间隔
const intervalId = setInterval(pollStatus, getPollingInterval());
pollStatus() // 立即执行一次
const intervalId = setInterval(pollStatus, 30000) // 每30秒更新一次
// 清理函数
return () => {
isMounted.current = false;
clearInterval(intervalId)
}
return () => clearInterval(intervalId)
}, [devices])
return statuses
}