LiveController.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controller\Api\v1;
  4. use App\Controller\AbstractController;
  5. use App\Master\Enum\RedisKeyEnum;
  6. use App\Master\Framework\Library\Tencent\TencentIm;
  7. use App\Model\Arts\LiveReportModel;
  8. use App\Model\Arts\LiveRoomAdminModel;
  9. use App\Model\Arts\LiveRoomBlackModel;
  10. use App\Model\Arts\LiveRoomFollowModel;
  11. use App\Model\Arts\LiveRoomGoodsModel;
  12. use App\Model\Arts\LiveRoomKeywordModel;
  13. use App\Model\Arts\LiveRoomLogLikeModel;
  14. use App\Model\Arts\LiveRoomModel;
  15. use App\Model\Arts\LiveSuggestModel;
  16. use App\Model\Arts\UserModel;
  17. use App\Request\Api\v1\Live\AdminListRequest;
  18. use App\Request\Api\v1\Live\AdminSetRequest;
  19. use App\Request\Api\v1\Live\AudienceRequest;
  20. use App\Request\Api\v1\Live\BlackAddRequest;
  21. use App\Request\Api\v1\Live\BlackRemoveRequest;
  22. use App\Request\Api\v1\Live\FollowRequest;
  23. use App\Request\Api\v1\Live\KeywordFilterAddRequest;
  24. use App\Request\Api\v1\Live\KeywordFilterDelRequest;
  25. use App\Request\Api\v1\Live\KeywordFilterListRequest;
  26. use App\Request\Api\v1\Live\LikeRequest;
  27. use App\Request\Api\v1\Live\ReportRequest;
  28. use App\Request\Api\v1\Live\RoomAddRequest;
  29. use App\Request\Api\v1\Live\RoomCloseRequest;
  30. use App\Request\Api\v1\Live\RoomDetailRequest;
  31. use App\Request\Api\v1\Live\RoomJoinRequest;
  32. use App\Request\Api\v1\Live\RoomListRequest;
  33. use App\Request\Api\v1\Live\ShutUpListRequest;
  34. use App\Request\Api\v1\Live\ShutUpRequest;
  35. use App\Request\Api\v1\Live\SuggestRequest;
  36. use App\Request\Api\v1\Live\TalkSetRequest;
  37. use App\Request\Api\v1\Live\UserInfoRequest;
  38. use App\Request\Api\v1\Live\UserRemoveRequest;
  39. use App\Service\QueueService;
  40. use App\Utils\AppResult;
  41. use App\Utils\Control\AuthUser;
  42. use App\Utils\LogUtil;
  43. use App\Utils\RedisUtil;
  44. use Hyperf\DbConnection\Db;
  45. use Hyperf\Di\Annotation\Inject;
  46. use function Hyperf\Stringable\str;
  47. /**
  48. * Demo
  49. * 示例
  50. */
  51. class LiveController extends AbstractController
  52. {
  53. // 日志模块名称
  54. const LOG_MODULE = 'v1/LiveController';
  55. #[Inject]
  56. protected QueueService $service;
  57. // 直播间列表
  58. public function room_list(RoomListRequest $request)
  59. {
  60. $params = $request->validated();
  61. $user = AuthUser::getInstance()->get();
  62. $model = new LiveRoomModel();
  63. $list = $model->getList(
  64. params : $params,
  65. orderBy: ['weigh' => 'desc'],
  66. select : ['id', 'user_id', 'room_no', 'name', 'logo', 'image', 'session', 'status', 'create_time'],
  67. with : [
  68. 'log' => function ($query) {
  69. $query->select(['id', 'session', 'like', 'ccu', 'goods_sales', 'share_num', 'follow_num', 'duration', 'open_time', 'close_time']);
  70. }
  71. ]
  72. );
  73. $im = new TencentIm();
  74. foreach ($list as $key => $val) {
  75. $list[$key]['push_url'] = $im->getLivePushUrl($val['room_no']);
  76. $list[$key]['play_url'] = $im->getLivePlayUrl($val['room_no']);
  77. }
  78. return AppResult::success('success', $list);
  79. }
  80. // 房间详情
  81. public function room_detail(RoomDetailRequest $request)
  82. {
  83. $params = $request->validated();
  84. $user = AuthUser::getInstance()->get();
  85. $model = new LiveRoomModel();
  86. $info = $model->getDetail(
  87. params: $params,
  88. select: ['id', 'user_id', 'room_no', 'name', 'logo', 'image', 'session', 'follow_num', 'status', 'create_time'],
  89. with : [
  90. 'log' => function ($query) {
  91. $query->select(['id', 'session', 'like', 'ccu', 'goods_sales', 'share_num', 'follow_num', 'duration', 'open_time', 'close_time']);
  92. },
  93. 'user' => function ($query) {
  94. $query->select(['id', 'nickname', 'avatar', 'gender']);
  95. }
  96. ]
  97. );
  98. $info['user']['chat_id'] = im_prefix($info['user']['id']);
  99. $info['user']['avatar'] = cdn_url($info['user']['avatar']);
  100. // 判断用户身份
  101. $info['role'] = 3;// 观众
  102. if ($user['id'] == $info['user_id']) {
  103. $info['role'] = 1;// 房主
  104. } else {
  105. $model = new LiveRoomAdminModel();
  106. $admin = $model->getAdmin($user['id'],$params['room_no']);
  107. if (!empty($admin)) {
  108. $info['role'] = 2;// 场控
  109. }
  110. }
  111. // 如果不是自己的直播间,需要判断关注按钮
  112. $info['is_follow'] = 2;//状态:0=未关注,1=关注,2=主播自己
  113. if ($info['user_id'] != $user['id']) {
  114. $info['is_follow'] = 0;
  115. // 查询是否关注对方
  116. if (LiveRoomFollowModel::query()->where(['room_id' => $info['id'], 'user_id' => $user['id'], 'status' => 1])->exists()) {
  117. $info['is_follow'] = 1; //状态:0=关注,1=互为关注
  118. }
  119. }
  120. // 配置直播推流连接
  121. $im = new TencentIm();
  122. $info['push_url'] = $im->getLivePushUrl($info['room_no']);
  123. $info['play_url'] = $im->getLivePlayUrl($info['room_no']);
  124. return AppResult::success('获取成功', $info);
  125. }
  126. // 创建直播间
  127. public function room_add(RoomAddRequest $request)
  128. {
  129. $params = $request->validated();
  130. $user = AuthUser::getInstance()->get();
  131. // 校验开播资格
  132. if ($user['group_id'] !== 2) {
  133. return AppResult::error('抱歉,您没有权限');
  134. }
  135. Db::beginTransaction();
  136. try {
  137. // 创建直播房间
  138. $model = new LiveRoomModel();
  139. if (!$model->createRoom($user, (string)$params['name'], (string)($params['image'] ?? ''))) {
  140. Db::rollBack();
  141. return AppResult::error($model->getMessage() ?? '操作失败');
  142. }
  143. $data = $model->getData();
  144. $room_status = $data['status'] ?? 0;// 直播房间状态
  145. RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $data['room_no'])->del();
  146. // 如果没开播
  147. if ($room_status == 0) {
  148. // IM直播创建房间 && 创建群组
  149. $im = new TencentIm();
  150. $im->create_group(im_prefix($user['id']), $data['room_no'], (string)$data['room_name'], notification: site('live_notice') ?? '');
  151. }
  152. Db::commit();
  153. } catch (\Exception $e) {
  154. Db::rollBack();
  155. return AppResult::error($e->getMessage() ?? '操作失败');
  156. }
  157. // 配置直播推流连接
  158. $im = new TencentIm();
  159. // 设置群属性
  160. $counter[] = [
  161. 'key' => 'talk_status',
  162. 'value' => (string)$data['talk_status']
  163. ];
  164. $counter[] = [
  165. 'key' => 'top_avatar',
  166. 'value' => ''
  167. ];
  168. $counter[] = [
  169. 'key' => 'like',
  170. 'value' => '0'
  171. ];
  172. $counter[] = [
  173. 'key' => 'online_member_num',
  174. 'value' => '0'
  175. ];
  176. $im->modify_group_attr($data['room_no'], $counter);
  177. return AppResult::success('创建成功', [
  178. 'room_no' => $data['room_no'],
  179. 'room_name' => $data['room_name'],
  180. 'push_url' => $im->getLivePushUrl($data['room_no']),
  181. 'play_url' => $im->getLivePlayUrl($data['room_no']),
  182. ]);
  183. }
  184. // 关闭直播间
  185. public function room_close(RoomCloseRequest $request)
  186. {
  187. $params = $request->validated();
  188. $user = AuthUser::getInstance()->get();
  189. $params['user_id'] = $user['id'];
  190. $model = new LiveRoomModel();
  191. $room = $model->getDetail(params: $params,with: ['log']);
  192. if (!$room) {
  193. return AppResult::error('直播间不存在或已关闭');
  194. }
  195. Db::beginTransaction();
  196. try {
  197. // 创建直播房间
  198. $model = new LiveRoomModel();
  199. if (!$model->closeRoom($room['id'])) {
  200. Db::rollBack();
  201. return AppResult::error($model->getMessage() ?? '操作失败');
  202. }
  203. LiveRoomGoodsModel::query()->where('room_no',$room['room_no'])->where('is_top',1)->update(['is_top' => 0]);
  204. // 腾讯直播创建房间 && 创建群组
  205. $tanIm = new TencentIm();
  206. $tanIm->destroy_group($room['room_no']);
  207. Db::commit();
  208. } catch (\Exception $e) {
  209. Db::rollBack();
  210. return AppResult::error($e->getMessage() ?? '操作失败');
  211. }
  212. $room['log']['close_time'] = time();
  213. $room['log']['duration'] = time() - $room['log']['open_time'];
  214. return AppResult::success('关闭成功',$room['log']);
  215. }
  216. // 进入房间
  217. public function room_join(RoomJoinRequest $request)
  218. {
  219. $params = $request->validated();
  220. $user = AuthUser::getInstance()->get();
  221. $model = new LiveRoomModel();
  222. $info = $model->getDetail(params: $params);
  223. if (!$info) {
  224. return AppResult::error('直播间已关闭');
  225. }
  226. if (RedisUtil::getInstance(RedisKeyEnum::ROOM_BLACK,$info['room_no'],im_prefix($user['id']))->get()){
  227. return AppResult::error('您被改直播间拉入黑名单,暂时无法进入');
  228. }
  229. // 处理直播间在线人数
  230. // 判断当前用户是否存在在直播间通过切换过来的
  231. $ROOM_USER_IN = RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_IN)->hGet((string)$user['id']);
  232. if (!$ROOM_USER_IN || $ROOM_USER_IN != $info['id']) {
  233. if ($ROOM_USER_IN != $info['id']) {
  234. // 从原房间内移除此用户
  235. RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $info['room_no'])->zRem($user['id']);
  236. // 扣除在线用户在房间情况
  237. RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_IN)->hDel((string)$user['id']);
  238. }
  239. // 记录在线用户在房间情况
  240. RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_IN)->hSet((string)$user['id'], $info['room_no']);
  241. $value = LiveRoomLogLikeModel::query()->where('user_id', $user['id'])->where('room_no', $info['room_no'])->value('like');
  242. RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $info['room_no'])->zAdd((int)($value ?: 0), $user['id']);
  243. }
  244. // 直播间观看人数加一
  245. $this->service->liveRoomDataPush(['session' => $info['session'], 'ccu' => 1]);
  246. return AppResult::success('进入成功');
  247. }
  248. // 离开房间
  249. public function room_leave(RoomJoinRequest $request)
  250. {
  251. $params = $request->validated();
  252. $user = AuthUser::getInstance()->get();
  253. $model = new LiveRoomModel();
  254. $info = $model->getDetail(params: $params);
  255. if (!$info) {
  256. return AppResult::error('直播间已关闭');
  257. }
  258. // 从原房间内移除此用户
  259. RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $info['room_no'])->zRem($user['id']);
  260. // 扣除在线用户在房间情况
  261. RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_IN)->hDel((string)$user['id']);
  262. if ($info) {
  263. $this->service->liveRoomDataPush(['session' => $info['session'], 'ccu' => -1]);
  264. if ($info['user_id'] == $user['id']) {
  265. // 如果是主播,则关闭直播间
  266. $model = new LiveRoomModel();
  267. $model->closeRoom($info['id']);
  268. // 腾讯直播解散群组
  269. $im = new TencentIm();
  270. $im->destroy_group($info['room_no']);
  271. }
  272. }
  273. return AppResult::success('已离开直播间');
  274. }
  275. // 房管列表
  276. public function admin_list(AdminListRequest $request)
  277. {
  278. $params = $request->validated();
  279. $model = new LiveRoomAdminModel();
  280. $model->setIsStatusSearchValue();
  281. $list = $model->getList(
  282. params: $params,
  283. with : [
  284. 'user' => function ($query) {
  285. $query->select(['id', 'nickname', 'avatar']);
  286. }
  287. ]
  288. );
  289. foreach ($list as $key => $val) {
  290. $list[$key]['user']['avatar'] = cdn_url($val['user']['avatar']);
  291. $list[$key]['user']['chat_id'] = im_prefix($val['user']['id']);
  292. }
  293. return AppResult::success('获取成功', $list);
  294. }
  295. // 设置超管
  296. public function admin_add(AdminSetRequest $request)
  297. {
  298. $params = $request->validated();
  299. $user = AuthUser::getInstance()->get();
  300. $model = new LiveRoomAdminModel();
  301. if (!$model->add($user['id'], (string)$params['room_no'], im_un_prefix($params['chat_id']))) {
  302. return AppResult::error($model->getMessage() ?? '操作失败');
  303. }
  304. return AppResult::success('设置成功');
  305. }
  306. // 删除超管
  307. public function admin_del(AdminSetRequest $request)
  308. {
  309. $params = $request->validated();
  310. $user = AuthUser::getInstance()->get();
  311. $model = new LiveRoomAdminModel();
  312. if (!$model->del($user['id'], (string)$params['room_no'], im_un_prefix($params['chat_id']))) {
  313. return AppResult::error($model->getMessage() ?? '操作失败');
  314. }
  315. return AppResult::success('删除成功');
  316. }
  317. // 房间观众信息
  318. public function user_info(UserInfoRequest $request)
  319. {
  320. $params = $request->validated();
  321. $user = AuthUser::getInstance()->get();
  322. $model = new LiveRoomModel();
  323. if (!$room = $model->getDetail(params: ['room_no' => $params['room_no']])) {
  324. return AppResult::error('直播间已关闭');
  325. }
  326. $userInfo = UserModel::query()->where('id',im_un_prefix($params['chat_id']))->where('status',1)->first();
  327. if (!$userInfo){
  328. return AppResult::error('用户不存在');
  329. }
  330. // 判断当前用户身份
  331. $user_role = 3;// 观众
  332. if ($user['id'] == $room['user_id']) {
  333. $user_role = 1;// 房主
  334. } else {
  335. $model = new LiveRoomAdminModel();
  336. $admin = $model->getAdmin($user['id'],$params['room_no']);
  337. if (!empty($admin)) {
  338. $user_role = 2;// 场控
  339. }
  340. }
  341. // 判断查询的用户身份
  342. $info_role = 3;// 观众
  343. if ($userInfo->id == $room['user_id']) {
  344. $info_role = 1;// 房主
  345. } else {
  346. $model = new LiveRoomAdminModel();
  347. $admin = $model->getAdmin($userInfo->id,$params['room_no']);
  348. if (!empty($admin)) {
  349. $info_role = 2;// 场控
  350. }
  351. }
  352. return AppResult::success('操作成功',[
  353. 'info' => [
  354. 'id' => $userInfo->id,
  355. 'chat_id' => $params['chat_id'],
  356. 'nickname' => $userInfo->nickname,
  357. 'avatar' => cdn_url($userInfo->avatar),
  358. 'role' => $info_role,
  359. 'is_shut_up' => RedisUtil::getInstance(RedisKeyEnum::ROOM_SHUT_UP,$params['room_no'],$params['chat_id'])->get() ? 1 : 0,
  360. 'is_black' => RedisUtil::getInstance(RedisKeyEnum::ROOM_BLACK,$params['room_no'],$params['chat_id'])->get() ? 1 : 0,
  361. ],
  362. 'me' => [
  363. 'role' => $user_role
  364. ]
  365. ]);
  366. }
  367. // 移除房间观众
  368. public function user_remove(UserRemoveRequest $request)
  369. {
  370. $params = $request->validated();
  371. $user = AuthUser::getInstance()->get();
  372. if ($user['id'] == im_un_prefix($params['chat_id'])) {
  373. return AppResult::error('无法对自己操作');
  374. }
  375. $model = new LiveRoomModel();
  376. if (!$room = $model->getDetail(params: ['room_no' => $params['room_no']])) {
  377. return AppResult::error('直播间已关闭');
  378. }
  379. if ($room['user_id'] != $user['id']) {
  380. $model = new LiveRoomAdminModel();
  381. if (!$model->getAdmin($user['id'], $params['room_no'])) {
  382. return AppResult::error('未拥有此权限');
  383. }
  384. }
  385. // 腾讯直播创建房间 && 创建群组
  386. $im = new TencentIm();
  387. if (!$im->delete_group_member($params['room_no'], im_prefix($params['chat_id']))) {
  388. return AppResult::error($im->getMessage() ?? '操作失败');
  389. }
  390. // 移除观众列表
  391. RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $room['room_no'])->zRem(im_un_prefix($params['chat_id']));
  392. // 直播间人数减一
  393. $this->service->liveRoomDataPush(['session' => $room['session'], 'ccu' => -1]);
  394. return AppResult::success('操作成功');
  395. }
  396. // 禁言列表
  397. public function shut_up_list(ShutUpListRequest $request)
  398. {
  399. $params = $request->validated();
  400. $user = AuthUser::getInstance()->get();
  401. $model = new LiveRoomModel();
  402. if (!$room = $model->getDetail(params: ['room_no' => $params['room_no']])) {
  403. return AppResult::error('直播间已关闭');
  404. }
  405. if ($room['user_id'] != $user['id']) {
  406. $model = new LiveRoomAdminModel();
  407. if (!$model->getAdmin($user['id'], $params['room_no'])) {
  408. return AppResult::error('未拥有此权限');
  409. }
  410. }
  411. $im = new TencentIm();
  412. if (!$im->get_group_muted_account($params['room_no'])) {
  413. return AppResult::error($im->getMessage() ?? '操作失败');
  414. }
  415. $data = $im->getData();
  416. $ids = [];
  417. foreach ($data['MutedAccountList'] as $item) {
  418. $ids[] = im_un_prefix($item['Member_Account']);
  419. }
  420. $model = new UserModel();
  421. $list = $model->getList(params: ['ids' => $ids], select: ['id', 'nickname', 'avatar']);
  422. foreach ($list as $key => $val) {
  423. $list[$key]['avatar'] = cdn_url($val['avatar']);
  424. $list[$key]['chat_id'] = im_prefix($val['id']);
  425. }
  426. return AppResult::success('操作成功', $list);
  427. }
  428. // 禁言
  429. public function shut_up(ShutUpRequest $request)
  430. {
  431. $params = $request->validated();
  432. $user = AuthUser::getInstance()->get();
  433. if ($user['id'] == im_un_prefix($params['chat_id'])) {
  434. return AppResult::error('无法对自己操作');
  435. }
  436. $model = new LiveRoomModel();
  437. if (!$model->shut_up($user['id'], (string)$params['room_no'], im_un_prefix($params['chat_id']), (int)($params['time'] ?? 86400))) {
  438. return AppResult::error($model->getMessage() ?? '操作失败');
  439. }
  440. return AppResult::success('操作成功');
  441. }
  442. // 黑名单列表
  443. public function black_list(ShutUpListRequest $request)
  444. {
  445. $params = $request->validated();
  446. $user = AuthUser::getInstance()->get();
  447. $model = new LiveRoomModel();
  448. if (!$room = $model->getDetail(params: ['room_no' => $params['room_no']])) {
  449. return AppResult::error('直播间已关闭');
  450. }
  451. if ($room['user_id'] != $user['id']) {
  452. $model = new LiveRoomAdminModel();
  453. if (!$model->getAdmin($user['id'], $params['room_no'])) {
  454. return AppResult::error('未拥有此权限');
  455. }
  456. }
  457. // $im = new TencentIm();
  458. // if (!$im->get_group_ban_member($params['room_no'])) {
  459. // return AppResult::error($im->getMessage() ?? '操作失败');
  460. // }
  461. // $data = $im->getData();
  462. // $ids = [];
  463. // foreach ($data['BannedAccountList'] as $item) {
  464. // $ids[] = im_un_prefix($item['Member_Account']);
  465. // }
  466. $ids = LiveRoomBlackModel::query()->where('room_no',$params['room_no'])->where('status',1)->where('end_time','>',time())->pluck('user_id')->toArray();
  467. $model = new UserModel();
  468. $list = $model->getList(params: ['ids' => $ids], select: ['id', 'nickname', 'avatar']);
  469. foreach ($list as $key => $val) {
  470. $list[$key]['avatar'] = cdn_url($val['avatar']);
  471. $list[$key]['chat_id'] = im_prefix($val['id']);
  472. }
  473. return AppResult::success('操作成功', $list);
  474. }
  475. // 封禁 黑名单
  476. public function black_add(BlackAddRequest $request)
  477. {
  478. $params = $request->validated();
  479. $user = AuthUser::getInstance()->get();
  480. if ($user['id'] == im_un_prefix($params['chat_id'])) {
  481. return AppResult::error('无法对自己操作');
  482. }
  483. $model = new LiveRoomModel();
  484. if (!$model->black_add($user['id'], (string)$params['room_no'], im_un_prefix($params['chat_id']), (int)($params['time'] ?? 86400))) {
  485. return AppResult::error($model->getMessage() ?? '操作失败');
  486. }
  487. return AppResult::success('操作成功');
  488. }
  489. // 移除 封禁 黑名单
  490. public function black_remove(BlackRemoveRequest $request)
  491. {
  492. $params = $request->validated();
  493. $user = AuthUser::getInstance()->get();
  494. if ($user['id'] == im_un_prefix($params['chat_id'])) {
  495. return AppResult::error('无法对自己操作');
  496. }
  497. $model = new LiveRoomModel();
  498. if (!$model->black_remove($user['id'], (string)$params['room_no'], im_un_prefix($params['chat_id']))) {
  499. return AppResult::error($model->getMessage() ?? '操作失败');
  500. }
  501. return AppResult::success('操作成功');
  502. }
  503. // 直播间观众列表(已关注的)
  504. public function audience(AudienceRequest $request)
  505. {
  506. $params = $request->validated();// 获取校验参数结果
  507. $model = new LiveRoomFollowModel();
  508. $model->setIsStatusSearchValue();
  509. $list = $model->getList(
  510. params : $params,
  511. orderBy: ['id' => 'desc'],
  512. with : [
  513. 'user' => function ($with) use ($params) {
  514. $with->select(['id', 'nickname', 'avatar']);
  515. }
  516. ]
  517. );
  518. // 查询当前直播间管理员id
  519. $adminIds = LiveRoomAdminModel::query()->where('room_no', $params['room_no'])->where('status', 1)->pluck('admin_id')->toArray();
  520. foreach ($list as $key => $val) {
  521. $list[$key]['is_admin'] = in_array($val['user_id'], $adminIds) ? 1 : 0;
  522. $list[$key]['user'] = [
  523. 'chat_id' => im_prefix($val['user']['id']),
  524. 'avatar' => cdn_url($val['user']['avatar']),
  525. 'nickname' => $val['user']['nickname'],
  526. ];
  527. }
  528. return AppResult::success('获取成功', $list);
  529. }
  530. // 直播间观众榜单
  531. public function top(LikeRequest $request)
  532. {
  533. $params = $request->validated();// 获取校验参数结果
  534. $user = AuthUser::getInstance()->get();
  535. $model = new LiveRoomModel();
  536. $room = $model->getDetail(params: $params);
  537. if (!$room) {
  538. return AppResult::error('直播间异常');
  539. }
  540. $model = new LiveRoomLogLikeModel();
  541. $list = $model->getTopList($room['room_no'], $room['user_id']);
  542. $meRank = RedisUtil::getInstance(RedisKeyEnum::ROOM_USER_LIST, $room['room_no'])->zRevRank($user['id']);
  543. return AppResult::success('success', [
  544. 'me' => [
  545. 'id' => $user['id'],
  546. 'chat_id' => im_prefix($user['id']),
  547. 'nickname' => $user['nickname'],
  548. 'avatar' => cdn_url($user['avatar']),
  549. 'rank' => $meRank >= 0 ? $meRank + 1 : ''
  550. ],
  551. 'list' => $list
  552. ]);
  553. }
  554. // 点赞
  555. public function like(LikeRequest $request)
  556. {
  557. $params = $request->validated();// 获取校验参数结果
  558. $user = AuthUser::getInstance()->get();
  559. $model = new LiveRoomModel();
  560. $room = $model->getDetail(params: $params);
  561. if (!$room) {
  562. return AppResult::error('直播间异常');
  563. }
  564. // 不可以赠送给自己
  565. if ($user['id'] == $room['user_id']) {
  566. return AppResult::error('不可以给自己点赞');
  567. }
  568. // 加入点赞队列
  569. $this->service->liveRoomDataPush([
  570. 'user_id' => $user['id'],
  571. 'room_id' => $room['id'],
  572. 'room_no' => $room['room_no'],
  573. 'session' => $room['session'],
  574. 'like' => 1
  575. ]);
  576. return AppResult::success('点赞成功');
  577. }
  578. // 关注 取消关注
  579. public function follow(FollowRequest $request)
  580. {
  581. $params = $request->validated();// 获取校验参数结果
  582. $user = AuthUser::getInstance()->get();
  583. $model = new LiveRoomModel();
  584. $room = $model->getDetail(params: $params);
  585. if (!$room) {
  586. return AppResult::error('直播间异常');
  587. }
  588. // 不可以赠送给自己
  589. if ($user['id'] == $room['user_id']) {
  590. return AppResult::error('不可以关注自己');
  591. }
  592. $model = new LiveRoomFollowModel();
  593. if ($params['status'] == 1) {
  594. if (!$model->follow($user['id'], $room['id'], $room['room_no'], $room['session'])) {
  595. return AppResult::error($model->getMessage() ?? '关注失败');
  596. }
  597. } else {
  598. if (!$model->cancelFollow($user['id'], $room['id'], $room['room_no'])) {
  599. return AppResult::error($model->getMessage() ?? '取关失败');
  600. }
  601. }
  602. return AppResult::success($model->getMessage() ?? '操作成功');
  603. }
  604. // 发言权限
  605. public function talk_set(TalkSetRequest $request)
  606. {
  607. $params = $request->validated();// 获取校验参数结果
  608. $user = AuthUser::getInstance()->get();
  609. $model = new LiveRoomModel();
  610. $room = $model->getDetail(params: $params);
  611. if (!$room) {
  612. return AppResult::error('直播间异常');
  613. }
  614. // 不可以赠送给自己
  615. if ($user['id'] != $room['user_id']) {
  616. $model = new LiveRoomAdminModel();
  617. if (!$model->getAdmin($user['id'], $room['room_no'])) {
  618. return AppResult::error('未拥有此权限');
  619. }
  620. }
  621. $model = new LiveRoomModel();
  622. if (!$model->query()->where('id', $room['id'])->update(['talk_status' => $params['talk_status'], 'update_time' => time()])) {
  623. return AppResult::error('操作失败');
  624. }
  625. // 设置群属性
  626. $counter[] = [
  627. 'key' => 'talk_status',
  628. 'value' => (string)$params['talk_status']
  629. ];
  630. $im = new TencentIm();
  631. if (!$im->modify_group_attr($room['room_no'], $counter)) {
  632. return AppResult::error($im->getMessage() ?? '操作成功', $im->getData());
  633. }
  634. return AppResult::success('操作成功');
  635. }
  636. // 卡顿上报
  637. public function suggest(SuggestRequest $request)
  638. {
  639. $params = $request->validated();// 获取校验参数结果
  640. $user = AuthUser::getInstance()->get();
  641. $model = new LiveRoomModel();
  642. $room = $model->getDetail(params: $params);
  643. if (!$room) {
  644. return AppResult::error('直播间异常');
  645. }
  646. $params['room_id'] = $room['id'];
  647. $model = new LiveSuggestModel();
  648. if (!$model->add($user['id'], $params)) {
  649. return AppResult::error('操作失败');
  650. }
  651. return AppResult::success('上报成功');
  652. }
  653. // 举报
  654. public function report(ReportRequest $request)
  655. {
  656. $params = $request->validated();// 获取校验参数结果
  657. $user = AuthUser::getInstance()->get();
  658. $model = new LiveRoomModel();
  659. $room = $model->getDetail(params: $params);
  660. if (!$room) {
  661. return AppResult::error('直播间异常');
  662. }
  663. $to_user = (new UserModel())->getDetail(params: ['id' => im_un_prefix($params['to_chat_id'])]);
  664. if (!$to_user) {
  665. return AppResult::error('举报用户不存在');
  666. }
  667. $params['room_id'] = $room['id'];
  668. $params['to_user_id'] = im_un_prefix($params['to_chat_id']);
  669. unset($params['to_chat_id']);
  670. $model = new LiveReportModel();
  671. if (!$model->add($user['id'], $params)) {
  672. return AppResult::error('操作失败');
  673. }
  674. return AppResult::success('举报成功');
  675. }
  676. // 敏感词
  677. public function keyword_filter_list(KeywordFilterListRequest $request)
  678. {
  679. $params = $request->validated();// 获取校验参数结果
  680. $user = AuthUser::getInstance()->get();
  681. $model = new LiveRoomModel();
  682. $room = $model->getDetail(params: $params);
  683. if (!$room) {
  684. return AppResult::error('直播间异常');
  685. }
  686. $model = new LiveRoomKeywordModel();
  687. return AppResult::success('获取成功',$model->getList($params));
  688. }
  689. // 敏感词
  690. public function keyword_filter_add(KeywordFilterAddRequest $request)
  691. {
  692. $params = $request->validated();// 获取校验参数结果
  693. $user = AuthUser::getInstance()->get();
  694. $model = new LiveRoomModel();
  695. $room = $model->getDetail(params: $params);
  696. if (!$room) {
  697. return AppResult::error('直播间异常');
  698. }
  699. if ($room['user_id'] != $user['id']) {
  700. $model = new LiveRoomAdminModel();
  701. if (!$model->getAdmin($user['id'], $params['room_no'])) {
  702. return AppResult::error('未拥有此权限');
  703. }
  704. }
  705. $model = new LiveRoomKeywordModel();
  706. if (!$model->add($user['id'], $room['id'], $room['room_no'], $params['keyword'])) {
  707. return AppResult::error($model->getMessage() ?? '操作失败');
  708. }
  709. return AppResult::success($model->getMessage() ?? '操作成功');
  710. }
  711. // 敏感词 删除
  712. public function keyword_filter_del(KeywordFilterDelRequest $request)
  713. {
  714. $params = $request->validated();// 获取校验参数结果
  715. $user = AuthUser::getInstance()->get();
  716. $model = new LiveRoomModel();
  717. $room = $model->getDetail(params: $params);
  718. if (!$room) {
  719. return AppResult::error('直播间异常');
  720. }
  721. if ($room['user_id'] != $user['id']) {
  722. $model = new LiveRoomAdminModel();
  723. if (!$model->getAdmin($user['id'], $params['room_no'])) {
  724. return AppResult::error('未拥有此权限');
  725. }
  726. }
  727. $model = new LiveRoomKeywordModel();
  728. if (!$model->del($params['keyword_id'])) {
  729. return AppResult::error($model->getMessage() ?? '操作失败');
  730. }
  731. return AppResult::success($model->getMessage() ?? '操作成功');
  732. }
  733. }