Jelajahi Sumber

代码生成

yxh 4 tahun lalu
induk
melakukan
ba8ea9c8cf

+ 198 - 0
app/system/api/tools_gen_table.go

@@ -0,0 +1,198 @@
+/*
+* @desc:代码生成
+* @company:云南省奇讯科技有限公司
+* @Author: yixiaohu
+* @Date:   2021/7/22 15:11
+ */
+
+package api
+
+import (
+	comModel "gfast/app/common/model"
+	"gfast/app/system/dao"
+	"gfast/app/system/model"
+	"gfast/app/system/service"
+	"github.com/gogf/gf/encoding/gjson"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/net/ghttp"
+	"github.com/gogf/gf/util/gconv"
+	"github.com/gogf/gf/util/gvalid"
+	"strings"
+)
+
+type toolsGenTable struct {
+	systemBase
+}
+
+var ToolsGenTable = new(toolsGenTable)
+
+// TableList 代码生成页列表数据
+func (c *toolsGenTable) TableList(r *ghttp.Request) {
+	var req *dao.ToolsGenTableSearchReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		c.FailJsonExit(r, err.(gvalid.Error).FirstString())
+	}
+	total, list, err := service.ToolsGenTable.SelectListByPage(req)
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	c.SusJsonExit(r, g.Map{
+		"total": total,
+		"list":  list,
+	})
+}
+
+// DataList 导入表格页列表数据
+func (c *toolsGenTable) DataList(r *ghttp.Request) {
+	var req *dao.ToolsGenTableSearchReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		c.FailJsonExit(r, err.(gvalid.Error).FirstString())
+	}
+
+	total, list, err := service.ToolsGenTable.SelectDbTableList(req)
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	c.SusJsonExit(r, g.Map{
+		"total": total,
+		"list":  list,
+	})
+}
+
+// ImportTableSave 导入表结构操作
+func (c *toolsGenTable) ImportTableSave(r *ghttp.Request) {
+	tables := r.GetString("tables")
+	if tables == "" {
+		c.FailJsonExit(r, "请选择要导入的表格")
+	}
+	tableArr := strings.Split(tables, ",")
+	tableList, err := service.ToolsGenTable.SelectDbTableListByNames(tableArr)
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	if tableList == nil {
+		c.FailJsonExit(r, "表信息不存在")
+	}
+	err = service.ToolsGenTable.ImportGenTable(tableList)
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	c.SusJsonExit(r, "导入数据表成功")
+}
+
+// ColumnList 表格字段列表数据
+func (c *toolsGenTable) ColumnList(r *ghttp.Request) {
+	tableId := r.GetInt64("tableId")
+	if tableId == 0 {
+		c.FailJsonExit(r, "参数错误")
+	}
+	list, err := service.ToolsGenTableColumn.SelectGenTableColumnListByTableId(tableId)
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	var tableInfo *model.ToolsGenTable
+	var tableMap g.Map
+	tableInfo, err = service.ToolsGenTable.GetTableInfoByTableId(tableId)
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	tableMap = gconv.Map(tableInfo)
+	//如果是树表则设置树表配置
+	if tableInfo != nil && tableInfo.TplCategory == "tree" {
+		options := gjson.New(tableInfo.Options)
+		tableMap["treeCode"] = options.Get("treeCode")
+		tableMap["treeParentCode"] = options.Get("treeParentCode")
+		tableMap["treeName"] = options.Get("treeName")
+	}
+	res := g.Map{
+		"rows": list,
+		"info": tableMap,
+	}
+	c.SusJsonExit(r, res)
+}
+
+// RelationTable 获取可选的关联表
+func (c *toolsGenTable) RelationTable(r *ghttp.Request) {
+	//获取表数据列表
+	_, tableList, err := service.ToolsGenTable.SelectListByPage(&dao.ToolsGenTableSearchReq{
+		PageReq: comModel.PageReq{
+			PageSize: 1000,
+		},
+	})
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	//获取所有字段
+	allColumns, err := service.ToolsGenTableColumn.GetAllTableColumns()
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	tableColumns := make([]*dao.ToolsGenTableColumnsRes, len(tableList))
+	for k, v := range tableList {
+		tableColumns[k] = &dao.ToolsGenTableColumnsRes{
+			ToolsGenTable: v,
+			Columns:       make([]*model.ToolsGenTableColumn, 0),
+		}
+		for _, cv := range allColumns {
+			if cv.TableId == v.TableId {
+				tableColumns[k].Columns = append(tableColumns[k].Columns, cv)
+			}
+		}
+	}
+	c.SusJsonExit(r, tableColumns)
+}
+
+// EditSave 编辑表格生成信息
+func (c *toolsGenTable) EditSave(r *ghttp.Request) {
+	var req *dao.ToolsGenTableEditReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		c.FailJsonExit(r, err.(gvalid.Error).FirstString())
+	}
+	err := service.ToolsGenTable.SaveEdit(req)
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	c.SusJsonExit(r, "设置成功")
+}
+
+// Preview 代码预览
+func (c *toolsGenTable) Preview(r *ghttp.Request) {
+	tableId := r.GetInt64("tableId")
+	if tableId == 0 {
+		c.FailJsonExit(r, "参数错误")
+	}
+	data, _, err := service.ToolsGenTable.GenData(tableId, r.GetCtx())
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	c.SusJsonExit(r, data)
+}
+
+// BatchGenCode 代码生成
+func (c *toolsGenTable) BatchGenCode(r *ghttp.Request) {
+	ids := r.GetInts("ids")
+	if len(ids) == 0 {
+		c.FailJsonExit(r, "参数错误")
+	}
+	err := service.ToolsGenTable.GenCode(ids, r.GetCtx())
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	c.SusJsonExit(r, "生成成功")
+}
+
+// Delete 删除导入的表信息
+func (c *toolsGenTable) Delete(r *ghttp.Request) {
+	ids := r.GetInts("ids")
+	if len(ids) == 0 {
+		c.FailJsonExit(r, "参数错误")
+	}
+	err := service.ToolsGenTable.Delete(ids)
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	c.SusJsonExit(r, "删除成功")
+}

+ 64 - 0
app/system/dao/internal/tools_gen_table.go

@@ -0,0 +1,64 @@
+// ==========================================================================
+// Code generated by GoFrame CLI tool. DO NOT EDIT.
+// ==========================================================================
+
+package internal
+
+import (
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+)
+
+// ToolsGenTableDao is the manager for logic model data accessing and custom defined data operations functions management.
+type ToolsGenTableDao struct {
+	gmvc.M                      // M is the core and embedded struct that inherits all chaining operations from gdb.Model.
+	C      toolsGenTableColumns // C is the short type for Columns, which contains all the column names of Table for convenient usage.
+	DB     gdb.DB               // DB is the raw underlying database management object.
+	Table  string               // Table is the underlying table name of the DAO.
+}
+
+// ToolsGenTableColumns defines and stores column names for table tools_gen_table.
+type toolsGenTableColumns struct {
+	TableId        string // 编号
+	TableName      string // 表名称
+	TableComment   string // 表描述
+	ClassName      string // 实体类名称
+	TplCategory    string // 使用的模板(crud单表操作 tree树表操作)
+	PackageName    string // 生成包路径
+	ModuleName     string // 生成模块名
+	BusinessName   string // 生成业务名
+	FunctionName   string // 生成功能名
+	FunctionAuthor string // 生成功能作者
+	Options        string // 其它生成选项
+	CreateTime     string // 创建时间
+	UpdateTime     string // 更新时间
+	Remark         string // 备注
+
+}
+
+// NewToolsGenTableDao creates and returns a new DAO object for table data access.
+func NewToolsGenTableDao() *ToolsGenTableDao {
+	columns := toolsGenTableColumns{
+		TableId:        "table_id",
+		TableName:      "table_name",
+		TableComment:   "table_comment",
+		ClassName:      "class_name",
+		TplCategory:    "tpl_category",
+		PackageName:    "package_name",
+		ModuleName:     "module_name",
+		BusinessName:   "business_name",
+		FunctionName:   "function_name",
+		FunctionAuthor: "function_author",
+		Options:        "options",
+		CreateTime:     "create_time",
+		UpdateTime:     "update_time",
+		Remark:         "remark",
+	}
+	return &ToolsGenTableDao{
+		C:     columns,
+		M:     g.DB("default").Model("tools_gen_table").Safe(),
+		DB:    g.DB("default"),
+		Table: "tools_gen_table",
+	}
+}

+ 83 - 0
app/system/dao/internal/tools_gen_table_column.go

@@ -0,0 +1,83 @@
+// ==========================================================================
+// Code generated by GoFrame CLI tool. DO NOT EDIT.
+// ==========================================================================
+
+package internal
+
+import (
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+)
+
+// ToolsGenTableColumnDao is the manager for logic model data accessing and custom defined data operations functions management.
+type ToolsGenTableColumnDao struct {
+	gmvc.M                            // M is the core and embedded struct that inherits all chaining operations from gdb.Model.
+	C      toolsGenTableColumnColumns // C is the short type for Columns, which contains all the column names of Table for convenient usage.
+	DB     gdb.DB                     // DB is the raw underlying database management object.
+	Table  string                     // Table is the underlying table name of the DAO.
+}
+
+// ToolsGenTableColumnColumns defines and stores column names for table tools_gen_table_column.
+type toolsGenTableColumnColumns struct {
+	ColumnId         string // 编号
+	TableId          string // 归属表编号
+	ColumnName       string // 列名称
+	ColumnComment    string // 列描述
+	ColumnType       string // 列类型
+	GoType           string // Go类型
+	GoField          string // Go字段名
+	HtmlField        string // html字段名
+	IsPk             string // 是否主键(1是)
+	IsIncrement      string // 是否自增(1是)
+	IsRequired       string // 是否必填(1是)
+	IsInsert         string // 是否为插入字段(1是)
+	IsEdit           string // 是否编辑字段(1是)
+	IsList           string // 是否列表字段(1是)
+	IsQuery          string // 是否查询字段(1是)
+	QueryType        string // 查询方式(等于、不等于、大于、小于、范围)
+	HtmlType         string // 显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)
+	DictType         string // 字典类型
+	Sort             string // 排序
+	LinkTableName    string // 关联表名
+	LinkTableClass   string // 关联表类名
+	LinkTablePackage string // 关联表包名
+	LinkLabelId      string // 关联表键名
+	LinkLabelName    string // 关联表字段值
+}
+
+// NewToolsGenTableColumnDao creates and returns a new DAO object for table data access.
+func NewToolsGenTableColumnDao() *ToolsGenTableColumnDao {
+	columns := toolsGenTableColumnColumns{
+		ColumnId:         "column_id",
+		TableId:          "table_id",
+		ColumnName:       "column_name",
+		ColumnComment:    "column_comment",
+		ColumnType:       "column_type",
+		GoType:           "go_type",
+		GoField:          "go_field",
+		HtmlField:        "html_field",
+		IsPk:             "is_pk",
+		IsIncrement:      "is_increment",
+		IsRequired:       "is_required",
+		IsInsert:         "is_insert",
+		IsEdit:           "is_edit",
+		IsList:           "is_list",
+		IsQuery:          "is_query",
+		QueryType:        "query_type",
+		HtmlType:         "html_type",
+		DictType:         "dict_type",
+		Sort:             "sort",
+		LinkTableName:    "link_table_name",
+		LinkTableClass:   "link_table_class",
+		LinkTablePackage: "link_table_package",
+		LinkLabelId:      "link_label_id",
+		LinkLabelName:    "link_label_name",
+	}
+	return &ToolsGenTableColumnDao{
+		C:     columns,
+		M:     g.DB("default").Model("tools_gen_table_column").Safe(),
+		DB:    g.DB("default"),
+		Table: "tools_gen_table_column",
+	}
+}

+ 90 - 0
app/system/dao/tools_gen_table.go

@@ -0,0 +1,90 @@
+// =================================================================================
+// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
+// =================================================================================
+
+package dao
+
+import (
+	comModel "gfast/app/common/model"
+	"gfast/app/system/dao/internal"
+	"gfast/app/system/model"
+	"github.com/gogf/gf/os/gtime"
+)
+
+// toolsGenTableDao is the manager for logic model data accessing and custom defined data operations functions management.
+// You can define custom methods on it to extend its functionality as you wish.
+type toolsGenTableDao struct {
+	*internal.ToolsGenTableDao
+}
+
+var (
+	// ToolsGenTable is globally public accessible object for table tools_gen_table operations.
+	ToolsGenTable toolsGenTableDao
+)
+
+func init() {
+	ToolsGenTable = toolsGenTableDao{
+		internal.NewToolsGenTableDao(),
+	}
+}
+
+// Fill with you ideas below.
+
+// ToolsGenTableSearchReq 分页请求参数
+type ToolsGenTableSearchReq struct {
+	TableName    string `p:"tableName"`    //表名称
+	TableComment string `p:"tableComment"` //表描述
+	comModel.PageReq
+}
+
+// ToolsGenTableColumnsRes 表与字段组合数据
+type ToolsGenTableColumnsRes struct {
+	*model.ToolsGenTable
+	Columns []*model.ToolsGenTableColumn `json:"columns"`
+}
+
+// ToolsGenTableEditReq 生成信息修改参数
+type ToolsGenTableEditReq struct {
+	TableId        int64                        `p:"tableId" v:"required#主键ID不能为空"`
+	TableName      string                       `p:"tableName"  v:"required#表名称不能为空"`
+	TableComment   string                       `p:"tableComment"  v:"required#表描述不能为空"`
+	ClassName      string                       `p:"className" v:"required#实体类名称不能为空"`
+	FunctionAuthor string                       `p:"functionAuthor"  v:"required#作者不能为空"`
+	TplCategory    string                       `p:"tplCategory"`
+	PackageName    string                       `p:"packageName" v:"required#生成包路径不能为空"`
+	ModuleName     string                       `p:"moduleName" v:"required#生成模块名不能为空"`
+	BusinessName   string                       `p:"businessName" v:"required#生成业务名不能为空"`
+	FunctionName   string                       `p:"functionName" v:"required#生成功能名不能为空"`
+	Remark         string                       `p:"remark"`
+	Params         string                       `p:"params"`
+	Columns        []*model.ToolsGenTableColumn `p:"columns"`
+	TreeCode       string                       `p:"tree_code"`
+	TreeParentCode string                       `p:"tree_parent_code"`
+	TreeName       string                       `p:"tree_name"`
+	UserName       string
+}
+
+// ToolsGenTableExtend 实体扩展
+type ToolsGenTableExtend struct {
+	TableId        int64                        `orm:"table_id,primary" json:"table_id"`        // 编号
+	TableName      string                       `orm:"table_name"       json:"table_name"`      // 表名称
+	TableComment   string                       `orm:"table_comment"    json:"table_comment"`   // 表描述
+	ClassName      string                       `orm:"class_name"       json:"class_name"`      // 实体类名称
+	TplCategory    string                       `orm:"tpl_category"     json:"tpl_category"`    // 使用的模板(crud单表操作 tree树表操作)
+	PackageName    string                       `orm:"package_name"     json:"package_name"`    // 生成包路径
+	ModuleName     string                       `orm:"module_name"      json:"module_name"`     // 生成模块名
+	BusinessName   string                       `orm:"business_name"    json:"business_name"`   // 生成业务名
+	FunctionName   string                       `orm:"function_name"    json:"function_name"`   // 生成功能名
+	FunctionAuthor string                       `orm:"function_author"  json:"function_author"` // 生成功能作者
+	Options        string                       `orm:"options"          json:"options"`         // 其它生成选项
+	CreateBy       string                       `orm:"create_by"        json:"create_by"`       // 创建者
+	CreateTime     *gtime.Time                  `orm:"create_time"      json:"create_time"`     // 创建时间
+	UpdateBy       string                       `orm:"update_by"        json:"update_by"`       // 更新者
+	UpdateTime     *gtime.Time                  `orm:"update_time"      json:"update_time"`     // 更新时间
+	Remark         string                       `orm:"remark"           json:"remark"`          // 备注
+	TreeCode       string                       `json:"tree_code"`                              // 树编码字段
+	TreeParentCode string                       `json:"tree_parent_code"`                       // 树父编码字段
+	TreeName       string                       `json:"tree_name"`                              // 树名称字段
+	Columns        []*model.ToolsGenTableColumn `json:"columns"`                                // 表列信息
+	PkColumn       *model.ToolsGenTableColumn   `json:"pkColumn"`                               // 主键列信息
+}

