增加vendor

This commit is contained in:
hoteas
2022-05-24 13:49:25 +08:00
parent c3a24eeb3c
commit 65ece0418e
742 changed files with 509206 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
# 微信开放平台
[官方文档](https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Third_party_platform_appid.html)
## 快速入门
### 服务端处理
```go
wc := wechat.NewWechat()
memory := cache.NewMemory()
cfg := &openplatform.Config{
AppID: "xxx",
AppSecret: "xxx",
Token: "xxx",
EncodingAESKey: "xxx",
Cache: memory,
}
openPlatform := wc.GetOpenPlatform(cfg)
// 传入request和responseWriter
server := openPlatform.GetServer(req, rw)
//设置接收消息的处理方法
server.SetMessageHandler(func(msg *message.MixMessage) *message.Reply {
if msg.InfoType == message.InfoTypeVerifyTicket {
componentVerifyTicket, err := openPlatform.SetComponentAccessToken(msg.ComponentVerifyTicket)
if err != nil {
log.Println(err)
return nil
}
//debug
fmt.Println(componentVerifyTicket)
rw.Write([]byte("success"))
return nil
}
//handle other message
//
return nil
})
//处理消息接收以及回复
err := server.Serve()
if err != nil {
fmt.Println(err)
return
}
//发送回复的消息
server.Send()
```
### 待授权处理消息
```go
//授权的第三方公众号的appID
appID := "xxx"
openPlatform := wc.GetOpenPlatform(cfg)
openPlatform.GetOfficialAccount(appID)
```
+34
View File
@@ -0,0 +1,34 @@
package account
import "github.com/silenceper/wechat/v2/openplatform/context"
// Account 开放平台张哈管理
// TODO 实现方法
type Account struct {
*context.Context
}
// NewAccount new
func NewAccount(ctx *context.Context) *Account {
return &Account{ctx}
}
// Create 创建开放平台帐号并绑定公众号/小程序
func (account *Account) Create(appID string) (string, error) {
return "", nil
}
// Bind 将公众号/小程序绑定到开放平台帐号下
func (account *Account) Bind(appID string) error {
return nil
}
// Unbind 将公众号/小程序从开放平台帐号下解绑
func (account *Account) Unbind(appID string, openAppID string) error {
return nil
}
// Get 获取公众号/小程序所绑定的开放平台帐号
func (account *Account) Get(appID string) (string, error) {
return "", nil
}
+14
View File
@@ -0,0 +1,14 @@
package config
import (
"github.com/silenceper/wechat/v2/cache"
)
// Config .config for 微信开放平台
type Config struct {
AppID string `json:"app_id"` // appid
AppSecret string `json:"app_secret"` // appsecret
Token string `json:"token"` // token
EncodingAESKey string `json:"encoding_aes_key"` // EncodingAESKey
Cache cache.Cache
}
@@ -0,0 +1,258 @@
// Package context 开放平台相关context
package context
import (
"encoding/json"
"fmt"
"net/url"
"time"
"github.com/silenceper/wechat/v2/util"
)
const (
componentAccessTokenURL = "https://api.weixin.qq.com/cgi-bin/component/api_component_token"
getPreCodeURL = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=%s"
queryAuthURL = "https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=%s"
refreshTokenURL = "https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=%s"
getComponentInfoURL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=%s"
componentLoginURL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=%s&pre_auth_code=%s&redirect_uri=%s&auth_type=%d&biz_appid=%s"
bindComponentURL = "https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&auth_type=%d&no_scan=1&component_appid=%s&pre_auth_code=%s&redirect_uri=%s&biz_appid=%s#wechat_redirect"
// TODO 获取授权方选项信息
// getComponentConfigURL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_option?component_access_token=%s"
// TODO 获取已授权的账号信息
// getuthorizerListURL = "POST https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_list?component_access_token=%s"
)
// ComponentAccessToken 第三方平台
type ComponentAccessToken struct {
util.CommonError
AccessToken string `json:"component_access_token"`
ExpiresIn int64 `json:"expires_in"`
}
// GetComponentAccessToken 获取 ComponentAccessToken
func (ctx *Context) GetComponentAccessToken() (string, error) {
accessTokenCacheKey := fmt.Sprintf("component_access_token_%s", ctx.AppID)
val := ctx.Cache.Get(accessTokenCacheKey)
if val == nil {
return "", fmt.Errorf("cann't get component access token")
}
return val.(string), nil
}
// SetComponentAccessToken 通过component_verify_ticket 获取 ComponentAccessToken
func (ctx *Context) SetComponentAccessToken(verifyTicket string) (*ComponentAccessToken, error) {
body := map[string]string{
"component_appid": ctx.AppID,
"component_appsecret": ctx.AppSecret,
"component_verify_ticket": verifyTicket,
}
respBody, err := util.PostJSON(componentAccessTokenURL, body)
if err != nil {
return nil, err
}
at := &ComponentAccessToken{}
if err := json.Unmarshal(respBody, at); err != nil {
return nil, err
}
if at.ErrCode != 0 {
return nil, fmt.Errorf("SetComponentAccessToken Error , errcode=%d , errmsg=%s", at.ErrCode, at.ErrMsg)
}
accessTokenCacheKey := fmt.Sprintf("component_access_token_%s", ctx.AppID)
expires := at.ExpiresIn - 1500
if err := ctx.Cache.Set(accessTokenCacheKey, at.AccessToken, time.Duration(expires)*time.Second); err != nil {
return nil, nil
}
return at, nil
}
// GetPreCode 获取预授权码
func (ctx *Context) GetPreCode() (string, error) {
cat, err := ctx.GetComponentAccessToken()
if err != nil {
return "", err
}
req := map[string]string{
"component_appid": ctx.AppID,
}
uri := fmt.Sprintf(getPreCodeURL, cat)
body, err := util.PostJSON(uri, req)
if err != nil {
return "", err
}
var ret struct {
PreCode string `json:"pre_auth_code"`
}
if err := json.Unmarshal(body, &ret); err != nil {
return "", err
}
return ret.PreCode, nil
}
// GetComponentLoginPage 获取第三方公众号授权链接(扫码授权)
func (ctx *Context) GetComponentLoginPage(redirectURI string, authType int, bizAppID string) (string, error) {
code, err := ctx.GetPreCode()
if err != nil {
return "", err
}
return fmt.Sprintf(componentLoginURL, ctx.AppID, code, url.QueryEscape(redirectURI), authType, bizAppID), nil
}
// GetBindComponentURL 获取第三方公众号授权链接(链接跳转,适用移动端)
func (ctx *Context) GetBindComponentURL(redirectURI string, authType int, bizAppID string) (string, error) {
code, err := ctx.GetPreCode()
if err != nil {
return "", err
}
return fmt.Sprintf(bindComponentURL, authType, ctx.AppID, code, url.QueryEscape(redirectURI), bizAppID), nil
}
// ID 微信返回接口中各种类型字段
type ID struct {
ID int `json:"id"`
}
// AuthBaseInfo 授权的基本信息
type AuthBaseInfo struct {
AuthrAccessToken
FuncInfo []AuthFuncInfo `json:"func_info"`
}
// AuthFuncInfo 授权的接口内容
type AuthFuncInfo struct {
FuncscopeCategory ID `json:"funcscope_category"`
}
// AuthrAccessToken 授权方AccessToken
type AuthrAccessToken struct {
Appid string `json:"authorizer_appid"`
AccessToken string `json:"authorizer_access_token"`
ExpiresIn int64 `json:"expires_in"`
RefreshToken string `json:"authorizer_refresh_token"`
}
// QueryAuthCode 使用授权码换取公众号或小程序的接口调用凭据和授权信息
func (ctx *Context) QueryAuthCode(authCode string) (*AuthBaseInfo, error) {
cat, err := ctx.GetComponentAccessToken()
if err != nil {
return nil, err
}
req := map[string]string{
"component_appid": ctx.AppID,
"authorization_code": authCode,
}
uri := fmt.Sprintf(queryAuthURL, cat)
body, err := util.PostJSON(uri, req)
if err != nil {
return nil, err
}
var ret struct {
util.CommonError
Info *AuthBaseInfo `json:"authorization_info"`
}
if err := json.Unmarshal(body, &ret); err != nil {
return nil, err
}
if ret.ErrCode != 0 {
err = fmt.Errorf("QueryAuthCode error : errcode=%v , errmsg=%v", ret.ErrCode, ret.ErrMsg)
return nil, err
}
return ret.Info, nil
}
// RefreshAuthrToken 获取(刷新)授权公众号或小程序的接口调用凭据(令牌)
func (ctx *Context) RefreshAuthrToken(appid, refreshToken string) (*AuthrAccessToken, error) {
cat, err := ctx.GetComponentAccessToken()
if err != nil {
return nil, err
}
req := map[string]string{
"component_appid": ctx.AppID,
"authorizer_appid": appid,
"authorizer_refresh_token": refreshToken,
}
uri := fmt.Sprintf(refreshTokenURL, cat)
body, err := util.PostJSON(uri, req)
if err != nil {
return nil, err
}
ret := &AuthrAccessToken{}
if err := json.Unmarshal(body, ret); err != nil {
return nil, err
}
authrTokenKey := "authorizer_access_token_" + appid
if err := ctx.Cache.Set(authrTokenKey, ret.AccessToken, time.Minute*80); err != nil {
return nil, err
}
return ret, nil
}
// GetAuthrAccessToken 获取授权方AccessToken
func (ctx *Context) GetAuthrAccessToken(appid string) (string, error) {
authrTokenKey := "authorizer_access_token_" + appid
val := ctx.Cache.Get(authrTokenKey)
if val == nil {
return "", fmt.Errorf("cannot get authorizer %s access token", appid)
}
return val.(string), nil
}
// AuthorizerInfo 授权方详细信息
type AuthorizerInfo struct {
NickName string `json:"nick_name"`
HeadImg string `json:"head_img"`
ServiceTypeInfo ID `json:"service_type_info"`
VerifyTypeInfo ID `json:"verify_type_info"`
UserName string `json:"user_name"`
PrincipalName string `json:"principal_name"`
BusinessInfo struct {
OpenStore string `json:"open_store"`
OpenScan string `json:"open_scan"`
OpenPay string `json:"open_pay"`
OpenCard string `json:"open_card"`
OpenShake string `json:"open_shake"`
}
Alias string `json:"alias"`
QrcodeURL string `json:"qrcode_url"`
}
// GetAuthrInfo 获取授权方的帐号基本信息
func (ctx *Context) GetAuthrInfo(appid string) (*AuthorizerInfo, *AuthBaseInfo, error) {
cat, err := ctx.GetComponentAccessToken()
if err != nil {
return nil, nil, err
}
req := map[string]string{
"component_appid": ctx.AppID,
"authorizer_appid": appid,
}
uri := fmt.Sprintf(getComponentInfoURL, cat)
body, err := util.PostJSON(uri, req)
if err != nil {
return nil, nil, err
}
var ret struct {
AuthorizerInfo *AuthorizerInfo `json:"authorizer_info"`
AuthorizationInfo *AuthBaseInfo `json:"authorization_info"`
}
if err := json.Unmarshal(body, &ret); err != nil {
return nil, nil, err
}
return ret.AuthorizerInfo, ret.AuthorizationInfo, nil
}
+10
View File
@@ -0,0 +1,10 @@
package context
import (
"github.com/silenceper/wechat/v2/openplatform/config"
)
// Context struct
type Context struct {
*config.Config
}
@@ -0,0 +1,52 @@
package basic
import (
"fmt"
openContext "github.com/silenceper/wechat/v2/openplatform/context"
"github.com/silenceper/wechat/v2/util"
)
const (
getAccountBasicInfoURL = "https://api.weixin.qq.com/cgi-bin/account/getaccountbasicinfo"
)
// Basic 基础信息设置
type Basic struct {
*openContext.Context
appID string
}
// NewBasic new
func NewBasic(opContext *openContext.Context, appID string) *Basic {
return &Basic{Context: opContext, appID: appID}
}
// AccountBasicInfo 基础信息
type AccountBasicInfo struct {
util.CommonError
}
// GetAccountBasicInfo 获取小程序基础信息
//reference:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Mini_Program_Information_Settings.html
func (basic *Basic) GetAccountBasicInfo() (*AccountBasicInfo, error) {
ak, err := basic.GetAuthrAccessToken(basic.AppID)
if err != nil {
return nil, err
}
url := fmt.Sprintf("%s?access_token=%s", getAccountBasicInfoURL, ak)
data, err := util.HTTPGet(url)
if err != nil {
return nil, err
}
result := &AccountBasicInfo{}
if err := util.DecodeWithError(data, result, "account/getaccountbasicinfo"); err != nil {
return nil, err
}
return result, nil
}
// modify_domain设置服务器域名
// TODO
// func (encryptor *Basic) modifyDomain() {
// }
@@ -0,0 +1,69 @@
package component
import (
"fmt"
openContext "github.com/silenceper/wechat/v2/openplatform/context"
"github.com/silenceper/wechat/v2/util"
)
const (
fastregisterweappURL = "https://api.weixin.qq.com/cgi-bin/component/fastregisterweapp"
)
// Component 快速创建小程序
type Component struct {
*openContext.Context
}
// NewComponent new
func NewComponent(opContext *openContext.Context) *Component {
return &Component{opContext}
}
// RegisterMiniProgramParam 快速注册小程序参数
type RegisterMiniProgramParam struct {
Name string `json:"name"` // 企业名
Code string `json:"code"` // 企业代码
CodeType string `json:"code_type"` // 企业代码类型 1:统一社会信用代码(18 位) 2:组织机构代码(9 位 xxxxxxxx-x) 3:营业执照注册号(15 位)
LegalPersonaWechat string `json:"legal_persona_wechat"` // 法人微信号
LegalPersonaName string `json:"legal_persona_name"` // 法人姓名(绑定银行卡)
ComponentPhone string `json:"component_phone"` // 第三方联系电话(方便法人与第三方联系)
}
// RegisterMiniProgram 快速创建小程
// reference: https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Fast_Registration_Interface_document.html
func (component *Component) RegisterMiniProgram(param *RegisterMiniProgramParam) error {
componentAK, err := component.GetComponentAccessToken()
if err != nil {
return nil
}
url := fmt.Sprintf(fastregisterweappURL+"?action=create&component_access_token=%s", componentAK)
data, err := util.PostJSON(url, param)
if err != nil {
return err
}
return util.DecodeWithCommonError(data, "component/fastregisterweapp?action=create")
}
// GetRegistrationStatusParam 查询任务创建状态
type GetRegistrationStatusParam struct {
Name string `json:"name"` // 企业名
LegalPersonaWechat string `json:"legal_persona_wechat"` // 法人微信号
LegalPersonaName string `json:"legal_persona_name"` // 法人姓名(绑定银行卡)
}
// GetRegistrationStatus 查询创建任务状态.
func (component *Component) GetRegistrationStatus(param *GetRegistrationStatusParam) error {
componentAK, err := component.GetComponentAccessToken()
if err != nil {
return nil
}
url := fmt.Sprintf(fastregisterweappURL+"?action=search&component_access_token=%s", componentAK)
data, err := util.PostJSON(url, param)
if err != nil {
return err
}
return util.DecodeWithCommonError(data, "component/fastregisterweapp?action=search")
}
@@ -0,0 +1,32 @@
package miniprogram
import (
openContext "github.com/silenceper/wechat/v2/openplatform/context"
"github.com/silenceper/wechat/v2/openplatform/miniprogram/basic"
"github.com/silenceper/wechat/v2/openplatform/miniprogram/component"
)
// MiniProgram 代小程序实现业务
type MiniProgram struct {
AppID string
openContext *openContext.Context
}
// NewMiniProgram 实例化
func NewMiniProgram(opCtx *openContext.Context, appID string) *MiniProgram {
return &MiniProgram{
openContext: opCtx,
AppID: appID,
}
}
// GetComponent get component
// 快速注册小程序相关
func (miniProgram *MiniProgram) GetComponent() *component.Component {
return component.NewComponent(miniProgram.openContext)
}
// GetBasic 基础信息设置
func (miniProgram *MiniProgram) GetBasic() *basic.Basic {
return basic.NewBasic(miniProgram.openContext, miniProgram.AppID)
}
@@ -0,0 +1,57 @@
package js
import (
"fmt"
"github.com/silenceper/wechat/v2/credential"
"github.com/silenceper/wechat/v2/officialaccount/context"
officialJs "github.com/silenceper/wechat/v2/officialaccount/js"
"github.com/silenceper/wechat/v2/util"
)
// Js wx jssdk
type Js struct {
*context.Context
credential.JsTicketHandle
}
// NewJs init
func NewJs(context *context.Context, appID string) *Js {
js := new(Js)
js.Context = context
jsTicketHandle := credential.NewDefaultJsTicket(appID, credential.CacheKeyOfficialAccountPrefix, context.Cache)
js.SetJsTicketHandle(jsTicketHandle)
return js
}
// SetJsTicketHandle 自定义js ticket取值方式
func (js *Js) SetJsTicketHandle(ticketHandle credential.JsTicketHandle) {
js.JsTicketHandle = ticketHandle
}
// GetConfig 第三方平台 - 获取jssdk需要的配置参数
// uri 为当前网页地址
func (js *Js) GetConfig(uri, appid string) (config *officialJs.Config, err error) {
config = new(officialJs.Config)
var accessToken string
accessToken, err = js.GetAccessToken()
if err != nil {
return
}
var ticketStr string
ticketStr, err = js.GetTicket(accessToken)
if err != nil {
return
}
nonceStr := util.RandomStr(16)
timestamp := util.GetCurrTS()
str := fmt.Sprintf("jsapi_ticket=%s&noncestr=%s&timestamp=%d&url=%s", ticketStr, nonceStr, timestamp, uri)
sigStr := util.Signature(str)
config.AppID = appid
config.NonceStr = nonceStr
config.Timestamp = timestamp
config.Signature = sigStr
return
}
@@ -0,0 +1,65 @@
package oauth
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"github.com/silenceper/wechat/v2/officialaccount/context"
officialOauth "github.com/silenceper/wechat/v2/officialaccount/oauth"
"github.com/silenceper/wechat/v2/util"
)
const (
platformRedirectOauthURL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&component_appid=%s#wechat_redirect"
platformAccessTokenURL = "https://api.weixin.qq.com/sns/oauth2/component/access_token?appid=%s&code=%s&grant_type=authorization_code&component_appid=%s&component_access_token=%s"
)
// Oauth 平台代发起oauth2网页授权
type Oauth struct {
*context.Context
}
// NewOauth 实例化平台代发起oauth2网页授权
func NewOauth(context *context.Context) *Oauth {
auth := new(Oauth)
auth.Context = context
return auth
}
// GetRedirectURL 第三方平台 - 获取跳转的url地址
func (oauth *Oauth) GetRedirectURL(redirectURI, scope, state, appID string) (string, error) {
// url encode
urlStr := url.QueryEscape(redirectURI)
return fmt.Sprintf(platformRedirectOauthURL, appID, urlStr, scope, state, oauth.AppID), nil
}
// Redirect 第三方平台 - 跳转到网页授权
func (oauth *Oauth) Redirect(writer http.ResponseWriter, req *http.Request, redirectURI, scope, state, appID string) error {
location, err := oauth.GetRedirectURL(redirectURI, scope, state, appID)
if err != nil {
return err
}
http.Redirect(writer, req, location, http.StatusFound)
return nil
}
// GetUserAccessToken 第三方平台 - 通过网页授权的code 换取access_token(区别于context中的access_token)
func (oauth *Oauth) GetUserAccessToken(code, appID, componentAccessToken string) (result officialOauth.ResAccessToken, err error) {
urlStr := fmt.Sprintf(platformAccessTokenURL, appID, code, oauth.AppID, componentAccessToken)
var response []byte
response, err = util.HTTPGet(urlStr)
if err != nil {
return
}
err = json.Unmarshal(response, &result)
if err != nil {
return
}
if result.ErrCode != 0 {
err = fmt.Errorf("GetUserAccessToken error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
return
}
return
}
@@ -0,0 +1,60 @@
package officialaccount
import (
"github.com/silenceper/wechat/v2/credential"
"github.com/silenceper/wechat/v2/officialaccount"
offConfig "github.com/silenceper/wechat/v2/officialaccount/config"
opContext "github.com/silenceper/wechat/v2/openplatform/context"
"github.com/silenceper/wechat/v2/openplatform/officialaccount/js"
"github.com/silenceper/wechat/v2/openplatform/officialaccount/oauth"
)
// OfficialAccount 代公众号实现业务
type OfficialAccount struct {
// 授权的公众号的appID
appID string
*officialaccount.OfficialAccount
}
// NewOfficialAccount 实例化
// appID :为授权方公众号 APPID,非开放平台第三方平台 APPID
func NewOfficialAccount(opCtx *opContext.Context, appID string) *OfficialAccount {
officialAccount := officialaccount.NewOfficialAccount(&offConfig.Config{
AppID: opCtx.AppID,
EncodingAESKey: opCtx.EncodingAESKey,
Token: opCtx.Token,
Cache: opCtx.Cache,
})
// 设置获取access_token的函数
officialAccount.SetAccessTokenHandle(NewDefaultAuthrAccessToken(opCtx, appID))
return &OfficialAccount{appID: appID, OfficialAccount: officialAccount}
}
// PlatformOauth 平台代发起oauth2网页授权
func (officialAccount *OfficialAccount) PlatformOauth() *oauth.Oauth {
return oauth.NewOauth(officialAccount.GetContext())
}
// PlatformJs 平台代获取js-sdk配置
func (officialAccount *OfficialAccount) PlatformJs() *js.Js {
return js.NewJs(officialAccount.GetContext(), officialAccount.appID)
}
// DefaultAuthrAccessToken 默认获取授权ak的方法
type DefaultAuthrAccessToken struct {
opCtx *opContext.Context
appID string
}
// NewDefaultAuthrAccessToken New
func NewDefaultAuthrAccessToken(opCtx *opContext.Context, appID string) credential.AccessTokenHandle {
return &DefaultAuthrAccessToken{
opCtx: opCtx,
appID: appID,
}
}
// GetAccessToken 获取ak
func (ak *DefaultAuthrAccessToken) GetAccessToken() (string, error) {
return ak.opCtx.GetAuthrAccessToken(ak.appID)
}
+50
View File
@@ -0,0 +1,50 @@
package openplatform
import (
"net/http"
"github.com/silenceper/wechat/v2/officialaccount/server"
"github.com/silenceper/wechat/v2/openplatform/account"
"github.com/silenceper/wechat/v2/openplatform/config"
"github.com/silenceper/wechat/v2/openplatform/context"
"github.com/silenceper/wechat/v2/openplatform/miniprogram"
"github.com/silenceper/wechat/v2/openplatform/officialaccount"
)
// OpenPlatform 微信开放平台相关api
type OpenPlatform struct {
*context.Context
}
// NewOpenPlatform new openplatform
func NewOpenPlatform(cfg *config.Config) *OpenPlatform {
if cfg.Cache == nil {
panic("cache 未设置")
}
ctx := &context.Context{
Config: cfg,
}
return &OpenPlatform{ctx}
}
// GetServer get server
func (openPlatform *OpenPlatform) GetServer(req *http.Request, writer http.ResponseWriter) *server.Server {
off := officialaccount.NewOfficialAccount(openPlatform.Context, "")
return off.GetServer(req, writer)
}
// GetOfficialAccount 公众号代处理
func (openPlatform *OpenPlatform) GetOfficialAccount(appID string) *officialaccount.OfficialAccount {
return officialaccount.NewOfficialAccount(openPlatform.Context, appID)
}
// GetMiniProgram 小程序代理
func (openPlatform *OpenPlatform) GetMiniProgram(appID string) *miniprogram.MiniProgram {
return miniprogram.NewMiniProgram(openPlatform.Context, appID)
}
// GetAccountManager 账号管理
// TODO
func (openPlatform *OpenPlatform) GetAccountManager() *account.Account {
return account.NewAccount(openPlatform.Context)
}