import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../core/theme/app_theme.dart'; import '../../providers/auth_provider.dart'; import '../../providers/wallet_provider.dart'; import '../../services/wallet_service.dart'; /// 钱包页:余额 / 累计充值·获得·消耗 / 评论奖励进度 / 积分明细(biz_type 筛选 + 触底分页) class WalletScreen extends ConsumerWidget { const WalletScreen({super.key}); static const List> _filters = [ {'label': '全部', 'value': null}, {'label': '充值', 'value': 1}, {'label': '观看', 'value': 2}, {'label': '评论奖励', 'value': 3}, {'label': '会员', 'value': 4}, {'label': '赠送', 'value': 5}, {'label': '调整', 'value': 6}, {'label': '扣回', 'value': 7}, ]; @override Widget build(BuildContext context, WidgetRef ref) { final state = ref.watch(walletProvider); final isLoggedIn = ref.watch(authProvider).isLoggedIn; // 未登录时引导(钱包页入口 mine_screen 已做登录守卫,此处兜底) if (!isLoggedIn) { return Scaffold( appBar: AppBar(title: const Text('钱包')), body: _GuestGuide(onLogin: () => context.push('/login')), ); } return Scaffold( appBar: AppBar(title: const Text('钱包')), body: state.isLoading && state.wallet == null ? const Center(child: CircularProgressIndicator()) : state.loadFailed && state.wallet == null ? _LoadFailed( onRetry: () => ref.read(walletProvider.notifier).load(), ) : RefreshIndicator( onRefresh: () => ref.read(walletProvider.notifier).load(), child: ListView.builder( padding: const EdgeInsets.all(16), itemCount: 1 + (state.records.isEmpty ? 1 : state.records.length + 1), itemBuilder: (context, index) { // 头部:余额 + 进度 if (index == 0) { return Column( children: [ _BalanceCard(wallet: state.wallet), const SizedBox(height: 16), _RewardProgress( progress: state.wallet?.rewardProgress), const SizedBox(height: 20), // 筛选 chips SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: _filters.map((f) { final active = state.bizType == f['value']; return Padding( padding: const EdgeInsets.only(right: 8), child: ChoiceChip( label: Text(f['label'] as String), selected: active, onSelected: (_) => ref .read(walletProvider.notifier) .setBizType(f['value'] as int?), selectedColor: AppColors.primary, backgroundColor: AppColors.surface, labelStyle: TextStyle( color: active ? Colors.white : AppColors.textSecondary, fontSize: 12, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), ), ); }).toList(), ), ), const SizedBox(height: 8), const Divider(), const SizedBox(height: 4), ], ); } // 明细列表 final listIndex = index - 1; if (listIndex < state.records.length) { final item = state.records[listIndex]; return _RecordTile(item: item); } if (listIndex == state.records.length) { // 空态 / 加载更多 if (state.records.isEmpty) { return const Center( child: Padding( padding: EdgeInsets.symmetric(vertical: 40), child: Text( '暂无明细', style: TextStyle( color: AppColors.textSecondary, fontSize: 14), ), ), ); } if (state.loadingMore) { return const Padding( padding: EdgeInsets.symmetric(vertical: 12), child: Center( child: SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), )), ); } if (state.hasMore) { WidgetsBinding.instance.addPostFrameCallback((_) { ref.read(walletProvider.notifier).loadMore(); }); } return const SizedBox.shrink(); } return const SizedBox.shrink(); }, ), ), ); } } /// 余额 + 累计概览 class _BalanceCard extends StatelessWidget { const _BalanceCard({this.wallet}); final WalletInfo? wallet; @override Widget build(BuildContext context) { final points = wallet?.points ?? 0; final totalRecharge = wallet?.totalRecharge ?? 0; final totalEarned = wallet?.totalEarned ?? 0; final totalConsumed = wallet?.totalConsumed ?? 0; return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('当前积分', style: TextStyle(color: AppColors.textSecondary, fontSize: 13)), const SizedBox(height: 6), Text('$points', style: const TextStyle( fontSize: 36, fontWeight: FontWeight.w800, color: AppColors.gold)), const SizedBox(height: 14), Row( children: [ _StatColumn(label: '累计充值', value: '$totalRecharge'), _StatColumn(label: '累计获得', value: '$totalEarned'), _StatColumn(label: '累计消耗', value: '$totalConsumed'), ], ), const SizedBox(height: 14), SizedBox( width: double.infinity, height: 40, child: ElevatedButton( onPressed: () => context.push('/recharge'), child: const Text('充值', style: TextStyle(fontSize: 14)), ), ), ], ), ); } } class _StatColumn extends StatelessWidget { const _StatColumn({required this.label, required this.value}); final String label; final String value; @override Widget build(BuildContext context) { return Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: const TextStyle( color: AppColors.textWeak, fontSize: 11)), const SizedBox(height: 2), Text(value, style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w700)), ], ), ); } } /// 评论奖励进度条 class _RewardProgress extends StatelessWidget { const _RewardProgress({this.progress}); final CommentRewardProgress? progress; @override Widget build(BuildContext context) { final cur = progress?.current ?? 0; final target = progress?.target ?? 10; final today = progress?.todayRewarded ?? 0; final limit = progress?.dailyLimit ?? 5; final ratio = target == 0 ? 0.0 : (cur / target).clamp(0.0, 1.0); return Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('今日评论奖励进度', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600)), Text('$today / $limit 次', style: const TextStyle( color: AppColors.textSecondary, fontSize: 12)), ], ), const SizedBox(height: 8), ClipRRect( borderRadius: BorderRadius.circular(4), child: LinearProgressIndicator( value: ratio, minHeight: 8, backgroundColor: AppColors.textWeak.withValues(alpha: 0.2), valueColor: const AlwaysStoppedAnimation(AppColors.primary), ), ), const SizedBox(height: 6), Text( '已评论 $cur 条,再评论 ${(target - cur).clamp(0, target)} 条即可领取奖励', style: const TextStyle( color: AppColors.textWeak, fontSize: 12), ), ], ), ); } } /// 明细条目 class _RecordTile extends StatelessWidget { const _RecordTile({required this.item}); final PointsRecord item; @override Widget build(BuildContext context) { return ListTile( contentPadding: EdgeInsets.zero, dense: true, title: Text(item.bizTypeLabel, style: const TextStyle(fontSize: 14)), subtitle: item.remark.isNotEmpty ? Text(item.remark, style: const TextStyle( color: AppColors.textWeak, fontSize: 12)) : null, trailing: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( '${item.isExpense ? '' : '+'}${item.changeAmount}', style: TextStyle( color: item.isExpense ? AppColors.textSecondary : AppColors.gold, fontSize: 14, fontWeight: FontWeight.w700, ), ), Text(item.createdAt, style: const TextStyle( color: AppColors.textWeak, fontSize: 11)), ], ), ); } } class _GuestGuide extends StatelessWidget { const _GuestGuide({required this.onLogin}); final VoidCallback onLogin; @override Widget build(BuildContext context) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.account_balance_wallet_outlined, size: 64, color: AppColors.textWeak), const SizedBox(height: 12), const Text('登录后查看钱包', style: TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 16), ElevatedButton( onPressed: onLogin, style: ElevatedButton.styleFrom( minimumSize: const Size(160, 44), ), child: const Text('去登录 / 注册'), ), ], ), ); } } class _LoadFailed extends StatelessWidget { const _LoadFailed({required this.onRetry}); final VoidCallback onRetry; @override Widget build(BuildContext context) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Text('加载失败', style: TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 12), TextButton(onPressed: onRetry, child: const Text('点击重试')), ], ), ); } }