167 lines
4.3 KiB
Go
167 lines
4.3 KiB
Go
package system
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/xuri/excelize/v2"
|
|
)
|
|
|
|
func templateColumns(raw string) ([]string, map[string]string, error) {
|
|
labels := map[string]string{}
|
|
decoder := json.NewDecoder(strings.NewReader(raw))
|
|
token, err := decoder.Token()
|
|
if err != nil || token != json.Delim('{') {
|
|
return nil, nil, err
|
|
}
|
|
keys := make([]string, 0)
|
|
for decoder.More() {
|
|
keyToken, tokenErr := decoder.Token()
|
|
if tokenErr != nil {
|
|
return nil, nil, tokenErr
|
|
}
|
|
key := keyToken.(string)
|
|
var label string
|
|
if tokenErr = decoder.Decode(&label); tokenErr != nil {
|
|
return nil, nil, tokenErr
|
|
}
|
|
keys = append(keys, key)
|
|
labels[key] = label
|
|
}
|
|
if _, err = decoder.Token(); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return keys, labels, nil
|
|
}
|
|
func (s *ExportService) Export(ctx context.Context, tid string, params map[string]string) ([]byte, string, error) {
|
|
template, err := s.uc.FindExportTemplate(ctx, 0, tid)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
rows, _, err := s.uc.QueryExport(ctx, template, params)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
keys, labels, err := templateColumns(template.TemplateInfo)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
file := excelize.NewFile()
|
|
sheet := file.GetSheetName(0)
|
|
for column, key := range keys {
|
|
cell, _ := excelize.CoordinatesToCellName(column+1, 1)
|
|
_ = file.SetCellValue(sheet, cell, labels[key])
|
|
}
|
|
for rowIndex, row := range rows {
|
|
for column, key := range keys {
|
|
cell, _ := excelize.CoordinatesToCellName(column+1, rowIndex+2)
|
|
lookup := strings.ReplaceAll(strings.ReplaceAll(key, `"`, ""), "`", "")
|
|
if len(template.Joins) > 0 {
|
|
if parts := strings.Split(lookup, " as "); len(parts) > 1 {
|
|
lookup = strings.TrimSpace(parts[1])
|
|
} else if parts = strings.Split(lookup, "."); len(parts) > 1 {
|
|
lookup = parts[1]
|
|
}
|
|
}
|
|
_ = file.SetCellValue(sheet, cell, exportCellValue(row[lookup]))
|
|
}
|
|
}
|
|
buffer, err := file.WriteToBuffer()
|
|
_ = file.Close()
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
return buffer.Bytes(), template.Name + ".xlsx", nil
|
|
}
|
|
|
|
func exportCellValue(value any) any {
|
|
switch typed := value.(type) {
|
|
case time.Time:
|
|
return typed.Format("2006-01-02 15:04:05")
|
|
case []byte:
|
|
return string(typed)
|
|
case string:
|
|
return typed
|
|
default:
|
|
return value
|
|
}
|
|
}
|
|
func (s *ExportService) ExportBlankTemplate(ctx context.Context, tid string) ([]byte, string, error) {
|
|
template, err := s.uc.FindExportTemplate(ctx, 0, tid)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
keys, labels, err := templateColumns(template.TemplateInfo)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
file := excelize.NewFile()
|
|
sheet := file.GetSheetName(0)
|
|
for column, key := range keys {
|
|
cell, _ := excelize.CoordinatesToCellName(column+1, 1)
|
|
_ = file.SetCellValue(sheet, cell, labels[key])
|
|
}
|
|
buffer, err := file.WriteToBuffer()
|
|
_ = file.Close()
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
return buffer.Bytes(), template.Name + "_template.xlsx", nil
|
|
}
|
|
func (s *ExportService) Preview(ctx context.Context, tid string, params map[string]string) (string, error) {
|
|
template, err := s.uc.FindExportTemplate(ctx, 0, tid)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return s.uc.PreviewExport(ctx, template, params)
|
|
}
|
|
func (s *ExportService) Import(ctx context.Context, tid string, reader io.Reader) error {
|
|
template, err := s.uc.FindExportTemplate(ctx, 0, tid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
file, err := excelize.OpenReader(reader)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
rows, err := file.GetRows("Sheet1")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(rows) < 2 {
|
|
return errors.New("Excel data is not enough.\nIt should contain title row and data")
|
|
}
|
|
keys, labels, err := templateColumns(template.TemplateInfo)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
reverse := map[string]string{}
|
|
for _, key := range keys {
|
|
reverse[labels[key]] = key
|
|
}
|
|
headers := rows[0]
|
|
for index := range headers {
|
|
headers[index] = strings.TrimSpace(headers[index])
|
|
}
|
|
items := make([]map[string]any, 0, len(rows)-1)
|
|
for _, row := range rows[1:] {
|
|
item := map[string]any{}
|
|
for column, value := range row {
|
|
if column >= len(headers) {
|
|
continue
|
|
}
|
|
key := reverse[headers[column]]
|
|
if key != "" {
|
|
item[key] = value
|
|
}
|
|
}
|
|
items = append(items, item)
|
|
}
|
|
return s.uc.ImportExportRows(ctx, template, items)
|
|
}
|