390 lines
11 KiB
Go
390 lines
11 KiB
Go
package user
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"fmt"
|
||
"time"
|
||
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/os/gtime"
|
||
"nl-video-api/internal/dao"
|
||
"nl-video-api/internal/model/entity"
|
||
"nl-video-api/utility/crypto"
|
||
)
|
||
|
||
// UserService 用户服务
|
||
type UserService struct{}
|
||
|
||
var User = &UserService{}
|
||
|
||
// UserCreateReq 创建用户请求
|
||
type UserCreateReq struct {
|
||
Username string `json:"username" v:"required|length:3,20#用户名不能为空|用户名长度为3-20位"`
|
||
Phone string `json:"phone" v:"required|phone#手机号不能为空|手机号格式错误"`
|
||
Email string `json:"email" v:"email#邮箱格式错误"`
|
||
Password string `json:"password" v:"required|length:6,20#密码不能为空|密码长度为6-20位"`
|
||
Nickname string `json:"nickname" v:"length:1,20#昵称长度为1-20位"`
|
||
Avatar string `json:"avatar"`
|
||
Gender int `json:"gender" v:"in:0,1,2#性别值错误"`
|
||
Birthday string `json:"birthday"`
|
||
VipLevel int `json:"vip_level" v:"min:1,max:10#VIP等级范围1-10"`
|
||
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
|
||
}
|
||
|
||
// UserUpdateReq 更新用户请求
|
||
type UserUpdateReq struct {
|
||
Id int `json:"id" v:"required|min:1#用户ID不能为空"`
|
||
Username string `json:"username" v:"length:3,20#用户名长度为3-20位"`
|
||
Phone string `json:"phone" v:"phone#手机号格式错误"`
|
||
Email string `json:"email" v:"email#邮箱格式错误"`
|
||
Nickname string `json:"nickname" v:"length:1,20#昵称长度为1-20位"`
|
||
Avatar string `json:"avatar"`
|
||
Gender int `json:"gender" v:"in:0,1,2#性别值错误"`
|
||
Birthday string `json:"birthday"`
|
||
VipLevel int `json:"vip_level" v:"min:1,max:10#VIP等级范围1-10"`
|
||
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
|
||
}
|
||
|
||
// UserPasswordReq 修改密码请求
|
||
type UserPasswordReq struct {
|
||
Id int `json:"id" v:"required|min:1#用户ID不能为空"`
|
||
OldPassword string `json:"old_password" v:"required#原密码不能为空"`
|
||
NewPassword string `json:"new_password" v:"required|length:6,20#新密码不能为空|新密码长度为6-20位"`
|
||
}
|
||
|
||
// VipUpgradeReq VIP升级请求
|
||
type VipUpgradeReq struct {
|
||
UserId int `json:"user_id" v:"required|min:1#用户ID不能为空"`
|
||
VipLevel int `json:"vip_level" v:"required|min:1,max:10#VIP等级不能为空|VIP等级范围1-10"`
|
||
Days int `json:"days" v:"required|min:1#天数不能为空"`
|
||
}
|
||
|
||
// Create 创建用户
|
||
func (s *UserService) Create(ctx context.Context, req *UserCreateReq) (int64, error) {
|
||
// 检查用户名是否存在
|
||
existUser, err := dao.User.GetByUsername(ctx, req.Username)
|
||
if err != nil {
|
||
return 0, fmt.Errorf("检查用户名失败: %v", err)
|
||
}
|
||
if existUser != nil {
|
||
return 0, errors.New("用户名已存在")
|
||
}
|
||
|
||
// 检查手机号是否存在
|
||
existPhone, err := dao.User.GetByPhone(ctx, req.Phone)
|
||
if err != nil {
|
||
return 0, fmt.Errorf("检查手机号失败: %v", err)
|
||
}
|
||
if existPhone != nil {
|
||
return 0, errors.New("手机号已存在")
|
||
}
|
||
|
||
// 检查邮箱是否存在
|
||
if req.Email != "" {
|
||
existEmail, err := dao.User.GetByEmail(ctx, req.Email)
|
||
if err != nil {
|
||
return 0, fmt.Errorf("检查邮箱失败: %v", err)
|
||
}
|
||
if existEmail != nil {
|
||
return 0, errors.New("邮箱已存在")
|
||
}
|
||
}
|
||
|
||
// 加密密码
|
||
hashedPassword, err := crypto.HashPassword(req.Password)
|
||
if err != nil {
|
||
return 0, fmt.Errorf("密码加密失败: %v", err)
|
||
}
|
||
|
||
// 设置默认值
|
||
if req.Nickname == "" {
|
||
req.Nickname = req.Username
|
||
}
|
||
if req.VipLevel == 0 {
|
||
req.VipLevel = 1 // 默认普通用户
|
||
}
|
||
if req.Status == 0 {
|
||
req.Status = 1 // 默认启用
|
||
}
|
||
|
||
// 解析生日
|
||
var birthday *time.Time
|
||
if req.Birthday != "" {
|
||
if parsedTime, err := time.Parse("2006-01-02", req.Birthday); err == nil {
|
||
birthday = &parsedTime
|
||
}
|
||
}
|
||
|
||
// 创建用户
|
||
user := &entity.NlUser{
|
||
Username: req.Username,
|
||
Phone: req.Phone,
|
||
Email: req.Email,
|
||
Password: hashedPassword,
|
||
NickName: req.Nickname,
|
||
Avatar: req.Avatar,
|
||
Gender: req.Gender,
|
||
Birthday: birthday,
|
||
VipLevel: req.VipLevel,
|
||
Status: req.Status,
|
||
}
|
||
|
||
return dao.User.Create(ctx, user)
|
||
}
|
||
|
||
// Update 更新用户
|
||
func (s *UserService) Update(ctx context.Context, req *UserUpdateReq) error {
|
||
// 检查用户是否存在
|
||
existUser, err := dao.User.GetById(ctx, req.Id)
|
||
if err != nil {
|
||
return fmt.Errorf("查询用户失败: %v", err)
|
||
}
|
||
if existUser == nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
updateData := g.Map{}
|
||
|
||
// 检查用户名是否重复
|
||
if req.Username != "" && req.Username != existUser.Username {
|
||
checkUser, err := dao.User.GetByUsername(ctx, req.Username)
|
||
if err != nil {
|
||
return fmt.Errorf("检查用户名失败: %v", err)
|
||
}
|
||
if checkUser != nil && int(checkUser.Id) != req.Id {
|
||
return errors.New("用户名已存在")
|
||
}
|
||
updateData["username"] = req.Username
|
||
}
|
||
|
||
// 检查手机号是否重复
|
||
if req.Phone != "" && req.Phone != existUser.Phone {
|
||
checkPhone, err := dao.User.GetByPhone(ctx, req.Phone)
|
||
if err != nil {
|
||
return fmt.Errorf("检查手机号失败: %v", err)
|
||
}
|
||
if checkPhone != nil && int(checkPhone.Id) != req.Id {
|
||
return errors.New("手机号已存在")
|
||
}
|
||
updateData["phone"] = req.Phone
|
||
}
|
||
|
||
// 检查邮箱是否重复
|
||
if req.Email != "" && req.Email != existUser.Email {
|
||
checkEmail, err := dao.User.GetByEmail(ctx, req.Email)
|
||
if err != nil {
|
||
return fmt.Errorf("检查邮箱失败: %v", err)
|
||
}
|
||
if checkEmail != nil && int(checkEmail.Id) != req.Id {
|
||
return errors.New("邮箱已存在")
|
||
}
|
||
updateData["email"] = req.Email
|
||
}
|
||
|
||
// 更新其他字段
|
||
if req.Nickname != "" {
|
||
updateData["nick_name"] = req.Nickname
|
||
}
|
||
if req.Avatar != "" {
|
||
updateData["avatar"] = req.Avatar
|
||
}
|
||
if req.Gender >= 0 {
|
||
updateData["gender"] = req.Gender
|
||
}
|
||
if req.Birthday != "" {
|
||
// 解析生日
|
||
if parsedTime, err := time.Parse("2006-01-02", req.Birthday); err == nil {
|
||
updateData["birthday"] = &parsedTime
|
||
}
|
||
}
|
||
if req.VipLevel > 0 {
|
||
updateData["vip_level"] = req.VipLevel
|
||
}
|
||
if req.Status >= 0 {
|
||
updateData["status"] = req.Status
|
||
}
|
||
|
||
if len(updateData) == 0 {
|
||
return errors.New("没有需要更新的数据")
|
||
}
|
||
|
||
return dao.User.Update(ctx, req.Id, updateData)
|
||
}
|
||
|
||
// GetById 根据ID获取用户
|
||
func (s *UserService) GetById(ctx context.Context, id int) (*entity.NlUser, error) {
|
||
user, err := dao.User.GetById(ctx, id)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("查询用户失败: %v", err)
|
||
}
|
||
|
||
// 清除敏感信息
|
||
if user != nil {
|
||
user.Password = ""
|
||
}
|
||
|
||
return user, nil
|
||
}
|
||
|
||
// GetList 获取用户列表
|
||
func (s *UserService) GetList(ctx context.Context, req *dao.UserListReq) ([]*entity.NlUser, int, error) {
|
||
users, total, err := dao.User.GetList(ctx, req)
|
||
if err != nil {
|
||
return nil, 0, fmt.Errorf("查询用户列表失败: %v", err)
|
||
}
|
||
|
||
// 清除敏感信息
|
||
for _, user := range users {
|
||
user.Password = ""
|
||
}
|
||
|
||
return users, total, nil
|
||
}
|
||
|
||
// Delete 删除用户
|
||
func (s *UserService) Delete(ctx context.Context, id int) error {
|
||
// 检查用户是否存在
|
||
user, err := dao.User.GetById(ctx, id)
|
||
if err != nil {
|
||
return fmt.Errorf("查询用户失败: %v", err)
|
||
}
|
||
if user == nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
return dao.User.Delete(ctx, id)
|
||
}
|
||
|
||
// ChangePassword 修改密码
|
||
func (s *UserService) ChangePassword(ctx context.Context, req *UserPasswordReq) error {
|
||
// 获取用户信息
|
||
user, err := dao.User.GetById(ctx, req.Id)
|
||
if err != nil {
|
||
return fmt.Errorf("查询用户失败: %v", err)
|
||
}
|
||
if user == nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
// 验证原密码
|
||
if !crypto.CheckPassword(req.OldPassword, user.Password) {
|
||
return errors.New("原密码错误")
|
||
}
|
||
|
||
// 加密新密码
|
||
hashedPassword, err := crypto.HashPassword(req.NewPassword)
|
||
if err != nil {
|
||
return fmt.Errorf("密码加密失败: %v", err)
|
||
}
|
||
|
||
// 更新密码
|
||
return dao.User.Update(ctx, req.Id, g.Map{
|
||
"password": hashedPassword,
|
||
})
|
||
}
|
||
|
||
// BatchUpdateStatus 批量更新用户状态
|
||
func (s *UserService) BatchUpdateStatus(ctx context.Context, ids []int, status int) error {
|
||
if len(ids) == 0 {
|
||
return errors.New("请选择要操作的用户")
|
||
}
|
||
|
||
return dao.User.BatchUpdateStatus(ctx, ids, status)
|
||
}
|
||
|
||
// BatchDelete 批量删除用户
|
||
func (s *UserService) BatchDelete(ctx context.Context, ids []int) error {
|
||
if len(ids) == 0 {
|
||
return errors.New("请选择要删除的用户")
|
||
}
|
||
|
||
return dao.User.BatchDelete(ctx, ids)
|
||
}
|
||
|
||
// GetUserStats 获取用户统计信息
|
||
func (s *UserService) GetUserStats(ctx context.Context) (g.Map, error) {
|
||
return dao.User.GetUserStats(ctx)
|
||
}
|
||
|
||
// UpgradeVip 升级VIP
|
||
func (s *UserService) UpgradeVip(ctx context.Context, req *VipUpgradeReq) error {
|
||
// 检查用户是否存在
|
||
user, err := dao.User.GetById(ctx, req.UserId)
|
||
if err != nil {
|
||
return fmt.Errorf("查询用户失败: %v", err)
|
||
}
|
||
if user == nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
// 计算VIP到期时间
|
||
var expireAt int64
|
||
if int64(user.VipExpireTime) > gtime.Now().Unix() {
|
||
// 如果当前VIP未过期,在原基础上延长
|
||
expireAt = int64(user.VipExpireTime) + int64(req.Days*24*3600)
|
||
} else {
|
||
// 如果已过期或首次开通,从现在开始计算
|
||
expireAt = gtime.Now().Unix() + int64(req.Days*24*3600)
|
||
}
|
||
|
||
// 更新用户VIP信息
|
||
return dao.User.Update(ctx, req.UserId, g.Map{
|
||
"vip_level": req.VipLevel,
|
||
"vip_expire_time": int(expireAt),
|
||
})
|
||
}
|
||
|
||
// SearchUsers 搜索用户
|
||
func (s *UserService) SearchUsers(ctx context.Context, keyword string, page, pageSize int) ([]*entity.NlUser, int, error) {
|
||
if keyword == "" {
|
||
return nil, 0, errors.New("搜索关键词不能为空")
|
||
}
|
||
|
||
users, total, err := dao.User.SearchUsers(ctx, keyword, page, pageSize)
|
||
if err != nil {
|
||
return nil, 0, fmt.Errorf("搜索用户失败: %v", err)
|
||
}
|
||
|
||
// 清除敏感信息
|
||
for _, user := range users {
|
||
user.Password = ""
|
||
}
|
||
|
||
return users, total, nil
|
||
}
|
||
|
||
// GetVipUsers 获取VIP用户列表
|
||
func (s *UserService) GetVipUsers(ctx context.Context, page, pageSize int) ([]*entity.NlUser, int, error) {
|
||
users, total, err := dao.User.GetVipUsers(ctx, page, pageSize)
|
||
if err != nil {
|
||
return nil, 0, fmt.Errorf("查询VIP用户失败: %v", err)
|
||
}
|
||
|
||
// 清除敏感信息
|
||
for _, user := range users {
|
||
user.Password = ""
|
||
}
|
||
|
||
return users, total, nil
|
||
}
|
||
|
||
// GetExpiredVipUsers 获取VIP即将过期的用户
|
||
func (s *UserService) GetExpiredVipUsers(ctx context.Context, days int) ([]*entity.NlUser, error) {
|
||
users, err := dao.User.GetExpiredVipUsers(ctx, days)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("查询即将过期VIP用户失败: %v", err)
|
||
}
|
||
|
||
// 清除敏感信息
|
||
for _, user := range users {
|
||
user.Password = ""
|
||
}
|
||
|
||
return users, nil
|
||
}
|
||
|
||
// UpdateLoginInfo 更新登录信息
|
||
func (s *UserService) UpdateLoginInfo(ctx context.Context, userId int, ip string) error {
|
||
return dao.User.UpdateLoginInfo(ctx, userId, ip)
|
||
} |