import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import '../../../shared/services/cache_service.dart'; import '../services/auth_provider.dart'; /// 登录页面 /// /// 支持表单校验、密码可见切换、记住用户名(通过 CacheService 持久化)、加载态。 class LoginPage extends StatefulWidget { const LoginPage({super.key}); @override State createState() => _LoginPageState(); } class _LoginPageState extends State { static const String _kRememberKey = 'login:remember_username'; final _formKey = GlobalKey(); final _usernameController = TextEditingController(); final _passwordController = TextEditingController(); final _cache = CacheService(); bool _obscurePassword = true; bool _rememberUsername = true; bool _restored = false; @override void initState() { super.initState(); _restoreRememberedUsername(); } /// 从本地缓存恢复上次记住的用户名 Future _restoreRememberedUsername() async { final saved = await _cache.get(_kRememberKey, box: 'auth'); if (saved != null && saved.isNotEmpty && mounted) { setState(() { _usernameController.text = saved; _restored = true; }); } } /// 持久化/清除记住的用户名 Future _persistRememberedUsername(String username) async { if (_rememberUsername) { await _cache.put(_kRememberKey, username, box: 'auth'); } else { await _cache.delete(_kRememberKey, box: 'auth'); } } @override void dispose() { _usernameController.dispose(); _passwordController.dispose(); super.dispose(); } Future _handleLogin() async { if (!_formKey.currentState!.validate()) return; final username = _usernameController.text.trim(); final authProvider = Provider.of(context, listen: false); final success = await authProvider.login( username: username, password: _passwordController.text, ); if (success && mounted) { // 登录成功:按勾选状态持久化用户名 await _persistRememberedUsername(username); // 登录成功后路由由 AuthGuard 自动处理 GoRouter.of(context).go('/main'); } else if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(authProvider.errorMessage ?? '登录失败'), backgroundColor: Colors.red, ), ); } } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.all(32), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Logo 和应用名 const Icon( Icons.water_drop, size: 80, color: Color(0xFF1976D2), ), const SizedBox(height: 16), const Text( '供水管理系统', textAlign: TextAlign.center, style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xFF1976D2), ), ), const SizedBox(height: 8), Text( '供水 · 巡检 · 营收', textAlign: TextAlign.center, style: TextStyle( fontSize: 14, color: Colors.grey[600], ), ), const SizedBox(height: 48), // 用户名输入 TextFormField( controller: _usernameController, decoration: const InputDecoration( labelText: '用户名', prefixIcon: Icon(Icons.person), hintText: '请输入用户名', ), validator: (value) { if (value == null || value.trim().isEmpty) { return '请输入用户名'; } return null; }, ), const SizedBox(height: 16), // 密码输入 TextFormField( controller: _passwordController, decoration: InputDecoration( labelText: '密码', prefixIcon: const Icon(Icons.lock), hintText: '请输入密码', suffixIcon: IconButton( icon: Icon( _obscurePassword ? Icons.visibility_off : Icons.visibility, ), onPressed: () { setState(() { _obscurePassword = !_obscurePassword; }); }, ), ), obscureText: _obscurePassword, validator: (value) { if (value == null || value.isEmpty) { return '请输入密码'; } if (value.length < 6) { return '密码长度不能少于6位'; } return null; }, ), const SizedBox(height: 12), // 记住用户名 Row( children: [ Checkbox( value: _rememberUsername, onChanged: (v) => setState(() => _rememberUsername = v ?? false), ), const Text('记住用户名'), ], ), const SizedBox(height: 20), // 登录按钮 Consumer( builder: (context, auth, child) { return ElevatedButton( onPressed: auth.isLoading ? null : _handleLogin, child: auth.isLoading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white, ), ) : const Text( '登 录', style: TextStyle(fontSize: 16), ), ); }, ), const SizedBox(height: 16), // 版本信息 Text( 'v1.0.0', textAlign: TextAlign.center, style: TextStyle(color: Colors.grey[400], fontSize: 12), ), ], ), ), ), ), ), ); } }