Browse Source

新增微信模板消息推送

longyu 2 years ago
parent
commit
58280dad55

+ 8 - 4
controllers/base_auth.go

@@ -40,11 +40,15 @@ func (this *BaseAuthController) Prepare() {
 			}
 
 			if authorization == "" {
+				this.JSON(models.BaseResponse{Ret: 408, Msg: "签名为空!", ErrMsg: "签名错误,请重新授权:Token is empty or account is empty"}, false, false)
+				this.StopRun()
+				return
+			}
+			if authorization != utils.Authorization {
 				this.JSON(models.BaseResponse{Ret: 408, Msg: "签名错误,请重新授权!", ErrMsg: "签名错误,请重新授权:Token is empty or account is empty"}, false, false)
 				this.StopRun()
 				return
 			}
-
 		} else {
 			this.JSON(models.BaseResponse{Ret: 408, Msg: "请求异常,请联系客服!", ErrMsg: "POST之外的请求,暂不支持"}, false, false)
 			this.StopRun()
@@ -80,8 +84,8 @@ func (c *BaseAuthController) ServeJSON(encoding ...bool) {
 			requestBody = string(c.Ctx.Input.RequestBody)
 		}
 		if baseRes.Ret != 200 && baseRes.IsSendEmail {
-			msg:="URI:"+c.Ctx.Input.URI()+"<br/> "+"Params"+requestBody+" <br/>"+"ErrMsg:"+baseRes.ErrMsg+";<br/>Msg:"+baseRes.Msg+";<br/> Body:"+string(body)+"<br/>"
-			go alarm_msg.SendAlarmMsg(msg,3)
+			msg := "URI:" + c.Ctx.Input.URI() + "<br/> " + "Params" + requestBody + " <br/>" + "ErrMsg:" + baseRes.ErrMsg + ";<br/>Msg:" + baseRes.Msg + ";<br/> Body:" + string(body) + "<br/>"
+			go alarm_msg.SendAlarmMsg(msg, 3)
 		}
 	}
 	c.JSON(c.Data["json"], hasIndent, hasEncoding)
@@ -113,4 +117,4 @@ func (c *BaseAuthController) JSON(data interface{}, hasIndent bool, coding bool)
 		content = []byte(utils.StringsToJSON(string(content)))
 	}
 	return c.Ctx.Output.Body(content)
-}
+}

+ 43 - 0
controllers/wechat.go

@@ -0,0 +1,43 @@
+package controllers
+
+import (
+	"encoding/json"
+	"hongze/hongze_public_api/models"
+	"hongze/hongze_public_api/services"
+	"hongze/hongze_public_api/services/alarm_msg"
+)
+
+//发送模板消息
+type WechatController struct {
+	BaseAuthController
+}
+
+// @Title 推送模板消息
+// @Description 推送模板消息
+// @Success 200 新增成功
+// @router /send_template_msg [post]
+func (this *WechatController) SendTemplateMsg() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	body := this.Ctx.Input.RequestBody
+	sendItem := new(models.SendWxTemplate)
+	err := json.Unmarshal(body, &sendItem)
+	if err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	go func() {
+		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)
+		}
+	}()
+	br.Ret = 200
+	br.Msg = "推送成功"
+	return
+}

+ 23 - 0
models/user_template_record.go

@@ -0,0 +1,23 @@
+package models
+
+import "github.com/beego/beego/v2/client/orm"
+
+type UserTemplateRecord struct {
+	Id         int `orm:"column(id);pk"`
+	UserId     int
+	OpenId     string
+	Resource   string
+	SendData   string
+	Result     string
+	CreateDate string
+	CreateTime string
+	SendStatus int
+	SendType   int
+}
+
+//添加banner
+func AddUserTemplateRecord(item *UserTemplateRecord) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Insert(item)
+	return
+}

+ 88 - 0
models/wechat.go

