feat(fsgx): 完成全部24项开发任务 Phase1-7

Phase1 后端核心:
- 新增 fsgx_v1.sql 迁移脚本(is_queue_goods/frozen_points/available_points/no_assess)
- SystemConfigServices 返佣设置扩展(周期人数/分档比例/范围/时机)
- StoreOrderCreateServices 周期循环佣金计算
- StoreOrderTakeServices 佣金发放后同步冻结积分
- StoreProductServices/StoreProduct 保存 is_queue_goods

Phase2 后端接口:
- GET /api/hjf/brokerage/progress 佣金周期进度
- GET /api/hjf/assets/overview 资产总览
- HjfPointsServices 每日 frozen_points 0.4‰ 释放定时任务
- PUT /adminapi/hjf/member/{uid}/no_assess 不考核接口
- GET /adminapi/hjf/points/release_log 积分日志接口

Phase3 前端清理:
- hjfCustom.js 路由精简(仅保留 points/log)
- hjfQueue.js/hjfMember.js API 清理/重定向至 CRMEB 原生接口
- pages.json 公排→推荐佣金/佣金记录/佣金规则

Phase4-5 前端改造:
- queue/status.vue 推荐佣金进度页整体重写
- 商品详情/订单确认/支付结果页文案与逻辑改造
- 个人中心/资产页/引导页/规则页文案改造
- HjfQueueProgress/HjfRefundNotice/HjfAssetCard 组件改造
- 推广中心嵌入佣金进度摘要
- hjfMockData.js 全量更新(公排字段→佣金字段)

Phase6 Admin 增强:
- 用户列表新增 frozen_points/available_points 列及不考核操作按钮
- hjfPoints.js USE_MOCK=false 对接真实积分日志接口

Phase7 配置文档:
- docs/fsgx-phase7-config-checklist.md 后台配置与全链路验收清单

Made-with: Cursor
This commit is contained in:
apple
2026-03-23 22:32:19 +08:00
parent 788ee0c0c0
commit 434aa8c69d
13098 changed files with 2008990 additions and 961 deletions

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),
]);
}
}