swing_account/lib/widgets/statistics/monthly_overview.dart
2025-01-02 13:39:25 +08:00

137 lines
3.6 KiB
Dart

import 'package:flutter/material.dart';
import '../../models/record.dart';
class MonthlyOverview extends StatelessWidget {
final List<Record> records;
final bool isYearView;
const MonthlyOverview({
Key? key,
required this.records,
this.isYearView = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final totalExpense = records
.where((r) => r.type == RecordType.expense)
.fold(0.0, (sum, r) => sum + r.amount);
final totalIncome = records
.where((r) => r.type == RecordType.income)
.fold(0.0, (sum, r) => sum + r.amount);
final balance = totalIncome - totalExpense;
// 计算日均支出
final daysInPeriod = isYearView
? (records.isNotEmpty ? _getDaysInYear(records.first.createTime.year) : 365)
: (records.isNotEmpty ? _getDaysInMonth(records.first.createTime) : 30);
final dailyAverage = totalExpense / daysInPeriod;
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Column(
children: [
Row(
children: [
Expanded(
child: _buildOverviewItem(
label: '${isYearView ? "" : ""}支出',
amount: totalExpense,
textColor: Colors.red,
),
),
Expanded(
child: _buildOverviewItem(
label: '${isYearView ? "" : ""}收入',
amount: totalIncome,
textColor: Colors.green,
),
),
],
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: _buildOverviewItem(
label: '结余',
amount: balance,
textColor: balance >= 0 ? Colors.green : Colors.red,
showSign: true,
),
),
Expanded(
child: _buildOverviewItem(
label: '日均支出',
amount: dailyAverage,
textColor: Colors.grey[800]!,
),
),
],
),
],
),
);
}
int _getDaysInMonth(DateTime date) {
return DateTime(date.year, date.month + 1, 0).day;
}
int _getDaysInYear(int year) {
return DateTime(year).isLeapYear ? 366 : 365;
}
Widget _buildOverviewItem({
required String label,
required double amount,
required Color textColor,
bool showSign = false,
}) {
String amountText = '¥${amount.toStringAsFixed(2)}';
if (showSign && amount > 0) {
amountText = '+$amountText';
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
const SizedBox(height: 4),
Text(
amountText,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: textColor,
),
),
],
);
}
}
extension DateTimeExtension on DateTime {
bool get isLeapYear {
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
}