feat(frontend): 多项功能改进
- 将所有 USDT 文本替换为 积分 - 监控页面:将"挖矿待开启"改为"开启监控",开启时显示关闭按钮 - 我的伞下:树图默认居中显示 - 树图节点:长按查看详情(序列号、认种数、直推人数) - 分享页面:显示推荐码并支持复制 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
8d68b292c8
commit
6dd7e64a95
|
|
@ -214,7 +214,7 @@ export default function AuthorizationPage() {
|
|||
/>
|
||||
</div>
|
||||
<div className={styles.authorization__formGroup}>
|
||||
<label className={styles.authorization__formLabel}>考核阶段单棵权益(USDT)</label>
|
||||
<label className={styles.authorization__formLabel}>考核阶段单棵权益(积分)</label>
|
||||
<input
|
||||
className={styles.authorization__formInput}
|
||||
type="text"
|
||||
|
|
@ -227,7 +227,7 @@ export default function AuthorizationPage() {
|
|||
</div>
|
||||
<div className={styles.authorization__formRow}>
|
||||
<div className={styles.authorization__formGroup}>
|
||||
<label className={styles.authorization__formLabel}>考核达标后每新增 1 棵省公司获得(USDT)</label>
|
||||
<label className={styles.authorization__formLabel}>考核达标后每新增 1 棵省公司获得(积分)</label>
|
||||
<input
|
||||
className={styles.authorization__formInput}
|
||||
type="text"
|
||||
|
|
@ -296,7 +296,7 @@ export default function AuthorizationPage() {
|
|||
/>
|
||||
</div>
|
||||
<div className={styles.authorization__formGroup}>
|
||||
<label className={styles.authorization__formLabel}>考核阶段单棵权益(USDT)</label>
|
||||
<label className={styles.authorization__formLabel}>考核阶段单棵权益(积分)</label>
|
||||
<input
|
||||
className={styles.authorization__formInput}
|
||||
type="text"
|
||||
|
|
@ -309,7 +309,7 @@ export default function AuthorizationPage() {
|
|||
</div>
|
||||
<div className={styles.authorization__formRow}>
|
||||
<div className={styles.authorization__formGroup}>
|
||||
<label className={styles.authorization__formLabel}>考核达标后每新增 1 棵市公司获得(USDT)</label>
|
||||
<label className={styles.authorization__formLabel}>考核达标后每新增 1 棵市公司获得(积分)</label>
|
||||
<input
|
||||
className={styles.authorization__formInput}
|
||||
type="text"
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ const mockTargets: AssessmentTarget[] = [
|
|||
|
||||
export default function SettingsPage() {
|
||||
// 结算参数设置
|
||||
const [settlementCurrencies, setSettlementCurrencies] = useState<string[]>(['BNB', 'USDT']);
|
||||
const [settlementCurrencies, setSettlementCurrencies] = useState<string[]>(['BNB', '积分']);
|
||||
const [defaultCurrency, setDefaultCurrency] = useState('');
|
||||
|
||||
// 龙虎榜设置
|
||||
|
|
@ -144,7 +144,7 @@ export default function SettingsPage() {
|
|||
<div className={styles.settings__fieldGroup}>
|
||||
<label className={styles.settings__label}>可用结算币种</label>
|
||||
<div className={styles.settings__checkboxGroup}>
|
||||
{['BNB', 'OG', 'USDT', 'DST'].map(currency => (
|
||||
{['BNB', 'OG', '积分', 'DST'].map(currency => (
|
||||
<label key={currency} className={styles.settings__checkboxItem}>
|
||||
<input
|
||||
type="checkbox"
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export const ASSESSMENT_CYCLE_LABELS: Record<string, string> = {
|
|||
};
|
||||
|
||||
// 结算货币
|
||||
export const CURRENCIES = ['BNB', 'OG', 'USDT', 'DST'] as const;
|
||||
export const CURRENCIES = ['BNB', 'OG', '积分', 'DST'] as const;
|
||||
|
||||
// 龙虎榜类型
|
||||
export const LEADERBOARD_TYPES = {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export function formatCurrency(amount: number, currency = 'CNY'): string {
|
|||
const symbols: Record<string, string> = {
|
||||
CNY: '¥',
|
||||
USD: '$',
|
||||
USDT: 'USDT ',
|
||||
USDT: '积分 ',
|
||||
BTC: 'BTC ',
|
||||
};
|
||||
const symbol = symbols[currency] || '';
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ class _DepositUsdtPageState extends ConsumerState<DepositUsdtPage> {
|
|||
// 标题
|
||||
const Expanded(
|
||||
child: Text(
|
||||
'充值 USDT',
|
||||
'充值 积分',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -263,7 +263,7 @@ class _DepositUsdtPageState extends ConsumerState<DepositUsdtPage> {
|
|||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Text(
|
||||
'可用余额: $_balance USDT',
|
||||
'可用余额: $_balance 积分',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -577,7 +577,7 @@ class _DepositUsdtPageState extends ConsumerState<DepositUsdtPage> {
|
|||
return Container(
|
||||
padding: const EdgeInsets.fromLTRB(20, 16, 20, 48),
|
||||
child: Text(
|
||||
'仅支持 USDT,错充将无法追回',
|
||||
'仅支持 积分,错充将无法追回',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Inter',
|
||||
|
|
|
|||
|
|
@ -4,15 +4,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import '../../../../core/di/injection_container.dart';
|
||||
|
||||
/// 挖矿状态枚举
|
||||
enum MiningStatus {
|
||||
/// 监控状态枚举
|
||||
enum MonitorStatus {
|
||||
pending, // 待开启
|
||||
mining, // 挖矿中
|
||||
paused, // 已暂停
|
||||
active, // 监控中
|
||||
}
|
||||
|
||||
/// 监控页面 - 显示挖矿状态和控制
|
||||
/// 展示用户序列号、社区信息和挖矿开关
|
||||
/// 监控页面 - 显示监控状态和控制
|
||||
/// 展示用户序列号、社区信息,未来将接入实时监控视频流
|
||||
class MiningPage extends ConsumerStatefulWidget {
|
||||
const MiningPage({super.key});
|
||||
|
||||
|
|
@ -21,8 +20,8 @@ class MiningPage extends ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class _MiningPageState extends ConsumerState<MiningPage> {
|
||||
// 当前挖矿状态
|
||||
MiningStatus _miningStatus = MiningStatus.pending;
|
||||
// 当前监控状态
|
||||
MonitorStatus _monitorStatus = MonitorStatus.pending;
|
||||
|
||||
// 用户数据(从存储加载)
|
||||
String _serialNumber = '--';
|
||||
|
|
@ -131,9 +130,9 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
|||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('监控说明'),
|
||||
content: const Text('监控是您查看挖矿状态的工具。\n\n'
|
||||
'开启挖矿后,您将开始获得收益。\n\n'
|
||||
'收益与您的算力和团队规模相关。'),
|
||||
content: const Text('监控是您查看榴莲种植实况的工具。\n\n'
|
||||
'开启监控后,您可以实时查看种植基地的视频流。\n\n'
|
||||
'目前功能正在开发中,敬请期待。'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
|
|
@ -144,28 +143,29 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
|||
);
|
||||
}
|
||||
|
||||
/// 切换挖矿状态
|
||||
void _toggleMining() {
|
||||
/// 开启监控
|
||||
void _startMonitor() {
|
||||
setState(() {
|
||||
if (_miningStatus == MiningStatus.pending) {
|
||||
_miningStatus = MiningStatus.mining;
|
||||
} else if (_miningStatus == MiningStatus.mining) {
|
||||
_miningStatus = MiningStatus.paused;
|
||||
} else {
|
||||
_miningStatus = MiningStatus.mining;
|
||||
}
|
||||
_monitorStatus = MonitorStatus.active;
|
||||
});
|
||||
// TODO: 未来在这里连接实时监控视频流
|
||||
}
|
||||
|
||||
/// 关闭监控
|
||||
void _stopMonitor() {
|
||||
setState(() {
|
||||
_monitorStatus = MonitorStatus.pending;
|
||||
});
|
||||
// TODO: 未来在这里断开视频流连接
|
||||
}
|
||||
|
||||
/// 获取状态文本
|
||||
String _getStatusText() {
|
||||
switch (_miningStatus) {
|
||||
case MiningStatus.pending:
|
||||
return '挖矿待开启';
|
||||
case MiningStatus.mining:
|
||||
return '挖矿中';
|
||||
case MiningStatus.paused:
|
||||
return '挖矿已暂停';
|
||||
switch (_monitorStatus) {
|
||||
case MonitorStatus.pending:
|
||||
return '开启监控';
|
||||
case MonitorStatus.active:
|
||||
return '监控中';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,24 +212,7 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
|||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
// 占位
|
||||
const SizedBox(width: 48),
|
||||
// 标题
|
||||
const Expanded(
|
||||
child: Text(
|
||||
'监控',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w700,
|
||||
height: 1.25,
|
||||
letterSpacing: -0.27,
|
||||
color: Color(0xFF5D4037),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
// 帮助按钮
|
||||
// 帮助按钮(左侧)
|
||||
GestureDetector(
|
||||
onTap: _showHelpInfo,
|
||||
child: Container(
|
||||
|
|
@ -259,6 +242,38 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
|||
),
|
||||
),
|
||||
),
|
||||
// 标题
|
||||
const Expanded(
|
||||
child: Text(
|
||||
'监控',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w700,
|
||||
height: 1.25,
|
||||
letterSpacing: -0.27,
|
||||
color: Color(0xFF5D4037),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
// 关闭按钮(仅在监控开启时显示)
|
||||
if (_monitorStatus == MonitorStatus.active)
|
||||
GestureDetector(
|
||||
onTap: _stopMonitor,
|
||||
child: Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
alignment: Alignment.center,
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
size: 24,
|
||||
color: Color(0xFF8B5A2B),
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
const SizedBox(width: 48), // 占位保持布局平衡
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
@ -329,7 +344,7 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
|||
);
|
||||
}
|
||||
|
||||
/// 构建挖矿状态区域
|
||||
/// 构建监控状态区域
|
||||
Widget _buildMiningStatusArea() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
|
|
@ -339,104 +354,119 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
|||
color: const Color(0x66FFFFFF),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// 挖矿开关按钮
|
||||
GestureDetector(
|
||||
onTap: _toggleMining,
|
||||
child: Container(
|
||||
width: 100,
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: _miningStatus == MiningStatus.mining
|
||||
? const Color(0xFFD4AF37)
|
||||
: Colors.transparent,
|
||||
border: Border.all(
|
||||
color: _miningStatus == MiningStatus.mining
|
||||
? const Color(0xFFD4AF37)
|
||||
: const Color(0xFFD4AF37).withOpacity(0.5),
|
||||
width: 3,
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.power_settings_new,
|
||||
size: 48,
|
||||
color: _miningStatus == MiningStatus.mining
|
||||
? Colors.white
|
||||
: const Color(0xFFD4AF37).withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// 状态文本
|
||||
Text(
|
||||
_getStatusText(),
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.56,
|
||||
color: Color(0xFF8B5A2B),
|
||||
),
|
||||
),
|
||||
// 挖矿中显示额外信息
|
||||
if (_miningStatus == MiningStatus.mining) ...[
|
||||
const SizedBox(height: 24),
|
||||
_buildMiningStats(),
|
||||
],
|
||||
],
|
||||
),
|
||||
child: _monitorStatus == MonitorStatus.active
|
||||
? _buildMonitorActiveView()
|
||||
: _buildMonitorPendingView(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 构建挖矿统计信息
|
||||
Widget _buildMiningStats() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0x33D4AF37),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildStatRow('个人算力', '100 H/s'),
|
||||
const SizedBox(height: 8),
|
||||
_buildStatRow('团队算力', '1,000 H/s'),
|
||||
const SizedBox(height: 8),
|
||||
_buildStatRow('今日收益', '0.00 DST'),
|
||||
const SizedBox(height: 8),
|
||||
_buildStatRow('累计收益', '0.00 DST'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 构建统计行
|
||||
Widget _buildStatRow(String label, String value) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
/// 构建监控待开启视图
|
||||
Widget _buildMonitorPendingView() {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// 开启监控按钮
|
||||
GestureDetector(
|
||||
onTap: _startMonitor,
|
||||
child: Container(
|
||||
width: 100,
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.transparent,
|
||||
border: Border.all(
|
||||
color: const Color(0xFFD4AF37).withOpacity(0.5),
|
||||
width: 3,
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.videocam_outlined,
|
||||
size: 48,
|
||||
color: const Color(0xFFD4AF37).withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// 状态文本
|
||||
Text(
|
||||
label,
|
||||
_getStatusText(),
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontSize: 18,
|
||||
fontFamily: 'Inter',
|
||||
height: 1.5,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.56,
|
||||
color: Color(0xFF8B5A2B),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
'点击开启实时监控',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w600,
|
||||
height: 1.5,
|
||||
color: Color(0xFF5D4037),
|
||||
color: Color(0x998B5A2B),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// 构建监控中视图
|
||||
Widget _buildMonitorActiveView() {
|
||||
return Column(
|
||||
children: [
|
||||
// 视频流占位区域
|
||||
Expanded(
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black87,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.videocam,
|
||||
size: 64,
|
||||
color: Color(0xFFD4AF37),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
'监控中',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFFD4AF37),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
'视频流功能开发中...',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
color: Colors.white70,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 底部提示
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Text(
|
||||
'点击右上角 × 关闭监控',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Inter',
|
||||
color: const Color(0xFF8B5A2B).withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ class _PlantingQuantityPageState extends ConsumerState<PlantingQuantityPage> {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'可用余额 (USDT)',
|
||||
'可用余额 (积分)',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -651,7 +651,7 @@ class _PlantingQuantityPageState extends ConsumerState<PlantingQuantityPage> {
|
|||
children: [
|
||||
// 每棵价格
|
||||
Text(
|
||||
'每棵价格:${_pricePerTree.toInt()} USDT',
|
||||
'每棵价格:${_pricePerTree.toInt()} 积分',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
|
|
|
|||
|
|
@ -628,7 +628,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
builder: (dialogContext) => AlertDialog(
|
||||
title: const Text('确认领取'),
|
||||
content: Text(
|
||||
'确定领取全部收益吗?\nUSDT: ${_formatNumber(_pendingUsdt)}\n算力: ${_formatNumber(_pendingPower)}',
|
||||
'确定领取全部收益吗?\n积分: ${_formatNumber(_pendingUsdt)}\n算力: ${_formatNumber(_pendingPower)}',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
|
|
@ -1230,10 +1230,10 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
// 收益区域
|
||||
_buildEarningsSection(),
|
||||
const SizedBox(height: 16),
|
||||
// 结算区域
|
||||
// 结算区域(待领取)
|
||||
_buildSettlementSection(),
|
||||
const SizedBox(height: 16),
|
||||
// 已过期区域
|
||||
// 已过期区域(放在待领取下面)
|
||||
_buildExpiredSection(),
|
||||
const SizedBox(height: 16),
|
||||
// 操作按钮
|
||||
|
|
@ -1264,7 +1264,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
initialTarget: _authCityCompanyInitialTarget,
|
||||
monthlyTarget: _authCityCompanyMonthlyTarget,
|
||||
monthIndex: _authCityCompanyMonthIndex,
|
||||
rewardDescription: '每新增认种 1 棵可获得 40 USDT',
|
||||
rewardDescription: '每新增认种 1 棵可获得 40 积分',
|
||||
),
|
||||
],
|
||||
// 省团队权益考核
|
||||
|
|
@ -1278,7 +1278,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
initialTarget: _authProvinceCompanyInitialTarget,
|
||||
monthlyTarget: _authProvinceCompanyMonthlyTarget,
|
||||
monthIndex: _authProvinceCompanyMonthIndex,
|
||||
rewardDescription: '每新增认种 1 棵可获得 20 USDT',
|
||||
rewardDescription: '每新增认种 1 棵可获得 20 积分',
|
||||
),
|
||||
],
|
||||
// 市区域权益考核
|
||||
|
|
@ -1292,7 +1292,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
initialTarget: _cityCompanyInitialTarget,
|
||||
monthlyTarget: _cityCompanyMonthlyTarget,
|
||||
monthIndex: _cityCompanyMonthIndex,
|
||||
rewardDescription: '每新增认种 1 棵可获得 35 USDT',
|
||||
rewardDescription: '每新增认种 1 棵可获得 35 积分',
|
||||
),
|
||||
],
|
||||
// 省区域权益考核
|
||||
|
|
@ -1306,7 +1306,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
initialTarget: _provinceCompanyInitialTarget,
|
||||
monthlyTarget: _provinceCompanyMonthlyTarget,
|
||||
monthIndex: _provinceCompanyMonthIndex,
|
||||
rewardDescription: '每新增认种 1 棵可获得 15 USDT',
|
||||
rewardDescription: '每新增认种 1 棵可获得 15 积分',
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
|
|
@ -1430,7 +1430,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'待领取 (USDT)',
|
||||
'待领取 (积分)',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -1516,13 +1516,13 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
// 构建金额显示文本
|
||||
final List<String> amountParts = [];
|
||||
if (item.usdtAmount > 0) {
|
||||
amountParts.add('${_formatNumber(item.usdtAmount)} USDT');
|
||||
amountParts.add('${_formatNumber(item.usdtAmount)} 积分');
|
||||
}
|
||||
if (item.hashpowerAmount > 0) {
|
||||
amountParts.add('${_formatNumber(item.hashpowerAmount)} 算力');
|
||||
}
|
||||
// 如果都为0,显示默认文本
|
||||
final amountText = amountParts.isNotEmpty ? amountParts.join(' ') : '0 USDT';
|
||||
final amountText = amountParts.isNotEmpty ? amountParts.join(' ') : '0 积分';
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
|
|
@ -1622,7 +1622,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'可结算 (USDT)',
|
||||
'可结算 (积分)',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -1649,7 +1649,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'已结算 (USDT)',
|
||||
'已结算 (积分)',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -1730,7 +1730,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'已过期 (USDT)',
|
||||
'已过期 (积分)',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -1800,7 +1800,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'充值 USDT (KAVA / BSC)',
|
||||
'充值 积分 (KAVA / BSC)',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -1826,7 +1826,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'进入交易 (卖出 DST → USDT)',
|
||||
'进入交易 (卖出 DST → 积分)',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -2356,7 +2356,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
Expanded(
|
||||
child: Text(
|
||||
_communityBenefitActive
|
||||
? '每新增认种 1 棵可获得 80 USDT'
|
||||
? '每新增认种 1 棵可获得 80 积分'
|
||||
: '需团队认种达到 $_communityInitialTarget 棵激活',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
|
|
|
|||
|
|
@ -81,10 +81,22 @@ class _TeamTreeWidgetState extends State<TeamTreeWidget> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SingleChildScrollView(
|
||||
child: _buildTreeLevel([widget.rootNode], 0),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minWidth: screenWidth,
|
||||
),
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildTreeLevel([widget.rootNode], 0),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -174,6 +186,7 @@ class _TeamTreeWidgetState extends State<TeamTreeWidget> {
|
|||
Widget _buildNodeBox(TeamTreeNode node) {
|
||||
return GestureDetector(
|
||||
onTap: () => _handleNodeTap(node),
|
||||
onLongPress: () => _showNodeDetails(node),
|
||||
child: Container(
|
||||
width: nodeWidth,
|
||||
height: nodeHeight,
|
||||
|
|
@ -380,6 +393,26 @@ class _TeamTreeWidgetState extends State<TeamTreeWidget> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 显示节点详情弹窗
|
||||
void _showNodeDetails(TeamTreeNode node) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.white,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
builder: (context) => _NodeDetailsSheet(
|
||||
node: node,
|
||||
onExpandTap: node.hasChildren
|
||||
? () {
|
||||
Navigator.pop(context);
|
||||
_handleNodeTap(node);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 显示隐藏节点的底部弹窗
|
||||
void _showHiddenNodesSheet(List<TeamTreeNode> hiddenNodes) {
|
||||
showModalBottomSheet(
|
||||
|
|
@ -595,3 +628,120 @@ class _TreeLinePainter extends CustomPainter {
|
|||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
}
|
||||
|
||||
/// 节点详情弹窗
|
||||
class _NodeDetailsSheet extends StatelessWidget {
|
||||
final TeamTreeNode node;
|
||||
final VoidCallback? onExpandTap;
|
||||
|
||||
const _NodeDetailsSheet({
|
||||
required this.node,
|
||||
this.onExpandTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 标题栏
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'成员详情',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Color(0xFF5D4037),
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
color: Color(0xFF999999),
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// 序列号
|
||||
_buildDetailRow('序列号', node.accountSequence),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// 个人认种数
|
||||
_buildDetailRow('个人认种', '${node.personalPlantingCount} 棵'),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// 团队认种数
|
||||
_buildDetailRow('团队认种', '${node.teamPlantingCount} 棵'),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// 直推人数
|
||||
_buildDetailRow('直推人数', '${node.directReferralCount} 人'),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 操作按钮
|
||||
if (onExpandTap != null)
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: onExpandTap,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFFD4AF37),
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
node.isExpanded ? '收起下级' : '展开下级 (${node.directReferralCount}人)',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// 底部安全区域
|
||||
SizedBox(height: MediaQuery.of(context).padding.bottom + 8),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDetailRow(String label, String value) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
color: Color(0xFF8B5A2B),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF5D4037),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ class _SharePageState extends ConsumerState<SharePage> {
|
|||
bool _isLoading = true;
|
||||
/// 错误信息
|
||||
String? _errorMessage;
|
||||
/// 推荐码(从 API 获取后保存)
|
||||
String? _referralCode;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -57,8 +59,8 @@ class _SharePageState extends ConsumerState<SharePage> {
|
|||
if (mounted) {
|
||||
setState(() {
|
||||
// 使用 APK 下载链接 + 推荐码参数
|
||||
final referralCode = linkResponse.referralCode;
|
||||
_displayLink = '$_apkDownloadUrl?ref=$referralCode';
|
||||
_referralCode = linkResponse.referralCode;
|
||||
_displayLink = '$_apkDownloadUrl?ref=$_referralCode';
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
|
|
@ -69,6 +71,7 @@ class _SharePageState extends ConsumerState<SharePage> {
|
|||
_isLoading = false;
|
||||
// 失败时使用传入的推荐码构造链接
|
||||
if (widget.referralCode != null && widget.referralCode!.isNotEmpty) {
|
||||
_referralCode = widget.referralCode;
|
||||
_displayLink = '$_apkDownloadUrl?ref=${widget.referralCode}';
|
||||
} else {
|
||||
_displayLink = _apkDownloadUrl;
|
||||
|
|
@ -193,44 +196,105 @@ class _SharePageState extends ConsumerState<SharePage> {
|
|||
|
||||
/// 构建 QR 码区域
|
||||
Widget _buildQrCodeSection() {
|
||||
return Container(
|
||||
width: 256,
|
||||
height: 256,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFAF3E3),
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0x1A8C6A3E), // rgba(140, 106, 62, 0.1)
|
||||
blurRadius: 30,
|
||||
offset: Offset(0, 8),
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 256,
|
||||
height: 256,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFAF3E3),
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0x1A8C6A3E), // rgba(140, 106, 62, 0.1)
|
||||
blurRadius: 30,
|
||||
offset: Offset(0, 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: _isLoading
|
||||
? const CircularProgressIndicator(
|
||||
color: Color(0xFFD4A84B),
|
||||
strokeWidth: 2,
|
||||
)
|
||||
: QrImageView(
|
||||
data: _displayLink,
|
||||
version: QrVersions.auto,
|
||||
size: 200,
|
||||
backgroundColor: Colors.transparent,
|
||||
eyeStyle: const QrEyeStyle(
|
||||
eyeShape: QrEyeShape.square,
|
||||
color: Color(0xFF8C6A3E),
|
||||
),
|
||||
dataModuleStyle: const QrDataModuleStyle(
|
||||
dataModuleShape: QrDataModuleShape.square,
|
||||
color: Color(0xFF8C6A3E),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 推荐码显示
|
||||
if (_referralCode != null && _referralCode!.isNotEmpty) ...[
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF8F1E2),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
'我的推荐码:',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Segoe UI',
|
||||
color: Color(0xFF8C6A3E),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
_referralCode!,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Segoe UI',
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Color(0xFFD4A84B),
|
||||
letterSpacing: 1,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTap: _copyReferralCode,
|
||||
child: const Icon(
|
||||
Icons.copy_outlined,
|
||||
color: Color(0xFF8C6A3E),
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: _isLoading
|
||||
? const CircularProgressIndicator(
|
||||
color: Color(0xFFD4A84B),
|
||||
strokeWidth: 2,
|
||||
)
|
||||
: QrImageView(
|
||||
data: _displayLink,
|
||||
version: QrVersions.auto,
|
||||
size: 200,
|
||||
backgroundColor: Colors.transparent,
|
||||
eyeStyle: const QrEyeStyle(
|
||||
eyeShape: QrEyeShape.square,
|
||||
color: Color(0xFF8C6A3E),
|
||||
),
|
||||
dataModuleStyle: const QrDataModuleStyle(
|
||||
dataModuleShape: QrDataModuleShape.square,
|
||||
color: Color(0xFF8C6A3E),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// 复制推荐码
|
||||
void _copyReferralCode() {
|
||||
if (_referralCode != null && _referralCode!.isNotEmpty) {
|
||||
Clipboard.setData(ClipboardData(text: _referralCode!));
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('推荐码已复制'),
|
||||
backgroundColor: Color(0xFFD4A84B),
|
||||
duration: Duration(seconds: 2),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 构建链接显示区域
|
||||
Widget _buildLinkSection() {
|
||||
return Padding(
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ class _TradingPageState extends ConsumerState<TradingPage> {
|
|||
builder: (context) => AlertDialog(
|
||||
title: const Text('确认结算'),
|
||||
content: Text(
|
||||
'确定将 ${_formatNumber(_settleableAmount)} USDT 结算为 ${_getCurrencyName(_selectedCurrency)} 吗?',
|
||||
'确定将 ${_formatNumber(_settleableAmount)} 积分 结算为 ${_getCurrencyName(_selectedCurrency)} 吗?',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
|
|
@ -169,7 +169,7 @@ class _TradingPageState extends ConsumerState<TradingPage> {
|
|||
builder: (context) => AlertDialog(
|
||||
title: const Text('卖出 DST'),
|
||||
content: Text(
|
||||
'确定将 ${_formatNumber(_dstBalance)} DST 转换为 USDT 吗?',
|
||||
'确定将 ${_formatNumber(_dstBalance)} DST 转换为 积分 吗?',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
|
|
@ -329,7 +329,7 @@ class _TradingPageState extends ConsumerState<TradingPage> {
|
|||
),
|
||||
)
|
||||
: Text(
|
||||
'${_formatNumber(_settleableAmount)} USDT',
|
||||
'${_formatNumber(_settleableAmount)} 积分',
|
||||
style: const TextStyle(
|
||||
fontSize: 32,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -409,7 +409,7 @@ class _TradingPageState extends ConsumerState<TradingPage> {
|
|||
const SizedBox(width: 8),
|
||||
_buildCurrencyChip(SettlementCurrency.og, 'OG'),
|
||||
const SizedBox(width: 8),
|
||||
_buildCurrencyChip(SettlementCurrency.usdt, 'USDT'),
|
||||
_buildCurrencyChip(SettlementCurrency.usdt, '积分'),
|
||||
const SizedBox(width: 8),
|
||||
_buildCurrencyChip(SettlementCurrency.dst, 'DST'),
|
||||
],
|
||||
|
|
@ -480,7 +480,7 @@ class _TradingPageState extends ConsumerState<TradingPage> {
|
|||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'卖出 DST 转换为 USDT(暂未开放)',
|
||||
'卖出 DST 转换为 积分(暂未开放)',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -590,7 +590,7 @@ class _TradingPageState extends ConsumerState<TradingPage> {
|
|||
),
|
||||
)
|
||||
: Text(
|
||||
'USDT 余额: ${_formatNumber(_usdtBalance)}',
|
||||
'积分 余额: ${_formatNumber(_usdtBalance)}',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
|
|
|
|||
|
|
@ -340,13 +340,13 @@ class _WithdrawConfirmPageState extends ConsumerState<WithdrawConfirmPage> {
|
|||
const SizedBox(height: 12),
|
||||
_buildDetailRow('提款地址', _formatAddress(widget.params.address)),
|
||||
const SizedBox(height: 12),
|
||||
_buildDetailRow('提款金额', '${widget.params.amount.toStringAsFixed(2)} USDT'),
|
||||
_buildDetailRow('提款金额', '${widget.params.amount.toStringAsFixed(2)} 积分'),
|
||||
const SizedBox(height: 12),
|
||||
_buildDetailRow('手续费', '${fee.toStringAsFixed(2)} USDT'),
|
||||
_buildDetailRow('手续费', '${fee.toStringAsFixed(2)} 积分'),
|
||||
const Divider(color: Color(0x33D4AF37), height: 24),
|
||||
_buildDetailRow(
|
||||
'实际到账',
|
||||
'${actual.toStringAsFixed(2)} USDT',
|
||||
'${actual.toStringAsFixed(2)} 积分',
|
||||
isHighlight: true,
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ class _WithdrawUsdtPageState extends ConsumerState<WithdrawUsdtPage> {
|
|||
}
|
||||
|
||||
if (amount < _minAmount) {
|
||||
_showErrorSnackBar('最小提款金额为 $_minAmount USDT');
|
||||
_showErrorSnackBar('最小提款金额为 $_minAmount 积分');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -365,7 +365,7 @@ class _WithdrawUsdtPageState extends ConsumerState<WithdrawUsdtPage> {
|
|||
// 标题
|
||||
const Expanded(
|
||||
child: Text(
|
||||
'提款 USDT',
|
||||
'提款 积分',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -426,7 +426,7 @@ class _WithdrawUsdtPageState extends ConsumerState<WithdrawUsdtPage> {
|
|||
const Padding(
|
||||
padding: EdgeInsets.only(bottom: 4),
|
||||
child: Text(
|
||||
'USDT',
|
||||
'积分',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -675,7 +675,7 @@ class _WithdrawUsdtPageState extends ConsumerState<WithdrawUsdtPage> {
|
|||
height: 1.4,
|
||||
color: Color(0x995D4037),
|
||||
),
|
||||
suffixText: 'USDT',
|
||||
suffixText: '积分',
|
||||
suffixStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -687,7 +687,7 @@ class _WithdrawUsdtPageState extends ConsumerState<WithdrawUsdtPage> {
|
|||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'最小提款金额: $_minAmount USDT',
|
||||
'最小提款金额: $_minAmount 积分',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Inter',
|
||||
|
|
@ -718,11 +718,11 @@ class _WithdrawUsdtPageState extends ConsumerState<WithdrawUsdtPage> {
|
|||
children: [
|
||||
_buildFeeRow('手续费率', '${(_feeRate * 100).toStringAsFixed(1)}%'),
|
||||
const SizedBox(height: 8),
|
||||
_buildFeeRow('手续费', '${fee.toStringAsFixed(2)} USDT'),
|
||||
_buildFeeRow('手续费', '${fee.toStringAsFixed(2)} 积分'),
|
||||
const Divider(color: Color(0x33D4AF37), height: 24),
|
||||
_buildFeeRow(
|
||||
'预计到账',
|
||||
'${actual > 0 ? actual.toStringAsFixed(2) : '0.00'} USDT',
|
||||
'${actual > 0 ? actual.toStringAsFixed(2) : '0.00'} 积分',
|
||||
isHighlight: true,
|
||||
),
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in New Issue