Files
xk-api-yii/service/modules/v1/controllers/ImController.php

746 lines
32 KiB
PHP
Raw Normal View History

2024-09-19 11:32:39 +08:00
<?php
namespace service\modules\v1\controllers;
use common\core\BaseServiceController;
use common\enums\ImMessageSendTypeEnum;
use common\enums\ImSessionStatusEnum;
use common\enums\ImSessionTypeEnum;
use common\enums\OrderAcceptEnum;
use common\enums\UserRoleEnum;
use common\forms\ImMessageForm;
use common\helpers\ArrayHelper;
use common\helpers\FuncHelper;
use common\models\DoctorInfo;
use common\models\ImMessage;
use common\models\ImMessageSession;
use common\models\LeadInfo;
use common\models\Order;
use common\models\PharmacistrInfo;
use common\models\User;
use yii\base\Exception;
/**
* @doc-module Im
*/
class ImController extends BaseServiceController
{
public $types;//可以获取的会话类型,导医和客服分别获取的不一样
public function beforeAction($action)
{
$parent = parent::beforeAction($action); // TODO: Change the autogenerated stub
switch(\Yii::$app->user->identity->role)
{
case UserRoleEnum::DOCTOR:
$this->types = [ImSessionTypeEnum::USER_DOC];
break;
case UserRoleEnum::DRUG:
$this->types = [ImSessionTypeEnum::DRUG_SERV];
break;
case UserRoleEnum::LEADER:
//用户-导师
$this->types = [ImSessionTypeEnum::USER_LEAD];//导医的列表只获取跟用户的聊天,跟客服的聊天单独
break;
case UserRoleEnum::SERVICE:
//医生-客服,导医-客服,药师-客服
$this->types = [ImSessionTypeEnum::DOC_SERV,ImSessionTypeEnum::LEAD_SERV,ImSessionTypeEnum::DRUG_SERV];
break;
default:
throw new Exception('参数异常');
break;
}
return $parent;
}
/**
* 医生和客服
*/
/**
* 药师和客服
*/
/**
* 标记已读
*/
/**
* @doc-name 结束会话
* @doc-param int ims_id 会话id
* @doc-param int user_id 用户id
*/
public function actionOverSession()
{
$ims_id = \Yii::$app->request->post('ims_id');
$user_id = \Yii::$app->request->post('user_id');
if (!$ims_id)throw new \yii\db\Exception('会话ims_id不能为空');
if (!$user_id)throw new \yii\db\Exception('用户id不能为空');
$imMessageSession= ImMessageSession::find()->where([
'id'=>$ims_id,
'user_id'=>$user_id,
'service_id'=>\Yii::$app->user->identity->getId(),
'status'=>0
])->one();
if (!$imMessageSession)throw new \yii\db\Exception('聊天消息会话不存在或已结束');
ImMessageSession::updateAll(['status'=>10],
['id'=>$ims_id,
'user_id'=>$user_id,
'service_id'=>\Yii::$app->user->identity->getId()]);
return ['会话已结束'];
}
/**
* @doc-name 导医客服会话列表
* @doc-param string keyword 客户名称或者聊天记录
* @doc-return mixed ImMessageSession{id,type,@User{name-string-名称,avatar-string-头像},noread_count-int-未读数量,@Last{created_at-int-时间,created_at_format-string-格式化时间,content-string-内容}} 会话列表
*/
public function actionSessionList()
{
$post = \Yii::$app->request->post();
$keyword = ArrayHelper::getValue($post,'keyword','');
switch(\Yii::$app->user->identity->role)
{
case UserRoleEnum::LEADER:
//用户-导医
$types = [ImSessionTypeEnum::USER_LEAD];
if($keyword){
$id_arr = User::find()->where(['like','nickname',$keyword])->select('id')->column();
$ims_id_arr = ImMessageSession::find()->where([
'service_id' => \Yii::$app->user->identity->id,
'user_id' => $id_arr,
'type' => $types,
'status' => ImSessionStatusEnum::ING,//这边只查进行中的
'is_delete' => 0
])->addSelect('id')->column();
//查询到所有符合的用户昵称的会话
//查询到符合内容的会话这里的id就是满足查询条件的会话的id - 跟上边是or的关系
$query1 = ImMessage::find()->where([
'service_id' => \Yii::$app->user->identity->id,
'is_delete' => 0,
])
->andWhere([
'or',
['like','content',$keyword],
['ims_id'=>$ims_id_arr]
])
->addSelect('ims_id,MAX(id) as id,max(created_at) as created_at')->groupBy('ims_id')->orderBy('id desc');
}else{
//最新的消息排在最上边,不管是谁发送的,不管已读未读
$query1 = ImMessage::find()->where([
'is_delete' => 0,
])->addSelect('ims_id,MAX(id) as id,max(created_at) as created_at')->groupBy('ims_id')->orderBy('id desc');
}
break;
case UserRoleEnum::SERVICE:
//医生-客服,导医-客服,药师-客服
$types = [ImSessionTypeEnum::DOC_SERV,ImSessionTypeEnum::LEAD_SERV,ImSessionTypeEnum::DRUG_SERV];
if($keyword){
//查询用户昵称
$su_id_arr1 = DoctorInfo::find()->where(['like','name',$keyword])->select('su_id')->column();
$su_id_arr2 = LeadInfo::find()->where(['like','name',$keyword])->select('su_id')->column();
$su_id_arr3 = PharmacistrInfo::find()->where(['like','name',$keyword])->select('su_id')->column();
$su_id_arr = array_merge($su_id_arr1,$su_id_arr2,$su_id_arr3);
$ims_id_arr = ImMessageSession::find()->where([
'service_id' => \Yii::$app->user->identity->id,
'user_id' => $su_id_arr,
'type' => $types,
'status' => ImSessionStatusEnum::ING,//这边只查进行中的
'is_delete' => 0
])->addSelect('id')->column();
//查询到所有符合的用户昵称的会话
//查询到符合内容的会话这里的id就是满足查询条件的会话的id - 跟上边是or的关系
$query1 = ImMessage::find()->where([
'service_id' => \Yii::$app->user->identity->id,
'is_delete' => 0,
])->andWhere([
'or',
['like','content',$keyword],
['ims_id'=>$ims_id_arr]
])->addSelect('ims_id,MAX(id) as id,max(created_at) as created_at')->groupBy('ims_id')->orderBy('id desc');
}else{
//最新的消息排在最上边,不管是谁发送的,不管已读未读
$query1 = ImMessage::find()->where([
'is_delete' => 0,
])->addSelect('ims_id,MAX(id) as id,max(created_at) as created_at')->groupBy('ims_id')->orderBy('id desc');
}
break;
default:
throw new Exception('参数异常');
break;
}
$sessions_query = ImMessageSession::find()->alias('ims')->select([
'ims.*',
])->addSelect('l.id as last_id,l.created_at as last_time')->where([
'ims.service_id' => \Yii::$app->user->identity->id,
'ims.type' => $types,
'ims.status' => ImSessionStatusEnum::ING,//这边只查进行中的
'ims.is_delete' => 0
]);
if($keyword){
$sessions_query->innerJoin('(' . $query1->createCommand()->getRawSql() . ') l', 'ims.id = l.ims_id');
}else{
$sessions_query->leftJoin('(' . $query1->createCommand()->getRawSql() . ') l', 'ims.id = l.ims_id');
};
$sessions = $sessions_query->orderBy('l.created_at desc,ims.id desc')->all();
return count($sessions) ? ArrayHelper::toArray($sessions,[
ImMessageSession::class => [
'id',
'type',
'user' => function($model){
switch($model->type) {
case ImSessionTypeEnum::USER_USER:
case ImSessionTypeEnum::USER_DOC:
case ImSessionTypeEnum::USER_LEAD:
$user = User::findOne($model->user_id);
return [
'name' => $user->nickname,
'avatar' => $user->avatarurl,
];
break;
case ImSessionTypeEnum::DOC_SERV:
return [
'name' => $model->serviceUserByUserId->docInfo->name,
'avatar' => $model->serviceUserByUserId->docInfo->name,
];
break;
case ImSessionTypeEnum::DRUG_SERV:
return [
'name' => $model->serviceUserByUserId->drugInfo->name,
'avatar' => $model->serviceUserByUserId->drugInfo->avatar,
];
break;
case ImSessionTypeEnum::LEAD_SERV:
return [
'name' => $model->serviceUserByUserId->leadInfo->name,
'avatar' => $model->serviceUserByUserId->leadInfo->avatar,
];
break;
}
},
'noread_count' => function($model){
$count = ImMessage::find()->where([
'ims_id' => $model->id,
'read_status' => 0,
'type' => ImMessageSendTypeEnum::USER_SEND,
'is_delete' => 0
])->count();
return $count;
},
'last' => function($model){
$message = ImMessage::findOne($model->last_id);
if($message){
return [
'created_at' => $model->last_time,
'created_at_format' => FuncHelper::time_tran($model->last_time),
'content' => $message->content
];
}else{
return [];
}
}
]
]) : [];
}
/**
* @doc-name 会话消息记录
* @doc-param int ims_id 会话id
* @doc-param int page 页码 1 optional
* @doc-param int page_size 每页条数 20 optional
* @doc-return mixed @Session{ImMessageSession{*,@User-mixed-用户信息{name-string-名称,avatar-string-头像},@ServiceUser-mixed-服务人员信息{name-string-名称,avator-string-头像}}} 会话信息
* @doc-return mixed @List{ImMessage{*,@User-mixed-用户信息{name-string-名称,avatar-string-头像},@ServiceUser-mixed-服务人员信息{name-string-名称,avator-string-头像}}} 消息记录
* @doc-return mixed @Pagination{total_count-int-总数量,page_count-int-总页数,current_page-int-当前页,per_page-int-每页条数} 分页数据
*/
public function actionMessageList()
{
$post = \Yii::$app->request->post();
$this->requestValidate($post,[
['ims_id','required']
]);
$imMessageSession = ImMessageSession::find()->with('user','serviceUser')->where([
'id' => $post['ims_id'],
'service_id' => \Yii::$app->user->identity->id,
])->with('order')->one();
$session = $imMessageSession ? ArrayHelper::toArray($imMessageSession,[
ImMessageSession::class => [
'id','user_id','service_id','type','status','created_at',
'order',
'user' => function($model){
switch($model->type) {
// case ImSessionTypeEnum::USER_USER:
case ImSessionTypeEnum::USER_DOC:
case ImSessionTypeEnum::USER_LEAD:
return [
'name' => $model->user->nickname,
'avatar' => $model->user->avatarurl,
];
break;
case ImSessionTypeEnum::DOC_SERV:
return [
'name' => $model->serviceUserByUserId->docInfo->name,
'avatar' => $model->serviceUserByUserId->docInfo->avatar,
];
break;
case ImSessionTypeEnum::DRUG_SERV:
return [
'name' => $model->serviceUserByUserId->drugInfo->name,
'avatar' => $model->serviceUserByUserId->drugInfo->avatar,
];
break;
case ImSessionTypeEnum::LEAD_SERV:
return [
'name' => $model->serviceUserByUserId->leadInfo->name,
'avatar' => $model->serviceUserByUserId->leadInfo->avatar,
];
break;
}
},
'serviceUser' => function($model){
switch($model->type) {
// case ImSessionTypeEnum::USER_USER:
case ImSessionTypeEnum::USER_DOC:
return [
'name' => $model->serviceUser->docInfo->name,
'avatar' => $model->serviceUser->docInfo->avatar,
];
break;
case ImSessionTypeEnum::USER_LEAD:
return [
'name' => $model->serviceUser->leadInfo->name,
'avatar' => $model->serviceUser->leadInfo->avatar,
];
break;
case ImSessionTypeEnum::DOC_SERV:
case ImSessionTypeEnum::DRUG_SERV:
case ImSessionTypeEnum::LEAD_SERV:
return [
'name' => $model->serviceUser->servInfo->name,
'avatar' => $model->serviceUser->servInfo->avatar,
];
break;
}
}
],
Order::class => [
'id',
'auto_over_time',
'image_limit_status',
'left_number',
'status' => function($model){
return Order::status_info($model);
},
'accept_status' => function($model){
return Order::accept_info($model);
},
]
]) : [];
$this->extend_result['session'] = $session;
$query = ImMessage::find()->where([
'ims_id' => $post['ims_id'],
'service_id' => \Yii::$app->user->identity->id,
'is_delete' => 0
])->with('imSession','user','serviceUser')->orderBy('id desc');
$this->field = [
ImMessage::class => [
'id','user_id','service_id','content','read_status','type','created_at',
'user' => function($model){
switch($model->imSession->type) {
// case ImSessionTypeEnum::USER_USER:
case ImSessionTypeEnum::USER_DOC:
case ImSessionTypeEnum::USER_LEAD:
return [
'name' => $model->user->nickname,
'avatar' => $model->user->avatarurl,
];
break;
case ImSessionTypeEnum::DOC_SERV:
return [
'name' => $model->serviceUserByUserId->docInfo->name,
'avatar' => $model->serviceUserByUserId->docInfo->avatar,
];
break;
case ImSessionTypeEnum::DRUG_SERV:
return [
'name' => $model->serviceUserByUserId->drugInfo->name,
'avatar' => $model->serviceUserByUserId->drugInfo->avatar,
];
break;
case ImSessionTypeEnum::LEAD_SERV:
return [
'name' => $model->serviceUserByUserId->leadInfo->name,
'avatar' => $model->serviceUserByUserId->leadInfo->avatar,
];
break;
}
},
'serviceUser' => function($model){
switch($model->imSession->type) {
// case ImSessionTypeEnum::USER_USER:
case ImSessionTypeEnum::USER_DOC:
return [
'name' => $model->serviceUser->docInfo->name,
'avatar' => $model->serviceUser->docInfo->avatar,
];
break;
case ImSessionTypeEnum::USER_LEAD:
return [
'name' => $model->serviceUser->leadInfo->name,
'avatar' => $model->serviceUser->leadInfo->avatar,
];
break;
case ImSessionTypeEnum::DOC_SERV:
case ImSessionTypeEnum::DRUG_SERV:
case ImSessionTypeEnum::LEAD_SERV:
return [
'name' => $model->serviceUser->servInfo->name,
'avatar' => $model->serviceUser->servInfo->avatar,
];
break;
}
}
],
];
return $this->create($query,$post);
}
/**
* @doc-name 待接入会话列表
* @doc-return mixed ImMessageSession{id,@User{name,avatar},@Last{content-string-消息内容,created_at-int-消息时间,created_at_format-string-格式后的时间}} 待接入会话列表
*/
public function actionWaitInList()
{
//这个就按最新的待接入会话在最上边
$query = ImMessageSession::find()->where([
'service_id' => 0,
'type' => $this->types,
'status' => ImSessionStatusEnum::ING
])->orderBy('id desc');
$sessions = $query->with('user','serviceUser')->all();
return count($sessions) ? ArrayHelper::toArray($sessions,[
ImMessageSession::class => [
'id' => 'id',
'user' => function($model){
switch($model->type) {
case ImSessionTypeEnum::USER_USER:
case ImSessionTypeEnum::USER_DOC:
case ImSessionTypeEnum::USER_LEAD:
return [
'name' => $model->user->nickname,
'avatar' => $model->user->avatarurl,
];
break;
case ImSessionTypeEnum::DOC_SERV:
return [
'name' => $model->serviceUserByUserId->docInfo->name,
'avatar' => $model->serviceUserByUserId->docInfo->avatar,
];
break;
case ImSessionTypeEnum::DRUG_SERV:
return [
'name' => $model->serviceUserByUserId->drugInfo->name,
'avatar' => $model->serviceUserByUserId->drugInfo->avatar,
];
break;
case ImSessionTypeEnum::LEAD_SERV:
return [
'name' => $model->serviceUserByUserId->leadInfo->name,
'avatar' => $model->serviceUserByUserId->leadInfo->avatar,
];
break;
}
},
'last' => function($model){
$message = ImMessage::find()->where([
'ims_id' => $model->id,
'user_id' => $model->user_id,
'is_delete' => 0
])->orderBy('id desc')->one();
if($message){
return [
'content' => $message->content,
'created_at' => $message->created_at,
'created_at_format' => FuncHelper::time_tran($message->created_at)
];
}else{
return [];
}
}
]
]) : [];
}
/**
* @doc-name 接入会话
* @doc-param ims_id 会话id
*/
public function actionSessionIn()
{
$post = \Yii::$app->request->post();
$this->requestValidate($post,[
['ims_id','required']
]);
$model = ImMessageSession::find()->where([
'id' => $post['ims_id'],
'type' => $this->types,
'service_id' => 0,
'status' => ImSessionStatusEnum::ING
])->one();
if(!$model){
throw new Exception('待接入会话不存在');
}
$count = ImMessageSession::updateAll(['service_id'=>\Yii::$app->user->identity->id,'in_time'=>time()],[
'id' => $post['ims_id'],
'type' => $this->types,
'service_id' => 0,
'status' => ImSessionStatusEnum::ING
]);
if(!$count){
throw new Exception('接入失败');
}
ImMessage::updateAll(['service_id'=>\Yii::$app->user->identity->id],[
'ims_id' => $post['ims_id']
]);
//这里可以给用户发一个已接入的提醒
//这里进行接入的消息发送
$form = new ImMessageForm();
$form->sessionIn($post['ims_id'],0,\Yii::$app->user->identity->role,[
'type' => 'session-in' //定义的类型是接入
]);
return [];
}
/**
* @doc-name 服务端发送消息
* @doc-desc session_type直接传递用会话返回的会话类型如果是医生药师导医端和客服的会话第一次可能没有会话id则直接会话id=0,会话类型当前角色+4客服 = 567否则直接传递会话id和会话类型客服现在只能接入医生药师导医的会话所以会有会话id和session_type
* @doc-param int ims_id 会话id
* @doc-param int session_type 会话类型1医生发给用户3导医发给用户5医生和客服会话6药师和客服7导医和客服
* @doc-param json content 消息内容
*/
public function actionMessageSend()
{
//服务端发送消息
$post = \Yii::$app->request->post();
$this->requestValidate($post,[
[['ims_id','session_type'],'required'],
['content','required','message'=>'消息内容不能为空']
]);
$form = new ImMessageForm();
$form->attributes = $post;
$form->from_id = \Yii::$app->user->identity->id;
switch($post['session_type'])
{
case ImSessionTypeEnum::USER_DOC: //医生给用户发消息
$form->type = ImMessageSendTypeEnum::SERVICE_SEND;
$ims = ImMessageSession::find()->where([
'id' => $post['ims_id'],
'is_delete' => 0
])->with('order')->one();
if(!$ims || !$ims->order){
throw new Exception('会话不存在或者会话订单不存在');
}
$order = $ims->order;
$form->to_id = $ims->user_id;
if($order->accept_status == OrderAcceptEnum::ACCEPTING ){
$form->sendMessage();
}else{
//其他情况-拒绝
throw new Exception('发送失败:订单非接诊状态,无法发送消息');
}
return [];
break;
case ImSessionTypeEnum::USER_LEAD: //导医给用户发消息 - 如果已经结束,则不能再发送 - 在下一步有判断
$form->type = ImMessageSendTypeEnum::SERVICE_SEND;
$ims = ImMessageSession::find()->where([
'id' => $post['ims_id'],
'service_id' => \Yii::$app->user->identity->id,
'type' => $post['session_type'],
'is_delete' => 0,
'status' => ImSessionStatusEnum::ING
])->one();
if(!$ims){
throw new Exception('会话不存在');
}
$form->to_id = $ims->user_id;
$form->sendMessage();
break;
case ImSessionTypeEnum::DOC_SERV://有可能是医生给客服发,也可能是客服给医生发 - 取决于当前的角色
if(\Yii::$app->user->identity->role == UserRoleEnum::DOCTOR){//医生给客服发,当前医生相当于user_id客服相当与service_id
$form->type = ImMessageSendTypeEnum::USER_SEND;
$query = ImMessageSession::find()->where([
'user_id' => \Yii::$app->user->identity->id,
'type' => $post['session_type'],
'is_delete' => 0,
'status' => ImSessionStatusEnum::ING
]);
if($post['ims_id']){
$query->andWhere([
'id' => $post['ims_id']
]);
}
$ims = $query->one();
if(!$ims){
$ims = new ImMessageSession();
$ims->user_id = \Yii::$app->user->identity->id;
$ims->type = $post['session_type'];
$ims->saveOrFail();
}
$form->ims_id = $ims->id;
$form->to_id = $ims->service_id;
$form->sendMessage();
}elseif(\Yii::$app->user->identity->role == UserRoleEnum::SERVICE){//客服给医生发
$form->type = ImMessageSendTypeEnum::SERVICE_SEND;
$ims = ImMessageSession::find()->where([
'id' => $post['ims_id'],
'service_id' => \Yii::$app->user->identity->id,
'type' => $post['session_type'],
'is_delete' => 0,
'status' => ImSessionStatusEnum::ING
])->one();
$form->to_id = $ims->user_id;
$form->sendMessage();
}else{
throw new Exception('客户端传递参数错误');
}
break;
case ImSessionTypeEnum::LEAD_SERV://有可能是导医给客服发,也可能是客服给导医发
if(\Yii::$app->user->identity->role == UserRoleEnum::LEADER){//导师给客服发,当前导师相当于user_id客服相当与service_id
$form->type = ImMessageSendTypeEnum::USER_SEND;
$query = ImMessageSession::find()->where([
'user_id' => \Yii::$app->user->identity->id,
'type' => $post['session_type'],
'is_delete' => 0,
'status' => ImSessionStatusEnum::ING
]);
if($post['ims_id']){
$query->andWhere([
'id' => $post['ims_id']
]);
}
$ims = $query->one();
if(!$ims){
$ims = new ImMessageSession();
$ims->user_id = \Yii::$app->user->identity->id;
$ims->type = $post['session_type'];
$ims->saveOrFail();
}
$form->ims_id = $ims->id;
$form->to_id = $ims->service_id;
$form->sendMessage();
}elseif(\Yii::$app->user->identity->role == UserRoleEnum::SERVICE){//客服给导师发
$form->type = ImMessageSendTypeEnum::SERVICE_SEND;
$ims = ImMessageSession::find()->where([
'id' => $post['ims_id'],
'service_id' => \Yii::$app->user->identity->id,
'type' => $post['session_type'],
'is_delete' => 0,
'status' => ImSessionStatusEnum::ING
])->one();
$form->to_id = $ims->user_id;
$form->sendMessage();
}else{
throw new Exception('客户端传递参数错误');
}
break;
case ImSessionTypeEnum::DRUG_SERV://有可能是药师给客服发,也可能是客服给药师发
if(\Yii::$app->user->identity->role == UserRoleEnum::DRUG){//药师给客服发
$form->type = ImMessageSendTypeEnum::USER_SEND;
$query = ImMessageSession::find()->where([
'user_id' => \Yii::$app->user->identity->id,
'type' => $post['session_type'],
'is_delete' => 0,
'status' => ImSessionStatusEnum::ING
]);
if($post['ims_id']){
$query->andWhere([
'id' => $post['ims_id']
]);
}
$ims = $query->one();
if(!$ims){
$ims = new ImMessageSession();
$ims->user_id = \Yii::$app->user->identity->id;
$ims->type = $post['session_type'];
$ims->saveOrFail();
}
$form->ims_id = $ims->id;
$form->to_id = $ims->service_id;
$form->sendMessage();
}elseif(\Yii::$app->user->identity->role == UserRoleEnum::SERVICE){//客服给药师发
$form->type = ImMessageSendTypeEnum::SERVICE_SEND;
$ims = ImMessageSession::find()->where([
'id' => $post['ims_id'],
'service_id' => \Yii::$app->user->identity->id,
'type' => $post['session_type'],
'is_delete' => 0,
'status' => ImSessionStatusEnum::ING
])->one();
$form->to_id = $ims->user_id;
$form->sendMessage();
}else{
throw new Exception('客户端传递参数错误');
}
break;
}
return [];
}
}