import 'package:flutter/material.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/i18n/app_localizations.dart'; /// 核销管理页面 /// /// 扫码核销 + 手动输入券码 + 批量核销 + 核销记录 class RedemptionPage extends StatelessWidget { const RedemptionPage({super.key}); @override Widget build(BuildContext context) { return DefaultTabController( length: 2, child: Scaffold( appBar: AppBar( title: Text(context.t('redemption_title')), bottom: TabBar( tabs: [ Tab(text: context.t('redemption_tab_scan')), Tab(text: context.t('redemption_tab_history')), ], ), ), body: const TabBarView( children: [ _ScanRedeemTab(), _RedeemHistoryTab(), ], ), ), ); } } class _ScanRedeemTab extends StatelessWidget { const _ScanRedeemTab(); @override Widget build(BuildContext context) { return SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( children: [ // Scan Area Container( height: 260, decoration: BoxDecoration( color: AppColors.gray900, borderRadius: BorderRadius.circular(16), ), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 160, height: 160, decoration: BoxDecoration( border: Border.all(color: AppColors.primary, width: 2), borderRadius: BorderRadius.circular(12), ), child: const Icon(Icons.qr_code_scanner_rounded, color: AppColors.primary, size: 64), ), const SizedBox(height: 16), Text(context.t('redemption_scan_hint'), style: const TextStyle(color: Colors.white70, fontSize: 14)), ], ), ), ), const SizedBox(height: 20), // Manual Input Row( children: [ Expanded( child: TextField( decoration: InputDecoration( hintText: context.t('redemption_manual_hint'), prefixIcon: const Icon(Icons.keyboard_rounded), ), ), ), const SizedBox(width: 12), SizedBox( height: 52, child: ElevatedButton( onPressed: () => _showRedeemConfirm(context), child: Text(context.t('redemption_redeem')), ), ), ], ), const SizedBox(height: 20), // Batch Redeem OutlinedButton.icon( onPressed: () => _showBatchRedeem(context), icon: const Icon(Icons.list_alt_rounded), label: Text(context.t('redemption_batch')), style: OutlinedButton.styleFrom( minimumSize: const Size(double.infinity, 48), ), ), const SizedBox(height: 24), // Today Stats Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColors.borderLight), ), child: const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(context.t('redemption_today_title'), style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _StatItem(label: context.t('redemption_today_count'), value: '45'), _StatItem(label: context.t('redemption_today_amount'), value: '\$1,125'), _StatItem(label: context.t('redemption_today_stores'), value: '3'), ], ), ], ), ), ], ), ); } void _showRedeemConfirm(BuildContext context) { showModalBottomSheet( context: context, builder: (ctx) => Container( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.check_circle_rounded, color: AppColors.success, size: 56), const SizedBox(height: 16), Text(context.t('redemption_confirm_title'), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 8), const Text('¥25 星巴克礼品卡', style: TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 24), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () => Navigator.pop(ctx), child: Text(context.t('redemption_confirm_button')), ), ), const SizedBox(height: 12), ], ), ), ); } void _showBatchRedeem(BuildContext context) { showModalBottomSheet( context: context, isScrollControlled: true, builder: (ctx) => DraggableScrollableSheet( expand: false, initialChildSize: 0.6, builder: (_, controller) => Padding( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(context.t('redemption_batch'), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 8), Text(context.t('redemption_batch_desc'), style: const TextStyle(color: AppColors.textSecondary)), const SizedBox(height: 16), Expanded( child: TextField( maxLines: null, expands: true, textAlignVertical: TextAlignVertical.top, decoration: InputDecoration( hintText: context.t('redemption_batch_hint'), border: OutlineInputBorder(), ), ), ), const SizedBox(height: 16), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () => Navigator.pop(ctx), child: Text(context.t('redemption_batch')), ), ), ], ), ), ), ); } } class _RedeemHistoryTab extends StatelessWidget { const _RedeemHistoryTab(); @override Widget build(BuildContext context) { final records = [ ('¥25 礼品卡', '门店A · 收银员张三', '10分钟前', true), ('¥100 购物券', '门店B · 收银员李四', '25分钟前', true), ('¥50 生活券', '手动输入', '1小时前', true), ('¥25 礼品卡', '门店A · 扫码', '2小时前', false), ]; return ListView.separated( padding: const EdgeInsets.all(20), itemCount: records.length, separatorBuilder: (_, __) => const Divider(height: 1), itemBuilder: (context, index) { final (name, source, time, success) = records[index]; return ListTile( contentPadding: const EdgeInsets.symmetric(vertical: 8), leading: Container( width: 40, height: 40, decoration: BoxDecoration( color: success ? AppColors.successLight : AppColors.errorLight, borderRadius: BorderRadius.circular(10), ), child: Icon( success ? Icons.check_rounded : Icons.close_rounded, color: success ? AppColors.success : AppColors.error, size: 20, ), ), title: Text(name, style: const TextStyle(fontWeight: FontWeight.w500)), subtitle: Text(source, style: const TextStyle(fontSize: 12, color: AppColors.textSecondary)), trailing: Text(time, style: const TextStyle(fontSize: 11, color: AppColors.textTertiary)), ); }, ); } } class _StatItem extends StatelessWidget { final String label; final String value; const _StatItem({required this.label, required this.value}); @override Widget build(BuildContext context) { return Column( children: [ Text(value, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w700, color: AppColors.primary)), const SizedBox(height: 4), Text(label, style: const TextStyle(fontSize: 12, color: AppColors.textTertiary)), ], ); } }