This commit is contained in:
2026-08-17 02:12:17 +08:00
parent 560ae46b82
commit 6a05803e08
96 changed files with 2888 additions and 685 deletions
+56 -42
View File
@@ -12,6 +12,7 @@ import (
"github.com/google/uuid"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
func (r *userRepo) FindUserByUsername(ctx context.Context, username string) (*biz.User, error) {
@@ -36,9 +37,20 @@ func (r *userRepo) FindUserByID(ctx context.Context, id uint) (*biz.User, error)
return r.loadUser(ctx, &po)
}
func (r *userRepo) FindUserByUUID(ctx context.Context, value string) (*biz.User, error) {
var po userPO
if err := r.data.gormDB.WithContext(ctx).Where("uuid = ?", value).First(&po).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, biz.ErrUserNotFound
}
return nil, err
}
return r.loadUser(ctx, &po)
}
func (r *userRepo) loadUser(ctx context.Context, po *userPO) (*biz.User, error) {
var authority authorityPO
if err := r.data.gormDB.WithContext(ctx).First(&authority, "authority_id = ?", po.AuthorityID).Error; err != nil {
if err := r.data.gormDB.WithContext(ctx).First(&authority, "authority_id = ?", po.AuthorityID).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
var authorityPOs []authorityPO
@@ -58,13 +70,17 @@ func (r *userRepo) loadUser(ctx context.Context, po *userPO) (*biz.User, error)
return nil, err
}
departments := make([]biz.Department, 0, len(departmentPOs))
var primary *biz.Department
for _, item := range departmentPOs {
value := deptFromPO(item)
departments = append(departments, *value)
if item.ID == po.DeptID {
copy := *value
primary = &copy
}
var primary *biz.Department
if po.DeptID != 0 {
var primaryPO departmentPO
if err := r.data.gormDB.WithContext(ctx).First(&primaryPO, po.DeptID).Error; err == nil {
primary = deptFromPO(primaryPO)
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
}
var positionPOs []positionPO
@@ -200,12 +216,21 @@ func (r *userRepo) loadUsers(ctx context.Context, pos []userPO) ([]*biz.User, er
return users, nil
}
func (r *userRepo) HasAuthorityMenu(ctx context.Context, authorityID uint, name string) (bool, error) {
var count int64
err := r.data.gormDB.WithContext(ctx).Model(&menuPO{}).
Joins("JOIN sys_authority_menus ON sys_authority_menus.sys_base_menu_id = sys_base_menus.id").
Where("sys_authority_menus.sys_authority_authority_id = ? AND sys_base_menus.name = ?", authorityID, name).
Count(&count).Error
return count > 0, err
}
func (r *userRepo) MenusByAuthority(ctx context.Context, authorityID uint) ([]*biz.Menu, error) {
var pos []menuPO
err := r.data.gormDB.WithContext(ctx).Table("sys_base_menus").
Joins("JOIN sys_authority_menus ON sys_authority_menus.sys_base_menu_id = sys_base_menus.id").
Where("sys_authority_menus.sys_authority_authority_id = ? AND sys_base_menus.deleted_at IS NULL", authorityID).
Order("sys_base_menus.sort asc, sys_base_menus.id asc").Scan(&pos).Error
Order("sys_base_menus.sort").Scan(&pos).Error
if err != nil {
return nil, err
}
@@ -214,15 +239,15 @@ func (r *userRepo) MenusByAuthority(ctx context.Context, authorityID uint) ([]*b
for _, po := range pos {
menu := menuFromPO(po)
menu.MenuID = po.ID
menu.Children = []*biz.Menu{}
menu.Children = nil
menu.Parameters = []*biz.MenuParameter{}
menu.Buttons = []*biz.MenuButton{}
menu.Buttons = nil
byID[po.ID] = menu
menuIDs = append(menuIDs, po.ID)
}
if len(menuIDs) > 0 {
var parameters []menuParameterPO
if err := r.data.gormDB.WithContext(ctx).Where("sys_base_menu_id IN ?", menuIDs).Order("id").Find(&parameters).Error; err != nil {
if err := r.data.gormDB.WithContext(ctx).Where("sys_base_menu_id IN ?", menuIDs).Find(&parameters).Error; err != nil {
return nil, err
}
for _, parameter := range parameters {
@@ -240,7 +265,7 @@ func (r *userRepo) MenusByAuthority(ctx context.Context, authorityID uint) ([]*b
menu.Buttons = append(menu.Buttons, value)
}
}
roots := make([]*biz.Menu, 0)
var roots []*biz.Menu
for _, po := range pos {
menu := byID[po.ID]
if parent := byID[po.ParentID]; parent != nil {
@@ -281,7 +306,7 @@ func (r *userRepo) ListUsers(ctx context.Context, page, pageSize int, filter *bi
return nil, 0, err
}
var pos []userPO
if err := applyPagination(db.Order(order), page, pageSize, 100).Find(&pos).Error; err != nil {
if err := applyRequiredPagination(db.Order(order), page, pageSize, 100).Find(&pos).Error; err != nil {
return nil, 0, err
}
users, err := r.loadUsers(ctx, pos)
@@ -307,9 +332,7 @@ func (r *userRepo) CreateUserWithAuthorities(ctx context.Context, user *biz.User
}
now := time.Now()
po := userPO{UUID: user.UUID, Username: user.Username, Password: user.Password, NickName: user.NickName, HeaderImg: user.HeaderImg, AuthorityID: user.AuthorityID, Phone: user.Phone, Email: user.Email, Enable: user.Enable, PasswordUpdatedAt: &now, MustChangePassword: user.MustChangePassword}
if len(authorityIDs) == 0 {
authorityIDs = []uint{user.AuthorityID}
}
var createdAuthorities []biz.Authority
if err := r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// The compatible registration rejects an existing non-deleted username before creating the
// account. The username column is intentionally not unique for legacy
@@ -321,34 +344,36 @@ func (r *userRepo) CreateUserWithAuthorities(ctx context.Context, user *biz.User
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
if err := validateAuthorities(tx, authorityIDs); err != nil {
return err
}
if err := tx.Create(&po).Error; err != nil {
return err
}
if len(authorityIDs) == 0 {
return nil
}
links := make([]userAuthorityPO, 0, len(authorityIDs))
for _, authorityID := range authorityIDs {
// Creating a user through the compatible administration endpoint lets
// GORM save the many-to-many authority values supplied by the request.
// With an ID-only value this is an upsert: an existing role is left
// untouched, while a missing role is materialized with model defaults.
associated := authorityPO{AuthorityID: authorityID}
if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&associated).Error; err != nil {
return err
}
createdAuthorities = append(createdAuthorities, toBizAuthority(associated))
links = append(links, userAuthorityPO{SysUserID: po.ID, SysAuthorityAuthorityID: authorityID})
}
return tx.Create(&links).Error
}); err != nil {
return nil, err
}
return r.FindUserByID(ctx, po.ID)
}
func validateAuthorities(tx *gorm.DB, authorityIDs []uint) error {
for _, authorityID := range authorityIDs {
var count int64
if err := tx.Model(&authorityPO{}).Where("authority_id = ?", authorityID).Count(&count).Error; err != nil {
return err
}
if count == 0 {
return errors.New("角色不存在")
}
}
return nil
// Registration returns the just-created entity, not a second hydrated
// query. The reference handler returns the request's authority IDs and
// leaves related authority/department records at their zero values; keep
// that response contract while retaining the persisted timestamps/UUID.
created := baseBizUser(&po)
created.Authorities = createdAuthorities
return created, nil
}
func (r *userRepo) UpdateUser(ctx context.Context, user *biz.User) error {
@@ -416,14 +441,6 @@ func (r *userRepo) FillDepartmentNamePaths(ctx context.Context, user *biz.User)
parts = append(parts, user.Departments[i].Name)
user.Departments[i].NamePath = strings.Join(parts, "/")
}
if user.Department != nil {
for i := range user.Departments {
if user.Departments[i].ID == user.Department.ID {
user.Department.NamePath = user.Departments[i].NamePath
break
}
}
}
return nil
}
@@ -504,9 +521,6 @@ func setUserAuthorities(tx *gorm.DB, id uint, authorityIDs []uint) error {
if len(authorityIDs) == 0 {
return errors.New("角色不能为空")
}
if err := validateAuthorities(tx, authorityIDs); err != nil {
return err
}
if err := tx.Where("sys_user_id = ?", id).Delete(&userAuthorityPO{}).Error; err != nil {
return err
}