Files
vf_react/src/store/api/eventsApi.js

145 lines
4.1 KiB
JavaScript
Raw 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.

// src/store/api/eventsApi.js
// RTK Query API for Events - 事件数据获取 API
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import { logger } from '../../utils/logger';
/**
* Events API Slice - 使用 RTK Query 管理事件数据
*
* 特性:
* - ✅ 自动缓存管理(按 queryKey 缓存)
* - ✅ 自动去重请求
* - ✅ 返回第一页刷新数据invalidateTags
* - ✅ 预加载支持prefetch
* - ✅ 统一在 Redux DevTools 中调试
* - ✅ 无需额外 Provider
*/
export const eventsApi = createApi({
reducerPath: 'eventsApi',
// 基础查询配置
baseQuery: fetchBaseQuery({
baseUrl: '/api',
prepareHeaders: (headers) => {
// 可以在这里添加认证 token
// const token = localStorage.getItem('token');
// if (token) {
// headers.set('Authorization', `Bearer ${token}`);
// }
return headers;
},
}),
// 标签类型定义(用于缓存失效)
tagTypes: ['Events'],
// API 端点定义
endpoints: (builder) => ({
/**
* 获取分页事件列表
*
* @param {Object} params
* @param {number} params.page - 页码
* @param {number} params.per_page - 每页数量
* @param {string} params.mode - 显示模式vertical / four-row
* @param {string} params.sort - 排序方式
* @param {string} params.importance - 重要性筛选
* @param {string} params.q - 搜索关键词
* @param {string} params.date_range - 日期范围
* @param {string} params.industry_code - 行业代码
*
* @returns {Object} { events: Array, pagination: Object }
*/
getEvents: builder.query({
query: ({ page = 1, per_page = 5, mode = 'vertical', ...filters }) => {
logger.debug('eventsApi', 'getEvents 请求', {
page,
per_page,
mode,
filters,
});
return {
url: '/events',
params: {
page,
per_page,
...filters,
},
};
},
// 🔥 缓存标签:用于缓存失效
providesTags: (result, error, { page, mode }) => {
if (error) return [];
return [
{ type: 'Events', id: `${mode}-${page}` }, // 具体页面的标签
{ type: 'Events', id: `${mode}-LIST` }, // 模式的总标签
];
},
// 转换响应数据
transformResponse: (response) => {
logger.debug('eventsApi', 'getEvents 响应', {
eventsCount: response.data?.events?.length,
total: response.data?.pagination?.total,
});
if (!response.success || !response.data?.events) {
throw new Error('数据格式错误');
}
return {
events: response.data.events,
pagination: response.data.pagination || {},
};
},
// 错误处理
transformErrorResponse: (response) => {
logger.error('eventsApi', 'getEvents 失败', new Error(response.status));
return {
status: response.status,
message: response.data?.message || '获取事件数据失败',
};
},
// 🔥 keepUnusedDataFor: 缓存保留时间(秒)
keepUnusedDataFor: 600, // 10分钟
// 🔥 合并查询结果(用于无限滚动)
// serializeQueryArgs: ({ endpointName, queryArgs }) => {
// const { mode, ...filters } = queryArgs;
// return `${endpointName}(${mode})`;
// },
// merge: (currentCache, newItems) => {
// currentCache.events.push(...newItems.events);
// },
// forceRefetch: ({ currentArg, previousArg }) => {
// return currentArg.page !== previousArg?.page;
// },
}),
/**
* 预加载下一页(性能优化)
*
* 用法:
* dispatch(eventsApi.util.prefetch('getEvents', { page: 2, ... }))
*/
}),
});
// 导出自动生成的 Hooks
export const {
useGetEventsQuery,
useLazyGetEventsQuery, // 手动触发的版本
usePrefetch, // 预加载 Hook
} = eventsApi;
// 导出工具方法
export const {
util: { invalidateTags, prefetch },
} = eventsApi;