feat(user): temp

This commit is contained in:
liangzai 2024-12-24 11:37:25 +08:00
parent 4748bb0cfb
commit 97e14bbe37
36 changed files with 1980 additions and 656 deletions

View File

@ -33,6 +33,7 @@ service main {
prefix: api/v1
group: pay
jwt: JwtAuth
middleware: SourceInterceptor
)
service main {
// 支付

View File

@ -19,6 +19,10 @@ import (
jwt: JwtAuth
)
service main {
@doc "query service"
@handler queryService
post /query/service/:product (QueryServiceReq) returns (QueryServiceResp)
@doc "query marriage"
@handler marriage
post /query/marriage (QueryReq) returns (QueryResp)
@ -76,6 +80,10 @@ service main {
@handler queryDetailByOrderId
get /query/orderId/:order_id (QueryDetailByOrderIdReq) returns (QueryDetailByOrderIdResp)
@doc "查询详情 按订单号"
@handler queryDetailByOrderNo
get /query/orderNo/:order_no (QueryDetailByOrderNoReq) returns (QueryDetailByOrderNoResp)
@doc "查询详情"
@handler queryDetail
get /query/:id (QueryDetailReq) returns (QueryDetailResp)

View File

@ -16,15 +16,25 @@ type (
}
)
type (
QueryServiceReq {
Product string `path:"product"`
Data string `json:"data" validate:"required"`
}
QueryServiceResp {
id string `json:"id"`
}
)
type Query {
Id int64 `json:"id"` // 主键ID
OrderId int64 `json:"order_id"` // 订单ID
UserId int64 `json:"user_id"` // 用户ID
ProductId int64 `json:"product_id"` // 产品ID
QueryData []map[string]interface{} `json:"query_data"`
CreateTime string `json:"create_time"` // 创建时间
UpdateTime string `json:"update_time"` // 更新时间
QueryState string `json:"query_state"` // 查询状态
Id int64 `json:"id"` // 主键ID
OrderId int64 `json:"order_id"` // 订单ID
UserId int64 `json:"user_id"` // 用户ID
ProductName string `json:"product_name"` // 产品ID
QueryData []map[string]interface{} `json:"query_data"`
CreateTime string `json:"create_time"` // 创建时间
UpdateTime string `json:"update_time"` // 更新时间
QueryState string `json:"query_state"` // 查询状态
}
// 获取查询临时订单
@ -78,6 +88,15 @@ type (
}
)
type (
QueryDetailByOrderNoReq {
OrderNo string `path:"order_no"`
}
QueryDetailByOrderNoResp {
Query
}
)
type (
QueryRetryReq {
Id int64 `path:"id"`

View File

@ -31,6 +31,15 @@ service main {
@doc "mobile code login"
@handler mobileCodeLogin
post /user/mobileCodeLogin (MobileCodeLoginReq) returns (MobileCodeLoginResp)
@doc "wechat mini auth"
@handler wxMiniAuth
post /user/wxMiniAuth (WXMiniAuthReq) returns (WXMiniAuthResp)
@doc "wechat h5 auth"
@handler wxH5Auth
post /user/wxh5Auth (WXH5AuthReq) returns (WXH5AuthResp)
}
//need login
@ -43,10 +52,6 @@ service main {
@doc "get user info"
@handler detail
get /user/detail returns (UserInfoResp)
@doc "wechat mini auth"
@handler wxMiniAuth
post /user/wxMiniAuth (WXMiniAuthReq) returns (WXMiniAuthResp)
}
//============================> auth v1 <============================

View File

@ -62,7 +62,16 @@ type (
RefreshAfter int64 `json:"refreshAfter"`
}
)
type (
WXH5AuthReq {
Code string `json:"code"`
}
WXH5AuthResp {
AccessToken string `json:"accessToken"`
AccessExpire int64 `json:"accessExpire"`
RefreshAfter int64 `json:"refreshAfter"`
}
)
type (
UserInfoResp {
UserInfo User `json:"userInfo"`

View File

@ -14,8 +14,8 @@ VerifyCode:
AccessKeyID: "LTAI5tKGB3TVJbMHSoZN3yr9"
AccessKeySecret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
EndpointURL: "dysmsapi.aliyuncs.com"
SignName: "天远数据"
TemplateCode: "SMS_474525324"
SignName: "全能查"
TemplateCode: "SMS_473780047"
ValidTime: 300
Encrypt:
SecretKey: "ff83609b2b24fc73196aac3d3dfb874f"
@ -47,4 +47,6 @@ Applepay:
KeyID: "LAY65829DQ"
LoadPrivateKeyPath: "etc/merchant/AuthKey_LAY65829DQ.p8"
Ali:
Code: "d55b58829efb41c8aa8e86769cba4844"
Code: "d55b58829efb41c8aa8e86769cba4844"
SystemConfig:
ThreeVerify: false

View File

@ -4,7 +4,7 @@ Port: 8888
DataSource: "qnc:5vg67b3UNHu8@tcp(qnc_mysql:3306)/qnc?charset=utf8mb4&parseTime=True&loc=Local"
CacheRedis:
- Host: "qnc_redis:6379"
Pass: "3m3WsgyCKWqz" # Redis 密码,如果未设置则留空
Pass: " " # Redis 密码,如果未设置则留空
Type: "node" # 单节点模式
JwtAuth:
@ -48,4 +48,6 @@ Applepay:
KeyID: "LAY65829DQ"
LoadPrivateKeyPath: "etc/merchant/AuthKey_LAY65829DQ.p8"
Ali:
Code: "d55b58829efb41c8aa8e86769cba4844"
Code: "d55b58829efb41c8aa8e86769cba4844"
SystemConfig:
ThreeVerify: false

View File

@ -7,16 +7,17 @@ import (
type Config struct {
rest.RestConf
DataSource string
CacheRedis cache.CacheConf
JwtAuth JwtAuth // JWT 鉴权相关配置
VerifyCode VerifyCode
Encrypt Encrypt
Alipay AlipayConfig
Wxpay WxpayConfig
Applepay ApplepayConfig
Ali AliConfig
WestConfig WestConfig
DataSource string
CacheRedis cache.CacheConf
JwtAuth JwtAuth // JWT 鉴权相关配置
VerifyCode VerifyCode
Encrypt Encrypt
Alipay AlipayConfig
Wxpay WxpayConfig
Applepay ApplepayConfig
Ali AliConfig
WestConfig WestConfig
SystemConfig SystemConfig
}
// JwtAuth 用于 JWT 鉴权配置
@ -71,3 +72,7 @@ type WestConfig struct {
SecretId string
SecretSecondId string
}
type SystemConfig struct {
ThreeVerify bool
}

View File

@ -0,0 +1,29 @@
package query
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"qnc-server/app/user/cmd/api/internal/logic/query"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/api/internal/types"
"qnc-server/common/result"
"qnc-server/pkg/lzkit/validator"
)
func QueryDetailByOrderNoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.QueryDetailByOrderNoReq
if err := httpx.Parse(r, &req); err != nil {
result.ParamErrorResult(r, w, err)
return
}
if err := validator.Validate(req); err != nil {
result.ParamValidateErrorResult(r, w, err)
return
}
l := query.NewQueryDetailByOrderNoLogic(r.Context(), svcCtx)
resp, err := l.QueryDetailByOrderNo(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@ -0,0 +1,24 @@
package query
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"qnc-server/app/user/cmd/api/internal/logic/query"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/api/internal/types"
"qnc-server/common/result"
)
func QueryServiceHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.QueryServiceReq
if err := httpx.Parse(r, &req); err != nil {
result.ParamErrorResult(r, w, err)
return
}
l := query.NewQueryServiceLogic(r.Context(), svcCtx)
resp, err := l.QueryService(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@ -49,18 +49,21 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
)
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodPost,
Path: "/pay/iap_callback",
Handler: pay.IapCallbackHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/pay/payment",
Handler: pay.PaymentHandler(serverCtx),
},
},
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.SourceInterceptor},
[]rest.Route{
{
Method: http.MethodPost,
Path: "/pay/iap_callback",
Handler: pay.IapCallbackHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/pay/payment",
Handler: pay.PaymentHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1"),
)
@ -126,6 +129,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/query/riskAssessment",
Handler: query.RiskAssessmentHandler(serverCtx),
},
{
// query service
Method: http.MethodPost,
Path: "/query/service/:product",
Handler: query.QueryServiceHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1"),
@ -157,6 +166,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/query/orderId/:order_id",
Handler: query.QueryDetailByOrderIdHandler(serverCtx),
},
{
// 查询详情 按订单号
Method: http.MethodGet,
Path: "/query/orderNo/:order_no",
Handler: query.QueryDetailByOrderNoHandler(serverCtx),
},
{
// 获取查询临时订单
Method: http.MethodGet,
@ -194,6 +209,18 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/user/register",
Handler: user.RegisterHandler(serverCtx),
},
{
// wechat mini auth
Method: http.MethodPost,
Path: "/user/wxMiniAuth",
Handler: user.WxMiniAuthHandler(serverCtx),
},
{
// wechat h5 auth
Method: http.MethodPost,
Path: "/user/wxh5Auth",
Handler: user.WxH5AuthHandler(serverCtx),
},
},
rest.WithPrefix("/api/v1"),
)
@ -206,12 +233,6 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/user/detail",
Handler: user.DetailHandler(serverCtx),
},
{
// wechat mini auth
Method: http.MethodPost,
Path: "/user/wxMiniAuth",
Handler: user.WxMiniAuthHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1"),

View File

@ -0,0 +1,29 @@
package user
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"qnc-server/app/user/cmd/api/internal/logic/user"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/api/internal/types"
"qnc-server/common/result"
"qnc-server/pkg/lzkit/validator"
)
func WxH5AuthHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.WXH5AuthReq
if err := httpx.Parse(r, &req); err != nil {
result.ParamErrorResult(r, w, err)
return
}
if err := validator.Validate(req); err != nil {
result.ParamValidateErrorResult(r, w, err)
return
}
l := user.NewWxH5AuthLogic(r.Context(), svcCtx)
resp, err := l.WxH5Auth(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@ -40,7 +40,7 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
if cacheErr != nil {
return nil, cacheErr
}
var data types.QueryCache
var data types.QueryCacheLoad
err = json.Unmarshal([]byte(cache), &data)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 解析缓存内容失败, %+v", err)
@ -55,7 +55,11 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
if decodeErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取AES密钥失败: %+v", decodeErr)
}
encryptParams, aesEncryptErr := crypto.AesEncrypt([]byte(cache), key)
params, marshalErr := json.Marshal(data.Params)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 序列化参数失败: %+v", marshalErr)
}
encryptParams, aesEncryptErr := crypto.AesEncrypt(params, key)
if aesEncryptErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 加密参数失败: %+v", aesEncryptErr)
}
@ -65,10 +69,10 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
var createOrderErr error
if req.PayMethod == "wechatpay" {
outTradeNo = l.svcCtx.WechatPayService.GenerateOutTradeNo()
prepayID, createOrderErr = l.svcCtx.WechatPayService.CreateWechatAppOrder(l.ctx, product.SellPrice, product.Description, outTradeNo)
prepayID, createOrderErr = l.svcCtx.WechatPayService.CreateWechatOrder(l.ctx, product.SellPrice, product.Description, outTradeNo)
} else if req.PayMethod == "alipay" {
outTradeNo = l.svcCtx.AlipayService.GenerateOutTradeNo()
prepayID, createOrderErr = l.svcCtx.AlipayService.CreateAlipayAppOrder(product.SellPrice, product.Description, outTradeNo)
prepayID, createOrderErr = l.svcCtx.AlipayService.CreateAlipayOrder(l.ctx, product.SellPrice, product.Description, outTradeNo)
} else if req.PayMethod == "appleiap" {
outTradeNo = l.svcCtx.ApplePayService.GenerateOutTradeNo()
prepayID = l.svcCtx.ApplePayService.GetIappayAppID(product.ProductEn)

View File

@ -94,7 +94,7 @@ func (l *MarriageLogic) Marriage(req *types.QueryReq) (resp *types.QueryResp, er
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "婚恋评估, 验证码不正确: %s", data.Mobile)
}
//// 3、二要素三要素核验
//// 3、二要素核验
//twoVerification := service.TwoFactorVerificationRequest{
// Name: data.Name,
// IDCard: data.IDCard,
@ -106,7 +106,7 @@ func (l *MarriageLogic) Marriage(req *types.QueryReq) (resp *types.QueryResp, er
//if !verification.Passed {
// return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "婚恋评估, 二要素验证不通过: %+v", err)
//}
// 3、二要素三要素核验
// 3、三要素核验
threeVerification := service.ThreeFactorVerificationRequest{
Name: data.Name,
IDCard: data.IDCard,

View File

@ -65,8 +65,8 @@ func (l *QueryDetailByOrderIdLogic) QueryDetailByOrderId(req *types.QueryDetailB
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找订单错误: %+v", err)
}
}
if order.Status != "paid" {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIC_QUERY_WAIT, ""), "")
if order.Status == "failed" {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIC_QUERY_ERROR, ""), "")
}
// 获取报告信息
queryModel, err := l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, req.OrderId)
@ -125,7 +125,11 @@ func (l *QueryDetailByOrderIdLogic) QueryDetailByOrderId(req *types.QueryDetailB
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结构体复制失败, %+v", err)
}
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %+v", err)
}
query.ProductName = product.ProductName
return &types.QueryDetailByOrderIdResp{
Query: query,
}, nil

