2021-06-03 19:03:48 +00:00
package code
import (
2022-03-12 17:12:29 +00:00
. "code.hoteas.com/golang/hotime/common"
"code.hoteas.com/golang/hotime/db"
2021-06-03 19:03:48 +00:00
"errors"
2021-06-04 02:04:37 +00:00
"fmt"
2021-06-03 19:03:48 +00:00
"io/ioutil"
"net/http"
"os"
"path/filepath"
2022-03-12 21:06:28 +00:00
"sort"
2021-06-04 02:04:37 +00:00
"strings"
2021-09-15 20:33:10 +00:00
"time"
2021-06-03 19:03:48 +00:00
)
type MakeCode struct {
2022-03-12 21:06:28 +00:00
FileConfig Map
2021-06-12 05:33:35 +00:00
IndexMenus Map
TableConfig Map
TableColumns map [ string ] map [ string ] Map
SearchColumns map [ string ] map [ string ] Map
Config Map
2022-03-12 21:06:28 +00:00
RuleConfig [ ] Map
2021-06-03 19:03:48 +00:00
Error
}
2022-03-12 21:06:28 +00:00
func ( that * MakeCode ) Db2JSON ( db * db . HoTimeDB , config Map ) {
2021-06-04 18:18:56 +00:00
isMake := false
idSlice := Slice { }
2022-03-12 21:06:28 +00:00
that . FileConfig = config
2021-06-03 19:03:48 +00:00
if that . TableColumns == nil {
that . TableColumns = make ( map [ string ] map [ string ] Map )
}
2021-06-12 05:33:35 +00:00
if that . SearchColumns == nil {
that . SearchColumns = make ( map [ string ] map [ string ] Map )
}
2021-06-03 19:03:48 +00:00
//加载配置文件
2022-03-12 21:06:28 +00:00
btes , err := ioutil . ReadFile ( config . GetString ( "config" ) )
2021-06-03 19:03:48 +00:00
that . Config = DeepCopyMap ( Config ) . ( Map )
2022-03-12 21:06:28 +00:00
that . Config [ "name" ] = config . GetString ( "table" )
2021-06-03 19:03:48 +00:00
if err == nil {
cmap := Map { }
//文件是否损坏
cmap . JsonToMap ( string ( btes ) , & that . Error )
for k , v := range cmap {
that . Config [ k ] = v //程序配置
2022-03-12 21:06:28 +00:00
//Config[k] = v //系统配置
}
} else {
that . Error . SetError ( errors . New ( "config配置文件不存在, 或者配置出错, 使用缺省默认配置" ) )
}
//加载规则文件
btesRule , errRule := ioutil . ReadFile ( config . GetString ( "rule" ) )
that . RuleConfig = [ ] Map { }
if errRule == nil {
//cmap := Map{}
//文件是否损坏
ruleLis := ObjToSlice ( string ( btesRule ) , & that . Error )
//cmap.JSON()
for k , _ := range ruleLis {
that . RuleConfig = append ( that . RuleConfig , ruleLis . GetMap ( k ) )
2021-06-03 19:03:48 +00:00
}
} else {
2022-03-12 21:06:28 +00:00
for _ , v := range ColumnNameType {
that . RuleConfig = append ( that . RuleConfig , Map { "name" : v . Name , "list" : v . List , "edit" : v . Edit , "info" : v . Info , "must" : v . Must , "strict" : v . Strict , "type" : v . Type } )
}
2022-03-12 21:13:32 +00:00
if db != nil {
_ = os . MkdirAll ( filepath . Dir ( config . GetString ( "rule" ) ) , os . ModeDir )
err = ioutil . WriteFile ( config . GetString ( "rule" ) , [ ] byte ( ObjToStr ( that . RuleConfig ) ) , os . ModePerm )
if err != nil {
that . Error . SetError ( err )
}
}
2022-03-12 21:06:28 +00:00
that . Error . SetError ( errors . New ( "rule配置文件不存在, 或者配置出错, 使用缺省默认配置" ) )
2021-06-03 19:03:48 +00:00
}
2022-03-12 21:06:28 +00:00
2021-06-11 00:06:44 +00:00
that . IndexMenus = Map { }
menusConfig := that . Config . GetSlice ( "menus" )
//将配置写入到内存中仅作为判断用
if menusConfig != nil {
for kmenu , _ := range menusConfig {
menu := menusConfig . GetMap ( kmenu )
if menu != nil {
mname := menu . GetString ( "table" )
if mname == "" { //如果为空则不是表格
mname = menu . GetString ( "name" )
}
that . IndexMenus [ mname ] = menu
childMenus := menu . GetSlice ( "menus" )
if childMenus != nil {
for ckmenu , _ := range childMenus {
cmenu := childMenus . GetMap ( ckmenu )
if cmenu != nil {
cname := cmenu . GetString ( "table" )
if cmenu . GetString ( "table" ) == "" {
continue
}
that . IndexMenus [ mname + "/" + cname ] = cmenu
}
}
}
}
}
}
2021-06-05 23:50:58 +00:00
that . TableConfig = that . Config . GetMap ( "tables" )
if that . TableConfig == nil {
that . TableConfig = Map { }
}
for tableName , _ := range that . TableConfig {
columns := that . TableConfig . GetMap ( tableName ) . GetSlice ( "columns" )
2021-06-12 05:33:35 +00:00
search := that . TableConfig . GetMap ( tableName ) . GetSlice ( "search" )
2021-06-03 19:03:48 +00:00
//初始化
if that . TableColumns [ tableName ] == nil {
that . TableColumns [ tableName ] = map [ string ] Map { }
}
2021-06-12 05:33:35 +00:00
//初始化搜索项
if that . SearchColumns [ tableName ] == nil {
that . SearchColumns [ tableName ] = map [ string ] Map { }
}
2021-06-03 19:03:48 +00:00
//注入源数据
2021-06-05 23:50:58 +00:00
for index , _ := range columns {
columnsName := columns . GetMap ( index ) . GetString ( "name" )
that . TableColumns [ tableName ] [ columnsName ] = columns . GetMap ( index )
2021-06-03 19:03:48 +00:00
}
2021-06-12 05:33:35 +00:00
//注入search源数据
for index , _ := range search {
searchName := search . GetMap ( index ) . GetString ( "name" )
that . SearchColumns [ tableName ] [ searchName ] = search . GetMap ( index )
}
2021-06-03 19:03:48 +00:00
}
2021-09-15 20:33:10 +00:00
if db == nil {
2021-09-11 21:35:14 +00:00
return
}
//数据库反哺
2022-03-12 21:06:28 +00:00
myInit := strings . Replace ( InitTpt , "{{name}}" , config . GetString ( "table" ) , - 1 )
2021-06-04 02:04:37 +00:00
ctrList := ""
2021-06-04 18:18:56 +00:00
nowTables := make ( [ ] Map , 0 )
if db . Type == "mysql" {
nowTables = db . Select ( "INFORMATION_SCHEMA.TABLES" , "TABLE_NAME as name,TABLE_COMMENT as label" , Map { "TABLE_SCHEMA" : db . DBName } )
}
2021-06-03 19:03:48 +00:00
if db . Type == "sqlite" {
2021-06-04 18:18:56 +00:00
nowTables = db . Select ( "sqlite_sequence" , "name" )
}
//idSlice=append(idSlice,nowTables)
for _ , v := range nowTables {
2021-08-29 23:36:17 +00:00
if v . GetString ( "name" ) == "cached" {
continue
}
2021-06-04 18:18:56 +00:00
if that . TableConfig . GetMap ( v . GetString ( "name" ) ) == nil {
if v . GetString ( "label" ) == "" {
2021-06-11 00:06:44 +00:00
v [ "label" ] = v . GetString ( "name" )
2021-06-04 18:18:56 +00:00
}
that . TableConfig [ v . GetString ( "name" ) ] = Map {
"label" : v . GetString ( "label" ) ,
"table" : v . GetString ( "name" ) ,
2022-01-12 09:33:20 +00:00
"auth" : [ ] string { "show" , "add" , "delete" , "edit" , "info" } ,
2021-06-04 18:18:56 +00:00
"columns" : [ ] Map { } ,
"search" : [ ] Map {
2021-09-15 20:33:10 +00:00
2021-06-12 19:08:43 +00:00
{ "type" : "search" , "name" : "keyword" , "label" : "请输入关键词" , "value" : nil } ,
{ "type" : "search" , "name" : "daterange" , "label" : "时间段" , "value" : nil } ,
{ "type" : "search" , "name" : "sort" , "label" : "排序" , "value" : nil } ,
2021-06-04 18:18:56 +00:00
} ,
2021-06-03 19:03:48 +00:00
}
2021-06-04 18:18:56 +00:00
}
2021-09-15 20:33:10 +00:00
2021-06-04 18:18:56 +00:00
//初始化
if that . TableColumns [ v . GetString ( "name" ) ] == nil {
that . TableColumns [ v . GetString ( "name" ) ] = make ( map [ string ] Map )
}
2021-06-11 00:06:44 +00:00
2021-06-12 05:33:35 +00:00
//初始化
if that . SearchColumns [ v . GetString ( "name" ) ] == nil {
that . SearchColumns [ v . GetString ( "name" ) ] = make ( map [ string ] Map )
}
2021-06-04 18:18:56 +00:00
tableInfo := make ( [ ] Map , 0 )
if db . Type == "mysql" {
tableInfo = db . Select ( "INFORMATION_SCHEMA.COLUMNS" , "COLUMN_NAME AS name,COLUMN_TYPE AS type,COLUMN_COMMENT AS label" , Map { "AND" : Map { "TABLE_SCHEMA" : db . DBName , "TABLE_NAME" : v . GetString ( "name" ) } } )
}
if db . Type == "sqlite" {
tableInfo = db . Query ( "pragma table_info([" + v . GetString ( "name" ) + "]);" )
}
2021-06-03 19:03:48 +00:00
2021-06-04 18:18:56 +00:00
idSlice = append ( idSlice , tableInfo )
2022-01-16 20:47:39 +00:00
for _ , info1 := range tableInfo {
info := DeepCopyMap ( info1 ) . ( Map )
2021-06-04 18:18:56 +00:00
if info . GetString ( "label" ) == "" {
2021-06-11 00:06:44 +00:00
info [ "label" ] = info . GetString ( "name" )
2021-06-03 19:03:48 +00:00
}
2021-06-05 23:50:58 +00:00
coloum := that . TableColumns [ v . GetString ( "name" ) ] [ info . GetString ( "name" ) ]
2021-06-04 18:18:56 +00:00
2021-06-05 23:50:58 +00:00
if coloum == nil {
2021-06-07 03:32:47 +00:00
//根据类型判断真实类型
2021-09-15 20:33:10 +00:00
for k , v1 := range ColumnDataType {
if strings . Contains ( info . GetString ( "name" ) , k ) || strings . Contains ( info . GetString ( "type" ) , k ) {
info [ "type" ] = v1
2021-06-07 03:32:47 +00:00
}
}
2021-08-29 23:36:17 +00:00
2021-06-05 23:50:58 +00:00
coloum = Map {
2021-06-04 18:18:56 +00:00
"name" : info . GetString ( "name" ) ,
"type" : info . GetString ( "type" ) ,
"label" : info . GetString ( "label" ) ,
//"add": false, "info": false, "edit": false, "list": true,
2021-06-07 03:32:47 +00:00
//"must": false,
2021-06-04 18:18:56 +00:00
}
2022-01-16 20:47:39 +00:00
2021-06-12 05:33:35 +00:00
//备注以空格隔开,空格后的是其他备注
2022-01-16 20:47:39 +00:00
indexNum := strings . Index ( info . GetString ( "label" ) , " " )
if indexNum > - 1 {
2021-06-12 05:33:35 +00:00
coloum [ "label" ] = info . GetString ( "label" ) [ : indexNum ]
}
2022-01-16 20:47:39 +00:00
//去除数据信息,是用:号分割的
indexNum = strings . Index ( coloum . GetString ( "label" ) , ":" )
if indexNum > - 1 {
coloum [ "label" ] = coloum . GetString ( "label" ) [ : indexNum ]
}
2021-06-03 19:03:48 +00:00
2022-03-12 21:06:28 +00:00
for _ , ColumnName := range that . RuleConfig {
if ( ColumnName . GetBool ( "strict" ) && coloum . GetString ( "name" ) == ColumnName . GetString ( "name" ) ) ||
( ! ColumnName . GetBool ( "strict" ) && strings . Contains ( coloum . GetString ( "name" ) , ColumnName . GetString ( "name" ) ) ) {
2021-06-07 03:32:47 +00:00
//全部都不需要则不加入
2022-03-12 21:06:28 +00:00
if ColumnName . GetBool ( "edit" ) == false && ColumnName . GetBool ( "list" ) == false && ColumnName . GetBool ( "info" ) == false {
2021-06-07 03:32:47 +00:00
coloum [ "notUse" ] = true
2021-09-15 20:33:10 +00:00
//continue
2021-06-07 03:32:47 +00:00
}
2022-03-12 21:06:28 +00:00
coloum [ "info" ] = ColumnName . GetBool ( "info" )
coloum [ "edit" ] = ColumnName . GetBool ( "edit" )
coloum [ "add" ] = ColumnName . GetBool ( "edit" )
coloum [ "list" ] = ColumnName . GetBool ( "list" )
coloum [ "must" ] = ColumnName . GetBool ( "must" )
2021-09-15 20:33:10 +00:00
2022-03-12 21:06:28 +00:00
if ColumnName . GetBool ( "info" ) {
2021-09-15 20:33:10 +00:00
delete ( coloum , "info" )
2021-06-07 03:32:47 +00:00
}
2022-03-12 21:06:28 +00:00
if ColumnName . GetBool ( "edit" ) {
2021-09-15 20:33:10 +00:00
delete ( coloum , "edit" )
delete ( coloum , "add" )
2021-06-07 03:32:47 +00:00
}
2022-03-12 21:06:28 +00:00
if ColumnName . GetBool ( "list" ) {
2021-09-15 20:33:10 +00:00
delete ( coloum , "list" )
2021-06-07 03:32:47 +00:00
}
2022-03-26 08:53:40 +00:00
if ! ColumnName . GetBool ( "must" ) {
2021-09-15 20:33:10 +00:00
delete ( coloum , "must" )
2021-06-07 03:32:47 +00:00
}
2021-09-15 20:33:10 +00:00
2022-03-12 21:06:28 +00:00
if ColumnName . GetString ( "type" ) != "" {
2022-04-25 11:58:49 +00:00
if ColumnName . GetString ( "type" ) == "time" && coloum [ "type" ] == "number" {
coloum [ "type" ] = "unixTime"
} else {
coloum [ "type" ] = ColumnName . GetString ( "type" )
}
2021-06-07 03:32:47 +00:00
}
2022-03-12 21:06:28 +00:00
if ColumnName . GetBool ( "strict" ) && coloum . GetString ( "name" ) == ColumnName . GetString ( "name" ) {
2021-09-15 20:33:10 +00:00
break
}
2021-06-07 03:32:47 +00:00
}
}
2021-06-12 05:33:35 +00:00
2021-06-12 19:08:43 +00:00
//如果是select类型需要设置options
if coloum . GetString ( "type" ) == "number" {
coloum [ "sortable" ] = true
}
2021-09-15 20:33:10 +00:00
//if !coloum.GetBool("notUse") {
that . TableConfig . GetMap ( v . GetString ( "name" ) ) [ "columns" ] = append ( that . TableConfig . GetMap ( v . GetString ( "name" ) ) . GetSlice ( "columns" ) , coloum )
//}
2021-06-12 05:33:35 +00:00
//如果是select类型需要设置options
2021-07-13 16:48:34 +00:00
//if coloum.GetString("type") == "select" {
2021-06-12 05:33:35 +00:00
2021-07-13 16:48:34 +00:00
options := Slice { }
2021-08-28 05:05:12 +00:00
comments := strings . Split ( info . GetString ( "label" ) , ":" )
2021-07-13 16:48:34 +00:00
if len ( comments ) >= 2 {
optionComment := strings . Split ( comments [ 1 ] , "," )
for _ , v := range optionComment {
optionSlice := strings . Split ( v , "-" )
if len ( optionSlice ) >= 2 {
options = append ( options , Map { "name" : optionSlice [ 1 ] , "value" : optionSlice [ 0 ] } )
2021-06-12 05:33:35 +00:00
}
}
}
2021-07-13 16:48:34 +00:00
if coloum . GetString ( "type" ) == "select" {
2022-03-26 08:53:40 +00:00
//coloum["must"] = true
2021-07-13 16:48:34 +00:00
coloum [ "options" ] = options
} else if len ( options ) > 0 {
2022-03-26 08:53:40 +00:00
//coloum["must"] = true
2021-07-13 16:48:34 +00:00
coloum [ "options" ] = options
coloum [ "type" ] = "select"
2021-06-04 02:04:37 +00:00
}
2021-07-13 16:48:34 +00:00
//}
2021-06-04 02:04:37 +00:00
2021-06-07 03:32:47 +00:00
}
//else {
//
// //if !(coloum.GetString("label") != "备注" && info.GetString("label") == "备注") {
// // coloum["label"] = info.GetString("label")
// //}
// //coloum["type"] = info.GetString("type")
//}
//暂时不关闭参数,保证表数据完全读取到
2021-06-05 23:50:58 +00:00
that . TableColumns [ v . GetString ( "name" ) ] [ info . GetString ( "name" ) ] = coloum
2021-06-04 02:04:37 +00:00
2021-06-03 19:03:48 +00:00
}
2021-06-04 02:04:37 +00:00
2022-03-12 21:06:28 +00:00
if config . GetInt ( "mode" ) != 0 {
2021-12-27 12:40:16 +00:00
//创建模块文件
//判断文件是否存在
//_, err := os.OpenFile(name+"/"+v.GetString("name"), os.O_RDONLY, os.ModePerm)
2022-03-12 21:06:28 +00:00
_ , err := os . Stat ( config . GetString ( "name" ) + "/" + v . GetString ( "name" ) + ".go" )
2021-12-27 12:40:16 +00:00
if err != nil { //文件不存在,则根据模板创建
2022-03-12 21:06:28 +00:00
myCtr := strings . Replace ( CtrTpt , "{{name}}" , config . GetString ( "name" ) , - 1 )
2021-12-27 12:40:16 +00:00
myCtr = strings . Replace ( myCtr , "{{table}}" , v . GetString ( "name" ) , - 1 )
2022-03-12 21:06:28 +00:00
_ = os . MkdirAll ( config . GetString ( "name" ) , os . ModeDir )
err = ioutil . WriteFile ( config . GetString ( "name" ) + "/" + v . GetString ( "name" ) + ".go" , [ ] byte ( myCtr ) , os . ModePerm )
2021-12-27 12:40:16 +00:00
if err != nil {
that . Error . SetError ( err )
}
isMake = true
2021-06-03 19:03:48 +00:00
}
2021-06-04 02:04:37 +00:00
2021-12-27 12:40:16 +00:00
ctrList = ctrList + ` " ` + v . GetString ( "name" ) + ` ": ` + v . GetString ( "name" ) + "Ctr,\r\n "
}
2021-06-04 18:18:56 +00:00
}
2021-06-05 23:50:58 +00:00
that . Config [ "tables" ] = that . TableConfig
2021-06-04 18:18:56 +00:00
2021-06-07 03:32:47 +00:00
//生成id, 判断数据库是否有改变, 以保证数据库和配置文件匹配唯一
2021-06-04 18:18:56 +00:00
id := Md5 ( ObjToStr ( idSlice ) )
2021-06-04 02:04:37 +00:00
if id == that . Config . GetString ( "id" ) {
2021-06-04 18:18:56 +00:00
if isMake { //有生成包文件
fmt . Println ( "有新的业务代码生成,请重新运行" )
os . Exit ( - 1 )
}
2021-06-04 02:04:37 +00:00
return
}
2021-06-11 00:06:44 +00:00
//数据生成完后进一步解析
2021-06-07 03:32:47 +00:00
for fk , fv := range that . TableColumns {
2021-06-11 00:06:44 +00:00
//判断是否将表写入menu中
isMenusGet := false //判断是否被目录收录
for indexKey , _ := range that . IndexMenus {
indexCode := strings . Index ( indexKey , fk )
2022-01-16 20:47:39 +00:00
if indexCode == 0 || indexCode == 4 {
2021-11-14 19:26:54 +00:00
isMenusGet = false
continue
}
2021-06-11 00:06:44 +00:00
//如果相等或者表名在目录中已经设置(主要前一位是/并且他是最后一个字符串)
if indexKey == fk || ( indexCode != - 1 && indexKey [ indexCode - 1 ] == '/' && indexKey [ indexCode : ] == fk ) {
isMenusGet = true
break
}
}
//目录没有收录
if ! isMenusGet {
tablePrefixCode := strings . Index ( fk , "_" )
isNewPrefix := false //假定表名没有前缀
prefixName := ""
//并且代表有前缀,根据数据表分库设定使用
if tablePrefixCode != - 1 {
prefixName = fk [ : tablePrefixCode ]
2021-11-14 19:26:54 +00:00
} else {
prefixName = fk
2021-06-11 00:06:44 +00:00
}
2021-11-14 19:26:54 +00:00
//if tablePrefixCode != -1 {
for ck , _ := range that . TableColumns {
//判断不止一个前缀相同
2022-01-16 20:47:39 +00:00
if ( strings . Index ( ck , prefixName ) == 0 || strings . Index ( prefixName , ck ) == 4 ) && ck != fk {
2021-11-14 19:26:54 +00:00
isNewPrefix = true
break
2021-06-11 00:06:44 +00:00
}
}
2021-11-14 19:26:54 +00:00
//}
prefixName = DefaultMenuParentName + ":" + prefixName
2021-06-11 00:06:44 +00:00
menuIns := Map { "label" : that . TableConfig . GetMap ( fk ) . GetString ( "label" ) , "table" : fk }
//多耗费一点内存
mMenu := Map { "menus" : Slice { menuIns } , "label" : that . TableConfig . GetMap ( fk ) . GetString ( "label" ) , "name" : prefixName , "icon" : "el-icon-setting" }
//表名有前缀
if ! isNewPrefix {
//是否已有对应前缀, 已经有对应的menu只需要push进去即可
prefixName = DefaultMenuParentName
mMenu = Map { "menus" : Slice { menuIns } , "label" : "系统管理" , "name" : prefixName , "icon" : "el-icon-setting" }
}
//没有新前缀
if that . IndexMenus [ prefixName ] != nil {
2022-01-16 20:47:39 +00:00
if that . IndexMenus [ prefixName + "/" + fk ] == nil {
that . IndexMenus . GetMap ( prefixName ) [ "menus" ] = append ( that . IndexMenus . GetMap ( prefixName ) . GetSlice ( "menus" ) , menuIns )
that . IndexMenus [ prefixName + "/" + fk ] = menuIns
} else {
for k , v := range menuIns {
that . IndexMenus . GetMap ( prefixName + "/" + fk ) [ k ] = v
}
}
2021-06-11 00:06:44 +00:00
} else {
that . Config [ "menus" ] = append ( that . Config . GetSlice ( "menus" ) , mMenu ) //注入配置
//写入Index
that . IndexMenus [ prefixName ] = mMenu
that . IndexMenus [ prefixName + "/" + fk ] = menuIns
}
}
2021-06-07 03:32:47 +00:00
for k , v := range fv {
2021-06-12 05:33:35 +00:00
//搜索服务
if that . SearchColumns [ fk ] [ v . GetString ( "name" ) ] == nil &&
v . GetString ( "type" ) == "select" {
search := that . TableConfig . GetMap ( fk ) . GetSlice ( "search" )
sv := DeepCopyMap ( v ) . ( Map )
sv [ "value" ] = nil
sv [ "options" ] = append ( sv . GetSlice ( "options" ) , Map { "name" : "全部" , "value" : nil } )
that . TableConfig . GetMap ( fk ) [ "search" ] = append ( search , sv )
2021-06-15 22:10:57 +00:00
that . SearchColumns [ fk ] [ k ] = sv
2021-06-12 05:33:35 +00:00
}
2021-06-11 01:41:23 +00:00
//虚招后缀是_id结尾的表字段 假设org_id
2021-06-07 03:32:47 +00:00
if len ( k ) <= 3 || strings . LastIndex ( k , "_id" ) != len ( k ) - 3 {
continue
}
2021-06-11 01:41:23 +00:00
//普通表匹配 org_id匹配为org
2021-06-07 03:32:47 +00:00
oldTableName := k [ : len ( k ) - 3 ]
//上级ID匹配
if oldTableName == "parent" {
oldTableName = fk
}
2021-12-27 06:01:04 +00:00
//如果本身匹配则不再继续精简匹配
if that . TableConfig [ oldTableName ] == nil {
2021-06-11 01:41:23 +00:00
2021-12-27 06:01:04 +00:00
//如果依然找不到则查询system_org是否存在
if that . TableConfig [ DefaultMenuParentName + "_" + oldTableName ] != nil {
oldTableName = DefaultMenuParentName + "_" + oldTableName
}
2021-06-11 01:41:23 +00:00
2021-12-27 06:01:04 +00:00
//字段有动词前缀,自动进行解析
prefixColumn := strings . Index ( oldTableName , "_" )
2021-07-06 20:08:40 +00:00
2021-12-27 06:01:04 +00:00
//sys_org_id oldTableName即为sys此处判断为org表存在
2021-07-06 20:08:40 +00:00
2021-12-27 06:01:04 +00:00
if prefixColumn > - 1 && that . TableConfig [ oldTableName [ prefixColumn + 1 : ] ] != nil {
oldTableName = oldTableName [ prefixColumn + 1 : ]
}
if prefixColumn >= len ( oldTableName ) {
prefixColumn = - 1
}
//如果依然找不到则查询system_org是否存在
if prefixColumn > - 1 && that . TableConfig [ DefaultMenuParentName + "_" + oldTableName [ prefixColumn + 1 : ] ] != nil {
oldTableName = DefaultMenuParentName + "_" + oldTableName [ prefixColumn + 1 : ]
}
2021-06-11 01:41:23 +00:00
}
//普通方式查询不到,则转换为大型项目模块划分,暂时只支持一级模块划分,
//比如表sys_user 字段org_id, 查询不到sys_org表则查询org表, org表查询不到则查询默认前缀system_org表
2021-06-07 03:32:47 +00:00
//都查询不到则找不到,
prefix := strings . Index ( fk , "_" )
tableName := oldTableName
if prefix > 0 {
2021-06-11 01:41:23 +00:00
//表模块前缀sys_user sys即为前缀 sys_org
2021-06-07 03:32:47 +00:00
tableName = fk [ : prefix + 1 ] + oldTableName
2021-07-06 20:08:40 +00:00
if that . TableConfig [ tableName ] == nil || that . TableConfig [ oldTableName ] != nil {
2021-06-11 01:41:23 +00:00
//不存在则改为org
2021-06-07 03:32:47 +00:00
tableName = oldTableName
}
//表前缀+去除字段前缀
prefixColumn := strings . Index ( oldTableName , "_" )
if prefixColumn > - 1 {
tableName = fk [ : prefix + 1 ] + oldTableName [ prefixColumn + 1 : ]
if that . TableConfig [ tableName ] == nil {
tableName = oldTableName
}
}
}
2021-06-11 00:06:44 +00:00
//如果数据匹配则写入到配置中
2021-06-07 03:32:47 +00:00
if that . TableConfig [ tableName ] != nil {
v [ "link" ] = tableName
2021-06-11 01:41:23 +00:00
//一般查询name字段或者label字段, 如果没有name字段则默认第二个地段
2021-06-07 03:32:47 +00:00
if that . TableColumns [ tableName ] [ "name" ] != nil {
2021-06-12 05:33:35 +00:00
v [ "value" ] = "name"
continue
2021-06-07 03:32:47 +00:00
}
2021-06-11 01:41:23 +00:00
if that . TableColumns [ tableName ] [ "label" ] != nil {
2021-06-12 05:33:35 +00:00
v [ "value" ] = "label"
continue
2021-06-11 01:41:23 +00:00
}
2022-04-25 11:58:49 +00:00
tempC := that . TableConfig . GetMap ( tableName ) . GetSlice ( "columns" )
isGet := true
for k2 , _ := range tempC {
if strings . Contains ( tempC . GetMap ( k2 ) . GetString ( "name" ) , "name" ) {
v [ "value" ] = tempC . GetMap ( k2 ) . GetString ( "name" )
isGet = false
break
}
}
2021-06-07 03:32:47 +00:00
2022-04-25 11:58:49 +00:00
if isGet && len ( that . TableConfig . GetMap ( tableName ) . GetSlice ( "columns" ) ) > 2 {
2021-06-12 05:33:35 +00:00
v [ "value" ] = that . TableConfig . GetMap ( tableName ) . GetSlice ( "columns" ) . GetMap ( 1 ) . GetString ( "name" )
continue
2021-06-07 03:32:47 +00:00
}
}
}
}
2021-06-15 22:10:57 +00:00
//搜索增加树节点
for fk , fv := range that . TableColumns {
for k , v := range fv {
if v . GetString ( "link" ) != "" && that . SearchColumns [ fk ] [ k ] == nil &&
that . TableColumns [ v . GetString ( "link" ) ] [ "parent_id" ] != nil {
//搜索服务
search := that . TableConfig . GetMap ( fk ) . GetSlice ( "search" )
sv := Map { "type" : "tree" , "label" : v [ "label" ] , "name" : v [ "name" ] , "value" : v [ "value" ] , "link" : v [ "link" ] }
that . TableConfig . GetMap ( fk ) [ "search" ] = append ( search , sv )
that . SearchColumns [ fk ] [ k ] = sv
}
}
}
2021-06-04 18:18:56 +00:00
fmt . Println ( id , "---" , that . Config . GetString ( "id" ) )
2021-06-04 02:04:37 +00:00
that . Config [ "id" ] = id
2021-12-27 12:40:16 +00:00
2022-03-12 21:06:28 +00:00
if config . GetInt ( "mode" ) != 0 {
2021-12-27 12:40:16 +00:00
//init文件初始化
myInit = strings . Replace ( myInit , "{{id}}" , id , - 1 )
myInit = strings . Replace ( myInit , "{{tablesCtr}}" , ctrList , - 1 )
2022-03-12 21:06:28 +00:00
_ = os . MkdirAll ( config . GetString ( "name" ) , os . ModeDir )
err = ioutil . WriteFile ( config . GetString ( "name" ) + "/init.go" , [ ] byte ( myInit ) , os . ModePerm )
2021-12-27 12:40:16 +00:00
if err != nil {
that . Error . SetError ( err )
}
2021-06-03 19:03:48 +00:00
}
2022-03-12 21:06:28 +00:00
//写入配置文件
2021-06-04 18:18:56 +00:00
//err = json.Indent(&configByte, []byte(that.Config.ToJsonString()), "", "\t")
2022-03-12 21:06:28 +00:00
_ = os . MkdirAll ( filepath . Dir ( config . GetString ( "config" ) ) , os . ModeDir )
err = ioutil . WriteFile ( config . GetString ( "config" ) , [ ] byte ( that . Config . ToJsonString ( ) ) , os . ModePerm )
2021-06-03 19:03:48 +00:00
if err != nil {
that . Error . SetError ( err )
}
2022-03-12 21:06:28 +00:00
2021-06-04 02:04:37 +00:00
fmt . Println ( "有新的代码生成,请重新运行" )
os . Exit ( - 1 )
2021-12-27 12:40:16 +00:00
2021-06-03 19:03:48 +00:00
}
2021-06-07 03:32:47 +00:00
2021-09-16 20:00:49 +00:00
func ( that * MakeCode ) Info ( table string , userData Map , db * db . HoTimeDB ) ( string , Map ) {
2021-06-03 19:03:48 +00:00
reStr := ""
2021-09-16 20:00:49 +00:00
data := Map { }
var ruleData Map
2022-03-12 21:06:28 +00:00
testQu := [ ] string { }
testQuData := that . TableColumns [ table ]
for key , _ := range testQuData {
//fmt.Println(key, ":", value)
testQu = append ( testQu , key )
}
sort . Strings ( testQu )
for _ , k := range testQu {
v := testQuData [ k ]
2021-06-07 03:32:47 +00:00
if v == nil {
continue
}
2021-09-16 20:00:49 +00:00
//准备加入索引权限
if v . GetString ( "link" ) != "" &&
userData != nil &&
that . TableColumns [ v . GetString ( "link" ) ] [ "parent_id" ] != nil {
//初始化ruleData
if ruleData == nil {
ruleData = Map { }
for _ , v := range that . TableColumns [ "admin" ] {
if v . GetString ( "link" ) != "" &&
v . GetString ( "name" ) != "parent_id" &&
userData . Get ( v . GetString ( "name" ) ) != nil {
ruleData [ v . GetString ( "link" ) ] = userData . Get ( v . GetString ( "name" ) )
}
}
}
if ruleData [ v . GetString ( "link" ) ] != nil {
if v . GetString ( "name" ) == "parent_id" {
data [ "index[~]" ] = "," + ruleData . GetString ( v . GetString ( "link" ) ) + ","
} else {
2021-10-21 15:19:32 +00:00
idMap := db . Select ( v . GetString ( "link" ) , "id" , Map { "index[~]" : "," + ruleData . GetString ( v . GetString ( "link" ) ) + "," } )
2021-09-16 20:00:49 +00:00
ids := Slice { ruleData . GetCeilInt ( v . GetString ( "link" ) ) }
for _ , v := range idMap {
ids = append ( ids , v . GetCeilInt ( "id" ) )
}
data [ v . GetString ( "name" ) ] = ids
}
}
}
2021-06-03 19:03:48 +00:00
if v . Get ( "info" ) == nil || v . GetBool ( "info" ) {
2021-07-06 20:08:40 +00:00
reStr += "`" + v . GetString ( "name" ) + "`,"
2021-06-03 19:03:48 +00:00
}
}
if len ( reStr ) != 0 {
reStr = reStr [ : len ( reStr ) - 1 ]
}
2021-09-16 20:00:49 +00:00
return reStr , data
2021-06-03 19:03:48 +00:00
}
2022-04-25 11:58:49 +00:00
func ( that * MakeCode ) Add ( table string , user Map , req * http . Request ) Map {
2021-06-03 19:03:48 +00:00
data := Map { }
for _ , v := range that . TableColumns [ table ] {
2021-06-07 03:32:47 +00:00
//不可使用,未在前端展示,但在内存中保持有
if v . GetBool ( "notUse" ) {
2021-09-16 20:00:49 +00:00
if v . GetString ( "type" ) == "index" && that . TableColumns [ table ] [ "parent_id" ] != nil {
2021-10-21 14:52:40 +00:00
data [ v . GetString ( "name" ) ] = ","
2021-09-16 20:00:49 +00:00
}
2021-06-07 03:32:47 +00:00
continue
}
2021-06-03 19:03:48 +00:00
if v . Get ( "add" ) == nil || v . GetBool ( "add" ) {
2021-07-06 20:08:40 +00:00
if len ( req . Form [ v . GetString ( "name" ) ] ) == 0 {
2022-03-26 08:53:40 +00:00
2022-04-25 11:58:49 +00:00
if user [ v . GetString ( "name" ) ] != nil {
2022-03-26 08:53:40 +00:00
data [ v . GetString ( "name" ) ] = user [ v . GetString ( "name" ) ]
continue
}
2022-04-25 11:58:49 +00:00
if that . FileConfig . GetString ( "table" ) + "_id" == v . GetString ( "name" ) {
2022-03-26 08:53:40 +00:00
data [ v . GetString ( "name" ) ] = user [ "id" ]
continue
}
2021-12-27 06:01:04 +00:00
if v . GetBool ( "must" ) {
return nil
} else {
continue
}
2021-06-03 19:03:48 +00:00
}
2021-07-06 20:08:40 +00:00
reqValue := req . FormValue ( v . GetString ( "name" ) )
2021-08-29 23:36:17 +00:00
if ( reqValue == "" || reqValue == "null" ) && strings . Contains ( v . GetString ( "name" ) , "id" ) {
2021-07-06 20:08:40 +00:00
data [ v . GetString ( "name" ) ] = nil
} else {
2021-08-29 23:36:17 +00:00
if v . GetString ( "type" ) == "password" {
data [ v . GetString ( "name" ) ] = Md5 ( reqValue )
} else {
data [ v . GetString ( "name" ) ] = reqValue
}
2021-07-06 20:08:40 +00:00
}
2021-09-15 20:33:10 +00:00
}
2021-12-27 10:21:41 +00:00
2021-09-15 20:33:10 +00:00
if v . GetString ( "name" ) == "create_time" {
2022-04-25 11:58:49 +00:00
if v . GetString ( "type" ) == "unixTime" {
data [ v . GetString ( "name" ) ] = time . Now ( ) . Unix ( )
}
if v . GetString ( "type" ) == "time" {
data [ v . GetString ( "name" ) ] = time . Now ( ) . Format ( "2006-01-02 15-04-05" )
}
2021-09-15 20:33:10 +00:00
continue
}
2021-12-27 10:21:41 +00:00
2021-09-15 20:33:10 +00:00
if v . GetString ( "name" ) == "modify_time" {
2022-04-25 11:58:49 +00:00
if v . GetString ( "type" ) == "unixTime" {
data [ v . GetString ( "name" ) ] = time . Now ( ) . Unix ( )
}
if v . GetString ( "type" ) == "time" {
data [ v . GetString ( "name" ) ] = time . Now ( ) . Format ( "2006-01-02 15-04-05" )
}
2021-06-03 19:03:48 +00:00
}
}
if len ( data ) == 0 {
return nil
}
return data
}
func ( that * MakeCode ) Edit ( table string , req * http . Request ) Map {
data := Map { }
for _ , v := range that . TableColumns [ table ] {
2021-06-07 03:32:47 +00:00
//不可使用,未在前端展示,但在内存中保持有
if v . GetBool ( "notUse" ) {
2021-09-16 20:00:49 +00:00
if v . GetString ( "type" ) == "index" && that . TableColumns [ table ] [ "parent_id" ] != nil {
2021-10-21 14:52:40 +00:00
data [ v . GetString ( "name" ) ] = ","
2021-09-16 20:00:49 +00:00
}
2021-06-07 03:32:47 +00:00
continue
}
2021-09-16 20:00:49 +00:00
2021-06-03 19:03:48 +00:00
if v . Get ( "edit" ) == nil || v . GetBool ( "edit" ) {
reqValue := req . FormValue ( v . GetString ( "name" ) )
2021-08-29 23:36:17 +00:00
if reqValue == "" || reqValue == "null" {
2021-06-03 19:03:48 +00:00
continue
}
2021-08-29 23:36:17 +00:00
if v . GetString ( "type" ) == "password" {
data [ v . GetString ( "name" ) ] = Md5 ( reqValue )
} else {
data [ v . GetString ( "name" ) ] = reqValue
}
2021-06-03 19:03:48 +00:00
}
2021-09-15 20:33:10 +00:00
if v . GetString ( "name" ) == "modify_time" {
data [ v . GetString ( "name" ) ] = time . Now ( ) . Unix ( )
}
2021-06-03 19:03:48 +00:00
}
if len ( data ) == 0 {
return nil
}
return data
}
2021-09-16 20:00:49 +00:00
func ( that * MakeCode ) Delete ( table string , req * http . Request ) Map {
data := Map { }
for _ , v := range that . TableColumns [ table ] {
//不可使用,未在前端展示,但在内存中保持有
if v . GetBool ( "notUse" ) {
if v . GetString ( "type" ) == "index" && that . TableColumns [ table ] [ "parent_id" ] != nil {
2021-10-21 14:52:40 +00:00
data [ v . GetString ( "name" ) ] = ","
2021-09-16 20:00:49 +00:00
}
continue
}
}
return data
}
2021-06-03 19:03:48 +00:00
2021-09-16 20:00:49 +00:00
func ( that * MakeCode ) Search ( table string , userData Map , req * http . Request , db * db . HoTimeDB ) ( string , Map , Map ) {
2021-06-03 19:03:48 +00:00
reStr := ""
2021-06-13 02:40:19 +00:00
leftJoin := Map { }
data := Map { }
keyword := Map { }
daterange := Map { }
2022-03-12 21:06:28 +00:00
sortMap := Map { }
2021-09-16 20:00:49 +00:00
var ruleData Map
2021-10-21 15:19:32 +00:00
hasUser := false
2021-06-13 02:40:19 +00:00
keywordStr := req . FormValue ( "keyword" )
2022-03-12 21:06:28 +00:00
testQu := [ ] string { }
testQuData := that . TableColumns [ table ]
for key , _ := range testQuData {
//fmt.Println(key, ":", value)
testQu = append ( testQu , key )
}
sort . Strings ( testQu )
for _ , k := range testQu {
v := testQuData [ k ]
2021-06-07 03:32:47 +00:00
//不可使用,未在前端展示,但在内存中保持有
if v . GetBool ( "notUse" ) {
2021-09-16 20:00:49 +00:00
2021-06-07 03:32:47 +00:00
continue
}
2021-06-13 02:40:19 +00:00
if v [ "list" ] != false {
if v . GetString ( "link" ) != "" &&
v . GetString ( "name" ) != "parent_id" {
2021-09-15 20:33:10 +00:00
reStr += table + "." + v . GetString ( "name" ) + "," +
v . GetString ( "link" ) + "." + v . GetString ( "value" ) + " AS " +
2021-06-13 02:40:19 +00:00
v . GetString ( "link" ) + "_" + v . GetString ( "name" ) + "_" + v . GetString ( "value" ) + ","
2022-04-25 11:58:49 +00:00
if that . TableColumns [ v . GetString ( "link" ) ] [ "phone" ] != nil {
2022-03-26 08:53:40 +00:00
reStr += table + "." + v . GetString ( "name" ) + "," +
v . GetString ( "link" ) + ".phone AS " +
v . GetString ( "link" ) + "_" + v . GetString ( "name" ) + "_phone,"
}
2021-06-13 02:40:19 +00:00
leftJoin [ "[>]" + v . GetString ( "link" ) ] =
2021-06-13 17:19:05 +00:00
table + "." + v . GetString ( "name" ) + "=" +
2021-06-13 02:40:19 +00:00
v . GetString ( "link" ) + ".id"
2021-10-21 15:19:32 +00:00
if v . GetString ( "link" ) == "admin" {
hasUser = true
}
2021-09-15 20:33:10 +00:00
2021-12-27 06:01:04 +00:00
reqValue := req . FormValue ( v . GetString ( "name" ) )
if reqValue != "" {
data [ table + "." + v . GetString ( "name" ) ] = reqValue
}
2021-06-13 02:40:19 +00:00
} else {
reStr += table + "." + v . GetString ( "name" ) + ","
}
2021-09-16 20:00:49 +00:00
//准备加入索引权限
if v . GetString ( "link" ) != "" &&
userData != nil &&
that . TableColumns [ v . GetString ( "link" ) ] [ "parent_id" ] != nil {
//初始化ruleData
if ruleData == nil {
ruleData = Map { }
for _ , v := range that . TableColumns [ "admin" ] {
if v . GetString ( "link" ) != "" &&
v . GetString ( "name" ) != "parent_id" &&
userData . Get ( v . GetString ( "name" ) ) != nil {
ruleData [ v . GetString ( "link" ) ] = userData . Get ( v . GetString ( "name" ) )
}
}
}
if ruleData [ v . GetString ( "link" ) ] != nil {
if v . GetString ( "name" ) == "parent_id" {
data [ table + ".index[~]" ] = "," + ruleData . GetString ( v . GetString ( "link" ) ) + ","
} else {
2021-10-21 15:19:32 +00:00
idMap := db . Select ( v . GetString ( "link" ) , "id" , Map { "index[~]" : "," + ruleData . GetString ( v . GetString ( "link" ) ) + "," } )
2021-09-16 20:00:49 +00:00
ids := Slice { ruleData . GetCeilInt ( v . GetString ( "link" ) ) }
for _ , v := range idMap {
ids = append ( ids , v . GetCeilInt ( "id" ) )
}
data [ table + "." + v . GetString ( "name" ) ] = ids
}
}
}
2021-06-13 02:40:19 +00:00
if keywordStr != "" {
if v . GetString ( "type" ) == "text" {
keyword [ table + "." + v . GetString ( "name" ) + "[~]" ] = keywordStr
}
if v . GetString ( "name" ) == "id" {
keyword [ table + "." + v . GetString ( "name" ) ] = keywordStr
}
if v . GetString ( "link" ) != "" &&
v . GetString ( "name" ) != "parent_id" {
childs := db . Select ( v . GetString ( "link" ) , "id" , Map { v . GetString ( "value" ) + "[~]" : keywordStr } )
childIds := Slice { }
for _ , cv := range childs {
childIds = append ( childIds , cv . GetString ( "id" ) )
}
if len ( childIds ) != 0 {
keyword [ v . GetString ( "link" ) + ".id" ] = childIds
}
}
}
2021-06-03 19:03:48 +00:00
}
}
if len ( reStr ) != 0 {
reStr = reStr [ : len ( reStr ) - 1 ]
}
2021-06-12 19:08:43 +00:00
search := that . TableConfig . GetMap ( table ) . GetSlice ( "search" )
2021-06-03 19:03:48 +00:00
for k , _ := range search {
reqValue := req . FormValue ( search . GetMap ( k ) . GetString ( "name" ) )
if reqValue == "" {
continue
}
2021-06-12 19:08:43 +00:00
searchItem := search . GetMap ( k )
searchItemName := searchItem . GetString ( "name" )
2021-06-13 02:40:19 +00:00
//columns := that.TableConfig.GetMap(table).GetSlice("columns")
2021-06-12 19:08:43 +00:00
if searchItem . GetString ( "type" ) == "search" {
2021-06-13 02:40:19 +00:00
for _ , v := range that . TableColumns [ table ] {
if v [ "list" ] == false {
2021-06-13 01:53:37 +00:00
continue
}
2021-06-12 19:08:43 +00:00
//日期类型
2021-06-13 02:40:19 +00:00
if searchItemName == "daterange" && v . GetString ( "type" ) == "time" {
2021-09-15 20:33:10 +00:00
//fmt.Println(req.Form["daterange"])
2022-04-25 11:58:49 +00:00
if len ( req . Form [ "daterange" ] ) == 1 {
daterange [ table + "." + v . GetString ( "name" ) + "[<]" ] = req . FormValue ( "daterange" )
} else {
2022-03-26 08:53:40 +00:00
daterange [ table + "." + v . GetString ( "name" ) + "[<>]" ] = ObjToSlice ( req . Form [ "daterange" ] )
}
2021-06-12 19:08:43 +00:00
}
}
if searchItem . GetString ( "name" ) == "sort" {
2022-03-12 21:06:28 +00:00
sortMap [ "ORDER" ] = table + "." + reqValue
2021-06-12 19:08:43 +00:00
}
continue
}
2021-06-17 20:56:22 +00:00
//树节点模式搜索
if searchItemName == "parent_id" {
parentID := ObjToInt ( req . FormValue ( "parent_id" ) )
if parentID == 0 {
2021-09-16 20:00:49 +00:00
parentID = userData . GetCeilInt ( table + "_id" )
data [ "OR" ] = Map { table + ".id" : parentID , table + ".parent_id" : nil }
2021-06-17 20:56:22 +00:00
} else {
data [ table + ".parent_id" ] = parentID
}
continue
}
2021-06-12 19:08:43 +00:00
2021-06-15 22:10:57 +00:00
data [ table + "." + searchItemName ] = reqValue
2021-06-13 17:19:05 +00:00
}
2022-03-12 21:06:28 +00:00
if sortMap [ "ORDER" ] == nil {
sortMap [ "ORDER" ] = table + ".id DESC"
2021-10-17 20:49:55 +00:00
}
2021-06-13 17:19:05 +00:00
2021-06-12 19:08:43 +00:00
where := Map { }
if len ( keyword ) == 1 {
for k , v := range keyword {
data [ k ] = v
}
}
if len ( keyword ) > 1 {
2021-06-13 17:19:05 +00:00
if data [ "OR" ] != nil {
data = Map { "AND" : data , "OR" : keyword }
} else {
data [ "OR" ] = keyword
}
2021-06-12 19:08:43 +00:00
}
if len ( daterange ) == 1 {
for k , v := range daterange {
data [ k ] = v
}
}
if len ( daterange ) > 1 {
2022-03-26 08:53:40 +00:00
//if data["AND"] == nil {
2022-04-25 11:58:49 +00:00
data = Map { "AND" : Map { "AND" : data , "OR" : daterange } }
2022-03-26 08:53:40 +00:00
//}else{
// data = Map{"AND": Map{"AND": data, "OR": daterange}}
//}
2021-06-12 19:08:43 +00:00
}
2021-06-03 19:03:48 +00:00
2021-06-12 19:08:43 +00:00
if len ( data ) > 1 {
where [ "AND" ] = data
}
2021-06-03 19:03:48 +00:00
2021-06-12 19:08:43 +00:00
if len ( data ) == 1 {
where = data
}
2021-10-21 15:19:32 +00:00
if len ( where ) == 0 && hasUser {
2022-01-02 17:42:35 +00:00
//where["admin.id"] = userData["id"]
2021-10-21 15:19:32 +00:00
}
2022-03-12 21:06:28 +00:00
if len ( sortMap ) != 0 {
for k , v := range sortMap {
2021-06-12 19:08:43 +00:00
where [ k ] = v
}
2021-06-03 19:03:48 +00:00
}
2021-06-13 01:53:37 +00:00
return reStr , leftJoin , where
2021-06-03 19:03:48 +00:00
}
2021-12-27 12:40:16 +00:00
func setListener ( ) {
}