2026-03-09 21:28:58 +08:00
|
|
|
|
package dto
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"carrot_bbs/internal/model"
|
|
|
|
|
|
"carrot_bbs/internal/pkg/utils"
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"encoding/json"
|
|
|
|
|
|
"strconv"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== User 转换 ====================
|
|
|
|
|
|
|
|
|
|
|
|
// getAvatarOrDefault 获取头像URL,如果为空则返回在线头像生成服务的URL
|
|
|
|
|
|
func getAvatarOrDefault(user *model.User) string {
|
|
|
|
|
|
return utils.GetAvatarOrDefault(user.Username, user.Nickname, user.Avatar)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertUserToResponse 将User转换为UserResponse
|
|
|
|
|
|
func ConvertUserToResponse(user *model.User) *UserResponse {
|
|
|
|
|
|
if user == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &UserResponse{
|
|
|
|
|
|
ID: user.ID,
|
|
|
|
|
|
Username: user.Username,
|
|
|
|
|
|
Nickname: user.Nickname,
|
|
|
|
|
|
Email: user.Email,
|
|
|
|
|
|
Phone: user.Phone,
|
|
|
|
|
|
EmailVerified: user.EmailVerified,
|
|
|
|
|
|
Avatar: getAvatarOrDefault(user),
|
|
|
|
|
|
CoverURL: user.CoverURL,
|
|
|
|
|
|
Bio: user.Bio,
|
|
|
|
|
|
Website: user.Website,
|
|
|
|
|
|
Location: user.Location,
|
|
|
|
|
|
PostsCount: user.PostsCount,
|
|
|
|
|
|
FollowersCount: user.FollowersCount,
|
|
|
|
|
|
FollowingCount: user.FollowingCount,
|
|
|
|
|
|
CreatedAt: FormatTime(user.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertUserToResponseWithFollowing 将User转换为UserResponse(包含关注状态)
|
|
|
|
|
|
func ConvertUserToResponseWithFollowing(user *model.User, isFollowing bool) *UserResponse {
|
|
|
|
|
|
if user == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &UserResponse{
|
|
|
|
|
|
ID: user.ID,
|
|
|
|
|
|
Username: user.Username,
|
|
|
|
|
|
Nickname: user.Nickname,
|
|
|
|
|
|
Email: user.Email,
|
|
|
|
|
|
Phone: user.Phone,
|
|
|
|
|
|
EmailVerified: user.EmailVerified,
|
|
|
|
|
|
Avatar: getAvatarOrDefault(user),
|
|
|
|
|
|
CoverURL: user.CoverURL,
|
|
|
|
|
|
Bio: user.Bio,
|
|
|
|
|
|
Website: user.Website,
|
|
|
|
|
|
Location: user.Location,
|
|
|
|
|
|
PostsCount: user.PostsCount,
|
|
|
|
|
|
FollowersCount: user.FollowersCount,
|
|
|
|
|
|
FollowingCount: user.FollowingCount,
|
|
|
|
|
|
IsFollowing: isFollowing,
|
|
|
|
|
|
IsFollowingMe: false, // 默认false,需要单独计算
|
|
|
|
|
|
CreatedAt: FormatTime(user.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertUserToResponseWithPostsCount 将User转换为UserResponse(使用实时计算的帖子数量)
|
|
|
|
|
|
func ConvertUserToResponseWithPostsCount(user *model.User, postsCount int) *UserResponse {
|
|
|
|
|
|
if user == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &UserResponse{
|
|
|
|
|
|
ID: user.ID,
|
|
|
|
|
|
Username: user.Username,
|
|
|
|
|
|
Nickname: user.Nickname,
|
|
|
|
|
|
Email: user.Email,
|
|
|
|
|
|
Phone: user.Phone,
|
|
|
|
|
|
EmailVerified: user.EmailVerified,
|
|
|
|
|
|
Avatar: getAvatarOrDefault(user),
|
|
|
|
|
|
CoverURL: user.CoverURL,
|
|
|
|
|
|
Bio: user.Bio,
|
|
|
|
|
|
Website: user.Website,
|
|
|
|
|
|
Location: user.Location,
|
|
|
|
|
|
PostsCount: postsCount,
|
|
|
|
|
|
FollowersCount: user.FollowersCount,
|
|
|
|
|
|
FollowingCount: user.FollowingCount,
|
|
|
|
|
|
CreatedAt: FormatTime(user.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertUserToResponseWithMutualFollow 将User转换为UserResponse(包含双向关注状态)
|
|
|
|
|
|
func ConvertUserToResponseWithMutualFollow(user *model.User, isFollowing, isFollowingMe bool) *UserResponse {
|
|
|
|
|
|
if user == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &UserResponse{
|
|
|
|
|
|
ID: user.ID,
|
|
|
|
|
|
Username: user.Username,
|
|
|
|
|
|
Nickname: user.Nickname,
|
|
|
|
|
|
Email: user.Email,
|
|
|
|
|
|
Phone: user.Phone,
|
|
|
|
|
|
EmailVerified: user.EmailVerified,
|
|
|
|
|
|
Avatar: getAvatarOrDefault(user),
|
|
|
|
|
|
CoverURL: user.CoverURL,
|
|
|
|
|
|
Bio: user.Bio,
|
|
|
|
|
|
Website: user.Website,
|
|
|
|
|
|
Location: user.Location,
|
|
|
|
|
|
PostsCount: user.PostsCount,
|
|
|
|
|
|
FollowersCount: user.FollowersCount,
|
|
|
|
|
|
FollowingCount: user.FollowingCount,
|
|
|
|
|
|
IsFollowing: isFollowing,
|
|
|
|
|
|
IsFollowingMe: isFollowingMe,
|
|
|
|
|
|
CreatedAt: FormatTime(user.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertUserToResponseWithMutualFollowAndPostsCount 将User转换为UserResponse(包含双向关注状态和实时计算的帖子数量)
|
|
|
|
|
|
func ConvertUserToResponseWithMutualFollowAndPostsCount(user *model.User, isFollowing, isFollowingMe bool, postsCount int) *UserResponse {
|
|
|
|
|
|
if user == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &UserResponse{
|
|
|
|
|
|
ID: user.ID,
|
|
|
|
|
|
Username: user.Username,
|
|
|
|
|
|
Nickname: user.Nickname,
|
|
|
|
|
|
Email: user.Email,
|
|
|
|
|
|
Phone: user.Phone,
|
|
|
|
|
|
EmailVerified: user.EmailVerified,
|
|
|
|
|
|
Avatar: getAvatarOrDefault(user),
|
|
|
|
|
|
CoverURL: user.CoverURL,
|
|
|
|
|
|
Bio: user.Bio,
|
|
|
|
|
|
Website: user.Website,
|
|
|
|
|
|
Location: user.Location,
|
|
|
|
|
|
PostsCount: postsCount,
|
|
|
|
|
|
FollowersCount: user.FollowersCount,
|
|
|
|
|
|
FollowingCount: user.FollowingCount,
|
|
|
|
|
|
IsFollowing: isFollowing,
|
|
|
|
|
|
IsFollowingMe: isFollowingMe,
|
|
|
|
|
|
CreatedAt: FormatTime(user.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertUserToDetailResponse 将User转换为UserDetailResponse
|
|
|
|
|
|
func ConvertUserToDetailResponse(user *model.User) *UserDetailResponse {
|
|
|
|
|
|
if user == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &UserDetailResponse{
|
|
|
|
|
|
ID: user.ID,
|
|
|
|
|
|
Username: user.Username,
|
|
|
|
|
|
Nickname: user.Nickname,
|
|
|
|
|
|
Email: user.Email,
|
|
|
|
|
|
EmailVerified: user.EmailVerified,
|
|
|
|
|
|
Avatar: getAvatarOrDefault(user),
|
|
|
|
|
|
CoverURL: user.CoverURL,
|
|
|
|
|
|
Bio: user.Bio,
|
|
|
|
|
|
Website: user.Website,
|
|
|
|
|
|
Location: user.Location,
|
|
|
|
|
|
PostsCount: user.PostsCount,
|
|
|
|
|
|
FollowersCount: user.FollowersCount,
|
|
|
|
|
|
FollowingCount: user.FollowingCount,
|
|
|
|
|
|
IsVerified: user.IsVerified,
|
|
|
|
|
|
CreatedAt: FormatTime(user.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertUserToDetailResponseWithPostsCount 将User转换为UserDetailResponse(使用实时计算的帖子数量)
|
|
|
|
|
|
func ConvertUserToDetailResponseWithPostsCount(user *model.User, postsCount int) *UserDetailResponse {
|
|
|
|
|
|
if user == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &UserDetailResponse{
|
|
|
|
|
|
ID: user.ID,
|
|
|
|
|
|
Username: user.Username,
|
|
|
|
|
|
Nickname: user.Nickname,
|
|
|
|
|
|
Email: user.Email,
|
|
|
|
|
|
EmailVerified: user.EmailVerified,
|
|
|
|
|
|
Phone: user.Phone, // 仅当前用户自己可见
|
|
|
|
|
|
Avatar: getAvatarOrDefault(user),
|
|
|
|
|
|
CoverURL: user.CoverURL,
|
|
|
|
|
|
Bio: user.Bio,
|
|
|
|
|
|
Website: user.Website,
|
|
|
|
|
|
Location: user.Location,
|
|
|
|
|
|
PostsCount: postsCount,
|
|
|
|
|
|
FollowersCount: user.FollowersCount,
|
|
|
|
|
|
FollowingCount: user.FollowingCount,
|
|
|
|
|
|
IsVerified: user.IsVerified,
|
|
|
|
|
|
CreatedAt: FormatTime(user.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertUsersToResponse 将User列表转换为响应列表
|
|
|
|
|
|
func ConvertUsersToResponse(users []*model.User) []*UserResponse {
|
|
|
|
|
|
result := make([]*UserResponse, 0, len(users))
|
|
|
|
|
|
for _, user := range users {
|
|
|
|
|
|
result = append(result, ConvertUserToResponse(user))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertUsersToResponseWithMutualFollow 将User列表转换为响应列表(包含双向关注状态)
|
|
|
|
|
|
// followingStatusMap: key是用户ID,value是[isFollowing, isFollowingMe]
|
|
|
|
|
|
func ConvertUsersToResponseWithMutualFollow(users []*model.User, followingStatusMap map[string][2]bool) []*UserResponse {
|
|
|
|
|
|
result := make([]*UserResponse, 0, len(users))
|
|
|
|
|
|
for _, user := range users {
|
|
|
|
|
|
status, ok := followingStatusMap[user.ID]
|
|
|
|
|
|
if ok {
|
|
|
|
|
|
result = append(result, ConvertUserToResponseWithMutualFollow(user, status[0], status[1]))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
result = append(result, ConvertUserToResponse(user))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertUsersToResponseWithMutualFollowAndPostsCount 将User列表转换为响应列表(包含双向关注状态和实时计算的帖子数量)
|
|
|
|
|
|
// followingStatusMap: key是用户ID,value是[isFollowing, isFollowingMe]
|
|
|
|
|
|
// postsCountMap: key是用户ID,value是帖子数量
|
|
|
|
|
|
func ConvertUsersToResponseWithMutualFollowAndPostsCount(users []*model.User, followingStatusMap map[string][2]bool, postsCountMap map[string]int64) []*UserResponse {
|
|
|
|
|
|
result := make([]*UserResponse, 0, len(users))
|
|
|
|
|
|
for _, user := range users {
|
|
|
|
|
|
status, hasStatus := followingStatusMap[user.ID]
|
|
|
|
|
|
postsCount, hasPostsCount := postsCountMap[user.ID]
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有帖子数量,使用数据库中的值
|
|
|
|
|
|
if !hasPostsCount {
|
|
|
|
|
|
postsCount = int64(user.PostsCount)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if hasStatus {
|
|
|
|
|
|
result = append(result, ConvertUserToResponseWithMutualFollowAndPostsCount(user, status[0], status[1], int(postsCount)))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
result = append(result, ConvertUserToResponseWithPostsCount(user, int(postsCount)))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== Post 转换 ====================
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertPostImageToResponse 将PostImage转换为PostImageResponse
|
|
|
|
|
|
func ConvertPostImageToResponse(img *model.PostImage) PostImageResponse {
|
|
|
|
|
|
if img == nil {
|
|
|
|
|
|
return PostImageResponse{}
|
|
|
|
|
|
}
|
|
|
|
|
|
return PostImageResponse{
|
|
|
|
|
|
ID: img.ID,
|
|
|
|
|
|
URL: img.URL,
|
|
|
|
|
|
ThumbnailURL: img.ThumbnailURL,
|
|
|
|
|
|
Width: img.Width,
|
|
|
|
|
|
Height: img.Height,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertPostImagesToResponse 将PostImage列表转换为响应列表
|
|
|
|
|
|
func ConvertPostImagesToResponse(images []model.PostImage) []PostImageResponse {
|
|
|
|
|
|
result := make([]PostImageResponse, 0, len(images))
|
|
|
|
|
|
for i := range images {
|
|
|
|
|
|
result = append(result, ConvertPostImageToResponse(&images[i]))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertPostToResponse 将Post转换为PostResponse(列表用)
|
|
|
|
|
|
func ConvertPostToResponse(post *model.Post, isLiked, isFavorited bool) *PostResponse {
|
|
|
|
|
|
if post == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
images := make([]PostImageResponse, 0)
|
|
|
|
|
|
for _, img := range post.Images {
|
|
|
|
|
|
images = append(images, ConvertPostImageToResponse(&img))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var author *UserResponse
|
|
|
|
|
|
if post.User != nil {
|
|
|
|
|
|
author = ConvertUserToResponse(post.User)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &PostResponse{
|
|
|
|
|
|
ID: post.ID,
|
|
|
|
|
|
UserID: post.UserID,
|
|
|
|
|
|
Title: post.Title,
|
|
|
|
|
|
Content: post.Content,
|
|
|
|
|
|
Images: images,
|
2026-03-10 12:58:23 +08:00
|
|
|
|
Status: string(post.Status),
|
2026-03-09 21:28:58 +08:00
|
|
|
|
LikesCount: post.LikesCount,
|
|
|
|
|
|
CommentsCount: post.CommentsCount,
|
|
|
|
|
|
FavoritesCount: post.FavoritesCount,
|
|
|
|
|
|
SharesCount: post.SharesCount,
|
|
|
|
|
|
ViewsCount: post.ViewsCount,
|
|
|
|
|
|
IsPinned: post.IsPinned,
|
|
|
|
|
|
IsLocked: post.IsLocked,
|
|
|
|
|
|
IsVote: post.IsVote,
|
|
|
|
|
|
CreatedAt: FormatTime(post.CreatedAt),
|
2026-03-10 12:58:23 +08:00
|
|
|
|
UpdatedAt: FormatTime(post.UpdatedAt),
|
2026-03-09 21:28:58 +08:00
|
|
|
|
Author: author,
|
|
|
|
|
|
IsLiked: isLiked,
|
|
|
|
|
|
IsFavorited: isFavorited,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertPostToDetailResponse 将Post转换为PostDetailResponse
|
|
|
|
|
|
func ConvertPostToDetailResponse(post *model.Post, isLiked, isFavorited bool) *PostDetailResponse {
|
|
|
|
|
|
if post == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
images := make([]PostImageResponse, 0)
|
|
|
|
|
|
for _, img := range post.Images {
|
|
|
|
|
|
images = append(images, ConvertPostImageToResponse(&img))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var author *UserResponse
|
|
|
|
|
|
if post.User != nil {
|
|
|
|
|
|
author = ConvertUserToResponse(post.User)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &PostDetailResponse{
|
|
|
|
|
|
ID: post.ID,
|
|
|
|
|
|
UserID: post.UserID,
|
|
|
|
|
|
Title: post.Title,
|
|
|
|
|
|
Content: post.Content,
|
|
|
|
|
|
Images: images,
|
|
|
|
|
|
Status: string(post.Status),
|
|
|
|
|
|
LikesCount: post.LikesCount,
|
|
|
|
|
|
CommentsCount: post.CommentsCount,
|
|
|
|
|
|
FavoritesCount: post.FavoritesCount,
|
|
|
|
|
|
SharesCount: post.SharesCount,
|
|
|
|
|
|
ViewsCount: post.ViewsCount,
|
|
|
|
|
|
IsPinned: post.IsPinned,
|
|
|
|
|
|
IsLocked: post.IsLocked,
|
|
|
|
|
|
IsVote: post.IsVote,
|
|
|
|
|
|
CreatedAt: FormatTime(post.CreatedAt),
|
|
|
|
|
|
UpdatedAt: FormatTime(post.UpdatedAt),
|
|
|
|
|
|
Author: author,
|
|
|
|
|
|
IsLiked: isLiked,
|
|
|
|
|
|
IsFavorited: isFavorited,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertPostsToResponse 将Post列表转换为响应列表(每个帖子独立检查点赞/收藏状态)
|
|
|
|
|
|
func ConvertPostsToResponse(posts []*model.Post, isLikedMap, isFavoritedMap map[string]bool) []*PostResponse {
|
|
|
|
|
|
result := make([]*PostResponse, 0, len(posts))
|
|
|
|
|
|
for _, post := range posts {
|
|
|
|
|
|
isLiked := false
|
|
|
|
|
|
isFavorited := false
|
|
|
|
|
|
if isLikedMap != nil {
|
|
|
|
|
|
isLiked = isLikedMap[post.ID]
|
|
|
|
|
|
}
|
|
|
|
|
|
if isFavoritedMap != nil {
|
|
|
|
|
|
isFavorited = isFavoritedMap[post.ID]
|
|
|
|
|
|
}
|
|
|
|
|
|
result = append(result, ConvertPostToResponse(post, isLiked, isFavorited))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 20:52:50 +08:00
|
|
|
|
// BuildPostResponse 构建单个帖子响应(包含交互状态)
|
|
|
|
|
|
// 这是一个语义化的辅助函数,便于 Handler 层调用
|
|
|
|
|
|
func BuildPostResponse(post *model.Post, isLiked, isFavorited bool) *PostResponse {
|
|
|
|
|
|
return ConvertPostToResponse(post, isLiked, isFavorited)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// BuildPostsWithInteractionResponse 批量构建帖子响应(包含交互状态)
|
|
|
|
|
|
// 这是一个语义化的辅助函数,便于 Handler 层调用
|
|
|
|
|
|
func BuildPostsWithInteractionResponse(posts []*model.Post, isLikedMap, isFavoritedMap map[string]bool) []*PostResponse {
|
|
|
|
|
|
return ConvertPostsToResponse(posts, isLikedMap, isFavoritedMap)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-09 21:28:58 +08:00
|
|
|
|
// ==================== Comment 转换 ====================
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertCommentToResponse 将Comment转换为CommentResponse
|
|
|
|
|
|
func ConvertCommentToResponse(comment *model.Comment, isLiked bool) *CommentResponse {
|
|
|
|
|
|
if comment == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var author *UserResponse
|
|
|
|
|
|
if comment.User != nil {
|
|
|
|
|
|
author = ConvertUserToResponse(comment.User)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 转换子回复(扁平化结构)
|
|
|
|
|
|
var replies []*CommentResponse
|
|
|
|
|
|
if len(comment.Replies) > 0 {
|
|
|
|
|
|
replies = make([]*CommentResponse, 0, len(comment.Replies))
|
|
|
|
|
|
for _, reply := range comment.Replies {
|
|
|
|
|
|
replies = append(replies, ConvertCommentToResponse(reply, false))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TargetID 就是 ParentID,前端根据这个 ID 找到被回复用户的昵称
|
|
|
|
|
|
var targetID *string
|
|
|
|
|
|
if comment.ParentID != nil && *comment.ParentID != "" {
|
|
|
|
|
|
targetID = comment.ParentID
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析图片JSON
|
|
|
|
|
|
var images []CommentImageResponse
|
|
|
|
|
|
if comment.Images != "" {
|
|
|
|
|
|
var urlList []string
|
|
|
|
|
|
if err := json.Unmarshal([]byte(comment.Images), &urlList); err == nil {
|
|
|
|
|
|
images = make([]CommentImageResponse, 0, len(urlList))
|
|
|
|
|
|
for _, url := range urlList {
|
|
|
|
|
|
images = append(images, CommentImageResponse{URL: url})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &CommentResponse{
|
|
|
|
|
|
ID: comment.ID,
|
|
|
|
|
|
PostID: comment.PostID,
|
|
|
|
|
|
UserID: comment.UserID,
|
|
|
|
|
|
ParentID: comment.ParentID,
|
|
|
|
|
|
RootID: comment.RootID,
|
|
|
|
|
|
Content: comment.Content,
|
|
|
|
|
|
Images: images,
|
|
|
|
|
|
LikesCount: comment.LikesCount,
|
|
|
|
|
|
RepliesCount: comment.RepliesCount,
|
|
|
|
|
|
CreatedAt: FormatTime(comment.CreatedAt),
|
|
|
|
|
|
Author: author,
|
|
|
|
|
|
IsLiked: isLiked,
|
|
|
|
|
|
TargetID: targetID,
|
|
|
|
|
|
Replies: replies,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertCommentsToResponse 将Comment列表转换为响应列表
|
|
|
|
|
|
func ConvertCommentsToResponse(comments []*model.Comment, isLiked bool) []*CommentResponse {
|
|
|
|
|
|
result := make([]*CommentResponse, 0, len(comments))
|
|
|
|
|
|
for _, comment := range comments {
|
|
|
|
|
|
result = append(result, ConvertCommentToResponse(comment, isLiked))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// IsLikedChecker 点赞状态检查器接口
|
|
|
|
|
|
type IsLikedChecker interface {
|
|
|
|
|
|
IsLiked(ctx context.Context, commentID, userID string) bool
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertCommentToResponseWithUser 将Comment转换为CommentResponse(根据用户ID检查点赞状态)
|
|
|
|
|
|
func ConvertCommentToResponseWithUser(comment *model.Comment, userID string, checker IsLikedChecker) *CommentResponse {
|
|
|
|
|
|
if comment == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查当前用户是否点赞了该评论
|
|
|
|
|
|
isLiked := false
|
|
|
|
|
|
if userID != "" && checker != nil {
|
|
|
|
|
|
isLiked = checker.IsLiked(context.Background(), comment.ID, userID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var author *UserResponse
|
|
|
|
|
|
if comment.User != nil {
|
|
|
|
|
|
author = ConvertUserToResponse(comment.User)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 转换子回复(扁平化结构),递归检查点赞状态
|
|
|
|
|
|
var replies []*CommentResponse
|
|
|
|
|
|
if len(comment.Replies) > 0 {
|
|
|
|
|
|
replies = make([]*CommentResponse, 0, len(comment.Replies))
|
|
|
|
|
|
for _, reply := range comment.Replies {
|
|
|
|
|
|
replies = append(replies, ConvertCommentToResponseWithUser(reply, userID, checker))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TargetID 就是 ParentID,前端根据这个 ID 找到被回复用户的昵称
|
|
|
|
|
|
var targetID *string
|
|
|
|
|
|
if comment.ParentID != nil && *comment.ParentID != "" {
|
|
|
|
|
|
targetID = comment.ParentID
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析图片JSON
|
|
|
|
|
|
var images []CommentImageResponse
|
|
|
|
|
|
if comment.Images != "" {
|
|
|
|
|
|
var urlList []string
|
|
|
|
|
|
if err := json.Unmarshal([]byte(comment.Images), &urlList); err == nil {
|
|
|
|
|
|
images = make([]CommentImageResponse, 0, len(urlList))
|
|
|
|
|
|
for _, url := range urlList {
|
|
|
|
|
|
images = append(images, CommentImageResponse{URL: url})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &CommentResponse{
|
|
|
|
|
|
ID: comment.ID,
|
|
|
|
|
|
PostID: comment.PostID,
|
|
|
|
|
|
UserID: comment.UserID,
|
|
|
|
|
|
ParentID: comment.ParentID,
|
|
|
|
|
|
RootID: comment.RootID,
|
|
|
|
|
|
Content: comment.Content,
|
|
|
|
|
|
Images: images,
|
|
|
|
|
|
LikesCount: comment.LikesCount,
|
|
|
|
|
|
RepliesCount: comment.RepliesCount,
|
|
|
|
|
|
CreatedAt: FormatTime(comment.CreatedAt),
|
|
|
|
|
|
Author: author,
|
|
|
|
|
|
IsLiked: isLiked,
|
|
|
|
|
|
TargetID: targetID,
|
|
|
|
|
|
Replies: replies,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertCommentsToResponseWithUser 将Comment列表转换为响应列表(根据用户ID检查点赞状态)
|
|
|
|
|
|
func ConvertCommentsToResponseWithUser(comments []*model.Comment, userID string, checker IsLikedChecker) []*CommentResponse {
|
|
|
|
|
|
result := make([]*CommentResponse, 0, len(comments))
|
|
|
|
|
|
for _, comment := range comments {
|
|
|
|
|
|
result = append(result, ConvertCommentToResponseWithUser(comment, userID, checker))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== Notification 转换 ====================
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertNotificationToResponse 将Notification转换为NotificationResponse
|
|
|
|
|
|
func ConvertNotificationToResponse(notification *model.Notification) *NotificationResponse {
|
|
|
|
|
|
if notification == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &NotificationResponse{
|
|
|
|
|
|
ID: notification.ID,
|
|
|
|
|
|
UserID: notification.UserID,
|
|
|
|
|
|
Type: string(notification.Type),
|
|
|
|
|
|
Title: notification.Title,
|
|
|
|
|
|
Content: notification.Content,
|
|
|
|
|
|
Data: notification.Data,
|
|
|
|
|
|
IsRead: notification.IsRead,
|
|
|
|
|
|
CreatedAt: FormatTime(notification.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertNotificationsToResponse 将Notification列表转换为响应列表
|
|
|
|
|
|
func ConvertNotificationsToResponse(notifications []*model.Notification) []*NotificationResponse {
|
|
|
|
|
|
result := make([]*NotificationResponse, 0, len(notifications))
|
|
|
|
|
|
for _, n := range notifications {
|
|
|
|
|
|
result = append(result, ConvertNotificationToResponse(n))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== Message 转换 ====================
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertMessageToResponse 将Message转换为MessageResponse
|
|
|
|
|
|
func ConvertMessageToResponse(message *model.Message) *MessageResponse {
|
|
|
|
|
|
if message == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 直接使用 segments,不需要解析
|
|
|
|
|
|
segments := make(model.MessageSegments, len(message.Segments))
|
|
|
|
|
|
for i, seg := range message.Segments {
|
|
|
|
|
|
segments[i] = model.MessageSegment{
|
|
|
|
|
|
Type: seg.Type,
|
|
|
|
|
|
Data: seg.Data,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &MessageResponse{
|
|
|
|
|
|
ID: message.ID,
|
|
|
|
|
|
ConversationID: message.ConversationID,
|
|
|
|
|
|
SenderID: message.SenderID,
|
|
|
|
|
|
Seq: message.Seq,
|
|
|
|
|
|
Segments: segments,
|
|
|
|
|
|
ReplyToID: message.ReplyToID,
|
|
|
|
|
|
Status: string(message.Status),
|
|
|
|
|
|
Category: string(message.Category),
|
|
|
|
|
|
CreatedAt: FormatTime(message.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertConversationToResponse 将Conversation转换为ConversationResponse
|
|
|
|
|
|
// participants: 会话参与者列表(用户信息)
|
|
|
|
|
|
// unreadCount: 当前用户的未读消息数
|
|
|
|
|
|
// lastMessage: 最后一条消息
|
|
|
|
|
|
func ConvertConversationToResponse(conv *model.Conversation, participants []*model.User, unreadCount int, lastMessage *model.Message, isPinned bool) *ConversationResponse {
|
|
|
|
|
|
if conv == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var participantResponses []*UserResponse
|
|
|
|
|
|
for _, p := range participants {
|
|
|
|
|
|
participantResponses = append(participantResponses, ConvertUserToResponse(p))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 转换群组信息
|
|
|
|
|
|
var groupResponse *GroupResponse
|
|
|
|
|
|
if conv.Group != nil {
|
|
|
|
|
|
groupResponse = GroupToResponse(conv.Group)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &ConversationResponse{
|
|
|
|
|
|
ID: conv.ID,
|
|
|
|
|
|
Type: string(conv.Type),
|
|
|
|
|
|
IsPinned: isPinned,
|
|
|
|
|
|
Group: groupResponse,
|
|
|
|
|
|
LastSeq: conv.LastSeq,
|
|
|
|
|
|
LastMessage: ConvertMessageToResponse(lastMessage),
|
|
|
|
|
|
LastMessageAt: FormatTimePointer(conv.LastMsgTime),
|
|
|
|
|
|
UnreadCount: unreadCount,
|
|
|
|
|
|
Participants: participantResponses,
|
|
|
|
|
|
CreatedAt: FormatTime(conv.CreatedAt),
|
|
|
|
|
|
UpdatedAt: FormatTime(conv.UpdatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertConversationToDetailResponse 将Conversation转换为ConversationDetailResponse
|
|
|
|
|
|
func ConvertConversationToDetailResponse(conv *model.Conversation, participants []*model.User, unreadCount int64, lastMessage *model.Message, myLastReadSeq int64, otherLastReadSeq int64, isPinned bool) *ConversationDetailResponse {
|
|
|
|
|
|
if conv == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var participantResponses []*UserResponse
|
|
|
|
|
|
for _, p := range participants {
|
|
|
|
|
|
participantResponses = append(participantResponses, ConvertUserToResponse(p))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &ConversationDetailResponse{
|
|
|
|
|
|
ID: conv.ID,
|
|
|
|
|
|
Type: string(conv.Type),
|
|
|
|
|
|
IsPinned: isPinned,
|
|
|
|
|
|
LastSeq: conv.LastSeq,
|
|
|
|
|
|
LastMessage: ConvertMessageToResponse(lastMessage),
|
|
|
|
|
|
LastMessageAt: FormatTimePointer(conv.LastMsgTime),
|
|
|
|
|
|
UnreadCount: unreadCount,
|
|
|
|
|
|
Participants: participantResponses,
|
|
|
|
|
|
MyLastReadSeq: myLastReadSeq,
|
|
|
|
|
|
OtherLastReadSeq: otherLastReadSeq,
|
|
|
|
|
|
CreatedAt: FormatTime(conv.CreatedAt),
|
|
|
|
|
|
UpdatedAt: FormatTime(conv.UpdatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertMessagesToResponse 将Message列表转换为响应列表
|
|
|
|
|
|
func ConvertMessagesToResponse(messages []*model.Message) []*MessageResponse {
|
|
|
|
|
|
result := make([]*MessageResponse, 0, len(messages))
|
|
|
|
|
|
for _, msg := range messages {
|
|
|
|
|
|
result = append(result, ConvertMessageToResponse(msg))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConvertConversationsToResponse 将Conversation列表转换为响应列表
|
|
|
|
|
|
func ConvertConversationsToResponse(convs []*model.Conversation) []*ConversationResponse {
|
|
|
|
|
|
result := make([]*ConversationResponse, 0, len(convs))
|
|
|
|
|
|
for _, conv := range convs {
|
|
|
|
|
|
result = append(result, ConvertConversationToResponse(conv, nil, 0, nil, false))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== PushRecord 转换 ====================
|
|
|
|
|
|
|
|
|
|
|
|
// PushRecordToResponse 将PushRecord转换为PushRecordResponse
|
|
|
|
|
|
func PushRecordToResponse(record *model.PushRecord) *PushRecordResponse {
|
|
|
|
|
|
if record == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
resp := &PushRecordResponse{
|
|
|
|
|
|
ID: record.ID,
|
|
|
|
|
|
MessageID: record.MessageID,
|
|
|
|
|
|
PushChannel: string(record.PushChannel),
|
|
|
|
|
|
PushStatus: string(record.PushStatus),
|
|
|
|
|
|
RetryCount: record.RetryCount,
|
|
|
|
|
|
CreatedAt: record.CreatedAt,
|
|
|
|
|
|
}
|
|
|
|
|
|
if record.PushedAt != nil {
|
|
|
|
|
|
resp.PushedAt = *record.PushedAt
|
|
|
|
|
|
}
|
|
|
|
|
|
if record.DeliveredAt != nil {
|
|
|
|
|
|
resp.DeliveredAt = *record.DeliveredAt
|
|
|
|
|
|
}
|
|
|
|
|
|
return resp
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PushRecordsToResponse 将PushRecord列表转换为响应列表
|
|
|
|
|
|
func PushRecordsToResponse(records []*model.PushRecord) []*PushRecordResponse {
|
|
|
|
|
|
result := make([]*PushRecordResponse, 0, len(records))
|
|
|
|
|
|
for _, record := range records {
|
|
|
|
|
|
result = append(result, PushRecordToResponse(record))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== DeviceToken 转换 ====================
|
|
|
|
|
|
|
|
|
|
|
|
// DeviceTokenToResponse 将DeviceToken转换为DeviceTokenResponse
|
|
|
|
|
|
func DeviceTokenToResponse(token *model.DeviceToken) *DeviceTokenResponse {
|
|
|
|
|
|
if token == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
resp := &DeviceTokenResponse{
|
|
|
|
|
|
ID: token.ID,
|
|
|
|
|
|
DeviceID: token.DeviceID,
|
|
|
|
|
|
DeviceType: string(token.DeviceType),
|
|
|
|
|
|
IsActive: token.IsActive,
|
|
|
|
|
|
DeviceName: token.DeviceName,
|
|
|
|
|
|
CreatedAt: token.CreatedAt,
|
|
|
|
|
|
}
|
|
|
|
|
|
if token.LastUsedAt != nil {
|
|
|
|
|
|
resp.LastUsedAt = *token.LastUsedAt
|
|
|
|
|
|
}
|
|
|
|
|
|
return resp
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DeviceTokensToResponse 将DeviceToken列表转换为响应列表
|
|
|
|
|
|
func DeviceTokensToResponse(tokens []*model.DeviceToken) []*DeviceTokenResponse {
|
|
|
|
|
|
result := make([]*DeviceTokenResponse, 0, len(tokens))
|
|
|
|
|
|
for _, token := range tokens {
|
|
|
|
|
|
result = append(result, DeviceTokenToResponse(token))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== SystemMessage 转换 ====================
|
|
|
|
|
|
|
|
|
|
|
|
// SystemMessageToResponse 将Message转换为SystemMessageResponse
|
|
|
|
|
|
func SystemMessageToResponse(msg *model.Message) *SystemMessageResponse {
|
|
|
|
|
|
if msg == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从 segments 中提取文本内容
|
|
|
|
|
|
content := ExtractTextContentFromModel(msg.Segments)
|
|
|
|
|
|
|
|
|
|
|
|
resp := &SystemMessageResponse{
|
|
|
|
|
|
ID: msg.ID,
|
|
|
|
|
|
SenderID: msg.SenderID,
|
|
|
|
|
|
ReceiverID: "", // 系统消息的接收者需要从上下文获取
|
|
|
|
|
|
Content: content,
|
|
|
|
|
|
Category: string(msg.Category),
|
|
|
|
|
|
SystemType: string(msg.SystemType),
|
|
|
|
|
|
CreatedAt: msg.CreatedAt,
|
|
|
|
|
|
}
|
|
|
|
|
|
if msg.ExtraData != nil {
|
|
|
|
|
|
resp.ExtraData = map[string]interface{}{
|
|
|
|
|
|
"actor_id": msg.ExtraData.ActorID,
|
|
|
|
|
|
"actor_name": msg.ExtraData.ActorName,
|
|
|
|
|
|
"avatar_url": msg.ExtraData.AvatarURL,
|
|
|
|
|
|
"target_id": msg.ExtraData.TargetID,
|
|
|
|
|
|
"target_type": msg.ExtraData.TargetType,
|
|
|
|
|
|
"action_url": msg.ExtraData.ActionURL,
|
|
|
|
|
|
"action_time": msg.ExtraData.ActionTime,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return resp
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SystemMessagesToResponse 将Message列表转换为SystemMessageResponse列表
|
|
|
|
|
|
func SystemMessagesToResponse(messages []*model.Message) []*SystemMessageResponse {
|
|
|
|
|
|
result := make([]*SystemMessageResponse, 0, len(messages))
|
|
|
|
|
|
for _, msg := range messages {
|
|
|
|
|
|
result = append(result, SystemMessageToResponse(msg))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SystemNotificationToResponse 将SystemNotification转换为SystemMessageResponse
|
|
|
|
|
|
func SystemNotificationToResponse(n *model.SystemNotification) *SystemMessageResponse {
|
|
|
|
|
|
if n == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
resp := &SystemMessageResponse{
|
|
|
|
|
|
ID: strconv.FormatInt(n.ID, 10),
|
|
|
|
|
|
SenderID: model.SystemSenderIDStr, // 系统发送者
|
|
|
|
|
|
ReceiverID: n.ReceiverID,
|
|
|
|
|
|
Content: n.Content,
|
|
|
|
|
|
Category: "notification",
|
|
|
|
|
|
SystemType: string(n.Type),
|
|
|
|
|
|
IsRead: n.IsRead,
|
|
|
|
|
|
CreatedAt: n.CreatedAt,
|
|
|
|
|
|
}
|
|
|
|
|
|
if n.ExtraData != nil {
|
|
|
|
|
|
resp.ExtraData = map[string]interface{}{
|
|
|
|
|
|
"actor_id": n.ExtraData.ActorID,
|
|
|
|
|
|
"actor_id_str": n.ExtraData.ActorIDStr,
|
|
|
|
|
|
"actor_name": n.ExtraData.ActorName,
|
|
|
|
|
|
"avatar_url": n.ExtraData.AvatarURL,
|
|
|
|
|
|
"target_id": n.ExtraData.TargetID,
|
|
|
|
|
|
"target_title": n.ExtraData.TargetTitle,
|
|
|
|
|
|
"target_type": n.ExtraData.TargetType,
|
|
|
|
|
|
"action_url": n.ExtraData.ActionURL,
|
|
|
|
|
|
"action_time": n.ExtraData.ActionTime,
|
|
|
|
|
|
"group_id": n.ExtraData.GroupID,
|
|
|
|
|
|
"group_name": n.ExtraData.GroupName,
|
|
|
|
|
|
"group_avatar": n.ExtraData.GroupAvatar,
|
|
|
|
|
|
"group_description": n.ExtraData.GroupDescription,
|
|
|
|
|
|
"flag": n.ExtraData.Flag,
|
|
|
|
|
|
"request_type": n.ExtraData.RequestType,
|
|
|
|
|
|
"request_status": n.ExtraData.RequestStatus,
|
|
|
|
|
|
"reason": n.ExtraData.Reason,
|
|
|
|
|
|
"target_user_id": n.ExtraData.TargetUserID,
|
|
|
|
|
|
"target_user_name": n.ExtraData.TargetUserName,
|
|
|
|
|
|
"target_user_avatar": n.ExtraData.TargetUserAvatar,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return resp
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SystemNotificationsToResponse 将SystemNotification列表转换为SystemMessageResponse列表
|
|
|
|
|
|
func SystemNotificationsToResponse(notifications []*model.SystemNotification) []*SystemMessageResponse {
|
|
|
|
|
|
result := make([]*SystemMessageResponse, 0, len(notifications))
|
|
|
|
|
|
for _, n := range notifications {
|
|
|
|
|
|
result = append(result, SystemNotificationToResponse(n))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== Group 转换 ====================
|
|
|
|
|
|
|
|
|
|
|
|
// GroupToResponse 将Group转换为GroupResponse
|
|
|
|
|
|
func GroupToResponse(group *model.Group) *GroupResponse {
|
|
|
|
|
|
if group == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &GroupResponse{
|
|
|
|
|
|
ID: group.ID,
|
|
|
|
|
|
Name: group.Name,
|
|
|
|
|
|
Avatar: group.Avatar,
|
|
|
|
|
|
Description: group.Description,
|
|
|
|
|
|
OwnerID: group.OwnerID,
|
|
|
|
|
|
MemberCount: group.MemberCount,
|
|
|
|
|
|
MaxMembers: group.MaxMembers,
|
|
|
|
|
|
JoinType: int(group.JoinType),
|
|
|
|
|
|
MuteAll: group.MuteAll,
|
|
|
|
|
|
CreatedAt: FormatTime(group.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GroupsToResponse 将Group列表转换为GroupResponse列表
|
|
|
|
|
|
func GroupsToResponse(groups []model.Group) []*GroupResponse {
|
|
|
|
|
|
result := make([]*GroupResponse, 0, len(groups))
|
|
|
|
|
|
for i := range groups {
|
|
|
|
|
|
result = append(result, GroupToResponse(&groups[i]))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GroupMemberToResponse 将GroupMember转换为GroupMemberResponse
|
|
|
|
|
|
func GroupMemberToResponse(member *model.GroupMember) *GroupMemberResponse {
|
|
|
|
|
|
if member == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &GroupMemberResponse{
|
|
|
|
|
|
ID: member.ID,
|
|
|
|
|
|
GroupID: member.GroupID,
|
|
|
|
|
|
UserID: member.UserID,
|
|
|
|
|
|
Role: member.Role,
|
|
|
|
|
|
Nickname: member.Nickname,
|
|
|
|
|
|
Muted: member.Muted,
|
|
|
|
|
|
JoinTime: FormatTime(member.JoinTime),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GroupMemberToResponseWithUser 将GroupMember转换为GroupMemberResponse(包含用户信息)
|
|
|
|
|
|
func GroupMemberToResponseWithUser(member *model.GroupMember, user *model.User) *GroupMemberResponse {
|
|
|
|
|
|
if member == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
resp := GroupMemberToResponse(member)
|
|
|
|
|
|
if user != nil {
|
|
|
|
|
|
resp.User = ConvertUserToResponse(user)
|
|
|
|
|
|
}
|
|
|
|
|
|
return resp
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GroupMembersToResponse 将GroupMember列表转换为GroupMemberResponse列表
|
|
|
|
|
|
func GroupMembersToResponse(members []model.GroupMember) []*GroupMemberResponse {
|
|
|
|
|
|
result := make([]*GroupMemberResponse, 0, len(members))
|
|
|
|
|
|
for i := range members {
|
|
|
|
|
|
result = append(result, GroupMemberToResponse(&members[i]))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GroupAnnouncementToResponse 将GroupAnnouncement转换为GroupAnnouncementResponse
|
|
|
|
|
|
func GroupAnnouncementToResponse(announcement *model.GroupAnnouncement) *GroupAnnouncementResponse {
|
|
|
|
|
|
if announcement == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &GroupAnnouncementResponse{
|
|
|
|
|
|
ID: announcement.ID,
|
|
|
|
|
|
GroupID: announcement.GroupID,
|
|
|
|
|
|
Content: announcement.Content,
|
|
|
|
|
|
AuthorID: announcement.AuthorID,
|
|
|
|
|
|
IsPinned: announcement.IsPinned,
|
|
|
|
|
|
CreatedAt: FormatTime(announcement.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GroupAnnouncementsToResponse 将GroupAnnouncement列表转换为GroupAnnouncementResponse列表
|
|
|
|
|
|
func GroupAnnouncementsToResponse(announcements []model.GroupAnnouncement) []*GroupAnnouncementResponse {
|
|
|
|
|
|
result := make([]*GroupAnnouncementResponse, 0, len(announcements))
|
|
|
|
|
|
for i := range announcements {
|
|
|
|
|
|
result = append(result, GroupAnnouncementToResponse(&announcements[i]))
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|