template.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. package message
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/silenceper/wechat/v2/officialaccount/context"
  6. "github.com/silenceper/wechat/v2/util"
  7. )
  8. const (
  9. templateSendURL = "https://api.weixin.qq.com/cgi-bin/message/template/send"
  10. templateListURL = "https://api.weixin.qq.com/cgi-bin/template/get_all_private_template"
  11. templateAddURL = "https://api.weixin.qq.com/cgi-bin/template/api_add_template"
  12. templateDelURL = "https://api.weixin.qq.com/cgi-bin/template/del_private_template"
  13. )
  14. // Template 模板消息
  15. type Template struct {
  16. *context.Context
  17. }
  18. // NewTemplate 实例化
  19. func NewTemplate(context *context.Context) *Template {
  20. tpl := new(Template)
  21. tpl.Context = context
  22. return tpl
  23. }
  24. // TemplateMessage 发送的模板消息内容
  25. type TemplateMessage struct {
  26. ToUser string `json:"touser"` // 必须, 接受者OpenID
  27. TemplateID string `json:"template_id"` // 必须, 模版ID
  28. URL string `json:"url,omitempty"` // 可选, 用户点击后跳转的URL, 该URL必须处于开发者在公众平台网站中设置的域中
  29. Color string `json:"color,omitempty"` // 可选, 整个消息的颜色, 可以不设置
  30. Data map[string]*TemplateDataItem `json:"data"` // 必须, 模板数据
  31. ClientMsgID string `json:"client_msg_id,omitempty"` // 可选, 防重入ID
  32. MiniProgram struct {
  33. AppID string `json:"appid"` // 所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系)
  34. PagePath string `json:"pagepath"` // 所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar)
  35. } `json:"miniprogram"` // 可选,跳转至小程序地址
  36. }
  37. // TemplateDataItem 模版内某个 .DATA 的值
  38. type TemplateDataItem struct {
  39. Value string `json:"value"`
  40. Color string `json:"color,omitempty"`
  41. }
  42. type resTemplateSend struct {
  43. util.CommonError
  44. MsgID int64 `json:"msgid"`
  45. }
  46. // Send 发送模板消息
  47. func (tpl *Template) Send(msg *TemplateMessage) (msgID int64, err error) {
  48. var accessToken string
  49. accessToken, err = tpl.GetAccessToken()
  50. if err != nil {
  51. return
  52. }
  53. var (
  54. uri = fmt.Sprintf("%s?access_token=%s", templateSendURL, accessToken)
  55. response []byte
  56. )
  57. if response, err = util.PostJSON(uri, msg); err != nil {
  58. return
  59. }
  60. var result resTemplateSend
  61. if err = json.Unmarshal(response, &result); err != nil {
  62. return
  63. }
  64. if result.ErrCode != 0 {
  65. err = fmt.Errorf("template msg send error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  66. return
  67. }
  68. msgID = result.MsgID
  69. return
  70. }
  71. // TemplateItem 模板消息.
  72. type TemplateItem struct {
  73. TemplateID string `json:"template_id"`
  74. Title string `json:"title"`
  75. PrimaryIndustry string `json:"primary_industry"`
  76. DeputyIndustry string `json:"deputy_industry"`
  77. Content string `json:"content"`
  78. Example string `json:"example"`
  79. }
  80. type resTemplateList struct {
  81. util.CommonError
  82. TemplateList []*TemplateItem `json:"template_list"`
  83. }
  84. // List 获取模板列表
  85. func (tpl *Template) List() (templateList []*TemplateItem, err error) {
  86. var accessToken string
  87. accessToken, err = tpl.GetAccessToken()
  88. if err != nil {
  89. return
  90. }
  91. var (
  92. uri = fmt.Sprintf("%s?access_token=%s", templateListURL, accessToken)
  93. response []byte
  94. )
  95. if response, err = util.HTTPGet(uri); err != nil {
  96. return
  97. }
  98. var res resTemplateList
  99. err = util.DecodeWithError(response, &res, "ListTemplate")
  100. return res.TemplateList, err
  101. }
  102. type resTemplateAdd struct {
  103. util.CommonError
  104. TemplateID string `json:"template_id"`
  105. }
  106. // Add 添加模板.
  107. func (tpl *Template) Add(shortID string, keyNameList []string) (templateID string, err error) {
  108. var accessToken string
  109. accessToken, err = tpl.GetAccessToken()
  110. if err != nil {
  111. return
  112. }
  113. var (
  114. msg = struct {
  115. ShortID string `json:"template_id_short"`
  116. KeyNameList []string `json:"keyword_name_list"`
  117. }{ShortID: shortID, KeyNameList: keyNameList}
  118. uri = fmt.Sprintf("%s?access_token=%s", templateAddURL, accessToken)
  119. response []byte
  120. )
  121. if response, err = util.PostJSON(uri, msg); err != nil {
  122. return
  123. }
  124. var result resTemplateAdd
  125. err = util.DecodeWithError(response, &result, "AddTemplate")
  126. return result.TemplateID, err
  127. }
  128. // Delete 删除私有模板.
  129. func (tpl *Template) Delete(templateID string) (err error) {
  130. var accessToken string
  131. accessToken, err = tpl.GetAccessToken()
  132. if err != nil {
  133. return
  134. }
  135. var (
  136. msg = struct {
  137. TemplateID string `json:"template_id"`
  138. }{TemplateID: templateID}
  139. uri = fmt.Sprintf("%s?access_token=%s", templateDelURL, accessToken)
  140. response []byte
  141. )
  142. if response, err = util.PostJSON(uri, msg); err != nil {
  143. return
  144. }
  145. return util.DecodeWithCommonError(response, "DeleteTemplate")
  146. }