diff --git a/lib/api/api_path.dart b/lib/api/api_path.dart index 8be3538..2b8d92c 100644 --- a/lib/api/api_path.dart +++ b/lib/api/api_path.dart @@ -1,3 +1,5 @@ class ApiPath { static const String sendValidationCode = "/v1/common/sendValidationCode"; + static const String validationCodeLogin = "/v1/user/codeLogin"; + static const String passwordLogin = "/v1/user/pwdLogin"; } diff --git a/lib/api/base_api_service.dart b/lib/api/base_api_service.dart index 4e393cb..77866a4 100644 --- a/lib/api/base_api_service.dart +++ b/lib/api/base_api_service.dart @@ -13,20 +13,7 @@ class BaseApiService { dio.options.connectTimeout = const Duration(seconds: 30); dio.options.receiveTimeout = const Duration(seconds: 30); - // 🔥 添加日志拦截器 - if (kDebugMode) { - dio.interceptors.add(dioAlias.LogInterceptor( - request: true, - requestHeader: true, - requestBody: true, - responseHeader: true, - responseBody: true, - error: true, - logPrint: (obj) { - debugPrint('[DIO] $obj'); - }, - )); - } + } /// 统一请求方法 diff --git a/lib/api/model/common/request/send_validation_code_request.dart b/lib/api/model/common/request/send_validation_code_request.dart index 1c77d38..4336fe2 100644 --- a/lib/api/model/common/request/send_validation_code_request.dart +++ b/lib/api/model/common/request/send_validation_code_request.dart @@ -1,12 +1,13 @@ // 验证码接口请求参数 // 登陆后可使用 sendValidationCodeAuth 接口,免图片滑动验证,只需要 channel,codeType 两个参数即可 -import 'package:starwork_flutter/common/constant/validation_code_type.dart'; +import 'package:starwork_flutter/common/constant/verification_code_channel.dart'; +import 'package:starwork_flutter/common/constant/verification_code_type.dart'; class SendValidationCodeRequest { final String countryCode; final String account; - final String channel; //1 短信,2 邮箱 - final ValidationCodeType codeType; + final VerificationCodeChannel channel; //1 短信,2 邮箱 + final VerificationCodeType codeType; SendValidationCodeRequest({ required this.countryCode, @@ -19,7 +20,7 @@ class SendValidationCodeRequest { return { 'countryCode': countryCode, 'account': account, - 'channel': channel, + 'channel': channel.value, 'codeType': codeType.value, }; } diff --git a/lib/api/model/user/response/token_response.dart b/lib/api/model/user/response/token_response.dart new file mode 100644 index 0000000..73b17d3 --- /dev/null +++ b/lib/api/model/user/response/token_response.dart @@ -0,0 +1,9 @@ +class LoginResponse { + final String token; + + LoginResponse({required this.token}); + + factory LoginResponse.fromJson(Map json) { + return LoginResponse(token: json['token']); + } +} diff --git a/lib/api/model/user/user_model.dart b/lib/api/model/user/user_model.dart deleted file mode 100644 index ef0109d..0000000 --- a/lib/api/model/user/user_model.dart +++ /dev/null @@ -1,24 +0,0 @@ - -class UserModel { - final int id; - final String name; - final String email; - - UserModel({required this.id, required this.name, required this.email}); - - factory UserModel.fromJson(Map json) { - return UserModel( - id: json['id'], - name: json['name'], - email: json['email'], - ); - } - - Map toJson() { - return { - 'id': id, - 'name': name, - 'email': email, - }; - } -} \ No newline at end of file diff --git a/lib/api/service/common_api_service.dart b/lib/api/service/common_api_service.dart index 9ee9076..a862a2c 100644 --- a/lib/api/service/common_api_service.dart +++ b/lib/api/service/common_api_service.dart @@ -2,8 +2,6 @@ import 'package:starwork_flutter/api/api_path.dart'; import 'package:starwork_flutter/api/api_response.dart'; import 'package:starwork_flutter/api/base_api_service.dart'; import 'package:starwork_flutter/api/model/common/request/send_validation_code_request.dart'; -import 'package:starwork_flutter/api/model/string_response.dart'; -import 'package:starwork_flutter/api/model/user/user_model.dart'; import 'package:starwork_flutter/common/constant/http_constant.dart'; class CommonApiService { diff --git a/lib/api/service/user_api_service.dart b/lib/api/service/user_api_service.dart index 8376059..dfa157a 100644 --- a/lib/api/service/user_api_service.dart +++ b/lib/api/service/user_api_service.dart @@ -1,20 +1,26 @@ import 'package:get/get.dart'; +import 'package:starwork_flutter/api/api_path.dart'; import 'package:starwork_flutter/api/api_response.dart'; import 'package:starwork_flutter/api/base_api_service.dart'; -import 'package:starwork_flutter/api/model/user/user_model.dart'; +import 'package:starwork_flutter/api/model/user/request/validation_code_login.dart'; +import 'package:starwork_flutter/api/model/user/response/token_response.dart'; +import 'package:starwork_flutter/common/constant/http_constant.dart'; class UserApiService { final BaseApiService _api; UserApiService(this._api); // 通过构造函数注入 - Future> login(Map userData) { + // 验证码登录 + Future> validationCodeLogin({ + required ValidationCodeLoginRequest request, + }) { return _api.makeRequest( // 通过实例调用 - path: '/login', - method: 'POST', - data: userData, - fromJson: (data) => UserModel.fromJson(data), + path: ApiPath.validationCodeLogin, + method: HttpConstant.post, + data: request.toJson(), + fromJson: (data) => LoginResponse.fromJson(data), ); } } diff --git a/lib/app.dart b/lib/app.dart index abb4bbb..e422ba3 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,7 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:starwork_flutter/common/constant/cache_keys.dart'; +import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart'; import 'package:starwork_flutter/flavors.dart'; import 'package:starwork_flutter/i18n/app_i18n.dart'; import 'package:starwork_flutter/routes/app_pages.dart'; @@ -19,11 +22,15 @@ class App extends StatelessWidget { builder: (_, child) { return GetMaterialApp( theme: ThemeData( - textSelectionTheme: TextSelectionThemeData( - cursorColor: Colors.blue.shade200, - selectionColor: Colors.blue.shade100, - selectionHandleColor: Colors.blue.shade300, - )), + scaffoldBackgroundColor: Colors.white, + brightness: Brightness.light, + textSelectionTheme: TextSelectionThemeData( + cursorColor: Colors.blue.shade200, + selectionColor: Colors.blue.shade100, + selectionHandleColor: Colors.blue.shade300, + ), + dialogBackgroundColor: Colors.white, + ), // 必须配置以下三个本地化代理 localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, // 提供Material组件本地化字符串 @@ -41,10 +48,20 @@ class App extends StatelessWidget { fallbackLocale: const Locale('zh', 'CN'), // 必须设置 fallback 没有该语言时使用 getPages: AppPages.pages, - initialRoute: AppRoutes.login, + initialRoute: _checkIsLogin(), debugShowCheckedModeBanner: false, + builder: EasyLoading.init(), ); }, ); } + + String _checkIsLogin() { + var token = SharedPreferencesUtils.getString(CacheKeys.token); + if (token != null && token.isNotEmpty) { + return AppRoutes.main; + } else { + return AppRoutes.login; + } + } } diff --git a/lib/base/app_initialization.dart b/lib/base/app_initialization.dart index cd806f3..99467f8 100644 --- a/lib/base/app_initialization.dart +++ b/lib/base/app_initialization.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:starwork_flutter/api/base_api_service.dart'; @@ -9,6 +10,8 @@ import 'package:starwork_flutter/api/service/common_api_service.dart'; import 'package:starwork_flutter/api/service/user_api_service.dart'; import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart'; import 'package:starwork_flutter/i18n/app_i18n.dart'; +import 'package:starwork_flutter/views/login/login_controller.dart'; +import 'package:starwork_flutter/views/main/main_controller.dart'; class AppInitialization { static Future initializeApp() async { @@ -16,18 +19,18 @@ class AppInitialization { WidgetsFlutterBinding.ensureInitialized(); setSystemStatusBar(); await SharedPreferencesUtils.init(); + initEasyLoading(); - // 日志:方便调试 - print('✅ SharedPreferences initialized'); - - Get.lazyPut(() => BaseApiService()); - Get.lazyPut(() => CommonApiService(Get.find())); + Get.put(BaseApiService()); + Get.put(CommonApiService(Get.find())); + Get.put(UserApiService(Get.find())); + Get.put(LoginController()); + Get.put(MainController()); print('✅ API services registered'); } catch (e, stack) { print('❌ Initialization failed: $e'); print(stack); - // 可以上报错误(Sentry 等) rethrow; } } @@ -43,4 +46,20 @@ class AppInitialization { ); } } + + static void initEasyLoading() { + EasyLoading.instance + ..displayDuration = const Duration(milliseconds: 1000) + ..indicatorType = EasyLoadingIndicatorType.wanderingCubes + ..loadingStyle = EasyLoadingStyle.dark + ..indicatorSize = 45.0 + ..radius = 10.0 + ..progressColor = Colors.yellow + ..backgroundColor = Colors.green + ..indicatorColor = Colors.yellow + ..textColor = Colors.yellow + ..maskColor = Colors.blue.withOpacity(0.5) + ..userInteractions = false + ..dismissOnTap = false; + } } diff --git a/lib/base/base_controller.dart b/lib/base/base_controller.dart index 2b6bb90..6130de9 100644 --- a/lib/base/base_controller.dart +++ b/lib/base/base_controller.dart @@ -1,17 +1,34 @@ import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:get/get.dart'; class BaseController extends GetxController { void showToast(String message) { - Fluttertoast.showToast( - msg: message, - toastLength: Toast.LENGTH_SHORT, - gravity: ToastGravity.CENTER, - backgroundColor: Colors.black54, - textColor: Colors.white, - fontSize: 14.0.sp, - ); + EasyLoading.showToast(message); + } + + void showLoading() { + EasyLoading.show(status: 'loading...'); + } + + void hideLoading() { + EasyLoading.dismiss(); + } + + void showSuccess({String message = '操作成功'}) { + EasyLoading.showSuccess(message.tr); + } + + void showError({String message = '操作失败'}) { + EasyLoading.showError(message.tr); + } + + @override + void onClose() { + if (EasyLoading.isShow) { + EasyLoading.dismiss(); + } + super.onClose(); } } diff --git a/lib/common/constant/cache_keys.dart b/lib/common/constant/cache_keys.dart index e1fba86..1f3c81a 100644 --- a/lib/common/constant/cache_keys.dart +++ b/lib/common/constant/cache_keys.dart @@ -1,3 +1,4 @@ class CacheKeys { + static const String isSendValidationCode = 'isSendValidationCode'; static const String token = 'token'; } diff --git a/lib/common/constant/platform_type.dart b/lib/common/constant/platform_type.dart new file mode 100644 index 0000000..88865e6 --- /dev/null +++ b/lib/common/constant/platform_type.dart @@ -0,0 +1,36 @@ +class PlatformType { + static const web = PlatformType('1', 'web'); + static const app = PlatformType('2', 'app'); + static const smallProgram = PlatformType('3', '小程序'); + static const pc = PlatformType('4', 'pc'); + + final String value; + final String label; + + const PlatformType(this.value, this.label); + + // 支持通过字符串值查找枚举实例 + static PlatformType? fromValue(String? value) { + return { + '1': web, + '2': app, + '3': smallProgram, + '4': pc, + }[value]; + } + + // 支持 toString() 直接输出 value + @override + String toString() => value; + + // 可选:支持 == 比较 + @override + bool operator ==(Object other) => + identical(this, other) || + other is PlatformType && + runtimeType == other.runtimeType && + value == other.value; + + @override + int get hashCode => value.hashCode; +} diff --git a/lib/common/constant/validation_code_type.dart b/lib/common/constant/validation_code_type.dart deleted file mode 100644 index 2eff7bd..0000000 --- a/lib/common/constant/validation_code_type.dart +++ /dev/null @@ -1,46 +0,0 @@ -class ValidationCodeType { - static const login = ValidationCodeType('1', '登录'); - static const reset = ValidationCodeType('2', '重置密码'); - static const bindPhone = ValidationCodeType('3', '绑定手机号'); - static const unbindPhone = ValidationCodeType('4', '解绑手机号'); - static const deleteAccount = ValidationCodeType('5', '删除账号'); - static const bindEmail = ValidationCodeType('6', '绑定邮箱'); - static const unbindEmail = ValidationCodeType('7', '解绑邮箱'); - static const deleteLock = ValidationCodeType('8', '删除门锁'); - static const updatePassword = ValidationCodeType('9', '修改密码'); - - final String value; - final String label; - - const ValidationCodeType(this.value, this.label); - - // 支持通过字符串值查找枚举实例 - static ValidationCodeType? fromValue(String? value) { - return { - '1': login, - '2': reset, - '3': bindPhone, - '4': unbindPhone, - '5': deleteAccount, - '6': bindEmail, - '7': unbindEmail, - '8': deleteLock, - '9': updatePassword, - }[value]; - } - - // 支持 toString() 直接输出 value - @override - String toString() => value; - - // 可选:支持 == 比较 - @override - bool operator ==(Object other) => - identical(this, other) || - other is ValidationCodeType && - runtimeType == other.runtimeType && - value == other.value; - - @override - int get hashCode => value.hashCode; -} diff --git a/lib/common/constant/validation_code_channel.dart b/lib/common/constant/verification_code_channel.dart similarity index 62% rename from lib/common/constant/validation_code_channel.dart rename to lib/common/constant/verification_code_channel.dart index 5b13b93..c391c9a 100644 --- a/lib/common/constant/validation_code_channel.dart +++ b/lib/common/constant/verification_code_channel.dart @@ -1,15 +1,15 @@ // Description: 验证码渠道枚举类 -class ValidationCodeChannel { - static const sms = ValidationCodeChannel('1', '短信'); - static const email = ValidationCodeChannel('2', '邮箱'); +class VerificationCodeChannel { + static const sms = VerificationCodeChannel('1', '短信'); + static const email = VerificationCodeChannel('2', '邮箱'); final String value; final String label; - const ValidationCodeChannel(this.value, this.label); + const VerificationCodeChannel(this.value, this.label); // 支持通过字符串值查找枚举实例 - static ValidationCodeChannel? fromValue(String? value) { + static VerificationCodeChannel? fromValue(String? value) { return { '1': sms, '2': email, @@ -24,7 +24,7 @@ class ValidationCodeChannel { @override bool operator ==(Object other) => identical(this, other) || - other is ValidationCodeChannel && + other is VerificationCodeChannel && runtimeType == other.runtimeType && value == other.value; diff --git a/lib/common/constant/verification_code_type.dart b/lib/common/constant/verification_code_type.dart new file mode 100644 index 0000000..27f786f --- /dev/null +++ b/lib/common/constant/verification_code_type.dart @@ -0,0 +1,46 @@ +class VerificationCodeType { + static const login = VerificationCodeType('1', '登录'); + static const reset = VerificationCodeType('2', '重置密码'); + static const bindPhone = VerificationCodeType('3', '绑定手机号'); + static const unbindPhone = VerificationCodeType('4', '解绑手机号'); + static const deleteAccount = VerificationCodeType('5', '删除账号'); + static const bindEmail = VerificationCodeType('6', '绑定邮箱'); + static const unbindEmail = VerificationCodeType('7', '解绑邮箱'); + static const deleteLock = VerificationCodeType('8', '删除门锁'); + static const updatePassword = VerificationCodeType('9', '修改密码'); + + final String value; + final String label; + + const VerificationCodeType(this.value, this.label); + + // 支持通过字符串值查找枚举实例 + static VerificationCodeType? fromValue(String? value) { + return { + '1': login, + '2': reset, + '3': bindPhone, + '4': unbindPhone, + '5': deleteAccount, + '6': bindEmail, + '7': unbindEmail, + '8': deleteLock, + '9': updatePassword, + }[value]; + } + + // 支持 toString() 直接输出 value + @override + String toString() => value; + + // 可选:支持 == 比较 + @override + bool operator ==(Object other) => + identical(this, other) || + other is VerificationCodeType && + runtimeType == other.runtimeType && + value == other.value; + + @override + int get hashCode => value.hashCode; +} diff --git a/lib/common/utils/shared_preferences_utils.dart b/lib/common/utils/shared_preferences_utils.dart index 0b6b5ce..34a505d 100644 --- a/lib/common/utils/shared_preferences_utils.dart +++ b/lib/common/utils/shared_preferences_utils.dart @@ -1,4 +1,5 @@ import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:async'; class SharedPreferencesUtils { static SharedPreferences? _prefs; @@ -8,7 +9,63 @@ class SharedPreferencesUtils { _prefs = await SharedPreferences.getInstance(); } - // 使用 + + /// 存储带过期时间的字符串 + /// [key] 键 + /// [value] 值 + /// [expiry] 过期时间(如 Duration(hours: 1)) + static Future setStringWithExpiry( + String key, + String value, + Duration expiry, + ) async { + final prefs = _prefs; + if (prefs == null) return false; + + final expiryKey = '_expiry_$key'; // 用 _expiry_ 前缀标记过期时间 + final expireAt = DateTime.now().add(expiry).millisecondsSinceEpoch; + + // 使用 Transaction 确保原子性(可选) + return await prefs.setString(key, value) && + await prefs.setInt(expiryKey, expireAt); + } + + /// 获取带过期时间的字符串 + /// 如果已过期,则自动删除并返回 null + static String? getStringWithExpiry(String key) { + final prefs = _prefs; + if (prefs == null) return null; + + final expiryKey = '_expiry_$key'; + final expireAt = prefs.getInt(expiryKey); + + // 如果没有过期时间,视为永不过期(或已过期?根据需求) + if (expireAt == null) { + return prefs.getString(key); + } + + // 比较当前时间 + final now = DateTime.now().millisecondsSinceEpoch; + if (now > expireAt) { + // 已过期,清理 + removeKeyWithExpiry(key); + return null; + } + + return prefs.getString(key); + } + + /// 删除带过期时间的键(清理 value 和 expiry) + static Future removeKeyWithExpiry(String key) async { + final prefs = _prefs; + if (prefs == null) return; + + final expiryKey = '_expiry_$key'; + await prefs.remove(key); + await prefs.remove(expiryKey); + } + + static Future setString(String key, String value) async { return _prefs?.setString(key, value) ?? Future.value(false); } @@ -16,4 +73,4 @@ class SharedPreferencesUtils { static String? getString(String key) { return _prefs?.getString(key); } -} +} \ No newline at end of file diff --git a/lib/views/login/inputVerificationCode/input_verification_code_controller.dart b/lib/views/login/inputVerificationCode/input_verification_code_controller.dart index eafed43..e933f29 100644 --- a/lib/views/login/inputVerificationCode/input_verification_code_controller.dart +++ b/lib/views/login/inputVerificationCode/input_verification_code_controller.dart @@ -1,10 +1,24 @@ import 'dart:async'; import 'package:get/get.dart'; +import 'package:starwork_flutter/api/api_response.dart'; +import 'package:starwork_flutter/api/model/common/request/send_validation_code_request.dart'; +import 'package:starwork_flutter/api/model/user/request/validation_code_login.dart'; +import 'package:starwork_flutter/api/service/common_api_service.dart'; +import 'package:starwork_flutter/api/service/user_api_service.dart'; import 'package:starwork_flutter/base/base_controller.dart'; +import 'package:starwork_flutter/common/constant/cache_keys.dart'; +import 'package:starwork_flutter/common/constant/platform_type.dart'; +import 'package:starwork_flutter/common/constant/verification_code_channel.dart'; +import 'package:starwork_flutter/common/constant/verification_code_type.dart'; +import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart'; import 'package:starwork_flutter/routes/app_routes.dart'; class InputVerificationCodeController extends BaseController { + final userApi = Get.find(); + final commonApi = Get.find(); + + var rawPhone = ''.obs; var phone = ''.obs; var previousRoute = ''.obs; @@ -15,7 +29,7 @@ class InputVerificationCodeController extends BaseController { var countdownValue = 60.obs; @override - void onInit() { + void onInit() async { super.onInit(); final params = Get.parameters; @@ -24,56 +38,92 @@ class InputVerificationCodeController extends BaseController { previousRoute.value = Get.previousRoute; // 如 "/login" if (phoneParam != null && phoneParam.isNotEmpty) { + rawPhone.value = phoneParam; phone.value = maskMiddleFive(phoneParam); - // 开始倒计时(比如60秒) - startCountdown(); + if (previousRoute.value.contains(AppRoutes.login)) { + seedVerificationCode(codeType: VerificationCodeType.login); + } else if (previousRoute.value.contains(AppRoutes.forgotPassword)) { + seedVerificationCode(codeType: VerificationCodeType.reset); + } } } + @override + void onClose() { + super.onClose(); + String key = '${CacheKeys.isSendValidationCode}_${rawPhone.value}'; + String value = '${rawPhone.value}_${countdownValue.value}'; + // 存储发送验证码的时间戳,避免重复发送 + SharedPreferencesUtils.setStringWithExpiry( + key, + value, + Duration(seconds: countdownValue.value), + ); + } + String maskMiddleFive(String phone) { if (phone.length < 8) return phone; // 如果手机号少于8位,不处理(或根据需求返回原值/报错) - - // 假设手机号至少有 8 位,我们保留前 3 位,中间 5 位替换为 ****,显示后 3 位 - // 13812345678 → 138****678 String firstPart = phone.substring(0, 3); // 前3位:138 String middleReplaced = '*****'; // 中间5位替换为 **** String lastPart = phone.substring(8); // 后3位:678 - return '$firstPart$middleReplaced$lastPart'; // 拼接:138****678 } - /// 开始倒计时(比如60秒) - void startCountdown() { - if (isCountingDown.value) return; // 避免重复启动 - - isCountingDown.value = true; - countdownValue.value = 60; - - // 使用 Timer 实现倒计时 - Timer.periodic(const Duration(seconds: 1), (timer) { - if (countdownValue.value > 1) { - countdownValue.value--; - } else { - timer.cancel(); // 停止计时器 - isCountingDown.value = false; - countdownValue.value = 0; - } - }); - } - - void requestPhoneCodeLogin(String code) { + // 校验验证码 + void checkVerificationCode(String pin) { if (previousRoute.value.contains(AppRoutes.login)) { - _handleLogin(); + Get.offAllNamed(AppRoutes.main); } else if (previousRoute.value.contains(AppRoutes.forgotPassword)) { - _handleForgotPassword(); + Get.toNamed(AppRoutes.setNewPassword); } } - void _handleLogin() { - Get.offAndToNamed(AppRoutes.main); + void _handleSeedVerificationCode({ + required VerificationCodeType codeType, + }) async {} + + // 发送验证码 + void seedVerificationCode({ + required VerificationCodeType codeType, + }) async { + showLoading(); + var sendValidationCodeResult = await commonApi.sendValidationCode( + request: SendValidationCodeRequest( + countryCode: '+86', + account: rawPhone.value.trim(), + channel: VerificationCodeChannel.sms, + codeType: codeType, + ), + ); + if (sendValidationCodeResult.isSuccess) { + if (isCountingDown.value) return; // 避免重复启动 + + isCountingDown.value = true; + countdownValue.value = 60; + + // 使用 Timer 实现倒计时 + Timer.periodic(const Duration(seconds: 1), (timer) { + if (countdownValue.value > 1) { + countdownValue.value--; + } else { + timer.cancel(); // 停止计时器 + isCountingDown.value = false; + countdownValue.value = 0; + } + }); + showSuccess(message: '验证码已发送,请注意查收'.tr); + } else { + showError(message: sendValidationCodeResult.errorMsg!); + } + hideLoading(); } - void _handleForgotPassword() { - Get.toNamed(AppRoutes.setNewPassword); +// 跳转页面 + void _toPage() async { + if (previousRoute.value.contains(AppRoutes.login)) { + Get.offAllNamed(AppRoutes.main); + } else if (previousRoute.value.contains(AppRoutes.forgotPassword)) { + Get.toNamed(AppRoutes.setNewPassword); + } } } diff --git a/lib/views/login/inputVerificationCode/input_verification_code_view.dart b/lib/views/login/inputVerificationCode/input_verification_code_view.dart index b5ef988..d785260 100644 --- a/lib/views/login/inputVerificationCode/input_verification_code_view.dart +++ b/lib/views/login/inputVerificationCode/input_verification_code_view.dart @@ -3,6 +3,8 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:pinput/pinput.dart'; +import 'package:starwork_flutter/common/constant/verification_code_type.dart'; +import 'package:starwork_flutter/routes/app_routes.dart'; import 'package:starwork_flutter/views/login/inputVerificationCode/input_verification_code_controller.dart'; class InputVerificationCodeView @@ -47,6 +49,7 @@ class InputVerificationCodeView Pinput( length: 6, obscureText: false, + autofocus: true, defaultPinTheme: PinTheme( width: 50.w, height: 50.w, @@ -63,7 +66,7 @@ class InputVerificationCodeView return null; }, onCompleted: (pin) { - controller.requestPhoneCodeLogin(pin); + controller.checkVerificationCode(pin); }, ), ], @@ -106,7 +109,15 @@ class InputVerificationCodeView } else { return GestureDetector( onTap: () { - controller.startCountdown(); + if (controller.previousRoute.value.contains(AppRoutes.login)) { + controller.seedVerificationCode( + codeType: VerificationCodeType.login, + ); + } else if (controller.previousRoute.value.contains(AppRoutes.forgotPassword)) { + controller.seedVerificationCode( + codeType: VerificationCodeType.reset, + ); + } }, child: Text( '重新获取验证码'.tr, diff --git a/lib/views/login/login_controller.dart b/lib/views/login/login_controller.dart index 9b2f428..724a1cb 100644 --- a/lib/views/login/login_controller.dart +++ b/lib/views/login/login_controller.dart @@ -2,21 +2,16 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:get/get.dart'; -import 'package:starwork_flutter/api/model/common/request/send_validation_code_request.dart'; -import 'package:starwork_flutter/api/service/common_api_service.dart'; -import 'package:starwork_flutter/base/base_controller.dart'; -import 'package:starwork_flutter/common/constant/login_type.dart'; -import 'package:starwork_flutter/common/constant/validation_code_channel.dart'; -import 'package:starwork_flutter/common/constant/validation_code_type.dart'; -import 'package:starwork_flutter/routes/app_pages.dart'; +import 'package:get/get.dart'; +import 'package:starwork_flutter/base/base_controller.dart'; +import 'package:starwork_flutter/common/constant/cache_keys.dart'; +import 'package:starwork_flutter/common/constant/login_type.dart'; +import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart'; + import 'package:starwork_flutter/routes/app_routes.dart'; class LoginController extends BaseController { - final commonApi = Get.find(); - int phoneNumberSize = 11; TextEditingController phoneController = TextEditingController(); TextEditingController passwordController = TextEditingController(); @@ -44,7 +39,6 @@ class LoginController extends BaseController { void _validateForm() { isFormValid.value = phoneController.text.length == phoneNumberSize; - debugPrint('isFormValid: ${isFormValid.value}'); } // 获取手机验证码 @@ -55,23 +49,15 @@ class LoginController extends BaseController { content: '1', onConfirm: () async { isPrivacyAgreementValid.value = 1; + Get.toNamed( + AppRoutes.inputVerificationCode, + parameters: { + 'phone': phoneController.text.trim(), + }, + ); }, ); - } - _handleRequestPhoneCode(); - } - - void _handleRequestPhoneCode() async { - var sendValidationCodeResult = await commonApi.sendValidationCode( - request: SendValidationCodeRequest( - countryCode: '+86', - account: phoneController.text.trim(), - channel: ValidationCodeChannel.sms.value, - codeType: ValidationCodeType.login, - ), - ); - - if (sendValidationCodeResult.isSuccess) { + } else { Get.toNamed( AppRoutes.inputVerificationCode, parameters: { @@ -88,10 +74,10 @@ class LoginController extends BaseController { }) { Get.dialog( Dialog( + backgroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14.r), // 圆角 ), - backgroundColor: Colors.white, child: Column( mainAxisSize: MainAxisSize.min, children: [ diff --git a/pubspec.lock b/pubspec.lock index 4b14e2b..37d5265 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -126,6 +126,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_easyloading: + dependency: "direct main" + description: + name: flutter_easyloading + sha256: ba21a3c883544e582f9cc455a4a0907556714e1e9cf0eababfcb600da191d17c + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.5" flutter_flavorizr: dependency: "direct dev" description: @@ -155,6 +163,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "5.9.3" + flutter_spinkit: + dependency: "direct main" + description: + name: flutter_spinkit + sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472 + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.2.1" flutter_test: dependency: "direct dev" description: flutter @@ -165,14 +181,6 @@ packages: description: flutter source: sdk version: "0.0.0" - fluttertoast: - dependency: "direct main" - description: - name: fluttertoast - sha256: "95f349437aeebe524ef7d6c9bde3e6b4772717cf46a0eb6a3ceaddc740b297cc" - url: "https://pub.flutter-io.cn" - source: hosted - version: "8.2.8" get: dependency: "direct main" description: @@ -461,6 +469,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.4.1" + skeletonizer: + dependency: "direct main" + description: + name: skeletonizer + sha256: "0dcacc51c144af4edaf37672072156f49e47036becbc394d7c51850c5c1e884b" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.3" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 8994dde..adfa556 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -25,12 +25,15 @@ dependencies: shared_preferences: ^2.2.3 # 屏幕适配 flutter_screenutil: ^5.9.3 - # 提示 - fluttertoast: ^8.2.8 # 验证码输入框 pinput: ^5.0.1 # 网络请求库 dio: ^5.9.0 + # loading 动画库 需要指定flutter_spinkit为固定版本 + flutter_easyloading: ^3.0.0 + flutter_spinkit: 5.2.1 + # 骨架屏 + skeletonizer: ^1.4.3 dev_dependencies: