复制项目
This commit is contained in:
115
pkg/common/xlsx/main.go
Normal file
115
pkg/common/xlsx/main.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package xlsx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/xuri/excelize/v2"
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func ParseSheet(file *excelize.File, v interface{}) error {
|
||||
val := reflect.ValueOf(v)
|
||||
if val.Kind() != reflect.Ptr {
|
||||
return errors.New("not ptr")
|
||||
}
|
||||
val = val.Elem()
|
||||
if val.Kind() != reflect.Slice {
|
||||
return errors.New("not slice")
|
||||
}
|
||||
itemType := val.Type().Elem()
|
||||
if itemType.Kind() != reflect.Struct {
|
||||
return errors.New("not struct")
|
||||
}
|
||||
newItemValue := func() reflect.Value {
|
||||
return reflect.New(itemType).Elem()
|
||||
}
|
||||
putItem := func(v reflect.Value) {
|
||||
val.Set(reflect.Append(val, v))
|
||||
}
|
||||
var sheetName string
|
||||
if s, ok := newItemValue().Interface().(SheetName); ok {
|
||||
sheetName = s.SheetName()
|
||||
} else {
|
||||
sheetName = itemType.Name()
|
||||
}
|
||||
|
||||
if sheetIndex, err := file.GetSheetIndex(sheetName); err != nil {
|
||||
return err
|
||||
} else if sheetIndex < 0 {
|
||||
return nil
|
||||
}
|
||||
fieldIndex := make(map[string]int)
|
||||
for i := 0; i < itemType.NumField(); i++ {
|
||||
field := itemType.Field(i)
|
||||
alias := field.Tag.Get("column")
|
||||
switch alias {
|
||||
case "":
|
||||
fieldIndex[field.Name] = i
|
||||
case "-":
|
||||
continue
|
||||
default:
|
||||
fieldIndex[alias] = i
|
||||
}
|
||||
}
|
||||
if len(fieldIndex) == 0 {
|
||||
return errors.New("empty column struct")
|
||||
}
|
||||
sheetIndex := make(map[string]int)
|
||||
for i := 1; ; i++ {
|
||||
name, err := file.GetCellValue(sheetName, GetAxis(i, 1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if name == "" {
|
||||
break
|
||||
}
|
||||
if _, ok := fieldIndex[name]; ok {
|
||||
sheetIndex[name] = i
|
||||
}
|
||||
}
|
||||
if len(sheetIndex) == 0 {
|
||||
return errors.New("sheet column empty")
|
||||
}
|
||||
for i := 2; ; i++ {
|
||||
var (
|
||||
notEmpty int
|
||||
item = newItemValue()
|
||||
)
|
||||
for column, index := range sheetIndex {
|
||||
s, err := file.GetCellValue(sheetName, GetAxis(index, i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
notEmpty++
|
||||
if err = String2Value(s, item.Field(fieldIndex[column])); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if notEmpty > 0 {
|
||||
putItem(item)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseAll(r io.Reader, models ...interface{}) error {
|
||||
if len(models) == 0 {
|
||||
return errors.New("empty models")
|
||||
}
|
||||
file, err := excelize.OpenReader(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
for i := 0; i < len(models); i++ {
|
||||
if err := ParseSheet(file, models[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
18
pkg/common/xlsx/model/user.go
Normal file
18
pkg/common/xlsx/model/user.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package model
|
||||
|
||||
type User struct {
|
||||
UserID string `column:"user_id"`
|
||||
Nickname string `column:"nickname"`
|
||||
FaceURL string `column:"face_url"`
|
||||
Birth string `column:"birth"`
|
||||
Gender string `column:"gender"`
|
||||
AreaCode string `column:"area_code"`
|
||||
PhoneNumber string `column:"phone_number"`
|
||||
Email string `column:"email"`
|
||||
Account string `column:"account"`
|
||||
Password string `column:"password"`
|
||||
}
|
||||
|
||||
func (User) SheetName() string {
|
||||
return "user"
|
||||
}
|
||||
5
pkg/common/xlsx/sheet.go
Normal file
5
pkg/common/xlsx/sheet.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package xlsx
|
||||
|
||||
type SheetName interface {
|
||||
SheetName() string
|
||||
}
|
||||
199
pkg/common/xlsx/utils.go
Normal file
199
pkg/common/xlsx/utils.go
Normal file
@@ -0,0 +1,199 @@
|
||||
package xlsx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/xuri/excelize/v2"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Open(r io.Reader) (*excelize.File, error) {
|
||||
return excelize.OpenReader(r)
|
||||
}
|
||||
|
||||
func GetAxis(x, y int) string {
|
||||
return Num2AZ(x) + strconv.Itoa(y)
|
||||
}
|
||||
|
||||
func Num2AZ(num int) string {
|
||||
var (
|
||||
str string
|
||||
k int
|
||||
temp []int
|
||||
)
|
||||
slices := []string{"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
|
||||
|
||||
if num > 26 {
|
||||
for {
|
||||
k = num % 26
|
||||
if k == 0 {
|
||||
temp = append(temp, 26)
|
||||
k = 26
|
||||
} else {
|
||||
temp = append(temp, k)
|
||||
}
|
||||
num = (num - k) / 26
|
||||
if num <= 26 {
|
||||
temp = append(temp, num)
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return slices[num]
|
||||
}
|
||||
for _, value := range temp {
|
||||
str = slices[value] + str
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func String2Value(s string, rv reflect.Value) error {
|
||||
var (
|
||||
val interface{}
|
||||
err error
|
||||
)
|
||||
if s == "" {
|
||||
val = reflect.Zero(rv.Type()).Interface()
|
||||
} else {
|
||||
switch rv.Kind() {
|
||||
case reflect.Bool:
|
||||
switch strings.ToLower(s) {
|
||||
case "false", "f", "0":
|
||||
val = false
|
||||
case "true", "t", "1":
|
||||
val = true
|
||||
default:
|
||||
return fmt.Errorf("parse %s to bool error", s)
|
||||
}
|
||||
case reflect.Int:
|
||||
val, err = strconv.Atoi(s)
|
||||
case reflect.Int8:
|
||||
t, err := strconv.ParseInt(s, 10, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val = int8(t)
|
||||
case reflect.Int16:
|
||||
t, err := strconv.ParseInt(s, 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val = int16(t)
|
||||
case reflect.Int32:
|
||||
t, err := strconv.ParseInt(s, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val = int32(t)
|
||||
case reflect.Int64:
|
||||
val, err = strconv.ParseInt(s, 10, 64)
|
||||
case reflect.Uint:
|
||||
t, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val = uint(t)
|
||||
case reflect.Uint8:
|
||||
t, err := strconv.ParseUint(s, 10, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val = uint8(t)
|
||||
case reflect.Uint16:
|
||||
t, err := strconv.ParseUint(s, 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val = uint16(t)
|
||||
case reflect.Uint32:
|
||||
t, err := strconv.ParseUint(s, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val = uint32(t)
|
||||
case reflect.Uint64:
|
||||
val, err = strconv.ParseUint(s, 10, 64)
|
||||
case reflect.Float32:
|
||||
t, err := strconv.ParseFloat(s, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val = float32(t)
|
||||
case reflect.Float64:
|
||||
val, err = strconv.ParseFloat(s, 64)
|
||||
case reflect.String:
|
||||
val = s
|
||||
default:
|
||||
return errors.New("not Supported " + rv.Kind().String())
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rv.Set(reflect.ValueOf(val))
|
||||
return nil
|
||||
}
|
||||
|
||||
func ZeroValue(kind reflect.Kind) (interface{}, error) {
|
||||
var v interface{}
|
||||
switch kind {
|
||||
case reflect.Bool:
|
||||
v = false
|
||||
case reflect.Int:
|
||||
v = int(0)
|
||||
case reflect.Int8:
|
||||
v = int8(0)
|
||||
case reflect.Int16:
|
||||
v = int16(0)
|
||||
case reflect.Int32:
|
||||
v = int32(0)
|
||||
case reflect.Int64:
|
||||
v = int64(0)
|
||||
case reflect.Uint:
|
||||
v = uint(0)
|
||||
case reflect.Uint8:
|
||||
v = uint8(0)
|
||||
case reflect.Uint16:
|
||||
v = uint16(0)
|
||||
case reflect.Uint32:
|
||||
v = uint32(0)
|
||||
case reflect.Uint64:
|
||||
v = uint64(0)
|
||||
case reflect.Float32:
|
||||
v = float32(0)
|
||||
case reflect.Float64:
|
||||
v = float64(0)
|
||||
case reflect.String:
|
||||
v = ""
|
||||
default:
|
||||
return nil, errors.New("not Supported " + kind.String())
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func GetSheetName(v interface{}) string {
|
||||
return getSheetName(reflect.TypeOf(v))
|
||||
}
|
||||
|
||||
func getSheetName(t reflect.Type) string {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() == reflect.Slice {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() != reflect.Struct {
|
||||
return ""
|
||||
}
|
||||
if s, ok := reflect.New(t).Interface().(SheetName); ok {
|
||||
return s.SheetName()
|
||||
} else {
|
||||
return t.Name()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user