diff --git a/internal/domains/api/dto/api_request_dto.go b/internal/domains/api/dto/api_request_dto.go index fcc96c6..c7c4433 100644 --- a/internal/domains/api/dto/api_request_dto.go +++ b/internal/domains/api/dto/api_request_dto.go @@ -272,6 +272,13 @@ type QCXG4896Req struct { PlateNo string `json:"plate_no" validate:"required"` AuthDate string `json:"auth_date" validate:"required,validAuthDate" encrypt:"false"` } +type QCXG5F3AReq struct { + IDCard string `json:"id_card" validate:"required,validIDCard"` +} +type QCXG4D2EReq struct { + IDCard string `json:"id_card" validate:"required,validIDCard"` + UserType string `json:"user_type" validate:"required,oneof=1 2 3"` +} type COMENT01Req struct { EntName string `json:"ent_name" validate:"required,min=1,validEnterpriseName"` EntCode string `json:"ent_code" validate:"required,validUSCI"` @@ -731,8 +738,8 @@ type IVYZ6M8PReq struct { } type IVYZ9H2MReq struct { - IDCard string `json:"id_no" validate:"required,validIDCard"` - Name string `json:"name" validate:"required,min=1,validName"` + IDNo string `json:"id_no" validate:"required,validIDCard"` + Name string `json:"name" validate:"required,min=1,validName"` } type YYSY9E4AReq struct { diff --git a/internal/domains/api/services/api_request_service.go b/internal/domains/api/services/api_request_service.go index 5064da2..0da828a 100644 --- a/internal/domains/api/services/api_request_service.go +++ b/internal/domains/api/services/api_request_service.go @@ -225,6 +225,8 @@ func registerAllProcessors(combService *comb.CombService) { "QCXG8A3D": qcxg.ProcessQCXG8A3DRequest, "QCXG6B4E": qcxg.ProcessQCXG6B4ERequest, "QCXG4896": qcxg.ProcessQCXG4896Request, + "QCXG5F3A": qcxg.ProcessQCXG5F3ARequest, // 极光个人车辆查询 + "QCXG4D2E": qcxg.ProcessQCXG4D2ERequest, // 极光名下车辆数量查询 // DWBG系列处理器 - 多维报告 "DWBG6A2C": dwbg.ProcessDWBG6A2CRequest, diff --git a/internal/domains/api/services/form_config_service.go b/internal/domains/api/services/form_config_service.go index 5abbb76..6d8ff9e 100644 --- a/internal/domains/api/services/form_config_service.go +++ b/internal/domains/api/services/form_config_service.go @@ -205,6 +205,8 @@ func (s *FormConfigServiceImpl) getDTOStruct(ctx context.Context, apiCode string "IVYZBPQ2": &dto.IVYZBPQ2Req{}, //人脸比对V2 "IVYZSFEL": &dto.IVYZSFELReq{}, //全国自然人人像三要素核验_V1 "QYGL66SL": &dto.QYGL66SLReq{}, //全国企业司法模型服务查询_V1 + "QCXG5F3A": &dto.QCXG5F3AReq{}, //极光个人车辆查询 + "QCXG4D2E": &dto.QCXG4D2EReq{}, //极光名下车辆数量查询 } // 优先返回已配置的DTO diff --git a/internal/domains/api/services/processors/ivyz/ivyz9h2m_processor.go b/internal/domains/api/services/processors/ivyz/ivyz9h2m_processor.go index 179a363..c9e9286 100644 --- a/internal/domains/api/services/processors/ivyz/ivyz9h2m_processor.go +++ b/internal/domains/api/services/processors/ivyz/ivyz9h2m_processor.go @@ -23,12 +23,14 @@ func ProcessIVYZ9H2MRequest(ctx context.Context, params []byte, deps *processors // 构建请求参数 reqData := map[string]interface{}{ - "idCard": paramsDto.IDCard, - "name": paramsDto.Name, + "idNo": paramsDto.IDCard, + "name": paramsDto.Name, } - // 调用极光API,apiCode为 marriage-single-v2 - respBytes, err := deps.JiguangService.CallAPI(ctx, "marriage-single-v2", reqData) + // 调用极光API + // apiCode: marriage-single-v2 (用于请求头) + // apiPath: marriage/single-v2 (用于URL路径) + respBytes, err := deps.JiguangService.CallAPI(ctx, "marriage-single-v2", "marriage/single-v2", reqData) if err != nil { // 根据错误类型返回相应的错误 if errors.Is(err, jiguang.ErrNotFound) { diff --git a/internal/domains/api/services/processors/qcxg/qcxg4d2e_processor.go b/internal/domains/api/services/processors/qcxg/qcxg4d2e_processor.go new file mode 100644 index 0000000..adbff30 --- /dev/null +++ b/internal/domains/api/services/processors/qcxg/qcxg4d2e_processor.go @@ -0,0 +1,49 @@ +package qcxg + +import ( + "context" + "encoding/json" + "errors" + + "tyapi-server/internal/domains/api/dto" + "tyapi-server/internal/domains/api/services/processors" + "tyapi-server/internal/infrastructure/external/jiguang" +) + +// ProcessQCXG4D2ERequest QCXG4D2E API处理方法 - 极光名下车辆数量查询 +func ProcessQCXG4D2ERequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) { + var paramsDto dto.QCXG4D2EReq + if err := json.Unmarshal(params, ¶msDto); err != nil { + return nil, errors.Join(processors.ErrSystem, err) + } + + if err := deps.Validator.ValidateStruct(paramsDto); err != nil { + return nil, errors.Join(processors.ErrInvalidParam, err) + } + + // 构建请求参数 + reqData := map[string]interface{}{ + "idNum": paramsDto.IDCard, + "userType": paramsDto.UserType, + } + + + // 调用极光API + // apiCode: vehicle-inquiry-under-name (用于请求头) + // apiPath: vehicle/inquiry-under-name (用于URL路径) + respBytes, err := deps.JiguangService.CallAPI(ctx, "vehicle-inquiry-under-name", "vehicle/inquiry-under-name", reqData) + if err != nil { + // 根据错误类型返回相应的错误 + if errors.Is(err, jiguang.ErrNotFound) { + return nil, errors.Join(processors.ErrNotFound, err) + } else if errors.Is(err, jiguang.ErrDatasource) { + return nil, errors.Join(processors.ErrDatasource, err) + } else { + return nil, errors.Join(processors.ErrSystem, err) + } + } + + // 极光服务已经返回了 data 字段的 JSON,直接返回即可 + return respBytes, nil +} + diff --git a/internal/domains/api/services/processors/qcxg/qcxg5f3a_processor.go b/internal/domains/api/services/processors/qcxg/qcxg5f3a_processor.go new file mode 100644 index 0000000..a5ab3ba --- /dev/null +++ b/internal/domains/api/services/processors/qcxg/qcxg5f3a_processor.go @@ -0,0 +1,47 @@ +package qcxg + +import ( + "context" + "encoding/json" + "errors" + + "tyapi-server/internal/domains/api/dto" + "tyapi-server/internal/domains/api/services/processors" + "tyapi-server/internal/infrastructure/external/jiguang" +) + +// ProcessQCXG5F3ARequest QCXG5F3A API处理方法 - 极光个人车辆查询 +func ProcessQCXG5F3ARequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) { + var paramsDto dto.QCXG5F3AReq + if err := json.Unmarshal(params, ¶msDto); err != nil { + return nil, errors.Join(processors.ErrSystem, err) + } + + if err := deps.Validator.ValidateStruct(paramsDto); err != nil { + return nil, errors.Join(processors.ErrInvalidParam, err) + } + + // 构建请求参数 + reqData := map[string]interface{}{ + "id_card": paramsDto.IDCard, + } + + // 调用极光API + // apiCode: vehicle-person-vehicles (用于请求头) + // apiPath: vehicle/person-vehicles (用于URL路径) + respBytes, err := deps.JiguangService.CallAPI(ctx, "vehicle-person-vehicles", "vehicle/person-vehicles", reqData) + if err != nil { + // 根据错误类型返回相应的错误 + if errors.Is(err, jiguang.ErrNotFound) { + return nil, errors.Join(processors.ErrNotFound, err) + } else if errors.Is(err, jiguang.ErrDatasource) { + return nil, errors.Join(processors.ErrDatasource, err) + } else { + return nil, errors.Join(processors.ErrSystem, err) + } + } + + // 极光服务已经返回了 data 字段的 JSON,直接返回即可 + return respBytes, nil +} + diff --git a/internal/infrastructure/external/jiguang/crypto.go b/internal/infrastructure/external/jiguang/crypto.go index 3d897a7..fe82437 100644 --- a/internal/infrastructure/external/jiguang/crypto.go +++ b/internal/infrastructure/external/jiguang/crypto.go @@ -5,6 +5,7 @@ import ( "crypto/md5" "encoding/hex" "fmt" + "strings" ) // SignMethod 签名方法类型 @@ -38,7 +39,7 @@ func GenerateSign(timestamp string, appSecret string, signMethod SignMethod) (st } // 将二进制转化为大写的十六进制(正确签名应该为32大写字符串) - return hex.EncodeToString(hashBytes), nil + return strings.ToUpper(hex.EncodeToString(hashBytes)), nil } // GenerateSignWithDefault 使用默认的 HMAC-MD5 方法生成签名 diff --git a/internal/infrastructure/external/jiguang/jiguang_service.go b/internal/infrastructure/external/jiguang/jiguang_service.go index 1547ffe..7d3549f 100644 --- a/internal/infrastructure/external/jiguang/jiguang_service.go +++ b/internal/infrastructure/external/jiguang/jiguang_service.go @@ -10,6 +10,7 @@ import ( "io" "net/http" "strconv" + "strings" "time" "tyapi-server/internal/shared/external_logger" @@ -76,9 +77,10 @@ func (j *JiguangService) generateRequestID() string { } // CallAPI 调用极光API -// apiCode: API服务编码(如 marriage-single-v2) +// apiCode: API服务编码(如 marriage-single-v2),用于请求头 +// apiPath: API路径(如 marriage/single-v2),用于URL路径 // params: 请求参数(会作为JSON body发送) -func (j *JiguangService) CallAPI(ctx context.Context, apiCode string, params map[string]interface{}) (resp []byte, err error) { +func (j *JiguangService) CallAPI(ctx context.Context, apiCode string, apiPath string, params map[string]interface{}) (resp []byte, err error) { startTime := time.Now() requestID := j.generateRequestID() @@ -101,9 +103,12 @@ func (j *JiguangService) CallAPI(ctx context.Context, apiCode string, params map return nil, err } + // 构建完整的请求URL,使用apiPath作为路径 + requestURL := strings.TrimSuffix(j.config.URL, "/") + "/" + strings.TrimPrefix(apiPath, "/") + // 记录请求日志 if j.logger != nil { - j.logger.LogRequest(requestID, transactionID, apiCode, j.config.URL, params) + j.logger.LogRequest(requestID, transactionID, apiCode, requestURL, params) } // 将请求参数转换为JSON @@ -117,7 +122,7 @@ func (j *JiguangService) CallAPI(ctx context.Context, apiCode string, params map } // 创建HTTP POST请求 - req, newRequestErr := http.NewRequestWithContext(ctx, "POST", j.config.URL, bytes.NewBuffer(jsonData)) + req, newRequestErr := http.NewRequestWithContext(ctx, "POST", requestURL, bytes.NewBuffer(jsonData)) if newRequestErr != nil { err = errors.Join(ErrSystem, newRequestErr) if j.logger != nil {