You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

846 lines
29 KiB

import 'dart:convert';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:dating_touchme_app/controller/global.dart';
import 'package:dating_touchme_app/controller/overlay_controller.dart';
import 'package:dating_touchme_app/model/live/gift_product_model.dart';
import 'package:dating_touchme_app/model/rtc/link_mic_card_model.dart';
import 'package:dating_touchme_app/model/rtc/rtc_channel_data.dart';
import 'package:dating_touchme_app/model/rtc/rtc_channel_detail.dart';
import 'package:dating_touchme_app/network/network_service.dart';
import 'package:dating_touchme_app/rtc/rtc_manager.dart';
import 'package:dating_touchme_app/rtc/rtm_manager.dart';
import 'package:dating_touchme_app/service/live_chat_message_service.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import '../../model/live/live_chat_message.dart';
import '../../pages/discover/live_end_page.dart';
import '../../pages/mine/real_name_page.dart';
import '../../pages/setting/match_spread_page.dart';
import '../../widget/live/live_recharge_popup.dart';
import '../message/call_controller.dart';
import 'discover_controller.dart';
import 'svga_player_manager.dart';
// 当前角色
enum CurrentRole {
broadcaster, //主持
maleAudience, //男嘉宾
femaleAudience, //女嘉宾
audience, //观众
normalUser, //普通用户
}
/// 直播房间相关控制器
class RoomController extends GetxController with WidgetsBindingObserver {
RoomController({NetworkService? networkService})
: _networkService = networkService ?? Get.find<NetworkService>();
final NetworkService _networkService;
CurrentRole currentRole = CurrentRole.normalUser;
var isLive = false.obs;
var matchmakerFlag = false.obs;
/// 当前频道信息
final Rxn<RtcChannelData> rtcChannel = Rxn<RtcChannelData>();
final Rxn<RtcChannelDetail> rtcChannelDetail = Rxn<RtcChannelDetail>();
/// 聊天消息列表
final RxList<LiveChatMessage> chatMessages = <LiveChatMessage>[].obs;
/// 礼物产品列表
final RxList<GiftProductModel> giftProducts = <GiftProductModel>[].obs;
/// 连麦卡片信息
final Rxn<LinkMicCardModel> linkMicCard = Rxn<LinkMicCardModel>();
/// 玫瑰数量
final RxInt roseCount = 0.obs;
var isDialogShowing = false.obs;
/// 消息服务实例
final LiveChatMessageService _messageService =
LiveChatMessageService.instance;
// matchmakerFlag
@override
void onInit() {
super.onInit();
WidgetsBinding.instance.addObserver(this);
matchmakerFlag.value = GlobalData().userData!.matchmakerFlag!;
// 注册消息监听
_registerMessageListener();
// 加载礼物产品列表
loadGiftProducts();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
// print('_handleAppResumed');
}
}
@override
void onClose() {
super.onClose();
WidgetsBinding.instance.removeObserver(this);
// 移除消息监听
_messageService.unregisterMessageListener();
// 清空RTM消息列表
chatMessages.clear();
}
void setDialogDismiss(bool flag){
isDialogShowing.value = flag;
}
/// 注册消息监听
void _registerMessageListener() {
_messageService.registerMessageListener(
onMessageReceived: (message) {
_addMessage(message);
},
onMessageError: (error) {
print('❌ 消息处理错误: $error');
},
);
}
/// 添加消息到列表(带去重和数量限制)
void _addMessage(LiveChatMessage message) {
// 去重:检查是否已存在相同的消息(基于 userId + content + timestamp)
final exists = chatMessages.any(
(m) =>
m.userId == message.userId &&
m.content == message.content &&
(m.timestamp - message.timestamp).abs() < 1000,
); // 1秒内的相同消息视为重复
if (exists) {
print('⚠️ 消息已存在,跳过添加');
return;
}
chatMessages.add(message);
print('✅ 消息已添加到列表,当前消息数: ${chatMessages.length}');
// 限制消息数量,最多保留100条
if (chatMessages.length > 300) {
chatMessages.removeAt(0);
print('📝 消息列表已满,移除最旧的消息');
}
}
/// 调用接口创建 RTC 频道
Future<void> createRtcChannel() async {
if (isLive.value) {
return;
}
// 检查是否正在通话中(包括呼叫中)
try {
// 先尝试使用 Get.find 获取已注册的实例,如果不存在再使用 instance
CallController callController;
if (Get.isRegistered<CallController>()) {
callController = Get.find<CallController>();
} else {
callController = CallController.instance;
}
print('⚠️ [RoomController] 检查通话状态: currentCall=${callController.currentCall.value}, hashCode=${callController.hashCode}');
if (callController.currentCall.value != null) {
SmartDialog.showToast('请先结束通话');
print('⚠️ [RoomController] 当前正在通话中,无法开始直播');
return;
}
} catch (e) {
// 如果获取失败,说明没有正在进行的通话,继续执行
print('⚠️ [RoomController] 获取CallController失败(可能没有通话): $e');
}
final granted = await _ensureRtcPermissions();
if (!granted) return;
try {
final response = await _networkService.rtcApi.createRtcChannel();
final base = response.data;
if (base.isSuccess && base.data != null) {
rtcChannel.value = base.data;
currentRole = CurrentRole.broadcaster;
isLive.value = true;
await _joinRtcChannel(
base.data!.token,
base.data!.channelId,
base.data!.uid,
ClientRoleType.clientRoleBroadcaster,
);
} else {
final message = base.message.isNotEmpty ? base.message : '创建频道失败';
SmartDialog.showToast(message);
}
} catch (e) {
SmartDialog.showToast('创建频道异常:$e');
}
}
Future<void> joinChannel(String channelName) async {
// 检查是否正在通话中(包括呼叫中)
try {
// 直接使用 CallController.instance,因为它使用单例模式会自动注册
final callController = CallController.instance;
if (callController.currentCall.value != null) {
SmartDialog.showToast('请先结束通话');
print('⚠️ [RoomController] 当前正在通话中,无法加入直播间');
return;
}
} catch (e) {
// 忽略错误,继续处理加入频道逻辑
print('⚠️ [RoomController] 检查通话状态失败: $e');
}
final response = await _networkService.rtcApi.getSwRtcToken(channelName);
final base = response.data;
if (base.isSuccess && base.data != null) {
rtcChannel.value = base.data;
// 加入他人直播间时,当前用户默认作为普通观众,不在麦上
currentRole = CurrentRole.normalUser;
isLive.value = false;
await _joinRtcChannel(
base.data!.token,
channelName,
base.data!.uid,
ClientRoleType.clientRoleAudience,
);
}
}
Future<void> _joinRtcChannel(
String token,
String channelName,
int uid,
ClientRoleType roleType,
) async {
try {
await _fetchRtcChannelDetail(channelName);
await RTCManager.instance.joinChannel(
token: token,
channelId: channelName,
uid: uid,
role: roleType,
);
} catch (e) {
SmartDialog.showToast('加入频道失败:$e');
}
}
Future<void> joinChat(CurrentRole role) async {
// 根据角色检查权限:男/女嘉宾需要摄像头和麦克风权限,普通观众只需要麦克风权限
bool granted = false;
if (role == CurrentRole.maleAudience || role == CurrentRole.femaleAudience) {
// 男/女嘉宾上麦:需要摄像头和麦克风权限
granted = await _ensureRtcPermissions();
} else {
// 普通观众上麦:只需要麦克风权限
granted = await _ensureMicrophonePermission();
}
if (!granted) {
print('❌ [RoomController] 权限检查失败,无法上麦');
return;
}
final data = {
'channelId': RTCManager.instance.currentChannelId,
'seatNumber': role == CurrentRole.maleAudience ? 1 : 2,
'isMicrophoneOn': role != CurrentRole.normalUser ? true : false,
'isVideoOn':
role == CurrentRole.maleAudience || role == CurrentRole.femaleAudience
? true
: false,
};
final response = await _networkService.rtcApi.connectRtcChannel(data);
if (!response.data.isSuccess) {
// 刷新 DiscoverController.loadRtcChannelPage
if (Get.isRegistered<DiscoverController>()) {
final discoverController = Get.find<DiscoverController>();
discoverController.loadRtcChannelPage();
}
SmartDialog.showToast(response.data.message);
return;
}
if (!response.data.data['success']) {
return;
}
currentRole = role;
if (role == CurrentRole.maleAudience ||
role == CurrentRole.femaleAudience) {
await RTCManager.instance.publishVideo(role);
} else {
await RTCManager.instance.publishAudio();
}
// 上麦成功后刷新连麦卡片数据
await getUserPropLinkMicCard();
RtcSeatUserInfo userInfo = RtcSeatUserInfo(
uid: rtcChannel.value?.uid,
miId: GlobalData().userData?.id ?? '',
userId: GlobalData().userData?.id ?? '',
nickName: GlobalData().userData?.nickName ?? '',
profilePhoto: GlobalData().userData?.profilePhoto ?? '',
seatNumber: role == CurrentRole.maleAudience ? 1 : 2,
isFriend: false,
isMicrophoneOn: true,
isVideoOn:
role == CurrentRole.maleAudience || role == CurrentRole.femaleAudience
? true
: false,
genderCode: GlobalData().userData?.genderCode ?? 0,
);
final newDetail = RtcChannelDetail(
channelId: rtcChannelDetail.value!.channelId,
anchorInfo: rtcChannelDetail.value!.anchorInfo,
maleInfo: role == CurrentRole.maleAudience
? userInfo
: rtcChannelDetail.value?.maleInfo,
femaleInfo: role == CurrentRole.femaleAudience
? userInfo
: rtcChannelDetail.value?.femaleInfo,
);
rtcChannelDetail.value = newDetail;
isLive.value = true;
}
Future<void> leaveChat() async {
final data = {'channelId': RTCManager.instance.currentChannelId};
final response = await _networkService.rtcApi.disconnectRtcChannel(data);
if (response.data.isSuccess) {
isLive.value = false;
await RTCManager.instance.unpublish(currentRole);
if (currentRole == CurrentRole.maleAudience) {
final newDetail = RtcChannelDetail(
channelId: rtcChannelDetail.value!.channelId,
anchorInfo: rtcChannelDetail.value!.anchorInfo,
maleInfo: null,
femaleInfo: rtcChannelDetail.value!.femaleInfo,
);
rtcChannelDetail.value = newDetail;
} else if (currentRole == CurrentRole.femaleAudience) {
final newDetail = RtcChannelDetail(
channelId: rtcChannelDetail.value!.channelId,
anchorInfo: rtcChannelDetail.value!.anchorInfo,
maleInfo: rtcChannelDetail.value!.maleInfo,
femaleInfo: null,
);
rtcChannelDetail.value = newDetail;
}
currentRole = CurrentRole.normalUser;
}
}
/// 获取 RTC 频道详情(公有方法,供外部调用)
Future<void> fetchRtcChannelDetail(String channelName) async {
try {
final response = await _networkService.rtcApi.getRtcChannelDetail(
channelName,
);
final base = response.data;
if (base.isSuccess && base.data != null) {
rtcChannelDetail.value = base.data;
}
} catch (e) {
print('获取 RTC 频道详情失败:$e');
}
}
Future<void> _fetchRtcChannelDetail(String channelName) async {
await fetchRtcChannelDetail(channelName);
}
/// 发送公屏消息
Future<void> sendChatMessage(String content) async {
final channelName = RTCManager.instance.currentChannelId;
final result = await _messageService.sendMessage(
content: content,
channelName: channelName,
);
// 如果发送成功,立即添加到本地列表(优化体验,避免等待 RTM 回调)
if (result.success && result.message != null) {
_addMessage(result.message!);
}
}
Future<bool> _ensureRtcPermissions() async {
final statuses = await [Permission.camera, Permission.microphone].request();
final allGranted = statuses.values.every((status) => status.isGranted);
if (allGranted) {
return true;
}
final permanentlyDenied = statuses.values.any(
(status) => status.isPermanentlyDenied,
);
if (permanentlyDenied) {
SmartDialog.showToast('请在系统设置中开启摄像头和麦克风权限');
await openAppSettings();
} else {
SmartDialog.showToast('请允许摄像头和麦克风权限以进入房间');
}
return false;
}
/// 检查麦克风权限(用于普通观众上麦)
Future<bool> _ensureMicrophonePermission() async {
final micStatus = await Permission.microphone.request();
if (micStatus.isGranted) {
return true;
}
if (micStatus.isPermanentlyDenied) {
SmartDialog.showToast('请在系统设置中开启麦克风权限');
await openAppSettings();
} else {
SmartDialog.showToast('请允许麦克风权限以进入房间');
}
return false;
}
Future<void> leaveChannel() async {
if (currentRole == CurrentRole.broadcaster) {
try {
// 先调用销毁 RTC 频道 API
final destroyResponse = await _networkService.rtcApi.destroyRtcChannel();
if (destroyResponse.data.isSuccess) {
// 然后发送结束直播消息
final channelId = RTCManager.instance.currentChannelId;
if (channelId != null && channelId.isNotEmpty) {
await RTMManager.instance.publishChannelMessage(
channelName: channelId,
message: json.encode({'type': 'end_live'}),
);
}
}
} catch (e) {
print('❌ 销毁 RTC 频道异常: $e');
}
} else if (currentRole == CurrentRole.maleAudience || currentRole == CurrentRole.femaleAudience) {
try {
// 嘉宾离开时调用断开 RTC 频道连接接口
final channelId = RTCManager.instance.currentChannelId;
if (channelId != null && channelId.isNotEmpty) {
final data = {'channelId': channelId};
final response = await _networkService.rtcApi.disconnectRtcChannel(data);
if (response.data.isSuccess) {
print('✅ [RoomController] 嘉宾已断开 RTC 频道连接,channelId: $channelId');
} else {
print('⚠️ [RoomController] 断开 RTC 频道连接失败: ${response.data.message}');
}
}
} catch (e) {
print('❌ [RoomController] 断开 RTC 频道连接异常: $e');
}
}
isLive.value = false;
if (currentRole == CurrentRole.maleAudience ||
currentRole == CurrentRole.femaleAudience) {
await RTCManager.instance.unpublish(currentRole);
}
currentRole = CurrentRole.normalUser;
await RTCManager.instance.leaveChannel();
// 清空RTM消息列表
chatMessages.clear();
}
/// 加载礼物产品列表
Future<void> loadGiftProducts() async {
try {
final response = await _networkService.rtcApi.listGiftProduct();
final base = response.data;
if (base.isSuccess && base.data != null) {
giftProducts.assignAll(base.data!);
print('✅ 礼物产品列表加载成功,共 ${giftProducts.length}');
} else {
print('❌ 加载礼物产品列表失败: ${base.message}');
}
} catch (e) {
print('❌ 加载礼物产品列表异常: $e');
}
}
/// 赠送礼物
Future<void> sendGift({
required GiftProductModel gift,
required int targetUserId,
required int type,
}) async {
try {
// 先调用消费接口
final channelId = RTCManager.instance.currentChannelId;
if (channelId == null || channelId.isEmpty) {
SmartDialog.showToast('频道ID不存在');
return;
}
// 准备请求参数
final requestData = {
'channelId': int.tryParse(channelId) ?? 0,
'type': type, // 1.送礼 2.添加好友
'toUId': targetUserId,
'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;
}
if (response.data.isSuccess && !response.data.data['success']) {
final code = response.data.data['code'];
if (code == 'E0002') {
// 玫瑰不足,显示 toast 并弹出充值弹框
SmartDialog.showToast('玫瑰不足请充值');
Get.log('❌ 送礼失败: ${response.data.data}');
// 使用 addPostFrameCallback 确保在下一帧显示弹框,避免与 toast 冲突
WidgetsBinding.instance.addPostFrameCallback((_) {
setDialogDismiss(true);
SmartDialog.show(
alignment: Alignment.bottomCenter,
onDismiss: (){
setDialogDismiss(false);
},
maskColor: Colors.black.withOpacity(0.5),
builder: (_) => const LiveRechargePopup(),
);
});
} else {
SmartDialog.showToast('发送礼物失败');
}
return;
}
// 消费成功后刷新玫瑰数量
await getVirtualAccount();
// 消费成功后再添加到本地播放队列
final svgaManager = SvgaPlayerManager.instance;
svgaManager.addToQueue(
SvgaAnimationItem(
svgaFile: gift.svgaFile,
targetUserId: targetUserId,
senderUserId: rtcChannel.value?.uid,
giftProductId: gift.productId,
),
);
print('✅ 礼物已添加到播放队列: ${gift.productTitle}');
// 在公屏显示赠送礼物消息
final senderNickName = GlobalData().userData?.nickName ?? '用户';
String targetNickName = '用户';
// 从频道详情中查找目标用户昵称
final channelDetail = rtcChannelDetail.value;
if (channelDetail != null) {
// 检查是否是主持人
final anchorInfo = channelDetail.anchorInfo;
if (anchorInfo != null && anchorInfo.uid == targetUserId) {
targetNickName = anchorInfo.nickName.isNotEmpty
? anchorInfo.nickName
: '用户';
}
// 检查是否是男嘉宾
else {
final maleInfo = channelDetail.maleInfo;
if (maleInfo != null && maleInfo.uid == targetUserId) {
targetNickName = maleInfo.nickName.isNotEmpty
? maleInfo.nickName
: '用户';
}
// 检查是否是女嘉宾
else {
final femaleInfo = channelDetail.femaleInfo;
if (femaleInfo != null && femaleInfo.uid == targetUserId) {
targetNickName = femaleInfo.nickName.isNotEmpty
? femaleInfo.nickName
: '用户';
}
}
}
}
// 发送 RTM 消息通知其他用户(包含目标用户昵称)
final messageData = {
'type': 'gift',
'svgaFile': gift.svgaFile,
'giftProductId': gift.productId,
'targetUserId': targetUserId,
'targetNickName': targetNickName, // 包含目标用户昵称
'senderUserId': rtcChannel.value?.uid,
'senderNickName': senderNickName,
'senderAvatar': GlobalData().userData?.profilePhoto ?? '',
};
await RTMManager.instance.publishChannelMessage(
channelName: channelId,
message: json.encode(messageData),
);
print('✅ 礼物消息已发送: ${gift.productTitle}');
// 创建公屏消息
final giftMessage = LiveChatMessage(
userId: GlobalData().userId ?? GlobalData().userData?.id ?? '',
userName: senderNickName,
avatar: GlobalData().userData?.profilePhoto,
content: '$targetNickName赠送了${gift.productTitle}',
timestamp: DateTime.now().millisecondsSinceEpoch,
);
// 添加到消息列表
_addMessage(giftMessage);
} catch (e) {
print('❌ 发送礼物失败: $e');
SmartDialog.showToast('发送礼物失败');
}
}
/// 接收RTC消息
Future<void> receiveRTCMessage(Map<String, dynamic> message) async {
if (message['type'] == 'gift') {
// 处理礼物消息
try {
final svgaFile = message['svgaFile']?.toString() ?? '';
final giftProductId = message['giftProductId']?.toString();
final targetUserId = message['targetUserId'];
final targetNickNameFromMessage = message['targetNickName']?.toString();
final senderUserId = message['senderUserId'];
final senderNickName = message['senderNickName']?.toString() ?? '用户';
final senderAvatar = message['senderAvatar']?.toString();
// 从礼物产品列表中查找礼物名称
String giftTitle = '礼物';
if (giftProductId != null && giftProductId.isNotEmpty) {
try {
final gift = giftProducts.firstWhere(
(g) => g.productId == giftProductId,
);
giftTitle = gift.productTitle;
} catch (e) {
// 如果找不到对应的礼物,使用默认名称
print('⚠️ 未找到礼物ID: $giftProductId');
}
}
// 获取目标用户昵称(优先使用消息中的昵称,如果不存在则从频道详情中查找)
String targetNickName = targetNickNameFromMessage ?? '用户';
if (targetNickName == '用户' || targetNickName.isEmpty) {
final channelDetail = rtcChannelDetail.value;
if (channelDetail != null) {
final targetUserIdStr = targetUserId?.toString() ?? '';
final targetUid = targetUserId is int
? targetUserId
: (int.tryParse(targetUserIdStr) ?? 0);
// 检查是否是主持人(同时检查 uid 和 userId)
final anchorInfo = channelDetail.anchorInfo;
if (anchorInfo != null &&
(anchorInfo.uid == targetUid || anchorInfo.userId == targetUserIdStr)) {
targetNickName = anchorInfo.nickName.isNotEmpty
? anchorInfo.nickName
: '用户';
}
// 检查是否是男嘉宾(同时检查 uid 和 userId)
else {
final maleInfo = channelDetail.maleInfo;
if (maleInfo != null &&
(maleInfo.uid == targetUid || maleInfo.userId == targetUserIdStr)) {
targetNickName = maleInfo.nickName.isNotEmpty
? maleInfo.nickName
: '用户';
}
// 检查是否是女嘉宾(同时检查 uid 和 userId)
else {
final femaleInfo = channelDetail.femaleInfo;
if (femaleInfo != null &&
(femaleInfo.uid == targetUid || femaleInfo.userId == targetUserIdStr)) {
targetNickName = femaleInfo.nickName.isNotEmpty
? femaleInfo.nickName
: '用户';
}
}
}
}
}
// 在公屏显示赠送礼物消息
final giftMessage = LiveChatMessage(
userId: senderUserId?.toString() ?? '',
userName: senderNickName,
avatar: senderAvatar?.isNotEmpty == true ? senderAvatar : null,
content: '$targetNickName赠送了$giftTitle',
timestamp: DateTime.now().millisecondsSinceEpoch,
);
_addMessage(giftMessage);
if (svgaFile.isNotEmpty) {
// 添加到播放队列
final svgaManager = SvgaPlayerManager.instance;
svgaManager.addToQueue(
SvgaAnimationItem(
svgaFile: svgaFile,
targetUserId: targetUserId,
senderUserId: senderUserId is int
? senderUserId
: (int.tryParse(senderUserId?.toString() ?? '') ?? 0),
giftProductId: giftProductId,
),
);
print('✅ 收到礼物消息,已添加到播放队列: $senderNickName 赠送了礼物');
}
} catch (e) {
print('❌ 处理礼物消息失败: $e');
}
} else if (message['type'] == 'kick_user') {
// 处理踢人消息
try {
final kickingUId = message['kickingUId'];
final operatorName = message['operatorName']?.toString() ?? '主持人';
print('✅ 收到踢人消息: 被踢用户ID $kickingUId');
// 判断当前用户是否是被踢的用户
if (rtcChannel.value?.uid == kickingUId) {
// 被踢用户:关闭小窗口
if (Get.isRegistered<OverlayController>()) {
try {
final overlayController = Get.find<OverlayController>();
overlayController.hide(); // 隐藏直播房间小窗
} catch (e) {
print('关闭小窗口失败: $e');
}
}
// 被踢用户:离开房间
await leaveChannel();
// 跳转到结束直播页面,并传入被踢出标识
Get.off(
() => LiveEndPage(isKickedOut: true, operatorName: operatorName),
);
} else {
// 其他用户:刷新房间详情
final channelName = RTCManager.instance.currentChannelId;
if (channelName != null && channelName.isNotEmpty) {
await fetchRtcChannelDetail(channelName);
}
print('✅ 其他用户收到踢人消息,已刷新房间详情');
}
} catch (e) {
print('❌ 处理踢人消息失败: $e');
}
}
}
void registerMatch() async {
if (GlobalData().userData!.identityCard != null &&
GlobalData().userData!.identityCard!.isNotEmpty) {
await Get.to(() => MatchSpreadPage());
} else {
SmartDialog.showToast('请先进行实名认证');
await Get.to(() => RealNamePage(type: 1));
}
print(455);
matchmakerFlag.value = GlobalData().userData!.matchmakerFlag!;
}
/// 踢出 RTC 频道用户
Future<void> kickingRtcChannelUser({
required String channelId,
required int kickingUId,
}) async {
try {
final requestData = {'channelId': channelId, 'kickingUId': kickingUId};
final response = await _networkService.rtcApi.kickingRtcChannelUser(
requestData,
);
if (response.data.isSuccess) {
SmartDialog.showToast('已踢出用户');
// 发送 RTM 消息通知所有用户
final channelName = RTCManager.instance.currentChannelId;
if (channelName != null && channelName.isNotEmpty) {
final messageData = {
'type': 'kick_user',
'kickingUId': kickingUId,
'operatorId': GlobalData().userData?.id ?? '',
'operatorName': GlobalData().userData?.nickName ?? '',
};
await RTMManager.instance.publishChannelMessage(
channelName: channelName,
message: json.encode(messageData),
);
print('✅ 踢人消息已发送: 踢出用户ID $kickingUId');
// 刷新频道详情
await fetchRtcChannelDetail(channelName);
}
} else {
final message = response.data.message.isNotEmpty
? response.data.message
: '踢出用户失败';
SmartDialog.showToast(message);
}
} catch (e) {
print('❌ 踢出用户异常: $e');
SmartDialog.showToast('踢出用户失败');
}
}
/// 获取用户道具连麦卡片
Future<void> getUserPropLinkMicCard() async {
try {
final response = await _networkService.rtcApi.getUserPropLinkMicCard();
final base = response.data;
if (base.isSuccess && base.data != null) {
linkMicCard.value = base.data;
print(
'✅ 获取连麦卡片成功: type=${base.data!.type}, num=${base.data!.num}, unitSellingPrice=${base.data!.unitSellingPrice}',
);
} else {
linkMicCard.value = null;
print('❌ 获取连麦卡片失败: ${base.message}');
}
} catch (e) {
linkMicCard.value = null;
print('❌ 获取连麦卡片异常: $e');
}
}
/// 获取虚拟账户(玫瑰数量)
Future<void> getVirtualAccount() async {
try {
final response = await _networkService.userApi.getVirtualAccount({});
final base = response.data;
if (base.isSuccess && base.data != null) {
roseCount.value = base.data!.balance ?? 0;
print('✅ 获取玫瑰数量成功: ${roseCount.value}');
} else {
roseCount.value = 0;
print('❌ 获取玫瑰数量失败: ${base.message}');
}
} catch (e) {
roseCount.value = 0;
print('❌ 获取玫瑰数量异常: $e');
}
}
}