133 lines
2.8 KiB
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))
|
||
|
}
|