完善用户接口
This commit is contained in:
parent
af3d954e75
commit
de74c4c2a2
|
@ -0,0 +1,8 @@
|
|||
// 是否启用缓存
|
||||
const CacheEnable = false;
|
||||
|
||||
// 缓存的最长时间,单位(秒)
|
||||
const CacheMaxAge = 1000;
|
||||
|
||||
// 最大缓存数
|
||||
const CacheMaxCount = 100;
|
|
@ -0,0 +1,4 @@
|
|||
/// Api地址
|
||||
const String ServerApiUrl = "http://172.31.163.87:4523/m1/2998542-0-default";
|
||||
|
||||
const CryptoSalt = "E1pWsyfiy@R@X#qn17!StJNdZK1fFF8iV6ffN!goZkqt#JxO";
|
|
@ -0,0 +1,14 @@
|
|||
/// 用户 - 配置信息
|
||||
const String StorageUserProfileKey = 'user_profile';
|
||||
|
||||
/// 用户 - 配置信息
|
||||
const String StorageUserTokenKey = 'user_token';
|
||||
|
||||
/// 设备是否第一次打开
|
||||
const String StorageDeviceFirstOpenKey = 'device_first_open';
|
||||
|
||||
/// 首页新闻cacheKey
|
||||
const String StorageIndexNewsCacheKey= 'cache_index_news';
|
||||
|
||||
/// 多语言
|
||||
const String StorageLanguageCode = 'language_code';
|
|
@ -1,6 +0,0 @@
|
|||
class UserLoginRequest {
|
||||
String email;
|
||||
String password;
|
||||
|
||||
UserLoginRequest({required this.email, required this.password});
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// 注册请求
|
||||
class UserRegisterRequest {
|
||||
String email;
|
||||
String password;
|
||||
|
||||
UserRegisterRequest({
|
||||
required this.email,
|
||||
required this.password,
|
||||
});
|
||||
|
||||
factory UserRegisterRequest.fromJson(Map<String, dynamic> json) =>
|
||||
UserRegisterRequest(
|
||||
email: json["email"],
|
||||
password: json["password"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"email": email,
|
||||
"password": password,
|
||||
};
|
||||
}
|
||||
|
||||
// 登录请求
|
||||
class UserLoginRequest {
|
||||
String email;
|
||||
String password;
|
||||
|
||||
UserLoginRequest({
|
||||
required this.email,
|
||||
required this.password,
|
||||
});
|
||||
|
||||
factory UserLoginRequest.fromJson(Map<String, dynamic> json) =>
|
||||
UserLoginRequest(
|
||||
email: json["email"],
|
||||
password: json["password"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"email": email,
|
||||
"password": password,
|
||||
};
|
||||
}
|
||||
|
||||
// 登录返回
|
||||
class UserLoginResponse {
|
||||
String? accessToken;
|
||||
String? displayName;
|
||||
List<String>? channels;
|
||||
|
||||
UserLoginResponse({
|
||||
this.accessToken,
|
||||
this.displayName,
|
||||
this.channels,
|
||||
});
|
||||
|
||||
factory UserLoginResponse.fromJson(Map<String, dynamic> json) =>
|
||||
UserLoginResponse(
|
||||
accessToken: json["access_token"],
|
||||
displayName: json["display_name"],
|
||||
channels: List<String>.from(json["channels"].map((x) => x)),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"access_token": accessToken,
|
||||
"display_name": displayName,
|
||||
"channels":
|
||||
channels == null ? [] : List<dynamic>.from(channels!.map((x) => x)),
|
||||
};
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// 用户
|
||||
import 'package:news_getx/data/model/user.dart';
|
||||
import 'package:news_getx/utils/http.dart';
|
||||
|
||||
class UserAPI {
|
||||
/// 登录
|
||||
static Future<UserLoginResponse> login(UserLoginRequest? data) async {
|
||||
UserLoginResponse response = await HttpUtil().post(
|
||||
"/user/login",
|
||||
data: data?.toJson(),
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
/// 注册
|
||||
static Future<UserRegisterRequest> register(UserRegisterRequest request, {
|
||||
UserRegisterRequest? data,
|
||||
}) async {
|
||||
var response = await HttpUtil().post(
|
||||
'/user/register',
|
||||
data: data?.toJson(),
|
||||
);
|
||||
return UserRegisterRequest.fromJson(response);
|
||||
}
|
||||
|
||||
/// Profile
|
||||
static Future<UserLoginResponse> profile() async {
|
||||
var response = await HttpUtil().post(
|
||||
'/user/profile',
|
||||
);
|
||||
return UserLoginResponse.fromJson(response);
|
||||
}
|
||||
|
||||
/// Logout
|
||||
static Future logout() async {
|
||||
return await HttpUtil().post(
|
||||
'/user/logout',
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import 'package:news_getx/data/model/user.dart';
|
||||
import 'package:news_getx/data/provider/user.dart';
|
||||
|
||||
class UserRepository {
|
||||
Future<UserLoginResponse> login(UserLoginRequest request) {
|
||||
return UserAPI.login(request);
|
||||
}
|
||||
|
||||
Future<UserRegisterRequest> register(
|
||||
UserRegisterRequest request, {
|
||||
UserRegisterRequest? data,
|
||||
}) {
|
||||
return UserAPI.register(request, data: data);
|
||||
}
|
||||
|
||||
Future<UserLoginResponse> profile() {
|
||||
return UserAPI.profile();
|
||||
}
|
||||
|
||||
Future logout() {
|
||||
return UserAPI.logout();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/config/storage.dart';
|
||||
import 'package:news_getx/data/services/storage.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
class ConfigService extends GetxService {
|
||||
static ConfigService get to => Get.find();
|
||||
|
||||
bool isFirstOpen = false;
|
||||
PackageInfo? _platform;
|
||||
|
||||
String get version => _platform?.version ?? "-";
|
||||
bool get isRelease => bool.fromEnvironment("dart.vm.product");
|
||||
Locale locale = Locale("en", "US");
|
||||
|
||||
List<Locale> languages = [
|
||||
Locale('en', 'US'),
|
||||
Locale('zh', 'CN'),
|
||||
];
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
isFirstOpen = StorageService.to.getBool(StorageDeviceFirstOpenKey);
|
||||
}
|
||||
|
||||
Future<void> getPlatform() async {
|
||||
_platform = await PackageInfo.fromPlatform();
|
||||
}
|
||||
|
||||
// 标记用户已打开APP
|
||||
Future<bool> saveAlreadyOpen() {
|
||||
return StorageService.to.setBool(StorageDeviceFirstOpenKey, false);
|
||||
}
|
||||
|
||||
void onInitLocale() {
|
||||
String langCode = StorageService.to.getString(StorageLanguageCode);
|
||||
if (langCode .isEmpty) return;
|
||||
|
||||
int index = languages.indexWhere((element) {
|
||||
return element.languageCode == langCode;
|
||||
});
|
||||
if (index < 0) return;
|
||||
locale = languages[index];
|
||||
}
|
||||
|
||||
void onLocaleUpdate(Locale value) {
|
||||
locale = value;
|
||||
// 更新app的语言
|
||||
Get.updateLocale(value);
|
||||
StorageService.to.setString(StorageLanguageCode, value.languageCode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
|
||||
class StorageService extends GetxService {
|
||||
static StorageService get to => Get.find<StorageService>();
|
||||
late final SharedPreferences _prefs;
|
||||
|
||||
Future<StorageService> init() async {
|
||||
_prefs = await SharedPreferences.getInstance();
|
||||
return this;
|
||||
}
|
||||
|
||||
Future<bool> setString(String key, String value) async {
|
||||
return await _prefs.setString(key, value);
|
||||
}
|
||||
|
||||
Future<bool> setBool(String key, bool value) async {
|
||||
return await _prefs.setBool(key, value);
|
||||
}
|
||||
|
||||
Future<bool> setList(String key, List<String> value) async {
|
||||
return await _prefs.setStringList(key, value);
|
||||
}
|
||||
|
||||
String getString(String key) {
|
||||
return _prefs.getString(key) ?? '';
|
||||
}
|
||||
|
||||
bool getBool(String key) {
|
||||
return _prefs.getBool(key) ?? false;
|
||||
}
|
||||
|
||||
List<String> getList(String key) {
|
||||
return _prefs.getStringList(key) ?? [];
|
||||
}
|
||||
|
||||
Future<bool> remove(String key) async {
|
||||
return await _prefs.remove(key);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/config/storage.dart';
|
||||
import 'package:news_getx/data/model/user.dart';
|
||||
import 'package:news_getx/data/provider/user.dart';
|
||||
import 'package:news_getx/data/services/storage.dart';
|
||||
|
||||
class UserService extends GetxService {
|
||||
static UserService get to => Get.find();
|
||||
|
||||
// 是否登录
|
||||
var _isLogin = false.obs;
|
||||
|
||||
// 令牌 token
|
||||
String token = "";
|
||||
|
||||
// 用户 profile
|
||||
var _profile = UserLoginResponse().obs;
|
||||
|
||||
bool get hasToken => token.isNotEmpty;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
token = StorageService.to.getString(StorageUserTokenKey);
|
||||
var profileOffline = StorageService.to.getString(StorageUserProfileKey);
|
||||
if (profileOffline.isNotEmpty) {
|
||||
_profile(UserLoginResponse.fromJson(jsonDecode(profileOffline)));
|
||||
}
|
||||
}
|
||||
|
||||
// 保存 token
|
||||
Future<void> setToken(String value) async {
|
||||
await StorageService.to.setString(StorageUserTokenKey, value);
|
||||
token = value;
|
||||
}
|
||||
|
||||
// 获取 profile
|
||||
Future<void> getProfile() async {
|
||||
if (token.isEmpty) return;
|
||||
UserLoginResponse result = await UserAPI.profile();
|
||||
_profile(result);
|
||||
_isLogin.value = true;
|
||||
StorageService.to.setString(StorageUserProfileKey, jsonEncode(result));
|
||||
}
|
||||
|
||||
// 保存 profile
|
||||
Future<void> saveProfile(UserLoginResponse profile) async {
|
||||
_isLogin.value = true;
|
||||
await StorageService.to.setString(StorageUserProfileKey, jsonEncode(profile));
|
||||
}
|
||||
|
||||
// 注销
|
||||
Future<void> onLogout() async {
|
||||
if (_isLogin.value) await UserAPI.logout();
|
||||
await StorageService.to.remove(StorageUserTokenKey);
|
||||
_isLogin.value = false;
|
||||
token = '';
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
import 'package:get/get.dart';
|
||||
|
||||
class NotFoundController extends GetxController {
|
||||
// title
|
||||
final _title = "".obs;
|
||||
|
||||
set title(value) => _title.value = value;
|
||||
get title => _title.value;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,10 @@ class NotFoundPage extends GetView<NotFoundController> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
return Obx(() {
|
||||
return Center(
|
||||
child: Obx(() => Text(controller.title)),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/data/repository/user_repository.dart';
|
||||
|
||||
import 'sign_in_controller.dart';
|
||||
|
||||
class SignInBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => SignInController());
|
||||
Get.lazyPut(
|
||||
() => SignInController(
|
||||
repository: UserRepository(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,26 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/data/model/user.dart';
|
||||
import 'package:news_getx/data/repository/user_repository.dart';
|
||||
import 'package:news_getx/data/services/user.dart';
|
||||
import 'package:news_getx/modules/widgets/toast.dart';
|
||||
import 'package:news_getx/routes/app_pages.dart';
|
||||
import 'package:news_getx/utils/security.dart';
|
||||
import 'package:news_getx/utils/validator.dart';
|
||||
|
||||
class SignInController extends GetxController {
|
||||
final UserRepository repository;
|
||||
|
||||
// email的控制器
|
||||
final TextEditingController emailController = TextEditingController();
|
||||
|
||||
// 密码的控制器
|
||||
final TextEditingController passwordController = TextEditingController();
|
||||
|
||||
SignInController({required this.repository});
|
||||
|
||||
// 跳转 注册界面
|
||||
handleNavSignUp(){
|
||||
handleNavSignUp() {
|
||||
// TODO 注册页面
|
||||
Get.toNamed(AppRoutes.Signup);
|
||||
}
|
||||
|
@ -28,11 +37,20 @@ class SignInController extends GetxController {
|
|||
return;
|
||||
}
|
||||
|
||||
if(!checkStringLength(passwordController.text, 6)){
|
||||
if (!checkStringLength(passwordController.text, 6)) {
|
||||
toastInfo(msg: '密码不能小于6位');
|
||||
return;
|
||||
}
|
||||
|
||||
UserLoginRequest request = UserLoginRequest(
|
||||
email: emailController.text,
|
||||
password: cryptoSha256(passwordController.text),
|
||||
);
|
||||
|
||||
UserLoginResponse response = await repository.login(request);
|
||||
|
||||
UserService.to.saveProfile(response);
|
||||
|
||||
Get.offAndToNamed(AppRoutes.Application);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/data/repository/user_repository.dart';
|
||||
|
||||
import 'sign_up_controller.dart';
|
||||
|
||||
class SignUpBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => SignUpController());
|
||||
Get.lazyPut(() => SignUpController(
|
||||
repository: UserRepository(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,32 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/data/model/user.dart';
|
||||
import 'package:news_getx/data/repository/user_repository.dart';
|
||||
import 'package:news_getx/modules/widgets/toast.dart';
|
||||
import 'package:news_getx/routes/app_pages.dart';
|
||||
import 'package:news_getx/utils/security.dart';
|
||||
import 'package:news_getx/utils/validator.dart';
|
||||
|
||||
class SignUpController extends GetxController {
|
||||
final UserRepository repository;
|
||||
|
||||
// email的控制器
|
||||
final TextEditingController fullNameController = TextEditingController();
|
||||
|
||||
// email的控制器
|
||||
final TextEditingController emailController = TextEditingController();
|
||||
|
||||
// 密码的控制器
|
||||
final TextEditingController passwordController = TextEditingController();
|
||||
|
||||
SignUpController({required this.repository});
|
||||
|
||||
// 返回上一级
|
||||
handleNavPop() {
|
||||
Get.back();
|
||||
}
|
||||
|
||||
handleRegister() {
|
||||
handleRegister() async {
|
||||
if (!checkStringLength(fullNameController.text, 5)) {
|
||||
toastInfo(msg: '用户名不能小于5位');
|
||||
return;
|
||||
|
@ -31,7 +40,12 @@ class SignUpController extends GetxController {
|
|||
return;
|
||||
}
|
||||
|
||||
toastInfo(msg: '注册成功');
|
||||
UserRegisterRequest params = UserRegisterRequest(
|
||||
email: emailController.text, password: cryptoSha256(passwordController.text),
|
||||
);
|
||||
|
||||
await repository.register(params);
|
||||
|
||||
Get.back();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/modules/not_found/not_found_binding.dart';
|
||||
import 'package:news_getx/modules/not_found/not_found_page.dart';
|
||||
import 'package:news_getx/modules/sign_in/sign_in_binding.dart';
|
||||
import 'package:news_getx/modules/sign_in/sign_in_page.dart';
|
||||
import 'package:news_getx/modules/sign_up/sign_up_binding.dart';
|
||||
|
@ -10,6 +12,7 @@ part './app_routes.dart';
|
|||
|
||||
abstract class AppPages {
|
||||
static final pages = [
|
||||
// 免登陆
|
||||
GetPage(
|
||||
name: AppRoutes.Initial,
|
||||
page: () => WelcomePage(),
|
||||
|
@ -24,6 +27,11 @@ abstract class AppPages {
|
|||
name: AppRoutes.Signup,
|
||||
page: () => SignUpPage(),
|
||||
binding: SignUpBinding(),
|
||||
)
|
||||
),
|
||||
GetPage(
|
||||
name: AppRoutes.NotFound,
|
||||
page: () => NotFoundPage(),
|
||||
binding: NotFoundBinding(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,379 @@
|
|||
import 'package:dio/dio.dart';
|
||||
import 'package:get/get.dart' hide FormData;
|
||||
import 'package:news_getx/config/cache.dart';
|
||||
import 'package:news_getx/config/server.dart';
|
||||
import 'package:cookie_jar/cookie_jar.dart';
|
||||
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:news_getx/data/services/user.dart';
|
||||
import 'package:news_getx/utils/loading.dart';
|
||||
|
||||
/*
|
||||
* http 操作类
|
||||
*
|
||||
* 手册
|
||||
* https://github.com/cfug/dio/blob/main/dio/README-ZH.md
|
||||
*
|
||||
* 从 4 升级到 5
|
||||
* https://github.com/cfug/dio/blob/main/dio/migration_guide.md
|
||||
*/
|
||||
class HttpUtil {
|
||||
late Dio dio;
|
||||
CancelToken cancelToken = CancelToken();
|
||||
|
||||
// 每次调用都会重新生成一个dio对象
|
||||
static HttpUtil _instance = HttpUtil._internal();
|
||||
|
||||
factory HttpUtil() => _instance;
|
||||
|
||||
HttpUtil._internal() {
|
||||
// BaseOptions、Options、RequestOptions 都可以配置参数,优先级别依次递增,且可以根据优先级别覆盖参数
|
||||
BaseOptions options = BaseOptions(
|
||||
// 请求基地址,可以包含子路径
|
||||
baseUrl: ServerApiUrl,
|
||||
//连接服务器超时时间,单位是毫秒.
|
||||
connectTimeout: Duration(seconds: 10),
|
||||
// 响应流上前后两次接受到数据的间隔,单位为毫秒。
|
||||
receiveTimeout: Duration(seconds: 5),
|
||||
// Http请求头.
|
||||
headers: {},
|
||||
|
||||
/// 请求的Content-Type,默认值是"application/json; charset=utf-8".
|
||||
/// 如果您想以"application/x-www-form-urlencoded"格式编码请求数据,
|
||||
/// 可以设置此选项为 `Headers.formUrlEncodedContentType`, 这样[Dio]
|
||||
/// 就会自动编码请求体.
|
||||
contentType: "application/json; charset=utf-8",
|
||||
|
||||
/// [responseType] 表示期望以那种格式(方式)接受响应数据。
|
||||
/// 目前 [ResponseType] 接受三种类型 `JSON`, `STREAM`, `PLAIN`.
|
||||
///
|
||||
/// 默认值是 `JSON`, 当响应头中content-type为"application/json"时,dio 会自动将响应内容转化为json对象。
|
||||
/// 如果想以二进制方式接受响应数据,如下载一个二进制文件,那么可以使用 `STREAM`.
|
||||
///
|
||||
/// 如果想以文本(字符串)格式接收响应数据,请使用 `PLAIN`.
|
||||
responseType: ResponseType.json,
|
||||
);
|
||||
|
||||
dio = Dio(options);
|
||||
|
||||
// Cookie管理
|
||||
CookieJar cookieJar = CookieJar();
|
||||
// 增加拦截器CookieManager
|
||||
dio.interceptors.add(CookieManager(cookieJar));
|
||||
|
||||
// 添加拦截器
|
||||
dio.interceptors.add(InterceptorsWrapper(
|
||||
onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
|
||||
// Do something before request is sent
|
||||
return handler.next(options);
|
||||
// 如果你想完成请求并返回一些自定义数据,你可以resolve一个Response对象 `handler.resolve(response)`。
|
||||
// 这样请求将会被终止,上层then会被调用,then中返回的数据将是你的自定义response.
|
||||
//
|
||||
// 如果你想终止请求并触发一个错误,你可以返回一个`DioException`对象,如`handler.reject(error)`,
|
||||
// 这样请求将被中止并触发异常,上层catchError会被调用。
|
||||
},
|
||||
onResponse: (response, handler) {
|
||||
// Do something with response data
|
||||
return handler.next(response);
|
||||
// 如果你想终止请求并触发一个错误,你可以 reject 一个`DioException`对象,如`handler.reject(error)`,
|
||||
// 这样请求将被中止并触发异常,上层catchError会被调用。
|
||||
},
|
||||
onError: (DioException err, ErrorInterceptorHandler handler) {
|
||||
// Do something with response error
|
||||
Loading.dismiss();
|
||||
ErrorEntity entity = createErrorEntity(err);
|
||||
onError(entity);
|
||||
return handler.next(err);
|
||||
// 如果你想完成请求并返回一些自定义数据,可以resolve 一个`Response`,如`handler.resolve(response)`。
|
||||
// 这样请求将会被终止,上层then会被调用,then中返回的数据将是你的自定义response.
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
/// 统一错误处理
|
||||
void onError(ErrorEntity errorEntity) {
|
||||
print(
|
||||
'error.code -> ${errorEntity.code}, error.message -> ${errorEntity.message}');
|
||||
switch (errorEntity.code) {
|
||||
case 401:
|
||||
// 会话过期 返回到登录页
|
||||
UserService.to.onLogout();
|
||||
EasyLoading.showError(errorEntity.message);
|
||||
break;
|
||||
default:
|
||||
EasyLoading.showError('未知错误');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 错误信息
|
||||
ErrorEntity createErrorEntity(DioException error) {
|
||||
switch (error.type) {
|
||||
case DioExceptionType.cancel:
|
||||
return ErrorEntity(code: -1, message: "请求取消");
|
||||
case DioExceptionType.connectionTimeout:
|
||||
return ErrorEntity(code: -1, message: "连接超时");
|
||||
case DioExceptionType.sendTimeout:
|
||||
return ErrorEntity(code: -1, message: "请求超时");
|
||||
case DioExceptionType.receiveTimeout:
|
||||
return ErrorEntity(code: -1, message: "响应超时");
|
||||
case DioExceptionType.badResponse:
|
||||
{
|
||||
try {
|
||||
int errCode =
|
||||
error.response != null ? error.response!.statusCode! : -1;
|
||||
// String errMsg = error.response.statusMessage;
|
||||
// return ErrorEntity(code: errCode, message: errMsg);
|
||||
switch (errCode) {
|
||||
case 400:
|
||||
return ErrorEntity(code: errCode, message: "请求语法错误");
|
||||
case 401:
|
||||
return ErrorEntity(code: errCode, message: "没有权限");
|
||||
case 403:
|
||||
return ErrorEntity(code: errCode, message: "服务器拒绝执行");
|
||||
case 404:
|
||||
return ErrorEntity(code: errCode, message: "无法连接服务器");
|
||||
case 405:
|
||||
return ErrorEntity(code: errCode, message: "请求方法被禁止");
|
||||
case 500:
|
||||
return ErrorEntity(code: errCode, message: "服务器内部错误");
|
||||
case 502:
|
||||
return ErrorEntity(code: errCode, message: "无效的请求");
|
||||
case 503:
|
||||
return ErrorEntity(code: errCode, message: "服务器挂了");
|
||||
case 505:
|
||||
return ErrorEntity(code: errCode, message: "不支持HTTP协议请求");
|
||||
default:
|
||||
{
|
||||
// return ErrorEntity(code: errCode, message: "未知错误");
|
||||
return ErrorEntity(
|
||||
code: errCode,
|
||||
message: error.response != null
|
||||
? error.response!.statusMessage!
|
||||
: "",
|
||||
);
|
||||
}
|
||||
}
|
||||
} on Exception catch (_) {
|
||||
return ErrorEntity(code: -1, message: "未知错误");
|
||||
}
|
||||
}
|
||||
default:
|
||||
{
|
||||
return ErrorEntity(code: -1, message: error.message ?? "未定义错误");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 取消请求
|
||||
/// 同一个cancel token 可以用于多个请求,当一个cancel token取消时,所有使用该cancel token的请求都会被取消。
|
||||
/// 所以参数可选
|
||||
void cancelRequests(CancelToken token) {
|
||||
token.cancel("cancelled");
|
||||
}
|
||||
|
||||
/// 读取本地配置
|
||||
Map<String, dynamic>? getAuthorizationHeader() {
|
||||
var headers = <String, dynamic>{};
|
||||
if (Get.isRegistered<UserService>() && UserService.to.hasToken) {
|
||||
headers['Authorization'] = 'Bearer ${UserService.to.token}';
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
/// restful get 操作
|
||||
/// refresh 是否下拉刷新 默认 false
|
||||
/// noCache 是否不缓存 默认 true
|
||||
/// list 是否列表 默认 false
|
||||
/// cacheKey 缓存key
|
||||
/// cacheDisk 是否磁盘缓存
|
||||
Future<dynamic> get(
|
||||
String path, {
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
bool refresh = false,
|
||||
bool noCache = !CacheEnable,
|
||||
bool list = false,
|
||||
String cacheKey = '',
|
||||
bool cacheDisk = false,
|
||||
}) async {
|
||||
Options requestOptions = options ?? Options();
|
||||
// 设置自定义字段 用于后续使用
|
||||
requestOptions.extra ??= <String, dynamic>{
|
||||
"refresh": refresh,
|
||||
"noCache": noCache,
|
||||
"list": list,
|
||||
"cacheKey": cacheKey,
|
||||
"cacheDisk": cacheDisk,
|
||||
};
|
||||
// 设置头信息
|
||||
requestOptions.headers ??= {};
|
||||
Map<String, dynamic>? authorization = getAuthorizationHeader();
|
||||
if (authorization != null) {
|
||||
requestOptions.headers!.addAll(authorization);
|
||||
}
|
||||
|
||||
var response = await dio.get(
|
||||
path,
|
||||
queryParameters: queryParameters,
|
||||
options: options,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/// restful post 操作
|
||||
Future post(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
}) async {
|
||||
Options requestOptions = options ?? Options();
|
||||
requestOptions.headers = requestOptions.headers ?? {};
|
||||
Map<String, dynamic>? authorization = getAuthorizationHeader();
|
||||
if (authorization != null) {
|
||||
requestOptions.headers!.addAll(authorization);
|
||||
}
|
||||
var response = await dio.post(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: queryParameters,
|
||||
options: requestOptions,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/// restful put 操作
|
||||
Future put(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
}) async {
|
||||
Options requestOptions = options ?? Options();
|
||||
requestOptions.headers = requestOptions.headers ?? {};
|
||||
Map<String, dynamic>? authorization = getAuthorizationHeader();
|
||||
if (authorization != null) {
|
||||
requestOptions.headers!.addAll(authorization);
|
||||
}
|
||||
var response = await dio.put(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: queryParameters,
|
||||
options: requestOptions,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/// restful patch 操作
|
||||
Future patch(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
}) async {
|
||||
Options requestOptions = options ?? Options();
|
||||
requestOptions.headers = requestOptions.headers ?? {};
|
||||
Map<String, dynamic>? authorization = getAuthorizationHeader();
|
||||
if (authorization != null) {
|
||||
requestOptions.headers!.addAll(authorization);
|
||||
}
|
||||
var response = await dio.patch(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: queryParameters,
|
||||
options: requestOptions,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/// restful delete 操作
|
||||
Future delete(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
}) async {
|
||||
Options requestOptions = options ?? Options();
|
||||
requestOptions.headers = requestOptions.headers ?? {};
|
||||
Map<String, dynamic>? authorization = getAuthorizationHeader();
|
||||
if (authorization != null) {
|
||||
requestOptions.headers!.addAll(authorization);
|
||||
}
|
||||
var response = await dio.delete(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: queryParameters,
|
||||
options: requestOptions,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/// restful post form 表单提交操作
|
||||
Future postForm(
|
||||
String path, {
|
||||
required Map<String, dynamic> data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
}) async {
|
||||
Options requestOptions = options ?? Options();
|
||||
requestOptions.headers = requestOptions.headers ?? {};
|
||||
Map<String, dynamic>? authorization = getAuthorizationHeader();
|
||||
if (authorization != null) {
|
||||
requestOptions.headers!.addAll(authorization);
|
||||
}
|
||||
var response = await dio.post(
|
||||
path,
|
||||
data: FormData.fromMap(data),
|
||||
queryParameters: queryParameters,
|
||||
options: requestOptions,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/// restful post Stream 流数据
|
||||
Future postStream(
|
||||
String path, {
|
||||
dynamic data,
|
||||
int dataLength = 0,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
}) async {
|
||||
Options requestOptions = options ?? Options();
|
||||
requestOptions.headers = requestOptions.headers ?? {};
|
||||
Map<String, dynamic>? authorization = getAuthorizationHeader();
|
||||
if (authorization != null) {
|
||||
requestOptions.headers!.addAll(authorization);
|
||||
}
|
||||
requestOptions.headers!.addAll({
|
||||
Headers.contentLengthHeader: dataLength.toString(),
|
||||
});
|
||||
var response = await dio.post(
|
||||
path,
|
||||
data: Stream.fromIterable(data.map((e) => [e])),
|
||||
queryParameters: queryParameters,
|
||||
options: requestOptions,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
class ErrorEntity implements Exception {
|
||||
int code = -1;
|
||||
String message = "";
|
||||
|
||||
ErrorEntity({required this.code, required this.message});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (message.isEmpty) return "Exception";
|
||||
return "Exception: code $code, $message";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
|
||||
class Loading {
|
||||
Loading() {
|
||||
// 调整loading的配置
|
||||
EasyLoading.instance
|
||||
..displayDuration = const Duration(milliseconds: 2000)
|
||||
..indicatorType = EasyLoadingIndicatorType.ring
|
||||
..loadingStyle = EasyLoadingStyle.custom
|
||||
..indicatorSize = 35.0
|
||||
..lineWidth = 2
|
||||
..radius = 10.0
|
||||
..progressColor = Colors.white
|
||||
..backgroundColor = Colors.black.withOpacity(0.7)
|
||||
..indicatorColor = Colors.white
|
||||
..textColor = Colors.white
|
||||
..maskColor = Colors.black.withOpacity(0.6)
|
||||
..userInteractions = true
|
||||
..dismissOnTap = false
|
||||
..maskType = EasyLoadingMaskType.custom;
|
||||
}
|
||||
|
||||
static void show([String? text]) {
|
||||
// 应在显示加载时允许用户交互
|
||||
EasyLoading.instance.userInteractions = false;
|
||||
EasyLoading.show(status: text ?? "Loading...");
|
||||
}
|
||||
|
||||
static void toast(String text) {
|
||||
EasyLoading.showToast(text);
|
||||
}
|
||||
|
||||
static void dismiss() {
|
||||
EasyLoading.instance.userInteractions = true;
|
||||
EasyLoading.dismiss();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:news_getx/config/server.dart';
|
||||
|
||||
String cryptoSha256(String input) {
|
||||
var bytes = utf8.encode(input + CryptoSalt);
|
||||
var digest = sha256.convert(bytes);
|
||||
return digest.toString();
|
||||
}
|
36
pubspec.lock
36
pubspec.lock
|
@ -69,10 +69,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: cookie_jar
|
||||
sha256: d1cc6516a190ba667941f722b6365d202caff3dacb38de24268b8d6ff1ec8a1d
|
||||
sha256: "1024f3a52bee181fc8f10f4a359085471587d7406323090a53a7171bc0aa5c37"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "4.0.5"
|
||||
crypto:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -109,18 +109,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: dio
|
||||
sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8"
|
||||
sha256: a9d76e72985d7087eb7c5e7903224ae52b337131518d127c554b9405936752b8
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "4.0.6"
|
||||
version: "5.2.1+1"
|
||||
dio_cookie_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dio_cookie_manager
|
||||
sha256: ed7ee3ba6cdb54599c8984d5a4ce09675c553ead6c28608eb54e38eec5b4f954
|
||||
sha256: c4b7a693aa09efd694a5c5e12065daa5e026647b106245281ed1042b3ebefb8f
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "3.1.0"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -317,14 +317,22 @@ packages:
|
|||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
package_info:
|
||||
package_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: package_info
|
||||
sha256: "6c07d9d82c69e16afeeeeb6866fe43985a20b3b50df243091bfc4a4ad2b03b75"
|
||||
name: package_info_plus
|
||||
sha256: ceb027f6bc6a60674a233b4a90a7658af1aebdea833da0b5b53c1e9821a78c7b
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
version: "4.0.2"
|
||||
package_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_info_plus_platform_interface
|
||||
sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -594,6 +602,14 @@ packages:
|
|||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
universal_io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: universal_io
|
||||
sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -46,9 +46,9 @@ dependencies:
|
|||
flutter_screenutil: ^5.7.0
|
||||
|
||||
# http
|
||||
dio: ^4.0.0
|
||||
dio_cookie_manager: ^2.0.0
|
||||
cookie_jar: ^3.0.1
|
||||
dio: ^5.2.1+1
|
||||
dio_cookie_manager: ^3.1.0
|
||||
cookie_jar: ^4.0.5
|
||||
|
||||
# 日期
|
||||
intl: ^0.18.0
|
||||
|
@ -80,7 +80,7 @@ dependencies:
|
|||
device_info: ^2.0.0
|
||||
|
||||
# 包信息
|
||||
package_info: ^2.0.0
|
||||
package_info_plus: ^4.0.2
|
||||
|
||||
# 路径查询
|
||||
path_provider: ^2.0.1
|
||||
|
|
Loading…
Reference in New Issue