diff --git a/lib/controller/mine/login_controller.dart b/lib/controller/mine/login_controller.dart index 493df7d..d2c0f0e 100644 --- a/lib/controller/mine/login_controller.dart +++ b/lib/controller/mine/login_controller.dart @@ -141,7 +141,7 @@ class LoginController extends GetxController { } // 使用UserController获取基础信息 - await userController.getBaseUserInfo(userId); + await userController.getBaseUserInfo(userId, false); } catch (e) { // 获取用户信息失败不影响登录流程 print('获取用户信息异常: $e'); diff --git a/lib/controller/mine/phone_controller.dart b/lib/controller/mine/phone_controller.dart new file mode 100644 index 0000000..7ce0496 --- /dev/null +++ b/lib/controller/mine/phone_controller.dart @@ -0,0 +1,114 @@ +import 'dart:async'; +import 'package:get/get.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import '../../network/user_api.dart'; +import '../global.dart'; + +class PhoneController extends GetxController { + late UserApi _userApi; + final phone = ''.obs; + // 手机号输入 + final phoneNumber = ''.obs; + // 验证码输入 + final verificationCode = ''.obs; + // 是否正在发送验证码 + final isSendingCode = false.obs; + // 倒计时秒数 + final countdownSeconds = 0.obs; + // 是否正在登录中 + final isLoggingIn = false.obs; + final tabIndex = 0.obs; + + @override + void onInit() { + super.onInit(); + // 从全局依赖中获取UserApi + _userApi = Get.find(); + phone.value = GlobalData().userData!.phone!; + } + + // 获取验证码 + Future getVerificationCode() async { + if (countdownSeconds.value > 0) { + return; + } + // 验证手机号格式 + if (phoneNumber.value.isEmpty || phoneNumber.value.length != 11) { + SmartDialog.showToast('请输入正确的手机号'); + return; + } + isSendingCode.value = true; + try { + // 构建请求参数 + final params = { + 'purpose': 3, // 认证 + 'verifiableAccount': phoneNumber.value, + 'verifiableAccountType': 1, // 手机 + }; + // 调用UserApi中的验证码接口 + final response = await _userApi.getVerificationCode(params); + // 处理响应 + if (response.data.isSuccess) { + // 生产环境移除打印,可考虑使用正式的日志框架 + SmartDialog.showToast('验证码发送成功'); + // 开始倒计时 + countdownSeconds.value = 60; + startCountdown(); + } else { + SmartDialog.showToast(response.data.message); + } + } catch (e) { + SmartDialog.showToast('网络请求失败,请重试'); + } finally { + isSendingCode.value = false; + } + } + + // 开始倒计时 + void startCountdown() { + Future.delayed(const Duration(seconds: 1), () { + if (countdownSeconds.value > 0) { + countdownSeconds.value--; + startCountdown(); + } else { + isSendingCode.value = false; + } + }); + } + + Future changePhone() async { + if(isSendingCode.value){ + return; + } + if (phoneNumber.value.isEmpty) { + SmartDialog.showToast('请输入手机号'); + return; + } + if (verificationCode.value.isEmpty) { + SmartDialog.showToast('请输入验证码'); + return; + } + isSendingCode.value = true; + try { + // 调用登录接口 + SmartDialog.showLoading(msg: '处理中'); + final param = { 'phone': phoneNumber.value, 'captcha': verificationCode.value}; + final response = await _userApi.updatePhone(param); + // 处理响应 + if (response.data.isSuccess) { + GlobalData().userData!.phone = phoneNumber.value; + SmartDialog.showToast('更换成功'); + Get.back(result: 1); + } else { + SmartDialog.showToast(response.data.message); + } + } catch (e) { + SmartDialog.showToast('网络请求失败,请检查网络连接'); + } finally { + SmartDialog.dismiss(); + isSendingCode.value = true; + } + } + +} + diff --git a/lib/controller/mine/user_controller.dart b/lib/controller/mine/user_controller.dart index bdba3ee..efa1462 100644 --- a/lib/controller/mine/user_controller.dart +++ b/lib/controller/mine/user_controller.dart @@ -52,63 +52,83 @@ class UserController extends GetxController { } } + bool _checkInformation(UserData information){ + if(information.id == null){ + return true; + } + if(information.id!.isEmpty){ + return true; + } + if(information.genderCode == null){ + return true; + } + if(information.genderCode!.isNaN){ + return true; + } + if(information.birthYear == null){ + return true; + } + if(information.nickName == null){ + return true; + } + if(information.nickName!.isEmpty){ + return true; + } + return false; + } + /// 获取用户基础信息 - Future getBaseUserInfo(String userId) async { + Future getBaseUserInfo(String userId, bool isMain) async { try { final response = await _userApi.getBaseUserInfo(userId); if (response.data.isSuccess && response.data.data != null) { // 成功获取基础信息后,调用获取婚姻信息详情接口 - await getMarriageInformationDetail(false); - } else { - SmartDialog.showToast(response.data.message); - } - } catch (e) { - // 获取用户信息失败不影响登录流程 - SmartDialog.showToast('获取用户信息失败'); - } - } + final baseInfo = response.data.data!; - /// 获取用户婚姻信息详情 - Future getMarriageInformationDetail(bool isMain) async { - try { - final response = await _userApi.getMarriageInformationDetail(); - if (response.data.isSuccess) { - // 检查data是否为null或者是空对象 - if(response.data.data == null){ - if(isMain){ - SmartDialog.showToast('转到完善信息'); - Get.to(() => UserInfoPage()); - } else { - Get.offAll(() => UserInfoPage()); + final result = await _userApi.getMarriageInformationDetail(); + if (result.data.isSuccess) { + if(result.data.data == null){ + if(isMain){ + SmartDialog.showToast('转到完善信息'); + Get.to(() => UserInfoPage()); + } else { + Get.offAll(() => UserInfoPage()); + } + var information = UserData(); + information.matchmakerFlag = baseInfo.matchmakerFlag; + information.realName = baseInfo.realName; + information.phone = baseInfo.phone; + GlobalData().userData = information; + return; } - return; - } - final information = response.data.data!; - // if (information.id.isNotEmpty) { - // final result = await _userApi.getCertificationList(information.id); - // List list = result.data.data!; - // final record = list.firstWhere((item) => item.authenticationCode == 0); - // information.realAuth = record.status == 1; - // } - GlobalData().userData = information; - if (information.id.isEmpty || information.genderCode.isNaN || information.birthYear == null || information.nickName.isEmpty) { - //跳转到完善信息 - SmartDialog.showToast('转到完善信息'); - // 导航到完善信息页面 - if(isMain){ + final information = result.data.data!; + information.matchmakerFlag = baseInfo.matchmakerFlag; + information.realName = baseInfo.realName; + information.phone = baseInfo.phone; + GlobalData().userData = information; + if (_checkInformation(information)) { + //跳转到完善信息 SmartDialog.showToast('转到完善信息'); - Get.to(() => UserInfoPage()); - } else { - Get.offAll(() => UserInfoPage()); + // 导航到完善信息页面 + if(isMain){ + SmartDialog.showToast('转到完善信息'); + Get.to(() => UserInfoPage()); + } else { + Get.offAll(() => UserInfoPage()); + } + } else if(!isMain){ + Get.offAll(MainPage()); } - } else if(!isMain){ - Get.offAll(MainPage()); } + } else { + SmartDialog.showToast(response.data.message); } } catch (e) { - // 获取婚姻信息失败不影响登录流程 - print('获取婚姻信息异常: $e'); + // 获取用户信息失败不影响登录流程 + SmartDialog.showToast('获取用户信息失败'); + print('获取用户信息失败: $e'); } } + } \ No newline at end of file diff --git a/lib/extension/router_service.dart b/lib/extension/router_service.dart index d16e7f8..d641d59 100644 --- a/lib/extension/router_service.dart +++ b/lib/extension/router_service.dart @@ -13,7 +13,7 @@ class RouteGuardService extends GetxService { bool checked = false; if (GlobalData().userData != null) { final information = GlobalData().userData!; - if(information.id.isNotEmpty && information.birthYear != null){ + if(information.id != null && information.id!.isNotEmpty && information.birthYear != null){ checked = true; } } diff --git a/lib/model/mine/user_data.dart b/lib/model/mine/user_data.dart index 77e2fb0..65b50f3 100644 --- a/lib/model/mine/user_data.dart +++ b/lib/model/mine/user_data.dart @@ -1,12 +1,12 @@ // 用户详细信息实体类 class UserData { - final String id; - final String nickName; + final String? id; + final String? nickName; final String? name; final String? profilePhoto; String? identityCard; - final int genderCode; - final String genderValue; + final int? genderCode; + final String? genderValue; final String? homeCountryCode; final String? homeCountry; final int? provinceCode; @@ -59,15 +59,18 @@ class UserData { final String? hometownProvinceName; final int? hometownCityCode; final String? hometownCityName; + String? phone; + String? realName; + bool? matchmakerFlag; UserData({ - required this.id, - required this.nickName, + this.id, + this.nickName, this.name, this.profilePhoto, this.identityCard, - required this.genderCode, - required this.genderValue, + this.genderCode, + this.genderValue, this.homeCountryCode, this.homeCountry, this.provinceCode, @@ -120,6 +123,9 @@ class UserData { this.hometownProvinceName, this.hometownCityCode, this.hometownCityName, + this.phone, + this.realName, + this.matchmakerFlag, }); // 从JSON映射创建实例 diff --git a/lib/network/api_urls.dart b/lib/network/api_urls.dart index e2abf10..a5864ae 100644 --- a/lib/network/api_urls.dart +++ b/lib/network/api_urls.dart @@ -7,6 +7,7 @@ class ApiUrls { // 用户相关接口 static const String getBaseUserInfo = 'dating-agency-uec/user/get/base-info'; + static const String updatePhone = 'dating-agency-uec/user/modify/phone'; static const String getMarriageInformationDetail = 'dating-agency-service/user/get/dongwo/marriage-information-detail'; static const String registerMarriageInformation = 'dating-agency-service/user/register/marriage-information'; static const String getHxUserToken = 'dating-agency-chat-audio/user/get/hx/user/token'; diff --git a/lib/network/user_api.dart b/lib/network/user_api.dart index b68d86a..731b951 100644 --- a/lib/network/user_api.dart +++ b/lib/network/user_api.dart @@ -46,6 +46,11 @@ abstract class UserApi { Future>> saveCertificationAudit( @Body() Map data, ); + @POST(ApiUrls.updatePhone) + Future>> updatePhone( + @Body() Map data, + ); + @GET(ApiUrls.getCertificationList) Future>>> getCertificationList( diff --git a/lib/network/user_api.g.dart b/lib/network/user_api.g.dart index 4450293..33890cb 100644 --- a/lib/network/user_api.g.dart +++ b/lib/network/user_api.g.dart @@ -220,6 +220,40 @@ class _UserApi implements UserApi { return httpResponse; } + @override + Future>> updatePhone( + Map data, + ) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = {}; + _data.addAll(data); + final _options = _setStreamType>>( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + 'dating-agency-uec/user/modify/phone', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); + final _result = await _dio.fetch>(_options); + late BaseResponse _value; + try { + _value = BaseResponse.fromJson( + _result.data!, + (json) => json as dynamic, + ); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + final httpResponse = HttpResponse(_value, _result); + return httpResponse; + } + @override Future>>> getCertificationList(String miId) async { diff --git a/lib/pages/main/main_page.dart b/lib/pages/main/main_page.dart index 92331c2..ef427f8 100644 --- a/lib/pages/main/main_page.dart +++ b/lib/pages/main/main_page.dart @@ -53,7 +53,10 @@ class _MainPageState extends State { Future checkTokenAndFetchMarriageInfo() async { // 调用userController中的getMarriageInformationDetail方法 final userController = Get.find(); - await userController.getMarriageInformationDetail(true); + final userId = storage.read('userId'); + if(userId != null && userId.isNotEmpty){ + await userController.getBaseUserInfo(userId, true); + } } @override diff --git a/lib/pages/mine/auth_center_page.dart b/lib/pages/mine/auth_center_page.dart index 9cfbc51..188a73b 100644 --- a/lib/pages/mine/auth_center_page.dart +++ b/lib/pages/mine/auth_center_page.dart @@ -8,6 +8,7 @@ import '../../controller/mine/auth_controller.dart'; import '../../extension/router_service.dart'; import '../../generated/assets.dart'; import 'edit_info_page.dart'; +import 'phone_page.dart'; class AuthCenterPage extends StatelessWidget { AuthCenterPage({super.key}); @@ -106,15 +107,17 @@ class AuthCenterPage extends StatelessWidget { ], ), ).onTap(() async{ - if(item.index == 2){ + if(item.index == 1) { + await Get.to(() => PhonePage()); + } else if(item.index == 2){ await Get.to(() => EditInfoPage()); - controller.loadInitialData(); } else if(item.index == 3){ - final result = await Get.to(() => RealNamePage()); - if(result > 0){ - controller.loadInitialData(); + if(item.authed){ + return; } + await Get.to(() => RealNamePage()); } + controller.loadInitialData(); }); } diff --git a/lib/pages/mine/phone_page.dart b/lib/pages/mine/phone_page.dart new file mode 100644 index 0000000..e602a6c --- /dev/null +++ b/lib/pages/mine/phone_page.dart @@ -0,0 +1,151 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:tdesign_flutter/tdesign_flutter.dart'; + +import '../../controller/mine/phone_controller.dart'; + +class PhonePage extends StatelessWidget { + PhonePage({super.key}); + + final PhoneController controller = Get.put(PhoneController()); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color(0xffFFFFFF), + appBar: AppBar( + title: Text('手机认证', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), + centerTitle: true, + ), + body: Obx(() { + return IndexedStack( + index: controller.tabIndex.value, + children: [ + // 推荐列表 + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, // 垂直居中 + crossAxisAlignment: CrossAxisAlignment.center, // 水平居中 + children: [ + const Text('已经认证的手机号码', style: TextStyle(fontSize: 18, color: Color(0xFF999999))), + const SizedBox(height: 12), + Text(_encryptPhone(controller.phone.value), style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold)), + SizedBox(height: 64), + TDButton( + text: '更换手机号码', + width: MediaQuery.of(context).size.width - 50, + size: TDButtonSize.large, + type: TDButtonType.fill, + shape: TDButtonShape.round, + style: TDButtonStyle( + textColor: Colors.white, + backgroundColor: Color(0xFF7562F9), + ), + activeStyle: TDButtonStyle( + textColor: Colors.white, + backgroundColor: Color(0xC37562F9), + ), + onTap: (){ + controller.tabIndex.value = 1; + }, + ), + SizedBox(height: 200), + ], + ), + ), + // 同城列表 + Center( + child: Column( + children: [ + const SizedBox(height:32), + const Text('请输入新的手机号码', style: TextStyle(fontSize: 16, color: Color(0xFF333333))), + const SizedBox(height: 8), + const Text('手机号码仅用于登录和账号保护', style: TextStyle(fontSize: 14, color: Color(0xFF999999))), + const SizedBox(height: 56), + TDInput( + type: TDInputType.cardStyle, + inputType: TextInputType.phone, + maxLength: 11, + cardStyle: TDCardStyle.topText, + width: MediaQuery.of(context).size.width - 50, + hintText: '请输入你的手机号', + onChanged: (text) { + controller.phoneNumber.value = text; + } + ), + const SizedBox(height: 24), + TDInput( + type: TDInputType.cardStyle, + inputType: TextInputType.number, + maxLength: 6, + cardStyle: TDCardStyle.topText, + width: MediaQuery.of(context).size.width - 50, + hintText: '请输入验证码', + onChanged: (text) { + controller.verificationCode.value = text; + }, + rightBtn: SizedBox( + width: 100, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only(right: 10), + child: Container( + width: 0.5, + height: 24, + color: TDTheme.of(context).grayColor3, + ), + ), + controller.countdownSeconds.value > 0 ? + TDText('${controller.countdownSeconds.value}秒后重试', textColor: TDTheme.of(context).fontGyColor4) + : TDText('获取验证码', textColor: Color(0xFF7562F9)), + ], + ), + ), + needClear: false, + onBtnTap: () { + controller.getVerificationCode(); + } + ), + const SizedBox(height: 48), + TDButton( + text: '确定更换', + width: MediaQuery.of(context).size.width - 50, + size: TDButtonSize.large, + type: TDButtonType.fill, + shape: TDButtonShape.round, + style: TDButtonStyle( + textColor: Colors.white, + backgroundColor: Color(0xFF7562F9), + ), + activeStyle: TDButtonStyle( + textColor: Colors.white, + backgroundColor: Color(0xC37562F9), + ), + onTap: (){ + controller.changePhone(); + }, + ), + ], + ), + ) + ], + ); + }) + ); + } + + String _encryptPhone(String phone) { + if (phone.isEmpty) return ''; + if (phone.length < 7) return phone; + + // 保留前3位和后4位,中间用*代替 + String start = phone.substring(0, 3); + String end = phone.substring(phone.length - 4); + String middle = '*' * (phone.length - 7); + + return '$start$middle$end'; + } + +} \ No newline at end of file diff --git a/lib/pages/mine/real_name_page.dart b/lib/pages/mine/real_name_page.dart index 14669fa..a45e396 100644 --- a/lib/pages/mine/real_name_page.dart +++ b/lib/pages/mine/real_name_page.dart @@ -40,7 +40,7 @@ class RealNamePage extends StatelessWidget { width: MediaQuery.of(context).size.width - 40, decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade300), - borderRadius: BorderRadius.circular(28), + borderRadius: BorderRadius.circular(6), // border: Border( // bottom: BorderSide( // color: Colors.grey[400]!, @@ -97,7 +97,7 @@ class RealNamePage extends StatelessWidget { width: MediaQuery.of(context).size.width - 40, decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade300), - borderRadius: BorderRadius.circular(28), + borderRadius: BorderRadius.circular(6), // border: Border( // bottom: BorderSide( // color: Colors.grey[400]!,