279 lines
9.3 KiB
Dart
279 lines
9.3 KiB
Dart
|
|
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/login_page.dart';
|
|||
|
|
import 'package:qhd_prevention/services/SessionService.dart';
|
|||
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|||
|
|
import '../../http/ApiService.dart';
|
|||
|
|
|
|||
|
|
class MineSetPwdPage extends StatefulWidget {
|
|||
|
|
const MineSetPwdPage(this.type, {super.key});
|
|||
|
|
|
|||
|
|
final String type;
|
|||
|
|
@override
|
|||
|
|
State<MineSetPwdPage> createState() => _MineSetPwdPageState();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class _MineSetPwdPageState extends State<MineSetPwdPage> {
|
|||
|
|
final _formKey = GlobalKey<FormState>();
|
|||
|
|
|
|||
|
|
final _oldPwdController = TextEditingController();
|
|||
|
|
final _newPwdController = TextEditingController();
|
|||
|
|
final _confirmPwdController = TextEditingController();
|
|||
|
|
|
|||
|
|
bool _obscureOld = true;
|
|||
|
|
bool _obscureNew = true;
|
|||
|
|
bool _obscureConfirm = true;
|
|||
|
|
|
|||
|
|
String textString =
|
|||
|
|
"为了您的账户安全,请确保密码长度为 8-18 位,必须包含大小写字母+数字+特殊字符,例如:Aa@123456";
|
|||
|
|
|
|||
|
|
Map<String, dynamic> passData = {
|
|||
|
|
"id": '',
|
|||
|
|
"password": "",
|
|||
|
|
"newPassword": "",
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
void initState() {
|
|||
|
|
super.initState();
|
|||
|
|
switch (widget.type) {
|
|||
|
|
case "0":
|
|||
|
|
textString =
|
|||
|
|
"密码长度8-18位,需包含数字、字母、英文符号至少2种或以上元素";
|
|||
|
|
break;
|
|||
|
|
case "1":
|
|||
|
|
textString =
|
|||
|
|
"检测到您的密码为弱密码,请修改密码后重新登录。为了您的账户安全,请确保密码长度为 8-18 位,必须包含大小写字母+数字+特殊字符,例如:Aa@123456";
|
|||
|
|
break;
|
|||
|
|
case "2":
|
|||
|
|
textString =
|
|||
|
|
"检测到您30天内未修改密码,请修改密码后重新登录。为了您的账户安全,请确保密码长度为 8-18 位,必须包含大小写字母+数字+特殊字符,例如:Aa@123456";
|
|||
|
|
break;
|
|||
|
|
case "3":
|
|||
|
|
textString =
|
|||
|
|
"检测到您的密码为弱密码,请修改密码后重新登录。为了您的账户安全,请确保密码长度为 8-18 位,必须包含大小写字母+数字+特殊字符,例如:Aa@123456";
|
|||
|
|
break;
|
|||
|
|
case "4":
|
|||
|
|
textString =
|
|||
|
|
"检测到您30天内未修改密码,请修改密码后重新登录。为了您的账户安全,请确保密码长度为 8-18 位,必须包含大小写字母+数字+特殊字符,例如:Aa@123456";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
void dispose() {
|
|||
|
|
_oldPwdController.dispose();
|
|||
|
|
_newPwdController.dispose();
|
|||
|
|
_confirmPwdController.dispose();
|
|||
|
|
super.dispose();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 与登录页一致的输入框样式
|
|||
|
|
Widget _buildRoundedInput({
|
|||
|
|
required TextEditingController controller,
|
|||
|
|
required String hint,
|
|||
|
|
bool obscure = false,
|
|||
|
|
VoidCallback? toggleObscure,
|
|||
|
|
FormFieldValidator<String>? validator,
|
|||
|
|
}) {
|
|||
|
|
return TextFormField(
|
|||
|
|
controller: controller,
|
|||
|
|
obscureText: obscure,
|
|||
|
|
validator: validator,
|
|||
|
|
decoration: InputDecoration(
|
|||
|
|
hintText: hint,
|
|||
|
|
hintStyle: const TextStyle(color: Colors.grey),
|
|||
|
|
filled: true,
|
|||
|
|
fillColor: const Color(0xFFE2EBF4),
|
|||
|
|
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14),
|
|||
|
|
suffixIcon: toggleObscure == null
|
|||
|
|
? null
|
|||
|
|
: IconButton(
|
|||
|
|
icon: Icon(
|
|||
|
|
obscure ? Icons.visibility_off : Icons.visibility,
|
|||
|
|
color: Colors.grey,
|
|||
|
|
),
|
|||
|
|
onPressed: toggleObscure,
|
|||
|
|
),
|
|||
|
|
enabledBorder: OutlineInputBorder(
|
|||
|
|
borderRadius: BorderRadius.circular(30),
|
|||
|
|
borderSide: BorderSide.none,
|
|||
|
|
),
|
|||
|
|
focusedBorder: OutlineInputBorder(
|
|||
|
|
borderRadius: BorderRadius.circular(30),
|
|||
|
|
borderSide: BorderSide.none,
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
style: const TextStyle(color: Colors.black),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 密码复杂度校验
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void _handleSubmit() async {
|
|||
|
|
// 使用 Form 验证必填
|
|||
|
|
if (!(_formKey.currentState?.validate() ?? false)) return;
|
|||
|
|
|
|||
|
|
final oldPwd = _oldPwdController.text.trim();
|
|||
|
|
final newPwd = _newPwdController.text.trim();
|
|||
|
|
final confirmPwd = _confirmPwdController.text.trim();
|
|||
|
|
|
|||
|
|
if (newPwd != confirmPwd) {
|
|||
|
|
ToastUtil.showNormal(context, '新密码和确认密码两次输入的密码不一致');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (newPwd.length < 8) {
|
|||
|
|
ToastUtil.showNormal(context, '新密码需要大于8位');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (newPwd.length > 32) {
|
|||
|
|
ToastUtil.showNormal(context, '新密码需要小于32位');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!isPasswordValid(newPwd)) {
|
|||
|
|
ToastUtil.showNormal(context, '新密码必须包含大小写字母、数字和特殊符号。');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
await _changePass(oldPwd, newPwd, confirmPwd);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Future<void> _changePass(String oldPwd, String newPwd, String confirmPwd) async {
|
|||
|
|
try {
|
|||
|
|
passData['id'] = SessionService.instance.accountId ?? "";
|
|||
|
|
passData['password'] = oldPwd;
|
|||
|
|
passData['newPassword'] = newPwd;
|
|||
|
|
passData['confirmPassword'] = confirmPwd;
|
|||
|
|
|
|||
|
|
final raw = await AuthApi.changePassWord(passData);
|
|||
|
|
|
|||
|
|
if (raw['success'] == true) {
|
|||
|
|
ToastUtil.showNormal(context, '新密码修改成功!');
|
|||
|
|
Navigator.pop(context, true);
|
|||
|
|
|
|||
|
|
// 清除用户登录状态
|
|||
|
|
await _clearUserSession();
|
|||
|
|
|
|||
|
|
// 跳转到登录页并清除所有历史路由
|
|||
|
|
Navigator.pushAndRemoveUntil(
|
|||
|
|
context,
|
|||
|
|
MaterialPageRoute(builder: (context) => const LoginPage()),
|
|||
|
|
(Route<dynamic> route) => false,
|
|||
|
|
);
|
|||
|
|
} else if (raw['success'] == false) {
|
|||
|
|
ToastUtil.showNormal(context, '当前密码密码有误');
|
|||
|
|
} else {
|
|||
|
|
ToastUtil.showNormal(context, '登录错误!请联系管理员');
|
|||
|
|
}
|
|||
|
|
} catch (e) {
|
|||
|
|
print('修改密码出错:$e');
|
|||
|
|
ToastUtil.showNormal(context, '登录错误!请联系管理员');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Future<void> _clearUserSession() async {
|
|||
|
|
final prefs = await SharedPreferences.getInstance();
|
|||
|
|
await prefs.remove('isLoggedIn'); // 清除登录状态
|
|||
|
|
// 根据你项目的实际 key 再删除 token 等(如果有)
|
|||
|
|
// await prefs.remove('user_token');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Widget build(BuildContext context) {
|
|||
|
|
return Scaffold(
|
|||
|
|
backgroundColor: Colors.white,
|
|||
|
|
appBar: const MyAppbar(title: '修改密码'),
|
|||
|
|
body: SafeArea(
|
|||
|
|
child: Padding(
|
|||
|
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 20),
|
|||
|
|
child: Form(
|
|||
|
|
key: _formKey,
|
|||
|
|
child: Column(
|
|||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|||
|
|
children: [
|
|||
|
|
const Text(
|
|||
|
|
'修改密码',
|
|||
|
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
|||
|
|
),
|
|||
|
|
const SizedBox(height: 30),
|
|||
|
|
|
|||
|
|
// 当前密码
|
|||
|
|
_buildRoundedInput(
|
|||
|
|
controller: _oldPwdController,
|
|||
|
|
hint: '当前密码',
|
|||
|
|
obscure: _obscureOld,
|
|||
|
|
toggleObscure: () => setState(() => _obscureOld = !_obscureOld),
|
|||
|
|
validator: (v) {
|
|||
|
|
if (v == null || v.isEmpty) return '请输入当前密码';
|
|||
|
|
return null;
|
|||
|
|
},
|
|||
|
|
),
|
|||
|
|
const SizedBox(height: 20),
|
|||
|
|
|
|||
|
|
// 新密码
|
|||
|
|
_buildRoundedInput(
|
|||
|
|
controller: _newPwdController,
|
|||
|
|
hint: '新密码',
|
|||
|
|
obscure: _obscureNew,
|
|||
|
|
toggleObscure: () => setState(() => _obscureNew = !_obscureNew),
|
|||
|
|
validator: (v) {
|
|||
|
|
if (v == null || v.isEmpty) return '请输入新密码';
|
|||
|
|
return null;
|
|||
|
|
},
|
|||
|
|
),
|
|||
|
|
const SizedBox(height: 20),
|
|||
|
|
|
|||
|
|
// 确认新密码
|
|||
|
|
_buildRoundedInput(
|
|||
|
|
controller: _confirmPwdController,
|
|||
|
|
hint: '确认新密码',
|
|||
|
|
obscure: _obscureConfirm,
|
|||
|
|
toggleObscure: () => setState(() => _obscureConfirm = !_obscureConfirm),
|
|||
|
|
validator: (v) {
|
|||
|
|
if (v == null || v.isEmpty) return '请输入确认密码';
|
|||
|
|
return null;
|
|||
|
|
},
|
|||
|
|
),
|
|||
|
|
const SizedBox(height: 15),
|
|||
|
|
|
|||
|
|
Text(
|
|||
|
|
textString,
|
|||
|
|
style: const TextStyle(color: Colors.red, fontSize: 13),
|
|||
|
|
),
|
|||
|
|
const SizedBox(height: 30),
|
|||
|
|
|
|||
|
|
SizedBox(
|
|||
|
|
width: double.infinity,
|
|||
|
|
height: 45,
|
|||
|
|
child: CustomButton(
|
|||
|
|
onPressed: _handleSubmit,
|
|||
|
|
text: "提交",
|
|||
|
|
backgroundColor: Colors.blue,
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
],
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|