QinGang_interested/lib/pages/user/register_page.dart

329 lines
11 KiB
Dart
Raw Normal View History

2025-12-12 09:11:30 +08:00
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<RegisterPage> createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {
final _formKey = GlobalKey<FormState>();
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<void> _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<void> _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,
};
2025-12-24 16:07:53 +08:00
LoadingDialogHelper.show();
2025-12-12 09:11:30 +08:00
final resp = await BasicInfoApi.register(data);
2025-12-24 16:07:53 +08:00
LoadingDialogHelper.hide();
2025-12-12 09:11:30 +08:00
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) {
2025-12-24 16:07:53 +08:00
LoadingDialogHelper.hide();
2025-12-12 09:11:30 +08:00
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,
),
),
],
),
),
),
),
);
}
}