diff --git a/config/config.go b/config/config.go index ed74bf7..7b91422 100644 --- a/config/config.go +++ b/config/config.go @@ -33,6 +33,34 @@ type Config struct { Data map[string]interface{} `json:"data,omitempty"` } +func (c *Config) AddElement(elements ...*Element) *Config { + c.Elements = append(c.Elements, elements...) + return c +} + +func (c *Config) AddLanguage(languages ...*Language) *Config { + c.Languages = append(c.Languages, languages...) + return c +} + +func (c *Config) AddButton(buttons ...string) *Config { + c.Buttons = append(c.Buttons, buttons...) + return c +} + +func (c *Config) AddAttribute(attributes ...string) *Config { + c.Attributes = append(c.Attributes, attributes) + return c +} + +func (c *Config) Set(name string, value interface{}) *Config { + if c.Data == nil { + c.Data = map[string]interface{}{} + } + c.Data[name] = value + return c +} + func (c *Config) Clone() *Config { r := *c return &r diff --git a/config/element.go b/config/element.go index da3933b..dc22e99 100644 --- a/config/element.go +++ b/config/element.go @@ -42,3 +42,31 @@ func (e *Element) HasAttr(attrs ...string) bool { } return false } + +func (e *Element) AddElement(elements ...*Element) *Element { + e.Elements = append(e.Elements, elements...) + return e +} + +func (e *Element) AddLanguage(languages ...*Language) *Element { + e.Languages = append(e.Languages, languages...) + return e +} + +func (e *Element) AddAttribute(attributes ...string) *Element { + e.Attributes = append(e.Attributes, attributes) + return e +} + +func (e *Element) AddChoice(choices ...*Choice) *Element { + e.Choices = append(e.Choices, choices...) + return e +} + +func (e *Element) Set(name string, value interface{}) *Element { + if e.Data == nil { + e.Data = map[string]interface{}{} + } + e.Data[name] = value + return e +} diff --git a/forms_test.go b/forms_test.go new file mode 100644 index 0000000..5aac1a9 --- /dev/null +++ b/forms_test.go @@ -0,0 +1,71 @@ +package forms + +import ( + "fmt" + "testing" + + "github.com/coscms/forms/config" + "github.com/webx-top/com" +) + +func TestForms(t *testing.T) { + type Data struct { + Test string + } + mp := map[string]interface{}{ + `name`: `test`, + `age`: 20, + `items`: map[string]string{ + `itemK1`: `itemV1`, + }, + `data`: &Data{ + Test: `test-data`, + }, + `list`: []string{ + `1`, `2`, + }, + `listData`: []*Data{ + &Data{ + Test: `test-listdata-1`, + }, &Data{ + Test: `test-listdata-2`, + }, + }, + } + cfg := NewConfig() + cfg.AddElement(&config.Element{ + ID: `input-name`, + Type: `text`, + Name: `name`, + Label: `名称`, + }, &config.Element{ + ID: `input-items-k1`, + Type: `text`, + Name: `items.itemK1`, + Label: `Item K1`, + }, &config.Element{ + ID: `input-data-test`, + Type: `text`, + Name: `data.test`, + Label: `Data`, + }, &config.Element{ + ID: `input-list-0`, + Type: `text`, + Name: `list.0`, + Label: `List 0`, + }, &config.Element{ + ID: `input-list-2`, + Type: `text`, + Name: `list.2`, + Label: `List 2`, + }, &config.Element{ + ID: `input-listdata-0`, + Type: `text`, + Name: `listData.0.test`, + Label: `ListData 0`, + }) + form := NewWithModelConfig(mp, cfg) + com.Dump(form.Data()) + result := form.String() + fmt.Println(result) +} diff --git a/go.mod b/go.mod index ab914ec..be3981b 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,12 @@ require ( github.com/admpub/fsnotify v1.5.0 // indirect github.com/admpub/json5 v0.0.1 github.com/francoispqt/gojay v1.2.13 // indirect - github.com/goccy/go-json v0.7.6 // indirect - github.com/json-iterator/go v1.1.11 // indirect + github.com/goccy/go-json v0.7.8 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/stretchr/testify v1.7.0 - github.com/webx-top/com v0.2.7 + github.com/webx-top/com v0.2.8 github.com/webx-top/tagfast v0.0.0-20161020041435-9a2065ce3dd2 github.com/webx-top/validation v0.0.3 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55 // indirect + golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 // indirect ) diff --git a/go.sum b/go.sum index 1496452..195179a 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,6 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1 dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/admpub/fsnotify v1.4.4 h1:LhmWQAC3la+JtwlVZ42uRSahOU0lccSOZV7/hB4gqCA= -github.com/admpub/fsnotify v1.4.4/go.mod h1:IE7rjoj2vwr4cYUYQFUeBV1KgldTeXTQy7TwOe0Zwlk= github.com/admpub/fsnotify v1.5.0 h1:8eYm3SBw3Y4cNt0sQIcWKd0IcsRXNYH9j308GNu66mk= github.com/admpub/fsnotify v1.5.0/go.mod h1:2YN7o9RdisXYVueAUsZxjx0Rbsiz6bu6B9XCgovJHY0= github.com/admpub/json5 v0.0.1 h1:ZgD9YKNEpOqjcg553hqi1Zv8f8tNWLjxZrFcoksCRCw= @@ -33,6 +31,8 @@ github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/goccy/go-json v0.7.6 h1:H0wq4jppBQ+9222sk5+hPLL25abZQiRuQ6YPnjO9c+A= github.com/goccy/go-json v0.7.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.7.8 h1:CvMH7LotYymYuLGEohBM1lTZWX4g6jzWUUl2aLFuBoE= +github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= @@ -56,6 +56,8 @@ github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -72,6 +74,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= @@ -118,6 +122,8 @@ github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49u github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/webx-top/com v0.2.7 h1:RPpbx9PRYo8+SbP2KwyHm1102zGW1ElTQleyyXyzqWM= github.com/webx-top/com v0.2.7/go.mod h1:DDfATzu1w5+vD5XmG3YRTfLjaIqZWi/yeJ7HQEGsM2Q= +github.com/webx-top/com v0.2.8 h1:i7xHg7Ms9nJqU+z68oHyxUlMNXSLLgUKx3auLe4xMlQ= +github.com/webx-top/com v0.2.8/go.mod h1:DDfATzu1w5+vD5XmG3YRTfLjaIqZWi/yeJ7HQEGsM2Q= github.com/webx-top/tagfast v0.0.0-20161020041435-9a2065ce3dd2 h1:lqnGa1BnWT7pN+c9V31bik0lTp5XxyOMRp7ICsZ6K5M= github.com/webx-top/tagfast v0.0.0-20161020041435-9a2065ce3dd2/go.mod h1:pMe3sJitHxbxX2EAI/v9HEAXjodP4c+yUVw3rbKcljI= github.com/webx-top/validation v0.0.3 h1:6vBoAp5iqjIpfFA+XoCnIzBHcuLjQzxv7MRlshptUqk= @@ -156,12 +162,11 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816032535-30e4713e60e3 h1:7hHxyYeKyS0AU/brXAMuc+9BxCO/a4vL1DoUVLDTVIo= -golang.org/x/sys v0.0.0-20210816032535-30e4713e60e3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55 h1:rw6UNGRMfarCepjI8qOepea/SXwIBVfTKjztZ5gBbq4= golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 h1:J27LZFQBFoihqXoegpscI10HpjZ7B5WQLLKL2FZXQKw= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/json.go b/json.go index 6411027..30898fe 100644 --- a/json.go +++ b/json.go @@ -24,6 +24,7 @@ import ( "net/url" "path/filepath" "reflect" + "strconv" "strings" "github.com/admpub/json5" @@ -319,31 +320,62 @@ func (form *Form) parseElement(ele *config.Element, typ reflect.Type, val reflec parts := strings.Split(ele.Name, `.`) isValid := true for _, field := range parts { - field = strings.Title(field) if value.Kind() == reflect.Ptr { if value.IsNil() { - value.Set(reflect.New(value.Type().Elem())) + isValid = false + break } value = value.Elem() } - value = value.FieldByName(field) + switch typ.Kind() { + case reflect.Map: + index := reflect.ValueOf(field) + value = value.MapIndex(index) + case reflect.Slice: + index, _ := strconv.Atoi(field) + if index >= value.Len() { + isValid = false + goto OUTLOOP + } + value = value.Index(index) + case reflect.Struct: + field = strings.Title(field) + value = value.FieldByName(field) + default: + isValid = false + goto OUTLOOP + } if !value.IsValid() { isValid = false break } + if value.Kind() == reflect.Interface { + value = reflect.ValueOf(value.Interface()) + } + value = reflect.Indirect(value) + kind := value.Kind() + if kind != reflect.Struct && kind != reflect.Map && kind != reflect.Slice { + break + } + typ = value.Type() } + + OUTLOOP: if isValid { sv = fmt.Sprintf("%v", value.Interface()) } } + isStruct := typ.Kind() == reflect.Struct switch ele.Type { case common.DATE: dateFormat := fields.DATE_FORMAT if len(ele.Format) > 0 { dateFormat = ele.Format - } else if structField, ok := typ.FieldByName(strings.Title(ele.Name)); ok { - if format := tagfast.Value(typ, structField, `form_format`); len(format) > 0 { - dateFormat = format + } else if isStruct { + if structField, ok := typ.FieldByName(strings.Title(ele.Name)); ok { + if format := tagfast.Value(typ, structField, `form_format`); len(format) > 0 { + dateFormat = format + } } } f = fields.TextField(ele.Name, ele.Type) @@ -359,9 +391,11 @@ func (form *Form) parseElement(ele *config.Element, typ reflect.Type, val reflec dateFormat := fields.DATETIME_FORMAT if len(ele.Format) > 0 { dateFormat = ele.Format - } else if structField, ok := typ.FieldByName(strings.Title(ele.Name)); ok { - if format := tagfast.Value(typ, structField, `form_format`); len(format) > 0 { - dateFormat = format + } else if isStruct { + if structField, ok := typ.FieldByName(strings.Title(ele.Name)); ok { + if format := tagfast.Value(typ, structField, `form_format`); len(format) > 0 { + dateFormat = format + } } } f = fields.TextField(ele.Name, ele.Type) @@ -377,9 +411,11 @@ func (form *Form) parseElement(ele *config.Element, typ reflect.Type, val reflec dateFormat := fields.DATETIME_FORMAT if len(ele.Format) > 0 { dateFormat = ele.Format - } else if structField, ok := typ.FieldByName(strings.Title(ele.Name)); ok { - if format := tagfast.Value(typ, structField, `form_format`); len(format) > 0 { - dateFormat = format + } else if isStruct { + if structField, ok := typ.FieldByName(strings.Title(ele.Name)); ok { + if format := tagfast.Value(typ, structField, `form_format`); len(format) > 0 { + dateFormat = format + } } } f = fields.TextField(ele.Name, ele.Type) @@ -395,9 +431,11 @@ func (form *Form) parseElement(ele *config.Element, typ reflect.Type, val reflec dateFormat := fields.TIME_FORMAT if len(ele.Format) > 0 { dateFormat = ele.Format - } else if structField, ok := typ.FieldByName(strings.Title(ele.Name)); ok { - if format := tagfast.Value(typ, structField, `form_format`); len(format) > 0 { - dateFormat = format + } else if isStruct { + if structField, ok := typ.FieldByName(strings.Title(ele.Name)); ok { + if format := tagfast.Value(typ, structField, `form_format`); len(format) > 0 { + dateFormat = format + } } } f = fields.TextField(ele.Name, ele.Type) @@ -411,26 +449,18 @@ func (form *Form) parseElement(ele *config.Element, typ reflect.Type, val reflec case common.TEXT: f = fields.TextField(ele.Name, ele.Type) - if len(ele.Format) > 0 { //时间格式 + format := ele.Format + if len(format) == 0 && isStruct { + if structField, ok := typ.FieldByName(strings.Title(ele.Name)); ok { + format = tagfast.Value(typ, structField, `form_format`) + } + } + if len(format) > 0 { //时间格式 if vt, isEmpty := fields.ConvertTime(sv); !vt.IsZero() { - f.SetValue(vt.Format(ele.Format)) + f.SetValue(vt.Format(format)) } else if isEmpty { f.SetValue(``) } - } else if structField, ok := typ.FieldByName(strings.Title(ele.Name)); ok { - if format := tagfast.Value(typ, structField, `form_format`); len(format) > 0 { - if vt, isEmpty := fields.ConvertTime(sv); !vt.IsZero() { - f.SetValue(vt.Format(format)) - } else if isEmpty { - f.SetValue(``) - } - } else { - if len(sv) == 0 { - f.SetValue(ele.Value) - } else { - f.SetValue(sv) - } - } } else { if len(sv) == 0 { f.SetValue(ele.Value)