🎨 移除多余模块

This commit is contained in:
2026-04-08 12:19:24 +08:00
parent 22bb5fdc94
commit 7599146f24
192 changed files with 623 additions and 13983 deletions

View File

@@ -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)

View File

@@ -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
)

View File

@@ -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")
}

View File

@@ -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)
}

View 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)
}

View 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)
}

View 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)
}

View 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)
}

View 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
}

View File

@@ -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
}

View File

@@ -1,11 +0,0 @@
package plugin
import (
"github.com/gin-gonic/gin"
)
// Plugin 插件模式接口化v2
type Plugin interface {
// Register 注册路由
Register(group *gin.Engine)
}

View File

@@ -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
}

View File

@@ -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()}}