2025-12-12 09:11:30 +08:00
|
|
|
|
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';
|
2026-08-10 14:01:43 +08:00
|
|
|
|
import 'package:qhd_prevention/services/auth_service.dart';
|
|
|
|
|
|
import 'package:qhd_prevention/services/password_policy.dart';
|
2026-02-28 14:38:07 +08:00
|
|
|
|
import 'package:qhd_prevention/tools/tools.dart';
|
2025-12-12 09:11:30 +08:00
|
|
|
|
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 =
|
2026-08-10 14:01:43 +08:00
|
|
|
|
"为了您的账户安全,请确保密码长度为 8-16 位,必须包含大小写字母、数字和特殊字符(!#@*&),例如:Aa@12345";
|
2025-12-12 09:11:30 +08:00
|
|
|
|
|
2026-08-10 14:01:43 +08:00
|
|
|
|
Map<String, dynamic> passData = {"id": '', "password": "", "newPassword": ""};
|
2025-12-12 09:11:30 +08:00
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
void initState() {
|
|
|
|
|
|
super.initState();
|
|
|
|
|
|
switch (widget.type) {
|
|
|
|
|
|
case "0":
|
2026-08-10 14:01:43 +08:00
|
|
|
|
textString = "密码长度8-16位,且必须包含大小写字母、数字和特殊符号(!#@*&)";
|
2025-12-12 09:11:30 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "1":
|
|
|
|
|
|
textString =
|
2026-08-10 14:01:43 +08:00
|
|
|
|
"检测到您的密码为弱密码,请修改密码后重新登录。密码长度为8-16位,且必须包含大小写字母、数字和特殊符号(!#@*&)。";
|
2025-12-12 09:11:30 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "2":
|
|
|
|
|
|
textString =
|
2026-08-10 14:01:43 +08:00
|
|
|
|
"检测到您30天内未修改密码,请修改密码后重新登录。密码长度为8-16位,且必须包含大小写字母、数字和特殊符号(!#@*&)。";
|
2025-12-12 09:11:30 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "3":
|
|
|
|
|
|
textString =
|
2026-08-10 14:01:43 +08:00
|
|
|
|
"检测到您的密码为弱密码,请修改密码后重新登录。密码长度为8-16位,且必须包含大小写字母、数字和特殊符号(!#@*&)。";
|
2025-12-12 09:11:30 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "4":
|
|
|
|
|
|
textString =
|
2026-08-10 14:01:43 +08:00
|
|
|
|
"检测到您30天内未修改密码,请修改密码后重新登录。密码长度为8-16位,且必须包含大小写字母、数字和特殊符号(!#@*&)。";
|
2025-12-12 09:11:30 +08:00
|
|
|
|
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),
|
2026-08-10 14:01:43 +08:00
|
|
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
|
|
|
|
horizontal: 20,
|
|
|
|
|
|
vertical: 14,
|
2025-12-12 09:11:30 +08:00
|
|
|
|
),
|
2026-08-10 14:01:43 +08:00
|
|
|
|
suffixIcon:
|
|
|
|
|
|
toggleObscure == null
|
|
|
|
|
|
? null
|
|
|
|
|
|
: IconButton(
|
|
|
|
|
|
icon: Icon(
|
|
|
|
|
|
obscure ? Icons.visibility_off : Icons.visibility,
|
|
|
|
|
|
color: Colors.grey,
|
|
|
|
|
|
),
|
|
|
|
|
|
onPressed: toggleObscure,
|
|
|
|
|
|
),
|
2025-12-12 09:11:30 +08:00
|
|
|
|
enabledBorder: OutlineInputBorder(
|
|
|
|
|
|
borderRadius: BorderRadius.circular(30),
|
|
|
|
|
|
borderSide: BorderSide.none,
|
|
|
|
|
|
),
|
|
|
|
|
|
focusedBorder: OutlineInputBorder(
|
|
|
|
|
|
borderRadius: BorderRadius.circular(30),
|
|
|
|
|
|
borderSide: BorderSide.none,
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
style: const TextStyle(color: Colors.black),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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();
|
2026-02-28 14:38:07 +08:00
|
|
|
|
// if (oldPwd == newPwd) {
|
|
|
|
|
|
// ToastUtil.showNormal(context, '新密码不能喝旧密码相同');
|
|
|
|
|
|
// return;
|
|
|
|
|
|
// }
|
2025-12-12 09:11:30 +08:00
|
|
|
|
if (newPwd != confirmPwd) {
|
|
|
|
|
|
ToastUtil.showNormal(context, '新密码和确认密码两次输入的密码不一致');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:01:43 +08:00
|
|
|
|
final passwordError = PasswordPolicy.validate(newPwd);
|
|
|
|
|
|
if (passwordError != null) {
|
|
|
|
|
|
ToastUtil.showNormal(context, passwordError);
|
2025-12-12 09:11:30 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
await _changePass(oldPwd, newPwd, confirmPwd);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:01:43 +08:00
|
|
|
|
Future<void> _changePass(
|
|
|
|
|
|
String oldPwd,
|
|
|
|
|
|
String newPwd,
|
|
|
|
|
|
String confirmPwd,
|
|
|
|
|
|
) async {
|
2026-02-28 14:38:07 +08:00
|
|
|
|
LoadingDialogHelper.show();
|
2025-12-12 09:11:30 +08:00
|
|
|
|
try {
|
|
|
|
|
|
passData['id'] = SessionService.instance.accountId ?? "";
|
|
|
|
|
|
passData['password'] = oldPwd;
|
|
|
|
|
|
passData['newPassword'] = newPwd;
|
2026-08-10 14:01:43 +08:00
|
|
|
|
passData['confirmPassword'] = newPwd;
|
2025-12-12 09:11:30 +08:00
|
|
|
|
|
|
|
|
|
|
final raw = await AuthApi.changePassWord(passData);
|
2026-08-10 14:01:43 +08:00
|
|
|
|
LoadingDialogHelper.hide();
|
2025-12-12 09:11:30 +08:00
|
|
|
|
if (raw['success'] == true) {
|
|
|
|
|
|
ToastUtil.showNormal(context, '新密码修改成功!');
|
2026-08-10 14:01:43 +08:00
|
|
|
|
await AuthService.logout();
|
2025-12-12 09:11:30 +08:00
|
|
|
|
|
|
|
|
|
|
// 跳转到登录页并清除所有历史路由
|
|
|
|
|
|
Navigator.pushAndRemoveUntil(
|
|
|
|
|
|
context,
|
|
|
|
|
|
MaterialPageRoute(builder: (context) => const LoginPage()),
|
2026-08-10 14:01:43 +08:00
|
|
|
|
(Route<dynamic> route) => false,
|
2025-12-12 09:11:30 +08:00
|
|
|
|
);
|
|
|
|
|
|
} else {
|
2026-01-14 09:55:23 +08:00
|
|
|
|
ToastUtil.showNormal(context, raw['errMessage'] ?? '请求失败,请重试');
|
2025-12-12 09:11:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
} catch (e) {
|
2026-08-10 14:01:43 +08:00
|
|
|
|
LoadingDialogHelper.hide();
|
2025-12-12 09:11:30 +08:00
|
|
|
|
print('修改密码出错:$e');
|
2026-01-14 09:55:23 +08:00
|
|
|
|
ToastUtil.showNormal(context, '请求失败,请重试');
|
2025-12-12 09:11:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@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,
|
2026-08-10 14:01:43 +08:00
|
|
|
|
toggleObscure:
|
|
|
|
|
|
() => setState(() => _obscureOld = !_obscureOld),
|
2025-12-12 09:11:30 +08:00
|
|
|
|
validator: (v) {
|
|
|
|
|
|
if (v == null || v.isEmpty) return '请输入当前密码';
|
|
|
|
|
|
return null;
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
|
|
|
|
|
|
|
|
// 新密码
|
|
|
|
|
|
_buildRoundedInput(
|
|
|
|
|
|
controller: _newPwdController,
|
|
|
|
|
|
hint: '新密码',
|
|
|
|
|
|
obscure: _obscureNew,
|
2026-08-10 14:01:43 +08:00
|
|
|
|
toggleObscure:
|
|
|
|
|
|
() => setState(() => _obscureNew = !_obscureNew),
|
2025-12-12 09:11:30 +08:00
|
|
|
|
validator: (v) {
|
|
|
|
|
|
if (v == null || v.isEmpty) return '请输入新密码';
|
|
|
|
|
|
return null;
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
|
|
|
|
|
|
|
|
// 确认新密码
|
|
|
|
|
|
_buildRoundedInput(
|
|
|
|
|
|
controller: _confirmPwdController,
|
|
|
|
|
|
hint: '确认新密码',
|
|
|
|
|
|
obscure: _obscureConfirm,
|
2026-08-10 14:01:43 +08:00
|
|
|
|
toggleObscure:
|
|
|
|
|
|
() => setState(() => _obscureConfirm = !_obscureConfirm),
|
2025-12-12 09:11:30 +08:00
|
|
|
|
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,
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|