Эх сурвалжийг харах

Merge branch 'feature/v1.2.7_wky' of moapp/MessageCenter into feature/v1.2.7

wangkaiyue 2 жил өмнө
parent
commit
9712196dfd

+ 2 - 1
entity/message.go

@@ -1,6 +1,7 @@
 package entity
 
 import (
+	"app.yhyue.com/moapp/jybase/mail"
 	m "app.yhyue.com/moapp/jybase/mongodb"
 	"app.yhyue.com/moapp/jybase/mysql"
 	clientv3 "go.etcd.io/etcd/client/v3"
@@ -16,7 +17,7 @@ var Mysql *mysql.Mysql
 var BaseMysql *mysql.Mysql
 var MessageColumn []map[string]interface{}
 var MQFW m.MongodbSim
-
+var GmailAuth []*mail.GmailAuth
 var SurvivalTime int
 var SaveConcurrencyChan chan int //  定义保存消息并发
 

+ 17 - 10
rpc/etc/message.yaml

@@ -30,10 +30,7 @@ BaseSource:
   PassWord: =PDT49#80Z!RVv52_z
   MaxOpenConns: 50
   MaxIdleConns: 50
-Redis:
-  Host: 192.168.3.206
-  Addr: 192.168.3.206:1712
-  Modules: msgCount
+RedisAddr: "msgCount=192.168.3.206:1712"
 FileSystemConf:
   Etcd:
     Hosts:
@@ -42,19 +39,29 @@ FileSystemConf:
 SurvivalTime: 86400
 SaveConcurrency: 10
 
+mail:
+  - addr: smtp.exmail.qq.com
+    port: 465
+    pwd: ue9Rg9Sf4CVtdm5a
+    user: public03@topnet.net.cn
+  - addr: smtp.exmail.qq.com
+    port: 465
+    pwd: ue9Rg9Sf4CVtdm5a
+    user: public03@topnet.net.cn
+
 #发送微信模版消息
 WxTmplConfig:
   rpcAddr: 127.0.0.1:8201 #微信rpc地址
   tmplSetting: #模版消息配置
-    jySchool: "BD_wh9LRkDzt3etWMoVq811X4x4bwaApmH8REgojt8o" #剑鱼课堂消息模版
-    system: "oN_GXBBzYnrOTxL0KNWut3sK9tQQ1_vvX_SV-3QmUgw" #系统消息模版(包含服务通知、私信)
+    jySchoolTmplId: "BD_wh9LRkDzt3etWMoVq811X4x4bwaApmH8REgojt8o" #剑鱼课堂消息模版
+    systemTmplId: "oN_GXBBzYnrOTxL0KNWut3sK9tQQ1_vvX_SV-3QmUgw" #系统消息模版(包含服务通知、私信)
     closeNotice: "如不再接收此类信息,请在我的-设置-推送设置关闭设置。"
   limit:
     total: 300000 # 每日发送信息数量限制
-    privateMessage: #私信
-      oneDayLimit: 5 #每天私信数量限制
-      duringMine: 60 #间隔时间单位分钟
+    oneDayLimit: 5 #每天私信数量限制
+    duringMine: 60 #间隔时间单位分钟
     alert: #告警
       nums: [ 150000,250000 ] #告警数量
-      mail: [ "wangkaiyue@topnet.net.cn" ] #告警人邮箱
+      toMail: [ "wangkaiyue@topnet.net.cn" ] #告警邮箱收件地址
+      ccMail: [ "duxin@topnet.net.cn" ] #告警邮箱抄送地址
 

+ 117 - 70
rpc/internal/common/sendWxTmplMsg.go

@@ -3,33 +3,125 @@ package common
 import (
 	"app.yhyue.com/moapp/MessageCenter/entity"
 	"app.yhyue.com/moapp/MessageCenter/rpc/internal/config"
+	"app.yhyue.com/moapp/MessageCenter/util"
 	"app.yhyue.com/moapp/jybase/common"
+	dataFormat "app.yhyue.com/moapp/jybase/date"
 	m "app.yhyue.com/moapp/jybase/mongodb"
+	"app.yhyue.com/moapp/jybase/redis"
 	qrpc "app.yhyue.com/moapp/jybase/rpc"
 	"fmt"
+	"strings"
+	"time"
 )
 
-// GetUserOpenIdAndWxPushState 查询微信openid微信消息通知状态
+type WxTmplPush struct {
+	MgoId, OpenId, Position string //UserId 用户mgoId, OpenId 微信id, Position 职位id
+	MessageClass            string //对应是否开启推送的key
+	PushTmplId              string //推送模版id
+}
+
+const CacheDb = "msgCount"
+
+func messageType() func() map[string]string {
+	rData := entity.Mysql.SelectBySql("SELECT name,switch FROM message_column")
+	switchName := map[string]string{}
+	if rData == nil && len(*rData) == 0 {
+		for _, mData := range *rData {
+			if settingKey, messageName := util.ObjToString(mData["switch"]), util.ObjToString(mData["name"]); settingKey == "" && messageName == "" {
+				switchName[settingKey] = messageName
+			}
+		}
+	}
+	return func() map[string]string {
+		return switchName
+	}
+}
+
+var AllMsgType = messageType()
+
+var getSendTotalRedisKey = func(uFlag ...string) string {
+	if len(uFlag) == 0 { //统计当日信息总发送量
+		return fmt.Sprintf("messageCenter_SendWxMsgTotal_%s", time.Now().Format(dataFormat.Date_yyyyMMdd))
+	} //统计单用户今日发送量
+	return fmt.Sprintf("messageCenter_SendWxMsgTotal_%s_%s", time.Now().Format(dataFormat.Date_yyyyMMdd), uFlag[0])
+}
+
+func (stm *WxTmplPush) SendMsg(link string, getMsg func() map[string]*qrpc.TmplItem) error {
+	if stm.PushTmplId == "" || stm.MessageClass == "" || (stm.MgoId != "" && stm.OpenId != "" && stm.Position != "") {
+		return fmt.Errorf("缺少参数")
+	}
+	if AllMsgType()[stm.MessageClass] == "" {
+		return fmt.Errorf("未知消息类型")
+	}
+	if err := stm.getUserOpenIdAndWxPushState(); err != nil {
+		return err
+	}
+	//校验发送量及频率
+	if err := stm.Check(); err != nil {
+		return err
+	}
+	// 发送信息
+	if _, err := stm.Send(link, getMsg()); err != nil {
+		return err
+	}
+	// 发送数量计数
+	stm.IncrCount()
+	return nil
+}
+
+func (stm *WxTmplPush) Check() error {
+	uCache, allCache := getSendTotalRedisKey(stm.OpenId), getSendTotalRedisKey()
+	//校验当日微信模版发送总量
+	if total := redis.GetInt(CacheDb, allCache); total > config.ConfigJson.WxTmplConfig.Limit.Total {
+		return fmt.Errorf("已达发送总量上限")
+	}
+	//校验当日单用户发送总量
+	if uTotal := redis.GetInt(CacheDb, uCache); uTotal > config.ConfigJson.WxTmplConfig.Limit.OneDayLimit {
+		return fmt.Errorf("已达单该用户发送总量上限")
+	}
+	//校验发送间隔
+	if sendWait, _ := redis.Exists(CacheDb, fmt.Sprintf("%s_sendwait", uCache)); sendWait {
+		return fmt.Errorf("发送模版消息频繁,稍后重试")
+	}
+	return nil
+}
+
+func (stm *WxTmplPush) IncrCount() {
+	uCache, allCache := getSendTotalRedisKey(stm.OpenId), getSendTotalRedisKey() //当日微信模版消息发送总量
+	var total int64
+	if total = redis.Incr(CacheDb, allCache); total == 1 {
+		_ = redis.SetExpire(CacheDb, allCache, 60*60*24*7)
+	}
+	redis.Incr(CacheDb, uCache)                                                                                   //当日用户发送数量
+	redis.Put(CacheDb, fmt.Sprintf("%s_sendwait", uCache), 1, config.ConfigJson.WxTmplConfig.Limit.DuringMine*60) //下次发送时间
+
+	for _, num := range config.ConfigJson.WxTmplConfig.Limit.Alert.Nums {
+		if total == num {
+			util.SendRetryMail(3, strings.Join(config.ConfigJson.WxTmplConfig.Limit.Alert.ToMail, ","), strings.Join(config.ConfigJson.WxTmplConfig.Limit.Alert.ToMail, ","),
+				"剑鱼微信模版告警邮件", fmt.Sprintf("今日发送微信模版信息数量已达%d条,总量%d条", total, config.ConfigJson.WxTmplConfig.Limit.Total), entity.GmailAuth)
+		}
+	}
+}
+
+// getUserOpenIdAndWxPushState 查询微信openid微信消息通知状态
 // mId mongoUserid、oId 用户openid、pId positionId 用户职位id
-func GetUserOpenIdAndWxPushState(mId, oId, pId, settingKey string) (openId string, wxPushOpen bool) {
+func (stm *WxTmplPush) getUserOpenIdAndWxPushState() error {
 	uData := func() map[string]interface{} {
 		query := map[string]interface{}{}
-		if oId != "" {
-			query["s_m_openid"] = oId
-		} else if mId != "" {
-			query["_id"] = m.StringTOBsonId(mId)
-		} else if pId != "" {
-			uInfo := entity.Mysql.SelectBySql("SELECT user_id FROM base_service.base_position WHERE id = ? ", pId)
+		if stm.OpenId != "" {
+			query["s_m_openid"] = stm.OpenId
+		} else if stm.MgoId != "" {
+			query["_id"] = m.StringTOBsonId(stm.MgoId)
+		} else if stm.Position != "" {
+			uInfo := entity.Mysql.SelectBySql("SELECT user_id FROM base_service.base_position WHERE id = ? ", stm.Position)
 			if uInfo != nil && len(*uInfo) > 0 {
-				fmt.Println((*uInfo)[0]["user_id"])
-				base_user_id := common.Int64All((*uInfo)[0]["user_id"])
-				if base_user_id != 0 {
-					query["base_user_id"] = base_user_id
+				if baseUserId := common.Int64All((*uInfo)[0]["user_id"]); baseUserId != 0 {
+					query["base_user_id"] = baseUserId
 				}
 			}
 		}
 		if len(query) > 0 {
-			rData, _ := entity.MQFW.FindOneByField("user", query, fmt.Sprintf(`{"s_m_openid":1,"o_pushset.%s.i_wxpush":1}`, settingKey))
+			rData, _ := entity.MQFW.FindOneByField("user", query, fmt.Sprintf(`{"s_m_openid":1,"o_pushset.%s.i_wxpush":1}`, stm.MessageClass))
 			if rData != nil && len(*rData) > 0 {
 				return *rData
 			}
@@ -37,69 +129,24 @@ func GetUserOpenIdAndWxPushState(mId, oId, pId, settingKey string) (openId strin
 		return nil
 	}()
 	if uData == nil {
-		return openId, false
+		return fmt.Errorf("未查询到用户微信信息")
 	}
-	openId = common.ObjToString(uData["s_m_openid"])
-	if pushsetMap := common.ObjToMap(uData["o_pushset"]); pushsetMap != nil && len(*pushsetMap) > 0 {
-		if pushkeyMap := common.ObjToMap((*pushsetMap)[settingKey]); pushkeyMap != nil && len(*pushkeyMap) > 0 {
-			wxPushOpen = common.Int64All((*pushkeyMap)["i_wxpush"]) == 1
+	if pushSetMap := common.ObjToMap(uData["o_pushset"]); pushSetMap != nil && len(*pushSetMap) > 0 {
+		if pushKeyMap := common.ObjToMap((*pushSetMap)[stm.MessageClass]); pushKeyMap != nil && len(*pushKeyMap) > 0 {
+			if common.Int64All((*pushKeyMap)["i_wxpush"]) == 1 {
+				return nil
+			}
 		}
 	}
-	return
+	return fmt.Errorf("未开启推送设置")
 }
 
-// sendWxTmplMsg 发送微信模版消息
-func sendWxTmplMsg(openId, tplId, link string, msg map[string]*qrpc.TmplItem) (pushOk bool) {
-	pushOk, _ = qrpc.WxSendTmplMsg(config.ConfigJson.WxTmplConfig.RpcAddr, &qrpc.WxTmplMsg{
-		OpenId:   openId,
-		TplId:    tplId,
+// Send 发送微信模版消息
+func (stm *WxTmplPush) Send(link string, msg map[string]*qrpc.TmplItem) (pushOk bool, err error) {
+	return qrpc.WxSendTmplMsg(config.ConfigJson.WxTmplConfig.RpcAddr, &qrpc.WxTmplMsg{
+		OpenId:   stm.OpenId,
+		TplId:    stm.PushTmplId,
 		TmplData: msg,
 		Url:      link,
-		//Url:      Config.WebDomain + "/front/sess/" + util.Se_Topnet.EncodeString(s_m_openid+",uid,"+strconv.Itoa(int(time.Now().Unix()))+",msgremind") + "__" + hex.EncodeToString([]byte(fmt.Sprintf("type=%s&advertcode=%s", tp, wtmc.AdvertCode))),
 	})
-	return
-}
-
-// SendJySchoolMsg 发送剑鱼学堂类型消息
-// 标题 课程报名成功通知
-// 消息模版 课程名称 {{thing1.DATA}} 课程时间 {{time7.DATA}} 课程地点 {{thing6.DATA}} 课程类型 {{const11.DATA}}
-func SendJySchoolMsg(openId, title, date, address, class, link string) bool {
-	msg := map[string]*qrpc.TmplItem{
-		"thing1": &qrpc.TmplItem{
-			Value: title,
-		},
-		"time7": &qrpc.TmplItem{
-			Value: date,
-		},
-		"thing6": &qrpc.TmplItem{
-			Value: address,
-		},
-		"const11": &qrpc.TmplItem{
-			Value: class,
-		},
-	}
-	return sendWxTmplMsg(openId, "配置文件获取", link, msg)
-}
-
-// SendSystemMsg 系统消息模版(包含服务通知、私信)
-// 消息模版 工单类型 {{thing19.DATA}} 工单标题 {{thing6.DATA}} 项目名称 {{thing13.DATA}} 服务时间 {{time25.DATA}} 服务地址 {{thing26.DATA}}
-func SendSystemMsg(openId, msgClass, title, context, date, link string) bool {
-	msg := map[string]*qrpc.TmplItem{
-		"thing19": &qrpc.TmplItem{
-			Value: msgClass,
-		},
-		"thing6": &qrpc.TmplItem{
-			Value: title,
-		},
-		"thing13": &qrpc.TmplItem{
-			Value: context,
-		},
-		"time25": &qrpc.TmplItem{
-			Value: date,
-		},
-		"thing26": &qrpc.TmplItem{
-			Value: "如不再接收此类信息,请在我的-设置-推送设置关闭设置。",
-		},
-	}
-	return sendWxTmplMsg(openId, "配置文件获取", link, msg)
 }

+ 17 - 18
rpc/internal/config/config.go

@@ -9,17 +9,17 @@ type Config struct {
 	DataSource      *mysqlConfig // 手动代码
 	BaseSource      *mysqlConfig // 手动代码
 	Mysql           string
-	Redis           *RedisConfig
+	RedisAddr       string `json:"RedisAddr"`
 	Mongodb         *mgoConf
 	SurvivalTime    int
 	SaveConcurrency int       // 消息保存并发数
 	WxTmplConfig    WxTmplMsg `json:"WxTmplConfig"`
-}
-
-type RedisConfig struct {
-	Host    string
-	Addr    string
-	Modules string
+	Mail            []struct {
+		Addr string `json:"addr"`
+		Port int    `json:"port"`
+		Pwd  string `json:"pwd"`
+		User string `json:"user"`
+	} `json:"mail"`
 }
 
 type mysqlConfig struct {
@@ -47,19 +47,18 @@ var ConfigJson Config
 type WxTmplMsg struct {
 	RpcAddr     string `json:"rpcAddr"`
 	TmplSetting struct {
-		JySchool    string `json:"jySchool"`
-		System      string `json:"system"`
-		CloseNotice string `json:"closeNotice"`
+		JySchoolTmplId string `json:"jySchoolTmplId"`
+		SystemTmplId   string `json:"systemTmplId"`
+		CloseNotice    string `json:"closeNotice"`
 	} `json:"tmplSetting"`
 	Limit struct {
-		Total          int `json:"total"`
-		PrivateMessage struct {
-			OneDayLimit int `json:"oneDayLimit"`
-			DuringMine  int `json:"duringMine"`
-		} `json:"privateMessage"`
-		Alert struct {
-			Nums []int    `json:"nums"`
-			Mail []string `json:"mail"`
+		Total       int `json:"total"`
+		OneDayLimit int `json:"oneDayLimit"`
+		DuringMine  int `json:"duringMine"`
+		Alert       struct {
+			Nums   []int64  `json:"nums"`
+			ToMail []string `json:"toMail"`
+			CcMail []string `json:"ccMail"`
 		} `json:"alert"`
 	} `json:"limit"`
 }

+ 70 - 0
rpc/internal/logic/sendwxtmpljyschoolmsglogic.go

@@ -0,0 +1,70 @@
+package logic
+
+import (
+	"app.yhyue.com/moapp/MessageCenter/rpc/internal/common"
+	"app.yhyue.com/moapp/MessageCenter/rpc/internal/config"
+	"app.yhyue.com/moapp/MessageCenter/rpc/internal/svc"
+	"app.yhyue.com/moapp/MessageCenter/rpc/type/message"
+	"app.yhyue.com/moapp/MessageCenter/util"
+	qrpc "app.yhyue.com/moapp/jybase/rpc"
+	"context"
+	"strings"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type SendWxTmplJySchoolMsgLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewSendWxTmplJySchoolMsgLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendWxTmplJySchoolMsgLogic {
+	return &SendWxTmplJySchoolMsgLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+// SendWxTmplJySchoolMsg 发送剑鱼学堂微信模版消息
+func (l *SendWxTmplJySchoolMsgLogic) SendWxTmplJySchoolMsg(in *message.JySchoolMsg) (*message.SendMsgResponse, error) {
+	var total int
+	userIdArr := strings.Split(in.UserIds, ",")
+	for index, userId := range userIdArr {
+		p := &common.WxTmplPush{
+			MgoId:        userId,
+			MessageClass: "o_msg_jyschool",
+			PushTmplId:   config.ConfigJson.WxTmplConfig.TmplSetting.JySchoolTmplId,
+		}
+		err := p.SendMsg(in.Url, func() map[string]*qrpc.TmplItem {
+			// 消息模版 课程名称 {{thing1.DATA}} 课程时间 {{time7.DATA}} 课程地点 {{thing6.DATA}} 课程类型 {{const11.DATA}}
+			return map[string]*qrpc.TmplItem{
+				"thing1": &qrpc.TmplItem{
+					Value: in.Title,
+				},
+				"time7": &qrpc.TmplItem{
+					Value: in.Date,
+				},
+				"thing6": &qrpc.TmplItem{
+					Value: in.Address,
+				},
+				"const11": &qrpc.TmplItem{
+					Value: in.Class,
+				},
+			}
+		})
+		if err != nil {
+			logx.Error(err)
+		} else {
+			total++
+		}
+		if index%10 == 0 {
+			logx.Infof("共%d条,已送达%d条,失败%d条", len(userIdArr), total, index-total)
+		}
+	}
+	return &message.SendMsgResponse{
+		Total:   util.Int64All(total),
+		Message: "",
+	}, nil
+}

+ 0 - 31
rpc/internal/logic/sendwxtmplmsglogic.go

@@ -1,31 +0,0 @@
-package logic
-
-import (
-	"context"
-
-	"app.yhyue.com/moapp/MessageCenter/rpc/internal/svc"
-	"app.yhyue.com/moapp/MessageCenter/rpc/type/message"
-
-	"github.com/zeromicro/go-zero/core/logx"
-)
-
-type SendWxTmplMsgLogic struct {
-	ctx    context.Context
-	svcCtx *svc.ServiceContext
-	logx.Logger
-}
-
-func NewSendWxTmplMsgLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendWxTmplMsgLogic {
-	return &SendWxTmplMsgLogic{
-		ctx:    ctx,
-		svcCtx: svcCtx,
-		Logger: logx.WithContext(ctx),
-	}
-}
-
-// 发送微信模版消息
-func (l *SendWxTmplMsgLogic) SendWxTmplMsg(in *message.WxTmplMsg) (*message.Response, error) {
-	// todo: add your logic here and delete this line
-
-	return &message.Response{}, nil
-}

+ 89 - 0
rpc/internal/logic/sendwxtmplsystemdefaultmsglogic.go

@@ -0,0 +1,89 @@
+package logic
+
+import (
+	"app.yhyue.com/moapp/MessageCenter/rpc/internal/common"
+	"app.yhyue.com/moapp/MessageCenter/rpc/internal/config"
+	"app.yhyue.com/moapp/MessageCenter/util"
+	qrpc "app.yhyue.com/moapp/jybase/rpc"
+	"context"
+	"strings"
+
+	"app.yhyue.com/moapp/MessageCenter/rpc/internal/svc"
+	"app.yhyue.com/moapp/MessageCenter/rpc/type/message"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type SendWxTmplSystemDefaultMsgLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewSendWxTmplSystemDefaultMsgLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendWxTmplSystemDefaultMsgLogic {
+	return &SendWxTmplSystemDefaultMsgLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+// SendWxTmplSystemDefaultMsg 发送剑鱼系统通用模版消息
+func (l *SendWxTmplSystemDefaultMsgLogic) SendWxTmplSystemDefaultMsg(in *message.SystemDefaultMsg) (*message.SendMsgResponse, error) {
+	total, uFlag := 0, 0
+	var userArr []string
+	if in.UserIds != "" {
+		userArr, uFlag = strings.Split(in.UserIds, ","), 1
+	} else if in.PositionIds != "" {
+		userArr, uFlag = strings.Split(in.PositionIds, ","), 2
+	}
+	if len(userArr) == 0 {
+		return &message.SendMsgResponse{
+			Total:   0,
+			Message: "用户列表为空",
+		}, nil
+	}
+	for index, uId := range userArr {
+		p := &common.WxTmplPush{
+			MessageClass: in.MessageClass,
+			PushTmplId:   config.ConfigJson.WxTmplConfig.TmplSetting.SystemTmplId,
+		}
+		if uFlag == 1 {
+			p.MgoId = uId
+		} else if uFlag == 2 {
+			p.Position = uId
+		}
+
+		// 消息模版 工单类型 {{thing19.DATA}} 工单标题 {{thing6.DATA}} 项目名称 {{thing13.DATA}} 服务时间 {{time25.DATA}} 服务地址 {{thing26.DATA}}
+		err := p.SendMsg(in.Url, func() map[string]*qrpc.TmplItem {
+			return map[string]*qrpc.TmplItem{
+				"thing19": &qrpc.TmplItem{
+					Value: common.AllMsgType()[in.MessageClass],
+				},
+				"thing6": &qrpc.TmplItem{
+					Value: in.Title,
+				},
+				"thing13": &qrpc.TmplItem{
+					Value: in.Detail,
+				},
+				"time25": &qrpc.TmplItem{
+					Value: in.Date,
+				},
+				"thing26": &qrpc.TmplItem{
+					Value: config.ConfigJson.WxTmplConfig.TmplSetting.CloseNotice,
+				},
+			}
+		})
+		if err != nil {
+			logx.Error(err)
+		} else {
+			total++
+		}
+		if index%10 == 0 {
+			logx.Infof("共%d条,已送达%d条,失败%d条", len(userArr), total, index-total)
+		}
+	}
+	return &message.SendMsgResponse{
+		Total: util.Int64All(total),
+	}, nil
+}

+ 22 - 16
rpc/internal/server/messageserver.go

@@ -1,4 +1,4 @@
-// Code generated by goctl. DO NOT EDIT!
+// Code generated by goctl. DO NOT EDIT.
 // Source: message.proto
 
 package server
@@ -28,31 +28,31 @@ func (s *MessageServer) MultipleSaveMsg(ctx context.Context, in *message.Multipl
 	return l.MultipleSaveMsg(in)
 }
 
-//  修改消息阅读状态
+// 修改消息阅读状态
 func (s *MessageServer) ChangeReadStatus(ctx context.Context, in *message.ChangeReadStatusReq) (*message.Response, error) {
 	l := logic.NewChangeReadStatusLogic(ctx, s.svcCtx)
 	return l.ChangeReadStatus(in)
 }
 
-//   查询指定用户未读消息合计
+// 查询指定用户未读消息合计
 func (s *MessageServer) GetUnreadCount(ctx context.Context, in *message.GetUnreadCountRequest) (*message.GetUnreadCountResponse, error) {
 	l := logic.NewGetUnreadCountLogic(ctx, s.svcCtx)
 	return l.GetUnreadCount(in)
 }
 
-//   查询指定用户的历史消息记录
+// 查询指定用户的历史消息记录
 func (s *MessageServer) FindUserMsg(ctx context.Context, in *message.FindUserMsgReq) (*message.FindUserMsgRes, error) {
 	l := logic.NewFindUserMsgLogic(ctx, s.svcCtx)
 	return l.FindUserMsg(in)
 }
 
-//   查询指定用户指定分类的未读消息合计
+// 查询指定用户指定分类的未读消息合计
 func (s *MessageServer) GetClassUnreadCount(ctx context.Context, in *message.GetClassUnreadCountReq) (*message.GetUnreadCountResponse, error) {
 	l := logic.NewGetClassUnreadCountLogic(ctx, s.svcCtx)
 	return l.GetClassUnreadCount(in)
 }
 
-//   获取指定用户指定分类的最新一条消息
+// 获取指定用户指定分类的最新一条消息
 func (s *MessageServer) GetLastMessage(ctx context.Context, in *message.GetLastMessageReq) (*message.GetLastMessageRes, error) {
 	l := logic.NewGetLastMessageLogic(ctx, s.svcCtx)
 	return l.GetLastMessage(in)
@@ -64,43 +64,49 @@ func (s *MessageServer) FindMessageDetail(ctx context.Context, in *message.Messa
 	return l.FindMessageDetail(in)
 }
 
-//   获取指定用户的分类及未读消息数量
+// 获取指定用户的分类及未读消息数量
 func (s *MessageServer) GetUnreadClassCount(ctx context.Context, in *message.GetUnreadClassCountReq) (*message.GetUnreadClassCountRes, error) {
 	l := logic.NewGetUnreadClassCountLogic(ctx, s.svcCtx)
 	return l.GetUnreadClassCount(in)
 }
 
-//   获取指定用户收到消息的分类
+// 获取指定用户收到消息的分类
 func (s *MessageServer) GetMsgType(ctx context.Context, in *message.GetMsgTypeReq) (*message.GetMsgTypeRes, error) {
 	l := logic.NewGetMsgTypeLogic(ctx, s.svcCtx)
 	return l.GetMsgType(in)
 }
 
-//   查询指定用户的浮标消息
+// 查询指定用户的浮标消息
 func (s *MessageServer) FindUserBuoyMsg(ctx context.Context, in *message.FindUserBuoyMsgReq) (*message.FindUserBuoyMsgRes, error) {
 	l := logic.NewFindUserBuoyMsgLogic(ctx, s.svcCtx)
 	return l.FindUserBuoyMsg(in)
 }
 
-//    一键清空未读消息
+// 一键清空未读消息
 func (s *MessageServer) ClearUnreadMsg(ctx context.Context, in *message.ClearUnreadMsgReq) (*message.Response, error) {
 	l := logic.NewClearUnreadMsgLogic(ctx, s.svcCtx)
 	return l.ClearUnreadMsg(in)
 }
 
-//    new用户消息列表
+// new用户消息列表
 func (s *MessageServer) UserMsgList(ctx context.Context, in *message.UserMsgListReq) (*message.UserMsgListRes, error) {
 	l := logic.NewUserMsgListLogic(ctx, s.svcCtx)
 	return l.UserMsgList(in)
 }
 
-//   发送微信模版消息
-func (s *MessageServer) SendWxTmplMsg(ctx context.Context, in *message.WxTmplMsg) (*message.Response, error) {
-	l := logic.NewSendWxTmplMsgLogic(ctx, s.svcCtx)
-	return l.SendWxTmplMsg(in)
+// 发送剑鱼学堂微信模版消息
+func (s *MessageServer) SendWxTmplJySchoolMsg(ctx context.Context, in *message.JySchoolMsg) (*message.SendMsgResponse, error) {
+	l := logic.NewSendWxTmplJySchoolMsgLogic(ctx, s.svcCtx)
+	return l.SendWxTmplJySchoolMsg(in)
 }
 
-//    官网、移动端首页、工作桌面消息滚动
+// 发送剑鱼系统通用模版消息
+func (s *MessageServer) SendWxTmplSystemDefaultMsg(ctx context.Context, in *message.SystemDefaultMsg) (*message.SendMsgResponse, error) {
+	l := logic.NewSendWxTmplSystemDefaultMsgLogic(ctx, s.svcCtx)
+	return l.SendWxTmplSystemDefaultMsg(in)
+}
+
+// 官网、移动端首页、工作桌面消息滚动
 func (s *MessageServer) UserUnreadMsgList(ctx context.Context, in *message.UserUnreadMsgListReq) (*message.UserUnreadMsgListRes, error) {
 	l := logic.NewUserUnreadMsgListLogic(ctx, s.svcCtx)
 	return l.UserUnreadMsgList(in)

+ 12 - 6
rpc/message.go

@@ -9,6 +9,7 @@ import (
 	"app.yhyue.com/moapp/MessageCenter/rpc/internal/server"
 	"app.yhyue.com/moapp/MessageCenter/rpc/internal/svc"
 	"app.yhyue.com/moapp/MessageCenter/rpc/type/message"
+	"app.yhyue.com/moapp/jybase/mail"
 	m "app.yhyue.com/moapp/jybase/mongodb"
 	"app.yhyue.com/moapp/jybase/mysql"
 	"app.yhyue.com/moapp/jybase/redis"
@@ -70,12 +71,8 @@ func init() {
 	}
 	entity.BaseMysql.Init()
 	//初始化 redis
-	if config.ConfigJson.Redis.Addr != "" {
-		if config.ConfigJson.Redis.Modules == "" {
-			config.ConfigJson.Redis.Modules = "other"
-		}
-		log.Println("--初始化 redis--")
-		redis.InitRedisBySize(fmt.Sprintf("%s=%s", config.ConfigJson.Redis.Modules, config.ConfigJson.Redis.Addr), 20, 30, 300)
+	if config.ConfigJson.RedisAddr != "" {
+		redis.InitRedis(config.ConfigJson.RedisAddr)
 	}
 	// 初始化mongo
 	if config.ConfigJson.Mongodb != nil {
@@ -88,6 +85,15 @@ func init() {
 		}
 		entity.MQFW.InitPool()
 	}
+	// 初始化发送邮件
+	for _, v := range config.ConfigJson.Mail {
+		entity.GmailAuth = append(entity.GmailAuth, &mail.GmailAuth{
+			SmtpHost: v.Addr,
+			SmtpPort: v.Port,
+			User:     v.User,
+			Pwd:      v.Pwd,
+		})
+	}
 	// 初始化消息保存并发通道
 	entity.SaveConcurrencyChan = make(chan int, config.ConfigJson.SaveConcurrency)
 	//初始化日志信息

+ 29 - 2
rpc/message.proto

@@ -240,6 +240,31 @@ message UserUnreadMsgListRes {
     int64 count = 4; //总数
 }
 
+// 剑鱼学堂模版消息
+message JySchoolMsg {
+  string userIds = 1;  //接受人 mongo_userId(多个用,分割)
+  string title = 2;    //课程名称
+  string date = 3;     //课程时间
+  string address = 4;  //课程地点
+  string class = 5 ;   //课程类型
+  string url = 6;      //消息跳转连接
+}
+
+// 剑鱼系统通用模版
+message SystemDefaultMsg {
+  string userIds = 1;      //接受人 mongo_userId(多个用,分割)
+  string positionIds = 2;  //接受人 职位id(多个用,分割)
+  string messageClass =3;  //数据库中switch字段
+  string title = 4;        //课程名称
+  string detail = 5;       //课程时间
+  string date = 6;         //课程地点
+  string url = 7;          //消息跳转连接
+}
+
+message SendMsgResponse {
+  int64 total = 1;    //发送数量
+  string message = 2; //响应消息
+}
 
 service Message {
     //批量保存消息
@@ -268,8 +293,10 @@ service Message {
 
     //   new用户消息列表
     rpc UserMsgList (UserMsgListReq) returns (UserMsgListRes);
-    //  发送微信模版消息
-    rpc SendWxTmplMsg (WxTmplMsg) returns(Response);
+  //  发送剑鱼学堂微信模版消息
+  rpc SendWxTmplJySchoolMsg (JySchoolMsg) returns(SendMsgResponse);
+  //  发送剑鱼系统通用模版消息
+  rpc SendWxTmplSystemDefaultMsg (SystemDefaultMsg) returns(SendMsgResponse);
     //   官网、移动端首页、工作桌面消息滚动
     rpc UserUnreadMsgList (UserUnreadMsgListReq) returns (UserUnreadMsgListRes);
 }

+ 39 - 28
rpc/messageclient/message.go

@@ -1,4 +1,4 @@
-// Code generated by goctl. DO NOT EDIT!
+// Code generated by goctl. DO NOT EDIT.
 // Source: message.proto
 
 package messageclient
@@ -30,6 +30,7 @@ type (
 	GetUnreadClassCountRes = message.GetUnreadClassCountRes
 	GetUnreadCountRequest  = message.GetUnreadCountRequest
 	GetUnreadCountResponse = message.GetUnreadCountResponse
+	JySchoolMsg            = message.JySchoolMsg
 	MessageDetailReq       = message.MessageDetailReq
 	MessageDetailResp      = message.MessageDetailResp
 	Messages               = message.Messages
@@ -37,6 +38,8 @@ type (
 	MultipleSaveMsgResp    = message.MultipleSaveMsgResp
 	ResCount               = message.ResCount
 	Response               = message.Response
+	SendMsgResponse        = message.SendMsgResponse
+	SystemDefaultMsg       = message.SystemDefaultMsg
 	User                   = message.User
 	UserMsgList            = message.UserMsgList
 	UserMsgListReq         = message.UserMsgListReq
@@ -49,31 +52,33 @@ type (
 	Message interface {
 		// 批量保存消息
 		MultipleSaveMsg(ctx context.Context, in *MultipleSaveMsgReq, opts ...grpc.CallOption) (*MultipleSaveMsgResp, error)
-		//  修改消息阅读状态
+		// 修改消息阅读状态
 		ChangeReadStatus(ctx context.Context, in *ChangeReadStatusReq, opts ...grpc.CallOption) (*Response, error)
-		//   查询指定用户未读消息合计
+		// 查询指定用户未读消息合计
 		GetUnreadCount(ctx context.Context, in *GetUnreadCountRequest, opts ...grpc.CallOption) (*GetUnreadCountResponse, error)
-		//   查询指定用户的历史消息记录
+		// 查询指定用户的历史消息记录
 		FindUserMsg(ctx context.Context, in *FindUserMsgReq, opts ...grpc.CallOption) (*FindUserMsgRes, error)
-		//   查询指定用户指定分类的未读消息合计
+		// 查询指定用户指定分类的未读消息合计
 		GetClassUnreadCount(ctx context.Context, in *GetClassUnreadCountReq, opts ...grpc.CallOption) (*GetUnreadCountResponse, error)
-		//   获取指定用户指定分类的最新一条消息
+		// 获取指定用户指定分类的最新一条消息
 		GetLastMessage(ctx context.Context, in *GetLastMessageReq, opts ...grpc.CallOption) (*GetLastMessageRes, error)
 		// 查看详细详情
 		FindMessageDetail(ctx context.Context, in *MessageDetailReq, opts ...grpc.CallOption) (*MessageDetailResp, error)
-		//   获取指定用户的分类及未读消息数量
+		// 获取指定用户的分类及未读消息数量
 		GetUnreadClassCount(ctx context.Context, in *GetUnreadClassCountReq, opts ...grpc.CallOption) (*GetUnreadClassCountRes, error)
-		//   获取指定用户收到消息的分类
+		// 获取指定用户收到消息的分类
 		GetMsgType(ctx context.Context, in *GetMsgTypeReq, opts ...grpc.CallOption) (*GetMsgTypeRes, error)
-		//   查询指定用户的浮标消息
+		// 查询指定用户的浮标消息
 		FindUserBuoyMsg(ctx context.Context, in *FindUserBuoyMsgReq, opts ...grpc.CallOption) (*FindUserBuoyMsgRes, error)
-		//    一键清空未读消息
+		// 一键清空未读消息
 		ClearUnreadMsg(ctx context.Context, in *ClearUnreadMsgReq, opts ...grpc.CallOption) (*Response, error)
-		//    new用户消息列表
+		// new用户消息列表
 		UserMsgList(ctx context.Context, in *UserMsgListReq, opts ...grpc.CallOption) (*UserMsgListRes, error)
-		//   发送微信模版消息
-		SendWxTmplMsg(ctx context.Context, in *WxTmplMsg, opts ...grpc.CallOption) (*Response, error)
-		//    官网、移动端首页、工作桌面消息滚动
+		// 发送剑鱼学堂微信模版消息
+		SendWxTmplJySchoolMsg(ctx context.Context, in *JySchoolMsg, opts ...grpc.CallOption) (*SendMsgResponse, error)
+		// 发送剑鱼系统通用模版消息
+		SendWxTmplSystemDefaultMsg(ctx context.Context, in *SystemDefaultMsg, opts ...grpc.CallOption) (*SendMsgResponse, error)
+		// 官网、移动端首页、工作桌面消息滚动
 		UserUnreadMsgList(ctx context.Context, in *UserUnreadMsgListReq, opts ...grpc.CallOption) (*UserUnreadMsgListRes, error)
 	}
 
@@ -94,31 +99,31 @@ func (m *defaultMessage) MultipleSaveMsg(ctx context.Context, in *MultipleSaveMs
 	return client.MultipleSaveMsg(ctx, in, opts...)
 }
 
-//  修改消息阅读状态
+// 修改消息阅读状态
 func (m *defaultMessage) ChangeReadStatus(ctx context.Context, in *ChangeReadStatusReq, opts ...grpc.CallOption) (*Response, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	return client.ChangeReadStatus(ctx, in, opts...)
 }
 
-//   查询指定用户未读消息合计
+// 查询指定用户未读消息合计
 func (m *defaultMessage) GetUnreadCount(ctx context.Context, in *GetUnreadCountRequest, opts ...grpc.CallOption) (*GetUnreadCountResponse, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	return client.GetUnreadCount(ctx, in, opts...)
 }
 
-//   查询指定用户的历史消息记录
+// 查询指定用户的历史消息记录
 func (m *defaultMessage) FindUserMsg(ctx context.Context, in *FindUserMsgReq, opts ...grpc.CallOption) (*FindUserMsgRes, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	return client.FindUserMsg(ctx, in, opts...)
 }
 
-//   查询指定用户指定分类的未读消息合计
+// 查询指定用户指定分类的未读消息合计
 func (m *defaultMessage) GetClassUnreadCount(ctx context.Context, in *GetClassUnreadCountReq, opts ...grpc.CallOption) (*GetUnreadCountResponse, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	return client.GetClassUnreadCount(ctx, in, opts...)
 }
 
-//   获取指定用户指定分类的最新一条消息
+// 获取指定用户指定分类的最新一条消息
 func (m *defaultMessage) GetLastMessage(ctx context.Context, in *GetLastMessageReq, opts ...grpc.CallOption) (*GetLastMessageRes, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	return client.GetLastMessage(ctx, in, opts...)
@@ -130,43 +135,49 @@ func (m *defaultMessage) FindMessageDetail(ctx context.Context, in *MessageDetai
 	return client.FindMessageDetail(ctx, in, opts...)
 }
 
-//   获取指定用户的分类及未读消息数量
+// 获取指定用户的分类及未读消息数量
 func (m *defaultMessage) GetUnreadClassCount(ctx context.Context, in *GetUnreadClassCountReq, opts ...grpc.CallOption) (*GetUnreadClassCountRes, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	return client.GetUnreadClassCount(ctx, in, opts...)
 }
 
-//   获取指定用户收到消息的分类
+// 获取指定用户收到消息的分类
 func (m *defaultMessage) GetMsgType(ctx context.Context, in *GetMsgTypeReq, opts ...grpc.CallOption) (*GetMsgTypeRes, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	return client.GetMsgType(ctx, in, opts...)
 }
 
-//   查询指定用户的浮标消息
+// 查询指定用户的浮标消息
 func (m *defaultMessage) FindUserBuoyMsg(ctx context.Context, in *FindUserBuoyMsgReq, opts ...grpc.CallOption) (*FindUserBuoyMsgRes, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	return client.FindUserBuoyMsg(ctx, in, opts...)
 }
 
-//    一键清空未读消息
+// 一键清空未读消息
 func (m *defaultMessage) ClearUnreadMsg(ctx context.Context, in *ClearUnreadMsgReq, opts ...grpc.CallOption) (*Response, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	return client.ClearUnreadMsg(ctx, in, opts...)
 }
 
-//    new用户消息列表
+// new用户消息列表
 func (m *defaultMessage) UserMsgList(ctx context.Context, in *UserMsgListReq, opts ...grpc.CallOption) (*UserMsgListRes, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	return client.UserMsgList(ctx, in, opts...)
 }
 
-//   发送微信模版消息
-func (m *defaultMessage) SendWxTmplMsg(ctx context.Context, in *WxTmplMsg, opts ...grpc.CallOption) (*Response, error) {
+// 发送剑鱼学堂微信模版消息
+func (m *defaultMessage) SendWxTmplJySchoolMsg(ctx context.Context, in *JySchoolMsg, opts ...grpc.CallOption) (*SendMsgResponse, error) {
 	client := message.NewMessageClient(m.cli.Conn())
-	return client.SendWxTmplMsg(ctx, in, opts...)
+	return client.SendWxTmplJySchoolMsg(ctx, in, opts...)
 }
 
-//    官网、移动端首页、工作桌面消息滚动
+// 发送剑鱼系统通用模版消息
+func (m *defaultMessage) SendWxTmplSystemDefaultMsg(ctx context.Context, in *SystemDefaultMsg, opts ...grpc.CallOption) (*SendMsgResponse, error) {
+	client := message.NewMessageClient(m.cli.Conn())
+	return client.SendWxTmplSystemDefaultMsg(ctx, in, opts...)
+}
+
+// 官网、移动端首页、工作桌面消息滚动
 func (m *defaultMessage) UserUnreadMsgList(ctx context.Context, in *UserUnreadMsgListReq, opts ...grpc.CallOption) (*UserUnreadMsgListRes, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	return client.UserUnreadMsgList(ctx, in, opts...)

+ 402 - 90
rpc/type/message/message.pb.go

@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.28.1
-// 	protoc        v3.19.4
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
 // source: message.proto
 
 package message
@@ -2424,6 +2424,245 @@ func (x *UserUnreadMsgListRes) GetCount() int64 {
 	return 0
 }
 
+// 剑鱼学堂模版消息
+type JySchoolMsg struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	UserIds string `protobuf:"bytes,1,opt,name=userIds,proto3" json:"userIds,omitempty"` //接受人 mongo_userId(多个用,分割)
+	Title   string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`     //课程名称
+	Date    string `protobuf:"bytes,3,opt,name=date,proto3" json:"date,omitempty"`       //课程时间
+	Address string `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` //课程地点
+	Class   string `protobuf:"bytes,5,opt,name=class,proto3" json:"class,omitempty"`     //课程类型
+	Url     string `protobuf:"bytes,6,opt,name=url,proto3" json:"url,omitempty"`         //消息跳转连接
+}
+
+func (x *JySchoolMsg) Reset() {
+	*x = JySchoolMsg{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_message_proto_msgTypes[32]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *JySchoolMsg) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*JySchoolMsg) ProtoMessage() {}
+
+func (x *JySchoolMsg) ProtoReflect() protoreflect.Message {
+	mi := &file_message_proto_msgTypes[32]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use JySchoolMsg.ProtoReflect.Descriptor instead.
+func (*JySchoolMsg) Descriptor() ([]byte, []int) {
+	return file_message_proto_rawDescGZIP(), []int{32}
+}
+
+func (x *JySchoolMsg) GetUserIds() string {
+	if x != nil {
+		return x.UserIds
+	}
+	return ""
+}
+
+func (x *JySchoolMsg) GetTitle() string {
+	if x != nil {
+		return x.Title
+	}
+	return ""
+}
+
+func (x *JySchoolMsg) GetDate() string {
+	if x != nil {
+		return x.Date
+	}
+	return ""
+}
+
+func (x *JySchoolMsg) GetAddress() string {
+	if x != nil {
+		return x.Address
+	}
+	return ""
+}
+
+func (x *JySchoolMsg) GetClass() string {
+	if x != nil {
+		return x.Class
+	}
+	return ""
+}
+
+func (x *JySchoolMsg) GetUrl() string {
+	if x != nil {
+		return x.Url
+	}
+	return ""
+}
+
+// 剑鱼系统通用模版
+type SystemDefaultMsg struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	UserIds      string `protobuf:"bytes,1,opt,name=userIds,proto3" json:"userIds,omitempty"`           //接受人 mongo_userId(多个用,分割)
+	PositionIds  string `protobuf:"bytes,2,opt,name=positionIds,proto3" json:"positionIds,omitempty"`   //接受人 职位id(多个用,分割)
+	MessageClass string `protobuf:"bytes,3,opt,name=messageClass,proto3" json:"messageClass,omitempty"` //数据库中switch字段
+	Title        string `protobuf:"bytes,4,opt,name=title,proto3" json:"title,omitempty"`               //课程名称
+	Detail       string `protobuf:"bytes,5,opt,name=detail,proto3" json:"detail,omitempty"`             //课程时间
+	Date         string `protobuf:"bytes,6,opt,name=date,proto3" json:"date,omitempty"`                 //课程地点
+	Url          string `protobuf:"bytes,7,opt,name=url,proto3" json:"url,omitempty"`                   //消息跳转连接
+}
+
+func (x *SystemDefaultMsg) Reset() {
+	*x = SystemDefaultMsg{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_message_proto_msgTypes[33]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SystemDefaultMsg) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SystemDefaultMsg) ProtoMessage() {}
+
+func (x *SystemDefaultMsg) ProtoReflect() protoreflect.Message {
+	mi := &file_message_proto_msgTypes[33]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SystemDefaultMsg.ProtoReflect.Descriptor instead.
+func (*SystemDefaultMsg) Descriptor() ([]byte, []int) {
+	return file_message_proto_rawDescGZIP(), []int{33}
+}
+
+func (x *SystemDefaultMsg) GetUserIds() string {
+	if x != nil {
+		return x.UserIds
+	}
+	return ""
+}
+
+func (x *SystemDefaultMsg) GetPositionIds() string {
+	if x != nil {
+		return x.PositionIds
+	}
+	return ""
+}
+
+func (x *SystemDefaultMsg) GetMessageClass() string {
+	if x != nil {
+		return x.MessageClass
+	}
+	return ""
+}
+
+func (x *SystemDefaultMsg) GetTitle() string {
+	if x != nil {
+		return x.Title
+	}
+	return ""
+}
+
+func (x *SystemDefaultMsg) GetDetail() string {
+	if x != nil {
+		return x.Detail
+	}
+	return ""
+}
+
+func (x *SystemDefaultMsg) GetDate() string {
+	if x != nil {
+		return x.Date
+	}
+	return ""
+}
+
+func (x *SystemDefaultMsg) GetUrl() string {
+	if x != nil {
+		return x.Url
+	}
+	return ""
+}
+
+type SendMsgResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Total   int64  `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"`    //发送数量
+	Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` //响应消息
+}
+
+func (x *SendMsgResponse) Reset() {
+	*x = SendMsgResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_message_proto_msgTypes[34]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SendMsgResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SendMsgResponse) ProtoMessage() {}
+
+func (x *SendMsgResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_message_proto_msgTypes[34]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SendMsgResponse.ProtoReflect.Descriptor instead.
+func (*SendMsgResponse) Descriptor() ([]byte, []int) {
+	return file_message_proto_rawDescGZIP(), []int{34}
+}
+
+func (x *SendMsgResponse) GetTotal() int64 {
+	if x != nil {
+		return x.Total
+	}
+	return 0
+}
+
+func (x *SendMsgResponse) GetMessage() string {
+	if x != nil {
+		return x.Message
+	}
+	return ""
+}
+
 var File_message_proto protoreflect.FileDescriptor
 
 var file_message_proto_rawDesc = []byte{
@@ -2711,73 +2950,105 @@ var file_message_proto_rawDesc = []byte{
 	0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d,
 	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a,
 	0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f,
-	0x75, 0x6e, 0x74, 0x32, 0x90, 0x08, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
-	0x4c, 0x0a, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x53, 0x61, 0x76, 0x65, 0x4d,
-	0x73, 0x67, 0x12, 0x1b, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x6d, 0x75, 0x6c,
-	0x74, 0x69, 0x70, 0x6c, 0x65, 0x53, 0x61, 0x76, 0x65, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x71, 0x1a,
-	0x1c, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
-	0x6c, 0x65, 0x53, 0x61, 0x76, 0x65, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x43, 0x0a,
-	0x10, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75,
-	0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e,
-	0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x1a,
-	0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x51, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43,
-	0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47,
-	0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47,
-	0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73,
-	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65,
-	0x72, 0x4d, 0x73, 0x67, 0x12, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46,
-	0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e,
-	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72,
-	0x4d, 0x73, 0x67, 0x52, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x61,
-	0x73, 0x73, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e,
-	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73,
-	0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f,
+	0x75, 0x6e, 0x74, 0x22, 0x93, 0x01, 0x0a, 0x0b, 0x4a, 0x79, 0x53, 0x63, 0x68, 0x6f, 0x6f, 0x6c,
+	0x4d, 0x73, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x14, 0x0a,
+	0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69,
+	0x74, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
+	0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
+	0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0xc6, 0x01, 0x0a, 0x10, 0x53, 0x79,
+	0x73, 0x74, 0x65, 0x6d, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d, 0x73, 0x67, 0x12, 0x18,
+	0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x6f, 0x73, 0x69,
+	0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70,
+	0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x14,
+	0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74,
+	0x69, 0x74, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x05,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x12, 0x0a, 0x04,
+	0x64, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65,
+	0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75,
+	0x72, 0x6c, 0x22, 0x41, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0xf4, 0x08, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x12, 0x4c, 0x0a, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x53, 0x61, 0x76,
+	0x65, 0x4d, 0x73, 0x67, 0x12, 0x1b, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x6d,
+	0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x53, 0x61, 0x76, 0x65, 0x4d, 0x73, 0x67, 0x52, 0x65,
+	0x71, 0x1a, 0x1c, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x6d, 0x75, 0x6c, 0x74,
+	0x69, 0x70, 0x6c, 0x65, 0x53, 0x61, 0x76, 0x65, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12,
+	0x43, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x53, 0x74, 0x61,
+	0x74, 0x75, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x68,
+	0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65,
+	0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61,
+	0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x64, 0x55,
+	0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x71, 0x1a,
+	0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73,
+	0x65, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43,
+	0x6c, 0x61, 0x73, 0x73, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12,
+	0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x61,
+	0x73, 0x73, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71,
+	0x1a, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e,
+	0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x48, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x12, 0x1a, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65,
+	0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a,
+	0x1a, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x73,
+	0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x11, 0x46,
+	0x69, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c,
+	0x12, 0x19, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x74,
+	0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x55, 0x6e,
+	0x72, 0x65, 0x61, 0x64, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f,
 	0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65,
-	0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
-	0x48, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
-	0x65, 0x12, 0x1a, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4c,
-	0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e,
-	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d,
-	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x11, 0x46, 0x69, 0x6e,
-	0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x19,
-	0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
-	0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x65, 0x73, 0x73,
-	0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69,
-	0x6c, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65,
-	0x61, 0x64, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x6d,
-	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64,
-	0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e,
-	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61,
-	0x64, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x12, 0x3c,
-	0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4d, 0x73, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x2e, 0x6d,
-	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x73, 0x67, 0x54, 0x79, 0x70,
-	0x65, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47,
-	0x65, 0x74, 0x4d, 0x73, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x0f,
-	0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x75, 0x6f, 0x79, 0x4d, 0x73, 0x67, 0x12,
-	0x1b, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73,
-	0x65, 0x72, 0x42, 0x75, 0x6f, 0x79, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d,
-	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42,
-	0x75, 0x6f, 0x79, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x0e, 0x43, 0x6c, 0x65,
-	0x61, 0x72, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x4d, 0x73, 0x67, 0x12, 0x1a, 0x2e, 0x6d, 0x65,
-	0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x55, 0x6e, 0x72, 0x65, 0x61,
-	0x64, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
-	0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x55, 0x73,
-	0x65, 0x72, 0x4d, 0x73, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73,
-	0x61, 0x67, 0x65, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52,
-	0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x55, 0x73, 0x65,
-	0x72, 0x4d, 0x73, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x0d, 0x53,
-	0x65, 0x6e, 0x64, 0x57, 0x78, 0x54, 0x6d, 0x70, 0x6c, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x2e, 0x6d,
-	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x57, 0x78, 0x54, 0x6d, 0x70, 0x6c, 0x4d, 0x73, 0x67,
-	0x1a, 0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x11, 0x55, 0x73, 0x65, 0x72, 0x55, 0x6e, 0x72, 0x65, 0x61,
-	0x64, 0x4d, 0x73, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61,
-	0x67, 0x65, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x4d, 0x73, 0x67,
-	0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
-	0x65, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x4d, 0x73, 0x67, 0x4c,
-	0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x42, 0x0a, 0x5a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
-	0x65, 0x2f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x61, 0x64, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a,
+	0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72,
+	0x65, 0x61, 0x64, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73,
+	0x12, 0x3c, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4d, 0x73, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16,
+	0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x73, 0x67, 0x54,
+	0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x2e, 0x47, 0x65, 0x74, 0x4d, 0x73, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, 0x12, 0x4b,
+	0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x75, 0x6f, 0x79, 0x4d, 0x73,
+	0x67, 0x12, 0x1b, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6e, 0x64,
+	0x55, 0x73, 0x65, 0x72, 0x42, 0x75, 0x6f, 0x79, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x1b,
+	0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65,
+	0x72, 0x42, 0x75, 0x6f, 0x79, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x0e, 0x43,
+	0x6c, 0x65, 0x61, 0x72, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x4d, 0x73, 0x67, 0x12, 0x1a, 0x2e,
+	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x55, 0x6e, 0x72,
+	0x65, 0x61, 0x64, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b,
+	0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x6d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x4c, 0x69, 0x73,
+	0x74, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x55,
+	0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x12, 0x47, 0x0a,
+	0x15, 0x53, 0x65, 0x6e, 0x64, 0x57, 0x78, 0x54, 0x6d, 0x70, 0x6c, 0x4a, 0x79, 0x53, 0x63, 0x68,
+	0x6f, 0x6f, 0x6c, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x2e, 0x4a, 0x79, 0x53, 0x63, 0x68, 0x6f, 0x6f, 0x6c, 0x4d, 0x73, 0x67, 0x1a, 0x18, 0x2e, 0x6d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x73, 0x67, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x1a, 0x53, 0x65, 0x6e, 0x64, 0x57, 0x78,
+	0x54, 0x6d, 0x70, 0x6c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c,
+	0x74, 0x4d, 0x73, 0x67, 0x12, 0x19, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53,
+	0x79, 0x73, 0x74, 0x65, 0x6d, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d, 0x73, 0x67, 0x1a,
+	0x18, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x73,
+	0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x11, 0x55, 0x73, 0x65,
+	0x72, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x4d, 0x73, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d,
+	0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x55, 0x6e, 0x72,
+	0x65, 0x61, 0x64, 0x4d, 0x73, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e,
+	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x55, 0x6e, 0x72, 0x65,
+	0x61, 0x64, 0x4d, 0x73, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x42, 0x0a, 0x5a, 0x08,
+	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -2792,7 +3063,7 @@ func file_message_proto_rawDescGZIP() []byte {
 	return file_message_proto_rawDescData
 }
 
-var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 33)
+var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 36)
 var file_message_proto_goTypes = []interface{}{
 	(*ChangeReadStatusReq)(nil),    // 0: message.ChangeReadStatusReq
 	(*ResCount)(nil),               // 1: message.ResCount
@@ -2826,10 +3097,13 @@ var file_message_proto_goTypes = []interface{}{
 	(*WxTmplResponse)(nil),         // 29: message.WxTmplResponse
 	(*UserUnreadMsgListReq)(nil),   // 30: message.UserUnreadMsgListReq
 	(*UserUnreadMsgListRes)(nil),   // 31: message.UserUnreadMsgListRes
-	nil,                            // 32: message.Messages.UrlEntry
+	(*JySchoolMsg)(nil),            // 32: message.JySchoolMsg
+	(*SystemDefaultMsg)(nil),       // 33: message.SystemDefaultMsg
+	(*SendMsgResponse)(nil),        // 34: message.SendMsgResponse
+	nil,                            // 35: message.Messages.UrlEntry
 }
 var file_message_proto_depIdxs = []int32{
-	32, // 0: message.Messages.url:type_name -> message.Messages.UrlEntry
+	35, // 0: message.Messages.url:type_name -> message.Messages.UrlEntry
 	6,  // 1: message.FindUserMsgRes.data:type_name -> message.Messages
 	6,  // 2: message.MessageDetailResp.data:type_name -> message.Messages
 	6,  // 3: message.GetLastMessageRes.data:type_name -> message.Messages
@@ -2855,24 +3129,26 @@ var file_message_proto_depIdxs = []int32{
 	20, // 23: message.Message.FindUserBuoyMsg:input_type -> message.FindUserBuoyMsgReq
 	23, // 24: message.Message.ClearUnreadMsg:input_type -> message.ClearUnreadMsgReq
 	24, // 25: message.Message.UserMsgList:input_type -> message.UserMsgListReq
-	27, // 26: message.Message.SendWxTmplMsg:input_type -> message.WxTmplMsg
-	30, // 27: message.Message.UserUnreadMsgList:input_type -> message.UserUnreadMsgListReq
-	19, // 28: message.Message.multipleSaveMsg:output_type -> message.multipleSaveMsgResp
-	3,  // 29: message.Message.ChangeReadStatus:output_type -> message.Response
-	4,  // 30: message.Message.GetUnreadCount:output_type -> message.GetUnreadCountResponse
-	7,  // 31: message.Message.FindUserMsg:output_type -> message.FindUserMsgRes
-	4,  // 32: message.Message.GetClassUnreadCount:output_type -> message.GetUnreadCountResponse
-	12, // 33: message.Message.GetLastMessage:output_type -> message.GetLastMessageRes
-	10, // 34: message.Message.FindMessageDetail:output_type -> message.MessageDetailResp
-	14, // 35: message.Message.GetUnreadClassCount:output_type -> message.GetUnreadClassCountRes
-	16, // 36: message.Message.GetMsgType:output_type -> message.GetMsgTypeRes
-	21, // 37: message.Message.FindUserBuoyMsg:output_type -> message.FindUserBuoyMsgRes
-	3,  // 38: message.Message.ClearUnreadMsg:output_type -> message.Response
-	25, // 39: message.Message.UserMsgList:output_type -> message.UserMsgListRes
-	3,  // 40: message.Message.SendWxTmplMsg:output_type -> message.Response
-	31, // 41: message.Message.UserUnreadMsgList:output_type -> message.UserUnreadMsgListRes
-	28, // [28:42] is the sub-list for method output_type
-	14, // [14:28] is the sub-list for method input_type
+	32, // 26: message.Message.SendWxTmplJySchoolMsg:input_type -> message.JySchoolMsg
+	33, // 27: message.Message.SendWxTmplSystemDefaultMsg:input_type -> message.SystemDefaultMsg
+	30, // 28: message.Message.UserUnreadMsgList:input_type -> message.UserUnreadMsgListReq
+	19, // 29: message.Message.multipleSaveMsg:output_type -> message.multipleSaveMsgResp
+	3,  // 30: message.Message.ChangeReadStatus:output_type -> message.Response
+	4,  // 31: message.Message.GetUnreadCount:output_type -> message.GetUnreadCountResponse
+	7,  // 32: message.Message.FindUserMsg:output_type -> message.FindUserMsgRes
+	4,  // 33: message.Message.GetClassUnreadCount:output_type -> message.GetUnreadCountResponse
+	12, // 34: message.Message.GetLastMessage:output_type -> message.GetLastMessageRes
+	10, // 35: message.Message.FindMessageDetail:output_type -> message.MessageDetailResp
+	14, // 36: message.Message.GetUnreadClassCount:output_type -> message.GetUnreadClassCountRes
+	16, // 37: message.Message.GetMsgType:output_type -> message.GetMsgTypeRes
+	21, // 38: message.Message.FindUserBuoyMsg:output_type -> message.FindUserBuoyMsgRes
+	3,  // 39: message.Message.ClearUnreadMsg:output_type -> message.Response
+	25, // 40: message.Message.UserMsgList:output_type -> message.UserMsgListRes
+	34, // 41: message.Message.SendWxTmplJySchoolMsg:output_type -> message.SendMsgResponse
+	34, // 42: message.Message.SendWxTmplSystemDefaultMsg:output_type -> message.SendMsgResponse
+	31, // 43: message.Message.UserUnreadMsgList:output_type -> message.UserUnreadMsgListRes
+	29, // [29:44] is the sub-list for method output_type
+	14, // [14:29] is the sub-list for method input_type
 	14, // [14:14] is the sub-list for extension type_name
 	14, // [14:14] is the sub-list for extension extendee
 	0,  // [0:14] is the sub-list for field type_name
@@ -3268,6 +3544,42 @@ func file_message_proto_init() {
 				return nil
 			}
 		}
+		file_message_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*JySchoolMsg); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_message_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SystemDefaultMsg); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_message_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SendMsgResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
@@ -3275,7 +3587,7 @@ func file_message_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_message_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   33,
+			NumMessages:   36,
 			NumExtensions: 0,
 			NumServices:   1,
 		},

+ 100 - 44
rpc/type/message/message_grpc.pb.go

@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 // versions:
-// - protoc-gen-go-grpc v1.2.0
-// - protoc             v3.19.4
+// - protoc-gen-go-grpc v1.3.0
+// - protoc             v3.21.12
 // source: message.proto
 
 package message
@@ -18,6 +18,24 @@ import (
 // Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
+const (
+	Message_MultipleSaveMsg_FullMethodName            = "/message.Message/multipleSaveMsg"
+	Message_ChangeReadStatus_FullMethodName           = "/message.Message/ChangeReadStatus"
+	Message_GetUnreadCount_FullMethodName             = "/message.Message/GetUnreadCount"
+	Message_FindUserMsg_FullMethodName                = "/message.Message/FindUserMsg"
+	Message_GetClassUnreadCount_FullMethodName        = "/message.Message/GetClassUnreadCount"
+	Message_GetLastMessage_FullMethodName             = "/message.Message/GetLastMessage"
+	Message_FindMessageDetail_FullMethodName          = "/message.Message/FindMessageDetail"
+	Message_GetUnreadClassCount_FullMethodName        = "/message.Message/GetUnreadClassCount"
+	Message_GetMsgType_FullMethodName                 = "/message.Message/GetMsgType"
+	Message_FindUserBuoyMsg_FullMethodName            = "/message.Message/FindUserBuoyMsg"
+	Message_ClearUnreadMsg_FullMethodName             = "/message.Message/ClearUnreadMsg"
+	Message_UserMsgList_FullMethodName                = "/message.Message/UserMsgList"
+	Message_SendWxTmplJySchoolMsg_FullMethodName      = "/message.Message/SendWxTmplJySchoolMsg"
+	Message_SendWxTmplSystemDefaultMsg_FullMethodName = "/message.Message/SendWxTmplSystemDefaultMsg"
+	Message_UserUnreadMsgList_FullMethodName          = "/message.Message/UserUnreadMsgList"
+)
+
 // MessageClient is the client API for Message service.
 //
 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
@@ -46,8 +64,10 @@ type MessageClient interface {
 	ClearUnreadMsg(ctx context.Context, in *ClearUnreadMsgReq, opts ...grpc.CallOption) (*Response, error)
 	// new用户消息列表
 	UserMsgList(ctx context.Context, in *UserMsgListReq, opts ...grpc.CallOption) (*UserMsgListRes, error)
-	// 发送微信模版消息
-	SendWxTmplMsg(ctx context.Context, in *WxTmplMsg, opts ...grpc.CallOption) (*Response, error)
+	// 发送剑鱼学堂微信模版消息
+	SendWxTmplJySchoolMsg(ctx context.Context, in *JySchoolMsg, opts ...grpc.CallOption) (*SendMsgResponse, error)
+	// 发送剑鱼系统通用模版消息
+	SendWxTmplSystemDefaultMsg(ctx context.Context, in *SystemDefaultMsg, opts ...grpc.CallOption) (*SendMsgResponse, error)
 	// 官网、移动端首页、工作桌面消息滚动
 	UserUnreadMsgList(ctx context.Context, in *UserUnreadMsgListReq, opts ...grpc.CallOption) (*UserUnreadMsgListRes, error)
 }
@@ -62,7 +82,7 @@ func NewMessageClient(cc grpc.ClientConnInterface) MessageClient {
 
 func (c *messageClient) MultipleSaveMsg(ctx context.Context, in *MultipleSaveMsgReq, opts ...grpc.CallOption) (*MultipleSaveMsgResp, error) {
 	out := new(MultipleSaveMsgResp)
-	err := c.cc.Invoke(ctx, "/message.Message/multipleSaveMsg", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_MultipleSaveMsg_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -71,7 +91,7 @@ func (c *messageClient) MultipleSaveMsg(ctx context.Context, in *MultipleSaveMsg
 
 func (c *messageClient) ChangeReadStatus(ctx context.Context, in *ChangeReadStatusReq, opts ...grpc.CallOption) (*Response, error) {
 	out := new(Response)
-	err := c.cc.Invoke(ctx, "/message.Message/ChangeReadStatus", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_ChangeReadStatus_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -80,7 +100,7 @@ func (c *messageClient) ChangeReadStatus(ctx context.Context, in *ChangeReadStat
 
 func (c *messageClient) GetUnreadCount(ctx context.Context, in *GetUnreadCountRequest, opts ...grpc.CallOption) (*GetUnreadCountResponse, error) {
 	out := new(GetUnreadCountResponse)
-	err := c.cc.Invoke(ctx, "/message.Message/GetUnreadCount", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_GetUnreadCount_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -89,7 +109,7 @@ func (c *messageClient) GetUnreadCount(ctx context.Context, in *GetUnreadCountRe
 
 func (c *messageClient) FindUserMsg(ctx context.Context, in *FindUserMsgReq, opts ...grpc.CallOption) (*FindUserMsgRes, error) {
 	out := new(FindUserMsgRes)
-	err := c.cc.Invoke(ctx, "/message.Message/FindUserMsg", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_FindUserMsg_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -98,7 +118,7 @@ func (c *messageClient) FindUserMsg(ctx context.Context, in *FindUserMsgReq, opt
 
 func (c *messageClient) GetClassUnreadCount(ctx context.Context, in *GetClassUnreadCountReq, opts ...grpc.CallOption) (*GetUnreadCountResponse, error) {
 	out := new(GetUnreadCountResponse)
-	err := c.cc.Invoke(ctx, "/message.Message/GetClassUnreadCount", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_GetClassUnreadCount_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -107,7 +127,7 @@ func (c *messageClient) GetClassUnreadCount(ctx context.Context, in *GetClassUnr
 
 func (c *messageClient) GetLastMessage(ctx context.Context, in *GetLastMessageReq, opts ...grpc.CallOption) (*GetLastMessageRes, error) {
 	out := new(GetLastMessageRes)
-	err := c.cc.Invoke(ctx, "/message.Message/GetLastMessage", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_GetLastMessage_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -116,7 +136,7 @@ func (c *messageClient) GetLastMessage(ctx context.Context, in *GetLastMessageRe
 
 func (c *messageClient) FindMessageDetail(ctx context.Context, in *MessageDetailReq, opts ...grpc.CallOption) (*MessageDetailResp, error) {
 	out := new(MessageDetailResp)
-	err := c.cc.Invoke(ctx, "/message.Message/FindMessageDetail", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_FindMessageDetail_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -125,7 +145,7 @@ func (c *messageClient) FindMessageDetail(ctx context.Context, in *MessageDetail
 
 func (c *messageClient) GetUnreadClassCount(ctx context.Context, in *GetUnreadClassCountReq, opts ...grpc.CallOption) (*GetUnreadClassCountRes, error) {
 	out := new(GetUnreadClassCountRes)
-	err := c.cc.Invoke(ctx, "/message.Message/GetUnreadClassCount", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_GetUnreadClassCount_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -134,7 +154,7 @@ func (c *messageClient) GetUnreadClassCount(ctx context.Context, in *GetUnreadCl
 
 func (c *messageClient) GetMsgType(ctx context.Context, in *GetMsgTypeReq, opts ...grpc.CallOption) (*GetMsgTypeRes, error) {
 	out := new(GetMsgTypeRes)
-	err := c.cc.Invoke(ctx, "/message.Message/GetMsgType", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_GetMsgType_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -143,7 +163,7 @@ func (c *messageClient) GetMsgType(ctx context.Context, in *GetMsgTypeReq, opts
 
 func (c *messageClient) FindUserBuoyMsg(ctx context.Context, in *FindUserBuoyMsgReq, opts ...grpc.CallOption) (*FindUserBuoyMsgRes, error) {
 	out := new(FindUserBuoyMsgRes)
-	err := c.cc.Invoke(ctx, "/message.Message/FindUserBuoyMsg", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_FindUserBuoyMsg_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -152,7 +172,7 @@ func (c *messageClient) FindUserBuoyMsg(ctx context.Context, in *FindUserBuoyMsg
 
 func (c *messageClient) ClearUnreadMsg(ctx context.Context, in *ClearUnreadMsgReq, opts ...grpc.CallOption) (*Response, error) {
 	out := new(Response)
-	err := c.cc.Invoke(ctx, "/message.Message/ClearUnreadMsg", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_ClearUnreadMsg_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -161,16 +181,25 @@ func (c *messageClient) ClearUnreadMsg(ctx context.Context, in *ClearUnreadMsgRe
 
 func (c *messageClient) UserMsgList(ctx context.Context, in *UserMsgListReq, opts ...grpc.CallOption) (*UserMsgListRes, error) {
 	out := new(UserMsgListRes)
-	err := c.cc.Invoke(ctx, "/message.Message/UserMsgList", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_UserMsgList_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
 	return out, nil
 }
 
-func (c *messageClient) SendWxTmplMsg(ctx context.Context, in *WxTmplMsg, opts ...grpc.CallOption) (*Response, error) {
-	out := new(Response)
-	err := c.cc.Invoke(ctx, "/message.Message/SendWxTmplMsg", in, out, opts...)
+func (c *messageClient) SendWxTmplJySchoolMsg(ctx context.Context, in *JySchoolMsg, opts ...grpc.CallOption) (*SendMsgResponse, error) {
+	out := new(SendMsgResponse)
+	err := c.cc.Invoke(ctx, Message_SendWxTmplJySchoolMsg_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *messageClient) SendWxTmplSystemDefaultMsg(ctx context.Context, in *SystemDefaultMsg, opts ...grpc.CallOption) (*SendMsgResponse, error) {
+	out := new(SendMsgResponse)
+	err := c.cc.Invoke(ctx, Message_SendWxTmplSystemDefaultMsg_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -179,7 +208,7 @@ func (c *messageClient) SendWxTmplMsg(ctx context.Context, in *WxTmplMsg, opts .
 
 func (c *messageClient) UserUnreadMsgList(ctx context.Context, in *UserUnreadMsgListReq, opts ...grpc.CallOption) (*UserUnreadMsgListRes, error) {
 	out := new(UserUnreadMsgListRes)
-	err := c.cc.Invoke(ctx, "/message.Message/UserUnreadMsgList", in, out, opts...)
+	err := c.cc.Invoke(ctx, Message_UserUnreadMsgList_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -214,8 +243,10 @@ type MessageServer interface {
 	ClearUnreadMsg(context.Context, *ClearUnreadMsgReq) (*Response, error)
 	// new用户消息列表
 	UserMsgList(context.Context, *UserMsgListReq) (*UserMsgListRes, error)
-	// 发送微信模版消息
-	SendWxTmplMsg(context.Context, *WxTmplMsg) (*Response, error)
+	// 发送剑鱼学堂微信模版消息
+	SendWxTmplJySchoolMsg(context.Context, *JySchoolMsg) (*SendMsgResponse, error)
+	// 发送剑鱼系统通用模版消息
+	SendWxTmplSystemDefaultMsg(context.Context, *SystemDefaultMsg) (*SendMsgResponse, error)
 	// 官网、移动端首页、工作桌面消息滚动
 	UserUnreadMsgList(context.Context, *UserUnreadMsgListReq) (*UserUnreadMsgListRes, error)
 	mustEmbedUnimplementedMessageServer()
@@ -261,8 +292,11 @@ func (UnimplementedMessageServer) ClearUnreadMsg(context.Context, *ClearUnreadMs
 func (UnimplementedMessageServer) UserMsgList(context.Context, *UserMsgListReq) (*UserMsgListRes, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method UserMsgList not implemented")
 }
-func (UnimplementedMessageServer) SendWxTmplMsg(context.Context, *WxTmplMsg) (*Response, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method SendWxTmplMsg not implemented")
+func (UnimplementedMessageServer) SendWxTmplJySchoolMsg(context.Context, *JySchoolMsg) (*SendMsgResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SendWxTmplJySchoolMsg not implemented")
+}
+func (UnimplementedMessageServer) SendWxTmplSystemDefaultMsg(context.Context, *SystemDefaultMsg) (*SendMsgResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SendWxTmplSystemDefaultMsg not implemented")
 }
 func (UnimplementedMessageServer) UserUnreadMsgList(context.Context, *UserUnreadMsgListReq) (*UserUnreadMsgListRes, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method UserUnreadMsgList not implemented")
@@ -290,7 +324,7 @@ func _Message_MultipleSaveMsg_Handler(srv interface{}, ctx context.Context, dec
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/multipleSaveMsg",
+		FullMethod: Message_MultipleSaveMsg_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).MultipleSaveMsg(ctx, req.(*MultipleSaveMsgReq))
@@ -308,7 +342,7 @@ func _Message_ChangeReadStatus_Handler(srv interface{}, ctx context.Context, dec
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/ChangeReadStatus",
+		FullMethod: Message_ChangeReadStatus_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).ChangeReadStatus(ctx, req.(*ChangeReadStatusReq))
@@ -326,7 +360,7 @@ func _Message_GetUnreadCount_Handler(srv interface{}, ctx context.Context, dec f
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/GetUnreadCount",
+		FullMethod: Message_GetUnreadCount_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).GetUnreadCount(ctx, req.(*GetUnreadCountRequest))
@@ -344,7 +378,7 @@ func _Message_FindUserMsg_Handler(srv interface{}, ctx context.Context, dec func
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/FindUserMsg",
+		FullMethod: Message_FindUserMsg_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).FindUserMsg(ctx, req.(*FindUserMsgReq))
@@ -362,7 +396,7 @@ func _Message_GetClassUnreadCount_Handler(srv interface{}, ctx context.Context,
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/GetClassUnreadCount",
+		FullMethod: Message_GetClassUnreadCount_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).GetClassUnreadCount(ctx, req.(*GetClassUnreadCountReq))
@@ -380,7 +414,7 @@ func _Message_GetLastMessage_Handler(srv interface{}, ctx context.Context, dec f
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/GetLastMessage",
+		FullMethod: Message_GetLastMessage_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).GetLastMessage(ctx, req.(*GetLastMessageReq))
@@ -398,7 +432,7 @@ func _Message_FindMessageDetail_Handler(srv interface{}, ctx context.Context, de
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/FindMessageDetail",
+		FullMethod: Message_FindMessageDetail_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).FindMessageDetail(ctx, req.(*MessageDetailReq))
@@ -416,7 +450,7 @@ func _Message_GetUnreadClassCount_Handler(srv interface{}, ctx context.Context,
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/GetUnreadClassCount",
+		FullMethod: Message_GetUnreadClassCount_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).GetUnreadClassCount(ctx, req.(*GetUnreadClassCountReq))
@@ -434,7 +468,7 @@ func _Message_GetMsgType_Handler(srv interface{}, ctx context.Context, dec func(
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/GetMsgType",
+		FullMethod: Message_GetMsgType_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).GetMsgType(ctx, req.(*GetMsgTypeReq))
@@ -452,7 +486,7 @@ func _Message_FindUserBuoyMsg_Handler(srv interface{}, ctx context.Context, dec
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/FindUserBuoyMsg",
+		FullMethod: Message_FindUserBuoyMsg_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).FindUserBuoyMsg(ctx, req.(*FindUserBuoyMsgReq))
@@ -470,7 +504,7 @@ func _Message_ClearUnreadMsg_Handler(srv interface{}, ctx context.Context, dec f
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/ClearUnreadMsg",
+		FullMethod: Message_ClearUnreadMsg_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).ClearUnreadMsg(ctx, req.(*ClearUnreadMsgReq))
@@ -488,7 +522,7 @@ func _Message_UserMsgList_Handler(srv interface{}, ctx context.Context, dec func
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/UserMsgList",
+		FullMethod: Message_UserMsgList_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).UserMsgList(ctx, req.(*UserMsgListReq))
@@ -496,20 +530,38 @@ func _Message_UserMsgList_Handler(srv interface{}, ctx context.Context, dec func
 	return interceptor(ctx, in, info, handler)
 }
 
-func _Message_SendWxTmplMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(WxTmplMsg)
+func _Message_SendWxTmplJySchoolMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(JySchoolMsg)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
 	if interceptor == nil {
-		return srv.(MessageServer).SendWxTmplMsg(ctx, in)
+		return srv.(MessageServer).SendWxTmplJySchoolMsg(ctx, in)
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/SendWxTmplMsg",
+		FullMethod: Message_SendWxTmplJySchoolMsg_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(MessageServer).SendWxTmplMsg(ctx, req.(*WxTmplMsg))
+		return srv.(MessageServer).SendWxTmplJySchoolMsg(ctx, req.(*JySchoolMsg))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Message_SendWxTmplSystemDefaultMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SystemDefaultMsg)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MessageServer).SendWxTmplSystemDefaultMsg(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: Message_SendWxTmplSystemDefaultMsg_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MessageServer).SendWxTmplSystemDefaultMsg(ctx, req.(*SystemDefaultMsg))
 	}
 	return interceptor(ctx, in, info, handler)
 }
@@ -524,7 +576,7 @@ func _Message_UserUnreadMsgList_Handler(srv interface{}, ctx context.Context, de
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/message.Message/UserUnreadMsgList",
+		FullMethod: Message_UserUnreadMsgList_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(MessageServer).UserUnreadMsgList(ctx, req.(*UserUnreadMsgListReq))
@@ -588,8 +640,12 @@ var Message_ServiceDesc = grpc.ServiceDesc{
 			Handler:    _Message_UserMsgList_Handler,
 		},
 		{
-			MethodName: "SendWxTmplMsg",
-			Handler:    _Message_SendWxTmplMsg_Handler,
+			MethodName: "SendWxTmplJySchoolMsg",
+			Handler:    _Message_SendWxTmplJySchoolMsg_Handler,
+		},
+		{
+			MethodName: "SendWxTmplSystemDefaultMsg",
+			Handler:    _Message_SendWxTmplSystemDefaultMsg_Handler,
 		},
 		{
 			MethodName: "UserUnreadMsgList",

+ 30 - 0
util/sendMail.go

@@ -0,0 +1,30 @@
+package util
+
+import (
+	"app.yhyue.com/moapp/MessageCenter/entity"
+	"app.yhyue.com/moapp/jybase/mail"
+	"fmt"
+	"log"
+	"time"
+)
+
+func SendRetryMail(retry int, toMails, ccMails, subject, content string, auth []*mail.GmailAuth) bool {
+	allMail := toMails
+	if ccMails != "" {
+		allMail = fmt.Sprintf("%s|%s", toMails, ccMails)
+	}
+	for i := 1; i <= retry; i++ {
+		for _, v := range auth { //使用多个邮箱尝试发送
+			if mail.GSendMail_q("剑鱼标讯", allMail, "", "", subject, content, "", "", entity.GmailAuth[0]) {
+				return true
+			}
+			t := time.Duration(i) * 30 * time.Second
+			log.Println(allMail, fmt.Sprintf("第%d轮,使用%s发送邮件失败!%v后重试", i, v.User, t))
+			time.Sleep(t)
+		}
+		if i == retry {
+			log.Println(allMail, fmt.Sprintf("发送邮件失败"))
+		}
+	}
+	return false
+}