diff --git a/api/auth/init.go b/api/auth/init.go index 9733acc..fbf92c6 100644 --- a/api/auth/init.go +++ b/api/auth/init.go @@ -31,6 +31,7 @@ func init() { // === 认证用户接口(需要登录)=== // 用户搜索(返回公开信息) Router.Get("/users", "搜索用户", searchUsers) + Router.Post("/users", "批量查询用户", searchUsers) // 当前用户(需要认证) meRouter := Router.SubRouter("/me") diff --git a/api/auth/search_users.go b/api/auth/search_users.go index 672fe5e..547711b 100644 --- a/api/auth/search_users.go +++ b/api/auth/search_users.go @@ -7,6 +7,8 @@ package auth import ( + "strings" + "github.com/veypi/vbase/cfg" "github.com/veypi/vbase/models" "github.com/veypi/vigo" @@ -15,25 +17,32 @@ import ( // PublicUserInfo 公开的用户信息(仅包含无关紧要的信息) type PublicUserInfo struct { ID string `json:"id"` + Name string `json:"name"` Username string `json:"username"` Nickname string `json:"nickname"` + Icon string `json:"icon"` Avatar string `json:"avatar"` } // SearchUsersRequest 搜索用户请求 type SearchUsersRequest struct { - Keyword *string `json:"keyword" src:"query" desc:"搜索关键词(用户名或昵称)"` - Limit int `json:"limit" src:"query" default:"20" desc:"返回数量限制"` + Keyword *string `json:"keyword" src:"query" desc:"搜索关键词(用户名或昵称)"` + Limit int `json:"limit" src:"query" default:"20" desc:"返回数量限制"` + IDs []string `json:"ids" src:"json" desc:"用户ID列表"` } // SearchUsersResponse 搜索用户响应 type SearchUsersResponse struct { Items []PublicUserInfo `json:"items"` - Total int64 `json:"total"` + Total int64 `json:"total"` } // searchUsers 搜索用户(公开接口,仅返回公开信息) func searchUsers(x *vigo.X, req *SearchUsersRequest) (*SearchUsersResponse, error) { + if len(req.IDs) > 0 { + return searchUsersByIDs(req) + } + if req.Limit <= 0 || req.Limit > 50 { req.Limit = 20 } @@ -59,12 +68,7 @@ func searchUsers(x *vigo.X, req *SearchUsersRequest) (*SearchUsersResponse, erro // 转换为公开信息 items := make([]PublicUserInfo, len(users)) for i, user := range users { - items[i] = PublicUserInfo{ - ID: user.ID, - Username: user.Username, - Nickname: user.Nickname, - Avatar: user.Avatar, - } + items[i] = buildPublicUserInfo(&user) } return &SearchUsersResponse{ @@ -72,3 +76,69 @@ func searchUsers(x *vigo.X, req *SearchUsersRequest) (*SearchUsersResponse, erro Total: total, }, nil } + +func searchUsersByIDs(req *SearchUsersRequest) (*SearchUsersResponse, error) { + ids := make([]string, 0, len(req.IDs)) + seen := make(map[string]struct{}, len(req.IDs)) + for _, id := range req.IDs { + id = strings.TrimSpace(id) + if id == "" { + continue + } + if _, ok := seen[id]; ok { + continue + } + seen[id] = struct{}{} + ids = append(ids, id) + } + + if len(ids) == 0 { + return &SearchUsersResponse{ + Items: []PublicUserInfo{}, + Total: 0, + }, nil + } + + var users []models.User + if err := cfg.DB(). + Model(&models.User{}). + Where("status = ? AND id IN ?", models.UserStatusActive, ids). + Find(&users).Error; err != nil { + return nil, vigo.ErrInternalServer.WithError(err) + } + + userMap := make(map[string]models.User, len(users)) + for _, user := range users { + userMap[user.ID] = user + } + + items := make([]PublicUserInfo, 0, len(users)) + for _, id := range ids { + user, ok := userMap[id] + if !ok { + continue + } + items = append(items, buildPublicUserInfo(&user)) + } + + return &SearchUsersResponse{ + Items: items, + Total: int64(len(items)), + }, nil +} + +func buildPublicUserInfo(user *models.User) PublicUserInfo { + name := user.Nickname + if name == "" { + name = user.Username + } + + return PublicUserInfo{ + ID: user.ID, + Name: name, + Username: user.Username, + Nickname: user.Nickname, + Icon: user.Avatar, + Avatar: user.Avatar, + } +}