+ 28 - 0
app/system/dao/tools_gen_table_column.go

@@ -0,0 +1,28 @@
+// =================================================================================
+// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
+// =================================================================================
+
+package dao
+
+import (
+	"gfast/app/system/dao/internal"
+)
+
+// toolsGenTableColumnDao is the manager for logic model data accessing and custom defined data operations functions management.
+// You can define custom methods on it to extend its functionality as you wish.
+type toolsGenTableColumnDao struct {
+	*internal.ToolsGenTableColumnDao
+}
+
+var (
+	// ToolsGenTableColumn is globally public accessible object for table tools_gen_table_column operations.
+	ToolsGenTableColumn toolsGenTableColumnDao
+)
+
+func init() {
+	ToolsGenTableColumn = toolsGenTableColumnDao{
+		internal.NewToolsGenTableColumnDao(),
+	}
+}
+
+// Fill with you ideas below.

+ 27 - 0
app/system/model/tools_gen_table.go

@@ -0,0 +1,27 @@
+// =================================================================================
+// Code generated by GoFrame CLI tool. DO NOT EDIT.
+// =================================================================================
+
+package model
+
+import (
+	"github.com/gogf/gf/os/gtime"
+)
+
+// ToolsGenTable is the golang structure for table tools_gen_table.
+type ToolsGenTable struct {
+	TableId        int64       `orm:"table_id,primary"   json:"tableId"`        // 编号
+	TableName      string      `orm:"table_name"         json:"tableName"`      // 表名称
+	TableComment   string      `orm:"table_comment"      json:"tableComment"`   // 表描述
+	ClassName      string      `orm:"class_name"         json:"className"`      // 实体类名称
+	TplCategory    string      `orm:"tpl_category"       json:"tplCategory"`    // 使用的模板(crud单表操作 tree树表操作)
+	PackageName    string      `orm:"package_name"       json:"packageName"`    // 生成包路径
+	ModuleName     string      `orm:"module_name"        json:"moduleName"`     // 生成模块名
+	BusinessName   string      `orm:"business_name"      json:"businessName"`   // 生成业务名
+	FunctionName   string      `orm:"function_name"      json:"functionName"`   // 生成功能名
+	FunctionAuthor string      `orm:"function_author"    json:"functionAuthor"` // 生成功能作者
+	Options        string      `orm:"options"            json:"options"`        // 其它生成选项
+	CreateTime     *gtime.Time `orm:"create_time"        json:"createTime"`     // 创建时间
+	UpdateTime     *gtime.Time `orm:"update_time"        json:"updateTime"`     // 更新时间
+	Remark         string      `orm:"remark"             json:"remark"`         // 备注
+}

+ 33 - 0
app/system/model/tools_gen_table_column.go

@@ -0,0 +1,33 @@
+// =================================================================================
+// Code generated by GoFrame CLI tool. DO NOT EDIT.
+// =================================================================================
+
+package model
+
+// ToolsGenTableColumn is the golang structure for table tools_gen_table_column.
+type ToolsGenTableColumn struct {
+	ColumnId         int64  `orm:"column_id,primary" json:"columnId"`          // 编号
+	TableId          int64  `orm:"table_id"          json:"tableId"`           // 归属表编号
+	ColumnName       string `orm:"column_name"       json:"columnName"`        // 列名称
+	ColumnComment    string `orm:"column_comment"    json:"columnComment"`     // 列描述
+	ColumnType       string `orm:"column_type"       json:"columnType"`        // 列类型
+	GoType           string `orm:"go_type"           json:"goType"`            // Go类型
+	GoField          string `orm:"go_field"          json:"goField"`           // Go字段名
+	HtmlField        string `orm:"html_field"        json:"htmlField"`         // html字段名
+	IsPk             string `orm:"is_pk"             json:"isPk"`              // 是否主键(1是)
+	IsIncrement      string `orm:"is_increment"      json:"isIncrement"`       // 是否自增(1是)
+	IsRequired       string `orm:"is_required"       json:"isRequired"`        // 是否必填(1是)
+	IsInsert         string `orm:"is_insert"         json:"isInsert"`          // 是否为插入字段(1是)
+	IsEdit           string `orm:"is_edit"           json:"isEdit"`            // 是否编辑字段(1是)
+	IsList           string `orm:"is_list"           json:"isList"`            // 是否列表字段(1是)
+	IsQuery          string `orm:"is_query"          json:"isQuery"`           // 是否查询字段(1是)
+	QueryType        string `orm:"query_type"        json:"queryType"`         // 查询方式(等于、不等于、大于、小于、范围)
+	HtmlType         string `orm:"html_type"         json:"htmlType"`          // 显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)
+	DictType         string `orm:"dict_type"         json:"dictType"`          // 字典类型
+	Sort             int    `orm:"sort"              json:"sort"`              // 排序
+	LinkTableName    string `orm:"link_table_name"    json:"linkTableName"`    // 关联表名
+	LinkTableClass   string `orm:"link_table_class"   json:"linkTableClass"`   // 关联表类名
+	LinkTablePackage string `orm:"link_table_package" json:"linkTablePackage"` // 关联表包名
+	LinkLabelId      string `orm:"link_label_id"      json:"linkLabelId"`      // 关联表键名
+	LinkLabelName    string `orm:"link_label_name"    json:"linkLabelName"`    // 关联表字段值
+}

+ 15 - 0
app/system/router/router.go

@@ -148,6 +148,21 @@ func init() {
 					group.DELETE("clear", api.SysOperLog.Clear)
 				})
 			})
+			//开发工具
+			group.Group("/tools", func(group *ghttp.RouterGroup) {
+				//代码生成
+				group.Group("/gen", func(group *ghttp.RouterGroup) {
+					group.GET("tableList", api.ToolsGenTable.TableList)
+					group.GET("dataList", api.ToolsGenTable.DataList)
+					group.POST("importTableSave", api.ToolsGenTable.ImportTableSave)
+					group.DELETE("delete", api.ToolsGenTable.Delete)
+					group.GET("columnList", api.ToolsGenTable.ColumnList)
+					group.GET("relationTable", api.ToolsGenTable.RelationTable)
+					group.PUT("editSave", api.ToolsGenTable.EditSave)
+					group.GET("preview", api.ToolsGenTable.Preview)
+					group.PUT("batchGenCode", api.ToolsGenTable.BatchGenCode)
+				})
+			})
 		})
 	})
 }

+ 701 - 0
app/system/service/tools_gen_table.go

