xlsx/export/xlsx.go

133 lines
2.8 KiB
Go

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))
}