1458 lines
48 KiB
Go

/*
* @desc:代码生成表数据处理
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @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
}
if req.Remark != "" {
table.Remark = req.Remark
}
if req.Overwrite != "" {
table.Overwrite = gconv.Bool(req.Overwrite)
}
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 = ""
}
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":
columnEx.FieldValidation = gstr.CaseCamelLower(columnName) + "@" + dateValidationRule + "#" + column.ColumnComment + "需为YYYY-MM-DD格式"
columnEx.FieldConversion = "gconv.Time"
tableEx.HasConversion = true
break
case "Time":
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
_, 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/")
for key, code := range genData {
switch key {
case "api":
path := strings.Join([]string{curDir, "/", apiName, "/", modulePath, "/", extendData.BusinessName, ".go"}, "")
err = s.createFile(path, code, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "controller":
path := strings.Join([]string{curDir, "/", packageName, "/controller/", extendData.BusinessName, ".go"}, "")
err = s.createFile(path, code, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "dao":
path := strings.Join([]string{curDir, "/", packageName, "/dao/", extendData.BusinessName, ".go"}, "")
err = s.createFile(path, code, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "dao_internal":
path := strings.Join([]string{curDir, "/", packageName, "/dao/internal/", extendData.BusinessName, ".go"}, "")
err = s.createFile(path, code, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "logic":
path := strings.Join([]string{curDir, "/", packageName, "/logic/", businessName, "/", extendData.BusinessName, ".go"}, "")
err = s.createFile(path, code, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "model":
path := strings.Join([]string{curDir, "/", packageName, "/model/", extendData.BusinessName, ".go"}, "")
err = s.createFile(path, code, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "model_do":
path := strings.Join([]string{curDir, "/", packageName, "/model/do/", extendData.BusinessName, ".go"}, "")
err = s.createFile(path, code, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "model_entity":
path := strings.Join([]string{curDir, "/", packageName, "/model/entity/", extendData.BusinessName, ".go"}, "")
err = s.createFile(path, code, extendData.Overwrite)
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, false)
liberr.ErrIsNil(ctx, err)
}
case "router_func":
path := strings.Join([]string{curDir, "/", packageName, "/router/", extendData.BusinessName, ".go"}, "")
err = s.createFile(path, code, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "service":
path := strings.Join([]string{curDir, "/", packageName, "/service/", extendData.BusinessName, ".go"}, "")
err = s.createFile(path, code, extendData.Overwrite)
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, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
if !hasSql || extendData.Overwrite {
//第一次生成则向数据库写入菜单数据
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, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "tsModel":
path := strings.Join([]string{frontDir, "/src/views/", modulePath, "/", businessName + "/list/component/model", ".ts"}, "")
err = s.createFile(path, code, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "vue":
path := strings.Join([]string{frontDir, "/src/views/", modulePath, "/", businessName, "/list/index.vue"}, "")
err = s.createFile(path, code, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "vueDetail":
path := strings.Join([]string{frontDir, "/src/views/", modulePath, "/", businessName + "/list/component/detail", ".vue"}, "")
err = s.createFile(path, code, extendData.Overwrite)
liberr.ErrIsNil(ctx, err)
case "vueEdit":
path := strings.Join([]string{frontDir, "/src/views/", modulePath, "/", businessName + "/list/component/edit", ".vue"}, "")
err = s.createFile(path, code, extendData.Overwrite)
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
}