Im.php 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. <?php
  2. namespace app\enterprise\controller;
  3. use app\BaseController;
  4. use think\facade\Session;
  5. use think\facade\Db;
  6. use app\enterprise\model\{User, Message, GroupUser, Friend,Group,ChatDelog};
  7. use GatewayClient\Gateway;
  8. use Exception;
  9. use League\Flysystem\Util;
  10. use think\facade\Cache;
  11. class Im extends BaseController
  12. {
  13. protected $fileType = ['file', 'image','video','voice','emoji'];
  14. // 获取联系人列表
  15. public function getContacts()
  16. {
  17. $data = User::getUserList([['status', '=', 1], ['user_id', '<>', $this->userInfo['user_id']]], $this->userInfo['user_id']);
  18. $count=Friend::where(['status'=>2,'friend_user_id'=>$this->uid])->count();
  19. $time=Friend::where(['friend_user_id'=>$this->uid,'is_invite'=>1])->order('create_time desc')->value('create_time');
  20. return success('', $data,$count,$time*1000);
  21. }
  22. // 获取聊天列表
  23. public function getChatList()
  24. {
  25. $data = User::getChatList($this->userInfo['user_id']);
  26. $count=Friend::where(['status'=>2,'friend_user_id'=>$this->uid])->count();
  27. $time=Friend::where(['friend_user_id'=>$this->uid,'is_invite'=>1])->order('create_time desc')->value('create_time');
  28. return success('', $data,$count,$time*1000);
  29. }
  30. // 获取好友列表
  31. public function getFriendList()
  32. {
  33. $data = User::getFriendList([['status', '=', 1], ['user_id', '<>', $this->userInfo['user_id']]],$this->userInfo['user_id']);
  34. return success('', $data);
  35. }
  36. // 获取群聊列表
  37. public function getGroupList()
  38. {
  39. $data = User::getGroupList($this->userInfo['user_id']);
  40. return success('', $data);
  41. }
  42. // 获取单个人员的信息
  43. public function getContactInfo(){
  44. $id = $this->request->param('id');
  45. $is_group = is_string($id) ? 1 : 0;
  46. $user=new User;
  47. $data=$user->setContact($id,$is_group);
  48. if(!$data){
  49. return warning($user->getError());
  50. }
  51. return success('',$data);
  52. }
  53. //发送消息
  54. public function sendMessage()
  55. {
  56. $param = $this->request->param();
  57. $param['user_id'] = $this->userInfo['user_id'];
  58. $message=new Message();
  59. $data = $message->sendMessage($param,$this->globalConfig);
  60. if ($data) {
  61. return success('', $data);
  62. } else {
  63. return warning($message->getError());
  64. }
  65. }
  66. //转发消息
  67. public function forwardMessage()
  68. {
  69. $param = $this->request->param();
  70. $userIds=$param['user_ids'] ?? [];
  71. if(!$userIds || count($userIds)>5){
  72. return warning(lang('im.forwardLimit',['count'=>5]));
  73. }
  74. $msg_id=$param['msg_id'] ?? 0;
  75. $message=Message::find($msg_id);
  76. if(!$message){
  77. return warning(lang('im.exist'));
  78. }
  79. $msg=$message->toArray();
  80. $userInfo=$this->userInfo;
  81. queuePush([
  82. 'action'=>'forwardMessage',
  83. 'message'=>$msg,
  84. 'user_ids'=>$userIds,
  85. 'config'=>$this->globalConfig,
  86. 'userInfo'=>$userInfo
  87. ]);
  88. return success(lang('im.forwardOk'));
  89. }
  90. // 获取用户信息
  91. public function getUserInfo()
  92. {
  93. $user_id = $this->request->param('user_id');
  94. $group_id = $this->request->param('group_id');
  95. $groupInfo=[];
  96. if($group_id){
  97. $group_id = explode('-', $group_id)[1];
  98. $groupInfo=Group::where(['group_id'=>$group_id])->find();
  99. if($groupInfo){
  100. // 查询操作对象的角色
  101. $groupInfo['userInfo']=GroupUser::where(['user_id'=>$user_id,'group_id'=>$group_id])->find() ?: [];
  102. // 查询我的角色
  103. $groupInfo['manageRole']=GroupUser::where(['user_id'=>$this->userInfo['user_id'],'group_id'=>$group_id])->value('role') ?: 3;
  104. }
  105. }
  106. $user=User::find($user_id);
  107. if(!$user){
  108. return error(lang('user.exist'));
  109. }
  110. $user->avatar=avatarUrl($user->avatar,$user->realname,$user->user_id,120);
  111. // 账号前面截取3位,后面截取两位,中间星号展示
  112. $user->account=substr($user->account, 0, 3).'******'.substr($user->account, -2, 2);
  113. // 查询好友关系
  114. $friend=Friend::where(['friend_user_id'=>$user_id,'create_user'=>$this->userInfo['user_id'],'status'=>1])->find();
  115. $user->friend=$friend ? : '';
  116. $location='';
  117. if($user->last_login_ip){
  118. $location=implode(" ", \Ip::find($user->last_login_ip));
  119. }
  120. $user->location=$location;
  121. $user->groupInfo=$groupInfo ? : [];
  122. $user->password='';
  123. $userModel=new User;
  124. $user->contactInfo=$userModel->setContact($user_id,0) ?? [];
  125. return success('', $user);
  126. }
  127. // 扫码登录,向客户端推送数据
  128. public function tokenLogin(){
  129. $param = $this->request->param();
  130. $token=$param['token'] ?? '';
  131. $client_id='';
  132. if($token){
  133. $client_id=authcode(urldecode($token),"DECODE", config('app.app_id'));
  134. if(!$client_id){
  135. return warning(lang('user.loginError'));
  136. }
  137. }else{
  138. return warning(lang('user.loginError'));
  139. }
  140. $userInfo=$this->userInfo;
  141. if(!$userInfo){
  142. return warning(lang('user.loginError'));
  143. }
  144. // 如果用户已经有设置
  145. $setting=$userInfo['setting'] ?: '';
  146. if($setting){
  147. $setting['hideMessageName']= $setting['hideMessageName']=='true' ? true : false;
  148. $setting['hideMessageTime']= $setting['hideMessageTime']=='true' ? true : false;
  149. $setting['avatarCricle']= $setting['avatarCricle']=='true' ? true : false;
  150. $setting['isVoice']= $setting['isVoice']=='true' ? true : false;
  151. $setting['sendKey']=(int)$setting['sendKey'];
  152. }
  153. $userInfo['setting']=$setting;
  154. Gateway::$registerAddress = config('gateway.registerAddress');
  155. //如果登录信息中含有client——id则自动进行绑定
  156. if($client_id){
  157. $user_id=$userInfo['user_id'];
  158. // 如果当前ID在线,将其他地方登陆挤兑下线
  159. if(Gateway::isUidOnline($user_id)){
  160. wsSendMsg($user_id,'offline',['id'=>$user_id,'client_id'=>$client_id,'isMobile'=>false]);
  161. }
  162. Gateway::bindUid($client_id, $user_id);
  163. // 查询团队,如果有团队则加入团队
  164. $group=Group::getMyGroup(['gu.user_id'=>$user_id,'gu.status'=>1]);
  165. if($group){
  166. $group=$group->toArray();
  167. $group_ids=arrayToString($group,'group_id',false);
  168. foreach($group_ids as $v){
  169. Gateway::joinGroup($client_id, $v);
  170. }
  171. }
  172. }
  173. $update=[
  174. 'last_login_time'=>time(),
  175. 'last_login_ip'=>$this->request->ip(),
  176. 'login_count'=>Db::raw('login_count+1')
  177. ];
  178. User::where('user_id',$userInfo['user_id'])->update($update);
  179. $authToken=User::refreshToken($userInfo,'web');
  180. $data=[
  181. 'sessionId'=>Session::getId(),
  182. 'authToken'=>$authToken,
  183. 'userInfo'=>$userInfo
  184. ];
  185. Gateway::sendToClient($client_id, json_encode(array(
  186. 'type' => 'tokenLogin',
  187. 'data' => $data,
  188. )));
  189. return success(lang('user.loginOk'),$data);
  190. }
  191. // 搜索用户
  192. public function searchUser(){
  193. $keywords=$this->request->param('keywords','');
  194. if(!$keywords){
  195. return success('',[]);
  196. }
  197. $map=['status'=>1,'account'=>$keywords];
  198. $list=User::where($map)->field(User::$defaultField)->where([['account','<>',$this->userInfo['account']]])->select()->toArray();
  199. if($list){
  200. $ids=array_column($list,'user_id');
  201. $friendList=Friend::getFriend([['create_user','=',$this->uid],['friend_user_id','in',$ids]]);
  202. foreach($list as $k=>$v){
  203. $list[$k]['avatar']=avatarUrl($v['avatar'],$v['realname'],$v['user_id'],120);
  204. $list[$k]['friend']=$friendList[$v['user_id']] ?? '';
  205. }
  206. }
  207. return success('', $list);
  208. }
  209. // 获取系统所有人员加搜索
  210. public function userList(){
  211. $keywords=$this->request->param('keywords','');
  212. $listRows=$this->request->param('limit',20);
  213. $page=$this->request->param('page',1);
  214. $map=['status'=>1];
  215. $field="user_id,realname,avatar";
  216. if(!$keywords){
  217. $list=User::where($map)->field($field)->order('user_id asc')->limit(20)->paginate(['list_rows'=>$listRows,'page'=>$page]);;
  218. if($list){
  219. $list=$list->toArray()['data'];
  220. }
  221. }else{
  222. $list=User::where($map)->field($field)->where([['account','<>',$this->userInfo['account']]])->whereLike('account|realname|name_py','%'.$keywords.'%')->select()->toArray();
  223. }
  224. if($list){
  225. foreach($list as $k=>$v){
  226. $list[$k]['avatar']=avatarUrl($v['avatar'],$v['realname'],$v['user_id'],120);
  227. $list[$k]['id']=$v['user_id'];
  228. }
  229. }
  230. return success('', $list);
  231. }
  232. // 获取聊天记录
  233. public function getMessageList()
  234. {
  235. $param = $this->request->param();
  236. $is_group = isset($param['is_group']) ? $param['is_group'] : 0;
  237. // 如果toContactId是数字,绝对是单聊
  238. $is_group = is_numeric($param['toContactId']) ? 0 : $is_group;
  239. // 设置当前聊天消息为已读
  240. $chat_identify = $this->setIsRead($is_group, $param['toContactId']);
  241. $type = isset($param['type']) ? $param['type'] : '';
  242. $is_at = isset($param['is_at']) ? $param['is_at'] : '';
  243. $map = ['chat_identify' => $chat_identify, 'status' => 1];
  244. $where = [];
  245. if ($type && $type != "all") {
  246. $map['type'] = $type;
  247. } else {
  248. if (isset($param['type'])) {
  249. $where[] = ['type', '<>', 'event'];
  250. }
  251. }
  252. $groupManage=[];
  253. // 群聊查询入群时间以后的消息
  254. if($is_group==1){
  255. $group_id = explode('-', $param['toContactId'])[1];
  256. $group=Group::where(['group_id'=> $group_id])->find();
  257. $groupManage=GroupUser::getGroupManage($group_id);
  258. if($group && $group['setting']){
  259. $groupSetting=json_decode($group['setting'],true);
  260. $history=$groupSetting['history'] ?? false;
  261. // 如果开启了历史记录才可以查看所有记录,否者根据进群时间查询记录
  262. if(!$history){
  263. $createTime=GroupUser::where(['group_id'=> $group_id,'user_id'=>$this->userInfo['user_id']])->value('create_time');
  264. $where[] = ['create_time', '>=', $createTime ? : 0];
  265. }
  266. }
  267. }
  268. $keywords = isset($param['keywords']) ? $param['keywords'] : '';
  269. if ($keywords && in_array($type, ['text', 'all'])) {
  270. $where[] = ['content', 'like', '%' . $keywords . '%'];
  271. }
  272. // 如果是查询@数据
  273. if($is_at){
  274. $atList=Db::name('message')->where($map)->where($where)->whereFindInSet('at',$this->userInfo['user_id'])->order('msg_id desc')->select()->toArray();
  275. if($atList){
  276. $data = $this->recombileMsg($atList,false);
  277. Message::setAtread($data,$this->userInfo['user_id']);
  278. return success('', $data, count($data));
  279. }else{
  280. return success('', [], 0);
  281. }
  282. }
  283. $listRows = $param['limit'] ?: 20;
  284. $pageSize = $param['page'] ?: 1;
  285. $last_id = $param['last_id'] ?? 0;
  286. if($last_id){
  287. $where[]=['msg_id','<',$last_id];
  288. $pageSize=1;
  289. }
  290. //判断是客服还是用户
  291. if ($this->userInfo['role'] == 0) {
  292. //用户可见历史记录的时长
  293. $hours = Config::where('field', 'user_show_message')->value('val');
  294. if ($hours > 0) {
  295. $start_time = time() - $hours * 60 * 60;
  296. $where[] = ['create_time', '>=', $start_time];
  297. }
  298. } elseif ($this->userInfo['role'] == 3) {
  299. //客服可见历史记录的时长
  300. $hours = Config::where('field', 'kefu_show_message')->value('val');
  301. if ($hours > 0) {
  302. $start_time = time() - $hours * 60 * 60;
  303. $where[] = ['create_time', '>=', $start_time];
  304. }
  305. }
  306. $list = Message::getList($map, $where, 'msg_id desc', $listRows, $pageSize);
  307. $data = $this->recombileMsg($list,true,$groupManage);
  308. // 如果是群聊并且是第一页消息,需要推送@数据给用户
  309. if($param['is_group']==1 && $param['page']==1){
  310. $isPush=Cache::get('atMsgPush'.$chat_identify) ?? '';
  311. $atList=Db::name('message')->where(['chat_identify'=>$chat_identify,'is_group'=>1])->whereFindInSet('at',$this->userInfo['user_id'])->order('msg_id desc')->select()->toArray();
  312. $msgIda=array_column($atList,'msg_id');
  313. // 如果两次推送at数据的列表不一样,则推送
  314. if($isPush!=json_encode($msgIda)){
  315. $atData=$this->recombileMsg($atList,false);
  316. wsSendMsg($this->userInfo['user_id'],'atMsgList',[
  317. 'list'=>$atData,
  318. 'count'=>count($atData),
  319. 'toContactId'=>$param['toContactId']
  320. ]);
  321. Cache::set('atMsgPush'.$chat_identify,json_encode($msgIda),60);
  322. }
  323. }
  324. // 如果是消息管理器则不用倒序
  325. if (!isset($param['type'])) {
  326. $data = array_reverse($data);
  327. }
  328. return success('', $data, $list->total());
  329. }
  330. // 获取单条消息详情
  331. public function getMessageInfo()
  332. {
  333. $param = $this->request->param();
  334. $id = $param['msg_id'] ?? 0;
  335. $message = Message::where(['msg_id' => $id])->find();
  336. if ($message) {
  337. $data = $this->recombileMsg([$message], false);
  338. return success('', $data);
  339. } else {
  340. return warning(lang('im.exist'));
  341. }
  342. }
  343. // 获取单条消息上下文
  344. public function getMessageContext()
  345. {
  346. $param = $this->request->param();
  347. $is_group = isset($param['is_group']) ? $param['is_group'] : 0;
  348. $id = $param['msg_id'] ?? 0;
  349. $direction = $param['direction'] ?? 0;
  350. $message = Message::where(['msg_id' => $id])->find();
  351. if (!$message) {
  352. return warning(lang('im.exist'));
  353. }
  354. $groupManage=[];
  355. $where = [];
  356. $map = ['chat_identify' => $message['chat_identify'], 'status' => 1];
  357. if($is_group==1 && $direction<2){
  358. $group_id = $message['to_user'];
  359. $group=Group::where(['group_id'=> $group_id])->find();
  360. $groupManage=GroupUser::getGroupManage($group_id);
  361. if($group && $group['setting']){
  362. $groupSetting=json_decode($group['setting'],true);
  363. $history=$groupSetting['history'] ?? false;
  364. // 如果开启了历史记录才可以查看所有记录,否者根据进群时间查询记录
  365. if(!$history){
  366. $createTime=GroupUser::where(['group_id'=> $group_id,'user_id'=>$this->userInfo['user_id']])->value('create_time');
  367. $where[] = ['create_time', '>=', $createTime ? : 0];
  368. }
  369. }
  370. }
  371. if($direction==0){
  372. $where[] = ['msg_id', '<', $id];
  373. $beforeList = Message::where($map)->where($where)->order('msg_id desc')->limit(5)->select()->toArray();
  374. $beforeList = array_reverse($beforeList);
  375. $where2 = [];
  376. $where2[] = ['msg_id', '>=', $id];
  377. $afterList = Message::where($map)->where($where2)->order('msg_id asc')->limit(5)->select()->toArray();
  378. $data = array_merge($beforeList, $afterList);
  379. }elseif($direction==1){
  380. $where[] = ['msg_id', '<', $id];
  381. $data = Message::where($map)->where($where)->order('msg_id desc')->limit(5)->select()->toArray();
  382. $data = array_reverse($data);
  383. }else{
  384. $where[] = ['msg_id', '>', $id];
  385. $data = Message::where($map)->where($where)->order('msg_id asc')->limit(5)->select()->toArray();
  386. }
  387. if($data){
  388. $data = $this->recombileMsg($data, false,$groupManage);
  389. }
  390. return success('', $data);
  391. }
  392. protected function recombileMsg($list,$isPagination=true,$manage=[])
  393. {
  394. $data = [];
  395. $userInfo = $this->userInfo;
  396. if ($list) {
  397. $listData = $isPagination ? $list->toArray()['data'] : $list;
  398. $userList = User::matchUser($listData, true, 'from_user', 120);
  399. foreach ($listData as $k => $v) {
  400. // 屏蔽已删除的消息
  401. if ($v['del_user']) {
  402. $delUser = explode(',', $v['del_user']);
  403. if (in_array($userInfo['user_id'], $delUser)) {
  404. unset($list[$k]);
  405. continue;
  406. // $v['type']="event";
  407. // $v['content']="删除了一条消息";
  408. }
  409. }
  410. $content = str_encipher($v['content'],false);
  411. $preview = '';
  412. $ext='';
  413. if (in_array($v['type'], $this->fileType)) {
  414. $content = getFileUrl($content);
  415. $preview = previewUrl($content);
  416. $ext=getExtUrl($content);
  417. }
  418. $fromUser = $userList[$v['from_user']];
  419. // 处理撤回的消息
  420. if ($v['type'] == "event" && $v['is_undo']==1) {
  421. if ($v['from_user'] == $userInfo['user_id']) {
  422. $content = lang('im.you'). $content;
  423. } elseif ($v['is_group'] == 1) {
  424. $content = $fromUser['realname'] . $content;
  425. } else {
  426. $content = lang('im.other') . $content;
  427. }
  428. }
  429. $toContactId=$v['is_group'] ==1 ? 'group-'.$v['to_user'] : $v['to_user'];
  430. $atList=($v['at'] ?? null) ? explode(',',$v['at']): [];
  431. $role=$manage[$v['from_user']] ?? 3;
  432. $data[] = [
  433. 'msg_id' => $v['msg_id'],
  434. 'id' => $v['id'],
  435. 'status' => "succeed",
  436. 'type' => $v['type'],
  437. 'sendTime' => (is_string($v['create_time']) ? strtotime($v['create_time']) : $v['create_time'])* 1000,
  438. 'content' => $content,
  439. 'preview' => $preview,
  440. 'download' => $v['file_id'] ? getMainHost().'/filedown/'.encryptIds($v['file_id']) : '',
  441. 'is_read' => $v['is_read'],
  442. 'is_group' => $v['is_group'],
  443. 'at' => $atList,
  444. 'toContactId' => $toContactId,
  445. 'from_user' => $v['from_user'],
  446. 'file_id' => $v['file_id'],
  447. 'file_cate' => $v['file_cate'],
  448. 'fileName' => $v['file_name'],
  449. 'fileSize' => $v['file_size'],
  450. 'fromUser' => $fromUser,
  451. 'extUrl'=>$ext,
  452. 'role'=>$role,
  453. 'extends'=>is_string($v['extends'])?json_decode($v['extends'],true) : $v['extends']
  454. ];
  455. }
  456. }
  457. return $data;
  458. }
  459. // 设置当前窗口的消息默认为已读
  460. public function setMsgIsRead()
  461. {
  462. $param = $this->request->param();
  463. // 判断是否是一个二维数组
  464. if (is_array($param['messages'][0] ?? '')) {
  465. $messages=$param['messages'];
  466. } else {
  467. $messages=[$param['messages']];
  468. }
  469. $this->setIsRead($param['is_group'], $param['toContactId'],$messages);
  470. if (!$param['is_group']) {
  471. wsSendMsg($param['fromUser'], 'isRead', $messages, 0);
  472. }
  473. return success('');
  474. }
  475. // 设置全部为已读
  476. public function readAllMsg()
  477. {
  478. // 阅读所有单聊
  479. $map = ['to_user' => $this->userInfo['user_id'], 'is_read' => 0, 'is_group' => 0];
  480. Message::where($map)->update(['is_read' => 1]);
  481. // 阅读所有群聊
  482. GroupUser::where(['user_id' => $this->userInfo['user_id'], 'status' => 1])->update(['unread'=>0]);
  483. return success('');
  484. }
  485. // 设置消息已读
  486. protected function setIsRead($is_group, $to_user,$messages=[])
  487. {
  488. if ($is_group==1) {
  489. $chat_identify = $to_user;
  490. } else if($is_group==0) {
  491. $chat_identify = chat_identify($this->userInfo['user_id'], $to_user);
  492. } else if($is_group==2){
  493. $chat_identify = $to_user;
  494. }
  495. $data=[
  496. 'action'=>'setIsRead',
  497. 'is_group'=>$is_group,
  498. 'to_user'=>$to_user,
  499. 'messages'=>$messages,
  500. 'user_id'=>$this->userInfo['user_id']
  501. ];
  502. queuePush($data,3);
  503. return $chat_identify;
  504. }
  505. // 聊天设置
  506. public function setting()
  507. {
  508. $param = $this->request->param();
  509. if ($param) {
  510. User::where(['user_id' => $this->userInfo['user_id']])->update(['setting' => $param]);
  511. return success('');
  512. }
  513. return warning('');
  514. }
  515. // 撤回消息
  516. public function undoMessage()
  517. {
  518. $param = $this->request->param();
  519. $id = $param['id'];
  520. $message = Message::where(['id' => $id])->find();
  521. if ($message) {
  522. // 如果时间超过了2分钟也不能撤回
  523. $createTime=is_string($message['create_time']) ? strtotime($message['create_time']) : $message['create_time'];
  524. $redoTime=$this->globalConfig['chatInfo']['redoTime'] ?? 120;
  525. if(time()-$createTime>$redoTime && $message['is_group']==0){
  526. return warning(lang('im.redoLimitTime',['time'=>floor($redoTime/60)]));
  527. }
  528. $text = lang('im.redo');
  529. $fromUserName = lang('im.other');
  530. $toContactId = $message['to_user'];
  531. if ($message['is_group'] == 1) {
  532. $fromUserName = $this->userInfo['realname'];
  533. $toContactId = explode('-', $message['chat_identify'])[1];
  534. // 如果是群聊消息撤回,需要判断是否是群主或者管理员,如果是则可以撤回
  535. if($message['from_user']!=$this->userInfo['user_id']){
  536. $groupUser=GroupUser::where(['user_id'=>$this->userInfo['user_id'],'group_id'=>$toContactId])->find();
  537. if(!$groupUser || !in_array($groupUser['role'],[1,2])){
  538. return warning(lang('system.notAuth'));
  539. }
  540. $text=lang('im.manageRedo');
  541. }
  542. }
  543. $message->content = str_encipher($text);
  544. $message->type = 'event';
  545. $message->is_undo = 1;
  546. //@的数据清空
  547. $message->at = '';
  548. $message->save();
  549. $info = $message->toArray();
  550. // $data = $info;
  551. $data['content'] = $fromUserName . $text;
  552. $data['sendTime'] = $createTime * 1000;
  553. $data['id'] = $info['id'];
  554. $data['from_user'] = $info['from_user'];
  555. $data['msg_id'] = $info['msg_id'];
  556. $data['status'] = $info['status'];
  557. $data['type'] = 'event';
  558. $data['is_last'] = $info['is_last'];
  559. $data['toContactId'] = $message['is_group'] == 1 ? $info['chat_identify'] : $toContactId;
  560. $data['isMobile'] = $this->request->isMobile() ? 1 : 0;
  561. wsSendMsg($toContactId, 'undoMessage', $data, $info['is_group']);
  562. if($info['is_group']==0){
  563. // 给自己也发一份推送,多端同步
  564. $data['content'] =lang('im.you'). $text;
  565. wsSendMsg($this->userInfo['user_id'], 'undoMessage', $data, $info['is_group']);
  566. }
  567. return success('');
  568. } else {
  569. return warning();
  570. }
  571. }
  572. // 删除消息
  573. public function removeMessage()
  574. {
  575. $param = $this->request->param();
  576. $id = $param['id'];
  577. $map = ['id' => $id];
  578. $message = Message::where($map)->find();
  579. if ($message) {
  580. $message->del_user = $this->userInfo['user_id'];
  581. if ($message['is_group'] == 1) {
  582. if ($message['del_user']) {
  583. $message->del_user .= ',' . $this->userInfo['user_id'];
  584. }
  585. } else {
  586. if ($message['del_user'] > 0) {
  587. $message->where($map)->delete();
  588. return success(lang('system.delOk'));
  589. }
  590. }
  591. $message->save();
  592. return success('');
  593. } else {
  594. return warning('');
  595. }
  596. }
  597. // 消息免打扰
  598. public function isNotice()
  599. {
  600. $param = $this->request->param();
  601. $user_id = $this->userInfo['user_id'];
  602. $id = $param['id'];
  603. if ($param['is_group'] == 1) {
  604. $group_id = explode('-', $param['id'])[1];
  605. GroupUser::update(['is_notice' => $param['is_notice']], ['user_id' => $user_id, 'group_id' => $group_id]);
  606. } else {
  607. $map = ['create_user' => $user_id, 'friend_user_id' => $id];
  608. $friend = Friend::where($map)->find();
  609. try {
  610. if ($friend) {
  611. $friend->is_notice = $param['is_notice'];
  612. $friend->save();
  613. } else {
  614. $info = [
  615. 'create_user' => $user_id,
  616. 'friend_user_id' => $id,
  617. 'is_notice' => $param['is_notice']
  618. ];
  619. Friend::create($info);
  620. }
  621. return success('');
  622. } catch (Exception $e) {
  623. return error($e->getMessage());
  624. }
  625. }
  626. wsSendMsg($user_id,"setIsNotice",['id'=>$id,'is_notice'=>$param['is_notice'],'is_group'=>$param['is_group']]);
  627. return success('');
  628. }
  629. // 设置聊天置顶
  630. public function setChatTop()
  631. {
  632. $param = $this->request->param();
  633. $user_id = $this->userInfo['user_id'];
  634. $is_group = $param['is_group'] ?: 0;
  635. $id = $param['id'];
  636. try {
  637. if ($is_group == 1) {
  638. $group_id = explode('-', $param['id'])[1];
  639. GroupUser::update(['is_top' => $param['is_top']], ['user_id' => $user_id, 'group_id' => $group_id]);
  640. } else {
  641. $map = ['create_user' => $user_id, 'friend_user_id' => $id];
  642. $friend = Friend::where($map)->find();
  643. if ($friend) {
  644. $friend->is_top = $param['is_top'];
  645. $friend->save();
  646. } else {
  647. $info = [
  648. 'create_user' => $user_id,
  649. 'friend_user_id' => $id,
  650. 'is_top' => $param['is_top']
  651. ];
  652. Friend::create($info);
  653. }
  654. }
  655. wsSendMsg($user_id,"setChatTop",['id'=>$id,'is_top'=>$param['is_top'],'is_group'=>$is_group]);
  656. return success('');
  657. } catch (Exception $e) {
  658. return error($e->getMessage());
  659. }
  660. }
  661. // 删除聊天
  662. public function delChat()
  663. {
  664. $param = $this->request->param();
  665. $user_id = $this->userInfo['user_id'];
  666. $is_group = $param['is_group'] ?: 0;
  667. $id = $param['id'];
  668. $data=[
  669. 'user_id'=>$user_id,
  670. 'is_group'=>$is_group,
  671. 'to_user'=>$id
  672. ];
  673. ChatDelog::create($data);
  674. ChatDelog::updateCache($user_id);
  675. return success('');
  676. }
  677. // 向用户发送消息
  678. public function sendToMsg(){
  679. $param=$this->request->param();
  680. $toContactId=$param['toContactId'];
  681. $type=$param['type'];
  682. $status=$param['status'];
  683. $event=$param['event'] ?? 'calling';
  684. if($event=='calling'){
  685. $status=3;
  686. }
  687. $sdp=$param['sdp'] ?? '';
  688. $iceCandidate=$param['iceCandidate'] ?? '';
  689. $callTime=$param['callTime'] ?? '';
  690. $msg_id=$param['msg_id'] ?? '';
  691. $id=$param['id'] ?? '';
  692. $code=($param['code'] ?? '') ?: 901;
  693. // 如果该用户不在线,则发送忙线
  694. Gateway::$registerAddress = config('gateway.registerAddress');
  695. if(!Gateway::isUidOnline($toContactId)){
  696. $toContactId=$this->userInfo['user_id'];
  697. $code=907;
  698. $event='busy';
  699. sleep(1);
  700. }
  701. switch($code){
  702. case 902:
  703. $content=lang('webRtc.cancel');
  704. break;
  705. case 903:
  706. $content=lang('webRtc.refuse');
  707. break;
  708. case 905:
  709. $content=lang('webRtc.notConnected');
  710. break;
  711. case 906:
  712. $content=lang('webRtc.duration',['time'=>date("i:s",$callTime)]);
  713. break;
  714. case 907:
  715. $content=lang('webRtc.busy');
  716. break;
  717. case 908:
  718. $content=lang('webRtc.other');
  719. break;
  720. default:
  721. $content=$type==1 ?lang('webRtc.video') : lang('webRtc.audio');
  722. break;
  723. }
  724. switch($event){
  725. case 'calling':
  726. $content=$type==1 ?lang('webRtc.video'): lang('webRtc.audio');
  727. break;
  728. case 'acceptRtc':
  729. $content=lang('webRtc.answer');
  730. break;
  731. case 'iceCandidate':
  732. $content=lang('webRtc.exchange');
  733. break;
  734. }
  735. $userInfo=$this->userInfo;
  736. $userInfo['id']=$userInfo['user_id'];
  737. $user = new User();
  738. $data=[
  739. 'id'=>$id,
  740. 'msg_id'=>$msg_id,
  741. 'sendTime'=>time()*1000,
  742. 'toContactId'=>$toContactId,
  743. 'content'=>$content,
  744. 'type'=>'webrtc',
  745. 'status'=>'succeed',
  746. 'is_group'=>0,
  747. 'is_read'=>0,
  748. 'fromUser'=>$userInfo,
  749. 'at'=>[],
  750. 'extends'=>[
  751. 'type'=>$type, //通话类型,1视频,0语音。
  752. 'status'=>$status, //,1拨打方,2接听方
  753. 'event'=>$event,
  754. 'callTime'=>$callTime,
  755. 'sdp'=>$sdp,
  756. 'code'=>$code, //通话状态:呼叫901,取消902,拒绝903,接听904,未接通905,接通后挂断906,忙线907,其他端操作908
  757. 'iceCandidate'=>$iceCandidate,
  758. 'isMobile'=>$this->request->isMobile() ? 1 : 0,
  759. ]
  760. ];
  761. if($event=='calling'){
  762. $chat_identify=chat_identify($userInfo['id'],$toContactId);
  763. $msg=[
  764. 'from_user'=>$userInfo['id'],
  765. 'to_user'=>$toContactId,
  766. 'id'=>$id,
  767. 'content'=>str_encipher($content),
  768. 'chat_identify'=>$chat_identify,
  769. 'create_time'=>time(),
  770. 'type'=>$data['type'],
  771. 'is_group'=>0,
  772. 'is_read'=>0,
  773. 'extends'=>$data['extends'],
  774. ];
  775. $message=new Message();
  776. $message->update(['is_last'=>0],['chat_identify'=>$chat_identify]);
  777. $message->save($msg);
  778. $msg_id=$message->msg_id;
  779. $data['msg_id']=$msg_id;
  780. // 将接收人设置为发送人才能定位到该消息
  781. $data['toContactId']=$userInfo['id'];
  782. $data['toUser']=$toContactId;
  783. }elseif($event=='hangup'){
  784. $message=Message::where(['id'=>$id])->find();
  785. if(!$message){
  786. return error(lang('webRtc.fail'));
  787. }
  788. if($message){
  789. $message->content=str_encipher($content);
  790. $extends=$message->extends;
  791. $extends['code']=$code;
  792. $extends['callTime']=$callTime;
  793. $message->extends=$extends;
  794. $message->save();
  795. }
  796. }
  797. wsSendMsg($toContactId,'webrtc',$data);
  798. $wsData=$data;
  799. if(in_array($event,['calling','acceptRtc','hangup'])){
  800. if(in_array($event,['acceptRtc','hangup'])){
  801. $data['extends']['event']='otherOpt'; //其他端操作
  802. }
  803. $data['toContactId']=$toContactId;
  804. $data['contactInfo']=$user->setContact($toContactId,0,'webrtc',$content) ? : [];
  805. wsSendMsg($userInfo['id'],'webrtc',$data);
  806. }
  807. return success('',$wsData);
  808. }
  809. // 修改密码
  810. public function editPassword()
  811. {
  812. if(env('app.demon_mode',false)){
  813. return warning(lang('system.demoMode'));
  814. }
  815. $user_id = $this->userInfo['user_id'];
  816. $user=User::find($user_id);
  817. if(!$user){
  818. return warning(lang('user.exist'));
  819. }
  820. $account=$user->account;
  821. $code=$this->request->param('code','');
  822. $originalPassword = $this->request->param('originalPassword', '');
  823. if($code){
  824. if(Cache::get($account)!=$code){
  825. return warning(lang('user.codeErr'));
  826. }
  827. }elseif($originalPassword){
  828. if(password_hash_tp($originalPassword,$user->salt)!= $user->password){
  829. return warning(lang('user.passErr'));
  830. }
  831. }else{
  832. return warning(lang('system.parameterError'));
  833. }
  834. try{
  835. $password = $this->request->param('password','');
  836. if($password){
  837. $salt=$user->salt;
  838. $user->password= password_hash_tp($password,$salt);
  839. }
  840. $user->save();
  841. return success(lang('system.editOk'));
  842. }catch (\Exception $e){
  843. return error(lang('system.editFail'));
  844. }
  845. }
  846. // 修改用户信息
  847. public function updateUserInfo(){
  848. try{
  849. $data = $this->request->param();
  850. $user=User::find($this->uid);
  851. if(!$user){
  852. return warning(lang('user.exist'));
  853. }
  854. // 接入用户名检测服务
  855. event('GreenText',['content'=>$data['realname'],'service'=>"nickname_detection"]);
  856. // 个性签名检测服务
  857. event('GreenText',['content'=>$data['motto'],'service'=>"comment_detection"]);
  858. $user->realname =$data['realname'];
  859. $user->email =$data['email'];
  860. $user->motto=$data['motto'];
  861. $user->sex =$data['sex'];
  862. $user->name_py= pinyin_sentence($data['realname']);
  863. $user->save();
  864. return success(lang('system.editOk'), $data);
  865. }catch (\Exception $e){
  866. return error($e->getMessage());
  867. }
  868. }
  869. // 修改账户
  870. public function editAccount(){
  871. if(env('app.demon_mode',false)){
  872. return warning(lang('system.demoMode'));
  873. }
  874. $code=$this->request->param('code','');
  875. $newCode=$this->request->param('newCode','');
  876. $account=$this->request->param('account','');
  877. $isUser=User::where('account',$account)->find();
  878. if($isUser){
  879. return warning(lang('user.already'));
  880. }
  881. $user=User::find($this->uid);
  882. if(!$user){
  883. return warning(lang('user.exist'));
  884. }
  885. // 如果已经认证过了,则需要验证验证码
  886. if($user->is_auth){
  887. if(Cache::get($user->account)!=$code){
  888. return warning(lang('user.codeErr'));
  889. }
  890. }
  891. if(Cache::get($account)!=$newCode){
  892. return warning(lang('user.newCodeErr'));
  893. }
  894. try{
  895. $user->account=$account;
  896. $user->is_auth=1;
  897. $user->save();
  898. return success(lang('system.editOk'));
  899. }catch (\Exception $e){
  900. return error(lang('system.editFail'));
  901. }
  902. }
  903. // 阅读@消息
  904. public function readAtMsg(){
  905. $param = $this->request->param();
  906. $atList=Db::name('message')->where(['chat_identify'=>$param['toContactId'],'is_group'=>1])->whereFindInSet('at',$this->userInfo['user_id'])->order('msg_id desc')->select();
  907. $atData=$this->recombileMsg($atList,false);
  908. Message::setAtRead($atData,$this->userInfo['user_id']);
  909. // $message=Message::where('msg_id',$param['msg_id'])->select();
  910. // $atList=($message ?? null) ? explode(',',$message): [];
  911. // // 两个数组取差集
  912. // $newAtList = array_diff($atList, [$this->userInfo['user_id']]);
  913. // Message::where('msg_id',$param['msg_id'])->update(['at'=>implode(',',$newAtList)]);
  914. return success('');
  915. }
  916. // 获取系统公告
  917. public function getAdminNotice(){
  918. $data=Message::where(['chat_identify'=>'admin_notice'])->order('msg_id desc')->find();
  919. $extends=$data['extends'] ?? [];
  920. if(!$extends){
  921. $extends['title']='';
  922. }
  923. $createTime=$data['create_time'] ?? 0;
  924. if(!$createTime){
  925. $extends['create_time']=$createTime;
  926. }else{
  927. $extends['create_time']=is_string($data['create_time']) ? strtotime($data['create_time']) : $data['create_time'];
  928. }
  929. return success('',$extends);
  930. }
  931. // 双向删除消息
  932. public function delMessage(){
  933. $param = $this->request->param();
  934. $id = $param['id'];
  935. if(!$this->globalConfig['chatInfo']['dbDelMsg']){
  936. return warning(lang('system.notAuth'));
  937. }
  938. $message = Message::where(['id' => $id])->find();
  939. if ($message) {
  940. if($message['from_user']!=$this->userInfo['user_id']){
  941. return warning(lang('system.notAuth'));
  942. }
  943. Message::where(['id' => $id])->delete();
  944. // 如果是最后一条消息,需要将上一条设置为最后一条
  945. if($message['is_last']){
  946. Message::where(['chat_identify'=>$message['chat_identify']])->order('msg_id desc')->limit(1)->update(['is_last'=>1]);
  947. }
  948. $toContactId = $message['to_user'];
  949. if ($message['is_group'] == 1) {
  950. $toContactId = explode('-', $message['chat_identify'])[1];
  951. }
  952. wsSendMsg($toContactId, 'delMessage', $message, $message['is_group']);
  953. return success('');
  954. } else {
  955. return warning(lang('im.exist'));
  956. }
  957. }
  958. }