mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-11-14 21:23:47 +08:00
发布代码生成、更新20+表单组件,优化数据字典,gf版本更新到2.3.1
This commit is contained in:
262
server/internal/library/hggen/views/column.go
Normal file
262
server/internal/library/hggen/views/column.go
Normal file
@@ -0,0 +1,262 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/internal/library/hggen/internal/cmd/gendao"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DoTableColumns 获取指定表生成字段列表
|
||||
func DoTableColumns(ctx context.Context, in sysin.GenCodesColumnListInp, config gendao.CGenDaoInput) (fields []*sysin.GenCodesColumnListModel, err error) {
|
||||
var (
|
||||
sql = "select ORDINAL_POSITION as `id`, COLUMN_NAME as `name`, COLUMN_COMMENT as `dc`, DATA_TYPE as `dataType`, COLUMN_TYPE as `sqlType`, CHARACTER_MAXIMUM_LENGTH as `length`, IS_NULLABLE as `isAllowNull`, COLUMN_DEFAULT as `defaultValue`, COLUMN_KEY as `index`, EXTRA as `extra` from information_schema.COLUMNS where TABLE_SCHEMA = '%s' and TABLE_NAME = '%s' ORDER BY `id` ASC"
|
||||
conf = g.DB(in.Name).GetConfig()
|
||||
)
|
||||
|
||||
err = g.DB(in.Name).Ctx(ctx).Raw(fmt.Sprintf(sql, conf.Name, in.Table)).Scan(&fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(fields) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, field := range fields {
|
||||
if in.IsLink == 1 {
|
||||
CustomLinkAttributes(ctx, in.Alias, field, config)
|
||||
} else {
|
||||
CustomAttributes(ctx, field, config)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CustomLinkAttributes 可自定义关联表的字段属性
|
||||
func CustomLinkAttributes(ctx context.Context, alias string, field *sysin.GenCodesColumnListModel, in gendao.CGenDaoInput) {
|
||||
field.GoName, field.GoType, field.TsName, field.TsType = GenGotype(ctx, field, in)
|
||||
|
||||
field.GoName = gstr.UcFirst(alias + field.GoName)
|
||||
field.TsName = gstr.LcFirst(field.GoName)
|
||||
|
||||
setDefaultQueryWhere(field)
|
||||
setDefaultValue(field)
|
||||
}
|
||||
|
||||
// CustomAttributes 可自定义的字段属性
|
||||
func CustomAttributes(ctx context.Context, field *sysin.GenCodesColumnListModel, in gendao.CGenDaoInput) {
|
||||
field.GoName, field.GoType, field.TsName, field.TsType = GenGotype(ctx, field, in)
|
||||
setDefault(field)
|
||||
}
|
||||
|
||||
// GenGotype 生成字段的go类型
|
||||
func GenGotype(ctx context.Context, field *sysin.GenCodesColumnListModel, in gendao.CGenDaoInput) (goName, typeName, tsName, tsType string) {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
tsName = getJsonTagFromCase(field.Name, in.JsonCase)
|
||||
goName = gstr.CaseCamel(field.Name)
|
||||
|
||||
typeName, err = CheckLocalTypeForField(ctx, field.DataType, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
switch typeName {
|
||||
case gdb.LocalTypeDate, gdb.LocalTypeDatetime:
|
||||
if in.StdTime {
|
||||
typeName = "time.Time"
|
||||
} else {
|
||||
typeName = "*gtime.Time"
|
||||
}
|
||||
|
||||
case gdb.LocalTypeInt64Bytes:
|
||||
typeName = "int64"
|
||||
|
||||
case gdb.LocalTypeUint64Bytes:
|
||||
typeName = "uint64"
|
||||
|
||||
// Special type handle.
|
||||
case gdb.LocalTypeJson, gdb.LocalTypeJsonb:
|
||||
if in.GJsonSupport {
|
||||
typeName = "*gjson.Json"
|
||||
} else {
|
||||
typeName = "string"
|
||||
}
|
||||
}
|
||||
|
||||
tsType = ShiftMap[typeName]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckLocalTypeForField checks and returns corresponding type for given db type.
|
||||
func CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue interface{}) (string, error) {
|
||||
var (
|
||||
typeName string
|
||||
typePattern string
|
||||
)
|
||||
match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType)
|
||||
if len(match) == 3 {
|
||||
typeName = gstr.Trim(match[1])
|
||||
typePattern = gstr.Trim(match[2])
|
||||
} else {
|
||||
typeName = gstr.Split(fieldType, " ")[0]
|
||||
}
|
||||
typeName = strings.ToLower(typeName)
|
||||
switch typeName {
|
||||
case
|
||||
"binary",
|
||||
"varbinary",
|
||||
"blob",
|
||||
"tinyblob",
|
||||
"mediumblob",
|
||||
"longblob":
|
||||
return gdb.LocalTypeBytes, nil
|
||||
|
||||
case
|
||||
"int",
|
||||
"tinyint",
|
||||
"small_int",
|
||||
"smallint",
|
||||
"medium_int",
|
||||
"mediumint",
|
||||
"serial":
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return gdb.LocalTypeUint, nil
|
||||
}
|
||||
return gdb.LocalTypeInt, nil
|
||||
|
||||
case
|
||||
"big_int",
|
||||
"bigint",
|
||||
"bigserial":
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return gdb.LocalTypeUint64, nil
|
||||
}
|
||||
return gdb.LocalTypeInt64, nil
|
||||
|
||||
case
|
||||
"real":
|
||||
return gdb.LocalTypeFloat32, nil
|
||||
|
||||
case
|
||||
"float",
|
||||
"double",
|
||||
"decimal",
|
||||
"money",
|
||||
"numeric",
|
||||
"smallmoney":
|
||||
return gdb.LocalTypeFloat64, nil
|
||||
|
||||
case
|
||||
"bit":
|
||||
// It is suggested using bit(1) as boolean.
|
||||
if typePattern == "1" {
|
||||
return gdb.LocalTypeBool, nil
|
||||
}
|
||||
s := gconv.String(fieldValue)
|
||||
// mssql is true|false string.
|
||||
if strings.EqualFold(s, "true") || strings.EqualFold(s, "false") {
|
||||
return gdb.LocalTypeBool, nil
|
||||
}
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return gdb.LocalTypeUint64Bytes, nil
|
||||
}
|
||||
return gdb.LocalTypeInt64Bytes, nil
|
||||
|
||||
case
|
||||
"bool":
|
||||
return gdb.LocalTypeBool, nil
|
||||
|
||||
case
|
||||
"date":
|
||||
return gdb.LocalTypeDate, nil
|
||||
|
||||
case
|
||||
"datetime",
|
||||
"timestamp",
|
||||
"timestamptz":
|
||||
return gdb.LocalTypeDatetime, nil
|
||||
|
||||
case
|
||||
"json":
|
||||
return gdb.LocalTypeJson, nil
|
||||
|
||||
case
|
||||
"jsonb":
|
||||
return gdb.LocalTypeJsonb, nil
|
||||
|
||||
default:
|
||||
// Auto-detect field type, using key match.
|
||||
switch {
|
||||
case strings.Contains(typeName, "text") || strings.Contains(typeName, "char") || strings.Contains(typeName, "character"):
|
||||
return gdb.LocalTypeString, nil
|
||||
|
||||
case strings.Contains(typeName, "float") || strings.Contains(typeName, "double") || strings.Contains(typeName, "numeric"):
|
||||
return gdb.LocalTypeFloat64, nil
|
||||
|
||||
case strings.Contains(typeName, "bool"):
|
||||
return gdb.LocalTypeBool, nil
|
||||
|
||||
case strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob"):
|
||||
return gdb.LocalTypeBytes, nil
|
||||
|
||||
case strings.Contains(typeName, "int"):
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return gdb.LocalTypeUint, nil
|
||||
}
|
||||
return gdb.LocalTypeInt, nil
|
||||
|
||||
case strings.Contains(typeName, "time"):
|
||||
return gdb.LocalTypeDatetime, nil
|
||||
|
||||
case strings.Contains(typeName, "date"):
|
||||
return gdb.LocalTypeDatetime, nil
|
||||
|
||||
default:
|
||||
return gdb.LocalTypeString, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getJsonTagFromCase call gstr.Case* function to convert the s to specified case.
|
||||
func getJsonTagFromCase(str, caseStr string) string {
|
||||
switch gstr.ToLower(caseStr) {
|
||||
case gstr.ToLower("Camel"):
|
||||
return gstr.CaseCamel(str)
|
||||
|
||||
case gstr.ToLower("CamelLower"):
|
||||
return gstr.CaseCamelLower(str)
|
||||
|
||||
case gstr.ToLower("Kebab"):
|
||||
return gstr.CaseKebab(str)
|
||||
|
||||
case gstr.ToLower("KebabScreaming"):
|
||||
return gstr.CaseKebabScreaming(str)
|
||||
|
||||
case gstr.ToLower("Snake"):
|
||||
return gstr.CaseSnake(str)
|
||||
|
||||
case gstr.ToLower("SnakeFirstUpper"):
|
||||
return gstr.CaseSnakeFirstUpper(str)
|
||||
|
||||
case gstr.ToLower("SnakeScreaming"):
|
||||
return gstr.CaseSnakeScreaming(str)
|
||||
}
|
||||
return str
|
||||
}
|
||||
312
server/internal/library/hggen/views/column_default.go
Normal file
312
server/internal/library/hggen/views/column_default.go
Normal file
@@ -0,0 +1,312 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 默认表单组件映射 Ts -> 表单组件
|
||||
var defaultFormModeMap = map[string]string{
|
||||
TsTypeString: FormModeInput,
|
||||
TsTypeNumber: FormModeInputNumber,
|
||||
TsTypeBoolean: FormModeInputNumber,
|
||||
TsTypeArray: FormModeInputDynamic,
|
||||
TsTypeTuple: FormModeInputDynamic,
|
||||
TsTypeAny: FormModeInput,
|
||||
}
|
||||
|
||||
var defaultEditSwitch = map[string]bool{
|
||||
"id": false,
|
||||
"level": false,
|
||||
"tree": false,
|
||||
"created_by": false,
|
||||
"updated_by": false,
|
||||
"created_at": false,
|
||||
"updated_at": false,
|
||||
"deleted_at": false,
|
||||
}
|
||||
var defaultListSwitch = map[string]bool{
|
||||
"level": false,
|
||||
"tree": false,
|
||||
"deleted_at": false,
|
||||
}
|
||||
|
||||
var defaultExportSwitch = map[string]bool{
|
||||
"level": false,
|
||||
"tree": false,
|
||||
"deleted_at": false,
|
||||
}
|
||||
|
||||
var defaultQuerySwitch = map[string]bool{
|
||||
"level": false,
|
||||
"tree": false,
|
||||
"deleted_at": false,
|
||||
}
|
||||
|
||||
var defaultSort = map[string]bool{
|
||||
"id": true,
|
||||
"sort": true,
|
||||
}
|
||||
|
||||
// 默认表单验证映射 物理类型命名识别
|
||||
var defaultFormRoleMap = map[string]string{
|
||||
"mobile": FormRolePhone,
|
||||
"qq": FormRoleQq,
|
||||
"email": FormRoleEmail,
|
||||
"id_card": FormRoleIdCard,
|
||||
"bank_card": FormRoleBankCard,
|
||||
"password": FormRolePassword,
|
||||
"pass": FormRolePassword,
|
||||
"price": FormRoleAmount,
|
||||
}
|
||||
|
||||
// 默认查询条件映射 go类型识别
|
||||
var defaultWhereModeMap = map[string]string{
|
||||
GoTypeString: WhereModeLike,
|
||||
GoTypeDate: WhereModeEq,
|
||||
GoTypeDatetime: WhereModeEq,
|
||||
GoTypeInt: WhereModeEq,
|
||||
GoTypeUint: WhereModeEq,
|
||||
GoTypeInt64: WhereModeEq,
|
||||
GoTypeUint64: WhereModeEq,
|
||||
GoTypeIntSlice: WhereModeIn,
|
||||
GoTypeInt64Slice: WhereModeIn,
|
||||
GoTypeUint64Slice: WhereModeIn,
|
||||
GoTypeFloat32: WhereModeEq,
|
||||
GoTypeFloat64: WhereModeEq,
|
||||
GoTypeBytes: WhereModeEq,
|
||||
GoTypeTime: WhereModeEq,
|
||||
GoTypeGTime: WhereModeEq,
|
||||
GoTypeJson: WhereModeJsonContains,
|
||||
}
|
||||
|
||||
// setDefault 设置默认属性
|
||||
func setDefault(field *sysin.GenCodesColumnListModel) {
|
||||
|
||||
setDefaultEdit(field)
|
||||
|
||||
setDefaultFormMode(field)
|
||||
|
||||
setDefaultFormRole(field)
|
||||
|
||||
setDefaultDictType(field)
|
||||
|
||||
setDefaultList(field)
|
||||
|
||||
setDefaultExport(field)
|
||||
|
||||
setDefaultQuery(field)
|
||||
|
||||
setDefaultQueryWhere(field)
|
||||
|
||||
setDefaultValue(field)
|
||||
|
||||
if field.IsAllowNull == "YES" {
|
||||
field.Required = true
|
||||
}
|
||||
|
||||
if strings.Contains(field.Index, consts.GenCodesIndexUNI) {
|
||||
field.Unique = true
|
||||
}
|
||||
|
||||
if df, ok := defaultSort[field.Name]; ok {
|
||||
field.IsSort = df
|
||||
}
|
||||
|
||||
if field.Dc == "" {
|
||||
field.Dc = field.Name
|
||||
}
|
||||
}
|
||||
|
||||
// setDefaultEdit 设置默认编辑
|
||||
func setDefaultEdit(field *sysin.GenCodesColumnListModel) {
|
||||
field.IsEdit = true
|
||||
|
||||
if field.Index == consts.GenCodesIndexPK {
|
||||
field.IsEdit = false
|
||||
return
|
||||
}
|
||||
|
||||
if df, ok := defaultEditSwitch[field.Name]; ok {
|
||||
field.IsEdit = df
|
||||
}
|
||||
}
|
||||
|
||||
// setDefaultFormMode 设置默认表单组件
|
||||
func setDefaultFormMode(field *sysin.GenCodesColumnListModel) {
|
||||
field.FormMode = FormModeInput
|
||||
if df, ok := defaultFormModeMap[field.TsType]; ok {
|
||||
field.FormMode = df
|
||||
}
|
||||
|
||||
if gstr.HasSuffix(field.GoName, "Status") && IsNumberType(field.GoType) {
|
||||
field.FormMode = FormModeSelect
|
||||
return
|
||||
}
|
||||
|
||||
if field.GoName == "CreatedAt" {
|
||||
field.FormMode = FormModeTimeRange
|
||||
return
|
||||
}
|
||||
|
||||
if field.DataType == "datetime" || field.DataType == "timestamp" || field.DataType == "timestamptz" {
|
||||
field.FormMode = FormModeTime
|
||||
return
|
||||
}
|
||||
|
||||
if field.DataType == "date" {
|
||||
field.FormMode = FormModeDate
|
||||
return
|
||||
}
|
||||
|
||||
if field.GoType == GoTypeString && field.Length >= 200 && field.Length <= 500 {
|
||||
field.FormMode = FormModeInputTextarea
|
||||
return
|
||||
}
|
||||
|
||||
if field.GoType == GoTypeString && field.Length > 500 {
|
||||
field.FormMode = FormModeInputEditor
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// setDefaultFormRole 设置默认表单验证
|
||||
func setDefaultFormRole(field *sysin.GenCodesColumnListModel) {
|
||||
field.FormRole = FormRoleNone
|
||||
|
||||
switch field.GoType {
|
||||
case GoTypeUint, GoTypeUint64:
|
||||
field.FormRole = FormRoleNum
|
||||
return
|
||||
}
|
||||
|
||||
if df, ok := defaultFormRoleMap[field.Name]; ok {
|
||||
field.FormRole = df
|
||||
}
|
||||
}
|
||||
|
||||
// setDefaultDictType 设置默认字典类型
|
||||
func setDefaultDictType(field *sysin.GenCodesColumnListModel) {
|
||||
if gstr.HasSuffix(field.GoName, "Status") && IsNumberType(field.GoType) {
|
||||
field.DictType = 3 // 默认系统状态ID
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// setDefaultList 设置默认列表
|
||||
func setDefaultList(field *sysin.GenCodesColumnListModel) {
|
||||
field.IsList = true
|
||||
switch field.GoType {
|
||||
case GoTypeIntSlice, GoTypeInt64Slice, GoTypeUint64Slice, GoTypeBytes, GoTypeJson:
|
||||
field.IsList = false
|
||||
return
|
||||
}
|
||||
|
||||
if field.Length >= 500 {
|
||||
field.IsList = false
|
||||
return
|
||||
}
|
||||
|
||||
if df, ok := defaultListSwitch[field.Name]; ok {
|
||||
field.IsList = df
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// setDefaultExport 设置默认导出
|
||||
func setDefaultExport(field *sysin.GenCodesColumnListModel) {
|
||||
field.IsExport = true
|
||||
switch field.GoType {
|
||||
case GoTypeIntSlice, GoTypeInt64Slice, GoTypeUint64Slice, GoTypeBytes, GoTypeJson:
|
||||
field.IsExport = false
|
||||
return
|
||||
}
|
||||
|
||||
if field.Length >= 500 {
|
||||
field.IsExport = false
|
||||
return
|
||||
}
|
||||
|
||||
if df, ok := defaultExportSwitch[field.Name]; ok {
|
||||
field.IsExport = df
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// setDefaultQuery 设置默认查询
|
||||
func setDefaultQuery(field *sysin.GenCodesColumnListModel) {
|
||||
field.IsQuery = false
|
||||
|
||||
if field.Index == consts.GenCodesIndexPK {
|
||||
field.IsQuery = true
|
||||
return
|
||||
}
|
||||
|
||||
if field.Index == consts.GenCodesIndexPK {
|
||||
field.IsQuery = true
|
||||
return
|
||||
}
|
||||
|
||||
if gstr.HasSuffix(field.GoName, "Status") && IsNumberType(field.GoType) {
|
||||
field.IsQuery = true
|
||||
return
|
||||
}
|
||||
|
||||
if field.GoName == "CreatedAt" {
|
||||
field.IsQuery = true
|
||||
return
|
||||
}
|
||||
|
||||
if df, ok := defaultQuerySwitch[field.Name]; ok {
|
||||
field.IsQuery = df
|
||||
}
|
||||
}
|
||||
|
||||
// setDefaultQueryWhere 设置默认查询条件
|
||||
func setDefaultQueryWhere(field *sysin.GenCodesColumnListModel) {
|
||||
field.QueryWhere = WhereModeEq
|
||||
|
||||
if field.GoName == "CreatedAt" {
|
||||
field.QueryWhere = WhereModeBetween
|
||||
return
|
||||
}
|
||||
|
||||
if field.Length >= 500 {
|
||||
field.QueryWhere = WhereModeLikeAll
|
||||
return
|
||||
}
|
||||
|
||||
if df, ok := defaultWhereModeMap[field.GoType]; ok {
|
||||
field.QueryWhere = df
|
||||
}
|
||||
}
|
||||
|
||||
// setDefaultValue 设置默认value
|
||||
func setDefaultValue(field *sysin.GenCodesColumnListModel) {
|
||||
var value interface{}
|
||||
if field.DefaultValue == nil {
|
||||
switch field.GoType {
|
||||
case GoTypeString, GoTypeBytes, GoTypeDate, GoTypeDatetime, GoTypeTime, GoTypeGTime:
|
||||
value = ""
|
||||
case GoTypeIntSlice, GoTypeInt64Slice, GoTypeUint64Slice, GoTypeJson:
|
||||
value = nil
|
||||
case GoTypeInt, GoTypeUint, GoTypeInt64, GoTypeUint64:
|
||||
value = 0
|
||||
case GoTypeBool:
|
||||
value = false
|
||||
}
|
||||
} else {
|
||||
value = consts.ConvType(field.DefaultValue, field.GoType)
|
||||
}
|
||||
|
||||
field.DefaultValue = value
|
||||
}
|
||||
248
server/internal/library/hggen/views/column_map.go
Normal file
248
server/internal/library/hggen/views/column_map.go
Normal file
@@ -0,0 +1,248 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
)
|
||||
|
||||
// 字段映射关系
|
||||
|
||||
// go类型
|
||||
const (
|
||||
GoTypeString = "string"
|
||||
GoTypeDate = "date"
|
||||
GoTypeDatetime = "datetime"
|
||||
GoTypeInt = "int"
|
||||
GoTypeUint = "uint"
|
||||
GoTypeInt64 = "int64"
|
||||
GoTypeUint64 = "uint64"
|
||||
GoTypeIntSlice = "[]int"
|
||||
GoTypeInt64Slice = "[]int64"
|
||||
GoTypeUint64Slice = "[]uint64"
|
||||
GoTypeFloat32 = "float32"
|
||||
GoTypeFloat64 = "float64"
|
||||
GoTypeBytes = "[]byte"
|
||||
GoTypeBool = "bool"
|
||||
GoTypeTime = "time.Time"
|
||||
GoTypeGTime = "*gtime.Time"
|
||||
GoTypeJson = "*gjson.Json"
|
||||
)
|
||||
|
||||
var GoTypeNameMap = map[string]string{
|
||||
GoTypeString: GoTypeString,
|
||||
GoTypeDate: GoTypeDate,
|
||||
GoTypeDatetime: GoTypeDatetime,
|
||||
GoTypeInt: GoTypeInt,
|
||||
GoTypeUint: GoTypeUint,
|
||||
GoTypeInt64: GoTypeInt64,
|
||||
GoTypeUint64: GoTypeUint64,
|
||||
GoTypeIntSlice: GoTypeIntSlice,
|
||||
GoTypeInt64Slice: GoTypeInt64Slice,
|
||||
GoTypeUint64Slice: GoTypeUint64Slice,
|
||||
GoTypeFloat32: GoTypeFloat32,
|
||||
GoTypeFloat64: GoTypeFloat64,
|
||||
GoTypeBytes: GoTypeBytes,
|
||||
GoTypeBool: GoTypeBool,
|
||||
GoTypeTime: GoTypeTime,
|
||||
GoTypeGTime: GoTypeGTime,
|
||||
GoTypeJson: GoTypeJson,
|
||||
}
|
||||
|
||||
// ts类型
|
||||
const (
|
||||
TsTypeString = "string"
|
||||
TsTypeNumber = "number"
|
||||
TsTypeBoolean = "boolean"
|
||||
TsTypeArray = "array"
|
||||
TsTypeTuple = "tuple"
|
||||
TsTypeAny = "any"
|
||||
)
|
||||
|
||||
var TsTypeNameMap = map[string]string{
|
||||
TsTypeString: TsTypeString,
|
||||
TsTypeNumber: TsTypeNumber,
|
||||
TsTypeBoolean: TsTypeBoolean,
|
||||
TsTypeArray: TsTypeArray,
|
||||
TsTypeTuple: TsTypeTuple,
|
||||
TsTypeAny: TsTypeAny,
|
||||
}
|
||||
|
||||
// ShiftMap Go -> Ts 类型转换
|
||||
var ShiftMap = map[string]string{
|
||||
GoTypeString: TsTypeString,
|
||||
GoTypeDate: TsTypeString,
|
||||
GoTypeDatetime: TsTypeString,
|
||||
GoTypeInt: TsTypeNumber,
|
||||
GoTypeUint: TsTypeNumber,
|
||||
GoTypeInt64: TsTypeNumber,
|
||||
GoTypeUint64: TsTypeNumber,
|
||||
GoTypeIntSlice: TsTypeArray,
|
||||
GoTypeInt64Slice: TsTypeArray,
|
||||
GoTypeUint64Slice: TsTypeArray,
|
||||
GoTypeFloat32: TsTypeNumber,
|
||||
GoTypeFloat64: TsTypeNumber,
|
||||
GoTypeBytes: TsTypeString,
|
||||
GoTypeBool: TsTypeBoolean,
|
||||
GoTypeTime: TsTypeString,
|
||||
GoTypeGTime: TsTypeString,
|
||||
GoTypeJson: TsTypeAny,
|
||||
}
|
||||
|
||||
// 表单组件
|
||||
const (
|
||||
FormModeInput = "Input" // 文本输入
|
||||
FormModeInputNumber = "InputNumber" // 数字输入
|
||||
FormModeInputTextarea = "InputTextarea" // 文本域
|
||||
FormModeInputEditor = "InputEditor" // 富文本
|
||||
FormModeInputDynamic = "InputDynamic" // 动态键值对
|
||||
FormModeDate = "Date" // 日期选择(Y-M-D)
|
||||
FormModeDateRange = "DateRange" // 日期范围选择
|
||||
FormModeTime = "Time" // 时间选择(Y-M-D H:i:s)
|
||||
FormModeTimeRange = "TimeRange" // 时间范围选择
|
||||
FormModeRadio = "Radio" // 单选按钮
|
||||
FormModeCheckbox = "Checkbox" // 复选按钮
|
||||
FormModeSelect = "Select" // 单选下拉框
|
||||
FormModeSelectMultiple = "SelectMultiple" // 多选下拉框
|
||||
FormModeUploadImage = "UploadImage" // 单图上传
|
||||
FormModeUploadImages = "UploadImages" // 多图上传
|
||||
FormModeUploadFile = "UploadFile" // 单文件上传
|
||||
FormModeUploadFiles = "UploadFiles" // 多文件上传
|
||||
FormModeSwitch = "Switch" // 开关
|
||||
FormModeRate = "Rate" // 评分
|
||||
)
|
||||
|
||||
var FormModes = []string{
|
||||
FormModeInput, FormModeInputNumber, FormModeInputTextarea, FormModeInputEditor, FormModeInputDynamic,
|
||||
FormModeDate, FormModeDateRange, FormModeTime, FormModeTimeRange,
|
||||
FormModeRadio, FormModeCheckbox, FormModeSelect, FormModeSelectMultiple,
|
||||
FormModeUploadImage, FormModeUploadImages, FormModeUploadFile, FormModeUploadFiles,
|
||||
FormModeSwitch,
|
||||
FormModeRate,
|
||||
}
|
||||
|
||||
var FormModeMap = map[string]string{
|
||||
FormModeInput: "文本输入",
|
||||
FormModeInputNumber: "数字输入",
|
||||
FormModeInputTextarea: "文本域",
|
||||
FormModeInputEditor: "富文本",
|
||||
FormModeInputDynamic: "动态键值对",
|
||||
FormModeDate: "日期选择(Y-M-D)",
|
||||
FormModeDateRange: "日期范围选择",
|
||||
FormModeTime: "时间选择(Y-M-D H:i:s)",
|
||||
FormModeTimeRange: "时间范围选择",
|
||||
FormModeRadio: "单选按钮",
|
||||
FormModeCheckbox: "复选按钮",
|
||||
FormModeSelect: "单选下拉框",
|
||||
FormModeSelectMultiple: "多选下拉框",
|
||||
FormModeUploadImage: "单图上传",
|
||||
FormModeUploadImages: "多图上传",
|
||||
FormModeUploadFile: "单文件上传",
|
||||
FormModeUploadFiles: "多文件上传",
|
||||
FormModeSwitch: "开关",
|
||||
FormModeRate: "评分",
|
||||
}
|
||||
|
||||
// 表单验证
|
||||
const (
|
||||
FormRoleNone = "none"
|
||||
FormRoleIp = "ip"
|
||||
FormRolePercentage = "percentage"
|
||||
FormRoleTel = "tel"
|
||||
FormRolePhone = "phone"
|
||||
FormRoleQq = "qq"
|
||||
FormRoleEmail = "email"
|
||||
FormRoleIdCard = "idCard"
|
||||
FormRoleNum = "num"
|
||||
FormRoleBankCard = "bankCard"
|
||||
FormRoleWeibo = "weibo"
|
||||
FormRoleUserName = "userName"
|
||||
FormRoleAccount = "account"
|
||||
FormRolePassword = "password"
|
||||
FormRoleAmount = "amount"
|
||||
)
|
||||
|
||||
var FormRoleMap = map[string]string{
|
||||
FormRoleNone: "不验证",
|
||||
FormRoleIp: "Ipv4或Ipv6",
|
||||
FormRolePercentage: "0-100百分比",
|
||||
FormRoleTel: "固话格式",
|
||||
FormRolePhone: "手机号",
|
||||
FormRoleQq: "QQ号码",
|
||||
FormRoleEmail: "邮箱",
|
||||
FormRoleIdCard: "身份证",
|
||||
FormRoleNum: "非零正整数",
|
||||
FormRoleBankCard: "银行卡",
|
||||
FormRoleWeibo: "微博号",
|
||||
FormRoleUserName: "用户名",
|
||||
FormRoleAccount: "账号",
|
||||
FormRolePassword: "密码",
|
||||
FormRoleAmount: "金额",
|
||||
}
|
||||
|
||||
// 查询条件
|
||||
const (
|
||||
WhereModeEq = "=" // =
|
||||
WhereModeNeq = "!=" // !=
|
||||
WhereModeGt = ">" // >
|
||||
WhereModeGte = ">=" // >=
|
||||
WhereModeLt = "<" // <
|
||||
WhereModeLte = "<=" // <=
|
||||
WhereModeIn = "IN" // IN (...)
|
||||
WhereModeNotIn = "NOT IN" // NOT IN (...)
|
||||
WhereModeBetween = "BETWEEN" // BETWEEN
|
||||
WhereModeNotBetween = "NOT BETWEEN" // NOT BETWEEN
|
||||
WhereModeLike = "LIKE" // LIKE
|
||||
WhereModeLikeAll = "LIKE %...%" // LIKE %...%
|
||||
WhereModeNotLike = "NOT LIKE" // NOT LIKE
|
||||
WhereModeJsonContains = "JSON_CONTAINS(json_doc, val)" // JSON_CONTAINS(json_doc, val[, path]) // 判断是否包含某个json值
|
||||
)
|
||||
|
||||
var WhereModes = []string{WhereModeEq,
|
||||
WhereModeNeq, WhereModeGt, WhereModeGte, WhereModeLt, WhereModeLte,
|
||||
WhereModeIn, WhereModeNotIn,
|
||||
WhereModeBetween, WhereModeNotBetween,
|
||||
WhereModeLike, WhereModeLikeAll, WhereModeNotLike,
|
||||
WhereModeJsonContains,
|
||||
}
|
||||
|
||||
// IsNumberType 是否是数字类型
|
||||
func IsNumberType(goType string) bool {
|
||||
switch goType {
|
||||
case GoTypeInt, GoTypeUint, GoTypeInt64, GoTypeUint64:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func HasColumn(masterFields []*sysin.GenCodesColumnListModel, column string) bool {
|
||||
for _, field := range masterFields {
|
||||
if field.GoName == column {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func HasMaxSort(masterFields []*sysin.GenCodesColumnListModel) bool {
|
||||
return HasColumn(masterFields, "Sort")
|
||||
}
|
||||
|
||||
func HasStatus(headOps []string, masterFields []*sysin.GenCodesColumnListModel) bool {
|
||||
if !gstr.InArray(headOps, "status") {
|
||||
return false
|
||||
}
|
||||
return HasColumn(masterFields, "Status")
|
||||
}
|
||||
|
||||
func HasSwitch(headOps []string, masterFields []*sysin.GenCodesColumnListModel) bool {
|
||||
if !gstr.InArray(headOps, "switch") {
|
||||
return false
|
||||
}
|
||||
return HasColumn(masterFields, "Switch")
|
||||
}
|
||||
632
server/internal/library/hggen/views/curd.go
Normal file
632
server/internal/library/hggen/views/curd.go
Normal file
@@ -0,0 +1,632 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"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/library/hggen/internal/cmd/gendao"
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/utility/convert"
|
||||
"hotgo/utility/file"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var Curd = gCurd{}
|
||||
|
||||
type gCurd struct{}
|
||||
|
||||
type CurdStep struct {
|
||||
HasMaxSort bool `json:"hasMaxSort"`
|
||||
HasAdd bool `json:"hasAdd"`
|
||||
HasBatchDel bool `json:"hasBatchDel"`
|
||||
HasExport bool `json:"hasExport"`
|
||||
HasEdit bool `json:"hasEdit"`
|
||||
HasDel bool `json:"hasDel"`
|
||||
HasView bool `json:"hasView"`
|
||||
HasStatus bool `json:"hasStatus"`
|
||||
HasSwitch bool `json:"hasSwitch"`
|
||||
HasCheck bool `json:"hasCheck"`
|
||||
HasMenu bool `json:"hasMenu"`
|
||||
}
|
||||
|
||||
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 CurdOptions struct {
|
||||
AutoOps []string `json:"autoOps"`
|
||||
ColumnOps []string `json:"columnOps"`
|
||||
HeadOps []string `json:"headOps"`
|
||||
Join []*CurdOptionsJoin `json:"join"`
|
||||
Menu *CurdOptionsMenu `json:"menu"`
|
||||
Step *CurdStep // 转换后的流程控制条件
|
||||
dictMap g.Map // 字典选项 -> 字段映射关系
|
||||
TemplateGroup string `json:"templateGroup"`
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
// 加载主表配置
|
||||
err = in.In.MasterColumns.Scan(&in.masterFields)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(in.masterFields) == 0 {
|
||||
in.masterFields, err = DoTableColumns(ctx, sysin.GenCodesColumnListInp{Name: in.In.DbName, Table: in.In.TableName}, in.DaoConfig)
|
||||
}
|
||||
|
||||
// 主键属性
|
||||
in.pk = l.getPkField(in)
|
||||
if in.pk == nil {
|
||||
return gerror.New("initInput no primary key is set in the table!")
|
||||
}
|
||||
|
||||
// 加载选项
|
||||
err = in.In.Options.Scan(&in.options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
initStep(ctx, in)
|
||||
in.options.dictMap = make(g.Map)
|
||||
in.options.TemplateGroup = "sys"
|
||||
return
|
||||
}
|
||||
|
||||
func initStep(ctx context.Context, 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")
|
||||
in.options.Step.HasExport = gstr.InArray(in.options.HeadOps, "export")
|
||||
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.options.ColumnOps, in.masterFields)
|
||||
in.options.Step.HasCheck = gstr.InArray(in.options.ColumnOps, "check")
|
||||
in.options.Step.HasMenu = gstr.InArray(in.options.AutoOps, "genMenuPermissions")
|
||||
}
|
||||
|
||||
func (l *gCurd) loadView(ctx context.Context, in *CurdPreviewInput) error {
|
||||
view := gview.New()
|
||||
err := view.SetConfigWithMap(g.Map{
|
||||
"Paths": "./resource/template/generate/default/curd",
|
||||
"Delimiters": in.Config.Delimiters,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
view.BindFuncMap(g.Map{
|
||||
"NowYear": gtime.Now().Year, // 当前年
|
||||
"ToLower": strings.ToLower, // 全部小写
|
||||
"LcFirst": gstr.LcFirst, // 首字母小写
|
||||
"UcFirst": gstr.UcFirst, // 首字母大写
|
||||
})
|
||||
|
||||
dictOptions, err := l.generateWebModelDictOptions(ctx, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
view.Assigns(gview.Params{
|
||||
"templateGroup": in.options.TemplateGroup, // 生成模板分组名称
|
||||
"servFunName": l.parseServFunName(in.options.TemplateGroup, in.In.VarName), // 业务服务名称
|
||||
"nowTime": gtime.Now().Format("Y-m-d H:i:s"), // 当前时间
|
||||
"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": dictOptions, // web字典选项
|
||||
})
|
||||
in.view = view
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *gCurd) DoBuild(ctx context.Context, in *CurdBuildInput) (err error) {
|
||||
preview, err := l.DoPreview(ctx, in.PreviewIn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 前置操作
|
||||
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 fmt.Errorf("in doBuild operation beforeEvent to '%s' failed::%v", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var needExecSql bool
|
||||
for _, vi := range preview.Views {
|
||||
// 无需生成
|
||||
if vi.Meth != consts.GenCodesBuildMethCreate && vi.Meth != consts.GenCodesBuildMethCover {
|
||||
continue
|
||||
}
|
||||
|
||||
if gstr.Str(vi.Path, `.`) == ".sql" && !gfile.Exists(vi.Path) {
|
||||
needExecSql = true
|
||||
}
|
||||
|
||||
if err = gfile.PutContents(vi.Path, strings.TrimSpace(vi.Content)); err != nil {
|
||||
return fmt.Errorf("writing content to '%s' failed: %v", vi.Path, err)
|
||||
}
|
||||
|
||||
if gstr.Str(vi.Path, `.`) == ".sql" && needExecSql {
|
||||
if err = ImportSql(ctx, vi.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if gstr.Str(vi.Path, `.`) == ".go" {
|
||||
utils.GoFmt(vi.Path)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 后置操作
|
||||
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 fmt.Errorf("in doBuild operation afterEvent to '%s' failed::%v", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 = new(sysin.GenCodesPreviewModel)
|
||||
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.Path = file.MergeAbs(in.Config.Application.Crud.Templates[0].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.Path = file.MergeAbs(in.Config.Application.Crud.Templates[0].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{"name": "test generateControllerContent..."}
|
||||
genFile = new(sysin.GenFile)
|
||||
)
|
||||
|
||||
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[0].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.Path = file.MergeAbs(in.Config.Application.Crud.Templates[0].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.Path = file.MergeAbs(in.Config.Application.Crud.Templates[0].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.Path = file.MergeAbs(in.Config.Application.Crud.Templates[0].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 err
|
||||
}
|
||||
|
||||
genFile.Content, err = in.view.Parse(ctx, name+".template", tplData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[0].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.Path = file.MergeAbs(in.Config.Application.Crud.Templates[0].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.Path = file.MergeAbs(in.Config.Application.Crud.Templates[0].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.Path = file.MergeAbs(in.Config.Application.Crud.Templates[0].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(in.In.DbName).GetConfig()
|
||||
tplData = g.Map{
|
||||
"dbName": config.Name,
|
||||
"menuTable": config.Prefix + "admin_menu",
|
||||
"mainComponent": "LAYOUT",
|
||||
}
|
||||
genFile = new(sysin.GenFile)
|
||||
)
|
||||
|
||||
if in.options.Menu.Pid > 0 {
|
||||
tplData["mainComponent"] = "ParentLayout" //gstr.LcFirst(in.In.VarName)
|
||||
}
|
||||
|
||||
genFile.Path = file.MergeAbs(in.Config.Application.Crud.Templates[0].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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
126
server/internal/library/hggen/views/curd_generate_input.go
Normal file
126
server/internal/library/hggen/views/curd_generate_input.go
Normal file
@@ -0,0 +1,126 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
)
|
||||
|
||||
const (
|
||||
InputTypeListInp = 1 // 列表输入
|
||||
InputTypeListModel = 2 // 列表输出
|
||||
InputTypeExportModel = 3 // 列表导出
|
||||
)
|
||||
|
||||
func (l *gCurd) inputTplData(ctx context.Context, in *CurdPreviewInput) (data g.Map, err error) {
|
||||
data = make(g.Map)
|
||||
data["listInpColumns"] = l.generateInputListColumns(ctx, in, InputTypeListInp)
|
||||
data["listModelColumns"] = l.generateInputListColumns(ctx, in, InputTypeListModel)
|
||||
data["exportModelColumns"] = l.generateInputListColumns(ctx, in, InputTypeExportModel)
|
||||
return
|
||||
}
|
||||
|
||||
func (l *gCurd) generateInputListColumns(ctx context.Context, in *CurdPreviewInput, inputType int) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
index := 0
|
||||
array := make([][]string, 1000)
|
||||
// 主表
|
||||
for _, field := range in.masterFields {
|
||||
row := l.generateStructFieldDefinition(field, inputType)
|
||||
if row == nil {
|
||||
continue
|
||||
}
|
||||
array[index] = row
|
||||
index++
|
||||
}
|
||||
|
||||
// 关联表
|
||||
if len(in.options.Join) > 0 {
|
||||
for _, v := range in.options.Join {
|
||||
if !isEffectiveJoin(v) {
|
||||
continue
|
||||
}
|
||||
for _, field := range v.Columns {
|
||||
row := l.generateStructFieldDefinition(field, inputType)
|
||||
if row != nil {
|
||||
array[index] = row
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tw := tablewriter.NewWriter(buffer)
|
||||
tw.SetBorder(false)
|
||||
tw.SetRowLine(false)
|
||||
tw.SetAutoWrapText(false)
|
||||
tw.SetColumnSeparator("")
|
||||
tw.AppendBulk(array)
|
||||
tw.Render()
|
||||
stContent := buffer.String()
|
||||
// Let's do this hack of table writer for indent!
|
||||
stContent = gstr.Replace(stContent, " #", "")
|
||||
stContent = gstr.Replace(stContent, "` ", "`")
|
||||
stContent = gstr.Replace(stContent, "``", "")
|
||||
stContent = removeEndWrap(stContent)
|
||||
|
||||
buffer.Reset()
|
||||
buffer.WriteString(stContent)
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// generateStructFieldForModel generates and returns the attribute definition for specified field.
|
||||
func (l *gCurd) generateStructFieldDefinition(field *sysin.GenCodesColumnListModel, inputType int) []string {
|
||||
var (
|
||||
tagKey = "`"
|
||||
result = []string{" #" + field.GoName}
|
||||
descriptionTag = gstr.Replace(formatComment(field.Dc), `"`, `\"`)
|
||||
)
|
||||
|
||||
switch inputType {
|
||||
case InputTypeListInp:
|
||||
if !field.IsQuery {
|
||||
return nil
|
||||
}
|
||||
|
||||
if field.QueryWhere == WhereModeBetween {
|
||||
result = append(result, " #[]"+field.GoType)
|
||||
} else {
|
||||
result = append(result, " #"+field.GoType)
|
||||
}
|
||||
result = append(result, " #"+fmt.Sprintf(tagKey+`json:"%s"`, field.TsName))
|
||||
result = append(result, " #"+fmt.Sprintf(`dc:"%s"`+tagKey, descriptionTag))
|
||||
|
||||
case InputTypeListModel:
|
||||
if !field.IsList {
|
||||
return nil
|
||||
}
|
||||
|
||||
result = append(result, " #"+field.GoType)
|
||||
result = append(result, " #"+fmt.Sprintf(tagKey+`json:"%s"`, field.TsName))
|
||||
result = append(result, " #"+fmt.Sprintf(`dc:"%s"`+tagKey, descriptionTag))
|
||||
case InputTypeExportModel:
|
||||
if !field.IsExport {
|
||||
return nil
|
||||
}
|
||||
|
||||
result = append(result, " #"+field.GoType)
|
||||
result = append(result, " #"+fmt.Sprintf(tagKey+`json:"%s"`, field.TsName))
|
||||
result = append(result, " #"+fmt.Sprintf(`dc:"%s"`+tagKey, descriptionTag))
|
||||
|
||||
default:
|
||||
panic("inputType is invalid")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
215
server/internal/library/hggen/views/curd_generate_logic.go
Normal file
215
server/internal/library/hggen/views/curd_generate_logic.go
Normal file
@@ -0,0 +1,215 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
)
|
||||
|
||||
const (
|
||||
LogicWhereComments = "\n\t// 查询%s\n"
|
||||
LogicWhereNoSupport = "\t// TODO 暂不支持生成[ %s ]查询方式,请自行补充此处代码!"
|
||||
LogicListSimpleSelect = "\tfields, err := hgorm.GenSelect(ctx, sysin.%sListModel{}, dao.%s)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}"
|
||||
LogicListJoinSelect = "\t//关联表select\n\tfields, err := hgorm.GenJoinSelect(ctx, %sin.%sListModel{}, dao.%s, []*hgorm.Join{\n%v\t})"
|
||||
LogicListJoinOnRelation = "\t// 关联表%s\n\tmod = mod.%s(hgorm.GenJoinOnRelation(\n\t\tdao.%s.Table(), dao.%s.Columns().%s, // 主表表名,关联条件\n\t\tdao.%s.Table(), \"%s\", dao.%s.Columns().%s, // 关联表表名,别名,关联条件\n\t)...)\n\n"
|
||||
LogicEditUpdate = "\t\t_, err = dao.%s.Ctx(ctx).\n\t\t\tFieldsEx(\n%s\t\t\t).\n\t\t\tWhere(dao.%s.Columns().%s, in.%s).Data(in).Update()\n\t\tif err != nil {\n\t\t\terr = gerror.Wrap(err, consts.ErrorORM)\n\t\t\treturn err\n\t\t}\n\t\treturn nil"
|
||||
LogicEditInsert = "\t_, err = dao.%s.Ctx(ctx).\n\t\tFieldsEx(\n%s\t\t).\n\t\tData(in).Insert()\n\tif err != nil {\n\t\terr = gerror.Wrap(err, consts.ErrorORM)\n\t\treturn err\n\t}"
|
||||
)
|
||||
|
||||
func (l *gCurd) logicTplData(ctx context.Context, in *CurdPreviewInput) (data g.Map, err error) {
|
||||
data = make(g.Map)
|
||||
data["listWhere"] = l.generateLogicListWhere(ctx, in)
|
||||
data["listJoin"] = l.generateLogicListJoin(ctx, in)
|
||||
data["listOrder"] = l.generateLogicListOrder(ctx, in)
|
||||
data["edit"] = l.generateLogicEdit(ctx, in)
|
||||
data["switchFields"] = l.generateLogicSwitchFields(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
func (l *gCurd) generateLogicSwitchFields(ctx context.Context, in *CurdPreviewInput) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
if in.options.Step.HasSwitch {
|
||||
buffer.WriteString("\t\tdao." + in.In.DaoName + ".Columns().Switch,\n")
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (l *gCurd) generateLogicEdit(ctx context.Context, in *CurdPreviewInput) g.Map {
|
||||
var (
|
||||
data = make(g.Map)
|
||||
updateFieldsEx = ""
|
||||
updateBuffer = bytes.NewBuffer(nil)
|
||||
insertFieldsEx = ""
|
||||
insertBuffer = bytes.NewBuffer(nil)
|
||||
)
|
||||
|
||||
for _, field := range in.masterFields {
|
||||
if field.GoName == "UpdatedBy" {
|
||||
updateBuffer.WriteString("\t\tin.UpdatedBy = contexts.GetUserId(ctx)\n")
|
||||
}
|
||||
|
||||
if field.GoName == "CreatedBy" {
|
||||
insertBuffer.WriteString("\tin.CreatedBy = contexts.GetUserId(ctx)\n")
|
||||
}
|
||||
|
||||
if field.Index == consts.GenCodesIndexPK || field.GoName == "CreatedAt" || field.GoName == "CreatedBy" || field.GoName == "DeletedAt" {
|
||||
updateFieldsEx = updateFieldsEx + "\t\t\t\tdao." + in.In.DaoName + ".Columns()." + field.GoName + ",\n"
|
||||
}
|
||||
|
||||
if field.Index == consts.GenCodesIndexPK || field.GoName == "UpdatedBy" || field.GoName == "DeletedAt" {
|
||||
insertFieldsEx = insertFieldsEx + "\t\t\t\tdao." + in.In.DaoName + ".Columns()." + field.GoName + ",\n"
|
||||
}
|
||||
}
|
||||
|
||||
updateBuffer.WriteString(fmt.Sprintf(LogicEditUpdate, in.In.DaoName, updateFieldsEx, in.In.DaoName, in.pk.GoName, in.pk.GoName))
|
||||
insertBuffer.WriteString(fmt.Sprintf(LogicEditInsert, in.In.DaoName, insertFieldsEx))
|
||||
|
||||
data["update"] = updateBuffer.String()
|
||||
data["insert"] = insertBuffer.String()
|
||||
return data
|
||||
}
|
||||
|
||||
func (l *gCurd) generateLogicListOrder(ctx context.Context, in *CurdPreviewInput) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
if in.options.Step.HasMaxSort {
|
||||
buffer.WriteString("OrderAsc(dao." + in.In.DaoName + ".Columns().Sort).")
|
||||
}
|
||||
buffer.WriteString("OrderDesc(dao." + in.In.DaoName + ".Columns()." + in.pk.GoName + ")")
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (l *gCurd) generateLogicListJoin(ctx context.Context, in *CurdPreviewInput) g.Map {
|
||||
var data = make(g.Map)
|
||||
data["link"] = ""
|
||||
if hasEffectiveJoins(in.options.Join) {
|
||||
var (
|
||||
selectBuffer = bytes.NewBuffer(nil)
|
||||
linkBuffer = bytes.NewBuffer(nil)
|
||||
joinSelectRows string
|
||||
)
|
||||
|
||||
for _, join := range in.options.Join {
|
||||
if isEffectiveJoin(join) {
|
||||
joinSelectRows = joinSelectRows + fmt.Sprintf("\t\t{Dao: dao.%s, Alias: \"%s\"},\n", join.DaoName, join.Alias)
|
||||
linkBuffer.WriteString(fmt.Sprintf(LogicListJoinOnRelation, join.Alias, consts.GenCodesJoinLinkMap[join.LinkMode], in.In.DaoName, in.In.DaoName, gstr.CaseCamel(join.MasterField), join.DaoName, join.Alias, join.DaoName, gstr.CaseCamel(join.Field)))
|
||||
}
|
||||
}
|
||||
|
||||
selectBuffer.WriteString(fmt.Sprintf(LogicListJoinSelect, in.options.TemplateGroup, in.In.VarName, in.In.DaoName, joinSelectRows))
|
||||
|
||||
data["select"] = selectBuffer.String()
|
||||
data["link"] = linkBuffer.String()
|
||||
|
||||
} else {
|
||||
data["select"] = fmt.Sprintf(LogicListSimpleSelect, in.In.VarName, in.In.DaoName)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func (l *gCurd) generateLogicListWhere(ctx context.Context, in *CurdPreviewInput) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
|
||||
// 主表
|
||||
l.generateLogicListWhereEach(buffer, in.masterFields, in.In.DaoName, "")
|
||||
|
||||
// 关联表
|
||||
if hasEffectiveJoins(in.options.Join) {
|
||||
for _, v := range in.options.Join {
|
||||
if isEffectiveJoin(v) {
|
||||
l.generateLogicListWhereEach(buffer, v.Columns, v.DaoName, v.Alias)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (l *gCurd) generateLogicListWhereEach(buffer *bytes.Buffer, fields []*sysin.GenCodesColumnListModel, daoName string, alias string) {
|
||||
isLink := false
|
||||
if alias != "" {
|
||||
alias = `"` + alias + `."+`
|
||||
isLink = true
|
||||
}
|
||||
for _, field := range fields {
|
||||
if !field.IsQuery || field.QueryWhere == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
var (
|
||||
linkMode string
|
||||
whereTag string
|
||||
columnName string
|
||||
)
|
||||
|
||||
if IsNumberType(field.GoType) {
|
||||
linkMode = `in.` + field.GoName + ` > 0`
|
||||
} else if field.GoType == GoTypeGTime {
|
||||
linkMode = `in.` + field.GoName + ` != nil`
|
||||
} else if field.GoType == GoTypeJson {
|
||||
linkMode = `!in.` + field.GoName + `.IsNil()`
|
||||
} else {
|
||||
linkMode = `in.` + field.GoName + ` != ""`
|
||||
}
|
||||
|
||||
if field.QueryWhere == WhereModeBetween || field.QueryWhere == WhereModeNotBetween {
|
||||
linkMode = `len(in.` + field.GoName + `) == 2`
|
||||
}
|
||||
|
||||
buffer.WriteString(fmt.Sprintf(LogicWhereComments, field.Dc))
|
||||
|
||||
// 如果是关联表重新转换字段
|
||||
columnName = field.GoName
|
||||
if isLink {
|
||||
columnName = gstr.CaseCamel(field.Name)
|
||||
}
|
||||
|
||||
switch field.QueryWhere {
|
||||
case WhereModeEq:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.Where(" + alias + "dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + ")\n\t}"
|
||||
case WhereModeNeq:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereNot(dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + ")\n\t}"
|
||||
case WhereModeGt:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereGT(dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + ")\n\t}"
|
||||
case WhereModeGte:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereGTE(dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + ")\n\t}"
|
||||
case WhereModeLt:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereLT(dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + ")\n\t}"
|
||||
case WhereModeLte:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereLTE(dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + ")\n\t}"
|
||||
case WhereModeIn:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereIn(dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + ")\n\t}"
|
||||
case WhereModeNotIn:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereNotIn(dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + ")\n\t}"
|
||||
case WhereModeBetween:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereBetween(dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + "[0], in." + field.GoName + "[1])\n\t}"
|
||||
case WhereModeNotBetween:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereNotBetween(dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + "[0], in." + field.GoName + "[1])\n\t}"
|
||||
case WhereModeLike:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereLike(dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + ")\n\t}"
|
||||
case WhereModeLikeAll:
|
||||
val := `"%"+in.` + field.GoName + `+"%"`
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereLike(dao." + daoName + ".Columns()." + columnName + ", " + val + ")\n\t}"
|
||||
case WhereModeNotLike:
|
||||
whereTag = "\tif " + linkMode + " {\n\t\tmod = mod.WhereNotLike(dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + ")\n\t}"
|
||||
case WhereModeJsonContains:
|
||||
val := "fmt.Sprintf(`JSON_CONTAINS(%s,'%v')`, dao." + daoName + ".Columns()." + columnName + ", in." + field.GoName + ")"
|
||||
whereTag = "\tif in." + field.GoName + linkMode + " {\n\t\tmod = mod.Where(" + val + ")\n\t}"
|
||||
|
||||
default:
|
||||
buffer.WriteString(fmt.Sprintf(LogicWhereNoSupport, field.QueryWhere))
|
||||
}
|
||||
|
||||
buffer.WriteString(whereTag + "\n")
|
||||
}
|
||||
}
|
||||
158
server/internal/library/hggen/views/curd_generate_web_edit.go
Normal file
158
server/internal/library/hggen/views/curd_generate_web_edit.go
Normal file
@@ -0,0 +1,158 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/internal/consts"
|
||||
)
|
||||
|
||||
func (l *gCurd) webEditTplData(ctx context.Context, in *CurdPreviewInput) (data g.Map, err error) {
|
||||
data = make(g.Map)
|
||||
data["formItem"] = l.generateWebEditFormItem(ctx, in)
|
||||
data["script"] = l.generateWebEditScript(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
func (l *gCurd) generateWebEditFormItem(ctx context.Context, in *CurdPreviewInput) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
for k, field := range in.masterFields {
|
||||
if !field.IsEdit {
|
||||
continue
|
||||
}
|
||||
|
||||
if field.Index == consts.GenCodesIndexPK {
|
||||
continue
|
||||
}
|
||||
|
||||
var (
|
||||
defaultComponent = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <n-input placeholder=\"请输入%s\" v-model:value=\"params.%s\" />\n </n-form-item>", field.Dc, field.TsName, field.Dc, field.TsName)
|
||||
component string
|
||||
)
|
||||
|
||||
switch field.FormMode {
|
||||
case FormModeInput:
|
||||
component = defaultComponent
|
||||
|
||||
case FormModeInputNumber:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <n-input-number placeholder=\"请输入%s\" v-model:value=\"params.%s\" />\n </n-form-item>", field.Dc, field.TsName, field.Dc, field.TsName)
|
||||
|
||||
case FormModeInputTextarea:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <n-input type=\"textarea\" placeholder=\"%s\" v-model:value=\"params.%s\" />\n </n-form-item>", field.Dc, field.TsName, field.Dc, field.TsName)
|
||||
|
||||
case FormModeInputEditor:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <Editor style=\"height: 450px\" v-model:value=\"params.%s\" />\n </n-form-item>", field.Dc, field.TsName, field.TsName)
|
||||
|
||||
case FormModeInputDynamic:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <n-dynamic-input\n v-model:value=\"params.%s\"\n preset=\"pair\"\n key-placeholder=\"键名\"\n value-placeholder=\"键值\"\n />\n </n-form-item>", field.Dc, field.TsName, field.TsName)
|
||||
|
||||
case FormModeDate:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <DatePicker v-model:formValue=\"params.%s\" type=\"date\" />\n </n-form-item>", field.Dc, field.TsName, field.TsName)
|
||||
|
||||
//case FormModeDateRange: // 必须要有两个字段,后面优化下
|
||||
|
||||
case FormModeTime:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <DatePicker v-model:formValue=\"params.%s\" type=\"datetime\" />\n </n-form-item>", field.Dc, field.TsName, field.TsName)
|
||||
|
||||
//case FormModeTimeRange: // 必须要有两个字段,后面优化下
|
||||
|
||||
case FormModeRadio:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <n-radio-group v-model:value=\"params.%s\" name=\"%s\">\n <n-radio-button\n v-for=\"%s in options.%s\"\n :key=\"%s.value\"\n :value=\"%s.value\"\n :label=\"%s.label\"\n />\n </n-radio-group>\n </n-form-item>", field.Dc, field.TsName, field.TsName, field.TsName, field.TsName, in.options.dictMap[field.TsName], field.TsName, field.TsName, field.TsName)
|
||||
|
||||
case FormModeCheckbox:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <n-checkbox-group v-model:value=\"params.%s\">\n <n-space>\n <n-checkbox\n v-for=\"item in options.%s\"\n :key=\"item.value\"\n :value=\"item.value\"\n :label=\"item.label\"\n />\n </n-space>\n </n-checkbox-group>\n </n-form-item>", field.Dc, field.TsName, field.TsName, in.options.dictMap[field.TsName])
|
||||
|
||||
case FormModeSelect:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <n-select v-model:value=\"params.%s\" :options=\"options.%s\" />\n </n-form-item>", field.Dc, field.TsName, field.TsName, in.options.dictMap[field.TsName])
|
||||
|
||||
case FormModeSelectMultiple:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <n-select multiple v-model:value=\"params.%s\" :options=\"options.%s\" />\n </n-form-item>", field.Dc, field.TsName, field.TsName, in.options.dictMap[field.TsName])
|
||||
|
||||
case FormModeUploadImage:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <UploadImage :maxNumber=\"1\" v-model:value=\"params.%s\" />\n </n-form-item>", field.Dc, field.TsName, field.TsName)
|
||||
|
||||
case FormModeUploadImages:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <UploadImage :maxNumber=\"10\" v-model:value=\"params.%s\" />\n </n-form-item>", field.Dc, field.TsName, field.TsName)
|
||||
|
||||
case FormModeUploadFile:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <UploadFile :maxNumber=\"1\" v-model:value=\"params.%s\" />\n </n-form-item>", field.Dc, field.TsName, field.TsName)
|
||||
|
||||
case FormModeUploadFiles:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <UploadFile :maxNumber=\"10\" v-model:value=\"params.%s\" />\n </n-form-item>", field.Dc, field.TsName, field.TsName)
|
||||
|
||||
case FormModeSwitch:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <n-switch v-model:value=\"params.%s\"\n />\n </n-form-item>", field.Dc, field.TsName, field.TsName)
|
||||
|
||||
case FormModeRate:
|
||||
component = fmt.Sprintf("<n-form-item label=\"%s\" path=\"%s\">\n <n-rate allow-half :default-value=\"params.%s\" :on-update:value=\"update%s\" />\n </n-form-item>", field.Dc, field.TsName, field.TsName, field.GoName)
|
||||
|
||||
default:
|
||||
component = defaultComponent
|
||||
}
|
||||
|
||||
if len(in.masterFields) == k {
|
||||
buffer.WriteString(" " + component)
|
||||
} else {
|
||||
buffer.WriteString(" " + component + "\n\n")
|
||||
}
|
||||
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (l *gCurd) generateWebEditScript(ctx context.Context, in *CurdPreviewInput) g.Map {
|
||||
var (
|
||||
data = make(g.Map)
|
||||
importBuffer = bytes.NewBuffer(nil)
|
||||
setupBuffer = bytes.NewBuffer(nil)
|
||||
)
|
||||
|
||||
if in.options.Step.HasMaxSort {
|
||||
importBuffer.WriteString(" import { onMounted, ref, computed, watch } from 'vue';\n")
|
||||
importBuffer.WriteString(" import { Edit, MaxSort } from '@/api/" + gstr.LcFirst(in.In.VarName) + "';\n")
|
||||
setupBuffer.WriteString(" watch(\n () => params.value,\n (value) => {\n if (value.id === 0) {\n MaxSort().then((res) => {\n params.value.sort = res.sort;\n });\n }\n }\n );\n\n")
|
||||
} else {
|
||||
importBuffer.WriteString(" import { onMounted, ref, computed } from 'vue';\n")
|
||||
importBuffer.WriteString(" import { Edit } from '@/api/" + gstr.LcFirst(in.In.VarName) + "';\n")
|
||||
}
|
||||
|
||||
for _, field := range in.masterFields {
|
||||
if !field.IsEdit {
|
||||
continue
|
||||
}
|
||||
switch field.FormMode {
|
||||
case FormModeDate, FormModeDateRange, FormModeTime, FormModeTimeRange:
|
||||
if !gstr.Contains(importBuffer.String(), `import DatePicker`) {
|
||||
importBuffer.WriteString(" import DatePicker from '@/components/DatePicker/datePicker.vue';\n")
|
||||
}
|
||||
case FormModeInputEditor:
|
||||
if !gstr.Contains(importBuffer.String(), `import Editor`) {
|
||||
importBuffer.WriteString(" import Editor from '@/components/Editor/editor.vue';\n")
|
||||
}
|
||||
case FormModeUploadImage, FormModeUploadImages:
|
||||
if !gstr.Contains(importBuffer.String(), `import UploadImage`) {
|
||||
importBuffer.WriteString(" import UploadImage from '@/components/Upload/uploadImage.vue';\n")
|
||||
}
|
||||
case FormModeUploadFile, FormModeUploadFiles:
|
||||
if !gstr.Contains(importBuffer.String(), `import UploadFile`) {
|
||||
importBuffer.WriteString(" import UploadFile from '@/components/Upload/uploadFile.vue';\n")
|
||||
}
|
||||
case FormModeRate:
|
||||
setupBuffer.WriteString(fmt.Sprintf(" function update%s(num) {\n params.value.%s = num;\n }\n", field.GoName, field.TsName))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data["import"] = importBuffer.String()
|
||||
data["setup"] = setupBuffer.String()
|
||||
|
||||
return data
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 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/frame/g"
|
||||
)
|
||||
|
||||
func (l *gCurd) webIndexTplData(ctx context.Context, in *CurdPreviewInput) (data g.Map, err error) {
|
||||
data = make(g.Map)
|
||||
return
|
||||
}
|
||||
285
server/internal/library/hggen/views/curd_generate_web_model.go
Normal file
285
server/internal/library/hggen/views/curd_generate_web_model.go
Normal file
@@ -0,0 +1,285 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/utility/convert"
|
||||
)
|
||||
|
||||
const (
|
||||
ModelLoadOptionsTemplate = "async function loadOptions() {\n options.value = await Dicts({\n types: [\n %v ],\n });\n for (const item of schemas.value) {\n switch (item.field) {\n%v }\n }\n}\n\nawait loadOptions();"
|
||||
)
|
||||
|
||||
func (l *gCurd) webModelTplData(ctx context.Context, in *CurdPreviewInput) (data g.Map, err error) {
|
||||
data = make(g.Map)
|
||||
data["state"] = l.generateWebModelState(ctx, in)
|
||||
data["defaultState"] = l.generateWebModelDefaultState(ctx, in)
|
||||
data["rules"] = l.generateWebModelRules(ctx, in)
|
||||
data["formSchema"] = l.generateWebModelFormSchema(ctx, in)
|
||||
data["columns"] = l.generateWebModelColumns(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
func (l *gCurd) generateWebModelState(ctx context.Context, in *CurdPreviewInput) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteString("export interface State {\n")
|
||||
for _, field := range in.masterFields {
|
||||
buffer.WriteString(fmt.Sprintf(" %s: %s;\n", field.TsName, field.TsType))
|
||||
}
|
||||
buffer.WriteString("}")
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (l *gCurd) generateWebModelDefaultState(ctx context.Context, in *CurdPreviewInput) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteString("export const defaultState = {\n")
|
||||
for _, field := range in.masterFields {
|
||||
var value = field.DefaultValue
|
||||
if value == nil {
|
||||
value = "null"
|
||||
}
|
||||
if value == "" {
|
||||
value = "''"
|
||||
}
|
||||
buffer.WriteString(fmt.Sprintf(" %s: %v,\n", field.TsName, value))
|
||||
}
|
||||
buffer.WriteString("};")
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (l *gCurd) generateWebModelDictOptions(ctx context.Context, in *CurdPreviewInput) (g.Map, error) {
|
||||
type DictType struct {
|
||||
Id int64 `json:"id"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
var (
|
||||
options = make(g.Map)
|
||||
dictTypeIds []int64
|
||||
dictTypeList []*DictType
|
||||
)
|
||||
|
||||
for _, field := range in.masterFields {
|
||||
if field.DictType > 0 {
|
||||
dictTypeIds = append(dictTypeIds, field.DictType)
|
||||
}
|
||||
}
|
||||
|
||||
dictTypeIds = convert.UniqueSliceInt64(dictTypeIds)
|
||||
if len(dictTypeIds) == 0 {
|
||||
options["has"] = false
|
||||
return options, nil
|
||||
}
|
||||
|
||||
err := g.Model("sys_dict_type").Ctx(ctx).
|
||||
Fields("id", "type").
|
||||
WhereIn("id", dictTypeIds).
|
||||
Scan(&dictTypeList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(dictTypeList) == 0 {
|
||||
options["has"] = false
|
||||
return options, nil
|
||||
}
|
||||
|
||||
options["has"] = true
|
||||
|
||||
var (
|
||||
awaitLoadOptions string
|
||||
switchLoadOptions string
|
||||
)
|
||||
|
||||
constOptionsBuffer := bytes.NewBuffer(nil)
|
||||
constOptionsBuffer.WriteString("export const options = ref<Options>({\n")
|
||||
|
||||
for _, v := range dictTypeList {
|
||||
// 字段映射字典
|
||||
for _, field := range in.masterFields {
|
||||
if field.DictType > 0 && v.Id == field.DictType {
|
||||
in.options.dictMap[field.TsName] = v.Type
|
||||
switchLoadOptions = fmt.Sprintf("%s case '%s':\n item.componentProps.options = options.value.%s;\n break;\n", switchLoadOptions, field.TsName, v.Type)
|
||||
}
|
||||
}
|
||||
|
||||
awaitLoadOptions = fmt.Sprintf("%s '%s',\n", awaitLoadOptions, v.Type)
|
||||
constOptionsBuffer.WriteString(" " + v.Type + ": [],\n")
|
||||
}
|
||||
|
||||
constOptionsBuffer.WriteString("});\n")
|
||||
|
||||
loadOptionsBuffer := bytes.NewBuffer(nil)
|
||||
loadOptionsBuffer.WriteString(fmt.Sprintf(ModelLoadOptionsTemplate, awaitLoadOptions, switchLoadOptions))
|
||||
|
||||
options["const"] = constOptionsBuffer.String()
|
||||
options["load"] = loadOptionsBuffer.String()
|
||||
|
||||
return options, nil
|
||||
}
|
||||
|
||||
func (l *gCurd) generateWebModelRules(ctx context.Context, in *CurdPreviewInput) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteString("export const rules = {\n")
|
||||
for _, field := range in.masterFields {
|
||||
if field.FormRole == "" || field.FormRole == FormRoleNone {
|
||||
continue
|
||||
}
|
||||
|
||||
buffer.WriteString(fmt.Sprintf(" %s: {\n required: %v,\n trigger: ['blur', 'input'],\n message: '请输入%s',\n validator: validate.%v,\n },\n", field.TsName, field.Required, field.Dc, field.FormRole))
|
||||
}
|
||||
buffer.WriteString("};\n")
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (l *gCurd) generateWebModelFormSchema(ctx context.Context, in *CurdPreviewInput) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteString("export const schemas = ref<FormSchema[]>([\n")
|
||||
|
||||
// 主表
|
||||
l.generateWebModelFormSchemaEach(buffer, in.masterFields)
|
||||
|
||||
// 关联表
|
||||
if len(in.options.Join) > 0 {
|
||||
for _, v := range in.options.Join {
|
||||
if !isEffectiveJoin(v) {
|
||||
continue
|
||||
}
|
||||
l.generateWebModelFormSchemaEach(buffer, v.Columns)
|
||||
}
|
||||
}
|
||||
|
||||
buffer.WriteString("]);\n")
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (l *gCurd) generateWebModelFormSchemaEach(buffer *bytes.Buffer, fields []*sysin.GenCodesColumnListModel) {
|
||||
for _, field := range fields {
|
||||
if !field.IsQuery {
|
||||
continue
|
||||
}
|
||||
|
||||
var (
|
||||
defaultComponent = fmt.Sprintf(" {\n field: '%s',\n component: '%s',\n label: '%s',\n componentProps: {\n placeholder: '请输入%s',\n onUpdateValue: (e: any) => {\n console.log(e);\n },\n },\n },\n", field.TsName, "NInput", field.Dc, field.Dc)
|
||||
component string
|
||||
)
|
||||
|
||||
// 这里根据编辑表单组件来进行推断,如果没有则使用默认input,这可能会导致和查询条件所需参数不符的情况
|
||||
switch field.FormMode {
|
||||
case FormModeInput, FormModeInputTextarea, FormModeInputEditor:
|
||||
component = defaultComponent
|
||||
|
||||
case FormModeInputNumber:
|
||||
component = fmt.Sprintf(" {\n field: '%s',\n component: '%s',\n label: '%s',\n componentProps: {\n placeholder: '请输入%s',\n onUpdateValue: (e: any) => {\n console.log(e);\n },\n },\n },\n", field.TsName, "NInputNumber", field.Dc, field.Dc)
|
||||
|
||||
case FormModeDate:
|
||||
component = fmt.Sprintf(" {\n field: '%s',\n component: '%s',\n label: '%s',\n componentProps: {\n type: '%s',\n clearable: true,\n shortcuts: %s,\n onUpdateValue: (e: any) => {\n console.log(e);\n },\n },\n },\n", field.TsName, "NDatePicker", field.Dc, "date", "defShortcuts()")
|
||||
|
||||
case FormModeDateRange:
|
||||
component = fmt.Sprintf(" {\n field: '%s',\n component: '%s',\n label: '%s',\n componentProps: {\n type: '%s',\n clearable: true,\n shortcuts: %s,\n onUpdateValue: (e: any) => {\n console.log(e);\n },\n },\n },\n", field.TsName, "NDatePicker", field.Dc, "daterange", "defRangeShortcuts()")
|
||||
|
||||
case FormModeTime:
|
||||
component = fmt.Sprintf(" {\n field: '%s',\n component: '%s',\n label: '%s',\n componentProps: {\n type: '%s',\n clearable: true,\n shortcuts: %s,\n onUpdateValue: (e: any) => {\n console.log(e);\n },\n },\n },\n", field.TsName, "NDatePicker", field.Dc, "datetime", "defShortcuts()")
|
||||
|
||||
case FormModeTimeRange:
|
||||
component = fmt.Sprintf(" {\n field: '%s',\n component: '%s',\n label: '%s',\n componentProps: {\n type: '%s',\n clearable: true,\n shortcuts: %s,\n onUpdateValue: (e: any) => {\n console.log(e);\n },\n },\n },\n", field.TsName, "NDatePicker", field.Dc, "datetimerange", "defRangeShortcuts()")
|
||||
|
||||
case FormModeRadio:
|
||||
component = fmt.Sprintf(" {\n field: '%s',\n component: '%s',\n label: '%s',\n giProps: {\n //span: 24,\n },\n componentProps: {\n options: [],\n onUpdateChecked: (e: any) => {\n console.log(e);\n },\n },\n },\n", field.TsName, "NRadioGroup", field.Dc)
|
||||
|
||||
case FormModeCheckbox:
|
||||
component = fmt.Sprintf(" {\n field: '%s',\n component: '%s',\n label: '%s',\n giProps: {\n span: 1,\n },\n componentProps: {\n placeholder: '请选择%s',\n options: [],\n onUpdateChecked: (e: any) => {\n console.log(e);\n },\n },\n },\n", field.TsName, "NCheckbox", field.Dc, field.Dc)
|
||||
|
||||
case FormModeSelect:
|
||||
component = fmt.Sprintf(" {\n field: '%s',\n component: '%s',\n label: '%s',\n defaultValue: null,\n componentProps: {\n placeholder: '请选择%s',\n options: [],\n onUpdateValue: (e: any) => {\n console.log(e);\n },\n },\n },\n", field.TsName, "NSelect", field.Dc, field.Dc)
|
||||
|
||||
case FormModeSelectMultiple:
|
||||
component = fmt.Sprintf(" {\n field: '%s',\n component: '%s',\n label: '%s',\n defaultValue: null,\n componentProps: {\n multiple: true,\n placeholder: '请选择%s',\n options: [],\n onUpdateValue: (e: any) => {\n console.log(e);\n },\n },\n },\n", field.TsName, "NSelect", field.Dc, field.Dc)
|
||||
|
||||
default:
|
||||
component = defaultComponent
|
||||
}
|
||||
|
||||
buffer.WriteString(component)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *gCurd) generateWebModelColumns(ctx context.Context, in *CurdPreviewInput) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteString("export const columns = [\n")
|
||||
|
||||
// 主表
|
||||
l.generateWebModelColumnsEach(buffer, in, in.masterFields)
|
||||
|
||||
// 关联表
|
||||
if len(in.options.Join) > 0 {
|
||||
for _, v := range in.options.Join {
|
||||
if !isEffectiveJoin(v) {
|
||||
continue
|
||||
}
|
||||
l.generateWebModelColumnsEach(buffer, in, v.Columns)
|
||||
}
|
||||
}
|
||||
|
||||
buffer.WriteString("];\n")
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (l *gCurd) generateWebModelColumnsEach(buffer *bytes.Buffer, in *CurdPreviewInput, fields []*sysin.GenCodesColumnListModel) {
|
||||
for _, field := range fields {
|
||||
if !field.IsList {
|
||||
continue
|
||||
}
|
||||
var (
|
||||
defaultComponent = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n },\n", field.Dc, field.TsName)
|
||||
component string
|
||||
)
|
||||
|
||||
// 这里根据编辑表单组件来进行推断,如果没有则使用默认input,这可能会导致和查询条件所需参数不符的情况
|
||||
switch field.FormMode {
|
||||
case FormModeDate:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n return formatToDate(row.%s);\n },\n },\n", field.Dc, field.TsName, field.TsName)
|
||||
|
||||
case FormModeSelect:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s)) {\n return ``;\n }\n return h(\n NTag,\n {\n style: {\n marginRight: '6px',\n },\n type: getOptionTag(options.value.%s, row.%s),\n bordered: false,\n },\n {\n default: () => getOptionLabel(options.value.%s, row.%s),\n }\n );\n },\n },\n", field.Dc, field.TsName, field.TsName, in.options.dictMap[field.TsName], field.TsName, in.options.dictMap[field.TsName], field.TsName)
|
||||
|
||||
case FormModeSelectMultiple:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s) || !isArray(row.%s)) {\n return ``;\n }\n return row.%s.map((tagKey) => {\n return h(\n NTag,\n {\n style: {\n marginRight: '6px',\n },\n type: getOptionTag(options.value.%s, tagKey),\n bordered: false,\n },\n {\n default: () => getOptionLabel(options.value.%s, tagKey),\n }\n );\n });\n },\n },\n", field.Dc, field.TsName, field.TsName, field.TsName, field.TsName, in.options.dictMap[field.TsName], in.options.dictMap[field.TsName])
|
||||
|
||||
case FormModeUploadImage:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n return h(%s, {\n width: 32,\n height: 32,\n src: row.%s,\n style: {\n width: '32px',\n height: '32px',\n 'max-width': '100%%',\n 'max-height': '100%%',\n },\n });\n },\n },\n", field.Dc, field.TsName, "NImage", field.TsName)
|
||||
|
||||
case FormModeUploadImages:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s)) {\n return ``;\n }\n return row.%s.map((image) => {\n return h(%s, {\n width: 32,\n height: 32,\n src: image,\n style: {\n width: '32px',\n height: '32px',\n 'max-width': '100%%',\n 'max-height': '100%%',\n 'margin-left': '2px',\n },\n });\n });\n },\n },\n", field.Dc, field.TsName, field.TsName, field.TsName, "NImage")
|
||||
|
||||
case FormModeUploadFile:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (row.%s === '') {\n return ``;\n }\n return h(\n %s,\n {\n size: 'small',\n },\n {\n default: () => getFileExt(row.%s),\n }\n );\n },\n },\n", field.Dc, field.TsName, field.TsName, "NAvatar", field.TsName)
|
||||
|
||||
case FormModeUploadFiles:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s)) {\n return ``;\n }\n return row.%s.map((attachfile) => {\n return h(\n %s,\n {\n size: 'small',\n style: {\n 'margin-left': '2px',\n },\n },\n {\n default: () => getFileExt(attachfile),\n }\n );\n });\n },\n },\n", field.Dc, field.TsName, field.TsName, field.TsName, "NAvatar")
|
||||
|
||||
case FormModeSwitch:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n width: 100,\n render(row) {\n return h(%s, {\n value: row.%s === 1,\n checked: '开启',\n unchecked: '关闭',\n disabled: !hasPermission(['%s']),\n onUpdateValue: function (e) {\n console.log('onUpdateValue e:' + JSON.stringify(e));\n row.%s = e ? 1 : 2;\n Switch({ %s: row.%s, key: '%s', value: row.%s }).then((_res) => {\n $message.success('操作成功');\n });\n },\n });\n },\n },\n", field.Dc, field.TsName, "NSwitch", field.TsName, "/"+gstr.LcFirst(in.In.VarName)+"/switch", field.TsName, in.pk.TsName, in.pk.TsName, field.TsName, field.TsName)
|
||||
|
||||
case FormModeRate:
|
||||
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n return h(%s, {\n allowHalf: true,\n readonly: true,\n defaultValue: row.%s,\n });\n },\n },\n", field.Dc, field.TsName, "NRate", field.TsName)
|
||||
|
||||
default:
|
||||
component = defaultComponent
|
||||
}
|
||||
|
||||
buffer.WriteString(component)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Package views
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
//
|
||||
package views
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (l *gCurd) webViewTplData(ctx context.Context, in *CurdPreviewInput) (data g.Map, err error) {
|
||||
data = make(g.Map)
|
||||
data["item"] = l.generateWebViewItem(ctx, in)
|
||||
return
|
||||
}
|
||||
|
||||
func (l *gCurd) generateWebViewItem(ctx context.Context, in *CurdPreviewInput) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
for _, field := range in.masterFields {
|
||||
if !field.IsEdit {
|
||||
continue
|
||||
}
|
||||
|
||||
var (
|
||||
defaultComponent = fmt.Sprintf("<n-descriptions-item>\n <template #label>%s</template>\n {{ formValue.%s }}\n </n-descriptions-item>", field.Dc, field.TsName)
|
||||
component string
|
||||
)
|
||||
|
||||
switch field.FormMode {
|
||||
|
||||
case FormModeInputTextarea, FormModeInputEditor:
|
||||
component = fmt.Sprintf("<n-descriptions-item>\n <template #label>%s</template>\n <span v-html=\"formValue.%s\"></span></n-descriptions-item>", field.Dc, field.TsName)
|
||||
|
||||
case FormModeInputDynamic:
|
||||
component = defaultComponent
|
||||
|
||||
case FormModeDate:
|
||||
component = defaultComponent
|
||||
|
||||
case FormModeTime:
|
||||
component = defaultComponent
|
||||
|
||||
case FormModeRadio, FormModeCheckbox, FormModeSelect, FormModeSelectMultiple:
|
||||
component = fmt.Sprintf("<n-descriptions-item label=\"%s\">\n <template v-for=\"(item, key) in formValue?.%s\" :key=\"key\">\n <n-tag\n :type=\"getOptionTag(options.%s, item)\"\n size=\"small\"\n class=\"min-left-space\"\n >{{ getOptionLabel(options.%s, item) }}</n-tag\n >\n </template>\n </n-descriptions-item>", field.Dc, field.TsName, in.options.dictMap[field.TsName], in.options.dictMap[field.TsName])
|
||||
|
||||
case FormModeUploadImage:
|
||||
component = fmt.Sprintf("<n-descriptions-item>\n <template #label>%s</template>\n <n-image style=\"margin-left: 10px; height: 100px; width: 100px\" :src=\"formValue.%s\"\n /></n-descriptions-item>", field.Dc, field.TsName)
|
||||
|
||||
case FormModeUploadImages:
|
||||
component = fmt.Sprintf("<n-descriptions-item>\n <template #label>%s</template>\n <n-image-group>\n <n-space>\n <span v-for=\"(item, key) in formValue?.%s\" :key=\"key\">\n <n-image style=\"margin-left: 10px; height: 100px; width: 100px\" :src=\"item\" />\n </span>\n </n-space>\n </n-image-group>\n </n-descriptions-item>", field.Dc, field.TsName)
|
||||
|
||||
case FormModeUploadFile:
|
||||
component = fmt.Sprintf("<n-descriptions-item>\n <template #label>%s</template>\n <div\n class=\"upload-card\"\n v-show=\"formValue.%s !== ''\"\n @click=\"download(formValue.%s)\"\n >\n <div class=\"upload-card-item\" style=\"height: 100px; width: 100px\">\n <div class=\"upload-card-item-info\">\n <div class=\"img-box\">\n <n-avatar :style=\"fileAvatarCSS\">{{ getFileExt(formValue.%s) }}</n-avatar>\n </div>\n </div>\n </div>\n </div>\n </n-descriptions-item>", field.Dc, field.TsName, field.TsName, field.TsName)
|
||||
|
||||
case FormModeUploadFiles:
|
||||
component = fmt.Sprintf("<n-descriptions-item>\n <template #label>%s</template>\n <div class=\"upload-card\">\n <n-space style=\"gap: 0px 0px\">\n <div\n class=\"upload-card-item\"\n style=\"height: 100px; width: 100px\"\n v-for=\"(item, key) in formValue.%s\"\n :key=\"key\"\n >\n <div class=\"upload-card-item-info\">\n <div class=\"img-box\">\n <n-avatar :style=\"fileAvatarCSS\" @click=\"download(item)\">{{\n getFileExt(item)\n }}</n-avatar>\n </div>\n </div>\n </div>\n </n-space>\n </div>\n </n-descriptions-item>", field.Dc, field.TsName)
|
||||
|
||||
case FormModeSwitch:
|
||||
component = fmt.Sprintf("<n-descriptions-item label=\"%s\">\n <n-switch v-model:value=\"formValue.%s\" :unchecked-value=\"2\" :checked-value=\"1\" :disabled=\"true\"\n /></n-descriptions-item>", field.Dc, field.TsName)
|
||||
|
||||
case FormModeRate:
|
||||
component = fmt.Sprintf("<n-descriptions-item label=\"%s\"\n ><n-rate readonly :default-value=\"formValue.%s\"\n /></n-descriptions-item>", field.Dc, field.TsName)
|
||||
|
||||
default:
|
||||
component = defaultComponent
|
||||
}
|
||||
|
||||
buffer.WriteString(" " + component + "\n\n")
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
96
server/internal/library/hggen/views/utils.go
Normal file
96
server/internal/library/hggen/views/utils.go
Normal file
@@ -0,0 +1,96 @@
|
||||
// Package hggen
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2022 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/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// parseServFunName 解析业务服务名称
|
||||
func (l *gCurd) parseServFunName(templateGroup, varName string) string {
|
||||
templateGroup = gstr.UcFirst(templateGroup)
|
||||
if gstr.HasPrefix(varName, templateGroup) && varName != templateGroup {
|
||||
return varName
|
||||
}
|
||||
|
||||
return templateGroup + varName
|
||||
}
|
||||
|
||||
// getPkField 获取主键
|
||||
func (l *gCurd) getPkField(in *CurdPreviewInput) *sysin.GenCodesColumnListModel {
|
||||
if len(in.masterFields) == 0 {
|
||||
panic("getPkField masterFields uninitialized.")
|
||||
}
|
||||
for _, field := range in.masterFields {
|
||||
if field.Index == consts.GenCodesIndexPK {
|
||||
return field
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// hasEffectiveJoin 存在有效的关联表
|
||||
func hasEffectiveJoins(joins []*CurdOptionsJoin) bool {
|
||||
for _, join := range joins {
|
||||
if isEffectiveJoin(join) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isEffectiveJoin(join *CurdOptionsJoin) bool {
|
||||
return join.Alias != "" && join.Field != "" && join.LinkTable != "" && join.MasterField != "" && join.DaoName != "" && join.LinkMode > 0
|
||||
}
|
||||
|
||||
// formatComment formats the comment string to fit the golang code without any lines.
|
||||
func formatComment(comment string) string {
|
||||
comment = gstr.ReplaceByArray(comment, g.SliceStr{
|
||||
"\n", " ",
|
||||
"\r", " ",
|
||||
})
|
||||
comment = gstr.Replace(comment, `\n`, " ")
|
||||
comment = gstr.Trim(comment)
|
||||
return comment
|
||||
}
|
||||
|
||||
// 移除末尾的换行符
|
||||
func removeEndWrap(comment string) string {
|
||||
if len(comment) > 2 && comment[len(comment)-2:] == " \n" {
|
||||
comment = comment[:len(comment)-2]
|
||||
}
|
||||
return comment
|
||||
}
|
||||
|
||||
// ImportSql 导出sql文件
|
||||
func ImportSql(ctx context.Context, path string) error {
|
||||
rows, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sqlArr := strings.Split(string(rows), "\n")
|
||||
for _, sql := range sqlArr {
|
||||
sql = strings.TrimSpace(sql)
|
||||
if sql == "" || strings.HasPrefix(sql, "--") {
|
||||
continue
|
||||
}
|
||||
exec, err := g.DB().Exec(ctx, sql)
|
||||
g.Log().Infof(ctx, "views.ImportSql sql:%v, exec:%+v, err:%+v", sql, exec, err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user