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))
|
a.logger.Error("Failed to start container", zap.Error(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.logger.Info("Container started successfully, setting up graceful shutdown...")
|
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.AlipayOrder{},
|
||||||
&financeEntities.InvoiceApplication{},
|
&financeEntities.InvoiceApplication{},
|
||||||
&financeEntities.UserInvoiceInfo{},
|
&financeEntities.UserInvoiceInfo{},
|
||||||
|
|
||||||
// 产品域
|
// 产品域
|
||||||
&productEntities.Product{},
|
&productEntities.Product{},
|
||||||
&productEntities.ProductPackageItem{},
|
&productEntities.ProductPackageItem{},
|
||||||
@@ -240,18 +240,18 @@ func (a *Application) autoMigrate(db *gorm.DB) error {
|
|||||||
&productEntities.Subscription{},
|
&productEntities.Subscription{},
|
||||||
&productEntities.ProductDocumentation{},
|
&productEntities.ProductDocumentation{},
|
||||||
&productEntities.ProductApiConfig{},
|
&productEntities.ProductApiConfig{},
|
||||||
|
|
||||||
// 文章域
|
// 文章域
|
||||||
&articleEntities.Article{},
|
&articleEntities.Article{},
|
||||||
&articleEntities.Category{},
|
&articleEntities.Category{},
|
||||||
&articleEntities.Tag{},
|
&articleEntities.Tag{},
|
||||||
&articleEntities.ScheduledTask{},
|
&articleEntities.ScheduledTask{},
|
||||||
|
|
||||||
// 统计域
|
// 统计域
|
||||||
&statisticsEntities.StatisticsMetric{},
|
&statisticsEntities.StatisticsMetric{},
|
||||||
&statisticsEntities.StatisticsDashboard{},
|
&statisticsEntities.StatisticsDashboard{},
|
||||||
&statisticsEntities.StatisticsReport{},
|
&statisticsEntities.StatisticsReport{},
|
||||||
|
|
||||||
// api
|
// api
|
||||||
&apiEntities.ApiUser{},
|
&apiEntities.ApiUser{},
|
||||||
&apiEntities.ApiCall{},
|
&apiEntities.ApiCall{},
|
||||||
|
|||||||
@@ -912,7 +912,7 @@ func (s *ApiApplicationServiceImpl) DecryptParams(ctx context.Context, userID st
|
|||||||
// GetFormConfig 获取指定API的表单配置
|
// GetFormConfig 获取指定API的表单配置
|
||||||
func (s *ApiApplicationServiceImpl) GetFormConfig(ctx context.Context, apiCode string) (*dto.FormConfigResponse, error) {
|
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 {
|
if err != nil {
|
||||||
s.logger.Error("获取表单配置失败", zap.String("api_code", apiCode), zap.Error(err))
|
s.logger.Error("获取表单配置失败", zap.String("api_code", apiCode), zap.Error(err))
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"tyapi-server/internal/domains/api/dto"
|
"tyapi-server/internal/domains/api/dto"
|
||||||
|
product_services "tyapi-server/internal/domains/product/services"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FormField 表单字段配置
|
// FormField 表单字段配置
|
||||||
@@ -26,21 +28,35 @@ type FormConfig struct {
|
|||||||
|
|
||||||
// FormConfigService 表单配置服务接口
|
// FormConfigService 表单配置服务接口
|
||||||
type FormConfigService interface {
|
type FormConfigService interface {
|
||||||
GetFormConfig(apiCode string) (*FormConfig, error)
|
GetFormConfig(ctx context.Context, apiCode string) (*FormConfig, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FormConfigServiceImpl 表单配置服务实现
|
// FormConfigServiceImpl 表单配置服务实现
|
||||||
type FormConfigServiceImpl struct{}
|
type FormConfigServiceImpl struct {
|
||||||
|
productManagementService *product_services.ProductManagementService
|
||||||
|
}
|
||||||
|
|
||||||
// NewFormConfigService 创建表单配置服务
|
// NewFormConfigService 创建表单配置服务
|
||||||
func NewFormConfigService() FormConfigService {
|
func NewFormConfigService(productManagementService *product_services.ProductManagementService) FormConfigService {
|
||||||
return &FormConfigServiceImpl{}
|
return &FormConfigServiceImpl{
|
||||||
|
productManagementService: productManagementService,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFormConfigServiceWithoutDependencies 创建表单配置服务(不注入依赖,用于测试)
|
||||||
|
func NewFormConfigServiceWithoutDependencies() FormConfigService {
|
||||||
|
return &FormConfigServiceImpl{
|
||||||
|
productManagementService: nil,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFormConfig 获取指定API的表单配置
|
// GetFormConfig 获取指定API的表单配置
|
||||||
func (s *FormConfigServiceImpl) GetFormConfig(apiCode string) (*FormConfig, error) {
|
func (s *FormConfigServiceImpl) GetFormConfig(ctx context.Context, apiCode string) (*FormConfig, error) {
|
||||||
// 根据API代码获取对应的DTO结构体
|
// 根据API代码获取对应的DTO结构体
|
||||||
dtoStruct := s.getDTOStruct(apiCode)
|
dtoStruct, err := s.getDTOStruct(ctx, apiCode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if dtoStruct == nil {
|
if dtoStruct == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -57,7 +73,7 @@ func (s *FormConfigServiceImpl) GetFormConfig(apiCode string) (*FormConfig, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getDTOStruct 根据API代码获取对应的DTO结构体
|
// getDTOStruct 根据API代码获取对应的DTO结构体
|
||||||
func (s *FormConfigServiceImpl) getDTOStruct(apiCode string) interface{} {
|
func (s *FormConfigServiceImpl) getDTOStruct(ctx context.Context, apiCode string) (interface{}, error) {
|
||||||
// 建立API代码到DTO结构体的映射
|
// 建立API代码到DTO结构体的映射
|
||||||
dtoMap := map[string]interface{}{
|
dtoMap := map[string]interface{}{
|
||||||
"IVYZ9363": &dto.IVYZ9363Req{},
|
"IVYZ9363": &dto.IVYZ9363Req{},
|
||||||
@@ -158,17 +174,16 @@ func (s *FormConfigServiceImpl) getDTOStruct(apiCode string) interface{} {
|
|||||||
|
|
||||||
// 优先返回已配置的DTO
|
// 优先返回已配置的DTO
|
||||||
if dto, exists := dtoMap[apiCode]; exists {
|
if dto, exists := dtoMap[apiCode]; exists {
|
||||||
return dto
|
return dto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否为通用组合包(COMB开头且未单独配置)
|
// 检查是否为通用组合包(COMB开头且未单独配置)
|
||||||
if len(apiCode) >= 4 && apiCode[:4] == "COMB" {
|
if len(apiCode) >= 4 && apiCode[:4] == "COMB" {
|
||||||
// 对于通用组合包,返回一个通用的空结构体,表示无需特定参数验证
|
// 动态从数据库获取组合包的子产品信息,并合并DTO
|
||||||
// 因为组合包的参数验证由各个子处理器负责
|
return s.mergeCombPackageDTOs(ctx, apiCode, dtoMap)
|
||||||
return &struct{}{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseDTOFields 通过反射解析DTO结构体字段
|
// parseDTOFields 通过反射解析DTO结构体字段
|
||||||
@@ -451,3 +466,74 @@ func (s *FormConfigServiceImpl) generateDescription(jsonTag string, validation s
|
|||||||
|
|
||||||
return "请输入" + s.generateFieldLabel(jsonTag)
|
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
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFormConfigService_GetFormConfig(t *testing.T) {
|
func TestFormConfigService_GetFormConfig(t *testing.T) {
|
||||||
service := NewFormConfigService()
|
service := NewFormConfigServiceWithoutDependencies()
|
||||||
|
|
||||||
// 测试获取存在的API配置
|
// 测试获取存在的API配置
|
||||||
config, err := service.GetFormConfig("IVYZ9363")
|
config, err := service.GetFormConfig(context.Background(), "IVYZ9363")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("获取表单配置失败: %v", err)
|
t.Fatalf("获取表单配置失败: %v", err)
|
||||||
}
|
}
|
||||||
@@ -47,7 +48,7 @@ func TestFormConfigService_GetFormConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 测试获取不存在的API配置
|
// 测试获取不存在的API配置
|
||||||
config, err = service.GetFormConfig("NONEXISTENT")
|
config, err = service.GetFormConfig(context.Background(), "NONEXISTENT")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("获取不存在的API配置不应返回错误: %v", err)
|
t.Fatalf("获取不存在的API配置不应返回错误: %v", err)
|
||||||
}
|
}
|
||||||
@@ -58,9 +59,9 @@ func TestFormConfigService_GetFormConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFormConfigService_FieldValidation(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 {
|
if err != nil {
|
||||||
t.Fatalf("获取表单配置失败: %v", err)
|
t.Fatalf("获取表单配置失败: %v", err)
|
||||||
}
|
}
|
||||||
@@ -96,9 +97,9 @@ func TestFormConfigService_FieldValidation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFormConfigService_FieldLabels(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 {
|
if err != nil {
|
||||||
t.Fatalf("获取表单配置失败: %v", err)
|
t.Fatalf("获取表单配置失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user