feat: 添加 /api/review-stats 端点和仪表盘实时数据集成
This commit is contained in:
@@ -318,3 +318,14 @@ export async function createManualBills(bills: ManualBillInput[]): Promise<Creat
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 获取待复核数据统计
|
||||
export async function fetchReviewStats(): Promise<ReviewResponse> {
|
||||
const response = await fetch(`${API_BASE}/api/review-stats`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { uploadBill, type UploadResponse, type BillType } from '$lib/api';
|
||||
import { onMount } from 'svelte';
|
||||
import { uploadBill, fetchMonthlyStats, fetchReviewStats, fetchBills, type UploadResponse, type BillType } from '$lib/api';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Badge } from '$lib/components/ui/badge';
|
||||
@@ -23,37 +24,145 @@
|
||||
let uploadResult: UploadResponse | null = $state(null);
|
||||
let errorMessage = $state('');
|
||||
|
||||
// 模拟统计数据
|
||||
const stats = [
|
||||
// 实时统计数据
|
||||
let stats = $state([
|
||||
{
|
||||
title: '本月支出',
|
||||
value: '¥12,580.00',
|
||||
change: '+12.5%',
|
||||
trend: 'up',
|
||||
description: '较上月增加'
|
||||
value: '¥0.00',
|
||||
change: '+0%',
|
||||
trend: 'up' as const,
|
||||
description: '加载中...'
|
||||
},
|
||||
{
|
||||
title: '本月收入',
|
||||
value: '¥25,000.00',
|
||||
change: '+8.2%',
|
||||
trend: 'up',
|
||||
description: '较上月增加'
|
||||
value: '¥0.00',
|
||||
change: '+0%',
|
||||
trend: 'up' as const,
|
||||
description: '加载中...'
|
||||
},
|
||||
{
|
||||
title: '待复核',
|
||||
value: '23',
|
||||
change: '-15%',
|
||||
trend: 'down',
|
||||
value: '0',
|
||||
change: '+0%',
|
||||
trend: 'up' as const,
|
||||
description: '需要人工确认'
|
||||
},
|
||||
{
|
||||
title: '已处理账单',
|
||||
value: '156',
|
||||
change: '+25%',
|
||||
trend: 'up',
|
||||
value: '0',
|
||||
change: '+0%',
|
||||
trend: 'up' as const,
|
||||
description: '累计处理记录'
|
||||
},
|
||||
];
|
||||
]);
|
||||
|
||||
// 加载真实统计数据
|
||||
async function loadStats() {
|
||||
try {
|
||||
const now = new Date();
|
||||
const currentMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
|
||||
|
||||
// 计算上月
|
||||
const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
|
||||
const previousMonth = `${lastMonth.getFullYear()}-${String(lastMonth.getMonth() + 1).padStart(2, '0')}`;
|
||||
|
||||
console.log('Current month:', currentMonth);
|
||||
console.log('Previous month:', previousMonth);
|
||||
|
||||
// 获取月度统计数据
|
||||
const monthlyResponse = await fetchMonthlyStats();
|
||||
console.log('Monthly response:', monthlyResponse);
|
||||
const monthlyStats = monthlyResponse.data || [];
|
||||
console.log('Monthly stats:', monthlyStats);
|
||||
|
||||
// 获取待复核统计
|
||||
const reviewResponse = await fetchReviewStats();
|
||||
console.log('Review response:', reviewResponse);
|
||||
const reviewTotal = reviewResponse.data?.total || 0;
|
||||
console.log('Review total:', reviewTotal);
|
||||
|
||||
// 获取已处理账单数量
|
||||
const billsResponse = await fetchBills({ page_size: 1 });
|
||||
console.log('Bills response:', billsResponse);
|
||||
const billTotal = billsResponse.data?.total || 0;
|
||||
console.log('Bill total:', billTotal);
|
||||
|
||||
// 提取当月和上月的数据
|
||||
const currentData = monthlyStats.find(m => m.month === currentMonth);
|
||||
const previousData = monthlyStats.find(m => m.month === previousMonth);
|
||||
|
||||
console.log('Current data:', currentData);
|
||||
console.log('Previous data:', previousData);
|
||||
|
||||
// 计算支出变化百分比
|
||||
const currentExpense = currentData?.expense || 0;
|
||||
const previousExpense = previousData?.expense || 0;
|
||||
const expenseChange = previousExpense > 0
|
||||
? ((currentExpense - previousExpense) / previousExpense * 100).toFixed(1)
|
||||
: 0;
|
||||
const expenseTrend = parseFloat(expenseChange.toString()) >= 0 ? 'up' : 'down';
|
||||
|
||||
// 计算收入变化百分比
|
||||
const currentIncome = currentData?.income || 0;
|
||||
const previousIncome = previousData?.income || 0;
|
||||
const incomeChange = previousIncome > 0
|
||||
? ((currentIncome - previousIncome) / previousIncome * 100).toFixed(1)
|
||||
: 0;
|
||||
const incomeTrend = parseFloat(incomeChange.toString()) >= 0 ? 'up' : 'down';
|
||||
|
||||
// 格式化金额
|
||||
const formatAmount = (amount: number) => {
|
||||
return `¥${amount.toFixed(2)}`;
|
||||
};
|
||||
|
||||
const formatChange = (change: number | string) => {
|
||||
const changeNum = typeof change === 'string' ? parseFloat(change) : change;
|
||||
const sign = changeNum >= 0 ? '+' : '';
|
||||
return `${sign}${changeNum.toFixed(1)}%`;
|
||||
};
|
||||
|
||||
const newStats = [
|
||||
{
|
||||
title: '本月支出',
|
||||
value: formatAmount(currentExpense),
|
||||
change: formatChange(expenseChange),
|
||||
trend: expenseTrend,
|
||||
description: '较上月' + (expenseTrend === 'up' ? '增加' : '减少')
|
||||
},
|
||||
{
|
||||
title: '本月收入',
|
||||
value: formatAmount(currentIncome),
|
||||
change: formatChange(incomeChange),
|
||||
trend: incomeTrend,
|
||||
description: '较上月' + (incomeTrend === 'up' ? '增加' : '减少')
|
||||
},
|
||||
{
|
||||
title: '待复核',
|
||||
value: reviewTotal.toString(),
|
||||
change: '+0%',
|
||||
trend: 'up' as const,
|
||||
description: '需要人工确认'
|
||||
},
|
||||
{
|
||||
title: '已处理账单',
|
||||
value: billTotal.toString(),
|
||||
change: '+0%',
|
||||
trend: 'up' as const,
|
||||
description: '累计处理记录'
|
||||
},
|
||||
];
|
||||
|
||||
console.log('New stats:', newStats);
|
||||
stats = newStats;
|
||||
} catch (err) {
|
||||
console.error('Failed to load stats:', err);
|
||||
// 保持默认状态
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
loadStats();
|
||||
});
|
||||
|
||||
function handleDragOver(e: DragEvent) {
|
||||
e.preventDefault();
|
||||
|
||||
Reference in New Issue
Block a user