1783 lines
60 KiB
Go
1783 lines
60 KiB
Go
package autocode
|
||
|
||
import (
|
||
"fmt"
|
||
"slices"
|
||
"strings"
|
||
"text/template"
|
||
)
|
||
|
||
// AutoCodeField 自动代码字段(用于模板函数)
|
||
type AutoCodeField struct {
|
||
FieldName string `json:"fieldName"`
|
||
FieldDesc string `json:"fieldDesc"`
|
||
FieldType string `json:"fieldType"`
|
||
FieldJson string `json:"fieldJson"`
|
||
DataTypeLong string `json:"dataTypeLong"`
|
||
Comment string `json:"comment"`
|
||
ColumnName string `json:"columnName"`
|
||
FieldSearchType string `json:"fieldSearchType"`
|
||
FieldSearchHide bool `json:"fieldSearchHide"`
|
||
DictType string `json:"dictType"`
|
||
Form bool `json:"form"`
|
||
Table bool `json:"table"`
|
||
Desc bool `json:"desc"`
|
||
Excel bool `json:"excel"`
|
||
Require bool `json:"require"`
|
||
DefaultValue string `json:"defaultValue"`
|
||
ErrorText string `json:"errorText"`
|
||
Clearable bool `json:"clearable"`
|
||
Sort bool `json:"sort"`
|
||
PrimaryKey bool `json:"primaryKey"`
|
||
DataSource *DataSource `json:"dataSource"`
|
||
CheckDataSource bool `json:"checkDataSource"`
|
||
FieldIndexType string `json:"fieldIndexType"`
|
||
}
|
||
|
||
// DataSource 数据源
|
||
type DataSource struct {
|
||
DBName string `json:"dbName"`
|
||
Table string `json:"table"`
|
||
Label string `json:"label"`
|
||
Value string `json:"value"`
|
||
Association int `json:"association"`
|
||
HasDeletedAt bool `json:"hasDeletedAt"`
|
||
}
|
||
|
||
// CustomMethod 自定义查询方法
|
||
// 用于在 GORM Gen 生成的代码中添加自定义查询方法
|
||
type CustomMethod struct {
|
||
Name string `json:"name"` // 方法名称 (如: FindByName, GetActiveUsers)
|
||
Description string `json:"description"` // 方法描述
|
||
ReturnType string `json:"returnType"` // 返回类型: single(单个), list(列表), count(计数), exists(存在检查)
|
||
Params []*CustomMethodParam `json:"params"` // 方法参数
|
||
Conditions []*CustomCondition `json:"conditions"` // 查询条件
|
||
OrderBy string `json:"orderBy"` // 排序字段 (如: created_at DESC)
|
||
Limit int `json:"limit"` // 限制数量 (0表示不限制)
|
||
}
|
||
|
||
// CustomMethodParam 自定义方法参数
|
||
type CustomMethodParam struct {
|
||
Name string `json:"name"` // 参数名称
|
||
Type string `json:"type"` // 参数类型 (string, int, uint, bool, time.Time等)
|
||
FieldName string `json:"fieldName"` // 对应的字段名 (用于生成查询条件)
|
||
}
|
||
|
||
// CustomCondition 自定义查询条件
|
||
type CustomCondition struct {
|
||
FieldName string `json:"fieldName"` // 字段名
|
||
Operator string `json:"operator"` // 操作符: eq, neq, gt, gte, lt, lte, like, in, between, isNull, isNotNull
|
||
ParamName string `json:"paramName"` // 参数名 (对应 CustomMethodParam.Name)
|
||
}
|
||
|
||
// ToPascalCase 将字符串转换为 PascalCase 格式
|
||
// 支持 snake_case、kebab-case 和普通字符串
|
||
// 例如: "article_status" -> "ArticleStatus", "user-role" -> "UserRole"
|
||
func ToPascalCase(s string) string {
|
||
if s == "" {
|
||
return s
|
||
}
|
||
// 将下划线和连字符替换为空格,然后使用 Title 转换
|
||
s = strings.ReplaceAll(s, "_", " ")
|
||
s = strings.ReplaceAll(s, "-", " ")
|
||
// 使用 strings.Title 转换每个单词首字母大写
|
||
s = strings.Title(s)
|
||
// 移除空格
|
||
return strings.ReplaceAll(s, " ", "")
|
||
}
|
||
|
||
// GetTemplateFuncMap 返回模板函数映射
|
||
func GetTemplateFuncMap() template.FuncMap {
|
||
return template.FuncMap{
|
||
"title": strings.Title,
|
||
"toPascalCase": ToPascalCase,
|
||
"GenerateField": GenerateField,
|
||
"GenerateModelField": GenerateModelField,
|
||
"GenerateSearchField": GenerateSearchField,
|
||
"GenerateSearchConditions": GenerateSearchConditions,
|
||
"GenerateGormGenSearchConditions": GenerateGormGenSearchConditions,
|
||
"GenerateSearchFormItem": GenerateSearchFormItem,
|
||
"GenerateTableColumn": GenerateTableColumn,
|
||
"GenerateFormItem": GenerateFormItem,
|
||
"GenerateDescriptionItem": GenerateDescriptionItem,
|
||
"GenerateDefaultFormValue": GenerateDefaultFormValue,
|
||
// React/TypeScript 相关函数
|
||
"GenerateTSType": GenerateTSType,
|
||
"GenerateReactSearchFormItem": GenerateReactSearchFormItem,
|
||
"GenerateReactTableColumn": GenerateReactTableColumn,
|
||
"GenerateReactProTableColumn": GenerateReactProTableColumn,
|
||
"GenerateReactFormItem": GenerateReactFormItem,
|
||
"GenerateReactDescriptionItem": GenerateReactDescriptionItem,
|
||
"GenerateReactDefaultValue": GenerateReactDefaultValue,
|
||
// 自定义查询方法相关函数
|
||
"GenerateCustomMethodInterface": GenerateCustomMethodInterface,
|
||
"GenerateCustomMethodImpl": GenerateCustomMethodImpl,
|
||
}
|
||
}
|
||
|
||
// GenerateField 渲染Model中的字段
|
||
func GenerateField(field AutoCodeField) string {
|
||
gormTag := ``
|
||
if field.FieldIndexType != "" {
|
||
gormTag += field.FieldIndexType + ";"
|
||
}
|
||
if field.PrimaryKey {
|
||
gormTag += "primarykey;"
|
||
}
|
||
if field.DefaultValue != "" {
|
||
gormTag += fmt.Sprintf("default:%s;", field.DefaultValue)
|
||
}
|
||
if field.Comment != "" {
|
||
gormTag += fmt.Sprintf("comment:%s;", field.Comment)
|
||
}
|
||
gormTag += "column:" + field.ColumnName + ";"
|
||
if field.DataTypeLong != "" && field.FieldType != "enum" && field.FieldType != "int" {
|
||
gormTag += fmt.Sprintf("size:%s;", field.DataTypeLong)
|
||
}
|
||
|
||
requireTag := ` binding:"required"` + "`"
|
||
var result string
|
||
|
||
switch field.FieldType {
|
||
case "enum":
|
||
result = fmt.Sprintf(`%s string `+"`"+`json:"%s" form:"%s" gorm:"%stype:enum(%s);"`+"`",
|
||
field.FieldName, field.FieldJson, field.FieldJson, gormTag, field.DataTypeLong)
|
||
case "picture", "video":
|
||
tagContent := fmt.Sprintf(`json:"%s" form:"%s" gorm:"%s"`, field.FieldJson, field.FieldJson, gormTag)
|
||
result = fmt.Sprintf(`%s string `+"`"+`%s`+"`"+``, field.FieldName, tagContent)
|
||
case "file", "pictures", "array":
|
||
tagContent := fmt.Sprintf(`json:"%s" form:"%s" gorm:"%s"`, field.FieldJson, field.FieldJson, gormTag)
|
||
result = fmt.Sprintf(`%s datatypes.JSON `+"`"+`%s swaggertype:"array,object"`+"`"+``, field.FieldName, tagContent)
|
||
case "richtext":
|
||
tagContent := fmt.Sprintf(`json:"%s" form:"%s" gorm:"%s`, field.FieldJson, field.FieldJson, gormTag)
|
||
result = fmt.Sprintf(`%s *string `+"`"+`%stype:text;"`+"`"+``, field.FieldName, tagContent)
|
||
case "json":
|
||
tagContent := fmt.Sprintf(`json:"%s" form:"%s" gorm:"%s"`, field.FieldJson, field.FieldJson, gormTag)
|
||
result = fmt.Sprintf(`%s datatypes.JSON `+"`"+`%s swaggertype:"object"`+"`"+``, field.FieldName, tagContent)
|
||
default:
|
||
tagContent := fmt.Sprintf(`json:"%s" form:"%s" gorm:"%s"`, field.FieldJson, field.FieldJson, gormTag)
|
||
var fieldType string
|
||
if field.FieldType == "int" {
|
||
switch field.DataTypeLong {
|
||
case "1", "2", "3":
|
||
fieldType = "int8"
|
||
case "4", "5":
|
||
fieldType = "int16"
|
||
case "6", "7", "8", "9", "10":
|
||
fieldType = "int32"
|
||
default:
|
||
fieldType = "int64"
|
||
}
|
||
} else {
|
||
fieldType = field.FieldType
|
||
}
|
||
result = fmt.Sprintf(`%s *%s `+"`"+`%s`+"`"+``, field.FieldName, fieldType, tagContent)
|
||
}
|
||
|
||
if field.Require {
|
||
result = result[0:len(result)-1] + requireTag
|
||
}
|
||
if field.FieldDesc != "" {
|
||
result += fmt.Sprintf(" //%s", field.FieldDesc)
|
||
}
|
||
return result
|
||
}
|
||
|
||
// GenerateModelField 生成 GORM Gen 风格的模型字段定义
|
||
// 用于生成与 GORM Gen 兼容的模型结构体字段
|
||
func GenerateModelField(field AutoCodeField) string {
|
||
// 构建 GORM 标签
|
||
var gormParts []string
|
||
|
||
// column 标签
|
||
gormParts = append(gormParts, fmt.Sprintf("column:%s", field.ColumnName))
|
||
|
||
// type 标签 - 根据字段类型生成数据库类型
|
||
dbType := getDBType(field)
|
||
if dbType != "" {
|
||
gormParts = append(gormParts, fmt.Sprintf("type:%s", dbType))
|
||
}
|
||
|
||
// index 标签
|
||
if field.FieldIndexType != "" {
|
||
gormParts = append(gormParts, field.FieldIndexType)
|
||
}
|
||
|
||
// default 标签
|
||
if field.DefaultValue != "" {
|
||
gormParts = append(gormParts, fmt.Sprintf("default:%s", field.DefaultValue))
|
||
}
|
||
|
||
// comment 标签
|
||
comment := field.Comment
|
||
if comment == "" {
|
||
comment = field.FieldDesc
|
||
}
|
||
if comment != "" {
|
||
gormParts = append(gormParts, fmt.Sprintf("comment:%s", comment))
|
||
}
|
||
|
||
gormTag := strings.Join(gormParts, ";")
|
||
|
||
// 获取 Go 类型
|
||
goType := getModelGoType(field)
|
||
|
||
// 构建完整的字段定义
|
||
var result string
|
||
if comment != "" {
|
||
result = fmt.Sprintf(`%s %s `+"`"+`gorm:"%s" json:"%s"`+"`"+` // %s`,
|
||
field.FieldName, goType, gormTag, field.FieldJson, comment)
|
||
} else {
|
||
result = fmt.Sprintf(`%s %s `+"`"+`gorm:"%s" json:"%s"`+"`",
|
||
field.FieldName, goType, gormTag, field.FieldJson)
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
// getDBType 根据字段类型获取数据库类型
|
||
func getDBType(field AutoCodeField) string {
|
||
switch field.FieldType {
|
||
case "string":
|
||
if field.DataTypeLong != "" {
|
||
return fmt.Sprintf("varchar(%s)", field.DataTypeLong)
|
||
}
|
||
return "varchar(191)"
|
||
case "int":
|
||
switch field.DataTypeLong {
|
||
case "1", "2", "3":
|
||
return "tinyint"
|
||
case "4", "5":
|
||
return "smallint"
|
||
case "6", "7", "8", "9", "10":
|
||
return "int"
|
||
default:
|
||
return "bigint(20)"
|
||
}
|
||
case "int64":
|
||
return "bigint(20)"
|
||
case "uint":
|
||
return "bigint(20) unsigned"
|
||
case "float64":
|
||
return "double"
|
||
case "bool":
|
||
return "tinyint(1)"
|
||
case "time.Time":
|
||
return "datetime(3)"
|
||
case "enum":
|
||
if field.DataTypeLong != "" {
|
||
return fmt.Sprintf("enum(%s)", field.DataTypeLong)
|
||
}
|
||
return "varchar(50)"
|
||
case "richtext":
|
||
return "text"
|
||
case "json", "file", "pictures", "array":
|
||
return "json"
|
||
case "picture", "video":
|
||
return "varchar(500)"
|
||
default:
|
||
return ""
|
||
}
|
||
}
|
||
|
||
// getModelGoType 根据字段类型获取 Go 类型(用于 GORM Gen 模型)
|
||
func getModelGoType(field AutoCodeField) string {
|
||
switch field.FieldType {
|
||
case "string", "picture", "video":
|
||
return "string"
|
||
case "int":
|
||
switch field.DataTypeLong {
|
||
case "1", "2", "3":
|
||
return "int8"
|
||
case "4", "5":
|
||
return "int16"
|
||
case "6", "7", "8", "9", "10":
|
||
return "int32"
|
||
default:
|
||
return "int64"
|
||
}
|
||
case "int64":
|
||
return "int64"
|
||
case "uint":
|
||
return "int64" // GORM Gen 使用 int64 表示 unsigned
|
||
case "float64":
|
||
return "float64"
|
||
case "bool":
|
||
return "bool"
|
||
case "time.Time":
|
||
return "time.Time"
|
||
case "enum":
|
||
return "string"
|
||
case "richtext":
|
||
return "string"
|
||
case "json", "file", "pictures", "array":
|
||
return "datatypes.JSON"
|
||
default:
|
||
return "string"
|
||
}
|
||
}
|
||
|
||
// GenerateSearchConditions 格式化搜索条件语句
|
||
func GenerateSearchConditions(fields []*AutoCodeField) string {
|
||
var conditions []string
|
||
for _, field := range fields {
|
||
if field.FieldSearchType == "" {
|
||
continue
|
||
}
|
||
var condition string
|
||
if slices.Contains([]string{"enum", "pictures", "picture", "video", "json", "richtext", "array"}, field.FieldType) {
|
||
if field.FieldType == "enum" {
|
||
if field.FieldSearchType == "LIKE" {
|
||
condition = fmt.Sprintf(`
|
||
if info.%s != "" {
|
||
db = db.Where("%s LIKE ?", "%%"+ info.%s+"%%")
|
||
}`, field.FieldName, field.ColumnName, field.FieldName)
|
||
} else {
|
||
condition = fmt.Sprintf(`
|
||
if info.%s != "" {
|
||
db = db.Where("%s %s ?", info.%s)
|
||
}`, field.FieldName, field.ColumnName, field.FieldSearchType, field.FieldName)
|
||
}
|
||
} else {
|
||
condition = fmt.Sprintf(`
|
||
if info.%s != "" {
|
||
// TODO 数据类型为复杂类型,请根据业务需求自行实现复杂类型的查询业务
|
||
}`, field.FieldName)
|
||
}
|
||
} else if field.FieldSearchType == "BETWEEN" || field.FieldSearchType == "NOT BETWEEN" {
|
||
if field.FieldType == "time.Time" {
|
||
condition = fmt.Sprintf(`
|
||
if len(info.%sRange) == 2 {
|
||
db = db.Where("%s %s ? AND ? ", info.%sRange[0], info.%sRange[1])
|
||
}`, field.FieldName, field.ColumnName, field.FieldSearchType, field.FieldName, field.FieldName)
|
||
} else {
|
||
condition = fmt.Sprintf(`
|
||
if info.Start%s != nil && info.End%s != nil {
|
||
db = db.Where("%s %s ? AND ? ", *info.Start%s, *info.End%s)
|
||
}`, field.FieldName, field.FieldName, field.ColumnName, field.FieldSearchType, field.FieldName, field.FieldName)
|
||
}
|
||
} else if field.FieldSearchType == "IN" || field.FieldSearchType == "NOT IN" {
|
||
// IN 和 NOT IN 需要传递数组
|
||
condition = fmt.Sprintf(`
|
||
if info.%s != nil && len(info.%s) > 0 {
|
||
db = db.Where("%s %s ?", info.%s)
|
||
}`, field.FieldName, field.FieldName, field.ColumnName, field.FieldSearchType, field.FieldName)
|
||
} else {
|
||
nullCheck := "info." + field.FieldName + " != nil"
|
||
if field.FieldType == "string" {
|
||
condition = fmt.Sprintf(`
|
||
if %s && *info.%s != "" {`, nullCheck, field.FieldName)
|
||
} else {
|
||
condition = fmt.Sprintf(`
|
||
if %s {`, nullCheck)
|
||
}
|
||
if field.FieldSearchType == "LIKE" {
|
||
condition += fmt.Sprintf(`
|
||
db = db.Where("%s LIKE ?", "%%"+ *info.%s+"%%")
|
||
}`, field.ColumnName, field.FieldName)
|
||
} else {
|
||
condition += fmt.Sprintf(`
|
||
db = db.Where("%s %s ?", *info.%s)
|
||
}`, field.ColumnName, field.FieldSearchType, field.FieldName)
|
||
}
|
||
}
|
||
conditions = append(conditions, condition)
|
||
}
|
||
return strings.Join(conditions, "")
|
||
}
|
||
|
||
// GenerateGormGenSearchConditions 生成 GORM Gen 风格的搜索条件语句
|
||
// 使用类型安全的 GORM Gen 查询语法,如 q.Where(t.FieldName.Like(...))
|
||
func GenerateGormGenSearchConditions(fields []*AutoCodeField, structName string) string {
|
||
var conditions []string
|
||
for _, field := range fields {
|
||
if field.FieldSearchType == "" {
|
||
continue
|
||
}
|
||
var condition string
|
||
// 复杂类型处理
|
||
if slices.Contains([]string{"enum", "pictures", "picture", "video", "json", "richtext", "array"}, field.FieldType) {
|
||
if field.FieldType == "enum" {
|
||
if field.FieldSearchType == "LIKE" {
|
||
condition = fmt.Sprintf(`
|
||
if req.%s != "" {
|
||
q = q.Where(t.%s.Like("%%" + req.%s + "%%"))
|
||
}`, field.FieldName, field.FieldName, field.FieldName)
|
||
} else {
|
||
condition = fmt.Sprintf(`
|
||
if req.%s != "" {
|
||
q = q.Where(t.%s.Eq(req.%s))
|
||
}`, field.FieldName, field.FieldName, field.FieldName)
|
||
}
|
||
} else {
|
||
condition = fmt.Sprintf(`
|
||
if req.%s != "" {
|
||
// TODO 数据类型为复杂类型,请根据业务需求自行实现复杂类型的查询业务
|
||
}`, field.FieldName)
|
||
}
|
||
} else if field.FieldSearchType == "BETWEEN" || field.FieldSearchType == "NOT BETWEEN" {
|
||
// BETWEEN 查询
|
||
if field.FieldType == "time.Time" {
|
||
condition = fmt.Sprintf(`
|
||
if len(req.%sRange) == 2 {
|
||
q = q.Where(t.%s.Between(req.%sRange[0], req.%sRange[1]))
|
||
}`, field.FieldName, field.FieldName, field.FieldName, field.FieldName)
|
||
} else {
|
||
condition = fmt.Sprintf(`
|
||
if req.Start%s != nil && req.End%s != nil {
|
||
q = q.Where(t.%s.Between(*req.Start%s, *req.End%s))
|
||
}`, field.FieldName, field.FieldName, field.FieldName, field.FieldName, field.FieldName)
|
||
}
|
||
} else {
|
||
// 普通查询
|
||
nullCheck := "req." + field.FieldName + " != nil"
|
||
if field.FieldType == "string" {
|
||
condition = fmt.Sprintf(`
|
||
if %s && *req.%s != "" {`, nullCheck, field.FieldName)
|
||
} else {
|
||
condition = fmt.Sprintf(`
|
||
if %s {`, nullCheck)
|
||
}
|
||
// 根据搜索类型生成不同的查询方法
|
||
switch field.FieldSearchType {
|
||
case "LIKE":
|
||
condition += fmt.Sprintf(`
|
||
q = q.Where(t.%s.Like("%%" + *req.%s + "%%"))
|
||
}`, field.FieldName, field.FieldName)
|
||
case "=", "EQ":
|
||
if field.FieldType == "string" {
|
||
condition += fmt.Sprintf(`
|
||
q = q.Where(t.%s.Eq(*req.%s))
|
||
}`, field.FieldName, field.FieldName)
|
||
} else {
|
||
condition += fmt.Sprintf(`
|
||
q = q.Where(t.%s.Eq(*req.%s))
|
||
}`, field.FieldName, field.FieldName)
|
||
}
|
||
case ">", "GT":
|
||
condition += fmt.Sprintf(`
|
||
q = q.Where(t.%s.Gt(*req.%s))
|
||
}`, field.FieldName, field.FieldName)
|
||
case ">=", "GTE":
|
||
condition += fmt.Sprintf(`
|
||
q = q.Where(t.%s.Gte(*req.%s))
|
||
}`, field.FieldName, field.FieldName)
|
||
case "<", "LT":
|
||
condition += fmt.Sprintf(`
|
||
q = q.Where(t.%s.Lt(*req.%s))
|
||
}`, field.FieldName, field.FieldName)
|
||
case "<=", "LTE":
|
||
condition += fmt.Sprintf(`
|
||
q = q.Where(t.%s.Lte(*req.%s))
|
||
}`, field.FieldName, field.FieldName)
|
||
case "<>", "!=", "NEQ":
|
||
condition += fmt.Sprintf(`
|
||
q = q.Where(t.%s.Neq(*req.%s))
|
||
}`, field.FieldName, field.FieldName)
|
||
case "IN":
|
||
condition += fmt.Sprintf(`
|
||
q = q.Where(t.%s.In(*req.%s...))
|
||
}`, field.FieldName, field.FieldName)
|
||
case "NOT IN":
|
||
condition += fmt.Sprintf(`
|
||
q = q.Where(t.%s.NotIn(*req.%s...))
|
||
}`, field.FieldName, field.FieldName)
|
||
default:
|
||
// 默认使用 Eq
|
||
condition += fmt.Sprintf(`
|
||
q = q.Where(t.%s.Eq(*req.%s))
|
||
}`, field.FieldName, field.FieldName)
|
||
}
|
||
}
|
||
conditions = append(conditions, condition)
|
||
}
|
||
return strings.Join(conditions, "")
|
||
}
|
||
|
||
// GenerateSearchFormItem 格式化前端搜索条件
|
||
func GenerateSearchFormItem(field AutoCodeField) string {
|
||
result := fmt.Sprintf(`<el-form-item label="%s" prop="%s">
|
||
`, field.FieldDesc, field.FieldJson)
|
||
|
||
if field.FieldType == "bool" {
|
||
result += fmt.Sprintf(` <el-select v-model="searchInfo.%s" clearable placeholder="请选择">
|
||
`, field.FieldJson)
|
||
result += ` <el-option key="true" label="是" value="true"></el-option>
|
||
`
|
||
result += ` <el-option key="false" label="否" value="false"></el-option>
|
||
`
|
||
result += ` </el-select>
|
||
`
|
||
} else if field.DictType != "" {
|
||
multipleAttr := ""
|
||
if field.FieldType == "array" {
|
||
multipleAttr = "multiple "
|
||
}
|
||
result += fmt.Sprintf(` <el-tree-select v-model="searchInfo.%s" placeholder="请选择%s" :data="%sOptions" style="width:100%%" filterable :clearable="%v" check-strictly %s></el-tree-select>
|
||
`, field.FieldJson, field.FieldDesc, field.DictType, field.Clearable, multipleAttr)
|
||
} else if field.CheckDataSource {
|
||
multipleAttr := ""
|
||
if field.DataSource.Association == 2 {
|
||
multipleAttr = "multiple "
|
||
}
|
||
result += fmt.Sprintf(` <el-select %sv-model="searchInfo.%s" filterable placeholder="请选择%s" :clearable="%v">
|
||
`, multipleAttr, field.FieldJson, field.FieldDesc, field.Clearable)
|
||
result += fmt.Sprintf(` <el-option v-for="(item,key) in dataSource.%s" :key="key" :label="item.label" :value="item.value" />
|
||
`, field.FieldJson)
|
||
result += ` </el-select>
|
||
`
|
||
} else if field.FieldType == "float64" || field.FieldType == "int" {
|
||
if field.FieldSearchType == "BETWEEN" || field.FieldSearchType == "NOT BETWEEN" {
|
||
result += fmt.Sprintf(` <el-input class="!w-40" v-model.number="searchInfo.start%s" placeholder="最小值" />
|
||
`, field.FieldName)
|
||
result += ` —
|
||
`
|
||
result += fmt.Sprintf(` <el-input class="!w-40" v-model.number="searchInfo.end%s" placeholder="最大值" />
|
||
`, field.FieldName)
|
||
} else {
|
||
result += fmt.Sprintf(` <el-input v-model.number="searchInfo.%s" placeholder="搜索条件" />
|
||
`, field.FieldJson)
|
||
}
|
||
} else if field.FieldType == "time.Time" {
|
||
if field.FieldSearchType == "BETWEEN" || field.FieldSearchType == "NOT BETWEEN" {
|
||
result += ` <template #label>
|
||
`
|
||
result += ` <span>
|
||
`
|
||
result += fmt.Sprintf(` %s
|
||
`, field.FieldDesc)
|
||
result += ` <el-tooltip content="搜索范围是开始日期(包含)至结束日期(不包含)">
|
||
`
|
||
result += ` <el-icon><QuestionFilled /></el-icon>
|
||
`
|
||
result += ` </el-tooltip>
|
||
`
|
||
result += ` </span>
|
||
`
|
||
result += ` </template>
|
||
`
|
||
result += fmt.Sprintf(`<el-date-picker class="!w-380px" v-model="searchInfo.%sRange" type="datetimerange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间"></el-date-picker>`, field.FieldJson)
|
||
} else {
|
||
result += fmt.Sprintf(`<el-date-picker v-model="searchInfo.%s" type="datetime" placeholder="搜索条件"></el-date-picker>`, field.FieldJson)
|
||
}
|
||
} else {
|
||
result += fmt.Sprintf(` <el-input v-model="searchInfo.%s" placeholder="搜索条件" />
|
||
`, field.FieldJson)
|
||
}
|
||
result += `</el-form-item>`
|
||
return result
|
||
}
|
||
|
||
// GenerateTableColumn 生成表格列HTML
|
||
func GenerateTableColumn(field AutoCodeField) string {
|
||
sortAttr := ""
|
||
if field.Sort {
|
||
sortAttr = " sortable"
|
||
}
|
||
|
||
if field.CheckDataSource {
|
||
result := fmt.Sprintf(`<el-table-column%s align="left" label="%s" prop="%s" width="120">
|
||
`, sortAttr, field.FieldDesc, field.FieldJson)
|
||
result += ` <template #default="scope">
|
||
`
|
||
if field.DataSource.Association == 2 {
|
||
result += fmt.Sprintf(` <el-tag v-for="(item,key) in filterDataSource(dataSource.%s,scope.row.%s)" :key="key">
|
||
`, field.FieldJson, field.FieldJson)
|
||
result += ` {{ item }}
|
||
`
|
||
result += ` </el-tag>
|
||
`
|
||
} else {
|
||
result += fmt.Sprintf(` <span>{{ filterDataSource(dataSource.%s,scope.row.%s) }}</span>
|
||
`, field.FieldJson, field.FieldJson)
|
||
}
|
||
result += ` </template>
|
||
`
|
||
result += `</el-table-column>`
|
||
return result
|
||
} else if field.DictType != "" {
|
||
result := fmt.Sprintf(`<el-table-column%s align="left" label="%s" prop="%s" width="120">
|
||
`, sortAttr, field.FieldDesc, field.FieldJson)
|
||
result += ` <template #default="scope">
|
||
`
|
||
if field.FieldType == "array" {
|
||
result += fmt.Sprintf(` <el-tag class="mr-1" v-for="item in scope.row.%s" :key="item"> {{ filterDict(item,%sOptions) }}</el-tag>
|
||
`, field.FieldJson, field.DictType)
|
||
} else {
|
||
result += fmt.Sprintf(` {{ filterDict(scope.row.%s,%sOptions) }}
|
||
`, field.FieldJson, field.DictType)
|
||
}
|
||
result += ` </template>
|
||
`
|
||
result += `</el-table-column>`
|
||
return result
|
||
} else if field.FieldType == "bool" {
|
||
result := fmt.Sprintf(`<el-table-column%s align="left" label="%s" prop="%s" width="120">
|
||
`, sortAttr, field.FieldDesc, field.FieldJson)
|
||
result += fmt.Sprintf(` <template #default="scope">{{ formatBoolean(scope.row.%s) }}</template>
|
||
`, field.FieldJson)
|
||
result += `</el-table-column>`
|
||
return result
|
||
} else if field.FieldType == "time.Time" {
|
||
result := fmt.Sprintf(`<el-table-column%s align="left" label="%s" prop="%s" width="180">
|
||
`, sortAttr, field.FieldDesc, field.FieldJson)
|
||
result += fmt.Sprintf(` <template #default="scope">{{ formatDate(scope.row.%s) }}</template>
|
||
`, field.FieldJson)
|
||
result += `</el-table-column>`
|
||
return result
|
||
} else if field.FieldType == "picture" {
|
||
result := fmt.Sprintf(`<el-table-column label="%s" prop="%s" width="200">
|
||
`, field.FieldDesc, field.FieldJson)
|
||
result += ` <template #default="scope">
|
||
`
|
||
result += fmt.Sprintf(` <el-image preview-teleported style="width: 100px; height: 100px" :src="getUrl(scope.row.%s)" fit="cover"/>
|
||
`, field.FieldJson)
|
||
result += ` </template>
|
||
`
|
||
result += `</el-table-column>`
|
||
return result
|
||
} else if field.FieldType == "pictures" {
|
||
result := fmt.Sprintf(`<el-table-column label="%s" prop="%s" width="200">
|
||
`, field.FieldDesc, field.FieldJson)
|
||
result += ` <template #default="scope">
|
||
`
|
||
result += ` <div class="multiple-img-box">
|
||
`
|
||
result += fmt.Sprintf(` <el-image preview-teleported v-for="(item,index) in scope.row.%s" :key="index" style="width: 80px; height: 80px" :src="getUrl(item)" fit="cover"/>
|
||
`, field.FieldJson)
|
||
result += ` </div>
|
||
`
|
||
result += ` </template>
|
||
`
|
||
result += `</el-table-column>`
|
||
return result
|
||
} else if field.FieldType == "video" {
|
||
result := fmt.Sprintf(`<el-table-column label="%s" prop="%s" width="200">
|
||
`, field.FieldDesc, field.FieldJson)
|
||
result += ` <template #default="scope">
|
||
`
|
||
result += ` <video style="width: 100px; height: 100px" muted preload="metadata">
|
||
`
|
||
result += fmt.Sprintf(` <source :src="getUrl(scope.row.%s) + '#t=1'">
|
||
`, field.FieldJson)
|
||
result += ` </video>
|
||
`
|
||
result += ` </template>
|
||
`
|
||
result += `</el-table-column>`
|
||
return result
|
||
} else if field.FieldType == "richtext" {
|
||
result := fmt.Sprintf(`<el-table-column label="%s" prop="%s" width="200">
|
||
`, field.FieldDesc, field.FieldJson)
|
||
result += ` <template #default="scope">
|
||
`
|
||
result += ` [富文本内容]
|
||
`
|
||
result += ` </template>
|
||
`
|
||
result += `</el-table-column>`
|
||
return result
|
||
} else if field.FieldType == "file" {
|
||
result := fmt.Sprintf(`<el-table-column label="%s" prop="%s" width="200">
|
||
`, field.FieldDesc, field.FieldJson)
|
||
result += ` <template #default="scope">
|
||
`
|
||
result += ` <div class="file-list">
|
||
`
|
||
result += fmt.Sprintf(` <el-tag v-for="file in scope.row.%s" :key="file.uid" @click="onDownloadFile(file.url)">{{ file.name }}</el-tag>
|
||
`, field.FieldJson)
|
||
result += ` </div>
|
||
`
|
||
result += ` </template>
|
||
`
|
||
result += `</el-table-column>`
|
||
return result
|
||
} else if field.FieldType == "json" {
|
||
result := fmt.Sprintf(`<el-table-column label="%s" prop="%s" width="200">
|
||
`, field.FieldDesc, field.FieldJson)
|
||
result += ` <template #default="scope">
|
||
`
|
||
result += ` [JSON]
|
||
`
|
||
result += ` </template>
|
||
`
|
||
result += `</el-table-column>`
|
||
return result
|
||
} else if field.FieldType == "array" {
|
||
result := fmt.Sprintf(`<el-table-column label="%s" prop="%s" width="200">
|
||
`, field.FieldDesc, field.FieldJson)
|
||
result += ` <template #default="scope">
|
||
`
|
||
result += fmt.Sprintf(` <ArrayCtrl v-model="scope.row.%s"/>
|
||
`, field.FieldJson)
|
||
result += ` </template>
|
||
`
|
||
result += `</el-table-column>`
|
||
return result
|
||
}
|
||
return fmt.Sprintf(`<el-table-column%s align="left" label="%s" prop="%s" width="120" />
|
||
`, sortAttr, field.FieldDesc, field.FieldJson)
|
||
}
|
||
|
||
// GenerateFormItem 生成表单项
|
||
func GenerateFormItem(field AutoCodeField) string {
|
||
result := fmt.Sprintf(`<el-form-item label="%s:" prop="%s">
|
||
`, field.FieldDesc, field.FieldJson)
|
||
|
||
if field.CheckDataSource {
|
||
multipleAttr := ""
|
||
if field.DataSource.Association == 2 {
|
||
multipleAttr = " multiple"
|
||
}
|
||
result += fmt.Sprintf(` <el-select%s v-model="formData.%s" placeholder="请选择%s" filterable style="width:100%%" :clearable="%v">
|
||
`, multipleAttr, field.FieldJson, field.FieldDesc, field.Clearable)
|
||
result += fmt.Sprintf(` <el-option v-for="(item,key) in dataSource.%s" :key="key" :label="item.label" :value="item.value" />
|
||
`, field.FieldJson)
|
||
result += ` </el-select>
|
||
`
|
||
} else {
|
||
switch field.FieldType {
|
||
case "bool":
|
||
result += fmt.Sprintf(` <el-switch v-model="formData.%s" active-color="#13ce66" inactive-color="#ff4949" active-text="是" inactive-text="否" clearable ></el-switch>
|
||
`, field.FieldJson)
|
||
case "string":
|
||
if field.DictType != "" {
|
||
result += fmt.Sprintf(` <el-tree-select v-model="formData.%s" placeholder="请选择%s" :data="%sOptions" style="width:100%%" filterable :clearable="%v" check-strictly></el-tree-select>
|
||
`, field.FieldJson, field.FieldDesc, field.DictType, field.Clearable)
|
||
} else {
|
||
result += fmt.Sprintf(` <el-input v-model="formData.%s" :clearable="%v" placeholder="请输入%s" />
|
||
`, field.FieldJson, field.Clearable, field.FieldDesc)
|
||
}
|
||
case "richtext":
|
||
result += fmt.Sprintf(` <RichEdit v-model="formData.%s"/>
|
||
`, field.FieldJson)
|
||
case "json":
|
||
result += fmt.Sprintf(` // 此字段为json结构,可以前端自行控制展示和数据绑定模式 需绑定json的key为 formData.%s 后端会按照json的类型进行存取
|
||
`, field.FieldJson)
|
||
result += fmt.Sprintf(` {{ formData.%s }}
|
||
`, field.FieldJson)
|
||
case "array":
|
||
if field.DictType != "" {
|
||
result += fmt.Sprintf(` <el-select multiple v-model="formData.%s" placeholder="请选择%s" filterable style="width:100%%" :clearable="%v">
|
||
`, field.FieldJson, field.FieldDesc, field.Clearable)
|
||
result += fmt.Sprintf(` <el-option v-for="(item,key) in %sOptions" :key="key" :label="item.label" :value="item.value" />
|
||
`, field.DictType)
|
||
result += ` </el-select>
|
||
`
|
||
} else {
|
||
result += fmt.Sprintf(` <ArrayCtrl v-model="formData.%s" editable/>
|
||
`, field.FieldJson)
|
||
}
|
||
case "int":
|
||
result += fmt.Sprintf(` <el-input v-model.number="formData.%s" :clearable="%v" placeholder="请输入%s" />
|
||
`, field.FieldJson, field.Clearable, field.FieldDesc)
|
||
case "time.Time":
|
||
result += fmt.Sprintf(` <el-date-picker v-model="formData.%s" type="date" style="width:100%%" placeholder="选择日期" :clearable="%v" />
|
||
`, field.FieldJson, field.Clearable)
|
||
case "float64":
|
||
result += fmt.Sprintf(` <el-input-number v-model="formData.%s" style="width:100%%" :precision="2" :clearable="%v" />
|
||
`, field.FieldJson, field.Clearable)
|
||
case "enum":
|
||
result += fmt.Sprintf(` <el-select v-model="formData.%s" placeholder="请选择%s" style="width:100%%" filterable :clearable="%v">
|
||
`, field.FieldJson, field.FieldDesc, field.Clearable)
|
||
result += fmt.Sprintf(` <el-option v-for="item in [%s]" :key="item" :label="item" :value="item" />
|
||
`, field.DataTypeLong)
|
||
result += ` </el-select>
|
||
`
|
||
case "picture":
|
||
result += fmt.Sprintf(` <SelectImage v-model="formData.%s" file-type="image"/>
|
||
`, field.FieldJson)
|
||
case "pictures":
|
||
result += fmt.Sprintf(` <SelectImage multiple v-model="formData.%s" file-type="image"/>
|
||
`, field.FieldJson)
|
||
case "video":
|
||
result += fmt.Sprintf(` <SelectImage v-model="formData.%s" file-type="video"/>
|
||
`, field.FieldJson)
|
||
case "file":
|
||
result += fmt.Sprintf(` <SelectFile v-model="formData.%s" />
|
||
`, field.FieldJson)
|
||
}
|
||
}
|
||
result += `</el-form-item>`
|
||
return result
|
||
}
|
||
|
||
// GenerateDescriptionItem 生成描述项
|
||
func GenerateDescriptionItem(field AutoCodeField) string {
|
||
result := fmt.Sprintf(`<el-descriptions-item label="%s">
|
||
`, field.FieldDesc)
|
||
|
||
if field.CheckDataSource {
|
||
result += ` <template #default="scope">
|
||
`
|
||
if field.DataSource.Association == 2 {
|
||
result += fmt.Sprintf(` <el-tag v-for="(item,key) in filterDataSource(dataSource.%s,detailForm.%s)" :key="key">
|
||
`, field.FieldJson, field.FieldJson)
|
||
result += ` {{ item }}
|
||
`
|
||
result += ` </el-tag>
|
||
`
|
||
} else {
|
||
result += fmt.Sprintf(` <span>{{ filterDataSource(dataSource.%s,detailForm.%s) }}</span>
|
||
`, field.FieldJson, field.FieldJson)
|
||
}
|
||
result += ` </template>
|
||
`
|
||
} else if field.FieldType != "picture" && field.FieldType != "pictures" &&
|
||
field.FieldType != "file" && field.FieldType != "array" &&
|
||
field.FieldType != "richtext" {
|
||
result += fmt.Sprintf(` {{ detailForm.%s }}
|
||
`, field.FieldJson)
|
||
} else {
|
||
switch field.FieldType {
|
||
case "picture":
|
||
result += fmt.Sprintf(` <el-image style="width: 50px; height: 50px" :preview-src-list="returnArrImg(detailForm.%s)" :src="getUrl(detailForm.%s)" fit="cover" />
|
||
`, field.FieldJson, field.FieldJson)
|
||
case "array":
|
||
result += fmt.Sprintf(` <ArrayCtrl v-model="detailForm.%s"/>
|
||
`, field.FieldJson)
|
||
case "pictures":
|
||
result += fmt.Sprintf(` <el-image style="width: 50px; height: 50px; margin-right: 10px" :preview-src-list="returnArrImg(detailForm.%s)" :initial-index="index" v-for="(item,index) in detailForm.%s" :key="index" :src="getUrl(item)" fit="cover" />
|
||
`, field.FieldJson, field.FieldJson)
|
||
case "richtext":
|
||
result += fmt.Sprintf(` <RichView v-model="detailForm.%s" />
|
||
`, field.FieldJson)
|
||
case "file":
|
||
result += fmt.Sprintf(` <div class="fileBtn" v-for="(item,index) in detailForm.%s" :key="index">
|
||
`, field.FieldJson)
|
||
result += ` <el-button type="primary" text bg @click="onDownloadFile(item.url)">
|
||
`
|
||
result += ` <el-icon style="margin-right: 5px"><Download /></el-icon>
|
||
`
|
||
result += ` {{ item.name }}
|
||
`
|
||
result += ` </el-button>
|
||
`
|
||
result += ` </div>
|
||
`
|
||
}
|
||
}
|
||
result += `</el-descriptions-item>`
|
||
return result
|
||
}
|
||
|
||
// GenerateDefaultFormValue 生成默认表单值
|
||
func GenerateDefaultFormValue(field AutoCodeField) string {
|
||
var defaultValue string
|
||
switch field.FieldType {
|
||
case "bool":
|
||
defaultValue = "false"
|
||
case "string", "richtext":
|
||
defaultValue = "''"
|
||
case "int":
|
||
if field.DataSource != nil {
|
||
defaultValue = "undefined"
|
||
} else {
|
||
defaultValue = "0"
|
||
}
|
||
case "time.Time":
|
||
defaultValue = "new Date()"
|
||
case "float64":
|
||
defaultValue = "0"
|
||
case "picture", "video":
|
||
defaultValue = "\"\""
|
||
case "pictures", "file", "array":
|
||
defaultValue = "[]"
|
||
case "json":
|
||
defaultValue = "{}"
|
||
default:
|
||
defaultValue = "null"
|
||
}
|
||
return fmt.Sprintf(`%s: %s,`, field.FieldJson, defaultValue)
|
||
}
|
||
|
||
// GenerateSearchField 生成搜索字段
|
||
func GenerateSearchField(field AutoCodeField) string {
|
||
if field.FieldSearchType == "" {
|
||
return ""
|
||
}
|
||
var result string
|
||
if field.FieldSearchType == "BETWEEN" || field.FieldSearchType == "NOT BETWEEN" {
|
||
if field.FieldType == "time.Time" {
|
||
result = fmt.Sprintf("%sRange []time.Time `json:\"%sRange\" form:\"%sRange[]\"`",
|
||
field.FieldName, field.FieldJson, field.FieldJson)
|
||
} else {
|
||
startField := fmt.Sprintf("Start%s *%s `json:\"start%s\" form:\"start%s\"`",
|
||
field.FieldName, field.FieldType, field.FieldName, field.FieldName)
|
||
endField := fmt.Sprintf("End%s *%s `json:\"end%s\" form:\"end%s\"`",
|
||
field.FieldName, field.FieldType, field.FieldName, field.FieldName)
|
||
result = startField + "\n" + endField
|
||
}
|
||
} else if field.FieldSearchType == "IN" || field.FieldSearchType == "NOT IN" {
|
||
// IN 和 NOT IN 需要数组类型
|
||
result = fmt.Sprintf("%s []%s `json:\"%s\" form:\"%s\"`",
|
||
field.FieldName, field.FieldType, field.FieldJson, field.FieldJson)
|
||
} else {
|
||
if field.FieldType == "enum" || field.FieldType == "picture" ||
|
||
field.FieldType == "pictures" || field.FieldType == "video" ||
|
||
field.FieldType == "json" || field.FieldType == "richtext" ||
|
||
field.FieldType == "array" || field.FieldType == "file" {
|
||
result = fmt.Sprintf("%s string `json:\"%s\" form:\"%s\"` ",
|
||
field.FieldName, field.FieldJson, field.FieldJson)
|
||
} else {
|
||
result = fmt.Sprintf("%s *%s `json:\"%s\" form:\"%s\"` ",
|
||
field.FieldName, field.FieldType, field.FieldJson, field.FieldJson)
|
||
}
|
||
}
|
||
return result
|
||
}
|
||
|
||
// ==================== React/TypeScript 模板函数 ====================
|
||
|
||
// GenerateTSType Go类型转TypeScript类型
|
||
func GenerateTSType(goType string) string {
|
||
typeMap := map[string]string{
|
||
"int": "number",
|
||
"int8": "number",
|
||
"int16": "number",
|
||
"int32": "number",
|
||
"int64": "number",
|
||
"uint": "number",
|
||
"uint8": "number",
|
||
"uint16": "number",
|
||
"uint32": "number",
|
||
"uint64": "number",
|
||
"float32": "number",
|
||
"float64": "number",
|
||
"string": "string",
|
||
"bool": "boolean",
|
||
"time.Time": "string",
|
||
"datatypes.JSON": "Record<string, any>",
|
||
"json": "Record<string, any>",
|
||
"picture": "string",
|
||
"pictures": "string[]",
|
||
"video": "string",
|
||
"file": "Array<{ name: string; url: string; uid: string }>",
|
||
"array": "any[]",
|
||
"richtext": "string",
|
||
"enum": "string",
|
||
}
|
||
if tsType, ok := typeMap[goType]; ok {
|
||
return tsType
|
||
}
|
||
// 处理指针类型
|
||
if strings.HasPrefix(goType, "*") {
|
||
return GenerateTSType(goType[1:])
|
||
}
|
||
return "any"
|
||
}
|
||
|
||
// GenerateReactSearchFormItem 生成React搜索表单项
|
||
func GenerateReactSearchFormItem(field AutoCodeField) string {
|
||
var result string
|
||
|
||
switch {
|
||
case field.FieldType == "bool":
|
||
result = fmt.Sprintf(`<Form.Item name="%s" label="%s">
|
||
<Select placeholder="请选择" allowClear>
|
||
<Select.Option value={true}>是</Select.Option>
|
||
<Select.Option value={false}>否</Select.Option>
|
||
</Select>
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc)
|
||
|
||
case field.DictType != "":
|
||
result = fmt.Sprintf(`<Form.Item name="%s" label="%s">
|
||
<Select placeholder="请选择%s" allowClear options={%sOptions} />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, field.FieldDesc, field.DictType)
|
||
|
||
case field.CheckDataSource:
|
||
result = fmt.Sprintf(`<Form.Item name="%s" label="%s">
|
||
<Select placeholder="请选择%s" allowClear options={dataSource['%s']} fieldNames={{ label: 'label', value: 'value' }} />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, field.FieldDesc, field.FieldJson)
|
||
|
||
case field.FieldType == "time.Time":
|
||
if field.FieldSearchType == "BETWEEN" || field.FieldSearchType == "NOT BETWEEN" {
|
||
result = fmt.Sprintf(`<Form.Item name="%sRange" label="%s">
|
||
<DatePicker.RangePicker showTime />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc)
|
||
} else {
|
||
result = fmt.Sprintf(`<Form.Item name="%s" label="%s">
|
||
<DatePicker showTime />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc)
|
||
}
|
||
|
||
case field.FieldType == "int" || field.FieldType == "float64":
|
||
if field.FieldSearchType == "BETWEEN" || field.FieldSearchType == "NOT BETWEEN" {
|
||
result = fmt.Sprintf(`<Form.Item label="%s">
|
||
<Input.Group compact>
|
||
<Form.Item name="start%s" noStyle>
|
||
<Input style={{ width: 100 }} placeholder="最小值" />
|
||
</Form.Item>
|
||
<Input style={{ width: 30, borderLeft: 0, borderRight: 0, pointerEvents: 'none' }} placeholder="~" disabled />
|
||
<Form.Item name="end%s" noStyle>
|
||
<Input style={{ width: 100 }} placeholder="最大值" />
|
||
</Form.Item>
|
||
</Input.Group>
|
||
</Form.Item>`, field.FieldDesc, field.FieldName, field.FieldName)
|
||
} else {
|
||
result = fmt.Sprintf(`<Form.Item name="%s" label="%s">
|
||
<Input placeholder="请输入%s" allowClear />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, field.FieldDesc)
|
||
}
|
||
|
||
default:
|
||
result = fmt.Sprintf(`<Form.Item name="%s" label="%s">
|
||
<Input placeholder="请输入%s" allowClear />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, field.FieldDesc)
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
// GenerateReactTableColumn 生成React表格列配置
|
||
func GenerateReactTableColumn(field AutoCodeField) string {
|
||
sortable := ""
|
||
if field.Sort {
|
||
sortable = "\n\t\t\tsorter: true,"
|
||
}
|
||
|
||
switch {
|
||
case field.CheckDataSource:
|
||
if field.DataSource != nil && field.DataSource.Association == 2 {
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 120,%s
|
||
render: (val) => val?.map((v: any) => <Tag key={v}>{dataSource['%s']?.find((d: any) => d.value === v)?.label || v}</Tag>),
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson, sortable, field.FieldJson)
|
||
}
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 120,%s
|
||
render: (val) => dataSource['%s']?.find((d: any) => d.value === val)?.label || val,
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson, sortable, field.FieldJson)
|
||
|
||
case field.DictType != "":
|
||
if field.FieldType == "array" {
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 120,%s
|
||
render: (val) => val?.map((v: any) => <Tag key={v}>{%sOptions?.find((d: any) => d.value === v)?.label || v}</Tag>),
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson, sortable, field.DictType)
|
||
}
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 120,%s
|
||
render: (val) => %sOptions?.find((d: any) => d.value === val)?.label || val,
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson, sortable, field.DictType)
|
||
|
||
case field.FieldType == "bool":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 80,%s
|
||
render: (val) => val ? '是' : '否',
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson, sortable)
|
||
|
||
case field.FieldType == "time.Time":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 180,%s
|
||
render: (val) => val ? dayjs(val).format('YYYY-MM-DD HH:mm:ss') : '-',
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson, sortable)
|
||
|
||
case field.FieldType == "picture":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 100,
|
||
render: (val) => val ? <Image width={50} height={50} src={val} /> : '-',
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
|
||
case field.FieldType == "pictures":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 200,
|
||
render: (val) => val?.map((url: string, i: number) => <Image key={i} width={50} height={50} src={url} style={{ marginRight: 4 }} />),
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
|
||
case field.FieldType == "file":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 200,
|
||
render: (val) => val?.map((f: any) => <Tag key={f.uid}>{f.name}</Tag>),
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
|
||
case field.FieldType == "richtext":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 100,
|
||
render: () => '[富文本]',
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
|
||
case field.FieldType == "json":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 100,
|
||
render: () => '[JSON]',
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
|
||
default:
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
key: '%s',
|
||
width: 120,%s
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson, sortable)
|
||
}
|
||
}
|
||
|
||
// GenerateReactFormItem 生成React表单项
|
||
func GenerateReactFormItem(field AutoCodeField) string {
|
||
rules := ""
|
||
if field.Require {
|
||
rules = fmt.Sprintf(`
|
||
rules={[{ required: true, message: '%s' }]}`, field.ErrorText)
|
||
}
|
||
|
||
switch {
|
||
case field.CheckDataSource:
|
||
multiple := ""
|
||
if field.DataSource != nil && field.DataSource.Association == 2 {
|
||
multiple = " mode=\"multiple\""
|
||
}
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
<Select%s placeholder="请选择%s" allowClear options={dataSource['%s']} fieldNames={{ label: 'label', value: 'value' }} />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules, multiple, field.FieldDesc, field.FieldJson)
|
||
|
||
case field.FieldType == "bool":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s" valuePropName="checked"%s>
|
||
<Switch checkedChildren="是" unCheckedChildren="否" />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules)
|
||
|
||
case field.DictType != "":
|
||
multiple := ""
|
||
if field.FieldType == "array" {
|
||
multiple = " mode=\"multiple\""
|
||
}
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
<Select%s placeholder="请选择%s" allowClear options={%sOptions} />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules, multiple, field.FieldDesc, field.DictType)
|
||
|
||
case field.FieldType == "richtext":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
{/* TODO: 使用富文本编辑器组件 */}
|
||
<Input.TextArea rows={4} placeholder="请输入%s" />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules, field.FieldDesc)
|
||
|
||
case field.FieldType == "json":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
{/* TODO: JSON编辑器 */}
|
||
<Input.TextArea rows={4} placeholder="请输入JSON" />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules)
|
||
|
||
case field.FieldType == "array":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
<Select mode="tags" placeholder="请输入%s" />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules, field.FieldDesc)
|
||
|
||
case field.FieldType == "int":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
<InputNumber style={{ width: '100%%' }} placeholder="请输入%s" />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules, field.FieldDesc)
|
||
|
||
case field.FieldType == "float64":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
<InputNumber style={{ width: '100%%' }} precision={2} placeholder="请输入%s" />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules, field.FieldDesc)
|
||
|
||
case field.FieldType == "time.Time":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
<DatePicker style={{ width: '100%%' }} showTime placeholder="请选择%s" />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules, field.FieldDesc)
|
||
|
||
case field.FieldType == "enum":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
<Select placeholder="请选择%s" allowClear>
|
||
{/* TODO: 根据枚举值生成选项 */}
|
||
</Select>
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules, field.FieldDesc)
|
||
|
||
case field.FieldType == "picture":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
{/* TODO: 图片上传组件 */}
|
||
<Input placeholder="请输入图片URL" />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules)
|
||
|
||
case field.FieldType == "pictures":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
{/* TODO: 多图片上传组件 */}
|
||
<Input placeholder="请输入图片URL" />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules)
|
||
|
||
case field.FieldType == "video":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
{/* TODO: 视频上传组件 */}
|
||
<Input placeholder="请输入视频URL" />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules)
|
||
|
||
case field.FieldType == "file":
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
{/* TODO: 文件上传组件 */}
|
||
<Input placeholder="请上传文件" />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules)
|
||
|
||
default:
|
||
return fmt.Sprintf(`<Form.Item name="%s" label="%s"%s>
|
||
<Input placeholder="请输入%s" allowClear />
|
||
</Form.Item>`, field.FieldJson, field.FieldDesc, rules, field.FieldDesc)
|
||
}
|
||
}
|
||
|
||
// GenerateReactDescriptionItem 生成React描述项
|
||
// 根据字段配置生成对应的详情展示项,支持多种字段类型
|
||
func GenerateReactDescriptionItem(field AutoCodeField) string {
|
||
switch {
|
||
// 数据源字段 - 从外部数据源获取显示值
|
||
case field.CheckDataSource:
|
||
if field.DataSource != nil && field.DataSource.Association == 2 {
|
||
// 多选数据源 - 显示为多个标签
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
{currentRecord?.%s?.map((v: any) => <Tag key={v}>{dataSource['%s']?.find((d: any) => d.value === v)?.label || v}</Tag>)}
|
||
</Descriptions.Item>`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
}
|
||
// 单选数据源 - 显示标签文本
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
{dataSource['%s']?.find((d: any) => d.value === currentRecord?.%s)?.label || currentRecord?.%s}
|
||
</Descriptions.Item>`, field.FieldDesc, field.FieldJson, field.FieldJson, field.FieldJson)
|
||
|
||
// 字典类型字段 - 从字典获取显示值
|
||
case field.DictType != "":
|
||
if field.FieldType == "array" {
|
||
// 数组类型字典 - 显示为多个标签
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
{currentRecord?.%s?.map((v: any) => <Tag key={v}>{get%sLabel(v)}</Tag>)}
|
||
</Descriptions.Item>`, field.FieldDesc, field.FieldJson, ToPascalCase(field.DictType))
|
||
}
|
||
// 单值字典 - 显示字典标签
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
{get%sLabel(currentRecord?.%s)}
|
||
</Descriptions.Item>`, field.FieldDesc, ToPascalCase(field.DictType), field.FieldJson)
|
||
|
||
// 布尔类型 - 显示是/否
|
||
case field.FieldType == "bool":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">{currentRecord?.%s ? '是' : '否'}</Descriptions.Item>`, field.FieldDesc, field.FieldJson)
|
||
|
||
// 时间类型 - 格式化显示
|
||
case field.FieldType == "time.Time":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
{currentRecord?.%s ? dayjs(currentRecord.%s).format('YYYY-MM-DD HH:mm:ss') : '-'}
|
||
</Descriptions.Item>`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
|
||
// 单图片类型 - 显示图片预览
|
||
case field.FieldType == "picture":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
{currentRecord?.%s && <Image width={100} src={currentRecord.%s} />}
|
||
</Descriptions.Item>`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
|
||
// 多图片类型 - 显示图片列表
|
||
case field.FieldType == "pictures":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
{currentRecord?.%s?.map((url: string, i: number) => <Image key={i} width={50} src={url} style={{ marginRight: 4 }} />)}
|
||
</Descriptions.Item>`, field.FieldDesc, field.FieldJson)
|
||
|
||
// 视频类型 - 显示视频播放器
|
||
case field.FieldType == "video":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
{currentRecord?.%s && (
|
||
<video width={200} controls src={currentRecord.%s}>
|
||
您的浏览器不支持视频播放
|
||
</video>
|
||
)}
|
||
</Descriptions.Item>`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
|
||
// 文件类型 - 显示文件列表带下载
|
||
case field.FieldType == "file":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
{currentRecord?.%s?.map((f: any, i: number) => (
|
||
<Tag key={f.uid || i}>
|
||
<a href={f.url} target="_blank" rel="noopener noreferrer">{f.name}</a>
|
||
</Tag>
|
||
))}
|
||
</Descriptions.Item>`, field.FieldDesc, field.FieldJson)
|
||
|
||
// 富文本类型 - 渲染HTML内容
|
||
case field.FieldType == "richtext":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
<div dangerouslySetInnerHTML={{ __html: currentRecord?.%s || '' }} />
|
||
</Descriptions.Item>`, field.FieldDesc, field.FieldJson)
|
||
|
||
// JSON类型 - 格式化显示JSON
|
||
case field.FieldType == "json":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
<pre style={{ margin: 0, whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>{JSON.stringify(currentRecord?.%s, null, 2)}</pre>
|
||
</Descriptions.Item>`, field.FieldDesc, field.FieldJson)
|
||
|
||
// 数组类型(无字典) - 显示为标签列表
|
||
case field.FieldType == "array":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">
|
||
{currentRecord?.%s?.map((v: any, i: number) => <Tag key={i}>{v}</Tag>)}
|
||
</Descriptions.Item>`, field.FieldDesc, field.FieldJson)
|
||
|
||
// 枚举类型 - 直接显示值
|
||
case field.FieldType == "enum":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">{currentRecord?.%s}</Descriptions.Item>`, field.FieldDesc, field.FieldJson)
|
||
|
||
// 整数类型 - 显示数字
|
||
case field.FieldType == "int":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">{currentRecord?.%s ?? '-'}</Descriptions.Item>`, field.FieldDesc, field.FieldJson)
|
||
|
||
// 浮点数类型 - 保留两位小数
|
||
case field.FieldType == "float64":
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">{currentRecord?.%s !== undefined ? currentRecord.%s.toFixed(2) : '-'}</Descriptions.Item>`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
|
||
// 默认类型 - 直接显示值
|
||
default:
|
||
return fmt.Sprintf(`<Descriptions.Item label="%s">{currentRecord?.%s ?? '-'}</Descriptions.Item>`, field.FieldDesc, field.FieldJson)
|
||
}
|
||
}
|
||
|
||
// GenerateReactDefaultValue 生成React表单默认值
|
||
func GenerateReactDefaultValue(field AutoCodeField) string {
|
||
switch field.FieldType {
|
||
case "bool":
|
||
return fmt.Sprintf(`%s: false,`, field.FieldJson)
|
||
case "string", "richtext", "picture", "video":
|
||
return fmt.Sprintf(`%s: '',`, field.FieldJson)
|
||
case "int", "float64":
|
||
if field.DataSource != nil {
|
||
return fmt.Sprintf(`%s: undefined,`, field.FieldJson)
|
||
}
|
||
return fmt.Sprintf(`%s: 0,`, field.FieldJson)
|
||
case "time.Time":
|
||
return fmt.Sprintf(`%s: undefined,`, field.FieldJson)
|
||
case "pictures", "file", "array":
|
||
return fmt.Sprintf(`%s: [],`, field.FieldJson)
|
||
case "json":
|
||
return fmt.Sprintf(`%s: {},`, field.FieldJson)
|
||
default:
|
||
return fmt.Sprintf(`%s: undefined,`, field.FieldJson)
|
||
}
|
||
}
|
||
|
||
// GenerateReactProTableColumn 生成 Ant Design Pro Table 列配置
|
||
func GenerateReactProTableColumn(field AutoCodeField) string {
|
||
sorter := ""
|
||
if field.Sort {
|
||
sorter = "\n\t\t\tsorter: true,"
|
||
}
|
||
|
||
// 搜索配置
|
||
hideInSearch := ""
|
||
if field.FieldSearchType == "" {
|
||
hideInSearch = "\n\t\t\thideInSearch: true,"
|
||
}
|
||
|
||
switch {
|
||
case field.CheckDataSource:
|
||
valueType := "select"
|
||
if field.DataSource != nil && field.DataSource.Association == 2 {
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 150,%s%s
|
||
valueType: '%s',
|
||
fieldProps: {
|
||
mode: 'multiple',
|
||
options: dataSource['%s'],
|
||
},
|
||
render: (_, record) => record.%s?.map((v: any) => (
|
||
<Tag key={v}>{dataSource['%s']?.find((d: any) => d.value === v)?.label || v}</Tag>
|
||
)),
|
||
},`, field.FieldDesc, field.FieldJson, sorter, hideInSearch, valueType, field.FieldJson, field.FieldJson, field.FieldJson)
|
||
}
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 150,%s%s
|
||
valueType: '%s',
|
||
fieldProps: {
|
||
options: dataSource['%s'],
|
||
},
|
||
render: (_, record) => dataSource['%s']?.find((d: any) => d.value === record.%s)?.label || record.%s,
|
||
},`, field.FieldDesc, field.FieldJson, sorter, hideInSearch, valueType, field.FieldJson, field.FieldJson, field.FieldJson, field.FieldJson)
|
||
|
||
case field.DictType != "":
|
||
valueType := "select"
|
||
if field.FieldType == "array" {
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 150,%s%s
|
||
valueType: '%s',
|
||
fieldProps: {
|
||
mode: 'multiple',
|
||
options: %sOptions,
|
||
},
|
||
render: (_, record) => record.%s?.map((v: any) => (
|
||
<Tag key={v}>{get%sLabel(v)}</Tag>
|
||
)),
|
||
},`, field.FieldDesc, field.FieldJson, sorter, hideInSearch, valueType, field.DictType, field.FieldJson, ToPascalCase(field.DictType))
|
||
}
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 150,%s%s
|
||
valueType: '%s',
|
||
fieldProps: {
|
||
options: %sOptions,
|
||
},
|
||
render: (_, record) => get%sLabel(record.%s),
|
||
},`, field.FieldDesc, field.FieldJson, sorter, hideInSearch, valueType, field.DictType, ToPascalCase(field.DictType), field.FieldJson)
|
||
|
||
case field.FieldType == "bool":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 80,%s%s
|
||
valueType: 'select',
|
||
valueEnum: {
|
||
true: { text: '是', status: 'Success' },
|
||
false: { text: '否', status: 'Default' },
|
||
},
|
||
},`, field.FieldDesc, field.FieldJson, sorter, hideInSearch)
|
||
|
||
case field.FieldType == "time.Time":
|
||
searchType := ""
|
||
if field.FieldSearchType == "BETWEEN" {
|
||
searchType = "\n\t\t\tvalueType: 'dateTimeRange',"
|
||
} else {
|
||
searchType = "\n\t\t\tvalueType: 'dateTime',"
|
||
}
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 180,%s%s%s
|
||
},`, field.FieldDesc, field.FieldJson, sorter, hideInSearch, searchType)
|
||
|
||
case field.FieldType == "picture":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 100,
|
||
hideInSearch: true,
|
||
render: (_, record) => record.%s ? <Image width={50} height={50} src={record.%s} /> : '-',
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson, field.FieldJson)
|
||
|
||
case field.FieldType == "pictures":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 200,
|
||
hideInSearch: true,
|
||
render: (_, record) => record.%s?.map((url: string, i: number) => (
|
||
<Image key={i} width={50} height={50} src={url} style={{ marginRight: 4 }} />
|
||
)),
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
|
||
case field.FieldType == "file":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 200,
|
||
hideInSearch: true,
|
||
render: (_, record) => record.%s?.map((f: any) => <Tag key={f.uid}>{f.name}</Tag>),
|
||
},`, field.FieldDesc, field.FieldJson, field.FieldJson)
|
||
|
||
case field.FieldType == "richtext":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 100,
|
||
hideInSearch: true,
|
||
render: () => <Typography.Text type="secondary">[富文本]</Typography.Text>,
|
||
},`, field.FieldDesc, field.FieldJson)
|
||
|
||
case field.FieldType == "json":
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 100,
|
||
hideInSearch: true,
|
||
render: () => <Typography.Text type="secondary">[JSON]</Typography.Text>,
|
||
},`, field.FieldDesc, field.FieldJson)
|
||
|
||
case field.FieldType == "int", field.FieldType == "float64":
|
||
valueType := "digit"
|
||
if field.FieldSearchType == "BETWEEN" {
|
||
valueType = "digitRange"
|
||
}
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 120,%s%s
|
||
valueType: '%s',
|
||
},`, field.FieldDesc, field.FieldJson, sorter, hideInSearch, valueType)
|
||
|
||
default:
|
||
return fmt.Sprintf(`{
|
||
title: '%s',
|
||
dataIndex: '%s',
|
||
width: 150,%s%s
|
||
ellipsis: true,
|
||
},`, field.FieldDesc, field.FieldJson, sorter, hideInSearch)
|
||
}
|
||
}
|
||
|
||
// ==================== 自定义查询方法模板函数 ====================
|
||
|
||
// GenerateCustomMethodInterface 生成自定义方法的接口定义
|
||
// 用于 biz 层 Repository 接口
|
||
func GenerateCustomMethodInterface(methods []*CustomMethod, structName, pkgName string) string {
|
||
if len(methods) == 0 {
|
||
return ""
|
||
}
|
||
|
||
var builder strings.Builder
|
||
builder.WriteString("\n\t// 自定义查询方法\n")
|
||
|
||
for _, method := range methods {
|
||
// 生成方法签名
|
||
params := generateMethodParams(method.Params)
|
||
returnType := generateReturnType(method.ReturnType, structName, pkgName)
|
||
comment := method.Description
|
||
if comment == "" {
|
||
comment = method.Name
|
||
}
|
||
|
||
builder.WriteString(fmt.Sprintf("\t// %s %s\n", method.Name, comment))
|
||
builder.WriteString(fmt.Sprintf("\t%s(ctx context.Context%s) %s\n", method.Name, params, returnType))
|
||
}
|
||
|
||
return builder.String()
|
||
}
|
||
|
||
// GenerateCustomMethodImpl 生成自定义方法的实现
|
||
// 用于 data 层 Repository 实现
|
||
func GenerateCustomMethodImpl(methods []*CustomMethod, structName, pkgName, abbreviation string) string {
|
||
if len(methods) == 0 {
|
||
return ""
|
||
}
|
||
|
||
var builder strings.Builder
|
||
|
||
for _, method := range methods {
|
||
// 生成方法签名
|
||
params := generateMethodParams(method.Params)
|
||
returnType := generateReturnType(method.ReturnType, structName, pkgName)
|
||
comment := method.Description
|
||
if comment == "" {
|
||
comment = method.Name
|
||
}
|
||
|
||
builder.WriteString(fmt.Sprintf("\n// %s %s\n", method.Name, comment))
|
||
builder.WriteString(fmt.Sprintf("func (r *%sRepo) %s(ctx context.Context%s) %s {\n", abbreviation, method.Name, params, returnType))
|
||
|
||
// 生成方法体
|
||
builder.WriteString(fmt.Sprintf("\tt := query.%s\n", structName))
|
||
builder.WriteString("\tq := t.WithContext(ctx)\n\n")
|
||
|
||
// 生成查询条件
|
||
conditions := generateConditions(method.Conditions, method.Params)
|
||
if conditions != "" {
|
||
builder.WriteString(conditions)
|
||
}
|
||
|
||
// 生成排序
|
||
if method.OrderBy != "" {
|
||
builder.WriteString(generateOrderBy(method.OrderBy))
|
||
}
|
||
|
||
// 生成限制
|
||
if method.Limit > 0 {
|
||
builder.WriteString(fmt.Sprintf("\tq = q.Limit(%d)\n", method.Limit))
|
||
}
|
||
|
||
// 生成返回语句
|
||
builder.WriteString(generateReturnStatement(method.ReturnType, structName, pkgName))
|
||
builder.WriteString("}\n")
|
||
}
|
||
|
||
return builder.String()
|
||
}
|
||
|
||
// generateMethodParams 生成方法参数列表
|
||
func generateMethodParams(params []*CustomMethodParam) string {
|
||
if len(params) == 0 {
|
||
return ""
|
||
}
|
||
|
||
var parts []string
|
||
for _, p := range params {
|
||
parts = append(parts, fmt.Sprintf("%s %s", p.Name, p.Type))
|
||
}
|
||
return ", " + strings.Join(parts, ", ")
|
||
}
|
||
|
||
// generateReturnType 生成返回类型
|
||
func generateReturnType(returnType, structName, pkgName string) string {
|
||
switch returnType {
|
||
case "single":
|
||
return fmt.Sprintf("(*%s.%s, error)", pkgName, structName)
|
||
case "list":
|
||
return fmt.Sprintf("([]*%s.%s, error)", pkgName, structName)
|
||
case "count":
|
||
return "(int64, error)"
|
||
case "exists":
|
||
return "(bool, error)"
|
||
default:
|
||
return fmt.Sprintf("(*%s.%s, error)", pkgName, structName)
|
||
}
|
||
}
|
||
|
||
// generateConditions 生成查询条件
|
||
func generateConditions(conditions []*CustomCondition, params []*CustomMethodParam) string {
|
||
if len(conditions) == 0 {
|
||
return ""
|
||
}
|
||
|
||
var builder strings.Builder
|
||
builder.WriteString("\t// 查询条件\n")
|
||
|
||
for _, cond := range conditions {
|
||
// 查找对应的参数类型
|
||
var paramType string
|
||
for _, p := range params {
|
||
if p.Name == cond.ParamName {
|
||
paramType = p.Type
|
||
break
|
||
}
|
||
}
|
||
|
||
condStr := generateSingleCondition(cond, paramType)
|
||
if condStr != "" {
|
||
builder.WriteString(condStr)
|
||
}
|
||
}
|
||
|
||
return builder.String()
|
||
}
|
||
|
||
// generateSingleCondition 生成单个查询条件
|
||
func generateSingleCondition(cond *CustomCondition, paramType string) string {
|
||
fieldName := cond.FieldName
|
||
paramName := cond.ParamName
|
||
|
||
switch cond.Operator {
|
||
case "eq", "=":
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.Eq(%s))\n", fieldName, paramName)
|
||
case "neq", "!=", "<>":
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.Neq(%s))\n", fieldName, paramName)
|
||
case "gt", ">":
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.Gt(%s))\n", fieldName, paramName)
|
||
case "gte", ">=":
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.Gte(%s))\n", fieldName, paramName)
|
||
case "lt", "<":
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.Lt(%s))\n", fieldName, paramName)
|
||
case "lte", "<=":
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.Lte(%s))\n", fieldName, paramName)
|
||
case "like":
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.Like(\"%%"+"\" + %s + \""+"%%\"))\n", fieldName, paramName)
|
||
case "in":
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.In(%s...))\n", fieldName, paramName)
|
||
case "notIn":
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.NotIn(%s...))\n", fieldName, paramName)
|
||
case "between":
|
||
// between 需要两个参数,假设参数名为 paramName + "Start" 和 paramName + "End"
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.Between(%sStart, %sEnd))\n", fieldName, paramName, paramName)
|
||
case "isNull":
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.IsNull())\n", fieldName)
|
||
case "isNotNull":
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.IsNotNull())\n", fieldName)
|
||
default:
|
||
return fmt.Sprintf("\tq = q.Where(t.%s.Eq(%s))\n", fieldName, paramName)
|
||
}
|
||
}
|
||
|
||
// generateOrderBy 生成排序语句
|
||
func generateOrderBy(orderBy string) string {
|
||
if orderBy == "" {
|
||
return ""
|
||
}
|
||
|
||
// 解析排序字段,格式: "field_name DESC" 或 "field_name ASC" 或 "FieldName"
|
||
parts := strings.Fields(orderBy)
|
||
if len(parts) == 0 {
|
||
return ""
|
||
}
|
||
|
||
fieldName := ToPascalCase(parts[0])
|
||
direction := "Asc"
|
||
if len(parts) > 1 && strings.ToUpper(parts[1]) == "DESC" {
|
||
direction = "Desc"
|
||
}
|
||
|
||
return fmt.Sprintf("\tq = q.Order(t.%s.%s())\n", fieldName, direction)
|
||
}
|
||
|
||
// generateReturnStatement 生成返回语句
|
||
func generateReturnStatement(returnType, structName, pkgName string) string {
|
||
switch returnType {
|
||
case "single":
|
||
return fmt.Sprintf(`
|
||
m, err := q.First()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return toBiz%s(m), nil
|
||
`, structName)
|
||
case "list":
|
||
return fmt.Sprintf(`
|
||
models, err := q.Find()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
result := make([]*%s.%s, len(models))
|
||
for i, m := range models {
|
||
result[i] = toBiz%s(m)
|
||
}
|
||
return result, nil
|
||
`, pkgName, structName, structName)
|
||
case "count":
|
||
return `
|
||
count, err := q.Count()
|
||
return count, err
|
||
`
|
||
case "exists":
|
||
return `
|
||
count, err := q.Count()
|
||
if err != nil {
|
||
return false, err
|
||
}
|
||
return count > 0, nil
|
||
`
|
||
default:
|
||
return fmt.Sprintf(`
|
||
m, err := q.First()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return toBiz%s(m), nil
|
||
`, structName)
|
||
}
|
||
}
|