ufutx.dma/app/Services/WechatService.php

1071 lines
39 KiB
PHP
Raw Normal View History

2026-03-04 14:42:40 +08:00
<?php
namespace App\Services;
use App\Http\Response\CatchError;
use App\Models\ESTP\User as EstpUser;
use App\Models\User;
use App\Models\Wechat;
use EasyWeChat\Kernel\Support\Str;
use EasyWeChat\MiniApp\Application;
use EasyWeChat\Work\Application as WorkApplication;
use EasyWeChat\OfficialAccount\Application as OfficialApplication;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Facades\UploadService;
use Symfony\Component\Cache\Psr16Cache;
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Util\PemUtil;
class WechatService
{
use CatchError;
protected $app, $official_app, $official_access_token, $mp_access_token;
public function __construct()
{
//小程序
$config = config('wechat.mini_program');
$app = new Application($config);
$this->app = $app;
//公众号
$config = config('wechat.official_account.default');
$official_app = new OfficialApplication($config);
// $app->setCache(new Psr16Cache(app('cache.psr6')));
// $access_token_key = "mp_access_token";
// Log::info("当前access_token: {$app->getAccessToken()->getToken()}");
// if (config('app.env') == 'production') {
// if (Cache::has($access_token_key)) {
// $this->mp_access_token = Cache::get($access_token_key);
// }else {
// $app->getAccessToken()->refresh();
// $this->mp_access_token = $app->getAccessToken()->getToken();
// Cache::put($access_token_key, $this->mp_access_token, now()->addMinutes(90));
// }
// }
// Log::info("缓存access_token: {$this->mp_access_token}");
// $official_app->setCache(new Psr16Cache(app('cache.psr6')));
// $app->setCache(new Psr16Cache(app('cache.psr6')));
// $access_token_key = "official_access_token";
// Log::info("当前access_token: {$official_app->getAccessToken()->getToken()}");
// if (config('app.env') == 'production') {
// if (Cache::has($access_token_key)) {
// $this->official_access_token = Cache::get($access_token_key);
// }else {
// $official_app->getAccessToken()->refresh();
// $this->official_access_token = $official_app->getAccessToken()->getToken();
// Cache::put($access_token_key, $this->official_access_token, now()->addMinutes(90));
// }
// }
// Log::info("缓存access_token: {$this->official_access_token}");
$this->official_app = $official_app;
}
public function instance()
{
//商户号
$merchantId = config('wechat.payment.mch_id');
// 从本地文件中加载「商户API私钥」「商户API私钥」会用来生成请求的签名
$merchantPrivateKeyFilePath = 'file://' . config('wechat.payment.private_key');
$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
// 「商户API证书」的「证书序列号」
$merchantCertificateSerial = config('wechat.payment.serial');
// 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名
$platformCertificateFilePath = 'file://' . config('wechat.payment.certificate');
$platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
// 从「微信支付平台证书」中获取「证书序列号」
$platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
// 构造一个 APIv3 客户端实例
$instance = Builder::factory([
'mchid' => $merchantId,
'serial' => $merchantCertificateSerial,
'privateKey' => $merchantPrivateKeyInstance,
'certs' => [
$platformCertificateSerial => $platformPublicKeyInstance,
],
]);
return $instance;
}
public function app()
{
return $this->app;
}
/**
* 公众号
* @return \EasyWeChat\OfficialAccount\Application
*/
public function officialApp()
{
return $this->official_app;
}
/**
* 企业微信
* @return WorkApplication
*/
public function workApp($type)
{
$work_config = config('wechat.' . $type);
$work_app = new WorkApplication($work_config);
return $work_app;
}
/**
* 小程序code 换取session 信息
* @param $code
* @param string $grant_type
* @return array
* @throws \Exception
*/
public function codeToSession($code, $grant_type = 'authorization_code')
{
try {
$utils = $this->app->getUtils();
$response = $utils->codeToSession($code);
return $response;
} catch (\Throwable $e) {
throw new \Exception($e->getMessage());
}
}
/**
* 小程序code换取手机号信息
* @param $code
* @return array|string[]
* @throws \Exception
*/
public function phoneNuber($code)
{
try {
if (env('APP_ENV') == 'local')
return ['mobile' => '15872844805'];
$data = ['code' => (string) $code];
$res = $this->app->getClient()->postJson('wxa/business/getuserphonenumber', $data);
if ($res->isFailed())
throw new \Exception($res->getContent());
$r = json_decode($res->toJson());
return ['mobile' => $r->phone_info->phoneNumber];
} catch (\Throwable $e) {
throw new \Exception($e->getMessage());
}
}
/**
* 小程序订阅消息列表
* @return mixed|null
* @throws \Exception
*/
public function templates()
{
try {
$res = $this->app->getClient()->get('wxaapi/newtmpl/gettemplate');
if ($res->isFailed())
throw new \Exception($res->getContent());
return $res['data'] ?? null;
} catch (\Throwable $e) {
throw new \Exception($e->getMessage());
}
}
/**
* 小程序发送订阅消息
* @param $openid
* @param $template_id
* @param $page
* @param array $data
* @return bool|int|mixed
*/
public function subSend($openid, $template_id, $page, $data = [])
{
try {
if (empty($openid))
return false;
$all_data = [
'template_id' => $template_id,
'touser' => $openid,
'page' => $page,
'data' => $data,
'miniprogram_state' => (env('APP_ENV') == 'production') ? 'formal' : 'developer',
'lang' => 'zh_CN',
];
$client = $this->app->getClient();
$response = $client->postJson('cgi-bin/message/subscribe/send', $all_data);
$all_data['type'] = 'mp';
if ($response['errcode']) {
$all_data['err_msg'] = $response['errmsg'];
$all_data['status'] = 0;
} else {
$all_data['err_msg'] = '';
$all_data['status'] = 1;
}
// $this->addTemplateMsgLog($all_data);
return $response['errcode'] ?? 1;
} catch (\Throwable $e) {
$this->getError($e);
return true;
}
}
// public function addTemplateMsgLog($data)
// {
// $where = $data['type'] == 'mp'?['openid'=>$data['touser']]:['official_openid'=>$data['touser']];
// $user_id = Wechat::where($where)->value('user_id');
// $log = new TemplateMsgLog;
// $log->user_id = $user_id;
// $log->openid = $data['touser'];
// $log->type = $data['type'];
// $log->template_id = $data['template_id'];
// $log->status = $data['status'];
// $log->err_msg = $data['err_msg']??'';
// $log->data = json_encode($data);
// $log->save();
// return true;
// }
/**
* 获取小程序二维码
* @param $scene
* @param $page
* @param string $env_version 正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版。
* @param int $width
* @param bool $is_hyaline
* @return string
* @throws \EasyWeChat\Kernel\Exceptions\BadResponseException
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*/
public function getMPQrcode($scene, $page, $env_version = 'release', $width = 430, $is_hyaline = true)
{
$app = $this->app;
$response = $app->getClient()->postJson('/wxa/getwxacodeunlimit', [
'scene' => $scene,
'page' => $page,
'width' => $width,
'is_hyaline' => $is_hyaline,
'env_version' => $env_version,
'check_path' => false
]);
$file_name = uniqid() . time() . 'qrcode.png';
$path = storage_path('qrcode/' . $file_name);
$response->saveAs($path);
$pic = '';
if (file_exists($path)) {
$pic = UploadService::uploadFile($path);
@unlink($path);
}
return $pic;
}
/**
* 小程序支付
* @param $trade_no
* @param $openid
* @param $total
* @param $desc
* @param $callback
* @return array|false
*/
public function mpPay($trade_no, $openid, $total, $desc, $callback, $appId = '', $sub_mchid = '')
{
if (config('wechat.payment.debug')) {
return false;
}
$sub_appid = config('wechat.payment.sub_app_id');
if ($appId) {
$sub_appid = $appId;
}
$resp = $this->instance()
->chain('v3/pay/partner/transactions/jsapi')
->post([
'json' => [
'sp_mchid' => config('wechat.payment.mch_id'),
'sp_appid' => config('wechat.payment.sp_appid'),
'sub_appid' => $sub_appid,
'sub_mchid' => $sub_mchid ?: config('wechat.payment.sub_merchant_id'),
'out_trade_no' => $trade_no,
'description' => $desc,
'notify_url' => $callback,
'amount' => [
'total' => (int) number_format($total * 100, 0, '', ''),
'currency' => 'CNY'
],
'payer' => [
'sub_openid' => $openid,
]
]
]);
$res = json_decode($resp->getBody());
$prepay_id = $res->prepay_id;
$config = $this->paySign($prepay_id, $sub_appid);
$config['prepay_id'] = $prepay_id;
return $config;
}
/**
* 获取jssdk配置
* @param $url
* @return mixed[]
* @throws \EasyWeChat\Kernel\Exceptions\HttpException
* @throws \Psr\SimpleCache\InvalidArgumentException
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*/
// public function getOfficialShareConfig($url){
// $app = $this->officialApp();
// $config = $app->getUtils()->buildJsSdkConfig($url, ['updateAppMessageShareData','updateTimelineShareData','onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'openLocation', 'getLocation', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'openAddress', 'updateAppMessageShareData', 'updateTimelineShareData', 'wx-open-launch-weapp', 'chooseVideo', 'hideMenuItems','showMenuItems'], ['wx-open-launch-weapp'], false);
// return $config;
// }
public function buildJsSdkConfig($url)
{
// $app = $this->officialApp();
// $api = $app->getClient();
$token_url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
$params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
try {
$res = \App\Facades\HttpService::postData($token_url, $params);
$access_token = $res['data'];
} catch (\Exception $e) {
$access_token = '';
}
// $res = $api->get("cgi-bin/ticket/getticket?access_token=$access_token&type=jsapi");
// if ($res->isFailed()) {
//
// }
// $res = json_decode($res->toJson(),true);
$ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" . $access_token . "&type=jsapi";
$res = \App\Facades\HttpService::getData($ticket_url);
Log::info("获取微信ticket cgi-bin/ticket/getticket?access_token=$access_token&type=jsapi");
Log::info($res);
$ticket = $res['ticket'];
$nonce = Str::random();
$timestamp = time();
$signature = sha1("jsapi_ticket=$ticket&noncestr=$nonce&timestamp=$timestamp&url=$url");
$jsApiList = ['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'openLocation', 'getLocation', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'openAddress', 'updateAppMessageShareData', 'updateTimelineShareData', 'wx-open-launch-weapp', 'chooseVideo', 'hideMenuItems', 'showMenuItems'];
$openTagList = ['wx-open-launch-weapp'];
return [
'appId' => config('wechat.official_account.default.app_id'),
'beta' => false,
'debug' => false,
'jsApiList' => $jsApiList,
'nonceStr' => $nonce,
'openTagList' => $openTagList,
'signature' => $signature,
'timestamp' => $timestamp,
'url' => $url,
];
}
/**
* 退款
* @param $trade_no
* @param $refund_trade_no
* @param $total_amount
* @param $refund_amount
* @param array $array
* @return array
*/
public function refund($trade_no, $refund_trade_no, $total_amount, $refund_amount, $callback, $sub_mchid = '')
{
if (config('wechat.payment.debug')) {
return ["status" => true, 'msg' => ''];
}
if (!$sub_mchid) {
$sub_mchid = config('wechat.payment.sub_merchant_id');
}
try {
$resp = $this->instance()
->chain('v3/refund/domestic/refunds')
->post([
'json' => [
'sub_mchid' => $sub_mchid,
'out_trade_no' => $trade_no,
'out_refund_no' => $refund_trade_no,
'notify_url' => $callback,
'amount' => [
'total' => (int) number_format($total_amount * 100, 0, '', ''),
'refund' => (int) number_format($refund_amount * 100, 0, '', ''),
'currency' => 'CNY'
],
]
]);
$res = json_decode($resp->getBody());
Log::info($resp->getBody());
if ($res->status == 'PROCESSING' || $res->status == "SUCCESS") {
return ['status' => true, 'msg' => ''];
}
return ['status' => false, 'msg' => '打款失败'];
} catch (\Exception $e) {
$msg = $e->getMessage();
Log::info($msg);
return ['status' => false, 'msg' => $msg];
}
}
/**
* 退款订单查询
* @param string $refund_trade_no 退款订单号
*/
public function orderRefunded($refund_trade_no, $sub_mch_id = null)
{
if (config('wechat.payment.debug')) {
return ['status' => true, 'message' => ""];
}
try {
if (!$sub_mch_id) {
$sub_mch_id = config('wechat.payment.sub_merchant_id');
}
$resp = $this->instance()
->chain('v3/refund/domestic/refunds/' . $refund_trade_no)
->get([
'query' => [
'sub_mchid' => $sub_mch_id
],
'out_refund_no' => $refund_trade_no,
]);
$res = json_decode($resp->getBody());
if ($res->status == 'SUCCESS') {
return ['status' => true, 'message' => ""];
}
return ['status' => false, 'message' => "退款失败"];
} catch (\Exception $e) {
Log::debug($refund_trade_no . '订单查询退款异常:' . $e->getMessage());
return ['status' => false, 'message' => $e->getMessage()];
}
}
/**
* 小程序-查询订单是否支付
* @param $trade_no
* @return bool
*/
public function mpPaid($trade_no, $sub_mch_id = '')
{
if (config('wechat.payment.debug')) {
return false;
}
if (empty($sub_mch_id)) {
$sub_mch_id = config('wechat.payment.sub_merchant_id');
}
$resp = $this->instance()
->chain('v3/pay/partner/transactions/out-trade-no/' . $trade_no)
->get([
// Query 参数
'query' => [
'sp_mchid' => config('wechat.payment.mch_id'),
'sub_mchid' => $sub_mch_id,
],
// 变量名 => 变量值
'out_trade_no' => $trade_no,
]);
Log::info($resp->getBody());
$res = json_decode($resp->getBody());
if (empty($res))
return true;
if ($res->trade_state == 'NOTPAY' || $res->trade_state == "CLOSED")
return $res->trade_state_desc;
return false;
}
/**
* 小程序-支付签名
* @param $prepay_id
* @return array
*/
public function paySign($prepay_id, $sub_appid)
{
$merchantPrivateKeyFilePath = 'file://' . config('wechat.payment.private_key');
$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath);
$params = [
// 'appId' => config('wechat.mini_program.app_id'),
'appId' => $sub_appid,
'timeStamp' => (string) Formatter::timestamp(),
'nonceStr' => Formatter::nonce(),
'package' => 'prepay_id=' . $prepay_id,
];
$params += [
'paySign' => Rsa::sign(
Formatter::joinedByLineFeed(...array_values($params)),
$merchantPrivateKeyInstance
),
'signType' => 'RSA'
];
return $params;
}
public function sendSubscribeMessage($params)
{
if (config('app.env') == 'production') {
$app = $this->app;
// $accessToken = $app->getAccessToken();
// $accessToken->getToken();
$response = $app->getClient()->postJson('cgi-bin/message/subscribe/send', $params);
// if ($response['errcode'] && $response['errcode'] != "43101") {
Log::info($params);
//todo 发送失败
// throw new \Exception($response['errmsg']);
// }
}
}
/**
* 公众号-后台服务
* @return \Psr\Http\Message\ResponseInterface
* @throws \EasyWeChat\Kernel\Exceptions\BadRequestException
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
* @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
* @throws \ReflectionException
* @throws \Throwable
*/
public function server()
{
$app = $this->officialApp();
$server = $app->getServer();
$server->with(function ($message, \Closure $next) {
Log::info("api server");
// 你的自定义逻辑
// Log::info($message);
$openid = $message->FromUserName;
//获取微信用户信息
$info = $this->wechatUserByOfficialOpenid($openid);
Log::info($openid . '用户信息', $info);
if ($message->MsgType == 'event') {
if ($message->Event == 'subscribe' || $message->Event == 'unsubscribe') {//关注
//同步健康信息
$this->syncSubscribe($info);
}
}
//同步创业家项目关注信息
// $this->syncEstpSubscribe($info);
return $next($message);
});
return $server->serve();
}
/**
* 同步公众号关注
* @param $info
*/
public function syncSubscribe($info)
{
$subscribe = $info['subscribe'];
if ($subscribe) {
//是否有本地小程序信息信息
$wechat = Wechat::where(['unionid' => $info['unionid'], 'type' => 'mp'])->first();
// if (empty($wechat)) return ;
DB::beginTransaction();
//是否有本地公众号信息信息
$official_wechat = Wechat::where('type', 'official')
->where('openid', $info['openid'])
->first();
if (empty($official_wechat))
return;
// if (!empty($wechat)){
// $official_wechat->user_id = $wechat->user_id;
// }
$official_wechat->unionid = $info['unionid'];
$official_wechat->save();
} else {
$official_wechat = Wechat::where(['openid' => $info['openid'], 'type' => 'official'])->first();
if (empty($official_wechat))
return;
}
//同步关注信息
User::where('id', $official_wechat->user_id)->update(['is_subscribe' => $subscribe]);
DB::commit();
}
/**
* 同步创业家项目关注
* @param $info
*/
public function syncEstpSubscribe($info)
{
$subscribe = $info['subscribe'];
if ($subscribe) {
//关注
$user = EstpUser::query()->where('unionid', $info['unionid'])->first();
if ($user) {
$user['is_subscribe'] = $subscribe;
$user['openid'] = $info['openid'];
$user->save();
}
} else {
//取关
$user = EstpUser::query()->where('openid', $info['openid'])->first();
if ($user) {
$user['is_subscribe'] = $subscribe;
$user['open_recommend'] = $subscribe;
$user->save();
}
}
if ($user) {
Log::info([
'msg' => '已更新创业家' . ['取关', '关注'][$subscribe] . '信息',
'data' => $user->toArray(),
]);
}
}
/**
* 公众号-通过openid获取用户信息
* @param $openid
* @return mixed
* @throws \EasyWeChat\Kernel\Exceptions\BadResponseException
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*/
public function wechatUserByOfficialOpenid($openid)
{
// $app = $this->officialApp();
// $api = $app->getClient();
//处理token过期报错
// $accessToken = $this->official_access_token;
// $accessToken = $app->getAccessToken()->getToken();
$url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
$params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
try {
$res = \App\Facades\HttpService::postData($url, $params);
$access_token = $res['data'];
} catch (\Exception $e) {
$access_token = '';
}
$url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=$access_token&openid=$openid";
$res = \App\Facades\HttpService::getData($url);
return $res;
// $response = $api->get('/cgi-bin/user/info', [
// "openid" => $openid,
// "access_token" => $access_token,
// ]);
// if ($response->isFailed()) {
// throw new \Exception("通过openid获取用户微信信息失败, ".$response->getContent());
// }
// $content = $response->toJson();
// return json_decode($content,true);
}
/**
* 公众号-发送模板消息
* @param $param
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*/
public function sendTemplateNotice($param)
{
if (config('app.env') == 'production') {
// $app = $this->officialApp();
// $api = $app->getClient();
// $accessToken = $app->getAccessToken()->getToken();
// $accessToken = $this->official_access_token;
$url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
$params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
try {
$res = \App\Facades\HttpService::postData($url, $params);
$access_token = $res['data'];
} catch (\Exception $e) {
$access_token = '';
}
$url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" . $access_token;
$res = \App\Facades\HttpService::postData($url, $param);
// $response = $api->postJson('/cgi-bin/message/template/send?access_token=' . $access_token, $param);
// if ($response->isFailed()) {
// $errMsg = $response->toJson();
// $errMsg = json_decode($errMsg,true);
// if (isset($errMsg['errcode']) && $errMsg['errcode'] == 40001) {
// $app->getAccessToken()->refresh();
// $newResponse = $api->postJson('/cgi-bin/message/template/send', $param);
// Log::error("sendTemplateNotice1".$newResponse->getContent());
// throw new \Exception("发送模板消息失败, ".$response->getContent());
// }
// Log::error("sendTemplateNotice" . $response->getContent());
// }
}
}
/**
* 获取公众号二维码
* @param $param
* @return mixed
* @throws \EasyWeChat\Kernel\Exceptions\BadResponseException
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*/
public function getOfficialQrcode($param)
{
// $app = $this->officialApp();
// $api = $app->getClient();
// $accessToken = $this->official_access_token;
$url = config('app.url') . '/go/api/h5/v1/common/accesstoken/get';
$params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
try {
$res = \App\Facades\HttpService::postData($url, $params);
$access_token = $res['data'];
} catch (\Exception $e) {
$access_token = '';
}
$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" . $access_token;
$res = \App\Facades\HttpService::postData($url, $param);
return $res;
// $response = $api->postJson('/cgi-bin/qrcode/create?access_token=' . $access_token, $param);
// $content = $response->toJson();
// return json_decode($content,true);
}
/**
* 发送群消息
* @param $touser
* @param $msgtype
* @param $content
* @param string $toparty
* @param string $totag
* @param int $enable_duplicate_check
* @param int $duplicate_check_interval
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*/
public function sendWorkMessage($touser, $msgtype, $content, $toparty = '', $totag = '', $enable_duplicate_check = 0, $duplicate_check_interval = 1800)
{
$api = $this->workApp('work_application')->getClient();
$params = [
"touser" => $touser,
'toparty' => $toparty,
'totag' => $totag,
"msgtype" => $msgtype,
"agentid" => 1000008,
"safe" => 0,
$msgtype => $content,
"enable_duplicate_check" => $enable_duplicate_check,
"duplicate_check_interval" => $duplicate_check_interval
];
$response = $api->postJson('/cgi-bin/message/send', $params);
if ($response->isFailed()) {
// 出错了,处理异常
throw new \Exception($response->getContent());
}
}
/**
* 发送应用消息
* @param $chatid
* @param $msgtype
* @param $content
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*/
public function sendAppChat($chatid, $msgtype, $content)
{
$api = $this->workApp('work_application')->getClient();
// $access_token = $this->workApp()->getAccessToken()->getToken();
// dd($access_token);
$params = [
'chatid' => $chatid,
'msgtype' => $msgtype,
'content' => $content,
'safe' => 0
];
$response = $api->postJson("/cgi-bin/appchat/send", $params);
if ($response->isFailed()) {
// 出错了,处理异常
throw new \Exception($response->getContent());
}
// dd($response->getContent());
}
/**
* 微信公众号授权-获取code
* @param $redirect_uri
* @return string|void
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
*/
public function connectAuth($redirect_uri) //snsapi_userinfo
{
$app = $this->officialApp();
$oauth = $app->getOauth();
$wechat_user = session('wechat_user');
$openid = $wechat_user['id'] ?? null;
if (empty($openid)) {
session(['intend_url' => $redirect_uri]);
// Log::info($redirect_uri);
//生成完整的授权URL
$redirectUrl = $oauth->redirect($redirect_uri);
// Log::info($redirectUrl);
return $redirectUrl;
}
}
/**
* 微信公众号授权-获取维信息
* @param $code
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Session\SessionManager|\Illuminate\Session\Store|mixed|string
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
*/
public function connectAuthByCode($code)
{
// Log::info("wechat code: ". $code);
try {
$app = $this->officialApp();
$oauth = $app->getOauth();
$user = $oauth->userFromCode($code);
session(['wechat_user' => $user->toArray()]);
$targetUrl = session('intend_url') ?: '/';
return $targetUrl;
} catch (\Exception $e) {
// 获取异常错误信息
$errorMessage = $e->getMessage();
// 进行错误处理,例如记录日志或返回给前端
Log::error("connectAuthByCode error: " . $errorMessage);
}
}
public function connectWorkAuthByCode($code, $config = 'work_application')
{
Log::info("wechat code: " . $code);
$app = $this->workApp($config);
Log::info("缓存测试 " . $code);
$user = $app->getOAuth()->detailed()->userFromCode($code);
// $user = $oauth->userFromCode($code);
// Log::info($user->toArray());
//缓存用户信息
Log::info("缓存用户信息");
// Log::info($user->toArray());
session(['work_wechat_user' => $user->toArray()]);
$targetUrl = session('intend_url') ?: '/';
return $targetUrl;
}
public function connectWorkAuth($redirect_uri, $config = 'work_application') //snsapi_userinfo
{
Log::info("connectWorkAuth " . $redirect_uri);
session(['intend_url' => $redirect_uri]);
$app = $this->workApp($config);
$redirect_uri = $app->getOAuth()->redirect($redirect_uri);
return $redirect_uri;
}
/**
* 获取企业微信jsSDK
* @param $url
* @param $type
* @return array|mixed[]
* @throws \EasyWeChat\Kernel\Exceptions\HttpException
* @throws \Psr\SimpleCache\InvalidArgumentException
* @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*/
public function workJsSdkConfig($url, $type)
{
$config = [];
if ($type == 'work') {
$utils = $this->workApp('work')->getUtils();
$config = $utils->buildJsSdkConfig(
$url,
[],
[],
false,
);
// $config['jsapi_ticket'] = $this->workApp('work')->getTicket()->getTicket();
} elseif ($type == 'app') {
$utils = $this->workApp('work_application')->getUtils();
$config = $utils->buildJsSdkAgentConfig(
config('wechat.work_application.agent_id'),
$url,
[],
[],
false,
);
// $config['jsapi_ticket'] = $this->workApp('work_application')->getTicket()->getAgentTicket(1000003);
}
return $config;
}
public function groupChats($cursor = '', $limit = 15, $status_filter = 0, $userid_list = [])
{
$api = $this->workApp('work')->getClient();
$response = $api->postJson('/cgi-bin/externalcontact/groupchat/list', [
'status_filter' => $status_filter,
'owner_filter' => [
'userid_list' => $userid_list
],
'cursor' => $cursor,
'limit' => $limit
]);
if ($response->isFailed()) {
// 出错了,处理异常
throw new \Exception($response->getContent());
}
return json_decode($response->toJson());
}
public function groupChat($chat_id, $need_name = 0)
{
try {
$api = $this->workApp('work')->getClient();
$response = $api->postJson('/cgi-bin/externalcontact/groupchat/get', [
'chat_id' => $chat_id,
'need_name' => $need_name
]);
// if ($response->isFailed()) {
// // 出错了,处理异常
// throw new \Exception($response->getContent());
// }
$res = json_decode($response->toJson());
return $res;
} catch (\Exception $e) {
$this->getError($e);
return false;
}
}
public function workUserInfo($user_id)
{
$api = $this->workApp('work')->getClient();
$response = $api->get('/cgi-bin/user/get', ['userid' => $user_id]);
if ($response->isFailed()) {
// 出错了,处理异常
throw new \Exception($response->getContent());
}
// Log::info($response->toJson());
return json_decode($response->toJson());
}
public function test()
{
$access = $this->official_app->getAccessToken()->getToken();
dd($access);
}
/**
* 获取小程序 url link
*/
public function urlLink($path, $query)
{
$data = [
"path" => $path,
"query" => $query,
];
$res = $this->app->getClient()->post('wxa/generate_urllink', [
'json' => $data
]);
if ($res->isFailed())
throw new \Exception($res->getContent());
$r = json_decode($res->toJson());
return $r->url_link;
}
public function getUrlLink($url_link)
{
$data = [
'url_link' => $url_link,
];
$res = $this->app->getClient()->postJson('wxa/query_urllink', $data);
if ($res->isFailed())
throw new \Exception($res->getContent());
$r = json_decode($res->toJson());
return $r->url_link_info;
}
public function getUserStep($code, $iv, $encryptedData)
{
try {
$app = $this->app;
$utils = $app->getUtils();
$response = $utils->codeToSession($code);
// 获取解密后的用户数据
$userInfo = $utils->decryptSession($response['session_key'], $iv, $encryptedData);
// 用户的微信步数
$stepInfoList = $userInfo['stepInfoList'];
$stepCount = end($stepInfoList); // 获取最近一天的步数
$stepCount['stepInfoList'] = $stepInfoList;
return $stepCount;
} catch (\Throwable $e) {
throw new \Exception($e->getMessage());
}
}
public function getMpUrlLink($url, $query = null)
{
// $access_token = $this->app->getAccessToken()->getToken();
$token_url = config('app.url') . '/go/api/mp/v1/common/accesstoken_mp/get';
$params = ['curr_date' => "#" . date("Y-m-d") . "@-"];
try {
$res = \App\Facades\HttpService::postData($token_url, $params);
$access_token = $res['data'];
} catch (\Exception $e) {
$access_token = '';
}
$res = $this->app->getClient()->post('wxa/generatescheme?access_token=' . $access_token, [
'json' => [
'jump_wxa' => [
'path' => $url,
'query' => $query
],
"is_expire" => true,
"expire_time" => time() + 30 * 24 * 60 * 60
]
]);
if ($res->isFailed())
throw new \Exception($res->getContent());
$r = json_decode($res->toJson());
return $r->openlink;
}
}