Im.php 39 KB

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