@@ -0,0 +1,701 @@
+/*
+* @desc:代码生成功能
+* @company:云南省奇讯科技有限公司
+* @Author: yixiaohu
+* @Date:   2021/7/22 15:30
+ */
+
+package service
+
+import (
+	"bufio"
+	"context"
+	"database/sql"
+	"gfast/app/common/global"
+	comModel "gfast/app/common/model"
+	comService "gfast/app/common/service"
+	"gfast/app/system/dao"
+	"gfast/app/system/model"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/encoding/gjson"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/os/gfile"
+	"github.com/gogf/gf/os/gmutex"
+	"github.com/gogf/gf/os/gtime"
+	"github.com/gogf/gf/os/gview"
+	"github.com/gogf/gf/text/gregex"
+	"github.com/gogf/gf/text/gstr"
+	"github.com/gogf/gf/util/gconv"
+	"io"
+	"os"
+	"strings"
+)
+
+type toolsGenTable struct {
+	mu *gmutex.Mutex
+}
+
+var ToolsGenTable = &toolsGenTable{
+	mu: gmutex.New(),
+}
+
+// SelectListByPage 查询已导入的数据表
+func (s *toolsGenTable) SelectListByPage(param *dao.ToolsGenTableSearchReq) (total int, list []*model.ToolsGenTable, err error) {
+	model := dao.ToolsGenTable.M
+	if param != nil {
+		if param.TableName != "" {
+			model = model.Where(dao.ToolsGenTable.C.TableName+" like ?", "%"+param.TableName+"%")
+		}
+		if param.TableComment != "" {
+			model = model.Where(dao.ToolsGenTable.C.TableComment+"like ?", "%"+param.TableComment+"%")
+		}
+		if param.BeginTime != "" {
+			model = model.Where(dao.ToolsGenTable.C.CreateTime+" >= ", param.BeginTime)
+		}
+		if param.EndTime != "" {
+			model = model.Where(dao.ToolsGenTable.C.CreateTime+" <= ", param.EndTime)
+		}
+		total, err = model.Count()
+		if err != nil {
+			g.Log().Error(err)
+			err = gerror.New("获取总行数失败")
+			return
+		}
+		if param.PageNum == 0 {
+			param.PageNum = 1
+		}
+		if param.PageSize == 0 {
+			param.PageSize = comModel.PageSize
+		}
+		err = model.Page(param.PageNum, param.PageSize).Order(dao.ToolsGenTable.C.TableId + " asc").Scan(&list)
+		if err != nil {
+			g.Log().Error(err)
+			err = gerror.New("获取数据失败")
+		}
+	}
+	return
+}
+
+// SelectDbTableList 查询据库表
+func (s *toolsGenTable) SelectDbTableList(param *dao.ToolsGenTableSearchReq) (total int, list []*model.ToolsGenTable, err error) {
+	db := g.DB()
+	if s.getDbDriver() != "mysql" {
+		err = gerror.New("代码生成暂时只支持mysql数据库")
+		return
+	}
+	sql := " from information_schema.tables where table_schema = (select database())" +
+		" and table_name NOT LIKE 'qrtz_%' AND table_name NOT LIKE 'gen_%' and table_name NOT IN (select table_name from " + dao.ToolsGenTable.Table + ") "
+	if param != nil {
+		if param.TableName != "" {
+			sql += gdb.FormatSqlWithArgs(" and lower(table_name) like lower(?)", []interface{}{"%" + param.TableName + "%"})
+		}
+
+		if param.TableComment != "" {
+			sql += gdb.FormatSqlWithArgs(" and lower(table_comment) like lower(?)", []interface{}{"%" + param.TableComment + "%"})
+		}
+
+		if param.BeginTime != "" {
+			sql += gdb.FormatSqlWithArgs(" and date_format(create_time,'%y%m%d') >= date_format(?,'%y%m%d') ", []interface{}{param.BeginTime})
+		}
+
+		if param.EndTime != "" {
+			sql += gdb.FormatSqlWithArgs(" and date_format(create_time,'%y%m%d') <= date_format(?,'%y%m%d') ", []interface{}{param.EndTime})
+		}
+	}
+	countSql := "select count(1) " + sql
+	total, err = db.GetCount(countSql)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("读取总表数失败")
+		return
+	}
+	sql = "table_name, table_comment, create_time, update_time " + sql
+
+	if param.PageNum == 0 {
+		param.PageNum = 1
+	}
+
+	if param.PageSize == 0 {
+		param.PageSize = comModel.PageSize
+	}
+	page := (param.PageNum - 1) * param.PageSize
+	sql += " order by create_time desc,table_name asc limit  " + gconv.String(page) + "," + gconv.String(param.PageSize)
+	err = db.GetScan(&list, "select "+sql)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("读取数据失败")
+	}
+	return
+}
+
+//获取数据库驱动类型
+func (s *toolsGenTable) getDbDriver() string {
+	config := g.DB().GetConfig()
+	return gstr.ToLower(config.Type)
+}
+
+// SelectDbTableListByNames 查询数据库中对应的表数据
+func (s *toolsGenTable) SelectDbTableListByNames(tableNames []string) ([]*model.ToolsGenTable, error) {
+	if s.getDbDriver() != "mysql" {
+		return nil, gerror.New("代码生成只支持mysql数据库")
+	}
+	db := g.DB()
+	sql := "select * from information_schema.tables where table_name NOT LIKE 'qrtz_%' and table_name NOT LIKE 'gen_%' " +
+		" and table_schema = (select database()) "
+	if len(tableNames) > 0 {
+		in := gstr.TrimRight(gstr.Repeat("?,", len(tableNames)), ",")
+		sql += " and " + gdb.FormatSqlWithArgs("table_name in ("+in+")", gconv.SliceAny(tableNames))
+	}
+	var result []*model.ToolsGenTable
+	err := db.GetScan(&result, sql)
+	if err != nil {
+		g.Log().Error(err)
+		return nil, gerror.New("获取表格信息失败")
+	}
+	return result, err
+}
+
+// ImportGenTable 导入表结构
+func (s *toolsGenTable) ImportGenTable(tableList []*model.ToolsGenTable) error {
+	if tableList != nil {
+		tx, err := g.DB().Begin()
+		if err != nil {
+			return err
+		}
+		for _, table := range tableList {
+			tableName := table.TableName
+			s.InitTable(table)
+			result, err := tx.Model(dao.ToolsGenTable.Table).Insert(table)
+			if err != nil {
+				return err
+			}
+
+			tmpId, err := result.LastInsertId()
+
+			if err != nil || tmpId <= 0 {
+				tx.Rollback()
+				return gerror.New("保存数据失败")
+			}
+
+			table.TableId = tmpId
+
+			// 保存列信息
+			genTableColumns, err := ToolsGenTableColumn.SelectDbTableColumnsByName(tableName)
+
+			if err != nil || len(genTableColumns) <= 0 {
+				tx.Rollback()
+				return gerror.New("获取列数据失败")
+			}
+			for _, column := range genTableColumns {
+				ToolsGenTableColumn.InitColumnField(column, table)
+				_, err = tx.Model(dao.ToolsGenTableColumn.Table).Insert(column)
+				if err != nil {
+					tx.Rollback()
+					return gerror.New("保存列数据失败")
+				}
+			}
+		}
+		return tx.Commit()
+	} else {
+		return gerror.New("参数错误")
+	}
+}
+
+// InitTable 初始化表信息
+func (s *toolsGenTable) InitTable(table *model.ToolsGenTable) {
+	table.ClassName = s.ConvertClassName(table.TableName)
+	table.PackageName = g.Cfg().GetString("gen.packageName")
+	table.ModuleName = g.Cfg().GetString("gen.moduleName")
+	table.BusinessName = s.GetBusinessName(table.TableName)
+	table.FunctionName = strings.ReplaceAll(table.TableComment, "表", "")
+	table.FunctionAuthor = g.Cfg().GetString("gen.author")
+	table.TplCategory = "crud"
+	table.CreateTime = gtime.Now()
+	table.UpdateTime = table.CreateTime
+}
+
+// ConvertClassName 表名转换成类名
+func (s *toolsGenTable) ConvertClassName(tableName string) string {
+	return gstr.CaseCamel(s.removeTablePrefix(tableName))
+}
+
+// GetBusinessName 获取业务名
+func (s *toolsGenTable) GetBusinessName(tableName string) string {
+	return s.removeTablePrefix(tableName)
+}
+
+//删除表前缀
+func (s *toolsGenTable) removeTablePrefix(tableName string) string {
+	autoRemovePre := g.Cfg().GetBool("gen.autoRemovePre")
+	tablePrefix := g.Cfg().GetString("gen.tablePrefix")
+	if autoRemovePre && tablePrefix != "" {
+		searchList := strings.Split(tablePrefix, ",")
+		for _, str := range searchList {
+			if strings.HasPrefix(tableName, str) {
+				tableName = strings.Replace(tableName, str, "", 1) //注意,只替换一次
+			}
+		}
+	}
+	return tableName
+}
+
+// Delete 删除表信息
+func (s *toolsGenTable) Delete(ids []int) error {
+	tx, err := g.DB().Begin()
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("开启删除事务出错")
+	}
+	_, err = tx.Model(dao.ToolsGenTable.Table).Where(dao.ToolsGenTable.C.TableId+" in(?)", ids).Delete()
+	if err != nil {
+		g.Log().Error(err)
+		tx.Rollback()
+		return gerror.New("删除表格数据失败")
+	}
+	_, err = tx.Model(dao.ToolsGenTableColumn.Table).Where(dao.ToolsGenTableColumn.C.TableId+" in(?)", ids).Delete()
+	if err != nil {
+		g.Log().Error(err)
+		tx.Rollback()
+		return gerror.New("删除表格字段数据失败")
+	}
+	tx.Commit()
+	return nil
+}
+
+// GetTableInfoByTableId 获取表格信息
+func (s *toolsGenTable) GetTableInfoByTableId(tableId int64) (info *model.ToolsGenTable, err error) {
+	err = dao.ToolsGenTable.WherePri(tableId).Scan(&info)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取表格信息出错")
+	}
+	return
+}
+
+// SaveEdit 更新表及字段生成信息
+func (s *toolsGenTable) SaveEdit(req *dao.ToolsGenTableEditReq) (err error) {
+	if req == nil {
+		err = gerror.New("参数错误")
+		return
+	}
+	var table *model.ToolsGenTable
+	err = dao.ToolsGenTable.Where("table_id=?", req.TableId).Scan(&table)
+	if err != nil || table == nil {
+		err = gerror.New("数据不存在")
+		return
+	}
+	if req.TableName != "" {
+		table.TableName = req.TableName
+	}
+	if req.TableComment != "" {
+		table.TableComment = req.TableComment
+	}
+	if req.BusinessName != "" {
+		table.BusinessName = req.BusinessName
+	}
+	if req.ClassName != "" {
+		table.ClassName = req.ClassName
+	}
+	if req.FunctionAuthor != "" {
+		table.FunctionAuthor = req.FunctionAuthor
+	}
+	if req.FunctionName != "" {
+		table.FunctionName = req.FunctionName
+	}
+	if req.ModuleName != "" {
+		table.ModuleName = req.ModuleName
+	}
+	if req.PackageName != "" {
+		table.PackageName = req.PackageName
+	}
+	if req.Remark != "" {
+		table.Remark = req.Remark
+	}
+	if req.TplCategory != "" {
+		table.TplCategory = req.TplCategory
+	}
+	if req.Params != "" {
+		table.Options = req.Params
+	}
+	table.UpdateTime = gtime.Now()
+	var options g.Map
+	if req.TplCategory == "tree" {
+		//树表设置options
+		options = g.Map{
+			"treeCode":       req.TreeCode,
+			"treeParentCode": req.TreeParentCode,
+			"treeName":       req.TreeName,
+		}
+		table.Options = gconv.String(options)
+	} else {
+		table.Options = ""
+	}
+
+	var tx *gdb.TX
+	tx, err = g.DB().Begin()
+	if err != nil {
+		return
+	}
+	_, err = tx.Model(dao.ToolsGenTable.Table).Save(table)
+	if err != nil {
+		tx.Rollback()
+		return err
+	}
+
+	//保存列数据
+	if req.Columns != nil {
+		for _, column := range req.Columns {
+			if column.ColumnId > 0 {
+				var dbColumn *model.ToolsGenTableColumn
+				err = dao.ToolsGenTableColumn.Where("column_id=?", column.ColumnId).Scan(&dbColumn)
+				if dbColumn != nil {
+					dbColumn.ColumnComment = column.ColumnComment
+					dbColumn.GoType = column.GoType
+					dbColumn.HtmlType = column.HtmlType
+					dbColumn.QueryType = column.QueryType
+					dbColumn.GoField = column.GoField
+					dbColumn.DictType = column.DictType
+					dbColumn.IsInsert = column.IsInsert
+					dbColumn.IsEdit = column.IsEdit
+					dbColumn.IsList = column.IsList
+					dbColumn.IsQuery = column.IsQuery
+					dbColumn.IsRequired = column.IsRequired
+					if tc, e := options["treeParentCode"]; options != nil && e && tc != "" && tc == dbColumn.HtmlField {
+						dbColumn.IsQuery = "0"
+						dbColumn.IsList = "0"
+						dbColumn.HtmlType = "select"
+					}
+					//获取字段关联表信息
+					if column.LinkLabelName != "" {
+						dbColumn.LinkTableName = column.LinkTableName
+						dbColumn.LinkLabelId = column.LinkLabelId
+						dbColumn.LinkLabelName = column.LinkLabelName
+						var linkTable *model.ToolsGenTable
+						err = dao.ToolsGenTable.Where("table_name =?", column.LinkTableName).Scan(&linkTable)
+						if err != nil {
+							tx.Rollback()
+							return
+						}
+						dbColumn.LinkTableClass = linkTable.ClassName
+						dbColumn.LinkTablePackage = linkTable.PackageName
+					}
+					_, err = tx.Model(dao.ToolsGenTableColumn.Table).Save(dbColumn)
+					if err != nil {
+						tx.Rollback()
+						return
+					}
+				}
+			}
+		}
+	}
+	tx.Commit()
+	return
+}
+
+func (s *toolsGenTable) SelectRecordById(tableId int64) (entityExtend *dao.ToolsGenTableExtend, err error) {
+	var table *model.ToolsGenTable
+	table, err = s.GetTableInfoByTableId(tableId)
+	if err != nil {
+		return
+	}
+	m := gconv.Map(table)
+	gconv.Struct(m, &entityExtend)
+	if entityExtend.TplCategory == "tree" {
+		opt := gjson.New(entityExtend.Options)
+		entityExtend.TreeParentCode = opt.GetString("treeParentCode")
+		entityExtend.TreeCode = opt.GetString("treeCode")
+		entityExtend.TreeName = opt.GetString("treeName")
+	}
+	//表字段数据
+	var columns []*model.ToolsGenTableColumn
+	columns, err = ToolsGenTableColumn.SelectGenTableColumnListByTableId(tableId)
+	if err != nil {
+		return
+	}
+	entityExtend.Columns = columns
+	return
+}
+
+func (s *toolsGenTable) GenCode(ids []int, ctx context.Context) (err error) {
+	//获取当前运行时目录
+	curDir, err := os.Getwd()
+	if err != nil {
+		return gerror.New("获取本地路径失败")
+	}
+	fontDir := g.Cfg().GetString("gen.fontDir")
+	for _, id := range ids {
+		var genData g.MapStrStr
+		var extendData *dao.ToolsGenTableExtend
+		genData, extendData, err = s.GenData(gconv.Int64(id), ctx)
+		packageName := gstr.SubStr(extendData.PackageName, gstr.Pos(extendData.PackageName, "/"))
+		bisinessName := gstr.CaseCamelLower(extendData.BusinessName)
+		for key, code := range genData {
+			switch key {
+			case "controller":
+				path := strings.Join([]string{curDir, packageName, "/api/", extendData.TableName, ".go"}, "")
+				err = s.createFile(path, code, false)
+			case "dao":
+				path := strings.Join([]string{curDir, packageName, "/dao/", extendData.TableName, ".go"}, "")
+				err = s.createFile(path, code, false)
+			case "dao_internal":
+				path := strings.Join([]string{curDir, packageName, "/dao/internal/", extendData.TableName, ".go"}, "")
+				err = s.createFile(path, code, true)
+			case "model":
+				path := strings.Join([]string{curDir, packageName, "/model/", extendData.TableName, ".go"}, "")
+				err = s.createFile(path, code, true)
+			case "router":
+				path := strings.Join([]string{curDir, packageName, "/router/", extendData.TableName, ".go"}, "")
+				err = s.createFile(path, code, false)
+			case "service":
+				path := strings.Join([]string{curDir, packageName, "/service/", extendData.TableName, ".go"}, "")
+				err = s.createFile(path, code, false)
+			case "sql":
+				path := strings.Join([]string{curDir, "/data/gen_sql/", packageName, "/", extendData.TableName, ".sql"}, "")
+				hasSql := gfile.Exists(path)
+				err = s.createFile(path, code, false)
+				if !hasSql {
+					//第一次生成则向数据库写入菜单数据
+					err = s.writeDb(path)
+					if err != nil {
+						return
+					}
+					//清除菜单缓存
+					comService.Cache.New().Remove(global.SysAuthMenu)
+				}
+
+			case "vue":
+				path := strings.Join([]string{fontDir, "/src/views/", extendData.ModuleName, "/", bisinessName, "/list/index.vue"}, "")
+				err = s.createFile(path, code, false)
+			case "jsApi":
+				path := strings.Join([]string{fontDir, "/src/api/", extendData.ModuleName, "/", bisinessName, ".js"}, "")
+				err = s.createFile(path, code, false)
+			}
+		}
+	}
+	return
+}
+
+// createFile 创建文件
+func (s *toolsGenTable) createFile(fileName, data string, cover bool) (err error) {
+	if !gfile.Exists(fileName) || cover {
+		var f *os.File
+		f, err = gfile.Create(fileName)
+		if err == nil {
+			f.WriteString(data)
+		}
+		f.Close()
+	}
+	return
+}
+
+// GenData 获取生成数据
+func (s *toolsGenTable) GenData(tableId int64, ctx context.Context) (data g.MapStrStr, extendData *dao.ToolsGenTableExtend, err error) {
+	extendData, err = ToolsGenTable.SelectRecordById(tableId)
+	if err != nil {
+		return
+	}
+	if extendData == nil {
+		err = gerror.New("表格数据不存在")
+		return
+	}
+	ToolsGenTableColumn.SetPkColumn(extendData, extendData.Columns)
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	view := gview.New()
+	view.SetConfigWithMap(g.Map{
+		"Paths":      g.Cfg().GetString("gen.templatePath"),
+		"Delimiters": []string{"{{", "}}"},
+	})
+	view.BindFuncMap(g.Map{
+		"UcFirst": func(str string) string {
+			return gstr.UcFirst(str)
+		},
+		"Sum": func(a, b int) int {
+			return a + b
+		},
+		"CaseCamelLower": gstr.CaseCamelLower, //首字母小写驼峰
+		"CaseCamel":      gstr.CaseCamel,      //首字母大写驼峰
+		"HasSuffix":      gstr.HasSuffix,      //是否存在后缀
+		"VueTag": func(t string) string {
+			return t
+		},
+	})
+
+	//树形菜单选项
+	tplData := g.Map{"table": extendData}
+	daoKey := "dao"
+	daoValue := ""
+	var tmpDao string
+	if tmpDao, err = view.Parse(ctx, "go/dao.template", tplData); err == nil {
+		daoValue = tmpDao
+		daoValue, err = s.trimBreak(daoValue)
+	} else {
+		return
+	}
+	daoInternalKey := "dao_internal"
+	daoInternalValue := ""
+	var tmpInternalDao string
+	if tmpInternalDao, err = view.Parse(ctx, "go/dao_internal.template", tplData); err == nil {
+		daoInternalValue = tmpInternalDao
+		daoInternalValue, err = s.trimBreak(daoInternalValue)
+	} else {
+		return
+	}
+	modelKey := "model"
+	modelValue := ""
+	var tmpModel string
+	if tmpModel, err = view.Parse(ctx, "go/model.template", tplData); err == nil {
+		modelValue = tmpModel
+		modelValue, err = s.trimBreak(modelValue)
+	} else {
+		return
+	}
+	controllerKey := "controller"
+	controllerValue := ""
+	var tmpController string
+	if tmpController, err = view.Parse(ctx, "go/controller.template", tplData); err == nil {
+		controllerValue = tmpController
+		controllerValue, err = s.trimBreak(controllerValue)
+	} else {
+		return
+	}
+
+	serviceKey := "service"
+	serviceValue := ""
+	var tmpService string
+	if tmpService, err = view.Parse(ctx, "go/service.template", tplData); err == nil {
+		serviceValue = tmpService
+		serviceValue, err = s.trimBreak(serviceValue)
+	} else {
+		return
+	}
+
+	routerKey := "router"
+	routerValue := ""
+	var tmpRouter string
+	if tmpRouter, err = view.Parse(ctx, "go/router.template", tplData); err == nil {
+		routerValue = tmpRouter
+		routerValue, err = s.trimBreak(routerValue)
+	} else {
+		return
+	}
+
+	sqlKey := "sql"
+	sqlValue := ""
+	var tmpSql string
+	if tmpSql, err = view.Parse(ctx, "sql/sql.template", tplData); err == nil {
+		sqlValue = tmpSql
+		sqlValue, err = s.trimBreak(sqlValue)
+	} else {
+		return
+	}
+
+	jsApiKey := "jsApi"
+	jsApiValue := ""
+	var tmpJsApi string
+	if tmpJsApi, err = view.Parse(ctx, "js/api.template", tplData); err == nil {
+		jsApiValue = tmpJsApi
+		jsApiValue, err = s.trimBreak(jsApiValue)
+	} else {
+		return
+	}
+
+	vueKey := "vue"
+	vueValue := ""
+	var tmpVue string
+	tmpFile := "vue/list-vue.template"
+	if extendData.TplCategory == "tree" {
+		//树表
+		tmpFile = "vue/tree-vue.template"
+	}
+	if tmpVue, err = view.Parse(ctx, tmpFile, tplData); err == nil {
+		vueValue = tmpVue
+		vueValue, err = s.trimBreak(vueValue)
+	} else {
+		return
+	}
+
+	data = g.MapStrStr{
+		daoKey:         daoValue,
+		daoInternalKey: daoInternalValue,
+		modelKey:       modelValue,
+		controllerKey:  controllerValue,
+		serviceKey:     serviceValue,
+		routerKey:      routerValue,
+		sqlKey:         sqlValue,
+		jsApiKey:       jsApiValue,
+		vueKey:         vueValue,
+	}
+	return
+}
+
+//剔除多余的换行
+func (s *toolsGenTable) trimBreak(str string) (rStr string, err error) {
+	var b []byte
+	if b, err = gregex.Replace("(([\\s\t]*)\r?\n){2,}", []byte("$2\n"), []byte(str)); err == nil {
+		rStr = gconv.String(b)
+	}
+	return
+}
+
+// 写入菜单数据
+func (s *toolsGenTable) writeDb(path string) (err error) {
+	isAnnotation := false
+	var fi *os.File
+	fi, err = os.Open(path)
+	if err != nil {
+		return
+	}
+	defer fi.Close()
+	br := bufio.NewReader(fi)
+	var sqlStr []string
+	now := gtime.Now()
+	var res sql.Result
+	var id int64
+	for {
+		bytes, e := br.ReadBytes('\n')
+		if e == io.EOF {
+			break
+		}
+		bytes = bytes[:len(bytes)-2]
+		str := string(bytes)
+
+		if strings.Contains(str, "/*") {
+			isAnnotation = true
+		}
+
+		if isAnnotation {
+			if strings.Contains(str, "*/") {
+				isAnnotation = false
+			}
+			continue
+		}
+
+		if str == "" || strings.HasPrefix(str, "--") || strings.HasPrefix(str, "#") {
+			continue
+		}
+		if strings.HasSuffix(str, ";") {
+			if gstr.ContainsI(str, "select") {
+				if gstr.ContainsI(str, "@now") {
+					continue
+				}
+				if gstr.ContainsI(str, "@parentId") {
+					id, err = res.LastInsertId()
+				}
+			}
+			sqlStr = append(sqlStr, str)
+			sql := strings.Join(sqlStr, "")
+			gstr.ReplaceByArray(sql, []string{"@parentId", gconv.String(id), "@now", now.Format("Y-m-d H:i:s")})
+			//插入业务
+			res, err = g.DB().Exec(sql)
+			if err != nil {
+				return
+			}
+			sqlStr = nil
+		} else {
+			sqlStr = []string{str}
+		}
+	}
+	return
+}

