From 2f1eb7abc493626d225b0ce192f249863cf9901d Mon Sep 17 00:00:00 2001 From: GYJ <1157756119@qq.com> Date: Mon, 25 Nov 2024 14:11:57 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95=E9=A1=B5=E9=9D=A2=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/common/manager/app_manager.dart | 21 +- lib/common/print/print.dart | 2 + lib/common/request/request_manager.dart | 75 ++++++ lib/common/utils/utils.dart | 47 ++++ lib/home/home_view.dart | 14 +- lib/login/login_view.dart | 305 ++++++++++++++++++------ lib/model/login_model.dart | 11 + pubspec.lock | 13 + pubspec.yaml | 1 + 9 files changed, 401 insertions(+), 88 deletions(-) create mode 100644 lib/common/request/request_manager.dart create mode 100644 lib/common/utils/utils.dart create mode 100644 lib/model/login_model.dart diff --git a/lib/common/manager/app_manager.dart b/lib/common/manager/app_manager.dart index 1714ebb..d658a9c 100644 --- a/lib/common/manager/app_manager.dart +++ b/lib/common/manager/app_manager.dart @@ -1,3 +1,4 @@ +import 'package:cashier_reserve/common/push/push.dart'; import 'package:cashier_reserve/login/login_view.dart'; import '../base/ui.dart'; @@ -38,13 +39,15 @@ class AppManager { Navigator.of(globalContext!).pop(); } - showDialog( - context: globalContext!, - barrierDismissible: false, - builder: (BuildContext context) { - return WillPopScope( - onWillPop: () => Future.value(false), child: const LoginView()); - }); + YJPush.presentWidget(globalContext!, const LoginView()); + + // showDialog( + // context: globalContext!, + // barrierDismissible: false, + // builder: (BuildContext context) { + // return WillPopScope( + // onWillPop: () => Future.value(false), child: const LoginView()); + // }); } static void disposeLoginWidget() { @@ -54,4 +57,8 @@ class AppManager { static bool isShowLoginView() { return _isAlertLogin; } + + static String getUserToken() { + return HiveManager.getUserToken(); + } } diff --git a/lib/common/print/print.dart b/lib/common/print/print.dart index be9d781..1683224 100644 --- a/lib/common/print/print.dart +++ b/lib/common/print/print.dart @@ -1,6 +1,8 @@ import 'package:flutter/foundation.dart'; +const bool inProduction = !kDebugMode; + void yjPrint(Object? object) { if (kDebugMode) { print(object); diff --git a/lib/common/request/request_manager.dart b/lib/common/request/request_manager.dart new file mode 100644 index 0000000..59257c8 --- /dev/null +++ b/lib/common/request/request_manager.dart @@ -0,0 +1,75 @@ +import 'package:cashier_reserve/common/manager/app_manager.dart'; +import 'package:cashier_reserve/common/print/print.dart'; +import 'package:dio/dio.dart'; + +import '../utils/utils.dart'; + +const String kBaseUrl = 'https://admintestpapi.sxczgkj.cn'; + +const kSuccessCode = 200; +const kNeedLoginCode = 401; + +class RequestManager { + + /// HttpClient + static final Dio _c = Dio(BaseOptions( + baseUrl: kBaseUrl, + connectTimeout: const Duration(milliseconds: 5000), + receiveTimeout: const Duration(milliseconds: 5000) + )); + + /// GET + static Future get(String url, {bool catchError = true}) { + return _doRequest("GET", url, catchError: catchError); + } + + /// DELETE + static Future delete(String url, {bool catchError = true}) { + return _doRequest("DELETE", url, catchError: catchError); + } + + /// POST + static Future post(String url, Map? body, + {bool catchError = true}) { + return _doRequest("POST", url, body: body, catchError: catchError); + } + + /// PUT + static Future put(String url, Map? body, + {bool catchError = true}) { + return _doRequest("PUT", url, body: body, catchError: catchError); + } + + static Future _doRequest(String method, String url, + {Map? body, required bool catchError}) async { + yjPrint("[RequestManager req]: $method 【$url】body === $body"); + + try { + final resp = await _c.request(url, + data: body, + options: Options( + method: method, + headers: {"authorization": "Bearer ${AppManager.getUserToken()}"})); + yjPrint("[RequestManager resp]: $method 【$url】body === $resp"); + if (catchError) { + if (resp.statusCode == kNeedLoginCode) { + AppManager.gotoLogin(); + return null; + } + if (resp.statusCode != kSuccessCode) { + _alertError("提示", resp.data ?? "未知错误"); + return null; + } + } + return resp.data; + } catch (e) { + yjPrint("[RequestManager error]: $method 【$url】error === $e"); + // _alertError("网络错误", "请检查您的网络连接!"); + return null; + } + } + + static _alertError(String title, String errorText) { + Utils.alert(AppManager.globalContext!, errorText, title: title); + } +} \ No newline at end of file diff --git a/lib/common/utils/utils.dart b/lib/common/utils/utils.dart new file mode 100644 index 0000000..3482ddf --- /dev/null +++ b/lib/common/utils/utils.dart @@ -0,0 +1,47 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; + +import 'func_tools.dart'; + +class Utils { + ///大陆手机号码11位数,匹配格式:前三位固定格式+后8位任意数 + static bool isPhone(String phone) { + return RegExp('^1\\d{10}\$').hasMatch(phone); + } + + static void toast(String? text, BuildContext? context) { + if (isEmptyString(text)) { + return; + } + Fluttertoast.showToast( + msg: "$text", + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.CENTER, + timeInSecForIosWeb: 1, + // backgroundColor: Colors.red, + // textColor: Colors.white, + fontSize: 16.0); + } + + + + static Future alert(BuildContext context, String? content, {String? title}) { + return showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(title ?? '提示'), + content: Text(content!), + actions: [ + TextButton( + child: const Text('确定'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }); + } +} \ No newline at end of file diff --git a/lib/home/home_view.dart b/lib/home/home_view.dart index bfbc414..b4909bc 100644 --- a/lib/home/home_view.dart +++ b/lib/home/home_view.dart @@ -48,12 +48,14 @@ class HomeView extends BaseUI { return Container( color: const Color(0xff1D2227), width: leftBarWidth, - child: Column( - children: _buildDestinations( - context, - provider, - leftBarWidth, - itemHeight, + child: SingleChildScrollView( + child: Column( + children: _buildDestinations( + context, + provider, + leftBarWidth, + itemHeight, + ), ), ), ); diff --git a/lib/login/login_view.dart b/lib/login/login_view.dart index 043ce4a..074056f 100644 --- a/lib/login/login_view.dart +++ b/lib/login/login_view.dart @@ -1,4 +1,8 @@ +import 'dart:convert'; +import 'dart:typed_data'; + import 'package:cashier_reserve/common/print/print.dart'; +import 'package:cashier_reserve/model/login_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -20,6 +24,35 @@ class _LoginViewState extends State { TextEditingController passwordText = TextEditingController(); TextEditingController codeText = TextEditingController(); + String authCodeUuid = ""; + String authCodeImg = ""; + + @override + void initState() { + super.initState(); + + _loadAuthCode(); + } + + void _loadAuthCode() async { + var res = await LoginModel.getLoginAuthCode(); + + if (res is Map) { + Map result = res as Map; + setState(() { + authCodeUuid = result["uuid"] ?? ""; + String img = result["img"] ?? ""; + if (img.startsWith("data:image/png;base64,")) { + authCodeImg = img.substring("data:image/png;base64,".length); + } + }); + } else { + yjPrint("获取验证码失败"); + } + } + + void _goLogin() async {} + @override void dispose() { merchantText.dispose(); @@ -31,89 +64,211 @@ class _LoginViewState extends State { @override Widget build(BuildContext context) { - return Container( - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, - color: const Color(0x55000000), - child: Center( + return Scaffold( + backgroundColor: Colors.black.withOpacity(0.2), + body: GestureDetector( + onTap: () { + FocusScope.of(context).requestFocus(FocusNode()); + }, child: Container( - padding: const EdgeInsets.fromLTRB(30, 30, 30, 30), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - ), - width: 400, - height: 400, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "银收客订餐系统", - style: TextStyle( - fontSize: 25, - color: Color(0xff333333), - decoration: TextDecoration.none), - ) - ], + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + color: const Color(0x55000000), + child: Center( + child: Container( + padding: const EdgeInsets.fromLTRB(30, 30, 30, 30), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), ), - const SizedBox( - height: 30, - ), - CupertinoSegmentedControl( - //子标签 - children: { - 0: Container( - width: 60, - height: 30, - alignment: Alignment.center, - child: const Text( - "商户", - style: TextStyle( - fontSize: 14, - // color: Color(0xff333333), - decoration: TextDecoration.none), + width: 400, + // height: 400, + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTitle(context), + const SizedBox( + height: 30, ), - ), - 1: Container( - width: 60, - height: 30, - alignment: Alignment.center, - child: const Text( - "员工", - style: TextStyle( - fontSize: 14, - // color: Color(0xff333333), - decoration: TextDecoration.none), + _buildSegment(context), + const SizedBox( + height: 5, ), - ), - }, - //当前选中的索引 - groupValue: segmentIndex, - //点击回调 - onValueChanged: (int index) { - setState(() { - segmentIndex = index; - loginType = index == 0 ? "merchant" : "staff"; - }); - }, - selectedColor: Colors.blue, - borderColor: Colors.blue, - unselectedColor: Colors.white, + _buildInputTextField(context, merchantText, + hintText: "请输入商户号", + icon: Icons.store_sharp, + isHidden: loginType == "merchant"), + _buildInputTextField(context, accountText, + hintText: "请输入账号", icon: Icons.people), + _buildInputTextField(context, passwordText, + hintText: "请输入密码", icon: Icons.lock, isPassword: true), + _buildInputTextField(context, codeText, + hintText: "请输入验证码", + icon: Icons.admin_panel_settings_sharp, + isCode: true), + _buildLoginBtn(context), + ], + ), ), - const SizedBox( - height: 5, - ), - // TextField( - // controller: merchantText, - // ) - ], + ), ), ), ), ); } + + Widget _buildLoginBtn(BuildContext context) { + return InkWell( + onTap: () { + _goLogin(); + }, + child: Container( + margin: const EdgeInsets.only(top: 25), + height: 35, + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(5), + ), + child: const Center( + child: Text( + "登录", + style: TextStyle(fontSize: 15, color: Colors.white), + ), + ), + ), + ); + } + + Widget _buildTitle(BuildContext context) { + return const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "银收客订餐系统", + style: TextStyle( + fontSize: 25, + color: Color(0xff333333), + decoration: TextDecoration.none), + ) + ], + ); + } + + Widget _buildSegment(BuildContext context) { + return CupertinoSegmentedControl( + //子标签 + children: { + 0: Container( + width: 60, + height: 30, + alignment: Alignment.center, + child: const Text( + "商户", + style: TextStyle( + fontSize: 14, + // color: Color(0xff333333), + decoration: TextDecoration.none), + ), + ), + 1: Container( + width: 60, + height: 30, + alignment: Alignment.center, + child: const Text( + "员工", + style: TextStyle( + fontSize: 14, + // color: Color(0xff333333), + decoration: TextDecoration.none), + ), + ), + }, + //当前选中的索引 + groupValue: segmentIndex, + //点击回调 + onValueChanged: (int index) { + setState(() { + segmentIndex = index; + loginType = index == 0 ? "merchant" : "staff"; + }); + }, + selectedColor: Colors.blue, + borderColor: Colors.blue, + unselectedColor: Colors.white, + ); + } + + Widget _buildInputTextField( + BuildContext context, + TextEditingController controller, { + String hintText = "", + IconData icon = Icons.people, + bool isPassword = false, + bool isHidden = false, + bool isCode = false, + }) { + if (isHidden) { + return Container(); + } + return Column( + children: [ + const SizedBox( + height: 10, + ), + Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + border: Border.all(color: const Color(0xffefefef), width: 1), + borderRadius: BorderRadius.circular(5), + ), + padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 35, + child: TextField( + controller: controller, + obscureText: isPassword, + decoration: InputDecoration( + icon: Icon( + icon, + color: const Color(0xffa6a6a6), + ), + hintText: hintText, + hintStyle: const TextStyle( + fontSize: 14, + color: Color(0xff999999), + ), + contentPadding: EdgeInsets.zero, + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(5), + ), + ), + ), + ), + ), + if (isCode) + InkWell( + onTap: () { + _loadAuthCode(); + }, + child: Container( + margin: const EdgeInsets.only(left: 15), + width: 100, + height: 35, + child: Image.memory(base64ToUint8List(authCodeImg)), + ), + ) + ], + ), + ], + ); + } + + Uint8List base64ToUint8List(String base64String) { + const decoder = Base64Decoder(); + return decoder.convert(base64String); + } } diff --git a/lib/model/login_model.dart b/lib/model/login_model.dart new file mode 100644 index 0000000..fa20154 --- /dev/null +++ b/lib/model/login_model.dart @@ -0,0 +1,11 @@ +import 'package:cashier_reserve/common/print/print.dart'; +import 'package:cashier_reserve/common/request/request_manager.dart'; + +class LoginModel { + + /// 获取 登录验证码 + static Future getLoginAuthCode() async { + final r = await RequestManager.get("/auth/code"); + return r; + } +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 2158b2f..4981742 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -221,6 +221,19 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + sha256: "95f349437aeebe524ef7d6c9bde3e6b4772717cf46a0eb6a3ceaddc740b297cc" + url: "https://pub.flutter-io.cn" + source: hosted + version: "8.2.8" glob: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e87b1d3..93336ea 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,6 +45,7 @@ dependencies: hive: ^4.0.0-dev.2 isar_flutter_libs: ^4.0.0-dev.13 path_provider: ^2.1.0 + fluttertoast: ^8.2.8 dev_dependencies: flutter_test: