mirror of
https://github.com/silenceper/wechat.git
synced 2026-02-23 13:42:25 +08:00
Compare commits
7 Commits
71e348ff08
...
v2.1.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5e674bf10 | ||
|
|
0ffe34187a | ||
|
|
04b62f6c3c | ||
|
|
4adc59b1b0 | ||
|
|
dad7932574 | ||
|
|
56a3734546 | ||
|
|
d4fd145bb5 |
8
.github/workflows/go.yml
vendored
8
.github/workflows/go.yml
vendored
@@ -2,15 +2,15 @@ name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master,release-*,v2 ]
|
||||
branches: [ master,release-*,v2,feature/** ]
|
||||
pull_request:
|
||||
branches: [ master,release-*,v2 ]
|
||||
branches: [ master,release-*,v2,feature/** ]
|
||||
|
||||
jobs:
|
||||
golangci:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ '1.16','1.17','1.18','1.19','1.20' ]
|
||||
go-version: [ '1.16','1.17','1.18','1.19','1.20','1.21' ]
|
||||
name: golangci-lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
# strategy set
|
||||
strategy:
|
||||
matrix:
|
||||
go: [ '1.16','1.17','1.18','1.19','1.20' ]
|
||||
go: [ '1.16','1.17','1.18','1.19','1.20','1.21' ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@@ -66,9 +66,11 @@ func (ak *DefaultAccessToken) GetAccessToken() (accessToken string, err error) {
|
||||
func (ak *DefaultAccessToken) GetAccessTokenContext(ctx context.Context) (accessToken string, err error) {
|
||||
// 先从cache中取
|
||||
accessTokenCacheKey := fmt.Sprintf("%s_access_token_%s", ak.cacheKeyPrefix, ak.appID)
|
||||
val := ak.cache.Get(accessTokenCacheKey)
|
||||
if accessToken = val.(string); accessToken != "" {
|
||||
return
|
||||
|
||||
if val := ak.cache.Get(accessTokenCacheKey); val != nil {
|
||||
if accessToken = val.(string); accessToken != "" {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 加上lock,是为了防止在并发获取token时,cache刚好失效,导致从微信服务器上获取到不同token
|
||||
@@ -76,9 +78,10 @@ func (ak *DefaultAccessToken) GetAccessTokenContext(ctx context.Context) (access
|
||||
defer ak.accessTokenLock.Unlock()
|
||||
|
||||
// 双检,防止重复从微信服务器获取
|
||||
val = ak.cache.Get(accessTokenCacheKey)
|
||||
if accessToken = val.(string); accessToken != "" {
|
||||
return
|
||||
if val := ak.cache.Get(accessTokenCacheKey); val != nil {
|
||||
if accessToken = val.(string); accessToken != "" {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// cache失效,从微信服务器获取
|
||||
|
||||
@@ -90,10 +90,12 @@ host: https://qyapi.weixin.qq.com/
|
||||
| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | 贡献者 |
|
||||
|:---------:|------|:----------------------------------------| ---------- | ------------------------------- |----------|
|
||||
| 获取子部门ID列表 | GET | /cgi-bin/department/simplelist | YES | (r *Client) DepartmentSimpleList| MARKWANG |
|
||||
| 获取部门列表 | GET | /cgi-bin/department/list | YES | (r *Client) DepartmentList| just5325, ourines |
|
||||
| 获取部门成员 | GET | /cgi-bin/user/simplelist | YES | (r *Client) UserSimpleList | MARKWANG |
|
||||
| 获取成员ID列表 | Post | /cgi-bin/user/list_id | YES | (r *Client) UserListId | MARKWANG |
|
||||
|
||||
|
||||
|
||||
## 素材管理
|
||||
[官方文档](https://developer.work.weixin.qq.com/document/path/91054)
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@ package openapi
|
||||
|
||||
import "github.com/silenceper/wechat/v2/util"
|
||||
|
||||
// GetAPIQuotaParams 查询API调用额度参数
|
||||
// GetAPIQuotaParams 查询 API 调用额度参数
|
||||
type GetAPIQuotaParams struct {
|
||||
CgiPath string `json:"cgi_path"` // api的请求地址,例如"/cgi-bin/message/custom/send";不要前缀“https://api.weixin.qq.com” ,也不要漏了"/",否则都会76003的报错
|
||||
CgiPath string `json:"cgi_path"` // api 的请求地址,例如"/cgi-bin/message/custom/send";不要前缀“https://api.weixin.qq.com” ,也不要漏了"/",否则都会 76003 的报错
|
||||
}
|
||||
|
||||
// APIQuota API调用额度
|
||||
// APIQuota API 调用额度
|
||||
type APIQuota struct {
|
||||
util.CommonError
|
||||
Quota struct {
|
||||
@@ -17,20 +17,20 @@ type APIQuota struct {
|
||||
} `json:"quota"` // 详情
|
||||
}
|
||||
|
||||
// GetRidInfoParams 查询rid信息参数
|
||||
// GetRidInfoParams 查询 rid 信息参数
|
||||
type GetRidInfoParams struct {
|
||||
Rid string `json:"rid"` // 调用接口报错返回的rid
|
||||
Rid string `json:"rid"` // 调用接口报错返回的 rid
|
||||
}
|
||||
|
||||
// RidInfo rid信息
|
||||
// RidInfo rid 信息
|
||||
type RidInfo struct {
|
||||
util.CommonError
|
||||
Request struct {
|
||||
InvokeTime int64 `json:"invoke_time"` // 发起请求的时间戳
|
||||
CostInMs int64 `json:"cost_in_ms"` // 请求毫秒级耗时
|
||||
RequestURL string `json:"request_url"` // 请求的URL参数
|
||||
RequestBody string `json:"request_body"` // post请求的请求参数
|
||||
RequestURL string `json:"request_url"` // 请求的 URL 参数
|
||||
RequestBody string `json:"request_body"` // post 请求的请求参数
|
||||
ResponseBody string `json:"response_body"` // 接口请求返回参数
|
||||
ClientIP string `json:"client_ip"` // 接口请求的客户端ip
|
||||
} `json:"request"` // 该rid对应的请求详情
|
||||
ClientIP string `json:"client_ip"` // 接口请求的客户端 ip
|
||||
} `json:"request"` // 该 rid 对应的请求详情
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ const (
|
||||
MsgTypeMiniProgramPage = "miniprogrampage"
|
||||
// MsgTypeEvent 事件
|
||||
MsgTypeEvent MsgType = "event"
|
||||
// DataTypeXML XML格式数据
|
||||
// DataTypeXML XML 格式数据
|
||||
DataTypeXML = "xml"
|
||||
// DataTypeJSON JSON格式数据
|
||||
// DataTypeJSON JSON 格式数据
|
||||
DataTypeJSON = "json"
|
||||
)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ type MediaText struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// MediaResource 消息使用的临时素材id
|
||||
// MediaResource 消息使用的临时素材 id
|
||||
type MediaResource struct {
|
||||
MediaID string `json:"media_id"`
|
||||
}
|
||||
@@ -51,7 +51,7 @@ type MediaLink struct {
|
||||
|
||||
// CustomerMessage 客服消息
|
||||
type CustomerMessage struct {
|
||||
ToUser string `json:"touser"` // 接受者OpenID
|
||||
ToUser string `json:"touser"` // 接受者 OpenID
|
||||
Msgtype MsgType `json:"msgtype"` // 客服消息类型
|
||||
Text *MediaText `json:"text,omitempty"` // 可选
|
||||
Image *MediaResource `json:"image,omitempty"` // 可选
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/silenceper/wechat/v2/miniprogram/context"
|
||||
"github.com/silenceper/wechat/v2/miniprogram/security"
|
||||
"github.com/silenceper/wechat/v2/util"
|
||||
@@ -18,11 +20,11 @@ import (
|
||||
type ConfirmReceiveMethod int8
|
||||
|
||||
const (
|
||||
// EventTypeTradeManageRemindAccessAPI 提醒接入发货信息管理服务API
|
||||
// EventTypeTradeManageRemindAccessAPI 提醒接入发货信息管理服务 API
|
||||
// 小程序完成账期授权时/小程序产生第一笔交易时/已产生交易但从未发货的小程序,每天一次
|
||||
EventTypeTradeManageRemindAccessAPI EventType = "trade_manage_remind_access_api"
|
||||
// EventTypeTradeManageRemindShipping 提醒需要上传发货信息
|
||||
// 曾经发过货的小程序,订单超过48小时未发货时
|
||||
// 曾经发过货的小程序,订单超过 48 小时未发货时
|
||||
EventTypeTradeManageRemindShipping EventType = "trade_manage_remind_shipping"
|
||||
// EventTypeTradeManageOrderSettlement 订单将要结算或已经结算
|
||||
// 订单完成发货时/订单结算时
|
||||
@@ -39,14 +41,27 @@ const (
|
||||
EventTypeXpayGoodsDeliverNotify EventType = "xpay_goods_deliver_notify"
|
||||
// EventTypeXpayCoinPayNotify 代币支付推送事件
|
||||
EventTypeXpayCoinPayNotify EventType = "xpay_coin_pay_notify"
|
||||
// EventSubscribePopup 用户操作订阅通知弹窗事件推送,用户在图文等场景内订阅通知的操作
|
||||
EventSubscribePopup EventType = "subscribe_msg_popup_event"
|
||||
// EventSubscribeMsgChange 用户管理订阅通知,用户在服务通知管理页面做通知管理时的操作
|
||||
EventSubscribeMsgChange EventType = "subscribe_msg_change_event"
|
||||
// EventSubscribeMsgSent 发送订阅通知,调用 bizsend 接口发送通知
|
||||
EventSubscribeMsgSent EventType = "subscribe_msg_sent_event"
|
||||
// ConfirmReceiveMethodAuto 自动确认收货
|
||||
ConfirmReceiveMethodAuto ConfirmReceiveMethod = 1
|
||||
// ConfirmReceiveMethodManual 手动确认收货
|
||||
ConfirmReceiveMethodManual ConfirmReceiveMethod = 2
|
||||
)
|
||||
|
||||
const (
|
||||
// InfoTypeAcceptSubscribeMessage 接受订阅通知
|
||||
InfoTypeAcceptSubscribeMessage InfoType = "accept"
|
||||
// InfoTypeRejectSubscribeMessage 拒绝订阅通知
|
||||
InfoTypeRejectSubscribeMessage InfoType = "reject"
|
||||
)
|
||||
|
||||
// PushReceiver 接收消息推送
|
||||
// 暂仅支付Aes加密方式
|
||||
// 暂仅支付 Aes 加密方式
|
||||
type PushReceiver struct {
|
||||
*context.Context
|
||||
}
|
||||
@@ -58,16 +73,16 @@ func NewPushReceiver(ctx *context.Context) *PushReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
// GetMsg 获取接收到的消息(如果是加密的返回解密数据)
|
||||
// GetMsg 获取接收到的消息 (如果是加密的返回解密数据)
|
||||
func (receiver *PushReceiver) GetMsg(r *http.Request) (string, []byte, error) {
|
||||
// 判断请求格式
|
||||
var dataType string
|
||||
contentType := r.Header.Get("Content-Type")
|
||||
if strings.HasPrefix(contentType, "text/xml") {
|
||||
// xml格式
|
||||
// xml 格式
|
||||
dataType = DataTypeXML
|
||||
} else {
|
||||
// json格式
|
||||
// json 格式
|
||||
dataType = DataTypeJSON
|
||||
}
|
||||
|
||||
@@ -108,7 +123,7 @@ func (receiver *PushReceiver) GetMsg(r *http.Request) (string, []byte, error) {
|
||||
return dataType, byteData, err
|
||||
}
|
||||
|
||||
// GetMsgData 获取接收到的消息(解密数据)
|
||||
// GetMsgData 获取接收到的消息 (解密数据)
|
||||
func (receiver *PushReceiver) GetMsgData(r *http.Request) (MsgType, EventType, PushData, error) {
|
||||
dataType, decryptMsg, err := receiver.GetMsg(r)
|
||||
if err != nil {
|
||||
@@ -144,7 +159,7 @@ func (receiver *PushReceiver) GetMsgData(r *http.Request) (MsgType, EventType, P
|
||||
func (receiver *PushReceiver) getEvent(dataType string, eventType EventType, decryptMsg []byte) (PushData, error) {
|
||||
switch eventType {
|
||||
case EventTypeTradeManageRemindAccessAPI:
|
||||
// 提醒接入发货信息管理服务API
|
||||
// 提醒接入发货信息管理服务 API
|
||||
var pushData PushDataRemindAccessAPI
|
||||
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
|
||||
return &pushData, err
|
||||
@@ -188,25 +203,104 @@ func (receiver *PushReceiver) getEvent(dataType string, eventType EventType, dec
|
||||
var pushData PushDataXpayCoinPayNotify
|
||||
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
|
||||
return &pushData, err
|
||||
case EventSubscribePopup:
|
||||
// 用户操作订阅通知弹窗事件推送
|
||||
return receiver.unmarshalSubscribePopup(dataType, decryptMsg)
|
||||
case EventSubscribeMsgChange:
|
||||
// 用户管理订阅通知事件推送
|
||||
return receiver.unmarshalSubscribeMsgChange(dataType, decryptMsg)
|
||||
case EventSubscribeMsgSent:
|
||||
// 用户发送订阅通知事件推送
|
||||
return receiver.unmarshalSubscribeMsgSent(dataType, decryptMsg)
|
||||
}
|
||||
// 暂不支持其他事件类型,直接返回解密后的数据,由调用方处理
|
||||
return decryptMsg, nil
|
||||
}
|
||||
|
||||
// unmarshal 解析推送的数据
|
||||
func (receiver *PushReceiver) unmarshal(dateType string, decryptMsg []byte, pushData interface{}) error {
|
||||
if dateType == DataTypeXML {
|
||||
func (receiver *PushReceiver) unmarshal(dataType string, decryptMsg []byte, pushData interface{}) error {
|
||||
if dataType == DataTypeXML {
|
||||
return xml.Unmarshal(decryptMsg, pushData)
|
||||
}
|
||||
return json.Unmarshal(decryptMsg, pushData)
|
||||
}
|
||||
|
||||
// unmarshalSubscribePopup
|
||||
func (receiver *PushReceiver) unmarshalSubscribePopup(dataType string, decryptMsg []byte) (PushData, error) {
|
||||
var pushData PushDataSubscribePopup
|
||||
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
|
||||
if err == nil {
|
||||
listData := gjson.Get(string(decryptMsg), "List")
|
||||
if listData.IsObject() {
|
||||
listItem := SubscribeMsgPopupEventList{}
|
||||
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
|
||||
return &pushData, parseErr
|
||||
}
|
||||
pushData.SetSubscribeMsgPopupEvents([]SubscribeMsgPopupEventList{listItem})
|
||||
} else if listData.IsArray() {
|
||||
listItems := make([]SubscribeMsgPopupEventList, 0)
|
||||
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
|
||||
return &pushData, parseErr
|
||||
}
|
||||
pushData.SetSubscribeMsgPopupEvents(listItems)
|
||||
}
|
||||
}
|
||||
|
||||
return &pushData, err
|
||||
}
|
||||
|
||||
// unmarshalSubscribeMsgChange 解析用户管理订阅通知事件推送
|
||||
func (receiver *PushReceiver) unmarshalSubscribeMsgChange(dataType string, decryptMsg []byte) (PushData, error) {
|
||||
var pushData PushDataSubscribeMsgChange
|
||||
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
|
||||
if err == nil {
|
||||
listData := gjson.Get(string(decryptMsg), "List")
|
||||
if listData.IsObject() {
|
||||
listItem := SubscribeMsgChangeList{}
|
||||
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
|
||||
return &pushData, parseErr
|
||||
}
|
||||
pushData.SetSubscribeMsgChangeEvents([]SubscribeMsgChangeList{listItem})
|
||||
} else if listData.IsArray() {
|
||||
listItems := make([]SubscribeMsgChangeList, 0)
|
||||
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
|
||||
return &pushData, parseErr
|
||||
}
|
||||
pushData.SetSubscribeMsgChangeEvents(listItems)
|
||||
}
|
||||
}
|
||||
return &pushData, err
|
||||
}
|
||||
|
||||
// unmarshalSubscribeMsgSent 解析用户发送订阅通知事件推送
|
||||
func (receiver *PushReceiver) unmarshalSubscribeMsgSent(dataType string, decryptMsg []byte) (PushData, error) {
|
||||
var pushData PushDataSubscribeMsgSent
|
||||
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
|
||||
if err == nil {
|
||||
listData := gjson.Get(string(decryptMsg), "List")
|
||||
if listData.IsObject() {
|
||||
listItem := SubscribeMsgSentList{}
|
||||
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
|
||||
return &pushData, parseErr
|
||||
}
|
||||
pushData.SetSubscribeMsgSentEvents([]SubscribeMsgSentList{listItem})
|
||||
} else if listData.IsArray() {
|
||||
listItems := make([]SubscribeMsgSentList, 0)
|
||||
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
|
||||
return &pushData, parseErr
|
||||
}
|
||||
pushData.SetSubscribeMsgSentEvents(listItems)
|
||||
}
|
||||
}
|
||||
return &pushData, err
|
||||
}
|
||||
|
||||
// DataReceived 接收到的数据
|
||||
type DataReceived struct {
|
||||
Encrypt string `json:"Encrypt" xml:"Encrypt"` // 加密的消息体
|
||||
}
|
||||
|
||||
// PushData 推送的数据(已转对应的结构体)
|
||||
// PushData 推送的数据 (已转对应的结构体)
|
||||
type PushData interface{}
|
||||
|
||||
// CommonPushData 推送数据通用部分
|
||||
@@ -216,7 +310,7 @@ type CommonPushData struct {
|
||||
Event EventType `json:"Event" xml:"Event"` // 事件类型
|
||||
ToUserName string `json:"ToUserName" xml:"ToUserName"` // 小程序的原始 ID
|
||||
FromUserName string `json:"FromUserName" xml:"FromUserName"` // 发送方账号(一个 OpenID,此时发送方是系统账号)
|
||||
CreateTime int64 `json:"CreateTime" xml:"CreateTime"` // 消息创建时间 (整型),时间戳
|
||||
CreateTime int64 `json:"CreateTime" xml:"CreateTime"` // 消息创建时间(整型),时间戳
|
||||
}
|
||||
|
||||
// MediaCheckAsyncData 媒体内容安全异步审查结果通知
|
||||
@@ -272,7 +366,7 @@ type PushDataRemindShipping struct {
|
||||
Msg string `json:"msg" xml:"msg"` // 消息文本内容
|
||||
}
|
||||
|
||||
// PushDataRemindAccessAPI 提醒接入发货信息管理服务API信息
|
||||
// PushDataRemindAccessAPI 提醒接入发货信息管理服务 API 信息
|
||||
type PushDataRemindAccessAPI struct {
|
||||
CommonPushData
|
||||
Msg string `json:"msg" xml:"msg"` // 消息文本内容
|
||||
@@ -281,9 +375,9 @@ type PushDataRemindAccessAPI struct {
|
||||
// PushDataAddExpressPath 运单轨迹更新信息
|
||||
type PushDataAddExpressPath struct {
|
||||
CommonPushData
|
||||
DeliveryID string `json:"DeliveryID" xml:"DeliveryID"` // 快递公司ID
|
||||
WayBillID string `json:"WaybillId" xml:"WaybillId"` // 运单ID
|
||||
OrderID string `json:"OrderId" xml:"OrderId"` // 订单ID
|
||||
DeliveryID string `json:"DeliveryID" xml:"DeliveryID"` // 快递公司 ID
|
||||
WayBillID string `json:"WaybillId" xml:"WaybillId"` // 运单 ID
|
||||
OrderID string `json:"OrderId" xml:"OrderId"` // 订单 ID
|
||||
Version int `json:"Version" xml:"Version"` // 轨迹版本号(整型)
|
||||
Count int `json:"Count" xml:"Count"` // 轨迹节点数(整型)
|
||||
Actions []*PushDataAddExpressPathAction `json:"Actions" xml:"Actions"` // 轨迹节点列表
|
||||
@@ -304,10 +398,10 @@ type PushDataSecVodUpload struct {
|
||||
|
||||
// SecVodUploadEvent 短剧媒资上传完成事件
|
||||
type SecVodUploadEvent struct {
|
||||
MediaID string `json:"media_id" xml:"media_id"` // 媒资id
|
||||
MediaID string `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"` // 错误提示
|
||||
ErrCode int `json:"errcode" xml:"errcode"` // 错误码,上传失败时该值非
|
||||
ErrMsg string `json:"errmsg" xml:"errmsg"` // 错误提示
|
||||
}
|
||||
|
||||
// PushDataSecVodAudit 短剧媒资审核状态
|
||||
@@ -318,14 +412,14 @@ type PushDataSecVodAudit struct {
|
||||
|
||||
// SecVodAuditEvent 短剧媒资审核状态事件
|
||||
type SecVodAuditEvent struct {
|
||||
DramaID string `json:"drama_id" xml:"drama_id"` // 剧目id
|
||||
DramaID string `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查询剧集详情得到
|
||||
AuditDetail DramaAuditDetail `json:"audit_detail" xml:"audit_detail"` // 剧目审核结果,单独每一集的审核结果可以根据 drama_id 查询剧集详情得到
|
||||
}
|
||||
|
||||
// DramaAuditDetail 剧目审核结果
|
||||
type DramaAuditDetail struct {
|
||||
Status int `json:"status" xml:"status"` // 审核状态,0为无效值;1为审核中;2为最终失败;3为审核通过;4为驳回重填
|
||||
Status int `json:"status" xml:"status"` // 审核状态,0 为无效值;1 为审核中;2 为最终失败;3 为审核通过;4 为驳回重填
|
||||
CreateTime int64 `json:"create_time" xml:"create_time"` // 提审时间戳
|
||||
AuditTime int64 `json:"audit_time" xml:"audit_time"` // 审核时间戳
|
||||
}
|
||||
@@ -333,9 +427,9 @@ type DramaAuditDetail struct {
|
||||
// PushDataXpayGoodsDeliverNotify 道具发货推送
|
||||
type PushDataXpayGoodsDeliverNotify struct {
|
||||
CommonPushData
|
||||
OpenID string `json:"OpenId" xml:"OpenId"` // 用户openid
|
||||
OpenID string `json:"OpenId" xml:"OpenId"` // 用户 openid
|
||||
OutTradeNo string `json:"OutTradeNo" xml:"OutTradeNo"` // 业务订单号
|
||||
Env int `json:"Env" xml:"Env"` //,环境配置 0:现网环境(也叫正式环境)1:沙箱环境
|
||||
Env int `json:"Env" xml:"Env"` // ,环境配置 0:现网环境(也叫正式环境)1:沙箱环境
|
||||
WeChatPayInfo WeChatPayInfo `json:"WeChatPayInfo" xml:"WeChatPayInfo"` // 微信支付信息 非微信支付渠道可能没有
|
||||
GoodsInfo GoodsInfo `json:"GoodsInfo" xml:"GoodsInfo"` // 道具参数信息
|
||||
}
|
||||
@@ -344,14 +438,14 @@ type PushDataXpayGoodsDeliverNotify struct {
|
||||
type WeChatPayInfo struct {
|
||||
MchOrderNo string `json:"MchOrderNo" xml:"MchOrderNo"` // 微信支付商户单号
|
||||
TransactionID string `json:"TransactionId" xml:"TransactionId"` // 交易单号(微信支付订单号)
|
||||
PaidTime int64 `json:"PaidTime" xml:"PaidTime"` // 用户支付时间,Linux秒级时间戳
|
||||
PaidTime int64 `json:"PaidTime" xml:"PaidTime"` // 用户支付时间,Linux 秒级时间戳
|
||||
}
|
||||
|
||||
// GoodsInfo 道具参数信息
|
||||
type GoodsInfo struct {
|
||||
ProductID string `json:"ProductId" xml:"ProductId"` // 道具ID
|
||||
ProductID string `json:"ProductId" xml:"ProductId"` // 道具 ID
|
||||
Quantity int `json:"Quantity" xml:"Quantity"` // 数量
|
||||
OrigPrice int64 `json:"OrigPrice" xml:"OrigPrice"` // 物品原始价格 (单位:分)
|
||||
OrigPrice int64 `json:"OrigPrice" xml:"OrigPrice"` // 物品原始价格(单位:分)
|
||||
ActualPrice int64 `json:"ActualPrice" xml:"ActualPrice"` // 物品实际支付价格(单位:分)
|
||||
Attach string `json:"Attach" xml:"Attach"` // 透传信息
|
||||
}
|
||||
@@ -359,9 +453,9 @@ type GoodsInfo struct {
|
||||
// PushDataXpayCoinPayNotify 代币支付推送
|
||||
type PushDataXpayCoinPayNotify struct {
|
||||
CommonPushData
|
||||
OpenID string `json:"OpenId" xml:"OpenId"` // 用户openid
|
||||
OpenID string `json:"OpenId" xml:"OpenId"` // 用户 openid
|
||||
OutTradeNo string `json:"OutTradeNo" xml:"OutTradeNo"` // 业务订单号
|
||||
Env int `json:"Env" xml:"Env"` //,环境配置 0:现网环境(也叫正式环境)1:沙箱环境
|
||||
Env int `json:"Env" xml:"Env"` // ,环境配置 0:现网环境(也叫正式环境)1:沙箱环境
|
||||
WeChatPayInfo WeChatPayInfo `json:"WeChatPayInfo" xml:"WeChatPayInfo"` // 微信支付信息 非微信支付渠道可能没有
|
||||
CoinInfo CoinInfo `json:"CoinInfo" xml:"CoinInfo"` // 代币参数信息
|
||||
}
|
||||
@@ -369,7 +463,117 @@ type PushDataXpayCoinPayNotify struct {
|
||||
// CoinInfo 代币参数信息
|
||||
type CoinInfo struct {
|
||||
Quantity int `json:"Quantity" xml:"Quantity"` // 数量
|
||||
OrigPrice int64 `json:"OrigPrice" xml:"OrigPrice"` // 物品原始价格 (单位:分)
|
||||
OrigPrice int64 `json:"OrigPrice" xml:"OrigPrice"` // 物品原始价格(单位:分)
|
||||
ActualPrice int64 `json:"ActualPrice" xml:"ActualPrice"` // 物品实际支付价格(单位:分)
|
||||
Attach string `json:"Attach" xml:"Attach"` // 透传信息
|
||||
}
|
||||
|
||||
// PushDataSubscribePopup 用户操作订阅通知弹窗事件推送
|
||||
type PushDataSubscribePopup struct {
|
||||
CommonPushData
|
||||
subscribeMsgPopupEventList []SubscribeMsgPopupEventList `json:"-"`
|
||||
SubscribeMsgPopupEvent SubscribeMsgPopupEvent `xml:"SubscribeMsgPopupEvent"`
|
||||
}
|
||||
|
||||
// SubscribeMsgPopupEvent 用户操作订阅通知弹窗消息回调
|
||||
type SubscribeMsgPopupEvent struct {
|
||||
List []SubscribeMsgPopupEventList `xml:"List"`
|
||||
}
|
||||
|
||||
// SubscribeMsgPopupEventList 订阅消息事件列表
|
||||
type SubscribeMsgPopupEventList struct {
|
||||
TemplateID string `xml:"TemplateId" json:"TemplateId"`
|
||||
SubscribeStatusString string `xml:"SubscribeStatusString" json:"SubscribeStatusString"`
|
||||
PopupScene string `xml:"PopupScene" json:"PopupScene"`
|
||||
}
|
||||
|
||||
// SetSubscribeMsgPopupEvents 设置订阅消息事件
|
||||
func (s *PushDataSubscribePopup) SetSubscribeMsgPopupEvents(list []SubscribeMsgPopupEventList) {
|
||||
s.subscribeMsgPopupEventList = list
|
||||
}
|
||||
|
||||
// GetSubscribeMsgPopupEvents 获取订阅消息事件数据
|
||||
func (s *PushDataSubscribePopup) GetSubscribeMsgPopupEvents() []SubscribeMsgPopupEventList {
|
||||
if s.subscribeMsgPopupEventList != nil {
|
||||
return s.subscribeMsgPopupEventList
|
||||
}
|
||||
|
||||
if s.SubscribeMsgPopupEvent.List == nil || len(s.SubscribeMsgPopupEvent.List) < 1 {
|
||||
return nil
|
||||
}
|
||||
return s.SubscribeMsgPopupEvent.List
|
||||
}
|
||||
|
||||
// PushDataSubscribeMsgChange 用户管理订阅通知事件推送
|
||||
type PushDataSubscribeMsgChange struct {
|
||||
CommonPushData
|
||||
SubscribeMsgChangeEvent SubscribeMsgChangeEvent `xml:"SubscribeMsgChangeEvent"`
|
||||
subscribeMsgChangeList []SubscribeMsgChangeList `json:"-"`
|
||||
}
|
||||
|
||||
// SubscribeMsgChangeEvent 用户管理订阅通知回调
|
||||
type SubscribeMsgChangeEvent struct {
|
||||
List []SubscribeMsgChangeList `xml:"List" json:"List"`
|
||||
}
|
||||
|
||||
// SubscribeMsgChangeList 订阅消息事件列表
|
||||
type SubscribeMsgChangeList struct {
|
||||
TemplateID string `xml:"TemplateId" json:"TemplateId"`
|
||||
SubscribeStatusString string `xml:"SubscribeStatusString" json:"SubscribeStatusString"`
|
||||
}
|
||||
|
||||
// SetSubscribeMsgChangeEvents 设置订阅消息事件
|
||||
func (s *PushDataSubscribeMsgChange) SetSubscribeMsgChangeEvents(list []SubscribeMsgChangeList) {
|
||||
s.subscribeMsgChangeList = list
|
||||
}
|
||||
|
||||
// GetSubscribeMsgChangeEvents 获取订阅消息事件数据
|
||||
func (s *PushDataSubscribeMsgChange) GetSubscribeMsgChangeEvents() []SubscribeMsgChangeList {
|
||||
if s.subscribeMsgChangeList != nil {
|
||||
return s.subscribeMsgChangeList
|
||||
}
|
||||
|
||||
if s.SubscribeMsgChangeEvent.List == nil || len(s.SubscribeMsgChangeEvent.List) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.SubscribeMsgChangeEvent.List
|
||||
}
|
||||
|
||||
// PushDataSubscribeMsgSent 用户发送订阅通知事件推送
|
||||
type PushDataSubscribeMsgSent struct {
|
||||
CommonPushData
|
||||
SubscribeMsgSentEvent SubscribeMsgSentEvent `xml:"SubscribeMsgSentEvent"`
|
||||
subscribeMsgSentEventList []SubscribeMsgSentList `json:"-"`
|
||||
}
|
||||
|
||||
// SubscribeMsgSentEvent 用户发送订阅通知回调
|
||||
type SubscribeMsgSentEvent struct {
|
||||
List []SubscribeMsgSentList `xml:"List" json:"List"`
|
||||
}
|
||||
|
||||
// SubscribeMsgSentList 订阅消息事件列表
|
||||
type SubscribeMsgSentList struct {
|
||||
TemplateID string `xml:"TemplateId" json:"TemplateId"`
|
||||
MsgID string `xml:"MsgID" json:"MsgID"`
|
||||
ErrorCode int `xml:"ErrorCode" json:"ErrorCode"`
|
||||
ErrorStatus string `xml:"ErrorStatus" json:"ErrorStatus"`
|
||||
}
|
||||
|
||||
// SetSubscribeMsgSentEvents 设置订阅消息事件
|
||||
func (s *PushDataSubscribeMsgSent) SetSubscribeMsgSentEvents(list []SubscribeMsgSentList) {
|
||||
s.subscribeMsgSentEventList = list
|
||||
}
|
||||
|
||||
// GetSubscribeMsgSentEvents 获取订阅消息事件数据
|
||||
func (s *PushDataSubscribeMsgSent) GetSubscribeMsgSentEvents() []SubscribeMsgSentList {
|
||||
if s.subscribeMsgSentEventList != nil {
|
||||
return s.subscribeMsgSentEventList
|
||||
}
|
||||
|
||||
if s.SubscribeMsgSentEvent.List == nil || len(s.SubscribeMsgSentEvent.List) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.SubscribeMsgSentEvent.List
|
||||
}
|
||||
|
||||
15
miniprogram/message/reply.go
Normal file
15
miniprogram/message/reply.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package message
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrInvalidReply 无效的回复
|
||||
var ErrInvalidReply = errors.New("无效的回复信息")
|
||||
|
||||
// ErrUnsupportedReply 不支持的回复类型
|
||||
var ErrUnsupportedReply = errors.New("不支持的回复消息")
|
||||
|
||||
// Reply 消息回复
|
||||
type Reply struct {
|
||||
MsgType MsgType
|
||||
MsgData interface{}
|
||||
}
|
||||
@@ -27,15 +27,15 @@ const (
|
||||
MsgTypeVideo MsgType = "video"
|
||||
// MsgTypeMiniprogrampage 表示小程序卡片消息
|
||||
MsgTypeMiniprogrampage MsgType = "miniprogrampage"
|
||||
// MsgTypeShortVideo 表示短视频消息[限接收]
|
||||
// MsgTypeShortVideo 表示短视频消息 [限接收]
|
||||
MsgTypeShortVideo MsgType = "shortvideo"
|
||||
// MsgTypeLocation 表示坐标消息[限接收]
|
||||
// MsgTypeLocation 表示坐标消息 [限接收]
|
||||
MsgTypeLocation MsgType = "location"
|
||||
// MsgTypeLink 表示链接消息[限接收]
|
||||
// MsgTypeLink 表示链接消息 [限接收]
|
||||
MsgTypeLink MsgType = "link"
|
||||
// MsgTypeMusic 表示音乐消息[限回复]
|
||||
// MsgTypeMusic 表示音乐消息 [限回复]
|
||||
MsgTypeMusic MsgType = "music"
|
||||
// MsgTypeNews 表示图文消息[限回复]
|
||||
// MsgTypeNews 表示图文消息 [限回复]
|
||||
MsgTypeNews MsgType = "news"
|
||||
// MsgTypeTransfer 表示消息消息转发到客服
|
||||
MsgTypeTransfer MsgType = "transfer_customer_service"
|
||||
@@ -91,7 +91,7 @@ const (
|
||||
const (
|
||||
// 微信开放平台需要用到
|
||||
|
||||
// InfoTypeVerifyTicket 返回ticket
|
||||
// InfoTypeVerifyTicket 返回 ticket
|
||||
InfoTypeVerifyTicket InfoType = "component_verify_ticket"
|
||||
// InfoTypeAuthorized 授权
|
||||
InfoTypeAuthorized InfoType = "authorized"
|
||||
@@ -108,8 +108,8 @@ type MixMessage struct {
|
||||
CommonToken
|
||||
|
||||
// 基本消息
|
||||
MsgID int64 `xml:"MsgId"` // 其他消息推送过来是MsgId
|
||||
TemplateMsgID int64 `xml:"MsgID"` // 模板消息推送成功的消息是MsgID
|
||||
MsgID int64 `xml:"MsgId"` // 其他消息推送过来是 MsgId
|
||||
TemplateMsgID int64 `xml:"MsgID"` // 模板消息推送成功的消息是 MsgID
|
||||
Content string `xml:"Content"`
|
||||
Recognition string `xml:"Recognition"`
|
||||
PicURL string `xml:"PicUrl"`
|
||||
@@ -166,17 +166,17 @@ type MixMessage struct {
|
||||
|
||||
// 事件相关:发布能力
|
||||
PublishEventInfo struct {
|
||||
PublishID int64 `xml:"publish_id"` // 发布任务id
|
||||
PublishID int64 `xml:"publish_id"` // 发布任务 id
|
||||
PublishStatus freepublish.PublishStatus `xml:"publish_status"` // 发布状态
|
||||
ArticleID string `xml:"article_id"` // 当发布状态为0时(即成功)时,返回图文的 article_id,可用于“客服消息”场景
|
||||
ArticleID string `xml:"article_id"` // 当发布状态为 0 时(即成功)时,返回图文的 article_id,可用于“客服消息”场景
|
||||
ArticleDetail struct {
|
||||
Count uint `xml:"count"` // 文章数量
|
||||
Item []struct {
|
||||
Index uint `xml:"idx"` // 文章对应的编号
|
||||
ArticleURL string `xml:"article_url"` // 图文的永久链接
|
||||
} `xml:"item"`
|
||||
} `xml:"article_detail"` // 当发布状态为0时(即成功)时,返回内容
|
||||
FailIndex []uint `xml:"fail_idx"` // 当发布状态为2或4时,返回不通过的文章编号,第一篇为 1;其他发布状态则为空
|
||||
} `xml:"article_detail"` // 当发布状态为 0 时(即成功)时,返回内容
|
||||
FailIndex []uint `xml:"fail_idx"` // 当发布状态为 2 或 4 时,返回不通过的文章编号,第一篇为 1;其他发布状态则为空
|
||||
} `xml:"PublishEventInfo"`
|
||||
|
||||
// 第三方平台相关
|
||||
@@ -222,19 +222,19 @@ type MixMessage struct {
|
||||
TraceID string `xml:"trace_id"`
|
||||
StatusCode int `xml:"status_code"`
|
||||
|
||||
//小程序名称审核结果事件推送
|
||||
Ret int32 `xml:"ret"` //审核结果 2:失败,3:成功
|
||||
NickName string `xml:"nickname"` //小程序昵称
|
||||
// 小程序名称审核结果事件推送
|
||||
Ret int32 `xml:"ret"` // 审核结果 2:失败,3:成功
|
||||
NickName string `xml:"nickname"` // 小程序昵称
|
||||
|
||||
// 设备相关
|
||||
device.MsgDevice
|
||||
|
||||
//小程序审核通知
|
||||
SuccTime int `xml:"SuccTime"` //审核成功时的时间戳
|
||||
FailTime int `xml:"FailTime"` //审核不通过的时间戳
|
||||
DelayTime int `xml:"DelayTime"` //审核延后时的时间戳
|
||||
Reason string `xml:"Reason"` //审核不通过的原因
|
||||
ScreenShot string `xml:"ScreenShot"` //审核不通过的截图示例。用 | 分隔的 media_id 的列表,可通过获取永久素材接口拉取截图内容
|
||||
// 小程序审核通知
|
||||
SuccTime int `xml:"SuccTime"` // 审核成功时的时间戳
|
||||
FailTime int `xml:"FailTime"` // 审核不通过的时间戳
|
||||
DelayTime int `xml:"DelayTime"` // 审核延后时的时间戳
|
||||
Reason string `xml:"Reason"` // 审核不通过的原因
|
||||
ScreenShot string `xml:"ScreenShot"` // 审核不通过的截图示例。用 | 分隔的 media_id 的列表,可通过获取永久素材接口拉取截图内容
|
||||
}
|
||||
|
||||
// SubscribeMsgPopupEvent 订阅通知事件推送的消息体
|
||||
@@ -282,7 +282,7 @@ type ResponseEncryptedXMLMsg struct {
|
||||
Nonce string `xml:"Nonce" json:"Nonce"`
|
||||
}
|
||||
|
||||
// CDATA 使用该类型,在序列化为 xml 文本时文本会被解析器忽略
|
||||
// CDATA 使用该类型,在序列化为 xml 文本时文本会被解析器忽略
|
||||
type CDATA string
|
||||
|
||||
// MarshalXML 实现自己的序列化方法
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
ctx2 "context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -73,11 +74,28 @@ type ResAccessToken struct {
|
||||
UnionID string `json:"unionid"`
|
||||
}
|
||||
|
||||
// GetUserInfoByCodeContext 通过网页授权的code 换取用户的信息
|
||||
func (oauth *Oauth) GetUserInfoByCodeContext(ctx ctx2.Context, code string) (result UserInfo, err error) {
|
||||
var (
|
||||
token ResAccessToken
|
||||
)
|
||||
if token, err = oauth.GetUserAccessTokenContext(ctx, code); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return oauth.GetUserInfoContext(ctx, token.AccessToken, token.OpenID, "")
|
||||
}
|
||||
|
||||
// GetUserAccessToken 通过网页授权的code 换取access_token(区别于context中的access_token)
|
||||
func (oauth *Oauth) GetUserAccessToken(code string) (result ResAccessToken, err error) {
|
||||
return oauth.GetUserAccessTokenContext(ctx2.Background(), code)
|
||||
}
|
||||
|
||||
// GetUserAccessTokenContext 通过网页授权的code 换取access_token(区别于context中的access_token) with context
|
||||
func (oauth *Oauth) GetUserAccessTokenContext(ctx ctx2.Context, code string) (result ResAccessToken, err error) {
|
||||
urlStr := fmt.Sprintf(accessTokenURL, oauth.AppID, oauth.AppSecret, code)
|
||||
var response []byte
|
||||
response, err = util.HTTPGet(urlStr)
|
||||
response, err = util.HTTPGetContext(ctx, urlStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -94,9 +112,14 @@ func (oauth *Oauth) GetUserAccessToken(code string) (result ResAccessToken, err
|
||||
|
||||
// RefreshAccessToken 刷新access_token
|
||||
func (oauth *Oauth) RefreshAccessToken(refreshToken string) (result ResAccessToken, err error) {
|
||||
return oauth.RefreshAccessTokenContext(ctx2.Background(), refreshToken)
|
||||
}
|
||||
|
||||
// RefreshAccessTokenContext 刷新access_token with context
|
||||
func (oauth *Oauth) RefreshAccessTokenContext(ctx ctx2.Context, refreshToken string) (result ResAccessToken, err error) {
|
||||
urlStr := fmt.Sprintf(refreshAccessTokenURL, oauth.AppID, refreshToken)
|
||||
var response []byte
|
||||
response, err = util.HTTPGet(urlStr)
|
||||
response, err = util.HTTPGetContext(ctx, urlStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -113,9 +136,14 @@ func (oauth *Oauth) RefreshAccessToken(refreshToken string) (result ResAccessTok
|
||||
|
||||
// CheckAccessToken 检验access_token是否有效
|
||||
func (oauth *Oauth) CheckAccessToken(accessToken, openID string) (b bool, err error) {
|
||||
return oauth.CheckAccessTokenContext(ctx2.Background(), accessToken, openID)
|
||||
}
|
||||
|
||||
// CheckAccessTokenContext 检验access_token是否有效 with context
|
||||
func (oauth *Oauth) CheckAccessTokenContext(ctx ctx2.Context, accessToken, openID string) (b bool, err error) {
|
||||
urlStr := fmt.Sprintf(checkAccessTokenURL, accessToken, openID)
|
||||
var response []byte
|
||||
response, err = util.HTTPGet(urlStr)
|
||||
response, err = util.HTTPGetContext(ctx, urlStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -149,12 +177,17 @@ type UserInfo struct {
|
||||
|
||||
// GetUserInfo 如果scope为 snsapi_userinfo 则可以通过此方法获取到用户基本信息
|
||||
func (oauth *Oauth) GetUserInfo(accessToken, openID, lang string) (result UserInfo, err error) {
|
||||
return oauth.GetUserInfoContext(ctx2.Background(), accessToken, openID, lang)
|
||||
}
|
||||
|
||||
// GetUserInfoContext 如果scope为 snsapi_userinfo 则可以通过此方法获取到用户基本信息 with context
|
||||
func (oauth *Oauth) GetUserInfoContext(ctx ctx2.Context, accessToken, openID, lang string) (result UserInfo, err error) {
|
||||
if lang == "" {
|
||||
lang = "zh_CN"
|
||||
}
|
||||
urlStr := fmt.Sprintf(userInfoURL, accessToken, openID, lang)
|
||||
var response []byte
|
||||
response, err = util.HTTPGet(urlStr)
|
||||
response, err = util.HTTPGetContext(ctx, urlStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func (srv *Server) Serve() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 非安全模式下,请求处理方法返回为nil则直接回复success给微信服务器
|
||||
// 非安全模式下,请求处理方法返回为 nil 则直接回复 success 给微信服务器
|
||||
if response == nil && !srv.isSafeMode {
|
||||
srv.String("success")
|
||||
return nil
|
||||
@@ -198,7 +198,7 @@ func (srv *Server) parseRequestMessage(rawXMLMsgBytes []byte) (msg *message.MixM
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// nonstandard json, 目前小程序订阅消息返回数据格式不标准,订阅消息模板单个List返回是对象,多个List返回是数组。
|
||||
// nonstandard json, 目前小程序订阅消息返回数据格式不标准,订阅消息模板单个 List 返回是对象,多个 List 返回是数组。
|
||||
if msg.MsgType == message.MsgTypeEvent {
|
||||
listData := gjson.Get(string(rawXMLMsgBytes), "List")
|
||||
if listData.IsObject() {
|
||||
@@ -284,7 +284,7 @@ func (srv *Server) Send() (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// TODO 如果获取不到timestamp nonce 则自己生成
|
||||
// TODO 如果获取不到 timestamp nonce 则自己生成
|
||||
timestamp := srv.timestamp
|
||||
timestampStr := strconv.FormatInt(timestamp, 10)
|
||||
msgSignature := util.Signature(srv.Token, timestampStr, srv.nonce, string(encryptedMsg))
|
||||
|
||||
28
util/http.go
28
util/http.go
@@ -17,6 +17,16 @@ import (
|
||||
"golang.org/x/crypto/pkcs12"
|
||||
)
|
||||
|
||||
// URIModifier URI修改器
|
||||
type URIModifier func(uri string) string
|
||||
|
||||
var uriModifier URIModifier
|
||||
|
||||
// SetURIModifier 设置URI修改器
|
||||
func SetURIModifier(fn URIModifier) {
|
||||
uriModifier = fn
|
||||
}
|
||||
|
||||
// HTTPGet get 请求
|
||||
func HTTPGet(uri string) ([]byte, error) {
|
||||
return HTTPGetContext(context.Background(), uri)
|
||||
@@ -24,6 +34,9 @@ func HTTPGet(uri string) ([]byte, error) {
|
||||
|
||||
// HTTPGetContext get 请求
|
||||
func HTTPGetContext(ctx context.Context, uri string) ([]byte, error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -47,6 +60,9 @@ func HTTPPost(uri string, data string) ([]byte, error) {
|
||||
|
||||
// HTTPPostContext post 请求
|
||||
func HTTPPostContext(ctx context.Context, uri string, data []byte, header map[string]string) ([]byte, error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
body := bytes.NewBuffer(data)
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, body)
|
||||
if err != nil {
|
||||
@@ -71,6 +87,9 @@ func HTTPPostContext(ctx context.Context, uri string, data []byte, header map[st
|
||||
|
||||
// PostJSONContext post json 数据请求
|
||||
func PostJSONContext(ctx context.Context, uri string, obj interface{}) ([]byte, error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
jsonBuf := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(jsonBuf)
|
||||
enc.SetEscapeHTML(false)
|
||||
@@ -146,6 +165,9 @@ type MultipartFormField struct {
|
||||
|
||||
// PostMultipartForm 上传文件或其他多个字段
|
||||
func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte, err error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
bodyBuf := &bytes.Buffer{}
|
||||
bodyWriter := multipart.NewWriter(bodyBuf)
|
||||
|
||||
@@ -198,6 +220,9 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte
|
||||
|
||||
// PostXML perform a HTTP/POST request with XML body
|
||||
func PostXML(uri string, obj interface{}) ([]byte, error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
xmlData, err := xml.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -259,6 +284,9 @@ func pkcs12ToPem(p12 []byte, password string) tls.Certificate {
|
||||
|
||||
// PostXMLWithTLS perform a HTTP/POST request with XML body and TLS
|
||||
func PostXMLWithTLS(uri string, obj interface{}, ca, key string) ([]byte, error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
xmlData, err := xml.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -12,7 +12,8 @@ const (
|
||||
// departmentSimpleListURL 获取子部门ID列表
|
||||
departmentSimpleListURL = "https://qyapi.weixin.qq.com/cgi-bin/department/simplelist?access_token=%s&id=%d"
|
||||
// departmentListURL 获取部门列表
|
||||
departmentListURL = "https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=%s"
|
||||
departmentListURL = "https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=%s"
|
||||
departmentListByIDURL = "https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=%s&id=%d"
|
||||
// departmentGetURL 获取单个部门详情 https://qyapi.weixin.qq.com/cgi-bin/department/get?access_token=ACCESS_TOKEN&id=ID
|
||||
departmentGetURL = "https://qyapi.weixin.qq.com/cgi-bin/department/get?access_token=%s&id=%d"
|
||||
)
|
||||
@@ -106,13 +107,31 @@ func (r *Client) DepartmentSimpleList(departmentID int) ([]*DepartmentID, error)
|
||||
// DepartmentList 获取部门列表
|
||||
// @desc https://developer.work.weixin.qq.com/document/path/90208
|
||||
func (r *Client) DepartmentList() ([]*Department, error) {
|
||||
return r.DepartmentListByID(0)
|
||||
}
|
||||
|
||||
// DepartmentListByID 获取部门列表
|
||||
//
|
||||
// departmentID 部门id。获取指定部门及其下的子部门(以及子部门的子部门等等,递归)
|
||||
//
|
||||
// @desc https://developer.work.weixin.qq.com/document/path/90208
|
||||
func (r *Client) DepartmentListByID(departmentID int) ([]*Department, error) {
|
||||
var formatURL string
|
||||
|
||||
// 获取accessToken
|
||||
accessToken, err := r.GetAccessToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if departmentID > 0 {
|
||||
formatURL = fmt.Sprintf(departmentListByIDURL, accessToken, departmentID)
|
||||
} else {
|
||||
formatURL = fmt.Sprintf(departmentListURL, accessToken)
|
||||
}
|
||||
|
||||
// 发起http请求
|
||||
response, err := util.HTTPGet(fmt.Sprintf(departmentListURL, accessToken))
|
||||
response, err := util.HTTPGet(formatURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -13,6 +13,14 @@ const (
|
||||
getDayDataURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckin_daydata?access_token=%s"
|
||||
// getMonthDataURL 获取打卡月报数据
|
||||
getMonthDataURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckin_monthdata?access_token=%s"
|
||||
// getCorpOptionURL 获取企业所有打卡规则
|
||||
getCorpOptionURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcorpcheckinoption?access_token=%s"
|
||||
// getOptionURL 获取员工打卡规则
|
||||
getOptionURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckinoption?access_token=%s"
|
||||
// getScheduleListURL 获取打卡人员排班信息
|
||||
getScheduleListURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckinschedulist?access_token=%s"
|
||||
// getHardwareDataURL获取设备打卡数据
|
||||
getHardwareDataURL = "https://qyapi.weixin.qq.com/cgi-bin/hardware/get_hardware_checkin_data?access_token=%s"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -257,3 +265,396 @@ func (r *Client) GetMonthData(req *GetCheckinDataRequest) (result *GetMonthDataR
|
||||
err = util.DecodeWithError(response, result, "GetMonthData")
|
||||
return
|
||||
}
|
||||
|
||||
// GetCorpOptionResponse 获取企业所有打卡规则响应
|
||||
type GetCorpOptionResponse struct {
|
||||
util.CommonError
|
||||
Group []CorpOptionGroup `json:"group"`
|
||||
}
|
||||
|
||||
// CorpOptionGroup 企业规则信息列表
|
||||
type CorpOptionGroup struct {
|
||||
GroupType int64 `json:"grouptype"`
|
||||
GroupID int64 `json:"groupid"`
|
||||
GroupName string `json:"groupname"`
|
||||
CheckinDate []GroupCheckinDate `json:"checkindate"`
|
||||
SpeWorkdays []SpeWorkdays `json:"spe_workdays"`
|
||||
SpeOffDays []SpeOffDays `json:"spe_offdays"`
|
||||
SyncHolidays bool `json:"sync_holidays"`
|
||||
NeedPhoto bool `json:"need_photo"`
|
||||
NoteCanUseLocalPic bool `json:"note_can_use_local_pic"`
|
||||
AllowCheckinOffWorkday bool `json:"allow_checkin_offworkday"`
|
||||
AllowApplyOffWorkday bool `json:"allow_apply_offworkday"`
|
||||
WifiMacInfos []WifiMacInfos `json:"wifimac_infos"`
|
||||
LocInfos []LocInfos `json:"loc_infos"`
|
||||
Range []Range `json:"range"`
|
||||
CreateTime int64 `json:"create_time"`
|
||||
WhiteUsers []string `json:"white_users"`
|
||||
Type int64 `json:"type"`
|
||||
ReporterInfo ReporterInfo `json:"reporterinfo"`
|
||||
OtInfo GroupOtInfo `json:"ot_info"`
|
||||
OtApplyInfo OtApplyInfo `json:"otapplyinfo"`
|
||||
Uptime int64 `json:"uptime"`
|
||||
AllowApplyBkCnt int64 `json:"allow_apply_bk_cnt"`
|
||||
OptionOutRange int64 `json:"option_out_range"`
|
||||
CreateUserID string `json:"create_userid"`
|
||||
UseFaceDetect bool `json:"use_face_detect"`
|
||||
AllowApplyBkDayLimit int64 `json:"allow_apply_bk_day_limit"`
|
||||
UpdateUserID string `json:"update_userid"`
|
||||
BukaRestriction int64 `json:"buka_restriction"`
|
||||
ScheduleList []ScheduleList `json:"schedulelist"`
|
||||
OffWorkIntervalTime int64 `json:"offwork_interval_time"`
|
||||
}
|
||||
|
||||
// GroupCheckinDate 打卡时间,当规则类型为排班时没有意义
|
||||
type GroupCheckinDate struct {
|
||||
Workdays []int64 `json:"workdays"`
|
||||
CheckinTime []GroupCheckinTime `json:"checkintime"`
|
||||
NoNeedOffWork bool `json:"noneed_offwork"`
|
||||
LimitAheadTime int64 `json:"limit_aheadtime"`
|
||||
FlexOnDutyTime int64 `json:"flex_on_duty_time"`
|
||||
FlexOffDutyTime int64 `json:"flex_off_duty_time"`
|
||||
}
|
||||
|
||||
// GroupCheckinTime 工作日上下班打卡时间信息
|
||||
type GroupCheckinTime struct {
|
||||
WorkSec int64 `json:"work_sec"`
|
||||
OffWorkSec int64 `json:"off_work_sec"`
|
||||
RemindWorkSec int64 `json:"remind_work_sec"`
|
||||
RemindOffWorkSec int64 `json:"remind_off_work_sec"`
|
||||
}
|
||||
|
||||
// SpeWorkdays 特殊日期-必须打卡日期信息
|
||||
type SpeWorkdays struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Notes string `json:"notes"`
|
||||
CheckinTime []GroupCheckinTime `json:"checkintime"`
|
||||
}
|
||||
|
||||
// SpeOffDays 特殊日期-不用打卡日期信息
|
||||
type SpeOffDays struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Notes string `json:"notes"`
|
||||
}
|
||||
|
||||
// WifiMacInfos 打卡地点-WiFi打卡信息
|
||||
type WifiMacInfos struct {
|
||||
WifiName string `json:"wifiname"`
|
||||
WifiMac string `json:"wifimac"`
|
||||
}
|
||||
|
||||
// LocInfos 打卡地点-位置打卡信息
|
||||
type LocInfos struct {
|
||||
Lat int64 `json:"lat"`
|
||||
Lng int64 `json:"lng"`
|
||||
LocTitle string `json:"loc_title"`
|
||||
LocDetail string `json:"loc_detail"`
|
||||
Distance int64 `json:"distance"`
|
||||
}
|
||||
|
||||
// Range 打卡人员信息
|
||||
type Range struct {
|
||||
PartyID []string `json:"partyid"`
|
||||
UserID []string `json:"userid"`
|
||||
TagID []int64 `json:"tagid"`
|
||||
}
|
||||
|
||||
// ReporterInfo 汇报对象信息
|
||||
type ReporterInfo struct {
|
||||
Reporters []Reporters `json:"reporters"`
|
||||
UpdateTime int64 `json:"updatetime"`
|
||||
}
|
||||
|
||||
// Reporters 汇报对象,每个汇报人用userid表示
|
||||
type Reporters struct {
|
||||
UserID string `json:"userid"`
|
||||
}
|
||||
|
||||
// GroupOtInfo 加班信息
|
||||
type GroupOtInfo struct {
|
||||
Type int64 `json:"type"`
|
||||
AllowOtWorkingDay bool `json:"allow_ot_workingday"`
|
||||
AllowOtNonWorkingDay bool `json:"allow_ot_nonworkingday"`
|
||||
OtCheckInfo OtCheckInfo `json:"otcheckinfo"`
|
||||
}
|
||||
|
||||
// OtCheckInfo 以打卡时间为准-加班时长计算规则信息
|
||||
type OtCheckInfo struct {
|
||||
OtWorkingDayTimeStart int64 `json:"ot_workingday_time_start"`
|
||||
OtWorkingDayTimeMin int64 `json:"ot_workingday_time_min"`
|
||||
OtWorkingDayTimeMax int64 `json:"ot_workingday_time_max"`
|
||||
OtNonworkingDayTimeMin int64 `json:"ot_nonworkingday_time_min"`
|
||||
OtNonworkingDayTimeMax int64 `json:"ot_nonworkingday_time_max"`
|
||||
OtNonworkingDaySpanDayTime int64 `json:"ot_nonworkingday_spanday_time"`
|
||||
OtWorkingDayRestInfo OtRestInfo `json:"ot_workingday_restinfo"`
|
||||
OtNonWorkingDayRestInfo OtRestInfo `json:"ot_nonworkingday_restinfo"`
|
||||
}
|
||||
|
||||
// OtRestInfo 加班-休息扣除配置信息
|
||||
type OtRestInfo struct {
|
||||
Type int64 `json:"type"`
|
||||
FixTimeRule FixTimeRule `json:"fix_time_rule"`
|
||||
CalOtTimeRule CalOtTimeRule `json:"cal_ottime_rule"`
|
||||
}
|
||||
|
||||
// FixTimeRule 工作日加班-指定休息时间配置信息
|
||||
type FixTimeRule struct {
|
||||
FixTimeBeginSec int64 `json:"fix_time_begin_sec"`
|
||||
FixTimeEndSec int64 `json:"fix_time_end_sec"`
|
||||
}
|
||||
|
||||
// CalOtTimeRule 工作日加班-按加班时长扣除配置信息
|
||||
type CalOtTimeRule struct {
|
||||
Items []CalOtTimeRuleItem `json:"items"`
|
||||
}
|
||||
|
||||
// CalOtTimeRuleItem 工作日加班-按加班时长扣除条件信息
|
||||
type CalOtTimeRuleItem struct {
|
||||
OtTime int64 `json:"ot_time"`
|
||||
RestTime int64 `json:"rest_time"`
|
||||
}
|
||||
|
||||
// OtApplyInfo 以加班申请核算打卡记录相关信息
|
||||
type OtApplyInfo struct {
|
||||
AllowOtWorkingDay bool `json:"allow_ot_workingday"`
|
||||
AllowOtNonWorkingDay bool `json:"allow_ot_nonworkingday"`
|
||||
Uiptime int64 `json:"uptime"`
|
||||
OtNonworkingDaySpanDayTime int64 `json:"ot_nonworkingday_spanday_time"`
|
||||
OtWorkingDayRestInfo OtRestInfo `json:"ot_workingday_restinfo"`
|
||||
OtNonWorkingDayRestInfo OtRestInfo `json:"ot_nonworkingday_restinfo"`
|
||||
}
|
||||
|
||||
// ScheduleList 排班信息列表
|
||||
type ScheduleList struct {
|
||||
ScheduleID int64 `json:"schedule_id"`
|
||||
ScheduleName string `json:"schedule_name"`
|
||||
TimeSection []TimeSection `json:"time_section"`
|
||||
LimitAheadTime int64 `json:"limit_aheadtime"`
|
||||
NoNeedOffWork bool `json:"noneed_offwork"`
|
||||
LimitOffTime int64 `json:"limit_offtime"`
|
||||
FlexOnDutyTime int64 `json:"flex_on_duty_time"`
|
||||
FlexOffDutyTime int64 `json:"flex_off_duty_time"`
|
||||
AllowFlex bool `json:"allow_flex"`
|
||||
LateRule LateRule `json:"late_rule"`
|
||||
MaxAllowArriveEarly int64 `json:"max_allow_arrive_early"`
|
||||
MaxAllowArriveLate int64 `json:"max_allow_arrive_late"`
|
||||
}
|
||||
|
||||
// TimeSection 班次上下班时段信息
|
||||
type TimeSection 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"`
|
||||
}
|
||||
|
||||
// LateRule 晚走晚到时间规则信息
|
||||
type LateRule struct {
|
||||
AllowOffWorkAfterTime bool `json:"allow_offwork_after_time"`
|
||||
TimeRules []TimeRule `json:"timerules"`
|
||||
}
|
||||
|
||||
// TimeRule 迟到规则时间
|
||||
type TimeRule struct {
|
||||
OffWorkAfterTime int64 `json:"offwork_after_time"`
|
||||
OnWorkFlexTime int64 `json:"onwork_flex_time"`
|
||||
}
|
||||
|
||||
// GetCorpOption 获取企业所有打卡规则
|
||||
// @see https://developer.work.weixin.qq.com/document/path/93384
|
||||
func (r *Client) GetCorpOption() (*GetCorpOptionResponse, error) {
|
||||
var (
|
||||
accessToken string
|
||||
err error
|
||||
)
|
||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response []byte
|
||||
if response, err = util.HTTPPost(fmt.Sprintf(getCorpOptionURL, accessToken), ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := &GetCorpOptionResponse{}
|
||||
err = util.DecodeWithError(response, result, "GetCorpOption")
|
||||
return result, err
|
||||
}
|
||||
|
||||
// GetOptionRequest 获取员工打卡规则请求
|
||||
type GetOptionRequest struct {
|
||||
Datetime int64 `json:"datetime"`
|
||||
UserIDList []string `json:"useridlist"`
|
||||
}
|
||||
|
||||
// GetOptionResponse 获取员工打卡规则响应
|
||||
type GetOptionResponse struct {
|
||||
util.CommonError
|
||||
Info []OptionInfo `json:"info"`
|
||||
}
|
||||
|
||||
// OptionInfo 打卡规则列表
|
||||
type OptionInfo struct {
|
||||
UserID string `json:"userid"`
|
||||
Group OptionGroup `json:"group"`
|
||||
}
|
||||
|
||||
// OptionGroup 打卡规则相关信息
|
||||
type OptionGroup struct {
|
||||
GroupType int64 `json:"grouptype"`
|
||||
GroupID int64 `json:"groupid"`
|
||||
GroupName string `json:"groupname"`
|
||||
CheckinDate []OptionCheckinDate `json:"checkindate"`
|
||||
SpeWorkdays []SpeWorkdays `json:"spe_workdays"`
|
||||
SpeOffDays []SpeOffDays `json:"spe_offdays"`
|
||||
SyncHolidays bool `json:"sync_holidays"`
|
||||
NeedPhoto bool `json:"need_photo"`
|
||||
WifiMacInfos []WifiMacInfos `json:"wifimac_infos"`
|
||||
NoteCanUseLocalPic bool `json:"note_can_use_local_pic"`
|
||||
AllowCheckinOffWorkday bool `json:"allow_checkin_offworkday"`
|
||||
AllowApplyOffWorkday bool `json:"allow_apply_offworkday"`
|
||||
LocInfos []LocInfos `json:"loc_infos"`
|
||||
ScheduleList []ScheduleList `json:"schedulelist"`
|
||||
BukaRestriction int64 `json:"buka_restriction"`
|
||||
}
|
||||
|
||||
// OptionCheckinDate 打卡时间配置
|
||||
type OptionCheckinDate struct {
|
||||
Workdays []int64 `json:"workdays"`
|
||||
CheckinTime []GroupCheckinTime `json:"checkintime"`
|
||||
FlexTime int64 `json:"flex_time"`
|
||||
NoNeedOffWork bool `json:"noneed_offwork"`
|
||||
LimitAheadTime int64 `json:"limit_aheadtime"`
|
||||
FlexOnDutyTime int64 `json:"flex_on_duty_time"`
|
||||
FlexOffDutyTime int64 `json:"flex_off_duty_time"`
|
||||
}
|
||||
|
||||
// GetOption 获取员工打卡规则
|
||||
// see https://developer.work.weixin.qq.com/document/path/90263
|
||||
func (r *Client) GetOption(req *GetOptionRequest) (*GetOptionResponse, error) {
|
||||
var (
|
||||
accessToken string
|
||||
err error
|
||||
)
|
||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response []byte
|
||||
if response, err = util.PostJSON(fmt.Sprintf(getOptionURL, accessToken), req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := &GetOptionResponse{}
|
||||
err = util.DecodeWithError(response, result, "GetOption")
|
||||
return result, err
|
||||
}
|
||||
|
||||
// GetScheduleListRequest 获取打卡人员排班信息请求
|
||||
type GetScheduleListRequest struct {
|
||||
StartTime int64 `json:"starttime"`
|
||||
EndTime int64 `json:"endtime"`
|
||||
UserIDList []string `json:"useridlist"`
|
||||
}
|
||||
|
||||
// GetScheduleListResponse 获取打卡人员排班信息响应
|
||||
type GetScheduleListResponse struct {
|
||||
util.CommonError
|
||||
ScheduleList []ScheduleItem `json:"schedule_list"`
|
||||
}
|
||||
|
||||
// ScheduleItem 排班表信息
|
||||
type ScheduleItem struct {
|
||||
UserID string `json:"userid"`
|
||||
YearMonth int64 `json:"yearmonth"`
|
||||
GroupID int64 `json:"groupid"`
|
||||
GroupName string `json:"groupname"`
|
||||
Schedule Schedule `json:"schedule"`
|
||||
}
|
||||
|
||||
// Schedule 个人排班信息
|
||||
type Schedule struct {
|
||||
ScheduleList []ScheduleListItem `json:"scheduleList"`
|
||||
}
|
||||
|
||||
// ScheduleListItem 个人排班表信息
|
||||
type ScheduleListItem struct {
|
||||
Day int64 `json:"day"`
|
||||
ScheduleInfo ScheduleInfo `json:"schedule_info"`
|
||||
}
|
||||
|
||||
// ScheduleInfo 个人当日排班信息
|
||||
type ScheduleInfo struct {
|
||||
ScheduleID int64 `json:"schedule_id"`
|
||||
ScheduleName string `json:"schedule_name"`
|
||||
TimeSection []ScheduleTimeSection `json:"time_section"`
|
||||
}
|
||||
|
||||
// ScheduleTimeSection 班次上下班时段信息
|
||||
type ScheduleTimeSection struct {
|
||||
ID int64 `json:"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"`
|
||||
}
|
||||
|
||||
// GetScheduleList 获取打卡人员排班信息
|
||||
// see https://developer.work.weixin.qq.com/document/path/93380
|
||||
func (r *Client) GetScheduleList(req *GetScheduleListRequest) (*GetScheduleListResponse, error) {
|
||||
var (
|
||||
accessToken string
|
||||
err error
|
||||
)
|
||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response []byte
|
||||
if response, err = util.PostJSON(fmt.Sprintf(getScheduleListURL, accessToken), req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := &GetScheduleListResponse{}
|
||||
err = util.DecodeWithError(response, result, "GetScheduleList")
|
||||
return result, err
|
||||
}
|
||||
|
||||
// GetHardwareDataRequest 获取设备打卡数据请求
|
||||
type GetHardwareDataRequest struct {
|
||||
FilterType int64 `json:"filter_type"`
|
||||
StartTime int64 `json:"starttime"`
|
||||
EndTime int64 `json:"endtime"`
|
||||
UserIDList []string `json:"useridlist"`
|
||||
}
|
||||
|
||||
// GetHardwareDataResponse 获取设备打卡数据响应
|
||||
type GetHardwareDataResponse struct {
|
||||
util.CommonError
|
||||
CheckinData []HardwareCheckinData `json:"checkindata"`
|
||||
}
|
||||
|
||||
// HardwareCheckinData 设备打卡数据
|
||||
type HardwareCheckinData struct {
|
||||
UserID string `json:"userid"`
|
||||
CheckinTime int64 `json:"checkin_time"`
|
||||
DeviceSn string `json:"device_sn"`
|
||||
DeviceName string `json:"device_name"`
|
||||
}
|
||||
|
||||
// GetHardwareData 获取设备打卡数据
|
||||
// see https://developer.work.weixin.qq.com/document/path/94126
|
||||
func (r *Client) GetHardwareData(req *GetHardwareDataRequest) (*GetHardwareDataResponse, error) {
|
||||
var (
|
||||
accessToken string
|
||||
err error
|
||||
)
|
||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response []byte
|
||||
if response, err = util.PostJSON(fmt.Sprintf(getHardwareDataURL, accessToken), req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := &GetHardwareDataResponse{}
|
||||
err = util.DecodeWithError(response, result, "GetHardwareData")
|
||||
return result, err
|
||||
}
|
||||
|
||||
@@ -287,14 +287,14 @@ func (r *Client) SendWelcomeMsg(req *SendWelcomeMsgRequest) error {
|
||||
|
||||
// AddGroupWelcomeTemplateRequest 添加入群欢迎语素材请求
|
||||
type AddGroupWelcomeTemplateRequest struct {
|
||||
Text MsgText `json:"text"`
|
||||
Image AttachmentImg `json:"image"`
|
||||
Link AttachmentLink `json:"link"`
|
||||
MiniProgram AttachmentMiniProgram `json:"miniprogram"`
|
||||
File AttachmentFile `json:"file"`
|
||||
Video AttachmentVideo `json:"video"`
|
||||
AgentID int `json:"agentid"`
|
||||
Notify int `json:"notify"`
|
||||
Text MsgText `json:"text"`
|
||||
Image *AttachmentImg `json:"image,omitempty"`
|
||||
Link *AttachmentLink `json:"link,omitempty"`
|
||||
MiniProgram *AttachmentMiniProgram `json:"miniprogram,omitempty"`
|
||||
File *AttachmentFile `json:"file,omitempty"`
|
||||
Video *AttachmentVideo `json:"video,omitempty"`
|
||||
AgentID int `json:"agentid,omitempty"`
|
||||
Notify int `json:"notify,omitempty"`
|
||||
}
|
||||
|
||||
// AddGroupWelcomeTemplateResponse 添加入群欢迎语素材响应
|
||||
@@ -324,14 +324,14 @@ func (r *Client) AddGroupWelcomeTemplate(req *AddGroupWelcomeTemplateRequest) (*
|
||||
|
||||
// EditGroupWelcomeTemplateRequest 编辑入群欢迎语素材请求
|
||||
type EditGroupWelcomeTemplateRequest struct {
|
||||
TemplateID string `json:"template_id"`
|
||||
Text MsgText `json:"text"`
|
||||
Image AttachmentImg `json:"image"`
|
||||
Link AttachmentLink `json:"link"`
|
||||
MiniProgram AttachmentMiniProgram `json:"miniprogram"`
|
||||
File AttachmentFile `json:"file"`
|
||||
Video AttachmentVideo `json:"video"`
|
||||
AgentID int `json:"agentid"`
|
||||
TemplateID string `json:"template_id"`
|
||||
Text MsgText `json:"text"`
|
||||
Image *AttachmentImg `json:"image"`
|
||||
Link *AttachmentLink `json:"link"`
|
||||
MiniProgram *AttachmentMiniProgram `json:"miniprogram"`
|
||||
File *AttachmentFile `json:"file"`
|
||||
Video *AttachmentVideo `json:"video"`
|
||||
AgentID int `json:"agentid"`
|
||||
}
|
||||
|
||||
// EditGroupWelcomeTemplateResponse 编辑入群欢迎语素材响应
|
||||
@@ -366,11 +366,11 @@ type GetGroupWelcomeTemplateRequest struct {
|
||||
type GetGroupWelcomeTemplateResponse struct {
|
||||
util.CommonError
|
||||
Text MsgText `json:"text"`
|
||||
Image AttachmentImg `json:"image"`
|
||||
Link AttachmentLink `json:"link"`
|
||||
MiniProgram AttachmentMiniProgram `json:"miniprogram"`
|
||||
File AttachmentFile `json:"file"`
|
||||
Video AttachmentVideo `json:"video"`
|
||||
Image AttachmentImg `json:"image,omitempty"`
|
||||
Link AttachmentLink `json:"link,omitempty"`
|
||||
MiniProgram AttachmentMiniProgram `json:"miniprogram,omitempty"`
|
||||
File AttachmentFile `json:"file,omitempty"`
|
||||
Video AttachmentVideo `json:"video,omitempty"`
|
||||
}
|
||||
|
||||
// GetGroupWelcomeTemplate 获取入群欢迎语素材
|
||||
|
||||
Reference in New Issue
Block a user