From 8113868cc0bddd7d6696e68da3dc817e2d45eb21 Mon Sep 17 00:00:00 2001
From: hucan <951870319@qq.com>
Date: Sat, 17 May 2025 09:10:14 +0800
Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E8=B0=83=E6=95=B4gas=E8=B4=B9?=
 =?UTF-8?q?=E6=B5=AE=E5=8A=A8=E6=AF=94=E4=BE=8B=E4=B8=BA90%?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
 app/admin/apis/wm_transfer_item.go            |  22 +++-
 app/admin/apis/wm_wallet_info.go              |  46 ++++++++
 app/admin/models/wm_transfer.go               |   2 +
 app/admin/models/wm_wallet_info.go            |   1 +
 app/admin/router/wm_transfer_item.go          |   1 +
 app/admin/router/wm_wallet_info.go            |   3 +
 app/admin/service/dto/wm_token.go             |   1 +
 app/admin/service/dto/wm_transfer.go          |   8 ++
 app/admin/service/dto/wm_transfer_item.go     |   7 +-
 app/admin/service/dto/wm_wallet_info.go       |  16 ++-
 app/admin/service/wm_token.go                 |  11 +-
 app/admin/service/wm_transfer.go              |  25 ++++-
 app/admin/service/wm_transfer_item.go         | 104 ++++++++++++++++--
 app/admin/service/wm_wallet_info.go           |  73 +++++++++++-
 static/excel/钱包导入模板.xlsx                | Bin 0 -> 9216 bytes
 ...alanceof_helper.go => balanceof_helper.go} |  24 ++++
 .../balanceof_helper_test.go                  |  25 +++++
 utils/ethtransferhelper/transfer_helper.go    |   8 +-
 utils/excelhelper/excel_helper.go             |  43 ++++++++
 19 files changed, 397 insertions(+), 23 deletions(-)
 create mode 100644 static/excel/钱包导入模板.xlsx
 rename utils/ethbalanceofhelper/{baalanceof_helper.go => balanceof_helper.go} (74%)
 create mode 100644 utils/ethbalanceofhelper/balanceof_helper_test.go
diff --git a/app/admin/apis/wm_transfer_item.go b/app/admin/apis/wm_transfer_item.go
index e7c2d6c..7245157 100644
--- a/app/admin/apis/wm_transfer_item.go
+++ b/app/admin/apis/wm_transfer_item.go
@@ -43,7 +43,7 @@ func (e WmTransferItem) GetPage(c *gin.Context) {
 	}
 
 	p := actions.GetPermissionFromContext(c)
-	list := make([]models.WmTransferItem, 0)
+	list := make([]dto.WmTransferItemResp, 0)
 	var count int64
 
 	err = s.GetPage(&req, p, &list, &count)
@@ -262,3 +262,23 @@ func (e WmTransferItem) GetAutoTransferLogPage(c *gin.Context) {
 	}
 	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
 }
+
+// 清除自动转账
+func (e WmTransferItem) ClearAutoLog(c *gin.Context) {
+	s := service.WmTransferItem{}
+	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.ClearAutoLog()
+	if err != nil {
+		e.Error(500, err, fmt.Sprintf("清除自动转账日志失败,\r\n失败信息 %s", err.Error()))
+		return
+	}
+	e.OK(nil, "清除成功")
+}
diff --git a/app/admin/apis/wm_wallet_info.go b/app/admin/apis/wm_wallet_info.go
index 0ddafb2..fc1661b 100644
--- a/app/admin/apis/wm_wallet_info.go
+++ b/app/admin/apis/wm_wallet_info.go
@@ -174,3 +174,49 @@ func (e WmWalletInfo) ClearAll(c *gin.Context) {
 	}
 	e.OK(nil, "清空成功")
 }