+ 315 - 0
app/system/service/tools_gen_table_column.go

@@ -0,0 +1,315 @@
+/*
+* @desc:代码生成表格字段维护
+* @company:云南省奇讯科技有限公司
+* @Author: yixiaohu
+* @Date:   2021/7/22 17:39
+ */
+
+package service
+
+import (
+	"gfast/app/system/dao"
+	"gfast/app/system/model"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/text/gregex"
+	"github.com/gogf/gf/text/gstr"
+	"github.com/gogf/gf/util/gconv"
+	"strings"
+)
+
+var (
+	ToolsGenTableColumn = &toolsGenTableColumn{
+		ColumnTypeStr:      []string{"char", "varchar", "narchar", "varchar2", "tinytext", "text", "mediumtext", "longtext"},
+		ColumnTypeTime:     []string{"datetime", "time", "date", "timestamp"},
+		ColumnTypeNumber:   []string{"tinyint", "smallint", "mediumint", "int", "number", "integer", "bigint", "float", "float", "double", "decimal"},
+		ColumnNameNotEdit:  []string{"id", "created_by", "created_at", "updated_by", "updated_at", "deleted_at"},
+		ColumnNameNotList:  []string{"id", "created_by", "updated_by", "created_at", "updated_at", "deleted_at"},
+		ColumnNameNotQuery: []string{"id", "created_by", "updated_by", "created_at", "updated_at", "deleted_at", "remark"},
+	}
+)
+
+type toolsGenTableColumn struct {
+	ColumnTypeStr      []string //数据库字符串类型
+	ColumnTypeTime     []string //数据库时间类型
+	ColumnTypeNumber   []string //数据库数字类型
+	ColumnNameNotEdit  []string //页面不需要编辑字段
+	ColumnNameNotList  []string //页面不需要显示的列表字段
+	ColumnNameNotQuery []string //页面不需要查询字段
+}
+
+// SelectDbTableColumnsByName 根据表名称查询列信息
+func (s *toolsGenTableColumn) SelectDbTableColumnsByName(tableName string) ([]*model.ToolsGenTableColumn, error) {
+	db := g.DB()
+	var res []*model.ToolsGenTableColumn
+	sql := " select column_name, (case when (is_nullable = 'no' && column_key != 'PRI') then '1' else null end) as is_required, " +
+		"(case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment," +
+		" (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type from information_schema.columns" +
+		" where table_schema = (select database()) "
+	sql += " and " + gdb.FormatSqlWithArgs(" table_name=? ", []interface{}{tableName}) + " order by ordinal_position ASC "
+	err := db.GetScan(&res, sql)
+	if err != nil {
+		g.Log().Error(err)
+		return nil, gerror.New("查询列信息失败")
+	}
+	return res, nil
+
+}
+
+// InitColumnField 初始化列属性字段
+func (s *toolsGenTableColumn) InitColumnField(column *model.ToolsGenTableColumn, table *model.ToolsGenTable) {
+	dataType := s.GetDbType(column.ColumnType)
+	columnName := column.ColumnName
+	column.TableId = table.TableId
+	//设置字段名
+	column.GoField = gstr.CaseCamel(columnName)
+	column.HtmlField = gstr.CaseCamelLower(columnName)
+
+	if s.IsStringObject(dataType) {
+		//字段为字符串类型
+		column.GoType = "string"
+		columnLength := s.GetColumnLength(column.ColumnType)
+		if columnLength >= 500 {
+			column.HtmlType = "textarea"
+		} else {
+			column.HtmlType = "input"
+		}
+	} else if s.IsTimeObject(dataType) {
+		//字段为时间类型
+		column.GoType = "Time"
+		column.HtmlType = "datetime"
+	} else if s.IsNumberObject(dataType) {
+		//字段为数字类型
+		column.HtmlType = "input"
+		t, _ := gregex.ReplaceString(`\(.+\)`, "", column.ColumnType)
+		t = gstr.Split(gstr.Trim(t), " ")[0]
+		t = gstr.ToLower(t)
+		// 如果是浮点型
+		switch t {
+		case "float", "double", "decimal":
+			column.GoType = "float64"
+		case "bit", "int", "tinyint", "small_int", "smallint", "medium_int", "mediumint":
+			if gstr.ContainsI(column.ColumnType, "unsigned") {
+				column.GoType = "uint"
+			} else {
+				column.GoType = "int"
+			}
+		case "big_int", "bigint":
+			if gstr.ContainsI(column.ColumnType, "unsigned") {
+				column.GoType = "uint64"
+			} else {
+				column.GoType = "int64"
+			}
+		}
+	}
+	//新增字段
+	if s.IsNotEdit(columnName) {
+		column.IsRequired = "0"
+		column.IsInsert = "0"
+	} else {
+		column.IsInsert = "1"
+		if strings.Index(columnName, "name") >= 0 || strings.Index(columnName, "status") >= 0 {
+			column.IsRequired = "1"
+		}
+	}
+
+	// 编辑字段
+	if s.IsNotEdit(columnName) {
+		column.IsEdit = "0"
+	} else {
+		if column.IsPk == "1" {
+			column.IsEdit = "0"
+		} else {
+			column.IsEdit = "1"
+		}
+	}
+	// 列表字段
+	if s.IsNotList(columnName) {
+		column.IsList = "0"
+	} else {
+		column.IsList = "1"
+	}
+	// 查询字段
+	if s.IsNotQuery(columnName) {
+		column.IsQuery = "0"
+	} else {
+		column.IsQuery = "1"
+	}
+
+	// 查询字段类型
+	if s.CheckNameColumn(columnName) {
+		column.QueryType = "LIKE"
+	} else {
+		column.QueryType = "EQ"
+	}
+
+	// 状态字段设置单选框
+	if s.CheckStatusColumn(columnName) {
+		column.HtmlType = "radio"
+	} else if s.CheckTypeColumn(columnName) || s.CheckSexColumn(columnName) {
+		// 类型&性别字段设置下拉框
+		column.HtmlType = "select"
+	}
+}
+
+// GetDbType 获取数据库类型字段
+func (s *toolsGenTableColumn) GetDbType(columnType string) string {
+	if strings.Index(columnType, "(") > 0 {
+		return columnType[0:strings.Index(columnType, "(")]
+	} else {
+		return columnType
+	}
+}
+
+// IsExistInArray 判断 value 是否存在在切片array中
+func (s *toolsGenTableColumn) IsExistInArray(value string, array []string) bool {
+	for _, v := range array {
+		if v == value {
+			return true
+		}
+	}
+	return false
+}
+
+// GetColumnLength 获取字段长度
+func (s *toolsGenTableColumn) GetColumnLength(columnType string) int {
+	start := strings.Index(columnType, "(")
+	end := strings.Index(columnType, ")")
+	result := ""
+	if start >= 0 && end >= 0 {
+		result = columnType[start+1 : end-1]
+	}
+	return gconv.Int(result)
+}
+
+// IsStringObject 判断是否是数据库字符串类型
+func (s *toolsGenTableColumn) IsStringObject(dataType string) bool {
+	return s.IsExistInArray(dataType, s.ColumnTypeStr)
+}
+
+// IsTimeObject 判断是否是数据库时间类型
+func (s *toolsGenTableColumn) IsTimeObject(dataType string) bool {
+	return s.IsExistInArray(dataType, s.ColumnTypeTime)
+}
+
+// IsNumberObject 是否数字类型
+func (s *toolsGenTableColumn) IsNumberObject(dataType string) bool {
+	return s.IsExistInArray(dataType, s.ColumnTypeNumber)
+}
+
+// IsNotEdit 是否不可编辑
+func (s *toolsGenTableColumn) IsNotEdit(name string) bool {
+	return s.IsExistInArray(name, s.ColumnNameNotEdit)
+}
+
+// IsNotList 不在列表显示
+func (s *toolsGenTableColumn) IsNotList(name string) bool {
+	return s.IsExistInArray(name, s.ColumnNameNotList)
+}
+
+// IsNotQuery 不可用于查询
+func (s *toolsGenTableColumn) IsNotQuery(name string) bool {
+	return s.IsExistInArray(name, s.ColumnNameNotQuery)
+}
+
+// CheckNameColumn 检查字段名后4位是否是name
+func (s *toolsGenTableColumn) CheckNameColumn(columnName string) bool {
+	if len(columnName) >= 4 {
+		end := len(columnName)
+		start := end - 4
+		if start <= 0 {
+			start = 0
+		}
+		tmp := columnName[start:end]
+		if tmp == "name" {
+			return true
+		}
+	}
+	return false
+}
+
+// CheckStatusColumn 检查字段名后6位是否是status
+func (s *toolsGenTableColumn) CheckStatusColumn(columnName string) bool {
+	if len(columnName) >= 6 {
+		end := len(columnName)
+		start := end - 6
+
+		if start <= 0 {
+			start = 0
+		}
+		tmp := columnName[start:end]
+
+		if tmp == "status" {
+			return true
+		}
+	}
+
+	return false
+}
+
+// CheckTypeColumn 检查字段名后4位是否是type
+func (s *toolsGenTableColumn) CheckTypeColumn(columnName string) bool {
+	if len(columnName) >= 4 {
+		end := len(columnName)
+		start := end - 4
+
+		if start <= 0 {
+			start = 0
+		}
+
+		if columnName[start:end] == "type" {
+			return true
+		}
+	}
+	return false
+}
+
+// CheckSexColumn 检查字段名后3位是否是sex
+func (s *toolsGenTableColumn) CheckSexColumn(columnName string) bool {
+	if len(columnName) >= 3 {
+		end := len(columnName)
+		start := end - 3
+		if start <= 0 {
+			start = 0
+		}
+		if columnName[start:end] == "sex" {
+			return true
+		}
+	}
+	return false
+}
+
+// SelectGenTableColumnListByTableId 查询业务字段列表
+func (s *toolsGenTableColumn) SelectGenTableColumnListByTableId(tableId int64) (list []*model.ToolsGenTableColumn, err error) {
+	err = dao.ToolsGenTableColumn.Where(dao.ToolsGenTableColumn.C.TableId, tableId).
+		Order(dao.ToolsGenTableColumn.C.Sort + " asc, " + dao.ToolsGenTableColumn.C.ColumnId + " asc").Scan(&list)
+	if err != nil {
+		g.Log().Error(err)
+		return nil, gerror.New("获取字段信息出错")
+	}
+	return list, nil
+}
+
+// GetAllTableColumns 获取所有字段信息
+func (s *toolsGenTableColumn) GetAllTableColumns() (list []*model.ToolsGenTableColumn, err error) {
+	err = dao.ToolsGenTableColumn.Order(dao.ToolsGenTableColumn.C.Sort + " asc, " + dao.ToolsGenTableColumn.C.ColumnId + " asc").Scan(&list)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取字段信息出错")
+		return
+	}
+	return
+}
+
+func (s *toolsGenTableColumn) SetPkColumn(table *dao.ToolsGenTableExtend, columns []*model.ToolsGenTableColumn) {
+	for _, column := range columns {
+		if column.IsPk == "1" {
+			table.PkColumn = column
+			break
+		}
+	}
+	if table.PkColumn == nil {
+		table.PkColumn = columns[0]
+	}
+}

File diff ditekan karena terlalu besar
+ 96 - 1
data/gfast-v2-open.sql


+ 147 - 0
template/vm/go/controller.template

