diff --git a/app/controller/admin/gen_table.go b/app/controller/admin/gen_table.go index 519f636..5ea5250 100644 --- a/app/controller/admin/gen_table.go +++ b/app/controller/admin/gen_table.go @@ -5,6 +5,8 @@ import ( "gfast/app/service/admin/gen_service" "gfast/app/service/admin/user_service" "gfast/library/response" + "strings" + "github.com/gogf/gf/encoding/gcompress" "github.com/gogf/gf/encoding/gjson" "github.com/gogf/gf/errors/gerror" @@ -17,7 +19,6 @@ import ( "github.com/gogf/gf/util/gconv" "github.com/gogf/gf/util/grand" "github.com/gogf/gf/util/gvalid" - "strings" ) type Gen struct{} @@ -222,10 +223,25 @@ func (c *Gen) BatchGenCode(r *ghttp.Request) { response.FailJson(true, r, err.Error()) } case "vm/go/" + entity.BusinessName + "_model.go.vm": + err = gfile.PutContents(dataFilePath+"/gen/"+dataFileRange+"/go/"+pathMap["gfgenModel"], val) + if err != nil { + response.FailJson(true, r, err.Error()) + } + case "vm/go/" + entity.BusinessName + "_entity.go.vm": + err = gfile.PutContents(dataFilePath+"/gen/"+dataFileRange+"/go/"+pathMap["gfgenEntity"], val) + if err != nil { + response.FailJson(true, r, err.Error()) + } + case "vm/go/" + entity.BusinessName + ".go.vm": err = gfile.PutContents(dataFilePath+"/gen/"+dataFileRange+"/go/"+pathMap["model"], val) if err != nil { response.FailJson(true, r, err.Error()) } + case "vm/go/" + entity.BusinessName + "_route.go.vm": + err = gfile.PutContents(dataFilePath+"/gen/"+dataFileRange+"/go/路由说明.txt", val) + if err != nil { + response.FailJson(true, r, err.Error()) + } case "vm/html/" + entity.BusinessName + "_api.js.vm": err = gfile.PutContents(dataFilePath+"/gen/"+dataFileRange+"/vue/"+pathMap["api"], val) if err != nil { @@ -259,14 +275,18 @@ func (c *Gen) getPath(entity *gen_table.EntityExtend) g.MapStrStr { controller := "app/controller/" + entity.ModuleName + "/" + entity.ClassName + ".go" service := "app/service/" + entity.ModuleName + "/" + entity.BusinessName + "_service/" + entity.ClassName + ".go" model := "app/model/" + entity.ModuleName + "/" + entity.BusinessName + "/" + entity.ClassName + ".go" + gfgenModel := "app/model/" + entity.ModuleName + "/" + entity.BusinessName + "/" + entity.ClassName + "_model.go" + gfgenEntity := "app/model/" + entity.ModuleName + "/" + entity.BusinessName + "/" + entity.ClassName + "_entity.go" vue := "views/" + entity.ModuleName + "/" + entity.BusinessName + "/index.vue" api := "api/" + entity.ModuleName + "/" + entity.BusinessName + ".js" return g.MapStrStr{ - "controller": controller, - "service": service, - "model": model, - "vue": vue, - "api": api, + "controller": controller, + "service": service, + "model": model, + "gfgenModel": gfgenModel, + "gfgenEntity": gfgenEntity, + "vue": vue, + "api": api, } } @@ -285,8 +305,14 @@ func (c *Gen) genData(tableId int64) (data g.MapStrStr, entity *gen_table.Entity controllerValue := "" serviceKey := "vm/go/" + entity.BusinessName + "_service.go.vm" serviceValue := "" - modelKey := "vm/go/" + entity.BusinessName + "_model.go.vm" + modelKey := "vm/go/" + entity.BusinessName + ".go.vm" modelValue := "" + routeKey := "vm/go/" + entity.BusinessName + "_route.go.vm" + routeValue := "" + gfgenModelKey := "vm/go/" + entity.BusinessName + "_model.go.vm" + gfgenModelValue := "" + gfgenEntityKey := "vm/go/" + entity.BusinessName + "_entity.go.vm" + gfgenEntityValue := "" apiJsKey := "vm/html/" + entity.BusinessName + "_api.js.vm" apiJsValue := "" vueKey := "vm/html/" + entity.BusinessName + "_vue.js.vm" @@ -343,12 +369,34 @@ func (c *Gen) genData(tableId int64) (data g.MapStrStr, entity *gen_table.Entity return } + var tmpRouter string + if tmpRouter, err = view.Parse("vm/go/common/route.template", g.Map{"table": entity}); err == nil { + routeValue = tmpRouter + } else { + return + } + var tmpGfModel string + if tmpGfModel, err = view.Parse("vm/go/common/model.template", g.Map{"table": entity}); err == nil { + gfgenModelValue = tmpGfModel + } else { + return + } + var tmpGfEntity string + if tmpGfEntity, err = view.Parse("vm/go/common/entity.template", g.Map{"table": entity}); err == nil { + gfgenEntityValue = tmpGfEntity + } else { + return + } + data = g.MapStrStr{ - modelKey: modelValue, - serviceKey: serviceValue, - controllerKey: controllerValue, - apiJsKey: apiJsValue, - vueKey: vueValue, + routeKey: routeValue, + gfgenModelKey: gfgenModelValue, + gfgenEntityKey: gfgenEntityValue, + modelKey: modelValue, + serviceKey: serviceValue, + controllerKey: controllerValue, + apiJsKey: apiJsValue, + vueKey: vueValue, } return } diff --git a/template/vm/go/common/entity.template b/template/vm/go/common/entity.template new file mode 100644 index 0000000..0419525 --- /dev/null +++ b/template/vm/go/common/entity.template @@ -0,0 +1,76 @@ +// ========================================================================== +// 生成日期:${.table.CreateTime} +// 生成人:${.table.FunctionAuthor} +// ========================================================================== + +package ${.table.BusinessName} + +import ( + "database/sql" + + "github.com/gogf/gf/database/gdb" + "github.com/gogf/gf/os/gtime" +) + +// Entity is the golang structure for table ${.table.TableName}. +type Entity struct { + ${range $index, $column := .table.Columns} + ${$column.GoField} ${if eq $column.GoType "Time"}*gtime.Time${else}${$column.GoType}${end} `orm:"${$column.ColumnName}${if eq $column.IsPk "1"},primary${end}" json:"${$column.ColumnName}"` // ${$column.ColumnComment} ${end} +} + +// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers +// the data and where attributes for empty values. +// Deprecated. +func (r *Entity) OmitEmpty() *arModel { + return Model.Data(r).OmitEmpty() +} + +// Inserts does "INSERT...INTO..." statement for inserting current object into table. +// Deprecated. +func (r *Entity) Insert() (result sql.Result, err error) { + return Model.Data(r).Insert() +} + +// InsertIgnore does "INSERT IGNORE INTO ..." statement for inserting current object into table. +// Deprecated. +func (r *Entity) InsertIgnore() (result sql.Result, err error) { + return Model.Data(r).InsertIgnore() +} + +// Replace does "REPLACE...INTO..." statement for inserting current object into table. +// If there's already another same record in the table (it checks using primary key or unique index), +// it deletes it and insert this one. +// Deprecated. +func (r *Entity) Replace() (result sql.Result, err error) { + return Model.Data(r).Replace() +} + +// Save does "INSERT...INTO..." statement for inserting/updating current object into table. +// It updates the record if there's already another same record in the table +// (it checks using primary key or unique index). +// Deprecated. +func (r *Entity) Save() (result sql.Result, err error) { + return Model.Data(r).Save() +} + +// Update does "UPDATE...WHERE..." statement for updating current object from table. +// It updates the record if there's already another same record in the table +// (it checks using primary key or unique index). +// Deprecated. +func (r *Entity) Update() (result sql.Result, err error) { + where, args, err := gdb.GetWhereConditionOfStruct(r) + if err != nil { + return nil, err + } + return Model.Data(r).Where(where, args).Update() +} + +// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table. +// Deprecated. +func (r *Entity) Delete() (result sql.Result, err error) { + where, args, err := gdb.GetWhereConditionOfStruct(r) + if err != nil { + return nil, err + } + return Model.Where(where, args).Delete() +} diff --git a/template/vm/go/common/model.template b/template/vm/go/common/model.template new file mode 100644 index 0000000..b171a39 --- /dev/null +++ b/template/vm/go/common/model.template @@ -0,0 +1,304 @@ +// ========================================================================== +// 生成日期:${.table.CreateTime} +// 生成人:${.table.FunctionAuthor} +// ========================================================================== + +package ${.table.BusinessName} + +import ( + "context" + "database/sql" + "github.com/gogf/gf/database/gdb" + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/frame/gmvc" + "time" +) + +// arModel is a active record design model for table ${.table.TableName} operations. +type arModel struct { + gmvc.M +} + +var ( + // Table is the table name of ${.table.TableName}. + Table = "${.table.TableName}" + // Model is the model object of ${.table.TableName}. + Model = &arModel{g.DB("default").Model(Table).Safe()} + // Columns defines and stores column names for table ${.table.TableName}. + Columns = struct { + ${range $index, $column := .table.Columns} + ${$column.GoField} string // ${$column.ColumnComment} ${end} + }{ + ${range $index, $column := .table.Columns} + ${$column.GoField}: "${$column.ColumnName}", ${end} + } +) + +// Ctx is a chaining function, which creates and returns a new DB that is a shallow copy +// of current DB object and with given context in it. +// Note that this returned DB object can be used only once, so do not assign it to +// a global or package variable for long using. +func (m *arModel) Ctx(ctx context.Context) *arModel { + return &arModel{m.M.Ctx(ctx)} +} + +// As sets an alias name for current table. +func (m *arModel) As(as string) *arModel { + return &arModel{m.M.As(as)} +} + +// TX sets the transaction for current operation. +func (m *arModel) TX(tx *gdb.TX) *arModel { + return &arModel{m.M.TX(tx)} +} + +// Master marks the following operation on master node. +func (m *arModel) Master() *arModel { + return &arModel{m.M.Master()} +} + +// Slave marks the following operation on slave node. +// Note that it makes sense only if there's any slave node configured. +func (m *arModel) Slave() *arModel { + return &arModel{m.M.Slave()} +} + +// LeftJoin does "LEFT JOIN ... ON ..." statement on the model. +// The parameter can be joined table and its joined condition, +// and also with its alias name, like: +// Table("user").LeftJoin("user_detail", "user_detail.uid=user.uid") +// Table("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid") +func (m *arModel) LeftJoin(table ...string) *arModel { + return &arModel{m.M.LeftJoin(table ...)} +} + +// RightJoin does "RIGHT JOIN ... ON ..." statement on the model. +// The parameter
can be joined table and its joined condition, +// and also with its alias name, like: +// Table("user").RightJoin("user_detail", "user_detail.uid=user.uid") +// Table("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid") +func (m *arModel) RightJoin(table ...string) *arModel { + return &arModel{m.M.RightJoin(table ...)} +} + +// InnerJoin does "INNER JOIN ... ON ..." statement on the model. +// The parameter
can be joined table and its joined condition, +// and also with its alias name, like: +// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid") +// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid") +func (m *arModel) InnerJoin(table ...string) *arModel { + return &arModel{m.M.InnerJoin(table ...)} +} + +// Fields sets the operation fields of the model, multiple fields joined using char ','. +func (m *arModel) Fields(fieldNamesOrMapStruct ...interface{}) *arModel { + return &arModel{m.M.Fields(fieldNamesOrMapStruct...)} +} + +// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','. +func (m *arModel) FieldsEx(fieldNamesOrMapStruct ...interface{}) *arModel { + return &arModel{m.M.FieldsEx(fieldNamesOrMapStruct...)} +} + +// Option sets the extra operation option for the model. +func (m *arModel) Option(option int) *arModel { + return &arModel{m.M.Option(option)} +} + +// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers +// the data and where attributes for empty values. +func (m *arModel) OmitEmpty() *arModel { + return &arModel{m.M.OmitEmpty()} +} + +// Filter marks filtering the fields which does not exist in the fields of the operated table. +func (m *arModel) Filter() *arModel { + return &arModel{m.M.Filter()} +} + +// Where sets the condition statement for the model. The parameter can be type of +// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times, +// multiple conditions will be joined into where statement using "AND". +// Eg: +// Where("uid=10000") +// Where("uid", 10000) +// Where("money>? AND name like ?", 99999, "vip_%") +// Where("uid", 1).Where("name", "john") +// Where("status IN (?)", g.Slice{1,2,3}) +// Where("age IN(?,?)", 18, 50) +// Where(User{ Id : 1, UserName : "john"}) +func (m *arModel) Where(where interface{}, args ...interface{}) *arModel { + return &arModel{m.M.Where(where, args...)} +} + +// WherePri does the same logic as Model.Where except that if the parameter +// is a single condition like int/string/float/slice, it treats the condition as the primary +// key value. That is, if primary key is "id" and given parameter as "123", the +// WherePri function treats the condition as "id=123", but Model.Where treats the condition +// as string "123". +func (m *arModel) WherePri(where interface{}, args ...interface{}) *arModel { + return &arModel{m.M.WherePri(where, args...)} +} + +// And adds "AND" condition to the where statement. +func (m *arModel) And(where interface{}, args ...interface{}) *arModel { + return &arModel{m.M.And(where, args...)} +} + +// Or adds "OR" condition to the where statement. +func (m *arModel) Or(where interface{}, args ...interface{}) *arModel { + return &arModel{m.M.Or(where, args...)} +} + +// Group sets the "GROUP BY" statement for the model. +func (m *arModel) Group(groupBy string) *arModel { + return &arModel{m.M.Group(groupBy)} +} + +// Order sets the "ORDER BY" statement for the model. +func (m *arModel) Order(orderBy ...string) *arModel { + return &arModel{m.M.Order(orderBy...)} +} + +// Limit sets the "LIMIT" statement for the model. +// The parameter can be either one or two number, if passed two number is passed, +// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]" +// statement. +func (m *arModel) Limit(limit ...int) *arModel { + return &arModel{m.M.Limit(limit...)} +} + +// Offset sets the "OFFSET" statement for the model. +// It only makes sense for some databases like SQLServer, PostgreSQL, etc. +func (m *arModel) Offset(offset int) *arModel { + return &arModel{m.M.Offset(offset)} +} + +// Page sets the paging number for the model. +// The parameter is started from 1 for paging. +// Note that, it differs that the Limit function start from 0 for "LIMIT" statement. +func (m *arModel) Page(page, limit int) *arModel { + return &arModel{m.M.Page(page, limit)} +} + +// Batch sets the batch operation number for the model. +func (m *arModel) Batch(batch int) *arModel { + return &arModel{m.M.Batch(batch)} +} + +// Cache sets the cache feature for the model. It caches the result of the sql, which means +// if there's another same sql request, it just reads and returns the result from cache, it +// but not committed and executed into the database. +// +// If the parameter < 0, which means it clear the cache with given . +// If the parameter = 0, which means it never expires. +// If the parameter > 0, which means it expires after . +// +// The optional parameter is used to bind a name to the cache, which means you can later +// control the cache like changing the or clearing the cache with specified . +// +// Note that, the cache feature is disabled if the model is operating on a transaction. +func (m *arModel) Cache(duration time.Duration, name ...string) *arModel { + return &arModel{m.M.Cache(duration, name...)} +} + +// Data sets the operation data for the model. +// The parameter can be type of string/map/gmap/slice/struct/*struct, etc. +// Eg: +// Data("uid=10000") +// Data("uid", 10000) +// Data(g.Map{"uid": 10000, "name":"john"}) +// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"}) +func (m *arModel) Data(data ...interface{}) *arModel { + return &arModel{m.M.Data(data...)} +} + +// All does "SELECT FROM ..." statement for the model. +// It retrieves the records from table and returns the result as []*Entity. +// It returns nil if there's no record retrieved with the given conditions from table. +// +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) All(where ...interface{}) ([]*Entity, error) { + all, err := m.M.All(where...) + if err != nil { + return nil, err + } + var entities []*Entity + if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows { + return nil, err + } + return entities, nil +} + +// One retrieves one record from table and returns the result as *Entity. +// It returns nil if there's no record retrieved with the given conditions from table. +// +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) One(where ...interface{}) (*Entity, error) { + one, err := m.M.One(where...) + if err != nil { + return nil, err + } + var entity *Entity + if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows { + return nil, err + } + return entity, nil +} + +// FindOne retrieves and returns a single Record by Model.WherePri and Model.One. +// Also see Model.WherePri and Model.One. +func (m *arModel) FindOne(where ...interface{}) (*Entity, error) { + one, err := m.M.FindOne(where...) + if err != nil { + return nil, err + } + var entity *Entity + if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows { + return nil, err + } + return entity, nil +} + +// FindAll retrieves and returns Result by by Model.WherePri and Model.All. +// Also see Model.WherePri and Model.All. +func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) { + all, err := m.M.FindAll(where...) + if err != nil { + return nil, err + } + var entities []*Entity + if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows { + return nil, err + } + return entities, nil +} + +// Chunk iterates the table with given size and callback function. +func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) { + m.M.Chunk(limit, func(result gdb.Result, err error) bool { + var entities []*Entity + err = result.Structs(&entities) + if err == sql.ErrNoRows { + return false + } + return callback(entities, err) + }) +} + +// LockUpdate sets the lock for update for current operation. +func (m *arModel) LockUpdate() *arModel { + return &arModel{m.M.LockUpdate()} +} + +// LockShared sets the lock in share mode for current operation. +func (m *arModel) LockShared() *arModel { + return &arModel{m.M.LockShared()} +} + +// Unscoped enables/disables the soft deleting feature. +func (m *arModel) Unscoped() *arModel { + return &arModel{m.M.Unscoped()} +} \ No newline at end of file diff --git a/template/vm/go/common/route.template b/template/vm/go/common/route.template new file mode 100644 index 0000000..200c425 --- /dev/null +++ b/template/vm/go/common/route.template @@ -0,0 +1,19 @@ +// ========================================================================== +// 生成日期:${.table.CreateTime} +// 生成人:${.table.FunctionAuthor} +// ========================================================================== + + +// 请手工复制以下内容,到 /route/routerAdmin.go 文件的合适位置 + + +import "${.table.PackageName}/app/controller/${.table.ModuleName}" + + +group.Group("/${.table.ModuleName}", func(group *ghttp.RouterGroup) { + //${.table.FunctionName} + group.ALL("/${.table.BusinessName}", new(${.table.ModuleName}.${.table.BusinessName|UcFirst})) +}) + + + diff --git a/template/vm/go/crud/model.template b/template/vm/go/crud/model.template index 6194ee9..969c4d5 100644 --- a/template/vm/go/crud/model.template +++ b/template/vm/go/crud/model.template @@ -21,13 +21,13 @@ ${end}${end} // AddReq 用于存储新增请求的请求参数 type AddReq struct { ${range $index, $column := .table.Columns} - ${if and (eq $column.IsInsert "1") (ne $column.IsPk "1")} ${$column.GoField} ${if eq $column.GoType "Time"}*gtime.Time${else}${$column.GoType}${end} `p:"${$column.HtmlField}" ${if eq $column.IsRequired "1"}v:"required#${$column.ColumnComment}不能为空"${end}` ${end} ${end} + ${if and (eq $column.IsInsert "1") (ne $column.IsPk "1")} ${$column.GoField} ${if eq $column.GoType "Time"}*gtime.Time${else}${$column.GoType}${end} `p:"${$column.ColumnName}" ${if eq $column.IsRequired "1"}v:"required#${$column.ColumnComment}不能为空"${end}` ${end} ${end} } // EditReq 用于存储修改请求参数 type EditReq struct { - ${.table.PkColumn.GoField} ${.table.PkColumn.GoType} `p:"${.table.PkColumn.HtmlField}" v:"required#主键ID不能为空"` ${range $index, $column := .table.Columns} ${if eq $column.IsEdit "1"} - ${$column.GoField} ${if eq $column.GoType "Time"}*gtime.Time${else}${$column.GoType}${end} `p:"${$column.HtmlField}" ${if eq $column.IsRequired "1"}v:"required#${$column.ColumnComment}不能为空"${end}` ${end} ${end} + ${.table.PkColumn.GoField} ${.table.PkColumn.GoType} `p:"${.table.PkColumn.ColumnName}" v:"required#主键ID不能为空"` ${range $index, $column := .table.Columns} ${if eq $column.IsEdit "1"} + ${$column.GoField} ${if eq $column.GoType "Time"}*gtime.Time${else}${$column.GoType}${end} `p:"${$column.ColumnName}" ${if eq $column.IsRequired "1"}v:"required#${$column.ColumnComment}不能为空"${end}` ${end} ${end} } // RemoveReq 用于存储删除请求参数 @@ -37,7 +37,7 @@ type RemoveReq struct { // SelectPageReq 用于存储分页查询的请求参数 type SelectPageReq struct { ${range $index, $column := .table.Columns} ${if eq $column.IsQuery "1"} - ${$column.GoField} ${if eq $column.GoType "Time"}*gtime.Time${else}${$column.GoType}${end} `p:"${$column.HtmlField}"` //${$column.ColumnComment} ${end} ${end} + ${$column.GoField} ${if eq $column.GoType "Time"}*gtime.Time${else}${$column.GoType}${end} `p:"${$column.ColumnName}"` //${$column.ColumnComment} ${end} ${end} BeginTime string `p:"beginTime"` //开始时间 EndTime string `p:"endTime"` //结束时间 PageNum int `p:"pageNum"` //当前页码 diff --git a/template/vm/html/vue_crud.template b/template/vm/html/vue_crud.template index 14e0e44..8224055 100644 --- a/template/vm/html/vue_crud.template +++ b/template/vm/html/vue_crud.template @@ -27,7 +27,7 @@ ${else if and (or (eq $column.HtmlType "select" ) (eq $column.HtmlType "radio ${else if and (eq $column.IsList "1") (ne $column.DictType "")} - + ${else if and (eq $column.IsList "1") (ne $ColumnName "")} ${end} @@ -150,7 +150,7 @@ ${end} ${"${"}dict.value${"}"} @@ -184,7 +184,7 @@ ${end} ${"${"}dict.value${"}"} @@ -250,11 +250,11 @@ export default { ${range $index,$column := $columns} ${$comment :=$column.ColumnComment} ${if ne $column.DictType ""} - // $comment字典 - ${$column.ColumnName}Options: [], + // ${$column.ColumnName}字典 + ${$column.HtmlField}Options: [], ${end} ${end} - // 查询参数 + // 查询参数 queryParams: { pageNum: 1, pageSize: 10, @@ -286,7 +286,7 @@ export default { ${range $index,$column := $columns} ${if ne $column.DictType ""} this.getDicts("${$column.DictType}").then(response => { - this.${$column.ColumnName}Options = response.data.values || []; + this.${$column.HtmlField}Options = response.data.values || []; }); ${end} ${end} @@ -306,8 +306,8 @@ export default { ${if ne $column.DictType ""} ${$comment:=$column.ColumnComment} // $comment字典翻译 - ${$column.ColumnName}Format(row, column) { - return this.selectDictLabel${if eq $column.HtmlType "checkbox"}s${end}(this.${$column.ColumnName}Options, row.${$column.ColumnName}); + ${$column.HtmlField}Format(row, column) { + return this.selectDictLabel${if eq $column.HtmlType "checkbox"}s${end}(this.${$column.HtmlField}Options, row.${$column.ColumnName}); }, ${end} ${end}