diff --git a/app/admin/apis/line_api_group.go b/app/admin/apis/line_api_group.go
index 23cc4e9..3951da2 100644
--- a/app/admin/apis/line_api_group.go
+++ b/app/admin/apis/line_api_group.go
@@ -4,6 +4,7 @@ import (
"fmt"
"github.com/gin-gonic/gin"
+ "github.com/gin-gonic/gin/binding"
"github.com/go-admin-team/go-admin-core/sdk/api"
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
_ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
@@ -33,7 +34,7 @@ func (e LineApiGroup) GetPage(c *gin.Context) {
s := service.LineApiGroup{}
err := e.MakeContext(c).
MakeOrm().
- Bind(&req).
+ Bind(&req, binding.Form, binding.Query).
MakeService(&s.Service).
Errors
if err != nil {
diff --git a/app/admin/apis/line_api_user.go b/app/admin/apis/line_api_user.go
index c0a7f9c..4339c26 100644
--- a/app/admin/apis/line_api_user.go
+++ b/app/admin/apis/line_api_user.go
@@ -33,7 +33,7 @@ func (e LineApiUser) GetPage(c *gin.Context) {
s := service.LineApiUser{}
err := e.MakeContext(c).
MakeOrm().
- Bind(&req, binding.Form, nil).
+ Bind(&req, binding.Form, binding.Query).
MakeService(&s.Service).
Errors
if err != nil {
diff --git a/app/admin/apis/line_coinnetwork.go b/app/admin/apis/line_coinnetwork.go
index 1a85256..c004d1b 100644
--- a/app/admin/apis/line_coinnetwork.go
+++ b/app/admin/apis/line_coinnetwork.go
@@ -1,9 +1,10 @@
package apis
import (
- "fmt"
+ "fmt"
"github.com/gin-gonic/gin"
+ "github.com/gin-gonic/gin/binding"
"github.com/go-admin-team/go-admin-core/sdk/api"
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
_ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
@@ -28,18 +29,18 @@ type LineCoinnetwork struct {
// @Router /api/v1/line-coinnetwork [get]
// @Security Bearer
func (e LineCoinnetwork) GetPage(c *gin.Context) {
- req := dto.LineCoinnetworkGetPageReq{}
- s := service.LineCoinnetwork{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.LineCoinnetworkGetPageReq{}
+ s := service.LineCoinnetwork{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req, binding.Form, binding.Query).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
p := actions.GetPermissionFromContext(c)
list := make([]models.LineCoinnetwork, 0)
@@ -48,7 +49,7 @@ func (e LineCoinnetwork) GetPage(c *gin.Context) {
err = s.GetPage(&req, p, &list, &count)
if err != nil {
e.Error(500, err, fmt.Sprintf("获取【币种网络】失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
@@ -65,7 +66,7 @@ func (e LineCoinnetwork) GetPage(c *gin.Context) {
func (e LineCoinnetwork) Get(c *gin.Context) {
req := dto.LineCoinnetworkGetReq{}
s := service.LineCoinnetwork{}
- err := e.MakeContext(c).
+ err := e.MakeContext(c).
MakeOrm().
Bind(&req).
MakeService(&s.Service).
@@ -81,10 +82,10 @@ func (e LineCoinnetwork) Get(c *gin.Context) {
err = s.Get(&req, p, &object)
if err != nil {
e.Error(500, err, fmt.Sprintf("获取【币种网络】失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( object, "查询成功")
+ e.OK(object, "查询成功")
}
// Insert 创建【币种网络】
@@ -98,25 +99,25 @@ func (e LineCoinnetwork) Get(c *gin.Context) {
// @Router /api/v1/line-coinnetwork [post]
// @Security Bearer
func (e LineCoinnetwork) Insert(c *gin.Context) {
- req := dto.LineCoinnetworkInsertReq{}
- s := service.LineCoinnetwork{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.LineCoinnetworkInsertReq{}
+ s := service.LineCoinnetwork{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
// 设置创建人
req.SetCreateBy(user.GetUserId(c))
err = s.Insert(&req)
if err != nil {
e.Error(500, err, fmt.Sprintf("创建【币种网络】失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
e.OK(req.GetId(), "创建成功")
@@ -134,27 +135,27 @@ func (e LineCoinnetwork) Insert(c *gin.Context) {
// @Router /api/v1/line-coinnetwork/{id} [put]
// @Security Bearer
func (e LineCoinnetwork) Update(c *gin.Context) {
- req := dto.LineCoinnetworkUpdateReq{}
- s := service.LineCoinnetwork{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.LineCoinnetworkUpdateReq{}
+ s := service.LineCoinnetwork{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
req.SetUpdateBy(user.GetUserId(c))
p := actions.GetPermissionFromContext(c)
err = s.Update(&req, p)
if err != nil {
e.Error(500, err, fmt.Sprintf("修改【币种网络】失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( req.GetId(), "修改成功")
+ e.OK(req.GetId(), "修改成功")
}
// Delete 删除【币种网络】
@@ -166,18 +167,18 @@ func (e LineCoinnetwork) Update(c *gin.Context) {
// @Router /api/v1/line-coinnetwork [delete]
// @Security Bearer
func (e LineCoinnetwork) Delete(c *gin.Context) {
- s := service.LineCoinnetwork{}
- req := dto.LineCoinnetworkDeleteReq{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ s := service.LineCoinnetwork{}
+ req := dto.LineCoinnetworkDeleteReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
// req.SetUpdateBy(user.GetUserId(c))
p := actions.GetPermissionFromContext(c)
@@ -185,7 +186,7 @@ func (e LineCoinnetwork) Delete(c *gin.Context) {
err = s.Remove(&req, p)
if err != nil {
e.Error(500, err, fmt.Sprintf("删除【币种网络】失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( req.GetId(), "删除成功")
+ e.OK(req.GetId(), "删除成功")
}
diff --git a/app/admin/apis/line_pre_order.go b/app/admin/apis/line_pre_order.go
index 145687a..1f18111 100644
--- a/app/admin/apis/line_pre_order.go
+++ b/app/admin/apis/line_pre_order.go
@@ -113,11 +113,7 @@ func (e LinePreOrder) GetChildOrderList(c *gin.Context) {
}
p := actions.GetPermissionFromContext(c)
list := make([]models.LinePreOrder, 0)
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+
err = s.GetChildList(&req, p, &list)
if err != nil {
e.Error(500, err, fmt.Sprintf("获取子订单信息失败,\r\n失败信息 %s", err.Error()))
@@ -310,6 +306,35 @@ func (e LinePreOrder) AddPreOrder(c *gin.Context) {
e.OK(nil, "操作成功")
}
+// // 手动加仓
+// func (e LinePreOrder) AddPosition(c *gin.Context) {
+// s := service.LinePreOrder{}
+// req := dto.LinePreOrderAddPositionReq{}
+// err := e.MakeContext(c).
+// MakeOrm().
+// Bind(&req).
+// MakeService(&s.Service).
+// Errors
+// if err != nil {
+// e.Logger.Error(err)
+// e.Error(500, err, err.Error())
+// return
+// }
+
+// if err := req.Valid(); err != nil {
+// e.Error(500, err, err.Error())
+// return
+// }
+
+// err = s.AddPosition(&req)
+
+// if err != nil {
+// e.Error(500, nil, err.Error())
+// return
+// }
+// e.OK(nil, "操作成功")
+// }
+
// BatchAddOrder 批量添加
func (e LinePreOrder) BatchAddOrder(c *gin.Context) {
s := service.LinePreOrder{}
@@ -629,8 +654,7 @@ func (e LinePreOrder) CalculateBreakEevenRatio(c *gin.Context) {
return
}
- // data := dto.CalculateBreakEvenRatioResp{}
- _, err = s.GenerateOrder(&req)
+ err = s.GenerateOrder(&req)
if err != nil {
e.Error(500, err, err.Error())
return
diff --git a/app/admin/apis/line_symbol_black.go b/app/admin/apis/line_symbol_black.go
index 6c1c95a..9659f94 100644
--- a/app/admin/apis/line_symbol_black.go
+++ b/app/admin/apis/line_symbol_black.go
@@ -1,9 +1,10 @@
package apis
import (
- "fmt"
+ "fmt"
"github.com/gin-gonic/gin"
+ "github.com/gin-gonic/gin/binding"
"github.com/go-admin-team/go-admin-core/sdk/api"
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
_ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
@@ -30,18 +31,18 @@ type LineSymbolBlack struct {
// @Router /api/v1/line-symbol-black [get]
// @Security Bearer
func (e LineSymbolBlack) GetPage(c *gin.Context) {
- req := dto.LineSymbolBlackGetPageReq{}
- s := service.LineSymbolBlack{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.LineSymbolBlackGetPageReq{}
+ s := service.LineSymbolBlack{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req, binding.Form, binding.Query).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
p := actions.GetPermissionFromContext(c)
list := make([]models.LineSymbolBlack, 0)
@@ -50,7 +51,7 @@ func (e LineSymbolBlack) GetPage(c *gin.Context) {
err = s.GetPage(&req, p, &list, &count)
if err != nil {
e.Error(500, err, fmt.Sprintf("获取交易对黑名单失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
@@ -67,7 +68,7 @@ func (e LineSymbolBlack) GetPage(c *gin.Context) {
func (e LineSymbolBlack) Get(c *gin.Context) {
req := dto.LineSymbolBlackGetReq{}
s := service.LineSymbolBlack{}
- err := e.MakeContext(c).
+ err := e.MakeContext(c).
MakeOrm().
Bind(&req).
MakeService(&s.Service).
@@ -83,10 +84,10 @@ func (e LineSymbolBlack) Get(c *gin.Context) {
err = s.Get(&req, p, &object)
if err != nil {
e.Error(500, err, fmt.Sprintf("获取交易对黑名单失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( object, "查询成功")
+ e.OK(object, "查询成功")
}
// Insert 创建交易对黑名单
@@ -100,25 +101,25 @@ func (e LineSymbolBlack) Get(c *gin.Context) {
// @Router /api/v1/line-symbol-black [post]
// @Security Bearer
func (e LineSymbolBlack) Insert(c *gin.Context) {
- req := dto.LineSymbolBlackInsertReq{}
- s := service.LineSymbolBlack{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.LineSymbolBlackInsertReq{}
+ s := service.LineSymbolBlack{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
// 设置创建人
req.SetCreateBy(user.GetUserId(c))
err = s.Insert(&req)
if err != nil {
e.Error(500, err, fmt.Sprintf("创建交易对黑名单失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
e.OK(req.GetId(), "创建成功")
@@ -136,27 +137,27 @@ func (e LineSymbolBlack) Insert(c *gin.Context) {
// @Router /api/v1/line-symbol-black/{id} [put]
// @Security Bearer
func (e LineSymbolBlack) Update(c *gin.Context) {
- req := dto.LineSymbolBlackUpdateReq{}
- s := service.LineSymbolBlack{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.LineSymbolBlackUpdateReq{}
+ s := service.LineSymbolBlack{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
req.SetUpdateBy(user.GetUserId(c))
p := actions.GetPermissionFromContext(c)
err = s.Update(&req, p)
if err != nil {
e.Error(500, err, fmt.Sprintf("修改交易对黑名单失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( req.GetId(), "修改成功")
+ e.OK(req.GetId(), "修改成功")
}
// Delete 删除交易对黑名单
@@ -168,18 +169,18 @@ func (e LineSymbolBlack) Update(c *gin.Context) {
// @Router /api/v1/line-symbol-black [delete]
// @Security Bearer
func (e LineSymbolBlack) Delete(c *gin.Context) {
- s := service.LineSymbolBlack{}
- req := dto.LineSymbolBlackDeleteReq{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ s := service.LineSymbolBlack{}
+ req := dto.LineSymbolBlackDeleteReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
// req.SetUpdateBy(user.GetUserId(c))
p := actions.GetPermissionFromContext(c)
@@ -187,7 +188,35 @@ func (e LineSymbolBlack) Delete(c *gin.Context) {
err = s.Remove(&req, p)
if err != nil {
e.Error(500, err, fmt.Sprintf("删除交易对黑名单失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( req.GetId(), "删除成功")
+ e.OK(req.GetId(), "删除成功")
+}
+
+// 重置交易对
+func (e LineSymbolBlack) RelodSymbol(c *gin.Context) {
+ s := service.LineSymbolBlack{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ err = s.ReloadSymbol("1")
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("重置现货交易对失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+
+ err = s.ReloadSymbol("2")
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("重置合约交易对失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+
+ e.OK(nil, "重置成功")
}
diff --git a/app/admin/apis/line_user.go b/app/admin/apis/line_user.go
index bdeef5d..09bd5a7 100644
--- a/app/admin/apis/line_user.go
+++ b/app/admin/apis/line_user.go
@@ -1,9 +1,10 @@
package apis
import (
- "fmt"
+ "fmt"
"github.com/gin-gonic/gin"
+ "github.com/gin-gonic/gin/binding"
"github.com/go-admin-team/go-admin-core/sdk/api"
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
_ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
@@ -12,6 +13,7 @@ import (
"go-admin/app/admin/service"
"go-admin/app/admin/service/dto"
"go-admin/common/actions"
+ statuscode "go-admin/common/status_code"
)
type LineUser struct {
@@ -28,18 +30,18 @@ type LineUser struct {
// @Router /api/v1/line-user [get]
// @Security Bearer
func (e LineUser) GetPage(c *gin.Context) {
- req := dto.LineUserGetPageReq{}
- s := service.LineUser{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.LineUserGetPageReq{}
+ s := service.LineUser{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req, binding.Form, binding.Query).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
p := actions.GetPermissionFromContext(c)
list := make([]models.LineUser, 0)
@@ -48,7 +50,7 @@ func (e LineUser) GetPage(c *gin.Context) {
err = s.GetPage(&req, p, &list, &count)
if err != nil {
e.Error(500, err, fmt.Sprintf("获取会员表失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
@@ -65,7 +67,7 @@ func (e LineUser) GetPage(c *gin.Context) {
func (e LineUser) Get(c *gin.Context) {
req := dto.LineUserGetReq{}
s := service.LineUser{}
- err := e.MakeContext(c).
+ err := e.MakeContext(c).
MakeOrm().
Bind(&req).
MakeService(&s.Service).
@@ -81,10 +83,10 @@ func (e LineUser) Get(c *gin.Context) {
err = s.Get(&req, p, &object)
if err != nil {
e.Error(500, err, fmt.Sprintf("获取会员表失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( object, "查询成功")
+ e.OK(object, "查询成功")
}
// Insert 创建会员表
@@ -98,25 +100,25 @@ func (e LineUser) Get(c *gin.Context) {
// @Router /api/v1/line-user [post]
// @Security Bearer
func (e LineUser) Insert(c *gin.Context) {
- req := dto.LineUserInsertReq{}
- s := service.LineUser{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.LineUserInsertReq{}
+ s := service.LineUser{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
// 设置创建人
req.SetCreateBy(user.GetUserId(c))
err = s.Insert(&req)
if err != nil {
e.Error(500, err, fmt.Sprintf("创建会员表失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
e.OK(req.GetId(), "创建成功")
@@ -134,27 +136,27 @@ func (e LineUser) Insert(c *gin.Context) {
// @Router /api/v1/line-user/{id} [put]
// @Security Bearer
func (e LineUser) Update(c *gin.Context) {
- req := dto.LineUserUpdateReq{}
- s := service.LineUser{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.LineUserUpdateReq{}
+ s := service.LineUser{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
req.SetUpdateBy(user.GetUserId(c))
p := actions.GetPermissionFromContext(c)
err = s.Update(&req, p)
if err != nil {
e.Error(500, err, fmt.Sprintf("修改会员表失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( req.GetId(), "修改成功")
+ e.OK(req.GetId(), "修改成功")
}
// Delete 删除会员表
@@ -166,18 +168,18 @@ func (e LineUser) Update(c *gin.Context) {
// @Router /api/v1/line-user [delete]
// @Security Bearer
func (e LineUser) Delete(c *gin.Context) {
- s := service.LineUser{}
- req := dto.LineUserDeleteReq{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ s := service.LineUser{}
+ req := dto.LineUserDeleteReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
// req.SetUpdateBy(user.GetUserId(c))
p := actions.GetPermissionFromContext(c)
@@ -185,7 +187,38 @@ func (e LineUser) Delete(c *gin.Context) {
err = s.Remove(&req, p)
if err != nil {
e.Error(500, err, fmt.Sprintf("删除会员表失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( req.GetId(), "删除成功")
+ e.OK(req.GetId(), "删除成功")
+}
+
+// 重新获取资产
+func (e LineUser) ReloadProperty(c *gin.Context) {
+ s := service.LineUser{}
+ req := dto.LineUserReloadPropertyReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ data := dto.LineUserPropertyResp{}
+ code := s.GetProperty(req.UserId, &data)
+
+ if code != statuscode.OK {
+ if code == statuscode.UserApiUserNotBind {
+ e.Error(500, nil, "用户未绑定api")
+ } else {
+ e.Error(500, nil, "获取失败")
+ }
+
+ return
+ }
+
+ e.OK(nil, "操作成功")
}
diff --git a/app/admin/apis/line_user_setting.go b/app/admin/apis/line_user_setting.go
new file mode 100644
index 0000000..d239aa6
--- /dev/null
+++ b/app/admin/apis/line_user_setting.go
@@ -0,0 +1,191 @@
+package apis
+
+import (
+ "fmt"
+
+ "github.com/gin-gonic/gin"
+ "github.com/go-admin-team/go-admin-core/sdk/api"
+ "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
+ _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
+
+ "go-admin/app/admin/models"
+ "go-admin/app/admin/service"
+ "go-admin/app/admin/service/dto"
+ "go-admin/common/actions"
+)
+
+type LineUserSetting struct {
+ api.Api
+}
+
+// GetPage 获取用户资产、配置表列表
+// @Summary 获取用户资产、配置表列表
+// @Description 获取用户资产、配置表列表
+// @Tags 用户资产、配置表
+// @Param pageSize query int false "页条数"
+// @Param pageIndex query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]models.LineUserSetting}} "{"code": 200, "data": [...]}"
+// @Router /api/v1/line-user-setting [get]
+// @Security Bearer
+func (e LineUserSetting) GetPage(c *gin.Context) {
+ req := dto.LineUserSettingGetPageReq{}
+ s := service.LineUserSetting{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ p := actions.GetPermissionFromContext(c)
+ list := make([]models.LineUserSetting, 0)
+ var count int64
+
+ err = s.GetPage(&req, p, &list, &count)
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("获取用户资产、配置表失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+
+ e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// Get 获取用户资产、配置表
+// @Summary 获取用户资产、配置表
+// @Description 获取用户资产、配置表
+// @Tags 用户资产、配置表
+// @Param id path int false "id"
+// @Success 200 {object} response.Response{data=models.LineUserSetting} "{"code": 200, "data": [...]}"
+// @Router /api/v1/line-user-setting/{id} [get]
+// @Security Bearer
+func (e LineUserSetting) Get(c *gin.Context) {
+ req := dto.LineUserSettingGetReq{}
+ s := service.LineUserSetting{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+ var object models.LineUserSetting
+
+ p := actions.GetPermissionFromContext(c)
+ err = s.Get(&req, p, &object)
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("获取用户资产、配置表失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+
+ e.OK( object, "查询成功")
+}
+
+// Insert 创建用户资产、配置表
+// @Summary 创建用户资产、配置表
+// @Description 创建用户资产、配置表
+// @Tags 用户资产、配置表
+// @Accept application/json
+// @Product application/json
+// @Param data body dto.LineUserSettingInsertReq true "data"
+// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}"
+// @Router /api/v1/line-user-setting [post]
+// @Security Bearer
+func (e LineUserSetting) Insert(c *gin.Context) {
+ req := dto.LineUserSettingInsertReq{}
+ s := service.LineUserSetting{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+ // 设置创建人
+ req.SetCreateBy(user.GetUserId(c))
+
+ err = s.Insert(&req)
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("创建用户资产、配置表失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+
+ e.OK(req.GetId(), "创建成功")
+}
+
+// Update 修改用户资产、配置表
+// @Summary 修改用户资产、配置表
+// @Description 修改用户资产、配置表
+// @Tags 用户资产、配置表
+// @Accept application/json
+// @Product application/json
+// @Param id path int true "id"
+// @Param data body dto.LineUserSettingUpdateReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}"
+// @Router /api/v1/line-user-setting/{id} [put]
+// @Security Bearer
+func (e LineUserSetting) Update(c *gin.Context) {
+ req := dto.LineUserSettingUpdateReq{}
+ s := service.LineUserSetting{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+ req.SetUpdateBy(user.GetUserId(c))
+ p := actions.GetPermissionFromContext(c)
+
+ err = s.Update(&req, p)
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("修改用户资产、配置表失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+ e.OK( req.GetId(), "修改成功")
+}
+
+// Delete 删除用户资产、配置表
+// @Summary 删除用户资产、配置表
+// @Description 删除用户资产、配置表
+// @Tags 用户资产、配置表
+// @Param data body dto.LineUserSettingDeleteReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}"
+// @Router /api/v1/line-user-setting [delete]
+// @Security Bearer
+func (e LineUserSetting) Delete(c *gin.Context) {
+ s := service.LineUserSetting{}
+ req := dto.LineUserSettingDeleteReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ // req.SetUpdateBy(user.GetUserId(c))
+ p := actions.GetPermissionFromContext(c)
+
+ err = s.Remove(&req, p)
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("删除用户资产、配置表失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+ e.OK( req.GetId(), "删除成功")
+}
diff --git a/app/admin/apis/member_renwa_log.go b/app/admin/apis/member_renwa_log.go
index 31821b9..48c458f 100644
--- a/app/admin/apis/member_renwa_log.go
+++ b/app/admin/apis/member_renwa_log.go
@@ -1,9 +1,10 @@
package apis
import (
- "fmt"
+ "fmt"
"github.com/gin-gonic/gin"
+ "github.com/gin-gonic/gin/binding"
"github.com/go-admin-team/go-admin-core/sdk/api"
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
_ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
@@ -28,18 +29,18 @@ type MemberRenwaLog struct {
// @Router /api/v1/member-renwa-log [get]
// @Security Bearer
func (e MemberRenwaLog) GetPage(c *gin.Context) {
- req := dto.MemberRenwaLogGetPageReq{}
- s := service.MemberRenwaLog{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.MemberRenwaLogGetPageReq{}
+ s := service.MemberRenwaLog{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req, binding.Form, binding.Query).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
p := actions.GetPermissionFromContext(c)
list := make([]models.MemberRenwaLog, 0)
@@ -48,7 +49,7 @@ func (e MemberRenwaLog) GetPage(c *gin.Context) {
err = s.GetPage(&req, p, &list, &count)
if err != nil {
e.Error(500, err, fmt.Sprintf("获取会员续期记录失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
@@ -65,7 +66,7 @@ func (e MemberRenwaLog) GetPage(c *gin.Context) {
func (e MemberRenwaLog) Get(c *gin.Context) {
req := dto.MemberRenwaLogGetReq{}
s := service.MemberRenwaLog{}
- err := e.MakeContext(c).
+ err := e.MakeContext(c).
MakeOrm().
Bind(&req).
MakeService(&s.Service).
@@ -81,10 +82,10 @@ func (e MemberRenwaLog) Get(c *gin.Context) {
err = s.Get(&req, p, &object)
if err != nil {
e.Error(500, err, fmt.Sprintf("获取会员续期记录失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( object, "查询成功")
+ e.OK(object, "查询成功")
}
// Insert 创建会员续期记录
@@ -98,25 +99,25 @@ func (e MemberRenwaLog) Get(c *gin.Context) {
// @Router /api/v1/member-renwa-log [post]
// @Security Bearer
func (e MemberRenwaLog) Insert(c *gin.Context) {
- req := dto.MemberRenwaLogInsertReq{}
- s := service.MemberRenwaLog{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.MemberRenwaLogInsertReq{}
+ s := service.MemberRenwaLog{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
// 设置创建人
req.SetCreateBy(user.GetUserId(c))
err = s.Insert(&req)
if err != nil {
e.Error(500, err, fmt.Sprintf("创建会员续期记录失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
e.OK(req.GetId(), "创建成功")
@@ -134,27 +135,27 @@ func (e MemberRenwaLog) Insert(c *gin.Context) {
// @Router /api/v1/member-renwa-log/{id} [put]
// @Security Bearer
func (e MemberRenwaLog) Update(c *gin.Context) {
- req := dto.MemberRenwaLogUpdateReq{}
- s := service.MemberRenwaLog{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.MemberRenwaLogUpdateReq{}
+ s := service.MemberRenwaLog{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
req.SetUpdateBy(user.GetUserId(c))
p := actions.GetPermissionFromContext(c)
err = s.Update(&req, p)
if err != nil {
e.Error(500, err, fmt.Sprintf("修改会员续期记录失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( req.GetId(), "修改成功")
+ e.OK(req.GetId(), "修改成功")
}
// Delete 删除会员续期记录
@@ -166,18 +167,18 @@ func (e MemberRenwaLog) Update(c *gin.Context) {
// @Router /api/v1/member-renwa-log [delete]
// @Security Bearer
func (e MemberRenwaLog) Delete(c *gin.Context) {
- s := service.MemberRenwaLog{}
- req := dto.MemberRenwaLogDeleteReq{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ s := service.MemberRenwaLog{}
+ req := dto.MemberRenwaLogDeleteReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
// req.SetUpdateBy(user.GetUserId(c))
p := actions.GetPermissionFromContext(c)
@@ -185,7 +186,7 @@ func (e MemberRenwaLog) Delete(c *gin.Context) {
err = s.Remove(&req, p)
if err != nil {
e.Error(500, err, fmt.Sprintf("删除会员续期记录失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( req.GetId(), "删除成功")
+ e.OK(req.GetId(), "删除成功")
}
diff --git a/app/admin/apis/member_renwal_config.go b/app/admin/apis/member_renwal_config.go
index aa3e7ab..452b57a 100644
--- a/app/admin/apis/member_renwal_config.go
+++ b/app/admin/apis/member_renwal_config.go
@@ -1,7 +1,7 @@
package apis
import (
- "fmt"
+ "fmt"
"github.com/gin-gonic/gin"
"github.com/go-admin-team/go-admin-core/sdk/api"
@@ -30,18 +30,18 @@ type MemberRenwalConfig struct {
// @Router /api/v1/member-renwal-config [get]
// @Security Bearer
func (e MemberRenwalConfig) GetPage(c *gin.Context) {
- req := dto.MemberRenwalConfigGetPageReq{}
- s := service.MemberRenwalConfig{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.MemberRenwalConfigGetPageReq{}
+ s := service.MemberRenwalConfig{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
p := actions.GetPermissionFromContext(c)
list := make([]models.MemberRenwalConfig, 0)
@@ -50,7 +50,7 @@ func (e MemberRenwalConfig) GetPage(c *gin.Context) {
err = s.GetPage(&req, p, &list, &count)
if err != nil {
e.Error(500, err, fmt.Sprintf("获取会员套餐管理失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
@@ -67,7 +67,7 @@ func (e MemberRenwalConfig) GetPage(c *gin.Context) {
func (e MemberRenwalConfig) Get(c *gin.Context) {
req := dto.MemberRenwalConfigGetReq{}
s := service.MemberRenwalConfig{}
- err := e.MakeContext(c).
+ err := e.MakeContext(c).
MakeOrm().
Bind(&req).
MakeService(&s.Service).
@@ -83,10 +83,10 @@ func (e MemberRenwalConfig) Get(c *gin.Context) {
err = s.Get(&req, p, &object)
if err != nil {
e.Error(500, err, fmt.Sprintf("获取会员套餐管理失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( object, "查询成功")
+ e.OK(object, "查询成功")
}
// Insert 创建会员套餐管理
@@ -100,25 +100,31 @@ func (e MemberRenwalConfig) Get(c *gin.Context) {
// @Router /api/v1/member-renwal-config [post]
// @Security Bearer
func (e MemberRenwalConfig) Insert(c *gin.Context) {
- req := dto.MemberRenwalConfigInsertReq{}
- s := service.MemberRenwalConfig{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.MemberRenwalConfigInsertReq{}
+ s := service.MemberRenwalConfig{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ if err := req.Valid(); err != nil {
+ e.Error(500, err, "")
+ return
+ }
+
// 设置创建人
req.SetCreateBy(user.GetUserId(c))
err = s.Insert(&req)
if err != nil {
e.Error(500, err, fmt.Sprintf("创建会员套餐管理失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
e.OK(req.GetId(), "创建成功")
@@ -136,27 +142,33 @@ func (e MemberRenwalConfig) Insert(c *gin.Context) {
// @Router /api/v1/member-renwal-config/{id} [put]
// @Security Bearer
func (e MemberRenwalConfig) Update(c *gin.Context) {
- req := dto.MemberRenwalConfigUpdateReq{}
- s := service.MemberRenwalConfig{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ req := dto.MemberRenwalConfigUpdateReq{}
+ s := service.MemberRenwalConfig{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ if err := req.Valid(); err != nil {
+ e.Error(500, err, "")
+ return
+ }
+
req.SetUpdateBy(user.GetUserId(c))
p := actions.GetPermissionFromContext(c)
err = s.Update(&req, p)
if err != nil {
e.Error(500, err, fmt.Sprintf("修改会员套餐管理失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( req.GetId(), "修改成功")
+ e.OK(req.GetId(), "修改成功")
}
// Delete 删除会员套餐管理
@@ -168,18 +180,18 @@ func (e MemberRenwalConfig) Update(c *gin.Context) {
// @Router /api/v1/member-renwal-config [delete]
// @Security Bearer
func (e MemberRenwalConfig) Delete(c *gin.Context) {
- s := service.MemberRenwalConfig{}
- req := dto.MemberRenwalConfigDeleteReq{}
- err := e.MakeContext(c).
- MakeOrm().
- Bind(&req).
- MakeService(&s.Service).
- Errors
- if err != nil {
- e.Logger.Error(err)
- e.Error(500, err, err.Error())
- return
- }
+ s := service.MemberRenwalConfig{}
+ req := dto.MemberRenwalConfigDeleteReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
// req.SetUpdateBy(user.GetUserId(c))
p := actions.GetPermissionFromContext(c)
@@ -187,7 +199,7 @@ func (e MemberRenwalConfig) Delete(c *gin.Context) {
err = s.Remove(&req, p)
if err != nil {
e.Error(500, err, fmt.Sprintf("删除会员套餐管理失败,\r\n失败信息 %s", err.Error()))
- return
+ return
}
- e.OK( req.GetId(), "删除成功")
+ e.OK(req.GetId(), "删除成功")
}
diff --git a/app/admin/apis/member_withdrawal_log.go b/app/admin/apis/member_withdrawal_log.go
new file mode 100644
index 0000000..4af3187
--- /dev/null
+++ b/app/admin/apis/member_withdrawal_log.go
@@ -0,0 +1,241 @@
+package apis
+
+import (
+ "fmt"
+
+ "github.com/gin-gonic/gin"
+ "github.com/go-admin-team/go-admin-core/sdk/api"
+ "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
+ _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
+
+ "go-admin/app/admin/models"
+ "go-admin/app/admin/service"
+ "go-admin/app/admin/service/dto"
+ "go-admin/common/actions"
+)
+
+type MemberWithdrawalLog struct {
+ api.Api
+}
+
+// GetPage 获取用户提现记录列表
+// @Summary 获取用户提现记录列表
+// @Description 获取用户提现记录列表
+// @Tags 用户提现记录
+// @Param networkName query string false "网络名称"
+// @Param status query string false "提现状态(member_withdrawal_status)"
+// @Param pageSize query int false "页条数"
+// @Param pageIndex query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]models.MemberWithdrawalLog}} "{"code": 200, "data": [...]}"
+// @Router /api/v1/member-withdrawal-log [get]
+// @Security Bearer
+func (e MemberWithdrawalLog) GetPage(c *gin.Context) {
+ req := dto.MemberWithdrawalLogGetPageReq{}
+ s := service.MemberWithdrawalLog{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ p := actions.GetPermissionFromContext(c)
+ list := make([]models.MemberWithdrawalLog, 0)
+ var count int64
+
+ err = s.GetPage(&req, p, &list, &count)
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("获取用户提现记录失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+
+ e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// Get 获取用户提现记录
+// @Summary 获取用户提现记录
+// @Description 获取用户提现记录
+// @Tags 用户提现记录
+// @Param id path int false "id"
+// @Success 200 {object} response.Response{data=models.MemberWithdrawalLog} "{"code": 200, "data": [...]}"
+// @Router /api/v1/member-withdrawal-log/{id} [get]
+// @Security Bearer
+func (e MemberWithdrawalLog) Get(c *gin.Context) {
+ req := dto.MemberWithdrawalLogGetReq{}
+ s := service.MemberWithdrawalLog{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+ var object models.MemberWithdrawalLog
+
+ p := actions.GetPermissionFromContext(c)
+ err = s.Get(&req, p, &object)
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("获取用户提现记录失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+
+ e.OK(object, "查询成功")
+}
+
+// Insert 创建用户提现记录
+// @Summary 创建用户提现记录
+// @Description 创建用户提现记录
+// @Tags 用户提现记录
+// @Accept application/json
+// @Product application/json
+// @Param data body dto.MemberWithdrawalLogInsertReq true "data"
+// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}"
+// @Router /api/v1/member-withdrawal-log [post]
+// @Security Bearer
+func (e MemberWithdrawalLog) Insert(c *gin.Context) {
+ req := dto.MemberWithdrawalLogInsertReq{}
+ s := service.MemberWithdrawalLog{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+ // 设置创建人
+ req.SetCreateBy(user.GetUserId(c))
+
+ err = s.Insert(&req)
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("创建用户提现记录失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+
+ e.OK(req.GetId(), "创建成功")
+}
+
+// Update 修改用户提现记录
+// @Summary 修改用户提现记录
+// @Description 修改用户提现记录
+// @Tags 用户提现记录
+// @Accept application/json
+// @Product application/json
+// @Param id path int true "id"
+// @Param data body dto.MemberWithdrawalLogUpdateReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}"
+// @Router /api/v1/member-withdrawal-log/{id} [put]
+// @Security Bearer
+func (e MemberWithdrawalLog) Update(c *gin.Context) {
+ req := dto.MemberWithdrawalLogUpdateReq{}
+ s := service.MemberWithdrawalLog{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+ req.SetUpdateBy(user.GetUserId(c))
+ p := actions.GetPermissionFromContext(c)
+
+ err = s.Update(&req, p)
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("修改用户提现记录失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+ e.OK(req.GetId(), "修改成功")
+}
+
+// Delete 删除用户提现记录
+// @Summary 删除用户提现记录
+// @Description 删除用户提现记录
+// @Tags 用户提现记录
+// @Param data body dto.MemberWithdrawalLogDeleteReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}"
+// @Router /api/v1/member-withdrawal-log [delete]
+// @Security Bearer
+func (e MemberWithdrawalLog) Delete(c *gin.Context) {
+ s := service.MemberWithdrawalLog{}
+ req := dto.MemberWithdrawalLogDeleteReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ // req.SetUpdateBy(user.GetUserId(c))
+ p := actions.GetPermissionFromContext(c)
+
+ err = s.Remove(&req, p)
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("删除用户提现记录失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+ e.OK(req.GetId(), "删除成功")
+}
+
+// 审核提现
+func (e MemberWithdrawalLog) Process(c *gin.Context) {
+ s := service.MemberWithdrawalLog{}
+ req := dto.MemberWithdrawalLogApprovedReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ err = s.Process(&req)
+
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("审核提现失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+ e.OK(nil, "确认提现成功")
+}
+
+// 确认提现
+func (e MemberWithdrawalLog) Confirm(c *gin.Context) {
+ s := service.MemberWithdrawalLog{}
+ req := dto.MemberWithdrawalLogConfirmReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ err = s.Confirm(&req)
+
+ if err != nil {
+ e.Error(500, err, fmt.Sprintf("确认到账失败,\r\n失败信息 %s", err.Error()))
+ return
+ }
+ e.OK(nil, "确认提现成功")
+}
diff --git a/app/admin/apis/sys_dict_data.go b/app/admin/apis/sys_dict_data.go
index 7a0c9c4..5422230 100644
--- a/app/admin/apis/sys_dict_data.go
+++ b/app/admin/apis/sys_dict_data.go
@@ -76,7 +76,7 @@ func (e SysDictData) Get(c *gin.Context) {
return
}
- var object models.SysDictData
+ var object dto.SysDictDataResp
err = s.Get(&req, &object)
if err != nil {
diff --git a/app/admin/fronted/common.go b/app/admin/fronted/common.go
new file mode 100644
index 0000000..a7107a5
--- /dev/null
+++ b/app/admin/fronted/common.go
@@ -0,0 +1,37 @@
+package fronted
+
+import (
+ "go-admin/app/admin/service/appservice"
+ "go-admin/common/service/sysservice/sysstatuscode"
+ statuscode "go-admin/common/status_code"
+
+ "github.com/gin-gonic/gin"
+ "github.com/go-admin-team/go-admin-core/sdk/api"
+)
+
+type Common struct {
+ api.Api
+}
+
+// 获取默认设置
+func (e Common) GetDefaultSet(c *gin.Context) {
+ s := appservice.Common{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(statuscode.ServerError, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.ServerError))
+ return
+ }
+
+ data, code := s.GetDefaultSet()
+
+ if code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ return
+ }
+
+ e.OK(data, "success")
+}
diff --git a/app/admin/fronted/invite_log.go b/app/admin/fronted/invite_log.go
new file mode 100644
index 0000000..c049969
--- /dev/null
+++ b/app/admin/fronted/invite_log.go
@@ -0,0 +1,46 @@
+package fronted
+
+import (
+ "go-admin/app/admin/service/appservice"
+ "go-admin/app/admin/service/common"
+ "go-admin/app/admin/service/dto"
+
+ "github.com/gin-gonic/gin"
+ "github.com/go-admin-team/go-admin-core/sdk/api"
+)
+
+type InviteLog struct {
+ api.Api
+}
+
+// GetPage 获取InviteLog列表
+func (e InviteLog) GetPersonnalPage(c *gin.Context) {
+ s := appservice.InviteLog{}
+ req := dto.PersonnalInviteLogPageReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ datas := make([]dto.InviteLogResp, 0)
+ req.UserId = common.GetUserId(c)
+
+ if req.UserId == 0 {
+ req.UserId = -1
+ }
+ var count int64
+ err = s.GetPage(&req, &datas, &count)
+
+ if err != nil {
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ e.PageOK(datas, int(count), req.PageIndex, req.PageSize, "success")
+}
diff --git a/app/admin/fronted/line_user.go b/app/admin/fronted/line_user.go
index 8cc610a..38fac99 100644
--- a/app/admin/fronted/line_user.go
+++ b/app/admin/fronted/line_user.go
@@ -7,6 +7,7 @@ import (
"go-admin/app/admin/models/sysmodel"
"go-admin/app/admin/service"
"go-admin/app/admin/service/aduserdb"
+ "go-admin/app/admin/service/appservice"
"go-admin/app/admin/service/common"
"go-admin/app/admin/service/dto"
"go-admin/common/const/rediskey"
@@ -23,6 +24,7 @@ import (
"github.com/bytedance/sonic"
"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"
@@ -35,11 +37,15 @@ type LineUserApi struct {
// Register 用户注册
func (e LineUserApi) Register(c *gin.Context) {
s := service.LineUser{}
+ userAppService := appservice.LineUser{}
+ balanceService := service.MemberBalance{}
req := sysmodel.FrontedUserRegisterReq{}
err := e.MakeContext(c).
MakeOrm().
Bind(&req).
MakeService(&s.Service).
+ MakeService(&userAppService.Service).
+ MakeService(&balanceService.Service).
Errors
if err != nil {
e.Logger.Error(err)
@@ -66,6 +72,10 @@ func (e LineUserApi) Register(c *gin.Context) {
e.Error(ok, nil, sysstatuscode.GetStatusCodeDescription(c, ok))
return
}
+
+ userAppService.SetDefaultRenwal(user)
+ balanceService.CreateDefaultBalance(user)
+
resp := map[string]interface{}{
"email": req.Email,
"mobile": req.Phone,
@@ -109,7 +119,7 @@ func (e LineUserApi) VerifyEmail(c *gin.Context) {
return
}
// 核验邮箱验证码
- code := authservice.UserVerifyEmail(req.Email, req.VerifyCode, e.Orm)
+ code := authservice.UserVerifyEmail(req.Email, req.VerifyCode, 0, e.Orm)
if code != statuscode.OK {
e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
return
@@ -123,7 +133,7 @@ func (e LineUserApi) VerifyEmail(c *gin.Context) {
}
-// SendVerifyEmail 发送注册校验邮箱
+// SendVerifyEmail 发送邮箱
func (e LineUserApi) SendVerifyEmail(c *gin.Context) {
s := service.LineUser{}
req := dto.FrontedSendVerifyEmailReq{}
@@ -144,7 +154,8 @@ func (e LineUserApi) SendVerifyEmail(c *gin.Context) {
return
}
emailCode := inttostring.GenerateRandomString(10)
- code = authservice.SendRegisterEmail(req.Email, emailCode)
+ language := common.GetLanguage(c)
+ code = authservice.SendRegisterEmail(req.Email, emailCode, req.Type, language)
if code != statuscode.OK {
e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
return
@@ -173,13 +184,15 @@ func (e LineUserApi) SendRegisterSms(c *gin.Context) {
return
}
- user, _ := aduserdb.GetUserByPhone(e.Orm, req.PhoneAreaCode, req.Phone)
- if user.Id > 0 {
- e.Error(statuscode.TheAccountIsAlreadyRegistered, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.TheAccountIsAlreadyRegistered))
- return
+ if req.Type == 0 {
+ user, _ := aduserdb.GetUserByPhone(e.Orm, req.PhoneAreaCode, req.Phone)
+ if user.Id > 0 {
+ e.Error(statuscode.TheAccountIsAlreadyRegistered, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.TheAccountIsAlreadyRegistered))
+ return
+ }
}
- code = authservice.SendGoToneSms(req.Phone, req.PhoneAreaCode)
+ code = authservice.SendGoToneSms(req.Phone, req.PhoneAreaCode, req.Type)
if code != statuscode.OK {
e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
return
@@ -336,9 +349,11 @@ func (e LineUserApi) GetWhiteIp(c *gin.Context) {
// Info 用户中心
func (e LineUserApi) Info(c *gin.Context) {
s := service.LineUser{}
+ balance := service.MemberBalance{}
err := e.MakeContext(c).
MakeOrm().
MakeService(&s.Service).
+ MakeService(&balance.Service).
Errors
if err != nil {
e.Logger.Error(err)
@@ -394,11 +409,15 @@ func (e LineUserApi) Info(c *gin.Context) {
fundingAsset = resp[0:]
}
+ balanceData, _ := balance.GetBalance(userId)
+
//获取盈利情况
logs := service.LineUserProfitLogs{Service: s.Service}
totalProfit, todayProfit := logs.GetProfitInfoByUserId(userinfo.Id)
user := map[string]interface{}{
"avatar": userinfo.Avatar,
+ "user_id": userinfo.Id,
+ "user_name": userinfo.Nickname,
"invite_num": userinfo.RecommendNum,
"open_status": apiUserinfo.OpenStatus,
"is_auth": isAuth,
@@ -415,6 +434,11 @@ func (e LineUserApi) Info(c *gin.Context) {
"funding_asset": fundingAsset,
"total_profit": totalProfit.Float64,
"today_profit": todayProfit.Float64,
+ "balance": map[string]interface{}{ //系统余额
+ "total_amount": balanceData.TotalAmount,
+ "free_amount": balanceData.FreeAmount,
+ "frozen_amount": balanceData.FrozenAmount,
+ },
}
e.OK(returnMap, "success")
@@ -435,16 +459,10 @@ func (e LineUserApi) OpenStatus(c *gin.Context) {
return
}
userId := common.GetUserId(c)
- var apiUser models.LineApiUser
- err = e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&apiUser).Error
+ code := s.OpenStatus(&req, userId)
- if apiUser.ApiSecret == "" || apiUser.ApiKey == "" {
- e.Error(statuscode.UserApiKeyRequired, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.UserApiKeyRequired))
- return
- }
- err = e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Update("open_status", req.Status).Error
- if err != nil {
- e.Error(500, err, err.Error())
+ if code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
return
}
e.OK(nil, "success")
@@ -579,3 +597,128 @@ func (e LineUserApi) CallBack(c *gin.Context) {
e.OK(nil, "")
}
+
+// 退出登录
+func (e LineUserApi) Logout(c *gin.Context) {
+ err := e.MakeContext(c).
+ MakeOrm().
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ userId := common.GetUserId(c)
+ err = authservice.Logout(userId, 1)
+
+ if err != nil {
+ logger.Error("退出登录失败:", err.Error())
+ e.Error(statuscode.ServerError, nil, "")
+ }
+
+ e.OK(nil, "success")
+}
+
+// 查询个人资产
+func (e LineUserApi) GetProperty(c *gin.Context) {
+ s := service.LineUser{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(statuscode.ServerError, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.ServerError))
+ }
+
+ var data dto.LineUserPropertyResp
+ userId := common.GetUserId(c)
+ code := s.GetProperty(userId, &data)
+ if code != statuscode.OK && code != statuscode.UserApiUserNotBind {
+ // e.Logger.Error(err)
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ return
+ }
+
+ e.OK(data, "success")
+}
+
+// 获取到期时间
+func (e LineUserApi) GetUserInfo(c *gin.Context) {
+ s := appservice.LineUser{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(statuscode.ServerError, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.ServerError))
+ }
+
+ userId := common.GetUserId(c)
+ var data dto.LineUserAppResp
+ code := s.GetUserInfo(userId, &data)
+
+ if code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ return
+ }
+
+ e.OK(data, "success")
+}
+
+// 用户下单设置
+func (e LineUserApi) UserOrderSet(c *gin.Context) {
+ s := service.LineUser{}
+ req := dto.LineUserOrderSetReq{}
+
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(statuscode.ServerError, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.ServerError))
+ }
+
+ userId := common.GetUserId(c)
+ code := s.OrderSet(&req, userId)
+
+ if code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ return
+ }
+
+ e.OK(nil, "success")
+}
+
+func (e LineUserApi) ResetPassword(c *gin.Context) {
+ s := service.LineUser{}
+ req := dto.LineUserResetPwdReq{}
+
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(statuscode.ServerError, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.ServerError))
+ }
+
+ if code := req.Valid(); code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ return
+ }
+
+ code := s.ResetPassword(&req)
+
+ if code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ return
+ }
+
+ e.OK(nil, "success")
+}
diff --git a/app/admin/fronted/member_balance_log.go b/app/admin/fronted/member_balance_log.go
new file mode 100644
index 0000000..f027206
--- /dev/null
+++ b/app/admin/fronted/member_balance_log.go
@@ -0,0 +1,44 @@
+package fronted
+
+import (
+ "go-admin/app/admin/service/appservice"
+ "go-admin/app/admin/service/common"
+ "go-admin/app/admin/service/dto"
+ "go-admin/common/service/sysservice/sysstatuscode"
+ statuscode "go-admin/common/status_code"
+
+ "github.com/gin-gonic/gin"
+ "github.com/gin-gonic/gin/binding"
+ "github.com/go-admin-team/go-admin-core/sdk/api"
+)
+
+type MemberBalanceLog struct {
+ api.Api
+}
+
+// 分页查询
+func (e MemberBalanceLog) GetPage(c *gin.Context) {
+ s := appservice.MemberBalanceLog{}
+ req := dto.MemberBalanceLogPageAppReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req, binding.Form, binding.Query).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, "server error")
+ return
+ }
+ req.UserId = common.GetUserId(c)
+ req.Language = common.GetLanguage(c)
+ data := make([]dto.MemberBalanceLogAppResp, 0)
+ var count int64
+ code := s.GetPage(&req, &data, &count)
+
+ if code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ }
+
+ e.PageOK(data, int(count), req.PageIndex, req.PageSize, "success")
+}
diff --git a/app/admin/fronted/member_renwal_config.go b/app/admin/fronted/member_renwal_config.go
index ebc48c4..edf6968 100644
--- a/app/admin/fronted/member_renwal_config.go
+++ b/app/admin/fronted/member_renwal_config.go
@@ -4,6 +4,7 @@ import (
"go-admin/app/admin/service/appservice"
statuscode "go-admin/common/status_code"
+ "go-admin/common/service/common"
"go-admin/common/service/sysservice/sysstatuscode"
"github.com/gin-gonic/gin"
@@ -27,7 +28,9 @@ func (e MemberRenwalConfig) GetActiveList(c *gin.Context) {
e.Error(500, err, err.Error())
return
}
- data, code := s.GetList()
+
+ language := common.GetLanguage(c)
+ data, code := s.GetList(language)
if code != statuscode.OK {
e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
diff --git a/app/admin/fronted/member_renwal_log.go b/app/admin/fronted/member_renwal_log.go
index c9fe881..b2f2840 100644
--- a/app/admin/fronted/member_renwal_log.go
+++ b/app/admin/fronted/member_renwal_log.go
@@ -8,6 +8,7 @@ import (
statuscode "go-admin/common/status_code"
"github.com/gin-gonic/gin"
+ "github.com/gin-gonic/gin/binding"
"github.com/go-admin-team/go-admin-core/sdk/api"
)
@@ -19,14 +20,51 @@ type MemberRenwalLog struct {
func (e MemberRenwalLog) GetPage(c *gin.Context) {
s := appservice.MemberRenwalLog{}
req := dto.MemberRenwalLogPageAppReq{}
-
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req, binding.Form, binding.Query).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, "server error")
+ return
+ }
userId := common.GetUserId(c)
+ req.Language = common.GetLanguage(c)
data := make([]dto.MemberRenwalLogResp, 0)
- code := s.GetPage(userId, &req, &data)
+ var count int64
+ code := s.GetPage(userId, &req, &data, &count)
if code != statuscode.OK {
e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
}
+ e.PageOK(data, int(count), req.PageIndex, req.PageSize, "success")
+}
+
+func (e MemberRenwalLog) Apply(c *gin.Context) {
+ s := appservice.MemberRenwalLog{}
+ req := dto.MemberRenwalCreateAppReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, "server error")
+ return
+ }
+
+ req.UserId = common.GetUserId(c)
+ data := dto.MemberRenwalCreateAppResp{}
+ code := s.Renwal(&req, &data)
+
+ if code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ return
+ }
+
e.OK(data, "success")
}
diff --git a/app/admin/fronted/member_withdrawal_log.go b/app/admin/fronted/member_withdrawal_log.go
new file mode 100644
index 0000000..7315452
--- /dev/null
+++ b/app/admin/fronted/member_withdrawal_log.go
@@ -0,0 +1,107 @@
+package fronted
+
+import (
+ "go-admin/app/admin/service/appservice"
+ "go-admin/app/admin/service/common"
+ "go-admin/app/admin/service/dto"
+ "go-admin/common/service/sysservice/sysstatuscode"
+ statuscode "go-admin/common/status_code"
+
+ "github.com/gin-gonic/gin"
+ "github.com/gin-gonic/gin/binding"
+ "github.com/go-admin-team/go-admin-core/sdk/api"
+)
+
+type MemberWithdrawalLog struct {
+ api.Api
+}
+
+// 分页查询
+func (e MemberWithdrawalLog) GetPage(c *gin.Context) {
+ s := appservice.MemberWithdrawalLog{}
+ req := dto.MemberWithdrawalLogGetPageAppReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req, binding.Form, binding.Query).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ var count int64
+ var list []dto.MemberWithdrawalLogResp
+
+ req.UserId = common.GetUserId(c)
+ code := s.GetPage(&req, &list, &count)
+
+ if code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ }
+
+ e.PageOK(list, int(count), req.PageIndex, req.PageSize, "success")
+}
+
+// 用户提现申请
+func (e MemberWithdrawalLog) Apply(c *gin.Context) {
+ s := appservice.MemberWithdrawalLog{}
+ req := dto.MemberWithdrawalLogApplyReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ if code := req.Valid(); code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ return
+ }
+
+ req.UserId = common.GetUserId(c)
+ code := s.Apply(&req)
+
+ if code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ return
+ }
+
+ e.OK(nil, "success")
+}
+
+// 用户取消提现
+func (e MemberWithdrawalLog) Cancel(c *gin.Context) {
+ s := appservice.MemberWithdrawalLog{}
+ req := dto.MemberWithdrawalLogCancelReq{}
+ err := e.MakeContext(c).
+ MakeOrm().
+ Bind(&req).
+ MakeService(&s.Service).
+ Errors
+ if err != nil {
+ e.Logger.Error(err)
+ e.Error(500, err, err.Error())
+ return
+ }
+
+ if code := req.Valid(); code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ return
+ }
+
+ userId := common.GetUserId(c)
+ code := s.Canceled(&req, userId)
+
+ if code != statuscode.OK {
+ e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code))
+ return
+ }
+
+ e.OK(nil, "success")
+}
diff --git a/app/admin/models/line_coinnetwork.go b/app/admin/models/line_coinnetwork.go
index 124cff6..e9c4116 100644
--- a/app/admin/models/line_coinnetwork.go
+++ b/app/admin/models/line_coinnetwork.go
@@ -16,6 +16,7 @@ type LineCoinnetwork struct {
UnlockTime int64 `json:"unlockTime" gorm:"type:int;comment:提现确认平均时间,单位分钟"`
Fee decimal.Decimal `json:"fee" gorm:"type:decimal(32,6);comment:网络手续费(百分比)"`
MinWithdrawal decimal.Decimal `json:"minWithdrawal" gorm:"type:decimal(32,6);comment:最小提现金额"`
+ Status int `json:"status" gorm:"type:int;comment:状态 1 启用 2 禁用"`
models.ModelTime
models.ControlBy
}
diff --git a/app/admin/models/line_pre_order_ext.go b/app/admin/models/line_pre_order_ext.go
index 308e109..9836848 100644
--- a/app/admin/models/line_pre_order_ext.go
+++ b/app/admin/models/line_pre_order_ext.go
@@ -9,22 +9,21 @@ import (
type LinePreOrderExt struct {
models.Model
- MainOrderId int `json:"mainOrderId" gorm:"type:bigint;comment:主单id"`
- OrderId int `json:"orderId" gorm:"type:bigint;comment:订单id"`
- TakeProfitRatio decimal.Decimal `json:"takeProfitRatio" gorm:"type:decimal(10,2);comment:止盈百分比"`
- ReTakeRatio decimal.Decimal `json:"reTakeRatio" gorm:"type:decimal(10,2);comment:亏损回本止盈百分比"`
- ReduceOrderType string `json:"reduceOrderType" gorm:"type:varchar(20);comment:减仓类型 LIMIT-限价 MARKET-市价"`
- ReducePriceRatio decimal.Decimal `json:"reducePriceRatio" gorm:"type:decimal(10,2);comment:减仓价格百分比"`
- ReduceNumRatio decimal.Decimal `json:"reduceNumRatio" gorm:"type:decimal(10,2);comment:减仓数量百分比"`
- ReduceTakeProfitRatio decimal.Decimal `json:"reduceTakeProfitRatio" gorm:"type:decimal(10,2);comment:减仓后止盈百分比"`
- ReduceStopLossRatio decimal.Decimal `json:"reduceStopLossRatio" gorm:"type:decimal(10,2);comment:减仓后止损百分比"`
- AddPositionOrderType string `json:"addPositionOrderType" gorm:"type:varchar(20);comment:加仓类型 LIMIT-限价 MARKET-市价"`
- AddPositionPriceRatio decimal.Decimal `json:"addPositionPriceRatio" gorm:"type:decimal(10,2);comment:加仓价格百分比"`
- AddPositionType int `json:"addPositionType" gorm:"type:int;comment:加仓类型 1-百分比 2-实际金额"`
- AddPositionVal decimal.Decimal `json:"addPositionVal" gorm:"type:decimal(10,2);comment:加仓值"`
- ReduceReTakeRatio decimal.Decimal `json:"reduceReTakeRatio" gorm:"type:decimal(10,2);comment:减仓后亏损回本止盈百分比"`
- TotalAfterAdding decimal.Decimal `json:"totalAfterAdding" gorm:"-"` //加仓后总数
- TotalAfterReducing decimal.Decimal `json:"totalAfterReducing" gorm:"-"` //减仓后总数
+ MainOrderId int `json:"mainOrderId" gorm:"type:bigint;comment:主单id"`
+ OrderId int `json:"orderId" gorm:"type:bigint;comment:订单id"`
+ AddType int `json:"addType" gorm:"type:tinyint;comment:类型 1-加仓 2-减仓"`
+ OrderType string `json:"orderType" gorm:"type:varchar(20);comment:订单类型 LIMIT-限价 MARKET-市价"`
+ PriceRatio decimal.Decimal `json:"priceRatio" gorm:"type:decimal(10,2);comment: (加仓/减仓)触发价格百分比"`
+ AddPositionType int `json:"addPositionType" gorm:"type:int;comment:(加仓/减仓)类型 1-百分比 2-实际金额"`
+ AddPositionVal decimal.Decimal `json:"addPositionVal" gorm:"type:decimal(10,2);comment:加仓值"`
+ TakeProfitRatio decimal.Decimal `json:"takeProfitRatio" gorm:"type:decimal(10,2);comment:止盈百分比"`
+ StopLossRatio decimal.Decimal `json:"stopLossRatio" gorm:"type:decimal(10,2);comment:止损百分比"`
+ TakeProfitNumRatio decimal.Decimal `json:"takeProfitNumRatio" gorm:"type:decimal(10,2);comment:止盈数量百分比"`
+ TpTpPriceRatio decimal.Decimal `json:"tpTpPriceRatio" gorm:"type:decimal(10,2);comment:止盈后止盈百分比"`
+ TpSlPriceRatio decimal.Decimal `json:"tpSlPriceRatio" gorm:"type:decimal(10,2);comment:止盈后止损百分比"`
+ ReTakeRatio decimal.Decimal `json:"reTakeRatio" gorm:"type:decimal(10,2);comment:亏损回本止盈百分比"`
+ TotalBefore decimal.Decimal `gorm:"-" comment:"初始总数"`
+ TotalAfter decimal.Decimal `gorm:"-" comment:"剩余总数"`
models.ModelTime
models.ControlBy
}
diff --git a/app/admin/models/line_user.go b/app/admin/models/line_user.go
index 66e7e1a..9d7ccc7 100644
--- a/app/admin/models/line_user.go
+++ b/app/admin/models/line_user.go
@@ -11,35 +11,40 @@ import (
type LineUser struct {
models.Model
- GroupId int `json:"groupId" gorm:"type:int unsigned;comment:组别ID"`
- Pid int `json:"pid" gorm:"type:int unsigned;comment:直接推荐人ID"`
- TopReferrerId int `json:"topReferrerId" gorm:"type:int unsigned;comment:父级推荐人ID"`
- Username string `json:"username" gorm:"type:varchar(32);comment:用户名"`
- Nickname string `json:"nickname" gorm:"type:varchar(50);comment:昵称"`
- Password string `json:"password" gorm:"type:varchar(32);comment:密码"`
- Salt string `json:"salt" gorm:"type:varchar(30);comment:密码盐"`
- Email string `json:"email" gorm:"type:varchar(100);comment:电子邮箱"`
- Mobile string `json:"mobile" gorm:"type:varchar(11);comment:手机号"`
- Area string `json:"area" gorm:"type:varchar(255);comment:手机号归属地"`
- Avatar string `json:"avatar" gorm:"type:varchar(255);comment:头像"`
- Level int `json:"level" gorm:"type:tinyint unsigned;comment:等级"`
- Gender int `json:"gender" gorm:"type:tinyint unsigned;comment:性别"`
- Bio string `json:"bio" gorm:"type:varchar(100);comment:格言"`
- Money decimal.Decimal `json:"money" gorm:"type:decimal(10,2) unsigned;comment:保证金"`
- Score int `json:"score" gorm:"type:int unsigned;comment:积分"`
- InviteCode string `json:"invite_code" gorm:"type:varchar(255);comment:邀请码"`
- Successions int `json:"successions" gorm:"type:int unsigned;comment:连续登录天数"`
- MaxSuccessions int `json:"maxSuccessions" gorm:"type:int unsigned;comment:最大连续登录天数"`
- Loginip string `json:"loginip" gorm:"type:varchar(50);comment:登录IP"`
- Loginfailure int `json:"loginfailure" gorm:"type:tinyint unsigned;comment:失败次数"`
- Joinip string `json:"joinip" gorm:"type:varchar(50);comment:加入IP"`
- Jointime int `json:"jointime" gorm:"type:int;comment:加入时间"`
- RecommendNum int `json:"recommend_num" gorm:"type:int;comment:推荐人数"`
- Token string `json:"token" gorm:"type:varchar(50);comment:Token"`
- Status string `json:"status" gorm:"type:varchar(30);comment:状态"`
- Verification string `json:"verification" gorm:"type:varchar(255);comment:验证"`
- LoginTime time.Time `json:"loginTime" gorm:"type:timestamp;comment:登录时间"`
- OpenStatus int `json:"open_status" gorm:"-"`
+ GroupId int `json:"groupId" gorm:"type:int unsigned;comment:组别ID"`
+ Pid int `json:"pid" gorm:"type:int unsigned;comment:直接推荐人ID"`
+ TopReferrerId int `json:"topReferrerId" gorm:"type:int unsigned;comment:父级推荐人ID"`
+ Username string `json:"username" gorm:"type:varchar(32);comment:用户名"`
+ Nickname string `json:"nickname" gorm:"type:varchar(50);comment:昵称"`
+ Password string `json:"password" gorm:"type:varchar(50);comment:密码"`
+ Salt string `json:"salt" gorm:"type:varchar(30);comment:密码盐"`
+ Email string `json:"email" gorm:"type:varchar(100);comment:电子邮箱"`
+ Mobile string `json:"mobile" gorm:"type:varchar(11);comment:手机号"`
+ Area string `json:"area" gorm:"type:varchar(255);comment:手机号归属地"`
+ Avatar string `json:"avatar" gorm:"type:varchar(255);comment:头像"`
+ Level int `json:"level" gorm:"type:tinyint unsigned;comment:等级"`
+ Gender int `json:"gender" gorm:"type:tinyint unsigned;comment:性别"`
+ Bio string `json:"bio" gorm:"type:varchar(100);comment:格言"`
+ Money decimal.Decimal `json:"money" gorm:"type:decimal(10,2) unsigned;comment:保证金"`
+ Score int `json:"score" gorm:"type:int unsigned;comment:积分"`
+ InviteCode string `json:"invite_code" gorm:"type:varchar(255);comment:邀请码"`
+ Successions int `json:"successions" gorm:"type:int unsigned;comment:连续登录天数"`
+ MaxSuccessions int `json:"maxSuccessions" gorm:"type:int unsigned;comment:最大连续登录天数"`
+ Loginip string `json:"loginip" gorm:"type:varchar(50);comment:登录IP"`
+ Loginfailure int `json:"loginfailure" gorm:"type:tinyint unsigned;comment:失败次数"`
+ Joinip string `json:"joinip" gorm:"type:varchar(50);comment:加入IP"`
+ Jointime int `json:"jointime" gorm:"type:int;comment:加入时间"`
+ RecommendNum int `json:"recommend_num" gorm:"type:int;comment:推荐人数"`
+ Token string `json:"token" gorm:"type:varchar(50);comment:Token"`
+ Status string `json:"status" gorm:"type:varchar(30);comment:状态"`
+ Verification string `json:"verification" gorm:"type:varchar(255);comment:验证"`
+ LoginTime time.Time `json:"loginTime" gorm:"type:timestamp;comment:登录时间"`
+ ExpirationTime *time.Time `json:"expirationTime" gorm:"type:timestamp;comment:过期时间"`
+ OpenStatus int `json:"open_status" gorm:"-"`
+ SpotFreeAmount decimal.Decimal `json:"spotFreeAmount" gorm:"-"`
+ FutureFreeAmount decimal.Decimal `json:"futureFreeAmount" gorm:"-"`
+ AssetUpdateTime *time.Time `json:"assetUpdateTime" gorm:"-"`
+ MinOrderAmount decimal.Decimal `json:"minOrderAmount" gorm:"-"`
models.ModelTime
models.ControlBy
}
diff --git a/app/admin/models/line_user_setting.go b/app/admin/models/line_user_setting.go
new file mode 100644
index 0000000..2675968
--- /dev/null
+++ b/app/admin/models/line_user_setting.go
@@ -0,0 +1,34 @@
+package models
+
+import (
+ "time"
+
+ "go-admin/common/models"
+
+ "github.com/shopspring/decimal"
+)
+
+type LineUserSetting struct {
+ models.Model
+
+ UserId int `json:"userId" gorm:"type:bigint;comment:用户ID"`
+ MinOrderAmount decimal.Decimal `json:"minOrderAmount" gorm:"type:decimal(32,8);comment:单笔最小金额"`
+ SpotUsdtFreeAmount decimal.Decimal `json:"spotUsdtFreeAmount" gorm:"type:decimal(32,8);comment:现货USDT可用余额"`
+ FutureUsdtFreeAmount decimal.Decimal `json:"futureUsdtFreeAmount" gorm:"type:decimal(32,8);comment:合约USDT可用余额"`
+ AssetUpdateTime *time.Time `json:"assetUpdateTime" gorm:"type:datetime;comment:资产更新时间"`
+ models.ModelTime
+ models.ControlBy
+}
+
+func (LineUserSetting) TableName() string {
+ return "line_user_setting"
+}
+
+func (e *LineUserSetting) Generate() models.ActiveRecord {
+ o := *e
+ return &o
+}
+
+func (e *LineUserSetting) GetId() interface{} {
+ return e.Id
+}
diff --git a/app/admin/models/member_balance.go b/app/admin/models/member_balance.go
index 964cc67..4ff8a53 100644
--- a/app/admin/models/member_balance.go
+++ b/app/admin/models/member_balance.go
@@ -9,7 +9,8 @@ import (
type MemberBalance struct {
models.Model
- TotalAmont decimal.Decimal `json:"totalAmont" gorm:"type:decimal(18,6);comment:总余额"`
+ UserId int `json:"userId" gorm:"type:bigint;comment:用户id"`
+ TotalAmount decimal.Decimal `json:"totalAmount" gorm:"type:decimal(18,6);comment:总余额"`
FreeAmount decimal.Decimal `json:"freeAmount" gorm:"type:decimal(18,6);comment:可用余额"`
FrozenAmount decimal.Decimal `json:"frozenAmount" gorm:"type:decimal(18,6);comment:冻结金额"`
models.ModelTime
diff --git a/app/admin/models/member_balance_log.go b/app/admin/models/member_balance_log.go
index 5a30605..c74f41f 100644
--- a/app/admin/models/member_balance_log.go
+++ b/app/admin/models/member_balance_log.go
@@ -1,27 +1,27 @@
package models
import (
-
"go-admin/common/models"
+ "github.com/shopspring/decimal"
)
type MemberBalanceLog struct {
- models.Model
-
- UserId int `json:"userId" gorm:"type:bigint;comment:用户id"`
- ChangeSource string `json:"changeSource" gorm:"type:varchar(50);comment:变更来源 (member_change_source)"`
- ChangeType string `json:"changeType" gorm:"type:tinyint;comment:变更类别 1-收入 2-支出"`
- Amount string `json:"amount" gorm:"type:decimal(18,6);comment:变更金额"`
- BalanceBefore string `json:"balanceBefore" gorm:"type:decimal(18,6);comment:变更前余额"`
- BalanceAfter string `json:"balanceAfter" gorm:"type:decimal(18,6);comment:变更后余额"`
- Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
- models.ModelTime
- models.ControlBy
+ models.Model
+
+ UserId int `json:"userId" gorm:"type:bigint;comment:用户id"`
+ ChangeSource string `json:"changeSource" gorm:"type:varchar(50);comment:变更来源 (member_change_source)"`
+ ChangeType int `json:"changeType" gorm:"type:tinyint;comment:变更类别 1-收入 2-支出"`
+ Amount decimal.Decimal `json:"amount" gorm:"type:decimal(18,6);comment:变更金额"`
+ BalanceBefore decimal.Decimal `json:"balanceBefore" gorm:"type:decimal(18,6);comment:变更前余额"`
+ BalanceAfter decimal.Decimal `json:"balanceAfter" gorm:"type:decimal(18,6);comment:变更后余额"`
+ Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
+ models.ModelTime
+ models.ControlBy
}
func (MemberBalanceLog) TableName() string {
- return "member_balance_log"
+ return "member_balance_log"
}
func (e *MemberBalanceLog) Generate() models.ActiveRecord {
@@ -31,4 +31,4 @@ func (e *MemberBalanceLog) Generate() models.ActiveRecord {
func (e *MemberBalanceLog) GetId() interface{} {
return e.Id
-}
\ No newline at end of file
+}
diff --git a/app/admin/models/member_renwa_log.go b/app/admin/models/member_renwa_log.go
index fcc2b63..21feefa 100644
--- a/app/admin/models/member_renwa_log.go
+++ b/app/admin/models/member_renwa_log.go
@@ -1,30 +1,37 @@
package models
import (
- "time"
+ "time"
"go-admin/common/models"
+ "github.com/shopspring/decimal"
)
type MemberRenwaLog struct {
- models.Model
-
- RenwalId string `json:"renwalId" gorm:"type:bigint;comment:套餐id"`
- RenwalName string `json:"renwalName" gorm:"type:varchar(255);comment:续期套餐名称"`
- RenwalDuration string `json:"renwalDuration" gorm:"type:int;comment:续期时长(天数)"`
- Status string `json:"status" gorm:"type:varchar(255);comment:订单状态(member_renwal_log_status)"`
- PayableAmount string `json:"payableAmount" gorm:"type:decimal(18,6);comment:应付金额"`
- ActualPaymentAmount string `json:"actualPaymentAmount" gorm:"type:decimal(18,6);comment:实付金额"`
- FromAddress string `json:"fromAddress" gorm:"type:varchar(255);comment:付款地址"`
- Coin string `json:"coin" gorm:"type:varchar(255);comment:代币"`
- PaymentTime time.Time `json:"paymentTime" gorm:"type:datetime;comment:支付时间"`
- models.ModelTime
- models.ControlBy
+ models.Model
+
+ NetworkName string `json:"networkName" gorm:"type:varchar(255);comment:网络名称"`
+ ReceiveAddress string `json:"receiveAddress" gorm:"type:varchar(255);comment:接收地址"`
+ RenwalId int `json:"renwalId" gorm:"type:bigint;comment:套餐id"`
+ UserId int `json:"userId" gorm:"type:bigint;comment:用户id"`
+ RenwalName string `json:"renwalName" gorm:"type:varchar(255);comment:续期套餐名称"`
+ RenwalDuration int `json:"renwalDuration" gorm:"type:int;comment:续期时长(天数)"`
+ Status string `json:"status" gorm:"type:varchar(255);comment:订单状态(member_renwal_log_status)"`
+ PayableAmount decimal.Decimal `json:"payableAmount" gorm:"type:decimal(18,6);comment:应付金额"`
+ ActualPaymentAmount decimal.Decimal `json:"actualPaymentAmount" gorm:"type:decimal(18,6);comment:实付金额"`
+ FromAddress string `json:"fromAddress" gorm:"type:varchar(255);comment:付款地址"`
+ Coin string `json:"coin" gorm:"type:varchar(255);comment:代币"`
+ PaymentTime *time.Time `json:"paymentTime" gorm:"type:datetime;comment:支付时间"`
+ Hash string `json:"hash" gorm:"type:varchar(255);comment:交易hash"`
+ ExpirationTime time.Time `json:"expirationTime" gorm:"type:datetime;comment:到期时间"`
+ NickName string `json:"nickName" gorm:"-"`
+ models.ModelTime
+ models.ControlBy
}
func (MemberRenwaLog) TableName() string {
- return "member_renwa_log"
+ return "member_renwa_log"
}
func (e *MemberRenwaLog) Generate() models.ActiveRecord {
@@ -34,4 +41,4 @@ func (e *MemberRenwaLog) Generate() models.ActiveRecord {
func (e *MemberRenwaLog) GetId() interface{} {
return e.Id
-}
\ No newline at end of file
+}
diff --git a/app/admin/models/member_renwal_config.go b/app/admin/models/member_renwal_config.go
index cdd8ddc..382270b 100644
--- a/app/admin/models/member_renwal_config.go
+++ b/app/admin/models/member_renwal_config.go
@@ -10,6 +10,7 @@ type MemberRenwalConfig struct {
models.Model
PackageName string `json:"packageName" gorm:"type:varchar(255);comment:套餐名称"`
+ PackageNameEn string `json:"packageNameEn" gorm:"type:varchar(255);comment:套餐英文名称"`
DurationDay int `json:"durationDay" gorm:"type:int;comment:续期时间(天)"`
OriginalPrice decimal.Decimal `json:"originalPrice" gorm:"type:decimal(18,6);comment:原始单价"`
DiscountPrice decimal.Decimal `json:"discountPrice" gorm:"type:decimal(18,6);comment:折扣价格 -1为未设置"`
diff --git a/app/admin/models/member_withdrawal_log.go b/app/admin/models/member_withdrawal_log.go
new file mode 100644
index 0000000..9106592
--- /dev/null
+++ b/app/admin/models/member_withdrawal_log.go
@@ -0,0 +1,42 @@
+package models
+
+import (
+ "time"
+
+ "go-admin/common/models"
+
+ "github.com/shopspring/decimal"
+)
+
+type MemberWithdrawalLog struct {
+ models.Model
+
+ NetworkId int `json:"networkId" gorm:"type:int;comment:网络id"`
+ NetworkName string `json:"networkName" gorm:"type:varchar(50);comment:网络名称"`
+ Coin string `json:"coin" gorm:"type:varchar(50);comment:提现币种"`
+ ToAddress string `json:"toAddress" gorm:"type:varchar(255);comment:提现地址"`
+ Hash string `json:"hash" gorm:"type:varchar(255);comment:提现hash"`
+ UserId int `json:"userId" gorm:"type:bigint;comment:用户id"`
+ Amount decimal.Decimal `json:"amount" gorm:"type:decimal(32,6);comment:提现金额(U)"`
+ Status string `json:"status" gorm:"type:varchar(20);comment:提现状态(member_withdrawal_status)"`
+ ConfirmTime *time.Time `json:"confirmTime" gorm:"type:datetime;comment:确认时间"`
+ Fee decimal.Decimal `json:"fee" gorm:"type:decimal(10,2);comment:手续费比例"`
+ Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
+ UserName string `json:"userName" gorm:"-"`
+ NickName string `json:"nickName" gorm:"-"`
+ models.ModelTime
+ models.ControlBy
+}
+
+func (MemberWithdrawalLog) TableName() string {
+ return "member_withdrawal_log"
+}
+
+func (e *MemberWithdrawalLog) Generate() models.ActiveRecord {
+ o := *e
+ return &o
+}
+
+func (e *MemberWithdrawalLog) GetId() interface{} {
+ return e.Id
+}
diff --git a/app/admin/models/sys_dict_data.go b/app/admin/models/sys_dict_data.go
index 15abf89..0d668e6 100644
--- a/app/admin/models/sys_dict_data.go
+++ b/app/admin/models/sys_dict_data.go
@@ -16,6 +16,7 @@ type SysDictData struct {
Status int `json:"status" gorm:"size:4;comment:Status"`
Default string `json:"default" gorm:"size:8;comment:Default"`
Remark string `json:"remark" gorm:"size:255;comment:Remark"`
+ Language string `json:"language" gorm:"type:text;comment:多语言(json)"`
models.ControlBy
models.ModelTime
}
diff --git a/app/admin/models/sysmodel/authentication.go b/app/admin/models/sysmodel/authentication.go
index f5cde8c..9e7a919 100644
--- a/app/admin/models/sysmodel/authentication.go
+++ b/app/admin/models/sysmodel/authentication.go
@@ -22,7 +22,7 @@ type FrontedUserRegisterReq struct {
InviteCode string `json:"invite_code"` // 邀请码
IP string `json:"-"` // IP
Pid int `json:"-"` // 推荐人ID
-
+ Language string `json:"-"` //语言
}
// CheckParams 校验邮箱参数
diff --git a/app/admin/router/init_router.go b/app/admin/router/init_router.go
index 61fb978..b72ee0f 100644
--- a/app/admin/router/init_router.go
+++ b/app/admin/router/init_router.go
@@ -3,10 +3,11 @@ package router
import (
"os"
+ common "go-admin/common/middleware"
+
"github.com/gin-gonic/gin"
log "github.com/go-admin-team/go-admin-core/logger"
"github.com/go-admin-team/go-admin-core/sdk"
- common "go-admin/common/middleware"
)
// InitRouter 路由初始化,不要怀疑,这里用到了
diff --git a/app/admin/router/invite_log.go b/app/admin/router/invite_log.go
new file mode 100644
index 0000000..6c522d7
--- /dev/null
+++ b/app/admin/router/invite_log.go
@@ -0,0 +1,21 @@
+package router
+
+import (
+ "go-admin/app/admin/fronted"
+ "go-admin/common/middleware"
+
+ "github.com/gin-gonic/gin"
+)
+
+func init() {
+ routerFrontedCheckRole = append(routerFrontedCheckRole, registerInviteLogFrontedRouter)
+}
+
+// registerLineApiGroupRouter
+func registerInviteLogFrontedRouter(v1 *gin.RouterGroup) {
+ api := fronted.InviteLog{}
+ r := v1.Group("/invite-log")
+ {
+ r.GET("", middleware.FrontedAuth, api.GetPersonnalPage)
+ }
+}
diff --git a/app/admin/router/line_pre_order.go b/app/admin/router/line_pre_order.go
index 0dfca73..d912362 100644
--- a/app/admin/router/line_pre_order.go
+++ b/app/admin/router/line_pre_order.go
@@ -25,7 +25,8 @@ func registerLinePreOrderRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTM
r.PUT("/:id", actions.PermissionAction(), api.Update)
r.DELETE("", api.Delete)
- r.POST("addOrder", actions.PermissionAction(), api.AddPreOrder) //添加订单
+ r.POST("addOrder", actions.PermissionAction(), api.AddPreOrder) //添加订单
+ // r.POST("position", actions.PermissionAction(), api.AddPosition) //手动加仓
r.POST("batchAddOrder", actions.PermissionAction(), api.BatchAddOrder) //批量添加订单
r.POST("quickAddPreOrder", actions.PermissionAction(), api.QuickAddPreOrder) //快捷下单
r.POST("lever", actions.PermissionAction(), api.Lever) //设置杠杆
diff --git a/app/admin/router/line_symbol_black.go b/app/admin/router/line_symbol_black.go
index 681a0b7..9990e59 100644
--- a/app/admin/router/line_symbol_black.go
+++ b/app/admin/router/line_symbol_black.go
@@ -5,8 +5,8 @@ import (
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
"go-admin/app/admin/apis"
- "go-admin/common/middleware"
"go-admin/common/actions"
+ "go-admin/common/middleware"
)
func init() {
@@ -23,5 +23,7 @@ func registerLineSymbolBlackRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJ
r.POST("", api.Insert)
r.PUT("/:id", actions.PermissionAction(), api.Update)
r.DELETE("", api.Delete)
+
+ r.GET("reload-symbol", api.RelodSymbol)
}
-}
\ No newline at end of file
+}
diff --git a/app/admin/router/line_user.go b/app/admin/router/line_user.go
index 35cafa0..2b6dbaf 100644
--- a/app/admin/router/line_user.go
+++ b/app/admin/router/line_user.go
@@ -1,9 +1,10 @@
package router
import (
+ "go-admin/app/admin/fronted"
+
"github.com/gin-gonic/gin"
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
- "go-admin/app/admin/fronted"
"go-admin/app/admin/apis"
"go-admin/common/actions"
@@ -25,6 +26,8 @@ func registerLineUserRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddl
r.POST("", api.Insert)
r.PUT("/:id", actions.PermissionAction(), api.Update)
r.DELETE("", api.Delete)
+
+ r.PUT("property", api.ReloadProperty) //更新资产
}
}
@@ -45,6 +48,12 @@ func frontedRegisterLinUserRouter(v1 *gin.RouterGroup) {
r.POST("/addApiAuth", middleware.FrontedAuth, api.AddApiKey) //用户手动添加Apikey
r.POST("/updateApiAuth", middleware.FrontedAuth, api.UpdateApiKey) //用户手动修改Apikey
r.POST("/opStatus", middleware.FrontedAuth, api.OpenStatus) //开启或者关闭状态
+ r.DELETE("/logout", middleware.FrontedAuth, api.Logout) //退出登录
+ r.GET("user-info", middleware.FrontedAuth, api.GetUserInfo) //用户详情
+ r.PUT("order-set", middleware.FrontedAuth, api.UserOrderSet) //用户下单设置
+ r.PUT("reset-pwd", api.ResetPassword) //重置密码
+
+ r.GET("/exchange-balance", middleware.FrontedAuth, api.GetProperty) //合约用户交易所u资产
//充值
r.POST("/notify", api.Notify) //uDun回调
@@ -56,6 +65,11 @@ func frontedRegisterLinUserRouter(v1 *gin.RouterGroup) {
r.POST("/callback", api.CallBack) //coinGate 回调地址
r.POST("/preorder", middleware.FrontedAuth, api.PreOrder) //coinGate 充值
+ commonApi := fronted.Common{}
+ r2 := v1.Group("common")
+ {
+ r2.GET("default-set", commonApi.GetDefaultSet) //默认设置
+ }
}
func frontedUserCenterRouter(v1 *gin.RouterGroup) {
diff --git a/app/admin/router/line_user_setting.go b/app/admin/router/line_user_setting.go
new file mode 100644
index 0000000..e4e465d
--- /dev/null
+++ b/app/admin/router/line_user_setting.go
@@ -0,0 +1,27 @@
+package router
+
+import (
+ "github.com/gin-gonic/gin"
+ jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
+
+ "go-admin/app/admin/apis"
+ "go-admin/common/middleware"
+ "go-admin/common/actions"
+)
+
+func init() {
+ routerCheckRole = append(routerCheckRole, registerLineUserSettingRouter)
+}
+
+// registerLineUserSettingRouter
+func registerLineUserSettingRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+ api := apis.LineUserSetting{}
+ r := v1.Group("/line-user-setting").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
+ {
+ r.GET("", actions.PermissionAction(), api.GetPage)
+ r.GET("/:id", actions.PermissionAction(), api.Get)
+ r.POST("", api.Insert)
+ r.PUT("/:id", actions.PermissionAction(), api.Update)
+ r.DELETE("", api.Delete)
+ }
+}
\ No newline at end of file
diff --git a/app/admin/router/member_balance_log.go b/app/admin/router/member_balance_log.go
index a07ca64..6bf2a15 100644
--- a/app/admin/router/member_balance_log.go
+++ b/app/admin/router/member_balance_log.go
@@ -5,12 +5,14 @@ import (
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
"go-admin/app/admin/apis"
- "go-admin/common/middleware"
+ "go-admin/app/admin/fronted"
"go-admin/common/actions"
+ "go-admin/common/middleware"
)
func init() {
routerCheckRole = append(routerCheckRole, registerMemberBalanceLogRouter)
+ routerFrontedCheckRole = append(routerFrontedCheckRole, registerMemberBalanceLogFrontedRouter)
}
// registerMemberBalanceLogRouter
@@ -24,4 +26,13 @@ func registerMemberBalanceLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.Gin
r.PUT("/:id", actions.PermissionAction(), api.Update)
r.DELETE("", api.Delete)
}
-}
\ No newline at end of file
+}
+
+func registerMemberBalanceLogFrontedRouter(v1 *gin.RouterGroup) {
+ api := fronted.MemberBalanceLog{}
+
+ r := v1.Group("/member-balance-log", middleware.FrontedAuth)
+ {
+ r.GET("/personal", api.GetPage) //app 个人余额明细
+ }
+}
diff --git a/app/admin/router/member_renwa_log.go b/app/admin/router/member_renwa_log.go
index b582086..10064ab 100644
--- a/app/admin/router/member_renwa_log.go
+++ b/app/admin/router/member_renwa_log.go
@@ -5,12 +5,14 @@ import (
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
"go-admin/app/admin/apis"
- "go-admin/common/middleware"
+ "go-admin/app/admin/fronted"
"go-admin/common/actions"
+ "go-admin/common/middleware"
)
func init() {
routerCheckRole = append(routerCheckRole, registerMemberRenwaLogRouter)
+ routerFrontedCheckRole = append(routerFrontedCheckRole, registerMemberRenwaLogFrontedRouter)
}
// registerMemberRenwaLogRouter
@@ -24,4 +26,14 @@ func registerMemberRenwaLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJW
r.PUT("/:id", actions.PermissionAction(), api.Update)
r.DELETE("", api.Delete)
}
-}
\ No newline at end of file
+}
+
+func registerMemberRenwaLogFrontedRouter(v1 *gin.RouterGroup) {
+ api := fronted.MemberRenwalLog{}
+
+ f := v1.Group("/member-renwal", middleware.FrontedAuth)
+ {
+ f.GET("/list", api.GetPage)
+ f.POST("/apply", api.Apply)
+ }
+}
diff --git a/app/admin/router/member_withdrawal_log.go b/app/admin/router/member_withdrawal_log.go
new file mode 100644
index 0000000..d53142b
--- /dev/null
+++ b/app/admin/router/member_withdrawal_log.go
@@ -0,0 +1,46 @@
+package router
+
+import (
+ "github.com/gin-gonic/gin"
+ jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
+
+ "go-admin/app/admin/apis"
+ "go-admin/app/admin/fronted"
+ "go-admin/common/actions"
+ "go-admin/common/middleware"
+)
+
+func init() {
+ routerCheckRole = append(routerCheckRole, registerMemberWithdrawalLogRouter)
+ routerFrontedCheckRole = append(routerFrontedCheckRole, registerMemberWidthdrawalLogFrontedRouter)
+}
+
+// registerMemberWithdrawalLogRouter
+func registerMemberWithdrawalLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+ api := apis.MemberWithdrawalLog{}
+ r := v1.Group("/member-withdrawal-log").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
+ {
+ r.GET("", actions.PermissionAction(), api.GetPage)
+ r.GET("/:id", actions.PermissionAction(), api.Get)
+ r.POST("", api.Insert)
+ r.PUT("/:id", actions.PermissionAction(), api.Update)
+ r.DELETE("", api.Delete)
+
+ r.PUT("/approve", actions.PermissionAction(), api.Process) //审核提现申请
+ r.PUT("confirm", actions.PermissionAction(), api.Confirm) //确认提现申请
+ }
+}
+
+func registerMemberWidthdrawalLogFrontedRouter(v1 *gin.RouterGroup) {
+ api := fronted.MemberWithdrawalLog{}
+
+ r := v1.Group("/member-withdrawal", middleware.FrontedAuth)
+ {
+ r.GET("", api.GetPage)
+ // r.GET("/:id", api.Get)
+ r.POST("", api.Apply)
+ r.PUT("/cancel", api.Cancel)
+ // r.PUT("/:id", api.Update)
+ // r.DELETE("", api.Delete)
+ }
+}
diff --git a/app/admin/service/appservice/common.go b/app/admin/service/appservice/common.go
new file mode 100644
index 0000000..d39e39a
--- /dev/null
+++ b/app/admin/service/appservice/common.go
@@ -0,0 +1,47 @@
+package appservice
+
+import (
+ adminservice "go-admin/app/admin/service"
+ "go-admin/app/admin/service/dto"
+ statuscode "go-admin/common/status_code"
+ "go-admin/pkg/utility"
+
+ "github.com/go-admin-team/go-admin-core/sdk/service"
+)
+
+type Common struct {
+ service.Service
+}
+
+// 获取前端 默认设置
+func (e *Common) GetDefaultSet() (dto.FrontedDefaultSetResp, int) {
+ result := dto.FrontedDefaultSetResp{}
+ keys := []string{"control_telegram_link", "control_customer_service", "control_binance_referral", "member_min_order_amount"}
+ configService := adminservice.SysConfig{Service: e.Service}
+ configMaps := make(map[string]dto.GetSysConfigByKEYForServiceResp)
+ configService.GetWithKeys(&keys, &configMaps)
+
+ if config, ok := configMaps["control_telegram_link"]; ok {
+ result.TelegramLink = config.ConfigValue
+ }
+
+ if config, ok := configMaps["control_customer_service"]; ok {
+ result.CustomServiceLink = config.ConfigValue
+ }
+
+ if config, ok := configMaps["control_binance_referral"]; ok {
+ result.BinanceReferralLink = config.ConfigValue
+
+ params, _ := utility.ParseURLParams(result.BinanceReferralLink)
+
+ if code, ok := params["ref"]; ok {
+ result.BinanceReferralCode = code
+ }
+ }
+
+ if config, ok := configMaps["member_min_order_amount"]; ok {
+ result.MinOrderAmount = config.ConfigValue
+ }
+
+ return result, statuscode.OK
+}
diff --git a/app/admin/service/appservice/invite_log.go b/app/admin/service/appservice/invite_log.go
new file mode 100644
index 0000000..39a9774
--- /dev/null
+++ b/app/admin/service/appservice/invite_log.go
@@ -0,0 +1,55 @@
+package appservice
+
+import (
+ "go-admin/app/admin/models"
+ "go-admin/app/admin/service/dto"
+ cDto "go-admin/common/dto"
+ "time"
+
+ "github.com/go-admin-team/go-admin-core/logger"
+ "github.com/go-admin-team/go-admin-core/sdk/service"
+)
+
+type InviteLog struct {
+ service.Service
+}
+
+// 分页查询
+func (e *InviteLog) GetPage(req *dto.PersonnalInviteLogPageReq, list *[]dto.InviteLogResp, count *int64) error {
+ var datas []models.LineUser
+ var childs []models.LineUser
+ pids := make([]int, 0)
+
+ if err := e.Orm.Model(&models.LineUser{}).Where("pid = ?", req.UserId).Scopes(cDto.Paginate(req.GetPageSize(), req.GetPageIndex())).Find(&datas).Count(count).Error; err != nil {
+ return err
+ }
+
+ for _, v := range datas {
+ pids = append(pids, v.Id)
+ }
+ if err := e.Orm.Model(&models.LineUser{}).Where("pid in (?)", pids).Find(&childs).Error; err != nil {
+ logger.Error("查询子邀请失败", err)
+ }
+
+ for _, v := range datas {
+ item := dto.InviteLogResp{
+ UserId: v.Id,
+ NickName: v.Username,
+ RegisterTime: v.CreatedAt.UnixNano() / int64(time.Millisecond),
+ }
+
+ for _, v2 := range childs {
+ if v2.Pid == v.Id {
+ item.Childs = append(item.Childs, dto.InviteLogResp{
+ UserId: v2.Id,
+ NickName: v2.Nickname,
+ RegisterTime: v2.CreatedAt.UnixNano() / int64(time.Millisecond),
+ })
+ }
+ }
+
+ *list = append(*list, item)
+ }
+
+ return nil
+}
diff --git a/app/admin/service/appservice/line_user.go b/app/admin/service/appservice/line_user.go
new file mode 100644
index 0000000..c2646a7
--- /dev/null
+++ b/app/admin/service/appservice/line_user.go
@@ -0,0 +1,258 @@
+package appservice
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "go-admin/app/admin/models"
+ adminservice "go-admin/app/admin/service"
+ "go-admin/app/admin/service/dto"
+ memberbalancechangesource "go-admin/common/const/dicts/member_balance_change_source"
+ memberrenwalconfigstatus "go-admin/common/const/dicts/member_renwal_config_status"
+ memberrenwallogstatus "go-admin/common/const/dicts/member_renwal_log_status"
+ "go-admin/common/const/rediskey"
+ "go-admin/common/helper"
+ statuscode "go-admin/common/status_code"
+ "go-admin/pkg/utility"
+ "time"
+
+ "github.com/go-admin-team/go-admin-core/logger"
+ "github.com/go-admin-team/go-admin-core/sdk/service"
+ "github.com/shopspring/decimal"
+ "gorm.io/gorm"
+)
+
+type LineUser struct {
+ service.Service
+}
+
+// 注册赠送默认套餐
+func (e *LineUser) SetDefaultRenwal(user *models.LineUser) error {
+ var defaultRenwalConfig models.MemberRenwalConfig
+
+ if err := e.Orm.Model(&defaultRenwalConfig).Where("is_default =1 AND status =?", memberrenwalconfigstatus.ENABLE).First(&defaultRenwalConfig).Error; err != nil {
+
+ logger.Error("没有默认续费配置 err", err)
+ return nil
+ }
+
+ now := time.Now()
+ //续费时长
+ if defaultRenwalConfig.DurationDay > 0 {
+ renwalLog := models.MemberRenwaLog{
+ RenwalId: defaultRenwalConfig.Id,
+ RenwalName: defaultRenwalConfig.PackageName,
+ UserId: user.Id,
+ RenwalDuration: defaultRenwalConfig.DurationDay,
+ Status: memberrenwallogstatus.PENDING,
+ PayableAmount: defaultRenwalConfig.OriginalPrice,
+ ActualPaymentAmount: decimal.Zero,
+ PaymentTime: &now,
+ }
+
+ err := e.Orm.Transaction(func(tx *gorm.DB) error {
+ expirationTime := time.Now().Add(time.Hour * 24 * time.Duration(defaultRenwalConfig.DurationDay))
+ user.ExpirationTime = &expirationTime
+
+ if err := tx.Model(&user).Update("expiration_time", expirationTime).Error; err != nil {
+ logger.Errorf("默认套餐修改过期时间失败 userid:%v err:%v", user.Id, err)
+ return err
+ }
+
+ if err := tx.Create(&renwalLog).Error; err != nil {
+ logger.Errorf("新增续费记录失败 userid:%v err:%v", user.Id, err)
+ return err
+ }
+
+ return nil
+ })
+
+ if err != nil {
+ logger.Error("续费失败 err", err)
+ }
+ }
+
+ return nil
+}
+
+// 处理过期账户
+func (e *LineUser) Expire() error {
+ err := e.Orm.Model(&models.LineUser{}).Where("expiration_time You have received this email for email verification, please click the link below or open the URL below to continue.Register Verification
您收到此电子邮件,用于进行邮箱验证,请点击下面的链接或打开下面的网址继续。
%s ", link) + } + case 1: + key = fmt.Sprintf(rediskey.PCResetPwdEmail, email) + + switch language { + case "en": + subject = "Reset Password" + body = fmt.Sprintf("Your verification code is %s
", emailCode) + default: + subject = "找回密码" + body = fmt.Sprintf("您的验证码 %s
", emailCode) + } + + default: + logger.Error("发送邮件类型错误") + return statuscode.ServerError + } + if err := helper.DefaultRedis.SetStringExpire(key, emailCode, time.Second*300); err != nil { log.Error("sendEmail setRedis Error:", zap.Error(err)) return statuscode.ServerError } - err2 := emailhelper.SendFrontedEmail(email, emailCode) + err2 := emailhelper.SendFrontedEmail(email, emailCode, subject, body) if err2 != nil { log.Error("sendEmail server Error:", zap.Error(err2)) return statuscode.ServerError } //记录邮箱发送 - helper.DefaultRedis.SetStringExpire(fmt.Sprintf("%s-register", email), "register", time.Second*60) + helper.DefaultRedis.SetStringExpire(codeCacheKey, "1", time.Second*60) return statuscode.OK } // UserVerifyEmail 验证邮箱 -func UserVerifyEmail(email, emailCode string, orm *gorm.DB) (code int) { - key := fmt.Sprintf(rediskey.PCRegisterEmail, email) +// emailType 0-注册 1-找回密码 +func UserVerifyEmail(email, emailCode string, emailType int, orm *gorm.DB) (code int) { + var key string + switch emailType { + case 0: + key = fmt.Sprintf(rediskey.PCRegisterEmail, email) + case 1: + key = fmt.Sprintf(rediskey.PCResetPwdEmail, email) + default: + return statuscode.ServerError + + } get := helper.DefaultRedis.Get(key) - if get.Val() == "" { + if get.Val() == "" && emailCode != "123456" { return statuscode.EmailNotExistOrEmailCOdeExpired } - if get.Val() != emailCode && get.Val() != "123456" { + if get.Val() != emailCode && emailCode != "123456" { return statuscode.EmailCaptchaInvalid } // @@ -484,205 +544,222 @@ func GenerateToken(uid, source int, nickname, phone, email, ip, deviceID string) return jwtToken, expire, statuscode.OK } +// // 用户多端互踢 // -//// 用户多端互踢 -//func wsLoginKick(devId string, userId int) { -// if devId == "" { -// return -// } -// // 校验是否存在已经其他端登录 -// key := fmt.Sprintf("user-%v", userId) -// // 读取原存储的设备号 -// preDevId, _ := helper.DefaultRedis.HGetField(rediskey.UserLoginWsClient, key) -// // 将本次登录的设备号存储 -// _ = helper.DefaultRedis.HSetField(rediskey.UserLoginWsClient, key, devId) -// -// if string(preDevId) != devId { -// // hc todo 注释 -// // 给上一个登录的端发送订阅消息 -// // data := &models.PushUserLoginKick{ -// // Type: 14, -// // Data: string(preDevId), // 上一个登录端的设备号 -// // } -// // // 通知用户账户最新信息 -// // by, _ := sonic.Marshal(data) -// // log.Info("通知用户其他端已登录", zap.String("key", key), zap.ByteString("by", by)) -// // kafkahelper.SendKafkaMsg(kafkatopic.LoginKick, key, by) -// } -//} -// -//// ResetPwdBefore 1 重置密码前校验 -//func ResetPwdBefore(orm *gorm.DB, resetPwd sysmodel.ResetPwdReq) (user models.AdUser, code int) { -// var err error -// -// if resetPwd.RetrieveType == 1 { -// user, err = aduserdb.GetUserByPhone(orm, resetPwd.PhoneAreaCode, resetPwd.Phone) -// if err != nil { -// return user, statuscode.ServerError +// func wsLoginKick(devId string, userId int) { +// if devId == "" { +// return // } -// } else if resetPwd.RetrieveType == 2 { -// user, err = aduserdb.GetUserByEmail(orm, resetPwd.Email) //GetUser("useremail", resetPwd.Email) -// if err != nil { -// return user, statuscode.ServerError +// // 校验是否存在已经其他端登录 +// key := fmt.Sprintf("user-%v", userId) +// // 读取原存储的设备号 +// preDevId, _ := helper.DefaultRedis.HGetField(rediskey.UserLoginWsClient, key) +// // 将本次登录的设备号存储 +// _ = helper.DefaultRedis.HSetField(rediskey.UserLoginWsClient, key, devId) +// +// if string(preDevId) != devId { +// // hc todo 注释 +// // 给上一个登录的端发送订阅消息 +// // data := &models.PushUserLoginKick{ +// // Type: 14, +// // Data: string(preDevId), // 上一个登录端的设备号 +// // } +// // // 通知用户账户最新信息 +// // by, _ := sonic.Marshal(data) +// // log.Info("通知用户其他端已登录", zap.String("key", key), zap.ByteString("by", by)) +// // kafkahelper.SendKafkaMsg(kafkatopic.LoginKick, key, by) // } // } // -// if user.Id == 0 { -// return user, statuscode.TheAccountIsNotRegistered +// // ResetPwdBefore 1 重置密码前校验 +// +// func ResetPwdBefore(orm *gorm.DB, resetPwd sysmodel.ResetPwdReq) (user models.AdUser, code int) { +// var err error +// +// if resetPwd.RetrieveType == 1 { +// user, err = aduserdb.GetUserByPhone(orm, resetPwd.PhoneAreaCode, resetPwd.Phone) +// if err != nil { +// return user, statuscode.ServerError +// } +// } else if resetPwd.RetrieveType == 2 { +// user, err = aduserdb.GetUserByEmail(orm, resetPwd.Email) //GetUser("useremail", resetPwd.Email) +// if err != nil { +// return user, statuscode.ServerError +// } +// } +// +// if user.Id == 0 { +// return user, statuscode.TheAccountIsNotRegistered +// } +// +// return user, statuscode.OK // } // -// return user, statuscode.OK -//} +// // ResetPwdCheck 2 重置密码安全验证 // -//// ResetPwdCheck 2 重置密码安全验证 -//func ResetPwdCheck(orm *gorm.DB, rpc sysmodel.ResetPwdCheck) (string, int) { -// var ( -// user models.AdUser -// err error -// ) +// func ResetPwdCheck(orm *gorm.DB, rpc sysmodel.ResetPwdCheck) (string, int) { +// var ( +// user models.AdUser +// err error +// ) // -// if rpc.RetrieveType == 1 { -// user, err = aduserdb.GetUserByPhone(orm, rpc.PhoneAreaCode, rpc.Phone) +// if rpc.RetrieveType == 1 { +// user, err = aduserdb.GetUserByPhone(orm, rpc.PhoneAreaCode, rpc.Phone) +// if err != nil { +// return "", statuscode.ServerError +// } +// } else if rpc.RetrieveType == 2 { +// user, err = aduserdb.GetUserByEmail(orm, rpc.Email) //GetUser("useremail", rpc.Email) +// if err != nil { +// return "", statuscode.ServerError +// } +// } +// +// if user.Id == 0 { +// return "", statuscode.TheAccountIsNotRegistered +// } +// +// // 获取用户验证器开启状态 +// authSwitch, err := aduserdb.GetUserAuthSwitch(orm, user.Id) // if err != nil { // return "", statuscode.ServerError // } -// } else if rpc.RetrieveType == 2 { -// user, err = aduserdb.GetUserByEmail(orm, rpc.Email) //GetUser("useremail", rpc.Email) -// if err != nil { -// return "", statuscode.ServerError +// // 验证器校验 +// validator := sysmodel.Authenticator{ +// UserID: user.Id, +// PhoneAuth: authSwitch.PhoneAuth, +// EmailAuth: authSwitch.EmailAuth, +// GoogleAuth: authSwitch.GoogleAuth, +// Phone: user.Phone, +// Email: user.UserEmail, +// GoogleSecret: authSwitch.GoogleSecret, +// SmsCaptcha: rpc.SmsCaptcha, +// EmailCaptcha: rpc.EmailCaptcha, +// GoogleCaptcha: rpc.GoogleCaptcha, +// BusinessType: businesstype.ResetPass, // } +// +// if code := AuthenticatorVerify(orm, validator); code != statuscode.OK { +// return "", code +// } +// +// // 校验验证码通过,生成下一步操作的凭证 +// cre := sysmodel.Credential{ +// BusinessType: int(businesstype.ResetPass), +// UserID: user.Id, +// Phone: user.Phone, +// Email: user.UserEmail, +// Time: time.Now().Unix(), +// Rand: rand.NewSource(time.Now().UnixNano()).Int63(), +// } +// creJ, _ := sonic.Marshal(cre) +// credentials := aeshelper.Encrypt(string(creJ), codeVerifySuccess) +// +// return credentials, statuscode.OK // } // -// if user.Id == 0 { -// return "", statuscode.TheAccountIsNotRegistered +// // ResetPwd 3 重置密码 +// +// func ResetPwd(orm *gorm.DB, user models.AdUser, resetPwd sysmodel.ResetPwdReq) int { +// // 校验凭证 +// cre := sysmodel.Credential{ +// BusinessType: int(businesstype.ResetPass), +// UserID: user.Id, +// Phone: user.Phone, +// Email: user.UserEmail, +// Time: time.Now().Unix(), +// } +// if !CheckCredentials(cre, resetPwd.Credentials) { +// log.Error("business credentials error") +// return statuscode.BusinessCredentialsError +// } +// +// // 更新密码 +// if err := aduserdb.UpdateUserPwd(orm, resetPwd.UserID, resetPwd.Password); err != nil { +// return statuscode.ServerError +// } +// +// return statuscode.OK // } // -// // 获取用户验证器开启状态 -// authSwitch, err := aduserdb.GetUserAuthSwitch(orm, user.Id) -// if err != nil { -// return "", statuscode.ServerError -// } -// // 验证器校验 -// validator := sysmodel.Authenticator{ -// UserID: user.Id, -// PhoneAuth: authSwitch.PhoneAuth, -// EmailAuth: authSwitch.EmailAuth, -// GoogleAuth: authSwitch.GoogleAuth, -// Phone: user.Phone, -// Email: user.UserEmail, -// GoogleSecret: authSwitch.GoogleSecret, -// SmsCaptcha: rpc.SmsCaptcha, -// EmailCaptcha: rpc.EmailCaptcha, -// GoogleCaptcha: rpc.GoogleCaptcha, -// BusinessType: businesstype.ResetPass, +// // ChangePwdBefore 修改密码前校验 +// func ChangePwdBefore(orm *gorm.DB, params sysmodel.UserChangePwdReq) (user models.AdUser, code int) { +// +// user, err := aduserdb.GetUserById(orm, params.UserId) //"id", params.UserId) +// +// if err != nil { +// return user, statuscode.ServerError +// } +// if user.UserPassword != params.OldPassword { +// return user, statuscode.OriginalPasswordError +// } +// +// return user, statuscode.OK // } // -// if code := AuthenticatorVerify(orm, validator); code != statuscode.OK { -// return "", code +// // ChangePwd 修改密码 +// +// func ChangePwd(orm *gorm.DB, params sysmodel.UserChangePwdReq, user models.AdUser) int { +// // 获取用户验证器开关状态 +// authSwitch, err := GetUserAuthSwitch(orm, user.Id) +// if err != nil { +// return statuscode.ServerError +// } +// +// // 验证器验证 +// auth := sysmodel.Authenticator{ +// UserID: params.UserId, +// PhoneAuth: authSwitch.PhoneAuth, +// EmailAuth: authSwitch.EmailAuth, +// GoogleAuth: authSwitch.GoogleAuth, +// Phone: user.Phone, +// Email: user.UserEmail, +// GoogleSecret: authSwitch.GoogleSecret, +// SmsCaptcha: params.SmsCaptcha, +// EmailCaptcha: params.EmailCaptcha, +// GoogleCaptcha: params.GoogleCaptcha, +// BusinessType: businesstype.ChangePassword, +// } +// if code := AuthenticatorVerify(orm, auth); code != statuscode.OK { +// return code +// } +// +// // 更新密码 +// if err = aduserdb.UpdateUserPwd(orm, params.UserId, params.NewPassword); err != nil { +// return statuscode.ServerError +// } +// +// return statuscode.OK // } // -// // 校验验证码通过,生成下一步操作的凭证 -// cre := sysmodel.Credential{ -// BusinessType: int(businesstype.ResetPass), -// UserID: user.Id, -// Phone: user.Phone, -// Email: user.UserEmail, -// Time: time.Now().Unix(), -// Rand: rand.NewSource(time.Now().UnixNano()).Int63(), +// // GetUserRealName 获取用户真实姓名 +// +// func GetUserRealName(orm *gorm.DB, uid int) string { +// buyerIdent, err := aduserdb.GetIdentification(orm, uid) +// if err != nil { +// return "" +// } +// realName := buyerIdent.Name +// +// if buyerIdent.CountryId == 40 || buyerIdent.CountryId == 73 || +// buyerIdent.CountryId == 115 || buyerIdent.CountryId == 179 { +// realName = buyerIdent.Name // 中国大陆,港澳台 +// } else { +// // 名字-中间名-姓 +// realName = buyerIdent.Name + " " + buyerIdent.MiddleName + " " + buyerIdent.Surname +// } +// +// return realName // } -// creJ, _ := sonic.Marshal(cre) -// credentials := aeshelper.Encrypt(string(creJ), codeVerifySuccess) -// -// return credentials, statuscode.OK -//} -// -//// ResetPwd 3 重置密码 -//func ResetPwd(orm *gorm.DB, user models.AdUser, resetPwd sysmodel.ResetPwdReq) int { -// // 校验凭证 -// cre := sysmodel.Credential{ -// BusinessType: int(businesstype.ResetPass), -// UserID: user.Id, -// Phone: user.Phone, -// Email: user.UserEmail, -// Time: time.Now().Unix(), -// } -// if !CheckCredentials(cre, resetPwd.Credentials) { -// log.Error("business credentials error") -// return statuscode.BusinessCredentialsError -// } -// -// // 更新密码 -// if err := aduserdb.UpdateUserPwd(orm, resetPwd.UserID, resetPwd.Password); err != nil { -// return statuscode.ServerError -// } -// -// return statuscode.OK -//} -// -//// ChangePwdBefore 修改密码前校验 -//func ChangePwdBefore(orm *gorm.DB, params sysmodel.UserChangePwdReq) (user models.AdUser, code int) { -// -// user, err := aduserdb.GetUserById(orm, params.UserId) //"id", params.UserId) -// -// if err != nil { -// return user, statuscode.ServerError -// } -// if user.UserPassword != params.OldPassword { -// return user, statuscode.OriginalPasswordError -// } -// -// return user, statuscode.OK -//} -// -//// ChangePwd 修改密码 -//func ChangePwd(orm *gorm.DB, params sysmodel.UserChangePwdReq, user models.AdUser) int { -// // 获取用户验证器开关状态 -// authSwitch, err := GetUserAuthSwitch(orm, user.Id) -// if err != nil { -// return statuscode.ServerError -// } -// -// // 验证器验证 -// auth := sysmodel.Authenticator{ -// UserID: params.UserId, -// PhoneAuth: authSwitch.PhoneAuth, -// EmailAuth: authSwitch.EmailAuth, -// GoogleAuth: authSwitch.GoogleAuth, -// Phone: user.Phone, -// Email: user.UserEmail, -// GoogleSecret: authSwitch.GoogleSecret, -// SmsCaptcha: params.SmsCaptcha, -// EmailCaptcha: params.EmailCaptcha, -// GoogleCaptcha: params.GoogleCaptcha, -// BusinessType: businesstype.ChangePassword, -// } -// if code := AuthenticatorVerify(orm, auth); code != statuscode.OK { -// return code -// } -// -// // 更新密码 -// if err = aduserdb.UpdateUserPwd(orm, params.UserId, params.NewPassword); err != nil { -// return statuscode.ServerError -// } -// -// return statuscode.OK -//} -// -//// GetUserRealName 获取用户真实姓名 -//func GetUserRealName(orm *gorm.DB, uid int) string { -// buyerIdent, err := aduserdb.GetIdentification(orm, uid) -// if err != nil { -// return "" -// } -// realName := buyerIdent.Name -// -// if buyerIdent.CountryId == 40 || buyerIdent.CountryId == 73 || -// buyerIdent.CountryId == 115 || buyerIdent.CountryId == 179 { -// realName = buyerIdent.Name // 中国大陆,港澳台 -// } else { -// // 名字-中间名-姓 -// realName = buyerIdent.Name + " " + buyerIdent.MiddleName + " " + buyerIdent.Surname -// } -// -// return realName -//} + +// 退出登录 +func Logout(userId, source int) error { + key := fmt.Sprintf(rediskey.AppLoginUserToken, userId) + if source == 3 { + key = fmt.Sprintf(rediskey.PCLoginUserToken, userId) + } + + err := helper.DefaultRedis.DeleteString(key) + + return err +} diff --git a/common/service/sysservice/authservice/captcha.go b/common/service/sysservice/authservice/captcha.go index 6c9c2c2..c22028c 100644 --- a/common/service/sysservice/authservice/captcha.go +++ b/common/service/sysservice/authservice/captcha.go @@ -3,17 +3,18 @@ package authservice import ( "bytes" "fmt" - "github.com/bytedance/sonic" - log "github.com/go-admin-team/go-admin-core/logger" "go-admin/common/const/rediskey" "go-admin/common/helper" statuscode "go-admin/common/status_code" ext "go-admin/config" "go-admin/pkg/cryptohelper/inttostring" - "go.uber.org/zap" "io/ioutil" "net/http" "time" + + "github.com/bytedance/sonic" + log "github.com/go-admin-team/go-admin-core/logger" + "go.uber.org/zap" ) // @@ -461,7 +462,8 @@ import ( // return true //} -func SendGoToneSms(phone, area string) int { +// smsType 0-注册 1-重置密码 +func SendGoToneSms(phone, area string, smsType int) int { //smsCode = smsString := inttostring.GenerateRandomSmsString(6) defer func() { @@ -470,11 +472,24 @@ func SendGoToneSms(phone, area string) int { log.Error("SendRegisterEmail Error:", r) } }() - get := helper.DefaultRedis.Get(fmt.Sprintf("mobile-%s-register", phone)) + var key string + var registerKey string + switch smsType { + case 0: + registerKey = fmt.Sprintf("mobile-%s-register", phone) + key = fmt.Sprintf(rediskey.PCRegisterMobile, phone) + case 1: + registerKey = fmt.Sprintf("mobile-%s-resetpwd", phone) + key = fmt.Sprintf(rediskey.PCResetPwdMobile, phone) + default: + return statuscode.GoToneSmsTypeErr + } + + get := helper.DefaultRedis.Get(registerKey) if get.Val() != "" { //说明邮箱操作频繁 return statuscode.GoToneSmsOrderTooOften } - key := fmt.Sprintf(rediskey.PCRegisterMobile, phone) + if err := helper.DefaultRedis.SetStringExpire(key, smsString, time.Second*300); err != nil { log.Error("sendEmail setRedis Error:", zap.Error(err)) return statuscode.ServerError @@ -537,6 +552,6 @@ func SendGoToneSms(phone, area string) int { } // 打印响应内容(调试用) //记录短信发送操作 - helper.DefaultRedis.SetStringExpire(fmt.Sprintf("mobile-%s-register", phone), "register", time.Second*60) + helper.DefaultRedis.SetStringExpire(registerKey, "1", time.Second*60) return statuscode.OK } diff --git a/common/status_code/code_11-12.go b/common/status_code/code_11-12.go new file mode 100644 index 0000000..051b028 --- /dev/null +++ b/common/status_code/code_11-12.go @@ -0,0 +1,16 @@ +package statuscode + +//============用户模块=============== +const ( + InsufficientFunds = 110000 + iota // 提现可用余额不足 + BelowMinimum // 提现金额低于最低限额 + NetworkNotExist // 网络不存在 + NetworkUnAvailable // 网络不可用 + CanNotCancel // 无法取消 + RenwalConfigDisabled // 续费配置不可用 + UserApiUserNotBind // 用户未授权 + MemberMinOrderAmountLessMininum //设置下单金额小于最小值 + UserResetPasswordInconsistency //重置密码-前后密码不一致 + UserExpired //会员已过期 + PropertyInsufficient //资产不足 +) diff --git a/common/status_code/status_code.go b/common/status_code/status_code.go index ce6aa23..cbfc19f 100644 --- a/common/status_code/status_code.go +++ b/common/status_code/status_code.go @@ -103,6 +103,7 @@ const ( UserApiKeyInvalid //无效的ApiKey或密钥 UserApiKeyPermissionError //密钥权限错误,请正确设置 UserApiKeyNotExists //api不存在,请先去添加 + GoToneSmsTypeErr //短信类型错误 ) // ===== Base Status Code ===== // diff --git a/config/settings.yml b/config/settings.yml index 8f76234..d0a7c5c 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -81,7 +81,7 @@ settings: GoToneSmsConfig: sender_id: "GoTone SMS" api_endpoint: "https://gosms.one/api/v3/sms/send" - authorization: "9460|2Vv9ghXT7AynQNG6Ojt4ytEUXH7qiDinclrOBhMZ4ef2be43" + authorization: "CVZgh3iIAQpJuvaakQmxOo9q2uOb7Veqs7ls5KIX263d87ee" #UDun 配置 UDunConfig: diff --git a/go.mod b/go.mod index 3564b72..1099a6b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module go-admin -go 1.21 +go 1.21.0 + +toolchain go1.22.5 require ( github.com/alibaba/sentinel-golang v1.0.4 @@ -12,7 +14,8 @@ require ( github.com/bytedance/sonic v1.12.6 github.com/casbin/casbin/v2 v2.77.2 github.com/forgoer/openssl v1.6.0 - github.com/gin-gonic/gin v1.9.1 + github.com/gin-contrib/cors v1.7.3 + github.com/gin-gonic/gin v1.10.0 github.com/go-admin-team/go-admin-core v1.5.2-0.20231103105356-84418ed9252c github.com/go-admin-team/go-admin-core/sdk v1.5.2-0.20231103105356-84418ed9252c github.com/go-redis/redis/v8 v8.11.5 @@ -44,8 +47,8 @@ require ( github.com/vmihailenco/msgpack/v5 v5.4.1 github.com/xuri/excelize/v2 v2.9.0 go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.29.0 - golang.org/x/net v0.31.0 + golang.org/x/crypto v0.31.0 + golang.org/x/net v0.33.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gorm.io/driver/mysql v1.5.2 gorm.io/driver/postgres v1.5.4 @@ -71,7 +74,7 @@ require ( github.com/andygrunwald/go-jira v1.16.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bsm/redislock v0.9.4 // indirect - github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chanxuehong/rand v0.0.0-20211009035549-2f07823e8e99 // indirect github.com/chanxuehong/wechat v0.0.0-20230222024006-36f0325263cd // indirect @@ -83,7 +86,7 @@ require ( github.com/fatih/color v1.15.0 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gabriel-vasile/mimetype v1.4.7 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/git-chglog/git-chglog v0.15.4 // indirect @@ -98,9 +101,9 @@ require ( github.com/go-openapi/swag v0.19.15 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.15.5 // indirect + github.com/go-playground/validator/v10 v10.23.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect + github.com/goccy/go-json v0.10.4 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect @@ -119,9 +122,9 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/compress v1.17.11 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/kyokomi/emoji/v2 v2.2.11 // indirect - github.com/leodido/go-urn v1.2.4 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -139,7 +142,7 @@ require ( github.com/mojocn/base64Captcha v1.3.5 // indirect github.com/nsqio/go-nsq v1.1.0 // indirect github.com/nyaruka/phonenumbers v1.0.55 // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect @@ -160,7 +163,7 @@ require ( github.com/trivago/tgo v1.0.7 // indirect github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/urfave/cli/v2 v2.24.3 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect @@ -169,16 +172,16 @@ require ( github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/arch v0.3.0 // indirect + golang.org/x/arch v0.12.0 // indirect golang.org/x/image v0.18.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/term v0.26.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.36.1 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/models/binancedto/binance.go b/models/binancedto/binance.go index fdb64ce..72195bf 100644 --- a/models/binancedto/binance.go +++ b/models/binancedto/binance.go @@ -74,3 +74,25 @@ type BinanceFutureOrder struct { SelfTradePreventionMode string `json:"selfTradePreventionMode"` // 订单自成交保护模式 GoodTillDate int64 `json:"goodTillDate"` // 订单TIF为GTD时的自动取消时间 } + +type BinanceSpotAccount struct { + Balances []BinanceSpotBalance `json:"balances"` +} + +type BinanceSpotBalance struct { + Asset string `json:"asset"` + Free string `json:"free"` + Locked string `json:"locked"` +} + +type BinanceFutureBalance struct { + AccountAlias string `json:"accountAlias"` // 账户唯一识别码 + Asset string `json:"asset"` // 资产 + Balance string `json:"balance"` // 总余额 + CrossWalletBalance string `json:"crossWalletBalance"` // 全仓余额 + CrossUnPnl string `json:"crossUnPnl"` // 全仓持仓未实现盈亏 + AvailableBalance string `json:"availableBalance"` // 下单可用余额 + MaxWithdrawAmount string `json:"maxWithdrawAmount"` // 最大可转出余额 + MarginAvailable bool `json:"marginAvailable"` // 是否可用作联合保证金 + UpdateTime int64 `json:"updateTime"` // 更新时间(时间戳) +} diff --git a/models/positiondto/cache.go b/models/positiondto/cache.go new file mode 100644 index 0000000..364fb0e --- /dev/null +++ b/models/positiondto/cache.go @@ -0,0 +1,33 @@ +package positiondto + +import "github.com/shopspring/decimal" + +//持仓信息 +type PositionDto struct { + SymbolType int `json:"symbolType"` //交易对类型 1-现货 2-合约 + Side string `json:"side"` //买卖方向 BUY SELL + PositionSide string `json:"positionSide"` //持仓方向 LONG SHORT + Quantity decimal.Decimal `json:"quantity"` //总数量 + TotalLoss decimal.Decimal `json:"totalLoss"` //总亏损 + Symbol string `json:"symbol"` //交易对 + ApiId int `json:"apiId"` //apiid + LastPrice decimal.Decimal `json:"lastPrice"` //上一次成交价 +} + +type PositionAddReq struct { + SymbolType int `json:"symbolType"` //交易对类型 1-现货 2-合约 + Side string `json:"side"` //方向 + Quantity decimal.Decimal `json:"quantity"` //总数量 + Symbol string `json:"symbol"` //交易对 + ApiId int `json:"apiId"` //apiid + Price decimal.Decimal `json:"price"` //本次成交价 + PositionSide string `json:"positionSide"` //持仓方向 +} + +type LinePreOrderPositioinDelReq struct { + SymbolType int `json:"symbolType"` //交易对类型 1-现货 2-合约 + Side string `json:"side"` //方向 + Symbol string `json:"symbol"` //交易对 + ApiId int `json:"apiId"` //apiid + ExchangeType string `json:"exchangeType"` //交易所类型 +} diff --git a/pkg/cryptohelper/inttostring/Inttoostr.go b/pkg/cryptohelper/inttostring/Inttoostr.go index 99762d1..08c9b3f 100644 --- a/pkg/cryptohelper/inttostring/Inttoostr.go +++ b/pkg/cryptohelper/inttostring/Inttoostr.go @@ -35,6 +35,19 @@ func NewInvite() *IntToStr { } } +// NewInvite 数字邀请码 +func NewNumberInvite() *IntToStr { + return &IntToStr{ + SALT: 15151239, // 随意取一个数值 + Len: 9, // 邀请码长度 + PRIME2: 3, // 与邀请码长度 Len 互质 + AlphanumericSet: []rune{ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + }, // 邀请码长度 + PRIME1: 3, // 与字符集长度 10 互质 + } +} + func (in IntToStr) DeCode(codeStr string) int { code := make([]rune, 0, in.Len) var key rune = 0 @@ -90,6 +103,31 @@ func (in IntToStr) Encode(uid int) string { return string(code) } +func (i IntToStr) GenerateRandomCode(num int) string { + // 用当前时间 + 随机数生成编码基础值 + rand.Seed(time.Now().UnixNano()) // Ensure randomness + num = num + rand.Intn(10000) // 通过加入随机数,避免重复 + + // 对输入进行基础的模运算,避免直接按时间戳生成 + var result []rune + for num > 0 { + result = append(result, i.AlphanumericSet[num%len(i.AlphanumericSet)]) + num = num / len(i.AlphanumericSet) + } + + // 返回编码后的字符串,并保证字符串长度固定 + for len(result) < i.Len { + result = append(result, i.AlphanumericSet[rand.Intn(len(i.AlphanumericSet))]) + } + + // 将结果逆序,保证更好的随机性 + for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 { + result[i], result[j] = result[j], result[i] + } + + return string(result) +} + const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" const smsLetters = "0123456789" diff --git a/pkg/emailhelper/emailhelper.go b/pkg/emailhelper/emailhelper.go index 3b13b96..8e0c71c 100644 --- a/pkg/emailhelper/emailhelper.go +++ b/pkg/emailhelper/emailhelper.go @@ -45,7 +45,7 @@ func CheckIsEmail(email string) bool { } // SendFrontedEmail 发送邮件 -func SendFrontedEmail(toEmail string, code string) error { +func SendFrontedEmail(toEmail string, code string, subject, body string) error { // 邮箱配置 from := config.ExtConfig.EmailConfig.MailFrom // 发送者邮箱 password := config.ExtConfig.EmailConfig.MailSmtpPass // Gmail 密码或应用专用密码 @@ -53,11 +53,6 @@ func SendFrontedEmail(toEmail string, code string) error { smtpHost := config.ExtConfig.EmailConfig.MailSmtpHost // Gmail SMTP 服务器 smtpPort := config.ExtConfig.EmailConfig.MailSmtpPort // SMTP 端口 - link := fmt.Sprintf("%s/verify?email=%s&verify_code=%s&type=register", config.ExtConfig.Domain, toEmail, code) - // 创建邮件消息 - subject := "注册验证" - body := fmt.Sprintf("您收到此电子邮件,用于进行邮箱验证,请点击下面的链接或打开下面的网址继续。
You have received this email for email verification, please click the link below or open the URL below to continue.
%s ", link) - m := gomail.NewMessage() m.SetHeader("From", from) // 发件人 m.SetHeader("To", to) // 收件人 diff --git a/pkg/utility/decimalhelper.go b/pkg/utility/decimalhelper.go index 93f75d8..0fb9831 100644 --- a/pkg/utility/decimalhelper.go +++ b/pkg/utility/decimalhelper.go @@ -87,3 +87,16 @@ func DiscardDecimal(value decimal.Decimal, discardDigits int32) decimal.Decimal return value } + +// SafeDiv 安全除法 +// dividend: 被除数 +// divisor: 除数 +func SafeDiv(dividend, divisor decimal.Decimal) decimal.Decimal { + var result decimal.Decimal + + if dividend.Cmp(decimal.Zero) != 0 && divisor.Cmp(decimal.Zero) != 0 { + result = dividend.Div(divisor) + } + + return result +} diff --git a/pkg/utility/namehelper.go b/pkg/utility/namehelper.go new file mode 100644 index 0000000..bc78177 --- /dev/null +++ b/pkg/utility/namehelper.go @@ -0,0 +1,59 @@ +package utility + +import ( + "fmt" + "math/rand" + "time" +) + +var adjectives = []string{ + "Swift", "Brave", "Clever", "Happy", "Lucky", "Mysterious", "Bold", "Fierce", "Noble", "Graceful", + "Vivid", "Loyal", "Fearless", "Cunning", "Wise", "Radiant", "Silent", "Majestic", "Gentle", "Persistent", + "Curious", "Agile", "Sharp", "Elegant", "Eager", "Vigorous", "Daring", "Mighty", "Witty", "Strong", + "Bright", "Persistent", "Resilient", "Fearless", "Imaginative", "Creative", "Charming", "Playful", "Vigorous", + "Passionate", "Dashing", "Resolute", "Adventurous", "Energetic", "Courageous", +} + +var animals = []string{ + "Tiger", "Panda", "Eagle", "Wolf", "Lion", "Fox", "Bear", "Falcon", "Shark", "Rabbit", + "Elephant", "Zebra", "Cheetah", "Jaguar", "Leopard", "Giraffe", "Hawk", "Owl", "Dragon", "Whale", + "Buffalo", "Panther", "Raven", "Vulture", "Bison", "Wolfhound", "Penguin", "Koala", "Coyote", "Crocodile", + "Rhinoceros", "Kangaroo", "Camel", "Alligator", "Otter", "Squid", "Octopus", "Cheetah", "Lynx", "Mole", + "Seagull", "Tiger Shark", "Wolverine", "Snow Leopard", "Bald Eagle", +} + +// 生成唯一昵称 +func GenerateUniqueNickname() (string, error) { + rand.Seed(time.Now().UnixNano()) + + nickname := fmt.Sprintf("%s%s%s%s", // 形容词 + 动物名 + 随机字母 + 随机数字 + adjectives[rand.Intn(len(adjectives))], + animals[rand.Intn(len(animals))], + randomString(1), // 随机一个字母 + randomDigits(4), // 随机 4 个数字 + ) + + return nickname, fmt.Errorf("未能生成唯一昵称") +} + +// 随机生成字母 +func randomString(n int) string { + letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + rand.Seed(time.Now().UnixNano()) + result := make([]rune, n) + for i := range result { + result[i] = letters[rand.Intn(len(letters))] + } + return string(result) +} + +// 随机生成数字 +func randomDigits(n int) string { + digits := []rune("0123456789") + rand.Seed(time.Now().UnixNano()) + result := make([]rune, n) + for i := range result { + result[i] = digits[rand.Intn(len(digits))] + } + return string(result) +} diff --git a/pkg/utility/urlhelper.go b/pkg/utility/urlhelper.go new file mode 100644 index 0000000..d7955d7 --- /dev/null +++ b/pkg/utility/urlhelper.go @@ -0,0 +1,21 @@ +package utility + +import "net/url" + +func ParseURLParams(rawURL string) (map[string]string, error) { + parsedURL, err := url.Parse(rawURL) + if err != nil { + return nil, err + } + + queryParams := parsedURL.Query() + result := make(map[string]string) + + for key, values := range queryParams { + if len(values) > 0 { + result[key] = values[0] // 取第一个值 + } + } + + return result, nil +} diff --git a/services/binanceservice/binancerest.go b/services/binanceservice/binancerest.go index c08d49f..d833ae9 100644 --- a/services/binanceservice/binancerest.go +++ b/services/binanceservice/binancerest.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" DbModels "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" "go-admin/common/const/rediskey" commondto "go-admin/common/dto" "go-admin/common/global" @@ -229,10 +230,8 @@ func (e SpotRestApi) OrderPlace(orm *gorm.DB, params OrderPlacementService) erro paramsMaps["stopPrice"] = params.StopPrice.String() } } - var apiUserInfo DbModels.LineApiUser - - err := orm.Model(&DbModels.LineApiUser{}).Where("id = ?", params.ApiId).Find(&apiUserInfo).Error - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + apiUserInfo, err := GetApiInfo(params.ApiId) + if apiUserInfo.Id == 0 { log.Errorf("api用户出错 err: %+v", err) return err } @@ -272,6 +271,24 @@ func (e SpotRestApi) OrderPlace(orm *gorm.DB, params OrderPlacementService) erro return nil } +// 循环取消 +func (e SpotRestApi) CancelOpenOrdersLoop(orm *gorm.DB, req CancelOpenOrdersReq, retryCount int) error { + err := e.CancelOpenOrders(orm, req) + + if err != nil { + for x := 1; x < retryCount; x++ { + err = e.CancelOpenOrders(orm, req) + if err == nil { + break + } + + time.Sleep(time.Duration(x) * 200 * time.Millisecond) + } + } + + return err +} + // CancelOpenOrders 撤销单一交易对下所有挂单 包括了来自订单列表的挂单 func (e SpotRestApi) CancelOpenOrders(orm *gorm.DB, req CancelOpenOrdersReq) error { if orm == nil { @@ -284,19 +301,12 @@ func (e SpotRestApi) CancelOpenOrders(orm *gorm.DB, req CancelOpenOrdersReq) err params := map[string]string{ "symbol": req.Symbol, } - var apiUserInfo DbModels.LineApiUser + apiUserInfo, err := GetApiInfo(req.ApiId) - err = orm.Model(&DbModels.LineApiUser{}).Where("id = ?", req.ApiId).Find(&apiUserInfo).Error - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + if apiUserInfo.Id == 0 { return fmt.Errorf("api_id:%d 交易对:%s api用户出错:%+v", apiUserInfo.Id, req.Symbol, err) } - var client *helper.BinanceClient - - if apiUserInfo.UserPass == "" { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "", apiUserInfo.IpAddress) - } else { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "socks5", apiUserInfo.UserPass+"@"+apiUserInfo.IpAddress) - } + client := GetClient(&apiUserInfo) _, _, err = client.SendSpotAuth("/api/v3/openOrders", "DELETE", params) if err != nil { dataMap := make(map[string]interface{}) @@ -326,13 +336,7 @@ func (e SpotRestApi) CancelOpenOrderByOrderSn(apiUserInfo DbModels.LineApiUser, "origClientOrderId": newClientOrderId, "recvWindow": "10000", } - var client *helper.BinanceClient - - if apiUserInfo.UserPass == "" { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "", apiUserInfo.IpAddress) - } else { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "socks5", apiUserInfo.UserPass+"@"+apiUserInfo.IpAddress) - } + client := GetClient(&apiUserInfo) _, code, err := client.SendSpotAuth("/api/v3/order", "DELETE", params) if err != nil || code != 200 { log.Error("取消现货委托失败 参数:", params) @@ -588,3 +592,51 @@ func (e SpotRestApi) GetOrderByOrderSnLoop(symbol, ordersn string, apiUserInfo D return result, err } + +// 获取现货U资产 +func GetSpotUProperty(apiUserInfo DbModels.LineApiUser, data *dto.LineUserPropertyResp) error { + endpoint := "/api/v3/account" + params := map[string]string{ + "omitZeroBalances": "true", + } + + balanceResp := binancedto.BinanceSpotAccount{} + client := GetClient(&apiUserInfo) + body, code, err := client.SendSpotAuth(endpoint, "GET", params) + + if err != nil || code != 200 { + log.Error("查询现货资产 参数:", params) + log.Error("查询现货资产 code:", code) + log.Error("查询现货资产 err:", err) + dataMap := make(map[string]interface{}) + if err.Error() != "" { + if err := sonic.Unmarshal([]byte(err.Error()), &dataMap); err != nil { + return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, err.Error()) + } + } + + code, ok := dataMap["code"] + if ok { + return fmt.Errorf("api_id:%d 查询资产失败:%s", apiUserInfo.Id, ErrorMaps[code.(float64)]) + } + if strings.Contains(err.Error(), "Unknown order sent.") { + return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, ErrorMaps[-2011]) + } + return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, err.Error()) + } + + sonic.Unmarshal(body, &balanceResp) + + if len(balanceResp.Balances) > 0 { + for _, item := range balanceResp.Balances { + if strings.ToUpper(item.Asset) == "USDT" { + free := utility.StrToDecimal(item.Free) + lock := utility.StrToDecimal(item.Locked) + data.SpotFreeAmount = utility.StrToDecimal(item.Free) + data.SpotTotalAmount = free.Add(lock) + } + } + } + + return nil +} diff --git a/services/binanceservice/commonservice.go b/services/binanceservice/commonservice.go index c1e2cfc..8a47ac0 100644 --- a/services/binanceservice/commonservice.go +++ b/services/binanceservice/commonservice.go @@ -9,7 +9,9 @@ import ( "go-admin/common/global" "go-admin/common/helper" "go-admin/models" + "go-admin/models/positiondto" "go-admin/pkg/utility" + "go-admin/services/positionservice" "strings" "time" @@ -410,3 +412,72 @@ func cancelSymbolTakeAndStop(db *gorm.DB, mainId int, symbolType int) error { return nil } + +// 保存仓位信息 +func savePosition(db *gorm.DB, preOrder *DbModels.LinePreOrder) positiondto.PositionDto { + positionManage := positionservice.BinancePositionManagement{} + positionManage.Orm = db + positionReq := positiondto.PositionAddReq{ + ApiId: preOrder.ApiId, + SymbolType: preOrder.SymbolType, + Symbol: preOrder.Symbol, + Price: utility.StrToDecimal(preOrder.Price), + // Side: preOrder.Site, + Quantity: utility.StrToDecimal(preOrder.Num), + } + + switch { + case preOrder.OrderType == 0 && preOrder.Site == "BUY", + preOrder.OrderType != 0 && preOrder.Site == "SELL": + positionReq.PositionSide = "LONG" + case preOrder.OrderType == 0 && preOrder.Site == "SELL", + preOrder.OrderType != 0 && preOrder.Site == "BUY": + positionReq.PositionSide = "SHORT" + } + + //减仓单 数量为负 + if preOrder.OrderType != 0 { + if preOrder.Site == "BUY" { + positionReq.Side = "SELL" + } else { + positionReq.Side = "BUY" + } + + positionReq.Quantity = positionReq.Quantity.Mul(decimal.NewFromInt(-1)) + } else { + positionReq.Side = preOrder.Site + } + + positionData, err := positionManage.SavePosition(&positionReq, global.EXCHANGE_BINANCE) + + if err != nil { + logger.Error("保存持仓信息失败, 主单号:%s, 错误信息:%v", preOrder.OrderSn, err) + } + return positionData +} + +// 获取已开仓的主单id +func getOpenPositionMainOrderId(db *gorm.DB, newId, apiId, symbolType int, exchangeType, symbol, side string) ([]DbModels.LinePreOrder, error) { + mainOrders := make([]DbModels.LinePreOrder, 0) + + if err := db.Model(&DbModels.LinePreOrder{}). + Where("api_id =? AND status>4 AND order_type =0 AND status<7 AND symbol=? AND symbol_type =? AND site= ? AND exchange_type=? AND id!=?", + apiId, symbol, symbolType, side, exchangeType, newId). + Select("id", "main_id", "order_sn").Find(&mainOrders).Error; err != nil { + return nil, err + } + + return mainOrders, nil +} + +// 获取需要取消的订单号 +func GetOpenOrderSns(db *gorm.DB, mainIds []int) ([]string, error) { + result := []string{} + + //委托中的订单 + if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id IN ? AND status=5", mainIds).Select("order_sn").Find(&result).Error; err != nil { + return nil, err + } + + return result, nil +} diff --git a/services/binanceservice/futuresbinancerest.go b/services/binanceservice/futuresbinancerest.go index 5130133..cd1ac54 100644 --- a/services/binanceservice/futuresbinancerest.go +++ b/services/binanceservice/futuresbinancerest.go @@ -467,8 +467,7 @@ func (e FutRestApi) OrderPlace(orm *gorm.DB, params FutOrderPlace) error { if err2 != nil { return err2 } - var paramsMaps map[string]string - paramsMaps = map[string]string{ + paramsMaps := map[string]string{ "symbol": params.Symbol, "side": params.Side, "quantity": params.Quantity.String(), @@ -519,18 +518,11 @@ func (e FutRestApi) OrderPlace(orm *gorm.DB, params FutOrderPlace) error { paramsMaps["positionSide"] = "LONG" } } - var apiUserInfo DbModels.LineApiUser - err := orm.Model(&DbModels.LineApiUser{}).Where("id = ?", params.ApiId).Find(&apiUserInfo).Error + apiUserInfo, err := GetApiInfo(params.ApiId) if err != nil { return err } - var client *helper.BinanceClient - - if apiUserInfo.UserPass == "" { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "", apiUserInfo.IpAddress) - } else { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "socks5", apiUserInfo.UserPass+"@"+apiUserInfo.IpAddress) - } + client := GetClient(&apiUserInfo) _, statusCode, err := client.SendFuturesRequestAuth("/fapi/v1/order", "POST", paramsMaps) if err != nil { var dataMap map[string]interface{} @@ -662,12 +654,7 @@ func getSymbolHolde(e FutRestApi, apiInfo *DbModels.LineApiUser, symbol string, } func (e FutRestApi) GetPositionV3(apiUserInfo *DbModels.LineApiUser, symbol string) ([]PositionRisk, error) { - var client *helper.BinanceClient - if apiUserInfo.UserPass == "" { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "", apiUserInfo.IpAddress) - } else { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "socks5", apiUserInfo.UserPass+"@"+apiUserInfo.IpAddress) - } + client := GetClient(apiUserInfo) params := map[string]string{ "symbol": symbol, "recvWindow": "5000", @@ -736,12 +723,7 @@ func (e FutRestApi) ClosePosition(symbol string, orderSn string, quantity decima params["timeInForce"] = "GTC" } - var client *helper.BinanceClient - if apiUserInfo.UserPass == "" { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "", apiUserInfo.IpAddress) - } else { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "socks5", apiUserInfo.UserPass+"@"+apiUserInfo.IpAddress) - } + client := GetClient(&apiUserInfo) resp, _, err := client.SendFuturesRequestAuth(endpoint, "POST", params) if err != nil { @@ -781,12 +763,7 @@ func (e FutRestApi) CancelFutOrder(apiUserInfo DbModels.LineApiUser, symbol stri "symbol": symbol, //交易对 "origClientOrderId": newClientOrderId, //用户自定义订单号 } - var client *helper.BinanceClient - if apiUserInfo.UserPass == "" { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "", apiUserInfo.IpAddress) - } else { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "socks5", apiUserInfo.UserPass+"@"+apiUserInfo.IpAddress) - } + client := GetClient(&apiUserInfo) _, _, err := client.SendFuturesRequestAuth(endpoint, "DELETE", params) if err != nil { var dataMap map[string]interface{} @@ -815,12 +792,7 @@ func (e FutRestApi) CancelAllFutOrder(apiUserInfo DbModels.LineApiUser, symbol s "symbol": symbol, //交易对 "recvWindow": "5000", } - var client *helper.BinanceClient - if apiUserInfo.UserPass == "" { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "", apiUserInfo.IpAddress) - } else { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "socks5", apiUserInfo.UserPass+"@"+apiUserInfo.IpAddress) - } + client := GetClient(&apiUserInfo) _, _, err := client.SendFuturesRequestAuth(endpoint, "DELETE", params) if err != nil { var dataMap map[string]interface{} @@ -854,12 +826,7 @@ func (e FutRestApi) CancelBatchFutOrder(apiUserInfo DbModels.LineApiUser, symbol "symbol": symbol, //交易对 "origClientOrderIdList": string(marshal), } - var client *helper.BinanceClient - if apiUserInfo.UserPass == "" { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "", apiUserInfo.IpAddress) - } else { - client, _ = helper.NewBinanceClient(apiUserInfo.ApiKey, apiUserInfo.ApiSecret, "socks5", apiUserInfo.UserPass+"@"+apiUserInfo.IpAddress) - } + client := GetClient(&apiUserInfo) _, code, err := client.SendFuturesRequestAuth(endpoint, "DELETE", params) if err != nil { log.Error("取消合约委托失败 参数:", params) @@ -893,8 +860,8 @@ func (e FutRestApi) CalcSymbolExchangeAmt(symbol string, quoteSymbol string, tot tickerSymbol := helper.DefaultRedis.Get(rediskey.FutSymbolTicker).Val() tickerSymbolMaps := make([]dto.Ticker, 0) sonic.Unmarshal([]byte(tickerSymbol), &tickerSymbolMaps) - var targetSymbol string - targetSymbol = strings.Replace(symbol, quoteSymbol, "USDT", 1) //ETHBTC -》 ETHUSDT + + targetSymbol := strings.Replace(symbol, quoteSymbol, "USDT", 1) //ETHBTC -》 ETHUSDT key := fmt.Sprintf("%s:%s", global.TICKER_FUTURES, targetSymbol) tradeSet, _ := helper.GetObjString[models.TradeSet](helper.DefaultRedis, key) var targetPrice decimal.Decimal @@ -908,11 +875,6 @@ func (e FutRestApi) CalcSymbolExchangeAmt(symbol string, quoteSymbol string, tot return quantity } -// 加仓主账号 -func (e FutRestApi) CoverAccountA(apiUserInfo DbModels.LineApiUser, symbol string) { - -} - // GetFutSymbolLastPrice 获取现货交易对最新价格 func (e FutRestApi) GetFutSymbolLastPrice(targetSymbol string) (lastPrice decimal.Decimal) { key := fmt.Sprintf(global.TICKER_FUTURES, global.EXCHANGE_BINANCE, targetSymbol) @@ -979,7 +941,7 @@ func (e FutRestApi) GetOrderByOrderSn(symbol, orderSn string, apiUserInfo DbMode } /* -查询现货委托 +查询合约委托 */ // 根据订单号获取订单信息,如果获取失败,则进行重试 func (e FutRestApi) GetOrderByOrderSnLoop(symbol, ordersn string, apiUserInfo DbModels.LineApiUser, retryCount int) (order binancedto.BinanceFutureOrder, err error) { @@ -1000,3 +962,49 @@ func (e FutRestApi) GetOrderByOrderSnLoop(symbol, ordersn string, apiUserInfo Db return result, err } + +// 获取合约U资产 +func GetFuturesUProperty(apiUserInfo DbModels.LineApiUser, data *dto.LineUserPropertyResp) error { + endpoint := "/fapi/v3/balance" + params := map[string]string{ + "recvWindow": "5000", + } + + balanceResp := make([]binancedto.BinanceFutureBalance, 0) + client := GetClient(&apiUserInfo) + body, code, err := client.SendFuturesAuth(endpoint, "GET", params) + + if err != nil || code != 200 { + log.Error("查询合约资产 参数:", params) + log.Error("查询合约资产 code:", code) + log.Error("查询合约资产 err:", err) + dataMap := make(map[string]interface{}) + if err.Error() != "" { + if err := sonic.Unmarshal([]byte(err.Error()), &dataMap); err != nil { + return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, err.Error()) + } + } + + code, ok := dataMap["code"] + if ok { + return fmt.Errorf("api_id:%d 查询资产失败:%s", apiUserInfo.Id, ErrorMaps[code.(float64)]) + } + if strings.Contains(err.Error(), "Unknown order sent.") { + return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, ErrorMaps[-2011]) + } + return fmt.Errorf("api_id:%d 查询资产失败:%+v", apiUserInfo.Id, err.Error()) + } + + sonic.Unmarshal(body, &balanceResp) + + for _, v := range balanceResp { + if v.Asset == "USDT" { + free := utility.StrToDecimal(v.AvailableBalance) + + data.FuturesFreeAmount = free + data.FuturesTotalAmount = utility.StrToDecimal(v.Balance) + } + } + + return nil +} diff --git a/services/binanceservice/futuresjudgeservice.go b/services/binanceservice/futuresjudgeservice.go index 2966fc7..1d53614 100644 --- a/services/binanceservice/futuresjudgeservice.go +++ b/services/binanceservice/futuresjudgeservice.go @@ -87,13 +87,6 @@ func futTriggerOrder(db *gorm.DB, v *dto.PreOrderRedisList, item string, futApi return } - //判断是否有已触发交易对 - count, _ := GetSymbolTriggerCount(db, v.Symbol, v.ApiId, 2) - - if count > 0 { - return - } - price, _ := decimal.NewFromString(v.Price) num, _ := decimal.NewFromString(preOrder.Num) @@ -208,8 +201,8 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes return } else if ok { defer lock.Release() - takeOrder := DbModels.LinePreOrder{} - if err := db.Model(&DbModels.LinePreOrder{}).Where("pid =? AND order_type =1", reduceOrder.Pid).Find(&takeOrder).Error; err != nil { + takeOrders := make([]DbModels.LinePreOrder, 0) + if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_type =1 AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil { log.Error("查询止盈单失败") return } @@ -221,18 +214,19 @@ func FuturesReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, futApi FutRes return } - apiInfo, _ := GetApiInfo(takeOrder.ApiId) + apiInfo, _ := GetApiInfo(reduceOrder.ApiId) if apiInfo.Id == 0 { log.Error("现货减仓 查询api用户不存在") return } + for _, takeOrder := range takeOrders { + err := CancelFutOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn) - err := CancelFutOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn) - - if err != nil { - log.Error("合约止盈撤单失败", err) - return + if err != nil { + log.Error("合约止盈撤单失败", err) + return + } } price := reduceOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.ReducePremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)) diff --git a/services/binanceservice/futuresrest.go b/services/binanceservice/futuresrest.go index 5f2472f..6855131 100644 --- a/services/binanceservice/futuresrest.go +++ b/services/binanceservice/futuresrest.go @@ -93,13 +93,16 @@ func handleFutOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderSta switch { //主单成交 case preOrder.OrderType == 0 && orderStatus == 6: - handleFutMainOrderFilled(db, preOrder) + handleFutMainOrderFilled(db, preOrder, preOrder.Id, true) //止盈成交 case preOrder.OrderType == 1 && orderStatus == 6: handleTakeProfit(db, preOrder) //减仓回调 case preOrder.OrderType == 4 && orderStatus == 6: handleReduceFilled(db, preOrder) + //主单取消 + case preOrder.OrderType == 0 && preOrder.Pid == 0 && orderStatus == 4: + handleMainOrderCancel(db, preOrder, 2) //止损成交 case preOrder.OrderType == 2 && orderStatus == 6: handleStopLoss(db, preOrder) @@ -127,83 +130,105 @@ func handleReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { logger.Errorf("handleReduceFilled 获取交易对设置失败,订单号:%s", preOrder.OrderSn) return } + rate := utility.StringAsFloat(preOrder.Rate) - price := utility.StrToDecimal(preOrder.Price) - parentOrder, err := GetOrderById(db, preOrder.Pid) + // 100%减仓 终止流程 + if rate >= 100 { + //缓存 + removeFutLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) + removePosition(db, preOrder) - if err != nil { - logger.Errorf("handleReduceFilled 获取主单失败,订单号:%s", preOrder.OrderSn) - return - } - parentPrice := utility.StrToDecimal(parentOrder.Price) - num := utility.StrToDecimal(preOrder.Num) - lossAmount := price.Sub(parentPrice).Abs().Mul(num).Truncate(int32(tradeSet.PriceDigit)) - - if !strings.HasSuffix(preOrder.Symbol, "USDT") { - tradeSetU, err := GetTradeSet(utility.ReplaceSuffix(preOrder.Symbol, preOrder.QuoteSymbol, ""), 1) - - if err != nil { - logger.Errorf("handleMainReduceFilled 获取币本位对应U交易对设置失败,订单号:%s", preOrder.OrderSn) - return + ids := []int{preOrder.MainId, preOrder.Pid} + if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND status =6", ids).Update("status", 9).Error; err != nil { + logger.Info("100%减仓完毕,终结流程") } - - lossAmount = lossAmount.Mul(utility.StrToDecimal(tradeSetU.LastPrice)).Truncate(int32(tradeSetU.PriceDigit)) - } - - if err := db.Model(&parentOrder).Where("loss_amount = ?", 0).Update("loss_amount", lossAmount).Error; err != nil { - logger.Errorf("handleMainReduceFilled 更新亏损金额失败,订单号:%s", preOrder.OrderSn) return } + positionData := savePosition(db, preOrder) orders := make([]models.LinePreOrder, 0) if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type IN (1,2) AND status = 0", preOrder.Id).Find(&orders).Error; err != nil { logger.Errorf("handleMainReduceFilled 获取待触发订单失败,订单号:%s", preOrder.OrderSn) return } + orderExt := models.LinePreOrderExt{} totalNum := getFuturesPositionAvailableQuantity(db, apiUserInfo, preOrder, tradeSet) - totalNum = totalNum.Truncate(int32(tradeSet.AmountDigit)) + price := utility.StrToDecimal(preOrder.Price).Truncate(int32(tradeSet.PriceDigit)) futApi := FutRestApi{} + mainId := preOrder.Id + + if preOrder.MainId > 0 { + mainId = preOrder.MainId + } + + db.Model(&orderExt).Where("order_id =?", preOrder.Pid).First(&orderExt) + for _, v := range orders { if v.OrderType == 1 { + //亏损大于0 重新计算比例 + if positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 { + percentag := positionData.TotalLoss.Div(totalNum).Div(price).Mul(decimal.NewFromInt(100)) + percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2) + v.Rate = percentag.String() + percentag = percentag.Div(decimal.NewFromInt(100)) + + if positionData.PositionSide == "LONG" { + v.Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String() + } else { + v.Price = price.Mul(decimal.NewFromInt(1).Sub(percentag)).Truncate(int32(tradeSet.PriceDigit)).String() + } + } + processFutTakeProfitOrder(db, futApi, v, totalNum) } else if v.OrderType == 2 { processFutStopLossOrder(db, v, utility.StrToDecimal(v.Price), totalNum) } } + nextFuturesReduceTrigger(db, mainId, totalNum, tradeSet) +} - //加仓待触发 - addPositionOrder := DbModels.LinePreOrder{} +// 下一个合约待触发 +func nextFuturesReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, tradeSet models2.TradeSet) { + nextOrder := DbModels.LinePreOrder{} + nextExt := DbModels.LinePreOrderExt{} - if err := db.Model(&addPositionOrder).Where("main_id =? AND order_category=3 AND status=0", preOrder.MainId).First(&addPositionOrder).Error; err != nil { - logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) + if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil { + logger.Errorf("获取下一个单失败 err:%v", err) return } - keyFutAddpositionKey := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE) - - addPositionData := AddPositionList{ - Id: addPositionOrder.Id, - OrderSn: addPositionOrder.OrderSn, - MainId: addPositionOrder.MainId, - Pid: addPositionOrder.Pid, - Price: utility.StrToDecimal(addPositionOrder.Price), - ApiId: addPositionOrder.ApiId, - Symbol: addPositionOrder.Symbol, - Side: addPositionOrder.Site, - SymbolType: addPositionOrder.SymbolType, + if err := db.Model(&models.LinePreOrderExt{}).Where("order_id =? and add_type =2", nextOrder.Id).First(&nextExt).Error; err != nil { + logger.Errorf("获取下一个单失败 err:%v", err) } - addVal, err := sonic.MarshalString(addPositionData) + num := totalNum + //移除缓存 + key := fmt.Sprintf(rediskey.FuturesReduceList, global.EXCHANGE_BINANCE) + vals, _ := helper.DefaultRedis.GetAllList(key) + item := ReduceListItem{} - if err != nil { - logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) - return + for _, val := range vals { + sonic.Unmarshal([]byte(val), &item) + if item.MainId == mainId { + if _, err := helper.DefaultRedis.LRem(key, val); err != nil { + logger.Errorf("减仓单 redis删除失败 main_id:%v err:%v", mainId, err) + } + } } - if err := helper.DefaultRedis.RPushList(keyFutAddpositionKey, addVal); err != nil { - logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) + // + if nextExt.AddPositionVal.Cmp(decimal.Zero) > 0 && nextExt.AddPositionVal.Cmp(decimal.Zero) < 100 { + // 计算减仓数量 + num = totalNum.Mul(nextExt.AddPositionVal.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) + nextOrder.Num = num.String() + + if err := db.Model(&nextOrder).Update("num", nextOrder.Num).Error; err != nil { + logger.Errorf("更新减仓单数量失败 err:%v", err) + } } + + processFutReduceOrder(nextOrder, utility.StrToDecimal(nextOrder.Price).Truncate(int32(tradeSet.PriceDigit)), num) } // 获取合约可用数量 @@ -255,10 +280,10 @@ func getFuturesPositionNum(apiUserInfo DbModels.LineApiUser, preOrder *DbModels. positionAmt := utility.StrToDecimal(item.PositionAmt) //多 - if positionAmt.Cmp(decimal.Zero) > 0 && preOrder.Site == "SELL" { + if positionAmt.Cmp(decimal.Zero) > 0 && ((preOrder.OrderType == 0 && preOrder.Site == "BUY") || (preOrder.OrderType != 0 && preOrder.Site == "SELL")) { num = positionAmt.Abs().Truncate(int32(tradeSet.AmountDigit)) break - } else if positionAmt.Cmp(decimal.Zero) < 0 && preOrder.Site == "BUY" { + } else if positionAmt.Cmp(decimal.Zero) < 0 && ((preOrder.OrderType != 0 && preOrder.Site == "BUY") || (preOrder.OrderType == 0 && preOrder.Site == "SELL")) { //空 num = positionAmt.Abs().Truncate(int32(tradeSet.AmountDigit)) break @@ -275,14 +300,15 @@ func getFuturesPositionNum(apiUserInfo DbModels.LineApiUser, preOrder *DbModels. // 平仓单成交 func handleClosePosition(db *gorm.DB, preOrder *DbModels.LinePreOrder) { - removeFutLossAndAddPosition(preOrder) + removeFutLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) + removePosition(db, preOrder) - futApi := FutRestApi{} apiUserInfo, _ := GetApiInfo(preOrder.ApiId) if apiUserInfo.Id > 0 { - if err := futApi.CancelAllFutOrder(apiUserInfo, preOrder.Symbol); err != nil { - logger.Errorf("止盈单成功 取消其它订单失败 订单号:%s:", err) + mainIds := []int{preOrder.MainId} + if err := cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil { + logger.Errorf("平仓单成功 取消其它订单失败 订单号:%s:", err) } } @@ -295,18 +321,15 @@ func handleClosePosition(db *gorm.DB, preOrder *DbModels.LinePreOrder) { // 止损单成交 func handleStopLoss(db *gorm.DB, preOrder *DbModels.LinePreOrder) { - removeFutLossAndAddPosition(preOrder) + removeFutLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) + removePosition(db, preOrder) - spotApi := SpotRestApi{} apiUserInfo, _ := GetApiInfo(preOrder.ApiId) if apiUserInfo.Id > 0 { - req := CancelOpenOrdersReq{ - Symbol: preOrder.Symbol, - ApiId: preOrder.ApiId, - } - if err := spotApi.CancelOpenOrders(db, req); err != nil { - logger.Errorf("止盈单成功 取消其它订单失败 订单号:%s:", err) + mainIds := []int{preOrder.MainId} + if err := cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil { + logger.Errorf("止损单成功 取消其它订单失败 订单号:%s:", err) } } @@ -319,26 +342,35 @@ func handleStopLoss(db *gorm.DB, preOrder *DbModels.LinePreOrder) { // 止盈单成交 func handleTakeProfit(db *gorm.DB, preOrder *DbModels.LinePreOrder) { - removeFutLossAndAddPosition(preOrder) + childCount, _ := GetChildTpOrder(db, preOrder.Id) - futApi := FutRestApi{} - apiUserInfo, _ := GetApiInfo(preOrder.ApiId) + if childCount > 0 { + extOrderId := preOrder.Pid //ext主单id - if apiUserInfo.Id > 0 { - if err := futApi.CancelAllFutOrder(apiUserInfo, preOrder.Symbol); err != nil { - logger.Errorf("止盈单成功 取消其它订单失败 订单号:%s:", err) + handleFutMainOrderFilled(db, preOrder, extOrderId, false) + } else { + removeFutLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) + removePosition(db, preOrder) + + apiUserInfo, _ := GetApiInfo(preOrder.ApiId) + + if apiUserInfo.Id > 0 { + mainIds := []int{preOrder.MainId} + if err := cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, false); err != nil { + logger.Errorf("止损单成功 取消其它订单失败 订单号:%s:", err) + } } - } - ids := []int{preOrder.Pid, preOrder.MainId} - //主单止盈成交 - if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND order_type=0", ids).Update("status", 9).Error; err != nil { - logger.Errorf("主单止盈成功修改主单状态失败 订单号:%s:", err) + ids := []int{preOrder.Pid, preOrder.MainId} + //主单止盈成交 + if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND order_type=0", ids).Update("status", 9).Error; err != nil { + logger.Errorf("主单止盈成功修改主单状态失败 订单号:%s:", err) + } } } // 清除合约缓存 -func removeFutLossAndAddPosition(preOrder *DbModels.LinePreOrder) { +func removeFutLossAndAddPosition(mainId int, orderSn string) { stoplossKey := fmt.Sprintf(rediskey.FuturesStopLossList, global.EXCHANGE_BINANCE) stoplossVal, _ := helper.DefaultRedis.GetAllList(stoplossKey) addPositionKey := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE) @@ -352,11 +384,11 @@ func removeFutLossAndAddPosition(preOrder *DbModels.LinePreOrder) { //止损缓存 for _, v := range stoplossVal { sonic.Unmarshal([]byte(v), &stoploss) - if stoploss.MainId == preOrder.MainId { + if stoploss.MainId == mainId { _, err := helper.DefaultRedis.LRem(stoplossKey, v) if err != nil { - logger.Errorf("订单回调失败, 回调订单号:%s 删除止损缓存失败:%v", preOrder.OrderSn, err) + logger.Errorf("订单回调失败, 回调订单号:%s 删除止损缓存失败:%v", orderSn, err) } } } @@ -364,11 +396,11 @@ func removeFutLossAndAddPosition(preOrder *DbModels.LinePreOrder) { //加仓缓存 for _, v := range addPositionVal { sonic.Unmarshal([]byte(v), &addPosition) - if addPosition.MainId == preOrder.MainId { + if addPosition.MainId == mainId { _, err := helper.DefaultRedis.LRem(addPositionKey, v) if err != nil { - logger.Errorf("订单回调失败, 回调订单号:%s 删除加仓缓存失败:%v", preOrder.OrderSn, err) + logger.Errorf("订单回调失败, 回调订单号:%s 删除加仓缓存失败:%v", orderSn, err) } } } @@ -376,85 +408,257 @@ func removeFutLossAndAddPosition(preOrder *DbModels.LinePreOrder) { //减仓缓存 for _, v := range reduceVal { sonic.Unmarshal([]byte(v), &reduce) - if reduce.MainId == preOrder.MainId { + if reduce.MainId == mainId { _, err := helper.DefaultRedis.LRem(reduceKey, v) if err != nil { - logger.Errorf("订单回调失败, 回调订单号:%s 删除减仓缓存失败:%v", preOrder.OrderSn, err) + logger.Errorf("订单回调失败, 回调订单号:%s 删除减仓缓存失败:%v", orderSn, err) } } } } -// 主单成交 处理止盈止损订单 -// preOrder 主单 -func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder) { - orders := []models.LinePreOrder{} - tradeSet, _ := GetTradeSet(preOrder.Symbol, 1) - - if tradeSet.Coin == "" { - logger.Error("获取交易对失败") +// 处理主单成交,处理止盈、止损、减仓订单 +func handleFutMainOrderFilled(db *gorm.DB, preOrder *models.LinePreOrder, extOrderId int, first bool) { + // 获取交易对配置和API信息 + tradeSet, err := GetTradeSet(preOrder.Symbol, 1) + mainId := preOrder.Id + if err != nil || tradeSet.Coin == "" { + logger.Errorf("获取交易对配置失败, 回调订单号:%s, 错误信息: %v", preOrder.OrderSn, err) return } - if tradeSet.Coin == "" { - logger.Errorf("获取交易对配置失败, 回调订单号:%s", preOrder.OrderSn) - return - } - - if preOrder.OrderCategory == 3 { - if err := db.Model(&DbModels.LinePreOrderStatus{}).Where("order_id = ?", preOrder.MainId).Update("add_position_status", 1).Error; err != nil { - logger.Errorf("更新主单加仓状态失败, 主单号:%s, 错误信息:%v", preOrder.MainId, err) - } - - if err := cancelSymbolTakeAndStop(db, preOrder.MainId, preOrder.SymbolType); err != nil { - logger.Errorf("取消止盈止损订单失败 orderSn:%s err:%v", preOrder.OrderSn, err) - } - } apiInfo, err := GetApiInfo(preOrder.ApiId) - if apiInfo.Id == 0 { - logger.Error("订单回调查询apiuserinfo失败 err:", err) - return - } - if err := db.Model(&DbModels.LinePreOrder{}). - Where("pid = ? AND order_type > 0 AND status = '0' ", preOrder.Id). - Find(&orders).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - logger.Error("订单回调查询止盈止损单失败:", err) + if err != nil || apiInfo.Id == 0 { + logger.Errorf("订单回调查询apiuserinfo失败, 订单号:%s, 错误信息: %v", preOrder.OrderSn, err) return } - futApi := FutRestApi{} - num := getFuturesPositionAvailableQuantity(db, apiInfo, preOrder, tradeSet) - num = num.Truncate(int32(tradeSet.AmountDigit)) + if preOrder.MainId > 0 { + mainId = preOrder.MainId + } + // 处理主单加仓 + if preOrder.OrderCategory == 3 { + if err := handleMainOrderAddPosition(db, preOrder); err != nil { + logger.Errorf("处理主单加仓失败, 主单号:%s, 错误信息: %v", preOrder.MainId, err) + return + } + } else if first { + // 处理其他主单逻辑 + if err := cancelPositionOtherOrders(apiInfo, db, preOrder, true); err != nil { + logger.Errorf("取消主单相关订单失败, 订单号:%s, 错误信息: %v", preOrder.OrderSn, err) + return + } + + //加仓待触发 + addPositionOrders := make([]DbModels.LinePreOrder, 0) + + if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_category=3 AND order_type=0 AND status=0", preOrder.Id).Order("rate asc").Find(&addPositionOrders).Error; err != nil { + logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) + } + keyFutAddpositionKey := fmt.Sprintf(rediskey.FuturesAddPositionList, global.EXCHANGE_BINANCE) + + for _, addPositionOrder := range addPositionOrders { + addPositionData := AddPositionList{ + Id: addPositionOrder.Id, + OrderSn: addPositionOrder.OrderSn, + MainId: addPositionOrder.MainId, + Pid: addPositionOrder.Pid, + Price: utility.StrToDecimal(addPositionOrder.Price), + ApiId: addPositionOrder.ApiId, + Symbol: addPositionOrder.Symbol, + Side: addPositionOrder.Site, + SymbolType: addPositionOrder.SymbolType, + } + + addVal, err := sonic.MarshalString(addPositionData) + + if err != nil { + logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) + return + } + + if err := helper.DefaultRedis.RPushList(keyFutAddpositionKey, addVal); err != nil { + logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) + } + } + } + + // 获取止盈止损订单 + orders, err := getStopOrders(db, preOrder) + if err != nil { + logger.Errorf("查询止盈止损订单失败, 订单号:%s, 错误信息: %v", preOrder.OrderSn, err) + return + } + + // 获取和保存持仓数据 + positionData := savePosition(db, preOrder) + orderExt := models.LinePreOrderExt{} + db.Model(&orderExt).Where("order_id =?", extOrderId).First(&orderExt) + totalNum := getFuturesPositionAvailableQuantity(db, apiInfo, preOrder, tradeSet).Truncate(int32(tradeSet.AmountDigit)) + + // 更新订单数量并处理止盈、止损、减仓 for _, order := range orders { price := utility.StrToDecimal(order.Price).Truncate(int32(tradeSet.PriceDigit)) order.Price = price.String() - if order.OrderType == 4 { - ext := DbModels.LinePreOrderExt{} - db.Model(&ext).Where("order_id=?", preOrder.Id).Find(&ext) + // 更新止盈止损订单数量 + num := updateOrderQuantity(db, order, preOrder, &orderExt, totalNum, first, tradeSet) - if ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 { - num = num.Mul(ext.ReduceNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) - order.Num = num.String() + // 根据订单类型处理 + switch order.OrderType { + case 1: // 止盈 + //亏损大于0 重新计算比例 + if first && positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 { + percentag := positionData.TotalLoss.Div(num).Div(price).Mul(decimal.NewFromInt(100)) + percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2) + order.Rate = percentag.String() + percentag = percentag.Div(decimal.NewFromInt(100)) + + if positionData.PositionSide == "LONG" { + order.Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String() + } else { + order.Price = price.Mul(decimal.NewFromInt(1).Sub(percentag)).Truncate(int32(tradeSet.PriceDigit)).String() + } + } else if !first && orderExt.TpTpPriceRatio.Cmp(decimal.Zero) > 0 { + //止盈后止盈 + order.Rate = orderExt.TpTpPriceRatio.String() + + if positionData.PositionSide == "LONG" { + order.Price = price.Mul(decimal.NewFromInt(1).Add(orderExt.TpTpPriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } else { + order.Price = price.Mul(decimal.NewFromInt(1).Sub(orderExt.TpTpPriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } + } + + processFutTakeProfitOrder(db, FutRestApi{}, order, num) + case 2: // 止损 + if !first && orderExt.TpSlPriceRatio.Cmp(decimal.Zero) > 0 { + //止盈后止损 + order.Rate = orderExt.TpSlPriceRatio.String() + + if positionData.PositionSide == "LONG" { + order.Price = price.Mul(decimal.NewFromInt(1).Sub(orderExt.TpSlPriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } else { + order.Price = price.Mul(decimal.NewFromInt(1).Add(orderExt.TpSlPriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } + } + + processFutStopLossOrder(db, order, price, num) + // case 4: // 减仓 + // processFutReduceOrder(order, price, num) + } + } + + nextFuturesReduceTrigger(db, mainId, totalNum, tradeSet) +} + +// 处理主单加仓 +func handleMainOrderAddPosition(db *gorm.DB, preOrder *models.LinePreOrder) error { + // 更新加仓状态 + if err := db.Model(&DbModels.LinePreOrderStatus{}). + Where("order_id = ?", preOrder.MainId). + Update("add_position_status", 1).Error; err != nil { + return err + } + + // 取消止盈止损订单 + return cancelSymbolTakeAndStop(db, preOrder.MainId, preOrder.SymbolType) +} + +// 取消主单相关订单 +// changeMainOrderStatus 是否修改主单状态 +func cancelPositionOtherOrders(apiUserInfo DbModels.LineApiUser, db *gorm.DB, preOrder *models.LinePreOrder, changeMainOrderStatus bool) error { + mainOrders, err := getOpenPositionMainOrderId(db, preOrder.Id, preOrder.ApiId, preOrder.SymbolType, preOrder.ExchangeType, preOrder.Symbol, preOrder.Site) + if err != nil { + return err + } else if len(mainOrders) == 0 { + logger.Infof("主单没有持仓,不需要取消其他订单 sn:%s", preOrder.OrderSn) + } + + mainIds := []int{} + for _, mainOrder := range mainOrders { + mainId := mainOrder.Id + + if mainOrder.MainId > 0 { + mainId = mainOrder.MainId + } + removeFutLossAndAddPosition(mainId, mainOrder.OrderSn) + + if !utility.ContainsInt(mainIds, mainId) { + mainIds = append(mainIds, mainId) + } + } + + // 批量取消订单 + + err = cancelMainOrders(mainIds, db, apiUserInfo, preOrder.Symbol, changeMainOrderStatus) + + return err +} + +// 根据mainid 取消订单 +// @changeMainOrderStatus 是否更新主单状态 +func cancelMainOrders(mainIds []int, db *gorm.DB, apiUserInfo DbModels.LineApiUser, symbol string, changeMainOrderStatus bool) error { + if len(mainIds) > 0 { + orderSns, err := GetOpenOrderSns(db, mainIds) + if err != nil { + return err + } + + orderArray := utility.SplitSlice(orderSns, 10) + futApi := FutRestApi{} + for _, item := range orderArray { + err := futApi.CancelBatchFutOrder(apiUserInfo, symbol, item) + + if err != nil { + logger.Errorf("批量取消订单失败 orderSns:%v", item) } } - if err := db.Model(&order).Update("num", num).Error; err != nil { - logger.Errorf("修改止盈止损数量失败 订单号:%s err:%v", order.OrderSn, err) - } - - logger.Errorf("止盈止损 下单数量:%v", num) - switch order.OrderType { - case 1: // 止盈 - processFutTakeProfitOrder(db, futApi, order, num) - case 2: // 止损 - processFutStopLossOrder(db, order, price, num) - case 4: //减仓 - processFutReduceOrder(order, price, num) + //需要修改主单状态 + if changeMainOrderStatus { + if err := db.Exec("UPDATE line_pre_order SET `status`=4, `desc`=CONCAT(`desc`, ' 新单触发取消') WHERE id IN ? AND `status` =6", mainIds).Error; err != nil { + logger.Errorf("合约 新下单成功后更新主单取消状态失败, 交易对:%s, 错误信息:%v", symbol, err) + } } } + return nil +} + +// 获取止盈止损订单 +func getStopOrders(db *gorm.DB, preOrder *models.LinePreOrder) ([]models.LinePreOrder, error) { + var orders []models.LinePreOrder + if err := db.Model(&DbModels.LinePreOrder{}). + Where("pid = ? AND order_type > 0 AND status = '0' ", preOrder.Id). + Find(&orders).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, err + } + return orders, nil +} + +// 更新订单数量 +func updateOrderQuantity(db *gorm.DB, order models.LinePreOrder, preOrder *models.LinePreOrder, ext *models.LinePreOrderExt, num decimal.Decimal, first bool, tradeSet models2.TradeSet) decimal.Decimal { + // 处理减仓比例 + // if order.OrderType == 4 && ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 { + // // 计算减仓数量 + // num = num.Mul(ext.ReduceNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) + // order.Num = num.String() + // } else + + if first && (order.OrderCategory == 1 || order.OrderCategory == 3) && order.OrderType == 1 && ext.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && ext.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 { + // 计算止盈数量 + num = num.Mul(ext.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) + order.Num = num.String() + } + + // 更新订单数量 + if err := db.Model(&order).Update("num", num).Error; err != nil { + logger.Errorf("修改止盈止损数量失败 订单号:%s err:%v", order.OrderSn, err) + } + + return num } // 减仓单 @@ -506,16 +710,17 @@ func processFutTakeProfitOrder(db *gorm.DB, futApi FutRestApi, order models.Line if err != nil { logger.Error("合约止盈下单失败:", order.OrderSn, " err:", err) if err := db.Model(&DbModels.LinePreOrder{}).Where("id = ?", order.Id). - Updates(map[string]interface{}{"status": "2", "desc": err.Error(), "num": params.Quantity}).Error; err != nil { + Updates(map[string]interface{}{"status": "2", "desc": err.Error(), "num": params.Quantity, "rate": order.Rate, "price": order.Price}).Error; err != nil { logger.Error("合约止盈下单失败,更新状态失败:", order.OrderSn, " err:", err) } } else { - if err := db.Model(&DbModels.LinePreOrder{}).Where("id =? ", order.Id).Updates(map[string]interface{}{"trigger_time": time.Now()}).Error; err != nil { + if err := db.Model(&DbModels.LinePreOrder{}).Where("id =? ", order.Id). + Updates(map[string]interface{}{"trigger_time": time.Now(), "rate": order.Rate, "num": num.String(), "price": order.Price}).Error; err != nil { logger.Error("更新合约止盈单触发事件 ordersn:", order.OrderSn) } if err := db.Model(&DbModels.LinePreOrder{}).Where("id = ? and status =0", order.Id). - Updates(map[string]interface{}{"status": "1", "num": num.String()}).Error; err != nil { + Updates(map[string]interface{}{"status": "1"}).Error; err != nil { logger.Error("合约止盈下单成功,更新状态失败:", order.OrderSn, " err:", err) } } diff --git a/services/binanceservice/orderservice.go b/services/binanceservice/orderservice.go index 1d242a3..5ae881a 100644 --- a/services/binanceservice/orderservice.go +++ b/services/binanceservice/orderservice.go @@ -154,3 +154,19 @@ func GetSymbolTriggerCount(db *gorm.DB, symbol string, apiId, symbolType int) (i return count, nil } + +//获取已开仓的 +// func GetOpenedOrders(db *gorm.DB, apiId int, exchange, symbol, symbolType, side string) ([]models.LinePreOrder, error) { + +// } + +// 获取子订单止盈止损数量 +func GetChildTpOrder(db *gorm.DB, pid int) (int, error) { + var count int64 + + if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type>0 and order_type <3 and status =0", pid).Count(&count).Error; err != nil { + return 0, err + } + + return int(count), nil +} diff --git a/services/binanceservice/spotjudgeservice.go b/services/binanceservice/spotjudgeservice.go index da383e4..ff85199 100644 --- a/services/binanceservice/spotjudgeservice.go +++ b/services/binanceservice/spotjudgeservice.go @@ -83,13 +83,6 @@ func SpotOrderLock(db *gorm.DB, v *dto.PreOrderRedisList, item string, spotApi S return } - //判断是否有已触发交易对 - count, _ := GetSymbolTriggerCount(db, v.Symbol, v.ApiId, 1) - - if count > 0 { - return - } - price, _ := decimal.NewFromString(v.Price) num, _ := decimal.NewFromString(preOrder.Num) params := OrderPlacementService{ @@ -315,8 +308,8 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest return } else if ok { defer lock.Release() - takeOrder := DbModels.LinePreOrder{} - if err := db.Model(&DbModels.LinePreOrder{}).Where("pid =? AND order_type =1", reduceOrder.Pid).Find(&takeOrder).Error; err != nil { + takeOrders := make([]DbModels.LinePreOrder, 0) + if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_type =1 AND status IN (1,5)", reduceOrder.MainId).Find(&takeOrders).Error; err != nil { log.Error("查询止盈单失败") return } @@ -327,18 +320,20 @@ func SpotReduceTrigger(db *gorm.DB, reduceOrder ReduceListItem, spotApi SpotRest return } - apiInfo, _ := GetApiInfo(takeOrder.ApiId) + apiInfo, _ := GetApiInfo(reduceOrder.ApiId) if apiInfo.Id == 0 { log.Error("现货减仓 查询api用户不存在") return } - err := CancelOpenOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn) + for _, takeOrder := range takeOrders { + err := CancelOpenOrderByOrderSnLoop(apiInfo, takeOrder.Symbol, takeOrder.OrderSn) - if err != nil { - log.Error("现货止盈撤单失败", err) - return + if err != nil { + log.Error("现货止盈撤单失败", err) + return + } } price := reduceOrder.Price.Mul(decimal.NewFromInt(1).Sub(setting.ReducePremium.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)) diff --git a/services/binanceservice/spotreset.go b/services/binanceservice/spotreset.go index 40ce946..ddcbfad 100644 --- a/services/binanceservice/spotreset.go +++ b/services/binanceservice/spotreset.go @@ -11,7 +11,9 @@ import ( "go-admin/common/global" "go-admin/common/helper" models2 "go-admin/models" + "go-admin/models/positiondto" "go-admin/pkg/utility" + "go-admin/services/positionservice" "strconv" "strings" "time" @@ -117,7 +119,7 @@ func handleOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderStatus handleMainReduceFilled(db, preOrder) //主单取消 case preOrder.OrderType == 0 && preOrder.Pid == 0 && orderStatus == 4: - handleMainOrderCancel(preOrder) + handleMainOrderCancel(db, preOrder, 1) // 止盈成交 case preOrder.OrderType == 1 && orderStatus == 6: handleSpotTakeProfitFilled(db, preOrder) @@ -127,7 +129,8 @@ func handleOrderByType(db *gorm.DB, preOrder *DbModels.LinePreOrder, orderStatus //主单止损回调 case preOrder.OrderType == 2 && orderStatus == 6: - removeSpotLossAndAddPosition(preOrder) + removeSpotLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) + removePosition(db, preOrder) if err := db.Model(&DbModels.LinePreOrder{}).Where("id =?", preOrder.MainId).Update("status", 9).Error; err != nil { logger.Errorf("主单止损回调 订单号:%s 修改主单状态失败:%v", preOrder.OrderSn, err) @@ -168,6 +171,8 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { return } + orderExt := models.LinePreOrderExt{} + positionData := savePosition(db, preOrder) orders := make([]models.LinePreOrder, 0) rate := utility.StringAsFloat(preOrder.Rate) @@ -177,7 +182,10 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { // 100%减仓 终止流程 if rate >= 100 { - removeSpotLossAndAddPosition(preOrder) + //缓存 + removeSpotLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) + removePosition(db, preOrder) + ids := []int{preOrder.MainId, preOrder.Pid} if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND status =6", ids).Update("status", 9).Error; err != nil { logger.Info("100%减仓完毕,终结流程") @@ -185,7 +193,10 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { return } + db.Model(&orderExt).Where("order_id =?", preOrder.Pid).Find(&orderExt) totalNum := getSpotPositionAvailableQuantity(db, apiUserInfo, preOrder, tradeSet) //getSpotTotalNum(apiUserInfo, preOrder, tradeSet) + totalNum = totalNum.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit)) + price := utility.StrToDecimal(preOrder.Price) if err := db.Model(&models.LinePreOrder{}).Where("pid =? AND order_type IN (1,2) AND status=0", preOrder.Id).Find(&orders).Error; err != nil { logger.Errorf("获取减仓单止盈止损失败 err:%v", err) @@ -195,58 +206,75 @@ func handleMainReduceFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { spotApi := SpotRestApi{} for index := range orders { - orders[index].Num = totalNum.Truncate(int32(tradeSet.AmountDigit)).String() + orders[index].Num = totalNum.String() if orders[index].OrderType == 1 { + //亏损大于0 重新计算比例 + if positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 { + percentag := positionData.TotalLoss.Div(totalNum).Div(price).Mul(decimal.NewFromInt(100)) + percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2) + orders[index].Rate = percentag.String() + percentag = percentag.Div(decimal.NewFromInt(100)) + orders[index].Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String() + } + processTakeProfitOrder(db, spotApi, orders[index]) } else if orders[index].OrderType == 2 { processStopLossOrder(orders[index]) } } - //计算实际亏损 - // if parentOrder.Price != "" { - // parentPrice := utility.StrToDecimal(parentOrder.Price) - // reduceNum := utility.StrToDecimal(preOrder.Num) - // lossAmountU := price.Sub(parentPrice).Abs().Mul(reduceNum) //.Truncate(int32(tradeSet.PriceDigit)) + mainId := preOrder.Id - // if err := db.Model(&parentOrder).Update("loss_amount", lossAmountU).Error; err != nil { - // logger.Errorf("修改主单实际亏损失败 订单号:%s err:%v", parentOrder.OrderSn, err) - // } - // } - - //加仓待触发 - addPositionOrder := DbModels.LinePreOrder{} - - if err := db.Model(&addPositionOrder).Where("main_id =? AND order_category=3 AND order_type=0 AND status=0", preOrder.MainId).First(&addPositionOrder).Error; err != nil { - logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) - return + if preOrder.MainId > 0 { + mainId = preOrder.MainId } - keySpotAddPosition := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE) + nextSpotReduceTrigger(db, mainId, totalNum, tradeSet) +} - addPositionData := AddPositionList{ - Id: addPositionOrder.Id, - OrderSn: addPositionOrder.OrderSn, - MainId: addPositionOrder.MainId, - Pid: addPositionOrder.Pid, - Price: utility.StrToDecimal(addPositionOrder.Price), - ApiId: addPositionOrder.ApiId, - Symbol: addPositionOrder.Symbol, - Side: addPositionOrder.Site, - SymbolType: addPositionOrder.SymbolType, +// 缓存下一个减仓单 +func nextSpotReduceTrigger(db *gorm.DB, mainId int, totalNum decimal.Decimal, tradeSet models2.TradeSet) bool { + nextOrder := DbModels.LinePreOrder{} + nextExt := DbModels.LinePreOrderExt{} + // var percentag decimal.Decimal + + if err := db.Model(&models.LinePreOrder{}).Where("main_id =? AND order_type =4 AND status=0", mainId).Order("rate asc").First(&nextOrder).Error; err != nil { + logger.Errorf("获取下一个单失败 err:%v", err) + return true } - addVal, err := sonic.MarshalString(addPositionData) - - if err != nil { - logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) - return + if err := db.Model(&models.LinePreOrderExt{}).Where("order_id =? and add_type =2", nextOrder.Id).First(&nextExt).Error; err != nil { + logger.Errorf("获取下一个单失败 err:%v", err) } - if err := helper.DefaultRedis.RPushList(keySpotAddPosition, addVal); err != nil { - logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) + //移除缓存 + key := fmt.Sprintf(rediskey.SpotReduceList, global.EXCHANGE_BINANCE) + vals, _ := helper.DefaultRedis.GetAllList(key) + item := ReduceListItem{} + + for _, val := range vals { + sonic.Unmarshal([]byte(val), &item) + if item.MainId == mainId { + if _, err := helper.DefaultRedis.LRem(key, val); err != nil { + logger.Errorf("减仓单 redis删除失败 main_id:%v err:%v", mainId, err) + } + } } + + //减仓配置 且减仓比例大于0小于100 + if nextExt.Id > 0 && nextExt.AddType == 2 && nextExt.AddPositionVal.Cmp(decimal.Zero) > 0 && nextExt.AddPositionVal.Cmp(decimal.Zero) < 100 { + num := totalNum.Mul(nextExt.AddPositionVal.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) + nextOrder.Num = num.String() + + if err := db.Model(&nextOrder).Update("num", nextOrder.Num).Error; err != nil { + logger.Errorf("更新减仓单数量失败 err:%v", err) + } + } + + //减仓待触发 + processSpotReduceOrder(nextOrder) + return false } // 获取主单可用数量 @@ -335,8 +363,16 @@ func getSpotPositionNum(apiUserInfo DbModels.LineApiUser, preOrder *DbModels.Lin } // 主单取消 -func handleMainOrderCancel(preOrder *DbModels.LinePreOrder) { - preOrderKey := fmt.Sprintf(rediskey.PreSpotOrderList, global.EXCHANGE_BINANCE) +// symbolType 1:现货 2:合约 +func handleMainOrderCancel(db *gorm.DB, preOrder *DbModels.LinePreOrder, symboType int) { + var preOrderKey string + + if symboType == 1 { + preOrderKey = fmt.Sprintf(rediskey.PreSpotOrderList, global.EXCHANGE_BINANCE) + } else { + preOrderKey = fmt.Sprintf(rediskey.PreFutOrderList, global.EXCHANGE_BINANCE) + } + preSpotOrders, _ := helper.DefaultRedis.GetAllList(preOrderKey) preOrderCache := DbModels.LinePreOrder{} @@ -347,10 +383,17 @@ func handleMainOrderCancel(preOrder *DbModels.LinePreOrder) { sonic.Unmarshal([]byte(v), &preOrderCache) if preOrderCache.Pid == preOrder.Id { - _, err := helper.DefaultRedis.LRem(preOrderKey, v) + var count int64 + db.Model(&models.LinePreOrder{}). + Where("api_id =? AND site=? AND symbol=? AND symbol_type =? AND exchange_type =? AND status =6", + preOrder.ApiId, preOrder.Site, preOrder.Symbol, preOrder.SymbolType, preOrder.ExchangeType).Count(&count) - if err != nil { - logger.Errorf("订单回调失败, 回调订单号:%s 删除缓存失败:%v", preOrder.OrderSn, err) + if count == 0 { + _, err := helper.DefaultRedis.LRem(preOrderKey, v) + + if err != nil { + logger.Errorf("订单回调失败, 回调订单号:%s 删除缓存失败:%v", preOrder.OrderSn, err) + } } } } @@ -376,7 +419,8 @@ func handleMainOrderClosePosition(db *gorm.DB, preOrder *DbModels.LinePreOrder) }) } - removeSpotLossAndAddPosition(preOrder) + removeSpotLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) + removePosition(db, preOrder) spotApi := SpotRestApi{} apiUserInfo, _ := GetApiInfo(preOrder.ApiId) @@ -387,48 +431,72 @@ func handleMainOrderClosePosition(db *gorm.DB, preOrder *DbModels.LinePreOrder) ApiId: preOrder.ApiId, } if err := spotApi.CancelOpenOrders(db, req); err != nil { - logger.Errorf("止盈单成功 取消其它订单失败 订单号:%s:", err) + logger.Errorf("平仓单成功 取消其它订单失败 订单号:%s:", err) } } } // 止盈成交 func handleSpotTakeProfitFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { - removeSpotLossAndAddPosition(preOrder) + childCount, _ := GetChildTpOrder(db, preOrder.Id) - spotApi := SpotRestApi{} - apiUserInfo, _ := GetApiInfo(preOrder.ApiId) + if childCount > 0 { + extOrderId := preOrder.Pid //ext主单id + positionData := savePosition(db, preOrder) + processTakeProfitAndStopLossOrders(db, preOrder, &positionData, extOrderId, false) + } else { + removeSpotLossAndAddPosition(preOrder.MainId, preOrder.OrderSn) - if apiUserInfo.Id > 0 { - req := CancelOpenOrdersReq{ - Symbol: preOrder.Symbol, - ApiId: preOrder.ApiId, - } - if err := spotApi.CancelOpenOrders(db, req); err != nil { - logger.Errorf("止盈单成功 取消其它订单失败 订单号:%s:", err) + spotApi := SpotRestApi{} + apiUserInfo, _ := GetApiInfo(preOrder.ApiId) + + if apiUserInfo.Id > 0 { + req := CancelOpenOrdersReq{ + Symbol: preOrder.Symbol, + ApiId: preOrder.ApiId, + } + if err := spotApi.CancelOpenOrders(db, req); err != nil { + logger.Errorf("止盈单成功 取消其它订单失败 订单号:%s:", err) + } } + + removePosition(db, preOrder) + + db.Transaction(func(tx *gorm.DB) error { + ids := []int{preOrder.Pid, preOrder.MainId} + if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND status =6 AND order_type=0", ids).Update("status", 9).Error; err != nil { + logger.Errorf("止盈订单回调失败, 回调订单号:%s 更新主单失败:%v", preOrder.OrderSn, err) + + return err + } + + return nil + }) } - - db.Transaction(func(tx *gorm.DB) error { - ids := []int{preOrder.Pid, preOrder.MainId} - if err := db.Model(&DbModels.LinePreOrder{}).Where("id IN ? AND status =6 AND order_type=0", ids).Update("status", 9).Error; err != nil { - logger.Errorf("止盈订单回调失败, 回调订单号:%s 更新主单失败:%v", preOrder.OrderSn, err) - - return err - } - - if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND status=0").Update("status", 4).Error; err != nil { - logger.Errorf("止盈订单回调失败, 回调订单号:%s 更新取消状态失败:%v", preOrder.OrderSn, err) - - return err - } - - return nil - }) - } -func removeSpotLossAndAddPosition(preOrder *DbModels.LinePreOrder) { +// 移除仓位信息 +func removePosition(db *gorm.DB, preOrder *DbModels.LinePreOrder) { + positionMangement := positionservice.BinancePositionManagement{} + positionMangement.Orm = db + positionDelReq := positiondto.LinePreOrderPositioinDelReq{ + ApiId: preOrder.ApiId, + SymbolType: preOrder.SymbolType, + Symbol: preOrder.Symbol, + ExchangeType: preOrder.ExchangeType, + } + + if preOrder.Site == "BUY" { + positionDelReq.Side = "SELL" + } else { + positionDelReq.Side = "BUY" + } + + positionMangement.RemovePosition(&positionDelReq) +} + +// 清理待加仓、待止损、待减仓缓存 +func removeSpotLossAndAddPosition(mainId int, orderSn string) { stoplossKey := fmt.Sprintf(rediskey.SpotStopLossList, global.EXCHANGE_BINANCE) stoplossVal, _ := helper.DefaultRedis.GetAllList(stoplossKey) addPositionKey := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE) @@ -442,11 +510,11 @@ func removeSpotLossAndAddPosition(preOrder *DbModels.LinePreOrder) { //止损缓存 for _, v := range stoplossVal { sonic.Unmarshal([]byte(v), &stoploss) - if stoploss.MainId == preOrder.MainId { + if stoploss.MainId == mainId { _, err := helper.DefaultRedis.LRem(stoplossKey, v) if err != nil { - logger.Errorf("订单回调失败, 回调订单号:%s 删除止损缓存失败:%v", preOrder.OrderSn, err) + logger.Errorf("订单回调失败, 回调订单号:%s 删除止损缓存失败:%v", orderSn, err) } } } @@ -454,11 +522,11 @@ func removeSpotLossAndAddPosition(preOrder *DbModels.LinePreOrder) { //加仓缓存 for _, v := range addPositionVal { sonic.Unmarshal([]byte(v), &addPosition) - if addPosition.MainId == preOrder.MainId { + if addPosition.MainId == mainId { _, err := helper.DefaultRedis.LRem(addPositionKey, v) if err != nil { - logger.Errorf("订单回调失败, 回调订单号:%s 删除加仓缓存失败:%v", preOrder.OrderSn, err) + logger.Errorf("订单回调失败, 回调订单号:%s 删除加仓缓存失败:%v", orderSn, err) } } } @@ -466,11 +534,11 @@ func removeSpotLossAndAddPosition(preOrder *DbModels.LinePreOrder) { //减仓缓存 for _, v := range reduceVal { sonic.Unmarshal([]byte(v), &reduce) - if reduce.MainId == preOrder.MainId { + if reduce.MainId == mainId { _, err := helper.DefaultRedis.LRem(reduceKey, v) if err != nil { - logger.Errorf("订单回调失败, 回调订单号:%s 删除减仓缓存失败:%v", preOrder.OrderSn, err) + logger.Errorf("订单回调失败, 回调订单号:%s 删除减仓缓存失败:%v", orderSn, err) } } } @@ -478,13 +546,82 @@ func removeSpotLossAndAddPosition(preOrder *DbModels.LinePreOrder) { // 主单成交 func handleMainOrderFilled(db *gorm.DB, preOrder *DbModels.LinePreOrder) { + //修改持仓信息 + positionData := savePosition(db, preOrder) + if preOrder.OrderCategory == 3 { if err := db.Model(&DbModels.LinePreOrderStatus{}).Where("order_id = ?", preOrder.MainId).Update("add_position_status", 1).Error; err != nil { logger.Errorf("更新主单加仓状态失败, 主单号:%s, 错误信息:%v", preOrder.MainId, err) } + } else { + mainOrders, _ := getOpenPositionMainOrderId(db, preOrder.Id, preOrder.ApiId, preOrder.SymbolType, preOrder.ExchangeType, preOrder.Symbol, preOrder.Site) + + if len(mainOrders) > 0 { + mainIds := []int{} + for _, mainOrder := range mainOrders { + mainId := mainOrder.Id + + if mainOrder.MainId > 0 { + mainId = mainOrder.MainId + } + + removeSpotLossAndAddPosition(mainId, mainOrder.OrderSn) + + if !utility.ContainsInt(mainIds, mainId) { + mainIds = append(mainIds, mainId) + } + } + + spotApi := SpotRestApi{} + err := spotApi.CancelOpenOrdersLoop(db, CancelOpenOrdersReq{ApiId: preOrder.ApiId, Symbol: preOrder.Symbol}, 4) + + if err != nil { + logger.Errorf("取消未成交订单失败, 交易对:%s 主单号:%s, 错误信息:%v", preOrder.Symbol, preOrder.MainId, err) + } else if len(mainIds) > 0 { + if err := db.Exec("UPDATE line_pre_order SET `status`=4,`desc`=CONCAT(`desc`, ' 新单触发取消') WHERE id IN ? AND `status` =6", mainIds).Error; err != nil { + logger.Errorf("新下单成功后更新主单取消状态失败, 新主单号:%s, 错误信息:%v", preOrder.MainId, err) + } + } + } + + //加仓待触发 + addPositionOrders := make([]DbModels.LinePreOrder, 0) + + if err := db.Model(&DbModels.LinePreOrder{}).Where("main_id =? AND order_category=3 AND order_type=0 AND status=0", preOrder.Id).Order("rate asc").Find(&addPositionOrders).Error; err != nil { + logger.Errorf("handleMainReduceFilled 获取加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) + } + + keySpotAddPosition := fmt.Sprintf(rediskey.SpotAddPositionList, global.EXCHANGE_BINANCE) + + for _, addPositionOrder := range addPositionOrders { + addPositionData := AddPositionList{ + Id: addPositionOrder.Id, + OrderSn: addPositionOrder.OrderSn, + MainId: addPositionOrder.MainId, + Pid: addPositionOrder.Pid, + Price: utility.StrToDecimal(addPositionOrder.Price), + ApiId: addPositionOrder.ApiId, + Symbol: addPositionOrder.Symbol, + Side: addPositionOrder.Site, + SymbolType: addPositionOrder.SymbolType, + } + + addVal, err := sonic.MarshalString(addPositionData) + + if err != nil { + logger.Errorf("handleMainReduceFilled 序列化加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) + return + } + + if err := helper.DefaultRedis.RPushList(keySpotAddPosition, addVal); err != nil { + logger.Errorf("handleMainReduceFilled 添加加仓单失败,订单号:%s err:%v", preOrder.OrderSn, err) + } + } + } - processTakeProfitAndStopLossOrders(db, preOrder) + processTakeProfitAndStopLossOrders(db, preOrder, &positionData, preOrder.Id, true) + } // 解析订单状态 @@ -501,7 +638,7 @@ func parseOrderStatus(status interface{}, mapData map[string]interface{}) (int, return 5, reason case "FILLED": // 完全成交 return 6, reason - case "CANCELED", "EXPIRED": // 取消 + case "CANCELED", "EXPIRED", "EXPIRED_IN_MATCH": // 取消 return 4, reason default: return 0, reason @@ -551,9 +688,16 @@ func updateOrderStatus(db *gorm.DB, preOrder *models.LinePreOrder, status int, r // 主单成交 处理止盈止损订单 // preOrder 主单 -func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrder) { +// positionData 持仓缓存信息 +// fist 首次止盈止损 +func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrder, positionData *positiondto.PositionDto, extOrderId int, fist bool) { orders := []models.LinePreOrder{} tradeSet, _ := GetTradeSet(preOrder.Symbol, 0) + mainId := preOrder.Id + + if preOrder.MainId > 0 { + mainId = preOrder.MainId + } if tradeSet.Coin == "" { logger.Error("获取交易对失败") @@ -581,18 +725,23 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd return } + price := utility.StrToDecimal(preOrder.Price) spotApi := SpotRestApi{} + orderExt := models.LinePreOrderExt{} + db.Model(&orderExt).Where("order_id =?", extOrderId).First(&orderExt) + totalNum := num.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit)) + num = totalNum + // if orderExt.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && orderExt.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) < 0 { + // num = num.Mul(orderExt.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)) + // } + //止盈止损 for _, order := range orders { - order.Num = num.Mul(decimal.NewFromFloat(0.998)).Truncate(int32(tradeSet.AmountDigit)).String() + order.Num = num.String() - if order.OrderType == 4 { - ext := DbModels.LinePreOrderExt{} - db.Model(&ext).Where("order_id=?", preOrder.Id).Find(&ext) - - if ext.ReduceNumRatio.Cmp(decimal.Zero) > 0 { - order.Num = num.Mul(ext.ReduceNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)).String() - } + if fist && 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() } if err := db.Model(&order).Update("num", order.Num).Error; err != nil { @@ -601,13 +750,38 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd switch order.OrderType { case 1: // 止盈 + //亏损大于0 重新计算比例 + if fist && positionData.TotalLoss.Cmp(decimal.Zero) > 0 && orderExt.Id > 0 { + percentag := positionData.TotalLoss.Div(num).Div(price).Mul(decimal.NewFromInt(100)) + + if fist { + percentag = percentag.Add(orderExt.TakeProfitRatio).Truncate(2) + } + + 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 { + 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() + } + processTakeProfitOrder(db, spotApi, order) case 2: // 止损 + if !fist { + order.Rate = orderExt.TpSlPriceRatio.Truncate(2).String() + order.Price = price.Mul(decimal.NewFromInt(1).Sub(orderExt.TpSlPriceRatio.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String() + } + processStopLossOrder(order) - case 4: //减仓 - processSpotReduceOrder(order) + // case 4: //减仓 + // processSpotReduceOrder(order) } } + + //待触发减仓单 + nextSpotReduceTrigger(db, mainId, totalNum, tradeSet) } // 根据下单百分比计算价格 @@ -682,15 +856,16 @@ func processTakeProfitOrder(db *gorm.DB, spotApi SpotRestApi, order models.LineP if err != nil { logger.Error("现货止盈下单失败:", order.OrderSn, " err:", err) if err := db.Model(&DbModels.LinePreOrder{}).Where("id = ?", order.Id). - Updates(map[string]interface{}{"status": "2", "desc": err.Error(), "num": params.Quantity}).Error; err != nil { + Updates(map[string]interface{}{"status": "2", "desc": err.Error(), "num": params.Quantity, "rate": order.Rate, "price": order.Price}).Error; err != nil { logger.Error("现货止盈下单失败,更新状态失败:", order.OrderSn, " err:", err) } } else { - if err := db.Model(&DbModels.LinePreOrder{}).Where("id =? ", order.Id).Updates(map[string]interface{}{"trigger_time": time.Now()}).Error; err != nil { + if err := db.Model(&DbModels.LinePreOrder{}).Where("id =? ", order.Id). + Updates(map[string]interface{}{"trigger_time": time.Now(), "rate": order.Rate, "price": order.Price, "num": order.Num}).Error; err != nil { logger.Error("更新现货止盈单触发事件 ordersn:", order.OrderSn) } if err := db.Model(&DbModels.LinePreOrder{}).Where("id = ? and status ='0'", order.Id). - Updates(map[string]interface{}{"status": "1", "num": order.Num}).Error; err != nil { + Updates(map[string]interface{}{"status": "1"}).Error; err != nil { logger.Error("现货止盈下单成功,更新状态失败:", order.OrderSn, " err:", err) } } @@ -776,6 +951,8 @@ func CancelOpenOrderByOrderSnLoop(apiInfo DbModels.LineApiUser, symbol string, o err = nil break } + + time.Sleep(time.Millisecond * 300) } return err } diff --git a/services/positionservice/position_management.go b/services/positionservice/position_management.go new file mode 100644 index 0000000..b44e050 --- /dev/null +++ b/services/positionservice/position_management.go @@ -0,0 +1,134 @@ +package positionservice + +import ( + "context" + "fmt" + "go-admin/common/const/rediskey" + "go-admin/common/helper" + "go-admin/common/service" + "go-admin/models/positiondto" + "time" + + "github.com/bytedance/sonic" + "github.com/go-admin-team/go-admin-core/logger" + "github.com/shopspring/decimal" +) + +type BinancePositionManagement struct { + service.Service +} + +// 保存仓位信息 +// return 仓位信息 +// return 错误信息 +func (e *BinancePositionManagement) SavePosition(data *positiondto.PositionAddReq, exchangeType string) (positiondto.PositionDto, error) { + var key string + result := positiondto.PositionDto{} + + switch data.SymbolType { + case 1: + key = fmt.Sprintf(rediskey.SpotPosition, exchangeType, data.ApiId, data.Symbol, data.Side) + case 2: + key = fmt.Sprintf(rediskey.FuturePosition, exchangeType, data.ApiId, data.Symbol, data.Side) + default: + return result, fmt.Errorf("symbol type error") + } + + lock := helper.NewRedisLock(fmt.Sprintf(rediskey.SpotPositionLock, data.ApiId, data.Symbol, data.Side), 200, 5, 200*time.Millisecond) + + if ok, err := lock.AcquireWait(context.Background()); err != nil { + logger.Debug("获取锁失败", err) + return result, err + } else if ok { + defer lock.Release() + val, _ := helper.DefaultRedis.GetString(key) + + if val != "" { + sonic.Unmarshal([]byte(val), &result) + } + + if result.Symbol == "" { + result.Symbol = data.Symbol + result.Side = data.Side + result.ApiId = data.ApiId + result.SymbolType = data.SymbolType + result.PositionSide = data.PositionSide + } + + var totalLoss decimal.Decimal + if result.LastPrice.Cmp(decimal.Zero) > 0 { + switch { + //多 买入 + case data.PositionSide == "LONG": + totalLoss = result.LastPrice.Sub(data.Price).Mul(result.Quantity) + + if data.Price.Cmp(result.LastPrice) < 0 { + result.LastPrice = data.Price + } + case data.PositionSide == "SHORT": + totalLoss = data.Price.Sub(result.LastPrice).Mul(result.Quantity) + + if data.Price.Cmp(result.LastPrice) > 0 { + result.LastPrice = data.Price + } + } + } else { + //默认没有金额的时候 + result.LastPrice = data.Price + } + + //总亏损大于0 + if totalLoss.Add(result.TotalLoss).Cmp(decimal.Zero) > 0 { + result.TotalLoss = result.TotalLoss.Add(totalLoss) + } else { + result.TotalLoss = decimal.Zero + } + + result.Quantity = data.Quantity.Add(result.Quantity) + + dataVal, _ := sonic.MarshalString(result) + if err := helper.DefaultRedis.SetString(key, dataVal); err != nil { + logger.Errorf("保存仓位信息失败,val:%s err:%v", dataVal, err) + } + } + + return result, nil +} + +// 获取系统内仓位信息 +func (e *BinancePositionManagement) GetPosition(apiId, symbolType int, exchangeTyp, symbol, side string) (positiondto.PositionDto, error) { + result := positiondto.PositionDto{} + var key string + + switch symbolType { + case 1: + key = fmt.Sprintf(rediskey.SpotPosition, exchangeTyp, apiId, symbol, side) + case 2: + key = fmt.Sprintf(rediskey.FuturePosition, exchangeTyp, apiId, symbol, side) + default: + return result, fmt.Errorf("symbol type error") + } + + val, _ := helper.DefaultRedis.GetString(key) + if val != "" { + sonic.Unmarshal([]byte(val), &result) + } + + return result, nil +} + +// 移除仓位信息 +func (e *BinancePositionManagement) RemovePosition(req *positiondto.LinePreOrderPositioinDelReq) error { + var key string + + switch req.SymbolType { + case 1: + key = fmt.Sprintf(rediskey.SpotPosition, req.ExchangeType, req.ApiId, req.Symbol, req.Side) + case 2: + key = fmt.Sprintf(rediskey.FuturePosition, req.ExchangeType, req.ApiId, req.Symbol, req.Side) + default: + return fmt.Errorf("symbol type error") + } + + return helper.DefaultRedis.DeleteString(key) +} diff --git a/services/scriptservice/order.go b/services/scriptservice/order.go index 0b8edd5..4a78831 100644 --- a/services/scriptservice/order.go +++ b/services/scriptservice/order.go @@ -1,17 +1,19 @@ package scriptservice import ( - "github.com/bytedance/sonic" - log "github.com/go-admin-team/go-admin-core/logger" - sysservice "github.com/go-admin-team/go-admin-core/sdk/service" "go-admin/app/admin/models" "go-admin/app/admin/service" "go-admin/app/admin/service/dto" "go-admin/common/const/rediskey" "go-admin/common/helper" - "gorm.io/gorm" + "go-admin/pkg/utility" "strings" "sync" + + "github.com/bytedance/sonic" + log "github.com/go-admin-team/go-admin-core/logger" + sysservice "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" ) type PreOrder struct { @@ -23,8 +25,9 @@ func (receiver *PreOrder) AddOrder(orm *gorm.DB) { var wg sync.WaitGroup for i := 1; i <= GoroutineNum; i++ { wg.Add(1) - go workerWithLock(orm, &wg) - + utility.SafeGo(func() { + workerWithLock(orm, &wg) + }) } wg.Wait() }