+
+// 根据excel导入钱包信息
+func (e WmWalletInfo) ExcelImport(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
+	}
+
+	errs := s.ExcelImport(c)
+
+	e.OK(strings.Join(errs, "
"), "创建成功")
+}
+
+// UpdateRemark 更新备注信息
+func (e WmWalletInfo) UpdateRemark(c *gin.Context) {
+	s := service.WmWalletInfo{}
+	req := dto.WmWalletInfoBatchUpdateReq{}
+
+	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))
+
+	err = s.BatchUpdateRemark(&req)
+	if err != nil {
+		e.Error(500, err, fmt.Sprintf("更新备注信息失败,\r\n失败信息 %s", err.Error()))
+		return
+	}
+
+	e.OK(nil, "更新成功")
+}
diff --git a/app/admin/models/wm_transfer.go b/app/admin/models/wm_transfer.go
index c9bd0e7..9f7ca08 100644
--- a/app/admin/models/wm_transfer.go
+++ b/app/admin/models/wm_transfer.go
@@ -17,6 +17,8 @@ type WmTransfer struct {
 	Sucess       int    `json:"sucess" gorm:"-"`
 	Fail         int    `json:"fail" gorm:"-"`
 	Pending      int    `json:"pending" gorm:"-"`
+	NetworkName  string `json:"networkName" gorm:"-"`
+	TokenName    string `json:"tokenName" gorm:"-"`
 	models.ModelTime
 	models.ControlBy
 }
diff --git a/app/admin/models/wm_wallet_info.go b/app/admin/models/wm_wallet_info.go
index 5041a68..a18af14 100644
--- a/app/admin/models/wm_wallet_info.go
+++ b/app/admin/models/wm_wallet_info.go
@@ -12,6 +12,7 @@ type WmWalletInfo struct {
 	PrivateKey string          `json:"privateKey" gorm:"type:varchar(50);comment:钱包私钥"`
 	Address    string          `json:"address" gorm:"type:varchar(50);comment:钱包地址"`
 	UsdcAmount decimal.Decimal `json:"usdcAmount" gorm:"type:decimal(18,8);comment:USDC余额"`
+	Remark     string          `json:"remark" gorm:"type:varchar(255);comment:备注信息"`
 	models.ModelTime
 	models.ControlBy
 }
diff --git a/app/admin/router/wm_transfer_item.go b/app/admin/router/wm_transfer_item.go
index d6b837c..70b0035 100644
--- a/app/admin/router/wm_transfer_item.go
+++ b/app/admin/router/wm_transfer_item.go
@@ -24,6 +24,7 @@ func registerWmTransferItemRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJW
 		r.PUT("/:id", actions.PermissionAction(), api.Update)
 		r.DELETE("", api.Delete)
 
+		r.DELETE("/clear", api.ClearAutoLog)
 		r.GET("/export", actions.PermissionAction(), api.Export)
 		r.GET("/export-auto-log", actions.PermissionAction(), api.ExportAutoLog)
 		r.GET("/auto-log", actions.PermissionAction(), api.GetAutoTransferLogPage)
diff --git a/app/admin/router/wm_wallet_info.go b/app/admin/router/wm_wallet_info.go
index 949d073..5c2f2ab 100644
--- a/app/admin/router/wm_wallet_info.go
+++ b/app/admin/router/wm_wallet_info.go
@@ -24,5 +24,8 @@ func registerWmWalletInfoRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTM
 		// r.PUT("/:id", actions.PermissionAction(), api.Update)
 		r.DELETE("", api.Delete)
 		r.DELETE("clear", api.ClearAll)
+
+		r.POST("/excel-import", api.ExcelImport) //根据excel导入数据
+		r.PUT("/batch", api.UpdateRemark)        //批量更新备注
 	}
 }
