feat: backend core - auth, user, role, permission, device, webhook, monitoring, cache, repository, service, middleware, API handlers
This commit is contained in:
319
internal/service/custom_field.go
Normal file
319
internal/service/custom_field.go
Normal file
@@ -0,0 +1,319 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/user-management-system/internal/domain"
|
||||
"github.com/user-management-system/internal/repository"
|
||||
)
|
||||
|
||||
// CustomFieldService 自定义字段服务
|
||||
type CustomFieldService struct {
|
||||
fieldRepo *repository.CustomFieldRepository
|
||||
valueRepo *repository.UserCustomFieldValueRepository
|
||||
}
|
||||
|
||||
// NewCustomFieldService 创建自定义字段服务
|
||||
func NewCustomFieldService(
|
||||
fieldRepo *repository.CustomFieldRepository,
|
||||
valueRepo *repository.UserCustomFieldValueRepository,
|
||||
) *CustomFieldService {
|
||||
return &CustomFieldService{
|
||||
fieldRepo: fieldRepo,
|
||||
valueRepo: valueRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateFieldRequest 创建字段请求
|
||||
type CreateFieldRequest struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
FieldKey string `json:"field_key" binding:"required"`
|
||||
Type int `json:"type" binding:"required"`
|
||||
Required bool `json:"required"`
|
||||
Default string `json:"default"`
|
||||
MinLen int `json:"min_len"`
|
||||
MaxLen int `json:"max_len"`
|
||||
MinVal float64 `json:"min_val"`
|
||||
MaxVal float64 `json:"max_val"`
|
||||
Options string `json:"options"`
|
||||
Sort int `json:"sort"`
|
||||
}
|
||||
|
||||
// UpdateFieldRequest 更新字段请求
|
||||
type UpdateFieldRequest struct {
|
||||
Name string `json:"name"`
|
||||
Type int `json:"type"`
|
||||
Required *bool `json:"required"`
|
||||
Default string `json:"default"`
|
||||
MinLen int `json:"min_len"`
|
||||
MaxLen int `json:"max_len"`
|
||||
MinVal float64 `json:"min_val"`
|
||||
MaxVal float64 `json:"max_val"`
|
||||
Options string `json:"options"`
|
||||
Sort int `json:"sort"`
|
||||
Status *int `json:"status"`
|
||||
}
|
||||
|
||||
// CreateField 创建自定义字段
|
||||
func (s *CustomFieldService) CreateField(ctx context.Context, req *CreateFieldRequest) (*domain.CustomField, error) {
|
||||
// 检查field_key是否已存在
|
||||
existing, err := s.fieldRepo.GetByFieldKey(ctx, req.FieldKey)
|
||||
if err == nil && existing != nil {
|
||||
return nil, errors.New("字段标识符已存在")
|
||||
}
|
||||
|
||||
field := &domain.CustomField{
|
||||
Name: req.Name,
|
||||
FieldKey: req.FieldKey,
|
||||
Type: domain.CustomFieldType(req.Type),
|
||||
Required: req.Required,
|
||||
DefaultVal: req.Default,
|
||||
MinLen: req.MinLen,
|
||||
MaxLen: req.MaxLen,
|
||||
MinVal: req.MinVal,
|
||||
MaxVal: req.MaxVal,
|
||||
Options: req.Options,
|
||||
Sort: req.Sort,
|
||||
Status: 1,
|
||||
}
|
||||
|
||||
if err := s.fieldRepo.Create(ctx, field); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return field, nil
|
||||
}
|
||||
|
||||
// UpdateField 更新自定义字段
|
||||
func (s *CustomFieldService) UpdateField(ctx context.Context, id int64, req *UpdateFieldRequest) (*domain.CustomField, error) {
|
||||
field, err := s.fieldRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, errors.New("字段不存在")
|
||||
}
|
||||
|
||||
if req.Name != "" {
|
||||
field.Name = req.Name
|
||||
}
|
||||
if req.Type > 0 {
|
||||
field.Type = domain.CustomFieldType(req.Type)
|
||||
}
|
||||
if req.Required != nil {
|
||||
field.Required = *req.Required
|
||||
}
|
||||
if req.Default != "" {
|
||||
field.DefaultVal = req.Default
|
||||
}
|
||||
if req.MinLen > 0 {
|
||||
field.MinLen = req.MinLen
|
||||
}
|
||||
if req.MaxLen > 0 {
|
||||
field.MaxLen = req.MaxLen
|
||||
}
|
||||
if req.MinVal > 0 {
|
||||
field.MinVal = req.MinVal
|
||||
}
|
||||
if req.MaxVal > 0 {
|
||||
field.MaxVal = req.MaxVal
|
||||
}
|
||||
if req.Options != "" {
|
||||
field.Options = req.Options
|
||||
}
|
||||
if req.Sort > 0 {
|
||||
field.Sort = req.Sort
|
||||
}
|
||||
if req.Status != nil {
|
||||
field.Status = *req.Status
|
||||
}
|
||||
|
||||
if err := s.fieldRepo.Update(ctx, field); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return field, nil
|
||||
}
|
||||
|
||||
// DeleteField 删除自定义字段
|
||||
func (s *CustomFieldService) DeleteField(ctx context.Context, id int64) error {
|
||||
field, err := s.fieldRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("字段不存在")
|
||||
}
|
||||
|
||||
// 删除字段定义
|
||||
if err := s.fieldRepo.Delete(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 清理用户的该字段值(可选,取决于业务需求)
|
||||
_ = field
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetField 获取自定义字段
|
||||
func (s *CustomFieldService) GetField(ctx context.Context, id int64) (*domain.CustomField, error) {
|
||||
return s.fieldRepo.GetByID(ctx, id)
|
||||
}
|
||||
|
||||
// ListFields 获取所有启用的自定义字段
|
||||
func (s *CustomFieldService) ListFields(ctx context.Context) ([]*domain.CustomField, error) {
|
||||
return s.fieldRepo.List(ctx)
|
||||
}
|
||||
|
||||
// ListAllFields 获取所有自定义字段
|
||||
func (s *CustomFieldService) ListAllFields(ctx context.Context) ([]*domain.CustomField, error) {
|
||||
return s.fieldRepo.ListAll(ctx)
|
||||
}
|
||||
|
||||
// SetUserFieldValue 设置用户的自定义字段值
|
||||
func (s *CustomFieldService) SetUserFieldValue(ctx context.Context, userID int64, fieldKey string, value string) error {
|
||||
// 获取字段定义
|
||||
field, err := s.fieldRepo.GetByFieldKey(ctx, fieldKey)
|
||||
if err != nil {
|
||||
return errors.New("字段不存在")
|
||||
}
|
||||
|
||||
// 验证值
|
||||
if err := s.validateFieldValue(field, value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.valueRepo.Set(ctx, userID, field.ID, fieldKey, value)
|
||||
}
|
||||
|
||||
// BatchSetUserFieldValues 批量设置用户的自定义字段值
|
||||
func (s *CustomFieldService) BatchSetUserFieldValues(ctx context.Context, userID int64, values map[string]string) error {
|
||||
// 获取所有启用的字段定义
|
||||
fields, err := s.fieldRepo.List(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fieldMap := make(map[string]*domain.CustomField)
|
||||
for _, f := range fields {
|
||||
fieldMap[f.FieldKey] = f
|
||||
}
|
||||
|
||||
// 验证每个值
|
||||
for fieldKey, value := range values {
|
||||
field, ok := fieldMap[fieldKey]
|
||||
if !ok {
|
||||
return fmt.Errorf("字段不存在: %s", fieldKey)
|
||||
}
|
||||
if err := s.validateFieldValue(field, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 批量设置值
|
||||
return s.valueRepo.BatchSet(ctx, userID, values)
|
||||
}
|
||||
|
||||
// GetUserFieldValues 获取用户的所有自定义字段值
|
||||
func (s *CustomFieldService) GetUserFieldValues(ctx context.Context, userID int64) ([]*domain.CustomFieldValueResponse, error) {
|
||||
// 获取所有启用的字段定义
|
||||
fields, err := s.fieldRepo.List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取用户的字段值
|
||||
values, err := s.valueRepo.GetByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 构建字段值映射
|
||||
valueMap := make(map[int64]*domain.UserCustomFieldValue)
|
||||
for _, v := range values {
|
||||
valueMap[v.FieldID] = v
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
fieldMap := make(map[string]*domain.CustomField)
|
||||
for _, f := range fields {
|
||||
fieldMap[f.FieldKey] = f
|
||||
}
|
||||
|
||||
var result []*domain.CustomFieldValueResponse
|
||||
for _, field := range fields {
|
||||
resp := &domain.CustomFieldValueResponse{
|
||||
FieldKey: field.FieldKey,
|
||||
}
|
||||
|
||||
if val, ok := valueMap[field.ID]; ok {
|
||||
resp.Value = val.GetValueAsInterface(field)
|
||||
} else if field.DefaultVal != "" {
|
||||
resp.Value = field.DefaultVal
|
||||
} else {
|
||||
resp.Value = nil
|
||||
}
|
||||
|
||||
result = append(result, resp)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// DeleteUserFieldValue 删除用户的自定义字段值
|
||||
func (s *CustomFieldService) DeleteUserFieldValue(ctx context.Context, userID int64, fieldKey string) error {
|
||||
field, err := s.fieldRepo.GetByFieldKey(ctx, fieldKey)
|
||||
if err != nil {
|
||||
return errors.New("字段不存在")
|
||||
}
|
||||
|
||||
return s.valueRepo.Delete(ctx, userID, field.ID)
|
||||
}
|
||||
|
||||
// validateFieldValue 验证字段值
|
||||
func (s *CustomFieldService) validateFieldValue(field *domain.CustomField, value string) error {
|
||||
// 检查必填
|
||||
if field.Required && value == "" {
|
||||
return errors.New("字段值不能为空")
|
||||
}
|
||||
|
||||
// 如果值为空且有默认值,跳过验证
|
||||
if value == "" && field.DefaultVal != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch field.Type {
|
||||
case domain.CustomFieldTypeString:
|
||||
// 字符串长度验证
|
||||
if field.MinLen > 0 && len(value) < field.MinLen {
|
||||
return fmt.Errorf("值长度不能小于%d", field.MinLen)
|
||||
}
|
||||
if field.MaxLen > 0 && len(value) > field.MaxLen {
|
||||
return fmt.Errorf("值长度不能大于%d", field.MaxLen)
|
||||
}
|
||||
case domain.CustomFieldTypeNumber:
|
||||
// 数字验证
|
||||
numVal, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return errors.New("值必须是数字")
|
||||
}
|
||||
if field.MinVal > 0 && numVal < field.MinVal {
|
||||
return fmt.Errorf("值不能小于%.2f", field.MinVal)
|
||||
}
|
||||
if field.MaxVal > 0 && numVal > field.MaxVal {
|
||||
return fmt.Errorf("值不能大于%.2f", field.MaxVal)
|
||||
}
|
||||
case domain.CustomFieldTypeBoolean:
|
||||
// 布尔验证
|
||||
if value != "true" && value != "false" && value != "1" && value != "0" {
|
||||
return errors.New("值必须是布尔值(true/false/1/0)")
|
||||
}
|
||||
case domain.CustomFieldTypeDate:
|
||||
// 日期验证
|
||||
_, err := time.Parse("2006-01-02", value)
|
||||
if err != nil {
|
||||
return errors.New("值必须是有效的日期格式(YYYY-MM-DD)")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user