智慧水务管理系统 - 精河县供水工程综合管理平台

login_page.dart 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import 'package:flutter/material.dart';
  2. import 'package:provider/provider.dart';
  3. import '../services/auth_provider.dart';
  4. /// 登录页面
  5. class LoginPage extends StatefulWidget {
  6. const LoginPage({super.key});
  7. @override
  8. State<LoginPage> createState() => _LoginPageState();
  9. }
  10. class _LoginPageState extends State<LoginPage> {
  11. final _formKey = GlobalKey<FormState>();
  12. final _usernameController = TextEditingController();
  13. final _passwordController = TextEditingController();
  14. bool _obscurePassword = true;
  15. @override
  16. void dispose() {
  17. _usernameController.dispose();
  18. _passwordController.dispose();
  19. super.dispose();
  20. }
  21. Future<void> _handleLogin() async {
  22. if (!_formKey.currentState!.validate()) return;
  23. final authProvider = Provider.of<AuthProvider>(context, listen: false);
  24. final success = await authProvider.login(
  25. username: _usernameController.text.trim(),
  26. password: _passwordController.text,
  27. );
  28. if (success && mounted) {
  29. // 登录成功后路由由 AuthGuard 自动处理
  30. Navigator.of(context).pushReplacementNamed('/main');
  31. } else if (mounted) {
  32. ScaffoldMessenger.of(context).showSnackBar(
  33. SnackBar(
  34. content: Text(authProvider.errorMessage ?? '登录失败'),
  35. backgroundColor: Colors.red,
  36. ),
  37. );
  38. }
  39. }
  40. @override
  41. Widget build(BuildContext context) {
  42. return Scaffold(
  43. body: SafeArea(
  44. child: Center(
  45. child: SingleChildScrollView(
  46. padding: const EdgeInsets.all(32),
  47. child: Form(
  48. key: _formKey,
  49. child: Column(
  50. mainAxisAlignment: MainAxisAlignment.center,
  51. crossAxisAlignment: CrossAxisAlignment.stretch,
  52. children: [
  53. // Logo 和应用名
  54. const Icon(
  55. Icons.water_drop,
  56. size: 80,
  57. color: Color(0xFF1976D2),
  58. ),
  59. const SizedBox(height: 16),
  60. const Text(
  61. '供水管理系统',
  62. textAlign: TextAlign.center,
  63. style: TextStyle(
  64. fontSize: 24,
  65. fontWeight: FontWeight.bold,
  66. color: Color(0xFF1976D2),
  67. ),
  68. ),
  69. const SizedBox(height: 8),
  70. Text(
  71. '供水 · 巡检 · 营收',
  72. textAlign: TextAlign.center,
  73. style: TextStyle(
  74. fontSize: 14,
  75. color: Colors.grey[600],
  76. ),
  77. ),
  78. const SizedBox(height: 48),
  79. // 用户名输入
  80. TextFormField(
  81. controller: _usernameController,
  82. decoration: const InputDecoration(
  83. labelText: '用户名',
  84. prefixIcon: Icon(Icons.person),
  85. hintText: '请输入用户名',
  86. ),
  87. validator: (value) {
  88. if (value == null || value.trim().isEmpty) {
  89. return '请输入用户名';
  90. }
  91. return null;
  92. },
  93. ),
  94. const SizedBox(height: 16),
  95. // 密码输入
  96. TextFormField(
  97. controller: _passwordController,
  98. decoration: InputDecoration(
  99. labelText: '密码',
  100. prefixIcon: const Icon(Icons.lock),
  101. hintText: '请输入密码',
  102. suffixIcon: IconButton(
  103. icon: Icon(
  104. _obscurePassword ? Icons.visibility_off : Icons.visibility,
  105. ),
  106. onPressed: () {
  107. setState(() {
  108. _obscurePassword = !_obscurePassword;
  109. });
  110. },
  111. ),
  112. ),
  113. obscureText: _obscurePassword,
  114. validator: (value) {
  115. if (value == null || value.isEmpty) {
  116. return '请输入密码';
  117. }
  118. if (value.length < 6) {
  119. return '密码长度不能少于6位';
  120. }
  121. return null;
  122. },
  123. ),
  124. const SizedBox(height: 32),
  125. // 登录按钮
  126. Consumer<AuthProvider>(
  127. builder: (context, auth, child) {
  128. return ElevatedButton(
  129. onPressed: auth.isLoading ? null : _handleLogin,
  130. child: auth.isLoading
  131. ? const SizedBox(
  132. height: 20,
  133. width: 20,
  134. child: CircularProgressIndicator(
  135. strokeWidth: 2,
  136. color: Colors.white,
  137. ),
  138. )
  139. : const Text(
  140. '登 录',
  141. style: TextStyle(fontSize: 16),
  142. ),
  143. );
  144. },
  145. ),
  146. const SizedBox(height: 16),
  147. // 版本信息
  148. Text(
  149. 'v1.0.0',
  150. textAlign: TextAlign.center,
  151. style: TextStyle(color: Colors.grey[400], fontSize: 12),
  152. ),
  153. ],
  154. ),
  155. ),
  156. ),
  157. ),
  158. ),
  159. );
  160. }
  161. }