diff --git a/lib/components/commonFun.dart b/lib/components/commonFun.dart index 52d891d..9ffe344 100644 --- a/lib/components/commonFun.dart +++ b/lib/components/commonFun.dart @@ -3,6 +3,7 @@ import 'dart:developer' as developer; import 'dart:io'; import 'dart:math'; +import 'package:ai_save_account/ai_save_account.dart'; import 'package:camera/camera.dart'; import 'package:convert/convert.dart'; import 'package:crypto/crypto.dart' as crypto; @@ -221,6 +222,7 @@ int faceLogin = -1; //1 成功,0 失败,-1 处理中 int faceRegUserID = -1; //人脸注册时所需用户ID,-1 非法 List cameras; +List g_users = new List(); //历史账号 UserInfo g_userInfo = UserInfo(mapUserInfoRet: { "ret": 200, "data": { diff --git a/lib/pages/Login/LoginByName3.dart b/lib/pages/Login/LoginByName3.dart new file mode 100644 index 0000000..b33b126 --- /dev/null +++ b/lib/pages/Login/LoginByName3.dart @@ -0,0 +1,503 @@ +import 'dart:convert'; + +import 'package:ai_save_account/ai_save_account.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:hyzp_ybqx/pages/Works/TJXX/tj_data.dart'; + +import '../../components/EncryptUtil.dart'; +import '../../components/commonFun.dart'; +import '../../config/service_url.dart'; +import '../../services/EventBus.dart'; +import '../../services/Storage.dart'; +import '../../widget/JdText.dart'; + +class LoginByName3 extends StatefulWidget { + LoginByName3({Key key, this.height}) : super(key: key); + double height; + + _LoginPageState createState() => _LoginPageState(); +} + +class _LoginPageState extends State { + //try_setState(); //避免如下异常报错 + try_setState() { + try { + setState(() {}); + } catch (e) { + print('setState(() {})异常:${e}'); + } + } + + //监听登录页面销毁的事件 + dispose() { + super.dispose(); + eventBus.fire(new UserEvent('登录成功...')); + } + + bool bRemmberPW = false; + + GlobalKey _globalKey = new GlobalKey(); //用来标记控件 + bool _can_expand_ListView = false; //是否能够打开历史账号 + // List g_users = new List(); //历史账号 + + @override + void initState() { + super.initState(); + // g_userInfo.username = 'the_user_03'; + // g_userInfo.password = '123456'; + // g_userInfo.password = 'ybhb1234'; + g_userInfo.username = ''; + g_userInfo.password = ''; + doInit(); + + //监听统计数据改变事件 + eventBus.on().listen((event) { + print(event.str); + updateMayLogin(); + }); + } + + // 一套APP适应多个区县登录过程05、处理延迟登录。等待预加载数据成功后,进行页面跳转 + updateMayLogin() { + //判断从网络获取三种统计数据是否完成 + // if (listZptjStatisAlone.length >= dwSum && + // listTodayShtj.length >= dwSum && + // listClltjStatisAlone.length >= dwSum) { + // bMayLogin = true; + // } + if (listAllStatisData.length >= dwSum) { + bMayLogin = true; + } + + if (bMayLogin && bLoginVerify) { + //重新初始化处理延时登录的变量 + // bMayLogin = false; + // bPreLoading = false; + // bLoginVerify = false; //处理延时登录,判断用户名登录是否验证通过 + + Navigator.pushNamed(context, '/tabs', arguments: g_iIndex); + // Future.delayed(const Duration(milliseconds: 1000), () { + // }); + } + } + + doInit() async { + bRemmberPW = await Storage.getBool('bRemmberPW'); + bRemmberPW = (null == bRemmberPW) ? false : bRemmberPW; + print('bRemmberPW = $bRemmberPW'); + + if (bRemmberPW) { + //取出后需解密 + g_userInfo.username = await Storage.getString('username'); + g_userInfo.username = EncryptUtil.aesDecode(g_userInfo.username); + g_userInfo.password = await Storage.getString('password'); + g_userInfo.password = EncryptUtil.aesDecode(g_userInfo.password); + + //user account list + _gainUsers(); + } + try_setState(); + } + + doLogin() async { + //测试用,临时绕过登录处理 + // Navigator.pushNamed(context, '/tabs', arguments: g_iIndex); + // return; + + // if (!bMayLogin) { + // bPreLoading = true; + // try_setState(); + // } + + // 一套APP适应多个区县登录过程01、显示“加载中 ...” + bPreLoading = true; + try_setState(); + + // 一套APP适应多个区县登录过程02、进行登录验证,保存登录信息 + if (bRemmberPW) { + Storage.setBool('bRemmberPW', bRemmberPW); + //加密保存 + Storage.setString('username', EncryptUtil.aesEncode(g_userInfo.username)); + Storage.setString('password', EncryptUtil.aesEncode(g_userInfo.password)); + } else { + Storage.remove('username'); + Storage.remove('password'); + } + + var api = ServicePath.loginUrl; + print(api); + try { + print('开始处理登录请求...'); + print('username = ${g_userInfo.username}'); + print('password = ${g_userInfo.password}'); + Response response; + Dio dio = Dio(); + + String random = RandomBit(6); //flutter (dart)生成N位随机数 + print('random = ${random}'); + print('sign = ${GenerateMd5(APPkey + random)}'); + + response = await dio.post(api, data: { + "username": g_userInfo.username, + "password": g_userInfo.password, + "sign": GenerateMd5(APPkey + random), + "random": random, + }); + print('response = ${response.toString()}'); + //I/flutter ( 5242): {"ret":200,"data":{"is_login":true,"user_id":3,"token":"32EE57A0109A3D1D6590CFD3DEBA71820F77AB654093C1DE750347C88D1A41CF"},"msg":""} + if (response.statusCode == 200) { + // Storage.setString('userInfo', json.encode(response.data["userinfo"])); + // //Navigator.pop(context); + // Navigator.pushNamed(context, '/tabs', arguments: g_iIndex); + + //print('response.data["data"]["is_login"] = ${response.data["data"]["is_login"]}'); + //I/flutter ( 5242): response.data["data"]["is_login"] = true + + //{ + // "ret": 200, + // "data": { + // "is_login": true, + // "user_id": 1, + // "token": "B93EC91FA2FE293B7077162D4527FC4BB228CD6C0A4F24A882B9A8BBE6C3FB47" + // }, + // "msg": "" + // } + + print('response = ${response}'); + //response = {"ret":406,"data":{},"msg":"非法请求:签名错误"} + if (true == response.data["data"]["is_login"]) { + print('登录成功'); + print('response.data = ${response.data}'); + + // if (bRemmberPW) { + // // SaveAccountPasswordManager.getUsers(); + // SaveAccountPasswordManager.saveUser( + // UserAccount(g_userInfo.username, g_userInfo.password)); + // SaveAccountPasswordManager.getUsers().then((listUsers) { + // print("listUsers =\n${listUsers}"); + // }); + // } else { + // SaveAccountPasswordManager.getUsers().then((listUsers) { + // // print("listUsers =\n${listUsers}"); + // for (var user in listUsers) { + // print("User = ${user}"); + // SaveAccountPasswordManager.delUser(user); + // } + // }); + // } + + // 一套APP适应多个区县登录过程03、登录成功,保存登录信息 + Storage.setString('userInfo', json.encode(response.data["data"])); + g_userInfo + .setUserInfo(theMapUserInfoRet: await getMapFromJson(response.data)) + .then((value) { + // 一套APP适应多个区县登录过程04、登录成功,开始使用保存的登录信息预加载数据,并设置bLoginVerify = true + bLoginVerify = true; //处理延时登录,判断用户名登录是否验证通过 + startGetStatisDataNew(); // 2、登录前提前获取统计数据,改善用户登录体验 + // Navigator.pushNamed(context, '/tabs', arguments: g_iIndex); + }); + //获取用户所属分组和相应权限 + // getUserGroupAll().then((value) { + // bLoginVerify = true; //处理延时登录,判断用户名登录是否验证通过 + // if (bMayLogin) { + // // bMayLogin = false; + // // bPreLoading = false; + // // bLoginVerify = false; //处理延时登录,判断用户名登录是否验证通过 + // Navigator.pushNamed(context, '/tabs', arguments: g_iIndex); + // } + // }); + + // bLoginVerify = true; //处理延时登录,判断用户名登录是否验证通过 + // Navigator.pushNamed(context, '/tabs', arguments: g_iIndex); + } else { + print('登录失败:${response.data["data"]}'); + bLoginVerify = false; //处理延时登录,判断用户名登录是否验证通过 + bPreLoading = false; + try_setState(); // 登录失败后,刷新页面 + Fluttertoast.showToast( + msg: '登录失败:用户名或密码不正确。', + toastLength: Toast.LENGTH_LONG, + gravity: ToastGravity.BOTTOM, + ); + print('登录失败:${response.data["data"]}'); + } + print('登录过程正常完成'); + } else { + throw Exception('后端接口出现异常,请检测代码和服务器情况.........'); + } + } catch (e) { + print('登录过程异常...'); + print('ERROR:======>${e}'); + Fluttertoast.showToast( + msg: 'ERROR:======>${e}', + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.CENTER, + ); + } + + return; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + //resizeToAvoidBottomPadding: false, //解决输入法键盘弹出越界问题-无效 + backgroundColor: Colors.transparent, + body: GestureDetector( + onTap: () { + FocusScopeNode currentFocus = FocusScope.of(context); + // if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) { + if (true) { + FocusManager.instance.primaryFocus.unfocus(); // 【Flutter 实战】全局点击空白处隐藏键盘 + // 全局点击空白处隐藏账号输入框 + if (g_users.isNotEmpty) { + //如果个数大于1个或者唯一一个账号跟当前账号不一样才弹出历史账号 + // _can_expand_ListView = !_can_expand_ListView; + _can_expand_ListView = false; + } + setState(() {}); + } + }, + child: Container( + height: widget.height, + child: Column( + children: [ + Container(color: Colors.transparent, height: ScreenUtil().setHeight(45)), + Container( + color: Colors.white, + width: double.infinity, + height: ScreenUtil().setHeight(156), + padding: EdgeInsets.only(top: 10, bottom: 0, left: 20, right: 20), + child: JdText( + height: 126, + //JdText中已经使用ScreenUtil().setHeight(126),此处不能传 ScreenUtil().setHeight(126) ,否则严重错位 + title: '用户名:', + text: "请输入用户名", + onChanged: (String value) { + // print(value); + g_userInfo.username = value; + }, + endBtn: 'ClearBtn', + controller: TextEditingController(text: g_userInfo.username), + onEndBtn: () { + if (g_users.isNotEmpty) { + //如果个数大于1个或者唯一一个账号跟当前账号不一样才弹出历史账号 + setState(() { + _can_expand_ListView = !_can_expand_ListView; + }); + } + }, + onEndBtn2: () { + // FocusManager.instance.primaryFocus.unfocus(); // 【Flutter 实战】全局点击空白处隐藏键盘 + // 全局点击空白处隐藏账号输入框 + print('xx2'); + if (g_users.isNotEmpty) { + //如果个数大于1个或者唯一一个账号跟当前账号不一样才弹出历史账号 + _can_expand_ListView = false; + } + setState(() {}); + }, + ), + ), + Stack( + children: [ + Column( + children: [ + Container( + color: Colors.white, + width: double.infinity, + height: ScreenUtil().setHeight(224), + padding: EdgeInsets.only(top: 0, bottom: 20, left: 20, right: 20), + child: Column( + children: [ + Container( + color: Colors.transparent, height: ScreenUtil().setHeight(30)), + JdText( + height: 126, + //JdText中已经使用ScreenUtil().setHeight(126),此处不能传 ScreenUtil().setHeight(126) ,否则严重错位 + title: '密 码:', + text: "请输入密码", + password: true, + onChanged: (String value) { + g_userInfo.password = value; + }, + endBtn: 'ShowHiddenBtn', + controller: TextEditingController(text: g_userInfo.password), + ), + ], + ), + ), + Container(color: Colors.transparent, height: ScreenUtil().setHeight(30)), + Container( + //color: Colors.transparent, + padding: EdgeInsets.all(ScreenUtil().setWidth(10)), + child: Row( + children: [ + SizedBox(width: ScreenUtil().setWidth(45)), + InkWell( + onTap: () { + //Navigator.pushNamed(context, '/registerFirst'); + this.setState(() { + bRemmberPW = !bRemmberPW; + }); + Storage.setBool('bRemmberPW', bRemmberPW); + }, + child: Container( + alignment: Alignment(1, -1), + //width: 150, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + alignment: Alignment(0, 0), + height: 22, + width: 22, + padding: EdgeInsets.only(top: ScreenUtil().setHeight(3)), + // child: Checkbox( + // value: bRemmberPW, + // activeColor: Colors.blue, + // onChanged: (bool val) { + // this.setState(() { + // bRemmberPW = !bRemmberPW; + // }); + // Storage.setBool('bRemmberPW', bRemmberPW); + // }, + // ), + child: bRemmberPW + ? Icon(Icons.check_box, color: Colors.blue) + : Icon(Icons.check_box_outline_blank, + color: Colors.white), + ), + SizedBox(width: ScreenUtil().setWidth(15)), + Text('记住密码', + style: TextStyle(fontSize: 17, color: Colors.white)), + ], + ), + ), + ), + ], + ), + ), + SizedBox(height: ScreenUtil().setHeight(48)), + InkWell( + onTap: doLogin, + child: Container( + alignment: Alignment(0, 0), + margin: EdgeInsets.all(5), + padding: EdgeInsets.all(5), + width: ScreenUtil().setWidth(999), + height: ScreenUtil().setHeight(126), + decoration: BoxDecoration( + color: Color.fromRGBO(23, 176, 91, 1), + borderRadius: BorderRadius.circular(10)), + child: Text( + bPreLoading ? "加载中 . . ." : "登 录", + style: TextStyle(color: Colors.white, fontSize: 18), + ), + ), + ), + ], + ), + g_users.isNotEmpty ? _buildListView() : Container(), + ], + ), + // JdButton( + // height: 126, + // //JdText中已经使用ScreenUtil().setHeight(126),此处不能传 ScreenUtil().setHeight(126) ,否则严重错位 + // width: 999, + // text: "登 录", + // color: Color.fromRGBO(23, 176, 91, 1), + // onTop: doLogin, + // ), + ], + ), + ), + ), + ); + } + + /// 保存登录用户列表增加的代码 + + ///构建历史账号ListView + Widget _buildListView() { + if (_can_expand_ListView) { + return Column( + children: [ + ListView.builder( + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + UserAccount user = g_users[index]; + return GestureDetector( + child: Column( + children: [ + Container( + width: ScreenUtil().screenWidth * 0.9, + // color: Colors.grey[200], + color: Colors.grey[200], + padding: EdgeInsets.only(left: 8, top: 8, right: 8, bottom: 8), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("${user.username}"), + GestureDetector( + child: Padding( + padding: EdgeInsets.all(0), + child: Icon( + Icons.remove_circle_outline, + color: Colors.grey, + ), + ), + onTap: () { + setState(() { + g_users.remove(user); + SaveAccountPasswordManager.delUser(user); + //处理最后一个数据,假如最后一个被删掉,将Expand置为false + //如果个数大于1个或者唯一一个账号跟当前账号不一样才弹出历史账号 + _can_expand_ListView = g_users.isNotEmpty; + }); + }, + ), + ], + ), + Divider(height: 1.0, color: Colors.black), + ], + ), + ), + ], + ), + onTap: () { + setState(() { + g_userInfo.username = user.username; + g_userInfo.password = user.password; + }); + }, + ); + }, + itemCount: g_users.length, + ) + ], + ); + } + return Container(); + } + + ///获取历史用户 + void _gainUsers() async { + g_users.clear(); + g_users.addAll(await SaveAccountPasswordManager.getUsers()); + //默认加载第一个账号 + if (g_users.isNotEmpty) { + setState(() { + g_userInfo.username = g_users[0].username; + g_userInfo.password = g_users[0].password; + }); + } + } +} diff --git a/lib/pages/Login/LoginTabsWidget.dart b/lib/pages/Login/LoginTabsWidget.dart index 2bb5ae4..5be21e1 100644 --- a/lib/pages/Login/LoginTabsWidget.dart +++ b/lib/pages/Login/LoginTabsWidget.dart @@ -7,7 +7,7 @@ import 'package:hyzp_ybqx/widget/my_Tabs.dart' as my_Tabs; import '../../components/commonFun.dart'; import '../../services/Storage.dart'; import 'FaceLogin2.dart'; -import 'LoginByName2.dart'; +import 'LoginByName3.dart'; // class LoginTabsWidget extends StatelessWidget { // // This widget is the root of your application. @@ -157,7 +157,7 @@ class _MyHomePageState extends State with SingleTickerProviderS //flutter tabbar禁止手势滑动-OK physics: new NeverScrollableScrollPhysics(), children: [ - LoginByName2(height: _height), + LoginByName3(height: _height), FaceLogin2(), ], ), diff --git a/lib/widget/JdText.dart b/lib/widget/JdText.dart index 3b78e4a..cc8df71 100644 --- a/lib/widget/JdText.dart +++ b/lib/widget/JdText.dart @@ -1,17 +1,19 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; - import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:hyzp_ybqx/components/commonFun.dart'; class JdText extends StatefulWidget { final String text; final String title; bool password; - final Object onChanged; + final Function(String) onChanged; final int maxLines; final double height; TextEditingController controller; final String endBtn; + final Function() onEndBtn; + final Function() onEndBtn2; JdText( {Key key, @@ -22,7 +24,9 @@ class JdText extends StatefulWidget { this.maxLines = 1, this.height = 68, this.controller, - this.endBtn}) + this.endBtn, + this.onEndBtn, + this.onEndBtn2}) : super(key: key); _JdTextState createState() => _JdTextState(); @@ -31,8 +35,40 @@ class JdText extends StatefulWidget { class _JdTextState extends State { Icon ShowHiddenIcon = Icon(Icons.more_horiz); + // Flutter 监听TextField焦点 + FocusNode _focusNode = FocusNode(); + bool isFocus = false; + void initState() { super.initState(); + + // _focusNode.addListener(() { + // setState(() { + // isFocus = _focusNode.hasFocus; + // widget.onEndBtn2(); + // }); + // }); + + //输入框焦点 + _focusNode.addListener(() { + if (!_focusNode.hasFocus) { + print(widget.endBtn + ':失去焦点'); + } else { + print(widget.endBtn + ':得到焦点'); + if (null != widget.onEndBtn2) { + widget.onEndBtn2(); + setState(() {}); + } + } + }); + } + + //离开页面记着销毁和清除 + @override + void dispose() { + // TODO: implement dispose + _focusNode.unfocus(); + super.dispose(); } @override @@ -63,6 +99,7 @@ class _JdTextState extends State { //Flutter中Row中不能直接使用textfield控件 Expanded( child: TextField( + focusNode: _focusNode, textAlignVertical: TextAlignVertical(y: 1.0), controller: widget.controller, maxLines: 1, @@ -91,14 +128,29 @@ class _JdTextState extends State { // alignment: Alignment(0, -1), // padding: EdgeInsets.only(bottom: 23), child: IconButton( - icon: Icon(Icons.highlight_off), - onPressed: () { - setState(() { - widget.controller.clear(); - }); - }), + padding: EdgeInsets.only(bottom: 0.0), + iconSize: 40, + icon: Icon( + Icons.arrow_drop_down, + color: g_users.isNotEmpty ? Colors.blueAccent : Colors.grey, + ), + onPressed: widget.onEndBtn), ); break; + // case 'ClearBtn': + // widget.controller = new TextEditingController(); + // btn = Container( + // // alignment: Alignment(0, -1), + // // padding: EdgeInsets.only(bottom: 23), + // child: IconButton( + // icon: Icon(Icons.highlight_off), + // onPressed: () { + // setState(() { + // widget.controller.clear(); + // }); + // }), + // ); + // break; case 'ShowHiddenBtn': btn = Container( // alignment: Alignment(0, -1), diff --git a/pubspec.lock b/pubspec.lock index f856dfb..696ade1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,13 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + ai_save_account: + dependency: "direct main" + description: + name: ai_save_account + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" app_installer: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index dd878e1..5a91ac7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -177,7 +177,7 @@ dependencies: qr_flutter: ^3.2.0 # Flutter 保存用户登录历史记录 ai_save_account -# ai_save_account: ^1.0.1 + ai_save_account: ^1.0.1 dev_dependencies: flutter_test: