| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- 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"
- previewSendURL = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"
- massStatusSendURL = "https://api.weixin.qq.com/cgi-bin/message/mass/get"
- getSpeedSendURL = "https://api.weixin.qq.com/cgi-bin/message/mass/speed/get"
- setSpeedSendURL = "https://api.weixin.qq.com/cgi-bin/message/mass/speed/set"
- )
- // 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
- preview bool
- }
- // NewBroadcast new
- func NewBroadcast(ctx *context.Context) *Broadcast {
- return &Broadcast{ctx, false}
- }
- // 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"`
- MsgStatus string `json:"msg_status"`
- }
- // SpeedResult 群发速度返回结果
- type SpeedResult struct {
- util.CommonError
- Speed int64 `json:"speed"`
- RealSpeed int64 `json:"realspeed"`
- }
- // 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"`
- // 发送视频
- Mpvideo map[string]interface{} `json:"mpvideo,omitempty"`
- // 发送图片 - 预览使用
- Image map[string]interface{} `json:"image,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,
- }
- if broadcast.preview {
- req.Image = map[string]interface{}{
- "media_id": images.MediaIDs[0],
- }
- } else {
- 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.Mpvideo = 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")
- }
- // Preview 预览
- func (broadcast *Broadcast) Preview() *Broadcast {
- broadcast.preview = true
- return broadcast
- }
- // GetMassStatus 获取群发状态
- func (broadcast *Broadcast) GetMassStatus(msgID string) (*Result, error) {
- ak, err := broadcast.GetAccessToken()
- if err != nil {
- return nil, err
- }
- req := map[string]interface{}{
- "msg_id": msgID,
- }
- url := fmt.Sprintf("%s?access_token=%s", massStatusSendURL, ak)
- data, err := util.PostJSON(url, req)
- if err != nil {
- return nil, err
- }
- res := &Result{}
- err = util.DecodeWithError(data, res, "GetMassStatus")
- return res, err
- }
- // GetSpeed 获取群发速度
- func (broadcast *Broadcast) GetSpeed() (*SpeedResult, error) {
- ak, err := broadcast.GetAccessToken()
- if err != nil {
- return nil, err
- }
- req := map[string]interface{}{}
- url := fmt.Sprintf("%s?access_token=%s", getSpeedSendURL, ak)
- data, err := util.PostJSON(url, req)
- if err != nil {
- return nil, err
- }
- res := &SpeedResult{}
- err = util.DecodeWithError(data, res, "GetSpeed")
- return res, err
- }
- // SetSpeed 设置群发速度
- func (broadcast *Broadcast) SetSpeed(speed int) (*SpeedResult, error) {
- ak, err := broadcast.GetAccessToken()
- if err != nil {
- return nil, err
- }
- req := map[string]interface{}{
- "speed": speed,
- }
- url := fmt.Sprintf("%s?access_token=%s", setSpeedSendURL, ak)
- data, err := util.PostJSON(url, req)
- if err != nil {
- return nil, err
- }
- res := &SpeedResult{}
- err = util.DecodeWithError(data, res, "SetSpeed")
- return res, err
- }
- 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 broadcast.preview {
- // 预览 默认发给第一个用户
- if len(user.OpenID) != 0 {
- req.ToUser = user.OpenID[0]
- sendURL = previewSendURL
- }
- } 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
- }
|