瀏覽代碼

Merge branch 'feature/v1.2.7' into dev/v1.2.7_rjj

# Conflicts:
#	rpc/internal/server/messageserver.go
#	rpc/messageclient/message.go
#	rpc/type/message/message.pb.go
#	rpc/type/message/message_grpc.pb.go
renjiaojiao 2 年之前
父節點
當前提交
12cf154de3

+ 2 - 0
api/internal/logic/messagelistlogic.go

@@ -38,6 +38,8 @@ func (l *MessageListLogic) MessageList(req *types.MessageListReq) (resp *types.M
 		IsColumn:       req.IsColumn,
 		IsColumnNewMsg: req.IsColumnNewMsg,
 		IsMsgList:      req.IsMsgList,
+		PositionId:     req.PositionId,
+		NewUserId:      req.NewUserId,
 	})
 	if err != nil {
 		return nil, err

+ 5 - 3
api/internal/types/types.go

@@ -102,9 +102,11 @@ type MessageListReq struct {
 	Size           int64  `json:"size,optional"`
 	MsgType        int64  `json:"msgType,optional"`
 	IsRead         int64  `json:"isRead,optional"`
-	IsColumn       bool   `json:"isColumn"`       //是否需要获取栏目
-	IsColumnNewMsg bool   `json:"isColumnNewMsg"` //是否需各栏目获取最新消息
-	IsMsgList      bool   `json:"isMsgList"`      //是否需要列表信息
+	NewUserId      int64  `header:"newUserId,optional"`  //私信相关
+	PositionId     int64  `header:"positionId,optional"` //私信相关
+	IsColumn       bool   `json:"isColumn"`              //是否需要获取栏目
+	IsColumnNewMsg bool   `json:"isColumnNewMsg"`        //是否需各栏目获取最新消息
+	IsMsgList      bool   `json:"isMsgList"`             //是否需要列表信息
 }
 
 type MessageListResp struct {

+ 5 - 3
api/message.api

@@ -104,9 +104,11 @@ type MessageListReq {
 	Size           int64  `json:"size,optional"`
 	MsgType        int64  `json:"msgType,optional"`
 	IsRead         int64  `json:"isRead,optional"`
-	IsColumn       bool   `json:"isColumn"`       //是否需要获取栏目
-	IsColumnNewMsg bool   `json:"isColumnNewMsg"` //是否需各栏目获取最新消息
-	IsMsgList      bool   `json:"isMsgList"`      //是否需要列表信息
+	NewUserId      int64  `header:"newUserId,optional"`  //私信相关
+	PositionId     int64  `header:"positionId,optional"` //私信相关
+	IsColumn       bool   `json:"isColumn"`              //是否需要获取栏目
+	IsColumnNewMsg bool   `json:"isColumnNewMsg"`        //是否需各栏目获取最新消息
+	IsMsgList      bool   `json:"isMsgList"`             //是否需要列表信息
 }
 
 type MessageListResp {

+ 3 - 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"
@@ -13,9 +14,10 @@ import (
 var Engine *xorm.Engine
 var EtcdCli *clientv3.Client
 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 //  定义保存消息并发
 

+ 24 - 10
rpc/etc/message.yaml

@@ -23,10 +23,14 @@ DataSource:
     PassWord: =PDT49#80Z!RVv52_z
     MaxOpenConns: 50
     MaxIdleConns: 50
-Redis:
-  Host: 192.168.3.206
-  Addr: 192.168.3.206:1712
-  Modules: msgCount
+BaseSource:
+  DbName: base_service
+  Address: 192.168.3.217:4000
+  UserName: root
+  PassWord: =PDT49#80Z!RVv52_z
+  MaxOpenConns: 50
+  MaxIdleConns: 50
+RedisAddr: "msgCount=192.168.3.206:1712"
 FileSystemConf:
   Etcd:
     Hosts:
@@ -35,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" ] #告警邮箱抄送地址
 

+ 1 - 1
rpc/internal/common/getBuoyMsg.go

@@ -85,7 +85,7 @@ func ClearUnreadMsg(in *message.ClearUnreadMsgReq) error {
 			"my_position_id": in.PositionId,
 			"ent_id":         in.EntId,
 		}
-		if !entity.Mysql.Update("socialize_summary", sQuery, map[string]interface{}{"unread": 0}) {
+		if !entity.BaseMysql.Update("socialize_summary", sQuery, map[string]interface{}{"unread": 0}) {
 			log.Println("更新私信未读数失败")
 		}
 	}

+ 45 - 15
rpc/internal/common/sendMsg.go

@@ -96,7 +96,6 @@ func FindUserMsg(this message.FindUserMsgReq, isClean bool) message.FindUserMsgR
 	return data
 }
 
-// this.IsPc 是否pc端请求 this.MobileHome是否移动消息列表页
 func UserMsgList(this *message.UserMsgListReq) *message.UserMsgList {
 	var (
 		unread, count int64
@@ -153,12 +152,14 @@ func UserMsgList(this *message.UserMsgListReq) *message.UserMsgList {
 
 	//消息栏目下的最新消息
 	var columnData []*message.AllSortData
-	if this.IsColumn {
-		var msgTypes []string
-		columnUnread := make(map[string]int64)
-		for _, v := range entity.MessageColumn {
+	var msgTypes []string
+	for _, v := range entity.MessageColumn {
+		if common.IntAll(v["msg_type"]) > 0 {
 			msgTypes = append(msgTypes, fmt.Sprintf(`"%s"`, common.InterfaceToStr(v["msg_type"])))
 		}
+	}
+	if this.IsColumn {
+		columnUnread := make(map[string]int64)
 		query := entity.Mysql.SelectBySql(fmt.Sprintf("SELECT msg_type,COUNT(CASE WHEN isRead=0 THEN 1 END) as count  FROM message where receive_userid=? and isdel=1 and appid=? GROUP BY msg_type  ORDER BY FIELD(`msg_type`,%s)", strings.Join(msgTypes, ",")), this.UserId, this.Appid)
 		if query != nil && len(*query) > 0 {
 			for _, v := range *query {
@@ -168,20 +169,23 @@ func UserMsgList(this *message.UserMsgListReq) *message.UserMsgList {
 		for _, v := range entity.MessageColumn {
 			var column message.AllSortData
 			column.Name = common.InterfaceToStr(v["name"])
-			column.Img = common.InterfaceToStr(v["img"])
+			column.Img = fmt.Sprintf("/swordfish/msgCenter/%s.png", common.InterfaceToStr(v["img"]))
 			column.MsgType = common.Int64All(v["msg_type"])
-			msgType := common.InterfaceToStr(v["msg_type"])
-			//消息未读数
-			column.UnreadMessages = columnUnread[msgType]
+			if column.Name == "私信" {
+				column.UnreadMessages = unreadMsg(this)
+			} else {
+				//消息未读数
+				msgType := common.InterfaceToStr(v["msg_type"])
+				column.UnreadMessages = columnUnread[msgType]
+				column.Data = sData[msgType]
+			}
 			unread += column.UnreadMessages
-			column.Data = sData[msgType]
 			columnData = append(columnData, &column)
 		}
 	}
-
+	data.SortData = columnData
+	count = entity.Mysql.Count("message", cquery)
 	if this.IsMsgList {
-		data.SortData = columnData
-		count = entity.Mysql.Count("message", cquery)
 		if count > 0 {
 			res := entity.Mysql.Find("message", cquery, "", "createtime desc", (int(this.OffSet)-1)*int(this.PageSize), int(this.PageSize))
 			if res != nil && len(*res) > 0 {
@@ -209,13 +213,39 @@ func UserMsgList(this *message.UserMsgListReq) *message.UserMsgList {
 		}
 	}
 	data.Count = count
-	if !this.IsColumn && this.Read == 0 {
-		unread = count
+	if !this.IsColumn {
+		if this.Read == 0 {
+			unread = count
+			if !this.IsMsgList && !this.IsColumnNewMsg {
+				unread += unreadMsg(this) //仅用于移动端获取所有未读数
+			}
+		}
 	}
 	data.Unread = unread
 	return data
 }
 
+func unreadMsg(this *message.UserMsgListReq) int64 {
+	if this.PositionId <= 0 {
+		return 0
+	}
+	querySql := fmt.Sprintf("SELECT  b.*,(SELECT SUM( a.unread) FROM  %s a "+
+		"LEFT JOIN %s b ON a.message_id = b.id  "+
+		"WHERE  a.unread > 0 "+
+		"AND ( a.my_position_id = %d OR a.user_id = %d )) AS unread "+
+		"FROM %s a  "+
+		"LEFT JOIN %s b ON a.message_id = b.id  "+
+		"WHERE a.unread > 0  "+
+		"AND ( a.my_position_id = %d OR a.user_id = %d ) "+
+		"ORDER BY a.TIMESTAMP DESC LIMIT 0,1", "socialize_summary", "socialize_message", this.PositionId, this.NewUserId,
+		"socialize_summary", "socialize_message", this.PositionId, this.NewUserId)
+	log.Println("查询sql", querySql)
+	msgUnread := entity.BaseMysql.SelectBySql(querySql)
+	if msgUnread != nil && len(*msgUnread) > 0 {
+		return common.Int64All((*msgUnread)[0]["unread"])
+	}
+	return 0
+}
 func UserUnreadMsgList(this *message.UserUnreadMsgListReq) (int64, []*message.Messages) {
 	var count int64
 	var data []*message.Messages

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

@@ -3,33 +3,127 @@ 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, []map[string]interface{}) {
+	var data []map[string]interface{}
+	rData := entity.Mysql.SelectBySql("SELECT * FROM message_column ORDER BY sequence ASC")
+	switchName := map[string]string{}
+	if rData != nil && len(*rData) > 0 {
+		data = *rData
+		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
+	}, data
+}
+
+var AllMsgType func() map[string]string
+
+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 +131,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)
 }

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

@@ -7,18 +7,19 @@ import (
 type Config struct {
 	zrpc.RpcServerConf
 	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 {
@@ -46,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
+}

+ 1 - 1
rpc/internal/logic/usermsglistlogic.go

@@ -32,7 +32,7 @@ func (l *UserMsgListLogic) UserMsgList(in *message.UserMsgListReq) (*message.Use
 	data := new(message.UserMsgListRes)
 	res1 := service.UserMsgList(in)    //具体信息
 	res2 := service.MessageGetLast(in) //最新信息
-	if res2 != nil || res1.Data != nil {
+	if res2 != nil || res1 != nil {
 		var finalData []*message.Messages
 		if res1.Data != nil {
 			for _, v := range res1.Data {

+ 19 - 1
rpc/internal/server/messageserver.go

@@ -46,13 +46,31 @@ func (s *MessageServer) FindUserMsg(ctx context.Context, in *message.FindUserMsg
 	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)
+}
+
 // 查看详细详情
 func (s *MessageServer) FindMessageDetail(ctx context.Context, in *message.MessageDetailReq) (*message.MessageDetailResp, error) {
 	l := logic.NewFindMessageDetailLogic(ctx, s.svcCtx)
 	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)

+ 23 - 9
rpc/message.go

@@ -5,10 +5,12 @@ package main
 
 import (
 	"app.yhyue.com/moapp/MessageCenter/entity"
+	"app.yhyue.com/moapp/MessageCenter/rpc/internal/common"
 	"app.yhyue.com/moapp/MessageCenter/rpc/internal/config"
 	"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"
@@ -55,17 +57,20 @@ func init() {
 		MaxIdleConns: config.ConfigJson.DataSource.MaxIdleConns,
 	}
 	entity.Mysql.Init()
-	data := entity.Mysql.Find("message_column", map[string]interface{}{"equity": "private_msg"}, "", "sequence", -1, -1)
-	if data != nil && len(*data) > 0 {
-		entity.MessageColumn = *data
+	common.AllMsgType, entity.MessageColumn = common.MessageType()
+	//初始化basemysql
+	entity.BaseMysql = &mysql.Mysql{
+		Address:      config.ConfigJson.BaseSource.Address,
+		UserName:     config.ConfigJson.BaseSource.UserName,
+		PassWord:     config.ConfigJson.BaseSource.PassWord,
+		DBName:       config.ConfigJson.BaseSource.DbName,
+		MaxOpenConns: config.ConfigJson.BaseSource.MaxOpenConns,
+		MaxIdleConns: config.ConfigJson.BaseSource.MaxIdleConns,
 	}
+	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 {
@@ -78,6 +83,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)
 	//初始化日志信息

+ 34 - 5
rpc/message.proto

@@ -153,9 +153,11 @@ message UserMsgListReq {
     int64 msgType = 6; //是否区分类型
     int64 read = 7; // 是否区分已读未读 -1 不区分已读未读  0 未读 1 已读
     int64 SortSize = 8; //分类 每类数
-    bool IsColumn   =9;    //是否需要获取栏目
-    bool IsColumnNewMsg = 10; //是否需各栏目获取最新消息
-    bool IsMsgList =11;  //是否需要列表信息
+    bool isColumn   =9;    //是否需要获取栏目
+    bool isColumnNewMsg = 10; //是否需各栏目获取最新消息
+    bool isMsgList =11;  //是否需要列表信息
+    int64 NewUserId   =12;//私信相关
+    int64 PositionId  =13;//私信相关
 
 }
 
@@ -216,6 +218,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 {
     //批量保存消息
@@ -238,8 +265,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);
 }

+ 31 - 3
rpc/messageclient/message.go

@@ -21,14 +21,18 @@ type (
 	FindUserBuoyMsgRes     = message.FindUserBuoyMsgRes
 	FindUserMsgReq         = message.FindUserMsgReq
 	FindUserMsgRes         = message.FindUserMsgRes
+	GetClassUnreadCountReq = message.GetClassUnreadCountReq
+	GetLastMessageReq      = message.GetLastMessageReq
+	GetLastMessageRes      = message.GetLastMessageRes
 	GetMsgTypeReq          = message.GetMsgTypeReq
 	GetMsgTypeRes          = message.GetMsgTypeRes
+	GetUnreadClassCountReq = message.GetUnreadClassCountReq
+	GetUnreadClassCountRes = message.GetUnreadClassCountRes
 	GetUnreadCountRequest  = message.GetUnreadCountRequest
 	GetUnreadCountResponse = message.GetUnreadCountResponse
 	MessageDetailReq       = message.MessageDetailReq
 	MessageDetailResp      = message.MessageDetailResp
 	Messages               = message.Messages
-	MsgTypes               = message.MsgTypes
 	MultipleSaveMsgReq     = message.MultipleSaveMsgReq
 	MultipleSaveMsgResp    = message.MultipleSaveMsgResp
 	ResCount               = message.ResCount
@@ -51,9 +55,15 @@ type (
 		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)
@@ -102,13 +112,31 @@ func (m *defaultMessage) FindUserMsg(ctx context.Context, in *FindUserMsgReq, op
 	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...)
+}
+
 // 查看详细详情
 func (m *defaultMessage) FindMessageDetail(ctx context.Context, in *MessageDetailReq, opts ...grpc.CallOption) (*MessageDetailResp, error) {
 	client := message.NewMessageClient(m.cli.Conn())
 	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...)

文件差異過大導致無法顯示
+ 618 - 324
rpc/type/message/message.pb.go


+ 116 - 2
rpc/type/message/message_grpc.pb.go

@@ -30,9 +30,15 @@ type MessageClient interface {
 	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)
@@ -90,6 +96,24 @@ func (c *messageClient) FindUserMsg(ctx context.Context, in *FindUserMsgReq, opt
 	return out, nil
 }
 
+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...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+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...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 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...)
@@ -99,6 +123,15 @@ func (c *messageClient) FindMessageDetail(ctx context.Context, in *MessageDetail
 	return out, nil
 }
 
+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...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 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...)
@@ -165,9 +198,15 @@ type MessageServer interface {
 	GetUnreadCount(context.Context, *GetUnreadCountRequest) (*GetUnreadCountResponse, error)
 	//  查询指定用户的历史消息记录
 	FindUserMsg(context.Context, *FindUserMsgReq) (*FindUserMsgRes, error)
+	//  查询指定用户指定分类的未读消息合计
+	GetClassUnreadCount(context.Context, *GetClassUnreadCountReq) (*GetUnreadCountResponse, error)
+	//  获取指定用户指定分类的最新一条消息
+	GetLastMessage(context.Context, *GetLastMessageReq) (*GetLastMessageRes, error)
 	//查看详细详情
 	FindMessageDetail(context.Context, *MessageDetailReq) (*MessageDetailResp, error)
-	//  消息的分类
+	//  获取指定用户的分类及未读消息数量
+	GetUnreadClassCount(context.Context, *GetUnreadClassCountReq) (*GetUnreadClassCountRes, error)
+	//  获取指定用户收到消息的分类
 	GetMsgType(context.Context, *GetMsgTypeReq) (*GetMsgTypeRes, error)
 	//  查询指定用户的浮标消息
 	FindUserBuoyMsg(context.Context, *FindUserBuoyMsgReq) (*FindUserBuoyMsgRes, error)
@@ -198,9 +237,18 @@ func (UnimplementedMessageServer) GetUnreadCount(context.Context, *GetUnreadCoun
 func (UnimplementedMessageServer) FindUserMsg(context.Context, *FindUserMsgReq) (*FindUserMsgRes, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method FindUserMsg not implemented")
 }
+func (UnimplementedMessageServer) GetClassUnreadCount(context.Context, *GetClassUnreadCountReq) (*GetUnreadCountResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetClassUnreadCount not implemented")
+}
+func (UnimplementedMessageServer) GetLastMessage(context.Context, *GetLastMessageReq) (*GetLastMessageRes, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetLastMessage not implemented")
+}
 func (UnimplementedMessageServer) FindMessageDetail(context.Context, *MessageDetailReq) (*MessageDetailResp, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method FindMessageDetail not implemented")
 }
+func (UnimplementedMessageServer) GetUnreadClassCount(context.Context, *GetUnreadClassCountReq) (*GetUnreadClassCountRes, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetUnreadClassCount not implemented")
+}
 func (UnimplementedMessageServer) GetMsgType(context.Context, *GetMsgTypeReq) (*GetMsgTypeRes, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method GetMsgType not implemented")
 }
@@ -304,6 +352,42 @@ func _Message_FindUserMsg_Handler(srv interface{}, ctx context.Context, dec func
 	return interceptor(ctx, in, info, handler)
 }
 
+func _Message_GetClassUnreadCount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetClassUnreadCountReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MessageServer).GetClassUnreadCount(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/message.Message/GetClassUnreadCount",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MessageServer).GetClassUnreadCount(ctx, req.(*GetClassUnreadCountReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Message_GetLastMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetLastMessageReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MessageServer).GetLastMessage(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/message.Message/GetLastMessage",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MessageServer).GetLastMessage(ctx, req.(*GetLastMessageReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _Message_FindMessageDetail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(MessageDetailReq)
 	if err := dec(in); err != nil {
@@ -322,6 +406,24 @@ func _Message_FindMessageDetail_Handler(srv interface{}, ctx context.Context, de
 	return interceptor(ctx, in, info, handler)
 }
 
+func _Message_GetUnreadClassCount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetUnreadClassCountReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MessageServer).GetUnreadClassCount(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/message.Message/GetUnreadClassCount",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MessageServer).GetUnreadClassCount(ctx, req.(*GetUnreadClassCountReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _Message_GetMsgType_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(GetMsgTypeReq)
 	if err := dec(in); err != nil {
@@ -453,10 +555,22 @@ var Message_ServiceDesc = grpc.ServiceDesc{
 			MethodName: "FindUserMsg",
 			Handler:    _Message_FindUserMsg_Handler,
 		},
+		{
+			MethodName: "GetClassUnreadCount",
+			Handler:    _Message_GetClassUnreadCount_Handler,
+		},
+		{
+			MethodName: "GetLastMessage",
+			Handler:    _Message_GetLastMessage_Handler,
+		},
 		{
 			MethodName: "FindMessageDetail",
 			Handler:    _Message_FindMessageDetail_Handler,
 		},
+		{
+			MethodName: "GetUnreadClassCount",
+			Handler:    _Message_GetUnreadClassCount_Handler,
+		},
 		{
 			MethodName: "GetMsgType",
 			Handler:    _Message_GetMsgType_Handler,

+ 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
+}

部分文件因文件數量過多而無法顯示