feat(all): v1.0
This commit is contained in:
137
app/user/cmd/api/internal/service/alipayService.go
Normal file
137
app/user/cmd/api/internal/service/alipayService.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/smartwalle/alipay/v3"
|
||||
mathrand "math/rand"
|
||||
"net/http"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/pkg/lzkit/lzUtils"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AliPayService struct {
|
||||
config config.AlipayConfig
|
||||
AlipayClient *alipay.Client
|
||||
}
|
||||
|
||||
// NewAliPayService 是一个构造函数,用于初始化 AliPayService
|
||||
func NewAliPayService(c config.Config) *AliPayService {
|
||||
client, err := alipay.New(c.Alipay.AppID, c.Alipay.PrivateKey, c.Alipay.IsProduction)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("创建支付宝客户端失败: %v", err))
|
||||
}
|
||||
|
||||
// 加载支付宝公钥
|
||||
err = client.LoadAliPayPublicKey(c.Alipay.AlipayPublicKey)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("加载支付宝公钥失败: %v", err))
|
||||
}
|
||||
return &AliPayService{
|
||||
config: c.Alipay,
|
||||
AlipayClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AliPayService) CreateAlipayAppOrder(amount float64, subject string, outTradeNo string) (string, error) {
|
||||
client := a.AlipayClient
|
||||
totalAmount := lzUtils.ToAlipayAmount(amount)
|
||||
// 构造移动支付请求
|
||||
p := alipay.TradeAppPay{
|
||||
Trade: alipay.Trade{
|
||||
Subject: subject,
|
||||
OutTradeNo: outTradeNo,
|
||||
TotalAmount: totalAmount,
|
||||
ProductCode: "QUICK_MSECURITY_PAY", // 移动端支付专用代码
|
||||
NotifyURL: a.config.NotifyUrl, // 异步回调通知地址
|
||||
},
|
||||
}
|
||||
|
||||
// 获取APP支付字符串,这里会签名
|
||||
payStr, err := client.TradeAppPay(p)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("创建支付宝订单失败: %v", err)
|
||||
}
|
||||
|
||||
return payStr, nil
|
||||
}
|
||||
|
||||
// AliRefund 发起支付宝退款
|
||||
func (a *AliPayService) AliRefund(ctx context.Context, outTradeNo string, refundAmount float64) (*alipay.TradeRefundRsp, error) {
|
||||
refund := alipay.TradeRefund{
|
||||
OutTradeNo: outTradeNo,
|
||||
RefundAmount: lzUtils.ToAlipayAmount(refundAmount),
|
||||
OutRequestNo: fmt.Sprintf("%s-refund", outTradeNo),
|
||||
}
|
||||
|
||||
// 发起退款请求
|
||||
refundResp, err := a.AlipayClient.TradeRefund(ctx, refund)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("支付宝退款请求错误:%v", err)
|
||||
}
|
||||
return refundResp, nil
|
||||
}
|
||||
|
||||
// HandleAliPaymentNotification 支付宝支付回调
|
||||
func (a *AliPayService) HandleAliPaymentNotification(r *http.Request) (*alipay.Notification, error) {
|
||||
// 解析表单
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解析请求表单失败:%v", err)
|
||||
}
|
||||
// 解析并验证通知,DecodeNotification 会自动验证签名
|
||||
notification, err := a.AlipayClient.DecodeNotification(r.Form)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("验证签名失败: %v", err)
|
||||
}
|
||||
return notification, nil
|
||||
}
|
||||
func (a *AliPayService) QueryOrderStatus(ctx context.Context, outTradeNo string) (*alipay.TradeQueryRsp, error) {
|
||||
queryRequest := alipay.TradeQuery{
|
||||
OutTradeNo: outTradeNo,
|
||||
}
|
||||
|
||||
// 发起查询请求
|
||||
resp, err := a.AlipayClient.TradeQuery(ctx, queryRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询支付宝订单失败: %v", err)
|
||||
}
|
||||
|
||||
// 返回交易状态
|
||||
if resp.IsSuccess() {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("查询支付宝订单失败: %v", resp.SubMsg)
|
||||
}
|
||||
|
||||
// GenerateOutTradeNo 生成唯一订单号的函数
|
||||
func (a *AliPayService) GenerateOutTradeNo() string {
|
||||
length := 16
|
||||
// 获取当前时间戳
|
||||
timestamp := time.Now().UnixNano()
|
||||
|
||||
// 转换为字符串
|
||||
timeStr := strconv.FormatInt(timestamp, 10)
|
||||
|
||||
// 生成随机数
|
||||
mathrand.Seed(time.Now().UnixNano())
|
||||
randomPart := strconv.Itoa(mathrand.Intn(1000000))
|
||||
|
||||
// 组合时间戳和随机数
|
||||
combined := timeStr + randomPart
|
||||
|
||||
// 如果长度超出指定值,则截断;如果不够,则填充随机字符
|
||||
if len(combined) >= length {
|
||||
return combined[:length]
|
||||
}
|
||||
|
||||
// 如果长度不够,填充0
|
||||
for len(combined) < length {
|
||||
combined += strconv.Itoa(mathrand.Intn(10)) // 填充随机数
|
||||
}
|
||||
|
||||
return combined
|
||||
}
|
||||
59
app/user/cmd/api/internal/service/asynqService.go
Normal file
59
app/user/cmd/api/internal/service/asynqService.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// asynq_service.go
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/app/user/cmd/api/internal/types"
|
||||
)
|
||||
|
||||
type AsynqService struct {
|
||||
client *asynq.Client
|
||||
config config.Config
|
||||
}
|
||||
|
||||
// NewAsynqService 创建并初始化 Asynq 客户端
|
||||
func NewAsynqService(c config.Config) *AsynqService {
|
||||
client := asynq.NewClient(asynq.RedisClientOpt{
|
||||
Addr: c.CacheRedis[0].Host,
|
||||
Password: c.CacheRedis[0].Pass,
|
||||
})
|
||||
|
||||
return &AsynqService{client: client, config: c}
|
||||
}
|
||||
|
||||
// Close 关闭 Asynq 客户端
|
||||
func (s *AsynqService) Close() error {
|
||||
return s.client.Close()
|
||||
}
|
||||
func (s *AsynqService) SendQueryTask(orderID int64) error {
|
||||
// 准备任务的 payload
|
||||
payload := types.MsgPaySuccessQueryPayload{
|
||||
OrderID: orderID,
|
||||
}
|
||||
payloadBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
logx.Errorf("发送异步任务失败 (无法编码 payload): %v, 订单号: %d", err, orderID)
|
||||
return err // 直接返回错误,避免继续执行
|
||||
}
|
||||
|
||||
options := []asynq.Option{
|
||||
asynq.MaxRetry(5), // 设置最大重试次数
|
||||
}
|
||||
// 创建任务
|
||||
task := asynq.NewTask(types.MsgPaySuccessQuery, payloadBytes, options...)
|
||||
|
||||
// 将任务加入队列并获取任务信息
|
||||
info, err := s.client.Enqueue(task)
|
||||
if err != nil {
|
||||
logx.Errorf("发送异步任务失败 (加入队列失败): %+v, 订单号: %d", err, orderID)
|
||||
return err
|
||||
}
|
||||
|
||||
// 记录成功日志,带上任务 ID 和队列信息
|
||||
logx.Infof("发送异步任务成功,任务ID: %s, 队列: %s, 订单号: %d", info.ID, info.Queue, orderID)
|
||||
return nil
|
||||
}
|
||||
116
app/user/cmd/api/internal/service/verificationService.go
Normal file
116
app/user/cmd/api/internal/service/verificationService.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type VerificationService struct {
|
||||
c config.Config
|
||||
}
|
||||
|
||||
func NewVerificationService(c config.Config) *VerificationService {
|
||||
return &VerificationService{
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
type TwoFactorVerificationRequest struct {
|
||||
Name string
|
||||
IDCard string
|
||||
}
|
||||
type TwoFactorVerificationResp struct {
|
||||
Msg string `json:"msg"`
|
||||
Success bool `json:"success"`
|
||||
Code int `json:"code"`
|
||||
Data *TwoFactorVerificationData `json:"data"` //
|
||||
}
|
||||
type TwoFactorVerificationData struct {
|
||||
Birthday string `json:"birthday"`
|
||||
Result int `json:"result"`
|
||||
Address string `json:"address"`
|
||||
OrderNo string `json:"orderNo"`
|
||||
Sex string `json:"sex"`
|
||||
Desc string `json:"desc"`
|
||||
}
|
||||
|
||||
// VerificationResult 定义校验结果结构体
|
||||
type VerificationResult struct {
|
||||
Passed bool
|
||||
Err error
|
||||
}
|
||||
|
||||
// ValidationError 定义校验错误类型
|
||||
type ValidationError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *ValidationError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func (r *VerificationService) TwoFactorVerification(request TwoFactorVerificationRequest) (*VerificationResult, error) {
|
||||
appCode := r.c.Ali.Code
|
||||
requestUrl := "https://kzidcardv1.market.alicloudapi.com/api-mall/api/id_card/check"
|
||||
|
||||
// 构造查询参数
|
||||
data := url.Values{}
|
||||
data.Add("name", request.Name)
|
||||
data.Add("idcard", request.IDCard)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, requestUrl, strings.NewReader(data.Encode()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建请求失败: %+v", err)
|
||||
}
|
||||
req.Header.Set("Authorization", "APPCODE "+appCode)
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("请求失败: %+v", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("请求失败, 状态码: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("响应体读取失败:%v", err)
|
||||
}
|
||||
var twoFactorVerificationResp TwoFactorVerificationResp
|
||||
err = json.Unmarshal(respBody, &twoFactorVerificationResp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("二要素解析错误: %v", err)
|
||||
}
|
||||
|
||||
if !twoFactorVerificationResp.Success {
|
||||
return &VerificationResult{
|
||||
Passed: false,
|
||||
Err: &ValidationError{Message: "请输入有效的身份证号码"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
if twoFactorVerificationResp.Code != 200 {
|
||||
return &VerificationResult{
|
||||
Passed: false,
|
||||
Err: &ValidationError{Message: twoFactorVerificationResp.Msg},
|
||||
}, nil
|
||||
}
|
||||
|
||||
if twoFactorVerificationResp.Data.Result == 1 {
|
||||
return &VerificationResult{
|
||||
Passed: false,
|
||||
Err: &ValidationError{Message: "姓名与身份证不一致"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &VerificationResult{Passed: true, Err: nil}, nil
|
||||
}
|
||||
188
app/user/cmd/api/internal/service/wechatpayService.go
Normal file
188
app/user/cmd/api/internal/service/wechatpayService.go
Normal file
@@ -0,0 +1,188 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core/downloader"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/app"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/utils"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"net/http"
|
||||
"qnc-server/app/user/cmd/api/internal/config"
|
||||
"qnc-server/pkg/lzkit/lzUtils"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
TradeStateSuccess = "SUCCESS" // 支付成功
|
||||
TradeStateRefund = "REFUND" // 转入退款
|
||||
TradeStateNotPay = "NOTPAY" // 未支付
|
||||
TradeStateClosed = "CLOSED" // 已关闭
|
||||
TradeStateRevoked = "REVOKED" // 已撤销(付款码支付)
|
||||
TradeStateUserPaying = "USERPAYING" // 用户支付中(付款码支付)
|
||||
TradeStatePayError = "PAYERROR" // 支付失败(其他原因,如银行返回失败)
|
||||
)
|
||||
|
||||
type WechatPayService struct {
|
||||
config config.WxpayConfig
|
||||
wechatClient *core.Client
|
||||
notifyHandler *notify.Handler
|
||||
}
|
||||
|
||||
// NewWechatPayService 初始化微信支付服务
|
||||
func NewWechatPayService(c config.Config) *WechatPayService {
|
||||
// 从配置中加载商户信息
|
||||
mchID := c.Wxpay.MchID
|
||||
mchCertificateSerialNumber := c.Wxpay.MchCertificateSerialNumber
|
||||
mchAPIv3Key := c.Wxpay.MchApiv3Key
|
||||
|
||||
// 从文件中加载商户私钥
|
||||
mchPrivateKey, err := utils.LoadPrivateKeyWithPath(c.Wxpay.MchPrivateKeyPath)
|
||||
if err != nil {
|
||||
logx.Errorf("加载商户私钥失败: %v", err)
|
||||
panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) // 记录错误并停止程序
|
||||
}
|
||||
|
||||
// 使用商户私钥和其他参数初始化微信支付客户端
|
||||
opts := []core.ClientOption{
|
||||
option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
|
||||
}
|
||||
client, err := core.NewClient(context.Background(), opts...)
|
||||
if err != nil {
|
||||
logx.Errorf("创建微信支付客户端失败: %v", err)
|
||||
panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) // 记录错误并停止程序
|
||||
}
|
||||
// 在初始化时获取证书访问器并创建 notifyHandler
|
||||
certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(mchID)
|
||||
notifyHandler, err := notify.NewRSANotifyHandler(mchAPIv3Key, verifiers.NewSHA256WithRSAVerifier(certificateVisitor))
|
||||
if err != nil {
|
||||
logx.Errorf("获取证书访问器失败: %v", err)
|
||||
panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) // 记录错误并停止程序
|
||||
}
|
||||
return &WechatPayService{
|
||||
config: c.Wxpay,
|
||||
wechatClient: client,
|
||||
notifyHandler: notifyHandler,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateWechatAppOrder 创建微信APP支付订单
|
||||
func (w *WechatPayService) CreateWechatAppOrder(ctx context.Context, amount float64, description string, outTradeNo string) (string, error) {
|
||||
totalAmount := lzUtils.ToWechatAmount(amount)
|
||||
|
||||
// 构建支付请求参数
|
||||
payRequest := app.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: &app.Amount{
|
||||
Total: core.Int64(totalAmount),
|
||||
},
|
||||
}
|
||||
|
||||
// 初始化 AppApiService
|
||||
svc := app.AppApiService{Client: w.wechatClient}
|
||||
|
||||
// 发起预支付请求
|
||||
resp, result, err := svc.Prepay(ctx, payRequest)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode)
|
||||
}
|
||||
|
||||
// 返回预支付交易会话标识
|
||||
return *resp.PrepayId, nil
|
||||
}
|
||||
|
||||
// HandleWechatPayNotification 处理微信支付回调
|
||||
func (w *WechatPayService) HandleWechatPayNotification(ctx context.Context, req *http.Request) (*payments.Transaction, error) {
|
||||
transaction := new(payments.Transaction)
|
||||
_, err := w.notifyHandler.ParseNotifyRequest(ctx, req, transaction)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("微信支付通知处理失败: %v", err)
|
||||
}
|
||||
// 返回交易信息
|
||||
return transaction, nil
|
||||
}
|
||||
|
||||
// HandleRefundNotification 处理微信退款回调
|
||||
func (w *WechatPayService) HandleRefundNotification(ctx context.Context, req *http.Request) (*refunddomestic.Refund, error) {
|
||||
refund := new(refunddomestic.Refund)
|
||||
_, err := w.notifyHandler.ParseNotifyRequest(ctx, req, refund)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("微信退款回调通知处理失败: %v", err)
|
||||
}
|
||||
return refund, nil
|
||||
}
|
||||
|
||||
// QueryOrderStatus 主动查询订单状态
|
||||
func (w *WechatPayService) QueryOrderStatus(ctx context.Context, transactionID string) (*payments.Transaction, error) {
|
||||
svc := jsapi.JsapiApiService{Client: w.wechatClient}
|
||||
|
||||
// 调用 QueryOrderById 方法查询订单状态
|
||||
resp, result, err := svc.QueryOrderById(ctx, jsapi.QueryOrderByIdRequest{
|
||||
TransactionId: core.String(transactionID),
|
||||
Mchid: core.String(w.config.MchID),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("订单查询失败: %v, 状态码: %d", err, result.Response.StatusCode)
|
||||
}
|
||||
return resp, nil
|
||||
|
||||
}
|
||||
|
||||
// WeChatRefund 申请微信退款
|
||||
func (w *WechatPayService) WeChatRefund(ctx context.Context, outTradeNo string, refundAmount float64, totalAmount float64) error {
|
||||
|
||||
// 生成唯一的退款单号
|
||||
outRefundNo := fmt.Sprintf("%s-refund", outTradeNo)
|
||||
|
||||
// 初始化退款服务
|
||||
svc := refunddomestic.RefundsApiService{Client: w.wechatClient}
|
||||
|
||||
// 创建退款请求
|
||||
resp, result, err := svc.Create(ctx, refunddomestic.CreateRequest{
|
||||
OutTradeNo: core.String(outTradeNo),
|
||||
OutRefundNo: core.String(outRefundNo),
|
||||
NotifyUrl: core.String(w.config.RefundNotifyUrl),
|
||||
Amount: &refunddomestic.AmountReq{
|
||||
Currency: core.String("CNY"),
|
||||
Refund: core.Int64(lzUtils.ToWechatAmount(refundAmount)),
|
||||
Total: core.Int64(lzUtils.ToWechatAmount(totalAmount)),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("微信订单申请退款错误: %v", err)
|
||||
}
|
||||
// 打印退款结果
|
||||
logx.Infof("退款申请成功,状态码=%d,退款单号=%s,微信退款单号=%s", result.Response.StatusCode, *resp.OutRefundNo, *resp.RefundId)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateOutTradeNo 生成唯一订单号
|
||||
func (w *WechatPayService) GenerateOutTradeNo() string {
|
||||
length := 16
|
||||
timestamp := time.Now().UnixNano()
|
||||
timeStr := strconv.FormatInt(timestamp, 10)
|
||||
randomPart := strconv.Itoa(int(timestamp % 1e6))
|
||||
combined := timeStr + randomPart
|
||||
|
||||
if len(combined) >= length {
|
||||
return combined[:length]
|
||||
}
|
||||
|
||||
for len(combined) < length {
|
||||
combined += strconv.Itoa(int(timestamp % 10))
|
||||
}
|
||||
|
||||
return combined
|
||||
}
|
||||
707
app/user/cmd/api/internal/service/westdexService.go
Normal file
707
app/user/cmd/api/internal/service/westdexService.go
Normal file
@@ -0,0 +1,707 @@
|
||||
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"
|
||||
)
|
||||
|
||||
type WestResp struct {
|
||||
Message string `json:"message"`
|
||||
Code string `json:"code"`
|
||||
Data string `json:"data"`
|
||||
ID string `json:"id"`
|
||||
ErrorCode *int `json:"error_code"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
type G05HZ01WestResp struct {
|
||||
Message string `json:"message"`
|
||||
Code string `json:"code"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
ID string `json:"id"`
|
||||
ErrorCode *int `json:"error_code"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
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 {
|
||||
return &WestDexService{
|
||||
config: c.WestConfig,
|
||||
}
|
||||
}
|
||||
|
||||
// CallAPI 调用西部数据的 API
|
||||
func (w *WestDexService) CallAPI(code string, reqData map[string]interface{}) (resp []byte, err error) {
|
||||
// 生成当前的13位时间戳
|
||||
timestamp := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)
|
||||
|
||||
// 构造请求URL
|
||||
reqUrl := fmt.Sprintf("%s/%s/%s?timestamp=%s", w.config.Url, w.config.SecretId, code, timestamp)
|
||||
|
||||
jsonData, marshalErr := json.Marshal(reqData)
|
||||
if marshalErr != nil {
|
||||
return nil, marshalErr
|
||||
}
|
||||
|
||||
// 创建HTTP POST请求
|
||||
req, newRequestErr := http.NewRequest("POST", reqUrl, bytes.NewBuffer(jsonData))
|
||||
if newRequestErr != nil {
|
||||
return nil, newRequestErr
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// 发送请求
|
||||
client := &http.Client{}
|
||||
httpResp, clientDoErr := client.Do(req)
|
||||
if clientDoErr != nil {
|
||||
return nil, clientDoErr
|
||||
}
|
||||
defer func(Body io.ReadCloser) {
|
||||
closeErr := Body.Close()
|
||||
if closeErr != nil {
|
||||
|
||||
}
|
||||
}(httpResp.Body)
|
||||
|
||||
// 检查请求是否成功
|
||||
if httpResp.StatusCode == 200 {
|
||||
// 读取响应体
|
||||
bodyBytes, ReadErr := io.ReadAll(httpResp.Body)
|
||||
if ReadErr != nil {
|
||||
return nil, ReadErr
|
||||
}
|
||||
|
||||
// 手动调用 json.Unmarshal 触发自定义的 UnmarshalJSON 方法
|
||||
var westDexResp WestResp
|
||||
UnmarshalErr := json.Unmarshal(bodyBytes, &westDexResp)
|
||||
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)
|
||||
}
|
||||
decryptedData, DecryptErr := crypto.WestDexDecrypt(westDexResp.Data, w.config.Key)
|
||||
if DecryptErr != nil {
|
||||
return nil, DecryptErr
|
||||
}
|
||||
return decryptedData, errors.New(westDexResp.Message)
|
||||
}
|
||||
if westDexResp.Data == "" {
|
||||
return nil, errors.New(westDexResp.Message)
|
||||
}
|
||||
// 解密响应数据
|
||||
decryptedData, DecryptErr := crypto.WestDexDecrypt(westDexResp.Data, w.config.Key)
|
||||
if DecryptErr != nil {
|
||||
return nil, DecryptErr
|
||||
}
|
||||
// 输出解密后的数据
|
||||
return decryptedData, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("西部请求失败Code: %d", httpResp.StatusCode)
|
||||
}
|
||||
|
||||
// CallAPI 调用西部数据的 API
|
||||
func (w *WestDexService) G05HZ01CallAPI(code string, reqData map[string]interface{}) (resp []byte, err error) {
|
||||
// 生成当前的13位时间戳
|
||||
timestamp := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)
|
||||
|
||||
// 构造请求URL
|
||||
reqUrl := fmt.Sprintf("%s/%s/%s?timestamp=%s", w.config.Url, w.config.SecretSecondId, code, timestamp)
|
||||
|
||||
jsonData, marshalErr := json.Marshal(reqData)
|
||||
if marshalErr != nil {
|
||||
return nil, marshalErr
|
||||
}
|
||||
|
||||
// 创建HTTP POST请求
|
||||
req, newRequestErr := http.NewRequest("POST", reqUrl, bytes.NewBuffer(jsonData))
|
||||
if newRequestErr != nil {
|
||||
return nil, newRequestErr
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// 发送请求
|
||||
client := &http.Client{}
|
||||
httpResp, clientDoErr := client.Do(req)
|
||||
if clientDoErr != nil {
|
||||
return nil, clientDoErr
|
||||
}
|
||||
defer func(Body io.ReadCloser) {
|
||||
closeErr := Body.Close()
|
||||
if closeErr != nil {
|
||||
|
||||
}
|
||||
}(httpResp.Body)
|
||||
|
||||
// 检查请求是否成功
|
||||
if httpResp.StatusCode == 200 {
|
||||
// 读取响应体
|
||||
bodyBytes, ReadErr := io.ReadAll(httpResp.Body)
|
||||
if ReadErr != nil {
|
||||
return nil, ReadErr
|
||||
}
|
||||
|
||||
// 手动调用 json.Unmarshal 触发自定义的 UnmarshalJSON 方法
|
||||
var westDexResp G05HZ01WestResp
|
||||
UnmarshalErr := json.Unmarshal(bodyBytes, &westDexResp)
|
||||
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)
|
||||
}
|
||||
return westDexResp.Data, errors.New(westDexResp.Message)
|
||||
}
|
||||
if westDexResp.Data == nil {
|
||||
return nil, errors.New(westDexResp.Message)
|
||||
}
|
||||
return westDexResp.Data, nil
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("响应数据转 JSON 失败: %+v", err)
|
||||
}
|
||||
|
||||
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) {
|
||||
// 使用 GJSON 递归搜索 "maritalStatus" 字段
|
||||
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
|
||||
}
|
||||
|
||||
// GetDateRange 返回今天到明天的日期范围,格式为 "yyyyMMdd-yyyyMMdd"
|
||||
func GetDateRange() string {
|
||||
today := time.Now().Format("20060102") // 获取今天的日期
|
||||
tomorrow := time.Now().Add(24 * time.Hour).Format("20060102") // 获取明天的日期
|
||||
return fmt.Sprintf("%s-%s", today, tomorrow) // 拼接日期范围并返回
|
||||
}
|
||||
Reference in New Issue
Block a user