1、
This commit is contained in:
		| @ -1,6 +1,7 @@ | ||||
| package apis | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"go-admin/common/const/rediskey" | ||||
| 	"go-admin/common/global" | ||||
| @ -284,7 +285,15 @@ func (e LinePreOrder) AddPreOrder(c *gin.Context) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	userId := user.GetUserId(c) | ||||
|  | ||||
| 	if userId <= 0 { | ||||
| 		e.Error(500, errors.New("用户不存在"), "用户不存在") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	p := actions.GetPermissionFromContext(c) | ||||
| 	req.SetCreateBy(userId) | ||||
| 	errs := make([]error, 0) | ||||
| 	errStr := make([]string, 0) | ||||
| 	var tickerSymbol string | ||||
| @ -358,6 +367,13 @@ func (e LinePreOrder) BatchAddOrder(c *gin.Context) { | ||||
| 	p := actions.GetPermissionFromContext(c) | ||||
| 	errs := make([]error, 0) | ||||
| 	errStr := make([]string, 0) | ||||
| 	userId := user.GetUserId(c) | ||||
|  | ||||
| 	if userId <= 0 { | ||||
| 		e.Error(500, nil, "用户不存在") | ||||
| 		return | ||||
| 	} | ||||
| 	req.SetCreateBy(userId) | ||||
| 	s.AddBatchPreOrder(&req, p, &errs) | ||||
| 	if len(errs) > 0 { | ||||
| 		//e.Logger.Error(err) | ||||
| @ -392,7 +408,14 @@ func (e LinePreOrder) QuickAddPreOrder(c *gin.Context) { | ||||
| 	p := actions.GetPermissionFromContext(c) | ||||
| 	errs := make([]error, 0) | ||||
| 	errStr := make([]string, 0) | ||||
| 	err = s.QuickAddPreOrder(&req, p, &errs) | ||||
| 	userId := user.GetUserId(c) | ||||
|  | ||||
| 	if userId <= 0 { | ||||
| 		e.Error(500, nil, "用户不存在") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	err = s.QuickAddPreOrder(&req, p, userId, &errs) | ||||
| 	if len(errs) > 0 { | ||||
| 		//e.Logger.Error(err) | ||||
| 		for _, err2 := range errs { | ||||
|  | ||||
| @ -26,7 +26,6 @@ import ( | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"github.com/go-admin-team/go-admin-core/logger" | ||||
| 	"github.com/go-admin-team/go-admin-core/sdk/api" | ||||
| 	"github.com/shopspring/decimal" | ||||
| 	"gorm.io/gorm" | ||||
| ) | ||||
|  | ||||
| @ -364,6 +363,11 @@ func (e LineUserApi) Info(c *gin.Context) { | ||||
| 	binanceAccount := service.BinanceAccount{Service: s.Service} | ||||
|  | ||||
| 	//获取用户资金账户资产 | ||||
| 	totalAsset, err := binanceAccount.GetTotalAsset(userId) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		e.Logger.Errorf("获取用户资金账户资产失败:%v", err) | ||||
| 	} | ||||
| 	resp, err := binanceAccount.GetFundingAsset(userId) | ||||
| 	if err != nil { | ||||
| 		e.Logger.Error(500, err, err.Error()) | ||||
| @ -375,28 +379,26 @@ func (e LineUserApi) Info(c *gin.Context) { | ||||
| 	if val != "" { | ||||
| 		sonic.Unmarshal([]byte(val), &tickerData) | ||||
| 	} | ||||
| 	var usdtBalance decimal.Decimal | ||||
| 	// var usdtBalance decimal.Decimal | ||||
| 	for i, asset := range resp { | ||||
| 		symbol := asset.Asset + "USDT" | ||||
| 		for _, datum := range tickerData { | ||||
| 			if datum.Symbol == symbol { | ||||
| 				mul := utility.StringToDecimal(datum.Price).Mul(utility.StringToDecimal(asset.Free)) | ||||
| 				usdtBalance = usdtBalance.Add(mul) | ||||
| 				// mul := utility.StringToDecimal(datum.Price).Mul(utility.StringToDecimal(asset.Free)) | ||||
| 				// usdtBalance = usdtBalance.Add(mul) | ||||
| 				resp[i].UsdtValuation = datum.Price | ||||
| 			} | ||||
| 		} | ||||
| 		//if asset.Asset == "USDT" { | ||||
| 		//	usdt = asset.Free | ||||
| 		//} | ||||
| 	} | ||||
|  | ||||
| 	// 邀请人数 | ||||
| 	//var inviteNum int64 | ||||
| 	var inviteNum int64 | ||||
| 	var userinfo models.LineUser | ||||
| 	e.Orm.Model(&models.LineUser{}).Where("id = ?", userId).Find(&userinfo) | ||||
| 	e.Orm.Model(&models.LineUser{}).Where("pid =? or top_referrer_id =?", userId, userId).Count(&inviteNum) | ||||
|  | ||||
| 	var apiUserinfo models.LineApiUser | ||||
| 	e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&apiUserinfo) | ||||
| 	e.Orm.Model(&models.LineApiUser{}).Where("user_id = ? ", userId).Find(&apiUserinfo) | ||||
| 	var isAuth bool | ||||
| 	if apiUserinfo.ApiKey != "" && apiUserinfo.ApiSecret != "" { | ||||
| 		isAuth = true | ||||
| @ -418,7 +420,7 @@ func (e LineUserApi) Info(c *gin.Context) { | ||||
| 		"avatar":      userinfo.Avatar, | ||||
| 		"user_id":     userinfo.Id, | ||||
| 		"user_name":   userinfo.Nickname, | ||||
| 		"invite_num":  userinfo.RecommendNum, | ||||
| 		"invite_num":  inviteNum, | ||||
| 		"open_status": apiUserinfo.OpenStatus, | ||||
| 		"is_auth":     isAuth, | ||||
| 		"invite_url":  fmt.Sprintf("%s/invice_url?invite_code=%s", ext.ExtConfig.Domain, userinfo.InviteCode), | ||||
| @ -428,7 +430,7 @@ func (e LineUserApi) Info(c *gin.Context) { | ||||
| 		"api_secret":  inttostring.EncryptString(apiUserinfo.ApiSecret, 4, 4), | ||||
| 	} | ||||
| 	returnMap := map[string]interface{}{ | ||||
| 		"u_balance":     usdtBalance.Truncate(2), | ||||
| 		"u_balance":     totalAsset.Truncate(2), | ||||
| 		"margin":        userinfo.Money, | ||||
| 		"userinfo":      user, | ||||
| 		"funding_asset": fundingAsset, | ||||
|  | ||||
| @ -9,3 +9,9 @@ type FundingAsset struct { | ||||
| 	BtcValuation  string `json:"btcValuation"` | ||||
| 	UsdtValuation string `json:"usdt_valuation"` | ||||
| } | ||||
|  | ||||
| type BinanceWalletBalance struct { | ||||
| 	Active     bool   `json:"active"` | ||||
| 	Balance    string `json:"balance"` | ||||
| 	WalletName string `json:"walletName"` | ||||
| } | ||||
|  | ||||
| @ -3,12 +3,19 @@ package service | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/bytedance/sonic" | ||||
| 	"github.com/go-admin-team/go-admin-core/sdk/service" | ||||
| 	"go-admin/app/admin/models" | ||||
| 	"go-admin/common/const/rediskey" | ||||
| 	"go-admin/common/global" | ||||
| 	"go-admin/common/helper" | ||||
| 	ext "go-admin/config" | ||||
| 	"go-admin/pkg/utility" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/bytedance/sonic" | ||||
| 	"github.com/go-admin-team/go-admin-core/logger" | ||||
| 	"github.com/go-admin-team/go-admin-core/sdk/service" | ||||
| 	"github.com/shopspring/decimal" | ||||
| ) | ||||
|  | ||||
| const ProxyType = "socks5" | ||||
| @ -62,3 +69,90 @@ func (e *BinanceAccount) GetFundingAsset(userId int) (resp []models.FundingAsset | ||||
|  | ||||
| 	return resp, nil | ||||
| } | ||||
|  | ||||
| /* | ||||
| 获取钱包余额 | ||||
|  | ||||
|   - @param userId 用户id | ||||
|   - @param quoteAsset 币种 USDT, ETH, USDC, BNB等。 默认 BTC | ||||
|   - @return []models.FundingAsset 钱包余额 | ||||
| */ | ||||
| func (e *BinanceAccount) GetWalletBalance(userId int, quoteAsset string) (resp []models.BinanceWalletBalance, err error) { | ||||
| 	if quoteAsset == "" { | ||||
| 		quoteAsset = "BTC" | ||||
| 	} | ||||
|  | ||||
| 	var proxyUrl, proxyType string | ||||
| 	var apiUser models.LineApiUser | ||||
| 	url := "/sapi/v1/asset/wallet/balance" | ||||
| 	err = e.Orm.Where(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&apiUser).Error | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("Service LineApiUser error:%s \r\n", err) | ||||
| 		return []models.BinanceWalletBalance{}, err | ||||
| 	} | ||||
| 	if apiUser.Id <= 0 { | ||||
| 		e.Log.Errorf("Service LineApiUser error:%s \r\n", "用户未找到") | ||||
| 		return []models.BinanceWalletBalance{}, err | ||||
| 	} | ||||
|  | ||||
| 	if ext.ExtConfig.ProxyUrl != "" { | ||||
| 		proxyUrl = "127.0.0.1:7890" | ||||
| 		proxyType = "http" | ||||
| 	} | ||||
|  | ||||
| 	if apiUser.IpAddress != "" && apiUser.UserPass != "" { | ||||
| 		proxyUrl = fmt.Sprintf("%s:%s", apiUser.IpAddress, apiUser.UserPass) | ||||
| 		proxyType = ProxyType | ||||
| 	} | ||||
| 	clinet, err := helper.NewBinanceClient(apiUser.ApiKey, apiUser.ApiSecret, proxyType, proxyUrl) | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("Service NewBinanceClient error:%s \r\n", err) | ||||
| 		return []models.BinanceWalletBalance{}, err | ||||
| 	} | ||||
| 	req := map[string]string{ | ||||
| 		"quoteAsset": quoteAsset, | ||||
| 		"recvWindow": "10000", | ||||
| 	} | ||||
|  | ||||
| 	httpResp, statusCode, err := clinet.SendSpotAuth(url, "GET", req) | ||||
| 	if err != nil { | ||||
| 		e.Log.Errorf("Service SendSpotAuth error:%s \r\n", err) | ||||
| 		return []models.BinanceWalletBalance{}, err | ||||
| 	} | ||||
|  | ||||
| 	if statusCode != http.StatusOK { | ||||
| 		e.Log.Errorf("Service 请求失败 error:%s \r\n", err) | ||||
| 		return []models.BinanceWalletBalance{}, errors.New("请求失败") | ||||
| 	} | ||||
| 	sonic.Unmarshal(httpResp, &resp) | ||||
|  | ||||
| 	return resp, nil | ||||
| } | ||||
|  | ||||
| /* | ||||
| 获取用户总资产 | ||||
| */ | ||||
| func (e *BinanceAccount) GetTotalAsset(userId int) (decimal.Decimal, error) { | ||||
| 	key := fmt.Sprintf(rediskey.User_Total_Asset, global.EXCHANGE_BINANCE, userId) | ||||
| 	totalStr, _ := helper.DefaultRedis.GetString(key) | ||||
| 	result := decimal.Zero | ||||
| 	if totalStr != "" { | ||||
| 		result = utility.StrToDecimal(totalStr) | ||||
| 	} else { | ||||
| 		assets, err := e.GetWalletBalance(userId, "USDT") | ||||
|  | ||||
| 		if err != nil { | ||||
| 			logger.Errorf("GetTotalAsset error:%s", err) | ||||
|  | ||||
| 			return decimal.Decimal{}, err | ||||
| 		} | ||||
|  | ||||
| 		for _, asset := range assets { | ||||
| 			result = result.Add(utility.StrToDecimal(asset.Balance)) | ||||
| 		} | ||||
|  | ||||
| 		helper.DefaultRedis.SetStringExpire(key, result.String(), 30*time.Second) | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| @ -209,6 +209,7 @@ type LineAddPreOrderReq struct { | ||||
| 	ReduceReTakeProfitRatio decimal.Decimal `json:"re_take_profit_ratio" comment:"减仓后亏损回本止盈百分比"` | ||||
|  | ||||
| 	Ext []LineAddPreOrderExtReq `json:"ext" ` //拓展字段 | ||||
| 	common.ControlBy | ||||
| } | ||||
|  | ||||
| type LinePreOrderAddPositionReq struct { | ||||
| @ -389,6 +390,7 @@ type LineBatchAddPreOrderReq struct { | ||||
| 	ReduceTakeProfitRatio decimal.Decimal         `json:"reduce_take_profit"`       //主单减仓后止盈价百分比 | ||||
| 	ReduceStopLossRatio   decimal.Decimal         `json:"reduce_stop_price"`        //主单减仓后止损价百分比 | ||||
| 	Ext                   []LineAddPreOrderExtReq `json:"ext"`                      //拓展字段 | ||||
| 	common.ControlBy | ||||
| } | ||||
|  | ||||
| func (req LineBatchAddPreOrderReq) CheckParams() error { | ||||
|  | ||||
| @ -18,10 +18,12 @@ type LineSymbolGetPageReq struct { | ||||
| } | ||||
|  | ||||
| type LineSymbolExportResp struct { | ||||
| 	Symbol     string `json:"symbol" excel:"交易对"` | ||||
| 	Coin       string `json:"coin" excel:"基础货币"` | ||||
| 	Currency   string `json:"currency" excel:"计价货币"` | ||||
| 	SymbolType string `json:"symbolType" excel:"交易对类型"` | ||||
| 	ExchangeType string `json:"exchangeType"  excel:"交易所"` | ||||
| 	Symbol       string `json:"symbol" excel:"交易对"` | ||||
| 	Coin         string `json:"coin" excel:"基础货币"` | ||||
| 	Currency     string `json:"currency" excel:"计价货币"` | ||||
| 	SymbolType   string `json:"symbolType" excel:"交易对类型"` | ||||
| 	LastPrice    string `json:"lastPrice" excel:"最新价"` | ||||
| } | ||||
|  | ||||
| type LineSymbolOrder struct { | ||||
|  | ||||
| @ -278,14 +278,15 @@ func (receiver FrontedLoginReq) CheckParams() int { | ||||
| } | ||||
|  | ||||
| type AddApiKeyReq struct { | ||||
| 	ApiName   string `json:"api_name"` | ||||
| 	ApiKey    string `json:"api_key"` | ||||
| 	ApiSecret string `json:"api_secret"` | ||||
| 	ApiIp     string `json:"api_ip"` | ||||
| 	ExchangeType string `json:"exchange_type"` | ||||
| 	ApiName      string `json:"api_name"` | ||||
| 	ApiKey       string `json:"api_key"` | ||||
| 	ApiSecret    string `json:"api_secret"` | ||||
| 	ApiIp        string `json:"api_ip"` | ||||
| } | ||||
|  | ||||
| func (a AddApiKeyReq) CheckParams() int { | ||||
| 	if a.ApiKey == "" || a.ApiSecret == "" { | ||||
| 	if a.ExchangeType == "" || a.ApiKey == "" || a.ApiSecret == "" { | ||||
| 		return statuscode.ParamErr | ||||
| 	} | ||||
| 	return statuscode.OK | ||||
|  | ||||
| @ -29,7 +29,7 @@ func (e *LineDirection) GetPage(c *dto.LineDirectionGetPageReq, p *actions.DataP | ||||
| 		Scopes( | ||||
| 			cDto.MakeCondition(c.GetNeedSearch()), | ||||
| 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), | ||||
| 			actions.Permission(data.TableName(), p), | ||||
| 			// actions.Permission(data.TableName(), p), | ||||
| 		). | ||||
| 		Find(list).Limit(-1).Offset(-1). | ||||
| 		Count(count).Error | ||||
| @ -45,9 +45,9 @@ func (e *LineDirection) Get(d *dto.LineDirectionGetReq, p *actions.DataPermissio | ||||
| 	var data models.LineDirection | ||||
|  | ||||
| 	err := e.Orm.Model(&data). | ||||
| 		Scopes( | ||||
| 			actions.Permission(data.TableName(), p), | ||||
| 		). | ||||
| 		// Scopes( | ||||
| 		// 	actions.Permission(data.TableName(), p), | ||||
| 		// ). | ||||
| 		First(model, d.GetId()).Error | ||||
| 	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { | ||||
| 		err = errors.New("查看对象不存在或无权查看") | ||||
|  | ||||
| @ -391,6 +391,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 			Type:   1, | ||||
| 			Switch: "0", | ||||
| 		} | ||||
| 		saveTemplateParams.CreateBy = req.CreateBy | ||||
| 		e.Orm.Model(&models.LineOrderTemplateLogs{}).Create(&saveTemplateParams) | ||||
| 	} | ||||
| 	if req.SaveTemplate == "2" { | ||||
| @ -426,6 +427,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		AddOrder.CreateBy = req.CreateBy | ||||
| 		AddOrder.ExchangeType = req.ExchangeType | ||||
| 		AddOrder.OrderCategory = 1 | ||||
| 		AddOrder.SignPriceType = "new" | ||||
| @ -598,6 +600,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 			ext.TotalBefore = mainParam.RemainingQuantity    //初始数量 | ||||
| 			ext.TotalAfter = calculateResp.RemainingQuantity //计算后数量 | ||||
| 			ext.ReTakeRatio = calculateResp.Ratio | ||||
| 			ext.CreateBy = req.CreateBy | ||||
| 			mainParam.LossBeginPercent = addPosition.PriceRatio | ||||
| 			mainParam.RemainingQuantity = calculateResp.RemainingQuantity | ||||
| 			mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU | ||||
| @ -637,18 +640,29 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
|  | ||||
| 			//是否有止盈止损订单 | ||||
| 			if req.Profit != "" { | ||||
| 				if strings.ToUpper(req.Site) == "BUY" { | ||||
| 					profitOrder.Site = "SELL" | ||||
| 					profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 				if req.PricePattern == "mixture" { | ||||
| 					mixturePrice := utility.StrToDecimal(req.Profit) | ||||
|  | ||||
| 					if mixturePrice.Cmp(decimal.Zero) <= 0 { | ||||
| 						return fmt.Errorf("止盈价不能小于等于0") | ||||
| 					} | ||||
|  | ||||
| 					profitOrder.Price = mixturePrice.Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 					profitOrder.Rate = "0" | ||||
| 				} else { | ||||
| 					profitOrder.Site = "BUY" | ||||
| 					profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 					if strings.ToUpper(req.Site) == "BUY" { | ||||
| 						profitOrder.Site = "SELL" | ||||
| 						profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 					} else { | ||||
| 						profitOrder.Site = "BUY" | ||||
| 						profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 					} | ||||
| 					profitOrder.Rate = req.Profit | ||||
| 				} | ||||
| 				profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) | ||||
| 				profitOrder.Pid = AddOrder.Id | ||||
| 				profitOrder.OrderType = 1 | ||||
| 				profitOrder.Status = 0 | ||||
| 				profitOrder.Rate = req.Profit | ||||
| 				profitOrder.MainId = AddOrder.Id | ||||
|  | ||||
| 				if req.ProfitNumRatio.Cmp(decimal.Zero) > 0 { | ||||
| @ -673,12 +687,23 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 			} | ||||
|  | ||||
| 			if req.ReducePriceRatio.Cmp(decimal.Zero) > 0 { | ||||
| 				if strings.ToUpper(req.Site) == "BUY" { | ||||
| 					stopOrder.Site = "SELL" | ||||
| 					stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Sub(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 				if req.PricePattern == "mixture" { | ||||
| 					if req.ReducePriceRatio.Cmp(decimal.Zero) <= 0 { | ||||
| 						return errors.New("检查价格不能小于等于0") | ||||
| 					} | ||||
|  | ||||
| 					stopOrder.Price = req.ReducePriceRatio.Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 					stopOrder.Rate = "0" | ||||
| 				} else { | ||||
| 					stopOrder.Site = "BUY" | ||||
| 					stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Add(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 					if strings.ToUpper(req.Site) == "BUY" { | ||||
| 						stopOrder.Site = "SELL" | ||||
| 						stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Sub(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 					} else { | ||||
| 						stopOrder.Site = "BUY" | ||||
| 						stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Add(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 					} | ||||
|  | ||||
| 					stopOrder.Rate = req.ReducePriceRatio.String() | ||||
| 				} | ||||
| 				stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10) | ||||
| 				stopOrder.Pid = AddOrder.Id | ||||
| @ -686,7 +711,6 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP | ||||
| 				stopOrder.OrderType = 4 | ||||
| 				stopOrder.Status = 0 | ||||
| 				stopOrder.BuyPrice = "0" | ||||
| 				stopOrder.Rate = req.ReducePriceRatio.String() | ||||
| 				stopNum := utility.StrToDecimal(AddOrder.Num).Mul(req.ReduceNumRatio.Div(decimal.NewFromInt(100)).Truncate(4)) | ||||
| 				stopOrder.Num = stopNum.Truncate(int32(tradeSet.AmountDigit)).String() | ||||
| 				stopOrder.ExpireTime = time.Now().AddDate(10, 0, 0) | ||||
| @ -1068,6 +1092,8 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p | ||||
| 			Type:   2, | ||||
| 			Switch: "0", | ||||
| 		} | ||||
|  | ||||
| 		saveTemplateParams.CreateBy = p.UserId | ||||
| 		e.Orm.Model(&models.LineOrderTemplateLogs{}).Create(&saveTemplateParams) | ||||
| 	} | ||||
|  | ||||
| @ -1149,6 +1175,7 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p | ||||
| 					req.ReduceNumRatio = batchReq.ReduceNumRatio | ||||
| 					req.ReduceStopLossRatio = batchReq.ReduceStopLossRatio | ||||
| 					req.ReduceTakeProfitRatio = batchReq.ReduceTakeProfitRatio | ||||
| 					req.CreateBy = batchReq.CreateBy | ||||
|  | ||||
| 					e.AddPreOrder(&req, p, errs, tickerSymbol) | ||||
| 				} | ||||
| @ -1162,7 +1189,7 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p | ||||
| } | ||||
|  | ||||
| // QuickAddPreOrder 模板快速下单 | ||||
| func (e *LinePreOrder) QuickAddPreOrder(quickReq *dto.QuickAddPreOrderReq, p *actions.DataPermission, errs *[]error) error { | ||||
| func (e *LinePreOrder) QuickAddPreOrder(quickReq *dto.QuickAddPreOrderReq, p *actions.DataPermission, userId int, errs *[]error) error { | ||||
| 	templateLogs := make([]models.LineOrderTemplateLogs, 0) | ||||
| 	e.Orm.Model(&models.LineOrderTemplateLogs{}).Where("id in ?", strings.Split(quickReq.Ids, ",")).Find(&templateLogs) | ||||
| 	for _, log := range templateLogs { | ||||
| @ -1188,6 +1215,13 @@ func (e *LinePreOrder) QuickAddPreOrder(quickReq *dto.QuickAddPreOrderReq, p *ac | ||||
| 		if log.Type == 2 { | ||||
| 			var batchAddPreOrder dto.LineBatchAddPreOrderReq | ||||
| 			sonic.Unmarshal([]byte(log.Params), &batchAddPreOrder) | ||||
|  | ||||
| 			if userId > 0 { | ||||
| 				batchAddPreOrder.CreateBy = userId | ||||
| 			} else { | ||||
| 				batchAddPreOrder.CreateBy = log.CreateBy | ||||
| 			} | ||||
|  | ||||
| 			e.AddBatchPreOrder(&batchAddPreOrder, p, errs) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -20,6 +20,7 @@ import ( | ||||
| 	"go-admin/common/global" | ||||
| 	"go-admin/common/helper" | ||||
| 	commonModels "go-admin/models" | ||||
| 	models2 "go-admin/models" | ||||
| 	"go-admin/pkg/utility" | ||||
| 	"go-admin/services/binanceservice" | ||||
| ) | ||||
| @ -37,7 +38,7 @@ func (e *LineSymbol) GetPage(c *dto.LineSymbolGetPageReq, p *actions.DataPermiss | ||||
| 		Scopes( | ||||
| 			cDto.MakeCondition(c.GetNeedSearch()), | ||||
| 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), | ||||
| 			actions.Permission(data.TableName(), p), | ||||
| 			// actions.Permission(data.TableName(), p), | ||||
| 		). | ||||
| 		Find(list).Limit(-1).Offset(-1). | ||||
| 		Count(count).Error | ||||
| @ -126,7 +127,7 @@ func (e *LineSymbol) ExportExcel(c *gin.Context, p *actions.DataPermission, req | ||||
| 	err := e.Orm.Model(&data). | ||||
| 		Scopes( | ||||
| 			cDto.MakeCondition(req.GetNeedSearch()), | ||||
| 			actions.Permission(data.TableName(), p), | ||||
| 			// actions.Permission(data.TableName(), p), | ||||
| 		). | ||||
| 		Find(&list).Error | ||||
|  | ||||
| @ -134,17 +135,64 @@ func (e *LineSymbol) ExportExcel(c *gin.Context, p *actions.DataPermission, req | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	exchanges := []string{} | ||||
| 	exchangeFutMap := make(map[string]models2.TradeSet) | ||||
| 	exchangeSpotMap := make(map[string]models2.TradeSet) | ||||
|  | ||||
| 	for _, v := range list { | ||||
| 		if !utility.ContainsStr(exchanges, v.ExchangeType) { | ||||
| 			key := fmt.Sprintf(global.TICKER_FUTURES, v.ExchangeType, "*") | ||||
| 			key2 := fmt.Sprintf(global.TICKER_SPOT, v.ExchangeType, "*") | ||||
| 			futs, _ := helper.DefaultRedis.GetAllKeysAndValues(key) | ||||
| 			spots, _ := helper.DefaultRedis.GetAllKeysAndValues(key2) | ||||
| 			trade := models2.TradeSet{} | ||||
|  | ||||
| 			for _, v2 := range futs { | ||||
| 				if v2 != "" { | ||||
| 					sonic.Unmarshal([]byte(v2), &trade) | ||||
|  | ||||
| 					if trade.LastPrice != "" { | ||||
| 						exchangeFutMap[v.ExchangeType+"_"+trade.Coin+trade.Currency] = trade | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			for _, v2 := range spots { | ||||
| 				if v2 != "" { | ||||
| 					sonic.Unmarshal([]byte(v2), &trade) | ||||
|  | ||||
| 					if trade.LastPrice != "" { | ||||
| 						exchangeSpotMap[v.ExchangeType+"_"+trade.Coin+trade.Currency] = trade | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			exchanges = append(exchanges, v.ExchangeType) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, v := range list { | ||||
| 		item := dto.LineSymbolExportResp{ | ||||
| 			Symbol:   v.Symbol, | ||||
| 			Coin:     v.BaseAsset, | ||||
| 			Currency: v.QuoteAsset, | ||||
| 			ExchangeType: v.ExchangeType, | ||||
| 			Symbol:       v.Symbol, | ||||
| 			Coin:         v.BaseAsset, | ||||
| 			Currency:     v.QuoteAsset, | ||||
| 		} | ||||
|  | ||||
| 		if v.Type == "1" { | ||||
| 			item.SymbolType = "现货" | ||||
| 			if v, ok := exchangeSpotMap[v.ExchangeType+"_"+v.Symbol]; ok { | ||||
| 				if v.LastPrice != "" { | ||||
| 					item.LastPrice = v.LastPrice | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| 			item.SymbolType = "合约" | ||||
| 			if v, ok := exchangeFutMap[v.ExchangeType+"_"+v.Symbol]; ok { | ||||
| 				if v.LastPrice != "" { | ||||
| 					item.LastPrice = v.LastPrice | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		datas = append(datas, item) | ||||
|  | ||||
| @ -51,7 +51,7 @@ func (e *LineUser) GetPage(c *dto.LineUserGetPageReq, p *actions.DataPermission, | ||||
| 		Scopes( | ||||
| 			cDto.MakeCondition(c.GetNeedSearch()), | ||||
| 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), | ||||
| 			actions.Permission(data.TableName(), p), | ||||
| 			// actions.Permission(data.TableName(), p), | ||||
| 		). | ||||
| 		Find(list).Limit(-1).Offset(-1). | ||||
| 		Count(count).Error | ||||
| @ -225,15 +225,16 @@ func (e *LineUser) AddApiKey(userId int, req *dto.AddApiKeyReq) int { | ||||
| 	} | ||||
|  | ||||
| 	err = e.Orm.Model(&models.LineApiUser{}).Create(&models.LineApiUser{ | ||||
| 		UserId:      int64(userId), | ||||
| 		ApiName:     req.ApiName, | ||||
| 		ApiKey:      req.ApiKey, | ||||
| 		ApiSecret:   req.ApiSecret, | ||||
| 		Affiliation: 3, | ||||
| 		AdminShow:   0, | ||||
| 		Site:        "3", | ||||
| 		Subordinate: "0", | ||||
| 		OpenStatus:  0, | ||||
| 		ExchangeType: req.ExchangeType, | ||||
| 		UserId:       int64(userId), | ||||
| 		ApiName:      req.ApiName, | ||||
| 		ApiKey:       req.ApiKey, | ||||
| 		ApiSecret:    req.ApiSecret, | ||||
| 		Affiliation:  3, | ||||
| 		AdminShow:    0, | ||||
| 		Site:         "3", | ||||
| 		Subordinate:  "0", | ||||
| 		OpenStatus:   0, | ||||
| 	}).Error | ||||
|  | ||||
| 	if err != nil { | ||||
| @ -743,6 +744,8 @@ func (e *LineUser) OpenStatus(req *dto.OpenStatusReq, userId int) int { | ||||
| 		propperty := dto.LineUserPropertyResp{} | ||||
| 		e.GetProperty(userId, &propperty) | ||||
|  | ||||
| 		logger.Infof("合约可用资产:%v", propperty.FuturesFreeAmount) | ||||
| 		logger.Infof("现货可用资产:%v", propperty.SpotFreeAmount) | ||||
| 		//可用资产不足 | ||||
| 		if propperty.FuturesFreeAmount.Cmp(userSet.MinOrderAmount) < 0 && propperty.SpotFreeAmount.Cmp(userSet.MinOrderAmount) < 0 { | ||||
| 			return statuscode.PropertyInsufficient | ||||
|  | ||||
| @ -142,7 +142,7 @@ func (t AutoPlaceOrder) Exec(arg interface{}) error { | ||||
| 		preOrderService.Orm = db | ||||
| 		errs := make([]error, 0) | ||||
| 		errStr := make([]string, 0) | ||||
| 		err := preOrderService.QuickAddPreOrder(&req, nil, &errs) | ||||
| 		err := preOrderService.QuickAddPreOrder(&req, nil, 0, &errs) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
							
								
								
									
										6
									
								
								common/const/rediskey/control.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								common/const/rediskey/control.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| package rediskey | ||||
|  | ||||
| const ( | ||||
| 	//用户总资产 {exchange_type,user_id} | ||||
| 	User_Total_Asset = "u_total_asset:%s:%v" | ||||
| ) | ||||
| @ -8,6 +8,7 @@ import ( | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"golang.org/x/net/proxy" | ||||
| ) | ||||
| @ -20,7 +21,9 @@ import ( | ||||
| */ | ||||
| func CreateHtppProxy(proxyType, proxyAddr string, client *http.Client) error { | ||||
| 	// Set up proxy based on type (HTTP, HTTPS, SOCKS5) | ||||
| 	transport := &http.Transport{} | ||||
| 	transport := &http.Transport{ | ||||
| 		TLSHandshakeTimeout: 10 * time.Second, | ||||
| 	} | ||||
| 	if proxyAddr != "" { | ||||
| 		if !strings.HasPrefix(proxyAddr, "http://") && !strings.HasPrefix(proxyAddr, "https://") && !strings.HasPrefix(proxyAddr, "socks5://") { | ||||
| 			proxyAddr = proxyType + "://" + proxyAddr | ||||
|  | ||||
| @ -1,18 +1,13 @@ | ||||
| package authservice | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go-admin/common/const/rediskey" | ||||
| 	"go-admin/common/helper" | ||||
| 	statuscode "go-admin/common/status_code" | ||||
| 	ext "go-admin/config" | ||||
| 	"go-admin/pkg/cryptohelper/inttostring" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/bytedance/sonic" | ||||
| 	log "github.com/go-admin-team/go-admin-core/logger" | ||||
| 	"go.uber.org/zap" | ||||
| ) | ||||
| @ -496,60 +491,8 @@ func SendGoToneSms(phone, area string, smsType int) int { | ||||
| 	} | ||||
| 	//ext.ExtConfig.GoToneSmsConfig | ||||
| 	// SmsRequest 用于构建发送短信请求的结构体 | ||||
| 	type SmsRequest struct { | ||||
| 		Recipient string `json:"recipient"` // 收件人电话号码 | ||||
| 		Message   string `json:"message"`   // 短信内容 | ||||
| 		SenderId  string `json:"sender_id"` // 发送者名称 | ||||
| 		Type      string `json:"type"` | ||||
| 	} | ||||
| 	// 创建请求数据 | ||||
| 	smsRequest := SmsRequest{ | ||||
| 		Recipient: "+" + area + phone, | ||||
| 		SenderId:  ext.ExtConfig.GoToneSmsConfig.SenderId, | ||||
| 		Message:   fmt.Sprintf("欢迎使用 GoTone SMS,高速稳定地发送短信至中国大陆及全球用户,体验验证码:%s。如非本人操作请忽略此信息", smsString), | ||||
| 		Type:      "plain", | ||||
| 	} | ||||
| 	// 将请求数据编码为 JSON | ||||
| 	requestBody, err := sonic.Marshal(smsRequest) | ||||
| 	if err != nil { | ||||
| 		log.Error("GoToneSms requestBody Error:", err) | ||||
| 		return statuscode.ServerError | ||||
| 	} | ||||
| 	// 创建 HTTP 请求 | ||||
| 	req, err := http.NewRequest("POST", ext.ExtConfig.GoToneSmsConfig.APIEndpoint, bytes.NewBuffer(requestBody)) | ||||
| 	if err != nil { | ||||
| 		log.Error("GoToneSms http.NewRequest Error:", err) | ||||
| 		return statuscode.ServerError | ||||
| 	} | ||||
| 	// 设置请求头 | ||||
| 	req.Header.Set("Content-Type", "application/json") | ||||
| 	req.Header.Set("Authorization", "Bearer "+ext.ExtConfig.GoToneSmsConfig.Authorization) // 使用 API 密钥进行身份验证 | ||||
| 	// todo 短信cangchu | ||||
|  | ||||
| 	// 创建 HTTP 客户端并发送请求 | ||||
| 	client := &http.Client{ | ||||
| 		Timeout: 10 * time.Second, // 设置请求超时时间 | ||||
| 	} | ||||
| 	resp, err := client.Do(req) | ||||
| 	fmt.Println("resp:", resp) | ||||
| 	if err != nil { | ||||
| 		log.Error("GoToneSms do NewRequest Error:", err) | ||||
| 		return statuscode.CaptchaFailInSend | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	// 检查响应状态 | ||||
| 	if resp.StatusCode != http.StatusOK { | ||||
| 		log.Error("GoToneSms do NewRequest Error:", err) | ||||
| 		return statuscode.CaptchaFailInSend | ||||
| 	} | ||||
| 	// 读取响应体 | ||||
| 	body, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		log.Error("读取响应体失败:", err) | ||||
| 		fmt.Printf("响应体: %s", string(body)) | ||||
| 		return statuscode.CaptchaFailInSend | ||||
| 		//return fmt.Errorf("读取响应体失败: %v", err) | ||||
| 	} | ||||
| 	// 打印响应内容(调试用) | ||||
| 	//记录短信发送操作 | ||||
| 	helper.DefaultRedis.SetStringExpire(registerKey, "1", time.Second*60) | ||||
|  | ||||
| @ -16,11 +16,11 @@ type Extend struct { | ||||
| 	EmailConfig     EmailConfig     `mapstructure:"emailConfig"` | ||||
| 	BinanceSet      BinanceConfig   `mapstructure:"binanceSet"` //binance配置 | ||||
| 	Domain          string          //网站域名 | ||||
| 	GoToneSmsConfig GoToneSmsConfig `mapstructure:"GoToneSmsConfig"` | ||||
| 	UDunConfig      UDunConfig      `mapstructure:"UDunConfig"` | ||||
| 	ProxyUrl        string          //代理地址 | ||||
| 	CoinGate        CoinGateConfig  `mapstructure:"coingate"` //coingate钱包 | ||||
|  | ||||
| 	GoToneSmsConfig GoToneSmsConfig `mapstructure:"GoToneSmsConfig"` | ||||
| 	InnoPaas        InnoPaasConfig  `mapstructure:"innoPaas"` //创蓝短信 | ||||
| } | ||||
|  | ||||
| type CoinGateConfig struct { | ||||
| @ -70,6 +70,12 @@ type GoToneSmsConfig struct { | ||||
| 	Authorization string `json:"authorization"` | ||||
| } | ||||
|  | ||||
| type InnoPaasConfig struct { | ||||
| 	Url      string `json:"url"` | ||||
| 	ApiKey   string `json:"apiKey"` | ||||
| 	Password string `json:"password"` | ||||
| } | ||||
|  | ||||
| type UDunConfig struct { | ||||
| 	UDunUrl        string `json:"UDunUrl"` | ||||
| 	UDunMerchantID string `json:"UDunMerchantID"` | ||||
|  | ||||
| @ -11,7 +11,7 @@ settings: | ||||
|     readtimeout: 1 | ||||
|     writertimeout: 2 | ||||
|     # 数据权限功能开关 | ||||
|     enabledp: false | ||||
|     enabledp: true | ||||
|   logger: | ||||
|     # 日志存放路径 | ||||
|     path: temp/logs | ||||
| @ -82,6 +82,10 @@ settings: | ||||
|       sender_id: "GoTone SMS" | ||||
|       api_endpoint: "https://gosms.one/api/v3/sms/send" | ||||
|       authorization: "CVZgh3iIAQpJuvaakQmxOo9q2uOb7Veqs7ls5KIX263d87ee" | ||||
|     InnoPaas: | ||||
|       url: "http://intapi.sgap.253.com" | ||||
|       apiKey: "OI1706483" | ||||
|       password: "N4R84hhVvP6505" | ||||
|  | ||||
|     #UDun 配置 | ||||
|     UDunConfig: | ||||
|  | ||||
| @ -739,7 +739,7 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd | ||||
| 	for _, order := range orders { | ||||
| 		order.Num = num.String() | ||||
|  | ||||
| 		if fist && order.OrderCategory == 1 && order.OrderType == 1 && orderExt.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && orderExt.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 { | ||||
| 		if fist && (order.OrderCategory == 3 || order.OrderCategory == 1) && order.OrderType == 1 && orderExt.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && orderExt.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 { | ||||
| 			//主单第一次且止盈数量不是100% 止盈数量 | ||||
| 			order.Num = num.Mul(orderExt.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)).String() | ||||
| 		} | ||||
| @ -761,7 +761,7 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd | ||||
| 				order.Rate = percentag.String() | ||||
| 				percentag = percentag.Div(decimal.NewFromInt(100)) | ||||
| 				order.Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
| 			} else if orderExt.Id > 0 { | ||||
| 			} else if !fist && orderExt.TpTpPriceRatio.Cmp(decimal.Zero) > 0 { | ||||
| 				percentag := orderExt.TpTpPriceRatio | ||||
| 				order.Rate = percentag.String() | ||||
| 				order.Price = price.Mul(decimal.NewFromInt(1).Add(percentag.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() | ||||
|  | ||||
							
								
								
									
										76
									
								
								services/smsservice/gotone_service.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								services/smsservice/gotone_service.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | ||||
| package smsservice | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	statuscode "go-admin/common/status_code" | ||||
| 	"go-admin/config" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/bytedance/sonic" | ||||
| 	"github.com/go-admin-team/go-admin-core/logger" | ||||
| ) | ||||
|  | ||||
| type GotoneService struct { | ||||
| } | ||||
|  | ||||
| func (s *GotoneService) SendSMS(area, phonenumber string, content string) int { | ||||
| 	type SmsRequest struct { | ||||
| 		Recipient string `json:"recipient"` // 收件人电话号码 | ||||
| 		Message   string `json:"message"`   // 短信内容 | ||||
| 		SenderId  string `json:"sender_id"` // 发送者名称 | ||||
| 		Type      string `json:"type"` | ||||
| 	} | ||||
| 	// 创建请求数据 | ||||
| 	smsRequest := SmsRequest{ | ||||
| 		Recipient: "+" + area + phonenumber, | ||||
| 		SenderId:  config.ExtConfig.GoToneSmsConfig.SenderId, | ||||
| 		Message:   fmt.Sprintf("欢迎使用 GoTone SMS,高速稳定地发送短信至中国大陆及全球用户,体验验证码:%s。如非本人操作请忽略此信息", content), | ||||
| 		Type:      "plain", | ||||
| 	} | ||||
| 	// 将请求数据编码为 JSON | ||||
| 	requestBody, err := sonic.Marshal(smsRequest) | ||||
| 	if err != nil { | ||||
| 		logger.Error("GoToneSms requestBody Error:", err) | ||||
| 		return statuscode.ServerError | ||||
| 	} | ||||
| 	// 创建 HTTP 请求 | ||||
| 	req, err := http.NewRequest("POST", config.ExtConfig.GoToneSmsConfig.APIEndpoint, bytes.NewBuffer(requestBody)) | ||||
| 	if err != nil { | ||||
| 		logger.Error("GoToneSms http.NewRequest Error:", err) | ||||
| 		return statuscode.ServerError | ||||
| 	} | ||||
| 	// 设置请求头 | ||||
| 	req.Header.Set("Content-Type", "application/json") | ||||
| 	req.Header.Set("Authorization", "Bearer "+config.ExtConfig.GoToneSmsConfig.Authorization) // 使用 API 密钥进行身份验证 | ||||
|  | ||||
| 	// 创建 HTTP 客户端并发送请求 | ||||
| 	client := &http.Client{ | ||||
| 		Timeout: 10 * time.Second, // 设置请求超时时间 | ||||
| 	} | ||||
| 	resp, err := client.Do(req) | ||||
| 	fmt.Println("resp:", resp) | ||||
| 	if err != nil { | ||||
| 		logger.Error("GoToneSms do NewRequest Error:", err) | ||||
| 		return statuscode.CaptchaFailInSend | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	// 检查响应状态 | ||||
| 	if resp.StatusCode != http.StatusOK { | ||||
| 		logger.Error("GoToneSms do NewRequest Error:", err) | ||||
| 		return statuscode.CaptchaFailInSend | ||||
| 	} | ||||
| 	// 读取响应体 | ||||
| 	body, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		logger.Error("读取响应体失败:", err) | ||||
| 		fmt.Printf("响应体: %s", string(body)) | ||||
| 		return statuscode.CaptchaFailInSend | ||||
| 		//return fmt.Errorf("读取响应体失败: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	return statuscode.OK | ||||
| } | ||||
							
								
								
									
										44
									
								
								services/smsservice/innopass_service.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								services/smsservice/innopass_service.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| package smsservice | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	statuscode "go-admin/common/status_code" | ||||
| 	"go-admin/config" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/bytedance/sonic" | ||||
| 	"github.com/go-admin-team/go-admin-core/logger" | ||||
| ) | ||||
|  | ||||
| type InnopaasService struct { | ||||
| } | ||||
|  | ||||
| func (i *InnopaasService) SendSMS(area, phoneNumber string, message string) int { | ||||
| 	// Implement the logic to send SMS using Innopass API | ||||
| 	params := map[string]string{ | ||||
| 		"account":  config.ExtConfig.InnoPaas.ApiKey, | ||||
| 		"password": config.ExtConfig.InnoPaas.Password, | ||||
| 		"mobile":   area + phoneNumber, | ||||
| 		"msg":      message, | ||||
| 	} | ||||
| 	payload, _ := sonic.MarshalString(params) // strings.NewReader("{\"account\":\"I7145744\",\"password\":\"password\",\"mobile\":\"0012012074149,0012012074142\",\"msg\":\"Your verification code is 8888\"}") | ||||
|  | ||||
| 	req, _ := http.NewRequest("POST", config.ExtConfig.InnoPaas.Url, strings.NewReader(payload)) | ||||
|  | ||||
| 	req.Header.Add("accept", "application/json") | ||||
| 	req.Header.Add("content-type", "application/json") | ||||
|  | ||||
| 	res, _ := http.DefaultClient.Do(req) | ||||
|  | ||||
| 	defer res.Body.Close() | ||||
| 	body, err := io.ReadAll(res.Body) | ||||
| 	if err != nil { | ||||
| 		logger.Error("读取响应体失败:", err) | ||||
| 		fmt.Printf("响应体: %s", string(body)) | ||||
| 		return statuscode.CaptchaFailInSend | ||||
| 		//return fmt.Errorf("读取响应体失败: %v", err) | ||||
| 	} | ||||
| 	return statuscode.OK | ||||
| } | ||||
							
								
								
									
										13
									
								
								services/smsservice/sms_service.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								services/smsservice/sms_service.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| package smsservice | ||||
|  | ||||
| type SMSService interface { | ||||
| 	// SendSMS 发送短信 | ||||
| 	// area 区号 | ||||
| 	// phoneNumber 手机号 | ||||
| 	// message 短信内容 | ||||
| 	SendSMS(area, phoneNumber string, message string) int | ||||
| } | ||||
|  | ||||
| func NewSMSService() SMSService { | ||||
| 	return &GotoneService{} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user