mirror of
https://github.com/silenceper/wechat.git
synced 2026-02-04 12:52:27 +08:00
Merge branch 'v2' of github.com:silenceper/wechat into feature/remove-redis
This commit is contained in:
6
.github/ISSUE_TEMPLATE/bug.md
vendored
6
.github/ISSUE_TEMPLATE/bug.md
vendored
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: 报告Bug
|
||||
about: 反馈BUG信息
|
||||
name: 报告 Bug
|
||||
about: 反馈 BUG 信息
|
||||
title: "[BUG]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
@@ -18,4 +18,4 @@ assignees: ''
|
||||
|
||||
|
||||
**使用的版本**
|
||||
- SDK版本: [比如 v0.0.0]
|
||||
- SDK 版本:[比如 v0.0.0]
|
||||
|
||||
8
.github/ISSUE_TEMPLATE/feature.md
vendored
8
.github/ISSUE_TEMPLATE/feature.md
vendored
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: API需求
|
||||
about: 待实现的API接口,SDK的强大离不开社区的帮助,欢迎为项目贡献PR
|
||||
name: API 需求
|
||||
about: 待实现的 API 接口,SDK 的强大离不开社区的帮助,欢迎为项目贡献 PR
|
||||
title: "[Feature]"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
@@ -8,8 +8,8 @@ assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
!!!SDK的强大离不开社区的帮助,欢迎为本项目贡献PR!!!
|
||||
!!!SDK 的强大离不开社区的帮助,欢迎为本项目贡献 PR!!!
|
||||
-->
|
||||
**你想要实现的模块或API**
|
||||
**你想要实现的模块或 API**
|
||||
|
||||
|
||||
|
||||
6
.github/ISSUE_TEMPLATE/question.md
vendored
6
.github/ISSUE_TEMPLATE/question.md
vendored
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: 使用咨询
|
||||
about: 关于SDK使用相关的咨询,在使用前请先阅读官方微信文档
|
||||
about: 关于 SDK 使用相关的咨询,在使用前请先阅读官方微信文档
|
||||
title: "[咨询]"
|
||||
labels: question
|
||||
assignees: ''
|
||||
@@ -9,7 +9,7 @@ assignees: ''
|
||||
|
||||
<!--
|
||||
重要:
|
||||
1、在使用本SDK前请先阅读对应的官方微信API文档:https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html
|
||||
2、本SDK部分接口文档: https://silenceper.com/wechat/
|
||||
1、在使用本 SDK 前请先阅读对应的官方微信 API 文档:https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html
|
||||
2、本 SDK 部分接口文档:https://silenceper.com/wechat/
|
||||
-->
|
||||
**请描述您的问题**
|
||||
|
||||
18
.github/workflows/go.yml
vendored
18
.github/workflows/go.yml
vendored
@@ -2,26 +2,26 @@ name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master,release-*,v2,feature/** ]
|
||||
branches: [ master,release-*,v2,feature/**,fix/** ]
|
||||
pull_request:
|
||||
branches: [ master,release-*,v2,feature/** ]
|
||||
branches: [ master,release-*,v2,feature/**,fix/** ]
|
||||
|
||||
jobs:
|
||||
golangci:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ '1.16','1.17','1.18','1.19','1.20','1.21' ]
|
||||
go-version: [ '1.16','1.17','1.18','1.19','1.20','1.21.4' ]
|
||||
name: golangci-lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Golang ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
uses: golangci/golangci-lint-action@v4
|
||||
with:
|
||||
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
||||
version: v1.52.2
|
||||
@@ -37,12 +37,12 @@ jobs:
|
||||
# strategy set
|
||||
strategy:
|
||||
matrix:
|
||||
go: [ '1.16','1.17','1.18','1.19','1.20','1.21' ]
|
||||
go: [ '1.16','1.17','1.18','1.19','1.20','1.21','1.22' ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
id: go
|
||||
|
||||
@@ -90,9 +90,9 @@ func (ak *DefaultAccessToken) GetAccessTokenContext(ctx context.Context) (access
|
||||
return
|
||||
}
|
||||
|
||||
if err = ak.cache.Set(accessTokenCacheKey, resAccessToken.AccessToken, time.Duration(resAccessToken.ExpiresIn-1500)*time.Second); err != nil {
|
||||
return
|
||||
}
|
||||
expires := resAccessToken.ExpiresIn - 1500
|
||||
err = ak.cache.Set(accessTokenCacheKey, resAccessToken.AccessToken, time.Duration(expires)*time.Second)
|
||||
|
||||
accessToken = resAccessToken.AccessToken
|
||||
return
|
||||
}
|
||||
@@ -141,7 +141,7 @@ func (ak *StableAccessToken) GetAccessTokenContext(ctx context.Context) (accessT
|
||||
}
|
||||
|
||||
expires := resAccessToken.ExpiresIn - 300
|
||||
_ = ak.cache.Set(accessTokenCacheKey, resAccessToken.AccessToken, time.Duration(expires)*time.Second)
|
||||
err = ak.cache.Set(accessTokenCacheKey, resAccessToken.AccessToken, time.Duration(expires)*time.Second)
|
||||
|
||||
accessToken = resAccessToken.AccessToken
|
||||
return
|
||||
@@ -219,9 +219,7 @@ func (ak *WorkAccessToken) GetAccessTokenContext(ctx context.Context) (accessTok
|
||||
|
||||
expires := resAccessToken.ExpiresIn - 1500
|
||||
err = ak.cache.Set(accessTokenCacheKey, resAccessToken.AccessToken, time.Duration(expires)*time.Second)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
accessToken = resAccessToken.AccessToken
|
||||
return
|
||||
}
|
||||
|
||||
@@ -138,10 +138,8 @@ func (auth *Auth) GetPhoneNumberContext(ctx context2.Context, code string) (*Get
|
||||
}
|
||||
|
||||
var result GetPhoneNumberResponse
|
||||
if err = util.DecodeWithError(response, &result, "phonenumber.getPhoneNumber"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
err = util.DecodeWithError(response, &result, "phonenumber.getPhoneNumber")
|
||||
return &result, err
|
||||
}
|
||||
|
||||
// GetPhoneNumber 小程序通过code获取用户手机号
|
||||
|
||||
@@ -45,10 +45,5 @@ func (business *Business) GetPhoneNumber(in *GetPhoneNumberRequest) (info PhoneI
|
||||
PhoneInfo PhoneInfo `json:"phone_info"`
|
||||
}
|
||||
err = util.DecodeWithError(response, &resp, "business.GetPhoneNumber")
|
||||
if nil != err {
|
||||
return
|
||||
}
|
||||
|
||||
info = resp.PhoneInfo
|
||||
return
|
||||
return resp.PhoneInfo, err
|
||||
}
|
||||
|
||||
@@ -398,7 +398,7 @@ type PushDataSecVodUpload struct {
|
||||
|
||||
// SecVodUploadEvent 短剧媒资上传完成事件
|
||||
type SecVodUploadEvent struct {
|
||||
MediaID string `json:"media_id" xml:"media_id"` // 媒资 id
|
||||
MediaID int64 `json:"media_id" xml:"media_id"` // 媒资 id
|
||||
SourceContext string `json:"source_context" xml:"source_context"` // 透传上传接口中开发者设置的值。
|
||||
ErrCode int `json:"errcode" xml:"errcode"` // 错误码,上传失败时该值非
|
||||
ErrMsg string `json:"errmsg" xml:"errmsg"` // 错误提示
|
||||
@@ -412,7 +412,7 @@ type PushDataSecVodAudit struct {
|
||||
|
||||
// SecVodAuditEvent 短剧媒资审核状态事件
|
||||
type SecVodAuditEvent struct {
|
||||
DramaID string `json:"drama_id" xml:"drama_id"` // 剧目 id
|
||||
DramaID int64 `json:"drama_id" xml:"drama_id"` // 剧目 id
|
||||
SourceContext string `json:"source_context" xml:"source_context"` // 透传上传接口中开发者设置的值
|
||||
AuditDetail DramaAuditDetail `json:"audit_detail" xml:"audit_detail"` // 剧目审核结果,单独每一集的审核结果可以根据 drama_id 查询剧集详情得到
|
||||
}
|
||||
|
||||
102
miniprogram/message/updatable_msg.go
Normal file
102
miniprogram/message/updatable_msg.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/silenceper/wechat/v2/miniprogram/context"
|
||||
"github.com/silenceper/wechat/v2/util"
|
||||
)
|
||||
|
||||
const (
|
||||
// createActivityURL 创建activity_id
|
||||
createActivityURL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/activityid/create?access_token=%s"
|
||||
// SendUpdatableMsgURL 修改动态消息
|
||||
setUpdatableMsgURL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/updatablemsg/send?access_token=%s"
|
||||
)
|
||||
|
||||
// UpdatableTargetState 动态消息状态
|
||||
type UpdatableTargetState int
|
||||
|
||||
const (
|
||||
// TargetStateNotStarted 未开始
|
||||
TargetStateNotStarted UpdatableTargetState = 0
|
||||
// TargetStateStarted 已开始
|
||||
TargetStateStarted UpdatableTargetState = 1
|
||||
// TargetStateFinished 已结束
|
||||
TargetStateFinished UpdatableTargetState = 2
|
||||
)
|
||||
|
||||
// UpdatableMessage 动态消息
|
||||
type UpdatableMessage struct {
|
||||
*context.Context
|
||||
}
|
||||
|
||||
// NewUpdatableMessage 实例化
|
||||
func NewUpdatableMessage(ctx *context.Context) *UpdatableMessage {
|
||||
return &UpdatableMessage{
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateActivityID 创建activity_id
|
||||
func (updatableMessage *UpdatableMessage) CreateActivityID() (res CreateActivityIDResponse, err error) {
|
||||
accessToken, err := updatableMessage.GetAccessToken()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf(createActivityURL, accessToken)
|
||||
response, err := util.HTTPGet(uri)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = util.DecodeWithError(response, &res, "CreateActivityID")
|
||||
return
|
||||
}
|
||||
|
||||
// SetUpdatableMsg 修改动态消息
|
||||
func (updatableMessage *UpdatableMessage) SetUpdatableMsg(activityID string, targetState UpdatableTargetState, template UpdatableMsgTemplate) (err error) {
|
||||
accessToken, err := updatableMessage.GetAccessToken()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf(setUpdatableMsgURL, accessToken)
|
||||
data := SendUpdatableMsgReq{
|
||||
ActivityID: activityID,
|
||||
TargetState: targetState,
|
||||
TemplateInfo: template,
|
||||
}
|
||||
|
||||
response, err := util.PostJSON(uri, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return util.DecodeWithCommonError(response, "SendUpdatableMsg")
|
||||
}
|
||||
|
||||
// CreateActivityIDResponse 创建activity_id 返回
|
||||
type CreateActivityIDResponse struct {
|
||||
util.CommonError
|
||||
|
||||
ActivityID string `json:"activity_id"`
|
||||
ExpirationTime int64 `json:"expiration_time"`
|
||||
}
|
||||
|
||||
// UpdatableMsgTemplate 动态消息模板
|
||||
type UpdatableMsgTemplate struct {
|
||||
ParameterList []UpdatableMsgParameter `json:"parameter_list"`
|
||||
}
|
||||
|
||||
// UpdatableMsgParameter 动态消息参数
|
||||
type UpdatableMsgParameter struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// SendUpdatableMsgReq 修改动态消息参数
|
||||
type SendUpdatableMsgReq struct {
|
||||
ActivityID string `json:"activity_id"`
|
||||
TemplateInfo UpdatableMsgTemplate `json:"template_info"`
|
||||
TargetState UpdatableTargetState `json:"target_state"`
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/silenceper/wechat/v2/miniprogram/order"
|
||||
"github.com/silenceper/wechat/v2/miniprogram/privacy"
|
||||
"github.com/silenceper/wechat/v2/miniprogram/qrcode"
|
||||
"github.com/silenceper/wechat/v2/miniprogram/redpacketcover"
|
||||
"github.com/silenceper/wechat/v2/miniprogram/riskcontrol"
|
||||
"github.com/silenceper/wechat/v2/miniprogram/security"
|
||||
"github.com/silenceper/wechat/v2/miniprogram/shortlink"
|
||||
@@ -155,3 +156,13 @@ func (miniProgram *MiniProgram) GetShipping() *order.Shipping {
|
||||
func (miniProgram *MiniProgram) GetMiniDrama() *minidrama.MiniDrama {
|
||||
return minidrama.NewMiniDrama(miniProgram.ctx)
|
||||
}
|
||||
|
||||
// GetRedPacketCover 小程序微信红包封面 API
|
||||
func (miniProgram *MiniProgram) GetRedPacketCover() *redpacketcover.RedPacketCover {
|
||||
return redpacketcover.NewRedPacketCover(miniProgram.ctx)
|
||||
}
|
||||
|
||||
// GetUpdatableMessage 小程序动态消息
|
||||
func (miniProgram *MiniProgram) GetUpdatableMessage() *message.UpdatableMessage {
|
||||
return message.NewUpdatableMessage(miniProgram.ctx)
|
||||
}
|
||||
|
||||
@@ -103,11 +103,8 @@ func (s *Privacy) GetPrivacySetting(privacyVer int) (GetPrivacySettingResponse,
|
||||
}
|
||||
// 返回错误信息
|
||||
var result GetPrivacySettingResponse
|
||||
if err = util.DecodeWithError(response, &result, "getprivacysetting"); err != nil {
|
||||
return GetPrivacySettingResponse{}, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
err = util.DecodeWithError(response, &result, "getprivacysetting")
|
||||
return result, err
|
||||
}
|
||||
|
||||
// SetPrivacySetting 更新小程序权限配置
|
||||
@@ -130,11 +127,7 @@ func (s *Privacy) SetPrivacySetting(privacyVer int, ownerSetting OwnerSetting, s
|
||||
}
|
||||
|
||||
// 返回错误信息
|
||||
if err = util.DecodeWithCommonError(response, "setprivacysetting"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return util.DecodeWithCommonError(response, "setprivacysetting")
|
||||
}
|
||||
|
||||
// UploadPrivacyExtFileResponse 上传权限定义模板响应参数
|
||||
@@ -159,9 +152,6 @@ func (s *Privacy) UploadPrivacyExtFile(fileData []byte) (UploadPrivacyExtFileRes
|
||||
|
||||
// 返回错误信息
|
||||
var result UploadPrivacyExtFileResponse
|
||||
if err = util.DecodeWithError(response, &result, "setprivacysetting"); err != nil {
|
||||
return UploadPrivacyExtFileResponse{}, err
|
||||
}
|
||||
|
||||
err = util.DecodeWithError(response, &result, "setprivacysetting")
|
||||
return result, err
|
||||
}
|
||||
|
||||
59
miniprogram/redpacketcover/redpacketcover.go
Normal file
59
miniprogram/redpacketcover/redpacketcover.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package redpacketcover
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/silenceper/wechat/v2/miniprogram/context"
|
||||
"github.com/silenceper/wechat/v2/util"
|
||||
)
|
||||
|
||||
const (
|
||||
getRedPacketCoverURL = "https://api.weixin.qq.com/redpacketcover/wxapp/cover_url/get_by_token?access_token=%s"
|
||||
)
|
||||
|
||||
// RedPacketCover struct
|
||||
type RedPacketCover struct {
|
||||
*context.Context
|
||||
}
|
||||
|
||||
// NewRedPacketCover 实例
|
||||
func NewRedPacketCover(context *context.Context) *RedPacketCover {
|
||||
redPacketCover := new(RedPacketCover)
|
||||
redPacketCover.Context = context
|
||||
return redPacketCover
|
||||
}
|
||||
|
||||
// GetRedPacketCoverRequest 获取微信红包封面参数
|
||||
type GetRedPacketCoverRequest struct {
|
||||
// openid 可领取用户的openid
|
||||
OpenID string `json:"openid"`
|
||||
// ctoken 在红包封面平台获取发放ctoken(需要指定可以发放的appid)
|
||||
CToken string `json:"ctoken"`
|
||||
}
|
||||
|
||||
// GetRedPacketCoverResp 获取微信红包封面
|
||||
type GetRedPacketCoverResp struct {
|
||||
util.CommonError
|
||||
Data struct {
|
||||
URL string `json:"url"`
|
||||
} `json:"data"` // 唯一请求标识
|
||||
}
|
||||
|
||||
// GetRedPacketCoverURL 获得指定用户可以领取的红包封面链接。获取参数ctoken参考微信红包封面开放平台
|
||||
// 文档地址: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/red-packet-cover/getRedPacketCoverUrl.html
|
||||
func (cover *RedPacketCover) GetRedPacketCoverURL(coderParams GetRedPacketCoverRequest) (res GetRedPacketCoverResp, err error) {
|
||||
accessToken, err := cover.GetAccessToken()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf(getRedPacketCoverURL, accessToken)
|
||||
response, err := util.PostJSON(uri, coderParams)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 使用通用方法返回错误
|
||||
err = util.DecodeWithError(response, &res, "GetRedPacketCoverURL")
|
||||
return
|
||||
}
|
||||
@@ -51,12 +51,7 @@ func (security *Security) MediaCheckAsyncV1(in *MediaCheckAsyncV1Request) (trace
|
||||
TraceID string `json:"trace_id"`
|
||||
}
|
||||
err = util.DecodeWithError(response, &res, "MediaCheckAsyncV1")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
traceID = res.TraceID
|
||||
return
|
||||
return res.TraceID, err
|
||||
}
|
||||
|
||||
// MediaCheckAsyncRequest 图片/音频异步校验请求参数
|
||||
@@ -93,12 +88,7 @@ func (security *Security) MediaCheckAsync(in *MediaCheckAsyncRequest) (traceID s
|
||||
TraceID string `json:"trace_id"`
|
||||
}
|
||||
err = util.DecodeWithError(response, &res, "MediaCheckAsync")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
traceID = res.TraceID
|
||||
return
|
||||
return res.TraceID, err
|
||||
}
|
||||
|
||||
// ImageCheckV1 校验一张图片是否含有违法违规内容(同步)
|
||||
|
||||
@@ -60,11 +60,7 @@ func (shortLink *ShortLink) generate(shortLinkParams ShortLinker) (string, error
|
||||
// 使用通用方法返回错误
|
||||
var res resShortLinker
|
||||
err = util.DecodeWithError(response, &res, "GenerateShortLink")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return res.Link, nil
|
||||
return res.Link, err
|
||||
}
|
||||
|
||||
// GenerateShortLinkPermanent 生成永久 shortLink
|
||||
|
||||
@@ -168,11 +168,7 @@ func (s *Subscribe) Add(ShortID string, kidList []int, sceneDesc string) (templa
|
||||
}
|
||||
var result resSubscribeAdd
|
||||
err = util.DecodeWithError(response, &result, "AddSubscribe")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
templateID = result.TemplateID
|
||||
return
|
||||
return result.TemplateID, err
|
||||
}
|
||||
|
||||
// Delete 删除私有模板
|
||||
|
||||
@@ -65,8 +65,5 @@ func (u *URLLink) Generate(params *ULParams) (string, error) {
|
||||
}
|
||||
var resp ULResult
|
||||
err = util.DecodeWithError(response, &resp, "URLLink.Generate")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return resp.URLLink, nil
|
||||
return resp.URLLink, err
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ type SchemeInfo struct {
|
||||
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.query.html#参数
|
||||
type resQueryScheme struct {
|
||||
// 通用错误
|
||||
*util.CommonError
|
||||
util.CommonError
|
||||
// scheme 配置
|
||||
SchemeInfo SchemeInfo `json:"scheme_info"`
|
||||
// 访问该链接的openid,没有用户访问过则为空字符串
|
||||
@@ -62,9 +62,5 @@ func (u *URLScheme) QueryScheme(querySchemeParams QueryScheme) (schemeInfo Schem
|
||||
// 使用通用方法返回错误
|
||||
var res resQueryScheme
|
||||
err = util.DecodeWithError(response, &res, "QueryScheme")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return res.SchemeInfo, res.VisitOpenid, nil
|
||||
return res.SchemeInfo, res.VisitOpenid, err
|
||||
}
|
||||
|
||||
@@ -78,8 +78,5 @@ func (u *URLScheme) Generate(params *USParams) (string, error) {
|
||||
}
|
||||
var resp USResult
|
||||
err = util.DecodeWithError(response, &resp, "URLScheme.Generate")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return resp.OpenLink, nil
|
||||
return resp.OpenLink, err
|
||||
}
|
||||
|
||||
@@ -44,9 +44,6 @@ func (basic *Basic) Long2ShortURL(longURL string) (shortURL string, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = util.DecodeWithError(responseBytes, resp, long2shortAction); err != nil {
|
||||
return
|
||||
}
|
||||
shortURL = resp.ShortURL
|
||||
return
|
||||
err = util.DecodeWithError(responseBytes, resp, long2shortAction)
|
||||
return resp.ShortURL, err
|
||||
}
|
||||
|
||||
@@ -79,6 +79,10 @@ type sendRequest struct {
|
||||
Mpnews map[string]interface{} `json:"mpnews,omitempty"`
|
||||
// 发送语音
|
||||
Voice map[string]interface{} `json:"voice,omitempty"`
|
||||
// 发送视频
|
||||
Mpvideo map[string]interface{} `json:"mpvideo,omitempty"`
|
||||
// 发送图片-预览使用
|
||||
Image map[string]interface{} `json:"image,omitempty"`
|
||||
// 发送图片
|
||||
Images *Image `json:"images,omitempty"`
|
||||
// 发送卡券
|
||||
@@ -183,7 +187,13 @@ func (broadcast *Broadcast) SendImage(user *User, images *Image) (*Result, error
|
||||
ToUser: nil,
|
||||
MsgType: MsgTypeImage,
|
||||
}
|
||||
req.Images = images
|
||||
if broadcast.preview {
|
||||
req.Image = map[string]interface{}{
|
||||
"media_id": images.MediaIDs[0],
|
||||
}
|
||||
} else {
|
||||
req.Images = images
|
||||
}
|
||||
req, sendURL := broadcast.chooseTagOrOpenID(user, req)
|
||||
url := fmt.Sprintf("%s?access_token=%s", sendURL, ak)
|
||||
data, err := util.PostJSON(url, req)
|
||||
@@ -205,7 +215,7 @@ func (broadcast *Broadcast) SendVideo(user *User, mediaID string, title, descrip
|
||||
ToUser: nil,
|
||||
MsgType: MsgTypeVideo,
|
||||
}
|
||||
req.Voice = map[string]interface{}{
|
||||
req.Mpvideo = map[string]interface{}{
|
||||
"media_id": mediaID,
|
||||
"title": title,
|
||||
"description": description,
|
||||
|
||||
@@ -72,11 +72,7 @@ func (csm *Manager) List() (customerServiceList []*KeFuInfo, err error) {
|
||||
}
|
||||
var res resKeFuList
|
||||
err = util.DecodeWithError(response, &res, "ListCustomerService")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
customerServiceList = res.KfList
|
||||
return
|
||||
return res.KfList, err
|
||||
}
|
||||
|
||||
// KeFuOnlineInfo 客服在线信息
|
||||
@@ -107,11 +103,7 @@ func (csm *Manager) OnlineList() (customerServiceOnlineList []*KeFuOnlineInfo, e
|
||||
}
|
||||
var res resKeFuOnlineList
|
||||
err = util.DecodeWithError(response, &res, "ListOnlineCustomerService")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
customerServiceOnlineList = res.KfOnlineList
|
||||
return
|
||||
return res.KfOnlineList, err
|
||||
}
|
||||
|
||||
// Add 添加客服账号
|
||||
|
||||
@@ -183,9 +183,6 @@ func (cube *DataCube) fetchData(params ParamsPublisher) (response []byte, err er
|
||||
uri := fmt.Sprintf("%s?%s", publisherURL, v.Encode())
|
||||
|
||||
response, err = util.HTTPGet(uri)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -64,11 +64,7 @@ func (draft *Draft) AddDraft(articles []*Article) (mediaID string, err error) {
|
||||
MediaID string `json:"media_id"`
|
||||
}
|
||||
err = util.DecodeWithError(response, &res, "AddDraft")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
mediaID = res.MediaID
|
||||
return
|
||||
return res.MediaID, err
|
||||
}
|
||||
|
||||
// GetDraft 获取草稿
|
||||
@@ -94,12 +90,7 @@ func (draft *Draft) GetDraft(mediaID string) (articles []*Article, err error) {
|
||||
NewsItem []*Article `json:"news_item"`
|
||||
}
|
||||
err = util.DecodeWithError(response, &res, "GetDraft")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
articles = res.NewsItem
|
||||
return
|
||||
return res.NewsItem, err
|
||||
}
|
||||
|
||||
// DeleteDraft 删除草稿
|
||||
@@ -172,12 +163,7 @@ func (draft *Draft) CountDraft() (total uint, err error) {
|
||||
Total uint `json:"total_count"`
|
||||
}
|
||||
err = util.DecodeWithError(response, &res, "CountDraft")
|
||||
if nil != err {
|
||||
return
|
||||
}
|
||||
|
||||
total = res.Total
|
||||
return
|
||||
return res.Total, err
|
||||
}
|
||||
|
||||
// ArticleList 草稿列表
|
||||
|
||||
@@ -73,12 +73,7 @@ func (freePublish *FreePublish) Publish(mediaID string) (publishID int64, err er
|
||||
PublishID int64 `json:"publish_id"`
|
||||
}
|
||||
err = util.DecodeWithError(response, &res, "SubmitFreePublish")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
publishID = res.PublishID
|
||||
return
|
||||
return res.PublishID, err
|
||||
}
|
||||
|
||||
// PublishStatusList 发布任务状态列表
|
||||
@@ -191,12 +186,7 @@ func (freePublish *FreePublish) First(articleID string) (list []Article, err err
|
||||
NewsItem []Article `json:"news_item"`
|
||||
}
|
||||
err = util.DecodeWithError(response, &res, "FirstFreePublish")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
list = res.NewsItem
|
||||
return
|
||||
return res.NewsItem, err
|
||||
}
|
||||
|
||||
// ArticleList 发布列表
|
||||
|
||||
@@ -90,11 +90,7 @@ func (tpl *Subscribe) List() (templateList []*PrivateSubscribeItem, err error) {
|
||||
}
|
||||
var res resPrivateSubscribeList
|
||||
err = util.DecodeWithError(response, &res, "ListSubscribe")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
templateList = res.SubscriptionList
|
||||
return
|
||||
return res.SubscriptionList, err
|
||||
}
|
||||
|
||||
type resSubscribeAdd struct {
|
||||
@@ -123,11 +119,7 @@ func (tpl *Subscribe) Add(ShortID string, kidList []int, sceneDesc string) (temp
|
||||
}
|
||||
var result resSubscribeAdd
|
||||
err = util.DecodeWithError(response, &result, "AddSubscribe")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
templateID = result.TemplateID
|
||||
return
|
||||
return result.TemplateID, err
|
||||
}
|
||||
|
||||
// Delete 删除私有模板
|
||||
@@ -175,11 +167,7 @@ func (tpl *Subscribe) GetCategory() (categoryList []*PublicTemplateCategory, err
|
||||
}
|
||||
var result resSubscribeCategoryList
|
||||
err = util.DecodeWithError(response, &result, "GetCategory")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
categoryList = result.CategoryList
|
||||
return
|
||||
return result.CategoryList, err
|
||||
}
|
||||
|
||||
// PublicTemplateKeyWords 模板中的关键词
|
||||
@@ -210,11 +198,7 @@ func (tpl *Subscribe) GetPubTplKeyWordsByID(titleID string) (keyWordsList []*Pub
|
||||
}
|
||||
var result resPublicTemplateKeyWordsList
|
||||
err = util.DecodeWithError(response, &result, "GetPublicTemplateKeyWords")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
keyWordsList = result.KeyWordsList
|
||||
return
|
||||
return result.KeyWordsList, err
|
||||
}
|
||||
|
||||
// PublicTemplateTitle 类目下的公共模板
|
||||
@@ -246,10 +230,5 @@ func (tpl *Subscribe) GetPublicTemplateTitleList(ids string, start int, limit in
|
||||
}
|
||||
var result resPublicTemplateTitleList
|
||||
err = util.DecodeWithError(response, &result, "GetPublicTemplateTitle")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
count = result.Count
|
||||
templateTitleList = result.TemplateTitleList
|
||||
return
|
||||
return result.Count, result.TemplateTitleList, err
|
||||
}
|
||||
|
||||
@@ -111,11 +111,7 @@ func (tpl *Template) List() (templateList []*TemplateItem, err error) {
|
||||
}
|
||||
var res resTemplateList
|
||||
err = util.DecodeWithError(response, &res, "ListTemplate")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
templateList = res.TemplateList
|
||||
return
|
||||
return res.TemplateList, err
|
||||
}
|
||||
|
||||
type resTemplateAdd struct {
|
||||
@@ -143,11 +139,7 @@ func (tpl *Template) Add(shortID string) (templateID string, err error) {
|
||||
|
||||
var result resTemplateAdd
|
||||
err = util.DecodeWithError(response, &result, "AddTemplate")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
templateID = result.TemplateID
|
||||
return
|
||||
return result.TemplateID, err
|
||||
}
|
||||
|
||||
// Delete 删除私有模板.
|
||||
|
||||
@@ -62,10 +62,6 @@ func (user *User) ListChangeOpenIDs(fromAppID string, openIDs ...string) (list *
|
||||
}
|
||||
|
||||
err = util.DecodeWithError(resp, list, "ListChangeOpenIDs")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -126,10 +126,7 @@ func (user *User) GetTag() (tags []*TagInfo, err error) {
|
||||
Tags []*TagInfo `json:"tags"`
|
||||
}
|
||||
err = json.Unmarshal(response, &result)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return result.Tags, nil
|
||||
return result.Tags, err
|
||||
}
|
||||
|
||||
// OpenIDListByTag 获取标签下粉丝列表
|
||||
@@ -154,9 +151,6 @@ func (user *User) OpenIDListByTag(tagID int32, nextOpenID ...string) (userList *
|
||||
}
|
||||
userList = new(TagOpenIDList)
|
||||
err = json.Unmarshal(response, &userList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -100,11 +100,8 @@ func (ctx *Context) GetPreCodeContext(stdCtx context.Context) (string, error) {
|
||||
var ret struct {
|
||||
PreCode string `json:"pre_auth_code"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &ret); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ret.PreCode, nil
|
||||
err = json.Unmarshal(body, &ret)
|
||||
return ret.PreCode, err
|
||||
}
|
||||
|
||||
// GetPreCode 获取预授权码
|
||||
|
||||
@@ -9,6 +9,12 @@ import (
|
||||
|
||||
const (
|
||||
getAccountBasicInfoURL = "https://api.weixin.qq.com/cgi-bin/account/getaccountbasicinfo"
|
||||
checkNickNameURL = "https://api.weixin.qq.com/cgi-bin/wxverify/checkwxverifynickname"
|
||||
setNickNameURL = "https://api.weixin.qq.com/wxa/setnickname"
|
||||
setSignatureURL = "https://api.weixin.qq.com/cgi-bin/account/modifysignature"
|
||||
setHeadImageURL = "https://api.weixin.qq.com/cgi-bin/account/modifyheadimage"
|
||||
getSearchStatusURL = "https://api.weixin.qq.com/wxa/getwxasearchstatus"
|
||||
setSearchStatusURL = "https://api.weixin.qq.com/wxa/changewxasearchstatus"
|
||||
)
|
||||
|
||||
// Basic 基础信息设置
|
||||
@@ -51,3 +57,181 @@ func (basic *Basic) GetAccountBasicInfo() (*AccountBasicInfo, error) {
|
||||
// TODO
|
||||
// func (encryptor *Basic) modifyDomain() {
|
||||
// }
|
||||
|
||||
// CheckNickNameResp 小程序名称检测结果
|
||||
type CheckNickNameResp struct {
|
||||
util.CommonError
|
||||
HitCondition bool `json:"hit_condition"` // 是否命中关键字策略。若命中,可以选填关键字材料
|
||||
Wording string `json:"wording"` // 命中关键字的说明描述
|
||||
}
|
||||
|
||||
// CheckNickName 检测微信认证的名称是否符合规则
|
||||
// ref: https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/basic-info-management/checkNickName.html
|
||||
func (basic *Basic) CheckNickName(nickname string) (*CheckNickNameResp, error) {
|
||||
ak, err := basic.GetAuthrAccessToken(basic.AppID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
url := fmt.Sprintf("%s?access_token=%s", checkNickNameURL, ak)
|
||||
data, err := util.PostJSON(url, map[string]string{
|
||||
"nick_name": nickname,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := &CheckNickNameResp{}
|
||||
err = util.DecodeWithError(data, res, "CheckNickName")
|
||||
return res, err
|
||||
}
|
||||
|
||||
// SetNickNameResp 设置小程序名称结果
|
||||
type SetNickNameResp struct {
|
||||
util.CommonError
|
||||
AuditID int64 `json:"audit_id"` // 审核单Id,通过用于查询改名审核状态
|
||||
Wording string `json:"wording"` // 材料说明
|
||||
}
|
||||
|
||||
// SetNickNameParam 设置小程序名称参数
|
||||
type SetNickNameParam struct {
|
||||
NickName string `json:"nick_name"` // 昵称,不支持包含“小程序”关键字的昵称
|
||||
IDCard string `json:"id_card,omitempty"` // 身份证照片 mediaid,个人号必填
|
||||
License string `json:"license,omitempty"` // 组织机构代码证或营业执照 mediaid,组织号必填
|
||||
NameingOtherStuff1 string `json:"naming_other_stuff_1,omitempty"` // 其他证明材料 mediaid,选填
|
||||
NameingOtherStuff2 string `json:"naming_other_stuff_2,omitempty"` // 其他证明材料 mediaid,选填
|
||||
NameingOtherStuff3 string `json:"naming_other_stuff_3,omitempty"` // 其他证明材料 mediaid,选填
|
||||
NameingOtherStuff4 string `json:"naming_other_stuff_4,omitempty"` // 其他证明材料 mediaid,选填
|
||||
NameingOtherStuff5 string `json:"naming_other_stuff_5,omitempty"` // 其他证明材料 mediaid,选填
|
||||
}
|
||||
|
||||
// SetNickName 设置小程序名称
|
||||
func (basic *Basic) SetNickName(nickname string) (*SetNickNameResp, error) {
|
||||
return basic.SetNickNameFull(&SetNickNameParam{
|
||||
NickName: nickname,
|
||||
})
|
||||
}
|
||||
|
||||
// SetNickNameFull 设置小程序名称
|
||||
// ref: https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/basic-info-management/setNickName.html
|
||||
func (basic *Basic) SetNickNameFull(param *SetNickNameParam) (*SetNickNameResp, error) {
|
||||
ak, err := basic.GetAuthrAccessToken(basic.AppID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
url := fmt.Sprintf("%s?access_token=%s", setNickNameURL, ak)
|
||||
data, err := util.PostJSON(url, param)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := &SetNickNameResp{}
|
||||
err = util.DecodeWithError(data, res, "SetNickName")
|
||||
return res, err
|
||||
}
|
||||
|
||||
// SetSignatureResp 小程序功能介绍修改结果
|
||||
type SetSignatureResp struct {
|
||||
util.CommonError
|
||||
}
|
||||
|
||||
// SetSignature 小程序修改功能介绍
|
||||
// ref: https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/basic-info-management/setSignature.html
|
||||
func (basic *Basic) SetSignature(signature string) error {
|
||||
ak, err := basic.GetAuthrAccessToken(basic.AppID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
url := fmt.Sprintf("%s?access_token=%s", setSignatureURL, ak)
|
||||
data, err := util.PostJSON(url, map[string]string{
|
||||
"signature": signature,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return util.DecodeWithError(data, &SetSignatureResp{}, "SetSignature")
|
||||
}
|
||||
|
||||
// GetSearchStatusResp 查询小程序当前是否可被搜索
|
||||
type GetSearchStatusResp struct {
|
||||
util.CommonError
|
||||
Status int `json:"status"` // 1 表示不可搜索,0 表示可搜索
|
||||
}
|
||||
|
||||
// GetSearchStatus 查询小程序当前是否可被搜索
|
||||
// ref: https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/basic-info-management/getSearchStatus.html
|
||||
func (basic *Basic) GetSearchStatus(signature string) (*GetSearchStatusResp, error) {
|
||||
ak, err := basic.GetAuthrAccessToken(basic.AppID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
url := fmt.Sprintf("%s?access_token=%s", getSearchStatusURL, ak)
|
||||
data, err := util.HTTPGet(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := &GetSearchStatusResp{}
|
||||
err = util.DecodeWithError(data, res, "GetSearchStatus")
|
||||
return res, err
|
||||
}
|
||||
|
||||
// SetSearchStatusResp 小程序是否可被搜索修改结果
|
||||
type SetSearchStatusResp struct {
|
||||
util.CommonError
|
||||
}
|
||||
|
||||
// SetSearchStatus 修改小程序是否可被搜索
|
||||
// status: 1 表示不可搜索,0 表示可搜索
|
||||
// ref: https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/basic-info-management/setSearchStatus.html
|
||||
func (basic *Basic) SetSearchStatus(status int) error {
|
||||
ak, err := basic.GetAuthrAccessToken(basic.AppID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
url := fmt.Sprintf("%s?access_token=%s", setSearchStatusURL, ak)
|
||||
data, err := util.PostJSON(url, map[string]int{
|
||||
"status": status,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return util.DecodeWithError(data, &SetSearchStatusResp{}, "SetSearchStatus")
|
||||
}
|
||||
|
||||
// SetHeadImageResp 小程序头像修改结果
|
||||
type SetHeadImageResp struct {
|
||||
util.CommonError
|
||||
}
|
||||
|
||||
// SetHeadImageParam 小程序头像修改参数
|
||||
type SetHeadImageParam struct {
|
||||
HeadImageMediaID string `json:"head_img_media_id"` // 头像素材 media_id
|
||||
X1 string `json:"x1"` // 裁剪框左上角 x 坐标(取值范围:[0, 1])
|
||||
Y1 string `json:"y1"` // 裁剪框左上角 y 坐标(取值范围:[0, 1])
|
||||
X2 string `json:"x2"` // 裁剪框右下角 x 坐标(取值范围:[0, 1])
|
||||
Y2 string `json:"y2"` // 裁剪框右下角 y 坐标(取值范围:[0, 1])
|
||||
}
|
||||
|
||||
// SetHeadImage 修改小程序头像
|
||||
func (basic *Basic) SetHeadImage(imgMediaID string) error {
|
||||
return basic.SetHeadImageFull(&SetHeadImageParam{
|
||||
HeadImageMediaID: imgMediaID,
|
||||
X1: "0",
|
||||
Y1: "0",
|
||||
X2: "1",
|
||||
Y2: "1",
|
||||
})
|
||||
}
|
||||
|
||||
// SetHeadImageFull 修改小程序头像
|
||||
// 新增临时素材: https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/New_temporary_materials.html
|
||||
// ref: https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/basic-info-management/setHeadImage.html
|
||||
func (basic *Basic) SetHeadImageFull(param *SetHeadImageParam) error {
|
||||
ak, err := basic.GetAuthrAccessToken(basic.AppID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
url := fmt.Sprintf("%s?access_token=%s", setHeadImageURL, ak)
|
||||
data, err := util.PostJSON(url, param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return util.DecodeWithError(data, &SetHeadImageResp{}, "account/setheadimage")
|
||||
}
|
||||
|
||||
24
util/http.go
24
util/http.go
@@ -22,6 +22,9 @@ type URIModifier func(uri string) string
|
||||
|
||||
var uriModifier URIModifier
|
||||
|
||||
// DefaultHTTPClient 默认httpClient
|
||||
var DefaultHTTPClient = http.DefaultClient
|
||||
|
||||
// SetURIModifier 设置URI修改器
|
||||
func SetURIModifier(fn URIModifier) {
|
||||
uriModifier = fn
|
||||
@@ -41,7 +44,7 @@ func HTTPGetContext(ctx context.Context, uri string) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := http.DefaultClient.Do(request)
|
||||
response, err := DefaultHTTPClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -73,7 +76,7 @@ func HTTPPostContext(ctx context.Context, uri string, data []byte, header map[st
|
||||
request.Header.Set(key, value)
|
||||
}
|
||||
|
||||
response, err := http.DefaultClient.Do(request)
|
||||
response, err := DefaultHTTPClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -102,7 +105,7 @@ func PostJSONContext(ctx context.Context, uri string, obj interface{}) ([]byte,
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json;charset=utf-8")
|
||||
response, err := http.DefaultClient.Do(req)
|
||||
response, err := DefaultHTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -129,7 +132,7 @@ func PostJSONWithRespContentType(uri string, obj interface{}) ([]byte, string, e
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
response, err := http.Post(uri, "application/json;charset=utf-8", jsonBuf)
|
||||
response, err := DefaultHTTPClient.Post(uri, "application/json;charset=utf-8", jsonBuf)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -205,7 +208,7 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte
|
||||
contentType := bodyWriter.FormDataContentType()
|
||||
bodyWriter.Close()
|
||||
|
||||
resp, e := http.Post(uri, contentType, bodyBuf)
|
||||
resp, e := DefaultHTTPClient.Post(uri, contentType, bodyBuf)
|
||||
if e != nil {
|
||||
err = e
|
||||
return
|
||||
@@ -229,7 +232,7 @@ func PostXML(uri string, obj interface{}) ([]byte, error) {
|
||||
}
|
||||
|
||||
body := bytes.NewBuffer(xmlData)
|
||||
response, err := http.Post(uri, "application/xml;charset=utf-8", body)
|
||||
response, err := DefaultHTTPClient.Post(uri, "application/xml;charset=utf-8", body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -252,11 +255,10 @@ func httpWithTLS(rootCa, key string) (*http.Client, error) {
|
||||
config := &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: config,
|
||||
DisableCompression: true,
|
||||
}
|
||||
client = &http.Client{Transport: tr}
|
||||
trans := (DefaultHTTPClient.Transport.(*http.Transport)).Clone()
|
||||
trans.TLSClientConfig = config
|
||||
trans.DisableCompression = true
|
||||
client = &http.Client{Transport: trans}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
openConfig "github.com/silenceper/wechat/v2/openplatform/config"
|
||||
"github.com/silenceper/wechat/v2/pay"
|
||||
payConfig "github.com/silenceper/wechat/v2/pay/config"
|
||||
"github.com/silenceper/wechat/v2/util"
|
||||
"github.com/silenceper/wechat/v2/work"
|
||||
workConfig "github.com/silenceper/wechat/v2/work/config"
|
||||
)
|
||||
@@ -81,3 +83,8 @@ func (wc *Wechat) GetWork(cfg *workConfig.Config) *work.Work {
|
||||
}
|
||||
return work.NewWork(cfg)
|
||||
}
|
||||
|
||||
// SetHTTPClient 设置HTTPClient
|
||||
func (wc *Wechat) SetHTTPClient(client *http.Client) {
|
||||
util.DefaultHTTPClient = client
|
||||
}
|
||||
|
||||
387
work/checkin/checkin.go
Normal file
387
work/checkin/checkin.go
Normal file
@@ -0,0 +1,387 @@
|
||||
package checkin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/silenceper/wechat/v2/util"
|
||||
)
|
||||
|
||||
const (
|
||||
// setScheduleListURL 为打卡人员排班
|
||||
setScheduleListURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/setcheckinschedulist?access_token=%s"
|
||||
// punchCorrectionURL 为打卡人员补卡
|
||||
punchCorrectionURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/punch_correction?access_token=%s"
|
||||
// addUserFaceURL 录入打卡人员人脸信息
|
||||
addUserFaceURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/addcheckinuserface?access_token=%s"
|
||||
// addOptionURL 创建打卡规则
|
||||
addOptionURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/add_checkin_option?access_token=%s"
|
||||
// updateOptionURL 修改打卡规则
|
||||
updateOptionURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/update_checkin_option?access_token=%s"
|
||||
// clearOptionURL 清空打卡规则数组元素
|
||||
clearOptionURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/clear_checkin_option_array_field?access_token=%s"
|
||||
// delOptionURL 删除打卡规则
|
||||
delOptionURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/del_checkin_option?access_token=%s"
|
||||
)
|
||||
|
||||
// SetScheduleListRequest 为打卡人员排班请求
|
||||
type SetScheduleListRequest struct {
|
||||
GroupID int64 `json:"groupid"`
|
||||
Items []SetScheduleListItem `json:"items"`
|
||||
YearMonth int64 `json:"yearmonth"`
|
||||
}
|
||||
|
||||
// SetScheduleListItem 排班表信息
|
||||
type SetScheduleListItem struct {
|
||||
UserID string `json:"userid"`
|
||||
Day int64 `json:"day"`
|
||||
ScheduleID int64 `json:"schedule_id"`
|
||||
}
|
||||
|
||||
// SetScheduleList 为打卡人员排班
|
||||
// see https://developer.work.weixin.qq.com/document/path/93385
|
||||
func (r *Client) SetScheduleList(req *SetScheduleListRequest) error {
|
||||
var (
|
||||
accessToken string
|
||||
err error
|
||||
)
|
||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||
return err
|
||||
}
|
||||
var response []byte
|
||||
if response, err = util.PostJSON(fmt.Sprintf(setScheduleListURL, accessToken), req); err != nil {
|
||||
return err
|
||||
}
|
||||
return util.DecodeWithCommonError(response, "SetScheduleList")
|
||||
}
|
||||
|
||||
// PunchCorrectionRequest 为打卡人员补卡请求
|
||||
type PunchCorrectionRequest struct {
|
||||
UserID string `json:"userid"`
|
||||
ScheduleDateTime int64 `json:"schedule_date_time"`
|
||||
ScheduleCheckinTime int64 `json:"schedule_checkin_time"`
|
||||
CheckinTime int64 `json:"checkin_time"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
// PunchCorrection 为打卡人员补卡
|
||||
// see https://developer.work.weixin.qq.com/document/path/95803
|
||||
func (r *Client) PunchCorrection(req *PunchCorrectionRequest) error {
|
||||
var (
|
||||
accessToken string
|
||||
err error
|
||||
)
|
||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||
return err
|
||||
}
|
||||
var response []byte
|
||||
if response, err = util.PostJSON(fmt.Sprintf(punchCorrectionURL, accessToken), req); err != nil {
|
||||
return err
|
||||
}
|
||||
return util.DecodeWithCommonError(response, "PunchCorrection")
|
||||
}
|
||||
|
||||
// AddUserFaceRequest 录入打卡人员人脸信息请求
|
||||
type AddUserFaceRequest struct {
|
||||
UserID string `json:"userid"`
|
||||
UserFace string `json:"userface"`
|
||||
}
|
||||
|
||||
// AddUserFace 录入打卡人员人脸信息
|
||||
// see https://developer.work.weixin.qq.com/document/path/93378
|
||||
func (r *Client) AddUserFace(req *AddUserFaceRequest) error {
|
||||
var (
|
||||
accessToken string
|
||||
err error
|
||||
)
|
||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||
return err
|
||||
}
|
||||
var response []byte
|
||||
if response, err = util.PostJSON(fmt.Sprintf(addUserFaceURL, accessToken), req); err != nil {
|
||||
return err
|
||||
}
|
||||
return util.DecodeWithCommonError(response, "AddUserFace")
|
||||
}
|
||||
|
||||
// AddOptionRequest 创建打卡规则请求
|
||||
type AddOptionRequest struct {
|
||||
EffectiveNow bool `json:"effective_now,omitempty"`
|
||||
Group OptionGroupRule `json:"group,omitempty"`
|
||||
}
|
||||
|
||||
// OptionGroupRule 打卡规则字段
|
||||
type OptionGroupRule struct {
|
||||
GroupID int64 `json:"groupid,omitempty"`
|
||||
GroupType int64 `json:"grouptype"`
|
||||
GroupName string `json:"groupname"`
|
||||
CheckinDate []OptionGroupRuleCheckinDate `json:"checkindate,omitempty"`
|
||||
SpeWorkdays []OptionGroupSpeWorkdays `json:"spe_workdays,omitempty"`
|
||||
SpeOffDays []OptionGroupSpeOffDays `json:"spe_offdays,omitempty"`
|
||||
SyncHolidays bool `json:"sync_holidays,omitempty"`
|
||||
NeedPhoto bool `json:"need_photo,omitempty"`
|
||||
NoteCanUseLocalPic bool `json:"note_can_use_local_pic,omitempty"`
|
||||
WifiMacInfos []OptionGroupWifiMacInfos `json:"wifimac_infos,omitempty"`
|
||||
LocInfos []OptionGroupLocInfos `json:"loc_infos,omitempty"`
|
||||
AllowCheckinOffWorkday bool `json:"allow_checkin_offworkday,omitempty"`
|
||||
AllowApplyOffWorkday bool `json:"allow_apply_offworkday,omitempty"`
|
||||
Range []OptionGroupRange `json:"range"`
|
||||
WhiteUsers []string `json:"white_users,omitempty"`
|
||||
Type int64 `json:"type,omitempty"`
|
||||
ReporterInfo OptionGroupReporterInfo `json:"reporterinfo,omitempty"`
|
||||
AllowApplyBkCnt int64 `json:"allow_apply_bk_cnt,omitempty"`
|
||||
AllowApplyBkDayLimit int64 `json:"allow_apply_bk_day_limit,omitempty"`
|
||||
BukaLimitNextMonth int64 `json:"buka_limit_next_month,omitempty"`
|
||||
OptionOutRange int64 `json:"option_out_range,omitempty"`
|
||||
ScheduleList []OptionGroupScheduleList `json:"schedulelist,omitempty"`
|
||||
OffWorkIntervalTime int64 `json:"offwork_interval_time,omitempty"`
|
||||
UseFaceDetect bool `json:"use_face_detect,omitempty"`
|
||||
OpenFaceLiveDetect bool `json:"open_face_live_detect,omitempty"`
|
||||
OtInfoV2 OptionGroupOtInfoV2 `json:"ot_info_v2,omitempty"`
|
||||
SyncOutCheckin bool `json:"sync_out_checkin,omitempty"`
|
||||
BukaRemind OptionGroupBukaRemind `json:"buka_remind,omitempty"`
|
||||
BukaRestriction int64 `json:"buka_restriction,omitempty"`
|
||||
SpanDayTime int64 `json:"span_day_time,omitempty"`
|
||||
StandardWorkDuration int64 `json:"standard_work_duration,omitempty"`
|
||||
}
|
||||
|
||||
// OptionGroupRuleCheckinDate 固定时间上下班打卡时间
|
||||
type OptionGroupRuleCheckinDate struct {
|
||||
Workdays []int64 `json:"workdays"`
|
||||
CheckinTime []OptionGroupRuleCheckinTime `json:"checkintime"`
|
||||
FlexTime int64 `json:"flex_time"`
|
||||
AllowFlex bool `json:"allow_flex"`
|
||||
FlexOnDutyTime int64 `json:"flex_on_duty_time"`
|
||||
FlexOffDutyTime int64 `json:"flex_off_duty_time"`
|
||||
MaxAllowArriveEarly int64 `json:"max_allow_arrive_early"`
|
||||
MaxAllowArriveLate int64 `json:"max_allow_arrive_late"`
|
||||
LateRule OptionGroupLateRule `json:"late_rule"`
|
||||
}
|
||||
|
||||
// OptionGroupRuleCheckinTime 工作日上下班打卡时间信息
|
||||
type OptionGroupRuleCheckinTime struct {
|
||||
TimeID int64 `json:"time_id"`
|
||||
WorkSec int64 `json:"work_sec"`
|
||||
OffWorkSec int64 `json:"off_work_sec"`
|
||||
RemindWorkSec int64 `json:"remind_work_sec"`
|
||||
RemindOffWorkSec int64 `json:"remind_off_work_sec"`
|
||||
AllowRest bool `json:"allow_rest"`
|
||||
RestBeginTime int64 `json:"rest_begin_time"`
|
||||
RestEndTime int64 `json:"rest_end_time"`
|
||||
EarliestWorkSec int64 `json:"earliest_work_sec"`
|
||||
LatestWorkSec int64 `json:"latest_work_sec"`
|
||||
EarliestOffWorkSec int64 `json:"earliest_off_work_sec"`
|
||||
LatestOffWorkSec int64 `json:"latest_off_work_sec"`
|
||||
NoNeedCheckOn bool `json:"no_need_checkon"`
|
||||
NoNeedCheckOff bool `json:"no_need_checkoff"`
|
||||
}
|
||||
|
||||
// OptionGroupLateRule 晚走晚到时间规则信息
|
||||
type OptionGroupLateRule struct {
|
||||
OffWorkAfterTime int64 `json:"offwork_after_time"`
|
||||
OnWorkFlexTime int64 `json:"onwork_flex_time"`
|
||||
AllowOffWorkAfterTime int64 `json:"allow_offwork_after_time"`
|
||||
TimeRules []OptionGroupTimeRule `json:"timerules"`
|
||||
}
|
||||
|
||||
// OptionGroupTimeRule 晚走晚到时间规则
|
||||
type OptionGroupTimeRule struct {
|
||||
OffWorkAfterTime int64 `json:"offwork_after_time"`
|
||||
OnWorkFlexTime int64 `json:"onwork_flex_time"`
|
||||
}
|
||||
|
||||
// OptionGroupSpeWorkdays 特殊工作日
|
||||
type OptionGroupSpeWorkdays struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Notes string `json:"notes"`
|
||||
CheckinTime []OptionGroupCheckinTime `json:"checkintime"`
|
||||
Type int64 `json:"type"`
|
||||
BegTime int64 `json:"begtime"`
|
||||
EndTime int64 `json:"endtime"`
|
||||
}
|
||||
|
||||
// OptionGroupCheckinTime 特殊工作日的上下班打卡时间配置
|
||||
type OptionGroupCheckinTime struct {
|
||||
TimeID int64 `json:"time_id"`
|
||||
WorkSec int64 `json:"work_sec"`
|
||||
OffWorkSec int64 `json:"off_work_sec"`
|
||||
RemindWorkSec int64 `json:"remind_work_sec"`
|
||||
RemindOffWorkSec int64 `json:"remind_off_work_sec"`
|
||||
}
|
||||
|
||||
// OptionGroupSpeOffDays 特殊非工作日
|
||||
type OptionGroupSpeOffDays struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Notes string `json:"notes"`
|
||||
Type int64 `json:"type"`
|
||||
BegTime int64 `json:"begtime"`
|
||||
EndTime int64 `json:"endtime"`
|
||||
}
|
||||
|
||||
// OptionGroupWifiMacInfos WIFI信息
|
||||
type OptionGroupWifiMacInfos struct {
|
||||
WifiName string `json:"wifiname"`
|
||||
WifiMac string `json:"wifimac"`
|
||||
}
|
||||
|
||||
// OptionGroupLocInfos 地点信息
|
||||
type OptionGroupLocInfos struct {
|
||||
Lat int64 `json:"lat"`
|
||||
Lng int64 `json:"lng"`
|
||||
LocTitle string `json:"loc_title"`
|
||||
LocDetail string `json:"loc_detail"`
|
||||
Distance int64 `json:"distance"`
|
||||
}
|
||||
|
||||
// OptionGroupRange 人员信息
|
||||
type OptionGroupRange struct {
|
||||
PartyID []string `json:"party_id"`
|
||||
UserID []string `json:"userid"`
|
||||
TagID []int64 `json:"tagid"`
|
||||
}
|
||||
|
||||
// OptionGroupReporterInfo 汇报人
|
||||
type OptionGroupReporterInfo struct {
|
||||
Reporters []OptionGroupReporters `json:"reporters"`
|
||||
}
|
||||
|
||||
// OptionGroupReporters 汇报对象
|
||||
type OptionGroupReporters struct {
|
||||
UserID string `json:"userid"`
|
||||
TagID int64 `json:"tagid"`
|
||||
}
|
||||
|
||||
// OptionGroupScheduleList 自定义排班规则所有排班
|
||||
type OptionGroupScheduleList struct {
|
||||
ScheduleID int64 `json:"schedule_id"`
|
||||
ScheduleName string `json:"schedule_name"`
|
||||
TimeSection []OptionGroupTimeSection `json:"time_section"`
|
||||
AllowFlex bool `json:"allow_flex"`
|
||||
FlexOnDutyTime int64 `json:"flex_on_duty_time"`
|
||||
FlexOffDutyTime int64 `json:"flex_off_duty_time"`
|
||||
LateRule OptionGroupLateRule `json:"late_rule"`
|
||||
MaxAllowArriveEarly int64 `json:"max_allow_arrive_early"`
|
||||
MaxAllowArriveLate int64 `json:"max_allow_arrive_late"`
|
||||
}
|
||||
|
||||
// OptionGroupTimeSection 班次上下班时段信息
|
||||
type OptionGroupTimeSection struct {
|
||||
TimeID int64 `json:"time_id"`
|
||||
WorkSec int64 `json:"work_sec"`
|
||||
OffWorkSec int64 `json:"off_work_sec"`
|
||||
RemindWorkSec int64 `json:"remind_work_sec"`
|
||||
RemindOffWorkSec int64 `json:"remind_off_work_sec"`
|
||||
RestBeginTime int64 `json:"rest_begin_time"`
|
||||
RestEndTime int64 `json:"rest_end_time"`
|
||||
AllowRest bool `json:"allow_rest"`
|
||||
EarliestWorkSec int64 `json:"earliest_work_sec"`
|
||||
LatestWorkSec int64 `json:"latest_work_sec"`
|
||||
EarliestOffWorkSec int64 `json:"earliest_off_work_sec"`
|
||||
LatestOffWorkSec int64 `json:"latest_off_work_sec"`
|
||||
NoNeedCheckOn bool `json:"no_need_checkon"`
|
||||
NoNeedCheckOff bool `json:"no_need_checkoff"`
|
||||
}
|
||||
|
||||
// OptionGroupOtInfoV2 加班配置
|
||||
type OptionGroupOtInfoV2 struct {
|
||||
WorkdayConf OptionGroupWorkdayConf `json:"workdayconf"`
|
||||
}
|
||||
|
||||
// OptionGroupWorkdayConf 工作日加班配置
|
||||
type OptionGroupWorkdayConf struct {
|
||||
AllowOt bool `json:"allow_ot"`
|
||||
Type int64 `json:"type"`
|
||||
}
|
||||
|
||||
// OptionGroupBukaRemind 补卡提醒
|
||||
type OptionGroupBukaRemind struct {
|
||||
OpenRemind bool `json:"open_remind"`
|
||||
BukaRemindDay int64 `json:"buka_remind_day"`
|
||||
BukaRemindMonth int64 `json:"buka_remind_month"`
|
||||
}
|
||||
|
||||
// AddOption 创建打卡规则
|
||||
// see https://developer.work.weixin.qq.com/document/path/98041#%E5%88%9B%E5%BB%BA%E6%89%93%E5%8D%A1%E8%A7%84%E5%88%99
|
||||
func (r *Client) AddOption(req *AddOptionRequest) error {
|
||||
var (
|
||||
accessToken string
|
||||
err error
|
||||
)
|
||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||
return err
|
||||
}
|
||||
var response []byte
|
||||
if response, err = util.PostJSON(fmt.Sprintf(addOptionURL, accessToken), req); err != nil {
|
||||
return err
|
||||
}
|
||||
return util.DecodeWithCommonError(response, "AddOption")
|
||||
}
|
||||
|
||||
// UpdateOptionRequest 修改打卡规则请求
|
||||
type UpdateOptionRequest struct {
|
||||
EffectiveNow bool `json:"effective_now,omitempty"`
|
||||
Group OptionGroupRule `json:"group,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateOption 修改打卡规则
|
||||
// see https://developer.work.weixin.qq.com/document/path/98041#%E4%BF%AE%E6%94%B9%E6%89%93%E5%8D%A1%E8%A7%84%E5%88%99
|
||||
func (r *Client) UpdateOption(req *UpdateOptionRequest) error {
|
||||
var (
|
||||
accessToken string
|
||||
err error
|
||||
)
|
||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||
return err
|
||||
}
|
||||
var response []byte
|
||||
if response, err = util.PostJSON(fmt.Sprintf(updateOptionURL, accessToken), req); err != nil {
|
||||
return err
|
||||
}
|
||||
return util.DecodeWithCommonError(response, "UpdateOption")
|
||||
}
|
||||
|
||||
// ClearOptionRequest 清空打卡规则数组元素请求
|
||||
type ClearOptionRequest struct {
|
||||
GroupID int64 `json:"groupid"`
|
||||
ClearField []int64 `json:"clear_field"`
|
||||
EffectiveNow bool `json:"effective_now"`
|
||||
}
|
||||
|
||||
// ClearOption 清空打卡规则数组元素
|
||||
// see https://developer.work.weixin.qq.com/document/path/98041#%E6%B8%85%E7%A9%BA%E6%89%93%E5%8D%A1%E8%A7%84%E5%88%99%E6%95%B0%E7%BB%84%E5%85%83%E7%B4%A0
|
||||
func (r *Client) ClearOption(req *ClearOptionRequest) error {
|
||||
var (
|
||||
accessToken string
|
||||
err error
|
||||
)
|
||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||
return err
|
||||
}
|
||||
var response []byte
|
||||
if response, err = util.PostJSON(fmt.Sprintf(clearOptionURL, accessToken), req); err != nil {
|
||||
return err
|
||||
}
|
||||
return util.DecodeWithCommonError(response, "ClearOption")
|
||||
}
|
||||
|
||||
// DelOptionRequest 删除打卡规则请求
|
||||
type DelOptionRequest struct {
|
||||
GroupID int64 `json:"groupid"`
|
||||
EffectiveNow bool `json:"effective_now"`
|
||||
}
|
||||
|
||||
// DelOption 删除打卡规则
|
||||
// see https://developer.work.weixin.qq.com/document/path/98041#%E5%88%A0%E9%99%A4%E6%89%93%E5%8D%A1%E8%A7%84%E5%88%99
|
||||
func (r *Client) DelOption(req *DelOptionRequest) error {
|
||||
var (
|
||||
accessToken string
|
||||
err error
|
||||
)
|
||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||
return err
|
||||
}
|
||||
var response []byte
|
||||
if response, err = util.PostJSON(fmt.Sprintf(delOptionURL, accessToken), req); err != nil {
|
||||
return err
|
||||
}
|
||||
return util.DecodeWithCommonError(response, "DelOption")
|
||||
}
|
||||
@@ -63,16 +63,16 @@ type ExternalUserDetailResponse struct {
|
||||
|
||||
// ExternalUser 外部联系人
|
||||
type ExternalUser struct {
|
||||
ExternalUserID string `json:"external_userid"`
|
||||
Name string `json:"name"`
|
||||
Avatar string `json:"avatar"`
|
||||
Type int64 `json:"type"`
|
||||
Gender int64 `json:"gender"`
|
||||
UnionID string `json:"unionid"`
|
||||
Position string `json:"position"`
|
||||
CorpName string `json:"corp_name"`
|
||||
CorpFullName string `json:"corp_full_name"`
|
||||
ExternalProfile string `json:"external_profile"`
|
||||
ExternalUserID string `json:"external_userid"`
|
||||
Name string `json:"name"`
|
||||
Avatar string `json:"avatar"`
|
||||
Type int64 `json:"type"`
|
||||
Gender int64 `json:"gender"`
|
||||
UnionID string `json:"unionid"`
|
||||
Position string `json:"position"`
|
||||
CorpName string `json:"corp_name"`
|
||||
CorpFullName string `json:"corp_full_name"`
|
||||
ExternalProfile *ExternalProfile `json:"external_profile,omitempty"`
|
||||
}
|
||||
|
||||
// FollowUser 跟进用户(指企业内部用户)
|
||||
@@ -104,6 +104,46 @@ type WechatChannel struct {
|
||||
Source int `json:"source"`
|
||||
}
|
||||
|
||||
// ExternalProfile 外部联系人的自定义展示信息,可以有多个字段和多种类型,包括文本,网页和小程序
|
||||
type ExternalProfile struct {
|
||||
ExternalCorpName string `json:"external_corp_name"`
|
||||
WechatChannels WechatChannels `json:"wechat_channels"`
|
||||
ExternalAttr []ExternalAttr `json:"external_attr"`
|
||||
}
|
||||
|
||||
// WechatChannels 视频号属性。须从企业绑定到企业微信的视频号中选择,可在“我的企业”页中查看绑定的视频号
|
||||
type WechatChannels struct {
|
||||
Nickname string `json:"nickname"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
// ExternalAttr 属性列表,目前支持文本、网页、小程序三种类型
|
||||
type ExternalAttr struct {
|
||||
Type int `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Text *Text `json:"text,omitempty"`
|
||||
Web *Web `json:"web,omitempty"`
|
||||
MiniProgram *MiniProgram `json:"miniprogram,omitempty"`
|
||||
}
|
||||
|
||||
// Text 文本
|
||||
type Text struct {
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// Web 网页
|
||||
type Web struct {
|
||||
URL string `json:"url"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
// MiniProgram 小程序
|
||||
type MiniProgram struct {
|
||||
AppID string `json:"appid"`
|
||||
Pagepath string `json:"pagepath"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
// GetExternalUserDetail 获取外部联系人详情
|
||||
// @see https://developer.work.weixin.qq.com/document/path/92114
|
||||
func (r *Client) GetExternalUserDetail(externalUserID string, nextCursor ...string) (*ExternalUserDetailResponse, error) {
|
||||
|
||||
@@ -76,13 +76,14 @@ type (
|
||||
}
|
||||
//GroupChat 客户群详情
|
||||
GroupChat struct {
|
||||
ChatID string `json:"chat_id"` //客户群ID
|
||||
Name string `json:"name"` //群名
|
||||
Owner string `json:"owner"` //群主ID
|
||||
CreateTime int64 `json:"create_time"` //群的创建时间
|
||||
Notice string `json:"notice"` //群公告
|
||||
MemberList []GroupChatMember `json:"member_list"` //群成员列表
|
||||
AdminList []GroupChatAdmin `json:"admin_list"` //群管理员列表
|
||||
ChatID string `json:"chat_id"` //客户群ID
|
||||
Name string `json:"name"` //群名
|
||||
Owner string `json:"owner"` //群主ID
|
||||
CreateTime int64 `json:"create_time"` //群的创建时间
|
||||
Notice string `json:"notice"` //群公告
|
||||
MemberList []GroupChatMember `json:"member_list"` //群成员列表
|
||||
AdminList []GroupChatAdmin `json:"admin_list"` //群管理员列表
|
||||
MemberVersion string `json:"member_version"` //当前群成员版本号。可以配合客户群变更事件减少主动调用本接口的次数
|
||||
}
|
||||
//GroupChatDetailResponse 客户群详情 返回值
|
||||
GroupChatDetailResponse struct {
|
||||
|
||||
Reference in New Issue
Block a user