chore: 添加静态资源文件和版本配置文件

添加大量图片、字体、音频等静态资源文件,包括用户界面图片、模板文件和安装界面素材
添加系统版本配置文件(.version)和常量定义文件(.constant)
更新供应商依赖文件,包括Symfony VarDumper组件和相关许可证文件
添加验证码配置文件(captcha.php)和.gitignore规则
This commit is contained in:
2026-03-06 20:14:23 +08:00
commit c9a98f342c
4485 changed files with 490986 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client;
use EasyWeChat\Kernel\Form\File;
use EasyWeChat\Kernel\Form\Form;
use EasyWeChat\Kernel\HttpClient\Response;
use EasyWeChat\Kernel\HttpClient\AccessTokenAwareClient;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
/**
* 基础接口请求
* Class BaseClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/18
* @package crmeb\services\wechat\client
*/
abstract class BaseClient
{
/**
* UserClient constructor.
* @param AccessTokenAwareClient $api
*/
public function __construct(protected AccessTokenAwareClient $api)
{
}
/**
* 上传文件
* @param string $url
* @param array $files
* @param array $form
* @param array $query
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function httpUpload(string $url, array $files = [], array $form = [], array $query = [])
{
$form['media'] = File::fromPath($files['media']);
$options = Form::create($form)->toArray();
return $this->api->request(
'POST',
$url.'?'.http_build_query($query),
$options
);
}
/**
* @param string $mediaId
* @param string $uri
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
protected function getResources(string $mediaId, string $uri)
{
return $this->api->request('GET', $uri, [
'query' => [
'media_id' => $mediaId,
],
]);
}
}

View File

@@ -0,0 +1,160 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\miniprogram;
use crmeb\services\wechat\client\BaseClient;
use crmeb\services\wechat\config\MiniProgramConfig;
use crmeb\services\wechat\util\AES;
use crmeb\services\wechat\WechatException;
use EasyWeChat\Kernel\HttpClient\AccessTokenAwareClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use think\annotation\Inject;
/**
* 授权
* Class AuthClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
* @package crmeb\services\wechat\client\miniprogram
*/
class AuthClient extends BaseClient
{
/**
* @var MiniProgramConfig
*/
protected MiniProgramConfig $config;
/**
* AuthClient constructor.
* @param AccessTokenAwareClient $api
*/
public function __construct(AccessTokenAwareClient $api)
{
parent::__construct($api);
$this->config = app()->make(MiniProgramConfig::class);
}
/**
* 使用code换取用户信息
* @param string $code
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function session(string $code): ResponseInterface|Response
{
$params = [
'appid' => $this->config->appId,
'secret' => $this->config->secret,
'js_code' => $code,
'grant_type' => 'authorization_code',
];
return $this->api->get('sns/jscode2session', $params);
}
/**
* 解密数据
* @param string $sessionKey
* @param string $iv
* @param string $encrypted
* @return array
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function decryptData(string $sessionKey, string $iv, string $encrypted): array
{
$decrypted = AES::decrypt(
base64_decode($encrypted, false),
base64_decode($sessionKey, false),
base64_decode($iv, false)
);
$decrypted = json_decode($decrypted, true);
if (!$decrypted) {
throw new WechatException('The given payload is invalid.');
}
return $decrypted;
}
/**
* 获取小程序码:适用于需要的码数量极多,或仅临时使用的业务场景
* @param string $scene
* @param array $optional
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getUnlimit(string $scene, array $optional = []): Response
{
$params = array_merge([
'scene' => $scene,
], $optional);
return $this->getStream('wxa/getwxacodeunlimit', $params);
}
/**
* 获取流文件
* @param string $endpoint
* @param array $params
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
protected function getStream(string $endpoint, array $params): Response
{
return $this->api->request('POST', $endpoint, ['json' => $params]);
}
/**
* 获取小程序短链
* @param string $path 通过 URL Link 进入的小程序页面路径,必须是已经发布的小程序存在的页面,不可携带 query 。path 为空时会跳转小程序主页
* @param string $query 通过 URL Link 进入小程序时的query,最大1024个字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~%
* @param int $expire_type 默认值0.小程序 URL Link 失效类型,失效时间:0,失效间隔天数:1
* @param int $expire_time 到期失效的 URL Link 的失效时间,为 Unix 时间戳。生成的到期失效 URL Link 在该时间前有效。最长有效期为30天。expire_type 为 0 必填
* @param int $expire_interval 到期失效的URL Link的失效间隔天数。生成的到期失效URL Link在该间隔时间到达前有效。最长间隔天数为30天。expire_type 为 1 必填
* @throws TransportExceptionInterface User: liusl
* DateTime: 2024/11/23 下午2:46
*/
public function generateUrlLink(string $path, string $query, int $expire_type = 0, int $expire_time = 30 * 24 * 3600, int $expire_interval = 29)
{
$params = [
'path' => $path,
'query' => $query,
'expire_type' => $expire_type,
];
if ($expire_type == 0) {
$params['expire_time'] = time() + $expire_time;
} else {
$params['expire_interval'] = $expire_interval;
}
return $this->api->postJson('wxa/generate_urllink', $params);
}
}

View File

@@ -0,0 +1,304 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\miniprogram;
use crmeb\services\wechat\client\BaseClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 直播
* Class LiveClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
* @package crmeb\services\wechat\client\miniprogram
*/
class LiveClient extends BaseClient
{
/**
* 添加直播间参数
* @var array
*/
protected array $createData = [
'name' => '', // 房间名字
'coverImg' => '', // 通过 uploadfile 上传,填写 mediaID
'startTime' => 0, // 开始时间
'endTime' => 0, // 结束时间
'anchorName' => '', // 主播昵称
'anchorWechat' => '', // 主播微信号
'shareImg' => '', //通过 uploadfile 上传,填写 mediaID
'feedsImg' => '', //通过 uploadfile 上传,填写 mediaID
'isFeedsPublic' => 1, // 是否开启官方收录,1 开启,0 关闭
'type' => 1, // 直播类型,1 推流 0 手机直播
'screenType' => 0, // 1:横屏 0:竖屏
'closeLike' => 0, // 是否 关闭点赞 1 关闭
'closeGoods' => 0, // 是否 关闭商品货架,1:关闭
'closeComment' => 0, // 是否开启评论,1:关闭
'closeReplay' => 1, // 是否关闭回放 1 关闭
'closeShare' => 0, // 是否关闭分享 1 关闭
'closeKf' => 0 // 是否关闭客服,1 关闭
];
/**
* 获取直播房间
* @param int $start
* @param int $limit
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getRooms(int $start = 0, int $limit = 10): ResponseInterface|Response
{
$params = [
'start' => $start,
'limit' => $limit,
];
return $this->api->postJson('wxa/business/getliveinfo', $params);
}
/**
* 获取直播回放
* @param int $roomId
* @param int $start
* @param int $limit
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getPlaybacks(int $roomId, int $start = 0, int $limit = 10): ResponseInterface|Response
{
$params = [
'action' => 'get_replay',
'room_id' => $roomId,
'start' => $start,
'limit' => $limit,
];
return $this->api->postJson('wxa/business/getliveinfo', $params);
}
/**
* 创建直播间
* @param array $data
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function createRoom(array $data): ResponseInterface|Response
{
$params = array_merge($this->createData, $data);
return $this->api->postJson('wxaapi/broadcast/room/create', $params);
}
/**
* 直播间导入商品
* @param int $room_id
* @param $ids
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function roomAddGoods(int $room_id, $ids): ResponseInterface|Response
{
$params = [
'ids' => $ids,
'roomId' => $room_id
];
return $this->api->postJson('wxaapi/broadcast/room/addgoods', $params);
}
/**
* 获取商品列表信息
* @param int $status
* @param int $page
* @param int $limit
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getGoodsList(int $status, int $page = 0, int $limit = 30): ResponseInterface|Response
{
$params = [
'offset' => $page * $limit,
'limit' => $limit,
'status' => $status
];
return $this->api->get('wxaapi/broadcast/goods/getapproved', $params);
}
/**
* 获取商品详情
* @param array $ids
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getGooodsInfo(array $ids): ResponseInterface|Response
{
$params = [
'goods_ids' => $ids
];
return $this->api->get('wxa/business/getgoodswarehouse', $params);
}
/**
* 商品添加并审核
* @param string $coverImgUrl
* @param string $name
* @param int $priceType
* @param string $url
* @param string $price
* @param string $price2
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function addGoods(string $coverImgUrl, string $name, int $priceType, string $url, string $price, string $price2 = ''): ResponseInterface|Response
{
$params = [
'goodsInfo' => [
'coverImgUrl' => $coverImgUrl,
'name' => $name,
'priceType' => $priceType,
'price' => $price,
'url' => $url
]
];
if ($priceType != 1) $params['goodsInfo']['price2'] = $price2;
return $this->api->postJson('wxaapi/broadcast/goods/add', $params);
}
/**
* 撤回审核
* @param int $goodsId
* @param int $auditId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function resetauditGoods(int $goodsId, int $auditId): ResponseInterface|Response
{
$params = [
'goodsId' => $goodsId,
'auditId' => $auditId
];
return $this->api->postJson('wxaapi/broadcast/goods/resetaudit', $params);
}
/**
* 重新提交审核
* @param int $goodsId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function auditGoods(int $goodsId): ResponseInterface|Response
{
$params = [
'goodsId' => $goodsId
];
return $this->api->postJson('wxaapi/broadcast/goods/autdit', $params);
}
/**
* 删除商品
* @param int $goodsId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function deleteGoods(int $goodsId): ResponseInterface|Response
{
$params = [
'goodsId' => $goodsId
];
return $this->api->postJson('wxaapi/broadcast/goods/delete', $params);
}
/**
* 更新商品
* @param int $goodsId
* @param string $coverImgUrl
* @param string $name
* @param int $priceType
* @param string $url
* @param string $price
* @param string $price2
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function updateGoods(int $goodsId, string $coverImgUrl, string $name, int $priceType, string $url, string $price, string $price2 = ''): ResponseInterface|Response
{
$params = ['goodsInfo' => [
'goodsId' => $goodsId,
'coverImgUrl' => $coverImgUrl,
'name' => $name,
'priceType' => $priceType,
'price' => $price,
'url' => $url
]];
if ($priceType != 1) $params['goodsInfo']['price2'] = $price2;
return $this->api->postJson('wxaapi/broadcast/goods/update', $params);
}
/**
* 获取成员列表
* @param int $role
* @param int $page
* @param int $limit
* @param string $keyword
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getRoleList(int $role = 2, int $page = 0, int $limit = 30, string $keyword = ''): ResponseInterface|Response
{
$params = [
'role' => $role,
'offset' => $page * $limit,
'limit' => $limit,
'keyword' => $keyword
];
return $this->api->get('wxaapi/broadcast/role/getrolelist', $params);
}
}

View File

@@ -0,0 +1,62 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\miniprogram;
use crmeb\services\wechat\client\BaseClient;
use crmeb\services\wechat\WechatException;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
/**
* 附件
* Class MaterialClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/26
* @package crmeb\services\wechat\client\miniprogram
*/
class MaterialClient extends BaseClient
{
/**
* 附件类型
* @var array|string[]
*/
protected array $allowTypes = ['image', 'voice', 'video', 'thumb'];
/**
* 上传
* @param string $type
* @param string $path
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function upload(string $type, string $path): Response
{
if (!file_exists($path) || !is_readable($path)) {
throw new WechatException(sprintf("File does not exist, or the file is unreadable: '%s'", $path));
}
if (!in_array($type, $this->allowTypes, true)) {
throw new WechatException(sprintf("Unsupported media type: '%s'", $type));
}
return $this->httpUpload('cgi-bin/media/upload', ['media' => $path], ['type' => $type]);
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\miniprogram;
use crmeb\services\wechat\client\BaseClient;
use crmeb\services\wechat\config\MiniProgramConfig;
use crmeb\services\wechat\util\AES;
use crmeb\services\wechat\WechatException;
use EasyWeChat\Kernel\HttpClient\AccessTokenAwareClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use think\annotation\Inject;
use think\exception\ValidateException;
class MediaCheckClient extends BaseClient
{
const MSG_API = 'wxa/msg_sec_check';
const MEDIA_API = 'wxa/media_check_async';
const LABEL = [
100 => '正常',
10001 => '广告',
20001 => '时政',
20002 => '色情',
20003 => '辱骂',
20006 => '违法犯罪',
20008 => '欺诈',
20012 => '低俗',
20013 => '版权',
21000 => '其他'
];
//scene 场景枚举值(1 资料;2 评论;3 论坛;4 社交日志)
/**
* 文本敏感词检测
* @param $content
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* User: liusl
* DateTime: 2024/11/26 下午5:28
*/
public function msgSecCheck($content)
{
$params = [
'content' => $content
];
return $this->api->postJson(self::MSG_API, $params);
}
}

View File

@@ -0,0 +1,424 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\miniprogram;
use Redis;
use crmeb\exceptions\AdminException;
use crmeb\services\wechat\config\MiniProgramConfig;
use crmeb\services\wechat\config\PaymentConfig;
use crmeb\services\wechat\util\Helper;
use crmeb\services\wechat\WechatException;
use crmeb\services\wechat\WechatResponse;
use EasyWeChat\Kernel\HttpClient\AccessTokenAwareClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface as ResponseInterfaceAlias;
use think\facade\Cache;
/**
* 订单管理
* Class OrderClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
* @package crmeb\services\wechat\client\miniprogram
*/
class OrderClient
{
const redis_prefix = 'mini_order';
const express_company = 'ZTO'; // 默认发货快递公司为(中通快递)
/**
* @var PaymentConfig
*/
protected PaymentConfig $config;
/**
* @var MiniProgramConfig
*/
protected MiniProgramConfig $miniProgramConfig;
/**
* @var Redis
*/
protected Redis $redis;
/**
* UserClient constructor.
* @param AccessTokenAwareClient $api
*/
public function __construct(protected AccessTokenAwareClient $api)
{
$this->config = app()->make(PaymentConfig::class);
$this->miniProgramConfig = app()->make(MiniProgramConfig::class);
}
/**
* 处理联系人
* @param array $contact
* @return array
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
protected function handleContact(array $contact = []): array
{
if (isset($contact)) {
if (isset($contact['consignor_contact']) && $contact['consignor_contact']) {
$contact['consignor_contact'] = Helper::encryptTel($contact['consignor_contact']);
}
if (isset($contact['receiver_contact']) && $contact['receiver_contact']) {
$contact['receiver_contact'] = Helper::encryptTel($contact['receiver_contact']);
}
}
return $contact;
}
/**
* 上传订单
* @param string $out_trade_no
* @param int $logistics_type
* @param array $shipping_list
* @param string $payer_openid
* @param $path
* @param int $delivery_mode
* @param bool $is_all_delivered
* @return mixed
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function shippingByTradeNo(string $out_trade_no, int $logistics_type, array $shipping_list, string $payer_openid, $path, int $delivery_mode = 1, bool $is_all_delivered = true)
{
if (!$this->checkManaged()) {
throw new AdminException('开通小程序订单管理服务后重试');
}
$params = [
'order_key' => [
'order_number_type' => 2,
'mchid' => $this->config->mchId,
'transaction_id' => $out_trade_no
],
'logistics_type' => $logistics_type,
'delivery_mode' => $delivery_mode,
'upload_time' => date(DATE_RFC3339),
'payer' => [
'openid' => $payer_openid
]
];
if ($delivery_mode == 2) {
$params['is_all_delivered'] = $is_all_delivered;
}
foreach ($shipping_list as $shipping) {
$contact = $this->handleContact($shipping['contact'] ?? []);
$params['shipping_list'][] = [
'tracking_no' => $shipping['tracking_no'] ?? '',
'express_company' => $shipping['express_company'] ?? '',
'item_desc' => $shipping['item_desc'],
'contact' => $contact
];
}
return $this->shipping($params);
}
/**
* 合单
* @param string $out_trade_no
* @param int $logistics_type
* @param array $sub_orders
* @param string $payer_openid
* @param int $delivery_mode
* @param bool $is_all_delivered
* @return mixed
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function combinedShippingByTradeNo(string $out_trade_no, int $logistics_type, array $sub_orders, string $payer_openid, int $delivery_mode = 2, bool $is_all_delivered = false)
{
if (!$this->checkManaged()) {
throw new WechatException('开通小程序订单管理服务后重试');
}
$params = [
'order_key' => [
'order_number_type' => 1,
'mchid' => $this->config->mchId,
'out_trade_no' => $out_trade_no,
],
'upload_time' => date(DATE_RFC3339),
'payer' => [
'openid' => $payer_openid
]
];
foreach ($sub_orders as $order) {
$sub_order = [
'order_key' => [
'order_number_type' => 1,
'mchid' => $this->config->mchId,
'out_trade_no' => $order['out_trade_no'],
'logistics_type' => $logistics_type,
],
'delivery_mode' => $delivery_mode,
'is_all_delivered' => $is_all_delivered
];
foreach ($sub_orders['shipping_list'] as $shipping) {
$contact = $this->handleContact($shipping['contact'] ?? []);
$sub_order['shipping_list'][] = [
'tracking_no' => $shipping['tracking_no'] ?? '',
'express_company' => isset($shipping['express_company']) ? $this->getDelivery($shipping['express_company']) : '',
'item_desc' => $shipping['item_desc'],
'contact' => $contact
];
}
$params['sub_orders'][] = $sub_order;
}
return $this->resultHandle($this->api->postJson('wxa/sec/order/upload_combined_shipping_info', $params));
}
/**
* 签收通知
* @param string $merchant_trade_no
* @param string $received_time
* @return mixed
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function notifyConfirmByTradeNo(string $merchant_trade_no, string $received_time)
{
$params = [
'merchant_id' => $this->config->mchId,
'merchant_trade_no' => $merchant_trade_no,
'received_time' => $received_time
];
return $this->resultHandle($this->api->postJson('wxa/sec/order/notify_confirm_receive', $params));
}
/**
* 设置小修跳转路径
* @param $path
* @return mixed
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function setMesJumpPathAndCheck($path)
{
if (!$this->checkManaged()) {
throw new WechatException('开通小程序订单管理服务后重试');
}
$params = [
'path' => $path
];
return $this->resultHandle($this->api->postJson('wxa/sec/order/set_msg_jump_path', $params));
}
/**
* @param $params
* @return mixed
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function shipping($params)
{
return $this->resultHandle($this->api->postJson('wxa/sec/order/upload_shipping_info', $params));
}
/**
* @return object|Redis|null
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
protected function getRedis()
{
if (empty($this->redis)) {
$this->redis = Cache::store('redis')->handler();
}
return $this->redis;
}
/**
* 查询小程序是否已开通发货信息管理服务
* @return mixed
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function isManaged()
{
$params = [
'appid' => $this->miniProgramConfig->appId
];
return $this->resultHandle($this->api->postJson('wxa/sec/order/is_trade_managed', $params));
}
/**
* @param Response|ResponseInterfaceAlias $result
* @return mixed
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
private function resultHandle(Response|ResponseInterfaceAlias $result)
{
return new WechatResponse($result);
}
/**
* 获取运力id列表get_delivery_list
* @return mixed
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getDeliveryList()
{
return $this->resultHandle($this->api->postJson('cgi-bin/express/delivery/open_msg/get_delivery_list', []));
}
/**
* 设置物流列表
* @return array
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function setDeliveryList()
{
$list = $this->getDeliveryList();
if ($list) {
$key = self::redis_prefix . '_delivery_list';
$date = array_column($list['delivery_list'], 'delivery_id', 'delivery_name');
// 创建缓存
$this->getRedis()->hMSet($key, $date);
return $date;
} else {
throw new WechatException('物流公司列表异常');
}
}
/**
* @return bool
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function checkManaged()
{
$key = self::redis_prefix . '_is_trade_managed';
if ($this->getRedis()->exists($key)) {
return true;
} else {
return $this->setManaged();
}
}
/**
* @return bool
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function setManaged()
{
try {
$res = $this->isManaged();
if ($res['is_trade_managed']) {
$key = self::redis_prefix . '_is_trade_managed';
$this->getRedis()->set($key, $res['is_trade_managed']);
return true;
} else {
return false;
}
} catch (\Throwable) {
return false;
}
}
/**
* 获取物流列表
* @param $company_name
* @return mixed|string
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getDelivery($company_name)
{
$key = self::redis_prefix . '_delivery_list';
if (!$this->getRedis()->exists($key)) {
$date = $this->setDeliveryList();
$express_company = $date[$company_name] ?? '';
} else {
$express_company = $this->getRedis()->hMGet($key, [$company_name])[$company_name] ?? '';
}
if (empty($express_company)) {
$express_company = self::express_company;
}
return $express_company;
}
}

View File

@@ -0,0 +1,158 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\miniprogram;
use crmeb\services\wechat\client\BaseClient;
use crmeb\services\wechat\WechatException;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
class SubscribeClient extends BaseClient
{
/**
* @var array
*/
protected array $message = [
'touser' => '',
'template_id' => '',
'page' => '',
'data' => [],
'miniprogram_state' => 'formal',
];
/**
* @var string[]
*/
protected array $required = ['touser', 'template_id', 'data'];
/**
* 添加订阅消息模版
* @param string $tid
* @param array $kidList
* @param string|null $sceneDesc
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function addTemplate(string $tid, array $kidList, string $sceneDesc = null): ResponseInterface|Response
{
$sceneDesc = $sceneDesc ?? '';
$data = compact('tid', 'kidList', 'sceneDesc');
return $this->api->post('wxaapi/newtmpl/addtemplate', $data);
}
/**
* 删除模板消息
* @param string $id
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function deleteTemplate(string $id): ResponseInterface|Response
{
return $this->api->post('wxaapi/newtmpl/deltemplate', ['priTmplId' => $id]);
}
/**
* 获取模版标题的关键词列表
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
* @param string $tid
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
*/
public function getTemplateKeywords(string $tid): ResponseInterface|Response
{
return $this->api->get('wxaapi/newtmpl/getpubtemplatekeywords', compact('tid'));
}
/**
* 发送消息
* @param array $data
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function send(array $data = []): ResponseInterface|Response
{
$params = $this->formatMessage($data);
$this->restoreMessage();
return $this->api->postJson('cgi-bin/message/subscribe/send', $params);
}
/**
* @param array $data
* @return array
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
protected function formatMessage(array $data = []): array
{
$params = array_merge($this->message, $data);
foreach ($params as $key => $value) {
if (in_array($key, $this->required, true) && empty($value) && empty($this->message[$key])) {
throw new WechatException(sprintf('Attribute "%s" can not be empty!', $key));
}
$params[$key] = empty($value) ? $this->message[$key] : $value;
}
foreach ($params['data'] as $key => $value) {
if (is_array($value)) {
if (\array_key_exists('value', $value)) {
$params['data'][$key] = ['value' => $value['value']];
continue;
}
if (count($value) >= 1) {
$value = [
'value' => $value[0],
];
}
} else {
$value = [
'value' => strval($value),
];
}
$params['data'][$key] = $value;
}
return $params;
}
/**
* Restore message.
*/
protected function restoreMessage()
{
$this->message = (new \ReflectionClass(static::class))->getDefaultProperties()['message'];
}
}

View File

@@ -0,0 +1,226 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\official;
use crmeb\services\wechat\client\BaseClient;
use EasyWeChat\Kernel\HttpClient\AccessTokenAwareClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 卡片
* Class CardClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/18
* @package crmeb\services\wechat\client\official
*/
class CardClient extends BaseClient
{
const STATUS_CONTENT = 'CARD_STATUS_VERIFY_OK';
/**
* 获取会员卡列表
* @param int $offset
* @param int $count
* @param string $statusList
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function list(int $offset = 0, int $count = 10, string $statusList = self::STATUS_CONTENT): ResponseInterface|Response
{
$params = [
'offset' => $offset,
'count' => $count,
'status_list' => $statusList,
];
return $this->api->postJson('card/batchget', $params);
}
/**
* 获取颜色
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function colors(): ResponseInterface|Response
{
return $this->api->get('card/getcolors');
}
/**
* 创建卡卷
* @param string $cardType
* @param array $attributes
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function create(string $cardType = 'member_card', array $attributes = []): ResponseInterface|Response
{
$params = [
'card' => [
'card_type' => strtoupper($cardType),
strtolower($cardType) => $attributes,
],
];
return $this->api->postJson('card/create', $params);
}
/**
* 获取卡卷信息
* @param string $cardId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function get(string $cardId): ResponseInterface|Response
{
$params = [
'card_id' => $cardId,
];
return $this->api->postJson('card/get', $params);
}
/**
* 修改卡卷
* @param string $cardId
* @param string $type
* @param array $attributes
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function update(string $cardId, string $type, array $attributes = []): ResponseInterface|Response
{
$card = [];
$card['card_id'] = $cardId;
$card[strtolower($type)] = $attributes;
return $this->api->postJson('card/update', $card);
}
/**
* 删除卡卷
* @param string $cardId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function delete(string $cardId): ResponseInterface|Response
{
$params = [
'card_id' => $cardId,
];
return $this->api->postJson('card/delete', $params);
}
/**
* 创建二维码.
* @param array $cards
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function createQrCode(array $cards): ResponseInterface|Response
{
return $this->api->postJson('card/qrcode/create', $cards);
}
/**
* 设置开卡字段接口.
* @param string $cardId
* @param array $settings
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function setActivationForm(string $cardId, array $settings): ResponseInterface|Response
{
$params = array_merge(['card_id' => $cardId], $settings);
return $this->api->postJson('card/membercard/activateuserform/set', $params);
}
/**
* 会员卡接口激活.
* @param array $info
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function activate(array $info = []): ResponseInterface|Response
{
return $this->api->postJson('card/membercard/activate', $info);
}
/**
* 拉取会员信息接口.
* @param string $cardId
* @param string $code
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function getUser(string $cardId, string $code): ResponseInterface|Response
{
$params = [
'card_id' => $cardId,
'code' => $code,
];
return $this->api->postJson('card/membercard/userinfo/get', $params);
}
/**
* 更新会员信息.
* @param array $params
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function updateUser(array $params = []): ResponseInterface|Response
{
return $this->api->postJson('card/membercard/updateuser', $params);
}
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\official;
use crmeb\services\wechat\client\BaseClient;
use crmeb\services\wechat\WechatException;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
/**
* 永久素材上传-附件
* Class MaterialClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/18
* @package crmeb\services\wechat\client\official
*/
class MaterialClient extends BaseClient
{
/**
* 上传图片
* @param string $path
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function uploadImage(string $path): Response
{
return $this->upload('image', $path);
}
/**
* 上传音频
* @param string $path
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function uploadVoice(string $path): Response
{
return $this->upload('voice', $path);
}
/**
* 上传文件
* @param string $type
* @param string $path
* @param array $form
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function upload(string $type, string $path, array $form = []): Response
{
if (!file_exists($path) || !is_readable($path)) {
throw new WechatException(sprintf('File does not exist, or the file is unreadable: "%s"', $path));
}
$form['type'] = $type;
return $this->httpUpload($this->getApiByType($type), ['media' => $path], $form);
}
/**
* 获取接口
* @param string $type
* @return string
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function getApiByType(string $type): string
{
return match ($type) {
'news_image' => 'cgi-bin/media/uploadimg',
default => 'cgi-bin/material/add_material'
};
}
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\official;
use crmeb\services\wechat\client\BaseClient;
use crmeb\services\wechat\WechatException;
class MediaClient extends BaseClient
{
/**
* Allow media type.
*
* @var array
*/
protected $allowTypes = ['image', 'voice', 'video', 'thumb'];
public function uploadImage($path)
{
return $this->upload('image', $path);
}
public function uploadVideo($path)
{
return $this->upload('video', $path);
}
public function uploadVoice($path)
{
return $this->upload('voice', $path);
}
public function uploadThumb($path)
{
return $this->upload('thumb', $path);
}
public function upload(string $type, string $path)
{
if (!file_exists($path) || !is_readable($path)) {
throw new WechatException(sprintf("File does not exist, or the file is unreadable: '%s'", $path));
}
if (!in_array($type, $this->allowTypes, true)) {
throw new WechatException(sprintf("Unsupported media type: '%s'", $type));
}
return $this->httpUpload('cgi-bin/media/upload', ['media' => $path], ['type' => $type]);
}
}

View File

@@ -0,0 +1,131 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\official;
use crmeb\services\wechat\client\BaseClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 二维码
* Class QrCodeClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/18
* @package crmeb\services\wechat\client\official
*/
class QrCodeClient extends BaseClient
{
public const DAY = 86400;
public const SCENE_MAX_VALUE = 100000;
public const SCENE_QR_CARD = 'QR_CARD';
public const SCENE_QR_TEMPORARY = 'QR_SCENE';
public const SCENE_QR_TEMPORARY_STR = 'QR_STR_SCENE';
public const SCENE_QR_FOREVER = 'QR_LIMIT_SCENE';
public const SCENE_QR_FOREVER_STR = 'QR_LIMIT_STR_SCENE';
/**
* 获取url
* @param string $ticket
* @return string
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function url(string $ticket): string
{
return sprintf('https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s', urlencode($ticket));
}
/**
* createForeverQrcode
* @param string|int $sceneValue
* @return array|mixed[]
* @throws TransportExceptionInterface
* @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
*/
public function forever(string|int $sceneValue): array
{
if (is_int($sceneValue) && $sceneValue > 0 && $sceneValue < self::SCENE_MAX_VALUE) {
$type = self::SCENE_QR_FOREVER;
$sceneKey = 'scene_id';
} else {
$type = self::SCENE_QR_FOREVER_STR;
$sceneKey = 'scene_str';
}
$scene = [$sceneKey => $sceneValue];
return $this->create($type, $scene, false)->toArray();
}
/**
* 临时二维码生成
* @param int|string $sceneValue
* @param int|null $expireSeconds
* @return array|mixed[]
* @throws TransportExceptionInterface
* @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
*/
public function temporary(int|string $sceneValue, ?int $expireSeconds = null): array
{
if (is_int($sceneValue) && $sceneValue > 0) {
$type = self::SCENE_QR_TEMPORARY;
$sceneKey = 'scene_id';
} else {
$type = self::SCENE_QR_TEMPORARY_STR;
$sceneKey = 'scene_str';
}
$scene = [$sceneKey => $sceneValue];
return $this->create($type, $scene, true, $expireSeconds)->toArray();
}
/**
* 创建二维码
* @param $actionName
* @param $actionInfo
* @param bool $temporary
* @param null $expireSeconds
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
protected function create($actionName, $actionInfo, bool $temporary = true, $expireSeconds = null): ResponseInterface|Response
{
null !== $expireSeconds || $expireSeconds = 7 * self::DAY;
$params = [
'action_name' => $actionName,
'action_info' => ['scene' => $actionInfo],
];
if ($temporary) {
$params['expire_seconds'] = min($expireSeconds, 30 * self::DAY);
}
return $this->api->postJson('cgi-bin/qrcode/create', $params);
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\official;
use crmeb\services\wechat\client\BaseClient;
use crmeb\services\wechat\message\MessageInterface;
use crmeb\services\wechat\message\Raw;
use EasyWeChat\Kernel\HttpClient\AccessTokenAwareClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 消息
* Class StaffClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
* @package crmeb\services\wechat\client\offical
*/
class StaffClient extends BaseClient
{
/**
* 发送消息
* @param MessageInterface|string $message
* @param string $to
* @param string $account
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function send(MessageInterface|string $message, string $to, string $account = ''): ResponseInterface|Response
{
if (empty($message)) {
throw new \RuntimeException('No message to send.');
}
if ($message instanceof Raw) {
$message = json_decode($message->get('content'), true);
} else {
$prepends = [
'touser' => $to,
];
if ($account) {
$prepends['customservice'] = ['kf_account' => $account];
}
$message = $message->transformForJsonRequest($prepends);
}
return $this->api->postJson('cgi-bin/message/custom/send', $message);
}
}

View File

@@ -0,0 +1,215 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\official;
use crmeb\services\wechat\client\BaseClient;
use crmeb\services\wechat\WechatException;
use EasyWeChat\Kernel\HttpClient\AccessTokenAwareClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 模板消息
* Class TemplateClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/18
* @package crmeb\services\wechat\client\official
*/
class TemplateClient extends BaseClient
{
/**
* @var array
*/
protected array $message = [
'touser' => '',
'template_id' => '',
'url' => '',
'data' => [],
'miniprogram' => '',
];
/**
* @var array|string[]
*/
protected array $required = ['touser', 'template_id'];
/**
* 设置行业
* @param string $industryOne
* @param string $industryTwo
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function setIndustry(string $industryOne, string $industryTwo): ResponseInterface|Response
{
$params = [
'industry_id1' => $industryOne,
'industry_id2' => $industryTwo,
];
return $this->api->postJson('cgi-bin/template/api_set_industry', $params);
}
/**
* 添加模板消息
* @param int $shortId
* @param array $keywordList
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function addTemplate($shortId, $keywordList): ResponseInterface|Response
{
$params = ['template_id_short' => $shortId, 'keyword_name_list' => $keywordList];
return $this->api->postJson('cgi-bin/template/api_add_template', $params);
}
/**
* 获取模板消息
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function getPrivateTemplates(): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/template/get_all_private_template');
}
/**
* 删除模板
* @param string $templateId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function deletePrivateTemplate(string $templateId): ResponseInterface|Response
{
$params = ['template_id' => $templateId];
return $this->api->postJson('cgi-bin/template/del_private_template', $params);
}
/**
* 获取行业
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function getIndustry()
{
return $this->api->postJson('cgi-bin/template/get_industry');
}
/**
* 发送模板消息
* @param array $data
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function send(array $data = [])
{
$params = $this->formatMessage($data);
$this->restoreMessage();
return $this->api->postJson('cgi-bin/message/template/send', $params);
}
protected function restoreMessage()
{
$this->message = (new \ReflectionClass(static::class))->getDefaultProperties()['message'];
}
/**
* 获取
* @param array $data
* @return array
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
protected function formatMessage(array $data = [])
{
$params = array_merge($this->message, $data);
foreach ($params as $key => $value) {
if (in_array($key, $this->required, true) && empty($value) && empty($this->message[$key])) {
throw new WechatException(sprintf('Attribute "%s" can not be empty!', $key));
}
$params[$key] = empty($value) ? $this->message[$key] : $value;
}
$params['data'] = $this->formatData($params['data'] ?? []);
return $params;
}
/**
* 获取data
* @param array $data
* @return array
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
protected function formatData(array $data)
{
$formatted = [];
foreach ($data as $key => $value) {
if (is_array($value)) {
if (\array_key_exists('value', $value)) {
$formatted[$key] = $value;
continue;
}
if (count($value) >= 2) {
$value = [
'value' => $value[0],
'color' => $value[1],
];
}
} else {
$value = [
'value' => strval($value),
];
}
$formatted[$key] = $value;
}
return $formatted;
}
}

View File

@@ -0,0 +1,113 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\official;
use crmeb\services\wechat\client\BaseClient;
use EasyWeChat\Kernel\HttpClient\AccessTokenAwareClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 用户接口
* Class UserClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
* @package crmeb\services\wechat\offical\user
*/
class UserClient extends BaseClient
{
/**
* 获取单个用户
* @param string $openid
* @param string $lang
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function get(string $openid, string $lang = 'zh_CN'): ResponseInterface|Response
{
$params = [
'openid' => $openid,
'lang' => $lang,
];
return $this->api->get('cgi-bin/user/info', $params);
}
/**
* 创建菜单
* @param array $buttons
* @param array $matchRule
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function menuCreate(array $buttons, array $matchRule = []): ResponseInterface|Response
{
if (!empty($matchRule)) {
return $this->api->postJson('cgi-bin/menu/addconditional', [
'button' => $buttons,
'matchrule' => $matchRule,
]);
}
return $this->api->postJson('cgi-bin/menu/create', ['button' => $buttons]);
}
/**
* 批量获取用户
* @param string|null $nextOpenId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function list(string $nextOpenId = null): ResponseInterface|Response
{
$params = ['next_openid' => $nextOpenId];
return $this->api->get('cgi-bin/user/get', $params);
}
/**
* 搜索用户
* @param array $openids
* @param string $lang
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function select(array $openids, string $lang = 'zh_CN'): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/user/info/batchget', [
'user_list' => array_map(function ($openid) use ($lang) {
return [
'openid' => $openid,
'lang' => $lang,
];
}, $openids),
]);
}
}

View File

@@ -0,0 +1,339 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\pay;
use crmeb\services\wechat\util\Helper;
use crmeb\services\wechat\util\XML;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use think\helper\Arr;
use EasyWeChat\Pay\Client;
use EasyWeChat\Kernel\Contracts\Config;
/**
* 创建订单
* Class OrderClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/26
* @package crmeb\services\wechat\client\pay
*/
class OrderClient
{
/**
* OrderClient constructor.
* @param Client $api
* @param Config $config
*/
public function __construct(protected Client $api, protected Config $config)
{
}
/**
* 小程序创建订单
* @param array $params
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function createorder(array $params): ResponseInterface|Response
{
$data = [
'openid' => $params['openid'],//支付者的openid
'combine_trade_no' => $params['out_trade_no'],//商家合单支付总交易单号
'expire_time' => time() + 7000,
'sub_orders' => [
[
'mchid' => $this->config->get('mch_id'),
'amount' => (int)$params['total_fee'],
'trade_no' => $params['out_trade_no'],
'description' => $params['body'],
]
],
];
return $this->api->postJson('shop/pay/createorder', $data);
}
/**
* 小程序退款
* @param array $params
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function refundorder(array $params): ResponseInterface|Response
{
$data = [
'openid' => $params['openid'],
'mchid' => $this->config->get('mch_id'),
'trade_no' => $params['trade_no'],
'transaction_id' => $params['transaction_id'],
'refund_no' => $params['refund_no'],
'total_amount' => (int)$params['total_amount'],
'refund_amount' => (int)$params['refund_amount'],
];
return $this->api->postJson('shop/pay/refundorder', $data);
}
/**
* 付款码支付
* @param array $params
* @return ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function pay(array $params): ResponseInterface
{
$params['appid'] = $this->config->get('app_id');
return $this->api->request('post', 'pay/micropay', $params);
}
/**
* 下单
* @param array $params
* @return ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
public function unify(array $params): ResponseInterface
{
if (empty($params['spbill_create_ip'])) {
$params['spbill_create_ip'] = request()->ip();
}
$params['notify_url'] = $params['notify_url'] ?? $this->config->get('notify_url');
return $this->request('pay/unifiedorder', $params);
}
/**
* 发起请求
* @param string $endpoint
* @param array $params
* @param string $method
* @param array $options
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/14
*/
protected function request(string $endpoint, array $params = [], string $method = 'post', array $options = []): ResponseInterface
{
$base = [
'appid' => $this->config->get('app_id'),
'mch_id' => $this->config->get('mch_id'),
'nonce_str' => uniqid(),
];
$params = array_filter(array_filter(array_merge($base, [], $params)), 'strlen');
$secretKey = $this->config->get('v2_secret_key');
$encryptMethod = Helper::getEncryptMethod(Arr::get($params, 'sign_type', 'MD5'), $secretKey);
$params['sign'] = Helper::generateSign($params, $secretKey, $encryptMethod);
$options = array_merge([
'body' => XML::build($params),
], $options);
return $this->api->request(strtoupper($method), $endpoint, $options);
}
/**
* 商户订单号退款
* @param string $number
* @param string $refundNumber
* @param int $totalFee
* @param int $refundFee
* @param array $optional
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function byOutTradeNumber(string $number, string $refundNumber, int $totalFee, int $refundFee, array $optional = []): Response
{
return $this->refund($refundNumber, $totalFee, $refundFee, array_merge($optional, ['out_trade_no' => $number]));
}
/**
* 支付回执单号退款
* @param string $transactionId
* @param string $refundNumber
* @param int $totalFee
* @param int $refundFee
* @param array $optional
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function byTransactionId(string $transactionId, string $refundNumber, int $totalFee, int $refundFee, array $optional = []): Response
{
return $this->refund($refundNumber, $totalFee, $refundFee, array_merge($optional, ['transaction_id' => $transactionId]));
}
/**
* 退款
* @param string $refundNumber
* @param int $totalFee
* @param int $refundFee
* @param array $optional
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
protected function refund(string $refundNumber, int $totalFee, int $refundFee, array $optional = []): Response
{
$params = array_merge([
'out_refund_no' => $refundNumber,
'total_fee' => $totalFee,
'refund_fee' => $refundFee,
'appid' => $this->config->get('app_id'),
], $optional);
return $this->safeRequest('secapi/pay/refund', $params);
}
/**
* 撤销订单
* @param string $outTradeNumber
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function reverseByOutTradeNumber(string $outTradeNumber): Response
{
return $this->reverse($outTradeNumber, 'out_trade_no');
}
/**
* 撤销订单
* @param string $number
* @param string $type
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
protected function reverse(string $number, string $type): Response
{
$params = [
'appid' => $this->config->get('app_id'),
$type => $number,
];
return $this->safeRequest('secapi/pay/reverse', $params);
}
/**
* 查询退款订单
* @param string $number
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function queryByOutTradeNumber(string $number): Response
{
return $this->query([
'out_trade_no' => $number,
]);
}
/**
* 查询订单
* @param array $params
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
protected function query(array $params): Response
{
$params['appid'] = $this->config->get('app_id');
return $this->request('pay/orderquery', $params);
}
/**
* 企业付款到零钱
* @param array $params
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function toBalance(array $params): Response
{
$base = [
'mch_id' => null,
'mchid' => $this->config->get('mch_id'),
'mch_appid' => $this->config->get('app_id'),
];
if (empty($params['spbill_create_ip'])) {
$params['spbill_create_ip'] = request()->ip();
}
return $this->safeRequest('mmpaymkttransfers/promotion/transfers', array_merge($base, $params));
}
/**
* 退款请求
* @param string $endpoint
* @param array $params
* @param string $method
* @param array $options
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
protected function safeRequest(string $endpoint, array $params, string $method = 'post', array $options = []): Response
{
$options = array_merge([
'cert' => $this->config->get('certificate'),
'ssl_key' => $this->config->get('private_key'),
], $options);
return $this->request($endpoint, $params, $method, $options);
}
}

View File

@@ -0,0 +1,133 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\work;
use crmeb\services\wechat\client\BaseClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 联系客服
* Class ContactWayClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/19
* @package crmeb\services\wechat\client\work
*/
class ContactWayClient extends BaseClient
{
/**
* 配置客户联系「联系我」方式.
* @param int $type
* @param int $scene
* @param array $config
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function create(int $type, int $scene, array $config = []): ResponseInterface|Response
{
$params = array_merge([
'type' => $type,
'scene' => $scene,
], $config);
return $this->api->postJson('cgi-bin/externalcontact/add_contact_way', $params);
}
/**
* 更新企业已配置的「联系我」方式.
* @param string $configId
* @param array $config
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function update(string $configId, array $config = []): ResponseInterface|Response
{
$params = array_merge([
'config_id' => $configId,
], $config);
return $this->api->postJson('cgi-bin/externalcontact/update_contact_way', $params);
}
/**
* 删除企业已配置的「联系我」方式.
* @param string $configId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function delete(string $configId): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/externalcontact/del_contact_way', [
'config_id' => $configId,
]);
}
/**
* 获取企业已配置的「联系我」列表,注意,该接口仅可获取2021年7月10日以后创建的「联系我」
* @param string $cursor 分页查询使用的游标,为上次请求返回的 next_cursor
* @param int $limit 每次查询的分页大小,默认为100条,最多支持1000条
* @param int|null $startTime 「联系我」创建起始时间戳, 不传默认为90天前
* @param int|null $endTime 「联系我」创建结束时间戳, 不传默认为当前时间
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function list(string $cursor = '', int $limit = 100, int $startTime = null, int $endTime = null): ResponseInterface|Response
{
$data = [
'cursor' => $cursor,
'limit' => $limit,
];
if ($startTime) {
$data['start_time'] = $startTime;
}
if ($endTime) {
$data['end_time'] = $endTime;
}
return $this->api->postJson('cgi-bin/externalcontact/list_contact_way', $data);
}
/**
* 结束临时会话
* @param string $userId 企业成员的user_id
* @param string $externalUserId 客户的外部联系人user_id
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function closeTempChat(string $userId, string $externalUserId): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/externalcontact/close_temp_chat', [
'userid' => $userId,
'external_userid' => $externalUserId
]);
}
}

View File

@@ -0,0 +1,101 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\work;
use crmeb\services\wechat\client\BaseClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 部门
* Class DepartmentClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
* @package crmeb\services\wechat\client\work
*/
class DepartmentClient extends BaseClient
{
/**
* 获取部门信息
* @param int $id
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function get(int $id): ResponseInterface|Response
{
return $this->api->get('cgi-bin/department/get', compact('id'));
}
/**
* 获取部门列表
* @param int|null $id
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function list(?int $id = null): ResponseInterface|Response
{
return $this->api->get('cgi-bin/department/list', compact('id'));
}
/**
* 获取子部门ID列表
* @param int|null $id
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function simpleList(?int $id = null): ResponseInterface|Response
{
return $this->api->get('cgi-bin/department/simplelist', compact('id'));
}
/**
* 获取成员ID列表
* @param int $limit
* @param string $cursor
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getUserListIds(int $limit = 0, string $cursor = ''): ResponseInterface|Response
{
$data = [];
if ($limit) {
$data['limit'] = $limit;
}
if ($cursor) {
$data['cursor'] = $cursor;
}
return $this->api->postJson('cgi-bin/user/list_id', $data);
}
}

View File

@@ -0,0 +1,222 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\work;
use crmeb\services\wechat\client\BaseClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 外部联系
* Class ExternalContactClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
* @package crmeb\services\wechat\client\work
*/
class ExternalContactClient extends BaseClient
{
/**
* 获取外部联系人详情
* @param string $externalUserId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function get(string $externalUserId): ResponseInterface|Response
{
return $this->api->get('cgi-bin/externalcontact/get', [
'external_userid' => $externalUserId,
]);
}
/**
* 批量获取客户详情
* @param array $userIdList
* @param string $cursor
* @param int $limit
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function batchGet(array $userIdList, string $cursor = '', int $limit = 100): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/externalcontact/batch/get_by_user', [
'userid_list' => $userIdList,
'cursor' => $cursor,
'limit' => $limit,
]);
}
/**
* 获取企业标签库
* @param array $tagIds
* @param array $groupIds
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getCorpTags(array $tagIds = [], array $groupIds = []): ResponseInterface|Response
{
$params = [
'tag_id' => $tagIds,
'group_id' => $groupIds
];
return $this->api->postJson('cgi-bin/externalcontact/get_corp_tag_list', $params);
}
/**
* 添加企业客户标签
* @param array $params
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function addCorpTag(array $params): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/externalcontact/add_corp_tag', $params);
}
/**
* 编辑企业客户标签
* @param string $id
* @param string|null $name
* @param int|null $order
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function updateCorpTag(string $id, ?string $name = null, ?int $order = null): ResponseInterface|Response
{
$params = [
"id" => $id
];
if (!\is_null($name)) {
$params['name'] = $name;
}
if (!\is_null($order)) {
$params['order'] = $order;
}
return $this->api->postJson('cgi-bin/externalcontact/edit_corp_tag', $params);
}
/**
* 删除企业客户标签
* @param array $tagId
* @param array $groupId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function deleteCorpTag(array $tagId, array $groupId): ResponseInterface|Response
{
$params = [
"tag_id" => $tagId,
"group_id" => $groupId,
];
return $this->api->postJson('cgi-bin/externalcontact/del_corp_tag', $params);
}
/**
* 编辑客户企业标签
* @param array $params
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function markTags(array $params): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/externalcontact/mark_tag', $params);
}
/**
* 获取客户群列表
* @param array $params
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getGroupChats(array $params): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/externalcontact/groupchat/list', $params);
}
/**
* 获取客户群详情
* @param string $chatId
* @param int $needName
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getGroupChat(string $chatId, int $needName = 0): ResponseInterface|Response
{
$params = [
'chat_id' => $chatId,
'need_name' => $needName,
];
return $this->api->postJson('cgi-bin/externalcontact/groupchat/get', $params);
}
/**
* 获取「群聊数据统计」数据. (按自然日聚合的方式)
* @param int $dayBeginTime
* @param int $dayEndTime
* @param array $userIds
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function groupChatStatisticGroupByDay(int $dayBeginTime, int $dayEndTime, array $userIds = []): ResponseInterface|Response
{
$params = [
'day_begin_time' => $dayBeginTime,
'day_end_time' => $dayEndTime,
'owner_filter' => [
'userid_list' => $userIds
]
];
return $this->api->postJson('cgi-bin/externalcontact/groupchat/statistic_group_by_day', $params);
}
}

View File

@@ -0,0 +1,121 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\work;
use crmeb\services\wechat\client\BaseClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 客户群聊配置
* Class GroupChatClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
* @package crmeb\services\wechat\client\work
*/
class GroupChatClient extends BaseClient
{
/**
* 更新客户群进群方式配置
* @param string $configId
* @param string $roomBaseName
* @param array $chatIdList
* @param string $state
* @param int $autoCreateRoom
* @param int $roomBaseId
* @param string|null $remark
* @param int $scene
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function updateJoinWay(string $configId, string $roomBaseName, array $chatIdList, string $state, int $autoCreateRoom = 1, int $roomBaseId = 1, string $remark = null, int $scene = 2): ResponseInterface|Response
{
$data = [
'config_id' => $configId,
'scene' => $scene,
'remark' => $remark,
'auto_create_room' => $autoCreateRoom,
'room_base_name' => $roomBaseName,
'room_base_id' => $roomBaseId,
'chat_id_list' => $chatIdList,
'state' => $state,
];
return $this->api->postJson('cgi-bin/externalcontact/groupchat/update_join_way', $data);
}
/**
* 配置客户群进群方式
* @param string $roomName
* @param array $chatIdList
* @param string $state
* @param int $autoCreateRoom
* @param int $roomBaseId
* @param string|null $remark
* @param int $scene
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function addJoinWay(string $roomName, array $chatIdList, string $state, int $autoCreateRoom = 1, int $roomBaseId = 1, string $remark = null, int $scene = 2): ResponseInterface|Response
{
$data = [
'scene' => $scene,
'remark' => $remark,
'chat_id_list' => $chatIdList,
'auto_create_room' => $autoCreateRoom,
'room_base_name' => $roomName,
'room_base_id' => $roomBaseId,
'state' => $state
];
return $this->api->postJson('cgi-bin/externalcontact/groupchat/add_join_way', $data);
}
/**
* 获取客户群进群方式配置
* @param string $configId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getJoinWay(string $configId): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/externalcontact/groupchat/get_join_way', ['config_id' => $configId]);
}
/**
* 删除客户群进群方式配置
* @param string $configId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function deleteJoinWay(string $configId): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/externalcontact/groupchat/del_join_way', ['config_id' => $configId]);
}
}

View File

@@ -0,0 +1,85 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\work;
use crmeb\services\wechat\client\BaseClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
/**
* 附件管理
* Class MediaClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
* @package crmeb\services\wechat\client\work
*/
class MediaClient extends BaseClient
{
/**
* @param string $type
* @param string $path
* @param array $form
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function upload(string $type, string $path, array $form = []): Response
{
$files = [
'media' => $path,
];
return $this->httpUpload('cgi-bin/media/upload', $files, $form, compact('type'));
}
/**
* 上传附件资源
* @param string $path
* @param string $mediaType
* @param string $attachmentType
* @return Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function uploadAttachment(string $path, string $mediaType, string $attachmentType): Response
{
$query = [
'media_type' => $mediaType,
'attachment_type' => $attachmentType,
];
return $this->httpUpload('cgi-bin/media/upload_attachment', ['media' => $path], $query);
}
/**
* 获取临时素材
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
* @param string $mediaId
* @return Response
* @throws TransportExceptionInterface
*/
public function get(string $mediaId): Response
{
return $this->getResources($mediaId, 'cgi-bin/media/get');
}
}

View File

@@ -0,0 +1,225 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\work;
use crmeb\services\wechat\client\BaseClient;
use crmeb\services\wechat\WechatException;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 消息发送
* Class MessageClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/10/8
* @package crmeb\services\wechat\client\work
*/
class MessageClient extends BaseClient
{
/**
* Required attributes.
*
* @var array
*/
protected array $required = ['content', 'title', 'url', 'pic_media_id', 'appid', 'page'];
/**
* @var array|string[]
*/
protected array $textMessage = [
'content' => '',
];
/**
* @var array
*/
protected array $imageMessage = [
];
/**
* @var array|string[]
*/
protected array $linkMessage = [
'title' => '',
'picurl' => '',
'desc' => '',
'url' => '',
];
/**
* @var array|string[]
*/
protected array $miniprogramMessage = [
'title' => '',
'pic_media_id' => '',
'appid' => '',
'page' => '',
];
/**
* @param array $message
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function send(array $message): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/message/send', $message);
}
/**
* 添加企业群发消息模板
* @param array $msg
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function submit(array $msg): ResponseInterface|Response
{
$params = $this->formatMessage($msg);
return $this->api->postJson('cgi-bin/externalcontact/add_msg_template', $params);
}
/**
* @param array $data
* @return array
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/26
*/
protected function formatMessage(array $data = [])
{
$params = $data;
if (!empty($params['text'])) {
$params['text'] = $this->formatFields($params['text'], $this->textMessage);
}
if (!empty($params['image'])) {
$params['image'] = $this->formatFields($params['image'], $this->imageMessage);
}
if (!empty($params['link'])) {
$params['link'] = $this->formatFields($params['link'], $this->linkMessage);
}
if (!empty($params['miniprogram'])) {
$params['miniprogram'] = $this->formatFields($params['miniprogram'], $this->miniprogramMessage);
}
return $params;
}
/**
* @param array $data
* @param array $default
* @return array
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/26
*/
protected function formatFields(array $data = [], array $default = [])
{
$params = array_merge($default, $data);
foreach ($params as $key => $value) {
if (in_array($key, $this->required, true) && empty($value) && empty($default[$key])) {
throw new WechatException(sprintf('Attribute "%s" can not be empty!', $key));
}
$params[$key] = empty($value) ? $default[$key] : $value;
}
return $params;
}
/**
* @param string $welcomeCode
* @param array $msg
* @return ResponseInterface|Response
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/26
*/
public function sendWelcome(string $welcomeCode, array $msg): ResponseInterface|Response
{
$formattedMsg = $this->formatMessage($msg);
$params = array_merge($formattedMsg, [
'welcome_code' => $welcomeCode,
]);
return $this->api->postJson('cgi-bin/externalcontact/send_welcome_msg', $params);
}
/**
* 获取群发成员发送任务列表
* @param string $msgId 群发消息的id,通过获取群发记录列表接口返回
* @param int|null $limit 返回的最大记录数,整型,最大值1000,默认值500,超过最大值时取默认值
* @param string|null $cursor 用于分页查询的游标,字符串类型,由上一次调用返回,首次调用可不填
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getGroupmsgTask(string $msgId, ?int $limit = null, ?string $cursor = null): ResponseInterface|Response
{
$data = [
'msgid' => $msgId,
'limit' => $limit,
'cursor' => $cursor,
];
$writableData = array_filter($data, function (string $key) use ($data) {
return !is_null($data[$key]);
}, ARRAY_FILTER_USE_KEY);
return $this->api->postJson('cgi-bin/externalcontact/get_groupmsg_task', $writableData);
}
/**
* 获取企业群发成员执行结果
* @param string $msgId 群发消息的id,通过获取群发记录列表接口返回
* @param string $userid 发送成员userid,通过获取群发成员发送任务列表接口返回
* @param int|null $limit 返回的最大记录数,整型,最大值1000,默认值500,超过最大值时取默认值
* @param string|null $cursor 用于分页查询的游标,字符串类型,由上一次调用返回,首次调用可不填
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getGroupmsgSendResult(string $msgId, string $userid, ?int $limit = null, ?string $cursor = null): ResponseInterface|Response
{
$data = [
'msgid' => $msgId,
'userid' => $userid,
'limit' => $limit,
'cursor' => $cursor,
];
$writableData = array_filter($data, function (string $key) use ($data) {
return !is_null($data[$key]);
}, ARRAY_FILTER_USE_KEY);
return $this->api->postJson('cgi-bin/externalcontact/get_groupmsg_send_result', $writableData);
}
}

View File

@@ -0,0 +1,164 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\work;
use crmeb\services\wechat\client\BaseClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
/**
* 朋友圈
* Class MomentClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
* @package crmeb\services\wechat\client\work
*/
class MomentClient extends BaseClient
{
/**
* 创建发表任务
* @param array $param
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function createTask(array $param): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/externalcontact/add_moment_task', $param);
}
/**
* 获取任务创建结果
* @param string $jobId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getTask(string $jobId): ResponseInterface|Response
{
return $this->api->get('cgi-bin/externalcontact/get_moment_task_result', ['jobid' => $jobId]);
}
/**
* 获取企业全部的发表列表
* @param array $params
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function list(array $params): ResponseInterface|Response
{
return $this->api->postJson('cgi-bin/externalcontact/get_moment_list', $params);
}
/**
* 获取客户朋友圈企业发表的列表
* @param string $momentId
* @param string $cursor
* @param int $limit
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getTasks(string $momentId, string $cursor = '', int $limit = 500): ResponseInterface|Response
{
$params = [
'moment_id' => $momentId,
'cursor' => $cursor,
'limit' => $limit
];
return $this->api->postJson('cgi-bin/externalcontact/get_moment_task', $params);
}
/**
* 获取客户朋友圈发表时选择的可见范围
* @param string $momentId
* @param string $userId
* @param string $cursor
* @param int $limit
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getCustomers(string $momentId, string $userId, string $cursor, int $limit): ResponseInterface|Response
{
$params = [
'moment_id' => $momentId,
'userid' => $userId,
'cursor' => $cursor,
'limit' => $limit
];
return $this->api->postJson('cgi-bin/externalcontact/get_moment_customer_list', $params);
}
/**
* 获取客户朋友圈发表后的可见客户列表
* @param string $momentId
* @param string $userId
* @param string $cursor
* @param int $limit
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getSendResult(string $momentId, string $userId, string $cursor, int $limit): ResponseInterface|Response
{
$params = [
'moment_id' => $momentId,
'userid' => $userId,
'cursor' => $cursor,
'limit' => $limit
];
return $this->api->postJson('cgi-bin/externalcontact/get_moment_send_result', $params);
}
/**
* 获取客户朋友圈的互动数据
* @param string $momentId
* @param string $userId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getComments(string $momentId, string $userId): ResponseInterface|Response
{
$params = [
'moment_id' => $momentId,
'userid' => $userId
];
return $this->api->postJson('cgi-bin/externalcontact/get_moment_comments', $params);
}
}

View File

@@ -0,0 +1,86 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services\wechat\client\work;
use crmeb\services\wechat\client\BaseClient;
use EasyWeChat\Kernel\HttpClient\Response;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* 用户
* Class UserClient
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/18
* @package crmeb\services\wechat\client\work
*/
class UserClient extends BaseClient
{
/**
* 获取部门成员详细信息
* @param int $departmentId
* @param bool $fetchChild
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function getDetailedDepartmentUsers(int $departmentId, bool $fetchChild = false): ResponseInterface|Response
{
$params = [
'department_id' => $departmentId,
'fetch_child' => (int)$fetchChild,
];
return $this->api->get('cgi-bin/user/list', $params);
}
/**
* 获取通讯录成员详情
* @param string $userId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function get(string $userId): ResponseInterface|Response
{
return $this->api->get('cgi-bin/user/get', ['userid' => $userId]);
}
/**
* userid转openid
* @param string $userId
* @param int|null $agentId
* @return Response|ResponseInterface
* @throws TransportExceptionInterface
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/15
*/
public function userIdToOpenid(string $userId, int $agentId = null): ResponseInterface|Response
{
$params = [
'userid' => $userId,
'agentid' => $agentId,
];
return $this->api->postJson('cgi-bin/user/convert_to_openid', $params);
}
}