diff --git a/lib/common/encrypt/pwd.dart b/lib/common/encrypt/pwd.dart new file mode 100644 index 0000000..ca14e70 --- /dev/null +++ b/lib/common/encrypt/pwd.dart @@ -0,0 +1,45 @@ + +import 'package:cashier_reserve/common/print/print.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; + +class PwdEncrypt { + static const _rsaPubKey = + "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ=="; + + static String encrypt(String pwd) { + return _encryptString(publicKeyString: _rsaPubKey, plainText: pwd); + } + + /// 利用公钥进行加密 + static String _encryptString( + {required String publicKeyString, required String plainText}) { + String key = '-----BEGIN PUBLIC KEY-----\n\r'; + int length = 0; + const baseLen = 64; + while (length < publicKeyString.length) { + bool over = length + baseLen > publicKeyString.length; + key += publicKeyString.substring( + length, over ? publicKeyString.length : length + baseLen); + key += '\n\r'; + length += baseLen; + } + key += '-----END PUBLIC KEY-----'; + + yjPrint(key); + + final publicKey = _parsePublicKeyFromPem(key); + + final encrypt = Encrypter(RSA(publicKey: publicKey)); + + final encryptedText = encrypt.encrypt(plainText); + + return encryptedText.base64; + } + + /// 通过PEM字符串解析公钥字符串 + static RSAPublicKey _parsePublicKeyFromPem(String pemString) { + final key = RSAKeyParser().parse(pemString); + return key as RSAPublicKey; + } +} diff --git a/lib/common/manager/app_manager.dart b/lib/common/manager/app_manager.dart index d658a9c..377186d 100644 --- a/lib/common/manager/app_manager.dart +++ b/lib/common/manager/app_manager.dart @@ -1,4 +1,5 @@ import 'package:cashier_reserve/common/push/push.dart'; +import 'package:cashier_reserve/datas/login/login_result.dart'; import 'package:cashier_reserve/login/login_view.dart'; import '../base/ui.dart'; @@ -40,14 +41,6 @@ class AppManager { } 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() { @@ -61,4 +54,15 @@ class AppManager { static String getUserToken() { return HiveManager.getUserToken(); } + + static void loginSuccess(LoginResult? r) { + HiveManager.setUserToken(r?.token ?? ''); + HiveManager.setShopId((r?.shopId ?? '').toString()); + HiveManager.setShopName(r?.shopName ?? ''); + HiveManager.setShopLogo(r?.logo ?? ''); + HiveManager.setUserInfo(r?.user?.toString() ?? ''); + + disposeLoginWidget(); + Navigator.of(globalContext!).pop(); + } } diff --git a/lib/common/manager/hive_manager.dart b/lib/common/manager/hive_manager.dart index c507bd1..7fbce26 100644 --- a/lib/common/manager/hive_manager.dart +++ b/lib/common/manager/hive_manager.dart @@ -11,7 +11,51 @@ class HiveManager { _userInfoBox = Hive.box(); } + static void clearLoginInfo() { + _userInfoBox?.delete('token'); + _userInfoBox?.delete('shopId'); + _userInfoBox?.delete('shopName'); + _userInfoBox?.delete('shopLogo'); + _userInfoBox?.delete('userInfo'); + } + + static void setUserToken(String token) { + _userInfoBox?.put('token', token); + } + static String getUserToken() { return _userInfoBox?.get('token') ?? ''; } + + static void setShopId(String shopId) { + _userInfoBox?.put('shopId', shopId); + } + + static String getShopId() { + return _userInfoBox?.get('shopId') ?? ''; + } + + static void setShopName(String shopName) { + _userInfoBox?.put('shopName', shopName); + } + + static String getShopName() { + return _userInfoBox?.get('shopName') ?? ''; + } + + static void setShopLogo(String shopLogo) { + _userInfoBox?.put('shopLogo', shopLogo); + } + + static String getShopLogo() { + return _userInfoBox?.get('shopLogo') ?? ''; + } + + static void setUserInfo(String userInfo) { + _userInfoBox?.put('userInfo', userInfo); + } + + static String getUserInfo() { + return _userInfoBox?.get('userInfo') ?? ''; + } } diff --git a/lib/common/request/request_manager.dart b/lib/common/request/request_manager.dart index 59257c8..2ed63b7 100644 --- a/lib/common/request/request_manager.dart +++ b/lib/common/request/request_manager.dart @@ -1,4 +1,5 @@ import 'package:cashier_reserve/common/manager/app_manager.dart'; +import 'package:cashier_reserve/common/manager/hive_manager.dart'; import 'package:cashier_reserve/common/print/print.dart'; import 'package:dio/dio.dart'; @@ -20,6 +21,11 @@ class RequestManager { /// GET static Future get(String url, {bool catchError = true}) { + if (url.contains("?")) { + url += "&shopId=${HiveManager.getShopId()}"; + } else { + url += "?shopId=${HiveManager.getShopId()}"; + } return _doRequest("GET", url, catchError: catchError); } @@ -31,12 +37,22 @@ class RequestManager { /// POST static Future post(String url, Map? body, {bool catchError = true}) { + if (body != null) { + body["shopId"] = HiveManager.getShopId(); + } else { + body = {"shopId": HiveManager.getShopId()}; + } return _doRequest("POST", url, body: body, catchError: catchError); } /// PUT static Future put(String url, Map? body, {bool catchError = true}) { + if (body != null) { + body["shopId"] = HiveManager.getShopId(); + } else { + body = {"shopId": HiveManager.getShopId()}; + } return _doRequest("PUT", url, body: body, catchError: catchError); } @@ -49,7 +65,8 @@ class RequestManager { data: body, options: Options( method: method, - headers: {"authorization": "Bearer ${AppManager.getUserToken()}"})); + headers: {"authorization": "Bearer ${AppManager.getUserToken()}"} + )); yjPrint("[RequestManager resp]: $method 【$url】body === $resp"); if (catchError) { if (resp.statusCode == kNeedLoginCode) { @@ -65,6 +82,17 @@ class RequestManager { } catch (e) { yjPrint("[RequestManager error]: $method 【$url】error === $e"); // _alertError("网络错误", "请检查您的网络连接!"); + if (e is DioException) { + DioException de = e; + if (de.response?.statusCode == kNeedLoginCode) { + AppManager.gotoLogin(); + return null; + } + if (de.response?.data is Map) { + final data = de.response!.data as Map; + Utils.toast(data["message"], AppManager.globalContext!); + } + } return null; } } diff --git a/lib/datas/login/login_result.dart b/lib/datas/login/login_result.dart new file mode 100644 index 0000000..a4e5977 --- /dev/null +++ b/lib/datas/login/login_result.dart @@ -0,0 +1,606 @@ +import 'dart:convert'; + +/// loginType : "merchant" +/// shopName : "双屿pirse(测77)" +/// logo : "https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240925/835c45e4729048e8921ba17d021029ec.jpg" +/// shopId : 11 +/// mainId : 11 +/// user : {"authorities":[{"authority":"tbProductGroup:del"},{"authority":"tbProductGroup:list"},{"authority":"roles:add"},{"authority":"roles:edit"},{"authority":"roles:del"},{"authority":"tbShopTable:list"},{"authority":"roles:list"}],"dataScopes":[18],"roles":["tbProductGroup:del","tbProductGroup:list","roles:add","roles:edit","roles:del","tbShopTable:list","roles:list"],"user":{"avatarName":null,"avatarPath":null,"createBy":"admin","createTime":"2024-05-27 14:10:09","dept":{"id":18,"name":"前厅"},"deptId":null,"email":null,"enabled":true,"gender":null,"id":40,"isAdmin":false,"jobs":[{"id":10,"name":"产品经理"}],"nickName":"双屿pirse(测77)","password":"$2a$10$j414tLJ/fdXXzXriW3y9A.QdP9Ak1.1hiGbvb1.zmQjPc5q.xoipy","phone":"13575788745","pwdResetTime":"2024-08-05 14:18:59","roles":[{"dataScope":"本级","id":2,"level":2,"name":"普通用户"}],"updateBy":"admin","updateTime":"2024-05-27 14:10:09","username":"13718478323"}} +/// token : "Bearer eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiI3ZWYzZmU2NWM0ZDU0ZjE5OWU5YmE4NTQ1NmUyZDZiZiIsInVzZXIiOiIxMzcxODQ3ODMyMyIsInNob3BJZCI6IjExIiwic3ViIjoiMTM3MTg0NzgzMjMifQ.9DY1f02WGTJ2e5w1MFJrUQ4KwEvl-QKWsSRALvpYYo6EsA3NercZAN56xL68e8K0eSsArk-9i1LFxb-PtBwmgw" + +LoginResult loginResultFromJson(String str) => + LoginResult.fromJson(json.decode(str)); + +String loginResultToJson(LoginResult data) => json.encode(data.toJson()); + +class LoginResult { + LoginResult({ + String? loginType, + String? shopName, + String? logo, + num? shopId, + num? mainId, + User? user, + String? token, + }) { + _loginType = loginType; + _shopName = shopName; + _logo = logo; + _shopId = shopId; + _mainId = mainId; + _user = user; + _token = token; + } + + LoginResult.fromJson(dynamic json) { + _loginType = json['loginType']; + _shopName = json['shopName']; + _logo = json['logo']; + _shopId = json['shopId']; + _mainId = json['mainId']; + _user = json['user'] != null ? User.fromJson(json['user']) : null; + _token = json['token']; + } + + String? _loginType; + String? _shopName; + String? _logo; + num? _shopId; + num? _mainId; + User? _user; + String? _token; + + LoginResult copyWith({ + String? loginType, + String? shopName, + String? logo, + num? shopId, + num? mainId, + User? user, + String? token, + }) => + LoginResult( + loginType: loginType ?? _loginType, + shopName: shopName ?? _shopName, + logo: logo ?? _logo, + shopId: shopId ?? _shopId, + mainId: mainId ?? _mainId, + user: user ?? _user, + token: token ?? _token, + ); + + String? get loginType => _loginType; + + String? get shopName => _shopName; + + String? get logo => _logo; + + num? get shopId => _shopId; + + num? get mainId => _mainId; + + User? get user => _user; + + String? get token => _token; + + Map toJson() { + final map = {}; + map['loginType'] = _loginType; + map['shopName'] = _shopName; + map['logo'] = _logo; + map['shopId'] = _shopId; + map['mainId'] = _mainId; + if (_user != null) { + map['user'] = _user?.toJson(); + } + map['token'] = _token; + return map; + } +} + +/// authorities : [{"authority":"tbProductGroup:del"},{"authority":"tbProductGroup:list"},{"authority":"roles:add"},{"authority":"roles:edit"},{"authority":"roles:del"},{"authority":"tbShopTable:list"},{"authority":"roles:list"}] +/// dataScopes : [18] +/// roles : ["tbProductGroup:del","tbProductGroup:list","roles:add","roles:edit","roles:del","tbShopTable:list","roles:list"] +/// user : {"avatarName":null,"avatarPath":null,"createBy":"admin","createTime":"2024-05-27 14:10:09","dept":{"id":18,"name":"前厅"},"deptId":null,"email":null,"enabled":true,"gender":null,"id":40,"isAdmin":false,"jobs":[{"id":10,"name":"产品经理"}],"nickName":"双屿pirse(测77)","password":"$2a$10$j414tLJ/fdXXzXriW3y9A.QdP9Ak1.1hiGbvb1.zmQjPc5q.xoipy","phone":"13575788745","pwdResetTime":"2024-08-05 14:18:59","roles":[{"dataScope":"本级","id":2,"level":2,"name":"普通用户"}],"updateBy":"admin","updateTime":"2024-05-27 14:10:09","username":"13718478323"} + +User userFromJson(String str) => User.fromJson(json.decode(str)); + +String userToJson(User data) => json.encode(data.toJson()); + +class User { + User({ + List? authorities, + List? dataScopes, + List? roles, + UserInfo? userInfo, + }) { + _authorities = authorities; + _dataScopes = dataScopes; + _roles = roles; + _userInfo = userInfo; + } + + User.fromJson(dynamic json) { + if (json['authorities'] != null) { + _authorities = []; + json['authorities'].forEach((v) { + _authorities?.add(Authorities.fromJson(v)); + }); + } + _dataScopes = + json['dataScopes'] != null ? json['dataScopes'].cast() : []; + _roles = json['roles'] != null ? json['roles'].cast() : []; + _userInfo = json['user'] != null ? UserInfo.fromJson(json['user']) : null; + } + + List? _authorities; + List? _dataScopes; + List? _roles; + UserInfo? _userInfo; + + User copyWith({ + List? authorities, + List? dataScopes, + List? roles, + UserInfo? userInfo, + }) => + User( + authorities: authorities ?? _authorities, + dataScopes: dataScopes ?? _dataScopes, + roles: roles ?? _roles, + userInfo: userInfo ?? _userInfo, + ); + + List? get authorities => _authorities; + + List? get dataScopes => _dataScopes; + + List? get roles => _roles; + + UserInfo? get userInfo => _userInfo; + + Map toJson() { + final map = {}; + if (_authorities != null) { + map['authorities'] = _authorities?.map((v) => v.toJson()).toList(); + } + map['dataScopes'] = _dataScopes; + map['roles'] = _roles; + if (_userInfo != null) { + map['user'] = _userInfo?.toJson(); + } + return map; + } +} + +/// avatarName : null +/// avatarPath : null +/// createBy : "admin" +/// createTime : "2024-05-27 14:10:09" +/// dept : {"id":18,"name":"前厅"} +/// deptId : null +/// email : null +/// enabled : true +/// gender : null +/// id : 40 +/// isAdmin : false +/// jobs : [{"id":10,"name":"产品经理"}] +/// nickName : "双屿pirse(测77)" +/// password : "$2a$10$j414tLJ/fdXXzXriW3y9A.QdP9Ak1.1hiGbvb1.zmQjPc5q.xoipy" +/// phone : "13575788745" +/// pwdResetTime : "2024-08-05 14:18:59" +/// roles : [{"dataScope":"本级","id":2,"level":2,"name":"普通用户"}] +/// updateBy : "admin" +/// updateTime : "2024-05-27 14:10:09" +/// username : "13718478323" + +User userInfoFromJson(String str) => User.fromJson(json.decode(str)); + +String userInfoToJson(User data) => json.encode(data.toJson()); + +class UserInfo { + UserInfo({ + dynamic avatarName, + dynamic avatarPath, + String? createBy, + String? createTime, + Dept? dept, + dynamic deptId, + dynamic email, + bool? enabled, + dynamic gender, + num? id, + bool? isAdmin, + List? jobs, + String? nickName, + String? password, + String? phone, + String? pwdResetTime, + List? roles, + String? updateBy, + String? updateTime, + String? username, + }) { + _avatarName = avatarName; + _avatarPath = avatarPath; + _createBy = createBy; + _createTime = createTime; + _dept = dept; + _deptId = deptId; + _email = email; + _enabled = enabled; + _gender = gender; + _id = id; + _isAdmin = isAdmin; + _jobs = jobs; + _nickName = nickName; + _password = password; + _phone = phone; + _pwdResetTime = pwdResetTime; + _roles = roles; + _updateBy = updateBy; + _updateTime = updateTime; + _username = username; + } + + UserInfo.fromJson(dynamic json) { + _avatarName = json['avatarName']; + _avatarPath = json['avatarPath']; + _createBy = json['createBy']; + _createTime = json['createTime']; + _dept = json['dept'] != null ? Dept.fromJson(json['dept']) : null; + _deptId = json['deptId']; + _email = json['email']; + _enabled = json['enabled']; + _gender = json['gender']; + _id = json['id']; + _isAdmin = json['isAdmin']; + if (json['jobs'] != null) { + _jobs = []; + json['jobs'].forEach((v) { + _jobs?.add(Jobs.fromJson(v)); + }); + } + _nickName = json['nickName']; + _password = json['password']; + _phone = json['phone']; + _pwdResetTime = json['pwdResetTime']; + if (json['roles'] != null) { + _roles = []; + json['roles'].forEach((v) { + _roles?.add(Roles.fromJson(v)); + }); + } + _updateBy = json['updateBy']; + _updateTime = json['updateTime']; + _username = json['username']; + } + + dynamic _avatarName; + dynamic _avatarPath; + String? _createBy; + String? _createTime; + Dept? _dept; + dynamic _deptId; + dynamic _email; + bool? _enabled; + dynamic _gender; + num? _id; + bool? _isAdmin; + List? _jobs; + String? _nickName; + String? _password; + String? _phone; + String? _pwdResetTime; + List? _roles; + String? _updateBy; + String? _updateTime; + String? _username; + + UserInfo copyWith({ + dynamic avatarName, + dynamic avatarPath, + String? createBy, + String? createTime, + Dept? dept, + dynamic deptId, + dynamic email, + bool? enabled, + dynamic gender, + num? id, + bool? isAdmin, + List? jobs, + String? nickName, + String? password, + String? phone, + String? pwdResetTime, + List? roles, + String? updateBy, + String? updateTime, + String? username, + }) => + UserInfo( + avatarName: avatarName ?? _avatarName, + avatarPath: avatarPath ?? _avatarPath, + createBy: createBy ?? _createBy, + createTime: createTime ?? _createTime, + dept: dept ?? _dept, + deptId: deptId ?? _deptId, + email: email ?? _email, + enabled: enabled ?? _enabled, + gender: gender ?? _gender, + id: id ?? _id, + isAdmin: isAdmin ?? _isAdmin, + jobs: jobs ?? _jobs, + nickName: nickName ?? _nickName, + password: password ?? _password, + phone: phone ?? _phone, + pwdResetTime: pwdResetTime ?? _pwdResetTime, + roles: roles ?? _roles, + updateBy: updateBy ?? _updateBy, + updateTime: updateTime ?? _updateTime, + username: username ?? _username, + ); + + dynamic get avatarName => _avatarName; + + dynamic get avatarPath => _avatarPath; + + String? get createBy => _createBy; + + String? get createTime => _createTime; + + Dept? get dept => _dept; + + dynamic get deptId => _deptId; + + dynamic get email => _email; + + bool? get enabled => _enabled; + + dynamic get gender => _gender; + + num? get id => _id; + + bool? get isAdmin => _isAdmin; + + List? get jobs => _jobs; + + String? get nickName => _nickName; + + String? get password => _password; + + String? get phone => _phone; + + String? get pwdResetTime => _pwdResetTime; + + List? get roles => _roles; + + String? get updateBy => _updateBy; + + String? get updateTime => _updateTime; + + String? get username => _username; + + Map toJson() { + final map = {}; + map['avatarName'] = _avatarName; + map['avatarPath'] = _avatarPath; + map['createBy'] = _createBy; + map['createTime'] = _createTime; + if (_dept != null) { + map['dept'] = _dept?.toJson(); + } + map['deptId'] = _deptId; + map['email'] = _email; + map['enabled'] = _enabled; + map['gender'] = _gender; + map['id'] = _id; + map['isAdmin'] = _isAdmin; + if (_jobs != null) { + map['jobs'] = _jobs?.map((v) => v.toJson()).toList(); + } + map['nickName'] = _nickName; + map['password'] = _password; + map['phone'] = _phone; + map['pwdResetTime'] = _pwdResetTime; + if (_roles != null) { + map['roles'] = _roles?.map((v) => v.toJson()).toList(); + } + map['updateBy'] = _updateBy; + map['updateTime'] = _updateTime; + map['username'] = _username; + return map; + } +} + +/// dataScope : "本级" +/// id : 2 +/// level : 2 +/// name : "普通用户" + +Roles rolesFromJson(String str) => Roles.fromJson(json.decode(str)); + +String rolesToJson(Roles data) => json.encode(data.toJson()); + +class Roles { + Roles({ + String? dataScope, + num? id, + num? level, + String? name, + }) { + _dataScope = dataScope; + _id = id; + _level = level; + _name = name; + } + + Roles.fromJson(dynamic json) { + _dataScope = json['dataScope']; + _id = json['id']; + _level = json['level']; + _name = json['name']; + } + + String? _dataScope; + num? _id; + num? _level; + String? _name; + + Roles copyWith({ + String? dataScope, + num? id, + num? level, + String? name, + }) => + Roles( + dataScope: dataScope ?? _dataScope, + id: id ?? _id, + level: level ?? _level, + name: name ?? _name, + ); + + String? get dataScope => _dataScope; + + num? get id => _id; + + num? get level => _level; + + String? get name => _name; + + Map toJson() { + final map = {}; + map['dataScope'] = _dataScope; + map['id'] = _id; + map['level'] = _level; + map['name'] = _name; + return map; + } +} + +/// id : 10 +/// name : "产品经理" + +Jobs jobsFromJson(String str) => Jobs.fromJson(json.decode(str)); + +String jobsToJson(Jobs data) => json.encode(data.toJson()); + +class Jobs { + Jobs({ + num? id, + String? name, + }) { + _id = id; + _name = name; + } + + Jobs.fromJson(dynamic json) { + _id = json['id']; + _name = json['name']; + } + + num? _id; + String? _name; + + Jobs copyWith({ + num? id, + String? name, + }) => + Jobs( + id: id ?? _id, + name: name ?? _name, + ); + + num? get id => _id; + + String? get name => _name; + + Map toJson() { + final map = {}; + map['id'] = _id; + map['name'] = _name; + return map; + } +} + +/// id : 18 +/// name : "前厅" + +Dept deptFromJson(String str) => Dept.fromJson(json.decode(str)); + +String deptToJson(Dept data) => json.encode(data.toJson()); + +class Dept { + Dept({ + num? id, + String? name, + }) { + _id = id; + _name = name; + } + + Dept.fromJson(dynamic json) { + _id = json['id']; + _name = json['name']; + } + + num? _id; + String? _name; + + Dept copyWith({ + num? id, + String? name, + }) => + Dept( + id: id ?? _id, + name: name ?? _name, + ); + + num? get id => _id; + + String? get name => _name; + + Map toJson() { + final map = {}; + map['id'] = _id; + map['name'] = _name; + return map; + } +} + +/// authority : "tbProductGroup:del" + +Authorities authoritiesFromJson(String str) => + Authorities.fromJson(json.decode(str)); + +String authoritiesToJson(Authorities data) => json.encode(data.toJson()); + +class Authorities { + Authorities({ + String? authority, + }) { + _authority = authority; + } + + Authorities.fromJson(dynamic json) { + _authority = json['authority']; + } + + String? _authority; + + Authorities copyWith({ + String? authority, + }) => + Authorities( + authority: authority ?? _authority, + ); + + String? get authority => _authority; + + Map toJson() { + final map = {}; + map['authority'] = _authority; + return map; + } +} diff --git a/lib/datas/reserve/table_area_model.dart b/lib/datas/reserve/table_area_model.dart new file mode 100644 index 0000000..d33c53a --- /dev/null +++ b/lib/datas/reserve/table_area_model.dart @@ -0,0 +1,117 @@ +import 'dart:convert'; + +/// capacityRange : null +/// createdAt : 1716791935255 +/// id : 20 +/// name : "大厅" +/// price : null +/// shopId : 11 +/// sort : 0 +/// updatedAt : 1716791935255 +/// view : null + +TableAreaModel tableAreaModelFromJson(String str) => + TableAreaModel.fromJson(json.decode(str)); + +String tableAreaModelToJson(TableAreaModel data) => json.encode(data.toJson()); + +class TableAreaModel { + TableAreaModel({ + dynamic capacityRange, + num? createdAt, + num? id, + String? name, + dynamic price, + num? shopId, + num? sort, + num? updatedAt, + dynamic view, + }) { + _capacityRange = capacityRange; + _createdAt = createdAt; + _id = id; + _name = name; + _price = price; + _shopId = shopId; + _sort = sort; + _updatedAt = updatedAt; + _view = view; + } + + TableAreaModel.fromJson(dynamic json) { + _capacityRange = json['capacityRange']; + _createdAt = json['createdAt']; + _id = json['id']; + _name = json['name']; + _price = json['price']; + _shopId = json['shopId']; + _sort = json['sort']; + _updatedAt = json['updatedAt']; + _view = json['view']; + } + + dynamic _capacityRange; + num? _createdAt; + num? _id; + String? _name; + dynamic _price; + num? _shopId; + num? _sort; + num? _updatedAt; + dynamic _view; + + TableAreaModel copyWith({ + dynamic capacityRange, + num? createdAt, + num? id, + String? name, + dynamic price, + num? shopId, + num? sort, + num? updatedAt, + dynamic view, + }) => + TableAreaModel( + capacityRange: capacityRange ?? _capacityRange, + createdAt: createdAt ?? _createdAt, + id: id ?? _id, + name: name ?? _name, + price: price ?? _price, + shopId: shopId ?? _shopId, + sort: sort ?? _sort, + updatedAt: updatedAt ?? _updatedAt, + view: view ?? _view, + ); + + dynamic get capacityRange => _capacityRange; + + num? get createdAt => _createdAt; + + num? get id => _id; + + String? get name => _name; + + dynamic get price => _price; + + num? get shopId => _shopId; + + num? get sort => _sort; + + num? get updatedAt => _updatedAt; + + dynamic get view => _view; + + Map toJson() { + final map = {}; + map['capacityRange'] = _capacityRange; + map['createdAt'] = _createdAt; + map['id'] = _id; + map['name'] = _name; + map['price'] = _price; + map['shopId'] = _shopId; + map['sort'] = _sort; + map['updatedAt'] = _updatedAt; + map['view'] = _view; + return map; + } +} diff --git a/lib/home/reserve_view.dart b/lib/home/reserve_view.dart index 0a15701..054e745 100644 --- a/lib/home/reserve_view.dart +++ b/lib/home/reserve_view.dart @@ -62,7 +62,9 @@ class ReserveView extends BaseUI { width: 5, ), InkWell( - onTap: () {}, + onTap: () { + provider.loadTableAreaList(); + }, child: SizedBox( width: 40, height: 40, diff --git a/lib/home/reserve_view_model.dart b/lib/home/reserve_view_model.dart index 24f3d31..a4f1960 100644 --- a/lib/home/reserve_view_model.dart +++ b/lib/home/reserve_view_model.dart @@ -3,6 +3,7 @@ import 'package:cashier_reserve/common/channel/call_log_model.dart'; import 'package:cashier_reserve/common/channel/channel_manager.dart'; import 'package:cashier_reserve/common/manager/event_manager.dart'; import 'package:cashier_reserve/common/print/print.dart'; +import 'package:cashier_reserve/model/reserve_model.dart'; class ReserveViewModel extends BaseUIModel { Map weekdayMap = { @@ -35,12 +36,19 @@ class ReserveViewModel extends BaseUIModel { }); loadCallLog(); + loadTableAreaList(); } void loadCallLog() { ChannelManager.getCallLog("getCallLog"); } + void loadTableAreaList() async { + final r = await ReserveModel.getShopTableAreaList(); + + yjPrint(r); + } + String getCurrentDate() { DateTime now = DateTime.now(); return "${now.year}/${now.month}/${now.day}"; diff --git a/lib/login/login_view.dart b/lib/login/login_view.dart index 074056f..efd498e 100644 --- a/lib/login/login_view.dart +++ b/lib/login/login_view.dart @@ -1,10 +1,14 @@ import 'dart:convert'; import 'dart:typed_data'; +import 'package:cashier_reserve/common/encrypt/pwd.dart'; +import 'package:cashier_reserve/common/manager/app_manager.dart'; import 'package:cashier_reserve/common/print/print.dart'; +import 'package:cashier_reserve/common/utils/utils.dart'; import 'package:cashier_reserve/model/login_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; class LoginView extends StatefulWidget { const LoginView({super.key}); @@ -26,11 +30,15 @@ class _LoginViewState extends State { String authCodeUuid = ""; String authCodeImg = ""; + DateTime? lastPopTime; @override void initState() { super.initState(); + accountText.text = "13718478323"; + passwordText.text = "123456789"; + _loadAuthCode(); } @@ -51,7 +59,52 @@ class _LoginViewState extends State { } } - void _goLogin() async {} + void _goLogin() async { + if (loginType == "staff") { + if (merchantText.text.isEmpty) { + Utils.toast("请输入商户号", context); + return; + } + } + + if (accountText.text.isEmpty) { + Utils.toast("请输入账号", context); + return; + } + + if (passwordText.text.isEmpty) { + Utils.toast("请输入密码", context); + return; + } + + if (codeText.text.isEmpty) { + Utils.toast("请输入验证码", context); + return; + } + + String pwd = PwdEncrypt.encrypt(passwordText.text); + yjPrint("pwd === $pwd"); + + var params = { + "username": accountText.text, + "password": pwd, + "code": codeText.text, + "uuid": authCodeUuid, + "loginType": loginType, + }; + + if (loginType == "staff") { + params["loginType"] = "staff"; + params["merchantName"] = merchantText.text; + } + + final r = await LoginModel.login(params); + if (r == null) { + _loadAuthCode(); + return; + } + AppManager.loginSuccess(r); + } @override void dispose() { @@ -64,52 +117,69 @@ class _LoginViewState extends State { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.black.withOpacity(0.2), - body: GestureDetector( - onTap: () { - FocusScope.of(context).requestFocus(FocusNode()); - }, - child: Container( - 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), - ), - width: 400, - // height: 400, - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildTitle(context), - const SizedBox( - height: 30, - ), - _buildSegment(context), - const SizedBox( - height: 5, - ), - _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), - ], + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) async { + // 点击返回键的操作 + if (lastPopTime == null || + DateTime.now().difference(lastPopTime!) > const Duration(seconds: 2)) { + lastPopTime = DateTime.now(); + Utils.toast('再按一次退出', context); + } else { + lastPopTime = DateTime.now(); + // 退出app + await SystemChannels.platform.invokeMethod('SystemNavigator.pop'); + } + }, + child: Scaffold( + backgroundColor: Colors.black.withOpacity(0.2), + body: GestureDetector( + onTap: () { + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + 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), + ), + width: 400, + // height: 400, + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTitle(context), + const SizedBox( + height: 30, + ), + _buildSegment(context), + const SizedBox( + height: 5, + ), + _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), + ], + ), ), ), ), @@ -258,7 +328,9 @@ class _LoginViewState extends State { margin: const EdgeInsets.only(left: 15), width: 100, height: 35, - child: Image.memory(base64ToUint8List(authCodeImg)), + child: (authCodeImg.isNotEmpty) + ? Image.memory(base64ToUint8List(authCodeImg)) + : Container(), ), ) ], diff --git a/lib/model/login_model.dart b/lib/model/login_model.dart index fa20154..93ceb41 100644 --- a/lib/model/login_model.dart +++ b/lib/model/login_model.dart @@ -1,6 +1,7 @@ -import 'package:cashier_reserve/common/print/print.dart'; import 'package:cashier_reserve/common/request/request_manager.dart'; +import 'package:cashier_reserve/datas/login/login_result.dart'; +/// LoginModel 登录相关请求 class LoginModel { /// 获取 登录验证码 @@ -8,4 +9,9 @@ class LoginModel { final r = await RequestManager.get("/auth/code"); return r; } + + static Future login(Map params) async { + final r = await RequestManager.post("/auth/login", params); + return r == null ? null : LoginResult.fromJson(r); + } } \ No newline at end of file diff --git a/lib/model/reserve_model.dart b/lib/model/reserve_model.dart new file mode 100644 index 0000000..0ffd19a --- /dev/null +++ b/lib/model/reserve_model.dart @@ -0,0 +1,18 @@ +import 'package:cashier_reserve/common/request/request_manager.dart'; +import 'package:cashier_reserve/datas/reserve/table_area_model.dart'; + +/// ReserveModel 台桌预定相关请求 +class ReserveModel { + /// getShopTableAreaList 获取店铺桌台区域列表 + static Future> getShopTableAreaList() async { + final r = await RequestManager.get("/api/booking/shop-table/area"); + if (r == null) { + return []; + } + List list = []; + for (var item in r as List) { + list.add(TableAreaModel.fromJson(item)); + } + return list; + } +} \ No newline at end of file diff --git a/lib/root_view.dart b/lib/root_view.dart index 7997184..c23c681 100644 --- a/lib/root_view.dart +++ b/lib/root_view.dart @@ -1,9 +1,11 @@ import 'package:cashier_reserve/common/manager/app_manager.dart'; import 'package:cashier_reserve/home/home_view.dart'; import 'package:cashier_reserve/home/home_view_model.dart'; +import 'package:flutter/services.dart'; import 'common/base/provider.dart'; import 'common/base/ui.dart'; +import 'common/utils/utils.dart'; class RootView extends StatefulWidget { const RootView({super.key}); @@ -16,6 +18,7 @@ class _RootView extends State with AutomaticKeepAliveClientMixin, RouteAware { @override bool get wantKeepAlive => true; + DateTime? lastPopTime; @override void didChangeDependencies() { @@ -26,13 +29,27 @@ class _RootView extends State Widget build(BuildContext context) { AppManager.setGlobalContext(context); super.build(context); - return MultiProvider( + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) async { + // 点击返回键的操作 + if (lastPopTime == null || + DateTime.now().difference(lastPopTime!) > const Duration(seconds: 2)) { + lastPopTime = DateTime.now(); + Utils.toast('再按一次退出', context); + } else { + lastPopTime = DateTime.now(); + // 退出app + await SystemChannels.platform.invokeMethod('SystemNavigator.pop'); + } + }, + child: MultiProvider( providers: [ ChangeNotifierProvider( create: (_) => HomeViewModel(), ) ], child: BaseUIController(stateWidget: HomeView()), - ); + )); } } \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 4981742..6e676bd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -30,6 +30,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.6.0" + asn1lib: + dependency: transitive + description: + name: asn1lib + sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.5.8" async: dependency: transitive description: @@ -150,6 +158,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" + encrypt: + dependency: "direct main" + description: + name: encrypt + sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.3" event_bus: dependency: "direct main" description: @@ -474,6 +490,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.1.8" + pointycastle: + dependency: "direct main" + description: + name: pointycastle + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.9.1" provider: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 93336ea..6493a7f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,8 @@ dependencies: isar_flutter_libs: ^4.0.0-dev.13 path_provider: ^2.1.0 fluttertoast: ^8.2.8 + encrypt: ^5.0.3 + pointycastle: ^3.9.1 dev_dependencies: flutter_test: