kra/internal/biz/system/auto_code_template.go

706 lines
24 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package system
import (
"context"
"encoding/json"
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/token"
"os"
"path/filepath"
"strings"
"text/template"
"github.com/go-kratos/kratos/v2/log"
"github.com/pkg/errors"
"gorm.io/gorm"
"kra/internal/conf"
"kra/pkg/utils"
"kra/pkg/utils/autocode"
)
// AutoCodeTemplateRepo 自动代码模板仓储接口
type AutoCodeTemplateRepo interface {
GetPackageByName(ctx context.Context, packageName string) (*SysAutoCodePackage, error)
CreateApis(ctx context.Context, apis []SysApi) ([]uint, error)
GetMenuByName(ctx context.Context, name string) (*SysBaseMenu, error)
CreateMenu(ctx context.Context, menu *SysBaseMenu) error
CreateExportTemplate(ctx context.Context, tpl *SysExportTemplate) error
Repeat(ctx context.Context, businessDB, structName, abbreviation, pkg string) bool
}
// AutoCodeTemplateUsecase 自动代码模板用例
type AutoCodeTemplateUsecase struct {
repo AutoCodeTemplateRepo
historyRepo AutoCodeHistoryRepo
packageRepo AutoCodePackageRepo
config *conf.AutoCodeConfig
log *log.Helper
db *gorm.DB
}
// NewAutoCodeTemplateUsecase 创建自动代码模板用例
func NewAutoCodeTemplateUsecase(
repo AutoCodeTemplateRepo,
historyRepo AutoCodeHistoryRepo,
packageRepo AutoCodePackageRepo,
config *conf.AutoCodeConfig,
logger log.Logger,
db *gorm.DB,
) *AutoCodeTemplateUsecase {
return &AutoCodeTemplateUsecase{
repo: repo,
historyRepo: historyRepo,
packageRepo: packageRepo,
config: config,
log: log.NewHelper(logger),
db: db,
}
}
// checkPackage 检查包结构是否完整
// 支持 Kratos DDD 层次结构检查:
// - biz/{package}/enter.go - 业务逻辑层入口
// - data/{package}/enter.go - 数据访问层入口
// - service/{package}/enter.go - 服务层入口
// - server/handler/{package}/enter.go - HTTP Handler 层入口
// - server/router/{package}/enter.go - 路由层入口
func (uc *AutoCodeTemplateUsecase) checkPackage(pkg string, template string) error {
switch template {
case "package":
// Kratos DDD 架构目录检查
// 检查 Biz 层
bizEnter := filepath.Join(uc.config.Root, uc.config.Server, "internal", "biz", pkg, "enter.go")
if _, err := os.Stat(bizEnter); err != nil {
return fmt.Errorf("package结构异常,缺少internal/biz/%s/enter.go", pkg)
}
// 检查 Data 层
dataEnter := filepath.Join(uc.config.Root, uc.config.Server, "internal", "data", pkg, "enter.go")
if _, err := os.Stat(dataEnter); err != nil {
return fmt.Errorf("package结构异常,缺少internal/data/%s/enter.go", pkg)
}
// 检查 Service 层
serviceEnter := filepath.Join(uc.config.Root, uc.config.Server, "internal", "service", pkg, "enter.go")
if _, err := os.Stat(serviceEnter); err != nil {
return fmt.Errorf("package结构异常,缺少internal/service/%s/enter.go", pkg)
}
// 检查 Handler 层
handlerEnter := filepath.Join(uc.config.Root, uc.config.Server, "internal", "server", "handler", pkg, "enter.go")
if _, err := os.Stat(handlerEnter); err != nil {
return fmt.Errorf("package结构异常,缺少internal/server/handler/%s/enter.go", pkg)
}
// 检查 Router 层
routerEnter := filepath.Join(uc.config.Root, uc.config.Server, "internal", "server", "router", pkg, "enter.go")
if _, err := os.Stat(routerEnter); err != nil {
return fmt.Errorf("package结构异常,缺少internal/server/router/%s/enter.go", pkg)
}
case "plugin":
pluginEnter := filepath.Join(uc.config.Root, uc.config.Server, "internal", "plugin", pkg, "plugin.go")
if _, err := os.Stat(pluginEnter); err != nil {
return fmt.Errorf("plugin结构异常,缺少internal/plugin/%s/plugin.go", pkg)
}
}
return nil
}
// Create 创建生成自动化代码
func (uc *AutoCodeTemplateUsecase) Create(ctx context.Context, info *AutoCodeInfo) error {
// 查询包信息
autoPkg, err := uc.repo.GetPackageByName(ctx, info.Package)
if err != nil {
return errors.Wrap(err, "查询包失败!")
}
// 检查包结构
if err = uc.checkPackage(info.Package, autoPkg.Template); err != nil {
return err
}
// 检查重复创建
if uc.repo.Repeat(ctx, info.BusinessDB, info.StructName, info.Abbreviation, info.Package) {
return errors.New("已经创建过此数据结构,请勿重复创建!")
}
// 生成代码
generate, templates, injections, err := uc.generate(ctx, info, autoPkg)
if err != nil {
return err
}
// 写入文件
for key, builder := range generate {
if err = os.MkdirAll(filepath.Dir(key), os.ModePerm); err != nil {
return errors.Wrapf(err, "[filepath:%s]创建文件夹失败!", key)
}
if err = os.WriteFile(key, []byte(builder.String()), 0666); err != nil {
return errors.Wrapf(err, "[filepath:%s]写入文件失败!", key)
}
}
// 创建历史记录
history := &SysAutoCodeHistory{
Table: info.TableName,
Package: info.Package,
StructName: info.StructName,
Abbreviation: info.Abbreviation,
BusinessDB: info.BusinessDB,
Description: info.Description,
Templates: templates,
}
// 自动创建API
if info.AutoCreateApiToSql && !info.OnlyTemplate {
apis := uc.buildApis(info)
apiIDs, err := uc.repo.CreateApis(ctx, apis)
if err != nil {
return err
}
history.ApiIDs = apiIDs
}
// 自动创建菜单
if info.AutoCreateMenuToSql {
menu, err := uc.repo.GetMenuByName(ctx, info.Abbreviation)
if err == nil && menu != nil {
history.MenuID = menu.ID
} else {
newMenu := uc.buildMenu(info, autoPkg.Template)
if info.AutoCreateBtnAuth && !info.OnlyTemplate {
newMenu.MenuBtn = uc.buildMenuBtns(info)
}
if err = uc.repo.CreateMenu(ctx, newMenu); err != nil {
return errors.Wrap(err, "创建菜单失败!")
}
history.MenuID = newMenu.ID
}
}
// 处理Excel导出模板
if info.HasExcel {
exportTpl := uc.buildExportTemplate(info)
if err = uc.repo.CreateExportTemplate(ctx, exportTpl); err != nil {
return err
}
history.ExportTemplateID = exportTpl.ID
}
// 保存注入信息
history.Injections = make(map[string]string, len(injections))
for key, value := range injections {
bytes, _ := json.Marshal(value)
history.Injections[key] = string(bytes)
}
// 创建历史记录
return uc.historyRepo.Create(ctx, history)
}
// Preview 预览自动化代码
func (uc *AutoCodeTemplateUsecase) Preview(ctx context.Context, info *AutoCodeInfo) (map[string]string, error) {
// 查询包信息
entity, err := uc.repo.GetPackageByName(ctx, info.Package)
if err != nil {
return nil, errors.Wrap(err, "查询包失败!")
}
// 检查重复创建
if uc.repo.Repeat(ctx, info.BusinessDB, info.StructName, info.Abbreviation, info.Package) && !info.IsAdd {
return nil, errors.New("已经创建过此数据结构或重复简称,请勿重复创建!")
}
preview := make(map[string]string)
codes, _, _, err := uc.generate(ctx, info, entity)
if err != nil {
return nil, err
}
for key, writer := range codes {
if len(key) > len(uc.config.Root) {
key, _ = filepath.Rel(uc.config.Root, key)
}
suffix := filepath.Ext(key)[1:]
var builder strings.Builder
builder.WriteString("```" + suffix + "\n\n")
builder.WriteString(writer.String())
builder.WriteString("\n\n```")
preview[key] = builder.String()
}
return preview, nil
}
// generate 生成代码
func (uc *AutoCodeTemplateUsecase) generate(ctx context.Context, info *AutoCodeInfo, entity *SysAutoCodePackage) (map[string]strings.Builder, map[string]string, map[string]interface{}, error) {
dataList, asts, fileList, err := uc.packageRepo.Templates(ctx, entity, info, false)
if err != nil {
return nil, nil, nil, err
}
code := make(map[string]strings.Builder)
for templatePath := range dataList {
// 获取目标文件路径
targetPath, ok := fileList[templatePath]
if !ok {
continue
}
// 解析并执行模板
files, err := template.New(filepath.Base(templatePath)).Funcs(autocode.GetTemplateFuncMap()).ParseFiles(templatePath)
if err != nil {
return nil, nil, nil, errors.Wrapf(err, "[filepath:%s]读取模版文件失败!", templatePath)
}
var builder strings.Builder
if err = files.Execute(&builder, info); err != nil {
return nil, nil, nil, errors.Wrapf(err, "[filepath:%s]生成文件失败!", targetPath)
}
code[targetPath] = builder
}
injections := make(map[string]interface{}, len(asts))
for key, value := range asts {
keys := strings.Split(key, "=>")
if len(keys) == 2 {
if keys[1] == TypePluginInitializeV2 {
continue
}
if info.OnlyTemplate {
if keys[1] == TypePackageInitializeGorm || keys[1] == TypePluginInitializeGorm {
continue
}
}
if !info.AutoMigrate {
if keys[1] == TypePackageInitializeGorm || keys[1] == TypePluginInitializeGorm {
continue
}
}
var builder strings.Builder
parse, _ := value.Parse("", &builder)
if parse != nil {
_ = value.Injection(parse)
if err = value.Format("", &builder, parse); err != nil {
return nil, nil, nil, err
}
code[keys[0]] = builder
injections[keys[1]] = value
fmt.Println(keys[0], "注入成功!")
}
}
}
return code, fileList, injections, nil
}
// AddFunc 添加函数
func (uc *AutoCodeTemplateUsecase) AddFunc(info *AutoFuncInfo) error {
autoPkg, err := uc.packageRepo.FindByPackageName(context.Background(), info.Package)
if err != nil {
return err
}
if autoPkg.Template != "package" {
info.IsPlugin = true
}
if err = uc.addTemplateToFile("api.go", info); err != nil {
return err
}
if err = uc.addTemplateToFile("server.go", info); err != nil {
return err
}
if err = uc.addTemplateToFile("api.js", info); err != nil {
return err
}
return uc.addTemplateToAst("router", info)
}
// GetApiAndServer 获取API和Server代码
func (uc *AutoCodeTemplateUsecase) GetApiAndServer(info *AutoFuncInfo) (map[string]string, error) {
autoPkg, err := uc.packageRepo.FindByPackageName(context.Background(), info.Package)
if err != nil {
return nil, err
}
if autoPkg.Template != "package" {
info.IsPlugin = true
}
apiStr, err := uc.getTemplateStr("api.go", info)
if err != nil {
return nil, err
}
serverStr, err := uc.getTemplateStr("server.go", info)
if err != nil {
return nil, err
}
jsStr, err := uc.getTemplateStr("api.js", info)
if err != nil {
return nil, err
}
return map[string]string{"api": apiStr, "server": serverStr, "js": jsStr}, nil
}
// getTemplateStr 获取模板字符串
func (uc *AutoCodeTemplateUsecase) getTemplateStr(t string, info *AutoFuncInfo) (string, error) {
tempPath := filepath.Join(uc.config.Root, uc.config.Server, "resource", "function", t+".tpl")
files, err := template.New(filepath.Base(tempPath)).Funcs(autocode.GetTemplateFuncMap()).ParseFiles(tempPath)
if err != nil {
return "", errors.Wrapf(err, "[filepath:%s]读取模版文件失败!", tempPath)
}
var builder strings.Builder
if err = files.Execute(&builder, info); err != nil {
return "", errors.Wrapf(err, "[filepath:%s]生成文件失败!", tempPath)
}
return builder.String(), nil
}
// addTemplateToAst 添加模板到AST
// 支持 Kratos DDD 架构的路由注入
func (uc *AutoCodeTemplateUsecase) addTemplateToAst(t string, info *AutoFuncInfo) error {
// Kratos DDD 架构:路由文件在 internal/server/router/{package}/
tPath := filepath.Join(uc.config.Root, uc.config.Server, "internal", "server", "router", info.Package, info.HumpPackageName+".go")
funcName := fmt.Sprintf("Init%sRouter", info.StructName)
routerStr := "RouterWithoutAuth"
if info.IsAuth {
routerStr = "Router"
}
stmtStr := fmt.Sprintf("%s%s.%s(\"%s\", %sApi.%s)", info.Abbreviation, routerStr, info.Method, info.Router, info.Abbreviation, info.FuncName)
if info.IsPlugin {
tPath = filepath.Join(uc.config.Root, uc.config.Server, "internal", "plugin", info.Package, "router", info.HumpPackageName+".go")
stmtStr = fmt.Sprintf("group.%s(\"%s\", api%s.%s)", info.Method, info.Router, info.StructName, info.FuncName)
funcName = "Init"
}
src, err := os.ReadFile(tPath)
if err != nil {
return err
}
fileSet := token.NewFileSet()
astFile, err := parser.ParseFile(fileSet, "", src, 0)
if err != nil {
return err
}
funcDecl := utils.FindFunction(astFile, funcName)
stmtNode := utils.CreateStmt(stmtStr)
if info.IsAuth {
for i := 0; i < len(funcDecl.Body.List); i++ {
st := funcDecl.Body.List[i]
if blockStmt, ok := st.(*ast.BlockStmt); ok {
blockStmt.List = append(blockStmt.List, stmtNode)
break
}
}
} else {
for i := len(funcDecl.Body.List) - 1; i >= 0; i-- {
st := funcDecl.Body.List[i]
if blockStmt, ok := st.(*ast.BlockStmt); ok {
blockStmt.List = append(blockStmt.List, stmtNode)
break
}
}
}
f, err := os.Create(tPath)
if err != nil {
return err
}
defer f.Close()
return format.Node(f, fileSet, astFile)
}
// addTemplateToFile 添加模板到文件
// 支持 Kratos DDD 架构的文件路径:
// - handler: internal/server/handler/{package}/
// - service: internal/service/{package}/
// - api.ts: web/src/services/kratos/
func (uc *AutoCodeTemplateUsecase) addTemplateToFile(t string, info *AutoFuncInfo) error {
getTemplateStr, err := uc.getTemplateStr(t, info)
if err != nil {
return err
}
var target string
switch t {
case "api.go":
// Kratos DDD 架构Handler 在 internal/server/handler/{package}/
if info.IsAi && info.ApiFunc != "" {
getTemplateStr = info.ApiFunc
}
target = filepath.Join(uc.config.Root, uc.config.Server, "internal", "server", "handler", info.Package, info.HumpPackageName+".go")
case "server.go":
// Kratos DDD 架构Service 在 internal/service/{package}/
if info.IsAi && info.ServerFunc != "" {
getTemplateStr = info.ServerFunc
}
target = filepath.Join(uc.config.Root, uc.config.Server, "internal", "service", info.Package, info.HumpPackageName+".go")
case "api.js":
// Kratos DDD 架构:前端 API 在 web/src/services/kratos/
if info.IsAi && info.JsFunc != "" {
getTemplateStr = info.JsFunc
}
target = filepath.Join(uc.config.Root, uc.config.Web, "src", "services", "kratos", info.PackageName+".ts")
}
if info.IsPlugin {
switch t {
case "api.go":
target = filepath.Join(uc.config.Root, uc.config.Server, "internal", "plugin", info.Package, "api", info.HumpPackageName+".go")
case "server.go":
target = filepath.Join(uc.config.Root, uc.config.Server, "internal", "plugin", info.Package, "service", info.HumpPackageName+".go")
case "api.js":
target = filepath.Join(uc.config.Root, uc.config.Web, "src", "plugin", info.Package, "api", info.PackageName+".ts")
}
}
file, err := os.OpenFile(target, os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return err
}
defer file.Close()
_, err = fmt.Fprintln(file, getTemplateStr)
return err
}
// buildApis 构建API列表
func (uc *AutoCodeTemplateUsecase) buildApis(info *AutoCodeInfo) []SysApi {
apis := []SysApi{
{Path: "/" + info.Abbreviation + "/" + "create" + info.StructName, Description: "新增" + info.Description, ApiGroup: info.Description, Method: "POST"},
{Path: "/" + info.Abbreviation + "/" + "delete" + info.StructName, Description: "删除" + info.Description, ApiGroup: info.Description, Method: "DELETE"},
{Path: "/" + info.Abbreviation + "/" + "delete" + info.StructName + "ByIds", Description: "批量删除" + info.Description, ApiGroup: info.Description, Method: "DELETE"},
{Path: "/" + info.Abbreviation + "/" + "update" + info.StructName, Description: "更新" + info.Description, ApiGroup: info.Description, Method: "PUT"},
{Path: "/" + info.Abbreviation + "/" + "find" + info.StructName, Description: "根据ID获取" + info.Description, ApiGroup: info.Description, Method: "GET"},
{Path: "/" + info.Abbreviation + "/" + "get" + info.StructName + "List", Description: "获取" + info.Description + "列表", ApiGroup: info.Description, Method: "GET"},
}
if info.HasExcel {
apis = append(apis, []SysApi{
{Path: "/" + info.Abbreviation + "/" + "export" + info.StructName + "Excel", Description: "导出" + info.Description + "Excel", ApiGroup: info.Description, Method: "GET"},
{Path: "/" + info.Abbreviation + "/" + "import" + info.StructName + "Excel", Description: "导入" + info.Description + "Excel", ApiGroup: info.Description, Method: "POST"},
{Path: "/" + info.Abbreviation + "/" + "download" + info.StructName + "Template", Description: "下载" + info.Description + "模板", ApiGroup: info.Description, Method: "GET"},
}...)
}
return apis
}
// buildMenu 构建菜单
// 支持 Kratos DDD 架构的前端组件路径:
// - package: pages/{package}/{entity}/index
// - plugin: plugin/{package}/view/{entity}
func (uc *AutoCodeTemplateUsecase) buildMenu(info *AutoCodeInfo, template string) *SysBaseMenu {
// Kratos DDD 架构React 页面在 pages/{package}/{entity}/
component := "pages/" + info.Package + "/" + info.PackageName + "/index"
if template == "plugin" {
component = "plugin/" + info.Package + "/view/" + info.PackageName
}
return &SysBaseMenu{
ParentId: 0,
Path: info.Abbreviation,
Name: info.Abbreviation,
Hidden: false,
Component: component,
Sort: 0,
Meta: Meta{
Title: info.Description,
Icon: "menu",
},
}
}
// buildMenuBtns 构建菜单按钮
func (uc *AutoCodeTemplateUsecase) buildMenuBtns(info *AutoCodeInfo) []SysBaseMenuBtn {
btns := []SysBaseMenuBtn{
{Name: "add", Desc: "新增"},
{Name: "batchDelete", Desc: "批量删除"},
{Name: "delete", Desc: "删除"},
{Name: "edit", Desc: "编辑"},
{Name: "info", Desc: "详情"},
}
if info.HasExcel {
btns = append(btns, []SysBaseMenuBtn{
{Name: "exportTemplate", Desc: "导出模板"},
{Name: "exportExcel", Desc: "导出Excel"},
{Name: "importExcel", Desc: "导入Excel"},
}...)
}
return btns
}
// buildExportTemplate 构建导出模板
func (uc *AutoCodeTemplateUsecase) buildExportTemplate(info *AutoCodeInfo) *SysExportTemplate {
fieldsMap := make(map[string]string, len(info.Fields))
for _, field := range info.Fields {
if field.Excel {
fieldsMap[field.ColumnName] = field.FieldDesc
}
}
templateInfo, _ := json.Marshal(fieldsMap)
return &SysExportTemplate{
DBName: info.BusinessDB,
Name: info.Package + "_" + info.StructName,
Table: info.TableName,
TemplateID: info.Package + "_" + info.StructName,
TemplateInfo: string(templateInfo),
}
}
// AST类型常量
const (
TypePackageApiEnter = "PackageApiEnter"
TypePackageRouterEnter = "PackageRouterEnter"
TypePackageServiceEnter = "PackageServiceEnter"
TypePackageInitializeGorm = "PackageInitializeGorm"
TypePackageInitializeRouter = "PackageInitializeRouter"
TypePackageGormGen = "PackageGormGen"
TypePluginGen = "PluginGen"
TypePluginApiEnter = "PluginApiEnter"
TypePluginInitializeV2 = "PluginInitializeV2"
TypePluginRouterEnter = "PluginRouterEnter"
TypePluginServiceEnter = "PluginServiceEnter"
TypePluginInitializeGorm = "PluginInitializeGorm"
TypePluginInitializeRouter = "PluginInitializeRouter"
)
// AutoCodeInfo 相关实体类型
type AutoCodeInfo struct {
Package string
PackageT string
TableName string
BusinessDB string
StructName string
PackageName string
Description string
Abbreviation string
HumpPackageName string
GvaModel bool
AutoMigrate bool
AutoCreateResource bool
AutoCreateApiToSql bool
AutoCreateMenuToSql bool
AutoCreateBtnAuth bool
OnlyTemplate bool
IsTree bool
TreeJson string
IsAdd bool
Fields []*AutoCodeField
GenerateWeb bool
GenerateServer bool
Module string
DictTypes []string
PrimaryField *AutoCodeField
DataSourceMap map[string]*DataSource
HasPic bool
HasFile bool
HasTimer bool
NeedSort bool
NeedJSON bool
HasRichText bool
HasDataSource bool
HasSearchTimer bool
HasArray bool
HasExcel bool
CustomMethods []*CustomMethod // 自定义查询方法
HasCustomMethods bool // 是否有自定义查询方法
}
// CustomMethod 自定义查询方法
// 用于在 GORM Gen 生成的代码中添加自定义查询方法
type CustomMethod struct {
Name string `json:"name"` // 方法名称 (如: FindByName, GetActiveUsers)
Description string `json:"description"` // 方法描述
ReturnType string `json:"returnType"` // 返回类型: single(单个), list(列表), count(计数), exists(存在检查)
Params []*CustomMethodParam `json:"params"` // 方法参数
Conditions []*CustomCondition `json:"conditions"` // 查询条件
OrderBy string `json:"orderBy"` // 排序字段 (如: created_at DESC)
Limit int `json:"limit"` // 限制数量 (0表示不限制)
}
// CustomMethodParam 自定义方法参数
type CustomMethodParam struct {
Name string `json:"name"` // 参数名称
Type string `json:"type"` // 参数类型 (string, int, uint, bool, time.Time等)
FieldName string `json:"fieldName"` // 对应的字段名 (用于生成查询条件)
}
// CustomCondition 自定义查询条件
type CustomCondition struct {
FieldName string `json:"fieldName"` // 字段名
Operator string `json:"operator"` // 操作符: eq, neq, gt, gte, lt, lte, like, in, between, isNull, isNotNull
ParamName string `json:"paramName"` // 参数名 (对应 CustomMethodParam.Name)
}
// DataSource 数据源
type DataSource struct {
DBName string `json:"dbName"`
Table string `json:"table"`
Label string `json:"label"`
Value string `json:"value"`
Association int `json:"association"`
HasDeletedAt bool `json:"hasDeletedAt"`
}
// AutoCodeField 自动代码字段
type AutoCodeField struct {
FieldName string `json:"fieldName"`
FieldDesc string `json:"fieldDesc"`
FieldType string `json:"fieldType"`
FieldJson string `json:"fieldJson"`
DataTypeLong string `json:"dataTypeLong"`
Comment string `json:"comment"`
ColumnName string `json:"columnName"`
FieldSearchType string `json:"fieldSearchType"`
FieldSearchHide bool `json:"fieldSearchHide"`
DictType string `json:"dictType"`
Form bool `json:"form"`
Table bool `json:"table"`
Desc bool `json:"desc"`
Excel bool `json:"excel"`
Require bool `json:"require"`
DefaultValue string `json:"defaultValue"`
ErrorText string `json:"errorText"`
Clearable bool `json:"clearable"`
Sort bool `json:"sort"`
PrimaryKey bool `json:"primaryKey"`
DataSource *DataSource `json:"dataSource"`
CheckDataSource bool `json:"checkDataSource"`
FieldIndexType string `json:"fieldIndexType"`
}
// AutoFuncInfo 自动函数信息
type AutoFuncInfo struct {
Package string
FuncName string
Router string
FuncDesc string
BusinessDB string
StructName string
PackageName string
Description string
Abbreviation string
HumpPackageName string
Method string
IsPlugin bool
IsAuth bool
IsPreview bool
IsAi bool
ApiFunc string
ServerFunc string
JsFunc string
}
// SysExportTemplate 导出模板
type SysExportTemplate struct {
ID uint `json:"ID" gorm:"primarykey"`
DBName string `json:"dbName" gorm:"column:db_name;comment:数据库名"`
Name string `json:"name" gorm:"column:name;comment:模板名称"`
Table string `json:"tableName" gorm:"column:table_name;comment:表名"`
TemplateID string `json:"templateId" gorm:"column:template_id;comment:模板ID"`
TemplateInfo string `json:"templateInfo" gorm:"column:template_info;type:text;comment:模板信息"`
}
func (SysExportTemplate) TableName() string {
return "sys_export_templates"
}