diff --git a/model/app/teacher_vip.go b/model/app/teacher_vip.go index f11fc69..fe05f8f 100644 --- a/model/app/teacher_vip.go +++ b/model/app/teacher_vip.go @@ -10,6 +10,7 @@ type TeacherVip struct { Avatar string `json:"avatar" gorm:"comment:讲师头像"` Price float64 `json:"price" gorm:"comment:VIP价格(单位为分)"` Desc string `json:"desc" gorm:"comment:VIP描述;type:longtext"` + CategoryId uint `json:"category_id" gorm:"comment:分类ID;"` } func (TeacherVip) TableName() string { diff --git a/model/article/vo/article.go b/model/article/vo/article.go index 0cd2fba..3a27644 100644 --- a/model/article/vo/article.go +++ b/model/article/vo/article.go @@ -31,6 +31,7 @@ type ArticleVo struct { TeacherAvatar string `json:"teacherAvatar" gorm:"comment:讲师头像"` IsFree int `json:"isFree" gorm:"comment:是否免费;default:0"` // 是否免费 0-否 1-是 IsBuy int `json:"isBuy" gorm:"comment:是否购买;default:0"` // 是否购买 0-否 1-是 + CategoryId uint `json:"categoryId" gorm:"comment:分类ID"` } type ArticleTeacherVo struct { diff --git a/router/vip/vip.go b/router/vip/vip.go index bb8f3d8..6a5af35 100644 --- a/router/vip/vip.go +++ b/router/vip/vip.go @@ -10,7 +10,7 @@ type VipRouter struct{} // InitVipRouter 初始化会员路由 func (s *VipRouter) InitVipRouter(Router *gin.RouterGroup, PublicRouter *gin.RouterGroup) { vipRouter := Router.Group("vip").Use(middleware.OperationRecord()) - vipNoAuthRouter := PublicRouter.Group("vip").Use(middleware.OperationRecord()) + vipNoAuthRouter := PublicRouter.Group("vip") { vipRouter.POST("", vipApi.Create) // 获取用户列表 vipRouter.DELETE("", vipApi.Delete) // 更新用户余额 diff --git a/service/app/user.go b/service/app/user.go index 19054bb..ec35d54 100644 --- a/service/app/user.go +++ b/service/app/user.go @@ -250,14 +250,34 @@ func (u *AppUserService) GetTeacherList(p common.PageInfo) (list []vo.TeacherInf return nil, 0, err } - // 获取每个教师的粉丝数 - for i := range list { - followCount, err := u.GetTeacherFansCount(list[i].ID) + // 批量查询所有教师的粉丝数 + var teacherIDs []uint + for _, t := range list { + teacherIDs = append(teacherIDs, t.ID) + } + type FansCount struct { + TeacherId uint + Count int64 + } + var fansCounts []FansCount + if len(teacherIDs) > 0 { + err = global.GVA_DB.Model(&app.Follow{}). + Select("teacher_id, count(*) as count"). + Where("teacher_id IN ?", teacherIDs). + Group("teacher_id"). + Scan(&fansCounts).Error if err != nil { - global.GVA_LOG.Error("查询教师粉丝数失败", zap.Error(err)) + global.GVA_LOG.Error("批量查询教师粉丝数失败", zap.Error(err)) return nil, 0, err } - list[i].Follow = followCount + } + // 映射粉丝数 + fansMap := make(map[uint]int64) + for _, fc := range fansCounts { + fansMap[fc.TeacherId] = fc.Count + } + for i := range list { + list[i].Follow = fansMap[list[i].ID] } return diff --git a/service/article/article.go b/service/article/article.go index 55e7d7b..9f1a32a 100644 --- a/service/article/article.go +++ b/service/article/article.go @@ -64,11 +64,8 @@ func (s ArticleService) APPGetArticleList(pageInfo request.GetList) (list []vo.A offset := pageInfo.PageSize * (pageInfo.Page - 1) db := global.GVA_DB.Model(&article.Article{}).Where("status = 1") // 只查询已发布的文章 - err = db.Count(&total).Error - if err != nil { - return - } + // 优化:先构建所有筛选条件再查询总数和数据 if pageInfo.Title != "" { db = db.Where("title LIKE ?", "%"+pageInfo.Title+"%") } @@ -78,14 +75,41 @@ func (s ArticleService) APPGetArticleList(pageInfo request.GetList) (list []vo.A if pageInfo.TeacherId != 0 { db = db.Where("teacher_id = ?", pageInfo.TeacherId) } - if pageInfo.Keyword != "" { db = db.Where("title LIKE ? OR article.desc LIKE ? OR teacher_name LIKE ?", "%"+pageInfo.Keyword+"%", "%"+pageInfo.Keyword+"%", "%"+pageInfo.Keyword+"%") } + // 先查总数 + err = db.Count(&total).Error + if err != nil { + return + } + + // 批量查出teacher_id err = db.Limit(limit).Offset(offset).Omit("teacher_avatar").Order("created_at desc").Find(&list).Error + if err != nil { + return + } + + // 优化:批量查询讲师头像,避免N+1查询 + teacherIds := make([]int, 0, len(list)) + for _, a := range list { + teacherIds = append(teacherIds, a.TeacherId) + } + avatars := make(map[int]string) + if len(teacherIds) > 0 { + type avatarResult struct { + ID int + Avatar string + } + var results []avatarResult + global.GVA_DB.Table("app_user").Select("id, avatar").Where("id IN ?", teacherIds).Find(&results) + for _, r := range results { + avatars[r.ID] = r.Avatar + } + } for i, a := range list { - global.GVA_DB.Table("app_user").Select("avatar").Where("id = ?", a.TeacherId).Scan(&list[i].TeacherAvatar) + list[i].TeacherAvatar = avatars[a.TeacherId] } return @@ -113,9 +137,37 @@ func (s ArticleService) APPGetArticle(id string, userId int) (article *vo.Articl // 如果count = 0 或者 TeacherId 不等于 userId,表示用户没有购买过该文章 if count == 0 && article.TeacherId != userId { - // 用户没有购买过,隐藏Content - article.Content = "" - article.IsBuy = 0 // 设置为未购买 + + // 判断用户是否已经包月该讲师和是否是讲师本人 + if userId != 0 && userId != article.TeacherId { + var userTeacherVip []app.UserTeacherVip + err = global.GVA_DB.Model(&app.UserTeacherVip{}).Where("teacher_id = ? AND user_id = ? AND is_expire = 1", article.TeacherId, userId).Find(&userTeacherVip).Count(&count).Error + if err != nil { + global.GVA_LOG.Error("查询用户包月记录失败", zap.Error(err)) + return nil, err + } + + for _, vip := range userTeacherVip { + // 获取包月的信息 判断文章是否在包月范围内 + var teacherVipInfo app.TeacherVip + err = global.GVA_DB.Model(&app.TeacherVip{}).Where("id = ?", vip.TeacherVipId).First(&teacherVipInfo).Error + if err != nil { + global.GVA_LOG.Error("查询讲师包月信息失败", zap.Error(err)) + return nil, err + } + + // 用户包月了,判断文章是否在包月范围内 + if count != 0 { + if teacherVipInfo.CategoryId == article.CategoryId { + return + } + } + } + // 用户没有购买过,隐藏Content + article.Content = "" + article.IsBuy = 0 // 设置为未购买 + } + } }