package system import ( "context" "encoding/json" "errors" "kra/internal/biz/system" "kra/internal/data/model" "kra/internal/data/query" "github.com/google/uuid" "gorm.io/gorm" ) type userRepo struct { db *gorm.DB } // NewUserRepo 创建用户仓储 func NewUserRepo(db *gorm.DB) system.UserRepo { query.SetDefault(db) return &userRepo{db: db} } func (r *userRepo) Create(ctx context.Context, user *system.User) error { m := toBizUser(user) return query.SysUser.WithContext(ctx).Create(m) } func (r *userRepo) Update(ctx context.Context, user *system.User) error { _, err := query.SysUser.WithContext(ctx).Where(query.SysUser.ID.Eq(int64(user.ID))).Updates(map[string]any{ "nick_name": user.NickName, "header_img": user.HeaderImg, "phone": user.Phone, "email": user.Email, "enable": user.Enable, }) return err } func (r *userRepo) UpdateSelf(ctx context.Context, user *system.User) error { updates := map[string]any{} if user.NickName != "" { updates["nick_name"] = user.NickName } if user.HeaderImg != "" { updates["header_img"] = user.HeaderImg } if user.Phone != "" { updates["phone"] = user.Phone } if user.Email != "" { updates["email"] = user.Email } if user.SideMode != "" { updates["side_mode"] = user.SideMode } if user.BaseColor != "" { updates["base_color"] = user.BaseColor } if len(updates) == 0 { return nil } _, err := query.SysUser.WithContext(ctx).Where(query.SysUser.ID.Eq(int64(user.ID))).Updates(updates) return err } func (r *userRepo) UpdateSelfSetting(ctx context.Context, id uint, setting json.RawMessage) error { _, err := query.SysUser.WithContext(ctx).Where(query.SysUser.ID.Eq(int64(id))).Update(query.SysUser.OriginSetting, string(setting)) return err } 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 } return nil }) } func (r *userRepo) FindByID(ctx context.Context, id uint) (*system.User, error) { m, err := query.SysUser.WithContext(ctx).Where(query.SysUser.ID.Eq(int64(id))).First() if err != nil { return nil, err } return toModelUser(m), nil } 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 if err != nil { return nil, err } return toModelUserWithAuthorities(&m), nil } func (r *userRepo) FindByUUID(ctx context.Context, uuidStr string) (*system.User, error) { m, err := query.SysUser.WithContext(ctx).Where(query.SysUser.UUID.Eq(uuidStr)).First() if err != nil { return nil, err } return toModelUser(m), nil } 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 if err != nil { return nil, err } return toModelUserWithAuthorities(&m), nil } func (r *userRepo) FindByUsername(ctx context.Context, username string) (*system.User, error) { m, err := query.SysUser.WithContext(ctx).Where(query.SysUser.Username.Eq(username)).First() if err != nil { return nil, err } return toModelUser(m), nil } 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 if err != nil { return nil, err } 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{}) if v, ok := filters["username"]; ok && v != "" { db = db.Where("username LIKE ?", "%"+v+"%") } if v, ok := filters["nick_name"]; ok && v != "" { db = db.Where("nick_name LIKE ?", "%"+v+"%") } if v, ok := filters["phone"]; ok && v != "" { db = db.Where("phone LIKE ?", "%"+v+"%") } if v, ok := filters["email"]; ok && v != "" { db = db.Where("email LIKE ?", "%"+v+"%") } var total int64 if err := db.Count(&total).Error; 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 if err != nil { return nil, 0, err } users := make([]*system.User, len(list)) for i := range list { users[i] = toModelUserWithAuthorities(&list[i]) } return users, total, nil } func (r *userRepo) UpdatePassword(ctx context.Context, id uint, password string) error { return r.db.WithContext(ctx).Model(&model.SysUser{}).Where("id = ?", id).Update("password", password).Error } func (r *userRepo) UpdateAuthorityID(ctx context.Context, id uint, authorityId uint) error { return r.db.WithContext(ctx).Model(&model.SysUser{}).Where("id = ?", id).Update("authority_id", authorityId).Error } 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 } ua := &model.SysUserAuthority{ SysUserID: int64(userId), SysAuthorityAuthorityID: int64(aid), } if err := tx.Create(ua).Error; err != nil { return err } } // 更新用户默认角色 if len(authorityIds) > 0 { if err := tx.Model(&model.SysUser{}).Where("id = ?", userId).Update("authority_id", authorityIds[0]).Error; err != nil { return err } } return nil }) } // 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) { return errors.New("您没有权限分配该角色") } return err } return nil } func (r *userRepo) CheckUserHasAuthority(ctx context.Context, userId, authorityId uint) (bool, error) { var count int64 err := r.db.WithContext(ctx).Model(&model.SysUserAuthority{}). Where("sys_user_id = ? AND sys_authority_authority_id = ?", userId, authorityId). Count(&count).Error return count > 0, err } 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 } if len(authorityMenus) == 0 { return []string{}, nil } // 获取菜单ID menuIDs := make([]string, len(authorityMenus)) for i, am := range authorityMenus { menuIDs[i] = am.MenuID } // 获取菜单的name(路由) var menus []model.SysBaseMenu if err := r.db.WithContext(ctx).Where("id IN ?", menuIDs).Find(&menus).Error; err != nil { return nil, err } routers := make([]string, len(menus)) for i, m := range menus { if m.Name != nil { routers[i] = *m.Name } } return routers, nil } func (r *userRepo) GetAuthorityDefaultRouter(ctx context.Context, authorityId uint) (string, error) { var authority model.SysAuthority if err := r.db.WithContext(ctx).Where("authority_id = ?", authorityId).First(&authority).Error; err != nil { return "", err } if authority.DefaultRouter != nil { return *authority.DefaultRouter, nil } return "", nil } // 转换函数 func toBizUser(u *system.User) *model.SysUser { uuidStr := u.UUID.String() username := u.Username password := u.Password nickName := u.NickName headerImg := u.HeaderImg authorityID := int64(u.AuthorityId) phone := u.Phone email := u.Email enable := int64(u.Enable) return &model.SysUser{ ID: int64(u.ID), UUID: &uuidStr, Username: &username, Password: &password, NickName: &nickName, HeaderImg: &headerImg, AuthorityID: &authorityID, Phone: &phone, Email: &email, Enable: &enable, } } func toModelUser(m *model.SysUser) *system.User { u := &system.User{ID: uint(m.ID)} if m.UUID != nil { u.UUID, _ = uuid.Parse(*m.UUID) } if m.Username != nil { u.Username = *m.Username } if m.Password != nil { u.Password = *m.Password } 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) } if m.Phone != nil { u.Phone = *m.Phone } if m.Email != nil { u.Email = *m.Email } if m.Enable != nil { u.Enable = int(*m.Enable) } if m.OriginSetting != nil { u.OriginSetting = json.RawMessage(*m.OriginSetting) } if m.CreatedAt != nil { u.CreatedAt = *m.CreatedAt } if m.UpdatedAt != nil { u.UpdatedAt = *m.UpdatedAt } return u } 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 } } // 转换Authorities if len(m.Authorities) > 0 { u.Authorities = make([]*system.Authority, len(m.Authorities)) for i, a := range m.Authorities { u.Authorities[i] = &system.Authority{ AuthorityId: uint(a.AuthorityID), AuthorityName: safeString(a.AuthorityName), DefaultRouter: safeString(a.DefaultRouter), } if a.ParentID != nil { pid := uint(*a.ParentID) u.Authorities[i].ParentId = &pid } } } return u } func safeString(s *string) string { if s == nil { return "" } return *s }