package export import ( "fmt" "reflect" "strconv" "strings" "github.com/xuri/excelize/v2" ) type Exporter struct { File string Path string Sheets []string Titles []Title Data interface{} xlsx *excelize.File GlobalTitleStyle *excelize.Style } func NewExporter() *Exporter { return &Exporter{ xlsx: excelize.NewFile(), } } func DefaultExporter() *Exporter { return &Exporter{ xlsx: excelize.NewFile(), GlobalTitleStyle: DefaultTitleStyle(), Sheets: []string{"Sheet1"}, } } func (e *Exporter) newSheet() error { for _, sheet := range e.Sheets { _, err := e.xlsx.NewSheet(sheet) if err != nil { return fmt.Errorf("init sheet error:%s", err) } } return nil } func (e *Exporter) Export(sheetIndex int) error { if len(e.Sheets) == 0 { return fmt.Errorf("excel file has no sheet") } err := e.newSheet() if err != nil { return err } if len(e.Titles) == 0 { return fmt.Errorf("excel title is null") } sheet := e.Sheets[sheetIndex] e.SetTitle(sheet) v := reflect.ValueOf(e.Data) if v.Kind() != reflect.Pointer { return fmt.Errorf("data must be pointer") } if v.Elem().Kind() != reflect.Slice { return fmt.Errorf("data must be slice") } for i := 0; i < v.Elem().Len(); i++ { value := v.Elem().Index(i) if value.Kind() != reflect.Struct { return fmt.Errorf("element must be struct") } e.dealElement(sheet, value, i) } return nil } func (e *Exporter) dealElement(sheet string, data reflect.Value, index int) error { for i := 0; i < data.NumField(); i++ { field := data.Field(i) switch field.Kind() { case reflect.Struct: e.dealElement(sheet, field, index) // 该逻辑有待验证 case reflect.Slice: for j := 0; j < field.Len(); j++ { value := field.Index(j) if value.Kind() == reflect.Struct { e.dealElement(sheet, value, index) } } default: t := data.Type().Field(i) tag, ok := t.Tag.Lookup("export") if ok { tagMap := dealTag(tag) x, _ := strconv.Atoi(tagMap["x"]) y, _ := strconv.Atoi(tagMap["y"]) colSpan, _ := strconv.Atoi(tagMap["colspan"]) rowSpan, _ := strconv.Atoi(tagMap["rowspan"]) location := Location{ X: x, Y: y + index, } cell := Cell{ Location: location, Rowspan: rowSpan, Colspan: colSpan, Value: field, } e.SetCell(sheet, cell) } } } return e.Save() } func dealTag(tag string) map[string]string { tag_list := strings.Split(tag, ",") tag_map := make(map[string]string) for _, tag := range tag_list { tag_kv := strings.Split(tag, ":") if len(tag_kv) != 2 { continue } tag_map[tag_kv[0]] = tag_kv[1] } return tag_map } func (e *Exporter) Save() error { return e.xlsx.SaveAs(fmt.Sprintf("%s/%s", e.Path, e.File)) }