- 增加骆驼模块设置接口支持获取和更新配置 - 使用Redis缓存设置数据,实现模块配置的持久化管理 - 引入预拉取订单日志功能,支持日志的保存和按时间范围查询 - 预拉取订单请求响应数据记录到Redis,方便问题追踪 - 根据模块设置动态调整账号登录、预拉取订单并发数量 - 调整账号登录逻辑以支持配置的并发控制 - 优化预拉取订单补充流程,支持多面额库存管理 - 修正集成API请求函数名及调用,记录详细调用日志数据 - 调整定时任务调度频率,增加预拉取订单补充任务的执行频率 - 升级golang版本到1.25.5,保持开发环境最新状态
532 lines
19 KiB
Go
532 lines
19 KiB
Go
package camel_oil_api
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"errors"
|
||
"github.com/gogf/gf/v2/net/gclient"
|
||
"github.com/gogf/gf/v2/os/glog"
|
||
"kami/api/camel_oil/v1"
|
||
"kami/internal/service"
|
||
"math"
|
||
"math/rand"
|
||
"strings"
|
||
"sync"
|
||
"sync/atomic"
|
||
)
|
||
|
||
// 绑卡错误类型枚举
|
||
const (
|
||
RechargeCardSuccess = 0 // 绑卡成功
|
||
RechargeCardErrorCode = 1 // 卡密错误
|
||
RechargeCardErrorToken = 2 // Token 过期/无效
|
||
RechargeCardErrorNetwork = 3 // 网络或其他错误
|
||
)
|
||
|
||
type Client struct {
|
||
Client *gclient.Client
|
||
}
|
||
|
||
func NewClient() *Client {
|
||
client := gclient.New()
|
||
client.SetBrowserMode(true)
|
||
client.SetHeaderMap(map[string]string{
|
||
"accept-language": "zh-CN,zh-Hans;q=0.9",
|
||
"channel": "app",
|
||
"Content-Type": "application/json",
|
||
"host": "recharge3.bac365.com",
|
||
"User-Agent": "Mozilla/5.0 (iPad; CPU OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Html5Plus/1.0 (Immersed/20) uni-app",
|
||
})
|
||
return &Client{
|
||
Client: client,
|
||
}
|
||
}
|
||
|
||
func (c *Client) SendCaptcha(ctx context.Context, phone string) (bool, error) {
|
||
req := struct {
|
||
Phone string `json:"phone"`
|
||
Channel string `json:"channel"`
|
||
}{
|
||
Phone: phone,
|
||
Channel: "app",
|
||
}
|
||
resp, err := c.Client.ContentJson().Post(ctx, "https://recharge3.bac365.com/camel_wechat_mini_oil_server/sendVerifyMessage", req)
|
||
if err != nil {
|
||
return false, err
|
||
}
|
||
respStr := resp.ReadAllString()
|
||
glog.Info(ctx, "获取信息", respStr)
|
||
respStruct := struct {
|
||
Code string `json:"code"`
|
||
Message string `json:"message"`
|
||
}{}
|
||
err = json.Unmarshal([]byte(respStr), &respStruct)
|
||
return respStruct.Code == "success", err
|
||
}
|
||
|
||
func (c *Client) GetCaptcha(ctx context.Context) (string, error) {
|
||
return "eyJjZXJ0aWZ5SWQiOiIxUE5NbzhlTHJGIiwic2NlbmVJZCI6IjFyYW8yZ2w1IiwiaXNTaWduIjp0cnVlLCJzZWN1cml0eVRva2VuIjoiNm9PbzdlNzJuQTYxdVZMaVpWS2lMVHlSNEpNS1pZMng2dGR1bzZqMnRmQmhobkw0TVpNY3lCUUF6eE92NzZLU3pYSTYxQ2pRTmFNTnpvaVVQaEt2dklWNjZxMUJiK3M5ZzVhMU1sZzN5VkdWNUpxNW1rVEdNT3FCazE1SzIzRjQifQ==", nil
|
||
//responseStruct := struct {
|
||
// RequestId string `json:"RequestId"`
|
||
// Message string `json:"Message"`
|
||
// HttpStatusCode int `json:"HttpStatusCode"`
|
||
// Code string `json:"Code"`
|
||
// Success bool `json:"Success"`
|
||
// Result struct {
|
||
// SecurityToken string `json:"securityToken"`
|
||
// VerifyCode string `json:"VerifyCode"`
|
||
// VerifyResult bool `json:"VerifyResult"`
|
||
// CertifyId string `json:"certifyId"`
|
||
// } `json:"Result"`
|
||
//}{}
|
||
//
|
||
//response, err := gclient.New().Get(ctx, "http://124.223.113.140:3012/api_aliv3")
|
||
//if err != nil {
|
||
// return "", err
|
||
//}
|
||
//responseStr := response.ReadAllString()
|
||
//err = json.Unmarshal([]byte(responseStr), &responseStruct)
|
||
//reqSign := struct {
|
||
// CertifyId string `json:"certifyId"`
|
||
// SceneId string `json:"sceneId"`
|
||
// IsSign bool `json:"isSign"`
|
||
// SecurityToken string `json:"securityToken"`
|
||
//}{
|
||
// CertifyId: responseStruct.Result.CertifyId,
|
||
// SceneId: "1rao2gl5",
|
||
// IsSign: true,
|
||
// SecurityToken: responseStruct.Result.SecurityToken,
|
||
//}
|
||
//signBytes, _ := json.Marshal(reqSign)
|
||
//signStr := gbase64.Encode(signBytes)
|
||
//return string(signStr), err
|
||
}
|
||
|
||
func (c *Client) LoginWithCaptcha(ctx context.Context, phone string, code string) (string, error) {
|
||
//token, err := c.GetCaptcha(ctx)
|
||
//if err != nil {
|
||
// return "", err
|
||
//}
|
||
|
||
req := struct {
|
||
Phone string `json:"phone"`
|
||
Codes string `json:"codes"`
|
||
Channel string `json:"channel"`
|
||
}{
|
||
|
||
Phone: phone,
|
||
Codes: code,
|
||
Channel: "app",
|
||
}
|
||
resp, err := c.Client.ContentJson().Post(ctx, "https://recharge3.bac365.com/camel_wechat_mini_oil_server/loginApp", req)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
respStr := resp.ReadAllString()
|
||
glog.Info(ctx, "登录", req, respStr)
|
||
respStruct := struct {
|
||
LoginUser struct {
|
||
UserIdApp string `json:"userIdApp"`
|
||
Phone string `json:"phone"`
|
||
UserIdCamel string `json:"userIdCamel"`
|
||
LoginTime string `json:"loginTime"`
|
||
ExpireTime string `json:"expireTime"`
|
||
Ipaddr string `json:"ipaddr"`
|
||
} `json:"loginUser,omitempty"`
|
||
Code string `json:"code"`
|
||
Message string `json:"message"`
|
||
Token string `json:"token,omitempty"`
|
||
}{}
|
||
err = json.Unmarshal([]byte(respStr), &respStruct)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
if respStruct.Code != "success" {
|
||
return "", errors.New(respStruct.Message)
|
||
}
|
||
return respStruct.Token, err
|
||
}
|
||
|
||
// generateRandomCoordinates 生成指定坐标附近的随机坐标
|
||
func generateRandomCoordinates(baseLat, baseLon float64, radius float64) (float64, float64) {
|
||
// 在指定半径内生成随机坐标
|
||
// 纬度1度约等于111km
|
||
latDelta := (rand.Float64()*2 - 1) * (radius / 111000.0)
|
||
lonDelta := (rand.Float64()*2 - 1) * (radius / (111000.0 * math.Cos(baseLat*math.Pi/180.0)))
|
||
|
||
newLat := baseLat + latDelta
|
||
newLon := baseLon + lonDelta
|
||
|
||
return newLat, newLon
|
||
}
|
||
|
||
func (c *Client) getAuth(ctx context.Context, auth string) string {
|
||
base64Private := "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIHSkp+Z0Lu+lZWr/wKcMT3EcWEIihKTg/jEOyKaczqG9hWL9UULJ1dFtIQNlpWRySsVZcJLoGTFdGam557lVzpY/tbN73KG9iVMBaKALLF52cgmyg0DRve4atc0OnkhTjv7Rf8B85UokdHCAM/5MgNcjXwqBGHohJ2LGC9yN2erAgMBAAECgYATfTeqww4daTaOkhQF4cnYonl83inQMRoSSe8wuiwLQMCHqounEk4VIW9AlcOh75FaKOuuV+kbx7K6SFskNPy7nGYfS22t2aM9E9Rt+JH+caEniYi5qAfb3gCIgsGExUNI6iuSM2p3/R542EDGc2FyfPPqyht+jR4CjLOLoXHfoQJBALwvF6uIOSW0Lxh7Lo/JsKpWJ1qffDvXWYag605L9JAyP0yO64woF60Tn+mGRzcaEhNDSEjinKQqPEJnxDUGYaECQQCwm1mQKD95MaeKWBiOVJZsdzL5aJsW42xyiu0ZwA7bZUgJyUskzXG0ubeIHK/czlJbev9ODubbMNJFcngX4N3LAkAJaxH0M80oZew1fXTHHYEKBWXS00iUdiK06jjcolCLJvikDEMdsKP+tYy7U00dJODitetYOn88eCCr8iWPwdIBAkBtUjzGt6NS6iHDyXSp5kKXMdIkAVS/flgLL2RFpFWOCcvmAuy5A1N3g97QKrHSBQWGC0UulJri4/3Fb25XmaKxAkBifs9dbUifeqZRNVh2Omck4xedb1FyQPLDicUycjYug3Vca0T/LRr80aX/NhbhtpSdwzF1ukiZ6W46O9DmGuNy" // 私钥 base64 或带 PEM
|
||
base64Pub := "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpwypBPN8r3Zwv3T0XUh1Ka2m2hUe3KBgIyH4fHfN/T1jsBWnbwotKEQdZfRva7mRYiz9YrTHoH/eUAuv+WYqPMubaiqpWOu0l+BzEX1kPGA98qRC06IF2Tk4Z5xAmQ8p8u3O5jxohYFkO2XlDvPU+W9SDZgSEBTe8p80LExgo6wIDAQAB" // 公钥 base64 或带 PEM
|
||
authRes, _ := DecryptWithPrivateThenEncryptWithPublic(base64Private, base64Pub, auth)
|
||
return authRes
|
||
}
|
||
|
||
// QueryCamelOilCardAvailableDenominations 查询所有可用面额
|
||
func (c *Client) QueryCamelOilCardAvailableDenominations(ctx context.Context, token string) ([]Good, error) {
|
||
c.Client.SetHeader("authorization", "Bearer "+c.getAuth(ctx, token))
|
||
resp, err := c.Client.ContentJson().Post(ctx, "https://recharge3.bac365.com/camel_wechat_mini_oil_server/eCardMall/wechatCardGoods", struct {
|
||
Channel string `json:"channel"`
|
||
}{
|
||
Channel: "app",
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
queryRespStruct := struct {
|
||
Code string `json:"code"`
|
||
Goods []Good `json:"goods"`
|
||
}{}
|
||
respStr := resp.ReadAllString()
|
||
glog.Info(ctx, "查询面额", respStr)
|
||
if err = json.Unmarshal([]byte(respStr), &queryRespStruct); err != nil {
|
||
return nil, err
|
||
}
|
||
return queryRespStruct.Goods, nil
|
||
}
|
||
|
||
func (c *Client) CreateCamelOilOrder(ctx context.Context, phone, token string, amount float64) (orderId string, payUrl string, err error) {
|
||
c.Client.SetHeader("Authorization", "Bearer "+c.getAuth(ctx, token))
|
||
goods, err := c.QueryCamelOilCardAvailableDenominations(ctx, token)
|
||
if err != nil {
|
||
return "", "", err
|
||
}
|
||
goodId := ""
|
||
for _, good := range goods {
|
||
if good.Denomination == amount {
|
||
goodId = good.GoodId
|
||
break
|
||
}
|
||
}
|
||
if goodId == "" {
|
||
return "", "", errors.New("当前金额不支持")
|
||
}
|
||
|
||
const maxRetries = 10
|
||
|
||
// 获取骆驼模块设置
|
||
settingsRes, err := service.CamelOil().GetSettings(ctx, &v1.GetSettingsReq{})
|
||
var maxConcurrency int
|
||
if err != nil {
|
||
glog.Error(ctx, "获取骆驼模块设置失败,使用默认并发数", err)
|
||
// 使用默认值继续执行
|
||
maxConcurrency = 5
|
||
} else {
|
||
maxConcurrency = settingsRes.PrefetchConcurrencyAccounts
|
||
}
|
||
|
||
// 结果存储
|
||
var resultMutex sync.Mutex
|
||
var successResult *struct {
|
||
orderId string
|
||
payUrl string
|
||
}
|
||
var resultError error
|
||
var completed atomic.Bool
|
||
|
||
// 创建协程池
|
||
var wg sync.WaitGroup
|
||
semaphore := make(chan struct{}, maxConcurrency)
|
||
|
||
for range maxRetries {
|
||
// 检查是否已经有结果
|
||
if completed.Load() {
|
||
break
|
||
}
|
||
|
||
wg.Go(func() {
|
||
// 获取信号量
|
||
semaphore <- struct{}{}
|
||
defer func() { <-semaphore }()
|
||
|
||
// 已有结果则跳过
|
||
if completed.Load() {
|
||
return
|
||
}
|
||
|
||
//captchaSign, err2 := c.GetCaptcha(ctx)
|
||
//if err2 != nil {
|
||
// return
|
||
//}
|
||
|
||
// 生成随机坐标(在原坐标周围1公里范围内)
|
||
paramY, paramX := generateRandomCoordinates(36.36142896926231, 118.9886283180532, 1000.0)
|
||
|
||
bodyStr := struct {
|
||
OpenId string `json:"openId"`
|
||
Phone string `json:"phone"`
|
||
GoodId string `json:"goodId"`
|
||
GoodNum int `json:"goodNum"`
|
||
BindPhone string `json:"bindPhone"`
|
||
PayType string `json:"payType"`
|
||
ParamY float64 `json:"paramY"`
|
||
ParamX float64 `json:"paramX"`
|
||
Yanqian bool `json:"yanqian"`
|
||
MobileOperatingPlatform string `json:"mobileOperatingPlatform"`
|
||
SysVersion string `json:"sysVersion"`
|
||
PlatformType string `json:"platformType"`
|
||
NetWork string `json:"netWork"`
|
||
Platform string `json:"platform"`
|
||
Brand string `json:"brand"`
|
||
DeviceId string `json:"deviceId"`
|
||
}{
|
||
OpenId: "app2511282235395452908",
|
||
Phone: phone,
|
||
GoodId: goodId,
|
||
GoodNum: 1,
|
||
BindPhone: phone,
|
||
PayType: "appAli",
|
||
ParamY: paramY,
|
||
ParamX: paramX,
|
||
Yanqian: true,
|
||
MobileOperatingPlatform: "ios",
|
||
SysVersion: "iOS 26.2",
|
||
PlatformType: "iPad Pro (12.9-inch) (3rd generation)",
|
||
NetWork: "unknown",
|
||
Platform: "ios",
|
||
Brand: "apple",
|
||
DeviceId: "4E071A21C568F1939D61F38E5F5C3813",
|
||
}
|
||
pubkey := "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkc6Xr/JhWEx/WPxG2q3VHLQ+FYk/oCmQ1y14B5j4xOJY+mAWoDOOti3sAXg0Kk662gWjWET1nLI6YED4wb9HWon1NAZn47lgc5ohIpEdU91Jao85X/kgkD3NvTTvhFicttepUOsrYUZN8rAQCE7AhzwGgKnCiIRY/kE8jOCCeZQIDAQAB"
|
||
body, _ := json.Marshal(&bodyStr)
|
||
bodyS, _ := EncryptWithPublicKey(pubkey, string(body))
|
||
req := struct {
|
||
BodyStr string `json:"bodyStr"`
|
||
Yanqian bool `json:"yanqian"`
|
||
Channel string `json:"channel"`
|
||
}{
|
||
BodyStr: bodyS,
|
||
Channel: "app",
|
||
Yanqian: true,
|
||
}
|
||
//proxy, err2 := service.ProxyPool().GetProxyByOrderId(ctx, phone)
|
||
//if err2 == nil && proxy.Host != "" {
|
||
// glog.Info(ctx, "代理 ip", proxy.String())
|
||
// c.Client.SetProxy(proxy.String())
|
||
//}
|
||
resp, err1 := c.Client.Post(ctx, "https://recharge3.bac365.com/camel_wechat_mini_oil_server/eCardMall/wechatCardOrder", req)
|
||
if err1 != nil {
|
||
resultMutex.Lock()
|
||
if !completed.Load() && resultError == nil {
|
||
resultError = err1
|
||
}
|
||
resultMutex.Unlock()
|
||
return
|
||
}
|
||
respStr := resp.ReadAllString()
|
||
|
||
// 记录响应数据到日志
|
||
service.CamelOil().SavePrefetchOrderLog(ctx, phone, amount, respStr)
|
||
|
||
respStruct := struct {
|
||
Code string `json:"code"`
|
||
Message string `json:"message"`
|
||
OrderRes struct {
|
||
Body string `json:"body"`
|
||
} `json:"orderRes,omitempty"`
|
||
OrderId string `json:"orderid,omitempty"`
|
||
}{}
|
||
err = json.Unmarshal([]byte(respStr), &respStruct)
|
||
if err != nil {
|
||
resultMutex.Lock()
|
||
if !completed.Load() && resultError == nil {
|
||
resultError = err
|
||
}
|
||
resultMutex.Unlock()
|
||
return
|
||
}
|
||
|
||
// 处理响应
|
||
switch respStruct.Code {
|
||
case "limit", "error":
|
||
if respStruct.Code == "error" && strings.Contains(respStruct.Message, "系统繁忙") {
|
||
return // 继续重试
|
||
}
|
||
return
|
||
case "auth_error":
|
||
resultMutex.Lock()
|
||
if !completed.Load() {
|
||
resultError = errors.New("auth_error")
|
||
completed.Store(true)
|
||
}
|
||
resultMutex.Unlock()
|
||
return
|
||
case "success":
|
||
base64PrivateKey := "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKRzpev8mFYTH9Y/EbardUctD4ViT+gKZDXLXgHmPjE4lj6YBagM462LewBeDQqTrraBaNYRPWcsjpgQPjBv0daifU0BmfjuWBzmiEikR1T3Ulqjzlf+SCQPc29NO+EWJy216lQ6ythRk3ysBAITsCHPAaAqcKIhFj+QTyM4IJ5lAgMBAAECgYEAg/vlMI7b3EkhBhw8JTVavLMnf8+1fe/JGXuMiU22oF5gBwCPmZ4upLwLDfJt2Q1J7WPTNetEMqgKEXUH1GwKJkFGm2tSEMHSHdTmUTQ3w6bS1C0peZghyhmlWRXUlpKk5tDOQ24sWO268YrwZyueXnVGKJ4s0hY0KOiZIU2trUECQQDxA+lzq/t/L09M/bUybjsiP6eb/HBeZeu+2+JnHekb8z9BMXTOKTHqAI0Cs9UvE6BDT3aU9IJbWHbRogIMypT9AkEArq0fccphwWtAIyS0+fns4Hqs4On7yTfXSXWiAbSVif1LxP60b5n5Xm8lo12oHkdwOvKaesvgDpnIGUM9xjFfiQJASTZrABxKNYRljnmzRTJ+/BRiEdxJNiO3zS52Q+SuHzNxD5i6ZrXU18R7EUsXg0lu8YN9/hmYT687yMpx3Pjc8QJAZBs1lSouQgIsPLfRvB1+otvLbg7KzPPivufak+2hcfanUNvEHt14a6V5RZnsOoYojK/y1oM3AkchxVCi+43aOQJAC0gI6qsZ3VaPu9QDddrHPJ1dCHTXyfcNJ0op3srCVF92HoBWX54pzeagj+9g/Z4oUT9IhaO0Q3YE07N03HuVrQ=="
|
||
respData, _ := DecryptWithPrivateKey(base64PrivateKey, respStruct.OrderRes.Body)
|
||
resultMutex.Lock()
|
||
if !completed.Load() {
|
||
successResult = &struct {
|
||
orderId string
|
||
payUrl string
|
||
}{
|
||
orderId: respStruct.OrderId,
|
||
payUrl: respData,
|
||
}
|
||
completed.Store(true)
|
||
}
|
||
resultMutex.Unlock()
|
||
return
|
||
}
|
||
})
|
||
}
|
||
|
||
wg.Wait()
|
||
|
||
// 返回结果
|
||
if successResult != nil {
|
||
return successResult.orderId, successResult.payUrl, nil
|
||
}
|
||
if resultError != nil {
|
||
return "", "", resultError
|
||
}
|
||
return "", "", errors.New("创建订单超时")
|
||
}
|
||
|
||
// QueryOrder 查询对应订单
|
||
// 返回值说明:
|
||
// - result != nil && err == nil: 查询成功,找到订单
|
||
// - result == nil && err == nil: 查询成功,但未找到订单
|
||
// - result == nil && err != nil: 查询失败,有错误
|
||
func (c *Client) QueryOrder(ctx context.Context, phone, token, orderId string) (result *QueryResult, err error) {
|
||
c.Client.SetHeader("Authorization", "Bearer "+c.getAuth(ctx, token))
|
||
|
||
// 最多查询100页,防止无限循环
|
||
maxPages := 100
|
||
pageNum := 1
|
||
|
||
for pageNum <= maxPages {
|
||
reqBody := struct {
|
||
OrderId string `json:"orderId"`
|
||
Sign string `json:"sign"`
|
||
Channel string `json:"channel"`
|
||
Status string `json:"status"`
|
||
PageNum int `json:"pageNum"`
|
||
PageSize int `json:"pageSize"`
|
||
OpenId string `json:"openId"`
|
||
}{
|
||
OrderId: orderId,
|
||
Sign: Sign("app2511181557205741495"),
|
||
Channel: "app",
|
||
Status: "unused",
|
||
PageNum: pageNum,
|
||
PageSize: 50,
|
||
OpenId: "app2511181557205741495",
|
||
}
|
||
|
||
respData, err := c.Client.Post(ctx, "https://recharge3.bac365.com/camel_wechat_mini_oil_server/eCardMall/queryWechatUserECards", reqBody)
|
||
if err != nil {
|
||
glog.Errorf(ctx, "查询卡券失败,第%d页,错误: %v", pageNum, err)
|
||
return nil, err
|
||
}
|
||
|
||
respStruct := struct {
|
||
Total string `json:"total"`
|
||
Code string `json:"code"`
|
||
Cards []struct {
|
||
RecordId string `json:"recordId"`
|
||
Denomination float64 `json:"denomination"`
|
||
CreateTime string `json:"createTime"`
|
||
ExpireTime string `json:"expireTime"`
|
||
Status string `json:"status"`
|
||
OrderId string `json:"orderId"`
|
||
ECardNo string `json:"ecardNo"`
|
||
ECardCode string `json:"ecardCode"`
|
||
} `json:"cards,omitempty"`
|
||
}{}
|
||
|
||
err = json.Unmarshal(respData.ReadAll(), &respStruct)
|
||
if err != nil {
|
||
glog.Errorf(ctx, "解析响应失败,第%d页,错误: %v", pageNum, err)
|
||
return nil, err
|
||
}
|
||
|
||
// 如果当前页没有卡券数据,说明已查询所有数据
|
||
if len(respStruct.Cards) == 0 {
|
||
glog.Debugf(ctx, "查询订单%s已完成,共查询%d页,未找到", orderId, pageNum-1)
|
||
return nil, nil
|
||
}
|
||
|
||
// 在当前页查找目标订单
|
||
for _, card := range respStruct.Cards {
|
||
if card.OrderId == orderId {
|
||
glog.Infof(ctx, "查询订单%s成功,金额: %.2f", orderId, card.Denomination)
|
||
return &QueryResult{
|
||
Balance: card.Denomination,
|
||
CardNumber: card.ECardNo,
|
||
CardPassword: card.ECardCode,
|
||
}, nil
|
||
}
|
||
}
|
||
|
||
// 当前页未找到,继续查询下一页
|
||
pageNum++
|
||
}
|
||
|
||
glog.Warningf(ctx, "查询订单%s超过最大页数%d,未找到", orderId, maxPages)
|
||
return nil, nil
|
||
}
|
||
|
||
// RechargeCard 绑卡接口
|
||
// 返回值说明:
|
||
// - errType == RechargeCardSuccess: 绑卡成功
|
||
// - errType == RechargeCardErrorCode: 卡密错误
|
||
// - errType == RechargeCardErrorToken: token 过期/无效
|
||
// - errType == RechargeCardErrorNetwork: 网络或其他错误
|
||
func (c *Client) RechargeCard(ctx context.Context, token, phone, eCardCode string) (errType int, err error) {
|
||
c.Client.SetHeader("Authorization", "Bearer "+c.getAuth(ctx, token))
|
||
|
||
req := struct {
|
||
ECardCode string `json:"eCardCode"`
|
||
OpenId string `json:"openId"`
|
||
Phone string `json:"phone"`
|
||
Channel string `json:"channel"`
|
||
}{
|
||
ECardCode: eCardCode,
|
||
OpenId: "app2511181557205741495",
|
||
Phone: phone,
|
||
Channel: "app",
|
||
}
|
||
|
||
resp, err := c.Client.ContentJson().Post(ctx, "https://recharge3.bac365.com/camel_wechat_mini_oil_server/eCardMall/eCardRecharge", req)
|
||
if err != nil {
|
||
glog.Errorf(ctx, "绑卡请求失败,错误: %v", err)
|
||
return RechargeCardErrorNetwork, err
|
||
}
|
||
|
||
respStruct := struct {
|
||
Code string `json:"code"`
|
||
Message string `json:"message"`
|
||
}{}
|
||
|
||
err = json.Unmarshal(resp.ReadAll(), &respStruct)
|
||
if err != nil {
|
||
glog.Errorf(ctx, "解析绑卡响应失败,错误: %v", err)
|
||
return RechargeCardErrorNetwork, err
|
||
}
|
||
|
||
// 根据不同的错误码进行分类
|
||
switch respStruct.Code {
|
||
case "success":
|
||
glog.Infof(ctx, "卡密绑卡成功,手机号: %s", phone)
|
||
return RechargeCardSuccess, nil
|
||
case "codeError":
|
||
err = errors.New(respStruct.Message)
|
||
glog.Warningf(ctx, "卡密错误: %v", err)
|
||
return RechargeCardErrorCode, err
|
||
case "auth_error", "unauthorized":
|
||
err = errors.New(respStruct.Message)
|
||
glog.Warningf(ctx, "Token 错误或已过期: %v", err)
|
||
return RechargeCardErrorToken, err
|
||
default:
|
||
err = errors.New(respStruct.Message)
|
||
glog.Errorf(ctx, "绑卡失败: %v", err)
|
||
return RechargeCardErrorNetwork, err
|
||
}
|
||
}
|