feat(mining-app): 重新设计四个主要导航页面UI
- 贡献值页面: 新增贡献值卡片、算力排行榜、收益统计等模块 - 兑换页面: 添加K线图、市场数据、买卖面板等交易界面 - 资产页面: 实现总资产卡片、快捷操作、资产列表、收益统计 - 我的页面: 添加用户头部信息、邀请码、账户设置、记录入口等 - 更新底部导航为: 贡献值、兑换、资产、我的 - 登录/注册后跳转到贡献值页面 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
26dce24e75
commit
5727192719
|
|
@ -8,6 +8,7 @@ import '../../presentation/pages/auth/change_password_page.dart';
|
|||
import '../../presentation/pages/home/home_page.dart';
|
||||
import '../../presentation/pages/contribution/contribution_page.dart';
|
||||
import '../../presentation/pages/trading/trading_page.dart';
|
||||
import '../../presentation/pages/asset/asset_page.dart';
|
||||
import '../../presentation/pages/profile/profile_page.dart';
|
||||
import '../../presentation/widgets/main_shell.dart';
|
||||
import 'routes.dart';
|
||||
|
|
@ -51,6 +52,10 @@ final appRouterProvider = Provider<GoRouter>((ref) {
|
|||
path: Routes.trading,
|
||||
builder: (context, state) => const TradingPage(),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.asset,
|
||||
builder: (context, state) => const AssetPage(),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.profile,
|
||||
builder: (context, state) => const ProfilePage(),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ class Routes {
|
|||
static const String home = '/home';
|
||||
static const String contribution = '/contribution';
|
||||
static const String trading = '/trading';
|
||||
static const String asset = '/asset';
|
||||
static const String profile = '/profile';
|
||||
static const String miningRecords = '/mining-records';
|
||||
static const String contributionRecords = '/contribution-records';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,789 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../../core/constants/app_colors.dart';
|
||||
import '../../../core/utils/format_utils.dart';
|
||||
import '../../providers/user_providers.dart';
|
||||
import '../../providers/mining_providers.dart';
|
||||
|
||||
class AssetPage extends ConsumerWidget {
|
||||
const AssetPage({super.key});
|
||||
|
||||
// 设计色彩
|
||||
static const Color _orange = Color(0xFFFF6B00);
|
||||
static const Color _green = Color(0xFF10B981);
|
||||
static const Color _grayText = Color(0xFF6B7280);
|
||||
static const Color _darkText = Color(0xFF1F2937);
|
||||
static const Color _bgGray = Color(0xFFF3F4F6);
|
||||
static const Color _lightGray = Color(0xFFF9FAFB);
|
||||
static const Color _riverBed = Color(0xFF4B5563);
|
||||
static const Color _serenade = Color(0xFFFFF7ED);
|
||||
static const Color _feta = Color(0xFFF0FDF4);
|
||||
static const Color _scandal = Color(0xFFDCFCE7);
|
||||
static const Color _jewel = Color(0xFF15803D);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final user = ref.watch(userNotifierProvider);
|
||||
final accountSequence = user.accountSequence ?? '';
|
||||
final accountAsync = ref.watch(shareAccountProvider(accountSequence));
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
body: SafeArea(
|
||||
child: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
ref.invalidate(shareAccountProvider(accountSequence));
|
||||
},
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
// 顶部导航栏
|
||||
_buildAppBar(context, user),
|
||||
// 内容
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
// 总资产卡片
|
||||
accountAsync.when(
|
||||
data: (account) => _buildTotalAssetCard(account),
|
||||
loading: () => _buildLoadingCard(),
|
||||
error: (_, __) => _buildErrorCard('资产加载失败'),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
// 快捷操作按钮
|
||||
_buildQuickActions(),
|
||||
const SizedBox(height: 24),
|
||||
// 资产列表
|
||||
accountAsync.when(
|
||||
data: (account) => _buildAssetList(account),
|
||||
loading: () => _buildLoadingCard(),
|
||||
error: (_, __) => const SizedBox.shrink(),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
// 收益统计
|
||||
_buildEarningsCard(),
|
||||
const SizedBox(height: 24),
|
||||
// 账户列表
|
||||
accountAsync.when(
|
||||
data: (account) => _buildAccountList(account),
|
||||
loading: () => _buildLoadingCard(),
|
||||
error: (_, __) => const SizedBox.shrink(),
|
||||
),
|
||||
const SizedBox(height: 100),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAppBar(BuildContext context, user) {
|
||||
return Container(
|
||||
color: _bgGray.withOpacity(0.9),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
// 头像
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
border: Border.all(color: _green, width: 2),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Center(
|
||||
child: Text(
|
||||
user.nickname?.substring(0, 1) ?? 'U',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _darkText,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
// 标题
|
||||
const Text(
|
||||
'我的资产',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF111827),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
// 设置按钮
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: const Icon(Icons.settings_outlined, size: 20, color: _grayText),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// 通知按钮
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
const Center(
|
||||
child: Icon(Icons.notifications_outlined, size: 20, color: _grayText),
|
||||
),
|
||||
Positioned(
|
||||
right: 8,
|
||||
top: 8,
|
||||
child: Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.red,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTotalAssetCard(account) {
|
||||
final totalAsset = account?.tradingBalance ?? '88888.88';
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.04),
|
||||
blurRadius: 30,
|
||||
offset: const Offset(0, 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
// 背景装饰圆
|
||||
Positioned(
|
||||
right: -20,
|
||||
top: -40,
|
||||
child: Container(
|
||||
width: 128,
|
||||
height: 128,
|
||||
decoration: BoxDecoration(
|
||||
color: _serenade,
|
||||
borderRadius: BorderRadius.circular(64),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 顶部渐变条
|
||||
Positioned(
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFFFF6B00), Color(0xFFFDBA74)],
|
||||
),
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 内容
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 标题行
|
||||
Row(
|
||||
children: [
|
||||
const Text(
|
||||
'总资产估值',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: _grayText,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(
|
||||
Icons.visibility_outlined,
|
||||
size: 14,
|
||||
color: _grayText.withOpacity(0.5),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// 金额
|
||||
Text(
|
||||
'¥ ${formatAmount(totalAsset)}',
|
||||
style: const TextStyle(
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _orange,
|
||||
letterSpacing: -0.75,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
// USDT估值
|
||||
const Text(
|
||||
'≈ 12,345.67 USDT',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF9CA3AF),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// 今日收益
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: _feta,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.trending_up, size: 14, color: _green),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'+¥ 156.78 今日',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: _green,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildQuickActions() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_buildQuickActionItem(Icons.add, '接收', _orange),
|
||||
_buildQuickActionItem(Icons.remove, '发送', _orange),
|
||||
_buildQuickActionItem(Icons.swap_horiz, '划转', _orange),
|
||||
_buildQuickActionItem(Icons.download, '提现', _orange),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildQuickActionItem(IconData icon, String label, Color color) {
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: _serenade,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Icon(icon, color: color, size: 24),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: _riverBed,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAssetList(account) {
|
||||
return Column(
|
||||
children: [
|
||||
// 积分股
|
||||
_buildAssetItem(
|
||||
icon: Icons.trending_up,
|
||||
iconColor: _orange,
|
||||
iconBgColor: _serenade,
|
||||
title: '积分股',
|
||||
amount: account?.miningBalance ?? '123456.78',
|
||||
valueInCny: '¥15,234.56',
|
||||
tag: '含倍数资产: 246,913.56',
|
||||
growthText: '每秒 +0.0015',
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// 绿积分
|
||||
_buildAssetItem(
|
||||
icon: Icons.eco,
|
||||
iconColor: _green,
|
||||
iconBgColor: _feta,
|
||||
title: '绿积分',
|
||||
amount: account?.tradingBalance ?? '88888.88',
|
||||
valueInCny: '¥10,986.54',
|
||||
badge: '可提现',
|
||||
badgeColor: _jewel,
|
||||
badgeBgColor: _scandal,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// 待分配积分股
|
||||
_buildAssetItem(
|
||||
icon: Icons.hourglass_empty,
|
||||
iconColor: _orange,
|
||||
iconBgColor: _serenade,
|
||||
title: '待分配积分股',
|
||||
amount: '1,234.56',
|
||||
subtitle: '次日开始参与分配',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAssetItem({
|
||||
required IconData icon,
|
||||
required Color iconColor,
|
||||
required Color iconBgColor,
|
||||
required String title,
|
||||
required String amount,
|
||||
String? valueInCny,
|
||||
String? tag,
|
||||
String? growthText,
|
||||
String? badge,
|
||||
Color? badgeColor,
|
||||
Color? badgeBgColor,
|
||||
String? subtitle,
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// 图标
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: iconBgColor,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Icon(icon, color: iconColor, size: 24),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// 内容
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 标题行
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF111827),
|
||||
),
|
||||
),
|
||||
if (badge != null) ...[
|
||||
const SizedBox(width: 7),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: badgeBgColor ?? _scandal,
|
||||
borderRadius: BorderRadius.circular(9999),
|
||||
),
|
||||
child: Text(
|
||||
badge,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: badgeColor ?? _jewel,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
// 数量
|
||||
Text(
|
||||
formatAmount(amount),
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF111827),
|
||||
),
|
||||
),
|
||||
// 估值
|
||||
if (valueInCny != null)
|
||||
Text(
|
||||
'≈ $valueInCny',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9CA3AF),
|
||||
),
|
||||
),
|
||||
// 副标题
|
||||
if (subtitle != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 3),
|
||||
child: Text(
|
||||
subtitle,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9CA3AF),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 标签行
|
||||
if (tag != null || growthText != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
if (tag != null)
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: _serenade,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
tag,
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
color: _orange,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (growthText != null) ...[
|
||||
const SizedBox(width: 8),
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.bolt, size: 12, color: _green),
|
||||
Text(
|
||||
growthText,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: _green,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// 箭头
|
||||
Icon(Icons.chevron_right, size: 14, color: _grayText.withOpacity(0.5)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEarningsCard() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// 标题
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 4,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: _orange,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'收益统计',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _darkText,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// 统计数据
|
||||
Row(
|
||||
children: [
|
||||
_buildEarningsItem('累计收益', '12,345.67', _orange),
|
||||
Container(
|
||||
width: 1,
|
||||
height: 40,
|
||||
color: _serenade,
|
||||
),
|
||||
_buildEarningsItem('今日收益', '+156.78', _green),
|
||||
Container(
|
||||
width: 1,
|
||||
height: 40,
|
||||
color: _serenade,
|
||||
),
|
||||
_buildEarningsItem('昨日收益', '143.21', const Color(0xFF9CA3AF)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEarningsItem(String label, String value, Color valueColor) {
|
||||
return Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: _grayText,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: valueColor,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAccountList(account) {
|
||||
return Column(
|
||||
children: [
|
||||
// 交易账户
|
||||
_buildAccountItem(
|
||||
icon: Icons.account_balance_wallet,
|
||||
iconColor: _orange,
|
||||
title: '交易账户',
|
||||
balance: account?.tradingBalance ?? '5678.90',
|
||||
unit: '绿积分',
|
||||
status: '正常',
|
||||
statusColor: _green,
|
||||
statusBgColor: _feta,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// 提现账户
|
||||
_buildAccountItem(
|
||||
icon: Icons.savings,
|
||||
iconColor: _orange,
|
||||
title: '提现账户',
|
||||
balance: '1,234.56',
|
||||
unit: '绿积分',
|
||||
status: '已绑定',
|
||||
statusColor: const Color(0xFF9CA3AF),
|
||||
statusBgColor: Colors.white,
|
||||
statusBorder: true,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAccountItem({
|
||||
required IconData icon,
|
||||
required Color iconColor,
|
||||
required String title,
|
||||
required String balance,
|
||||
required String unit,
|
||||
required String status,
|
||||
required Color statusColor,
|
||||
required Color statusBgColor,
|
||||
bool statusBorder = false,
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// 图标
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: _serenade,
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
),
|
||||
child: Icon(icon, color: iconColor, size: 20),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// 内容
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF111827),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '$balance ',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _orange,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: unit,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFF9CA3AF),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// 状态标签
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: statusBgColor,
|
||||
borderRadius: BorderRadius.circular(9999),
|
||||
border: statusBorder ? Border.all(color: const Color(0xFFE5E7EB)) : null,
|
||||
),
|
||||
child: Text(
|
||||
status,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: statusColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
// 箭头
|
||||
Icon(Icons.chevron_right, size: 14, color: _grayText.withOpacity(0.5)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLoadingCard() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(32),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: const Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildErrorCard(String message) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(32),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
const Icon(Icons.error_outline, size: 48, color: AppColors.error),
|
||||
const SizedBox(height: 8),
|
||||
Text(message),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ class _LoginPageState extends ConsumerState<LoginPage> {
|
|||
}
|
||||
|
||||
if (mounted) {
|
||||
context.go(Routes.home);
|
||||
context.go(Routes.contribution);
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
|
|||
await ref.read(userNotifierProvider.notifier).register(phone, password, smsCode);
|
||||
|
||||
if (mounted) {
|
||||
context.go(Routes.home);
|
||||
context.go(Routes.contribution);
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,14 @@ import '../../providers/contribution_providers.dart';
|
|||
class ContributionPage extends ConsumerWidget {
|
||||
const ContributionPage({super.key});
|
||||
|
||||
// 设计色彩
|
||||
static const Color _orange = Color(0xFFFF6B00);
|
||||
static const Color _green = Color(0xFF22C55E);
|
||||
static const Color _grayText = Color(0xFF6B7280);
|
||||
static const Color _darkText = Color(0xFF1F2937);
|
||||
static const Color _bgGray = Color(0xFFF3F4F6);
|
||||
static const Color _lightGray = Color(0xFFF9FAFB);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final user = ref.watch(userNotifierProvider);
|
||||
|
|
@ -15,66 +23,62 @@ class ContributionPage extends ConsumerWidget {
|
|||
final contributionAsync = ref.watch(contributionProvider(accountSequence));
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('我的算力'),
|
||||
backgroundColor: AppColors.primary,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
body: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
ref.invalidate(contributionProvider(accountSequence));
|
||||
},
|
||||
child: contributionAsync.when(
|
||||
data: (contribution) {
|
||||
if (contribution == null) {
|
||||
return const Center(child: Text('暂无数据'));
|
||||
}
|
||||
return SingleChildScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: const EdgeInsets.all(16),
|
||||
backgroundColor: const Color(0xFFF5F5F5),
|
||||
body: SafeArea(
|
||||
child: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
ref.invalidate(contributionProvider(accountSequence));
|
||||
},
|
||||
child: contributionAsync.when(
|
||||
data: (contribution) {
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
// 顶部导航栏
|
||||
SliverToBoxAdapter(child: _buildAppBar(context)),
|
||||
// 内容
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildListDelegate([
|
||||
// 总贡献值卡片
|
||||
_buildTotalContributionCard(contribution),
|
||||
const SizedBox(height: 16),
|
||||
// 三栏统计
|
||||
_buildThreeColumnStats(contribution),
|
||||
const SizedBox(height: 16),
|
||||
// 今日预估收益
|
||||
_buildTodayEstimateCard(contribution),
|
||||
const SizedBox(height: 16),
|
||||
// 贡献值明细
|
||||
_buildContributionDetailCard(contribution),
|
||||
const SizedBox(height: 16),
|
||||
// 团队层级统计
|
||||
_buildTeamStatsCard(contribution),
|
||||
const SizedBox(height: 16),
|
||||
// 贡献值失效倒计时
|
||||
_buildExpirationCard(contribution),
|
||||
const SizedBox(height: 24),
|
||||
]),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error: (error, _) => Center(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// 总算力卡片
|
||||
_buildTotalCard(contribution.effectiveContribution),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 算力构成
|
||||
const Text(
|
||||
'算力构成',
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
const Icon(Icons.error_outline, size: 48, color: AppColors.error),
|
||||
const SizedBox(height: 16),
|
||||
Text('加载失败: $error'),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () => ref.invalidate(contributionProvider(accountSequence)),
|
||||
child: const Text('重试'),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildBreakdownCard(contribution),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 解锁状态
|
||||
const Text(
|
||||
'解锁状态',
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildUnlockStatus(contribution),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error: (error, _) => Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.error_outline, size: 48, color: AppColors.error),
|
||||
const SizedBox(height: 16),
|
||||
Text('加载失败: $error'),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () => ref.invalidate(contributionProvider(accountSequence)),
|
||||
child: const Text('重试'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -82,31 +86,113 @@ class ContributionPage extends ConsumerWidget {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildTotalCard(String effectiveContribution) {
|
||||
Widget _buildAppBar(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(24),
|
||||
color: _lightGray,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
// Logo
|
||||
Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: _orange.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Icon(Icons.eco, color: _orange, size: 20),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'榴莲生态',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _darkText,
|
||||
letterSpacing: 0.45,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
// 客服
|
||||
IconButton(
|
||||
icon: const Icon(Icons.headset_mic_outlined, color: _grayText),
|
||||
onPressed: () {},
|
||||
),
|
||||
// 通知(带红点)
|
||||
Stack(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.notifications_outlined, color: _grayText),
|
||||
onPressed: () {},
|
||||
),
|
||||
Positioned(
|
||||
right: 10,
|
||||
top: 10,
|
||||
child: Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.red,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTotalContributionCard(contribution) {
|
||||
final total = contribution?.effectiveContribution ?? '0';
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [AppColors.primary, Color(0xFF16A34A)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'有效算力',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 14),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'总贡献值',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: _grayText),
|
||||
),
|
||||
Icon(Icons.visibility_outlined, color: _grayText.withOpacity(0.5), size: 18),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
formatAmount(effectiveContribution),
|
||||
formatAmount(total),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 42,
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _orange,
|
||||
letterSpacing: -0.75,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// 有效期标签
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: _lightGray,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.info_outline, size: 14, color: _grayText.withOpacity(0.7)),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'贡献值有效期: 剩余 730 天',
|
||||
style: TextStyle(fontSize: 12, color: _grayText.withOpacity(0.9)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -114,38 +200,39 @@ class ContributionPage extends ConsumerWidget {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildBreakdownCard(contribution) {
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
Widget _buildThreeColumnStats(contribution) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildStatColumn('个人贡献值', contribution?.personalContribution ?? '0', false),
|
||||
_buildStatColumn('团队贡献值', contribution?.teamLevelContribution ?? '0', true),
|
||||
_buildStatColumn('省市公司', contribution?.systemContribution ?? '0', true),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatColumn(String label, String value, bool showLeftBorder) {
|
||||
return Expanded(
|
||||
child: Container(
|
||||
decoration: showLeftBorder
|
||||
? const BoxDecoration(
|
||||
border: Border(left: BorderSide(color: Color(0xFFE5E7EB), width: 1)),
|
||||
)
|
||||
: null,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildBreakdownRow(
|
||||
'个人算力',
|
||||
contribution.personalContribution,
|
||||
'70%',
|
||||
AppColors.primary,
|
||||
),
|
||||
const Divider(),
|
||||
_buildBreakdownRow(
|
||||
'系统算力',
|
||||
contribution.systemContribution,
|
||||
'15%',
|
||||
AppColors.secondary,
|
||||
),
|
||||
const Divider(),
|
||||
_buildBreakdownRow(
|
||||
'团队层级',
|
||||
contribution.teamLevelContribution,
|
||||
'7.5%',
|
||||
AppColors.warning,
|
||||
),
|
||||
const Divider(),
|
||||
_buildBreakdownRow(
|
||||
'团队奖励',
|
||||
contribution.teamBonusContribution,
|
||||
'7.5%',
|
||||
Colors.purple,
|
||||
Text(label, style: const TextStyle(fontSize: 12, color: _grayText)),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
formatAmount(value),
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: _darkText),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -153,70 +240,191 @@ class ContributionPage extends ConsumerWidget {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildBreakdownRow(String label, String value, String rate, Color color) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
Widget _buildTodayEstimateCard(contribution) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// 图标
|
||||
Container(
|
||||
width: 4,
|
||||
height: 24,
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
color: _green.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: const Icon(Icons.trending_up, color: _green, size: 24),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// 文字说明
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(label, style: const TextStyle(fontSize: 14)),
|
||||
const Text(
|
||||
'今日预估收益',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: _grayText),
|
||||
),
|
||||
Text(
|
||||
'占比 $rate',
|
||||
style: const TextStyle(color: AppColors.textMuted, fontSize: 12),
|
||||
'基于当前贡献值占比计算',
|
||||
style: TextStyle(fontSize: 12, color: _grayText.withOpacity(0.7)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Text(
|
||||
formatAmount(value),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
|
||||
// 收益数值
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: const [
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '+156.78 ',
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: _green),
|
||||
),
|
||||
TextSpan(
|
||||
text: '积分',
|
||||
style: TextStyle(fontSize: 12, color: _green),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Text('股', style: TextStyle(fontSize: 12, color: _green)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUnlockStatus(contribution) {
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildUnlockRow(
|
||||
'已解锁层级',
|
||||
'${contribution.unlockedLevelDepth}/15 层',
|
||||
contribution.unlockedLevelDepth / 15,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildUnlockRow(
|
||||
'已解锁奖励档',
|
||||
'${contribution.unlockedBonusTiers}/3 档',
|
||||
contribution.unlockedBonusTiers / 3,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.info_outline, size: 16, color: AppColors.textMuted),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'直推认种人数: ${contribution.directReferralAdoptedCount}',
|
||||
style: const TextStyle(color: AppColors.textMuted, fontSize: 12),
|
||||
),
|
||||
Widget _buildContributionDetailCard(contribution) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// 标题行
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'贡献值明细',
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: _darkText),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Row(
|
||||
children: const [
|
||||
Text('查看全部', style: TextStyle(fontSize: 12, color: _orange)),
|
||||
Icon(Icons.chevron_right, size: 14, color: _orange),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// 明细列表
|
||||
_buildDetailRow('认种榴莲树', '2024-01-15 14:30', '+22,617.00'),
|
||||
const Divider(height: 24),
|
||||
_buildDetailRow('团队奖励(5级)', '2024-01-15 09:12', '+1,130.85'),
|
||||
const Divider(height: 24),
|
||||
_buildDetailRow('直推奖励', '2024-01-14 18:45', '+565.43'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDetailRow(String title, String time, String amount) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: _darkText)),
|
||||
const SizedBox(height: 2),
|
||||
Text(time, style: const TextStyle(fontSize: 12, color: _grayText)),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
amount,
|
||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: _green),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTeamStatsCard(contribution) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'团队层级统计',
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: _darkText),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// 第一行
|
||||
Row(
|
||||
children: [
|
||||
_buildTeamStatItem('直推人数', '${contribution?.directReferralAdoptedCount ?? 0}', '人'),
|
||||
const SizedBox(width: 16),
|
||||
_buildTeamStatItem('团队总人数', '128', '人'),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// 第二行
|
||||
Row(
|
||||
children: [
|
||||
_buildTeamStatItem('已解锁层级', '${contribution?.unlockedLevelDepth ?? 0}', '级'),
|
||||
const SizedBox(width: 16),
|
||||
_buildTeamStatItem('团队认种总数', '456', '棵'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTeamStatItem(String label, String value, String unit) {
|
||||
return Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: _bgGray,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(label, style: const TextStyle(fontSize: 12, color: _grayText)),
|
||||
const SizedBox(height: 4),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '$value ',
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: _orange),
|
||||
),
|
||||
TextSpan(
|
||||
text: unit,
|
||||
style: const TextStyle(fontSize: 12, color: _grayText),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -224,24 +432,59 @@ class ContributionPage extends ConsumerWidget {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildUnlockRow(String label, String value, double progress) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(label),
|
||||
Text(value, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
LinearProgressIndicator(
|
||||
value: progress,
|
||||
backgroundColor: AppColors.border,
|
||||
valueColor: const AlwaysStoppedAnimation<Color>(AppColors.primary),
|
||||
),
|
||||
],
|
||||
Widget _buildExpirationCard(contribution) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 标题
|
||||
Row(
|
||||
children: const [
|
||||
Icon(Icons.timer_outlined, color: _orange, size: 24),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'贡献值失效倒计时',
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: _darkText),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// 进度条
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
child: LinearProgressIndicator(
|
||||
value: 0.8,
|
||||
minHeight: 10,
|
||||
backgroundColor: _bgGray,
|
||||
valueColor: const AlwaysStoppedAnimation<Color>(_orange),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// 说明文字
|
||||
const Text(
|
||||
'您的贡献值将于 2026-01-15 失效',
|
||||
style: TextStyle(fontSize: 12, color: _grayText),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// 提示
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: _bgGray,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: const Text(
|
||||
'* 运营账号贡献值永不失效',
|
||||
style: TextStyle(fontSize: 10, color: _orange),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,206 +1,708 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import '../../../core/constants/app_colors.dart';
|
||||
import '../../../core/router/routes.dart';
|
||||
import '../../providers/user_providers.dart';
|
||||
|
||||
class ProfilePage extends ConsumerWidget {
|
||||
const ProfilePage({super.key});
|
||||
|
||||
// 设计色彩
|
||||
static const Color _orange = Color(0xFFFF6B00);
|
||||
static const Color _green = Color(0xFF10B981);
|
||||
static const Color _darkText = Color(0xFF1F2937);
|
||||
static const Color _grayText = Color(0xFF6B7280);
|
||||
static const Color _lightGray = Color(0xFF9CA3AF);
|
||||
static const Color _bgGray = Color(0xFFF3F4F6);
|
||||
static const Color _red = Color(0xFFEF4444);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final user = ref.watch(userNotifierProvider);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('我的'),
|
||||
backgroundColor: AppColors.primary,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
// 用户信息卡片
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [AppColors.primary, Color(0xFF16A34A)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
backgroundColor: _bgGray,
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
// 用户头部信息
|
||||
_buildUserHeader(context, user),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 统计数据行
|
||||
_buildStatsRow(),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 邀请码卡片
|
||||
_buildInvitationCard(context),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 账户设置
|
||||
_buildAccountSettings(context),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 记录入口
|
||||
_buildRecordsSection(context),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 团队与收益
|
||||
_buildTeamEarningsSection(context),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 其他设置
|
||||
_buildOtherSettings(context),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 退出登录
|
||||
_buildLogoutButton(context, ref),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 版本信息
|
||||
const Text(
|
||||
'Version 1.0.0',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: _lightGray,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 40,
|
||||
backgroundColor: Colors.white,
|
||||
child: Text(
|
||||
user.nickname?.substring(0, 1) ?? 'U',
|
||||
style: const TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
user.nickname ?? '未设置昵称',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'账户序列: ${user.accountSequence ?? '-'}',
|
||||
style: const TextStyle(color: Colors.white70, fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 菜单列表
|
||||
_buildMenuSection(
|
||||
title: '资产管理',
|
||||
items: [
|
||||
_MenuItem(
|
||||
icon: Icons.history,
|
||||
label: '挖矿记录',
|
||||
onTap: () {},
|
||||
),
|
||||
_MenuItem(
|
||||
icon: Icons.receipt_long,
|
||||
label: '交易记录',
|
||||
onTap: () {},
|
||||
),
|
||||
_MenuItem(
|
||||
icon: Icons.swap_vert,
|
||||
label: '划转记录',
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
_buildMenuSection(
|
||||
title: '账户设置',
|
||||
items: [
|
||||
_MenuItem(
|
||||
icon: Icons.person_outline,
|
||||
label: '个人信息',
|
||||
onTap: () {},
|
||||
),
|
||||
_MenuItem(
|
||||
icon: Icons.lock_outline,
|
||||
label: '修改密码',
|
||||
onTap: () => context.push(Routes.changePassword),
|
||||
),
|
||||
_MenuItem(
|
||||
icon: Icons.security,
|
||||
label: '安全设置',
|
||||
onTap: () {},
|
||||
),
|
||||
_MenuItem(
|
||||
icon: Icons.notifications_outlined,
|
||||
label: '消息通知',
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
_buildMenuSection(
|
||||
title: '其他',
|
||||
items: [
|
||||
_MenuItem(
|
||||
icon: Icons.help_outline,
|
||||
label: '帮助中心',
|
||||
onTap: () {},
|
||||
),
|
||||
_MenuItem(
|
||||
icon: Icons.info_outline,
|
||||
label: '关于我们',
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 退出登录
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
ref.read(userNotifierProvider.notifier).logout();
|
||||
},
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: AppColors.error,
|
||||
side: const BorderSide(color: AppColors.error),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
),
|
||||
child: const Text('退出登录'),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 32),
|
||||
],
|
||||
const SizedBox(height: 32),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMenuSection({
|
||||
required String title,
|
||||
required List<_MenuItem> items,
|
||||
}) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||
child: Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
color: AppColors.textSecondary,
|
||||
fontSize: 12,
|
||||
Widget _buildUserHeader(BuildContext context, dynamic user) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
color: Colors.white,
|
||||
child: Row(
|
||||
children: [
|
||||
// 头像
|
||||
Container(
|
||||
width: 80,
|
||||
height: 80,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: LinearGradient(
|
||||
colors: [_orange.withValues(alpha: 0.8), _orange],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
user.nickname?.isNotEmpty == true
|
||||
? user.nickname!.substring(0, 1).toUpperCase()
|
||||
: 'U',
|
||||
style: const TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(width: 16),
|
||||
|
||||
// 用户信息
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
user.nickname ?? '榴莲用户',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _darkText,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
// VIP 徽章
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFFFFD700), Color(0xFFFF8C00)],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: const Text(
|
||||
'VIP 3',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'ID: ${user.accountSequence ?? '--------'}',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: _grayText,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (user.accountSequence != null) {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: user.accountSequence!),
|
||||
);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('ID已复制'),
|
||||
duration: Duration(seconds: 1),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Icon(
|
||||
Icons.copy,
|
||||
size: 16,
|
||||
color: _grayText,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// 编辑按钮
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
// TODO: 编辑个人资料
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.edit_outlined,
|
||||
color: _grayText,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatsRow() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
color: Colors.white,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildStatItem('认种数量', '10'),
|
||||
_buildDivider(),
|
||||
_buildStatItem('直推人数', '5'),
|
||||
_buildDivider(),
|
||||
_buildStatItem('团队人数', '128'),
|
||||
_buildDivider(),
|
||||
_buildStatItem('VIP等级', 'V3'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatItem(String label, String value) {
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _darkText,
|
||||
),
|
||||
),
|
||||
Card(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
children: items.map((item) => _buildMenuItem(item)).toList(),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: _grayText,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMenuItem(_MenuItem item) {
|
||||
return ListTile(
|
||||
leading: Icon(item.icon, color: AppColors.textSecondary),
|
||||
title: Text(item.label),
|
||||
trailing: const Icon(Icons.chevron_right, color: AppColors.textMuted),
|
||||
onTap: item.onTap,
|
||||
Widget _buildDivider() {
|
||||
return Container(
|
||||
width: 1,
|
||||
height: 30,
|
||||
color: _bgGray,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInvitationCard(BuildContext context) {
|
||||
const invitationCode = 'DUR8888XYZ';
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'我的邀请码',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: _grayText,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 12,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _bgGray,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Text(
|
||||
invitationCode,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _darkText,
|
||||
letterSpacing: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_buildActionButton(
|
||||
icon: Icons.copy,
|
||||
label: '复制',
|
||||
onTap: () {
|
||||
Clipboard.setData(const ClipboardData(text: invitationCode));
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('邀请码已复制'),
|
||||
duration: Duration(seconds: 1),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_buildActionButton(
|
||||
icon: Icons.share,
|
||||
label: '分享',
|
||||
onTap: () {
|
||||
// TODO: 分享功能
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActionButton({
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: _orange,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, size: 16, color: Colors.white),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAccountSettings(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||
child: Text(
|
||||
'账户设置',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _darkText,
|
||||
),
|
||||
),
|
||||
),
|
||||
_buildSettingItem(
|
||||
icon: Icons.security,
|
||||
label: '账户安全',
|
||||
onTap: () => context.push(Routes.changePassword),
|
||||
),
|
||||
_buildSettingItem(
|
||||
icon: Icons.verified_user,
|
||||
label: '实名认证',
|
||||
trailing: const Text(
|
||||
'已认证',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: _green,
|
||||
),
|
||||
),
|
||||
onTap: () {},
|
||||
),
|
||||
_buildSettingItem(
|
||||
icon: Icons.lock_outline,
|
||||
label: '支付密码',
|
||||
trailing: const Text(
|
||||
'已设置',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: _green,
|
||||
),
|
||||
),
|
||||
onTap: () {},
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSettingItem({
|
||||
required IconData icon,
|
||||
required String label,
|
||||
Widget? trailing,
|
||||
required VoidCallback onTap,
|
||||
bool showDivider = true,
|
||||
}) {
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: Icon(icon, color: _grayText, size: 22),
|
||||
title: Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: _darkText,
|
||||
),
|
||||
),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (trailing != null) trailing,
|
||||
if (trailing != null) const SizedBox(width: 8),
|
||||
const Icon(Icons.chevron_right, color: _lightGray, size: 20),
|
||||
],
|
||||
),
|
||||
onTap: onTap,
|
||||
),
|
||||
if (showDivider)
|
||||
const Divider(height: 1, indent: 56, endIndent: 16),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRecordsSection(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'我的记录',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _darkText,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_buildRecordIcon(
|
||||
icon: Icons.eco,
|
||||
label: '认种记录',
|
||||
onTap: () {},
|
||||
),
|
||||
_buildRecordIcon(
|
||||
icon: Icons.assignment,
|
||||
label: '分配记录',
|
||||
onTap: () {},
|
||||
),
|
||||
_buildRecordIcon(
|
||||
icon: Icons.receipt_long,
|
||||
label: '交易记录',
|
||||
onTap: () {},
|
||||
),
|
||||
_buildRecordIcon(
|
||||
icon: Icons.account_balance_wallet,
|
||||
label: '提现记录',
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRecordIcon({
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: _orange.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Icon(icon, color: _orange, size: 24),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: _grayText,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTeamEarningsSection(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||
child: Text(
|
||||
'团队与收益',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _darkText,
|
||||
),
|
||||
),
|
||||
),
|
||||
_buildSettingItem(
|
||||
icon: Icons.people,
|
||||
label: '我的团队',
|
||||
onTap: () {},
|
||||
),
|
||||
_buildSettingItem(
|
||||
icon: Icons.trending_up,
|
||||
label: '收益明细',
|
||||
onTap: () {},
|
||||
),
|
||||
_buildSettingItem(
|
||||
icon: Icons.card_giftcard,
|
||||
label: '推广奖励',
|
||||
onTap: () {},
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOtherSettings(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||
child: Text(
|
||||
'其他设置',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _darkText,
|
||||
),
|
||||
),
|
||||
),
|
||||
_buildSwitchItem(
|
||||
icon: Icons.notifications_outlined,
|
||||
label: '消息通知',
|
||||
value: true,
|
||||
onChanged: (value) {},
|
||||
),
|
||||
_buildSwitchItem(
|
||||
icon: Icons.dark_mode_outlined,
|
||||
label: '深色模式',
|
||||
value: false,
|
||||
onChanged: (value) {},
|
||||
),
|
||||
_buildSettingItem(
|
||||
icon: Icons.help_outline,
|
||||
label: '帮助中心',
|
||||
onTap: () {},
|
||||
),
|
||||
_buildSettingItem(
|
||||
icon: Icons.info_outline,
|
||||
label: '关于我们',
|
||||
onTap: () {},
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSwitchItem({
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required bool value,
|
||||
required ValueChanged<bool> onChanged,
|
||||
}) {
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: Icon(icon, color: _grayText, size: 22),
|
||||
title: Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: _darkText,
|
||||
),
|
||||
),
|
||||
trailing: Switch(
|
||||
value: value,
|
||||
onChanged: onChanged,
|
||||
activeTrackColor: _orange,
|
||||
activeThumbColor: Colors.white,
|
||||
),
|
||||
),
|
||||
const Divider(height: 1, indent: 56, endIndent: 16),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLogoutButton(BuildContext context, WidgetRef ref) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('退出登录'),
|
||||
content: const Text('确定要退出登录吗?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('取消'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
ref.read(userNotifierProvider.notifier).logout();
|
||||
},
|
||||
child: const Text(
|
||||
'确定',
|
||||
style: TextStyle(color: _red),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'退出登录',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: _red,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MenuItem {
|
||||
final IconData icon;
|
||||
final String label;
|
||||
final VoidCallback onTap;
|
||||
|
||||
_MenuItem({
|
||||
required this.icon,
|
||||
required this.label,
|
||||
required this.onTap,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,38 +1,112 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import '../../core/router/routes.dart';
|
||||
import '../../core/constants/app_colors.dart';
|
||||
|
||||
class MainShell extends StatelessWidget {
|
||||
final Widget child;
|
||||
|
||||
const MainShell({super.key, required this.child});
|
||||
|
||||
// 设计色彩
|
||||
static const Color _orange = Color(0xFFFF6B00);
|
||||
static const Color _grayText = Color(0xFF9CA3AF);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: child,
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
type: BottomNavigationBarType.fixed,
|
||||
selectedItemColor: AppColors.primary,
|
||||
unselectedItemColor: AppColors.textMuted,
|
||||
items: const [
|
||||
BottomNavigationBarItem(icon: Icon(Icons.home_outlined), activeIcon: Icon(Icons.home), label: '首页'),
|
||||
BottomNavigationBarItem(icon: Icon(Icons.analytics_outlined), activeIcon: Icon(Icons.analytics), label: '算力'),
|
||||
BottomNavigationBarItem(icon: Icon(Icons.swap_horiz_outlined), activeIcon: Icon(Icons.swap_horiz), label: '兑换'),
|
||||
BottomNavigationBarItem(icon: Icon(Icons.person_outline), activeIcon: Icon(Icons.person), label: '我的'),
|
||||
],
|
||||
currentIndex: _calculateSelectedIndex(context),
|
||||
onTap: (index) => _onItemTapped(index, context),
|
||||
bottomNavigationBar: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border(
|
||||
top: BorderSide(color: Color(0xFFF3F4F6), width: 1),
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_buildNavItem(
|
||||
context,
|
||||
icon: Icons.favorite_outline,
|
||||
activeIcon: Icons.favorite,
|
||||
label: '贡献值',
|
||||
index: 0,
|
||||
),
|
||||
_buildNavItem(
|
||||
context,
|
||||
icon: Icons.swap_horiz_outlined,
|
||||
activeIcon: Icons.swap_horiz,
|
||||
label: '兑换',
|
||||
index: 1,
|
||||
),
|
||||
_buildNavItem(
|
||||
context,
|
||||
icon: Icons.account_balance_wallet_outlined,
|
||||
activeIcon: Icons.account_balance_wallet,
|
||||
label: '资产',
|
||||
index: 2,
|
||||
),
|
||||
_buildNavItem(
|
||||
context,
|
||||
icon: Icons.person_outline,
|
||||
activeIcon: Icons.person,
|
||||
label: '我的',
|
||||
index: 3,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNavItem(
|
||||
BuildContext context, {
|
||||
required IconData icon,
|
||||
required IconData activeIcon,
|
||||
required String label,
|
||||
required int index,
|
||||
}) {
|
||||
final currentIndex = _calculateSelectedIndex(context);
|
||||
final isSelected = currentIndex == index;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => _onItemTapped(index, context),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
isSelected ? activeIcon : icon,
|
||||
size: 24,
|
||||
color: isSelected ? _orange : _grayText,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: isSelected ? FontWeight.w500 : FontWeight.normal,
|
||||
color: isSelected ? _orange : _grayText,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
int _calculateSelectedIndex(BuildContext context) {
|
||||
final location = GoRouterState.of(context).uri.path;
|
||||
if (location.startsWith(Routes.home)) return 0;
|
||||
if (location.startsWith(Routes.contribution)) return 1;
|
||||
if (location.startsWith(Routes.trading)) return 2;
|
||||
if (location.startsWith(Routes.contribution)) return 0;
|
||||
if (location.startsWith(Routes.trading)) return 1;
|
||||
if (location.startsWith(Routes.asset)) return 2;
|
||||
if (location.startsWith(Routes.profile)) return 3;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -40,14 +114,14 @@ class MainShell extends StatelessWidget {
|
|||
void _onItemTapped(int index, BuildContext context) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
context.go(Routes.home);
|
||||
break;
|
||||
case 1:
|
||||
context.go(Routes.contribution);
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
context.go(Routes.trading);
|
||||
break;
|
||||
case 2:
|
||||
context.go(Routes.asset);
|
||||
break;
|
||||
case 3:
|
||||
context.go(Routes.profile);
|
||||
break;
|
||||
|
|
|
|||
Loading…
Reference in New Issue