feat(admin-web): integrate planting-service stats API for dashboard

Use planting-service's reliable database aggregation for total planting count
instead of reporting-service's Kafka event-driven statistics.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-04 07:04:39 -08:00
parent 251fee4f1e
commit 21c8f1906a
5 changed files with 71 additions and 6 deletions

View File

@ -12,6 +12,7 @@ import {
useDashboardTrend,
useDashboardRegion,
useDashboardActivities,
usePlantingStats,
} from '@/hooks';
import type { DashboardPeriod } from '@/types';
import styles from './dashboard.module.scss';
@ -76,6 +77,29 @@ export default function DashboardPage() {
refetch: refetchActivities,
} = useDashboardActivities(5);
// 从 planting-service 获取可靠的认种统计数据
const {
data: plantingStatsData,
isLoading: plantingStatsLoading,
error: plantingStatsError,
refetch: refetchPlantingStats,
} = usePlantingStats();
// 合并统计数据:总认种量使用 planting-service 的数据
const mergedStatsData = statsData?.map((stat) => {
if (stat.title === '总认种量' && plantingStatsData) {
return {
...stat,
value: plantingStatsData.totalTreeCount,
};
}
return stat;
});
// 判断是否正在加载统计数据
const isStatsLoading = statsLoading || plantingStatsLoading;
const hasStatsError = statsError || plantingStatsError;
const headerActions = (
<>
<Button variant="outline" size="sm">
@ -99,24 +123,27 @@ export default function DashboardPage() {
<div className={styles.dashboard}>
{/* 统计卡片区 */}
<div className={styles.dashboard__stats}>
{statsLoading ? (
{isStatsLoading ? (
// 加载状态显示骨架屏
<>
{[1, 2, 3, 4].map((i) => (
<StatCardSkeleton key={i} />
))}
</>
) : statsError ? (
) : hasStatsError ? (
// 错误状态
<div className={styles.dashboard__statsError}>
<ErrorMessage
message="加载统计数据失败"
onRetry={() => refetchStats()}
onRetry={() => {
refetchStats();
refetchPlantingStats();
}}
/>
</div>
) : statsData && statsData.length > 0 ? (
// 正常显示数据
statsData.map((stat, index) => (
) : mergedStatsData && mergedStatsData.length > 0 ? (
// 正常显示数据(总认种量使用 planting-service 的可靠数据)
mergedStatsData.map((stat, index) => (
<StatCard key={index} {...stat} />
))
) : (

View File

@ -15,6 +15,7 @@ export const dashboardKeys = {
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,
};
/**
@ -97,3 +98,19 @@ export function useDashboardActivities(limit = 5) {
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,
});
}

View File

@ -111,6 +111,11 @@ export const API_ENDPOINTS = {
REGION: '/v1/dashboard/region',
},
// 认种统计 (planting-service) - 从订单表实时聚合,数据可靠
PLANTING_STATS: {
GLOBAL: '/v1/planting/stats/global',
},
// 通知管理 (admin-service)
NOTIFICATIONS: {
LIST: '/v1/admin/notifications',

View File

@ -13,6 +13,7 @@ import type {
RegionDistributionItem,
DashboardActivity,
DashboardStatItem,
PlantingGlobalStats,
} from '@/types';
/** 仪表板概览响应 */
@ -80,6 +81,14 @@ export const dashboardService = {
params: { limit },
});
},
/**
* planting-service
* reporting-service
*/
async getPlantingStats(): Promise<ApiResponse<PlantingGlobalStats>> {
return apiClient.get(API_ENDPOINTS.PLANTING_STATS.GLOBAL);
},
};
export default dashboardService;

View File

@ -87,3 +87,10 @@ export interface DashboardTrendParams {
export interface DashboardActivitiesParams {
limit?: number;
}
/** 认种全局统计数据(来自 planting-service */
export interface PlantingGlobalStats {
totalTreeCount: number;
totalOrderCount: number;
totalAmount: string;
}