package rest import ( "gorm.io/gorm/schema" "reflect" "strings" "time" ) var ( timeKind = reflect.TypeOf(time.Time{}).Kind() timePtrKind = reflect.TypeOf(&time.Time{}).Kind() ) //dataTypeOf 推断数据的类型 func dataTypeOf(field *schema.Field) string { var dataType string reflectType := field.FieldType for reflectType.Kind() == reflect.Ptr { reflectType = reflectType.Elem() } dataValue := reflect.Indirect(reflect.New(reflectType)) switch dataValue.Kind() { case reflect.Bool: dataType = TypeBoolean case reflect.Int8, reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: dataType = TypeInteger case reflect.Float32, reflect.Float64: dataType = TypeFloat default: dataType = TypeString } return dataType } //dataFormatOf 推断数据的格式 func dataFormatOf(field *schema.Field) string { var format string format = field.Tag.Get("format") if format != "" { return format } //如果有枚举值,直接设置为下拉类型 enum := field.Tag.Get("enum") if enum != "" { return FormatDropdown } reflectType := field.FieldType for reflectType.Kind() == reflect.Ptr { reflectType = reflectType.Elem() } //时间处理 dataValue := reflect.Indirect(reflect.New(reflectType)) if field.Name == "CreatedAt" || field.Name == "UpdatedAt" || field.Name == "DeletedAt" { switch dataValue.Kind() { case reflect.Int8, reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return FormatTimestamp default: return FormatDatetime } } if strings.Contains(strings.ToLower(field.Name), "pass") { return FormatPassword } switch dataValue.Kind() { case timeKind, timePtrKind: format = FormatDatetime case reflect.Bool: format = FormatBoolean case reflect.Int8, reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: format = FormatInteger case reflect.Float32, reflect.Float64: format = FormatFloat case reflect.Struct: if _, ok := dataValue.Interface().(time.Time); ok { format = FormatDatetime } default: if field.Size >= 1024 { format = FormatText } else { format = FormatString } } return format } //generateFieldName 生成字段名称 func generateFieldName(name string) string { tokens := strings.Split(name, "_") for i, s := range tokens { tokens[i] = strings.Title(s) } return strings.Join(tokens, " ") } //generateFieldScenario 生成数据的显示场景 func generateFieldScenario(index int, field *schema.Field) Scenarios { var ss Scenarios if v, ok := field.Tag.Lookup("scenarios"); ok { v = strings.TrimSpace(v) if v != "" { ss = strings.Split(v, ";") } } else { if field.PrimaryKey { ss = []string{ScenarioList, ScenarioView, ScenarioExport} } else if field.Name == "CreatedAt" || field.Name == "UpdatedAt" { ss = []string{ScenarioList} } else if field.Name == "DeletedAt" || field.Name == "Namespace" { //不添加任何显示场景 ss = []string{} } else { if index < 10 { //高级字段只配置一些简单的场景 ss = []string{ScenarioSearch, ScenarioList, ScenarioCreate, ScenarioUpdate, ScenarioView, ScenarioExport} } else { //高级字段只配置一些简单的场景 ss = []string{ScenarioCreate, ScenarioUpdate, ScenarioView, ScenarioExport} } } } return ss } //generateFieldRule 生成字段的规则 func generateFieldRule(field *schema.Field) Rule { r := Rule{ Required: []string{}, } if field.GORMDataType == schema.String { r.Max = field.Size } if field.GORMDataType == schema.Int || field.GORMDataType == schema.Float || field.GORMDataType == schema.Uint { r.Max = field.Scale } if field.NotNull { r.Required = []string{ScenarioCreate, ScenarioUpdate} } if field.PrimaryKey { r.Unique = true } return r } // generateFieldAttribute 生成数据属性 func generateFieldAttribute(field *schema.Field) Attribute { attr := Attribute{ Match: MatchFuzzy, PrimaryKey: field.PrimaryKey, DefaultValue: field.DefaultValue, Readonly: []string{}, Disable: []string{}, Visible: make([]VisibleCondition, 0), Values: make([]EnumValue, 0), Live: LiveValue{}, Description: "", } //赋值属性 props := field.Tag.Get("props") if props != "" { vs := strings.Split(props, ";") for _, str := range vs { kv := strings.SplitN(str, ":", 2) if len(kv) != 2 { continue } switch strings.ToLower(kv[0]) { case "icon": attr.Icon = kv[1] case "suffix": attr.Suffix = kv[1] case "tooltip": attr.Tooltip = kv[1] case "description": attr.Description = kv[1] case "live": //在线数据解析 ss := strings.Split(kv[1], ",") for _, s := range ss { if len(s) == 0 { continue } attr.Live.Enable = true if s == LiveTypeDropdown || s == LiveTypeCascader { attr.Live.Type = s } else if s[0] == '/' || strings.HasPrefix(s, "http") { attr.Live.Url = s } else { if strings.IndexByte(s, '.') > -1 { attr.Live.Columns = strings.Split(s, ".") } } } } } } //赋值枚举值 enumns := field.Tag.Get("enum") if enumns != "" { vs := strings.Split(enumns, ";") for _, str := range vs { kv := strings.SplitN(str, ":", 2) if len(kv) != 2 { continue } fv := EnumValue{Value: kv[0]} //颜色分隔符 if pos := strings.IndexByte(kv[1], '#'); pos > -1 { fv.Label = kv[1][:pos] fv.Color = kv[1][pos:] } else { fv.Label = kv[1] } attr.Values = append(attr.Values, fv) } } if !field.Creatable { attr.Disable = append(attr.Disable, ScenarioCreate) } if !field.Updatable { attr.Disable = append(attr.Disable, ScenarioUpdate) } attr.Tooltip = field.Comment return attr }