Im.php 46 KB

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