import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../core/network/api_exception.dart'; import '../../core/storage/local_store.dart'; import '../../core/theme/app_theme.dart'; import '../../providers/auth_provider.dart'; import '../../services/auth_service.dart'; /// 注册页:手机号 + 验证码 + 密码;邀请码选填(口令/模糊归因命中时自动预填) class RegisterScreen extends ConsumerStatefulWidget { const RegisterScreen({super.key}); @override ConsumerState createState() => _RegisterScreenState(); } class _RegisterScreenState extends ConsumerState { final _phone = TextEditingController(); final _code = TextEditingController(); final _password = TextEditingController(); final _nickname = TextEditingController(); late final TextEditingController _inviteCode; bool _loading = false; String? _error; /// 验证码发送倒计时 int _countdown = 0; Timer? _timer; @override void initState() { super.initState(); // 首启归因命中的邀请码预填(用户可改可清空) _inviteCode = TextEditingController(text: LocalStore.I.pendingInviteCode ?? ''); } @override void dispose() { _timer?.cancel(); _phone.dispose(); _code.dispose(); _password.dispose(); _nickname.dispose(); _inviteCode.dispose(); super.dispose(); } Future _sendCode() async { final phone = _phone.text.trim(); if (!RegExp(r'^1\d{10}$').hasMatch(phone)) { setState(() => _error = '请输入正确的手机号'); return; } try { final devCode = await AuthService.sendSmsCode(phone, 'register'); setState(() { _error = null; _countdown = 60; }); if (devCode != null && mounted) { // 短信通道未配置时的开发模式:直接展示验证码(上线配置短信后服务端不再返回) ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('开发模式验证码:$devCode(5 分钟内有效)'), duration: const Duration(seconds: 6)), ); } _timer?.cancel(); _timer = Timer.periodic(const Duration(seconds: 1), (t) { if (_countdown <= 1) { t.cancel(); setState(() => _countdown = 0); } else { setState(() => _countdown -= 1); } }); } on ApiException catch (e) { setState(() => _error = e.message); } catch (_) { setState(() => _error = '网络异常,请稍后重试'); } } Future _submit() async { final phone = _phone.text.trim(); final code = _code.text.trim(); final password = _password.text; if (phone.isEmpty || code.isEmpty || password.isEmpty) { setState(() => _error = '请填写手机号、验证码和密码'); return; } setState(() { _loading = true; _error = null; }); try { final result = await AuthService.register( type: 'phone', account: phone, code: code, password: password, nickname: _nickname.text.trim(), inviteCode: _inviteCode.text.trim().toUpperCase(), ); // 注册成功:pending 邀请码已被消费,清除本地标记 await LocalStore.I.clearPendingInviteCode(); await ref.read(authProvider.notifier).onLoginSuccess(result.user); if (!mounted) return; if (result.trialPlanName != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('注册成功,已赠送${result.trialPlanName}')), ); } context.go('/home'); } on ApiException catch (e) { setState(() => _error = e.message); } catch (_) { setState(() => _error = '网络异常,请稍后重试'); } finally { if (mounted) setState(() => _loading = false); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('注册')), body: SafeArea( child: ListView( padding: const EdgeInsets.all(24), children: [ const Text('创建账号', style: TextStyle(fontSize: 26, fontWeight: FontWeight.w700)), const SizedBox(height: 32), TextField( controller: _phone, keyboardType: TextInputType.phone, decoration: const InputDecoration(hintText: '手机号'), ), const SizedBox(height: 16), Row( children: [ Expanded( child: TextField( controller: _code, keyboardType: TextInputType.number, decoration: const InputDecoration(hintText: '短信验证码'), ), ), const SizedBox(width: 12), SizedBox( width: 120, child: OutlinedButton( onPressed: _countdown > 0 ? null : _sendCode, child: Text(_countdown > 0 ? '${_countdown}s 后重发' : '获取验证码'), ), ), ], ), const SizedBox(height: 16), TextField( controller: _password, obscureText: true, decoration: const InputDecoration(hintText: '密码(8-32 位,含字母和数字)'), ), const SizedBox(height: 16), TextField( controller: _nickname, decoration: const InputDecoration(hintText: '昵称(选填)'), ), const SizedBox(height: 16), TextField( controller: _inviteCode, textCapitalization: TextCapitalization.characters, decoration: const InputDecoration(hintText: '邀请码(选填)'), ), if (_error != null) ...[ const SizedBox(height: 12), Text(_error!, style: const TextStyle(color: AppColors.primary, fontSize: 13)), ], const SizedBox(height: 24), ElevatedButton( onPressed: _loading ? null : _submit, child: _loading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : const Text('注册并登录'), ), const SizedBox(height: 16), TextButton( onPressed: () => context.pop(), child: const Text('已有账号?去登录', style: TextStyle(color: AppColors.textSecondary)), ), ], ), ), ); } }