diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..c9b0d72 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,18 @@ +package main + +func main() { + +} + +//分块获取数据 + +//获取关联表单数据 + +//组装数据 + +//将数据写入excel中 + +//更具切割参数,计算拆分文件序号 + +//并发读写数据的能力 +//控制内存使用、cpu使用 diff --git a/data/conn.go b/data/conn.go new file mode 100644 index 0000000..574568f --- /dev/null +++ b/data/conn.go @@ -0,0 +1,14 @@ +package data + +import ( + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +func Conn() *gorm.DB { + conn, err := gorm.Open(mysql.Open("root:root@tcp(192.168.6.74:3307)/new_sys?charset=utf8mb4&parseTime=True")) + if err != nil { + panic("数据库连接失败") + } + return conn +} diff --git a/data/order.go b/data/order.go new file mode 100644 index 0000000..8e1d8ba --- /dev/null +++ b/data/order.go @@ -0,0 +1,86 @@ +package data + +import ( + "context" + "gorm.io/gorm" + "time" +) + +type Reseller struct { + Id int64 `gorm:"primaryKey;column:id"` + Name string +} + +func (o Reseller) TableName() string { + return "reseller" +} + +type OrderItem struct { + OrderNumber string `gorm:"primaryKey;column:order_order_number"` + OursProductId int + OursProductTitle string +} + +func (o OrderItem) TableName() string { + return "order_item" +} + +type OrderRemark struct { + OrderNumber string `gorm:"primaryKey;column:order_number"` + Remark string +} + +func (o OrderRemark) TableName() string { + return "order_remark" +} + +type Order struct { + OrderNumber string `gorm:"primaryKey;column:order_number"` + ResellerId int64 + ResellerOrderNumber string + Amount float32 + Account string + Quantity int + Status int + PayStatus int + CreateTime int64 + FinishTime int64 + Item OrderItem `gorm:"foreignkey:order_order_number;references:order_number"` + Remark OrderRemark `gorm:"foreignkey:order_number;references:order_number"` + Reseller Reseller `gorm:"foreignkey:id;references:reseller_id"` +} + +func (o Order) TableName() string { + return "order" +} + +type OrderRepo struct { + db *gorm.DB +} + +func NewOrderRepo(db *gorm.DB) *OrderRepo { + return &OrderRepo{ + db: db, + } +} + +func (repo OrderRepo) List(ctx context.Context, begin, end time.Time, limit int, last string) ([]Order, error) { + var orders []Order + db := repo.db.WithContext(ctx).Debug(). + Preload("Reseller"). + Preload("Item"). + Preload("Remark"). + Where("create_time BETWEEN ? AND ?", begin.Unix(), end.Unix()) + if last != "" { + db.Where("order_number > ?", last) + } + result := db.Order("create_time,order_number"). + Limit(limit). + Find(&orders) + + if result.Error != nil { + return nil, result.Error + } + + return orders, nil +} diff --git a/data/order_test.go b/data/order_test.go new file mode 100644 index 0000000..151f92b --- /dev/null +++ b/data/order_test.go @@ -0,0 +1,21 @@ +package data + +import ( + "context" + "fmt" + "testing" + "time" +) + +func orderRepo() *OrderRepo { + db := Conn() + return NewOrderRepo(db) +} +func TestOrderRepo_List(t *testing.T) { + repo := orderRepo() + begin := time.Date(2022, 10, 1, 0, 0, 0, 0, time.Local) + end := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local) + orders, err := repo.List(context.Background(), begin, end, 10, "123") + fmt.Println(err) + fmt.Printf("%+v\n", orders) +} diff --git a/export/entity.go b/export/entity.go new file mode 100644 index 0000000..73614c8 --- /dev/null +++ b/export/entity.go @@ -0,0 +1,7 @@ +package export + +type Entity interface { + Title() []string + Size() int + Data() []interface{} +} diff --git a/export/excel.go b/export/excel.go new file mode 100644 index 0000000..c8ae787 --- /dev/null +++ b/export/excel.go @@ -0,0 +1,129 @@ +package export + +import ( + "errors" + "fmt" + "github.com/tealeg/xlsx/v3" + "os" +) + +const sheet_name = "sheet_1" + +type Export struct { + index int + count int //总数 + row int //当前执行的数据行 + limit int //导出限制 + path string + isNew bool + titles []string + file *xlsx.File + sheet *xlsx.Sheet +} + +func NewExport(path string, limit int) *Export { + return &Export{ + path: path, + limit: limit, + } +} + +func (e *Export) Title(titles []string) error { + if e.file == nil || e.sheet == nil { + return errors.New("没有执行open方法") + } + + if titles != nil { + e.titles = titles + } + + if e.titles != nil && e.isNew { + row := e.sheet.AddRow() + row.WriteSlice(e.titles, -1) + } + return nil +} + +func (e *Export) fileName() string { + return fmt.Sprintf(e.path, e.index) +} + +func (e *Export) slice() { + e.row++ + if e.row > e.limit { + e.row = 0 + e.reset() + } + +} + +func (e *Export) reset() { + e.Save() + e.index++ + e.Open() + e.Title(nil) + e.slice() +} + +func (e *Export) Export(data Entity) error { + if e.file == nil || e.sheet == nil { + return errors.New("没有执行open方法") + } + + e.count = data.Size() + for _, order := range data.Data() { + e.slice() + row := e.sheet.AddRow() + row.WriteStruct(order, -1) + } + return nil +} + +func (e *Export) Open() error { + path := e.fileName() + exist, err := e.isFielExist(path) + if err != nil { + return err + } + + if exist { + e.isNew = false + if e.file, err = xlsx.OpenFile(path); err != nil { + return err + } + } else { + e.isNew = true + e.file = xlsx.NewFile() + } + + var ok bool + e.sheet, ok = e.file.Sheet[sheet_name] + if !ok { + e.sheet, err = e.file.AddSheet(sheet_name) + if err != nil { + return err + } + } else { + //需要处理偏移数据 + e.row = e.sheet.MaxRow - 1 + } + + return nil +} + +func (e *Export) isFielExist(file string) (bool, error) { + _, err := os.Stat(file) + if err == nil { + return true, nil + } + + if os.IsNotExist(err) { + return false, nil + } + + return false, err +} + +func (e *Export) Save() error { + return e.file.Save(e.fileName()) +} diff --git a/export/excel_test.go b/export/excel_test.go new file mode 100644 index 0000000..91f74a0 --- /dev/null +++ b/export/excel_test.go @@ -0,0 +1,226 @@ +package export + +import ( + "fmt" + "lsxd_excel/data" + "os" + "testing" +) + +func TestExport_Export(t *testing.T) { + dir, _ := os.Getwd() + path := dir + "/aa_%d.xlsx" + e := NewExport(path, 4) + err := e.Open() + fmt.Println(err) + + data := NewOrder([]data.Order{ + { + OrderNumber: "123451", + Reseller: data.Reseller{ + Id: 23456, + Name: "分销商名称", + }, + ResellerOrderNumber: "123456448", + Amount: 12.22, + Account: "13512345678", + Quantity: 1, + Status: 1, + PayStatus: 1, + CreateTime: 1672744984, + FinishTime: 1672744984, + Item: data.OrderItem{ + OursProductId: 101, + OursProductTitle: "商品名称", + }, + Remark: data.OrderRemark{ + Remark: "备注信息", + }, + }, + { + OrderNumber: "123452", + Reseller: data.Reseller{ + Id: 23456, + Name: "分销商名称", + }, + ResellerOrderNumber: "123456448", + Amount: 12.22, + Account: "13512345678", + Quantity: 1, + Status: 1, + PayStatus: 1, + CreateTime: 1672744984, + FinishTime: 1672744984, + Item: data.OrderItem{ + OursProductId: 101, + OursProductTitle: "商品名称", + }, + Remark: data.OrderRemark{ + Remark: "备注信息", + }, + }, + { + OrderNumber: "123453", + Reseller: data.Reseller{ + Id: 23456, + Name: "分销商名称", + }, + ResellerOrderNumber: "123456448", + Amount: 12.22, + Account: "13512345678", + Quantity: 1, + Status: 1, + PayStatus: 1, + CreateTime: 1672744984, + FinishTime: 1672744984, + Item: data.OrderItem{ + OursProductId: 101, + OursProductTitle: "商品名称", + }, + Remark: data.OrderRemark{ + Remark: "备注信息", + }, + }, + { + OrderNumber: "123454", + Reseller: data.Reseller{ + Id: 23456, + Name: "分销商名称", + }, + ResellerOrderNumber: "123456448", + Amount: 12.22, + Account: "13512345678", + Quantity: 1, + Status: 1, + PayStatus: 1, + CreateTime: 1672744984, + FinishTime: 1672744984, + Item: data.OrderItem{ + OursProductId: 101, + OursProductTitle: "商品名称", + }, + Remark: data.OrderRemark{ + Remark: "备注信息", + }, + }, + { + OrderNumber: "123455", + Reseller: data.Reseller{ + Id: 23456, + Name: "分销商名称", + }, + ResellerOrderNumber: "123456448", + Amount: 12.22, + Account: "13512345678", + Quantity: 1, + Status: 1, + PayStatus: 1, + CreateTime: 1672744984, + FinishTime: 1672744984, + Item: data.OrderItem{ + OursProductId: 101, + OursProductTitle: "商品名称", + }, + Remark: data.OrderRemark{ + Remark: "备注信息", + }, + }, + { + OrderNumber: "123456", + Reseller: data.Reseller{ + Id: 23456, + Name: "分销商名称", + }, + ResellerOrderNumber: "123456448", + Amount: 12.22, + Account: "13512345678", + Quantity: 1, + Status: 1, + PayStatus: 1, + CreateTime: 1672744984, + FinishTime: 1672744984, + Item: data.OrderItem{ + OursProductId: 101, + OursProductTitle: "商品名称", + }, + Remark: data.OrderRemark{ + Remark: "备注信息", + }, + }, + { + OrderNumber: "123457", + Reseller: data.Reseller{ + Id: 23456, + Name: "分销商名称", + }, + ResellerOrderNumber: "123456448", + Amount: 12.22, + Account: "13512345678", + Quantity: 1, + Status: 1, + PayStatus: 1, + CreateTime: 1672744984, + FinishTime: 1672744984, + Item: data.OrderItem{ + OursProductId: 101, + OursProductTitle: "商品名称", + }, + Remark: data.OrderRemark{ + Remark: "备注信息", + }, + }, + { + OrderNumber: "123458", + Reseller: data.Reseller{ + Id: 23456, + Name: "分销商名称", + }, + ResellerOrderNumber: "123456448", + Amount: 12.22, + Account: "13512345678", + Quantity: 1, + Status: 1, + PayStatus: 1, + CreateTime: 1672744984, + FinishTime: 1672744984, + Item: data.OrderItem{ + OursProductId: 101, + OursProductTitle: "商品名称", + }, + Remark: data.OrderRemark{ + Remark: "备注信息", + }, + }, + { + OrderNumber: "123459", + Reseller: data.Reseller{ + Id: 23456, + Name: "分销商名称", + }, + ResellerOrderNumber: "123456448", + Amount: 12.22, + Account: "13512345678", + Quantity: 1, + Status: 1, + PayStatus: 1, + CreateTime: 1672744984, + FinishTime: 1672744984, + Item: data.OrderItem{ + OursProductId: 101, + OursProductTitle: "商品名称", + }, + Remark: data.OrderRemark{ + Remark: "备注信息", + }, + }, + }) + + err = e.Title(data.Title()) + fmt.Println(err) + + err = e.Export(data) + fmt.Println(err) + + err = e.Save() + fmt.Println(err) +} diff --git a/export/order.go b/export/order.go new file mode 100644 index 0000000..84603df --- /dev/null +++ b/export/order.go @@ -0,0 +1,83 @@ +package export + +import ( + "lsxd_excel/data" + "time" +) + +type Order struct { + OrderNumber string + ResellerId int64 + ResellerName string + ResellerOrderNumber string + Amount float32 + Account string + Quantity int + Status int + PayStatus int + OursProductId int + OursProductTitle string + Remark string + CreateTime string + FinishTime string +} + +func TransformOrder(order data.Order) *Order { + return &Order{ + OrderNumber: order.OrderNumber, + ResellerId: order.ResellerId, + ResellerName: order.Reseller.Name, + ResellerOrderNumber: order.ResellerOrderNumber, + Amount: order.Amount, + Account: order.Account, + Quantity: order.Quantity, + Status: order.Status, + PayStatus: order.PayStatus, + CreateTime: time.Unix(order.CreateTime, 0).Format("2006-01-02 15:04:05"), + FinishTime: time.Unix(order.FinishTime, 0).Format("2006-01-02 15:04:05"), + OursProductId: order.Item.OursProductId, + OursProductTitle: order.Item.OursProductTitle, + Remark: order.Remark.Remark, + } +} + +func NewOrder(data []data.Order) Orders { + o := make([]*Order, len(data)) + for i, v := range data { + o[i] = TransformOrder(v) + } + return o +} + +type Orders []*Order + +func (o Orders) Title() []string { + return []string{ + "订单号", + "分销商ID", + "分销商名称", + "分销商订单号", + "总价", + "充值账号", + "数量", + "状态", + "支付状态", + "商品编号", + "商品名称", + "备注", + "创建时间", + "完成时间", + } +} + +func (o Orders) Size() int { + return len(o) +} + +func (o Orders) Data() []interface{} { + d := make([]interface{}, o.Size()) + for i, v := range o { + d[i] = v + } + return d +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..00cd312 --- /dev/null +++ b/go.mod @@ -0,0 +1,22 @@ +module excel_export + +go 1.18 + +require ( + github.com/frankban/quicktest v1.11.2 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/google/btree v1.0.0 // indirect + github.com/google/go-cmp v0.5.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/kr/pretty v0.2.1 // indirect + github.com/kr/text v0.1.0 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/rogpeppe/fastuuid v1.2.0 // indirect + github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa // indirect + github.com/tealeg/xlsx/v3 v3.2.4 // direct + golang.org/x/text v0.3.3 // indirect + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect + gorm.io/driver/mysql v1.4.5 // direct + gorm.io/gorm v1.24.3 // direct +)