diff --git a/api/v1/plant/enter.go b/api/v1/plant/enter.go index b0efb12..d09ceca 100644 --- a/api/v1/plant/enter.go +++ b/api/v1/plant/enter.go @@ -4,8 +4,10 @@ import "sundynix-go/service" type ApiGroup struct { MyPlantApi + PostApi } var ( plantService = service.GroupApp.PlantServiceGroup.MyPlantService + postService = service.GroupApp.PlantServiceGroup.PostService ) diff --git a/api/v1/plant/my_plant.go b/api/v1/plant/my_plant.go index 5fd933b..c24c770 100644 --- a/api/v1/plant/my_plant.go +++ b/api/v1/plant/my_plant.go @@ -27,6 +27,7 @@ func (a *MyPlantApi) AddPlant(c *gin.Context) { err := c.ShouldBindJSON(&req) if err != nil { response.FailWithMsg("请求参数错误", c) + return } userId := auth.GetUserId(c) err = plantService.AddPlant(req, userId) diff --git a/api/v1/plant/post.go b/api/v1/plant/post.go new file mode 100644 index 0000000..9e7b0f4 --- /dev/null +++ b/api/v1/plant/post.go @@ -0,0 +1,119 @@ +package plant + +import ( + "sundynix-go/global" + "sundynix-go/model/commom/response" + plantReq "sundynix-go/model/plant/request" + "sundynix-go/utils/auth" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +type PostApi struct{} + +// PublishPost 发布帖子 +// @Tags 帖子 +// @Summary 发布帖子 +// @Security ApiKeyAuth +// @accept json +// @Produce application/json +// @Param data body plantReq.CreatePost true "发布帖子" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"发布成功"}" +// @Router /post/publish [post] +func (a *PostApi) PublishPost(c *gin.Context) { + var req plantReq.CreatePost + err := c.ShouldBindJSON(&req) + if err != nil { + response.FailWithMsg("请求参数错误", c) + return + } + userId := auth.GetUserId(c) + err = postService.PublishPost(req, userId) + if err != nil { + global.Logger.Error("发布帖子失败", zap.Error(err)) + response.FailWithMsg("发布失败", c) + return + } + response.OkWithMsg("发布成功", c) + +} + +// PostPage 帖子列表 +// @Tags 帖子 +// @Summary 帖子列表 +// @Security ApiKeyAuth +// @accept json +// @Produce application/json +// @Param data body plantReq.PostPage true "分页获取帖子列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /post/page [post] +func (a *PostApi) PostPage(c *gin.Context) { + var req plantReq.PostPage + err := c.ShouldBindJSON(&req) + if err != nil { + response.FailWithMsg("请求参数错误", c) + return + } + userId := auth.GetUserId(c) + posts, total, err := postService.PostPage(req, userId) + if err != nil { + global.Logger.Error("获取帖子列表失败", zap.Error(err)) + response.FailWithMsg("获取帖子列表失败", c) + return + } + response.OkWithData(response.PageResult{ + List: posts, + Total: total, + Page: req.Current, + PageSize: req.PageSize, + }, c) +} + +// LikePost 点赞帖子 +// @Tags 帖子 +// @Summary 点赞帖子 +// @Security ApiKeyAuth +// @Produce application/json +// @Param id query string true "帖子id" +// @Param type query string true "点赞类型 1 点赞 2 取消点赞" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"点赞成功"}" +// @Router /post/like [get] +func (a *PostApi) LikePost(c *gin.Context) { + postId := c.Query("id") + class := c.Query("type") + userId := auth.GetUserId(c) + err := postService.LikePost(userId, postId, class) + if err != nil { + global.Logger.Error("操作失败", zap.Error(err)) + response.FailWithMsg("操作失败", c) + return + } + response.OkWithMsg("操作成功", c) +} + +// CommentPost 评论帖子 +// @Tags 帖子 +// @Summary 评论帖子 +// @Security ApiKeyAuth +// @accept json +// @Produce application/json +// @Param data body plantReq.CreateComment true "评论帖子" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"评论成功"}" +// @Router /post/comment [post] +func (a *PostApi) CommentPost(c *gin.Context) { + var req plantReq.CreateComment + err := c.ShouldBindJSON(&req) + if err != nil { + response.FailWithMsg("请求参数错误", c) + return + } + userId := auth.GetUserId(c) + err = postService.CommentPost(req, userId) + if err != nil { + global.Logger.Error("评论失败", zap.Error(err)) + response.FailWithMsg("评论失败", c) + return + } + response.OkWithMsg("评论成功", c) +} diff --git a/initialize/gorm.go b/initialize/gorm.go index 1c1fd03..51af66f 100644 --- a/initialize/gorm.go +++ b/initialize/gorm.go @@ -39,10 +39,13 @@ func MigrateTable() { system.SysOperationRecord{}, system.Oss{}, - plant.MyPlant{}, //我的植物 - plant.CarePlan{}, //植物养护计划 - plant.CareTask{}, //植物养护任务 - plant.CareRecord{}, //植物养护记录 + plant.MyPlant{}, //我的植物 + plant.CarePlan{}, //植物养护计划 + plant.CareTask{}, //植物养护任务 + plant.CareRecord{}, //植物养护记录 + plant.Post{}, //帖子 + plant.PostLike{}, //帖子点赞 + plant.PostComment{}, //帖子评论 ) if err != nil { diff --git a/initialize/router.go b/initialize/router.go index 38e8a2e..dddb275 100644 --- a/initialize/router.go +++ b/initialize/router.go @@ -49,7 +49,8 @@ func Routers() { { //需要鉴权的路由 - plantGroup.InitPlantRouter(NeedAuthGroup) + plantGroup.InitPlantRouter(NeedAuthGroup) // 植物相关 + plantGroup.InitPostRouter(NeedAuthGroup) // 帖子相关 } diff --git a/model/plant/community_post.go b/model/plant/community_post.go new file mode 100644 index 0000000..5fef4b6 --- /dev/null +++ b/model/plant/community_post.go @@ -0,0 +1,27 @@ +package plant + +import ( + "sundynix-go/global" + "sundynix-go/model/system" +) + +// Post 帖子 +type Post struct { + global.BaseModel + UserId string `json:"userId" form:"userId" gorm:"column:user_id;size:50;comment:用户id"` + Title string `json:"title" form:"title" gorm:"column:title;size:100;comment:帖子标题"` + Content string `json:"content" form:"content" gorm:"column:content;size:500;comment:帖子内容"` + ViewCount int `json:"viewCount" form:"viewCount" gorm:"default:0;column:view_count;comment:浏览次数"` + CommentCount int `json:"commentCount" form:"commentCount" gorm:"default:0;column:comment_count;comment:评论次数"` + LikeCount int `json:"likeCount" form:"likeCount" gorm:"default:0;column:like_count;comment:点赞次数"` + Location string `json:"location" form:"location" gorm:"column:location;size:100;comment:位置"` + HasReviewed int `json:"hasReviewed" form:"hasReviewed" gorm:"column:has_reviewed;comment:是否审核通过"` + HasLiked int `json:"hasLiked" form:"hasLiked" gorm:"-"` + //图片 + ImgList []*system.Oss `json:"imgList" form:"imgList" gorm:"many2many:post_oss;comment:图片列表"` + //评论 + CommentList []*PostComment `json:"commentList" form:"commentList" gorm:"foreignKey:PostId;comment:评论列表"` + //点赞 + LikeList []*PostLike `json:"likeList" form:"likeList" gorm:"foreignKey:PostId;comment:点赞列表"` + Publisher *system.User `json:"publisher" form:"publisher" gorm:"foreignKey:UserId;comment:用户"` +} diff --git a/model/plant/community_post_comment.go b/model/plant/community_post_comment.go new file mode 100644 index 0000000..49e4433 --- /dev/null +++ b/model/plant/community_post_comment.go @@ -0,0 +1,16 @@ +package plant + +import ( + "sundynix-go/global" + "sundynix-go/model/system" +) + +type PostComment struct { + global.BaseModel + RootId string `json:"rootId" form:"rootId" gorm:"column:root_id;size:50;default:'0';comment:根评论id"` + ParentId string `json:"parentId" form:"parentId" gorm:"column:parent_id;size:50;comment:父级评论id"` + PostId string `json:"postId" form:"postId" gorm:"index;column:post_id;size:50;comment:帖子id"` + UserId string `json:"userId" form:"userId" gorm:"index;column:user_id;size:50;comment:用户id"` + Content string `json:"content" form:"content" gorm:"column:content;size:500;comment:评论内容"` + Commentator *system.User `json:"commentator" form:"commentator" gorm:"foreignKey:UserId;comment:评论者"` +} diff --git a/model/plant/community_post_like.go b/model/plant/community_post_like.go new file mode 100644 index 0000000..1e239fb --- /dev/null +++ b/model/plant/community_post_like.go @@ -0,0 +1,13 @@ +package plant + +import ( + "sundynix-go/global" + "sundynix-go/model/system" +) + +type PostLike struct { + global.BaseModel + PostId string `json:"postId" form:"postId" gorm:"index;column:post_id;size:50;comment:帖子id"` + UserId string `json:"userId" form:"userId" gorm:"index;column:user_id;size:50;comment:用户id"` + Liker *system.User `json:"liker" form:"liker" gorm:"foreignKey:UserId;comment:点赞者"` +} diff --git a/model/plant/request/post.go b/model/plant/request/post.go new file mode 100644 index 0000000..26a8b44 --- /dev/null +++ b/model/plant/request/post.go @@ -0,0 +1,30 @@ +package request + +import common "sundynix-go/model/commom/request" + +type CreatePost struct { + Title string `json:"title"` // 标题 必须 + Content string `json:"content"` // 内容 + Location string `json:"location"` //位置 + OssIds []string `json:"ossIds"` // 图片id[] +} + +// UpdatePost 修改帖子 +type UpdatePost struct { + Id string `json:"id" binding:"required"` + Title string `json:"title"` // 标题 + Content string `json:"content"` // 内容 +} + +// PostPage 帖子列表 +type PostPage struct { + common.PageInfo + Title string `json:"title"` // 标题 + HasReviewed int `json:"hasReviewed"` //是否审核通过 +} + +// CreateComment 创建评论 +type CreateComment struct { + PostId string `json:"postId" binding:"required"` // 帖子id + Content string `json:"content" binding:"required"` // 评论内容 +} diff --git a/router/enter.go b/router/enter.go index c22d323..91f8403 100644 --- a/router/enter.go +++ b/router/enter.go @@ -10,5 +10,5 @@ var GroupApp = new(Group) // Group 路由组 type Group struct { System system.SysRouterGroup - Plant plant.MyPlantRouter + Plant plant.RouterGroup } diff --git a/router/plant/enter.go b/router/plant/enter.go index 9b63d75..67add1d 100644 --- a/router/plant/enter.go +++ b/router/plant/enter.go @@ -4,9 +4,11 @@ import v1 "sundynix-go/api/v1" type RouterGroup struct { MyPlantRouter + PostRouter } // 初始化路由 var ( myPlantApi = v1.ApiGroupApp.PlantApiGroup.MyPlantApi + postApi = v1.ApiGroupApp.PlantApiGroup.PostApi ) diff --git a/router/plant/post_router.go b/router/plant/post_router.go new file mode 100644 index 0000000..8f916f3 --- /dev/null +++ b/router/plant/post_router.go @@ -0,0 +1,17 @@ +package plant + +import "github.com/gin-gonic/gin" + +type PostRouter struct{} + +func (p *PostRouter) InitPostRouter(Router *gin.RouterGroup) { + postRouter := Router.Group("post") + { + postRouter.POST("publish", postApi.PublishPost) // 发布帖子 + postRouter.POST("page", postApi.PostPage) // 帖子列表 + postRouter.GET("like", postApi.LikePost) // 点赞或者取消点赞 + postRouter.POST("comment", postApi.CommentPost) // 评论 + //postRouter.POST("deleteComment", postApi.delementComment) // 取消评论 + + } +} diff --git a/service/plant/enter.go b/service/plant/enter.go index e03779c..e1af4a6 100644 --- a/service/plant/enter.go +++ b/service/plant/enter.go @@ -2,4 +2,5 @@ package plant type ServiceGroup struct { MyPlantService + PostService } diff --git a/service/plant/post.go b/service/plant/post.go new file mode 100644 index 0000000..55da30a --- /dev/null +++ b/service/plant/post.go @@ -0,0 +1,182 @@ +package plant + +import ( + "sundynix-go/global" + "sundynix-go/model/plant" + plantReq "sundynix-go/model/plant/request" + "sundynix-go/model/system" + + "gorm.io/gorm" +) + +type PostService struct{} + +var PostServiceApp = new(PostService) + +// PublishPost 发表帖子 +func (s *PostService) PublishPost(req plantReq.CreatePost, userId string) error { + return global.DB.Transaction(func(tx *gorm.DB) error { + //1.验证oss是否存在 + var ossList []*system.Oss + err := tx.Where("id in ?", req.OssIds).Find(&ossList).Error + if err != nil { + return err + } + //2.保存帖子 + post := plant.Post{ + Title: req.Title, + UserId: userId, + Content: req.Content, + Location: req.Location, + } + err = tx.Create(&post).Error + if err != nil { + return err + } + //3.处理图片关系 + if len(ossList) > 0 { + var relations []map[string]interface{} + for _, oss := range ossList { + relations = append(relations, map[string]interface{}{ + "post_id": post.Id, + "oss_id": oss.Id, + }) + } + err = tx.Table("sundynix_post_oss").Create(relations).Error + if err != nil { + return err + } + } + return nil + }) +} + +// PostPage 帖子列表 +func (s *PostService) PostPage(req plantReq.PostPage, userId string) (list interface{}, total int64, err error) { + limit := req.PageSize + offset := req.PageSize * (req.Current - 1) + db := global.DB.Model(&plant.Post{}). + Preload("ImgList", func(db *gorm.DB) *gorm.DB { + return db.Order("created_at desc") + }). + Preload("Publisher", func(db *gorm.DB) *gorm.DB { + return db.Preload("Avatar") + }). + Preload("LikeList", func(db *gorm.DB) *gorm.DB { + return db.Preload("Liker", func(db *gorm.DB) *gorm.DB { + return db.Preload("Avatar") + }) + }). + Preload("CommentList", func(db *gorm.DB) *gorm.DB { + return db.Preload("Commentator", func(db *gorm.DB) *gorm.DB { + return db.Preload("Avatar") + }) + }) + var posts []plant.Post + if req.Title != "" { + db = db.Where("title like ?", "%"+req.Title+"%") + } + //todo 审核帖子 + err = db.Count(&total).Error + if err != nil { + return + } + err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&posts).Error + // 优化 N+1 查询 + var postIds []string + for _, v := range posts { + postIds = append(postIds, v.Id) + } + // 批量查询当前用户点赞的记录 + var postLikeList []*plant.PostLike + err = global.DB.Where("user_id = ? and post_id in ?", userId, postIds).Find(&postLikeList).Error + if err != nil { + return + } + // 构建id映射 + likesMap := make(map[string]bool) + for _, v := range postLikeList { + likesMap[v.PostId] = true + } + // 是否点赞 + for i := range posts { + if likesMap[posts[i].Id] { + posts[i].HasLiked = 1 + } else { + posts[i].HasLiked = 0 + } + + } + + return posts, total, err +} + +// LikePost 点赞帖或取消赞 +func (s *PostService) LikePost(userId, postId, class string) error { + // class = 1点赞 + if class == "1" { + return global.DB.Transaction(func(tx *gorm.DB) error { + var post plant.Post + err := tx.Where("id = ?", postId).First(&post).Error + if err != nil { + return err + } + //1.更新点赞数 + err = tx.Model(&post).Update("like_count", post.LikeCount+1).Error + if err != nil { + return err + } + //2.添加点赞记录 + like := plant.PostLike{ + UserId: userId, + PostId: postId, + } + return tx.Create(&like).Error + }) + } else if class == "2" { + return global.DB.Transaction(func(tx *gorm.DB) error { + var like plant.PostLike + err := tx.Where("post_id = ? and user_id = ?", postId, userId).First(&like).Error + if err != nil { + return err + } + //1.更新点赞数 + var post plant.Post + err = tx.Where("id = ?", postId).First(&post).Error + if err != nil { + return err + } + err = tx.Model(&post).Update("like_count", post.LikeCount-1).Error + if err != nil { + return err + } + //2.删除点赞记录 + return tx.Unscoped().Delete(&like).Error + }) + } + return nil +} + +// CommentPost 评论帖子 +func (s *PostService) CommentPost(req plantReq.CreateComment, userId string) error { + return global.DB.Transaction(func(tx *gorm.DB) error { + //1.为帖子评论数量+1 + var post plant.Post + err := global.DB.Where("id = ?", req.PostId).First(&post).Error + if err != nil { + return err + } + //1.更新评论数 + err = tx.Model(&post).Update("comment_count", post.CommentCount+1).Error + if err != nil { + return err + } + //2.添加评论 + comment := plant.PostComment{ + PostId: req.PostId, + UserId: userId, + Content: req.Content, + } + return tx.Create(&comment).Error + }) +}