diff --git a/frontend/mobile-app/lib/core/constants/api_endpoints.dart b/frontend/mobile-app/lib/core/constants/api_endpoints.dart index b05eee17..d1e2b6af 100644 --- a/frontend/mobile-app/lib/core/constants/api_endpoints.dart +++ b/frontend/mobile-app/lib/core/constants/api_endpoints.dart @@ -1,38 +1,39 @@ +/// API 端点常量 +/// +/// 注意: 这些路径不包含 /api/v1 前缀,因为 AppConfig.apiBaseUrl 已经包含了 +/// 例如 baseUrl = 'https://rwaapi.szaiai.com/api/v1' class ApiEndpoints { ApiEndpoints._(); - // Base URL - 生产环境 + // Base URL - 生产环境 (仅供参考,实际使用 AppConfig) static const String baseUrl = 'https://rwaapi.szaiai.com'; // Base URL - 开发环境 static const String baseUrlDev = 'https://rwaapi-dev.szaiai.com'; - // API 版本前缀 - static const String apiPrefix = '/api/v1'; - // Auth (-> Identity Service) - static const String auth = '$apiPrefix/auth'; + static const String auth = '/auth'; static const String login = '$auth/login'; static const String register = '$auth/register'; static const String refreshToken = '$auth/refresh'; static const String logout = '$auth/logout'; // User (-> Identity Service) - static const String user = '$apiPrefix/user'; + static const String user = '/user'; static const String autoCreate = '$user/auto-create'; static const String userWallet = '$user/wallet'; // 获取钱包状态 - static const String me = '$apiPrefix/me'; // 获取当前用户完整信息 + static const String me = '/me'; // 获取当前用户完整信息 static const String profile = '$user/profile'; static const String updateProfile = '$user/profile/update'; static const String updateAvatar = '$user/avatar'; // Wallet (-> Wallet Service) - static const String wallet = '$apiPrefix/wallet'; + static const String wallet = '/wallet'; static const String createWallet = '$wallet/create'; static const String importWallet = '$wallet/import'; static const String balance = '$wallet/balance'; // Mining (-> Reward Service) - static const String mining = '$apiPrefix/mining'; + static const String mining = '/mining'; static const String miningStatus = '$mining/status'; static const String startMining = '$mining/start'; static const String stopMining = '$mining/stop'; @@ -40,33 +41,33 @@ class ApiEndpoints { static const String hashPower = '$mining/hash-power'; // Ranking (-> Leaderboard Service) - static const String ranking = '$apiPrefix/ranking'; + static const String ranking = '/ranking'; static const String dailyRanking = '$ranking/daily'; static const String weeklyRanking = '$ranking/weekly'; static const String monthlyRanking = '$ranking/monthly'; // Trading (-> Wallet Service) - static const String trading = '$apiPrefix/trading'; + static const String trading = '/trading'; static const String exchange = '$trading/exchange'; static const String settlement = '$trading/settlement'; static const String transactions = '$trading/transactions'; // Deposit (-> Wallet Service) - static const String deposit = '$apiPrefix/deposit'; + static const String deposit = '/deposit'; static const String depositAddress = '$deposit/address'; static const String confirmDeposit = '$deposit/confirm'; static const String depositRecords = '$deposit/records'; // Planting (-> Planting Service) - static const String planting = '$apiPrefix/planting'; + static const String planting = '/planting'; static const String plantingPrice = '$planting/price'; static const String submitPlanting = '$planting/submit'; static const String provinces = '$planting/provinces'; static const String cities = '$planting/cities'; // Community & Referral (-> Referral Service) - static const String community = '$apiPrefix/community'; - static const String referral = '$apiPrefix/referral'; + static const String community = '/community'; + static const String referral = '/referral'; static const String referralMe = '$referral/me'; // 获取当前用户推荐信息 static const String referralDirects = '$referral/me/direct-referrals'; // 获取直推列表 static const String referralList = '$community/referrals'; @@ -75,11 +76,11 @@ class ApiEndpoints { static const String generateReferralLink = '$referral/generate-link'; // Authorization (-> Authorization Service) - static const String authorizations = '$apiPrefix/authorizations'; + static const String authorizations = '/authorizations'; static const String myAuthorizations = '$authorizations/my'; // 获取我的授权列表 // Telemetry (-> Reporting Service) - static const String telemetry = '$apiPrefix/telemetry'; + static const String telemetry = '/telemetry'; static const String telemetrySession = '$telemetry/session'; static const String telemetryHeartbeat = '$telemetry/heartbeat'; static const String telemetryEvents = '$telemetry/events'; diff --git a/frontend/mobile-app/lib/features/auth/presentation/pages/guide_page.dart b/frontend/mobile-app/lib/features/auth/presentation/pages/guide_page.dart index 845390a6..90e9e1af 100644 --- a/frontend/mobile-app/lib/features/auth/presentation/pages/guide_page.dart +++ b/frontend/mobile-app/lib/features/auth/presentation/pages/guide_page.dart @@ -146,50 +146,45 @@ class _GuidePageState extends ConsumerState { } /// 构建向导页 (页面1-4) - 全屏背景图片,无文字 - /// 使用 BoxFit.fitWidth 保持图片原始比例,不拉伸文字 + /// 使用 BoxFit.cover 填满屏幕,保持宽高比(会裁剪超出部分) Widget _buildGuidePage(GuidePageData data, int index) { debugPrint('[GuidePage] _buildGuidePage() - 页面 ${index + 1}, 图片: ${data.imagePath}'); - return Container( - color: Colors.black, // 如果图片不够高,上下用黑色填充 - child: Stack( - fit: StackFit.expand, - children: [ - // 全屏背景图片 - 使用 fitWidth 保持宽高比 - if (data.imagePath != null) - LayoutBuilder( - builder: (context, constraints) { - debugPrint('[GuidePage] 页面 ${index + 1} 容器尺寸: ${constraints.maxWidth.toStringAsFixed(1)} x ${constraints.maxHeight.toStringAsFixed(1)}'); - debugPrint('[GuidePage] 页面 ${index + 1} 使用 BoxFit.fitWidth'); - return Center( - child: Image.asset( - data.imagePath!, - fit: BoxFit.fitWidth, - width: double.infinity, - errorBuilder: (context, error, stackTrace) { - debugPrint('[GuidePage] 页面 ${index + 1} 图片加载失败: $error'); - return Container( - color: const Color(0xFFFFF8E7), - child: _buildPlaceholderImage(index), - ); - }, - ), - ); - }, - ) - else - Container( - color: const Color(0xFFFFF8E7), - child: _buildPlaceholderImage(index), - ), - // 底部页面指示器 - Positioned( - left: 0, - right: 0, - bottom: 80.h, - child: _buildPageIndicator(), + return Stack( + fit: StackFit.expand, + children: [ + // 全屏背景图片 - 使用 cover 填满屏幕 + if (data.imagePath != null) + Image.asset( + data.imagePath!, + fit: BoxFit.cover, + width: double.infinity, + height: double.infinity, + errorBuilder: (context, error, stackTrace) { + debugPrint('[GuidePage] 页面 ${index + 1} 图片加载失败: $error'); + return Container( + color: const Color(0xFFFFF8E7), + child: _buildPlaceholderImage(index), + ); + }, + ) + else + Container( + color: const Color(0xFFFFF8E7), + child: _buildPlaceholderImage(index), ), - ], - ), + // 底部页面指示器 - 使用 SafeArea 避免被系统 UI 遮挡 + Positioned( + left: 0, + right: 0, + bottom: 0, + child: SafeArea( + child: Padding( + padding: EdgeInsets.only(bottom: 40.h), + child: _buildPageIndicator(), + ), + ), + ), + ], ); } @@ -423,42 +418,39 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> { Widget build(BuildContext context) { return GestureDetector( onTap: () => FocusScope.of(context).unfocus(), - child: Container( - color: Colors.black, // 如果图片不够高,上下用黑色填充 - child: Stack( - fit: StackFit.expand, - children: [ - // 全屏背景图片 - 使用 fitWidth 保持宽高比 - if (widget.backgroundImage != null) - Center( - child: Image.asset( - widget.backgroundImage!, - fit: BoxFit.fitWidth, - width: double.infinity, - errorBuilder: (context, error, stackTrace) { - return Container( - color: const Color(0xFFFFF8E7), - ); - }, - ), - ) - else - Container( - color: const Color(0xFFFFF8E7), - ), - // 半透明遮罩,让内容更清晰 + child: Stack( + fit: StackFit.expand, + children: [ + // 全屏背景图片 - 使用 cover 填满屏幕 + if (widget.backgroundImage != null) + Image.asset( + widget.backgroundImage!, + fit: BoxFit.cover, + width: double.infinity, + height: double.infinity, + errorBuilder: (context, error, stackTrace) { + return Container( + color: const Color(0xFFFFF8E7), + ); + }, + ) + else Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.black.withValues(alpha: 0.3), - Colors.black.withValues(alpha: 0.6), - ], - ), + color: const Color(0xFFFFF8E7), + ), + // 半透明遮罩,让内容更清晰 + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withValues(alpha: 0.3), + Colors.black.withValues(alpha: 0.6), + ], ), ), + ), // 内容区域 SafeArea( child: LayoutBuilder( @@ -567,7 +559,6 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> { ), ), ], - ), ), ); } diff --git a/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart b/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart index 35b7657a..6503e3fa 100644 --- a/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart +++ b/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart @@ -637,18 +637,58 @@ class _ProfilePageState extends ConsumerState { } /// 构建SVG或默认头像 + /// 注意:_avatarSvg 可能存储的是 URL(用户上传的图片)或 SVG 字符串(随机生成的头像) Widget _buildSvgOrDefaultAvatar() { - if (_avatarSvg != null) { - debugPrint('[ProfilePage] _buildSvgOrDefaultAvatar() - 使用SVG头像,长度=${_avatarSvg!.length}'); - debugPrint('[ProfilePage] SVG前50字符: ${_avatarSvg!.substring(0, _avatarSvg!.length > 50 ? 50 : _avatarSvg!.length)}'); - return SvgPicture.string( - _avatarSvg!, - width: 80, - height: 80, - fit: BoxFit.cover, - ); + if (_avatarSvg != null && _avatarSvg!.isNotEmpty) { + debugPrint('[ProfilePage] _buildSvgOrDefaultAvatar() - 检查头像内容,长度=${_avatarSvg!.length}'); + debugPrint('[ProfilePage] 内容前50字符: ${_avatarSvg!.substring(0, _avatarSvg!.length > 50 ? 50 : _avatarSvg!.length)}'); + + // 检测是否是 URL(用户上传的头像图片) + if (_avatarSvg!.startsWith('http://') || _avatarSvg!.startsWith('https://')) { + debugPrint('[ProfilePage] _buildSvgOrDefaultAvatar() - 检测到是URL,使用网络图片'); + return Image.network( + _avatarSvg!, + width: 80, + height: 80, + fit: BoxFit.cover, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return const Center( + child: SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Color(0xFFD4AF37)), + ), + ), + ); + }, + errorBuilder: (context, error, stackTrace) { + debugPrint('[ProfilePage] _buildSvgOrDefaultAvatar() - 网络图片加载失败: $error'); + return const Icon( + Icons.person, + size: 40, + color: Color(0xFF8B5A2B), + ); + }, + ); + } + + // 检测是否是 SVG 字符串(随机生成的 SVG 头像) + if (_avatarSvg!.contains('