fix: 修复设备管理页面前后端分页混合导致的数据闪烁问题

- 移除 append/loadMore 模式,改为纯后端分页
- 删除前端 slice useEffect,翻页时只调用后端请求
- 清理 loadMoreRef/hasMoreRef/deviceLoadingMore 等无用变量
- 删除 currentPageDevices state,allDevices 即当前页数据
This commit is contained in:
zhang96110
2026-04-01 07:44:57 +00:00
parent de7da77c11
commit 00cdd481d4
+14 -118
View File
@@ -118,7 +118,6 @@ function DeviceManagement() {
const [batchStatusLoading, setBatchStatusLoading] = useState(false);
const [exportModalVisible, setExportModalVisible] = useState(false);
const [currentPageDevices, setCurrentPageDevices] = useState([]);
const [selectedDevices, setSelectedDevices] = useState([]);
const [selectAll, setSelectAll] = useState(false);
@@ -127,19 +126,10 @@ function DeviceManagement() {
const debouncedKeyword = useDebounce(keyword, DEBOUNCE_DELAY);
const loadMoreRef = useRef(null);
const hasMoreRef = useRef(true);
const isLoadingRef = useRef(false);
const [deviceLoadingMore, setDeviceLoadingMore] = useState(false);
const fetchDevices = useCallback(
async (page = 1, pageSize = 50, append = false) => {
async (page = 1, pageSize = 50) => {
try {
if (append) {
setDeviceLoadingMore(true);
} else {
setLoading(true);
}
setLoading(true);
const params = {
page,
@@ -155,20 +145,13 @@ function DeviceManagement() {
const { devices: deviceList, total } = response.data;
const processedDevices = deviceList.map(processDeviceData);
if (append) {
setAllDevices(prev => [...prev, ...processedDevices]);
} else {
setAllDevices(processedDevices);
}
setAllDevices(processedDevices);
setPagination(prev => ({ ...prev, current: page, pageSize, total }));
hasMoreRef.current = page * pageSize < total;
} catch (error) {
message.error('获取设备列表失败');
console.error('获取设备列表失败:', error);
} finally {
setLoading(false);
setDeviceLoadingMore(false);
}
},
[debouncedKeyword, status, type, roomId, rackId]
@@ -260,72 +243,6 @@ function DeviceManagement() {
}
}, [searchParams, setSearchParams]);
useEffect(() => {
if (allDevices.length > 0) {
const start = (pagination.current - 1) * pagination.pageSize;
const end = start + pagination.pageSize;
const currentPageData = allDevices.slice(start, end);
setCurrentPageDevices(currentPageData);
} else {
setCurrentPageDevices([]);
}
}, [allDevices, pagination.current, pagination.pageSize]);
const handleLoadMoreDevices = useCallback(() => {
if (!hasMoreRef.current || isLoadingRef.current || deviceLoadingMore) return;
if (
debouncedKeyword ||
status !== 'all' ||
type !== 'all' ||
roomId !== 'all' ||
rackId !== 'all'
) {
return;
}
isLoadingRef.current = true;
const nextPage = pagination.current + 1;
fetchDevices(nextPage, pagination.pageSize, true).then(() => {
isLoadingRef.current = false;
});
}, [
pagination.current,
pagination.pageSize,
debouncedKeyword,
status,
type,
roomId,
rackId,
deviceLoadingMore,
fetchDevices,
]);
useEffect(() => {
if (!loadMoreRef.current) return;
const observer = new IntersectionObserver(
entries => {
if (entries[0].isIntersecting && hasMoreRef.current && !deviceLoadingMore) {
if (
!debouncedKeyword &&
status === 'all' &&
type === 'all' &&
roomId === 'all' &&
rackId === 'all'
) {
handleLoadMoreDevices();
}
}
},
{ threshold: 0.1, rootMargin: '100px' }
);
observer.observe(loadMoreRef.current);
return () => {
observer.disconnect();
};
}, [handleLoadMoreDevices, deviceLoadingMore, debouncedKeyword, status, type, roomId, rackId]);
const showModal = (device = null) => {
setEditingDevice(device);
setModalVisible(true);
@@ -347,7 +264,7 @@ function DeviceManagement() {
}
setModalVisible(false);
fetchDevices(1, pagination.pageSize, false);
fetchDevices(1, pagination.pageSize);
setEditingDevice(null);
} catch (error) {
const errorMsg = error.response?.data?.error || error.message || '未知错误';
@@ -385,13 +302,7 @@ function DeviceManagement() {
const handleTableChange = newPagination => {
setPagination(newPagination);
const start = (newPagination.current - 1) * newPagination.pageSize;
const end = start + newPagination.pageSize;
const currentPageData = allDevices.slice(start, end);
setCurrentPageDevices(currentPageData);
fetchDevices(newPagination.current, newPagination.pageSize, false);
fetchDevices(newPagination.current, newPagination.pageSize);
};
const handleBatchDelete = async () => {
@@ -409,7 +320,7 @@ function DeviceManagement() {
message.success(response.data.message || '批量删除成功');
setSelectedDevices([]);
setSelectAll(false);
fetchDevices(1, 50, false);
fetchDevices(1, 50);
} catch (error) {
message.error('批量删除失败');
console.error('批量删除设备失败:', error);
@@ -436,7 +347,7 @@ function DeviceManagement() {
message.success(response.data.message || '成功删除所有设备');
setSelectedDevices([]);
setSelectAll(false);
fetchDevices(1, 50, false);
fetchDevices(1, 50);
} catch (error) {
message.error('删除所有设备失败');
console.error('删除所有设备失败:', error);
@@ -464,7 +375,7 @@ function DeviceManagement() {
message.success(response.data.message || '设备已标记为空闲');
setSelectedDevices([]);
setSelectAll(false);
fetchDevices(1, 50, false);
fetchDevices(1, 50);
} catch (error) {
message.error(error.response?.data?.error || '标记为空闲失败');
console.error('标记为空闲失败:', error);
@@ -484,7 +395,7 @@ function DeviceManagement() {
try {
await axios.delete(`/api/devices/${deviceId}`);
message.success('设备删除成功');
fetchDevices(1, pagination.pageSize, false);
fetchDevices(1, pagination.pageSize);
} catch (error) {
message.error('设备删除失败');
console.error('设备删除失败:', error);
@@ -530,7 +441,7 @@ function DeviceManagement() {
setBatchStatusModalVisible(false);
setSelectedDevices([]);
setSelectAll(false);
fetchDevices(1, pagination.pageSize, false);
fetchDevices(1, pagination.pageSize);
} catch (error) {
message.error('批量状态变更失败');
console.error('批量状态变更失败:', error);
@@ -552,7 +463,7 @@ function DeviceManagement() {
if (scope === 'selected') {
deviceIds = selectedDevices;
} else if (scope === 'currentPage') {
deviceIds = currentPageDevices.map(device => device.deviceId);
deviceIds = allDevices.map(device => device.deviceId);
} else if (scope === 'all') {
deviceIds = allDevices.map(device => device.deviceId);
}
@@ -621,7 +532,7 @@ function DeviceManagement() {
}
setTimeout(() => {
fetchDevices(1, pagination.pageSize, false);
fetchDevices(1, pagination.pageSize);
}, 1000);
} catch (error) {
let errorMessage = '导入失败';
@@ -1153,7 +1064,7 @@ function DeviceManagement() {
</Space>
<Button
icon={<ReloadOutlined />}
onClick={() => fetchDevices(1, pagination.pageSize, false)}
onClick={() => fetchDevices(1, pagination.pageSize)}
style={{
borderRadius: designTokens.borderRadius.medium,
border: `1px solid ${designTokens.colors.border.light}`,
@@ -1345,21 +1256,6 @@ function DeviceManagement() {
return index % 2 === 0 ? 'ant-table-row-even' : 'ant-table-row-odd';
}}
/>
{hasMoreRef.current &&
!debouncedKeyword &&
status === 'all' &&
type === 'all' &&
roomId === 'all' &&
rackId === 'all' && (
<div ref={loadMoreRef} style={{ textAlign: 'center', padding: '20px' }}>
{deviceLoadingMore && <Spin tip="加载更多设备..." />}
</div>
)}
{!hasMoreRef.current && allDevices.length > 0 && (
<div style={{ textAlign: 'center', padding: '16px', color: '#999' }}>
已加载全部 {pagination.total} 个设备
</div>
)}
</div>
)}
</Card>
@@ -1397,7 +1293,7 @@ function DeviceManagement() {
<ExportModal
visible={exportModalVisible}
selectedDevices={selectedDevices}
currentPageDevices={currentPageDevices}
currentPageDevices={allDevices}
allDevices={allDevices}
onExport={handleEnhancedExport}
onCancel={() => setExportModalVisible(false)}