subscribe.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. package subscribe
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/silenceper/wechat/v2/miniprogram/context"
  6. "github.com/silenceper/wechat/v2/util"
  7. )
  8. const (
  9. // 发送订阅消息
  10. // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
  11. subscribeSendURL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send"
  12. // 获取当前帐号下的个人模板列表
  13. // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.getTemplateList.html
  14. getTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate"
  15. // 添加订阅模板
  16. // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.addTemplate.html
  17. addTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/addtemplate"
  18. // 删除私有模板
  19. // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.deleteTemplate.html
  20. delTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/deltemplate"
  21. // 统一服务消息
  22. // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/uniform-message/uniformMessage.send.html
  23. uniformMessageSend = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send"
  24. )
  25. // Subscribe 订阅消息
  26. type Subscribe struct {
  27. *context.Context
  28. }
  29. // NewSubscribe 实例化
  30. func NewSubscribe(ctx *context.Context) *Subscribe {
  31. return &Subscribe{Context: ctx}
  32. }
  33. // Message 订阅消息请求参数
  34. type Message struct {
  35. ToUser string `json:"touser"` // 必选,接收者(用户)的 openid
  36. TemplateID string `json:"template_id"` // 必选,所需下发的订阅模板id
  37. Page string `json:"page"` // 可选,点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
  38. Data map[string]*DataItem `json:"data"` // 必选, 模板内容
  39. MiniprogramState string `json:"miniprogram_state"` // 可选,跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
  40. Lang string `json:"lang"` // 入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN
  41. }
  42. // DataItem 模版内某个 .DATA 的值
  43. type DataItem struct {
  44. Value interface{} `json:"value"`
  45. Color string `json:"color"`
  46. }
  47. // TemplateItem template item
  48. type TemplateItem struct {
  49. PriTmplID string `json:"priTmplId"`
  50. Title string `json:"title"`
  51. Content string `json:"content"`
  52. Example string `json:"example"`
  53. Type int64 `json:"type"`
  54. }
  55. // TemplateList template list
  56. type TemplateList struct {
  57. util.CommonError
  58. Data []TemplateItem `json:"data"`
  59. }
  60. // resTemplateSend 发送获取 msg id
  61. type resTemplateSend struct {
  62. util.CommonError
  63. MsgID int64 `json:"msgid"`
  64. }
  65. // Send 发送订阅消息
  66. func (s *Subscribe) Send(msg *Message) (err error) {
  67. var accessToken string
  68. accessToken, err = s.GetAccessToken()
  69. if err != nil {
  70. return
  71. }
  72. uri := fmt.Sprintf("%s?access_token=%s", subscribeSendURL, accessToken)
  73. response, err := util.PostJSON(uri, msg)
  74. if err != nil {
  75. return
  76. }
  77. return util.DecodeWithCommonError(response, "Send")
  78. }
  79. // SendGetMsgID 发送订阅消息返回 msgid
  80. func (s *Subscribe) SendGetMsgID(msg *Message) (msgID int64, err error) {
  81. var accessToken string
  82. accessToken, err = s.GetAccessToken()
  83. if err != nil {
  84. return
  85. }
  86. uri := fmt.Sprintf("%s?access_token=%s", subscribeSendURL, accessToken)
  87. response, err := util.PostJSON(uri, msg)
  88. if err != nil {
  89. return
  90. }
  91. var result resTemplateSend
  92. if err = json.Unmarshal(response, &result); err != nil {
  93. return
  94. }
  95. if result.ErrCode != 0 {
  96. err = fmt.Errorf("template msg send error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  97. return
  98. }
  99. msgID = result.MsgID
  100. return
  101. }
  102. // ListTemplates 获取当前帐号下的个人模板列表
  103. // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.getTemplateList.html
  104. func (s *Subscribe) ListTemplates() (*TemplateList, error) {
  105. accessToken, err := s.GetAccessToken()
  106. if err != nil {
  107. return nil, err
  108. }
  109. uri := fmt.Sprintf("%s?access_token=%s", getTemplateURL, accessToken)
  110. response, err := util.HTTPGet(uri)
  111. if err != nil {
  112. return nil, err
  113. }
  114. templateList := TemplateList{}
  115. err = util.DecodeWithError(response, &templateList, "ListTemplates")
  116. if err != nil {
  117. return nil, err
  118. }
  119. return &templateList, nil
  120. }
  121. // UniformMessage 统一服务消息
  122. type UniformMessage struct {
  123. ToUser string `json:"touser"`
  124. WeappTemplateMsg struct {
  125. TemplateID string `json:"template_id"`
  126. Page string `json:"page"`
  127. FormID string `json:"form_id"`
  128. Data map[string]*DataItem `json:"data"`
  129. EmphasisKeyword string `json:"emphasis_keyword"`
  130. } `json:"weapp_template_msg"`
  131. MpTemplateMsg struct {
  132. Appid string `json:"appid"`
  133. TemplateID string `json:"template_id"`
  134. URL string `json:"url"`
  135. Miniprogram struct {
  136. Appid string `json:"appid"`
  137. Pagepath string `json:"pagepath"`
  138. } `json:"miniprogram"`
  139. Data map[string]*DataItem `json:"data"`
  140. } `json:"mp_template_msg"`
  141. }
  142. // UniformSend 发送统一服务消息
  143. func (s *Subscribe) UniformSend(msg *UniformMessage) (err error) {
  144. var accessToken string
  145. accessToken, err = s.GetAccessToken()
  146. if err != nil {
  147. return
  148. }
  149. uri := fmt.Sprintf("%s?access_token=%s", uniformMessageSend, accessToken)
  150. response, err := util.PostJSON(uri, msg)
  151. if err != nil {
  152. return
  153. }
  154. return util.DecodeWithCommonError(response, "UniformSend")
  155. }
  156. type resSubscribeAdd struct {
  157. util.CommonError
  158. TemplateID string `json:"priTmplId"`
  159. }
  160. // Add 添加订阅消息模板
  161. func (s *Subscribe) Add(ShortID string, kidList []int, sceneDesc string) (templateID string, err error) {
  162. var accessToken string
  163. accessToken, err = s.GetAccessToken()
  164. if err != nil {
  165. return
  166. }
  167. var msg = struct {
  168. TemplateIDShort string `json:"tid"`
  169. SceneDesc string `json:"sceneDesc"`
  170. KidList []int `json:"kidList"`
  171. }{TemplateIDShort: ShortID, SceneDesc: sceneDesc, KidList: kidList}
  172. uri := fmt.Sprintf("%s?access_token=%s", addTemplateURL, accessToken)
  173. var response []byte
  174. response, err = util.PostJSON(uri, msg)
  175. if err != nil {
  176. return
  177. }
  178. var result resSubscribeAdd
  179. err = util.DecodeWithError(response, &result, "AddSubscribe")
  180. return result.TemplateID, err
  181. }
  182. // Delete 删除私有模板
  183. func (s *Subscribe) Delete(templateID string) (err error) {
  184. var accessToken string
  185. accessToken, err = s.GetAccessToken()
  186. if err != nil {
  187. return
  188. }
  189. var msg = struct {
  190. TemplateID string `json:"priTmplId"`
  191. }{TemplateID: templateID}
  192. uri := fmt.Sprintf("%s?access_token=%s", delTemplateURL, accessToken)
  193. var response []byte
  194. response, err = util.PostJSON(uri, msg)
  195. if err != nil {
  196. return
  197. }
  198. return util.DecodeWithCommonError(response, "DeleteSubscribe")
  199. }