login_page.dart 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. import 'package:dio/dio.dart';
  2. import 'package:flutter/foundation.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
  5. import 'package:lszlgl/base/base_lifecycle_state.dart';
  6. import 'package:lszlgl/main.dart';
  7. import 'package:lszlgl/model/req/login_req.dart';
  8. import 'package:lszlgl/network/my_api.dart';
  9. import 'package:lszlgl/service/dict_service.dart';
  10. import 'package:lszlgl/service/upgrade_service.dart';
  11. import 'package:lszlgl/service/user_service.dart';
  12. import 'package:lszlgl/widget/button.dart';
  13. import '../../config/reresh_config.dart';
  14. import '../../network/base_dio.dart';
  15. import '../../utils/location_utils.dart';
  16. import '../../utils/sp_utils.dart';
  17. import 'package:lszlgl/service/print_service.dart';
  18. /// 登录页面
  19. class LoginPage extends StatefulWidget {
  20. const LoginPage({Key? key}) : super(key: key);
  21. @override
  22. State<LoginPage> createState() => _LoginPageState();
  23. }
  24. class _LoginPageState extends BaseLifecycleState<LoginPage> {
  25. late TextEditingController accountCtrl;
  26. late TextEditingController pwdCtrl;
  27. late ValueNotifier<bool> _showPwd;
  28. void onLogin() async {
  29. var account = accountCtrl.text;
  30. var pwd = pwdCtrl.text;
  31. if (account.isEmpty || pwd.isEmpty) {
  32. MyNavigator.showToast('请输入账号和密码');
  33. return;
  34. }
  35. MyNavigator.showLoading();
  36. try {
  37. // 登录
  38. var login = await MyApi.get().login(LoginReq(username: account, password: pwd));
  39. if (login.data == null) {
  40. MyNavigator.showToast('获取数据失败');
  41. MyNavigator.dismissLoading();
  42. return;
  43. }
  44. await UserService.get().saveLogin(login.data);
  45. getSystemData();
  46. } on DioException catch (_) {
  47. } catch (e) {
  48. logger.e(e);
  49. MyNavigator.showToast('获取数据失败');
  50. }
  51. MyNavigator.dismissLoading();
  52. }
  53. /// 获取基础数据
  54. void getSystemData() async {
  55. MyNavigator.showLoading(clickDismiss: false);
  56. try {
  57. // 获取用户数据
  58. var user = await MyApi.get().userProfile();
  59. await UserService.get().saveUser(user.data);
  60. // 获取字典
  61. var dictData = await MyApi.get().getAllDict();
  62. DictService.saveDictList(dictData.data);
  63. UpgradeService.checkUpgrade(false);
  64. // 进入主页
  65. MyNavigator.dismissLoading();
  66. startHome();
  67. } on DioException catch (_) {
  68. } on Exception catch (a, _) {
  69. logger.e('$a');
  70. MyNavigator.showToast('获取数据失败');
  71. }
  72. MyNavigator.dismissLoading();
  73. }
  74. /// 进入主页
  75. void startHome() {
  76. var login = UserService.get().getLogin()!;
  77. if (login.defaultPassword ?? false) {
  78. MyNavigator.showToast('密码强度过低,请修改密码');
  79. // 修改密码
  80. MyRouter.startChangePwd(startHome: true);
  81. } else {
  82. // 进入主页
  83. MyRouter.startMain(popAll: true);
  84. }
  85. }
  86. @override
  87. void onInit() {
  88. accountCtrl = TextEditingController();
  89. pwdCtrl = TextEditingController();
  90. _showPwd = ValueNotifier<bool>(true);
  91. }
  92. @override
  93. void onFirstShow(Duration timeStamp) async {
  94. // MyNavigator.showLoading();
  95. /// 初始化基础库 start
  96. BaseDio.get().init();
  97. await SPUtils.getInstance().init();
  98. RefreshConfig.get().initDefault();
  99. LocationUtils.updatePrivacyShow(true, true);
  100. LocationUtils.updatePrivacyAgree(true);
  101. LocationUtils.setApiKey(
  102. kReleaseMode ? '2c783509376e267b24d63b21681686fa' : '7d0c033909f84adc14a0e60a835f044f', '');
  103. /// 获取手机设备信息
  104. PrintService.getDeviceInfo();
  105. /// 同步数据库里的蓝牙设备信息到服务器
  106. database.savaBleDataToServer();
  107. /// 初始化基础库 end
  108. MyNavigator.dismissLoading();
  109. // 已登录
  110. if (UserService.get().getLogin() != null) {
  111. getSystemData();
  112. }
  113. }
  114. @override
  115. void onDestroy() {
  116. accountCtrl.dispose();
  117. pwdCtrl.dispose();
  118. }
  119. @override
  120. Widget build(BuildContext context) {
  121. return Scaffold(
  122. backgroundColor: const Color(0xFF49AAF2),
  123. body: KeyboardDismissOnTap(
  124. child: SingleChildScrollView(
  125. physics: const BouncingScrollPhysics(),
  126. child: Stack(
  127. children: [
  128. Positioned.fill(child: Image.asset(imgLoginBg, fit: BoxFit.fill)),
  129. SizedBox(
  130. height: MediaQuery.of(context).size.height,
  131. child: buildBody(),
  132. ),
  133. ],
  134. ),
  135. ),
  136. ),
  137. );
  138. }
  139. Widget buildBody() {
  140. return Column(
  141. children: [
  142. const Spacer(flex: 3),
  143. Container(
  144. width: double.infinity,
  145. padding: const EdgeInsets.symmetric(horizontal: 48),
  146. child: Image.asset(imgLoginTitle, fit: BoxFit.fill),
  147. ),
  148. const Spacer(),
  149. loginContainer(),
  150. const Spacer(flex: 7),
  151. ],
  152. );
  153. }
  154. Widget loginContainer() {
  155. return SizedBox(
  156. width: double.infinity,
  157. child: Stack(
  158. alignment: Alignment.topCenter,
  159. children: [
  160. buildInputContent(),
  161. userTitle(),
  162. ],
  163. ),
  164. );
  165. }
  166. Widget userTitle() {
  167. return Row(
  168. children: [
  169. const Spacer(),
  170. Expanded(
  171. child: Container(
  172. padding: const EdgeInsets.symmetric(vertical: 12),
  173. alignment: Alignment.center,
  174. decoration: const BoxDecoration(
  175. color: Colors.white,
  176. borderRadius: BorderRadius.all(Radius.circular(100)),
  177. border: Border.fromBorderSide(BorderSide(color: Color(0xFF49AAF2), width: 1)),
  178. boxShadow: [BoxShadow(color: Color(0x941C90FF), offset: Offset(0, 2))],
  179. ),
  180. child: const Text(
  181. '用户登录',
  182. style: TextStyle(color: Color(0xFF1187DE), fontSize: 14),
  183. ),
  184. ),
  185. ),
  186. const Spacer(),
  187. ],
  188. );
  189. }
  190. Widget buildInputContent() {
  191. return Container(
  192. margin: const EdgeInsets.only(top: 18, left: 16, right: 16),
  193. padding: const EdgeInsets.all(6),
  194. decoration: BoxDecoration(
  195. color: Colors.white.withOpacity(0.2),
  196. borderRadius: const BorderRadius.all(Radius.circular(36)),
  197. ),
  198. child: Container(
  199. padding: const EdgeInsets.symmetric(horizontal: 24),
  200. alignment: Alignment.center,
  201. decoration: const BoxDecoration(
  202. color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(32))),
  203. child: Column(
  204. children: [
  205. const SizedBox(height: 56),
  206. buildEdit(
  207. ctrl: accountCtrl,
  208. hint: '请输入登录账号',
  209. icon: imgLoginAccount,
  210. action: TextInputAction.next,
  211. ),
  212. const SizedBox(height: 32),
  213. ValueListenableBuilder(
  214. valueListenable: _showPwd,
  215. builder: (BuildContext ctx, bool show, Widget? child) {
  216. return buildEdit(
  217. ctrl: pwdCtrl,
  218. hint: '请输入登录密码',
  219. icon: imgLoginPwd,
  220. obscure: show,
  221. onSubmit: (value) => onLogin(),
  222. rightIcon: child,
  223. );
  224. },
  225. child: IconButton(
  226. icon: const Icon(Icons.remove_red_eye_outlined, size: 16, color: Color(0xFFBBBBBB)),
  227. onPressed: () {
  228. _showPwd.value = !_showPwd.value;
  229. },
  230. )),
  231. const SizedBox(height: 44),
  232. buildLoginBtn(),
  233. SizedBox(
  234. width: double.infinity,
  235. child: TextButton(
  236. onPressed: () {
  237. MyRouter.forgetPwd();
  238. },
  239. style: const ButtonStyle(alignment: Alignment.centerRight),
  240. child: const Text('忘记密码', style: TextStyle(color: Color(0xFF25A6EE), fontSize: 14))),
  241. ),
  242. const SizedBox(height: 18),
  243. ],
  244. ),
  245. ),
  246. );
  247. }
  248. Widget buildEdit({
  249. required TextEditingController ctrl,
  250. required String hint,
  251. String? icon,
  252. TextInputAction action = TextInputAction.done,
  253. bool obscure = false,
  254. ValueChanged? onSubmit,
  255. Widget? rightIcon,
  256. }) {
  257. return TextField(
  258. controller: ctrl,
  259. decoration: InputDecoration(
  260. prefixIcon: icon == null
  261. ? null
  262. : Padding(
  263. padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
  264. child: Image.asset(icon, height: 18),
  265. ),
  266. prefixIconConstraints: const BoxConstraints(),
  267. border: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(100))),
  268. enabledBorder: const OutlineInputBorder(
  269. borderSide: BorderSide(color: Color(0xFFE6E6E6), width: 1),
  270. borderRadius: BorderRadius.all(Radius.circular(100)),
  271. ),
  272. hintText: hint,
  273. hintStyle: const TextStyle(color: Color(0xFFBBBBBB)),
  274. isDense: true,
  275. contentPadding: EdgeInsets.zero,
  276. suffixIcon: rightIcon,
  277. ),
  278. style: const TextStyle(fontSize: 14),
  279. textInputAction: action,
  280. obscureText: obscure,
  281. onSubmitted: onSubmit,
  282. );
  283. }
  284. Widget buildLoginBtn() {
  285. return MyButton(
  286. '登录',
  287. onTap: onLogin,
  288. gradient: const LinearGradient(colors: [Color(0xFF60B5F4), Color(0xFF62A4D6)]),
  289. );
  290. }
  291. }