package service import ( "context" "errors" "fmt" "giter.top/smart/internal/iam/entity" "giter.top/smart/internal/iam/repository" "giter.top/smart/pkg/utils/id" "golang.org/x/crypto/bcrypt" ) // UserService 用户 type UserService interface { Create(ctx context.Context, tenantID string, req *CreateUserRequest) (*entity.User, error) Update(ctx context.Context, tenantID string, uid string, req *UpdateUserRequest) (*entity.User, error) Delete(ctx context.Context, tenantID string, ids []string) error Get(ctx context.Context, tenantID string, uid string) (*entity.User, error) List(ctx context.Context, tenantID string, q *UserListQuery) (*UserListResponse, error) DataScopeForUser(ctx context.Context, userID string) (int16, error) } type CreateUserRequest struct { UserName string `json:"user_name" binding:"required,max=64"` Password string `json:"password" binding:"required,min=6,max=64"` RealName string `json:"real_name" binding:"max=64"` Phone string `json:"phone"` Email string `json:"email"` DeptID *string `json:"dept_id"` DeptIDs []string `json:"dept_ids"` RoleIDs []string `json:"role_ids"` } type UpdateUserRequest struct { RealName *string `json:"real_name"` Phone *string `json:"phone"` Email *string `json:"email"` DeptID *string `json:"dept_id"` DeptIDs []string `json:"dept_ids"` RoleIDs []string `json:"role_ids"` Status *int16 `json:"status"` Password *string `json:"password"` } type UserListQuery struct { DeptID *string RoleID *string Keyword string Status *int16 Page int PageSize int } type UserListResponse struct { Items []entity.User `json:"items"` Total int64 `json:"total"` Page int `json:"page"` PageSize int `json:"page_size"` TotalPages int `json:"total_pages"` } type userService struct { users repository.UserRepository roles repository.RoleRepository } func NewUserService(users repository.UserRepository, roles repository.RoleRepository) UserService { return &userService{users: users, roles: roles} } func (s *userService) Create(ctx context.Context, tenantID string, req *CreateUserRequest) (*entity.User, error) { ok, err := s.users.ExistsUserName(ctx, tenantID, req.UserName, "") if err != nil { return nil, err } if ok { return nil, fmt.Errorf("账号已存在") } hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) if err != nil { return nil, err } u := &entity.User{ ID: id.New(), TenantID: tenantID, UserName: req.UserName, RealName: req.RealName, Phone: req.Phone, Email: req.Email, PasswordHash: string(hash), Status: 1, } if req.DeptID != nil { u.DeptID = req.DeptID } if err := s.users.Create(ctx, u); err != nil { return nil, err } depts := req.DeptIDs primary := "" if req.DeptID != nil { primary = *req.DeptID } if len(depts) == 0 && primary != "" { depts = []string{primary} } if len(depts) > 0 { if primary == "" { primary = depts[0] } u.DeptID = &primary _ = s.users.Update(ctx, u) if err := s.users.ReplaceUserDepts(ctx, u.ID, primary, depts); err != nil { return nil, err } } if len(req.RoleIDs) > 0 { if err := s.users.ReplaceUserRoles(ctx, u.ID, req.RoleIDs); err != nil { return nil, err } } return u, nil } func (s *userService) Update(ctx context.Context, tenantID string, uid string, req *UpdateUserRequest) (*entity.User, error) { u, err := s.users.GetByID(ctx, uid) if err != nil { if errors.Is(err, repository.ErrNotFound) { return nil, fmt.Errorf("用户不存在") } return nil, err } if u.TenantID != tenantID { return nil, fmt.Errorf("用户不属于当前租户") } if req.RealName != nil { u.RealName = *req.RealName } if req.Phone != nil { u.Phone = *req.Phone } if req.Email != nil { u.Email = *req.Email } if req.Status != nil { u.Status = *req.Status } if req.Password != nil && *req.Password != "" { hash, err := bcrypt.GenerateFromPassword([]byte(*req.Password), bcrypt.DefaultCost) if err != nil { return nil, err } u.PasswordHash = string(hash) } if err := s.users.Update(ctx, u); err != nil { return nil, err } if req.DeptIDs != nil || req.DeptID != nil { depts := req.DeptIDs primary := "" if req.DeptID != nil { primary = *req.DeptID u.DeptID = req.DeptID _ = s.users.Update(ctx, u) } if len(depts) == 0 && primary != "" { depts = []string{primary} } if primary == "" && len(depts) > 0 { primary = depts[0] } if err := s.users.ReplaceUserDepts(ctx, u.ID, primary, depts); err != nil { return nil, err } } if req.RoleIDs != nil { if err := s.users.ReplaceUserRoles(ctx, u.ID, req.RoleIDs); err != nil { return nil, err } } return u, nil } func (s *userService) Delete(ctx context.Context, tenantID string, ids []string) error { for _, uid := range ids { u, err := s.users.GetByID(ctx, uid) if err != nil { return err } if u.TenantID != tenantID { return fmt.Errorf("用户 %s 不属于当前租户", uid) } if err := s.users.Delete(ctx, uid); err != nil { return err } } return nil } func (s *userService) Get(ctx context.Context, tenantID string, uid string) (*entity.User, error) { u, err := s.users.GetByID(ctx, uid) if err != nil { return nil, err } if u.TenantID != tenantID { return nil, fmt.Errorf("用户不属于当前租户") } return u, nil } func (s *userService) List(ctx context.Context, tenantID string, q *UserListQuery) (*UserListResponse, error) { if q.Page <= 0 { q.Page = 1 } if q.PageSize <= 0 { q.PageSize = 10 } rows, total, err := s.users.List(ctx, tenantID, q.DeptID, q.RoleID, q.Keyword, q.Status, q.Page, q.PageSize) if err != nil { return nil, err } tp := int(total) / q.PageSize if int(total)%q.PageSize != 0 { tp++ } return &UserListResponse{Items: rows, Total: total, Page: q.Page, PageSize: q.PageSize, TotalPages: tp}, nil } func (s *userService) DataScopeForUser(ctx context.Context, userID string) (int16, error) { roles, err := s.roles.ListRolesByUser(ctx, userID) if err != nil { return 0, err } scopes := make([]int16, 0, len(roles)) for _, r := range roles { scopes = append(scopes, r.DataScope) } return MergeDataScope(scopes), nil }