GZHSendKFMessage.php 7.1 KB

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