From b03f38704dcfa96bf8233318b47e5b7340a278cf Mon Sep 17 00:00:00 2001 From: wucongxing <815046773@qq.com> Date: Fri, 10 Mar 2023 14:53:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Eim=E5=9B=9E=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Amqp/Consumer/AssignDoctorConsumer.php | 2 +- app/Controller/CallBackController.php | 210 ++++++++++++++++++++- app/Controller/UserController.php | 42 +++-- app/Model/Message.php | 86 +++++++++ app/Services/ImService.php | 44 +++++ config/config.php | 1 + extend/TencentIm/Message.php | 1 - 7 files changed, 362 insertions(+), 24 deletions(-) create mode 100644 app/Model/Message.php diff --git a/app/Amqp/Consumer/AssignDoctorConsumer.php b/app/Amqp/Consumer/AssignDoctorConsumer.php index 8a4406b..fd2ee32 100644 --- a/app/Amqp/Consumer/AssignDoctorConsumer.php +++ b/app/Amqp/Consumer/AssignDoctorConsumer.php @@ -216,7 +216,7 @@ class AssignDoctorConsumer extends ConsumerMessage $cloud_custom_data = array(); $cloud_custom_data['order_inquiry_id'] = $order_inquiry['order_inquiry_id']; $cloud_custom_data['inquiry_type'] = $order_inquiry['inquiry_type']; - $cloud_custom_data['message_type'] = 1;//1:系统发送 其余:用户发送 + $cloud_custom_data['message_type'] = 1;//消息类型(1:系统发送 其余:用户发送) $arg['CloudCustomData'] = json_encode($cloud_custom_data,JSON_UNESCAPED_UNICODE); diff --git a/app/Controller/CallBackController.php b/app/Controller/CallBackController.php index 3f4ae1a..30cd303 100644 --- a/app/Controller/CallBackController.php +++ b/app/Controller/CallBackController.php @@ -21,7 +21,10 @@ use Hyperf\Amqp\Producer; use Hyperf\DbConnection\Db; use Hyperf\HttpMessage\Stream\SwooleFileStream; use Hyperf\HttpMessage\Stream\SwooleStream; +use Hyperf\Redis\Redis; use Hyperf\Utils\ApplicationContext; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; use Psr\Http\Message\ResponseInterface; class CallBackController extends AbstractController @@ -111,6 +114,9 @@ class CallBackController extends AbstractController return $this->wxPayErrorReturn($e->getMessage()); } + Log::getInstance()->info("微信支付回调处理成功"); + Log::getInstance()->info("微信支付回调处理成功,开始发送系统问诊消息"); + try { if ($message['trade_state'] == "SUCCESS"){ if ($order_inquiry['inquiry_type'] == 2 || $order_inquiry['inquiry_type'] == 4){ @@ -178,9 +184,18 @@ class CallBackController extends AbstractController return $server->serve(); } + Log::getInstance()->info("微信支付回调处理成功,发送系统问诊消息成功"); + return $server->serve(); } + /** + * 微信退款回调 + * @return ResponseInterface + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws \Throwable + */ public function wxPayRefundCallBack(): ResponseInterface { try { @@ -200,7 +215,7 @@ class CallBackController extends AbstractController Log::getInstance()->info("微信退款回调数据:" . json_encode($message->toArray(),JSON_UNESCAPED_UNICODE)); return $server->serve(); - }catch (\Exception $e) { + } catch (\Exception $e) { // 验证失败 Db::rollBack(); Log::getInstance()->error("微信支付回调数据验证失败:" . $e->getMessage()); @@ -225,10 +240,195 @@ class CallBackController extends AbstractController ) ); } - // im回调 - public function imCallBack(){ + + // + + /** + * im回调 + * @return ResponseInterface + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function imCallBack(): ResponseInterface + { $request_params = $this->request->all(); - dump($request_params); - Log::getInstance()->info(json_encode($request_params,JSON_UNESCAPED_UNICODE)); + try { + Log::getInstance()->info("Im回调数据:" . json_encode($request_params,JSON_UNESCAPED_UNICODE)); + + if (empty($request_params['RequestTime']) || empty($request_params['Sign'])){ + Log::getInstance()->error("Im回调数据处理失败:缺少时间时间戳/签名字段"); + return $this->ImErrorReturn("缺少时间时间戳/签名字段"); + } + + // 鉴定回调签名 + $imService = new ImService(); + $result = $imService->validateSign($request_params['RequestTime'],$request_params['Sign']); + if (!$result){ + Log::getInstance()->error("Im回调数据处理失败:回调签名不匹配"); + return $this->ImErrorReturn("回调签名不匹配"); + } + + // 验证消息内容 + if (empty($request_params['MsgBody'])){ + Log::getInstance()->error("Im回调数据处理失败:消息内容错误"); + return $this->ImErrorReturn("消息内容错误,缺少MsgBody"); + } + + // 验证接收方user_id + if (empty($request_params['To_Account'])){ + Log::getInstance()->error("Im回调数据处理失败:接收用户错误"); + return $this->ImErrorReturn("消息内容错误,接收用户错误"); + } + + // 验证消息唯一id + if (empty($request_params['MsgKey'])){ + Log::getInstance()->error("Im回调数据处理失败:消息唯一标识错误"); + return $this->ImErrorReturn("消息内容错误,消息唯一标识错误"); + } + + // 验证消息重复性 + $params = array(); + $params['message_key'] = $request_params['MsgKey']; + $message = \App\Model\Message::getExists($params); + if ($message){ + // 消息重复 + Log::getInstance()->info("Im回调数据处理失败:消息重复"); + return $this->ImSuccessReturn(); + } + + // 处理发送结果 + if ($request_params['message_send_result'] == 0){ + // im中0表示成功 + $message_send_result = 1; + } + + // 验证自定义消息内容 + $is_system = 0;// 是否系统操作发送(0:否 1:是) + if (!empty($request_params['CloudCustomData'])){ + $cloud_custom_data = json_decode($request_params['CloudCustomData'],true); + + if (!empty($cloud_custom_data['order_inquiry_id'])){ + // 获取订单数据 + $params = array(); + $params['order_inquiry_id'] = $cloud_custom_data['order_inquiry_id']; + $order_inquiry = OrderInquiry::getOne($params); + if (empty($order_inquiry)){ + Log::getInstance()->error("Im回调数据处理失败:非法订单"); + return $this->ImErrorReturn("消息内容错误,非法订单"); + } + + $order_inquiry_id = $cloud_custom_data['order_inquiry_id']; + } + + if (!empty($cloud_custom_data['is_system'])){ + if ($cloud_custom_data['is_system'] == 1){ + // 系统发送 + $is_system = 1; + } + } + } + + // 入库 + $data = array(); + if (!empty($request_params['From_Account'])){ + // 系统发送时不带参数 + $data['from_user_id'] = $request_params['From_Account']; + } + $data['to_user_id'] = $request_params['To_Account']; + $data['message_key'] = $request_params['MsgKey']; + $data['message_send_time'] = $request_params['RequestTime']; + $data['message_seq'] = $request_params['MsgSeq']; + $data['message_send_result'] = $message_send_result ?? 0; + $data['send_error_info'] = $request_params['ErrorInfo']; + $data['message_type'] = $request_params['MsgBody'][0]['MsgType'] ?? "未定义"; + + $data['is_system'] = $is_system; + if (!empty($order_inquiry_id)){ + $data['order_inquiry_id'] = $order_inquiry_id; + } + + $message_content = $request_params['MsgBody'][0]['MsgContent'] ?? ""; + $data['message_content'] = json_encode($message_content,JSON_UNESCAPED_UNICODE); + $data['message_custom_content'] = $request_params['CloudCustomData'] ?? ""; + $message = \App\Model\Message::addMessage($data); + if (empty($message)){ + Log::getInstance()->error("Im回调数据处理失败:存储数据库失败"); + return $this->wxPayErrorReturn("存储数据库失败"); + } + + // 存储redisList + if (!empty($order_inquiry) && !empty($request_params['CloudCustomData'])){ + if (!empty($cloud_custom_data['is_system'])){ + if ($cloud_custom_data['is_system'] != 1){ + // 非系统发送 + if (!empty($cloud_custom_data['sender_user_type'])){ + if ($cloud_custom_data['sender_user_type'] == 1 || $cloud_custom_data['sender_user_type'] == 2){ + // 患者-医生发送 + $data['order_inquiry_id'] = $order_inquiry['order_inquiry_id']; + $data['patient_name'] = $order_inquiry['patient_name']; + $data['patient_sex'] = $order_inquiry['patient_sex']; + $data['patient_age'] = $order_inquiry['patient_age']; + $data['inquiry_status'] = $order_inquiry['inquiry_status']; + $data['message_send_time'] = $request_params['RequestTime']; + $data['last_message_content'] = $request_params['MsgBody'][0]['MsgContent'] ?? ""; + + $imService = new ImService(); + $imService->addRecentContactRecordCache($order_inquiry['doctor_id'],$order_inquiry['inquiry_type'],$order_inquiry['user_id'],$data); + } + } + } + } + } + } catch (\Exception $e) { + // 验证失败 + Log::getInstance()->error("Im回调数据处理失败:" . $e->getMessage()); + return $this->wxPayErrorReturn($e->getMessage()); + } + + Log::getInstance()->info("Im回调数据处理成功"); + return $this->ImSuccessReturn(); + } + + /** + * im返回错误响应 + * @param string $message + * @return ResponseInterface + */ + protected function ImErrorReturn(string $message): ResponseInterface + { + return $this->response + ->withStatus(200) + ->withBody( + new SwooleStream( + strval( + json_encode([ + 'ActionStatus' => 'FAIL', + 'ErrorCode' => 1, + 'ErrorInfo' => $message, + ], JSON_UNESCAPED_UNICODE) + ) + ) + ); + } + + /** + * im返回正确响应 + * @return ResponseInterface + */ + protected function ImSuccessReturn(): ResponseInterface + { + return $this->response + ->withStatus(200) + ->withBody( + new SwooleStream( + strval( + json_encode([ + 'ActionStatus' => 'OK', + 'ErrorCode' => 0, + 'ErrorInfo' => "", + ], JSON_UNESCAPED_UNICODE) + ) + ) + ); } } \ No newline at end of file diff --git a/app/Controller/UserController.php b/app/Controller/UserController.php index 2062bb9..e2684b0 100644 --- a/app/Controller/UserController.php +++ b/app/Controller/UserController.php @@ -125,7 +125,7 @@ class UserController extends AbstractController $group = new Group(); $friend = new Friend(); $message = new Message(); - $result = $account->createAccount(10009,'测试患者9',"https://img.applets.igandanyiyuan.com/applet/doctor/avatar/03dc8df2-e7c0-4ad9-b87e-5133e40e0f76.jpg"); +// $result = $account->createAccount(10009,'测试患者9',"https://img.applets.igandanyiyuan.com/applet/doctor/avatar/03dc8df2-e7c0-4ad9-b87e-5133e40e0f76.jpg"); // 查询账号导入状态 // $result = $account->checkAccountStatus("123456"); @@ -148,23 +148,31 @@ class UserController extends AbstractController // $result = $friend->addFriend("123456",'1234567',"快速问诊"); // 发送消息 -// $arg = array(); -// $arg['From_Account'] = "1234567"; // 发送方user_id 如系统发送,无需填写 -// $arg['To_Account'] = "123456"; // 接收方user_id -// $arg['ForbidCallbackControl'] = ['ForbidBeforeSendMsgCallback']; -// -// $arg['MsgBody'] = [ -// [ -// "MsgType" => "TIMTextElem", -// "MsgContent" => [ -// "Text" => "测试消息1", -// ], -// ] -// ]; -// -// $result = $message->sendMessage($arg); + $arg = array(); + $arg['From_Account'] = "10000"; // 发送方user_id 如系统发送,无需填写 + $arg['To_Account'] = "123456"; // 接收方user_id + $arg['ForbidCallbackControl'] = ['ForbidBeforeSendMsgCallback']; + + $arg['MsgBody'] = [ + [ + "MsgType" => "TIMTextElem", + "MsgContent" => [ + "Text" => "测试消息22", + ], + ] + ]; + + // 自定义消息 + $cloud_custom_data = array(); + $cloud_custom_data['order_inquiry_id'] = 491937904055369728; + $cloud_custom_data['is_system'] = 1; + + $arg['CloudCustomData'] = json_encode($cloud_custom_data,JSON_UNESCAPED_UNICODE); + + $result = $message->sendMessage($arg); + +// $result = $profile->getOneAccountPortraitList("123456"); - $result = $profile->getOneAccountPortraitList("123456"); dump($result); diff --git a/app/Model/Message.php b/app/Model/Message.php new file mode 100644 index 0000000..91aa8ce --- /dev/null +++ b/app/Model/Message.php @@ -0,0 +1,86 @@ +exists(); + } + + /** + * 获取信息-单条 + * @param array $params + * @param array $fields + * @return object|null + */ + public static function getOne(array $params, array $fields = ['*']): object|null + { + return self::where($params)->first($fields); + } + + /** + * 获取数据-多 + * @param array $params + * @param array $fields + * @return Collection|array + */ + public static function getList(array $params = [], array $fields = ['*']): Collection|array + { + return self::where($params)->get($fields); + } + + /** + * 新增 + * @param array $data + * @return \Hyperf\Database\Model\Model|Message + */ + public static function addMessage(array $data): \Hyperf\Database\Model\Model|Message + { + return self::create($data); + } +} diff --git a/app/Services/ImService.php b/app/Services/ImService.php index a590d69..5ea167c 100644 --- a/app/Services/ImService.php +++ b/app/Services/ImService.php @@ -13,6 +13,9 @@ use App\Utils\Log; use Extend\TencentIm\Account; use Extend\TencentIm\Profile; use GuzzleHttp\Exception\GuzzleException; +use Hyperf\Redis\Redis; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; class ImService extends BaseService { @@ -120,4 +123,45 @@ class ImService extends BaseService } + /** + * 验证回调签名 + * @param string $request_time 签名时间戳 + * @param string $sign 签名 + * @return bool + */ + public function validateSign(string $request_time,string $sign): bool + { + $token = config('im.token'); + if (empty($token)){ + throw new BusinessException("Im Token Config Error"); + } + + $sys_sign = hash("sha256", $token . $request_time); + if ($sign != $sys_sign){ + return false; + } + + return true; + } + + /** + * 添加最近联系人会话记录缓存 + * @param string $doctor_id 医生id + * @param string $inquiry_type 订单类型(自定义字段 1:专家问诊 2:快速问诊 3:公益问诊 4:问诊购药) + * @param string $patient_user_id 患者用户id + * @param array $content 内容 + * @return void + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function addRecentContactRecordCache(string $doctor_id,string $inquiry_type,string $patient_user_id,array $content): void + { + $redis_key = "recentContact" . $doctor_id . $inquiry_type; + + $hash_key = $patient_user_id; + + $redis = $this->container->get(Redis::class); + + $redis->hSet($redis_key,$hash_key,json_encode($content,JSON_UNESCAPED_UNICODE)); + } } \ No newline at end of file diff --git a/config/config.php b/config/config.php index ec604ff..2116193 100644 --- a/config/config.php +++ b/config/config.php @@ -72,5 +72,6 @@ return [ "app_id" => "1400796919", "secret" => "a5bcd8c583181cf004e9d91a47687d719d4b5d2a10ce33fbee95d587889447d8", "base_url" => "https://console.tim.qq.com/", + "token" => "NDc5MzExMDMxMDY2NDMxNDg5L", // 鉴权回调使用 ], ]; diff --git a/extend/TencentIm/Message.php b/extend/TencentIm/Message.php index 0eb821c..bcf3431 100644 --- a/extend/TencentIm/Message.php +++ b/extend/TencentIm/Message.php @@ -86,7 +86,6 @@ class Message extends Base */ public function sendMessage(array $arg): bool { - try { // 合并发送参数 $arg = array_merge($this->arg,$arg);