import 'package:flutter/material.dart'; import '../models/record.dart'; import '../services/database_service.dart'; class WeeklySpendingChart extends StatelessWidget { final List records; late final DatabaseService _dbService; WeeklySpendingChart({ Key? key, required this.records, }) : super(key: key) { _dbService = DatabaseService(); } /// 获取最近7天的数据 Future> _getWeeklyData() async { final now = DateTime.now(); final startDate = DateTime(now.year, now.month, now.day - 6); final endDate = DateTime(now.year, now.month, now.day, 23, 59, 59); // 直接从数据库获取最近7天的数据 final weekRecords = await _dbService.getRecordsByDateRange(startDate, endDate); final List weeklyData = []; for (int i = 6; i >= 0; i--) { final date = DateTime(now.year, now.month, now.day - i); final dayRecords = weekRecords.where((record) => record.createTime.year == date.year && record.createTime.month == date.month && record.createTime.day == date.day && record.type == RecordType.expense ); final dailyTotal = dayRecords.fold(0.0, (sum, record) => sum + record.amount); weeklyData.add(DailySpending( date: date, amount: dailyTotal, )); } return weeklyData; } String _formatAmount(double amount) { if (amount >= 10000) { return '${(amount / 10000).toStringAsFixed(2)}w'; } else if (amount >= 1000) { return '${(amount / 1000).toStringAsFixed(2)}k'; } return amount.toStringAsFixed(2); } @override Widget build(BuildContext context) { return FutureBuilder>( future: _getWeeklyData(), builder: (context, snapshot) { if (!snapshot.hasData) { return const Center(child: CircularProgressIndicator()); } final weeklyData = snapshot.data!; final totalSpending = weeklyData.fold(0.0, (sum, day) => sum + day.amount); final maxDailySpending = weeklyData.fold(0.0, (max, day) => day.amount > max ? day.amount : max); return Container( padding: const EdgeInsets.all(16), margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), spreadRadius: 1, blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( '最近7日支出', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), Text( '总计: ${totalSpending.toStringAsFixed(2)}', style: const TextStyle( fontSize: 14, color: Colors.grey, ), ), ], ), const SizedBox(height: 16), SizedBox( height: 140, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.end, children: weeklyData.map((day) { final barHeight = maxDailySpending > 0 ? (day.amount / maxDailySpending) * 80 : 0.0; return SizedBox( width: 40, child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.end, children: [ Text( _formatAmount(day.amount), style: const TextStyle( fontSize: 11, height: 1.2, ), textAlign: TextAlign.center, ), const SizedBox(height: 4), Container( width: 24, height: barHeight, decoration: BoxDecoration( color: Theme.of(context).primaryColor.withOpacity(0.8), borderRadius: const BorderRadius.vertical( top: Radius.circular(4), ), ), ), const SizedBox(height: 4), Text( _getWeekdayText(day.date.weekday), style: const TextStyle( fontSize: 12, height: 1.2, ), ), ], ), ); }).toList(), ), ), ], ), ); }, ); } String _getWeekdayText(int weekday) { const weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']; return weekdays[weekday - 1]; } } class DailySpending { final DateTime date; final double amount; DailySpending({ required this.date, required this.amount, }); }