package services import ( "encoding/json" "errors" "eta/eta_mini_crm_ht/models" "eta/eta_mini_crm_ht/utils" "fmt" "io" "net/http" "strings" "time" ) var ( TemplateMsgSendUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s" TemplateMsgClearQuotaUrl = "https://api.weixin.qq.com/cgi-bin/clear_quota?access_token=%s" ) type TemplateMsgSendClient struct { AccessToken string Data []byte } type SendTemplateResponse struct { Errcode int `json:"errcode"` Errmsg string `json:"errmsg"` MsgID int `json:"msgid"` } type ClearQuotaResponse struct { Errcode int `json:"errcode"` Errmsg string `json:"errmsg"` } type OpenIdList struct { OpenId string UserId int FollowingGzh bool } //// TemplateMsgSendClient.ClearQuota 清除发送超过当日10万次限制 //func (c *TemplateMsgSendClient) ClearQuota() (result *ClearQuotaResponse, err error) { // key := "CACHE_SendTemplateMsg_ERR" // exists := utils.Rc.IsExist(key) // if exists { // return // } // _ = utils.Rc.SetEX(key, 1, 6*time.Minute) // // sendUrl := fmt.Sprintf(TemplateMsgClearQuotaUrl, c.AccessToken) // client := http.Client{} // clearData := make(map[string]interface{}) // clearData["appid"] = utils.HT_WX_APPID // clearJson, _ := json.Marshal(clearData) // resp, err := client.Post(sendUrl, "application/json", bytes.NewBuffer(clearJson)) // if err != nil { // return // } // defer func() { // _ = resp.Body.Close() // }() // clearBody, err := io.ReadAll(resp.Body) // err = json.Unmarshal(clearBody, &result) // return //} //// TemplateMsgSendClient.SendMsg 推送消息 //func (c *TemplateMsgSendClient) SendMsg() (sendRes *SendTemplateResponse, err error) { // // 请求接口 // sendUrl := fmt.Sprintf(TemplateMsgSendUrl, c.AccessToken) // client := http.Client{} // resp, err := client.Post(sendUrl, "application/json", bytes.NewBuffer(c.Data)) // if err != nil { // return // } // defer func() { // _ = resp.Body.Close() // }() // body, _ := io.ReadAll(resp.Body) // if err = json.Unmarshal(body, &sendRes); err != nil { // return // } // // 模板消息发送超过当日10万次限制错误处理 // if sendRes.Errcode == 45009 { // // 发送提示邮件 // // go alarm_msg.SendAlarmMsg("模板消息发送超过当日10万次限制, SendTemplateResponse: "+string(body), 3) // // 清理限制 // clearRes, e := c.ClearQuota() // if e != nil { // err = e // return // } // if clearRes.Errcode != 0 { // clearJson, er := json.Marshal(clearRes) // if er != nil { // return nil, er // } // fmt.Println("自动清理模板消息限制接口, 调用失败, ClearQuotaResponse: " + string(clearJson)) // // go alarm_msg.SendAlarmMsg("自动清理模板消息限制接口, 调用失败, ClearQuotaResponse: "+string(clearJson), 3) // return // } // // 发送成功邮件 // // go alarm_msg.SendAlarmMsg("自动清理模板消息限制接口, 调用成功", 1) // // 重新推送 // go func() { // _, e := c.SendMsg() // if e != nil { // return // // reSendJson, _ := json.Marshal(reSend) // // alarm_msg.SendAlarmMsg("重新推送模板消息失败, SendTemplateResponse: "+string(reSendJson), 3) // } // }() // } // if sendRes.Errcode != 0 { // err = errors.New("推送模板消息失败, SendTemplateResponse: " + string(body)) // } // return //} // AddUserTemplateRecord 新增模板消息推送记录 func AddUserTemplateRecord(userId, sendStatus int, sendType string, openid, sendData, result string) (err error) { item := &models.UserTemplateRecord{ UserId: userId, OpenId: openid, SendData: sendData, Result: result, CreateDate: time.Now().Format(utils.FormatDate), CreateTime: time.Now().Format(utils.FormatDateTime), SendStatus: sendStatus, SendType: sendType, } err = item.Insert() return } // SendMultiTemplateMsg 推送模板消息至多个用户 func SendMultiTemplateMsg(templateData SendWxTemplate, items []*OpenIdList, Id int, sendType string) (err error) { if err != nil { utils.FileLog.Info("获取微信token失败, Err:" + err.Error()) return } var path string switch sendType { case "report": path = "/pages-report/reportDetail/index?id=%d" case "audio": path = "/pages-media/audioDetail/index?id=%d" case "video": path = "/pages-media/videoDetail/index?id=%d" default: return errors.New("非法的消息类型") } templateData.WxAppId = utils.HT_WX_APPID templateData.TemplateId = utils.TEMPLATE_ID_BY_PRODUCT templateData.RedirectUrl = fmt.Sprintf(path, Id) templateData.Resource = templateData.RedirectUrl templateData.SendType = 8 for _, item := range items { templateData.OpenIdArr = append(templateData.OpenIdArr, item.OpenId) } templateData.RedirectTarget = 5 return sendMsg(templateData) } type SendWxTemplate struct { WxAppId string `description:"公众号appId"` First string `description:"模板消息first字段"` Keyword1 string `description:"模板消息keyword1字段"` Keyword2 string `description:"模板消息keyword2字段"` Keyword3 string `description:"模板消息keyword3字段"` Keyword4 string `description:"模板消息keyword4字段"` Keyword5 string `description:"模板消息keyword5字段"` Productname string `description:"模板消息productname字段"` Date string `description:"模板消息date字段"` Remark string `description:"模板消息remark字段"` TemplateId string `description:"模板id"` RedirectUrl string `description:"跳转地址"` RedirectTarget int `description:"小程序跳转目标:1:弘则研报小程序,2:随手办公小程序,3:查研观向"` Resource string `description:"资源唯一标识"` SendType int `description:"发送的消息类型:1:报告,2:指标更新提醒,3:审批通知,4:销售领取客户通知,5:活动取消通知,6活动更改时间通知,7:关注的作者发布报告通知,8:发送日报(周报、双周报、月报)模板消息,9:活动预约/报名时间通知"` OpenIdArr []string `description:"消息接收者openid"` } func sendMsg(template SendWxTemplate) (err error) { if utils.ETA_PUB_URL == `` { // 找不到推送服务 return } // 设置请求 URL // 设置 POST 请求的数据 data, err := json.Marshal(template) if err != nil { utils.FileLog.Error("发送消息模板失败,请求data json序列化失败,err:%v", err) } body := io.NopCloser(strings.NewReader(string(data))) req, _ := http.NewRequest("POST", utils.ETA_PUB_URL, body) if err != nil { fmt.Println("发送模板消息失败,创建请求失败:", err) return } // 设置 Content-Type req.Header.Set("Authorization", utils.ETA_PUB_TOKEN) req.Header.Set("Content-Type", "application/json;charset=utf-8") // 发送 POST 请求 client := &http.Client{} resp, err := client.Do(req) if err != nil { utils.FileLog.Error("发送消息模板失败,请求失败,err:%v", err) return } defer resp.Body.Close() // 处理响应 repBody, err := io.ReadAll(resp.Body) if err != nil { return err } if resp.StatusCode != http.StatusOK { utils.FileLog.Error("发送消息模板失败,请求失败,err:%v", string(repBody)) return } utils.FileLog.Info("发送消息模板成功,请求成功,body:%v", string(repBody)) return }