feat: 实现实时要闻服务端分页功能
功能新增:
- 实时要闻组件支持服务端分页,每次切换页码重新请求数据
- 分页控制器组件,支持数字页码、上下翻页、快速跳转
- Mock 数据量从 100 条增加到 200 条,支持分页测试
技术实现:
1. Redux 状态管理(communityDataSlice.js)
- fetchDynamicNews 接收分页参数 { page, per_page }
- 返回数据结构调整为 { events, pagination }
- initialState 新增 dynamicNewsPagination 字段
- Reducer 分别存储 events 和 pagination 信息
- Selector 返回完整的 pagination 数据
2. 组件层(index.js → DynamicNewsCard → EventScrollList)
- Community/index.js: 获取并传递 pagination 信息
- DynamicNewsCard.js: 管理分页状态,触发服务端请求
- EventScrollList.js: 接收服务端 totalPages,渲染当前页数据
- 页码切换时自动选中第一个事件
3. 分页控制器(PaginationControl.js)
- 精简版设计:移除首页/末页按钮
- 上一页/下一页按钮,边界状态自动禁用
- 智能页码列表(最多5个,使用省略号)
- 输入框跳转功能,支持回车键
- Toast 提示非法输入
- 全部使用 xs 尺寸,紧凑布局
4. Mock 数据(events.js)
- 总事件数从 100 增加到 200 条
- 支持服务端分页测试(40 页 × 5 条/页)
分页流程:
1. 初始加载:请求 page=1, per_page=5
2. 切换页码:dispatch(fetchDynamicNews({ page: 2, per_page: 5 }))
3. 后端返回:{ events: [5条], pagination: { page, total, total_pages } }
4. 前端更新:显示新页面数据,更新分页控制器状态
UI 优化:
- 紧凑的分页控制器布局
- 移除冗余元素(首页/末页/总页数提示)
- xs 尺寸按钮,减少视觉负担
- 保留核心功能(翻页、页码、跳转)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -159,28 +159,33 @@ export const fetchHotEvents = createAsyncThunk(
|
||||
/**
|
||||
* 获取动态新闻(无缓存,每次都发起请求)
|
||||
* 用于 DynamicNewsCard 组件,需要保持实时性
|
||||
* @param {Object} params - 分页参数 { page, per_page }
|
||||
*/
|
||||
export const fetchDynamicNews = createAsyncThunk(
|
||||
'communityData/fetchDynamicNews',
|
||||
async (_, { rejectWithValue }) => {
|
||||
async ({ page = 1, per_page = 5 } = {}, { rejectWithValue }) => {
|
||||
try {
|
||||
logger.debug('CommunityData', '开始获取动态新闻');
|
||||
logger.debug('CommunityData', '开始获取动态新闻', { page, per_page });
|
||||
const response = await eventService.getEvents({
|
||||
page: 1,
|
||||
per_page: 5,
|
||||
page,
|
||||
per_page,
|
||||
sort: 'new'
|
||||
});
|
||||
|
||||
if (response.success && response.data?.events) {
|
||||
logger.info('CommunityData', '动态新闻加载成功', {
|
||||
count: response.data.events.length,
|
||||
page: response.data.pagination?.page || page,
|
||||
total: response.data.pagination?.total || 0
|
||||
});
|
||||
return response.data.events;
|
||||
return {
|
||||
events: response.data.events,
|
||||
pagination: response.data.pagination || {}
|
||||
};
|
||||
}
|
||||
|
||||
logger.warn('CommunityData', '动态新闻返回数据为空', response);
|
||||
return [];
|
||||
return { events: [], pagination: {} };
|
||||
} catch (error) {
|
||||
logger.error('CommunityData', '获取动态新闻失败', error);
|
||||
return rejectWithValue(error.message || '获取动态新闻失败');
|
||||
@@ -197,6 +202,7 @@ const communityDataSlice = createSlice({
|
||||
popularKeywords: [],
|
||||
hotEvents: [],
|
||||
dynamicNews: [], // 动态新闻(无缓存)
|
||||
dynamicNewsPagination: {}, // 动态新闻分页信息
|
||||
|
||||
// 加载状态
|
||||
loading: {
|
||||
@@ -279,7 +285,24 @@ const communityDataSlice = createSlice({
|
||||
// 使用工厂函数创建 reducers,消除重复代码
|
||||
createDataReducers(builder, fetchPopularKeywords, 'popularKeywords');
|
||||
createDataReducers(builder, fetchHotEvents, 'hotEvents');
|
||||
createDataReducers(builder, fetchDynamicNews, 'dynamicNews');
|
||||
|
||||
// dynamicNews 需要特殊处理(包含 pagination)
|
||||
builder
|
||||
.addCase(fetchDynamicNews.pending, (state) => {
|
||||
state.loading.dynamicNews = true;
|
||||
state.error.dynamicNews = null;
|
||||
})
|
||||
.addCase(fetchDynamicNews.fulfilled, (state, action) => {
|
||||
state.loading.dynamicNews = false;
|
||||
state.dynamicNews = action.payload.events;
|
||||
state.dynamicNewsPagination = action.payload.pagination;
|
||||
state.lastUpdated.dynamicNews = new Date().toISOString();
|
||||
})
|
||||
.addCase(fetchDynamicNews.rejected, (state, action) => {
|
||||
state.loading.dynamicNews = false;
|
||||
state.error.dynamicNews = action.payload;
|
||||
logger.error('CommunityData', 'dynamicNews 加载失败', new Error(action.payload));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -314,6 +337,7 @@ export const selectDynamicNewsWithLoading = (state) => ({
|
||||
data: state.communityData.dynamicNews,
|
||||
loading: state.communityData.loading.dynamicNews,
|
||||
error: state.communityData.error.dynamicNews,
|
||||
pagination: state.communityData.dynamicNewsPagination,
|
||||
lastUpdated: state.communityData.lastUpdated.dynamicNews
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user