diff --git a/app/admin/service/dto/wm_token.go b/app/admin/service/dto/wm_token.go
index 37f74f5..3af02e1 100644
--- a/app/admin/service/dto/wm_token.go
+++ b/app/admin/service/dto/wm_token.go
@@ -13,6 +13,7 @@ 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:"代币名称"`
+	TransType      int    `form:"transType"  search:"-" comment:"转账类型 1-百分比 2-实际金额"`
 	WmTokenOrder
 }
 
diff --git a/app/admin/service/dto/wm_transfer.go b/app/admin/service/dto/wm_transfer.go
index 8f4084e..65df912 100644
--- a/app/admin/service/dto/wm_transfer.go
+++ b/app/admin/service/dto/wm_transfer.go
@@ -2,9 +2,11 @@ package dto
 
 import (
 	"errors"
+	"fmt"
 	"go-admin/app/admin/models"
 	"go-admin/common/dto"
 	common "go-admin/common/models"
+	"go-admin/utils/ethtransferhelper"
 	"strings"
 
 	"github.com/shopspring/decimal"
@@ -105,6 +107,12 @@ func (s *WmTransferInsertReq) Valid() error {
 		}
 	}
 
+	for _, content := range contents {
+		if !ethtransferhelper.IsValidAddress(content) {
+			return fmt.Errorf("%s 地址格式错误", content)
+		}
+	}
+
 	return nil
 }
 
diff --git a/app/admin/service/dto/wm_transfer_item.go b/app/admin/service/dto/wm_transfer_item.go
index 27d0e25..1e1489f 100644
--- a/app/admin/service/dto/wm_transfer_item.go
+++ b/app/admin/service/dto/wm_transfer_item.go
@@ -17,7 +17,10 @@ type WmTransferItemGetPageReq struct {
 
 type WmTransferItemAutoLogPageReq struct {
 	dto.Pagination `search:"-"`
-	NetworkId      int `form:"networkId"  search:"type:exact;column:network_id;table:wm_transfer_item"`
+	NetworkId      int     `form:"networkId"  search:"type:exact;column:network_id;table:wm_transfer_item"`
+	StartAmount    float64 `form:"startAmount" search:"-"`
+	EndAmount      float64 `form:"endAmount" search:"-"`
+	Status         int     `form:"status" search:"-"`
 	WmTransferItemOrder
 }
 
@@ -146,6 +149,8 @@ type WmTransferItemExportReq struct {
 }
 
 type WmTransferItemExportData struct {
+	NetworkName  string          `json:"networkName" excel:"网络名称"`
+	TokenName    string          `json:"tokenName" excel:"代币名称"`
 	PrivateKey   string          `json:"privateKey" excel:"私钥"`
 	TokenAddress string          `json:"tokenAddress" excel:"代币地址"`
 	FromAddress  string          `json:"fromAddress" excel:"来源地址"`
diff --git a/app/admin/service/dto/wm_wallet_info.go b/app/admin/service/dto/wm_wallet_info.go
index ae21b21..450345a 100644
--- a/app/admin/service/dto/wm_wallet_info.go
+++ b/app/admin/service/dto/wm_wallet_info.go
@@ -10,7 +10,7 @@ import (
 
 type WmWalletInfoGetPageReq struct {
 	dto.Pagination `search:"-"`
-	PrivateKey     string `form:"privateKey"  search:"type:exact;column:private_key;table:wm_wallet_info" comment:"钱包私钥"`
+	PrivateKey     string `form:"privateKey"  search:"-" comment:"钱包私钥"`
 	WmWalletInfoOrder
 }
 
@@ -30,7 +30,8 @@ func (m *WmWalletInfoGetPageReq) GetNeedSearch() interface{} {
 }
 
 type WmWalletInfoBatchInsertReq struct {
-	Keys string `json:"keys"`
+	Keys   string `json:"keys"`
+	Remark string `json:"remark"`
 	common.ControlBy
 }
 
@@ -103,3 +104,14 @@ type WmWalletInfoDeleteReq struct {
 func (s *WmWalletInfoDeleteReq) GetId() interface{} {
 	return s.Ids
 }
+
+type WmWalletExcelImportReq struct {
+	PrivateKey string `json:"privateKey" excel:"钱包私钥"`
+	Remark     string `json:"remark" excel:"备注"`
+}
+
+type WmWalletInfoBatchUpdateReq struct {
+	Ids    []int  `json:"ids" form:"ids"`
+	Remark string `json:"remark" form:"remark"`
+	common.ControlBy
+}
diff --git a/app/admin/service/wm_token.go b/app/admin/service/wm_token.go
index 8973f8a..8950a13 100644
--- a/app/admin/service/wm_token.go
+++ b/app/admin/service/wm_token.go
@@ -25,13 +25,18 @@ type WmToken struct {
 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).
+	query := e.Orm.Model(&data).
 		Scopes(
 			cDto.MakeCondition(c.GetNeedSearch()),
 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
 			actions.Permission(data.TableName(), p),
-		).
+		)
+
+	if c.TransType > 0 {
+		query.Where("trans_type = ?", c.TransType)
+	}
+
+	err = query.
 		Find(list).Limit(-1).Offset(-1).
 		Count(count).Error
 	if err != nil {
diff --git a/app/admin/service/wm_transfer.go b/app/admin/service/wm_transfer.go
index 1001ae6..e403169 100644
--- a/app/admin/service/wm_transfer.go
+++ b/app/admin/service/wm_transfer.go
@@ -56,6 +56,10 @@ func (e *WmTransfer) GetPage(c *dto.WmTransferGetPageReq, p *actions.DataPermiss
 	}
 
 	itemData, _ := e.GetItemData(transferIds)
+	networkService := WmNetwork{Service: e.Service}
+	networks, _ := networkService.GetAll()
+	tokenService := WmToken{Service: e.Service}
+	tokens, _ := tokenService.GetAll()
 
 	for i := range *list {
 		var total int
@@ -74,6 +78,20 @@ func (e *WmTransfer) GetPage(c *dto.WmTransferGetPageReq, p *actions.DataPermiss
 			}
 		}
 
+		for _, network := range networks {
+			if network.Id == (*list)[i].NetworkId {
+				(*list)[i].NetworkName = network.NetworkName
+				break
+			}
+		}
+
+		for _, token := range tokens {
+			if token.NetworkId == (*list)[i].NetworkId && token.TokenAddress == (*list)[i].TokenAddress {
+				(*list)[i].TokenName = token.TokenName
+				break
+			}
+		}
+
 		(*list)[i].Total = total
 	}
 
@@ -196,6 +214,7 @@ func (e *WmTransfer) Insert(c *dto.WmTransferInsertReq) error {
 			caches[i].TransferId = data.Id
 			caches[i].IsAuto = 2
 			caches[i].TokenAddress = c.TokenAddress
+			caches[i].Decimals = token.Decimals
 		}
 
 		if err := tx.CreateInBatches(&caches, 100).Error; err != nil {
@@ -226,7 +245,7 @@ func (e *WmTransfer) getPrivateKeyAmount(privateKey, tokenAddress string, decima
 			return amount, errors.New("连接区块链失败")
 		}
 
-		amount, err = ethbalanceofhelper.GetERC20Balance(client, tokenAddress, accountAddress.String(), decimals)
+		amount, err = ethbalanceofhelper.GetBalance(client, tokenAddress, accountAddress.String(), decimals)
 
 		if err != nil {
 			return amount, errors.New("查询主账号余额失败")
@@ -372,11 +391,11 @@ func (e *WmTransfer) CheckHashStatus() error {
 // 清理数据
 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 {
+		if err1 := tx.Exec("delete from wm_transfer_item where is_auto = 2").Error; err1 != nil {
 			return err1
 		}
 
-		if err2 := tx.Exec("truncate table wm_transfer").Error; err2 != nil {
+		if err2 := tx.Exec("delete from wm_transfer ").Error; err2 != nil {
 			return err2
 		}
 
diff --git a/app/admin/service/wm_transfer_item.go b/app/admin/service/wm_transfer_item.go
index b79d512..d026037 100644
--- a/app/admin/service/wm_transfer_item.go
+++ b/app/admin/service/wm_transfer_item.go
@@ -21,9 +21,10 @@ type WmTransferItem struct {
 }
 
 // GetPage 获取WmTransferItem列表
-func (e *WmTransferItem) GetPage(c *dto.WmTransferItemGetPageReq, p *actions.DataPermission, list *[]models.WmTransferItem, count *int64) error {
+func (e *WmTransferItem) GetPage(c *dto.WmTransferItemGetPageReq, 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).
 		Scopes(
@@ -31,15 +32,48 @@ func (e *WmTransferItem) GetPage(c *dto.WmTransferItemGetPageReq, p *actions.Dat
 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
 			actions.Permission(data.TableName(), p),
 		).
-		Find(list).Limit(-1).Offset(-1).
+		Find(&datas).Limit(-1).Offset(-1).
 		Count(count).Error
 	if err != nil {
 		e.Log.Errorf("WmTransferItemService GetPage error:%s \r\n", err)
 		return err
 	}
 
-	for i := 0; i < len(*list); i++ {
-		(*list)[i].PrivateKey = stringhelper.DesensitizeWalletAddress(aeshelper.AesEcbDecrypt((*list)[i].PrivateKey))
+	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
@@ -50,9 +84,22 @@ func (e *WmTransferItem) GetAutoTransferLogPage(c *dto.WmTransferItemAutoLogPage
 	var err error
 	var data models.WmTransferItem
 	var datas []models.WmTransferItem
+	query := e.Orm.Model(&data).
+		Where("is_auto = 1")
 
-	err = e.Orm.Model(&data).
-		Where("is_auto = 1").
+	if c.StartAmount >= 0 {
+		query.Where("amount >=?", c.StartAmount)
+	}
+
+	if c.EndAmount > 0 {
+		query.Where("amount <=?", c.EndAmount)
+	}
+
+	if c.Status > 0 {
+		query.Where("status =?", c.Status)
+	}
+
+	err = query.
 		Scopes(
 			cDto.MakeCondition(c.GetNeedSearch()),
 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
@@ -111,8 +158,21 @@ func (e *WmTransferItem) ExportAutoLog(req *dto.WmTransferItemAutoLogPageReq, c
 	var err error
 	var data models.WmTransferItem
 	exportDatas := make([]dto.WmTransferItemResp, 0)
+	query := e.Orm.Model(&data)
 
-	err = e.Orm.Model(&data).
+	if req.StartAmount >= 0 {
+		query.Where("amount >=?", req.StartAmount)
+	}
+
+	if req.EndAmount > 0 {
+		query.Where("amount <=?", req.EndAmount)
+	}
+
+	if req.Status > 0 {
+		query.Where("status =?", req.Status)
+	}
+
+	err = query.
 		Where("is_auto = 1").
 		Scopes(
 			cDto.MakeCondition(req.GetNeedSearch()),
@@ -259,6 +319,11 @@ func (e *WmTransferItem) ExportExcel(req *dto.WmTransferItemExportReq, p *action
 		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.WmTransferItemExportData{
@@ -281,6 +346,21 @@ func (e *WmTransferItem) ExportExcel(req *dto.WmTransferItemExportReq, p *action
 		default:
 			exportData.Status = "默认"
 		}
+
+		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
+			}
+		}
+
 		exportDatas = append(exportDatas, exportData)
 	}
 
@@ -290,3 +370,13 @@ func (e *WmTransferItem) ExportExcel(req *dto.WmTransferItemExportReq, p *action
 
 	return excelhelper.ExportExcel(c, "转账明细", exportDatas, []string{})
 }
+
+// 批量删除自动转账日志
+func (e *WmTransferItem) ClearAutoLog() error {
+	if err := e.Orm.Where("is_auto=1").Unscoped().Delete(&models.WmTransferItem{}).Error; err != nil {
+		e.Log.Errorf("Service ClearAutoLog error:%s \r\n", err)
+		return err
+	}
+
+	return nil
+}
diff --git a/app/admin/service/wm_wallet_info.go b/app/admin/service/wm_wallet_info.go
index 746338d..495f9fa 100644
--- a/app/admin/service/wm_wallet_info.go
+++ b/app/admin/service/wm_wallet_info.go
@@ -4,6 +4,7 @@ import (
 	"errors"
 	"strings"
 
+	"github.com/gin-gonic/gin"
 	"github.com/go-admin-team/go-admin-core/sdk/service"
 	"github.com/shopspring/decimal"
 	"gorm.io/gorm"
@@ -16,6 +17,7 @@ import (
 	"go-admin/utils/aeshelper"
 	"go-admin/utils/ethbalanceofhelper"
 	"go-admin/utils/ethtransferhelper"
+	"go-admin/utils/excelhelper"
 	"go-admin/utils/stringhelper"
 )
 
@@ -27,8 +29,13 @@ type WmWalletInfo struct {
 func (e *WmWalletInfo) GetPage(c *dto.WmWalletInfoGetPageReq, p *actions.DataPermission, list *[]models.WmWalletInfo, count *int64) error {
 	var err error
 	var data models.WmWalletInfo
+	query := e.Orm.Model(&data)
+	if c.PrivateKey != "" {
+		key := aeshelper.AesEcbDecrypt(c.PrivateKey)
+		query.Where("private_key =?", key)
+	}
 
-	err = e.Orm.Model(&data).
+	err = query.
 		Scopes(
 			cDto.MakeCondition(c.GetNeedSearch()),
 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
@@ -174,7 +181,7 @@ func (e *WmWalletInfo) ScheduledTask() error {
 		}
 
 		for i := range datas {
-			amount, err := ethbalanceofhelper.GetERC20Balance(client, token.TokenAddress, datas[i].Address, token.Decimals)
+			amount, err := ethbalanceofhelper.GetBalance(client, token.TokenAddress, datas[i].Address, token.Decimals)
 
 			if err != nil {
 				e.Log.Errorf("GetERC20Balance error:%s", err)
@@ -245,3 +252,65 @@ func (e *WmWalletInfo) ClearAll() error {
 
 	return err
 }
+
+// 根据excel导入数据
+func (e *WmWalletInfo) ExcelImport(c *gin.Context) []string {
+	dataRows, headers, err := excelhelper.GetExcelContent(c)
+	errors := []string{}
+
+	if err != nil {
+		errors = append(errors, err.Error())
+		return errors
+	}
+
+	datas, err := excelhelper.MapExcelToStruct[dto.WmWalletExcelImportReq](dataRows, headers)
+
+	if err != nil {
+		errors = append(errors, err.Error())
+		return errors
+	}
+	// entitys := make([]models.WmWalletInfo, 0)
+	var count int64
+	for _, data := range datas {
+		privateKey := strings.ReplaceAll(data.PrivateKey, " ", "")
+		if privateKey == "" {
+			continue
+		}
+
+		_, address, _ := ethtransferhelper.GetAddressFromPrivateKey(privateKey)
+		entity := models.WmWalletInfo{
+			PrivateKey: aeshelper.AesEcbEncrypt(privateKey),
+			Address:    address.String(),
+			Remark:     data.Remark,
+		}
+
+		if err := e.Orm.Model(entity).Where("private_key =?", entity.PrivateKey).Count(&count).Error; err != nil {
+			e.Log.Errorf("db error:%s", err)
+		}
+		if count == 0 {
+			if err := e.Orm.Create(&entity).Error; err != nil {
+				e.Log.Errorf("db error:%s", err)
+				errors = append(errors, err.Error())
+			}
+		}
+		// entitys = append(entitys, entity)
+	}
+
+	// if len(entitys) > 0 {
+	// 	if err := e.Orm.CreateInBatches(entitys, 100).Error; err != nil {
+	// 		e.Log.Errorf("定时转账保存数据库失败 error:%s", err)
+	// 		return err
+	// 	}
+	// }
+
+	return errors
+}
+
+// 批量修改备注
+func (e *WmWalletInfo) BatchUpdateRemark(req *dto.WmWalletInfoBatchUpdateReq) error {
+	if err := e.Orm.Model(&models.WmWalletInfo{}).Where("id in ?", req.Ids).Update("remark", req.Remark).Error; err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/static/excel/钱包导入模板.xlsx b/static/excel/钱包导入模板.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..08f068d21a87ca7161baa30bc69e1bce35608a0b
GIT binary patch
literal 9216
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