任务三

This commit is contained in:
Yvan
2026-01-07 11:53:56 +08:00
parent 05e12a2e2a
commit a017d93dbf
10 changed files with 1082 additions and 119 deletions
+233
View File
@@ -0,0 +1,233 @@
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)
}