This commit is contained in:
2025-09-12 01:15:09 +08:00
parent c563b2266b
commit e05ad9e223
103 changed files with 20034 additions and 1041 deletions

View File

@@ -0,0 +1,133 @@
package export
import (
"context"
"fmt"
"strings"
"github.com/xuri/excelize/v2"
"go.uber.org/zap"
)
// ExportConfig 定义了导出所需的配置
type ExportConfig struct {
SheetName string // 工作表名称
Headers []string // 表头
Data [][]interface{} // 导出数据
ColumnWidths []float64 // 列宽
}
// ExportManager 负责管理不同格式的导出
type ExportManager struct {
logger *zap.Logger
}
// NewExportManager 创建一个新的ExportManager
func NewExportManager(logger *zap.Logger) *ExportManager {
return &ExportManager{
logger: logger,
}
}
// Export 根据配置和格式生成导出文件
func (m *ExportManager) Export(ctx context.Context, config *ExportConfig, format string) ([]byte, error) {
switch format {
case "excel":
return m.generateExcel(ctx, config)
case "csv":
return m.generateCSV(ctx, config)
default:
return nil, fmt.Errorf("不支持的导出格式: %s", format)
}
}
// generateExcel 生成Excel导出文件
func (m *ExportManager) generateExcel(ctx context.Context, config *ExportConfig) ([]byte, error) {
f := excelize.NewFile()
defer func() {
if err := f.Close(); err != nil {
m.logger.Error("关闭Excel文件失败", zap.Error(err))
}
}()
sheetName := config.SheetName
index, err := f.NewSheet(sheetName)
if err != nil {
return nil, err
}
f.SetActiveSheet(index)
// 设置表头
for i, header := range config.Headers {
cell, err := excelize.CoordinatesToCellName(i+1, 1)
if err != nil {
return nil, fmt.Errorf("生成表头单元格坐标失败: %v", err)
}
f.SetCellValue(sheetName, cell, header)
}
// 设置表头样式
headerStyle, err := f.NewStyle(&excelize.Style{
Font: &excelize.Font{Bold: true},
Fill: excelize.Fill{Type: "pattern", Color: []string{"#E6F3FF"}, Pattern: 1},
})
if err != nil {
return nil, err
}
// 计算表头范围
lastCol, err := excelize.CoordinatesToCellName(len(config.Headers), 1)
if err != nil {
return nil, fmt.Errorf("生成表头范围失败: %v", err)
}
headerRange := fmt.Sprintf("A1:%s", lastCol)
f.SetCellStyle(sheetName, headerRange, headerRange, headerStyle)
// 批量写入数据
for i, rowData := range config.Data {
row := i + 2 // 从第2行开始写入数据
for j, value := range rowData {
cell, err := excelize.CoordinatesToCellName(j+1, row)
if err != nil {
return nil, fmt.Errorf("生成数据单元格坐标失败: %v", err)
}
f.SetCellValue(sheetName, cell, value)
}
}
// 设置列宽
for i, width := range config.ColumnWidths {
col, err := excelize.ColumnNumberToName(i + 1)
if err != nil {
return nil, fmt.Errorf("生成列名失败: %v", err)
}
f.SetColWidth(sheetName, col, col, width)
}
buf, err := f.WriteToBuffer()
if err != nil {
return nil, err
}
m.logger.Info("Excel文件生成完成", zap.Int("file_size", len(buf.Bytes())))
return buf.Bytes(), nil
}
// generateCSV 生成CSV导出文件
func (m *ExportManager) generateCSV(ctx context.Context, config *ExportConfig) ([]byte, error) {
var csvData strings.Builder
// 写入CSV头部
csvData.WriteString(strings.Join(config.Headers, ",") + "\n")
// 写入数据行
for _, rowData := range config.Data {
rowStrings := make([]string, len(rowData))
for i, value := range rowData {
rowStrings[i] = fmt.Sprintf("%v", value) // 使用%v通用格式化
}
csvData.WriteString(strings.Join(rowStrings, ",") + "\n")
}
return []byte(csvData.String()), nil
}