Files
lckt-server/service/app/user.go

419 lines
12 KiB
Go

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
}
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("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
}