/* * @desc:代码生成表数据处理 * @company:云南奇讯科技有限公司 * @Author: yixiaohu * @Date: 2022/10/26 17:00 */ package toolsGenTable import ( "bufio" "context" "database/sql" "fmt" "github.com/gogf/gf/v2/container/gmap" "github.com/gogf/gf/v2/container/gset" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/encoding/gjson" "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/gregex" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" "github.com/tiger1103/gfast/v3/api/v1/system" commonService "github.com/tiger1103/gfast/v3/internal/app/common/service" "github.com/tiger1103/gfast/v3/internal/app/system/consts" "github.com/tiger1103/gfast/v3/internal/app/system/dao" "github.com/tiger1103/gfast/v3/internal/app/system/model" "github.com/tiger1103/gfast/v3/internal/app/system/model/entity" "github.com/tiger1103/gfast/v3/internal/app/system/service" "github.com/tiger1103/gfast/v3/library/liberr" "golang.org/x/tools/imports" "io" "os" "reflect" "sort" "strings" ) func init() { service.RegisterToolsGenTable(New()) } func New() service.IToolsGenTable { return new(sToolsGenTable) } type sToolsGenTable struct{} // List 代码生成页面数据列表 func (s *sToolsGenTable) List(ctx context.Context, req *system.ToolsGenTableSearchReq) (res *system.ToolsGenTableSearchRes, err error) { res = new(system.ToolsGenTableSearchRes) m := dao.ToolsGenTable.Ctx(ctx) if req != nil { if req.TableName != "" { m = m.Where(dao.ToolsGenTable.Columns().TableName+" like ?", "%"+req.TableName+"%") } if req.TableComment != "" { m = m.Where(dao.ToolsGenTable.Columns().TableComment+" like ?", "%"+req.TableComment+"%") } if len(req.DateRange) > 0 { m = m.Where(dao.ToolsGenTable.Columns().CreateTime+" >=? AND "+dao.ToolsGenTable.Columns().CreateTime+" <=?", req.DateRange[0], req.DateRange[1]) } err = g.Try(ctx, func(ctx context.Context) { res.Total, err = m.Count() liberr.ErrIsNil(ctx, err, "获取总行数失败") if req.PageNum == 0 { req.PageNum = 1 } if req.PageSize == 0 { req.PageSize = consts.PageSize } err = m.Page(req.PageNum, req.PageSize).Order(dao.ToolsGenTable.Columns().TableId + " asc").Scan(&res.List) liberr.ErrIsNil(ctx, err, "获取数据失败") }) } return } // SelectDbTableList 查询据库表 func (s *sToolsGenTable) SelectDbTableList(ctx context.Context, req *system.ToolsGenTableImportSearchReq) (res *system.ToolsGenTableSearchRes, err error) { res = new(system.ToolsGenTableSearchRes) db := g.DB() err = g.Try(ctx, func(ctx context.Context) { if !s.IsMysql() && !s.IsPg() { liberr.ErrIsNil(ctx, gerror.New("代码生成暂时只支持mysql及postgresql数据库")) } var sqlStr string if s.IsMysql() { sqlStr = " from information_schema.tables where table_schema = (select database())" + " and table_name NOT LIKE 'tools_gen_%' and table_name NOT IN (select table_name from " + dao.ToolsGenTable.Table() + ") " if req != nil { if req.TableName != "" { sqlStr += gdb.FormatSqlWithArgs(" and lower(table_name) like lower(?)", []interface{}{"%" + req.TableName + "%"}) } if req.TableComment != "" { sqlStr += gdb.FormatSqlWithArgs(" and lower(table_comment) like lower(?)", []interface{}{"%" + req.TableComment + "%"}) } if len(req.DateRange) > 0 { sqlStr += gdb.FormatSqlWithArgs(" and date_format(create_time,'%y%m%d') >= date_format(?,'%y%m%d') ", []interface{}{req.DateRange[0]}) sqlStr += gdb.FormatSqlWithArgs(" and date_format(create_time,'%y%m%d') <= date_format(?,'%y%m%d') ", []interface{}{req.DateRange[1]}) } } countSql := "select count(1) " + sqlStr res.Total, err = db.GetCount(ctx, countSql) liberr.ErrIsNil(ctx, err, "读取总表数失败") sqlStr = "table_name, table_comment, create_time, update_time " + sqlStr if req.PageNum == 0 { req.PageNum = 1 } if req.PageSize == 0 { req.PageSize = consts.PageSize } page := (req.PageNum - 1) * req.PageSize sqlStr += " order by create_time desc,table_name asc limit " + gconv.String(page) + "," + gconv.String(req.PageSize) g.Log().Debug(ctx, "select "+sqlStr) err = db.GetScan(ctx, &res.List, "select "+sqlStr) liberr.ErrIsNil(ctx, err, "读取数据失败") } else if s.IsPg() { sqlStr = " from information_schema.tables JOIN pg_class ON pg_class.relname = table_name " + " WHERE table_schema = current_schema() AND table_name NOT LIKE 'tools_gen_%' and table_name NOT IN (select table_name from " + dao.ToolsGenTable.Table() + ") " if req != nil { if req.TableName != "" { sqlStr += gdb.FormatSqlWithArgs(" and lower(table_name) like lower(?)", []interface{}{"%" + req.TableName + "%"}) } if req.TableComment != "" { sqlStr += gdb.FormatSqlWithArgs(" and lower(obj_description(pg_class.oid)) like lower(?)", []interface{}{"%" + req.TableComment + "%"}) } if len(req.DateRange) > 0 { sqlStr += gdb.FormatSqlWithArgs(" and pg_stat_get_last_analyze_time(pg_class.oid) >= date_format(?,'%y%m%d') ", []interface{}{req.DateRange[0]}) sqlStr += gdb.FormatSqlWithArgs(" and pg_stat_get_last_analyze_time(pg_class.oid) <= date_format(?,'%y%m%d') ", []interface{}{req.DateRange[1]}) } } countSql := "select count(1) " + sqlStr res.Total, err = db.GetCount(ctx, countSql) liberr.ErrIsNil(ctx, err, "读取总表数失败") sqlStr = "table_name, obj_description(pg_class.oid) AS table_comment, " + "pg_stat_get_last_analyze_time(pg_class.oid) AS create_time, " + "pg_stat_get_last_autoanalyze_time(pg_class.oid) AS update_time " + sqlStr if req.PageNum == 0 { req.PageNum = 1 } if req.PageSize == 0 { req.PageSize = consts.PageSize } page := (req.PageNum - 1) * req.PageSize sqlStr += " order by pg_stat_get_last_analyze_time(pg_class.oid) desc,table_name asc LIMIT " + gconv.String(req.PageSize) + " OFFSET " + gconv.String(page) err = db.GetScan(ctx, &res.List, "select "+sqlStr) liberr.ErrIsNil(ctx, err, "读取数据失败") } }) return } // SelectDbTableListByNames 查询数据库中对应的表数据 func (s *sToolsGenTable) SelectDbTableListByNames(ctx context.Context, tableNames []string) ([]*entity.ToolsGenTable, error) { var result []*entity.ToolsGenTable err := g.Try(ctx, func(ctx context.Context) { if !s.IsMysql() && !s.IsPg() { liberr.ErrIsNil(ctx, gerror.New("代码生成暂时只支持mysql及postgresql数据库")) } db := g.DB() var sqlStr string if s.IsMysql() { sqlStr = "select * from information_schema.tables where table_name NOT LIKE 'tools_gen_%' " + " and table_schema = (select database()) " if len(tableNames) > 0 { in := gstr.TrimRight(gstr.Repeat("?,", len(tableNames)), ",") sqlStr += " and " + gdb.FormatSqlWithArgs("table_name in ("+in+")", gconv.SliceAny(tableNames)) } err := db.GetScan(ctx, &result, sqlStr) liberr.ErrIsNil(ctx, err, "获取表格信息失败") } else if s.IsPg() { sqlStr = "select * from information_schema.tables WHERE table_schema = current_schema() " + "AND table_name NOT LIKE 'tools_gen_%' " if len(tableNames) > 0 { in := gstr.TrimRight(gstr.Repeat("?,", len(tableNames)), ",") sqlStr += " and " + gdb.FormatSqlWithArgs("table_name in ("+in+")", gconv.SliceAny(tableNames)) } err := db.GetScan(ctx, &result, sqlStr) liberr.ErrIsNil(ctx, err, "获取表格信息失败") } }) return result, err } // ImportGenTable 导入表结构 func (s *sToolsGenTable) ImportGenTable(ctx context.Context, tableList []*entity.ToolsGenTable) error { if tableList != nil { err := g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { err := g.Try(ctx, func(ctx context.Context) { for _, table := range tableList { tableName := table.TableName // 保存列信息 genTableColumns, err := service.ToolsGenTableColumn().SelectDbTableColumnsByName(ctx, tableName) liberr.ErrIsNil(ctx, err, "获取列数据失败") if len(genTableColumns) <= 0 { liberr.ErrIsNil(ctx, gerror.New("获取列数据失败")) } err = s.InitTable(ctx, table, genTableColumns) liberr.ErrIsNil(ctx, err) result, err1 := tx.Model(dao.ToolsGenTable.Table()).FieldsEx("table_id"). Insert(table) liberr.ErrIsNil(ctx, err1) tmpId, err2 := result.LastInsertId() liberr.ErrIsNil(ctx, err2, "保存数据失败") if tmpId <= 0 { liberr.ErrIsNil(ctx, gerror.New("保存数据失败")) } table.TableId = tmpId for _, column := range genTableColumns { service.ToolsGenTableColumn().InitColumnField(column, table) _, err3 := tx.Model(dao.ToolsGenTableColumn.Table()).FieldsEx("column_id"). Insert(column) liberr.ErrIsNil(ctx, err3, "保存列数据失败") } } }) return err }) return err } else { return gerror.New("参数错误") } } // InitTable 初始化表信息 func (s *sToolsGenTable) InitTable(ctx context.Context, table *entity.ToolsGenTable, columns []*entity.ToolsGenTableColumn) error { table.ClassName = s.ConvertClassName(ctx, table.TableName) table.PackageName = g.Cfg().MustGet(ctx, "gen.packageName").String() table.ModuleName = g.Cfg().MustGet(ctx, "gen.moduleName").String() table.BusinessName = s.GetBusinessName(ctx, table.TableName) table.FunctionName = table.TableComment table.FunctionAuthor = g.Cfg().MustGet(ctx, "gen.author").String() table.TplCategory = "crud" pkColumn, err := s.getPkColumn(columns) if err != nil { return err } table.Overwrite = false table.SortColumn = pkColumn.ColumnName table.SortType = "asc" table.ShowDetail = false table.CreateTime = gtime.Now() table.UpdateTime = table.CreateTime return nil } // ConvertClassName 表名转换成类名 func (s *sToolsGenTable) ConvertClassName(ctx context.Context, tableName string) string { return gstr.CaseCamel(s.removeTablePrefix(ctx, tableName)) } // GetBusinessName 获取业务名 func (s *sToolsGenTable) GetBusinessName(ctx context.Context, tableName string) string { return s.removeTablePrefix(ctx, tableName) } // 找到主键 column func (s *sToolsGenTable) getPkColumn(columns []*entity.ToolsGenTableColumn) (*entity.ToolsGenTableColumn, error) { for _, column := range columns { if column.IsPk { return column, nil } } return nil, gerror.New("无法找到主键") } // 删除表前缀 func (s *sToolsGenTable) removeTablePrefix(ctx context.Context, tableName string) string { autoRemovePre := g.Cfg().MustGet(ctx, "gen.autoRemovePre").Bool() tablePrefix := g.Cfg().MustGet(ctx, "gen.tablePrefix").String() if autoRemovePre && tablePrefix != "" { searchList := strings.Split(tablePrefix, ",") for _, str := range searchList { if strings.HasPrefix(tableName, str) { tableName = strings.Replace(tableName, str, "", 1) //注意,只替换一次 } } } return tableName } // 获取数据库驱动类型 func (s *sToolsGenTable) getDbDriver() string { config := g.DB().GetConfig() return gstr.ToLower(config.Type) } func (s *sToolsGenTable) IsPg() bool { return s.getDbDriver() == "pgsql" } func (s *sToolsGenTable) IsMysql() bool { return s.getDbDriver() == "mysql" } // DeleteTable 删除表信息 func (s *sToolsGenTable) DeleteTable(ctx context.Context, req *system.ToolsGenTableDeleteReq) error { err := g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { err := g.Try(ctx, func(ctx context.Context) { _, err := tx.Model(dao.ToolsGenTable.Table()).Where(dao.ToolsGenTable.Columns().TableId+" in(?)", req.Ids).Delete() liberr.ErrIsNil(ctx, err, "删除表格数据失败") _, err = tx.Model(dao.ToolsGenTableColumn.Table()).Where(dao.ToolsGenTableColumn.Columns().TableId+" in(?)", req.Ids).Delete() liberr.ErrIsNil(ctx, err, "删除表格字段数据失败") }) return err }) return err } // ColumnList 表格字段列表数据 func (s *sToolsGenTable) ColumnList(ctx context.Context, req *system.ToolsGenTableEditReq) (res *system.ToolsGenTableEditRes, err error) { res = new(system.ToolsGenTableEditRes) err = g.Try(ctx, func(ctx context.Context) { var ( tableInfo *entity.ToolsGenTable ) res.List, err = service.ToolsGenTableColumn().SelectGenTableColumnListByTableId(ctx, req.TableId) liberr.ErrIsNil(ctx, err) tableInfo, err = s.GetTableInfoByTableId(ctx, req.TableId) liberr.ErrIsNil(ctx, err) if tableInfo == nil { liberr.ErrIsNil(ctx, gerror.New("表数据不存在")) } res.Info = &model.ToolsGenTableEditData{ ToolsGenTable: tableInfo, } //如果是树表则设置树表配置 if tableInfo != nil && tableInfo.TplCategory == "tree" { options := gjson.New(tableInfo.Options) res.Info.TreeCode = options.Get("treeCode") res.Info.TreeParentCode = options.Get("treeParentCode") res.Info.TreeName = options.Get("treeName") } }) return } // GetTableInfoByTableId 获取表格数据 func (s *sToolsGenTable) GetTableInfoByTableId(ctx context.Context, tableId int64) (data *entity.ToolsGenTable, err error) { err = g.Try(ctx, func(ctx context.Context) { err = dao.ToolsGenTable.Ctx(ctx).WherePri(tableId).Scan(&data) liberr.ErrIsNil(ctx, err, "获取表格信息出错") }) return } // GetRelationTable 获取关联表数据 func (s *sToolsGenTable) GetRelationTable(ctx context.Context, req *system.ToolsGenRelationTableReq) (res *system.ToolsGenRelationTableRes, err error) { var tableColumnsAll []*entity.ToolsGenTableColumn res = new(system.ToolsGenRelationTableRes) err = g.Try(ctx, func(ctx context.Context) { m := dao.ToolsGenTable.Ctx(ctx) if req.TableName != "" { m = m.WhereLike(dao.ToolsGenTable.Columns().TableName, "%"+req.TableName+"%") } if req.TableComment != "" { m = m.WhereLike(dao.ToolsGenTable.Columns().TableComment, "%"+req.TableComment+"%") } res.Total, err = m.Count() liberr.ErrIsNil(ctx, err, "获取表数据总数失败") if req.PageNum == 0 { req.PageNum = 1 } if req.PageSize == 0 { req.PageSize = consts.PageSize } res.CurrentPage = req.PageNum //获取表数据 err = m.Page(req.PageNum, req.PageSize).Order(dao.ToolsGenTable.Columns().TableId + " ASC ").Scan(&res.Data) liberr.ErrIsNil(ctx, err, "获取表数据失败") //获取表字段数据 tableColumnsAll, err = service.ToolsGenTableColumn().GetAllTableColumns(ctx) liberr.ErrIsNil(ctx, err) for k, v := range res.Data { for _, cv := range tableColumnsAll { if cv.TableId == v.TableId { res.Data[k].Columns = append(res.Data[k].Columns, cv) } } } }) return } // SaveEdit 更新表及字段生成信息 func (s *sToolsGenTable) SaveEdit(ctx context.Context, req *system.ToolsGenTableColumnsEditReq) (err error) { if req == nil { err = gerror.New("参数错误") return } var table *entity.ToolsGenTable err = dao.ToolsGenTable.Ctx(ctx).Where("table_id=?", req.TableId).Scan(&table) if err != nil || table == nil { err = gerror.New("数据不存在") return } if req.TableName != "" { table.TableName = req.TableName } if req.TableComment != "" { table.TableComment = req.TableComment } if req.BusinessName != "" { table.BusinessName = req.BusinessName } if req.ClassName != "" { table.ClassName = req.ClassName } if req.FunctionAuthor != "" { table.FunctionAuthor = req.FunctionAuthor } if req.FunctionName != "" { table.FunctionName = req.FunctionName } if req.ModuleName != "" { table.ModuleName = req.ModuleName } if req.PackageName != "" { table.PackageName = req.PackageName //从包名中获取模块名 lastIndex := gstr.PosR(table.PackageName, "/") if lastIndex != -1 { table.ModuleName = gstr.SubStr(table.PackageName, lastIndex+1) } } if req.Remark != "" { table.Remark = req.Remark } if req.Overwrite != "" { table.Overwrite = gconv.Bool(req.Overwrite) table.OverwriteInfo = req.OverwriteInfo } if req.SortColumn != "" { table.SortColumn = req.SortColumn } if req.SortType != "" { table.SortType = req.SortType } if req.ShowDetail != "" { table.ShowDetail = gconv.Bool(req.ShowDetail) } if req.ExcelPort != "" { table.ExcelPort = gconv.Bool(req.ExcelPort) } if req.ExcelImp != "" { table.ExcelImp = gconv.Bool(req.ExcelImp) } if req.UseSnowId != "" { table.UseSnowId = gconv.Bool(req.UseSnowId) } if req.UseVirtual != "" { table.UseVirtual = gconv.Bool(req.UseVirtual) } if req.TplCategory != "" { table.TplCategory = req.TplCategory } if req.Params != "" { table.Options = req.Params } table.UpdateTime = gtime.Now() var options g.Map if req.TplCategory == "tree" { //树表设置options options = g.Map{ "treeCode": req.TreeCode, "treeParentCode": req.TreeParentCode, "treeName": req.TreeName, } table.Options = gconv.String(options) } else { table.Options = "" } table.MenuPid = req.MenuPid err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) { err = g.Try(ctx, func(ctx context.Context) { _, err = tx.Model(dao.ToolsGenTable.Table()). WherePri(table.TableId). Update(table) liberr.ErrIsNil(ctx, err, "保存表数据失败") //保存列数据 if req.Columns != nil { for _, column := range req.Columns { if column.ColumnId > 0 { var dbColumn *entity.ToolsGenTableColumn err = dao.ToolsGenTableColumn.Ctx(ctx).Where("column_id=?", column.ColumnId).Scan(&dbColumn) liberr.ErrIsNil(ctx, err, "列数据信息不存在") if dbColumn != nil { dbColumn.ColumnComment = column.ColumnComment dbColumn.GoType = column.GoType dbColumn.HtmlType = column.HtmlType dbColumn.HtmlField = column.HtmlField dbColumn.QueryType = column.QueryType dbColumn.GoField = column.GoField dbColumn.DictType = column.DictType dbColumn.IsEdit = column.IsEdit dbColumn.IsList = column.IsList dbColumn.IsDetail = column.IsDetail dbColumn.IsQuery = column.IsQuery dbColumn.SortOrderEdit = column.SortOrderEdit dbColumn.SortOrderList = column.SortOrderList dbColumn.SortOrderDetail = column.SortOrderDetail dbColumn.SortOrderQuery = column.SortOrderQuery dbColumn.IsRequired = column.IsRequired dbColumn.ColSpan = column.ColSpan dbColumn.RowSpan = column.RowSpan dbColumn.IsRowStart = column.IsRowStart dbColumn.MinWidth = column.MinWidth dbColumn.IsFixed = column.IsFixed dbColumn.IsOverflowTooltip = column.IsOverflowTooltip dbColumn.IsCascade = column.IsCascade dbColumn.ParentColumnName = column.ParentColumnName dbColumn.CascadeColumnName = column.CascadeColumnName dbColumn.TsType = column.TsType if tc, e := options["treeParentCode"]; options != nil && e && tc != "" && tc == dbColumn.HtmlField { dbColumn.IsQuery = false dbColumn.IsList = false dbColumn.HtmlType = "treeSelect" } //获取字段关联表信息 if column.LinkLabelName != "" { dbColumn.LinkTableName = column.LinkTableName dbColumn.LinkLabelId = column.LinkLabelId dbColumn.LinkLabelName = column.LinkLabelName var linkTable *entity.ToolsGenTable err = dao.ToolsGenTable.Ctx(ctx).Where("table_name =?", column.LinkTableName).Scan(&linkTable) liberr.ErrIsNil(ctx, err, "获取关联表数据失败") dbColumn.LinkTableClass = linkTable.ClassName dbColumn.LinkTableModuleName = linkTable.ModuleName dbColumn.LinkTableBusinessName = linkTable.BusinessName dbColumn.LinkTablePackage = linkTable.PackageName } else { dbColumn.LinkTableName = "" dbColumn.LinkTableClass = "" dbColumn.LinkTableModuleName = "" dbColumn.LinkTableBusinessName = "" dbColumn.LinkTablePackage = "" dbColumn.LinkLabelId = "" dbColumn.LinkLabelName = "" } _, err = tx.Model(dao.ToolsGenTableColumn.Table()). WherePri(dbColumn.ColumnId). Update(dbColumn) liberr.ErrIsNil(ctx, err, "保存列:"+dbColumn.ColumnName+",数据失败") } } } } }) return }) return } // GenData 获取生成数据 func (s *sToolsGenTable) GenData(ctx context.Context, tableId int64) (data g.MapStrStr, extendData *model.ToolsGenTableEx, err error) { extendData, err = s.SelectRecordById(ctx, tableId) if err != nil { return } if extendData == nil { err = gerror.New("表格数据不存在") return } service.ToolsGenTableColumn().SetPkColumn(extendData, extendData.Columns) view := gview.New() err = view.SetConfigWithMap(g.Map{ "Paths": g.Cfg().MustGet(ctx, "gen.templatePath").String(), "Delimiters": []string{"{{", "}}"}, }) if err != nil { return } view.BindFuncMap(g.Map{ "UcFirst": func(str string) string { return gstr.UcFirst(str) }, "Sum": func(a, b int) int { return a + b }, "CaseCamelLower": gstr.CaseCamelLower, //首字母小写驼峰 "CaseCamel": gstr.CaseCamel, //首字母大写驼峰 "HasSuffix": gstr.HasSuffix, //是否存在后缀 "ContainsI": gstr.ContainsI, //是否包含子字符串 "VueTag": func(t string) string { return t }, "inArray": func(arr []interface{}, val interface{}) bool { for _, v := range arr { if reflect.DeepEqual(v, val) { return true } } return false }, "append": func(arr []interface{}, val ...interface{}) []interface{} { arr = append(arr, val...) return arr }, "newArray": func() []interface{} { return []interface{}{} }, "strTrim": func(str interface{}, trimStr interface{}) string { strCon := gconv.String(str) strSub := gconv.String(trimStr) if len(strCon) > len(strSub) { strCon = gstr.StrEx(strCon, strSub) } return strCon }, }) //树形菜单选项 tplData := g.Map{ "table": extendData, "goModName": g.Cfg().MustGet(ctx, "gen.goModName").String(), "apiVersion": g.Cfg().MustGet(ctx, "gen.apiName").String(), "modulePath": gstr.StrEx(extendData.PackageName, "internal/app/"), } apiKey := "api" apiValue := "" var tmpApi string if tmpApi, err = view.Parse(ctx, "go/api.template", tplData); err == nil { apiValue = tmpApi apiValue, err = s.trimBreak(apiValue) } else { return } daoKey := "dao" daoValue := "" var tmpDao string if tmpDao, err = view.Parse(ctx, "go/dao.template", tplData); err == nil { daoValue = tmpDao daoValue, err = s.trimBreak(daoValue) } else { return } daoInternalKey := "dao_internal" daoInternalValue := "" var tmpInternalDao string if tmpInternalDao, err = view.Parse(ctx, "go/dao_internal.template", tplData); err == nil { daoInternalValue = tmpInternalDao daoInternalValue, err = s.trimBreak(daoInternalValue) } else { return } modelKey := "model" modelValue := "" var tmpModel string if tmpModel, err = view.Parse(ctx, "go/model.template", tplData); err == nil { modelValue = tmpModel modelValue, err = s.trimBreak(modelValue) } else { return } modelEntityKey := "model_entity" modelEntityValue := "" var tmpModelEntity string if tmpModelEntity, err = view.Parse(ctx, "go/model_entity.template", tplData); err == nil { modelEntityValue = tmpModelEntity modelEntityValue, err = s.trimBreak(modelEntityValue) } else { return } modelDoKey := "model_do" modelDoValue := "" var tmpModelDo string if tmpModelDo, err = view.Parse(ctx, "go/model_do.template", tplData); err == nil { modelDoValue = tmpModelDo modelDoValue, err = s.trimBreak(modelDoValue) } else { return } controllerKey := "controller" controllerValue := "" var tmpController string if tmpController, err = view.Parse(ctx, "go/controller.template", tplData); err == nil { controllerValue = tmpController controllerValue, err = s.trimBreak(controllerValue) } else { return } serviceKey := "service" serviceValue := "" var tmpService string if tmpService, err = view.Parse(ctx, "go/service.template", tplData); err == nil { serviceValue = tmpService serviceValue, err = s.trimBreak(serviceValue) } else { return } logicKey := "logic" logicValue := "" var tmpLogic string if tmpLogic, err = view.Parse(ctx, "go/logic.template", tplData); err == nil { logicValue = tmpLogic logicValue, err = s.trimBreak(logicValue) } else { return } routerKey := "router" routerValue := "" var tmpRouter string if tmpRouter, err = view.Parse(ctx, "go/router.template", tplData); err == nil { routerValue = tmpRouter routerValue, err = s.trimBreak(routerValue) } else { return } routerFuncKey := "router_func" routerFuncValue := "" var tmpRouterFunc string if tmpRouterFunc, err = view.Parse(ctx, "go/router_func.template", tplData); err == nil { routerFuncValue = tmpRouterFunc routerFuncValue, err = s.trimBreak(routerFuncValue) } else { return } sqlKey := "sql" sqlValue := "" var tmpSql string var tmpSqlPath string if s.IsPg() { tmpSqlPath = "sql/pgsql.template" } else { tmpSqlPath = "sql/mysql.template" } if tmpSql, err = view.Parse(ctx, tmpSqlPath, tplData); err == nil { sqlValue = tmpSql sqlValue, err = s.trimBreak(sqlValue) } else { return } tsApiKey := "tsApi" tsApiValue := "" var tmpTsApi string if tmpTsApi, err = view.Parse(ctx, "ts/api.template", tplData); err == nil { tsApiValue = tmpTsApi tsApiValue, err = s.trimBreak(tsApiValue) } else { return } tsModelKey := "tsModel" tsModelValue := "" var tmpTsModel string if tmpTsModel, err = view.Parse(ctx, "ts/model.template", tplData); err == nil { tsModelValue = tmpTsModel tsModelValue, err = s.trimBreak(tsModelValue) } else { return } vueKey := "vue" vueValue := "" var tmpVue string tmpFile := "vue/list-vue.template" if extendData.TplCategory == "tree" { if extendData.UseVirtual { //使用虚拟表树表 tmpFile = "vue/tree-virtual-vue.template" } else { //树表 tmpFile = "vue/tree-vue.template" } } if tmpVue, err = view.Parse(ctx, tmpFile, tplData); err == nil { vueValue = tmpVue vueValue, err = s.trimBreak(vueValue) } else { return } vueEditKey := "vueEdit" vueEditValue := "" var tmpVueEditModel string if tmpVueEditModel, err = view.Parse(ctx, "vue/edit-vue.template", tplData); err == nil { vueEditValue = tmpVueEditModel vueEditValue, err = s.trimBreak(vueEditValue) } else { return } vueDetailKey := "vueDetail" vueDetailValue := "" var tmpVueDetailModel string if tmpVueDetailModel, err = view.Parse(ctx, "vue/detail-vue.template", tplData); err == nil { vueDetailValue = tmpVueDetailModel vueDetailValue, err = s.trimBreak(vueDetailValue) } else { return } data = g.MapStrStr{ apiKey: apiValue, daoKey: daoValue, daoInternalKey: daoInternalValue, modelKey: modelValue, modelEntityKey: modelEntityValue, modelDoKey: modelDoValue, controllerKey: controllerValue, serviceKey: serviceValue, logicKey: logicValue, routerKey: routerValue, routerFuncKey: routerFuncValue, sqlKey: sqlValue, tsApiKey: tsApiValue, tsModelKey: tsModelValue, vueKey: vueValue, vueEditKey: vueEditValue, vueDetailKey: vueDetailValue, } return } func (s *sToolsGenTable) SelectRecordById(ctx context.Context, tableId int64) (tableEx *model.ToolsGenTableEx, err error) { var table *entity.ToolsGenTable table, err = s.GetTableInfoByTableId(ctx, tableId) if err != nil { return } m := gconv.Map(table) err = gconv.Struct(m, &tableEx) if err != nil { return } if tableEx.TplCategory == "tree" { opt := gjson.New(tableEx.Options) tableEx.TreeParentCode = opt.Get("treeParentCode").String() tableEx.TreeCode = opt.Get("treeCode").String() tableEx.TreeName = opt.Get("treeName").String() } //表字段数据 var columns []*entity.ToolsGenTableColumn columns, err = service.ToolsGenTableColumn().SelectGenTableColumnListByTableId(ctx, tableId) if err != nil { return } for _, column := range columns { if column.GoType == "Time" { tableEx.HasTimeColumn = true continue } } allColumnExs := make([]*model.ToolsGenTableColumnEx, len(columns)) var ( editColumns []*model.ToolsGenTableColumnEx listColumns []*model.ToolsGenTableColumnEx detailColumns []*model.ToolsGenTableColumnEx queryColumns []*model.ToolsGenTableColumnEx ) columnMap := make(map[string]*model.ToolsGenTableColumnEx, len(columns)) for i, column := range columns { columnName := column.ColumnName columnEx := &model.ToolsGenTableColumnEx{} m1 := gconv.Map(column) err = gconv.Struct(m1, columnEx) columnMap[columnName] = columnEx allColumnExs[i] = columnEx tableEx.IsPkInsertable = tableEx.IsPkInsertable || column.IsPk && !column.IsIncrement && !tableEx.UseSnowId tableEx.IsPkListable = tableEx.IsPkListable || column.IsPk && column.IsList if column.IsEdit && !service.ToolsGenTableColumn().IsNotEdit(columnName) && !column.IsPk { editColumns = append(editColumns, columnEx) columnEx.IsEdit = true } else { columnEx.IsEdit = false } if column.IsList && !service.ToolsGenTableColumn().IsNotList(columnName) { listColumns = append(listColumns, columnEx) columnEx.IsList = true } else { columnEx.IsList = false } if column.IsDetail && !service.ToolsGenTableColumn().IsNotDetail(columnName) { detailColumns = append(detailColumns, columnEx) columnEx.IsDetail = true } else { columnEx.IsDetail = false } if column.IsQuery && !service.ToolsGenTableColumn().IsNotQuery(columnName) { queryColumns = append(queryColumns, columnEx) columnEx.IsQuery = true } else { columnEx.IsQuery = false } // validation 规则 和 conversion 方法 integerValidationRule := "integer" floatValidationRule := "float" dateValidationRule := "date" datetimeValidationRule := "datetime" if column.QueryType == "BETWEEN" { integerValidationRule += "-array" floatValidationRule += "-array" dateValidationRule += "-array" datetimeValidationRule += "-array" } if column.IsPk { //主键不处理 continue } switch column.GoType { case "byte": columnEx.FieldValidation = gstr.CaseCamelLower(columnName) + "@" + integerValidationRule + "|max-length:1#" + column.ColumnComment + "需为整数" columnEx.FieldConversion = "gconv.Uint64" tableEx.HasConversion = true break case "int": columnEx.FieldValidation = gstr.CaseCamelLower(columnName) + "@" + integerValidationRule + "#" + column.ColumnComment + "需为整数" columnEx.FieldConversion = "gconv.Int" tableEx.HasConversion = true break case "int64": columnEx.FieldValidation = gstr.CaseCamelLower(columnName) + "@" + integerValidationRule + "#" + column.ColumnComment + "需为整数" columnEx.FieldConversion = "gconv.Int64" tableEx.HasConversion = true break case "uint": columnEx.FieldValidation = gstr.CaseCamelLower(columnName) + "@" + integerValidationRule + "#" + column.ColumnComment + "需为整数" columnEx.FieldConversion = "gconv.Uint" tableEx.HasConversion = true break case "uint64": columnEx.FieldValidation = gstr.CaseCamelLower(columnName) + "@" + integerValidationRule + "#" + column.ColumnComment + "需为整数" columnEx.FieldConversion = "gconv.Uint64" tableEx.HasConversion = true break case "float": columnEx.FieldValidation = gstr.CaseCamelLower(columnName) + "@" + floatValidationRule + "#" + column.ColumnComment + "需为浮点数" columnEx.FieldConversion = "gconv.Float" tableEx.HasConversion = true break case "float64": columnEx.FieldValidation = gstr.CaseCamelLower(columnName) + "@" + floatValidationRule + "#" + column.ColumnComment + "需为浮点数" columnEx.FieldConversion = "gconv.Float64" tableEx.HasConversion = true break case "bool": columnEx.FieldValidation = gstr.CaseCamelLower(columnName) + "@boolean#" + column.ColumnComment + "需为true/false" columnEx.FieldConversion = "gconv.Bool" tableEx.HasConversion = true break case "date": case "Time": if column.ColumnType == "date" { columnEx.FieldValidation = gstr.CaseCamelLower(columnName) + "@" + dateValidationRule + "#" + column.ColumnComment + "需为YYYY-MM-DD格式" } else { columnEx.FieldValidation = gstr.CaseCamelLower(columnName) + "@" + datetimeValidationRule + "#" + column.ColumnComment + "需为YYYY-MM-DD hh:mm:ss格式" } columnEx.FieldConversion = "gconv.Time" tableEx.HasConversion = true break } } sort.Slice(editColumns, func(i, j int) bool { return editColumns[i].SortOrderEdit < editColumns[j].SortOrderEdit }) sort.Slice(listColumns, func(i, j int) bool { return listColumns[i].SortOrderList < listColumns[j].SortOrderList }) sort.Slice(detailColumns, func(i, j int) bool { return detailColumns[i].SortOrderDetail < detailColumns[j].SortOrderDetail }) sort.Slice(queryColumns, func(i, j int) bool { return queryColumns[i].SortOrderQuery < queryColumns[j].SortOrderQuery }) tableEx.Columns = allColumnExs tableEx.EditColumns = editColumns tableEx.DetailColumns = detailColumns tableEx.ListColumns = listColumns tableEx.QueryColumns = queryColumns _, hasCreatedBy := columnMap["created_by"] tableEx.HasCreatedBy = hasCreatedBy _, hasDeptId := columnMap["dept_id"] tableEx.HasDeptId = hasDeptId _, hasUpdateBy := columnMap["updated_by"] tableEx.HasUpdatedBy = hasUpdateBy for _, column := range allColumnExs { if column.IsCascade { parentColumnName := column.ParentColumnName if g.IsEmpty(parentColumnName) { err = gerror.New("级联查询字段\"" + column.ColumnName + "\"并未设置parentColumnName") return nil, err } parent := columnMap[parentColumnName] if g.IsEmpty(parent) { err = gerror.New("级联查询字段\"" + column.ColumnName + "\"的parentColumnName\"" + parentColumnName + "\"不存在于表中") return nil, err } column.ParentColumnName = parentColumnName column.CascadeParent = parent parent.IsCascadeParent = true parent.CascadeChildrenColumns = gset.NewStrSet() } } for _, column := range allColumnExs { if column.IsCascade { child := column for { parentColumnName := child.ParentColumnName if g.IsEmpty(parentColumnName) { break } parent := columnMap[parentColumnName] parent.CascadeChildrenColumns.Add(column.ColumnName) child = parent } } } // 提取关联表信息 var linkedTableMap = gmap.New() for _, column := range allColumnExs { if len(column.LinkTableName) == 0 { continue } linkedTableName := column.LinkTableName // 关联表信息 linkedTableInfo, err1 := s.getLinkedTableInfo(ctx, linkedTableName) if err1 != nil { err = err1 return } linkedTable := linkedTableMap.GetOrSet(linkedTableName, interface{}(linkedTableInfo)).(*model.ToolsGenTableLinked) allColumnMap, err2 := service.ToolsGenTableColumn().SelectDbTableColumnMapByName(ctx, linkedTableName) if err2 != nil { err = err2 return } // 关联字段 linkedTableIdColumn, foundId := allColumnMap[column.LinkLabelId] if !foundId { err = gerror.New("无法找到关联表的列" + column.LinkLabelId) return } linkedTableValueColumn, foundValue := allColumnMap[column.LinkLabelName] if !foundValue { err = gerror.New("无法找到关联表的列" + column.LinkLabelId) return } service.ToolsGenTableColumn().InitColumnField(linkedTableIdColumn, table) service.ToolsGenTableColumn().InitColumnField(linkedTableValueColumn, table) if linkedTableIdColumn.GoType == "Time" || linkedTableValueColumn.GoType == "Time" { tableEx.HasTimeColumn = true } linkedTable.RefColumns.GetOrSet(linkedTableIdColumn.ColumnName, linkedTableIdColumn) linkedTable.RefColumns.GetOrSet(linkedTableValueColumn.ColumnName, &linkedTableValueColumn) } tableEx.LinkedTables = make([]*model.ToolsGenTableLinked, linkedTableMap.Size()) for i, v := range linkedTableMap.Values() { tableEx.LinkedTables[i] = v.(*model.ToolsGenTableLinked) } return } // GenCode 代码生成操作 func (s *sToolsGenTable) GenCode(ctx context.Context, ids []int) (err error) { err = g.Try(ctx, func(ctx context.Context) { //获取当前运行时目录 curDir, err := os.Getwd() liberr.ErrIsNil(ctx, err, "获取本地路径失败") frontDir := g.Cfg().MustGet(ctx, "gen.frontDir").String() if !gfile.IsDir(frontDir) { panic("项目前端路径不存在,请检查是否已在配置文件中配置!") } apiName := g.Cfg().MustGet(ctx, "gen.apiName").String() goModName := g.Cfg().MustGet(ctx, "gen.goModName").String() for _, id := range ids { var genData g.MapStrStr var extendData *model.ToolsGenTableEx genData, extendData, err = s.GenData(ctx, gconv.Int64(id)) liberr.ErrIsNil(ctx, err) packageName := extendData.PackageName businessName := gstr.CaseCamelLower(extendData.BusinessName) modulePath := gstr.StrEx(extendData.PackageName, "internal/app/") overwriteInfo := gmap.NewStrAnyMap() for _, ov := range extendData.OverwriteInfo { overwriteInfo.Set(ov.Key, ov.Value) } for key, code := range genData { switch key { case "api": path := strings.Join([]string{curDir, "/", apiName, "/", modulePath, "/", extendData.BusinessName, ".go"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("api"))) liberr.ErrIsNil(ctx, err) case "controller": path := strings.Join([]string{curDir, "/", packageName, "/controller/", extendData.BusinessName, ".go"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("controller"))) liberr.ErrIsNil(ctx, err) case "dao": path := strings.Join([]string{curDir, "/", packageName, "/dao/", extendData.BusinessName, ".go"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("dao"))) liberr.ErrIsNil(ctx, err) case "dao_internal": path := strings.Join([]string{curDir, "/", packageName, "/dao/internal/", extendData.BusinessName, ".go"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("dao_internal"))) liberr.ErrIsNil(ctx, err) case "logic": path := strings.Join([]string{curDir, "/", packageName, "/logic/", businessName, "/", extendData.BusinessName, ".go"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("logic"))) liberr.ErrIsNil(ctx, err) case "model": path := strings.Join([]string{curDir, "/", packageName, "/model/", extendData.BusinessName, ".go"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("model"))) liberr.ErrIsNil(ctx, err) case "model_do": path := strings.Join([]string{curDir, "/", packageName, "/model/do/", extendData.BusinessName, ".go"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("model_do"))) liberr.ErrIsNil(ctx, err) case "model_entity": path := strings.Join([]string{curDir, "/", packageName, "/model/entity/", extendData.BusinessName, ".go"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("model_entity"))) liberr.ErrIsNil(ctx, err) case "router": if !gstr.ContainsI(packageName, "system") { // system 模块不生成router文件 path := strings.Join([]string{curDir, "/", packageName, "/router/router", ".go"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("router"))) liberr.ErrIsNil(ctx, err) } case "router_func": path := strings.Join([]string{curDir, "/", packageName, "/router/", extendData.BusinessName, ".go"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("router_func"))) liberr.ErrIsNil(ctx, err) case "service": path := strings.Join([]string{curDir, "/", packageName, "/service/", extendData.BusinessName, ".go"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("service"))) liberr.ErrIsNil(ctx, err) case "sql": path := strings.Join([]string{curDir, "/resource/data/gen_sql/", modulePath, "/", extendData.BusinessName, ".sql"}, "") hasSql := gfile.Exists(path) err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("sql"))) liberr.ErrIsNil(ctx, err) if !hasSql || gconv.Bool(overwriteInfo.Get("sql")) { //第一次生成则向数据库写入菜单数据 if s.IsPg() { content := gfile.GetContents(path) _, err = g.DB().Exec(ctx, content) } else { err = s.writeDb(ctx, path) } liberr.ErrIsNil(ctx, err) //清除菜单缓存 commonService.Cache().Remove(ctx, consts.CacheSysAuthMenu) } case "tsApi": path := strings.Join([]string{frontDir, "/src/api/", modulePath, "/", businessName, ".ts"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("tsApi"))) liberr.ErrIsNil(ctx, err) case "tsModel": path := strings.Join([]string{frontDir, "/src/views/", modulePath, "/", businessName + "/list/component/model", ".ts"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("tsModel"))) liberr.ErrIsNil(ctx, err) case "vue": path := strings.Join([]string{frontDir, "/src/views/", modulePath, "/", businessName, "/list/index.vue"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("vue"))) liberr.ErrIsNil(ctx, err) case "vueDetail": path := strings.Join([]string{frontDir, "/src/views/", modulePath, "/", businessName + "/list/component/detail", ".vue"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("vueDetail"))) liberr.ErrIsNil(ctx, err) case "vueEdit": path := strings.Join([]string{frontDir, "/src/views/", modulePath, "/", businessName + "/list/component/edit", ".vue"}, "") err = s.createFile(path, code, gconv.Bool(overwriteInfo.Get("vueEdit"))) liberr.ErrIsNil(ctx, err) } } //生成模块路由 err = s.genModuleRouter(curDir, goModName, extendData.ModuleName, modulePath) liberr.ErrIsNil(ctx, err) //生成模块boot logic err = s.genModuleBootLogic(curDir, extendData.ModuleName, modulePath) liberr.ErrIsNil(ctx, err) //生成对应模块的业务logic err = s.genModuleLogic(curDir, goModName, extendData.PackageName) liberr.ErrIsNil(ctx, err) } }) return } // 写入菜单数据 func (s *sToolsGenTable) writeDb(ctx context.Context, path string) (err error) { isAnnotation := false var fi *os.File fi, err = os.Open(path) if err != nil { return } defer fi.Close() br := bufio.NewReader(fi) var sqlStr []string now := gtime.Now() var res sql.Result var id int64 var tx gdb.TX tx, err = g.DB().Ctx(ctx).Begin(ctx) if err != nil { return } for { bytes, e := br.ReadBytes('\n') if e == io.EOF { break } str := gstr.Trim(string(bytes)) if str == "" { continue } if strings.Contains(str, "/*") { isAnnotation = true } if isAnnotation { if strings.Contains(str, "*/") { isAnnotation = false } continue } if str == "" || strings.HasPrefix(str, "--") || strings.HasPrefix(str, "#") { continue } if strings.HasSuffix(str, ";") { if gstr.ContainsI(str, "select") { if gstr.ContainsI(str, "@now") { continue } if gstr.ContainsI(str, "@parentId") { id, err = res.LastInsertId() } } sqlStr = append(sqlStr, str) sql := strings.Join(sqlStr, "") gstr.ReplaceByArray(sql, []string{"@parentId", gconv.String(id), "@now", now.Format("Y-m-d H:i:s")}) //插入业务 res, err = tx.Exec(sql) if err != nil { tx.Rollback() return } sqlStr = nil } else { sqlStr = []string{str} } } tx.Commit() return } // createFile 创建文件 func (s *sToolsGenTable) createFile(fileName, data string, cover bool) (err error) { if !gfile.Exists(fileName) || cover { var f *os.File f, err = gfile.Create(fileName) if err == nil { f.WriteString(data) } f.Close() err = s.goFmt(fileName) } return } func (s *sToolsGenTable) getLinkedTableInfo(ctx context.Context, tableName string) (linkedTable *model.ToolsGenTableLinked, err error) { var table *entity.ToolsGenTable err = g.Try(ctx, func(ctx context.Context) { err = dao.ToolsGenTable.Ctx(ctx).Where(dao.ToolsGenTable.Columns().TableName, tableName).Scan(&table) liberr.ErrIsNil(ctx, err, "获取关联表格"+tableName+"信息出错") m := gconv.Map(table) err = gconv.Struct(m, &linkedTable) liberr.ErrIsNil(ctx, err) if linkedTable.Options != "" { err = gconv.Struct(linkedTable.Options, &linkedTable.OptionsStruct) liberr.ErrIsNil(ctx, err) err = dao.ToolsGenTableColumn.Ctx(ctx).Where(dao.ToolsGenTableColumn.Columns().TableId, table.TableId). Where(dao.ToolsGenTableColumn.Columns().ColumnName, gstr.CaseSnake(linkedTable.OptionsStruct.TreeParentCode)). Scan(&linkedTable.OptionsStruct.ColumnAttr) liberr.ErrIsNil(ctx, err) } linkedTable.RefColumns = gmap.NewListMap() }) return } // 剔除多余的换行 func (s *sToolsGenTable) trimBreak(str string) (rStr string, err error) { var b []byte if b, err = gregex.Replace("(([\\s\t]*)\r?\n){2,}", []byte("$2\n"), []byte(str)); err != nil { return } if b, err = gregex.Replace("(([\\s\t]*)/{4}\r?\n)", []byte("$2\n\n"), b); err == nil { rStr = gconv.String(b) } return } // GenModuleRouter 生成模块logic func (s *sToolsGenTable) genModuleLogic(curDir, goModName, packageName string) (err error) { var ( packages []string code string ) //logic路径 path := strings.Join([]string{curDir, "/", packageName, "/logic"}, "") //获取该路径下所有需要加载的包 packages, err = gfile.ScanDirFunc(path, "*", false, func(p string) string { if gfile.IsDir(p) { return p } return "" }) if err != nil { return } for _, v := range packages { v = gstr.Replace(v, "\\", "/") v = gstr.SubStr(v, gstr.PosR(v, "/")) code += strings.Join([]string{"import _ ", `"`, goModName, "/", packageName, "/logic", v, `"`, "\n"}, "") } code = fmt.Sprintf(`package logic%s%s`, "\n\n", code) err = s.createFile(path+"/logic.go", code, true) return } func (s *sToolsGenTable) genModuleRouter(curDir, goModName, moduleName, modulePath string) (err error) { modulePathName := gstr.CaseCamelLower(gstr.Replace(modulePath, "/", "_")) path := strings.Join([]string{curDir, "/internal/router/" + modulePathName + ".go"}, "") if gfile.IsFile(path) || moduleName == "system" { return } moduleNameUpper := gstr.CaseCamel(modulePathName) code := fmt.Sprintf(`package router import ( "context" "github.com/gogf/gf/v2/net/ghttp" %sRouter "%s/internal/app/%s/router" ) func (router *Router) Bind%sModuleController(ctx context.Context, group *ghttp.RouterGroup) { %sRouter.R.BindController(ctx, group) }`, moduleName, goModName, modulePath, moduleNameUpper, moduleName) err = s.createFile(path, code, true) return } func (s *sToolsGenTable) genModuleBootLogic(curDir, moduleName, modulePath string) (err error) { modulePathName := gstr.CaseCamelLower(gstr.Replace(modulePath, "/", "_")) path := strings.Join([]string{curDir, "/internal/app/boot/" + modulePathName + ".go"}, "") if gfile.IsFile(path) || moduleName == "system" { return } code := fmt.Sprintf(`package boot import ( _ "github.com/tiger1103/gfast/v3/internal/app/%s/logic" ) `, modulePath) err = s.createFile(path, code, true) return } func (s *sToolsGenTable) SyncTable(ctx context.Context, tableId int64) (err error) { var ( extendData *model.ToolsGenTableEx table *entity.ToolsGenTable genTableColumns []*entity.ToolsGenTableColumn ) extendData, err = s.SelectRecordById(ctx, tableId) if err != nil { return } if extendData == nil { err = gerror.New("表格数据不存在") return } err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { err = g.Try(ctx, func(ctx context.Context) { table, err = s.GetTableInfoByTableId(ctx, tableId) liberr.ErrIsNil(ctx, err) if table == nil { liberr.ErrIsNil(ctx, gerror.New("表格数据不存在")) } genTableColumns, err = service.ToolsGenTableColumn().SelectDbTableColumnsByName(ctx, extendData.TableName) liberr.ErrIsNil(ctx, err, "获取列数据失败") if len(genTableColumns) <= 0 { liberr.ErrIsNil(ctx, gerror.New("获取列数据失败")) } for _, column := range genTableColumns { alreadyExists := false //字段是否存在 for _, tableColumn := range extendData.Columns { if column.ColumnName == tableColumn.ColumnName { alreadyExists = true break } } //字段不存在则添加 if !alreadyExists { service.ToolsGenTableColumn().InitColumnField(column, table) _, err = tx.Model(dao.ToolsGenTableColumn.Table()).Insert(column) liberr.ErrIsNil(ctx, err, fmt.Sprintf("保存列`%s`数据失败", column.ColumnName)) } } for _, tableColumn := range extendData.Columns { alreadyDelete := true //数据表中字段是否已删除 for _, column := range genTableColumns { if column.ColumnName == tableColumn.ColumnName { alreadyDelete = false break } } if alreadyDelete { //删除columns表中字段 _, err = dao.ToolsGenTableColumn.Ctx(ctx). Where(dao.ToolsGenTableColumn.Columns().ColumnId, tableColumn.ColumnId). Delete() liberr.ErrIsNil(ctx, err) } } }) return err }) return } // goFmt formats the source file and adds or removes import statements as necessary. func (s *sToolsGenTable) goFmt(path string) (err error) { replaceFunc := func(path, content string) string { res, err := imports.Process(path, []byte(content), nil) if err != nil { g.Log().Printf(context.Background(), `error format "%s" go files: %v`, path, err) return content } return string(res) } if gfile.IsFile(path) { // File format. if gfile.ExtName(path) != "go" { return } err = gfile.ReplaceFileFunc(replaceFunc, path) } else { // Folder format. err = gfile.ReplaceDirFunc(replaceFunc, path, "*.go", true) } if err != nil { err = fmt.Errorf(`error format "%s" go files: %v`, path, err) } return }