Browse Source

feat(rtc): 实现频道礼物消费功能

- 新增频道礼物消费API接口定义与实现
- 在RoomController中集成礼物发送前的消费逻辑
- 添加消费接口调用及错误处理机制
- 优化代码格式与空格处理
- 调整条件判断逻辑提升可读性
- 移除冗余空行使代码更紧凑
ios
Jolie 4 months ago
parent
commit
16006af58c
4 changed files with 92 additions and 26 deletions
  1. 76
      lib/controller/discover/room_controller.dart
  2. 2
      lib/network/api_urls.dart
  3. 6
      lib/network/rtc_api.dart
  4. 34
      lib/network/rtc_api.g.dart

76
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<NetworkService>();
@ -39,6 +38,7 @@ class RoomController extends GetxController with WidgetsBindingObserver {
CurrentRole currentRole = CurrentRole.normalUser;
var isLive = false.obs;
var matchmakerFlag = false.obs;
///
final Rxn<RtcChannelData> rtcChannel = Rxn<RtcChannelData>();
final Rxn<RtcChannelDetail> rtcChannelDetail = Rxn<RtcChannelDetail>();
@ -50,7 +50,8 @@ class RoomController extends GetxController with WidgetsBindingObserver {
final RxList<GiftProductModel> giftProducts = <GiftProductModel>[].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<void> 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!;
}
}

2
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 =

6
lib/network/rtc_api.dart

@ -70,4 +70,10 @@ abstract class RtcApi {
///
@GET(ApiUrls.listGiftProduct)
Future<HttpResponse<BaseResponse<List<GiftProductModel>>>> listGiftProduct();
/// /
@POST(ApiUrls.costChannelGift)
Future<HttpResponse<BaseResponse<dynamic>>> costChannelGift(
@Body() Map<String, dynamic> data,
);
}

34
lib/network/rtc_api.g.dart

@ -399,6 +399,40 @@ class _RtcApi implements RtcApi {
return httpResponse;
}
@override
Future<HttpResponse<BaseResponse<dynamic>>> costChannelGift(
Map<String, dynamic> data,
) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(data);
final _options = _setStreamType<HttpResponse<BaseResponse<dynamic>>>(
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<Map<String, dynamic>>(_options);
late BaseResponse<dynamic> _value;
try {
_value = BaseResponse<dynamic>.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<T>(RequestOptions requestOptions) {
if (T != dynamic &&
!(requestOptions.responseType == ResponseType.bytes ||

Loading…
Cancel
Save