353 lines
8.7 KiB
Go
353 lines
8.7 KiB
Go
/**
|
||
* package service
|
||
* 作用:聚合搜索服务
|
||
*/
|
||
package service
|
||
|
||
import (
|
||
"strings"
|
||
"xk-websocket-v2/internal/model"
|
||
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// SearchService 搜索服务结构体
|
||
type SearchService struct {
|
||
DB *gorm.DB
|
||
}
|
||
|
||
// SearchSvc 全局单例
|
||
var SearchSvc *SearchService
|
||
|
||
/**
|
||
* InitSearchService
|
||
* 功能:初始化搜索服务
|
||
*/
|
||
func InitSearchService(db *gorm.DB) {
|
||
SearchSvc = &SearchService{DB: db}
|
||
}
|
||
|
||
// SearchResult 搜索结果结构
|
||
type SearchResult struct {
|
||
Contacts []ContactSearchResult `json:"contacts"`
|
||
Groups []GroupSearchResult `json:"groups"`
|
||
Messages []MessageSearchResult `json:"messages"`
|
||
}
|
||
|
||
// ContactSearchResult 联系人搜索结果
|
||
type ContactSearchResult struct {
|
||
User *model.User `json:"user"`
|
||
RemarkName string `json:"remark_name"`
|
||
RoomID string `json:"room_id"`
|
||
}
|
||
|
||
// GroupSearchResult 群聊搜索结果
|
||
type GroupSearchResult struct {
|
||
RoomID string `json:"room_id"`
|
||
RoomName string `json:"room_name"`
|
||
RoomAvatar string `json:"room_avatar"`
|
||
OwnerID string `json:"owner_id"`
|
||
MemberCount int `json:"member_count"`
|
||
}
|
||
|
||
// MessageSearchResult 消息搜索结果
|
||
type MessageSearchResult struct {
|
||
ID uint `json:"id"`
|
||
RoomID string `json:"room_id"`
|
||
RoomName string `json:"room_name"`
|
||
Content string `json:"content"`
|
||
MessageType int `json:"message_type"`
|
||
CreatedAt string `json:"created_at"`
|
||
Sender *model.User `json:"sender"`
|
||
IsGroupChat bool `json:"is_group_chat"`
|
||
MatchContent string `json:"match_content"`
|
||
}
|
||
|
||
/**
|
||
* GlobalSearch
|
||
* 功能:全局聚合搜索(联系人、群聊、聊天记录)
|
||
* @param userID 当前用户ID
|
||
* @param keyword 搜索关键词
|
||
* @param searchType 搜索类型:all, contacts, groups, messages
|
||
* @param limit 每类结果的最大数量
|
||
*/
|
||
func (s *SearchService) GlobalSearch(userID, keyword, searchType string, limit int) (*SearchResult, error) {
|
||
result := &SearchResult{
|
||
Contacts: []ContactSearchResult{},
|
||
Groups: []GroupSearchResult{},
|
||
Messages: []MessageSearchResult{},
|
||
}
|
||
|
||
if keyword == "" {
|
||
return result, nil
|
||
}
|
||
|
||
keyword = strings.TrimSpace(keyword)
|
||
likeKeyword := "%" + keyword + "%"
|
||
|
||
// 搜索联系人
|
||
if searchType == "all" || searchType == "contacts" {
|
||
contacts, err := s.searchContacts(userID, likeKeyword, limit)
|
||
if err == nil {
|
||
result.Contacts = contacts
|
||
}
|
||
}
|
||
|
||
// 搜索群聊
|
||
if searchType == "all" || searchType == "groups" {
|
||
groups, err := s.searchGroups(userID, likeKeyword, limit)
|
||
if err == nil {
|
||
result.Groups = groups
|
||
}
|
||
}
|
||
|
||
// 搜索聊天记录
|
||
if searchType == "all" || searchType == "messages" {
|
||
messages, err := s.searchMessages(userID, likeKeyword, limit)
|
||
if err == nil {
|
||
result.Messages = messages
|
||
}
|
||
}
|
||
|
||
return result, nil
|
||
}
|
||
|
||
/**
|
||
* searchContacts
|
||
* 功能:搜索联系人(好友)
|
||
* 搜索字段:用户名、备注名、邮箱、手机号
|
||
*/
|
||
func (s *SearchService) searchContacts(userID, likeKeyword string, limit int) ([]ContactSearchResult, error) {
|
||
var contacts []model.UserContact
|
||
var results []ContactSearchResult
|
||
|
||
// 查询当前用户的好友
|
||
err := s.DB.Where("user_id = ?", userID).Find(&contacts).Error
|
||
if err != nil {
|
||
return results, err
|
||
}
|
||
|
||
// 获取所有好友的用户ID
|
||
contactIDs := make([]string, 0, len(contacts))
|
||
contactMap := make(map[string]model.UserContact)
|
||
for _, c := range contacts {
|
||
contactIDs = append(contactIDs, c.ContactID)
|
||
contactMap[c.ContactID] = c
|
||
}
|
||
|
||
if len(contactIDs) == 0 {
|
||
return results, nil
|
||
}
|
||
|
||
// 查询匹配的用户
|
||
var users []model.User
|
||
err = s.DB.Where("id IN ?", contactIDs).
|
||
Where("name LIKE ? OR email LIKE ? OR phone LIKE ?", likeKeyword, likeKeyword, likeKeyword).
|
||
Limit(limit).
|
||
Find(&users).Error
|
||
if err != nil {
|
||
return results, err
|
||
}
|
||
|
||
// 组装结果
|
||
for _, user := range users {
|
||
contact := contactMap[user.ID]
|
||
userCopy := user
|
||
results = append(results, ContactSearchResult{
|
||
User: &userCopy,
|
||
RemarkName: contact.RemarkName,
|
||
RoomID: contact.RoomID,
|
||
})
|
||
}
|
||
|
||
// 同时搜索备注名匹配的联系人
|
||
var remarkContacts []model.UserContact
|
||
err = s.DB.Where("user_id = ? AND remark_name LIKE ?", userID, likeKeyword).
|
||
Limit(limit).
|
||
Find(&remarkContacts).Error
|
||
if err == nil {
|
||
remarkIDs := make([]string, 0)
|
||
existingIDs := make(map[string]bool)
|
||
for _, r := range results {
|
||
existingIDs[r.User.ID] = true
|
||
}
|
||
for _, c := range remarkContacts {
|
||
if !existingIDs[c.ContactID] {
|
||
remarkIDs = append(remarkIDs, c.ContactID)
|
||
}
|
||
}
|
||
if len(remarkIDs) > 0 {
|
||
var remarkUsers []model.User
|
||
s.DB.Where("id IN ?", remarkIDs).Find(&remarkUsers)
|
||
userMap := make(map[string]model.User)
|
||
for _, u := range remarkUsers {
|
||
userMap[u.ID] = u
|
||
}
|
||
for _, c := range remarkContacts {
|
||
if u, ok := userMap[c.ContactID]; ok && !existingIDs[c.ContactID] {
|
||
userCopy := u
|
||
results = append(results, ContactSearchResult{
|
||
User: &userCopy,
|
||
RemarkName: c.RemarkName,
|
||
RoomID: c.RoomID,
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return results, nil
|
||
}
|
||
|
||
/**
|
||
* searchGroups
|
||
* 功能:搜索群聊
|
||
* 搜索字段:群名称
|
||
*/
|
||
func (s *SearchService) searchGroups(userID, likeKeyword string, limit int) ([]GroupSearchResult, error) {
|
||
var results []GroupSearchResult
|
||
|
||
// 获取用户所在的群聊
|
||
var members []model.RoomMember
|
||
err := s.DB.Where("user_id = ?", userID).Find(&members).Error
|
||
if err != nil {
|
||
return results, err
|
||
}
|
||
|
||
roomIDs := make([]string, 0, len(members))
|
||
for _, m := range members {
|
||
if strings.HasPrefix(m.RoomID, "group_") {
|
||
roomIDs = append(roomIDs, m.RoomID)
|
||
}
|
||
}
|
||
|
||
if len(roomIDs) == 0 {
|
||
return results, nil
|
||
}
|
||
|
||
// 查询匹配的群聊
|
||
var rooms []model.ChatRoom
|
||
err = s.DB.Where("room_id IN ? AND room_type = ? AND room_name LIKE ?", roomIDs, "group", likeKeyword).
|
||
Limit(limit).
|
||
Find(&rooms).Error
|
||
if err != nil {
|
||
return results, err
|
||
}
|
||
|
||
// 获取每个群的成员数量
|
||
for _, room := range rooms {
|
||
var memberCount int64
|
||
s.DB.Model(&model.RoomMember{}).Where("room_id = ?", room.RoomID).Count(&memberCount)
|
||
|
||
results = append(results, GroupSearchResult{
|
||
RoomID: room.RoomID,
|
||
RoomName: room.RoomName,
|
||
RoomAvatar: room.RoomAvatar,
|
||
OwnerID: room.OwnerID,
|
||
MemberCount: int(memberCount),
|
||
})
|
||
}
|
||
|
||
return results, nil
|
||
}
|
||
|
||
/**
|
||
* searchMessages
|
||
* 功能:搜索聊天记录(仅文本消息)
|
||
* 搜索字段:消息内容
|
||
*/
|
||
func (s *SearchService) searchMessages(userID, likeKeyword string, limit int) ([]MessageSearchResult, error) {
|
||
var results []MessageSearchResult
|
||
|
||
// 获取用户有权限查看的房间
|
||
var contacts []model.UserContact
|
||
s.DB.Where("user_id = ?", userID).Find(&contacts)
|
||
|
||
var members []model.RoomMember
|
||
s.DB.Where("user_id = ?", userID).Find(&members)
|
||
|
||
roomIDs := make([]string, 0)
|
||
for _, c := range contacts {
|
||
if c.RoomID != "" {
|
||
roomIDs = append(roomIDs, c.RoomID)
|
||
}
|
||
}
|
||
for _, m := range members {
|
||
roomIDs = append(roomIDs, m.RoomID)
|
||
}
|
||
|
||
if len(roomIDs) == 0 {
|
||
return results, nil
|
||
}
|
||
|
||
// 查询匹配的消息(仅文本消息)
|
||
var messages []model.ChatMessage
|
||
err := s.DB.Where("room_id IN ? AND message_type = ? AND content LIKE ?", roomIDs, 0, likeKeyword).
|
||
Order("created_at DESC").
|
||
Limit(limit).
|
||
Find(&messages).Error
|
||
if err != nil {
|
||
return results, err
|
||
}
|
||
|
||
// 获取发送者信息和房间信息
|
||
senderIDs := make([]string, 0)
|
||
roomIDSet := make(map[string]bool)
|
||
for _, m := range messages {
|
||
senderIDs = append(senderIDs, m.SenderUserID)
|
||
roomIDSet[m.RoomID] = true
|
||
}
|
||
|
||
var users []model.User
|
||
if len(senderIDs) > 0 {
|
||
s.DB.Where("id IN ?", senderIDs).Find(&users)
|
||
}
|
||
userMap := make(map[string]*model.User)
|
||
for i := range users {
|
||
userMap[users[i].ID] = &users[i]
|
||
}
|
||
|
||
uniqueRoomIDs := make([]string, 0, len(roomIDSet))
|
||
for rid := range roomIDSet {
|
||
uniqueRoomIDs = append(uniqueRoomIDs, rid)
|
||
}
|
||
var rooms []model.ChatRoom
|
||
if len(uniqueRoomIDs) > 0 {
|
||
s.DB.Where("room_id IN ?", uniqueRoomIDs).Find(&rooms)
|
||
}
|
||
roomMap := make(map[string]*model.ChatRoom)
|
||
for i := range rooms {
|
||
roomMap[rooms[i].RoomID] = &rooms[i]
|
||
}
|
||
|
||
for _, msg := range messages {
|
||
room := roomMap[msg.RoomID]
|
||
roomName := ""
|
||
isGroupChat := false
|
||
if room != nil {
|
||
roomName = room.RoomName
|
||
isGroupChat = room.RoomType == "group"
|
||
}
|
||
|
||
matchContent := msg.Content
|
||
if len(matchContent) > 100 {
|
||
matchContent = matchContent[:100] + "..."
|
||
}
|
||
|
||
results = append(results, MessageSearchResult{
|
||
ID: msg.ID,
|
||
RoomID: msg.RoomID,
|
||
RoomName: roomName,
|
||
Content: msg.Content,
|
||
MessageType: msg.MessageType,
|
||
CreatedAt: msg.CreatedAt.Format("2006-01-02 15:04:05"),
|
||
Sender: userMap[msg.SenderUserID],
|
||
IsGroupChat: isGroupChat,
|
||
MatchContent: matchContent,
|
||
})
|
||
}
|
||
|
||
return results, nil
|
||
}
|
||
|