@@ -0,0 +1,88 @@
+package models
+
+import (
+	"encoding/json"
+	"fmt"
+	"time"
+
+	"hongze/hongze_public_api/utils"
+
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/http"
+)
+
+type WxToken struct {
+	AccessToken string
+	ExpiresIn   int64
+	Id          int64
+}
+
+func GetWxAccessToken() (accessTokenStr string, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM wx_token LIMIT 1`
+	wxToken := new(WxToken)
+	err = o.Raw(sql).QueryRow(&wxToken)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		utils.FileLog.Info("Get wxToken Err:", err.Error())
+		return
+	}
+	//Token不存在
+	if wxToken == nil {
+		fmt.Println("wxToken is empty")
+		accessToken, err := GetWxToken()
+		if err != nil {
+			return "", err
+		}
+		if accessToken.AccessToken != "" {
+			expiresIn := time.Now().Add(time.Duration(accessToken.ExpiresIn) * time.Second).Unix()
+			addSql := "insert into wx_token (access_token,expires_in) values (?,?)"
+			_, err = o.Raw(addSql, accessToken.AccessToken, expiresIn).Exec()
+			accessTokenStr = accessToken.AccessToken
+		}
+		return accessTokenStr, err
+	} else {
+		//判断token是否过期
+		if time.Now().Unix() > wxToken.ExpiresIn {
+			accessToken, err := GetWxToken()
+			if err != nil {
+				return "", err
+			}
+			if accessToken.AccessToken != "" {
+				expiresIn := time.Now().Add(time.Duration(accessToken.ExpiresIn) * time.Second).Unix()
+				updateSql := "update wx_token set access_token = ?,expires_in = ? "
+				_, err = o.Raw(updateSql, accessToken.AccessToken, expiresIn).Exec()
+				accessTokenStr = accessToken.AccessToken
+				fmt.Println("更新 TOKEN:", err)
+			}
+			return accessTokenStr, err
+		} else {
+			return wxToken.AccessToken, nil
+		}
+	}
+	return
+}
+
+type WxAccessToken struct {
+	AccessToken string `json:"access_token"`
+	ExpiresIn   int    `json:"expires_in"`
+	Errcode     int    `json:"errcode"`
+	Errmsg      string `json:"errmsg"`
+}
+
+func GetWxToken() (item *WxAccessToken, err error) {
+	getUrl := "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + utils.WxAppId + "&secret=" + utils.WxAppSecret
+	result, err := http.Get(getUrl)
+	if err != nil {
+		utils.FileLog.Info("GetWxToken Err:", err.Error())
+		return
+	}
+	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
+}

+ 219 - 0
models/wechat_send_msg.go

@@ -0,0 +1,219 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"hongze/hongze_public_api/utils"
+	"strings"
+)
+
+type OpenIdList struct {
+	OpenId string
+	UserId int
+}
+
+func GetOpenIdList() (items []*OpenIdList, err error) {
+	sql := `SELECT DISTINCT ur.open_id,wu.user_id FROM wx_user AS wu 
+          INNER JOIN company AS c ON c.company_id = wu.company_id 
+          INNER JOIN company_product AS d ON c.company_id=d.company_id
+		INNER join user_record  as ur on wu.user_id=ur.user_id
+          WHERE ur.open_id != "" AND ur.subscribe=1 and ur.create_platform=1 AND  d.status IN('正式','试用','永续') `
+	_, err = orm.NewOrm().Raw(sql).QueryRows(&items)
+	return
+}
+
+func GetOpenIdListByMobile(mobile string) (items []*OpenIdList, err error) {
+	sql := `SELECT DISTINCT ur.open_id,wu.user_id FROM wx_user AS wu 
+          INNER JOIN company AS c ON c.company_id = wu.company_id 
+          INNER join user_record  as ur on wu.user_id=ur.user_id
+          WHERE ur.open_id != "" AND ur.subscribe=1 and ur.create_platform=1 AND wu.mobile=? `
+
+	_, err = orm.NewOrm().Raw(sql, mobile).QueryRows(&items)
+	return
+}
+
+//获取预约活动的用户的openID
+func GetActivityOpenIdList(activityId int) (items []*OpenIdList, err error) {
+	sql := `SELECT DISTINCT cr.open_id,u.user_id
+			FROM
+			cygx_my_schedule AS m
+			INNER JOIN user_record AS u ON u.bind_account = m.mobile 
+			INNER JOIN cygx_user_record AS cr ON cr.union_id = u.union_id 
+			WHERE m.activity_id = ? AND u.create_platform = 4 `
+	_, err = orm.NewOrm().Raw(sql, activityId).QueryRows(&items)
+	return
+}
+
+//获取预约活动的用户的openID测试环境
+func GetActivityOpenIdListByDeBug(activityId int) (items []*OpenIdList, err error) {
+	sql := `SELECT
+			u.open_id,
+			u.user_id 
+		FROM
+			cygx_my_schedule AS s
+			INNER JOIN wx_user AS wx ON wx.user_id = s.user_id
+			INNER JOIN user_record AS u ON u.bind_account = wx.mobile
+			INNER JOIN company_product AS p ON p.company_id = wx.company_id 
+		WHERE
+			s.activity_id = ? 
+			AND u.create_platform = 1 
+			AND p.STATUS IN ( '正式', '试用', '永续' ) 
+		GROUP BY
+			u.open_id`
+	_, err = orm.NewOrm().Raw(sql, activityId).QueryRows(&items)
+	return
+}
+
+//获取预约活动的用户的openID
+func GetActivitySpecialOpenIdList() (items []*OpenIdList, err error) {
+	sql := `SELECT DISTINCT cr.open_id,u.user_id
+			FROM
+			cygx_user_follow_special AS m
+			INNER JOIN user_record AS u ON u.bind_account = m.mobile 
+			INNER JOIN cygx_user_record AS cr ON cr.union_id = u.union_id 
+			WHERE  u.create_platform = 4 `
+	_, err = orm.NewOrm().Raw(sql).QueryRows(&items)
+	return
+}
+
+//获取预约活动的用户的openID测试环境
+func GetActivitySpecialOpenIdListByDeBug() (items []*OpenIdList, err error) {
+	sql := `SELECT
+			u.open_id,
+			u.user_id 
+		FROM
+			cygx_user_follow_special AS s
+			INNER JOIN wx_user AS wx ON wx.user_id = s.user_id
+			INNER JOIN user_record AS u ON u.bind_account = wx.mobile
+			INNER JOIN company_product AS p ON p.company_id = wx.company_id 
+		WHERE
+			u.create_platform = 1 
+			AND p.STATUS IN ( '正式', '试用', '永续' ) 
+		GROUP BY
+			u.open_id`
+	_, err = orm.NewOrm().Raw(sql).QueryRows(&items)
+	return
+}
+
+//获取关注作者的用户的openID
+func GetFollowDepartmentOpenIdList(departmentId int) (items []*OpenIdList, err error) {
+	sql := `SELECT cr.open_id,u.user_id
+			FROM
+				cygx_article_department_follow AS f
+				INNER JOIN user_record AS u ON u.bind_account = f.mobile
+				INNER JOIN wx_user AS wx ON wx.user_id = f.user_id
+				INNER JOIN company_product AS p ON p.company_id = wx.company_id 
+				INNER JOIN cygx_user_record AS cr ON cr.union_id = u.union_id 
+			WHERE
+				f.department_id = ?
+				AND u.create_platform = 4 
+				AND f.type = 1 
+				AND p.status IN ('正式','试用','永续')
+			GROUP BY
+				cr.open_id `
+	_, err = orm.NewOrm().Raw(sql, departmentId).QueryRows(&items)
+	return
+}
+
+//获取关注作者的用户的openID测试环境
+func GetFollowDepartmentOpenIdListByDeBug(departmentId int) (items []*OpenIdList, err error) {
+	sql := `SELECT
+			u.open_id,
+			u.user_id 
+		FROM
+			cygx_article_department_follow AS f
+			INNER JOIN wx_user AS wx ON wx.user_id = f.user_id
+			INNER JOIN user_record AS u ON u.bind_account = wx.mobile
+			INNER JOIN company_product AS p ON p.company_id = wx.company_id
+		WHERE
+			f.department_id = ? 
+			AND u.create_platform = 1
+			AND f.type = 1 
+			AND p.STATUS IN ( '正式', '试用', '永续' ) 
+		GROUP BY
+			u.open_id`
+	_, err = orm.NewOrm().Raw(sql, departmentId).QueryRows(&items)
+	return
+}
+
+//获取关注产业的用户的openID
+func GetFollowindustrialOpenIdList(industrialManagementId int) (items []*OpenIdList, err error) {
+	sql := `SELECT cr.open_id,u.user_id
+			FROM
+			cygx_industry_fllow AS f
+			INNER JOIN wx_user AS wx ON wx.user_id = f.user_id
+			INNER JOIN user_record AS u ON u.bind_account = wx.mobile 
+			INNER JOIN cygx_user_record AS cr ON cr.union_id = u.union_id 
+			WHERE
+			f.industrial_management_id = ? 
+			AND u.create_platform = 4 
+			AND f.type = 1 GROUP BY cr.open_id `
+	_, err = orm.NewOrm().Raw(sql, industrialManagementId).QueryRows(&items)
+	return
+}
+
+//获取关注产业的用户的openID 测试环境
+func GetFollowindustrialOpenIdListByDeBug(industrialManagementId int) (items []*OpenIdList, err error) {
+	sql := `SELECT
+			u.open_id,
+			u.user_id 
+		FROM
+			cygx_industry_fllow AS f
+			INNER JOIN wx_user AS wx ON wx.user_id = f.user_id
+			INNER JOIN user_record AS u ON u.bind_account = wx.mobile
+		WHERE
+			f.industrial_management_id = ? 
+			AND u.create_platform = 1 
+			AND u.bind_account != ""
+			AND f.type = 1 
+		GROUP BY
+			u.open_id`
+	_, err = orm.NewOrm().Raw(sql, industrialManagementId).QueryRows(&items)
+	return
+}
+
+// GetUserOpenidListByUserIds 根据用户id字符串集合来获取他的openid列表集合
+func GetUserOpenidListByUserIds(userIdStr []string) (list []*OpenIdList, err error) {
+	if len(userIdStr) <= 0 {
+		return
+	}
+	sql := `SELECT open_id,u.user_id FROM user_record WHERE user_id in (` + strings.Join(userIdStr, ",") + `) and create_platform = 1`
+	_, err = orm.NewOrm().Raw(sql).QueryRows(&list)
+	return
+}
+
+func GetAdminOpenIdByMobile(mobile string) (items []*OpenIdList, err error) {
+	sql := `SELECT DISTINCT ur.open_id,wu.user_id FROM wx_user AS wu 
+          INNER JOIN company AS c ON c.company_id = wu.company_id 
+          INNER join user_record  as ur on wu.user_id=ur.user_id
+          WHERE ur.open_id != "" and ur.create_platform=1 AND wu.mobile=? `
+	_, err = orm.NewOrm().Raw(sql, mobile).QueryRows(&items)
+	return
+}
+
+//根据手机号获取用户的openid查研观向小助手专用
+func GetUserRecordListByMobile(platform int, bindAccount string) (items []*OpenIdList, err error) {
+	var sql string
+	if utils.RunMode == "release" {
+		sql = `SELECT cr.open_id FROM user_record  as u 
+			INNER JOIN cygx_user_record AS cr ON cr.union_id = u.union_id 
+			WHERE create_platform=? AND bind_account IN (` + bindAccount + `)`
+	} else {
+		platform = 1
+		sql = `SELECT open_id FROM	user_record  WHERE create_platform =? AND bind_account IN (` + bindAccount + `)`
+	}
+	_, err = orm.NewOrm().Raw(sql, platform).QueryRows(&items)
+	return
+}
+
+type SendWxTemplate struct {
+	First       string   `description:"模板消息first字段"`
+	Keyword1    string   `description:"模板消息keyword1字段"`
+	Keyword2    string   `description:"模板消息keyword2字段"`
+	Keyword3    string   `description:"模板消息keyword3字段"`
+	Keyword4    string   `description:"模板消息keyword4字段"`
+	TemplateId  string   `description:"模板id"`
+	RedirectUrl string   `description:"跳转地址"`
+	Resource    string   `description:"资源唯一标识"`
+	SendType    int      `description:"发送的消息类型:1:报告,2:指标更新提醒,3:审批通知,4:销售领取客户通知,5:活动取消通知,6活动更改时间通知,7:关注的作者发布报告通知,8:发送日报(周报、双周报、月报)模板消息,9:活动预约/报名时间通知"`
+	OpenIdArr   []string `description:"消息接收者openid"`
+}

+ 5 - 0
routers/router.go

@@ -20,6 +20,11 @@ func init() {
 				&controllers.ImageController{},
 			),
 		),
+		beego.NSNamespace("/wechat",
+			beego.NSInclude(
+				&controllers.WechatController{},
+			),
+		),
 	)
 	beego.AddNamespace(ns)
 }

+ 3 - 0
services/wechat.go

@@ -0,0 +1,3 @@
+package services
+
+

+ 206 - 0
services/wechat_send_msg.go

@@ -0,0 +1,206 @@
+package services
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"hongze/hongze_public_api/models"
+	"hongze/hongze_public_api/services/alarm_msg"
+	"hongze/hongze_public_api/utils"
+	"io/ioutil"
+	"net/http"
+	"time"
+)
+
+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"`
+}
+
+func SendWxTemplateMsg(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("%s", "services SendMsg")
+
+	accessToken, err := models.GetWxAccessToken()
+	if err != nil {
+		msg = "GetWxAccessToken Err:" + err.Error()
+		return
+	}
+	if accessToken == "" {
+		msg = "accessToken is empty"
+		return
+	}
+
+	sendUrl := "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken
+	fmt.Println("send start")
+	utils.FileLog.Info("send start")
+
+	sendMap := make(map[string]interface{})
+	sendData := make(map[string]interface{})
+
+	if sendInfo.First != "" {
+		sendData["first"] = map[string]interface{}{"value": sendInfo.First, "color": "#173177"}
+	}
+
+	if sendInfo.Keyword1 != "" {
+		sendData["keyword1"] = map[string]interface{}{"value": sendInfo.Keyword1, "color": "#173177"}
+	}
+
+	if sendInfo.Keyword2 != "" {
+		sendData["keyword2"] = map[string]interface{}{"value": sendInfo.Keyword2, "color": "#173177"}
+	}
+
+	if sendInfo.Keyword3 != "" {
+		sendData["keyword3"] = map[string]interface{}{"value": sendInfo.Keyword3, "color": "#173177"}
+	}
+
+	if sendInfo.Keyword4 != "" {
+		sendData["keyword4"] = map[string]interface{}{"value": sendInfo.Keyword4, "color": "#173177"}
+	}
+
+	if sendInfo.TemplateId != "" {
+		sendMap["template_id"] = sendInfo.TemplateId
+	}
+
+	if sendInfo.RedirectUrl != "" {
+		sendMap["url"] = sendInfo.RedirectUrl
+	}
+	sendMap["data"] = sendData
+	sendTemplateMsg(sendUrl, sendMap, sendInfo.OpenIdArr, sendInfo.Resource, sendInfo.SendType)
+	//}
+	fmt.Println("send end")
+	utils.FileLog.Info("send end")
+	return
+}
+
+func sendTemplateMsg(sendUrl string, sendMap map[string]interface{}, openIdArr []string, resource 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 = toSendTemplateMsg(sendUrl, data, resource, sendType, openId)
+		if err != nil {
+			fmt.Println("send err:", err.Error())
+			utils.FileLog.Info(fmt.Sprintf("ToSendTemplateMsg Err:%s", err.Error()))
+		}
+	}
+	return
+}
+
+func toSendTemplateMsg(sendUrl string, data []byte, resource string, sendType int, openId string) (err error) {
+	var msg string
+	utils.FileLog.Info("Send:" + string(data))
+	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("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.SendType = sendType
+		go func() {
+			err = models.AddUserTemplateRecord(tr)
+			if err != nil {
+				utils.FileLog.Info(fmt.Sprintf("AddUserTemplateRecord Err:%s", err.Error()))
+			}
+		}()
+	}
+	accessToken, err := models.GetWxAccessToken()
+	if err != nil {
+		msg = "GetWxAccessToken Err:" + err.Error()
+		utils.FileLog.Info("获取Token失败,msg:" + msg)
+		return
+	}
+	if accessToken == "" {
+		msg = "accessToken is empty"
+		utils.FileLog.Info("accessToken为空,msg:" + msg)
+		return
+	}
+	//模板消息发送超过当日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.WxAppId
+		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)
+			//重新推送一次
+			toSendTemplateMsg(sendUrl, data, resource, sendType, openId)
+		}
+	}
+	return
+}

