diff --git a/lib/controller/discover/room_controller.dart b/lib/controller/discover/room_controller.dart index bd6c2fa..c9fcfd6 100644 --- a/lib/controller/discover/room_controller.dart +++ b/lib/controller/discover/room_controller.dart @@ -31,7 +31,6 @@ enum CurrentRole { /// 直播房间相关控制器 class RoomController extends GetxController with WidgetsBindingObserver { - RoomController({NetworkService? networkService}) : _networkService = networkService ?? Get.find(); @@ -39,6 +38,7 @@ class RoomController extends GetxController with WidgetsBindingObserver { CurrentRole currentRole = CurrentRole.normalUser; var isLive = false.obs; var matchmakerFlag = false.obs; + /// 当前频道信息 final Rxn rtcChannel = Rxn(); final Rxn rtcChannelDetail = Rxn(); @@ -50,7 +50,8 @@ class RoomController extends GetxController with WidgetsBindingObserver { final RxList giftProducts = [].obs; /// 消息服务实例 - final LiveChatMessageService _messageService = LiveChatMessageService.instance; + final LiveChatMessageService _messageService = + LiveChatMessageService.instance; // matchmakerFlag @@ -67,7 +68,7 @@ class RoomController extends GetxController with WidgetsBindingObserver { @override void didChangeAppLifecycleState(AppLifecycleState state) { - if(state == AppLifecycleState.resumed){ + if (state == AppLifecycleState.resumed) { // print('_handleAppResumed'); } } @@ -119,7 +120,7 @@ class RoomController extends GetxController with WidgetsBindingObserver { /// 调用接口创建 RTC 频道 Future createRtcChannel() async { - if(isLive.value){ + if (isLive.value) { return; } final granted = await _ensureRtcPermissions(); @@ -331,8 +332,6 @@ class RoomController extends GetxController with WidgetsBindingObserver { } catch (e) { print('❌ 销毁 RTC 频道异常: $e'); } - - } isLive.value = false; @@ -366,7 +365,35 @@ class RoomController extends GetxController with WidgetsBindingObserver { String? targetUserId, }) async { try { - // 添加到本地播放队列 + // 先调用消费接口 + final channelId = RTCManager.instance.currentChannelId; + if (channelId == null || channelId.isEmpty) { + SmartDialog.showToast('频道ID不存在'); + return; + } + + // 准备请求参数 + final requestData = { + 'channelId': int.tryParse(channelId) ?? 0, + 'type': 1, // 1.送礼 2.添加好友 + 'toUId': targetUserId != null ? int.tryParse(targetUserId) ?? 0 : 0, + 'productSpecId': int.tryParse(gift.productSpecId) ?? 0, + 'quantity': 1, + }; + + // 调用消费接口 + final response = await _networkService.rtcApi.costChannelGift( + requestData, + ); + + if (!response.data.isSuccess) { + SmartDialog.showToast( + response.data.message.isNotEmpty ? response.data.message : '发送礼物失败', + ); + return; + } + + // 消费成功后再添加到本地播放队列 final svgaManager = SvgaPlayerManager.instance; svgaManager.addToQueue( SvgaAnimationItem( @@ -379,23 +406,20 @@ class RoomController extends GetxController with WidgetsBindingObserver { print('✅ 礼物已添加到播放队列: ${gift.productTitle}'); // 发送 RTM 消息通知其他用户 - final channelId = RTCManager.instance.currentChannelId; - if (channelId != null && channelId.isNotEmpty) { - final messageData = { - 'type': 'gift', - 'svgaFile': gift.svgaFile, - 'giftProductId': gift.productId, - 'targetUserId': targetUserId, - 'senderUserId': GlobalData().userId ?? GlobalData().userData?.id, - 'senderNickName': GlobalData().userData?.nickName ?? '', - }; - - await RTMManager.instance.publishChannelMessage( - channelName: channelId, - message: json.encode(messageData), - ); - print('✅ 礼物消息已发送: ${gift.productTitle}'); - } + final messageData = { + 'type': 'gift', + 'svgaFile': gift.svgaFile, + 'giftProductId': gift.productId, + 'targetUserId': targetUserId, + 'senderUserId': GlobalData().userId ?? GlobalData().userData?.id, + 'senderNickName': GlobalData().userData?.nickName ?? '', + }; + + await RTMManager.instance.publishChannelMessage( + channelName: channelId, + message: json.encode(messageData), + ); + print('✅ 礼物消息已发送: ${gift.productTitle}'); } catch (e) { print('❌ 发送礼物失败: $e'); SmartDialog.showToast('发送礼物失败'); @@ -515,7 +539,8 @@ class RoomController extends GetxController with WidgetsBindingObserver { } void registerMatch() async { - if(GlobalData().userData!.identityCard != null && GlobalData().userData!.identityCard!.isNotEmpty){ + if (GlobalData().userData!.identityCard != null && + GlobalData().userData!.identityCard!.isNotEmpty) { await Get.to(() => MatchSpreadPage()); } else { SmartDialog.showToast('请先进行实名认证'); @@ -524,5 +549,4 @@ class RoomController extends GetxController with WidgetsBindingObserver { print(455); matchmakerFlag.value = GlobalData().userData!.matchmakerFlag!; } - } diff --git a/lib/network/api_urls.dart b/lib/network/api_urls.dart index 3e6707d..1224b05 100644 --- a/lib/network/api_urls.dart +++ b/lib/network/api_urls.dart @@ -62,6 +62,8 @@ class ApiUrls { 'dating-agency-chat-audio/user/page/rtc-channel'; static const String listGiftProduct = 'dating-agency-mall/user/list/gift-product'; + static const String costChannelGift = + 'dating-agency-chat-audio/user/cost/channel-gift'; static const String listBankCardByIndividual = 'dating-agency-mall/user/list/bank-card/by-individual'; static const String createBankCardByIndividual = diff --git a/lib/network/rtc_api.dart b/lib/network/rtc_api.dart index 7c2e928..6a87261 100644 --- a/lib/network/rtc_api.dart +++ b/lib/network/rtc_api.dart @@ -70,4 +70,10 @@ abstract class RtcApi { /// 获取礼物产品列表 @GET(ApiUrls.listGiftProduct) Future>>> listGiftProduct(); + + /// 频道礼物/添加好友消费 + @POST(ApiUrls.costChannelGift) + Future>> costChannelGift( + @Body() Map data, + ); } diff --git a/lib/network/rtc_api.g.dart b/lib/network/rtc_api.g.dart index 52bbfcb..5aa117a 100644 --- a/lib/network/rtc_api.g.dart +++ b/lib/network/rtc_api.g.dart @@ -399,6 +399,40 @@ class _RtcApi implements RtcApi { return httpResponse; } + @override + Future>> costChannelGift( + 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-chat-audio/user/cost/channel-gift', + 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; + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes ||