任务三

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
+5 -2
View File
@@ -1,6 +1,9 @@
package biz
import "github.com/google/wire"
import (
"github.com/google/wire"
"kra/internal/biz/system"
)
// ProviderSet is biz providers.
var ProviderSet = wire.NewSet(NewAdminUsecase)
var ProviderSet = wire.NewSet(system.NewUserUsecase)
+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)
}
+2
View File
@@ -28,6 +28,8 @@ type SysUser struct {
Email *string `gorm:"column:email;type:varchar(191);comment:用户邮箱" json:"email"` // 用户邮箱
Enable *int64 `gorm:"column:enable;type:bigint(20);default:1;comment:用户是否被冻结 1正常 2冻结" json:"enable"` // 用户是否被冻结 1正常 2冻结
OriginSetting *string `gorm:"column:origin_setting;type:text;comment:配置" json:"origin_setting"` // 配置
Authority SysAuthority `gorm:"foreignKey:AuthorityID;references:AuthorityID" json:"authority"`
Authorities []SysAuthority `gorm:"joinForeignKey:SysUserID;joinReferences:SysAuthorityAuthorityID;many2many:sys_user_authority" json:"authorities"`
}
// TableName SysUser's table name
+184 -1
View File
@@ -42,6 +42,17 @@ func newSysUser(db *gorm.DB, opts ...gen.DOOption) sysUser {
_sysUser.Email = field.NewString(tableName, "email")
_sysUser.Enable = field.NewInt64(tableName, "enable")
_sysUser.OriginSetting = field.NewString(tableName, "origin_setting")
_sysUser.Authority = sysUserHasOneAuthority{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Authority", "model.SysAuthority"),
}
_sysUser.Authorities = sysUserManyToManyAuthorities{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Authorities", "model.SysAuthority"),
}
_sysUser.fillFieldMap()
@@ -66,6 +77,9 @@ type sysUser struct {
Email field.String // 用户邮箱
Enable field.Int64 // 用户是否被冻结 1正常 2冻结
OriginSetting field.String // 配置
Authority sysUserHasOneAuthority
Authorities sysUserManyToManyAuthorities
fieldMap map[string]field.Expr
}
@@ -120,7 +134,7 @@ func (s *sysUser) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
}
func (s *sysUser) fillFieldMap() {
s.fieldMap = make(map[string]field.Expr, 14)
s.fieldMap = make(map[string]field.Expr, 16)
s.fieldMap["id"] = s.ID
s.fieldMap["created_at"] = s.CreatedAt
s.fieldMap["updated_at"] = s.UpdatedAt
@@ -135,18 +149,187 @@ func (s *sysUser) fillFieldMap() {
s.fieldMap["email"] = s.Email
s.fieldMap["enable"] = s.Enable
s.fieldMap["origin_setting"] = s.OriginSetting
}
func (s sysUser) clone(db *gorm.DB) sysUser {
s.sysUserDo.ReplaceConnPool(db.Statement.ConnPool)
s.Authority.db = db.Session(&gorm.Session{Initialized: true})
s.Authority.db.Statement.ConnPool = db.Statement.ConnPool
s.Authorities.db = db.Session(&gorm.Session{Initialized: true})
s.Authorities.db.Statement.ConnPool = db.Statement.ConnPool
return s
}
func (s sysUser) replaceDB(db *gorm.DB) sysUser {
s.sysUserDo.ReplaceDB(db)
s.Authority.db = db.Session(&gorm.Session{})
s.Authorities.db = db.Session(&gorm.Session{})
return s
}
type sysUserHasOneAuthority struct {
db *gorm.DB
field.RelationField
}
func (a sysUserHasOneAuthority) Where(conds ...field.Expr) *sysUserHasOneAuthority {
if len(conds) == 0 {
return &a
}
exprs := make([]clause.Expression, 0, len(conds))
for _, cond := range conds {
exprs = append(exprs, cond.BeCond().(clause.Expression))
}
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
return &a
}
func (a sysUserHasOneAuthority) WithContext(ctx context.Context) *sysUserHasOneAuthority {
a.db = a.db.WithContext(ctx)
return &a
}
func (a sysUserHasOneAuthority) Session(session *gorm.Session) *sysUserHasOneAuthority {
a.db = a.db.Session(session)
return &a
}
func (a sysUserHasOneAuthority) Model(m *model.SysUser) *sysUserHasOneAuthorityTx {
return &sysUserHasOneAuthorityTx{a.db.Model(m).Association(a.Name())}
}
func (a sysUserHasOneAuthority) Unscoped() *sysUserHasOneAuthority {
a.db = a.db.Unscoped()
return &a
}
type sysUserHasOneAuthorityTx struct{ tx *gorm.Association }
func (a sysUserHasOneAuthorityTx) Find() (result *model.SysAuthority, err error) {
return result, a.tx.Find(&result)
}
func (a sysUserHasOneAuthorityTx) Append(values ...*model.SysAuthority) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a sysUserHasOneAuthorityTx) Replace(values ...*model.SysAuthority) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a sysUserHasOneAuthorityTx) Delete(values ...*model.SysAuthority) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a sysUserHasOneAuthorityTx) Clear() error {
return a.tx.Clear()
}
func (a sysUserHasOneAuthorityTx) Count() int64 {
return a.tx.Count()
}
func (a sysUserHasOneAuthorityTx) Unscoped() *sysUserHasOneAuthorityTx {
a.tx = a.tx.Unscoped()
return &a
}
type sysUserManyToManyAuthorities struct {
db *gorm.DB
field.RelationField
}
func (a sysUserManyToManyAuthorities) Where(conds ...field.Expr) *sysUserManyToManyAuthorities {
if len(conds) == 0 {
return &a
}
exprs := make([]clause.Expression, 0, len(conds))
for _, cond := range conds {
exprs = append(exprs, cond.BeCond().(clause.Expression))
}
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
return &a
}
func (a sysUserManyToManyAuthorities) WithContext(ctx context.Context) *sysUserManyToManyAuthorities {
a.db = a.db.WithContext(ctx)
return &a
}
func (a sysUserManyToManyAuthorities) Session(session *gorm.Session) *sysUserManyToManyAuthorities {
a.db = a.db.Session(session)
return &a
}
func (a sysUserManyToManyAuthorities) Model(m *model.SysUser) *sysUserManyToManyAuthoritiesTx {
return &sysUserManyToManyAuthoritiesTx{a.db.Model(m).Association(a.Name())}
}
func (a sysUserManyToManyAuthorities) Unscoped() *sysUserManyToManyAuthorities {
a.db = a.db.Unscoped()
return &a
}
type sysUserManyToManyAuthoritiesTx struct{ tx *gorm.Association }
func (a sysUserManyToManyAuthoritiesTx) Find() (result []*model.SysAuthority, err error) {
return result, a.tx.Find(&result)
}
func (a sysUserManyToManyAuthoritiesTx) Append(values ...*model.SysAuthority) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a sysUserManyToManyAuthoritiesTx) Replace(values ...*model.SysAuthority) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a sysUserManyToManyAuthoritiesTx) Delete(values ...*model.SysAuthority) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a sysUserManyToManyAuthoritiesTx) Clear() error {
return a.tx.Clear()
}
func (a sysUserManyToManyAuthoritiesTx) Count() int64 {
return a.tx.Count()
}
func (a sysUserManyToManyAuthoritiesTx) Unscoped() *sysUserManyToManyAuthoritiesTx {
a.tx = a.tx.Unscoped()
return &a
}
type sysUserDo struct{ gen.DO }
type ISysUserDo interface {
+38 -62
View File
@@ -73,11 +73,9 @@ func (r *userRepo) UpdateSelfSetting(ctx context.Context, id uint, setting json.
func (r *userRepo) Delete(ctx context.Context, id uint) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// 删除用户
if err := tx.Where("id = ?", id).Delete(&model.SysUser{}).Error; err != nil {
return err
}
// 删除用户角色关联
if err := tx.Where("sys_user_id = ?", id).Delete(&model.SysUserAuthority{}).Error; err != nil {
return err
}
@@ -94,16 +92,15 @@ func (r *userRepo) FindByID(ctx context.Context, id uint) (*system.User, error)
}
func (r *userRepo) FindByIDWithAuthorities(ctx context.Context, id uint) (*system.User, error) {
var m model.SysUser
err := r.db.WithContext(ctx).
Preload("Authorities").
Preload("Authority").
Where("id = ?", id).
First(&m).Error
m, err := query.SysUser.WithContext(ctx).
Preload(query.SysUser.Authority).
Preload(query.SysUser.Authorities).
Where(query.SysUser.ID.Eq(int64(id))).
First()
if err != nil {
return nil, err
}
return toModelUserWithAuthorities(&m), nil
return toModelUserWithAuthorities(m), nil
}
func (r *userRepo) FindByUUID(ctx context.Context, uuidStr string) (*system.User, error) {
@@ -115,16 +112,15 @@ func (r *userRepo) FindByUUID(ctx context.Context, uuidStr string) (*system.User
}
func (r *userRepo) FindByUUIDWithAuthorities(ctx context.Context, uuidStr string) (*system.User, error) {
var m model.SysUser
err := r.db.WithContext(ctx).
Preload("Authorities").
Preload("Authority").
Where("uuid = ?", uuidStr).
First(&m).Error
m, err := query.SysUser.WithContext(ctx).
Preload(query.SysUser.Authority).
Preload(query.SysUser.Authorities).
Where(query.SysUser.UUID.Eq(uuidStr)).
First()
if err != nil {
return nil, err
}
return toModelUserWithAuthorities(&m), nil
return toModelUserWithAuthorities(m), nil
}
func (r *userRepo) FindByUsername(ctx context.Context, username string) (*system.User, error) {
@@ -136,49 +132,48 @@ func (r *userRepo) FindByUsername(ctx context.Context, username string) (*system
}
func (r *userRepo) FindByUsernameWithAuthorities(ctx context.Context, username string) (*system.User, error) {
var m model.SysUser
err := r.db.WithContext(ctx).
Preload("Authorities").
Preload("Authority").
Where("username = ?", username).
First(&m).Error
m, err := query.SysUser.WithContext(ctx).
Preload(query.SysUser.Authority).
Preload(query.SysUser.Authorities).
Where(query.SysUser.Username.Eq(username)).
First()
if err != nil {
return nil, err
}
return toModelUserWithAuthorities(&m), nil
return toModelUserWithAuthorities(m), nil
}
func (r *userRepo) List(ctx context.Context, page, pageSize int, filters map[string]string) ([]*system.User, int64, error) {
db := r.db.WithContext(ctx).Model(&model.SysUser{})
u := query.SysUser
q := u.WithContext(ctx)
if v, ok := filters["username"]; ok && v != "" {
db = db.Where("username LIKE ?", "%"+v+"%")
q = q.Where(u.Username.Like("%" + v + "%"))
}
if v, ok := filters["nick_name"]; ok && v != "" {
db = db.Where("nick_name LIKE ?", "%"+v+"%")
q = q.Where(u.NickName.Like("%" + v + "%"))
}
if v, ok := filters["phone"]; ok && v != "" {
db = db.Where("phone LIKE ?", "%"+v+"%")
q = q.Where(u.Phone.Like("%" + v + "%"))
}
if v, ok := filters["email"]; ok && v != "" {
db = db.Where("email LIKE ?", "%"+v+"%")
q = q.Where(u.Email.Like("%" + v + "%"))
}
var total int64
if err := db.Count(&total).Error; err != nil {
total, err := q.Count()
if err != nil {
return nil, 0, err
}
var list []model.SysUser
offset := (page - 1) * pageSize
err := db.Preload("Authorities").Preload("Authority").Offset(offset).Limit(pageSize).Find(&list).Error
list, err := q.Preload(u.Authority).Preload(u.Authorities).Offset(offset).Limit(pageSize).Find()
if err != nil {
return nil, 0, err
}
users := make([]*system.User, len(list))
for i := range list {
users[i] = toModelUserWithAuthorities(&list[i])
users[i] = toModelUserWithAuthorities(list[i])
}
return users, total, nil
}
@@ -193,20 +188,16 @@ func (r *userRepo) UpdateAuthorityID(ctx context.Context, id uint, authorityId u
func (r *userRepo) SetUserAuthorities(ctx context.Context, adminAuthorityID, userId uint, authorityIds []uint) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// 查询用户是否存在
var user model.SysUser
if err := tx.Where("id = ?", userId).First(&user).Error; err != nil {
return errors.New("查询用户数据失败")
}
// 删除旧的用户角色关联
if err := tx.Where("sys_user_id = ?", userId).Delete(&model.SysUserAuthority{}).Error; err != nil {
return err
}
// 检查管理员权限并创建新的用户角色关联
for _, aid := range authorityIds {
// 检查管理员是否有权限分配该角色
if err := checkAuthorityIDAuth(tx, adminAuthorityID, aid); err != nil {
return err
}
@@ -219,7 +210,6 @@ func (r *userRepo) SetUserAuthorities(ctx context.Context, adminAuthorityID, use
}
}
// 更新用户默认角色
if len(authorityIds) > 0 {
if err := tx.Model(&model.SysUser{}).Where("id = ?", userId).Update("authority_id", authorityIds[0]).Error; err != nil {
return err
@@ -229,13 +219,10 @@ func (r *userRepo) SetUserAuthorities(ctx context.Context, adminAuthorityID, use
})
}
// checkAuthorityIDAuth 检查管理员是否有权限分配该角色
func checkAuthorityIDAuth(tx *gorm.DB, adminAuthorityID, targetAuthorityID uint) error {
// 如果是超级管理员(888),直接通过
if adminAuthorityID == 888 {
return nil
}
// 检查目标角色是否是管理员的子角色
var authority model.SysAuthority
if err := tx.Where("authority_id = ? AND parent_id = ?", targetAuthorityID, adminAuthorityID).First(&authority).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
@@ -255,7 +242,6 @@ func (r *userRepo) CheckUserHasAuthority(ctx context.Context, userId, authorityI
}
func (r *userRepo) GetAuthorityMenuRouters(ctx context.Context, authorityId uint) ([]string, error) {
// 获取角色的菜单ID列表
var authorityMenus []model.SysAuthorityMenu
if err := r.db.WithContext(ctx).Where("sys_authority_authority_id = ?", authorityId).Find(&authorityMenus).Error; err != nil {
return nil, err
@@ -265,13 +251,11 @@ func (r *userRepo) GetAuthorityMenuRouters(ctx context.Context, authorityId uint
return []string{}, nil
}
// 获取菜单ID
menuIDs := make([]string, len(authorityMenus))
menuIDs := make([]int64, len(authorityMenus))
for i, am := range authorityMenus {
menuIDs[i] = am.MenuID
menuIDs[i] = am.SysBaseMenuID
}
// 获取菜单的name(路由)
var menus []model.SysBaseMenu
if err := r.db.WithContext(ctx).Where("id IN ?", menuIDs).Find(&menus).Error; err != nil {
return nil, err
@@ -337,15 +321,9 @@ func toModelUser(m *model.SysUser) *system.User {
if m.NickName != nil {
u.NickName = *m.NickName
}
if m.SideMode != nil {
u.SideMode = *m.SideMode
}
if m.HeaderImg != nil {
u.HeaderImg = *m.HeaderImg
}
if m.BaseColor != nil {
u.BaseColor = *m.BaseColor
}
if m.AuthorityID != nil {
u.AuthorityId = uint(*m.AuthorityID)
}
@@ -374,16 +352,14 @@ func toModelUserWithAuthorities(m *model.SysUser) *system.User {
u := toModelUser(m)
// 转换Authority
if m.Authority != nil {
u.Authority = &system.Authority{
AuthorityId: uint(m.Authority.AuthorityID),
AuthorityName: safeString(m.Authority.AuthorityName),
DefaultRouter: safeString(m.Authority.DefaultRouter),
}
if m.Authority.ParentID != nil {
pid := uint(*m.Authority.ParentID)
u.Authority.ParentId = &pid
}
u.Authority = &system.Authority{
AuthorityId: uint(m.Authority.AuthorityID),
AuthorityName: safeString(m.Authority.AuthorityName),
DefaultRouter: safeString(m.Authority.DefaultRouter),
}
if m.Authority.ParentID != nil {
pid := uint(*m.Authority.ParentID)
u.Authority.ParentId = &pid
}
// 转换Authorities
+1 -1
View File
@@ -3,4 +3,4 @@ package service
import "github.com/google/wire"
// ProviderSet is service providers.
var ProviderSet = wire.NewSet(NewAdminService)
var ProviderSet = wire.NewSet()
+558
View File
@@ -0,0 +1,558 @@
package system
import (
"context"
"encoding/json"
"kra/internal/biz/system"
"kra/internal/server/middleware"
"kra/pkg/jwt"
"github.com/go-kratos/kratos/v2/errors"
"github.com/go-kratos/kratos/v2/transport/http"
)
// UserService 用户服务
type UserService struct {
uc *system.UserUsecase
jwtPkg *jwt.JWT
}
// NewUserService 创建用户服务
func NewUserService(uc *system.UserUsecase, jwtPkg *jwt.JWT) *UserService {
return &UserService{uc: uc, jwtPkg: jwtPkg}
}
// LoginRequest 登录请求
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
Captcha string `json:"captcha"`
CaptchaId string `json:"captchaId"`
}
// LoginResponse 登录响应
type LoginResponse struct {
User *UserInfo `json:"user"`
Token string `json:"token"`
ExpiresAt int64 `json:"expiresAt"`
}
// UserInfo 用户信息
type UserInfo struct {
ID uint `json:"id"`
UUID string `json:"uuid"`
Username string `json:"username"`
NickName string `json:"nickName"`
SideMode string `json:"sideMode"`
HeaderImg string `json:"headerImg"`
BaseColor string `json:"baseColor"`
AuthorityId uint `json:"authorityId"`
Phone string `json:"phone"`
Email string `json:"email"`
Enable int `json:"enable"`
OriginSetting json.RawMessage `json:"originSetting,omitempty"`
Authority *AuthorityInfo `json:"authority,omitempty"`
Authorities []*AuthorityInfo `json:"authorities,omitempty"`
}
// AuthorityInfo 角色信息
type AuthorityInfo struct {
AuthorityId uint `json:"authorityId"`
AuthorityName string `json:"authorityName"`
ParentId *uint `json:"parentId,omitempty"`
DefaultRouter string `json:"defaultRouter"`
}
// Login 用户登录
func (s *UserService) Login(ctx context.Context, req *LoginRequest) (*LoginResponse, error) {
user, err := s.uc.Login(ctx, req.Username, req.Password)
if err != nil {
return nil, errors.Unauthorized("LOGIN_FAILED", err.Error())
}
if user.Enable != 1 {
return nil, errors.Forbidden("USER_DISABLED", "用户被禁止登录")
}
// 生成 JWT token
claims := s.jwtPkg.CreateClaims(jwt.BaseClaims{
UUID: user.UUID.String(),
ID: uint(user.ID),
Username: user.Username,
NickName: user.NickName,
AuthorityID: user.AuthorityId,
})
token, err := s.jwtPkg.CreateToken(claims.BaseClaims)
if err != nil {
return nil, errors.InternalServer("TOKEN_ERROR", "生成token失败")
}
return &LoginResponse{
User: toUserInfo(user),
Token: token,
ExpiresAt: claims.ExpiresAt.UnixMilli(),
}, nil
}
// RegisterRequest 注册请求
type RegisterRequest struct {
Username string `json:"username"`
Password string `json:"password"`
NickName string `json:"nickName"`
HeaderImg string `json:"headerImg"`
AuthorityId uint `json:"authorityId"`
AuthorityIds []uint `json:"authorityIds"`
Phone string `json:"phone"`
Email string `json:"email"`
Enable int `json:"enable"`
}
// Register 用户注册
func (s *UserService) Register(ctx context.Context, req *RegisterRequest) (*UserInfo, error) {
user := &system.User{
Username: req.Username,
Password: req.Password,
NickName: req.NickName,
HeaderImg: req.HeaderImg,
AuthorityId: req.AuthorityId,
Phone: req.Phone,
Email: req.Email,
Enable: req.Enable,
}
created, err := s.uc.Register(ctx, user)
if err != nil {
return nil, errors.BadRequest("REGISTER_FAILED", err.Error())
}
return toUserInfo(created), nil
}
// ChangePasswordRequest 修改密码请求
type ChangePasswordRequest struct {
Password string `json:"password"`
NewPassword string `json:"newPassword"`
}
// ChangePassword 修改密码
func (s *UserService) ChangePassword(ctx context.Context, userID uint, req *ChangePasswordRequest) error {
return s.uc.ChangePassword(ctx, userID, req.Password, req.NewPassword)
}
// ResetPasswordRequest 重置密码请求
type ResetPasswordRequest struct {
ID uint `json:"id"`
Password string `json:"password"`
}
// ResetPassword 重置密码
func (s *UserService) ResetPassword(ctx context.Context, req *ResetPasswordRequest) error {
return s.uc.ResetPassword(ctx, req.ID, req.Password)
}
// GetUserInfo 获取用户信息
func (s *UserService) GetUserInfo(ctx context.Context, uuid string) (*UserInfo, error) {
user, err := s.uc.GetUserInfo(ctx, uuid)
if err != nil {
return nil, errors.NotFound("USER_NOT_FOUND", err.Error())
}
return toUserInfo(user), nil
}
// GetUserListRequest 获取用户列表请求
type GetUserListRequest struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
Username string `json:"username"`
NickName string `json:"nickName"`
Phone string `json:"phone"`
Email string `json:"email"`
}
// GetUserListResponse 获取用户列表响应
type GetUserListResponse struct {
List []*UserInfo `json:"list"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
}
// GetUserList 获取用户列表
func (s *UserService) GetUserList(ctx context.Context, req *GetUserListRequest) (*GetUserListResponse, error) {
filters := make(map[string]string)
if req.Username != "" {
filters["username"] = req.Username
}
if req.NickName != "" {
filters["nick_name"] = req.NickName
}
if req.Phone != "" {
filters["phone"] = req.Phone
}
if req.Email != "" {
filters["email"] = req.Email
}
users, total, err := s.uc.GetUserList(ctx, req.Page, req.PageSize, filters)
if err != nil {
return nil, errors.InternalServer("LIST_ERROR", err.Error())
}
list := make([]*UserInfo, len(users))
for i, u := range users {
list[i] = toUserInfo(u)
}
return &GetUserListResponse{
List: list,
Total: total,
Page: req.Page,
PageSize: req.PageSize,
}, nil
}
// SetUserInfoRequest 设置用户信息请求(管理员用)
type SetUserInfoRequest struct {
ID uint `json:"id"`
NickName string `json:"nickName"`
HeaderImg string `json:"headerImg"`
Phone string `json:"phone"`
Email string `json:"email"`
Enable int `json:"enable"`
AuthorityIds []uint `json:"authorityIds"`
}
// SetUserInfo 设置用户信息
func (s *UserService) SetUserInfo(ctx context.Context, req *SetUserInfoRequest) error {
user := &system.User{
ID: req.ID,
NickName: req.NickName,
HeaderImg: req.HeaderImg,
Phone: req.Phone,
Email: req.Email,
Enable: req.Enable,
}
return s.uc.SetUserInfo(ctx, user)
}
// SetSelfInfoRequest 设置自己信息请求(用户用)
type SetSelfInfoRequest struct {
NickName string `json:"nickName"`
HeaderImg string `json:"headerImg"`
Phone string `json:"phone"`
Email string `json:"email"`
SideMode string `json:"sideMode"`
BaseColor string `json:"baseColor"`
}
// SetSelfInfo 设置自己的信息
func (s *UserService) SetSelfInfo(ctx context.Context, userID uint, req *SetSelfInfoRequest) error {
user := &system.User{
ID: userID,
NickName: req.NickName,
HeaderImg: req.HeaderImg,
Phone: req.Phone,
Email: req.Email,
SideMode: req.SideMode,
BaseColor: req.BaseColor,
}
return s.uc.SetSelfInfo(ctx, user)
}
// SetSelfSetting 设置自己的配置
func (s *UserService) SetSelfSetting(ctx context.Context, userID uint, setting json.RawMessage) error {
return s.uc.SetSelfSetting(ctx, userID, setting)
}
// DeleteUser 删除用户
func (s *UserService) DeleteUser(ctx context.Context, id uint) error {
return s.uc.DeleteUser(ctx, id)
}
// SetUserAuthorityRequest 设置用户角色请求
type SetUserAuthorityRequest struct {
AuthorityId uint `json:"authorityId"`
}
// SetUserAuthority 设置用户角色(切换角色)
func (s *UserService) SetUserAuthority(ctx context.Context, userID uint, req *SetUserAuthorityRequest) error {
return s.uc.SetUserAuthority(ctx, userID, req.AuthorityId)
}
// SetUserAuthoritiesRequest 设置用户多角色请求
type SetUserAuthoritiesRequest struct {
ID uint `json:"id"`
AuthorityIds []uint `json:"authorityIds"`
}
// SetUserAuthorities 设置用户多角色
func (s *UserService) SetUserAuthorities(ctx context.Context, adminAuthorityID uint, req *SetUserAuthoritiesRequest) error {
return s.uc.SetUserAuthorities(ctx, adminAuthorityID, req.ID, req.AuthorityIds)
}
// 转换函数
func toUserInfo(u *system.User) *UserInfo {
info := &UserInfo{
ID: u.ID,
UUID: u.UUID.String(),
Username: u.Username,
NickName: u.NickName,
SideMode: u.SideMode,
HeaderImg: u.HeaderImg,
BaseColor: u.BaseColor,
AuthorityId: u.AuthorityId,
Phone: u.Phone,
Email: u.Email,
Enable: u.Enable,
OriginSetting: u.OriginSetting,
}
if u.Authority != nil {
info.Authority = &AuthorityInfo{
AuthorityId: u.Authority.AuthorityId,
AuthorityName: u.Authority.AuthorityName,
ParentId: u.Authority.ParentId,
DefaultRouter: u.Authority.DefaultRouter,
}
}
if len(u.Authorities) > 0 {
info.Authorities = make([]*AuthorityInfo, len(u.Authorities))
for i, a := range u.Authorities {
info.Authorities[i] = &AuthorityInfo{
AuthorityId: a.AuthorityId,
AuthorityName: a.AuthorityName,
ParentId: a.ParentId,
DefaultRouter: a.DefaultRouter,
}
}
}
return info
}
// RegisterRoutes 注册路由
func (s *UserService) RegisterRoutes(srv *http.Server) {
r := srv.Route("/")
// 公开接口
r.POST("/base/login", s.handleLogin)
// 需要认证的接口
r.POST("/user/register", s.handleRegister)
r.POST("/user/changePassword", s.handleChangePassword)
r.POST("/user/resetPassword", s.handleResetPassword)
r.GET("/user/getUserInfo", s.handleGetUserInfo)
r.POST("/user/getUserList", s.handleGetUserList)
r.PUT("/user/setUserInfo", s.handleSetUserInfo)
r.PUT("/user/setSelfInfo", s.handleSetSelfInfo)
r.PUT("/user/setSelfSetting", s.handleSetSelfSetting)
r.DELETE("/user/deleteUser", s.handleDeleteUser)
r.POST("/user/setUserAuthority", s.handleSetUserAuthority)
r.POST("/user/setUserAuthorities", s.handleSetUserAuthorities)
}
// HTTP Handlers
func (s *UserService) handleLogin(ctx http.Context) error {
var req LoginRequest
if err := ctx.Bind(&req); err != nil {
return err
}
resp, err := s.Login(ctx, &req)
if err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "登录成功",
"data": resp,
})
}
func (s *UserService) handleRegister(ctx http.Context) error {
var req RegisterRequest
if err := ctx.Bind(&req); err != nil {
return err
}
resp, err := s.Register(ctx, &req)
if err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "注册成功",
"data": resp,
})
}
func (s *UserService) handleChangePassword(ctx http.Context) error {
var req ChangePasswordRequest
if err := ctx.Bind(&req); err != nil {
return err
}
userID := middleware.GetUserID(ctx)
if userID == 0 {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
if err := s.ChangePassword(ctx, userID, &req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "修改成功",
})
}
func (s *UserService) handleResetPassword(ctx http.Context) error {
var req ResetPasswordRequest
if err := ctx.Bind(&req); err != nil {
return err
}
if err := s.ResetPassword(ctx, &req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "重置成功",
})
}
func (s *UserService) handleGetUserInfo(ctx http.Context) error {
claims, ok := middleware.GetClaims(ctx)
if !ok {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
resp, err := s.GetUserInfo(ctx, claims.UUID)
if err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "获取成功",
"data": map[string]any{"userInfo": resp},
})
}
func (s *UserService) handleGetUserList(ctx http.Context) error {
var req GetUserListRequest
if err := ctx.Bind(&req); err != nil {
return err
}
resp, err := s.GetUserList(ctx, &req)
if err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "获取成功",
"data": resp,
})
}
func (s *UserService) handleSetUserInfo(ctx http.Context) error {
var req SetUserInfoRequest
if err := ctx.Bind(&req); err != nil {
return err
}
if err := s.SetUserInfo(ctx, &req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "设置成功",
})
}
func (s *UserService) handleSetSelfInfo(ctx http.Context) error {
var req SetSelfInfoRequest
if err := ctx.Bind(&req); err != nil {
return err
}
userID := middleware.GetUserID(ctx)
if userID == 0 {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
if err := s.SetSelfInfo(ctx, userID, &req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "设置成功",
})
}
func (s *UserService) handleSetSelfSetting(ctx http.Context) error {
var req json.RawMessage
if err := ctx.Bind(&req); err != nil {
return err
}
userID := middleware.GetUserID(ctx)
if userID == 0 {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
if err := s.SetSelfSetting(ctx, userID, req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "设置成功",
})
}
func (s *UserService) handleDeleteUser(ctx http.Context) error {
var req struct {
ID uint `json:"id"`
}
if err := ctx.Bind(&req); err != nil {
return err
}
// 不能删除自己
userID := middleware.GetUserID(ctx)
if userID == req.ID {
return errors.BadRequest("DELETE_SELF", "删除失败, 无法删除自己")
}
if err := s.DeleteUser(ctx, req.ID); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "删除成功",
})
}
func (s *UserService) handleSetUserAuthority(ctx http.Context) error {
var req SetUserAuthorityRequest
if err := ctx.Bind(&req); err != nil {
return err
}
userID := middleware.GetUserID(ctx)
if userID == 0 {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
if err := s.SetUserAuthority(ctx, userID, &req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "修改成功",
})
}
func (s *UserService) handleSetUserAuthorities(ctx http.Context) error {
var req SetUserAuthoritiesRequest
if err := ctx.Bind(&req); err != nil {
return err
}
adminAuthorityID := middleware.GetAuthorityID(ctx)
if adminAuthorityID == 0 {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
if err := s.SetUserAuthorities(ctx, adminAuthorityID, &req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "修改成功",
})
}