View File

@ -0,0 +1,132 @@
package query
import (
"context"
"encoding/hex"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"qnc-server/common/xerr"
"qnc-server/pkg/lzkit/delay"
"time"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type QueryDetailByOrderNoLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryDetailByOrderNoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryDetailByOrderNoLogic {
return &QueryDetailByOrderNoLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryDetailByOrderNoLogic) QueryDetailByOrderNo(req *types.QueryDetailByOrderNoReq) (resp *types.QueryDetailByOrderNoResp, err error) {
// 获取订单信息
order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %+v", err)
}
// 创建渐进式延迟策略实例
progressiveDelayOrder, err := delay.New(200*time.Millisecond, 3*time.Second, 10*time.Second, 1.5)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "初始化渐进式延迟策略失败: %+v", err)
}
// 等待订单状态变为 "paid"
startTime := time.Now()
for order.Status == "pending" {
if time.Since(startTime) > 10*time.Second {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIC_QUERY_WAIT, ""), "")
}
// 使用渐进式延迟,获取下次延迟时间
nextDelay, _ := progressiveDelayOrder.NextDelay()
// 等待一段时间后再查一次订单状态
time.Sleep(nextDelay)
// 再次查找订单
order, err = l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找订单错误: %+v", err)
}
}
if order.Status != "paid" {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIC_QUERY_WAIT, ""), "")
}
// 获取报告信息
queryModel, err := l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, order.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %+v", err)
}
// 创建渐进式延迟实例
progressiveDelayQuery, err := delay.New(200*time.Millisecond, 3*time.Second, 10*time.Second, 1.5)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "初始化渐进式延迟策略失败: %+v", err)
}
// 等待 queryModel.QueryState 不再是 "pending"
startTime = time.Now()
for queryModel.QueryState == "pending" {
if time.Since(startTime) > 10*time.Second {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询超时,查询状态长时间为 'pending'")
}
// 使用渐进式延迟,获取下次延迟时间
nextDelay, _ := progressiveDelayQuery.NextDelay()
// 每隔一段时间检查一次查询状态
time.Sleep(nextDelay)
// 再次查询 report 状态
queryModel, err = l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, order.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %+v", err)
}
}
// 根据 QueryState 做后续处理
if queryModel.QueryState == "failed" {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIC_QUERY_ERROR, ""), "")
}
var query types.Query
query.CreateTime = queryModel.CreateTime.Format("2006-01-02 15:04:05")
query.UpdateTime = queryModel.UpdateTime.Format("2006-01-02 15:04:05")
// 解密查询数据
secretKey := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取AES解密解药失败, %+v", err)
}
processErr := ProcessQueryData(queryModel.QueryData, &query.QueryData, key)
if processErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结果处理失败: %v", processErr)
}
// 复制报告数据
err = copier.Copy(&query, queryModel)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结构体复制失败, %+v", err)
}
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %+v", err)
}
query.ProductName = product.ProductName
return &types.QueryDetailByOrderNoResp{
Query: query,
}, nil
}

View File

@ -58,6 +58,11 @@ func (l *QueryDetailLogic) QueryDetail(req *types.QueryDetailReq) (resp *types.Q
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结构体复制失败, %+v", err)
}
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %+v", err)
}
query.ProductName = product.ProductName
return &types.QueryDetailResp{
Query: query,
}, nil

View File

@ -51,6 +51,11 @@ func (l *QueryExampleLogic) QueryExample(req *types.QueryExampleReq) (resp *type
if copyErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 示例报告结构体复制失败, %+v", err)
}
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 获取商品信息失败, %+v", err)
}
query.ProductName = product.ProductName
return &types.QueryExampleResp{
Query: query,
}, nil

View File

@ -50,6 +50,11 @@ func (l *QueryListLogic) QueryList(req *types.QueryListReq) (resp *types.QueryLi
if copyErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告列表查询, 报告结构体复制失败, %+v", err)
}
product, findProductErr := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
if findProductErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告列表查询, 获取商品信息失败, %+v", err)
}
query.ProductName = product.ProductName
list = append(list, query)
}
}

View File

