// +---------------------------------------------------------------------- namespace App\Services\Api; use App\Models\ImChatModel; use App\Models\MerchantModel; use App\Models\MessageModel; use App\Services\BaseService; use App\Services\ConfigService; use App\Services\RedisService; /** * 站内消息服务管理-服务类 * @author laravel开发员 * @since 2020/11/11 * Class MessageService * @package App\Services\Api */ class MessageService extends BaseService { // 静态对象 protected static $instance = null; /** * 构造函数 * @author laravel开发员 * @since 2020/11/11 * MessageService constructor. */ public function __construct() { $this->model = new MessageModel(); } /** * 静态入口 * @return static|null */ public static function make() { if (!self::$instance) { self::$instance = (new static()); } return self::$instance; } /** * 消息列表 * @param $userId * @param $params * @param int $pageSize * @return array */ public function getDataList($userId, $params, $pageSize=0) { $page = request()->post('page', 1); $cacheKey = "caches:messages:history_{$page}_".md5($userId.json_encode($params). $pageSize); $datas = RedisService::get($cacheKey); if($datas) { return $datas; } $where = ['a.status'=>1,'a.mark'=>1]; $field = ['a.id','a.title','a.type','a.msg_type','a.chat_type','a.description','a.content','a.from_user_name','a.from_user_avatar','a.from_uid','a.to_user_name','a.to_user_avatar','a.to_uid','a.create_time','a.is_read','a.pages','a.status']; $datas = $this->model->from('message as a') ->leftJoin('member as b','b.id','=','a.from_uid') ->leftJoin('member as c','c.id','=','a.to_uid') ->where($where) ->where(function($query) use($params,$userId){ $fromUid = isset($params['from_uid'])? intval($params['from_uid']) : 0; if($fromUid){ $query->where('a.from_uid', $fromUid); } $type = isset($params['type'])? intval($params['type']) : 0; if($type){ $query->where('a.type', $type); } if($type != 9){ $query->where('a.to_uid', $userId); } $chatType = isset($params['chat_type'])? intval($params['chat_type']) : 0; if($chatType){ $query->where('a.chat_type', $chatType); } $chatKey = isset($params['chat_key'])? trim($params['chat_key']) : ''; if($chatKey){ $query->where('a.chat_key', $chatKey); } })->select($field) ->orderBy('a.create_time','desc') ->orderBy('a.id','desc') ->paginate($pageSize > 0 ? $pageSize : 9999999); $datas = $datas ? $datas->toArray() : []; if ($datas) { $ids = []; foreach ($datas['data'] as &$item) { $ids[] = $item['id']; $item['time_text'] = isset($item['create_time']) && $item['create_time']? dateForWeek($item['create_time']) : ''; $item['content'] = $item['msg_type'] ==2? get_images_preview(json_decode($item['content'],true),'') : $item['content']; $item['from_user_avatar'] = $item['from_user_avatar']? get_image_url($item['from_user_avatar']) : get_image_url('/images/member/logo.png'); $item['to_user_avatar'] = $item['to_user_avatar']? get_image_url($item['to_user_avatar']) : get_image_url('/images/member/logo.png'); } unset($item); // 更新已读 if($ids){ $this->model->whereIn('id', $ids)->update(['is_read'=> 1,'update_time'=>time()]); } arsort($datas['data'], true); $datas['data'] = array_reverse($datas['data'], false); RedisService::set($cacheKey, $datas, rand(3,5)); } return [ 'list'=> isset($datas['data'])? $datas['data'] : [], 'total'=> isset($datas['total'])? $datas['total'] : 0, 'pageSize'=>$pageSize ]; } /** * 获取站内消息窗口列表 * @param $userId * @return array|mixed */ public function getGroupList($userId) { $cachekey = "caches:messages:topList_{$userId}"; $datas = RedisService::get($cachekey); if($datas){ return $datas; } $types = [1,4,5]; $setting = MemberSettingService::make()->getSetting($userId); if($setting){ foreach ($setting as $k => $v){ if($k == 'receive_order'){ $types[] = 2; }else if ($k == 'receive_account'){ $types[] = 3; } } asort($types); }else{ $types = [1,2,3,4,5]; } $field = ['title','type','to_uid','description','is_read','create_time']; $datas = $this->model->where(['to_uid'=> $userId,'status'=>1,'mark'=>1]) ->whereIn('type', $types) ->groupBy('type') ->orderBy('type','asc') ->orderBy('is_read','desc') ->orderBy('create_time','desc') ->select($field) ->get(); $datas = $datas? $datas->toArray() : []; $total = 0; if($datas){ $titles = [1=>'公告通知',2=>'订单通知',3=>'账户通知',4=>'客服通知',5=>'互动消息']; foreach($datas as &$item){ $item['title'] = isset($titles[$item['type']])? $titles[$item['type']] : '消息通知'; $data = $this->getNewMessage($item['type'],0, $userId); $item['description'] = isset($data['description']) && $data['description']? $data['description'] : (isset($data['message'])? mb_substr($data['message'],0,20,'utf-8'): lang('有新消息')); $item['create_time'] = isset($data['create_time']) && $data['create_time']? $data['create_time'] : ''; $item['time_text'] = isset($item['create_time']) && $item['create_time'] ? dateFormat($item['create_time']) : ''; $item['create_time'] = isset($item['create_time']) ? datetime($item['create_time'], 'Y-m-d H.i.s') : ''; $unread = $this->getUnreadCount($userId,0, $item['type']); $item['unread'] = intval($unread); $total += intval($unread); } RedisService::set($cachekey, ['list'=>$datas,'total'=>$total,'types'=>$types], rand(3,5)); } return ['list'=>$datas,'total'=> $total,'types'=>$types]; } /** * 聊天分组消息 * @param $userId * @param $params * @param int $pageSize * @return array */ public function getDataListFromatKey($userId, $params, $pageSize=0) { $page = request()->post('page', 1); $cacheKey = "caches:message:chat_{$page}_".md5($userId.json_encode($params).$pageSize); $datas = RedisService::get($cacheKey); $data = isset($datas['data'])? $datas['data'] : []; if($datas && $data) { return [ 'unread'=> isset($datas['unReadCount'])? $datas['unReadCount'] : 0, 'total'=> isset($datas['total'])? $datas['total'] : 0, 'list'=> $data, 'pageSize'=> $pageSize, 'cache'=> true, ]; } $where = ['a.type'=>9,'a.status'=> 1,'a.mark'=>1]; $expire = ConfigService::make()->getConfigByCode('chat_log_expire'); $expire = $expire? $expire*86400 : 60*86400; $field = ['a.id','a.chat_key','a.from_user_id','a.to_user_id','a.msg_type','a.create_time','a.video_time','a.is_connect','a.is_read','a.from_is_show','a.to_is_show','a.status','b.avatar as from_avatar','b.nickname as from_nickname','c.avatar as to_avatar','c.nickname as to_nickname']; $datas = $this->model->from('imchat as a') ->where($where) ->where('a.chat_key','>', 0) ->where('a.create_time','>=', time() - $expire) ->where(function($query) use($params){ $chatKey = isset($params['chat_key'])? trim($params['chat_key']) : ''; if($chatKey){ $query->where('a.chat_key', $chatKey); } $isRead = isset($params['is_read'])? intval($params['is_read']) : 0; if($isRead){ $query->where('a.is_read', $isRead); } $chatType = isset($params['chat_type'])? intval($params['chat_type']) : 0; if($chatType){ $query->where('a.chat_type', $chatType); } }) ->select($field) ->groupBy('chat_key') ->orderBy('a.create_time','desc') ->orderBy('a.id','desc') ->paginate($pageSize > 0 ? $pageSize : 9999999); $datas = $datas ? $datas->toArray() : []; $unReadCount = 0; if ($datas) { foreach ($datas['data'] as &$item) { $item['from_user_avatar'] = isset($item['from_user_avatar']) && $item['from_user_avatar'] ? get_image_url($item['from_user_avatar']) : get_image_url('/images/member/logo.png'); $item['to_user_avatar'] = isset($item['to_user_avatar']) && $item['to_user_avatar'] ? get_image_url($item['to_user_avatar']) : get_image_url('/images/member/logo.png'); $data = $this->getNewMessage(0,$item['chat_key']); $item['description'] = isset($data['description']) && $data['description']? $data['description'] : (isset($data['message'])? mb_substr($data['message'],0,20,'utf-8'):lang('有新消息')); $item['create_time'] = isset($data['create_time']) && $data['create_time']? $data['create_time'] : ''; $item['time_text'] = isset($item['create_time']) && $item['create_time'] ? dateFormat($item['create_time']) : ''; $item['create_time'] = isset($item['create_time']) ? datetime($item['create_time'], 'Y-m-d H.i.s') : ''; $item['unread'] = $this->getUnreadCount($userId, $item['chat_key'], 0); $unReadCount += intval($item['unread']); } unset($item); $datas['unReadCount'] = $unReadCount; RedisService::set($cacheKey, $datas, rand(3, 5)); } return [ 'unread'=> $unReadCount, 'total'=> isset($datas['total'])? $datas['total'] : 0, 'list'=> isset($datas['data'])? $datas['data'] : [], 'pageSize'=> $pageSize, 'cache'=> false, ]; } /** * 获取最新消息 * @param $chatKey * @return mixed */ public function getNewMessage($type=0, $chatKey=0, $userId=0) { $cacheKey = "caches:messages:new_{$type}_{$chatKey}_{$userId}"; $data = RedisService::get($cacheKey); if($data){ return $data; } $where = ['status'=>1,'mark'=>1]; if($type){ $where['type'] = $type; } if($chatKey){ $where['chat_key'] = $chatKey; } if($userId){ $where['to_uid'] = $userId; } $data = $this->model->where($where)->select('id','description','msg_type','content','create_time') ->orderBy('create_time','desc') ->orderBy('id','desc') ->first(); $data = $data? $data->toArray() : []; if($data){ if($data['msg_type'] ==2){ $data['description'] = '[图片]'; } else if($data['msg_type'] == 3){ $data['description'] = '[视频聊天]'; } else if($data['msg_type'] == 4){ $data['description'] = '[直播间分享]'; } RedisService::set($cacheKey, $data, rand(3, 5)); } return $data; } /** * 获取未读消息数量 * @param $userId * @return array|mixed */ public function getBarCount($userId, $type=0) { $cacheKey = "caches:messages:barCount:{$userId}_{$type}"; $data = RedisService::get($cacheKey); if($data){ return $data; } $data1 = $this->getUnreadCount($userId, $type); $data1 = $data1? intval($data1) : 0; $data2 = ImChatService::make()->getUnreadCount($userId); $data = $data1+$data2; RedisService::set($cacheKey, $data, rand(3, 5)); return $data; } /** * 获取 * @param $userId * @return array|mixed */ public function getUnreadCount($userId, $chatKey=0, $type=0) { $cacheKey = "caches:messages:unReadCount:{$userId}_{$chatKey}_{$type}"; $data = RedisService::get($cacheKey); if(RedisService::exists($cacheKey)){ return $data; } $where = ['to_uid'=> $userId,'status'=>1,'is_read'=>2,'mark'=>1]; if($type>0){ $where['type'] = $type; } if($chatKey){ $where['chat_key'] = $chatKey; } $data = $this->model->where($where)->count('id'); RedisService::set($cacheKey, $data, rand(3, 5)); return $data; } /** * 验证发送消息或者内容是否有屏蔽词 * @param $message 消息或内容 * @param $type 是否返回屏蔽后内容:1-是 * @return bool */ public function filterMessage($message, $type = 1) { $filter = ConfigService::make()->getConfigByCode('chat_sensitive'); $filter = !empty($filter)? explode('、', $filter) : []; $filter = array_filter($filter); if($filter){ if($type != 2){ foreach ($filter as $kw){ $message = preg_replace("/{$kw}/",'***', $message); } }else{ foreach ($filter as $kw){ if(preg_match("/{$kw}/", $message)){ return false; } } } // 手机号、邮箱、网址 if($type == 1){ $message = preg_replace("/^(1[3-9][0-9]{9})$/", '***',$message); $message = preg_replace("/([a-z0-9&\-_.]+@[\w\-_]+([\w\-.]+)?\.[\w\-]+)/is", '***',$message); $message = str_replace(['https:','http:','.com','.cn','.net','.top','www.'], '***',$message); $message = preg_replace("/([a-zA-Z0-9][a-zA-Z0-9\_]{6,20})/", '***',$message); $message = preg_replace("/\*{3}\*{1,}/",'***', $message); } } return $type == 3 && $message === '***'? '' : $message; } /** * 已读 * @param $userId 用户ID * @param $chatKey 聊天窗口ID * @return bool */ public function setRead($userId, $type=0, $chatKey='') { $where = ['to_uid'=> $userId]; if($type){ $where['type'] = $type; } if($chatKey){ $where['chat_key'] = $chatKey; } $this->model->where($where)->update(['is_read'=>1,'update_time'=>time()]); // 清除缓存 RedisService::keyDel("caches:messages:bar*"); RedisService::keyDel("caches:messages:new_*"); RedisService::keyDel("caches:messages:topList_{$userId}"); return true; } /** * 隐藏 * @param $userId * @param int $expire * @return mixed */ public function setHide($userId, $type) { $this->model->where(['to_uid'=>$userId,'type'=> $type,'status'=> 1,'mark'=>1]) ->update(['update_time'=>time(),'is_read'=>1,'status'=> 3]); // 清除缓存 RedisService::keyDel("caches:messages:bar*"); RedisService::keyDel("caches:messages:new_*"); RedisService::keyDel("caches:messages:topList_{$userId}"); return true; } /** * 清除历史 * @param $userId * @param int $expire * @return mixed */ public function clear($userId, $msgType) { $this->model->where(['to_uid'=>$userId,'type'=> $msgType,'mark'=>1]) ->update(['update_time'=>time(),'mark'=>0]); // 清除缓存 RedisService::keyDel("caches:messages:bar*"); RedisService::keyDel("caches:messages:new_*"); RedisService::keyDel("caches:messages:topList_{$userId}"); return true; } /** * 清除历史 * @param $userId * @param int $expire * @return mixed */ public function clearAll($userId) { $expire = ConfigService::make()->getConfigByCode('chat_log_expire'); $expire = $expire>0? $expire : 60; $this->model->where(['to_uid'=>$userId,'mark'=>0]) ->where('update_time','<', time() - 7*86400) ->delete(); // 清除缓存 RedisService::keyDel("caches:messages:bar*"); RedisService::keyDel("caches:messages:new_*"); RedisService::keyDel("caches:messages:topList_{$userId}"); return $this->model->where(['to_uid'=>$userId,'mark'=>1]) ->where('create_time','<', time() -$expire*86400) ->update(['update_time'=>time(),'mark'=>0]); } }