package services import ( "errors" "fmt" "strings" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" "git.beifan.cn/trace-system/backend-go/database" "git.beifan.cn/trace-system/backend-go/models" ) // UsersService 用户管理服务 type UsersService struct{} func toUserDTO(user models.User) models.UserDTO { return models.UserDTO{ ID: user.ID, Username: user.Username, Name: user.Name, Email: user.Email, Role: user.Role, CreatedAt: user.CreatedAt, } } // Create 创建用户 func (s *UsersService) Create(dto models.CreateUserDTO) (*models.UserDTO, error) { username := strings.TrimSpace(dto.Username) var existing models.User err := database.DB.Where("username = ?", username).First(&existing).Error if err == nil { return nil, errors.New("用户名已存在") } if !errors.Is(err, gorm.ErrRecordNotFound) { return nil, fmt.Errorf("查询用户失败: %w", err) } hashed, err := bcrypt.GenerateFromPassword([]byte(dto.Password), bcrypt.DefaultCost) if err != nil { return nil, fmt.Errorf("密码加密失败: %w", err) } user := models.User{ Username: username, Password: string(hashed), Name: dto.Name, Email: dto.Email, Role: dto.Role, } if err := database.DB.Create(&user).Error; err != nil { return nil, fmt.Errorf("创建用户失败: %w", err) } dtoOut := toUserDTO(user) return &dtoOut, nil } // FindAll 分页 + 按角色过滤 func (s *UsersService) FindAll(page int, limit int, role string, search string) ([]models.UserDTO, int, int, error) { var users []models.User var total int64 db := database.DB.Model(&models.User{}) if role != "" { db = db.Where("role = ?", role) } if search != "" { pattern := "%" + search + "%" db = db.Where("username LIKE ? OR name LIKE ? OR email LIKE ?", pattern, pattern, pattern) } if err := db.Count(&total).Error; err != nil { return nil, 0, 0, fmt.Errorf("统计用户数失败: %w", err) } offset := (page - 1) * limit if err := db.Order("created_at DESC").Offset(offset).Limit(limit).Find(&users).Error; err != nil { return nil, 0, 0, fmt.Errorf("查询用户列表失败: %w", err) } result := make([]models.UserDTO, 0, len(users)) for _, u := range users { result = append(result, toUserDTO(u)) } totalPages := (int(total) + limit - 1) / limit return result, int(total), totalPages, nil } // FindAssignable 获取可分配的用户(admin + technician),用于售后工单分配 func (s *UsersService) FindAssignable() ([]models.UserDTO, error) { var users []models.User if err := database.DB.Where("role IN ?", []string{"admin", "technician"}). Order("role DESC, created_at ASC").Find(&users).Error; err != nil { return nil, fmt.Errorf("查询可分配用户失败: %w", err) } result := make([]models.UserDTO, 0, len(users)) for _, u := range users { result = append(result, toUserDTO(u)) } return result, nil } // Update 更新用户信息(不含密码) func (s *UsersService) Update(userId uint, dto models.UpdateUserDTO, currentUserId uint) (*models.UserDTO, error) { var user models.User if err := database.DB.First(&user, userId).Error; err != nil { return nil, errors.New("用户不存在") } if dto.Name != "" { user.Name = dto.Name } if dto.Email != "" { user.Email = dto.Email } if dto.Role != "" { // 防止管理员把自己降级 if user.ID == currentUserId && user.Role == "admin" && dto.Role != "admin" { return nil, errors.New("不能修改自己的管理员角色") } user.Role = dto.Role } if err := database.DB.Save(&user).Error; err != nil { return nil, fmt.Errorf("更新用户失败: %w", err) } dtoOut := toUserDTO(user) return &dtoOut, nil } // ResetPassword 管理员重置用户密码 func (s *UsersService) ResetPassword(userId uint, newPassword string) error { var user models.User if err := database.DB.First(&user, userId).Error; err != nil { return errors.New("用户不存在") } hashed, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost) if err != nil { return fmt.Errorf("密码加密失败: %w", err) } user.Password = string(hashed) if err := database.DB.Save(&user).Error; err != nil { return fmt.Errorf("重置密码失败: %w", err) } return nil } // Delete 删除用户 func (s *UsersService) Delete(userId uint, currentUserId uint) error { if userId == currentUserId { return errors.New("不能删除自己") } var user models.User if err := database.DB.First(&user, userId).Error; err != nil { return errors.New("用户不存在") } if user.Role == "admin" { // 防止删除最后一个 admin var adminCount int64 database.DB.Model(&models.User{}).Where("role = ?", "admin").Count(&adminCount) if adminCount <= 1 { return errors.New("不能删除最后一个管理员") } } if err := database.DB.Delete(&user).Error; err != nil { return fmt.Errorf("删除用户失败: %w", err) } return nil }