package broadcast import ( "fmt" "github.com/silenceper/wechat/v2/officialaccount/context" "github.com/silenceper/wechat/v2/util" ) const ( sendURLByTag = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall" sendURLByOpenID = "https://api.weixin.qq.com/cgi-bin/message/mass/send" deleteSendURL = "https://api.weixin.qq.com/cgi-bin/message/mass/delete" ) //MsgType 发送消息类型 type MsgType string const ( //MsgTypeNews 图文消息 MsgTypeNews MsgType = "mpnews" //MsgTypeText 文本 MsgTypeText MsgType = "text" //MsgTypeVoice 语音/音频 MsgTypeVoice MsgType = "voice" //MsgTypeImage 图片 MsgTypeImage MsgType = "image" //MsgTypeVideo 视频 MsgTypeVideo MsgType = "mpvideo" //MsgTypeWxCard 卡券 MsgTypeWxCard MsgType = "wxcard" ) //Broadcast 群发消息 type Broadcast struct { *context.Context } //NewBroadcast new func NewBroadcast(ctx *context.Context) *Broadcast { return &Broadcast{ctx} } //User 发送的用户 type User struct { TagID int64 OpenID []string } //Result 群发返回结果 type Result struct { util.CommonError MsgID int64 `json:"msg_id"` MsgDataID int64 `json:"msg_data_id"` } //sendRequest 发送请求的数据 type sendRequest struct { //根据tag获全部发送 Filter map[string]interface{} `json:"filter,omitempty"` //根据OpenID发送 ToUser interface{} `json:"touser,omitempty"` //发送文本 Text map[string]interface{} `json:"text,omitempty"` //发送图文消息 Mpnews map[string]interface{} `json:"mpnews,omitempty"` //发送语音 Voice map[string]interface{} `json:"voice,omitempty"` //发送图片 Images *Image `json:"images,omitempty"` //发送卡券 WxCard map[string]interface{} `json:"wxcard,omitempty"` MsgType MsgType `json:"msgtype"` SendIgnoreReprint int32 `json:"send_ignore_reprint,omitempty"` } //Image 发送图片 type Image struct { MediaIDs []string `json:"media_ids"` Recommend string `json:"recommend"` NeedOpenComment int32 `json:"need_open_comment"` OnlyFansCanComment int32 `json:"only_fans_can_comment"` } //SendText 群发文本 //user 为nil,表示全员发送 //&User{TagID:2} 根据tag发送 //&User{OpenID:[]string("xxx","xxx")} 根据openid发送 func (broadcast *Broadcast) SendText(user *User, content string) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { return nil, err } req := &sendRequest{ ToUser: nil, MsgType: MsgTypeText, } req.Text = map[string]interface{}{ "content": content, } req, sendURL := broadcast.chooseTagOrOpenID(user, req) url := fmt.Sprintf("%s?access_token=%s", sendURL, ak) data, err := util.PostJSON(url, req) if err != nil { return nil, err } res := &Result{} err = util.DecodeWithError(data, res, "SendText") return res, err } //SendNews 发送图文 func (broadcast *Broadcast) SendNews(user *User, mediaID string, ignoreReprint bool) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { return nil, err } req := &sendRequest{ ToUser: nil, MsgType: MsgTypeNews, } if ignoreReprint { req.SendIgnoreReprint = 1 } req.Mpnews = map[string]interface{}{ "media_id": mediaID, } req, sendURL := broadcast.chooseTagOrOpenID(user, req) url := fmt.Sprintf("%s?access_token=%s", sendURL, ak) data, err := util.PostJSON(url, req) if err != nil { return nil, err } res := &Result{} err = util.DecodeWithError(data, res, "SendNews") return res, err } //SendVoice 发送语音 func (broadcast *Broadcast) SendVoice(user *User, mediaID string) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { return nil, err } req := &sendRequest{ ToUser: nil, MsgType: MsgTypeVoice, } req.Voice = map[string]interface{}{ "media_id": mediaID, } req, sendURL := broadcast.chooseTagOrOpenID(user, req) url := fmt.Sprintf("%s?access_token=%s", sendURL, ak) data, err := util.PostJSON(url, req) if err != nil { return nil, err } res := &Result{} err = util.DecodeWithError(data, res, "SendVoice") return res, err } //SendImage 发送图片 func (broadcast *Broadcast) SendImage(user *User, images *Image) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { return nil, err } req := &sendRequest{ ToUser: nil, MsgType: MsgTypeImage, } req.Images = images req, sendURL := broadcast.chooseTagOrOpenID(user, req) url := fmt.Sprintf("%s?access_token=%s", sendURL, ak) data, err := util.PostJSON(url, req) if err != nil { return nil, err } res := &Result{} err = util.DecodeWithError(data, res, "SendImage") return res, err } //SendVideo 发送视频 func (broadcast *Broadcast) SendVideo(user *User, mediaID string, title, description string) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { return nil, err } req := &sendRequest{ ToUser: nil, MsgType: MsgTypeVideo, } req.Voice = map[string]interface{}{ "media_id": mediaID, "title": title, "description": description, } req, sendURL := broadcast.chooseTagOrOpenID(user, req) url := fmt.Sprintf("%s?access_token=%s", sendURL, ak) data, err := util.PostJSON(url, req) if err != nil { return nil, err } res := &Result{} err = util.DecodeWithError(data, res, "SendVideo") return res, err } //SendWxCard 发送卡券 func (broadcast *Broadcast) SendWxCard(user *User, cardID string) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { return nil, err } req := &sendRequest{ ToUser: nil, MsgType: MsgTypeWxCard, } req.WxCard = map[string]interface{}{ "card_id": cardID, } req, sendURL := broadcast.chooseTagOrOpenID(user, req) url := fmt.Sprintf("%s?access_token=%s", sendURL, ak) data, err := util.PostJSON(url, req) if err != nil { return nil, err } res := &Result{} err = util.DecodeWithError(data, res, "SendWxCard") return res, err } //Delete 删除群发消息 func (broadcast *Broadcast) Delete(msgID int64, articleIDx int64) error { ak, err := broadcast.GetAccessToken() if err != nil { return err } req := map[string]interface{}{ "msg_id": msgID, "article_idx": articleIDx, } url := fmt.Sprintf("%s?access_token=%s", deleteSendURL, ak) data, err := util.PostJSON(url, req) if err != nil { return err } return util.DecodeWithCommonError(data, "Delete") } //TODO 发送预览,群发消息状态,发送速度 func (broadcast *Broadcast) chooseTagOrOpenID(user *User, req *sendRequest) (ret *sendRequest, url string) { sendURL := "" if user == nil { req.Filter = map[string]interface{}{ "is_to_all": true, } sendURL = sendURLByTag } else { if user.TagID != 0 { req.Filter = map[string]interface{}{ "is_to_all": false, "tag_id": user.TagID, } sendURL = sendURLByTag } if len(user.OpenID) != 0 { req.ToUser = user.OpenID sendURL = sendURLByOpenID } } return req, sendURL }