package system import ( "context" "encoding/json" "errors" "time" "github.com/google/uuid" "golang.org/x/crypto/bcrypt" ) var ( ErrUserNotFound = errors.New("用户不存在") ErrUserAlreadyExists = errors.New("用户名已注册") ErrPasswordWrong = errors.New("密码错误") ErrOldPasswordWrong = errors.New("原密码错误") ErrUserNoAuthority = errors.New("该用户无此角色") ErrDefaultRouterEmpty = errors.New("找不到默认路由,无法切换本角色") ) // User 用户实体 type User struct { ID uint UUID uuid.UUID Username string Password string NickName string SideMode string HeaderImg string BaseColor string AuthorityId uint Phone string Email string Enable int OriginSetting json.RawMessage Authority *Authority Authorities []*Authority CreatedAt time.Time UpdatedAt time.Time } // Authority 角色实体 type Authority struct { AuthorityId uint AuthorityName string ParentId *uint DefaultRouter string } // UserRepo 用户仓储接口 type UserRepo interface { Create(ctx context.Context, user *User) error Update(ctx context.Context, user *User) error UpdateSelf(ctx context.Context, user *User) error UpdateSelfSetting(ctx context.Context, id uint, setting json.RawMessage) error Delete(ctx context.Context, id uint) error FindByID(ctx context.Context, id uint) (*User, error) FindByIDWithAuthorities(ctx context.Context, id uint) (*User, error) FindByUUID(ctx context.Context, uuid string) (*User, error) FindByUUIDWithAuthorities(ctx context.Context, uuid string) (*User, error) FindByUsername(ctx context.Context, username string) (*User, error) FindByUsernameWithAuthorities(ctx context.Context, username string) (*User, error) List(ctx context.Context, page, pageSize int, filters map[string]string) ([]*User, int64, error) UpdatePassword(ctx context.Context, id uint, password string) error UpdateAuthorityID(ctx context.Context, id uint, authorityId uint) error SetUserAuthorities(ctx context.Context, adminAuthorityID, userId uint, authorityIds []uint) error CheckUserHasAuthority(ctx context.Context, userId, authorityId uint) (bool, error) GetAuthorityMenuRouters(ctx context.Context, authorityId uint) ([]string, error) GetAuthorityDefaultRouter(ctx context.Context, authorityId uint) (string, error) } // UserUsecase 用户用例 type UserUsecase struct { repo UserRepo } // NewUserUsecase 创建用户用例 func NewUserUsecase(repo UserRepo) *UserUsecase { return &UserUsecase{repo: repo} } // Register 用户注册 func (uc *UserUsecase) Register(ctx context.Context, user *User) (*User, error) { // 检查用户名是否已存在 existing, _ := uc.repo.FindByUsername(ctx, user.Username) if existing != nil { return nil, ErrUserAlreadyExists } // 密码加密 hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost) if err != nil { return nil, err } user.Password = string(hashedPassword) user.UUID = uuid.New() if err := uc.repo.Create(ctx, user); err != nil { return nil, err } return user, nil } // Login 用户登录(预加载Authorities) func (uc *UserUsecase) Login(ctx context.Context, username, password string) (*User, error) { user, err := uc.repo.FindByUsernameWithAuthorities(ctx, username) if err != nil { return nil, ErrUserNotFound } if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil { return nil, ErrPasswordWrong } return user, nil } // ChangePassword 修改密码 func (uc *UserUsecase) ChangePassword(ctx context.Context, id uint, oldPassword, newPassword string) error { user, err := uc.repo.FindByID(ctx, id) if err != nil { return ErrUserNotFound } if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword)); err != nil { return ErrOldPasswordWrong } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost) if err != nil { return err } return uc.repo.UpdatePassword(ctx, id, string(hashedPassword)) } // ResetPassword 重置密码 func (uc *UserUsecase) ResetPassword(ctx context.Context, id uint, newPassword string) error { hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost) if err != nil { return err } return uc.repo.UpdatePassword(ctx, id, string(hashedPassword)) } // GetUserInfo 获取用户信息(预加载Authorities) func (uc *UserUsecase) GetUserInfo(ctx context.Context, uuid string) (*User, error) { return uc.repo.FindByUUIDWithAuthorities(ctx, uuid) } // GetUserByID 通过ID获取用户 func (uc *UserUsecase) GetUserByID(ctx context.Context, id uint) (*User, error) { return uc.repo.FindByID(ctx, id) } // FindUserById 通过ID获取用户(GVA兼容) func (uc *UserUsecase) FindUserById(ctx context.Context, id uint) (*User, error) { return uc.repo.FindByID(ctx, id) } // FindUserByUuid 通过UUID获取用户(GVA兼容) func (uc *UserUsecase) FindUserByUuid(ctx context.Context, uuid string) (*User, error) { return uc.repo.FindByUUID(ctx, uuid) } // GetUserList 获取用户列表 func (uc *UserUsecase) GetUserList(ctx context.Context, page, pageSize int, filters map[string]string) ([]*User, int64, error) { return uc.repo.List(ctx, page, pageSize, filters) } // SetUserInfo 设置用户信息(管理员用) func (uc *UserUsecase) SetUserInfo(ctx context.Context, user *User) error { return uc.repo.Update(ctx, user) } // SetSelfInfo 设置自己的信息(用户用) func (uc *UserUsecase) SetSelfInfo(ctx context.Context, user *User) error { return uc.repo.UpdateSelf(ctx, user) } // SetSelfSetting 设置自己的配置 func (uc *UserUsecase) SetSelfSetting(ctx context.Context, id uint, setting json.RawMessage) error { return uc.repo.UpdateSelfSetting(ctx, id, setting) } // DeleteUser 删除用户 func (uc *UserUsecase) DeleteUser(ctx context.Context, id uint) error { return uc.repo.Delete(ctx, id) } // SetUserAuthority 设置用户角色(切换角色) func (uc *UserUsecase) SetUserAuthority(ctx context.Context, id uint, authorityId uint) error { // 检查用户是否拥有该角色 hasAuthority, err := uc.repo.CheckUserHasAuthority(ctx, id, authorityId) if err != nil { return err } if !hasAuthority { return ErrUserNoAuthority } // 获取角色的默认路由 defaultRouter, err := uc.repo.GetAuthorityDefaultRouter(ctx, authorityId) if err != nil { return err } // 获取角色的菜单路由列表 menuRouters, err := uc.repo.GetAuthorityMenuRouters(ctx, authorityId) if err != nil { return err } // 检查默认路由是否在菜单中 hasMenu := false for _, router := range menuRouters { if router == defaultRouter { hasMenu = true break } } if !hasMenu { return ErrDefaultRouterEmpty } return uc.repo.UpdateAuthorityID(ctx, id, authorityId) } // SetUserAuthorities 设置用户多角色 func (uc *UserUsecase) SetUserAuthorities(ctx context.Context, adminAuthorityID, userId uint, authorityIds []uint) error { return uc.repo.SetUserAuthorities(ctx, adminAuthorityID, userId, authorityIds) }