package code import ( . "../common" "../db" "errors" "fmt" "io/ioutil" "net/http" "os" "path/filepath" "strings" "time" ) type MakeCode struct { IndexMenus Map TableConfig Map TableColumns map[string]map[string]Map SearchColumns map[string]map[string]Map Config Map Error } func (that *MakeCode) Db2JSON(name string, path string, db *db.HoTimeDB, makeCode bool) { isMake := false idSlice := Slice{} if that.TableColumns == nil { that.TableColumns = make(map[string]map[string]Map) } if that.SearchColumns == nil { that.SearchColumns = make(map[string]map[string]Map) } //加载配置文件 btes, err := ioutil.ReadFile(path) Config["name"] = name that.Config = DeepCopyMap(Config).(Map) if err == nil { cmap := Map{} //文件是否损坏 cmap.JsonToMap(string(btes), &that.Error) for k, v := range cmap { that.Config[k] = v //程序配置 Config[k] = v //系统配置 } } else { that.Error.SetError(errors.New("配置文件不存在,或者配置出错,使用缺省默认配置")) } 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 } } } } } } 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") search := that.TableConfig.GetMap(tableName).GetSlice("search") //初始化 if that.TableColumns[tableName] == nil { that.TableColumns[tableName] = map[string]Map{} } //初始化搜索项 if that.SearchColumns[tableName] == nil { that.SearchColumns[tableName] = map[string]Map{} } //注入源数据 for index, _ := range columns { columnsName := columns.GetMap(index).GetString("name") that.TableColumns[tableName][columnsName] = columns.GetMap(index) } //注入search源数据 for index, _ := range search { searchName := search.GetMap(index).GetString("name") that.SearchColumns[tableName][searchName] = search.GetMap(index) } } if db == nil { return } //数据库反哺 myInit := strings.Replace(InitTpt, "{{name}}", name, -1) ctrList := "" 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}) } if db.Type == "sqlite" { nowTables = db.Select("sqlite_sequence", "name") } //idSlice=append(idSlice,nowTables) for _, v := range nowTables { if v.GetString("name") == "cached" { continue } if that.TableConfig.GetMap(v.GetString("name")) == nil { if v.GetString("label") == "" { v["label"] = v.GetString("name") } that.TableConfig[v.GetString("name")] = Map{ "label": v.GetString("label"), "table": v.GetString("name"), "auth": []string{"show", "add", "delete", "edit", "info"}, "columns": []Map{}, "search": []Map{ {"type": "search", "name": "keyword", "label": "请输入关键词", "value": nil}, {"type": "search", "name": "daterange", "label": "时间段", "value": nil}, {"type": "search", "name": "sort", "label": "排序", "value": nil}, }, } } //初始化 if that.TableColumns[v.GetString("name")] == nil { that.TableColumns[v.GetString("name")] = make(map[string]Map) } //初始化 if that.SearchColumns[v.GetString("name")] == nil { that.SearchColumns[v.GetString("name")] = make(map[string]Map) } 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") + "]);") } idSlice = append(idSlice, tableInfo) for _, info := range tableInfo { if info.GetString("label") == "" { info["label"] = info.GetString("name") } coloum := that.TableColumns[v.GetString("name")][info.GetString("name")] if coloum == nil { //根据类型判断真实类型 for k, v1 := range ColumnDataType { if strings.Contains(info.GetString("name"), k) || strings.Contains(info.GetString("type"), k) { info["type"] = v1 } } coloum = Map{ "name": info.GetString("name"), "type": info.GetString("type"), "label": info.GetString("label"), //"add": false, "info": false, "edit": false, "list": true, //"must": false, } //备注以空格隔开,空格后的是其他备注 indexNum := strings.Index(info.GetString("label"), ":") if indexNum > 0 { coloum["label"] = info.GetString("label")[:indexNum] } for _, ColumnName := range ColumnNameType { if (ColumnName.Strict && coloum.GetString("name") == ColumnName.Name) || (!ColumnName.Strict && strings.Contains(coloum.GetString("name"), ColumnName.Name)) { //全部都不需要则不加入 if ColumnName.Edit == false && ColumnName.List == false && ColumnName.Info == false { coloum["notUse"] = true //continue } coloum["info"] = ColumnName.Info coloum["edit"] = ColumnName.Edit coloum["add"] = ColumnName.Edit coloum["list"] = ColumnName.List coloum["must"] = ColumnName.Must if ColumnName.Info { delete(coloum, "info") } if ColumnName.Edit { delete(coloum, "edit") delete(coloum, "add") } if ColumnName.List { delete(coloum, "list") } if ColumnName.Must { delete(coloum, "must") } if ColumnName.Type != "" { coloum["type"] = ColumnName.Type } if ColumnName.Strict && coloum.GetString("name") == ColumnName.Name { break } } } //如果是select类型需要设置options if coloum.GetString("type") == "number" { coloum["sortable"] = true } //if !coloum.GetBool("notUse") { that.TableConfig.GetMap(v.GetString("name"))["columns"] = append(that.TableConfig.GetMap(v.GetString("name")).GetSlice("columns"), coloum) //} //如果是select类型需要设置options //if coloum.GetString("type") == "select" { options := Slice{} comments := strings.Split(info.GetString("label"), ":") 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]}) } } } if coloum.GetString("type") == "select" { coloum["must"] = true coloum["options"] = options } else if len(options) > 0 { coloum["must"] = true coloum["options"] = options coloum["type"] = "select" } //} } //else { // // //if !(coloum.GetString("label") != "备注" && info.GetString("label") == "备注") { // // coloum["label"] = info.GetString("label") // //} // //coloum["type"] = info.GetString("type") //} //暂时不关闭参数,保证表数据完全读取到 that.TableColumns[v.GetString("name")][info.GetString("name")] = coloum } if makeCode { //创建模块文件 //判断文件是否存在 //_, err := os.OpenFile(name+"/"+v.GetString("name"), os.O_RDONLY, os.ModePerm) _, err := os.Stat(name + "/" + v.GetString("name") + ".go") if err != nil { //文件不存在,则根据模板创建 myCtr := strings.Replace(CtrTpt, "{{name}}", name, -1) myCtr = strings.Replace(myCtr, "{{table}}", v.GetString("name"), -1) _ = os.MkdirAll(name, os.ModeDir) err = ioutil.WriteFile(name+"/"+v.GetString("name")+".go", []byte(myCtr), os.ModePerm) if err != nil { that.Error.SetError(err) } isMake = true } ctrList = ctrList + `"` + v.GetString("name") + `":` + v.GetString("name") + "Ctr,\r\n " } } that.Config["tables"] = that.TableConfig //生成id,判断数据库是否有改变,以保证数据库和配置文件匹配唯一 id := Md5(ObjToStr(idSlice)) if id == that.Config.GetString("id") { if isMake { //有生成包文件 fmt.Println("有新的业务代码生成,请重新运行") os.Exit(-1) } return } //数据生成完后进一步解析 for fk, fv := range that.TableColumns { //判断是否将表写入menu中 isMenusGet := false //判断是否被目录收录 for indexKey, _ := range that.IndexMenus { indexCode := strings.Index(indexKey, fk) if indexCode == 0 { isMenusGet = false continue } //如果相等或者表名在目录中已经设置(主要前一位是/并且他是最后一个字符串) 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] } else { prefixName = fk } //if tablePrefixCode != -1 { for ck, _ := range that.TableColumns { //判断不止一个前缀相同 if strings.Index(ck, prefixName) == 0 && ck != fk { isNewPrefix = true break } } //} prefixName = DefaultMenuParentName + ":" + prefixName 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 { that.IndexMenus.GetMap(prefixName)["menus"] = append(that.IndexMenus.GetMap(prefixName).GetSlice("menus"), menuIns) that.IndexMenus[prefixName+"/"+fk] = menuIns } else { that.Config["menus"] = append(that.Config.GetSlice("menus"), mMenu) //注入配置 //写入Index that.IndexMenus[prefixName] = mMenu that.IndexMenus[prefixName+"/"+fk] = menuIns } } for k, v := range fv { //搜索服务 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) that.SearchColumns[fk][k] = sv } //虚招后缀是_id结尾的表字段 假设org_id if len(k) <= 3 || strings.LastIndex(k, "_id") != len(k)-3 { continue } //普通表匹配 org_id匹配为org oldTableName := k[:len(k)-3] //上级ID匹配 if oldTableName == "parent" { oldTableName = fk } //如果本身匹配则不再继续精简匹配 if that.TableConfig[oldTableName] == nil { //如果依然找不到则查询system_org是否存在 if that.TableConfig[DefaultMenuParentName+"_"+oldTableName] != nil { oldTableName = DefaultMenuParentName + "_" + oldTableName } //字段有动词前缀,自动进行解析 prefixColumn := strings.Index(oldTableName, "_") //sys_org_id oldTableName即为sys此处判断为org表存在 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:] } } //普通方式查询不到,则转换为大型项目模块划分,暂时只支持一级模块划分, //比如表sys_user 字段org_id,查询不到sys_org表则查询org表,org表查询不到则查询默认前缀system_org表 //都查询不到则找不到, prefix := strings.Index(fk, "_") tableName := oldTableName if prefix > 0 { //表模块前缀sys_user sys即为前缀 sys_org tableName = fk[:prefix+1] + oldTableName if that.TableConfig[tableName] == nil || that.TableConfig[oldTableName] != nil { //不存在则改为org tableName = oldTableName } //表前缀+去除字段前缀 prefixColumn := strings.Index(oldTableName, "_") if prefixColumn > -1 { tableName = fk[:prefix+1] + oldTableName[prefixColumn+1:] if that.TableConfig[tableName] == nil { tableName = oldTableName } } } //如果数据匹配则写入到配置中 if that.TableConfig[tableName] != nil { v["link"] = tableName //一般查询name字段或者label字段,如果没有name字段则默认第二个地段 if that.TableColumns[tableName]["name"] != nil { v["value"] = "name" continue } if that.TableColumns[tableName]["label"] != nil { v["value"] = "label" continue } if len(that.TableConfig.GetMap(tableName).GetSlice("columns")) > 2 { v["value"] = that.TableConfig.GetMap(tableName).GetSlice("columns").GetMap(1).GetString("name") continue } } } } //搜索增加树节点 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 } } } fmt.Println(id, "---", that.Config.GetString("id")) that.Config["id"] = id if makeCode { //init文件初始化 myInit = strings.Replace(myInit, "{{id}}", id, -1) myInit = strings.Replace(myInit, "{{tablesCtr}}", ctrList, -1) _ = os.MkdirAll(name, os.ModeDir) err = ioutil.WriteFile(name+"/init.go", []byte(myInit), os.ModePerm) if err != nil { that.Error.SetError(err) } } //写入配置文件 //var configByte bytes.Buffer //err = json.Indent(&configByte, []byte(that.Config.ToJsonString()), "", "\t") _ = os.MkdirAll(filepath.Dir(path), os.ModeDir) err = ioutil.WriteFile(path, []byte(that.Config.ToJsonString()), os.ModePerm) if err != nil { that.Error.SetError(err) } fmt.Println("有新的代码生成,请重新运行") os.Exit(-1) } func (that *MakeCode) Info(table string, userData Map, db *db.HoTimeDB) (string, Map) { reStr := "" data := Map{} var ruleData Map for _, v := range that.TableColumns[table] { if v == nil { continue } //准备加入索引权限 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 { idMap := db.Select(v.GetString("link"), "id", Map{"index[~]": "," + ruleData.GetString(v.GetString("link")) + ","}) ids := Slice{ruleData.GetCeilInt(v.GetString("link"))} for _, v := range idMap { ids = append(ids, v.GetCeilInt("id")) } data[v.GetString("name")] = ids } } } if v.Get("info") == nil || v.GetBool("info") { reStr += "`" + v.GetString("name") + "`," } } if len(reStr) != 0 { reStr = reStr[:len(reStr)-1] } return reStr, data } func (that *MakeCode) Add(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 { data[v.GetString("name")] = "," } continue } if v.Get("add") == nil || v.GetBool("add") { if len(req.Form[v.GetString("name")]) == 0 { if v.GetBool("must") { return nil } else { continue } } reqValue := req.FormValue(v.GetString("name")) if (reqValue == "" || reqValue == "null") && strings.Contains(v.GetString("name"), "id") { data[v.GetString("name")] = nil } else { if v.GetString("type") == "password" { data[v.GetString("name")] = Md5(reqValue) } else { data[v.GetString("name")] = reqValue } } } if v.GetString("name") == "create_time" { data[v.GetString("name")] = time.Now().Unix() continue } if v.GetString("name") == "modify_time" { data[v.GetString("name")] = time.Now().Unix() } } 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] { //不可使用,未在前端展示,但在内存中保持有 if v.GetBool("notUse") { if v.GetString("type") == "index" && that.TableColumns[table]["parent_id"] != nil { data[v.GetString("name")] = "," } continue } if v.Get("edit") == nil || v.GetBool("edit") { reqValue := req.FormValue(v.GetString("name")) if reqValue == "" || reqValue == "null" { continue } if v.GetString("type") == "password" { data[v.GetString("name")] = Md5(reqValue) } else { data[v.GetString("name")] = reqValue } } if v.GetString("name") == "modify_time" { data[v.GetString("name")] = time.Now().Unix() } } if len(data) == 0 { return nil } return data } 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 { data[v.GetString("name")] = "," } continue } } return data } func (that *MakeCode) Search(table string, userData Map, req *http.Request, db *db.HoTimeDB) (string, Map, Map) { reStr := "" leftJoin := Map{} data := Map{} keyword := Map{} daterange := Map{} sort := Map{} var ruleData Map hasUser := false keywordStr := req.FormValue("keyword") for _, v := range that.TableColumns[table] { //不可使用,未在前端展示,但在内存中保持有 if v.GetBool("notUse") { continue } if v["list"] != false { if v.GetString("link") != "" && v.GetString("name") != "parent_id" { reStr += table + "." + v.GetString("name") + "," + v.GetString("link") + "." + v.GetString("value") + " AS " + v.GetString("link") + "_" + v.GetString("name") + "_" + v.GetString("value") + "," leftJoin["[>]"+v.GetString("link")] = table + "." + v.GetString("name") + "=" + v.GetString("link") + ".id" if v.GetString("link") == "admin" { hasUser = true } reqValue := req.FormValue(v.GetString("name")) if reqValue != "" { data[table+"."+v.GetString("name")] = reqValue } } else { reStr += table + "." + v.GetString("name") + "," } //准备加入索引权限 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 { idMap := db.Select(v.GetString("link"), "id", Map{"index[~]": "," + ruleData.GetString(v.GetString("link")) + ","}) ids := Slice{ruleData.GetCeilInt(v.GetString("link"))} for _, v := range idMap { ids = append(ids, v.GetCeilInt("id")) } data[table+"."+v.GetString("name")] = ids } } } 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 } } } } } if len(reStr) != 0 { reStr = reStr[:len(reStr)-1] } search := that.TableConfig.GetMap(table).GetSlice("search") for k, _ := range search { reqValue := req.FormValue(search.GetMap(k).GetString("name")) if reqValue == "" { continue } searchItem := search.GetMap(k) searchItemName := searchItem.GetString("name") //columns := that.TableConfig.GetMap(table).GetSlice("columns") if searchItem.GetString("type") == "search" { for _, v := range that.TableColumns[table] { if v["list"] == false { continue } //日期类型 if searchItemName == "daterange" && v.GetString("type") == "time" { //fmt.Println(req.Form["daterange"]) daterange[table+"."+v.GetString("name")+"[<>]"] = ObjToSlice(req.Form["daterange"]) } } if searchItem.GetString("name") == "sort" { sort["ORDER"] = table + "." + reqValue } continue } //树节点模式搜索 if searchItemName == "parent_id" { parentID := ObjToInt(req.FormValue("parent_id")) if parentID == 0 { parentID = userData.GetCeilInt(table + "_id") data["OR"] = Map{table + ".id": parentID, table + ".parent_id": nil} } else { data[table+".parent_id"] = parentID } continue } data[table+"."+searchItemName] = reqValue } if sort["ORDER"] == nil { sort["ORDER"] = table + ".id DESC" } where := Map{} if len(keyword) == 1 { for k, v := range keyword { data[k] = v } } if len(keyword) > 1 { if data["OR"] != nil { data = Map{"AND": data, "OR": keyword} } else { data["OR"] = keyword } } if len(daterange) == 1 { for k, v := range daterange { data[k] = v } } if len(daterange) > 1 { if data["AND"] != nil { data = Map{"AND": Map{"AND": data, "OR": daterange}} } } if len(data) > 1 { where["AND"] = data } if len(data) == 1 { where = data } if len(where) == 0 && hasUser { //where["admin.id"] = userData["id"] } if len(sort) != 0 { for k, v := range sort { where[k] = v } } return reStr, leftJoin, where } func setListener() { }