1
0
mirror of https://github.com/silenceper/wechat.git synced 2026-02-08 14:42:26 +08:00

Compare commits

...

4 Commits

Author SHA1 Message Date
markwang
8a810837a4 feat: 微信小程序-动态消息及订阅消息 (#835)
* feat: 微信小程序-动态消息及订阅消息

* feat: 微信小程序-动态消息及订阅消息

* feat: 微信小程序-动态消息及订阅消息
2025-06-18 16:16:43 +08:00
yahuian
c51d41ee8a security 模块增加 context 调用函数 (#836) 2025-06-18 16:14:10 +08:00
Lien Li
24f812d187 feat: 支持Redis作为Cache的时候使用TLS (#834)
* feat: 支持Redis作为Cache的时候使用TLS

* feat: fix lint

* fix lint

* Update redis.go
2025-05-03 23:43:15 +08:00
markwang
dd43b7baa3 feat: 微信小程序-小程序链接 (#833)
* feat: 微信小程序-小程序链接

* feat: 微信小程序-小程序链接
2025-05-01 10:19:19 +08:00
7 changed files with 407 additions and 68 deletions

33
cache/redis.go vendored
View File

@@ -2,6 +2,8 @@ package cache
import ( import (
"context" "context"
"crypto/tls"
"net"
"time" "time"
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
@@ -15,25 +17,38 @@ type Redis struct {
// RedisOpts redis 连接属性 // RedisOpts redis 连接属性
type RedisOpts struct { type RedisOpts struct {
Host string `yml:"host" json:"host"` Host string `json:"host" yml:"host"`
Username string `yaml:"username" json:"username"` Username string `json:"username" yaml:"username"`
Password string `yml:"password" json:"password"` Password string `json:"password" yml:"password"`
Database int `yml:"database" json:"database"` Database int `json:"database" yml:"database"`
MaxIdle int `yml:"max_idle" json:"max_idle"` MaxIdle int `json:"max_idle" yml:"max_idle"`
MaxActive int `yml:"max_active" json:"max_active"` MaxActive int `json:"max_active" yml:"max_active"`
IdleTimeout int `yml:"idle_timeout" json:"idle_timeout"` // second IdleTimeout int `json:"idle_timeout" yml:"idle_timeout"` // second
UseTLS bool `json:"use_tls" yml:"use_tls"` // 是否使用TLS
} }
// NewRedis 实例化 // NewRedis 实例化
func NewRedis(ctx context.Context, opts *RedisOpts) *Redis { func NewRedis(ctx context.Context, opts *RedisOpts) *Redis {
conn := redis.NewUniversalClient(&redis.UniversalOptions{ uniOpt := &redis.UniversalOptions{
Addrs: []string{opts.Host}, Addrs: []string{opts.Host},
DB: opts.Database, DB: opts.Database,
Username: opts.Username, Username: opts.Username,
Password: opts.Password, Password: opts.Password,
IdleTimeout: time.Second * time.Duration(opts.IdleTimeout), IdleTimeout: time.Second * time.Duration(opts.IdleTimeout),
MinIdleConns: opts.MaxIdle, MinIdleConns: opts.MaxIdle,
}) }
if opts.UseTLS {
h, _, err := net.SplitHostPort(opts.Host)
if err != nil {
h = opts.Host
}
uniOpt.TLSConfig = &tls.Config{
ServerName: h,
}
}
conn := redis.NewUniversalClient(uniOpt)
return &Redis{ctx: ctx, conn: conn} return &Redis{ctx: ctx, conn: conn}
} }

View File

@@ -8,10 +8,12 @@ import (
) )
const ( const (
// createActivityURL 创建activity_id // createActivityIDURL 创建activity_id
createActivityURL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/activityid/create?access_token=%s" createActivityIDURL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/activityid/create?access_token=%s&unionid=%s&openid=%s"
// SendUpdatableMsgURL 修改动态消息 // SendUpdatableMsgURL 修改动态消息
setUpdatableMsgURL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/updatablemsg/send?access_token=%s" setUpdatableMsgURL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/updatablemsg/send?access_token=%s"
// setChatToolMsgURL 修改小程序聊天工具的动态卡片消息
setChatToolMsgURL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/chattoolmsg/send?access_token=%s"
) )
// UpdatableTargetState 动态消息状态 // UpdatableTargetState 动态消息状态
@@ -38,15 +40,26 @@ func NewUpdatableMessage(ctx *context.Context) *UpdatableMessage {
} }
} }
// CreateActivityIDRequest 创建activity_id请求
type CreateActivityIDRequest struct {
UnionID string
OpenID string
}
// CreateActivityID 创建activity_id // CreateActivityID 创建activity_id
func (updatableMessage *UpdatableMessage) CreateActivityID() (res CreateActivityIDResponse, err error) { func (updatableMessage *UpdatableMessage) CreateActivityID() (CreateActivityIDResponse, error) {
return updatableMessage.CreateActivityIDWithReq(&CreateActivityIDRequest{})
}
// CreateActivityIDWithReq 创建activity_id
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/updatable-message/createActivityId.html
func (updatableMessage *UpdatableMessage) CreateActivityIDWithReq(req *CreateActivityIDRequest) (res CreateActivityIDResponse, err error) {
accessToken, err := updatableMessage.GetAccessToken() accessToken, err := updatableMessage.GetAccessToken()
if err != nil { if err != nil {
return return
} }
url := fmt.Sprintf(createActivityIDURL, accessToken, req.UnionID, req.OpenID)
uri := fmt.Sprintf(createActivityURL, accessToken) response, err := util.HTTPGet(url)
response, err := util.HTTPGet(uri)
if err != nil { if err != nil {
return return
} }
@@ -100,3 +113,35 @@ type SendUpdatableMsgReq struct {
TemplateInfo UpdatableMsgTemplate `json:"template_info"` TemplateInfo UpdatableMsgTemplate `json:"template_info"`
TargetState UpdatableTargetState `json:"target_state"` TargetState UpdatableTargetState `json:"target_state"`
} }
// SetChatToolMsgRequest 修改小程序聊天工具的动态卡片消息请求
type SetChatToolMsgRequest struct {
VersionType int64 `json:"version_type"`
TargetState UpdatableTargetState `json:"target_state"`
ActivityID string `json:"activity_id"`
TemplateID string `json:"template_id"`
ParticipatorInfoList []ParticipatorInfo `json:"participator_info_list,omitempty"`
}
// ParticipatorInfo 更新后的聊天室成员状态
type ParticipatorInfo struct {
State int `json:"state"`
GroupOpenID string `json:"group_openid"`
}
// SetChatToolMsg 修改小程序聊天工具的动态卡片消息
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/updatable-message/setChatToolMsg.html
func (updatableMessage *UpdatableMessage) SetChatToolMsg(req *SetChatToolMsgRequest) error {
var (
accessToken string
err error
)
if accessToken, err = updatableMessage.GetAccessToken(); err != nil {
return err
}
var response []byte
if response, err = util.PostJSON(fmt.Sprintf(setChatToolMsgURL, accessToken), req); err != nil {
return err
}
return util.DecodeWithCommonError(response, "SetChatToolMsg")
}

View File

@@ -1,6 +1,7 @@
package security package security
import ( import (
context2 "context"
"fmt" "fmt"
"strconv" "strconv"
@@ -64,7 +65,12 @@ type MediaCheckAsyncRequest struct {
// MediaCheckAsync 异步校验图片/音频是否含有违法违规内容 // MediaCheckAsync 异步校验图片/音频是否含有违法违规内容
func (security *Security) MediaCheckAsync(in *MediaCheckAsyncRequest) (traceID string, err error) { func (security *Security) MediaCheckAsync(in *MediaCheckAsyncRequest) (traceID string, err error) {
accessToken, err := security.GetAccessToken() return security.MediaCheckAsyncContext(context2.Background(), in)
}
// MediaCheckAsyncContext 异步校验图片/音频是否含有违法违规内容
func (security *Security) MediaCheckAsyncContext(ctx context2.Context, in *MediaCheckAsyncRequest) (traceID string, err error) {
accessToken, err := security.GetAccessTokenContext(ctx)
if err != nil { if err != nil {
return return
} }
@@ -77,7 +83,7 @@ func (security *Security) MediaCheckAsync(in *MediaCheckAsyncRequest) (traceID s
req.Version = 2 req.Version = 2
uri := fmt.Sprintf(mediaCheckAsyncURL, accessToken) uri := fmt.Sprintf(mediaCheckAsyncURL, accessToken)
response, err := util.PostJSON(uri, req) response, err := util.PostJSONContext(ctx, uri, req)
if err != nil { if err != nil {
return return
} }
@@ -222,7 +228,12 @@ func (security *Security) MsgCheckV1(content string) (res MsgCheckResponse, err
// MsgCheck 检查一段文本是否含有违法违规内容 // MsgCheck 检查一段文本是否含有违法违规内容
func (security *Security) MsgCheck(in *MsgCheckRequest) (res MsgCheckResponse, err error) { func (security *Security) MsgCheck(in *MsgCheckRequest) (res MsgCheckResponse, err error) {
accessToken, err := security.GetAccessToken() return security.MsgCheckContext(context2.Background(), in)
}
// MsgCheckContext 检查一段文本是否含有违法违规内容
func (security *Security) MsgCheckContext(ctx context2.Context, in *MsgCheckRequest) (res MsgCheckResponse, err error) {
accessToken, err := security.GetAccessTokenContext(ctx)
if err != nil { if err != nil {
return return
} }
@@ -235,7 +246,7 @@ func (security *Security) MsgCheck(in *MsgCheckRequest) (res MsgCheckResponse, e
req.Version = 2 req.Version = 2
uri := fmt.Sprintf(msgCheckURL, accessToken) uri := fmt.Sprintf(msgCheckURL, accessToken)
response, err := util.PostJSON(uri, req) response, err := util.PostJSONContext(ctx, uri, req)
if err != nil { if err != nil {
return return
} }

View File

@@ -12,22 +12,30 @@ const (
// 发送订阅消息 // 发送订阅消息
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
subscribeSendURL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send" subscribeSendURL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send"
// 获取当前帐号下的个人模板列表 // 获取当前帐号下的个人模板列表
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.getTemplateList.html // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.getTemplateList.html
getTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate" getTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate"
// 添加订阅模板 // 添加订阅模板
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.addTemplate.html // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.addTemplate.html
addTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/addtemplate" addTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/addtemplate"
// 删除私有模板 // 删除私有模板
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.deleteTemplate.html // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.deleteTemplate.html
delTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/deltemplate" delTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/deltemplate"
// 统一服务消息 // 统一服务消息
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/uniform-message/uniformMessage.send.html // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/uniform-message/uniformMessage.send.html
uniformMessageSend = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send" uniformMessageSend = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send"
// getCategoryURL 获取类目
getCategoryURL = "https://api.weixin.qq.com/wxaapi/newtmpl/getcategory?access_token=%s"
// getPubTemplateKeyWordsByIDURL 获取关键词列表
getPubTemplateKeyWordsByIDURL = "https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatekeywords?access_token=%s&tid=%s"
// getPubTemplateTitleListURL 获取所属类目下的公共模板
getPubTemplateTitleListURL = "https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatetitles?access_token=%s&ids=%s&start=%d&limit=%d"
// setUserNotifyURL 激活与更新服务卡片
setUserNotifyURL = "https://api.weixin.qq.com/wxa/set_user_notify?access_token=%s"
// setUserNotifyExtURL 更新服务卡片扩展信息
setUserNotifyExtURL = "https://api.weixin.qq.com/wxa/set_user_notifyext?access_token=%s"
// getUserNotifyURL 查询服务卡片状态
getUserNotifyURL = "https://api.weixin.qq.com/wxa/get_user_notify?access_token=%s"
) )
// Subscribe 订阅消息 // Subscribe 订阅消息
@@ -58,11 +66,18 @@ type DataItem struct {
// TemplateItem template item // TemplateItem template item
type TemplateItem struct { type TemplateItem struct {
PriTmplID string `json:"priTmplId"` PriTmplID string `json:"priTmplId"`
Title string `json:"title"` Title string `json:"title"`
Content string `json:"content"` Content string `json:"content"`
Example string `json:"example"` Example string `json:"example"`
Type int64 `json:"type"` Type int64 `json:"type"`
KeywordEnumValueList []KeywordEnumValue `json:"keywordEnumValueList"`
}
// KeywordEnumValue 枚举参数值范围
type KeywordEnumValue struct {
EnumValueList []string `json:"enumValueList"`
KeywordCode string `json:"keywordCode"`
} }
// TemplateList template list // TemplateList template list
@@ -224,3 +239,200 @@ func (s *Subscribe) Delete(templateID string) (err error) {
} }
return util.DecodeWithCommonError(response, "DeleteSubscribe") return util.DecodeWithCommonError(response, "DeleteSubscribe")
} }
// GetCategoryResponse 获取类目响应
type GetCategoryResponse struct {
util.CommonError
Data []Category `json:"data"`
}
// Category 类目
type Category struct {
ID int64 `json:"id"`
Name string `json:"name"`
}
// GetCategory 获取类目
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/getCategory.html
func (s *Subscribe) GetCategory() ([]Category, error) {
var (
accessToken string
err error
)
if accessToken, err = s.GetAccessToken(); err != nil {
return nil, err
}
var response []byte
if response, err = util.HTTPGet(fmt.Sprintf(getCategoryURL, accessToken)); err != nil {
return nil, err
}
result := &GetCategoryResponse{}
err = util.DecodeWithError(response, result, "GetCategory")
return result.Data, err
}
// GetPubTemplateKeywordsByIDResponse 获取关键词列表响应
type GetPubTemplateKeywordsByIDResponse struct {
util.CommonError
Count int64 `json:"count"`
Data []PubTemplateKeywords `json:"data"`
}
// PubTemplateKeywords 关键词
type PubTemplateKeywords struct {
KID int64 `json:"kid"`
Name string `json:"name"`
Example string `json:"example"`
Rule string `json:"rule"`
}
// GetPubTemplateKeywordsByID 获取关键词列表
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/getPubTemplateKeyWordsById.html
func (s *Subscribe) GetPubTemplateKeywordsByID(tid string) (*GetPubTemplateKeywordsByIDResponse, error) {
var (
accessToken string
err error
)
if accessToken, err = s.GetAccessToken(); err != nil {
return nil, err
}
var response []byte
if response, err = util.HTTPGet(fmt.Sprintf(getPubTemplateKeyWordsByIDURL, accessToken, tid)); err != nil {
return nil, err
}
result := &GetPubTemplateKeywordsByIDResponse{}
err = util.DecodeWithError(response, result, "GetPubTemplateKeywordsByID")
return result, err
}
// GetPubTemplateTitleListRequest 获取所属类目下的公共模板请求
type GetPubTemplateTitleListRequest struct {
Start int64
Limit int64
IDs string
}
// GetPubTemplateTitleListResponse 获取所属类目下的公共模板响应
type GetPubTemplateTitleListResponse struct {
util.CommonError
Count int64 `json:"count"`
Data []PubTemplateTitle `json:"data"`
}
// PubTemplateTitle 模板标题
type PubTemplateTitle struct {
Type int64 `json:"type"`
TID string `json:"tid"`
Title string `json:"title"`
CategoryID string `json:"categoryId"`
}
// GetPubTemplateTitleList 获取所属类目下的公共模板
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/getPubTemplateTitleList.html
func (s *Subscribe) GetPubTemplateTitleList(req *GetPubTemplateTitleListRequest) (*GetPubTemplateTitleListResponse, error) {
var (
accessToken string
err error
)
if accessToken, err = s.GetAccessToken(); err != nil {
return nil, err
}
var response []byte
if response, err = util.HTTPGet(fmt.Sprintf(getPubTemplateTitleListURL, accessToken, req.IDs, req.Start, req.Limit)); err != nil {
return nil, err
}
result := &GetPubTemplateTitleListResponse{}
err = util.DecodeWithError(response, result, "GetPubTemplateTitleList")
return result, err
}
// SetUserNotifyRequest 激活与更新服务卡片请求
type SetUserNotifyRequest struct {
OpenID string `json:"openid"`
NotifyType int64 `json:"notify_type"`
NotifyCode string `json:"notify_code"`
ContentJSON string `json:"content_json"`
CheckJSON string `json:"check_json,omitempty"`
}
// SetUserNotify 激活与更新服务卡片
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/setUserNotify.html
func (s *Subscribe) SetUserNotify(req *SetUserNotifyRequest) error {
var (
accessToken string
err error
)
if accessToken, err = s.GetAccessToken(); err != nil {
return err
}
var response []byte
if response, err = util.PostJSON(fmt.Sprintf(setUserNotifyURL, accessToken), req); err != nil {
return err
}
return util.DecodeWithCommonError(response, "SetUserNotify")
}
// SetUserNotifyExtRequest 更新服务卡片扩展信息请求
type SetUserNotifyExtRequest struct {
OpenID string `json:"openid"`
NotifyType int64 `json:"notify_type"`
NotifyCode string `json:"notify_code"`
ExtJSON string `json:"ext_json"`
}
// SetUserNotifyExt 更新服务卡片扩展信息
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/setUserNotifyExt.html
func (s *Subscribe) SetUserNotifyExt(req *SetUserNotifyExtRequest) error {
var (
accessToken string
err error
)
if accessToken, err = s.GetAccessToken(); err != nil {
return err
}
var response []byte
if response, err = util.PostJSON(fmt.Sprintf(setUserNotifyExtURL, accessToken), req); err != nil {
return err
}
return util.DecodeWithCommonError(response, "SetUserNotifyExt")
}
// GetUserNotifyRequest 查询服务卡片状态请求
type GetUserNotifyRequest struct {
OpenID string `json:"openid"`
NotifyType int64 `json:"notify_type"`
NotifyCode string `json:"notify_code"`
}
// GetUserNotifyResponse 查询服务卡片状态响应
type GetUserNotifyResponse struct {
util.CommonError
NotifyInfo NotifyInfo `json:"notify_info"`
}
// NotifyInfo 卡片状态
type NotifyInfo struct {
NotifyType int64 `json:"notify_type"`
ContentJSON string `json:"content_json"`
CodeState int64 `json:"code_state"`
CodeExpireTime int64 `json:"code_expire_time"`
}
// GetUserNotify 查询服务卡片状态
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/getUserNotify.html
func (s *Subscribe) GetUserNotify(req *GetUserNotifyRequest) (*GetUserNotifyResponse, error) {
var (
accessToken string
err error
)
if accessToken, err = s.GetAccessToken(); err != nil {
return nil, err
}
var response []byte
if response, err = util.PostJSON(fmt.Sprintf(getUserNotifyURL, accessToken), req); err != nil {
return nil, err
}
result := &GetUserNotifyResponse{}
err = util.DecodeWithError(response, result, "GetUserNotify")
return result, err
}

View File

@@ -6,7 +6,13 @@ import (
"github.com/silenceper/wechat/v2/util" "github.com/silenceper/wechat/v2/util"
) )
const queryURL = "https://api.weixin.qq.com/wxa/query_urllink" const queryURL = "https://api.weixin.qq.com/wxa/query_urllink?access_token=%s"
// ULQueryRequest 查询加密URLLink请求
type ULQueryRequest struct {
URLLink string `json:"url_link"`
QueryType int `json:"query_type"`
}
// ULQueryResult 返回的结果 // ULQueryResult 返回的结果
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.query.html 返回值 // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.query.html 返回值
@@ -28,25 +34,35 @@ type ULQueryResult struct {
ResourceAppid string `json:"resource_appid"` ResourceAppid string `json:"resource_appid"`
} `json:"cloud_base"` } `json:"cloud_base"`
} `json:"url_link_info"` } `json:"url_link_info"`
VisitOpenid string `json:"visit_openid"` VisitOpenid string `json:"visit_openid"`
QuotaInfo QuotaInfo `json:"quota_info"`
}
// QuotaInfo quota 配置
type QuotaInfo struct {
RemainVisitQuota int64 `json:"remain_visit_quota"`
} }
// Query 查询小程序 url_link 配置。 // Query 查询小程序 url_link 配置。
func (u *URLLink) Query(urlLink string) (*ULQueryResult, error) { func (u *URLLink) Query(urlLink string) (*ULQueryResult, error) {
accessToken, err := u.GetAccessToken() return u.QueryWithType(&ULQueryRequest{URLLink: urlLink})
if err != nil { }
return nil, err
} // QueryWithType 查询加密URLLink
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-link/queryUrlLink.html
uri := fmt.Sprintf("%s?access_token=%s", queryURL, accessToken) func (u *URLLink) QueryWithType(req *ULQueryRequest) (*ULQueryResult, error) {
response, err := util.PostJSON(uri, map[string]string{"url_link": urlLink}) var (
if err != nil { accessToken string
return nil, err err error
} )
var resp ULQueryResult if accessToken, err = u.GetAccessToken(); err != nil {
err = util.DecodeWithError(response, &resp, "URLLink.Query") return nil, err
if err != nil { }
return nil, err var response []byte
} if response, err = util.PostJSON(fmt.Sprintf(queryURL, accessToken), req); err != nil {
return &resp, nil return nil, err
}
result := &ULQueryResult{}
err = util.DecodeWithError(response, result, "URLLink.Query")
return result, err
} }

View File

@@ -14,7 +14,8 @@ const (
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.query.html#参数 // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.query.html#参数
type QueryScheme struct { type QueryScheme struct {
// 小程序 scheme 码 // 小程序 scheme 码
Scheme string `json:"scheme"` Scheme string `json:"scheme"`
QueryType int `json:"query_type"`
} }
// SchemeInfo scheme 配置 // SchemeInfo scheme 配置
@@ -33,34 +34,47 @@ type SchemeInfo struct {
EnvVersion EnvVersion `json:"env_version"` EnvVersion EnvVersion `json:"env_version"`
} }
// resQueryScheme 返回结构体 // QuotaInfo quota 配置
type QuotaInfo struct {
RemainVisitQuota int64 `json:"remain_visit_quota"`
}
// ResQueryScheme 返回结构体
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.query.html#参数 // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.query.html#参数
type resQueryScheme struct { type ResQueryScheme struct {
// 通用错误 // 通用错误
util.CommonError util.CommonError
// scheme 配置 // scheme 配置
SchemeInfo SchemeInfo `json:"scheme_info"` SchemeInfo SchemeInfo `json:"scheme_info"`
// 访问该链接的openid没有用户访问过则为空字符串 // 访问该链接的openid没有用户访问过则为空字符串
VisitOpenid string `json:"visit_openid"` VisitOpenid string `json:"visit_openid"`
QuotaInfo QuotaInfo `json:"quota_info"`
} }
// QueryScheme 查询小程序 scheme 码 // QueryScheme 查询小程序 scheme 码
func (u *URLScheme) QueryScheme(querySchemeParams QueryScheme) (schemeInfo SchemeInfo, visitOpenid string, err error) { func (u *URLScheme) QueryScheme(querySchemeParams QueryScheme) (schemeInfo SchemeInfo, visitOpenid string, err error) {
var accessToken string res, err := u.QuerySchemeWithRes(querySchemeParams)
accessToken, err = u.GetAccessToken()
if err != nil { if err != nil {
return return
} }
urlStr := fmt.Sprintf(querySchemeURL, accessToken)
var response []byte
response, err = util.PostJSON(urlStr, querySchemeParams)
if err != nil {
return
}
// 使用通用方法返回错误
var res resQueryScheme
err = util.DecodeWithError(response, &res, "QueryScheme")
return res.SchemeInfo, res.VisitOpenid, err return res.SchemeInfo, res.VisitOpenid, err
} }
// QuerySchemeWithRes 查询scheme码
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-scheme/queryScheme.html
func (u *URLScheme) QuerySchemeWithRes(req QueryScheme) (*ResQueryScheme, error) {
var (
accessToken string
err error
)
if accessToken, err = u.GetAccessToken(); err != nil {
return nil, err
}
var response []byte
if response, err = util.PostJSON(fmt.Sprintf(querySchemeURL, accessToken), req); err != nil {
return nil, err
}
result := &ResQueryScheme{}
err = util.DecodeWithError(response, result, "QueryScheme")
return result, err
}

View File

@@ -17,7 +17,12 @@ func NewURLScheme(ctx *context.Context) *URLScheme {
return &URLScheme{Context: ctx} return &URLScheme{Context: ctx}
} }
const generateURL = "https://api.weixin.qq.com/wxa/generatescheme" const (
// generateURL 获取加密scheme码
generateURL = "https://api.weixin.qq.com/wxa/generatescheme"
// generateNFCURL 获取 NFC 的小程序 scheme
generateNFCURL = "https://api.weixin.qq.com/wxa/generatenfcscheme?access_token=%s"
)
// TExpireType 失效类型 (指定时间戳/指定间隔) // TExpireType 失效类型 (指定时间戳/指定间隔)
type TExpireType int type TExpireType int
@@ -50,11 +55,13 @@ type JumpWxa struct {
// USParams 请求参数 // USParams 请求参数
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.generate.html#请求参数 // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.generate.html#请求参数
type USParams struct { type USParams struct {
JumpWxa *JumpWxa `json:"jump_wxa"` JumpWxa *JumpWxa `json:"jump_wxa,omitempty"`
ExpireType TExpireType `json:"expire_type"` ExpireType TExpireType `json:"expire_type,omitempty"`
ExpireTime int64 `json:"expire_time"` ExpireTime int64 `json:"expire_time,omitempty"`
ExpireInterval int `json:"expire_interval"` ExpireInterval int `json:"expire_interval,omitempty"`
IsExpire bool `json:"is_expire,omitempty"` IsExpire bool `json:"is_expire,omitempty"`
ModelID string `json:"model_id,omitempty"`
Sn string `json:"sn,omitempty"`
} }
// USResult 返回的结果 // USResult 返回的结果
@@ -81,3 +88,22 @@ func (u *URLScheme) Generate(params *USParams) (string, error) {
err = util.DecodeWithError(response, &resp, "URLScheme.Generate") err = util.DecodeWithError(response, &resp, "URLScheme.Generate")
return resp.OpenLink, err return resp.OpenLink, err
} }
// GenerateNFC 获取 NFC 的小程序 scheme
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-scheme/generateNFCScheme.html
func (u *URLScheme) GenerateNFC(params *USParams) (string, error) {
var (
accessToken string
err error
)
if accessToken, err = u.GetAccessToken(); err != nil {
return "", err
}
var response []byte
if response, err = util.PostJSON(fmt.Sprintf(generateNFCURL, accessToken), params); err != nil {
return "", err
}
result := &USResult{}
err = util.DecodeWithError(response, result, "URLScheme.GenerateNFC")
return result.OpenLink, err
}