完成业务流转
This commit is contained in:
parent
fabed6916c
commit
69b5ee0814
|
|
@ -3,15 +3,18 @@ package config
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var DefaultConfig = &Config{}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Config struct {
|
Config struct {
|
||||||
Systems []System
|
Systems []System `json:"System" mapstructure:"System"`
|
||||||
}
|
}
|
||||||
System struct {
|
System struct {
|
||||||
Name string
|
Name string
|
||||||
|
|
@ -23,10 +26,11 @@ type (
|
||||||
Name string
|
Name string
|
||||||
Tasks []Task
|
Tasks []Task
|
||||||
File string
|
File string
|
||||||
|
Size int //文件最大行数
|
||||||
}
|
}
|
||||||
|
|
||||||
Task struct {
|
Task struct {
|
||||||
PK string
|
PK string `mapstructure:"pk"`
|
||||||
Sql string
|
Sql string
|
||||||
Timestamp bool
|
Timestamp bool
|
||||||
Elt string
|
Elt string
|
||||||
|
|
@ -34,22 +38,22 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c Config) GetSystem(system string) (System, error) {
|
func (c Config) GetSystem(name string) (System, error) {
|
||||||
for _, s := range c.Systems {
|
for _, s := range c.Systems {
|
||||||
if s.Name == system {
|
if s.Name == name {
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return System{}, errors.New("没有找到相关配置:" + system)
|
return System{}, errors.New("没有找到相关配置:" + name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s System) GetJob(job string) (Job, error) {
|
func (s System) GetJob(name string) (Job, error) {
|
||||||
for _, j := range s.Jobs {
|
for _, j := range s.Jobs {
|
||||||
if j.Name == job {
|
if j.Name == name {
|
||||||
return j, nil
|
return j, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Job{}, errors.New("没有找到相关配置:" + job)
|
return Job{}, errors.New("没有找到相关配置:" + name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Task) GetSql(params map[string]interface{}) string {
|
func (t Task) GetSql(params map[string]interface{}) string {
|
||||||
|
|
@ -94,3 +98,25 @@ func (t Task) getParam(parm interface{}) string {
|
||||||
return fmt.Sprint(p)
|
return fmt.Sprint(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadConfig(path string) *Config {
|
||||||
|
var c Config
|
||||||
|
|
||||||
|
viper.AddConfigPath(path) //设置读取的文件路径
|
||||||
|
viper.SetConfigName("Config") //设置读取的文件名
|
||||||
|
viper.SetConfigType("yaml") //设置文件的类型
|
||||||
|
|
||||||
|
//尝试进行配置读取
|
||||||
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
|
fmt.Println("请将config.yml.example拷贝为config.yaml")
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
//v := viper.GetViper()
|
||||||
|
//fmt.Println(v)
|
||||||
|
if err := viper.Unmarshal(&c); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultConfig = &c
|
||||||
|
return &c
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLoadConfig(t *testing.T) {
|
||||||
|
path, err := os.Getwd()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
path = path + "/../../Config/"
|
||||||
|
config := LoadConfig(path)
|
||||||
|
|
||||||
|
zltx, err := config.GetSystem("直连天下")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "root:root@tcp(192.168.6.74:3307)/new_sys?charset=utf8mb4&parseTime=True", zltx.Db)
|
||||||
|
|
||||||
|
order, err := zltx.GetJob("上游订单")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Len(t, order.Tasks, 2)
|
||||||
|
|
||||||
|
assert.False(t, order.Tasks[0].Timestamp)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
|
"excel_export/biz/export"
|
||||||
|
"fmt"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ export.DataFetcher = new(Db)
|
||||||
|
|
||||||
|
type Db struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDb(str string) (*Db, error) {
|
||||||
|
db, err := gorm.Open(mysql.Open(str + ""))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//db = db.Debug()
|
||||||
|
return &Db{
|
||||||
|
db: db,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Db) Fetch(s string) (*export.Data, error) {
|
||||||
|
|
||||||
|
rows, err := d.db.Raw(s).Rows()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
titles, values, err := getRowStruct(rows)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data []interface{}
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
rows.Scan(values...)
|
||||||
|
row := make([]interface{}, len(values))
|
||||||
|
for i, value := range values {
|
||||||
|
|
||||||
|
vv := reflect.ValueOf(value)
|
||||||
|
if vv.Kind() == reflect.Ptr {
|
||||||
|
//将指针对象转换为值对象
|
||||||
|
value = vv.Elem().Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch vvv := value.(type) {
|
||||||
|
case driver.Valuer:
|
||||||
|
row[i], _ = vvv.Value()
|
||||||
|
case sql.RawBytes:
|
||||||
|
row[i] = string(vvv)
|
||||||
|
default:
|
||||||
|
row[i] = vvv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data = append(data, row)
|
||||||
|
// 业务逻辑...
|
||||||
|
}
|
||||||
|
|
||||||
|
return &export.Data{
|
||||||
|
Title: titles,
|
||||||
|
Data: data,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRowStruct(rows *sql.Rows) (title []string, t []interface{}, err error) {
|
||||||
|
titles, _ := rows.Columns()
|
||||||
|
|
||||||
|
tt, err := rows.ColumnTypes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("ColumnTypes: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
types := make([]reflect.Type, len(tt))
|
||||||
|
for i, tp := range tt {
|
||||||
|
st := tp.ScanType()
|
||||||
|
if st == nil {
|
||||||
|
return nil, nil, fmt.Errorf("scantype is null for column %q", tp.Name())
|
||||||
|
}
|
||||||
|
types[i] = st
|
||||||
|
}
|
||||||
|
|
||||||
|
values := make([]interface{}, len(tt))
|
||||||
|
for i := range values {
|
||||||
|
values[i] = reflect.New(types[i]).Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
return titles, values, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const test_db = "root:root@(192.168.6.74:3307)/recharge_trade?charset=utf8mb4&parseTime=true"
|
||||||
|
|
||||||
|
func TestDb_Fetch(t *testing.T) {
|
||||||
|
db, err := NewDb(test_db)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
sql := "select trade_number as `交易号`,account as `充值号码` from trade limit 10"
|
||||||
|
ret, err := db.Fetch(sql)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
fmt.Printf("%v \n", ret)
|
||||||
|
item := ret.Data[0].([]interface{})
|
||||||
|
for _, i := range item {
|
||||||
|
fmt.Printf("%v", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package export
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/tealeg/xlsx/v3"
|
"github.com/tealeg/xlsx/v3"
|
||||||
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Sheet_Name = "sheet_1"
|
const Sheet_Name = "sheet_1"
|
||||||
|
|
@ -57,7 +58,7 @@ func (e *Excel) Open() error {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//需要处理偏移数据
|
//需要处理偏移数据
|
||||||
e.f.SetRow(e.sheet.MaxRow - 1)
|
e.f.SetRow(e.sheet.MaxRow)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -78,6 +79,7 @@ func (e *Excel) WriteTitle(titles []string) error {
|
||||||
|
|
||||||
if e.titles != nil && e.isNew {
|
if e.titles != nil && e.isNew {
|
||||||
e.Write(e.titles)
|
e.Write(e.titles)
|
||||||
|
e.isNew = false
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +89,24 @@ func (e *Excel) Write(data interface{}) error {
|
||||||
e.reset()
|
e.reset()
|
||||||
}
|
}
|
||||||
row := e.sheet.AddRow()
|
row := e.sheet.AddRow()
|
||||||
row.WriteSlice(data, -1)
|
|
||||||
|
v := reflect.ValueOf(data)
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
if v.Kind() != reflect.Slice {
|
||||||
|
return errors.New("数据无效,不是切片类型")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch val := data.(type) {
|
||||||
|
case []string:
|
||||||
|
row.WriteSlice(val, -1)
|
||||||
|
case []interface{}:
|
||||||
|
for _, i := range data.([]interface{}) {
|
||||||
|
cell := row.AddCell()
|
||||||
|
cell.SetValue(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
package export
|
package export
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
type ExcelExporter struct {
|
type ExcelExporter struct {
|
||||||
mFetcher DataFetcher
|
mFetcher DataFetcher
|
||||||
file FileAdapter
|
file FileAdapter
|
||||||
|
count int
|
||||||
|
last interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExcelExporter(fetcher DataFetcher, file FileAdapter) DataExporter {
|
func NewExcelExporter(fetcher DataFetcher, file FileAdapter) DataExporter {
|
||||||
|
|
@ -20,15 +24,38 @@ func (ee *ExcelExporter) File(file FileAdapter) {
|
||||||
ee.file = file
|
ee.file = file
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ee *ExcelExporter) Export(sql string) error {
|
func (ee *ExcelExporter) Export(sql, pk string) error {
|
||||||
rows := ee.mFetcher.Fetch(sql)
|
data, err := ee.mFetcher.Fetch(sql)
|
||||||
//fmt.Printf("Excel Exporter.Excel, got %v rows\n", len(rows))
|
if err != nil {
|
||||||
ee.file.Open()
|
return fmt.Errorf("数据获取错误:%w", err)
|
||||||
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.count = len(data.Data)
|
||||||
|
//fmt.Printf("Excel Exporter.Excel, got %v data\n", len(data))
|
||||||
|
ee.file.Open()
|
||||||
|
ee.file.WriteTitle(data.Title)
|
||||||
|
var last interface{}
|
||||||
|
for _, val := range data.Data {
|
||||||
|
last = val
|
||||||
|
ee.file.Write(last)
|
||||||
|
}
|
||||||
|
|
||||||
|
if row, ok := last.([]interface{}); ok {
|
||||||
|
ee.last = row[getPkIndex(data.Title, pk)]
|
||||||
|
}
|
||||||
|
|
||||||
ee.file.Close()
|
ee.file.Close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ee *ExcelExporter) Last() (int, interface{}) {
|
||||||
|
return ee.count, ee.last
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPkIndex(titles []string, pk string) int {
|
||||||
|
for i, title := range titles {
|
||||||
|
if title == pk {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,16 @@ type (
|
||||||
DataExporter interface {
|
DataExporter interface {
|
||||||
Fetcher(fetcher DataFetcher)
|
Fetcher(fetcher DataFetcher)
|
||||||
File(file FileAdapter)
|
File(file FileAdapter)
|
||||||
Export(sql string) error
|
Export(sql, pk string) error
|
||||||
|
Last() (int, interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
Data struct {
|
||||||
|
Title []string
|
||||||
|
Data []interface{}
|
||||||
}
|
}
|
||||||
DataFetcher interface {
|
DataFetcher interface {
|
||||||
Fetch(sql string) []interface{}
|
Fetch(sql string) (*Data, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
FileAdapter interface {
|
FileAdapter interface {
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,14 @@ type MysqlDataFetcher struct {
|
||||||
Config string
|
Config string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mf *MysqlDataFetcher) Fetch(sql string) []interface{} {
|
func (mf *MysqlDataFetcher) Fetch(sql string) (*Data, error) {
|
||||||
rows := make([]interface{}, 0, 6)
|
rows := make([]interface{}, 0, 6)
|
||||||
// 插入6个随机数组成的切片,模拟查询要返回的数据集
|
// 插入6个随机数组成的切片,模拟查询要返回的数据集
|
||||||
rows = append(rows, rand.Perm(5), rand.Perm(5), rand.Perm(5), rand.Perm(5), rand.Perm(5), rand.Perm(5))
|
rows = append(rows, rand.Perm(5), rand.Perm(5), rand.Perm(5), rand.Perm(5), rand.Perm(5), rand.Perm(5))
|
||||||
return rows
|
return &Data{
|
||||||
|
Title: []string{"字段1", "字段2", "字段3", "字段4", "字段5"},
|
||||||
|
Data: rows,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMysqlDataFetcher(configStr string) DataFetcher {
|
func NewMysqlDataFetcher(configStr string) DataFetcher {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"excel_export/biz/config"
|
||||||
|
"excel_export/biz/db"
|
||||||
|
"excel_export/biz/export"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Export(conf *config.Config, sysName, jobName string, begin, end time.Time, batch int) error {
|
||||||
|
job, dbStr, err := GetJob(conf, sysName, jobName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d, err := db.NewDb(dbStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return JobHandler(job, d, map[string]interface{}{
|
||||||
|
"begin": begin,
|
||||||
|
"end": end,
|
||||||
|
"last": 0,
|
||||||
|
}, batch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetJob(conf *config.Config, sys, job string) (config.Job, string, error) {
|
||||||
|
s, err := conf.GetSystem(sys)
|
||||||
|
if err != nil {
|
||||||
|
return config.Job{}, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
j, err := s.GetJob(job)
|
||||||
|
if err != nil {
|
||||||
|
return config.Job{}, "", err
|
||||||
|
}
|
||||||
|
return j, s.Db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func JobHandler(job config.Job, d export.DataFetcher, params map[string]interface{}, batch int) error {
|
||||||
|
|
||||||
|
f := export.NewExcel(job.File, job.Size, map[string]string{
|
||||||
|
"begin": params["begin"].(time.Time).Format("20060102"),
|
||||||
|
"end": params["end"].(time.Time).Format("20060102"),
|
||||||
|
})
|
||||||
|
|
||||||
|
for i, task := range job.Tasks {
|
||||||
|
fmt.Printf("执行导出任务:%d\n", i+1)
|
||||||
|
if err := TaskExport(d, task, params, f, batch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TaskExport(d export.DataFetcher, t config.Task, params map[string]interface{}, f export.FileAdapter, batch int) error {
|
||||||
|
//todo 最多分1000个批次进行处理
|
||||||
|
for i := 0; i < 1000; i++ {
|
||||||
|
sql := t.GetSql(params)
|
||||||
|
|
||||||
|
e := export.NewExcelExporter(d, f)
|
||||||
|
|
||||||
|
e.Export(sql+" limit "+strconv.Itoa(batch), t.PK)
|
||||||
|
|
||||||
|
count, last := e.Last()
|
||||||
|
fmt.Printf("已导出 %d 条数据\n", batch*i+count)
|
||||||
|
if count < batch {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
params["last"] = last
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"excel_export/biz"
|
|
||||||
"excel_export/data"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
var OrderCmd = &cobra.Command{
|
|
||||||
Use: "order",
|
|
||||||
Short: "导出订单记录",
|
|
||||||
Run: orderRun,
|
|
||||||
}
|
|
||||||
|
|
||||||
func orderRun(cmd *cobra.Command, args []string) {
|
|
||||||
begin := MustFlagsDateTime(cmd, "begin")
|
|
||||||
end := MustFlagsDateTime(cmd, "end")
|
|
||||||
|
|
||||||
query, limit, path := GetGlobalFlags(cmd)
|
|
||||||
|
|
||||||
db := data.Conn()
|
|
||||||
repo := data.NewOrderRepo(db)
|
|
||||||
historyRepo := data.NewHistoryOrderRepo(db)
|
|
||||||
|
|
||||||
orderBiz := biz.NewOrderBiz(repo, historyRepo, biz.NewExportOpts(query, limit, path))
|
|
||||||
|
|
||||||
cmd.Println("开始导出文件...")
|
|
||||||
cobra.CheckErr(orderBiz.Export(begin, end))
|
|
||||||
|
|
||||||
cmd.Println("导出文件完成")
|
|
||||||
for _, name := range orderBiz.FileNames() {
|
|
||||||
cmd.Println(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"excel_export/biz/config"
|
||||||
|
"fmt"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"os"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
|
|
@ -10,19 +13,83 @@ var rootCmd = &cobra.Command{
|
||||||
Short: "导出直充系统订单数据",
|
Short: "导出直充系统订单数据",
|
||||||
SilenceUsage: true,
|
SilenceUsage: true,
|
||||||
SilenceErrors: true,
|
SilenceErrors: true,
|
||||||
|
Run: rootRun,
|
||||||
}
|
}
|
||||||
|
|
||||||
func Execute() {
|
func Execute() {
|
||||||
path, _ := os.Getwd()
|
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringP("path", "p", path, "文件路径")
|
rootCmd.Flags().IntP("query", "q", 10000, "单次查询数")
|
||||||
rootCmd.PersistentFlags().IntP("query", "q", 10000, "单次查询数")
|
|
||||||
rootCmd.PersistentFlags().IntP("limit", "l", 1000000, "单个文档最大记录数")
|
|
||||||
|
|
||||||
OrderCmd.Flags().StringP("begin", "b", "", "开始时间,如:2006-01-02 15:04:05")
|
rootCmd.Flags().StringP("system", "s", "", "需要导出的系统")
|
||||||
OrderCmd.Flags().StringP("end", "e", "", "结束时间,如:2006-01-02 15:04:05")
|
rootCmd.Flags().StringP("job", "j", "", "需要导出的任务")
|
||||||
|
rootCmd.Flags().StringP("begin", "b", "", "开始时间,如:2006-01-02 15:04:05")
|
||||||
|
rootCmd.Flags().StringP("end", "e", "", "结束时间,如:2006-01-02 15:04:05")
|
||||||
|
// rootCmd.AddCommand(ExportCmd)
|
||||||
|
|
||||||
rootCmd.AddCommand(OrderCmd)
|
|
||||||
cobra.CheckErr(rootCmd.Execute())
|
cobra.CheckErr(rootCmd.Execute())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func rootRun(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
|
fmt.Println(args)
|
||||||
|
c := config.DefaultConfig
|
||||||
|
|
||||||
|
sName := cmd.Flag("system").Value.String()
|
||||||
|
if sName == "" {
|
||||||
|
cmd.Println("支持的系统")
|
||||||
|
for i, system := range c.Systems {
|
||||||
|
cmd.Printf("\t %d\t%s\n", i+1, system.Name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var sys config.System
|
||||||
|
sIndex, err := strconv.Atoi(sName)
|
||||||
|
if err == nil {
|
||||||
|
sys = c.Systems[sIndex-1]
|
||||||
|
sName = sys.Name
|
||||||
|
} else {
|
||||||
|
sys, err = c.GetSystem(sName)
|
||||||
|
if err != nil {
|
||||||
|
CmdError(cmd, "%s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jName := cmd.Flag("job").Value.String()
|
||||||
|
if jName == "" {
|
||||||
|
cmd.Println("支持的任务")
|
||||||
|
for i, job := range sys.Jobs {
|
||||||
|
cmd.Printf("\t %d\t%s \n", i+1, job.Name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var job config.Job
|
||||||
|
jIndex, err := strconv.Atoi(jName)
|
||||||
|
if err == nil {
|
||||||
|
job = sys.Jobs[jIndex-1]
|
||||||
|
jName = job.Name
|
||||||
|
} else {
|
||||||
|
job, err = sys.GetJob(jName)
|
||||||
|
if err != nil {
|
||||||
|
CmdError(cmd, "%s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("[%s]执行【%s】【%s】导出\n", time.Now().Format("2006-01-02 15:04:05"), sName, jName)
|
||||||
|
|
||||||
|
begin := MustFlagsDateTime(cmd, "begin")
|
||||||
|
end := MustFlagsDateTime(cmd, "end")
|
||||||
|
|
||||||
|
query := cmd.Flag("query").Value.String()
|
||||||
|
batch, err := strconv.Atoi(query)
|
||||||
|
if err != nil {
|
||||||
|
CmdError(cmd, "无效的参数:%s", err.Error())
|
||||||
|
}
|
||||||
|
b := time.Now()
|
||||||
|
Export(config.DefaultConfig, sName, jName, begin, end, batch)
|
||||||
|
e := time.Now()
|
||||||
|
fmt.Println("耗时:" + e.Sub(b).String())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,15 +35,3 @@ func CmdError(cmd *cobra.Command, format string, opts ...interface{}) {
|
||||||
fmt.Fprintf(cmd.OutOrStderr(), format, opts...)
|
fmt.Fprintf(cmd.OutOrStderr(), format, opts...)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGlobalFlags(cmd *cobra.Command) (int, int, string) {
|
|
||||||
path, err := cmd.Flags().GetString("path")
|
|
||||||
cobra.CheckErr(err)
|
|
||||||
|
|
||||||
query, err := cmd.Flags().GetInt("query")
|
|
||||||
cobra.CheckErr(err)
|
|
||||||
|
|
||||||
limit, err := cmd.Flags().GetInt("limit")
|
|
||||||
cobra.CheckErr(err)
|
|
||||||
return query, limit, path
|
|
||||||
}
|
|
||||||
|
|
|
||||||
34
cmd/main.go
34
cmd/main.go
|
|
@ -1,20 +1,26 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "excel_export/cmd/cmd"
|
import (
|
||||||
|
"excel_export/biz/config"
|
||||||
|
"excel_export/cmd/cmd"
|
||||||
|
"github.com/tealeg/xlsx/v3"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Config *config.Config
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
//设置默认格式
|
||||||
|
xlsx.DefaultDateTimeOptions = xlsx.DateTimeOptions{
|
||||||
|
Location: time.UTC,
|
||||||
|
ExcelTimeFormat: "yyyy-m-d h:mm:ss",
|
||||||
|
}
|
||||||
|
xlsx.DefaultDateTimeFormat = ""
|
||||||
|
|
||||||
|
path, _ := os.Getwd()
|
||||||
|
Config = config.LoadConfig(path + "/config")
|
||||||
|
|
||||||
cmd.Execute()
|
cmd.Execute()
|
||||||
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
//分块获取数据
|
|
||||||
|
|
||||||
//获取关联表单数据
|
|
||||||
|
|
||||||
//组装数据
|
|
||||||
|
|
||||||
//将数据写入excel中
|
|
||||||
|
|
||||||
//更具切割参数,计算拆分文件序号
|
|
||||||
|
|
||||||
//并发读写数据的能力
|
|
||||||
//控制内存使用、cpu使用
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
system:
|
system:
|
||||||
- name: "直连天下"
|
- name: "直连天下"
|
||||||
db: ""
|
db: "root:lhb767@tcp(120.79.35.82:3307)/new_sys?charset=utf8mb4&parseTime=True"
|
||||||
jobs:
|
jobs:
|
||||||
- name: "卡密订单"
|
- name: "卡密订单"
|
||||||
tasks:
|
tasks:
|
||||||
- sql: >-
|
- pk: "订单号"
|
||||||
|
sql: >-
|
||||||
SELECT
|
SELECT
|
||||||
order_number AS `订单号` ,
|
order_number AS `订单号` ,
|
||||||
reseller_order_number AS `分销商订单号`,
|
reseller_order_number AS `分销商订单号`,
|
||||||
|
|
@ -27,10 +28,12 @@ system:
|
||||||
timestamp: true
|
timestamp: true
|
||||||
elt: "order_card.create_time BETWEEN {begin} AND {end} and order_card.order_number > {last}"
|
elt: "order_card.create_time BETWEEN {begin} AND {end} and order_card.order_number > {last}"
|
||||||
order: "order_card.create_time,order_card.order_number"
|
order: "order_card.create_time,order_card.order_number"
|
||||||
file: "直连天下-卡密订单-${month}.xlsx"
|
file: "直连天下-卡密订单-{begin}-{end}.xlsx"
|
||||||
|
size: 10000
|
||||||
- name: "上游订单"
|
- name: "上游订单"
|
||||||
tasks:
|
tasks:
|
||||||
- sql: >-
|
- pk: "流水号"
|
||||||
|
sql: >-
|
||||||
SELECT
|
SELECT
|
||||||
o.reseller_id as `分销商id`,
|
o.reseller_id as `分销商id`,
|
||||||
r.`name` as `分销商名称`,
|
r.`name` as `分销商名称`,
|
||||||
|
|
@ -73,7 +76,8 @@ system:
|
||||||
timestamp: false
|
timestamp: false
|
||||||
elt: "od.create_time BETWEEN '{begin}' and '{end}' and od.serial_number > {last}"
|
elt: "od.create_time BETWEEN '{begin}' and '{end}' and od.serial_number > {last}"
|
||||||
order: "od.create_time,od.serial_number"
|
order: "od.create_time,od.serial_number"
|
||||||
- sql: >-
|
- pk: "流水号"
|
||||||
|
sql: >-
|
||||||
SELECT
|
SELECT
|
||||||
o.reseller_id as `分销商id`,
|
o.reseller_id as `分销商id`,
|
||||||
r.`name` as `分销商名称`,
|
r.`name` as `分销商名称`,
|
||||||
|
|
@ -118,10 +122,12 @@ system:
|
||||||
timestamp: false
|
timestamp: false
|
||||||
elt: "od.create_time BETWEEN '{begin}' and '{end}' and od.serial_number > {last}"
|
elt: "od.create_time BETWEEN '{begin}' and '{end}' and od.serial_number > {last}"
|
||||||
order: "od.create_time,od.serial_number"
|
order: "od.create_time,od.serial_number"
|
||||||
file: "直连天下-上游订单-${month}.xlsx"
|
file: "直连天下-上游订单-{begin}-{end}.xlsx"
|
||||||
|
size: 10000
|
||||||
- name: "下游订单"
|
- name: "下游订单"
|
||||||
tasks:
|
tasks:
|
||||||
- sql: >-
|
- ps: "订单号"
|
||||||
|
sql: >-
|
||||||
SELECT
|
SELECT
|
||||||
o.order_number as `订单号`,
|
o.order_number as `订单号`,
|
||||||
o.reseller_id as `分销商id`,
|
o.reseller_id as `分销商id`,
|
||||||
|
|
@ -166,7 +172,8 @@ system:
|
||||||
elt: "o.`create_time` >= '{begin}' and o.create_time < '{end}' and o.order_number > {last}"
|
elt: "o.`create_time` >= '{begin}' and o.create_time < '{end}' and o.order_number > {last}"
|
||||||
timestamp: false
|
timestamp: false
|
||||||
order: "o.create_time,o.order_number"
|
order: "o.create_time,o.order_number"
|
||||||
- sql: >-
|
- pk: "订单号"
|
||||||
|
sql: >-
|
||||||
SELECT
|
SELECT
|
||||||
o.order_number as `订单号`,
|
o.order_number as `订单号`,
|
||||||
o.reseller_id as `分销商id`,
|
o.reseller_id as `分销商id`,
|
||||||
|
|
@ -212,13 +219,18 @@ system:
|
||||||
elt: "o.`create_time` >= {begin} and o.create_time < {end} and o.order_number > {last}"
|
elt: "o.`create_time` >= {begin} and o.create_time < {end} and o.order_number > {last}"
|
||||||
timestamp: true
|
timestamp: true
|
||||||
order: "o.create_time,o.order_number"
|
order: "o.create_time,o.order_number"
|
||||||
file: "直连天下-下游订单-${month}.xlsx"
|
file: "直连天下-下游订单-{begin}-{end}.xlsx"
|
||||||
|
size: 10000
|
||||||
|
|
||||||
- name: "营销系统"
|
- name: "营销系统"
|
||||||
db: ""
|
db: ""
|
||||||
jobs:
|
jobs:
|
||||||
- name: "订单信息"
|
- name: "订单信息"
|
||||||
tasks:
|
tasks:
|
||||||
- sql: ""
|
- pk: ""
|
||||||
|
sql: ""
|
||||||
elt: ""
|
elt: ""
|
||||||
file: "营销系统-订单信息-${month}.xlsx"
|
timestamp: true
|
||||||
|
order: ""
|
||||||
|
file: "营销系统-订单信息-{begin}-{end}.xlsx"
|
||||||
|
size: 10000
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package data
|
|
||||||
|
|
||||||
type Batch struct {
|
|
||||||
BatchId string `gorm:"primaryKey;column:batch_id"`
|
|
||||||
Customer string
|
|
||||||
Price float32
|
|
||||||
DingTalkSn string
|
|
||||||
Remark string
|
|
||||||
Success int
|
|
||||||
Fail int
|
|
||||||
ResellerId int
|
|
||||||
Reseller Reseller `gorm:"foreignkey:id;references:reseller_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b Batch) TableName() string {
|
|
||||||
return "batch_direct"
|
|
||||||
}
|
|
||||||
63
data/card.go
63
data/card.go
|
|
@ -1,63 +0,0 @@
|
||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Card struct {
|
|
||||||
OrderNumber string `gorm:"primaryKey;column:order_number"`
|
|
||||||
ResellerId int `gorm:"column:reseller_id"`
|
|
||||||
ResellerOrderNumber string `gorm:"column:reseller_order_number"`
|
|
||||||
OursProductId int `gorm:"column:ours_product_id"`
|
|
||||||
Price float32 `gorm:"column:price"`
|
|
||||||
Quantity int `gorm:"column:quantity"`
|
|
||||||
Amount float32 `gorm:"column:amount"`
|
|
||||||
PayStatus int `gorm:"column:pay_status"`
|
|
||||||
Status int `gorm:"column:status"`
|
|
||||||
Profit float32 `gorm:"column:profit"`
|
|
||||||
NotifyTime int64 `gorm:"column:notify_time"`
|
|
||||||
CreateIp int64 `gorm:"column:create_ip"`
|
|
||||||
CreateTime int64 `gorm:"column:create_time"`
|
|
||||||
CardCode string `gorm:"column:card_code"`
|
|
||||||
FinishTime time.Time `gorm:"column:finish_time"`
|
|
||||||
Message string `gorm:"column:message"`
|
|
||||||
Mobile string `gorm:"column:mobile"`
|
|
||||||
OurProduct OurProduct `gorm:"foreignkey:id;references:ours_product_id"`
|
|
||||||
Reseller Reseller `gorm:"foreignkey:id;references:reseller_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o Card) TableName() string {
|
|
||||||
return "order_card"
|
|
||||||
}
|
|
||||||
|
|
||||||
type CardRepo struct {
|
|
||||||
db *gorm.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCardRepo(db *gorm.DB) *CardRepo {
|
|
||||||
return &CardRepo{
|
|
||||||
db: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo CardRepo) List(ctx context.Context, begin, end time.Time, limit int, last string) ([]Card, error) {
|
|
||||||
var orders []Card
|
|
||||||
db := repo.db.WithContext(ctx).
|
|
||||||
Preload("OurProduct").
|
|
||||||
Preload("Reseller").
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cardRepo() *CardRepo {
|
|
||||||
db := Conn()
|
|
||||||
return NewCardRepo(db)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCardRepo_List(t *testing.T) {
|
|
||||||
repo := cardRepo()
|
|
||||||
begin := time.Date(2018, 10, 1, 0, 0, 0, 0, time.Local)
|
|
||||||
end := time.Date(2023, 12, 1, 0, 0, 0, 0, time.Local)
|
|
||||||
cards, err := repo.List(context.Background(), begin, end, 10, "123")
|
|
||||||
assert.Nil(t, err)
|
|
||||||
fmt.Printf("%+v\n", cards)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
package data
|
|
||||||
|
|
||||||
type OurProduct struct {
|
|
||||||
Id int64 `gorm:"column:id"`
|
|
||||||
Name string `gorm:"column:name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o OurProduct) TableName() string {
|
|
||||||
return "ours_product"
|
|
||||||
}
|
|
||||||
|
|
||||||
type Platform struct {
|
|
||||||
Id int64
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Platform) TableName() string {
|
|
||||||
return "platform"
|
|
||||||
}
|
|
||||||
|
|
||||||
type PlatformProduct struct {
|
|
||||||
Id int64
|
|
||||||
PlatformId int64
|
|
||||||
Name string
|
|
||||||
Code string
|
|
||||||
Platform Platform `gorm:"foreignkey:id;references:platform_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p PlatformProduct) TableName() string {
|
|
||||||
return "platform_product"
|
|
||||||
}
|
|
||||||
|
|
||||||
type Reseller struct {
|
|
||||||
Id int64 `gorm:"primaryKey;column:id"`
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o Reseller) TableName() string {
|
|
||||||
return "reseller"
|
|
||||||
}
|
|
||||||
14
data/conn.go
14
data/conn.go
|
|
@ -1,14 +0,0 @@
|
||||||
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 //.Debug()
|
|
||||||
}
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Direct struct {
|
|
||||||
SerialNumber string `gorm:"primaryKey;column:serial_number"`
|
|
||||||
OrderOrderNumber string `gorm:"column:order_order_number"`
|
|
||||||
TerminalAccount string `gorm:"column:terminal_account"`
|
|
||||||
OursProductId int `gorm:"column:ours_product_id"`
|
|
||||||
Status int `gorm:"column:status"`
|
|
||||||
TradePrice float32 `gorm:"column:trade_price"`
|
|
||||||
PlatformProductId int `gorm:"column:platform_product_id"`
|
|
||||||
PlatformPrice float32 `gorm:"column:platform_price"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time"`
|
|
||||||
ExecuteTime time.Time `gorm:"column:execute_time"`
|
|
||||||
Identifier int `gorm:"column:identifier"`
|
|
||||||
Version int `gorm:"column:version"`
|
|
||||||
Type int `gorm:"column:type"`
|
|
||||||
Position int `gorm:"column:position"`
|
|
||||||
Order Order `gorm:"foreignkey:order_number;references:order_order_number"`
|
|
||||||
OrderItem OrderItem `gorm:"foreignkey:order_order_number;references:order_order_number"`
|
|
||||||
PlatformProduct PlatformProduct `gorm:"foreignkey:id;references:platform_product_id"`
|
|
||||||
Batch Batch `gorm:"foreignkey:batch_id;references:order_order_number"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d Direct) TableName() string {
|
|
||||||
return "order_direct"
|
|
||||||
}
|
|
||||||
|
|
||||||
type DirectRepo struct {
|
|
||||||
db *gorm.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDirectRepo(db *gorm.DB) *DirectRepo {
|
|
||||||
return &DirectRepo{
|
|
||||||
db: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo DirectRepo) List(ctx context.Context, begin, end time.Time, limit int, last string) ([]Direct, error) {
|
|
||||||
var directs []Direct
|
|
||||||
db := repo.db.WithContext(ctx).
|
|
||||||
Preload("Order.Remark").
|
|
||||||
Preload("Order.Reseller").
|
|
||||||
Preload("OrderItem").
|
|
||||||
Preload("PlatformProduct").
|
|
||||||
Preload("PlatformProduct.Platform").
|
|
||||||
Where("create_time BETWEEN ? AND ?", begin, end)
|
|
||||||
if last != "" {
|
|
||||||
db.Where("serial_number > ?", last)
|
|
||||||
}
|
|
||||||
result := db.Order("create_time,serial_number").
|
|
||||||
Limit(limit).
|
|
||||||
Find(&directs)
|
|
||||||
|
|
||||||
if result.Error != nil {
|
|
||||||
return nil, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return directs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo DirectRepo) BatchList(ctx context.Context, begin, end time.Time, limit int, last string) ([]Direct, error) {
|
|
||||||
var directs []Direct
|
|
||||||
db := repo.db.WithContext(ctx).
|
|
||||||
InnerJoins("Batch").
|
|
||||||
Preload("Batch.Reseller").
|
|
||||||
Preload("PlatformProduct").
|
|
||||||
Preload("PlatformProduct.Platform").
|
|
||||||
Where("order_direct.create_time BETWEEN ? AND ?", begin, end)
|
|
||||||
if last != "" {
|
|
||||||
db.Where("order_direct.serial_number > ?", last)
|
|
||||||
}
|
|
||||||
result := db.Order("order_direct.create_time,order_direct.serial_number").
|
|
||||||
Limit(limit).
|
|
||||||
Find(&directs)
|
|
||||||
|
|
||||||
if result.Error != nil {
|
|
||||||
return nil, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return directs, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func directRepo() *DirectRepo {
|
|
||||||
db := Conn()
|
|
||||||
return NewDirectRepo(db)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDirectRepo_List(t *testing.T) {
|
|
||||||
repo := directRepo()
|
|
||||||
begin := time.Date(2022, 10, 1, 0, 0, 0, 0, time.Local)
|
|
||||||
end := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local)
|
|
||||||
directs, err := repo.List(context.Background(), begin, end, 10, "123")
|
|
||||||
assert.Nil(t, err)
|
|
||||||
fmt.Printf("%+v\n", directs)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDirectRepo_BatchList(t *testing.T) {
|
|
||||||
repo := directRepo()
|
|
||||||
begin := time.Date(2022, 10, 1, 0, 0, 0, 0, time.Local)
|
|
||||||
end := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local)
|
|
||||||
directs, err := repo.BatchList(context.Background(), begin, end, 10, "123")
|
|
||||||
assert.Nil(t, err)
|
|
||||||
fmt.Printf("%+v\n", directs)
|
|
||||||
}
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HistoryDirect struct {
|
|
||||||
SerialNumber string `gorm:"primaryKey;column:serial_number"`
|
|
||||||
OrderOrderNumber string `gorm:"column:order_order_number"`
|
|
||||||
TerminalAccount string `gorm:"column:terminal_account"`
|
|
||||||
OursProductId int `gorm:"column:ours_product_id"`
|
|
||||||
Status int `gorm:"column:status"`
|
|
||||||
TradePrice float32 `gorm:"column:trade_price"`
|
|
||||||
PlatformProductId int `gorm:"column:platform_product_id"`
|
|
||||||
PlatformPrice float32 `gorm:"column:platform_price"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time"`
|
|
||||||
ExecuteTime time.Time `gorm:"column:execute_time"`
|
|
||||||
Identifier int `gorm:"column:identifier"`
|
|
||||||
Version int `gorm:"column:version"`
|
|
||||||
Type int `gorm:"column:type"`
|
|
||||||
Position int `gorm:"column:position"`
|
|
||||||
Order HistoryOrder `gorm:"foreignkey:order_number;references:order_order_number"`
|
|
||||||
OrderItem HistoryOrderItem `gorm:"foreignkey:order_order_number;references:order_order_number"`
|
|
||||||
PlatformProduct PlatformProduct `gorm:"foreignkey:id;references:platform_product_id"`
|
|
||||||
Batch Batch `gorm:"foreignkey:batch_id;references:order_order_number"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d HistoryDirect) TableName() string {
|
|
||||||
return "history_order_direct"
|
|
||||||
}
|
|
||||||
|
|
||||||
type HistoryDirectRepo struct {
|
|
||||||
db *gorm.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHistoryDirectRepo(db *gorm.DB) *HistoryDirectRepo {
|
|
||||||
return &HistoryDirectRepo{
|
|
||||||
db: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo HistoryDirectRepo) List(ctx context.Context, begin, end time.Time, limit int, last string) ([]HistoryDirect, error) {
|
|
||||||
var directs []HistoryDirect
|
|
||||||
db := repo.db.WithContext(ctx).
|
|
||||||
Preload("Order.Remark").
|
|
||||||
Preload("Order.Reseller").
|
|
||||||
Preload("OrderItem").
|
|
||||||
Preload("PlatformProduct").
|
|
||||||
Preload("PlatformProduct.Platform").
|
|
||||||
Where("create_time BETWEEN ? AND ?", begin, end)
|
|
||||||
if last != "" {
|
|
||||||
db.Where("serial_number > ?", last)
|
|
||||||
}
|
|
||||||
result := db.Order("create_time,serial_number").
|
|
||||||
Limit(limit).
|
|
||||||
Find(&directs)
|
|
||||||
|
|
||||||
if result.Error != nil {
|
|
||||||
return nil, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return directs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo HistoryDirectRepo) BatchList(ctx context.Context, begin, end time.Time, limit int, last string) ([]HistoryDirect, error) {
|
|
||||||
var directs []HistoryDirect
|
|
||||||
db := repo.db.WithContext(ctx).
|
|
||||||
InnerJoins("Batch").
|
|
||||||
Preload("Batch.Reseller").
|
|
||||||
Preload("PlatformProduct").
|
|
||||||
Preload("PlatformProduct.Platform").
|
|
||||||
Where("history_order_direct.create_time BETWEEN ? AND ?", begin, end)
|
|
||||||
if last != "" {
|
|
||||||
db.Where("history_order_direct.serial_number > ?", last)
|
|
||||||
}
|
|
||||||
result := db.Order("history_order_direct.create_time,history_order_direct.serial_number").
|
|
||||||
Limit(limit).
|
|
||||||
Find(&directs)
|
|
||||||
|
|
||||||
if result.Error != nil {
|
|
||||||
return nil, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
return directs, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HistoryOrderItem struct {
|
|
||||||
OrderNumber string `gorm:"primaryKey;column:order_order_number"`
|
|
||||||
OursProductId int
|
|
||||||
OursProductTitle string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o HistoryOrderItem) TableName() string {
|
|
||||||
return "history_order_item"
|
|
||||||
}
|
|
||||||
|
|
||||||
type HistoryOrderRemark struct {
|
|
||||||
OrderNumber string `gorm:"primaryKey;column:order_number"`
|
|
||||||
Remark string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o HistoryOrderRemark) TableName() string {
|
|
||||||
return "history_order_remark"
|
|
||||||
}
|
|
||||||
|
|
||||||
type HistoryOrder struct {
|
|
||||||
OrderNumber string `gorm:"primaryKey;column:order_number"`
|
|
||||||
ResellerId int64
|
|
||||||
ResellerOrderNumber string
|
|
||||||
Amount float32
|
|
||||||
Account string
|
|
||||||
Quantity int
|
|
||||||
Status int
|
|
||||||
PayStatus int
|
|
||||||
CreateTime time.Time
|
|
||||||
FinishTime time.Time
|
|
||||||
Item HistoryOrderItem `gorm:"foreignkey:order_order_number;references:order_number"`
|
|
||||||
Remark HistoryOrderRemark `gorm:"foreignkey:order_number;references:order_number"`
|
|
||||||
Reseller Reseller `gorm:"foreignkey:id;references:reseller_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o HistoryOrder) TableName() string {
|
|
||||||
return "history_order"
|
|
||||||
}
|
|
||||||
|
|
||||||
type HistoryOrderRepo struct {
|
|
||||||
db *gorm.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHistoryOrderRepo(db *gorm.DB) *HistoryOrderRepo {
|
|
||||||
return &HistoryOrderRepo{
|
|
||||||
db: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo HistoryOrderRepo) List(ctx context.Context, begin, end time.Time, limit int, last string) ([]HistoryOrder, error) {
|
|
||||||
var orders []HistoryOrder
|
|
||||||
db := repo.db.WithContext(ctx).
|
|
||||||
Preload("Reseller").
|
|
||||||
Preload("Item").
|
|
||||||
Preload("Remark").
|
|
||||||
Where("create_time BETWEEN ? AND ?", begin, end)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
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).
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
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)
|
|
||||||
}
|
|
||||||
28
go.mod
28
go.mod
|
|
@ -14,27 +14,35 @@ require (
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/smartystreets/goconvey v1.7.2
|
require github.com/spf13/viper v1.15.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/frankban/quicktest v1.11.2 // indirect
|
github.com/frankban/quicktest v1.14.3 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||||
github.com/google/btree v1.0.0 // indirect
|
github.com/google/btree v1.0.0 // indirect
|
||||||
github.com/google/go-cmp v0.5.2 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/jtolds/gls v4.20.0+incompatible // indirect
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
github.com/kr/pretty v0.2.1 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/kr/text v0.1.0 // indirect
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/rogpeppe/fastuuid v1.2.0 // indirect
|
github.com/rogpeppe/fastuuid v1.2.0 // indirect
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1 // indirect
|
||||||
github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa // indirect
|
github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa // indirect
|
||||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
github.com/spf13/afero v1.9.3 // indirect
|
||||||
golang.org/x/text v0.3.3 // indirect
|
github.com/spf13/cast v1.5.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
|
github.com/subosito/gotenv v1.4.2 // indirect
|
||||||
|
golang.org/x/sys v0.3.0 // indirect
|
||||||
|
golang.org/x/text v0.5.0 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue