167 lines
5.0 KiB
TypeScript
167 lines
5.0 KiB
TypeScript
/**
|
||
* 仪表板数据 Hooks
|
||
* 使用 React Query 进行数据获取和缓存管理
|
||
*/
|
||
|
||
import { useQuery } from '@tanstack/react-query';
|
||
import { dashboardService } from '@/services/dashboardService';
|
||
import type { DashboardPeriod } from '@/types';
|
||
|
||
/** Query Keys */
|
||
export const dashboardKeys = {
|
||
all: ['dashboard'] as const,
|
||
overview: () => [...dashboardKeys.all, 'overview'] as const,
|
||
stats: () => [...dashboardKeys.all, 'stats'] as const,
|
||
trend: (period: DashboardPeriod) => [...dashboardKeys.all, 'trend', period] as const,
|
||
region: () => [...dashboardKeys.all, 'region'] as const,
|
||
activities: (limit: number) => [...dashboardKeys.all, 'activities', limit] as const,
|
||
plantingStats: () => [...dashboardKeys.all, 'plantingStats'] as const,
|
||
// [2026-01-06] 新增:planting-service 趋势数据(用于仪表板)
|
||
plantingTrend: (days: number) => [...dashboardKeys.all, 'plantingTrend', days] as const,
|
||
// [2026-01-07] 新增:热钱包余额
|
||
hotWalletBalance: () => [...dashboardKeys.all, 'hotWalletBalance'] as const,
|
||
};
|
||
|
||
/**
|
||
* 获取仪表板概览数据
|
||
*/
|
||
export function useDashboardOverview() {
|
||
return useQuery({
|
||
queryKey: dashboardKeys.overview(),
|
||
queryFn: async () => {
|
||
const response = await dashboardService.getOverview();
|
||
return response.data;
|
||
},
|
||
staleTime: 30 * 1000, // 30秒后标记为过期
|
||
gcTime: 5 * 60 * 1000, // 5分钟后垃圾回收
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 获取统计卡片数据
|
||
*/
|
||
export function useDashboardStats() {
|
||
return useQuery({
|
||
queryKey: dashboardKeys.stats(),
|
||
queryFn: async () => {
|
||
const response = await dashboardService.getStats();
|
||
// 确保返回数组,即使 API 返回 undefined 或非数组
|
||
return response?.data?.stats ?? [];
|
||
},
|
||
staleTime: 30 * 1000,
|
||
gcTime: 5 * 60 * 1000,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 获取趋势图表数据
|
||
* @param period 时间周期
|
||
*/
|
||
export function useDashboardTrend(period: DashboardPeriod = '7d') {
|
||
return useQuery({
|
||
queryKey: dashboardKeys.trend(period),
|
||
queryFn: async () => {
|
||
const response = await dashboardService.getTrendData(period);
|
||
return response.data.trend;
|
||
},
|
||
staleTime: 60 * 1000, // 1分钟后标记为过期
|
||
gcTime: 5 * 60 * 1000,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 获取区域分布数据
|
||
*/
|
||
export function useDashboardRegion() {
|
||
return useQuery({
|
||
queryKey: dashboardKeys.region(),
|
||
queryFn: async () => {
|
||
const response = await dashboardService.getRegionDistribution();
|
||
// 确保返回数组
|
||
return response?.data?.regions ?? [];
|
||
},
|
||
staleTime: 5 * 60 * 1000, // 5分钟后标记为过期
|
||
gcTime: 10 * 60 * 1000,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 获取最近活动数据
|
||
* @param limit 返回数量限制
|
||
*/
|
||
export function useDashboardActivities(limit = 5) {
|
||
return useQuery({
|
||
queryKey: dashboardKeys.activities(limit),
|
||
queryFn: async () => {
|
||
const response = await dashboardService.getRecentActivities(limit);
|
||
// 确保返回数组
|
||
return response?.data?.activities ?? [];
|
||
},
|
||
staleTime: 30 * 1000, // 30秒后标记为过期
|
||
gcTime: 5 * 60 * 1000,
|
||
refetchInterval: 60 * 1000, // 每分钟自动刷新
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 获取认种统计数据(来自 planting-service,直接从订单表聚合)
|
||
* 数据更可靠,用于显示总认种量
|
||
*/
|
||
export function usePlantingStats() {
|
||
return useQuery({
|
||
queryKey: dashboardKeys.plantingStats(),
|
||
queryFn: async () => {
|
||
const response = await dashboardService.getPlantingStats();
|
||
return response?.data ?? null;
|
||
},
|
||
staleTime: 60 * 1000, // 1分钟后标记为过期
|
||
gcTime: 5 * 60 * 1000,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 获取认种趋势数据(用于仪表板趋势图)
|
||
* [2026-01-06] 新增:直接使用 planting-service 数据
|
||
* @param days 天数:7, 30, 90 对应仪表板的三个选项
|
||
*/
|
||
export function usePlantingTrendForDashboard(days: 7 | 30 | 90 = 7) {
|
||
return useQuery({
|
||
queryKey: dashboardKeys.plantingTrend(days),
|
||
queryFn: async () => {
|
||
// 使用 day 维度获取趋势数据
|
||
const response = await dashboardService.getPlantingTrendData('day');
|
||
if (!response?.data) return [];
|
||
|
||
// 根据 days 参数截取最近的数据
|
||
const allData = response.data;
|
||
const slicedData = allData.slice(-days);
|
||
|
||
// 转换为 TrendChart 组件需要的格式
|
||
return slicedData.map(item => ({
|
||
date: item.label.slice(5), // 2026-01-06 -> 01-06
|
||
value: item.treeCount,
|
||
}));
|
||
},
|
||
staleTime: 60 * 1000,
|
||
gcTime: 5 * 60 * 1000,
|
||
});
|
||
}
|
||
|
||
// [2026-01-07] 新增:热钱包余额查询
|
||
/**
|
||
* 获取热钱包余额(公共账户和因子)
|
||
* 用于仪表板显示实时余额
|
||
*/
|
||
export function useHotWalletBalance() {
|
||
return useQuery({
|
||
queryKey: dashboardKeys.hotWalletBalance(),
|
||
queryFn: async () => {
|
||
const response = await dashboardService.getHotWalletBalance();
|
||
return response?.data ?? null;
|
||
},
|
||
staleTime: 10 * 1000, // 10秒后标记为过期(实时性要求较高)
|
||
gcTime: 60 * 1000,
|
||
refetchInterval: 15 * 1000, // 每15秒自动刷新
|
||
});
|
||
}
|