@@ -0,0 +1,147 @@
+// ==========================================================================
+// GFast自动生成控制器相关代码,只生成一次,按需修改,再次生成不会覆盖.
+// 生成日期:{{.table.CreateTime}}
+// 生成路径: {{.table.PackageName}}/api/{{.table.BusinessName}}.go
+// 生成人:{{.table.FunctionAuthor}}
+// ==========================================================================
+
+{{$structName := .table.BusinessName | CaseCamelLower}}
+
+package api
+
+{{$hasGStr:=false}}
+{{range $index,$column:=.table.Columns}}
+{{if eq $column.HtmlType "checkbox"}}
+{{$hasGStr = true}}
+{{end}}
+{{end}}
+
+import (
+    "gfast/app/system/dao"
+    "gfast/app/system/service"
+    "github.com/gogf/gf/frame/g"
+    "github.com/gogf/gf/net/ghttp"
+    "github.com/gogf/gf/util/gvalid"
+    {{if $hasGStr}}
+    "github.com/gogf/gf/text/gstr"
+    {{end}}
+)
+
+type {{$structName}} struct {
+	{{.table.ModuleName}}Base
+}
+
+var {{.table.ClassName}} = new({{$structName}})
+
+// List 列表
+func (c *{{$structName}}) List(r *ghttp.Request) {
+	var req *dao.{{.table.ClassName}}SearchReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		c.FailJsonExit(r, err.(gvalid.Error).FirstString())
+	}
+	total, page, list, err := service.{{.table.ClassName}}.GetList(req)
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	result := g.Map{
+		"currentPage": page,
+		"total":       total,
+		"list":        list,
+	}
+	c.SusJsonExit(r, result)
+}
+
+// Add 添加
+func (c *{{$structName}}) Add(r *ghttp.Request) {
+    var req *dao.{{.table.ClassName}}AddReq
+    //获取参数
+    if err := r.Parse(&req); err != nil {
+        c.FailJsonExit(r, err.(gvalid.Error).FirstString())
+    }
+    {{range $index,$column:= .table.Columns}}
+    {{if eq $column.ColumnName "created_by"}}
+    req.CreatedBy = c.GetCurrentUser(r.GetCtx()).GetUserId()
+    {{end}}
+    {{if eq $column.HtmlType "checkbox"}}
+    {{$column.HtmlField}} := r.GetStrings("{{$column.HtmlField}}")
+    if len({{$column.HtmlField}})>0{
+       req.{{$column.GoField}} = gstr.Join({{$column.HtmlField}},",")
+    }else{
+       req.{{$column.GoField}} = ""
+    }
+    {{end}}
+    {{end}}
+    err := service.{{.table.ClassName}}.Add(req)
+    if err != nil {
+        c.FailJsonExit(r, err.Error())
+    }
+    c.SusJsonExit(r, "添加成功")
+}
+
+
+// Get 获取
+func (c *{{$structName}}) Get(r *ghttp.Request) {
+	id := r.GetInt64("id")
+	info, err := service.{{.table.ClassName}}.GetInfoById(id)
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	c.SusJsonExit(r, info)
+}
+
+// Edit 修改
+func (c *{{$structName}}) Edit(r *ghttp.Request) {
+    var req *dao.{{.table.ClassName}}EditReq
+    //获取参数
+    if err := r.Parse(&req); err != nil {
+        c.FailJsonExit(r, err.(gvalid.Error).FirstString())
+    }
+    {{range $index,$column:= .table.Columns}}
+    {{if eq $column.ColumnName "updated_by"}}
+    req.UpdatedBy = c.GetCurrentUser(r.GetCtx()).GetUserId() //获取登陆用户id
+    {{end}}
+    {{if eq $column.HtmlType "checkbox"}}
+    {{$column.HtmlField}} := r.GetStrings("{{$column.HtmlField}}")
+    if len({{$column.HtmlField}})>0{
+       req.{{$column.GoField}} = gstr.Join({{$column.HtmlField}},",")
+    }else{
+       req.{{$column.GoField}} = ""
+    }
+    {{end}}
+    {{end}}
+    err := service.{{.table.ClassName}}.Edit(req)
+    if err != nil {
+        c.FailJsonExit(r, err.Error())
+    }
+    c.SusJsonExit(r, "修改成功")
+}
+
+
+// Delete 删除
+func (c *{{$structName}}) Delete(r *ghttp.Request) {
+	ids := r.GetInts("ids")
+	err := service.{{.table.ClassName}}.DeleteByIds(ids)
+	if err != nil {
+		c.FailJsonExit(r, err.Error())
+	}
+	c.SusJsonExit(r, "删除成功")
+}
+
+{{range $index,$column:= .table.Columns}}
+{{if and (HasSuffix $column.ColumnName "status") (eq $column.IsList "1") }}
+// Change{{$column.GoField}} 修改状态
+func (c *{{$structName}})Change{{$column.GoField}}(r *ghttp.Request){
+	   var req *dao.{{$.table.ClassName}}{{$column.GoField}}Req
+	   //获取参数
+	   if err := r.Parse(&req); err != nil {
+	       c.FailJsonExit(r, err.(gvalid.Error).FirstString())
+	   }
+	   if err := service.{{$.table.ClassName}}.Change{{$column.GoField}}(req); err != nil {
+	       c.FailJsonExit(r, err.Error())
+	   } else {
+	       c.SusJsonExit(r, "状态设置成功")
+	   }
+}
+{{end}}
+{{end}}

+ 88 - 0
template/vm/go/dao.template

@@ -0,0 +1,88 @@
+// ==========================================================================
+// GFast自动生成dao操作代码,无需手动修改,重新生成不会自动覆盖.
+// 生成日期:{{.table.CreateTime}}
+// 生成路径: {{.table.PackageName}}/dao/{{.table.TableName}}.go
+// 生成人:{{.table.FunctionAuthor}}
+// ==========================================================================
+
+package dao
+
+{{$hasGTime:=false}}
+{{range $index, $column := .table.Columns}}
+{{if eq $column.GoType "Time"}}
+{{$hasGTime = true}}
+{{end}}
+{{end}}
+
+import (
+    comModel "gfast/app/common/model"
+    "{{.table.PackageName}}/dao/internal"
+    {{if $hasGTime}}
+    "github.com/gogf/gf/os/gtime"
+    {{end}}
+)
+
+
+// {{.table.BusinessName | CaseCamelLower}}Dao is the manager for logic model data accessing and custom defined data operations functions management.
+// You can define custom methods on it to extend its functionality as you wish.
+type {{.table.BusinessName | CaseCamelLower}}Dao struct {
+	*internal.{{.table.BusinessName | CaseCamel}}Dao
+}
+
+var (
+	// {{.table.ClassName}} is globally public accessible object for table tools_gen_table operations.
+	{{.table.ClassName}} {{.table.BusinessName | CaseCamelLower}}Dao
+)
+
+func init() {
+	{{.table.ClassName}} = {{.table.BusinessName | CaseCamelLower}}Dao{
+            internal.New{{.table.ClassName}}Dao(),
+	}
+}
+
+// Fill with you ideas below.
+
+
+// {{.table.ClassName}}SearchReq 分页请求参数
+type {{.table.ClassName}}SearchReq struct {
+    {{range $index, $column := .table.Columns}}
+    {{if eq $column.IsQuery "1"}}
+    {{$column.GoField}}  {{if eq $column.GoType "Time"}}*gtime.Time{{else if or (eq $column.GoType "int") (eq $column.GoType "int64") (eq $column.GoType "uint") (eq $column.GoType "uint64")}}string{{else}}{{$column.GoType}}{{end}} `p:"{{$column.HtmlField}}"` //{{$column.ColumnComment}}
+    {{end}}
+    {{end}}
+    comModel.PageReq
+}
+
+
+// {{.table.ClassName}}AddReq 添加操作请求参数
+type {{.table.ClassName}}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}}
+    {{if eq $column.ColumnName "created_by"}}CreatedBy       uint64 {{end}}
+    {{end}}
+}
+
+
+// {{.table.ClassName}}EditReq 修改操作请求参数
+type {{.table.ClassName}}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}}
+    {{if eq $column.ColumnName "updated_by"}}UpdatedBy       uint64 {{end}}
+    {{end}}
+}
+
+
+
+{{range $index,$column:= .table.Columns}}
+{{if and (HasSuffix $column.ColumnName "status") (eq $column.IsList "1") }}
+// {{$.table.ClassName}}{{$column.GoField}}Req 设置用户状态参数
+type {{$.table.ClassName}}{{$column.GoField}}Req struct {
+	{{$.table.PkColumn.GoField}}    {{$.table.PkColumn.GoType}}  `p:"{{$.table.PkColumn.HtmlField}}" v:"required#主键ID不能为空"`
+	{{$column.GoField}} {{$column.GoType}}   `p:"{{$column.HtmlField}}" v:"required#{{$column.ColumnComment}}不能为空"`
+}
+{{end}}
+{{end}}

+ 48 - 0
template/vm/go/dao_internal.template

@@ -0,0 +1,48 @@
+// ==========================================================================
+// GFast自动生成dao internal操作代码,无需手动修改,重新生成会自动覆盖.
+// 生成日期:{{.table.CreateTime}}
+// 生成路径: {{.table.PackageName}}/dao/internal/{{.table.TableName}}.go
+// 生成人:{{.table.FunctionAuthor}}
+// ==========================================================================
+
+package internal
+
+
+import (
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+)
+
+
+// {{.table.ClassName}}Dao is the manager for logic model data accessing and custom defined data operations functions management.
+type {{.table.ClassName}}Dao struct {
+	gmvc.M                      // M is the core and embedded struct that inherits all chaining operations from gdb.Model.
+	C      {{.table.BusinessName | CaseCamelLower}}Columns // C is the short type for Columns, which contains all the column names of Table for convenient usage.
+	DB     gdb.DB               // DB is the raw underlying database management object.
+	Table  string               // Table is the underlying table name of the DAO.
+}
+
+
+// {{.table.BusinessName | CaseCamelLower}}Columns defines and stores column names for table {{.table.TableName}}.
+type {{.table.BusinessName | CaseCamelLower}}Columns struct {
+    {{range $index, $column := .table.Columns}}
+        {{$column.GoField}}  string  // {{$column.ColumnComment}}
+    {{end}}
+}
+
+
+// New{{.table.ClassName}}Dao creates and returns a new DAO object for table data access.
+func New{{.table.ClassName}}Dao() *{{.table.ClassName}}Dao {
+	columns := {{.table.BusinessName | CaseCamelLower}}Columns{
+	    {{range $index, $column := .table.Columns}}
+            {{$column.GoField}}:  "{{$column.ColumnName}}",
+        {{end}}
+	}
+	return &{{.table.ClassName}}Dao{
+		C:     columns,
+		M:     g.DB("default").Model("{{.table.TableName}}").Safe(),
+		DB:    g.DB("default"),
+		Table: "{{.table.TableName}}",
+	}
+}

+ 27 - 0
template/vm/go/model.template

@@ -0,0 +1,27 @@
+// ==========================================================================
+// GFast自动生成model代码,无需手动修改,重新生成会自动覆盖.
+// 生成日期:{{.table.CreateTime}}
+// 生成路径: {{.table.PackageName}}/model/{{.table.TableName}}.go
+// 生成人:{{.table.FunctionAuthor}}
+// ==========================================================================
+
+package model
+
+
+{{$hasGTime:=false}}
+{{range $index, $column := .table.Columns}}
+{{if eq $column.GoType "Time"}}
+{{$hasGTime = true}}
+{{end}}
+{{end}}
+
+{{if $hasGTime}}
+import "github.com/gogf/gf/os/gtime"
+{{end}}
+
+// {{.table.ClassName}} is the golang structure for table {{.table.TableName}}.
+type {{.table.ClassName}} struct {
+	{{range $index, $column := .table.Columns}}
+        {{if eq $column.IsPk "1"}} {{$column.GoField}}       {{if eq $column.GoType "Time"}}*gtime.Time{{else}}{{$column.GoType}}{{end}}         `orm:"{{$column.ColumnName}},primary" json:"{{$column.HtmlField}}"`    // {{$column.ColumnComment}} {{else}} {{$column.GoField}}    {{if eq $column.GoType "Time"}}*gtime.Time{{else}}{{$column.GoType}}{{end}}         `orm:"{{$column.ColumnName}}" json:"{{$column.HtmlField}}"`    // {{$column.ColumnComment}} {{end}}
+    {{end}}
+}

+ 49 - 0
template/vm/go/router.template

@@ -0,0 +1,49 @@
+// ==========================================================================
+// GFast自动生成路由代码,只生成一次,按需修改,再次生成不会覆盖.
+// 生成日期:{{.table.CreateTime}}
+// 生成路径: {{.table.PackageName}}/router/{{.table.BusinessName}}.go
+// 生成人:{{.table.FunctionAuthor}}
+// ==========================================================================
+package router
+
+import (
+    "{{.table.PackageName}}/api"
+    "gfast/middleware"
+    "github.com/gogf/gf/frame/g"
+    "github.com/gogf/gf/net/ghttp"
+    {{if ne $.table.ModuleName "system"}}
+    sysApi "gfast/app/system/api"
+    {{end}}
+)
+
+//加载路由
+func init() {
+    s := g.Server()
+    s.Group("/", func(group *ghttp.RouterGroup) {
+        group.Group("/{{.table.ModuleName}}", func(group *ghttp.RouterGroup) {
+            {{if ne $.table.ModuleName "system"}}
+            //gToken拦截器
+            sysApi.GfToken.Middleware(group)
+            {{end}}
+            //context拦截器
+            group.Middleware(middleware.Ctx, middleware.Auth)
+            {{if ne $.table.ModuleName "system"}}
+            //后台操作日志记录
+            group.Hook("/*", ghttp.HookAfterOutput, sysApi.SysOperLog.OperationLog)
+            {{end}}
+
+            group.Group("/{{.table.BusinessName | CaseCamelLower}}", func(group *ghttp.RouterGroup) {
+                group.GET("list", api.{{.table.ClassName}}.List)
+                group.GET("get", api.{{.table.ClassName}}.Get)
+                group.POST("add", api.{{.table.ClassName}}.Add)
+                group.PUT("edit", api.{{.table.ClassName}}.Edit)
+                group.DELETE("delete", api.{{.table.ClassName}}.Delete)
+                {{range $index,$column:= .table.Columns}}
+                {{if and (HasSuffix $column.ColumnName "status") (eq $column.IsList "1") }}
+                group.PUT("change{{$column.GoField}}",api.{{$.table.ClassName}}.Change{{$column.GoField}})
+                {{end}}
+                {{end}}
+            })
+        })
+    })
+}

+ 202 - 0
template/vm/go/service.template