+ 23 - 0
utils/common.go

@@ -13,6 +13,7 @@ import (
 	"io"
 	"math"
 	"math/rand"
+	"net"
 	"net/http"
 	"os"
 	"os/exec"
@@ -735,3 +736,25 @@ func ConvertNumToCny(num float64) (str string, err error) {
 	str = reg.ReplaceAllString(str, "零")
 	return
 }
+
+
+func GetLocalIP() (ip string, err error) {
+	addrs, err := net.InterfaceAddrs()
+	if err != nil {
+		return
+	}
+	for _, addr := range addrs {
+		ipAddr, ok := addr.(*net.IPNet)
+		if !ok {
+			continue
+		}
+		if ipAddr.IP.IsLoopback() {
+			continue
+		}
+		if !ipAddr.IP.IsGlobalUnicast() {
+			continue
+		}
+		return ipAddr.IP.String(), nil
+	}
+	return
+}

+ 142 - 0
utils/config.go

@@ -1,12 +1,49 @@
 package utils
 
 import (
+	"fmt"
 	beeLogger "github.com/beego/bee/v2/logger"
 	"github.com/beego/beego/v2/server/web"
+	"github.com/rdlucklib/rdluck_tools/cache"
 )
 
 var (
 	RunMode        string //运行模式
+	MYSQL_URL             string //数据库连接
+
+	REDIS_CACHE string       //缓存地址
+	Rc          *cache.Cache //redis缓存
+	Re          error        //redis错误
+)
+
+//微信配置信息
+var (
+	WxId                string //微信原始ID
+	WxAppId             string
+	WxAppSecret         string
+	TemplateIdByProduct string //产品运行报告通知-模板ID
+
+	TemplateRedirectUrl                   string //模板消息跳转地址
+	DayReportTemplateRedirectUrl          string //模板消息跳转地址(晨报、周报)
+	TemplateIdByCompanyApply              string //客户申请单审批通知-模板ID
+	TemplateCompanyApplyRedirectUrl       string //审批单模板消息跳转地址
+	TemplateIdByCompanyReceive            string //销售跨部门领取客户通知-模板ID
+	TemplateIdByCompanyReceivePermission  string //销售"添加客户/领取客户"权限变更通知
+	WxMsgTemplateIdActivityChangeApply    string //查研观向活动变更通知-模板ID
+	WxMsgTemplateIdActivityChangeApplyXzs string //查研观向活动变更通知-模板ID(小助手)
+	TemplateIdByProductXzs                string //产品运行报告通知-模板ID(小助手)
+	WxCygxAppId                           string //查研观向小程序APPID
+	WxMsgTemplateIdAskByUser              string //查研观向用户提问新消息推送ID
+	WxCrmAppId                            string //随手办公小程序APPID
+	WxPublicIdXzs                         string //查研观向小助手公众号
+	WxPublicSecretXzs                     string //查研观向小助手公众号
+	WxYbAppId                             string //弘则研报小程序APPID
+
+	WxMsgTemplateIdWithRoadshowPending      string //路演->研究员收到待处理的申请
+	WxMsgTemplateIdWithRoadshowDetailResult string //路演->销售收到处理结果
+	WxMsgTemplateIdWithRoadshowDeleteNotice string //路演->研究员收到活动删除通知
+
+	WxMsgTemplateIdWithYbCommunityQuestion string // 研报小程序->问答社区回复通知
 )
 
 func init() {
@@ -16,10 +53,115 @@ func init() {
 	}
 	RunMode = tmpRunMode
 
+	if RunMode == "" {
+		localIp, err := GetLocalIP()
+		fmt.Println("localIp:", localIp)
+		if localIp == "10.0.0.123" {
+			RunMode = "debug"
+		} else {
+			RunMode = "release"
+		}
+		fmt.Println("RunMode:", RunMode)
+		configPath := `/home/code/config/hongze_public_api/conf/app.conf`
+		fmt.Println("configPath:", configPath)
+		err = web.LoadAppConfig("ini", configPath)
+		if err != nil {
+			fmt.Println("web.LoadAppConfig Err:" + err.Error())
+		}
+
+		WxRelease()
+	}
+
+	config, err := web.AppConfig.GetSection(RunMode)
+	if err != nil {
+		panic("配置文件读取错误 " + err.Error())
+	}
+	MYSQL_URL = config["mysql_url"]
+
+	REDIS_CACHE = config["beego_cache"]
+	if len(REDIS_CACHE) <= 0 {
+		panic("redis链接参数没有配置")
+	}
+	Rc, Re = cache.NewCache(REDIS_CACHE) //初始化缓存
+	if Re != nil {
+		fmt.Println(Re)
+		panic(Re)
+	}
+
 	beeLogger.Log.Info(RunMode + " 模式")
 	if RunMode == "release" {
 
 	} else {
+		WxDebug()
+	}
+}
+
+
+//测试环境模板消息
+func WxDebug() {
+	WxAppId = "wx9b5d7291e581233a"
+	WxAppSecret = "f4d52e34021eee262dce9682b31f8861"
+	WxId = "gh_5dc508325c6f"
+	//模板消息
+	{
+		TemplateIdByProduct = "-YjuPOB7Fqd-S3ilabYa6wvjDY9aXmeEfPN6DCiy-EY"
+		WxMsgTemplateIdAskByUser = `qfNuops-sKrfIkbA7U97A7gSrX03mUpoEpJksRUdloo`
+		TemplateIdByCompanyApply = "eTalI1LbiT_B0mTaBeDTlfSMITenK8dQIgEB5yqjjvA"
+		//销售跨部门领取客户通知
+		TemplateIdByCompanyReceive = "KAxFvX79f-DHmtC_Jw98elvqxiDPK0xP_b48LUT-Y14"
+		//销售"添加客户/领取客户"权限变更通知
+		TemplateIdByCompanyReceivePermission = "CB7bOl7f3viMG4s1uhRo7WM0Jbx3WvodKuIZ8A_z8fM"
+		WxMsgTemplateIdActivityChangeApply = "CB7bOl7f3viMG4s1uhRo7WM0Jbx3WvodKuIZ8A_z8fM"
+
+		//路演
+		WxMsgTemplateIdWithRoadshowPending = "qfNuops-sKrfIkbA7U97A7gSrX03mUpoEpJksRUdloo"      //路演->研究员收到待处理的申请
+		WxMsgTemplateIdWithRoadshowDetailResult = "CB7bOl7f3viMG4s1uhRo7WM0Jbx3WvodKuIZ8A_z8fM" //路演->销售收到处理结果
+		WxMsgTemplateIdWithRoadshowDeleteNotice = "CB7bOl7f3viMG4s1uhRo7WM0Jbx3WvodKuIZ8A_z8fM" //路演->研究员收到活动删除通知
+
+		// 研报小程序
+		WxMsgTemplateIdWithYbCommunityQuestion = "CB7bOl7f3viMG4s1uhRo7WM0Jbx3WvodKuIZ8A_z8fM" // 研报小程序->问答社区回复通知
+	}
 
+	//查研观向小助手
+	{
+		//原有的模板ID
+		WxPublicIdXzs = "wx9b5d7291e581233a"                                                  //查研观向小助手
+		WxPublicSecretXzs = "f4d52e34021eee262dce9682b31f8861"                                //查研观向小助手
+		WxMsgTemplateIdActivityChangeApplyXzs = "CB7bOl7f3viMG4s1uhRo7WM0Jbx3WvodKuIZ8A_z8fM" //查研观向活动变更通知-模板ID(小助手)
+		TemplateIdByProductXzs = "-YjuPOB7Fqd-S3ilabYa6wvjDY9aXmeEfPN6DCiy-EY"                //产品运行报告通知-模板ID(小助手)
 	}
+
 }
+
+//生产环境模板消息
+func WxRelease() {
+	WxAppId = "wx4a844c734d8c8e56"
+	WxAppSecret = "26c586e7ccb3c575433f0f37797b3eeb"
+	WxId = "gh_b67e0049fb8c"
+	//模板消息
+	{
+		TemplateIdByProduct = "Cp2wF8gvBtxyWV4DeYuI172oqwyYXVRSm3AyJO42d84"
+		TemplateIdByCompanyApply = "ZKcOfNIWBpwHJxpptufHIK1mp2nIwkT3cxub-35cFqI"
+		WxMsgTemplateIdActivityChangeApply = "dYg6iHooRq74PyCXmw_Ns7qdJZmbtLoKS2p2FKeaXl0"
+		//销售跨部门领取客户通知
+		TemplateIdByCompanyReceive = "A5fV-XWBcu-LIj_W-tBiOJ-D39a9WDd9GOB0WGbpoBg"
+		//销售"添加客户/领取客户"权限变更通知
+		TemplateIdByCompanyReceivePermission = "dYg6iHooRq74PyCXmw_Ns7qdJZmbtLoKS2p2FKeaXl0"
+		//路演
+		WxMsgTemplateIdWithRoadshowPending = "PaoDanHGlt1kFw5q-4_ipJSwO3FyZpxSSNg4rwB7YCk"      //路演->研究员收到待处理的申请
+		WxMsgTemplateIdWithRoadshowDetailResult = "dYg6iHooRq74PyCXmw_Ns7qdJZmbtLoKS2p2FKeaXl0" //路演->销售收到处理结果
+		WxMsgTemplateIdWithRoadshowDeleteNotice = "dYg6iHooRq74PyCXmw_Ns7qdJZmbtLoKS2p2FKeaXl0" //路演->研究员收到活动删除通知
+
+		// 研报小程序
+		WxMsgTemplateIdWithYbCommunityQuestion = "dYg6iHooRq74PyCXmw_Ns7qdJZmbtLoKS2p2FKeaXl0" // 研报小程序->问答社区回复通知
+	}
+
+	//查研观向小助手
+	{
+		//新的模板ID
+		WxPublicIdXzs = "wxb7cb8a15abad5b8e"                                                  //查研观向小助手
+		WxPublicSecretXzs = "f425ba2863084249722af1e2a5cfffd3"                                //查研观向小助手
+		WxMsgTemplateIdActivityChangeApplyXzs = "7qe3i4MrGxAIPhJeMgoqqw6j0A_foUB65DLSmxKe05s" //查研观向活动变更通知-模板ID(小助手)
+		TemplateIdByProductXzs = "tNcCUiK_uUkuxaFF7M9NP2RwLkw8uHFjG-TDIxGUKxo"                //产品运行报告通知-模板ID(小助手)
+	}
+}

+ 6 - 2
utils/constants.go

@@ -29,6 +29,10 @@ const (
 )
 
 var (
-	AccessKeyId      string = "LTAIFMZYQhS2BTvW"
-	AccessKeySecret  string = "12kk1ptCHoGWedhBnKRVW5hRJzq9Fq"
+	AccessKeyId     string = "LTAIFMZYQhS2BTvW"
+	AccessKeySecret string = "12kk1ptCHoGWedhBnKRVW5hRJzq9Fq"
+)
+
+var (
+	Authorization = "dc855fce962a639faa779cbdd4cd332f"
 )