@ -0,0 +1,717 @@
package query
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"qnc-server/app/user/cmd/api/internal/service"
"qnc-server/common/ctxdata"
"qnc-server/common/xerr"
"qnc-server/pkg/lzkit/crypto"
"qnc-server/pkg/lzkit/validator"
"time"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/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) {
return l.PreprocessLogic(req, req.Product)
}
var productProcessors = map[string]func(*QueryServiceLogic, *types.QueryServiceReq) (*types.QueryServiceResp, error){
"marriage": (*QueryServiceLogic).ProcessMarriageLogic,
"homeservice": (*QueryServiceLogic).ProcessHomeServiceLogic,
"riskassessment": (*QueryServiceLogic).ProcessRiskAssessmentLogic,
"companyinfo": (*QueryServiceLogic).ProcessCompanyInfoLogic,
"rentalinfo": (*QueryServiceLogic).ProcessRentalInfoLogic,
"preloanbackgroundcheck": (*QueryServiceLogic).ProcessPreLoanBackgroundCheckLogic,
"backgroundcheck": (*QueryServiceLogic).ProcessBackgroundCheckLogic,
"toc_marriage": (*QueryServiceLogic).ProcessTocMarriageLogic,
"toc_PersonalBadRecord": (*QueryServiceLogic).ProcessTocPersonalBadRecordLogic,
"toc_ShareholderBusinessRelation": (*QueryServiceLogic).ProcessTocShareholderBusinessRelationLogic,
"toc_PersonalLawsuit": (*QueryServiceLogic).ProcessTocPersonalLawsuitLogic,
"toc_EnterpriseLawsuit": (*QueryServiceLogic).ProcessTocEnterpriseLawsuitLogic,
}
func (l *QueryServiceLogic) PreprocessLogic(req *types.QueryServiceReq, product string) (*types.QueryServiceResp, error) {
if processor, exists := productProcessors[product]; exists {
return processor(l, req) // 调用对应的处理函数
}
return nil, errors.New("未找到相应的处理程序")
}
func (l *QueryServiceLogic) ProcessMarriageLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{
"name": data.Name,
"id_card": data.IDCard,
"mobile": data.Mobile,
}
cacheNo, cacheDataErr := l.CacheData(params, "marriage", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, nil
}
// 处理家政服务相关逻辑
func (l *QueryServiceLogic) ProcessHomeServiceLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
var data types.HomeServiceReq
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{
"name": data.Name,
"id_card": data.IDCard,
"mobile": data.Mobile,
}
cacheNo, cacheDataErr := l.CacheData(params, "homeservice", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, nil
}
// 处理风险评估相关逻辑
func (l *QueryServiceLogic) ProcessRiskAssessmentLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
var data types.RiskAssessmentReq
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{
"name": data.Name,
"id_card": data.IDCard,
"mobile": data.Mobile,
}
cacheNo, cacheDataErr := l.CacheData(params, "riskassessment", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, nil
}
// 处理公司信息查询相关逻辑
func (l *QueryServiceLogic) ProcessCompanyInfoLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
var data types.CompanyInfoReq
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{
"name": data.Name,
"id_card": data.IDCard,
"mobile": data.Mobile,
}
cacheNo, cacheDataErr := l.CacheData(params, "companyinfo", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, nil
}
// 处理租赁信息查询相关逻辑
func (l *QueryServiceLogic) ProcessRentalInfoLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
var data types.RentalInfoReq
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{
"name": data.Name,
"id_card": data.IDCard,
"mobile": data.Mobile,
}
cacheNo, cacheDataErr := l.CacheData(params, "rentalinfo", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, nil
}
// 处理贷前背景检查相关逻辑
func (l *QueryServiceLogic) ProcessPreLoanBackgroundCheckLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
var data types.PreLoanBackgroundCheckReq
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{
"name": data.Name,
"id_card": data.IDCard,
"mobile": data.Mobile,
}
cacheNo, cacheDataErr := l.CacheData(params, "preloanbackgroundcheck", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, nil
}
// 处理人事背调相关逻辑
func (l *QueryServiceLogic) ProcessBackgroundCheckLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{
"name": data.Name,
"id_card": data.IDCard,
"mobile": data.Mobile,
}
cacheNo, cacheDataErr := l.CacheData(params, "backgroundcheck", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, nil
}
func (l *QueryServiceLogic) ProcessTocMarriageLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{
"name": data.Name,
"id_card": data.IDCard,
"mobile": data.Mobile,
}
cacheNo, cacheDataErr := l.CacheData(params, "toc_marriage", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, nil
}
func (l *QueryServiceLogic) ProcessTocPersonalBadRecordLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{
"name": data.Name,
"id_card": data.IDCard,
"mobile": data.Mobile,
}
cacheNo, cacheDataErr := l.CacheData(params, "toc_PersonalBadRecord", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, nil
}
func (l *QueryServiceLogic) ProcessTocShareholderBusinessRelationLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{
"name": data.Name,
"id_card": data.IDCard,
"mobile": data.Mobile,
}
cacheNo, cacheDataErr := l.CacheData(params, "toc_ShareholderBusinessRelation", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, nil
}
func (l *QueryServiceLogic) ProcessTocPersonalLawsuitLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{
"name": data.Name,
"id_card": data.IDCard,
"mobile": data.Mobile,
}
cacheNo, cacheDataErr := l.CacheData(params, "toc_PersonalLawsuit", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, nil
}
func (l *QueryServiceLogic) ProcessTocEnterpriseLawsuitLogic(req *types.QueryServiceReq) (*types.QueryServiceResp, error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 获取用户信息失败, %+v", getUidErr)
}
// AES解密
decryptData, DecryptDataErr := l.DecryptData(req.Data)
if DecryptDataErr != nil {
return nil, DecryptDataErr
}
// 校验参数
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)
}
// 校验验证码
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素 后期应改为企业二要素
//verifyErr := l.Verify(data, data.IDCard, data.Mobile)
//if verifyErr != nil {
// return nil, verifyErr
//}
// 缓存
params := map[string]interface{}{
"ent_name": data.EntName,
"ent_code": data.EntCode,
}
cacheNo, cacheDataErr := l.CacheData(params, "toc_EnterpriseLawsuit", userID)
if cacheDataErr != nil {
return nil, cacheDataErr
}
return &types.QueryServiceResp{Id: cacheNo}, 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
}
// 校验验证码
func (l *QueryServiceLogic) VerifyCode(mobile string, code string) error {
codeRedisKey := fmt.Sprintf("%s:%s", "query", mobile)
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) Verify(Name string, IDCard string, Mobile string) error {
if l.svcCtx.Config.SystemConfig.ThreeVerify {
// 三要素验证
threeVerification := service.ThreeFactorVerificationRequest{
Name,
IDCard,
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)
}
} else {
twoVerification := service.TwoFactorVerificationRequest{
Name,
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
}
// 缓存
func (l *QueryServiceLogic) CacheData(params map[string]interface{}, Product string, userID int64) (string, error) {
queryCache := types.QueryCacheLoad{
Params: params,
Product: Product,
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return "", cacheErr
}
return outTradeNo, nil
}

View File

@ -0,0 +1,134 @@
package user
import (
"context"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"io"
"net/http"
"qnc-server/app/user/model"
jwtx "qnc-server/common/jwt"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type WxH5AuthLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewWxH5AuthLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WxH5AuthLogic {
return &WxH5AuthLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthResp, err error) {
// Step 1: 使用code获取access_token
accessTokenResp, err := GetAccessToken(req.Code)
if err != nil {
return nil, errors.Wrap(err, "获取access_token失败")
}
// Step 2: 查找用户授权信息
userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, accessTokenResp.Openid, "h5-weixin")
if findErr != nil && !errors.Is(findErr, model.ErrNotFound) {
return nil, errors.Wrapf(findErr, "查询用户授权失败openid: %s", accessTokenResp.Openid)
}
// Step 3: 查找或创建用户
var user *model.User
if userAuth != nil {
// 授权信息存在,查找用户
userModel, findUserErr := l.svcCtx.UserModel.FindOne(l.ctx, userAuth.UserId)
if findUserErr != nil {
return nil, errors.Wrapf(findUserErr, "查询用户失败userId: %d", userAuth.UserId)
}
user = userModel
} else {
// 授权信息不存在,创建新用户
user = &model.User{}
if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(context context.Context, session sqlx.Session) error {
// 插入数据库
insertResult, insertErr := l.svcCtx.UserModel.Insert(l.ctx, session, user)
if insertErr != nil {
return errors.Wrapf(insertErr, "创建新用户失败openid: %s", accessTokenResp.Openid)
}
// 获取插入后生成的 user.Id
lastInsertId, lastInsertIdErr := insertResult.LastInsertId()
if lastInsertIdErr != nil {
return errors.Wrapf(lastInsertIdErr, "获取新用户ID失败openid: %s", accessTokenResp.Openid)
}
user.Id = lastInsertId
// 创建用户授权信息
userAuth = &model.UserAuth{
UserId: user.Id,
AuthKey: accessTokenResp.Openid,
AuthType: "mp-weixin", // 微信小程序
}
if _, insertUserAuthErr := l.svcCtx.UserAuthModel.Insert(l.ctx, session, userAuth); insertUserAuthErr != nil {
return errors.Wrapf(insertUserAuthErr, "创建用户授权失败openid: %s", accessTokenResp.Openid)
}
return nil
}); transErr != nil {
return nil, transErr
}
}
// Step 4: 生成JWT Token
token, genErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if genErr != nil {
return nil, errors.Wrap(genErr, "生成JWT token失败")
}
// 返回登录信息
return &types.WXH5AuthResp{
AccessToken: token,
AccessExpire: l.svcCtx.Config.JwtAuth.AccessExpire,
RefreshAfter: l.svcCtx.Config.JwtAuth.RefreshAfter,
}, nil
}
type AccessTokenResp struct {
AccessToken string `json:"access_token"`
Openid string `json:"openid"`
}
// GetAccessToken 通过code获取access_token
func GetAccessToken(code string) (*AccessTokenResp, error) {
appID := "wxd1554b7a57cecc9e"
appSecret := "fb8026c0bc66625b580453300d4b43db"
url := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", appID, appSecret, code)
resp, err := http.Get(url)
if err != nil {
return nil, errors.Wrap(err, "获取access_token失败")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "读取access_token响应失败")
}
var accessTokenResp AccessTokenResp
if err := json.Unmarshal(body, &accessTokenResp); err != nil {
return nil, errors.Wrap(err, "解析access_token响应失败")
}
if accessTokenResp.AccessToken == "" {
return nil, errors.New("获取access_token失败")
}
return &accessTokenResp, nil
}

View File

@ -0,0 +1,41 @@
package middleware
import (
"context"
"net/http"
)
const (
BrandKey = "X-Brand"
PlatformKey = "X-Platform"
)
type SourceInterceptorMiddleware struct {
}
func NewSourceInterceptorMiddleware() *SourceInterceptorMiddleware {
return &SourceInterceptorMiddleware{}
}
func (m *SourceInterceptorMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 获取请求头 X-Brand 和 X-Platform 的值
brand := r.Header.Get(BrandKey)
platform := r.Header.Get(PlatformKey)
// 将值放入新的 context 中
ctx := r.Context()
if brand != "" {
ctx = context.WithValue(ctx, "brand", brand)
}
if platform != "" {
ctx = context.WithValue(ctx, "platform", platform)
}
// 通过 r.WithContext 将更新后的 ctx 传递给后续的处理函数
r = r.WithContext(ctx)
// 传递给下一个处理器
next(w, r)
}
}

View File

