validated(); $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $list = $model->getList( params : $params, orderBy: ['weigh' => 'desc'], select : ['id', 'user_id', 'room_no', 'name', 'logo', 'image', 'session', 'status', 'create_time'], with : [ 'log' => function ($query) { $query->select(['id', 'session', 'like', 'ccu', 'goods_sales', 'share_num', 'follow_num', 'duration', 'open_time', 'close_time']); } ] ); $im = new TencentIm(); foreach ($list as $key => $val) { $list[$key]['push_url'] = $im->getLivePushUrl($val['room_no']); $list[$key]['play_url'] = $im->getLivePlayUrl($val['room_no']); } return AppResult::success('success', $list); } // 房间详情 public function room_detail(RoomDetailRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $info = $model->getDetail( params: $params, select: ['id', 'user_id', 'room_no', 'name', 'logo', 'image', 'session', 'follow_num', 'status', 'create_time'], with : [ 'log' => function ($query) { $query->select(['id', 'session', 'like', 'ccu', 'goods_sales', 'share_num', 'follow_num', 'duration', 'open_time', 'close_time']); }, 'user' => function ($query) { $query->select(['id', 'nickname', 'avatar', 'gender']); } ] ); $info['user']['chat_id'] = im_prefix($info['user']['id']); $info['user']['avatar'] = cdn_url($info['user']['avatar']); // 判断用户身份 $info['role'] = 3;// 观众 if ($user['id'] == $info['user_id']) { $info['role'] = 1;// 房主 } else { $model = new LiveRoomAdminModel(); $admin = $model->getAdmin($user['id'],$params['room_no']); if (!empty($admin)) { $info['role'] = 2;// 场控 } } // 如果不是自己的直播间,需要判断关注按钮 $info['is_follow'] = 2;//状态:0=未关注,1=关注,2=主播自己 if ($info['user_id'] != $user['id']) { $info['is_follow'] = 0; // 查询是否关注对方 if (LiveRoomFollowModel::query()->where(['room_id' => $info['id'], 'user_id' => $user['id'], 'status' => 1])->exists()) { $info['is_follow'] = 1; //状态:0=关注,1=互为关注 } } // 配置直播推流连接 $im = new TencentIm(); $info['push_url'] = $im->getLivePushUrl($info['room_no']); $info['play_url'] = $im->getLivePlayUrl($info['room_no']); return AppResult::success('获取成功', $info); } // 创建直播间 public function room_add(RoomAddRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); // 校验开播资格 if ($user['group_id'] !== 2) { return AppResult::error('抱歉,您没有权限'); } Db::beginTransaction(); try { // 创建直播房间 $model = new LiveRoomModel(); if (!$model->createRoom($user, (string)$params['name'], (string)($params['image'] ?? ''))) { Db::rollBack(); return AppResult::error($model->getMessage() ?? '操作失败'); } $data = $model->getData(); $room_status = $data['status'] ?? 0;// 直播房间状态 RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $data['room_no'])->del(); // 如果没开播 if ($room_status == 0) { // IM直播创建房间 && 创建群组 $im = new TencentIm(); $im->create_group(im_prefix($user['id']), $data['room_no'], (string)$data['room_name'], notification: site('live_notice') ?? ''); } Db::commit(); } catch (\Exception $e) { Db::rollBack(); return AppResult::error($e->getMessage() ?? '操作失败'); } // 配置直播推流连接 $im = new TencentIm(); // 设置群属性 $counter[] = [ 'key' => 'talk_status', 'value' => (string)$data['talk_status'] ]; $counter[] = [ 'key' => 'top_avatar', 'value' => '' ]; $counter[] = [ 'key' => 'like', 'value' => '0' ]; $counter[] = [ 'key' => 'online_member_num', 'value' => '0' ]; $im->modify_group_attr($data['room_no'], $counter); return AppResult::success('创建成功', [ 'room_no' => $data['room_no'], 'room_name' => $data['room_name'], 'push_url' => $im->getLivePushUrl($data['room_no']), 'play_url' => $im->getLivePlayUrl($data['room_no']), ]); } // 关闭直播间 public function room_close(RoomCloseRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); $params['user_id'] = $user['id']; $model = new LiveRoomModel(); $room = $model->getDetail(params: $params,with: ['log']); if (!$room) { return AppResult::error('直播间不存在或已关闭'); } Db::beginTransaction(); try { // 创建直播房间 $model = new LiveRoomModel(); if (!$model->closeRoom($room['id'])) { Db::rollBack(); return AppResult::error($model->getMessage() ?? '操作失败'); } LiveRoomGoodsModel::query()->where('room_no',$room['room_no'])->where('is_top',1)->update(['is_top' => 0]); // 腾讯直播创建房间 && 创建群组 $tanIm = new TencentIm(); $tanIm->destroy_group($room['room_no']); Db::commit(); } catch (\Exception $e) { Db::rollBack(); return AppResult::error($e->getMessage() ?? '操作失败'); } $room['log']['close_time'] = time(); $room['log']['duration'] = time() - $room['log']['open_time']; return AppResult::success('关闭成功',$room['log']); } // 进入房间 public function room_join(RoomJoinRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $info = $model->getDetail(params: $params); if (!$info) { return AppResult::error('直播间已关闭'); } if (RedisUtil::getInstance(RedisKeyEnum::ROOM_BLACK,$info['room_no'],im_prefix($user['id']))->get()){ return AppResult::error('您被改直播间拉入黑名单,暂时无法进入'); } // 处理直播间在线人数 // 判断当前用户是否存在在直播间通过切换过来的 $ROOM_USER_IN = RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_IN)->hGet((string)$user['id']); if (!$ROOM_USER_IN || $ROOM_USER_IN != $info['id']) { if ($ROOM_USER_IN != $info['id']) { // 从原房间内移除此用户 RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $info['room_no'])->zRem($user['id']); // 扣除在线用户在房间情况 RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_IN)->hDel((string)$user['id']); } // 记录在线用户在房间情况 RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_IN)->hSet((string)$user['id'], $info['room_no']); $value = LiveRoomLogLikeModel::query()->where('user_id', $user['id'])->where('room_no', $info['room_no'])->value('like'); RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $info['room_no'])->zAdd((int)($value ?: 0), $user['id']); } // 直播间观看人数加一 $this->service->liveRoomDataPush(['session' => $info['session'], 'ccu' => 1]); return AppResult::success('进入成功'); } // 离开房间 public function room_leave(RoomJoinRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $info = $model->getDetail(params: $params); if (!$info) { return AppResult::error('直播间已关闭'); } // 从原房间内移除此用户 RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $info['room_no'])->zRem($user['id']); // 扣除在线用户在房间情况 RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_IN)->hDel((string)$user['id']); if ($info) { $this->service->liveRoomDataPush(['session' => $info['session'], 'ccu' => -1]); if ($info['user_id'] == $user['id']) { // 如果是主播,则关闭直播间 $model = new LiveRoomModel(); $model->closeRoom($info['id']); // 腾讯直播解散群组 $im = new TencentIm(); $im->destroy_group($info['room_no']); } } return AppResult::success('已离开直播间'); } // 房管列表 public function admin_list(AdminListRequest $request) { $params = $request->validated(); $model = new LiveRoomAdminModel(); $model->setIsStatusSearchValue(); $list = $model->getList( params: $params, with : [ 'user' => function ($query) { $query->select(['id', 'nickname', 'avatar']); } ] ); foreach ($list as $key => $val) { $list[$key]['user']['avatar'] = cdn_url($val['user']['avatar']); $list[$key]['user']['chat_id'] = im_prefix($val['user']['id']); } return AppResult::success('获取成功', $list); } // 设置超管 public function admin_add(AdminSetRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); $model = new LiveRoomAdminModel(); if (!$model->add($user['id'], (string)$params['room_no'], im_un_prefix($params['chat_id']))) { return AppResult::error($model->getMessage() ?? '操作失败'); } return AppResult::success('设置成功'); } // 删除超管 public function admin_del(AdminSetRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); $model = new LiveRoomAdminModel(); if (!$model->del($user['id'], (string)$params['room_no'], im_un_prefix($params['chat_id']))) { return AppResult::error($model->getMessage() ?? '操作失败'); } return AppResult::success('删除成功'); } // 房间观众信息 public function user_info(UserInfoRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); if (!$room = $model->getDetail(params: ['room_no' => $params['room_no']])) { return AppResult::error('直播间已关闭'); } $userInfo = UserModel::query()->where('id',im_un_prefix($params['chat_id']))->where('status',1)->first(); if (!$userInfo){ return AppResult::error('用户不存在'); } // 判断当前用户身份 $user_role = 3;// 观众 if ($user['id'] == $room['user_id']) { $user_role = 1;// 房主 } else { $model = new LiveRoomAdminModel(); $admin = $model->getAdmin($user['id'],$params['room_no']); if (!empty($admin)) { $user_role = 2;// 场控 } } // 判断查询的用户身份 $info_role = 3;// 观众 if ($userInfo->id == $room['user_id']) { $info_role = 1;// 房主 } else { $model = new LiveRoomAdminModel(); $admin = $model->getAdmin($userInfo->id,$params['room_no']); if (!empty($admin)) { $info_role = 2;// 场控 } } return AppResult::success('操作成功',[ 'info' => [ 'id' => $userInfo->id, 'chat_id' => $params['chat_id'], 'nickname' => $userInfo->nickname, 'avatar' => cdn_url($userInfo->avatar), 'role' => $info_role, 'is_shut_up' => RedisUtil::getInstance(RedisKeyEnum::ROOM_SHUT_UP,$params['room_no'],$params['chat_id'])->get() ? 1 : 0, 'is_black' => RedisUtil::getInstance(RedisKeyEnum::ROOM_BLACK,$params['room_no'],$params['chat_id'])->get() ? 1 : 0, ], 'me' => [ 'role' => $user_role ] ]); } // 移除房间观众 public function user_remove(UserRemoveRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); if ($user['id'] == im_un_prefix($params['chat_id'])) { return AppResult::error('无法对自己操作'); } $model = new LiveRoomModel(); if (!$room = $model->getDetail(params: ['room_no' => $params['room_no']])) { return AppResult::error('直播间已关闭'); } if ($room['user_id'] != $user['id']) { $model = new LiveRoomAdminModel(); if (!$model->getAdmin($user['id'], $params['room_no'])) { return AppResult::error('未拥有此权限'); } } // 腾讯直播创建房间 && 创建群组 $im = new TencentIm(); if (!$im->delete_group_member($params['room_no'], im_prefix($params['chat_id']))) { return AppResult::error($im->getMessage() ?? '操作失败'); } // 移除观众列表 RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $room['room_no'])->zRem(im_un_prefix($params['chat_id'])); // 直播间人数减一 $this->service->liveRoomDataPush(['session' => $room['session'], 'ccu' => -1]); return AppResult::success('操作成功'); } // 禁言列表 public function shut_up_list(ShutUpListRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); if (!$room = $model->getDetail(params: ['room_no' => $params['room_no']])) { return AppResult::error('直播间已关闭'); } if ($room['user_id'] != $user['id']) { $model = new LiveRoomAdminModel(); if (!$model->getAdmin($user['id'], $params['room_no'])) { return AppResult::error('未拥有此权限'); } } $im = new TencentIm(); if (!$im->get_group_muted_account($params['room_no'])) { return AppResult::error($im->getMessage() ?? '操作失败'); } $data = $im->getData(); $ids = []; foreach ($data['MutedAccountList'] as $item) { $ids[] = im_un_prefix($item['Member_Account']); } $model = new UserModel(); $list = $model->getList(params: ['ids' => $ids], select: ['id', 'nickname', 'avatar']); foreach ($list as $key => $val) { $list[$key]['avatar'] = cdn_url($val['avatar']); $list[$key]['chat_id'] = im_prefix($val['id']); } return AppResult::success('操作成功', $list); } // 禁言 public function shut_up(ShutUpRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); if ($user['id'] == im_un_prefix($params['chat_id'])) { return AppResult::error('无法对自己操作'); } $model = new LiveRoomModel(); if (!$model->shut_up($user['id'], (string)$params['room_no'], im_un_prefix($params['chat_id']), (int)($params['time'] ?? 86400))) { return AppResult::error($model->getMessage() ?? '操作失败'); } return AppResult::success('操作成功'); } // 黑名单列表 public function black_list(ShutUpListRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); if (!$room = $model->getDetail(params: ['room_no' => $params['room_no']])) { return AppResult::error('直播间已关闭'); } if ($room['user_id'] != $user['id']) { $model = new LiveRoomAdminModel(); if (!$model->getAdmin($user['id'], $params['room_no'])) { return AppResult::error('未拥有此权限'); } } // $im = new TencentIm(); // if (!$im->get_group_ban_member($params['room_no'])) { // return AppResult::error($im->getMessage() ?? '操作失败'); // } // $data = $im->getData(); // $ids = []; // foreach ($data['BannedAccountList'] as $item) { // $ids[] = im_un_prefix($item['Member_Account']); // } $ids = LiveRoomBlackModel::query()->where('room_no',$params['room_no'])->where('status',1)->where('end_time','>',time())->pluck('user_id')->toArray(); $model = new UserModel(); $list = $model->getList(params: ['ids' => $ids], select: ['id', 'nickname', 'avatar']); foreach ($list as $key => $val) { $list[$key]['avatar'] = cdn_url($val['avatar']); $list[$key]['chat_id'] = im_prefix($val['id']); } return AppResult::success('操作成功', $list); } // 封禁 黑名单 public function black_add(BlackAddRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); if ($user['id'] == im_un_prefix($params['chat_id'])) { return AppResult::error('无法对自己操作'); } $model = new LiveRoomModel(); if (!$model->black_add($user['id'], (string)$params['room_no'], im_un_prefix($params['chat_id']), (int)($params['time'] ?? 86400))) { return AppResult::error($model->getMessage() ?? '操作失败'); } return AppResult::success('操作成功'); } // 移除 封禁 黑名单 public function black_remove(BlackRemoveRequest $request) { $params = $request->validated(); $user = AuthUser::getInstance()->get(); if ($user['id'] == im_un_prefix($params['chat_id'])) { return AppResult::error('无法对自己操作'); } $model = new LiveRoomModel(); if (!$model->black_remove($user['id'], (string)$params['room_no'], im_un_prefix($params['chat_id']))) { return AppResult::error($model->getMessage() ?? '操作失败'); } return AppResult::success('操作成功'); } // 直播间观众列表(已关注的) public function audience(AudienceRequest $request) { $params = $request->validated();// 获取校验参数结果 $model = new LiveRoomFollowModel(); $model->setIsStatusSearchValue(); $list = $model->getList( params : $params, orderBy: ['id' => 'desc'], with : [ 'user' => function ($with) use ($params) { $with->select(['id', 'nickname', 'avatar']); } ] ); // 查询当前直播间管理员id $adminIds = LiveRoomAdminModel::query()->where('room_no', $params['room_no'])->where('status', 1)->pluck('admin_id')->toArray(); foreach ($list as $key => $val) { $list[$key]['is_admin'] = in_array($val['user_id'], $adminIds) ? 1 : 0; $list[$key]['user'] = [ 'chat_id' => im_prefix($val['user']['id']), 'avatar' => cdn_url($val['user']['avatar']), 'nickname' => $val['user']['nickname'], ]; } return AppResult::success('获取成功', $list); } // 直播间观众榜单 public function top(LikeRequest $request) { $params = $request->validated();// 获取校验参数结果 $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $room = $model->getDetail(params: $params); if (!$room) { return AppResult::error('直播间异常'); } $model = new LiveRoomLogLikeModel(); $list = $model->getTopList($room['room_no'], $room['user_id']); $meRank = RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $room['room_no'])->zRevRank($user['id']); return AppResult::success('success', [ 'me' => [ 'id' => $user['id'], 'chat_id' => im_prefix($user['id']), 'nickname' => $user['nickname'], 'avatar' => cdn_url($user['avatar']), 'rank' => $meRank >= 0 ? $meRank + 1 : '' ], 'list' => $list ]); } // 点赞 public function like(LikeRequest $request) { $params = $request->validated();// 获取校验参数结果 $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $room = $model->getDetail(params: $params); if (!$room) { return AppResult::error('直播间异常'); } // 不可以赠送给自己 if ($user['id'] == $room['user_id']) { return AppResult::error('不可以给自己点赞'); } // 加入点赞队列 $this->service->liveRoomDataPush([ 'user_id' => $user['id'], 'room_id' => $room['id'], 'room_no' => $room['room_no'], 'session' => $room['session'], 'like' => 1 ]); return AppResult::success('点赞成功'); } // 关注 取消关注 public function follow(FollowRequest $request) { $params = $request->validated();// 获取校验参数结果 $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $room = $model->getDetail(params: $params); if (!$room) { return AppResult::error('直播间异常'); } // 不可以赠送给自己 if ($user['id'] == $room['user_id']) { return AppResult::error('不可以关注自己'); } $model = new LiveRoomFollowModel(); if ($params['status'] == 1) { if (!$model->follow($user['id'], $room['id'], $room['room_no'], $room['session'])) { return AppResult::error($model->getMessage() ?? '关注失败'); } } else { if (!$model->cancelFollow($user['id'], $room['id'], $room['room_no'])) { return AppResult::error($model->getMessage() ?? '取关失败'); } } return AppResult::success($model->getMessage() ?? '操作成功'); } // 发言权限 public function talk_set(TalkSetRequest $request) { $params = $request->validated();// 获取校验参数结果 $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $room = $model->getDetail(params: $params); if (!$room) { return AppResult::error('直播间异常'); } // 不可以赠送给自己 if ($user['id'] != $room['user_id']) { $model = new LiveRoomAdminModel(); if (!$model->getAdmin($user['id'], $room['room_no'])) { return AppResult::error('未拥有此权限'); } } $model = new LiveRoomModel(); if (!$model->query()->where('id', $room['id'])->update(['talk_status' => $params['talk_status'], 'update_time' => time()])) { return AppResult::error('操作失败'); } // 设置群属性 $counter[] = [ 'key' => 'talk_status', 'value' => (string)$params['talk_status'] ]; $im = new TencentIm(); if (!$im->modify_group_attr($room['room_no'], $counter)) { return AppResult::error($im->getMessage() ?? '操作成功', $im->getData()); } return AppResult::success('操作成功'); } // 卡顿上报 public function suggest(SuggestRequest $request) { $params = $request->validated();// 获取校验参数结果 $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $room = $model->getDetail(params: $params); if (!$room) { return AppResult::error('直播间异常'); } $params['room_id'] = $room['id']; $model = new LiveSuggestModel(); if (!$model->add($user['id'], $params)) { return AppResult::error('操作失败'); } return AppResult::success('上报成功'); } // 举报 public function report(ReportRequest $request) { $params = $request->validated();// 获取校验参数结果 $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $room = $model->getDetail(params: $params); if (!$room) { return AppResult::error('直播间异常'); } $to_user = (new UserModel())->getDetail(params: ['id' => im_un_prefix($params['to_chat_id'])]); if (!$to_user) { return AppResult::error('举报用户不存在'); } $params['room_id'] = $room['id']; $params['to_user_id'] = im_un_prefix($params['to_chat_id']); unset($params['to_chat_id']); $model = new LiveReportModel(); if (!$model->add($user['id'], $params)) { return AppResult::error('操作失败'); } return AppResult::success('举报成功'); } // 敏感词 public function keyword_filter_list(KeywordFilterListRequest $request) { $params = $request->validated();// 获取校验参数结果 $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $room = $model->getDetail(params: $params); if (!$room) { return AppResult::error('直播间异常'); } $model = new LiveRoomKeywordModel(); return AppResult::success('获取成功',$model->getList($params)); } // 敏感词 public function keyword_filter_add(KeywordFilterAddRequest $request) { $params = $request->validated();// 获取校验参数结果 $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $room = $model->getDetail(params: $params); if (!$room) { return AppResult::error('直播间异常'); } if ($room['user_id'] != $user['id']) { $model = new LiveRoomAdminModel(); if (!$model->getAdmin($user['id'], $params['room_no'])) { return AppResult::error('未拥有此权限'); } } $model = new LiveRoomKeywordModel(); if (!$model->add($user['id'], $room['id'], $room['room_no'], $params['keyword'])) { return AppResult::error($model->getMessage() ?? '操作失败'); } return AppResult::success($model->getMessage() ?? '操作成功'); } // 敏感词 删除 public function keyword_filter_del(KeywordFilterDelRequest $request) { $params = $request->validated();// 获取校验参数结果 $user = AuthUser::getInstance()->get(); $model = new LiveRoomModel(); $room = $model->getDetail(params: $params); if (!$room) { return AppResult::error('直播间异常'); } if ($room['user_id'] != $user['id']) { $model = new LiveRoomAdminModel(); if (!$model->getAdmin($user['id'], $params['room_no'])) { return AppResult::error('未拥有此权限'); } } $model = new LiveRoomKeywordModel(); if (!$model->del($params['keyword_id'])) { return AppResult::error($model->getMessage() ?? '操作失败'); } return AppResult::success($model->getMessage() ?? '操作成功'); } }