feat: 优化web

This commit is contained in:
2026-04-23 18:58:13 +08:00
commit 544a2f3428
160 changed files with 27327 additions and 0 deletions
+240
View File
@@ -0,0 +1,240 @@
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
}