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