@ -8,7 +8,6 @@ import (
"github.com/hibiken/asynq"
"github.com/zeromicro/go-zero/core/logx"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/api/internal/types"
"qnc-server/app/user/model"
"qnc-server/pkg/lzkit/crypto"
"qnc-server/pkg/lzkit/lzUtils"
@ -68,42 +67,11 @@ func (l *PaySuccessNotifyUserHandler) ProcessTask(ctx context.Context, t *asynq.
decryptData, aesdecryptErr := crypto.AesDecrypt(query.QueryParams, key)
if aesdecryptErr != nil {
aesdecryptErr = fmt.Errorf("密响应信息失败: %v", aesdecryptErr)
aesdecryptErr = fmt.Errorf("密响应信息失败: %v", aesdecryptErr)
return l.handleError(ctx, aesdecryptErr, order, query)
}
requests, exists := types.WestDexParams[product.ProductEn]
if !exists {
err = fmt.Errorf("未找到有效的参数配置: productEn: %s", product.ProductEn)
return l.handleError(ctx, err, order, query)
}
// 根据产品类型选择结构体类型
var requestData interface{}
switch product.ProductEn {
case "marriage":
requestData = &types.MarriageReq{}
case "homeservice":
requestData = &types.HomeServiceReq{}
case "riskassessment":
requestData = &types.RiskAssessmentReq{}
case "companyinfo":
requestData = &types.CompanyInfoReq{}
case "rentalinfo":
requestData = &types.RentalInfoReq{}
case "preloanbackgroundcheck":
requestData = &types.PreLoanBackgroundCheckReq{}
case "backgroundcheck":
requestData = &types.BackgroundCheckReq{}
default:
err = fmt.Errorf("未支持的产品类型: productEn: %s", product.ProductEn)
return l.handleError(ctx, err, order, query)
}
unmarshalErr := json.Unmarshal(decryptData, &requestData)
if unmarshalErr != nil {
unmarshalErr = fmt.Errorf("解析参数失败: %v", unmarshalErr)
return l.handleError(ctx, unmarshalErr, order, query)
}
combinedResponse, err := l.svcCtx.WestDexService.ProcessRequests(requestData, requests)
combinedResponse, err := l.svcCtx.ApiRequestService.ProcessRequests(decryptData, product.Id)
if err != nil {
return l.handleError(ctx, err, order, query)
}

View File

@ -58,6 +58,51 @@ func (a *AliPayService) CreateAlipayAppOrder(amount float64, subject string, out
return payStr, nil
}
// CreateAlipayH5Order 创建支付宝H5支付订单
func (a *AliPayService) CreateAlipayH5Order(amount float64, subject string, outTradeNo string) (string, error) {
amount = 0.01
client := a.AlipayClient
totalAmount := lzUtils.ToAlipayAmount(amount)
// 构造H5支付请求
p := alipay.TradeWapPay{
Trade: alipay.Trade{
Subject: subject,
OutTradeNo: outTradeNo,
TotalAmount: totalAmount,
ProductCode: "QUICK_WAP_WAY", // H5支付专用产品码
NotifyURL: a.config.NotifyUrl, // 异步回调通知地址
ReturnURL: "http://192.168.1.124:5173/#/pages/report",
},
}
// 获取H5支付请求字符串这里会签名
payUrl, err := client.TradeWapPay(p)
if err != nil {
return "", fmt.Errorf("创建支付宝H5订单失败: %v", err)
}
return payUrl.String(), nil
}
// CreateAlipayOrder 根据平台类型创建支付宝支付订单
func (a *AliPayService) CreateAlipayOrder(ctx context.Context, amount float64, subject string, outTradeNo string) (string, error) {
// 根据 ctx 中的 platform 判断平台
platform, platformOk := ctx.Value("platform").(string)
if !platformOk {
return "", fmt.Errorf("无的支付平台: %s", platform)
}
switch platform {
case "app":
// 调用App支付的创建方法
return a.CreateAlipayAppOrder(amount, subject, outTradeNo)
case "h5":
// 调用H5支付的创建方法并传入 returnUrl
return a.CreateAlipayH5Order(amount, subject, outTradeNo)
default:
return "", fmt.Errorf("不支持的支付平台: %s", platform)
}
}
// AliRefund 发起支付宝退款
func (a *AliPayService) AliRefund(ctx context.Context, outTradeNo string, refundAmount float64) (*alipay.TradeRefundRsp, error) {
refund := alipay.TradeRefund{

View File

@ -0,0 +1,526 @@
package service
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/Masterminds/squirrel"
"github.com/tidwall/gjson"
"github.com/zeromicro/go-zero/core/logx"
"qnc-server/app/user/cmd/api/internal/config"
"qnc-server/app/user/model"
"qnc-server/pkg/lzkit/crypto"
"sync"
"sync/atomic"
"time"
)
type ApiRequestService struct {
config config.Config
westDexService *WestDexService
featureModel model.FeatureModel
productFeatureModel model.ProductFeatureModel
}
// NewApiRequestService 是一个构造函数,用于初始化 ApiRequestService
func NewApiRequestService(c config.Config, westDexService *WestDexService, featureModel model.FeatureModel, productFeatureModel model.ProductFeatureModel) *ApiRequestService {
return &ApiRequestService{
config: c,
featureModel: featureModel,
productFeatureModel: productFeatureModel,
westDexService: westDexService,
}
}
type APIResponseData struct {
ApiID string `json:"apiID"`
Data json.RawMessage `json:"data"` // 这里用 RawMessage 来存储原始的 data
Success bool `json:"success"`
Timestamp string `json:"timestamp"`
Error string `json:"error,omitempty"`
}
// ProcessRequests 处理请求
func (a *ApiRequestService) ProcessRequests(params []byte, productID int64) ([]byte, error) {
var ctx, cancel = context.WithCancel(context.Background())
defer cancel()
build := a.productFeatureModel.SelectBuilder().Where(squirrel.Eq{
"product_id": productID,
})
productFeatureList, findProductFeatureErr := a.productFeatureModel.FindAll(ctx, build, "")
if findProductFeatureErr != nil {
return nil, findProductFeatureErr
}
var featureIDs []int64
for _, pf := range productFeatureList {
featureIDs = append(featureIDs, pf.FeatureId)
}
if len(featureIDs) == 0 {
return nil, errors.New("featureIDs 是空的")
}
builder := a.featureModel.SelectBuilder().Where(squirrel.Eq{"id": featureIDs})
featureList, findFeatureErr := a.featureModel.FindAll(ctx, builder, "")
if findFeatureErr != nil {
return nil, findFeatureErr
}
if len(featureList) == 0 {
return nil, errors.New("处理请求错误,产品无对应接口功能")
}
var (
wg sync.WaitGroup
resultsCh = make(chan APIResponseData, len(featureList))
errorsCh = make(chan error, len(featureList))
errorCount int32
errorLimit = len(featureList)
)
for i, feature := range featureList {
wg.Add(1)
go func(i int, feature *model.Feature) {
defer wg.Done()
select {
case <-ctx.Done():
return
default:
}
result := APIResponseData{
ApiID: feature.ApiId,
Success: false,
}
// 请求参数预处理
resp, preprocessErr := a.PreprocessRequestApi(params, feature.ApiId)
timestamp := time.Now().Format("2006-01-02 15:04:05")
if preprocessErr != nil {
result.Timestamp = timestamp
result.Error = preprocessErr.Error()
result.Data = resp
resultsCh <- result
errorsCh <- fmt.Errorf("请求预处理失败: %v", preprocessErr)
atomic.AddInt32(&errorCount, 1)
if atomic.LoadInt32(&errorCount) >= int32(errorLimit) {
cancel()
}
return
}
result.Data = resp
result.Success = true
result.Timestamp = timestamp
resultsCh <- result
}(i, feature)
}
go func() {
wg.Wait()
close(resultsCh)
close(errorsCh)
}()
// 收集所有结果并合并
var responseData []APIResponseData
for result := range resultsCh {
responseData = append(responseData, result)
}
if atomic.LoadInt32(&errorCount) >= int32(errorLimit) {
var allErrors []error
for err := range errorsCh {
allErrors = append(allErrors, err)
}
return nil, fmt.Errorf("请求失败次数超过 %d 次: %v", errorLimit, allErrors)
}
combinedResponse, err := json.Marshal(responseData)
if err != nil {
return nil, fmt.Errorf("响应数据转 JSON 失败: %+v", err)
}
return combinedResponse, nil
}
// ------------------------------------请求处理器--------------------------
var requestProcessors = map[string]func(*ApiRequestService, []byte) ([]byte, error){
"G09SC02": (*ApiRequestService).ProcessG09SC02Request,
"G27BJ05": (*ApiRequestService).ProcessG27BJ05Request,
"G26BJ05": (*ApiRequestService).ProcessG26BJ05Request,
"G34BJ03": (*ApiRequestService).ProcessG34BJ03Request,
"G35SC01": (*ApiRequestService).ProcessG35SC01Request,
"G28BJ05": (*ApiRequestService).ProcessG28BJ05Request,
"G05HZ01": (*ApiRequestService).ProcessG05HZ01Request,
"Q23SC01": (*ApiRequestService).ProcessQ23SC01Request,
}
// PreprocessRequestApi 调用指定的请求处理函数
func (a *ApiRequestService) PreprocessRequestApi(params []byte, apiID string) ([]byte, error) {
if processor, exists := requestProcessors[apiID]; exists {
return processor(a, params) // 调用 ApiRequestService 方法
}
return nil, errors.New("api请求, 未找到相应的处理程序")
}
func (a *ApiRequestService) ProcessG09SC02Request(params []byte) ([]byte, error) {
name := gjson.GetBytes(params, "name")
idCard := gjson.GetBytes(params, "id_card")
if !name.Exists() || !idCard.Exists() {
return nil, errors.New("api请求, G09SC02, 获取相关参数失败")
}
request := map[string]interface{}{
"data": map[string]interface{}{
"certNumMan": a.westDexService.Encrypt(idCard.String()),
"nameMan": a.westDexService.Encrypt(name.String()),
},
}
resp, callApiErr := a.westDexService.CallAPI("G09SC02", request)
if callApiErr != nil {
return nil, callApiErr
}
result := gjson.GetBytes(resp, "data.0.maritalStatus")
if result.Exists() {
responseMap := map[string]string{"status": result.String()}
jsonResponse, err := json.Marshal(responseMap)
if err != nil {
return nil, err
}
return jsonResponse, nil
} else {
return nil, errors.New("查询为空")
}
}
func (a *ApiRequestService) ProcessG27BJ05Request(params []byte) ([]byte, error) {
name := gjson.GetBytes(params, "name")
idCard := gjson.GetBytes(params, "id_card")
mobile := gjson.GetBytes(params, "mobile")
if !name.Exists() || !idCard.Exists() || !mobile.Exists() {
return nil, errors.New("api请求, G27BJ05, 获取相关参数失败")
}
request := map[string]interface{}{
"data": map[string]interface{}{
"id": a.westDexService.Encrypt(idCard.String()),
"name": a.westDexService.Encrypt(name.String()),
"cell": a.westDexService.Encrypt(mobile.String()),
},
}
resp, callApiErr := a.westDexService.CallAPI("G27BJ05", request)
if callApiErr != nil {
return nil, callApiErr
}
// 获取 code 字段
codeResult := gjson.GetBytes(resp, "code")
if !codeResult.Exists() {
return nil, fmt.Errorf("code 字段不存在")
}
if codeResult.String() != "00" {
return nil, fmt.Errorf("未匹配到相关结果")
}
// 获取 data 字段
dataResult := gjson.GetBytes(resp, "data")
if !dataResult.Exists() {
return nil, fmt.Errorf("data 字段不存在")
}
// 将 data 字段解析为 map
var dataMap map[string]interface{}
if err := json.Unmarshal([]byte(dataResult.Raw), &dataMap); err != nil {
return nil, fmt.Errorf("解析 data 字段失败: %v", err)
}
// 删除指定字段
delete(dataMap, "swift_number")
delete(dataMap, "DataStrategy")
// 重新编码为 JSON
modifiedData, err := json.Marshal(dataMap)
if err != nil {
return nil, fmt.Errorf("编码修改后的 data 失败: %v", err)
}
return modifiedData, nil
}
func (a *ApiRequestService) ProcessG26BJ05Request(params []byte) ([]byte, error) {
name := gjson.GetBytes(params, "name")
idCard := gjson.GetBytes(params, "id_card")
mobile := gjson.GetBytes(params, "mobile")
if !name.Exists() || !idCard.Exists() || !mobile.Exists() {
return nil, errors.New("api请求, G26BJ05, 获取相关参数失败")
}
request := map[string]interface{}{
"data": map[string]interface{}{
"id": a.westDexService.Encrypt(idCard.String()),
"name": a.westDexService.Encrypt(name.String()),
"cell": a.westDexService.Encrypt(mobile.String()),
"time_range": 5,
},
}
resp, callApiErr := a.westDexService.CallAPI("G26BJ05", request)
if callApiErr != nil {
return nil, callApiErr
}
codeResult := gjson.GetBytes(resp, "code")
if !codeResult.Exists() {
return nil, fmt.Errorf("code 字段不存在")
}
if codeResult.String() != "00" {
return nil, fmt.Errorf("未匹配到相关结果")
}
// 获取 data 字段
dataResult := gjson.GetBytes(resp, "data")
if !dataResult.Exists() {
return nil, fmt.Errorf("data 字段不存在")
}
// 将 data 字段解析为 map
var dataMap map[string]interface{}
if err := json.Unmarshal([]byte(dataResult.Raw), &dataMap); err != nil {
return nil, fmt.Errorf("解析 data 字段失败: %v", err)
}
// 删除指定字段
delete(dataMap, "swift_number")
delete(dataMap, "DataStrategy")
// 重新编码为 JSON
modifiedData, err := json.Marshal(dataMap)
if err != nil {
return nil, fmt.Errorf("编码修改后的 data 失败: %v", err)
}
return modifiedData, nil
}
func (a *ApiRequestService) ProcessG34BJ03Request(params []byte) ([]byte, error) {
name := gjson.GetBytes(params, "name")
idCard := gjson.GetBytes(params, "id_card")
if !name.Exists() || !idCard.Exists() {
return nil, errors.New("api请求, G34BJ03, 获取相关参数失败")
}
request := map[string]interface{}{
"data": map[string]interface{}{
"id_card": a.westDexService.Encrypt(idCard.String()),
"name": a.westDexService.Encrypt(name.String()),
},
}
resp, callApiErr := a.westDexService.CallAPI("G34BJ03", request)
if callApiErr != nil {
return nil, callApiErr
}
dataResult := gjson.GetBytes(resp, "negative_info.data.risk_level")
if dataResult.Exists() {
// 如果字段存在,构造包含 "status" 的 JSON 响应
responseMap := map[string]string{"risk_level": dataResult.String()}
jsonResponse, err := json.Marshal(responseMap)
if err != nil {
return nil, err
}
return jsonResponse, nil
} else {
return nil, errors.New("查询为空")
}
}
func (a *ApiRequestService) ProcessG35SC01Request(params []byte) ([]byte, error) {
name := gjson.GetBytes(params, "name")
idCard := gjson.GetBytes(params, "id_card")
if !name.Exists() || !idCard.Exists() {
return nil, errors.New("api请求, G35SC01, 获取相关参数失败")
}
request := map[string]interface{}{
"data": map[string]interface{}{
"idcard": a.westDexService.Encrypt(idCard.String()),
"name": a.westDexService.Encrypt(name.String()),
"inquired_auth": a.westDexService.GetDateRange(),
},
}
resp, callApiErr := a.westDexService.CallAPI("G35SC01", request)
if callApiErr != nil {
return nil, callApiErr
}
// 第一步:提取外层的 data 字段
dataResult := gjson.GetBytes(resp, "data")
if !dataResult.Exists() {
return nil, fmt.Errorf("外层 data 字段不存在")
}
// 第二步:解析外层 data 的 JSON 字符串
var outerDataMap map[string]interface{}
if err := json.Unmarshal([]byte(dataResult.String()), &outerDataMap); err != nil {
return nil, fmt.Errorf("解析外层 data 字段失败: %v", err)
}
// 第三步:提取内层的 data 字段
innerData, ok := outerDataMap["data"].(string)
if !ok {
return nil, fmt.Errorf("内层 data 字段不存在或类型错误")
}
// 第四步:解析内层 data 的 JSON 字符串
var finalDataMap map[string]interface{}
if err := json.Unmarshal([]byte(innerData), &finalDataMap); err != nil {
return nil, fmt.Errorf("解析内层 data 字段失败: %v", err)
}
// 将最终的 JSON 对象编码为字节数组返回
finalDataBytes, err := json.Marshal(finalDataMap)
if err != nil {
return nil, fmt.Errorf("编码最终的 JSON 对象失败: %v", err)
}
return finalDataBytes, nil
}
func (a *ApiRequestService) ProcessG28BJ05Request(params []byte) ([]byte, error) {
name := gjson.GetBytes(params, "name")
idCard := gjson.GetBytes(params, "id_card")
mobile := gjson.GetBytes(params, "mobile")
if !name.Exists() || !idCard.Exists() || !mobile.Exists() {
return nil, errors.New("api请求, G28BJ05, 获取相关参数失败")
}
request := map[string]interface{}{
"data": map[string]interface{}{
"id": a.westDexService.Encrypt(idCard.String()),
"name": a.westDexService.Encrypt(name.String()),
"cell": a.westDexService.Encrypt(mobile.String()),
},
}
resp, callApiErr := a.westDexService.CallAPI("G28BJ05", request)
if callApiErr != nil {
return nil, callApiErr
}
// 获取 code 字段
codeResult := gjson.GetBytes(resp, "code")
if !codeResult.Exists() {
return nil, fmt.Errorf("code 字段不存在")
}
if codeResult.String() != "00" {
return nil, fmt.Errorf("未匹配到相关结果")
}
// 获取 data 字段
dataResult := gjson.GetBytes(resp, "data")
if !dataResult.Exists() {
return nil, fmt.Errorf("data 字段不存在")
}
// 将 data 字段解析为 map
var dataMap map[string]interface{}
if err := json.Unmarshal([]byte(dataResult.Raw), &dataMap); err != nil {
return nil, fmt.Errorf("解析 data 字段失败: %v", err)
}
// 删除指定字段
delete(dataMap, "swift_number")
delete(dataMap, "DataStrategy")
// 重新编码为 JSON
modifiedData, err := json.Marshal(dataMap)
if err != nil {
return nil, fmt.Errorf("编码修改后的 data 失败: %v", err)
}
return modifiedData, nil
}
func (a *ApiRequestService) ProcessG05HZ01Request(params []byte) ([]byte, error) {
idCard := gjson.GetBytes(params, "id_card")
if !idCard.Exists() {
return nil, errors.New("api请求, G05HZ01, 获取相关参数失败")
}
request := map[string]interface{}{
"pid": crypto.Md5Encrypt(idCard.String()),
}
resp, callApiErr := a.westDexService.G05HZ01CallAPI("G05HZ01", request)
if callApiErr != nil {
return nil, callApiErr
}
// 处理股东人企关系的响应数据
code := gjson.GetBytes(resp, "code")
if !code.Exists() {
return nil, fmt.Errorf("响应中缺少 code 字段")
}
// 判断 code 是否等于 "0000"
if code.String() == "0000" {
// 获取 data 字段的值
data := gjson.GetBytes(resp, "data")
if !data.Exists() {
return nil, fmt.Errorf("响应中缺少 data 字段")
}
// 返回 data 字段的内容
return []byte(data.Raw), nil
}
// code 不等于 "0000",返回错误
return nil, fmt.Errorf("响应code错误%s", code.String())
}
func (a *ApiRequestService) ProcessQ23SC01Request(params []byte) ([]byte, error) {
entName := gjson.GetBytes(params, "ent_name")
entCode := gjson.GetBytes(params, "ent_code")
if !entName.Exists() || !entCode.Exists() {
return nil, errors.New("api请求, Q23SC01, 获取相关参数失败")
}
request := map[string]interface{}{
"data": map[string]interface{}{
"uscc": a.westDexService.Encrypt(entCode.String()),
"org_name": a.westDexService.Encrypt(entName.String()),
"inquired_auth": a.westDexService.GetDateRange(),
},
}
resp, callApiErr := a.westDexService.CallAPI("Q23SC01", request)
logx.Infof("企业涉诉返回%+v", string(resp))
if callApiErr != nil {
return nil, callApiErr
}
// 第一步:提取外层的 data 字段
dataResult := gjson.GetBytes(resp, "data")
if !dataResult.Exists() {
return nil, fmt.Errorf("外层 data 字段不存在")
}
// 第二步:解析外层 data 的 JSON 字符串
var outerDataMap map[string]interface{}
if err := json.Unmarshal([]byte(dataResult.String()), &outerDataMap); err != nil {
return nil, fmt.Errorf("解析外层 data 字段失败: %v", err)
}
// 第三步:提取内层的 data 字段
innerData, ok := outerDataMap["data"].(string)
if !ok {
return nil, fmt.Errorf("内层 data 字段不存在或类型错误")
}
// 第四步:解析内层 data 的 JSON 字符串
var finalDataMap map[string]interface{}
if err := json.Unmarshal([]byte(innerData), &finalDataMap); err != nil {
return nil, fmt.Errorf("解析内层 data 字段失败: %v", err)
}
// 将最终的 JSON 对象编码为字节数组返回
finalDataBytes, err := json.Marshal(finalDataMap)
if err != nil {
return nil, fmt.Errorf("编码最终的 JSON 对象失败: %v", err)
}
statusResult := gjson.GetBytes(finalDataBytes, "status.status")
if statusResult.Exists() || statusResult.Int() == -1 {
return nil, fmt.Errorf("企业涉诉为空: %+v", finalDataBytes)
}
return finalDataBytes, nil
}

View File

@ -103,6 +103,65 @@ func (w *WechatPayService) CreateWechatAppOrder(ctx context.Context, amount floa
return *resp.PrepayId, nil
}
// CreateWechatMiniProgramOrder 创建微信小程序支付订单
func (w *WechatPayService) CreateWechatMiniProgramOrder(ctx context.Context, amount float64, description string, outTradeNo string, openid string) (string, error) {
totalAmount := lzUtils.ToWechatAmount(amount)
// 构建支付请求参数
payRequest := jsapi.PrepayRequest{
Appid: core.String(w.config.AppID),
Mchid: core.String(w.config.MchID),
Description: core.String(description),
OutTradeNo: core.String(outTradeNo),
NotifyUrl: core.String(w.config.NotifyUrl),
Amount: &jsapi.Amount{
Total: core.Int64(totalAmount),
},
Payer: &jsapi.Payer{
Openid: core.String(openid), // 用户的 OpenID通过前端传入
}}
// 初始化 AppApiService
svc := jsapi.JsapiApiService{Client: w.wechatClient}
// 发起预支付请求
resp, result, err := svc.PrepayWithRequestPayment(ctx, payRequest)
if err != nil {
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode)
}
// 返回预支付交易会话标识
return *resp.PrepayId, nil
}
// CreateWechatOrder 创建微信支付订单(集成 APP、H5、小程序
func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64, description string, outTradeNo string) (string, error) {
// 根据 ctx 中的 platform 判断平台
platform := ctx.Value("platform").(string)
var prepayId string
var err error
switch platform {
case "mp-weixin":
// 如果是小程序平台,调用小程序支付订单创建
prepayId, err = w.CreateWechatMiniProgramOrder(ctx, amount, description, outTradeNo, "asdasd")
case "app":
// 如果是 APP 平台,调用 APP 支付订单创建
prepayId, err = w.CreateWechatAppOrder(ctx, amount, description, outTradeNo)
default:
return "", fmt.Errorf("不支持的支付平台: %s", platform)
}
// 如果创建支付订单失败,返回错误
if err != nil {
return "", fmt.Errorf("支付订单创建失败: %v", err)
}
// 返回预支付ID
return prepayId, nil
}
// HandleWechatPayNotification 处理微信支付回调
func (w *WechatPayService) HandleWechatPayNotification(ctx context.Context, req *http.Request) (*payments.Transaction, error) {
transaction := new(payments.Transaction)

View File

@ -2,21 +2,14 @@ package service
import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/tidwall/gjson"
"github.com/zeromicro/go-zero/core/logx"
"io"
"net/http"
"qnc-server/app/user/cmd/api/internal/config"
"qnc-server/app/user/cmd/api/internal/types"
"qnc-server/pkg/lzkit/crypto"
"reflect"
"strconv"
"sync"
"sync/atomic"
"time"
)
@ -39,13 +32,6 @@ type G05HZ01WestResp struct {
type WestDexService struct {
config config.WestConfig
}
type APIResponseData struct {
ApiID string `json:"apiID"`
Data json.RawMessage `json:"data"` // 这里用 RawMessage 来存储原始的 data
Success bool `json:"success"`
Timestamp string `json:"timestamp"`
Error string `json:"error,omitempty"`
}
// NewWestDexService 是一个构造函数,用于初始化 WestDexService
func NewWestDexService(c config.Config) *WestDexService {
@ -103,7 +89,6 @@ func (w *WestDexService) CallAPI(code string, reqData map[string]interface{}) (r
if UnmarshalErr != nil {
return nil, UnmarshalErr
}
logx.Infof("西部数据请求响应, code: %s, response: %v", code, westDexResp)
if westDexResp.Code != "00000" {
if westDexResp.Data == "" {
return nil, errors.New(westDexResp.Message)
@ -178,7 +163,6 @@ func (w *WestDexService) G05HZ01CallAPI(code string, reqData map[string]interfac
if UnmarshalErr != nil {
return nil, UnmarshalErr
}
logx.Infof("西部数据请求响应, code: %s, response: %v", code, westDexResp)
if westDexResp.Code != "0000" {
if westDexResp.Data == nil {
return nil, errors.New(westDexResp.Message)
@ -194,512 +178,16 @@ func (w *WestDexService) G05HZ01CallAPI(code string, reqData map[string]interfac
return nil, fmt.Errorf("西部请求失败Code: %d", httpResp.StatusCode)
}
// EncryptStructFields 加密字段的函数,处理不同类型,并跳过空值字段
func (w *WestDexService) EncryptStructFields(inputStruct interface{}) (map[string]interface{}, error) {
encryptedFields := make(map[string]interface{})
// 使用反射获取结构体的类型和值
v := reflect.ValueOf(inputStruct)
// 检查并解引用指针类型
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
return nil, errors.New("传入的interfact不是struct")
}
// 遍历结构体字段
for i := 0; i < v.NumField(); i++ {
field := v.Type().Field(i)
fieldValue := v.Field(i)
// 检查字段的 encrypt 标签是否为 "false"
encryptTag := field.Tag.Get("encrypt")
if encryptTag == "false" {
encryptedFields[field.Name] = fieldValue.Interface()
continue
}
// 如果字段为空值,跳过
if fieldValue.IsZero() {
continue
}
// 将字段的值转换为字符串进行加密
strValue := fmt.Sprintf("%v", fieldValue.Interface())
// 执行加密操作
encryptedValue, err := crypto.WestDexEncrypt(strValue, w.config.Key)
if err != nil {
return nil, err
}
// 将加密后的值存入结果映射
encryptedFields[field.Name] = encryptedValue
}
return encryptedFields, nil
}
// MapStructToAPIRequest 字段映射
func (w *WestDexService) MapStructToAPIRequest(encryptedFields map[string]interface{}, fieldMapping map[string]string, wrapField string) map[string]interface{} {
apiRequest := make(map[string]interface{})
// 遍历字段映射表
for structField, apiField := range fieldMapping {
// 如果加密后的字段存在,才添加到请求
if structField == "InquiredAuth" {
apiRequest[apiField] = GetDateRange()
} else if structField == "TimeRange" {
apiRequest[apiField] = "5"
} else if value, exists := encryptedFields[structField]; exists {
apiRequest[apiField] = value
}
}
// 如果 wrapField 不为空,将 apiRequest 包裹到该字段下
if wrapField != "" {
return map[string]interface{}{
wrapField: apiRequest,
}
}
return apiRequest
}
// ProcessRequests 批量处理
func (w *WestDexService) ProcessRequests(data interface{}, requests []types.WestDexServiceRequestParams) ([]byte, error) {
var (
wg sync.WaitGroup
resultsCh = make(chan APIResponseData, len(requests))
errorsCh = make(chan error, len(requests))
ctx, cancel = context.WithCancel(context.Background())
errorCount int32
errorLimit = 4
)
defer cancel()
for i, req := range requests {
wg.Add(1)
go func(i int, req types.WestDexServiceRequestParams) {
defer wg.Done()
select {
case <-ctx.Done():
return
default:
}
// 请求参数预处理
apiRequest, preprocessErr := w.PreprocessRequestParams(req.ApiID, data)
if preprocessErr != nil {
errorsCh <- fmt.Errorf("请求预处理失败: %v", preprocessErr)
atomic.AddInt32(&errorCount, 1)
if atomic.LoadInt32(&errorCount) >= int32(errorLimit) {
cancel()
}
return
}
var resp []byte
var callApiErr error
if req.ApiID == "G05HZ01" {
resp, callApiErr = w.G05HZ01CallAPI(req.ApiID, apiRequest)
} else {
resp, callApiErr = w.CallAPI(req.ApiID, apiRequest)
}
timestamp := time.Now().Format("2006-01-02 15:04:05")
result := APIResponseData{
ApiID: req.ApiID,
Success: false,
Timestamp: timestamp,
}
if callApiErr != nil {
errorsCh <- fmt.Errorf("西部请求, 请求失败: %+v", callApiErr)
atomic.AddInt32(&errorCount, 1)
if atomic.LoadInt32(&errorCount) >= int32(errorLimit) {
cancel()
}
result.Error = callApiErr.Error()
result.Data = resp
resultsCh <- result
return
}
processedResp, processErr := processResponse(resp, req.ApiID)
if processErr != nil {
errorsCh <- fmt.Errorf("处理响应失败: %v", processErr)
atomic.AddInt32(&errorCount, 1)
if atomic.LoadInt32(&errorCount) >= int32(errorLimit) {
cancel()
}
result.Error = processErr.Error()
} else {
result.Data = processedResp
result.Success = true
}
resultsCh <- result
}(i, req)
}
go func() {
wg.Wait()
close(resultsCh)
close(errorsCh)
}()
// 收集所有结果并合并
var responseData []APIResponseData
for result := range resultsCh {
responseData = append(responseData, result)
}
if atomic.LoadInt32(&errorCount) >= int32(errorLimit) {
var allErrors []error
for err := range errorsCh {
allErrors = append(allErrors, err)
}
return nil, fmt.Errorf("请求失败次数超过 %d 次: %v", errorLimit, allErrors)
}
combinedResponse, err := json.Marshal(responseData)
func (w *WestDexService) Encrypt(data string) string {
encryptedValue, err := crypto.WestDexEncrypt(data, w.config.Key)
if err != nil {
return nil, fmt.Errorf("响应数据转 JSON 失败: %+v", err)
panic("WestDexEncrypt error: " + err.Error())
}
return combinedResponse, nil
}
// ------------------------------------请求处理器--------------------------
var requestProcessors = map[string]func(*WestDexService, interface{}) (map[string]interface{}, error){
"G09SC02": (*WestDexService).ProcessG09SC02Request,
"G27BJ05": (*WestDexService).ProcessG27BJ05Request,
"G26BJ05": (*WestDexService).ProcessG26BJ05Request,
"G34BJ03": (*WestDexService).ProcessG34BJ03Request,
"G35SC01": (*WestDexService).ProcessG35SC01Request,
"G28BJ05": (*WestDexService).ProcessG28BJ05Request,
"G05HZ01": (*WestDexService).ProcessG05HZ01Request,
}
// PreprocessRequestParams 调用指定的请求处理函数
func (w *WestDexService) PreprocessRequestParams(apiID string, params interface{}) (map[string]interface{}, error) {
if processor, exists := requestProcessors[apiID]; exists {
return processor(w, params) // 调用 WestDexService 方法
}
var request map[string]interface{}
return request, nil
}
// / 将处理函数作为 WestDexService 的方法
func (w *WestDexService) ProcessG09SC02Request(params interface{}) (map[string]interface{}, error) {
encryptedFields, err := w.EncryptStructFields(params)
if err != nil {
return nil, fmt.Errorf("西部请求, 生成请求数据失败: %+v", err)
}
apiRequest := w.MapStructToAPIRequest(encryptedFields, types.G09SC02FieldMapping, "data")
return apiRequest, nil
}
func (w *WestDexService) ProcessG27BJ05Request(params interface{}) (map[string]interface{}, error) {
encryptedFields, err := w.EncryptStructFields(params)
if err != nil {
return nil, fmt.Errorf("西部请求, 生成请求数据失败: %+v", err)
}
apiRequest := w.MapStructToAPIRequest(encryptedFields, types.G27BJ05FieldMapping, "data")
return apiRequest, nil
}
func (w *WestDexService) ProcessG26BJ05Request(params interface{}) (map[string]interface{}, error) {
// 特殊名单 G26BJ05
encryptedFields, err := w.EncryptStructFields(params)
if err != nil {
return nil, fmt.Errorf("西部请求, 生成请求数据失败: %+v", err)
}
apiRequest := w.MapStructToAPIRequest(encryptedFields, types.G26BJ05FieldMapping, "data")
return apiRequest, nil
}
func (w *WestDexService) ProcessG34BJ03Request(params interface{}) (map[string]interface{}, error) {
// 个人不良 G34BJ03
encryptedFields, err := w.EncryptStructFields(params)
if err != nil {
return nil, fmt.Errorf("西部请求, 生成请求数据失败: %+v", err)
}
apiRequest := w.MapStructToAPIRequest(encryptedFields, types.G34BJ03FieldMapping, "data")
return apiRequest, nil
}
func (w *WestDexService) ProcessG35SC01Request(params interface{}) (map[string]interface{}, error) {
// 个人涉诉 G35SC01
encryptedFields, err := w.EncryptStructFields(params)
if err != nil {
return nil, fmt.Errorf("西部请求, 生成请求数据失败: %+v", err)
}
apiRequest := w.MapStructToAPIRequest(encryptedFields, types.G35SC01FieldMapping, "data")
return apiRequest, nil
}
func (w *WestDexService) ProcessG28BJ05Request(params interface{}) (map[string]interface{}, error) {
// 借贷行为 G28BJ05
encryptedFields, err := w.EncryptStructFields(params)
if err != nil {
return nil, fmt.Errorf("西部请求, 生成请求数据失败: %+v", err)
}
apiRequest := w.MapStructToAPIRequest(encryptedFields, types.G28BJ05FieldMapping, "data")
return apiRequest, nil
}
func (w *WestDexService) ProcessG05HZ01Request(params interface{}) (map[string]interface{}, error) {
// 使用 reflect 获取 params 的值和类型
val := reflect.ValueOf(params)
if val.Kind() == reflect.Ptr {
val = val.Elem() // 如果是指针,获取指向的实际值
}
if val.Kind() != reflect.Struct {
return nil, fmt.Errorf("请求参数必须是结构体类型")
}
// 初始化一个 map 来存储加密后的字段
encryptedFields := make(map[string]interface{})
// 遍历结构体字段,将其转换为 map[string]interface{}
valType := val.Type()
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
fieldName := valType.Field(i).Name
// 如果字段名为 "IDCard",对其值进行加密
if fieldName == "IDCard" {
if field.Kind() != reflect.String {
return nil, fmt.Errorf("IDCard 字段不是字符串类型")
}
idCard := field.String()
encryptedIDCard := crypto.Md5Encrypt(idCard)
encryptedFields[fieldName] = encryptedIDCard
} else {
// 否则直接将字段值添加到 map 中
encryptedFields[fieldName] = field.Interface()
}
}
// 使用字段映射表生成最终的 API 请求
apiRequest := w.MapStructToAPIRequest(encryptedFields, types.G05HZ01FieldMapping, "")
return apiRequest, nil
}
// -----------------------------------------------------------------------------
// 响应处理器
var responseProcessors = map[string]func([]byte) ([]byte, error){
"G09SC02": processG09SC02Response, // 单人婚姻
"G27BJ05": processG27BJ05Response, // 借贷意向
"G28BJ05": processG28BJ05Response, // 借贷行为
"G26BJ05": processG26BJ05Response, // 特殊名单
"G05HZ01": processG05HZ01Response, // 股东人企关系
"G34BJ03": processG34BJ03Response, // 个人不良
"G35SC01": processG35SC01Response, // 个人涉诉
}
// processResponse 处理响应数据
func processResponse(resp []byte, apiID string) ([]byte, error) {
if processor, exists := responseProcessors[apiID]; exists {
return processor(resp)
}
return resp, nil
}
func processG09SC02Response(resp []byte) ([]byte, error) {
result := gjson.GetBytes(resp, "data.0.maritalStatus")
if result.Exists() {
// 如果字段存在,构造包含 "status" 的 JSON 响应
responseMap := map[string]string{"status": result.String()}
jsonResponse, err := json.Marshal(responseMap)
if err != nil {
return nil, err
}
return jsonResponse, nil
} else {
return nil, errors.New("查询为空")
}
}
func processG27BJ05Response(resp []byte) ([]byte, error) {
// 获取 code 字段
codeResult := gjson.GetBytes(resp, "code")
if !codeResult.Exists() {
return nil, fmt.Errorf("code 字段不存在")
}
if codeResult.String() != "00" {
return nil, fmt.Errorf("未匹配到相关结果")
}
// 获取 data 字段
dataResult := gjson.GetBytes(resp, "data")
if !dataResult.Exists() {
return nil, fmt.Errorf("data 字段不存在")
}
// 将 data 字段解析为 map
var dataMap map[string]interface{}
if err := json.Unmarshal([]byte(dataResult.Raw), &dataMap); err != nil {
return nil, fmt.Errorf("解析 data 字段失败: %v", err)
}
// 删除指定字段
delete(dataMap, "swift_number")
delete(dataMap, "DataStrategy")
// 重新编码为 JSON
modifiedData, err := json.Marshal(dataMap)
if err != nil {
return nil, fmt.Errorf("编码修改后的 data 失败: %v", err)
}
return modifiedData, nil
}
func processG28BJ05Response(resp []byte) ([]byte, error) {
// 处理借贷行为的响应数据
// 获取 code 字段
codeResult := gjson.GetBytes(resp, "code")
if !codeResult.Exists() {
return nil, fmt.Errorf("code 字段不存在")
}
if codeResult.String() != "00" {
return nil, fmt.Errorf("未匹配到相关结果")
}
// 获取 data 字段
dataResult := gjson.GetBytes(resp, "data")
if !dataResult.Exists() {
return nil, fmt.Errorf("data 字段不存在")
}
// 将 data 字段解析为 map
var dataMap map[string]interface{}
if err := json.Unmarshal([]byte(dataResult.Raw), &dataMap); err != nil {
return nil, fmt.Errorf("解析 data 字段失败: %v", err)
}
// 删除指定字段
delete(dataMap, "swift_number")
delete(dataMap, "DataStrategy")
// 重新编码为 JSON
modifiedData, err := json.Marshal(dataMap)
if err != nil {
return nil, fmt.Errorf("编码修改后的 data 失败: %v", err)
}
return modifiedData, nil
}
func processG26BJ05Response(resp []byte) ([]byte, error) {
// 处理特殊名单的响应数据
// 获取 code 字段
codeResult := gjson.GetBytes(resp, "code")
if !codeResult.Exists() {
return nil, fmt.Errorf("code 字段不存在")
}
if codeResult.String() != "00" {
return nil, fmt.Errorf("未匹配到相关结果")
}
// 获取 data 字段
dataResult := gjson.GetBytes(resp, "data")
if !dataResult.Exists() {
return nil, fmt.Errorf("data 字段不存在")
}
// 将 data 字段解析为 map
var dataMap map[string]interface{}
if err := json.Unmarshal([]byte(dataResult.Raw), &dataMap); err != nil {
return nil, fmt.Errorf("解析 data 字段失败: %v", err)
}
// 删除指定字段
delete(dataMap, "swift_number")
delete(dataMap, "DataStrategy")
// 重新编码为 JSON
modifiedData, err := json.Marshal(dataMap)
if err != nil {
return nil, fmt.Errorf("编码修改后的 data 失败: %v", err)
}
return modifiedData, nil
}
func processG05HZ01Response(resp []byte) ([]byte, error) {
// 处理股东人企关系的响应数据
code := gjson.GetBytes(resp, "code")
if !code.Exists() {
return nil, fmt.Errorf("响应中缺少 code 字段")
}
// 判断 code 是否等于 "0000"
if code.String() == "0000" {
// 获取 data 字段的值
data := gjson.GetBytes(resp, "data")
if !data.Exists() {
return nil, fmt.Errorf("响应中缺少 data 字段")
}
// 返回 data 字段的内容
return []byte(data.Raw), nil
}
// code 不等于 "0000",返回错误
return nil, fmt.Errorf("响应code错误%s", code.String())
}
func processG34BJ03Response(resp []byte) ([]byte, error) {
// 处理个人不良的响应数据
dataResult := gjson.GetBytes(resp, "negative_info.data.risk_level")
if dataResult.Exists() {
// 如果字段存在,构造包含 "status" 的 JSON 响应
responseMap := map[string]string{"risk_level": dataResult.String()}
jsonResponse, err := json.Marshal(responseMap)
if err != nil {
return nil, err
}
return jsonResponse, nil
} else {
return nil, errors.New("查询为空")
}
}
func processG35SC01Response(resp []byte) ([]byte, error) {
// 第一步:提取外层的 data 字段
dataResult := gjson.GetBytes(resp, "data")
if !dataResult.Exists() {
return nil, fmt.Errorf("外层 data 字段不存在")
}
// 第二步:解析外层 data 的 JSON 字符串
var outerDataMap map[string]interface{}
if err := json.Unmarshal([]byte(dataResult.String()), &outerDataMap); err != nil {
return nil, fmt.Errorf("解析外层 data 字段失败: %v", err)
}
// 第三步:提取内层的 data 字段
innerData, ok := outerDataMap["data"].(string)
if !ok {
return nil, fmt.Errorf("内层 data 字段不存在或类型错误")
}
// 第四步:解析内层 data 的 JSON 字符串
var finalDataMap map[string]interface{}
if err := json.Unmarshal([]byte(innerData), &finalDataMap); err != nil {
return nil, fmt.Errorf("解析内层 data 字段失败: %v", err)
}
// 将最终的 JSON 对象编码为字节数组返回
finalDataBytes, err := json.Marshal(finalDataMap)
if err != nil {
return nil, fmt.Errorf("编码最终的 JSON 对象失败: %v", err)
}
return finalDataBytes, nil
return encryptedValue
}
// GetDateRange 返回今天到明天的日期范围,格式为 "yyyyMMdd-yyyyMMdd"
func GetDateRange() string {
func (w *WestDexService) GetDateRange() string {
today := time.Now().Format("20060102") // 获取今天的日期
tomorrow := time.Now().Add(24 * time.Hour).Format("20060102") // 获取明天的日期
return fmt.Sprintf("%s-%s", today, tomorrow) // 拼接日期范围并返回

View File

@ -5,7 +5,9 @@ import (
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/rest"
"qnc-server/app/user/cmd/api/internal/config"
"qnc-server/app/user/cmd/api/internal/middleware"
"qnc-server/app/user/cmd/api/internal/service"
"qnc-server/app/user/model"
)
@ -13,6 +15,7 @@ import (
type ServiceContext struct {
Config config.Config
Redis *redis.Redis
SourceInterceptor rest.Middleware
UserModel model.UserModel
UserAuthModel model.UserAuthModel
ProductModel model.ProductModel
@ -24,6 +27,7 @@ type ServiceContext struct {
WechatPayService *service.WechatPayService
ApplePayService *service.ApplePayService
WestDexService *service.WestDexService
ApiRequestService *service.ApiRequestService
AsynqServer *asynq.Server // 服务端
AsynqService *service.AsynqService // 客户端
VerificationService *service.VerificationService
@ -47,23 +51,27 @@ func NewServiceContext(c config.Config) *ServiceContext {
},
)
westDexService := service.NewWestDexService(c)
productFeatureModel := model.NewProductFeatureModel(db, c.CacheRedis)
featureModel := model.NewFeatureModel(db, c.CacheRedis)
return &ServiceContext{
Config: c,
Redis: redis.MustNewRedis(redisConf),
SourceInterceptor: middleware.NewSourceInterceptorMiddleware().Handle,
AlipayService: service.NewAliPayService(c),
WechatPayService: service.NewWechatPayService(c),
ApplePayService: service.NewApplePayService(c),
WestDexService: westDexService,
VerificationService: service.NewVerificationService(c, westDexService),
AsynqServer: asynqServer,
ApiRequestService: service.NewApiRequestService(c, westDexService, featureModel, productFeatureModel),
AsynqService: service.NewAsynqService(c),
UserModel: model.NewUserModel(db, c.CacheRedis),
UserAuthModel: model.NewUserAuthModel(db, c.CacheRedis),
ProductModel: model.NewProductModel(db, c.CacheRedis),
OrderModel: model.NewOrderModel(db, c.CacheRedis),
QueryModel: model.NewQueryModel(db, c.CacheRedis),
FeatureModel: model.NewFeatureModel(db, c.CacheRedis),
ProductFeatureModel: model.NewProductFeatureModel(db, c.CacheRedis),
FeatureModel: featureModel,
ProductFeatureModel: productFeatureModel,
}
}
func (s *ServiceContext) Close() {

View File

@ -6,3 +6,7 @@ type QueryCache struct {
Mobile string `json:"mobile"`
Product string `json:"product_id"`
}
type QueryCacheLoad struct {
Product string `json:"product_en"`
Params map[string]interface{} `json:"params"`
}

View File

@ -52,3 +52,9 @@ type BackgroundCheckReq struct {
Mobile string `json:"mobile" validate:"required,mobile"`
Code string `json:"code" validate:"required"`
}
type EntLawsuitReq struct {
EntName string `json:"ent_name" validate:"required,name"`
EntCode string `json:"ent_code" validate:"required,USCI"`
Mobile string `json:"mobile" validate:"required,mobile"`
Code string `json:"code" validate:"required"`
}

View File

@ -66,14 +66,14 @@ type ProductResponse struct {
}
type Query struct {
Id int64 `json:"id"` // 主键ID
OrderId int64 `json:"order_id"` // 订单ID
UserId int64 `json:"user_id"` // 用户ID
ProductId int64 `json:"product_id"` // 产品ID
QueryData []map[string]interface{} `json:"query_data"`
CreateTime string `json:"create_time"` // 创建时间
UpdateTime string `json:"update_time"` // 更新时间
QueryState string `json:"query_state"` // 查询状态
Id int64 `json:"id"` // 主键ID
OrderId int64 `json:"order_id"` // 订单ID
UserId int64 `json:"user_id"` // 用户ID
ProductName string `json:"product_name"` // 产品ID
QueryData []map[string]interface{} `json:"query_data"`
CreateTime string `json:"create_time"` // 创建时间
UpdateTime string `json:"update_time"` // 更新时间
QueryState string `json:"query_state"` // 查询状态
}
type QueryDetailByOrderIdReq struct {
@ -84,6 +84,14 @@ type QueryDetailByOrderIdResp struct {
Query
}
type QueryDetailByOrderNoReq struct {
OrderNo string `path:"order_no"`
}
type QueryDetailByOrderNoResp struct {
Query
}
type QueryDetailReq struct {
Id int64 `path:"id"`
}
@ -136,6 +144,15 @@ type QueryRetryReq struct {
type QueryRetryResp struct {
}
type QueryServiceReq struct {
Product string `path:"product"`
Data string `json:"data" validate:"required"`
}
type QueryServiceResp struct {
Id string `json:"id"`
}
type RegisterReq struct {
Mobile string `json:"mobile" validate:"required,mobile"`
Password string `json:"password" validate:"required,min=11,max=11,password"`
@ -158,6 +175,16 @@ type UserInfoResp struct {
UserInfo User `json:"userInfo"`
}
type WXH5AuthReq struct {
Code string `json:"code"`
}
type WXH5AuthResp struct {
AccessToken string `json:"accessToken"`
AccessExpire int64 `json:"accessExpire"`
RefreshAfter int64 `json:"refreshAfter"`
}
type WXMiniAuthReq struct {
Code string `json:"code"`
IV string `json:"iv"`

View File

@ -27,9 +27,8 @@ var (
productRowsExpectAutoSet = strings.Join(stringx.Remove(productFieldNames, "`id`", "`create_time`", "`update_time`"), ",")
productRowsWithPlaceHolder = strings.Join(stringx.Remove(productFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
cacheQncProductIdPrefix = "cache:qnc:product:id:"
cacheQncProductProductEnPrefix = "cache:qnc:product:productEn:"
cacheQncProductProductNamePrefix = "cache:qnc:product:productName:"
cacheQncProductIdPrefix = "cache:qnc:product:id:"
cacheQncProductProductEnPrefix = "cache:qnc:product:productEn:"
)
type (
@ -37,7 +36,6 @@ type (
Insert(ctx context.Context, session sqlx.Session, data *Product) (sql.Result, error)
FindOne(ctx context.Context, id int64) (*Product, error)
FindOneByProductEn(ctx context.Context, productEn string) (*Product, error)
FindOneByProductName(ctx context.Context, productName string) (*Product, error)
Update(ctx context.Context, session sqlx.Session, data *Product) (sql.Result, error)
UpdateWithVersion(ctx context.Context, session sqlx.Session, data *Product) error
Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error
@ -85,14 +83,13 @@ func (m *defaultProductModel) Insert(ctx context.Context, session sqlx.Session,
data.DelState = globalkey.DelStateNo
qncProductIdKey := fmt.Sprintf("%s%v", cacheQncProductIdPrefix, data.Id)
qncProductProductEnKey := fmt.Sprintf("%s%v", cacheQncProductProductEnPrefix, data.ProductEn)
qncProductProductNameKey := fmt.Sprintf("%s%v", cacheQncProductProductNamePrefix, data.ProductName)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, productRowsExpectAutoSet)
if session != nil {
return session.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.ProductName, data.ProductEn, data.Description, data.Notes, data.CostPrice, data.SellPrice)
}
return conn.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.ProductName, data.ProductEn, data.Description, data.Notes, data.CostPrice, data.SellPrice)
}, qncProductIdKey, qncProductProductEnKey, qncProductProductNameKey)
}, qncProductIdKey, qncProductProductEnKey)
}
func (m *defaultProductModel) FindOne(ctx context.Context, id int64) (*Product, error) {
@ -132,26 +129,6 @@ func (m *defaultProductModel) FindOneByProductEn(ctx context.Context, productEn
}
}
func (m *defaultProductModel) FindOneByProductName(ctx context.Context, productName string) (*Product, error) {
qncProductProductNameKey := fmt.Sprintf("%s%v", cacheQncProductProductNamePrefix, productName)
var resp Product
err := m.QueryRowIndexCtx(ctx, &resp, qncProductProductNameKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
query := fmt.Sprintf("SELECT %s FROM %s WHERE `product_name` = ? AND del_state = ? limit 1", productRows, m.table)
if err := conn.QueryRowCtx(ctx, &resp, query, productName, globalkey.DelStateNo); err != nil {
return nil, err
}
return resp.Id, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, model.ErrNotFound
default:
return nil, err
}
}
func (m *defaultProductModel) Update(ctx context.Context, session sqlx.Session, newData *Product) (sql.Result, error) {
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
@ -159,14 +136,13 @@ func (m *defaultProductModel) Update(ctx context.Context, session sqlx.Session,
}
qncProductIdKey := fmt.Sprintf("%s%v", cacheQncProductIdPrefix, data.Id)
qncProductProductEnKey := fmt.Sprintf("%s%v", cacheQncProductProductEnPrefix, data.ProductEn)
qncProductProductNameKey := fmt.Sprintf("%s%v", cacheQncProductProductNamePrefix, data.ProductName)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("UPDATE %s SET %s WHERE `id` = ?", m.table, productRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ProductName, newData.ProductEn, newData.Description, newData.Notes, newData.CostPrice, newData.SellPrice, newData.Id)
}
return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ProductName, newData.ProductEn, newData.Description, newData.Notes, newData.CostPrice, newData.SellPrice, newData.Id)
}, qncProductIdKey, qncProductProductEnKey, qncProductProductNameKey)
}, qncProductIdKey, qncProductProductEnKey)
}
func (m *defaultProductModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, newData *Product) error {
@ -183,14 +159,13 @@ func (m *defaultProductModel) UpdateWithVersion(ctx context.Context, session sql
}
qncProductIdKey := fmt.Sprintf("%s%v", cacheQncProductIdPrefix, data.Id)
qncProductProductEnKey := fmt.Sprintf("%s%v", cacheQncProductProductEnPrefix, data.ProductEn)
qncProductProductNameKey := fmt.Sprintf("%s%v", cacheQncProductProductNamePrefix, data.ProductName)
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("UPDATE %s SET %s WHERE `id` = ? AND version = ? ", m.table, productRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ProductName, newData.ProductEn, newData.Description, newData.Notes, newData.CostPrice, newData.SellPrice, newData.Id, oldVersion)
}
return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ProductName, newData.ProductEn, newData.Description, newData.Notes, newData.CostPrice, newData.SellPrice, newData.Id, oldVersion)
}, qncProductIdKey, qncProductProductEnKey, qncProductProductNameKey)
}, qncProductIdKey, qncProductProductEnKey)
if err != nil {
return err
}
@ -415,14 +390,13 @@ func (m *defaultProductModel) Delete(ctx context.Context, session sqlx.Session,
qncProductIdKey := fmt.Sprintf("%s%v", cacheQncProductIdPrefix, id)
qncProductProductEnKey := fmt.Sprintf("%s%v", cacheQncProductProductEnPrefix, data.ProductEn)
qncProductProductNameKey := fmt.Sprintf("%s%v", cacheQncProductProductNamePrefix, data.ProductName)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("DELETE FROM %s WHERE `id` = ?", m.table)
if session != nil {
return session.ExecCtx(ctx, query, id)
}
return conn.ExecCtx(ctx, query, id)
}, qncProductIdKey, qncProductProductEnKey, qncProductProductNameKey)
}, qncProductIdKey, qncProductProductEnKey)
return err
}
func (m *defaultProductModel) formatPrimary(primary interface{}) string {

View File

@ -39,7 +39,7 @@ func HttpResult(r *http.Request, w http.ResponseWriter, resp interface{}, err er
logx.WithContext(r.Context()).Errorf("【API-ERR】 : %+v ", err)
httpx.WriteJson(w, http.StatusBadRequest, Error(errcode, errmsg))
httpx.WriteJson(w, http.StatusOK, Error(errcode, errmsg))
}
}
@ -79,7 +79,7 @@ func AuthHttpResult(r *http.Request, w http.ResponseWriter, resp interface{}, er
// http 参数错误返回
func ParamErrorResult(r *http.Request, w http.ResponseWriter, err error) {
errMsg := fmt.Sprintf("%s,%s", xerr.MapErrMsg(xerr.REUQEST_PARAM_ERROR), err.Error())
httpx.WriteJson(w, http.StatusBadRequest, Error(xerr.REUQEST_PARAM_ERROR, errMsg))
httpx.WriteJson(w, http.StatusOK, Error(xerr.REUQEST_PARAM_ERROR, errMsg))
}
// http 参数校验失败返回

View File

@ -19,7 +19,6 @@ CREATE TABLE `product` (
`cost_price` DECIMAL(10, 2) NOT NULL DEFAULT '1.00' COMMENT '成本',
`sell_price` DECIMAL(10, 2) NOT NULL DEFAULT '1.00' COMMENT '售价',
PRIMARY KEY (`id`),
UNIQUE KEY `unique_product_name` (`product_name`),
UNIQUE KEY `unique_product_en` (`product_en`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='产品表';
@ -33,8 +32,26 @@ INSERT INTO `product` (`product_name`, `product_en`, `description`, `notes`, `co
('婚姻状态', 'marriagelogic', '', '', 1, 1),
('贷前背调', 'preloanbackgroundchecklogic', '', '', 1, 1),
('租赁服务', 'rentalinfologic', '', '', 1, 1),
('个人风险评估', 'riskassessmentlogic', '', '', 1, 1);
('个人风险评估', 'riskassessmentlogic', '', '', 1, 1),
('手机三要素', 'toc_PhoneThreeElements', '', '', 1, 1),
('银行卡黑名单', 'toc_BankCardBlacklist', '', '', 1, 1),
('身份证二要素', 'toc_IDCardTwoElements', '', '', 1, 1),
('手机二要素', 'toc_PhoneTwoElements', '', '', 1, 1),
('在网时长', 'toc_NetworkDuration', '', '', 1, 1),
('手机二次卡', 'toc_PhoneSecondaryCard', '', '', 1, 1),
('手机号码风险', 'toc_PhoneNumberRisk', '', '', 1, 1),
('银行卡四要素', 'toc_BankCardFourElements', '', '', 1, 1),
('银行卡三要素', 'toc_BankCardThreeElements', '', '', 1, 1),
('自然人生存状态', 'toc_NaturalLifeStatus', '', '', 1, 1),
('学历核验', 'toc_EducationVerification', '', '', 1, 1),
('人车核验', 'toc_PersonVehicleVerification', '', '', 1, 1),
('名下车辆', 'toc_VehiclesUnderName', '', '', 1, 1),
('双人婚姻', 'toc_DualMarriage', '', '', 1, 1),
('个人不良', 'toc_PersonalBadRecord', '', '', 1, 1),
('股东人企关系', 'toc_ShareholderBusinessRelation', '', '', 1, 1),
('个人涉诉', 'toc_PersonalLawsuit', '', '', 1, 1),
('企业涉诉', 'toc_EnterpriseLawsuit', '', '', 1, 1),
('婚姻评估', 'toc_MarriageAssessment', '', '', 1, 1);
SET FOREIGN_KEY_CHECKS = 1;
@ -50,7 +67,7 @@ CREATE TABLE `feature` (
`delete_time` datetime DEFAULT NULL COMMENT '删除时间',
`del_state` tinyint NOT NULL DEFAULT '0' COMMENT '删除状态',
`version` bigint NOT NULL DEFAULT '0' COMMENT '版本号',
`api_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'API标识',
`api_id` varchar kujmio,5(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'API标识',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '描述',
PRIMARY KEY (`id`),
UNIQUE KEY `unique_api_id` (`api_id`)

View File

@ -13,7 +13,9 @@ var customMessages = map[string]string{
"IDCard.idCard": "无效的身份证号码",
"Password.min": "密码不能少于8位数",
"Password.max": "密码不能超过32位数",
"password.password": "密码强度太弱",
"Password.password": "密码强度太弱",
//"EntCode.required":"请输入统一社会信用代码",
//"EntCode.USCI": "请输入正确的统一社会信用代码",
}
// 获取自定义错误消息

View File

@ -1 +0,0 @@
exit status 1