import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:qhd_prevention/customWidget/custom_button.dart'; import 'package:qhd_prevention/customWidget/toast_util.dart'; import 'package:qhd_prevention/pages/my_appbar.dart'; import 'package:qhd_prevention/pages/user/CustomInput.dart'; import 'package:qhd_prevention/pages/user/login_page.dart'; import 'package:qhd_prevention/tools/tools.dart'; import '../../http/ApiService.dart'; // 假设你的 API 在这里 class RegisterPage extends StatefulWidget { const RegisterPage({super.key}); @override State createState() => _RegisterPageState(); } class _RegisterPageState extends State { final _formKey = GlobalKey(); final TextEditingController _phoneController = TextEditingController(); final TextEditingController _codeController = TextEditingController(); final TextEditingController _pwdController = TextEditingController(); final TextEditingController _confirmPwdController = TextEditingController(); bool _obscurePwd = true; bool _obscureConfirm = true; // 验证码发送状态和倒计时 bool _isSendingCode = false; int _secondsLeft = 0; Timer? _timer; String textString = "*密码长度8-18位,必须包含大小写字母+数字+特殊字母,例如:Qa@123456"; @override void dispose() { _timer?.cancel(); _phoneController.dispose(); _codeController.dispose(); _pwdController.dispose(); _confirmPwdController.dispose(); super.dispose(); } // 验证密码复杂度 bool isPasswordValid(String password) { final hasUpperCase = RegExp(r'[A-Z]'); final hasLowerCase = RegExp(r'[a-z]'); final hasNumber = RegExp(r'[0-9]'); final hasSpecialChar = RegExp(r'[!@#\$%\^&\*\(\)_\+\-=\[\]\{\};:"\\|,.<>\/\?~`]'); return hasUpperCase.hasMatch(password) && hasLowerCase.hasMatch(password) && hasNumber.hasMatch(password) && hasSpecialChar.hasMatch(password); } // 手机号简单校验(11 位数字) bool _isPhoneValid(String phone) { final RegExp phoneReg = RegExp(r'^\d{11}$'); return phoneReg.hasMatch(phone); } void _startCountdown(int seconds) { _timer?.cancel(); setState(() { _secondsLeft = seconds; }); _timer = Timer.periodic(const Duration(seconds: 1), (timer) { if (!mounted) return; setState(() { _secondsLeft--; if (_secondsLeft <= 0) { _timer?.cancel(); _secondsLeft = 0; } }); }); } Future _sendCode() async { final phone = _phoneController.text.trim(); if (phone.isEmpty) { ToastUtil.showNormal(context, '请输入手机号'); return; } if (!_isPhoneValid(phone)) { ToastUtil.showNormal(context, '请输入有效的手机号(11位)'); return; } if (_isSendingCode || _secondsLeft > 0) return; setState(() { _isSendingCode = true; }); LoadingDialogHelper.show(); try { final resp = await BasicInfoApi.sendRegisterSms({'phone': phone}); LoadingDialogHelper.hide(); if (resp != null && resp['success'] == true) { ToastUtil.showNormal(context, '验证码已发送'); _startCountdown(60); } else { ToastUtil.showNormal(context, resp?['message'] ?? '发送验证码失败'); } } catch (e) { LoadingDialogHelper.hide(); ToastUtil.showNormal(context, '发送验证码失败,请稍后重试'); } finally { setState(() { _isSendingCode = false; }); } } Future _handleRegister() async { if (!(_formKey.currentState?.validate() ?? false)) return; final phone = _phoneController.text.trim(); final code = _codeController.text.trim(); final pwd = _pwdController.text.trim(); final confirm = _confirmPwdController.text.trim(); if (!_isPhoneValid(phone)) { ToastUtil.showNormal(context, '请输入有效的手机号(11位)'); return; } if (code.isEmpty) { ToastUtil.showNormal(context, '请输入验证码'); return; } if (pwd.isEmpty) { ToastUtil.showNormal(context, '请输入密码'); return; } if (confirm.isEmpty) { ToastUtil.showNormal(context, '请确认密码'); return; } if (pwd != confirm) { ToastUtil.showNormal(context, '两次输入的密码不一致'); return; } if (pwd.length < 8) { ToastUtil.showNormal(context, '密码长度需至少8位'); return; } if (pwd.length > 32) { ToastUtil.showNormal(context, '密码长度需小于32位'); return; } if (!isPasswordValid(pwd)) { ToastUtil.showNormal(context, '密码必须包含大小写字母、数字和特殊符号'); return; } try { final data = { 'phone': phone, 'phoneCode': code, 'newPassword': pwd, 'confirmPassword': pwd, }; LoadingDialogHelper.show(); final resp = await BasicInfoApi.register(data); LoadingDialogHelper.hide(); if (resp != null && resp['success'] == true) { ToastUtil.showNormal(context, '注册成功,请登录'); // 跳转到登录页并移除当前页面栈 Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (context) => const LoginPage()), (route) => false, ); } else { ToastUtil.showNormal(context, resp?['message'] ?? '注册失败,请重试'); } } catch (e) { LoadingDialogHelper.hide(); ToastUtil.showNormal(context, '注册失败,请稍后重试'); } } @override Widget build(BuildContext context) { return Scaffold( appBar: MyAppbar(title: '注册账号'), backgroundColor: Colors.white, body: SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 20), child: Form( key: _formKey, child: Column( children: [ const SizedBox(height: 8), // 手机号(使用 CustomInput) CustomInput.buildInput( _phoneController, title: '手机号', hint: '请输入手机号', keyboardType: TextInputType.phone, validator: (v) { if (v == null || v.isEmpty) return '请输入手机号'; if (!_isPhoneValid(v.trim())) return '请输入有效的手机号'; return null; }, ), const SizedBox(height: 16), // 验证码 + 发送按钮 行(验证码输入使用 CustomInput) Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: CustomInput.buildInput( _codeController, title: '验证码', hint: '请输入验证码', keyboardType: TextInputType.number, validator: (v) { if (v == null || v.isEmpty) return '请输入验证码'; return null; }, ), ), const SizedBox(width: 12), Column( children: [ const SizedBox(height: 40), SizedBox( height: 40, child: ElevatedButton( onPressed: (_secondsLeft > 0 || _isSendingCode) ? null : _sendCode, style: ElevatedButton.styleFrom( backgroundColor: (_secondsLeft > 0) ? Colors.grey.shade400 : const Color(0xFF2A75F8), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), padding: const EdgeInsets.symmetric(horizontal: 12), ), child: Text( _secondsLeft > 0 ? '$_secondsLeft s后可重发' : '发送验证码', style: const TextStyle(fontSize: 14, color: Colors.white), ), ), ), ], ) ], ), const SizedBox(height: 16), // 密码 CustomInput.buildInput( _pwdController, title: '密码', hint: '请输入密码', obscure: _obscurePwd, suffix: IconButton( icon: Icon(_obscurePwd ? Icons.visibility_off : Icons.visibility, color: Colors.grey), onPressed: () => setState(() => _obscurePwd = !_obscurePwd), ), validator: (v) { if (v == null || v.isEmpty) return '请输入密码'; if (v.length < 8) return '密码长度至少 8 位'; return null; }, ), const SizedBox(height: 16), // 确认密码 CustomInput.buildInput( _confirmPwdController, title: '确认密码', hint: '请再次输入密码', obscure: _obscureConfirm, suffix: IconButton( icon: Icon(_obscureConfirm ? Icons.visibility_off : Icons.visibility, color: Colors.grey), onPressed: () => setState(() => _obscureConfirm = !_obscureConfirm), ), validator: (v) { if (v == null || v.isEmpty) return '请确认密码'; return null; }, ), const SizedBox(height: 12), // 密码提示语 Align( alignment: Alignment.centerLeft, child: Text( textString, style: const TextStyle(color: Colors.red, fontSize: 13), ), ), const SizedBox(height: 30), // 注册确认按钮 SizedBox( width: double.infinity, height: 45, child: CustomButton( onPressed: _handleRegister, text: '确认', backgroundColor: Colors.blue, ), ), ], ), ), ), ), ); } }