|
|
|
// lib/modules/auth/views/login_page.dart
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
|
|
import 'package:get/get.dart';
|
|
|
|
import 'package:problem_check_system/modules/auth/controllers/auth_controller.dart';
|
|
|
|
|
|
|
|
class LoginPage extends GetView<AuthController> {
|
|
|
|
const LoginPage({super.key});
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Scaffold(
|
|
|
|
body: Stack(children: [_buildBackground(), _buildLoginCard(controller)]),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildBackground() {
|
|
|
|
return Stack(
|
|
|
|
children: [
|
|
|
|
Container(
|
|
|
|
decoration: const BoxDecoration(
|
|
|
|
image: DecorationImage(
|
|
|
|
image: AssetImage('assets/images/background.png'),
|
|
|
|
fit: BoxFit.fitWidth,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Positioned(
|
|
|
|
left: 28.5.w,
|
|
|
|
top: 89.5.h,
|
|
|
|
child: Image.asset(
|
|
|
|
'assets/images/label.png',
|
|
|
|
width: 171.5.w,
|
|
|
|
height: 23.5.h,
|
|
|
|
fit: BoxFit.fitWidth,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Positioned(
|
|
|
|
left: 28.5.w,
|
|
|
|
top: 128.5.h,
|
|
|
|
child: Image.asset(
|
|
|
|
'assets/images/label1.png',
|
|
|
|
width: 296.5.w,
|
|
|
|
height: 35.5.h,
|
|
|
|
fit: BoxFit.fitWidth,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 修改 _buildLoginCard 方法,它不再需要传入 TextEditingController
|
|
|
|
Widget _buildLoginCard(AuthController controller) {
|
|
|
|
return Positioned(
|
|
|
|
left: 20.5.w,
|
|
|
|
top: 220.5.h,
|
|
|
|
child: Container(
|
|
|
|
width: 334.w,
|
|
|
|
height: 574.5.h,
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
color: const Color(0xFFFFFFFF).withOpacity(0.6),
|
|
|
|
borderRadius: BorderRadius.all(Radius.circular(23.5.r)),
|
|
|
|
),
|
|
|
|
padding: EdgeInsets.all(24.w),
|
|
|
|
child: Column(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
// 直接使用控制器中的 TextEditingController
|
|
|
|
_buildTextFieldSection(
|
|
|
|
label: '账号',
|
|
|
|
hintText: '请输入您的账号',
|
|
|
|
controller: controller.usernameController,
|
|
|
|
),
|
|
|
|
const SizedBox(height: 22),
|
|
|
|
_buildTextFieldSection(
|
|
|
|
label: '密码',
|
|
|
|
hintText: '请输入您的密码',
|
|
|
|
obscureText: true,
|
|
|
|
controller: controller.passwordController,
|
|
|
|
),
|
|
|
|
const SizedBox(height: 9.5),
|
|
|
|
_buildRememberPasswordRow(controller),
|
|
|
|
const SizedBox(height: 138.5),
|
|
|
|
_buildLoginButton(controller),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 修改 _buildTextFieldSection,不再需要 onChanged 回调
|
|
|
|
Widget _buildTextFieldSection({
|
|
|
|
required String label,
|
|
|
|
required String hintText,
|
|
|
|
required TextEditingController controller,
|
|
|
|
bool obscureText = false,
|
|
|
|
}) {
|
|
|
|
return Column(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
Text(
|
|
|
|
label,
|
|
|
|
style: TextStyle(fontSize: 16.5.sp, color: Colors.black),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 10.5),
|
|
|
|
TextField(
|
|
|
|
controller: controller, // 使用传入的控制器
|
|
|
|
obscureText: obscureText,
|
|
|
|
style: const TextStyle(color: Colors.black),
|
|
|
|
decoration: InputDecoration(
|
|
|
|
hintText: hintText,
|
|
|
|
hintStyle: const TextStyle(color: Colors.grey),
|
|
|
|
border: const OutlineInputBorder(),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildRememberPasswordRow(AuthController controller) {
|
|
|
|
return Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
|
|
children: [
|
|
|
|
Obx(
|
|
|
|
() => Checkbox(
|
|
|
|
value: controller.rememberPassword.value,
|
|
|
|
onChanged: (value) => controller.rememberPassword.value = value!,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Text(
|
|
|
|
'记住密码',
|
|
|
|
style: TextStyle(color: const Color(0xFF959595), fontSize: 14.sp),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildLoginButton(AuthController controller) {
|
|
|
|
return SizedBox(
|
|
|
|
width: double.infinity,
|
|
|
|
child: ElevatedButton(
|
|
|
|
onPressed: controller.login,
|
|
|
|
style: ElevatedButton.styleFrom(
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
backgroundColor: Colors.transparent,
|
|
|
|
shadowColor: Colors.transparent,
|
|
|
|
shape: RoundedRectangleBorder(
|
|
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
|
|
),
|
|
|
|
minimumSize: Size(double.infinity, 48.h),
|
|
|
|
),
|
|
|
|
child: Ink(
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
gradient: const LinearGradient(
|
|
|
|
colors: [Color(0xFF418CFC), Color(0xFF3DBFFC)],
|
|
|
|
begin: Alignment.centerLeft,
|
|
|
|
end: Alignment.centerRight,
|
|
|
|
),
|
|
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
|
|
),
|
|
|
|
child: Container(
|
|
|
|
constraints: BoxConstraints(minHeight: 48.h),
|
|
|
|
alignment: Alignment.center,
|
|
|
|
padding: EdgeInsets.symmetric(vertical: 12.h, horizontal: 24.w),
|
|
|
|
child: Obx(() {
|
|
|
|
if (controller.isLoading.value) {
|
|
|
|
return const CircularProgressIndicator(
|
|
|
|
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return Text(
|
|
|
|
'登录',
|
|
|
|
style: TextStyle(
|
|
|
|
color: Colors.white,
|
|
|
|
fontSize: 16.sp,
|
|
|
|
fontWeight: FontWeight.w500,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|