1
This commit is contained in:
@ -70,6 +70,60 @@ func (e LineSymbol) GetPage(c *gin.Context) {
|
|||||||
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export 导出交易对列表
|
||||||
|
// @Summary 导出交易对列表
|
||||||
|
// @Description 导出交易对列表
|
||||||
|
// @Tags 交易对列表
|
||||||
|
// @Param type query string false "类型:1=现货,2=合约"
|
||||||
|
// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
|
||||||
|
// @Router /api/v1/line-symbol-group/export [get]
|
||||||
|
func (e LineSymbol) Export(c *gin.Context) {
|
||||||
|
req := dto.LineSymbolGetPageReq{}
|
||||||
|
s := service.LineSymbol{}
|
||||||
|
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)
|
||||||
|
err = s.ExportExcel(c, p, &req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, fmt.Sprintf("导出交易对列表失败,\r\n失败信息 %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAll 获取所有交易对名
|
||||||
|
func (e LineSymbol) GetAll(c *gin.Context) {
|
||||||
|
req := dto.LineSymbolGetListReq{}
|
||||||
|
s := service.LineSymbol{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
datas, err := s.GetAll(&req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.OK(datas, "查询成功")
|
||||||
|
}
|
||||||
|
|
||||||
// Get 获取交易对管理
|
// Get 获取交易对管理
|
||||||
// @Summary 获取交易对管理
|
// @Summary 获取交易对管理
|
||||||
// @Description 获取交易对管理
|
// @Description 获取交易对管理
|
||||||
|
|||||||
@ -39,6 +39,7 @@ func registerLinePreOrderRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTM
|
|||||||
r.POST("aiCoinPrice", actions.PermissionAction(), api.QueryAiCoinPrice) //获取aiCoin买入点
|
r.POST("aiCoinPrice", actions.PermissionAction(), api.QueryAiCoinPrice) //获取aiCoin买入点
|
||||||
|
|
||||||
r.POST("/calculate", api.CalculateBreakEevenRatio) //计算亏损后止盈百分比
|
r.POST("/calculate", api.CalculateBreakEevenRatio) //计算亏损后止盈百分比
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,5 +28,8 @@ func registerLineSymbolRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMid
|
|||||||
r.POST("syncSpotSymbol", api.SyncSpotSymbol) //同步现货交易对
|
r.POST("syncSpotSymbol", api.SyncSpotSymbol) //同步现货交易对
|
||||||
r.POST("syncFutSymbol", api.SyncFutSymbol) //同步合约交易对
|
r.POST("syncFutSymbol", api.SyncFutSymbol) //同步合约交易对
|
||||||
r.POST("getSymbol", api.GetSymbol) //获取现货和合约都有的交易对
|
r.POST("getSymbol", api.GetSymbol) //获取现货和合约都有的交易对
|
||||||
|
r.GET("/export", api.Export) //导出交易对
|
||||||
|
|
||||||
|
r.GET("/all", api.GetAll) //获取所有交易对
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,8 @@ import (
|
|||||||
|
|
||||||
type LinePreOrderGetPageReq struct {
|
type LinePreOrderGetPageReq struct {
|
||||||
dto.Pagination `search:"-"`
|
dto.Pagination `search:"-"`
|
||||||
ExchangeType string `json:"exchangeType" search:"type:exact;column:exchange_type;table:line_pre_order" comment:"交易所类型 字典exchange_type"`
|
ExchangeType string `json:"exchangeType" form:"exchangeType" search:"type:exact;column:exchange_type;table:line_pre_order" comment:"交易所类型 字典exchange_type"`
|
||||||
|
SymbolType int `json:"symbolType" form:"symbolType" search:"type:exact;column:symbol_type;table:line_pre_order"`
|
||||||
ApiId string `form:"apiId" search:"type:exact;column:api_id;table:line_pre_order" comment:"api用户"`
|
ApiId string `form:"apiId" search:"type:exact;column:api_id;table:line_pre_order" comment:"api用户"`
|
||||||
Symbol string `form:"symbol" search:"type:exact;column:symbol;table:line_pre_order" comment:"交易对"`
|
Symbol string `form:"symbol" search:"type:exact;column:symbol;table:line_pre_order" comment:"交易对"`
|
||||||
QuoteSymbol string `form:"quoteSymbol" search:"type:exact;column:quote_symbol;table:line_pre_order" comment:"计较货币"`
|
QuoteSymbol string `form:"quoteSymbol" search:"type:exact;column:quote_symbol;table:line_pre_order" comment:"计较货币"`
|
||||||
|
|||||||
@ -17,6 +17,13 @@ type LineSymbolGetPageReq struct {
|
|||||||
LineSymbolOrder
|
LineSymbolOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LineSymbolExportResp struct {
|
||||||
|
Symbol string `json:"symbol" excel:"交易对"`
|
||||||
|
Coin string `json:"coin" excel:"基础货币"`
|
||||||
|
Currency string `json:"currency" excel:"计价货币"`
|
||||||
|
SymbolType string `json:"symbolType" excel:"交易对类型"`
|
||||||
|
}
|
||||||
|
|
||||||
type LineSymbolOrder struct {
|
type LineSymbolOrder struct {
|
||||||
Id string `form:"idOrder" search:"type:order;column:id;table:line_symbol"`
|
Id string `form:"idOrder" search:"type:order;column:id;table:line_symbol"`
|
||||||
ApiId string `form:"apiIdOrder" search:"type:order;column:api_id;table:line_symbol"`
|
ApiId string `form:"apiIdOrder" search:"type:order;column:api_id;table:line_symbol"`
|
||||||
@ -34,6 +41,7 @@ type LineSymbolOrder struct {
|
|||||||
|
|
||||||
type LineSymbolGetListReq struct {
|
type LineSymbolGetListReq struct {
|
||||||
ExchangeType string `json:"exchangeType" form:"exchangeType"`
|
ExchangeType string `json:"exchangeType" form:"exchangeType"`
|
||||||
|
Type string `json:"type" form:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (req *LineSymbolGetListReq) Valid() error {
|
func (req *LineSymbolGetListReq) Valid() error {
|
||||||
|
|||||||
@ -4,6 +4,7 @@ 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"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LineSymbolGroupGetPageReq struct {
|
type LineSymbolGroupGetPageReq struct {
|
||||||
@ -46,8 +47,11 @@ func (s *LineSymbolGroupInsertReq) Generate(model *models.LineSymbolGroup) {
|
|||||||
model.Model = common.Model{Id: s.Id}
|
model.Model = common.Model{Id: s.Id}
|
||||||
}
|
}
|
||||||
// model.ExchangeType = s.ExchangeType
|
// model.ExchangeType = s.ExchangeType
|
||||||
|
model.ExchangeType = s.ExchangeType
|
||||||
model.GroupName = s.GroupName
|
model.GroupName = s.GroupName
|
||||||
model.Symbol = s.Symbol
|
model.Symbol = strings.ReplaceAll(strings.ReplaceAll(s.Symbol, ",", ","), " ", "")
|
||||||
|
model.Symbol = strings.ReplaceAll(model.Symbol, "\r\n", ",")
|
||||||
|
model.Symbol = strings.ReplaceAll(model.Symbol, "\n", ",")
|
||||||
model.GroupType = s.GroupType
|
model.GroupType = s.GroupType
|
||||||
model.Type = s.Type
|
model.Type = s.Type
|
||||||
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
||||||
@ -73,8 +77,11 @@ func (s *LineSymbolGroupUpdateReq) Generate(model *models.LineSymbolGroup) {
|
|||||||
}
|
}
|
||||||
// model.ExchangeType = s.ExchangeType
|
// model.ExchangeType = s.ExchangeType
|
||||||
model.GroupName = s.GroupName
|
model.GroupName = s.GroupName
|
||||||
model.Symbol = s.Symbol
|
model.Symbol = strings.ReplaceAll(strings.ReplaceAll(s.Symbol, ",", ","), " ", "")
|
||||||
|
model.Symbol = strings.ReplaceAll(model.Symbol, "\r\n", ",")
|
||||||
|
model.Symbol = strings.ReplaceAll(model.Symbol, "\n", ",")
|
||||||
model.GroupType = s.GroupType
|
model.GroupType = s.GroupType
|
||||||
|
model.ExchangeType = s.ExchangeType
|
||||||
model.Type = s.Type
|
model.Type = s.Type
|
||||||
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
||||||
}
|
}
|
||||||
|
|||||||
@ -509,18 +509,14 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
|||||||
//加仓、减仓状态
|
//加仓、减仓状态
|
||||||
tx.Model(&models.LinePreOrderStatus{}).Create(&preOrderStatus)
|
tx.Model(&models.LinePreOrderStatus{}).Create(&preOrderStatus)
|
||||||
|
|
||||||
for index := range preOrderExts {
|
// for index := range preOrderExts {
|
||||||
if index == 0 {
|
// if index == 0 {
|
||||||
preOrderExts[index].OrderId = AddOrder.Id
|
// preOrderExts[index].OrderId = AddOrder.Id
|
||||||
}
|
// }
|
||||||
|
|
||||||
preOrderExts[index].MainOrderId = AddOrder.Id
|
// preOrderExts[index].MainOrderId = AddOrder.Id
|
||||||
}
|
// }
|
||||||
|
|
||||||
err = tx.Model(&models.LinePreOrderExt{}).Create(&preOrderExts).Error
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
list := dto.PreOrderRedisList{
|
list := dto.PreOrderRedisList{
|
||||||
Id: AddOrder.Id,
|
Id: AddOrder.Id,
|
||||||
Symbol: AddOrder.Symbol,
|
Symbol: AddOrder.Symbol,
|
||||||
@ -605,12 +601,12 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
preOrderExts[index].OrderId = addPosition.Id
|
|
||||||
if err := e.Orm.Create(&addPosition).Error; err != nil {
|
if err := e.Orm.Create(&addPosition).Error; err != nil {
|
||||||
logger.Error("保存加仓单失败")
|
logger.Error("保存加仓单失败")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preOrderExts[index].OrderId = addPosition.Id
|
||||||
//止盈、减仓
|
//止盈、减仓
|
||||||
orders, err := makeFuturesTakeAndReduce(&addPosition, v, tradeSet)
|
orders, err := makeFuturesTakeAndReduce(&addPosition, v, tradeSet)
|
||||||
|
|
||||||
@ -645,6 +641,11 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = tx.Model(&models.LinePreOrderExt{}).Create(&preOrderExts).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-admin-team/go-admin-core/logger"
|
"github.com/go-admin-team/go-admin-core/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"
|
"github.com/shopspring/decimal"
|
||||||
@ -115,6 +116,66 @@ func (e *LineSymbol) GetSamePage(c *dto.LineSymbolGetPageReq, p *actions.DataPer
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 导出excel
|
||||||
|
func (e *LineSymbol) ExportExcel(c *gin.Context, p *actions.DataPermission, req *dto.LineSymbolGetPageReq) error {
|
||||||
|
list := make([]models.LineSymbol, 0)
|
||||||
|
datas := make([]dto.LineSymbolExportResp, 0)
|
||||||
|
var data models.LineSymbol
|
||||||
|
var fileName string
|
||||||
|
|
||||||
|
err := e.Orm.Model(&data).
|
||||||
|
Scopes(
|
||||||
|
cDto.MakeCondition(req.GetNeedSearch()),
|
||||||
|
actions.Permission(data.TableName(), p),
|
||||||
|
).
|
||||||
|
Find(&list).Error
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range list {
|
||||||
|
item := dto.LineSymbolExportResp{
|
||||||
|
Symbol: v.Symbol,
|
||||||
|
Coin: v.BaseAsset,
|
||||||
|
Currency: v.QuoteAsset,
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Type == "1" {
|
||||||
|
item.SymbolType = "现货"
|
||||||
|
} else {
|
||||||
|
item.SymbolType = "合约"
|
||||||
|
}
|
||||||
|
|
||||||
|
datas = append(datas, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(datas) == 0 {
|
||||||
|
return errors.New("无数据")
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Type == "1" {
|
||||||
|
fileName = "现货交易对"
|
||||||
|
} else {
|
||||||
|
fileName = "合约交易对"
|
||||||
|
}
|
||||||
|
|
||||||
|
err = helper.ExportExcel(c, fileName, datas, []string{})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有交易对
|
||||||
|
func (e *LineSymbol) GetAll(req *dto.LineSymbolGetListReq) ([]string, error) {
|
||||||
|
result := make([]string, 0)
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&models.LineSymbol{}).Where("type = ? AND exchange_type =?", req.Type, req.ExchangeType).Pluck("symbol", &result).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Get 获取LineSymbol对象
|
// Get 获取LineSymbol对象
|
||||||
func (e *LineSymbol) Get(d *dto.LineSymbolGetReq, p *actions.DataPermission, model *models.LineSymbol) error {
|
func (e *LineSymbol) Get(d *dto.LineSymbolGetReq, p *actions.DataPermission, model *models.LineSymbol) error {
|
||||||
var data models.LineSymbol
|
var data models.LineSymbol
|
||||||
|
|||||||
@ -11,6 +11,7 @@ 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/pkg/utility"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LineSymbolGroup struct {
|
type LineSymbolGroup struct {
|
||||||
@ -73,6 +74,14 @@ func (e *LineSymbolGroup) Insert(c *dto.LineSymbolGroupInsertReq) error {
|
|||||||
var err error
|
var err error
|
||||||
var data models.LineSymbolGroup
|
var data models.LineSymbolGroup
|
||||||
c.Generate(&data)
|
c.Generate(&data)
|
||||||
|
|
||||||
|
symbols := availableSymbols(data.Symbol, c.Type, e)
|
||||||
|
|
||||||
|
if len(symbols) == 0 {
|
||||||
|
return errors.New("全部交易对不可用")
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Symbol = strings.Join(symbols, ",")
|
||||||
err = e.Orm.Create(&data).Error
|
err = e.Orm.Create(&data).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Log.Errorf("LineSymbolGroupService Insert error:%s \r\n", err)
|
e.Log.Errorf("LineSymbolGroupService Insert error:%s \r\n", err)
|
||||||
@ -81,6 +90,25 @@ func (e *LineSymbolGroup) Insert(c *dto.LineSymbolGroupInsertReq) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 可用交易对
|
||||||
|
func availableSymbols(symbols, symbolType string, e *LineSymbolGroup) []string {
|
||||||
|
blacks := make([]string, 0)
|
||||||
|
newSymbols := make([]string, 0)
|
||||||
|
reqSymbols := strings.Split(symbols, ",")
|
||||||
|
e.Orm.Model(&models.LineSymbolBlack{}).Where("type=?", symbolType).Select("symbol").Find(&blacks)
|
||||||
|
for _, v := range reqSymbols {
|
||||||
|
symbol := strings.ToUpper(v)
|
||||||
|
|
||||||
|
//黑名单跳过
|
||||||
|
if utility.ContainsStr(blacks, symbol) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newSymbols = append(newSymbols, symbol)
|
||||||
|
}
|
||||||
|
return newSymbols
|
||||||
|
}
|
||||||
|
|
||||||
// Update 修改LineSymbolGroup对象
|
// Update 修改LineSymbolGroup对象
|
||||||
func (e *LineSymbolGroup) Update(c *dto.LineSymbolGroupUpdateReq, p *actions.DataPermission) error {
|
func (e *LineSymbolGroup) Update(c *dto.LineSymbolGroupUpdateReq, p *actions.DataPermission) error {
|
||||||
var err error
|
var err error
|
||||||
@ -89,7 +117,13 @@ func (e *LineSymbolGroup) Update(c *dto.LineSymbolGroupUpdateReq, p *actions.Dat
|
|||||||
actions.Permission(data.TableName(), p),
|
actions.Permission(data.TableName(), p),
|
||||||
).First(&data, c.GetId())
|
).First(&data, c.GetId())
|
||||||
c.Generate(&data)
|
c.Generate(&data)
|
||||||
|
symbols := availableSymbols(data.Symbol, c.Type, e)
|
||||||
|
|
||||||
|
if len(symbols) == 0 {
|
||||||
|
return errors.New("全部交易对不可用")
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Symbol = strings.Join(symbols, ",")
|
||||||
db := e.Orm.Save(&data)
|
db := e.Orm.Save(&data)
|
||||||
if err = db.Error; err != nil {
|
if err = db.Error; err != nil {
|
||||||
e.Log.Errorf("LineSymbolGroupService Save error:%s \r\n", err)
|
e.Log.Errorf("LineSymbolGroupService Save error:%s \r\n", err)
|
||||||
|
|||||||
168
common/helper/excel_helper.go
Normal file
168
common/helper/excel_helper.go
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"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 != "" && !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
common/helper/extension_helper.go
Normal file
52
common/helper/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
|
||||||
|
}
|
||||||
8
go.mod
8
go.mod
@ -134,6 +134,7 @@ require (
|
|||||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||||
github.com/mojocn/base64Captcha v1.3.5 // indirect
|
github.com/mojocn/base64Captcha v1.3.5 // indirect
|
||||||
github.com/nsqio/go-nsq v1.1.0 // indirect
|
github.com/nsqio/go-nsq v1.1.0 // indirect
|
||||||
github.com/nyaruka/phonenumbers v1.0.55 // indirect
|
github.com/nyaruka/phonenumbers v1.0.55 // indirect
|
||||||
@ -143,6 +144,8 @@ require (
|
|||||||
github.com/prometheus/common v0.45.0 // indirect
|
github.com/prometheus/common v0.45.0 // indirect
|
||||||
github.com/prometheus/procfs v0.12.0 // indirect
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
github.com/redis/go-redis/v9 v9.3.0 // indirect
|
github.com/redis/go-redis/v9 v9.3.0 // indirect
|
||||||
|
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||||
|
github.com/richardlehane/msoleps v1.0.4 // 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
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||||
@ -161,10 +164,13 @@ require (
|
|||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
|
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d // indirect
|
||||||
|
github.com/xuri/excelize/v2 v2.9.0 // indirect
|
||||||
|
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||||
go.uber.org/multierr v1.10.0 // indirect
|
go.uber.org/multierr v1.10.0 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/image v0.13.0 // indirect
|
golang.org/x/image v0.18.0 // indirect
|
||||||
golang.org/x/mod v0.17.0 // indirect
|
golang.org/x/mod v0.17.0 // indirect
|
||||||
golang.org/x/sync v0.9.0 // indirect
|
golang.org/x/sync v0.9.0 // indirect
|
||||||
golang.org/x/sys v0.27.0 // indirect
|
golang.org/x/sys v0.27.0 // indirect
|
||||||
|
|||||||
Reference in New Issue
Block a user