2025-08-27 22:19:19 +08:00
|
|
|
|
package services
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2025-11-01 16:57:58 +08:00
|
|
|
|
"context"
|
2025-08-27 22:19:19 +08:00
|
|
|
|
"reflect"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
"tyapi-server/internal/domains/api/dto"
|
2025-11-01 16:57:58 +08:00
|
|
|
|
product_services "tyapi-server/internal/domains/product/services"
|
2025-08-27 22:19:19 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// FormField 表单字段配置
|
|
|
|
|
|
type FormField struct {
|
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
|
Label string `json:"label"`
|
|
|
|
|
|
Type string `json:"type"`
|
|
|
|
|
|
Required bool `json:"required"`
|
|
|
|
|
|
Validation string `json:"validation"`
|
|
|
|
|
|
Description string `json:"description"`
|
|
|
|
|
|
Example string `json:"example"`
|
|
|
|
|
|
Placeholder string `json:"placeholder"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// FormConfig 表单配置
|
|
|
|
|
|
type FormConfig struct {
|
2025-10-16 18:46:44 +08:00
|
|
|
|
ApiCode string `json:"api_code"`
|
2025-08-27 22:19:19 +08:00
|
|
|
|
Fields []FormField `json:"fields"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// FormConfigService 表单配置服务接口
|
|
|
|
|
|
type FormConfigService interface {
|
2025-11-01 16:57:58 +08:00
|
|
|
|
GetFormConfig(ctx context.Context, apiCode string) (*FormConfig, error)
|
2025-08-27 22:19:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// FormConfigServiceImpl 表单配置服务实现
|
2025-11-01 16:57:58 +08:00
|
|
|
|
type FormConfigServiceImpl struct {
|
|
|
|
|
|
productManagementService *product_services.ProductManagementService
|
|
|
|
|
|
}
|
2025-08-27 22:19:19 +08:00
|
|
|
|
|
|
|
|
|
|
// NewFormConfigService 创建表单配置服务
|
2025-11-01 16:57:58 +08:00
|
|
|
|
func NewFormConfigService(productManagementService *product_services.ProductManagementService) FormConfigService {
|
|
|
|
|
|
return &FormConfigServiceImpl{
|
|
|
|
|
|
productManagementService: productManagementService,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewFormConfigServiceWithoutDependencies 创建表单配置服务(不注入依赖,用于测试)
|
|
|
|
|
|
func NewFormConfigServiceWithoutDependencies() FormConfigService {
|
|
|
|
|
|
return &FormConfigServiceImpl{
|
|
|
|
|
|
productManagementService: nil,
|
|
|
|
|
|
}
|
2025-08-27 22:19:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetFormConfig 获取指定API的表单配置
|
2025-11-01 16:57:58 +08:00
|
|
|
|
func (s *FormConfigServiceImpl) GetFormConfig(ctx context.Context, apiCode string) (*FormConfig, error) {
|
2025-08-27 22:19:19 +08:00
|
|
|
|
// 根据API代码获取对应的DTO结构体
|
2025-11-01 16:57:58 +08:00
|
|
|
|
dtoStruct, err := s.getDTOStruct(ctx, apiCode)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
2025-08-27 22:19:19 +08:00
|
|
|
|
if dtoStruct == nil {
|
|
|
|
|
|
return nil, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 通过反射解析结构体字段
|
|
|
|
|
|
fields := s.parseDTOFields(dtoStruct)
|
|
|
|
|
|
|
|
|
|
|
|
config := &FormConfig{
|
|
|
|
|
|
ApiCode: apiCode,
|
|
|
|
|
|
Fields: fields,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return config, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// getDTOStruct 根据API代码获取对应的DTO结构体
|
2025-11-01 16:57:58 +08:00
|
|
|
|
func (s *FormConfigServiceImpl) getDTOStruct(ctx context.Context, apiCode string) (interface{}, error) {
|
2025-08-27 22:19:19 +08:00
|
|
|
|
// 建立API代码到DTO结构体的映射
|
|
|
|
|
|
dtoMap := map[string]interface{}{
|
|
|
|
|
|
"IVYZ9363": &dto.IVYZ9363Req{},
|
|
|
|
|
|
"IVYZ385E": &dto.IVYZ385EReq{},
|
|
|
|
|
|
"IVYZ5733": &dto.IVYZ5733Req{},
|
|
|
|
|
|
"FLXG3D56": &dto.FLXG3D56Req{},
|
|
|
|
|
|
"FLXG75FE": &dto.FLXG75FEReq{},
|
|
|
|
|
|
"FLXG0V3B": &dto.FLXG0V3BReq{},
|
|
|
|
|
|
"FLXG0V4B": &dto.FLXG0V4BReq{},
|
|
|
|
|
|
"FLXG54F5": &dto.FLXG54F5Req{},
|
|
|
|
|
|
"FLXG162A": &dto.FLXG162AReq{},
|
|
|
|
|
|
"FLXG0687": &dto.FLXG0687Req{},
|
2025-10-16 18:46:44 +08:00
|
|
|
|
"FLXGBC21": &dto.FLXGBC21Req{},
|
2025-08-27 22:19:19 +08:00
|
|
|
|
"FLXG970F": &dto.FLXG970FReq{},
|
|
|
|
|
|
"FLXG5876": &dto.FLXG5876Req{},
|
|
|
|
|
|
"FLXG9687": &dto.FLXG9687Req{},
|
|
|
|
|
|
"FLXGC9D1": &dto.FLXGC9D1Req{},
|
|
|
|
|
|
"FLXGCA3D": &dto.FLXGCA3DReq{},
|
|
|
|
|
|
"FLXGDEC7": &dto.FLXGDEC7Req{},
|
|
|
|
|
|
"JRZQ0A03": &dto.JRZQ0A03Req{},
|
|
|
|
|
|
"JRZQ4AA8": &dto.JRZQ4AA8Req{},
|
|
|
|
|
|
"JRZQ8203": &dto.JRZQ8203Req{},
|
|
|
|
|
|
"JRZQDBCE": &dto.JRZQDBCEReq{},
|
|
|
|
|
|
"QYGL2ACD": &dto.QYGL2ACDReq{},
|
|
|
|
|
|
"QYGL6F2D": &dto.QYGL6F2DReq{},
|
|
|
|
|
|
"QYGL45BD": &dto.QYGL45BDReq{},
|
|
|
|
|
|
"QYGL8261": &dto.QYGL8261Req{},
|
|
|
|
|
|
"QYGL8271": &dto.QYGL8271Req{},
|
|
|
|
|
|
"QYGLB4C0": &dto.QYGLB4C0Req{},
|
|
|
|
|
|
"QYGL23T7": &dto.QYGL23T7Req{},
|
2025-09-20 23:29:49 +08:00
|
|
|
|
"QYGL5A3C": &dto.QYGL5A3CReq{},
|
|
|
|
|
|
"QYGL8B4D": &dto.QYGL8B4DReq{},
|
|
|
|
|
|
"QYGL9E2F": &dto.QYGL9E2FReq{},
|
|
|
|
|
|
"QYGL7C1A": &dto.QYGL7C1AReq{},
|
2025-09-30 12:03:51 +08:00
|
|
|
|
"QYGL3F8E": &dto.QYGL3F8EReq{},
|
2025-08-27 22:19:19 +08:00
|
|
|
|
"YYSY4B37": &dto.YYSY4B37Req{},
|
|
|
|
|
|
"YYSY4B21": &dto.YYSY4B21Req{},
|
|
|
|
|
|
"YYSY6F2E": &dto.YYSY6F2EReq{},
|
|
|
|
|
|
"YYSY09CD": &dto.YYSY09CDReq{},
|
|
|
|
|
|
"IVYZ0b03": &dto.IVYZ0b03Req{},
|
|
|
|
|
|
"YYSYBE08": &dto.YYSYBE08Req{},
|
|
|
|
|
|
"YYSYD50F": &dto.YYSYD50FReq{},
|
|
|
|
|
|
"YYSYF7DB": &dto.YYSYF7DBReq{},
|
|
|
|
|
|
"IVYZ9A2B": &dto.IVYZ9A2BReq{},
|
|
|
|
|
|
"IVYZ7F2A": &dto.IVYZ7F2AReq{},
|
|
|
|
|
|
"IVYZ4E8B": &dto.IVYZ4E8BReq{},
|
|
|
|
|
|
"IVYZ1C9D": &dto.IVYZ1C9DReq{},
|
|
|
|
|
|
"IVYZGZ08": &dto.IVYZGZ08Req{},
|
|
|
|
|
|
"FLXG8A3F": &dto.FLXG8A3FReq{},
|
|
|
|
|
|
"FLXG5B2E": &dto.FLXG5B2EReq{},
|
|
|
|
|
|
"COMB298Y": &dto.COMB298YReq{},
|
|
|
|
|
|
"COMB86PM": &dto.COMB86PMReq{},
|
|
|
|
|
|
"QCXG7A2B": &dto.QCXG7A2BReq{},
|
|
|
|
|
|
"COMENT01": &dto.COMENT01Req{},
|
|
|
|
|
|
"JRZQ09J8": &dto.JRZQ09J8Req{},
|
|
|
|
|
|
"FLXGDEA8": &dto.FLXGDEA8Req{},
|
|
|
|
|
|
"FLXGDEA9": &dto.FLXGDEA9Req{},
|
|
|
|
|
|
"JRZQ1D09": &dto.JRZQ1D09Req{},
|
|
|
|
|
|
"IVYZ2A8B": &dto.IVYZ2A8BReq{},
|
|
|
|
|
|
"IVYZ7C9D": &dto.IVYZ7C9DReq{},
|
|
|
|
|
|
"IVYZ5E3F": &dto.IVYZ5E3FReq{},
|
|
|
|
|
|
"YYSY4F2E": &dto.YYSY4F2EReq{},
|
|
|
|
|
|
"YYSY8B1C": &dto.YYSY8B1CReq{},
|
|
|
|
|
|
"YYSY6D9A": &dto.YYSY6D9AReq{},
|
|
|
|
|
|
"YYSY3E7F": &dto.YYSY3E7FReq{},
|
|
|
|
|
|
"FLXG5A3B": &dto.FLXG5A3BReq{},
|
|
|
|
|
|
"FLXG9C1D": &dto.FLXG9C1DReq{},
|
|
|
|
|
|
"FLXG2E8F": &dto.FLXG2E8FReq{},
|
|
|
|
|
|
"JRZQ3C7B": &dto.JRZQ3C7BReq{},
|
|
|
|
|
|
"JRZQ8A2D": &dto.JRZQ8A2DReq{},
|
|
|
|
|
|
"JRZQ5E9F": &dto.JRZQ5E9FReq{},
|
|
|
|
|
|
"JRZQ4B6C": &dto.JRZQ4B6CReq{},
|
|
|
|
|
|
"JRZQ7F1A": &dto.JRZQ7F1AReq{},
|
|
|
|
|
|
"DWBG6A2C": &dto.DWBG6A2CReq{},
|
|
|
|
|
|
"DWBG8B4D": &dto.DWBG8B4DReq{},
|
|
|
|
|
|
"FLXG8B4D": &dto.FLXG8B4DReq{},
|
2025-10-16 18:46:44 +08:00
|
|
|
|
"IVYZ81NC": &dto.IVYZ81NCReq{},
|
|
|
|
|
|
"IVYZ7F3A": &dto.IVYZ7F3AReq{},
|
2025-11-09 16:08:58 +08:00
|
|
|
|
"IVYZ3P9M": &dto.IVYZ3P9MReq{},
|
2025-10-16 18:46:44 +08:00
|
|
|
|
"IVYZ3A7F": &dto.IVYZ3A7FReq{},
|
|
|
|
|
|
"IVYZ9D2E": &dto.IVYZ9D2EReq{},
|
2025-11-20 18:02:18 +08:00
|
|
|
|
"IVYZ9K2L": &dto.IVYZ9K2LReq{},
|
2025-10-16 18:46:44 +08:00
|
|
|
|
"DWBG7F3A": &dto.DWBG7F3AReq{},
|
|
|
|
|
|
"YYSY8F3A": &dto.YYSY8F3AReq{},
|
2025-10-17 17:59:54 +08:00
|
|
|
|
"QCXG9P1C": &dto.QCXG9P1CReq{},
|
|
|
|
|
|
"JRZQ9E2A": &dto.JRZQ9E2AReq{},
|
|
|
|
|
|
"YYSY9A1B": &dto.YYSY9A1BReq{},
|
|
|
|
|
|
"YYSY8C2D": &dto.YYSY8C2DReq{},
|
|
|
|
|
|
"YYSY7D3E": &dto.YYSY7D3EReq{},
|
2025-10-22 16:40:14 +08:00
|
|
|
|
"YYSY9E4A": &dto.YYSY9E4AReq{},
|
2025-10-17 17:59:54 +08:00
|
|
|
|
"JRZQ6F2A": &dto.JRZQ6F2AReq{},
|
|
|
|
|
|
"JRZQ8B3C": &dto.JRZQ8B3CReq{},
|
|
|
|
|
|
"JRZQ9D4E": &dto.JRZQ9D4EReq{},
|
|
|
|
|
|
"FLXG7E8F": &dto.FLXG7E8FReq{},
|
|
|
|
|
|
"QYGL5F6A": &dto.QYGL5F6AReq{},
|
|
|
|
|
|
"IVYZ6G7H": &dto.IVYZ6G7HReq{},
|
|
|
|
|
|
"IVYZ8I9J": &dto.IVYZ8I9JReq{},
|
2025-10-24 17:18:46 +08:00
|
|
|
|
"JRZQ0L85": &dto.JRZQ0L85Req{},
|
2025-11-12 23:16:37 +08:00
|
|
|
|
"COMBHZY2": &dto.COMBHZY2Req{},
|
2025-11-13 20:43:35 +08:00
|
|
|
|
"QCXG8A3D": &dto.QCXG8A3DReq{},
|
|
|
|
|
|
"QCXG6B4E": &dto.QCXG6B4EReq{},
|
|
|
|
|
|
"QYGL2B5C": &dto.QYGL2B5CReq{},
|
|
|
|
|
|
"JRZQ2F8A": &dto.JRZQ2F8AReq{},
|
|
|
|
|
|
"JRZQ1E7B": &dto.JRZQ1E7BReq{},
|
2025-08-27 22:19:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-20 23:29:49 +08:00
|
|
|
|
// 优先返回已配置的DTO
|
|
|
|
|
|
if dto, exists := dtoMap[apiCode]; exists {
|
2025-11-01 16:57:58 +08:00
|
|
|
|
return dto, nil
|
2025-09-20 23:29:49 +08:00
|
|
|
|
}
|
2025-10-16 18:46:44 +08:00
|
|
|
|
|
2025-09-20 23:29:49 +08:00
|
|
|
|
// 检查是否为通用组合包(COMB开头且未单独配置)
|
|
|
|
|
|
if len(apiCode) >= 4 && apiCode[:4] == "COMB" {
|
2025-11-01 16:57:58 +08:00
|
|
|
|
// 动态从数据库获取组合包的子产品信息,并合并DTO
|
|
|
|
|
|
return s.mergeCombPackageDTOs(ctx, apiCode, dtoMap)
|
2025-09-20 23:29:49 +08:00
|
|
|
|
}
|
2025-10-16 18:46:44 +08:00
|
|
|
|
|
2025-11-01 16:57:58 +08:00
|
|
|
|
return nil, nil
|
2025-08-27 22:19:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// parseDTOFields 通过反射解析DTO结构体字段
|
|
|
|
|
|
func (s *FormConfigServiceImpl) parseDTOFields(dtoStruct interface{}) []FormField {
|
|
|
|
|
|
var fields []FormField
|
|
|
|
|
|
|
|
|
|
|
|
t := reflect.TypeOf(dtoStruct).Elem()
|
|
|
|
|
|
|
|
|
|
|
|
for i := 0; i < t.NumField(); i++ {
|
|
|
|
|
|
field := t.Field(i)
|
|
|
|
|
|
|
|
|
|
|
|
// 获取JSON标签
|
|
|
|
|
|
jsonTag := field.Tag.Get("json")
|
|
|
|
|
|
if jsonTag == "" {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取验证标签
|
|
|
|
|
|
validateTag := field.Tag.Get("validate")
|
|
|
|
|
|
|
|
|
|
|
|
// 解析验证规则
|
|
|
|
|
|
required := strings.Contains(validateTag, "required")
|
|
|
|
|
|
validation := s.parseValidationRules(validateTag)
|
|
|
|
|
|
|
|
|
|
|
|
// 根据字段类型和验证规则生成前端字段类型
|
|
|
|
|
|
fieldType := s.getFieldType(field.Type, validation)
|
|
|
|
|
|
|
|
|
|
|
|
// 生成字段标签(将下划线转换为中文)
|
|
|
|
|
|
label := s.generateFieldLabel(jsonTag)
|
|
|
|
|
|
|
|
|
|
|
|
// 生成示例值
|
|
|
|
|
|
example := s.generateExampleValue(field.Type, jsonTag)
|
|
|
|
|
|
|
|
|
|
|
|
// 生成占位符
|
|
|
|
|
|
placeholder := s.generatePlaceholder(jsonTag, fieldType)
|
|
|
|
|
|
|
|
|
|
|
|
// 生成字段描述
|
|
|
|
|
|
description := s.generateDescription(jsonTag, validation)
|
|
|
|
|
|
|
|
|
|
|
|
formField := FormField{
|
|
|
|
|
|
Name: jsonTag,
|
|
|
|
|
|
Label: label,
|
|
|
|
|
|
Type: fieldType,
|
|
|
|
|
|
Required: required,
|
|
|
|
|
|
Validation: validation,
|
|
|
|
|
|
Description: description,
|
|
|
|
|
|
Example: example,
|
|
|
|
|
|
Placeholder: placeholder,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fields = append(fields, formField)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return fields
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// parseValidationRules 解析验证规则
|
|
|
|
|
|
func (s *FormConfigServiceImpl) parseValidationRules(validateTag string) string {
|
|
|
|
|
|
if validateTag == "" {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将验证规则转换为前端可理解的格式
|
|
|
|
|
|
rules := strings.Split(validateTag, ",")
|
|
|
|
|
|
var frontendRules []string
|
|
|
|
|
|
|
|
|
|
|
|
for _, rule := range rules {
|
|
|
|
|
|
rule = strings.TrimSpace(rule)
|
|
|
|
|
|
switch {
|
|
|
|
|
|
case rule == "required":
|
|
|
|
|
|
frontendRules = append(frontendRules, "必填")
|
|
|
|
|
|
case strings.HasPrefix(rule, "min="):
|
|
|
|
|
|
min := strings.TrimPrefix(rule, "min=")
|
|
|
|
|
|
frontendRules = append(frontendRules, "最小长度"+min)
|
|
|
|
|
|
case strings.HasPrefix(rule, "max="):
|
|
|
|
|
|
max := strings.TrimPrefix(rule, "max=")
|
|
|
|
|
|
frontendRules = append(frontendRules, "最大长度"+max)
|
|
|
|
|
|
case rule == "validMobileNo":
|
|
|
|
|
|
frontendRules = append(frontendRules, "手机号格式")
|
|
|
|
|
|
case rule == "validIDCard":
|
|
|
|
|
|
frontendRules = append(frontendRules, "身份证格式")
|
|
|
|
|
|
case rule == "validName":
|
|
|
|
|
|
frontendRules = append(frontendRules, "姓名格式")
|
|
|
|
|
|
case rule == "validUSCI":
|
|
|
|
|
|
frontendRules = append(frontendRules, "统一社会信用代码格式")
|
2025-11-13 20:43:35 +08:00
|
|
|
|
case rule == "validEnterpriseName" || rule == "enterprise_name":
|
|
|
|
|
|
frontendRules = append(frontendRules, "企业名称格式")
|
2025-08-27 22:19:19 +08:00
|
|
|
|
case rule == "validBankCard":
|
|
|
|
|
|
frontendRules = append(frontendRules, "银行卡号格式")
|
|
|
|
|
|
case rule == "validDate":
|
|
|
|
|
|
frontendRules = append(frontendRules, "日期格式")
|
|
|
|
|
|
case rule == "validAuthDate":
|
|
|
|
|
|
frontendRules = append(frontendRules, "授权日期格式")
|
|
|
|
|
|
case rule == "validTimeRange":
|
|
|
|
|
|
frontendRules = append(frontendRules, "时间范围格式")
|
|
|
|
|
|
case rule == "validMobileType":
|
|
|
|
|
|
frontendRules = append(frontendRules, "手机类型")
|
|
|
|
|
|
case rule == "validUniqueID":
|
|
|
|
|
|
frontendRules = append(frontendRules, "唯一标识格式")
|
|
|
|
|
|
case rule == "validReturnURL":
|
|
|
|
|
|
frontendRules = append(frontendRules, "返回链接格式")
|
|
|
|
|
|
case rule == "validAuthorizationURL":
|
|
|
|
|
|
frontendRules = append(frontendRules, "授权链接格式")
|
|
|
|
|
|
case strings.HasPrefix(rule, "oneof="):
|
|
|
|
|
|
values := strings.TrimPrefix(rule, "oneof=")
|
|
|
|
|
|
frontendRules = append(frontendRules, "可选值: "+values)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return strings.Join(frontendRules, "、")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// getFieldType 根据字段类型和验证规则确定前端字段类型
|
|
|
|
|
|
func (s *FormConfigServiceImpl) getFieldType(fieldType reflect.Type, validation string) string {
|
|
|
|
|
|
switch fieldType.Kind() {
|
|
|
|
|
|
case reflect.String:
|
|
|
|
|
|
if strings.Contains(validation, "手机号") {
|
|
|
|
|
|
return "tel"
|
|
|
|
|
|
} else if strings.Contains(validation, "身份证") {
|
|
|
|
|
|
return "text"
|
|
|
|
|
|
} else if strings.Contains(validation, "姓名") {
|
|
|
|
|
|
return "text"
|
2025-11-01 21:19:21 +08:00
|
|
|
|
} else if strings.Contains(validation, "时间范围格式") {
|
|
|
|
|
|
return "text" // time_range是HH:MM-HH:MM格式,使用文本输入
|
|
|
|
|
|
} else if strings.Contains(validation, "授权日期格式") {
|
|
|
|
|
|
return "text" // auth_date是YYYYMMDD-YYYYMMDD格式,使用文本输入
|
2025-08-27 22:19:19 +08:00
|
|
|
|
} else if strings.Contains(validation, "日期") {
|
|
|
|
|
|
return "date"
|
|
|
|
|
|
} else if strings.Contains(validation, "链接") {
|
|
|
|
|
|
return "url"
|
|
|
|
|
|
} else if strings.Contains(validation, "可选值") {
|
|
|
|
|
|
return "select"
|
|
|
|
|
|
}
|
|
|
|
|
|
return "text"
|
|
|
|
|
|
case reflect.Int64:
|
|
|
|
|
|
return "number"
|
|
|
|
|
|
case reflect.Bool:
|
|
|
|
|
|
return "checkbox"
|
|
|
|
|
|
default:
|
|
|
|
|
|
return "text"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// generateFieldLabel 生成字段标签
|
|
|
|
|
|
func (s *FormConfigServiceImpl) generateFieldLabel(jsonTag string) string {
|
|
|
|
|
|
// 将下划线命名转换为中文标签
|
|
|
|
|
|
labelMap := map[string]string{
|
2025-11-02 20:33:28 +08:00
|
|
|
|
"mobile_no": "手机号码",
|
|
|
|
|
|
"id_card": "身份证号",
|
|
|
|
|
|
"name": "姓名",
|
|
|
|
|
|
"man_name": "男方姓名",
|
|
|
|
|
|
"woman_name": "女方姓名",
|
|
|
|
|
|
"man_id_card": "男方身份证",
|
|
|
|
|
|
"woman_id_card": "女方身份证",
|
|
|
|
|
|
"ent_name": "企业名称",
|
|
|
|
|
|
"legal_person": "法人姓名",
|
|
|
|
|
|
"ent_code": "企业代码",
|
|
|
|
|
|
"auth_date": "授权日期",
|
|
|
|
|
|
"time_range": "时间范围",
|
|
|
|
|
|
"authorized": "是否授权",
|
|
|
|
|
|
"authorization_url": "授权链接",
|
|
|
|
|
|
"unique_id": "唯一标识",
|
|
|
|
|
|
"return_url": "返回链接",
|
|
|
|
|
|
"mobile_type": "手机类型",
|
|
|
|
|
|
"start_date": "开始日期",
|
|
|
|
|
|
"years": "年数",
|
|
|
|
|
|
"bank_card": "银行卡号",
|
|
|
|
|
|
"user_type": "关系类型",
|
|
|
|
|
|
"vehicle_type": "车辆类型",
|
|
|
|
|
|
"page_num": "页码",
|
|
|
|
|
|
"page_size": "每页数量",
|
|
|
|
|
|
"use_scenario": "使用场景",
|
2025-11-01 21:19:21 +08:00
|
|
|
|
"auth_authorize_file_code": "授权文件编码",
|
2025-11-13 20:43:35 +08:00
|
|
|
|
"plate_no": "车牌号",
|
|
|
|
|
|
"plate_type": "号牌类型",
|
|
|
|
|
|
"vin_code": "车辆识别代号VIN码",
|
2025-11-19 13:41:41 +08:00
|
|
|
|
"return_type": "返回类型",
|
2025-11-20 18:02:18 +08:00
|
|
|
|
"photo_data": "人脸图片",
|
2025-08-27 22:19:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if label, exists := labelMap[jsonTag]; exists {
|
|
|
|
|
|
return label
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有预定义,尝试自动转换
|
|
|
|
|
|
return strings.ReplaceAll(jsonTag, "_", " ")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// generateExampleValue 生成示例值
|
|
|
|
|
|
func (s *FormConfigServiceImpl) generateExampleValue(fieldType reflect.Type, jsonTag string) string {
|
|
|
|
|
|
exampleMap := map[string]string{
|
2025-11-02 20:33:28 +08:00
|
|
|
|
"mobile_no": "13800138000",
|
|
|
|
|
|
"id_card": "110101199001011234",
|
|
|
|
|
|
"name": "张三",
|
|
|
|
|
|
"man_name": "张三",
|
|
|
|
|
|
"woman_name": "李四",
|
|
|
|
|
|
"ent_name": "示例企业有限公司",
|
|
|
|
|
|
"legal_person": "王五",
|
|
|
|
|
|
"ent_code": "91110000123456789X",
|
|
|
|
|
|
"auth_date": "20240101-20241231",
|
|
|
|
|
|
"time_range": "09:00-18:00",
|
|
|
|
|
|
"authorized": "1",
|
|
|
|
|
|
"years": "5",
|
|
|
|
|
|
"bank_card": "6222021234567890123",
|
|
|
|
|
|
"mobile_type": "移动",
|
|
|
|
|
|
"start_date": "2024-01-01",
|
|
|
|
|
|
"unique_id": "UNIQUE123456",
|
|
|
|
|
|
"return_url": "https://example.com/return",
|
|
|
|
|
|
"authorization_url": "https://example.com/auth20250101.pdf 注意:请不要使用示例链接,示例链接仅作为参考格式。必须为实际的被查询人授权具有法律效益的授权书文件链接,如访问不到或为不实授权书将追究责任。协议必须为http https",
|
|
|
|
|
|
"user_type": "1",
|
|
|
|
|
|
"vehicle_type": "0",
|
|
|
|
|
|
"page_num": "1",
|
|
|
|
|
|
"page_size": "10",
|
|
|
|
|
|
"use_scenario": "1",
|
2025-11-01 21:19:21 +08:00
|
|
|
|
"auth_authorize_file_code": "AUTH123456",
|
2025-11-13 20:43:35 +08:00
|
|
|
|
"plate_no": "京A12345",
|
|
|
|
|
|
"plate_type": "01",
|
|
|
|
|
|
"vin_code": "LSGBF53M8DS123456",
|
2025-11-19 13:41:41 +08:00
|
|
|
|
"return_type": "1",
|
2025-11-20 18:02:18 +08:00
|
|
|
|
"photo_data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
|
2025-08-27 22:19:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if example, exists := exampleMap[jsonTag]; exists {
|
|
|
|
|
|
return example
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 根据字段类型生成默认示例
|
|
|
|
|
|
switch fieldType.Kind() {
|
|
|
|
|
|
case reflect.String:
|
|
|
|
|
|
return "示例值"
|
|
|
|
|
|
case reflect.Int64:
|
|
|
|
|
|
return "123"
|
|
|
|
|
|
case reflect.Bool:
|
|
|
|
|
|
return "true"
|
|
|
|
|
|
default:
|
|
|
|
|
|
return "示例值"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// generatePlaceholder 生成占位符
|
|
|
|
|
|
func (s *FormConfigServiceImpl) generatePlaceholder(jsonTag string, fieldType string) string {
|
|
|
|
|
|
placeholderMap := map[string]string{
|
2025-11-02 20:33:28 +08:00
|
|
|
|
"mobile_no": "请输入11位手机号码",
|
|
|
|
|
|
"id_card": "请输入18位身份证号码",
|
|
|
|
|
|
"name": "请输入真实姓名",
|
|
|
|
|
|
"man_name": "请输入男方真实姓名",
|
|
|
|
|
|
"woman_name": "请输入女方真实姓名",
|
|
|
|
|
|
"ent_name": "请输入企业全称",
|
|
|
|
|
|
"legal_person": "请输入法人真实姓名",
|
|
|
|
|
|
"ent_code": "请输入统一社会信用代码",
|
|
|
|
|
|
"auth_date": "请输入授权日期范围(YYYYMMDD-YYYYMMDD)",
|
|
|
|
|
|
"time_range": "请输入时间范围(HH:MM-HH:MM)",
|
|
|
|
|
|
"authorized": "请选择是否授权",
|
|
|
|
|
|
"years": "请输入查询年数(0-100)",
|
|
|
|
|
|
"bank_card": "请输入银行卡号",
|
|
|
|
|
|
"mobile_type": "请选择手机类型",
|
|
|
|
|
|
"start_date": "请选择开始日期",
|
|
|
|
|
|
"unique_id": "请输入唯一标识",
|
|
|
|
|
|
"return_url": "请输入返回链接",
|
|
|
|
|
|
"authorization_url": "请输入授权链接",
|
|
|
|
|
|
"user_type": "请选择关系类型",
|
|
|
|
|
|
"vehicle_type": "请选择车辆类型",
|
|
|
|
|
|
"page_num": "请输入页码",
|
|
|
|
|
|
"page_size": "请输入每页数量(1-100)",
|
|
|
|
|
|
"use_scenario": "请选择使用场景",
|
2025-11-01 21:19:21 +08:00
|
|
|
|
"auth_authorize_file_code": "请输入授权文件编码",
|
2025-11-13 20:43:35 +08:00
|
|
|
|
"plate_no": "请输入车牌号",
|
|
|
|
|
|
"plate_type": "请选择号牌类型(01或02)",
|
|
|
|
|
|
"vin_code": "请输入17位车辆识别代号VIN码",
|
2025-11-19 13:41:41 +08:00
|
|
|
|
"return_type": "请选择返回类型",
|
2025-11-20 18:02:18 +08:00
|
|
|
|
"photo_data": "请输入base64编码的人脸图片(支持JPG、BMP、PNG格式)",
|
2025-08-27 22:19:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if placeholder, exists := placeholderMap[jsonTag]; exists {
|
|
|
|
|
|
return placeholder
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 根据字段类型生成默认占位符
|
|
|
|
|
|
switch fieldType {
|
|
|
|
|
|
case "tel":
|
|
|
|
|
|
return "请输入电话号码"
|
|
|
|
|
|
case "date":
|
|
|
|
|
|
return "请选择日期"
|
|
|
|
|
|
case "url":
|
|
|
|
|
|
return "请输入链接地址"
|
|
|
|
|
|
case "number":
|
|
|
|
|
|
return "请输入数字"
|
|
|
|
|
|
default:
|
|
|
|
|
|
return "请输入" + s.generateFieldLabel(jsonTag)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// generateDescription 生成字段描述
|
|
|
|
|
|
func (s *FormConfigServiceImpl) generateDescription(jsonTag string, validation string) string {
|
|
|
|
|
|
descMap := map[string]string{
|
2025-11-02 20:33:28 +08:00
|
|
|
|
"mobile_no": "请输入11位手机号码",
|
|
|
|
|
|
"id_card": "请输入18位身份证号码",
|
|
|
|
|
|
"name": "请输入真实姓名",
|
|
|
|
|
|
"man_name": "请输入男方真实姓名",
|
|
|
|
|
|
"woman_name": "请输入女方真实姓名",
|
|
|
|
|
|
"ent_name": "请输入企业全称",
|
|
|
|
|
|
"legal_person": "请输入法人真实姓名",
|
|
|
|
|
|
"ent_code": "请输入统一社会信用代码",
|
|
|
|
|
|
"auth_date": "请输入授权日期范围,格式:YYYYMMDD-YYYYMMDD,且日期范围必须包括今天",
|
|
|
|
|
|
"time_range": "请输入时间范围,格式:HH:MM-HH:MM",
|
|
|
|
|
|
"authorized": "请输入是否授权:0-未授权,1-已授权",
|
|
|
|
|
|
"years": "请输入查询年数(0-100)",
|
|
|
|
|
|
"bank_card": "请输入银行卡号",
|
|
|
|
|
|
"mobile_type": "请选择手机类型",
|
|
|
|
|
|
"start_date": "请选择开始日期",
|
|
|
|
|
|
"unique_id": "请输入唯一标识",
|
|
|
|
|
|
"return_url": "请输入返回链接",
|
|
|
|
|
|
"authorization_url": "请输入授权链接",
|
|
|
|
|
|
"user_type": "关系类型:1-ETC开户人;2-车辆所有人;3-ETC经办人(默认1-ETC开户人)",
|
|
|
|
|
|
"vehicle_type": "车辆类型:0-客车;1-货车;2-全部(默认查全部)",
|
|
|
|
|
|
"page_num": "请输入页码,从1开始",
|
|
|
|
|
|
"page_size": "请输入每页数量,范围1-100",
|
|
|
|
|
|
"use_scenario": "使用场景:1-信贷审核;2-保险评估;3-招聘背景调查;4-其他业务场景;99-其他",
|
2025-11-01 21:19:21 +08:00
|
|
|
|
"auth_authorize_file_code": "请输入授权文件编码",
|
2025-11-13 20:43:35 +08:00
|
|
|
|
"plate_no": "请输入车牌号",
|
|
|
|
|
|
"plate_type": "号牌类型:01-小型汽车;02-大型汽车(可选)",
|
|
|
|
|
|
"vin_code": "请输入17位车辆识别代号VIN码(Vehicle Identification Number)",
|
2025-11-19 13:41:41 +08:00
|
|
|
|
"return_type": "返回类型:1-专业和学校名称数据返回编码形式(默认);2-专业和学校名称数据返回中文名称",
|
2025-11-20 18:02:18 +08:00
|
|
|
|
"photo_data": "人脸图片(选填):base64编码的图片数据,仅支持JPG、BMP、PNG三种格式",
|
2025-08-27 22:19:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if desc, exists := descMap[jsonTag]; exists {
|
|
|
|
|
|
return desc
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return "请输入" + s.generateFieldLabel(jsonTag)
|
|
|
|
|
|
}
|
2025-11-01 16:57:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
}
|
2025-11-02 20:33:28 +08:00
|
|
|
|
|
2025-11-01 16:57:58 +08:00
|
|
|
|
// 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)
|
2025-11-02 20:33:28 +08:00
|
|
|
|
|
2025-11-01 16:57:58 +08:00
|
|
|
|
// 创建并返回结构体实例
|
|
|
|
|
|
structValue := reflect.New(structType)
|
|
|
|
|
|
return structValue.Interface(), nil
|
|
|
|
|
|
}
|