diff --git a/app/main/api/internal/logic/query/queryservicelogic.go b/app/main/api/internal/logic/query/queryservicelogic.go index 6e453dd..0e50cef 100644 --- a/app/main/api/internal/logic/query/queryservicelogic.go +++ b/app/main/api/internal/logic/query/queryservicelogic.go @@ -6,12 +6,12 @@ import ( "encoding/json" "fmt" "os" - "time" "qnc-server/app/main/api/internal/service" "qnc-server/common/ctxdata" "qnc-server/common/xerr" "qnc-server/pkg/lzkit/crypto" "qnc-server/pkg/lzkit/validator" + "time" "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/stores/redis" @@ -55,6 +55,21 @@ var productProcessors = map[string]func(*QueryServiceLogic, *types.QueryServiceR "backgroundcheck": (*QueryServiceLogic).ProcessBackgroundCheckLogic, "personalData": (*QueryServiceLogic).ProcessPersonalDataLogic, "consumerFinanceReport": (*QueryServiceLogic).ProcessConsumerFinanceReportLogic, + // 车辆类产品 + "toc_VehiclesUnderNameCount": (*QueryServiceLogic).ProcessVehiclesUnderNameCountLogic, + "toc_VehicleStaticInfo": (*QueryServiceLogic).ProcessVehicleVinCodeLogic, + "toc_VehicleMileageMixed": (*QueryServiceLogic).ProcessVehicleMileageMixedLogic, + "toc_VehicleVinValuation": (*QueryServiceLogic).ProcessVehicleVinValuationLogic, + "toc_VehicleTransferSimple": (*QueryServiceLogic).ProcessVehicleTransferSimpleLogic, + "toc_VehicleTransferDetail": (*QueryServiceLogic).ProcessVehicleVinCodeLogic, + "toc_VehicleMaintenanceSimple": (*QueryServiceLogic).ProcessVehicleMaintenanceSimpleLogic, + "toc_VehicleMaintenanceDetail": (*QueryServiceLogic).ProcessVehicleMaintenanceDetailLogic, + "toc_VehicleClaimDetail": (*QueryServiceLogic).ProcessVehicleClaimDetailLogic, + "toc_VehicleClaimVerify": (*QueryServiceLogic).ProcessVehicleClaimVerifyLogic, + "toc_VehiclesUnderName": (*QueryServiceLogic).ProcessMarriageLogic, + "toc_VehiclesUnderNamePlate": (*QueryServiceLogic).ProcessMarriageLogic, + "toc_PersonVehicleVerification": (*QueryServiceLogic).ProcessPersonVehicleVerificationLogic, + "toc_PersonVehicleVerificationDetail": (*QueryServiceLogic).ProcessPersonVehicleVerificationLogic, } func (l *QueryServiceLogic) PreprocessLogic(req *types.QueryServiceReq, product string) (*types.QueryServiceResp, error) { @@ -709,6 +724,435 @@ func (l *QueryServiceLogic) CacheData(params map[string]interface{}, Product str return outTradeNo, nil } +// ---- 车辆类产品处理方法 ---- + +// ProcessVehiclesUnderNameCountLogic 名下车辆(数量):仅 user_type + id_card +func (l *QueryServiceLogic) ProcessVehiclesUnderNameCountLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) { + decryptData, DecryptDataErr := l.DecryptData(req.Data) + if DecryptDataErr != nil { + return nil, DecryptDataErr + } + var data types.TocVehiclesUnderNameCountReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + userType := data.UserType + if userType == "" { + userType = "1" + } + params := map[string]interface{}{ + "user_type": userType, + "id_card": data.IDCard, + } + userID, err := l.GetOrCreateUser() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 处理用户失败: %v", err) + } + cacheNo, cacheDataErr := l.CacheData(params, "toc_VehiclesUnderNameCount", userID) + if cacheDataErr != nil { + return nil, cacheDataErr + } + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) + } + now := time.Now().Unix() + return &types.QueryServiceResp{ + Id: cacheNo, + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + +// ProcessVehicleVinCodeLogic 仅 vin_code(车辆静态信息、过户详版等) +func (l *QueryServiceLogic) ProcessVehicleVinCodeLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) { + decryptData, DecryptDataErr := l.DecryptData(req.Data) + if DecryptDataErr != nil { + return nil, DecryptDataErr + } + var data types.TocVehicleVinCodeReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + params := map[string]interface{}{ + "vin_code": data.VinCode, + } + product := req.Product + userID, err := l.GetOrCreateUser() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 处理用户失败: %v", err) + } + cacheNo, cacheDataErr := l.CacheData(params, product, userID) + if cacheDataErr != nil { + return nil, cacheDataErr + } + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) + } + now := time.Now().Unix() + return &types.QueryServiceResp{ + Id: cacheNo, + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + +// ProcessVehicleMileageMixedLogic 车辆里程记录(混合) QCXG1U4U +func (l *QueryServiceLogic) ProcessVehicleMileageMixedLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) { + decryptData, DecryptDataErr := l.DecryptData(req.Data) + if DecryptDataErr != nil { + return nil, DecryptDataErr + } + var data types.TocVehicleMileageMixedReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + params := map[string]interface{}{ + "vin_code": data.VinCode, + "image_url": data.ImageURL, + } + userID, err := l.GetOrCreateUser() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 处理用户失败: %v", err) + } + cacheNo, cacheDataErr := l.CacheData(params, "toc_VehicleMileageMixed", userID) + if cacheDataErr != nil { + return nil, cacheDataErr + } + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) + } + now := time.Now().Unix() + return &types.QueryServiceResp{ + Id: cacheNo, + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + +// ProcessVehicleVinValuationLogic 二手车VIN估值 QCXGY7F2 +func (l *QueryServiceLogic) ProcessVehicleVinValuationLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) { + decryptData, DecryptDataErr := l.DecryptData(req.Data) + if DecryptDataErr != nil { + return nil, DecryptDataErr + } + var data types.TocVehicleVinValuationReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + params := map[string]interface{}{ + "vin_code": data.VinCode, + "vehicle_location": data.VehicleLocation, + "first_registrationdate": data.FirstRegistrationDate, + } + userID, err := l.GetOrCreateUser() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 处理用户失败: %v", err) + } + cacheNo, cacheDataErr := l.CacheData(params, "toc_VehicleVinValuation", userID) + if cacheDataErr != nil { + return nil, cacheDataErr + } + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) + } + now := time.Now().Unix() + return &types.QueryServiceResp{ + Id: cacheNo, + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + +// ProcessVehicleTransferSimpleLogic 车辆过户简版 QCXG1H7Y +func (l *QueryServiceLogic) ProcessVehicleTransferSimpleLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) { + decryptData, DecryptDataErr := l.DecryptData(req.Data) + if DecryptDataErr != nil { + return nil, DecryptDataErr + } + var data types.TocVehicleTransferSimpleReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + params := map[string]interface{}{ + "vin_code": data.VinCode, + } + userID, err := l.GetOrCreateUser() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 处理用户失败: %v", err) + } + cacheNo, cacheDataErr := l.CacheData(params, "toc_VehicleTransferSimple", userID) + if cacheDataErr != nil { + return nil, cacheDataErr + } + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) + } + now := time.Now().Unix() + return &types.QueryServiceResp{ + Id: cacheNo, + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + +// ProcessVehicleMaintenanceSimpleLogic 车辆维保简版 QCXG3Y6B +func (l *QueryServiceLogic) ProcessVehicleMaintenanceSimpleLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) { + decryptData, DecryptDataErr := l.DecryptData(req.Data) + if DecryptDataErr != nil { + return nil, DecryptDataErr + } + var data types.TocVehicleMaintenanceSimpleReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + params := map[string]interface{}{ + "vin_code": data.VinCode, + } + userID, err := l.GetOrCreateUser() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 处理用户失败: %v", err) + } + cacheNo, cacheDataErr := l.CacheData(params, "toc_VehicleMaintenanceSimple", userID) + if cacheDataErr != nil { + return nil, cacheDataErr + } + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) + } + now := time.Now().Unix() + return &types.QueryServiceResp{ + Id: cacheNo, + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + +// ProcessVehicleMaintenanceDetailLogic 车辆维保详细版 QCXG3Z3L +func (l *QueryServiceLogic) ProcessVehicleMaintenanceDetailLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) { + decryptData, DecryptDataErr := l.DecryptData(req.Data) + if DecryptDataErr != nil { + return nil, DecryptDataErr + } + var data types.TocVehicleMaintenanceDetailReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + params := map[string]interface{}{ + "vin_code": data.VinCode, + } + userID, err := l.GetOrCreateUser() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 处理用户失败: %v", err) + } + cacheNo, cacheDataErr := l.CacheData(params, "toc_VehicleMaintenanceDetail", userID) + if cacheDataErr != nil { + return nil, cacheDataErr + } + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) + } + now := time.Now().Unix() + return &types.QueryServiceResp{ + Id: cacheNo, + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + +// ProcessVehicleClaimDetailLogic 车辆出险详版 QCXGP00W +func (l *QueryServiceLogic) ProcessVehicleClaimDetailLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) { + decryptData, DecryptDataErr := l.DecryptData(req.Data) + if DecryptDataErr != nil { + return nil, DecryptDataErr + } + var data types.TocVehicleClaimDetailReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + params := map[string]interface{}{ + "vin_code": data.VinCode, + "vlphoto_data": data.VlphotoData, + } + userID, err := l.GetOrCreateUser() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 处理用户失败: %v", err) + } + cacheNo, cacheDataErr := l.CacheData(params, "toc_VehicleClaimDetail", userID) + if cacheDataErr != nil { + return nil, cacheDataErr + } + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) + } + now := time.Now().Unix() + return &types.QueryServiceResp{ + Id: cacheNo, + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + +// ProcessVehicleClaimVerifyLogic 车辆出险记录核验 QCXG6B4E +func (l *QueryServiceLogic) ProcessVehicleClaimVerifyLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) { + decryptData, DecryptDataErr := l.DecryptData(req.Data) + if DecryptDataErr != nil { + return nil, DecryptDataErr + } + var data types.TocVehicleClaimVerifyReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + auth := data.Authorized + if auth == "" { + auth = "1" + } + params := map[string]interface{}{ + "vin_code": data.VINCode, + "authorized": auth, + } + userID, err := l.GetOrCreateUser() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 处理用户失败: %v", err) + } + cacheNo, cacheDataErr := l.CacheData(params, "toc_VehicleClaimVerify", userID) + if cacheDataErr != nil { + return nil, cacheDataErr + } + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) + } + now := time.Now().Unix() + return &types.QueryServiceResp{ + Id: cacheNo, + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + +// ProcessPersonVehicleVerificationLogic 人车核验简版:姓名+号牌类型+车牌号 +func (l *QueryServiceLogic) ProcessPersonVehicleVerificationLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) { + decryptData, DecryptDataErr := l.DecryptData(req.Data) + if DecryptDataErr != nil { + return nil, DecryptDataErr + } + var data types.TocPersonVehicleVerification + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + params := map[string]interface{}{ + "name": data.Name, + "plate_no": data.CarLicense, + "carplate_type": data.CarType, + } + userID, err := l.GetOrCreateUser() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 处理用户失败: %v", err) + } + cacheNo, cacheDataErr := l.CacheData(params, req.Product, userID) + if cacheDataErr != nil { + return nil, cacheDataErr + } + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) + } + now := time.Now().Unix() + return &types.QueryServiceResp{ + Id: cacheNo, + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + // GetOrCreateUser 获取或创建用户 // 1. 如果已登录,使用当前登录用户 // 2. 如果未登录,创建临时用户(UUID用户) diff --git a/app/main/api/internal/logic/query/queryservicelogic.md b/app/main/api/internal/logic/query/queryservicelogic.md new file mode 100644 index 0000000..bc1a25d --- /dev/null +++ b/app/main/api/internal/logic/query/queryservicelogic.md @@ -0,0 +1,921 @@ +package query + +import ( + "context" + "database/sql" + "encoding/hex" + "encoding/json" + "fmt" + "os" + "time" + "tyc-server/app/main/api/internal/service" + "tyc-server/app/main/model" + "tyc-server/common/ctxdata" + "tyc-server/common/globalkey" + "tyc-server/common/xerr" + "tyc-server/pkg/captcha" + "tyc-server/pkg/lzkit/crypto" + "tyc-server/pkg/lzkit/validator" + + "github.com/pkg/errors" + "github.com/zeromicro/go-zero/core/stores/redis" + + "tyc-server/app/main/api/internal/svc" + "tyc-server/app/main/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type QueryServiceLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewQueryServiceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryServiceLogic { + return &QueryServiceLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *QueryServiceLogic) QueryService(req *types.QueryServiceReq) (resp *types.QueryServiceResp, err error) { + if req.AgentIdentifier != "" { + l.ctx = context.WithValue(l.ctx, "agentIdentifier", req.AgentIdentifier) + } else if req.App { + l.ctx = context.WithValue(l.ctx, "app", req.App) + } + return l.PreprocessLogic(req, req.Product) +} + +// queryHandlerFunc 通用查询 handler:解密后的数据 + 产品名 -> 校验并返回待缓存的 params +// 新增产品时只需在 productHandlers 里加一行并选用已有 handler 类型即可,无需再写 ProcessXxx +type queryHandlerFunc func(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) + +var productHandlers = map[string]queryHandlerFunc{ + "marriage": runMarriageReq, + "homeservice": runMarriageReq, + "riskassessment": runMarriageReq, + "companyinfo": runMarriageReq, + "rentalinfo": runMarriageReq, + "preloanbackgroundcheck": runMarriageReq, + "backgroundcheck": runBackgroundCheckReq, + "personalData": runMarriageReq, + "toc_PersonalBadRecord": runPersonalBadRecordReq, + "toc_PersonalLawsuit": runMarriageReq, + "toc_EnterpriseLawsuit": runEntLawsuitReq, + // 人企关系加强版:仅身份证号 + "toc_PersonEnterprisePro": runPersonEnterpriseProReq, + // 新司法涉诉类产品 + "toc_EnterpriseLawsuitQYGL66SL": runEnterpriseLawsuitSimpleReq, + "toc_LimitHighExecuted": runLimitHighExecutedReq, + "toc_DishonestExecutedPerson": runDishonestExecutedReq, + "toc_Marriage": runMarriageReq, + "toc_PersonalMarriageStatus": runMarriageReq, + "toc_MarriageStatusRegisterTime": runMarriageReq, + "toc_MarriageStatusSupplement": runMarriageReq, + "toc_MarriageStatusVerify": runMarriageReq, + "toc_DualMarriageStatusRegisterTime": runDualMarriageReq, + "toc_VehiclesUnderName": runMarriageReq, + "toc_VehiclesUnderNamePlate": runMarriageReq, + "toc_PersonVehicleVerification": runPersonVehicleVerificationReq, + "toc_PersonVehicleVerificationDetail": runPersonVehicleVerificationReq, + // 车辆类产品(按 md 传参) + "toc_VehiclesUnderNameCount": runVehiclesUnderNameCountReq, + "toc_VehicleStaticInfo": runVehicleVinCodeReq, + "toc_VehicleMileageMixed": runVehicleMileageMixedReq, + "toc_VehicleVinValuation": runVehicleVinValuationReq, + "toc_VehicleTransferSimple": runVehicleTransferSimpleReq, + "toc_VehicleTransferDetail": runVehicleVinCodeReq, + "toc_VehicleMaintenanceSimple": runVehicleMaintenanceSimpleReq, + "toc_VehicleMaintenanceDetail": runVehicleMaintenanceDetailReq, + "toc_VehicleClaimDetail": runVehicleClaimDetailReq, + "toc_VehicleClaimVerify": runVehicleClaimVerifyReq, + // 核验工具(verify feature.md) + "toc_PoliceTwoFactors": runVerifyAuthTwoReq, + "toc_PoliceThreeFactors": runVerifyAuthThreeReq, + "toc_ProfessionalCertificate": runVerifyCertReq, + "toc_PersonalConsumptionCapacityLevel": runVerifyConsumptionReq, // 个人消费能力(沿用现有 product_en) + "toc_OperatorTwoFactors": runVerifyYysTwoReq, + "toc_MobileThreeFactors": runVerifyYysThreeReq, + "toc_NumberRecycle": runVerifyMobileOnlyReq, + "toc_MobileEmptyCheck": runVerifyMobileOnlyReq, + "toc_MobilePortability": runVerifyMobileOnlyReq, + "toc_MobileOnlineStatus": runVerifyMobileOnlyReq, + "toc_MobileOnlineDuration": runVerifyMobileOnlyReq, + "toc_MobileAttribution": runVerifyMobileOnlyReq, + "toc_MobileConsumptionRange": runVerifyYysConsumptionReq, + "toc_EnterpriseRelation": runVerifyEntRelationReq, + "toc_BankcardFourFactors": runVerifyBankFourReq, + "toc_BankcardBlacklist": runVerifyBankBlackReq, +} + +// productHasSmsCode 表示该 product 解密后的请求结构体中是否包含必填短信验证码 Code。 +// 有 Code 的产品在「获取验证码」时已经做了滑块,这里不再强制要求 CaptchaVerifyParam。 +// 其他产品(无 Code)在查询时必须传并校验 CaptchaVerifyParam,防止跳过图形验证; +// 微信小程序(X-Platform: wxmini,见 ctxdata.GetPlatformFromCtx)不嵌入 H5 滑块,由 PreprocessLogic 跳过图形校验。 +func productHasSmsCode(product string) bool { + switch product { + case "marriage", + "homeservice", + "riskassessment", + "companyinfo", + "rentalinfo", + "preloanbackgroundcheck", + "personalData", + "toc_PersonalLawsuit", + "toc_EnterpriseLawsuit", + "toc_Marriage", + "toc_PersonalMarriageStatus", + "toc_MarriageStatusRegisterTime", + "toc_MarriageStatusSupplement", + "toc_MarriageStatusVerify", + "toc_DualMarriageStatusRegisterTime", + "toc_VehiclesUnderName", + "toc_VehiclesUnderNamePlate": + return true + default: + return false + } +} + +func (l *QueryServiceLogic) PreprocessLogic(req *types.QueryServiceReq, product string) (*types.QueryServiceResp, error) { + // 无短信验证码 Code 的 product:查询前必须传并校验滑块;微信小程序端跳过(依赖登录态与 X-Platform) + requireCaptcha := !productHasSmsCode(product) + if requireCaptcha { + if plat, platErr := ctxdata.GetPlatformFromCtx(l.ctx); platErr == nil && plat == model.PlatformWxMini { + requireCaptcha = false + } + } + if requireCaptcha { + if req.CaptchaVerifyParam == "" { + return nil, errors.Wrapf(xerr.NewErrMsg("请完成图形验证"), "product %s requires captcha", product) + } + cfg := l.svcCtx.Config.Captcha + if err := captcha.Verify(captcha.Config{ + AccessKeyID: cfg.AccessKeyID, + AccessKeySecret: cfg.AccessKeySecret, + EndpointURL: cfg.EndpointURL, + SceneID: cfg.SceneID, + }, req.CaptchaVerifyParam); err != nil { + return nil, err + } + } + + decryptData, err := l.DecryptData(req.Data) + if err != nil { + return nil, err + } + handler, exists := productHandlers[product] + if !exists { + return nil, errors.New("未找到相应的处理程序") + } + params, err := handler(l, decryptData, product) + if err != nil { + return nil, err + } + return l.commonQueryTail(params, product) +} + +// commonQueryTail 通用收尾:写缓存、生成 token 并返回 +func (l *QueryServiceLogic) commonQueryTail(params map[string]interface{}, product string) (*types.QueryServiceResp, error) { + userID, err := l.GetOrCreateUser() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 处理用户失败: %v", err) + } + cacheNo, cacheDataErr := l.CacheData(params, product, userID) + if cacheDataErr != nil { + return nil, cacheDataErr + } + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) + } + now := time.Now().Unix() + return &types.QueryServiceResp{ + Id: cacheNo, + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + +// runMarriageReq 姓名+身份证+手机+验证码 类产品(婚恋、家政、司法涉诉、婚姻状况、名下车辆等) +func runMarriageReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.MarriageReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + if verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile); verifyErr != nil { + return nil, verifyErr + } + return map[string]interface{}{ + "name": data.Name, + "id_card": data.IDCard, + "mobile": data.Mobile, + }, nil +} + +func runBackgroundCheckReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.BackgroundCheckReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile); verifyErr != nil { + return nil, verifyErr + } + return map[string]interface{}{ + "name": data.Name, + "id_card": data.IDCard, + "mobile": data.Mobile, + }, nil +} + +// runEntLawsuitReq 企业司法涉诉:企业名称+统一社会信用代码+手机+验证码 +func runEntLawsuitReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.EntLawsuitReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + return map[string]interface{}{ + "ent_name": data.EntName, + "ent_code": data.EntCode, + "mobile": data.Mobile, + }, nil +} + +// 企业司法涉诉简版 QYGL66SL:仅企业名称,auth_date 与授权文件编码由后端自动生成 +func runEnterpriseLawsuitSimpleReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.EnterpriseLawsuitSimpleReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + now := time.Now() + start := now.AddDate(0, 0, -7) + end := now.AddDate(0, 0, 7) + authDate := fmt.Sprintf("%s-%s", start.Format("20060102"), end.Format("20060102")) + return map[string]interface{}{ + "ent_name": data.EntName, + "auth_date": authDate, + "auth_authorize_file_code": "AUTHTYC0001", + }, nil +} + +// 限高被执行人 FLXG3A9B +func runLimitHighExecutedReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.LimitHighExecutedReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + auth := data.Authorized + if auth == "" { + auth = "1" + } + return map[string]interface{}{ + "name": data.Name, + "id_card": data.IDCard, + "mobile_no": data.Mobile, + "authorized": auth, + }, nil +} + +// 本人不良 FLXGDEA9:姓名 + 身份证(授权由 ApiRequest 默认传 1) +func runPersonalBadRecordReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.PersonalBadRecordReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + return map[string]interface{}{ + "name": data.Name, + "id_card": data.IDCard, + }, nil +} + +// 失信被执行人 QYGL2S0W +func runDishonestExecutedReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.DishonestExecutedReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + tp := data.Type + if tp == "" { + tp = "per" + } + return map[string]interface{}{ + "type": tp, + "name": data.Name, + "id_card": data.IDCard, + }, nil +} + +// runDualMarriageReq 双人婚姻状态:男方/女方姓名+身份证+手机+验证码 +func runDualMarriageReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocDualMarriageReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + if verifyErr := l.VerifyTwo(data.NameMan, data.IDCardMan); verifyErr != nil { + return nil, verifyErr + } + if verifyErr := l.VerifyTwo(data.NameWoman, data.IDCardWoman); verifyErr != nil { + return nil, verifyErr + } + return map[string]interface{}{ + "name": data.NameMan, + "id_card": data.IDCardMan, + "mobile": data.Mobile, + "name_man": data.NameMan, + "id_card_man": data.IDCardMan, + "name_woman": data.NameWoman, + "id_card_woman": data.IDCardWoman, + }, nil +} + +// runPersonVehicleVerificationReq 人车核验简版:姓名+号牌类型+车牌号 +func runPersonVehicleVerificationReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocPersonVehicleVerification + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + + return map[string]interface{}{ + "name": data.Name, + "plate_no": data.CarLicense, + "carplate_type": data.CarType, + }, nil +} + +// runVehiclesUnderNameCountReq 名下车辆(数量) QCXG4D2E:仅 user_type + id_card +func runVehiclesUnderNameCountReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVehiclesUnderNameCountReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + userType := data.UserType + if userType == "" { + userType = "1" + } + return map[string]interface{}{ + "user_type": userType, + "id_card": data.IDCard, + }, nil +} + +// runVehicleVinCodeReq 仅 vin_code(车辆静态信息、过户详版等) +func runVehicleVinCodeReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVehicleVinCodeReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + return map[string]interface{}{ + "vin_code": data.VinCode, + }, nil +} + +// runVehicleMileageMixedReq 车辆里程记录(混合) QCXG1U4U +func runVehicleMileageMixedReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVehicleMileageMixedReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + // 回调地址由后端在 ApiRequestService 中统一生成,此处不再下发 return_url + return map[string]interface{}{ + "vin_code": data.VinCode, + "image_url": data.ImageURL, + }, nil +} + +// runVehicleVinValuationReq 二手车VIN估值 QCXGY7F2(仅必填) +func runVehicleVinValuationReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVehicleVinValuationReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + return map[string]interface{}{ + "vin_code": data.VinCode, + "vehicle_location": data.VehicleLocation, + "first_registrationdate": data.FirstRegistrationDate, + }, nil +} + +// runVehicleTransferSimpleReq 车辆过户简版 QCXG1H7Y(仅必填 vin_code) +func runVehicleTransferSimpleReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVehicleTransferSimpleReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + return map[string]interface{}{"vin_code": data.VinCode}, nil +} + +// runVehicleMaintenanceSimpleReq 车辆维保简版 QCXG3Y6B(仅必填 vin_code;回调地址后端自动生成) +func runVehicleMaintenanceSimpleReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVehicleMaintenanceSimpleReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + // 回调地址由后端在 ApiRequestService 中统一生成,此处不再下发 return_url + return map[string]interface{}{ + "vin_code": data.VinCode, + }, nil +} + +// runVehicleMaintenanceDetailReq 车辆维保详细版 QCXG3Z3L(仅必填 vin_code;回调地址后端自动生成) +func runVehicleMaintenanceDetailReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVehicleMaintenanceDetailReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + // 回调地址由后端在 ApiRequestService 中统一生成,此处不再下发 return_url + return map[string]interface{}{ + "vin_code": data.VinCode, + }, nil +} + +// runVehicleClaimDetailReq 车辆出险详版 QCXGP00W(仅必填 vin_code, vlphoto_data;回调地址后端自动生成),vlphoto_data 由 API 层加密为 data +func runVehicleClaimDetailReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVehicleClaimDetailReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + // 回调地址由后端在 ApiRequestService 中统一生成,此处不再下发 return_url + return map[string]interface{}{ + "vin_code": data.VinCode, + "vlphoto_data": data.VlphotoData, + }, nil +} + +// runVehicleClaimVerifyReq 车辆出险记录核验 QCXG6B4E +func runVehicleClaimVerifyReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVehicleClaimVerifyReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + if data.Mobile != "" && data.Code != "" { + if verifyCodeErr := l.VerifyCode(data.Mobile, data.Code); verifyCodeErr != nil { + return nil, verifyCodeErr + } + } + auth := data.Authorized + if auth == "" { + auth = "1" + } + return map[string]interface{}{ + "vin_code": data.VINCode, + "authorized": auth, + }, nil +} + +// runPersonEnterpriseProReq 人企关系加强版预查询:仅身份证号 +func runPersonEnterpriseProReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocPersonEnterpriseProReq + if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr) + } + if validatorErr := validator.Validate(data); validatorErr != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr) + } + return map[string]interface{}{ + "id_card": data.IDCard, + }, nil +} + +// --------------- 核验工具 handlers --------------- +func runVerifyAuthTwoReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVerifyAuthTwoReq + if err := json.Unmarshal(decryptData, &data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", err) + } + if err := validator.Validate(data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, err.Error()), "查询服务, 参数不正确: %+v", err) + } + return map[string]interface{}{"mobile_no": data.MobileNo, "id_card": data.IDCard, "name": data.Name}, nil +} + +func runVerifyAuthThreeReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVerifyAuthThreeReq + if err := json.Unmarshal(decryptData, &data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", err) + } + if err := validator.Validate(data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, err.Error()), "查询服务, 参数不正确: %+v", err) + } + return map[string]interface{}{"photo_data": data.PhotoData, "id_card": data.IDCard, "name": data.Name}, nil +} + +func runVerifyCertReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVerifyCertReq + if err := json.Unmarshal(decryptData, &data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", err) + } + if err := validator.Validate(data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, err.Error()), "查询服务, 参数不正确: %+v", err) + } + return map[string]interface{}{"id_card": data.IDCard, "name": data.Name}, nil +} + +func runVerifyConsumptionReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVerifyConsumptionReq + if err := json.Unmarshal(decryptData, &data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", err) + } + if err := validator.Validate(data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, err.Error()), "查询服务, 参数不正确: %+v", err) + } + return map[string]interface{}{"mobile_no": data.MobileNo, "id_card": data.IDCard, "name": data.Name}, nil +} + +func runVerifyYysTwoReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVerifyYysTwoReq + if err := json.Unmarshal(decryptData, &data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", err) + } + if err := validator.Validate(data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, err.Error()), "查询服务, 参数不正确: %+v", err) + } + return map[string]interface{}{"mobile_no": data.MobileNo, "name": data.Name}, nil +} + +func runVerifyYysThreeReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVerifyYysThreeReq + if err := json.Unmarshal(decryptData, &data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", err) + } + if err := validator.Validate(data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, err.Error()), "查询服务, 参数不正确: %+v", err) + } + return map[string]interface{}{"mobile_no": data.MobileNo, "id_card": data.IDCard, "name": data.Name}, nil +} + +func runVerifyMobileOnlyReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVerifyMobileOnlyReq + if err := json.Unmarshal(decryptData, &data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", err) + } + if err := validator.Validate(data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, err.Error()), "查询服务, 参数不正确: %+v", err) + } + return map[string]interface{}{"mobile_no": data.MobileNo}, nil +} + +func runVerifyYysConsumptionReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVerifyYysConsumptionReq + if err := json.Unmarshal(decryptData, &data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", err) + } + if err := validator.Validate(data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, err.Error()), "查询服务, 参数不正确: %+v", err) + } + return map[string]interface{}{"mobile_no": data.MobileNo, "authorized": data.Authorized}, nil +} + +func runVerifyEntRelationReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVerifyEntRelationReq + if err := json.Unmarshal(decryptData, &data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", err) + } + out := map[string]interface{}{} + if data.IDCard != "" { + out["id_card"] = data.IDCard + } + return out, nil +} + +func runVerifyBankFourReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVerifyBankFourReq + if err := json.Unmarshal(decryptData, &data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", err) + } + if err := validator.Validate(data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, err.Error()), "查询服务, 参数不正确: %+v", err) + } + return map[string]interface{}{ + "mobile_no": data.MobileNo, + "id_card": data.IDCard, + "bank_card": data.BankCard, + "name": data.Name, + }, nil +} + +func runVerifyBankBlackReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) { + var data types.TocVerifyBankBlackReq + if err := json.Unmarshal(decryptData, &data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", err) + } + if err := validator.Validate(data); err != nil { + return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, err.Error()), "查询服务, 参数不正确: %+v", err) + } + return map[string]interface{}{ + "mobile_no": data.MobileNo, + "id_card": data.IDCard, + "name": data.Name, + "bank_card": data.BankCard, + }, nil +} + +func (l *QueryServiceLogic) DecryptData(data string) ([]byte, error) { + secretKey := l.svcCtx.Config.Encrypt.SecretKey + key, decodeErr := hex.DecodeString(secretKey) + if decodeErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "密钥获取失败: %+v", decodeErr) + } + decryptData, aesDecryptErr := crypto.AesDecrypt(data, key) + if aesDecryptErr != nil || len(decryptData) == 0 { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解密失败: %+v", aesDecryptErr) + } + return decryptData, nil +} + +// 校验验证码(开发环境 ENV=development 可跳过) +func (l *QueryServiceLogic) VerifyCode(mobile string, code string) error { + if os.Getenv("ENV") == "development" { + return nil + } + secretKey := l.svcCtx.Config.Encrypt.SecretKey + encryptedMobile, err := crypto.EncryptMobile(mobile, secretKey) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密手机号失败: %+v", err) + } + codeRedisKey := fmt.Sprintf("%s:%s", "query", encryptedMobile) + cacheCode, err := l.svcCtx.Redis.Get(codeRedisKey) + if err != nil { + if errors.Is(err, redis.Nil) { + return errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "验证码过期: %s", mobile) + } + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "读取验证码redis缓存失败, mobile: %s, err: %+v", mobile, err) + } + if cacheCode != code { + return errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "验证码不正确: %s", mobile) + } + return nil +} + +func (l *QueryServiceLogic) IsAgentQuery() bool { + agentID, _ := l.ctx.Value("agentIdentifier").(string) + return agentID != "" +} + +// 二要素验证(仅姓名+身份证号)(开发环境不调用验证 API) +func (l *QueryServiceLogic) VerifyTwo(Name string, IDCard string) error { + if os.Getenv("ENV") == "development" { + return nil + } + twoVerification := service.TwoFactorVerificationRequest{ + Name: Name, + IDCard: IDCard, + } + verification, err := l.svcCtx.VerificationService.TwoFactorVerification(twoVerification) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "二要素验证失败: %v", err) + } + if !verification.Passed { + return errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "二要素验证不通过: %v", err) + } + return nil +} + +// 按代理/非代理切换要素验证:代理走三要素;非代理走二要素(开发环境不调用验证 API) +func (l *QueryServiceLogic) Verify(Name string, IDCard string, Mobile string) error { + if os.Getenv("ENV") == "development" { + return nil + } + if !l.IsAgentQuery() { + twoVerification := service.TwoFactorVerificationRequest{ + Name: Name, + IDCard: IDCard, + } + verification, err := l.svcCtx.VerificationService.TwoFactorVerification(twoVerification) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "二要素验证失败: %v", err) + } + if !verification.Passed { + return errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "二要素验证不通过: %v", err) + } + } else { + // 三要素验证 + if Mobile == "" { + return errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, "手机号不能为空"), "三要素验证参数不正确: mobile为空") + } + threeVerification := service.ThreeFactorVerificationRequest{ + Name: Name, + IDCard: IDCard, + Mobile: Mobile, + } + verification, err := l.svcCtx.VerificationService.ThreeFactorVerification(threeVerification) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "三要素验证失败: %v", err) + } + if !verification.Passed { + return errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "三要素验证不通过: %v", err) + } + } + return nil +} + +// 缓存 +func (l *QueryServiceLogic) CacheData(params map[string]interface{}, Product string, userID int64) (string, error) { + agentIdentifier, _ := l.ctx.Value("agentIdentifier").(string) + secretKey := l.svcCtx.Config.Encrypt.SecretKey + key, decodeErr := hex.DecodeString(secretKey) + if decodeErr != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取AES密钥失败: %+v", decodeErr) + } + paramsMarshal, marshalErr := json.Marshal(params) + if marshalErr != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 序列化参数失败: %+v", marshalErr) + } + encryptParams, aesEncryptErr := crypto.AesEncrypt(paramsMarshal, key) + if aesEncryptErr != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 加密参数失败: %+v", aesEncryptErr) + } + queryCache := types.QueryCacheLoad{ + Params: encryptParams, + Product: Product, + AgentIdentifier: agentIdentifier, + } + jsonData, marshalErr := json.Marshal(queryCache) + if marshalErr != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 序列化参数失败: %+v", marshalErr) + } + outTradeNo := "Q_" + l.svcCtx.AlipayService.GenerateOutTradeNo() + redisKey := fmt.Sprintf(types.QueryCacheKey, userID, outTradeNo) + cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour)) + if cacheErr != nil { + return "", cacheErr + } + + // 写入 query_user_record,用于后台按被查询人姓名/身份证/手机号追溯订单(见 query_user_record.sql 说明 1) + nameStr, _ := params["name"].(string) + idCardStr, _ := params["id_card"].(string) + mobileStr, _ := params["mobile"].(string) + if nameStr != "" || idCardStr != "" || mobileStr != "" { + var encName, encIdCard, encMobile string + if nameStr != "" { + encName, _ = crypto.AesEcbEncrypt([]byte(nameStr), key) + } + if idCardStr != "" { + encIdCard, _ = crypto.EncryptIDCard(idCardStr, key) + } + if mobileStr != "" { + encMobile, _ = crypto.EncryptMobile(mobileStr, secretKey) + } + agentIdent := sql.NullString{} + if agentIdentifier != "" { + agentIdent = sql.NullString{String: agentIdentifier, Valid: true} + } + rec := &model.QueryUserRecord{ + DeleteTime: sql.NullTime{}, + DelState: globalkey.DelStateNo, + Version: 0, + UserId: userID, + Name: encName, + IdCard: encIdCard, + Mobile: encMobile, + Product: Product, + QueryNo: outTradeNo, + OrderId: 0, + PlatformOrderId: sql.NullString{}, + AgentIdentifier: agentIdent, + } + _, insertErr := l.svcCtx.QueryUserRecordModel.Insert(l.ctx, nil, rec) + if insertErr != nil { + logx.WithContext(l.ctx).Errorf("CacheData 写入 query_user_record 失败: %v", insertErr) + } + } + + return outTradeNo, nil +} + +// GetOrCreateUser 获取或创建用户 +// 1. 如果上下文中已有用户ID,直接返回 +// 2. 如果是代理查询或APP请求,创建新用户 +// 3. 其他情况返回未登录错误 +func (l *QueryServiceLogic) GetOrCreateUser() (int64, error) { + // 尝试获取用户ID + claims, err := ctxdata.GetClaimsFromCtx(l.ctx) + if err != nil { + return 0, err + } + userID := claims.UserId + return userID, nil + + // // 如果不是未登录错误,说明是其他错误,直接返回 + // if !ctxdata.IsNoUserIdError(err) { + // return 0, err + // } + + // // 检查是否是代理查询或APP请求 + // isAgentQuery := false + // if agentID, ok := l.ctx.Value("agentIdentifier").(string); ok && agentID != "" { + // isAgentQuery = true + // } + // if app, ok := l.ctx.Value("app").(bool); ok && app { + // isAgentQuery = true + // } + + // // 如果不是代理查询或APP请求,返回未登录错误 + // if !isAgentQuery { + // return 0, ctxdata.ErrNoUserIdInCtx + // } + + // // 创建新用户 + // return l.svcCtx.UserService.RegisterUUIDUser(l.ctx) +} diff --git a/app/main/api/internal/types/query.go b/app/main/api/internal/types/query.go new file mode 100644 index 0000000..43933a1 --- /dev/null +++ b/app/main/api/internal/types/query.go @@ -0,0 +1,70 @@ +package types + +// ---- 车辆类产品请求结构体 ---- + +// TocVehiclesUnderNameCountReq 名下车辆(数量) QCXG4D2E:user_type + id_card +type TocVehiclesUnderNameCountReq struct { + UserType string `json:"user_type,optional"` // 1=个人(默认) 2=企业 + IDCard string `json:"id_card" validate:"required"` +} + +// TocVehicleVinCodeReq 仅 vin_code(车辆静态信息、过户详版等) +type TocVehicleVinCodeReq struct { + VinCode string `json:"vin_code" validate:"required"` + Mobile string `json:"mobile,optional"` + Code string `json:"code,optional"` +} + +// TocVehicleMileageMixedReq 车辆里程记录(混合) QCXG1U4U +type TocVehicleMileageMixedReq struct { + VinCode string `json:"vin_code" validate:"required"` + ImageURL string `json:"image_url,optional"` + Mobile string `json:"mobile,optional"` + Code string `json:"code,optional"` +} + +// TocVehicleVinValuationReq 二手车VIN估值 QCXGY7F2 +type TocVehicleVinValuationReq struct { + VinCode string `json:"vin_code" validate:"required"` + VehicleLocation string `json:"vehicle_location" validate:"required"` + FirstRegistrationDate string `json:"first_registrationdate" validate:"required"` + Mobile string `json:"mobile,optional"` + Code string `json:"code,optional"` +} + +// TocVehicleTransferSimpleReq 车辆过户简版 QCXG1H7Y +type TocVehicleTransferSimpleReq struct { + VinCode string `json:"vin_code" validate:"required"` + Mobile string `json:"mobile,optional"` + Code string `json:"code,optional"` +} + +// TocVehicleMaintenanceSimpleReq 车辆维保简版 QCXG3Y6B +type TocVehicleMaintenanceSimpleReq struct { + VinCode string `json:"vin_code" validate:"required"` + Mobile string `json:"mobile,optional"` + Code string `json:"code,optional"` +} + +// TocVehicleMaintenanceDetailReq 车辆维保详细版 QCXG3Z3L +type TocVehicleMaintenanceDetailReq struct { + VinCode string `json:"vin_code" validate:"required"` + Mobile string `json:"mobile,optional"` + Code string `json:"code,optional"` +} + +// TocVehicleClaimDetailReq 车辆出险详版 QCXGP00W +type TocVehicleClaimDetailReq struct { + VinCode string `json:"vin_code" validate:"required"` + VlphotoData string `json:"vlphoto_data" validate:"required"` + Mobile string `json:"mobile,optional"` + Code string `json:"code,optional"` +} + +// TocVehicleClaimVerifyReq 车辆出险记录核验 QCXG6B4E +type TocVehicleClaimVerifyReq struct { + VINCode string `json:"vin_code" validate:"required"` + Authorized string `json:"authorized,optional"` + Mobile string `json:"mobile,optional"` + Code string `json:"code,optional"` +}