TencentImGroupService.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. <?php
  2. namespace App\Services;
  3. use App\Exceptions\TencentImException;
  4. use App\Models\ChatTeam;
  5. use App\Models\TencentImGroup;
  6. use App\Models\User;
  7. use App\Traits\TencentIm;
  8. class TencentImGroupService
  9. {
  10. use TencentIm;
  11. const TENCENT_REST_APIS = [
  12. 'get_appid_group_list' => 'v4/group_open_http_svc/get_appid_group_list',//获取 App 中的所有群组
  13. 'create_group' => 'v4/group_open_http_svc/create_group',//创建群组
  14. 'get_group_info' => 'v4/group_open_http_svc/get_group_info',//获取群详细资料
  15. 'get_group_member_info' => 'v4/group_open_http_svc/get_group_member_info',//获取群成员详细资料
  16. 'modify_group_base_info' => 'v4/group_open_http_svc/modify_group_base_info',//修改群基础资料
  17. 'add_group_member' => 'v4/group_open_http_svc/add_group_member',//增加群成员
  18. 'delete_group_member' => 'v4/group_open_http_svc/delete_group_member',//删除群成员
  19. 'modify_group_member_info' => 'v4/group_open_http_svc/modify_group_member_info',//修改群成员资料
  20. 'destroy_group' => 'v4/group_open_http_svc/destroy_group',//解散群组
  21. 'get_joined_group_list' => 'v4/group_open_http_svc/get_joined_group_list',//获取用户所加入的群组
  22. 'get_role_in_group' => 'v4/group_open_http_svc/get_joined_group_list',//查询用户在群组中的身份
  23. 'forbid_send_msg' => 'v4/group_open_http_svc/forbid_send_msg',//批量禁言和取消禁言
  24. 'get_group_shutted_uin' => 'v4/group_open_http_svc/get_group_shutted_uin',//获取被禁言群成员列表
  25. 'send_group_msg' => 'v4/group_open_http_svc/send_group_msg',//在群组中发送普通消息
  26. 'send_group_system_notification' => 'v4/group_open_http_svc/send_group_system_notification',//在群组中发送系统通知
  27. 'group_msg_recall' => 'v4/group_open_http_svc/group_msg_recall',//撤回群消息
  28. 'change_group_owner' => 'v4/group_open_http_svc/change_group_owner',//转让群主
  29. 'import_group' => 'v4/group_open_http_svc/import_group',//导入群基础资料
  30. 'import_group_msg' => 'v4/group_open_http_svc/import_group_msg',//导入群消息
  31. 'import_group_member' => 'v4/group_open_http_svc/import_group_member',//导入群成员
  32. 'set_unread_msg_num' => 'v4/group_open_http_svc/set_unread_msg_num',//设置成员未读消息计数
  33. 'delete_group_msg_by_sender' => 'v4/group_open_http_svc/delete_group_msg_by_sender',//删除指定用户发送的消息
  34. 'group_msg_get_simple' => 'v4/group_open_http_svc/group_msg_get_simple',//拉取群历史消息
  35. 'get_online_member_num' => 'v4/group_open_http_svc/get_online_member_num',//获取直播群在线人数
  36. 'createGroup' => 'v4/group_open_http_svc/create_group', //创建群组 支持同时创建多个
  37. 'getGroupList' => 'v4/group_open_http_svc/get_appid_group_list', //获取app中所有群组
  38. ];
  39. public static $instance;
  40. //获取实例
  41. public static function getInstance()
  42. {
  43. if (empty(self::$instance)) {
  44. self::$instance = new self();
  45. }
  46. return self::$instance;
  47. }
  48. /**
  49. * 获取所有 APP 中的群组
  50. * @param int $limit
  51. * @param int $next
  52. * @return \Psr\Http\Message\ResponseInterface
  53. * @throws TencentImException
  54. * @throws \GuzzleHttp\Exception\GuzzleException
  55. */
  56. public function getGroupList(int $limit = 10000, int $next = 0)
  57. {
  58. $this->restApiName = self::TENCENT_REST_APIS['getGroupList'];
  59. $baseApiHost = $this->getTencentImRestApiBaseHost();
  60. $params = [
  61. 'Limit' => $limit,
  62. 'Next' => $next
  63. ];
  64. $apiResult = $this->requestApi($baseApiHost, $params);
  65. self::verifyApiResult($apiResult);
  66. return $apiResult;
  67. }
  68. /**
  69. * @param array $createData
  70. * @return \Psr\Http\Message\ResponseInterface
  71. * @throws TencentImException
  72. * @throws \GuzzleHttp\Exception\GuzzleException
  73. * 创建群聊
  74. */
  75. public function createGroup(array $createData)
  76. {
  77. $this->restApiName = self::TENCENT_REST_APIS['createGroup'];
  78. $baseApiHost = $this->getTencentImRestApiBaseHost();
  79. //组装群成员
  80. $member_list = array();
  81. foreach ($createData['member_list'] as $k => $v) {
  82. $member_list [] = ['Member_Account' => $v['tencent_im_user_id']];
  83. }
  84. $createData['group_name'] = mb_substr($createData['group_name'], 0, 30);
  85. //TODO 做单点登录,避免并发
  86. $params = [
  87. //TODO 新建群默认群主为APP管理员
  88. 'Owner_Account' => $createData['Owner_Account'],//群主账户
  89. 'Type' => 'Public',
  90. 'Name' => $createData['group_name'], //群名称
  91. 'FaceUrl' => $createData['avatar'], //群头像
  92. "MemberList" => $member_list,
  93. ];
  94. $apiResult = $this->requestApi($baseApiHost, $params);
  95. self::verifyApiResult($apiResult);
  96. return $apiResult;
  97. }
  98. /**
  99. * 获取群详细资料
  100. * @param $group_id
  101. * @return \Psr\Http\Message\ResponseInterface
  102. * @throws TencentImException
  103. * @throws \GuzzleHttp\Exception\GuzzleException
  104. */
  105. public function getGroupInfo($group_id)
  106. {
  107. $this->restApiName = self::TENCENT_REST_APIS['get_group_info'];
  108. $baseApiHost = $this->getTencentImRestApiBaseHost();
  109. $params = [
  110. 'GroupIdList' => [$group_id],
  111. ];
  112. $apiResult = $this->requestApi($baseApiHost, $params);
  113. self::verifyApiResult($apiResult);
  114. return $apiResult;
  115. }
  116. /**
  117. * 获取群成员详细资料
  118. * @param $group_id
  119. * @return \Psr\Http\Message\ResponseInterface
  120. * @throws TencentImException
  121. * @throws \GuzzleHttp\Exception\GuzzleException
  122. */
  123. public function getGroupMemberInfo($group_id)
  124. {
  125. $this->restApiName = self::TENCENT_REST_APIS['get_group_member_info'];
  126. $baseApiHost = $this->getTencentImRestApiBaseHost();
  127. $params = [
  128. 'GroupId' => $group_id,
  129. ];
  130. $apiResult = $this->requestApi($baseApiHost, $params);
  131. self::verifyApiResult($apiResult);
  132. return $apiResult;
  133. }
  134. /**
  135. * 修改群基础资料
  136. * @param $data
  137. * @return \Psr\Http\Message\ResponseInterface
  138. * @throws TencentImException
  139. * @throws \GuzzleHttp\Exception\GuzzleException
  140. */
  141. public function modifyGroupBaseInfo($data)
  142. {
  143. $this->restApiName = self::TENCENT_REST_APIS['modify_group_base_info'];
  144. $baseApiHost = $this->getTencentImRestApiBaseHost();
  145. $params = array();
  146. $params['GroupId'] = $data['GroupId']; //必须
  147. //群名称
  148. if (isset($data['name']) && !empty($data['name'])) {
  149. $params['Name'] = $data['name'];
  150. }
  151. //群头像
  152. if (isset($data['FaceUrl']) && !empty($data['FaceUrl'])) {
  153. $params['FaceUrl'] = $data['FaceUrl'];
  154. }
  155. //群简介
  156. if (isset($data['Introduction']) && !empty($data['Introduction'])) {
  157. $params['Introduction'] = $data['Introduction'];
  158. }
  159. //群公告
  160. if (isset($data['Notification']) && !empty($data['Notification'])) {
  161. $params['Notification'] = $data['Notification'];
  162. }
  163. //最大群成员数量
  164. if (isset($data['MaxMemberNum']) && !empty($data['MaxMemberNum'])) {
  165. $params['MaxMemberNum'] = $data['MaxMemberNum'];
  166. }
  167. //申请加群方式
  168. if (isset($data['ApplyJoinOption']) && !empty($data['ApplyJoinOption'])) {
  169. $params['ApplyJoinOption'] = $data['ApplyJoinOption'];
  170. }
  171. //设置全员禁言(选填):"On"开启,"Off"关闭
  172. if (isset($data['ShutUpAllMember']) && !empty($data['ShutUpAllMember'])) {
  173. $params['ShutUpAllMember'] = $data['ShutUpAllMember'];
  174. }
  175. $apiResult = $this->requestApi($baseApiHost, $params);
  176. self::verifyApiResult($apiResult);
  177. return $apiResult;
  178. }
  179. /**
  180. * 添加群成员
  181. * @param $group_id
  182. * @return \Psr\Http\Message\ResponseInterface
  183. * @throws TencentImException
  184. * @throws \GuzzleHttp\Exception\GuzzleException
  185. */
  186. public function addGroupMember($data)
  187. {
  188. $this->restApiName = self::TENCENT_REST_APIS['add_group_member'];
  189. $baseApiHost = $this->getTencentImRestApiBaseHost();
  190. //组装群成员
  191. $member_list = array();
  192. foreach ($data['member_list'] as $k => $v) {
  193. $member_list [] = ['Member_Account' => $v['tencent_im_user_id']];
  194. }
  195. $params = [
  196. 'GroupId' => $data['GroupId'],
  197. //"Silence"=> 1, //静默加人
  198. 'MemberList' => $member_list,
  199. ];
  200. $apiResult = $this->requestApi($baseApiHost, $params);
  201. self::verifyApiResult($apiResult);
  202. $this->updateFaceUrl($data['GroupId']);
  203. return $apiResult;
  204. }
  205. /**
  206. * 删除群成员
  207. * @param $data
  208. * @return \Psr\Http\Message\ResponseInterface
  209. * @throws TencentImException
  210. * @throws \GuzzleHttp\Exception\GuzzleException
  211. */
  212. public function deleteGroupMember($data)
  213. {
  214. $this->restApiName = self::TENCENT_REST_APIS['delete_group_member'];
  215. $baseApiHost = $this->getTencentImRestApiBaseHost();
  216. //组装群成员
  217. $member_list = array();
  218. foreach ($data['member_list'] as $k => $v) {
  219. $member_list [] = $v['tencent_im_user_id'];
  220. }
  221. $params = [
  222. 'GroupId' => $data['GroupId'],
  223. 'Silence' => 1, //静默删人
  224. 'MemberToDel_Account' => $member_list,
  225. ];
  226. $apiResult = $this->requestApi($baseApiHost, $params);
  227. self::verifyApiResult($apiResult);
  228. $this->updateFaceUrl($data['GroupId']);
  229. return $apiResult;
  230. }
  231. /**
  232. * 解散群
  233. * @param $data
  234. * @return \Psr\Http\Message\ResponseInterface
  235. * @throws TencentImException
  236. * @throws \GuzzleHttp\Exception\GuzzleException
  237. */
  238. public function destroyGroup($data)
  239. {
  240. $this->restApiName = self::TENCENT_REST_APIS['destroy_group'];
  241. $baseApiHost = $this->getTencentImRestApiBaseHost();
  242. $params = [
  243. 'GroupId' => $data['GroupId']
  244. ];
  245. $apiResult = $this->requestApi($baseApiHost, $params);
  246. self::verifyApiResult($apiResult);
  247. return $apiResult;
  248. }
  249. /**
  250. * 获取用户所加入的群组
  251. * @param $data
  252. * @return \Psr\Http\Message\ResponseInterface
  253. * @throws TencentImException
  254. * @throws \GuzzleHttp\Exception\GuzzleException
  255. */
  256. public function getJoinedGroupList($data)
  257. {
  258. $this->restApiName = self::TENCENT_REST_APIS['get_joined_group_list'];
  259. $baseApiHost = $this->getTencentImRestApiBaseHost();
  260. $params = [
  261. 'Member_Account' => $data['tencent_im_user_id'],
  262. "GroupType" => "Public",
  263. "Limit"=> 10, // 拉取多少个,不填标识拉取全部
  264. //"Offset"=> 0 // 从第多少个开始拉取
  265. ];
  266. $apiResult = $this->requestApi($baseApiHost, $params);
  267. self::verifyApiResult($apiResult);
  268. return $apiResult;
  269. }
  270. /**
  271. * 查询用户在群组中的身份
  272. * @param $data
  273. * @return \Psr\Http\Message\ResponseInterface
  274. * @throws TencentImException
  275. * @throws \GuzzleHttp\Exception\GuzzleException
  276. */
  277. public function getRoleInGroup($data)
  278. {
  279. $this->restApiName = self::TENCENT_REST_APIS['get_role_in_group'];
  280. $baseApiHost = $this->getTencentImRestApiBaseHost();
  281. //组装群成员
  282. $member_list = array();
  283. foreach ($data['member_list'] as $k => $v) {
  284. $member_list [] = $v['tencent_im_user_id'];
  285. }
  286. $params = [
  287. 'GroupId' => $data['GroupId'],
  288. 'User_Account' => $member_list,
  289. ];
  290. $apiResult = $this->requestApi($baseApiHost, $params);
  291. self::verifyApiResult($apiResult);
  292. return $apiResult;
  293. }
  294. /**
  295. * 批量禁言和取消禁言
  296. * @param $data
  297. * @return \Psr\Http\Message\ResponseInterface
  298. * @throws TencentImException
  299. * @throws \GuzzleHttp\Exception\GuzzleException
  300. */
  301. public function forbidSendMsg($data)
  302. {
  303. $this->restApiName = self::TENCENT_REST_APIS['forbid_send_msg'];
  304. $baseApiHost = $this->getTencentImRestApiBaseHost();
  305. //组装群成员
  306. $member_list = array();
  307. foreach ($data['member_list'] as $k => $v) {
  308. $member_list [] = $v['tencent_im_user_id'];
  309. }
  310. $params = [
  311. 'GroupId' => $data['GroupId'],
  312. 'Members_Account' => $member_list,
  313. 'ShutUpTime' => $data['ShutUpTime'], //禁言时间 单位秒 0表示取消禁言
  314. ];
  315. $apiResult = $this->requestApi($baseApiHost, $params);
  316. self::verifyApiResult($apiResult);
  317. return $apiResult;
  318. }
  319. /**
  320. * 获取被禁言群成员列表
  321. * @param $data
  322. * @return \Psr\Http\Message\ResponseInterface
  323. * @throws TencentImException
  324. * @throws \GuzzleHttp\Exception\GuzzleException
  325. */
  326. public function getGroupShuttedUin($data)
  327. {
  328. $this->restApiName = self::TENCENT_REST_APIS['get_group_shutted_uin'];
  329. $baseApiHost = $this->getTencentImRestApiBaseHost();
  330. $params = [
  331. 'GroupId' => $data['GroupId'],
  332. ];
  333. $apiResult = $this->requestApi($baseApiHost, $params);
  334. self::verifyApiResult($apiResult);
  335. return $apiResult;
  336. }
  337. /**
  338. * 发消息
  339. * @param $data
  340. * @return \Psr\Http\Message\ResponseInterface
  341. * @throws TencentImException
  342. * @throws \GuzzleHttp\Exception\GuzzleException
  343. */
  344. public function sendGroupMsg($data)
  345. {
  346. $this->restApiName = self::TENCENT_REST_APIS['send_group_msg'];
  347. $baseApiHost = $this->getTencentImRestApiBaseHost();
  348. $params = [
  349. 'GroupId' => $data['GroupId'],
  350. 'Random' => time(), //无符号32位整数 随机值
  351. 'MsgBody' => $data['MsgBody'],
  352. ];
  353. $apiResult = $this->requestApi($baseApiHost, $params);
  354. self::verifyApiResult($apiResult);
  355. return $apiResult;
  356. }
  357. /**
  358. * 在群组中发送系统通知
  359. * @param $data
  360. * @return \Psr\Http\Message\ResponseInterface
  361. * @throws TencentImException
  362. * @throws \GuzzleHttp\Exception\GuzzleException
  363. */
  364. public function sendGroupSystemNotification($data)
  365. {
  366. $this->restApiName = self::TENCENT_REST_APIS['send_group_system_notification'];
  367. $baseApiHost = $this->getTencentImRestApiBaseHost();
  368. $params = [
  369. 'GroupId' => $data['GroupId'],
  370. 'Content' => $data['content'],
  371. ];
  372. $apiResult = $this->requestApi($baseApiHost, $params);
  373. self::verifyApiResult($apiResult);
  374. return $apiResult;
  375. }
  376. /**
  377. * 转让群主
  378. * @param $data
  379. * @return \Psr\Http\Message\ResponseInterface
  380. * @throws TencentImException
  381. * @throws \GuzzleHttp\Exception\GuzzleException
  382. */
  383. public function changeGroupOwner($data)
  384. {
  385. $this->restApiName = self::TENCENT_REST_APIS['change_group_owner'];
  386. $baseApiHost = $this->getTencentImRestApiBaseHost();
  387. $params = [
  388. 'GroupId' => $data['GroupId'],
  389. 'NewOwner_Account' => $data['tencent_im_user_id'],
  390. ];
  391. $apiResult = $this->requestApi($baseApiHost, $params);
  392. self::verifyApiResult($apiResult);
  393. return $apiResult;
  394. }
  395. /**
  396. * 撤回群消息
  397. * @param $data
  398. * @return \Psr\Http\Message\ResponseInterface
  399. * @throws TencentImException
  400. * @throws \GuzzleHttp\Exception\GuzzleException
  401. */
  402. public function groupMsgRecall($data)
  403. {
  404. $this->restApiName = self::TENCENT_REST_APIS['group_msg_recall'];
  405. $baseApiHost = $this->getTencentImRestApiBaseHost();
  406. $params = [
  407. 'GroupId' => $data['GroupId'],
  408. 'MsgSeqList' => [['MsgSeq' => $data['MsgSeq']]],
  409. ];
  410. $apiResult = $this->requestApi($baseApiHost, $params);
  411. self::verifyApiResult($apiResult);
  412. return $apiResult;
  413. }
  414. /**
  415. * 拉取群历史消息
  416. * @param $data
  417. * @return \Psr\Http\Message\ResponseInterface
  418. * @throws TencentImException
  419. * @throws \GuzzleHttp\Exception\GuzzleException
  420. */
  421. public function groupMsgGetSimple($data)
  422. {
  423. $this->restApiName = self::TENCENT_REST_APIS['group_msg_get_simple'];
  424. $baseApiHost = $this->getTencentImRestApiBaseHost();
  425. $params['GroupId'] = $data['GroupId'];
  426. $params['ReqMsgNumber'] = $data['number']; //拉取的历史消息的条数,目前一次请求最多返回20条历史消息,所以这里最好小于等于20
  427. if (isset($data['seq']) && !empty($data['seq'])) {
  428. $params['ReqMsgSeq'] = $data['seq']; //拉取消息的最大 seq
  429. }
  430. $apiResult = $this->requestApi($baseApiHost, $params);
  431. self::verifyApiResult($apiResult);
  432. return $apiResult;
  433. }
  434. /**
  435. * @param $ids
  436. * @return array
  437. * 获取群聊用户和头像
  438. */
  439. public function getUsersAndAvatar($ids)
  440. {
  441. $users = User::query()->whereIn('id', $ids)
  442. ->select(['id', 'name', 'avatar', 'tencent_im_user_id'])
  443. ->get()->toArray();
  444. $arr_avatar = array();
  445. foreach ($users as $k => $v) {
  446. $arr_avatar[] = $v['avatar'];
  447. }
  448. $file_avatar = '/avatar/' . time() . rand(100, 999) . '.png';
  449. if (GroupAvatar::getGroupAvatar($arr_avatar, true, '.' . $file_avatar)) {
  450. $file_avatar = "https://" . $_SERVER['HTTP_HOST'] . $file_avatar;
  451. }
  452. $data = [
  453. 'users' => $users,
  454. 'file_avatar' => $file_avatar,
  455. ];
  456. return $data;
  457. }
  458. /**
  459. * @param $group_id
  460. * @throws TencentImException
  461. * @throws \GuzzleHttp\Exception\GuzzleException
  462. * 设置群聊头像(成员变动需要更新群头像)
  463. */
  464. public function updateFaceUrl($group_id)
  465. {
  466. $res = $this->getGroupInfo($group_id);
  467. $groupAvatarUrl = $res['GroupInfo'][0]['FaceUrl'];
  468. if ($res['ErrorCode'] == 0 && !empty($res['GroupInfo'])) {
  469. if (!empty($res['GroupInfo'][0]['MemberList'])) {
  470. foreach ($res['GroupInfo'][0]['MemberList'] as &$v) {
  471. $user = User::query()->where(['tencent_im_user_id' => $v['Member_Account']])->select('id', 'name', 'avatar')->first();
  472. $v['user_id'] = $user->id;
  473. $v['name'] = $user->id;
  474. $v['avatar'] = $user->avatar;
  475. }
  476. }
  477. }
  478. $arr_avatar = array_column($res['GroupInfo'][0]['MemberList'], 'avatar');
  479. $fileName = basename($groupAvatarUrl);
  480. $fileName = substr($fileName, 0, strpos($fileName, '.'));
  481. $file_avatar = '/avatar/' . $fileName . '.png';
  482. GroupAvatar::getGroupAvatar($arr_avatar, true, '.' . $file_avatar);
  483. }
  484. }