137 lines
3.6 KiB
Dart
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);
|
|
}
|
|
} |