broadcast.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. package broadcast
  2. import (
  3. "fmt"
  4. "github.com/silenceper/wechat/v2/officialaccount/context"
  5. "github.com/silenceper/wechat/v2/util"
  6. )
  7. const (
  8. sendURLByTag = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"
  9. sendURLByOpenID = "https://api.weixin.qq.com/cgi-bin/message/mass/send"
  10. deleteSendURL ="https://api.weixin.qq.com/cgi-bin/message/mass/delete"
  11. )
  12. //MsgType 发送消息类型
  13. type MsgType string
  14. const (
  15. //MsgTypeNews 图文消息
  16. MsgTypeNews MsgType = "mpnews"
  17. //MsgTypeText 文本
  18. MsgTypeText MsgType = "text"
  19. //MsgTypeVoice 语音/音频
  20. MsgTypeVoice MsgType = "voice"
  21. //MsgTypeImage 图片
  22. MsgTypeImage MsgType = "image"
  23. //MsgTypeVideo 视频
  24. MsgTypeVideo MsgType = "mpvideo"
  25. //MsgTypeWxCard 卡券
  26. MsgTypeWxCard MsgType = "wxcard"
  27. )
  28. //Broadcast 群发消息
  29. type Broadcast struct {
  30. *context.Context
  31. }
  32. //NewBroadcast new
  33. func NewBroadcast(ctx *context.Context) *Broadcast {
  34. return &Broadcast{ctx}
  35. }
  36. //User 发送的用户
  37. type User struct {
  38. TagID int64
  39. OpenID []string
  40. }
  41. //Result 群发返回结果
  42. type Result struct {
  43. util.CommonError
  44. MsgID int64 `json:"msg_id"`
  45. MsgDataID int64 `json:"msg_data_id"`
  46. }
  47. //sendRequest 发送请求的数据
  48. type sendRequest struct {
  49. //根据tag获全部发送
  50. Filter map[string]interface{} `json:"filter,omitempty"`
  51. //根据OpenID发送
  52. ToUser interface{} `json:"touser,omitempty"`
  53. //发送文本
  54. Text map[string]interface{} `json:"text,omitempty"`
  55. //发送图文消息
  56. Mpnews map[string]interface{} `json:"mpnews,omitempty"`
  57. //发送语音
  58. Voice map[string]interface{} `json:"voice,omitempty"`
  59. //发送图片
  60. Images *Image `json:"images,omitempty"`
  61. //发送卡券
  62. WxCard map[string]interface{} `json:"wxcard,omitempty"`
  63. MsgType MsgType `json:"msgtype"`
  64. SendIgnoreReprint int32 `json:"send_ignore_reprint,omitempty"`
  65. }
  66. //Image 发送图片
  67. type Image struct{
  68. MediaIDs []string `json:"media_ids"`
  69. Recommend string `json:"recommend"`
  70. NeedOpenComment int32 `json:"need_open_comment"`
  71. OnlyFansCanComment int32 `json:"only_fans_can_comment"`
  72. }
  73. //SendText 群发文本
  74. //user 为nil,表示全员发送
  75. //&User{TagID:2} 根据tag发送
  76. //&User{OpenID:[]string("xxx","xxx")} 根据openid发送
  77. func (broadcast *Broadcast) SendText(user *User, content string) (*Result, error) {
  78. ak, err := broadcast.GetAccessToken()
  79. if err != nil {
  80. return nil, err
  81. }
  82. req := &sendRequest{
  83. ToUser: nil,
  84. MsgType: MsgTypeText,
  85. }
  86. req.Text=map[string]interface{}{
  87. "content":content,
  88. }
  89. req,sendURL:=broadcast.chooseTagOrOpenID(user,req)
  90. url := fmt.Sprintf("%s?access_token=%s", sendURL, ak)
  91. data, err := util.PostJSON(url, req)
  92. if err != nil {
  93. return nil, err
  94. }
  95. res := &Result{}
  96. err = util.DecodeWithError(data, res, "SendText")
  97. return res, err
  98. }
  99. //SendNews 发送图文
  100. func (broadcast *Broadcast) SendNews(user *User, mediaID string,ignoreReprint bool) (*Result, error) {
  101. ak, err := broadcast.GetAccessToken()
  102. if err != nil {
  103. return nil, err
  104. }
  105. req := &sendRequest{
  106. ToUser: nil,
  107. MsgType: MsgTypeNews,
  108. }
  109. if ignoreReprint{
  110. req.SendIgnoreReprint=1
  111. }
  112. req.Mpnews=map[string]interface{}{
  113. "media_id":mediaID,
  114. }
  115. req,sendURL:=broadcast.chooseTagOrOpenID(user,req)
  116. url := fmt.Sprintf("%s?access_token=%s", sendURL, ak)
  117. data, err := util.PostJSON(url, req)
  118. if err != nil {
  119. return nil, err
  120. }
  121. res := &Result{}
  122. err = util.DecodeWithError(data, res, "SendNews")
  123. return res, err
  124. }
  125. //SendVoice 发送语音
  126. func (broadcast *Broadcast) SendVoice(user *User, mediaID string) (*Result, error) {
  127. ak, err := broadcast.GetAccessToken()
  128. if err != nil {
  129. return nil, err
  130. }
  131. req := &sendRequest{
  132. ToUser: nil,
  133. MsgType: MsgTypeVoice,
  134. }
  135. req.Voice=map[string]interface{}{
  136. "media_id":mediaID,
  137. }
  138. req,sendURL:=broadcast.chooseTagOrOpenID(user,req)
  139. url := fmt.Sprintf("%s?access_token=%s", sendURL, ak)
  140. data, err := util.PostJSON(url, req)
  141. if err != nil {
  142. return nil, err
  143. }
  144. res := &Result{}
  145. err = util.DecodeWithError(data, res, "SendVoice")
  146. return res, err
  147. }
  148. //SendImage 发送图片
  149. func (broadcast *Broadcast) SendImage(user *User, images *Image) (*Result, error) {
  150. ak, err := broadcast.GetAccessToken()
  151. if err != nil {
  152. return nil, err
  153. }
  154. req := &sendRequest{
  155. ToUser: nil,
  156. MsgType: MsgTypeImage,
  157. }
  158. req.Images=images
  159. req,sendURL:=broadcast.chooseTagOrOpenID(user,req)
  160. url := fmt.Sprintf("%s?access_token=%s", sendURL, ak)
  161. data, err := util.PostJSON(url, req)
  162. if err != nil {
  163. return nil, err
  164. }
  165. res := &Result{}
  166. err = util.DecodeWithError(data, res, "SendImage")
  167. return res, err
  168. }
  169. //SendVideo 发送视频
  170. func (broadcast *Broadcast) SendVideo(user *User, mediaID string,title,description string) (*Result, error) {
  171. ak, err := broadcast.GetAccessToken()
  172. if err != nil {
  173. return nil, err
  174. }
  175. req := &sendRequest{
  176. ToUser: nil,
  177. MsgType: MsgTypeVideo,
  178. }
  179. req.Voice=map[string]interface{}{
  180. "media_id":mediaID,
  181. "title":title,
  182. "description":description,
  183. }
  184. req,sendURL:=broadcast.chooseTagOrOpenID(user,req)
  185. url := fmt.Sprintf("%s?access_token=%s", sendURL, ak)
  186. data, err := util.PostJSON(url, req)
  187. if err != nil {
  188. return nil, err
  189. }
  190. res := &Result{}
  191. err = util.DecodeWithError(data, res, "SendVideo")
  192. return res, err
  193. }
  194. //SendWxCard 发送卡券
  195. func (broadcast *Broadcast) SendWxCard(user *User, cardID string) (*Result, error) {
  196. ak, err := broadcast.GetAccessToken()
  197. if err != nil {
  198. return nil, err
  199. }
  200. req := &sendRequest{
  201. ToUser: nil,
  202. MsgType: MsgTypeWxCard,
  203. }
  204. req.WxCard=map[string]interface{}{
  205. "card_id":cardID,
  206. }
  207. req,sendURL:=broadcast.chooseTagOrOpenID(user,req)
  208. url := fmt.Sprintf("%s?access_token=%s", sendURL, ak)
  209. data, err := util.PostJSON(url, req)
  210. if err != nil {
  211. return nil, err
  212. }
  213. res := &Result{}
  214. err = util.DecodeWithError(data, res, "SendWxCard")
  215. return res, err
  216. }
  217. //Delete 删除群发消息
  218. func (broadcast *Broadcast) Delete(msgID int64 ,articleIDx int64) error {
  219. ak, err := broadcast.GetAccessToken()
  220. if err != nil {
  221. return err
  222. }
  223. req := map[string]interface{}{
  224. "msg_id": msgID,
  225. "article_idx": articleIDx,
  226. }
  227. url := fmt.Sprintf("%s?access_token=%s", deleteSendURL, ak)
  228. data, err := util.PostJSON(url, req)
  229. if err != nil {
  230. return err
  231. }
  232. return util.DecodeWithCommonError(data, "Delete")
  233. }
  234. //TODO 发送预览,群发消息状态,发送速度
  235. func (broadcast *Broadcast) chooseTagOrOpenID(user *User,req *sendRequest)(ret *sendRequest,url string){
  236. sendURL:=""
  237. if user == nil {
  238. req.Filter=map[string]interface{}{
  239. "is_to_all":true,
  240. }
  241. sendURL=sendURLByTag
  242. } else {
  243. if user.TagID != 0 {
  244. req.Filter=map[string]interface{}{
  245. "is_to_all":false,
  246. "tag_id":user.TagID,
  247. }
  248. sendURL=sendURLByTag
  249. }
  250. if len(user.OpenID) != 0 {
  251. req.ToUser = user.OpenID
  252. sendURL=sendURLByOpenID
  253. }
  254. }
  255. return req,sendURL
  256. }