fix: 修复设备管理页面前后端分页混合导致的数据闪烁问题
- 移除 append/loadMore 模式,改为纯后端分页 - 删除前端 slice useEffect,翻页时只调用后端请求 - 清理 loadMoreRef/hasMoreRef/deviceLoadingMore 等无用变量 - 删除 currentPageDevices state,allDevices 即当前页数据
This commit is contained in:
@@ -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)}
|
||||
|
||||
Reference in New Issue
Block a user