332 lines
13 KiB
PHP
332 lines
13 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Amqp\Consumer;
|
||
|
||
use App\Amqp\Producer\SendSmsMessageProducer;
|
||
use App\Constants\HttpEnumCode;
|
||
use App\Exception\BusinessException;
|
||
use App\Model\LogMessagePush;
|
||
use App\Model\SubTemplate;
|
||
use App\Model\User;
|
||
use App\Model\UserDoctor;
|
||
use App\Model\UserPatient;
|
||
use App\Services\UserService;
|
||
use App\Utils\Log;
|
||
use Extend\Wechat\Wechat;
|
||
use Hyperf\Amqp\Producer;
|
||
use Hyperf\Amqp\Result;
|
||
use Hyperf\Amqp\Annotation\Consumer;
|
||
use Hyperf\Amqp\Message\ConsumerMessage;
|
||
use Hyperf\DbConnection\Db;
|
||
use PhpAmqpLib\Message\AMQPMessage;
|
||
use Psr\Container\ContainerExceptionInterface;
|
||
use Psr\Container\NotFoundExceptionInterface;
|
||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||
|
||
/**
|
||
* 订阅消息推送
|
||
* 每条消息都需携带发送短信参数,用户可能拒绝接受订阅消息
|
||
*/
|
||
#[Consumer(exchange: 'amqp.direct', routingKey: 'SendSubMessage', queue: 'send.sub.message.queue', nums: 1)]
|
||
class SendSubMessageConsumer extends ConsumerMessage
|
||
{
|
||
/**
|
||
* @param $data
|
||
* @param AMQPMessage $message
|
||
* @return string
|
||
* @throws ContainerExceptionInterface
|
||
* @throws NotFoundExceptionInterface
|
||
* @throws ClientExceptionInterface
|
||
* @throws DecodingExceptionInterface
|
||
* @throws RedirectionExceptionInterface
|
||
* @throws ServerExceptionInterface
|
||
* @throws TransportExceptionInterface
|
||
*/
|
||
public function consumeMessage($data, AMQPMessage $message): string
|
||
{
|
||
Log::getInstance()->info("开始执行 订阅消息推送 队列:" . json_encode($data, JSON_UNESCAPED_UNICODE));
|
||
|
||
// 获取被推送用户信息
|
||
$params = array();
|
||
$params['user_id'] = $data['sub_data']['push_user_id'];
|
||
$user = User::getOne($params);
|
||
if (empty($user)){
|
||
Log::getInstance()->error("订阅消息推送执行失败:未查询到被推送用户信息");
|
||
return Result::ACK;
|
||
}
|
||
|
||
try {
|
||
// 验证发送参数
|
||
if (empty($data['sub_data']['params']['data'])){
|
||
Log::getInstance()->error("订阅消息推送执行失败:无推送数据");
|
||
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"无推送数据");
|
||
|
||
return Result::DROP;
|
||
}
|
||
|
||
// 处理发送参数
|
||
$send_data = array();
|
||
foreach ($data['sub_data']['params']['data'] as $key => $item){
|
||
$send_data[$key] = [
|
||
"value" => $item
|
||
];
|
||
}
|
||
|
||
if (empty($send_data)){
|
||
Log::getInstance()->error("订阅消息推送执行失败:发送参数处理失败");
|
||
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"发送参数处理失败");
|
||
|
||
return Result::DROP;
|
||
}
|
||
|
||
Log::getInstance()->info("订阅消息推送数据记录:" . json_encode($send_data,JSON_UNESCAPED_UNICODE));
|
||
|
||
// 获取open_id
|
||
$UserService = new UserService();
|
||
$open_id = $UserService->getOpenIdWithUserId($user['user_id'],$user['user_type']);
|
||
if (empty($open_id)){
|
||
Log::getInstance()->error("订阅消息推送执行失败:未获取到被推送用户open_id");
|
||
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"未获取到被推送用户open_id");
|
||
|
||
// 执行发送短信步骤
|
||
$this->addSendSmsMessageQueue($data['sms_data']);
|
||
|
||
return Result::ACK;
|
||
}
|
||
|
||
// 处理发送环境
|
||
// $miniprogram_state = "developer";
|
||
$miniprogram_state = "trial";
|
||
if (env("APP_ENV") == "prod"){
|
||
$miniprogram_state = "formal";
|
||
}
|
||
|
||
$options = [
|
||
"template_id" => $data['sub_data']['wx_template_id'],
|
||
"page" => $data['sub_data']['params']['page'] ?: "",
|
||
"touser" => $open_id,
|
||
"data" => $send_data,
|
||
"miniprogram_state" => $miniprogram_state,
|
||
"lang" => "zh_CN",
|
||
];
|
||
|
||
// 发起推送
|
||
$Wechat = new Wechat($user['user_type']);
|
||
$result = $Wechat->sendSubscribeMessage($options);
|
||
if (empty($result)){
|
||
Log::getInstance()->error("订阅消息推送执行失败:推送失败");
|
||
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"推送失败");
|
||
}
|
||
|
||
if (!isset($result['errcode'])){
|
||
Log::getInstance()->error("订阅消息推送执行失败:推送失败,返回值错误" . json_encode($result,JSON_UNESCAPED_UNICODE));
|
||
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"推送失败,返回值错误");
|
||
}
|
||
|
||
if ($result['errcode'] == 43101){
|
||
Log::getInstance()->error("订阅消息推送执行失败:用户拒绝接收消息");
|
||
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"用户拒绝接收消息");
|
||
|
||
// 执行发送短信步骤
|
||
$this->addSendSmsMessageQueue($data['sms_data']);
|
||
|
||
return Result::ACK;
|
||
}
|
||
|
||
Log::getInstance()->info("订阅消息推送执行成功");
|
||
$this->saveSuccessPushLog($user['user_type'],$data['sub_data']);
|
||
|
||
} catch (\Exception $e) {
|
||
Log::getInstance()->error("订阅消息推送执行失败:" . $e->getMessage());
|
||
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],$e->getMessage());
|
||
}
|
||
|
||
return Result::ACK;
|
||
}
|
||
|
||
/**
|
||
* 记录成功日志
|
||
* @param string|int $user_type 用户类型
|
||
* @param array $sub_data 需发送的订阅消息数据
|
||
* @return void
|
||
*/
|
||
private function saveSuccessPushLog(string|int $user_type,array $sub_data): void
|
||
{
|
||
$data = array();
|
||
$data['to_user_id'] = $sub_data['push_user_id'];
|
||
$data['user_type'] = $user_type;
|
||
$data['type'] = 2;
|
||
$data['status'] = 1;
|
||
$data['content'] = json_encode($sub_data['params'],JSON_UNESCAPED_UNICODE);
|
||
$log_message_push = LogMessagePush::addLogMessagePush($data);
|
||
if (empty($log_message_push)){
|
||
Log::getInstance()->error("订阅消息推送成功,增加推送日志失败:" . json_encode($data,JSON_UNESCAPED_UNICODE));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 记录成功日志
|
||
* @param string|int $user_type 用户类型
|
||
* @param array $sub_data 需发送的订阅消息数据
|
||
* @param string $fail_reason 失败原因
|
||
* @return void
|
||
*/
|
||
private function saveErrorPushLog(string|int $user_type,array $sub_data,string $fail_reason): void
|
||
{
|
||
$data = array();
|
||
$data['to_user_id'] = $sub_data['push_user_id'];
|
||
$data['user_type'] = $user_type;
|
||
$data['type'] = 2;
|
||
$data['status'] = 2;
|
||
$data['fail_reason'] = $fail_reason ?: "";
|
||
$data['content'] = json_encode($sub_data['params'],JSON_UNESCAPED_UNICODE);
|
||
$log_message_push = LogMessagePush::addLogMessagePush($data);
|
||
if (empty($log_message_push)){
|
||
Log::getInstance()->error("订阅消息推送成功,增加推送日志失败:" . json_encode($data,JSON_UNESCAPED_UNICODE));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 添加短信队列
|
||
* 接收所有异常
|
||
* 只返回true,失败情况不处理
|
||
* @param array $sms_data 短信发送参数
|
||
* @return void
|
||
* @throws ContainerExceptionInterface
|
||
* @throws NotFoundExceptionInterface
|
||
*/
|
||
private function addSendSmsMessageQueue(array $sms_data): void
|
||
{
|
||
try {
|
||
if (empty($sms_data)){
|
||
// 无需发送短信
|
||
Log::getInstance()->info("无数据需添加短信推送队列");
|
||
return;
|
||
}
|
||
|
||
Log::getInstance()->info("添加短信推送队列");
|
||
|
||
// 增加至发送短信队列
|
||
$message = new SendSmsMessageProducer($sms_data);
|
||
$producer = $this->container->get(Producer::class);
|
||
$res = $producer->produce($message);
|
||
if (!$res) {
|
||
Log::getInstance()->error("添加短信推送队列失败" . json_encode($sms_data,JSON_UNESCAPED_UNICODE));
|
||
}
|
||
|
||
} catch (\Exception $e) {
|
||
Log::getInstance()->error("添加短信推送队列失败" . $e->getMessage());
|
||
}
|
||
|
||
Log::getInstance()->info("添加短信推送队列成功");
|
||
|
||
}
|
||
|
||
/**
|
||
* 获取数据库订阅消息模版
|
||
* 接收所有异常
|
||
* 异常记录log,不进行处理
|
||
* @param string|int $user_type 用户类型
|
||
* @param string $template_title 模版名称
|
||
* @return array
|
||
* @throws ClientExceptionInterface
|
||
* @throws ContainerExceptionInterface
|
||
* @throws DecodingExceptionInterface
|
||
* @throws NotFoundExceptionInterface
|
||
* @throws RedirectionExceptionInterface
|
||
* @throws ServerExceptionInterface
|
||
* @throws TransportExceptionInterface
|
||
*/
|
||
public function getSubTemplate(string|int $user_type, string $template_title): array
|
||
{
|
||
try {
|
||
Log::getInstance()->info("获取数据库消息订阅模版");
|
||
|
||
// 获取订阅消息模版数据
|
||
$params = array();
|
||
$params['client_type'] = $user_type; // 客户端类型(1:患者端 2:医师端 3:药师端)
|
||
$params['template_title'] = $template_title;
|
||
$sub_template = SubTemplate::getOne($params);
|
||
if (empty($sub_template)){
|
||
// 下载消息模版数据
|
||
Log::getInstance()->info("消息模版:" . $template_title . " 在数据库中为空");
|
||
$this->downSubTemplate($user_type);
|
||
|
||
// 重新获取订阅消息模版
|
||
$params = array();
|
||
$params['client_type'] = $user_type; // 客户端类型(1:患者端 2:医师端 3:药师端)
|
||
$params['template_title'] = $template_title;
|
||
$sub_template = SubTemplate::getOne($params);
|
||
}
|
||
} catch (\Exception $e) {
|
||
Log::getInstance()->error("获取数据库消息订阅模版失败:" . $e->getMessage());
|
||
}
|
||
|
||
if (empty($sub_template)){
|
||
return [];
|
||
}else{
|
||
return $sub_template->toArray();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 下载消息订阅模版
|
||
* 接收所有异常
|
||
* 只返回true,失败情况不处理
|
||
* @param string|int $user_type
|
||
* @return void
|
||
* @throws ClientExceptionInterface
|
||
* @throws ContainerExceptionInterface
|
||
* @throws DecodingExceptionInterface
|
||
* @throws NotFoundExceptionInterface
|
||
* @throws RedirectionExceptionInterface
|
||
* @throws ServerExceptionInterface
|
||
* @throws TransportExceptionInterface
|
||
*/
|
||
private function downSubTemplate(string|int $user_type): void
|
||
{
|
||
try {
|
||
Log::getInstance()->info("下载微信消息订阅模版");
|
||
|
||
$weChat = new Wechat($user_type);
|
||
$result = $weChat->getTemplate();
|
||
if (empty($result)){
|
||
return;
|
||
}
|
||
|
||
$template = json_decode($result, true);
|
||
|
||
foreach ($template['data'] as $item) {
|
||
$params = array();
|
||
$params['wx_template_id'] = $item['priTmplId'];
|
||
$sub_template = SubTemplate::getOne($params);
|
||
if (empty($sub_template)) {
|
||
// 新增模版
|
||
$data = array();
|
||
$data['client_type'] = 1;
|
||
$data['wx_template_id'] = $item['priTmplId'];
|
||
$data['template_title'] = $item['title'];
|
||
$data['template_type'] = $item['type'];
|
||
$data['template_content'] = $item['content'];
|
||
$sub_template = SubTemplate::addSubTemplate($data);
|
||
if (empty($sub_template)) {
|
||
// 此处添加失败不做处理,记录log,
|
||
Log::getInstance()->error("下载微信消息订阅模版失败:" . json_encode($data,JSON_UNESCAPED_UNICODE));
|
||
}
|
||
}
|
||
}
|
||
|
||
} catch (\Exception $e) {
|
||
Log::getInstance()->error("下载微信消息订阅模版失败:" . $e->getMessage());
|
||
}
|
||
|
||
Log::getInstance()->info("下载微信消息订阅模版成功");
|
||
}
|
||
}
|