Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e3d9bbbcc5 |
@@ -13,6 +13,7 @@ Excel导出工具提供了将数据导出到Excel文件的功能,支持结构
|
||||
- **自定义格式化**:支持自定义字段值的格式化函数
|
||||
- **自动列宽**:自动调整列宽以适应内容
|
||||
- **表头样式**:自动应用表头样式(加粗、背景色等)
|
||||
- **智能工作表管理**:自动处理工作表的创建和删除,避免产生空sheet
|
||||
- **ExportData接口**:支持实现ExportData接口进行高级定制
|
||||
|
||||
## 使用方法
|
||||
@@ -114,7 +115,7 @@ columns := []factory.ExportColumn{
|
||||
Header: "创建时间",
|
||||
Field: "CreatedAt",
|
||||
Width: 20,
|
||||
Format: excel.FormatDateTimeDefault, // 使用便捷的格式化函数
|
||||
Format: excel.AdaptTimeFormatter(tools.FormatDateTime), // 使用适配器直接调用tools函数
|
||||
},
|
||||
{
|
||||
Header: "状态",
|
||||
@@ -215,8 +216,18 @@ file.SetCellStyle("Sheet2", "A1", "A1", style)
|
||||
|
||||
**返回:** 错误信息
|
||||
|
||||
**工作表处理逻辑:**
|
||||
- 如果 `sheetName` 为空或未指定,默认使用 "Sheet1"
|
||||
- 如果指定的工作表已存在,直接使用该工作表
|
||||
- 如果指定的工作表不存在,会自动创建新工作表
|
||||
- 如果使用自定义名称(非"Sheet1"),会自动删除默认的"Sheet1"工作表,避免产生空sheet
|
||||
|
||||
**示例:**
|
||||
```go
|
||||
// 使用默认Sheet1
|
||||
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
|
||||
// 使用默认Sheet1
|
||||
fac.ExportToExcelFile("users.xlsx", "", columns, users)
|
||||
|
||||
// 使用自定义工作表名称
|
||||
fac.ExportToExcelFile("users.xlsx", "用户列表", columns, users)
|
||||
```
|
||||
|
||||
@@ -270,38 +291,42 @@ type ExportColumn struct {
|
||||
- `Width`: 列宽,0表示自动调整
|
||||
- `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
|
||||
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)
|
||||
|
||||
**示例:**
|
||||
```go
|
||||
Format: excel.FormatDate
|
||||
```
|
||||
// 使用tools.FormatTime
|
||||
Format: excel.AdaptTimeFormatter(tools.FormatTime)
|
||||
|
||||
#### excel.FormatDateTimeDefault(value interface{}) string
|
||||
|
||||
格式化日期时间(格式:2006-01-02 15:04:05)。
|
||||
|
||||
**示例:**
|
||||
```go
|
||||
Format: excel.FormatDateTimeDefault
|
||||
// 使用自定义格式化函数
|
||||
Format: excel.AdaptTimeFormatter(func(t time.Time) string {
|
||||
return tools.Format(t, "2006-01-02 15:04:05", "Asia/Shanghai")
|
||||
})
|
||||
```
|
||||
|
||||
### ExportData接口
|
||||
@@ -356,7 +381,7 @@ func exportUsersHandler(w http.ResponseWriter, r *http.Request) {
|
||||
Header: "创建时间",
|
||||
Field: "CreatedAt",
|
||||
Width: 20,
|
||||
Format: excel.FormatDateTimeDefault,
|
||||
Format: excel.AdaptTimeFormatter(tools.FormatDateTime),
|
||||
},
|
||||
{
|
||||
Header: "状态",
|
||||
@@ -411,6 +436,10 @@ func main() {
|
||||
5. **嵌套字段**:支持嵌套字段访问(如 "User.Name"),但需要确保字段路径正确
|
||||
6. **格式化函数**:格式化函数返回的字符串会直接写入Excel单元格
|
||||
7. **列宽设置**:Width为0时会自动调整列宽,但可能影响性能(大数据量时建议设置固定宽度)
|
||||
8. **工作表处理**:
|
||||
- 使用默认"Sheet1"时,会直接使用默认工作表,不会产生空sheet
|
||||
- 使用自定义工作表名称时,会自动删除默认的"Sheet1",确保文件只有一个工作表
|
||||
- 如果指定的工作表已存在,会直接使用,不会重复创建
|
||||
|
||||
## 最佳实践
|
||||
|
||||
@@ -419,6 +448,10 @@ func main() {
|
||||
3. **使用格式化函数**:对于日期时间、状态等字段,使用格式化函数提高可读性
|
||||
4. **错误处理**:始终检查导出方法的返回值
|
||||
5. **HTTP响应**:导出到HTTP响应时,记得设置正确的Content-Type和Content-Disposition头
|
||||
6. **工作表命名**:
|
||||
- 推荐使用有意义的工作表名称(如"用户列表"、"订单数据"等),提高可读性
|
||||
- 如果不指定工作表名称,会使用默认的"Sheet1"
|
||||
- 工具会自动处理工作表的创建和删除,确保不会产生空sheet
|
||||
|
||||
## 示例
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ columns := []factory.ExportColumn{
|
||||
Header: "创建时间",
|
||||
Field: "CreatedAt",
|
||||
Width: 20,
|
||||
Format: excel.FormatDateTimeDefault,
|
||||
Format: excel.AdaptTimeFormatter(tools.FormatDateTime),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"git.toowon.com/jimmy/go-common/excel"
|
||||
"git.toowon.com/jimmy/go-common/factory"
|
||||
"git.toowon.com/jimmy/go-common/tools"
|
||||
)
|
||||
|
||||
// User 用户结构体示例
|
||||
@@ -111,7 +112,7 @@ func example3(fac *factory.Factory) {
|
||||
Header: "创建时间",
|
||||
Field: "CreatedAt",
|
||||
Width: 20,
|
||||
Format: excel.FormatDateTimeDefault, // 使用便捷的格式化函数
|
||||
Format: excel.AdaptTimeFormatter(tools.FormatDateTime), // 使用适配器直接调用tools函数
|
||||
},
|
||||
{
|
||||
Header: "状态",
|
||||
@@ -174,7 +175,7 @@ func (d *UserExportData) GetExportColumns() []excel.ExportColumn {
|
||||
Header: "创建时间",
|
||||
Field: "CreatedAt",
|
||||
Width: 20,
|
||||
Format: excel.FormatDateTimeDefault,
|
||||
Format: excel.AdaptTimeFormatter(tools.FormatDateTime),
|
||||
},
|
||||
{
|
||||
Header: "状态",
|
||||
@@ -230,4 +231,3 @@ func (w *mockResponseWriter) Write(data []byte) (int, error) {
|
||||
func (w *mockResponseWriter) WriteHeader(statusCode int) {
|
||||
// 模拟实现
|
||||
}
|
||||
|
||||
|
||||
123
excel/excel.go
123
excel/excel.go
@@ -6,6 +6,7 @@ import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"git.toowon.com/jimmy/go-common/tools"
|
||||
"github.com/xuri/excelize/v2"
|
||||
)
|
||||
|
||||
@@ -94,21 +95,33 @@ func (e *Excel) ExportToWriter(w io.Writer, sheetName string, columns []ExportCo
|
||||
sheetName = "Sheet1"
|
||||
}
|
||||
|
||||
// 删除默认工作表(如果存在)
|
||||
index, err := e.file.GetSheetIndex("Sheet1")
|
||||
if err == nil && index > 0 {
|
||||
e.file.DeleteSheet("Sheet1")
|
||||
}
|
||||
// 检查工作表是否已存在
|
||||
sheetIndex, err := e.file.GetSheetIndex(sheetName)
|
||||
if err != nil || sheetIndex == 0 {
|
||||
// 工作表不存在,需要创建
|
||||
// 如果sheetName不是"Sheet1",且默认"Sheet1"存在,则删除它
|
||||
if sheetName != "Sheet1" {
|
||||
defaultIndex, _ := e.file.GetSheetIndex("Sheet1")
|
||||
if defaultIndex > 0 {
|
||||
e.file.DeleteSheet("Sheet1")
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新工作表
|
||||
_, err = e.file.NewSheet(sheetName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create sheet: %w", err)
|
||||
// 创建新工作表
|
||||
_, err = e.file.NewSheet(sheetName)
|
||||
if err != nil {
|
||||
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 err == nil && sheetIndex > 0 {
|
||||
if sheetIndex > 0 {
|
||||
e.file.SetActiveSheet(sheetIndex)
|
||||
}
|
||||
|
||||
@@ -210,21 +223,33 @@ func (e *Excel) ExportToFile(filePath string, sheetName string, columns []Export
|
||||
sheetName = "Sheet1"
|
||||
}
|
||||
|
||||
// 删除默认工作表(如果存在)
|
||||
index, err := e.file.GetSheetIndex("Sheet1")
|
||||
if err == nil && index > 0 {
|
||||
e.file.DeleteSheet("Sheet1")
|
||||
}
|
||||
// 检查工作表是否已存在
|
||||
sheetIndex, err := e.file.GetSheetIndex(sheetName)
|
||||
if err != nil || sheetIndex == 0 {
|
||||
// 工作表不存在,需要创建
|
||||
// 如果sheetName不是"Sheet1",且默认"Sheet1"存在,则删除它
|
||||
if sheetName != "Sheet1" {
|
||||
defaultIndex, _ := e.file.GetSheetIndex("Sheet1")
|
||||
if defaultIndex > 0 {
|
||||
e.file.DeleteSheet("Sheet1")
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新工作表
|
||||
_, err = e.file.NewSheet(sheetName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create sheet: %w", err)
|
||||
// 创建新工作表
|
||||
_, err = e.file.NewSheet(sheetName)
|
||||
if err != nil {
|
||||
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 err == nil && sheetIndex > 0 {
|
||||
if sheetIndex > 0 {
|
||||
e.file.SetActiveSheet(sheetIndex)
|
||||
}
|
||||
|
||||
@@ -451,31 +476,49 @@ func (e *Excel) getColumnMaxWidth(sheetName string, colIndex int, maxRow int) fl
|
||||
return maxWidth
|
||||
}
|
||||
|
||||
// FormatDateTime 格式化日期时间(便捷函数)
|
||||
// 用于ExportColumn的Format字段
|
||||
func FormatDateTime(layout string) func(interface{}) string {
|
||||
// AdaptTimeFormatter 适配器函数:将tools包的格式化函数转换为Excel Format字段需要的函数类型
|
||||
// 允许直接使用tools包的任何格式化函数
|
||||
//
|
||||
// 示例:
|
||||
//
|
||||
// // 直接使用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 {
|
||||
if t, ok := value.(time.Time); ok {
|
||||
return t.Format(layout)
|
||||
return fn(t)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// FormatDate 格式化日期(便捷函数)
|
||||
// 用于ExportColumn的Format字段,格式:2006-01-02
|
||||
func FormatDate(value interface{}) string {
|
||||
if t, ok := value.(time.Time); ok {
|
||||
return t.Format("2006-01-02")
|
||||
}
|
||||
return ""
|
||||
// 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...)
|
||||
})
|
||||
}
|
||||
|
||||
// FormatDateTimeDefault 格式化日期时间(便捷函数)
|
||||
// formatDate 格式化日期(内部便捷函数)
|
||||
// 用于ExportColumn的Format字段,格式:2006-01-02
|
||||
// 直接调用 tools.FormatDate() 方法
|
||||
var formatDate = AdaptTimeFormatter(tools.FormatDate)
|
||||
|
||||
// formatDateTimeDefault 格式化日期时间(内部便捷函数)
|
||||
// 用于ExportColumn的Format字段,格式:2006-01-02 15:04:05
|
||||
func FormatDateTimeDefault(value interface{}) string {
|
||||
if t, ok := value.(time.Time); ok {
|
||||
return t.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
// 直接调用 tools.FormatDateTime() 方法
|
||||
var formatDateTimeDefault = AdaptTimeFormatter(tools.FormatDateTime)
|
||||
|
||||
// formatTime 格式化时间(内部便捷函数)
|
||||
// 用于ExportColumn的Format字段,格式:15:04:05
|
||||
// 直接调用 tools.FormatTime() 方法
|
||||
var formatTime = AdaptTimeFormatter(tools.FormatTime)
|
||||
|
||||
Reference in New Issue
Block a user