GZHSendKFMessage.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. namespace App\Jobs\WechatPlatform;
  3. use App\Service\Util\Support\Trace\TraceContext;
  4. use App\Service\WechatPlatform\GZHSendKFMessageService;
  5. use App\Service\WechatPlatform\WechatPlatform;
  6. use EasyWeChat\OfficialAccount\Application;
  7. use Illuminate\Bus\Queueable;
  8. use Illuminate\Contracts\Queue\ShouldBeUnique;
  9. use Illuminate\Contracts\Queue\ShouldQueue;
  10. use Illuminate\Foundation\Bus\Dispatchable;
  11. use Illuminate\Queue\InteractsWithQueue;
  12. use Illuminate\Queue\SerializesModels;
  13. use Illuminate\Support\Facades\DB;
  14. class GZHSendKFMessage implements ShouldQueue
  15. {
  16. use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
  17. /**
  18. * @var
  19. * <pre>
  20. * [
  21. * 'gzhId' => $gzhId, // wechat_authorization_infos.id
  22. * 'messageId' => $item->id, // wechat_kf_messages.id
  23. * 'traceInfo' => $traceContext->getTraceInfo() // traceInfo
  24. * ]
  25. * </pre>
  26. */
  27. private $info;
  28. private $isTest;
  29. /**
  30. * @var TraceContext
  31. */
  32. private $traceContext;
  33. /**
  34. * Create a new job instance.
  35. */
  36. public function __construct($info)
  37. {
  38. $this->info = $info;
  39. $this->isTest = $info['isTest'] ?? false;
  40. }
  41. /**
  42. * Execute the job.
  43. */
  44. public function handle(): void
  45. {
  46. $this->traceContext = TraceContext::newFromParent($this->info['traceInfo']);
  47. myLog('KFMessageSend')->info('公众号开始发送客服消息', [
  48. 'info' => $this->info,
  49. 'traceInfo' => $this->traceContext->getTraceInfo(),
  50. ]);
  51. $gzh = $this->getGZH();
  52. if(!$gzh) return;
  53. $message = $this->getMessage();
  54. if(!$message) return;
  55. $messageContent = collect(\json_decode($message->message_content, true));
  56. $messageStr = $messageContent->pluck('text')->join("\n");
  57. $officialAccount = $this->getOfficialAccount($gzh);
  58. if(false === $officialAccount) return;
  59. if($this->isTest) {
  60. $openid = $this->info['openid'] ?? '';
  61. if(!$openid) {
  62. myLog('KFMessageSend')->error('测试回传没有openid', [
  63. 'info' => $this->info
  64. ]);
  65. }
  66. GZHSendKFMessageService::sendText($officialAccount, $openid, $messageStr, $this->traceContext);
  67. } else {
  68. $next_openid = '';
  69. $loop = 1;
  70. while (true) {
  71. if($loop++ > 10000) {
  72. break;
  73. }
  74. if(1 == $message->u_type) {
  75. $info = $this->getUserOpenids($officialAccount, $next_openid);
  76. foreach ($info['openid'] as $opid){
  77. GZHSendKFMessageService::sendText($officialAccount, $opid, $messageStr, $this->traceContext);
  78. }
  79. $next_openid = $info['next_openid'];
  80. if(!$next_openid) {
  81. break;
  82. }
  83. } elseif (2 == $message->u_type) {
  84. // todo, 从人群包中获取.
  85. }
  86. }
  87. }
  88. }
  89. private function getMessage() {
  90. $message = DB::table('wechat_kf_messages')
  91. ->where('id', $this->info['messageId'])
  92. ->first();
  93. if(!$message) {
  94. myLog('KFMessageSend')->error('消息不存在', [
  95. 'info' => $this->info,
  96. 'traceInfo' => $this->traceContext->getTraceInfo(),
  97. ]);
  98. return false;
  99. }
  100. if(1 != $message->message_type) {
  101. myLog('KFMessageSend')->error('不支持的消息类型', [
  102. 'info' => $this->info,
  103. 'traceInfo' => $this->traceContext->getTraceInfo(),
  104. ]);
  105. return false;
  106. }
  107. return $message;
  108. }
  109. /**
  110. *
  111. * @param $officialAccount Application
  112. */
  113. private function getUserOpenids($officialAccount, $next_openid) {
  114. $result = $officialAccount->getClient()
  115. ->get('cgi-bin/user/get', [
  116. 'query' => [
  117. 'next_openid' => $next_openid,
  118. ]
  119. ])->toArray();
  120. if(0 != ($result['errcode'] ?? 0)) {
  121. return false;
  122. }
  123. return $result;
  124. }
  125. /**
  126. * 获取公众号调用对象
  127. * @param $gzh
  128. * @return \EasyWeChat\OfficialAccount\Application
  129. * @throws \EasyWeChat\Kernel\Exceptions\BadResponseException
  130. * @throws \EasyWeChat\Kernel\Exceptions\HttpException
  131. * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
  132. * @throws \Psr\SimpleCache\InvalidArgumentException
  133. * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
  134. * @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
  135. * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
  136. * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
  137. * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
  138. */
  139. private function getOfficialAccount($gzh) {
  140. try{
  141. return WechatPlatform::buildApplication($gzh)
  142. ->getOfficialAccountWithRefreshToken($gzh->authorizer_appid, $gzh->authorizer_refresh_token);
  143. } catch (\Throwable $exception) {
  144. myLog('KFMessageSend')->error('获取公众号调用对象失败', [
  145. 'exceptionMessage' => $exception->getMessage(),
  146. 'traceInfo' => $this->traceContext->getTraceInfo()
  147. ]);
  148. return false;
  149. }
  150. }
  151. private function getGZH() {
  152. $gzh = DB::table('wechat_authorization_infos as a')
  153. ->join('wechat_open_platform_infos as b', 'a.component_appid', 'b.app_id')
  154. ->where([
  155. ['a.id', '=', $this->info['gzhId']],
  156. ['a.is_enabled', '=', 1],
  157. ['b.is_enabled', '=', 1]
  158. ])->select('a.authorizer_appid', 'a.authorizer_refresh_token', 'b.app_id', 'b.secret', 'b.token', 'b.aes_key')
  159. ->first();
  160. if(!$gzh) {
  161. myLog('KFMessageSend')->error('公众号不可用', [
  162. 'traceInfo' => $this->traceContext->getTraceInfo(),
  163. ]);
  164. }
  165. return $gzh;
  166. }
  167. }