/* * @Author: wangyang 1147192855@qq.com * @Date: 2022-07-06 10:37:36 * @LastEditors: wangyang 1147192855@qq.com * @LastEditTime: 2022-09-26 17:24:33 * @FilePath: \marking_app\lib\pages\login\index.dart * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; import 'package:dio/adapter.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:marking_app/common/config/request_config.dart'; import 'package:marking_app/common/mixin/common.dart'; import 'package:marking_app/utils/const_text.dart'; import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/my_text.dart'; import 'package:marking_app/utils/request/rest_client.dart'; import 'package:marking_app/common/model/common/base_structure_result.dart'; import 'package:marking_app/common/model/user/user_info.dart'; import 'package:marking_app/common/model/user/user_login.dart'; import 'package:marking_app/common/model/user/user_login_params.dart'; import 'package:marking_app/provider/user_provider.dart'; import 'package:marking_app/routes/RouterManager.dart'; import 'package:marking_app/utils/sys_protocol.dart'; class TheLogin extends StatefulHookConsumerWidget { const TheLogin({Key? key}) : super(key: key); @override _TheLoginState createState() => _TheLoginState(); } class _TheLoginState extends ConsumerState with CommonMixin { late Dio dio; late RestClient client; //添加证书 setHttpsPEM() async { (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) { client.badCertificateCallback = (X509Certificate cert, String host, int port) { return true; }; }; } //文本输入框控制器 late final TextEditingController _userNameController; late final TextEditingController _passwordController; late final FocusNode _pwdFocus; // 密码 late final FocusNode _theFocus; bool keepPwd = false; // 记住密码 bool readAgreement = false; // 阅读协议 bool canLogin = true; bool hasNameVal = false; bool _isShowPwd = true; bool showRegister = false; void _showPassword() { setState(() { _isShowPwd = !_isShowPwd; }); } @override void initState() { Future.delayed(Duration(seconds: 1), () => sysProtocol(context)); Future(() { // 延迟更新 Provider ref.read(userTokenProvider.notifier).clean(); // 进入登录页先清空信息 }); getShowRegister(); super.initState(); dio = Dio( BaseOptions( contentType: "application/json", connectTimeout: 8000, receiveTimeout: 8000, ), ); dio.interceptors.add(LogInterceptor(responseBody: true, requestBody: true)); //添加日志 setHttpsPEM(); client = RestClient(dio, baseUrl: RequestConfig().loginBaseUrl); _userNameController = TextEditingController()..addListener(userNameListener); _passwordController = TextEditingController(); _pwdFocus = FocusNode(); _theFocus = FocusNode(); FastData.getInstance().getUserPwd().then((value) { if (value == null || value == '') return; Map valMap = json.decode(value); setState(() { _passwordController.text = valMap['pwd']; _userNameController.text = valMap['account']; keepPwd = true; }); }); } void getShowRegister() async { RestClient client = await getClientLogin(); BaseStructureResult resultData = await client.showRegister(); if (resultData.success) { setState(() { showRegister = resultData.data; }); } } void userNameListener() { String userName = _userNameController.text; int useNameLength = userName.length; bool hasNameValNew = useNameLength > 0; if (hasNameValNew != hasNameVal) toUpState(setState, () => hasNameVal = hasNameValNew, mounted); const isProd = bool.fromEnvironment('dart.vm.product'); if (!isProd && useNameLength == 11) { _passwordController.text = userName.substring(useNameLength - 6); } } @override void dispose() { super.dispose(); _userNameController ..removeListener(userNameListener) ..dispose(); _passwordController.dispose(); _pwdFocus.dispose(); _theFocus.dispose(); } @override Widget build(BuildContext context) { return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { FocusScope.of(context).requestFocus(_theFocus); }, child: AnnotatedRegion( value: const SystemUiOverlayStyle( statusBarColor: Colors.transparent, systemNavigationBarIconBrightness: Brightness.light, statusBarIconBrightness: Brightness.light, statusBarBrightness: Brightness.dark, ), child: Scaffold( backgroundColor: Colors.transparent, resizeToAvoidBottomInset: false, body: Container( width: double.infinity, height: double.infinity, alignment: Alignment.center, decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/login_bgi.png'), fit: BoxFit.fill, // 完全填充 ), ), child: SingleChildScrollView( child: Column( children: [ Container( width: 86.w, height: 86.w, alignment: Alignment.center, child: SizedBox( height: 86.w, width: 86.w, child: Image.asset('assets/images/logo.png', fit: BoxFit.cover), ), ), Container( margin: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.h), padding: EdgeInsets.only(top: 34.h, bottom: 16.h, left: 22.w, right: 22.w), decoration: BoxDecoration( color: Colors.white, border: Border.all(width: 1.w, color: Colors.white), borderRadius: BorderRadius.all(Radius.circular(10.w)), boxShadow: const [ BoxShadow( color: Color.fromRGBO(46, 91, 255, 0.1), offset: Offset.zero, //阴影y轴偏移量 blurRadius: 100, //阴影模糊程度 spreadRadius: 100, //阴影扩散程度 ) ], ), child: Column(children: [ TextField( controller: _userNameController, maxLines: 1, maxLength: 20, textInputAction: TextInputAction.next, onEditingComplete: () { FocusScope.of(context).requestFocus(_pwdFocus); }, style: TextStyle( color: const Color.fromRGBO(80, 87, 103, 1), fontSize: 15.sp, ), decoration: InputDecoration( hintText: "请输入账号", hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)), labelText: "账号", labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), suffixIcon: !hasNameVal ? null : Transform.translate( offset: Offset(10, 10), // 根据原始组件的padding值来设置偏移量 child: IconButton( alignment: Alignment.center, padding: EdgeInsets.zero, icon: Icon( Icons.highlight_off_sharp, color: Colors.grey, size: 16.r, ), onPressed: () { _userNameController.clear(); // 清空文本框内容 _passwordController.clear(); }, ), ), ), ), TextField( focusNode: _pwdFocus, controller: _passwordController, keyboardType: TextInputType.number, maxLines: 1, obscureText: _isShowPwd, //隐藏密码显示 textInputAction: TextInputAction.go, onSubmitted: (val) => toLogin(), style: TextStyle( color: const Color.fromRGBO(80, 87, 103, 1), fontSize: 15.sp, ), decoration: InputDecoration( hintText: "请输入密码", suffix: GestureDetector( onTap: _showPassword, child: Icon( Icons.remove_red_eye, color: !_isShowPwd ? Theme.of(context).primaryColor : Colors.grey, ), ), hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)), labelText: "密码", isDense: true, labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), ), ), SizedBox( height: 12.h, ), Row( children: [ Container( width: 30.w, padding: EdgeInsets.only(right: 10.w), child: Checkbox( activeColor: Theme.of(context).primaryColor, checkColor: Colors.white, value: keepPwd, onChanged: (value) { FocusScope.of(context).requestFocus(_pwdFocus); FocusScope.of(context).requestFocus(_theFocus); setState(() { keepPwd = value ?? false; }); }, ), ), InkWell( onTap: () { FocusScope.of(context).requestFocus(_pwdFocus); FocusScope.of(context).requestFocus(_theFocus); setState(() => keepPwd = !keepPwd); }, child: Text( '记住密码', style: TextStyle( fontSize: 14.sp, color: const Color.fromRGBO(148, 163, 182, 1), ), ), ), Spacer(), if (showRegister == true) InkWell( onTap: () { RouterManager.router.navigateTo(context, RouterManager.registerPath); }, child: Text( '注册', style: TextStyle(fontSize: 14.sp, color: const Color.fromRGBO(148, 163, 182, 1)), )), ], ), InkWell( onTap: () => easyThrottle('TO_GO_LOGOIN', toLogin), child: Container( margin: EdgeInsets.symmetric(vertical: 10.h), decoration: BoxDecoration( color: canLogin ? const Color.fromRGBO(9, 105, 246, 1) : Colors.grey, boxShadow: [ BoxShadow( color: const Color.fromRGBO(46, 91, 255, 0.5), offset: Offset(6.w, 10.h), //阴影y轴偏移量 blurRadius: 14, //阴影模糊程度 spreadRadius: 0.5, //阴影扩散程度 ) ], borderRadius: BorderRadius.all( Radius.circular(8.w), ), ), alignment: Alignment.center, width: double.infinity, height: 50.h, child: Text( '登 录', style: TextStyle(fontSize: 16.sp, color: Colors.white), ), ), ), Row( children: [ Container( width: 30.w, padding: EdgeInsets.only(right: 10.w), child: Checkbox( activeColor: Colors.deepOrangeAccent, checkColor: Colors.white, value: readAgreement, onChanged: (value) { FocusScope.of(context).requestFocus(_pwdFocus); FocusScope.of(context).requestFocus(_theFocus); setState(() { readAgreement = value ?? false; }); }, ), ), InkWell( onTap: () { RouterManager.router.navigateTo( context, '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.USER_AGREEMENT.name}', transition: getTransition(), ); }, child: quickText('我已阅读', size: 11.sp), ), InkWell( onTap: () { RouterManager.router.navigateTo( context, '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.USER_AGREEMENT.name}', transition: getTransition(), ); }, child: quickText( '《用户协议》', size: 12.sp, color: Colors.deepOrangeAccent, ), ), quickText('和', size: 10.sp), InkWell( onTap: () { RouterManager.router.navigateTo( context, '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.PRIVACY_GREEMENT.name}', transition: getTransition(), ); }, child: quickText( '《隐私协议》', size: 12.sp, color: Colors.deepOrangeAccent, ), ), ], ), ]), ) ], ), )), ), ), ); } // 前往登录 void toLogin() async { if (!canLogin) return; setState(() => canLogin = false); void toMsg(msg) { ToastUtils.showError(msg); setState(() => canLogin = true); } try { FocusScope.of(context).requestFocus(_theFocus); if (!readAgreement) { var resFlag = await showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return CupertinoAlertDialog( title: quickText('用户协议及隐私协议', size: 14.sp, color: Color.fromARGB(255, 53, 52, 52)), content: SingleChildScrollView( padding: EdgeInsets.only(top: 4.h), child: RichText( text: TextSpan( text: '为了更好地保障您的合法权益,请您阅读并同意以下协议', style: TextStyle(color: Color.fromARGB(255, 137, 138, 139), fontSize: 11.sp), children: [ TextSpan(text: '《用户协议》《隐式协议》', style: TextStyle(color: Colors.deepOrangeAccent, fontSize: 13.sp)), ], ), ), ), actions: [ CupertinoDialogAction( child: Text("取消", style: TextStyle(color: Color.fromARGB(255, 58, 58, 58))), onPressed: () => Navigator.of(context).pop(false), ), CupertinoDialogAction( child: Text("确定"), onPressed: () => Navigator.of(context).pop(true), ), ], ); }, ); if (!resFlag!) return; setState(() => readAgreement = true); } String userName = _userNameController.text.trim(); String userPwd = _passwordController.text.trim(); if (userName == '') return toMsg('请填写用户账号'); if (userPwd == '') return toMsg('请填写密码再试'); if (!readAgreement) return toMsg('请勾选我已阅读用户协议和隐私协议'); String userPwdMd5 = CommonUtils.generateMD5(userPwd); print('userPwdMd5=$userPwdMd5'); EasyLoading.show(status: 'loading...'); BaseStructureResult resultData = await client.toLogin(UserLoginParams(userName, userPwdMd5)); UserLogin? userData = resultData.code == 200 && resultData.data != null ? UserLogin.fromJson(resultData.data) : null; if (resultData.code != 200 || userData?.accessToken == null || userData?.accessToken == '') { return toMsg(resultData.message ?? '登录失败,请重试'); } FastData fastData = FastData.getInstance(); fastData.setToken(userData!.accessToken); BaseStructureResult userRes = await client.getUserInfo('Bearer ${userData.accessToken}'); if (userRes.code != 200 || userRes.data == null) { throw Exception('登录失败,请重试'); } fastData.setUser(userRes.data!).then((value) { // 记住密码 if (keepPwd) { fastData.setUserPwdAndAccount({'pwd': userPwd, 'account': userName}); } // 更新 ref.read(userProvider.notifier).initUserInfo(); ref.read(userTokenProvider.notifier).initToken(); // 跳转登录页 RouterManager.router.navigateTo(context, RouterManager.root, clearStack: true, transition: getTransition()); }); } catch (e) { toPrint(val: e.toString()); String? msg; if (e is DioError) { DioErrorType errorType = e.type; switch (errorType) { case DioErrorType.connectTimeout: msg = '连接超时,请检查网络再重试'; break; case DioErrorType.sendTimeout: msg = '发送时间超时,请重试'; break; case DioErrorType.receiveTimeout: msg = '接收数据超时,请重试'; break; case DioErrorType.response: // TODO: Handle this case. break; case DioErrorType.cancel: // TODO: Handle this case. break; case DioErrorType.other: // TODO: Handle this case. break; } } FastData.getInstance().cleanShared(); return toMsg(msg ?? '登录失败,请重试'); } finally { EasyLoading.dismiss(); setState(() => canLogin = true); } } }