fix comb form_config_service
This commit is contained in:
@@ -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{},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user