- 新增 /customers/export、/sessions/export、/statistics/export - 沿用列表筛选与角色可见范围,UTF-8 BOM 便于 Excel 打开 - 前端三处导出按钮接入真实下载
71 lines
1.3 KiB
Go
71 lines
1.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
const exportMaxRows = 5000
|
|
|
|
func csvEscape(s string) string {
|
|
return strings.ReplaceAll(s, "\r\n", " ")
|
|
}
|
|
|
|
func writeCSVResponse(c *gin.Context, filename string, header []string, rows [][]string) {
|
|
if !strings.HasSuffix(strings.ToLower(filename), ".csv") {
|
|
filename += ".csv"
|
|
}
|
|
// 兼容 Excel 中文:UTF-8 BOM
|
|
c.Header("Content-Type", "text/csv; charset=utf-8")
|
|
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename*=UTF-8''%s", url.PathEscape(filename)))
|
|
c.Status(http.StatusOK)
|
|
|
|
if _, err := c.Writer.Write([]byte{0xEF, 0xBB, 0xBF}); err != nil {
|
|
return
|
|
}
|
|
w := csv.NewWriter(c.Writer)
|
|
_ = w.Write(header)
|
|
for _, row := range rows {
|
|
for i := range row {
|
|
row[i] = csvEscape(row[i])
|
|
}
|
|
_ = w.Write(row)
|
|
}
|
|
w.Flush()
|
|
}
|
|
|
|
func formatCSVTime(t time.Time) string {
|
|
if t.IsZero() {
|
|
return ""
|
|
}
|
|
return t.In(time.Local).Format("2006-01-02 15:04:05")
|
|
}
|
|
|
|
func formatCSVTimePtr(t *time.Time) string {
|
|
if t == nil {
|
|
return ""
|
|
}
|
|
return formatCSVTime(*t)
|
|
}
|
|
|
|
func formatUintPtr(v *uint) string {
|
|
if v == nil {
|
|
return ""
|
|
}
|
|
return strconv.FormatUint(uint64(*v), 10)
|
|
}
|
|
|
|
func formatIntPtr(v *int) string {
|
|
if v == nil {
|
|
return ""
|
|
}
|
|
return strconv.Itoa(*v)
|
|
}
|