Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 544 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 442 B |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 721 B |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,41 @@
|
||||
import 'environment/environment.dart';
|
||||
|
||||
class API {
|
||||
static const tokenKey = 'Telephony-Manage-Token';
|
||||
|
||||
///HOST
|
||||
static String get host {
|
||||
if (DevEV.instance.dev) {
|
||||
return 'http://10.0.2.2:8088';
|
||||
} else {
|
||||
return 'https://api.yunyunwenche.com';
|
||||
}
|
||||
}
|
||||
|
||||
static String get imageHost {
|
||||
if (DevEV.instance.dev) {
|
||||
return 'http://10.0.2.2:8088';
|
||||
} else {
|
||||
return 'https://static.yunyunwenche.com';
|
||||
}
|
||||
}
|
||||
static const int networkTimeOut = 10000;
|
||||
|
||||
static String get baseURL => '$host';
|
||||
|
||||
static _Manager manager = _Manager();
|
||||
static _Pay pay = _Pay();
|
||||
}
|
||||
class _Manager {
|
||||
String get login => '/manage/login';
|
||||
String get logout => '/manage/login/logout';
|
||||
String get captcha => '/manage/captcha';
|
||||
String get info => '/manage/user/info';
|
||||
}
|
||||
|
||||
class _Pay {
|
||||
String get wxpay => '/manage/pay/wxpay';
|
||||
String get alipay => '/manage/pay/alipay';
|
||||
String get wxCallback => '/callback/wxpay/notify';
|
||||
String get aliCallback => '/callback/alipay/notify';
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
part 'login_info_model.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class LoginInfo extends Equatable {
|
||||
final String token;
|
||||
final User user;
|
||||
|
||||
factory LoginInfo.fromJson(Map<String, dynamic> json) =>
|
||||
_$LoginInfoFromJson(json);
|
||||
|
||||
const LoginInfo({
|
||||
required this.token,
|
||||
required this.user,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [token, user];
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class User extends Equatable {
|
||||
final int id;
|
||||
final String name;
|
||||
|
||||
const User({
|
||||
required this.id,
|
||||
required this.name,
|
||||
});
|
||||
|
||||
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
|
||||
|
||||
@override
|
||||
List<Object?> get props =>
|
||||
[
|
||||
id,
|
||||
name,
|
||||
];
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'login_info_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
LoginInfo _$LoginInfoFromJson(Map<String, dynamic> json) => LoginInfo(
|
||||
token: json['token'] as String,
|
||||
user: User.fromJson(json['user'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$LoginInfoToJson(LoginInfo instance) => <String, dynamic>{
|
||||
'token': instance.token,
|
||||
'user': instance.user,
|
||||
};
|
||||
|
||||
User _$UserFromJson(Map<String, dynamic> json) => User(
|
||||
id: json['id'] as int,
|
||||
name: json['name'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'name': instance.name,
|
||||
};
|
@ -0,0 +1,107 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
|
||||
import '../../constants/api.dart';
|
||||
import '../../utils/toast/cloud_toast.dart';
|
||||
import 'base_list_model.dart';
|
||||
import 'base_model.dart';
|
||||
import 'net_interceptor.dart';
|
||||
|
||||
final ApiClient apiClient = ApiClient();
|
||||
|
||||
class ApiClient {
|
||||
late Dio _dio;
|
||||
|
||||
Dio get dio => _dio;
|
||||
|
||||
ApiClient() {
|
||||
var headers = <String, dynamic>{};
|
||||
if (kIsWeb) {
|
||||
headers = {'device-type': 'web'};
|
||||
} else {
|
||||
headers = {
|
||||
'device-type': const LocalPlatform().operatingSystem.toLowerCase()
|
||||
};
|
||||
}
|
||||
|
||||
_dio = Dio()
|
||||
..options.baseUrl = API.baseURL
|
||||
..options.headers = headers
|
||||
..interceptors.add(NetworkInterceptor());
|
||||
}
|
||||
|
||||
///设置token
|
||||
Dio setToken(String token) {
|
||||
return _dio..options.headers[API.tokenKey] = token;
|
||||
}
|
||||
|
||||
///清除token
|
||||
Dio clearToken() {
|
||||
return _dio
|
||||
..options.headers.removeWhere((key, value) => key == API.tokenKey);
|
||||
}
|
||||
|
||||
///发送请求
|
||||
Future<BaseModel> request(
|
||||
String path, {
|
||||
dynamic data,
|
||||
bool showMessage = false,
|
||||
}) async {
|
||||
try {
|
||||
var response = await _dio.post(path, data: data);
|
||||
var baseModel = BaseModel.fromJson(response.data);
|
||||
if (showMessage) CloudToast.show(baseModel.msg);
|
||||
return baseModel;
|
||||
} catch (e) {
|
||||
if (e is DioError) {
|
||||
return BaseModel.dioErr(e);
|
||||
}
|
||||
}
|
||||
|
||||
return BaseModel.unknown();
|
||||
}
|
||||
|
||||
///请求列表
|
||||
Future<BaseListModel> requestList(
|
||||
String path, {
|
||||
dynamic data,
|
||||
bool showMessage = false,
|
||||
}) async {
|
||||
var response = await _dio.post(path, data: data);
|
||||
var baseModel = BaseListModel.fromJson(response.data);
|
||||
if (showMessage) CloudToast.show(baseModel.msg);
|
||||
return baseModel;
|
||||
}
|
||||
|
||||
// ///上传图片
|
||||
// Future<String> uploadImage(File file) async {
|
||||
// var response = await _dio.post(
|
||||
// API.file.uploadImage,
|
||||
// data: FormData.fromMap(
|
||||
// {'image': await MultipartFile.fromFile(file.path)},
|
||||
// ),
|
||||
// );
|
||||
// var model = BaseModel.fromJson(response.data);
|
||||
// return model.data['path'];
|
||||
// }
|
||||
|
||||
// Future<List<String>> uploadFiles(
|
||||
// List<File> files,
|
||||
// ) async {
|
||||
// List<String> urls = [];
|
||||
// if (files.isEmpty) {
|
||||
// return [];
|
||||
// } else {
|
||||
// for (var item in files) {
|
||||
// String path = await uploadImage(item);
|
||||
// if (path.isNotEmpty) {
|
||||
// urls.add(path);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return urls;
|
||||
// }
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'base_list_model.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class BaseListModel<T> {
|
||||
final int code;
|
||||
final String msg;
|
||||
final ListInnerModel? data;
|
||||
|
||||
BaseListModel({
|
||||
required this.code,
|
||||
required this.msg,
|
||||
required this.data,
|
||||
});
|
||||
|
||||
factory BaseListModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$BaseListModelFromJson(json);
|
||||
|
||||
List get nullSafetyList {
|
||||
if (data == null) {
|
||||
return [];
|
||||
} else if (data!.list == null) {
|
||||
return [];
|
||||
} else {
|
||||
return data!.list!;
|
||||
}
|
||||
}
|
||||
|
||||
int get nullSafetyTotal {
|
||||
if (data == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return data!.total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class ListInnerModel {
|
||||
final List<dynamic>? list;
|
||||
final int total;
|
||||
|
||||
ListInnerModel({
|
||||
this.list,
|
||||
required this.total,
|
||||
});
|
||||
|
||||
factory ListInnerModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$ListInnerModelFromJson(json);
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'base_list_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
BaseListModel<T> _$BaseListModelFromJson<T>(Map<String, dynamic> json) =>
|
||||
BaseListModel<T>(
|
||||
code: json['code'] as int,
|
||||
msg: json['msg'] as String,
|
||||
data: json['data'] == null
|
||||
? null
|
||||
: ListInnerModel.fromJson(json['data'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$BaseListModelToJson<T>(BaseListModel<T> instance) =>
|
||||
<String, dynamic>{
|
||||
'code': instance.code,
|
||||
'msg': instance.msg,
|
||||
'data': instance.data,
|
||||
};
|
||||
|
||||
ListInnerModel _$ListInnerModelFromJson(Map<String, dynamic> json) =>
|
||||
ListInnerModel(
|
||||
list: json['list'] as List<dynamic>?,
|
||||
total: json['total'] as int,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ListInnerModelToJson(ListInnerModel instance) =>
|
||||
<String, dynamic>{
|
||||
'list': instance.list,
|
||||
'total': instance.total,
|
||||
};
|
@ -0,0 +1,36 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'base_model.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class BaseModel<T> {
|
||||
int code;
|
||||
String msg;
|
||||
dynamic data;
|
||||
BaseModel({
|
||||
required this.code,
|
||||
required this.msg,
|
||||
this.data,
|
||||
});
|
||||
|
||||
|
||||
|
||||
List<T> map(T Function(dynamic json) f) {
|
||||
if (data == null) return [];
|
||||
return (data! as List<T>).map(f).toList();
|
||||
}
|
||||
|
||||
factory BaseModel.unknown() => BaseModel(
|
||||
code: -1,
|
||||
msg: 'UNKNOW FAIL',
|
||||
);
|
||||
|
||||
factory BaseModel.dioErr(DioError err) => BaseModel(
|
||||
code: err.response?.statusCode ?? -1,
|
||||
msg: err.message,
|
||||
);
|
||||
|
||||
factory BaseModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$BaseModelFromJson(json) as BaseModel<T>;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'base_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
BaseModel<T> _$BaseModelFromJson<T>(Map<String, dynamic> json) => BaseModel<T>(
|
||||
code: json['code'] as int,
|
||||
msg: json['msg'] as String,
|
||||
data: json['data'],
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$BaseModelToJson<T>(BaseModel<T> instance) =>
|
||||
<String, dynamic>{
|
||||
'code': instance.code,
|
||||
'msg': instance.msg,
|
||||
'data': instance.data,
|
||||
};
|
@ -0,0 +1,21 @@
|
||||
class LoginModel {
|
||||
String? message;
|
||||
String? token;
|
||||
bool? status;
|
||||
|
||||
LoginModel({this.message, this.token, this.status});
|
||||
|
||||
LoginModel.fromJson(Map<String, dynamic> json) {
|
||||
message = json['message'];
|
||||
token = json['token'];
|
||||
status = json['status'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['message'] = this.message;
|
||||
data['token'] = this.token;
|
||||
data['status'] = this.status;
|
||||
return data;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:get/get.dart' hide Response;
|
||||
import 'package:power_logger/power_logger.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../providers/user_provider.dart';
|
||||
import '../../ui/login/login_page.dart';
|
||||
import '../../utils/toast/cloud_toast.dart';
|
||||
|
||||
class NetworkInterceptor extends Interceptor {
|
||||
@override
|
||||
void onResponse(Response response, ResponseInterceptorHandler handler) async {
|
||||
final userProvider = Provider.of<UserProvider>(Get.context!, listen: false);
|
||||
LoggerData.addData(response);
|
||||
int code = response.data['code'] ?? 0;
|
||||
switch (code) {
|
||||
//登录超时
|
||||
case 100000:
|
||||
await userProvider.logout();
|
||||
CloudToast.show(response.data['msg']);
|
||||
await Get.offAll(() => const LoginPage());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
super.onResponse(response, handler);
|
||||
}
|
||||
|
||||
@override
|
||||
void onError(DioError err, ErrorInterceptorHandler handler) async {
|
||||
LoggerData.addData(err);
|
||||
switch (err.type) {
|
||||
case DioErrorType.connectTimeout:
|
||||
case DioErrorType.sendTimeout:
|
||||
case DioErrorType.receiveTimeout:
|
||||
CloudToast.show('连接超时');
|
||||
break;
|
||||
case DioErrorType.response:
|
||||
CloudToast.show('Server Err');
|
||||
break;
|
||||
case DioErrorType.cancel:
|
||||
break;
|
||||
case DioErrorType.other:
|
||||
CloudToast.show('网络出现问题');
|
||||
break;
|
||||
}
|
||||
super.onError(err, handler);
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
part 'user_info_model.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class UserInfoModel extends Equatable {
|
||||
final int id;
|
||||
final String name;
|
||||
final String phone;
|
||||
final int status;
|
||||
final Vip vip;
|
||||
|
||||
factory UserInfoModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$UserInfoModelFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$UserInfoModelToJson(this);
|
||||
|
||||
static UserInfoModel get fail => const UserInfoModel(
|
||||
id: 0,
|
||||
name: '',
|
||||
phone: '',
|
||||
status: 0,
|
||||
vip: Vip(start: '', end: ''),
|
||||
);
|
||||
|
||||
@override
|
||||
List<Object> get props => [id, name, phone, status, vip];
|
||||
|
||||
const UserInfoModel({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.phone,
|
||||
required this.status,
|
||||
required this.vip,
|
||||
});
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class Vip extends Equatable {
|
||||
final String start;
|
||||
final String end;
|
||||
|
||||
const Vip({
|
||||
required this.start,
|
||||
required this.end,
|
||||
});
|
||||
|
||||
factory Vip.fromJson(Map<String, dynamic> json) => _$VipFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$VipToJson(this);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [start, end];
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'user_info_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
UserInfoModel _$UserInfoModelFromJson(Map<String, dynamic> json) =>
|
||||
UserInfoModel(
|
||||
id: json['id'] as int,
|
||||
name: json['name'] as String,
|
||||
phone: json['phone'] as String,
|
||||
status: json['status'] as int,
|
||||
vip: Vip.fromJson(json['vip'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$UserInfoModelToJson(UserInfoModel instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'name': instance.name,
|
||||
'phone': instance.phone,
|
||||
'status': instance.status,
|
||||
'vip': instance.vip,
|
||||
};
|
||||
|
||||
Vip _$VipFromJson(Map<String, dynamic> json) => Vip(
|
||||
start: json['start'] as String,
|
||||
end: json['end'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$VipToJson(Vip instance) => <String, dynamic>{
|
||||
'start': instance.start,
|
||||
'end': instance.end,
|
||||
};
|
@ -0,0 +1,56 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../constants/api.dart';
|
||||
import '../model/login_info_model.dart';
|
||||
import '../model/network/api_client.dart';
|
||||
import '../model/user_info_model.dart';
|
||||
import '../utils/hive_store.dart';
|
||||
import '../utils/toast/cloud_toast.dart';
|
||||
|
||||
class UserProvider extends ChangeNotifier {
|
||||
bool _isLogin = false;
|
||||
|
||||
bool get isLogin => _isLogin;
|
||||
late UserInfoModel _userInfo;
|
||||
|
||||
UserInfoModel get userInfo => _userInfo;
|
||||
|
||||
Future<bool> init() async {
|
||||
if (HiveStore.appBox?.containsKey('token') ?? false) {
|
||||
final token = HiveStore.appBox?.get('token') as String;
|
||||
_isLogin = true;
|
||||
apiClient.setToken(token);
|
||||
await updateUserInfo();
|
||||
return true;
|
||||
} else {
|
||||
_isLogin = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future setToken(String token, {User? user}) async {
|
||||
apiClient.setToken(token);
|
||||
await HiveStore.appBox!.put('token', token);
|
||||
_isLogin = true;
|
||||
//每次打开app更新用户信息
|
||||
await updateUserInfo();
|
||||
}
|
||||
|
||||
Future logout() async {
|
||||
apiClient.clearToken();
|
||||
_isLogin = false;
|
||||
await HiveStore.appBox?.delete('token');
|
||||
}
|
||||
|
||||
Future updateUserInfo() async {
|
||||
var base = await apiClient.request(API.manager.info);
|
||||
if (base.code == 0) {
|
||||
_userInfo = UserInfoModel.fromJson(base.data);
|
||||
} else {
|
||||
CloudToast.show(base.msg);
|
||||
_userInfo = UserInfoModel.fail;
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
class HiveStore {
|
||||
static Box? _appBox;
|
||||
|
||||
static Box? get appBox => _appBox;
|
||||
static Box? _userBox;
|
||||
|
||||
static Box? get userBox => _userBox;
|
||||
static Box? _dataBox;
|
||||
|
||||
static Box? get dataBox => _dataBox;
|
||||
|
||||
static Future init() async {
|
||||
if (!kIsWeb) {
|
||||
var dir = await getApplicationDocumentsDirectory();
|
||||
Hive.init(dir.path);
|
||||
_appBox = await Hive.openBox('app');
|
||||
_userBox = await Hive.openBox('userBox');
|
||||
_dataBox = await Hive.openBox('dataBox');
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
|
||||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CloudToast {
|
||||
static show(String text,{AlignmentGeometry? align}) {
|
||||
BotToast.showText(
|
||||
text: text,
|
||||
align: align?? const Alignment(0, 0.8),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
);
|
||||
}
|
||||
|
||||
static Function get loading {
|
||||
return BotToast.showCustomLoading(
|
||||
toastBuilder: (cancel) {
|
||||
return const Center(
|
||||
child: Material(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
shape: StadiumBorder(),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import 'package:provider/provider.dart';
|
||||
import '../providers/user_provider.dart';
|
||||
import 'headers.dart';
|
||||
|
||||
class UserTool {
|
||||
static UserProvider userProvider =
|
||||
Provider.of<UserProvider>(Get.context!, listen: false);
|
||||
}
|