Commit 056970d81f6fc136aef89e88912071f87b2f4bc2
1 parent
725dc3f2
feat: api
Showing
30 changed files
with
762 additions
and
113 deletions
lib/app/splash_page.dart
... | ... | @@ -2,7 +2,7 @@ import 'dart:async'; |
2 | 2 | |
3 | 3 | import 'package:flutter/material.dart'; |
4 | 4 | import 'package:wow_english/common/extension/string_extension.dart'; |
5 | -import 'package:wow_english/network/basic_configuration.dart'; | |
5 | +import 'package:wow_english/network/basic_configuration.dart.txt'; | |
6 | 6 | import 'package:wow_english/route/route.dart'; |
7 | 7 | |
8 | 8 | |
... | ... | @@ -59,4 +59,4 @@ class _TransitionViewState extends State<TransitionView> { |
59 | 59 | ), |
60 | 60 | ); |
61 | 61 | } |
62 | -} | |
63 | 62 | \ No newline at end of file |
63 | +} | ... | ... |
lib/common/request/api_response/api_response_entity.dart
0 → 100644
1 | +import 'dart:convert'; | |
2 | + | |
3 | +import 'api_response_entity.g.dart'; | |
4 | + | |
5 | +class ApiResponse<T> { | |
6 | + int? code; | |
7 | + String? msg; | |
8 | + T? data; | |
9 | + | |
10 | + ApiResponse(); | |
11 | + | |
12 | + factory ApiResponse.fromJson(Map<String, dynamic> json) => $ApiResponseFromJson<T>(json); | |
13 | + | |
14 | + Map<String, dynamic> toJson() => $ApiResponseToJson(this); | |
15 | + | |
16 | + @override | |
17 | + String toString() { | |
18 | + return jsonEncode(this); | |
19 | + } | |
20 | +} | ... | ... |
lib/common/request/api_response/api_response_entity.g.dart
0 → 100644
1 | +import 'package:flutter/foundation.dart'; | |
2 | + | |
3 | +import '../../../generated/json/base/json_convert_content.dart'; | |
4 | +import 'api_response_entity.dart'; | |
5 | + | |
6 | +ApiResponse<T> $ApiResponseFromJson<T>(Map<String, dynamic> json) { | |
7 | + final ApiResponse<T> apiResponseEntity = ApiResponse<T>(); | |
8 | + final int? code = jsonConvert.convert<int>(json['code']); | |
9 | + if (code != null) { | |
10 | + apiResponseEntity.code = code; | |
11 | + } | |
12 | + final String? msg = jsonConvert.convert<String>(json['msg']); | |
13 | + if (msg != null) { | |
14 | + apiResponseEntity.msg = msg; | |
15 | + } | |
16 | + String type = T.toString(); | |
17 | + T? data; | |
18 | + if (kDebugMode) { | |
19 | + print("type:$type"); | |
20 | + } | |
21 | + if (json['data'] != null) { | |
22 | + data = jsonConvert.convert<T>(json['data']); | |
23 | + } | |
24 | + if (data != null) { | |
25 | + apiResponseEntity.data = data; | |
26 | + } | |
27 | + return apiResponseEntity; | |
28 | +} | |
29 | + | |
30 | +Map<String, dynamic> $ApiResponseToJson(ApiResponse entity) { | |
31 | + final Map<String, dynamic> data = <String, dynamic>{}; | |
32 | + data['code'] = entity.code; | |
33 | + data['msg'] = entity.msg; | |
34 | + data['data'] = entity.data; | |
35 | + return data; | |
36 | +} | ... | ... |
lib/common/request/api_response/raw_data.dart
0 → 100644
lib/common/request/apis.dart
0 → 100644
1 | +class Apis { | |
2 | + /// app初始化配置信息 | |
3 | + // GET /system/app/config | |
4 | + // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897678 | |
5 | + static const String appConfig = 'system/app/config'; | |
6 | + | |
7 | + /// 登陆 | |
8 | + static const String login = 'login'; | |
9 | + | |
10 | + /// 登出 | |
11 | + static const String logout = 'logout'; | |
12 | + | |
13 | + /// 发送验证码 | |
14 | + static const String sendSmsCode = 'system/send/code'; | |
15 | + | |
16 | + /// 课程模块 | |
17 | + // GET /home/courseModule | |
18 | + // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897663 | |
19 | + static const String courseModule = 'home/courseModule'; | |
20 | + | |
21 | + /// 课程列表 | |
22 | + // GET /home/courseLesson | |
23 | + // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897662 | |
24 | + static const String courseLesson = 'home/courseLesson'; | |
25 | +} | ... | ... |
lib/common/request/config.dart
0 → 100644
lib/common/request/dao/user_dao.dart
0 → 100644
1 | +import '../../../models/user_entity.dart'; | |
2 | +import '../api_response/api_response_entity.dart'; | |
3 | +import '../apis.dart'; | |
4 | +import '../exception.dart'; | |
5 | +import '../request_client.dart'; | |
6 | + | |
7 | +class UserDao { | |
8 | + static loginByPassword( | |
9 | + phoneNumber, | |
10 | + password, | |
11 | + Function(ApiResponse<UserEntity>)? onResponse, | |
12 | + bool Function(ApiException)? onError, | |
13 | + ) async { | |
14 | + /*await DioUtil().requestData( | |
15 | + HttpMethod.post, | |
16 | + Api.login, | |
17 | + data: { | |
18 | + 'phoneNum':phoneNumber, | |
19 | + 'type':'pwd', | |
20 | + 'password':password}, | |
21 | + successCallBack: (data){ | |
22 | + emitter(LoginResultChangeState(true)); | |
23 | + }, | |
24 | + errorCallBack: (error){ | |
25 | + emitter(LoginResultChangeState(false)); | |
26 | + });*/ | |
27 | + var params = {'phoneNum': phoneNumber, 'type': 'pwd', 'password': password}; | |
28 | + await requestClient.post(Apis.login, data: params, onResponse: onResponse, onError: onError); | |
29 | + } | |
30 | + | |
31 | + static loginBySmsCode(phoneNumber, smsCode) {} | |
32 | +} | ... | ... |
lib/common/request/exception.dart
0 → 100644
1 | +import 'package:dio/dio.dart'; | |
2 | + | |
3 | +import 'api_response/api_response_entity.dart'; | |
4 | + | |
5 | +class ApiException implements Exception { | |
6 | + static const unknownException = "未知错误"; | |
7 | + final String? message; | |
8 | + final int? code; | |
9 | + String? stackInfo; | |
10 | + | |
11 | + ApiException([this.code, this.message]); | |
12 | + | |
13 | + factory ApiException.fromDioError(DioException error) { | |
14 | + switch (error.type) { | |
15 | + case DioExceptionType.connectionTimeout: | |
16 | + return BadRequestException(-1, "连接超时"); | |
17 | + case DioExceptionType.sendTimeout: | |
18 | + return BadRequestException(-1, "请求超时"); | |
19 | + case DioExceptionType.receiveTimeout: | |
20 | + return BadRequestException(-1, "响应超时"); | |
21 | + case DioExceptionType.badCertificate: | |
22 | + return BadRequestException(-1, "证书错误"); | |
23 | + case DioExceptionType.badResponse: | |
24 | + return BadRequestException(-1, "返回错误"); | |
25 | + case DioExceptionType.cancel: | |
26 | + return BadRequestException(-1, "请求取消"); | |
27 | + case DioExceptionType.connectionError: | |
28 | + return BadRequestException(-1, "连接错误"); | |
29 | + case DioExceptionType.unknown: | |
30 | + try { | |
31 | + /// http错误码带业务错误信息 | |
32 | + ApiResponse apiResponse = ApiResponse.fromJson(error.response?.data); | |
33 | + if (apiResponse.code != null) { | |
34 | + return ApiException(apiResponse.code, apiResponse.msg); | |
35 | + } | |
36 | + | |
37 | + int? errCode = error.response?.statusCode; | |
38 | + switch (errCode) { | |
39 | + case 400: | |
40 | + return BadRequestException(errCode, "请求语法错误"); | |
41 | + case 401: | |
42 | + return UnauthorisedException(errCode!, "没有权限"); | |
43 | + case 403: | |
44 | + return UnauthorisedException(errCode!, "服务器拒绝执行"); | |
45 | + case 404: | |
46 | + return UnauthorisedException(errCode!, "无法连接服务器"); | |
47 | + case 405: | |
48 | + return UnauthorisedException(errCode!, "请求方法被禁止"); | |
49 | + case 500: | |
50 | + return UnauthorisedException(errCode!, "服务器内部错误"); | |
51 | + case 502: | |
52 | + return UnauthorisedException(errCode!, "无效的请求"); | |
53 | + case 503: | |
54 | + return UnauthorisedException(errCode!, "服务器异常"); | |
55 | + case 505: | |
56 | + return UnauthorisedException(errCode!, "不支持HTTP协议请求"); | |
57 | + default: | |
58 | + return ApiException(errCode, error.response?.statusMessage ?? '未知错误'); | |
59 | + } | |
60 | + } on Exception catch (e) { | |
61 | + return ApiException(-1, unknownException); | |
62 | + } | |
63 | + default: | |
64 | + return ApiException(-1, error.message); | |
65 | + } | |
66 | + } | |
67 | + | |
68 | + factory ApiException.from(dynamic exception) { | |
69 | + if (exception is DioException) { | |
70 | + return ApiException.fromDioError(exception); | |
71 | + } | |
72 | + if (exception is ApiException) { | |
73 | + return exception; | |
74 | + } else { | |
75 | + var apiException = ApiException(-1, unknownException); | |
76 | + apiException.stackInfo = exception?.toString(); | |
77 | + return apiException; | |
78 | + } | |
79 | + } | |
80 | +} | |
81 | + | |
82 | +/// 请求错误 | |
83 | +class BadRequestException extends ApiException { | |
84 | + BadRequestException([int? code, String? message]) : super(code, message); | |
85 | +} | |
86 | + | |
87 | +/// 未认证异常 | |
88 | +class UnauthorisedException extends ApiException { | |
89 | + UnauthorisedException([int code = -1, String message = '']) : super(code, message); | |
90 | +} | ... | ... |
lib/common/request/exception_handler.dart
0 → 100644
1 | +import 'package:flutter_easyloading/flutter_easyloading.dart'; | |
2 | + | |
3 | +import 'exception.dart'; | |
4 | + | |
5 | + | |
6 | +bool handleException(ApiException exception, | |
7 | + {bool Function(ApiException)? onError}) { | |
8 | + if (onError?.call(exception) == true) { | |
9 | + return true; | |
10 | + } | |
11 | + | |
12 | + if (exception.code == 401) { | |
13 | + ///todo to login | |
14 | + return true; | |
15 | + } | |
16 | + EasyLoading.showError(exception.message ?? ApiException.unknownException); | |
17 | + | |
18 | + return false; | |
19 | +} | ... | ... |
lib/common/request/request.dart
0 → 100644
1 | +import '../../utils/loading.dart'; | |
2 | +import 'exception.dart'; | |
3 | +import 'exception_handler.dart'; | |
4 | + | |
5 | +Future request( | |
6 | + Function() block, { | |
7 | + bool showLoading = true, | |
8 | + bool Function(ApiException)? onError, | |
9 | +}) async { | |
10 | + try { | |
11 | + await loading(block, isShowLoading: showLoading); | |
12 | + } catch (e) { | |
13 | + handleException(ApiException.from(e), onError: onError); | |
14 | + } | |
15 | + return; | |
16 | +} | ... | ... |
lib/common/request/request_client.dart
0 → 100644
1 | +import 'dart:convert'; | |
2 | + | |
3 | +import 'package:dio/dio.dart'; | |
4 | +import 'package:pretty_dio_logger/pretty_dio_logger.dart'; | |
5 | + | |
6 | +import 'api_response/api_response_entity.dart'; | |
7 | +import 'api_response/raw_data.dart'; | |
8 | +import 'config.dart'; | |
9 | +import 'exception.dart'; | |
10 | +import 'token_interceptor.dart'; | |
11 | + | |
12 | +RequestClient requestClient = RequestClient(); | |
13 | + | |
14 | +class RequestClient { | |
15 | + late Dio _dio; | |
16 | + | |
17 | + RequestClient() { | |
18 | + _dio = Dio(BaseOptions(baseUrl: RequestConfig.baseUrl, connectTimeout: RequestConfig.connectTimeout)); | |
19 | + _dio.interceptors.add(TokenInterceptor()); | |
20 | + _dio.interceptors.add(PrettyDioLogger(requestHeader: true, requestBody: true, responseHeader: true)); | |
21 | + } | |
22 | + | |
23 | + Future<T?> request<T>( | |
24 | + String url, { | |
25 | + required String method, | |
26 | + Map<String, dynamic>? queryParameters, | |
27 | + data, | |
28 | + Map<String, dynamic>? headers, | |
29 | + Function(ApiResponse<T>)? onResponse, | |
30 | + bool Function(ApiException)? onError, | |
31 | + }) async { | |
32 | + try { | |
33 | + Options options = Options() | |
34 | + ..method = method | |
35 | + ..headers = headers; | |
36 | + | |
37 | + data = _convertRequestData(data); | |
38 | + | |
39 | + Response response = await _dio.request(url, queryParameters: queryParameters, data: data, options: options); | |
40 | + | |
41 | + return _handleResponse<T>(response, onResponse); | |
42 | + } catch (e) { | |
43 | + var exception = ApiException.from(e); | |
44 | + if (onError?.call(exception) != true) { | |
45 | + throw exception; | |
46 | + } | |
47 | + } | |
48 | + | |
49 | + return null; | |
50 | + } | |
51 | + | |
52 | + _convertRequestData(data) { | |
53 | + if (data != null) { | |
54 | + data = jsonDecode(jsonEncode(data)); | |
55 | + } | |
56 | + return data; | |
57 | + } | |
58 | + | |
59 | + /// get | |
60 | + Future<T?> get<T>( | |
61 | + String url, { | |
62 | + Map<String, dynamic>? queryParameters, | |
63 | + Map<String, dynamic>? headers, | |
64 | + bool showLoading = true, | |
65 | + Function(ApiResponse<T>)? onResponse, | |
66 | + bool Function(ApiException)? onError, | |
67 | + }) { | |
68 | + return request(url, | |
69 | + method: 'GET', queryParameters: queryParameters, headers: headers, onResponse: onResponse, onError: onError); | |
70 | + } | |
71 | + | |
72 | + /// post | |
73 | + Future<T?> post<T>( | |
74 | + String url, { | |
75 | + Map<String, dynamic>? queryParameters, | |
76 | + data, | |
77 | + Map<String, dynamic>? headers, | |
78 | + bool showLoading = true, | |
79 | + Function(ApiResponse<T>)? onResponse, | |
80 | + bool Function(ApiException)? onError, | |
81 | + }) { | |
82 | + return request(url, | |
83 | + method: "POST", | |
84 | + queryParameters: queryParameters, | |
85 | + data: data, | |
86 | + headers: headers, | |
87 | + onResponse: onResponse, | |
88 | + onError: onError); | |
89 | + } | |
90 | + | |
91 | + /// delete | |
92 | + Future<T?> delete<T>( | |
93 | + String url, { | |
94 | + Map<String, dynamic>? queryParameters, | |
95 | + data, | |
96 | + Map<String, dynamic>? headers, | |
97 | + bool showLoading = true, | |
98 | + Function(ApiResponse<T>)? onResponse, | |
99 | + bool Function(ApiException)? onError, | |
100 | + }) { | |
101 | + return request(url, | |
102 | + method: "DELETE", | |
103 | + queryParameters: queryParameters, | |
104 | + data: data, | |
105 | + headers: headers, | |
106 | + onResponse: onResponse, | |
107 | + onError: onError); | |
108 | + } | |
109 | + | |
110 | + /// put | |
111 | + Future<T?> put<T>( | |
112 | + String url, { | |
113 | + Map<String, dynamic>? queryParameters, | |
114 | + data, | |
115 | + Map<String, dynamic>? headers, | |
116 | + bool showLoading = true, | |
117 | + Function(ApiResponse<T>)? onResponse, | |
118 | + bool Function(ApiException)? onError, | |
119 | + }) { | |
120 | + return request(url, | |
121 | + method: "PUT", | |
122 | + queryParameters: queryParameters, | |
123 | + data: data, | |
124 | + headers: headers, | |
125 | + onResponse: onResponse, | |
126 | + onError: onError); | |
127 | + } | |
128 | + | |
129 | + /// 请求响应内容处理 | |
130 | + T? _handleResponse<T>( | |
131 | + Response response, | |
132 | + Function(ApiResponse<T>)? onResponse, | |
133 | + ) { | |
134 | + int statusCode = response.statusCode ?? -1; | |
135 | + print('statusCode=$statusCode'); | |
136 | + // 200..299 成功响应 | |
137 | + if (statusCode >= 200 && statusCode <= 299) { | |
138 | + if (T.toString() == (RawData).toString()) { | |
139 | + RawData raw = RawData(); | |
140 | + raw.value = response.data; | |
141 | + return raw as T; | |
142 | + } else { | |
143 | + ApiResponse<T> apiResponse = ApiResponse<T>.fromJson(response.data); | |
144 | + onResponse?.call(apiResponse); | |
145 | + return _handleBusinessResponse<T>(apiResponse); | |
146 | + } | |
147 | + } else { | |
148 | + var exception = ApiException(response.statusCode, ApiException.unknownException); | |
149 | + throw exception; | |
150 | + } | |
151 | + } | |
152 | + | |
153 | + /// 业务内容处理 | |
154 | + T? _handleBusinessResponse<T>(ApiResponse<T> response) { | |
155 | + if (response.code == RequestConfig.successCode) { | |
156 | + return response.data; | |
157 | + } else { | |
158 | + var exception = ApiException(response.code, response.msg); | |
159 | + throw exception; | |
160 | + } | |
161 | + } | |
162 | +} | ... | ... |
lib/common/request/token_interceptor.dart
0 → 100644
1 | +import 'package:dio/dio.dart'; | |
2 | + | |
3 | +class TokenInterceptor extends Interceptor { | |
4 | + @override | |
5 | + void onRequest(RequestOptions options, RequestInterceptorHandler handler) { | |
6 | + /// todo 判断token不为空插入 | |
7 | + options.headers["Auth-token"] = ''; | |
8 | + options.headers["version"] = '1.0.0'; | |
9 | + super.onRequest(options, handler); | |
10 | + } | |
11 | +} | ... | ... |
lib/generated/json/base/json_convert_content.dart
0 → 100644
1 | +// ignore_for_file: non_constant_identifier_names | |
2 | +// ignore_for_file: camel_case_types | |
3 | +// ignore_for_file: prefer_single_quotes | |
4 | + | |
5 | +// This file is automatically generated. DO NOT EDIT, all your changes would be lost. | |
6 | +import 'package:flutter/material.dart' show debugPrint; | |
7 | +import 'package:wow_english/models/user_entity.dart'; | |
8 | + | |
9 | +JsonConvert jsonConvert = JsonConvert(); | |
10 | +typedef JsonConvertFunction<T> = T Function(Map<String, dynamic> json); | |
11 | +typedef EnumConvertFunction<T> = T Function(String value); | |
12 | + | |
13 | +class JsonConvert { | |
14 | + static final Map<String, JsonConvertFunction> convertFuncMap = { | |
15 | + (UserEntity).toString(): UserEntity.fromJson, | |
16 | + }; | |
17 | + | |
18 | + T? convert<T>(dynamic value, {EnumConvertFunction? enumConvert}) { | |
19 | + if (value == null) { | |
20 | + return null; | |
21 | + } | |
22 | + if (value is T) { | |
23 | + return value; | |
24 | + } | |
25 | + try { | |
26 | + return _asT<T>(value, enumConvert: enumConvert); | |
27 | + } catch (e, stackTrace) { | |
28 | + debugPrint('asT<$T> $e $stackTrace'); | |
29 | + return null; | |
30 | + } | |
31 | + } | |
32 | + | |
33 | + List<T?>? convertList<T>(List<dynamic>? value, {EnumConvertFunction? enumConvert}) { | |
34 | + if (value == null) { | |
35 | + return null; | |
36 | + } | |
37 | + try { | |
38 | + return value.map((dynamic e) => _asT<T>(e,enumConvert: enumConvert)).toList(); | |
39 | + } catch (e, stackTrace) { | |
40 | + debugPrint('asT<$T> $e $stackTrace'); | |
41 | + return <T>[]; | |
42 | + } | |
43 | + } | |
44 | + | |
45 | +List<T>? convertListNotNull<T>(dynamic value, {EnumConvertFunction? enumConvert}) { | |
46 | + if (value == null) { | |
47 | + return null; | |
48 | + } | |
49 | + try { | |
50 | + return (value as List<dynamic>).map((dynamic e) => _asT<T>(e,enumConvert: enumConvert)!).toList(); | |
51 | + } catch (e, stackTrace) { | |
52 | + debugPrint('asT<$T> $e $stackTrace'); | |
53 | + return <T>[]; | |
54 | + } | |
55 | + } | |
56 | + | |
57 | + T? _asT<T extends Object?>(dynamic value, | |
58 | + {EnumConvertFunction? enumConvert}) { | |
59 | + final String type = T.toString(); | |
60 | + final String valueS = value.toString(); | |
61 | + if (enumConvert != null) { | |
62 | + return enumConvert(valueS) as T; | |
63 | + } else if (type == "String") { | |
64 | + return valueS as T; | |
65 | + } else if (type == "int") { | |
66 | + final int? intValue = int.tryParse(valueS); | |
67 | + if (intValue == null) { | |
68 | + return double.tryParse(valueS)?.toInt() as T?; | |
69 | + } else { | |
70 | + return intValue as T; | |
71 | + } | |
72 | + } else if (type == "double") { | |
73 | + return double.parse(valueS) as T; | |
74 | + } else if (type == "DateTime") { | |
75 | + return DateTime.parse(valueS) as T; | |
76 | + } else if (type == "bool") { | |
77 | + if (valueS == '0' || valueS == '1') { | |
78 | + return (valueS == '1') as T; | |
79 | + } | |
80 | + return (valueS == 'true') as T; | |
81 | + } else if (type == "Map" || type.startsWith("Map<")) { | |
82 | + return value as T; | |
83 | + } else { | |
84 | + if (convertFuncMap.containsKey(type)) { | |
85 | + return convertFuncMap[type]!(Map<String, dynamic>.from(value)) as T; | |
86 | + } else { | |
87 | + throw UnimplementedError('$type unimplemented'); | |
88 | + } | |
89 | + } | |
90 | + } | |
91 | + | |
92 | + //list is returned by type | |
93 | + static M? _getListChildType<M>(List<Map<String, dynamic>> data) { | |
94 | + if(<UserEntity>[] is M){ | |
95 | + return data.map<UserEntity>((Map<String, dynamic> e) => UserEntity.fromJson(e)).toList() as M; | |
96 | + } | |
97 | + | |
98 | + debugPrint("${M.toString()} not found"); | |
99 | + | |
100 | + return null; | |
101 | +} | |
102 | + | |
103 | + static M? fromJsonAsT<M>(dynamic json) { | |
104 | + if (json is List) { | |
105 | + return _getListChildType<M>(json.map((e) => e as Map<String, dynamic>).toList()); | |
106 | + } else { | |
107 | + return jsonConvert.convert<M>(json); | |
108 | + } | |
109 | + } | |
110 | +} | ... | ... |
lib/generated/json/base/json_field.dart
0 → 100644
1 | +// ignore_for_file: non_constant_identifier_names | |
2 | +// ignore_for_file: camel_case_types | |
3 | +// ignore_for_file: prefer_single_quotes | |
4 | + | |
5 | +// This file is automatically generated. DO NOT EDIT, all your changes would be lost. | |
6 | + | |
7 | +class JsonSerializable{ | |
8 | + const JsonSerializable(); | |
9 | +} | |
10 | + | |
11 | +class JSONField { | |
12 | + //Specify the parse field name | |
13 | + final String? name; | |
14 | + | |
15 | + //Whether to participate in toJson | |
16 | + final bool? serialize; | |
17 | + | |
18 | + //Whether to participate in fromMap | |
19 | + final bool? deserialize; | |
20 | + | |
21 | + //Enumeration or not | |
22 | + final bool? isEnum; | |
23 | + | |
24 | + const JSONField({this.name, this.serialize, this.deserialize, this.isEnum}); | |
25 | +} | ... | ... |
lib/generated/json/user_entity.g.dart
0 → 100644
1 | +import 'package:wow_english/generated/json/base/json_convert_content.dart'; | |
2 | +import 'package:wow_english/models/user_entity.dart'; | |
3 | + | |
4 | +UserEntity $UserEntityFromJson(Map<String, dynamic> json) { | |
5 | + final UserEntity userEntity = UserEntity(); | |
6 | + final int? id = jsonConvert.convert<int>(json['id']); | |
7 | + if (id != null) { | |
8 | + userEntity.id = id; | |
9 | + } | |
10 | + final String? name = jsonConvert.convert<String>(json['name']); | |
11 | + if (name != null) { | |
12 | + userEntity.name = name; | |
13 | + } | |
14 | + final int? age = jsonConvert.convert<int>(json['age']); | |
15 | + if (age != null) { | |
16 | + userEntity.age = age; | |
17 | + } | |
18 | + final int? gender = jsonConvert.convert<int>(json['gender']); | |
19 | + if (gender != null) { | |
20 | + userEntity.gender = gender; | |
21 | + } | |
22 | + final String? avatarUrl = jsonConvert.convert<String>(json['avatarUrl']); | |
23 | + if (avatarUrl != null) { | |
24 | + userEntity.avatarUrl = avatarUrl; | |
25 | + } | |
26 | + final String? phoneNum = jsonConvert.convert<String>(json['phoneNum']); | |
27 | + if (phoneNum != null) { | |
28 | + userEntity.phoneNum = phoneNum; | |
29 | + } | |
30 | + final String? token = jsonConvert.convert<String>(json['token']); | |
31 | + if (token != null) { | |
32 | + userEntity.token = token; | |
33 | + } | |
34 | + final int? expireTime = jsonConvert.convert<int>(json['expireTime']); | |
35 | + if (expireTime != null) { | |
36 | + userEntity.expireTime = expireTime; | |
37 | + } | |
38 | + return userEntity; | |
39 | +} | |
40 | + | |
41 | +Map<String, dynamic> $UserEntityToJson(UserEntity entity) { | |
42 | + final Map<String, dynamic> data = <String, dynamic>{}; | |
43 | + data['id'] = entity.id; | |
44 | + data['name'] = entity.name; | |
45 | + data['age'] = entity.age; | |
46 | + data['gender'] = entity.gender; | |
47 | + data['avatarUrl'] = entity.avatarUrl; | |
48 | + data['phoneNum'] = entity.phoneNum; | |
49 | + data['token'] = entity.token; | |
50 | + data['expireTime'] = entity.expireTime; | |
51 | + return data; | |
52 | +} | ... | ... |
lib/home/home_page.dart
... | ... | @@ -32,6 +32,8 @@ class _HomePageView extends StatelessWidget { |
32 | 32 | Navigator.of(AppRouter.context).pushNamed(AppRouteName.listen); |
33 | 33 | } else if (type == HeaderActionType.shop) { |
34 | 34 | Navigator.of(AppRouter.context).pushNamed(AppRouteName.shop); |
35 | + } else if (type == HeaderActionType.user) { | |
36 | + Navigator.of(AppRouter.context).pushNamed(AppRouteName.user); | |
35 | 37 | } else { |
36 | 38 | // Navigator.of(AppRouter.context).pushNamed(AppRouteName.topicPic); |
37 | 39 | // Navigator.of(AppRouter.context).pushNamed(AppRouteName.topicWord); |
... | ... | @@ -117,4 +119,4 @@ class _HomePageView extends StatelessWidget { |
117 | 119 | ), |
118 | 120 | ); |
119 | 121 | }); |
120 | -} | |
121 | 122 | \ No newline at end of file |
123 | +} | ... | ... |
lib/home/widgets/home_tab_header_widget.dart
... | ... | @@ -12,7 +12,7 @@ enum HeaderActionType { |
12 | 12 | //购买 |
13 | 13 | shop, |
14 | 14 | //个人信息 |
15 | - userinfo | |
15 | + user | |
16 | 16 | } |
17 | 17 | |
18 | 18 | class HomeTabHeaderWidget extends StatelessWidget { |
... | ... | @@ -34,7 +34,7 @@ class HomeTabHeaderWidget extends StatelessWidget { |
34 | 34 | GestureDetector( |
35 | 35 | onTap: () { |
36 | 36 | if(actionTap != null) { |
37 | - actionTap!(HeaderActionType.userinfo); | |
37 | + actionTap!(HeaderActionType.user); | |
38 | 38 | } |
39 | 39 | }, |
40 | 40 | child: Container( |
... | ... | @@ -56,7 +56,7 @@ class HomeTabHeaderWidget extends StatelessWidget { |
56 | 56 | GestureDetector( |
57 | 57 | onTap: () { |
58 | 58 | if(actionTap != null) { |
59 | - actionTap!(HeaderActionType.userinfo); | |
59 | + actionTap!(HeaderActionType.user); | |
60 | 60 | } |
61 | 61 | }, |
62 | 62 | child: Container( |
... | ... | @@ -128,4 +128,4 @@ class HomeTabHeaderWidget extends StatelessWidget { |
128 | 128 | ), |
129 | 129 | ); |
130 | 130 | } |
131 | -} | |
132 | 131 | \ No newline at end of file |
132 | +} | ... | ... |
lib/login/loginpage/bloc/login_bloc.dart
1 | 1 | import 'package:flutter/cupertino.dart'; |
2 | 2 | import 'package:flutter_bloc/flutter_bloc.dart'; |
3 | -import 'package:wow_english/network/api.dart'; | |
4 | -import 'package:wow_english/network/network_manager.dart'; | |
3 | +import 'package:flutter_easyloading/flutter_easyloading.dart'; | |
4 | + | |
5 | +import '../../../common/request/api_response/api_response_entity.dart'; | |
6 | +import '../../../common/request/apis.dart'; | |
7 | +import '../../../common/request/request.dart'; | |
8 | +import '../../../common/request/request_client.dart'; | |
9 | +import '../../../models/user_entity.dart'; | |
5 | 10 | |
6 | 11 | part 'login_event.dart'; |
7 | 12 | part 'login_state.dart'; |
... | ... | @@ -9,26 +14,35 @@ part 'login_state.dart'; |
9 | 14 | enum LoginType { |
10 | 15 | ///密码登陆 |
11 | 16 | pwd, |
17 | + | |
12 | 18 | ///验证码登陆 |
13 | 19 | sms, |
14 | 20 | } |
15 | 21 | |
16 | 22 | class LoginBloc extends Bloc<LoginEvent, LoginState> { |
17 | - | |
18 | 23 | bool _canLogin = false; |
24 | + | |
19 | 25 | ///是否可以发送验证码 |
20 | 26 | bool _canSendSms = false; |
27 | + | |
21 | 28 | ///是否阅读协议 |
22 | 29 | bool _agreement = false; |
30 | + | |
23 | 31 | ///登陆方式 |
24 | - LoginType _loginType = LoginType.sms; | |
32 | + //LoginType _loginType = LoginType.sms; | |
33 | + bool _isSmsLoginType = true; | |
25 | 34 | |
26 | 35 | final TextEditingController phoneNumController = TextEditingController(); |
27 | 36 | final TextEditingController checkNumController = TextEditingController(); |
28 | 37 | |
29 | 38 | bool get canLogin => _canLogin; |
39 | + | |
30 | 40 | bool get agreement => _agreement; |
31 | - LoginType get loginType => _loginType; | |
41 | + | |
42 | + //LoginType get loginType => _loginType; | |
43 | + | |
44 | + bool get isSmsLoginType => _isSmsLoginType; | |
45 | + | |
32 | 46 | bool get canSendSms => _canSendSms; |
33 | 47 | |
34 | 48 | LoginBloc() : super(LoginInitial()) { |
... | ... | @@ -40,22 +54,40 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> { |
40 | 54 | on<RequestSmsCodeEvent>(_requestSmsCodeApi); |
41 | 55 | } |
42 | 56 | |
43 | - | |
44 | 57 | ///请求登陆 |
45 | 58 | void _requestLoginApi(RequestLoginEvent event, Emitter<LoginState> emitter) async { |
46 | - await DioUtil().requestData( | |
47 | - Api.login, | |
48 | - method: HttpMethod.post, | |
49 | - data: { | |
50 | - 'phoneNum':'17730280759', | |
51 | - 'type':_loginType.toString(), | |
52 | - 'password':'asd123456'}, | |
53 | - successCallBack: (data){ | |
54 | - emitter(LoginResultChangeState(true)); | |
59 | + var phoneNumber = phoneNumController.text; | |
60 | + if (phoneNumber.isEmpty) { | |
61 | + EasyLoading.showToast('号码不能为空'); | |
62 | + return; | |
63 | + } | |
64 | + | |
65 | + var checkNumber = checkNumController.text; | |
66 | + if (checkNumber.isEmpty) { | |
67 | + var text = _isSmsLoginType ? '密码' : '验证码'; | |
68 | + EasyLoading.showToast('$text不能为空'); | |
69 | + return; | |
70 | + } | |
71 | + var checkKey = _isSmsLoginType ? 'smsCode' : 'password'; | |
72 | + var type = _isSmsLoginType ? 'sms_code' : 'pwd'; | |
73 | + | |
74 | + request(() async { | |
75 | + var params = {'phoneNum': phoneNumber, 'type': type, checkKey: checkNumber}; | |
76 | + await requestClient.post( | |
77 | + Apis.login, | |
78 | + data: params, | |
79 | + onResponse: (ApiResponse<UserEntity> response) { | |
80 | + print('response=$response'); | |
81 | + // todo 持久化用户对象 | |
82 | + // todo 写入全局对象 | |
83 | + //emitter.call(LoginResultChangeState()); | |
84 | + }, | |
85 | + onError: (e) { | |
86 | + EasyLoading.showToast('登陆失败:${e.message}'); | |
87 | + return true; | |
55 | 88 | }, |
56 | - errorCallBack: (error){ | |
57 | - emitter(LoginResultChangeState(false)); | |
58 | - }); | |
89 | + ); | |
90 | + }); | |
59 | 91 | } |
60 | 92 | |
61 | 93 | ///请求验证码 |
... | ... | @@ -65,10 +97,10 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> { |
65 | 97 | |
66 | 98 | ///切换登陆方式 |
67 | 99 | void _changeLoginType(ChangeLoginTypeEvent event, Emitter<LoginState> emitter) async { |
68 | - if (_loginType == LoginType.sms) { | |
69 | - _loginType = LoginType.pwd; | |
100 | + if (_isSmsLoginType) { | |
101 | + _isSmsLoginType = false; | |
70 | 102 | } else { |
71 | - _loginType = LoginType.sms; | |
103 | + _isSmsLoginType = true; | |
72 | 104 | } |
73 | 105 | checkNumController.clear(); |
74 | 106 | if (_loginStateChange()) { |
... | ... | @@ -79,7 +111,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> { |
79 | 111 | |
80 | 112 | ///手机号输入 |
81 | 113 | void _changePhoneNumber(PhoneNumChangeEvent event, Emitter<LoginState> emitter) async { |
82 | - if(phoneNumController.text.isNotEmpty) { | |
114 | + if (phoneNumController.text.isNotEmpty) { | |
83 | 115 | if (!_canSendSms) { |
84 | 116 | _canSendSms = true; |
85 | 117 | emitter(SmsSendTypeChangeState()); |
... | ... | @@ -99,7 +131,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> { |
99 | 131 | } |
100 | 132 | |
101 | 133 | ///验证码/密码输入变化 |
102 | - void _checkFiledChange(CheckFieldChangeEvent event,Emitter<LoginState> emitter) async { | |
134 | + void _checkFiledChange(CheckFieldChangeEvent event, Emitter<LoginState> emitter) async { | |
103 | 135 | if (_loginStateChange()) { |
104 | 136 | emitter(LoginEventChangeState()); |
105 | 137 | } | ... | ... |
lib/login/loginpage/bloc/login_state.dart
... | ... | @@ -4,18 +4,20 @@ part of 'login_bloc.dart'; |
4 | 4 | abstract class LoginState {} |
5 | 5 | |
6 | 6 | class LoginInitial extends LoginState {} |
7 | + | |
7 | 8 | ///登陆按钮状态 |
8 | 9 | class LoginEventChangeState extends LoginState {} |
10 | + | |
9 | 11 | ///切换登陆方式 |
10 | 12 | class LoginTypeChangeState extends LoginState {} |
13 | + | |
11 | 14 | ///发送验证码按钮状态 |
12 | 15 | class SmsSendTypeChangeState extends LoginState {} |
16 | + | |
13 | 17 | ///是否同意协议 |
14 | 18 | class AgreementTypeChangeState extends LoginState {} |
15 | 19 | ///获取验证码 |
16 | 20 | class SmsCodeRequestState extends LoginState {} |
21 | + | |
17 | 22 | ///登陆请求结果 |
18 | -class LoginResultChangeState extends LoginState { | |
19 | - bool result = false; | |
20 | - LoginResultChangeState(this.result); | |
21 | -} | |
23 | +class LoginResultChangeState extends LoginState {} | ... | ... |
lib/login/loginpage/login_page.dart
1 | 1 | import 'package:flutter/gestures.dart'; |
2 | 2 | import 'package:flutter/material.dart'; |
3 | 3 | import 'package:flutter_bloc/flutter_bloc.dart'; |
4 | -import 'package:flutter_easyloading/flutter_easyloading.dart'; | |
5 | 4 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
6 | 5 | import 'package:wow_english/common/extension/string_extension.dart'; |
7 | 6 | import 'package:wow_english/common/widgets/textfield_customer_widget.dart'; |
... | ... | @@ -27,7 +26,6 @@ class _LoginPageView extends StatelessWidget { |
27 | 26 | return BlocListener<LoginBloc,LoginState>( |
28 | 27 | listener: (context, state){ |
29 | 28 | if (state is LoginResultChangeState) { |
30 | - EasyLoading.showToast('登陆接口回调'); | |
31 | 29 | Navigator.of(context).pushNamed(AppRouteName.home); |
32 | 30 | } |
33 | 31 | }, |
... | ... | @@ -61,7 +59,7 @@ class _LoginPageView extends StatelessWidget { |
61 | 59 | ), |
62 | 60 | padding: EdgeInsets.symmetric(horizontal: 18.w,vertical: 5.h), |
63 | 61 | child: Text( |
64 | - bloc.loginType == LoginType.sms?'密码登陆':'验证码密码', | |
62 | + bloc.isSmsLoginType?'密码登陆':'验证码密码', | |
65 | 63 | style: TextStyle( |
66 | 64 | fontSize: 16.sp |
67 | 65 | ), |
... | ... | @@ -78,11 +76,11 @@ class _LoginPageView extends StatelessWidget { |
78 | 76 | width: 131.w, |
79 | 77 | ), |
80 | 78 | Offstage( |
81 | - offstage: bloc.loginType == LoginType.pwd, | |
79 | + offstage: !bloc.isSmsLoginType, | |
82 | 80 | child: _buildSmsViewWidget(), |
83 | 81 | ), |
84 | 82 | Offstage( |
85 | - offstage: bloc.loginType == LoginType.sms, | |
83 | + offstage: bloc.isSmsLoginType, | |
86 | 84 | child: _buildPwdViewWidget(), |
87 | 85 | ), |
88 | 86 | Row( |
... | ... | @@ -313,5 +311,3 @@ class _LoginPageView extends StatelessWidget { |
313 | 311 | ); |
314 | 312 | }); |
315 | 313 | } |
316 | - | |
317 | - | ... | ... |
lib/models/response_model.dart renamed to lib/models/response_model.dart.txt
lib/models/response_model.g.dart renamed to lib/models/response_model.g.dart.txt
lib/models/test_model.dart deleted
1 | -import 'package:json_annotation/json_annotation.dart'; | |
2 | - | |
3 | -part 'test_model.g.dart'; | |
4 | - | |
5 | -@JsonSerializable() | |
6 | -class TestModel { | |
7 | - @JsonKey(name: 'test_name') | |
8 | - String? name; | |
9 | - @JsonKey(defaultValue: '男') | |
10 | - String? sex; | |
11 | - int? age; | |
12 | - | |
13 | - TestModel({this.name,this.sex,this.age}); | |
14 | - | |
15 | - factory TestModel.fromJson(Map<String, dynamic> json) => _$TestModelFromJson(json); | |
16 | - | |
17 | - Map<String, dynamic> toJson() => _$TestModelToJson(this); | |
18 | -} | |
19 | 0 | \ No newline at end of file |
lib/models/test_model.g.dart deleted
1 | -// GENERATED CODE - DO NOT MODIFY BY HAND | |
2 | - | |
3 | -part of 'test_model.dart'; | |
4 | - | |
5 | -// ************************************************************************** | |
6 | -// JsonSerializableGenerator | |
7 | -// ************************************************************************** | |
8 | - | |
9 | -TestModel _$TestModelFromJson(Map<String, dynamic> json) => TestModel( | |
10 | - name: json['test_name'] as String?, | |
11 | - sex: json['sex'] as String? ?? '男', | |
12 | - age: json['age'] as int?, | |
13 | - ); | |
14 | - | |
15 | -Map<String, dynamic> _$TestModelToJson(TestModel instance) => <String, dynamic>{ | |
16 | - 'test_name': instance.name, | |
17 | - 'sex': instance.sex, | |
18 | - 'age': instance.age, | |
19 | - }; |
lib/models/user_entity.dart
0 → 100644
1 | +import 'dart:convert'; | |
2 | + | |
3 | +import 'package:wow_english/generated/json/base/json_field.dart'; | |
4 | +import 'package:wow_english/generated/json/user_entity.g.dart'; | |
5 | + | |
6 | +@JsonSerializable() | |
7 | +class UserEntity { | |
8 | + late int id; | |
9 | + late String name; | |
10 | + late int age; | |
11 | + late int gender; | |
12 | + late String avatarUrl; | |
13 | + late String phoneNum; | |
14 | + late String token; | |
15 | + late int expireTime; | |
16 | + | |
17 | + UserEntity(); | |
18 | + | |
19 | + factory UserEntity.fromJson(Map<String, dynamic> json) => $UserEntityFromJson(json); | |
20 | + | |
21 | + Map<String, dynamic> toJson() => $UserEntityToJson(this); | |
22 | + | |
23 | + @override | |
24 | + String toString() { | |
25 | + return jsonEncode(this); | |
26 | + } | |
27 | +} | ... | ... |
lib/network/api.dart renamed to lib/network/api.dart.txt
lib/network/basic_configuration.dart renamed to lib/network/basic_configuration.dart.txt
1 | 1 | enum DevelopEvent { |
2 | 2 | ///开发环境 |
3 | 3 | dev, |
4 | + | |
4 | 5 | ///正式环境 |
5 | 6 | formal |
6 | 7 | } |
... | ... | @@ -12,12 +13,13 @@ class BasicConfigurationManager { |
12 | 13 | |
13 | 14 | //服务器地址 |
14 | 15 | String? baseUrl; |
16 | + | |
15 | 17 | //SessionId |
16 | 18 | String? sessionId; |
17 | 19 | |
18 | - BasicConfigurationManager._internal(){ | |
20 | + BasicConfigurationManager._internal() { | |
19 | 21 | DevelopEvent developType = DevelopEvent.dev; |
20 | - if(developType == DevelopEvent.dev) { | |
22 | + if (developType == DevelopEvent.dev) { | |
21 | 23 | baseUrl = 'http://wow-app.dev.kouyuxingqiu.com/'; |
22 | 24 | } else { |
23 | 25 | baseUrl = 'http://wow-app.dev.kouyuxingqiu.com/'; | ... | ... |
lib/network/network_manager.dart renamed to lib/network/network_manager.dart.txt
1 | -import 'dart:io'; | |
2 | - | |
3 | 1 | import 'package:dio/dio.dart'; |
4 | 2 | import 'package:flutter/foundation.dart'; |
5 | -import 'package:flutter_easyloading/flutter_easyloading.dart'; | |
6 | 3 | import 'package:wow_english/models/response_model.dart'; |
7 | -import 'package:wow_english/network/basic_configuration.dart'; | |
8 | - | |
4 | +import 'package:wow_english/network/basic_configuration.dart.txt'; | |
9 | 5 | |
10 | 6 | enum HttpMethod { |
11 | 7 | get, |
... | ... | @@ -27,24 +23,22 @@ class DioUtil { |
27 | 23 | |
28 | 24 | static BaseOptions getDefOptions() { |
29 | 25 | final BaseOptions options = BaseOptions(); |
30 | - options.baseUrl = BasicConfigurationManager().baseUrl??''; | |
26 | + options.baseUrl = BasicConfigurationManager().baseUrl ?? ''; | |
31 | 27 | options.connectTimeout = const Duration(milliseconds: 1000); |
32 | 28 | options.receiveTimeout = const Duration(milliseconds: 1000); |
33 | - options.headers['content-type'] = 'application/x-www-form-urlencoded'; | |
34 | 29 | return options; |
35 | 30 | } |
36 | 31 | |
37 | 32 | Future<void> requestData<T>( |
38 | - String path, { | |
39 | - data, | |
40 | - // HttpMethod method = HttpMethod.post, | |
41 | - Map<String, dynamic>? queryParameters, | |
42 | - ProgressCallback? onSendProgress, | |
43 | - ProgressCallback? onReceiveProgress, | |
44 | - required Function successCallBack, | |
45 | - required Function errorCallBack, | |
46 | - required HttpMethod method, | |
47 | - }) async{ | |
33 | + HttpMethod method, | |
34 | + String path, { | |
35 | + data, | |
36 | + Function? successCallBack, | |
37 | + Function? errorCallBack, | |
38 | + Map<String, dynamic>? queryParameters, | |
39 | + ProgressCallback? onSendProgress, | |
40 | + ProgressCallback? onReceiveProgress, | |
41 | + }) async { | |
48 | 42 | try { |
49 | 43 | Map<String, dynamic> headers = <String, dynamic>{}; |
50 | 44 | |
... | ... | @@ -52,32 +46,31 @@ class DioUtil { |
52 | 46 | headers['content-type'] = 'application/json'; |
53 | 47 | } |
54 | 48 | Response<dynamic> response; |
55 | - response = await _dio.request( | |
56 | - path, | |
57 | - data: data??{}, | |
49 | + response = await _dio.request(path, | |
50 | + data: data ?? {}, | |
58 | 51 | queryParameters: queryParameters, |
59 | - options: Options(method: method.name,headers: headers), | |
52 | + options: Options(method: method.name, headers: headers), | |
60 | 53 | onSendProgress: onSendProgress, |
61 | 54 | onReceiveProgress: onReceiveProgress); |
62 | - if (response.statusCode == HttpStatus.ok || response.statusCode == HttpStatus.created) { | |
55 | + int statusCode = response.statusCode ?? 0; | |
56 | + if (statusCode >= 200 && statusCode < 300) { | |
63 | 57 | if (kDebugMode) { |
64 | 58 | print(response.data); |
65 | 59 | } |
66 | 60 | final ResponseModel model = ResponseModel.fromJson(response.data); |
67 | - if (model.code != 200) { | |
68 | - errorCallBack(model.msg); | |
61 | + if (model.code == 200) { | |
62 | + successCallBack?.call(response.data); | |
69 | 63 | } else { |
70 | - successCallBack(response.data); | |
64 | + errorCallBack?.call(model.msg); | |
71 | 65 | } |
72 | 66 | } else { |
73 | - errorCallBack('请求失败'); | |
67 | + errorCallBack?.call('请求失败'); | |
74 | 68 | } |
75 | - } on DioError catch(error) { | |
76 | - EasyLoading.dismiss(); | |
69 | + } on DioException catch (error) { | |
77 | 70 | if (kDebugMode) { |
78 | 71 | print(error); |
79 | 72 | } |
80 | - rethrow; | |
73 | + errorCallBack?.call("网络错误: ${error.message}"); | |
81 | 74 | } |
82 | 75 | } |
83 | -} | |
84 | 76 | \ No newline at end of file |
77 | +} | ... | ... |
lib/utils/loading.dart
0 → 100644
1 | +import 'package:flutter_easyloading/flutter_easyloading.dart'; | |
2 | + | |
3 | +Future loading(Function block, {bool isShowLoading = true}) async { | |
4 | + if (isShowLoading) { | |
5 | + showLoading(); | |
6 | + } | |
7 | + try { | |
8 | + await block(); | |
9 | + } catch (e) { | |
10 | + rethrow; | |
11 | + } finally { | |
12 | + dismissLoading(); | |
13 | + } | |
14 | + return; | |
15 | +} | |
16 | + | |
17 | +void showLoading() { | |
18 | + EasyLoading.show(status: "加载中..."); | |
19 | +} | |
20 | + | |
21 | +void dismissLoading() { | |
22 | + EasyLoading.dismiss(); | |
23 | +} | ... | ... |
pubspec.yaml
... | ... | @@ -37,6 +37,8 @@ dependencies: |
37 | 37 | cupertino_icons: ^1.0.2 |
38 | 38 | #网络请求 https://pub.dev/packages/dio |
39 | 39 | dio: ^5.1.2 |
40 | + # https://pub.dev/packages/pretty_dio_logger | |
41 | + pretty_dio_logger: ^1.3.1 | |
40 | 42 | #谷歌字体 https://pub.dev/packages/google_fonts |
41 | 43 | google_fonts: ^4.0.4 |
42 | 44 | #状态管理 https://pub.dev/packages/flutter_bloc |
... | ... | @@ -64,9 +66,9 @@ dependencies: |
64 | 66 | # 拍照,从相册中选择 https://pub.flutter-io.cn/packages/image_picker |
65 | 67 | image_picker: ^0.8.7+5 |
66 | 68 | # 支付宝支付SDK https://pub.flutter-io.cn/packages/tobias |
67 | -# tobias: ^3.1.0 | |
69 | + # tobias: ^3.1.0 | |
68 | 70 | # 微信SDK相关 https://pub.flutter-io.cn/packages/fluwx |
69 | -# fluwx: ^4.2.4+1 | |
71 | + # fluwx: ^4.2.4+1 | |
70 | 72 | # json数据解析 https://pub.flutter-io.cn/packages/json_annotation |
71 | 73 | json_annotation: ^4.8.1 |
72 | 74 | # double丢失精度问题 https://pub.dev/packages/decimal | ... | ... |