🎨 移除多余模块
This commit is contained in:
@@ -3,7 +3,6 @@ package ast
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/printer"
|
||||
@@ -22,7 +21,7 @@ func RollGormBack(pk, model string) {
|
||||
// 首先分析存在多少个ttt作为调用方的node块
|
||||
// 如果多个 仅仅删除对应块即可
|
||||
// 如果单个 那么还需要剔除import
|
||||
path := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, "initialize", "gorm_biz.go")
|
||||
path := filepath.Join(resolveServerRoot(), "initialize", "gorm_biz.go")
|
||||
src, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -99,7 +98,7 @@ func RollRouterBack(pk, model string) {
|
||||
// 首先抓到所有的代码块结构 {}
|
||||
// 分析结构中是否存在一个变量叫做 pk+Router
|
||||
// 然后获取到代码块指针 对内部需要回滚的代码进行剔除
|
||||
path := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, "initialize", "router_biz.go")
|
||||
path := filepath.Join(resolveServerRoot(), "initialize", "router_biz.go")
|
||||
src, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
||||
@@ -20,12 +20,6 @@ func (r Type) Group() string {
|
||||
return "RouterGroup"
|
||||
case TypePackageServiceModuleEnter:
|
||||
return "ServiceGroup"
|
||||
case TypePluginApiEnter:
|
||||
return "api"
|
||||
case TypePluginRouterEnter:
|
||||
return "router"
|
||||
case TypePluginServiceEnter:
|
||||
return "service"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
@@ -40,14 +34,4 @@ const (
|
||||
TypePackageServiceModuleEnter = "PackageServiceModuleEnter" // server/service/{package}/enter.go
|
||||
TypePackageInitializeGorm = "PackageInitializeGorm" // server/initialize/gorm_biz.go
|
||||
TypePackageInitializeRouter = "PackageInitializeRouter" // server/initialize/router_biz.go
|
||||
TypePluginGen = "PluginGen" // server/plugin/{package}/gen/main.go
|
||||
TypePluginApiEnter = "PluginApiEnter" // server/plugin/{package}/enter.go
|
||||
TypePluginInitializeV1 = "PluginInitializeV1" // server/initialize/plugin_biz_v1.go
|
||||
TypePluginInitializeV2 = "PluginInitializeV2" // server/plugin/register.go
|
||||
TypePluginRouterEnter = "PluginRouterEnter" // server/plugin/{package}/enter.go
|
||||
TypePluginServiceEnter = "PluginServiceEnter" // server/plugin/{package}/enter.go
|
||||
TypePluginInitializeApi = "PluginInitializeApi" // server/plugin/{package}/initialize/api.go
|
||||
TypePluginInitializeGorm = "PluginInitializeGorm" // server/plugin/{package}/initialize/gorm.go
|
||||
TypePluginInitializeMenu = "PluginInitializeMenu" // server/plugin/{package}/initialize/menu.go
|
||||
TypePluginInitializeRouter = "PluginInitializeRouter" // server/plugin/{package}/initialize/router.go
|
||||
)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/pkg/errors"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
@@ -61,7 +60,7 @@ func (a *Base) Format(filename string, writer io.Writer, file *ast.File) error {
|
||||
|
||||
// RelativePath 绝对路径转相对路径
|
||||
func (a *Base) RelativePath(filePath string) string {
|
||||
server := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server)
|
||||
server := resolveServerRoot()
|
||||
hasServer := strings.Index(filePath, server)
|
||||
if hasServer != -1 {
|
||||
filePath = strings.TrimPrefix(filePath, server)
|
||||
@@ -73,9 +72,30 @@ func (a *Base) RelativePath(filePath string) string {
|
||||
|
||||
// AbsolutePath 相对路径转绝对路径
|
||||
func (a *Base) AbsolutePath(filePath string) string {
|
||||
server := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server)
|
||||
server := resolveServerRoot()
|
||||
keys := strings.Split(filePath, "/")
|
||||
filePath = filepath.Join(keys...)
|
||||
filePath = filepath.Join(server, filePath)
|
||||
return filePath
|
||||
}
|
||||
|
||||
func resolveProjectRoot() string {
|
||||
if cwd, err := os.Getwd(); err == nil {
|
||||
if filepath.Base(cwd) == "server" {
|
||||
return filepath.Dir(cwd)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(cwd, "server")); err == nil {
|
||||
return cwd
|
||||
}
|
||||
return cwd
|
||||
}
|
||||
return "."
|
||||
}
|
||||
|
||||
func resolveServerRoot() string {
|
||||
root := resolveProjectRoot()
|
||||
if filepath.Base(root) == "server" {
|
||||
return root
|
||||
}
|
||||
return filepath.Join(root, "server")
|
||||
}
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"io"
|
||||
)
|
||||
|
||||
// PluginEnter 插件化入口
|
||||
// ModuleName := PackageName.GroupName.ServiceName
|
||||
type PluginEnter struct {
|
||||
Base
|
||||
Type Type // 类型
|
||||
Path string // 文件路径
|
||||
ImportPath string // 导包路径
|
||||
RelativePath string // 相对路径
|
||||
StructName string // 结构体名称
|
||||
StructCamelName string // 结构体小驼峰名称
|
||||
ModuleName string // 模块名称
|
||||
GroupName string // 分组名称
|
||||
PackageName string // 包名
|
||||
ServiceName string // 服务名称
|
||||
}
|
||||
|
||||
func (a *PluginEnter) Parse(filename string, writer io.Writer) (file *ast.File, err error) {
|
||||
if filename == "" {
|
||||
if a.RelativePath == "" {
|
||||
filename = a.Path
|
||||
a.RelativePath = a.Base.RelativePath(a.Path)
|
||||
return a.Base.Parse(filename, writer)
|
||||
}
|
||||
a.Path = a.Base.AbsolutePath(a.RelativePath)
|
||||
filename = a.Path
|
||||
}
|
||||
return a.Base.Parse(filename, writer)
|
||||
}
|
||||
|
||||
func (a *PluginEnter) Rollback(file *ast.File) error {
|
||||
//回滚结构体内内容
|
||||
var structType *ast.StructType
|
||||
ast.Inspect(file, func(n ast.Node) bool {
|
||||
switch x := n.(type) {
|
||||
case *ast.TypeSpec:
|
||||
if s, ok := x.Type.(*ast.StructType); ok {
|
||||
structType = s
|
||||
for i, field := range x.Type.(*ast.StructType).Fields.List {
|
||||
if len(field.Names) > 0 && field.Names[0].Name == a.StructName {
|
||||
s.Fields.List = append(s.Fields.List[:i], s.Fields.List[i+1:]...)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if len(structType.Fields.List) == 0 {
|
||||
_ = NewImport(a.ImportPath).Rollback(file)
|
||||
}
|
||||
|
||||
if a.Type == TypePluginServiceEnter {
|
||||
return nil
|
||||
}
|
||||
|
||||
//回滚变量内容
|
||||
ast.Inspect(file, func(n ast.Node) bool {
|
||||
genDecl, ok := n.(*ast.GenDecl)
|
||||
if ok && genDecl.Tok == token.VAR {
|
||||
for i, spec := range genDecl.Specs {
|
||||
valueSpec, vsok := spec.(*ast.ValueSpec)
|
||||
if vsok {
|
||||
for _, name := range valueSpec.Names {
|
||||
if name.Name == a.ModuleName {
|
||||
genDecl.Specs = append(genDecl.Specs[:i], genDecl.Specs[i+1:]...)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PluginEnter) Injection(file *ast.File) error {
|
||||
_ = NewImport(a.ImportPath).Injection(file)
|
||||
|
||||
has := false
|
||||
hasVar := false
|
||||
var firstStruct *ast.StructType
|
||||
var varSpec *ast.GenDecl
|
||||
//寻找是否存在结构且定位
|
||||
ast.Inspect(file, func(n ast.Node) bool {
|
||||
switch x := n.(type) {
|
||||
case *ast.TypeSpec:
|
||||
if s, ok := x.Type.(*ast.StructType); ok {
|
||||
firstStruct = s
|
||||
for _, field := range x.Type.(*ast.StructType).Fields.List {
|
||||
if len(field.Names) > 0 && field.Names[0].Name == a.StructName {
|
||||
has = true
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if !has {
|
||||
field := &ast.Field{
|
||||
Names: []*ast.Ident{{Name: a.StructName}},
|
||||
Type: &ast.Ident{Name: a.StructCamelName},
|
||||
}
|
||||
firstStruct.Fields.List = append(firstStruct.Fields.List, field)
|
||||
}
|
||||
|
||||
if a.Type == TypePluginServiceEnter {
|
||||
return nil
|
||||
}
|
||||
|
||||
//寻找是否存在变量且定位
|
||||
ast.Inspect(file, func(n ast.Node) bool {
|
||||
genDecl, ok := n.(*ast.GenDecl)
|
||||
if ok && genDecl.Tok == token.VAR {
|
||||
for _, spec := range genDecl.Specs {
|
||||
valueSpec, vsok := spec.(*ast.ValueSpec)
|
||||
if vsok {
|
||||
varSpec = genDecl
|
||||
for _, name := range valueSpec.Names {
|
||||
if name.Name == a.ModuleName {
|
||||
hasVar = true
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if !hasVar {
|
||||
spec := &ast.ValueSpec{
|
||||
Names: []*ast.Ident{{Name: a.ModuleName}},
|
||||
Values: []ast.Expr{
|
||||
&ast.SelectorExpr{
|
||||
X: &ast.SelectorExpr{
|
||||
X: &ast.Ident{Name: a.PackageName},
|
||||
Sel: &ast.Ident{Name: a.GroupName},
|
||||
},
|
||||
Sel: &ast.Ident{Name: a.ServiceName},
|
||||
},
|
||||
},
|
||||
}
|
||||
varSpec.Specs = append(varSpec.Specs, spec)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PluginEnter) Format(filename string, writer io.Writer, file *ast.File) error {
|
||||
if filename == "" {
|
||||
filename = a.Path
|
||||
}
|
||||
return a.Base.Format(filename, writer, file)
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"io"
|
||||
)
|
||||
|
||||
type PluginGen struct {
|
||||
Base
|
||||
Type Type // 类型
|
||||
Path string // 文件路径
|
||||
ImportPath string // 导包路径
|
||||
RelativePath string // 相对路径
|
||||
StructName string // 结构体名称
|
||||
PackageName string // 包名
|
||||
IsNew bool // 是否使用new关键字
|
||||
}
|
||||
|
||||
func (a *PluginGen) Parse(filename string, writer io.Writer) (file *ast.File, err error) {
|
||||
if filename == "" {
|
||||
if a.RelativePath == "" {
|
||||
filename = a.Path
|
||||
a.RelativePath = a.Base.RelativePath(a.Path)
|
||||
return a.Base.Parse(filename, writer)
|
||||
}
|
||||
a.Path = a.Base.AbsolutePath(a.RelativePath)
|
||||
filename = a.Path
|
||||
}
|
||||
return a.Base.Parse(filename, writer)
|
||||
}
|
||||
func (a *PluginGen) Rollback(file *ast.File) error {
|
||||
for i := 0; i < len(file.Decls); i++ {
|
||||
v1, o1 := file.Decls[i].(*ast.FuncDecl)
|
||||
if o1 {
|
||||
for j := 0; j < len(v1.Body.List); j++ {
|
||||
v2, o2 := v1.Body.List[j].(*ast.ExprStmt)
|
||||
if o2 {
|
||||
v3, o3 := v2.X.(*ast.CallExpr)
|
||||
if o3 {
|
||||
v4, o4 := v3.Fun.(*ast.SelectorExpr)
|
||||
if o4 {
|
||||
if v4.Sel.Name != "ApplyBasic" {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < len(v3.Args); k++ {
|
||||
v5, o5 := v3.Args[k].(*ast.CallExpr)
|
||||
if o5 {
|
||||
v6, o6 := v5.Fun.(*ast.Ident)
|
||||
if o6 {
|
||||
if v6.Name != "new" {
|
||||
continue
|
||||
}
|
||||
for l := 0; l < len(v5.Args); l++ {
|
||||
v7, o7 := v5.Args[l].(*ast.SelectorExpr)
|
||||
if o7 {
|
||||
v8, o8 := v7.X.(*ast.Ident)
|
||||
if o8 {
|
||||
if v8.Name == a.PackageName && v7.Sel.Name == a.StructName {
|
||||
v3.Args = append(v3.Args[:k], v3.Args[k+1:]...)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if k >= len(v3.Args) {
|
||||
break
|
||||
}
|
||||
v6, o6 := v3.Args[k].(*ast.CompositeLit)
|
||||
if o6 {
|
||||
v7, o7 := v6.Type.(*ast.SelectorExpr)
|
||||
if o7 {
|
||||
v8, o8 := v7.X.(*ast.Ident)
|
||||
if o8 {
|
||||
if v8.Name == a.PackageName && v7.Sel.Name == a.StructName {
|
||||
v3.Args = append(v3.Args[:k], v3.Args[k+1:]...)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(v3.Args) == 0 {
|
||||
_ = NewImport(a.ImportPath).Rollback(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PluginGen) Injection(file *ast.File) error {
|
||||
_ = NewImport(a.ImportPath).Injection(file)
|
||||
for i := 0; i < len(file.Decls); i++ {
|
||||
v1, o1 := file.Decls[i].(*ast.FuncDecl)
|
||||
if o1 {
|
||||
for j := 0; j < len(v1.Body.List); j++ {
|
||||
v2, o2 := v1.Body.List[j].(*ast.ExprStmt)
|
||||
if o2 {
|
||||
v3, o3 := v2.X.(*ast.CallExpr)
|
||||
if o3 {
|
||||
v4, o4 := v3.Fun.(*ast.SelectorExpr)
|
||||
if o4 {
|
||||
if v4.Sel.Name != "ApplyBasic" {
|
||||
continue
|
||||
}
|
||||
var has bool
|
||||
for k := 0; k < len(v3.Args); k++ {
|
||||
v5, o5 := v3.Args[k].(*ast.CallExpr)
|
||||
if o5 {
|
||||
v6, o6 := v5.Fun.(*ast.Ident)
|
||||
if o6 {
|
||||
if v6.Name != "new" {
|
||||
continue
|
||||
}
|
||||
for l := 0; l < len(v5.Args); l++ {
|
||||
v7, o7 := v5.Args[l].(*ast.SelectorExpr)
|
||||
if o7 {
|
||||
v8, o8 := v7.X.(*ast.Ident)
|
||||
if o8 {
|
||||
if v8.Name == a.PackageName && v7.Sel.Name == a.StructName {
|
||||
has = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
v6, o6 := v3.Args[k].(*ast.CompositeLit)
|
||||
if o6 {
|
||||
v7, o7 := v6.Type.(*ast.SelectorExpr)
|
||||
if o7 {
|
||||
v8, o8 := v7.X.(*ast.Ident)
|
||||
if o8 {
|
||||
if v8.Name == a.PackageName && v7.Sel.Name == a.StructName {
|
||||
has = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !has {
|
||||
if a.IsNew {
|
||||
arg := &ast.CallExpr{
|
||||
Fun: &ast.Ident{Name: "\n\t\tnew"},
|
||||
Args: []ast.Expr{
|
||||
&ast.SelectorExpr{
|
||||
X: &ast.Ident{Name: a.PackageName},
|
||||
Sel: &ast.Ident{Name: a.StructName},
|
||||
},
|
||||
},
|
||||
}
|
||||
v3.Args = append(v3.Args, arg)
|
||||
v3.Args = append(v3.Args, &ast.BasicLit{
|
||||
Kind: token.STRING,
|
||||
Value: "\n",
|
||||
})
|
||||
break
|
||||
}
|
||||
arg := &ast.CompositeLit{
|
||||
Type: &ast.SelectorExpr{
|
||||
X: &ast.Ident{Name: a.PackageName},
|
||||
Sel: &ast.Ident{Name: a.StructName},
|
||||
},
|
||||
}
|
||||
v3.Args = append(v3.Args, arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PluginGen) Format(filename string, writer io.Writer, file *ast.File) error {
|
||||
if filename == "" {
|
||||
filename = a.Path
|
||||
}
|
||||
return a.Base.Format(filename, writer, file)
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"io"
|
||||
)
|
||||
|
||||
type PluginInitializeGorm struct {
|
||||
Base
|
||||
Type Type // 类型
|
||||
Path string // 文件路径
|
||||
ImportPath string // 导包路径
|
||||
RelativePath string // 相对路径
|
||||
StructName string // 结构体名称
|
||||
PackageName string // 包名
|
||||
IsNew bool // 是否使用new关键字 true: new(PackageName.StructName) false: &PackageName.StructName{}
|
||||
}
|
||||
|
||||
func (a *PluginInitializeGorm) Parse(filename string, writer io.Writer) (file *ast.File, err error) {
|
||||
if filename == "" {
|
||||
if a.RelativePath == "" {
|
||||
filename = a.Path
|
||||
a.RelativePath = a.Base.RelativePath(a.Path)
|
||||
return a.Base.Parse(filename, writer)
|
||||
}
|
||||
a.Path = a.Base.AbsolutePath(a.RelativePath)
|
||||
filename = a.Path
|
||||
}
|
||||
return a.Base.Parse(filename, writer)
|
||||
}
|
||||
|
||||
func (a *PluginInitializeGorm) Rollback(file *ast.File) error {
|
||||
var needRollBackImport bool
|
||||
ast.Inspect(file, func(n ast.Node) bool {
|
||||
callExpr, ok := n.(*ast.CallExpr)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
|
||||
selExpr, seok := callExpr.Fun.(*ast.SelectorExpr)
|
||||
if !seok || selExpr.Sel.Name != "AutoMigrate" {
|
||||
return true
|
||||
}
|
||||
if len(callExpr.Args) <= 1 {
|
||||
needRollBackImport = true
|
||||
}
|
||||
// 删除指定的参数
|
||||
for i, arg := range callExpr.Args {
|
||||
compLit, cok := arg.(*ast.CompositeLit)
|
||||
if !cok {
|
||||
continue
|
||||
}
|
||||
|
||||
cselExpr, sok := compLit.Type.(*ast.SelectorExpr)
|
||||
if !sok {
|
||||
continue
|
||||
}
|
||||
|
||||
ident, idok := cselExpr.X.(*ast.Ident)
|
||||
if idok && ident.Name == a.PackageName && cselExpr.Sel.Name == a.StructName {
|
||||
// 删除参数
|
||||
callExpr.Args = append(callExpr.Args[:i], callExpr.Args[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
if needRollBackImport {
|
||||
_ = NewImport(a.ImportPath).Rollback(file)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PluginInitializeGorm) Injection(file *ast.File) error {
|
||||
_ = NewImport(a.ImportPath).Injection(file)
|
||||
var call *ast.CallExpr
|
||||
ast.Inspect(file, func(n ast.Node) bool {
|
||||
callExpr, ok := n.(*ast.CallExpr)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
|
||||
selExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
|
||||
if ok && selExpr.Sel.Name == "AutoMigrate" {
|
||||
call = callExpr
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
arg := &ast.CompositeLit{
|
||||
Type: &ast.SelectorExpr{
|
||||
X: &ast.Ident{Name: a.PackageName},
|
||||
Sel: &ast.Ident{Name: a.StructName},
|
||||
},
|
||||
}
|
||||
|
||||
call.Args = append(call.Args, arg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PluginInitializeGorm) Format(filename string, writer io.Writer, file *ast.File) error {
|
||||
if filename == "" {
|
||||
filename = a.Path
|
||||
}
|
||||
return a.Base.Format(filename, writer, file)
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"io"
|
||||
)
|
||||
|
||||
// PluginInitializeRouter 插件初始化路由
|
||||
// PackageName.AppName.GroupName.FunctionName()
|
||||
type PluginInitializeRouter struct {
|
||||
Base
|
||||
Type Type // 类型
|
||||
Path string // 文件路径
|
||||
ImportPath string // 导包路径
|
||||
ImportGlobalPath string // 导包全局变量路径
|
||||
ImportMiddlewarePath string // 导包中间件路径
|
||||
RelativePath string // 相对路径
|
||||
AppName string // 应用名称
|
||||
GroupName string // 分组名称
|
||||
PackageName string // 包名
|
||||
FunctionName string // 函数名
|
||||
LeftRouterGroupName string // 左路由分组名称
|
||||
RightRouterGroupName string // 右路由分组名称
|
||||
}
|
||||
|
||||
func (a *PluginInitializeRouter) Parse(filename string, writer io.Writer) (file *ast.File, err error) {
|
||||
if filename == "" {
|
||||
if a.RelativePath == "" {
|
||||
filename = a.Path
|
||||
a.RelativePath = a.Base.RelativePath(a.Path)
|
||||
return a.Base.Parse(filename, writer)
|
||||
}
|
||||
a.Path = a.Base.AbsolutePath(a.RelativePath)
|
||||
filename = a.Path
|
||||
}
|
||||
return a.Base.Parse(filename, writer)
|
||||
}
|
||||
|
||||
func (a *PluginInitializeRouter) Rollback(file *ast.File) error {
|
||||
funcDecl := FindFunction(file, "Router")
|
||||
delI := 0
|
||||
routerNum := 0
|
||||
for i := len(funcDecl.Body.List) - 1; i >= 0; i-- {
|
||||
stmt, ok := funcDecl.Body.List[i].(*ast.ExprStmt)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
callExpr, ok := stmt.X.(*ast.CallExpr)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
selExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
ident, ok := selExpr.X.(*ast.SelectorExpr)
|
||||
|
||||
if ok {
|
||||
if iExpr, ieok := ident.X.(*ast.SelectorExpr); ieok {
|
||||
if iden, idok := iExpr.X.(*ast.Ident); idok {
|
||||
if iden.Name == "router" {
|
||||
routerNum++
|
||||
}
|
||||
}
|
||||
}
|
||||
if ident.Sel.Name == a.GroupName && selExpr.Sel.Name == a.FunctionName {
|
||||
// 删除语句
|
||||
delI = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
funcDecl.Body.List = append(funcDecl.Body.List[:delI], funcDecl.Body.List[delI+1:]...)
|
||||
|
||||
if routerNum <= 1 {
|
||||
_ = NewImport(a.ImportPath).Rollback(file)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PluginInitializeRouter) Injection(file *ast.File) error {
|
||||
_ = NewImport(a.ImportPath).Injection(file)
|
||||
funcDecl := FindFunction(file, "Router")
|
||||
|
||||
var exists bool
|
||||
|
||||
ast.Inspect(funcDecl, func(n ast.Node) bool {
|
||||
callExpr, ok := n.(*ast.CallExpr)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
|
||||
selExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
|
||||
ident, ok := selExpr.X.(*ast.SelectorExpr)
|
||||
if ok && ident.Sel.Name == a.GroupName && selExpr.Sel.Name == a.FunctionName {
|
||||
exists = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if !exists {
|
||||
stmtStr := fmt.Sprintf("%s.%s.%s.%s(%s, %s)", a.PackageName, a.AppName, a.GroupName, a.FunctionName, a.LeftRouterGroupName, a.RightRouterGroupName)
|
||||
stmt := CreateStmt(stmtStr)
|
||||
funcDecl.Body.List = append(funcDecl.Body.List, stmt)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PluginInitializeRouter) Format(filename string, writer io.Writer, file *ast.File) error {
|
||||
if filename == "" {
|
||||
filename = a.Path
|
||||
}
|
||||
return a.Base.Format(filename, writer, file)
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type PluginInitializeV2 struct {
|
||||
Base
|
||||
Type Type // 类型
|
||||
Path string // 文件路径
|
||||
PluginPath string // 插件路径
|
||||
RelativePath string // 相对路径
|
||||
ImportPath string // 导包路径
|
||||
StructName string // 结构体名称
|
||||
PackageName string // 包名
|
||||
}
|
||||
|
||||
func (a *PluginInitializeV2) Parse(filename string, writer io.Writer) (file *ast.File, err error) {
|
||||
if filename == "" {
|
||||
if a.RelativePath == "" {
|
||||
filename = a.PluginPath
|
||||
a.RelativePath = a.Base.RelativePath(a.PluginPath)
|
||||
return a.Base.Parse(filename, writer)
|
||||
}
|
||||
a.PluginPath = a.Base.AbsolutePath(a.RelativePath)
|
||||
filename = a.PluginPath
|
||||
}
|
||||
return a.Base.Parse(filename, writer)
|
||||
}
|
||||
|
||||
func (a *PluginInitializeV2) Injection(file *ast.File) error {
|
||||
importPath := strings.TrimSpace(a.ImportPath)
|
||||
if importPath == "" {
|
||||
return nil
|
||||
}
|
||||
importPath = strings.Trim(importPath, "\"")
|
||||
if importPath == "" || CheckImport(file, importPath) {
|
||||
return nil
|
||||
}
|
||||
|
||||
importSpec := &ast.ImportSpec{
|
||||
Name: ast.NewIdent("_"),
|
||||
Path: &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote(importPath)},
|
||||
}
|
||||
var importDecl *ast.GenDecl
|
||||
for _, decl := range file.Decls {
|
||||
genDecl, ok := decl.(*ast.GenDecl)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if genDecl.Tok == token.IMPORT {
|
||||
importDecl = genDecl
|
||||
break
|
||||
}
|
||||
}
|
||||
if importDecl == nil {
|
||||
file.Decls = append([]ast.Decl{
|
||||
&ast.GenDecl{
|
||||
Tok: token.IMPORT,
|
||||
Specs: []ast.Spec{importSpec},
|
||||
},
|
||||
}, file.Decls...)
|
||||
return nil
|
||||
}
|
||||
importDecl.Specs = append(importDecl.Specs, importSpec)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PluginInitializeV2) Rollback(file *ast.File) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PluginInitializeV2) Format(filename string, writer io.Writer, file *ast.File) error {
|
||||
if filename == "" {
|
||||
filename = a.PluginPath
|
||||
}
|
||||
return a.Base.Format(filename, writer, file)
|
||||
}
|
||||
@@ -1,713 +0,0 @@
|
||||
package autocode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
|
||||
"slices"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// GetTemplateFuncMap 返回模板函数映射,用于在模板中使用
|
||||
func GetTemplateFuncMap() template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"title": strings.Title,
|
||||
"GenerateField": GenerateField,
|
||||
"GenerateSearchField": GenerateSearchField,
|
||||
"GenerateSearchConditions": GenerateSearchConditions,
|
||||
"GenerateSearchFormItem": GenerateSearchFormItem,
|
||||
"GenerateTableColumn": GenerateTableColumn,
|
||||
"GenerateFormItem": GenerateFormItem,
|
||||
"GenerateDescriptionItem": GenerateDescriptionItem,
|
||||
"GenerateDefaultFormValue": GenerateDefaultFormValue,
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染Model中的字段
|
||||
func GenerateField(field systemReq.AutoCodeField) string {
|
||||
// 构建gorm标签
|
||||
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 + ";"
|
||||
|
||||
// 对于int类型,根据DataTypeLong决定具体的Go类型,不使用size标签
|
||||
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)
|
||||
|
||||
// 对于int类型,根据DataTypeLong决定具体的Go类型
|
||||
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"
|
||||
case "11", "12", "13", "14", "15", "16", "17", "18", "19", "20":
|
||||
fieldType = "int64"
|
||||
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
|
||||
}
|
||||
|
||||
// 格式化搜索条件语句
|
||||
func GenerateSearchConditions(fields []*systemReq.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 {
|
||||
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, "")
|
||||
}
|
||||
|
||||
// 格式化前端搜索条件
|
||||
func GenerateSearchFormItem(field systemReq.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 generates HTML for table column based on field properties
|
||||
func GenerateTableColumn(field systemReq.AutoCodeField) string {
|
||||
// Add sortable attribute if needed
|
||||
sortAttr := ""
|
||||
if field.Sort {
|
||||
sortAttr = " sortable"
|
||||
}
|
||||
|
||||
// Handle different field types
|
||||
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
|
||||
`
|
||||
result += ` style="width: 100px; height: 100px"
|
||||
`
|
||||
result += ` muted
|
||||
`
|
||||
result += ` preload="metadata"
|
||||
`
|
||||
result += ` >
|
||||
`
|
||||
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
|
||||
} else {
|
||||
return fmt.Sprintf(`<el-table-column%s align="left" label="%s" prop="%s" width="120" />
|
||||
`,
|
||||
sortAttr, field.FieldDesc, field.FieldJson)
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateFormItem(field systemReq.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
|
||||
}
|
||||
|
||||
func GenerateDescriptionItem(field systemReq.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
|
||||
}
|
||||
|
||||
func GenerateDefaultFormValue(field systemReq.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 systemReq.AutoCodeField) string {
|
||||
var result string
|
||||
|
||||
if field.FieldSearchType == "" {
|
||||
return "" // 如果没有搜索类型,返回空字符串
|
||||
}
|
||||
|
||||
if field.FieldSearchType == "BETWEEN" || field.FieldSearchType == "NOT BETWEEN" {
|
||||
// 生成范围搜索字段
|
||||
// time 的情况
|
||||
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.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
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const (
|
||||
OnlyFuncName = "Plugin"
|
||||
)
|
||||
|
||||
// Plugin 插件模式接口化
|
||||
type Plugin interface {
|
||||
// Register 注册路由
|
||||
Register(group *gin.RouterGroup)
|
||||
|
||||
// RouterPath 用户返回注册路由
|
||||
RouterPath() string
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Plugin 插件模式接口化v2
|
||||
type Plugin interface {
|
||||
// Register 注册路由
|
||||
Register(group *gin.Engine)
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package plugin
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
registryMu sync.RWMutex
|
||||
registry []Plugin
|
||||
)
|
||||
|
||||
// Register records a plugin for auto initialization.
|
||||
func Register(p Plugin) {
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
registryMu.Lock()
|
||||
registry = append(registry, p)
|
||||
registryMu.Unlock()
|
||||
}
|
||||
|
||||
// Registered returns a snapshot of all registered plugins.
|
||||
func Registered() []Plugin {
|
||||
registryMu.RLock()
|
||||
defer registryMu.RUnlock()
|
||||
out := make([]Plugin, len(registry))
|
||||
copy(out, registry)
|
||||
return out
|
||||
}
|
||||
@@ -8,9 +8,6 @@ var (
|
||||
LoginVerify = Rules{"Username": {NotEmpty()}, "Password": {NotEmpty()}}
|
||||
RegisterVerify = Rules{"Username": {NotEmpty()}, "NickName": {NotEmpty()}, "Password": {NotEmpty()}, "AuthorityId": {NotEmpty()}}
|
||||
PageInfoVerify = Rules{"Page": {NotEmpty()}, "PageSize": {NotEmpty()}}
|
||||
CustomerVerify = Rules{"CustomerName": {NotEmpty()}, "CustomerPhoneData": {NotEmpty()}}
|
||||
AutoCodeVerify = Rules{"Abbreviation": {NotEmpty()}, "StructName": {NotEmpty()}, "PackageName": {NotEmpty()}}
|
||||
AutoPackageVerify = Rules{"PackageName": {NotEmpty()}}
|
||||
AuthorityVerify = Rules{"AuthorityId": {NotEmpty()}, "AuthorityName": {NotEmpty()}}
|
||||
AuthorityIdVerify = Rules{"AuthorityId": {NotEmpty()}}
|
||||
OldAuthorityVerify = Rules{"OldAuthorityId": {NotEmpty()}}
|
||||
|
||||
Reference in New Issue
Block a user