From 306ff1d952216fed7fe6e554bf0d1b753b8d64b5 Mon Sep 17 00:00:00 2001 From: Jolie <412895109@qq.com> Date: Thu, 6 Nov 2025 12:01:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0oss=E5=B0=81=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/config/env_config.dart | 9 +- .../mine/login_controller.dart | 75 +++++----------- lib/controller/mine/user_controller.dart | 89 +++++++++++++++++++ .../mine/user_info_controller.dart | 43 +++++---- lib/network/api_urls.dart | 1 + lib/network/network_config.dart | 15 +--- lib/network/network_service.dart | 15 +--- lib/network/user_api.dart | 3 + lib/network/user_api.g.dart | 31 +++++++ lib/oss/oss_manager.dart | 46 ++++++++++ lib/pages/main/main_page.dart | 18 ++-- lib/pages/mine/login_page.dart | 2 +- lib/pages/mine/mine_page.dart | 1 + lib/pages/mine/user_info_page.dart | 2 +- 14 files changed, 233 insertions(+), 117 deletions(-) rename lib/{pages => controller}/mine/login_controller.dart (62%) create mode 100644 lib/controller/mine/user_controller.dart rename lib/{pages => controller}/mine/user_info_controller.dart (95%) create mode 100644 lib/oss/oss_manager.dart diff --git a/lib/config/env_config.dart b/lib/config/env_config.dart index 7015a08..bcbf972 100644 --- a/lib/config/env_config.dart +++ b/lib/config/env_config.dart @@ -9,13 +9,11 @@ class EnvConfig { // 开发环境配置 static const Map _devConfig = { 'mainBaseUrl': 'https://dating-agency-api-test.qniao.cn/', - 'fileBaseUrl': 'https://dating-agency-api-test.qniao.cn/', }; // 生产环境配置 static const Map _releaseConfig = { 'mainBaseUrl': 'https://dating-agency-api.quzhaoqin.com/', - 'fileBaseUrl': 'https://dating-agency-api-test.qniao.cn/', }; /// 获取当前环境的配置值 @@ -33,12 +31,7 @@ class EnvConfig { : _releaseConfig['mainBaseUrl']!; } - /// 获取文件API的baseUrl - static String get fileBaseUrl { - return current == Environment.dev - ? _devConfig['fileBaseUrl']! - : _releaseConfig['fileBaseUrl']!; - } + /// 设置环境(主要用于测试或特定场景) static void setEnvironment(Environment env) { diff --git a/lib/pages/mine/login_controller.dart b/lib/controller/mine/login_controller.dart similarity index 62% rename from lib/pages/mine/login_controller.dart rename to lib/controller/mine/login_controller.dart index c192281..a609404 100644 --- a/lib/pages/mine/login_controller.dart +++ b/lib/controller/mine/login_controller.dart @@ -1,11 +1,9 @@ import 'dart:async'; -import 'package:dating_touchme_app/pages/main/main_page.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; -import 'package:dating_touchme_app/network/user_api.dart'; -import 'package:dating_touchme_app/pages/mine/user_info_page.dart'; - +import '../../network/user_api.dart'; +import 'user_controller.dart'; class LoginController extends GetxController { // 手机号输入 @@ -82,7 +80,6 @@ class LoginController extends GetxController { // 清除错误信息 - 由于使用SmartDialog,此方法不再需要 // void clearErrorMessage() {} - // 登录方法 Future login() async { // 验证输入 @@ -111,18 +108,18 @@ class LoginController extends GetxController { // 处理响应 if (response.data.isSuccess) { - // 保存token和用户信息 - if (response.data.data != null) { - final loginData = response.data.data!; - await storage.write('token', loginData.token); - await storage.write('userId', loginData.userId); - // 保存用户信息 - await storage.write('userInfo', loginData.toJson()); - - // 登录成功后获取用户基础信息 - await _getBaseUserInfo(loginData.userId); - } - } else { + // 保存token和用户信息 + if (response.data.data != null) { + final loginData = response.data.data!; + await storage.write('token', loginData.token); + await storage.write('userId', loginData.userId); + // 保存用户信息 + await storage.write('userInfo', loginData.toJson()); + + // 登录成功后获取用户信息 + await _handleUserInfoRetrieval(loginData.userId); + } + } else { SmartDialog.showToast(response.data.message); } } catch (e) { @@ -131,44 +128,16 @@ class LoginController extends GetxController { isLoggingIn.value = false; } } - - // 获取用户基础信息 - Future _getBaseUserInfo(String userId) async { + + // 使用UserController中的方法获取用户信息 + Future _handleUserInfoRetrieval(String userId) async { try { - final response = await _userApi.getBaseUserInfo(userId); - - if (response.data.isSuccess && response.data.data != null) { - // 成功获取基础信息后,调用获取婚姻信息详情接口 - await _getMarriageInformationDetail(); - } else { - SmartDialog.showToast(response.data.message); - } + // 使用UserController获取基础信息和婚姻信息 + final userController = Get.find(); + await userController.getBaseUserInfo(userId); } catch (e) { // 获取用户信息失败不影响登录流程 - SmartDialog.showToast('获取用户信息失败'); - } - } - - // 获取用户婚姻信息详情 - Future _getMarriageInformationDetail() async { - try { - final response = await _userApi.getMarriageInformationDetail(); - if (response.data.isSuccess) { - // 检查data是否为null或者是空对象 - if(response.data.data == null){ - //跳转到完善信息 - SmartDialog.showToast('转到完善信息'); - // 导航到完善信息页面 - Get.offAll(() => UserInfoPage()); - }else{ - Get.offAll(MainPage()); - } - } else { - // 获取婚姻信息失败不影响登录流程 - } - } catch (e) { - // 获取婚姻信息失败不影响登录流程 - print('获取婚姻信息异常: $e'); + print('获取用户信息异常: $e'); } } -} \ No newline at end of file +} diff --git a/lib/controller/mine/user_controller.dart b/lib/controller/mine/user_controller.dart new file mode 100644 index 0000000..36d00be --- /dev/null +++ b/lib/controller/mine/user_controller.dart @@ -0,0 +1,89 @@ +import 'package:get/get.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import '../../network/user_api.dart'; +import '../../pages/mine/user_info_page.dart'; +import '../../pages/main/main_page.dart'; + +class UserController extends GetxController { + + // UserApi实例 + late UserApi _userApi; + + @override + void onInit() { + super.onInit(); + // 从全局依赖中获取UserApi + _userApi = Get.find(); + } + + /// 获取环信用户token + Future getHxUserToken() async { + + try { + // 调用获取环信用户token接口 + final response = await _userApi.getHxUserToken(); + + // 处理响应 + if (response.data.isSuccess) { + // 保存token到本地存储 + String? token = response.data.data; + if (token != null) { + // 打印获取的token + print('获取环信用户token成功: $token'); + + return token; + } else { + SmartDialog.showToast('获取的环信用户token为空'); + return null; + } + } else { + SmartDialog.showToast(response.data.message); + return null; + } + } catch (e) { + print('获取环信用户token失败: $e'); + SmartDialog.showToast('获取环信用户token失败,请重试'); + return null; + } + } + + /// 获取用户基础信息 + Future getBaseUserInfo(String userId) async { + try { + final response = await _userApi.getBaseUserInfo(userId); + + if (response.data.isSuccess && response.data.data != null) { + // 成功获取基础信息后,调用获取婚姻信息详情接口 + await getMarriageInformationDetail(); + } else { + SmartDialog.showToast(response.data.message); + } + } catch (e) { + // 获取用户信息失败不影响登录流程 + SmartDialog.showToast('获取用户信息失败'); + } + } + + /// 获取用户婚姻信息详情 + Future getMarriageInformationDetail() async { + try { + final response = await _userApi.getMarriageInformationDetail(); + if (response.data.isSuccess) { + // 检查data是否为null或者是空对象 + if (response.data.data == null) { + //跳转到完善信息 + SmartDialog.showToast('转到完善信息'); + // 导航到完善信息页面 + Get.offAll(() => UserInfoPage()); + } else { + Get.offAll(MainPage()); + } + } else { + // 获取婚姻信息失败不影响登录流程 + } + } catch (e) { + // 获取婚姻信息失败不影响登录流程 + print('获取婚姻信息异常: $e'); + } + } +} diff --git a/lib/pages/mine/user_info_controller.dart b/lib/controller/mine/user_info_controller.dart similarity index 95% rename from lib/pages/mine/user_info_controller.dart rename to lib/controller/mine/user_info_controller.dart index a0bbf58..17c4bd1 100644 --- a/lib/pages/mine/user_info_controller.dart +++ b/lib/controller/mine/user_info_controller.dart @@ -3,8 +3,8 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:dating_touchme_app/network/user_api.dart'; -import 'package:dating_touchme_app/pages/main/main_page.dart'; +import '../../network/user_api.dart'; +import '../../pages/main/main_page.dart'; class UserInfoController extends GetxController { // 用户信息表单字段 @@ -14,13 +14,13 @@ class UserInfoController extends GetxController { final education = ''.obs; final invitationCode = ''.obs; final avatarUrl = ''.obs; - + // 加载状态 final isSubmitting = false.obs; - + // GetStorage实例,用于存储用户信息 final storage = GetStorage(); - + // UserApi实例 late UserApi _userApi; @@ -49,8 +49,6 @@ class UserInfoController extends GetxController { print('选择的学历: $selectedEducation'); // 显示选择结果 SmartDialog.showToast('学历已选择'); - - } // 选择头像 - 业务逻辑处理 @@ -59,7 +57,7 @@ class UserInfoController extends GetxController { // 请求相机权限并拍照 final ImagePicker picker = ImagePicker(); final XFile? photo = await picker.pickImage(source: ImageSource.camera); - + if (photo != null) { await processSelectedImage(File(photo.path)); } @@ -68,7 +66,8 @@ class UserInfoController extends GetxController { // 更友好的错误提示 if (e.toString().contains('permission') || e.toString().contains('权限')) { SmartDialog.showToast('相机权限被拒绝,请在设置中允许访问相机'); - } else if (e.toString().contains('camera') || e.toString().contains('相机')) { + } else if (e.toString().contains('camera') || + e.toString().contains('相机')) { SmartDialog.showToast('设备没有可用的相机'); } else { SmartDialog.showToast('拍照失败,请重试'); @@ -81,7 +80,7 @@ class UserInfoController extends GetxController { // 从相册选择图片 final ImagePicker picker = ImagePicker(); final XFile? image = await picker.pickImage(source: ImageSource.gallery); - + if (image != null) { await processSelectedImage(File(image.path)); } @@ -108,18 +107,18 @@ class UserInfoController extends GetxController { try { // 显示加载提示 SmartDialog.showLoading(msg: '正在处理头像...'); - + // 更新本地头像URL(实际项目中应该先上传到服务器) // 这里直接使用本地文件路径作为临时URL avatarUrl.value = imageFile.path; - + // 保存到本地存储 final currentUserInfo = storage.read('userInfo') ?? {}; if (currentUserInfo is Map) { currentUserInfo['avatarUrl'] = imageFile.path; await storage.write('userInfo', currentUserInfo); } - + SmartDialog.dismiss(); SmartDialog.showToast('头像设置成功'); } catch (e) { @@ -169,15 +168,15 @@ class UserInfoController extends GetxController { birthYear = int.tryParse(parts[0]) ?? 0; } } - + // 学历代码映射 Map educationCodeMap = { '大专以下': '0', '大专': '1', '本科': '2', - '硕士及以上': '3' + '硕士及以上': '3', }; - + return { 'birthYear': birthYear, 'educationCode': educationCodeMap[education.value] ?? '0', @@ -199,13 +198,13 @@ class UserInfoController extends GetxController { try { // 构建请求参数 final params = _buildSubmitParams(); - + // 打印提交的信息 print('提交用户信息参数: $params'); - + // 调用注册婚姻信息接口 final response = await _userApi.registerMarriageInformation(params); - + // 处理响应 if (response.data.isSuccess) { // 更新本地存储的用户信息 @@ -219,10 +218,10 @@ class UserInfoController extends GetxController { }); await storage.write('userInfo', currentUserInfo); } - + // 显示成功提示 SmartDialog.showToast('信息提交成功!'); - + // 延迟后跳转 Future.delayed(const Duration(milliseconds: 1500), () { // 跳转到主页面(根据登录流程,应该跳转到MainPage) @@ -239,4 +238,4 @@ class UserInfoController extends GetxController { isSubmitting.value = false; } } -} \ No newline at end of file +} diff --git a/lib/network/api_urls.dart b/lib/network/api_urls.dart index d9c6515..f8187df 100644 --- a/lib/network/api_urls.dart +++ b/lib/network/api_urls.dart @@ -9,6 +9,7 @@ class ApiUrls { static const String getBaseUserInfo = 'dating-agency-uec/user/get/base-info'; 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'; // 后续可以在此添加更多API端点 } \ No newline at end of file diff --git a/lib/network/network_config.dart b/lib/network/network_config.dart index 4cc28a3..58f0e53 100644 --- a/lib/network/network_config.dart +++ b/lib/network/network_config.dart @@ -9,7 +9,6 @@ import '../pages/mine/login_page.dart'; /// API类型枚举,用于区分不同的baseUrl enum ApiType { main, // 主API - file, // 文件上传下载API } /// 网络请求配置类 @@ -17,18 +16,10 @@ class NetworkConfig { static const int connectTimeout = 30000; static const int receiveTimeout = 30000; - /// 根据API类型创建不同的Dio实例 + /// 创建Dio实例 static Dio createDio({ApiType type = ApiType.main}) { - // 根据类型选择对应的baseUrl - String currentBaseUrl; - switch (type) { - case ApiType.main: - currentBaseUrl = EnvConfig.mainBaseUrl; - break; - case ApiType.file: - currentBaseUrl = EnvConfig.fileBaseUrl; - break; - } + // 使用主API的baseUrl + String currentBaseUrl = EnvConfig.mainBaseUrl; final dio = Dio( BaseOptions( diff --git a/lib/network/network_service.dart b/lib/network/network_service.dart index 0eb55e1..b1dfb19 100644 --- a/lib/network/network_service.dart +++ b/lib/network/network_service.dart @@ -11,7 +11,6 @@ class NetworkService { // API服务实例 late final ApiService _apiService; // 主API服务 - late final ApiService _fileApiService; // 文件API服务 late final UserApi _userApi; /// 获取单例实例 @@ -24,10 +23,6 @@ class NetworkService { final dio = NetworkConfig.createDio(); _apiService = ApiService(dio); _userApi = UserApi(dio); - - // 初始化文件上传API服务 - final fileDio = NetworkConfig.createDio(type: ApiType.file); - _fileApiService = ApiService(fileDio); } /// 通用GET请求 @@ -155,14 +150,10 @@ class NetworkService { return post(path, data, showLoading: showLoading, showError: showError, apiType: apiType); } - /// 根据API类型获取对应的API服务实例 + /// 获取API服务实例 ApiService _getApiServiceByType(ApiType type) { - switch (type) { - case ApiType.main: - return _apiService; - case ApiType.file: - return _fileApiService; - } + // 无论类型是什么,都返回主API服务 + return _apiService; } /// 用户相关API diff --git a/lib/network/user_api.dart b/lib/network/user_api.dart index 889b163..dc1d2d3 100644 --- a/lib/network/user_api.dart +++ b/lib/network/user_api.dart @@ -34,4 +34,7 @@ abstract class UserApi { Future>> registerMarriageInformation( @Body() Map data, ); + + @GET(ApiUrls.getHxUserToken) + Future>> getHxUserToken(); } \ No newline at end of file diff --git a/lib/network/user_api.g.dart b/lib/network/user_api.g.dart index 3232954..2081fef 100644 --- a/lib/network/user_api.g.dart +++ b/lib/network/user_api.g.dart @@ -186,6 +186,37 @@ class _UserApi implements UserApi { return httpResponse; } + @override + Future>> getHxUserToken() async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType>>( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + 'dating-agency-chat-audio/user/get/hx/user/token', + 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 String, + ); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + final httpResponse = HttpResponse(_value, _result); + return httpResponse; + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes || diff --git a/lib/oss/oss_manager.dart b/lib/oss/oss_manager.dart new file mode 100644 index 0000000..b53f386 --- /dev/null +++ b/lib/oss/oss_manager.dart @@ -0,0 +1,46 @@ +import 'dart:typed_data'; + +import 'package:flutter_oss_aliyun/flutter_oss_aliyun.dart'; + +class OSSManager { + // 静态单例实例 + static final OSSManager _instance = OSSManager._internal(); + bool isInit = false; + // 工厂构造函数,返回单例实例 + factory OSSManager() { + return _instance; + } + + // 私有构造函数,防止外部直接实例化 + OSSManager._internal(); + + void init(String stsUrl, String ossEndpoint, String bucketName) { + // 初始化 + Client.init( + stsUrl: stsUrl, + ossEndpoint: ossEndpoint, + bucketName: bucketName, + ); + isInit = true; + } + + Future uploadFile(Uint8List fileData, String objectName, {Function(int count, int total)? onSendProgress, + Function(int count, int total)? onReceiveProgress}) async { + if (!isInit) { + throw Exception("请先初始化"); + } + final result = await Client().putObject(fileData, objectName, option: PutRequestOption( + onSendProgress: onSendProgress != null ? (count, total) { + onSendProgress(count, total); + } : null, + onReceiveProgress: onReceiveProgress != null ? (count, total) { + onReceiveProgress(count, total); + } : null, + override: false, + aclModel: AclMode.publicRead, + storageType: StorageType.ia, + ), + ); + return result.statusCode == 200 ? result.realUri.path : throw Exception("上传失败"); + } +} \ No newline at end of file diff --git a/lib/pages/main/main_page.dart b/lib/pages/main/main_page.dart index a2a76f1..d0153dd 100644 --- a/lib/pages/main/main_page.dart +++ b/lib/pages/main/main_page.dart @@ -6,6 +6,7 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:dating_touchme_app/network/user_api.dart'; +import 'package:dating_touchme_app/controller/mine/user_controller.dart'; import '../../widget/double_tap_to_exit_widget.dart'; import '../discover/discover_page.dart'; @@ -24,7 +25,7 @@ class _MainPageState extends State { final storage = GetStorage(); PageController pageController = PageController(initialPage: 0); int currentIndex = 0; // 使用普通int替代RxInt - + // 将页面实例存储为成员变量,避免每次build都重新创建 late HomePage homePage; late DiscoverPage discoverPage; @@ -36,25 +37,26 @@ class _MainPageState extends State { super.initState(); // 获取UserApi实例 _userApi = Get.find(); - + // 初始化页面实例 homePage = HomePage(); discoverPage = DiscoverPage(); messagePage = MessagePage(); minePage = MinePage(); + // 初始化UserController并调用获取环信用户token的方法 + final userController = Get.put(UserController()); + userController.getHxUserToken(); + // 检查token并调用获取婚姻信息详情的方法 checkTokenAndFetchMarriageInfo(); } // 检查token并获取婚姻信息详情 Future checkTokenAndFetchMarriageInfo() async { - final response = await _userApi.getMarriageInformationDetail(); - if (response.data.isSuccess) { - if (response.data.data == null) { - - } - } + // 调用userController中的getMarriageInformationDetail方法 + final userController = Get.find(); + await userController.getMarriageInformationDetail(); } @override diff --git a/lib/pages/mine/login_page.dart b/lib/pages/mine/login_page.dart index 58c4f8a..25841d5 100644 --- a/lib/pages/mine/login_page.dart +++ b/lib/pages/mine/login_page.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -import 'package:dating_touchme_app/pages/mine/login_controller.dart'; +import 'package:dating_touchme_app/controller/mine/login_controller.dart'; class LoginPage extends StatelessWidget { LoginPage({super.key}); diff --git a/lib/pages/mine/mine_page.dart b/lib/pages/mine/mine_page.dart index 91b48f3..bb1f19b 100644 --- a/lib/pages/mine/mine_page.dart +++ b/lib/pages/mine/mine_page.dart @@ -10,6 +10,7 @@ class MinePage extends StatefulWidget { class _MinePageState extends State with AutomaticKeepAliveClientMixin{ @override Widget build(BuildContext context) { + super.build(context); return Container( color: Colors.white, ); diff --git a/lib/pages/mine/user_info_page.dart b/lib/pages/mine/user_info_page.dart index 6dda72a..2b64714 100644 --- a/lib/pages/mine/user_info_page.dart +++ b/lib/pages/mine/user_info_page.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:dating_touchme_app/generated/assets.dart'; import 'package:get/get.dart'; -import 'user_info_controller.dart'; +import 'package:dating_touchme_app/controller/mine/user_info_controller.dart'; class UserInfoPage extends StatelessWidget { const UserInfoPage({Key? key}) : super(key: key);