🎨 新增讲师关注功能
This commit is contained in:
@@ -109,7 +109,7 @@ func (*AppUserApi) WechatLogin(ctx *gin.Context) {
|
|||||||
|
|
||||||
user, err := appUserService.WechatLogin(info)
|
user, err := appUserService.WechatLogin(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.FailWithMessage("登录失败", ctx)
|
r.FailWithMessage("登录失败:"+err.Error(), ctx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 生成token
|
// 生成token
|
||||||
@@ -395,3 +395,84 @@ func (a *AppUserApi) GetTeacherList(context *gin.Context) {
|
|||||||
PageSize: p.PageSize,
|
PageSize: p.PageSize,
|
||||||
}, "获取讲师列表成功", context)
|
}, "获取讲师列表成功", context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFollowTeacherList 获取关注的讲师列表
|
||||||
|
func (a *AppUserApi) GetFollowTeacherList(context *gin.Context) {
|
||||||
|
var p common.PageInfo
|
||||||
|
if err := context.ShouldBind(&p); err != nil {
|
||||||
|
global.GVA_LOG.Error("参数错误,获取关注的讲师列表失败", zap.Error(err))
|
||||||
|
r.FailWithMessage("参数错误,获取关注的讲师列表失败", context)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
id := user_jwt.GetUserID(context)
|
||||||
|
if id == 0 {
|
||||||
|
global.GVA_LOG.Error("获取用户ID失败")
|
||||||
|
r.FailWithMessage("获取用户ID失败", context)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
teachers, total, err := appUserService.GetFollowTeacherList(id, p)
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("获取关注的讲师列表失败", zap.Error(err))
|
||||||
|
r.FailWithMessage("获取关注的讲师列表失败", context)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.OkWithDetailed(
|
||||||
|
r.PageResult{
|
||||||
|
List: teachers,
|
||||||
|
Total: total,
|
||||||
|
Page: p.Page,
|
||||||
|
PageSize: p.PageSize,
|
||||||
|
}, "获取关注的讲师列表成功", context)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FollowTeacher 关注讲师
|
||||||
|
func (a *AppUserApi) FollowTeacher(context *gin.Context) {
|
||||||
|
var p app.Follow
|
||||||
|
if err := context.ShouldBind(&p); err != nil {
|
||||||
|
global.GVA_LOG.Error("参数错误,关注讲师失败", zap.Error(err))
|
||||||
|
r.FailWithMessage("参数错误,关注讲师失败", context)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id := user_jwt.GetUserID(context)
|
||||||
|
if id == 0 {
|
||||||
|
global.GVA_LOG.Error("获取用户ID失败")
|
||||||
|
r.FailWithMessage("获取用户ID失败", context)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.UserId = id
|
||||||
|
if err := appUserService.FollowTeacher(p); err != nil {
|
||||||
|
global.GVA_LOG.Error("关注讲师失败", zap.Error(err))
|
||||||
|
r.FailWithMessage("关注讲师失败", context)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.OkWithMessage("关注讲师成功", context)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFollowStatus 获取用户关注讲师状态
|
||||||
|
func (a *AppUserApi) GetFollowStatus(ctx *gin.Context) {
|
||||||
|
userId := user_jwt.GetUserID(ctx)
|
||||||
|
if userId == 0 {
|
||||||
|
r.FailWithMessage("获取用户ID失败", ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
teacherIdStr := ctx.Query("teacherId")
|
||||||
|
if teacherIdStr == "" {
|
||||||
|
r.FailWithMessage("缺少参数: teacherId", ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
teacherId, err := strconv.ParseUint(teacherIdStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
r.FailWithMessage("teacherId参数格式错误", ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
followed, err := appUserService.IsFollowTeacher(uint(userId), uint(teacherId))
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("获取关注状态失败", zap.Error(err))
|
||||||
|
r.FailWithMessage("获取关注状态失败", ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.OkWithDetailed(followed, "获取关注状态成功", ctx)
|
||||||
|
}
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ func RegisterTables() {
|
|||||||
category.Category{},
|
category.Category{},
|
||||||
notice.Notice{},
|
notice.Notice{},
|
||||||
vip.Vip{},
|
vip.Vip{},
|
||||||
|
app.Follow{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.GVA_LOG.Error("register table failed", zap.Error(err))
|
global.GVA_LOG.Error("register table failed", zap.Error(err))
|
||||||
|
|||||||
13
model/app/follow.go
Normal file
13
model/app/follow.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import "git.echol.cn/loser/lckt/global"
|
||||||
|
|
||||||
|
type Follow struct {
|
||||||
|
global.GVA_MODEL
|
||||||
|
UserId uint `json:"userId" gorm:"comment:用户ID;uniqueIndex:idx_user_teacher"`
|
||||||
|
TeacherId uint `json:"teacherId" gorm:"comment:讲师ID;uniqueIndex:idx_user_teacher"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Follow) TableName() string {
|
||||||
|
return "app_follow"
|
||||||
|
}
|
||||||
@@ -21,4 +21,5 @@ type TeacherInfo struct {
|
|||||||
NickName string `json:"nick_name" form:"nick_name"`
|
NickName string `json:"nick_name" form:"nick_name"`
|
||||||
Avatar string `json:"avatar" form:"avatar"`
|
Avatar string `json:"avatar" form:"avatar"`
|
||||||
Des string `json:"des" form:"des"`
|
Des string `json:"des" form:"des"`
|
||||||
|
Follow int64 `json:"follow" form:"follow"` // 粉丝数
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ type User struct {
|
|||||||
UserType int8 `gorm:"column:user_type;default:1;NOT NULL;comment:'用户类型 1 用户 2 讲师'" json:"user_type" form:"user_type" `
|
UserType int8 `gorm:"column:user_type;default:1;NOT NULL;comment:'用户类型 1 用户 2 讲师'" json:"user_type" form:"user_type" `
|
||||||
IsVip int8 `gorm:"column:is_vip;default:0;NOT NULL;comment:'是否是VIP 0 否 1 是'" json:"is_vip" form:"is_vip"`
|
IsVip int8 `gorm:"column:is_vip;default:0;NOT NULL;comment:'是否是VIP 0 否 1 是'" json:"is_vip" form:"is_vip"`
|
||||||
VipExpireTime string `json:"vip_expire_time" form:"vip_expire_time" gorm:"comment:VIP过期时间"`
|
VipExpireTime string `json:"vip_expire_time" form:"vip_expire_time" gorm:"comment:VIP过期时间"`
|
||||||
|
//权重
|
||||||
|
Weight int `json:"weight" form:"weight" gorm:"comment:用户权重"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (User) TableName() string {
|
func (User) TableName() string {
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ func (s *UserRouter) InitAppUserRouter(AppAuthGroup, PublicRouter *gin.RouterGro
|
|||||||
appUserRouter.POST("/applyTeacher", userApi.ApplyTeacher) // 申请成为讲师
|
appUserRouter.POST("/applyTeacher", userApi.ApplyTeacher) // 申请成为讲师
|
||||||
appUserRouter.GET("/applyTeacher", userApi.GetTeacherApply) // 获取教师申请状态
|
appUserRouter.GET("/applyTeacher", userApi.GetTeacherApply) // 获取教师申请状态
|
||||||
appUserRouter.GET("/teachers", userApi.GetTeacherList) // 获取讲师列表
|
appUserRouter.GET("/teachers", userApi.GetTeacherList) // 获取讲师列表
|
||||||
|
appUserRouter.GET("/follows", userApi.GetFollowTeacherList) // 获取关注的讲师列表
|
||||||
|
appUserRouter.POST("/follow", userApi.FollowTeacher) // 关注/取关讲师
|
||||||
|
appUserRouter.GET("/followStatus", userApi.GetFollowStatus) // 获取关注状态
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
publicRouter.POST("wxLogin", userApi.WechatLogin) // 微信登录
|
publicRouter.POST("wxLogin", userApi.WechatLogin) // 微信登录
|
||||||
|
|||||||
@@ -79,6 +79,11 @@ func (u *AppUserService) WechatLogin(info *providers.User) (users user.User, err
|
|||||||
global.GVA_LOG.Error("查询用户失败", zap.Error(err))
|
global.GVA_LOG.Error("查询用户失败", zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if users.Status != 1 {
|
||||||
|
err = fmt.Errorf("用户已被封禁")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -244,5 +249,128 @@ func (u *AppUserService) GetTeacherList(p common.PageInfo) (list []vo.TeacherInf
|
|||||||
global.GVA_LOG.Error("查询教师列表失败", zap.Error(err))
|
global.GVA_LOG.Error("查询教师列表失败", zap.Error(err))
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取每个教师的粉丝数
|
||||||
|
for i := range list {
|
||||||
|
followCount, err := u.GetTeacherFansCount(list[i].ID)
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("查询教师粉丝数失败", zap.Error(err))
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
list[i].Follow = followCount
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *AppUserService) GetFollowTeacherList(id uint, p common.PageInfo) (list []vo.TeacherInfo, total int64, err error) {
|
||||||
|
limit := p.PageSize
|
||||||
|
offset := (p.Page - 1) * p.PageSize
|
||||||
|
|
||||||
|
// 1. 获取用户关注的教师ID列表
|
||||||
|
var followings []app.Follow
|
||||||
|
err = global.GVA_DB.Model(&app.Follow{}).Where("user_id = ?", id).Find(&followings).Error
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("查询关注列表失败", zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(followings) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var teacherIDs []uint
|
||||||
|
for _, f := range followings {
|
||||||
|
teacherIDs = append(teacherIDs, f.TeacherId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 根据教师ID列表获取教师信息
|
||||||
|
db := global.GVA_DB.Model(&user.User{}).Where("id IN ?", teacherIDs)
|
||||||
|
|
||||||
|
if p.Keyword != "" {
|
||||||
|
db = db.Where("nick_name LIKE ?", "%"+p.Keyword+"%")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.Count(&total).Error
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("查询关注教师总数失败", zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = db.Limit(limit).Offset(offset).Select("id, nick_name, avatar,des").Find(&list).Error
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("查询关注教师列表失败", zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取每个教师的粉丝数
|
||||||
|
for i := range list {
|
||||||
|
followCount, err := u.GetTeacherFansCount(list[i].ID)
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("查询教师粉丝数失败", zap.Error(err))
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
list[i].Follow = followCount
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FollowTeacher 用户关注/取消关注教师
|
||||||
|
func (u *AppUserService) FollowTeacher(p app.Follow) error {
|
||||||
|
var follow app.Follow
|
||||||
|
// 用 Unscoped 查询所有记录(包括软删除)
|
||||||
|
db := global.GVA_DB.Unscoped().Where("user_id = ? AND teacher_id = ?", p.UserId, p.TeacherId)
|
||||||
|
err := db.First(&follow).Error
|
||||||
|
if err == nil {
|
||||||
|
if follow.DeletedAt.Valid {
|
||||||
|
// 已软删除,恢复关注
|
||||||
|
err = global.GVA_DB.Model(&app.Follow{}).Unscoped().Where("id = ?", follow.ID).Update("deleted_at", nil).Error
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("恢复关注失败", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil // 恢复关注成功
|
||||||
|
} else {
|
||||||
|
// 已关注,取消关注
|
||||||
|
err = global.GVA_DB.Where("user_id = ? AND teacher_id = ?", p.UserId, p.TeacherId).Delete(&app.Follow{}).Error
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("取消关注失败", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil // 取消关注成功
|
||||||
|
}
|
||||||
|
} else if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
// 没有任何记录,直接关注
|
||||||
|
err = global.GVA_DB.Create(&p).Error
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("关注教师失败", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil // 关注成功
|
||||||
|
} else {
|
||||||
|
global.GVA_LOG.Error("查询关注记录失败", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTeacherFansCount 获取讲师粉丝数
|
||||||
|
func (u *AppUserService) GetTeacherFansCount(teacherId uint) (int64, error) {
|
||||||
|
var count int64
|
||||||
|
err := global.GVA_DB.Model(&app.Follow{}).Where("teacher_id = ?", teacherId).Count(&count).Error
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("统计粉丝数失败", zap.Error(err))
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsFollowTeacher 判断用户是否关注某讲师
|
||||||
|
func (u *AppUserService) IsFollowTeacher(userId, teacherId uint) (bool, error) {
|
||||||
|
var count int64
|
||||||
|
err := global.GVA_DB.Model(&app.Follow{}).
|
||||||
|
Where("user_id = ? AND teacher_id = ?", userId, teacherId).
|
||||||
|
Count(&count).Error
|
||||||
|
if err != nil {
|
||||||
|
global.GVA_LOG.Error("查询关注状态失败", zap.Error(err))
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return count > 0, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user