From 90bb1d017ebd1c080f30d0123295c35d7dddebdc Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Sat, 1 Nov 2025 16:57:58 +0800 Subject: [PATCH] fix comb form_config_service --- internal/app/app.go | 10 +- .../api/api_application_service.go | 2 +- .../api/services/form_config_service.go | 110 ++++++++++++++++-- .../api/services/form_config_service_test.go | 15 +-- 4 files changed, 112 insertions(+), 25 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index 5b29ae9..a8c6631 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -85,7 +85,7 @@ func (a *Application) Run() error { a.logger.Error("Failed to start container", zap.Error(err)) return err } - + a.logger.Info("Container started successfully, setting up graceful shutdown...") // 设置优雅关闭 @@ -232,7 +232,7 @@ func (a *Application) autoMigrate(db *gorm.DB) error { &financeEntities.AlipayOrder{}, &financeEntities.InvoiceApplication{}, &financeEntities.UserInvoiceInfo{}, - + // 产品域 &productEntities.Product{}, &productEntities.ProductPackageItem{}, @@ -240,18 +240,18 @@ func (a *Application) autoMigrate(db *gorm.DB) error { &productEntities.Subscription{}, &productEntities.ProductDocumentation{}, &productEntities.ProductApiConfig{}, - + // 文章域 &articleEntities.Article{}, &articleEntities.Category{}, &articleEntities.Tag{}, &articleEntities.ScheduledTask{}, - + // 统计域 &statisticsEntities.StatisticsMetric{}, &statisticsEntities.StatisticsDashboard{}, &statisticsEntities.StatisticsReport{}, - + // api &apiEntities.ApiUser{}, &apiEntities.ApiCall{}, diff --git a/internal/application/api/api_application_service.go b/internal/application/api/api_application_service.go index af2a584..5f5b36e 100644 --- a/internal/application/api/api_application_service.go +++ b/internal/application/api/api_application_service.go @@ -912,7 +912,7 @@ func (s *ApiApplicationServiceImpl) DecryptParams(ctx context.Context, userID st // GetFormConfig 获取指定API的表单配置 func (s *ApiApplicationServiceImpl) GetFormConfig(ctx context.Context, apiCode string) (*dto.FormConfigResponse, error) { // 调用领域服务获取表单配置 - config, err := s.formConfigService.GetFormConfig(apiCode) + config, err := s.formConfigService.GetFormConfig(ctx, apiCode) if err != nil { s.logger.Error("获取表单配置失败", zap.String("api_code", apiCode), zap.Error(err)) return nil, err diff --git a/internal/domains/api/services/form_config_service.go b/internal/domains/api/services/form_config_service.go index a2eaefe..cba6d6f 100644 --- a/internal/domains/api/services/form_config_service.go +++ b/internal/domains/api/services/form_config_service.go @@ -1,9 +1,11 @@ package services import ( + "context" "reflect" "strings" "tyapi-server/internal/domains/api/dto" + product_services "tyapi-server/internal/domains/product/services" ) // FormField 表单字段配置 @@ -26,21 +28,35 @@ type FormConfig struct { // FormConfigService 表单配置服务接口 type FormConfigService interface { - GetFormConfig(apiCode string) (*FormConfig, error) + GetFormConfig(ctx context.Context, apiCode string) (*FormConfig, error) } // FormConfigServiceImpl 表单配置服务实现 -type FormConfigServiceImpl struct{} +type FormConfigServiceImpl struct { + productManagementService *product_services.ProductManagementService +} // NewFormConfigService 创建表单配置服务 -func NewFormConfigService() FormConfigService { - return &FormConfigServiceImpl{} +func NewFormConfigService(productManagementService *product_services.ProductManagementService) FormConfigService { + return &FormConfigServiceImpl{ + productManagementService: productManagementService, + } +} + +// NewFormConfigServiceWithoutDependencies 创建表单配置服务(不注入依赖,用于测试) +func NewFormConfigServiceWithoutDependencies() FormConfigService { + return &FormConfigServiceImpl{ + productManagementService: nil, + } } // GetFormConfig 获取指定API的表单配置 -func (s *FormConfigServiceImpl) GetFormConfig(apiCode string) (*FormConfig, error) { +func (s *FormConfigServiceImpl) GetFormConfig(ctx context.Context, apiCode string) (*FormConfig, error) { // 根据API代码获取对应的DTO结构体 - dtoStruct := s.getDTOStruct(apiCode) + dtoStruct, err := s.getDTOStruct(ctx, apiCode) + if err != nil { + return nil, err + } if dtoStruct == nil { return nil, nil } @@ -57,7 +73,7 @@ func (s *FormConfigServiceImpl) GetFormConfig(apiCode string) (*FormConfig, erro } // getDTOStruct 根据API代码获取对应的DTO结构体 -func (s *FormConfigServiceImpl) getDTOStruct(apiCode string) interface{} { +func (s *FormConfigServiceImpl) getDTOStruct(ctx context.Context, apiCode string) (interface{}, error) { // 建立API代码到DTO结构体的映射 dtoMap := map[string]interface{}{ "IVYZ9363": &dto.IVYZ9363Req{}, @@ -158,17 +174,16 @@ func (s *FormConfigServiceImpl) getDTOStruct(apiCode string) interface{} { // 优先返回已配置的DTO if dto, exists := dtoMap[apiCode]; exists { - return dto + return dto, nil } // 检查是否为通用组合包(COMB开头且未单独配置) if len(apiCode) >= 4 && apiCode[:4] == "COMB" { - // 对于通用组合包,返回一个通用的空结构体,表示无需特定参数验证 - // 因为组合包的参数验证由各个子处理器负责 - return &struct{}{} + // 动态从数据库获取组合包的子产品信息,并合并DTO + return s.mergeCombPackageDTOs(ctx, apiCode, dtoMap) } - return nil + return nil, nil } // parseDTOFields 通过反射解析DTO结构体字段 @@ -451,3 +466,74 @@ func (s *FormConfigServiceImpl) generateDescription(jsonTag string, validation s return "请输入" + s.generateFieldLabel(jsonTag) } + +// mergeCombPackageDTOs 动态合并组合包的子产品DTO结构体 +func (s *FormConfigServiceImpl) mergeCombPackageDTOs(ctx context.Context, apiCode string, dtoMap map[string]interface{}) (interface{}, error) { + // 如果productManagementService为nil(测试环境),返回空结构体 + if s.productManagementService == nil { + return &struct{}{}, nil + } + + // 1. 从数据库获取组合包产品信息 + packageProduct, err := s.productManagementService.GetProductByCode(ctx, apiCode) + if err != nil { + // 如果获取失败,返回空结构体 + return &struct{}{}, nil + } + + // 2. 检查是否为组合包 + if !packageProduct.IsPackage { + return &struct{}{}, nil + } + + // 3. 获取组合包的所有子产品 + packageItems, err := s.productManagementService.GetPackageItems(ctx, packageProduct.ID) + if err != nil || len(packageItems) == 0 { + return &struct{}{}, nil + } + + // 4. 收集所有子产品的DTO字段并去重 + // 使用map记录已存在的字段,key为json tag + fieldMap := make(map[string]reflect.StructField) + + for _, item := range packageItems { + subProductCode := item.Product.Code + // 在dtoMap中查找子产品的DTO + if subDTO, exists := dtoMap[subProductCode]; exists { + // 解析DTO的字段 + dtoType := reflect.TypeOf(subDTO).Elem() + for i := 0; i < dtoType.NumField(); i++ { + field := dtoType.Field(i) + jsonTag := field.Tag.Get("json") + if jsonTag != "" && jsonTag != "-" { + // 去除omitempty等选项 + jsonTag = strings.Split(jsonTag, ",")[0] + // 如果字段不存在或已存在但新字段有required标记,则覆盖 + if existingField, exists := fieldMap[jsonTag]; !exists { + fieldMap[jsonTag] = field + } else { + // 如果新字段有required且旧字段没有,则用新字段 + newValidate := field.Tag.Get("validate") + oldValidate := existingField.Tag.Get("validate") + if strings.Contains(newValidate, "required") && !strings.Contains(oldValidate, "required") { + fieldMap[jsonTag] = field + } + } + } + } + } + } + + // 5. 动态创建结构体 + fields := make([]reflect.StructField, 0, len(fieldMap)) + for _, field := range fieldMap { + fields = append(fields, field) + } + + // 创建结构体类型 + structType := reflect.StructOf(fields) + + // 创建并返回结构体实例 + structValue := reflect.New(structType) + return structValue.Interface(), nil +} diff --git a/internal/domains/api/services/form_config_service_test.go b/internal/domains/api/services/form_config_service_test.go index 1d3910f..7711d3f 100644 --- a/internal/domains/api/services/form_config_service_test.go +++ b/internal/domains/api/services/form_config_service_test.go @@ -1,14 +1,15 @@ package services import ( + "context" "testing" ) func TestFormConfigService_GetFormConfig(t *testing.T) { - service := NewFormConfigService() + service := NewFormConfigServiceWithoutDependencies() // 测试获取存在的API配置 - config, err := service.GetFormConfig("IVYZ9363") + config, err := service.GetFormConfig(context.Background(), "IVYZ9363") if err != nil { t.Fatalf("获取表单配置失败: %v", err) } @@ -47,7 +48,7 @@ func TestFormConfigService_GetFormConfig(t *testing.T) { } // 测试获取不存在的API配置 - config, err = service.GetFormConfig("NONEXISTENT") + config, err = service.GetFormConfig(context.Background(), "NONEXISTENT") if err != nil { t.Fatalf("获取不存在的API配置不应返回错误: %v", err) } @@ -58,9 +59,9 @@ func TestFormConfigService_GetFormConfig(t *testing.T) { } func TestFormConfigService_FieldValidation(t *testing.T) { - service := NewFormConfigService() + service := NewFormConfigServiceWithoutDependencies() - config, err := service.GetFormConfig("FLXG3D56") + config, err := service.GetFormConfig(context.Background(), "FLXG3D56") if err != nil { t.Fatalf("获取表单配置失败: %v", err) } @@ -96,9 +97,9 @@ func TestFormConfigService_FieldValidation(t *testing.T) { } func TestFormConfigService_FieldLabels(t *testing.T) { - service := NewFormConfigService() + service := NewFormConfigServiceWithoutDependencies() - config, err := service.GetFormConfig("IVYZ9363") + config, err := service.GetFormConfig(context.Background(), "IVYZ9363") if err != nil { t.Fatalf("获取表单配置失败: %v", err) }