即时系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

443 lines
17 KiB

<?php
/**
* raingad IM [ThinkPHP6]
* @author xiekunyu <raingad@foxmail.com>
*/
namespace app\enterprise\model;
use app\BaseModel;
use app\common\controller\Upload;
use think\facade\Db;
use think\facade\Cache;
use think\model\concern\SoftDelete;
class Message extends BaseModel
{
use SoftDelete;
protected $deleteTime = 'delete_time';
protected $defaultSoftDelete = 0;
protected $pk="msg_id";
protected $json = ["extends"];
protected $jsonAssoc = true;
protected static $fileType=['file','image','video','voice','emoji'];
// 判断是否为拉黑发送的数据
protected $blackData = false;
// 添加聊天记录
public static function addData($data){
return Db::name('message')->insert($data);
}
// 更新消息状态
public static function editData($update,$map){
return Db::name('message')->where($map)->update($update);
}
// 查询聊天记录
public static function getList($map,$where,$sort,$listRows,$pageSize,$user_id){
$list= (new self())
->where($map)
->where($where)
->where(" (find_in_set({$user_id},`del_user`) = 0 or del_user is null)")
->order($sort)
->paginate(['list_rows'=>$listRows,'page'=>$pageSize]);
return $list;
}
// 发送消息
public function sendMessage($param,$globalConfig=false){
$is_group = $param['is_group'] ?? 0;
$uid=self::$uid;
if($param['toContactId']==-1 || $param['toContactId']==-2){
$is_group=0;
}
// 如果是系统账号,直接禁言
if($is_group>1){
$this->error=lang('im.forbidChat');
return false;
}
$sendInterval = $globalConfig['chatInfo']['sendInterval'] ?? 0;
// 如果设置了消息频率则验证
if ($sendInterval) {
if (Cache::has('send_' . $uid)) {
$this->error=lang('im.sendTimeLimit',['time'=>$sendInterval]);
return false;
}
}
if($param['type']=='text'){
// 限制文字内容长度
$text = strip_tags($param['content']);
$textLen = mb_strlen($text);
if ($textLen > 2048) {
$this->error=lang('im.msgContentLimit') . $textLen;
return false;
}
$param['content'] = preg_link($param['content']);
// 接入聊天内容检测服务
event('GreenText',['content'=>$param['content'],'service'=>"chat_detection"]);
}
$chatSetting = $globalConfig['chatInfo'];
if($param['toContactId']!=-1 && $param['toContactId']!=-2){
if ($is_group == 0) {
$kefuUser = [];
$status = $chatSetting['autoAddUser']['status'] ?? 0;
if ($status == 1) {
$kefuUser=$chatSetting['autoAddUser']['user_ids'] ?? [];
}
$manageUser=User::where([['status','=',1],['role','>',0]])->column('user_id');
$kefu=array_unique(array_merge($kefuUser,$manageUser));
$csUid = self::$userInfo['cs_uid'] ?? 0;
$manage=false;
// 发送者和接受者是客服或者管理员也可以发送消息
if(in_array($uid,$kefu) || in_array($param['toContactId'],$kefu)){
$manage=true;
}
if($chatSetting['simpleChat'] == 0 && !$manage){
$this->error=lang('im.forbidChat');
return false;
}
// 如果是单聊,并且是社区模式和不是自己的客服、需要判断是否是好友
if ($globalConfig['sysInfo']['runMode'] == 2 && $csUid != $param['toContactId'] && !$manage) {
// 判断我是不是对方的客服
$cus = User::where(['user_id' => $param['toContactId']])->value('cs_uid');
if ($cus != $uid) {
$friend = Friend::where(['friend_user_id' => $uid, 'create_user' => $param['toContactId']])->find();
if (!$friend) {
$this->error=lang('im.notFriend');
return false;
}
$otherFriend = Friend::where(['friend_user_id' => $param['toContactId'], 'create_user' => $uid])->find();
if (!$otherFriend) {
$this->error=lang('im.friendNot');
return false;
}
if ($friend['is_blacklist'] == 1) {
$param['del_user'] = $param['toContactId'];
}
if ($otherFriend['is_blacklist'] == 1) {
$param['del_user'] = $param['toContactId'];
}
}
}
}else{
// 群聊必须群成员才能发送消息
$group_id = explode('-', $param['toContactId'])[1] ?? '';
$toContactId=$group_id;
if(!$group_id){
$this->error=lang('system.parameterError');
return false;
}
if(!self::nospeak($group_id,$uid)){
return shutdown(lang('group.notSpeak'));
}
// 群聊必须群成员才能发送消息
$groupUser=GroupUser::where(['user_id'=>$uid,'status'=>1,'group_id'=>$group_id,'delete_time'=>0])->find();
if(!$groupUser){
$this->error = lang('group.notCustom');
return false;
}
if($groupUser['no_speak_time']>time()){
$this->error = lang('group.notSpeak',['time'=>date('Y-m-d H:i:s',$groupUser['no_speak_time'])]);
return false;
}
}
}
if ($sendInterval) {
Cache::set('send_' . $uid, time(), $sendInterval);
}
// 判断是否存在及数据有效性
if (isset($param['msg_id']) && is_numeric($param['msg_id'])) {
$where = ['msg_id' => $param['msg_id'], 'status' => 2];
$message = $this->where($where)->find();
if ($message) $this->blackData = true;
}
return self::sendMsg($param,$is_group,$this->blackData);
}
//实际发送消息
public static function sendMsg($param,$is_group=0,$blackData=false){
$uid=self::$uid ?: ($param['user_id'] ?? 1);
$toContactId=$param['toContactId'];
$manage=[];
if($is_group==1){
$group_id = explode('-', $param['toContactId'])[1] ?? '';
$chat_identify=$toContactId;
$toContactId=$group_id;
$manage=GroupUser::getGroupManage($group_id);
}else{
$chat_identify=chat_identify($param['user_id'],$toContactId);
}
$fileSzie=isset($param['file_size'])?$param['file_size']:'';
$fileName=isset($param['file_name'])?$param['file_name']:'';
$ossUrl=getDiskUrl();
// 如果是转发图片文件的消息,必须把域名去除掉
$content=$param['content'];
if(in_array($param['type'],self::$fileType)){
if(strpos($param['content'],$ossUrl)!==false){
$content=str_replace($ossUrl,'',$param['content']);
}
}
$param['content']=$content;
$atList=($param['at'] ?? null) ? array_map('intval', $param['at']): [];
// 如果at里面有0,代表@所有人
if($atList && in_array(0,$atList)){
$atList=GroupUser::where([['group_id','=',$toContactId],['status','=',1],['user_id','<>',$param['user_id']]])->column('user_id');
}
$at=$atList ? implode(',',$atList) : null;
if ($toContactId==-1) {
$is_group = 3;
}elseif ($toContactId==-2) {
$is_group = 4;
}
$data=[
'from_user'=>$param['user_id'],
'to_user'=>$toContactId,
'id'=>$param['id'],
'content'=>str_encipher($param['content'],true),
'plain_text'=>$param['plain_text']??'',
'chat_identify'=>$chat_identify,
'create_time'=>time(),
'type'=>$param['type'],
'is_group'=>$is_group,
'is_read'=>$is_group ? 1 : 0,
'file_id'=>$param['file_id'] ?? 0,
"file_cate"=>$param['file_cate'] ?? 0,
'file_size'=>$fileSzie,
'file_name'=>$fileName,
'at'=>$at,
'pid'=>$param['pid'] ?? 0,
'extends'=>($param['extends'] ?? null) ? $param['extends'] : null,
];
if ($param['type'] == 'video' && is_null($data['extends'])) {
$filePath = root_path().'public' . $param['content'];
$videoInfo=(new Upload())->getVideoCover($filePath);
if($videoInfo){
$extends=$videoInfo['videoInfo'];
$extends['poster']=getFileUrl($videoInfo['src']);
$data['extends']=$extends;
$param['extends']=$extends;
}else{
$data['poster']=getMainHost().'/static/common/img/video.png';
$param['poster']=$data['poster'];
}
}
if (isset($param['del_user']) && $param['del_user']) {
$data['del_user'] = $param['del_user'];
$data['status'] = 2;
} else {
$data['del_user'] = '';
$data['status'] = 1;
}
$message=new self();
$message->update(['is_last'=>0],['chat_identify'=>$chat_identify]);
if (isset($param['msg_id']) && $blackData) {
$message = $message->where('msg_id', $param['msg_id'])->find();
if (!$message) {
$message=new self();
}
}
$message->save($data);
if ($is_group > 1) $is_group = 0;
// 拼接消息推送
$type=$is_group?'group':'simple';
$sendData=$param;
$sendData['status']='succeed';
if (isset($data['status']) && $data['status'] == 2) {
$sendData['status']='failed';
}
$sendData['at']=$atList;
$sendData['msg_id']=$message->msg_id;
$sendData['is_read']=0;
$sendData['to_user']=$toContactId;
$sendData['role']=$manage[self::$uid] ?? 3;
$sendData['sendTime']=(int)$sendData['sendTime'];
//这里单聊中发送对方的消息,对方是接受状态,自己是对方的联系人,要把发送对象设置为发送者的ID。
if($is_group){
$sendData['toContactId']=$param['toContactId'];
// 将团队所有成员的未读状态+1
GroupUser::editGroupUser([['group_id','=',$toContactId],['user_id','<>',$uid]],['unread'=>Db::raw('unread+1')]);
}else{
$sendData['toContactId']=$uid;
}
$sendData['fromUser']['id']=(int)$sendData['fromUser']['id'];
$sendData['from_user']=(int)$sendData['fromUser']['id'];
$sendData['fileSize']=$fileSzie;
$sendData['fileName']=$fileName;
if(in_array($sendData['type'],self::$fileType)){
$sendData['content']=getFileUrl($sendData['content']);
if($sendData['type']=='image'){
$pre=1;
}else{
$pre=2;
}
$sendData['preview']=previewUrl($sendData['content'],$pre);
$sendData['extUrl']=getExtUrl($sendData['content']);
$sendData['download']= $sendData['file_id'] ? getMainHost().'/filedown/'.encryptIds($sendData['file_id']) : '';
}
if($is_group==0){
if ($sendData['status'] == 'succeed') {
$toContactId=[$toContactId,$param['user_id']];
} else {
$toContactId=[$param['user_id']];
}
}
$sendData['toUser']=$param['toContactId'];
$user=new User();
// 将聊天窗口的联系人信息带上,方便临时会话
$sendData['contactInfo']=$user->setContact($sendData['toContactId'],$is_group,$sendData['type'],$sendData['content']);
// 向发送方发送消息
wsSendMsg($toContactId,$type,$sendData,$is_group);
// 判断图片查看
if (isset($param['file_id']) && $param['file_id']) {
$res = MessageView::addView($message->msg_id,$param['user_id'],$param['file_id'], $data['content']);
if($res){
$src = File::where('file_id', $param['file_id'])->value('src');
if ($src) {
$sendData['content'] = getFileUrl($src);
$sendData['extUrl']= getExtUrl($src);
$sendData['preview']=previewUrl($src,$pre);
}
}
}
$sendData['toContactId']=$param['toContactId'];
return $sendData;
}
// 群禁言
public static function nospeak($group_id,$user_id){
$group=Group::find($group_id);
if($group->owner_id==$user_id){
return true;
}
if($group->setting){
$setting=json_decode($group->setting,true);
$nospeak=isset($setting['nospeak'])?$setting['nospeak']:0;
$role=GroupUser::where(['group_id'=>$group_id,'user_id'=>$user_id])->value('role');
if($nospeak==1 && $role>2){
return false;
}elseif($nospeak==2 && $role!=1){
return false;
}
}
return true;
}
// 将消息中的@用户加入到atListQueue中
public static function setAtread($messages,$user_id){
foreach($messages as $k=>$v){
if(!isset($v['at'])){
continue;
}
if($v['at'] && in_array($user_id,$v['at'])){
// $atListQueue=Cache::get("atListQueue");
// $atListQueue[$v['msg_id']][]=$user_id;
// Cache::set("atListQueue",$atListQueue);
$uniqueArr=array_unique($v['at']);
$key = array_search($user_id, $uniqueArr);
if ($key !== false) {
unset($uniqueArr[$key]);
}
self::where('msg_id',$v['msg_id'])->update(['at'=>implode(',',$uniqueArr)]);
}
}
}
// 设置自动删除提示消息
public static function setAutoDelMessageNotice($from_user,$to_user, $title,$is_group, $is_close = 0)
{
if ($is_group == 1) {
$chat_identify = "group-{$to_user}";
} else {
$chat_identify = chat_identify($from_user,$to_user);
}
$content = '已设置自动删除' . $title . '前发送的消息';
if ($is_close) $content = '关闭了自动删除计时器';
$data=[
'id' => \utils\Str::getUuid(),
'from_user'=>$from_user,
'to_user'=>$to_user,
'content'=>str_encipher($content,true),
'chat_identify'=>$chat_identify,
'create_time'=>time(),
'type'=>'event',
'is_group'=>$is_group,
'is_read'=>1,
'is_top'=>0,
'at'=>[],
'pid'=>0,
'is_undo'=>1
];
$message = new self();
$message->save($data);
$msgInfo = $data;
$msgInfo['msg_id'] = $message->msg_id;
$msgInfo['sendTime'] = $data['create_time'];
$msgInfo['toContactId'] = $msgInfo['is_group'] == 1 ? $msgInfo['chat_identify'] : $to_user;
$msgInfo['status']='successd';
$userList = User::matchUser([$msgInfo], true, 'from_user', 120);
$fromUser = $userList[$from_user];
if ($is_group) {
$msgInfo['content'] = $fromUser['realname'] . $data['content'];
}
$msgInfo['fromUser'] = $fromUser;
$msgInfo['download'] = '';
$msgInfo['extUrl'] = '';
$msgInfo['extends'] = null;
$msgInfo['fileName'] = null;
$msgInfo['fileSize'] = 0;
$msgInfo['file_cate'] = 0;
$msgInfo['file_id'] = 0;
$msgInfo['from_user'] = $from_user;
$msgInfo['preview'] = "";
$msgInfo['toContactId'] = $is_group ? $chat_identify :(int)$to_user;
return $msgInfo;
}
// 一键清除数据
public static function oneClickDelMsg($type)
{
switch ($type) {
case "user":
self::delMsg();
break;
case "group":
self::delMsg(1);
break;
case "all":
self::delMsg();
self::delMsg(1);
break;
default:
return false;
}
return true;
}
// 删除消息
public static function delMsg($is_group = 0)
{
$where = [
['is_group', '=', $is_group],
['file_id', '>', 0]
];
$model = new self();
$file_id_arr = $model->where($where)->column('file_id');
foreach ($file_id_arr as $file_id) {
File::syncDelFile($file_id);
}
$res = (new self())->where('is_group',$is_group)->select();
foreach ($res as $row) {
$row->force()->delete();
}
if ($is_group) {
$group_id_arr = (new Group())->column('group_id');
wsSendMsg($group_id_arr, 'delGroupAllMsg', [], 1);
} else {
$user_id_arr = (new User())->column('user_id');
wsSendMsg($user_id_arr, 'delUserAllMsg', [], 0);
}
}
}