1、更新
This commit is contained in:
@ -18,6 +18,11 @@ const (
|
||||
MachineKeywords = "m_keywords:%s"
|
||||
)
|
||||
|
||||
const (
|
||||
//设备重启缓存 {machineId}
|
||||
RebootMachine = "reboot_machine:%s"
|
||||
)
|
||||
|
||||
const (
|
||||
//系统配置缓存
|
||||
Config = "config:%s"
|
||||
|
||||
168
common/helper/excel_helper.go
Normal file
168
common/helper/excel_helper.go
Normal file
@ -0,0 +1,168 @@
|
||||
package helper
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/xuri/excelize/v2"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
/*
|
||||
导出csv文件
|
||||
|
||||
- @fileName 文件名 不带拓展名
|
||||
- @header 文件头
|
||||
- @records 内容
|
||||
*/
|
||||
func ExportCSV(c *gin.Context, fileName string, header []string, records [][]string) error {
|
||||
disposition := fmt.Sprintf("attachment; filename=%s.csv", fileName)
|
||||
|
||||
// Set headers
|
||||
c.Header("Content-Description", "File Transfer")
|
||||
c.Header("Content-Disposition", disposition)
|
||||
c.Header("Content-Type", "text/csv")
|
||||
|
||||
// Create a CSV writer using the response writer
|
||||
writer := csv.NewWriter(c.Writer)
|
||||
defer writer.Flush()
|
||||
|
||||
// Write CSV header
|
||||
writer.Write(header)
|
||||
|
||||
for _, record := range records {
|
||||
writer.Write(record)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
导出excel
|
||||
|
||||
- @fileName 文件名称
|
||||
- @data 数据源
|
||||
- @ingore 忽略header
|
||||
*/
|
||||
func ExportExcel[T any](c *gin.Context, fileName string, data []T, ingore []string) error {
|
||||
if len(data) == 0 {
|
||||
return errors.New("无导出记录")
|
||||
}
|
||||
// Create a new Excel file
|
||||
f := excelize.NewFile()
|
||||
// Use reflection to get the header from struct tags
|
||||
t := reflect.TypeOf(data[0])
|
||||
headers := []string{}
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
excelTag := field.Tag.Get("excel")
|
||||
if excelTag != "" && !ArrayAny(ingore, excelTag) {
|
||||
headers = append(headers, excelTag)
|
||||
}
|
||||
}
|
||||
// Set headers
|
||||
for i, header := range headers {
|
||||
col := string('A' + i)
|
||||
cell := fmt.Sprintf("%s1", col)
|
||||
f.SetCellValue("Sheet1", cell, header)
|
||||
}
|
||||
|
||||
// Fill rows with data
|
||||
for rowIndex, item := range data {
|
||||
rowValue := reflect.ValueOf(item)
|
||||
rowType := rowValue.Type()
|
||||
for colIndex, header := range headers {
|
||||
col := string('A' + colIndex)
|
||||
cell := fmt.Sprintf("%s%d", col, rowIndex+2)
|
||||
var fieldValue reflect.Value
|
||||
|
||||
for i := 0; i < rowType.NumField(); i++ {
|
||||
field := rowType.Field(i)
|
||||
if strings.EqualFold(field.Tag.Get("excel"), header) {
|
||||
fieldValue = rowValue.Field(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the fieldValue is valid before accessing it
|
||||
if fieldValue.IsValid() && fieldValue.CanInterface() {
|
||||
//f.SetCellValue("Sheet1", cell, fieldValue.Interface())
|
||||
value := fieldValue.Interface()
|
||||
|
||||
// Ensure the value is a string, convert it if necessary
|
||||
var stringValue string
|
||||
if v, ok := value.(string); ok {
|
||||
stringValue = v // If it's a string, use it directly
|
||||
} else {
|
||||
stringValue = fmt.Sprintf("%v", value) // Otherwise, convert to string
|
||||
}
|
||||
f.SetCellValue("Sheet1", cell, stringValue)
|
||||
} else {
|
||||
// Handle the case where fieldValue is invalid or nil
|
||||
f.SetCellValue("Sheet1", cell, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set response headers and send the file to the client
|
||||
|
||||
// c.Writer.Header().Set("Content-Disposition", "attachment; filename=test.xlsx")
|
||||
// c.Writer.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=binary")
|
||||
// c.Writer.Header().Set("Content-Transfer-Encoding", "binary")
|
||||
// c.Writer.Header().Set("Expires", "0")
|
||||
// c.Writer.Header().Set("Cache-Control", "must-revalidate")
|
||||
// c.Writer.Header().Set("Pragma", "public")
|
||||
c.Header("Content-Description", "File Transfer")
|
||||
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s.xlsx", fileName))
|
||||
c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
c.Header("Content-Transfer-Encoding", "binary")
|
||||
c.Header("Expires", "0")
|
||||
c.Header("Cache-Control", "must-revalidate")
|
||||
c.Header("Pragma", "public")
|
||||
c.Header("Content-Encoding", "")
|
||||
//fmt.Println("c.Writer.Header():", c.Writer.Header())
|
||||
if _, err := f.WriteTo(c.Writer); err != nil {
|
||||
log.Println("Error writing file:", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
//return f.WriteTo(c.Writer)
|
||||
}
|
||||
|
||||
func MapExcelToStruct[T any](rows [][]string, headers []string) ([]T, error) {
|
||||
var results []T
|
||||
if len(rows) == 0 {
|
||||
return results, nil
|
||||
}
|
||||
|
||||
for _, row := range rows {
|
||||
var result T
|
||||
v := reflect.ValueOf(&result).Elem()
|
||||
|
||||
for i, header := range headers {
|
||||
fieldName := ""
|
||||
for j := 0; j < v.NumField(); j++ {
|
||||
field := v.Type().Field(j)
|
||||
tag := field.Tag.Get("excel")
|
||||
if strings.EqualFold(tag, header) {
|
||||
fieldName = field.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if fieldName != "" && i < len(row) {
|
||||
field := v.FieldByName(fieldName)
|
||||
if field.IsValid() && field.CanSet() {
|
||||
field.Set(reflect.ValueOf(row[i]).Convert(field.Type()))
|
||||
}
|
||||
}
|
||||
}
|
||||
results = append(results, result)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
52
common/helper/extension_helper.go
Normal file
52
common/helper/extension_helper.go
Normal file
@ -0,0 +1,52 @@
|
||||
package helper
|
||||
|
||||
/*
|
||||
判断是否存在
|
||||
|
||||
- @arr 数组
|
||||
- @value 值
|
||||
*/
|
||||
func ArrayAny[T comparable](arr []T, value T) bool {
|
||||
for _, v := range arr {
|
||||
if v == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 定义一个条件函数类型
|
||||
type ConditionFunc[T any] func(T) bool
|
||||
|
||||
/*
|
||||
判断是否存在
|
||||
|
||||
- @arr 数组
|
||||
|
||||
- @condition 判断函数
|
||||
|
||||
@return 对象指针
|
||||
*/
|
||||
func ArrayAnyExtension[T any](arr *[]T, condition ConditionFunc[T]) *T {
|
||||
for _, v := range *arr {
|
||||
if condition(v) {
|
||||
return &v
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func RemoveDuplicates(nums []int64) []int64 {
|
||||
m := make(map[int64]bool)
|
||||
result := []int64{}
|
||||
|
||||
for _, num := range nums {
|
||||
if !m[num] {
|
||||
m[num] = true
|
||||
result = append(result, num)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user