ChatMessageService.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2017~2021 LARAVEL研发中心
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://www.laravel.cn
  8. // +----------------------------------------------------------------------
  9. // | Author: laravel开发员 <laravel.qq.com>
  10. // +----------------------------------------------------------------------
  11. namespace App\Services;
  12. use App\Models\ChatMessageModel;
  13. use App\Models\ConfigModel;
  14. /**
  15. * 聊天-服务类
  16. * Class ChatMessageService
  17. * @package App\Services
  18. */
  19. class ChatMessageService extends BaseService
  20. {
  21. // 静态对象
  22. protected static $instance = null;
  23. /**
  24. * 构造函数
  25. * ChatMessageService constructor.
  26. */
  27. public function __construct()
  28. {
  29. $this->model = new ChatMessageModel();
  30. }
  31. /**
  32. * 静态入口
  33. * @return static|null
  34. */
  35. public static function make()
  36. {
  37. if (!self::$instance) {
  38. self::$instance = (new static());
  39. }
  40. return self::$instance;
  41. }
  42. /**
  43. * 绑定用户
  44. * @param $fd
  45. * @param $data
  46. * @return bool
  47. */
  48. public function bind($fd, $data)
  49. {
  50. $userId = isset($data['from_uid']) ? intval($data['from_uid']) : 0;
  51. if ($userId <= 0) {
  52. $this->error = '1013';
  53. return false;
  54. }
  55. RedisService::set("chats:bind:{$userId}", ['fd' => $fd, 'user_id' => $userId], 86400);
  56. return true;
  57. }
  58. /**
  59. * 获取列表
  60. * @param $params
  61. * @param int $pageSize
  62. * @return array
  63. */
  64. public function getDataList($params, $pageSize = 15)
  65. {
  66. $where = ['a.mark' => 1, 'a.status' => 1];
  67. $type = isset($params['type']) ? $params['type'] : 1;
  68. $chatKey = isset($params['chat_key']) ? $params['chat_key'] : '';
  69. $fromUid = isset($params['from_uid']) ? $params['from_uid'] : 0;
  70. $toUid = isset($params['to_uid']) ? $params['to_uid'] : 0;
  71. $orderNo = isset($params['order_no']) ? $params['order_no'] : '';
  72. if ($type > 0) {
  73. $where['a.type'] = $type;
  74. }
  75. if ($chatKey) {
  76. $where['a.chat_key'] = $chatKey;
  77. }
  78. if ($fromUid > 0) {
  79. $where['a.from_uid'] = $fromUid;
  80. }
  81. if ($toUid > 0) {
  82. $where['a.to_uid'] = $toUid;
  83. }
  84. if ($orderNo) {
  85. $where['a.order_no'] = $orderNo;
  86. }
  87. $list = $this->model->from('chat_message as a')
  88. ->leftJoin('member as m', 'm.id', '=', 'a.from_uid')
  89. ->leftJoin('member as m1', 'm1.id', '=', 'a.to_uid')
  90. ->where($where)
  91. ->where(function ($query) use ($params) {
  92. $id = isset($params['id']) ? $params['id'] : 0;
  93. if ($id > 0) {
  94. $query->where('a.id', '<', $id);
  95. }
  96. })
  97. ->where(function ($query) use ($params) {
  98. $userId = isset($params['user_id']) ? $params['user_id'] : 0;
  99. if ($userId) {
  100. $query->where('a.from_uid', '=', $userId)->orWhere('a.to_uid', '=', $userId);
  101. }
  102. })
  103. ->select(['a.*', 'm.username as from_username', 'm.avatar as from_avatar', 'm1.username as to_username', 'm1.avatar as to_avatar'])
  104. ->orderBy('a.create_time', 'desc')
  105. ->paginate($pageSize > 0 ? $pageSize : 9999999);
  106. $list = $list ? $list->toArray() : [];
  107. if ($list) {
  108. foreach ($list['data'] as &$item) {
  109. $item['from_username_text'] = $item['from_username'] ? format_account($item['from_username']) : '客服';
  110. $item['from_username'] = $item['from_username'] ? $item['from_username'] : '客服';
  111. $item['to_username_text'] = $item['to_username'] ? format_account($item['to_username']) : '客服';
  112. $item['to_username'] = $item['to_username'] ? $item['to_username'] : '客服';
  113. $item['message_url'] = $item['message_type'] == 2 ? get_image_url($item['message']) : '';
  114. $item['from_avatar'] = $item['from_avatar'] ? get_image_url($item['from_avatar']) : '';
  115. $item['to_avatar'] = $item['to_avatar'] ? get_image_url($item['to_avatar']) : '';
  116. $item['time_text'] = $item['create_time'] ? format_time(strtotime($item['create_time'])) : '刚刚';
  117. $userId = isset($params['user_id']) ? $params['user_id'] : 0;
  118. if ($userId == $item['to_uid']) {
  119. // 已读
  120. $this->model->where(['id' => $item['id']])->update(['is_read' => 1, 'update_time' => time()]);
  121. }
  122. }
  123. }
  124. return [
  125. 'pageSize' => $pageSize,
  126. 'total' => isset($list['total']) ? $list['total'] : 0,
  127. 'list' => isset($list['data']) ? $list['data'] : []
  128. ];
  129. }
  130. /**
  131. * 消息列表
  132. * @param $params
  133. * @param int $pageSize
  134. * @return array
  135. */
  136. public function getNewList($params, $pageSize = 15)
  137. {
  138. $where = ['a.mark' => 1, 'a.status' => 1];
  139. $type = isset($params['type']) ? $params['type'] : 1;
  140. $chatKey = isset($params['chat_key']) ? $params['chat_key'] : '';
  141. $fromUid = isset($params['from_uid']) ? $params['from_uid'] : 0;
  142. $toUid = isset($params['to_uid']) ? $params['to_uid'] : 0;
  143. $orderNo = isset($params['order_no']) ? $params['order_no'] : '';
  144. if ($type > 0) {
  145. $where['a.type'] = $type;
  146. }
  147. if ($chatKey) {
  148. $where['a.chat_key'] = $chatKey;
  149. }
  150. if ($fromUid > 0) {
  151. $where['a.from_uid'] = $fromUid;
  152. }
  153. if ($toUid > 0) {
  154. $where['a.to_uid'] = $toUid;
  155. }
  156. if ($orderNo) {
  157. $where['a.order_no'] = $orderNo;
  158. }
  159. $list = $this->model->from('chat_message as a')
  160. ->leftJoin('member as m', 'm.id', '=', 'a.from_uid')
  161. ->leftJoin('member as m1', 'm1.id', '=', 'a.to_uid')
  162. ->where($where)
  163. ->where(function ($query) use ($params) {
  164. $userId = isset($params['user_id']) ? $params['user_id'] : 0;
  165. if ($userId) {
  166. $query->where('a.from_uid', '=', $userId)->orWhere('a.to_uid', '=', $userId);
  167. }
  168. })
  169. ->select(['a.id', 'a.from_uid', 'a.to_uid', 'a.type', 'a.message_type', 'a.data_type', 'a.message', 'a.chat_key', 'a.order_no', 'a.create_time', 'm.username as from_username', 'm.avatar as from_avatar', 'm1.username as to_username', 'm1.avatar as to_avatar'])
  170. ->groupBy('a.chat_key')
  171. ->orderBy('a.create_time', 'desc')
  172. ->paginate($pageSize > 0 ? $pageSize : 9999999);
  173. $list = $list ? $list->toArray() : [];
  174. if ($list) {
  175. foreach ($list['data'] as &$item) {
  176. $item['from_username_text'] = $item['from_username'] ? format_account($item['from_username']) : '客服';
  177. $item['to_username_text'] = $item['to_username'] ? format_account($item['to_username']) : '客服';
  178. $item['from_avatar'] = $item['from_avatar'] ? get_image_url($item['from_avatar']) : '';
  179. $item['to_avatar'] = $item['to_avatar'] ? get_image_url($item['to_avatar']) : '';
  180. $item['time_text'] = $item['create_time'] ? format_time(strtotime($item['create_time'])) : '刚刚';
  181. $item['info'] = $this->getTempInfo($item['chat_key']);
  182. }
  183. }
  184. return [
  185. 'pageSize' => $pageSize,
  186. 'total' => isset($list['total']) ? $list['total'] : 0,
  187. 'list' => isset($list['data']) ? $list['data'] : []
  188. ];
  189. }
  190. /**
  191. * 消息列表
  192. * @param $params
  193. * @param int $pageSize
  194. * @return array
  195. */
  196. public function getWaitList($params, $pageSize = 15)
  197. {
  198. $where = ['a.mark' => 1, 'a.status' => 1];
  199. $type = isset($params['type']) ? $params['type'] : 1;
  200. $chatKey = isset($params['chat_key']) ? $params['chat_key'] : '';
  201. $fromUid = isset($params['from_uid']) ? $params['from_uid'] : 0;
  202. $toUid = isset($params['to_uid']) ? $params['to_uid'] : 0;
  203. $orderNo = isset($params['order_no']) ? $params['order_no'] : '';
  204. if ($type > 0) {
  205. $where['a.type'] = $type;
  206. }
  207. if ($chatKey) {
  208. $where['a.chat_key'] = $chatKey;
  209. }
  210. if ($fromUid > 0) {
  211. $where['a.from_uid'] = $fromUid;
  212. }
  213. if ($toUid > 0) {
  214. $where['a.to_uid'] = $toUid;
  215. }
  216. if ($orderNo) {
  217. $where['a.order_no'] = $orderNo;
  218. }
  219. $list = $this->model->from('chat_message as a')
  220. ->leftJoin('member as m', 'm.id', '=', 'a.from_uid')
  221. ->leftJoin('member as m1', 'm1.id', '=', 'a.to_uid')
  222. ->where($where)
  223. ->where(function ($query) use ($params) {
  224. $userId = isset($params['user_id']) ? $params['user_id'] : 0;
  225. if ($userId) {
  226. $query->where('a.to_uid', '=', $userId);
  227. }
  228. })
  229. ->select(['a.id', 'a.from_uid', 'a.to_uid', 'a.type', 'a.message_type', 'a.data_type', 'a.message', 'a.chat_key', 'a.order_no', 'a.create_time', 'm.username as from_username', 'm.avatar as from_avatar', 'm1.username as to_username', 'm1.avatar as to_avatar'])
  230. ->groupBy('a.chat_key')
  231. ->orderBy('a.create_time', 'desc')
  232. ->paginate($pageSize > 0 ? $pageSize : 9999999);
  233. $list = $list ? $list->toArray() : [];
  234. if ($list) {
  235. foreach ($list['data'] as &$item) {
  236. $item['from_username_text'] = $item['from_username'] ? format_account($item['from_username']) : '客服';
  237. $item['to_username_text'] = $item['to_username'] ? format_account($item['to_username']) : '客服';
  238. $item['from_avatar'] = $item['from_avatar'] ? get_image_url($item['from_avatar']) : '';
  239. $item['to_avatar'] = $item['to_avatar'] ? get_image_url($item['to_avatar']) : '';
  240. $item['time_text'] = $item['create_time'] ? format_time(strtotime($item['create_time'])) : '刚刚';
  241. $item['info'] = $this->getTempInfo($item['chat_key']);
  242. }
  243. }
  244. return [
  245. 'pageSize' => $pageSize,
  246. 'total' => isset($list['total']) ? $list['total'] : 0,
  247. 'list' => isset($list['data']) ? $list['data'] : []
  248. ];
  249. }
  250. /**
  251. * 消息数量
  252. * @param $userId
  253. * @return int[]
  254. */
  255. public function getNewCount($userId)
  256. {
  257. $counts = ['notice' => 0, 'message' => 0];
  258. $counts['notice'] = (int)$this->model->where(['status' => 1, 'mark' => 1, 'type' => 3])
  259. ->where(function ($query) use ($userId) {
  260. $query->where(['to_uid' => $userId]);
  261. })->count('id');
  262. $result = $this->model->where(['status' => 1, 'mark' => 1, 'type' => 1])
  263. ->where(function ($query) use ($userId) {
  264. $query->where(['to_uid' => $userId]);
  265. })->select(['chat_key'])->groupBy('chat_key')->get();
  266. $result = $result ? $result->toArray() : [];
  267. $counts['message'] = count($result);
  268. return $counts;
  269. }
  270. /**
  271. * 消息数量
  272. * @param $userId
  273. * @return int[]
  274. */
  275. public function getUnReadCount($userId)
  276. {
  277. $count = $this->model->where(['status' => 1, 'mark' => 1, 'type' => 1,'is_read'=>2])
  278. ->where(function ($query) use ($userId) {
  279. $query->where(['to_uid' => $userId]);
  280. })->count('id');
  281. return $count;
  282. }
  283. /**
  284. * 获取最新的聊天消息
  285. * @param $chatKey 聊天窗口标识
  286. * @return array|mixed
  287. */
  288. public function getTempInfo($chatKey)
  289. {
  290. $cacheKey = "caches:chats:temp:{$chatKey}";
  291. $info = RedisService::get($cacheKey);
  292. if ($info) {
  293. return $info;
  294. }
  295. $info = $this->model->from('chat_message as a')
  296. ->leftJoin('member as m', 'm.id', '=', 'a.from_uid')
  297. ->leftJoin('member as m1', 'm1.id', '=', 'a.to_uid')
  298. ->where(['a.chat_key' => $chatKey, 'a.status' => 1, 'a.mark' => 1])
  299. ->select(['a.id', 'a.message','a.from_uid','a.to_uid', 'a.is_read', 'a.message_type', 'a.create_time', 'm.username as from_username', 'm.avatar as from_avatar', 'm1.username as to_username', 'm1.avatar as to_avatar'])
  300. ->orderBy('create_time', 'desc')
  301. ->orderBy('id', 'desc')
  302. ->first();
  303. $info = $info? $info->toArray() : [];
  304. if ($info) {
  305. $info['from_username_text'] = $info['from_username'] ? format_account($info['from_username']) : '客服';
  306. $info['to_username_text'] = $info['to_username'] ? format_account($info['to_username']) : '客服';
  307. $info['message_url'] = $info['message_type'] == 2 ? get_image_url($info['message']) : '';
  308. $info['time_text'] = $info['create_time'] ? format_time(strtotime($info['create_time'])) : '刚刚';
  309. RedisService::set($cacheKey, $info, rand(3, 5));
  310. }
  311. return $info;
  312. }
  313. /**
  314. * 添加或编辑
  315. * @return array
  316. */
  317. public function saveData($data)
  318. {
  319. $data = [
  320. 'type' => isset($data['type']) ? $data['type'] : 1,
  321. 'message_type' => isset($data['message_type']) ? $data['message_type'] : 1,
  322. 'from_uid' => isset($data['from_uid']) ? $data['from_uid'] : 1,
  323. 'to_uid' => isset($data['to_uid']) ? $data['to_uid'] : 1,
  324. 'order_no' => isset($data['order_no']) ? $data['order_no'] : '',
  325. 'chat_key' => getChatKey($data['from_uid'], $data['to_uid']),
  326. 'message' => isset($data['message']) ? $data['message'] : '',
  327. 'create_time' => time(),
  328. 'update_time' => time(),
  329. 'is_read' => 2,
  330. 'status' => 1,
  331. 'mark' => 1,
  332. ];
  333. // 清除旧记录
  334. $time = ConfigService::make()->getConfigByCode('chat_expired_time');
  335. $time = $time? $time : 30;
  336. $this->model->where('create_time','<=', $time * 24 * 3600)->delete();
  337. return $this->model->insertGetId($data);
  338. }
  339. /**
  340. * 推送保存消息,如订单消息
  341. * @param $data 消息数据
  342. * @return int|number
  343. */
  344. public function pushMessage($data)
  345. {
  346. return $this->model->edit($data);
  347. }
  348. /**
  349. * 获取最新
  350. * @param $businessId
  351. * @return array
  352. */
  353. public function getOrderNotify($businessId)
  354. {
  355. $cacheKey = "caches:orders:notify:{$businessId}";
  356. $info = RedisService::get($cacheKey);
  357. if($info){
  358. return $info;
  359. }
  360. $info = $this->model->from('chat_message as a')
  361. ->leftJoin('trade_order as b','b.order_no','=','a.order_no')
  362. ->where('a.create_time','>=', time() - 10)
  363. ->where(['a.to_uid'=> $businessId,'a.is_read'=>2,'a.mark'=>1,'a.status'=>1])
  364. ->whereIn('a.type',[2])
  365. ->select(['a.id','a.type','a.from_uid','a.to_uid','a.order_no','a.message','b.type as order_type'])
  366. ->orderBy('a.create_time','desc')
  367. ->first();
  368. $info = $info? $info->toArray() : [];
  369. if($info){
  370. $this->model->where(['id'=> $info['id']])->update(['is_read'=>1,'update_time'=>time()]);
  371. RedisService::set($cacheKey, $info, rand(3,5));
  372. }
  373. return $info? $info : [];
  374. }
  375. }