| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597 |
- package work
- import (
- "dashoo.cn/opms_libary/myerrors"
- "encoding/json"
- "errors"
- "fmt"
- "net/url"
- )
- const (
- //SysApprovalChange 审批实例变更
- SysApprovalChange = "sys_approval_change"
- )
- func marshalIntoJSONBody(x interface{}) ([]byte, error) {
- y, err := json.Marshal(x)
- if err != nil {
- // should never happen unless OOM or similar bad things
- return nil, fmt.Errorf("go-workwx: failed to marshal request: %w", err)
- }
- return y, nil
- }
- type reqAccessToken struct {
- CorpID string
- CorpSecret string
- }
- func (x reqAccessToken) intoURLValues() url.Values {
- return url.Values{
- "corpid": {x.CorpID},
- "corpsecret": {x.CorpSecret},
- }
- }
- type respCommon struct {
- ErrCode int64 `json:"errcode"`
- ErrMsg string `json:"errmsg"`
- }
- // IsOK 响应体是否为一次成功请求的响应
- //
- // 实现依据: https://work.weixin.qq.com/api/doc#10013
- //
- // > 企业微信所有接口,返回包里都有errcode、errmsg。
- // > 开发者需根据errcode是否为0判断是否调用成功(errcode意义请见全局错误码)。
- // > 而errmsg仅作参考,后续可能会有变动,因此不可作为是否调用成功的判据。
- func (x *respCommon) IsOK() bool {
- return x.ErrCode == 0
- }
- func (x *respCommon) TryIntoErr() error {
- if x.IsOK() {
- return nil
- }
- return myerrors.ThirdPluginError(errors.New(fmt.Sprintf("ErrCode:%v, ErrMsg:%v", x.ErrCode, x.ErrMsg)), "企业微信接口调用失败")
- }
- type respAccessToken struct {
- respCommon
- AccessToken string `json:"access_token"`
- ExpiresInSecs int64 `json:"expires_in"`
- }
- type reqJSAPITicketAgentConfig struct{}
- func (x reqJSAPITicketAgentConfig) intoURLValues() url.Values {
- return url.Values{
- "type": {"agent_config"},
- }
- }
- type reqJSAPITicket struct{}
- func (x reqJSAPITicket) intoURLValues() url.Values {
- return url.Values{}
- }
- type respJSAPITicket struct {
- respCommon
- Ticket string `json:"ticket"`
- ExpiresInSecs int64 `json:"expires_in"`
- }
- // reqConvertUserIDToOpenID userid转openid 请求
- type reqConvertUserIDToOpenID struct {
- UserID string `json:"userid"`
- }
- // respConvertUserIDToOpenID userid转openid 响应
- type respConvertUserIDToOpenID struct {
- respCommon
- OpenID string `json:"openid"`
- }
- func (x reqConvertUserIDToOpenID) intoBody() ([]byte, error) {
- return marshalIntoJSONBody(x)
- }
- // reqConvertOpenIDToUserID openid转userid 请求
- type reqConvertOpenIDToUserID struct {
- OpenID string `json:"openid"`
- }
- // respConvertUserIDToOpenID openid转userid 响应
- type respConvertOpenIDToUserID struct {
- respCommon
- UserID string `json:"userid"`
- }
- func (x reqConvertOpenIDToUserID) intoBody() ([]byte, error) {
- return marshalIntoJSONBody(x)
- }
- // SizeType qrcode尺寸类型
- //
- // 1: 171 x 171; 2: 399 x 399; 3: 741 x 741; 4: 2052 x 2052
- type SizeType int
- const (
- // SizeTypeMini 171 x 171
- SizeTypeMini SizeType = iota + 1
- // SizeTypeSmall 399 x 399
- SizeTypeSmall
- // SizeTypeMedium 741 x 741
- SizeTypeMedium
- // SizeTypeLarge 2052 x 2052
- SizeTypeLarge
- )
- // reqUserIDByMobile 手机号获取 userid 请求
- type reqUserIDByMobile struct {
- Mobile string `json:"mobile"`
- }
- func (x reqUserIDByMobile) intoBody() ([]byte, error) {
- return marshalIntoJSONBody(x)
- }
- // respUserIDByMobile 手机号获取 userid 响应
- type respUserIDByMobile struct {
- respCommon
- UserID string `json:"userid"`
- }
- // EmailType 用户邮箱的类型
- //
- // 1表示用户邮箱是企业邮箱(默认)
- // 2表示用户邮箱是个人邮箱
- type EmailType int
- const (
- // EmailTypeCorporate 企业邮箱
- EmailTypeCorporate EmailType = 1
- // EmailTypePersonal 个人邮箱
- EmailTypePersonal EmailType = 2
- )
- // reqUserIDByEmail 邮箱获取 userid 请求
- type reqUserIDByEmail struct {
- Email string `json:"email"`
- EmailType EmailType `json:"email_type"`
- }
- func (x reqUserIDByEmail) intoBody() ([]byte, error) {
- return marshalIntoJSONBody(x)
- }
- // respUserIDByEmail 邮箱获取 userid 响应
- type respUserIDByEmail struct {
- respCommon
- UserID string `json:"userid"`
- }
- // reqUserInfoGet 获取访问用户身份
- type reqUserInfoGet struct {
- // 通过成员授权获取到的code,最大为512字节。每次成员授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
- Code string
- }
- func (x reqUserInfoGet) intoURLValues() url.Values {
- return url.Values{
- "code": {x.Code},
- }
- }
- // reqJSCode2Session 临时登录凭证校验
- type reqJSCode2Session struct {
- JSCode string
- }
- func (x reqJSCode2Session) intoURLValues() url.Values {
- return url.Values{
- "js_code": {x.JSCode},
- "grant_type": {"authorization_code"},
- }
- }
- // respJSCode2Session 临时登录凭证校验
- type respJSCode2Session struct {
- respCommon
- JSCodeSession
- }
- // JSCodeSession 临时登录凭证
- type JSCodeSession struct {
- CorpID string `json:"corpid"`
- UserID string `json:"userid"`
- SessionKey string `json:"session_key"`
- }
- // reqAuthCode2UserInfo 获取访问用户身份
- type reqAuthCode2UserInfo struct {
- Code string
- }
- func (x reqAuthCode2UserInfo) intoURLValues() url.Values {
- return url.Values{
- "code": {x.Code},
- }
- }
- // respAuthCode2UserInfo 获取访问用户身份响应
- type respAuthCode2UserInfo struct {
- respCommon
- AuthCodeUserInfo
- }
- // AuthCodeUserInfo 访问用户身份
- type AuthCodeUserInfo struct {
- UserID string `json:"userid,omitempty"`
- UserTicket string `json:"user_ticket,omitempty"`
- OpenID string `json:"openid,omitempty"`
- ExternalUserID string `json:"external_userid,omitempty"`
- }
- type reqOAGetTemplateDetail struct {
- TemplateID string `json:"template_id"`
- }
- func (x reqOAGetTemplateDetail) intoBody() ([]byte, error) {
- return marshalIntoJSONBody(x)
- }
- type respOAGetTemplateDetail struct {
- respCommon
- OATemplateDetail
- }
- type reqOAApplyEvent struct {
- OAApplyEvent
- }
- func (x reqOAApplyEvent) intoBody() ([]byte, error) {
- return marshalIntoJSONBody(x)
- }
- type respOAApplyEvent struct {
- respCommon
- // SpNo 表单提交成功后,返回的表单编号
- SpNo string `json:"sp_no"`
- }
- type reqOAGetApprovalInfo struct {
- StartTime string `json:"starttime"`
- EndTime string `json:"endtime"`
- Cursor int `json:"cursor"`
- Size uint32 `json:"size"`
- Filters []OAApprovalInfoFilter `json:"filters"`
- }
- func (x reqOAGetApprovalInfo) intoBody() ([]byte, error) {
- return marshalIntoJSONBody(x)
- }
- type respOAGetApprovalInfo struct {
- respCommon
- // SpNoList 审批单号列表,包含满足条件的审批申请
- SpNoList []string `json:"sp_no_list"`
- }
- type reqOAGetApprovalDetail struct {
- // SpNo 审批单编号。
- SpNo string `json:"sp_no"`
- }
- func (x reqOAGetApprovalDetail) intoBody() ([]byte, error) {
- return marshalIntoJSONBody(x)
- }
- type respOAGetApprovalDetail struct {
- respCommon
- // Info 审批申请详情
- Info OAApprovalDetail `json:"info"`
- }
- // TaskCardBtn 任务卡片消息按钮
- type TaskCardBtn struct {
- // Key 按钮key值,用户点击后,会产生任务卡片回调事件,回调事件会带上该key值,只能由数字、字母和“_-@”组成,最长支持128字节
- Key string `json:"key"`
- // Name 按钮名称
- Name string `json:"name"`
- // ReplaceName 点击按钮后显示的名称,默认为“已处理”
- ReplaceName string `json:"replace_name"`
- // Color 按钮字体颜色,可选“red”或者“blue”,默认为“blue”
- Color string `json:"color"`
- // IsBold 按钮字体是否加粗,默认false
- IsBold bool `json:"is_bold"`
- }
- // Article news 类型的文章
- type Article struct {
- // 标题,不超过128个字节,超过会自动截断(支持id转译)
- Title string `json:"title"`
- // 描述,不超过512个字节,超过会自动截断(支持id转译)
- Description string `json:"description"`
- // 点击后跳转的链接。 最长2048字节,请确保包含了协议头(http/https),小程序或者url必须填写一个
- URL string `json:"url"`
- // 图文消息的图片链接,最长2048字节,支持JPG、PNG格式,较好的效果为大图 1068*455,小图150*150
- PicURL string `json:"picurl"`
- // 小程序appid,必须是与当前应用关联的小程序,appid和pagepath必须同时填写,填写后会忽略url字段
- AppID string `json:"appid"`
- // 点击消息卡片后的小程序页面,最长128字节,仅限本小程序内的页面。appid和pagepath必须同时填写,填写后会忽略url字段
- PagePath string `json:"pagepath"`
- }
- // MPArticle mpnews 类型的文章
- type MPArticle struct {
- // 标题,不超过128个字节,超过会自动截断(支持id转译)
- Title string `json:"title"`
- // 图文消息缩略图的media_id, 可以通过素材管理接口获得。此处thumb_media_id即上传接口返回的media_id
- ThumbMediaID string `json:"thumb_media_id"`
- // 图文消息的作者,不超过64个字节
- Author string `json:"author"`
- // 图文消息点击“阅读原文”之后的页面链接
- ContentSourceURL string `json:"content_source_url"`
- // 图文消息的内容,支持html标签,不超过666 K个字节(支持id转译)
- Content string `json:"content"`
- // 图文消息的描述,不超过512个字节,超过会自动截断(支持id转译)
- Digest string `json:"digest"`
- }
- // Source 卡片来源样式信息,不需要来源样式可不填写
- type Source struct {
- // 来源图片的url,来源图片的尺寸建议为72*72
- IconURL string `json:"icon_url"`
- // 来源图片的描述,建议不超过20个字,(支持id转译)
- Desc string `json:"desc"`
- // 来源文字的颜色,目前支持:0(默认) 灰色,1 黑色,2 红色,3 绿色
- DescColor int `json:"desc_color"`
- }
- // ActionList 操作列表,列表长度取值范围为 [1, 3]
- type ActionList struct {
- // 操作的描述文案
- Text string `json:"text"`
- // 操作key值,用户点击后,会产生回调事件将本参数作为EventKey返回,回调事件会带上该key值,最长支持1024字节,不可重复
- Key string `json:"key"`
- }
- // ActionMenu 卡片右上角更多操作按钮
- type ActionMenu struct {
- // 更多操作界面的描述
- Desc string `json:"desc"`
- ActionList []ActionList `json:"action_list"`
- }
- // MainTitle 一级标题
- type MainTitle struct {
- // 一级标题,建议不超过36个字,文本通知型卡片本字段非必填,但不可本字段和sub_title_text都不填,(支持id转译)
- Title string `json:"title"`
- // 标题辅助信息,建议不超过160个字,(支持id转译)
- Desc string `json:"desc"`
- }
- // QuoteArea 引用文献样式
- type QuoteArea struct {
- // 引用文献样式区域点击事件,0或不填代表没有点击事件,1 代表跳转url,2 代表跳转小程序
- Type int `json:"type"`
- // 点击跳转的url,quote_area.type是1时必填
- URL string `json:"url"`
- // 引用文献样式的标题
- Title string `json:"title"`
- // 引用文献样式的引用文案
- QuoteText string `json:"quote_text"`
- // 小程序appid,必须是与当前应用关联的小程序,appid和pagepath必须同时填写,填写后会忽略url字段
- AppID string `json:"appid"`
- // 点击消息卡片后的小程序页面,最长128字节,仅限本小程序内的页面。appid和pagepath必须同时填写,填写后会忽略url字段
- PagePath string `json:"pagepath"`
- }
- // EmphasisContent 关键数据样式
- type EmphasisContent struct {
- // 关键数据样式的数据内容,建议不超过14个字
- Title string `json:"title"`
- // 关键数据样式的数据描述内容,建议不超过22个字
- Desc string `json:"desc"`
- }
- // HorizontalContentList 二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6
- type HorizontalContentList struct {
- // 二级标题,建议不超过5个字
- KeyName string `json:"keyname"`
- // 二级文本,如果horizontal_content_list.type是2,该字段代表文件名称(要包含文件类型),建议不超过30个字,(支持id转译)
- Value string `json:"value"`
- // 链接类型,0或不填代表不是链接,1 代表跳转url,2 代表下载附件,3 代表点击跳转成员详情
- Type int `json:"type,omitempty"`
- // 链接跳转的url,horizontal_content_list.type是1时必填
- URL string `json:"url,omitempty"`
- // 附件的media_id,horizontal_content_list.type是2时必填
- MediaID string `json:"media_id,omitempty"`
- // 成员详情的userid,horizontal_content_list.type是3时必填
- Userid string `json:"userid,omitempty"`
- }
- // JumpList 跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3
- type JumpList struct {
- // 跳转链接类型,0或不填代表不是链接,1 代表跳转url,2 代表跳转小程序
- Type int `json:"type"`
- // 跳转链接样式的文案内容,建议不超过18个字
- Title string `json:"title"`
- // 跳转链接的url,jump_list.type是1时必填
- URL string `json:"url,omitempty"`
- // 跳转链接的小程序的appid,必须是与当前应用关联的小程序,jump_list.type是2时必填
- Appid string `json:"appid,omitempty"`
- // 跳转链接的小程序的pagepath,jump_list.type是2时选填
- PagePath string `json:"pagepath,omitempty"`
- }
- // CardAction 整体卡片的点击跳转事件,text_notice必填本字段
- type CardAction struct {
- // 跳转事件类型,1 代表跳转url,2 代表打开小程序。text_notice卡片模版中该字段取值范围为[1,2]
- Type int `json:"type"`
- // 跳转事件的url,card_action.type是1时必填
- URL string `json:"url"`
- // 跳转事件的小程序的appid,必须是与当前应用关联的小程序,card_action.type是2时必填
- Appid string `json:"appid"`
- // 跳转事件的小程序的pagepath,card_action.type是2时选填
- Pagepath string `json:"pagepath"`
- }
- // ImageTextArea 左图右文样式,news_notice类型的卡片,card_image和image_text_area两者必填一个字段,不可都不填
- type ImageTextArea struct {
- // 左图右文样式区域点击事件,0或不填代表没有点击事件,1 代表跳转url,2 代表跳转小程序
- Type int `json:"type"`
- // 点击跳转的url,image_text_area.type是1时必填
- URL string `json:"url"`
- // 点击跳转的小程序的appid,必须是与当前应用关联的小程序,image_text_area.type是2时必填
- AppID string `json:"appid,omitempty"`
- // 点击跳转的小程序的pagepath,image_text_area.type是2时选填
- PagePath string `json:"pagepath,omitempty"`
- // 左图右文样式的标题
- Title string `json:"title"`
- // 左图右文样式的描述
- Desc string `json:"desc"`
- // 左图右文样式的图片url
- ImageURL string `json:"image_url"`
- }
- // CardImage 图片样式,news_notice类型的卡片,card_image和image_text_area两者必填一个字段,不可都不填
- type CardImage struct {
- // 图片的url
- URL string `json:"url"`
- // 图片的宽高比,宽高比要小于2.25,大于1.3,不填该参数默认1.3
- AspectRatio float32 `json:"aspect_ratio"`
- }
- // ButtonSelection 按钮交互型
- type ButtonSelection struct {
- // 下拉式的选择器的key,用户提交选项后,会产生回调事件,回调事件会带上该key值表示该题,最长支持1024字节
- QuestionKey string `json:"question_key"`
- // 下拉式的选择器的key,用户提交选项后,会产生回调事件,回调事件会带上该key值表示该题,最长支持1024字节
- Title string `json:"title"`
- // 选项列表,下拉选项不超过 10 个,最少1个
- OptionList []struct {
- // 下拉式的选择器选项的id,用户提交后,会产生回调事件,回调事件会带上该id值表示该选项,最长支持128字节,不可重复
- ID string `json:"id"`
- // 下拉式的选择器选项的文案,建议不超过16个字
- Text string `json:"text"`
- } `json:"option_list"`
- // 默认选定的id,不填或错填默认第一个
- SelectedID string `json:"selected_id"`
- }
- type Button struct {
- // 按钮点击事件类型,0 或不填代表回调点击事件,1 代表跳转url
- Type int `json:"type,omitempty"`
- // 按钮文案,建议不超过10个字
- Text string `json:"text"`
- // 按钮样式,目前可填1~4,不填或错填默认1
- Style int `json:"style,omitempty"`
- // 按钮key值,用户点击后,会产生回调事件将本参数作为EventKey返回,回调事件会带上该key值,最长支持1024字节,不可重复,button_list.type是0时必填
- Key string `json:"key,omitempty"`
- // 跳转事件的url,button_list.type是1时必填
- URL string `json:"url,omitempty"`
- }
- // CheckBox 选择题样式
- type CheckBox struct {
- // 选择题key值,用户提交选项后,会产生回调事件,回调事件会带上该key值表示该题,最长支持1024字节
- QuestionKey string `json:"question_key"`
- // 选项list,选项个数不超过 20 个,最少1个
- OptionList []struct {
- // 选项id,用户提交选项后,会产生回调事件,回调事件会带上该id值表示该选项,最长支持128字节,不可重复
- ID string `json:"id"`
- // 选项文案描述,建议不超过17个字
- Text string `json:"text"`
- // 该选项是否要默认选中
- IsChecked bool `json:"is_checked"`
- } `json:"option_list" validate:"required,min=1,max=20"`
- // 选择题模式,单选:0,多选:1,不填默认0
- Mode int `json:"mode" validate:"omitempty,oneof=0 1"`
- }
- // SubmitButton 提交按钮样式
- type SubmitButton struct {
- // 按钮文案,建议不超过10个字,不填默认为提交
- Text string `json:"text"`
- // 提交按钮的key,会产生回调事件将本参数作为EventKey返回,最长支持1024字节
- Key string `json:"key"`
- }
- // SelectList 下拉式的选择器列表,multiple_interaction类型的卡片该字段不可为空,一个消息最多支持 3 个选择器
- type SelectList struct {
- // 下拉式的选择器题目的key,用户提交选项后,会产生回调事件,回调事件会带上该key值表示该题,最长支持1024字节,不可重复
- QuestionKey string `json:"question_key"`
- // 下拉式的选择器上面的title
- Title string `json:"title,omitempty"`
- // 默认选定的id,不填或错填默认第一个
- SelectedID string `json:"selected_id,omitempty"`
- OptionList []OptionList `json:"option_list"`
- }
- // 项列表,下拉选项不超过 10 个,最少1个
- type OptionList struct {
- // 下拉式的选择器选项的id,用户提交选项后,会产生回调事件,回调事件会带上该id值表示该选项,最长支持128字节,不可重复
- ID string `json:"id"`
- // 下拉式的选择器选项的文案,建议不超过16个字
- Text string `json:"text"`
- }
- // TemplateCardType 模板卡片的类型
- type TemplateCardType string
- const (
- CardTypeTextNotice TemplateCardType = "text_notice" // 文本通知型
- CardTypeNewsNotice TemplateCardType = "news_notice" // 图文展示型
- CardTypeButtonInteraction TemplateCardType = "button_interaction" // 按钮交互型
- CardTypeVoteInteraction TemplateCardType = "vote_interaction" // 投票选择型
- CardTypeMultipleInteraction TemplateCardType = "multiple_interaction" // 多项选择型
- )
- type TemplateCard struct {
- CardType TemplateCardType `json:"card_type"`
- Source Source `json:"source"`
- ActionMenu *ActionMenu `json:"action_menu,omitempty" validate:"required_with=TaskID"`
- TaskID string `json:"task_id,omitempty" validate:"required_with=ActionMenu"`
- MainTitle *MainTitle `json:"main_title"`
- QuoteArea *QuoteArea `json:"quote_area,omitempty"`
- // 文本通知型
- EmphasisContent *EmphasisContent `json:"emphasis_content,omitempty"`
- SubTitleText string `json:"sub_title_text,omitempty"`
- // 图文展示型
- ImageTextArea *ImageTextArea `json:"image_text_area,omitempty"`
- CardImage *CardImage `json:"card_image,omitempty"`
- HorizontalContentList []HorizontalContentList `json:"horizontal_content_list"`
- JumpList []JumpList `json:"jump_list"`
- CardAction *CardAction `json:"card_action,omitempty"`
- // 按钮交互型
- ButtonSelection *ButtonSelection `json:"button_selection,omitempty"`
- ButtonList []Button `json:"button_list,omitempty" validate:"omitempty,max=6"`
- // 投票选择型
- CheckBox *CheckBox `json:"checkbox,omitempty"`
- SelectList []SelectList `json:"select_list,omitempty" validate:"max=3"`
- SubmitButton *SubmitButton `json:"submit_button,omitempty"`
- }
- type TemplateCardUpdateMessage struct {
- UserIds []string `json:"userids" validate:"omitempty,max=100"`
- PartyIds []int64 `json:"partyids" validate:"omitempty,max=100"`
- TagIds []int32 `json:"tagids" validate:"omitempty,max=100"`
- AtAll int `json:"atall,omitempty"`
- ResponseCode string `json:"response_code"`
- Button struct {
- ReplaceName string `json:"replace_name"`
- } `json:"button" validate:"required_without=TemplateCard"`
- TemplateCard TemplateCard `json:"template_card" validate:"required_without=Button"`
- ReplaceText string `json:"replace_text,omitempty"`
- }
|