登录接口调试
This commit is contained in:
45
lib/common/encrypt/pwd.dart
Normal file
45
lib/common/encrypt/pwd.dart
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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') ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<dynamic> 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<dynamic> post(String url, Map<String, dynamic>? 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<dynamic> put(String url, Map<String, dynamic>? 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;
|
||||
}
|
||||
}
|
||||
|
||||
606
lib/datas/login/login_result.dart
Normal file
606
lib/datas/login/login_result.dart
Normal file
@@ -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<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
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>? authorities,
|
||||
List<num>? dataScopes,
|
||||
List<String>? 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<num>() : [];
|
||||
_roles = json['roles'] != null ? json['roles'].cast<String>() : [];
|
||||
_userInfo = json['user'] != null ? UserInfo.fromJson(json['user']) : null;
|
||||
}
|
||||
|
||||
List<Authorities>? _authorities;
|
||||
List<num>? _dataScopes;
|
||||
List<String>? _roles;
|
||||
UserInfo? _userInfo;
|
||||
|
||||
User copyWith({
|
||||
List<Authorities>? authorities,
|
||||
List<num>? dataScopes,
|
||||
List<String>? roles,
|
||||
UserInfo? userInfo,
|
||||
}) =>
|
||||
User(
|
||||
authorities: authorities ?? _authorities,
|
||||
dataScopes: dataScopes ?? _dataScopes,
|
||||
roles: roles ?? _roles,
|
||||
userInfo: userInfo ?? _userInfo,
|
||||
);
|
||||
|
||||
List<Authorities>? get authorities => _authorities;
|
||||
|
||||
List<num>? get dataScopes => _dataScopes;
|
||||
|
||||
List<String>? get roles => _roles;
|
||||
|
||||
UserInfo? get userInfo => _userInfo;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
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>? jobs,
|
||||
String? nickName,
|
||||
String? password,
|
||||
String? phone,
|
||||
String? pwdResetTime,
|
||||
List<Roles>? 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>? _jobs;
|
||||
String? _nickName;
|
||||
String? _password;
|
||||
String? _phone;
|
||||
String? _pwdResetTime;
|
||||
List<Roles>? _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>? jobs,
|
||||
String? nickName,
|
||||
String? password,
|
||||
String? phone,
|
||||
String? pwdResetTime,
|
||||
List<Roles>? 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<Jobs>? get jobs => _jobs;
|
||||
|
||||
String? get nickName => _nickName;
|
||||
|
||||
String? get password => _password;
|
||||
|
||||
String? get phone => _phone;
|
||||
|
||||
String? get pwdResetTime => _pwdResetTime;
|
||||
|
||||
List<Roles>? get roles => _roles;
|
||||
|
||||
String? get updateBy => _updateBy;
|
||||
|
||||
String? get updateTime => _updateTime;
|
||||
|
||||
String? get username => _username;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
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<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
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<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
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<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
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<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
map['authority'] = _authority;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
117
lib/datas/reserve/table_area_model.dart
Normal file
117
lib/datas/reserve/table_area_model.dart
Normal file
@@ -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<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,9 @@ class ReserveView extends BaseUI {
|
||||
width: 5,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
provider.loadTableAreaList();
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 40,
|
||||
height: 40,
|
||||
|
||||
@@ -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<int, String> 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}";
|
||||
|
||||
@@ -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<LoginView> {
|
||||
|
||||
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<LoginView> {
|
||||
}
|
||||
}
|
||||
|
||||
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<LoginView> {
|
||||
|
||||
@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<LoginView> {
|
||||
margin: const EdgeInsets.only(left: 15),
|
||||
width: 100,
|
||||
height: 35,
|
||||
child: Image.memory(base64ToUint8List(authCodeImg)),
|
||||
child: (authCodeImg.isNotEmpty)
|
||||
? Image.memory(base64ToUint8List(authCodeImg))
|
||||
: Container(),
|
||||
),
|
||||
)
|
||||
],
|
||||
|
||||
@@ -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<LoginResult?> login(Map<String, dynamic> params) async {
|
||||
final r = await RequestManager.post("/auth/login", params);
|
||||
return r == null ? null : LoginResult.fromJson(r);
|
||||
}
|
||||
}
|
||||
18
lib/model/reserve_model.dart
Normal file
18
lib/model/reserve_model.dart
Normal file
@@ -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<List<TableAreaModel?>> getShopTableAreaList() async {
|
||||
final r = await RequestManager.get("/api/booking/shop-table/area");
|
||||
if (r == null) {
|
||||
return [];
|
||||
}
|
||||
List<TableAreaModel?> list = [];
|
||||
for (var item in r as List) {
|
||||
list.add(TableAreaModel.fromJson(item));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -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<RootView>
|
||||
with AutomaticKeepAliveClientMixin, RouteAware {
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
DateTime? lastPopTime;
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
@@ -26,13 +29,27 @@ class _RootView extends State<RootView>
|
||||
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<HomeViewModel>(
|
||||
create: (_) => HomeViewModel(),
|
||||
)
|
||||
],
|
||||
child: BaseUIController(stateWidget: HomeView()),
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user