diff --git a/frontend/mobile-app/lib/core/storage/storage_keys.dart b/frontend/mobile-app/lib/core/storage/storage_keys.dart index 44fb5a85..5a662812 100644 --- a/frontend/mobile-app/lib/core/storage/storage_keys.dart +++ b/frontend/mobile-app/lib/core/storage/storage_keys.dart @@ -8,6 +8,7 @@ class StorageKeys { static const String avatarUrl = 'avatar_url'; // 用户上传的头像URL static const String referralCode = 'referral_code'; // 推荐码 static const String inviterSequence = 'inviter_sequence'; // 推荐人序列号 + static const String inviterReferralCode = 'inviter_referral_code'; // 邀请人推荐码(注册前临时存储) static const String isAccountCreated = 'is_account_created'; // 账号是否已创建 // 钱包信息 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 8eeda837..9a4f695a 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 @@ -5,6 +5,8 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:go_router/go_router.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; +import '../../../../core/di/injection_container.dart'; +import '../../../../core/storage/storage_keys.dart'; import '../../../../routes/route_paths.dart'; import '../providers/auth_provider.dart'; @@ -247,7 +249,7 @@ class _GuidePageState extends ConsumerState { } /// 欢迎加入页面内容 (第5页) -class _WelcomePageContent extends StatefulWidget { +class _WelcomePageContent extends ConsumerStatefulWidget { final VoidCallback onNext; final VoidCallback onExit; @@ -257,10 +259,10 @@ class _WelcomePageContent extends StatefulWidget { }); @override - State<_WelcomePageContent> createState() => _WelcomePageContentState(); + ConsumerState<_WelcomePageContent> createState() => _WelcomePageContentState(); } -class _WelcomePageContentState extends State<_WelcomePageContent> { +class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> { bool _hasReferrer = true; final TextEditingController _referralCodeController = TextEditingController(); @@ -313,6 +315,24 @@ class _WelcomePageContentState extends State<_WelcomePageContent> { return _isValidReferralCode(_referralCodeController.text); } + /// 保存推荐码并继续下一步 + Future _saveReferralCodeAndProceed() async { + if (!_canProceed) return; + + // 如果有推荐人且推荐码有效,保存到本地存储 + if (_hasReferrer && _referralCodeController.text.trim().isNotEmpty) { + final secureStorage = ref.read(secureStorageProvider); + await secureStorage.write( + key: StorageKeys.inviterReferralCode, + value: _referralCodeController.text.trim(), + ); + debugPrint('[GuidePage] 保存邀请人推荐码: ${_referralCodeController.text.trim()}'); + } + + // 调用下一步回调 + widget.onNext(); + } + /// 打开二维码扫描页面 Future _openQrScanner() async { final result = await Navigator.of(context).push( @@ -332,7 +352,8 @@ class _WelcomePageContentState extends State<_WelcomePageContent> { /// 从扫描结果中提取推荐码 /// 支持以下格式: - /// - 完整 URL: https://app.rwadurian.com/r/ABC123 -> ABC123 + /// - 查询参数: https://app.rwadurian.com/share?ref=ABC123 -> ABC123 + /// - 路径格式: https://app.rwadurian.com/r/ABC123 -> ABC123 /// - 短链: https://rwa.link/ABC123 -> ABC123 /// - 纯推荐码: ABC123 -> ABC123 String _extractReferralCode(String scannedData) { @@ -344,27 +365,32 @@ class _WelcomePageContentState extends State<_WelcomePageContent> { try { final uri = Uri.parse(data); - // 尝试从路径中提取 (如 /r/ABC123 或 /ABC123) - final pathSegments = uri.pathSegments; - if (pathSegments.isNotEmpty) { - // 取最后一个路径段作为推荐码 - final lastSegment = pathSegments.last; - if (lastSegment.isNotEmpty) { - return lastSegment; - } - // 如果最后一段是 'r',取倒数第二段 - if (pathSegments.length >= 2 && lastSegment == 'r') { - return pathSegments[pathSegments.length - 2]; - } - } - - // 尝试从查询参数中提取 (如 ?ref=ABC123 或 ?code=ABC123) + // 优先从查询参数中提取 (如 ?ref=ABC123 或 ?code=ABC123) final refCode = uri.queryParameters['ref'] ?? uri.queryParameters['code'] ?? uri.queryParameters['referral']; if (refCode != null && refCode.isNotEmpty) { return refCode; } + + // 其次从路径中提取 (如 /r/ABC123 或 /ABC123) + final pathSegments = uri.pathSegments; + if (pathSegments.isNotEmpty) { + // 取最后一个路径段作为推荐码 + final lastSegment = pathSegments.last; + // 排除常见的非推荐码路径段 + const excludedSegments = ['share', 'invite', 'r', 'ref', 'referral']; + if (lastSegment.isNotEmpty && !excludedSegments.contains(lastSegment.toLowerCase())) { + return lastSegment; + } + // 如果最后一段是排除项且有倒数第二段,检查倒数第二段 + if (pathSegments.length >= 2) { + final secondLastSegment = pathSegments[pathSegments.length - 2]; + if (secondLastSegment.isNotEmpty && !excludedSegments.contains(secondLastSegment.toLowerCase())) { + return secondLastSegment; + } + } + } } catch (e) { // URL 解析失败,返回原始数据 debugPrint('URL 解析失败: $e'); @@ -435,7 +461,7 @@ class _WelcomePageContentState extends State<_WelcomePageContent> { const Spacer(), // 下一步按钮 GestureDetector( - onTap: _canProceed ? widget.onNext : null, + onTap: _canProceed ? _saveReferralCodeAndProceed : null, child: Container( width: double.infinity, padding: EdgeInsets.symmetric(vertical: 16.h), diff --git a/frontend/mobile-app/lib/features/auth/presentation/pages/onboarding_page.dart b/frontend/mobile-app/lib/features/auth/presentation/pages/onboarding_page.dart index 05784493..9d2d53a9 100644 --- a/frontend/mobile-app/lib/features/auth/presentation/pages/onboarding_page.dart +++ b/frontend/mobile-app/lib/features/auth/presentation/pages/onboarding_page.dart @@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart'; import '../../../../routes/route_paths.dart'; import '../../../../routes/app_router.dart'; import '../../../../core/di/injection_container.dart'; +import '../../../../core/storage/storage_keys.dart'; /// 创建账号页面 - 用户首次进入应用时的引导页面 /// 提供创建钱包和导入助记词两种选项 @@ -106,14 +107,29 @@ class _OnboardingPageState extends ConsumerState { }); try { - // 获取 AccountService + // 获取 AccountService 和 SecureStorage final accountService = ref.read(accountServiceProvider); + final secureStorage = ref.read(secureStorageProvider); + + // 读取邀请人推荐码(从向导页保存的) + final inviterReferralCode = await secureStorage.read( + key: StorageKeys.inviterReferralCode, + ); + debugPrint('[OnboardingPage] _createAccount - 邀请人推荐码: ${inviterReferralCode ?? "无"}'); // 调用后端 API 创建账号 debugPrint('[OnboardingPage] _createAccount - 调用 accountService.createAccount()'); - final response = await accountService.createAccount(); + final response = await accountService.createAccount( + inviterReferralCode: inviterReferralCode, + ); debugPrint('[OnboardingPage] _createAccount - 成功! 序列号=${response.userSerialNum}, 用户名=${response.username}'); + // 创建成功后清除临时存储的邀请人推荐码 + if (inviterReferralCode != null) { + await secureStorage.delete(key: StorageKeys.inviterReferralCode); + debugPrint('[OnboardingPage] _createAccount - 已清除临时邀请人推荐码'); + } + if (!mounted) { debugPrint('[OnboardingPage] _createAccount - Widget已卸载,忽略响应'); return;