feat(admin-web): 仪表板改用 planting-service 源数据
统计卡片和趋势图不再使用 reporting-service,直接使用 planting-service 的源数据: - 统计卡片:总认种量、总订单数、今日认种、本月认种 - 趋势图:支持 7天/30天/90天 切换 - 新增 usePlantingTrendForDashboard hook 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
b947fe8205
commit
305514b246
|
|
@ -601,7 +601,33 @@
|
|||
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(wallet-service\\): 实现 Unit of Work 模式保证 settleToBalance 事务原子性\n\n- 新增 UnitOfWork 接口和实现,使用 Prisma Interactive Transaction\n- 修改 IWalletAccountRepository 和 ILedgerEntryRepository 接口支持可选事务参数\n- 修改仓库实现,支持在事务中执行数据库操作\n- 修改 settleToBalance 方法使用 UnitOfWork,确保钱包更新和流水记录原子性\n- 注册 UnitOfWorkService 到 InfrastructureModule\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
|
||||
"Bash(ls -la \"c:\\\\Users\\\\dong\\\\Desktop\\\\rwadurian\\\\backend\\\\services\\\\wallet-service\\\\prisma\\\\migrations\"\" 2>/dev/null || dir \"c:UsersdongDesktoprwadurianbackendserviceswallet-serviceprismamigrations \")",
|
||||
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(admin-web\\): 添加系统账户收益类型汇总统计功能\n\n在数据统计-系统账户中新增5个统计Tab:\n- 手续费账户汇总:统计成本费、运营费、总部社区基础费、RWAD底池注入\n- 省团队收益汇总:统计省团队权益收益\n- 市团队收益汇总:统计市团队权益收益\n- 分享引荐收益汇总:统计分享权益收益\n- 社区收益汇总:统计社区权益收益\n\n后端变更:\n- reward-service: 添加 getRewardsSummaryByType、getAllRewardTypeSummaries 方法\n- reporting-service: 聚合收益类型汇总统计接口\n\n前端变更:\n- 添加 RewardTypeSummary、FeeAccountSummary 类型定义\n- 添加 getRewardTypeSummaries API 方法\n- 添加 FeeAccountSection、RewardTypeSummarySection 组件\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
|
||||
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(wallet-service\\): 实现手续费归集账户功能\n\n- 新增系统账户 S0000000006 \\(user_id=-6\\) 用于归集提现手续费\n- 新增 FEE_COLLECTION 流水类型记录手续费归集\n- 区块链提现完成时使用 UnitOfWork 事务归集手续费\n- 法币提现完成时在事务中归集手续费\n- WithdrawalOrderRepository 添加事务支持\n- 所有手续费归集操作使用乐观锁保护\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")"
|
||||
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(wallet-service\\): 实现手续费归集账户功能\n\n- 新增系统账户 S0000000006 \\(user_id=-6\\) 用于归集提现手续费\n- 新增 FEE_COLLECTION 流水类型记录手续费归集\n- 区块链提现完成时使用 UnitOfWork 事务归集手续费\n- 法币提现完成时在事务中归集手续费\n- WithdrawalOrderRepository 添加事务支持\n- 所有手续费归集操作使用乐观锁保护\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
|
||||
"Bash(backend/services/blockchain-service/src/application/application.module.ts )",
|
||||
"Bash(backend/services/blockchain-service/src/application/event-handlers/system-withdrawal-requested.handler.ts )",
|
||||
"Bash(backend/services/blockchain-service/src/infrastructure/kafka/withdrawal-event-consumer.service.ts )",
|
||||
"Bash(backend/services/wallet-service/src/api/api.module.ts )",
|
||||
"Bash(backend/services/wallet-service/src/api/controllers/index.ts )",
|
||||
"Bash(backend/services/wallet-service/src/api/controllers/system-withdrawal.controller.ts )",
|
||||
"Bash(backend/services/wallet-service/src/application/services/index.ts )",
|
||||
"Bash(backend/services/wallet-service/src/application/services/system-withdrawal-application.service.ts )",
|
||||
"Bash(backend/services/wallet-service/src/application/event-handlers/system-withdrawal-status.handler.ts )",
|
||||
"Bash(backend/services/wallet-service/src/infrastructure/external/identity/identity-client.service.ts )",
|
||||
"Bash(backend/services/wallet-service/src/infrastructure/kafka/withdrawal-event-consumer.service.ts)",
|
||||
"Bash(backend/services/planting-service/src/api/controllers/planting-stats.controller.ts )",
|
||||
"Bash(backend/services/planting-service/src/api/dto/response/planting-stats.response.ts )",
|
||||
"Bash(backend/services/planting-service/src/domain/repositories/planting-order.repository.interface.ts )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/persistence/repositories/planting-order.repository.impl.ts )",
|
||||
"Bash(frontend/admin-web/src/app/\\\\\\(dashboard\\\\\\)/statistics/page.tsx )",
|
||||
"Bash(frontend/admin-web/src/app/\\\\\\(dashboard\\\\\\)/statistics/statistics.module.scss )",
|
||||
"Bash(frontend/admin-web/src/services/dashboardService.ts )",
|
||||
"Bash(frontend/admin-web/src/types/dashboard.types.ts)",
|
||||
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(wallet/blockchain/identity\\): implement system account withdrawal feature\n\n- Add SystemWithdrawalApplicationService to handle system account transfers\n- Add SystemWithdrawalController with endpoints for request, query, and account listing\n- Add SystemWithdrawalStatusHandler to process blockchain confirmation/failure events\n- Add SystemWithdrawalRequestedHandler in blockchain-service to execute ERC20 transfers\n- Add getUserByAccountSequence endpoint in identity-service for user lookup\n- Support dynamic memo generation based on actual source account name\n- Dual-sided ledger entries for system account transfers\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
|
||||
"Bash(frontend/admin-web/src/hooks/index.ts )",
|
||||
"Bash(frontend/admin-web/src/hooks/useSystemWithdrawal.ts )",
|
||||
"Bash(frontend/admin-web/src/services/systemWithdrawalService.ts )",
|
||||
"Bash(frontend/admin-web/src/types/system-withdrawal.types.ts )",
|
||||
"Bash(\"frontend/admin-web/src/app/\\(dashboard\\)/system-transfer/\")",
|
||||
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(admin-web\\): add system account transfer management page\n\n- Add system-transfer page with transfer form and order history\n- Add SystemWithdrawalService for API calls\n- Add useSystemWithdrawal hooks for React Query integration\n- Add system-withdrawal types definitions\n- Add navigation menu item for system transfer\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ async function main() {
|
|||
log('DEBUG', '转出方流水:', {
|
||||
id: transferOutEntry.id,
|
||||
amount: transferOutEntry.amount.toString(),
|
||||
balanceAfter: transferOutEntry.balanceAfter.toString(),
|
||||
balanceAfter: transferOutEntry.balanceAfter?.toString() ?? 'null',
|
||||
createdAt: transferOutEntry.createdAt.toISOString(),
|
||||
});
|
||||
}
|
||||
|
|
@ -172,7 +172,7 @@ async function main() {
|
|||
log('ERROR', '流水详情:', {
|
||||
id: existingTransferIn.id,
|
||||
amount: existingTransferIn.amount.toString(),
|
||||
balanceAfter: existingTransferIn.balanceAfter.toString(),
|
||||
balanceAfter: existingTransferIn.balanceAfter?.toString() ?? 'null',
|
||||
createdAt: existingTransferIn.createdAt.toISOString(),
|
||||
});
|
||||
log('ERROR', '');
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
'use client';
|
||||
|
||||
/**
|
||||
* 仪表板页面
|
||||
* [2026-01-06] 更新:统计卡片和趋势图改用 planting-service 数据(源数据)
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Button } from '@/components/common';
|
||||
import { PageContainer } from '@/components/layout';
|
||||
|
|
@ -8,11 +13,10 @@ import { TrendChart } from '@/components/features/dashboard/TrendChart';
|
|||
import { RegionDistribution } from '@/components/features/dashboard/RegionDistribution';
|
||||
import { RecentActivity } from '@/components/features/dashboard/RecentActivity';
|
||||
import {
|
||||
useDashboardStats,
|
||||
useDashboardTrend,
|
||||
useDashboardRegion,
|
||||
useDashboardActivities,
|
||||
usePlantingStats,
|
||||
usePlantingTrendForDashboard,
|
||||
} from '@/hooks';
|
||||
import type { DashboardPeriod } from '@/types';
|
||||
import styles from './dashboard.module.scss';
|
||||
|
|
@ -45,23 +49,34 @@ const EmptyData = ({ message }: { message: string }) => (
|
|||
</div>
|
||||
);
|
||||
|
||||
/** 将 DashboardPeriod 转换为天数 */
|
||||
function periodToDays(period: DashboardPeriod): 7 | 30 | 90 {
|
||||
switch (period) {
|
||||
case '7d': return 7;
|
||||
case '30d': return 30;
|
||||
case '90d': return 90;
|
||||
default: return 7;
|
||||
}
|
||||
}
|
||||
|
||||
export default function DashboardPage() {
|
||||
const [trendPeriod, setTrendPeriod] = useState<DashboardPeriod>('7d');
|
||||
|
||||
// 使用 React Query hooks 获取数据
|
||||
// [2026-01-06] 直接使用 planting-service 数据(源数据)
|
||||
const {
|
||||
data: statsData,
|
||||
data: plantingStatsData,
|
||||
isLoading: statsLoading,
|
||||
error: statsError,
|
||||
refetch: refetchStats,
|
||||
} = useDashboardStats();
|
||||
} = usePlantingStats();
|
||||
|
||||
// [2026-01-06] 趋势数据也使用 planting-service
|
||||
const {
|
||||
data: trendData,
|
||||
isLoading: trendLoading,
|
||||
error: trendError,
|
||||
refetch: refetchTrend,
|
||||
} = useDashboardTrend(trendPeriod);
|
||||
} = usePlantingTrendForDashboard(periodToDays(trendPeriod));
|
||||
|
||||
const {
|
||||
data: regionData,
|
||||
|
|
@ -77,28 +92,37 @@ 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;
|
||||
// [2026-01-06] 基于 planting-service 数据构建统计卡片数据
|
||||
const statsCards = plantingStatsData ? [
|
||||
{
|
||||
title: '总认种量',
|
||||
value: plantingStatsData.totalTreeCount,
|
||||
suffix: '棵',
|
||||
change: { value: plantingStatsData.todayStats?.treeCount ?? 0, trend: 'up' as const },
|
||||
color: '#10b981',
|
||||
},
|
||||
{
|
||||
title: '总订单数',
|
||||
value: plantingStatsData.totalOrderCount,
|
||||
suffix: '单',
|
||||
change: { value: plantingStatsData.todayStats?.orderCount ?? 0, trend: 'up' as const },
|
||||
color: '#3b82f6',
|
||||
},
|
||||
{
|
||||
title: '今日认种',
|
||||
value: plantingStatsData.todayStats?.treeCount ?? 0,
|
||||
suffix: '棵',
|
||||
change: { value: 0, trend: 'up' as const },
|
||||
color: '#f59e0b',
|
||||
},
|
||||
{
|
||||
title: '本月认种',
|
||||
value: plantingStatsData.monthStats?.treeCount ?? 0,
|
||||
suffix: '棵',
|
||||
change: { value: 0, trend: 'up' as const },
|
||||
color: '#8b5cf6',
|
||||
},
|
||||
] : [];
|
||||
|
||||
const headerActions = (
|
||||
<>
|
||||
|
|
@ -121,29 +145,26 @@ export default function DashboardPage() {
|
|||
actions={headerActions}
|
||||
>
|
||||
<div className={styles.dashboard}>
|
||||
{/* 统计卡片区 */}
|
||||
{/* 统计卡片区 - [2026-01-06] 使用 planting-service 数据 */}
|
||||
<div className={styles.dashboard__stats}>
|
||||
{isStatsLoading ? (
|
||||
{statsLoading ? (
|
||||
// 加载状态显示骨架屏
|
||||
<>
|
||||
{[1, 2, 3, 4].map((i) => (
|
||||
<StatCardSkeleton key={i} />
|
||||
))}
|
||||
</>
|
||||
) : hasStatsError ? (
|
||||
) : statsError ? (
|
||||
// 错误状态
|
||||
<div className={styles.dashboard__statsError}>
|
||||
<ErrorMessage
|
||||
message="加载统计数据失败"
|
||||
onRetry={() => {
|
||||
refetchStats();
|
||||
refetchPlantingStats();
|
||||
}}
|
||||
onRetry={() => refetchStats()}
|
||||
/>
|
||||
</div>
|
||||
) : mergedStatsData && mergedStatsData.length > 0 ? (
|
||||
// 正常显示数据(总认种量使用 planting-service 的可靠数据)
|
||||
mergedStatsData.map((stat, index) => (
|
||||
) : statsCards.length > 0 ? (
|
||||
// 正常显示数据(直接使用 planting-service 源数据)
|
||||
statsCards.map((stat, index) => (
|
||||
<StatCard key={index} {...stat} />
|
||||
))
|
||||
) : (
|
||||
|
|
@ -152,7 +173,7 @@ export default function DashboardPage() {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{/* 图表区 */}
|
||||
{/* 图表区 - [2026-01-06] 使用 planting-service 数据 */}
|
||||
<div className={styles.dashboard__charts}>
|
||||
<div className={styles.dashboard__mainChart}>
|
||||
{trendError ? (
|
||||
|
|
@ -163,7 +184,7 @@ export default function DashboardPage() {
|
|||
) : (
|
||||
<TrendChart
|
||||
title="认种趋势"
|
||||
data={trendData?.data ?? []}
|
||||
data={trendData ?? []}
|
||||
period={trendPeriod}
|
||||
onPeriodChange={setTrendPeriod}
|
||||
loading={trendLoading}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ export const dashboardKeys = {
|
|||
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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -114,3 +116,31 @@ export function usePlantingStats() {
|
|||
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,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue