import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../core/l10n/app_localizations.dart'; import '../../../core/theme/app_colors.dart'; import '../../../data/repositories/broker_repository.dart'; // ── Providers ───────────────────────────────────────────── final _brokerInfoProvider = FutureProvider.autoDispose?>((ref) { return ref.read(brokerRepositoryProvider).getBrokerInfo(); }); /// 今日返佣记录(对应安卓 rebatesInfo,startTime=今日零时) final _brokerTodayRewardsProvider = FutureProvider.autoDispose>>((ref) { final now = DateTime.now(); final todayStart = DateTime(now.year, now.month, now.day, 0, 0, 0); return ref.read(brokerRepositoryProvider).getRewardList( pageSize: 50, startTime: todayStart, ); }); // ── Screen ─────────────────────────────────────────────── class BrokerScreen extends ConsumerWidget { const BrokerScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final cs = Theme.of(context).colorScheme; final infoAsync = ref.watch(_brokerInfoProvider); final rewardsAsync = ref.watch(_brokerTodayRewardsProvider); return Scaffold( backgroundColor: cs.surface, appBar: AppBar( backgroundColor: cs.surface, elevation: 0, leading: IconButton( icon: const Icon(Icons.arrow_back_ios, size: 18), onPressed: () => context.pop(), ), title: Text(AppLocalizations.of(context)!.broker, style: TextStyle(color: cs.onSurface, fontSize: 17, fontWeight: FontWeight.w600)), centerTitle: true, ), body: infoAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => Center(child: Text('${AppLocalizations.of(context)!.loadFailed}: $e')), data: (info) => _BrokerBody(info: info, rewardsAsync: rewardsAsync), ), ); } } class _BrokerBody extends StatelessWidget { const _BrokerBody({required this.info, required this.rewardsAsync}); final Map? info; final AsyncValue>> rewardsAsync; @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; final uid = info?['id']?.toString() ?? '--'; // 与 profile_provider 保持一致:优先取 email,fallback 到 username final email = (info?['email'] as String?)?.trim().isNotEmpty == true ? info!['email'] as String : (info?['username'] as String? ?? ''); final maskedEmail = _maskEmail(email); // 代理商显示名:按优先级依次尝试各字段 final nickName = ((info?['nickName'] ?? info?['agentName'] ?? info?['name'] ?? info?['realName']) as String? ?? '').trim(); // 统计数据(字段对应安卓 AgentInfo:uc/agent/info) final todayNew = info?['todayNewUserCount']?.toString() ?? '0'; final todayTrading = info?['todayOrderUserCount']?.toString() ?? '0'; final todayRebate = _truncate4(info?['todayAward']?.toString() ?? '0.00'); return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ── 用户信息卡片 ────────────────────────────── Container( width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: isDark ? AppColors.darkBgSecondary : AppColors.lightBgSecondary, borderRadius: BorderRadius.circular(12), border: Border.all(color: cs.outlineVariant.withAlpha(60)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( nickName.isNotEmpty ? AppLocalizations.of(context)!.brokerWelcomeNamed(nickName) : AppLocalizations.of(context)!.brokerWelcome, style: TextStyle(fontSize: 18, fontWeight: FontWeight.w700, color: cs.onSurface), ), const SizedBox(height: 6), Row(children: [ Flexible( child: Text(maskedEmail, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 13, color: cs.onSurface.withAlpha(120))), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: cs.onSurface.withAlpha(18), borderRadius: BorderRadius.circular(4), ), child: Text('UID: $uid', style: TextStyle(fontSize: 12, color: cs.onSurface.withAlpha(140))), ), ]), ], ), ), const SizedBox(height: 12), // ── 提示横幅 ───────────────────────────────── Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), decoration: BoxDecoration( color: AppColors.brand.withAlpha(25), borderRadius: BorderRadius.circular(10), border: Border.all(color: AppColors.brand.withAlpha(80)), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Icon(Icons.info_outline, size: 16, color: AppColors.brand), const SizedBox(width: 8), Expanded( child: Text( AppLocalizations.of(context)!.brokerInviteTip, style: TextStyle(fontSize: 12, color: cs.onSurface.withAlpha(160), height: 1.5), ), ), ], ), ), const SizedBox(height: 20), // ── 统计数据(来自 agentInfo,与安卓一致)──── _StatsRow(todayNew: todayNew, todayTrading: todayTrading, todayRebate: todayRebate), const SizedBox(height: 24), // ── 两个按钮 ────────────────────────────────── Row(children: [ Expanded( child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.black, foregroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)), padding: const EdgeInsets.symmetric(vertical: 14), ), onPressed: () => context.push('/broker/my-invitations'), child: Text(AppLocalizations.of(context)!.myInvitations, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.black, foregroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)), padding: const EdgeInsets.symmetric(vertical: 14), ), onPressed: () => context.push('/broker/team-detail'), child: Text(AppLocalizations.of(context)!.teamDetail, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), ), ), ]), const SizedBox(height: 24), // ── 今日返佣列表(对应安卓 awardsLiveData)──── Text(AppLocalizations.of(context)!.inviteList, style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: cs.onSurface)), const SizedBox(height: 12), _RewardsTable(rewardsAsync: rewardsAsync), ], ), ); } String _maskEmail(String email) { if (email.isEmpty) return '--'; final atIdx = email.indexOf('@'); if (atIdx <= 1) return email; return '${email[0]}**${email.substring(atIdx)}'; } } /// 截断到4位小数,不四舍五入 String _truncate4(String value) { final d = double.tryParse(value); if (d == null) return value; final s = d.toStringAsFixed(10); final dot = s.indexOf('.'); if (dot == -1) return '$s.0000'; final end = dot + 5; // dot + 4 decimals return end >= s.length ? s.padRight(end, '0') : s.substring(0, end); } class _StatsRow extends StatelessWidget { const _StatsRow({required this.todayNew, required this.todayTrading, required this.todayRebate}); final String todayNew; final String todayTrading; final String todayRebate; @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; return Row( children: [ Expanded(child: _StatCell(value: todayNew, label: AppLocalizations.of(context)!.todayNewUsers)), Container(width: 1, height: 40, color: cs.outlineVariant.withAlpha(80)), Expanded(child: _StatCell(value: todayTrading, label: AppLocalizations.of(context)!.todayTradingUsers)), Container(width: 1, height: 40, color: cs.outlineVariant.withAlpha(80)), Expanded(child: _StatCell(value: todayRebate, label: AppLocalizations.of(context)!.todayRebateLabel)), ], ); } } class _StatCell extends StatelessWidget { const _StatCell({required this.value, required this.label}); final String value; final String label; @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; return Column( mainAxisSize: MainAxisSize.min, children: [ Text(value, style: TextStyle(fontSize: 22, fontWeight: FontWeight.w700, color: cs.onSurface)), const SizedBox(height: 4), Text(label, textAlign: TextAlign.center, style: TextStyle(fontSize: 11, color: cs.onSurface.withAlpha(120), height: 1.4)), ], ); } } class _RewardsTable extends StatelessWidget { const _RewardsTable({required this.rewardsAsync}); final AsyncValue>> rewardsAsync; @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; return rewardsAsync.when( loading: () => const Center(child: CircularProgressIndicator(strokeWidth: 2)), error: (e, _) => Text(AppLocalizations.of(context)!.loadFailed, style: TextStyle(color: cs.error)), data: (rewards) { if (rewards.isEmpty) { return Padding( padding: const EdgeInsets.symmetric(vertical: 32), child: Center(child: Text(AppLocalizations.of(context)!.noInviteRecord, style: TextStyle(color: cs.onSurface.withAlpha(120)))), ); } return Column(children: [ // 表头 Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: cs.surfaceContainerHighest.withAlpha(60), borderRadius: BorderRadius.circular(6)), child: Row(children: [ Expanded(child: Text(AppLocalizations.of(context)!.accountLabel, style: TextStyle(fontSize: 12, color: cs.onSurface.withAlpha(120)))), Expanded(child: Text('ID', textAlign: TextAlign.center, style: TextStyle(fontSize: 12, color: cs.onSurface.withAlpha(120)))), Expanded(child: Text(AppLocalizations.of(context)!.todayRebateLabel, textAlign: TextAlign.right, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 12, color: cs.onSurface.withAlpha(120)))), ]), ), ...rewards.map((r) => _RewardRow(reward: r)), ]); }, ); } } class _RewardRow extends StatelessWidget { const _RewardRow({required this.reward}); final Map reward; String _maskName(String? name) { if (name == null || name.isEmpty) return '--'; if (name.contains('@')) { final atIdx = name.indexOf('@'); if (atIdx > 1) return '${name[0]}**${name.substring(atIdx)}'; return name; } if (name.length > 4) return '${name.substring(0, 3)}****${name.substring(name.length - 2)}'; return name; } @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; final name = _maskName(reward['username'] as String?); final memberId = reward['memberId']?.toString() ?? '--'; final amount = reward['num']?.toString() ?? '0.0000'; final amountFormatted = double.tryParse(amount)?.toStringAsFixed(4) ?? amount; return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: cs.outlineVariant.withAlpha(40)))), child: Row(children: [ Expanded(child: Text(name, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 13, color: cs.onSurface))), Expanded(child: Text(memberId, textAlign: TextAlign.center, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 13, color: cs.onSurface))), Expanded(child: Text(amountFormatted, textAlign: TextAlign.right, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 13, color: cs.onSurface))), ]), ); } }