Browse Source

添加查研观向小助手的模板消息推送判断处理

xingzai 2 years ago
parent
commit
eb3c857fd3
5 changed files with 319 additions and 2 deletions
  1. 5 1
      controllers/wechat.go
  2. 25 0
      models/wechat.go
  3. 277 0
      services/wechat_send_msg_cygx.go
  4. 10 0
      utils/config.go
  5. 2 1
      utils/constants.go

+ 5 - 1
controllers/wechat.go

@@ -42,7 +42,11 @@ func (this *WechatController) SendTemplateMsg() {
 	}
 
 	go func() {
-		err = services.SendWxTemplateMsg(sendItem)
+		if 	sendItem.RedirectTarget == 3 {
+			err = services.SendWxTemplateMsgCygx(sendItem)
+		}else{
+			err = services.SendWxTemplateMsg(sendItem)
+		}
 		if err != nil {
 			msg := "URI:" + this.Ctx.Input.URI() + "<br/> " + "Params" + string(body) + " <br/>" + "ErrMsg:" + err.Error() + ";<br/> Body:" + string(body) + "<br/>"
 			go alarm_msg.SendAlarmMsg(msg, 1)

+ 25 - 0
models/wechat.go

@@ -88,6 +88,31 @@ func GetWxToken() (item *WxAccessToken, err error) {
 	return
 }
 
+func GetWxTokenCygx() (item *WxAccessToken, err error) {
+	var getUrl string
+	if utils.RunMode == "debug"{
+		getUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + utils.WxAppId + "&secret=" + utils.WxAppSecret
+	}else{
+		getUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + utils.WxAppIdCygx + "&secret=" + utils.WxAppSecretCygx
+	}
+
+	result, err := http.Get(getUrl)
+	if err != nil {
+		utils.FileLog.Info("GetWxToken Err:", err.Error())
+		return
+	}
+	utils.FileLog.Info(fmt.Sprintf("GetWxAccessToken :%s", string(result)))
+	err = json.Unmarshal(result, &item)
+	if err != nil {
+		fmt.Println(fmt.Sprintf("GetWxToken Unmarshal Err:%s", err.Error()))
+		return
+	}
+	if item.Errmsg != "" {
+		utils.FileLog.Info(fmt.Sprintf("GetWxToken fail result:%s", string(result)))
+	}
+	return
+}
+
 // ModifyAccessToken 修改wx_access_token
 func ModifyAccessToken(accessToken string,expiresIn int64)(err error){
 	o := orm.NewOrm()

+ 277 - 0
services/wechat_send_msg_cygx.go

@@ -0,0 +1,277 @@
+package services
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"hongze/hongze_public_api/models"
+	"hongze/hongze_public_api/services/alarm_msg"
+	"hongze/hongze_public_api/utils"
+	"io/ioutil"
+	"net/http"
+	"strings"
+	"time"
+)
+
+
+
+func SendWxTemplateMsgCygx(sendInfo *models.SendWxTemplate) (err error) {
+	var msg string
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("查研观向小助手发送模版消息失败,Err:"+err.Error()+";msg:"+msg, 3)
+			utils.FileLog.Info(fmt.Sprintf("发送模版消息失败,Err:%s,%s", err.Error(), msg))
+		}
+		if msg != "" {
+			utils.FileLog.Info(fmt.Sprintf("发送模版消息失败,msg:%s", msg))
+		}
+	}()
+	utils.FileLog.Info("services SendMsg")
+	fmt.Println("send start")
+	utils.FileLog.Info("send start")
+
+	sendMap := make(map[string]interface{})
+	sendData := make(map[string]interface{})
+	var uniqueCodeStr string
+	if sendInfo.First != "" {
+		sendData["first"] = map[string]interface{}{"value": sendInfo.First, "color": "#173177"}
+		uniqueCodeStr += sendInfo.First
+	}
+
+	if sendInfo.Keyword1 != "" {
+		sendData["keyword1"] = map[string]interface{}{"value": sendInfo.Keyword1, "color": "#173177"}
+		uniqueCodeStr += sendInfo.Keyword1
+	}
+
+	if sendInfo.Keyword2 != "" {
+		sendData["keyword2"] = map[string]interface{}{"value": sendInfo.Keyword2, "color": "#173177"}
+		uniqueCodeStr += sendInfo.Keyword2
+	}
+
+	if sendInfo.Keyword3 != "" {
+		sendData["keyword3"] = map[string]interface{}{"value": sendInfo.Keyword3, "color": "#173177"}
+		uniqueCodeStr += sendInfo.Keyword3
+	}
+
+	if sendInfo.Keyword4 != "" {
+		sendData["keyword4"] = map[string]interface{}{"value": sendInfo.Keyword4, "color": "#173177"}
+		uniqueCodeStr += sendInfo.Keyword4
+	}
+
+	if sendInfo.Remark != "" {
+		sendData["remark"] = map[string]interface{}{"value": sendInfo.Remark, "color": "#173177"}
+		uniqueCodeStr += sendInfo.Remark
+	}
+
+	if sendInfo.TemplateId != "" {
+		sendMap["template_id"] = sendInfo.TemplateId
+		uniqueCodeStr += sendInfo.TemplateId
+	}
+
+	if sendInfo.RedirectUrl != "" {
+		if strings.Contains(sendInfo.RedirectUrl, "http") || strings.Contains(sendInfo.RedirectUrl, "https") || sendInfo.RedirectTarget == 0 {
+			sendMap["url"] = sendInfo.RedirectUrl
+		} else {
+			sendMap["miniprogram"] = map[string]interface{}{"appid": utils.WxCygxAppId, "pagepath": sendInfo.RedirectUrl}
+		}
+		uniqueCodeStr += sendInfo.RedirectUrl
+	}
+
+	sendMap["data"] = sendData
+
+	uniqueCode := utils.MD5(uniqueCodeStr)
+
+	err = sendTemplateMsgCygx(sendMap, sendInfo.OpenIdArr, sendInfo.Resource, uniqueCode, sendInfo.SendType)
+	if err != nil {
+		utils.FileLog.Info("send err:" + err.Error())
+	}
+	fmt.Println("send end")
+	utils.FileLog.Info("send end")
+	return
+}
+
+// sendTemplateMsg 整理openid以及以往历史推送记录,移除已经推送的记录,并开始依次推送
+func sendTemplateMsgCygx(sendMap map[string]interface{}, openIdArr []string, resource, uniqueCode string, sendType int) (err error) {
+	for _, openId := range openIdArr {
+		sendMap["touser"] = openId
+		data, err := json.Marshal(sendMap)
+		if err != nil {
+			fmt.Println("SendTemplateMsgOne Marshal Err:", err.Error())
+			utils.FileLog.Info(fmt.Sprintf("SendTemplateMsgOne Marshal Err:%s", err.Error()))
+			return err
+		}
+		err = toSendTemplateMsgCygx(data, resource, sendType, openId, uniqueCode)
+		if err != nil {
+			fmt.Println("send err:", err.Error())
+			utils.FileLog.Info(fmt.Sprintf("ToSendTemplateMsg Err:%s", err.Error()))
+		}
+	}
+	return
+}
+
+// toSendTemplateMsg 实际推送微信
+func toSendTemplateMsgCygx(data []byte, resource string, sendType int, openId, uniqueCode string) (err error) {
+	utils.FileLog.Info("Send:" + string(data))
+	//获取accessToken
+	accessToken, err,errMsg := getWxAccessTokenCygx()
+	if err != nil {
+		utils.FileLog.Info(fmt.Sprintf("获取Token失败,err:%s,errMsg:%s",err.Error(), errMsg))
+		return
+	}
+	sendUrl := "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken
+
+	client := http.Client{}
+	resp, err := client.Post(sendUrl, "application/json", bytes.NewBuffer(data))
+	if err != nil {
+		return
+	}
+	defer resp.Body.Close()
+
+	body, _ := ioutil.ReadAll(resp.Body)
+	utils.FileLog.Info("Cygx_SendResult:" + string(body))
+	var templateResponse SendTemplateResponse
+	err = json.Unmarshal(body, &templateResponse)
+	if err != nil {
+		utils.FileLog.Info(fmt.Sprintf("SendResult Unmarshal Err:%s", err.Error()))
+		return err
+	}
+	//新增模板消息推送记录
+	{
+		tr := new(models.UserTemplateRecord)
+		tr.OpenId = openId
+		tr.Resource = resource
+		tr.SendData = string(data)
+		tr.Result = string(body)
+		tr.CreateDate = time.Now().Format(utils.FormatDate)
+		tr.CreateTime = time.Now().Format(utils.FormatDateTime)
+		if templateResponse.Errcode == 0 {
+			tr.SendStatus = 1
+		} else {
+			tr.SendStatus = 0
+		}
+		tr.UniqueCode = uniqueCode
+		tr.SendType = sendType
+		go func() {
+			err = models.AddUserTemplateRecord(tr)
+			if err != nil {
+				utils.FileLog.Info(fmt.Sprintf("AddUserTemplateRecord Err:%s", err.Error()))
+			}
+		}()
+	}
+
+	//accessToken过期
+	if templateResponse.Errcode == 40001{
+		//强刷token并重新推送
+		accessToken,err,errMsg = refreshWxAccessTokenCygx()
+		if err != nil{
+			utils.FileLog.Info(fmt.Sprintf("refreshWxAccessToken Err:%s", err.Error()))
+			return err
+		}
+		return toSendTemplateMsgCygx(data, resource, sendType, openId, uniqueCode)
+	}
+
+	//模板消息发送超过当日10万次限制错误处理
+	if templateResponse.Errcode == 45009 {
+		key := "CACHE_SendTemplateMsg_ERR"
+		isExist := utils.Rc.IsExist(key)
+		if isExist == true {
+			return
+		} else {
+			result, _ := json.Marshal(templateResponse)
+			if err != nil {
+				utils.FileLog.Info(fmt.Sprintf("templateResponse Marshal Err:%s", err.Error()))
+				return err
+			}
+			//发送邮件提醒异常
+			go alarm_msg.SendAlarmMsg("模板消息发送超过当日10万次限制,templateResponse = "+string(result), 3)
+			//go utils.SendEmail("异常提醒:", "模板消息发送超过当日10万次限制,templateResponse = "+string(result), utils.EmailSendToUsers)
+			//设置3分钟缓存,不允许重复添加
+			utils.Rc.SetNX(key, 1, 6*time.Minute)
+		}
+		//清空发送次数
+		sendUrl := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/clear_quota?access_token=%s", accessToken)
+		clearData := make(map[string]interface{})
+		clearData["appid"] = utils.WxAppIdCygx
+		clearJson, _ := json.Marshal(clearData)
+		utils.FileLog.Info("clear_quota data:" + string(clearJson))
+		resp, err := client.Post(sendUrl, "application/json", bytes.NewBuffer(clearJson))
+		if err != nil {
+			return err
+		}
+		defer resp.Body.Close()
+		clearBody, err := ioutil.ReadAll(resp.Body)
+		utils.FileLog.Info("clear_quota result:" + string(clearBody))
+		var clearQuotaResponse ClearQuotaResponse
+		err = json.Unmarshal(clearBody, &clearQuotaResponse)
+		if err != nil {
+			utils.FileLog.Info(fmt.Sprintf("clearQuotaResponse Unmarshal Err:%s", err.Error()))
+			return err
+		}
+		//if clearQuotaResponse.Errcode == 0 {
+		//	//发送邮件解决异常
+		//	go alarm_msg.SendAlarmMsg("异常已解决,自动清理限制接口,调用成功", 3)
+		//	//go utils.SendEmail("异常已解决:", "自动清理限制接口,调用成功", utils.EmailSendToUsers)
+		//	//重新推送一次
+		//	toSendTemplateMsgCygx(data, resource, sendType, openId, uniqueCode)
+		//}
+	}
+	return
+}
+
+// getWxAccessToken 获取微信token
+func getWxAccessTokenCygx()(accessToken string,err error,errMsg string){
+	var tokenKey string
+	if utils.RunMode == "debug"{
+		tokenKey = utils.CACHE_WX_ACCESS_TOKEN_HZ
+	}else{
+		tokenKey = utils.CACHE_WX_ACCESS_TOKEN_CYGX
+	}
+	accessToken, err = utils.Rc.RedisString(tokenKey)
+	if accessToken != ""{
+		return
+	}
+
+	//缓存中没有取到数据,那么需要去强制刷新新的accessToken
+	return refreshWxAccessTokenCygx()
+}
+
+// refreshWxAccessToken 强制刷新微信token
+func refreshWxAccessTokenCygx()(accessToken string,err error,errMsg string){
+	fmt.Println("强制刷新微信token")
+	//调用微信官方接口获取新的accessToken
+	wxAccessToken, tmpErr := models.GetWxTokenCygx()
+	if tmpErr != nil {
+		err = tmpErr
+		errMsg = "通过微信接口获取accessToken失败 Err:" + err.Error()
+		return
+	}
+	//如果没有token数据
+	if wxAccessToken.AccessToken == "" {
+		errMsg = "微信返回的accessToken异常: Err:" + wxAccessToken.Errmsg
+		err = errors.New(errMsg)
+		return
+	}
+	accessToken = wxAccessToken.AccessToken
+	//更新mysql的accessToken(如果是debug环境的话)
+	var tokenKey string
+	if utils.RunMode == "debug"{
+		expiresIn := time.Now().Add(time.Duration(wxAccessToken.ExpiresIn) * time.Second).Unix()
+		err = models.ModifyAccessToken(wxAccessToken.AccessToken,expiresIn)
+		if err!=nil{
+			errMsg = "更新mysql中的accessToken失败 Err:" + err.Error()
+			return
+		}
+		tokenKey = utils.CACHE_WX_ACCESS_TOKEN_HZ
+	}else{
+		tokenKey = utils.CACHE_WX_ACCESS_TOKEN_CYGX
+	}
+	//更新redis的accessToken(过期时间提前十分钟)
+	redisTimeExpire := time.Duration(wxAccessToken.ExpiresIn - 600) * time.Second
+	err = utils.Rc.Put(tokenKey,accessToken,redisTimeExpire)
+	if err!=nil{
+		errMsg = "更新redis中的accessToken失败 Err:" + err.Error()
+		return
+	}
+	return
+}

