package app import ( "errors" "fmt" "git.echol.cn/loser/lckt/global" "git.echol.cn/loser/lckt/model/app" "git.echol.cn/loser/lckt/model/app/vo" common "git.echol.cn/loser/lckt/model/common/request" "git.echol.cn/loser/lckt/model/user" "git.echol.cn/loser/lckt/model/user/request" utils2 "git.echol.cn/loser/lckt/utils" "github.com/ArtisanCloud/PowerSocialite/v3/src/providers" "go.uber.org/zap" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) type AppUserService struct{} // Login 用户登录 func (u *AppUserService) Login(req request.CodeLoginReq) (users user.User, err error) { // 1. 判断用户是否存在 var count int64 err = global.GVA_DB.Model(&user.User{}).Where("phone = ?", req.Phone).Count(&count).Error if err != nil { global.GVA_LOG.Error("查询用户失败", zap.Error(err)) return } // 2. 如果用户不存在,则创建用户 if count == 0 { user := user.User{ Phone: req.Phone, UserLabel: 1, } err = global.GVA_DB.Save(&user).Error if err != nil { global.GVA_LOG.Error("创建用户失败", zap.Error(err)) return } } else { err = global.GVA_DB.Where("phone = ?", req.Phone).First(&users).Error if err != nil { global.GVA_LOG.Error("查询用户失败", zap.Error(err)) return } } return } // WechatLogin 微信登录 func (u *AppUserService) WechatLogin(info *providers.User) (users user.User, err error) { openID := info.GetOpenID() var count int64 // 1. 判断用户是否存在 err = global.GVA_DB.Model(&users).Where("open_id = ?", openID).Count(&count).Error if err != nil { global.GVA_LOG.Error("查询用户失败", zap.Error(err)) return } if count == 0 { newUser := user.User{ OpenId: openID, NickName: info.GetNickname(), Avatar: info.GetAvatar(), } err = global.GVA_DB.Save(&newUser).Error if err != nil { global.GVA_LOG.Error("创建用户失败", zap.Error(err)) return } return newUser, nil } else { err = global.GVA_DB.Where("open_id = ?", openID).First(&users).Error if err != nil { global.GVA_LOG.Error("查询用户失败", zap.Error(err)) return } if users.Status != 1 { err = fmt.Errorf("用户已被封禁") return } } return } // PwdLogin 用户密码登录 func (u *AppUserService) PwdLogin(req request.PwdLoginReq) (users user.User, err error) { // 1. 判断用户是否存在 var count int64 err = global.GVA_DB.Model(&user.User{}).Where("phone = ?", req.Phone).First(&users).Count(&count).Error if err != nil { global.GVA_LOG.Error("查询用户失败", zap.Error(err)) return } if count == 0 { global.GVA_LOG.Error("用户不存在") err = fmt.Errorf("用户不存在") return } // 2. 判断密码是否正确 err = bcrypt.CompareHashAndPassword([]byte(users.Password), []byte(req.Password)) if err != nil { global.GVA_LOG.Error("密码错误", zap.Error(err)) return } return } func (u *AppUserService) GetUserInfo(id uint) (info vo.UserInfo, err error) { err = global.GVA_DB.Model(&user.User{}).Where("id = ?", id).First(&info).Error if err != nil { global.GVA_LOG.Error("查询用户信息失败", zap.Error(err)) return } return } func (u *AppUserService) Register(p request.RegisterReq) (userInfo user.User, err error) { err = global.GVA_DB.Transaction(func(tx *gorm.DB) error { // 1. 判断用户是否存在 var count int64 if err = tx.Model(&userInfo).Where("phone = ?", p.Phone).Count(&count).Error; err != nil { global.GVA_LOG.Error("查询用户失败", zap.Error(err)) return err } if count > 0 { global.GVA_LOG.Error("用户已存在") return fmt.Errorf("用户已存在") } // 2. 如果用户不存在,则创建用户 password, _ := bcrypt.GenerateFromPassword([]byte(p.Password), bcrypt.DefaultCost) userInfo = user.User{ Phone: p.Phone, Password: string(password), NickName: p.NickName, UserLabel: 1, Status: 1, UserType: p.UserType, Avatar: "https://ui-avatars.com/api/?name=" + p.NickName + "&background=0081ff&color=ffffff&rounded=true", } // 保存用户 if err = tx.Save(&userInfo).Error; err != nil { global.GVA_LOG.Error("创建用户失败", zap.Error(err)) return err } // 生成邀请码 code := utils2.GenerateInviteCode(userInfo.ID) userInfo.InviteCode = &code if err = tx.Model(&userInfo).Where("id = ?", userInfo.ID).Update("invite_code", code).Error; err != nil { global.GVA_LOG.Error("更新邀请码失败", zap.Error(err)) return err } return nil }) return } func (u *AppUserService) ApplyTeacher(p app.TeacherApply) (err error) { if err = global.GVA_DB.Save(&p).Error; err != nil { global.GVA_LOG.Error("保存申请信息失败", zap.Error(err)) return err } return nil } func (u *AppUserService) GetTeacherApplyStatus(id uint) (teacherApply *app.TeacherApply, err error) { // 获取最后一条申请记录 err = global.GVA_DB.Model(&app.TeacherApply{}).Where("user_id = ?", id).Last(&teacherApply).Error // 判断是否是记录未找到的错误 if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { global.GVA_LOG.Error("查询申请信息失败", zap.Error(err)) return } return } // BindWechat 手机登录用户绑定微信 func (u *AppUserService) BindWechat(p request.BindWechatReq) (*user.User, error) { var userInfo user.User err := global.GVA_DB.Model(&user.User{}).Where("id = ?", p.Id).First(&userInfo).Error if err != nil { global.GVA_LOG.Error("查询用户失败", zap.Error(err)) return nil, err } if userInfo.OpenId != "" { global.GVA_LOG.Error("用户已绑定微信") return nil, fmt.Errorf("用户已绑定微信") } userInfo.OpenId = p.Openid err = global.GVA_DB.Save(&userInfo).Error if err != nil { global.GVA_LOG.Error("绑定微信失败", zap.Error(err)) return nil, err } return &userInfo, nil } // BindPhone 微信登录用户绑定手机号 func (u *AppUserService) BindPhone(p request.BindPhoneReq) (*user.User, error) { var userInfo user.User err := global.GVA_DB.Model(&user.User{}).Where("id = ?", p.Id).First(&userInfo).Error if err != nil { global.GVA_LOG.Error("查询用户失败", zap.Error(err)) return nil, err } userInfo.Phone = p.Phone pwd, _ := bcrypt.GenerateFromPassword([]byte(p.PassWord), bcrypt.DefaultCost) userInfo.Password = string(pwd) err = global.GVA_DB.Save(&userInfo).Error if err != nil { global.GVA_LOG.Error("绑定微信失败", zap.Error(err)) return nil, err } return &userInfo, nil } func (u *AppUserService) GetTeacherList(p common.PageInfo) (list []vo.TeacherInfo, total int64, err error) { limit := p.PageSize offset := (p.Page - 1) * p.PageSize db := global.GVA_DB.Model(&user.User{}).Where("user_type = ?", 2) 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 nil, 0, err } 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 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 } 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 } // GetVipTeacherList 获取用户购买的讲师VIP列表 func (u *AppUserService) GetVipTeacherList(p common.PageInfo, userId uint) (list []vo.TeacherInfo, total int64, err error) { limit := p.PageSize offset := (p.Page - 1) * p.PageSize // 1. 获取所有购买了讲师VIP的讲师ID var vipTeacherIds []uint err = global.GVA_DB.Model(&app.UserTeacherVip{}).Where("user_id = ? and is_expire = 1", userId).Select("teacher_id").Scan(&vipTeacherIds).Error if err != nil { global.GVA_LOG.Error("获取用户讲师包月信息失败:", zap.Error(err)) return nil, 0, err } db := global.GVA_DB.Model(&user.User{}).Where("user_type = ? and id in ?", 2, vipTeacherIds) 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 nil, 0, err } 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 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 } // GetBalanceLog 获取用户余额变动日志 func (u *AppUserService) GetBalanceLog(id uint, p common.PageInfo) (list []app.BalanceLog, total int64, err error) { limit := p.PageSize offset := (p.Page - 1) * p.PageSize db := global.GVA_DB.Model(&app.BalanceLog{}).Where("user_id = ?", id) err = db.Count(&total).Error if err != nil { global.GVA_LOG.Error("查询余额变动总数失败", zap.Error(err)) return nil, 0, err } err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&list).Error if err != nil { global.GVA_LOG.Error("查询余额变动列表失败", zap.Error(err)) return nil, 0, err } return }