Commit 056970d81f6fc136aef89e88912071f87b2f4bc2

Authored by Key
1 parent 725dc3f2

feat: api

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
  1 +class RawData{
  2 + dynamic value;
  3 +}
0 4 \ No newline at end of file
... ...
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
  1 +///request config
  2 +class RequestConfig {
  3 + static String baseUrl = 'http://wow-app.dev.kouyuxingqiu.com/';
  4 + static const connectTimeout = Duration(seconds: 15);
  5 + static const successCode = 200;
  6 +}
... ...
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 &#39;login_state.dart&#39;;
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&lt;LoginEvent, LoginState&gt; {
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&lt;LoginEvent, LoginState&gt; {
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&lt;LoginEvent, LoginState&gt; {
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&lt;LoginEvent, LoginState&gt; {
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 &#39;login_bloc.dart&#39;;
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
1 1 // GENERATED CODE - DO NOT MODIFY BY HAND
2 2  
3   -part of 'response_model.dart';
  3 +part of 'response_model.dart.txt';
4 4  
5 5 // **************************************************************************
6 6 // JsonSerializableGenerator
... ...
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
... ...