+ 10 - 0
utils/config.go

@@ -21,6 +21,8 @@ var (
 	WxId                string //微信原始ID
 	WxAppId             string
 	WxAppSecret         string
+	WxAppIdCygx             string
+	WxAppSecretCygx         string
 )
 
 // LibreOfficePath LibreOfficePath的地址
@@ -50,6 +52,7 @@ func init() {
 		}
 
 		WxRelease()
+		WxReleaseCygx() // 查研观向小助手
 	}
 
 	config, err := web.AppConfig.GetSection(RunMode)
@@ -95,4 +98,11 @@ func WxRelease() {
 	WxAppId = "wx4a844c734d8c8e56"
 	WxAppSecret = "26c586e7ccb3c575433f0f37797b3eeb"
 	WxId = "gh_b67e0049fb8c"
+}
+
+
+//查研观向生产环境模板消息
+func WxReleaseCygx() {
+	WxAppIdCygx = "wxb7cb8a15abad5b8e"
+	WxAppSecretCygx = "f425ba2863084249722af1e2a5cfffd3"
 }

+ 2 - 1
utils/constants.go

@@ -40,9 +40,10 @@ const (
 const (
 	WxCrmAppId = `wx67b68e39913e511e` //随手办公
 	WxYbAppId  = `wxb059c872d79b9967` //弘则研报小程序
-	WxCygxAppId  = `wxcc32b61f96720d2f` //弘则研报小程序
+	WxCygxAppId  = `wxcc32b61f96720d2f` //查研观向小程序
 )
 // 缓存key
 const (
 	CACHE_WX_ACCESS_TOKEN_HZ         = "wx:accesstoken:hzyj"                  //弘则研究公众号 微信accessToken
+	CACHE_WX_ACCESS_TOKEN_CYGX         = "xygxxzs_wxtoken"                  //查研观向小助手公众号 微信accessToken
 )