package dto import ( "carrot_bbs/internal/model" "context" "encoding/json" ) // ==================== 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, 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), ContentEditedAt: FormatTimePointer(post.ContentEditedAt), 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), ContentEditedAt: FormatTimePointer(post.ContentEditedAt), 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 } // 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) } // ==================== 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 }