import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../models/budget.dart'; import '../../../utils/amount_util.dart'; import '../../../widgets/donut_chart.dart'; import '../../../widgets/state_views.dart'; /// 本月预算卡:环形图 + 预算 / 剩余 / 日均可用 class BudgetCard extends StatelessWidget { const BudgetCard({super.key, required this.budget}); final AsyncValue budget; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), ), child: budget.when( loading: () => const LoadingView(tip: '预算加载中...', padding: EdgeInsets.all(20)), error: (e, _) => ErrorView(message: '预算加载失败'), data: (info) => info.hasBudget ? _content(info) : _noBudget(), ), ); } Widget _noBudget() { return const EmptyView( icon: '🎯', title: '本月未设置预算', tip: '可在「我的 → 预算设置」中设置', padding: EdgeInsets.symmetric(vertical: 20), ); } Widget _content(BudgetInfo info) { final over = info.isOverBudget; final ringColor = over ? const Color(0xFFE53935) : const Color(0xFFC8956E); final usedRatio = info.usedRatio; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Padding( padding: EdgeInsets.only(left: 4, bottom: 12), child: Text( '本月预算', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF5D4037)), ), ), Row( children: [ DonutChart( size: 116, centerSpaceRadius: 38, slices: [ DonutSlice(value: usedRatio, color: ringColor), DonutSlice(value: 1 - usedRatio, color: const Color(0xFFF0E6D8)), ], center: Column( mainAxisSize: MainAxisSize.min, children: [ Text( over ? '超支' : '${(usedRatio * 100).round()}%', style: TextStyle( fontSize: over ? 14 : 17, fontWeight: FontWeight.bold, color: over ? const Color(0xFFE53935) : const Color(0xFF5D4037), ), ), if (!over) const Text('已用', style: TextStyle(fontSize: 10, color: Color(0xFF8D6E63))), ], ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _amountRow('预算总额', '¥${formatAmount(info.amount)}', const Color(0xFF5D4037)), const SizedBox(height: 8), _amountRow('已用', '¥${formatAmount(info.usedAmount)}', ringColor), const SizedBox(height: 8), _amountRow( '剩余', '¥${formatAmount(info.remainingAmount)}', info.remainingAmount < 0 ? const Color(0xFFE53935) : const Color(0xFF19BE6B), ), ], ), ), ], ), const SizedBox(height: 12), Container( width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0x33C8956E), Color(0x33FFD700)], ), borderRadius: BorderRadius.circular(12), border: Border.all(color: const Color(0xFFC8956E)), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('💰 日均可用 ', style: TextStyle(fontSize: 13, color: Color(0xFF6D4C41))), Text( '¥${formatAmount(info.remainingDaily)}', style: const TextStyle( fontSize: 15, fontWeight: FontWeight.bold, color: Color(0xFF5D4037), ), ), ], ), ), ], ); } Widget _amountRow(String label, String value, Color valueColor) { return Row( children: [ Text(label, style: const TextStyle(fontSize: 12.5, color: Color(0xFF8D6E63))), const Spacer(), Text( value, style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: valueColor), ), ], ); } }