213 lines
5.6 KiB
Go
213 lines
5.6 KiB
Go
package excelhelper
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"errors"
|
|
"fmt"
|
|
helper "go-admin/utils"
|
|
"log"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/xuri/excelize/v2"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
/*
|
|
导出csv文件
|
|
|
|
- @fileName 文件名 不带拓展名
|
|
- @header 文件头
|
|
- @records 内容
|
|
*/
|
|
func ExportCSV(c *gin.Context, fileName string, header []string, records [][]string) error {
|
|
disposition := fmt.Sprintf("attachment; filename=%s.csv", fileName)
|
|
|
|
// Set headers
|
|
c.Header("Content-Description", "File Transfer")
|
|
c.Header("Content-Disposition", disposition)
|
|
c.Header("Content-Type", "text/csv")
|
|
|
|
// Create a CSV writer using the response writer
|
|
writer := csv.NewWriter(c.Writer)
|
|
defer writer.Flush()
|
|
|
|
// Write CSV header
|
|
writer.Write(header)
|
|
|
|
for _, record := range records {
|
|
writer.Write(record)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
/*
|
|
导出excel
|
|
|
|
- @fileName 文件名称
|
|
- @data 数据源
|
|
- @ingore 忽略header
|
|
*/
|
|
func ExportExcel[T any](c *gin.Context, fileName string, data []T, ingore []string) error {
|
|
if len(data) == 0 {
|
|
return errors.New("无导出记录")
|
|
}
|
|
// Create a new Excel file
|
|
f := excelize.NewFile()
|
|
// Use reflection to get the header from struct tags
|
|
t := reflect.TypeOf(data[0])
|
|
headers := []string{}
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
excelTag := field.Tag.Get("excel")
|
|
if excelTag != "" && !helper.ArrayAny(ingore, excelTag) {
|
|
headers = append(headers, excelTag)
|
|
}
|
|
}
|
|
// Set headers
|
|
for i, header := range headers {
|
|
col := string('A' + i)
|
|
cell := fmt.Sprintf("%s1", col)
|
|
f.SetCellValue("Sheet1", cell, header)
|
|
}
|
|
|
|
// Fill rows with data
|
|
for rowIndex, item := range data {
|
|
rowValue := reflect.ValueOf(item)
|
|
rowType := rowValue.Type()
|
|
for colIndex, header := range headers {
|
|
col := string('A' + colIndex)
|
|
cell := fmt.Sprintf("%s%d", col, rowIndex+2)
|
|
var fieldValue reflect.Value
|
|
|
|
for i := 0; i < rowType.NumField(); i++ {
|
|
field := rowType.Field(i)
|
|
if strings.EqualFold(field.Tag.Get("excel"), header) {
|
|
fieldValue = rowValue.Field(i)
|
|
break
|
|
}
|
|
}
|
|
|
|
// Check if the fieldValue is valid before accessing it
|
|
if fieldValue.IsValid() && fieldValue.CanInterface() {
|
|
//f.SetCellValue("Sheet1", cell, fieldValue.Interface())
|
|
value := fieldValue.Interface()
|
|
|
|
// Ensure the value is a string, convert it if necessary
|
|
var stringValue string
|
|
if v, ok := value.(string); ok {
|
|
stringValue = v // If it's a string, use it directly
|
|
} else {
|
|
stringValue = fmt.Sprintf("%v", value) // Otherwise, convert to string
|
|
}
|
|
f.SetCellValue("Sheet1", cell, stringValue)
|
|
} else {
|
|
// Handle the case where fieldValue is invalid or nil
|
|
f.SetCellValue("Sheet1", cell, "")
|
|
}
|
|
}
|
|
}
|
|
// Set response headers and send the file to the client
|
|
|
|
// c.Writer.Header().Set("Content-Disposition", "attachment; filename=test.xlsx")
|
|
// c.Writer.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=binary")
|
|
// c.Writer.Header().Set("Content-Transfer-Encoding", "binary")
|
|
// c.Writer.Header().Set("Expires", "0")
|
|
// c.Writer.Header().Set("Cache-Control", "must-revalidate")
|
|
// c.Writer.Header().Set("Pragma", "public")
|
|
c.Header("Content-Description", "File Transfer")
|
|
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s.xlsx", fileName))
|
|
c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
|
c.Header("Content-Transfer-Encoding", "binary")
|
|
c.Header("Expires", "0")
|
|
c.Header("Cache-Control", "must-revalidate")
|
|
c.Header("Pragma", "public")
|
|
c.Header("Content-Encoding", "")
|
|
//fmt.Println("c.Writer.Header():", c.Writer.Header())
|
|
if _, err := f.WriteTo(c.Writer); err != nil {
|
|
log.Println("Error writing file:", err)
|
|
return err
|
|
}
|
|
return nil
|
|
//return f.WriteTo(c.Writer)
|
|
}
|
|
|
|
func MapExcelToStruct[T any](rows [][]string, headers []string) ([]T, error) {
|
|
var results []T
|
|
if len(rows) == 0 {
|
|
return results, nil
|
|
}
|
|
|
|
for _, row := range rows {
|
|
var result T
|
|
v := reflect.ValueOf(&result).Elem()
|
|
|
|
for i, header := range headers {
|
|
fieldName := ""
|
|
for j := 0; j < v.NumField(); j++ {
|
|
field := v.Type().Field(j)
|
|
tag := field.Tag.Get("excel")
|
|
if strings.EqualFold(tag, header) {
|
|
fieldName = field.Name
|
|
break
|
|
}
|
|
}
|
|
|
|
if fieldName != "" && i < len(row) {
|
|
field := v.FieldByName(fieldName)
|
|
if field.IsValid() && field.CanSet() {
|
|
field.Set(reflect.ValueOf(row[i]).Convert(field.Type()))
|
|
}
|
|
}
|
|
}
|
|
results = append(results, result)
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
// 获取上传文件的数据
|
|
func GetExcelContent(c *gin.Context) (dataRows [][]string, headers []string, err error) {
|
|
// 获取上传的文件
|
|
file, err := c.FormFile("file")
|
|
if err != nil {
|
|
err = errors.New("文件上传失败")
|
|
return
|
|
}
|
|
|
|
// 打开上传的文件
|
|
src, err := file.Open()
|
|
if err != nil {
|
|
err = errors.New("文件打开失败")
|
|
return
|
|
}
|
|
defer src.Close()
|
|
|
|
// 使用 excelize 读取 Excel 文件
|
|
xlFile, err := excelize.OpenReader(src)
|
|
if err != nil {
|
|
err = errors.New("读取 Excel 文件失败")
|
|
return
|
|
}
|
|
|
|
sheetName := xlFile.GetSheetName(0)
|
|
|
|
// 假设读取第一个工作表中的数据
|
|
rows, err := xlFile.GetRows(sheetName)
|
|
if err != nil {
|
|
err = errors.New("读取 Excel 行数据失败")
|
|
return
|
|
}
|
|
|
|
if len(rows) < 1 {
|
|
err = errors.New("没有数据内容")
|
|
return
|
|
}
|
|
|
|
headers = rows[0] // First row is the header
|
|
dataRows = rows[1:]
|
|
return
|
|
}
|