Files
2025-08-03 00:11:15 +08:00

390 lines
11 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}