From 182339c00f103ce670b7ff467b2f7d41bea14ead Mon Sep 17 00:00:00 2001 From: bear <18819259245@163.com> Date: Wed, 27 Apr 2022 23:50:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BC=81=E4=B8=9A=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=A4=96=E9=83=A8=E8=81=94=E7=B3=BB=E9=83=A8=E5=88=86?= =?UTF-8?q?=E7=9A=84=20sdk=20(#562)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- work/externalcontact/README.md | 3 + work/externalcontact/client.go | 17 +++ work/externalcontact/external_user.go | 177 ++++++++++++++++++++++++ work/externalcontact/follow_user.go | 39 ++++++ work/externalcontact/tag.go | 191 ++++++++++++++++++++++++++ work/work.go | 6 + 6 files changed, 433 insertions(+) create mode 100644 work/externalcontact/README.md create mode 100644 work/externalcontact/client.go create mode 100644 work/externalcontact/external_user.go create mode 100644 work/externalcontact/follow_user.go create mode 100644 work/externalcontact/tag.go diff --git a/work/externalcontact/README.md b/work/externalcontact/README.md new file mode 100644 index 0000000..f0a1e64 --- /dev/null +++ b/work/externalcontact/README.md @@ -0,0 +1,3 @@ +### 企业微信 客户联系部分 + +相关文档正在梳理中... \ No newline at end of file diff --git a/work/externalcontact/client.go b/work/externalcontact/client.go new file mode 100644 index 0000000..6399f4d --- /dev/null +++ b/work/externalcontact/client.go @@ -0,0 +1,17 @@ +package externalcontact + +import ( + "github.com/silenceper/wechat/v2/work/context" +) + +// Client 外部联系接口实例 +type Client struct { + *context.Context +} + +// NewClient 初始化实例 +func NewClient(ctx *context.Context) *Client { + return &Client{ + ctx, + } +} diff --git a/work/externalcontact/external_user.go b/work/externalcontact/external_user.go new file mode 100644 index 0000000..80c8c8f --- /dev/null +++ b/work/externalcontact/external_user.go @@ -0,0 +1,177 @@ +package externalcontact + +import ( + "encoding/json" + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + // FetchExternalContactUserListURL 获取客户列表 + FetchExternalContactUserListURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/list" + // FetchExternalContactUserDetailURL 获取客户详情 + FetchExternalContactUserDetailURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get" + // FetchBatchExternalContactUserDetailURL 批量获取客户详情 + FetchBatchExternalContactUserDetailURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/batch/get_by_user" + // UpdateUserRemarkURL 更新客户备注信息 + UpdateUserRemarkURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/remark" +) + +// ExternalUserListResponse 外部联系人列表响应 +type ExternalUserListResponse struct { + util.CommonError + ExternalUserID []string `json:"external_userid"` +} + +// GetExternalUserList 获取客户列表 +// @see https://developer.work.weixin.qq.com/document/path/92113 +func (r *Client) GetExternalUserList(userID string) ([]string, error) { + var accessToken string + accessToken, err := r.GetAccessToken() + if err != nil { + return nil, err + } + var response []byte + response, err = util.HTTPGet(fmt.Sprintf("%s?access_token=%v&userid=%v", FetchExternalContactUserListURL, accessToken, userID)) + if err != nil { + return nil, err + } + var result ExternalUserListResponse + err = util.DecodeWithError(response, &result, "GetExternalUserList") + if err != nil { + return nil, err + } + return result.ExternalUserID, nil +} + +// ExternalUserDetailResponse 外部联系人详情响应 +type ExternalUserDetailResponse struct { + util.CommonError + ExternalUser +} + +// ExternalUser 外部联系人 +type ExternalUser struct { + ExternalUserID string `json:"external_userid"` + Name string `json:"name"` + Avatar string `json:"avatar"` + Type int64 `json:"type"` + Gender int64 `json:"gender"` + UnionID string `json:"unionid"` + Position string `json:"position"` + CorpName string `json:"corp_name"` + CorpFullName string `json:"corp_full_name"` + ExternalProfile string `json:"external_profile"` + FollowUser []FollowUser `json:"follow_user"` + NextCursor string `json:"next_cursor"` +} + +// FollowUser 跟进用户(指企业内部用户) +type FollowUser struct { + UserID string `json:"userid"` + Remark string `json:"remark"` + Description string `json:"description"` + CreateTime string `json:"create_time"` + Tags []Tag `json:"tags"` + RemarkCorpName string `json:"remark_corp_name"` + RemarkMobiles []string `json:"remark_mobiles"` + OperUserID string `json:"oper_userid"` + AddWay int64 `json:"add_way"` + WeChatChannels WechatChannel `json:"wechat_channels"` + State string `json:"state"` +} + +// Tag 已绑定在外部联系人的标签 +type Tag struct { + GroupName string `json:"group_name"` + TagName string `json:"tag_name"` + Type int64 `json:"type"` + TagID string `json:"tag_id"` +} + +// WechatChannel 视频号添加的场景 +type WechatChannel struct { + NickName string `json:"nickname"` + Source string `json:"source"` +} + +// GetExternalUserDetail 获取外部联系人详情 +func (r *Client) GetExternalUserDetail(externalUserID string, nextCursor ...string) (*ExternalUser, error) { + var accessToken string + accessToken, err := r.GetAccessToken() + if err != nil { + return nil, err + } + var response []byte + response, err = util.HTTPGet(fmt.Sprintf("%s?access_token=%v&external_userid=%v&cursor=%v", FetchExternalContactUserDetailURL, accessToken, externalUserID, nextCursor)) + if err != nil { + return nil, err + } + var result ExternalUserDetailResponse + err = util.DecodeWithError(response, &result, "get_external_user_detail") + if err != nil { + return nil, err + } + return &result.ExternalUser, nil +} + +// BatchGetExternalUserDetailsRequest 批量获取外部联系人详情请求 +type BatchGetExternalUserDetailsRequest struct { + UserIDList []string `json:"userid_list"` + Cursor string `json:"cursor"` +} + +// ExternalUserDetailListResponse 批量获取外部联系人详情响应 +type ExternalUserDetailListResponse struct { + util.CommonError + ExternalContactList []ExternalUser `json:"external_contact_list"` +} + +// BatchGetExternalUserDetails 批量获取外部联系人详情 +func (r *Client) BatchGetExternalUserDetails(request BatchGetExternalUserDetailsRequest) ([]ExternalUser, error) { + var accessToken string + accessToken, err := r.GetAccessToken() + if err != nil { + return nil, err + } + var response []byte + jsonData, _ := json.Marshal(request) + response, err = util.HTTPPost(fmt.Sprintf("%s?access_token=%v", FetchBatchExternalContactUserDetailURL, accessToken), string(jsonData)) + if err != nil { + return nil, err + } + var result ExternalUserDetailListResponse + err = util.DecodeWithError(response, &result, "BatchGetExternalUserDetails") + if err != nil { + return nil, err + } + return result.ExternalContactList, nil +} + +// UpdateUserRemarkRequest 修改客户备注信息请求体 +type UpdateUserRemarkRequest struct { + UserID string `json:"userid"` + ExternalUserID string `json:"external_userid"` + Remark string `json:"remark"` + Description string `json:"description"` + RemarkCompany string `json:"remark_company"` + RemarkMobiles []string `json:"remark_mobiles"` + RemarkPicMediaid string `json:"remark_pic_mediaid"` +} + +// UpdateUserRemark 修改客户备注信息 +func (r *Client) UpdateUserRemark(request UpdateUserRemarkRequest) error { + var accessToken string + accessToken, err := r.GetAccessToken() + if err != nil { + return err + } + var response []byte + jsonData, _ := json.Marshal(request) + response, err = util.HTTPPost(fmt.Sprintf("%s?access_token=%v", UpdateUserRemarkURL, accessToken), string(jsonData)) + if err != nil { + return err + } + return util.DecodeWithCommonError(response, "UpdateUserRemark") +} diff --git a/work/externalcontact/follow_user.go b/work/externalcontact/follow_user.go new file mode 100644 index 0000000..64bbd2a --- /dev/null +++ b/work/externalcontact/follow_user.go @@ -0,0 +1,39 @@ +package externalcontact + +import ( + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + // FetchFollowUserListURL 获取配置了客户联系功能的成员列表 + FetchFollowUserListURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_follow_user_list" +) + +// followerUserResponse 客户联系功能的成员列表响应 +type followerUserResponse struct { + util.CommonError + FollowUser []string `json:"follow_user"` +} + +//GetFollowUserList 获取配置了客户联系功能的成员列表 +//@see https://developer.work.weixin.qq.com/document/path/92571 +func (r *Client) GetFollowUserList() ([]string, error) { + var accessToken string + accessToken, err := r.GetAccessToken() + if err != nil { + return nil, err + } + var response []byte + response, err = util.HTTPGet(fmt.Sprintf("%s?access_token=%s", FetchFollowUserListURL, accessToken)) + if err != nil { + return nil, err + } + var result followerUserResponse + err = util.DecodeWithError(response, &result, "GetFollowUserList") + if err != nil { + return nil, err + } + return result.FollowUser, nil +} diff --git a/work/externalcontact/tag.go b/work/externalcontact/tag.go new file mode 100644 index 0000000..01efdd5 --- /dev/null +++ b/work/externalcontact/tag.go @@ -0,0 +1,191 @@ +package externalcontact + +import ( + "encoding/json" + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + // GetCropTagURL 获取标签列表 + GetCropTagURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_corp_tag_list" + // AddCropTagURL 添加标签 + AddCropTagURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_corp_tag" + // EditCropTagURL 修改标签 + EditCropTagURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/edit_corp_tag" + // DelCropTagURL 删除标签 + DelCropTagURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/del_corp_tag" + // MarkCropTagURL 为客户打上、删除标签 + MarkCropTagURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/mark_tag" +) + +// GetCropTagRequest 获取企业标签请求 +type GetCropTagRequest struct { + TagID []string `json:"tag_id"` + GroupID []string `json:"group_id"` +} + +// GetCropTagListResponse 获取企业标签列表响应 +type GetCropTagListResponse struct { + util.CommonError + TagGroup []TagGroup `json:"tag_group"` +} + +// TagGroup 企业标签组 +type TagGroup struct { + GroupID string `json:"group_id"` + GroupName string `json:"group_name"` + CreateTime string `json:"create_time"` + GroupOrder int `json:"group_order"` + Deleted bool `json:"deleted"` + Tag []TagGroupTagItem `json:"tag"` +} + +// TagGroupTagItem 企业标签内的子项 +type TagGroupTagItem struct { + ID string `json:"id"` + Name string `json:"name"` + CreateTime int `json:"create_time"` + Order int `json:"order"` + Deleted bool `json:"deleted"` +} + +// GetCropTagList 获取企业标签库 +// @see https://developer.work.weixin.qq.com/document/path/92117 +func (r *Client) GetCropTagList(req GetCropTagRequest) ([]TagGroup, error) { + var accessToken string + accessToken, err := r.GetAccessToken() + if err != nil { + return nil, err + } + var response []byte + jsonData, _ := json.Marshal(req) + response, err = util.HTTPPost(fmt.Sprintf("%s?access_token=%v", GetCropTagURL, accessToken), string(jsonData)) + if err != nil { + return nil, err + } + var result GetCropTagListResponse + err = util.DecodeWithError(response, &result, "GetCropTagList") + if err != nil { + return nil, err + } + return result.TagGroup, nil +} + +// AddCropTagRequest 添加企业标签请求 +type AddCropTagRequest struct { + GroupID string `json:"group_id"` + GroupName string `json:"group_name"` + Order int `json:"order"` + Tag []AddCropTagItem `json:"tag"` + AgentID int `json:"agentid"` +} + +// AddCropTagItem 添加企业标签子项 +type AddCropTagItem struct { + Name string `json:"name"` + Order int `json:"order"` +} + +// AddCropTagResponse 添加企业标签响应 +type AddCropTagResponse struct { + util.CommonError + TagGroup TagGroup `json:"tag_group"` +} + +// AddCropTag 添加企业客户标签 +// @see https://developer.work.weixin.qq.com/document/path/92117 +func (r *Client) AddCropTag(req AddCropTagRequest) (*TagGroup, error) { + var accessToken string + accessToken, err := r.GetAccessToken() + if err != nil { + return nil, err + } + var response []byte + jsonData, _ := json.Marshal(req) + response, err = util.HTTPPost(fmt.Sprintf("%s?access_token=%v", AddCropTagURL, accessToken), string(jsonData)) + if err != nil { + return nil, err + } + var result AddCropTagResponse + err = util.DecodeWithError(response, &result, "AddCropTag") + if err != nil { + return nil, err + } + return &result.TagGroup, nil +} + +// EditCropTagRequest 编辑客户企业标签请求 +type EditCropTagRequest struct { + ID string `json:"id"` + Name string `json:"name"` + Order int `json:"order"` + AgentID string `json:"agent_id"` +} + +// EditCropTag 修改企业客户标签 +// @see https://developer.work.weixin.qq.com/document/path/92117 +func (r *Client) EditCropTag(req EditCropTagRequest) error { + var accessToken string + accessToken, err := r.GetAccessToken() + if err != nil { + return err + } + var response []byte + jsonData, _ := json.Marshal(req) + response, err = util.HTTPPost(fmt.Sprintf("%s?access_token=%v", EditCropTagURL, accessToken), string(jsonData)) + if err != nil { + return err + } + return util.DecodeWithCommonError(response, "EditCropTag") +} + +// DeleteCropTagRequest 删除企业标签请求 +type DeleteCropTagRequest struct { + TagID []string `json:"tag_id"` + GroupID []string `json:"group_id"` + AgentID string `json:"agent_id"` +} + +// DeleteCropTag 删除企业客户标签 +// @see https://developer.work.weixin.qq.com/document/path/92117 +func (r *Client) DeleteCropTag(req DeleteCropTagRequest) error { + var accessToken string + accessToken, err := r.GetAccessToken() + if err != nil { + return err + } + var response []byte + jsonData, _ := json.Marshal(req) + response, err = util.HTTPPost(fmt.Sprintf("%s?access_token=%v", DelCropTagURL, accessToken), string(jsonData)) + if err != nil { + return err + } + return util.DecodeWithCommonError(response, "DeleteCropTag") +} + +// MarkTagRequest 给客户打标签请求 +type MarkTagRequest struct { + UserID string `json:"user_id"` + ExternalUserID string `json:"external_userid"` + AddTag []string `json:"add_tag"` + RemoveTag []string `json:"remove_tag"` +} + +// MarkTag 为客户打上标签 +// @see https://developer.work.weixin.qq.com/document/path/92118 +func (r *Client) MarkTag(request MarkTagRequest) error { + var accessToken string + accessToken, err := r.GetAccessToken() + if err != nil { + return err + } + var response []byte + jsonData, _ := json.Marshal(request) + response, err = util.HTTPPost(fmt.Sprintf("%s?access_token=%v", MarkCropTagURL, accessToken), string(jsonData)) + if err != nil { + return err + } + return util.DecodeWithCommonError(response, "MarkTag") +} diff --git a/work/work.go b/work/work.go index c2b686c..f9d2029 100644 --- a/work/work.go +++ b/work/work.go @@ -4,6 +4,7 @@ import ( "github.com/silenceper/wechat/v2/credential" "github.com/silenceper/wechat/v2/work/config" "github.com/silenceper/wechat/v2/work/context" + "github.com/silenceper/wechat/v2/work/externalcontact" "github.com/silenceper/wechat/v2/work/kf" "github.com/silenceper/wechat/v2/work/msgaudit" "github.com/silenceper/wechat/v2/work/oauth" @@ -43,3 +44,8 @@ func (wk *Work) GetMsgAudit() (*msgaudit.Client, error) { func (wk *Work) GetKF() (*kf.Client, error) { return kf.NewClient(wk.ctx.Config) } + +// GetExternalContact get external_contact +func (wk *Work) GetExternalContact() *externalcontact.Client { + return externalcontact.NewClient(wk.ctx) +}