style(transfer): 树转让 3 页面从暗夜主题改为 App 标准浅色棕金主题

问题:树转让的 transfer_list_page、transfer_initiate_page、
transfer_detail_page 三个页面使用了深色暗夜主题(#1A1A2E 背景 +
#16213E 卡片),与 App 其余 40+ 功能页面的浅色棕金主题不一致。

修改内容(3 个文件,纯样式重写,零业务逻辑变更):

1. 页面背景:#1A1A2E → 渐变 #FFF7E6 → #EAE0C8(与 planting_quantity_page 一致)
2. 卡片背景:#16213E → #99FFFFFF 半透明白 + boxShadow(与认种页一致)
3. AppBar:深色背景白字 → 透明背景 + 金色返回键(#D4AF37) + 棕色标题(#5D4037)
4. 正文文字:Colors.white/white70 → #5D4037 棕色 / #745D43 次级棕色
5. 输入框:#16213E 填充 → #99FFFFFF 填充 + #EAE0C8 边框
6. 按钮:ElevatedButton → GestureDetector+Container(高度 56,与全局一致)
7. 分割线:Colors.white24 → #EAE0C8
8. Tab 栏:暗色系 → 半透明白卡片容器 + 金色指示器
9. Saga 时间线未完成节点:white 20% → #EAE0C8 暖色
10. 对话框:系统默认 → #FFF7E6 背景 + 棕色文字

样式参考基准:planting_quantity_page.dart(现有认种数量页)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-02-23 20:25:25 -08:00
parent a11e4d0261
commit e690a55c8e
3 changed files with 605 additions and 229 deletions

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../../core/di/injection_container.dart';
import '../../../../core/services/transfer_service.dart';
@ -98,16 +99,36 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
builder: (ctx) {
String text = '';
return AlertDialog(
title: const Text('取消转让'),
backgroundColor: const Color(0xFFFFF7E6),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
title: const Text(
'取消转让',
style: TextStyle(color: Color(0xFF5D4037), fontWeight: FontWeight.w700),
),
content: TextField(
onChanged: (v) => text = v,
decoration: const InputDecoration(hintText: '取消原因(可选)'),
style: const TextStyle(color: Color(0xFF5D4037)),
decoration: InputDecoration(
hintText: '取消原因(可选)',
hintStyle: const TextStyle(color: Color(0xFF745D43)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Color(0xFFEAE0C8)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Color(0xFFD4AF37)),
),
),
),
actions: [
TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('返回')),
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text('返回', style: TextStyle(color: Color(0xFF745D43))),
),
TextButton(
onPressed: () => Navigator.pop(ctx, text.isEmpty ? '用户主动取消' : text),
child: const Text('确认取消', style: TextStyle(color: Colors.red)),
child: const Text('确认取消', style: TextStyle(color: Color(0xFFE65100))),
),
],
);
@ -135,16 +156,78 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF1A1A2E),
appBar: AppBar(
backgroundColor: const Color(0xFF1A1A2E),
foregroundColor: Colors.white,
title: const Text(
'转让详情',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Colors.white),
body: Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFFFF7E6),
Color(0xFFEAE0C8),
],
),
),
child: SafeArea(
child: Column(
children: [
_buildHeader(),
Expanded(child: _buildBody()),
],
),
),
),
body: _buildBody(),
);
}
Widget _buildHeader() {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
GestureDetector(
onTap: () => context.pop(),
child: Container(
width: 32,
height: 32,
alignment: Alignment.center,
child: const Icon(
Icons.arrow_back_ios,
color: Color(0xFFD4AF37),
size: 20,
),
),
),
const SizedBox(width: 4),
GestureDetector(
onTap: () => context.pop(),
child: const Text(
'返回',
style: TextStyle(
fontSize: 16,
fontFamily: 'Inter',
height: 1.5,
color: Color(0xFFD4AF37),
),
),
),
const SizedBox(width: 42),
const Expanded(
child: Text(
'转让详情',
style: TextStyle(
fontSize: 18,
fontFamily: 'Inter',
fontWeight: FontWeight.w700,
height: 1.25,
letterSpacing: -0.27,
color: Color(0xFF5D4037),
),
),
),
],
),
);
}
@ -157,8 +240,21 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('加载失败', style: TextStyle(color: Colors.white.withValues(alpha: 0.7))),
TextButton(onPressed: _loadData, child: const Text('重试', style: TextStyle(color: Color(0xFFD4AF37)))),
const Icon(Icons.error_outline, color: Color(0xFFE65100), size: 32),
const SizedBox(height: 8),
const Text('加载失败', style: TextStyle(color: Color(0xFF5D4037), fontSize: 16)),
const SizedBox(height: 8),
GestureDetector(
onTap: _loadData,
child: const Text(
'点击重试',
style: TextStyle(
color: Color(0xFFD4AF37),
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
],
),
);
@ -191,9 +287,20 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFF16213E),
color: const Color(0x99FFFFFF),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white.withValues(alpha: 0.08)),
boxShadow: const [
BoxShadow(
color: Color(0x1A000000),
blurRadius: 6,
offset: Offset(0, 4),
),
BoxShadow(
color: Color(0x1A000000),
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -205,7 +312,7 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
Expanded(
child: Text(
order.transferOrderNo,
style: const TextStyle(fontSize: 14, color: Colors.white70, fontFamily: 'Inter'),
style: const TextStyle(fontSize: 14, color: Color(0xFF745D43), fontFamily: 'Inter'),
overflow: TextOverflow.ellipsis,
),
),
@ -236,16 +343,14 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: 0.5))),
Text(value, style: const TextStyle(fontSize: 13, color: Colors.white, fontFamily: 'Inter')),
Text(label, style: const TextStyle(fontSize: 13, color: Color(0xFF745D43))),
Text(value, style: const TextStyle(fontSize: 13, color: Color(0xFF5D4037), fontFamily: 'Inter')),
],
),
);
}
Widget _buildSagaTimeline(TransferOrderDetail order) {
final currentStatusStr = order.status.name.toUpperCase();
// Map enum name to API status string
final statusApiMap = {
'pending': 'PENDING',
'sellerConfirmed': 'SELLER_CONFIRMED',
@ -257,7 +362,7 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
'paymentSettled': 'PAYMENT_SETTLED',
'completed': 'COMPLETED',
};
final apiStatus = statusApiMap[order.status.name] ?? currentStatusStr;
final apiStatus = statusApiMap[order.status.name] ?? order.status.name.toUpperCase();
final currentIdx = _sagaSteps.indexWhere((s) => s['status'] == apiStatus);
final isFailed = order.status == TransferOrderStatus.failed ||
order.status == TransferOrderStatus.rollingBack ||
@ -266,16 +371,27 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFF16213E),
color: const Color(0x99FFFFFF),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white.withValues(alpha: 0.08)),
boxShadow: const [
BoxShadow(
color: Color(0x1A000000),
blurRadius: 6,
offset: Offset(0, 4),
),
BoxShadow(
color: Color(0x1A000000),
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Saga 进度',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF5D4037)),
),
const SizedBox(height: 16),
...List.generate(_sagaSteps.length, (idx) {
@ -284,8 +400,8 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
final isCurrent = idx == currentIdx && !order.isTerminal && !isFailed;
final isFailedStep = isFailed && idx == currentIdx;
Color dotColor = Colors.white.withValues(alpha: 0.2);
Color dotBorder = Colors.white.withValues(alpha: 0.2);
Color dotColor = const Color(0xFFEAE0C8);
Color dotBorder = const Color(0xFFEAE0C8);
if (isCompleted) {
dotColor = const Color(0xFF52C41A);
dotBorder = const Color(0xFF52C41A);
@ -330,7 +446,7 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
height: 20,
color: isCompleted
? const Color(0xFF52C41A).withValues(alpha: 0.4)
: Colors.white.withValues(alpha: 0.1),
: const Color(0xFFEAE0C8),
),
],
),
@ -345,14 +461,14 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
fontSize: 14,
fontWeight: (isCurrent || isCompleted) ? FontWeight.w600 : FontWeight.w400,
color: (isCurrent || isCompleted)
? Colors.white
: Colors.white.withValues(alpha: 0.4),
? const Color(0xFF5D4037)
: const Color(0xFF745D43),
),
),
if (logTime != null)
Text(
_formatDateTime(logTime),
style: TextStyle(fontSize: 11, color: Colors.white.withValues(alpha: 0.3)),
style: const TextStyle(fontSize: 11, color: Color(0xFF745D43)),
),
],
),
@ -370,16 +486,27 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFF16213E),
color: const Color(0x99FFFFFF),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white.withValues(alpha: 0.08)),
boxShadow: const [
BoxShadow(
color: Color(0x1A000000),
blurRadius: 6,
offset: Offset(0, 4),
),
BoxShadow(
color: Color(0x1A000000),
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'状态变更日志',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF5D4037)),
),
const SizedBox(height: 12),
...order.statusLogs.map((log) => Padding(
@ -390,13 +517,13 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
flex: 2,
child: Text(
'${log.fromStatus}${log.toStatus}',
style: const TextStyle(fontSize: 12, color: Colors.white70, fontFamily: 'Inter'),
style: const TextStyle(fontSize: 12, color: Color(0xFF745D43), fontFamily: 'Inter'),
),
),
Expanded(
child: Text(
_formatDateTime(log.createdAt),
style: TextStyle(fontSize: 11, color: Colors.white.withValues(alpha: 0.4)),
style: const TextStyle(fontSize: 11, color: Color(0xFF745D43)),
textAlign: TextAlign.right,
),
),
@ -416,30 +543,64 @@ class _TransferDetailPageState extends ConsumerState<TransferDetailPage> {
//
if (order.isPendingSellerConfirm)
Expanded(
child: ElevatedButton(
onPressed: _isActionLoading ? null : _handleSellerConfirm,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD4AF37),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: GestureDetector(
onTap: _isActionLoading ? null : _handleSellerConfirm,
child: Container(
height: 56,
decoration: BoxDecoration(
color: _isActionLoading
? const Color(0xFFD4AF37).withValues(alpha: 0.5)
: const Color(0xFFD4AF37),
borderRadius: BorderRadius.circular(12),
boxShadow: !_isActionLoading
? const [
BoxShadow(
color: Color(0x1A000000),
blurRadius: 15,
offset: Offset(0, 10),
),
]
: null,
),
child: Center(
child: Text(
_isActionLoading ? '处理中...' : '确认转让',
style: const TextStyle(
fontSize: 16,
fontFamily: 'Inter',
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
),
),
child: Text(_isActionLoading ? '处理中...' : '确认转让'),
),
),
if (order.isPendingSellerConfirm) const SizedBox(width: 12),
//
if (order.isCancellable)
Expanded(
child: OutlinedButton(
onPressed: _isActionLoading ? null : _handleCancel,
style: OutlinedButton.styleFrom(
foregroundColor: Colors.red,
side: const BorderSide(color: Colors.red),
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: GestureDetector(
onTap: _isActionLoading ? null : _handleCancel,
child: Container(
height: 56,
decoration: BoxDecoration(
color: const Color(0x99FFFFFF),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFFE65100)),
),
child: Center(
child: const Text(
'取消转让',
style: TextStyle(
fontSize: 16,
fontFamily: 'Inter',
fontWeight: FontWeight.w500,
color: Color(0xFFE65100),
),
),
),
),
child: const Text('取消转让'),
),
),
],

View File

@ -69,7 +69,12 @@ class _TransferInitiatePageState extends ConsumerState<TransferInitiatePage> {
final confirmed = await showDialog<bool>(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('确认发起转让'),
backgroundColor: const Color(0xFFFFF7E6),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
title: const Text(
'确认发起转让',
style: TextStyle(color: Color(0xFF5D4037), fontWeight: FontWeight.w700),
),
content: Text(
'买方账号: $buyer\n'
'转让棵数: $_treeCount\n'
@ -78,12 +83,20 @@ class _TransferInitiatePageState extends ConsumerState<TransferInitiatePage> {
'手续费: ${_feeAmount.toStringAsFixed(2)} USDT (${(_feeRate * 100).toStringAsFixed(0)}%)\n'
'您将收到: ${_sellerReceive.toStringAsFixed(2)} USDT\n\n'
'转让发起后需要卖方确认,确认后 Saga 流程将自动执行。',
style: const TextStyle(color: Color(0xFF5D4037), fontSize: 14, height: 1.6),
),
actions: [
TextButton(onPressed: () => Navigator.pop(ctx, false), child: const Text('取消')),
TextButton(
onPressed: () => Navigator.pop(ctx, false),
child: const Text('取消', style: TextStyle(color: Color(0xFF745D43))),
),
ElevatedButton(
onPressed: () => Navigator.pop(ctx, true),
style: ElevatedButton.styleFrom(backgroundColor: const Color(0xFFD4AF37)),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD4AF37),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: const Text('确认发起'),
),
],
@ -128,140 +141,242 @@ class _TransferInitiatePageState extends ConsumerState<TransferInitiatePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF1A1A2E),
appBar: AppBar(
backgroundColor: const Color(0xFF1A1A2E),
foregroundColor: Colors.white,
title: const Text(
'发起转让',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Colors.white),
body: Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFFFF7E6),
Color(0xFFEAE0C8),
],
),
),
child: SafeArea(
child: Column(
children: [
_buildHeader(),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFFD4AF37).withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFFD4AF37).withValues(alpha: 0.3)),
),
child: const Row(
children: [
Icon(Icons.info_outline, color: Color(0xFFD4AF37), size: 20),
SizedBox(width: 8),
Expanded(
child: Text(
'转让已认种的果树所有权。发起后需卖方确认,系统将自动完成资金冻结、所有权变更、算力调整等流程。',
style: TextStyle(fontSize: 13, color: Color(0xFF8B5A2B)),
),
),
],
),
),
const SizedBox(height: 24),
//
_buildLabel('买方账号'),
const SizedBox(height: 8),
_buildTextField(
controller: _buyerController,
hintText: '输入买方账号(如 D25121400002',
keyboardType: TextInputType.text,
),
const SizedBox(height: 20),
//
_buildLabel('转让棵数'),
const SizedBox(height: 8),
_buildTextField(
controller: _treeCountController,
hintText: '输入棵数',
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onChanged: (_) => setState(() {}),
),
const SizedBox(height: 20),
//
_buildLabel('每棵售价 (USDT)'),
const SizedBox(height: 8),
_buildTextField(
controller: _priceController,
hintText: '输入每棵售价',
keyboardType: const TextInputType.numberWithOptions(decimal: true),
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[\d.]'))],
onChanged: (_) => setState(() {}),
),
const SizedBox(height: 24),
//
if (_pricePerTree > 0) ...[
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0x99FFFFFF),
borderRadius: BorderRadius.circular(12),
boxShadow: const [
BoxShadow(
color: Color(0x1A000000),
blurRadius: 6,
offset: Offset(0, 4),
),
],
),
child: Column(
children: [
_feeRow('总价', '${_totalPrice.toStringAsFixed(0)} USDT'),
_feeRow('手续费 (${(_feeRate * 100).toStringAsFixed(0)}%)', '${_feeAmount.toStringAsFixed(2)} USDT'),
const Divider(color: Color(0xFFEAE0C8)),
_feeRow('您将收到', '${_sellerReceive.toStringAsFixed(2)} USDT',
valueColor: const Color(0xFFD4AF37)),
],
),
),
const SizedBox(height: 24),
],
//
if (_errorMessage != null) ...[
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0xFFFFF3E0),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: const Color(0xFFE65100)),
),
child: Row(
children: [
const Icon(Icons.error_outline, color: Color(0xFFE65100), size: 16),
const SizedBox(width: 8),
Expanded(
child: Text(_errorMessage!, style: const TextStyle(color: Color(0xFFE65100), fontSize: 13)),
),
],
),
),
const SizedBox(height: 16),
],
//
GestureDetector(
onTap: _isSubmitting ? null : _handleSubmit,
child: Container(
width: double.infinity,
height: 56,
decoration: BoxDecoration(
color: _isSubmitting
? const Color(0xFFD4AF37).withValues(alpha: 0.5)
: const Color(0xFFD4AF37),
borderRadius: BorderRadius.circular(12),
boxShadow: !_isSubmitting
? const [
BoxShadow(
color: Color(0x1A000000),
blurRadius: 15,
offset: Offset(0, 10),
),
BoxShadow(
color: Color(0x1A000000),
blurRadius: 6,
offset: Offset(0, 4),
),
]
: null,
),
child: Center(
child: _isSubmitting
? const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: const Text(
'发起转让',
style: TextStyle(
fontSize: 18,
fontFamily: 'Inter',
fontWeight: FontWeight.w500,
height: 1.56,
color: Colors.white,
),
),
),
),
),
],
),
),
),
],
),
),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFFD4AF37).withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFFD4AF37).withValues(alpha: 0.3)),
),
child: const Row(
children: [
Icon(Icons.info_outline, color: Color(0xFFD4AF37), size: 20),
SizedBox(width: 8),
Expanded(
child: Text(
'转让已认种的果树所有权。发起后需卖方确认,系统将自动完成资金冻结、所有权变更、算力调整等流程。',
style: TextStyle(fontSize: 13, color: Color(0xFFD4AF37)),
),
),
],
);
}
Widget _buildHeader() {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
GestureDetector(
onTap: () => context.pop(),
child: Container(
width: 32,
height: 32,
alignment: Alignment.center,
child: const Icon(
Icons.arrow_back_ios,
color: Color(0xFFD4AF37),
size: 20,
),
),
const SizedBox(height: 24),
//
_buildLabel('买方账号'),
const SizedBox(height: 8),
_buildTextField(
controller: _buyerController,
hintText: '输入买方账号(如 D25121400002',
keyboardType: TextInputType.text,
),
const SizedBox(height: 20),
//
_buildLabel('转让棵数'),
const SizedBox(height: 8),
_buildTextField(
controller: _treeCountController,
hintText: '输入棵数',
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onChanged: (_) => setState(() {}),
),
const SizedBox(height: 20),
//
_buildLabel('每棵售价 (USDT)'),
const SizedBox(height: 8),
_buildTextField(
controller: _priceController,
hintText: '输入每棵售价',
keyboardType: const TextInputType.numberWithOptions(decimal: true),
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[\d.]'))],
onChanged: (_) => setState(() {}),
),
const SizedBox(height: 24),
//
if (_pricePerTree > 0) ...[
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFF16213E),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white.withValues(alpha: 0.08)),
),
child: Column(
children: [
_feeRow('总价', '${_totalPrice.toStringAsFixed(0)} USDT'),
_feeRow('手续费 (${(_feeRate * 100).toStringAsFixed(0)}%)', '${_feeAmount.toStringAsFixed(2)} USDT'),
const Divider(color: Colors.white24),
_feeRow('您将收到', '${_sellerReceive.toStringAsFixed(2)} USDT',
valueColor: const Color(0xFFD4AF37)),
],
),
),
const SizedBox(height: 24),
],
//
if (_errorMessage != null) ...[
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.red.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
const Icon(Icons.error_outline, color: Colors.red, size: 16),
const SizedBox(width: 8),
Expanded(
child: Text(_errorMessage!, style: const TextStyle(color: Colors.red, fontSize: 13)),
),
],
),
),
const SizedBox(height: 16),
],
//
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _isSubmitting ? null : _handleSubmit,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFD4AF37),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
disabledBackgroundColor: const Color(0xFFD4AF37).withValues(alpha: 0.4),
),
child: Text(
_isSubmitting ? '提交中...' : '发起转让',
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
),
),
const SizedBox(width: 4),
GestureDetector(
onTap: () => context.pop(),
child: const Text(
'返回',
style: TextStyle(
fontSize: 16,
fontFamily: 'Inter',
height: 1.5,
color: Color(0xFFD4AF37),
),
),
],
),
),
const SizedBox(width: 42),
const Expanded(
child: Text(
'发起转让',
style: TextStyle(
fontSize: 18,
fontFamily: 'Inter',
fontWeight: FontWeight.w700,
height: 1.25,
letterSpacing: -0.27,
color: Color(0xFF5D4037),
),
),
),
],
),
);
}
@ -270,9 +385,11 @@ class _TransferInitiatePageState extends ConsumerState<TransferInitiatePage> {
return Text(
text,
style: const TextStyle(
fontSize: 14,
fontSize: 16,
fontFamily: 'Inter',
fontWeight: FontWeight.w500,
color: Colors.white,
height: 1.5,
color: Color(0xFF5D4037),
),
);
}
@ -289,23 +406,23 @@ class _TransferInitiatePageState extends ConsumerState<TransferInitiatePage> {
keyboardType: keyboardType,
inputFormatters: inputFormatters,
onChanged: onChanged,
style: const TextStyle(color: Colors.white, fontSize: 15, fontFamily: 'Inter'),
style: const TextStyle(color: Color(0xFF5D4037), fontSize: 15, fontFamily: 'Inter'),
decoration: InputDecoration(
hintText: hintText,
hintStyle: TextStyle(color: Colors.white.withValues(alpha: 0.3)),
hintStyle: const TextStyle(color: Color(0xFF745D43)),
filled: true,
fillColor: const Color(0xFF16213E),
fillColor: const Color(0x99FFFFFF),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.1)),
borderSide: const BorderSide(color: Color(0xFFEAE0C8)),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.1)),
borderSide: const BorderSide(color: Color(0xFFEAE0C8)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xFFD4AF37)),
borderSide: const BorderSide(color: Color(0xFFD4AF37), width: 2),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
),
@ -318,13 +435,13 @@ class _TransferInitiatePageState extends ConsumerState<TransferInitiatePage> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: 0.5))),
Text(label, style: const TextStyle(fontSize: 13, color: Color(0xFF745D43))),
Text(
value,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: valueColor ?? Colors.white,
color: valueColor ?? const Color(0xFF5D4037),
fontFamily: 'Inter',
),
),