@@ -0,0 +1,202 @@
+// ==========================================================================
+// GFast自动生成业务逻辑层相关代码,只生成一次,按需修改,再次生成不会覆盖.
+// 生成日期:{{.table.CreateTime}}
+// 生成路径: {{.table.PackageName}}/service/{{.table.BusinessName}}.go
+// 生成人:{{.table.FunctionAuthor}}
+// ==========================================================================
+{{$structName := .table.BusinessName | CaseCamelLower}}
+
+package service
+
+
+import (
+    {{if ne .table.TplCategory "tree"}}
+	comModel "gfast/app/common/model"
+	{{end}}
+	"gfast/app/system/dao"
+	"gfast/app/system/model"
+	{{if eq .table.TplCategory "tree"}}
+	"github.com/gogf/gf/util/gconv"
+	"gfast/library"
+    {{end}}
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+)
+
+
+type {{$structName}} struct {
+}
+
+var {{.table.ClassName}} = new({{$structName}})
+
+
+{{$pk:=""}}
+{{$pkGoField:=""}}
+
+{{$createdAt:=""}}
+{{$createdAtGoField:=""}}
+
+{{range $index, $column := .table.Columns}}
+{{if eq $column.IsPk "1"}}
+    {{$pk = $column.ColumnName}}
+    {{$pkGoField = $column.GoField}}
+{{end}}
+{{if eq $column.ColumnName "created_at"}}
+    {{$createdAt = $column.ColumnName}}
+    {{$createdAtGoField = $column.GoField}}
+{{end}}
+{{end}}
+
+// GetList 获取任务列表
+func (s *{{$structName}}) GetList(req *dao.{{.table.ClassName}}SearchReq) (total, page int, list []*model.{{.table.ClassName}}, err error) {
+	model := dao.{{.table.ClassName}}.M
+	if req != nil {
+	{{range $index, $column := .table.Columns}} {{if eq $column.IsQuery "1"}}
+        {{if eq $column.QueryType "LIKE"}}
+            if req.{{$column.GoField}} != "" {
+                model = model.Where(dao.{{$.table.ClassName}}.C.{{$column.GoField}}+" like ?", "%"+req.{{$column.GoField}}+"%")
+            } {{end}}
+        {{if eq $column.QueryType "EQ"}} {{if eq $column.GoType "string"}}
+            if req.{{$column.GoField}} != "" {
+                model = model.Where(dao.{{$.table.ClassName}}.C.{{$column.GoField}}+" = ?", req.{{$column.GoField}})
+            }
+        {{else if and (eq $column.GoType "Time") (eq $column.ColumnName "created_at")}}
+            if req.BeginTime != "" {
+                model = model.Where(dao.{{$.table.ClassName}}.C.{{$column.GoField}}+" >=", req.BeginTime)
+            }
+            if req.EndTime != "" {
+                model = model.Where(dao.{{$.table.ClassName}}.C.{{$column.GoField}}+" <", req.EndTime)
+            }
+        {{else if or (eq $column.GoType "int") (eq $column.GoType "int64") (eq $column.GoType "uint") (eq $column.GoType "uint64") }}
+            if req.{{$column.GoField}} != "" {
+                model = model.Where(dao.{{$.table.ClassName}}.C.{{$column.GoField}}+" = ?", req.{{$column.GoField}})
+            }
+        {{end}} {{end}}
+        {{if and (eq $column.QueryType "BETWEEN") (eq $column.ColumnType "datetime") }}
+            if req.{{$column.GoField}} != nil {
+                model = model.Where(dao.{{$.table.ClassName}}.C.{{$column.GoField}}+" >= ? AND "+dao.{{$.table.ClassName}}.C.{{$column.GoField}}+" < ?", req.{{$column.GoField}}, req.{{$column.GoField}}.Add(gtime.D))
+            }
+        {{end}}
+    {{end}}{{end}}
+	}
+	total, err = model.Count()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取总行数失败")
+		return
+	}
+    {{if ne .table.TplCategory "tree"}}
+    if req.PageNum == 0 {
+        req.PageNum = 1
+    }
+    page = req.PageNum
+    if req.PageSize == 0 {
+        req.PageSize = comModel.PageSize
+    }
+    order:= "{{$pk}} asc"
+    if req.OrderBy!=""{
+        order = req.OrderBy
+    }
+    err = model.Page(page, req.PageSize).Order(order).Scan(&list)
+    {{else}}
+	order:= "{{$pk}} asc"
+	if req.OrderBy!=""{
+		order = req.OrderBy
+	}
+	err = model.Order(order).Scan(&list)
+    {{end}}
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取数据失败")
+	}
+	return
+}
+
+
+// GetInfoById 通过id获取
+func (s *{{$structName}}) GetInfoById(id int64) (info *model.{{.table.ClassName}}, err error) {
+	if id == 0 {
+		err = gerror.New("参数错误")
+		return
+	}
+	err = dao.{{.table.ClassName}}.Where(dao.{{.table.ClassName}}.C.{{$pkGoField}}, id).Scan(&info)
+	if err != nil {
+		g.Log().Error(err)
+	}
+	if info == nil || err != nil {
+		err = gerror.New("获取信息失败")
+	}
+	return
+}
+
+// Add 添加
+func (s *{{$structName}}) Add(req *dao.{{.table.ClassName}}AddReq) (err error) {
+	_, err = dao.{{.table.ClassName}}.Insert(req)
+	return
+}
+
+// Edit 修改
+func (s *{{$structName}}) Edit(req *dao.{{.table.ClassName}}EditReq) error {
+    {{ $fieldsEx:= concat "dao." $.table.ClassName ".C." $pkGoField }}
+    {{if ne $createdAt ""}}
+        {{$fieldsEx = concat "dao." $.table.ClassName ".C." $pkGoField  "," "dao." $.table.ClassName ".C." $createdAtGoField}}
+    {{end}}
+	_, err := dao.{{.table.ClassName}}.FieldsEx({{$fieldsEx}}).Where(dao.{{.table.ClassName}}.C.{{$pkGoField}}, req.{{$pkGoField}}).
+		Update(req)
+	return err
+}
+
+
+// DeleteByIds 删除
+func (s *{{$structName}}) DeleteByIds(ids []int) (err error) {
+	if len(ids) == 0 {
+		err = gerror.New("参数错误")
+	}
+	{{if eq .table.TplCategory "tree"}}
+    ids, err = s.GetChildrenIds(ids)
+    if err != nil {
+        return
+    }
+	{{end}}
+	_, err = dao.{{.table.ClassName}}.Delete(dao.{{.table.ClassName}}.C.{{$pkGoField}}+" in (?)", ids)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("删除失败")
+	}
+	return
+}
+
+
+{{range $index,$column:= .table.Columns}}
+{{if and (HasSuffix $column.ColumnName "status") (eq $column.IsList "1") }}
+// Change{{$column.GoField}} 修改状态
+func (s *{{$structName}}) Change{{$column.GoField}}(req *dao.{{$.table.ClassName}}{{$column.GoField}}Req) error {
+	_, err := dao.{{$.table.ClassName}}.WherePri(req.{{$pkGoField}}).Update(g.Map{
+		dao.{{$.table.ClassName}}.C.{{$column.GoField}}: req.{{$column.GoField}},
+	})
+	return err
+}
+{{end}}
+{{end}}
+
+{{if eq .table.TplCategory "tree"}}
+// GetChildrenIds 通过ID获取子级ID
+func (s *{{$structName}})GetChildrenIds(ids []int) ([]int, error) {
+	//获取所有
+	_,_,all, err := s.GetList(new(dao.{{.table.ClassName}}SearchReq))
+	if err != nil {
+		return nil, err
+	}
+	list := make(g.List, len(all))
+	for k, info := range all {
+		list[k] = gconv.Map(info)
+	}
+	for _, id := range ids {
+		children := library.FindSonByParentId(list, id, "{{.table.TreeParentCode}}", "{{.table.TreeCode}}")
+		for _, cid := range children {
+			ids = append(ids, gconv.Int(cid["{{.table.TreeCode}}"]))
+		}
+	}
+	return ids, nil
+}
+{{end}}

+ 81 - 0
template/vm/js/api.template

