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/home/home_page.dart';
|
||||||
import '../../presentation/pages/contribution/contribution_page.dart';
|
import '../../presentation/pages/contribution/contribution_page.dart';
|
||||||
import '../../presentation/pages/trading/trading_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/pages/profile/profile_page.dart';
|
||||||
import '../../presentation/widgets/main_shell.dart';
|
import '../../presentation/widgets/main_shell.dart';
|
||||||
import 'routes.dart';
|
import 'routes.dart';
|
||||||
|
|
@ -51,6 +52,10 @@ final appRouterProvider = Provider<GoRouter>((ref) {
|
||||||
path: Routes.trading,
|
path: Routes.trading,
|
||||||
builder: (context, state) => const TradingPage(),
|
builder: (context, state) => const TradingPage(),
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: Routes.asset,
|
||||||
|
builder: (context, state) => const AssetPage(),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: Routes.profile,
|
path: Routes.profile,
|
||||||
builder: (context, state) => const ProfilePage(),
|
builder: (context, state) => const ProfilePage(),
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ class Routes {
|
||||||
static const String home = '/home';
|
static const String home = '/home';
|
||||||
static const String contribution = '/contribution';
|
static const String contribution = '/contribution';
|
||||||
static const String trading = '/trading';
|
static const String trading = '/trading';
|
||||||
|
static const String asset = '/asset';
|
||||||
static const String profile = '/profile';
|
static const String profile = '/profile';
|
||||||
static const String miningRecords = '/mining-records';
|
static const String miningRecords = '/mining-records';
|
||||||
static const String contributionRecords = '/contribution-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) {
|
if (mounted) {
|
||||||
context.go(Routes.home);
|
context.go(Routes.contribution);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
|
||||||
await ref.read(userNotifierProvider.notifier).register(phone, password, smsCode);
|
await ref.read(userNotifierProvider.notifier).register(phone, password, smsCode);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
context.go(Routes.home);
|
context.go(Routes.contribution);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,14 @@ import '../../providers/contribution_providers.dart';
|
||||||
class ContributionPage extends ConsumerWidget {
|
class ContributionPage extends ConsumerWidget {
|
||||||
const ContributionPage({super.key});
|
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
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final user = ref.watch(userNotifierProvider);
|
final user = ref.watch(userNotifierProvider);
|
||||||
|
|
@ -15,50 +23,45 @@ class ContributionPage extends ConsumerWidget {
|
||||||
final contributionAsync = ref.watch(contributionProvider(accountSequence));
|
final contributionAsync = ref.watch(contributionProvider(accountSequence));
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
backgroundColor: const Color(0xFFF5F5F5),
|
||||||
title: const Text('我的算力'),
|
body: SafeArea(
|
||||||
backgroundColor: AppColors.primary,
|
child: RefreshIndicator(
|
||||||
foregroundColor: Colors.white,
|
|
||||||
),
|
|
||||||
body: RefreshIndicator(
|
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
ref.invalidate(contributionProvider(accountSequence));
|
ref.invalidate(contributionProvider(accountSequence));
|
||||||
},
|
},
|
||||||
child: contributionAsync.when(
|
child: contributionAsync.when(
|
||||||
data: (contribution) {
|
data: (contribution) {
|
||||||
if (contribution == null) {
|
return CustomScrollView(
|
||||||
return const Center(child: Text('暂无数据'));
|
slivers: [
|
||||||
}
|
// 顶部导航栏
|
||||||
return SingleChildScrollView(
|
SliverToBoxAdapter(child: _buildAppBar(context)),
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
// 内容
|
||||||
|
SliverPadding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
sliver: SliverList(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
delegate: SliverChildListDelegate([
|
||||||
children: [
|
// 总贡献值卡片
|
||||||
// 总算力卡片
|
_buildTotalContributionCard(contribution),
|
||||||
_buildTotalCard(contribution.effectiveContribution),
|
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),
|
const SizedBox(height: 24),
|
||||||
|
]),
|
||||||
// 算力构成
|
|
||||||
const Text(
|
|
||||||
'算力构成',
|
|
||||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
||||||
),
|
),
|
||||||
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()),
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
|
|
@ -79,169 +82,409 @@ class ContributionPage extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTotalCard(String effectiveContribution) {
|
Widget _buildAppBar(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
color: _lightGray,
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
// Logo
|
||||||
|
Container(
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: const LinearGradient(
|
color: _orange.withOpacity(0.1),
|
||||||
colors: [AppColors.primary, Color(0xFF16A34A)],
|
borderRadius: BorderRadius.circular(8),
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
),
|
),
|
||||||
|
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(
|
||||||
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
|
||||||
const Text(
|
|
||||||
'有效算力',
|
|
||||||
style: TextStyle(color: Colors.white70, fontSize: 14),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
formatAmount(effectiveContribution),
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 42,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildBreakdownCard(contribution) {
|
|
||||||
return Card(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
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,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildBreakdownRow(String label, String value, String rate, Color color) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: 4,
|
|
||||||
height: 24,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: color,
|
|
||||||
borderRadius: BorderRadius.circular(2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(label, style: const TextStyle(fontSize: 14)),
|
|
||||||
Text(
|
|
||||||
'占比 $rate',
|
|
||||||
style: const TextStyle(color: AppColors.textMuted, fontSize: 12),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
formatAmount(value),
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 _buildUnlockRow(String label, String value, double progress) {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(label),
|
const Text(
|
||||||
Text(value, style: const TextStyle(fontWeight: FontWeight.bold)),
|
'总贡献值',
|
||||||
|
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: _grayText),
|
||||||
|
),
|
||||||
|
Icon(Icons.visibility_outlined, color: _grayText.withOpacity(0.5), size: 18),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
LinearProgressIndicator(
|
Text(
|
||||||
value: progress,
|
formatAmount(total),
|
||||||
backgroundColor: AppColors.border,
|
style: const TextStyle(
|
||||||
valueColor: const AlwaysStoppedAnimation<Color>(AppColors.primary),
|
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)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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: [
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTodayEstimateCard(contribution) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
// 图标
|
||||||
|
Container(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
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: [
|
||||||
|
const Text(
|
||||||
|
'今日预估收益',
|
||||||
|
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: _grayText),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'基于当前贡献值占比计算',
|
||||||
|
style: TextStyle(fontSize: 12, color: _grayText.withOpacity(0.7)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// 收益数值
|
||||||
|
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 _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),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,151 +1,78 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import '../../../core/constants/app_colors.dart';
|
|
||||||
import '../../../core/router/routes.dart';
|
import '../../../core/router/routes.dart';
|
||||||
import '../../providers/user_providers.dart';
|
import '../../providers/user_providers.dart';
|
||||||
|
|
||||||
class ProfilePage extends ConsumerWidget {
|
class ProfilePage extends ConsumerWidget {
|
||||||
const ProfilePage({super.key});
|
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
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final user = ref.watch(userNotifierProvider);
|
final user = ref.watch(userNotifierProvider);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
backgroundColor: _bgGray,
|
||||||
title: const Text('我的'),
|
body: SafeArea(
|
||||||
backgroundColor: AppColors.primary,
|
child: SingleChildScrollView(
|
||||||
foregroundColor: Colors.white,
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// 用户信息卡片
|
// 用户头部信息
|
||||||
Container(
|
_buildUserHeader(context, user),
|
||||||
width: double.infinity,
|
|
||||||
padding: const EdgeInsets.all(24),
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
colors: [AppColors.primary, Color(0xFF16A34A)],
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
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),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// 菜单列表
|
// 统计数据行
|
||||||
_buildMenuSection(
|
_buildStatsRow(),
|
||||||
title: '资产管理',
|
|
||||||
items: [
|
|
||||||
_MenuItem(
|
|
||||||
icon: Icons.history,
|
|
||||||
label: '挖矿记录',
|
|
||||||
onTap: () {},
|
|
||||||
),
|
|
||||||
_MenuItem(
|
|
||||||
icon: Icons.receipt_long,
|
|
||||||
label: '交易记录',
|
|
||||||
onTap: () {},
|
|
||||||
),
|
|
||||||
_MenuItem(
|
|
||||||
icon: Icons.swap_vert,
|
|
||||||
label: '划转记录',
|
|
||||||
onTap: () {},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
_buildMenuSection(
|
const SizedBox(height: 16),
|
||||||
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: '其他',
|
_buildInvitationCard(context),
|
||||||
items: [
|
|
||||||
_MenuItem(
|
const SizedBox(height: 16),
|
||||||
icon: Icons.help_outline,
|
|
||||||
label: '帮助中心',
|
// 账户设置
|
||||||
onTap: () {},
|
_buildAccountSettings(context),
|
||||||
),
|
|
||||||
_MenuItem(
|
const SizedBox(height: 16),
|
||||||
icon: Icons.info_outline,
|
|
||||||
label: '关于我们',
|
// 记录入口
|
||||||
onTap: () {},
|
_buildRecordsSection(context),
|
||||||
),
|
|
||||||
],
|
const SizedBox(height: 16),
|
||||||
),
|
|
||||||
|
// 团队与收益
|
||||||
|
_buildTeamEarningsSection(context),
|
||||||
|
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
// 其他设置
|
||||||
|
_buildOtherSettings(context),
|
||||||
|
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
// 退出登录
|
// 退出登录
|
||||||
Padding(
|
_buildLogoutButton(context, ref),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
||||||
child: OutlinedButton(
|
const SizedBox(height: 16),
|
||||||
onPressed: () {
|
|
||||||
ref.read(userNotifierProvider.notifier).logout();
|
// 版本信息
|
||||||
},
|
const Text(
|
||||||
style: OutlinedButton.styleFrom(
|
'Version 1.0.0',
|
||||||
foregroundColor: AppColors.error,
|
style: TextStyle(
|
||||||
side: const BorderSide(color: AppColors.error),
|
fontSize: 12,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
color: _lightGray,
|
||||||
minimumSize: const Size(double.infinity, 48),
|
|
||||||
),
|
|
||||||
child: const Text('退出登录'),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
@ -153,54 +80,629 @@ class ProfilePage extends ConsumerWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMenuSection({
|
Widget _buildUserHeader(BuildContext context, dynamic user) {
|
||||||
required String title,
|
return Container(
|
||||||
required List<_MenuItem> items,
|
padding: const EdgeInsets.all(20),
|
||||||
}) {
|
color: Colors.white,
|
||||||
return Column(
|
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,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Row(
|
||||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
|
children: [
|
||||||
child: Text(
|
Text(
|
||||||
title,
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: AppColors.textSecondary,
|
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
color: _grayText,
|
||||||
),
|
|
||||||
),
|
|
||||||
Card(
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
|
||||||
child: Column(
|
|
||||||
children: items.map((item) => _buildMenuItem(item)).toList(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMenuItem(_MenuItem item) {
|
Widget _buildDivider() {
|
||||||
return ListTile(
|
return Container(
|
||||||
leading: Icon(item.icon, color: AppColors.textSecondary),
|
width: 1,
|
||||||
title: Text(item.label),
|
height: 30,
|
||||||
trailing: const Icon(Icons.chevron_right, color: AppColors.textMuted),
|
color: _bgGray,
|
||||||
onTap: item.onTap,
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import '../../core/router/routes.dart';
|
import '../../core/router/routes.dart';
|
||||||
import '../../core/constants/app_colors.dart';
|
|
||||||
|
|
||||||
class MainShell extends StatelessWidget {
|
class MainShell extends StatelessWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
const MainShell({super.key, required this.child});
|
const MainShell({super.key, required this.child});
|
||||||
|
|
||||||
|
// 设计色彩
|
||||||
|
static const Color _orange = Color(0xFFFF6B00);
|
||||||
|
static const Color _grayText = Color(0xFF9CA3AF);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: child,
|
body: child,
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
bottomNavigationBar: Container(
|
||||||
type: BottomNavigationBarType.fixed,
|
decoration: const BoxDecoration(
|
||||||
selectedItemColor: AppColors.primary,
|
color: Colors.white,
|
||||||
unselectedItemColor: AppColors.textMuted,
|
border: Border(
|
||||||
items: const [
|
top: BorderSide(color: Color(0xFFF3F4F6), width: 1),
|
||||||
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: '兑换'),
|
child: SafeArea(
|
||||||
BottomNavigationBarItem(icon: Icon(Icons.person_outline), activeIcon: Icon(Icons.person), label: '我的'),
|
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,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
currentIndex: _calculateSelectedIndex(context),
|
),
|
||||||
onTap: (index) => _onItemTapped(index, context),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
int _calculateSelectedIndex(BuildContext context) {
|
||||||
final location = GoRouterState.of(context).uri.path;
|
final location = GoRouterState.of(context).uri.path;
|
||||||
if (location.startsWith(Routes.home)) return 0;
|
if (location.startsWith(Routes.contribution)) return 0;
|
||||||
if (location.startsWith(Routes.contribution)) return 1;
|
if (location.startsWith(Routes.trading)) return 1;
|
||||||
if (location.startsWith(Routes.trading)) return 2;
|
if (location.startsWith(Routes.asset)) return 2;
|
||||||
if (location.startsWith(Routes.profile)) return 3;
|
if (location.startsWith(Routes.profile)) return 3;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -40,14 +114,14 @@ class MainShell extends StatelessWidget {
|
||||||
void _onItemTapped(int index, BuildContext context) {
|
void _onItemTapped(int index, BuildContext context) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
context.go(Routes.home);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
context.go(Routes.contribution);
|
context.go(Routes.contribution);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 1:
|
||||||
context.go(Routes.trading);
|
context.go(Routes.trading);
|
||||||
break;
|
break;
|
||||||
|
case 2:
|
||||||
|
context.go(Routes.asset);
|
||||||
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
context.go(Routes.profile);
|
context.go(Routes.profile);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue