Files
hotgo/server/internal/library/hggen/views/curd.go

1002 lines
30 KiB
Go
Raw 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 views
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package views
import (
"context"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gview"
"github.com/gogf/gf/v2/text/gstr"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/hggen/internal/cmd/gendao"
"hotgo/internal/library/hgorm"
"hotgo/internal/model"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/convert"
"hotgo/utility/file"
"hotgo/utility/tree"
"runtime"
"strings"
)
var Curd = gCurd{}
type gCurd struct{}
type CurdStep struct {
HasMaxSort bool // 最大排序
HasAdd bool // 表单添加
HasBatchDel bool // 批量删除
HasExport bool // 表格导出
HasNotFilterAuth bool // 不过滤认证权限
HasEdit bool // 表单编辑
HasDel bool // 删除
HasView bool // 查看详情
HasStatus bool // 修改状态
HasSwitch bool // 数值开关
HasCheck bool // 勾选列
HasMenu bool // 菜单权限
IsTreeTable bool // 树型列表
IsOptionTreeTable bool // 选项式树型列表
HasRules bool // 表单验证规则
HasRulesValidator bool // 表单验证器
HasSearchForm bool // 列表搜索
HasDict bool // 字典
HasFuncDict bool // 注册方法字典
HasQueryMemberSummary bool // 查询用户摘要
HasHookMemberSummary bool // hook用户摘要
ImportModel ImportModel // 公用导包 - model.ts
ActionColumnWidth int64 // 列表操作栏宽度
IsAddon bool // 是否是插件
}
// ImportModel 导包 - model.ts
type ImportModel struct {
NaiveUI []string
UtilsIs []string
UtilsUrl []string
UtilsDate []string
UtilsValidate []string
UtilsHotGo []string
UtilsIndex []string
}
type CurdOptionsJoin struct {
Uuid string `json:"uuid"`
LinkTable string `json:"linkTable"`
Alias string `json:"alias"`
LinkMode int `json:"linkMode"`
Field string `json:"field"`
MasterField string `json:"masterField"`
DaoName string `json:"daoName"`
Columns []*sysin.GenCodesColumnListModel `json:"columns"`
}
type CurdOptionsMenu struct {
Icon string `json:"icon"`
Pid int `json:"pid"`
Sort int `json:"sort"`
}
type OptionsTree struct {
TitleColumn string `json:"titleColumn"`
StyleType int `json:"styleType"`
TitleField *sysin.GenCodesColumnListModel
}
// PresetStep 预设生成流程参数
type PresetStep struct {
FormGridCols int `json:"formGridCols" dc:"表单显示的栅格数量"`
}
type CurdOptions struct {
AutoOps []string `json:"autoOps"`
ColumnOps []string `json:"columnOps"`
HeadOps []string `json:"headOps"`
Join []*CurdOptionsJoin `json:"join"`
Menu *CurdOptionsMenu `json:"menu"`
Tree *OptionsTree `json:"tree"`
TemplateGroup string `json:"templateGroup"`
ApiPrefix string `json:"apiPrefix"`
ImportWebApi string `json:"importWebApi"`
FuncDict *FuncDict `json:"funcDict"`
PresetStep *PresetStep `json:"presetStep"`
Step *CurdStep // 转换后的流程控制条件
DictOps CurdOptionsDict // 字典选项
dictMap g.Map // 字典选项 -> 字段映射关系
}
type FuncDict struct {
ValueColumn string // 选项值
LabelColumn string //选项名称
Value *sysin.GenCodesColumnListModel
Label *sysin.GenCodesColumnListModel
}
type CurdOptionsDict struct {
Has bool
Types []string
Schemas []*OptionsSchemasField
}
type OptionsSchemasField struct {
Field string
Type string
}
type CurdPreviewInput struct {
In *sysin.GenCodesPreviewInp // 提交参数
DaoConfig gendao.CGenDaoInput // 生成dao配置
Config *model.GenerateConfig // 生成配置
view *gview.View // 视图模板
content *sysin.GenCodesPreviewModel // 页面代码
masterFields []*sysin.GenCodesColumnListModel // 主表字段属性
pk *sysin.GenCodesColumnListModel // 主键属性
options *CurdOptions // 生成选项
}
type CurdBuildEvent map[string]func(ctx context.Context) (err error)
type CurdBuildInput struct {
PreviewIn *CurdPreviewInput // 预览参数
BeforeEvent CurdBuildEvent // 前置事件
AfterEvent CurdBuildEvent // 后置事件
}
func (l *gCurd) initInput(ctx context.Context, in *CurdPreviewInput) (err error) {
in.content = new(sysin.GenCodesPreviewModel)
in.content.Views = make(map[string]*sysin.GenFile)
// 初始化生成选项
if err = initOptions(in); err != nil {
return err
}
// 初始化表字段配置
if err = initTableField(ctx, in); err != nil {
return err
}
// 初始化树表
if err = initTableTree(in); err != nil {
return err
}
initStep(in)
// 初始化方法字典
if err = initFuncDict(in); err != nil {
return err
}
// 初始化生成模板
if err = initTemplate(in); err != nil {
return err
}
return
}
func initOptions(in *CurdPreviewInput) (err error) {
if err = in.In.Options.Scan(&in.options); err != nil {
return
}
in.options.dictMap = make(g.Map)
return
}
func initTemplate(in *CurdPreviewInput) (err error) {
if len(in.Config.Application.Crud.Templates)-1 < in.In.GenTemplate {
return gerror.New("没有找到生成模板的配置,请检查!")
}
// api前缀
apiPrefix := gstr.LcFirst(in.In.VarName)
if in.Config.Application.Crud.Templates[in.In.GenTemplate].IsAddon {
apiPrefix = in.In.AddonName + "/" + apiPrefix
}
in.options.ApiPrefix = apiPrefix
if err = checkCurdPath(in.Config.Application.Crud.Templates[in.In.GenTemplate], in.In.AddonName); err != nil {
return
}
in.options.TemplateGroup = in.Config.Application.Crud.Templates[in.In.GenTemplate].MasterPackage
return
}
func initFuncDict(in *CurdPreviewInput) (err error) {
if !in.options.Step.HasFuncDict || in.options.FuncDict == nil {
return
}
if len(in.options.FuncDict.LabelColumn) == 0 || len(in.options.FuncDict.ValueColumn) == 0 {
err = gerror.New("生成字典选项必须设置选项值和选项名称")
return err
}
for _, field := range in.masterFields {
if field.Name == in.options.FuncDict.ValueColumn {
in.options.FuncDict.Value = field
}
if field.Name == in.options.FuncDict.LabelColumn {
in.options.FuncDict.Label = field
}
}
return
}
func initTableField(ctx context.Context, in *CurdPreviewInput) (err error) {
// 加载主表配置
if err = in.In.MasterColumns.Scan(&in.masterFields); err != nil {
return
}
if len(in.masterFields) == 0 {
if in.masterFields, err = DoTableColumns(ctx, &sysin.GenCodesColumnListInp{Name: in.In.DbName, Table: in.In.TableName}, in.DaoConfig); err != nil {
return
}
}
// 主键属性
in.pk = getPkField(in)
if in.pk == nil {
return gerror.New("initInput no primary key is set in the table!")
}
in.masterFields = ReviseFields(in.masterFields)
// 检查表命名
var names = []string{in.In.DaoName}
for _, v := range in.options.Join {
v.Columns = ReviseFields(v.Columns)
names = append(names, v.DaoName)
}
if err = CheckIllegalName("数据库表名", names...); err != nil {
return
}
if err = CheckIllegalName("实体命名", in.In.VarName); err != nil {
return
}
return
}
func initTableTree(in *CurdPreviewInput) (err error) {
// 检查树表字段
if in.In.GenType == consts.GenCodesTypeTree {
if err = CheckTreeTableFields(in.masterFields); err != nil {
return err
}
// 解析选项树名称字段
has := false
for _, field := range in.masterFields {
if in.options.Tree.TitleColumn == field.Name {
in.options.Tree.TitleField = field
has = true
break
}
}
if !has {
err = gerror.New("请选择一个有效的树名称字段")
return
}
}
return err
}
func initStep(in *CurdPreviewInput) {
in.options.Step = new(CurdStep)
in.options.Step.HasMaxSort = HasMaxSort(in.masterFields)
in.options.Step.HasAdd = gstr.InArray(in.options.HeadOps, "add")
in.options.Step.HasBatchDel = gstr.InArray(in.options.HeadOps, "batchDel") && gstr.InArray(in.options.ColumnOps, "check")
in.options.Step.HasExport = gstr.InArray(in.options.HeadOps, "export")
in.options.Step.HasNotFilterAuth = gstr.InArray(in.options.ColumnOps, "notFilterAuth")
in.options.Step.HasEdit = gstr.InArray(in.options.ColumnOps, "edit")
in.options.Step.HasDel = gstr.InArray(in.options.ColumnOps, "del")
in.options.Step.HasView = gstr.InArray(in.options.ColumnOps, "view")
in.options.Step.HasStatus = HasStatus(in.options.ColumnOps, in.masterFields)
in.options.Step.HasSwitch = HasSwitch(in.masterFields)
in.options.Step.HasCheck = gstr.InArray(in.options.ColumnOps, "check")
in.options.Step.HasMenu = gstr.InArray(in.options.AutoOps, "genMenuPermissions")
in.options.Step.HasQueryMemberSummary = HasQueryMemberSummary(in.masterFields)
in.options.Step.HasHookMemberSummary = HasHookMemberSummary(in.masterFields)
in.options.Step.IsTreeTable = in.In.GenType == consts.GenCodesTypeTree
if in.options.Step.IsTreeTable {
in.options.Step.IsOptionTreeTable = in.options.Tree.StyleType == consts.GenCodesTreeStyleTypeOption
}
in.options.Step.HasFuncDict = gstr.InArray(in.options.AutoOps, "genFuncDict")
in.options.Step.IsAddon = in.Config.Application.Crud.Templates[in.In.GenTemplate].IsAddon
if in.options.PresetStep.FormGridCols < 1 {
in.options.PresetStep.FormGridCols = 1
}
}
// getPkField 获取主键
func getPkField(in *CurdPreviewInput) *sysin.GenCodesColumnListModel {
if len(in.masterFields) == 0 {
panic("getPkField masterFields uninitialized.")
}
for _, field := range in.masterFields {
if IsIndexPK(field.Index) {
return field
}
}
return nil
}
func (l *gCurd) loadView(ctx context.Context, in *CurdPreviewInput) (err error) {
temp := in.Config.Application.Crud.Templates[in.In.GenTemplate]
view := gview.New()
err = view.SetConfigWithMap(g.Map{
"Paths": temp.TemplatePath,
"Delimiters": in.Config.Delimiters,
})
if err != nil {
return
}
now := gtime.Now()
view.BindFuncMap(g.Map{
"NowYear": now.Year, // 当前年
"ToLower": strings.ToLower, // 全部小写
"LcFirst": gstr.LcFirst, // 首字母小写
"UcFirst": gstr.UcFirst, // 首字母大写
"ToTSArray": ToTSArray, // 转为ts数组格式
})
if err = l.generateWebModelDictOptions(ctx, in); err != nil {
return
}
modName, err := GetModName(ctx)
if err != nil {
return
}
importApi := gstr.Replace(temp.ApiPath, "./", modName+"/") + "/" + strings.ToLower(in.In.VarName)
importInput := gstr.Replace(temp.InputPath, "./", modName+"/")
importController := gstr.Replace(temp.ControllerPath, "./", modName+"/")
importService := "hotgo/internal/service"
if temp.IsAddon {
importService = "hotgo/addons/" + in.In.AddonName + "/service"
}
in.options.ImportWebApi = "@/api/" + gstr.LcFirst(in.In.VarName)
if temp.IsAddon {
in.options.ImportWebApi = "@/api/addons/" + in.In.AddonName + "/" + gstr.LcFirst(in.In.VarName)
}
componentPrefix := gstr.LcFirst(in.In.VarName)
if temp.IsAddon {
componentPrefix = "addons/" + in.In.AddonName + "/" + componentPrefix
}
nowTime := now.Format("Y-m-d H:i:s")
view.Assigns(gview.Params{
"templateGroup": in.options.TemplateGroup, // 生成模板分组名称
"servFunName": l.parseServFunName(in.options.TemplateGroup, in.In.VarName), // 业务服务名称
"nowTime": nowTime, // 当前时间
"version": runtime.Version(), // GO 版本
"hgVersion": consts.VersionApp, // HG 版本
"varName": in.In.VarName, // 实体名称
"tableComment": in.In.TableComment, // 对外名称
"daoName": in.In.DaoName, // ORM模型
"masterFields": in.masterFields, // 主表字段
"pk": in.pk, // 主键属性
"options": in.options, // 提交选项
"dictOptions": in.options.DictOps, // web字典选项
"importApi": importApi, // 导入goApi包
"importInput": importInput, // 导入input包
"importController": importController, // 导入控制器包
"importService": importService, // 导入业务服务
"importWebApi": in.options.ImportWebApi, // 导入webApi
"apiPrefix": in.options.ApiPrefix, // api前缀
"componentPrefix": componentPrefix, // vue子组件前缀
})
in.view = view
return
}
func (l *gCurd) DoBuild(ctx context.Context, in *CurdBuildInput) (err error) {
st := gtime.Now()
preview, err := l.DoPreview(ctx, in.PreviewIn)
if err != nil {
return
}
db, err := g.DB().Open(ParseDBConfigNodeLink(&gdb.ConfigNode{Link: in.PreviewIn.DaoConfig.Link}))
if err != nil {
err = gerror.Newf("连接数据库失败,请检查配置文件[server/hack/config.yaml]数据库配置是否正确err:%v", err.Error())
return err
}
defer db.Close()
if err = db.Ping(); err != nil {
err = gerror.Newf("数据库访问异常,请检查配置文件[server/hack/config.yaml]数据库配置是否正确err:%v", err.Error())
return
}
// 前置操作
if len(in.BeforeEvent) > 0 {
for name, f := range in.BeforeEvent {
if gstr.InArray(in.PreviewIn.options.AutoOps, name) {
if err = f(ctx); err != nil {
return gerror.Newf("in doBuild operation beforeEvent to '%s' failed:%v", name, err)
}
}
}
}
// 处理sql文件
handleSqlFile := func(vi *sysin.GenFile) (err error) {
// 无需生成
if vi.Meth != consts.GenCodesBuildMethCreate && vi.Meth != consts.GenCodesBuildMethCover {
return
}
if err = gfile.PutContents(vi.Path, strings.TrimSpace(vi.Content)); err != nil {
return gerror.Newf("writing content to '%s' failed: %v", vi.Path, err)
}
// 导入失败将sql文件删除
if err = ImportSql(ctx, vi.Path); err != nil {
_ = gfile.Remove(vi.Path)
}
return
}
// 将sql文件提取出来优先处理
// sql执行过程出错是高概率事件后期在执行前要进行预效验尽量减少在执行过程中出错的可能性
sqlGenFile, ok := preview.Views["source.sql"]
if ok {
delete(preview.Views, "source.sql")
if err = handleSqlFile(sqlGenFile); err != nil {
return
}
}
for _, vi := range preview.Views {
// 无需生成
if vi.Meth != consts.GenCodesBuildMethCreate && vi.Meth != consts.GenCodesBuildMethCover {
continue
}
if err = gfile.PutContents(vi.Path, strings.TrimSpace(vi.Content)); err != nil {
return gerror.Newf("writing content to '%s' failed: %v", vi.Path, err)
}
}
// 后置操作
if len(in.AfterEvent) > 0 {
for name, f := range in.AfterEvent {
if gstr.InArray(in.PreviewIn.options.AutoOps, name) {
if err = f(ctx); err != nil {
return gerror.Newf("in doBuild operation afterEvent to '%s' failed:%v", name, err)
}
}
}
}
g.Log().Debugf(ctx, "generate code operation completed, %vms", gtime.Now().Sub(st).Milliseconds())
return
}
func (l *gCurd) DoPreview(ctx context.Context, in *CurdPreviewInput) (res *sysin.GenCodesPreviewModel, err error) {
// 初始化
if err = l.initInput(ctx, in); err != nil {
return nil, err
}
// 加载模板
if err = l.loadView(ctx, in); err != nil {
return nil, err
}
if err = l.generateApiContent(ctx, in); err != nil {
return nil, err
}
if err = l.generateInputContent(ctx, in); err != nil {
return nil, err
}
if err = l.generateControllerContent(ctx, in); err != nil {
return nil, err
}
if err = l.generateLogicContent(ctx, in); err != nil {
return nil, err
}
if err = l.generateRouterContent(ctx, in); err != nil {
return nil, err
}
if err = l.generateWebApiContent(ctx, in); err != nil {
return nil, err
}
if err = l.generateWebModelContent(ctx, in); err != nil {
return nil, err
}
if err = l.generateWebIndexContent(ctx, in); err != nil {
return nil, err
}
if err = l.generateWebEditContent(ctx, in); err != nil {
return nil, err
}
if err = l.generateWebViewContent(ctx, in); err != nil {
return nil, err
}
if err = l.generateSqlContent(ctx, in); err != nil {
return nil, err
}
in.content.Config = in.Config
res = in.content
return
}
func (l *gCurd) generateApiContent(ctx context.Context, in *CurdPreviewInput) (err error) {
var (
name = "api.go"
tplData = g.Map{}
genFile = new(sysin.GenFile)
)
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
if err != nil {
return err
}
genFile.Content, err = FormatGo(ctx, name, genFile.Content)
if err != nil {
return err
}
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[in.In.GenTemplate].ApiPath, strings.ToLower(in.In.VarName), strings.ToLower(in.In.VarName)+".go")
genFile.Meth = consts.GenCodesBuildMethCreate
if gfile.Exists(genFile.Path) {
genFile.Meth = consts.GenCodesBuildMethSkip
}
genFile.Required = true
if genFile.Meth == consts.GenCodesBuildMethSkip && gstr.InArray(in.options.AutoOps, "forcedCover") {
genFile.Meth = consts.GenCodesBuildMethCover
}
in.content.Views[name] = genFile
return
}
func (l *gCurd) generateInputContent(ctx context.Context, in *CurdPreviewInput) (err error) {
var (
name = "input.go"
genFile = new(sysin.GenFile)
)
tplData, err := l.inputTplData(ctx, in)
if err != nil {
return err
}
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
if err != nil {
return err
}
genFile.Content, err = FormatGo(ctx, name, genFile.Content)
if err != nil {
return err
}
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[in.In.GenTemplate].InputPath, convert.CamelCaseToUnderline(in.In.VarName)+".go")
genFile.Meth = consts.GenCodesBuildMethCreate
if gfile.Exists(genFile.Path) {
genFile.Meth = consts.GenCodesBuildMethSkip
}
genFile.Required = true
if genFile.Meth == consts.GenCodesBuildMethSkip && gstr.InArray(in.options.AutoOps, "forcedCover") {
genFile.Meth = consts.GenCodesBuildMethCover
}
in.content.Views[name] = genFile
return
}
func (l *gCurd) generateControllerContent(ctx context.Context, in *CurdPreviewInput) (err error) {
var (
name = "controller.go"
tplData = g.Map{}
genFile = new(sysin.GenFile)
)
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
if err != nil {
return err
}
genFile.Content, err = FormatGo(ctx, name, genFile.Content)
if err != nil {
return err
}
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[in.In.GenTemplate].ControllerPath, convert.CamelCaseToUnderline(in.In.VarName)+".go")
genFile.Meth = consts.GenCodesBuildMethCreate
if gfile.Exists(genFile.Path) {
genFile.Meth = consts.GenCodesBuildMethSkip
}
genFile.Required = true
if genFile.Meth == consts.GenCodesBuildMethSkip && gstr.InArray(in.options.AutoOps, "forcedCover") {
genFile.Meth = consts.GenCodesBuildMethCover
}
in.content.Views[name] = genFile
return
}
func (l *gCurd) generateLogicContent(ctx context.Context, in *CurdPreviewInput) (err error) {
var (
name = "logic.go"
genFile = new(sysin.GenFile)
)
tplData, err := l.logicTplData(ctx, in)
if err != nil {
return err
}
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
if err != nil {
return err
}
genFile.Content, err = FormatGo(ctx, name, genFile.Content)
if err != nil {
return err
}
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[in.In.GenTemplate].LogicPath, convert.CamelCaseToUnderline(in.In.VarName)+".go")
genFile.Meth = consts.GenCodesBuildMethCreate
if gfile.Exists(genFile.Path) {
genFile.Meth = consts.GenCodesBuildMethSkip
}
genFile.Required = true
if genFile.Meth == consts.GenCodesBuildMethSkip && gstr.InArray(in.options.AutoOps, "forcedCover") {
genFile.Meth = consts.GenCodesBuildMethCover
}
in.content.Views[name] = genFile
return
}
func (l *gCurd) generateRouterContent(ctx context.Context, in *CurdPreviewInput) (err error) {
var (
name = "router.go"
tplData = g.Map{}
genFile = new(sysin.GenFile)
)
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
if err != nil {
return err
}
genFile.Content, err = FormatGo(ctx, name, genFile.Content)
if err != nil {
return err
}
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[in.In.GenTemplate].RouterPath, convert.CamelCaseToUnderline(in.In.VarName)+".go")
genFile.Meth = consts.GenCodesBuildMethCreate
if gfile.Exists(genFile.Path) {
genFile.Meth = consts.GenCodesBuildMethSkip
}
genFile.Required = true
if genFile.Meth == consts.GenCodesBuildMethSkip && gstr.InArray(in.options.AutoOps, "forcedCover") {
genFile.Meth = consts.GenCodesBuildMethCover
}
in.content.Views[name] = genFile
return
}
func (l *gCurd) generateWebApiContent(ctx context.Context, in *CurdPreviewInput) (err error) {
var (
name = "web.api.ts"
tplData = g.Map{}
genFile = new(sysin.GenFile)
)
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
if err != nil {
return err
}
genFile.Content = FormatTs(genFile.Content)
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[in.In.GenTemplate].WebApiPath, gstr.LcFirst(in.In.VarName), "index.ts")
genFile.Meth = consts.GenCodesBuildMethCreate
if gfile.Exists(genFile.Path) {
genFile.Meth = consts.GenCodesBuildMethSkip
}
genFile.Required = true
if genFile.Meth == consts.GenCodesBuildMethSkip && gstr.InArray(in.options.AutoOps, "forcedCover") {
genFile.Meth = consts.GenCodesBuildMethCover
}
in.content.Views[name] = genFile
return
}
func (l *gCurd) generateWebModelContent(ctx context.Context, in *CurdPreviewInput) (err error) {
var (
name = "web.model.ts"
genFile = new(sysin.GenFile)
)
tplData, err := l.webModelTplData(ctx, in)
if err != nil {
return
}
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
if err != nil {
return
}
genFile.Content = FormatTs(genFile.Content)
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[in.In.GenTemplate].WebViewsPath, gstr.LcFirst(in.In.VarName), "model.ts")
genFile.Meth = consts.GenCodesBuildMethCreate
if gfile.Exists(genFile.Path) {
genFile.Meth = consts.GenCodesBuildMethSkip
}
genFile.Required = true
if genFile.Meth == consts.GenCodesBuildMethSkip && gstr.InArray(in.options.AutoOps, "forcedCover") {
genFile.Meth = consts.GenCodesBuildMethCover
}
in.content.Views[name] = genFile
return
}
func (l *gCurd) generateWebIndexContent(ctx context.Context, in *CurdPreviewInput) (err error) {
var (
name = "web.index.vue"
genFile = new(sysin.GenFile)
)
tplData, err := l.webIndexTplData(ctx, in)
if err != nil {
return err
}
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
if err != nil {
return err
}
genFile.Content = FormatVue(genFile.Content)
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[in.In.GenTemplate].WebViewsPath, gstr.LcFirst(in.In.VarName), "index.vue")
genFile.Meth = consts.GenCodesBuildMethCreate
if gfile.Exists(genFile.Path) {
genFile.Meth = consts.GenCodesBuildMethSkip
}
genFile.Required = true
if genFile.Meth == consts.GenCodesBuildMethSkip && gstr.InArray(in.options.AutoOps, "forcedCover") {
genFile.Meth = consts.GenCodesBuildMethCover
}
in.content.Views[name] = genFile
return
}
func (l *gCurd) generateWebEditContent(ctx context.Context, in *CurdPreviewInput) (err error) {
var (
name = "web.edit.vue"
genFile = new(sysin.GenFile)
)
tplData, err := l.webEditTplData(ctx, in)
if err != nil {
return err
}
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
if err != nil {
return err
}
genFile.Content = FormatVue(genFile.Content)
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[in.In.GenTemplate].WebViewsPath, gstr.LcFirst(in.In.VarName), "edit.vue")
genFile.Meth = consts.GenCodesBuildMethCreate
if gfile.Exists(genFile.Path) {
genFile.Meth = consts.GenCodesBuildMethSkip
}
genFile.Required = true
if genFile.Meth == consts.GenCodesBuildMethSkip && gstr.InArray(in.options.AutoOps, "forcedCover") {
genFile.Meth = consts.GenCodesBuildMethCover
}
if !in.options.Step.HasEdit {
genFile.Meth = consts.GenCodesBuildIgnore
genFile.Required = false
}
in.content.Views[name] = genFile
return
}
func (l *gCurd) generateWebViewContent(ctx context.Context, in *CurdPreviewInput) (err error) {
var (
name = "web.view.vue"
genFile = new(sysin.GenFile)
)
tplData, err := l.webViewTplData(ctx, in)
if err != nil {
return err
}
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
if err != nil {
return err
}
genFile.Content = FormatVue(genFile.Content)
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[in.In.GenTemplate].WebViewsPath, gstr.LcFirst(in.In.VarName), "view.vue")
genFile.Meth = consts.GenCodesBuildMethCreate
if gfile.Exists(genFile.Path) {
genFile.Meth = consts.GenCodesBuildMethSkip
}
genFile.Required = true
if genFile.Meth == consts.GenCodesBuildMethSkip && gstr.InArray(in.options.AutoOps, "forcedCover") {
genFile.Meth = consts.GenCodesBuildMethCover
}
if !in.options.Step.HasView {
genFile.Meth = consts.GenCodesBuildIgnore
genFile.Required = false
}
in.content.Views[name] = genFile
return
}
func (l *gCurd) generateSqlContent(ctx context.Context, in *CurdPreviewInput) (err error) {
var (
name = "source.sql"
config = g.DB("default").GetConfig()
tplData = g.Map{
"dbName": config.Name,
"menuTable": config.Prefix + "admin_menu",
"mainComponent": "LAYOUT",
}
genFile = new(sysin.GenFile)
)
menus, err := service.AdminMenu().GetFastList(ctx)
if err != nil {
return err
}
tplData["dirPid"], tplData["dirLevel"], tplData["dirTree"], err = hgorm.AutoUpdateTree(ctx, &dao.AdminMenu, 0, int64(in.options.Menu.Pid))
if err != nil {
return err
}
tplData["listLevel"] = tplData["dirLevel"].(int) + 1
tplData["btnLevel"] = tplData["dirLevel"].(int) + 2
tplData["sortLevel"] = tplData["dirLevel"].(int) + 3
pageRedirect := ""
if in.options.Menu.Pid > 0 {
tplData["mainComponent"] = "ParentLayout"
menu, ok := menus[int64(in.options.Menu.Pid)]
if !ok {
err = gerror.New("选择的上级菜单不存在")
return
}
for _, id := range tree.GetIds(menu.Tree) {
if v, ok2 := menus[id]; ok2 {
if !gstr.HasSuffix(pageRedirect, "/") && !gstr.HasPrefix(v.Path, "/") {
pageRedirect += "/"
}
pageRedirect += v.Path
}
}
if !gstr.HasSuffix(pageRedirect, "/") && !gstr.HasPrefix(menu.Path, "/") {
pageRedirect += "/"
}
pageRedirect += menu.Path
}
pageRedirect += "/" + gstr.LcFirst(in.In.VarName) + "/index"
tplData["pageRedirect"] = pageRedirect
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[in.In.GenTemplate].SqlPath, convert.CamelCaseToUnderline(in.In.VarName)+"_menu.sql")
genFile.Meth = consts.GenCodesBuildMethCreate
if gfile.Exists(genFile.Path) {
genFile.Meth = consts.GenCodesBuildMethSkip
}
genFile.Required = true
if !in.options.Step.HasMenu {
genFile.Meth = consts.GenCodesBuildIgnore
genFile.Required = false
}
// 需要生成时,检查菜单命名是否存在
if genFile.Meth == consts.GenCodesBuildMethCreate {
menuNamePrefix := gstr.LcFirst(in.In.VarName)
menuNames := []string{menuNamePrefix, menuNamePrefix + "Index"}
if in.options.Step.HasEdit {
menuNames = append(menuNames, menuNamePrefix+"Edit")
menuNames = append(menuNames, menuNamePrefix+"View")
}
if in.options.Step.HasView {
menuNames = append(menuNames, menuNamePrefix+"View")
}
if in.options.Step.HasMaxSort {
menuNames = append(menuNames, menuNamePrefix+"MaxSort")
}
if in.options.Step.HasDel {
menuNames = append(menuNames, menuNamePrefix+"Delete")
}
if in.options.Step.HasStatus {
menuNames = append(menuNames, menuNamePrefix+"Status")
}
if in.options.Step.HasSwitch {
menuNames = append(menuNames, menuNamePrefix+"Switch")
}
if in.options.Step.HasExport {
menuNames = append(menuNames, menuNamePrefix+"Export")
}
if in.options.Step.IsTreeTable {
menuNames = append(menuNames, menuNamePrefix+"TreeOption")
}
menuNames = convert.UniqueSlice(menuNames)
hasMenus, err := service.AdminMenu().Model(ctx).Fields("name").WhereIn("name", menuNames).Array()
if err != nil {
return err
}
if len(hasMenus) > 0 {
err = gerror.Newf("要生成的菜单中有已存在的路由别名,请检查并删除:%v", strings.Join(gvar.New(hasMenus).Strings(), ``))
return err
}
}
tplData["generatePath"] = genFile.Path
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
if err != nil {
return err
}
in.content.Views[name] = genFile
return
}