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>鐧诲綍鍗宠〃鏄庡悓鎰�&nbsp;<a href='${Constant.PROTOCOL_URL}'>鐢ㄦ埛鍗忚</a>&nbsp;鍜�&nbsp;<a href='${Constant.PRIVACY_URL}'>闅愮鏀跨瓥</a>&nbsp;</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>鐧诲綍鍗宠〃鏄庡悓鎰�&nbsp;<a href='${Constant.PROTOCOL_URL}'>鐢ㄦ埛鍗忚</a>&nbsp;鍜�&nbsp;<a href='${Constant.PRIVACY_URL}'>闅愮鏀跨瓥</a>&nbsp;</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