package service import ( "gorm.io/datatypes" "gorm.io/gorm" "github.com/sundynix/pets-be/internal/model" ) // tabTag 将 feed tab 映射为标签过滤(空表示不过滤) func tabTag(tab string) string { switch tab { case "新手求助": return "求助" case "晒宠": return "晒宠" case "经验": return "经验" default: // 推荐 / 关注 return "" } } // ListPosts 帖子分页列表 func (s *Service) ListPosts(tab string, offset, limit int) ([]model.Post, int64, error) { q := s.db.Model(&model.Post{}).Where("status = ?", model.PostPublished) if tag := tabTag(tab); tag != "" { q = q.Where("JSON_CONTAINS(tags, ?)", `"`+tag+`"`) } var total int64 if err := q.Count(&total).Error; err != nil { return nil, 0, err } var posts []model.Post if err := q.Order("id desc").Offset(offset).Limit(limit).Find(&posts).Error; err != nil { return nil, 0, err } return posts, total, nil } // GetPost 帖子详情 func (s *Service) GetPost(postID uint) (*model.Post, error) { var p model.Post if err := s.db.First(&p, postID).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, ErrNotFound } return nil, err } return &p, nil } // PostInput 发帖入参 type PostInput struct { PetID *uint Identity string Content string Tags datatypes.JSON Images datatypes.JSON } // CreatePost 发帖 func (s *Service) CreatePost(userID uint, in PostInput) (*model.Post, error) { authorName := "匿名宠友" authorEmoji := "🐾" switch in.Identity { case "official": authorName = "毛孩子计划官方" case "petName": if in.PetID != nil { var pet model.Pet if err := s.db.First(&pet, *in.PetID).Error; err == nil { authorName = pet.Name + "的铲屎官" authorEmoji = pet.Emoji } } } p := model.Post{ UserID: userID, PetID: in.PetID, AuthorName: authorName, AuthorEmoji: authorEmoji, Identity: in.Identity, Content: in.Content, Tags: in.Tags, Images: in.Images, Status: model.PostPublished, } if err := s.db.Create(&p).Error; err != nil { return nil, err } return &p, nil } // LikePost 点赞(幂等:已赞则不重复计数) func (s *Service) LikePost(userID, postID uint) (int, error) { if _, err := s.GetPost(postID); err != nil { return 0, err } err := s.db.Transaction(func(tx *gorm.DB) error { like := model.PostLike{PostID: postID, UserID: userID} res := tx.Where("post_id = ? AND user_id = ?", postID, userID).FirstOrCreate(&like) if res.Error != nil { return res.Error } if res.RowsAffected == 1 { // 新建才计数 return tx.Model(&model.Post{}).Where("id = ?", postID). UpdateColumn("like_count", gorm.Expr("like_count + 1")).Error } return nil }) if err != nil { return 0, err } return s.postLikeCount(postID) } // UnlikePost 取消点赞 func (s *Service) UnlikePost(userID, postID uint) (int, error) { if _, err := s.GetPost(postID); err != nil { return 0, err } err := s.db.Transaction(func(tx *gorm.DB) error { res := tx.Where("post_id = ? AND user_id = ?", postID, userID).Delete(&model.PostLike{}) if res.Error != nil { return res.Error } if res.RowsAffected == 1 { return tx.Model(&model.Post{}).Where("id = ? AND like_count > 0", postID). UpdateColumn("like_count", gorm.Expr("like_count - 1")).Error } return nil }) if err != nil { return 0, err } return s.postLikeCount(postID) } func (s *Service) postLikeCount(postID uint) (int, error) { var p model.Post if err := s.db.Select("like_count").First(&p, postID).Error; err != nil { return 0, err } return p.LikeCount, nil } // ListComments 评论分页 func (s *Service) ListComments(postID uint, offset, limit int) ([]model.Comment, int64, error) { q := s.db.Model(&model.Comment{}).Where("post_id = ? AND status = ?", postID, "published") var total int64 if err := q.Count(&total).Error; err != nil { return nil, 0, err } var comments []model.Comment if err := q.Order("id desc").Offset(offset).Limit(limit).Find(&comments).Error; err != nil { return nil, 0, err } return comments, total, nil } // CreateComment 评论 func (s *Service) CreateComment(userID, postID uint, content string) (*model.Comment, error) { if _, err := s.GetPost(postID); err != nil { return nil, err } var user model.User name := "宠友" if err := s.db.First(&user, userID).Error; err == nil && user.Nickname != "" { name = user.Nickname } comment := model.Comment{PostID: postID, UserID: userID, AuthorName: name, Content: content, Status: "published"} if err := s.db.Transaction(func(tx *gorm.DB) error { if err := tx.Create(&comment).Error; err != nil { return err } return tx.Model(&model.Post{}).Where("id = ?", postID). UpdateColumn("comment_count", gorm.Expr("comment_count + 1")).Error }); err != nil { return nil, err } return &comment, nil }