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

View File

@@ -13,7 +13,7 @@ import 'components/records_link_row.dart';
import '../orders/fund_orders_page.dart';
import 'transfer_page.dart';
/// 资产页面 - Matching .pen design spec (CMcqs)
/// 資產頁面 - Matching .pen design spec (CMcqs)
class AssetPage extends StatefulWidget {
const AssetPage({super.key});
@@ -78,24 +78,24 @@ class _AssetPageState extends State<AssetPage> with AutomaticKeepAliveClientMixi
Padding(
padding: const EdgeInsets.only(top: 16, bottom: 8),
child: Text(
'资产',
'資產',
style: AppTextStyles.displaySmall(context),
),
),
const SizedBox(height: AppSpacing.sm),
// 资金账户 + 交易账户 左右
// 資金賬戶 + 交易賬戶 左右
Row(
children: [
Expanded(
child: BalanceCard(
label: '资金账户',
label: '資金賬戶',
balance: provider.fundAccount?.balance ?? provider.overview?.fundBalance ?? '0.00',
),
),
const SizedBox(width: AppSpacing.sm),
Expanded(
child: BalanceCard(
label: '交易账户',
label: '交易賬戶',
balance: _calculateTradeTotal(provider),
),
),

View File

@@ -3,7 +3,7 @@ import '../../../../core/theme/app_theme.dart';
import '../../../../core/theme/app_theme_extension.dart';
import '../../../../core/theme/app_spacing.dart';
/// 账户标签切换器 — .pen node UE6xC
/// 賬戶標籤切換器 — .pen node UE6xC
/// height: 40, padding: 3, cornerRadius: md, fill: $bg-tertiary
/// activeTab: fill $bg-primary, cornerRadius sm, shadow blur 3, color #0000000D, offset y 1
/// activeTabText: 14px, fontWeight 600, fill $text-primary
@@ -31,13 +31,13 @@ class AccountTabSwitcher extends StatelessWidget {
children: [
_buildTab(
context: context,
label: '资金账户',
label: '資金賬戶',
isSelected: selectedIndex == 0,
onTap: () => onChanged(0),
),
_buildTab(
context: context,
label: '交易账户',
label: '交易賬戶',
isSelected: selectedIndex == 1,
onTap: () => onChanged(1),
),

View File

@@ -4,7 +4,7 @@ import '../../../../core/theme/app_spacing.dart';
import '../../../../core/theme/app_theme.dart';
import '../../../../core/theme/app_theme_extension.dart';
/// 操作按行 — .pen node pIpHe
/// 操作按行 — .pen node pIpHe
/// gap: 12, three buttons evenly distributed
/// Each button: circle 48x48 fill $bg-tertiary, cornerRadius 24
/// icon: 20px $accent-primary (lucide: arrow-up-right / arrow-down-left / repeat)
@@ -38,7 +38,7 @@ class ActionButtonsRow extends StatelessWidget {
const SizedBox(width: 12),
ActionButton(
icon: LucideIcons.arrowDownLeft,
label: '',
label: '',
accentColor: accentColor,
bgColor: bgColor,
onTap: onWithdraw,
@@ -46,7 +46,7 @@ class ActionButtonsRow extends StatelessWidget {
const SizedBox(width: 12),
ActionButton(
icon: LucideIcons.repeat,
label: '划转',
label: '劃轉',
accentColor: accentColor,
bgColor: bgColor,
onTap: onTransfer,
@@ -56,7 +56,7 @@ class ActionButtonsRow extends StatelessWidget {
}
}
/// 单个操作按 — matching .pen btn1/btn2/btn3
/// 單個操作按 — matching .pen btn1/btn2/btn3
class ActionButton extends StatelessWidget {
final IconData icon;
final String label;

View File

@@ -17,7 +17,7 @@ import '../../../shared/ui_constants.dart';
// Dialog helpers — shared sub-widgets
// ============================================
/// 信息行 — 用于对话框中示 label/value 键值对
/// 信息行 — 用於對話框中示 label/value 鍵值對
class InfoRow extends StatelessWidget {
final String label;
final String value;
@@ -54,7 +54,7 @@ class InfoRow extends StatelessWidget {
}
}
/// 包地址卡片 — 用充值结果对话框中展示包地址
/// 包地址卡片 — 用充值結果對話框中展示包地址
class WalletAddressCard extends StatelessWidget {
final String address;
final String network;
@@ -94,7 +94,7 @@ class WalletAddressCard extends StatelessWidget {
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(text: address));
ToastUtils.show('地址已复制到剪');
ToastUtils.show('地址已複製到剪');
},
child: Container(
padding: const EdgeInsets.all(AppSpacing.xs),
@@ -113,7 +113,7 @@ class WalletAddressCard extends StatelessWidget {
),
const SizedBox(height: AppSpacing.sm),
Text(
'网络: $network',
'網絡: $network',
style: AppTextStyles.bodySmall(context),
),
],
@@ -126,7 +126,7 @@ class WalletAddressCard extends StatelessWidget {
// Dialog functions — kept from original with style updates
// ============================================
/// 充值对话
/// 充值對話
void showDepositDialog(BuildContext context) {
final amountController = TextEditingController();
final formKey = GlobalKey<ShadFormState>();
@@ -183,14 +183,14 @@ void showDepositDialog(BuildContext context) {
child: ShadInputFormField(
id: 'amount',
controller: amountController,
label: const Text('充值金'),
label: const Text('充值金'),
placeholder: const Text('最低 1000 USDT'),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
validator: (v) {
if (v == null || v.isEmpty) return '请输入金';
if (v == null || v.isEmpty) return '請輸入金';
final n = double.tryParse(v);
if (n == null || n <= 0) return '请输入有效金';
if (n < 1000) return '单笔最低充值1000 USDT';
if (n == null || n <= 0) return '請輸入有效金';
if (n < 1000) return '單筆最低充值1000 USDT';
return null;
},
),
@@ -222,7 +222,7 @@ void showDepositDialog(BuildContext context) {
if (response.success && response.data != null) {
showDepositResultDialog(context, response.data!);
} else {
showResultDialog(context, '请失败', response.message);
showResultDialog(context, '請失敗', response.message);
}
}
}
@@ -240,7 +240,7 @@ void showDepositDialog(BuildContext context) {
);
}
/// 充值结果对话框 — 展示包地址和确认打款
/// 充值結果對話框 — 展示包地址和確認打款
void showDepositResultDialog(BuildContext context, Map<String, dynamic> data) {
final orderNo = data['orderNo'] as String? ?? '';
final amount = data['amount']?.toString() ?? '0.00';
@@ -268,7 +268,7 @@ void showDepositResultDialog(BuildContext context, Map<String, dynamic> data) {
),
const SizedBox(width: AppSpacing.sm),
Text(
'充值申成功',
'充值申成功',
style: AppTextStyles.headlineLarge(context).copyWith(
fontWeight: FontWeight.w700,
),
@@ -276,12 +276,12 @@ void showDepositResultDialog(BuildContext context, Map<String, dynamic> data) {
],
),
const SizedBox(height: AppSpacing.lg),
InfoRow(label: '订单号', value: orderNo),
InfoRow(label: '訂單號', value: orderNo),
const SizedBox(height: AppSpacing.sm),
InfoRow(label: '充值金', value: '$amount USDT', isBold: true),
InfoRow(label: '充值金', value: '$amount USDT', isBold: true),
const SizedBox(height: AppSpacing.lg),
Text(
'向以下地址转账:',
'向以下地址轉賬:',
style: AppTextStyles.bodyMedium(context).copyWith(
color: colorScheme.onSurfaceVariant,
),
@@ -304,7 +304,7 @@ void showDepositResultDialog(BuildContext context, Map<String, dynamic> data) {
const SizedBox(width: AppSpacing.sm),
Expanded(
child: Text(
'转账完成后请点击"已打款"按钮确认',
'轉賬完成後請點擊"已打款"按鈕確認',
style: AppTextStyles.bodyMedium(context).copyWith(
color: AppColorScheme.warning,
),
@@ -318,7 +318,7 @@ void showDepositResultDialog(BuildContext context, Map<String, dynamic> data) {
children: [
Expanded(
child: NeonButton(
text: '后确认',
text: '後確認',
type: NeonButtonType.outline,
onPressed: () => Navigator.of(ctx).pop(),
height: 44,
@@ -336,8 +336,8 @@ void showDepositResultDialog(BuildContext context, Map<String, dynamic> data) {
if (context.mounted) {
showResultDialog(
context,
response.success ? '确认成功' : '确认失败',
response.success ? '等待管理员审' : response.message,
response.success ? '確認成功' : '確認失敗',
response.success ? '等待管理員審' : response.message,
);
}
},
@@ -354,13 +354,13 @@ void showDepositResultDialog(BuildContext context, Map<String, dynamic> data) {
);
}
/// 提现对话
/// 提現對話
void showWithdrawDialog(BuildContext context, String? balance) {
final amountController = TextEditingController();
final addressController = TextEditingController();
final contactController = TextEditingController();
final formKey = GlobalKey<ShadFormState>();
final feeNotifier = ValueNotifier<String>('现将扣除10%手续费');
final feeNotifier = ValueNotifier<String>('現將扣除10%手續費');
final networksNotifier = ValueNotifier<List<String>>([]);
final selectedNetworkNotifier = ValueNotifier<String?>(null);
final colorScheme = Theme.of(context).colorScheme;
@@ -370,13 +370,13 @@ void showWithdrawDialog(BuildContext context, String? balance) {
if (amount > 0) {
final fee = amount * 0.1;
final receivable = amount - fee;
feeNotifier.value = '续费(10%): -${fee.toStringAsFixed(2)} USDT | 收款: ${receivable.toStringAsFixed(2)} USDT';
feeNotifier.value = '續費(10%): -${fee.toStringAsFixed(2)} USDT | 收款: ${receivable.toStringAsFixed(2)} USDT';
} else {
feeNotifier.value = '现将扣除10%手续费';
feeNotifier.value = '現將扣除10%手續費';
}
});
// 获取网络列表
// 獲取網絡列表
context.read<AssetProvider>().getWalletNetworks().then((list) {
networksNotifier.value = list;
if (list.isNotEmpty) {
@@ -411,7 +411,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
),
const SizedBox(width: AppSpacing.sm),
Text(
'',
'',
style: AppTextStyles.headlineLarge(context).copyWith(
fontWeight: FontWeight.w700,
),
@@ -420,7 +420,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
),
const SizedBox(height: AppSpacing.xs),
Text(
'安全地您的资产转移到外部包地址',
'安全地您的資產轉移到外部包地址',
style: AppTextStyles.bodyMedium(context).copyWith(
color: colorScheme.onSurfaceVariant,
),
@@ -443,7 +443,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
mainAxisSize: MainAxisSize.min,
children: [
Text(
'可用余额: ',
'可用餘額: ',
style: AppTextStyles.bodySmall(context).copyWith(
color: colorScheme.onSurfaceVariant,
),
@@ -467,13 +467,13 @@ void showWithdrawDialog(BuildContext context, String? balance) {
ShadInputFormField(
id: 'amount',
controller: amountController,
label: const Text('现金额'),
placeholder: const Text('请输入提现金额(USDT)'),
label: const Text('現金額'),
placeholder: const Text('請輸入提現金額(USDT)'),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
validator: Validators.amount,
),
const SizedBox(height: AppSpacing.md),
// 手续费/应收款提示
// 手續費/應收款提示
ValueListenableBuilder<String>(
valueListenable: feeNotifier,
builder: (_, feeText, __) {
@@ -501,7 +501,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
},
),
const SizedBox(height: AppSpacing.md),
// 提现网络选择
// 提現網絡選擇
ValueListenableBuilder<List<String>>(
valueListenable: networksNotifier,
builder: (_, networks, __) {
@@ -509,7 +509,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('现网络', style: AppTextStyles.bodyMedium(context).copyWith(
Text('現網絡', style: AppTextStyles.bodyMedium(context).copyWith(
fontWeight: FontWeight.w500,
)),
const SizedBox(height: AppSpacing.xs),
@@ -517,7 +517,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
valueListenable: selectedNetworkNotifier,
builder: (_, selected, __) {
return ShadSelect<String>(
placeholder: const Text('选择提现网络'),
placeholder: const Text('選擇提現網絡'),
initialValue: selected,
selectedOptionBuilder: (context, val) => Text(val),
onChanged: (value) {
@@ -535,16 +535,16 @@ void showWithdrawDialog(BuildContext context, String? balance) {
ShadInputFormField(
id: 'address',
controller: addressController,
label: const Text('地址'),
placeholder: const Text('请输入提地址'),
validator: (v) => Validators.required(v, '地址'),
label: const Text('地址'),
placeholder: const Text('請輸入提地址'),
validator: (v) => Validators.required(v, '地址'),
),
const SizedBox(height: AppSpacing.md),
ShadInputFormField(
id: 'contact',
controller: contactController,
label: const Text('联系方式(可)'),
placeholder: const Text('联系方式'),
label: const Text('聯繫方式(可)'),
placeholder: const Text('聯繫方式'),
),
],
),
@@ -580,8 +580,8 @@ void showWithdrawDialog(BuildContext context, String? balance) {
if (context.mounted) {
showResultDialog(
context,
response.success ? '成功' : '请失败',
response.success ? '等待管理员审' : response.message,
response.success ? '成功' : '請失敗',
response.success ? '等待管理員審' : response.message,
);
}
}
@@ -612,7 +612,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
);
}
/// 通用结果对话框 — 展示操作成功/失信息
/// 通用結果對話框 — 展示操作成功/失信息
void showResultDialog(BuildContext context, String title, String? message) {
final colorScheme = Theme.of(context).colorScheme;
@@ -646,7 +646,7 @@ void showResultDialog(BuildContext context, String title, String? message) {
SizedBox(
width: double.infinity,
child: NeonButton(
text: '',
text: '',
type: NeonButtonType.primary,
onPressed: () => Navigator.of(ctx).pop(),
height: 44,

View File

@@ -4,7 +4,7 @@ import '../../../../core/theme/app_theme_extension.dart';
import '../../../../core/theme/app_spacing.dart';
import '../../../components/glass_panel.dart';
/// 余额卡片 — 显示单个账户的 USDT 余额
/// 餘額卡片 — 顯示單個賬戶的 USDT 餘額
class BalanceCard extends StatelessWidget {
final String label;
final String balance;
@@ -20,7 +20,7 @@ class BalanceCard extends StatelessWidget {
final displayBalance = balance;
return SizedBox(
width: double.infinity, // 保卡片撑满宽
width: double.infinity, // 保卡片撐滿寬
child: GlassPanel(
padding: const EdgeInsets.all(20),
borderRadius: BorderRadius.circular(AppRadius.lg),

View File

@@ -5,8 +5,8 @@ import '../../../../core/theme/app_spacing.dart';
import '../../../../data/models/account_models.dart';
import '../../../components/glass_panel.dart';
/// 持仓区
/// Header: "我的资产" + "查看全部 >"
/// 持倉區
/// Header: "我的資產" + "查看全部 >"
/// Holdings Card: cornerRadius lg, fill $surface-card, stroke $border-default 1px
class HoldingsSection extends StatelessWidget {
final List holdings;
@@ -19,14 +19,14 @@ class HoldingsSection extends StatelessWidget {
return Column(
children: [
// Header row: "我的资产" + "查看全部 >"
// Header row: "我的資產" + "查看全部 >"
Padding(
padding: const EdgeInsets.only(bottom: AppSpacing.sm),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'我的资产',
'我的資產',
style: AppTextStyles.headlineLarge(context),
),
Text(
@@ -44,7 +44,7 @@ class HoldingsSection extends StatelessWidget {
Padding(
padding: const EdgeInsets.all(AppSpacing.xl),
child: Text(
'暂无持仓',
'暫無持倉',
style: AppTextStyles.bodyLarge(context).copyWith(
color: colorScheme.onSurfaceVariant,
),
@@ -78,7 +78,7 @@ class HoldingsSection extends StatelessWidget {
}
}
/// 持行分隔线 — .pen node BCCbR / yejhE
/// 持行分隔 — .pen node BCCbR / yejhE
/// fill: $border-default, height: 1, opacity: 0.5
class HoldingDivider extends StatelessWidget {
const HoldingDivider({super.key});
@@ -94,7 +94,7 @@ class HoldingDivider extends StatelessWidget {
}
}
/// 持行 — matching .pen nodes dAt4j / eK6vq / jiSUK
/// 持行 — matching .pen nodes dAt4j / eK6vq / jiSUK
/// padding [14, 16], space_between layout
/// Left: avatar circle (36x36, radius 18, fill $accent-light) + coin info (gap 2)
/// Right: value + pnl (gap 2, align end)

View File

@@ -5,7 +5,7 @@ import '../../../../core/theme/app_theme_extension.dart';
import '../../../../core/theme/app_spacing.dart';
import '../../../components/glass_panel.dart';
/// 订单记录链接行
/// 訂單記錄鏈接行
/// cornerRadius: lg, fill: $surface-card, padding: [14, 16], stroke: $border-default 1px
class RecordsLinkRow extends StatelessWidget {
final VoidCallback onTap;
@@ -25,7 +25,7 @@ class RecordsLinkRow extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'订单记录',
'訂單記錄',
style: AppTextStyles.headlineMedium(context).copyWith(
fontWeight: FontWeight.w500,
),

View File

@@ -8,7 +8,7 @@ import '../../../core/theme/app_spacing.dart';
import '../../../providers/asset_provider.dart';
import '../../../data/models/account_models.dart';
/// 划转页
/// 劃轉頁
class TransferPage extends StatefulWidget {
const TransferPage({super.key});
@@ -19,7 +19,7 @@ class TransferPage extends StatefulWidget {
class _TransferPageState extends State<TransferPage> {
final _amountController = TextEditingController();
final _focusNode = FocusNode();
int _direction = 1; // 1: 金→交易, 2: 交易→
int _direction = 1; // 1: 金→交易, 2: 交易→
bool _isLoading = false;
@override
@@ -38,26 +38,26 @@ class _TransferPageState extends State<TransferPage> {
}
// ============================================
// 数据访问
// 數據訪問
// ============================================
/// 获取资金账户余额(安全查)
/// 獲取資金賬戶餘額(安全查)
String get _fundBalance {
try {
final provider = context.read<AssetProvider>();
final balance = provider.fundAccount?.balance ?? provider.overview?.fundBalance ?? '0.00';
// 保返回的是有效的字格式
// 保返回的是有效的字格式
return _formatBalance(balance);
} catch (e) {
return '0.00';
}
}
/// 取交易账户 USDT 余额(安全查)
/// 取交易賬戶 USDT 餘額(安全查)
String get _tradeUsdtBalance {
try {
final provider = context.read<AssetProvider>();
// 先查列表是否
// 先查列表是否
if (provider.tradeAccounts.isEmpty) {
return '0.00';
}
@@ -81,32 +81,32 @@ class _TransferPageState extends State<TransferPage> {
}
}
/// 获取当前可用余额(根方向)
/// 獲取當前可用餘額(根方向)
String get _availableBalance => _direction == 1 ? _fundBalance : _tradeUsdtBalance;
/// 从账户
String get _fromLabel => _direction == 1 ? '资金账户' : '交易账户';
String get _toLabel => _direction == 1 ? '交易账户' : '资金账户';
/// 從賬戶
String get _fromLabel => _direction == 1 ? '資金賬戶' : '交易賬戶';
String get _toLabel => _direction == 1 ? '交易賬戶' : '資金賬戶';
String get _fromBalance => _direction == 1 ? _fundBalance : _tradeUsdtBalance;
String get _toBalance => _direction == 1 ? _tradeUsdtBalance : _fundBalance;
// ============================================
// 业务逻辑
// 業務邏輯
// ============================================
/// 执行划转
/// 執行劃轉
Future<void> _doTransfer() async {
final amount = _amountController.text;
final available = double.tryParse(_availableBalance) ?? 0;
final transferAmount = double.tryParse(amount) ?? 0;
if (transferAmount <= 0) {
_showSnackBar('请输入有效的划转金额');
_showSnackBar('請輸入有效的劃轉金額');
return;
}
if (transferAmount > available) {
_showSnackBar('余额不足');
_showSnackBar('餘額不足');
return;
}
@@ -121,10 +121,10 @@ class _TransferPageState extends State<TransferPage> {
if (mounted) {
if (response.success) {
_amountController.clear();
_showSnackBar('划转成功');
_showSnackBar('劃轉成功');
Navigator.of(context).pop(true);
} else {
_showSnackBar(response.message ?? '划转失败');
_showSnackBar(response.message ?? '劃轉失敗');
}
}
} finally {
@@ -140,14 +140,14 @@ class _TransferPageState extends State<TransferPage> {
);
}
/// 置快捷百分比金
/// 置快捷百分比金
void _setQuickAmount(double percent) {
final available = double.tryParse(_availableBalance) ?? 0;
final amount = available * percent;
_amountController.text = amount.toStringAsFixed(8).replaceAll(RegExp(r'\.?0+$'), '');
}
/// 切方向
/// 切方向
void _toggleDirection() {
setState(() {
_direction = _direction == 1 ? 2 : 1;
@@ -155,7 +155,7 @@ class _TransferPageState extends State<TransferPage> {
}
// ============================================
// 建 UI
// 建 UI
// ============================================
@override
@@ -173,7 +173,7 @@ class _TransferPageState extends State<TransferPage> {
onPressed: () => Navigator.of(context).pop(),
),
title: Text(
'账户划转',
'賬戶劃轉',
style: AppTextStyles.headlineLarge(context),
),
centerTitle: true,
@@ -205,7 +205,7 @@ class _TransferPageState extends State<TransferPage> {
Widget _buildTransferDirectionCard() {
final colorScheme = Theme.of(context).colorScheme;
// 金色主感知: Dark #D4AF37 (primary), Light #F59E0B (secondary)
// 金色主感知: Dark #D4AF37 (primary), Light #F59E0B (secondary)
final goldAccent = colorScheme.brightness == Brightness.dark
? colorScheme.primary
: colorScheme.secondary;
@@ -225,7 +225,7 @@ class _TransferPageState extends State<TransferPage> {
key: 'src-$_direction',
beginOffset: const Offset(0, -1),
child: _buildAccountRow(
label: '',
label: '',
accountName: _fromLabel,
balance: _fromBalance,
),
@@ -239,7 +239,7 @@ class _TransferPageState extends State<TransferPage> {
height: 40,
margin: const EdgeInsets.symmetric(vertical: AppSpacing.md),
decoration: BoxDecoration(
// 椭圆形半透明金色背景
// 橢圓形半透明金色背景
color: goldAccent.withValues(alpha: 0.15),
shape: BoxShape.circle,
border: Border.all(
@@ -272,7 +272,7 @@ class _TransferPageState extends State<TransferPage> {
);
}
/// 一的 AnimatedSwitcher
/// 一的 AnimatedSwitcher
Widget _animatedSwitcher({
required String key,
required Offset beginOffset,
@@ -313,7 +313,7 @@ class _TransferPageState extends State<TransferPage> {
Row(
children: [
Icon(
label == '' ? LucideIcons.wallet : LucideIcons.trendingUp,
label == '' ? LucideIcons.wallet : LucideIcons.trendingUp,
size: 18,
color: colorScheme.onSurfaceVariant,
),
@@ -342,14 +342,14 @@ class _TransferPageState extends State<TransferPage> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Label row: "划转金额" + "全部划转"
// Label row: "劃轉金額" + "全部劃轉"
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('划转金额', style: AppTextStyles.headlineSmall(context).copyWith(color: colorScheme.onSurfaceVariant)),
Text('劃轉金額', style: AppTextStyles.headlineSmall(context).copyWith(color: colorScheme.onSurfaceVariant)),
GestureDetector(
onTap: () => _setQuickAmount(1.0),
child: Text('全部划转', style: AppTextStyles.labelLarge(context).copyWith(
child: Text('全部劃轉', style: AppTextStyles.labelLarge(context).copyWith(
color: colorScheme.secondary,
fontWeight: FontWeight.w600,
)),
@@ -461,7 +461,7 @@ class _TransferPageState extends State<TransferPage> {
const SizedBox(width: AppSpacing.sm),
Expanded(
child: Text(
'划转即时到账,无需手续费',
'劃轉即時到賬,無需手續費',
style: AppTextStyles.bodyMedium(context).copyWith(color: upColor),
),
),
@@ -472,7 +472,7 @@ class _TransferPageState extends State<TransferPage> {
Widget _buildConfirmButton() {
final colorScheme = Theme.of(context).colorScheme;
// 金色主感知: Dark #D4AF37 (primary), Light #F59E0B (secondary)
// 金色主感知: Dark #D4AF37 (primary), Light #F59E0B (secondary)
final goldAccent = colorScheme.brightness == Brightness.dark
? colorScheme.primary
: colorScheme.secondary;
@@ -498,7 +498,7 @@ class _TransferPageState extends State<TransferPage> {
),
)
: const Text(
'确认划转',
'確認劃轉',
style: TextStyle(
color: Colors.white,
fontSize: 16,

View File

@@ -49,13 +49,13 @@ class _LoginPageState extends State<LoginPage> {
key: formKey,
child: Column(
children: [
// 部品牌
// 部品牌
_buildBrandSection(),
const SizedBox(height: AppSpacing.xxl),
// 表单区
// 表單區
_buildFormSection(),
const SizedBox(height: AppSpacing.xl),
// 底部注册链
// 底部註冊鏈
_buildRegisterRow(),
],
),
@@ -66,13 +66,13 @@ class _LoginPageState extends State<LoginPage> {
}
// ============================================
// 品牌域 - Logo + 品牌名 + 标语
// 品牌域 - Logo + 品牌名 + 標語
// ============================================
Widget _buildBrandSection() {
return Column(
children: [
// Logo 形:渐变 #1F2937 → #374151含 "M"
// Logo 形:漸變 #1F2937 → #374151含 "M"
Container(
width: _logoCircleSize,
height: _logoCircleSize,
@@ -105,9 +105,9 @@ class _LoginPageState extends State<LoginPage> {
textAlign: TextAlign.center,
),
const SizedBox(height: AppSpacing.md),
// 标语
// 標語
Text(
'虚拟货币模拟交易平',
'虛擬貨幣模擬交易平',
style: AppTextStyles.bodyLarge(context).copyWith(
color: context.colors.onSurfaceVariant,
),
@@ -118,7 +118,7 @@ class _LoginPageState extends State<LoginPage> {
}
// ============================================
// 表单区域 - 用名 + 密 + 登录按钮
// 表單區域 - 用名 + 密 + 登錄按鈕
// ============================================
Widget _buildFormSection() {
@@ -139,7 +139,7 @@ class _LoginPageState extends State<LoginPage> {
height: _inputHeight,
child: ShadInputFormField(
id: 'username',
placeholder: const Text('请输入用'),
placeholder: const Text('請輸入用'),
leading: Padding(
padding: const EdgeInsets.only(right: AppSpacing.sm),
child: Icon(LucideIcons.user, size: 18, color: context.appColors.onSurfaceMuted),
@@ -166,7 +166,7 @@ class _LoginPageState extends State<LoginPage> {
height: _inputHeight,
child: ShadInputFormField(
id: 'password',
placeholder: const Text('请输入密'),
placeholder: const Text('請輸入密'),
obscureText: _obscurePassword,
leading: Padding(
padding: const EdgeInsets.only(right: AppSpacing.sm),
@@ -196,7 +196,7 @@ class _LoginPageState extends State<LoginPage> {
}
Widget _buildLoginButton() {
// 设计稿: accent-primary = light:#1F2937 / dark:#D4AF37
// 設計稿: accent-primary = light:#1F2937 / dark:#D4AF37
final buttonColor = context.appColors.accentPrimary;
final textColor = context.colors.onPrimary;
@@ -222,7 +222,7 @@ class _LoginPageState extends State<LoginPage> {
),
)
: Text(
'',
'',
style: AppTextStyles.headlineLarge(context).copyWith(
fontWeight: FontWeight.w700,
color: textColor,
@@ -235,7 +235,7 @@ class _LoginPageState extends State<LoginPage> {
}
// ============================================
// 底部注册链
// 底部註冊鏈
// ============================================
Widget _buildRegisterRow() {
@@ -249,7 +249,7 @@ class _LoginPageState extends State<LoginPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'还没有账户',
'還沒有賬戶',
style: AppTextStyles.bodyLarge(context).copyWith(
color: secondaryTextColor,
),
@@ -258,7 +258,7 @@ class _LoginPageState extends State<LoginPage> {
GestureDetector(
onTap: _navigateToRegister,
child: Text(
'立即注册',
'立即註冊',
style: AppTextStyles.bodyLarge(context).copyWith(
fontWeight: FontWeight.w600,
color: goldColor,
@@ -276,20 +276,20 @@ class _LoginPageState extends State<LoginPage> {
String? _validateUsername(String? value) {
if (value == null || value.isEmpty) {
return '请输入用';
return '請輸入用';
}
if (value.length < 3) {
return '名至少 3 字符';
return '名至少 3 字符';
}
return null;
}
String? _validatePassword(String? value) {
if (value == null || value.isEmpty) {
return '请输入密';
return '請輸入密';
}
if (value.length < 6) {
return '至少 6 字符';
return '至少 6 字符';
}
return null;
}
@@ -312,7 +312,7 @@ class _LoginPageState extends State<LoginPage> {
if (response.success) {
_navigateToMainPage();
} else {
_showErrorDialog(response.message ?? '名或密码错误');
_showErrorDialog(response.message ?? '名或密碼錯誤');
}
}
@@ -334,11 +334,11 @@ class _LoginPageState extends State<LoginPage> {
showShadDialog(
context: context,
builder: (context) => ShadDialog.alert(
title: const Text('录失败'),
title: const Text('錄失敗'),
description: Text(message),
actions: [
ShadButton(
child: const Text(''),
child: const Text(''),
onPressed: () => Navigator.of(context).pop(),
),
],

View File

@@ -11,7 +11,7 @@ import '../../components/glass_panel.dart';
import '../../components/neon_glow.dart';
import '../main/main_page.dart';
/// 注册页面(两步注册:账号信息 + 身份证上传
/// 註冊頁面(兩步註冊:賬號信息 + 身份證上傳
class RegisterPage extends StatefulWidget {
const RegisterPage({super.key});
@@ -20,7 +20,7 @@ class RegisterPage extends StatefulWidget {
}
class _RegisterPageState extends State<RegisterPage> {
int _currentStep = 0; // 0: 账号信息, 1: 身份证上传
int _currentStep = 0; // 0: 賬號信息, 1: 身份證上傳
// 第一步
final _usernameController = TextEditingController();
@@ -96,11 +96,11 @@ class _RegisterPageState extends State<RegisterPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 步指示器
// 步指示器
_buildStepIndicator(colorScheme),
SizedBox(height: AppSpacing.xl),
// 内容区
// 內容區
_currentStep == 0 ? _buildStep1(colorScheme) : _buildStep2(colorScheme),
],
),
@@ -114,7 +114,7 @@ class _RegisterPageState extends State<RegisterPage> {
children: [
_buildStepCircle(
number: '1',
label: '账号信息',
label: '賬號信息',
isActive: true,
isComplete: _currentStep > 0,
colorScheme: colorScheme,
@@ -129,7 +129,7 @@ class _RegisterPageState extends State<RegisterPage> {
),
_buildStepCircle(
number: '2',
label: '身份验证',
label: '身份驗證',
isActive: _currentStep >= 1,
isComplete: false,
colorScheme: colorScheme,
@@ -191,17 +191,17 @@ class _RegisterPageState extends State<RegisterPage> {
);
}
/// 第一步:账号信息
/// 第一步:賬號信息
Widget _buildStep1(ColorScheme colorScheme) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 标题
// 標題
Center(
child: Text(
'创建账号',
'創建賬號',
style: AppTextStyles.displaySmall(context).copyWith(
fontWeight: FontWeight.bold,
color: colorScheme.onSurface,
@@ -210,30 +210,30 @@ class _RegisterPageState extends State<RegisterPage> {
),
SizedBox(height: AppSpacing.xxl),
// 用
// 用
TextFormField(
controller: _usernameController,
style: TextStyle(color: colorScheme.onSurface),
decoration: InputDecoration(
hintText: '请输入账号(4-20位字母字)',
hintText: '請輸入賬號(4-20位字母字)',
prefixIcon: Icon(Icons.person_outline, color: colorScheme.onSurfaceVariant),
),
validator: (value) {
if (value == null || value.isEmpty) return '请输入账号';
if (value.length < 4) return '账号至少4位';
if (value.length > 20) return '账号最多20位';
if (value == null || value.isEmpty) return '請輸入賬號';
if (value.length < 4) return '賬號至少4位';
if (value.length > 20) return '賬號最多20位';
return null;
},
),
SizedBox(height: AppSpacing.md),
// 密
// 密
TextFormField(
controller: _passwordController,
obscureText: _obscurePassword,
style: TextStyle(color: colorScheme.onSurface),
decoration: InputDecoration(
hintText: '请输入密(至少6位)',
hintText: '請輸入密(至少6位)',
prefixIcon: Icon(Icons.lock_outline, color: colorScheme.onSurfaceVariant),
suffixIcon: IconButton(
icon: Icon(
@@ -244,20 +244,20 @@ class _RegisterPageState extends State<RegisterPage> {
),
),
validator: (value) {
if (value == null || value.isEmpty) return '请输入密';
if (value.length < 6) return '至少6位';
if (value == null || value.isEmpty) return '請輸入密';
if (value.length < 6) return '至少6位';
return null;
},
),
SizedBox(height: AppSpacing.md),
// 确认密码
// 確認密碼
TextFormField(
controller: _confirmPasswordController,
obscureText: _obscureConfirmPassword,
style: TextStyle(color: colorScheme.onSurface),
decoration: InputDecoration(
hintText: '再次入密',
hintText: '再次入密',
prefixIcon: Icon(Icons.lock_outline, color: colorScheme.onSurfaceVariant),
suffixIcon: IconButton(
icon: Icon(
@@ -268,25 +268,25 @@ class _RegisterPageState extends State<RegisterPage> {
),
),
validator: (value) {
if (value == null || value.isEmpty) return '再次入密';
if (value != _passwordController.text) return '次密不一致';
if (value == null || value.isEmpty) return '再次入密';
if (value != _passwordController.text) return '次密不一致';
return null;
},
),
SizedBox(height: AppSpacing.md),
// 推广码(可
// 推廣碼(可
TextFormField(
controller: _referralCodeController,
style: TextStyle(color: colorScheme.onSurface),
decoration: InputDecoration(
hintText: '广码(选填)',
hintText: '廣碼(選填)',
prefixIcon: Icon(Icons.card_giftcard, color: colorScheme.onSurfaceVariant),
),
),
SizedBox(height: AppSpacing.xl),
// 下一步按
// 下一步按
SizedBox(
width: double.infinity,
child: NeonButton(
@@ -303,11 +303,11 @@ class _RegisterPageState extends State<RegisterPage> {
),
SizedBox(height: AppSpacing.md),
// 登录链
// 登錄鏈
Center(
child: TextButton(
onPressed: () => Navigator.pop(context),
child: Text('已有账号?立即登', style: AppTextStyles.headlineMedium(context)),
child: Text('已有賬號?立即登', style: AppTextStyles.headlineMedium(context)),
),
),
],
@@ -315,12 +315,12 @@ class _RegisterPageState extends State<RegisterPage> {
);
}
/// 第二步:身份证上传
/// 第二步:身份證上傳
Widget _buildStep2(ColorScheme colorScheme) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 标题区
// 標題區
GlassPanel(
padding: EdgeInsets.all(AppSpacing.lg),
child: Column(
@@ -345,7 +345,7 @@ class _RegisterPageState extends State<RegisterPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'身份验证',
'身份驗證',
style: AppTextStyles.headlineLarge(context).copyWith(
fontWeight: FontWeight.bold,
color: colorScheme.onSurface,
@@ -353,7 +353,7 @@ class _RegisterPageState extends State<RegisterPage> {
),
SizedBox(height: AppSpacing.xs),
Text(
'身份正反面完成注册',
'身份正反面完成註冊',
style: AppTextStyles.bodyMedium(context).copyWith(
color: colorScheme.onSurfaceVariant,
),
@@ -364,9 +364,9 @@ class _RegisterPageState extends State<RegisterPage> {
),
SizedBox(height: AppSpacing.xl),
// 身份正面
// 身份正面
Text(
'身份正面(人像面)',
'身份正面(人像面)',
style: AppTextStyles.bodyLarge(context).copyWith(
fontWeight: FontWeight.w600,
color: colorScheme.onSurface,
@@ -382,9 +382,9 @@ class _RegisterPageState extends State<RegisterPage> {
),
SizedBox(height: AppSpacing.lg),
// 身份反面
// 身份反面
Text(
'身份反面(徽面)',
'身份反面(徽面)',
style: AppTextStyles.bodyLarge(context).copyWith(
fontWeight: FontWeight.w600,
color: colorScheme.onSurface,
@@ -394,19 +394,19 @@ class _RegisterPageState extends State<RegisterPage> {
_buildUploadZone(
imageFile: _backFile,
imageBytes: _backBytes,
label: '徽面',
label: '徽面',
onTap: () => _pickImage(false),
colorScheme: colorScheme,
),
SizedBox(height: AppSpacing.xl),
// 注册按钮
// 註冊按鈕
Consumer<AuthProvider>(
builder: (context, auth, _) {
return SizedBox(
width: double.infinity,
child: NeonButton(
text: _isLoading ? '注册中...' : '完成注册',
text: _isLoading ? '註冊中...' : '完成註冊',
type: NeonButtonType.primary,
onPressed: _canSubmit && !auth.isLoading ? _handleRegister : null,
height: 48,
@@ -434,7 +434,7 @@ class _RegisterPageState extends State<RegisterPage> {
SizedBox(width: AppSpacing.sm),
Expanded(
child: Text(
'您的身份信息被加密存储,仅用于身份验证',
'您的身份信息被加密存儲,僅用於身份驗證',
style: AppTextStyles.bodySmall(context).copyWith(
color: AppColorScheme.up.withValues(alpha: 0.8),
),
@@ -502,7 +502,7 @@ class _RegisterPageState extends State<RegisterPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'$label已选择',
'$label已選擇',
style: AppTextStyles.bodyMedium(context).copyWith(
fontWeight: FontWeight.w600,
color: AppColorScheme.darkOnPrimary,
@@ -551,7 +551,7 @@ class _RegisterPageState extends State<RegisterPage> {
),
SizedBox(height: AppSpacing.sm),
Text(
'点击上传$label',
'點擊上傳$label',
style: AppTextStyles.bodyLarge(context).copyWith(
color: colorScheme.onSurfaceVariant.withValues(alpha: 0.6),
),
@@ -597,11 +597,11 @@ class _RegisterPageState extends State<RegisterPage> {
showShadDialog(
context: context,
builder: (ctx) => ShadDialog.alert(
title: const Text('注册失败'),
description: Text(response.message ?? '请稍后重试'),
title: const Text('註冊失敗'),
description: Text(response.message ?? '請稍後重試'),
actions: [
ShadButton(
child: const Text(''),
child: const Text(''),
onPressed: () => Navigator.of(ctx).pop(),
),
],
@@ -613,11 +613,11 @@ class _RegisterPageState extends State<RegisterPage> {
showShadDialog(
context: context,
builder: (ctx) => ShadDialog.alert(
title: const Text('注册失败'),
title: const Text('註冊失敗'),
description: Text(e.toString()),
actions: [
ShadButton(
child: const Text(''),
child: const Text(''),
onPressed: () => Navigator.of(ctx).pop(),
),
],
@@ -630,7 +630,7 @@ class _RegisterPageState extends State<RegisterPage> {
}
}
/// 虚线边框画笔
/// 虛線邊框畫筆
class _DashedBorderPainter extends CustomPainter {
final Color color;
final double borderRadius;

View File

@@ -9,7 +9,7 @@ import '../../../data/models/account_models.dart';
import '../../../data/services/bonus_service.dart';
import '../../../providers/asset_provider.dart';
/// 账单页面 — 代币盈亏账单 + 新人福利账单 + 推广福利账单
/// 賬單頁面 — 代幣盈虧賬單 + 新人福利賬單 + 推福利賬單
class BillsPage extends StatefulWidget {
const BillsPage({super.key});
@@ -42,7 +42,7 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
final provider = context.read<AssetProvider>();
final bonusService = context.read<BonusService>();
// 行加载持仓和福利记录
// 行加載持倉和福利記錄
await provider.loadTradeAccount(force: true);
final welfareResponse = await bonusService.getWelfareStatus();
@@ -73,7 +73,7 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
if (newUser != null) {
final claimed = newUser['claimed'] as bool? ?? false;
final eligible = newUser['eligible'] as bool? ?? false;
// 状态: 1=已取, 0=可取(待取), 2=不可用(未解)
// 狀態: 1=已取, 0=可取(待取), 2=不可用(未解)
final int status;
if (claimed) {
status = 1;
@@ -91,15 +91,15 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
});
}
// 推广福利列表
// 推福利列表
final referralRewards = data['referralRewards'] as List<dynamic>? ?? [];
for (var r in referralRewards) {
final map = r as Map<String, dynamic>;
final username = map['username'] as String? ?? '';
final username = map['username'] as String? ?? '';
final milestones = map['milestones'] as List<dynamic>? ?? [];
final claimableCount = map['claimableCount'] as int? ?? 0;
// 每 milestone 生成一条记录
// 每 milestone 生成一條記錄
for (var m in milestones) {
final ms = m as Map<String, dynamic>;
final earned = ms['earned'] as bool? ?? false;
@@ -108,26 +108,26 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
final int status;
if (earned) {
status = 1; // 已
status = 1; // 已
} else if (claimable) {
status = 0; // 可
status = 0; // 可
} else {
status = 2; // 未达标
status = 2; // 未達標
}
records.add({
'type': 'referral',
'title': '广福利 - $username (${milestoneVal}000)',
'title': '福利 - $username (${milestoneVal}000)',
'amount': '100.00',
'status': status,
'time': ms['claimTime'] ?? ms['createTime'],
});
}
// 如果有 milestone 但有 claimableCount也生成记录
// 如果有 milestone 但有 claimableCount也生成記錄
if (milestones.isEmpty && claimableCount > 0) {
records.add({
'type': 'referral',
'title': '广福利 - $username',
'title': '福利 - $username',
'amount': '${claimableCount * 100}',
'status': 0,
'time': null,
@@ -150,7 +150,7 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
icon: const Icon(LucideIcons.arrowLeft, size: 20),
onPressed: () => Navigator.of(context).pop(),
),
title: Text('我的账单', style: AppTextStyles.headlineLarge(context)),
title: Text('我的賬單', style: AppTextStyles.headlineLarge(context)),
backgroundColor: _isDark ? AppColorScheme.darkBackground : AppColorScheme.lightBackground,
elevation: 0,
scrolledUnderElevation: 0,
@@ -163,9 +163,9 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
labelStyle: AppTextStyles.headlineMedium(context).copyWith(fontWeight: FontWeight.w600),
unselectedLabelStyle: AppTextStyles.headlineMedium(context),
tabs: const [
Tab(text: '币盈亏'),
Tab(text: '幣盈虧'),
Tab(text: '新人福利'),
Tab(text: '广福利'),
Tab(text: '福利'),
],
),
),
@@ -183,16 +183,16 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
}
// ============================================
// 代币盈亏账单
// 代幣盈虧賬單
// ============================================
Widget _buildCoinProfitTab() {
final colorScheme = Theme.of(context).colorScheme;
if (_holdings.isEmpty) {
return _buildEmptyState(LucideIcons.wallet, '暂无持仓记录');
return _buildEmptyState(LucideIcons.wallet, '暫無持倉記錄');
}
// 汇总统计
// 彙總統計
double totalCost = 0;
double totalValue = 0;
double totalProfit = 0;
@@ -210,7 +210,7 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
child: ListView(
padding: const EdgeInsets.all(AppSpacing.md),
children: [
// 汇总卡片
// 彙總卡片
Container(
padding: const EdgeInsets.all(AppSpacing.lg),
decoration: BoxDecoration(
@@ -224,7 +224,7 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
),
child: Column(
children: [
Text('总盈亏 (USDT)', style: AppTextStyles.bodyMedium(context).copyWith(
Text('總盈虧 (USDT)', style: AppTextStyles.bodyMedium(context).copyWith(
color: colorScheme.onSurfaceVariant,
)),
const SizedBox(height: AppSpacing.xs),
@@ -239,9 +239,9 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildSummaryItem('成本', totalCost.toStringAsFixed(2)),
_buildSummaryItem('成本', totalCost.toStringAsFixed(2)),
Container(width: 1, height: 16, color: colorScheme.outlineVariant.withValues(alpha: 0.3)),
_buildSummaryItem('市值', totalValue.toStringAsFixed(2)),
_buildSummaryItem('市值', totalValue.toStringAsFixed(2)),
Container(width: 1, height: 16, color: colorScheme.outlineVariant.withValues(alpha: 0.3)),
_buildSummaryItem('收益率', '${profitRate >= 0 ? '+' : ''}${profitRate.toStringAsFixed(2)}%'),
],
@@ -251,7 +251,7 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
),
const SizedBox(height: AppSpacing.md),
// 各币种盈亏明细
// 各幣種盈虧明細
..._holdings.map((h) => _buildCoinProfitCard(h)),
],
),
@@ -296,7 +296,7 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
),
child: Column(
children: [
// 名 + 盈亏金额
// 名 + 盈虧金額
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@@ -333,11 +333,11 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
],
),
const SizedBox(height: AppSpacing.sm),
// 明
// 明
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(': ${h.avgPrice}', style: AppTextStyles.bodySmall(context).copyWith(
Text(': ${h.avgPrice}', style: AppTextStyles.bodySmall(context).copyWith(
color: colorScheme.onSurfaceVariant,
)),
Text('市值: ${h.currentValue} USDT', style: AppTextStyles.bodySmall(context).copyWith(
@@ -355,7 +355,7 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
}
// ============================================
// 福利账单
// 福利賬單
// ============================================
Widget _buildWelfareTab(String type) {
final records = _welfareRecords.where((r) => r['type'] == type).toList();
@@ -363,7 +363,7 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
if (records.isEmpty) {
return _buildEmptyState(
LucideIcons.gift,
type == 'new_user' ? '暂无新人福利记录' : '暂无推广福利记录',
type == 'new_user' ? '暫無新人福利記錄' : '暫無推廣福利記錄',
);
}
@@ -382,20 +382,20 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
final amount = double.tryParse(record['amount']?.toString() ?? '0') ?? 0;
final status = record['status'] as int? ?? 0;
// status: 0=待取, 1=已取, 2=未达标
// status: 0=待取, 1=已取, 2=未達標
String statusText;
Color statusColor;
switch (status) {
case 1:
statusText = '';
statusText = '';
statusColor = context.appColors.up;
break;
case 2:
statusText = '达标';
statusText = '達標';
statusColor = colorScheme.onSurfaceVariant;
break;
default:
statusText = '';
statusText = '';
statusColor = AppColorScheme.warning;
}
@@ -463,7 +463,7 @@ class _BillsPageState extends State<BillsPage> with SingleTickerProviderStateMix
}
// ============================================
// 通用
// 通用
// ============================================
Widget _buildEmptyState(IconData icon, String text) {
final colorScheme = Theme.of(context).colorScheme;

View File

@@ -6,7 +6,7 @@ import '../../../core/theme/app_color_scheme.dart';
import '../../../core/theme/app_spacing.dart';
import '../../../providers/auth_provider.dart';
/// 首页顶栏 - Logo + 搜索/通知/
/// 首頁頂欄 - Logo + 搜索/通知/
class HeaderBar extends StatelessWidget {
const HeaderBar({super.key});

View File

@@ -20,7 +20,7 @@ import 'hot_coins_section.dart';
import 'profit_analysis_page.dart';
import 'bills_page.dart';
/// 首
/// 首
class HomePage extends StatefulWidget {
const HomePage({super.key});
@@ -105,13 +105,13 @@ class _HomePageState extends State<HomePage>
// Header
HeaderBar(),
SizedBox(height: AppSpacing.md),
// 资产卡片(含估盈
// 資產卡片(含估盈
_AssetCard(
overview: provider.overview,
onDeposit: _showDeposit,
),
SizedBox(height: AppSpacing.md),
// 快捷操作
// 快捷操作
QuickActionsRow(
onDeposit: _showDeposit,
onWithdraw: _showWithdraw,
@@ -129,10 +129,10 @@ class _HomePageState extends State<HomePage>
),
),
SizedBox(height: AppSpacing.lg),
// 热门币种
// 熱門幣種
HotCoinsSection(),
SizedBox(height: AppSpacing.lg),
// 持
// 持
_HoldingsSection(holdings: provider.holdings),
],
),
@@ -174,7 +174,7 @@ class _HomePageState extends State<HomePage>
}
}
/// 资产卡片(含估盈
/// 資產卡片(含估盈
class _AssetCard extends StatefulWidget {
final AssetOverview? overview;
final VoidCallback onDeposit;
@@ -197,7 +197,7 @@ class _AssetCardState extends State<_AssetCard> {
@override
void didUpdateWidget(covariant _AssetCard oldWidget) {
super.didUpdateWidget(oldWidget);
// overview 更新重新加载盈亏数据
// overview 更新重新加載盈虧數據
if (widget.overview != oldWidget.overview) {
_loadProfit();
}
@@ -239,7 +239,7 @@ class _AssetCardState extends State<_AssetCard> {
final upColor = context.appColors.up;
final downColor = context.appColors.down;
// 总资产
// 總資產
final totalAsset = widget.overview?.totalAsset ?? '0.00';
final displayAsset = _formatAsset(totalAsset);
@@ -249,12 +249,12 @@ class _AssetCardState extends State<_AssetCard> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 部行:总资产标签 + 充值按
// 部行:總資產標籤 + 充值按
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'预估总资产(USDT)',
'預估總資產(USDT)',
style: AppTextStyles.bodyLarge(context),
),
GestureDetector(
@@ -284,7 +284,7 @@ class _AssetCardState extends State<_AssetCard> {
),
SizedBox(height: AppSpacing.sm),
// 总资产金额
// 總資產金額
Text(
displayAsset,
style: AppTextStyles.displayLarge(context).copyWith(
@@ -293,13 +293,13 @@ class _AssetCardState extends State<_AssetCard> {
),
SizedBox(height: AppSpacing.md),
// 盈亏统计区:预估今日盈 | 预估总盈亏
// 盈虧統計區:預估今日盈 | 預估總盈虧
Row(
children: [
// 估今日盈
// 估今日盈
Expanded(
child: _ProfitStatCard(
label: '估今日盈',
label: '估今日盈',
value: _todayProfit,
upColor: upColor,
downColor: downColor,
@@ -310,10 +310,10 @@ class _AssetCardState extends State<_AssetCard> {
),
),
SizedBox(width: AppSpacing.sm),
// 预估总盈亏
// 預估總盈虧
Expanded(
child: _ProfitStatCard(
label: '预估总盈亏',
label: '預估總盈虧',
value: _totalProfit,
upColor: upColor,
downColor: downColor,
@@ -357,7 +357,7 @@ class _WelfareCard extends StatelessWidget {
),
child: Row(
children: [
// 左侧图标
// 左側圖標
Container(
width: 48,
height: 48,
@@ -372,7 +372,7 @@ class _WelfareCard extends StatelessWidget {
),
),
SizedBox(width: AppSpacing.md),
// 中文字
// 中文字
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -386,14 +386,14 @@ class _WelfareCard extends StatelessWidget {
SizedBox(height: AppSpacing.xs),
Text(
totalClaimable > 0
? '您有 $totalClaimable 个奖励待领'
: '首充奖励 + 推广奖励',
? '您有 $totalClaimable 個獎勵待領'
: '首充獎勵 + 推廣獎勵',
style: AppTextStyles.bodyMedium(context),
),
],
),
),
// 右侧按钮
// 右側按鈕
Container(
padding: EdgeInsets.symmetric(
horizontal: AppSpacing.md,
@@ -440,7 +440,7 @@ class _WelfareCard extends StatelessWidget {
}
}
/// 持部分
/// 持部分
class _HoldingsSection extends StatelessWidget {
final List<AccountTrade> holdings;
@@ -454,7 +454,7 @@ class _HoldingsSection extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'我的持',
'我的持',
style: AppTextStyles.headlineLarge(context).copyWith(
fontWeight: FontWeight.bold,
),
@@ -467,7 +467,7 @@ class _HoldingsSection extends StatelessWidget {
),
child: Row(
children: [
Text('资产详',
Text('資產詳',
style: AppTextStyles.headlineSmall(context).copyWith(
fontWeight: FontWeight.bold,
)),
@@ -486,7 +486,7 @@ class _HoldingsSection extends StatelessWidget {
}
}
/// 空持
/// 空持
class _EmptyHoldings extends StatelessWidget {
const _EmptyHoldings();
@@ -505,7 +505,7 @@ class _EmptyHoldings extends StatelessWidget {
Icon(LucideIcons.wallet, size: 48, color: context.colors.onSurfaceVariant),
SizedBox(height: AppSpacing.md),
Text(
'暂无持仓',
'暫無持倉',
style: AppTextStyles.headlineMedium(context).copyWith(
fontWeight: FontWeight.w600,
),
@@ -521,7 +521,7 @@ class _EmptyHoldings extends StatelessWidget {
}
}
/// 持列表
/// 持列表
class _HoldingsList extends StatelessWidget {
final List<AccountTrade> holdings;
@@ -554,7 +554,7 @@ class _HoldingsList extends StatelessWidget {
}
}
/// 持仓项
/// 持倉項
class _HoldingItem extends StatelessWidget {
final AccountTrade holding;
@@ -615,7 +615,7 @@ class _HoldingItem extends StatelessWidget {
}
}
/// 盈亏统计小卡片
/// 盈虧統計小卡片
class _ProfitStatCard extends StatelessWidget {
final String label;
final double value;

View File

@@ -4,7 +4,7 @@ import '../../../core/theme/app_theme.dart';
import '../../../core/theme/app_spacing.dart';
import '../../../core/theme/app_theme_extension.dart';
/// 首页热门币种区块
/// 首頁熱門幣種區塊
class HotCoinsSection extends StatelessWidget {
const HotCoinsSection({super.key});
@@ -19,7 +19,7 @@ class HotCoinsSection extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'热门币种',
'熱門幣種',
style: AppTextStyles.headlineLarge(context),
),
Text(

View File

@@ -6,7 +6,7 @@ import '../../../core/theme/app_spacing.dart';
import '../../../core/theme/app_theme_extension.dart';
import '../../../data/services/asset_service.dart';
/// 盈分析面 - 月度盈亏日历
/// 盈分析面 - 月度盈虧日曆
class ProfitAnalysisPage extends StatefulWidget {
const ProfitAnalysisPage({super.key});
@@ -27,7 +27,7 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
}
// ============================================
// 数据加载
// 數據加載
// ============================================
Future<void> _loadProfit() async {
@@ -64,7 +64,7 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
}
// ============================================
// 盈亏数据解析
// 盈虧數據解析
// ============================================
double? _getDayProfit(int day) {
@@ -86,7 +86,7 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
}
// ============================================
// 建 UI
// 建 UI
// ============================================
@override
@@ -98,7 +98,7 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
return Scaffold(
backgroundColor: context.colors.surface,
appBar: AppBar(
title: const Text('分析'),
title: const Text('分析'),
backgroundColor: context.colors.surface,
elevation: 0,
scrolledUnderElevation: 0,
@@ -116,19 +116,19 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 月度盈摘要
// 月度盈摘要
_buildSummarySection(),
SizedBox(height: AppSpacing.md),
// 月份
// 月份
_buildMonthNavigation(isCurrentMonth),
SizedBox(height: AppSpacing.sm),
// 星期标题
// 星期標題
_buildWeekdayHeaders(),
SizedBox(height: AppSpacing.xs),
// 日历网
// 日曆網
if (_isLoading)
_buildLoadingIndicator()
else
@@ -143,7 +143,7 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
);
}
/// 月度盈摘要
/// 月度盈摘要
Widget _buildSummarySection() {
final upColor = context.appColors.up;
final downColor = context.appColors.down;
@@ -153,7 +153,7 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
return Column(
children: [
Text(
'月度盈',
'月度盈',
style: AppTextStyles.bodyMedium(context).copyWith(
color: context.colors.onSurfaceVariant,
),
@@ -172,7 +172,7 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
);
}
/// 月份航行
/// 月份航行
Widget _buildMonthNavigation(bool isCurrentMonth) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -193,14 +193,14 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
),
),
),
// 前年月
// 前年月
Text(
'${_currentMonth.year}${_currentMonth.month}',
style: AppTextStyles.headlineMedium(context).copyWith(
fontWeight: FontWeight.bold,
),
),
// 下一月(前月禁用)
// 下一月(前月禁用)
GestureDetector(
onTap: isCurrentMonth ? null : _nextMonth,
child: Container(
@@ -224,7 +224,7 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
);
}
/// 星期标题
/// 星期標題
Widget _buildWeekdayHeaders() {
return Row(
children: ['', '', '', '', '', '', ''].map((d) {
@@ -243,7 +243,7 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
);
}
/// 加指示器
/// 加指示器
Widget _buildLoadingIndicator() {
return Padding(
padding: EdgeInsets.symmetric(vertical: AppSpacing.xxl),
@@ -260,7 +260,7 @@ class _ProfitAnalysisPageState extends State<ProfitAnalysisPage> {
);
}
/// 日历网
/// 日曆網
List<Widget> _buildCalendarGrid(
DateTime now,
bool isCurrentMonth,

View File

@@ -3,7 +3,7 @@ import 'package:shadcn_ui/shadcn_ui.dart';
import '../../../core/theme/app_theme.dart';
import '../../../core/theme/app_spacing.dart';
/// 首快捷操作 - 充值/提现/划转/盈亏/账单
/// 首快捷操作 - 充值/提現/劃轉/盈虧/賬單
class QuickActionsRow extends StatelessWidget {
const QuickActionsRow({
super.key,
@@ -56,25 +56,25 @@ class QuickActionsRow extends StatelessWidget {
),
_ActionItem(
icon: LucideIcons.arrowDownLeft,
label: '',
label: '',
colorScheme: colorScheme,
onTap: onWithdraw,
),
_ActionItem(
icon: LucideIcons.repeat,
label: '划转',
label: '劃轉',
colorScheme: colorScheme,
onTap: onTransfer,
),
_ActionItem(
icon: LucideIcons.chartPie,
label: '',
label: '',
colorScheme: colorScheme,
onTap: onProfit,
),
_ActionItem(
icon: LucideIcons.fileText,
label: '账单',
label: '賬單',
colorScheme: colorScheme,
onTap: onBills,
),
@@ -105,7 +105,7 @@ class _ActionItem extends StatelessWidget {
? const Color(0xFF1E293B)
: const Color(0xFFF3F4F6);
// Light: #4B5563, Dark: 根据主题
// Light: #4B5563, Dark: 根據主題
final iconColor = isDark
? colorScheme.onSurfaceVariant
: const Color(0xFF4B5563);

View File

@@ -12,7 +12,7 @@ import '../trade/trade_page.dart';
import '../asset/asset_page.dart';
import '../mine/mine_page.dart';
/// 底部导航项
/// 底部導航項
class _NavItem {
final String label;
final IconData icon;
@@ -20,7 +20,7 @@ class _NavItem {
const _NavItem({required this.label, required this.icon});
}
/// 主面 - "The Kinetic Vault" 设计风
/// 主面 - "The Kinetic Vault" 設計風
class MainPage extends StatefulWidget {
const MainPage({super.key});
@@ -31,10 +31,10 @@ class MainPage extends StatefulWidget {
class MainPageState extends State<MainPage> {
int _currentIndex = 0;
final Set<int> _loadedPages = {0};
String? _tradeCoinCode; // 交易页面选中的币种代码
String? _tradeCoinCode; // 交易頁面選中的幣種代碼
late final List<Widget> _pages;
// 防抖:记录上次刷新时间,同一 Tab 500ms 不重刷新
// 防抖:記錄上次刷新時間,同一 Tab 500ms 不重刷新
final Map<int, DateTime> _lastRefreshTime = {};
@override
@@ -55,13 +55,13 @@ class MainPageState extends State<MainPage> {
_currentIndex = index;
_loadedPages.add(index);
});
// 切到已加的 Tab 刷新数据
// 切到已加的 Tab 刷新數據
if (wasLoaded) {
_refreshTab(index);
}
}
/// 刷新对应 Tab 的数据(带防抖)
/// 刷新對應 Tab 的數據(帶防抖)
void _refreshTab(int index) {
final now = DateTime.now();
final last = _lastRefreshTime[index];
@@ -69,30 +69,33 @@ class MainPageState extends State<MainPage> {
_lastRefreshTime[index] = now;
switch (index) {
case 0: // 首 - 刷新资产概览
case 0: // 首 - 刷新資產概覽
context.read<AssetProvider>().loadOverview(force: true);
break;
case 1: // 行情 - 刷新币种列表
case 1: // 行情 - 刷新幣種列表
context.read<MarketProvider>().loadCoins(force: true);
break;
case 3: // 资产 - 刷新全部资产
case 3: // 資產 - 刷新全部資產
context.read<AssetProvider>().refreshAll(force: true);
break;
}
}
/// 切到交易页面并选中指定币种
/// 切到交易頁面並選中指定幣種
void switchToTrade(String coinCode) {
setState(() {
_tradeCoinCode = coinCode;
_currentIndex = 2; // 交易面索引
_currentIndex = 2; // 交易面索引
_loadedPages.add(2);
// 重新建交易页面
_pages[2] = TradePage(initialCoinCode: _tradeCoinCode);
// 重新建交易頁面(用 Key 強制創建新 State
_pages[2] = TradePage(
key: ValueKey(_tradeCoinCode),
initialCoinCode: _tradeCoinCode,
);
});
}
/// 切到指定 tab
/// 切到指定 tab
void switchToTab(int index) {
setState(() {
_currentIndex = index;
@@ -101,10 +104,10 @@ class MainPageState extends State<MainPage> {
}
static const _navItems = [
_NavItem(label: '', icon: LucideIcons.house),
_NavItem(label: '', icon: LucideIcons.house),
_NavItem(label: '行情', icon: LucideIcons.trendingUp),
_NavItem(label: '交易', icon: LucideIcons.arrowLeftRight),
_NavItem(label: '资产', icon: LucideIcons.wallet),
_NavItem(label: '資產', icon: LucideIcons.wallet),
_NavItem(label: '我的', icon: LucideIcons.user),
];
@@ -128,7 +131,7 @@ class MainPageState extends State<MainPage> {
}
}
/// 底部导航栏 - 专业信任主
/// 底部導航欄 - 專業信任主
class _BottomNavBar extends StatelessWidget {
final List<_NavItem> items;
final int currentIndex;
@@ -175,7 +178,7 @@ class _BottomNavBar extends StatelessWidget {
}
}
/// 导航项组
/// 導航項組
class _NavItemWidget extends StatelessWidget {
final _NavItem item;
final bool isSelected;
@@ -220,7 +223,7 @@ class _NavItemWidget extends StatelessWidget {
}
}
/// 懒加载 IndexedStack - 只渲染已访问过的页
/// 懶加載 IndexedStack - 只渲染已訪問過的頁
class LazyIndexedStack extends StatefulWidget {
final int index;
final Set<int> loadedIndexes;

View File

@@ -10,7 +10,7 @@ import '../../../providers/market_provider.dart';
import '../../components/glass_panel.dart';
import '../main/main_page.dart';
/// 行情
/// 行情
class MarketPage extends StatefulWidget {
const MarketPage({super.key});
@@ -62,7 +62,7 @@ class _MarketPageState extends State<MarketPage>
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 页面标题 "行情"
// 頁面標題 "行情"
Padding(
padding: const EdgeInsets.only(bottom: AppSpacing.sm),
child: Text(
@@ -71,13 +71,13 @@ class _MarketPageState extends State<MarketPage>
),
),
const SizedBox(height: AppSpacing.md),
// 精选区BTC + ETH 卡片
// 精選區BTC + ETH 卡片
_buildFeaturedSection(provider),
const SizedBox(height: AppSpacing.md),
// 分区标题:全部币种 + 更多
// 分區標題:全部幣種 + 更多
_buildSectionHeader(),
const SizedBox(height: AppSpacing.md),
// 币种列表卡片
// 幣種列表卡片
_buildCoinList(provider),
],
),
@@ -88,7 +88,7 @@ class _MarketPageState extends State<MarketPage>
);
}
/// 精选区BTC + ETH 大卡片
/// 精選區BTC + ETH 大卡片
Widget _buildFeaturedSection(MarketProvider provider) {
final featured = provider.featuredCoins;
if (featured.isEmpty) return const SizedBox.shrink();
@@ -111,13 +111,13 @@ class _MarketPageState extends State<MarketPage>
);
}
/// 分区标题:全部币种 + 更多
/// 分區標題:全部幣種 + 更多
Widget _buildSectionHeader() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'全部币种',
'全部幣種',
style: AppTextStyles.headlineLarge(context),
),
Text(
@@ -130,14 +130,14 @@ class _MarketPageState extends State<MarketPage>
);
}
/// 币种列表
/// 幣種列表
Widget _buildCoinList(MarketProvider provider) {
final coins = provider.otherCoins;
if (coins.isEmpty) {
return _EmptyState(
icon: LucideIcons.coins,
message: '暂无数据',
message: '暫無數據',
onRetry: () => provider.refresh(),
);
}
@@ -167,7 +167,7 @@ class _MarketPageState extends State<MarketPage>
);
}
/// 错误状态
/// 錯誤狀態
Widget _buildErrorState(MarketProvider provider) {
return Center(
child: Padding(
@@ -178,14 +178,14 @@ class _MarketPageState extends State<MarketPage>
Icon(LucideIcons.circleAlert, size: 48, color: context.colors.error),
const SizedBox(height: AppSpacing.md),
Text(
provider.error ?? '载失败',
provider.error ?? '載失敗',
style: TextStyle(color: context.colors.error),
textAlign: TextAlign.center,
),
const SizedBox(height: AppSpacing.md),
ShadButton(
onPressed: () => provider.refresh(),
child: const Text(''),
child: const Text(''),
),
],
),
@@ -194,7 +194,7 @@ class _MarketPageState extends State<MarketPage>
}
}
/// 精卡片BTC / ETH (130px 高度,含迷你柱状图)
/// 精卡片BTC / ETH (130px 高度,含迷你柱狀圖)
class _FeaturedCard extends StatelessWidget {
final Coin coin;
@@ -216,13 +216,13 @@ class _FeaturedCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// 第一行:币种名称 + 跌徽章
// 第一行:幣種名稱 + 跌徽章
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${coin.code}/USDT',
style: AppTextStyles.labelLarge(context), // 小文字
style: AppTextStyles.labelLarge(context), // 小文字
),
Container(
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.xs + 2, vertical: 2),
@@ -234,27 +234,27 @@ class _FeaturedCard extends StatelessWidget {
coin.formattedChange,
style: AppTextStyles.labelSmall(context).copyWith(
color: changeColor,
fontSize: 10, // 小文字
fontSize: 10, // 小文字
),
),
),
],
),
// 第二行:
// 第二行:
Text(
'\$${_formatFeaturedPrice(coin)}',
style: AppTextStyles.headlineLarge(context).copyWith( // 小文字
style: AppTextStyles.headlineLarge(context).copyWith( // 小文字
fontWeight: FontWeight.bold,
),
),
// 第三行:币种全名
// 第三行:幣種全名
Text(
coin.name,
style: AppTextStyles.bodySmall(context).copyWith( // 小文字
style: AppTextStyles.bodySmall(context).copyWith( // 小文字
color: context.colors.onSurfaceVariant,
),
),
// 第四行:迷你柱状图
// 第四行:迷你柱狀圖
Expanded(
child: _MiniBarChart(isUp: isUp, seed: coin.code.hashCode),
),
@@ -263,7 +263,7 @@ class _FeaturedCard extends StatelessWidget {
);
}
/// 精卡片使用简短价格格式(带逗号
/// 精卡片使用簡短價格格式(帶逗號
String _formatFeaturedPrice(Coin coin) {
if (coin.price >= 1000) {
return _addCommas(coin.price.toStringAsFixed(2));
@@ -288,7 +288,7 @@ class _FeaturedCard extends StatelessWidget {
}
}
/// 迷你柱状图(模拟价格走
/// 迷你柱狀圖(模擬價格走
class _MiniBarChart extends StatelessWidget {
final bool isUp;
final int seed;
@@ -301,7 +301,7 @@ class _MiniBarChart extends StatelessWidget {
? context.appColors.up
: context.appColors.down;
// 生成随机但确定的高度序列
// 生成隨機但確定的高度序列
final heights = _generateHeights();
return Row(
@@ -310,7 +310,7 @@ class _MiniBarChart extends StatelessWidget {
children: heights.map((h) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 2), // 增加
padding: const EdgeInsets.only(left: 2), // 增加
child: Container(
height: h,
decoration: BoxDecoration(
@@ -326,13 +326,13 @@ class _MiniBarChart extends StatelessWidget {
List<double> _generateHeights() {
final random = Random(seed);
final base = 6.0; // 降低基高度
final range = 12.0; // 降低范围
final base = 6.0; // 降低基高度
final range = 12.0; // 降低範圍
return List.generate(6, (_) => base + random.nextDouble() * range);
}
}
/// 币种列表行
/// 幣種列表行
class _CoinRow extends StatelessWidget {
final Coin coin;
@@ -354,10 +354,10 @@ class _CoinRow extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md, vertical: 14),
child: Row(
children: [
// 像:形字母
// 像:形字母
_CoinAvatar(letter: coin.displayIcon, code: coin.code),
const SizedBox(width: AppSpacing.sm + AppSpacing.xs),
// 币种信息:交易 + 全名
// 幣種信息:交易 + 全名
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -375,7 +375,7 @@ class _CoinRow extends StatelessWidget {
],
),
),
// 右侧:价格 + 涨跌标签
// 右側:價格 + 漲跌標籤
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
@@ -412,7 +412,7 @@ class _CoinRow extends StatelessWidget {
}
}
/// 币种头像组
/// 幣種頭像組
class _CoinAvatar extends StatelessWidget {
final String letter;
final String code;
@@ -421,7 +421,7 @@ class _CoinAvatar extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 使用主题变量而非硬编码
// 使用主題變量而非硬編碼
final bgColor = context.colors.primary.withValues(alpha: context.appColors.glowOpacity);
return Container(
@@ -456,7 +456,7 @@ class _CoinAvatar extends StatelessWidget {
}
}
/// 空状态
/// 空狀態
class _EmptyState extends StatelessWidget {
final IconData icon;
final String message;
@@ -481,7 +481,7 @@ class _EmptyState extends StatelessWidget {
const SizedBox(height: AppSpacing.md),
ShadButton(
onPressed: onRetry,
child: const Text(''),
child: const Text(''),
),
],
],

View File

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import '../../../../core/theme/app_spacing.dart';
import '../../../../core/theme/app_theme.dart';
/// 信息行件(用于关于对话框)
/// 信息行件(用於關於對話框)
class InfoRow extends StatelessWidget {
final IconData icon;
final String text;

View File

@@ -1,9 +1,9 @@
import 'package:flutter/material.dart';
/// 圆形头像组
/// 圓形頭像組
///
/// 示用首字母或默比特币符号。通 [radius] 控制大小,
/// [fontSize] 控制文字大小,[text] 可入用户头像文字。
/// 示用首字母或默比特幣符號。通 [radius] 控制大小,
/// [fontSize] 控制文字大小,[text] 可入用戶頭像文字。
class AvatarCircle extends StatelessWidget {
final double radius;
final double fontSize;

View File

@@ -3,7 +3,7 @@ import '../../../../core/theme/app_color_scheme.dart';
import '../../../../core/theme/app_spacing.dart';
import '../../../../core/theme/app_theme.dart';
/// 退出登录按钮
/// 退出登錄按鈕
class LogoutButton extends StatelessWidget {
final VoidCallback onLogout;
const LogoutButton({super.key, required this.onLogout});
@@ -24,7 +24,7 @@ class LogoutButton extends StatelessWidget {
),
child: Center(
child: Text(
'退出登',
'退出登',
style: AppTextStyles.headlineMedium(context).copyWith(
color: AppColorScheme.down,
),

View File

@@ -10,7 +10,7 @@ import 'menu_group_container.dart';
import 'menu_row.dart';
import 'menu_trailing_widgets.dart';
/// 菜单分组1 - 福利中心 / 实名认证 / 安全置 / 消息通知
/// 菜單分組1 - 福利中心 / 實名認證 / 安全置 / 消息通知
class MenuGroup1 extends StatelessWidget {
final int kycStatus;
final void Function(String) onShowComingSoon;
@@ -39,11 +39,11 @@ class MenuGroup1 extends StatelessWidget {
},
),
const Divider(height: 1),
// 实名认证
// 實名認證
MenuRow(
icon: LucideIcons.shieldCheck,
iconColor: context.appColors.up,
title: '实名认证',
title: '實名認證',
trailing: KycBadge(kycStatus: kycStatus),
onTap: () {
if (kycStatus == 2) {
@@ -57,12 +57,12 @@ class MenuGroup1 extends StatelessWidget {
},
),
const Divider(height: 1),
// 安全
// 安全
MenuRow(
icon: LucideIcons.lock,
iconColor: context.colors.onSurfaceVariant,
title: '安全',
onTap: () => onShowComingSoon('安全'),
title: '安全',
onTap: () => onShowComingSoon('安全'),
),
const Divider(height: 1),
// 消息通知
@@ -79,7 +79,7 @@ class MenuGroup1 extends StatelessWidget {
}
}
/// 示 KYC 认证状态对话
/// 示 KYC 認證狀態對話
void showKycStatusDialog(BuildContext context) {
showShadDialog(
context: context,
@@ -88,13 +88,13 @@ void showKycStatusDialog(BuildContext context) {
children: [
Icon(Icons.check_circle, color: AppColorScheme.up, size: 20),
SizedBox(width: AppSpacing.sm),
const Text('实名认证'),
const Text('實名認證'),
],
),
description: const Text('您的实名认证已通'),
description: const Text('您的實名認證已通'),
actions: [
ShadButton(
child: const Text(''),
child: const Text(''),
onPressed: () => Navigator.of(ctx).pop(),
),
],

View File

@@ -4,7 +4,7 @@ import 'menu_group_container.dart';
import 'menu_row.dart';
import 'menu_trailing_widgets.dart';
/// 菜单分组2 - 深色模式 / 系统设置 / 关于我们
/// 菜單分組2 - 深色模式 / 系統設置 / 關於我們
class MenuGroup2 extends StatelessWidget {
final VoidCallback onShowAbout;
@@ -20,21 +20,21 @@ class MenuGroup2 extends StatelessWidget {
// 深色模式
const DarkModeRow(),
const Divider(height: 1),
// 系统设
// 系統設
MenuRow(
icon: LucideIcons.settings,
iconColor: colorScheme.onSurfaceVariant,
title: '统设',
title: '統設',
onTap: () {
// TODO: 系统设
// TODO: 系統設
},
),
const Divider(height: 1),
// 关于我们
// 關於我們
MenuRow(
icon: LucideIcons.info,
iconColor: colorScheme.onSurfaceVariant,
title: '关于我们',
title: '關於我們',
onTap: onShowAbout,
),
],

View File

@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
import '../../../../core/theme/app_spacing.dart';
import '../../../../core/theme/app_theme_extension.dart';
/// 菜单分组容器 - 一的角卡片
/// 菜單分組容器 - 一的角卡片
///
/// 所有菜单分组共享相同的容器式:背景色、角、框。
/// 通 [child] 入菜单项 Column。
/// 所有菜單分組共享相同的容器式:背景色、角、框。
/// 通 [child] 入菜單項 Column。
class MenuGroupContainer extends StatelessWidget {
final Widget child;

View File

@@ -4,9 +4,9 @@ import '../../../../core/theme/app_spacing.dart';
import '../../../../core/theme/app_theme.dart';
import '../../../../core/theme/app_theme_extension.dart';
/// 行菜单项:图标 + 标题 + 尾部件 (chevron)
/// 行菜單項:圖標 + 標題 + 尾部件 (chevron)
///
/// 图标颜色 (通常是使用主色)
/// 圖標顏色 (通常是使用主色)
class MenuRow extends StatelessWidget {
final IconData icon;
final Color iconColor;

View File

@@ -7,12 +7,12 @@ import '../../../../core/theme/app_theme.dart';
import '../../../../core/theme/app_theme_extension.dart';
import '../../../../providers/theme_provider.dart';
/// KYC 状态徽章 (e.g. "已认证" green badge + chevron)
/// KYC 狀態徽章 (e.g. "已認證" green badge + chevron)
///
/// 根 [kycStatus] 示不同状态
/// - 2: 已认证(绿色)
/// - 1: 核中(橙色)
/// - 其他: 仅显示 chevron
/// 根 [kycStatus] 示不同狀態
/// - 2: 已認證(綠色)
/// - 1: 核中(橙色)
/// - 其他: 僅顯示 chevron
class KycBadge extends StatelessWidget {
final int kycStatus;
const KycBadge({super.key, required this.kycStatus});
@@ -32,7 +32,7 @@ class KycBadge extends StatelessWidget {
borderRadius: BorderRadius.circular(AppRadius.sm),
),
child: Text(
'认证',
'認證',
style: AppTextStyles.labelMedium(context).copyWith(
color: green,
),
@@ -59,7 +59,7 @@ class KycBadge extends StatelessWidget {
borderRadius: BorderRadius.circular(AppRadius.sm),
),
child: Text(
'核中',
'核中',
style: AppTextStyles.labelMedium(context).copyWith(
color: AppColorScheme.warning,
),
@@ -83,7 +83,7 @@ class KycBadge extends StatelessWidget {
}
}
/// 红点指示器 - 消息通知 + chevron
/// 紅點指示器 - 消息通知 + chevron
class RedDotIndicator extends StatelessWidget {
const RedDotIndicator({super.key});
@@ -111,7 +111,7 @@ class RedDotIndicator extends StatelessWidget {
}
}
/// 深色模式切
/// 深色模式切
class DarkModeRow extends StatelessWidget {
const DarkModeRow({super.key});

View File

@@ -5,7 +5,7 @@ import '../../../../core/theme/app_theme.dart';
import '../../../../core/theme/app_theme_extension.dart';
import 'avatar_circle.dart';
/// 用户资料卡片 - 像 + 用名 + 徽章 + chevron
/// 用戶資料卡片 - 像 + 用名 + 徽章 + chevron
class ProfileCard extends StatelessWidget {
final dynamic user;
const ProfileCard({super.key, required this.user});
@@ -37,12 +37,12 @@ class ProfileCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
user?.username ?? '未登',
user?.username ?? '未登',
style: AppTextStyles.headlineLarge(context),
),
const SizedBox(height: 4),
Text(
'普通用',
'普通用',
style: AppTextStyles.bodyMedium(context).copyWith(
fontWeight: FontWeight.normal,
),

View File

@@ -11,7 +11,7 @@ import '../../../providers/auth_provider.dart';
import '../../components/glass_panel.dart';
import '../../components/neon_glow.dart';
/// KYC 实名认证页
/// KYC 實名認證頁
class KycPage extends StatefulWidget {
final bool returnToWithdraw;
@@ -64,7 +64,7 @@ class _KycPageState extends State<KycPage> {
backgroundColor: colorScheme.surface.withOpacity(0.0),
elevation: 0,
title: Text(
'实名认证',
'實名認證',
style: AppTextStyles.headlineLarge(context),
),
leading: IconButton(
@@ -77,17 +77,17 @@ class _KycPageState extends State<KycPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 步指示器
// 步指示器
_buildStepIndicator(colorScheme),
SizedBox(height: AppSpacing.xl),
// 主表单区
// 主表單區
GlassPanel(
padding: EdgeInsets.all(AppSpacing.lg),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 标题区
// 標題區
Row(
children: [
Container(
@@ -107,12 +107,12 @@ class _KycPageState extends State<KycPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'身份验证',
'身份驗證',
style: AppTextStyles.headlineLarge(context),
),
SizedBox(height: 2),
Text(
'身份正反面完成实名认证',
'身份正反面完成實名認證',
style: AppTextStyles.bodyMedium(context),
),
],
@@ -121,9 +121,9 @@ class _KycPageState extends State<KycPage> {
),
SizedBox(height: AppSpacing.xl),
// 身份正面上传区
// 身份正面上傳區
Text(
'身份正面(人像面)',
'身份正面(人像面)',
style: AppTextStyles.headlineSmall(context),
),
SizedBox(height: AppSpacing.sm),
@@ -136,26 +136,26 @@ class _KycPageState extends State<KycPage> {
),
SizedBox(height: AppSpacing.lg),
// 身份反面上传区
// 身份反面上傳區
Text(
'身份反面(徽面)',
'身份反面(徽面)',
style: AppTextStyles.headlineSmall(context),
),
SizedBox(height: AppSpacing.sm),
_buildUploadZone(
imageFile: _backFile,
imageBytes: _backBytes,
label: '徽面',
label: '徽面',
onTap: () => _pickImage(false),
colorScheme: colorScheme,
),
SizedBox(height: AppSpacing.xl),
// 提交按
// 提交按
SizedBox(
width: double.infinity,
child: NeonButton(
text: _isSubmitting ? '提交中...' : '提交认证',
text: _isSubmitting ? '提交中...' : '提交認證',
type: NeonButtonType.primary,
onPressed: _canSubmit ? _submitKyc : null,
height: 48,
@@ -187,7 +187,7 @@ class _KycPageState extends State<KycPage> {
SizedBox(width: AppSpacing.sm),
Expanded(
child: Text(
'您的身份信息被加密存储,仅用于身份验证',
'您的身份信息被加密存儲,僅用於身份驗證',
style: AppTextStyles.bodySmall(context).copyWith(
color: AppColorScheme.up.withOpacity(0.8),
),
@@ -209,7 +209,7 @@ class _KycPageState extends State<KycPage> {
children: [
_buildStepCircle(
number: '1',
label: '传证',
label: '傳證',
isActive: true,
isComplete: isComplete,
colorScheme: colorScheme,
@@ -224,7 +224,7 @@ class _KycPageState extends State<KycPage> {
),
_buildStepCircle(
number: '2',
label: '认证完成',
label: '認證完成',
isActive: false,
isComplete: false,
colorScheme: colorScheme,
@@ -317,12 +317,12 @@ class _KycPageState extends State<KycPage> {
child: Stack(
fit: StackFit.expand,
children: [
// 图片预览 - 使用 memory 以兼容 Web
// 圖片預覽 - 使用 memory 以兼容 Web
Image.memory(
imageBytes!,
fit: BoxFit.cover,
),
// 底部渐变遮罩 + 文字
// 底部漸變遮罩 + 文字
Positioned(
left: 0,
right: 0,
@@ -348,7 +348,7 @@ class _KycPageState extends State<KycPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'$label已选择',
'$label已選擇',
style: AppTextStyles.labelLarge(context).copyWith(
color: colorScheme.onPrimary,
),
@@ -400,7 +400,7 @@ class _KycPageState extends State<KycPage> {
),
SizedBox(height: AppSpacing.sm),
Text(
'点击上传$label',
'點擊上傳$label',
style: AppTextStyles.bodyLarge(context).copyWith(
color: colorScheme.onSurfaceVariant.withOpacity(0.6),
),
@@ -442,13 +442,13 @@ class _KycPageState extends State<KycPage> {
size: 20,
),
SizedBox(width: AppSpacing.sm),
const Text('认证成功'),
const Text('認證成功'),
],
),
description: const Text('您的实名认证已通过,现在可以行提操作'),
description: const Text('您的實名認證已通過,現在可以行提操作'),
actions: [
ShadButton(
child: const Text(''),
child: const Text(''),
onPressed: () {
Navigator.of(ctx).pop();
Navigator.of(context).pop();
@@ -461,11 +461,11 @@ class _KycPageState extends State<KycPage> {
showShadDialog(
context: context,
builder: (ctx) => ShadDialog.alert(
title: const Text('认证失败'),
description: Text(response.message ?? '请稍后重试'),
title: const Text('認證失敗'),
description: Text(response.message ?? '請稍後重試'),
actions: [
ShadButton(
child: const Text(''),
child: const Text(''),
onPressed: () => Navigator.of(ctx).pop(),
),
],
@@ -477,11 +477,11 @@ class _KycPageState extends State<KycPage> {
showShadDialog(
context: context,
builder: (ctx) => ShadDialog.alert(
title: const Text('认证失败'),
title: const Text('認證失敗'),
description: Text(e.toString()),
actions: [
ShadButton(
child: const Text(''),
child: const Text(''),
onPressed: () => Navigator.of(ctx).pop(),
),
],
@@ -494,7 +494,7 @@ class _KycPageState extends State<KycPage> {
}
}
/// 虚线边框画笔
/// 虛線邊框畫筆
class _DashedBorderPainter extends CustomPainter {
final Color color;
final double borderRadius;

View File

@@ -13,7 +13,7 @@ import 'components/menu_group1.dart';
import 'components/menu_group2.dart';
import 'components/profile_card.dart';
/// 我的面 - 匹配 .pen 设计稿
/// 我的面 - 匹配 .pen 設計稿
class MinePage extends StatefulWidget {
const MinePage({super.key});
@@ -77,10 +77,10 @@ class _MinePageState extends State<MinePage>
children: [
Icon(Icons.construction, color: AppColorScheme.warning, size: 20),
SizedBox(width: AppSpacing.sm),
const Text('功能开发'),
const Text('功能開發'),
],
),
description: Text('$feature功能正在开发,敬期待~'),
description: Text('$feature功能正在開發,敬期待~'),
actions: [
ShadButton(
child: const Text('知道了'),
@@ -100,7 +100,7 @@ class _MinePageState extends State<MinePage>
children: [
AvatarCircle(radius: 20, fontSize: 16),
SizedBox(width: AppSpacing.sm + AppSpacing.xs),
const Text(''),
const Text(''),
],
),
child: Column(
@@ -108,7 +108,7 @@ class _MinePageState extends State<MinePage>
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'虚拟货币模拟交易平',
'虛擬貨幣模擬交易平',
style: TextStyle(color: colorScheme.onSurfaceVariant),
),
SizedBox(height: AppSpacing.md),
@@ -121,7 +121,7 @@ class _MinePageState extends State<MinePage>
),
actions: [
ShadButton(
child: const Text(''),
child: const Text(''),
onPressed: () => Navigator.of(context).pop(),
),
],
@@ -133,8 +133,8 @@ class _MinePageState extends State<MinePage>
showShadDialog(
context: context,
builder: (ctx) => ShadDialog.alert(
title: const Text('确认退出'),
description: const Text('定要退出登录吗'),
title: const Text('確認退出'),
description: const Text('定要退出登錄嗎'),
actions: [
ShadButton.outline(
child: const Text('取消'),

View File

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

View File

@@ -6,12 +6,12 @@ import '../../../core/theme/app_theme.dart';
import '../../../core/theme/app_theme_extension.dart';
import '../../../core/storage/local_storage.dart';
/// 引导页数据模型
/// 引導頁數據模型
class _OnboardingItem {
final String title;
final String description;
final IconData? icon; // 图标(二一)
final String? imagePath; // 片路(二一)
final IconData? icon; // 圖標(二一)
final String? imagePath; // 片路(二一)
final List<Color> gradientColors;
const _OnboardingItem({
@@ -23,7 +23,7 @@ class _OnboardingItem {
});
}
/// 首次启动引导页
/// 首次啟動引導頁
class OnboardingPage extends StatefulWidget {
final VoidCallback onComplete;
@@ -39,27 +39,27 @@ class _OnboardingPageState extends State<OnboardingPage> {
final _items = const [
_OnboardingItem(
title: '实时行情',
description: '全球市行情实时更新,把握每一个投资机会',
imagePath: 'assets/images/onboarding_1.png', // 替换为你的
title: '實時行情',
description: '全球市行情實時更新,把握每一個投資機會',
imagePath: 'assets/images/onboarding_1.png', // 替換為你的
gradientColors: [AppColorScheme.darkPrimary, AppColorScheme.darkPrimaryContainer],
),
_OnboardingItem(
title: '交易',
description: '风险体验真实交易,学习投资策略',
imagePath: 'assets/images/onboarding_2.png', // 替换为你的
title: '交易',
description: '風險體驗真實交易,學習投資策略',
imagePath: 'assets/images/onboarding_2.png', // 替換為你的
gradientColors: [AppColorScheme.darkTertiary, AppColorScheme.darkTertiaryContainer],
),
_OnboardingItem(
title: '资产管理',
description: '清晰的资产概览,轻松管理你的投资组',
imagePath: 'assets/images/onboarding_3.png', // 替换为你的
title: '資產管理',
description: '清晰的資產概覽,輕鬆管理你的投資組',
imagePath: 'assets/images/onboarding_3.png', // 替換為你的
gradientColors: [AppColorScheme.darkSecondary, AppColorScheme.darkSecondaryFixed],
),
_OnboardingItem(
title: '安全可靠',
description: '数据加密存,保你的私安全',
imagePath: 'assets/images/onboarding_4.png', // 替换为你的
description: '數據加密存,保你的私安全',
imagePath: 'assets/images/onboarding_4.png', // 替換為你的
gradientColors: [AppColorScheme.darkPrimaryFixed, AppColorScheme.darkPrimaryFixedDim],
),
];
@@ -97,7 +97,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
body: SafeArea(
child: Column(
children: [
// 部跳过按钮
// 部跳過按鈕
Padding(
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.lg,
@@ -109,7 +109,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
TextButton(
onPressed: _skip,
child: Text(
'',
'',
style: AppTextStyles.headlineMedium(context).copyWith(
color: context.colors.onSurfaceVariant,
),
@@ -118,7 +118,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
],
),
),
// 页面内
// 頁面內
Expanded(
child: PageView.builder(
controller: _pageController,
@@ -133,7 +133,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
},
),
),
// 底部指示器和按
// 底部指示器和按
Padding(
padding: const EdgeInsets.fromLTRB(
AppSpacing.lg,
@@ -143,7 +143,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
),
child: Column(
children: [
// 面指示器
// 面指示器
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(
@@ -152,7 +152,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
),
),
const SizedBox(height: AppSpacing.xl),
// 下一步/始按
// 下一步/始按
SizedBox(
width: double.infinity,
height: 56,
@@ -167,7 +167,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
elevation: 0,
),
child: Text(
_currentPage == _items.length - 1 ? '始使用' : '下一步',
_currentPage == _items.length - 1 ? '始使用' : '下一步',
style: AppTextStyles.headlineLarge(context).copyWith(
fontWeight: FontWeight.w600,
),
@@ -189,7 +189,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 图标/图片容器
// 圖標/圖片容器
Container(
width: 200,
height: 200,
@@ -217,7 +217,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
height: 180,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
// 片加载失败时显示图标
// 片加載失敗時顯示圖標
return Icon(
item.icon ?? LucideIcons.image,
size: 72,
@@ -234,7 +234,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
),
),
const SizedBox(height: AppSpacing.xxl + AppSpacing.lg),
// 标题
// 標題
Text(
item.title,
style: AppTextStyles.displaySmall(context).copyWith(

View File

@@ -14,7 +14,7 @@ class _FundOrderCard extends StatelessWidget {
Color _getStatusColor(int status, bool isDeposit) {
if (isDeposit) {
// 充值状态: 1=待付款, 2=待确认, 3=已完成, 4=已回, 5=已取消
// 充值狀態: 1=待付款, 2=待確認, 3=已完成, 4=已回, 5=已取消
switch (status) {
case 1:
return AppColorScheme.warning;
@@ -30,7 +30,7 @@ class _FundOrderCard extends StatelessWidget {
return AppColorScheme.muted;
}
} else {
// 提现状态: 1=待批, 2=已出款, 3=已回, 4=已取消, 5=待财务审
// 提現狀態: 1=待批, 2=已出款, 3=已回, 4=已取消, 5=待財務審
switch (status) {
case 1:
return AppColorScheme.warning;
@@ -54,11 +54,11 @@ class _FundOrderCard extends StatelessWidget {
case 1:
return '待付款';
case 2:
return '确认';
return '確認';
case 3:
return '已完成';
case 4:
return '';
return '';
case 5:
return '已取消';
default:
@@ -67,15 +67,15 @@ class _FundOrderCard extends StatelessWidget {
} else {
switch (status) {
case 1:
return '';
return '';
case 2:
return '已出款';
case 3:
return '';
return '';
case 4:
return '已取消';
case 5:
return '财务审';
return '財務審';
default:
return '未知';
}
@@ -121,7 +121,7 @@ class _FundOrderCard extends StatelessWidget {
if (order.fee != null) ...[
Row(
children: [
Text('续费(10%): ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('續費(10%): ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('-${order.fee} USDT', style: AppTextStyles.bodyMedium(context)),
],
),
@@ -130,7 +130,7 @@ class _FundOrderCard extends StatelessWidget {
if (order.receivableAmount != null) ...[
Row(
children: [
Text('账金额: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('賬金額: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('${order.receivableAmount} USDT', style: AppTextStyles.bodyMedium(context).copyWith(fontWeight: FontWeight.w700)),
],
),
@@ -139,7 +139,7 @@ class _FundOrderCard extends StatelessWidget {
if (order.network != null) ...[
Row(
children: [
Text('现网络: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('現網絡: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text(order.network!, style: AppTextStyles.bodyMedium(context)),
],
),
@@ -148,7 +148,7 @@ class _FundOrderCard extends StatelessWidget {
if (order.walletAddress != null) ...[
Row(
children: [
Text('地址: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('地址: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Expanded(
child: Text(
order.walletAddress!,
@@ -164,16 +164,16 @@ class _FundOrderCard extends StatelessWidget {
],
Row(
children: [
Text('订单号: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('訂單號: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text(order.orderNo, style: AppTextStyles.bodyMedium(context)),
],
),
SizedBox(height: AppSpacing.xs),
Row(
children: [
Text('创建时间: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('創建時間: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text(
order.createTime?.toString() ?? '',
order.createTime?.toString() ?? '',
style: AppTextStyles.bodyMedium(context),
),
],
@@ -182,7 +182,7 @@ class _FundOrderCard extends StatelessWidget {
SizedBox(height: AppSpacing.xs),
Row(
children: [
Text('回原因: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('回原因: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Expanded(
child: Text(
order.rejectReason!,
@@ -206,7 +206,7 @@ class _FundOrderCard extends StatelessWidget {
Expanded(
child: ShadButton.outline(
onPressed: () => _handleCancel(context),
child: const Text('取消订单'),
child: const Text('取消訂單'),
),
),
],
@@ -222,12 +222,12 @@ class _FundOrderCard extends StatelessWidget {
if (context.mounted) {
if (response.success) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('确认打款,等待')),
const SnackBar(content: Text('確認打款,等待')),
);
context.read<AssetProvider>().loadFundOrders();
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(response.message ?? '确认失败')),
SnackBar(content: Text(response.message ?? '確認失敗')),
);
}
}
@@ -238,12 +238,12 @@ class _FundOrderCard extends StatelessWidget {
if (context.mounted) {
if (response.success) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('订单已取消')),
const SnackBar(content: Text('訂單已取消')),
);
context.read<AssetProvider>().loadFundOrders();
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(response.message ?? '取消失')),
SnackBar(content: Text(response.message ?? '取消失')),
);
}
}

View File

@@ -22,7 +22,7 @@ class FundOrdersList extends StatelessWidget {
if (orders.isEmpty) {
return _EmptyState(
icon: LucideIcons.receipt,
message: '暂无订单记录',
message: '暫無訂單記錄',
);
}
@@ -43,7 +43,7 @@ class FundOrdersList extends StatelessWidget {
}
}
/// 空状态组
/// 空狀態組
class _EmptyState extends StatelessWidget {
final IconData icon;
final String message;
@@ -70,7 +70,7 @@ class _EmptyState extends StatelessWidget {
}
}
/// 充值订单卡片 - 公开类
/// 充值訂單卡片 - 公開類
class FundOrderCard extends StatelessWidget {
final OrderFund order;
@@ -78,12 +78,12 @@ class FundOrderCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 直接使用 _FundOrderCard 的实现
// 直接使用 _FundOrderCard 的實現
return _FundOrderCardContent(order: order);
}
}
/// 订单卡片
/// 訂單卡片
class _FundOrderCardContent extends StatelessWidget {
final OrderFund order;
@@ -127,11 +127,11 @@ class _FundOrderCardContent extends StatelessWidget {
case 1:
return '待付款';
case 2:
return '确认';
return '確認';
case 3:
return '已完成';
case 4:
return '';
return '';
case 5:
return '已取消';
default:
@@ -140,11 +140,11 @@ class _FundOrderCardContent extends StatelessWidget {
} else {
switch (status) {
case 1:
return '';
return '';
case 2:
return '已出款';
case 3:
return '';
return '';
case 4:
return '已取消';
default:
@@ -192,7 +192,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.fee != null) ...[
Row(
children: [
Text('续费(10%): ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('續費(10%): ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('-${order.fee} USDT', style: AppTextStyles.bodyMedium(context)),
],
),
@@ -201,7 +201,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.receivableAmount != null) ...[
Row(
children: [
Text('账金额: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('賬金額: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('${order.receivableAmount} USDT', style: AppTextStyles.bodyMedium(context).copyWith(fontWeight: FontWeight.w700)),
],
),
@@ -210,7 +210,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.network != null) ...[
Row(
children: [
Text('现网络: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('現網絡: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text(order.network!, style: AppTextStyles.bodyMedium(context)),
],
),
@@ -219,7 +219,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.walletAddress != null) ...[
Row(
children: [
Text('地址: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('地址: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Expanded(
child: Text(
order.walletAddress!,
@@ -234,16 +234,16 @@ class _FundOrderCardContent extends StatelessWidget {
],
Row(
children: [
Text('订单号: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('訂單號: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text(order.orderNo, style: AppTextStyles.bodyMedium(context)),
],
),
SizedBox(height: AppSpacing.xs),
Row(
children: [
Text('创建时间: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('創建時間: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text(
order.createTime?.toString() ?? '',
order.createTime?.toString() ?? '',
style: AppTextStyles.bodyMedium(context),
),
],

View File

@@ -13,7 +13,7 @@ import '../../../core/event/app_event_bus.dart';
import '../../../providers/asset_provider.dart';
import '../../../data/models/order_models.dart';
/// 充提订单页
/// 充提訂單頁
class FundOrdersPage extends StatefulWidget {
const FundOrdersPage({super.key});
@@ -22,7 +22,7 @@ class FundOrdersPage extends StatefulWidget {
}
class _FundOrdersPageState extends State<FundOrdersPage> {
int _activeTab = 0; // 0=全部, 1=充值, 2=提
int _activeTab = 0; // 0=全部, 1=充值, 2=提
StreamSubscription<AppEvent>? _eventSub;
@override
@@ -53,7 +53,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
}
// ============================================
// 建 UI
// 建 UI
// ============================================
@override
@@ -65,7 +65,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
icon: const Icon(LucideIcons.arrowLeft, size: 20),
onPressed: () => Navigator.of(context).pop(),
),
title: Text('充提记录', style: AppTextStyles.headlineLarge(context).copyWith(color: context.colors.onSurface)),
title: Text('充提記錄', style: AppTextStyles.headlineLarge(context).copyWith(color: context.colors.onSurface)),
backgroundColor: context.colors.surface,
elevation: 0,
scrolledUnderElevation: 0,
@@ -97,7 +97,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
children: [
_buildPillTab('全部', 0),
_buildPillTab('充值', 1),
_buildPillTab('', 2),
_buildPillTab('', 2),
],
),
),
@@ -153,7 +153,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
children: [
Icon(LucideIcons.inbox, size: 64, color: context.appColors.onSurfaceMuted),
const SizedBox(height: AppSpacing.md),
Text('暂无订单记录', style: AppTextStyles.headlineMedium(context).copyWith(color: context.colors.onSurfaceVariant)),
Text('暫無訂單記錄', style: AppTextStyles.headlineMedium(context).copyWith(color: context.colors.onSurfaceVariant)),
],
),
);
@@ -199,7 +199,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
],
if (order.withdrawContact != null) ...[
const SizedBox(height: AppSpacing.sm - AppSpacing.xs),
_buildDetailRow('联系方式', order.withdrawContact!),
_buildDetailRow('聯繫方式', order.withdrawContact!),
],
if (order.receivableAmount != null && !order.isDeposit) ...[
const SizedBox(height: AppSpacing.sm),
@@ -214,13 +214,13 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'建: ${_formatTime(order.createTime)}',
'建: ${_formatTime(order.createTime)}',
style: AppTextStyles.bodySmall(context).copyWith(color: context.appColors.onSurfaceMuted),
),
if (order.rejectReason != null)
Expanded(
child: Text(
'回: ${order.rejectReason}',
'回: ${order.rejectReason}',
style: AppTextStyles.bodySmall(context).copyWith(color: context.appColors.down),
textAlign: TextAlign.right,
overflow: TextOverflow.ellipsis,
@@ -241,7 +241,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
order.isDeposit ? '充值' : '',
order.isDeposit ? '充值' : '',
style: AppTextStyles.headlineMedium(context).copyWith(color: context.colors.onSurface),
),
_buildStatusBadge(order),
@@ -261,7 +261,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
if (order.isDeposit) {
switch (order.status) {
case 1: // 待付款
case 2: // 待确认
case 2: // 待確認
bgColor = AppColorScheme.warning.withValues(alpha: 0.12);
textColor = AppColorScheme.warning;
break;
@@ -269,14 +269,14 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
bgColor = upBg;
textColor = upColor;
break;
default: // 已回/已取消
default: // 已回/已取消
bgColor = downBg;
textColor = downColor;
}
} else {
switch (order.status) {
case 1: // 待
case 5: // 待财务审
case 1: // 待
case 5: // 待財務審
bgColor = AppColorScheme.warning.withValues(alpha: 0.12);
textColor = AppColorScheme.warning;
break;
@@ -284,7 +284,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
bgColor = upBg;
textColor = upColor;
break;
default: // 已回/已取消
default: // 已回/已取消
bgColor = downBg;
textColor = downColor;
}
@@ -320,10 +320,10 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
Widget _buildDetailRows(OrderFund order) {
return Column(
children: [
_buildDetailRow('订单号', order.orderNo),
_buildDetailRow('訂單號', order.orderNo),
const SizedBox(height: AppSpacing.sm - AppSpacing.xs),
if (order.network != null) ...[
_buildDetailRow('网络', order.network!),
_buildDetailRow('網絡', order.network!),
const SizedBox(height: AppSpacing.sm - AppSpacing.xs),
],
if (order.walletAddress != null) ...[
@@ -333,7 +333,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
trailing: GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(text: order.walletAddress!));
ToastUtils.show('地址已复制');
ToastUtils.show('地址已複製');
},
child: Icon(LucideIcons.copy, size: 14, color: context.appColors.onSurfaceMuted),
),
@@ -341,11 +341,11 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
const SizedBox(height: AppSpacing.sm - AppSpacing.xs),
],
if (order.fee != null && !order.isDeposit) ...[
_buildDetailRow('续费', '${order.fee}%'),
_buildDetailRow('續費', '${order.fee}%'),
const SizedBox(height: AppSpacing.sm - AppSpacing.xs),
],
_buildDetailRow(
'时间',
'時間',
_formatTime(order.createTime),
),
],
@@ -383,7 +383,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
// ---------------------------------------------------------------------------
Widget _buildRejectionReason(OrderFund order) {
return Text(
'原因: ${order.rejectReason}',
'原因: ${order.rejectReason}',
style: AppTextStyles.bodyMedium(context).copyWith(color: context.appColors.down),
);
}
@@ -401,7 +401,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('付金', style: AppTextStyles.headlineSmall(context).copyWith(color: context.colors.onSurfaceVariant)),
Text('付金', style: AppTextStyles.headlineSmall(context).copyWith(color: context.colors.onSurfaceVariant)),
Text('${order.receivableAmount} USDT', style: AppTextStyles.headlineMedium(context).copyWith(color: context.colors.onSurface)),
],
),
@@ -427,7 +427,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
borderRadius: AppRadius.radiusSm,
border: Border.all(color: downColor, width: 1),
),
child: Text('取消订单', style: AppTextStyles.headlineSmall(context).copyWith(color: downColor)),
child: Text('取消訂單', style: AppTextStyles.headlineSmall(context).copyWith(color: downColor)),
),
),
if (order.canCancel && order.canConfirmPay)
@@ -467,14 +467,14 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
void _confirmPay(OrderFund order) async {
final confirmed = await showShadConfirmDialog(
context: context,
title: '确认已打款',
description: '确认您已完成向指定地址的转账',
title: '確認已打款',
description: '確認您已完成向指定地址的轉賬',
);
if (confirmed == true && mounted) {
final response = await context.read<AssetProvider>().confirmPay(order.orderNo);
if (mounted) {
BotToast.showText(text: response.success ? '确认成功,等待' : response.message ?? '确认失败');
BotToast.showText(text: response.success ? '確認成功,等待' : response.message ?? '確認失敗');
}
}
}
@@ -482,15 +482,15 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
void _cancelOrder(OrderFund order) async {
final confirmed = await showShadConfirmDialog(
context: context,
title: '取消订单',
description: '定要取消订单 ${order.orderNo} ',
title: '取消訂單',
description: '定要取消訂單 ${order.orderNo} ',
destructive: true,
);
if (confirmed == true && mounted) {
final response = await context.read<AssetProvider>().cancelOrder(order.orderNo);
if (mounted) {
BotToast.showText(text: response.success ? '订单已取消' : response.message ?? '取消失');
BotToast.showText(text: response.success ? '訂單已取消' : response.message ?? '取消失');
}
}
}
@@ -512,7 +512,7 @@ class _FundOrdersPageState extends State<FundOrdersPage> {
onPressed: () => Navigator.pop(context, false),
),
TextButton(
child: Text(destructive ? '定取消' : '确认'),
child: Text(destructive ? '定取消' : '確認'),
onPressed: () => Navigator.pop(context, true),
),
],

View File

@@ -8,7 +8,7 @@ import '../../../core/theme/app_theme_extension.dart';
import '../../../providers/asset_provider.dart';
import 'fund_orders_list.dart';
/// 订单管理
/// 訂單管理
class OrdersPage extends StatefulWidget {
const OrdersPage({super.key});
@@ -50,7 +50,7 @@ class _OrdersPageState extends State<OrdersPage> with AutomaticKeepAliveClientMi
child: Column(
children: [
TabSelector(
tabs: const ['订单记录', '交易记录'],
tabs: const ['訂單記錄', '交易記錄'],
selectedIndex: _activeTab,
onChanged: (index) => setState(() => _activeTab = index),
),
@@ -68,7 +68,7 @@ class _OrdersPageState extends State<OrdersPage> with AutomaticKeepAliveClientMi
}
}
/// Tab 选择
/// Tab 選擇
class TabSelector extends StatelessWidget {
final List<String> tabs;
final int selectedIndex;
@@ -129,7 +129,7 @@ class TabSelector extends StatelessWidget {
}
}
/// 交易订单列表
/// 交易訂單列表
class TradeOrdersList extends StatelessWidget {
final AssetProvider provider;
@@ -147,7 +147,7 @@ class TradeOrdersList extends StatelessWidget {
children: [
Icon(LucideIcons.receipt, size: 48, color: theme.colorScheme.mutedForeground),
SizedBox(height: AppSpacing.sm + AppSpacing.xs),
Text('暂无交易记录', style: theme.textTheme.muted),
Text('暫無交易記錄', style: theme.textTheme.muted),
],
),
),

View File

@@ -3,10 +3,10 @@ import '../../../../core/theme/app_color_scheme.dart';
import '../../../../core/theme/app_spacing.dart';
import '../../../../core/theme/app_theme.dart';
/// 金额输入框件(含超提示)
/// 金額輸入框件(含超提示)
///
/// 设计稿bg-tertiary角md高48。
/// 入金额超过可用 USDT 余额时显示警告提示。
/// 設計稿bg-tertiary角md高48。
/// 入金額超過可用 USDT 餘額時顯示警告提示。
class AmountInput extends StatefulWidget {
final TextEditingController amountController;
final String maxAmount;
@@ -63,7 +63,7 @@ class _AmountInputState extends State<AmountInput> {
Container(
height: 48,
decoration: BoxDecoration(
color: colorScheme.surfaceContainerHighest.withOpacity(0.5), // 整透明度
color: colorScheme.surfaceContainerHighest.withOpacity(0.5), // 調整透明度
borderRadius: BorderRadius.circular(AppRadius.md),
),
child: TextField(
@@ -74,7 +74,7 @@ class _AmountInputState extends State<AmountInput> {
fontWeight: FontWeight.w400,
),
decoration: InputDecoration(
hintText: '请输入金',
hintText: '請輸入金',
hintStyle: AppTextStyles.numberMedium(context).copyWith(
fontWeight: FontWeight.w400,
color: colorScheme.onSurfaceVariant.withOpacity(0.5),
@@ -94,7 +94,7 @@ class _AmountInputState extends State<AmountInput> {
Icon(Icons.error_outline, size: 13, color: warningColor),
SizedBox(width: AppSpacing.xs),
Text(
'超出可用USDT余额',
'超出可用USDT餘額',
style: AppTextStyles.bodySmall(context).copyWith(
color: warningColor,
),

View File

@@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
import '../../../../core/theme/app_spacing.dart';
import '../../../../core/theme/app_theme.dart';
/// 币种头像组
/// 幣種頭像組
///
/// 显示币种图标或首字母的圆形头像,带主题色边框和背景。
/// 顯示幣種圖標或首字母的圓形頭像,帶主題色邊框和背景。
class CoinAvatar extends StatelessWidget {
final String? icon;
const CoinAvatar({super.key, this.icon});

View File

@@ -6,9 +6,9 @@ import '../../../../core/theme/app_theme_extension.dart';
import '../../../../data/models/coin.dart';
import 'coin_avatar.dart';
/// 币种选择器组
/// 幣種選擇器組
///
/// 显示当前选中的币种交易对,点击弹出底部弹窗选择币种
/// 顯示當前選中的幣種交易對,點擊彈出底部彈窗選擇幣種
class CoinSelector extends StatelessWidget {
final Coin? selectedCoin;
final List<Coin> coins;
@@ -38,7 +38,7 @@ class CoinSelector extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// 币种信息:交易 + 名
// 幣種信息:交易 + 名
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
@@ -46,19 +46,19 @@ class CoinSelector extends StatelessWidget {
Text(
selectedCoin != null
? '${selectedCoin!.code}/USDT'
: '选择币种',
: '選擇幣種',
style: AppTextStyles.headlineLarge(context),
),
const SizedBox(height: 2),
Text(
selectedCoin?.name ?? '点击选择交易',
selectedCoin?.name ?? '點擊選擇交易',
style: AppTextStyles.bodyMedium(context).copyWith(
color: context.colors.onSurfaceVariant,
),
),
],
),
// 下拉箭
// 下拉箭
Icon(LucideIcons.chevronDown,
size: 16, color: context.colors.onSurfaceVariant),
],
@@ -83,7 +83,7 @@ class CoinSelector extends StatelessWidget {
),
child: Column(
children: [
// 拖指示器
// 拖指示器
Container(
margin: EdgeInsets.only(top: AppSpacing.sm),
width: 40,
@@ -93,13 +93,13 @@ class CoinSelector extends StatelessWidget {
borderRadius: BorderRadius.circular(AppRadius.sm),
),
),
// 标题栏
// 標題欄
Padding(
padding: EdgeInsets.all(AppSpacing.lg),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('选择币种',
Text('選擇幣種',
style: AppTextStyles.headlineLarge(context)),
GestureDetector(
onTap: () => Navigator.of(ctx).pop(),
@@ -110,7 +110,7 @@ class CoinSelector extends StatelessWidget {
),
),
Divider(height: 1, color: ctx.colors.outlineVariant.withValues(alpha: 0.2)),
// 币种列表
// 幣種列表
Expanded(
child: ListView.builder(
padding: EdgeInsets.symmetric(vertical: AppSpacing.sm),
@@ -150,7 +150,7 @@ class CoinSelector extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 第一行:币种代码 + USDT + 格 + 跌幅
// 第一行:幣種代碼 + USDT + 格 + 跌幅
Row(
children: [
Text(coin.code,
@@ -164,7 +164,7 @@ class CoinSelector extends StatelessWidget {
Text('\$${coin.formattedPrice}',
style: AppTextStyles.numberMedium(context)),
SizedBox(width: AppSpacing.sm),
// 跌幅徽章
// 跌幅徽章
Container(
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
@@ -185,7 +185,7 @@ class CoinSelector extends StatelessWidget {
],
),
SizedBox(height: 3),
// 第二行:币种名称
// 第二行:幣種名稱
Text(coin.name,
style: AppTextStyles.bodyMedium(context).copyWith(
color: context.colors.onSurfaceVariant,

View File

@@ -5,10 +5,10 @@ import '../../../../core/theme/app_theme_extension.dart';
import '../../../components/glass_panel.dart';
import '../../../components/neon_glow.dart';
/// 交易确认对话
/// 交易確認對話
///
/// 示交易情(交易、委托价格、交易金、交易量),
/// 用户确认后执行交易。
/// 示交易情(交易、委託價格、交易金、交易量),
/// 用戶確認後執行交易。
class ConfirmDialog extends StatelessWidget {
final bool isBuy;
final String coinCode;
@@ -42,19 +42,19 @@ class ConfirmDialog extends StatelessWidget {
children: [
Center(
child: Text(
'确认${isBuy ? '' : ''}',
'確認${isBuy ? '' : ''}',
style: AppTextStyles.headlineLarge(context),
),
),
SizedBox(height: AppSpacing.lg),
_dialogRow(context, '交易', '$coinCode/USDT'),
_dialogRow(context, '交易', '$coinCode/USDT'),
SizedBox(height: AppSpacing.sm),
_dialogRow(context, '托价', '$price USDT'),
_dialogRow(context, '託價', '$price USDT'),
SizedBox(height: AppSpacing.sm),
_dialogRow(context, '交易金', '$amount USDT',
_dialogRow(context, '交易金', '$amount USDT',
valueColor: actionColor),
SizedBox(height: AppSpacing.sm),
_dialogRow(context, '交易', '$quantity $coinCode'),
_dialogRow(context, '交易', '$quantity $coinCode'),
SizedBox(height: AppSpacing.lg),
Row(
children: [
@@ -70,7 +70,7 @@ class ConfirmDialog extends StatelessWidget {
SizedBox(width: AppSpacing.sm),
Expanded(
child: NeonButton(
text: '确认${isBuy ? '' : ''}',
text: '確認${isBuy ? '' : ''}',
type: isBuy ? NeonButtonType.tertiary : NeonButtonType.error,
onPressed: () => Navigator.of(context).pop(true),
height: 44,

View File

@@ -3,9 +3,9 @@ import '../../../../core/theme/app_spacing.dart';
import '../../../../core/theme/app_theme.dart';
import '../../../../core/theme/app_theme_extension.dart';
/// 位卡片
/// 位卡片
///
/// 当未选择币种时显示的位提示卡片。
/// 當未選擇幣種時顯示的位提示卡片。
class PlaceholderCard extends StatelessWidget {
final String message;
const PlaceholderCard({

View File

@@ -4,10 +4,10 @@ import '../../../../core/theme/app_theme.dart';
import '../../../../core/theme/app_theme_extension.dart';
import '../../../../data/models/coin.dart';
/// 格卡片
/// 格卡片
///
/// 显示当前币种价格和 24h 跌幅。
/// 局:大号价格(32px bold) + 跌幅徽章(角sm涨绿背景) + "24h 化" 副标题
/// 顯示當前幣種價格和 24h 跌幅。
/// 局:大號價格(32px bold) + 跌幅徽章(角sm漲綠背景) + "24h 化" 副標題
class PriceCard extends StatelessWidget {
final Coin coin;
const PriceCard({super.key, required this.coin});
@@ -34,7 +34,7 @@ class PriceCard extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 格行:大号价格 + 跌幅徽章
// 格行:大號價格 + 跌幅徽章
Row(
children: [
Text(
@@ -42,10 +42,10 @@ class PriceCard extends StatelessWidget {
style: AppTextStyles.numberLarge(context).copyWith(fontSize: 32),
),
const SizedBox(width: AppSpacing.sm),
// 跌幅徽章 - 角sm涨绿背景
// 跌幅徽章 - 角sm漲綠背景
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4), // 整 padding
horizontal: 8, vertical: 4), // 調整 padding
decoration: BoxDecoration(
color: changeBgColor,
borderRadius: BorderRadius.circular(AppRadius.sm),
@@ -61,9 +61,9 @@ class PriceCard extends StatelessWidget {
],
),
const SizedBox(height: AppSpacing.sm),
// 副标题
// 副標題
Text(
'24h ',
'24h ',
style: AppTextStyles.bodySmall(context),
),
],

View File

@@ -3,9 +3,9 @@ import '../../../../core/theme/app_color_scheme.dart';
import '../../../../core/theme/app_spacing.dart';
import '../../../../core/theme/app_theme.dart';
/// 交易按钮组
/// 交易按鈕組
///
/// CTA 入/出按。profit-green底 / sell-red底角lg高48入白字/卖出红字16px bold。
/// CTA 入/出按。profit-green底 / sell-red底角lg高48入白字/賣出紅字16px bold。
class TradeButton extends StatelessWidget {
final bool isBuy;
final String? coinCode;
@@ -27,7 +27,7 @@ class TradeButton extends StatelessWidget {
final colorScheme = Theme.of(context).colorScheme;
final fillColor =
isBuy ? AppColorScheme.buyButtonFill : AppColorScheme.sellButtonFill;
// 入按文字白色,出按文字为红
// 入按文字白色,出按文字為紅
final textColor = isBuy
? Colors.white
: (enabled ? AppColorScheme.sellButtonFill : colorScheme.onSurface.withOpacity(0.3));
@@ -52,7 +52,7 @@ class TradeButton extends StatelessWidget {
),
)
: Text(
'${isBuy ? '' : ''} ${coinCode ?? ""}',
'${isBuy ? '' : ''} ${coinCode ?? ""}',
style: AppTextStyles.headlineLarge(context).copyWith(
color: enabled
? textColor

View File

@@ -6,10 +6,10 @@ import '../../../../core/theme/app_theme_extension.dart';
import '../../../../data/models/coin.dart';
import 'amount_input.dart';
/// 交易表卡片
/// 交易表卡片
///
/// 包含入/出切、金额输入、可用余额、快捷比例按钮、计算数量行。
/// card背景 + 角lg + border + padding:20 + gap:16
/// 包含入/出切、金額輸入、可用餘額、快捷比例按鈕、計算數量行。
/// card背景 + 角lg + border + padding:20 + gap:16
class TradeFormCard extends StatelessWidget {
final int tradeType;
final Coin? selectedCoin;
@@ -43,7 +43,7 @@ class TradeFormCard extends StatelessWidget {
? context.appColors.up
: context.appColors.down;
// 设计稿中 card 背景色
// 設計稿中 card 背景色
final cardBgColor = context.appColors.surfaceCard;
return Container(
@@ -59,13 +59,13 @@ class TradeFormCard extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// ---- 入/出切 ----
// 设计稿ClipRRect + 角md两等宽按钮
// ---- 入/出切 ----
// 設計稿ClipRRect + 角md兩等寬按鈕
ClipRRect(
borderRadius: BorderRadius.circular(AppRadius.md),
child: Row(
children: [
// 入按
// 入按
Expanded(
child: GestureDetector(
onTap: () => onTradeTypeChanged(0),
@@ -84,7 +84,7 @@ class TradeFormCard extends StatelessWidget {
),
child: Center(
child: Text(
'',
'',
style: AppTextStyles.headlineMedium(context).copyWith(
color: isBuy
? Colors.white
@@ -95,7 +95,7 @@ class TradeFormCard extends StatelessWidget {
),
),
),
// 出按
// 出按
Expanded(
child: GestureDetector(
onTap: () => onTradeTypeChanged(1),
@@ -114,7 +114,7 @@ class TradeFormCard extends StatelessWidget {
),
child: Center(
child: Text(
'',
'',
style: AppTextStyles.headlineMedium(context).copyWith(
color: !isBuy
? Colors.white
@@ -130,11 +130,11 @@ class TradeFormCard extends StatelessWidget {
),
const SizedBox(height: AppSpacing.md + AppSpacing.sm),
// ---- 交易金 label 行 ----
// ---- 交易金 label 行 ----
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('交易金',
Text('交易金',
style: AppTextStyles.bodyMedium(context).copyWith(
color: context.colors.onSurfaceVariant,
)),
@@ -144,7 +144,7 @@ class TradeFormCard extends StatelessWidget {
),
const SizedBox(height: AppSpacing.sm),
// ---- 金额输入框 ----
// ---- 金額輸入框 ----
AmountInput(
amountController: amountController,
maxAmount: maxAmount,
@@ -154,7 +154,7 @@ class TradeFormCard extends StatelessWidget {
),
const SizedBox(height: AppSpacing.sm),
// ---- 可用余额 ----
// ---- 可用餘額 ----
Text(
isBuy
? '可用: $availableUsdt USDT'
@@ -165,8 +165,8 @@ class TradeFormCard extends StatelessWidget {
),
const SizedBox(height: AppSpacing.md),
// ---- 快捷比例按 25% 50% 75% 100% ----
// 设计稿gap:8角smbg-tertiary高32
// ---- 快捷比例按 25% 50% 75% 100% ----
// 設計稿gap:8角smbg-tertiary高32
Row(
children: [
_buildPctButton(context, '25%', 0.25),
@@ -180,11 +180,11 @@ class TradeFormCard extends StatelessWidget {
),
const SizedBox(height: AppSpacing.md + AppSpacing.sm),
// ---- 计算数量行 ----
// ---- 計算數量行 ----
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('交易',
Text('交易',
style: AppTextStyles.bodyMedium(context).copyWith(
color: context.colors.onSurfaceVariant,
)),
@@ -199,7 +199,7 @@ class TradeFormCard extends StatelessWidget {
);
}
/// 百分比按 - 设计稿:角smbg-tertiary高32
/// 百分比按 - 設計稿:角smbg-tertiary高32
Widget _buildPctButton(BuildContext context, String label, double pct) {
return Expanded(
child: GestureDetector(
@@ -207,7 +207,7 @@ class TradeFormCard extends StatelessWidget {
child: Container(
height: 32,
decoration: BoxDecoration(
color: context.colors.surfaceContainerHighest.withOpacity(0.5), // 更柔和的
color: context.colors.surfaceContainerHighest.withOpacity(0.5), // 更柔和的
borderRadius: BorderRadius.circular(AppRadius.sm),
),
child: Center(

View File

@@ -15,14 +15,14 @@ import 'components/trade_form_card.dart';
import 'components/trade_button.dart';
import 'components/confirm_dialog.dart';
/// 交易
/// 交易
///
/// 设计稿 Trade 面,布局结构
/// - 币种选择器卡片Coin Selector Card
/// - 格卡片Price Card号价格 + 跌幅徽章 + 副标题
/// - 入/出切Buy/Sell Toggle
/// - 交易表卡片Trade Form Card额输入 + 快捷比例 + 计算数
/// - CTA 入/出按Buy/Sell Button
/// 設計稿 Trade 面,佈局結構
/// - 幣種選擇器卡片Coin Selector Card
/// - 格卡片Price Card號價格 + 跌幅徽章 + 副標題
/// - 入/出切Buy/Sell Toggle
/// - 交易表卡片Trade Form Card額輸入 + 快捷比例 + 計算數
/// - CTA 入/出按Buy/Sell Button
class TradePage extends StatefulWidget {
final String? initialCoinCode;
@@ -34,7 +34,7 @@ class TradePage extends StatefulWidget {
class _TradePageState extends State<TradePage>
with AutomaticKeepAliveClientMixin {
int _tradeType = 0; // 0=入, 1=
int _tradeType = 0; // 0=入, 1=
Coin? _selectedCoin;
final _amountController = TextEditingController();
bool _isSubmitting = false;
@@ -71,14 +71,14 @@ class _TradePageState extends State<TradePage>
super.dispose();
}
/// 取交易账户中 USDT 可用余额
/// 取交易賬戶中 USDT 可用餘額
String get _availableUsdt {
final holdings = context.read<AssetProvider>().holdings;
final usdt = holdings.where((h) => h.coinCode == 'USDT').firstOrNull;
return usdt?.quantity ?? '0';
}
/// 取交易账户中当前币种的持仓数
/// 取交易賬戶中當前幣種的持倉數
String get _availableCoinQty {
if (_selectedCoin == null) return '0';
final holdings = context.read<AssetProvider>().holdings;
@@ -88,7 +88,7 @@ class _TradePageState extends State<TradePage>
return pos?.quantity ?? '0';
}
/// 算可入/出的最大 USDT 金
/// 算可入/出的最大 USDT 金
String get _maxAmount {
if (_selectedCoin == null) return '0';
final price = _selectedCoin!.price;
@@ -102,7 +102,7 @@ class _TradePageState extends State<TradePage>
}
}
/// 计算数
/// 計算數
String get _calculatedQuantity {
final amount = double.tryParse(_amountController.text) ?? 0;
final price = _selectedCoin?.price ?? 0;
@@ -121,11 +121,11 @@ class _TradePageState extends State<TradePage>
return SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.fromLTRB(
AppSpacing.md, AppSpacing.md, AppSpacing.md, AppSpacing.xl + AppSpacing.sm, // 添加顶部间
AppSpacing.md, AppSpacing.md, AppSpacing.md, AppSpacing.xl + AppSpacing.sm, // 添加頂部間
),
child: Column(
children: [
// 币种选择器卡片
// 幣種選擇器卡片
CoinSelector(
selectedCoin: _selectedCoin,
coins: market.allCoins
@@ -143,16 +143,16 @@ class _TradePageState extends State<TradePage>
),
const SizedBox(height: AppSpacing.md),
// 格卡片
// 格卡片
if (_selectedCoin != null)
PriceCard(coin: _selectedCoin!)
else
PlaceholderCard(
message: '请先选择交易币种',
message: '請先選擇交易幣種',
),
const SizedBox(height: AppSpacing.md),
// 交易表卡片(内含买入/出切 + 表
// 交易表卡片(內含買入/出切 + 表
TradeFormCard(
tradeType: _tradeType,
selectedCoin: _selectedCoin,
@@ -170,7 +170,7 @@ class _TradePageState extends State<TradePage>
),
const SizedBox(height: AppSpacing.md),
// CTA 入/出按
// CTA 入/出按
SizedBox(
width: double.infinity,
height: 48,
@@ -195,7 +195,7 @@ class _TradePageState extends State<TradePage>
if (_selectedCoin == null) return false;
final amount = double.tryParse(_amountController.text) ?? 0;
if (amount <= 0) return false;
// 买入时校验不超可用USDT
// 買入時校驗不超可用USDT
if (_tradeType == 0) {
final available = double.tryParse(_availableUsdt) ?? 0;
if (amount > available) return false;
@@ -243,16 +243,16 @@ class _TradePageState extends State<TradePage>
if (response.success) {
_amountController.clear();
// 刷新资产数据
// 刷新資產數據
context.read<AssetProvider>().refreshAll(force: true);
_showResultDialog(true, '${isBuy ? '' : ''}成功',
_showResultDialog(true, '${isBuy ? '' : ''}成功',
'$quantity $coinCode @ $price USDT');
} else {
_showResultDialog(false, '交易失', response.message ?? '请稍后重试');
_showResultDialog(false, '交易失', response.message ?? '請稍後重試');
}
} catch (e) {
if (mounted) {
_showResultDialog(false, '交易失', e.toString());
_showResultDialog(false, '交易失', e.toString());
}
} finally {
if (mounted) setState(() => _isSubmitting = false);
@@ -279,7 +279,7 @@ class _TradePageState extends State<TradePage>
description: Text(message),
actions: [
ShadButton(
child: const Text(''),
child: const Text(''),
onPressed: () => Navigator.of(ctx).pop(),
),
],