1
This commit is contained in:
194
app/admin/apis/wm_network.go
Normal file
194
app/admin/apis/wm_network.go
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
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 WmNetwork struct {
|
||||||
|
api.Api
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取网络配置列表
|
||||||
|
// @Summary 获取网络配置列表
|
||||||
|
// @Description 获取网络配置列表
|
||||||
|
// @Tags 网络配置
|
||||||
|
// @Param networkName query string false "网络名称"
|
||||||
|
// @Param code query string false "网络代码"
|
||||||
|
// @Param receiveAddress query string false "接收钱包地址"
|
||||||
|
// @Param pageSize query int false "页条数"
|
||||||
|
// @Param pageIndex query int false "页码"
|
||||||
|
// @Success 200 {object} response.Response{data=response.Page{list=[]models.WmNetwork}} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/wm-network [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e WmNetwork) GetPage(c *gin.Context) {
|
||||||
|
req := dto.WmNetworkGetPageReq{}
|
||||||
|
s := service.WmNetwork{}
|
||||||
|
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.WmNetwork, 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.WmNetwork} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/wm-network/{id} [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e WmNetwork) Get(c *gin.Context) {
|
||||||
|
req := dto.WmNetworkGetReq{}
|
||||||
|
s := service.WmNetwork{}
|
||||||
|
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.WmNetwork
|
||||||
|
|
||||||
|
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.WmNetworkInsertReq true "data"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}"
|
||||||
|
// @Router /api/v1/wm-network [post]
|
||||||
|
// @Security Bearer
|
||||||
|
// func (e WmNetwork) Insert(c *gin.Context) {
|
||||||
|
// req := dto.WmNetworkInsertReq{}
|
||||||
|
// s := service.WmNetwork{}
|
||||||
|
// 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.WmNetworkUpdateReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}"
|
||||||
|
// @Router /api/v1/wm-network/{id} [put]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e WmNetwork) Update(c *gin.Context) {
|
||||||
|
req := dto.WmNetworkUpdateReq{}
|
||||||
|
s := service.WmNetwork{}
|
||||||
|
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.WmNetworkDeleteReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}"
|
||||||
|
// @Router /api/v1/wm-network [delete]
|
||||||
|
// @Security Bearer
|
||||||
|
// func (e WmNetwork) Delete(c *gin.Context) {
|
||||||
|
// s := service.WmNetwork{}
|
||||||
|
// req := dto.WmNetworkDeleteReq{}
|
||||||
|
// 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(), "删除成功")
|
||||||
|
// }
|
||||||
205
app/admin/apis/wm_token.go
Normal file
205
app/admin/apis/wm_token.go
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
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 WmToken struct {
|
||||||
|
api.Api
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取代币配置列表
|
||||||
|
// @Summary 获取代币配置列表
|
||||||
|
// @Description 获取代币配置列表
|
||||||
|
// @Tags 代币配置
|
||||||
|
// @Param networkId query string false "网络id"
|
||||||
|
// @Param tokenName query string false "代币名称"
|
||||||
|
// @Param pageSize query int false "页条数"
|
||||||
|
// @Param pageIndex query int false "页码"
|
||||||
|
// @Success 200 {object} response.Response{data=response.Page{list=[]models.WmToken}} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/wm-token [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e WmToken) GetPage(c *gin.Context) {
|
||||||
|
req := dto.WmTokenGetPageReq{}
|
||||||
|
s := service.WmToken{}
|
||||||
|
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.WmToken, 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.WmToken} "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/wm-token/{id} [get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e WmToken) Get(c *gin.Context) {
|
||||||
|
req := dto.WmTokenGetReq{}
|
||||||
|
s := service.WmToken{}
|
||||||
|
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.WmToken
|
||||||
|
|
||||||
|
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.WmTokenInsertReq true "data"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}"
|
||||||
|
// @Router /api/v1/wm-token [post]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e WmToken) Insert(c *gin.Context) {
|
||||||
|
req := dto.WmTokenInsertReq{}
|
||||||
|
s := service.WmToken{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置创建人
|
||||||
|
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.WmTokenUpdateReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}"
|
||||||
|
// @Router /api/v1/wm-token/{id} [put]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e WmToken) Update(c *gin.Context) {
|
||||||
|
req := dto.WmTokenUpdateReq{}
|
||||||
|
s := service.WmToken{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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.WmTokenDeleteReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}"
|
||||||
|
// @Router /api/v1/wm-token [delete]
|
||||||
|
// @Security Bearer
|
||||||
|
func (e WmToken) Delete(c *gin.Context) {
|
||||||
|
s := service.WmToken{}
|
||||||
|
req := dto.WmTokenDeleteReq{}
|
||||||
|
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(), "删除成功")
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"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/api"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
|
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
|
||||||
_ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
|
_ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
|
||||||
@ -34,7 +35,7 @@ func (e WmTransfer) GetPage(c *gin.Context) {
|
|||||||
s := service.WmTransfer{}
|
s := service.WmTransfer{}
|
||||||
err := e.MakeContext(c).
|
err := e.MakeContext(c).
|
||||||
MakeOrm().
|
MakeOrm().
|
||||||
Bind(&req).
|
Bind(&req, binding.Form).
|
||||||
MakeService(&s.Service).
|
MakeService(&s.Service).
|
||||||
Errors
|
Errors
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -112,6 +113,12 @@ func (e WmTransfer) Insert(c *gin.Context) {
|
|||||||
e.Error(500, err, err.Error())
|
e.Error(500, err, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := req.Valid(); err != nil {
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 设置创建人
|
// 设置创建人
|
||||||
req.SetCreateBy(user.GetUserId(c))
|
req.SetCreateBy(user.GetUserId(c))
|
||||||
|
|
||||||
@ -124,41 +131,6 @@ func (e WmTransfer) Insert(c *gin.Context) {
|
|||||||
e.OK(req.GetId(), "创建成功")
|
e.OK(req.GetId(), "创建成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 修改批量转账任务
|
|
||||||
// @Summary 修改批量转账任务
|
|
||||||
// @Description 修改批量转账任务
|
|
||||||
// @Tags 批量转账任务
|
|
||||||
// @Accept application/json
|
|
||||||
// @Product application/json
|
|
||||||
// @Param id path int true "id"
|
|
||||||
// @Param data body dto.WmTransferUpdateReq true "body"
|
|
||||||
// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}"
|
|
||||||
// @Router /api/v1/wm-transfer/{id} [put]
|
|
||||||
// @Security Bearer
|
|
||||||
func (e WmTransfer) Update(c *gin.Context) {
|
|
||||||
req := dto.WmTransferUpdateReq{}
|
|
||||||
s := service.WmTransfer{}
|
|
||||||
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 删除批量转账任务
|
// Delete 删除批量转账任务
|
||||||
// @Summary 删除批量转账任务
|
// @Summary 删除批量转账任务
|
||||||
// @Description 删除批量转账任务
|
// @Description 删除批量转账任务
|
||||||
@ -191,3 +163,24 @@ func (e WmTransfer) Delete(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
e.OK(req.GetId(), "删除成功")
|
e.OK(req.GetId(), "删除成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清理数据
|
||||||
|
func (e WmTransfer) ClearAll(c *gin.Context) {
|
||||||
|
s := service.WmTransfer{}
|
||||||
|
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.ClearAll()
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("清理数据失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK(nil, "清理数据成功")
|
||||||
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"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/api"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
|
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
|
||||||
_ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
|
_ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
|
||||||
@ -54,6 +55,53 @@ func (e WmTransferItem) GetPage(c *gin.Context) {
|
|||||||
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 导出excel
|
||||||
|
func (e WmTransferItem) Export(c *gin.Context) {
|
||||||
|
s := service.WmTransferItem{}
|
||||||
|
req := dto.WmTransferItemExportReq{}
|
||||||
|
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)
|
||||||
|
err = s.ExportExcel(&req, p, c)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("导出excel失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportAutoLog 导出自动转账日志
|
||||||
|
func (e WmTransferItem) ExportAutoLog(c *gin.Context) {
|
||||||
|
s := service.WmTransferItem{}
|
||||||
|
req := dto.WmTransferItemAutoLogPageReq{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.ExportAutoLog(&req, c)
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("导出自动转账日志失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get 获取批量转账明细
|
// Get 获取批量转账明细
|
||||||
// @Summary 获取批量转账明细
|
// @Summary 获取批量转账明细
|
||||||
// @Description 获取批量转账明细
|
// @Description 获取批量转账明细
|
||||||
@ -189,3 +237,28 @@ func (e WmTransferItem) Delete(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
e.OK(req.GetId(), "删除成功")
|
e.OK(req.GetId(), "删除成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAutoTransferLogPage 获取自动转账日志列表
|
||||||
|
func (e WmTransferItem) GetAutoTransferLogPage(c *gin.Context) {
|
||||||
|
req := dto.WmTransferItemAutoLogPageReq{}
|
||||||
|
s := service.WmTransferItem{}
|
||||||
|
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([]dto.WmTransferItemResp, 0)
|
||||||
|
var count int64
|
||||||
|
err = s.GetAutoTransferLogPage(&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(), "查询成功")
|
||||||
|
}
|
||||||
|
|||||||
@ -152,3 +152,25 @@ func (e WmWalletInfo) Delete(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
e.OK(req.GetId(), "删除成功")
|
e.OK(req.GetId(), "删除成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearAll 清空所有钱包信息
|
||||||
|
func (e WmWalletInfo) ClearAll(c *gin.Context) {
|
||||||
|
s := service.WmWalletInfo{}
|
||||||
|
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.ClearAll()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("清空所有钱包信息失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK(nil, "清空成功")
|
||||||
|
}
|
||||||
|
|||||||
28
app/admin/models/wm_network.go
Normal file
28
app/admin/models/wm_network.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/common/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WmNetwork struct {
|
||||||
|
models.Model
|
||||||
|
|
||||||
|
NetworkName string `json:"networkName" gorm:"type:varchar(20);comment:网络名称"`
|
||||||
|
Code string `json:"code" gorm:"type:varchar(50);comment:网络代码"`
|
||||||
|
ReceiveAddress string `json:"receiveAddress" gorm:"type:varchar(255);comment:接收钱包地址"`
|
||||||
|
models.ModelTime
|
||||||
|
models.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (WmNetwork) TableName() string {
|
||||||
|
return "wm_network"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *WmNetwork) Generate() models.ActiveRecord {
|
||||||
|
o := *e
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *WmNetwork) GetId() interface{} {
|
||||||
|
return e.Id
|
||||||
|
}
|
||||||
36
app/admin/models/wm_token.go
Normal file
36
app/admin/models/wm_token.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/common/models"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WmToken struct {
|
||||||
|
models.Model
|
||||||
|
|
||||||
|
NetworkId int `json:"networkId" gorm:"type:bigint;comment:网络id"`
|
||||||
|
NetworkCode string `json:"code" gorm:"-"`
|
||||||
|
TokenName string `json:"tokenName" gorm:"type:varchar(20);comment:代币名称"`
|
||||||
|
TokenAddress string `json:"tokenAddress" gorm:"type:varchar(50);comment:代币地址"`
|
||||||
|
Decimals int `json:"decimals" gorm:"type:int;comment:代币精度"`
|
||||||
|
IsAuto int `json:"isAuto" gorm:"type:tinyint;comment:开启自动转账 1-开启 2-关闭"`
|
||||||
|
TriggerAmount decimal.Decimal `json:"triggerAmount" gorm:"type:decimal(18,8);comment:触发数量"`
|
||||||
|
TransType int `json:"transType" gorm:"type:tinyint;comment:转账类型 1-百分比 2-实际金额"`
|
||||||
|
TransValue decimal.Decimal `json:"transValue" gorm:"type:decimal(18,8);comment:转账值"`
|
||||||
|
models.ModelTime
|
||||||
|
models.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (WmToken) TableName() string {
|
||||||
|
return "wm_token"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *WmToken) Generate() models.ActiveRecord {
|
||||||
|
o := *e
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *WmToken) GetId() interface{} {
|
||||||
|
return e.Id
|
||||||
|
}
|
||||||
@ -1,18 +1,22 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"go-admin/common/models"
|
"go-admin/common/models"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type WmTransfer struct {
|
type WmTransfer struct {
|
||||||
models.Model
|
models.Model
|
||||||
|
|
||||||
Type int64 `json:"type" gorm:"type:tinyint;comment:类型 0-百分比 1-实际金额"`
|
NetworkId int `json:"networkId" gorm:"type:int;comment:网络id"`
|
||||||
TransferType int64 `json:"transferType" gorm:"type:tinyint;comment:转账类型 0-批量转出 1-批量汇总"`
|
TokenAddress string `json:"tokenAddress" gorm:"type:varchar(255);comment:代币地址"`
|
||||||
Status int64 `json:"status" gorm:"type:tinyint;comment:状态"`
|
Type int `json:"type" gorm:"type:tinyint;comment:类型 0-百分比 1-实际金额"`
|
||||||
|
TransferType int `json:"transferType" gorm:"type:tinyint;comment:转账类型 0-批量转出 1-批量汇总"`
|
||||||
|
Status int `json:"status" gorm:"type:tinyint;comment:状态"`
|
||||||
Remark string `json:"remark" gorm:"type:varchar(255);comment:备注信息"`
|
Remark string `json:"remark" gorm:"type:varchar(255);comment:备注信息"`
|
||||||
|
Total int `json:"total" gorm:"-"`
|
||||||
|
Sucess int `json:"sucess" gorm:"-"`
|
||||||
|
Fail int `json:"fail" gorm:"-"`
|
||||||
|
Pending int `json:"pending" gorm:"-"`
|
||||||
models.ModelTime
|
models.ModelTime
|
||||||
models.ControlBy
|
models.ControlBy
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,28 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"go-admin/common/models"
|
"go-admin/common/models"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WmTransferItem struct {
|
type WmTransferItem struct {
|
||||||
models.Model
|
models.Model
|
||||||
|
|
||||||
|
NetworkId int `json:"networkId" gorm:"type:int;comment:网络ID"`
|
||||||
|
TransferId int `json:"transferId" gorm:"type:int;comment:转账记录ID"`
|
||||||
|
IsAuto int `json:"isAuto" gorm:"type:tinyint;comment:是否自动转账 1-是 2-否 "`
|
||||||
TokenAddress string `json:"tokenAddress" gorm:"type:varchar(50);comment:代币地址"`
|
TokenAddress string `json:"tokenAddress" gorm:"type:varchar(50);comment:代币地址"`
|
||||||
|
Decimals int `json:"decimals" gorm:"type:int;comment:代币精度"`
|
||||||
FromAddress string `json:"fromAddress" gorm:"type:varchar(50);comment:来源地址"`
|
FromAddress string `json:"fromAddress" gorm:"type:varchar(50);comment:来源地址"`
|
||||||
ToAddress string `json:"toAddress" gorm:"type:varchar(50);comment:目标地址"`
|
ToAddress string `json:"toAddress" gorm:"type:varchar(50);comment:目标地址"`
|
||||||
Amount string `json:"amount" gorm:"type:decimal(18,8);comment:代币数量"`
|
Amount decimal.Decimal `json:"amount" gorm:"type:decimal(18,8);comment:代币数量"`
|
||||||
Type string `json:"type" gorm:"type:tinyint;comment:类型 0-主账号百分比 1-实际数量"`
|
Type int `json:"type" gorm:"type:tinyint;comment:类型 0-主账号百分比 1-实际数量"`
|
||||||
TypeValue string `json:"typeValue" gorm:"type:decimal(18,8);comment:操作类型值"`
|
TypeValue decimal.Decimal `json:"typeValue" gorm:"type:decimal(18,8);comment:操作类型值"`
|
||||||
PrivateKey string `json:"privateKey" gorm:"type:varchar(255);comment:私钥"`
|
PrivateKey string `json:"privateKey" gorm:"type:varchar(255);comment:私钥"`
|
||||||
|
Status int `json:"status" gorm:"type:tinyint;comment:状态 0-默认 1-已发起 2-成功 3-失败"`
|
||||||
|
Hash string `json:"hash" gorm:"type:varchar(255);comment:交易hash"`
|
||||||
|
Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
|
||||||
models.ModelTime
|
models.ModelTime
|
||||||
models.ControlBy
|
models.ControlBy
|
||||||
}
|
}
|
||||||
|
|||||||
27
app/admin/router/wm_network.go
Normal file
27
app/admin/router/wm_network.go
Normal file
@ -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/actions"
|
||||||
|
"go-admin/common/middleware"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
routerCheckRole = append(routerCheckRole, registerWmNetworkRouter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerWmNetworkRouter
|
||||||
|
func registerWmNetworkRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
|
||||||
|
api := apis.WmNetwork{}
|
||||||
|
r := v1.Group("/wm-network").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)
|
||||||
|
}
|
||||||
|
}
|
||||||
27
app/admin/router/wm_token.go
Normal file
27
app/admin/router/wm_token.go
Normal file
@ -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, registerWmTokenRouter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerWmTokenRouter
|
||||||
|
func registerWmTokenRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
|
||||||
|
api := apis.WmToken{}
|
||||||
|
r := v1.Group("/wm-token").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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,8 +5,8 @@ import (
|
|||||||
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
|
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
|
||||||
|
|
||||||
"go-admin/app/admin/apis"
|
"go-admin/app/admin/apis"
|
||||||
"go-admin/common/middleware"
|
|
||||||
"go-admin/common/actions"
|
"go-admin/common/actions"
|
||||||
|
"go-admin/common/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -21,7 +21,9 @@ func registerWmTransferRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMid
|
|||||||
r.GET("", actions.PermissionAction(), api.GetPage)
|
r.GET("", actions.PermissionAction(), api.GetPage)
|
||||||
r.GET("/:id", actions.PermissionAction(), api.Get)
|
r.GET("/:id", actions.PermissionAction(), api.Get)
|
||||||
r.POST("", api.Insert)
|
r.POST("", api.Insert)
|
||||||
r.PUT("/:id", actions.PermissionAction(), api.Update)
|
// r.PUT("/:id", actions.PermissionAction(), api.Update)
|
||||||
r.DELETE("", api.Delete)
|
r.DELETE("", api.Delete)
|
||||||
|
|
||||||
|
r.DELETE("clear", api.ClearAll)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,8 +5,8 @@ import (
|
|||||||
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
|
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
|
||||||
|
|
||||||
"go-admin/app/admin/apis"
|
"go-admin/app/admin/apis"
|
||||||
"go-admin/common/middleware"
|
|
||||||
"go-admin/common/actions"
|
"go-admin/common/actions"
|
||||||
|
"go-admin/common/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -23,5 +23,9 @@ func registerWmTransferItemRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJW
|
|||||||
r.POST("", api.Insert)
|
r.POST("", api.Insert)
|
||||||
r.PUT("/:id", actions.PermissionAction(), api.Update)
|
r.PUT("/:id", actions.PermissionAction(), api.Update)
|
||||||
r.DELETE("", api.Delete)
|
r.DELETE("", api.Delete)
|
||||||
|
|
||||||
|
r.GET("/export", actions.PermissionAction(), api.Export)
|
||||||
|
r.GET("/export-auto-log", actions.PermissionAction(), api.ExportAutoLog)
|
||||||
|
r.GET("/auto-log", actions.PermissionAction(), api.GetAutoTransferLogPage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,5 +23,6 @@ func registerWmWalletInfoRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTM
|
|||||||
r.POST("", api.Insert)
|
r.POST("", api.Insert)
|
||||||
// r.PUT("/:id", actions.PermissionAction(), api.Update)
|
// r.PUT("/:id", actions.PermissionAction(), api.Update)
|
||||||
r.DELETE("", api.Delete)
|
r.DELETE("", api.Delete)
|
||||||
|
r.DELETE("clear", api.ClearAll)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
106
app/admin/service/dto/wm_network.go
Normal file
106
app/admin/service/dto/wm_network.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/common/dto"
|
||||||
|
common "go-admin/common/models"
|
||||||
|
"go-admin/utils/ethtransferhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WmNetworkGetPageReq struct {
|
||||||
|
dto.Pagination `search:"-"`
|
||||||
|
NetworkName string `form:"networkName" search:"type:contains;column:network_name;table:wm_network" comment:"网络名称"`
|
||||||
|
Code string `form:"code" search:"type:exact;column:code;table:wm_network" comment:"网络代码"`
|
||||||
|
ReceiveAddress string `form:"receiveAddress" search:"type:exact;column:receive_address;table:wm_network" comment:"接收钱包地址"`
|
||||||
|
WmNetworkOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
type WmNetworkOrder struct {
|
||||||
|
Id string `form:"idOrder" search:"type:order;column:id;table:wm_network"`
|
||||||
|
NetworkName string `form:"networkNameOrder" search:"type:order;column:network_name;table:wm_network"`
|
||||||
|
Code string `form:"codeOrder" search:"type:order;column:code;table:wm_network"`
|
||||||
|
ReceiveAddress string `form:"receiveAddressOrder" search:"type:order;column:receive_address;table:wm_network"`
|
||||||
|
CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:wm_network"`
|
||||||
|
UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:wm_network"`
|
||||||
|
CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:wm_network"`
|
||||||
|
UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:wm_network"`
|
||||||
|
DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:wm_network"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WmNetworkGetPageReq) GetNeedSearch() interface{} {
|
||||||
|
return *m
|
||||||
|
}
|
||||||
|
|
||||||
|
type WmNetworkInsertReq struct {
|
||||||
|
Id int `json:"-" comment:"主键id"` // 主键id
|
||||||
|
NetworkName string `json:"networkName" comment:"网络名称"`
|
||||||
|
Code string `json:"code" comment:"网络代码"`
|
||||||
|
ReceiveAddress string `json:"receiveAddress" comment:"接收钱包地址"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmNetworkInsertReq) Generate(model *models.WmNetwork) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.NetworkName = s.NetworkName
|
||||||
|
model.Code = s.Code
|
||||||
|
model.ReceiveAddress = s.ReceiveAddress
|
||||||
|
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmNetworkInsertReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
type WmNetworkUpdateReq struct {
|
||||||
|
Id int `uri:"id" comment:"主键id"` // 主键id
|
||||||
|
NetworkName string `json:"networkName" comment:"网络名称"`
|
||||||
|
// Code string `json:"code" comment:"网络代码"`
|
||||||
|
ReceiveAddress string `json:"receiveAddress" comment:"接收钱包地址"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmNetworkUpdateReq) Valid() error {
|
||||||
|
if s.NetworkName == "" {
|
||||||
|
return errors.New("网络名称不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ethtransferhelper.IsValidAddress(s.ReceiveAddress) {
|
||||||
|
return errors.New("接收钱包地址格式不正确")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (s *WmNetworkUpdateReq) Generate(model *models.WmNetwork) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.NetworkName = s.NetworkName
|
||||||
|
// model.Code = s.Code
|
||||||
|
model.ReceiveAddress = s.ReceiveAddress
|
||||||
|
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmNetworkUpdateReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// WmNetworkGetReq 功能获取请求参数
|
||||||
|
type WmNetworkGetReq struct {
|
||||||
|
Id int `uri:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmNetworkGetReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// WmNetworkDeleteReq 功能删除请求参数
|
||||||
|
type WmNetworkDeleteReq struct {
|
||||||
|
Ids []int `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmNetworkDeleteReq) GetId() interface{} {
|
||||||
|
return s.Ids
|
||||||
|
}
|
||||||
140
app/admin/service/dto/wm_token.go
Normal file
140
app/admin/service/dto/wm_token.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/common/dto"
|
||||||
|
common "go-admin/common/models"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WmTokenGetPageReq struct {
|
||||||
|
dto.Pagination `search:"-"`
|
||||||
|
NetworkId string `form:"networkId" search:"type:contains;column:network_id;table:wm_token" comment:"网络id"`
|
||||||
|
TokenName string `form:"tokenName" search:"type:contains;column:token_name;table:wm_token" comment:"代币名称"`
|
||||||
|
WmTokenOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
type WmTokenOrder struct {
|
||||||
|
Id string `form:"idOrder" search:"type:order;column:id;table:wm_token"`
|
||||||
|
NetworkId string `form:"networkIdOrder" search:"type:order;column:network_id;table:wm_token"`
|
||||||
|
TokenName string `form:"tokenNameOrder" search:"type:order;column:token_name;table:wm_token"`
|
||||||
|
TokenAddress string `form:"tokenAddressOrder" search:"type:order;column:token_address;table:wm_token"`
|
||||||
|
Decimals string `form:"decimalsOrder" search:"type:order;column:decimals;table:wm_token"`
|
||||||
|
IsAuto string `form:"isAutoOrder" search:"type:order;column:is_auto;table:wm_token"`
|
||||||
|
CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:wm_token"`
|
||||||
|
UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:wm_token"`
|
||||||
|
CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:wm_token"`
|
||||||
|
UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:wm_token"`
|
||||||
|
DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:wm_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WmTokenGetPageReq) GetNeedSearch() interface{} {
|
||||||
|
return *m
|
||||||
|
}
|
||||||
|
|
||||||
|
type WmTokenInsertReq struct {
|
||||||
|
Id int `json:"-" comment:"主键"` // 主键
|
||||||
|
NetworkId int `json:"networkId" comment:"网络id"`
|
||||||
|
TokenName string `json:"tokenName" comment:"代币名称"`
|
||||||
|
TokenAddress string `json:"tokenAddress" comment:"代币地址"`
|
||||||
|
Decimals int `json:"decimals" comment:"代币精度"`
|
||||||
|
IsAuto int `json:"isAuto" comment:"开启自动转账 1-开启 2-关闭"`
|
||||||
|
TriggerAmount decimal.Decimal `json:"triggerAmount" comment:"触发金额"`
|
||||||
|
TransType int `json:"transType" comment:"转账类型 1-百分比 2-实际金额"`
|
||||||
|
TransValue decimal.Decimal `json:"transValue" comment:"转账金额"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmTokenInsertReq) Valid() error {
|
||||||
|
if s.IsAuto == 1 && (s.TransType == 0 || s.TransValue.IsZero()) {
|
||||||
|
return errors.New("开启自动转账时,转账类型、转账金额不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.IsAuto == 1 && s.TriggerAmount.Cmp(decimal.Zero) <= 0 {
|
||||||
|
return errors.New("触发金额不能小于0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmTokenInsertReq) Generate(model *models.WmToken) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.NetworkId = s.NetworkId
|
||||||
|
model.TokenName = s.TokenName
|
||||||
|
model.TokenAddress = s.TokenAddress
|
||||||
|
model.Decimals = s.Decimals
|
||||||
|
model.IsAuto = s.IsAuto
|
||||||
|
model.TransType = s.TransType
|
||||||
|
model.TransValue = s.TransValue
|
||||||
|
model.TriggerAmount = s.TriggerAmount
|
||||||
|
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmTokenInsertReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
type WmTokenUpdateReq struct {
|
||||||
|
Id int `uri:"id" comment:"主键"` // 主键
|
||||||
|
NetworkId int `json:"networkId" comment:"网络id"`
|
||||||
|
TokenName string `json:"tokenName" comment:"代币名称"`
|
||||||
|
TokenAddress string `json:"tokenAddress" comment:"代币地址"`
|
||||||
|
Decimals int `json:"decimals" comment:"代币精度"`
|
||||||
|
IsAuto int `json:"isAuto" comment:"开启自动转账 1-开启 2-关闭"`
|
||||||
|
TriggerAmount decimal.Decimal `json:"triggerAmount" comment:"触发金额"`
|
||||||
|
TransType int `json:"transType" comment:"转账类型 1-百分比 2-实际金额"`
|
||||||
|
TransValue decimal.Decimal `json:"transValue" comment:"转账金额"`
|
||||||
|
common.ControlBy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmTokenUpdateReq) Valid() error {
|
||||||
|
if s.IsAuto == 1 && (s.TransType == 0 || s.TransValue.IsZero()) {
|
||||||
|
return errors.New("开启自动转账时,转账类型、转账金额不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.IsAuto == 1 && s.TriggerAmount.Cmp(decimal.Zero) <= 0 {
|
||||||
|
return errors.New("触发金额不能小于0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (s *WmTokenUpdateReq) Generate(model *models.WmToken) {
|
||||||
|
if s.Id == 0 {
|
||||||
|
model.Model = common.Model{Id: s.Id}
|
||||||
|
}
|
||||||
|
model.NetworkId = s.NetworkId
|
||||||
|
model.TokenName = s.TokenName
|
||||||
|
model.TokenAddress = s.TokenAddress
|
||||||
|
model.Decimals = s.Decimals
|
||||||
|
model.IsAuto = s.IsAuto
|
||||||
|
model.TransType = s.TransType
|
||||||
|
model.TransValue = s.TransValue
|
||||||
|
model.TriggerAmount = s.TriggerAmount
|
||||||
|
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmTokenUpdateReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// WmTokenGetReq 功能获取请求参数
|
||||||
|
type WmTokenGetReq struct {
|
||||||
|
Id int `uri:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmTokenGetReq) GetId() interface{} {
|
||||||
|
return s.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// WmTokenDeleteReq 功能删除请求参数
|
||||||
|
type WmTokenDeleteReq struct {
|
||||||
|
Ids []int `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WmTokenDeleteReq) GetId() interface{} {
|
||||||
|
return s.Ids
|
||||||
|
}
|
||||||
@ -1,16 +1,19 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
"go-admin/common/dto"
|
"go-admin/common/dto"
|
||||||
common "go-admin/common/models"
|
common "go-admin/common/models"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WmTransferGetPageReq struct {
|
type WmTransferGetPageReq struct {
|
||||||
dto.Pagination `search:"-"`
|
dto.Pagination `search:"-"`
|
||||||
Type int64 `form:"type" search:"type:exact;column:type;table:wm_transfer" comment:"类型 0-百分比 1-实际金额"`
|
Type int `form:"type" search:"-" comment:"类型 1-百分比 2-实际金额"`
|
||||||
TransferType int64 `form:"transferType" search:"type:exact;column:transfer_type;table:wm_transfer" comment:"转账类型 0-批量转出 1-批量汇总"`
|
TransferType int `form:"transferType" search:"-" comment:"转账类型 1-批量转出 2-批量汇总"`
|
||||||
WmTransferOrder
|
WmTransferOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +28,6 @@ type WmTransferOrder struct {
|
|||||||
CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:wm_transfer"`
|
CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:wm_transfer"`
|
||||||
UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:wm_transfer"`
|
UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:wm_transfer"`
|
||||||
DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:wm_transfer"`
|
DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:wm_transfer"`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *WmTransferGetPageReq) GetNeedSearch() interface{} {
|
func (m *WmTransferGetPageReq) GetNeedSearch() interface{} {
|
||||||
@ -34,20 +36,87 @@ func (m *WmTransferGetPageReq) GetNeedSearch() interface{} {
|
|||||||
|
|
||||||
type WmTransferInsertReq struct {
|
type WmTransferInsertReq struct {
|
||||||
Id int `json:"-" comment:"主键id"` // 主键id
|
Id int `json:"-" comment:"主键id"` // 主键id
|
||||||
Type int64 `json:"type" comment:"类型 0-百分比 1-实际金额"`
|
NetworkId int `json:"networkId" comment:"网络id"`
|
||||||
TransferType int64 `json:"transferType" comment:"转账类型 0-批量转出 1-批量汇总"`
|
TokenAddress string `json:"tokenAddress" comment:"代币地址"`
|
||||||
Status int64 `json:"status" comment:"状态"`
|
Type int `json:"type" comment:"类型 1-百分比 2-实际金额"`
|
||||||
|
TransferType int `json:"transferType" comment:"转账类型 1-批量转出 2-批量汇总"`
|
||||||
|
TypeValue decimal.Decimal `json:"typeValue" comment:"操作类型值"`
|
||||||
|
Status int `json:"status" comment:"状态 1-待执行 2-执行中 3-执行完毕"`
|
||||||
Remark string `json:"remark" comment:"备注信息"`
|
Remark string `json:"remark" comment:"备注信息"`
|
||||||
|
Content string `json:"content" comment:"地址"`
|
||||||
|
PrivateKey string `json:"privateKey" comment:"私钥"`
|
||||||
common.ControlBy
|
common.ControlBy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WmTransferItemCache struct {
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
ToAddress string `json:"toAddress"`
|
||||||
|
TokenAddress string `json:"tokenAddress"`
|
||||||
|
Amount string `json:"amount" comment:"代币数量"`
|
||||||
|
Type int `json:"type" comment:"类型 1-百分比 2-实际金额"`
|
||||||
|
TypeValue decimal.Decimal `json:"typeValue" comment:"操作类型值"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid 功能验证
|
||||||
|
func (s *WmTransferInsertReq) Valid() error {
|
||||||
|
if s.Type > 2 || s.Type < 1 {
|
||||||
|
return errors.New("类型错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.TransferType > 2 || s.TransferType < 1 {
|
||||||
|
return errors.New("转账类型错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Content = strings.ReplaceAll(s.Content, " ", "")
|
||||||
|
s.Content = strings.ReplaceAll(s.Content, ",", "\n")
|
||||||
|
s.Content = strings.ReplaceAll(s.Content, "\r", "")
|
||||||
|
s.Content = strings.ReplaceAll(s.Content, ",", "\n")
|
||||||
|
s.PrivateKey = strings.ReplaceAll(s.PrivateKey, " ", "")
|
||||||
|
s.PrivateKey = strings.ReplaceAll(s.PrivateKey, "\r", "")
|
||||||
|
s.PrivateKey = strings.ReplaceAll(s.PrivateKey, ",", "\n")
|
||||||
|
s.PrivateKey = strings.ReplaceAll(s.PrivateKey, ",", "\n")
|
||||||
|
|
||||||
|
privateKeys := strings.Fields(s.PrivateKey)
|
||||||
|
s.PrivateKey = strings.Join(privateKeys, "\n")
|
||||||
|
|
||||||
|
contents := strings.Fields(s.Content)
|
||||||
|
s.Content = strings.Join(contents, "\n")
|
||||||
|
|
||||||
|
if s.PrivateKey == "" {
|
||||||
|
return errors.New("私钥不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Content == "" {
|
||||||
|
return errors.New("地址不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.TransferType == 1 {
|
||||||
|
keys := strings.Fields(s.PrivateKey)
|
||||||
|
|
||||||
|
if len(keys) > 1 {
|
||||||
|
return errors.New("批量转出 只支持单个私钥")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if s.TransferType == 2 {
|
||||||
|
keys := strings.Fields(s.Content)
|
||||||
|
|
||||||
|
if len(keys) > 1 {
|
||||||
|
return errors.New("批量汇总 只支持单个地址")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *WmTransferInsertReq) Generate(model *models.WmTransfer) {
|
func (s *WmTransferInsertReq) Generate(model *models.WmTransfer) {
|
||||||
if s.Id == 0 {
|
if s.Id == 0 {
|
||||||
model.Model = common.Model{Id: s.Id}
|
model.Model = common.Model{Id: s.Id}
|
||||||
}
|
}
|
||||||
model.Type = s.Type
|
model.Type = s.Type
|
||||||
model.TransferType = s.TransferType
|
model.TransferType = s.TransferType
|
||||||
model.Status = s.Status
|
model.NetworkId = s.NetworkId
|
||||||
|
model.TokenAddress = s.TokenAddress
|
||||||
|
model.Status = 0
|
||||||
model.Remark = s.Remark
|
model.Remark = s.Remark
|
||||||
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
||||||
}
|
}
|
||||||
@ -58,9 +127,11 @@ func (s *WmTransferInsertReq) GetId() interface{} {
|
|||||||
|
|
||||||
type WmTransferUpdateReq struct {
|
type WmTransferUpdateReq struct {
|
||||||
Id int `uri:"id" comment:"主键id"` // 主键id
|
Id int `uri:"id" comment:"主键id"` // 主键id
|
||||||
Type int64 `json:"type" comment:"类型 0-百分比 1-实际金额"`
|
NetworkId int `json:"networkId" comment:"网络id"`
|
||||||
TransferType int64 `json:"transferType" comment:"转账类型 0-批量转出 1-批量汇总"`
|
TokenAddress string `json:"tokenAddress" comment:"代币地址"`
|
||||||
Status int64 `json:"status" comment:"状态"`
|
Type int `json:"type" comment:"类型 1-百分比 2-实际金额"`
|
||||||
|
TransferType int `json:"transferType" comment:"转账类型 1-批量转出 2-批量汇总"`
|
||||||
|
Status int `json:"status" comment:"状态"`
|
||||||
Remark string `json:"remark" comment:"备注信息"`
|
Remark string `json:"remark" comment:"备注信息"`
|
||||||
common.ControlBy
|
common.ControlBy
|
||||||
}
|
}
|
||||||
@ -84,6 +155,7 @@ func (s *WmTransferUpdateReq) GetId() interface{} {
|
|||||||
type WmTransferGetReq struct {
|
type WmTransferGetReq struct {
|
||||||
Id int `uri:"id"`
|
Id int `uri:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WmTransferGetReq) GetId() interface{} {
|
func (s *WmTransferGetReq) GetId() interface{} {
|
||||||
return s.Id
|
return s.Id
|
||||||
}
|
}
|
||||||
@ -96,3 +168,9 @@ type WmTransferDeleteReq struct {
|
|||||||
func (s *WmTransferDeleteReq) GetId() interface{} {
|
func (s *WmTransferDeleteReq) GetId() interface{} {
|
||||||
return s.Ids
|
return s.Ids
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TransItemData struct {
|
||||||
|
TransferId int `json:"transferId"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
}
|
||||||
|
|||||||
@ -1,17 +1,45 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
"go-admin/common/dto"
|
"go-admin/common/dto"
|
||||||
common "go-admin/common/models"
|
common "go-admin/common/models"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WmTransferItemGetPageReq struct {
|
type WmTransferItemGetPageReq struct {
|
||||||
dto.Pagination `search:"-"`
|
dto.Pagination `search:"-"`
|
||||||
|
TransferId int `form:"transferId" search:"type:exact;column:transfer_id;table:wm_transfer_item"`
|
||||||
WmTransferItemOrder
|
WmTransferItemOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WmTransferItemAutoLogPageReq struct {
|
||||||
|
dto.Pagination `search:"-"`
|
||||||
|
NetworkId int `form:"networkId" search:"type:exact;column:network_id;table:wm_transfer_item"`
|
||||||
|
WmTransferItemOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
type WmTransferItemResp struct {
|
||||||
|
Id int `json:"id" comment:"主键id"` // 主键id
|
||||||
|
NetworkName string `json:"networkName" comment:"网络名称" excel:"网络名称"`
|
||||||
|
TokenName string `json:"tokenName" comment:"代币名称" excel:"代币名称"`
|
||||||
|
TokenAddress string `json:"tokenAddress" comment:"代币地址" excel:"代币地址"`
|
||||||
|
FromAddress string `json:"fromAddress" comment:"来源地址" excel:"来源地址"`
|
||||||
|
ToAddress string `json:"toAddress" comment:"目标地址" excel:"目标地址"`
|
||||||
|
Amount decimal.Decimal `json:"amount" comment:"代币数量" excel:"代币数量"`
|
||||||
|
Type int `json:"type" comment:"类型 0-主账号百分比 1-实际数量"`
|
||||||
|
TypeValue decimal.Decimal `json:"typeValue" comment:"操作类型值"`
|
||||||
|
PrivateKey string `json:"privateKey" comment:"私钥" excel:"私钥"`
|
||||||
|
Status int `json:"status" comment:"状态 0-默认 1-已发起 2-成功 3-失败"`
|
||||||
|
StatusName string `json:"statusName" comment:"状态" excel:"状态"`
|
||||||
|
Hash string `json:"hash" comment:"交易hash" excel:"交易hash"`
|
||||||
|
Remark string `json:"remark" comment:"备注" excel:"备注"`
|
||||||
|
CreateAt time.Time `json:"createAt" comment:"创建时间"`
|
||||||
|
CraeteAtStr string `json:"createAtStr" comment:"创建时间" excel:"创建时间"`
|
||||||
|
}
|
||||||
|
|
||||||
type WmTransferItemOrder struct {
|
type WmTransferItemOrder struct {
|
||||||
Id string `form:"idOrder" search:"type:order;column:id;table:wm_transfer_item"`
|
Id string `form:"idOrder" search:"type:order;column:id;table:wm_transfer_item"`
|
||||||
TokenAddress string `form:"tokenAddressOrder" search:"type:order;column:token_address;table:wm_transfer_item"`
|
TokenAddress string `form:"tokenAddressOrder" search:"type:order;column:token_address;table:wm_transfer_item"`
|
||||||
@ -26,21 +54,23 @@ type WmTransferItemOrder struct {
|
|||||||
CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:wm_transfer_item"`
|
CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:wm_transfer_item"`
|
||||||
UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:wm_transfer_item"`
|
UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:wm_transfer_item"`
|
||||||
DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:wm_transfer_item"`
|
DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:wm_transfer_item"`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *WmTransferItemGetPageReq) GetNeedSearch() interface{} {
|
func (m *WmTransferItemGetPageReq) GetNeedSearch() interface{} {
|
||||||
return *m
|
return *m
|
||||||
}
|
}
|
||||||
|
func (m *WmTransferItemAutoLogPageReq) GetNeedSearch() interface{} {
|
||||||
|
return *m
|
||||||
|
}
|
||||||
|
|
||||||
type WmTransferItemInsertReq struct {
|
type WmTransferItemInsertReq struct {
|
||||||
Id int `json:"-" comment:"主键id"` // 主键id
|
Id int `json:"-" comment:"主键id"` // 主键id
|
||||||
TokenAddress string `json:"tokenAddress" comment:"代币地址"`
|
TokenAddress string `json:"tokenAddress" comment:"代币地址"`
|
||||||
FromAddress string `json:"fromAddress" comment:"来源地址"`
|
FromAddress string `json:"fromAddress" comment:"来源地址"`
|
||||||
ToAddress string `json:"toAddress" comment:"目标地址"`
|
ToAddress string `json:"toAddress" comment:"目标地址"`
|
||||||
Amount string `json:"amount" comment:"代币数量"`
|
Amount decimal.Decimal `json:"amount" comment:"代币数量"`
|
||||||
Type string `json:"type" comment:"类型 0-主账号百分比 1-实际数量"`
|
Type int `json:"type" comment:"类型 0-主账号百分比 1-实际数量"`
|
||||||
TypeValue string `json:"typeValue" comment:"操作类型值"`
|
TypeValue decimal.Decimal `json:"typeValue" comment:"操作类型值"`
|
||||||
PrivateKey string `json:"privateKey" comment:"私钥"`
|
PrivateKey string `json:"privateKey" comment:"私钥"`
|
||||||
common.ControlBy
|
common.ControlBy
|
||||||
}
|
}
|
||||||
@ -68,9 +98,9 @@ type WmTransferItemUpdateReq struct {
|
|||||||
TokenAddress string `json:"tokenAddress" comment:"代币地址"`
|
TokenAddress string `json:"tokenAddress" comment:"代币地址"`
|
||||||
FromAddress string `json:"fromAddress" comment:"来源地址"`
|
FromAddress string `json:"fromAddress" comment:"来源地址"`
|
||||||
ToAddress string `json:"toAddress" comment:"目标地址"`
|
ToAddress string `json:"toAddress" comment:"目标地址"`
|
||||||
Amount string `json:"amount" comment:"代币数量"`
|
Amount decimal.Decimal `json:"amount" comment:"代币数量"`
|
||||||
Type string `json:"type" comment:"类型 0-主账号百分比 1-实际数量"`
|
Type int `json:"type" comment:"类型 0-主账号百分比 1-实际数量"`
|
||||||
TypeValue string `json:"typeValue" comment:"操作类型值"`
|
TypeValue decimal.Decimal `json:"typeValue" comment:"操作类型值"`
|
||||||
PrivateKey string `json:"privateKey" comment:"私钥"`
|
PrivateKey string `json:"privateKey" comment:"私钥"`
|
||||||
common.ControlBy
|
common.ControlBy
|
||||||
}
|
}
|
||||||
@ -97,6 +127,7 @@ func (s *WmTransferItemUpdateReq) GetId() interface{} {
|
|||||||
type WmTransferItemGetReq struct {
|
type WmTransferItemGetReq struct {
|
||||||
Id int `uri:"id"`
|
Id int `uri:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WmTransferItemGetReq) GetId() interface{} {
|
func (s *WmTransferItemGetReq) GetId() interface{} {
|
||||||
return s.Id
|
return s.Id
|
||||||
}
|
}
|
||||||
@ -109,3 +140,18 @@ type WmTransferItemDeleteReq struct {
|
|||||||
func (s *WmTransferItemDeleteReq) GetId() interface{} {
|
func (s *WmTransferItemDeleteReq) GetId() interface{} {
|
||||||
return s.Ids
|
return s.Ids
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WmTransferItemExportReq struct {
|
||||||
|
TransferId int `query:"transferId" form:"transferId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WmTransferItemExportData struct {
|
||||||
|
PrivateKey string `json:"privateKey" excel:"私钥"`
|
||||||
|
TokenAddress string `json:"tokenAddress" excel:"代币地址"`
|
||||||
|
FromAddress string `json:"fromAddress" excel:"来源地址"`
|
||||||
|
ToAddress string `json:"toAddress" excel:"目标地址"`
|
||||||
|
Amount decimal.Decimal `json:"amount" excel:"代币数量"`
|
||||||
|
TxHash string `json:"txHash" excel:"交易hash"`
|
||||||
|
Status string `json:"status" excel:"状态"`
|
||||||
|
CreateTime string `json:"createTime" excel:"创建时间"`
|
||||||
|
}
|
||||||
|
|||||||
166
app/admin/service/wm_network.go
Normal file
166
app/admin/service/wm_network.go
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/actions"
|
||||||
|
cDto "go-admin/common/dto"
|
||||||
|
"go-admin/common/rediskey"
|
||||||
|
helper "go-admin/utils/redishelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WmNetwork struct {
|
||||||
|
service.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取WmNetwork列表
|
||||||
|
func (e *WmNetwork) GetPage(c *dto.WmNetworkGetPageReq, p *actions.DataPermission, list *[]models.WmNetwork, count *int64) error {
|
||||||
|
var err error
|
||||||
|
var data models.WmNetwork
|
||||||
|
|
||||||
|
err = e.Orm.Model(&data).
|
||||||
|
Scopes(
|
||||||
|
cDto.MakeCondition(c.GetNeedSearch()),
|
||||||
|
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).
|
||||||
|
Find(list).Limit(-1).Offset(-1).
|
||||||
|
Count(count).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("WmNetworkService GetPage error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取WmNetwork对象
|
||||||
|
func (e *WmNetwork) Get(d *dto.WmNetworkGetReq, p *actions.DataPermission, model *models.WmNetwork) error {
|
||||||
|
var data models.WmNetwork
|
||||||
|
|
||||||
|
err := e.Orm.Model(&data).
|
||||||
|
Scopes(
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).
|
||||||
|
First(model, d.GetId()).Error
|
||||||
|
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
err = errors.New("查看对象不存在或无权查看")
|
||||||
|
e.Log.Errorf("Service GetWmNetwork error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("db error:%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建WmNetwork对象
|
||||||
|
func (e *WmNetwork) Insert(c *dto.WmNetworkInsertReq) error {
|
||||||
|
var err error
|
||||||
|
var data models.WmNetwork
|
||||||
|
c.Generate(&data)
|
||||||
|
err = e.Orm.Create(&data).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("WmNetworkService Insert error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改WmNetwork对象
|
||||||
|
func (e *WmNetwork) Update(c *dto.WmNetworkUpdateReq, p *actions.DataPermission) error {
|
||||||
|
var err error
|
||||||
|
var data = models.WmNetwork{}
|
||||||
|
e.Orm.Scopes(
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).First(&data, c.GetId())
|
||||||
|
c.Generate(&data)
|
||||||
|
|
||||||
|
db := e.Orm.Model(data).Updates(map[string]interface{}{"network_name": c.NetworkName, "receive_address": c.ReceiveAddress, "update_by": c.UpdateBy})
|
||||||
|
if err = db.Error; err != nil {
|
||||||
|
e.Log.Errorf("WmNetworkService Save error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权更新该数据")
|
||||||
|
}
|
||||||
|
|
||||||
|
//重置缓存
|
||||||
|
e.ReCache()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *WmNetwork) ReCache() {
|
||||||
|
var datas []models.WmNetwork
|
||||||
|
items := make([]string, 0)
|
||||||
|
|
||||||
|
if err := e.Orm.Find(&datas).Error; err != nil {
|
||||||
|
e.Log.Errorf("db error:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range datas {
|
||||||
|
contentByte, _ := json.Marshal(v)
|
||||||
|
|
||||||
|
if len(contentByte) > 0 {
|
||||||
|
items = append(items, string(contentByte))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(items) > 0 {
|
||||||
|
helper.DefaultRedis.SetListCache(rediskey.NetWorks, 0, items...)
|
||||||
|
} else {
|
||||||
|
helper.DefaultRedis.DeleteString(rediskey.NetWorks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove 删除WmNetwork
|
||||||
|
func (e *WmNetwork) Remove(d *dto.WmNetworkDeleteReq, p *actions.DataPermission) error {
|
||||||
|
var data models.WmNetwork
|
||||||
|
|
||||||
|
db := e.Orm.Model(&data).
|
||||||
|
Scopes(
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).Delete(&data, d.GetId())
|
||||||
|
if err := db.Error; err != nil {
|
||||||
|
e.Log.Errorf("Service RemoveWmNetwork error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权删除该数据")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAll 获取所有WmNetwork
|
||||||
|
func (e *WmNetwork) GetAll() ([]models.WmNetwork, error) {
|
||||||
|
vals, _ := helper.DefaultRedis.GetAllList(rediskey.NetWorks)
|
||||||
|
result := make([]models.WmNetwork, 0)
|
||||||
|
|
||||||
|
if len(vals) > 0 {
|
||||||
|
for _, v := range vals {
|
||||||
|
var item models.WmNetwork
|
||||||
|
_ = json.Unmarshal([]byte(v), &item)
|
||||||
|
|
||||||
|
if item.Id > 0 {
|
||||||
|
result = append(result, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(result) == 0 {
|
||||||
|
if err := e.Orm.Model(&models.WmNetwork{}).Find(&result).Error; err != nil {
|
||||||
|
e.Log.Errorf("db error:%s", err)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
234
app/admin/service/wm_token.go
Normal file
234
app/admin/service/wm_token.go
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/actions"
|
||||||
|
cDto "go-admin/common/dto"
|
||||||
|
"go-admin/common/rediskey"
|
||||||
|
helper "go-admin/utils/redishelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WmToken struct {
|
||||||
|
service.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPage 获取WmToken列表
|
||||||
|
func (e *WmToken) GetPage(c *dto.WmTokenGetPageReq, p *actions.DataPermission, list *[]models.WmToken, count *int64) error {
|
||||||
|
var err error
|
||||||
|
var data models.WmToken
|
||||||
|
|
||||||
|
err = e.Orm.Model(&data).
|
||||||
|
Scopes(
|
||||||
|
cDto.MakeCondition(c.GetNeedSearch()),
|
||||||
|
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).
|
||||||
|
Find(list).Limit(-1).Offset(-1).
|
||||||
|
Count(count).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("WmTokenService GetPage error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取WmToken对象
|
||||||
|
func (e *WmToken) Get(d *dto.WmTokenGetReq, p *actions.DataPermission, model *models.WmToken) error {
|
||||||
|
var data models.WmToken
|
||||||
|
|
||||||
|
err := e.Orm.Model(&data).
|
||||||
|
Scopes(
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).
|
||||||
|
First(model, d.GetId()).Error
|
||||||
|
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
err = errors.New("查看对象不存在或无权查看")
|
||||||
|
e.Log.Errorf("Service GetWmToken error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("db error:%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 创建WmToken对象
|
||||||
|
func (e *WmToken) Insert(c *dto.WmTokenInsertReq) error {
|
||||||
|
var err error
|
||||||
|
var data models.WmToken
|
||||||
|
c.Generate(&data)
|
||||||
|
err = e.Orm.Create(&data).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("WmTokenService Insert error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
e.ReCache("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改WmToken对象
|
||||||
|
func (e *WmToken) Update(c *dto.WmTokenUpdateReq, p *actions.DataPermission) error {
|
||||||
|
var err error
|
||||||
|
var data = models.WmToken{}
|
||||||
|
e.Orm.Scopes(
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).First(&data, c.GetId())
|
||||||
|
c.Generate(&data)
|
||||||
|
|
||||||
|
db := e.Orm.Save(&data)
|
||||||
|
if err = db.Error; err != nil {
|
||||||
|
e.Log.Errorf("WmTokenService Save error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权更新该数据")
|
||||||
|
}
|
||||||
|
e.ReCache("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove 删除WmToken
|
||||||
|
func (e *WmToken) Remove(d *dto.WmTokenDeleteReq, p *actions.DataPermission) error {
|
||||||
|
var data models.WmToken
|
||||||
|
|
||||||
|
db := e.Orm.Model(&data).
|
||||||
|
Scopes(
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).Delete(&data, d.GetId())
|
||||||
|
if err := db.Error; err != nil {
|
||||||
|
e.Log.Errorf("Service RemoveWmToken error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db.RowsAffected == 0 {
|
||||||
|
return errors.New("无权删除该数据")
|
||||||
|
}
|
||||||
|
|
||||||
|
e.ReCache("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置代币缓存
|
||||||
|
// networkCode 网络code(如果为空则重置所有网络的缓存)
|
||||||
|
func (e *WmToken) ReCache(networkCode string) error {
|
||||||
|
var datas []models.WmToken
|
||||||
|
mapData := make(map[int][]string)
|
||||||
|
query := e.Orm.Model(&models.WmToken{})
|
||||||
|
|
||||||
|
if networkCode != "" {
|
||||||
|
query.Where("network_id = ?", networkCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := query.Find(&datas).Error; err != nil {
|
||||||
|
e.Log.Errorf("Service ReCache error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range datas {
|
||||||
|
contentByte, _ := json.Marshal(v)
|
||||||
|
|
||||||
|
if len(contentByte) > 0 {
|
||||||
|
mapData[v.NetworkId] = append(mapData[v.NetworkId], string(contentByte))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range mapData {
|
||||||
|
key := fmt.Sprintf(rediskey.Tokens, k)
|
||||||
|
|
||||||
|
if err := helper.DefaultRedis.SetListCache(key, 0, v...); err != nil {
|
||||||
|
e.Log.Errorf("Service ReCache key:%s error:%s \r\n", key, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAll 获取所有代币信息
|
||||||
|
func (e *WmToken) GetAll() ([]models.WmToken, error) {
|
||||||
|
result := make([]models.WmToken, 0)
|
||||||
|
data := models.WmToken{}
|
||||||
|
keys, _ := helper.DefaultRedis.ScanKeys(fmt.Sprintf(rediskey.Tokens, "*"))
|
||||||
|
|
||||||
|
if keys == nil || len(keys) == 0 {
|
||||||
|
if err := e.Orm.Model(data).Find(&result).Error; err != nil {
|
||||||
|
e.Log.Errorf("Service GetAll error:%s \r\n", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, key := range keys {
|
||||||
|
tokenList, _ := helper.DefaultRedis.GetAllList(key)
|
||||||
|
|
||||||
|
for _, token := range tokenList {
|
||||||
|
sonic.UnmarshalString(token, &data)
|
||||||
|
|
||||||
|
if data.Id > 0 {
|
||||||
|
result = append(result, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByTokenId 根据networkId和tokenAddress获取代币信息
|
||||||
|
func (e *WmToken) GetByTokenId(networkId int, tokenAddress string) (models.WmToken, error) {
|
||||||
|
key := fmt.Sprintf(rediskey.Tokens, networkId)
|
||||||
|
token := models.WmToken{}
|
||||||
|
tokens, _ := helper.DefaultRedis.GetAllList(key)
|
||||||
|
|
||||||
|
for _, v := range tokens {
|
||||||
|
var data models.WmToken
|
||||||
|
_ = json.Unmarshal([]byte(v), &data)
|
||||||
|
if data.TokenAddress == tokenAddress {
|
||||||
|
token = data
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.Id == 0 {
|
||||||
|
if err := e.Orm.Model(&models.WmToken{}).Where("network_id = ? and token_address = ?", networkId, tokenAddress).First(&token).Error; err != nil {
|
||||||
|
e.Log.Errorf("Service GetByTokenId error:%s \r\n", err)
|
||||||
|
return models.WmToken{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAutoTransTokens 获取自动转账的代币列表
|
||||||
|
func (e WmToken) GetAutoTransTokens(netowrkIds []int) ([]models.WmToken, error) {
|
||||||
|
tokens := make([]models.WmToken, 0)
|
||||||
|
|
||||||
|
for _, networkId := range netowrkIds {
|
||||||
|
key := fmt.Sprintf(rediskey.Tokens, networkId)
|
||||||
|
tokensList, _ := helper.DefaultRedis.GetAllList(key)
|
||||||
|
|
||||||
|
for _, v := range tokensList {
|
||||||
|
var data models.WmToken
|
||||||
|
_ = json.Unmarshal([]byte(v), &data)
|
||||||
|
if data.IsAuto == 1 {
|
||||||
|
tokens = append(tokens, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tokens) == 0 {
|
||||||
|
if err := e.Orm.Model(&models.WmToken{}).Where("network_id in (?) and is_auto = ?", netowrkIds, 1).Find(&tokens).Error; err != nil {
|
||||||
|
e.Log.Errorf("Service GetAutoTransTokens error:%s \r\n", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens, nil
|
||||||
|
}
|
||||||
@ -2,14 +2,21 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/common/actions"
|
"go-admin/common/actions"
|
||||||
cDto "go-admin/common/dto"
|
cDto "go-admin/common/dto"
|
||||||
|
"go-admin/config"
|
||||||
|
"go-admin/utils/aeshelper"
|
||||||
|
"go-admin/utils/ethbalanceofhelper"
|
||||||
|
"go-admin/utils/ethtransferhelper"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WmTransfer struct {
|
type WmTransfer struct {
|
||||||
@ -20,8 +27,17 @@ type WmTransfer struct {
|
|||||||
func (e *WmTransfer) GetPage(c *dto.WmTransferGetPageReq, p *actions.DataPermission, list *[]models.WmTransfer, count *int64) error {
|
func (e *WmTransfer) GetPage(c *dto.WmTransferGetPageReq, p *actions.DataPermission, list *[]models.WmTransfer, count *int64) error {
|
||||||
var err error
|
var err error
|
||||||
var data models.WmTransfer
|
var data models.WmTransfer
|
||||||
|
query := e.Orm.Model(&data)
|
||||||
|
|
||||||
err = e.Orm.Model(&data).
|
if c.Type > 0 {
|
||||||
|
query.Where("type =?", c.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TransferType > 0 {
|
||||||
|
query.Where("transfer_type =?", c.TransferType)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = query.
|
||||||
Scopes(
|
Scopes(
|
||||||
cDto.MakeCondition(c.GetNeedSearch()),
|
cDto.MakeCondition(c.GetNeedSearch()),
|
||||||
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
||||||
@ -33,9 +49,47 @@ func (e *WmTransfer) GetPage(c *dto.WmTransferGetPageReq, p *actions.DataPermiss
|
|||||||
e.Log.Errorf("WmTransferService GetPage error:%s \r\n", err)
|
e.Log.Errorf("WmTransferService GetPage error:%s \r\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transferIds := make([]int, 0)
|
||||||
|
for _, item := range *list {
|
||||||
|
transferIds = append(transferIds, item.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemData, _ := e.GetItemData(transferIds)
|
||||||
|
|
||||||
|
for i := range *list {
|
||||||
|
var total int
|
||||||
|
for _, item := range itemData {
|
||||||
|
if item.TransferId == (*list)[i].Id {
|
||||||
|
total += item.Total
|
||||||
|
|
||||||
|
switch item.Status {
|
||||||
|
case 1:
|
||||||
|
(*list)[i].Pending = item.Total
|
||||||
|
case 2:
|
||||||
|
(*list)[i].Sucess = item.Total
|
||||||
|
case 3:
|
||||||
|
(*list)[i].Fail = item.Total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(*list)[i].Total = total
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetItemData 获取转账明细数据
|
||||||
|
func (e *WmTransfer) GetItemData(transIds []int) ([]dto.TransItemData, error) {
|
||||||
|
result := make([]dto.TransItemData, 0)
|
||||||
|
if err := e.Orm.Raw("select t.transfer_id as TransferId,t.`status`,count(*) as total from wm_transfer_item t where t.transfer_id in ? group by t.transfer_id,t.`status`", transIds).Scan(&result).Error; err != nil {
|
||||||
|
e.Log.Errorf("WmTransferService GetItemData error:%s \r\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Get 获取WmTransfer对象
|
// Get 获取WmTransfer对象
|
||||||
func (e *WmTransfer) Get(d *dto.WmTransferGetReq, p *actions.DataPermission, model *models.WmTransfer) error {
|
func (e *WmTransfer) Get(d *dto.WmTransferGetReq, p *actions.DataPermission, model *models.WmTransfer) error {
|
||||||
var data models.WmTransfer
|
var data models.WmTransfer
|
||||||
@ -62,14 +116,130 @@ func (e *WmTransfer) Insert(c *dto.WmTransferInsertReq) error {
|
|||||||
var err error
|
var err error
|
||||||
var data models.WmTransfer
|
var data models.WmTransfer
|
||||||
c.Generate(&data)
|
c.Generate(&data)
|
||||||
err = e.Orm.Create(&data).Error
|
caches := make([]models.WmTransferItem, 0)
|
||||||
|
tokenService := WmToken{Service: e.Service}
|
||||||
|
token, _ := tokenService.GetByTokenId(c.NetworkId, c.TokenAddress)
|
||||||
|
|
||||||
|
if token.Id == 0 {
|
||||||
|
return errors.New("代币不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TransferType == 1 {
|
||||||
|
items := strings.Fields(c.Content)
|
||||||
|
_, fromAddress, _ := ethtransferhelper.GetAddressFromPrivateKey(c.PrivateKey)
|
||||||
|
aesKey := aeshelper.AesEcbEncrypt(c.PrivateKey)
|
||||||
|
|
||||||
|
if c.TypeValue.Cmp(decimal.Zero) <= 0 {
|
||||||
|
return errors.New("比例值错误必须大于0")
|
||||||
|
}
|
||||||
|
|
||||||
|
amount, err := e.getPrivateKeyAmount(c.PrivateKey, token.TokenAddress, token.Decimals, c.Type, c.TypeValue)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if amount.Cmp(decimal.NewFromInt(0)) <= 0 {
|
||||||
|
return errors.New("转账金额错误必须大于0")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
if item == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cache := models.WmTransferItem{}
|
||||||
|
cache.NetworkId = c.NetworkId
|
||||||
|
cache.PrivateKey = aesKey
|
||||||
|
cache.FromAddress = fromAddress.String()
|
||||||
|
cache.ToAddress = item
|
||||||
|
cache.Type = c.Type
|
||||||
|
cache.TypeValue = c.TypeValue
|
||||||
|
cache.Amount = amount
|
||||||
|
|
||||||
|
caches = append(caches, cache)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
items := strings.Fields(c.PrivateKey)
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
if item == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
amount, err := e.getPrivateKeyAmount(item, token.TokenAddress, token.Decimals, c.Type, c.TypeValue)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, fromAddress, _ := ethtransferhelper.GetAddressFromPrivateKey(item)
|
||||||
|
cache := models.WmTransferItem{}
|
||||||
|
cache.NetworkId = c.NetworkId
|
||||||
|
cache.PrivateKey = aeshelper.AesEcbEncrypt(item)
|
||||||
|
cache.FromAddress = fromAddress.String()
|
||||||
|
cache.ToAddress = c.Content
|
||||||
|
cache.Type = c.Type
|
||||||
|
cache.TypeValue = c.TypeValue
|
||||||
|
cache.Amount = amount
|
||||||
|
|
||||||
|
caches = append(caches, cache)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
if err := tx.Create(&data).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range caches {
|
||||||
|
caches[i].TransferId = data.Id
|
||||||
|
caches[i].IsAuto = 2
|
||||||
|
caches[i].TokenAddress = c.TokenAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.CreateInBatches(&caches, 100).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Log.Errorf("WmTransferService Insert error:%s \r\n", err)
|
e.Log.Errorf("WmTransferService Insert error:%s \r\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go e.RunTransferJob(caches)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取金额
|
||||||
|
func (e *WmTransfer) getPrivateKeyAmount(privateKey, tokenAddress string, decimals int, reqType int, typeValue decimal.Decimal) (decimal.Decimal, error) {
|
||||||
|
var amount decimal.Decimal
|
||||||
|
if reqType == 1 {
|
||||||
|
_, accountAddress, _ := ethtransferhelper.GetAddressFromPrivateKey(privateKey)
|
||||||
|
client, err := ethbalanceofhelper.EthClientWithProxy(config.ExtConfig.ApiEndpoint, config.ExtConfig.ProxyUrl)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return amount, errors.New("连接区块链失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
amount, err = ethbalanceofhelper.GetERC20Balance(client, tokenAddress, accountAddress.String(), decimals)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return amount, errors.New("查询主账号余额失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
amount = amount.Mul(typeValue.Div(decimal.NewFromInt(100))).Truncate(int32(decimals))
|
||||||
|
} else {
|
||||||
|
amount = typeValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return amount, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Update 修改WmTransfer对象
|
// Update 修改WmTransfer对象
|
||||||
func (e *WmTransfer) Update(c *dto.WmTransferUpdateReq, p *actions.DataPermission) error {
|
func (e *WmTransfer) Update(c *dto.WmTransferUpdateReq, p *actions.DataPermission) error {
|
||||||
var err error
|
var err error
|
||||||
@ -107,3 +277,111 @@ func (e *WmTransfer) Remove(d *dto.WmTransferDeleteReq, p *actions.DataPermissio
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RunTransferJob 运行转账任务
|
||||||
|
func (e *WmTransfer) RunTransferJob(items []models.WmTransferItem) error {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
logger.Error("RunTransferJob panic", r)
|
||||||
|
|
||||||
|
if err2 := e.Orm.Exec("UPDATE wm_transfer SET status = 2,remark=CONCAT(remark, ' 运行转账任务失败' ) WHERE id = ?", items[0].TransferId).Error; err2 != nil {
|
||||||
|
logger.Error("更新转账记录失败", err2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
client, err := ethbalanceofhelper.EthClientWithProxy(config.ExtConfig.ApiEndpoint, config.ExtConfig.ProxyUrl)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if err2 := e.Orm.Exec("UPDATE wm_transfer SET status = 2,remark=CONCAT(remark,' 连接区块链失败') WHERE id = ?", items[0].TransferId).Error; err2 != nil {
|
||||||
|
logger.Error("更新转账记录失败", err2)
|
||||||
|
}
|
||||||
|
return errors.New("连接区块链失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
if item.Amount.Cmp(decimal.Zero) <= 0 {
|
||||||
|
if err2 := e.Orm.Model(item).Updates(map[string]interface{}{"status": 2, "remark": "转账金额不能为0"}).Error; err2 != nil {
|
||||||
|
logger.Error("更新转账记录失败", err2)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey := aeshelper.AesEcbDecrypt(item.PrivateKey)
|
||||||
|
privateKey = strings.Replace(privateKey, "0x", "", 1)
|
||||||
|
trans, err := ethtransferhelper.TransferErc20(client, privateKey, item.TokenAddress, item.ToAddress, item.Amount, uint8(item.Decimals))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
var hash string
|
||||||
|
|
||||||
|
if trans != nil {
|
||||||
|
hash = trans.Hash().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err2 := e.Orm.Model(item).Updates(map[string]interface{}{"status": 3, "hash": hash, "remark": err.Error()}).Error; err2 != nil {
|
||||||
|
logger.Error("更新转账记录失败", err2)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err2 := e.Orm.Model(item).Updates(map[string]interface{}{"status": 1, "hash": trans.Hash().String(), "remark": "发起交易"}).Error; err2 != nil {
|
||||||
|
logger.Error("更新转账记录失败", err2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckHashStatus 检查转账hash状态
|
||||||
|
func (e *WmTransfer) CheckHashStatus() error {
|
||||||
|
var datas []models.WmTransferItem
|
||||||
|
err := e.Orm.Model(&models.WmTransferItem{}).Select("id,hash").Where("status = 1 and hash <> ''").Find(&datas).Error
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("查询转账记录失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := ethbalanceofhelper.EthClientWithProxy(config.ExtConfig.ApiEndpoint, config.ExtConfig.ProxyUrl)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("连接区块链失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range datas {
|
||||||
|
status, err := ethtransferhelper.GetTransactionByHash(client, item.Hash)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("查询交易失败:%s error:%v", item.Hash, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == 1 {
|
||||||
|
item.Status = 2
|
||||||
|
item.Remark = "交易成功"
|
||||||
|
} else {
|
||||||
|
item.Status = 3
|
||||||
|
item.Remark = "交易失败"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := e.Orm.Model(item).Updates(map[string]interface{}{"status": item.Status, "remark": item.Remark}).Error; err != nil {
|
||||||
|
e.Log.Errorf("更新转账记录失败:%s error:%v", item.Hash, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理数据
|
||||||
|
func (e *WmTransfer) ClearAll() error {
|
||||||
|
err := e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
if err1 := tx.Exec("truncate table wm_transfer_item").Error; err1 != nil {
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
|
||||||
|
if err2 := tx.Exec("truncate table wm_transfer").Error; err2 != nil {
|
||||||
|
return err2
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package service
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
@ -10,6 +11,9 @@ import (
|
|||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/common/actions"
|
"go-admin/common/actions"
|
||||||
cDto "go-admin/common/dto"
|
cDto "go-admin/common/dto"
|
||||||
|
"go-admin/utils/aeshelper"
|
||||||
|
"go-admin/utils/excelhelper"
|
||||||
|
"go-admin/utils/stringhelper"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WmTransferItem struct {
|
type WmTransferItem struct {
|
||||||
@ -33,9 +37,144 @@ func (e *WmTransferItem) GetPage(c *dto.WmTransferItemGetPageReq, p *actions.Dat
|
|||||||
e.Log.Errorf("WmTransferItemService GetPage error:%s \r\n", err)
|
e.Log.Errorf("WmTransferItemService GetPage error:%s \r\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(*list); i++ {
|
||||||
|
(*list)[i].PrivateKey = stringhelper.DesensitizeWalletAddress(aeshelper.AesEcbDecrypt((*list)[i].PrivateKey))
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAutoTransferLogPage 获取自动转账日志列表
|
||||||
|
func (e *WmTransferItem) GetAutoTransferLogPage(c *dto.WmTransferItemAutoLogPageReq, p *actions.DataPermission, list *[]dto.WmTransferItemResp, count *int64) error {
|
||||||
|
var err error
|
||||||
|
var data models.WmTransferItem
|
||||||
|
var datas []models.WmTransferItem
|
||||||
|
|
||||||
|
err = e.Orm.Model(&data).
|
||||||
|
Where("is_auto = 1").
|
||||||
|
Scopes(
|
||||||
|
cDto.MakeCondition(c.GetNeedSearch()),
|
||||||
|
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).
|
||||||
|
Find(&datas).Limit(-1).Offset(-1).
|
||||||
|
Count(count).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("WmTransferItemService GetPage error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
networkService := WmNetwork{Service: e.Service}
|
||||||
|
networks, _ := networkService.GetAll()
|
||||||
|
tokenService := WmToken{Service: e.Service}
|
||||||
|
tokens, _ := tokenService.GetAll()
|
||||||
|
|
||||||
|
for i := 0; i < len(datas); i++ {
|
||||||
|
item := dto.WmTransferItemResp{}
|
||||||
|
item.Id = datas[i].Id
|
||||||
|
item.PrivateKey = stringhelper.DesensitizeWalletAddress(aeshelper.AesEcbDecrypt(datas[i].PrivateKey))
|
||||||
|
item.FromAddress = datas[i].FromAddress
|
||||||
|
item.ToAddress = datas[i].ToAddress
|
||||||
|
item.TokenAddress = datas[i].TokenAddress
|
||||||
|
item.Amount = datas[i].Amount
|
||||||
|
item.Status = datas[i].Status
|
||||||
|
item.Remark = datas[i].Remark
|
||||||
|
item.Type = datas[i].Type
|
||||||
|
item.TypeValue = datas[i].TypeValue
|
||||||
|
item.Hash = datas[i].Hash
|
||||||
|
item.CreateAt = datas[i].CreatedAt
|
||||||
|
|
||||||
|
for _, network := range networks {
|
||||||
|
if network.Id == datas[i].NetworkId {
|
||||||
|
item.NetworkName = network.NetworkName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, token := range tokens {
|
||||||
|
if token.NetworkId == datas[i].NetworkId && token.TokenAddress == datas[i].TokenAddress {
|
||||||
|
item.TokenName = token.TokenName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*list = append(*list, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出自动转账日志
|
||||||
|
func (e *WmTransferItem) ExportAutoLog(req *dto.WmTransferItemAutoLogPageReq, c *gin.Context) error {
|
||||||
|
datas := make([]models.WmTransferItem, 0)
|
||||||
|
var err error
|
||||||
|
var data models.WmTransferItem
|
||||||
|
exportDatas := make([]dto.WmTransferItemResp, 0)
|
||||||
|
|
||||||
|
err = e.Orm.Model(&data).
|
||||||
|
Where("is_auto = 1").
|
||||||
|
Scopes(
|
||||||
|
cDto.MakeCondition(req.GetNeedSearch()),
|
||||||
|
).
|
||||||
|
Find(&datas).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("Service ExportExcel error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
networkService := WmNetwork{Service: e.Service}
|
||||||
|
networks, _ := networkService.GetAll()
|
||||||
|
tokenService := WmToken{Service: e.Service}
|
||||||
|
tokens, _ := tokenService.GetAll()
|
||||||
|
|
||||||
|
for i := 0; i < len(datas); i++ {
|
||||||
|
(datas)[i].PrivateKey = stringhelper.DesensitizeWalletAddress(aeshelper.AesEcbDecrypt((datas)[i].PrivateKey))
|
||||||
|
exportData := dto.WmTransferItemResp{
|
||||||
|
PrivateKey: (datas)[i].PrivateKey,
|
||||||
|
TokenAddress: (datas)[i].TokenAddress,
|
||||||
|
FromAddress: (datas)[i].FromAddress,
|
||||||
|
ToAddress: (datas)[i].ToAddress,
|
||||||
|
Amount: (datas)[i].Amount,
|
||||||
|
Hash: (datas)[i].Hash,
|
||||||
|
Remark: (datas)[i].Remark,
|
||||||
|
CraeteAtStr: (datas)[i].CreatedAt.Format("2006-01-02 15:04:05"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, network := range networks {
|
||||||
|
if network.Id == datas[i].NetworkId {
|
||||||
|
exportData.NetworkName = network.NetworkName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, token := range tokens {
|
||||||
|
if token.NetworkId == datas[i].NetworkId && token.TokenAddress == datas[i].TokenAddress {
|
||||||
|
exportData.TokenName = token.TokenName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (datas)[i].Status {
|
||||||
|
case 1:
|
||||||
|
exportData.StatusName = "交易中"
|
||||||
|
case 2:
|
||||||
|
exportData.StatusName = "已成功"
|
||||||
|
case 3:
|
||||||
|
exportData.StatusName = "已失败"
|
||||||
|
default:
|
||||||
|
exportData.StatusName = "默认"
|
||||||
|
}
|
||||||
|
exportDatas = append(exportDatas, exportData)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(exportDatas) == 0 {
|
||||||
|
return errors.New("无数据")
|
||||||
|
}
|
||||||
|
|
||||||
|
return excelhelper.ExportExcel(c, "自动转账明细", exportDatas, []string{})
|
||||||
|
}
|
||||||
|
|
||||||
// Get 获取WmTransferItem对象
|
// Get 获取WmTransferItem对象
|
||||||
func (e *WmTransferItem) Get(d *dto.WmTransferItemGetReq, p *actions.DataPermission, model *models.WmTransferItem) error {
|
func (e *WmTransferItem) Get(d *dto.WmTransferItemGetReq, p *actions.DataPermission, model *models.WmTransferItem) error {
|
||||||
var data models.WmTransferItem
|
var data models.WmTransferItem
|
||||||
@ -107,3 +246,47 @@ func (e *WmTransferItem) Remove(d *dto.WmTransferItemDeleteReq, p *actions.DataP
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export 导出WmTransferItem
|
||||||
|
func (e *WmTransferItem) ExportExcel(req *dto.WmTransferItemExportReq, p *actions.DataPermission, c *gin.Context) error {
|
||||||
|
datas := make([]models.WmTransferItem, 0)
|
||||||
|
var err error
|
||||||
|
var data models.WmTransferItem
|
||||||
|
exportDatas := make([]dto.WmTransferItemExportData, 0)
|
||||||
|
|
||||||
|
if err = e.Orm.Model(&data).Where("transfer_id = ?", req.TransferId).Find(&datas).Error; err != nil {
|
||||||
|
e.Log.Errorf("Service ExportExcel error:%s \r\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(datas); i++ {
|
||||||
|
(datas)[i].PrivateKey = stringhelper.DesensitizeWalletAddress(aeshelper.AesEcbDecrypt((datas)[i].PrivateKey))
|
||||||
|
exportData := dto.WmTransferItemExportData{
|
||||||
|
PrivateKey: (datas)[i].PrivateKey,
|
||||||
|
TokenAddress: (datas)[i].TokenAddress,
|
||||||
|
FromAddress: (datas)[i].FromAddress,
|
||||||
|
ToAddress: (datas)[i].ToAddress,
|
||||||
|
Amount: (datas)[i].Amount,
|
||||||
|
TxHash: (datas)[i].Hash,
|
||||||
|
CreateTime: (datas)[i].CreatedAt.Format("2006-01-02 15:04:05"),
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (datas)[i].Status {
|
||||||
|
case 1:
|
||||||
|
exportData.Status = "交易中"
|
||||||
|
case 2:
|
||||||
|
exportData.Status = "已成功"
|
||||||
|
case 3:
|
||||||
|
exportData.Status = "已失败"
|
||||||
|
default:
|
||||||
|
exportData.Status = "默认"
|
||||||
|
}
|
||||||
|
exportDatas = append(exportDatas, exportData)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(exportDatas) == 0 {
|
||||||
|
return errors.New("无数据")
|
||||||
|
}
|
||||||
|
|
||||||
|
return excelhelper.ExportExcel(c, "转账明细", exportDatas, []string{})
|
||||||
|
}
|
||||||
|
|||||||
@ -5,9 +5,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"go-admin/abis/ethereumabi"
|
|
||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/common/actions"
|
"go-admin/common/actions"
|
||||||
@ -141,6 +141,9 @@ func (e *WmWalletInfo) Remove(d *dto.WmWalletInfoDeleteReq, p *actions.DataPermi
|
|||||||
// ScheduledTask 定时任务
|
// ScheduledTask 定时任务
|
||||||
func (e *WmWalletInfo) ScheduledTask() error {
|
func (e *WmWalletInfo) ScheduledTask() error {
|
||||||
var datas []models.WmWalletInfo
|
var datas []models.WmWalletInfo
|
||||||
|
transferItems := make([]models.WmTransferItem, 0)
|
||||||
|
networkService := WmNetwork{Service: e.Service}
|
||||||
|
tokenService := WmToken{Service: e.Service}
|
||||||
|
|
||||||
if err := e.Orm.Model(models.WmWalletInfo{}).Find(&datas).Error; err != nil {
|
if err := e.Orm.Model(models.WmWalletInfo{}).Find(&datas).Error; err != nil {
|
||||||
e.Log.Errorf("db error:%s", err)
|
e.Log.Errorf("db error:%s", err)
|
||||||
@ -154,21 +157,91 @@ func (e *WmWalletInfo) ScheduledTask() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
networkIds := make([]int, 0)
|
||||||
|
networks, _ := networkService.GetAll()
|
||||||
|
networkMap := make(map[int]models.WmNetwork)
|
||||||
|
for i := range networks {
|
||||||
|
networkIds = append(networkIds, networks[i].Id)
|
||||||
|
networkMap[networks[i].Id] = networks[i]
|
||||||
|
}
|
||||||
|
autoTokens, _ := tokenService.GetAutoTransTokens(networkIds)
|
||||||
|
|
||||||
|
for _, token := range autoTokens {
|
||||||
|
network := networkMap[token.NetworkId]
|
||||||
|
|
||||||
|
if network.Id == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for i := range datas {
|
for i := range datas {
|
||||||
amount, err := ethbalanceofhelper.GetERC20Balance(client, ethereumabi.USDCErc20, datas[i].Address)
|
amount, err := ethbalanceofhelper.GetERC20Balance(client, token.TokenAddress, datas[i].Address, token.Decimals)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Log.Errorf("GetERC20Balance error:%s", err)
|
e.Log.Errorf("GetERC20Balance error:%s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
datas[i].UsdcAmount = amount
|
if amount.Cmp(token.TriggerAmount) < 0 {
|
||||||
|
|
||||||
if err := e.Orm.Model(&datas[i]).Update("usdc_amount", amount).Error; err != nil {
|
|
||||||
e.Log.Errorf("db error:%s", err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
if err := e.Orm.Model(models.WmTransferItem{}).
|
||||||
|
Where("private_key =? and token_address =? and to_address =? and status =?",
|
||||||
|
datas[i].PrivateKey, token.TokenAddress, network.ReceiveAddress, 1).Count(&count).Error; err != nil {
|
||||||
|
e.Log.Errorf("fromAddress:%s, tokenAddress:%s, db error:%s", datas[i].Address, token.TokenAddress, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
e.Log.Errorf("fromAddress:%s, tokenAddress:%s, 交易中暂时不自动转账", datas[i].Address, token.TokenAddress)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case token.TransType == 1 && token.TransValue.Cmp(decimal.Zero) > 0:
|
||||||
|
amount = amount.Mul(token.TransValue.Div(decimal.NewFromInt(100))).Truncate(int32(token.Decimals))
|
||||||
|
case token.TransType == 2 && token.TransValue.Cmp(decimal.Zero) > 0:
|
||||||
|
amount = token.TransValue.Truncate(int32(token.Decimals))
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo: 自动转账
|
||||||
|
transferItems = append(transferItems, models.WmTransferItem{
|
||||||
|
IsAuto: 1,
|
||||||
|
NetworkId: network.Id,
|
||||||
|
TokenAddress: token.TokenAddress,
|
||||||
|
FromAddress: datas[i].Address,
|
||||||
|
ToAddress: network.ReceiveAddress,
|
||||||
|
Amount: amount,
|
||||||
|
Decimals: token.Decimals,
|
||||||
|
Type: token.TransType,
|
||||||
|
TypeValue: token.TransValue,
|
||||||
|
PrivateKey: datas[i].PrivateKey,
|
||||||
|
Status: 0,
|
||||||
|
Remark: "自动转账",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(transferItems) > 0 {
|
||||||
|
if err := e.Orm.CreateInBatches(transferItems, 100).Error; err != nil {
|
||||||
|
e.Log.Errorf("定时转账保存数据库失败 error:%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
transService := WmTransfer{Service: e.Service}
|
||||||
|
if err := transService.RunTransferJob(transferItems); err != nil {
|
||||||
|
e.Log.Errorf("定时转账执行失败 error:%s", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearAll 清空表数据
|
||||||
|
func (e *WmWalletInfo) ClearAll() error {
|
||||||
|
err := e.Orm.Exec("TRUNCATE TABLE wm_wallet_info;").Error
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@ -11,6 +11,8 @@ import (
|
|||||||
func InitJob() {
|
func InitJob() {
|
||||||
jobList = map[string]JobExec{
|
jobList = map[string]JobExec{
|
||||||
"ExamplesOne": ExamplesOne{},
|
"ExamplesOne": ExamplesOne{},
|
||||||
|
"TransferStatusJob": TransferStatusJob{},
|
||||||
|
"TransferJob": TransferJob{},
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import (
|
|||||||
|
|
||||||
type TransferJob struct{}
|
type TransferJob struct{}
|
||||||
|
|
||||||
|
type TransferStatusJob struct{}
|
||||||
|
|
||||||
// 定期转账
|
// 定期转账
|
||||||
func (t TransferJob) Exec(arg interface{}) error {
|
func (t TransferJob) Exec(arg interface{}) error {
|
||||||
walletService := service.WmWalletInfo{}
|
walletService := service.WmWalletInfo{}
|
||||||
@ -29,3 +31,12 @@ func getDefaultDb() *gorm.DB {
|
|||||||
}
|
}
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 定时查询交易状态
|
||||||
|
func (t TransferStatusJob) Exec(arg interface{}) error {
|
||||||
|
walletService := service.WmTransfer{}
|
||||||
|
walletService.Orm = getDefaultDb()
|
||||||
|
walletService.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
|
||||||
|
return walletService.CheckHashStatus()
|
||||||
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package jobs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go-admin/config"
|
"go-admin/config"
|
||||||
|
helper "go-admin/utils/redishelper"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-admin-team/go-admin-core/sdk"
|
"github.com/go-admin-team/go-admin-core/sdk"
|
||||||
@ -17,7 +18,23 @@ func TestTransferJob(t *testing.T) {
|
|||||||
config.ExtConfig.ApiEndpoint = "https://stylish-cool-fire.ethereum-sepolia.quiknode.pro/17572db4c091accfa5dc6faa0c60a805e5173459"
|
config.ExtConfig.ApiEndpoint = "https://stylish-cool-fire.ethereum-sepolia.quiknode.pro/17572db4c091accfa5dc6faa0c60a805e5173459"
|
||||||
config.ExtConfig.ProxyUrl = "http://127.0.0.1:7890"
|
config.ExtConfig.ProxyUrl = "http://127.0.0.1:7890"
|
||||||
|
|
||||||
|
helper.InitDefaultRedis("http://127.0.0.1:6379", "", 15) // 初始化配置
|
||||||
|
|
||||||
job := TransferJob{}
|
job := TransferJob{}
|
||||||
|
|
||||||
job.Exec(nil)
|
job.Exec(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 测试状态任务
|
||||||
|
func TestTransferStatusJob(t *testing.T) {
|
||||||
|
dsn := "root:123456@tcp(127.0.0.1:3306)/eth_transfer?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
|
sdk.Runtime.SetDb("default", db)
|
||||||
|
|
||||||
|
config.ExtConfig.ApiEndpoint = "https://stylish-cool-fire.ethereum-sepolia.quiknode.pro/17572db4c091accfa5dc6faa0c60a805e5173459"
|
||||||
|
config.ExtConfig.ProxyUrl = "http://127.0.0.1:7890"
|
||||||
|
|
||||||
|
job := TransferStatusJob{}
|
||||||
|
|
||||||
|
job.Exec(nil)
|
||||||
|
}
|
||||||
|
|||||||
@ -3,13 +3,15 @@ package api
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/runtime"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/runtime"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-admin-team/go-admin-core/config/source/file"
|
"github.com/go-admin-team/go-admin-core/config/source/file"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk"
|
"github.com/go-admin-team/go-admin-core/sdk"
|
||||||
@ -20,6 +22,7 @@ import (
|
|||||||
|
|
||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
"go-admin/app/admin/router"
|
"go-admin/app/admin/router"
|
||||||
|
"go-admin/app/admin/service"
|
||||||
"go-admin/app/jobs"
|
"go-admin/app/jobs"
|
||||||
"go-admin/common/database"
|
"go-admin/common/database"
|
||||||
"go-admin/common/global"
|
"go-admin/common/global"
|
||||||
@ -27,6 +30,7 @@ import (
|
|||||||
"go-admin/common/middleware/handler"
|
"go-admin/common/middleware/handler"
|
||||||
"go-admin/common/storage"
|
"go-admin/common/storage"
|
||||||
ext "go-admin/config"
|
ext "go-admin/config"
|
||||||
|
helper "go-admin/utils/redishelper"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -86,6 +90,16 @@ func run() error {
|
|||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//初始化redis
|
||||||
|
helper.InitDefaultRedis(config.CacheConfig.Redis.Addr, config.CacheConfig.Redis.Password, config.CacheConfig.Redis.DB)
|
||||||
|
|
||||||
|
if err := helper.DefaultRedis.Ping(); err != nil {
|
||||||
|
fmt.Println("初始化redis失败")
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
initCache()
|
||||||
|
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Addr: fmt.Sprintf("%s:%d", config.ApplicationConfig.Host, config.ApplicationConfig.Port),
|
Addr: fmt.Sprintf("%s:%d", config.ApplicationConfig.Host, config.ApplicationConfig.Port),
|
||||||
Handler: sdk.Runtime.GetEngine(),
|
Handler: sdk.Runtime.GetEngine(),
|
||||||
@ -184,3 +198,17 @@ func initRouter() {
|
|||||||
common.InitMiddleware(r)
|
common.InitMiddleware(r)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化缓存
|
||||||
|
func initCache() {
|
||||||
|
netWorkService := service.WmNetwork{}
|
||||||
|
dbs := sdk.Runtime.GetDb()
|
||||||
|
netWorkService.Orm = dbs["*"]
|
||||||
|
netWorkService.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
tokenService := service.WmToken{}
|
||||||
|
tokenService.Orm = netWorkService.Orm
|
||||||
|
tokenService.Log = netWorkService.Log
|
||||||
|
|
||||||
|
netWorkService.ReCache()
|
||||||
|
tokenService.ReCache("")
|
||||||
|
}
|
||||||
|
|||||||
8
common/rediskey/prefix_key.go
Normal file
8
common/rediskey/prefix_key.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package rediskey
|
||||||
|
|
||||||
|
const (
|
||||||
|
//区块链网络列表 LIST
|
||||||
|
NetWorks = "network"
|
||||||
|
//代币信息 LIST {networkCode}
|
||||||
|
Tokens = "token:%v"
|
||||||
|
)
|
||||||
@ -50,6 +50,7 @@ settings:
|
|||||||
name: data
|
name: data
|
||||||
|
|
||||||
apiEndpoint: https://stylish-cool-fire.ethereum-sepolia.quiknode.pro/17572db4c091accfa5dc6faa0c60a805e5173459
|
apiEndpoint: https://stylish-cool-fire.ethereum-sepolia.quiknode.pro/17572db4c091accfa5dc6faa0c60a805e5173459
|
||||||
|
proxyUrl: http://127.0.0.1:7890
|
||||||
cache:
|
cache:
|
||||||
redis:
|
redis:
|
||||||
addr: 127.0.0.1:6379
|
addr: 127.0.0.1:6379
|
||||||
|
|||||||
14
go.mod
14
go.mod
@ -49,12 +49,14 @@ require (
|
|||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.20.0 // indirect
|
github.com/bits-and-blooms/bitset v1.20.0 // indirect
|
||||||
github.com/bsm/redislock v0.5.0 // indirect
|
github.com/bsm/redislock v0.5.0 // indirect
|
||||||
github.com/bytedance/sonic v1.9.1 // indirect
|
github.com/bytedance/sonic v1.13.2 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||||
github.com/casbin/redis-watcher/v2 v2.0.0-20220614104201-0e70bf2be930 // indirect
|
github.com/casbin/redis-watcher/v2 v2.0.0-20220614104201-0e70bf2be930 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/chanxuehong/rand v0.0.0-20201110082127-2f19a1bdd973 // indirect
|
github.com/chanxuehong/rand v0.0.0-20201110082127-2f19a1bdd973 // indirect
|
||||||
github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd // indirect
|
github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
|
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||||
github.com/consensys/bavard v0.1.27 // indirect
|
github.com/consensys/bavard v0.1.27 // indirect
|
||||||
github.com/consensys/gnark-crypto v0.16.0 // indirect
|
github.com/consensys/gnark-crypto v0.16.0 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||||
@ -133,6 +135,8 @@ require (
|
|||||||
github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect
|
github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect
|
||||||
github.com/prometheus/common v0.32.1 // indirect
|
github.com/prometheus/common v0.32.1 // indirect
|
||||||
github.com/prometheus/procfs v0.7.3 // indirect
|
github.com/prometheus/procfs v0.7.3 // indirect
|
||||||
|
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||||
|
github.com/richardlehane/msoleps v1.0.4 // indirect
|
||||||
github.com/robinjoseph08/redisqueue/v2 v2.1.0 // indirect
|
github.com/robinjoseph08/redisqueue/v2 v2.1.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/shamsher31/goimgext v1.0.0 // indirect
|
github.com/shamsher31/goimgext v1.0.0 // indirect
|
||||||
@ -141,19 +145,23 @@ require (
|
|||||||
github.com/spf13/cast v1.3.1 // indirect
|
github.com/spf13/cast v1.3.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/supranational/blst v0.3.14 // indirect
|
github.com/supranational/blst v0.3.14 // indirect
|
||||||
|
github.com/tiendc/go-deepcopy v1.6.0 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||||
github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df // indirect
|
github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // 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.11 // indirect
|
||||||
github.com/urfave/cli v1.22.1 // indirect
|
github.com/urfave/cli v1.22.1 // indirect
|
||||||
|
github.com/xuri/efp v0.0.1 // indirect
|
||||||
|
github.com/xuri/excelize/v2 v2.9.1 // indirect
|
||||||
|
github.com/xuri/nfp v0.0.1 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
go.uber.org/atomic v1.6.0 // indirect
|
go.uber.org/atomic v1.6.0 // indirect
|
||||||
go.uber.org/multierr v1.5.0 // indirect
|
go.uber.org/multierr v1.5.0 // indirect
|
||||||
go.uber.org/zap v1.15.0 // indirect
|
go.uber.org/zap v1.15.0 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/image v0.1.0 // indirect
|
golang.org/x/image v0.25.0 // indirect
|
||||||
golang.org/x/net v0.36.0 // indirect
|
golang.org/x/net v0.40.0 // indirect
|
||||||
golang.org/x/sync v0.14.0 // indirect
|
golang.org/x/sync v0.14.0 // indirect
|
||||||
golang.org/x/sys v0.33.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
golang.org/x/text v0.25.0 // indirect
|
golang.org/x/text v0.25.0 // indirect
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go-admin/abis"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -38,7 +37,11 @@ const erc20ABI = `[
|
|||||||
]`
|
]`
|
||||||
|
|
||||||
// GetERC20Balance 查询 ERC-20 代币余额并转换为正常单位 (使用 decimal)
|
// GetERC20Balance 查询 ERC-20 代币余额并转换为正常单位 (使用 decimal)
|
||||||
func GetERC20Balance(client *ethclient.Client, tokenAbi abis.TokenABI, accountAddress string) (decimal.Decimal, error) {
|
// tokenAddress: 代币合约地址
|
||||||
|
// accountAddress: 账户地址
|
||||||
|
// decimals: 代币精度
|
||||||
|
// 返回值: 代币余额 (decimal.Decimal)
|
||||||
|
func GetERC20Balance(client *ethclient.Client, tokenAddress, accountAddress string, decimals int) (decimal.Decimal, error) {
|
||||||
// 1. 解析 ABI
|
// 1. 解析 ABI
|
||||||
contractABI, err := abi.JSON(strings.NewReader(erc20ABI))
|
contractABI, err := abi.JSON(strings.NewReader(erc20ABI))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -51,7 +54,7 @@ func GetERC20Balance(client *ethclient.Client, tokenAbi abis.TokenABI, accountAd
|
|||||||
return decimal.Zero, fmt.Errorf("构造 balanceOf 调用数据失败: %w", err)
|
return decimal.Zero, fmt.Errorf("构造 balanceOf 调用数据失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
address := common.HexToAddress(tokenAbi.TestAddress)
|
address := common.HexToAddress(tokenAddress)
|
||||||
// 3. 执行 balanceOf 调用
|
// 3. 执行 balanceOf 调用
|
||||||
balanceResult, err := client.CallContract(context.Background(), ethereum.CallMsg{
|
balanceResult, err := client.CallContract(context.Background(), ethereum.CallMsg{
|
||||||
To: &address,
|
To: &address,
|
||||||
@ -74,7 +77,7 @@ func GetERC20Balance(client *ethclient.Client, tokenAbi abis.TokenABI, accountAd
|
|||||||
|
|
||||||
// 8. 转换为正常单位 (使用 decimal)
|
// 8. 转换为正常单位 (使用 decimal)
|
||||||
balanceDecimal := decimal.NewFromBigInt(balance, 0) // Create decimal from big.Int
|
balanceDecimal := decimal.NewFromBigInt(balance, 0) // Create decimal from big.Int
|
||||||
decimalFactor := decimal.NewFromInt(10).Pow(decimal.NewFromInt(int64(tokenAbi.Decimals)))
|
decimalFactor := decimal.NewFromInt(10).Pow(decimal.NewFromInt(int64(decimals)))
|
||||||
readableBalance := balanceDecimal.Div(decimalFactor)
|
readableBalance := balanceDecimal.Div(decimalFactor)
|
||||||
|
|
||||||
return readableBalance, nil
|
return readableBalance, nil
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
@ -13,21 +14,114 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TransferErc20 发送 ERC-20 代币交易。
|
||||||
|
// tokenaddress: ERC-20 代币的合约地址。 如果为空则转移ETH
|
||||||
|
func TransferErc20(
|
||||||
|
client *ethclient.Client,
|
||||||
|
fromPrivateKey string,
|
||||||
|
tokenAddress string,
|
||||||
|
toAddress string,
|
||||||
|
tokenAmount decimal.Decimal,
|
||||||
|
tokenDecimals uint8) (*types.Transaction, error) {
|
||||||
|
switch tokenAddress {
|
||||||
|
case "":
|
||||||
|
return TransferEth(client, fromPrivateKey, toAddress, tokenAmount)
|
||||||
|
default:
|
||||||
|
return TransferErc20Token(client, fromPrivateKey, tokenAddress, toAddress, tokenAmount, tokenDecimals)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransferEth 发送 ETH 交易。
|
||||||
|
func TransferEth(client *ethclient.Client, fromPrivateKey string, toAddress string, tokenAmount decimal.Decimal) (*types.Transaction, error) {
|
||||||
|
// 1. 解析私钥
|
||||||
|
privateKey, fromAddressCommon, err := GetAddressFromPrivateKey(fromPrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 获取发送者的 nonce(交易序号)
|
||||||
|
nonce, err := client.PendingNonceAt(context.Background(), fromAddressCommon)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("获取 nonce 失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 设置交易的 value (对于代币转账,value 是 0)
|
||||||
|
value, _ := convertDecimalToBigInt(tokenAmount, 18)
|
||||||
|
|
||||||
|
// 5. 获取 Gas 价格
|
||||||
|
gasPrice, err := client.SuggestGasPrice(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("获取 Gas 价格失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 将地址字符串转换为 common.Address 类型
|
||||||
|
toAddressCommon := common.HexToAddress(toAddress)
|
||||||
|
|
||||||
|
// 7. 构造 ERC-20 transfer 函数的调用数据
|
||||||
|
// 7.1 函数签名:transfer(address,uint256)
|
||||||
|
transferFnSignature := "transfer(address,uint256)" // 已经是标准化的
|
||||||
|
hash := sha3.NewLegacyKeccak256() // 或 sha3.NewLegacyKeccak256()
|
||||||
|
hash.Write([]byte(transferFnSignature))
|
||||||
|
|
||||||
|
// 7.4 拼接调用数据
|
||||||
|
var data []byte
|
||||||
|
|
||||||
|
// 8. 估算 Gas 消耗
|
||||||
|
gasLimit, err := client.EstimateGas(context.Background(), ethereum.CallMsg{
|
||||||
|
From: fromAddressCommon,
|
||||||
|
To: &toAddressCommon,
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("估算 Gas 消耗失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9. (预估gas+基础费用)*1.1 作为 GasLimit
|
||||||
|
gasLimit = (gasLimit + 21000) * 12 / 10 // 增加 20%
|
||||||
|
if gasLimit < 23000 {
|
||||||
|
gasLimit = 23000 // 最小 Gas 限制
|
||||||
|
}
|
||||||
|
|
||||||
|
// 10. 创建交易
|
||||||
|
tx := types.NewTransaction(nonce, toAddressCommon, value, gasLimit, gasPrice, data)
|
||||||
|
|
||||||
|
// 11. 获取链 ID
|
||||||
|
chainID, err := client.NetworkID(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("获取链 ID 失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 12. 签名交易
|
||||||
|
signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("签名交易失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 13. 发送交易
|
||||||
|
err = client.SendTransaction(context.Background(), signedTx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("发送交易失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return signedTx, nil
|
||||||
|
}
|
||||||
|
|
||||||
// transferErc20Token 发送 ERC-20 代币交易。
|
// transferErc20Token 发送 ERC-20 代币交易。
|
||||||
// tokenAmount: 要发送的代币数量 (例如,1.0 代表 1 个代币)。
|
// tokenAmount: 要发送的代币数量 (例如,1.0 代表 1 个代币)。
|
||||||
// fromPrivateKey: 发送者的私钥。
|
// fromPrivateKey: 发送者的私钥。
|
||||||
// tokenAddress: ERC-20 代币的合约地址。
|
// tokenAddress: ERC-20 代币的合约地址。
|
||||||
// toAddress: 接收者的地址。
|
// toAddress: 接收者的地址。
|
||||||
// tokenDecimals: 代币的小数位数 (例如,USDC 是 6,很多其他代币是 18)。
|
// tokenDecimals: 代币的小数位数 (例如,USDC 是 6,很多其他代币是 18)。
|
||||||
func transferErc20Token(
|
func TransferErc20Token(
|
||||||
client *ethclient.Client,
|
client *ethclient.Client,
|
||||||
fromPrivateKey string,
|
fromPrivateKey string,
|
||||||
tokenAddress string,
|
tokenAddress string,
|
||||||
toAddress string,
|
toAddress string,
|
||||||
tokenAmount float64,
|
tokenAmount decimal.Decimal,
|
||||||
tokenDecimals uint8,
|
tokenDecimals uint8,
|
||||||
) (*types.Transaction, error) {
|
) (*types.Transaction, error) {
|
||||||
// 1. 解析私钥
|
// 1. 解析私钥
|
||||||
@ -57,15 +151,15 @@ func transferErc20Token(
|
|||||||
|
|
||||||
// 7. 构造 ERC-20 transfer 函数的调用数据
|
// 7. 构造 ERC-20 transfer 函数的调用数据
|
||||||
// 7.1 函数签名:transfer(address,uint256)
|
// 7.1 函数签名:transfer(address,uint256)
|
||||||
transferFnSignature := []byte("transfer(address,uint256)")
|
transferFnSignature := "transfer(address,uint256)" // 已经是标准化的
|
||||||
hash := sha3.New256()
|
hash := sha3.NewLegacyKeccak256() // 或 sha3.NewLegacyKeccak256()
|
||||||
hash.Write(transferFnSignature)
|
hash.Write([]byte(transferFnSignature))
|
||||||
methodID := hash.Sum(nil)[:4] // 取前 4 个字节作为方法 ID
|
methodID := hash.Sum(nil)[:4]
|
||||||
|
|
||||||
// 7.2 填充接收者地址和转账金额
|
// 7.2 填充接收者地址和转账金额
|
||||||
paddedAddress := common.LeftPadBytes(toAddressCommon.Bytes(), 32)
|
paddedAddress := common.LeftPadBytes(toAddressCommon.Bytes(), 32)
|
||||||
// 7.3 将代币数量转换为最小单位
|
// 7.3 将代币数量转换为最小单位
|
||||||
amountBigInt, err := convertTokenAmountToBigInt(tokenAmount, tokenDecimals)
|
amountBigInt, err := convertDecimalToBigInt(tokenAmount, tokenDecimals)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("转换代币数量失败: %w", err)
|
return nil, fmt.Errorf("转换代币数量失败: %w", err)
|
||||||
}
|
}
|
||||||
@ -80,15 +174,15 @@ func transferErc20Token(
|
|||||||
// 8. 估算 Gas 消耗
|
// 8. 估算 Gas 消耗
|
||||||
gasLimit, err := client.EstimateGas(context.Background(), ethereum.CallMsg{
|
gasLimit, err := client.EstimateGas(context.Background(), ethereum.CallMsg{
|
||||||
From: fromAddressCommon,
|
From: fromAddressCommon,
|
||||||
To: &tokenAddressCommon,
|
To: &toAddressCommon,
|
||||||
Data: data,
|
Data: data,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("估算 Gas 消耗失败: %w", err)
|
return nil, fmt.Errorf("估算 Gas 消耗失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 9. 增加 Gas 限制的安全边际
|
// 9. (预估gas+基础费用)*1.1 作为 GasLimit
|
||||||
gasLimit = gasLimit * 11 / 10 // 增加 10%
|
gasLimit = (gasLimit + 21000) * 12 / 10 // 增加 20%
|
||||||
if gasLimit < 23000 {
|
if gasLimit < 23000 {
|
||||||
gasLimit = 23000 // 最小 Gas 限制
|
gasLimit = 23000 // 最小 Gas 限制
|
||||||
}
|
}
|
||||||
@ -140,36 +234,45 @@ func GetAddressFromPrivateKey(fromPrivateKey string) (*ecdsa.PrivateKey, common.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// convertTokenAmountToBigInt 将代币数量 (例如,1.0) 转换为最小单位的整数表示 (例如,USDC 的 1000000)。
|
// convertTokenAmountToBigInt 将代币数量 (例如,1.0) 转换为最小单位的整数表示 (例如,USDC 的 1000000)。
|
||||||
func convertTokenAmountToBigInt(tokenAmount float64, tokenDecimals uint8) (*big.Int, error) {
|
func convertDecimalToBigInt(amountDecimal decimal.Decimal, tokenDecimals uint8) (*big.Int, error) {
|
||||||
// 1. 使用最大精度格式化浮点数
|
// 1. 创建一个与 token decimals 精度相同的 10 的幂
|
||||||
amountStr := fmt.Sprintf("%.18f", tokenAmount) // 使用最大精度
|
exponent := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(tokenDecimals)), nil)
|
||||||
|
|
||||||
// 2. 找到小数点的位置
|
// 2. 将 decimal 乘以该 10 的幂
|
||||||
decimalPointIndex := strings.Index(amountStr, ".")
|
amountScaled := amountDecimal.Mul(decimal.NewFromBigInt(exponent, 0))
|
||||||
|
|
||||||
// 3. 如果没有小数点,则添加足够的 0
|
// 3. 将 scaled decimal 转换为 big.Int
|
||||||
if decimalPointIndex == -1 {
|
amountBigInt := amountScaled.BigInt()
|
||||||
amountStr += "." + strings.Repeat("0", int(tokenDecimals))
|
|
||||||
} else {
|
|
||||||
// 4. 计算需要填充的 0 的数量
|
|
||||||
paddingNeeded := int(tokenDecimals) - (len(amountStr) - decimalPointIndex - 1)
|
|
||||||
|
|
||||||
// 5. 填充 0 或截断多余的小数位
|
|
||||||
if paddingNeeded > 0 {
|
|
||||||
amountStr += strings.Repeat("0", paddingNeeded)
|
|
||||||
} else if paddingNeeded < 0 {
|
|
||||||
amountStr = amountStr[:decimalPointIndex+int(tokenDecimals)+1]
|
|
||||||
}
|
|
||||||
// 6. 移除小数点
|
|
||||||
amountStr = strings.ReplaceAll(amountStr, ".", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 7. 将字符串转换为 big.Int
|
|
||||||
amountBigInt := new(big.Int)
|
|
||||||
amountBigInt, ok := amountBigInt.SetString(amountStr, 10)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("将金额字符串转换为 big.Int 失败: %s", amountStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return amountBigInt, nil
|
return amountBigInt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTransactionByHash 获取交易的状态。
|
||||||
|
// status 0:失败 1-成功
|
||||||
|
// error: 交易未确认或不存在
|
||||||
|
func GetTransactionByHash(client *ethclient.Client, hash string) (int, error) {
|
||||||
|
txHash := common.HexToHash(hash)
|
||||||
|
// 获取交易收据(包含状态)
|
||||||
|
receipt, err := client.TransactionReceipt(context.Background(), txHash)
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.New("交易未确认或不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(receipt.Status), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验钱包地址是否合法
|
||||||
|
func IsValidAddress(address string) bool {
|
||||||
|
if !strings.HasPrefix(address, "0x") {
|
||||||
|
address = "0x" + address
|
||||||
|
}
|
||||||
|
if len(address) != 42 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !regexp.MustCompile(`^0x[0-9a-fA-F]{40}$`).MatchString(address) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
checksumAddress := common.HexToAddress(address).String()
|
||||||
|
return address == checksumAddress
|
||||||
|
}
|
||||||
|
|||||||
169
utils/excelhelper/excel_helper.go
Normal file
169
utils/excelhelper/excel_helper.go
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
package excelhelper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
helper "go-admin/utils"
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/xuri/excelize/v2"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
导出csv文件
|
||||||
|
|
||||||
|
- @fileName 文件名 不带拓展名
|
||||||
|
- @header 文件头
|
||||||
|
- @records 内容
|
||||||
|
*/
|
||||||
|
func ExportCSV(c *gin.Context, fileName string, header []string, records [][]string) error {
|
||||||
|
disposition := fmt.Sprintf("attachment; filename=%s.csv", fileName)
|
||||||
|
|
||||||
|
// Set headers
|
||||||
|
c.Header("Content-Description", "File Transfer")
|
||||||
|
c.Header("Content-Disposition", disposition)
|
||||||
|
c.Header("Content-Type", "text/csv")
|
||||||
|
|
||||||
|
// Create a CSV writer using the response writer
|
||||||
|
writer := csv.NewWriter(c.Writer)
|
||||||
|
defer writer.Flush()
|
||||||
|
|
||||||
|
// Write CSV header
|
||||||
|
writer.Write(header)
|
||||||
|
|
||||||
|
for _, record := range records {
|
||||||
|
writer.Write(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
导出excel
|
||||||
|
|
||||||
|
- @fileName 文件名称
|
||||||
|
- @data 数据源
|
||||||
|
- @ingore 忽略header
|
||||||
|
*/
|
||||||
|
func ExportExcel[T any](c *gin.Context, fileName string, data []T, ingore []string) error {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return errors.New("无导出记录")
|
||||||
|
}
|
||||||
|
// Create a new Excel file
|
||||||
|
f := excelize.NewFile()
|
||||||
|
// Use reflection to get the header from struct tags
|
||||||
|
t := reflect.TypeOf(data[0])
|
||||||
|
headers := []string{}
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
field := t.Field(i)
|
||||||
|
excelTag := field.Tag.Get("excel")
|
||||||
|
if excelTag != "" && !helper.ArrayAny(ingore, excelTag) {
|
||||||
|
headers = append(headers, excelTag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set headers
|
||||||
|
for i, header := range headers {
|
||||||
|
col := string('A' + i)
|
||||||
|
cell := fmt.Sprintf("%s1", col)
|
||||||
|
f.SetCellValue("Sheet1", cell, header)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill rows with data
|
||||||
|
for rowIndex, item := range data {
|
||||||
|
rowValue := reflect.ValueOf(item)
|
||||||
|
rowType := rowValue.Type()
|
||||||
|
for colIndex, header := range headers {
|
||||||
|
col := string('A' + colIndex)
|
||||||
|
cell := fmt.Sprintf("%s%d", col, rowIndex+2)
|
||||||
|
var fieldValue reflect.Value
|
||||||
|
|
||||||
|
for i := 0; i < rowType.NumField(); i++ {
|
||||||
|
field := rowType.Field(i)
|
||||||
|
if strings.EqualFold(field.Tag.Get("excel"), header) {
|
||||||
|
fieldValue = rowValue.Field(i)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the fieldValue is valid before accessing it
|
||||||
|
if fieldValue.IsValid() && fieldValue.CanInterface() {
|
||||||
|
//f.SetCellValue("Sheet1", cell, fieldValue.Interface())
|
||||||
|
value := fieldValue.Interface()
|
||||||
|
|
||||||
|
// Ensure the value is a string, convert it if necessary
|
||||||
|
var stringValue string
|
||||||
|
if v, ok := value.(string); ok {
|
||||||
|
stringValue = v // If it's a string, use it directly
|
||||||
|
} else {
|
||||||
|
stringValue = fmt.Sprintf("%v", value) // Otherwise, convert to string
|
||||||
|
}
|
||||||
|
f.SetCellValue("Sheet1", cell, stringValue)
|
||||||
|
} else {
|
||||||
|
// Handle the case where fieldValue is invalid or nil
|
||||||
|
f.SetCellValue("Sheet1", cell, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set response headers and send the file to the client
|
||||||
|
|
||||||
|
// c.Writer.Header().Set("Content-Disposition", "attachment; filename=test.xlsx")
|
||||||
|
// c.Writer.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=binary")
|
||||||
|
// c.Writer.Header().Set("Content-Transfer-Encoding", "binary")
|
||||||
|
// c.Writer.Header().Set("Expires", "0")
|
||||||
|
// c.Writer.Header().Set("Cache-Control", "must-revalidate")
|
||||||
|
// c.Writer.Header().Set("Pragma", "public")
|
||||||
|
c.Header("Content-Description", "File Transfer")
|
||||||
|
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s.xlsx", fileName))
|
||||||
|
c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||||
|
c.Header("Content-Transfer-Encoding", "binary")
|
||||||
|
c.Header("Expires", "0")
|
||||||
|
c.Header("Cache-Control", "must-revalidate")
|
||||||
|
c.Header("Pragma", "public")
|
||||||
|
c.Header("Content-Encoding", "")
|
||||||
|
//fmt.Println("c.Writer.Header():", c.Writer.Header())
|
||||||
|
if _, err := f.WriteTo(c.Writer); err != nil {
|
||||||
|
log.Println("Error writing file:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
//return f.WriteTo(c.Writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapExcelToStruct[T any](rows [][]string, headers []string) ([]T, error) {
|
||||||
|
var results []T
|
||||||
|
if len(rows) == 0 {
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, row := range rows {
|
||||||
|
var result T
|
||||||
|
v := reflect.ValueOf(&result).Elem()
|
||||||
|
|
||||||
|
for i, header := range headers {
|
||||||
|
fieldName := ""
|
||||||
|
for j := 0; j < v.NumField(); j++ {
|
||||||
|
field := v.Type().Field(j)
|
||||||
|
tag := field.Tag.Get("excel")
|
||||||
|
if strings.EqualFold(tag, header) {
|
||||||
|
fieldName = field.Name
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fieldName != "" && i < len(row) {
|
||||||
|
field := v.FieldByName(fieldName)
|
||||||
|
if field.IsValid() && field.CanSet() {
|
||||||
|
field.Set(reflect.ValueOf(row[i]).Convert(field.Type()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results = append(results, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
52
utils/extension_helper.go
Normal file
52
utils/extension_helper.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
/*
|
||||||
|
判断是否存在
|
||||||
|
|
||||||
|
- @arr 数组
|
||||||
|
- @value 值
|
||||||
|
*/
|
||||||
|
func ArrayAny[T comparable](arr []T, value T) bool {
|
||||||
|
for _, v := range arr {
|
||||||
|
if v == value {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义一个条件函数类型
|
||||||
|
type ConditionFunc[T any] func(T) bool
|
||||||
|
|
||||||
|
/*
|
||||||
|
判断是否存在
|
||||||
|
|
||||||
|
- @arr 数组
|
||||||
|
|
||||||
|
- @condition 判断函数
|
||||||
|
|
||||||
|
@return 对象指针
|
||||||
|
*/
|
||||||
|
func ArrayAnyExtension[T any](arr *[]T, condition ConditionFunc[T]) *T {
|
||||||
|
for _, v := range *arr {
|
||||||
|
if condition(v) {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveDuplicates(nums []int64) []int64 {
|
||||||
|
m := make(map[int64]bool)
|
||||||
|
result := []int64{}
|
||||||
|
|
||||||
|
for _, num := range nums {
|
||||||
|
if !m[num] {
|
||||||
|
m[num] = true
|
||||||
|
result = append(result, num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
779
utils/redishelper/redis_helper.go
Normal file
779
utils/redishelper/redis_helper.go
Normal file
@ -0,0 +1,779 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RedisHelper 结构体封装了 Redis 客户端及上下文
|
||||||
|
type RedisHelper struct {
|
||||||
|
client *redis.Client // Redis 客户端
|
||||||
|
ctx context.Context // 上下文
|
||||||
|
emptyCacheValue string // 缓存空值的标志
|
||||||
|
}
|
||||||
|
|
||||||
|
var DefaultRedis *RedisHelper
|
||||||
|
|
||||||
|
// 初始化默认链接
|
||||||
|
func InitDefaultRedis(addr, password string, db int) {
|
||||||
|
if DefaultRedis == nil {
|
||||||
|
DefaultRedis = NewRedisHelper(addr, password, db)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("初始化redis链接")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRedisHelper 创建一个新的 RedisHelper 实例
|
||||||
|
func NewRedisHelper(addr, password string, db int) *RedisHelper {
|
||||||
|
rdb := redis.NewClient(&redis.Options{
|
||||||
|
Addr: addr, // Redis 服务器地址
|
||||||
|
Password: password, // Redis 密码
|
||||||
|
DB: db, // 使用的数据库编号
|
||||||
|
PoolSize: 50,
|
||||||
|
MinIdleConns: 10,
|
||||||
|
DialTimeout: 10 * time.Second, // 调整连接超时时间
|
||||||
|
ReadTimeout: 10 * time.Second, // 调整读超时时间
|
||||||
|
WriteTimeout: 10 * time.Second, // 调整写超时时间
|
||||||
|
})
|
||||||
|
|
||||||
|
return &RedisHelper{
|
||||||
|
client: rdb,
|
||||||
|
ctx: context.Background(), // 创建背景上下文
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试连接
|
||||||
|
func (r *RedisHelper) Ping() error {
|
||||||
|
return r.client.Ping(r.ctx).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetString 设置字符串值
|
||||||
|
func (r *RedisHelper) SetString(key, value string) error {
|
||||||
|
return r.client.Set(r.ctx, key, value, 0).Err() // 将值存储到指定的键
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量设置
|
||||||
|
func (r *RedisHelper) BatchSet(maps *map[string]string) error {
|
||||||
|
pipe := r.client.Pipeline()
|
||||||
|
|
||||||
|
for key, val := range *maps {
|
||||||
|
pipe.Set(r.ctx, key, val, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := pipe.Exec(r.ctx)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetString 设置字符串值
|
||||||
|
func (r *RedisHelper) SetStringExpire(key, value string, expireTime time.Duration) error {
|
||||||
|
return r.client.Set(r.ctx, key, value, expireTime).Err() // 将值存储到指定的键
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetString 设置字符串值
|
||||||
|
func (r *RedisHelper) SetAdd(key, value string, expireTime time.Duration) error {
|
||||||
|
// 存储到 SET 中
|
||||||
|
result, err := r.client.SAdd(r.ctx, key, value).Result()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if result == 1 {
|
||||||
|
// 设置 SET 的过期时间
|
||||||
|
err = r.client.Expire(r.ctx, key, expireTime).Err()
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("设置过期时间失败:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return errors.New("key已存在")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置对象
|
||||||
|
func SetObjString[T any](r *RedisHelper, key string, value T) error {
|
||||||
|
keyValue, err := sonic.Marshal(value)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.SetString(key, string(keyValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取对象
|
||||||
|
func GetObjString[T any](r *RedisHelper, key string) (T, error) {
|
||||||
|
var result T
|
||||||
|
value, err := r.GetString(key)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sonic.Unmarshal([]byte(value), &result)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHelper) Get(key string) *redis.StringCmd {
|
||||||
|
return r.client.Get(r.ctx, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
获取剩余时间
|
||||||
|
- @key redis key
|
||||||
|
*/
|
||||||
|
func (r *RedisHelper) TTL(key string) *redis.DurationCmd {
|
||||||
|
return r.client.TTL(r.ctx, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetString 获取字符串值
|
||||||
|
func (r *RedisHelper) GetString(key string) (string, error) {
|
||||||
|
return r.client.Get(r.ctx, key).Result() // 从指定的键获取值
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteString 删除字符串键
|
||||||
|
func (r *RedisHelper) DeleteString(key string) error {
|
||||||
|
return r.client.Del(r.ctx, key).Err() // 删除指定的键
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteString 删除目录下所有key
|
||||||
|
func (r *RedisHelper) DeleteAll(key string) error {
|
||||||
|
keys, err := r.ScanKeys(key)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.BatchDeleteKeys(keys)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
递增
|
||||||
|
- @key rediskey
|
||||||
|
*/
|
||||||
|
func (r *RedisHelper) Incr(key string) *redis.IntCmd {
|
||||||
|
return r.client.Incr(r.ctx, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
设置过期时间
|
||||||
|
- @key redis key
|
||||||
|
- @expiration 过期时间
|
||||||
|
*/
|
||||||
|
func (r *RedisHelper) Expire(key string, expiration time.Duration) *redis.BoolCmd {
|
||||||
|
return r.client.Expire(r.ctx, key, expiration)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
批量删除
|
||||||
|
|
||||||
|
- @keys 键数组
|
||||||
|
*/
|
||||||
|
func (r *RedisHelper) BatchDeleteKeys(keys []string) (int, error) {
|
||||||
|
if r.client == nil {
|
||||||
|
return 0, errors.New("Redis client is nil")
|
||||||
|
}
|
||||||
|
if len(keys) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
deletedCount := 0
|
||||||
|
batchSize := 1000 // 每批次删除的键数量
|
||||||
|
for i := 0; i < len(keys); i += batchSize {
|
||||||
|
end := i + batchSize
|
||||||
|
if end > len(keys) {
|
||||||
|
end = len(keys)
|
||||||
|
}
|
||||||
|
batch := keys[i:end]
|
||||||
|
|
||||||
|
_, err := r.client.Pipelined(r.ctx, func(pipe redis.Pipeliner) error {
|
||||||
|
for _, key := range batch {
|
||||||
|
pipe.Del(r.ctx, key)
|
||||||
|
deletedCount++
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return deletedCount, fmt.Errorf("failed to delete keys in batch: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return deletedCount, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteKeysByPrefix 删除指定前缀的键
|
||||||
|
func (r *RedisHelper) DeleteKeysByPrefix(prefixes ...string) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
// 遍历每个前缀
|
||||||
|
for _, prefix := range prefixes {
|
||||||
|
var cursor uint64
|
||||||
|
var keys []string
|
||||||
|
|
||||||
|
// 使用 SCAN 命令查找匹配的键
|
||||||
|
for {
|
||||||
|
var err error
|
||||||
|
keys, cursor, err = r.client.Scan(ctx, cursor, prefix+"*", 1000).Result()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除匹配的键
|
||||||
|
if len(keys) > 0 {
|
||||||
|
_, err := r.client.Del(ctx, keys...).Result()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("Deleted keys with prefix '%s': %v\n", prefix, keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果游标为 0,表示迭代结束
|
||||||
|
if cursor == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找所有value
|
||||||
|
func (r *RedisHelper) GetAllKeysAndValues(pattern string) ([]string, error) {
|
||||||
|
var cursor uint64
|
||||||
|
var result = []string{}
|
||||||
|
|
||||||
|
for {
|
||||||
|
// 使用 SCAN 命令获取匹配的键
|
||||||
|
keys, nextCursor, err := r.client.Scan(r.ctx, cursor, pattern+"*", 1000).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error scanning keys: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理匹配到的键
|
||||||
|
for _, key := range keys {
|
||||||
|
value, err := r.client.Get(r.ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
if err == redis.Nil {
|
||||||
|
fmt.Printf("Key %s does not exist\n", key)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Error getting value for key %s: %v", key, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = append(result, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 cursor 为 0,表示扫描完成
|
||||||
|
if nextCursor == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
cursor = nextCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LPushList 将一个或多个值插入到列表的头部
|
||||||
|
func (r *RedisHelper) LPushList(key string, values ...string) error {
|
||||||
|
return r.client.LPush(r.ctx, key, values).Err() // 将值插入到列表的头部
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPushList 将一个或多个值插入到列表的尾部
|
||||||
|
func (r *RedisHelper) RPushList(key string, values ...string) error {
|
||||||
|
return r.client.RPush(r.ctx, key, values).Err() // 将值插入到列表的尾部
|
||||||
|
}
|
||||||
|
|
||||||
|
// LPopList 从列表的头部弹出一个元素
|
||||||
|
func (r *RedisHelper) LPopList(key string) (string, error) {
|
||||||
|
return r.client.LPop(r.ctx, key).Result() // 从列表的头部移除并返回第一个元素
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPopList 从列表的尾部弹出一个元素
|
||||||
|
func (r *RedisHelper) RPopList(key string) (string, error) {
|
||||||
|
return r.client.RPop(r.ctx, key).Result() // 从列表的尾部移除并返回最后一个元素
|
||||||
|
}
|
||||||
|
|
||||||
|
// LRangeList 获取列表中指定范围的元素
|
||||||
|
func (r *RedisHelper) LRangeList(key string, start, stop int64) ([]string, error) {
|
||||||
|
return r.client.LRange(r.ctx, key, start, stop).Result() // 获取列表中指定范围的元素
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllList 获取列表中的所有元素
|
||||||
|
func (r *RedisHelper) GetAllList(key string) ([]string, error) {
|
||||||
|
values, err := r.client.LRange(r.ctx, key, 0, -1).Result()
|
||||||
|
if err == redis.Nil {
|
||||||
|
return nil, nil
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否包含空值标志
|
||||||
|
if len(values) == 1 && values[0] == r.emptyCacheValue {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return values, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHelper) LRem(key, val string) (int64, error) {
|
||||||
|
count := 0 // 删除所有与 valueToRemove 相等的元素
|
||||||
|
result, err := r.client.LRem(r.ctx, key, int64(count), val).Result()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("删除元素失败: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHelper) IsElementInList(key string, element string) (bool, error) {
|
||||||
|
var cursor int64 = 0
|
||||||
|
const batchSize int64 = 1000 // 每批次获取的元素数量
|
||||||
|
|
||||||
|
for {
|
||||||
|
// 分批次获取列表元素
|
||||||
|
elements, err := r.client.LRange(r.ctx, key, cursor, cursor+batchSize-1).Result()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if len(elements) == 0 {
|
||||||
|
break // 没有更多数据
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历当前批次的元素
|
||||||
|
for _, e := range elements {
|
||||||
|
if e == element {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor += batchSize // 移动到下一批次
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
SetListCache 重新设置列表缓存
|
||||||
|
- @expiration 0-过期 1-过期时间
|
||||||
|
*/
|
||||||
|
func (r *RedisHelper) SetListCache(key string, expiration time.Duration, values ...string) error {
|
||||||
|
tempKey := key + ":temp"
|
||||||
|
|
||||||
|
// 使用事务来确保操作的原子性
|
||||||
|
pipe := r.client.TxPipeline()
|
||||||
|
|
||||||
|
// 将新数据插入到临时列表中
|
||||||
|
pipe.RPush(r.ctx, tempKey, values)
|
||||||
|
|
||||||
|
// 重命名临时列表为目标列表
|
||||||
|
pipe.Rename(r.ctx, tempKey, key)
|
||||||
|
|
||||||
|
if expiration > 0 {
|
||||||
|
// 设置目标列表的过期时间
|
||||||
|
pipe.Expire(r.ctx, key, expiration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行事务
|
||||||
|
_, err := pipe.Exec(r.ctx)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEmptyListCache 设置空值缓存
|
||||||
|
func (r *RedisHelper) SetEmptyListCache(key string, expiration time.Duration) error {
|
||||||
|
// 使用一个特殊标志值表示列表为空
|
||||||
|
_, err := r.client.RPush(r.ctx, key, r.emptyCacheValue).Result()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置列表的过期时间
|
||||||
|
return r.client.Expire(r.ctx, key, expiration).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanKeys 使用 SCAN 命令获取所有匹配的键
|
||||||
|
func (r *RedisHelper) ScanKeys(pattern string) ([]string, error) {
|
||||||
|
|
||||||
|
var cursor uint64
|
||||||
|
var keys []string
|
||||||
|
for {
|
||||||
|
var newKeys []string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// SCAN 命令每次返回部分匹配的键
|
||||||
|
newKeys, cursor, err = r.client.Scan(r.ctx, cursor, pattern, 1000).Result()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
keys = append(keys, newKeys...)
|
||||||
|
if cursor == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 泛型函数,用于获取所有键的列表数据并合并为一个数组
|
||||||
|
func GetAndMergeLists[T any](r *RedisHelper, keys []string) ([]T, error) {
|
||||||
|
var combinedList []T
|
||||||
|
for _, key := range keys {
|
||||||
|
// 获取每个键的列表数据
|
||||||
|
listData, err := r.client.LRange(r.ctx, key, 0, -1).Result()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解码每个数据项为类型 T,并添加到结果列表中
|
||||||
|
for _, data := range listData {
|
||||||
|
var item T
|
||||||
|
if err := sonic.Unmarshal([]byte(data), &item); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
combinedList = append(combinedList, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return combinedList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNX 实现类似于 Redis 的 SETNX 命令
|
||||||
|
func (r *RedisHelper) SetNX(key string, value interface{}, expiration time.Duration) (bool, error) {
|
||||||
|
result, err := r.client.Set(r.ctx, key, value, expiration).Result()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果键不存在则 result 会等于 "OK"
|
||||||
|
return result == "OK", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFieldsFromStruct(obj interface{}) map[string]interface{} {
|
||||||
|
fields := make(map[string]interface{})
|
||||||
|
val := reflect.ValueOf(obj)
|
||||||
|
typ := reflect.TypeOf(obj)
|
||||||
|
|
||||||
|
for i := 0; i < val.NumField(); i++ {
|
||||||
|
field := typ.Field(i)
|
||||||
|
tag := field.Tag.Get("redis")
|
||||||
|
if tag != "" {
|
||||||
|
fieldVal := val.Field(i)
|
||||||
|
if fieldVal.Kind() == reflect.Slice || fieldVal.Kind() == reflect.Map {
|
||||||
|
// 处理切片或映射类型
|
||||||
|
// 对于切片,使用索引作为字段名
|
||||||
|
if fieldVal.Kind() == reflect.Slice {
|
||||||
|
for j := 0; j < fieldVal.Len(); j++ {
|
||||||
|
elem := fieldVal.Index(j).Interface()
|
||||||
|
fields[fmt.Sprintf("%s_%d", tag, j)] = elem
|
||||||
|
}
|
||||||
|
} else if fieldVal.Kind() == reflect.Map {
|
||||||
|
// 对于映射,使用键作为字段名
|
||||||
|
for _, key := range fieldVal.MapKeys() {
|
||||||
|
elem := fieldVal.MapIndex(key).Interface()
|
||||||
|
fields[fmt.Sprintf("%s_%v", tag, key.Interface())] = elem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fields[tag] = fieldVal.Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHelper) SetHashWithTags(key string, obj interface{}) error {
|
||||||
|
fields := getFieldsFromStruct(obj)
|
||||||
|
_, err := r.client.HSet(r.ctx, key, fields).Result()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// HSetField 设置哈希中的一个字段
|
||||||
|
func (r *RedisHelper) HSetField(key, field string, value interface{}) error {
|
||||||
|
_, err := r.client.HSet(r.ctx, key, field, value).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error setting field %s in hash %s: %v", field, key, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HSetMultipleFields 设置哈希中的多个字段
|
||||||
|
func (r *RedisHelper) HSetMultipleFields(key string, fields map[string]interface{}) error {
|
||||||
|
_, err := r.client.HSet(r.ctx, key, fields).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error setting multiple fields in hash %s: %v", key, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HGetField 获取哈希中某个字段的值
|
||||||
|
func (r *RedisHelper) HGetField(key, field string) (string, error) {
|
||||||
|
val, err := r.client.HGet(r.ctx, key, field).Result()
|
||||||
|
if err != nil {
|
||||||
|
if err == redis.Nil {
|
||||||
|
return "", nil // Field does not exist
|
||||||
|
}
|
||||||
|
log.Printf("Error getting field %s from hash %s: %v", field, key, err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HGetAllFields 获取哈希中所有字段的值
|
||||||
|
func (r *RedisHelper) HGetAllFields(key string) (map[string]string, error) {
|
||||||
|
fields, err := r.client.HGetAll(r.ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error getting all fields from hash %s: %v", key, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return fields, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HDelField 删除哈希中的某个字段
|
||||||
|
func (r *RedisHelper) HDelField(key, field string) error {
|
||||||
|
_, err := r.client.HDel(r.ctx, key, field).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error deleting field %s from hash %s: %v", field, key, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除哈希
|
||||||
|
func (r *RedisHelper) HDelAll(key string) error {
|
||||||
|
_, err := r.client.Del(r.ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error deleting from hash %s: %v", key, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HKeys 获取哈希中所有字段的名字
|
||||||
|
func (r *RedisHelper) HKeys(key string) ([]string, error) {
|
||||||
|
fields, err := r.client.HKeys(r.ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error getting keys from hash %s: %v", key, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return fields, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHelper) HExists(key, field, value string) (bool, error) {
|
||||||
|
exists, err := r.client.HExists(r.ctx, key, field).Result()
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("check existence failed: %v", err)
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
storedValue, err := r.client.HGet(r.ctx, key, field).Result()
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("get value failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果值是 JSON,比较前反序列化
|
||||||
|
var storedObj, inputObj interface{}
|
||||||
|
if err := sonic.UnmarshalString(storedValue, &storedObj); err != nil {
|
||||||
|
return false, fmt.Errorf("unmarshal stored value failed: %v", err)
|
||||||
|
}
|
||||||
|
if err := sonic.UnmarshalString(value, &inputObj); err != nil {
|
||||||
|
return false, fmt.Errorf("unmarshal input value failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 比较两个对象(需要根据实际类型调整)
|
||||||
|
return fmt.Sprintf("%v", storedObj) == fmt.Sprintf("%v", inputObj), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelSet 从集合中删除元素
|
||||||
|
func (r *RedisHelper) DelSet(key string, value string) error {
|
||||||
|
_, err := r.client.SRem(r.ctx, key, value).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error del value from set %s: %v", key, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHelper) Sismember(key string, value string) (bool, error) {
|
||||||
|
result, err := r.client.SIsMember(r.ctx, key, value).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error Sismember value from set %s: %v", key, err)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort set start
|
||||||
|
// 批量添加
|
||||||
|
func (r *RedisHelper) BatchSortSet(key string, array []*redis.Z) error {
|
||||||
|
pipe := r.client.Pipeline()
|
||||||
|
for _, val := range array {
|
||||||
|
pipe.ZAdd(r.ctx, key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := pipe.Exec(r.ctx)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单一写入 sort set
|
||||||
|
func (e *RedisHelper) SignelAdd(key string, score float64, member string) error {
|
||||||
|
// 先删除具有相同 score 的所有成员
|
||||||
|
scoreStr := strconv.FormatFloat(score, 'g', -1, 64)
|
||||||
|
_, err := e.client.ZRemRangeByScore(e.ctx, key, scoreStr, scoreStr).Result()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("删除score失败,err:%s", err.Error())
|
||||||
|
}
|
||||||
|
_, err = e.client.ZAdd(e.ctx, key, &redis.Z{
|
||||||
|
Score: score,
|
||||||
|
Member: member,
|
||||||
|
}).Result()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入数据
|
||||||
|
func (e *RedisHelper) AddSortSet(key string, score float64, member string) error {
|
||||||
|
_, err := e.client.ZAdd(e.ctx, key, &redis.Z{
|
||||||
|
Score: score,
|
||||||
|
Member: member,
|
||||||
|
}).Result()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除指定元素
|
||||||
|
func (e *RedisHelper) DelSortSet(key, member string) error {
|
||||||
|
return e.client.ZRem(e.ctx, key, member).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveBeforeScore 移除 Sorted Set 中分数小于等于指定值的数据
|
||||||
|
// key: Sorted Set 的键
|
||||||
|
// score: 分数上限,所有小于等于此分数的元素将被移除
|
||||||
|
// 返回值: 移除的元素数量和可能的错误
|
||||||
|
func (e *RedisHelper) RemoveBeforeScore(key string, score float64) (int64, error) {
|
||||||
|
if key == "" {
|
||||||
|
return 0, errors.New("key 不能为空")
|
||||||
|
}
|
||||||
|
if math.IsNaN(score) || math.IsInf(score, 0) {
|
||||||
|
return 0, errors.New("score 必须是有效数字")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 ZRemRangeByScore 移除数据
|
||||||
|
count, err := e.client.ZRemRangeByScore(e.ctx, key, "-inf", strconv.FormatFloat(score, 'f', -1, 64)).Result()
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("移除 Sorted Set 数据失败, key: %s, score: %f, err: %v", key, score, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNextAfterScore 获取指定分数及之后的第一条数据(包含指定分数)
|
||||||
|
func (e *RedisHelper) GetNextAfterScore(key string, score float64) (string, error) {
|
||||||
|
// 使用 ZRangeByScore 获取大于等于 score 的第一条数据
|
||||||
|
zs, err := e.client.ZRangeByScoreWithScores(e.ctx, key, &redis.ZRangeBy{
|
||||||
|
Min: fmt.Sprintf("%f", score), // 包含指定分数
|
||||||
|
Max: "+inf", // 上限为正无穷
|
||||||
|
Offset: 0, // 从第 0 条开始
|
||||||
|
Count: 1, // 只取 1 条
|
||||||
|
}).Result()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("获取数据失败: %v", err)
|
||||||
|
}
|
||||||
|
if len(zs) == 0 {
|
||||||
|
return "", nil // 没有符合条件的元素
|
||||||
|
}
|
||||||
|
return zs[0].Member.(string), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
获取sort set 所有数据
|
||||||
|
*/
|
||||||
|
func (e *RedisHelper) GetAllSortSet(key string) ([]string, error) {
|
||||||
|
return e.client.ZRange(e.ctx, key, 0, -1).Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
获取sort set 所有数据和score
|
||||||
|
*/
|
||||||
|
func (e *RedisHelper) GetRevRangeScoresSortSet(key string) ([]redis.Z, error) {
|
||||||
|
return e.client.ZRevRangeWithScores(e.ctx, key, 0, -1).Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取最后一条数据
|
||||||
|
func (e *RedisHelper) GetLastSortSet(key string) ([]redis.Z, error) {
|
||||||
|
// 获取最后一个元素及其分数
|
||||||
|
results, err := e.client.ZRevRangeWithScores(e.ctx, key, 0, 0).Result()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get last member: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有数据,返回空
|
||||||
|
if len(results) == 0 {
|
||||||
|
return []redis.Z{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取指定区间数据
|
||||||
|
func (e *RedisHelper) GetSortSetMembers(key string, start, stop int64) ([]string, error) {
|
||||||
|
return e.client.ZRange(e.ctx, key, start, stop).Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取最后N条数据
|
||||||
|
func (e *RedisHelper) GetLastSortSetMembers(key string, num int64) ([]string, error) {
|
||||||
|
return e.client.ZRevRange(e.ctx, key, 0, num).Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (e *RedisHelper) DelSortSet(key,)
|
||||||
|
|
||||||
|
// 根据索引范围删除
|
||||||
|
func (e *RedisHelper) DelByRank(key string, start, stop int64) error {
|
||||||
|
return e.client.ZRemRangeByRank(e.ctx, key, start, stop).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort set end
|
||||||
|
|
||||||
|
// GetUserLoginPwdErrFre 获取用户登录密码错误频次
|
||||||
|
func (e *RedisHelper) GetUserLoginPwdErrFre(key string) (total int, wait time.Duration, err error) {
|
||||||
|
total, _ = e.client.Get(e.ctx, key).Int()
|
||||||
|
wait = e.client.TTL(e.ctx, key).Val()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUserLoginPwdErrFre 设置用户登录密码错误频次
|
||||||
|
func (e *RedisHelper) SetUserLoginPwdErrFre(key string, expire time.Duration) (val int64, err error) {
|
||||||
|
val, err = e.client.Incr(e.ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = e.client.Expire(e.ctx, key, expire).Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user