From 97e14bbe374fe9d14643ee920cc263b072321ae4 Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Tue, 24 Dec 2024 11:37:25 +0800 Subject: [PATCH] feat(user): temp --- app/user/cmd/api/desc/pay.api | 1 + app/user/cmd/api/desc/query.api | 8 + app/user/cmd/api/desc/query/query.api | 35 +- app/user/cmd/api/desc/user.api | 13 +- app/user/cmd/api/desc/user/user.api | 11 +- app/user/cmd/api/etc/user.dev.yaml | 8 +- app/user/cmd/api/etc/user.yaml | 6 +- app/user/cmd/api/internal/config/config.go | 25 +- .../query/querydetailbyordernohandler.go | 29 + .../handler/query/queryservicehandler.go | 24 + app/user/cmd/api/internal/handler/routes.go | 57 +- .../internal/handler/user/wxh5authhandler.go | 29 + .../api/internal/logic/pay/paymentlogic.go | 12 +- .../api/internal/logic/query/marriagelogic.go | 4 +- .../logic/query/querydetailbyorderidlogic.go | 10 +- .../logic/query/querydetailbyordernologic.go | 132 ++++ .../internal/logic/query/querydetaillogic.go | 5 + .../internal/logic/query/queryexamplelogic.go | 5 + .../internal/logic/query/querylistlogic.go | 5 + .../internal/logic/query/queryservicelogic.go | 717 ++++++++++++++++++ .../api/internal/logic/user/wxh5authlogic.go | 134 ++++ .../middleware/sourceinterceptormiddleware.go | 41 + .../api/internal/queue/paySuccessNotify.go | 36 +- .../cmd/api/internal/service/alipayService.go | 45 ++ .../api/internal/service/apirequestService.go | 526 +++++++++++++ .../api/internal/service/wechatpayService.go | 59 ++ .../api/internal/service/westdexService.go | 522 +------------ .../cmd/api/internal/svc/servicecontext.go | 12 +- app/user/cmd/api/internal/types/cache.go | 4 + app/user/cmd/api/internal/types/query.go | 6 + app/user/cmd/api/internal/types/types.go | 43 +- app/user/model/productModel_gen.go | 38 +- common/result/httpResult.go | 4 +- deploy/sql/product.sql | 25 +- pkg/lzkit/validator/error_messages.go | 4 +- user/cmd/api/tmp/build-errors.log | 1 - 36 files changed, 1980 insertions(+), 656 deletions(-) create mode 100644 app/user/cmd/api/internal/handler/query/querydetailbyordernohandler.go create mode 100644 app/user/cmd/api/internal/handler/query/queryservicehandler.go create mode 100644 app/user/cmd/api/internal/handler/user/wxh5authhandler.go create mode 100644 app/user/cmd/api/internal/logic/query/querydetailbyordernologic.go create mode 100644 app/user/cmd/api/internal/logic/query/queryservicelogic.go create mode 100644 app/user/cmd/api/internal/logic/user/wxh5authlogic.go create mode 100644 app/user/cmd/api/internal/middleware/sourceinterceptormiddleware.go create mode 100644 app/user/cmd/api/internal/service/apirequestService.go delete mode 100644 user/cmd/api/tmp/build-errors.log diff --git a/app/user/cmd/api/desc/pay.api b/app/user/cmd/api/desc/pay.api index 854c254..018f9a0 100644 --- a/app/user/cmd/api/desc/pay.api +++ b/app/user/cmd/api/desc/pay.api @@ -33,6 +33,7 @@ service main { prefix: api/v1 group: pay jwt: JwtAuth + middleware: SourceInterceptor ) service main { // 支付 diff --git a/app/user/cmd/api/desc/query.api b/app/user/cmd/api/desc/query.api index 42a4080..f61d12f 100644 --- a/app/user/cmd/api/desc/query.api +++ b/app/user/cmd/api/desc/query.api @@ -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) diff --git a/app/user/cmd/api/desc/query/query.api b/app/user/cmd/api/desc/query/query.api index b0e3eb6..552e5a7 100644 --- a/app/user/cmd/api/desc/query/query.api +++ b/app/user/cmd/api/desc/query/query.api @@ -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"` diff --git a/app/user/cmd/api/desc/user.api b/app/user/cmd/api/desc/user.api index e5a65fe..07442dc 100644 --- a/app/user/cmd/api/desc/user.api +++ b/app/user/cmd/api/desc/user.api @@ -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 <============================ diff --git a/app/user/cmd/api/desc/user/user.api b/app/user/cmd/api/desc/user/user.api index 60bab5c..4976297 100644 --- a/app/user/cmd/api/desc/user/user.api +++ b/app/user/cmd/api/desc/user/user.api @@ -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"` diff --git a/app/user/cmd/api/etc/user.dev.yaml b/app/user/cmd/api/etc/user.dev.yaml index b7c0336..69fee7f 100644 --- a/app/user/cmd/api/etc/user.dev.yaml +++ b/app/user/cmd/api/etc/user.dev.yaml @@ -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" \ No newline at end of file + Code: "d55b58829efb41c8aa8e86769cba4844" +SystemConfig: + ThreeVerify: false \ No newline at end of file diff --git a/app/user/cmd/api/etc/user.yaml b/app/user/cmd/api/etc/user.yaml index 7ea2aff..d625dfe 100644 --- a/app/user/cmd/api/etc/user.yaml +++ b/app/user/cmd/api/etc/user.yaml @@ -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" \ No newline at end of file + Code: "d55b58829efb41c8aa8e86769cba4844" +SystemConfig: + ThreeVerify: false \ No newline at end of file diff --git a/app/user/cmd/api/internal/config/config.go b/app/user/cmd/api/internal/config/config.go index 620ee7d..741c53a 100644 --- a/app/user/cmd/api/internal/config/config.go +++ b/app/user/cmd/api/internal/config/config.go @@ -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 +} diff --git a/app/user/cmd/api/internal/handler/query/querydetailbyordernohandler.go b/app/user/cmd/api/internal/handler/query/querydetailbyordernohandler.go new file mode 100644 index 0000000..ee15def --- /dev/null +++ b/app/user/cmd/api/internal/handler/query/querydetailbyordernohandler.go @@ -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) + } +} diff --git a/app/user/cmd/api/internal/handler/query/queryservicehandler.go b/app/user/cmd/api/internal/handler/query/queryservicehandler.go new file mode 100644 index 0000000..0fd3e01 --- /dev/null +++ b/app/user/cmd/api/internal/handler/query/queryservicehandler.go @@ -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) + } +} diff --git a/app/user/cmd/api/internal/handler/routes.go b/app/user/cmd/api/internal/handler/routes.go index cb37eaf..c74110b 100644 --- a/app/user/cmd/api/internal/handler/routes.go +++ b/app/user/cmd/api/internal/handler/routes.go @@ -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"), diff --git a/app/user/cmd/api/internal/handler/user/wxh5authhandler.go b/app/user/cmd/api/internal/handler/user/wxh5authhandler.go new file mode 100644 index 0000000..54ed1e7 --- /dev/null +++ b/app/user/cmd/api/internal/handler/user/wxh5authhandler.go @@ -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) + } +} diff --git a/app/user/cmd/api/internal/logic/pay/paymentlogic.go b/app/user/cmd/api/internal/logic/pay/paymentlogic.go index f74c43a..9706d7f 100644 --- a/app/user/cmd/api/internal/logic/pay/paymentlogic.go +++ b/app/user/cmd/api/internal/logic/pay/paymentlogic.go @@ -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) diff --git a/app/user/cmd/api/internal/logic/query/marriagelogic.go b/app/user/cmd/api/internal/logic/query/marriagelogic.go index 26bffa5..0e16231 100644 --- a/app/user/cmd/api/internal/logic/query/marriagelogic.go +++ b/app/user/cmd/api/internal/logic/query/marriagelogic.go @@ -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, diff --git a/app/user/cmd/api/internal/logic/query/querydetailbyorderidlogic.go b/app/user/cmd/api/internal/logic/query/querydetailbyorderidlogic.go index 4ca1018..a310b62 100644 --- a/app/user/cmd/api/internal/logic/query/querydetailbyorderidlogic.go +++ b/app/user/cmd/api/internal/logic/query/querydetailbyorderidlogic.go @@ -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 diff --git a/app/user/cmd/api/internal/logic/query/querydetailbyordernologic.go b/app/user/cmd/api/internal/logic/query/querydetailbyordernologic.go new file mode 100644 index 0000000..20c78e0 --- /dev/null +++ b/app/user/cmd/api/internal/logic/query/querydetailbyordernologic.go @@ -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 +} diff --git a/app/user/cmd/api/internal/logic/query/querydetaillogic.go b/app/user/cmd/api/internal/logic/query/querydetaillogic.go index a82166d..c557611 100644 --- a/app/user/cmd/api/internal/logic/query/querydetaillogic.go +++ b/app/user/cmd/api/internal/logic/query/querydetaillogic.go @@ -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 diff --git a/app/user/cmd/api/internal/logic/query/queryexamplelogic.go b/app/user/cmd/api/internal/logic/query/queryexamplelogic.go index 83fd624..1a304f0 100644 --- a/app/user/cmd/api/internal/logic/query/queryexamplelogic.go +++ b/app/user/cmd/api/internal/logic/query/queryexamplelogic.go @@ -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 diff --git a/app/user/cmd/api/internal/logic/query/querylistlogic.go b/app/user/cmd/api/internal/logic/query/querylistlogic.go index 1588a0a..9cf5531 100644 --- a/app/user/cmd/api/internal/logic/query/querylistlogic.go +++ b/app/user/cmd/api/internal/logic/query/querylistlogic.go @@ -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) } } diff --git a/app/user/cmd/api/internal/logic/query/queryservicelogic.go b/app/user/cmd/api/internal/logic/query/queryservicelogic.go new file mode 100644 index 0000000..405fc7a --- /dev/null +++ b/app/user/cmd/api/internal/logic/query/queryservicelogic.go @@ -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 +} diff --git a/app/user/cmd/api/internal/logic/user/wxh5authlogic.go b/app/user/cmd/api/internal/logic/user/wxh5authlogic.go new file mode 100644 index 0000000..baa9a49 --- /dev/null +++ b/app/user/cmd/api/internal/logic/user/wxh5authlogic.go @@ -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 +} diff --git a/app/user/cmd/api/internal/middleware/sourceinterceptormiddleware.go b/app/user/cmd/api/internal/middleware/sourceinterceptormiddleware.go new file mode 100644 index 0000000..747f848 --- /dev/null +++ b/app/user/cmd/api/internal/middleware/sourceinterceptormiddleware.go @@ -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) + } +} diff --git a/app/user/cmd/api/internal/queue/paySuccessNotify.go b/app/user/cmd/api/internal/queue/paySuccessNotify.go index 55aebe7..4995d79 100644 --- a/app/user/cmd/api/internal/queue/paySuccessNotify.go +++ b/app/user/cmd/api/internal/queue/paySuccessNotify.go @@ -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) } diff --git a/app/user/cmd/api/internal/service/alipayService.go b/app/user/cmd/api/internal/service/alipayService.go index 3b6d654..811e2f1 100644 --- a/app/user/cmd/api/internal/service/alipayService.go +++ b/app/user/cmd/api/internal/service/alipayService.go @@ -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{ diff --git a/app/user/cmd/api/internal/service/apirequestService.go b/app/user/cmd/api/internal/service/apirequestService.go new file mode 100644 index 0000000..412a9be --- /dev/null +++ b/app/user/cmd/api/internal/service/apirequestService.go @@ -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 +} diff --git a/app/user/cmd/api/internal/service/wechatpayService.go b/app/user/cmd/api/internal/service/wechatpayService.go index e256085..4b537f5 100644 --- a/app/user/cmd/api/internal/service/wechatpayService.go +++ b/app/user/cmd/api/internal/service/wechatpayService.go @@ -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) diff --git a/app/user/cmd/api/internal/service/westdexService.go b/app/user/cmd/api/internal/service/westdexService.go index c022192..c71aa2c 100644 --- a/app/user/cmd/api/internal/service/westdexService.go +++ b/app/user/cmd/api/internal/service/westdexService.go @@ -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) // 拼接日期范围并返回 diff --git a/app/user/cmd/api/internal/svc/servicecontext.go b/app/user/cmd/api/internal/svc/servicecontext.go index d8e61c7..200c04e 100644 --- a/app/user/cmd/api/internal/svc/servicecontext.go +++ b/app/user/cmd/api/internal/svc/servicecontext.go @@ -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() { diff --git a/app/user/cmd/api/internal/types/cache.go b/app/user/cmd/api/internal/types/cache.go index 12cb65d..84ba143 100644 --- a/app/user/cmd/api/internal/types/cache.go +++ b/app/user/cmd/api/internal/types/cache.go @@ -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"` +} diff --git a/app/user/cmd/api/internal/types/query.go b/app/user/cmd/api/internal/types/query.go index 017bf01..e0f80a0 100644 --- a/app/user/cmd/api/internal/types/query.go +++ b/app/user/cmd/api/internal/types/query.go @@ -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"` +} diff --git a/app/user/cmd/api/internal/types/types.go b/app/user/cmd/api/internal/types/types.go index 43fc4fb..9b6a375 100644 --- a/app/user/cmd/api/internal/types/types.go +++ b/app/user/cmd/api/internal/types/types.go @@ -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"` diff --git a/app/user/model/productModel_gen.go b/app/user/model/productModel_gen.go index 45b41e0..b99af94 100644 --- a/app/user/model/productModel_gen.go +++ b/app/user/model/productModel_gen.go @@ -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 { diff --git a/common/result/httpResult.go b/common/result/httpResult.go index 478e60d..1b0609a 100644 --- a/common/result/httpResult.go +++ b/common/result/httpResult.go @@ -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 参数校验失败返回 diff --git a/deploy/sql/product.sql b/deploy/sql/product.sql index 1e8cdcf..be588c1 100644 --- a/deploy/sql/product.sql +++ b/deploy/sql/product.sql @@ -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`) diff --git a/pkg/lzkit/validator/error_messages.go b/pkg/lzkit/validator/error_messages.go index 5ae3233..4593f53 100644 --- a/pkg/lzkit/validator/error_messages.go +++ b/pkg/lzkit/validator/error_messages.go @@ -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": "请输入正确的统一社会信用代码", } // 获取自定义错误消息 diff --git a/user/cmd/api/tmp/build-errors.log b/user/cmd/api/tmp/build-errors.log deleted file mode 100644 index 05e5985..0000000 --- a/user/cmd/api/tmp/build-errors.log +++ /dev/null @@ -1 +0,0 @@ -exit status 1 \ No newline at end of file