From fabed6916c378c0d0a8578235ad5c28989e28484 Mon Sep 17 00:00:00 2001 From: "Mr.Li" Date: Tue, 4 Apr 2023 19:04:45 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=AF=BC=E5=87=BA=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=EF=BC=8C=E4=BD=BF=E7=94=A8sql=E8=AF=AD=E5=8F=A5?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E5=BC=8F=E8=BF=9B=E8=A1=8C=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- biz/BaseExportBiz.go | 32 ----- biz/batch.go | 153 -------------------- biz/batch_test.go | 36 ----- biz/card.go | 90 ------------ biz/card_test.go | 35 ----- biz/common.go | 41 ------ biz/config/config.go | 96 +++++++++++++ biz/config/task_test.go | 35 +++++ biz/direct.go | 159 -------------------- biz/direct_test.go | 36 ----- biz/export/excel.go | 96 +++++++++++++ biz/export/excel_exporter.go | 34 +++++ biz/export/excel_exporter_test.go | 24 ++++ biz/export/excel_test.go | 31 ++++ biz/export/export.go | 19 +++ biz/export/file.go | 88 ++++++++++++ biz/export/file_test.go | 39 +++++ biz/export/mysql_data_fetcher.go | 22 +++ biz/order.go | 150 ------------------- biz/order_test.go | 35 ----- config/config.yaml | 224 +++++++++++++++++++++++++++++ export/batch.go | 57 -------- export/card.go | 43 ------ export/direct.go | 57 -------- export/entity.go | 7 - export/excel.go | 133 ----------------- export/excel_test.go | 231 ------------------------------ export/order.go | 83 ----------- go.mod | 14 +- 29 files changed, 718 insertions(+), 1382 deletions(-) delete mode 100644 biz/BaseExportBiz.go delete mode 100644 biz/batch.go delete mode 100644 biz/batch_test.go delete mode 100644 biz/card.go delete mode 100644 biz/card_test.go delete mode 100644 biz/common.go create mode 100644 biz/config/config.go create mode 100644 biz/config/task_test.go delete mode 100644 biz/direct.go delete mode 100644 biz/direct_test.go create mode 100644 biz/export/excel.go create mode 100644 biz/export/excel_exporter.go create mode 100644 biz/export/excel_exporter_test.go create mode 100644 biz/export/excel_test.go create mode 100644 biz/export/export.go create mode 100644 biz/export/file.go create mode 100644 biz/export/file_test.go create mode 100644 biz/export/mysql_data_fetcher.go delete mode 100644 biz/order.go delete mode 100644 biz/order_test.go create mode 100644 config/config.yaml delete mode 100644 export/batch.go delete mode 100644 export/card.go delete mode 100644 export/direct.go delete mode 100644 export/entity.go delete mode 100644 export/excel.go delete mode 100644 export/excel_test.go delete mode 100644 export/order.go diff --git a/biz/BaseExportBiz.go b/biz/BaseExportBiz.go deleted file mode 100644 index 536d090..0000000 --- a/biz/BaseExportBiz.go +++ /dev/null @@ -1,32 +0,0 @@ -package biz - -import ( - "fmt" - "time" -) - -type baseExportBiz struct { - fileSize int - opts *ExportOpts - fileName string -} - -func (e *baseExportBiz) FileSize() int { - return e.fileSize -} - -func (e *baseExportBiz) FileName() string { - return e.fileName -} - -func (e *baseExportBiz) FileNames() []string { - name := make([]string, e.fileSize+1) - for i := 0; i <= e.fileSize; i++ { - name[i] = fmt.Sprintf(e.fileName, i) - } - return name -} - -func (e *baseExportBiz) setFileArg(begin time.Time) { - e.fileName = getFielName(e.opts.Path, e.opts.Tag, begin) -} diff --git a/biz/batch.go b/biz/batch.go deleted file mode 100644 index ee3b4d5..0000000 --- a/biz/batch.go +++ /dev/null @@ -1,153 +0,0 @@ -package biz - -import ( - "context" - "excel_export/data" - "excel_export/export" - "fmt" - "time" -) - -func NewBatchBiz(repo *data.DirectRepo, historyRepo *data.HistoryDirectRepo, opts *ExportOpts) *BatchBiz { - biz := &BatchBiz{ - repo: repo, - historyRepo: historyRepo, - } - biz.opts = DefaultOpts - if opts != nil { - biz.opts = opts - } - biz.opts.Tag = "batch" - return biz -} - -type BatchBiz struct { - repo *data.DirectRepo - historyRepo *data.HistoryDirectRepo - baseExportBiz -} - -func (e *BatchBiz) Export(begin, end time.Time) error { - e.setFileArg(begin) - file := export.NewExport(e.fileName, e.opts.ExcelMaxRow) - - if err := file.Open(); err != nil { - return err - } - if err := file.Title(export.Batchs{}.Title()); err != nil { - return err - } - - //导出历史订单数据 - if err := e.exportHistoryData(file, begin, end); err != nil { - return err - } - - //导出最近7天数据 - if err := e.exportData(file, begin, end); err != nil { - return err - } - - e.fileSize = file.Index() - return nil -} - -func (e *BatchBiz) exportHistoryData(export *export.Export, begin, end time.Time) error { - var last string - for true { - //导出最近7天数据 - data, err := e.historyRepo.BatchList(context.Background(), begin, end, e.opts.QueryLimit, last) - if err != nil { - return fmt.Errorf("获取导出数据错误:%w", err) - } - - if err := export.Export(e.HistoryTransforms(data)); err != nil { - return err - } - if len(data) < e.opts.QueryLimit { - return nil - } - last = data[len(data)-1].SerialNumber - } - - return nil -} - -func (e *BatchBiz) exportData(export *export.Export, begin, end time.Time) error { - var last string - for true { - //导出最近7天数据 - data, err := e.repo.BatchList(context.Background(), begin, end, e.opts.QueryLimit, last) - if err != nil { - return fmt.Errorf("获取导出数据错误:%w", err) - } - - if err := export.Export(e.Transforms(data)); err != nil { - return err - } - if len(data) < e.opts.QueryLimit { - return nil - } - last = data[len(data)-1].SerialNumber - } - - return nil -} - -func (e BatchBiz) Transforms(data []data.Direct) export.Batchs { - result := make(export.Batchs, len(data)) - for i, val := range data { - result[i] = e.Transform(val) - } - return result -} - -func (e BatchBiz) Transform(data data.Direct) *export.Batch { - return &export.Batch{ - ResellerId: data.Batch.ResellerId, - ResellerName: data.Batch.Reseller.Name, - OursProductId: data.OursProductId, - OursProductTitle: data.OrderItem.OursProductTitle, - PlatformName: data.PlatformProduct.Platform.Name, - PlatformProductCode: data.PlatformProduct.Code, - PlatformProductName: data.PlatformProduct.Name, - Status: data.Status, - OrderOrderNumber: data.OrderOrderNumber, - SerialNumber: data.SerialNumber, - TerminalAccount: data.TerminalAccount, - TradePrice: data.TradePrice, - PlatformPrice: data.PlatformPrice, - CreateTime: data.CreateTime.Format("2006-01-02 15:04:05"), - ExecuteTime: data.ExecuteTime.Format("2006-01-02 15:04:05"), - Remark: data.Batch.Remark, - } -} - -func (e BatchBiz) HistoryTransforms(data []data.HistoryDirect) export.Batchs { - result := make(export.Batchs, len(data)) - for i, val := range data { - result[i] = e.HistoryTransform(val) - } - return result -} - -func (e BatchBiz) HistoryTransform(data data.HistoryDirect) *export.Batch { - return &export.Batch{ - ResellerId: data.Batch.ResellerId, - ResellerName: data.Batch.Reseller.Name, - OursProductId: data.OursProductId, - OursProductTitle: data.OrderItem.OursProductTitle, - PlatformName: data.PlatformProduct.Platform.Name, - PlatformProductCode: data.PlatformProduct.Code, - PlatformProductName: data.PlatformProduct.Name, - Status: data.Status, - OrderOrderNumber: data.OrderOrderNumber, - SerialNumber: data.SerialNumber, - TerminalAccount: data.TerminalAccount, - TradePrice: data.TradePrice, - PlatformPrice: data.PlatformPrice, - CreateTime: data.CreateTime.Format("2006-01-02 15:04:05"), - ExecuteTime: data.ExecuteTime.Format("2006-01-02 15:04:05"), - Remark: data.Batch.Remark, - } -} diff --git a/biz/batch_test.go b/biz/batch_test.go deleted file mode 100644 index 832b703..0000000 --- a/biz/batch_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package biz - -import ( - "excel_export/data" - "fmt" - "github.com/stretchr/testify/assert" - "os" - "testing" - "time" -) - -func batchBiz() *BatchBiz { - db := data.Conn() - repo := data.NewDirectRepo(db) - historyRepo := data.NewHistoryDirectRepo(db) - - return NewBatchBiz(repo, historyRepo, nil) -} - -func TestBatchBiz_Export(t *testing.T) { - biz := batchBiz() - begin := time.Date(2021, 10, 1, 0, 0, 0, 0, time.Local) - end := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local) - - err := biz.Export(begin, end) - assert.Nil(t, err) - - for i := 0; i <= biz.FileSize(); i++ { - fileName := fmt.Sprintf(biz.FileName(), i) - assert.FileExists(t, fileName) - - //清理文件 - os.Remove(fileName) - } - -} diff --git a/biz/card.go b/biz/card.go deleted file mode 100644 index 9eac35a..0000000 --- a/biz/card.go +++ /dev/null @@ -1,90 +0,0 @@ -package biz - -import ( - "context" - "excel_export/data" - "excel_export/export" - "fmt" - "time" -) - -func NewCardBiz(repo *data.CardRepo, opts *ExportOpts) *CardBiz { - biz := &CardBiz{ - repo: repo, - } - - if opts == nil { - opts = DefaultOpts - } - opts.Tag = "card" - biz.opts = opts - return biz -} - -type CardBiz struct { - repo *data.CardRepo - baseExportBiz -} - -func (e *CardBiz) Export(begin, end time.Time) error { - e.setFileArg(begin) - file := export.NewExport(e.fileName, e.opts.ExcelMaxRow) - - if err := file.Open(); err != nil { - return err - } - if err := file.Title(export.Cards{}.Title()); err != nil { - return err - } - - if err := e.exportData(file, begin, end); err != nil { - return err - } - - e.fileSize = file.Index() - return nil -} - -func (e *CardBiz) exportData(export *export.Export, begin, end time.Time) error { - var last string - for true { - //导出最近7天数据 - data, err := e.repo.List(context.Background(), begin, end, e.opts.QueryLimit, last) - if err != nil { - return fmt.Errorf("获取导出数据错误:%w", err) - } - - if err := export.Export(e.Transforms(data)); err != nil { - return err - } - if len(data) < e.opts.QueryLimit { - return nil - } - last = data[len(data)-1].OrderNumber - } - - return nil -} - -func (e CardBiz) Transforms(data []data.Card) export.Cards { - result := make(export.Cards, len(data)) - for i, val := range data { - result[i] = e.Transform(val) - } - return result -} - -func (e CardBiz) Transform(data data.Card) *export.Card { - return &export.Card{ - OrderNumber: data.OrderNumber, - ResellerOrderNumber: data.ResellerOrderNumber, - Amount: data.Amount, - Quantity: data.Quantity, - Status: data.Status, - ResellerId: data.ResellerId, - ResellerName: data.Reseller.Name, - OursProductId: data.OursProductId, - OursProductTitle: data.OurProduct.Name, - CreateTime: time.Unix(data.CreateTime, 0).Format("2006-01-02 15:04:05"), - } -} diff --git a/biz/card_test.go b/biz/card_test.go deleted file mode 100644 index 5d04e0b..0000000 --- a/biz/card_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package biz - -import ( - "excel_export/data" - "fmt" - "github.com/stretchr/testify/assert" - "os" - "testing" - "time" -) - -func cardBiz() *CardBiz { - db := data.Conn() - repo := data.NewCardRepo(db) - - return NewCardBiz(repo, nil) -} - -func TestCardBiz_Export(t *testing.T) { - biz := cardBiz() - begin := time.Date(2012, 10, 1, 0, 0, 0, 0, time.Local) - end := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local) - - err := biz.Export(begin, end) - assert.Nil(t, err) - - for i := 0; i <= biz.FileSize(); i++ { - fileName := fmt.Sprintf(biz.FileName(), i) - assert.FileExists(t, fileName) - - //清理文件 - os.Remove(fileName) - } - -} diff --git a/biz/common.go b/biz/common.go deleted file mode 100644 index a2a4c71..0000000 --- a/biz/common.go +++ /dev/null @@ -1,41 +0,0 @@ -package biz - -import ( - "fmt" - "os" - "time" -) - -const ( - QueryLImit = 10 - ExcelMaxRow = 10 -) - -func getFielName(path, filename string, time time.Time) string { - if path == "" { - path, _ = os.Getwd() - } - date := time.Format("20060102") - return fmt.Sprintf("%s/%s_%s_%%d.xlsx", path, filename, date) -} - -type ExportOpts struct { - QueryLimit int - ExcelMaxRow int - Path string - Tag string -} - -var DefaultOpts *ExportOpts = &ExportOpts{ - QueryLimit: QueryLImit, - ExcelMaxRow: ExcelMaxRow, - Tag: "export", -} - -func NewExportOpts(query, limit int, path string) *ExportOpts { - return &ExportOpts{ - QueryLimit: query, - ExcelMaxRow: limit, - Path: path, - } -} diff --git a/biz/config/config.go b/biz/config/config.go new file mode 100644 index 0000000..de84ea7 --- /dev/null +++ b/biz/config/config.go @@ -0,0 +1,96 @@ +package config + +import ( + "errors" + "fmt" + "regexp" + "strconv" + "strings" + "time" +) + +type ( + Config struct { + Systems []System + } + System struct { + Name string + Db string + Jobs []Job + } + + Job struct { + Name string + Tasks []Task + File string + } + + Task struct { + PK string + Sql string + Timestamp bool + Elt string + Order string + } +) + +func (c Config) GetSystem(system string) (System, error) { + for _, s := range c.Systems { + if s.Name == system { + return s, nil + } + } + return System{}, errors.New("没有找到相关配置:" + system) +} + +func (s System) GetJob(job string) (Job, error) { + for _, j := range s.Jobs { + if j.Name == job { + return j, nil + } + } + return Job{}, errors.New("没有找到相关配置:" + job) +} + +func (t Task) GetSql(params map[string]interface{}) string { + sql := t.Sql + + m := regexp.MustCompile("({[a-zA-Z0-9]+})") + if strings.Trim(t.Elt, " ") != "" { + wehre := m.ReplaceAllFunc([]byte(t.Elt), func(b []byte) []byte { + field := string(b[1 : len(b)-1]) + + if val, ok := params[field]; ok { + return []byte(t.getParam(val)) + } + return b + }) + + sql = sql + " where " + string(wehre) + } + + if strings.Trim(t.Order, " ") != "" { + sql = sql + " order by " + t.Order + } + + return sql +} + +func (t Task) getParam(parm interface{}) string { + switch p := parm.(type) { + case time.Time: + if t.Timestamp { + return strconv.FormatInt(p.Unix(), 10) + } else { + return p.Format("2006-01-02 15:04:05") + } + case string: + return p + case int: + return strconv.Itoa(p) + case int32: + return strconv.FormatInt(int64(p), 10) + default: + return fmt.Sprint(p) + } +} diff --git a/biz/config/task_test.go b/biz/config/task_test.go new file mode 100644 index 0000000..ab506cb --- /dev/null +++ b/biz/config/task_test.go @@ -0,0 +1,35 @@ +package config + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +func TestTask_GetSql(t *testing.T) { + task := Task{ + Sql: "select * from order", + Elt: "create_time between {begin} and {end} and o.order_number > {last}", + Timestamp: true, + Order: " ", + } + begin, _ := time.Parse("2006-01-02 15:04:05", "2023-01-01 00:00:00") + end := begin.Add(time.Hour * 24) + sql := task.GetSql(map[string]interface{}{"begin": begin, "end": end, "last": 0}) + + assert.Equal(t, fmt.Sprintf("select * from order where create_time between %d and %d and o.order_number > 0", begin.Unix(), end.Unix()), sql) +} + +func TestTask_GetSql_OrderBy(t *testing.T) { + task := Task{ + Sql: "select * from order", + Elt: "create_time between '{begin}' and '{end}'", + Timestamp: false, + Order: "create_time", + } + begin, _ := time.Parse("2006-01-02 15:04:05", "2023-01-01 00:00:00") + end := begin.Add(time.Hour * 24) + sql := task.GetSql(map[string]interface{}{"begin": begin, "end": end}) + assert.Equal(t, fmt.Sprintf("select * from order where create_time between '%s' and '%s' order by create_time", begin.Format("2006-01-02 15:04:05"), end.Format("2006-01-02 15:04:05")), sql) +} diff --git a/biz/direct.go b/biz/direct.go deleted file mode 100644 index aaad4a1..0000000 --- a/biz/direct.go +++ /dev/null @@ -1,159 +0,0 @@ -package biz - -import ( - "context" - "excel_export/data" - "excel_export/export" - "fmt" - "time" -) - -func NewDirectBiz(repo *data.DirectRepo, historyRepo *data.HistoryDirectRepo, opts *ExportOpts) *DirectBiz { - biz := &DirectBiz{ - repo: repo, - historyRepo: historyRepo, - } - if opts == nil { - opts = DefaultOpts - } - opts.Tag = "direct" - biz.opts = opts - return biz -} - -type DirectBiz struct { - repo *data.DirectRepo - historyRepo *data.HistoryDirectRepo - baseExportBiz -} - -func (e *DirectBiz) FileSize() int { - return e.fileSize -} - -func (e *DirectBiz) Export(begin, end time.Time) error { - e.setFileArg(begin) - file := export.NewExport(e.fileName, e.opts.ExcelMaxRow) - - if err := file.Open(); err != nil { - return err - } - if err := file.Title(export.Directs{}.Title()); err != nil { - return err - } - - //导出历史订单数据 - if err := e.exportHistoryData(file, begin, end); err != nil { - return err - } - - //导出最近7天数据 - if err := e.exportData(file, begin, end); err != nil { - return err - } - - e.fileSize = file.Index() - return nil -} - -func (e *DirectBiz) exportHistoryData(export *export.Export, begin, end time.Time) error { - var last string - for true { - //导出最近7天数据 - data, err := e.historyRepo.List(context.Background(), begin, end, e.opts.QueryLimit, last) - if err != nil { - return fmt.Errorf("获取导出数据错误:%w", err) - } - - if err := export.Export(e.HistoryTransforms(data)); err != nil { - return err - } - if len(data) < e.opts.QueryLimit { - return nil - } - last = data[len(data)-1].SerialNumber - } - - return nil -} - -func (e *DirectBiz) exportData(export *export.Export, begin, end time.Time) error { - var last string - for true { - //导出最近7天数据 - data, err := e.repo.List(context.Background(), begin, end, e.opts.QueryLimit, last) - if err != nil { - return fmt.Errorf("获取导出数据错误:%w", err) - } - - if err := export.Export(e.Transforms(data)); err != nil { - return err - } - if len(data) < e.opts.QueryLimit { - return nil - } - last = data[len(data)-1].SerialNumber - } - - return nil -} - -func (e DirectBiz) Transforms(data []data.Direct) export.Directs { - result := make(export.Directs, len(data)) - for i, val := range data { - result[i] = e.Transform(val) - } - return result -} - -func (e DirectBiz) Transform(data data.Direct) *export.Direct { - return &export.Direct{ - ResellerId: data.Order.ResellerId, - ResellerName: data.Order.Reseller.Name, - ResellerOrderNumber: data.Order.ResellerOrderNumber, - OursProductId: data.OursProductId, - OursProductTitle: data.OrderItem.OursProductTitle, - PlatformName: data.PlatformProduct.Platform.Name, - PlatformProductCode: data.PlatformProduct.Code, - PlatformProductName: data.PlatformProduct.Name, - Status: data.Status, - OrderOrderNumber: data.OrderOrderNumber, - SerialNumber: data.SerialNumber, - TerminalAccount: data.TerminalAccount, - TradePrice: data.TradePrice, - PlatformPrice: data.PlatformPrice, - CreateTime: data.CreateTime.Format("2006-01-02 15:04:05"), - ExecuteTime: data.ExecuteTime.Format("2006-01-02 15:04:05"), - Remark: data.Order.Remark.Remark, - } -} - -func (e DirectBiz) HistoryTransforms(data []data.HistoryDirect) export.Directs { - result := make(export.Directs, len(data)) - for i, val := range data { - result[i] = e.HistoryTransform(val) - } - return result -} - -func (e DirectBiz) HistoryTransform(data data.HistoryDirect) *export.Direct { - return &export.Direct{ - ResellerId: data.Order.ResellerId, - ResellerName: data.Order.Reseller.Name, - ResellerOrderNumber: data.Order.ResellerOrderNumber, - OursProductId: data.OursProductId, - OursProductTitle: data.OrderItem.OursProductTitle, - PlatformName: data.PlatformProduct.Platform.Name, - PlatformProductCode: data.PlatformProduct.Code, - PlatformProductName: data.PlatformProduct.Name, - Status: data.Status, - OrderOrderNumber: data.OrderOrderNumber, - SerialNumber: data.SerialNumber, - TerminalAccount: data.TerminalAccount, - TradePrice: data.TradePrice, - PlatformPrice: data.PlatformPrice, - CreateTime: data.CreateTime.Format("2006-01-02 15:04:05"), - ExecuteTime: data.ExecuteTime.Format("2006-01-02 15:04:05"), - Remark: data.Order.Remark.Remark, - } -} diff --git a/biz/direct_test.go b/biz/direct_test.go deleted file mode 100644 index 58a4ec0..0000000 --- a/biz/direct_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package biz - -import ( - "excel_export/data" - "fmt" - "github.com/stretchr/testify/assert" - "os" - "testing" - "time" -) - -func directBiz() *DirectBiz { - db := data.Conn() - repo := data.NewDirectRepo(db) - historyRepo := data.NewHistoryDirectRepo(db) - - return NewDirectBiz(repo, historyRepo, nil) -} - -func TestDirectBiz_Export(t *testing.T) { - biz := directBiz() - begin := time.Date(2022, 10, 1, 0, 0, 0, 0, time.Local) - end := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local) - - err := biz.Export(begin, end) - assert.Nil(t, err) - - for i := 0; i <= biz.FileSize(); i++ { - fileName := fmt.Sprintf(biz.FileName(), i) - assert.FileExists(t, fileName) - - //清理文件 - os.Remove(fileName) - } - -} diff --git a/biz/export/excel.go b/biz/export/excel.go new file mode 100644 index 0000000..c5b93c4 --- /dev/null +++ b/biz/export/excel.go @@ -0,0 +1,96 @@ +package export + +import ( + "errors" + "github.com/tealeg/xlsx/v3" +) + +const Sheet_Name = "sheet_1" + +type Excel struct { + f *File + count int //总数 + isNew bool + titles []string + file *xlsx.File + sheet *xlsx.Sheet +} + +func NewExcel(fileName string, limit int, param map[string]string) *Excel { + return &Excel{ + f: NewFile(fileName, limit, param), + } +} + +func (e *Excel) slice() { + if e.f.slice() { + e.reset() + } +} + +func (e *Excel) reset() { + e.save() + e.f.NextFile() + e.Open() + e.WriteTitle(nil) + e.slice() +} + +func (e *Excel) Open() error { + var err error + if e.f.IsFileExist() { + e.file, err = xlsx.OpenFile(e.f.FileName()) + if 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.f.SetRow(e.sheet.MaxRow - 1) + } + + return nil +} + +func (e *Excel) save() error { + return e.file.Save(e.f.FileName()) +} + +func (e *Excel) WriteTitle(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 { + e.Write(e.titles) + } + return nil +} + +func (e *Excel) Write(data interface{}) error { + if e.f.slice() { + e.reset() + } + row := e.sheet.AddRow() + row.WriteSlice(data, -1) + return nil +} + +func (e *Excel) Close() error { + return e.save() +} diff --git a/biz/export/excel_exporter.go b/biz/export/excel_exporter.go new file mode 100644 index 0000000..e500213 --- /dev/null +++ b/biz/export/excel_exporter.go @@ -0,0 +1,34 @@ +package export + +type ExcelExporter struct { + mFetcher DataFetcher + file FileAdapter +} + +func NewExcelExporter(fetcher DataFetcher, file FileAdapter) DataExporter { + return &ExcelExporter{ + mFetcher: fetcher, + file: file, + } +} + +func (ee *ExcelExporter) Fetcher(fetcher DataFetcher) { + ee.mFetcher = fetcher +} + +func (ee *ExcelExporter) File(file FileAdapter) { + ee.file = file +} + +func (ee *ExcelExporter) Export(sql string) error { + rows := ee.mFetcher.Fetch(sql) + //fmt.Printf("Excel Exporter.Excel, got %v rows\n", len(rows)) + ee.file.Open() + ee.file.WriteTitle([]string{"字段1", "字段2", "字段3", "字段4", "字段5"}) + for _, v := range rows { + // fmt.Printf(" 行号: %d 值: %s\n", i+1, v) + ee.file.Write(v) + } + ee.file.Close() + return nil +} diff --git a/biz/export/excel_exporter_test.go b/biz/export/excel_exporter_test.go new file mode 100644 index 0000000..7e57b28 --- /dev/null +++ b/biz/export/excel_exporter_test.go @@ -0,0 +1,24 @@ +package export + +import ( + "github.com/stretchr/testify/assert" + "os" + "testing" +) + +func TestExcelExporter_Export(t *testing.T) { + data := NewMysqlDataFetcher("aaa") + pwd, _ := os.Getwd() + file := NewExcel(pwd+"/aa-{begin}.xlsx", 5, map[string]string{"begin": "202301"}) + e := NewExcelExporter(data, file) + err := e.Export("aa") + assert.Nil(t, err) + + assert.FileExists(t, pwd+"/aa-202301_0.xlsx") + assert.FileExists(t, pwd+"/aa-202301_1.xlsx") + assert.NoFileExists(t, pwd+"/aa-202301_2.xlsx") + + _ = os.Remove(pwd + "/aa-202301_0.xlsx") + _ = os.Remove(pwd + "/aa-202301_1.xlsx") + +} diff --git a/biz/export/excel_test.go b/biz/export/excel_test.go new file mode 100644 index 0000000..1e0cad4 --- /dev/null +++ b/biz/export/excel_test.go @@ -0,0 +1,31 @@ +package export + +import ( + "github.com/stretchr/testify/assert" + "os" + "testing" +) + +func TestExcel_Write(t *testing.T) { + pwd, _ := os.Getwd() + e := NewExcel(pwd+"/aa-{begin}.xlsx", 5, map[string]string{"begin": "202301"}) + + e.Open() + + e.WriteTitle([]string{"姓名", "年龄"}) + data := make([]interface{}, 2) + data[0] = "张三" + for i := 0; i < 9; i++ { + data[1] = 10 + i + e.Write(data) + } + e.Close() + + assert.FileExists(t, pwd+"/aa-202301_0.xlsx") + assert.FileExists(t, pwd+"/aa-202301_1.xlsx") + assert.NoFileExists(t, pwd+"/aa-202301_2.xlsx") + + _ = os.Remove(pwd + "/aa-202301_0.xlsx") + _ = os.Remove(pwd + "/aa-202301_1.xlsx") + +} diff --git a/biz/export/export.go b/biz/export/export.go new file mode 100644 index 0000000..40dd197 --- /dev/null +++ b/biz/export/export.go @@ -0,0 +1,19 @@ +package export + +type ( + DataExporter interface { + Fetcher(fetcher DataFetcher) + File(file FileAdapter) + Export(sql string) error + } + DataFetcher interface { + Fetch(sql string) []interface{} + } + + FileAdapter interface { + Open() error + WriteTitle([]string) error + Write(interface{}) error + Close() error + } +) diff --git a/biz/export/file.go b/biz/export/file.go new file mode 100644 index 0000000..3056ae5 --- /dev/null +++ b/biz/export/file.go @@ -0,0 +1,88 @@ +package export + +import ( + "os" + "regexp" + "strconv" +) + +type FileOpts struct { + fileName string + limit int + row int +} + +func (f *FileOpts) slice() bool { + f.row++ + if f.row > f.limit+1 { // +1 排除标题行 + f.row = 0 + return true + } + return false +} + +type File struct { + FileOpts + + param map[string]string + index int +} + +func NewFile(name string, limit int, param map[string]string) *File { + return &File{ + FileOpts: FileOpts{ + fileName: name, + limit: limit, + }, + param: param, + } +} +func (f *File) SetIndex(index int) *File { + f.index = index + return f +} +func (f *File) SetRow(row int) *File { + f.row = row + return f +} + +func (f *File) NextFile() *File { + f.index++ + return f +} + +func (f *File) FileName() string { + m := regexp.MustCompile("({[a-zA-Z0-9]+})") + name := m.ReplaceAllFunc([]byte(f.fileName), func(b []byte) []byte { + field := string(b[1 : len(b)-1]) + + if val, ok := f.param[field]; ok { + return []byte(val) + } + return b + }) + + ex := regexp.MustCompile("(\\..*)") + name = ex.ReplaceAllFunc(name, func(b []byte) []byte { + i := []byte("_" + strconv.Itoa(f.index)) + ret := make([]byte, len(b)+len(i)) + copy(ret, i) + copy(ret[len(i):], b) + return ret + }) + + return string(name) +} + +func (f *File) IsFileExist() bool { + _, err := os.Stat(f.FileName()) + if err == nil { + return true + } + + if os.IsNotExist(err) { + return false + } + + return false +} diff --git a/biz/export/file_test.go b/biz/export/file_test.go new file mode 100644 index 0000000..210a7a7 --- /dev/null +++ b/biz/export/file_test.go @@ -0,0 +1,39 @@ +package export + +import ( + "github.com/stretchr/testify/assert" + "os" + "testing" +) + +func TestFile_FileName(t *testing.T) { + f := NewFile("/usr/file-{begin}-{end}.xlsx", 10, map[string]string{ + "begin": "20230404", + "end": "20230404", + }) + assert.Equal(t, "/usr/file-20230404-20230404_0.xlsx", f.FileName()) + + f.NextFile() + assert.Equal(t, "/usr/file-20230404-20230404_1.xlsx", f.FileName()) +} + +func TestFile_IsFileExist(t *testing.T) { + gwd, _ := os.Getwd() + + f := NewFile(gwd+"/file-{begin}-{end}.xlsx", 10, map[string]string{ + "begin": "20230404", + "end": "20230404", + }) + + assert.False(t, f.IsFileExist()) + + path := gwd + "/file-20230404-20230404_0.xlsx" + _, err := os.Create(path) + assert.Nil(t, err) + + assert.FileExists(t, path) + assert.True(t, f.IsFileExist()) + + err = os.Remove(path) + assert.Nil(t, err) +} diff --git a/biz/export/mysql_data_fetcher.go b/biz/export/mysql_data_fetcher.go new file mode 100644 index 0000000..3d7bf98 --- /dev/null +++ b/biz/export/mysql_data_fetcher.go @@ -0,0 +1,22 @@ +package export + +import ( + "math/rand" +) + +type MysqlDataFetcher struct { + Config string +} + +func (mf *MysqlDataFetcher) Fetch(sql string) []interface{} { + rows := make([]interface{}, 0, 6) + // 插入6个随机数组成的切片,模拟查询要返回的数据集 + rows = append(rows, rand.Perm(5), rand.Perm(5), rand.Perm(5), rand.Perm(5), rand.Perm(5), rand.Perm(5)) + return rows +} + +func NewMysqlDataFetcher(configStr string) DataFetcher { + return &MysqlDataFetcher{ + Config: configStr, + } +} diff --git a/biz/order.go b/biz/order.go deleted file mode 100644 index d06ad13..0000000 --- a/biz/order.go +++ /dev/null @@ -1,150 +0,0 @@ -package biz - -import ( - "context" - "excel_export/data" - "excel_export/export" - "fmt" - "time" -) - -func NewOrderBiz(repo *data.OrderRepo, historyRepo *data.HistoryOrderRepo, opts *ExportOpts) *OrderBiz { - biz := &OrderBiz{ - repo: repo, - historyRepo: historyRepo, - } - - biz.opts = DefaultOpts - if opts != nil { - biz.opts = opts - } - return biz -} - -type OrderBiz struct { - repo *data.OrderRepo - historyRepo *data.HistoryOrderRepo - baseExportBiz -} - -func (e *OrderBiz) Export(begin, end time.Time) error { - e.setFileArg(begin) - file := export.NewExport(e.fileName, e.opts.ExcelMaxRow) - - if err := file.Open(); err != nil { - return err - } - - if err := file.Title(export.Orders{}.Title()); err != nil { - return err - } - - //导出历史订单数据 - if err := e.exportHistoryData(file, begin, end); err != nil { - return err - } - - //导出最近7天数据 - if err := e.exportData(file, begin, end); err != nil { - return err - } - - e.fileSize = file.Index() - return nil -} - -func (e *OrderBiz) exportHistoryData(export *export.Export, begin, end time.Time) error { - var last string - for true { - //导出最近7天数据 - data, err := e.historyRepo.List(context.Background(), begin, end, e.opts.QueryLimit, last) - if err != nil { - return fmt.Errorf("获取导出数据错误:%w", err) - } - - if err := export.Export(e.HistoryTransforms(data)); err != nil { - return err - } - if len(data) < e.opts.QueryLimit { - return nil - } - last = data[len(data)-1].OrderNumber - } - - return nil -} - -func (e *OrderBiz) exportData(export *export.Export, begin, end time.Time) error { - var last string - for true { - //导出最近7天数据 - data, err := e.repo.List(context.Background(), begin, end, e.opts.QueryLimit, last) - if err != nil { - return fmt.Errorf("获取导出数据错误:%w", err) - } - - if err := export.Export(e.Transforms(data)); err != nil { - return err - } - if len(data) < e.opts.QueryLimit { - return nil - } - last = data[len(data)-1].OrderNumber - } - - return nil -} - -func (e OrderBiz) Transforms(data []data.Order) export.Orders { - result := make(export.Orders, len(data)) - for i, val := range data { - result[i] = e.Transform(val) - } - return result -} - -func (e OrderBiz) Transform(order data.Order) *export.Order { - return &export.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 (e OrderBiz) HistoryTransforms(data []data.HistoryOrder) export.Orders { - result := make(export.Orders, len(data)) - for i, val := range data { - result[i] = e.HistoryTransform(val) - } - return result -} - -func (e OrderBiz) HistoryTransform(order data.HistoryOrder) *export.Order { - return &export.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: order.CreateTime.Format("2006-01-02 15:04:05"), - FinishTime: order.FinishTime.Format("2006-01-02 15:04:05"), - OursProductId: order.Item.OursProductId, - OursProductTitle: order.Item.OursProductTitle, - Remark: order.Remark.Remark, - } -} diff --git a/biz/order_test.go b/biz/order_test.go deleted file mode 100644 index 33b437e..0000000 --- a/biz/order_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package biz - -import ( - "excel_export/data" - "fmt" - "github.com/stretchr/testify/assert" - "os" - "testing" - "time" -) - -func orderBiz() *OrderBiz { - db := data.Conn() - repo := data.NewOrderRepo(db) - historyRepo := data.NewHistoryOrderRepo(db) - - return NewOrderBiz(repo, historyRepo, nil) -} - -func TestOrderBiz_Export(t *testing.T) { - biz := orderBiz() - begin := time.Date(2022, 8, 1, 0, 0, 0, 0, time.UTC) - end := time.Date(2022, 8, 2, 10, 0, 0, 0, time.UTC) - - err := biz.Export(begin, end) - assert.Nil(t, err) - - for i := 0; i <= biz.FileSize(); i++ { - fileName := fmt.Sprintf(biz.FileName(), i) - assert.FileExists(t, fileName) - - //清理文件 - os.Remove(fileName) - } -} diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 0000000..5e8c693 --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,224 @@ +system: + - name: "直连天下" + db: "" + jobs: + - name: "卡密订单" + tasks: + - sql: >- + SELECT + order_number AS `订单号` , + reseller_order_number AS `分销商订单号`, + order_card.price AS `扣款价格`, + order_card.`quantity` as `数量`, + case order_card.`status` + WHEN 0 THEN '充值中' + WHEN 1 THEN '充值成功' + WHEN -2 THEN '充值失败' + ELSE order_card.`status` + END + AS 充值状态, + r.`name` AS `分销商名称` , + o.`name` AS `订单商品名称`, + FROM_UNIXTIME(order_card.`create_time`) AS `创建时间` + FROM + order_card + LEFT JOIN reseller r ON order_card.reseller_id = r.id + LEFT JOIN ours_product o ON o.id = order_card.ours_product_id + timestamp: true + elt: "order_card.create_time BETWEEN {begin} AND {end} and order_card.order_number > {last}" + order: "order_card.create_time,order_card.order_number" + file: "直连天下-卡密订单-${month}.xlsx" + - name: "上游订单" + tasks: + - sql: >- + SELECT + o.reseller_id as `分销商id`, + r.`name` as `分销商名称`, + o.reseller_order_number as `商户订单号`, + od.ours_product_id as `我们的商品id`, + oi.ours_product_title as `订单商品名称`, + oi.ours_product_title as `商品名称`, + p.name as `接口平台`, + CASE od.`status` + WHEN -10 THEN '取消充值(失败)' + WHEN -6 THEN '手动失败' + WHEN -5 THEN '手动重试' + WHEN -3 THEN '卡单' + WHEN -2 THEN '失败重试' + WHEN -1 THEN '充值失败' + WHEN 0 THEN '待充值' + WHEN 1 THEN '充值成功' + WHEN 2 THEN '充值中' + else od.`status` + END + AS 充值状态, + pp.`code` as `接口平台产品编码`, + pp.`name` as `接口平台产品名称`, + od.order_order_number as `系统订单号`, + od.serial_number as `流水号`, + od.terminal_account as `充值账号`, + od.trade_price as `成交价格`, + od.platform_price as `接口平台价格`, + od.create_time as `创建时间`, + od.execute_time as `执行时间`, + re.remark as `备注` + FROM + history_order_direct od + right join `history_order` o on o.order_number = od.order_order_number + left join history_order_item oi on o.order_number = oi.order_order_number + left join platform_product pp on pp.id = od.platform_product_id + left join platform p on pp.platform_id = p.id + left join reseller r on r.id = o.reseller_id + left join history_order_remark re on o.order_number = re.order_number + timestamp: false + elt: "od.create_time BETWEEN '{begin}' and '{end}' and od.serial_number > {last}" + order: "od.create_time,od.serial_number" + - sql: >- + SELECT + o.reseller_id as `分销商id`, + r.`name` as `分销商名称`, + o.reseller_order_number as `商户订单号`, + od.ours_product_id as `我们的商品id`, + oi.ours_product_title as `订单商品名称`, + op.NAME as `商品名称`, + p.name as `接口平台`, + CASE od.`status` + WHEN -10 THEN '取掉充值(失败)' + WHEN -6 THEN '手动失败' + WHEN -5 THEN '手动重试' + WHEN -3 THEN '卡单' + WHEN -2 THEN '失败重试' + WHEN -1 THEN '充值失败' + WHEN 0 THEN '待充值' + WHEN 1 THEN '充值成功' + WHEN 2 THEN '充值中' + else od.`status` + END + AS 充值状态, + pp.`code` as `接口平台产品编码`, + pp.`name` as `接口平台产品名称`, + od.order_order_number as `系统订单号`, + od.serial_number as `流水号`, + od.terminal_account as `充值账号`, + od.trade_price as `成交价格`, + od.platform_price as `接口平台价格`, + od.create_time as `创建时间`, + od.execute_time as `执行时间`, + re.remark as `备注` + + FROM + order_direct od + right join `order` o on o.order_number = od.order_order_number + left join order_item oi on o.order_number = oi.order_order_number + left JOIN ours_product op ON od.ours_product_id = op.id + left join platform_product pp on pp.id = od.platform_product_id + left join platform p on pp.platform_id = p.id + left join reseller r on r.id = o.reseller_id + left join order_remark re on o.order_number = re.order_number + timestamp: false + elt: "od.create_time BETWEEN '{begin}' and '{end}' and od.serial_number > {last}" + order: "od.create_time,od.serial_number" + file: "直连天下-上游订单-${month}.xlsx" + - name: "下游订单" + tasks: + - sql: >- + SELECT + o.order_number as `订单号`, + o.reseller_id as `分销商id`, + r.`name` as `分销商名称`, + o.reseller_order_number as `商户订单号`, + o.amount as `扣款金额`, + oi.ours_product_id as `我们的商品id`, + oi.ours_product_title as `订单商品名称`, + oi.ours_product_title as `商品名称`, + o.account as `充值账号`, + o.quantity as `数量`, + CASE o.`status` + + WHEN -2 THEN '全部失败' + WHEN -1 THEN '关闭订单' + WHEN 0 THEN '待充值' + WHEN 1 THEN '订单完成' + WHEN 2 THEN '部分成功' + END + AS 充值状态, + CASE o.pay_status + + WHEN -2 THEN '退款失败' + WHEN -1 THEN '支付失败' + WHEN 0 THEN '未支付' + WHEN 1 THEN '支付中' + WHEN 2 THEN '支付成功' + WHEN 3 THEN '退款中' + WHEN 4 THEN '全部退款' + WHEN 5 THEN '部分退款' + END + AS 支付状态, + o.create_time as `创建时间`, + o.finish_time as `完成时间`, + re.remark as `备注` + + FROM + `history_order` o + left join history_order_item oi on oi.order_order_number = o.order_number + left join reseller r on r.id = o.reseller_id + left join history_order_remark re on o.order_number = re.order_number + elt: "o.`create_time` >= '{begin}' and o.create_time < '{end}' and o.order_number > {last}" + timestamp: false + order: "o.create_time,o.order_number" + - sql: >- + SELECT + o.order_number as `订单号`, + o.reseller_id as `分销商id`, + r.`name` as `分销商名称`, + o.reseller_order_number as `商户订单号`, + o.amount as `扣款金额`, + op.id as `我们的商品id`, + oi.ours_product_title as `订单商品名称`, + op.NAME as `商品名称`, + o.account as `充值账号`, + o.quantity as `数量`, + CASE o.`status` + + WHEN -2 THEN '全部失败' + WHEN -1 THEN '关闭订单' + WHEN 0 THEN '待充值' + WHEN 1 THEN '订单完成' + WHEN 2 THEN '部分成功' + END + AS 充值状态, + CASE o.pay_status + + WHEN -2 THEN '退款失败' + WHEN -1 THEN '支付失败' + WHEN 0 THEN '未支付' + WHEN 1 THEN '支付中' + WHEN 2 THEN '支付成功' + WHEN 3 THEN '退款中' + WHEN 4 THEN '全部退款' + WHEN 5 THEN '部分退款' + END + AS 支付状态, + from_unixtime(o.create_time) as `创建时间`, + from_unixtime(o.finish_time) as `完成时间`, + re.remark as `备注` + + FROM + `order` o + left join order_item oi on oi.order_order_number = o.order_number + left JOIN ours_product op ON oi.ours_product_id = op.id + left join reseller r on r.id = o.reseller_id + left join order_remark re on o.order_number = re.order_number + elt: "o.`create_time` >= {begin} and o.create_time < {end} and o.order_number > {last}" + timestamp: true + order: "o.create_time,o.order_number" + file: "直连天下-下游订单-${month}.xlsx" + + - name: "营销系统" + db: "" + jobs: + - name: "订单信息" + tasks: + - sql: "" + elt: "" + file: "营销系统-订单信息-${month}.xlsx" \ No newline at end of file diff --git a/export/batch.go b/export/batch.go deleted file mode 100644 index 05759a1..0000000 --- a/export/batch.go +++ /dev/null @@ -1,57 +0,0 @@ -package export - -type Batch struct { - ResellerId int - ResellerName string - OursProductId int - OursProductTitle string - PlatformName string - PlatformProductCode string - PlatformProductName string - Status int - OrderOrderNumber string - SerialNumber string - TerminalAccount string - TradePrice float32 - PlatformPrice float32 - CreateTime string - ExecuteTime string - DingTalkSn string - Remark string -} - -type Batchs []*Batch - -func (o Batchs) Title() []string { - return []string{ - "分销商id", - "分销商名称", - "我们的商品id", - "订单商品名称", - "接口平台", - "接口平台产品编码", - "接口平台产品名称", - "充值状态", - "系统订单号", - "流水号", - "充值账号", - "成交价格", - "接口平台价格", - "创建时间", - "执行时间", - "钉钉审批序号", - "批量备注", - } -} - -func (o Batchs) Size() int { - return len(o) -} - -func (o Batchs) Data() []interface{} { - d := make([]interface{}, o.Size()) - for i, v := range o { - d[i] = v - } - return d -} diff --git a/export/card.go b/export/card.go deleted file mode 100644 index cce0e95..0000000 --- a/export/card.go +++ /dev/null @@ -1,43 +0,0 @@ -package export - -type Card struct { - OrderNumber string - ResellerOrderNumber string - Amount float32 - Quantity int - Status int - ResellerId int - ResellerName string - OursProductId int - OursProductTitle string - CreateTime string -} - -type Cards []*Card - -func (o Cards) Title() []string { - return []string{ - "订单号", - "分销商订单号", - "扣款价格", - "数量", - "充值状态", - "分销商编号", - "分销商名称", - "订单商品编号", - "订单商品名称", - "创建时间", - } -} - -func (o Cards) Size() int { - return len(o) -} - -func (o Cards) Data() []interface{} { - d := make([]interface{}, o.Size()) - for i, v := range o { - d[i] = v - } - return d -} diff --git a/export/direct.go b/export/direct.go deleted file mode 100644 index 4b3cf88..0000000 --- a/export/direct.go +++ /dev/null @@ -1,57 +0,0 @@ -package export - -type Direct struct { - ResellerId int64 - ResellerName string - ResellerOrderNumber string - OursProductId int - OursProductTitle string - PlatformName string - PlatformProductCode string - PlatformProductName string - Status int - OrderOrderNumber string - SerialNumber string - TerminalAccount string - TradePrice float32 - PlatformPrice float32 - CreateTime string - ExecuteTime string - Remark string -} - -type Directs []*Direct - -func (o Directs) Title() []string { - return []string{ - "分销商id", - "分销商名称", - "商户订单号", - "我们的商品id", - "订单商品名称", - "接口平台", - "接口平台产品编码", - "接口平台产品名称", - "充值状态", - "系统订单号", - "流水号", - "充值账号", - "成交价格", - "接口平台价格", - "创建时间", - "执行时间", - "备注", - } -} - -func (o Directs) Size() int { - return len(o) -} - -func (o Directs) Data() []interface{} { - d := make([]interface{}, o.Size()) - for i, v := range o { - d[i] = v - } - return d -} diff --git a/export/entity.go b/export/entity.go deleted file mode 100644 index 73614c8..0000000 --- a/export/entity.go +++ /dev/null @@ -1,7 +0,0 @@ -package export - -type Entity interface { - Title() []string - Size() int - Data() []interface{} -} diff --git a/export/excel.go b/export/excel.go deleted file mode 100644 index 507497f..0000000 --- a/export/excel.go +++ /dev/null @@ -1,133 +0,0 @@ -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) Index() int { - return e.index -} - -func (e *Export) Export(data Entity) error { - if e.file == nil || e.sheet == nil { - return errors.New("没有执行open方法") - } - - e.count = e.count + data.Size() - for _, order := range data.Data() { - e.slice() - row := e.sheet.AddRow() - row.WriteStruct(order, -1) - } - return e.save() -} - -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 deleted file mode 100644 index 182a27e..0000000 --- a/export/excel_test.go +++ /dev/null @@ -1,231 +0,0 @@ -package export - -import ( - "excel_export/data" - "fmt" - "github.com/stretchr/testify/assert" - "os" - "testing" -) - -func TestExport_Export(t *testing.T) { - dir, _ := os.Getwd() - path := dir + "/aa_%d.xlsx" - e := NewExport(path, 4) - err := e.Open() - assert.Nil(t, 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()) - assert.Nil(t, err) - - err = e.Export(data) - assert.Nil(t, err) - - for i := 0; i <= e.Index(); i++ { - file := fmt.Sprintf(path, i) - assert.FileExists(t, file) - os.Remove(file) - } - -} diff --git a/export/order.go b/export/order.go deleted file mode 100644 index f5e60ca..0000000 --- a/export/order.go +++ /dev/null @@ -1,83 +0,0 @@ -package export - -import ( - "excel_export/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 index a238f79..eda2e53 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,18 @@ module excel_export go 1.17 require ( + github.com/spf13/cobra v1.6.1 // direct github.com/tealeg/xlsx/v3 v3.2.4 // direct gorm.io/driver/mysql v1.4.5 // direct gorm.io/gorm v1.24.3 // direct - github.com/spf13/cobra v1.6.1 // direct ) -require github.com/stretchr/testify v1.8.1 +require ( + github.com/spf13/pflag v1.0.5 + github.com/stretchr/testify v1.8.1 +) + +require github.com/smartystreets/goconvey v1.7.2 require ( github.com/davecgh/go-spew v1.1.1 // indirect @@ -17,17 +22,18 @@ require ( 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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/jtolds/gls v4.20.0+incompatible // 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/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/fastuuid v1.2.0 // indirect github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa // indirect - - github.com/spf13/pflag v1.0.5 // indirect + github.com/smartystreets/assertions v1.2.0 // indirect golang.org/x/text v0.3.3 // indirect golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect