This commit is contained in:
sion
2026-04-07 01:05:05 +08:00
parent edad10ff06
commit 5ca1274607
83 changed files with 1561 additions and 1241 deletions

View File

@@ -11,7 +11,7 @@ import '../../../core/event/app_event_bus.dart';
import '../../../data/services/bonus_service.dart';
import '../../../providers/asset_provider.dart';
/// 福利中心
/// 福利中心
class WelfareCenterPage extends StatefulWidget {
const WelfareCenterPage({super.key});
@@ -45,10 +45,10 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
}
// ============================================
// 容器样式辅
// 容器樣式輔
// ============================================
/// 标准卡片容器
/// 標準卡片容器
BoxDecoration _cardDecoration({Color? borderColor}) {
return BoxDecoration(
color: context.appColors.surfaceCard,
@@ -59,11 +59,11 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
);
}
/// 金色渐变卡片容器
/// 金色漸變卡片容器
BoxDecoration _goldGradientDecoration() {
final isDark = context.isDark;
// Light Mode: 琥珀色渐变(从 amber 15% 到深灰 5%
// Dark Mode: 金色渐变
// Light Mode: 琥珀色漸變(從 amber 15% 到深灰 5%
// Dark Mode: 金色漸變
final gradientColors = isDark
? [
context.appColors.accentPrimary.withValues(alpha: 0.15),
@@ -90,7 +90,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
);
}
/// 状态胶囊标签
/// 狀態膠囊標籤
Widget _statusBadge(String text, Color textColor, Color bgColor) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6), // [4,10] → [6,14]
@@ -105,7 +105,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
);
}
/// 全宽按钮
/// 全寬按鈕
Widget _fullWidthButton({
required String text,
required Color backgroundColor,
@@ -192,7 +192,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
}
// ============================================
// 推广码卡片(金色渐变边框 Hero Card
// 推廣碼卡片(金色漸變邊框 Hero Card
// ============================================
Widget _buildReferralCodeCard(BuildContext context) {
@@ -206,13 +206,13 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header Row: gift icon + 标题
// Header Row: gift icon + 標題
Row(
children: [
Icon(LucideIcons.gift, color: goldAccent, size: 24),
const SizedBox(width: 10),
Text(
'我的邀请码',
'我的邀請碼',
style: AppTextStyles.headlineLarge(context).copyWith(
fontWeight: FontWeight.w700,
),
@@ -221,9 +221,9 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
),
const SizedBox(height: 16),
Text(
referralCode.isEmpty ? '暂无邀请码' : referralCode,
referralCode.isEmpty ? '暫無邀請碼' : referralCode,
style: AppTextStyles.displayMedium(context).copyWith(
fontSize: 24, // 明确设置为 24px
fontSize: 24, // 明確設置為 24px
fontWeight: FontWeight.w800,
color: goldAccent,
letterSpacing: 2,
@@ -238,7 +238,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
? null
: () {
Clipboard.setData(ClipboardData(text: referralCode));
ToastUtils.show('请码已复制');
ToastUtils.show('請碼已複製');
},
style: ElevatedButton.styleFrom(
backgroundColor: goldAccent,
@@ -250,7 +250,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
disabledBackgroundColor: goldAccent.withValues(alpha: 0.4),
),
child: Text(
'复制邀请码',
'複製邀請碼',
style: AppTextStyles.headlineMedium(context).copyWith(color: context.colors.onPrimary),
),
),
@@ -272,7 +272,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
final claimed = newUserBonus?['claimed'] as bool? ?? false;
final deposited = newUserBonus?['deposited'] as bool? ?? false;
// 状态判定
// 狀態判定
String badgeText;
bool showAvailableBadge;
String buttonText;
@@ -280,23 +280,23 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
String description;
if (claimed) {
badgeText = '';
badgeText = '';
showAvailableBadge = false;
buttonText = '';
buttonText = '';
canClaim = false;
description = '新人福利已';
description = '新人福利已';
} else if (eligible) {
badgeText = '';
badgeText = '';
showAvailableBadge = true;
buttonText = '立即';
buttonText = '立即';
canClaim = true;
description = '完成首次充值即可';
description = '完成首次充值即可';
} else {
badgeText = deposited ? '已充值' : '待解';
badgeText = deposited ? '已充值' : '待解';
showAvailableBadge = false;
buttonText = '未解';
buttonText = '未解';
canClaim = false;
description = deposited ? '已充值,等待系统确认' : '完成首次充值即可';
description = deposited ? '已充值,等待系統確認' : '完成首次充值即可';
}
return Container(
@@ -306,7 +306,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header: 标题 + 状态标签
// Header: 標題 + 狀態標籤
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@@ -348,14 +348,14 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
}
// ============================================
// 推广奖励列表
// 推廣獎勵列表
// ============================================
Widget _buildReferralRewardsSection(BuildContext context) {
final referralRewards =
_welfareData?['referralRewards'] as List<dynamic>? ?? [];
// 汇总统计
// 彙總統計
int totalEarned = 0;
int totalClaimable = 0;
for (var r in referralRewards) {
@@ -373,17 +373,17 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
children: [
// Section Header
Text(
'广奖励',
'廣獎勵',
style: AppTextStyles.headlineLarge(context),
),
const SizedBox(height: 4),
Text(
'每邀一位好友充值达标,奖励100 USDT',
'每邀一位好友充值達標,獎勵100 USDT',
style: AppTextStyles.bodySmall(context).copyWith(
color: context.appColors.onSurfaceMuted,
),
),
// 汇总统计
// 彙總統計
if (referralRewards.isNotEmpty) ...[
const SizedBox(height: 12),
Container(
@@ -395,12 +395,12 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
),
child: Row(
children: [
_buildStatItem('已邀', '${referralRewards.length}'),
_buildStatItem('已邀', '${referralRewards.length}'),
Container(width: 1, height: 20, color: context.appColors.ghostBorder),
_buildStatItem('', '${totalEarned * 100} USDT'),
_buildStatItem('', '${totalEarned * 100} USDT'),
if (totalClaimable > 0) ...[
Container(width: 1, height: 20, color: context.appColors.ghostBorder),
_buildStatItem('', '$totalClaimable', highlight: true),
_buildStatItem('', '$totalClaimable', highlight: true),
],
],
),
@@ -408,7 +408,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
],
const SizedBox(height: 12),
// 推广列表卡片
// 推列表卡片
Container(
width: double.infinity,
decoration: _cardDecoration(),
@@ -450,7 +450,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
),
const SizedBox(height: 8),
Text(
'暂无推广用户',
'暫無推廣用戶',
style: AppTextStyles.bodyLarge(context).copyWith(
color: context.colors.onSurfaceVariant,
),
@@ -470,18 +470,21 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
final claimableCount = data['claimableCount'] as int? ?? 0;
final milestones = data['milestones'] as List<dynamic>? ?? [];
final userId = data['userId'] as int? ?? 0;
final indirectRefCount = data['indirectRefCount'] as int? ?? 0;
final indirectClaimableCount = data['indirectClaimableCount'] as int? ?? 0;
final indirectMilestones = data['indirectMilestones'] as List<dynamic>? ?? [];
final isLast = index == referralRewards.length - 1;
// 进度计
// 進度計
final progress = _computeProgress(milestones, totalDeposit);
// 操作按
// 操作按
final actionWidget = _buildReferralAction(
data: data,
claimableCount: claimableCount,
milestones: milestones,
progress: progress,
);
// 进度条颜
// 進度條顏
final progressColor = _referralProgressColor(claimableCount, progress);
return Column(
@@ -526,11 +529,21 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
),
),
),
// 里程碑
// 里程碑
if (milestones.isNotEmpty) ...[
const SizedBox(height: 12),
_buildMilestoneDetails(milestones, userId),
],
// 間接推廣獎勵
if (indirectRefCount > 0) ...[
const SizedBox(height: 12),
_buildIndirectSection(
userId,
indirectRefCount,
indirectClaimableCount,
indirectMilestones,
),
],
],
),
),
@@ -546,7 +559,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
);
}
/// 里程碑情行 — 示每里程碑状态
/// 里程碑情行 — 示每里程碑狀態
Widget _buildMilestoneDetails(List<dynamic> milestones, int userId) {
final upColor = context.appColors.up;
@@ -625,7 +638,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
);
}
/// 算推荐奖励进
/// 算推薦獎勵進
double _computeProgress(List<dynamic> milestones, String totalDeposit) {
if (milestones.isNotEmpty) {
int earnedCount = milestones.where((m) {
@@ -638,14 +651,14 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
return (deposit / 1000).clamp(0.0, 1.0);
}
/// 根据状态获取进度条颜
/// 根據狀態獲取進度條顏
Color _referralProgressColor(int claimableCount, double progress) {
if (claimableCount > 0) return context.appColors.up;
if (progress > 0) return context.appColors.accentPrimary;
return context.appColors.surfaceCardHigh;
}
/// 建推荐奖励的操作按
/// 建推薦獎勵的操作按
Widget? _buildReferralAction({
required Map<String, dynamic> data,
required int claimableCount,
@@ -665,21 +678,136 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
return GestureDetector(
onTap: () => _claimReferralBonus(data['userId'] as int, milestoneValue),
child: _statusBadge('', profitGreen, profitGreenBg),
child: _statusBadge('', profitGreen, profitGreenBg),
);
}
if (progress > 0) {
final warningColor = AppColorScheme.warning;
return _statusBadge('行中', warningColor, warningColor.withValues(alpha: 0.15));
return _statusBadge('行中', warningColor, warningColor.withValues(alpha: 0.15));
}
return Text(
'达标',
'達標',
style: AppTextStyles.labelLarge(context).copyWith(color: context.appColors.onSurfaceMuted),
);
}
// ============================================
// 奖励规则卡片
// 間接推廣獎勵區塊
// ============================================
Widget _buildIndirectSection(
int directReferralId,
int indirectRefCount,
int indirectClaimableCount,
List<dynamic> indirectMilestones,
) {
final goldAccent = context.appColors.accentPrimary;
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: context.appColors.surfaceCardHigh.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(AppRadius.md),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(LucideIcons.users, size: 14, color: goldAccent),
const SizedBox(width: 6),
Text(
'已推廣 $indirectRefCount',
style: AppTextStyles.bodyMedium(context).copyWith(
color: context.colors.onSurfaceVariant,
),
),
if (indirectClaimableCount > 0) ...[
const Spacer(),
_statusBadge(
'$indirectClaimableCount 個可領',
context.appColors.up,
context.appColors.upBackground,
),
],
],
),
// 間接里程碑標籤
if (indirectMilestones.isNotEmpty) ...[
const SizedBox(height: 8),
_buildIndirectMilestoneTags(directReferralId, indirectMilestones),
],
],
),
);
}
Widget _buildIndirectMilestoneTags(int directReferralId, List<dynamic> milestones) {
final upColor = context.appColors.up;
return Wrap(
spacing: 6,
runSpacing: 6,
children: milestones.map((m) {
final ms = m as Map<String, dynamic>;
final milestoneVal = ms['milestone'] as int? ?? 1;
final earned = ms['earned'] as bool? ?? false;
final claimed = ms['claimed'] as bool? ?? false;
final claimable = ms['claimable'] as bool? ?? false;
final indirectReferredUserId = ms['indirectReferredUserId'] as int? ?? 0;
// 不顯示未達標的里程碑
if (!earned && !claimed) return const SizedBox.shrink();
Color bgColor;
Color textColor;
String label;
if (claimed) {
bgColor = upColor.withValues(alpha: 0.1);
textColor = upColor;
label = '50\u2713';
} else if (claimable) {
bgColor = context.appColors.accentPrimary.withValues(alpha: 0.15);
textColor = context.appColors.accentPrimary;
label = '50\u{1F381}';
} else {
bgColor = context.appColors.surfaceCardHigh;
textColor = context.colors.onSurfaceVariant;
label = '50';
}
return GestureDetector(
onTap: claimable
? () => _claimIndirectReferralBonus(
directReferralId,
indirectReferredUserId,
milestoneVal,
)
: null,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(AppRadius.sm),
border: claimable ? Border.all(color: textColor.withValues(alpha: 0.3)) : null,
),
child: Text(
label,
style: AppTextStyles.bodySmall(context).copyWith(
fontSize: 11,
fontWeight: FontWeight.w600,
color: textColor,
),
),
),
);
}).toList(),
);
}
// ============================================
// 獎勵規則卡片
// ============================================
Widget _buildRulesCard(BuildContext context) {
@@ -694,13 +822,14 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'奖励规则',
'獎勵規則',
style: AppTextStyles.headlineSmall(context),
),
const SizedBox(height: 8),
_buildRuleItem('新用户注册完成实名认证奖励 100 USDT'),
_buildRuleItem('好友充值每 1000 USDT双方各获得 100 USDT'),
_buildRuleItem('奖励直接发放至资金账户'),
_buildRuleItem('新用戶註冊完成實名認證獎勵 100 USDT'),
_buildRuleItem('好友充值每 1000 USDT獎勵 100 USDT'),
_buildRuleItem('好友推廣的人充值每達 1000 USDT額外獎勵 50 USDT'),
_buildRuleItem('獎勵直接發放至資金賬戶'),
],
),
);
@@ -719,7 +848,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
}
// ============================================
// 业务逻辑
// 業務邏輯
// ============================================
Future<void> _claimNewUserBonus() async {
@@ -731,13 +860,13 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
if (response.success) {
context.read<AssetProvider>().refreshAll(force: true);
context.read<AppEventBus>().fire(AppEventType.assetChanged);
ToastUtils.show('取成功100 USDT 已到');
ToastUtils.show('取成功100 USDT 已到');
_loadData();
} else {
ToastUtils.show(response.message ?? '取失');
ToastUtils.show(response.message ?? '取失');
}
} catch (e) {
ToastUtils.show('取失: $e');
ToastUtils.show('取失: $e');
}
}
@@ -753,13 +882,40 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
if (response.success) {
context.read<AssetProvider>().refreshAll(force: true);
context.read<AppEventBus>().fire(AppEventType.assetChanged);
ToastUtils.show('取成功100 USDT 已到');
ToastUtils.show('取成功100 USDT 已到');
_loadData();
} else {
ToastUtils.show(response.message ?? '取失');
ToastUtils.show(response.message ?? '取失');
}
} catch (e) {
ToastUtils.show('取失: $e');
ToastUtils.show('取失: $e');
}
}
Future<void> _claimIndirectReferralBonus(
int directReferralId,
int indirectReferredUserId,
int milestone,
) async {
try {
final bonusService = context.read<BonusService>();
final response = await bonusService.claimIndirectReferralBonus(
directReferralId,
indirectReferredUserId,
milestone,
);
if (!mounted) return;
if (response.success) {
context.read<AssetProvider>().refreshAll(force: true);
context.read<AppEventBus>().fire(AppEventType.assetChanged);
ToastUtils.show('領取成功50 USDT 已到賬');
_loadData();
} else {
ToastUtils.show(response.message ?? '領取失敗');
}
} catch (e) {
ToastUtils.show('領取失敗: $e');
}
}
}