2025-11-23 22:49:46 +07:00

100 lines
2.2 KiB
Go

// internal/utils/excel_export.go
package utils
import (
"bytes"
"fmt"
"github.com/xuri/excelize/v2"
)
// ExcelExporter handles Excel file generation
type ExcelExporter struct {
file *excelize.File
sheetName string
rowIndex int
}
// NewExcelExporter creates a new Excel exporter
func NewExcelExporter() *ExcelExporter {
f := excelize.NewFile()
return &ExcelExporter{
file: f,
sheetName: "Sheet1",
rowIndex: 1,
}
}
// SetSheetName sets the active sheet name
func (e *ExcelExporter) SetSheetName(name string) {
e.file.SetSheetName("Sheet1", name)
e.sheetName = name
}
// AddRow adds a row of data
func (e *ExcelExporter) AddRow(data []string) error {
for colIndex, value := range data {
cell := fmt.Sprintf("%s%d", getColumnName(colIndex), e.rowIndex)
if err := e.file.SetCellValue(e.sheetName, cell, value); err != nil {
return err
}
}
e.rowIndex++
return nil
}
// AddHeader adds a header row with bold style
func (e *ExcelExporter) AddHeader(headers []string) error {
style, err := e.file.NewStyle(&excelize.Style{
Font: &excelize.Font{
Bold: true,
},
Fill: excelize.Fill{
Type: "pattern",
Color: []string{"#D3D3D3"},
Pattern: 1,
},
})
if err != nil {
return err
}
for colIndex, header := range headers {
cell := fmt.Sprintf("%s%d", getColumnName(colIndex), e.rowIndex)
if err := e.file.SetCellValue(e.sheetName, cell, header); err != nil {
return err
}
if err := e.file.SetCellStyle(e.sheetName, cell, cell, style); err != nil {
return err
}
}
e.rowIndex++
return nil
}
// AutoSizeColumns auto-sizes columns
func (e *ExcelExporter) AutoSizeColumns(columnCount int) {
for i := 0; i < columnCount; i++ {
col := getColumnName(i)
e.file.SetColWidth(e.sheetName, col, col, 15)
}
}
// Output returns the Excel file as bytes
func (e *ExcelExporter) Output() (*bytes.Buffer, error) {
buf := new(bytes.Buffer)
if err := e.file.Write(buf); err != nil {
return nil, err
}
return buf, nil
}
// getColumnName converts column index to Excel column name (A, B, C, ..., AA, AB, ...)
func getColumnName(index int) string {
name := ""
for index >= 0 {
name = string(rune('A'+(index%26))) + name
index = index/26 - 1
}
return name
}