diff --git a/lib/main.dart b/lib/main.dart index efeb738..5c1a90d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,17 +1,26 @@ import 'package:cpnav/appbar.dart'; +import 'package:cpnav/pages/login/loginprefs.dart'; import 'package:cpnav/pages/pass_track/controller.dart'; import 'package:cpnav/pages/pass_track/bottomIcon/iconController.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:scence_map/controller.dart'; +import 'pages/login/login_page.dart'; +import 'pages/login/my_routes.dart'; import 'pages/pass_track/view.dart'; +import 'service/pile_cm.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); //设置全屏 Get.put(PassTrackController('WXLMB', 'cp_road')); Get.put(IconController()); + Get.put(LoginPageController()); + Get.put(AccountLoginController()); + Get.put(PhoneLoginController()); + LoginPrefs loginPrefs = LoginPrefs(); + loginPrefs.removeToken(); runApp(const MyApp()); } @@ -24,25 +33,12 @@ class MyApp extends StatelessWidget { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( - // This is the theme of your application. - // - // TRY THIS: Try running your application with "flutter run". You'll see - // the application has a purple toolbar. Then, without quitting the app, - // try changing the seedColor in the colorScheme below to Colors.green - // and then invoke "hot reload" (save your changes or press the "hot - // reload" button in a Flutter-supported IDE, or press "r" if you used - // the command line to start the app). - // - // Notice that the counter didn't reset back to zero; the application - // state is not lost during the reload. To reset the state, use hot - // restart instead. - // - // This works for code too, not just values: Most code changes can be - // tested with just a hot reload. colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), + initialRoute: "home", + onGenerateRoute: onGenerateRoute, ); } } diff --git a/lib/models/login.dart b/lib/models/login.dart deleted file mode 100644 index 6a33920..0000000 --- a/lib/models/login.dart +++ /dev/null @@ -1,75 +0,0 @@ -import 'package:get/get.dart'; -import 'package:get_storage/get_storage.dart'; - -import 'package:cpnav/models/user.dart'; - -class LoginPrefs extends GetxController { - static const String expireStr = "expire"; //用户名 - static const String tokenStr = "token"; //token - static const String phoneStr = "phone"; - final box = GetStorage(); // 实例化 GetStorage - - Future init() async { - await GetStorage.init(); // 初始化 GetStorage - return 'ok'; - } - - void saveExpire(int expire) { - box.write(expireStr, expire); - update(); - } - - int getExpire() { - return box.read(expireStr) ?? 0; - } - - void saveToken(String token) { - box.write(tokenStr, token); - update(); - } - - String getToken() { - return box.read(tokenStr) ?? ""; - } - - void removeExpire() { - box.remove(expireStr); - update(); - } - - void removeToken() { - box.remove(tokenStr); - update(); - } - - void savePhone(String phone) { - box.write(phoneStr, phone); - update(); - } - - String getPhone() { - return box.read(phoneStr) ?? ""; - } - - void clearLogin() { - box.erase(); // 清除所有数据 - update(); - } -} - -class UserController extends GetxController { - final box = GetStorage(); // 实例化 GetStorage - - UserModel? getUser() { - final userMap = box.read('user'); - if (userMap != null) { - return UserModel.fromJson(userMap); - } - return null; - } - - void setUser(Map user) { - box.write('user', user); - update(); - } -} diff --git a/lib/pages/login/login_page.dart b/lib/pages/login/login_page.dart index d54d404..417b55b 100644 --- a/lib/pages/login/login_page.dart +++ b/lib/pages/login/login_page.dart @@ -5,29 +5,86 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:cpnav/pages/login/loginprefs.dart'; import 'package:cpnav/service/base.dart'; +import 'package:get/get.dart'; -class Login extends StatefulWidget { - const Login({super.key}); +// class Login extends StatefulWidget { +// const Login({super.key}); + +// @override +// State createState() => _LoginState(); +// } + +// class _LoginState extends State with SingleTickerProviderStateMixin { +// //with SingleTickerProviderStateMixin 使this 不报错 +// late TabController _tabController; +// //初始化实例 +// @override +// void initState() { +// _tabController = TabController(length: 2, vsync: this); +// super.initState(); +// } + +// @override +// void dispose() { +// _tabController.dispose(); +// super.dispose(); +// } + +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// appBar: AppBar( +// title: const Text('欢迎登录'), +// ), +// body: Column( +// children: [ +// TabBar( +// labelColor: Colors.black, // 设置选中标签的字体颜色为黑色 +// unselectedLabelColor: Colors.grey, // 设置未选中标签的字体颜色为灰色 +// labelStyle: const TextStyle(color: Colors.black), // 设置选中标签的字体颜色为黑色 +// unselectedLabelStyle: +// const TextStyle(color: Colors.grey), // 设置未选中标签的字体颜色为灰色 +// controller: _tabController, +// tabs: const [ +// Tab(text: '手机号登录', icon: Icon(Icons.phone_android)), +// Tab(text: '账号登录', icon: Icon(Icons.account_box_outlined)), +// ], +// ), +// Expanded( +// child: TabBarView( +// controller: _tabController, +// children: const [ +// PhoneLoginPage(), +// AccountLoginPage(), +// ], +// ), +// ), +// ], +// ), +// ); +// } +// } +class LoginPageController extends GetxController + with SingleGetTickerProviderMixin { + late TabController _tabController; @override - State createState() => _LoginState(); + void onInit() { + super.onInit(); + _tabController = TabController(length: 2, vsync: this); + } + + @override + void onClose() { + _tabController.dispose(); + super.onClose(); + } + + TabController get tabController => _tabController; } -class _LoginState extends State with SingleTickerProviderStateMixin { - //with SingleTickerProviderStateMixin 使this 不报错 - late TabController _tabController; - //初始化实例 - @override - void initState() { - _tabController = TabController(length: 2, vsync: this); - super.initState(); - } - - @override - void dispose() { - _tabController.dispose(); - super.dispose(); - } +class Login extends GetView { + const Login({super.key}); @override Widget build(BuildContext context) { @@ -43,7 +100,7 @@ class _LoginState extends State with SingleTickerProviderStateMixin { labelStyle: const TextStyle(color: Colors.black), // 设置选中标签的字体颜色为黑色 unselectedLabelStyle: const TextStyle(color: Colors.grey), // 设置未选中标签的字体颜色为灰色 - controller: _tabController, + controller: controller.tabController, tabs: const [ Tab(text: '手机号登录', icon: Icon(Icons.phone_android)), Tab(text: '账号登录', icon: Icon(Icons.account_box_outlined)), @@ -51,7 +108,7 @@ class _LoginState extends State with SingleTickerProviderStateMixin { ), Expanded( child: TabBarView( - controller: _tabController, + controller: controller.tabController, children: const [ PhoneLoginPage(), AccountLoginPage(), @@ -64,48 +121,211 @@ class _LoginState extends State with SingleTickerProviderStateMixin { } } -class AccountLoginPage extends StatefulWidget { - const AccountLoginPage({super.key}); +// class AccountLoginPage extends StatefulWidget { +// const AccountLoginPage({super.key}); + +// @override +// State createState() => _AccountLoginPageState(); +// } + +// class _AccountLoginPageState extends State { +// //初始化FormState +// final _formKey = GlobalKey(); +// String username = ""; +// String password = ""; +// String verifyCode = ""; +// String svgString = ""; +// String captchaId = ""; +// @override +// void initState() { +// super.initState(); +// SchedulerBinding.instance.addPostFrameCallback((_) async { +// await changeCaptcha(); +// }); +// } + +// changeCaptcha() async { +// var captcha = await GetServices().getCaptcha(); +// setState(() { +// svgString = captcha['data']; +// captchaId = captcha['captchaId']; +// }); +// } + +// showErrorSnackbar(BuildContext context, String text) { +// final snackBar = SnackBar( +// content: Text(text), +// backgroundColor: Colors.red, +// ); + +// ScaffoldMessenger.of(context).showSnackBar(snackBar); +// } + +// LoginPrefs loginPrefs = LoginPrefs(); +// bool _obscureText = false; +// @override +// Widget build(BuildContext context) { +// return SingleChildScrollView( +// child: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// children: [ +// Form( +// key: _formKey, +// child: Column( +// children: [ +// // 账号输入框 +// TextFormField( +// decoration: const InputDecoration( +// labelText: '用户名:', +// ), +// onSaved: (String? value) => username = value!, +// validator: (String? value) { +// String str = ""; + +// RegExp regex = RegExp(r'^[a-zA-Z0-9]+$'); +// if (value!.isEmpty) { +// str = '用户名不能为空'; +// } else if (!regex.hasMatch(value)) { +// str = '请输入有效的账号'; +// } + +// return str == "" ? null : str; +// }, +// ), +// const SizedBox(height: 16.0), + +// // 密码输入框 +// TextFormField( +// decoration: InputDecoration( +// labelText: '密码:', +// suffixIcon: IconButton( +// icon: Icon( +// _obscureText +// ? Icons.visibility +// : Icons.visibility_off, +// ), +// onPressed: () { +// setState(() { +// _obscureText = !_obscureText; // 切换密码可见状态 +// }); +// }), +// ), +// obscureText: _obscureText, +// onSaved: (String? value) => password = value!, +// validator: (String? value) { +// String str = ""; +// RegExp regex = RegExp(r'^[a-zA-Z0-9@#$]+$'); + +// if (value!.isEmpty) { +// str = '密码不能为空'; +// } else if (!regex.hasMatch(value)) { +// str = '请输入有效的密码'; +// } + +// return str == "" ? null : str; +// }, +// ), +// const SizedBox(height: 24.0), +// Row( +// children: [ +// Expanded( +// child: TextFormField( +// decoration: const InputDecoration( +// labelText: '验证码:', +// ), +// keyboardType: TextInputType.phone, +// validator: (String? value) { +// String str = ""; + +// if (value!.isEmpty) { +// str = '验证码不能为空'; +// } + +// return str == "" ? null : str; +// }, +// onSaved: (String? value) => verifyCode = value!, +// ), +// ), +// ElevatedButton( +// onPressed: () async { +// changeCaptcha(); +// }, +// child: svgString.isNotEmpty +// ? SvgPicture.string( +// svgString, +// width: 70, // 设置宽度 +// height: 40, // 设置高度 +// color: Colors.black, +// ) +// : const Text("")) +// ], +// ), +// // 登录按钮 +// ElevatedButton( +// onPressed: () async { +// if (_formKey.currentState!.validate()) { +// _formKey.currentState!.save(); //必须 +// var res = await GetServices().getAccountLogin( +// captchaId, password, username, verifyCode); +// setState(() { +// if (res['code'] != 1000) { +// changeCaptcha(); +// showErrorSnackbar(context, res["message"]); +// } else { +// loginPrefs.saveExpire((res["data"]["expire"])); +// loginPrefs.saveToken((res["data"]["token"])); +// Navigator.pushNamed(context, 'home'); //跳转至首页 +// } +// }); +// } +// }, +// child: const Text('登录'), +// ), +// ], +// )) +// ], +// ), +// ), +// ); +// } +// } +class AccountLoginController extends GetxController { + final formKey = GlobalKey(); + final username = ''.obs; + final password = ''.obs; + final verifyCode = ''.obs; + final svgString = ''.obs; + final captchaId = ''.obs; + final obscureText = false.obs; @override - State createState() => _AccountLoginPageState(); -} - -class _AccountLoginPageState extends State { - //初始化FormState - final _formKey = GlobalKey(); - String username = ""; - String password = ""; - String verifyCode = ""; - String svgString = ""; - String captchaId = ""; - @override - void initState() { - super.initState(); - SchedulerBinding.instance.addPostFrameCallback((_) async { - await changeCaptcha(); - }); + void onInit() { + super.onInit(); + changeCaptcha(); } - changeCaptcha() async { + Future changeCaptcha() async { var captcha = await GetServices().getCaptcha(); - setState(() { - svgString = captcha['data']; - captchaId = captcha['captchaId']; - }); + svgString.value = captcha['data']; + captchaId.value = captcha['captchaId']; } - showErrorSnackbar(BuildContext context, String text) { + void showErrorSnackbar(String text) { final snackBar = SnackBar( content: Text(text), backgroundColor: Colors.red, ); - ScaffoldMessenger.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(Get.context!).showSnackBar(snackBar); } - LoginPrefs loginPrefs = LoginPrefs(); - bool _obscureText = false; + +} + +class AccountLoginPage extends GetView { + const AccountLoginPage({super.key}); + @override Widget build(BuildContext context) { return SingleChildScrollView( @@ -114,119 +334,124 @@ class _AccountLoginPageState extends State { child: Column( children: [ Form( - key: _formKey, - child: Column( - children: [ - // 账号输入框 - TextFormField( - decoration: const InputDecoration( - labelText: '用户名:', - ), - onSaved: (String? value) => username = value!, - validator: (String? value) { - String str = ""; - - RegExp regex = RegExp(r'^[a-zA-Z0-9]+$'); - if (value!.isEmpty) { - str = '用户名不能为空'; - } else if (!regex.hasMatch(value)) { - str = '请输入有效的账号'; - } - - return str == "" ? null : str; - }, + key: controller.formKey, + child: Column( + children: [ + // 账号输入框 + TextFormField( + decoration: const InputDecoration( + labelText: '用户名:', ), - const SizedBox(height: 16.0), + onSaved: (String? value) => + controller.username.value = value!, + validator: (String? value) { + String str = ""; - // 密码输入框 - TextFormField( - decoration: InputDecoration( - labelText: '密码:', - suffixIcon: IconButton( - icon: Icon( - _obscureText - ? Icons.visibility - : Icons.visibility_off, - ), - onPressed: () { - setState(() { - _obscureText = !_obscureText; // 切换密码可见状态 - }); - }), - ), - obscureText: _obscureText, - onSaved: (String? value) => password = value!, - validator: (String? value) { - String str = ""; - RegExp regex = RegExp(r'^[a-zA-Z0-9@#$]+$'); + RegExp regex = RegExp(r'^[a-zA-Z0-9]+$'); + if (value!.isEmpty) { + str = '用户名不能为空'; + } else if (!regex.hasMatch(value)) { + str = '请输入有效的账号'; + } - if (value!.isEmpty) { - str = '密码不能为空'; - } else if (!regex.hasMatch(value)) { - str = '请输入有效的密码'; - } + return str == "" ? null : str; + }, + ), + const SizedBox(height: 16.0), - return str == "" ? null : str; - }, - ), - const SizedBox(height: 24.0), - Row( - children: [ - Expanded( - child: TextFormField( - decoration: const InputDecoration( - labelText: '验证码:', - ), - keyboardType: TextInputType.phone, - validator: (String? value) { - String str = ""; - - if (value!.isEmpty) { - str = '验证码不能为空'; - } - - return str == "" ? null : str; - }, - onSaved: (String? value) => verifyCode = value!, - ), + // 密码输入框 + Obx(() => TextFormField( + decoration: InputDecoration( + labelText: '密码:', + suffixIcon: IconButton( + icon: Icon( + controller.obscureText.value + ? Icons.visibility + : Icons.visibility_off, + ), + onPressed: () { + controller.obscureText.toggle(); // 切换密码可见状态 + }), ), - ElevatedButton( - onPressed: () async { - changeCaptcha(); - }, - child: svgString.isNotEmpty - ? SvgPicture.string( - svgString, - width: 70, // 设置宽度 - height: 40, // 设置高度 - color: Colors.black, - ) - : const Text("")) - ], - ), - // 登录按钮 - ElevatedButton( - onPressed: () async { - if (_formKey.currentState!.validate()) { - _formKey.currentState!.save(); //必须 - var res = await GetServices().getAccountLogin( - captchaId, password, username, verifyCode); - setState(() { - if (res['code'] != 1000) { - changeCaptcha(); - showErrorSnackbar(context, res["message"]); - } else { - loginPrefs.saveExpire((res["data"]["expire"])); - loginPrefs.saveToken((res["data"]["token"])); - Navigator.pushNamed(context, 'home'); //跳转至首页 + obscureText: controller.obscureText.value, + onSaved: (String? value) => + controller.password.value = value!, + validator: (String? value) { + String str = ""; + RegExp regex = RegExp(r'^[a-zA-Z0-9@#$]+$'); + + if (value!.isEmpty) { + str = '密码不能为空'; + } else if (!regex.hasMatch(value)) { + str = '请输入有效的密码'; + } + + return str == "" ? null : str; + }, + )), + const SizedBox(height: 24.0), + Row( + children: [ + Expanded( + child: TextFormField( + decoration: const InputDecoration( + labelText: '验证码:', + ), + keyboardType: TextInputType.phone, + validator: (String? value) { + String str = ""; + + if (value!.isEmpty) { + str = '验证码不能为空'; } - }); + + return str == "" ? null : str; + }, + onSaved: (String? value) => + controller.verifyCode.value = value!, + ), + ), + ElevatedButton( + onPressed: () async { + controller.changeCaptcha(); + }, + child: Obx(() => controller.svgString.isNotEmpty + ? SvgPicture.string( + controller.svgString.value, + width: 70, // 设置宽度 + height: 40, // 设置高度 + color: Colors.black, + ) + : const Text(""))) + ], + ), + // 登录按钮 + + ElevatedButton( + onPressed: () async { + if (controller.formKey.currentState!.validate()) { + controller.formKey.currentState!.save(); //必须 + var res = await GetServices().getAccountLogin( + controller.captchaId.value, + controller.password.value, + controller.username.value, + controller.verifyCode.value); + + if (res['code'] != 1000) { + controller.changeCaptcha(); + controller.showErrorSnackbar(res["message"]); + } else { + loginPrefs.saveExpire((res["data"]["expire"])); + loginPrefs.saveToken((res["data"]["token"])); + Navigator.pushNamed(context, 'home'); //跳转至首页 } - }, - child: const Text('登录'), - ), - ], - )) + } + }, + child: const Text('登录'), + ) + ], + ), + ) ], ), ), @@ -234,156 +459,311 @@ class _AccountLoginPageState extends State { } } -class PhoneLoginPage extends StatefulWidget { - const PhoneLoginPage({super.key}); +// class PhoneLoginPage extends StatefulWidget { +// const PhoneLoginPage({super.key}); - @override - State createState() => _PhoneLoginPageState(); -} +// @override +// State createState() => _PhoneLoginPageState(); +// } -class _PhoneLoginPageState extends State { - String phoneNumber = ""; - String smsCode = ""; - bool issmsCode = false; - String smsText = "获取验证码"; - int _seconds = 60; - late Timer _timer; - //初始化FormState +// class _PhoneLoginPageState extends State { +// String phoneNumber = ""; +// String smsCode = ""; +// bool issmsCode = false; +// String smsText = "获取验证码"; +// int _seconds = 60; +// late Timer _timer; +// //初始化FormState +// final _formKey = GlobalKey(); +// LoginPrefs loginPrefs = LoginPrefs(); +// @override +// void initState() { +// super.initState(); + +// phoneNumber = loginPrefs.getPhone(); +// } + +// void startTimer() { +// _timer = Timer.periodic(const Duration(seconds: 1), (timer) { +// if (_seconds > 0) { +// _seconds -= 1; +// smsText = "重新获取(${_seconds}s)"; +// } else { +// _timer.cancel(); // 到0时关闭定时器 +// smsText = "获取验证码"; +// } +// }); +// } + +// showErrorSnackbar(BuildContext context, String text) { +// final snackBar = SnackBar( +// content: Text(text), +// backgroundColor: Colors.red, +// ); + +// ScaffoldMessenger.of(context).showSnackBar(snackBar); +// } + +// final GlobalKey _scaffoldKey = GlobalKey(); +// @override +// Widget build(BuildContext context) { +// return Container( +// key: _scaffoldKey, +// padding: const EdgeInsets.all(16.0), +// child: SingleChildScrollView( +// child: Column( +// children: [ +// Form( +// key: _formKey, +// child: +// // 手机号输入框 +// Column( +// children: [ +// TextFormField( +// maxLength: 11, +// initialValue: phoneNumber, +// decoration: const InputDecoration( +// labelText: '手机号', +// ), +// keyboardType: TextInputType.phone, +// validator: (String? value) { +// String str = ""; +// final RegExp phoneRegex = RegExp(r'^[1-9]\d{10}$'); +// if (value!.isEmpty) { +// str = '手机号不能为空'; +// } else if (!phoneRegex.hasMatch(value)) { +// str = '请输入有效的手机号'; +// } + +// return str == "" ? null : str; +// }, +// onSaved: (String? value) => phoneNumber = value!, +// ), +// Row( +// children: [ +// Expanded( +// child: TextFormField( +// maxLength: 6, +// decoration: const InputDecoration( +// labelText: '验证码', +// ), +// keyboardType: TextInputType.phone, +// validator: (String? value) { +// String str = ""; +// if (value!.isEmpty) { +// str = '验证码不能为空'; +// } + +// if (issmsCode) { +// return null; +// } +// return str == "" ? null : str; +// }, +// onSaved: (val) => smsCode = val!, +// ), +// ), +// // 获取验证码按钮 +// ElevatedButton( +// onPressed: () async { +// issmsCode = true; +// if (_formKey.currentState!.validate()) { +// _formKey.currentState!.save(); +// // 收回键盘 +// FocusScope.of(context).unfocus(); +// await GetServices().getsmsCode(phoneNumber); +// startTimer(); // 开始定时器 +// } +// }, +// child: Text(smsText), +// ), +// ], +// ), +// const SizedBox(height: 16.0), + +// // 登录按钮 +// ElevatedButton( +// onPressed: () async { +// issmsCode = false; +// if (_formKey.currentState!.validate()) { +// _formKey.currentState!.save(); +// // 表单校验通过,执行提交逻辑... +// // 收回键盘 +// FocusScope.of(context).unfocus(); +// var res = await GetServices() +// .phoneLogin(phoneNumber, smsCode); +// setState(() { +// if (res['code'] != 1000) { +// showErrorSnackbar( +// _scaffoldKey.currentContext!, res["message"]); +// } else { +// loginPrefs.savePhone(phoneNumber); +// loginPrefs.saveExpire(res["data"]["expire"]); +// loginPrefs.saveToken(res["data"]["token"]); +// Navigator.pushNamed( +// _scaffoldKey.currentContext!, 'home'); //跳转至首页 +// } +// }); +// } +// }, +// child: const Text('登录'), +// ), +// ], +// )), +// ], +// ), +// ), +// ); +// } +// } +class PhoneLoginController extends GetxController { final _formKey = GlobalKey(); - LoginPrefs loginPrefs = LoginPrefs(); - @override - void initState() { - super.initState(); + final phoneNumber = ''.obs; + final smsCode = ''.obs; + final issmsCode = false.obs; + final smsText = '获取验证码'.obs; + final _seconds = 60.obs; + late Timer _timer; - phoneNumber = loginPrefs.getPhone(); + @override + void onInit() { + super.onInit(); + phoneNumber.value = LoginPrefs().getPhone(); } void startTimer() { _timer = Timer.periodic(const Duration(seconds: 1), (timer) { - if (_seconds > 0) { - _seconds -= 1; - smsText = "重新获取(${_seconds}s)"; + if (_seconds.value > 0) { + _seconds.value -= 1; + smsText.value = "重新获取(${_seconds.value}s)"; } else { _timer.cancel(); // 到0时关闭定时器 - smsText = "获取验证码"; + smsText.value = "获取验证码"; } }); } - showErrorSnackbar(BuildContext context, String text) { + void showErrorSnackbar(String text) { final snackBar = SnackBar( content: Text(text), backgroundColor: Colors.red, ); - ScaffoldMessenger.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(Get.context!).showSnackBar(snackBar); } - final GlobalKey _scaffoldKey = GlobalKey(); + Future getSmsCode() async { + issmsCode.value = true; + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + // 收回键盘 + FocusScope.of(Get.context!).unfocus(); + await GetServices().getsmsCode(phoneNumber.value); + startTimer(); // 开始定时器 + } + } + + Future login() async { + issmsCode.value = false; + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + // 表单校验通过,执行提交逻辑... + // 收回键盘 + FocusScope.of(Get.context!).unfocus(); + var res = + await GetServices().phoneLogin(phoneNumber.value, smsCode.value); + if (res['code'] != 1000) { + showErrorSnackbar(res["message"]); + } else { + LoginPrefs().savePhone(phoneNumber.value); + LoginPrefs().saveExpire(res["data"]["expire"]); + LoginPrefs().saveToken(res["data"]["token"]); + Get.offNamed('home'); // 跳转至首页 + } + } + } +} + +class PhoneLoginPage extends GetView { + const PhoneLoginPage({super.key}); + @override Widget build(BuildContext context) { return Container( - key: _scaffoldKey, padding: const EdgeInsets.all(16.0), child: SingleChildScrollView( child: Column( children: [ Form( - key: _formKey, - child: - // 手机号输入框 - Column( - children: [ - TextFormField( - maxLength: 11, - initialValue: phoneNumber, - decoration: const InputDecoration( - labelText: '手机号', - ), - keyboardType: TextInputType.phone, - validator: (String? value) { - String str = ""; - final RegExp phoneRegex = RegExp(r'^[1-9]\d{10}$'); - if (value!.isEmpty) { - str = '手机号不能为空'; - } else if (!phoneRegex.hasMatch(value)) { - str = '请输入有效的手机号'; - } - - return str == "" ? null : str; - }, - onSaved: (String? value) => phoneNumber = value!, + key: controller._formKey, + child: Column( + children: [ + // 手机号输入框 + TextFormField( + maxLength: 11, + initialValue: controller.phoneNumber.value, + decoration: const InputDecoration( + labelText: '手机号', ), - Row( - children: [ - Expanded( - child: TextFormField( - maxLength: 6, - decoration: const InputDecoration( - labelText: '验证码', - ), - keyboardType: TextInputType.phone, - validator: (String? value) { - String str = ""; - if (value!.isEmpty) { - str = '验证码不能为空'; - } + keyboardType: TextInputType.phone, + validator: (String? value) { + String str = ""; + final RegExp phoneRegex = RegExp(r'^[1-9]\d{10}$'); + if (value!.isEmpty) { + str = '手机号不能为空'; + } else if (!phoneRegex.hasMatch(value)) { + str = '请输入有效的手机号'; + } - if (issmsCode) { - return null; - } - return str == "" ? null : str; - }, - onSaved: (val) => smsCode = val!, + return str == "" ? null : str; + }, + onSaved: (String? value) => + controller.phoneNumber.value = value!, + ), + Row( + children: [ + Expanded( + child: TextFormField( + maxLength: 6, + decoration: const InputDecoration( + labelText: '验证码', ), - ), - // 获取验证码按钮 - ElevatedButton( - onPressed: () async { - issmsCode = true; - if (_formKey.currentState!.validate()) { - _formKey.currentState!.save(); - // 收回键盘 - FocusScope.of(context).unfocus(); - await GetServices().getsmsCode(phoneNumber); - startTimer(); // 开始定时器 + keyboardType: TextInputType.phone, + validator: (String? value) { + String str = ""; + if (value!.isEmpty) { + str = '验证码不能为空'; } - }, - child: Text(smsText), - ), - ], - ), - const SizedBox(height: 16.0), - // 登录按钮 - ElevatedButton( - onPressed: () async { - issmsCode = false; - if (_formKey.currentState!.validate()) { - _formKey.currentState!.save(); - // 表单校验通过,执行提交逻辑... - // 收回键盘 - FocusScope.of(context).unfocus(); - var res = await GetServices() - .phoneLogin(phoneNumber, smsCode); - setState(() { - if (res['code'] != 1000) { - showErrorSnackbar( - _scaffoldKey.currentContext!, res["message"]); - } else { - loginPrefs.savePhone(phoneNumber); - loginPrefs.saveExpire(res["data"]["expire"]); - loginPrefs.saveToken(res["data"]["token"]); - Navigator.pushNamed( - _scaffoldKey.currentContext!, 'home'); //跳转至首页 + if (controller.issmsCode.value) { + return null; } - }); - } - }, - child: const Text('登录'), - ), - ], - )), + return str == "" ? null : str; + }, + onSaved: (String? value) => + controller.smsCode.value = value!, + ), + ), + // 获取验证码按钮 + ElevatedButton( + onPressed: () async { + controller.getSmsCode(); + }, + child: Obx(() => Text(controller.smsText.value)), + ), + ], + ), + const SizedBox(height: 16.0), + + // 登录按钮 + ElevatedButton( + onPressed: () async { + controller.login(); + }, + child: const Text('登录'), + ), + ], + ), + ), ], ), ), diff --git a/lib/pages/login/loginprefs.dart b/lib/pages/login/loginprefs.dart index 6a33920..6fc9090 100644 --- a/lib/pages/login/loginprefs.dart +++ b/lib/pages/login/loginprefs.dart @@ -1,7 +1,7 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; -import 'package:cpnav/models/user.dart'; +import 'package:cpnav/pages/login/user.dart'; class LoginPrefs extends GetxController { static const String expireStr = "expire"; //用户名 diff --git a/lib/pages/login/my_routes.dart b/lib/pages/login/my_routes.dart new file mode 100644 index 0000000..c9dc01e --- /dev/null +++ b/lib/pages/login/my_routes.dart @@ -0,0 +1,48 @@ +//配置路由 + +import 'package:flutter/material.dart'; + +import '../../main.dart'; +import 'login_page.dart'; +import 'loginprefs.dart'; + +/* + * 这个方法是固定写法,功能就像是一个拦截器。 + */ +Route? onGenerateRoute(RouteSettings settings) { + Map routes = { + 'home': MyHomePage(title: 'Flutter Demo Home Page'), //定义app路径 + 'login': const Login(), //定义login路径 + }; + + String routerName = routeBeforeHook(settings); + bool mathMap = false; + Route? mathWidget; + routes.forEach((key, v) { + if (key == routerName) { + mathMap = true; + mathWidget = MaterialPageRoute(builder: (BuildContext context) => v); + } + }); + + if (mathMap) { + return mathWidget; + } + return MaterialPageRoute( + builder: (BuildContext context) => const Text('404')); +} + +String routeBeforeHook(RouteSettings settings) { + if (checkToken() == false) { + return 'login'; + } else { + return settings.name!; + } +} + +bool checkToken() { + LoginPrefs loginPrefs = LoginPrefs(); + String token = loginPrefs.getToken(); + if ('' != token) return true; + return false; +} diff --git a/lib/models/user.dart b/lib/pages/login/user.dart similarity index 100% rename from lib/models/user.dart rename to lib/pages/login/user.dart diff --git a/lib/service/base.dart b/lib/service/base.dart index ed7c0f2..1176a50 100644 --- a/lib/service/base.dart +++ b/lib/service/base.dart @@ -2,7 +2,8 @@ import 'dart:convert'; import 'dart:io'; import 'package:http/http.dart' as http; import 'package:http/http.dart'; -import 'loginprefs.dart'; + +import '../pages/login/loginprefs.dart'; LoginPrefs loginPrefs = LoginPrefs(); diff --git a/lib/service/loginprefs.dart b/lib/service/loginprefs.dart deleted file mode 100644 index 6516904..0000000 --- a/lib/service/loginprefs.dart +++ /dev/null @@ -1,74 +0,0 @@ -import 'package:get_storage/get_storage.dart'; - -import 'package:cpnav/models/user.dart'; - -class LoginPrefs { - static const String expireStr = "expire"; //用户名 - static const String tokenStr = "token"; //token - static const String phoneStr = "phone"; - final box = GetStorage(); // 实例化 GetStorage - - Future init() async { - await GetStorage.init(); // 初始化 GetStorage - return 'ok'; - } - - void saveExpire(int expire) { - box.write(expireStr, expire); - // update(); - } - - int getExpire() { - return box.read(expireStr) ?? 0; - } - - void saveToken(String token) { - box.write(tokenStr, token); - // update(); - } - - String getToken() { - return box.read(tokenStr) ?? ""; - } - - void removeExpire() { - box.remove(expireStr); - // update(); - } - - void removeToken() { - box.remove(tokenStr); - // update(); - } - - void savePhone(String phone) { - box.write(phoneStr, phone); - // update(); - } - - String getPhone() { - return box.read(phoneStr) ?? ""; - } - - void clearLogin() { - box.erase(); // 清除所有数据 - // update(); - } -} - -class UserController { - final box = GetStorage(); // 实例化 GetStorage - - UserModel? getUser() { - final userMap = box.read('user'); - if (userMap != null) { - return UserModel.fromJson(userMap); - } - return null; - } - - void setUser(Map user) { - box.write('user', user); - // update(); - } -} diff --git a/lib/service/user/loginprefs.dart b/lib/service/user/loginprefs.dart deleted file mode 100644 index 6a33920..0000000 --- a/lib/service/user/loginprefs.dart +++ /dev/null @@ -1,75 +0,0 @@ -import 'package:get/get.dart'; -import 'package:get_storage/get_storage.dart'; - -import 'package:cpnav/models/user.dart'; - -class LoginPrefs extends GetxController { - static const String expireStr = "expire"; //用户名 - static const String tokenStr = "token"; //token - static const String phoneStr = "phone"; - final box = GetStorage(); // 实例化 GetStorage - - Future init() async { - await GetStorage.init(); // 初始化 GetStorage - return 'ok'; - } - - void saveExpire(int expire) { - box.write(expireStr, expire); - update(); - } - - int getExpire() { - return box.read(expireStr) ?? 0; - } - - void saveToken(String token) { - box.write(tokenStr, token); - update(); - } - - String getToken() { - return box.read(tokenStr) ?? ""; - } - - void removeExpire() { - box.remove(expireStr); - update(); - } - - void removeToken() { - box.remove(tokenStr); - update(); - } - - void savePhone(String phone) { - box.write(phoneStr, phone); - update(); - } - - String getPhone() { - return box.read(phoneStr) ?? ""; - } - - void clearLogin() { - box.erase(); // 清除所有数据 - update(); - } -} - -class UserController extends GetxController { - final box = GetStorage(); // 实例化 GetStorage - - UserModel? getUser() { - final userMap = box.read('user'); - if (userMap != null) { - return UserModel.fromJson(userMap); - } - return null; - } - - void setUser(Map user) { - box.write('user', user); - update(); - } -}