@@ -0,0 +1,81 @@
+import request from '@/utils/request'
+
+{{$businessName := .table.BusinessName | CaseCamelLower}}
+
+// 查询{{.table.FunctionName}}列表
+export function list{{.table.ClassName}}(query) {
+  return request({
+    url: '/{{.table.ModuleName}}/{{$businessName}}/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询{{.table.FunctionName}}详细
+export function get{{.table.ClassName}}({{.table.PkColumn.ColumnName}}) {
+  return request({
+    url: '/{{.table.ModuleName}}/{{$businessName}}/get',
+    method: 'get',
+    params: {
+     id: {{.table.PkColumn.ColumnName}}
+    }
+  })
+}
+
+// 新增{{.table.FunctionName}}
+export function add{{.table.ClassName}}(data) {
+  return request({
+    url: '/{{.table.ModuleName}}/{{$businessName}}/add',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改{{.table.FunctionName}}
+export function update{{.table.ClassName}}(data) {
+  return request({
+    url: '/{{.table.ModuleName}}/{{$businessName}}/edit',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除{{.table.FunctionName}}
+export function del{{.table.ClassName}}({{.table.PkColumn.ColumnName}}s) {
+  return request({
+    url: '/{{.table.ModuleName}}/{{$businessName}}/delete',
+    method: 'delete',
+    data:{
+       ids:{{.table.PkColumn.ColumnName}}s
+    }
+  })
+}
+
+
+
+{{range $index,$column:= .table.Columns}}
+{{if and (HasSuffix $column.ColumnName "status") (eq $column.IsList "1") }}
+// {{$.table.FunctionName}}{{$column.ColumnComment}}修改
+export function change{{$.table.ClassName}}{{$column.GoField}}({{$.table.PkColumn.ColumnName}},{{$column.HtmlField}}) {
+  const data = {
+    {{$.table.PkColumn.ColumnName}},
+    {{$column.HtmlField}}
+  }
+  return request({
+    url: '/{{$.table.ModuleName}}/{{$businessName}}/change{{$column.GoField}}',
+    method: 'put',
+    data:data
+  })
+}
+{{end}}
+{{if ne $column.LinkTableName ""}}
+// 关联{{$column.LinkTableName}}表选项
+export function list{{$column.LinkTableClass}}(query){
+   return request({
+     url: '/{{$.table.ModuleName}}/{{$column.LinkTableName | CaseCamelLower}}/list',
+     method: 'get',
+     params: query
+   })
+}
+{{end}}
+{{end}}

+ 44 - 0
template/vm/sql/sql.template

@@ -0,0 +1,44 @@
+/*
+==========================================================================
+GFast自动生成菜单SQL,只生成一次,按需修改.
+生成日期:{{.table.CreateTime}}
+生成路径: data/gen_sql/{{.table.ModuleName}}/{{.table.BusinessName}}_menu.sql
+生成人:{{.table.FunctionAuthor}}
+==========================================================================
+*/
+-- 当前日期
+select @now := now();
+
+-- 目录 SQL
+INSERT INTO `sys_auth_rule` (`pid`,`name`,`title`,`icon`,`condition`,`remark`,`menu_type`,`weigh`,`status`,`always_show`,`path`,`jump_path`,`component`,`is_frame`,`module_type`,`model_id`,`created_at`,`updated_at`,`deleted_at` )
+VALUES(0,'{{.table.ModuleName}}/{{.table.BusinessName | CaseCamelLower}}','{{.table.FunctionName}}管理','form','','{{.table.FunctionName}}管理',0,0,1,1,'{{.table.BusinessName | CaseCamelLower}}','','',0,'sys_admin',0,@now,@now,NULL );
+
+-- 菜单父目录ID
+SELECT @parentId := LAST_INSERT_ID();
+
+-- 菜单 SQL
+INSERT INTO `sys_auth_rule` (`pid`,`name`,`title`,`icon`,`condition`,`remark`,`menu_type`,`weigh`,`status`,`always_show`,`path`,`jump_path`,`component`,`is_frame`,`module_type`,`model_id`,`created_at`,`updated_at`,`deleted_at` )
+VALUES(@parentId,'{{.table.ModuleName}}/{{.table.BusinessName | CaseCamelLower}}/list','{{.table.FunctionName}}列表','list','','{{.table.FunctionName}}列表',1,0,1,1,'{{.table.BusinessName | CaseCamelLower}}List','','{{.table.ModuleName}}/{{.table.BusinessName | CaseCamelLower}}/list',0,'sys_admin',0,@now,@now,NULL );
+
+-- 按钮父目录ID
+SELECT @parentId := LAST_INSERT_ID();
+
+-- 按钮 SQL
+INSERT INTO `sys_auth_rule` (`pid`,`name`,`title`,`icon`,`condition`,`remark`,`menu_type`,`weigh`,`status`,`always_show`,`path`,`jump_path`,`component`,`is_frame`,`module_type`,`model_id`,`created_at`,`updated_at`,`deleted_at` )
+VALUES(@parentId,'{{.table.ModuleName}}/{{.table.BusinessName | CaseCamelLower}}/get','{{.table.FunctionName}}查询','','','{{.table.FunctionName}}查询',2,0,1,1,'','','',0,'sys_admin',0,@now,@now,NULL );
+
+INSERT INTO `sys_auth_rule` (`pid`,`name`,`title`,`icon`,`condition`,`remark`,`menu_type`,`weigh`,`status`,`always_show`,`path`,`jump_path`,`component`,`is_frame`,`module_type`,`model_id`,`created_at`,`updated_at`,`deleted_at` )
+VALUES(@parentId,'{{.table.ModuleName}}/{{.table.BusinessName | CaseCamelLower}}/add','{{.table.FunctionName}}添加','','','{{.table.FunctionName}}添加',2,0,1,1,'','','',0,'sys_admin',0,@now,@now,NULL );
+
+INSERT INTO `sys_auth_rule` (`pid`,`name`,`title`,`icon`,`condition`,`remark`,`menu_type`,`weigh`,`status`,`always_show`,`path`,`jump_path`,`component`,`is_frame`,`module_type`,`model_id`,`created_at`,`updated_at`,`deleted_at` )
+VALUES(@parentId,'{{.table.ModuleName}}/{{.table.BusinessName | CaseCamelLower}}/edit','{{.table.FunctionName}}修改','','','{{.table.FunctionName}}修改',2,0,1,1,'','','',0,'sys_admin',0,@now,@now,NULL );
+
+INSERT INTO `sys_auth_rule` (`pid`,`name`,`title`,`icon`,`condition`,`remark`,`menu_type`,`weigh`,`status`,`always_show`,`path`,`jump_path`,`component`,`is_frame`,`module_type`,`model_id`,`created_at`,`updated_at`,`deleted_at` )
+VALUES(@parentId,'{{.table.ModuleName}}/{{.table.BusinessName | CaseCamelLower}}/delete','{{.table.FunctionName}}删除','','','{{.table.FunctionName}}删除',2,0,1,1,'','','',0,'sys_admin',0,@now,@now,NULL );
+
+{{range $index,$column:= .table.Columns}}
+{{if and (HasSuffix $column.ColumnName "status") (eq $column.IsList "1") }}
+INSERT INTO `sys_auth_rule` (`pid`,`name`,`title`,`icon`,`condition`,`remark`,`menu_type`,`weigh`,`status`,`always_show`,`path`,`jump_path`,`component`,`is_frame`,`module_type`,`model_id`,`created_at`,`updated_at`,`deleted_at` )
+VALUES(@parentId,'{{$.table.ModuleName}}/{{$.table.BusinessName | CaseCamelLower}}/change{{$column.GoField}}','{{$.table.FunctionName}}{{$column.ColumnComment}}修改','','','{{$.table.FunctionName}}{{$column.ColumnComment}}修改',2,0,1,1,'','','',0,'sys_admin',0,@now,@now,NULL );
+{{end}}
+{{end}}

+ 492 - 0
template/vm/vue/list-vue.template

@@ -0,0 +1,492 @@
+<template>
+{{$lens := .table.Columns|len}}
+{{$businessName := .table.BusinessName | CaseCamelLower}}
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
+    {{range $index, $column := .table.Columns}}
+    {{if and (eq $column.IsQuery "1") (ne $column.ColumnName "created_by") (ne $column.ColumnName "updated_by") (ne $column.ColumnName "created_at") (ne $column.ColumnName "updated_at") (ne $column.ColumnName "deleted_at")}}
+    {{if eq $column.HtmlType "input"}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+        <el-input
+            v-model="queryParams.{{$column.HtmlField}}"
+            placeholder="请输入{{$column.ColumnComment}}"
+            clearable
+            size="small"
+            @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      {{else if and (eq $column.HtmlType "select" "radio" "checkbox") (ne $column.DictType "") }}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+        <el-select v-model="queryParams.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable size="small">
+            <el-option
+                v-for="dict in {{$column.HtmlField}}Options"
+                :key="dict.key"
+                :label="dict.value"
+                :value="dict.key"
+            />
+        </el-select>
+      </el-form-item>
+      {{else if eq $column.HtmlType "datetime"}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+        <el-date-picker
+            clearable size="small" style="width: 200px"
+            v-model="queryParams.{{$column.HtmlField}}"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择{{$column.ColumnComment}}">
+        </el-date-picker>
+      </el-form-item>
+      {{else if and (eq $column.HtmlType "select" "radio" "checkbox") (ne $column.LinkTableName "")}}
+        <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+          <el-select v-model="queryParams.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable size="small">
+              <el-option
+                  v-for="item in {{$column.HtmlField}}Options"
+                  :key="item.key"
+                  :label="item.value"
+                  :value="item.key"
+              />
+          </el-select>
+        </el-form-item>
+        {{else}}
+        <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+          <el-select v-model="queryParams.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable size="small">
+              <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+      {{end}}
+      {{end}}
+      {{end}}
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['{{.table.ModuleName}}/{{$businessName}}/add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['{{.table.ModuleName}}/{{$businessName}}/edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['{{.table.ModuleName}}/{{$businessName}}/delete']"
+        >删除</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="{{$businessName}}List" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      {{range $index, $column := .table.Columns}}
+      {{if eq $column.IsPk "1"}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center" prop="{{$column.HtmlField}}" />
+      {{else if and (eq $column.IsList "1") (eq $column.HtmlType "datetime")}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center" prop="{{$column.HtmlField}}" width="180">
+        <template slot-scope="scope">
+            <span>{{VueTag "{{"}} parseTime(scope.row.{{$column.HtmlField}}, {y}-{m}-{d}) {{VueTag "}}"}}</span>
+        </template>
+      </el-table-column>
+      {{else if and (eq $column.IsList "1") (HasSuffix $column.ColumnName "status")}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center">
+        <template slot-scope="scope">
+            <el-switch
+              v-model="scope.row.{{$column.HtmlField}}"
+              :active-value="1"
+              :inactive-value="0"
+              @change="{{$column.HtmlField}}Change(scope.row)"
+            ></el-switch>
+        </template>
+      </el-table-column>
+      {{else if ne $column.LinkTableName ""}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center" prop="{{$column.HtmlField}}" :formatter="{{$column.HtmlField}}Format" width="100">
+        <template slot-scope="scope">
+          {{VueTag "{{" }} {{$column.HtmlField}}Format(scope.row) {{VueTag "}}" }}
+        </template>
+      </el-table-column>
+      {{else if and (eq $column.IsList "1") (ne $column.DictType "")}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center" prop="{{$column.HtmlField}}" :formatter="{{$column.HtmlField}}Format" />
+      {{else if and (eq $column.IsList "1") (ne $column.HtmlField "")}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center" prop="{{$column.HtmlField}}" />
+      {{end}}{{end}}
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['{{.table.ModuleName}}/{{$businessName}}/edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['{{.table.ModuleName}}/{{$businessName}}/delete']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改{{.table.FunctionName}}对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body :close-on-click-modal="false">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+      {{range $index, $column := .table.Columns}}
+      {{if and (eq $column.IsInsert "1") (ne $column.IsPk "1")}}
+      {{if eq $column.HtmlType "input"}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-input v-model="form.{{$column.HtmlField}}" placeholder="请输入{{$column.ColumnComment}}" />
+      </el-form-item>
+      {{else if eq $column.HtmlType "select" }}
+      {{if ne $column.LinkTableName ""}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+          <el-select v-model="form.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}">
+              <el-option
+                  v-for="item in {{$column.HtmlField}}Options"
+                  :key="item.key"
+                  :label="item.value"
+                  :value="item.key"
+              ></el-option>
+          </el-select>
+      </el-form-item>
+      {{else if ne $column.DictType ""}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+          <el-select v-model="form.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}">
+              <el-option
+                  v-for="dict in {{$column.HtmlField}}Options"
+                  :key="dict.key"
+                  :label="dict.value"
+                  {{if eq $column.GoType "Integer"}}
+                  :value="parseInt(dict.key)"
+                  {{else}}
+                      :value="dict.key"
+                  {{end}}
+              ></el-option>
+          </el-select>
+      </el-form-item>
+      {{else}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+          <el-select v-model="form.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}">
+              <el-option label="请选择字典生成" value="" />
+          </el-select>
+      </el-form-item>
+      {{end}}
+      {{else if eq $column.HtmlType "radio" }}
+      {{if ne $column.DictType ""}}
+       <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-radio-group v-model="form.{{$column.HtmlField}}">
+               <el-radio
+                v-for="dict in {{$column.HtmlField}}Options"
+                :key="dict.key"
+                :label="dict.key"
+               >{{ VueTag "{{" }}dict.value {{VueTag "}}"}}</el-radio>
+           </el-radio-group>
+       </el-form-item>
+       {{else}}
+       <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-radio-group v-model="form.{{$column.HtmlField}}">
+               <el-radio label="1">请选择字典生成</el-radio>
+           </el-radio-group>
+       </el-form-item>
+       {{end}}
+       {{else if eq $column.HtmlType "datetime"}}
+       <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-date-picker clearable size="small" style="width: 200px"
+               v-model="form.{{$column.HtmlField}}"
+               type="date"
+               value-format="yyyy-MM-dd"
+               placeholder="选择{{$column.ColumnComment}}">
+           </el-date-picker>
+       </el-form-item>
+       {{else if eq $column.HtmlType "textarea"}}
+       <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-input v-model="form.{{$column.HtmlField}}" type="textarea" placeholder="请输入内容" />
+       </el-form-item>
+       {{else if eq $column.HtmlType "checkbox" }}
+        <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-checkbox-group v-model="form.{{$column.HtmlField}}">
+              <el-checkbox
+                v-for="dict in {{$column.HtmlField}}Options"
+                :key="dict.key"
+                :label="dict.key"
+              >{{ VueTag "{{" }}dict.value {{VueTag "}}"}}</el-checkbox>
+           </el-checkbox-group>
+        </el-form-item>
+       {{end}}
+       {{end}}
+       {{end}}
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+    list{{.table.ClassName}},
+    get{{.table.ClassName}},
+    del{{.table.ClassName}},
+    add{{.table.ClassName}},
+    update{{.table.ClassName}},
+    {{range $index,$column:= .table.Columns}}
+    {{if and (HasSuffix $column.ColumnName "status") (eq $column.IsList "1") }}
+    change{{$.table.ClassName}}{{$column.GoField}},
+    {{end}}
+    {{if ne $column.LinkTableName ""}}
+    list{{$column.LinkTableClass}},
+    {{end}}
+    {{end}}
+} from "@/api/{{.table.ModuleName}}/{{$businessName}}";
+
+export default {
+  name: "{{.table.ClassName}}",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 总条数
+      total: 0,
+      // {{.table.FunctionName}}表格数据
+      {{$businessName}}List: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      {{range $index, $column := .table.Columns}}
+      {{if ne $column.DictType ""}}
+      // {{$column.HtmlField}}Options字典数据
+      {{$column.HtmlField}}Options: [],
+      {{else if ne $column.LinkTableName ""}}
+      // {{$column.HtmlField}}Options关联表数据
+      {{$column.HtmlField}}Options: [],
+      {{end}}
+      {{end}}
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,{{range $index, $column := .table.Columns}}{{if eq $column.IsQuery "1"}}
+        {{$column.HtmlField}}: undefined{{if ne $lens $index}},{{end}}{{end}}{{end}}
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: { {{range $index, $column := .table.Columns}}{{if eq $column.IsRequired "1"}}
+        {{$column.HtmlField}} : [
+          { required: true, message: "{{$column.ColumnComment}}不能为空", trigger: "blur" }
+        ]{{if ne $lens $index}},{{end}}{{end}}{{end}}
+      }
+    };
+  },
+  created() {
+    {{range $index, $column := .table.Columns}}
+    {{if ne $column.DictType ""}}
+    this.getDicts("{{$column.DictType}}").then(response => {
+      this.{{$column.HtmlField}}Options = response.data.values||[];
+    });
+    {{else if ne $column.LinkTableName ""}}
+    this.get{{$column.LinkTableClass}}Items()
+    {{end}}
+    {{end}}
+
+    this.getList();
+  },
+  methods: {
+    {{range $index, $column := .table.Columns}}
+    {{if ne $column.LinkTableName ""}}
+    //关联{{$column.LinkTableName}}表选项
+    get{{$column.LinkTableClass}}Items() {
+      this.getItems(list{{$column.LinkTableClass}}, {pageSize:10000}).then(res => {
+        this.{{$column.HtmlField}}Options = this.setItems(res, '{{$column.LinkLabelId}}', '{{$column.LinkLabelName}}')
+      })
+    },
+    {{else if and (HasSuffix $column.ColumnName "status") (eq $column.IsList "1")}}
+    // {{$column.ColumnComment}}修改
+    {{$column.HtmlField}}Change(row) {
+      let text = row.{{$column.HtmlField}} === 1 ? "启用" : "停用";
+      this.$confirm('确认要"' + text + '":吗?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return change{{$.table.ClassName}}{{$column.GoField}}(row.{{$.table.PkColumn.ColumnName}}, row.{{$column.HtmlField}});
+        }).then(() => {
+          this.msgSuccess(text + "成功");
+        }).catch(function() {
+          row.userStatus =row.userStatus === 0 ?1 : 0;
+        });
+    },
+    {{end}}
+    {{end}}
+    /** 查询{{.table.FunctionName}}列表 */
+    getList() {
+      this.loading = true;
+      list{{.table.ClassName}}(this.queryParams).then(response => {
+        this.{{$businessName}}List = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    {{range $index, $column := .table.Columns}}
+    {{if ne $column.DictType ""}}
+    {{if eq $column.HtmlType "checkbox"}}
+    // {{$column.ColumnComment}}字典翻译
+    {{$column.HtmlField}}Format(row, column) {
+      let {{$column.HtmlField}} = row.{{$column.HtmlField}}.split(",")
+      let data = [];
+      {{$column.HtmlField}}.map(item=>{
+        data.push(this.selectDictLabel(this.{{$column.HtmlField}}Options, item))
+      })
+      return data.join(",")
+    },
+    {{else}}
+    // {{$column.ColumnComment}}字典翻译
+    {{$column.HtmlField}}Format(row, column) {
+      return this.selectDictLabel(this.{{$column.HtmlField}}Options, row.{{$column.HtmlField}});
+    },
+    {{end}}
+    {{else if ne $column.LinkTableName ""}}
+    // {{$column.ColumnComment}}关联表翻译
+    {{$column.HtmlField}}Format(row, column) {
+      return this.selectItemsLabel(this.{{$column.HtmlField}}Options, row.{{$column.HtmlField}});
+    },
+    {{end}}
+    {{end}}
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        {{range $index, $column := .table.Columns}}
+        {{if eq $column.HtmlType "radio"}}
+        {{$column.HtmlField}}: "0" {{if ne $lens $index}},{{end}}
+        {{else if eq $column.HtmlType "checkbox"}}
+        {{$column.HtmlField}}: [] {{if ne $lens $index}},{{end}}
+        {{else}}
+        {{$column.HtmlField}}: undefined{{if ne $lens $index}},{{end}}{{end}}{{end}}
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.{{.table.PkColumn.HtmlField}})
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加{{.table.FunctionName}}";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const {{.table.PkColumn.HtmlField}} = row.{{.table.PkColumn.HtmlField}} || this.ids
+      get{{.table.ClassName}}({{.table.PkColumn.HtmlField}}).then(response => {
+        let data = response.data;
+        {{range $index, $column := .table.Columns}}
+        {{if eq $column.HtmlType "checkbox"}}
+        data.{{$column.HtmlField}} = data.{{$column.HtmlField}}.split(",")
+        {{else if eq $column.HtmlType "radio" "select"}}
+        data.{{$column.HtmlField}} = ''+data.{{$column.HtmlField}}
+        {{end}}
+        {{end}}
+        this.form = data;
+        this.open = true;
+        this.title = "修改{{.table.FunctionName}}";
+      });
+    },
+    /** 提交按钮 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.{{.table.PkColumn.HtmlField}} != undefined) {
+            update{{.table.ClassName}}(this.form).then(response => {
+              if (response.code === 0) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          } else {
+            add{{.table.ClassName}}(this.form).then(response => {
+              if (response.code === 0) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const {{.table.PkColumn.HtmlField}}s = row.{{.table.PkColumn.HtmlField}} || this.ids;
+      this.$confirm('是否确认删除{{.table.FunctionName}}编号为"' + {{.table.PkColumn.HtmlField}}s + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return del{{.table.ClassName}}({{.table.PkColumn.HtmlField}}s);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    }
+  }
+};
+</script>

+ 522 - 0
template/vm/vue/tree-vue.template

@@ -0,0 +1,522 @@
+<template>
+{{$lens := .table.Columns|len}}
+{{$businessName := .table.BusinessName | CaseCamelLower}}
+{{$treeParentCode := .table.TreeParentCode}}
+{{$treeCode := .table.TreeCode}}
+{{$treeName := .table.TreeName}}
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
+    {{range $index, $column := .table.Columns}}
+    {{if and (eq $column.IsQuery "1") (ne $column.ColumnName "created_by") (ne $column.ColumnName "updated_by") (ne $column.ColumnName "created_at") (ne $column.ColumnName "updated_at") (ne $column.ColumnName "deleted_at")}}
+    {{if eq $column.HtmlType "input"}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+        <el-input
+            v-model="queryParams.{{$column.HtmlField}}"
+            placeholder="请输入{{$column.ColumnComment}}"
+            clearable
+            size="small"
+            @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      {{else if and (eq $column.HtmlType "select" "radio" "checkbox") (ne $column.DictType "") }}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+        <el-select v-model="queryParams.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable size="small">
+            <el-option
+                v-for="dict in {{$column.HtmlField}}Options"
+                :key="dict.key"
+                :label="dict.value"
+                :value="dict.key"
+            />
+        </el-select>
+      </el-form-item>
+      {{else if eq $column.HtmlType "datetime"}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+        <el-date-picker
+            clearable size="small" style="width: 200px"
+            v-model="queryParams.{{$column.HtmlField}}"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择{{$column.ColumnComment}}">
+        </el-date-picker>
+      </el-form-item>
+      {{else if and (eq $column.HtmlType "select" "radio" "checkbox") (ne $column.LinkTableName "")}}
+        <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+          <el-select v-model="queryParams.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable size="small">
+              <el-option
+                  v-for="item in {{$column.HtmlField}}Options"
+                  :key="item.key"
+                  :label="item.value"
+                  :value="item.key"
+              />
+          </el-select>
+        </el-form-item>
+        {{else}}
+        <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+          <el-select v-model="queryParams.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable size="small">
+              <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+      {{end}}
+      {{end}}
+      {{end}}
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['{{.table.ModuleName}}/{{$businessName}}/add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['{{.table.ModuleName}}/{{$businessName}}/edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['{{.table.ModuleName}}/{{$businessName}}/delete']"
+        >删除</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="{{$businessName}}List"
+        @selection-change="handleSelectionChange"
+        row-key="{{$treeCode}}"
+        default-expand-all
+        :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+      <el-table-column type="selection" width="55" align="center" />
+      {{range $index, $column := .table.Columns}}
+      {{if eq $column.IsPk "1"}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center" prop="{{$column.HtmlField}}" />
+      {{else if and (eq $column.IsList "1") (eq $column.HtmlType "datetime")}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center" prop="{{$column.HtmlField}}" width="180">
+        <template slot-scope="scope">
+            <span>{{VueTag "{{"}} parseTime(scope.row.{{$column.HtmlField}}, {y}-{m}-{d}) {{VueTag "}}"}}</span>
+        </template>
+      </el-table-column>
+      {{else if and (eq $column.IsList "1") (HasSuffix $column.ColumnName "status")}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center">
+        <template slot-scope="scope">
+            <el-switch
+              v-model="scope.row.{{$column.HtmlField}}"
+              :active-value="1"
+              :inactive-value="0"
+              @change="{{$column.HtmlField}}Change(scope.row)"
+            ></el-switch>
+        </template>
+      </el-table-column>
+      {{else if ne $column.LinkTableName ""}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center" prop="{{$column.HtmlField}}" :formatter="{{$column.HtmlField}}Format" width="100">
+        <template slot-scope="scope">
+          {{VueTag "{{" }} {{$column.HtmlField}}Format(scope.row) {{VueTag "}}" }}
+        </template>
+      </el-table-column>
+      {{else if and (eq $column.IsList "1") (ne $column.DictType "")}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center" prop="{{$column.HtmlField}}" :formatter="{{$column.HtmlField}}Format" />
+      {{else if and (eq $column.IsList "1") (ne $column.HtmlField "")}}
+      <el-table-column label="{{$column.ColumnComment}}" align="center" prop="{{$column.HtmlField}}" />
+      {{end}}{{end}}
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['{{.table.ModuleName}}/{{$businessName}}/edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['{{.table.ModuleName}}/{{$businessName}}/delete']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 添加或修改{{.table.FunctionName}}对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body :close-on-click-modal="false">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+      {{range $index, $column := .table.Columns}}
+      {{if and (eq $column.IsInsert "1") (ne $column.IsPk "1")}}
+      {{if and (ne $treeParentCode "") (eq $column.HtmlField $treeParentCode)}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$treeParentCode}}">
+      <treeselect v-model="form.{{$treeParentCode}}" :options="{{$businessName}}Options" :normalizer="normalizer" placeholder="请选择{{$column.ColumnComment}}" />
+      </el-form-item>
+      {{else if eq $column.HtmlType "input"}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-input v-model="form.{{$column.HtmlField}}" placeholder="请输入{{$column.ColumnComment}}" />
+      </el-form-item>
+      {{else if eq $column.HtmlType "select" }}
+      {{if ne $column.LinkTableName ""}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+          <el-select v-model="form.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}">
+              <el-option
+                  v-for="item in {{$column.HtmlField}}Options"
+                  :key="item.key"
+                  :label="item.value"
+                  :value="item.key"
+              ></el-option>
+          </el-select>
+      </el-form-item>
+      {{else if ne $column.DictType ""}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+          <el-select v-model="form.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}">
+              <el-option
+                  v-for="dict in {{$column.HtmlField}}Options"
+                  :key="dict.key"
+                  :label="dict.value"
+                  {{if eq $column.GoType "Integer"}}
+                  :value="parseInt(dict.key)"
+                  {{else}}
+                      :value="dict.key"
+                  {{end}}
+              ></el-option>
+          </el-select>
+      </el-form-item>
+      {{else}}
+      <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+          <el-select v-model="form.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}">
+              <el-option label="请选择字典生成" value="" />
+          </el-select>
+      </el-form-item>
+      {{end}}
+      {{else if eq $column.HtmlType "radio" }}
+      {{if ne $column.DictType ""}}
+       <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-radio-group v-model="form.{{$column.HtmlField}}">
+               <el-radio
+                v-for="dict in {{$column.HtmlField}}Options"
+                :key="dict.key"
+                :label="dict.key"
+               >{{ VueTag "{{" }}dict.value {{VueTag "}}"}}</el-radio>
+           </el-radio-group>
+       </el-form-item>
+       {{else}}
+       <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-radio-group v-model="form.{{$column.HtmlField}}">
+               <el-radio label="1">请选择字典生成</el-radio>
+           </el-radio-group>
+       </el-form-item>
+       {{end}}
+       {{else if eq $column.HtmlType "datetime"}}
+       <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-date-picker clearable size="small" style="width: 200px"
+               v-model="form.{{$column.HtmlField}}"
+               type="date"
+               value-format="yyyy-MM-dd"
+               placeholder="选择{{$column.ColumnComment}}">
+           </el-date-picker>
+       </el-form-item>
+       {{else if eq $column.HtmlType "textarea"}}
+       <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-input v-model="form.{{$column.HtmlField}}" type="textarea" placeholder="请输入内容" />
+       </el-form-item>
+       {{else if eq $column.HtmlType "checkbox" }}
+        <el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
+           <el-checkbox-group v-model="form.{{$column.HtmlField}}">
+              <el-checkbox
+                v-for="dict in {{$column.HtmlField}}Options"
+                :key="dict.key"
+                :label="dict.key"
+              >{{ VueTag "{{" }}dict.value {{VueTag "}}"}}</el-checkbox>
+           </el-checkbox-group>
+        </el-form-item>
+       {{end}}
+       {{end}}
+       {{end}}
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+    list{{.table.ClassName}},
+    get{{.table.ClassName}},
+    del{{.table.ClassName}},
+    add{{.table.ClassName}},
+    update{{.table.ClassName}},
+    {{range $index,$column:= .table.Columns}}
+    {{if and (HasSuffix $column.ColumnName "status") (eq $column.IsList "1") }}
+    change{{$.table.ClassName}}{{$column.GoField}},
+    {{end}}
+    {{if ne $column.LinkTableName ""}}
+    list{{$column.LinkTableClass}},
+    {{end}}
+    {{end}}
+} from "@/api/{{.table.ModuleName}}/{{$businessName}}";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "{{.table.ClassName}}",
+  components: { Treeselect },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 总条数
+      total: 0,
+      // {{.table.FunctionName}}表格数据
+      {{$businessName}}List: [],
+      // {{.table.FunctionName}}树选项
+      {{$businessName}}Options: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      {{range $index, $column := .table.Columns}}
+      {{if ne $column.DictType ""}}
+      // {{$column.HtmlField}}Options字典数据
+      {{$column.HtmlField}}Options: [],
+      {{else if ne $column.LinkTableName ""}}
+      // {{$column.HtmlField}}Options关联表数据
+      {{$column.HtmlField}}Options: [],
+      {{end}}
+      {{end}}
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,{{range $index, $column := .table.Columns}}{{if eq $column.IsQuery "1"}}
+        {{$column.HtmlField}}: undefined{{if ne $lens $index}},{{end}}{{end}}{{end}}
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: { {{range $index, $column := .table.Columns}}{{if eq $column.IsRequired "1"}}
+        {{$column.HtmlField}} : [
+          { required: true, message: "{{$column.ColumnComment}}不能为空", trigger: "blur" }
+        ]{{if ne $lens $index}},{{end}}{{end}}{{end}}
+      }
+    };
+  },
+  created() {
+    {{range $index, $column := .table.Columns}}
+    {{if ne $column.DictType ""}}
+    this.getDicts("{{$column.DictType}}").then(response => {
+      this.{{$column.HtmlField}}Options = response.data.values||[];
+    });
+    {{else if ne $column.LinkTableName ""}}
+    this.get{{$column.LinkTableClass}}Items()
+    {{end}}
+    {{end}}
+
+    this.getList();
+  },
+  methods: {
+    {{range $index, $column := .table.Columns}}
+    {{if ne $column.LinkTableName ""}}
+    //关联{{$column.LinkTableName}}表选项
+    get{{$column.LinkTableClass}}Items() {
+      this.getItems(list{{$column.LinkTableClass}}, {pageSize:10000}).then(res => {
+        this.{{$column.HtmlField}}Options = this.setItems(res, '{{$column.LinkLabelId}}', '{{$column.LinkLabelName}}')
+      })
+    },
+    {{else if and (HasSuffix $column.ColumnName "status") (eq $column.IsList "1")}}
+    // {{$column.ColumnComment}}修改
+    {{$column.HtmlField}}Change(row) {
+      let text = row.{{$column.HtmlField}} === 1 ? "启用" : "停用";
+      this.$confirm('确认要"' + text + '":吗?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return change{{$.table.ClassName}}{{$column.GoField}}(row.{{$.table.PkColumn.ColumnName}}, row.{{$column.HtmlField}});
+        }).then(() => {
+          this.msgSuccess(text + "成功");
+        }).catch(function() {
+          row.userStatus =row.userStatus === 0 ?1 : 0;
+        });
+    },
+    {{end}}
+    {{end}}
+    /** 查询{{.table.FunctionName}}列表 */
+    getList() {
+      this.loading = true;
+      list{{.table.ClassName}}(this.queryParams).then(response => {
+        this.{{$businessName}}List = this.handleTree(response.data.list||[], "{{$treeCode}}", "{{$treeParentCode}}");
+        this.loading = false;
+      });
+    },
+    /** 转换{{.table.FunctionName}}数据结构 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.{{$treeCode}},
+        label: node.{{$treeName}},
+        children: node.children
+      };
+    },
+    /** 查询{{.table.FunctionName}}下拉树结构 */
+    getTreeselect() {
+      list{{.table.ClassName}}(this.queryParams).then(response => {
+        this.{{$businessName}}Options = [];
+        const data = { {{$treeCode}}: 0, {{$treeName}}: '顶级节点', children: [] };
+        data.children = this.handleTree(response.data.list||[], "{{$treeCode}}", "{{$treeParentCode}}");
+        this.{{$businessName}}Options.push(data);
+      });
+    },
+    {{range $index, $column := .table.Columns}}
+    {{if ne $column.DictType ""}}
+    {{if eq $column.HtmlType "checkbox"}}
+    // {{$column.ColumnComment}}字典翻译
+    {{$column.HtmlField}}Format(row, column) {
+      let {{$column.HtmlField}} = row.{{$column.HtmlField}}.split(",")
+      let data = [];
+      {{$column.HtmlField}}.map(item=>{
+        data.push(this.selectDictLabel(this.{{$column.HtmlField}}Options, item))
+      })
+      return data.join(",")
+    },
+    {{else}}
+    // {{$column.ColumnComment}}字典翻译
+    {{$column.HtmlField}}Format(row, column) {
+      return this.selectDictLabel(this.{{$column.HtmlField}}Options, row.{{$column.HtmlField}});
+    },
+    {{end}}
+    {{else if ne $column.LinkTableName ""}}
+    // {{$column.ColumnComment}}关联表翻译
+    {{$column.HtmlField}}Format(row, column) {
+      return this.selectItemsLabel(this.{{$column.HtmlField}}Options, row.{{$column.HtmlField}});
+    },
+    {{end}}
+    {{end}}
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        {{range $index, $column := .table.Columns}}
+        {{if eq $column.HtmlType "radio"}}
+        {{$column.HtmlField}}: "0" {{if ne $lens $index}},{{end}}
+        {{else if eq $column.HtmlType "checkbox"}}
+        {{$column.HtmlField}}: [] {{if ne $lens $index}},{{end}}
+        {{else}}
+        {{$column.HtmlField}}: undefined{{if ne $lens $index}},{{end}}{{end}}{{end}}
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.{{.table.PkColumn.HtmlField}})
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.getTreeselect()
+      this.open = true;
+      this.title = "添加{{.table.FunctionName}}";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      this.getTreeselect()
+      const {{.table.PkColumn.HtmlField}} = row.{{.table.PkColumn.HtmlField}} || this.ids
+      get{{.table.ClassName}}({{.table.PkColumn.HtmlField}}).then(response => {
+        let data = response.data;
+        {{range $index, $column := .table.Columns}}
+        {{if eq $column.HtmlType "checkbox"}}
+        data.{{$column.HtmlField}} = data.{{$column.HtmlField}}.split(",")
+        {{else if eq $column.HtmlType "radio" "select"}}
+        data.{{$column.HtmlField}} = ''+data.{{$column.HtmlField}}
+        {{end}}
+        {{end}}
+        this.form = data;
+        this.open = true;
+        this.title = "修改{{.table.FunctionName}}";
+      });
+    },
+    /** 提交按钮 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.{{.table.PkColumn.HtmlField}} != undefined) {
+            update{{.table.ClassName}}(this.form).then(response => {
+              if (response.code === 0) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          } else {
+            add{{.table.ClassName}}(this.form).then(response => {
+              if (response.code === 0) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const {{.table.PkColumn.HtmlField}}s = row.{{.table.PkColumn.HtmlField}} || this.ids;
+      this.$confirm('是否确认删除{{.table.FunctionName}}编号为"' + {{.table.PkColumn.HtmlField}}s + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return del{{.table.ClassName}}({{.table.PkColumn.HtmlField}}s);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    }
+  }
+};
+</script>

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini