Files
backend/internal/model/post.go
lan ee78071d4d
All checks were successful
Build Backend / build (push) Successful in 3m2s
Build Backend / build-docker (push) Successful in 2m44s
refactor: improve system stability, performance, and code structure
This commit introduces several architectural improvements and optimizations across the codebase:

- **Performance & Reliability**:
  - Implemented Redis pipelining in `ConversationCache.CacheMessage` to reduce network round-trips.
  - Added a circuit breaker to the JPush client to prevent cascading failures.
  - Introduced batch deletion and batch member addition capabilities in repositories.
  - Added message idempotency support using `client_msg_id` and a Redis-based cache.
  - Optimized WebSocket handling with connection limits (total and per-user) and improved error logging.

- **Code Refactoring**:
  - Refactored `Router` to use a `RouterDeps` struct, simplifying the constructor and improving maintainability.
  - Unified model ID generation logic using new `id_helper.go` (supporting UUID and Snowflake).
  - Standardized JSON serialization/deserialization in models using `json_helper.go`.
  - Refactored DTO conversion logic, specifically for `UserResponse` (using functional options) and `Report` responses.
  - Removed redundant/deprecated DTOs like `PostDetailResponse` and `TradeItemDetailResponse`.

- **Cache Improvements**:
  - Enhanced `LayeredCache` with `SetRaw` to avoid double-encoding when promoting values from Redis to local cache.
  - Added `DeleteBatch` support to the cache interface.

- **Other Changes**:
  - Cleaned up `config.go` by removing redundant default values and explicit environment variable overrides.
  - Improved WebSocket registration flow to handle connection limits gracefully.
2026-05-04 13:07:03 +08:00

101 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"time"
"gorm.io/gorm"
)
// PostStatus 帖子状态
type PostStatus string
const (
PostStatusDraft PostStatus = "draft"
PostStatusPending PostStatus = "pending" // 待审核
PostStatusPublished PostStatus = "published"
PostStatusRejected PostStatus = "rejected"
PostStatusDeleted PostStatus = "deleted"
)
// Post 帖子实体
type Post struct {
ID string `json:"id" gorm:"type:varchar(36);primaryKey"`
UserID string `json:"user_id" gorm:"type:varchar(36);index;index:idx_posts_user_status_created,priority:1;not null"`
ChannelID *string `json:"channel_id,omitempty" gorm:"type:varchar(36);index"`
Title string `json:"title" gorm:"type:varchar(200);not null"`
Content string `json:"content" gorm:"type:text;not null"`
Segments MessageSegments `json:"segments,omitempty" gorm:"type:text"`
// 关联
// User 需要参与缓存序列化;否则列表命中缓存后会丢失作者信息,前端退化为“匿名用户”
User *User `json:"user,omitempty" gorm:"foreignKey:UserID"`
Images []PostImage `json:"images" gorm:"foreignKey:PostID"`
// 审核状态
Status PostStatus `json:"status" gorm:"type:varchar(20);default:published;index:idx_posts_status_created,priority:1;index:idx_posts_user_status_created,priority:2"`
ReviewedAt *time.Time `json:"reviewed_at" gorm:"type:timestamp"`
ReviewedBy string `json:"reviewed_by" gorm:"type:varchar(50)"`
RejectReason string `json:"reject_reason" gorm:"type:varchar(500)"`
// 统计
LikesCount int `json:"likes_count" gorm:"column:likes_count;default:0"`
CommentsCount int `json:"comments_count" gorm:"column:comments_count;default:0"`
FavoritesCount int `json:"favorites_count" gorm:"column:favorites_count;default:0"`
SharesCount int `json:"shares_count" gorm:"column:shares_count;default:0"`
ViewsCount int `json:"views_count" gorm:"column:views_count;default:0"`
// 置顶/锁定
IsPinned bool `json:"is_pinned" gorm:"default:false"`
IsFeatured bool `json:"is_featured" gorm:"default:false"` // 加精
IsLocked bool `json:"is_locked" gorm:"default:false"`
IsDeleted bool `json:"-" gorm:"default:false"`
// 投票
IsVote bool `json:"is_vote" gorm:"column:is_vote;default:false"`
// 软删除
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
// 时间戳
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime;index:idx_posts_status_created,priority:2,sort:desc;index:idx_posts_user_status_created,priority:3,sort:desc"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime:false"`
// ContentEditedAt 仅在实际修改标题/正文/图片时更新,供前端展示「已编辑」;与统计类更新解耦
ContentEditedAt *time.Time `json:"content_edited_at,omitempty" gorm:"column:content_edited_at"`
}
// BeforeCreate 创建前生成UUID
func (p *Post) BeforeCreate(tx *gorm.DB) error {
SetUUIDIfEmpty(&p.ID)
return nil
}
func (Post) TableName() string {
return "posts"
}
// PostImage 帖子图片
type PostImage struct {
ID string `json:"id" gorm:"type:varchar(36);primaryKey"`
PostID string `json:"post_id" gorm:"type:varchar(36);not null;index:idx_post_images_post_sort,priority:1"`
URL string `json:"url" gorm:"type:text;not null"`
ThumbnailURL string `json:"thumbnail_url" gorm:"type:text"`
PreviewURL string `json:"preview_url" gorm:"type:text"` // 列表/网格预览图最大300px
PreviewURLLarge string `json:"preview_url_large" gorm:"type:text"` // 详情页预览图最大800px
Width int `json:"width" gorm:"default:0"`
Height int `json:"height" gorm:"default:0"`
Size int64 `json:"size" gorm:"default:0"` // 文件大小(字节)
MimeType string `json:"mime_type" gorm:"type:varchar(50)"`
SortOrder int `json:"sort_order" gorm:"default:0;index:idx_post_images_post_sort,priority:2"`
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
}
// BeforeCreate 创建前生成UUID
func (pi *PostImage) BeforeCreate(tx *gorm.DB) error {
SetUUIDIfEmpty(&pi.ID)
return nil
}
func (PostImage) TableName() string {
return "post_images"
}