template_msg.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. package services
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "eta/eta_mini_bridge/models"
  7. "eta/eta_mini_bridge/utils"
  8. "fmt"
  9. "io"
  10. "net/http"
  11. "time"
  12. )
  13. var (
  14. TemplateMsgSendUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s"
  15. TemplateMsgClearQuotaUrl = "https://api.weixin.qq.com/cgi-bin/clear_quota?access_token=%s"
  16. )
  17. type TemplateMsgSendClient struct {
  18. AccessToken string
  19. Data []byte
  20. }
  21. type SendTemplateResponse struct {
  22. Errcode int `json:"errcode"`
  23. Errmsg string `json:"errmsg"`
  24. MsgID int `json:"msgid"`
  25. }
  26. type ClearQuotaResponse struct {
  27. Errcode int `json:"errcode"`
  28. Errmsg string `json:"errmsg"`
  29. }
  30. type OpenIdList struct {
  31. OpenId string
  32. UserId int
  33. }
  34. // TemplateMsgSendClient.ClearQuota 清除发送超过当日10万次限制
  35. func (c *TemplateMsgSendClient) ClearQuota() (result *ClearQuotaResponse, err error) {
  36. key := "CACHE_SendTemplateMsg_ERR"
  37. exists := utils.Rc.IsExist(key)
  38. if exists {
  39. return
  40. }
  41. _ = utils.Rc.SetEX(key, 1, 6*time.Minute)
  42. sendUrl := fmt.Sprintf(TemplateMsgClearQuotaUrl, c.AccessToken)
  43. client := http.Client{}
  44. clearData := make(map[string]interface{})
  45. clearData["appid"] = utils.DW_WX_APPID
  46. clearJson, _ := json.Marshal(clearData)
  47. resp, err := client.Post(sendUrl, "application/json", bytes.NewBuffer(clearJson))
  48. if err != nil {
  49. return
  50. }
  51. defer func() {
  52. _ = resp.Body.Close()
  53. }()
  54. clearBody, err := io.ReadAll(resp.Body)
  55. err = json.Unmarshal(clearBody, &result)
  56. return
  57. }
  58. // TemplateMsgSendClient.SendMsg 推送消息
  59. func (c *TemplateMsgSendClient) SendMsg() (sendRes *SendTemplateResponse, err error) {
  60. // 请求接口
  61. sendUrl := fmt.Sprintf(TemplateMsgSendUrl, c.AccessToken)
  62. client := http.Client{}
  63. resp, err := client.Post(sendUrl, "application/json", bytes.NewBuffer(c.Data))
  64. if err != nil {
  65. return
  66. }
  67. defer func() {
  68. _ = resp.Body.Close()
  69. }()
  70. body, _ := io.ReadAll(resp.Body)
  71. if err = json.Unmarshal(body, &sendRes); err != nil {
  72. return
  73. }
  74. // 模板消息发送超过当日10万次限制错误处理
  75. if sendRes.Errcode == 45009 {
  76. // 发送提示邮件
  77. // go alarm_msg.SendAlarmMsg("模板消息发送超过当日10万次限制, SendTemplateResponse: "+string(body), 3)
  78. // 清理限制
  79. clearRes, e := c.ClearQuota()
  80. if e != nil {
  81. err = e
  82. return
  83. }
  84. if clearRes.Errcode != 0 {
  85. clearJson, er := json.Marshal(clearRes)
  86. if er != nil {
  87. return nil, er
  88. }
  89. fmt.Println("自动清理模板消息限制接口, 调用失败, ClearQuotaResponse: " + string(clearJson))
  90. // go alarm_msg.SendAlarmMsg("自动清理模板消息限制接口, 调用失败, ClearQuotaResponse: "+string(clearJson), 3)
  91. return
  92. }
  93. // 发送成功邮件
  94. // go alarm_msg.SendAlarmMsg("自动清理模板消息限制接口, 调用成功", 1)
  95. // 重新推送
  96. go func() {
  97. _, e := c.SendMsg()
  98. if e != nil {
  99. return
  100. // reSendJson, _ := json.Marshal(reSend)
  101. // alarm_msg.SendAlarmMsg("重新推送模板消息失败, SendTemplateResponse: "+string(reSendJson), 3)
  102. }
  103. }()
  104. }
  105. if sendRes.Errcode != 0 {
  106. err = errors.New("推送模板消息失败, SendTemplateResponse: " + string(body))
  107. }
  108. return
  109. }
  110. // AddUserTemplateRecord 新增模板消息推送记录
  111. func AddUserTemplateRecord(userId, sendStatus, sendType int, openid, sendData, result string) (err error) {
  112. item := &models.UserTemplateRecord{
  113. UserId: userId,
  114. OpenId: openid,
  115. SendData: sendData,
  116. Result: result,
  117. CreateDate: time.Now().Format(utils.FormatDate),
  118. CreateTime: time.Now().Format(utils.FormatDateTime),
  119. SendStatus: sendStatus,
  120. SendType: sendType,
  121. }
  122. err = item.Insert()
  123. return
  124. }
  125. // SendMultiTemplateMsg 推送模板消息至多个用户
  126. func SendMultiTemplateMsg(sendData map[string]interface{}, items []*OpenIdList, sendType, reportId int) (err error) {
  127. ws := GetWxChat()
  128. accessToken, err := ws.GetAccessToken()
  129. if err != nil {
  130. utils.FileLog.Info("获取微信token失败, Err:" + err.Error())
  131. // alarm_msg.SendAlarmMsg("获取微信token失败, Err:"+err.Error(), 1)
  132. return
  133. }
  134. sendMap := make(map[string]interface{})
  135. for _, item := range items {
  136. sendMap["template_id"] = utils.TEMPLATE_ID_BY_PRODUCT
  137. sendMap["miniprogram"] = map[string]interface{}{
  138. "appid": utils.WX_MINI_APPID,
  139. "pagepath": fmt.Sprintf("pages-report/reportDetail/index?id=%d", reportId),
  140. }
  141. sendMap["touser"] = item.OpenId
  142. sendMap["data"] = sendData
  143. data, e := json.Marshal(sendMap)
  144. if e != nil {
  145. utils.FileLog.Info("新增模板消息推送记录失败, Err:" + e.Error())
  146. return
  147. }
  148. ts := &TemplateMsgSendClient{
  149. AccessToken: accessToken,
  150. Data: data,
  151. }
  152. result, e := ts.SendMsg()
  153. if e != nil {
  154. utils.FileLog.Info("新增模板消息推送记录失败, Err:" + e.Error())
  155. return
  156. }
  157. if result == nil {
  158. return
  159. }
  160. // 推送消息记录
  161. {
  162. go func() {
  163. sendStatus := 1
  164. if e != nil {
  165. sendStatus = 0
  166. }
  167. resultJson, _ := json.Marshal(result)
  168. err = AddUserTemplateRecord(item.UserId, sendStatus, sendType, item.OpenId, string(data), string(resultJson))
  169. if err != nil {
  170. utils.FileLog.Info("新增模板消息推送记录失败, Err:" + err.Error())
  171. return
  172. }
  173. }()
  174. }
  175. }
  176. return
  177. }