1 Commits

Author SHA1 Message Date
e3d9bbbcc5 调整Excel导出时使用的方法 2025-12-28 12:15:37 +08:00
4 changed files with 142 additions and 66 deletions

View File

@@ -13,6 +13,7 @@ Excel导出工具提供了将数据导出到Excel文件的功能支持结构
- **自定义格式化**:支持自定义字段值的格式化函数 - **自定义格式化**:支持自定义字段值的格式化函数
- **自动列宽**:自动调整列宽以适应内容 - **自动列宽**:自动调整列宽以适应内容
- **表头样式**:自动应用表头样式(加粗、背景色等) - **表头样式**:自动应用表头样式(加粗、背景色等)
- **智能工作表管理**自动处理工作表的创建和删除避免产生空sheet
- **ExportData接口**支持实现ExportData接口进行高级定制 - **ExportData接口**支持实现ExportData接口进行高级定制
## 使用方法 ## 使用方法
@@ -114,7 +115,7 @@ columns := []factory.ExportColumn{
Header: "创建时间", Header: "创建时间",
Field: "CreatedAt", Field: "CreatedAt",
Width: 20, Width: 20,
Format: excel.FormatDateTimeDefault, // 使用便捷的格式化函数 Format: excel.AdaptTimeFormatter(tools.FormatDateTime), // 使用适配器直接调用tools函数
}, },
{ {
Header: "状态", Header: "状态",
@@ -215,8 +216,18 @@ file.SetCellStyle("Sheet2", "A1", "A1", style)
**返回:** 错误信息 **返回:** 错误信息
**工作表处理逻辑:**
- 如果 `sheetName` 为空或未指定,默认使用 "Sheet1"
- 如果指定的工作表已存在,直接使用该工作表
- 如果指定的工作表不存在,会自动创建新工作表
- 如果使用自定义名称(非"Sheet1"),会自动删除默认的"Sheet1"工作表避免产生空sheet
**示例:** **示例:**
```go ```go
// 使用默认Sheet1
fac.ExportToExcel(w, "", columns, users)
// 使用自定义工作表名称
fac.ExportToExcel(w, "用户列表", columns, users) fac.ExportToExcel(w, "用户列表", columns, users)
``` ```
@@ -232,8 +243,18 @@ fac.ExportToExcel(w, "用户列表", columns, users)
**返回:** 错误信息 **返回:** 错误信息
**工作表处理逻辑:**
- 如果 `sheetName` 为空或未指定,默认使用 "Sheet1"
- 如果指定的工作表已存在,直接使用该工作表
- 如果指定的工作表不存在,会自动创建新工作表
- 如果使用自定义名称(非"Sheet1"),会自动删除默认的"Sheet1"工作表避免产生空sheet
**示例:** **示例:**
```go ```go
// 使用默认Sheet1
fac.ExportToExcelFile("users.xlsx", "", columns, users)
// 使用自定义工作表名称
fac.ExportToExcelFile("users.xlsx", "用户列表", columns, users) fac.ExportToExcelFile("users.xlsx", "用户列表", columns, users)
``` ```
@@ -270,38 +291,42 @@ type ExportColumn struct {
- `Width`: 列宽0表示自动调整 - `Width`: 列宽0表示自动调整
- `Format`: 格式化函数,用于自定义字段值的显示格式 - `Format`: 格式化函数,用于自定义字段值的显示格式
### 便捷函数 ### 格式化函数适配器
#### excel.FormatDateTime(layout string) func(interface{}) string #### excel.AdaptTimeFormatter(fn func(time.Time, ...string) string) func(interface{}) string
创建日期时间格式化函数 适配器函数将tools包的格式化函数转换为Excel Format字段需要的函数类型
**参数:** **参数:**
- `layout`: 时间格式,如 "2006-01-02 15:04:05" - `fn`: tools包的格式化函数`tools.FormatDate``tools.FormatDateTime` 等)
**返回:** 格式化函数 **返回:** Excel Format字段需要的格式化函数
**说明:**
- 允许直接使用tools包的任何格式化函数
- 推荐使用此适配器,避免重复实现格式化逻辑
- 与factory中的FormatDateTime等方法保持一致
**示例:** **示例:**
```go ```go
Format: excel.FormatDateTime("2006-01-02 15:04:05") import (
``` "git.toowon.com/jimmy/go-common/excel"
"git.toowon.com/jimmy/go-common/tools"
)
#### excel.FormatDate(value interface{}) string // 使用tools.FormatDate
Format: excel.AdaptTimeFormatter(tools.FormatDate)
格式化日期格式2006-01-02 // 使用tools.FormatDateTime
Format: excel.AdaptTimeFormatter(tools.FormatDateTime)
**示例:** // 使用tools.FormatTime
```go Format: excel.AdaptTimeFormatter(tools.FormatTime)
Format: excel.FormatDate
```
#### excel.FormatDateTimeDefault(value interface{}) string // 使用自定义格式化函数
Format: excel.AdaptTimeFormatter(func(t time.Time) string {
格式化日期时间格式2006-01-02 15:04:05 return tools.Format(t, "2006-01-02 15:04:05", "Asia/Shanghai")
})
**示例:**
```go
Format: excel.FormatDateTimeDefault
``` ```
### ExportData接口 ### ExportData接口
@@ -356,7 +381,7 @@ func exportUsersHandler(w http.ResponseWriter, r *http.Request) {
Header: "创建时间", Header: "创建时间",
Field: "CreatedAt", Field: "CreatedAt",
Width: 20, Width: 20,
Format: excel.FormatDateTimeDefault, Format: excel.AdaptTimeFormatter(tools.FormatDateTime),
}, },
{ {
Header: "状态", Header: "状态",
@@ -411,6 +436,10 @@ func main() {
5. **嵌套字段**:支持嵌套字段访问(如 "User.Name"),但需要确保字段路径正确 5. **嵌套字段**:支持嵌套字段访问(如 "User.Name"),但需要确保字段路径正确
6. **格式化函数**格式化函数返回的字符串会直接写入Excel单元格 6. **格式化函数**格式化函数返回的字符串会直接写入Excel单元格
7. **列宽设置**Width为0时会自动调整列宽但可能影响性能大数据量时建议设置固定宽度 7. **列宽设置**Width为0时会自动调整列宽但可能影响性能大数据量时建议设置固定宽度
8. **工作表处理**
- 使用默认"Sheet1"时会直接使用默认工作表不会产生空sheet
- 使用自定义工作表名称时,会自动删除默认的"Sheet1",确保文件只有一个工作表
- 如果指定的工作表已存在,会直接使用,不会重复创建
## 最佳实践 ## 最佳实践
@@ -419,6 +448,10 @@ func main() {
3. **使用格式化函数**:对于日期时间、状态等字段,使用格式化函数提高可读性 3. **使用格式化函数**:对于日期时间、状态等字段,使用格式化函数提高可读性
4. **错误处理**:始终检查导出方法的返回值 4. **错误处理**:始终检查导出方法的返回值
5. **HTTP响应**导出到HTTP响应时记得设置正确的Content-Type和Content-Disposition头 5. **HTTP响应**导出到HTTP响应时记得设置正确的Content-Type和Content-Disposition头
6. **工作表命名**
- 推荐使用有意义的工作表名称(如"用户列表"、"订单数据"等),提高可读性
- 如果不指定工作表名称,会使用默认的"Sheet1"
- 工具会自动处理工作表的创建和删除确保不会产生空sheet
## 示例 ## 示例

View File

@@ -179,7 +179,7 @@ columns := []factory.ExportColumn{
Header: "创建时间", Header: "创建时间",
Field: "CreatedAt", Field: "CreatedAt",
Width: 20, Width: 20,
Format: excel.FormatDateTimeDefault, Format: excel.AdaptTimeFormatter(tools.FormatDateTime),
}, },
} }

View File

@@ -8,6 +8,7 @@ import (
"git.toowon.com/jimmy/go-common/excel" "git.toowon.com/jimmy/go-common/excel"
"git.toowon.com/jimmy/go-common/factory" "git.toowon.com/jimmy/go-common/factory"
"git.toowon.com/jimmy/go-common/tools"
) )
// User 用户结构体示例 // User 用户结构体示例
@@ -111,7 +112,7 @@ func example3(fac *factory.Factory) {
Header: "创建时间", Header: "创建时间",
Field: "CreatedAt", Field: "CreatedAt",
Width: 20, Width: 20,
Format: excel.FormatDateTimeDefault, // 使用便捷的格式化函数 Format: excel.AdaptTimeFormatter(tools.FormatDateTime), // 使用适配器直接调用tools函数
}, },
{ {
Header: "状态", Header: "状态",
@@ -174,7 +175,7 @@ func (d *UserExportData) GetExportColumns() []excel.ExportColumn {
Header: "创建时间", Header: "创建时间",
Field: "CreatedAt", Field: "CreatedAt",
Width: 20, Width: 20,
Format: excel.FormatDateTimeDefault, Format: excel.AdaptTimeFormatter(tools.FormatDateTime),
}, },
{ {
Header: "状态", Header: "状态",
@@ -230,4 +231,3 @@ func (w *mockResponseWriter) Write(data []byte) (int, error) {
func (w *mockResponseWriter) WriteHeader(statusCode int) { func (w *mockResponseWriter) WriteHeader(statusCode int) {
// 模拟实现 // 模拟实现
} }

View File

@@ -6,6 +6,7 @@ import (
"reflect" "reflect"
"time" "time"
"git.toowon.com/jimmy/go-common/tools"
"github.com/xuri/excelize/v2" "github.com/xuri/excelize/v2"
) )
@@ -94,11 +95,17 @@ func (e *Excel) ExportToWriter(w io.Writer, sheetName string, columns []ExportCo
sheetName = "Sheet1" sheetName = "Sheet1"
} }
// 删除默认工作表(如果存在 // 检查工作表是否已存在
index, err := e.file.GetSheetIndex("Sheet1") sheetIndex, err := e.file.GetSheetIndex(sheetName)
if err == nil && index > 0 { if err != nil || sheetIndex == 0 {
// 工作表不存在,需要创建
// 如果sheetName不是"Sheet1",且默认"Sheet1"存在,则删除它
if sheetName != "Sheet1" {
defaultIndex, _ := e.file.GetSheetIndex("Sheet1")
if defaultIndex > 0 {
e.file.DeleteSheet("Sheet1") e.file.DeleteSheet("Sheet1")
} }
}
// 创建新工作表 // 创建新工作表
_, err = e.file.NewSheet(sheetName) _, err = e.file.NewSheet(sheetName)
@@ -106,9 +113,15 @@ func (e *Excel) ExportToWriter(w io.Writer, sheetName string, columns []ExportCo
return fmt.Errorf("failed to create sheet: %w", err) return fmt.Errorf("failed to create sheet: %w", err)
} }
// 重新获取工作表索引
sheetIndex, err = e.file.GetSheetIndex(sheetName)
if err != nil {
return fmt.Errorf("failed to get sheet index: %w", err)
}
}
// 设置活动工作表 // 设置活动工作表
sheetIndex, err := e.file.GetSheetIndex(sheetName) if sheetIndex > 0 {
if err == nil && sheetIndex > 0 {
e.file.SetActiveSheet(sheetIndex) e.file.SetActiveSheet(sheetIndex)
} }
@@ -210,11 +223,17 @@ func (e *Excel) ExportToFile(filePath string, sheetName string, columns []Export
sheetName = "Sheet1" sheetName = "Sheet1"
} }
// 删除默认工作表(如果存在 // 检查工作表是否已存在
index, err := e.file.GetSheetIndex("Sheet1") sheetIndex, err := e.file.GetSheetIndex(sheetName)
if err == nil && index > 0 { if err != nil || sheetIndex == 0 {
// 工作表不存在,需要创建
// 如果sheetName不是"Sheet1",且默认"Sheet1"存在,则删除它
if sheetName != "Sheet1" {
defaultIndex, _ := e.file.GetSheetIndex("Sheet1")
if defaultIndex > 0 {
e.file.DeleteSheet("Sheet1") e.file.DeleteSheet("Sheet1")
} }
}
// 创建新工作表 // 创建新工作表
_, err = e.file.NewSheet(sheetName) _, err = e.file.NewSheet(sheetName)
@@ -222,9 +241,15 @@ func (e *Excel) ExportToFile(filePath string, sheetName string, columns []Export
return fmt.Errorf("failed to create sheet: %w", err) return fmt.Errorf("failed to create sheet: %w", err)
} }
// 重新获取工作表索引
sheetIndex, err = e.file.GetSheetIndex(sheetName)
if err != nil {
return fmt.Errorf("failed to get sheet index: %w", err)
}
}
// 设置活动工作表 // 设置活动工作表
sheetIndex, err := e.file.GetSheetIndex(sheetName) if sheetIndex > 0 {
if err == nil && sheetIndex > 0 {
e.file.SetActiveSheet(sheetIndex) e.file.SetActiveSheet(sheetIndex)
} }
@@ -451,31 +476,49 @@ func (e *Excel) getColumnMaxWidth(sheetName string, colIndex int, maxRow int) fl
return maxWidth return maxWidth
} }
// FormatDateTime 格式化日期时间(便捷函数) // AdaptTimeFormatter 适配器函数将tools包的格式化函数转换为Excel Format字段需要的函数类型
// 用于ExportColumn的Format字段 // 允许直接使用tools包的任何格式化函数
func FormatDateTime(layout string) func(interface{}) string { //
// 示例:
//
// // 直接使用tools.FormatDate
// Format: excel.AdaptTimeFormatter(tools.FormatDate)
//
// // 使用自定义格式化函数
// Format: excel.AdaptTimeFormatter(func(t time.Time) string {
// return tools.Format(t, "2006-01-02 15:04:05", "Asia/Shanghai")
// })
func AdaptTimeFormatter(fn func(time.Time, ...string) string) func(interface{}) string {
return func(value interface{}) string { return func(value interface{}) string {
if t, ok := value.(time.Time); ok { if t, ok := value.(time.Time); ok {
return t.Format(layout) return fn(t)
} }
return "" return ""
} }
} }
// FormatDate 格式化日期便捷函数) // formatDateTime 格式化日期时间(内部便捷函数)
// 用于ExportColumn的Format字段
// layout: 时间格式,如 "2006-01-02 15:04:05"
// timezone: 可选时区,如果为空则使用时间对象本身的时区
// 直接调用 tools.Format() 方法
func formatDateTime(layout string, timezone ...string) func(interface{}) string {
return AdaptTimeFormatter(func(t time.Time, _ ...string) string {
return tools.Format(t, layout, timezone...)
})
}
// formatDate 格式化日期(内部便捷函数)
// 用于ExportColumn的Format字段格式2006-01-02 // 用于ExportColumn的Format字段格式2006-01-02
func FormatDate(value interface{}) string { // 直接调用 tools.FormatDate() 方法
if t, ok := value.(time.Time); ok { var formatDate = AdaptTimeFormatter(tools.FormatDate)
return t.Format("2006-01-02")
}
return ""
}
// FormatDateTimeDefault 格式化日期时间(便捷函数) // formatDateTimeDefault 格式化日期时间(内部便捷函数)
// 用于ExportColumn的Format字段格式2006-01-02 15:04:05 // 用于ExportColumn的Format字段格式2006-01-02 15:04:05
func FormatDateTimeDefault(value interface{}) string { // 直接调用 tools.FormatDateTime() 方法
if t, ok := value.(time.Time); ok { var formatDateTimeDefault = AdaptTimeFormatter(tools.FormatDateTime)
return t.Format("2006-01-02 15:04:05")
} // formatTime 格式化时间(内部便捷函数)
return "" // 用于ExportColumn的Format字段格式15:04:05
} // 直接调用 tools.FormatTime() 方法
var formatTime = AdaptTimeFormatter(tools.FormatTime)