发布2.8.1 beta版本 (#2014)

AI: 增加了AI前端绘制功能,可以根据描述生成客户端页面【授权用户专属】

自动化: 自动化模板采用了function模式,更加方便用户二次开发和自定义改动

自动化: 默认携带ID和CreatedAt排序

自动化: 所有自动化Select模板默认支持select搜索

优化:http交互报错信息增加防止多次弹出错误遮罩机制

ICON: 优化ICON逻辑,防止多次加载svg

布局:增加侧边分栏模式
布局: 顶栏模式样式优化和高亮逻辑调整
优化: 个人配置不再需要手动点击保存,会根据变化自动保存

BUG: 修复了菜单点击设为主页勾选被取消的bug
安全: 更新了jwt版本,修复CVE-2025-30204
导出: 默认支持软删除过滤
代码: 优化了部分代码逻辑
本次更新需要重新执行 npm i

---------

Signed-off-by: joohwan <zhouhuan.chen@yunqutech.com >
Co-authored-by: huiyifyj <jxfengyijie@gmail.com>
Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: okppop <okppop@protonmail.com>
Co-authored-by: joohwan <zhouhuan.chen@yunqutech.com >
Co-authored-by: xuedinge <781408517@qq.com>
This commit is contained in:
PiexlMax(奇淼
2025-04-18 11:40:03 +08:00
committed by GitHub
co-authored by huiyifyj piexlMax(奇淼 okppop joohwan xuedinge
parent 84a3c3ba7c
commit a6255557ee
56 changed files with 2457 additions and 2828 deletions
@@ -1,112 +0,0 @@
{{- if .IsAdd}}
// 在结构体中新增如下字段
{{- range .Fields}}
{{- if eq .FieldType "enum" }}
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};type:enum({{.DataTypeLong}});" {{- if .Require }} binding:"required"{{- end -}}`
{{- else if eq .FieldType "picture" }}
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};" {{- if .Require }} binding:"required"{{- end -}}`
{{- else if eq .FieldType "video" }}
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};" {{- if .Require }} binding:"required"{{- end -}}`
{{- else if eq .FieldType "file" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};" {{- if .Require }} binding:"required"{{- end }} swaggertype:"array,object"`
{{- else if eq .FieldType "pictures" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};" {{- if .Require }} binding:"required"{{- end }} swaggertype:"array,object"`
{{- else if eq .FieldType "richtext" }}
{{.FieldName}} *string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};type:text;" {{- if .Require }} binding:"required"{{- end -}}`
{{- else if eq .FieldType "json" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};type:text;" {{- if .Require }} binding:"required"{{- end }} swaggertype:"object"`
{{- else if eq .FieldType "array" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};type:text;" {{- if .Require }} binding:"required"{{- end }} swaggertype:"array,object"`
{{- else }}
{{.FieldName}} *{{.FieldType}} `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};" {{- if .Require }} binding:"required"{{- end -}}`
{{- end }} {{ if .FieldDesc }}//{{.FieldDesc}}{{ end }}
{{- end }}
{{ else }}
package model
{{- if not .OnlyTemplate}}
import (
{{- if .GvaModel }}
"{{.Module}}/global"
{{- end }}
{{- if or .HasTimer }}
"time"
{{- end }}
{{- if .NeedJSON }}
"gorm.io/datatypes"
{{- end }}
)
{{- end }}
// {{.StructName}} {{.Description}} 结构体
type {{.StructName}} struct {
{{- if not .OnlyTemplate}}
{{- if .GvaModel }}
global.GVA_MODEL
{{- end }}
{{- range .Fields}}
{{- if eq .FieldType "enum" }}
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};type:enum({{.DataTypeLong}});" {{- if .Require }} binding:"required"{{- end -}}`
{{- else if eq .FieldType "picture" }}
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};" {{- if .Require }} binding:"required"{{- end -}}`
{{- else if eq .FieldType "video" }}
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};" {{- if .Require }} binding:"required"{{- end -}}`
{{- else if eq .FieldType "file" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};" {{- if .Require }} binding:"required"{{- end }} swaggertype:"array,object"`
{{- else if eq .FieldType "pictures" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};" {{- if .Require }} binding:"required"{{- end }} swaggertype:"array,object"`
{{- else if eq .FieldType "richtext" }}
{{.FieldName}} *string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};type:text;" {{- if .Require }} binding:"required"{{- end -}}`
{{- else if eq .FieldType "json" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};type:text;" {{- if .Require }} binding:"required"{{- end }} swaggertype:"object"`
{{- else if eq .FieldType "array" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};type:text;" {{- if .Require }} binding:"required"{{- end }} swaggertype:"array,object"`
{{- else }}
{{.FieldName}} *{{.FieldType}} `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{ formatGormTag .FieldIndexType .PrimaryKey .DefaultValue .ColumnName .Comment .DataTypeLong }};" {{- if .Require }} binding:"required"{{- end -}}`
{{- end }} {{ if .FieldDesc }}//{{.FieldDesc}}{{ end }}
{{- end }}
{{- if .AutoCreateResource }}
CreatedBy uint `gorm:"column:created_by;comment:创建者"`
UpdatedBy uint `gorm:"column:updated_by;comment:更新者"`
DeletedBy uint `gorm:"column:deleted_by;comment:删除者"`
{{- end }}
{{- if .IsTree }}
Children []*{{.StructName}} `json:"children" gorm:"-"` //子节点
ParentID int `json:"parentID" gorm:"column:parent_id;comment:父节点"`
{{- end }}
{{- end }}
}
{{ if .TableName }}
// TableName {{.Description}} {{.StructName}}自定义表名 {{.TableName}}
func ({{.StructName}}) TableName() string {
return "{{.TableName}}"
}
{{ end }}
{{if .IsTree }}
// GetChildren 实现TreeNode接口
func (s *{{.StructName}}) GetChildren() []*{{.StructName}} {
return s.Children
}
// SetChildren 实现TreeNode接口
func (s *{{.StructName}}) SetChildren(children *{{.StructName}}) {
s.Children = append(s.Children, children)
}
// GetID 实现TreeNode接口
func (s *{{.StructName}}) GetID() int {
return int({{if not .GvaModel}}*{{- end }}s.{{.PrimaryField.FieldName}})
}
// GetParentID 实现TreeNode接口
func (s *{{.StructName}}) GetParentID() int {
return s.ParentID
}
{{ end }}
{{ end }}
@@ -0,0 +1,76 @@
{{- if .IsAdd}}
// 在结构体中新增如下字段
{{- range .Fields}}
{{ GenerateField . }}
{{- end }}
{{ else }}
package model
{{- if not .OnlyTemplate}}
import (
{{- if .GvaModel }}
"{{.Module}}/global"
{{- end }}
{{- if or .HasTimer }}
"time"
{{- end }}
{{- if .NeedJSON }}
"gorm.io/datatypes"
{{- end }}
)
{{- end }}
// {{.StructName}} {{.Description}} 结构体
type {{.StructName}} struct {
{{- if not .OnlyTemplate}}
{{- if .GvaModel }}
global.GVA_MODEL
{{- end }}
{{- range .Fields}}
{{ GenerateField . }}
{{- end }}
{{- if .AutoCreateResource }}
CreatedBy uint `gorm:"column:created_by;comment:创建者"`
UpdatedBy uint `gorm:"column:updated_by;comment:更新者"`
DeletedBy uint `gorm:"column:deleted_by;comment:删除者"`
{{- end }}
{{- if .IsTree }}
Children []*{{.StructName}} `json:"children" gorm:"-"` //子节点
ParentID int `json:"parentID" gorm:"column:parent_id;comment:父节点"`
{{- end }}
{{- end }}
}
{{ if .TableName }}
// TableName {{.Description}} {{.StructName}}自定义表名 {{.TableName}}
func ({{.StructName}}) TableName() string {
return "{{.TableName}}"
}
{{ end }}
{{if .IsTree }}
// GetChildren 实现TreeNode接口
func (s *{{.StructName}}) GetChildren() []*{{.StructName}} {
return s.Children
}
// SetChildren 实现TreeNode接口
func (s *{{.StructName}}) SetChildren(children *{{.StructName}}) {
s.Children = append(s.Children, children)
}
// GetID 实现TreeNode接口
func (s *{{.StructName}}) GetID() int {
return int({{if not .GvaModel}}*{{- end }}s.{{.PrimaryField.FieldName}})
}
// GetParentID 实现TreeNode接口
func (s *{{.StructName}}) GetParentID() int {
return s.ParentID
}
{{ end }}
{{ end }}
@@ -3,13 +3,13 @@
{{- range .Fields}}
{{- if ne .FieldSearchType ""}}
{{- if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
Start{{.FieldName}} *{{.FieldType}} `{{ formatFieldTag (print "start" .FieldName) false }}`
End{{.FieldName}} *{{.FieldType}} `{{ formatFieldTag (print "end" .FieldName) false }}`
Start{{.FieldName}} *{{.FieldType}} `json:"start{{.FieldName}}" form:"start{{.FieldName}}"`
End{{.FieldName}} *{{.FieldType}} `json:"end{{.FieldName}}" form:"end{{.FieldName}}"`
{{- else }}
{{- if or (eq .FieldType "enum") (eq .FieldType "picture") (eq .FieldType "pictures") (eq .FieldType "video") (eq .FieldType "json") }}
{{.FieldName}} string `{{ formatFieldTag .FieldJson false }}`
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" `
{{- else }}
{{.FieldName}} *{{.FieldType}} `{{ formatFieldTag .FieldJson false }}`
{{.FieldName}} *{{.FieldType}} `json:"{{.FieldJson}}" form:"{{.FieldJson}}" `
{{- end }}
{{- end }}
{{- end}}
@@ -36,13 +36,13 @@ type {{.StructName}}Search struct{
{{- range .Fields}}
{{- if ne .FieldSearchType ""}}
{{- if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
Start{{.FieldName}} *{{.FieldType}} `{{ formatFieldTag (print "start" .FieldName) false }}`
End{{.FieldName}} *{{.FieldType}} `{{ formatFieldTag (print "end" .FieldName) false }}`
Start{{.FieldName}} *{{.FieldType}} `json:"start{{.FieldName}}" form:"start{{.FieldName}}"`
End{{.FieldName}} *{{.FieldType}} `json:"end{{.FieldName}}" form:"end{{.FieldName}}"`
{{- else }}
{{- if or (eq .FieldType "enum") (eq .FieldType "picture") (eq .FieldType "pictures") (eq .FieldType "video") (eq .FieldType "json") }}
{{.FieldName}} string `{{ formatFieldTag .FieldJson false }}`
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" `
{{- else }}
{{.FieldName}} *{{.FieldType}} `{{ formatFieldTag .FieldJson false }}`
{{.FieldName}} *{{.FieldType}} `json:"{{.FieldJson}}" form:"{{.FieldJson}}" `
{{- end }}
{{- end }}
{{- end}}
@@ -8,18 +8,8 @@
{{- if .IsAdd}}
// Get{{.StructName}}InfoList 新增搜索语句
{{- range .Fields}}
{{- if .FieldSearchType}}
{{- if or (eq .FieldType "enum") (eq .FieldType "pictures") (eq .FieldType "picture") (eq .FieldType "video") (eq .FieldType "json") }}
{{ formatSearchCondition .ColumnName .FieldSearchType .FieldName .FieldType }}
{{- else if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
{{ formatBetweenCondition .ColumnName .FieldSearchType .FieldName }}
{{- else}}
{{ formatSearchCondition .ColumnName .FieldSearchType .FieldName .FieldType }}
{{- end }}
{{- end }}
{{- end }}
{{ GenerateSearchConditions .Fields }}
// Get{{.StructName}}InfoList 新增排序语句 请自行在搜索语句中添加orderMap内容
{{- range .Fields}}
@@ -33,13 +23,7 @@ orderMap["{{.ColumnName}}"] = true
// Get{{.StructName}}DataSource()方法新增关联语句
{{range $key, $value := .DataSourceMap}}
{{$key}} := make([]map[string]any, 0)
{{ $dataDB := "" }}
{{- if eq $value.DBName "" }}
{{ $dataDB = $db }}
{{- else}}
{{ $dataDB = printf "global.MustGetGlobalDBByDBName(\"%s\")" $value.DBName }}
{{- end}}
{{$dataDB}}.Table("{{$value.Table}}"){{- if $value.HasDeletedAt}}.Where("deleted_at IS NULL"){{ end }}.Select("{{$value.Label}} as label,{{$value.Value}} as value").Scan(&{{$key}})
{{$db}}.Table("{{$value.Table}}"){{- if $value.HasDeletedAt}}.Where("deleted_at IS NULL"){{ end }}.Select("{{$value.Label}} as label,{{$value.Value}} as value").Scan(&{{$key}})
res["{{$key}}"] = {{$key}}
{{- end }}
{{- end }}
@@ -175,23 +159,7 @@ func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList(ctx context.Context, info
db = db.Where("created_at BETWEEN ? AND ?", info.StartCreatedAt, info.EndCreatedAt)
}
{{- end }}
{{- range .Fields}}
{{- if .FieldSearchType}}
{{- if or (eq .FieldType "enum") (eq .FieldType "pictures") (eq .FieldType "picture") (eq .FieldType "video") (eq .FieldType "json") }}
if info.{{.FieldName}} != "" {
{{- if or (eq .FieldType "enum")}}
{{ formatLikeCondition .ColumnName .FieldName }}
{{- else}}
// 数据类型为复杂类型,请根据业务需求自行实现复杂类型的查询业务
{{- end}}
}
{{- else if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
{{ formatBetweenCondition .ColumnName .FieldSearchType .FieldName }}
{{- else}}
{{ formatSearchCondition .ColumnName .FieldSearchType .FieldName .FieldType }}
{{- end }}
{{- end }}
{{- end }}
{{ GenerateSearchConditions .Fields }}
err = db.Count(&total).Error
if err!=nil {
return
@@ -199,6 +167,10 @@ func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList(ctx context.Context, info
{{- if .NeedSort}}
var OrderStr string
orderMap := make(map[string]bool)
{{- if .GvaModel }}
orderMap["ID"] = true
orderMap["CreatedAt"] = true
{{- end }}
{{- range .Fields}}
{{- if .Sort}}
orderMap["{{.ColumnName}}"] = true
@@ -225,13 +197,7 @@ func (s *{{.Abbreviation}})Get{{.StructName}}DataSource(ctx context.Context) (re
res = make(map[string][]map[string]any)
{{range $key, $value := .DataSourceMap}}
{{$key}} := make([]map[string]any, 0)
{{ $dataDB := "" }}
{{- if eq $value.DBName "" }}
{{ $dataDB = $db }}
{{- else}}
{{ $dataDB = printf "global.MustGetGlobalDBByDBName(\"%s\")" $value.DBName }}
{{- end}}
{{$dataDB}}.Table("{{$value.Table}}"){{- if $value.HasDeletedAt}}.Where("deleted_at IS NULL"){{ end }}.Select("{{$value.Label}} as label,{{$value.Value}} as value").Scan(&{{$key}})
{{$db}}.Table("{{$value.Table}}"){{- if $value.HasDeletedAt}}.Where("deleted_at IS NULL"){{ end }}.Select("{{$value.Label}} as label,{{$value.Value}} as value").Scan(&{{$key}})
res["{{$key}}"] = {{$key}}
{{- end }}
return