View File

@ -84,31 +84,112 @@ class _TransferListPageState extends ConsumerState<TransferListPage>
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF1A1A2E),
appBar: AppBar(
backgroundColor: const Color(0xFF1A1A2E),
foregroundColor: Colors.white,
title: const Text(
'转让记录',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Colors.white,
body: Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFFFF7E6),
Color(0xFFEAE0C8),
],
),
),
bottom: TabBar(
controller: _tabController,
indicatorColor: const Color(0xFFD4AF37),
labelColor: const Color(0xFFD4AF37),
unselectedLabelColor: Colors.white54,
tabs: const [
Tab(text: '全部'),
Tab(text: '转出'),
Tab(text: '转入'),
],
child: SafeArea(
child: Column(
children: [
_buildHeader(),
_buildTabBar(),
Expanded(child: _buildBody()),
],
),
),
),
body: _buildBody(),
);
}
Widget _buildHeader() {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
GestureDetector(
onTap: () => context.pop(),
child: Container(
width: 32,
height: 32,
alignment: Alignment.center,
child: const Icon(
Icons.arrow_back_ios,
color: Color(0xFFD4AF37),
size: 20,
),
),
),
const SizedBox(width: 4),
GestureDetector(
onTap: () => context.pop(),
child: const Text(
'返回',
style: TextStyle(
fontSize: 16,
fontFamily: 'Inter',
height: 1.5,
color: Color(0xFFD4AF37),
),
),
),
const SizedBox(width: 42),
const Expanded(
child: Text(
'转让记录',
style: TextStyle(
fontSize: 18,
fontFamily: 'Inter',
fontWeight: FontWeight.w700,
height: 1.25,
letterSpacing: -0.27,
color: Color(0xFF5D4037),
),
),
),
],
),
);
}
Widget _buildTabBar() {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: const Color(0x99FFFFFF),
borderRadius: BorderRadius.circular(12),
),
child: TabBar(
controller: _tabController,
indicatorColor: const Color(0xFFD4AF37),
indicatorSize: TabBarIndicatorSize.label,
labelColor: const Color(0xFFD4AF37),
unselectedLabelColor: const Color(0xFF745D43),
labelStyle: const TextStyle(
fontSize: 14,
fontFamily: 'Inter',
fontWeight: FontWeight.w600,
),
unselectedLabelStyle: const TextStyle(
fontSize: 14,
fontFamily: 'Inter',
fontWeight: FontWeight.w400,
),
dividerColor: Colors.transparent,
tabs: const [
Tab(text: '全部'),
Tab(text: '转出'),
Tab(text: '转入'),
],
),
);
}
@ -124,14 +205,23 @@ class _TransferListPageState extends ConsumerState<TransferListPage>
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, color: Color(0xFFE65100), size: 32),
const SizedBox(height: 8),
Text(
'加载失败',
style: TextStyle(color: Colors.white.withValues(alpha: 0.7), fontSize: 16),
style: const TextStyle(color: Color(0xFF5D4037), fontSize: 16),
),
const SizedBox(height: 8),
TextButton(
onPressed: _loadData,
child: const Text('重试', style: TextStyle(color: Color(0xFFD4AF37))),
GestureDetector(
onTap: _loadData,
child: const Text(
'点击重试',
style: TextStyle(
color: Color(0xFFD4AF37),
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
],
),
@ -142,7 +232,7 @@ class _TransferListPageState extends ConsumerState<TransferListPage>
return Center(
child: Text(
'暂无转让记录',
style: TextStyle(color: Colors.white.withValues(alpha: 0.5), fontSize: 16),
style: const TextStyle(color: Color(0xFF745D43), fontSize: 16),
),
);
}
@ -169,12 +259,20 @@ class _TransferListPageState extends ConsumerState<TransferListPage>
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFF16213E),
color: const Color(0x99FFFFFF),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.white.withValues(alpha: 0.08),
width: 1,
),
boxShadow: const [
BoxShadow(
color: Color(0x1A000000),
blurRadius: 6,
offset: Offset(0, 4),
),
BoxShadow(
color: Color(0x1A000000),
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -189,7 +287,7 @@ class _TransferListPageState extends ConsumerState<TransferListPage>
style: const TextStyle(
fontSize: 13,
fontFamily: 'Inter',
color: Colors.white70,
color: Color(0xFF745D43),
),
overflow: TextOverflow.ellipsis,
),
@ -217,7 +315,7 @@ class _TransferListPageState extends ConsumerState<TransferListPage>
children: [
Text(
order.sellerAccountSequence,
style: const TextStyle(fontSize: 14, color: Colors.white, fontFamily: 'Inter'),
style: const TextStyle(fontSize: 14, color: Color(0xFF5D4037), fontFamily: 'Inter'),
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
@ -225,7 +323,7 @@ class _TransferListPageState extends ConsumerState<TransferListPage>
),
Text(
order.buyerAccountSequence,
style: const TextStyle(fontSize: 14, color: Colors.white, fontFamily: 'Inter'),
style: const TextStyle(fontSize: 14, color: Color(0xFF5D4037), fontFamily: 'Inter'),
),
],
),
@ -236,7 +334,7 @@ class _TransferListPageState extends ConsumerState<TransferListPage>
children: [
Text(
'${order.treeCount}',
style: const TextStyle(fontSize: 14, color: Colors.white70),
style: const TextStyle(fontSize: 14, color: Color(0xFF745D43)),
),
Text(
'${order.totalPrice.toStringAsFixed(0)} USDT',
@ -253,7 +351,7 @@ class _TransferListPageState extends ConsumerState<TransferListPage>
//
Text(
_formatDateTime(order.createdAt),
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: 0.4)),
style: const TextStyle(fontSize: 12, color: Color(0xFF745D43)),
),
],
),