mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-08-26 16:46:14 +08:00
1002 lines
30 KiB
Go
1002 lines
30 KiB
Go
// 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
|
||
}
|