This commit is contained in:
2026-07-06 11:56:53 +08:00
7 changed files with 208 additions and 0 deletions

View File

@@ -138,6 +138,11 @@ type QCXGX2X6Req struct {
VehicleType string `json:"vehicle_type" validate:"omitempty"`
Name string `json:"name" validate:"required,min=1,validName"`
}
type QCXG7K2NReq struct {
PlateNo string `json:"plate_no" validate:"required"`
Name string `json:"name" validate:"required,min=1,validName"`
PlateType string `json:"plate_type" validate:"omitempty,oneof=01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 20 21 22 23 24 38 51 52"`
}
type QCXG1S2LReq struct {
VinCode string `json:"vin_code" validate:"required"`
}

View File

@@ -254,6 +254,7 @@ func registerAllProcessors(combService *comb.CombService) {
"QCXG521L": qcxg.ProcessQCXG521LRequest, // 车辆静态信息查询 10479
"QCXGIJY3": qcxg.ProcessQCXGIJY3Request, // 名下车辆诺尔
"QCXG6U5G": qcxg.ProcessQCXG6U5GRequest, // 车辆核验
"QCXG7K2N": qcxg.ProcessQCXG7K2NRequest, // 人车核验加强版
// DWBG系列处理器 - 多维报告

View File

@@ -312,6 +312,7 @@ func (s *FormConfigServiceImpl) getDTOStruct(ctx context.Context, apiCode string
"JRZQFC59": &dto.JRZQFC59Req{}, //房产核验
"IVYZX7J9": &dto.IVYZX7J9Req{}, //学籍核验
"QCXG6U5G": &dto.QCXG6U5GReq{}, //车辆核验
"QCXG7K2N": &dto.QCXG7K2NReq{}, //人车核验加强版
}
// 优先返回已配置的DTO

View File

@@ -0,0 +1,76 @@
package qcxg
import "strings"
const defaultPlateType = "02"
func normalizePlateType(plateType string) string {
code := strings.TrimSpace(plateType)
if code == "" {
return defaultPlateType
}
return code
}
func etcPlateColorParam(plateType string) (color string, include bool) {
code := strings.TrimSpace(plateType)
if code == "" || code == "02" {
return "", false
}
color, ok := plateTypePlateColorMap[code]
if !ok || color == "0" {
return "", false
}
return color, true
}
var plateTypePlateColorMap = map[string]string{
"01": "1",
"02": "0",
"03": "2",
"04": "2",
"05": "2",
"06": "2",
"07": "1",
"08": "0",
"09": "2",
"10": "2",
"11": "2",
"12": "2",
"13": "1",
"14": "1",
"15": "1",
"16": "1",
"17": "1",
"20": "7",
"21": "7",
"22": "7",
"23": "3",
"24": "3",
"38": "0",
"51": "5",
"52": "11",
}
func buildETCShujubaoParams(plateNo, name, plateType string) map[string]interface{} {
params := map[string]interface{}{
"key": "a2f32fc54b44ebc85b97a2aaff1734ec",
"carNo": plateNo,
"name": name,
}
if color, include := etcPlateColorParam(plateType); include {
params["plateColor"] = color
}
return params
}
func buildETCTianyuanParams(plateNo, name, plateType string) map[string]string {
params := map[string]string{
"plate_no": plateNo,
"name": name,
}
if color, include := etcPlateColorParam(plateType); include {
params["plate_color"] = color
}
return params
}

View File

@@ -0,0 +1,58 @@
package qcxg
import (
"context"
"encoding/json"
"errors"
"hyapi-server/internal/domains/api/dto"
"hyapi-server/internal/domains/api/services/processors"
)
// ProcessQCXG7K2NRequest QCXG7K2N 人车核验加强版:
// 优先经天远调用 QCXG3M7Z人车关系核验 ETC查无结果时降级调用本地 QCXGX2X6行驶证信息核验V2
func ProcessQCXG7K2NRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.QCXG7K2NReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
plateType := normalizePlateType(paramsDto.PlateType)
etcParams, err := json.Marshal(buildETCTianyuanParams(paramsDto.PlateNo, paramsDto.Name, paramsDto.PlateType))
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
respBytes, err := processors.CallTianyuanByProduct(ctx, deps, "QCXG3M7Z", etcParams)
if err == nil {
return respBytes, nil
}
if !errors.Is(err, processors.ErrNotFound) {
return nil, err
}
x2x6Params, err := json.Marshal(dto.QCXGX2X6Req{
PlateNo: paramsDto.PlateNo,
Name: paramsDto.Name,
VehicleType: plateType,
})
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
respBytes, err = ProcessQCXGX2X6Request(ctx, x2x6Params, deps)
if err != nil {
return nil, err
}
transformed, err := transformX2X6To3M7Z(respBytes)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return transformed, nil
}

View File

@@ -0,0 +1,29 @@
package qcxg
import (
"encoding/json"
"fmt"
)
// transformX2X6To3M7Z 将行驶证信息核验V2响应转换为 ETC 人车关系核验格式。
// checkResult: 00 姓名一致 -> status 101 姓名不一致 -> status 2。
func transformX2X6To3M7Z(respBytes []byte) ([]byte, error) {
var raw map[string]interface{}
if err := json.Unmarshal(respBytes, &raw); err != nil {
return nil, err
}
status := mapCheckResultToStatus(raw["checkResult"])
return json.Marshal(map[string]string{"status": status})
}
func mapCheckResultToStatus(checkResult interface{}) string {
switch fmt.Sprint(checkResult) {
case "00":
return "1"
case "01":
return "2"
default:
return "2"
}
}

View File

@@ -0,0 +1,38 @@
package qcxg
import (
"encoding/json"
"testing"
)
func TestTransformX2X6To3M7Z(t *testing.T) {
tests := []struct {
name string
input string
wantStat string
}{
{"姓名一致", `{"checkResult":"00","plate":"桂A12345"}`, "1"},
{"姓名不一致", `{"checkResult":"01","plate":"桂A12345"}`, "2"},
{"未知结果默认不一致", `{"checkResult":"99"}`, "2"},
{"缺少checkResult默认不一致", `{"plate":"桂A12345"}`, "2"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := transformX2X6To3M7Z([]byte(tt.input))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
var out map[string]string
if err := json.Unmarshal(got, &out); err != nil {
t.Fatalf("invalid json: %v", err)
}
if len(out) != 1 {
t.Fatalf("expected only status field, got %v", out)
}
if out["status"] != tt.wantStat {
t.Fatalf("status = %q, want %q", out["status"], tt.wantStat)
}
})
}
}