From 96c17fc30ff517de77f0b3b12a6016f3276a7472 Mon Sep 17 00:00:00 2001 From: admin <weikou2014> Date: 星期三, 09 二月 2022 14:21:21 +0800 Subject: [PATCH] flutter模板之邮箱登录、注册、找回密码 --- src/main/resources/code/flutter/lib/ui/mine/email_login.dart | 422 +++++++++++++++++++ src/main/resources/code/flutter/lib/ui/mine/email_register.dart | 462 +++++++++++++++++++++ src/main/resources/code/flutter/lib/ui/mine/email_pwd_find.dart | 419 +++++++++++++++++++ 3 files changed, 1,303 insertions(+), 0 deletions(-) diff --git a/src/main/resources/code/flutter/lib/ui/mine/email_login.dart b/src/main/resources/code/flutter/lib/ui/mine/email_login.dart new file mode 100644 index 0000000..9bf5643 --- /dev/null +++ b/src/main/resources/code/flutter/lib/ui/mine/email_login.dart @@ -0,0 +1,422 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:fluwx_no_pay/fluwx_no_pay.dart' as fluwx; +import 'package:hanju/ui/mine/email_pwd_find.dart'; +import 'package:hanju/ui/mine/email_register.dart'; +import 'package:html/dom.dart' as dom; +import '../../api/http.dart'; +import '../../model/user/user_info.dart'; +import '../../ui/common/browser.dart'; +import '../../ui/widget/button.dart'; +import '../../utils/event_bus_util.dart'; +import '../../utils/pageutils.dart'; +import '../../utils/push_util.dart'; +import '../../utils/string_util.dart'; +import '../../utils/ui_constant.dart'; +import '../../utils/ui_utils.dart'; +import '../../utils/user_util.dart'; +import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: '鐧诲綍', + theme: ThemeData(primaryColor: Color(0xFFF5F5F5)), + home: EmailLoginPage(title: ''), + ); + } +} + +class EmailLoginPage extends StatefulWidget { + //闃块噷浜戜竴閿櫥褰� + static const messageChannel = + BasicMessageChannel('AliyunPhoneNumberAuth', StandardMessageCodec()); + + EmailLoginPage({Key? key, required this.title}) : super(key: key); + + // This widget is the home page of your application. It is stateful, meaning + // that it has a State object (defined below) that contains fields that affect + // how it looks. + + // This class is the configuration for the state. It holds the values (in this + // case the title) provided by the parent (in this case the App widget) and + // used by the build method of the State. Fields in a Widget subclass are + // always marked "final". + + final String title; + + @override + _EmailLoginPageState createState() => _EmailLoginPageState(); +} + +class _EmailLoginPageState extends State<EmailLoginPage> + with SingleTickerProviderStateMixin { + bool oneKeyLogin = false; + bool checked = false; + TextEditingController? emailController = TextEditingController(); + TextEditingController? codeController = TextEditingController(); + String phone = ""; + String code = ""; + Timer? timer; + + //閲嶆柊鍙戦�侀獙璇佺爜鍊掕鏃� + int? reSendSMSTimeLeft; + + @override + void initState() { + super.initState(); + reSendSMSTimeLeft = -1; + //鍒濆鍖栧井淇$櫥褰曠洃鍚� + fluwx.weChatResponseEventHandler.distinct((a, b) => a == b).listen((res) { + if (res is fluwx.WeChatAuthResponse) { + int errCode = res.errCode; + if (errCode == 0) { + String? code = res.code; + //TODO 鎶婂井淇$櫥褰曡繑鍥炵殑code浼犵粰鍚庡彴锛屽墿涓嬬殑浜嬪氨浜ょ粰鍚庡彴澶勭悊 + } else if (errCode == -4) { + //showToast("鐢ㄦ埛鎷掔粷鎺堟潈"); + } else if (errCode == -2) { + // showToast("鐢ㄦ埛鍙栨秷鎺堟潈"); + } + } + }); + } + + bool _aliyunLogin = false; + + void aliyunOneKeyLogin() async { + if (_aliyunLogin) { + return; + } + _aliyunLogin = true; + Future.delayed(const Duration(milliseconds: 1000), () { + _aliyunLogin = false; + }); + + showLoading(context); + + Map value = + await EmailLoginPage.messageChannel.send({"method": "checkEnv"}) as Map; + dismissDialog(context); + if (value["code"] == 0) { + value = await EmailLoginPage.messageChannel.send({"method": "startLogin"}) + as Map; + print("杩斿洖鍐呭锛�${jsonEncode(value)}"); + if (value["code"] == 0) { + Map<String, dynamic>? resultValue = + await UserApiUtil.login(context, "", "", value["token"]); + + EmailLoginPage.messageChannel.send({"method": "closeLogin"}); + + if (resultValue == null) return; + + if (resultValue["code"] == 0) { + UserInfo user = UserInfo.fromJson(resultValue["data"]); + _loginSuccess(user); + } else { + Fluttertoast.showToast(msg: value["msg"]); + } + } else if (value["code"] == 700000) { + //Fluttertoast.showToast(msg: "鍙栨秷鐧诲綍浜�"); + } + } else { + Fluttertoast.showToast(msg: value["msg"]); + setState(() { + oneKeyLogin = false; + }); + } + } + + void qqLogin() async { + Map value = await UserUtil.loginQQ(); + } + + void _loginSuccess(UserInfo user) { + UserUtil.setUserInfo(user).then((value) { + print("鐧诲綍鎴愬姛"); + eventBus.fire(LoginEventBus(true)); + PushUtil.setAlias(user.id!.toString()).then((value) { + Navigator.pop(context); + }); + }); + } + + @override + void dispose() { + if (timer != null) { + timer!.cancel(); + } + super.dispose(); + } + + BoxDecoration getItemDecoration(Color bgColor, Color shadowColor) { + return BoxDecoration( + borderRadius: const BorderRadius.all(Radius.elliptical(10, 10)), + color: bgColor, + boxShadow: [ + BoxShadow( + color: shadowColor, + blurRadius: 2.0, + offset: Offset(0.0, 5.0), //闃村奖y杞村亸绉婚噺 + spreadRadius: 1 //闃村奖鎵╂暎绋嬪害 + ) + ]); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomInset: false, + backgroundColor: Colors.white, + body: Stack( + children: [ + Column(children: [ + //鐧诲綍鍐呭鍖哄煙 + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.fromLTRB(40, 120, 40, 14), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "assets/imgs/login/ic_login_logo.png", + width: 131, + ), + Container( + height: 70, + ), + Container( + constraints: BoxConstraints(minHeight: 180), + child: getLoginContent()), + Row( + children: [ + InkWell( + child: const Text( + "娉ㄥ唽", + style: TextStyle( + color: ColorConstant.theme), + ), + onTap: () { + NavigatorUtil.navigateToNextPage( + context, + EmailRegisterPage(title: ""), + (data) { + FocusScope.of(context).requestFocus(FocusNode()); + }); + }, + ), + Expanded(child: Container()), + InkWell( + child: const Text("鎵惧洖瀵嗙爜?", + style: TextStyle( + color: ColorConstant.theme)), + onTap: () { + NavigatorUtil.navigateToNextPage( + context, + EmailFindPwdPage(title: ""), + (data) { + FocusScope.of(context).requestFocus(FocusNode()); + }); + + }, + ), + ], + ) + ])))), + //鐢ㄦ埛鍗忚涓庨殣绉佹斂绛� + Row(children: [ + Container( + width: 25, + ), + RoundCheckBox( + value: checked, + onChanged: (value) { + setState(() { + checked = value; + }); + }, + ), + Expanded( + child: Container( + child: HtmlWidget( + "<p>鐧诲綍鍗宠〃鏄庡悓鎰� <a href='${Constant.PROTOCOL_URL}'>鐢ㄦ埛鍗忚</a> 鍜� <a href='${Constant.PRIVACY_URL}'>闅愮鏀跨瓥</a> </p>", + textStyle: + const TextStyle(color: Color(0xFF999999)), + customStylesBuilder: (element) { + // print(element.localName); + // if (element.localName == 'a') { + // return {'color': 'red'}; + // } + + return null; + }, onTapUrl: (url) { + String? title = ""; + if (url == Constant.PROTOCOL_URL) { + title = "鐢ㄦ埛鍗忚"; + } else { + title = "闅愮鏀跨瓥"; + } + + NavigatorUtil.navigateToNextPage( + context, + BrowserPage( + title: title, + url: url, + ), + (data) {}); + + return true; + }))), + ]) + ]), + //鍏抽棴鎸夐挳 + Positioned( + top: 30, + left: 20, + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Icon( + Icons.close, + size: 30, + ))) + ], + )); + } + + Widget getLoginContent() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.fromLTRB(20, 0, 5, 0), + decoration: BoxDecoration( + color: const Color(0xFFF5F5F5), + borderRadius: BorderRadius.circular(10)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "assets/imgs/login/icon_email.png", + width: 17, + height: 15, + ), + Container(width: 14), + Expanded( + child: TextField( + style: TextStyle(color: Color(0xFF333333), fontSize: 17), + onChanged: (value) { + setState(() { + phone = value; + }); + }, + textAlign: TextAlign.start, + keyboardType: TextInputType.emailAddress, + controller: emailController, + maxLength: 60, + decoration: InputDecoration( + counterText: "", + hintText: "璇疯緭鍏ラ偖绠�", + hintStyle: + TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), + contentPadding: EdgeInsets.only(bottom: 3), + border: InputBorder.none, + focusedBorder: InputBorder.none, + ), + )), + ], + ), + ), + Container(height: 10), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.fromLTRB(20, 0, 7, 0), + decoration: BoxDecoration( + color: const Color(0xFFF5F5F5), + borderRadius: BorderRadius.circular(10)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "assets/imgs/login/icon_pwd.png", + width: 16.5, + ), + Container(width: 14), + Expanded( + child: TextField( + style:const TextStyle(color: Color(0xFF333333), fontSize: 17), + onChanged: (value) { + setState(() { + phone = value; + }); + }, + textAlign: TextAlign.start, + keyboardType: TextInputType.visiblePassword, + controller: codeController, + maxLength: 32, + decoration: const InputDecoration( + counterText: "", + hintText: "璇疯緭鍏ュ瘑鐮�", + hintStyle: + TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), + contentPadding: EdgeInsets.only(bottom: 3), + border: InputBorder.none, + focusedBorder: InputBorder.none, + ), + )), + ], + ), + ), + Container(height: 20), + MyFillButton( + "鐧� 褰�", + 10, + height: 45, + color: const Color(0xFFFF2B4B), + fontSize: 17, + enable: StringUtil.isEmail(emailController!.value.text) && + codeController!.value.text.length >= 6, + + onClick: () { + if (!(StringUtil.isEmail(emailController!.value.text) && + codeController!.value.text.length >= 6)) { + return; + } + + if (!checked) { + Fluttertoast.showToast(msg: "璇峰悓鎰忕敤鎴峰崗璁笌闅愮鏀跨瓥"); + return; + } + + UserApiUtil.login(context, emailController!.value.text, + codeController!.value.text, "") + .then((value) { + print("缁撴灉锛� $value"); + if (value!["code"] == 0) { + UserInfo user = UserInfo.fromJson(value["data"]); + _loginSuccess(user); + } else { + Fluttertoast.showToast(msg: value["msg"]); + } + }); + }, + ), + ], + ); + } +} diff --git a/src/main/resources/code/flutter/lib/ui/mine/email_pwd_find.dart b/src/main/resources/code/flutter/lib/ui/mine/email_pwd_find.dart new file mode 100644 index 0000000..c2b8dc6 --- /dev/null +++ b/src/main/resources/code/flutter/lib/ui/mine/email_pwd_find.dart @@ -0,0 +1,419 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:fluwx_no_pay/fluwx_no_pay.dart' as fluwx; +import 'package:html/dom.dart' as dom; +import '../../api/http.dart'; +import '../../model/user/user_info.dart'; +import '../../ui/common/browser.dart'; +import '../../ui/widget/button.dart'; +import '../../utils/event_bus_util.dart'; +import '../../utils/pageutils.dart'; +import '../../utils/push_util.dart'; +import '../../utils/string_util.dart'; +import '../../utils/ui_constant.dart'; +import '../../utils/ui_utils.dart'; +import '../../utils/user_util.dart'; +import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: '娉ㄥ唽', + theme: ThemeData(primaryColor: Color(0xFFF5F5F5)), + home: EmailFindPwdPage(title: ''), + ); + } +} + +class EmailFindPwdPage extends StatefulWidget { + //闃块噷浜戜竴閿櫥褰� + static const messageChannel = + BasicMessageChannel('AliyunPhoneNumberAuth', StandardMessageCodec()); + + EmailFindPwdPage({Key? key, required this.title}) : super(key: key); + + // This widget is the home page of your application. It is stateful, meaning + // that it has a State object (defined below) that contains fields that affect + // how it looks. + + // This class is the configuration for the state. It holds the values (in this + // case the title) provided by the parent (in this case the App widget) and + // used by the build method of the State. Fields in a Widget subclass are + // always marked "final". + + final String title; + + @override + _EmailFindPwdPageState createState() => _EmailFindPwdPageState(); +} + +class _EmailFindPwdPageState extends State<EmailFindPwdPage> + with SingleTickerProviderStateMixin { + TextEditingController? emailController = TextEditingController(); + TextEditingController? codeController = TextEditingController(); + TextEditingController? pwdController = TextEditingController(); + String email = ""; + String code = ""; + Timer? timer; + + //閲嶆柊鍙戦�侀獙璇佺爜鍊掕鏃� + int? reSendSMSTimeLeft; + + @override + void initState() { + super.initState(); + reSendSMSTimeLeft = -1; + //鍒濆鍖栧井淇$櫥褰曠洃鍚� + fluwx.weChatResponseEventHandler.distinct((a, b) => a == b).listen((res) { + if (res is fluwx.WeChatAuthResponse) { + int errCode = res.errCode; + if (errCode == 0) { + String? code = res.code; + //TODO 鎶婂井淇$櫥褰曡繑鍥炵殑code浼犵粰鍚庡彴锛屽墿涓嬬殑浜嬪氨浜ょ粰鍚庡彴澶勭悊 + } else if (errCode == -4) { + //showToast("鐢ㄦ埛鎷掔粷鎺堟潈"); + } else if (errCode == -2) { + // showToast("鐢ㄦ埛鍙栨秷鎺堟潈"); + } + } + }); + } + + bool _aliyunLogin = false; + + void aliyunOneKeyLogin() async { + if (_aliyunLogin) { + return; + } + _aliyunLogin = true; + Future.delayed(const Duration(milliseconds: 1000), () { + _aliyunLogin = false; + }); + + showLoading(context); + + Map value = + await EmailFindPwdPage.messageChannel.send({"method": "checkEnv"}) as Map; + dismissDialog(context); + if (value["code"] == 0) { + value = + await EmailFindPwdPage.messageChannel.send({"method": "startLogin"}) as Map; + print("杩斿洖鍐呭锛�${jsonEncode(value)}"); + if (value["code"] == 0) { + Map<String, dynamic>? resultValue = + await UserApiUtil.login(context, "", "", value["token"]); + + EmailFindPwdPage.messageChannel.send({"method": "closeLogin"}); + + if (resultValue == null) return; + + if (resultValue["code"] == 0) { + UserInfo user = UserInfo.fromJson(resultValue["data"]); + _loginSuccess(user); + } else { + Fluttertoast.showToast(msg: value["msg"]); + } + } else if (value["code"] == 700000) { + //Fluttertoast.showToast(msg: "鍙栨秷鐧诲綍浜�"); + } + } else { + Fluttertoast.showToast(msg: value["msg"]); + } + } + + void qqLogin() async { + Map value = await UserUtil.loginQQ(); + } + + void _loginSuccess(UserInfo user) { + UserUtil.setUserInfo(user).then((value) { + print("鐧诲綍鎴愬姛"); + eventBus.fire(LoginEventBus(true)); + PushUtil.setAlias(user.id!.toString()).then((value) { + Navigator.pop(context); + }); + }); + } + + @override + void dispose() { + if (timer != null) { + timer!.cancel(); + } + super.dispose(); + } + + BoxDecoration getItemDecoration(Color bgColor, Color shadowColor) { + return BoxDecoration( + borderRadius: const BorderRadius.all(Radius.elliptical(10, 10)), + color: bgColor, + boxShadow: [ + BoxShadow( + color: shadowColor, + blurRadius: 2.0, + offset: Offset(0.0, 5.0), //闃村奖y杞村亸绉婚噺 + spreadRadius: 1 //闃村奖鎵╂暎绋嬪害 + ) + ]); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomInset: false, + backgroundColor: Colors.white, + body: Stack( + children: [ + Column(children: [ + //鐧诲綍鍐呭鍖哄煙 + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.fromLTRB(40, 120, 40, 14), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "assets/imgs/login/ic_login_logo.png", + width: 131, + ), + Container( + height: 70, + ), + Container( + constraints: BoxConstraints(minHeight: 200), + child: getLoginContent()), + Container( + height: 30, + ) + ])))), + + ]), + //鍏抽棴鎸夐挳 + Positioned( + top: 30, + left: 20, + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: const Icon( + Icons.arrow_back_ios_new, + size: 25, + ))) + ], + )); + } + + Widget getLoginContent() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.fromLTRB(20, 0, 5, 0), + decoration: BoxDecoration( + color: const Color(0xFFF5F5F5), + borderRadius: BorderRadius.circular(10)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "assets/imgs/login/icon_email.png", + width: 17, + height: 15, + ), + Container(width: 14), + Expanded( + child: TextField( + style: TextStyle(color: Color(0xFF333333), fontSize: 17), + onChanged: (value) { + setState(() { + email = value; + }); + }, + textAlign: TextAlign.start, + keyboardType: TextInputType.emailAddress, + controller: emailController, + maxLength: 60, + decoration: InputDecoration( + counterText: "", + hintText: "璇疯緭鍏ラ偖绠�", + hintStyle: + TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), + contentPadding: EdgeInsets.only(bottom: 3), + border: InputBorder.none, + focusedBorder: InputBorder.none, + ), + )), + ], + ), + ), + Container(height: 10), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.fromLTRB(20, 0, 7, 0), + decoration: BoxDecoration( + color: const Color(0xFFF5F5F5), + borderRadius: BorderRadius.circular(10)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "assets/imgs/login/icon_code.png", + width: 16.5, + ), + Container(width: 14), + Expanded( + child: TextField( + style: TextStyle(color: Color(0xFF333333), fontSize: 17), + onChanged: (value) { + setState(() { + email = value; + }); + }, + textAlign: TextAlign.start, + keyboardType: TextInputType.phone, + controller: codeController, + maxLength: 8, + decoration: const InputDecoration( + counterText: "", + hintText: "璇疯緭鍏ラ獙璇佺爜", + hintStyle: + TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), + contentPadding: EdgeInsets.only(bottom: 3), + border: InputBorder.none, + focusedBorder: InputBorder.none, + ), + )), + MyFillButton( + (reSendSMSTimeLeft! > 0 + ? (reSendSMSTimeLeft.toString() + "S閲嶆柊鑾峰彇") + : reSendSMSTimeLeft == -1 + ? "鑾峰彇楠岃瘉鐮�" + : "閲嶆柊鑾峰彇") + .toString(), + 10, + height: 34, + padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), + enable: (reSendSMSTimeLeft! < 1 && + StringUtil.isEmail(emailController!.value.text)), + onClick: () { + if (!(reSendSMSTimeLeft! < 1 && + StringUtil.isEmail(emailController!.value.text))) { + return; + } + //鍙戦�侀獙璇佺爜 + UserApiUtil.sendSMS( + context, emailController!.value.text) + .then((value) { + if (value != null && value["code"] == 0) { + setState(() { + reSendSMSTimeLeft = 60; + //鍊掕鏃� + timer = Timer.periodic(const Duration(seconds: 1), + (timer) { + if (reSendSMSTimeLeft! > 0) { + setState(() { + reSendSMSTimeLeft = reSendSMSTimeLeft! - 1; + }); + } else { + timer.cancel(); + } + }); + }); + } else { + ToastUtil.toast(value!["msg"]); + } + }); + }, + ), + ], + ), + ), + Container(height: 10), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.fromLTRB(20, 0, 7, 0), + decoration: BoxDecoration( + color: const Color(0xFFF5F5F5), + borderRadius: BorderRadius.circular(10)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "assets/imgs/login/icon_pwd.png", + width: 16.5, + ), + Container(width: 14), + Expanded( + child: TextField( + style: TextStyle(color: Color(0xFF333333), fontSize: 17), + onChanged: (value) { + setState(() { + email = value; + }); + }, + obscureText: true, + textAlign: TextAlign.start, + keyboardType: TextInputType.visiblePassword, + controller: pwdController, + maxLength: 32, + decoration: const InputDecoration( + counterText: "", + hintText: "璇疯緭鍏ュ瘑鐮�", + hintStyle: + TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), + contentPadding: EdgeInsets.only(bottom: 3), + border: InputBorder.none, + focusedBorder: InputBorder.none, + ), + )), + ], + ), + ), + Container(height: 52), + MyFillButton( + "璁剧疆瀵嗙爜", + 10, + height: 45, + color: ColorConstant.theme, + fontSize: 17, + enable: StringUtil.isEmail(emailController!.value.text) && + codeController!.value.text.length >= 4&&pwdController!.value.text.length >= 6, + onClick: () { + if (!(StringUtil.isEmail(emailController!.value.text) && + codeController!.value.text.length >= 4&&pwdController!.value.text.length >= 6)) { + return; + } + + UserApiUtil.login(context, emailController!.value.text, + codeController!.value.text, "") + .then((value) { + print("缁撴灉锛� $value"); + if (value!["code"] == 0) { + UserInfo user = UserInfo.fromJson(value["data"]); + _loginSuccess(user); + } else { + Fluttertoast.showToast(msg: value["msg"]); + } + }); + }, + ), + ], + ); + } + +} diff --git a/src/main/resources/code/flutter/lib/ui/mine/email_register.dart b/src/main/resources/code/flutter/lib/ui/mine/email_register.dart new file mode 100644 index 0000000..38ba6bf --- /dev/null +++ b/src/main/resources/code/flutter/lib/ui/mine/email_register.dart @@ -0,0 +1,462 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:fluwx_no_pay/fluwx_no_pay.dart' as fluwx; +import 'package:html/dom.dart' as dom; +import '../../api/http.dart'; +import '../../model/user/user_info.dart'; +import '../../ui/common/browser.dart'; +import '../../ui/widget/button.dart'; +import '../../utils/event_bus_util.dart'; +import '../../utils/pageutils.dart'; +import '../../utils/push_util.dart'; +import '../../utils/string_util.dart'; +import '../../utils/ui_constant.dart'; +import '../../utils/ui_utils.dart'; +import '../../utils/user_util.dart'; +import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: '娉ㄥ唽', + theme: ThemeData(primaryColor: Color(0xFFF5F5F5)), + home: EmailRegisterPage(title: ''), + ); + } +} + +class EmailRegisterPage extends StatefulWidget { + //闃块噷浜戜竴閿櫥褰� + static const messageChannel = + BasicMessageChannel('AliyunPhoneNumberAuth', StandardMessageCodec()); + + EmailRegisterPage({Key? key, required this.title}) : super(key: key); + + // This widget is the home page of your application. It is stateful, meaning + // that it has a State object (defined below) that contains fields that affect + // how it looks. + + // This class is the configuration for the state. It holds the values (in this + // case the title) provided by the parent (in this case the App widget) and + // used by the build method of the State. Fields in a Widget subclass are + // always marked "final". + + final String title; + + @override + _EmailRegisterPageState createState() => _EmailRegisterPageState(); +} + +class _EmailRegisterPageState extends State<EmailRegisterPage> + with SingleTickerProviderStateMixin { + bool checked = false; + TextEditingController? emailController = TextEditingController(); + TextEditingController? codeController = TextEditingController(); + TextEditingController? pwdController = TextEditingController(); + String email = ""; + String code = ""; + Timer? timer; + + //閲嶆柊鍙戦�侀獙璇佺爜鍊掕鏃� + int? reSendSMSTimeLeft; + + @override + void initState() { + super.initState(); + reSendSMSTimeLeft = -1; + //鍒濆鍖栧井淇$櫥褰曠洃鍚� + fluwx.weChatResponseEventHandler.distinct((a, b) => a == b).listen((res) { + if (res is fluwx.WeChatAuthResponse) { + int errCode = res.errCode; + if (errCode == 0) { + String? code = res.code; + //TODO 鎶婂井淇$櫥褰曡繑鍥炵殑code浼犵粰鍚庡彴锛屽墿涓嬬殑浜嬪氨浜ょ粰鍚庡彴澶勭悊 + } else if (errCode == -4) { + //showToast("鐢ㄦ埛鎷掔粷鎺堟潈"); + } else if (errCode == -2) { + // showToast("鐢ㄦ埛鍙栨秷鎺堟潈"); + } + } + }); + } + + bool _aliyunLogin = false; + + void aliyunOneKeyLogin() async { + if (_aliyunLogin) { + return; + } + _aliyunLogin = true; + Future.delayed(const Duration(milliseconds: 1000), () { + _aliyunLogin = false; + }); + + showLoading(context); + + Map value = + await EmailRegisterPage.messageChannel.send({"method": "checkEnv"}) as Map; + dismissDialog(context); + if (value["code"] == 0) { + value = + await EmailRegisterPage.messageChannel.send({"method": "startLogin"}) as Map; + print("杩斿洖鍐呭锛�${jsonEncode(value)}"); + if (value["code"] == 0) { + Map<String, dynamic>? resultValue = + await UserApiUtil.login(context, "", "", value["token"]); + + EmailRegisterPage.messageChannel.send({"method": "closeLogin"}); + + if (resultValue == null) return; + + if (resultValue["code"] == 0) { + UserInfo user = UserInfo.fromJson(resultValue["data"]); + _loginSuccess(user); + } else { + Fluttertoast.showToast(msg: value["msg"]); + } + } else if (value["code"] == 700000) { + //Fluttertoast.showToast(msg: "鍙栨秷鐧诲綍浜�"); + } + } else { + Fluttertoast.showToast(msg: value["msg"]); + } + } + + void qqLogin() async { + Map value = await UserUtil.loginQQ(); + } + + void _loginSuccess(UserInfo user) { + UserUtil.setUserInfo(user).then((value) { + print("鐧诲綍鎴愬姛"); + eventBus.fire(LoginEventBus(true)); + PushUtil.setAlias(user.id!.toString()).then((value) { + Navigator.pop(context); + }); + }); + } + + @override + void dispose() { + if (timer != null) { + timer!.cancel(); + } + super.dispose(); + } + + BoxDecoration getItemDecoration(Color bgColor, Color shadowColor) { + return BoxDecoration( + borderRadius: const BorderRadius.all(Radius.elliptical(10, 10)), + color: bgColor, + boxShadow: [ + BoxShadow( + color: shadowColor, + blurRadius: 2.0, + offset: Offset(0.0, 5.0), //闃村奖y杞村亸绉婚噺 + spreadRadius: 1 //闃村奖鎵╂暎绋嬪害 + ) + ]); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomInset: false, + backgroundColor: Colors.white, + body: Stack( + children: [ + Column(children: [ + //鐧诲綍鍐呭鍖哄煙 + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.fromLTRB(40, 120, 40, 14), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "assets/imgs/login/ic_login_logo.png", + width: 131, + ), + Container( + height: 70, + ), + Container( + constraints: BoxConstraints(minHeight: 200), + child: getLoginContent()), + Container( + height: 30, + ) + ])))), + //鐢ㄦ埛鍗忚涓庨殣绉佹斂绛� + Row(children: [ + Container( + width: 25, + ), + RoundCheckBox( + value: checked, + onChanged: (value) { + setState(() { + checked = value; + }); + }, + ), + Expanded( + child: Container( + child: HtmlWidget( + "<p>鐧诲綍鍗宠〃鏄庡悓鎰� <a href='${Constant.PROTOCOL_URL}'>鐢ㄦ埛鍗忚</a> 鍜� <a href='${Constant.PRIVACY_URL}'>闅愮鏀跨瓥</a> </p>", + textStyle: + const TextStyle(color: Color(0xFF999999)), + onTapUrl: (url) { + String? title = ""; + if (url == Constant.PROTOCOL_URL) { + title = "鐢ㄦ埛鍗忚"; + } else { + title = "闅愮鏀跨瓥"; + } + + NavigatorUtil.navigateToNextPage( + context, + BrowserPage( + title: title, + url: url, + ), + (data) {}); + + return true; + }))), + ]) + ]), + //鍏抽棴鎸夐挳 + Positioned( + top: 30, + left: 20, + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: const Icon( + Icons.arrow_back_ios_new, + size: 25, + ))) + ], + )); + } + + Widget getLoginContent() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.fromLTRB(20, 0, 5, 0), + decoration: BoxDecoration( + color: const Color(0xFFF5F5F5), + borderRadius: BorderRadius.circular(10)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "assets/imgs/login/icon_email.png", + width: 17, + height: 15, + ), + Container(width: 14), + Expanded( + child: TextField( + style: TextStyle(color: Color(0xFF333333), fontSize: 17), + onChanged: (value) { + setState(() { + email = value; + }); + }, + textAlign: TextAlign.start, + keyboardType: TextInputType.emailAddress, + controller: emailController, + maxLength: 60, + decoration: InputDecoration( + counterText: "", + hintText: "璇疯緭鍏ラ偖绠�", + hintStyle: + TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), + contentPadding: EdgeInsets.only(bottom: 3), + border: InputBorder.none, + focusedBorder: InputBorder.none, + ), + )), + ], + ), + ), + Container(height: 10), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.fromLTRB(20, 0, 7, 0), + decoration: BoxDecoration( + color: const Color(0xFFF5F5F5), + borderRadius: BorderRadius.circular(10)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "assets/imgs/login/icon_code.png", + width: 16.5, + ), + Container(width: 14), + Expanded( + child: TextField( + style: TextStyle(color: Color(0xFF333333), fontSize: 17), + onChanged: (value) { + setState(() { + email = value; + }); + }, + textAlign: TextAlign.start, + keyboardType: TextInputType.phone, + controller: codeController, + maxLength: 8, + decoration: const InputDecoration( + counterText: "", + hintText: "璇疯緭鍏ラ獙璇佺爜", + hintStyle: + TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), + contentPadding: EdgeInsets.only(bottom: 3), + border: InputBorder.none, + focusedBorder: InputBorder.none, + ), + )), + MyFillButton( + (reSendSMSTimeLeft! > 0 + ? (reSendSMSTimeLeft.toString() + "S閲嶆柊鑾峰彇") + : reSendSMSTimeLeft == -1 + ? "鑾峰彇楠岃瘉鐮�" + : "閲嶆柊鑾峰彇") + .toString(), + 10, + height: 34, + padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), + enable: (reSendSMSTimeLeft! < 1 && + StringUtil.isEmail(emailController!.value.text)), + onClick: () { + if (!(reSendSMSTimeLeft! < 1 && + StringUtil.isEmail(emailController!.value.text))) { + return; + } + //鍙戦�侀獙璇佺爜 + UserApiUtil.sendSMS( + context, emailController!.value.text) + .then((value) { + if (value != null && value["code"] == 0) { + setState(() { + reSendSMSTimeLeft = 60; + //鍊掕鏃� + timer = Timer.periodic(const Duration(seconds: 1), + (timer) { + if (reSendSMSTimeLeft! > 0) { + setState(() { + reSendSMSTimeLeft = reSendSMSTimeLeft! - 1; + }); + } else { + timer.cancel(); + } + }); + }); + } else { + ToastUtil.toast(value!["msg"]); + } + }); + }, + ), + ], + ), + ), + Container(height: 10), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.fromLTRB(20, 0, 7, 0), + decoration: BoxDecoration( + color: const Color(0xFFF5F5F5), + borderRadius: BorderRadius.circular(10)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "assets/imgs/login/icon_pwd.png", + width: 16.5, + ), + Container(width: 14), + Expanded( + child: TextField( + style: TextStyle(color: Color(0xFF333333), fontSize: 17), + onChanged: (value) { + setState(() { + email = value; + }); + }, + obscureText: true, + textAlign: TextAlign.start, + keyboardType: TextInputType.visiblePassword, + controller: pwdController, + maxLength: 32, + decoration: const InputDecoration( + counterText: "", + hintText: "璇疯緭鍏ュ瘑鐮�", + hintStyle: + TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), + contentPadding: EdgeInsets.only(bottom: 3), + border: InputBorder.none, + focusedBorder: InputBorder.none, + ), + )), + ], + ), + ), + Container(height: 52), + MyFillButton( + "娉� 鍐�", + 10, + height: 45, + color: ColorConstant.theme, + fontSize: 17, + enable: StringUtil.isEmail(emailController!.value.text) && + codeController!.value.text.length >= 4&&pwdController!.value.text.length >= 6, + onClick: () { + if (!(StringUtil.isEmail(emailController!.value.text) && + codeController!.value.text.length >= 4&&pwdController!.value.text.length >= 6)) { + return; + } + + if (!checked) { + Fluttertoast.showToast(msg: "璇峰悓鎰忕敤鎴峰崗璁笌闅愮鏀跨瓥"); + return; + } + + UserApiUtil.login(context, emailController!.value.text, + codeController!.value.text, "") + .then((value) { + print("缁撴灉锛� $value"); + if (value!["code"] == 0) { + UserInfo user = UserInfo.fromJson(value["data"]); + _loginSuccess(user); + } else { + Fluttertoast.showToast(msg: value["msg"]); + } + }); + }, + ), + ], + ); + } + +} -- Gitblit v1.8.0