|
|
@@ -0,0 +1,208 @@
|
|
|
+import 'package:chicken_farm/core/utils/logger.dart';
|
|
|
+import 'package:flutter/material.dart';
|
|
|
+import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
+import 'package:go_router/go_router.dart';
|
|
|
+import 'package:chicken_farm/core/utils/toast.dart';
|
|
|
+import 'package:chicken_farm/modes/auth/login_model.dart';
|
|
|
+import 'package:chicken_farm/routes/app_routes.dart';
|
|
|
+import 'package:chicken_farm/stores/auth_store.dart';
|
|
|
+import 'package:chicken_farm/widgets/config_dialog.dart';
|
|
|
+
|
|
|
+class LoginPage extends ConsumerStatefulWidget {
|
|
|
+ const LoginPage({super.key});
|
|
|
+
|
|
|
+ @override
|
|
|
+ ConsumerState<LoginPage> createState() => _LoginPageState();
|
|
|
+}
|
|
|
+
|
|
|
+class _LoginPageState extends ConsumerState<LoginPage> {
|
|
|
+ final _formKey = GlobalKey<FormState>();
|
|
|
+ final _usernameCtrl = TextEditingController(text: 'admin');
|
|
|
+ final _passwordCtrl = TextEditingController(text: '123iwb');
|
|
|
+
|
|
|
+ @override
|
|
|
+ void dispose() {
|
|
|
+ _usernameCtrl.dispose();
|
|
|
+ _passwordCtrl.dispose();
|
|
|
+ super.dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final authState = ref.watch(authStoreProvider);
|
|
|
+ final authStore = ref.read(authStoreProvider.notifier);
|
|
|
+
|
|
|
+ // 监听认证状态变化,如果已认证则跳转到主页
|
|
|
+ WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
+ if (authState.state == AuthState.authenticated && context.mounted) {
|
|
|
+ context.goNamed(AppRoutePaths.home);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ ref.listen<AuthInfo>(authStoreProvider, (previous, next) {
|
|
|
+ if (next.state == AuthState.authenticated) {
|
|
|
+ // 登录成功,跳转到主页
|
|
|
+ if (context.mounted) {
|
|
|
+ context.goNamed(AppRoutePaths.home);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return Scaffold(
|
|
|
+ appBar: AppBar(
|
|
|
+ title: const Text('用户登录'),
|
|
|
+ backgroundColor: Theme.of(context).colorScheme.primary,
|
|
|
+ foregroundColor: Colors.white,
|
|
|
+ ),
|
|
|
+ body: Stack(
|
|
|
+ children: [
|
|
|
+ Container(
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ gradient: LinearGradient(
|
|
|
+ begin: Alignment.topCenter,
|
|
|
+ end: Alignment.bottomCenter,
|
|
|
+ colors: [
|
|
|
+ Theme.of(context).colorScheme.primary.withValues(alpha: 0.1),
|
|
|
+ Theme.of(context).colorScheme.surface,
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: Center(
|
|
|
+ child: SingleChildScrollView(
|
|
|
+ padding: const EdgeInsets.all(24.0),
|
|
|
+ child: Card(
|
|
|
+ elevation: 8,
|
|
|
+ shape: RoundedRectangleBorder(
|
|
|
+ borderRadius: BorderRadius.circular(16),
|
|
|
+ ),
|
|
|
+ child: Padding(
|
|
|
+ padding: const EdgeInsets.all(24.0),
|
|
|
+ child: Form(
|
|
|
+ key: _formKey,
|
|
|
+ child: Column(
|
|
|
+ mainAxisSize: MainAxisSize.min,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ '养殖场管理系统',
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 24,
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ color: Theme.of(context).colorScheme.primary,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 24),
|
|
|
+ TextFormField(
|
|
|
+ controller: _usernameCtrl,
|
|
|
+ decoration: InputDecoration(
|
|
|
+ labelText: '用户名',
|
|
|
+ prefixIcon: const Icon(Icons.person),
|
|
|
+ border: OutlineInputBorder(
|
|
|
+ borderRadius: BorderRadius.circular(12),
|
|
|
+ ),
|
|
|
+ filled: true,
|
|
|
+ fillColor: Colors.grey[50],
|
|
|
+ ),
|
|
|
+ validator: (v) => v!.isEmpty ? '请输入用户名' : null,
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 16),
|
|
|
+ TextFormField(
|
|
|
+ controller: _passwordCtrl,
|
|
|
+ obscureText: true,
|
|
|
+ decoration: InputDecoration(
|
|
|
+ labelText: '密码',
|
|
|
+ prefixIcon: const Icon(Icons.lock),
|
|
|
+ border: OutlineInputBorder(
|
|
|
+ borderRadius: BorderRadius.circular(12),
|
|
|
+ ),
|
|
|
+ filled: true,
|
|
|
+ fillColor: Colors.grey[50],
|
|
|
+ ),
|
|
|
+ validator: (v) => v!.length < 6 ? '密码不能少于6位' : null,
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 24),
|
|
|
+ SizedBox(
|
|
|
+ width: double.infinity,
|
|
|
+ height: 50,
|
|
|
+ child: ElevatedButton(
|
|
|
+ onPressed: authState.state == AuthState.loading
|
|
|
+ ? null
|
|
|
+ : () {
|
|
|
+ if (_formKey.currentState!.validate()) {
|
|
|
+ authStore
|
|
|
+ .login(
|
|
|
+ LoginModel(
|
|
|
+ username: _usernameCtrl.text,
|
|
|
+ password: _passwordCtrl.text,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .then((_) async {
|
|
|
+ // 登录成功后跳转到主页
|
|
|
+ if (context.mounted) {
|
|
|
+ logger.d('登录成功');
|
|
|
+ context.goNamed(
|
|
|
+ AppRoutePaths.home,
|
|
|
+ );
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catchError((error) {
|
|
|
+ // 处理登录错误
|
|
|
+ logger.e('登录失败: $error');
|
|
|
+ if (context.mounted) {
|
|
|
+ String errorMessage = '登录失败';
|
|
|
+ if (error is Exception) {
|
|
|
+ errorMessage = error.toString();
|
|
|
+ }
|
|
|
+ ToastUtils.error(errorMessage);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ style: ElevatedButton.styleFrom(
|
|
|
+ shape: RoundedRectangleBorder(
|
|
|
+ borderRadius: BorderRadius.circular(12),
|
|
|
+ ),
|
|
|
+ textStyle: const TextStyle(fontSize: 16),
|
|
|
+ ),
|
|
|
+ child: authState.state == AuthState.loading
|
|
|
+ ? const CircularProgressIndicator(
|
|
|
+ color: Colors.white,
|
|
|
+ )
|
|
|
+ : const Text('登录'),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Positioned(
|
|
|
+ bottom: 16,
|
|
|
+ right: 16,
|
|
|
+ child: IconButton(
|
|
|
+ icon: const Icon(Icons.settings),
|
|
|
+ onPressed: () async {
|
|
|
+ final result = await showDialog(
|
|
|
+ context: context,
|
|
|
+ builder: (context) => const ConfigDialog(),
|
|
|
+ );
|
|
|
+ // 如果配置发生了变化,显示提示
|
|
|
+ if (result == true && context.mounted) {
|
|
|
+ // ScaffoldMessenger.of(context).showSnackBar(
|
|
|
+ // const SnackBar(
|
|
|
+ // content: Text('配置已保存'),
|
|
|
+ // duration: Duration(seconds: 2),
|
|
|
+ // ),
|
|
|
+ // );
|
|
|
+ ToastUtils.success('配置已保存');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|