mirror of
https://github.com/silenceper/wechat.git
synced 2026-02-23 13:42:25 +08:00
Compare commits
2 Commits
v2.1.6
...
516cdccb3a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
516cdccb3a | ||
|
|
de92dc0dcd |
8
.github/workflows/go.yml
vendored
8
.github/workflows/go.yml
vendored
@@ -2,15 +2,15 @@ name: Go
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master,release-*,v2,feature/** ]
|
branches: [ master,release-*,v2 ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master,release-*,v2,feature/** ]
|
branches: [ master,release-*,v2 ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
golangci:
|
golangci:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
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' ]
|
||||||
name: golangci-lint
|
name: golangci-lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
# strategy set
|
# strategy set
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
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' ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|||||||
@@ -66,23 +66,20 @@ func (ak *DefaultAccessToken) GetAccessToken() (accessToken string, err error) {
|
|||||||
func (ak *DefaultAccessToken) GetAccessTokenContext(ctx context.Context) (accessToken string, err error) {
|
func (ak *DefaultAccessToken) GetAccessTokenContext(ctx context.Context) (accessToken string, err error) {
|
||||||
// 先从cache中取
|
// 先从cache中取
|
||||||
accessTokenCacheKey := fmt.Sprintf("%s_access_token_%s", ak.cacheKeyPrefix, ak.appID)
|
accessTokenCacheKey := fmt.Sprintf("%s_access_token_%s", ak.cacheKeyPrefix, ak.appID)
|
||||||
|
val := ak.cache.Get(accessTokenCacheKey)
|
||||||
if val := ak.cache.Get(accessTokenCacheKey); val != nil {
|
|
||||||
if accessToken = val.(string); accessToken != "" {
|
if accessToken = val.(string); accessToken != "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 加上lock,是为了防止在并发获取token时,cache刚好失效,导致从微信服务器上获取到不同token
|
// 加上lock,是为了防止在并发获取token时,cache刚好失效,导致从微信服务器上获取到不同token
|
||||||
ak.accessTokenLock.Lock()
|
ak.accessTokenLock.Lock()
|
||||||
defer ak.accessTokenLock.Unlock()
|
defer ak.accessTokenLock.Unlock()
|
||||||
|
|
||||||
// 双检,防止重复从微信服务器获取
|
// 双检,防止重复从微信服务器获取
|
||||||
if val := ak.cache.Get(accessTokenCacheKey); val != nil {
|
val = ak.cache.Get(accessTokenCacheKey)
|
||||||
if accessToken = val.(string); accessToken != "" {
|
if accessToken = val.(string); accessToken != "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// cache失效,从微信服务器获取
|
// cache失效,从微信服务器获取
|
||||||
var resAccessToken ResAccessToken
|
var resAccessToken ResAccessToken
|
||||||
|
|||||||
@@ -90,12 +90,10 @@ host: https://qyapi.weixin.qq.com/
|
|||||||
| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | 贡献者 |
|
| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | 贡献者 |
|
||||||
|:---------:|------|:----------------------------------------| ---------- | ------------------------------- |----------|
|
|:---------:|------|:----------------------------------------| ---------- | ------------------------------- |----------|
|
||||||
| 获取子部门ID列表 | GET | /cgi-bin/department/simplelist | YES | (r *Client) DepartmentSimpleList| MARKWANG |
|
| 获取子部门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 |
|
| 获取部门成员 | GET | /cgi-bin/user/simplelist | YES | (r *Client) UserSimpleList | MARKWANG |
|
||||||
| 获取成员ID列表 | Post | /cgi-bin/user/list_id | YES | (r *Client) UserListId | MARKWANG |
|
| 获取成员ID列表 | Post | /cgi-bin/user/list_id | YES | (r *Client) UserListId | MARKWANG |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 素材管理
|
## 素材管理
|
||||||
[官方文档](https://developer.work.weixin.qq.com/document/path/91054)
|
[官方文档](https://developer.work.weixin.qq.com/document/path/91054)
|
||||||
|
|
||||||
@@ -118,14 +116,5 @@ host: https://qyapi.weixin.qq.com/
|
|||||||
| ---------------- | -------- | --------------------- | ---------- | -------------------------- | -------- |
|
| ---------------- | -------- | --------------------- | ---------- | -------------------------- | -------- |
|
||||||
| 群机器人发送消息 | POST | /cgi-bin/webhook/send | YES | (r *Client) RobotBroadcast | chcthink |
|
| 群机器人发送消息 | POST | /cgi-bin/webhook/send | YES | (r *Client) RobotBroadcast | chcthink |
|
||||||
|
|
||||||
## 打卡
|
|
||||||
|
|
||||||
[官方文档](https://developer.work.weixin.qq.com/document/path/96497)
|
|
||||||
|
|
||||||
| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | 贡献者 |
|
|
||||||
|----------| -------- | --------------------- | ---------- | -------------------------- |---------|
|
|
||||||
| 获取打卡日报数据 | POST | /cgi-bin/checkin/getcheckin_daydata | YES | (r *Client) GetDayData | Thinker |
|
|
||||||
| 获取打卡月报数据 | POST | /cgi-bin/checkin/getcheckin_monthdata | YES | (r *Client) GetMonthData | Thinker |
|
|
||||||
|
|
||||||
## 应用管理
|
## 应用管理
|
||||||
TODO
|
TODO
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tidwall/gjson"
|
|
||||||
|
|
||||||
"github.com/silenceper/wechat/v2/miniprogram/context"
|
"github.com/silenceper/wechat/v2/miniprogram/context"
|
||||||
"github.com/silenceper/wechat/v2/miniprogram/security"
|
"github.com/silenceper/wechat/v2/miniprogram/security"
|
||||||
"github.com/silenceper/wechat/v2/util"
|
"github.com/silenceper/wechat/v2/util"
|
||||||
@@ -41,25 +39,12 @@ const (
|
|||||||
EventTypeXpayGoodsDeliverNotify EventType = "xpay_goods_deliver_notify"
|
EventTypeXpayGoodsDeliverNotify EventType = "xpay_goods_deliver_notify"
|
||||||
// EventTypeXpayCoinPayNotify 代币支付推送事件
|
// EventTypeXpayCoinPayNotify 代币支付推送事件
|
||||||
EventTypeXpayCoinPayNotify EventType = "xpay_coin_pay_notify"
|
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 自动确认收货
|
||||||
ConfirmReceiveMethodAuto ConfirmReceiveMethod = 1
|
ConfirmReceiveMethodAuto ConfirmReceiveMethod = 1
|
||||||
// ConfirmReceiveMethodManual 手动确认收货
|
// ConfirmReceiveMethodManual 手动确认收货
|
||||||
ConfirmReceiveMethodManual ConfirmReceiveMethod = 2
|
ConfirmReceiveMethodManual ConfirmReceiveMethod = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// InfoTypeAcceptSubscribeMessage 接受订阅通知
|
|
||||||
InfoTypeAcceptSubscribeMessage InfoType = "accept"
|
|
||||||
// InfoTypeRejectSubscribeMessage 拒绝订阅通知
|
|
||||||
InfoTypeRejectSubscribeMessage InfoType = "reject"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PushReceiver 接收消息推送
|
// PushReceiver 接收消息推送
|
||||||
// 暂仅支付Aes加密方式
|
// 暂仅支付Aes加密方式
|
||||||
type PushReceiver struct {
|
type PushReceiver struct {
|
||||||
@@ -203,98 +188,19 @@ func (receiver *PushReceiver) getEvent(dataType string, eventType EventType, dec
|
|||||||
var pushData PushDataXpayCoinPayNotify
|
var pushData PushDataXpayCoinPayNotify
|
||||||
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
|
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
|
||||||
return &pushData, err
|
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
|
return decryptMsg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// unmarshal 解析推送的数据
|
// unmarshal 解析推送的数据
|
||||||
func (receiver *PushReceiver) unmarshal(dataType string, decryptMsg []byte, pushData interface{}) error {
|
func (receiver *PushReceiver) unmarshal(dateType string, decryptMsg []byte, pushData interface{}) error {
|
||||||
if dataType == DataTypeXML {
|
if dateType == DataTypeXML {
|
||||||
return xml.Unmarshal(decryptMsg, pushData)
|
return xml.Unmarshal(decryptMsg, pushData)
|
||||||
}
|
}
|
||||||
return json.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 接收到的数据
|
// DataReceived 接收到的数据
|
||||||
type DataReceived struct {
|
type DataReceived struct {
|
||||||
Encrypt string `json:"Encrypt" xml:"Encrypt"` // 加密的消息体
|
Encrypt string `json:"Encrypt" xml:"Encrypt"` // 加密的消息体
|
||||||
@@ -400,8 +306,8 @@ type PushDataSecVodUpload struct {
|
|||||||
type SecVodUploadEvent struct {
|
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"` // 透传上传接口中开发者设置的值。
|
SourceContext string `json:"source_context" xml:"source_context"` // 透传上传接口中开发者设置的值。
|
||||||
ErrCode int `json:"errcode" xml:"errcode"` // 错误码,上传失败时该值非
|
Errcode int `json:"errcode" xml:"errcode"` // 错误码,上传失败时该值非
|
||||||
ErrMsg string `json:"errmsg" xml:"errmsg"` // 错误提示
|
Errmsg string `json:"errmsg" xml:"errmsg"` // 错误提示
|
||||||
}
|
}
|
||||||
|
|
||||||
// PushDataSecVodAudit 短剧媒资审核状态
|
// PushDataSecVodAudit 短剧媒资审核状态
|
||||||
@@ -467,113 +373,3 @@ type CoinInfo struct {
|
|||||||
ActualPrice int64 `json:"ActualPrice" xml:"ActualPrice"` // 物品实际支付价格(单位:分)
|
ActualPrice int64 `json:"ActualPrice" xml:"ActualPrice"` // 物品实际支付价格(单位:分)
|
||||||
Attach string `json:"Attach" xml:"Attach"` // 透传信息
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
package message
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
// ErrInvalidReply 无效的回复
|
|
||||||
var ErrInvalidReply = errors.New("无效的回复信息")
|
|
||||||
|
|
||||||
// ErrUnsupportedReply 不支持的回复类型
|
|
||||||
var ErrUnsupportedReply = errors.New("不支持的回复消息")
|
|
||||||
|
|
||||||
// Reply 消息回复
|
|
||||||
type Reply struct {
|
|
||||||
MsgType MsgType
|
|
||||||
MsgData interface{}
|
|
||||||
}
|
|
||||||
@@ -282,7 +282,7 @@ type ResponseEncryptedXMLMsg struct {
|
|||||||
Nonce string `xml:"Nonce" json:"Nonce"`
|
Nonce string `xml:"Nonce" json:"Nonce"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CDATA 使用该类型,在序列化为 xml 文本时文本会被解析器忽略
|
// CDATA 使用该类型,在序列化为 xml 文本时文本会被解析器忽略
|
||||||
type CDATA string
|
type CDATA string
|
||||||
|
|
||||||
// MarshalXML 实现自己的序列化方法
|
// MarshalXML 实现自己的序列化方法
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package oauth
|
package oauth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
ctx2 "context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -74,28 +73,11 @@ type ResAccessToken struct {
|
|||||||
UnionID string `json:"unionid"`
|
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)
|
// GetUserAccessToken 通过网页授权的code 换取access_token(区别于context中的access_token)
|
||||||
func (oauth *Oauth) GetUserAccessToken(code string) (result ResAccessToken, err error) {
|
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)
|
urlStr := fmt.Sprintf(accessTokenURL, oauth.AppID, oauth.AppSecret, code)
|
||||||
var response []byte
|
var response []byte
|
||||||
response, err = util.HTTPGetContext(ctx, urlStr)
|
response, err = util.HTTPGet(urlStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -112,14 +94,9 @@ func (oauth *Oauth) GetUserAccessTokenContext(ctx ctx2.Context, code string) (re
|
|||||||
|
|
||||||
// RefreshAccessToken 刷新access_token
|
// RefreshAccessToken 刷新access_token
|
||||||
func (oauth *Oauth) RefreshAccessToken(refreshToken string) (result ResAccessToken, err error) {
|
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)
|
urlStr := fmt.Sprintf(refreshAccessTokenURL, oauth.AppID, refreshToken)
|
||||||
var response []byte
|
var response []byte
|
||||||
response, err = util.HTTPGetContext(ctx, urlStr)
|
response, err = util.HTTPGet(urlStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -136,14 +113,9 @@ func (oauth *Oauth) RefreshAccessTokenContext(ctx ctx2.Context, refreshToken str
|
|||||||
|
|
||||||
// CheckAccessToken 检验access_token是否有效
|
// CheckAccessToken 检验access_token是否有效
|
||||||
func (oauth *Oauth) CheckAccessToken(accessToken, openID string) (b bool, err error) {
|
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)
|
urlStr := fmt.Sprintf(checkAccessTokenURL, accessToken, openID)
|
||||||
var response []byte
|
var response []byte
|
||||||
response, err = util.HTTPGetContext(ctx, urlStr)
|
response, err = util.HTTPGet(urlStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -177,17 +149,12 @@ type UserInfo struct {
|
|||||||
|
|
||||||
// GetUserInfo 如果scope为 snsapi_userinfo 则可以通过此方法获取到用户基本信息
|
// GetUserInfo 如果scope为 snsapi_userinfo 则可以通过此方法获取到用户基本信息
|
||||||
func (oauth *Oauth) GetUserInfo(accessToken, openID, lang string) (result UserInfo, err error) {
|
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 == "" {
|
if lang == "" {
|
||||||
lang = "zh_CN"
|
lang = "zh_CN"
|
||||||
}
|
}
|
||||||
urlStr := fmt.Sprintf(userInfoURL, accessToken, openID, lang)
|
urlStr := fmt.Sprintf(userInfoURL, accessToken, openID, lang)
|
||||||
var response []byte
|
var response []byte
|
||||||
response, err = util.HTTPGetContext(ctx, urlStr)
|
response, err = util.HTTPGet(urlStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
60
openplatform/miniprogram/auth/auth.go
Normal file
60
openplatform/miniprogram/auth/auth.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
stdContext "context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/silenceper/wechat/v2/openplatform/context"
|
||||||
|
"github.com/silenceper/wechat/v2/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
code2SessionURL = "https://api.weixin.qq.com/sns/component/jscode2session?appid=%s&js_code=%s&grant_type=authorization_code&component_appid=%s&component_access_token=%s"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Auth 登录/用户信息
|
||||||
|
type Auth struct {
|
||||||
|
*context.Context
|
||||||
|
authorizerAppID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAuth new auth (授权方appID)
|
||||||
|
func NewAuth(ctx *context.Context, appID string) *Auth {
|
||||||
|
return &Auth{ctx, appID}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResCode2Session 登录凭证校验的返回结果
|
||||||
|
type ResCode2Session struct {
|
||||||
|
util.CommonError
|
||||||
|
OpenID string `json:"openid"` // 用户唯一标识
|
||||||
|
SessionKey string `json:"session_key"` // 会话密钥
|
||||||
|
UnionID string `json:"unionid"` // 用户在开放平台的唯一标识符,在满足UnionID下发条件的情况下会返回
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code2Session 登录凭证校验。
|
||||||
|
func (auth *Auth) Code2Session(jsCode string) (result ResCode2Session, err error) {
|
||||||
|
return auth.Code2SessionContext(stdContext.Background(), jsCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code2SessionContext 登录凭证校验。
|
||||||
|
func (auth *Auth) Code2SessionContext(ctx stdContext.Context, jsCode string) (result ResCode2Session, err error) {
|
||||||
|
var response []byte
|
||||||
|
var componentAccessToken string
|
||||||
|
componentAccessToken, err = auth.GetComponentAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parse := fmt.Sprintf(code2SessionURL, auth.authorizerAppID, jsCode, auth.Context.AppID, componentAccessToken)
|
||||||
|
if response, err = util.HTTPGetContext(ctx, parse); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = json.Unmarshal(response, &result); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if result.ErrCode != 0 {
|
||||||
|
err = fmt.Errorf("Code2Session error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
miniContext "github.com/silenceper/wechat/v2/miniprogram/context"
|
miniContext "github.com/silenceper/wechat/v2/miniprogram/context"
|
||||||
"github.com/silenceper/wechat/v2/miniprogram/urllink"
|
"github.com/silenceper/wechat/v2/miniprogram/urllink"
|
||||||
openContext "github.com/silenceper/wechat/v2/openplatform/context"
|
openContext "github.com/silenceper/wechat/v2/openplatform/context"
|
||||||
|
"github.com/silenceper/wechat/v2/openplatform/miniprogram/auth"
|
||||||
"github.com/silenceper/wechat/v2/openplatform/miniprogram/basic"
|
"github.com/silenceper/wechat/v2/openplatform/miniprogram/basic"
|
||||||
"github.com/silenceper/wechat/v2/openplatform/miniprogram/component"
|
"github.com/silenceper/wechat/v2/openplatform/miniprogram/component"
|
||||||
)
|
)
|
||||||
@@ -72,6 +73,11 @@ func (miniProgram *MiniProgram) GetURLLink() *urllink.URLLink {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAuth 登录/用户信息相关接口
|
||||||
|
func (miniProgram *MiniProgram) GetAuth() *auth.Auth {
|
||||||
|
return auth.NewAuth(miniProgram.openContext, miniProgram.AppID)
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultAuthrAccessToken 默认获取授权ak的方法
|
// DefaultAuthrAccessToken 默认获取授权ak的方法
|
||||||
type DefaultAuthrAccessToken struct {
|
type DefaultAuthrAccessToken struct {
|
||||||
opCtx *openContext.Context
|
opCtx *openContext.Context
|
||||||
|
|||||||
28
util/http.go
28
util/http.go
@@ -17,16 +17,6 @@ import (
|
|||||||
"golang.org/x/crypto/pkcs12"
|
"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 请求
|
// HTTPGet get 请求
|
||||||
func HTTPGet(uri string) ([]byte, error) {
|
func HTTPGet(uri string) ([]byte, error) {
|
||||||
return HTTPGetContext(context.Background(), uri)
|
return HTTPGetContext(context.Background(), uri)
|
||||||
@@ -34,9 +24,6 @@ func HTTPGet(uri string) ([]byte, error) {
|
|||||||
|
|
||||||
// HTTPGetContext get 请求
|
// HTTPGetContext get 请求
|
||||||
func HTTPGetContext(ctx context.Context, uri string) ([]byte, error) {
|
func HTTPGetContext(ctx context.Context, uri string) ([]byte, error) {
|
||||||
if uriModifier != nil {
|
|
||||||
uri = uriModifier(uri)
|
|
||||||
}
|
|
||||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
|
request, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -60,9 +47,6 @@ func HTTPPost(uri string, data string) ([]byte, error) {
|
|||||||
|
|
||||||
// HTTPPostContext post 请求
|
// HTTPPostContext post 请求
|
||||||
func HTTPPostContext(ctx context.Context, uri string, data []byte, header map[string]string) ([]byte, error) {
|
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)
|
body := bytes.NewBuffer(data)
|
||||||
request, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, body)
|
request, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -87,9 +71,6 @@ func HTTPPostContext(ctx context.Context, uri string, data []byte, header map[st
|
|||||||
|
|
||||||
// PostJSONContext post json 数据请求
|
// PostJSONContext post json 数据请求
|
||||||
func PostJSONContext(ctx context.Context, uri string, obj interface{}) ([]byte, error) {
|
func PostJSONContext(ctx context.Context, uri string, obj interface{}) ([]byte, error) {
|
||||||
if uriModifier != nil {
|
|
||||||
uri = uriModifier(uri)
|
|
||||||
}
|
|
||||||
jsonBuf := new(bytes.Buffer)
|
jsonBuf := new(bytes.Buffer)
|
||||||
enc := json.NewEncoder(jsonBuf)
|
enc := json.NewEncoder(jsonBuf)
|
||||||
enc.SetEscapeHTML(false)
|
enc.SetEscapeHTML(false)
|
||||||
@@ -165,9 +146,6 @@ type MultipartFormField struct {
|
|||||||
|
|
||||||
// PostMultipartForm 上传文件或其他多个字段
|
// PostMultipartForm 上传文件或其他多个字段
|
||||||
func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte, err error) {
|
func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte, err error) {
|
||||||
if uriModifier != nil {
|
|
||||||
uri = uriModifier(uri)
|
|
||||||
}
|
|
||||||
bodyBuf := &bytes.Buffer{}
|
bodyBuf := &bytes.Buffer{}
|
||||||
bodyWriter := multipart.NewWriter(bodyBuf)
|
bodyWriter := multipart.NewWriter(bodyBuf)
|
||||||
|
|
||||||
@@ -220,9 +198,6 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte
|
|||||||
|
|
||||||
// PostXML perform a HTTP/POST request with XML body
|
// PostXML perform a HTTP/POST request with XML body
|
||||||
func PostXML(uri string, obj interface{}) ([]byte, error) {
|
func PostXML(uri string, obj interface{}) ([]byte, error) {
|
||||||
if uriModifier != nil {
|
|
||||||
uri = uriModifier(uri)
|
|
||||||
}
|
|
||||||
xmlData, err := xml.Marshal(obj)
|
xmlData, err := xml.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -284,9 +259,6 @@ func pkcs12ToPem(p12 []byte, password string) tls.Certificate {
|
|||||||
|
|
||||||
// PostXMLWithTLS perform a HTTP/POST request with XML body and TLS
|
// PostXMLWithTLS perform a HTTP/POST request with XML body and TLS
|
||||||
func PostXMLWithTLS(uri string, obj interface{}, ca, key string) ([]byte, error) {
|
func PostXMLWithTLS(uri string, obj interface{}, ca, key string) ([]byte, error) {
|
||||||
if uriModifier != nil {
|
|
||||||
uri = uriModifier(uri)
|
|
||||||
}
|
|
||||||
xmlData, err := xml.Marshal(obj)
|
xmlData, err := xml.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ const (
|
|||||||
departmentSimpleListURL = "https://qyapi.weixin.qq.com/cgi-bin/department/simplelist?access_token=%s&id=%d"
|
departmentSimpleListURL = "https://qyapi.weixin.qq.com/cgi-bin/department/simplelist?access_token=%s&id=%d"
|
||||||
// departmentListURL 获取部门列表
|
// 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=ACCESS_TOKEN&id=ID
|
||||||
departmentGetURL = "https://qyapi.weixin.qq.com/cgi-bin/department/get?access_token=%s&id=%d"
|
departmentGetURL = "https://qyapi.weixin.qq.com/cgi-bin/department/get?access_token=%s&id=%d"
|
||||||
)
|
)
|
||||||
@@ -107,31 +106,13 @@ func (r *Client) DepartmentSimpleList(departmentID int) ([]*DepartmentID, error)
|
|||||||
// DepartmentList 获取部门列表
|
// DepartmentList 获取部门列表
|
||||||
// @desc https://developer.work.weixin.qq.com/document/path/90208
|
// @desc https://developer.work.weixin.qq.com/document/path/90208
|
||||||
func (r *Client) DepartmentList() ([]*Department, error) {
|
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
|
||||||
accessToken, err := r.GetAccessToken()
|
accessToken, err := r.GetAccessToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if departmentID > 0 {
|
|
||||||
formatURL = fmt.Sprintf(departmentListByIDURL, accessToken, departmentID)
|
|
||||||
} else {
|
|
||||||
formatURL = fmt.Sprintf(departmentListURL, accessToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发起http请求
|
// 发起http请求
|
||||||
response, err := util.HTTPGet(formatURL)
|
response, err := util.HTTPGet(fmt.Sprintf(departmentListURL, accessToken))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
67
work/checkin/checkin.go
Normal file
67
work/checkin/checkin.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package checkin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/silenceper/wechat/v2/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// getCheckinDataURL 获取打卡记录数据
|
||||||
|
getCheckinDataURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata?access_token=%s"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// GetCheckinDataRequest 获取打卡记录数据请求
|
||||||
|
GetCheckinDataRequest struct {
|
||||||
|
OpenCheckinDataType int64 `json:"opencheckindatatype"`
|
||||||
|
StartTime int64 `json:"starttime"`
|
||||||
|
EndTime int64 `json:"endtime"`
|
||||||
|
UserIDList []string `json:"useridlist"`
|
||||||
|
}
|
||||||
|
// GetCheckinDataResponse 获取打卡记录数据响应
|
||||||
|
GetCheckinDataResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
CheckinData []*GetCheckinDataItem `json:"checkindata"`
|
||||||
|
}
|
||||||
|
// GetCheckinDataItem 打卡记录数据
|
||||||
|
GetCheckinDataItem struct {
|
||||||
|
UserID string `json:"userid"`
|
||||||
|
GroupName string `json:"groupname"`
|
||||||
|
CheckinType string `json:"checkin_type"`
|
||||||
|
ExceptionType string `json:"exception_type"`
|
||||||
|
CheckinTime int64 `json:"checkin_time"`
|
||||||
|
LocationTitle string `json:"location_title"`
|
||||||
|
LocationDetail string `json:"location_detail"`
|
||||||
|
WifiName string `json:"wifiname"`
|
||||||
|
Notes string `json:"notes"`
|
||||||
|
WifiMac string `json:"wifimac"`
|
||||||
|
MediaIDs []string `json:"mediaids"`
|
||||||
|
SchCheckinTime int64 `json:"sch_checkin_time"`
|
||||||
|
GroupID int64 `json:"groupid"`
|
||||||
|
ScheduleID int64 `json:"schedule_id"`
|
||||||
|
TimelineID int64 `json:"timeline_id"`
|
||||||
|
Lat int64 `json:"lat,omitempty"`
|
||||||
|
Lng int64 `json:"lng,omitempty"`
|
||||||
|
DeviceID string `json:"deviceid,omitempty"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetCheckinData 获取打卡记录数据
|
||||||
|
// @see https://developer.work.weixin.qq.com/document/path/90262
|
||||||
|
func (r *Client) GetCheckinData(req *GetCheckinDataRequest) (*GetCheckinDataResponse, 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(getCheckinDataURL, accessToken), req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &GetCheckinDataResponse{}
|
||||||
|
err = util.DecodeWithError(response, result, "GetCheckinData")
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
@@ -1,660 +0,0 @@
|
|||||||
package checkin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/silenceper/wechat/v2/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// getCheckinDataURL 获取打卡记录数据
|
|
||||||
getCheckinDataURL = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata?access_token=%s"
|
|
||||||
// getDayDataURL 获取打卡日报数据
|
|
||||||
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 (
|
|
||||||
// GetCheckinDataRequest 获取打卡记录数据请求
|
|
||||||
GetCheckinDataRequest struct {
|
|
||||||
OpenCheckinDataType int64 `json:"opencheckindatatype"`
|
|
||||||
StartTime int64 `json:"starttime"`
|
|
||||||
EndTime int64 `json:"endtime"`
|
|
||||||
UserIDList []string `json:"useridlist"`
|
|
||||||
}
|
|
||||||
// GetCheckinDataResponse 获取打卡记录数据响应
|
|
||||||
GetCheckinDataResponse struct {
|
|
||||||
util.CommonError
|
|
||||||
CheckinData []*GetCheckinDataItem `json:"checkindata"`
|
|
||||||
}
|
|
||||||
// GetCheckinDataItem 打卡记录数据
|
|
||||||
GetCheckinDataItem struct {
|
|
||||||
UserID string `json:"userid"`
|
|
||||||
GroupName string `json:"groupname"`
|
|
||||||
CheckinType string `json:"checkin_type"`
|
|
||||||
ExceptionType string `json:"exception_type"`
|
|
||||||
CheckinTime int64 `json:"checkin_time"`
|
|
||||||
LocationTitle string `json:"location_title"`
|
|
||||||
LocationDetail string `json:"location_detail"`
|
|
||||||
WifiName string `json:"wifiname"`
|
|
||||||
Notes string `json:"notes"`
|
|
||||||
WifiMac string `json:"wifimac"`
|
|
||||||
MediaIDs []string `json:"mediaids"`
|
|
||||||
SchCheckinTime int64 `json:"sch_checkin_time"`
|
|
||||||
GroupID int64 `json:"groupid"`
|
|
||||||
ScheduleID int64 `json:"schedule_id"`
|
|
||||||
TimelineID int64 `json:"timeline_id"`
|
|
||||||
Lat int64 `json:"lat,omitempty"`
|
|
||||||
Lng int64 `json:"lng,omitempty"`
|
|
||||||
DeviceID string `json:"deviceid,omitempty"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetCheckinData 获取打卡记录数据
|
|
||||||
// @see https://developer.work.weixin.qq.com/document/path/90262
|
|
||||||
func (r *Client) GetCheckinData(req *GetCheckinDataRequest) (*GetCheckinDataResponse, 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(getCheckinDataURL, accessToken), req); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := &GetCheckinDataResponse{}
|
|
||||||
err = util.DecodeWithError(response, result, "GetCheckinData")
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type (
|
|
||||||
// GetDayDataResponse 获取打卡日报数据
|
|
||||||
GetDayDataResponse struct {
|
|
||||||
util.CommonError
|
|
||||||
Datas []DayDataItem `json:"datas"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DayDataItem 日报
|
|
||||||
DayDataItem struct {
|
|
||||||
BaseInfo DayBaseInfo `json:"base_info"`
|
|
||||||
SummaryInfo DaySummaryInfo `json:"summary_info"`
|
|
||||||
HolidayInfos []HolidayInfo `json:"holiday_infos"`
|
|
||||||
ExceptionInfos []ExceptionInfo `json:"exception_infos"`
|
|
||||||
OtInfo OtInfo `json:"ot_info"`
|
|
||||||
SpItems []SpItem `json:"sp_items"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DayBaseInfo 基础信息
|
|
||||||
DayBaseInfo struct {
|
|
||||||
Date int64 `json:"date"`
|
|
||||||
RecordType int64 `json:"record_type"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
NameEx string `json:"name_ex"`
|
|
||||||
DepartsName string `json:"departs_name"`
|
|
||||||
AcctID string `json:"acctid"`
|
|
||||||
DayType int64 `json:"day_type"`
|
|
||||||
RuleInfo DayRuleInfo `json:"rule_info"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DayCheckInTime 当日打卡时间
|
|
||||||
DayCheckInTime struct {
|
|
||||||
WorkSec int64 `json:"work_sec"`
|
|
||||||
OffWorkSec int64 `json:"off_work_sec"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DayRuleInfo 打卡人员所属规则信息
|
|
||||||
DayRuleInfo struct {
|
|
||||||
GroupID int64 `json:"groupid"`
|
|
||||||
GroupName string `json:"groupname"`
|
|
||||||
ScheduleID int64 `json:"scheduleid"`
|
|
||||||
ScheduleName string `json:"schedulename"`
|
|
||||||
CheckInTimes []DayCheckInTime `json:"checkintime"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaySummaryInfo 汇总信息
|
|
||||||
DaySummaryInfo struct {
|
|
||||||
CheckinCount int64 `json:"checkin_count"`
|
|
||||||
RegularWorkSec int64 `json:"regular_work_sec"`
|
|
||||||
StandardWorkSec int64 `json:"standard_work_sec"`
|
|
||||||
EarliestTime int64 `json:"earliest_time"`
|
|
||||||
LastestTime int64 `json:"lastest_time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// HolidayInfo 假勤相关信息
|
|
||||||
HolidayInfo struct {
|
|
||||||
SpNumber string `json:"sp_number"`
|
|
||||||
SpTitle SpTitle `json:"sp_title"`
|
|
||||||
SpDescription SpDescription `json:"sp_description"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SpTitle 假勤信息摘要-标题信息
|
|
||||||
SpTitle struct {
|
|
||||||
Data []SpData `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SpDescription 假勤信息摘要-描述信息
|
|
||||||
SpDescription struct {
|
|
||||||
Data []SpData `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SpData 假勤信息(多种语言描述,目前只有中文一种)
|
|
||||||
SpData struct {
|
|
||||||
Lang string `json:"lang"`
|
|
||||||
Text string `json:"text"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SpItem 假勤统计信息
|
|
||||||
SpItem struct {
|
|
||||||
Count int64 `json:"count"`
|
|
||||||
Duration int64 `json:"duration"`
|
|
||||||
TimeType int64 `json:"time_type"`
|
|
||||||
Type int64 `json:"type"`
|
|
||||||
VacationID int64 `json:"vacation_id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExceptionInfo 校准状态信息
|
|
||||||
ExceptionInfo struct {
|
|
||||||
Count int64 `json:"count"`
|
|
||||||
Duration int64 `json:"duration"`
|
|
||||||
Exception int64 `json:"exception"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// OtInfo 加班信息
|
|
||||||
OtInfo struct {
|
|
||||||
OtStatus int64 `json:"ot_status"`
|
|
||||||
OtDuration int64 `json:"ot_duration"`
|
|
||||||
ExceptionDuration []uint64 `json:"exception_duration"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetDayData 获取打卡日报数据
|
|
||||||
// @see https://developer.work.weixin.qq.com/document/path/96498
|
|
||||||
func (r *Client) GetDayData(req *GetCheckinDataRequest) (result *GetDayDataResponse, err error) {
|
|
||||||
var (
|
|
||||||
response []byte
|
|
||||||
accessToken string
|
|
||||||
)
|
|
||||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if response, err = util.PostJSON(fmt.Sprintf(getDayDataURL, accessToken), req); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
result = new(GetDayDataResponse)
|
|
||||||
err = util.DecodeWithError(response, result, "GetDayData")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type (
|
|
||||||
// GetMonthDataResponse 获取打卡月报数据
|
|
||||||
GetMonthDataResponse struct {
|
|
||||||
util.CommonError
|
|
||||||
Datas []MonthDataItem `json:"datas"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MonthDataItem 月报数据
|
|
||||||
MonthDataItem struct {
|
|
||||||
BaseInfo MonthBaseInfo `json:"base_info"`
|
|
||||||
SummaryInfo MonthSummaryInfo `json:"summary_info"`
|
|
||||||
ExceptionInfos []ExceptionInfo `json:"exception_infos"`
|
|
||||||
SpItems []SpItem `json:"sp_items"`
|
|
||||||
OverWorkInfo OverWorkInfo `json:"overwork_info"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MonthBaseInfo 基础信息
|
|
||||||
MonthBaseInfo struct {
|
|
||||||
RecordType int64 `json:"record_type"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
NameEx string `json:"name_ex"`
|
|
||||||
DepartsName string `json:"departs_name"`
|
|
||||||
AcctID string `json:"acctid"`
|
|
||||||
RuleInfo MonthRuleInfo `json:"rule_info"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MonthRuleInfo 打卡人员所属规则信息
|
|
||||||
MonthRuleInfo struct {
|
|
||||||
GroupID int64 `json:"groupid"`
|
|
||||||
GroupName string `json:"groupname"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MonthSummaryInfo 汇总信息
|
|
||||||
MonthSummaryInfo struct {
|
|
||||||
WorkDays int64 `json:"work_days"`
|
|
||||||
ExceptDays int64 `json:"except_days"`
|
|
||||||
RegularDays int64 `json:"regular_days"`
|
|
||||||
RegularWorkSec int64 `json:"regular_work_sec"`
|
|
||||||
StandardWorkSec int64 `json:"standard_work_sec"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// OverWorkInfo 加班情况
|
|
||||||
OverWorkInfo struct {
|
|
||||||
WorkdayOverSec int64 `json:"workday_over_sec"`
|
|
||||||
HolidayOverSec int64 `json:"holidays_over_sec"`
|
|
||||||
RestDayOverSec int64 `json:"restdays_over_sec"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetMonthData 获取打卡月报数据
|
|
||||||
// @see https://developer.work.weixin.qq.com/document/path/96499
|
|
||||||
func (r *Client) GetMonthData(req *GetCheckinDataRequest) (result *GetMonthDataResponse, err error) {
|
|
||||||
var (
|
|
||||||
response []byte
|
|
||||||
accessToken string
|
|
||||||
)
|
|
||||||
if accessToken, err = r.GetAccessToken(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if response, err = util.PostJSON(fmt.Sprintf(getMonthDataURL, accessToken), req); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
result = new(GetMonthDataResponse)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -38,23 +38,8 @@ type AddMsgTemplateRequest struct {
|
|||||||
Sender string `json:"sender,omitempty"`
|
Sender string `json:"sender,omitempty"`
|
||||||
Text MsgText `json:"text"`
|
Text MsgText `json:"text"`
|
||||||
Attachments []*Attachment `json:"attachments"`
|
Attachments []*Attachment `json:"attachments"`
|
||||||
AllowSelect bool `json:"allow_select,omitempty"`
|
|
||||||
ChatIDList []string `json:"chat_id_list,omitempty"`
|
|
||||||
TagFilter TagFilter `json:"tag_filter,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
|
||||||
// TagFilter 标签过滤
|
|
||||||
TagFilter struct {
|
|
||||||
GroupList []TagGroupList `json:"group_list"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TagGroupList 标签组
|
|
||||||
TagGroupList struct {
|
|
||||||
TagList []string `json:"tag_list"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// MsgText 文本消息
|
// MsgText 文本消息
|
||||||
type MsgText struct {
|
type MsgText struct {
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
@@ -288,13 +273,13 @@ func (r *Client) SendWelcomeMsg(req *SendWelcomeMsgRequest) error {
|
|||||||
// AddGroupWelcomeTemplateRequest 添加入群欢迎语素材请求
|
// AddGroupWelcomeTemplateRequest 添加入群欢迎语素材请求
|
||||||
type AddGroupWelcomeTemplateRequest struct {
|
type AddGroupWelcomeTemplateRequest struct {
|
||||||
Text MsgText `json:"text"`
|
Text MsgText `json:"text"`
|
||||||
Image *AttachmentImg `json:"image,omitempty"`
|
Image AttachmentImg `json:"image"`
|
||||||
Link *AttachmentLink `json:"link,omitempty"`
|
Link AttachmentLink `json:"link"`
|
||||||
MiniProgram *AttachmentMiniProgram `json:"miniprogram,omitempty"`
|
MiniProgram AttachmentMiniProgram `json:"miniprogram"`
|
||||||
File *AttachmentFile `json:"file,omitempty"`
|
File AttachmentFile `json:"file"`
|
||||||
Video *AttachmentVideo `json:"video,omitempty"`
|
Video AttachmentVideo `json:"video"`
|
||||||
AgentID int `json:"agentid,omitempty"`
|
AgentID int `json:"agentid"`
|
||||||
Notify int `json:"notify,omitempty"`
|
Notify int `json:"notify"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddGroupWelcomeTemplateResponse 添加入群欢迎语素材响应
|
// AddGroupWelcomeTemplateResponse 添加入群欢迎语素材响应
|
||||||
@@ -326,11 +311,11 @@ func (r *Client) AddGroupWelcomeTemplate(req *AddGroupWelcomeTemplateRequest) (*
|
|||||||
type EditGroupWelcomeTemplateRequest struct {
|
type EditGroupWelcomeTemplateRequest struct {
|
||||||
TemplateID string `json:"template_id"`
|
TemplateID string `json:"template_id"`
|
||||||
Text MsgText `json:"text"`
|
Text MsgText `json:"text"`
|
||||||
Image *AttachmentImg `json:"image"`
|
Image AttachmentImg `json:"image"`
|
||||||
Link *AttachmentLink `json:"link"`
|
Link AttachmentLink `json:"link"`
|
||||||
MiniProgram *AttachmentMiniProgram `json:"miniprogram"`
|
MiniProgram AttachmentMiniProgram `json:"miniprogram"`
|
||||||
File *AttachmentFile `json:"file"`
|
File AttachmentFile `json:"file"`
|
||||||
Video *AttachmentVideo `json:"video"`
|
Video AttachmentVideo `json:"video"`
|
||||||
AgentID int `json:"agentid"`
|
AgentID int `json:"agentid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,11 +351,11 @@ type GetGroupWelcomeTemplateRequest struct {
|
|||||||
type GetGroupWelcomeTemplateResponse struct {
|
type GetGroupWelcomeTemplateResponse struct {
|
||||||
util.CommonError
|
util.CommonError
|
||||||
Text MsgText `json:"text"`
|
Text MsgText `json:"text"`
|
||||||
Image AttachmentImg `json:"image,omitempty"`
|
Image AttachmentImg `json:"image"`
|
||||||
Link AttachmentLink `json:"link,omitempty"`
|
Link AttachmentLink `json:"link"`
|
||||||
MiniProgram AttachmentMiniProgram `json:"miniprogram,omitempty"`
|
MiniProgram AttachmentMiniProgram `json:"miniprogram"`
|
||||||
File AttachmentFile `json:"file,omitempty"`
|
File AttachmentFile `json:"file"`
|
||||||
Video AttachmentVideo `json:"video,omitempty"`
|
Video AttachmentVideo `json:"video"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGroupWelcomeTemplate 获取入群欢迎语素材
|
// GetGroupWelcomeTemplate 获取入群欢迎语素材
|
||||||
|
|||||||
Reference in New Issue
Block a user