diff --git a/lib/controller/discover/room_controller.dart b/lib/controller/discover/room_controller.dart index 72b73cd..f7e5c1c 100644 --- a/lib/controller/discover/room_controller.dart +++ b/lib/controller/discover/room_controller.dart @@ -552,4 +552,38 @@ class RoomController extends GetxController with WidgetsBindingObserver { print(455); matchmakerFlag.value = GlobalData().userData!.matchmakerFlag!; } + + /// 踢出 RTC 频道用户 + Future kickingRtcChannelUser({ + required int 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('已踢出用户'); + // 刷新频道详情 + final channelName = RTCManager.instance.currentChannelId; + if (channelName != null && channelName.isNotEmpty) { + await fetchRtcChannelDetail(channelName); + } + } else { + final message = response.data.message.isNotEmpty + ? response.data.message + : '踢出用户失败'; + SmartDialog.showToast(message); + } + } catch (e) { + print('❌ 踢出用户异常: $e'); + SmartDialog.showToast('踢出用户失败'); + } + } } diff --git a/lib/controller/mine/auth_controller.dart b/lib/controller/mine/auth_controller.dart index f5b95f5..9dfdcda 100644 --- a/lib/controller/mine/auth_controller.dart +++ b/lib/controller/mine/auth_controller.dart @@ -36,9 +36,7 @@ class AuthController extends GetxController { if(information.identityCard != null){ realAuth = true; } - if(information.profilePhoto != null){ - checkPhoto = true; - } + checkPhoto = information.isPhotoAudited(); } dataList.assignAll([ AuthCard( title: '手机绑定', desc: '防止账号丢失', index: 1, authed: true, defaultIcon: Assets.imagesPhoneChecked, activeIcon: Assets.imagesPhoneChecked, width: 28,height: 40), diff --git a/lib/controller/mine/user_controller.dart b/lib/controller/mine/user_controller.dart index 2b89f2c..52efd57 100644 --- a/lib/controller/mine/user_controller.dart +++ b/lib/controller/mine/user_controller.dart @@ -116,7 +116,6 @@ class UserController extends GetxController { information.realName = baseInfo.realName; information.phone = baseInfo.phone; GlobalData().userData = information; - // await storage.write('userId', GlobalData().userId); if (_checkInformation(information)) { //跳转到完善信息 diff --git a/lib/model/mine/user_data.dart b/lib/model/mine/user_data.dart index cb52c99..3a0651c 100644 --- a/lib/model/mine/user_data.dart +++ b/lib/model/mine/user_data.dart @@ -9,6 +9,7 @@ class UserData { String? identityCard; int? genderCode; Map? auditProfilePhoto; + bool? hasUploadProfilePhoto; final String? genderValue; final String? homeCountryCode; final String? homeCountry; @@ -133,7 +134,8 @@ class UserData { this.realName, this.matchmakerFlag, this.photoList, - this.matchmakerType + this.matchmakerType, + this.hasUploadProfilePhoto }); // 从JSON映射创建实例 @@ -145,6 +147,7 @@ class UserData { profilePhoto: json['profilePhoto'], identityCard: json['identityCard'], genderCode: json['genderCode'] ?? 0, + hasUploadProfilePhoto: json['hasUploadProfilePhoto'] ?? false, auditProfilePhoto: json['auditProfilePhoto'] ?? null, genderValue: json['genderValue'] ?? '', homeCountryCode: json['homeCountryCode'], @@ -212,6 +215,7 @@ class UserData { 'profilePhoto': profilePhoto, 'identityCard': identityCard, 'genderCode': genderCode, + 'hasUploadProfilePhoto': hasUploadProfilePhoto, 'auditProfilePhoto': auditProfilePhoto, 'genderValue': genderValue, 'homeCountryCode': homeCountryCode, @@ -274,4 +278,11 @@ class UserData { String toString() { return 'UserData(id: $id, nickName: $nickName, genderCode: $genderCode, auditProfilePhoto: $auditProfilePhoto, genderValue: $genderValue, birthYear: $birthYear, photoList: $photoList)'; } + + bool isPhotoAudited(){ + if(hasUploadProfilePhoto! && profilePhoto != null){ + return hasUploadProfilePhoto! && profilePhoto!.isNotEmpty; + } + return false; + } } \ No newline at end of file diff --git a/lib/network/api_urls.dart b/lib/network/api_urls.dart index 679652a..7dc552d 100644 --- a/lib/network/api_urls.dart +++ b/lib/network/api_urls.dart @@ -106,4 +106,6 @@ class ApiUrls { 'dating-agency-chat-audio/user/get/own-user-management'; static const String submitMatchmakerOrder = 'dating-agency-mall/user/submit/matchmaker-order'; + static const String kickingRtcChannelUser = + 'dating-agency-chat-audio/user/user//kicking/rtc-channel-user'; } diff --git a/lib/network/rtc_api.dart b/lib/network/rtc_api.dart index d3cf864..7abf0d5 100644 --- a/lib/network/rtc_api.dart +++ b/lib/network/rtc_api.dart @@ -82,4 +82,10 @@ abstract class RtcApi { Future>> costImGift( @Body() Map data, ); + + /// 踢出 RTC 频道用户 + @POST(ApiUrls.kickingRtcChannelUser) + Future>> kickingRtcChannelUser( + @Body() Map data, + ); } diff --git a/lib/network/rtc_api.g.dart b/lib/network/rtc_api.g.dart index febd393..63083af 100644 --- a/lib/network/rtc_api.g.dart +++ b/lib/network/rtc_api.g.dart @@ -467,6 +467,40 @@ class _RtcApi implements RtcApi { return httpResponse; } + @override + Future>> kickingRtcChannelUser( + 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/user//kicking/rtc-channel-user', + 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 || diff --git a/lib/widget/live/disconnect_mic_dialog.dart b/lib/widget/live/disconnect_mic_dialog.dart new file mode 100644 index 0000000..f5ebf7c --- /dev/null +++ b/lib/widget/live/disconnect_mic_dialog.dart @@ -0,0 +1,196 @@ +import 'package:dating_touchme_app/controller/discover/room_controller.dart'; +import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:dating_touchme_app/model/rtc/rtc_channel_detail.dart'; +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'; + +/// 解除连麦对话框 +class DisconnectMicDialog extends StatelessWidget { + const DisconnectMicDialog({super.key}); + + @override + Widget build(BuildContext context) { + final roomController = Get.find(); + + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.w), + ), + child: Container( + padding: EdgeInsets.all(20.w), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 标题栏 + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '解除连麦', + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + GestureDetector( + onTap: () => SmartDialog.dismiss(), + child: Icon( + Icons.close, + size: 24.w, + color: Colors.grey, + ), + ), + ], + ), + SizedBox(height: 20.w), + // 嘉宾列表 + Obx(() { + final maleInfo = roomController.rtcChannelDetail.value?.maleInfo; + final femaleInfo = roomController.rtcChannelDetail.value?.femaleInfo; + + // 如果没有嘉宾在连麦 + if (maleInfo == null && femaleInfo == null) { + return Padding( + padding: EdgeInsets.symmetric(vertical: 20.w), + child: Text( + '暂无嘉宾连麦', + style: TextStyle( + fontSize: 14.sp, + color: Colors.grey, + ), + ), + ); + } + + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + // 男嘉宾 + if (maleInfo != null) + Expanded( + child: _buildGuestItem( + context: context, + userInfo: maleInfo, + roomController: roomController, + isMale: true, + ), + ), + if (maleInfo != null && femaleInfo != null) + SizedBox(width: 20.w), + // 女嘉宾 + if (femaleInfo != null) + Expanded( + child: _buildGuestItem( + context: context, + userInfo: femaleInfo, + roomController: roomController, + isMale: false, + ), + ), + ], + ); + }), + SizedBox(height: 10.w), + ], + ), + ), + ); + } + + /// 构建嘉宾项 + Widget _buildGuestItem({ + required BuildContext context, + required RtcSeatUserInfo userInfo, + required RoomController roomController, + required bool isMale, + }) { + // 判断当前嘉宾是否还在连麦 + final isConnected = userInfo.isMicrophoneOn; + + return Column( + children: [ + // 头像 + ClipOval( + child: Image.network( + userInfo.profilePhoto, + width: 60.w, + height: 60.w, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Image.asset( + Assets.imagesUserAvatar, + width: 60.w, + height: 60.w, + ); + }, + ), + ), + SizedBox(height: 10.w), + // 昵称 + Text( + userInfo.nickName, + style: TextStyle( + fontSize: 14.sp, + color: Colors.black87, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + SizedBox(height: 10.w), + // 解除连麦按钮 + GestureDetector( + onTap: isConnected + ? () async { + // 解除连麦 + await _disconnectMic(roomController, isMale); + } + : null, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.w), + decoration: BoxDecoration( + color: isConnected ? const Color(0xFF8B5CF6) : Colors.grey[300], + borderRadius: BorderRadius.circular(20.w), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Image.asset( + Assets.imagesMicOff, + width: 14.w, + color: isConnected ? Colors.white : Colors.grey[600], + ), + SizedBox(width: 4.w), + Text( + isConnected ? '解除连麦' : '已解除连麦', + style: TextStyle( + fontSize: 12.sp, + color: isConnected ? Colors.white : Colors.grey[600], + ), + ), + ], + ), + ), + ), + ], + ); + } + + /// 解除连麦 + Future _disconnectMic(RoomController roomController, bool isMale) async { + // 更新本地状态 - 移除对应嘉宾的信息 + final currentDetail = roomController.rtcChannelDetail.value; + if (currentDetail != null) { + final newDetail = RtcChannelDetail( + channelId: currentDetail.channelId, + anchorInfo: currentDetail.anchorInfo, + maleInfo: isMale ? null : currentDetail.maleInfo, + femaleInfo: !isMale ? null : currentDetail.femaleInfo, + ); + roomController.rtcChannelDetail.value = newDetail; + } + } +} +