Files
hotime/code/makecode.go
T
hoteas 66f18a084a feat(app): 实现优雅停机功能
- 新增 shuttingDown 原子布尔标志和 shutdownOnce 保证单次执行
- 添加 DrainTimeout 和 ShutdownTimeout 配置参数,默认 5s 和 30s
- 修改 ServeHTTP 拦截新请求返回 503 Service Unavailable
- 实现跨平台信号处理:Windows 关窗口和 Linux SIGTERM/SIGINT
- 添加 recover 保护避免停机过程中 panic 触发重启
- 优化 HTTP 服务退出判断,排除正常关闭情况
- 新增 log.LoggerNoCaller 用于访问日志等无意义调用方场景
- 更新 README 文档增加优雅停机特性说明和文档链接
- 创建详细的优雅停机文档和测试用例
- 添加 Windows 平台特定信号处理实现
- 新增 .cursor 计划文件记录开发方案
2026-04-14 14:07:59 +08:00

1375 lines
40 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package code
import (
. "code.hoteas.com/golang/hotime/common"
"code.hoteas.com/golang/hotime/db"
"code.hoteas.com/golang/hotime/log"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"sort"
"strings"
"time"
)
type MakeCode struct {
FileConfig Map
IndexMenus Map
TableConfig Map
TableColumns map[string]map[string]Map
SearchColumns map[string]map[string]Map
Config Map
RuleConfig []Map
Log *log.Logger
}
func (that *MakeCode) Db2JSON(db *db.HoTimeDB, config Map) {
isMake := false
//hasConfigFile := false
idSlice := Slice{}
that.FileConfig = config
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(config.GetString("config"))
var err error
that.Config = DeepCopyMap(Config).(Map)
that.Config["name"] = config.GetString("table")
//加载规则文件
btesRule, errRule := ioutil.ReadFile(config.GetString("rule"))
that.RuleConfig = []Map{}
if errRule == nil {
//cmap := Map{}
//文件是否损坏
ruleLis := ObjToSlice(string(btesRule))
//cmap.JSON()
for k, _ := range ruleLis {
that.RuleConfig = append(that.RuleConfig, ruleLis.GetMap(k))
}
} else {
for _, v := range RuleConfig {
that.RuleConfig = append(that.RuleConfig, ObjToMap(DeepCopyMap(v)))
}
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.Log.Error().Err(err).Msg("写入 rule 配置文件失败")
}
}
that.Log.Warnf("rule配置文件不存在或配置出错,使用缺省默认配置")
}
that.IndexMenus = Map{}
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}}", config.GetString("table"), -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_master", "name", Map{"type": "table"})
}
if db.Type == "dm" || db.Type == "dameng" {
nowTables = db.Query(`SELECT TABLE_NAME AS "name", COMMENTS AS "label" FROM ALL_TAB_COMMENTS WHERE TABLE_TYPE='TABLE' AND OWNER='` + db.DBName + `'`)
}
//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")
}
if strings.HasSuffix(v.GetString("label"), "表") {
withoutTable := strings.TrimSuffix(v.GetString("label"), "表")
if len([]rune(withoutTable)) <= 3 {
v["label"] = withoutTable + "管理"
} else {
v["label"] = withoutTable
}
}
that.TableConfig[v.GetString("name")] = Map{
"label": v.GetString("label"),
"table": v.GetString("name"),
"auth": []string{"show", "add", "delete", "edit", "info", "download"},
"columns": []Map{},
"search": []Map{
{"type": "search", "name": "keywordtable", "label": "筛选", "options": Slice{Map{"name": "无", "value": nil}}, "value": nil},
{"type": "search", "name": "daterangetable", "label": "筛选", "options": Slice{Map{"name": "无", "value": nil}}, "value": nil},
{"type": "search", "name": "keyword", "label": "请输入关键词", "value": nil},
{"type": "search", "name": "daterange", "label": "时间段", "value": nil},
{"type": "search", "name": "sort", "label": "排序", "value": nil},
},
}
if v.GetString("name") == "logs" {
that.TableConfig.GetMap(v.GetString("name"))["auth"] = []string{"show", "download"}
}
}
//初始化
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,IS_NULLABLE AS must,COLUMN_DEFAULT AS dflt_value", Map{"AND": Map{"TABLE_SCHEMA": db.DBName, "TABLE_NAME": v.GetString("name")}, "ORDER": "ORDINAL_POSITION"})
}
if db.Type == "sqlite" {
tableInfo = db.Query("pragma table_info([" + v.GetString("name") + "]);")
}
if db.Type == "dm" || db.Type == "dameng" {
tableInfo = db.Query(`SELECT c.COLUMN_NAME AS "name", c.DATA_TYPE AS "type", m.COMMENTS AS "label", c.NULLABLE AS "must", c.DATA_DEFAULT AS "dflt_value" FROM ALL_TAB_COLUMNS c LEFT JOIN USER_COL_COMMENTS m ON c.TABLE_NAME=m.TABLE_NAME AND c.COLUMN_NAME=m.COLUMN_NAME WHERE c.TABLE_NAME='` + v.GetString("name") + `' AND c.OWNER='` + db.DBName + `' ORDER BY c.COLUMN_ID`)
}
idSlice = append(idSlice, tableInfo)
for _, info1 := range tableInfo {
info := DeepCopyMap(info1).(Map)
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(strings.ToLower(info.GetString("type")), k) {
info["type"] = v1
break
}
}
coloum = Map{
"name": info.GetString("name"),
"type": info.GetString("type"),
"label": info.GetString("label"),
//"add": false, "info": false, "edit": false, "list": true,
//"must": false,
}
if info.GetString("must") == "NO" {
coloum["must"] = true
}
if info["dflt_value"] != nil {
coloum["default"] = info["dflt_value"]
}
if info["pk"] != nil && info.GetCeilInt64("pk") == 1 {
coloum["must"] = true
}
//提取括号内的提示信息:支持 ()、()、{}
rawLabel := info.GetString("label")
for _, pair := range [][2]string{{"(", ")"}, {"", ""}, {"{", "}"}} {
start := strings.Index(rawLabel, pair[0])
end := strings.Index(rawLabel, pair[1])
if start != -1 && end > start {
coloum["ps"] = rawLabel[start+len(pair[0]) : end]
rawLabel = rawLabel[:start] + rawLabel[end+len(pair[1]):]
break
}
}
//空格截断,空格后的内容丢弃
if idx := strings.Index(rawLabel, " "); idx > -1 {
rawLabel = rawLabel[:idx]
}
//冒号截断,去除选项数据部分
if idx := strings.Index(rawLabel, ":"); idx > -1 {
rawLabel = rawLabel[:idx]
}
coloum["label"] = rawLabel
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"))) ||
(v.GetString("name")+"."+coloum.GetString("name") == ColumnName.GetString("name")) {
//全部都不需要则不加入
if ColumnName.GetBool("edit") == false && ColumnName.GetBool("list") == false && ColumnName.GetBool("info") == false {
coloum["notUse"] = true
//continue
}
coloum["info"] = ColumnName.GetBool("info")
coloum["edit"] = ColumnName.GetBool("edit")
coloum["add"] = ColumnName["add"]
coloum["list"] = ColumnName.GetBool("list")
//coloum["must"] = ColumnName.GetBool("must")
if coloum["must"] == nil {
coloum["must"] = ColumnName.GetBool("must")
} else {
if ColumnName["must"] != nil {
coloum["must"] = ColumnName.GetBool("must")
}
}
if ColumnName.GetBool("info") {
delete(coloum, "info")
}
if ColumnName.GetBool("edit") {
delete(coloum, "edit")
}
if ColumnName["add"] == nil || ColumnName.GetBool("add") {
delete(coloum, "add")
}
if ColumnName.GetBool("list") {
delete(coloum, "list")
}
if !ColumnName.GetBool("must") {
delete(coloum, "must")
}
if ColumnName.GetString("type") != "" {
if ColumnName.GetString("type") == "time" && coloum["type"] == "number" {
coloum["type"] = "unixTime"
} else {
coloum["type"] = ColumnName.GetString("type")
}
}
if ColumnName.GetBool("strict") && coloum.GetString("name") == ColumnName.GetString("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 {
//对已有配置列也提取 ps 并清理 label
rawLabel := coloum.GetString("label")
for _, pair := range [][2]string{{"(", ")"}, {"", ""}, {"{", "}"}} {
start := strings.Index(rawLabel, pair[0])
end := strings.Index(rawLabel, pair[1])
if start != -1 && end > start {
coloum["ps"] = rawLabel[start+len(pair[0]) : end]
rawLabel = rawLabel[:start] + rawLabel[end+len(pair[1]):]
break
}
}
if idx := strings.Index(rawLabel, " "); idx > -1 {
rawLabel = rawLabel[:idx]
}
if idx := strings.Index(rawLabel, ":"); idx > -1 {
rawLabel = rawLabel[:idx]
}
coloum["label"] = rawLabel
}
//暂时不关闭参数,保证表数据完全读取到
that.TableColumns[v.GetString("name")][info.GetString("name")] = coloum
}
if config.GetInt("mode") != 0 {
//创建模块文件
//判断文件是否存在
//_, err := os.OpenFile(name+"/"+v.GetString("name"), os.O_RDONLY, os.ModePerm)
_, err := os.Stat(config.GetString("name") + "/" + v.GetString("name") + ".go")
if err != nil { //文件不存在,则根据模板创建
myCtr := strings.Replace(CtrTpt, "{{name}}", config.GetString("name"), -1)
myCtr = strings.Replace(myCtr, "{{table}}", v.GetString("name"), -1)
_ = os.MkdirAll(config.GetString("name"), os.ModeDir)
err = ioutil.WriteFile(config.GetString("name")+"/"+v.GetString("name")+".go", []byte(myCtr), os.ModePerm)
if err != nil {
that.Log.Error().Err(err).Msg("写入代码文件失败")
}
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 {
//目录没有收录
//if !isMenusGet {
//if !hasConfigFile {
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 || strings.Index(prefixName, ck) == 4) && ck != fk {
isNewPrefix = true
break
}
}
//}
prefixName = DefaultMenuParentName + ":" + prefixName
menuIns := Map{"label": that.TableConfig.GetMap(fk).GetString("label"), "table": fk, "auth": that.TableConfig.GetMap(fk).GetSlice("auth")}
//多耗费一点内存
mMenu := Map{"menus": Slice{menuIns}, "auth": Slice{"show"}, "label": that.TableConfig.GetMap(fk).GetString("label"), "name": prefixName, "icon": "Setting"}
//表名有前缀
if !isNewPrefix {
//是否已有对应前缀,已经有对应的menu只需要push进去即可
prefixName = DefaultMenuParentName
mMenu = Map{"menus": Slice{menuIns}, "auth": Slice{"show"}, "label": "系统管理", "name": prefixName, "icon": "Setting"}
}
//没有新前缀
if that.IndexMenus[prefixName] != nil {
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
}
}
} else {
that.Config["menus"] = append(that.Config.GetSlice("menus"), mMenu) //注入配置
//写入Index
that.IndexMenus[prefixName] = mMenu
that.IndexMenus[prefixName+"/"+fk] = menuIns
}
//}
search := that.TableConfig.GetMap(fk).GetSlice("search")
for k, v := range fv {
//虚招后缀是_id结尾的表字段 假设org_id
if !(len(k) <= 3 || strings.LastIndex(k, "_id") != len(k)-3) {
//普通表匹配 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
}
tempC := that.TableConfig.GetMap(tableName).GetSlice("columns")
isGet := true
for k2, _ := range tempC {
if strings.Contains(tempC.GetMap(k2).GetString("name"), "name") || strings.Contains(tempC.GetMap(k2).GetString("name"), "title") {
v["value"] = tempC.GetMap(k2).GetString("name")
isGet = false
break
}
}
if isGet && len(that.TableConfig.GetMap(tableName).GetSlice("columns")) > 2 {
v["value"] = that.TableConfig.GetMap(tableName).GetSlice("columns").GetMap(1).GetString("name")
continue
}
}
}
//搜索服务
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})
search = append(search, sv)
that.TableConfig.GetMap(fk)["search"] = search
that.SearchColumns[fk][k] = sv
}
//搜索关键字
if strings.Contains(v.GetString("type"), "text") || v.GetString("name") == "id" {
keyWordSearchData := search.GetMap(0)
keyWordSearchData["options"] = append(keyWordSearchData.GetSlice("options"), Map{"name": v.GetString("label"), "value": v.GetString("name")})
search[0] = keyWordSearchData
}
if v.GetString("link") != "" &&
v.GetString("name") != "parent_id" {
keyWordSearchData := search.GetMap(0)
name := strings.Replace(that.TableConfig.GetMap(v.GetString("link")).GetString("label"), "管理", "", -1)
keyWordSearchData["options"] = append(keyWordSearchData.GetSlice("options"), Map{"name": name, "value": v.GetString("name")})
search[0] = keyWordSearchData
}
//搜索时间
if strings.Contains(v.GetString("type"), "time") {
daterangeData := search.GetMap(1)
daterangeData["options"] = append(daterangeData.GetSlice("options"), Map{"name": v.GetString("label"), "value": v.GetString("name")})
search[1] = daterangeData
}
}
}
flow := Map{}
//"user": {"table": "user", "stop": true,
// "SQL": {
// "role_id": "role_id",
// "admin_id": "admin_id",
// "parent_ids": "%,user_id,%"}}
//搜索增加树节点
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
}
//if fk == that.FileConfig.GetString("table") && v["link"] != nil && that.TableColumns[v.GetString("link")]["parent_id"] != nil {
// that.Config["stop"] = append(that.Config.GetSlice("stop"), v.GetString("link"))
// //that.
//}
for _, av := range that.TableColumns[that.FileConfig.GetString("table")] {
//同字段
if av["link"] != nil && av.GetString("link") == v.GetString("link") {
if flow[fk] == nil {
flow[fk] = Map{"table": fk, "stop": false, "sql": Map{}}
}
sql := flow.GetMap(fk).GetMap("sql")
if k == "parent_id" {
sql["parent_ids[~]"] = "," + av.GetString("name") + ","
} else {
sql[k] = k
}
flow.GetMap(fk)["sql"] = sql
}
//同表
if av["link"] != nil && av.GetString("link") == fk {
if flow[fk] == nil {
flow[fk] = Map{"table": fk, "stop": false, "sql": Map{}}
}
ta := flow.GetMap(fk)
ta["stop"] = true
flow[fk] = ta
if k == "id" && that.TableColumns[fk]["parent_id"] == nil {
sql := flow.GetMap(fk).GetMap("sql")
sql[k] = av.GetString("name")
flow.GetMap(fk)["sql"] = sql
}
}
}
if k == that.FileConfig.GetString("table")+"_id" {
if flow[fk] == nil {
flow[fk] = Map{"table": fk, "stop": false, "sql": Map{}}
}
sql := flow.GetMap(fk).GetMap("sql")
sql[k] = "id"
flow.GetMap(fk)["sql"] = sql
}
//当前用户
if k == "parent_id" && that.FileConfig.GetString("table") == fk {
if flow[fk] == nil {
flow[fk] = Map{"table": fk, "stop": false, "sql": Map{}}
}
sql := flow.GetMap(fk).GetMap("sql")
sql["parent_ids[~]"] = ",id,"
flow.GetMap(fk)["sql"] = sql
}
}
}
//fmt.Println(flow)
that.Config["flow"] = flow
//fmt.Println(id, "---", that.Config.GetString("id"))
//that.Config["id"] = id
if config.GetInt("mode") != 0 {
//init文件初始化
//myInit = strings.Replace(myInit, "{{id}}", id, -1)
myInit = strings.Replace(myInit, "{{tablesCtr}}", ctrList, -1)
_ = os.MkdirAll(config.GetString("name"), os.ModeDir)
err = ioutil.WriteFile(config.GetString("name")+"/init.go", []byte(myInit), os.ModePerm)
if err != nil {
that.Log.Error().Err(err).Msg("写入 init.go 失败")
}
}
//配置文件
if config.GetString("configDB") != "" {
that.Config["id"] = id
_ = os.MkdirAll(filepath.Dir(config.GetString("configDB")), os.ModeDir)
err = ioutil.WriteFile(config.GetString("configDB"), []byte(that.Config.ToJsonString()), os.ModePerm)
if err != nil {
that.Log.Error().Err(err).Msg("写入 configDB 文件失败")
}
that.Log.Infof("新建 configDB: %s", config.GetString("configDB"))
}
//不存在配置文件则生成,存在则不管
_, err = ioutil.ReadFile(config.GetString("config"))
if err != nil {
that.Config["id"] = id
_ = os.MkdirAll(filepath.Dir(config.GetString("config")), os.ModeDir)
newConfig := DeepCopyMap(that.Config).(Map)
delete(newConfig, "tables")
err = ioutil.WriteFile(config.GetString("config"), []byte(newConfig.ToJsonString()), os.ModePerm)
if err != nil {
that.Log.Error().Err(err).Msg("写入 config 文件失败")
}
that.Log.Infof("新建 config: %s", config.GetString("config"))
}
//fmt.Println("有新的代码生成,请重新运行")
//os.Exit(-1)
}
func (that *MakeCode) Info(table string, userData Map, db *db.HoTimeDB) (string, Map) {
reStr := ""
data := Map{}
var ruleData Map
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]
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[that.FileConfig.GetString("table")] {
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 {
parent_idsStr := ""
parent_ids := that.TableColumns[v.GetString("link")]["parent_ids"]
if parent_ids != nil {
parent_idsStr = "parent_ids[~]"
}
index := that.TableColumns[v.GetString("link")]["index"]
if index != nil {
parent_idsStr = "index[~]"
}
if v.GetString("name") == "parent_id" {
data[parent_idsStr] = "," + ruleData.GetString(v.GetString("link")) + ","
} else {
idMap := db.Select(v.GetString("link"), "id", Map{parent_idsStr: "," + 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, user Map, 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 || req.FormValue(v.GetString("name")) == "" {
if v["link"] != nil && user[v.GetString("name")] != nil {
data[v.GetString("name")] = user[v.GetString("name")]
continue
}
if that.FileConfig.GetString("table")+"_id" == v.GetString("name") {
data[v.GetString("name")] = user["id"]
continue
}
//if user[v.GetString("name")] != nil {
//
// data[v.GetString("name")] = user[v.GetString("name")]
// continue
//
//}
if v.GetBool("must") {
return nil
} else {
continue
}
}
if req.Form[v.GetString("name")] == nil {
continue
}
reqValue := req.FormValue(v.GetString("name"))
if reqValue == "null" {
data[v.GetString("name")] = nil
continue
}
if v.GetString("type") == "password" {
data[v.GetString("name")] = Md5(reqValue)
continue
}
data[v.GetString("name")] = reqValue
}
//sn则自动生成
if v.GetString("name") == "sn" {
reqValue := req.FormValue(v.GetString("name"))
if reqValue == "" {
data[v.GetString("name")] = Md5(ObjToStr(time.Now().UnixNano()))
} else {
data[v.GetString("name")] = reqValue
}
}
if v.GetString("name") == "create_time" {
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")
}
continue
}
if v.GetString("name") == "modify_time" {
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")
}
}
}
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") {
if len(req.Form[v.GetString("name")]) == 0 {
continue
}
reqValue := req.FormValue(v.GetString("name"))
if reqValue == "null" {
data[v.GetString("name")] = nil
continue
}
if v.GetString("type") == "number" && reqValue == "" {
data[v.GetString("name")] = nil
continue
}
if v.GetString("type") == "password" {
data[v.GetString("name")] = Md5(reqValue)
} else {
data[v.GetString("name")] = reqValue
}
}
if v.GetString("name") == "modify_time" {
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")
}
}
}
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, data Map, req *http.Request, db *db.HoTimeDB) (string, Map) {
reStr := ""
//leftJoin := Map{}
//data := Map{}
if data == nil {
data = Map{}
}
keyword := Map{}
daterange := Map{}
sortMap := Map{}
//var ruleData Map
hasUser := false
keywordStr := req.FormValue("keyword")
keywordTableStr := req.FormValue("keywordtable")
daterangeTableStr := req.FormValue("daterangetable")
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]
//不可使用,未在前端展示,但在内存中保持有
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") + ","
//
// if v.GetString("value") == "name" && that.TableColumns[v.GetString("link")]["nickname"] != nil {
// reStr += v.GetString("link") + ".nickname AS " +
// v.GetString("link") + "_" + v.GetString("name") + "_nickname,"
// }
//
// if that.TableColumns[v.GetString("link")]["phone"] != nil {
// reStr += v.GetString("link") + ".phone AS " +
// v.GetString("link") + "_" + v.GetString("name") + "_phone,"
// }
//
// 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 v.GetString("name") != "parent_id" && reqValue != "" {
data[v.GetString("name")] = reqValue
}
//
//} else {
reStr += "`" + v.GetString("name") + "`,"
//}
//if v["name"] == "parent_id" && v.GetString("link") != "" {
// leftJoin["[>]"+v.GetString("link")+" selfParent"] =
// "selfParent.id=" +
// v.GetString("link") + "." + v.GetString("name")
// reStr += "selfParent." + v.GetString("value") + " AS " + v.GetString("link") + "_" + v.GetString("name") + "_" + v.GetString("value") + ","
//}
//准备加入索引权限
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[that.FileConfig.GetString("table")] {
// 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 {
// parent_idsStr := ""
// parent_ids := that.TableColumns[v.GetString("link")]["parent_ids"]
// if parent_ids != nil {
// parent_idsStr = "parent_ids[~]"
// }
// index := that.TableColumns[v.GetString("link")]["index"]
// if index != nil {
// parent_idsStr = "index[~]"
// }
//
// if v.GetString("name") == "parent_id" {
//
// data[table+"."+parent_idsStr] = "," + ruleData.GetString(v.GetString("link")) + ","
//
// } else {
// idMap := db.Select(v.GetString("link"), "id", Map{parent_idsStr: "," + 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 strings.Contains(v.GetString("type"), "text") {
reqValue := req.FormValue(v.GetString("name"))
if reqValue != "" {
data[v.GetString("name")+"[~]"] = reqValue
}
}
if v.GetString("type") == "unixtime" {
if len(req.Form[v.GetString("name")]) == 1 {
daterange[v.GetString("name")+"[>]"] = req.FormValue("daterange")
} else if len(req.Form[v.GetString("name")]) == 2 {
daterange[v.GetString("name")+"[<>]"] = ObjToSlice(req.Form["daterange"])
}
//fmt.Println(req.Form["daterange"])
}
if v.GetString("type") == "time" {
//fmt.Println(req.Form["daterange"])
if len(req.Form[v.GetString("name")]) == 1 {
t := time.Unix(ObjToCeilInt64(req.FormValue(v.GetString("name"))), 0).Format("2006-01-02 15:04:05")
daterange[v.GetString("name")+"[>]"] = t
} else if len(req.Form[v.GetString("name")]) == 2 {
t1 := time.Unix(ObjToCeilInt64(req.Form[v.GetString("name")][0]), 0).Format("2006-01-02 15:04:05")
t2 := time.Unix(ObjToCeilInt64(req.Form[v.GetString("name")][1]), 0).Format("2006-01-02 15:04:05")
daterange[v.GetString("name")+"[<>]"] = Slice{t1, t2}
}
}
}
if len(reStr) != 0 {
reStr = reStr[:len(reStr)-1]
}
search := that.TableConfig.GetMap(table).GetSlice("search")
for k, _ := range search {
searchItem := search.GetMap(k)
searchItemName := searchItem.GetString("name")
//if data[table+"."+searchItemName] != nil {
// delete(data, table+"."+searchItemName)
//}
reqValue := req.Form[searchItemName]
parent_idsStr := ""
if searchItem.GetString("link") != "" {
parent_ids := that.TableColumns[searchItem.GetString("link")]["parent_ids"]
if parent_ids != nil {
parent_idsStr = "parent_ids[~]"
}
index := that.TableColumns[searchItem.GetString("link")]["index"]
if index != nil {
parent_idsStr = "index[~]"
}
//reqValue := req.FormValue(search.GetMap(k).GetString("name"))
if len(reqValue) == 0 || reqValue[0] == "" {
if parent_idsStr != "" && userData[searchItem.GetString("name")] != nil {
if data[searchItemName] == nil {
continue
}
where := Map{parent_idsStr: "," + ObjToStr(userData.GetCeilInt64(searchItem.GetString("name"))) + ","}
r := db.Select(searchItem.GetString("link"), "id", where)
reqValue = []string{}
for _, v := range r {
reqValue = append(reqValue, v.GetString("id"))
}
data[searchItemName] = reqValue
}
continue
}
}
//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" {
if daterangeTableStr != "" && daterangeTableStr != v.GetString("name") {
continue
}
if v.GetString("type") == "unixtime" {
//fmt.Println(req.Form["daterange"])
if len(req.Form["daterange"]) == 1 && req.Form["daterange"][0] != "" {
daterange[v.GetString("name")+"[>]"] = req.FormValue("daterange")
} else if len(req.Form["daterange"]) == 2 {
daterange[v.GetString("name")+"[<>]"] = ObjToSlice(req.Form["daterange"])
}
}
if v.GetString("type") == "time" {
//fmt.Println(req.Form["daterange"])
if len(req.Form["daterange"]) == 1 && req.Form["daterange"][0] != "" {
t := time.Unix(ObjToCeilInt64(req.FormValue("daterange")), 0).Format("2006-01-02 15:04:05")
daterange[v.GetString("name")+"[>]"] = t
} else if len(req.Form["daterange"]) == 2 {
t1 := time.Unix(ObjToCeilInt64(req.Form["daterange"][0]), 0).Format("2006-01-02 15:04:05")
t2 := time.Unix(ObjToCeilInt64(req.Form["daterange"][1]), 0).Format("2006-01-02 15:04:05")
daterange[v.GetString("name")+"[<>]"] = Slice{t1, t2}
}
}
}
if searchItemName == "keyword" && keywordStr != "" {
if keywordTableStr != "" {
if keywordTableStr == v.GetString("name") {
data[keywordTableStr+"[~]"] = keywordStr
}
if keywordTableStr == v.GetString("value") {
childs := db.Select(v.GetString("link"), "id", Map{v.GetString("value") + "[~]": keywordStr})
childIds := Slice{}
for _, cv := range childs {
childIds = append(childIds, cv.GetCeilInt64("id"))
}
if len(childIds) != 0 {
data[v.GetString("name")] = childIds
}
}
continue
}
if strings.Contains(v.GetString("type"), "text") {
keyword[v.GetString("name")+"[~]"] = keywordStr
}
if v.GetString("name") == "id" {
keyword[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.GetCeilInt64("id"))
}
if len(childIds) != 0 {
keyword[v.GetString("name")] = childIds
}
}
}
}
if len(reqValue) != 0 && searchItem.GetString("name") == "sort" && reqValue[0] != "" {
parts := strings.Fields(reqValue[0])
if len(parts) == 2 {
col := parts[0]
dir := strings.ToUpper(parts[1])
if (dir == "ASC" || dir == "DESC") && that.TableColumns[table][col] != nil {
sortMap["ORDER"] = col + " " + dir
}
}
}
continue
}
//树节点模式搜索
if searchItemName == "parent_id" {
parentID := ObjToInt(req.FormValue("parent_id"))
if parentID == 0 {
parentID = userData.GetCeilInt(table + "_id")
data["OR"] = Map{"id": parentID, "parent_id": nil}
} else {
//是否展示全部子级
where := Map{}
if req.FormValue("showall") == "1" {
for _, v := range reqValue {
if len(where) == 0 {
where[parent_idsStr] = "," + v + ","
continue
}
where = Map{"OR": where, parent_idsStr: "," + v + ","}
}
} else {
where["parent_id"] = reqValue
}
//是否展示自己
if req.FormValue("showself") == "1" {
if len(where) == 0 {
data["OR"] = Map{"id": reqValue}
} else {
data["OR"] = Map{"OR": where, "id": reqValue}
}
} else {
if len(where) != 0 {
data["OR"] = where
}
}
}
continue
}
//如果是树节点则需要判断是否符合权限
if searchItem.GetString("type") == "tree" {
if parent_idsStr != "" {
//where := Map{}
//是否全部展示
if req.FormValue("showall") != "1" {
if len(reqValue) != 0 {
data[searchItem.GetString("name")] = reqValue
}
} else {
ls := []int64{}
for _, v := range reqValue {
ls1 := db.Select(searchItem.GetString("link"), "id", Map{"OR": Map{parent_idsStr: "," + v + ",", "id": v}})
for _, vls1 := range ls1 {
ls = append(ls, vls1.GetCeilInt64("id"))
}
}
if len(ls) != 0 {
data[searchItem.GetString("name")] = ls
}
}
//用户
//if userData[searchItem.GetString("name")] != nil {
//
// where = Map{"AND": Map{searchItem.GetString("link") + "." + parent_idsStr: "," + ObjToStr(userData.GetCeilInt64(searchItem.GetString("name"))) + ",", "OR": where}}
//}
//if len(where)!=0{
// data["OR"] = where
//}
continue
//r := db.Select(searchItem.GetString("link"), "id", where)
//for _, v := range r {
// reqValue = append(reqValue, v.GetString("id"))
//}
}
}
if len(reqValue) != 0 && reqValue[0] != "" {
data[searchItemName] = reqValue
}
}
if sortMap["ORDER"] == nil {
sortMap["ORDER"] = "id DESC"
}
where := Map{}
//if where==nil{
// 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 == nil || len(data) == 0 {
data = Map{"OR": daterange}
} else {
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(sortMap) != 0 {
for k, v := range sortMap {
where[k] = v
}
}
return reStr, where
}