v0.9.29 更新UI
This commit is contained in:
parent
b6c65a63f1
commit
64d177fc27
4 changed files with 330 additions and 12 deletions
217
imports/column.go
Normal file
217
imports/column.go
Normal file
|
|
@ -0,0 +1,217 @@
|
||||||
|
package imports
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MarshalJSON for json marshalJSON
|
||||||
|
func (column Column) MarshalJSON() ([]byte, error) {
|
||||||
|
data := column.ToMap()
|
||||||
|
return jsoniter.Marshal(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON for json marshalJSON
|
||||||
|
func (column *Column) UnmarshalJSON(source []byte) error {
|
||||||
|
var data = map[string]interface{}{}
|
||||||
|
err := jsoniter.Unmarshal(source, &data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
new, err := ColumnOf(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*column = *new
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ColumnOf 映射表转换为字段定义
|
||||||
|
func ColumnOf(data map[string]interface{}) (*Column, error) {
|
||||||
|
var column = &Column{}
|
||||||
|
|
||||||
|
err := column.setLabel(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = column.setName(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = column.setMatch(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = column.setRules(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if primary, ok := data["primary"].(bool); ok {
|
||||||
|
column.Primary = primary
|
||||||
|
}
|
||||||
|
|
||||||
|
if nullable, ok := data["nullable"].(bool); ok {
|
||||||
|
column.Nullable = nullable
|
||||||
|
}
|
||||||
|
|
||||||
|
return column, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToMap 转换为映射表
|
||||||
|
func (column Column) ToMap() map[string]interface{} {
|
||||||
|
if column.IsArray {
|
||||||
|
column.Name = column.Name + "[*]"
|
||||||
|
}
|
||||||
|
|
||||||
|
if column.IsObject {
|
||||||
|
column.Name = column.Name + "." + column.Key
|
||||||
|
}
|
||||||
|
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"name": column.Name,
|
||||||
|
"label": column.Label,
|
||||||
|
"match": column.Match,
|
||||||
|
"rules": column.Rules,
|
||||||
|
}
|
||||||
|
|
||||||
|
if column.Nullable {
|
||||||
|
data["nullable"] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if column.Primary {
|
||||||
|
data["primary"] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// setRules 设置清洗规则
|
||||||
|
func (column *Column) setRules(data map[string]interface{}) error {
|
||||||
|
rules, err := GetArrayString(data, "rules")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 process 是否存在
|
||||||
|
|
||||||
|
column.Rules = rules
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setLabel 读取并设置字段标签
|
||||||
|
func (column *Column) setLabel(data map[string]interface{}) error {
|
||||||
|
label, err := GetString(data, "label", true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
column.Label = label
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setMatch 读取并设置字段名称
|
||||||
|
func (column *Column) setMatch(data map[string]interface{}) error {
|
||||||
|
match, err := GetArrayString(data, "match")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
column.Match = match
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setName 读取并设置字段名称
|
||||||
|
func (column *Column) setName(data map[string]interface{}) error {
|
||||||
|
name, err := GetString(data, "name", true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(name, "[*]") { // Array
|
||||||
|
namer := strings.Split(name, "[*]")
|
||||||
|
name = namer[0]
|
||||||
|
column.IsArray = true
|
||||||
|
name = strings.Join(namer, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(name, ".") { // Object
|
||||||
|
namer := strings.Split(name, ".")
|
||||||
|
name = namer[0]
|
||||||
|
if len(namer) > 1 {
|
||||||
|
column.IsObject = true
|
||||||
|
column.Key = strings.Join(namer[1:], ".")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
column.Name = name
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetString 读取字符串格式
|
||||||
|
func GetString(data map[string]interface{}, key string, required bool) (string, error) {
|
||||||
|
value, ok := data[key].(string)
|
||||||
|
if !ok {
|
||||||
|
if bytes, isok := data[key].([]byte); isok {
|
||||||
|
ok = isok
|
||||||
|
value = string(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok || (value == "" && required) {
|
||||||
|
return "", ErrorF("the %s format is incorrect", key)
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArrayString 读取字符串数组
|
||||||
|
func GetArrayString(data map[string]interface{}, key string) ([]string, error) {
|
||||||
|
value := []string{}
|
||||||
|
|
||||||
|
if data[key] == nil {
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := data[key].(string); ok {
|
||||||
|
return []string{v}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
value, ok := data[key].([]string)
|
||||||
|
if !ok {
|
||||||
|
if anys, isok := data[key].([]interface{}); isok {
|
||||||
|
ok = isok
|
||||||
|
for _, any := range anys {
|
||||||
|
value = append(value, fmt.Sprintf("%v", any))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
if anys, isok := data[key].([][]byte); isok {
|
||||||
|
ok = isok
|
||||||
|
for _, any := range anys {
|
||||||
|
value = append(value, string(any))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrorF("the %s format is incorrect", key)
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorF 返回错误数据对象
|
||||||
|
func ErrorF(format string, data ...interface{}) error {
|
||||||
|
values := []interface{}{}
|
||||||
|
for _, value := range data {
|
||||||
|
v, _ := jsoniter.Marshal(value)
|
||||||
|
values = append(values, v)
|
||||||
|
}
|
||||||
|
return fmt.Errorf(format, values...)
|
||||||
|
}
|
||||||
102
imports/column_test.go
Normal file
102
imports/column_test.go
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
package imports
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var data = map[string][]byte{
|
||||||
|
"normal": []byte(`{
|
||||||
|
"label": "订单号",
|
||||||
|
"name": "order_sn",
|
||||||
|
"match": ["订单号", "订单", "order_sn", "id"],
|
||||||
|
"rules": ["scripts.rules.order_sn"],
|
||||||
|
"primary": true
|
||||||
|
}`),
|
||||||
|
"object": []byte(`{
|
||||||
|
"label": "性别",
|
||||||
|
"name": "user.sex",
|
||||||
|
"match": "性别",
|
||||||
|
"rules": ["scripts.rules.FmtUser"],
|
||||||
|
"nullable": true
|
||||||
|
}`),
|
||||||
|
"array": []byte(`{
|
||||||
|
"label": "库存",
|
||||||
|
"name": "stock[*]",
|
||||||
|
"rules": ["scripts.rules.FmtGoods"]
|
||||||
|
}`),
|
||||||
|
"arrayObject": []byte(`{
|
||||||
|
"label": "商品",
|
||||||
|
"name": "skus[*].name",
|
||||||
|
"match": ["商品", "商品名称", "goods", "skus", "sku_id", "goods_id"],
|
||||||
|
"rules": ["scripts.rules.FmtGoods"]
|
||||||
|
}`),
|
||||||
|
"failure": []byte(`{
|
||||||
|
"xx": "商品",
|
||||||
|
"sx": "skus[*].name",
|
||||||
|
"a": ["商品", "商品名称", "goods", "skus", "sku_id", "goods_id"],
|
||||||
|
"b": ["scripts.rules.FmtGoods"]
|
||||||
|
}`),
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalJSON(t *testing.T) {
|
||||||
|
var normal Column
|
||||||
|
err := jsoniter.Unmarshal(data["normal"], &normal)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "订单号", normal.Label)
|
||||||
|
assert.Equal(t, "order_sn", normal.Name)
|
||||||
|
assert.Equal(t, "", normal.Key)
|
||||||
|
assert.Equal(t, []string{"订单号", "订单", "order_sn", "id"}, normal.Match)
|
||||||
|
assert.Equal(t, []string{"scripts.rules.order_sn"}, normal.Rules)
|
||||||
|
assert.Equal(t, false, normal.Nullable)
|
||||||
|
assert.Equal(t, true, normal.Primary)
|
||||||
|
assert.Equal(t, false, normal.IsArray)
|
||||||
|
assert.Equal(t, false, normal.IsObject)
|
||||||
|
|
||||||
|
var object Column
|
||||||
|
err = jsoniter.Unmarshal(data["object"], &object)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "性别", object.Label)
|
||||||
|
assert.Equal(t, "user", object.Name)
|
||||||
|
assert.Equal(t, "sex", object.Key)
|
||||||
|
assert.Equal(t, []string{"性别"}, object.Match)
|
||||||
|
assert.Equal(t, []string{"scripts.rules.FmtUser"}, object.Rules)
|
||||||
|
assert.Equal(t, true, object.Nullable)
|
||||||
|
assert.Equal(t, false, object.IsArray)
|
||||||
|
assert.Equal(t, true, object.IsObject)
|
||||||
|
assert.Equal(t, false, object.Primary)
|
||||||
|
|
||||||
|
var array Column
|
||||||
|
err = jsoniter.Unmarshal(data["array"], &array)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "库存", array.Label)
|
||||||
|
assert.Equal(t, "stock", array.Name)
|
||||||
|
assert.Equal(t, "", array.Key)
|
||||||
|
assert.Equal(t, []string{}, array.Match)
|
||||||
|
assert.Equal(t, []string{"scripts.rules.FmtGoods"}, array.Rules)
|
||||||
|
assert.Equal(t, false, array.Nullable)
|
||||||
|
assert.Equal(t, true, array.IsArray)
|
||||||
|
assert.Equal(t, false, array.IsObject)
|
||||||
|
assert.Equal(t, false, array.Primary)
|
||||||
|
|
||||||
|
var arrayObject Column
|
||||||
|
err = jsoniter.Unmarshal(data["arrayObject"], &arrayObject)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "商品", arrayObject.Label)
|
||||||
|
assert.Equal(t, "skus", arrayObject.Name)
|
||||||
|
assert.Equal(t, "name", arrayObject.Key)
|
||||||
|
assert.Equal(t, []string{"商品", "商品名称", "goods", "skus", "sku_id", "goods_id"}, arrayObject.Match)
|
||||||
|
assert.Equal(t, []string{"scripts.rules.FmtGoods"}, arrayObject.Rules)
|
||||||
|
assert.Equal(t, false, arrayObject.Nullable)
|
||||||
|
assert.Equal(t, true, arrayObject.IsArray)
|
||||||
|
assert.Equal(t, true, arrayObject.IsObject)
|
||||||
|
assert.Equal(t, false, arrayObject.Primary)
|
||||||
|
|
||||||
|
var failure Column
|
||||||
|
err = jsoniter.Unmarshal(data["failure"], &failure)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Contains(t, err.Error(), `"label" format is incorrect`)
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
package imports
|
package imports
|
||||||
|
|
||||||
import "github.com/yaoapp/gou"
|
|
||||||
|
|
||||||
// PreviewAuto 一直显示
|
// PreviewAuto 一直显示
|
||||||
const PreviewAuto = "auto"
|
const PreviewAuto = "auto"
|
||||||
|
|
||||||
|
|
@ -14,7 +12,7 @@ const PreviewNever = "never"
|
||||||
// Imports 数据导入
|
// Imports 数据导入
|
||||||
type Imports struct {
|
type Imports struct {
|
||||||
Title string `json:"title,omitempty"` // 导入名称
|
Title string `json:"title,omitempty"` // 导入名称
|
||||||
Process *gou.Process `json:"process"` // 处理器名称
|
Process string `json:"process"` // 处理器名称
|
||||||
Columns []Column `json:"columns"` // 字段列表
|
Columns []Column `json:"columns"` // 字段列表
|
||||||
Option Option `json:"option,omitempty"` // 导入配置项
|
Option Option `json:"option,omitempty"` // 导入配置项
|
||||||
}
|
}
|
||||||
|
|
@ -24,8 +22,9 @@ type Column struct {
|
||||||
Label string `json:"label"` // 字段标签
|
Label string `json:"label"` // 字段标签
|
||||||
Name string `json:"name"` // 字段名称
|
Name string `json:"name"` // 字段名称
|
||||||
Match []string `json:"match,omitempty"` // 匹配建议
|
Match []string `json:"match,omitempty"` // 匹配建议
|
||||||
Rules []gou.Process `json:"rules,omitempty"` // 清洗规则定义
|
Rules []string `json:"rules,omitempty"` // 清洗规则定义
|
||||||
Nullable bool `json:"nullable,omitempty"` // 是否可以为空
|
Nullable bool `json:"nullable,omitempty"` // 是否可以为空
|
||||||
|
Primary bool `json:"primary,omitempty"` // 是否为主键
|
||||||
|
|
||||||
Key string // 字段键名 Object Only
|
Key string // 字段键名 Object Only
|
||||||
IsArray bool // 字段是否为 Array
|
IsArray bool // 字段是否为 Array
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package share
|
package share
|
||||||
|
|
||||||
// VERSION 版本号
|
// VERSION 版本号
|
||||||
const VERSION = "0.9.28"
|
const VERSION = "0.9.29"
|
||||||
|
|
||||||
// DOMAIN 许可域(废弃)
|
// DOMAIN 许可域(废弃)
|
||||||
const DOMAIN = "*.iqka.com"
|
const DOMAIN = "*.iqka.com"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue