feat(api): add message segments support for posts and comments
All checks were successful
Build Backend / build (push) Successful in 19m52s
Build Backend / build-docker (push) Successful in 1m29s

Add rich message segment support enabling structured content (text, images, votes, mentions) in posts and comments. Includes segments field in models, DTOs, handlers, and services. Also adds @mention notification processing and migrates vote data to embedded segments.
This commit is contained in:
lafay
2026-04-23 22:29:34 +08:00
parent 15e7c99353
commit 05c7f8a5eb
14 changed files with 364 additions and 154 deletions

View File

@@ -1,8 +1,8 @@
package dto
package dto
import (
"with_you/internal/model"
"time"
"with_you/internal/model"
)
// ==================== User DTOs ====================
@@ -143,54 +143,56 @@ type PostImageResponse struct {
// PostResponse 帖子响应(列表用)
type PostResponse struct {
ID string `json:"id"`
UserID string `json:"user_id"`
ChannelID *string `json:"channel_id,omitempty"`
Title string `json:"title"`
Content string `json:"content"`
Images []PostImageResponse `json:"images"`
Status string `json:"status,omitempty"`
LikesCount int `json:"likes_count"`
CommentsCount int `json:"comments_count"`
FavoritesCount int `json:"favorites_count"`
SharesCount int `json:"shares_count"`
ViewsCount int `json:"views_count"`
IsPinned bool `json:"is_pinned"`
IsLocked bool `json:"is_locked"`
IsVote bool `json:"is_vote"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
ContentEditedAt string `json:"content_edited_at,omitempty"`
Author *UserResponse `json:"author"`
IsLiked bool `json:"is_liked"`
IsFavorited bool `json:"is_favorited"`
Channel *PostChannelBrief `json:"channel,omitempty"`
ID string `json:"id"`
UserID string `json:"user_id"`
ChannelID *string `json:"channel_id,omitempty"`
Title string `json:"title"`
Content string `json:"content"`
Segments model.MessageSegments `json:"segments,omitempty"`
Images []PostImageResponse `json:"images"`
Status string `json:"status,omitempty"`
LikesCount int `json:"likes_count"`
CommentsCount int `json:"comments_count"`
FavoritesCount int `json:"favorites_count"`
SharesCount int `json:"shares_count"`
ViewsCount int `json:"views_count"`
IsPinned bool `json:"is_pinned"`
IsLocked bool `json:"is_locked"`
IsVote bool `json:"is_vote"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
ContentEditedAt string `json:"content_edited_at,omitempty"`
Author *UserResponse `json:"author"`
IsLiked bool `json:"is_liked"`
IsFavorited bool `json:"is_favorited"`
Channel *PostChannelBrief `json:"channel,omitempty"`
}
// PostDetailResponse 帖子详情响应
type PostDetailResponse struct {
ID string `json:"id"`
UserID string `json:"user_id"`
ChannelID *string `json:"channel_id,omitempty"`
Title string `json:"title"`
Content string `json:"content"`
Images []PostImageResponse `json:"images"`
Status string `json:"status"`
LikesCount int `json:"likes_count"`
CommentsCount int `json:"comments_count"`
FavoritesCount int `json:"favorites_count"`
SharesCount int `json:"shares_count"`
ViewsCount int `json:"views_count"`
IsPinned bool `json:"is_pinned"`
IsLocked bool `json:"is_locked"`
IsVote bool `json:"is_vote"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
ContentEditedAt string `json:"content_edited_at,omitempty"`
Author *UserResponse `json:"author"`
IsLiked bool `json:"is_liked"`
IsFavorited bool `json:"is_favorited"`
Channel *PostChannelBrief `json:"channel,omitempty"`
ID string `json:"id"`
UserID string `json:"user_id"`
ChannelID *string `json:"channel_id,omitempty"`
Title string `json:"title"`
Content string `json:"content"`
Segments model.MessageSegments `json:"segments,omitempty"`
Images []PostImageResponse `json:"images"`
Status string `json:"status"`
LikesCount int `json:"likes_count"`
CommentsCount int `json:"comments_count"`
FavoritesCount int `json:"favorites_count"`
SharesCount int `json:"shares_count"`
ViewsCount int `json:"views_count"`
IsPinned bool `json:"is_pinned"`
IsLocked bool `json:"is_locked"`
IsVote bool `json:"is_vote"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
ContentEditedAt string `json:"content_edited_at,omitempty"`
Author *UserResponse `json:"author"`
IsLiked bool `json:"is_liked"`
IsFavorited bool `json:"is_favorited"`
Channel *PostChannelBrief `json:"channel,omitempty"`
}
// ==================== Comment DTOs ====================
@@ -209,6 +211,7 @@ type CommentResponse struct {
ParentID *string `json:"parent_id"`
RootID *string `json:"root_id"`
Content string `json:"content"`
Segments model.MessageSegments `json:"segments,omitempty"`
Images []CommentImageResponse `json:"images"`
LikesCount int `json:"likes_count"`
RepliesCount int `json:"replies_count"`
@@ -248,6 +251,7 @@ const (
SegmentTypeReply SegmentType = "reply"
SegmentTypeFace SegmentType = "face"
SegmentTypeLink SegmentType = "link"
SegmentTypeVote SegmentType = "vote"
)
// TextSegmentData 文本数据
@@ -315,6 +319,19 @@ type LinkSegmentData struct {
Image string `json:"image,omitempty"`
}
// VoteOptionData 投票选项数据
type VoteOptionData struct {
ID string `json:"id"`
Content string `json:"content"`
}
// VoteSegmentData 投票Segment数据
type VoteSegmentData struct {
Options []VoteOptionData `json:"options"`
MaxChoices int `json:"max_choices,omitempty"`
IsMultiChoice bool `json:"is_multi_choice,omitempty"`
}
// ==================== Message DTOs ====================
// MessageResponse 消息响应
@@ -887,7 +904,16 @@ type CreateVotePostRequest struct {
Content string `json:"content" binding:"max=2000"`
ChannelID *string `json:"channel_id,omitempty"`
Images []string `json:"images"`
VoteOptions []string `json:"vote_options" binding:"required,min=2,max=10"` // 投票选项至少2个最多10个
VoteOptions []string `json:"vote_options" binding:"required,min=2,max=10"`
}
// CreatePostWithSegmentsRequest 创建帖子请求(含 segments
type CreatePostWithSegmentsRequest struct {
Title string `json:"title" binding:"required,max=200"`
Content string `json:"content"`
Segments model.MessageSegments `json:"segments"`
Images []string `json:"images"`
ChannelID *string `json:"channel_id,omitempty"`
}
// VoteOptionDTO 投票选项DTO
@@ -943,29 +969,30 @@ type AdminPostListResponse struct {
// AdminPostDetailResponse 管理端帖子详情响应
type AdminPostDetailResponse struct {
ID string `json:"id"`
UserID string `json:"user_id"`
ChannelID *string `json:"channel_id,omitempty"`
Title string `json:"title"`
Content string `json:"content"`
Images []PostImageResponse `json:"images"`
Status string `json:"status"`
LikesCount int `json:"likes_count,omitzero"`
CommentsCount int `json:"comments_count,omitzero"`
FavoritesCount int `json:"favorites_count,omitzero"`
SharesCount int `json:"shares_count,omitzero"`
ViewsCount int `json:"views_count,omitzero"`
IsPinned bool `json:"is_pinned"`
IsFeatured bool `json:"is_featured"`
IsLocked bool `json:"is_locked"`
IsVote bool `json:"is_vote"`
RejectReason string `json:"reject_reason,omitempty"`
ReviewedAt string `json:"reviewed_at,omitempty"`
ReviewedBy string `json:"reviewed_by,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
ContentEditedAt string `json:"content_edited_at,omitempty"`
Author *UserResponse `json:"author"`
ID string `json:"id"`
UserID string `json:"user_id"`
ChannelID *string `json:"channel_id,omitempty"`
Title string `json:"title"`
Content string `json:"content"`
Segments model.MessageSegments `json:"segments,omitempty"`
Images []PostImageResponse `json:"images"`
Status string `json:"status"`
LikesCount int `json:"likes_count,omitzero"`
CommentsCount int `json:"comments_count,omitzero"`
FavoritesCount int `json:"favorites_count,omitzero"`
SharesCount int `json:"shares_count,omitzero"`
ViewsCount int `json:"views_count,omitzero"`
IsPinned bool `json:"is_pinned"`
IsFeatured bool `json:"is_featured"`
IsLocked bool `json:"is_locked"`
IsVote bool `json:"is_vote"`
RejectReason string `json:"reject_reason,omitempty"`
ReviewedAt string `json:"reviewed_at,omitempty"`
ReviewedBy string `json:"reviewed_by,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
ContentEditedAt string `json:"content_edited_at,omitempty"`
Author *UserResponse `json:"author"`
}
// AdminModeratePostRequest 审核帖子请求