复制项目
This commit is contained in:
555
internal/api/statistics.go
Normal file
555
internal/api/statistics.go
Normal file
@@ -0,0 +1,555 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/apistruct"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/authverify"
|
||||
rediscache "git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/cache/redis"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/database"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/rpcli"
|
||||
"git.imall.cloud/openim/protocol/constant"
|
||||
"git.imall.cloud/openim/protocol/sdkws"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/openimsdk/tools/a2r"
|
||||
"github.com/openimsdk/tools/apiresp"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type StatisticsApi struct {
|
||||
rdb redis.UniversalClient
|
||||
msgDatabase database.Msg
|
||||
userClient *rpcli.UserClient
|
||||
groupClient *rpcli.GroupClient
|
||||
}
|
||||
|
||||
func NewStatisticsApi(rdb redis.UniversalClient, msgDatabase database.Msg, userClient *rpcli.UserClient, groupClient *rpcli.GroupClient) *StatisticsApi {
|
||||
return &StatisticsApi{
|
||||
rdb: rdb,
|
||||
msgDatabase: msgDatabase,
|
||||
userClient: userClient,
|
||||
groupClient: groupClient,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
trendIntervalMinutes15 = 15
|
||||
trendIntervalMinutes30 = 30
|
||||
trendIntervalMinutes60 = 60
|
||||
trendChatTypeSingle = 1
|
||||
trendChatTypeGroup = 2
|
||||
defaultTrendDuration = 24 * time.Hour
|
||||
)
|
||||
|
||||
// refreshOnlineUserCountAndHistory 刷新在线人数并写入历史采样
|
||||
func refreshOnlineUserCountAndHistory(ctx context.Context, rdb redis.UniversalClient) {
|
||||
count, err := rediscache.RefreshOnlineUserCount(ctx, rdb)
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "refresh online user count failed", err)
|
||||
return
|
||||
}
|
||||
if err := rediscache.AppendOnlineUserCountHistory(ctx, rdb, time.Now().UnixMilli(), count); err != nil {
|
||||
log.ZWarn(ctx, "append online user count history failed", err)
|
||||
}
|
||||
}
|
||||
|
||||
// startOnlineCountRefresher 定时刷新在线人数缓存
|
||||
func startOnlineCountRefresher(ctx context.Context, cfg *Config, rdb redis.UniversalClient) {
|
||||
if cfg == nil || rdb == nil {
|
||||
return
|
||||
}
|
||||
refreshCfg := cfg.API.OnlineCountRefresh
|
||||
if !refreshCfg.Enable || refreshCfg.Interval <= 0 {
|
||||
return
|
||||
}
|
||||
log.ZInfo(ctx, "online user count refresh enabled", "interval", refreshCfg.Interval)
|
||||
go func() {
|
||||
refreshOnlineUserCountAndHistory(ctx, rdb)
|
||||
ticker := time.NewTicker(refreshCfg.Interval)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
refreshOnlineUserCountAndHistory(ctx, rdb)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// OnlineUserCount 在线人数统计接口
|
||||
func (s *StatisticsApi) OnlineUserCount(c *gin.Context) {
|
||||
if err := authverify.CheckAdmin(c); err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
if s.rdb == nil {
|
||||
apiresp.GinError(c, errs.ErrInternalServer.WrapMsg("redis client is nil"))
|
||||
return
|
||||
}
|
||||
count, err := rediscache.GetOnlineUserCount(c, s.rdb)
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
count, err = rediscache.RefreshOnlineUserCount(c, s.rdb)
|
||||
if err == nil {
|
||||
if appendErr := rediscache.AppendOnlineUserCountHistory(c, s.rdb, time.Now().UnixMilli(), count); appendErr != nil {
|
||||
log.ZWarn(c, "append online user count history failed", appendErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
apiresp.GinSuccess(c, &apistruct.OnlineUserCountResp{OnlineCount: count})
|
||||
}
|
||||
|
||||
// OnlineUserCountTrend 在线人数走势统计接口
|
||||
func (s *StatisticsApi) OnlineUserCountTrend(c *gin.Context) {
|
||||
if err := authverify.CheckAdmin(c); err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
req, err := a2r.ParseRequest[apistruct.OnlineUserCountTrendReq](c)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
if s.rdb == nil {
|
||||
apiresp.GinError(c, errs.ErrInternalServer.WrapMsg("redis client is nil"))
|
||||
return
|
||||
}
|
||||
intervalMillis, err := parseTrendIntervalMillis(req.IntervalMinutes)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
startTime, endTime, err := normalizeTrendTimeRange(req.StartTime, req.EndTime)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
bucketStart, bucketEnd := alignTrendRange(startTime, endTime, intervalMillis)
|
||||
// 使用对齐后的时间范围获取历史数据,确保数据范围与构建数据点的范围一致
|
||||
samples, err := rediscache.GetOnlineUserCountHistory(c, s.rdb, bucketStart, bucketEnd)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
// 将当前在线人数作为最新采样,确保最后一个时间段展示该段内的最大在线人数
|
||||
now := time.Now().UnixMilli()
|
||||
currentBucket := now - (now % intervalMillis)
|
||||
if now < 0 && now%intervalMillis != 0 {
|
||||
currentBucket = now - ((now % intervalMillis) + intervalMillis)
|
||||
}
|
||||
if currentBucket >= bucketStart && currentBucket <= bucketEnd {
|
||||
if currentCount, err := rediscache.GetOnlineUserCount(c, s.rdb); err == nil {
|
||||
samples = append(samples, rediscache.OnlineUserCountSample{
|
||||
Timestamp: now,
|
||||
Count: currentCount,
|
||||
})
|
||||
}
|
||||
}
|
||||
points := buildOnlineUserCountTrendPoints(samples, bucketStart, bucketEnd, intervalMillis)
|
||||
apiresp.GinSuccess(c, &apistruct.OnlineUserCountTrendResp{
|
||||
IntervalMinutes: req.IntervalMinutes,
|
||||
Points: points,
|
||||
})
|
||||
}
|
||||
|
||||
// UserSendMsgCount 用户发送消息总数统计
|
||||
func (s *StatisticsApi) UserSendMsgCount(c *gin.Context) {
|
||||
if err := authverify.CheckAdmin(c); err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
_, err := a2r.ParseRequest[apistruct.UserSendMsgCountReq](c)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
if s.msgDatabase == nil {
|
||||
apiresp.GinError(c, errs.ErrInternalServer.WrapMsg("msg database is nil"))
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
endTime := now.UnixMilli()
|
||||
start24h := now.Add(-24 * time.Hour).UnixMilli()
|
||||
start7d := now.Add(-7 * 24 * time.Hour).UnixMilli()
|
||||
start30d := now.Add(-30 * 24 * time.Hour).UnixMilli()
|
||||
|
||||
count24h, err := s.msgDatabase.CountUserSendMessages(c, "", start24h, endTime, "")
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
count7d, err := s.msgDatabase.CountUserSendMessages(c, "", start7d, endTime, "")
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
count30d, err := s.msgDatabase.CountUserSendMessages(c, "", start30d, endTime, "")
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
apiresp.GinSuccess(c, &apistruct.UserSendMsgCountResp{
|
||||
Count24h: count24h,
|
||||
Count7d: count7d,
|
||||
Count30d: count30d,
|
||||
})
|
||||
}
|
||||
|
||||
// UserSendMsgCountTrend 用户发送消息走势统计
|
||||
func (s *StatisticsApi) UserSendMsgCountTrend(c *gin.Context) {
|
||||
if err := authverify.CheckAdmin(c); err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
req, err := a2r.ParseRequest[apistruct.UserSendMsgCountTrendReq](c)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
if s.msgDatabase == nil {
|
||||
apiresp.GinError(c, errs.ErrInternalServer.WrapMsg("msg database is nil"))
|
||||
return
|
||||
}
|
||||
intervalMillis, err := parseTrendIntervalMillis(req.IntervalMinutes)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
startTime, endTime, err := normalizeTrendTimeRange(req.StartTime, req.EndTime)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
sessionTypes, err := mapTrendChatType(req.ChatType)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
bucketStart, bucketEnd := alignTrendRange(startTime, endTime, intervalMillis)
|
||||
countMap, err := s.msgDatabase.CountUserSendMessagesTrend(c, req.UserID, sessionTypes, startTime, endTime, intervalMillis)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
points := buildUserSendMsgCountTrendPoints(countMap, bucketStart, bucketEnd, intervalMillis)
|
||||
apiresp.GinSuccess(c, &apistruct.UserSendMsgCountTrendResp{
|
||||
UserID: req.UserID,
|
||||
ChatType: req.ChatType,
|
||||
IntervalMinutes: req.IntervalMinutes,
|
||||
Points: points,
|
||||
})
|
||||
}
|
||||
|
||||
// UserSendMsgQuery 用户发送消息查询
|
||||
func (s *StatisticsApi) UserSendMsgQuery(c *gin.Context) {
|
||||
if err := authverify.CheckAdmin(c); err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
req, err := a2r.ParseRequest[apistruct.UserSendMsgQueryReq](c)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
if req.StartTime > 0 && req.EndTime > 0 && req.EndTime <= req.StartTime {
|
||||
apiresp.GinError(c, errs.ErrArgs.WrapMsg("invalid time range"))
|
||||
return
|
||||
}
|
||||
if s.msgDatabase == nil {
|
||||
apiresp.GinError(c, errs.ErrInternalServer.WrapMsg("msg database is nil"))
|
||||
return
|
||||
}
|
||||
pageNumber := req.PageNumber
|
||||
if pageNumber <= 0 {
|
||||
pageNumber = 1
|
||||
}
|
||||
showNumber := req.ShowNumber
|
||||
if showNumber <= 0 {
|
||||
showNumber = 50
|
||||
}
|
||||
const maxShowNumber int32 = 200
|
||||
if showNumber > maxShowNumber {
|
||||
showNumber = maxShowNumber
|
||||
}
|
||||
total, msgs, err := s.msgDatabase.SearchUserMessages(c, req.UserID, req.StartTime, req.EndTime, req.Content, pageNumber, showNumber)
|
||||
if err != nil {
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
sendIDs := make([]string, 0, len(msgs))
|
||||
recvIDs := make([]string, 0, len(msgs))
|
||||
groupIDs := make([]string, 0, len(msgs))
|
||||
for _, item := range msgs {
|
||||
if item == nil || item.Msg == nil {
|
||||
continue
|
||||
}
|
||||
msg := item.Msg
|
||||
if msg.SendID != "" {
|
||||
sendIDs = append(sendIDs, msg.SendID)
|
||||
}
|
||||
switch msg.SessionType {
|
||||
case constant.ReadGroupChatType, constant.WriteGroupChatType:
|
||||
if msg.GroupID != "" {
|
||||
groupIDs = append(groupIDs, msg.GroupID)
|
||||
}
|
||||
default:
|
||||
if msg.RecvID != "" {
|
||||
recvIDs = append(recvIDs, msg.RecvID)
|
||||
}
|
||||
}
|
||||
}
|
||||
sendIDs = datautil.Distinct(sendIDs)
|
||||
recvIDs = datautil.Distinct(recvIDs)
|
||||
groupIDs = datautil.Distinct(groupIDs)
|
||||
|
||||
sendMap, recvMap, groupMap := map[string]*sdkws.UserInfo{}, map[string]*sdkws.UserInfo{}, map[string]*sdkws.GroupInfo{}
|
||||
if s.userClient != nil {
|
||||
if len(sendIDs) > 0 {
|
||||
if users, err := s.userClient.GetUsersInfo(c, sendIDs); err == nil {
|
||||
sendMap = datautil.SliceToMap(users, (*sdkws.UserInfo).GetUserID)
|
||||
}
|
||||
}
|
||||
if len(recvIDs) > 0 {
|
||||
if users, err := s.userClient.GetUsersInfo(c, recvIDs); err == nil {
|
||||
recvMap = datautil.SliceToMap(users, (*sdkws.UserInfo).GetUserID)
|
||||
}
|
||||
}
|
||||
}
|
||||
if s.groupClient != nil && len(groupIDs) > 0 {
|
||||
if groups, err := s.groupClient.GetGroupsInfo(c, groupIDs); err == nil {
|
||||
groupMap = datautil.SliceToMap(groups, (*sdkws.GroupInfo).GetGroupID)
|
||||
}
|
||||
}
|
||||
|
||||
records := make([]*apistruct.UserSendMsgQueryRecord, 0, len(msgs))
|
||||
for _, item := range msgs {
|
||||
if item == nil || item.Msg == nil {
|
||||
continue
|
||||
}
|
||||
msg := item.Msg
|
||||
msgID := msg.ServerMsgID
|
||||
if msgID == "" {
|
||||
msgID = msg.ClientMsgID
|
||||
}
|
||||
senderName := msg.SenderNickname
|
||||
if senderName == "" {
|
||||
if u := sendMap[msg.SendID]; u != nil {
|
||||
senderName = u.Nickname
|
||||
} else {
|
||||
senderName = msg.SendID
|
||||
}
|
||||
}
|
||||
recvID := msg.RecvID
|
||||
recvName := ""
|
||||
if msg.SessionType == constant.ReadGroupChatType || msg.SessionType == constant.WriteGroupChatType {
|
||||
if msg.GroupID != "" {
|
||||
recvID = msg.GroupID
|
||||
}
|
||||
if g := groupMap[recvID]; g != nil {
|
||||
recvName = g.GroupName
|
||||
} else if recvID != "" {
|
||||
recvName = recvID
|
||||
}
|
||||
} else {
|
||||
if u := recvMap[msg.RecvID]; u != nil {
|
||||
recvName = u.Nickname
|
||||
} else if msg.RecvID != "" {
|
||||
recvName = msg.RecvID
|
||||
}
|
||||
}
|
||||
records = append(records, &apistruct.UserSendMsgQueryRecord{
|
||||
MsgID: msgID,
|
||||
SendID: msg.SendID,
|
||||
SenderName: senderName,
|
||||
RecvID: recvID,
|
||||
RecvName: recvName,
|
||||
ContentType: msg.ContentType,
|
||||
ContentTypeName: contentTypeName(msg.ContentType),
|
||||
SessionType: msg.SessionType,
|
||||
ChatTypeName: chatTypeName(msg.SessionType),
|
||||
Content: msg.Content,
|
||||
SendTime: msg.SendTime,
|
||||
})
|
||||
}
|
||||
apiresp.GinSuccess(c, &apistruct.UserSendMsgQueryResp{
|
||||
Count: total,
|
||||
PageNumber: pageNumber,
|
||||
ShowNumber: showNumber,
|
||||
Records: records,
|
||||
})
|
||||
}
|
||||
|
||||
// parseTrendIntervalMillis 解析走势统计间隔并转换为毫秒
|
||||
func parseTrendIntervalMillis(intervalMinutes int32) (int64, error) {
|
||||
switch intervalMinutes {
|
||||
case trendIntervalMinutes15, trendIntervalMinutes30, trendIntervalMinutes60:
|
||||
return int64(intervalMinutes) * int64(time.Minute/time.Millisecond), nil
|
||||
default:
|
||||
return 0, errs.ErrArgs.WrapMsg("invalid intervalMinutes")
|
||||
}
|
||||
}
|
||||
|
||||
// normalizeTrendTimeRange 标准化走势统计时间区间
|
||||
func normalizeTrendTimeRange(startTime int64, endTime int64) (int64, int64, error) {
|
||||
now := time.Now().UnixMilli()
|
||||
if endTime <= 0 {
|
||||
endTime = now
|
||||
}
|
||||
if startTime <= 0 {
|
||||
startTime = endTime - int64(defaultTrendDuration/time.Millisecond)
|
||||
}
|
||||
if startTime < 0 {
|
||||
startTime = 0
|
||||
}
|
||||
if endTime <= startTime {
|
||||
return 0, 0, errs.ErrArgs.WrapMsg("invalid time range")
|
||||
}
|
||||
return startTime, endTime, nil
|
||||
}
|
||||
|
||||
// alignTrendRange 对齐走势统计区间到间隔边界
|
||||
func alignTrendRange(startTime int64, endTime int64, intervalMillis int64) (int64, int64) {
|
||||
if intervalMillis <= 0 {
|
||||
return startTime, endTime
|
||||
}
|
||||
// 开始时间向下对齐到间隔边界
|
||||
bucketStart := startTime - (startTime % intervalMillis)
|
||||
if startTime < 0 {
|
||||
bucketStart = startTime - ((startTime % intervalMillis) + intervalMillis)
|
||||
}
|
||||
// 结束时间向下对齐到所在间隔的起始(只包含已发生的间隔)
|
||||
bucketEnd := endTime - (endTime % intervalMillis)
|
||||
if endTime < 0 && endTime%intervalMillis != 0 {
|
||||
bucketEnd = endTime - ((endTime % intervalMillis) + intervalMillis)
|
||||
}
|
||||
// 确保至少覆盖一个间隔
|
||||
if bucketEnd < bucketStart {
|
||||
bucketEnd = bucketStart
|
||||
}
|
||||
return bucketStart, bucketEnd
|
||||
}
|
||||
|
||||
// buildOnlineUserCountTrendPoints 构建在线人数走势数据点
|
||||
func buildOnlineUserCountTrendPoints(samples []rediscache.OnlineUserCountSample, startTime int64, endTime int64, intervalMillis int64) []*apistruct.OnlineUserCountTrendItem {
|
||||
points := make([]*apistruct.OnlineUserCountTrendItem, 0)
|
||||
if intervalMillis <= 0 || endTime <= startTime {
|
||||
return points
|
||||
}
|
||||
maxMap := make(map[int64]int64)
|
||||
for _, sample := range samples {
|
||||
// 将采样时间戳对齐到间隔边界
|
||||
bucket := sample.Timestamp - (sample.Timestamp % intervalMillis)
|
||||
// 处理负数时间戳的情况(虽然通常不会发生)
|
||||
if sample.Timestamp < 0 && sample.Timestamp%intervalMillis != 0 {
|
||||
bucket = sample.Timestamp - ((sample.Timestamp % intervalMillis) + intervalMillis)
|
||||
}
|
||||
if sample.Count > maxMap[bucket] {
|
||||
maxMap[bucket] = sample.Count
|
||||
}
|
||||
}
|
||||
// 计算需要生成的数据点数量
|
||||
// endTime是对齐后的最后一个bucket的起始时间,所以需要包含它
|
||||
estimated := int((endTime-startTime)/intervalMillis) + 1
|
||||
if estimated > 0 {
|
||||
points = make([]*apistruct.OnlineUserCountTrendItem, 0, estimated)
|
||||
}
|
||||
// 生成从startTime到endTime(包含endTime)的所有时间点
|
||||
// endTime已经是对齐后的最后一个bucket的起始时间
|
||||
for ts := startTime; ts <= endTime; ts += intervalMillis {
|
||||
maxVal := maxMap[ts]
|
||||
points = append(points, &apistruct.OnlineUserCountTrendItem{
|
||||
Timestamp: ts,
|
||||
OnlineCount: maxVal,
|
||||
})
|
||||
}
|
||||
return points
|
||||
}
|
||||
|
||||
// buildUserSendMsgCountTrendPoints 构建用户发送消息走势数据点
|
||||
func buildUserSendMsgCountTrendPoints(countMap map[int64]int64, startTime int64, endTime int64, intervalMillis int64) []*apistruct.UserSendMsgCountTrendItem {
|
||||
points := make([]*apistruct.UserSendMsgCountTrendItem, 0)
|
||||
if intervalMillis <= 0 || endTime <= startTime {
|
||||
return points
|
||||
}
|
||||
estimated := int((endTime - startTime) / intervalMillis)
|
||||
if estimated > 0 {
|
||||
points = make([]*apistruct.UserSendMsgCountTrendItem, 0, estimated)
|
||||
}
|
||||
for ts := startTime; ts < endTime; ts += intervalMillis {
|
||||
points = append(points, &apistruct.UserSendMsgCountTrendItem{
|
||||
Timestamp: ts,
|
||||
Count: countMap[ts],
|
||||
})
|
||||
}
|
||||
return points
|
||||
}
|
||||
|
||||
// mapTrendChatType 走势统计聊天类型转为 sessionType 列表
|
||||
func mapTrendChatType(chatType int32) ([]int32, error) {
|
||||
switch chatType {
|
||||
case trendChatTypeSingle:
|
||||
return []int32{constant.SingleChatType}, nil
|
||||
case trendChatTypeGroup:
|
||||
return []int32{constant.ReadGroupChatType, constant.WriteGroupChatType}, nil
|
||||
default:
|
||||
return nil, errs.ErrArgs.WrapMsg("invalid chatType")
|
||||
}
|
||||
}
|
||||
|
||||
// contentTypeName 消息类型名称转换
|
||||
func contentTypeName(contentType int32) string {
|
||||
switch contentType {
|
||||
case constant.Text:
|
||||
return "文本消息"
|
||||
case constant.Picture:
|
||||
return "图片消息"
|
||||
case constant.Voice:
|
||||
return "语音消息"
|
||||
case constant.Video:
|
||||
return "视频消息"
|
||||
case constant.File:
|
||||
return "文件消息"
|
||||
case constant.AtText:
|
||||
return "艾特消息"
|
||||
case constant.Merger:
|
||||
return "合并消息"
|
||||
case constant.Card:
|
||||
return "名片消息"
|
||||
case constant.Location:
|
||||
return "位置消息"
|
||||
case constant.Custom:
|
||||
return "自定义消息"
|
||||
case constant.Revoke:
|
||||
return "撤回消息"
|
||||
case constant.MarkdownText:
|
||||
return "Markdown消息"
|
||||
default:
|
||||
return "未知消息"
|
||||
}
|
||||
}
|
||||
|
||||
// chatTypeName 聊天类型名称转换
|
||||
func chatTypeName(sessionType int32) string {
|
||||
switch sessionType {
|
||||
case constant.SingleChatType:
|
||||
return "单聊"
|
||||
case constant.ReadGroupChatType, constant.WriteGroupChatType:
|
||||
return "群聊"
|
||||
case constant.NotificationChatType:
|
||||
return "通知"
|
||||
default:
|
||||
return "未知"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user