浏览代码

接口修改

yxh 5 年之前
父节点
当前提交
954adb834c
共有 100 个文件被更改,包括 7438 次插入893 次删除
  1. 39 19
      README.MD
  2. 242 67
      app/controller/admin/auth.go
  3. 0 171
      app/controller/admin/cms_menu.go
  4. 0 17
      app/controller/admin/cms_model.go
  5. 0 122
      app/controller/admin/cms_news.go
  6. 66 21
      app/controller/admin/config_dict.go
  7. 8 2
      app/controller/admin/config_params.go
  8. 168 0
      app/controller/admin/dept.go
  9. 189 0
      app/controller/admin/gen_table.go
  10. 52 14
      app/controller/admin/index.go
  11. 11 1
      app/controller/admin/monitor_job.go
  12. 91 0
      app/controller/admin/post.go
  13. 21 0
      app/controller/admin/upload.go
  14. 86 0
      app/controller/admin/user.go
  15. 13 0
      app/controller/front/index.go
  16. 74 18
      app/model/admin/auth_rule/auth_rule.go
  17. 15 13
      app/model/admin/auth_rule/auth_rule_entity.go
  18. 31 6
      app/model/admin/cms_category/cms_category.go
  19. 1 0
      app/model/admin/cms_category/cms_category_entity.go
  20. 32 19
      app/model/admin/cms_news/cms_news.go
  21. 191 0
      app/model/admin/gen_table/gen_table.go
  22. 94 0
      app/model/admin/gen_table/gen_table_entity.go
  23. 373 0
      app/model/admin/gen_table/gen_table_model.go
  24. 97 0
      app/model/admin/gen_table_column/gen_table_column.go
  25. 80 0
      app/model/admin/gen_table_column/gen_table_column_entity.go
  26. 387 0
      app/model/admin/gen_table_column/gen_table_column_model.go
  27. 126 0
      app/model/admin/model_category/model_category.go
  28. 64 0
      app/model/admin/model_category/model_category_entity.go
  29. 357 0
      app/model/admin/model_category/model_category_model.go
  30. 136 0
      app/model/admin/plug_ad/plug_ad.go
  31. 67 0
      app/model/admin/plug_ad/plug_ad_entity.go
  32. 363 0
      app/model/admin/plug_ad/plug_ad_model.go
  33. 136 0
      app/model/admin/plug_adtype/plug_adtype.go
  34. 59 0
      app/model/admin/plug_adtype/plug_adtype_entity.go
  35. 347 0
      app/model/admin/plug_adtype/plug_adtype_model.go
  36. 135 11
      app/model/admin/role/role.go
  37. 8 8
      app/model/admin/role/role_entity.go
  38. 45 33
      app/model/admin/role/role_model.go
  39. 20 0
      app/model/admin/role_dept/role_dept.go
  40. 58 0
      app/model/admin/role_dept/role_dept_entity.go
  41. 345 0
      app/model/admin/role_dept/role_dept_model.go
  42. 7 5
      app/model/admin/sys_config/sys_config.go
  43. 213 0
      app/model/admin/sys_dept/sys_dept.go
  44. 71 0
      app/model/admin/sys_dept/sys_dept_entity.go
  45. 352 0
      app/model/admin/sys_dept/sys_dept_model.go
  46. 6 4
      app/model/admin/sys_dict_data/sys_dict_data.go
  47. 25 2
      app/model/admin/sys_dict_type/sys_dict_type.go
  48. 8 8
      app/model/admin/sys_job/sys_job.go
  49. 2 2
      app/model/admin/sys_login_log/sys_login_log.go
  50. 2 2
      app/model/admin/sys_oper_log/sys_oper_log.go
  51. 151 0
      app/model/admin/sys_post/sys_post.go
  52. 67 0
      app/model/admin/sys_post/sys_post_entity.go
  53. 344 0
      app/model/admin/sys_post/sys_post_model.go
  54. 154 51
      app/model/admin/user/user.go
  55. 3 0
      app/model/admin/user/user_entity.go
  56. 2 2
      app/model/admin/user_online/user_online.go
  57. 57 0
      app/model/admin/user_post/user_post.go
  58. 58 0
      app/model/admin/user_post/user_post_entity.go
  59. 345 0
      app/model/admin/user_post/user_post_model.go
  60. 65 14
      app/service/admin/auth_service/auth_rule.go
  61. 0 86
      app/service/admin/cms_service/menu.go
  62. 0 99
      app/service/admin/cms_service/news.go
  63. 48 0
      app/service/admin/dept_service/dept.go
  64. 22 0
      app/service/admin/dict_service/dict_type.go
  65. 498 0
      app/service/admin/gen_service/table.go
  66. 32 0
      app/service/admin/post_service/post.go
  67. 2 1
      app/service/admin/upload_service/upload.go
  68. 168 6
      app/service/admin/user_service/user.go
  69. 1 0
      app/service/cache_service/cache_values.go
  70. 20 2
      boot/boot.go
  71. 15 6
      config/config.toml
  72. 6 4
      data/db.sql
  73. 2 2
      go.mod
  74. 13 0
      go.sum
  75. 2 1
      hook/hook.go
  76. 13 2
      library/service/service.go
  77. 35 31
      middleWare/middleware.go
  78. 二进制
      public/resource/favicon.ico
  79. 0 0
      public/resource/index.html
  80. 0 1
      public/resource/static/css/403.c0a72452.css
  81. 0 1
      public/resource/static/css/404.1ecdb1c9.css
  82. 0 0
      public/resource/static/css/app.09dd2287.css
  83. 0 0
      public/resource/static/css/app.f8955b3b.css
  84. 0 1
      public/resource/static/css/chart.97ce4739.css
  85. 0 0
      public/resource/static/css/chunk-357f68a8.9e95771d.css
  86. 0 0
      public/resource/static/css/chunk-37ac3920.a257c198.css
  87. 1 0
      public/resource/static/css/chunk-680f17d1.8c5edb5c.css
  88. 1 0
      public/resource/static/css/chunk-68d5bf9e.3c72d4e5.css
  89. 0 0
      public/resource/static/css/chunk-768fe99a.af7d13f9.css
  90. 0 0
      public/resource/static/css/chunk-libs.da13e127.css
  91. 0 0
      public/resource/static/css/chunk-vendors.1aeb5dfd.css
  92. 0 1
      public/resource/static/css/dashboard.00d1b39a.css
  93. 0 0
      public/resource/static/css/donate.b4c4bd8b.css
  94. 0 12
      public/resource/static/css/donate~editor.1f0a25b2.css
  95. 0 1
      public/resource/static/css/drag.1e417d77.css
  96. 0 1
      public/resource/static/css/editor.ba996960.css
  97. 0 0
      public/resource/static/css/home.32cf4d8d.css
  98. 0 1
      public/resource/static/css/i18n.01cc2333.css
  99. 0 1
      public/resource/static/css/icon.3b04e6fe.css
  100. 0 1
      public/resource/static/css/login.2ad1457b.css

+ 39 - 19
README.MD

@@ -1,19 +1,24 @@
 ## 平台简介
 基于GF(Go Frame)的后台管理系统
-参考后台模板[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
+
 
 ## 内置功能
 
 1.  用户管理:用户是系统操作者,该功能主要完成系统用户配置。
-2.  角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
-3.  字典管理:对系统中经常使用的一些较为固定的数据进行维护。
-4.  参数管理:对系统动态配置常用参数。
-5.  操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
-6. 登录日志:系统登录日志记录查询包含登录异常。
-7. 在线用户:当前系统中活跃用户状态监控。
-8. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
-9. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
-10. 栏目信息发布,文件上传,缓存标签等
+2.  部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
+3.  岗位管理:配置系统用户所属担任职务。
+4.  菜单管理:配置系统菜单,操作权限,按钮权限标识等。
+5.  角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
+6.  字典管理:对系统中经常使用的一些较为固定的数据进行维护。
+7.  参数管理:对系统动态配置常用参数。
+8.  操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
+9. 登录日志:系统登录日志记录查询包含登录异常。
+10. 在线用户:当前系统中活跃用户状态监控。
+11. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
+12. 代码生成:前后端代码的生成。
+13. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
+14. 在线构建器:拖动表单元素生成相应的HTML代码。
+15. 文件上传,缓存标签等。
 
 ## 演示地址
 [http://47.107.158.252:8200/](http://47.107.158.252:8200/)
@@ -39,24 +44,39 @@ go run main.go 直接访问http://localhost:8200
 
 账号:demo  密码:123456
 
-项目为前后端分离,前端地址:[vue-gfast-admin](https://gitee.com/tiger1103/vue-gfast-admin)
+项目为前后端分离,前端地址:[gfast-ui](https://github.com/tiger1103/gfast-ui)
 
-##接口文件
-gfast.postman_collection.json 导入postman
 
 ## 演示图
 
 <table>
     <tr>
-        <td><img src="https://images.gitee.com/uploads/images/2020/0331/155731_5194c2c1_142572.png"/></td>
-        <td><img src="https://images.gitee.com/uploads/images/2020/0331/155825_773ca447_142572.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/cd1f90be5f2684f4560c9519c0f2a232ee8.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/707825ad3f29de74a8d6d02fbd73ad631ea.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/46be40cc6f01aa300eed53a19b5012bf484.jpg"/></td>
     </tr>
     <tr>
-        <td><img src="https://images.gitee.com/uploads/images/2020/0331/155850_783d7f42_142572.png"/></td>
-        <td><img src="https://images.gitee.com/uploads/images/2020/0331/155912_0ec85d71_142572.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/4284796d4cea240d181b8f2201813dda710.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/3ecfac87a049f7fe36abbcaafb2c40d36cf.jpg"/></td>
     </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/71c2d48905221a09a728df4aff4160b8607.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/c14c1ee9a64a6a9c2c22f67d43198767dbe.jpg"/></td>
+    </tr>	 
     <tr>
-        <td><img src="https://images.gitee.com/uploads/images/2020/0331/155931_72589aa0_142572.png"/></td>
-        <td><img src="https://images.gitee.com/uploads/images/2020/0331/155943_e3f15335_142572.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
+    </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/fdea1d8bb8625c27bf964176a2c8ebc6945.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/509d2708cfd762b6e6339364cac1cc1970c.jpg"/></td>
+    </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-f1fd681cc9d295db74e85ad6d2fe4389454.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
     </tr>
 </table>
+

+ 242 - 67
app/controller/admin/auth.go

@@ -4,8 +4,13 @@ import (
 	"fmt"
 	"gfast/app/model/admin/auth_rule"
 	"gfast/app/model/admin/role"
+	"gfast/app/model/admin/sys_dept"
 	"gfast/app/model/admin/user"
+	"gfast/app/model/admin/user_post"
 	"gfast/app/service/admin/auth_service"
+	"gfast/app/service/admin/dept_service"
+	"gfast/app/service/admin/dict_service"
+	"gfast/app/service/admin/post_service"
 	"gfast/app/service/admin/user_service"
 	"gfast/app/service/cache_service"
 	"gfast/app/service/casbin_adapter_service"
@@ -23,16 +28,46 @@ type Auth struct{}
 
 //菜单列表
 func (c *Auth) MenuList(r *ghttp.Request) {
-	//获取菜单信息
-	listEntities, err := auth_service.GetMenuList()
+	var req *auth_rule.ReqSearch
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+	}
+	var listEntities []*auth_rule.Entity
+	var err error
+	if req != nil {
+		listEntities, err = auth_service.GetMenuListSearch(req)
+	} else {
+		//获取菜单信息
+		listEntities, err = auth_service.GetMenuList()
+	}
 	if err != nil {
 		g.Log().Error(err)
 		response.FailJson(true, r, "获取数据失败")
 	}
 	list := gconv.SliceMap(listEntities)
-	list = utils.PushSonToParent(list)
+	if req != nil {
+		for k := range list {
+			list[k]["children"] = nil
+		}
+	} else {
+		list = utils.PushSonToParent(list, 0, "pid", "id", "children", "", nil, true)
+	}
+	//菜单显示状态
+	visibleOptions, err := dict_service.GetDictWithDataByType("sys_show_hide", "", "")
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	//菜单正常or停用状态
+	statusOptions, err := dict_service.GetDictWithDataByType("sys_normal_disable", "", "")
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+
 	response.SusJson(true, r, "成功", g.Map{
-		"list": list,
+		"list":           list,
+		"visibleOptions": visibleOptions,
+		"statusOptions":  statusOptions,
 	})
 }
 
@@ -61,6 +96,10 @@ func (c *Auth) AddMenu(r *ghttp.Request) {
 		if !auth_service.CheckMenuNameUnique(menu.Name, 0) {
 			response.FailJson(true, r, "菜单规则名称已经存在")
 		}
+		//判断路由是否已经存在
+		if !auth_service.CheckMenuPathUnique(menu.Path, 0) {
+			response.FailJson(true, r, "路由地址已经存在")
+		}
 		//保存到数据库
 		err, _ := auth_service.AddMenu(menu)
 		if err != nil {
@@ -76,14 +115,12 @@ func (c *Auth) AddMenu(r *ghttp.Request) {
 	if err != nil {
 		response.FailJson(true, r, "获取数据失败")
 	}
-	list := gconv.SliceMap(listEntities)
-	list = utils.ParentSonSort(list)
-	response.SusJson(true, r, "成功", g.Map{"parentList": list})
+	response.SusJson(true, r, "成功", g.Map{"parentList": listEntities})
 }
 
 //修改菜单
 func (c *Auth) EditMenu(r *ghttp.Request) {
-	id := r.GetInt("id")
+	id := r.GetInt("menuId")
 	if r.Method == "POST" {
 		menu := new(auth_rule.MenuReq)
 		if err := r.Parse(menu); err != nil {
@@ -93,6 +130,10 @@ func (c *Auth) EditMenu(r *ghttp.Request) {
 		if !auth_service.CheckMenuNameUnique(menu.Name, id) {
 			response.FailJson(true, r, "菜单规则名称已经存在")
 		}
+		//判断路由是否已经存在
+		if !auth_service.CheckMenuPathUnique(menu.Path, id) {
+			response.FailJson(true, r, "路由地址已经存在")
+		}
 		//保存到数据库
 		err, _ := auth_service.EditMenu(menu, id)
 		if err != nil {
@@ -139,16 +180,27 @@ func (c *Auth) DeleteMenu(r *ghttp.Request) {
 
 //角色列表
 func (c *Auth) RoleList(r *ghttp.Request) {
+	var req *role.SelectPageReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+	}
 	//获取角色列表
-	listEntities, err := auth_service.GetRoleList()
+	total, page, list, err := auth_service.GetRoleListSearch(req)
 	if err != nil {
 		g.Log().Error(err)
 		response.FailJson(true, r, "获取数据失败")
 	}
-	list := gconv.SliceMap(listEntities)
-	list = utils.PushSonToParent(list, 0, "parent_id", "id", "children", "", nil, false)
+	//菜单正常or停用状态
+	statusOptions, err := dict_service.GetDictWithDataByType("sys_normal_disable", "", "")
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
 	response.SusJson(true, r, "成功", g.Map{
-		"list": list,
+		"currentPage": page,
+		"total":       total,
+		"list":        list,
+		"searchTypes": statusOptions,
 	})
 }
 
@@ -158,6 +210,7 @@ func (c *Auth) AddRole(r *ghttp.Request) {
 	if r.Method == "POST" {
 		//获取表单提交的数据
 		res := r.GetFormMap()
+
 		tx, err := g.DB("default").Begin() //开启事务
 		if err != nil {
 			g.Log().Error(err)
@@ -171,43 +224,43 @@ func (c *Auth) AddRole(r *ghttp.Request) {
 			response.FailJson(true, r, err.Error())
 		}
 		//添加角色权限
-		err = auth_service.AddRoleRule(res["rule"], insertId)
+		err = auth_service.AddRoleRule(res["menuIds"], insertId)
 		if err != nil {
 			tx.Rollback() //回滚
 			g.Log().Error(err.Error())
-			response.FailJson(true, r, "添加用户组失败")
+			response.FailJson(true, r, "添加角色失败")
 		}
 		tx.Commit()
 		//清除TAG缓存
 		cache_service.New().RemoveByTag(cache_service.AdminAuthTag)
-		response.SusJson(true, r, "添加用户组成功")
+		response.SusJson(true, r, "添加角色成功")
 	}
-	//获取父级组
-	pListEntities, err := auth_service.GetRoleList()
-	if err != nil {
-		g.Log().Error(err)
-		response.FailJson(true, r, "获取父级数据失败")
-	}
-	pList := gconv.SliceMap(pListEntities)
-	pList = utils.ParentSonSort(pList, 0, 0, "parent_id", "id", "flg", "name")
+
 	//获取菜单信息
 	mListEntities, err := auth_service.GetMenuList()
 	if err != nil {
 		g.Log().Error(err)
 		response.FailJson(true, r, "获取菜单数据失败")
 	}
-	mList := gconv.SliceMap(mListEntities)
+	var mList g.ListStrAny
+	for _, entity := range mListEntities {
+		m := g.Map{
+			"id":    entity.Id,
+			"pid":   entity.Pid,
+			"label": entity.Title,
+		}
+		mList = append(mList, m)
+	}
 	mList = utils.PushSonToParent(mList)
 	res := g.Map{
-		"parentList": pList,
-		"menuList":   mList,
+		"menuList": mList,
 	}
 	response.SusJson(true, r, "成功", res)
 }
 
 //修改角色
 func (c *Auth) EditRole(r *ghttp.Request) {
-	id := r.GetRequestInt64("id")
+	id := r.GetRequestInt64("roleId")
 	if r.Method == "POST" {
 		//获取表单提交的数据
 		res := r.GetFormMap()
@@ -223,7 +276,7 @@ func (c *Auth) EditRole(r *ghttp.Request) {
 			response.FailJson(true, r, err.Error())
 		}
 		//添加角色权限
-		err = auth_service.EditRoleRule(res["rule"], id)
+		err = auth_service.EditRoleRule(res["menuIds"], id)
 		if err != nil {
 			tx.Rollback() //回滚
 			g.Log().Error(err.Error())
@@ -239,14 +292,7 @@ func (c *Auth) EditRole(r *ghttp.Request) {
 	if err != nil {
 		response.FailJson(true, r, "获取角色数据失败")
 	}
-	//获取父级组
-	pListEntities, err := auth_service.GetRoleList()
-	if err != nil {
-		g.Log().Error(err)
-		response.FailJson(true, r, "获取父级数据失败")
-	}
-	pList := gconv.SliceMap(pListEntities)
-	pList = utils.ParentSonSort(pList, 0, 0, "parent_id", "id", "flg", "name")
+
 	//获取菜单信息
 	mListEntities, err := auth_service.GetMenuList()
 	if err != nil {
@@ -264,10 +310,19 @@ func (c *Auth) EditRole(r *ghttp.Request) {
 	for k, v := range gp {
 		gpSlice[k] = gconv.Int(gstr.SubStr(v[1], 2))
 	}
-	mList := gconv.SliceMap(mListEntities)
+
+	var mList g.ListStrAny
+	for _, entity := range mListEntities {
+		m := g.Map{
+			"id":    entity.Id,
+			"pid":   entity.Pid,
+			"label": entity.Title,
+		}
+		mList = append(mList, m)
+	}
+
 	mList = utils.PushSonToParent(mList)
 	res := g.Map{
-		"parentList":   pList,
 		"menuList":     mList,
 		"role":         role,
 		"checkedRules": gpSlice,
@@ -293,17 +348,27 @@ func (c *Auth) DeleteRole(r *ghttp.Request) {
 //添加管理员
 func (c *Auth) AddUser(r *ghttp.Request) {
 	if r.Method == "POST" {
-		requestData := r.GetFormMap()
-		InsertId, err := auth_service.AddUser(requestData)
+		var req *user.AddUserReq
+		if err := r.Parse(&req); err != nil {
+			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+		}
+
+		InsertId, err := auth_service.AddUser(req)
 		if err != nil {
 			response.FailJson(true, r, err.Error())
 		}
 		//设置用户所属角色信息
-		err = auth_service.AddUserRole(requestData["role_id"], InsertId)
+		err = auth_service.AddUserRole(req.PostIds, InsertId)
 		if err != nil {
 			g.Log().Error(err)
 			response.FailJson(true, r, "设置用户权限失败")
 		}
+		//设置用户岗位
+		err = auth_service.AddUserPost(req.PostIds, InsertId)
+		if err != nil {
+			g.Log().Error(err)
+			response.FailJson(true, r, "设置用户岗位信息失败")
+		}
 		response.SusJson(true, r, "添加管理员成功")
 	}
 	//获取角色信息
@@ -312,31 +377,44 @@ func (c *Auth) AddUser(r *ghttp.Request) {
 		g.Log().Error(err)
 		response.FailJson(true, r, "获取角色数据失败")
 	}
-	roleList := gconv.SliceMap(roleListEntities)
-	roleList = utils.ParentSonSort(roleList, 0, 0, "parent_id", "id", "flg", "name")
+	//获取岗位信息
+	posts, err := post_service.GetUsedPost()
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
 	res := g.Map{
-		"roleList": roleList,
+		"roleList": roleListEntities,
+		"posts":    posts,
 	}
 	response.SusJson(true, r, "成功", res)
 }
 
 //修改管理员
 func (c *Auth) EditUser(r *ghttp.Request) {
-	id := r.GetRequestInt("id")
 	if r.Method == "POST" {
-		requestData := r.GetFormMap()
-		err := auth_service.EditUser(requestData)
+		var req *user.EditUserReq
+		if err := r.Parse(&req); err != nil {
+			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+		}
+		err := auth_service.EditUser(req)
 		if err != nil {
 			response.FailJson(true, r, err.Error())
 		}
 		//设置用户所属角色信息
-		err = auth_service.EditUserRole(requestData["role_id"], id)
+		err = auth_service.EditUserRole(req.RoleIds, req.UserId)
 		if err != nil {
 			g.Log().Error(err)
 			response.FailJson(true, r, "设置用户权限失败")
 		}
+		//设置用户岗位数据
+		err = auth_service.AddUserPost(req.PostIds, gconv.Int64(req.UserId))
+		if err != nil {
+			g.Log().Error(err)
+			response.FailJson(true, r, "设置用户岗位信息失败")
+		}
 		response.SusJson(true, r, "修改管理员成功")
 	}
+	id := r.GetRequestInt("id")
 	//用户用户信息
 	userEntity, err := user.Model.Where("id=?", id).One()
 	if err != nil {
@@ -349,34 +427,46 @@ func (c *Auth) EditUser(r *ghttp.Request) {
 		g.Log().Error(err)
 		response.FailJson(true, r, "获取角色数据失败")
 	}
-	roleList := gconv.SliceMap(roleListEntities)
-	roleList = utils.ParentSonSort(roleList, 0, 0, "parent_id", "id", "flg", "name")
+
 	//获取已选择的角色信息
 	checkedRoleIds, err := user_service.GetAdminRoleIds(id)
 	if err != nil {
 		g.Log().Error(err)
 		response.FailJson(true, r, "获取用户角色数据失败")
 	}
+	if checkedRoleIds == nil {
+		checkedRoleIds = g.SliceInt{}
+	}
+	//获取岗位信息
+	posts, err := post_service.GetUsedPost()
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	checkedPosts, err := user_service.GetAdminPosts(id)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	if checkedPosts == nil {
+		checkedPosts = []int64{}
+	}
 	res := g.Map{
-		"roleList":       roleList,
+		"roleList":       roleListEntities,
 		"userInfo":       userEntity,
 		"checkedRoleIds": checkedRoleIds,
+		"posts":          posts,
+		"checkedPosts":   checkedPosts,
 	}
 	response.SusJson(true, r, "成功", res)
 }
 
 //用户列表
 func (c *Auth) UserList(r *ghttp.Request) {
-	keyWords := r.GetString("keywords")
-	page := r.GetInt("page")
-	if page == 0 {
-		page = 1
-	}
-	var where = map[string]interface{}{}
-	if keyWords != "" {
-		where["keyWords"] = keyWords
+	var req *user.SearchReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
 	}
-	total, userList, err := user_service.GetAdminList(where, page)
+	total, page, userList, err := user_service.GetAdminList(req)
 	if err != nil {
 		g.Log().Error(err)
 		response.FailJson(true, r, "获取用户列表数据失败")
@@ -388,25 +478,49 @@ func (c *Auth) UserList(r *ghttp.Request) {
 		g.Log().Error(err)
 		response.FailJson(true, r, "获取用户角色数据失败")
 	}
+	//获取所有部门信息
+	depts, err := dept_service.GetList(&sys_dept.SearchParams{})
+	if err != nil {
+		g.Log().Error(err)
+		response.FailJson(true, r, "获取部门数据失败")
+	}
 	for k, u := range userList {
+		var dept *sys_dept.Dept
 		users[k] = gconv.Map(u)
+		for _, d := range depts {
+			if u.DeptId == d.DeptID {
+				dept = d
+			}
+		}
+		users[k]["dept"] = dept
 		roles, err := user_service.GetAdminRole(u.Id, allRoles)
 		if err != nil {
 			g.Log().Error(err)
 			response.FailJson(true, r, "获取用户角色数据失败")
 		}
-		roleInfo := make(map[int]string, len(roles))
+		roleInfo := make([]g.Map, 0, len(roles))
 		for _, r := range roles {
-			roleInfo[r.Id] = r.Name
+			roleInfo = append(roleInfo, g.Map{"roleId": r.Id, "name": r.Name})
 		}
+		users[k]["user_status"] = gconv.String(u.UserStatus)
 		users[k]["roleInfo"] = roleInfo
 	}
-	//获取用户对应角色
-
+	//用户状态
+	statusOptions, err := dict_service.GetDictWithDataByType("sys_normal_disable", "", "")
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	//用户性别
+	userGender, err := dict_service.GetDictWithDataByType("sys_user_sex", "", "")
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
 	res := g.Map{
-		"total":       total,
-		"currentPage": page,
-		"userList":    users,
+		"total":         total,
+		"currentPage":   page,
+		"userList":      users,
+		"statusOptions": statusOptions,
+		"userGender":    userGender,
 	}
 	response.SusJson(true, r, "成功", res)
 }
@@ -430,5 +544,66 @@ func (c *Auth) DeleteAdmin(r *ghttp.Request) {
 			enforcer.RemoveFilteredGroupingPolicy(0, fmt.Sprintf("u_%d", v))
 		}
 	}
+	//删除用户对应的岗位
+	_, err = user_post.Delete(user_post.Columns.UserId+" in (?)", ids)
+	if err != nil {
+		g.Log().Error(err)
+	}
 	response.SusJson(true, r, "删除成功")
 }
+
+//设置角色状态
+func (c *Auth) StatusSetRole(r *ghttp.Request) {
+	var req *role.StatusSetReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+	}
+	err := auth_service.StatusSetRole(req)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	response.SusJson(true, r, "状态设置成功")
+}
+
+//角色数据权限分配
+func (c *Auth) RoleDataScope(r *ghttp.Request) {
+	var req *role.DataScopeReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+	}
+	err := auth_service.RoleDataScope(req)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	response.SusJson(true, r, "数据权限设置成功", req)
+}
+
+//修改用户状态
+func (c *Auth) ChangeUserStatus(r *ghttp.Request) {
+	var req *user.StatusReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+	}
+	if err := user_service.ChangeUserStatus(req); err != nil {
+		response.FailJson(true, r, err.Error())
+	} else {
+		response.SusJson(true, r, "用户状态设置成功")
+	}
+}
+
+//重置用户密码
+func (c *Auth) ResetUserPwd(r *ghttp.Request) {
+	var req *user.ResetPwdReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+	}
+	if err := user_service.ResetUserPwd(req); err != nil {
+		response.FailJson(true, r, err.Error())
+	} else {
+		response.SusJson(true, r, "用户密码重置成功")
+	}
+}

+ 0 - 171
app/controller/admin/cms_menu.go

@@ -1,171 +0,0 @@
-package admin
-
-import (
-	"gfast/app/model/admin/cms_category"
-	"gfast/app/service/admin/cms_service"
-	"gfast/app/service/admin/dict_service"
-	"gfast/app/service/cache_service"
-	"gfast/library/response"
-	"gfast/library/utils"
-	"github.com/gogf/gf/frame/g"
-	"github.com/gogf/gf/net/ghttp"
-	"github.com/gogf/gf/util/gconv"
-	"github.com/gogf/gf/util/gvalid"
-)
-
-//cms栏目管理
-type CmsMenu struct{}
-
-func (c *CmsMenu) List(r *ghttp.Request) {
-	var req *cms_category.ReqSearchList
-	//获取参数
-	if err := r.Parse(&req); err != nil {
-		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
-	}
-	var menus []*cms_category.Entity
-	var err error
-	var list g.List
-	if req != nil && req.Name != "" {
-		//按栏目名搜索
-		menus, err = cms_service.GetMenuListSearch(req)
-		if err != nil {
-			response.FailJson(true, r, err.Error())
-		}
-		list = gconv.Maps(menus)
-	} else {
-		//获取所有栏目
-		menus, err = cms_service.GetMenuList()
-		if err != nil {
-			response.FailJson(true, r, err.Error())
-		}
-		list = gconv.Maps(menus)
-		list = utils.PushSonToParent(list, 0, "parent_id")
-	}
-	res := g.Map{
-		"list": list,
-	}
-	response.SusJson(true, r, "ok", res)
-}
-
-//添加栏目分类
-func (c *CmsMenu) Add(r *ghttp.Request) {
-	if r.Method == "POST" {
-		var req *cms_category.ReqAdd
-		//获取参数
-		if err := r.Parse(&req); err != nil {
-			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
-		}
-		_, err := cms_service.AddSave(req)
-		if err != nil {
-			response.FailJson(true, r, err.Error())
-		}
-		cache_service.New().RemoveByTag(cache_service.AdminCmsTag)
-		response.SusJson(true, r, "栏目添加成功")
-	}
-	//获取上级分类(频道)
-	menus, err := cms_service.GetMenuListChannel()
-	if err != nil {
-		response.FailJson(true, r, err.Error())
-	}
-	menuTop := []*cms_category.Entity{
-		{
-			Id:       0,
-			ParentId: -1,
-			Status:   1,
-			Name:     "最顶级",
-			CateType: 1,
-		},
-	}
-	menus = append(menuTop, menus...)
-	list := gconv.Maps(menus)
-	list = utils.PushSonToParent(list, -1, "parent_id")
-	typeChecker, err := dict_service.GetDictWithDataByType("cms_category_type", "", "")
-	if err != nil {
-		response.FailJson(true, r, err.Error())
-	}
-	res := g.Map{
-		"menus":       list,
-		"typeChecker": typeChecker,
-	}
-	response.SusJson(true, r, "添加栏目", res)
-}
-
-//修改栏目
-func (c *CmsMenu) Edit(r *ghttp.Request) {
-	if r.Method == "POST" {
-		var req *cms_category.ReqEdit
-		//获取参数
-		if err := r.Parse(&req); err != nil {
-			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
-		}
-		_, err := cms_service.EditSave(req)
-		if err != nil {
-			response.FailJson(true, r, err.Error())
-		}
-		cache_service.New().RemoveByTag(cache_service.AdminCmsTag)
-		response.SusJson(true, r, "栏目修改成功")
-	}
-	//获取栏目数据
-	id := r.GetInt("id")
-	menuInfo, err := cms_service.GetMenuInfoById(id)
-	if err != nil {
-		response.FailJson(true, r, err.Error())
-	}
-	if menuInfo == nil {
-		response.FailJson(true, r, "参数错误")
-	}
-	//获取上级分类(频道)
-	menus, err := cms_service.GetMenuListChannel()
-	if err != nil {
-		response.FailJson(true, r, err.Error())
-	}
-	menuTop := []*cms_category.Entity{
-		{
-			Id:       0,
-			ParentId: -1,
-			Status:   1,
-			Name:     "最顶级",
-			CateType: 1,
-		},
-	}
-	menus = append(menuTop, menus...)
-	list := gconv.Maps(menus)
-	list = utils.PushSonToParent(list, -1, "parent_id")
-	typeChecker, err := dict_service.GetDictWithDataByType("cms_category_type", gconv.String(menuInfo.CateType), "")
-	if err != nil {
-		response.FailJson(true, r, err.Error())
-	}
-
-	res := g.Map{
-		"menuInfo":    menuInfo,
-		"menus":       list,
-		"typeChecker": typeChecker,
-	}
-	response.SusJson(true, r, "修改栏目", res)
-}
-
-//栏目排序
-func (c *CmsMenu) Sort(r *ghttp.Request) {
-	sorts := r.Get("sorts")
-	s := gconv.Map(sorts)
-	if s == nil {
-		response.FailJson(true, r, "排序失败")
-	}
-	for k, v := range s {
-		cms_category.Model.Where("id=?", k).Data("list_order", v).Update()
-	}
-	cache_service.New().RemoveByTag(cache_service.AdminCmsTag)
-	response.SusJson(true, r, "排序成功")
-}
-
-func (c *CmsMenu) Delete(r *ghttp.Request) {
-	ids := r.GetInts("ids")
-	if len(ids) == 0 {
-		response.FailJson(true, r, "删除失败")
-	}
-	err := cms_service.DeleteMenuByIds(ids)
-	if err != nil {
-		response.FailJson(true, r, "删除失败")
-	}
-	response.SusJson(true, r, "删除信息成功", ids)
-}

+ 0 - 17
app/controller/admin/cms_model.go

@@ -1,17 +0,0 @@
-package admin
-
-import (
-	"gfast/library/response"
-	"github.com/gogf/gf/net/ghttp"
-)
-
-type CmsModel struct{}
-
-func (c *CmsModel) List(r *ghttp.Request) {
-	response.FailJson(true, r, "功能开发中...")
-}
-
-//添加模型
-func (c *CmsModel) Add(r *ghttp.Request) {
-	response.FailJson(true, r, "功能开发中...")
-}

+ 0 - 122
app/controller/admin/cms_news.go

@@ -1,122 +0,0 @@
-package admin
-
-import (
-	"gfast/app/model/admin/cms_news"
-	"gfast/app/service/admin/cms_service"
-	"gfast/app/service/admin/user_service"
-	"gfast/library/response"
-	"gfast/library/utils"
-	"github.com/gogf/gf/frame/g"
-	"github.com/gogf/gf/net/ghttp"
-	"github.com/gogf/gf/util/gvalid"
-)
-
-type CmsNews struct{}
-
-//信息列表
-func (c *CmsNews) List(r *ghttp.Request) {
-	var req *cms_news.ReqListSearchParams
-	//获取参数
-	if err := r.Parse(&req); err != nil {
-		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
-	}
-	total, page, list, err := cms_service.NewsListByPage(req)
-	if err != nil {
-		response.FailJson(true, r, err.Error())
-	}
-	//获取可选栏目
-	menus, err := cms_service.GetPublishableMenuList(req.CateId...)
-	if err != nil {
-		response.FailJson(true, r, err.Error())
-	}
-	menus = utils.PushSonToParent(menus, 0, "parent_id")
-	result := g.Map{
-		"currentPage": page,
-		"total":       total,
-		"list":        list,
-		"menus":       menus,
-	}
-	response.SusJson(true, r, "信息列表", result)
-}
-
-//添加信息
-func (c *CmsNews) Add(r *ghttp.Request) {
-	if r.Method == "POST" {
-		var req *cms_news.ReqAddParams
-		//获取参数
-		if err := r.Parse(&req); err != nil {
-			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
-		}
-		cateIds := r.GetInts("cateIds")
-		userId := user_service.GetLoginID(r)
-		_, err := cms_service.AddNews(req, cateIds, userId)
-		if err != nil {
-			response.FailJson(true, r, err.Error())
-		}
-		response.SusJson(true, r, "添加信息成功")
-	}
-	//获取可选栏目
-	menus, err := cms_service.GetPublishableMenuList()
-	if err != nil {
-		response.FailJson(true, r, err.Error())
-	}
-	menus = utils.PushSonToParent(menus, 0, "parent_id")
-	res := g.Map{
-		"menus": menus,
-	}
-	response.SusJson(true, r, "添加信息", res)
-}
-
-//修改信息
-func (c *CmsNews) Edit(r *ghttp.Request) {
-	if r.Method == "POST" {
-		var req *cms_news.ReqEditParams
-		//获取参数
-		if err := r.Parse(&req); err != nil {
-			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
-		}
-		cateIds := r.GetInts("cateIds")
-		err := cms_service.EditNews(req, cateIds)
-		if err != nil {
-			response.FailJson(true, r, err.Error())
-		}
-		response.SusJson(true, r, "修改信息成功")
-	}
-	id := r.GetInt("id")
-	if id == 0 {
-		response.FailJson(true, r, "参数错误")
-	}
-	//获取文章信息
-	news, err := cms_service.GetNewsById(id)
-	if err != nil {
-		response.FailJson(true, r, err.Error())
-	}
-	checkedCategoryId, err := cms_service.GetCheckedCategoryIdByNewsId(news.Id)
-	if err != nil {
-		response.FailJson(true, r, err.Error())
-	}
-	//获取可选栏目
-	menus, err := cms_service.GetPublishableMenuList(checkedCategoryId...)
-	if err != nil {
-		response.FailJson(true, r, err.Error())
-	}
-	menus = utils.PushSonToParent(menus, 0, "parent_id")
-	res := g.Map{
-		"menus": menus,
-		"news":  news,
-	}
-	response.SusJson(true, r, "添加信息", res)
-}
-
-//删除信息
-func (c *CmsNews) Delete(r *ghttp.Request) {
-	ids := r.GetInts("ids")
-	if len(ids) == 0 {
-		response.FailJson(true, r, "删除失败")
-	}
-	err := cms_service.DeleteCmsByIds(ids)
-	if err != nil {
-		response.FailJson(true, r, "删除失败")
-	}
-	response.SusJson(true, r, "删除信息成功")
-}

+ 66 - 21
app/controller/admin/config_dict.go

@@ -5,6 +5,7 @@ import (
 	"gfast/app/model/admin/sys_dict_type"
 	"gfast/app/service/admin/dict_service"
 	"gfast/app/service/admin/user_service"
+	"gfast/app/service/cache_service"
 	"gfast/library/response"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/net/ghttp"
@@ -25,11 +26,16 @@ func (c *Dict) List(r *ghttp.Request) {
 	if err != nil {
 		response.FailJson(true, r, err.Error())
 	}
+	//菜单正常or停用状态
+	statusOptions, err := dict_service.GetDictWithDataByType("sys_normal_disable", "", "")
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
 	result := g.Map{
 		"currentPage":  page,
 		"total":        total,
 		"list":         list,
-		"searchStatus": map[string]string{"": "所有", "0": "停用", "1": "正常"},
+		"searchStatus": statusOptions,
 	}
 	response.SusJson(true, r, "字典列表", result)
 }
@@ -51,6 +57,8 @@ func (c *Dict) Add(r *ghttp.Request) {
 			g.Log().Error(err.Error())
 			response.FailJson(true, r, "字典类型添加失败")
 		}
+		//清除tag缓存
+		cache_service.New().RemoveByTag(cache_service.AdminSysConfigTag)
 		response.SusJson(true, r, "添加字典成功")
 	}
 }
@@ -71,14 +79,16 @@ func (c *Dict) Edit(r *ghttp.Request) {
 		if err != nil {
 			response.FailJson(true, r, err.Error())
 		}
+		//清除tag缓存
+		cache_service.New().RemoveByTag(cache_service.AdminSysConfigTag)
 		response.SusJson(true, r, "修改成功")
 	}
-	id := r.GetInt("id")
+	id := r.GetInt("dictId")
 	entity, err := dict_service.GetDictById(id)
 	if err != nil {
-		response.FailJson(true, r, "字典类型添加失败")
+		response.FailJson(true, r, "字典数据获取失败")
 	}
-	response.SusJson(true, r, "ok", g.Map{"dict": entity})
+	response.SusJson(true, r, "ok", entity)
 }
 
 //字典数据列表
@@ -93,11 +103,18 @@ func (c *Dict) DataList(r *ghttp.Request) {
 	if err != nil {
 		response.FailJson(true, r, err.Error())
 	}
+
+	//菜单正常or停用状态
+	statusOptions, err := dict_service.GetDictWithDataByType("sys_normal_disable", "", "")
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+
 	result := g.Map{
 		"currentPage":  page,
 		"total":        total,
 		"list":         list,
-		"searchStatus": map[string]string{"": "所有", "0": "停用", "1": "正常"},
+		"searchStatus": statusOptions,
 	}
 	response.SusJson(true, r, "ok", result)
 }
@@ -115,15 +132,10 @@ func (c *Dict) DataAdd(r *ghttp.Request) {
 		if err != nil {
 			response.FailJson(true, r, err.Error())
 		}
+		//清除tag缓存
+		cache_service.New().RemoveByTag(cache_service.AdminSysConfigTag)
 		response.SusJson(true, r, "添加字典数据成功")
 	}
-	dictType := r.GetQueryString("dictType")
-	res := g.Map{
-		"listClassSelector": g.Map{"default": "默认", "primary": "主要", "success": "成功", "info": "信息",
-			"warning": "警告", "danger": "危险"},
-		"dictType": dictType,
-	}
-	response.SusJson(true, r, "ok", res)
 }
 
 //修改字典数据
@@ -139,21 +151,17 @@ func (c *Dict) DataEdit(r *ghttp.Request) {
 		if err != nil {
 			response.FailJson(true, r, err.Error())
 		}
+		//清除tag缓存
+		cache_service.New().RemoveByTag(cache_service.AdminSysConfigTag)
 		response.SusJson(true, r, "修改字典数据成功")
-
 	}
 	dictCode := r.GetInt("dictCode")
 	dictData, err := dict_service.GetDictDataById(dictCode)
 	if err != nil {
 		response.FailJson(true, r, err.Error())
 	}
-	res := g.Map{
-		"listClassSelector": g.Map{"default": "默认", "primary": "主要", "success": "成功", "info": "信息",
-			"warning": "警告", "danger": "危险"},
-		"dictType": dictData.DictType,
-		"dictData": dictData,
-	}
-	response.SusJson(true, r, "ok", res)
+
+	response.SusJson(true, r, "ok", dictData)
 }
 
 //删除字典
@@ -166,12 +174,14 @@ func (c *Dict) Delete(r *ghttp.Request) {
 	if err != nil {
 		response.FailJson(true, r, "删除失败")
 	}
+	//清除tag缓存
+	cache_service.New().RemoveByTag(cache_service.AdminSysConfigTag)
 	response.SusJson(true, r, "删除成功")
 }
 
 //删除字典数据
 func (c *Dict) DataDelete(r *ghttp.Request) {
-	dictCodes := r.GetInts("dictCode")
+	dictCodes := r.GetInts("ids")
 	if len(dictCodes) == 0 {
 		response.FailJson(true, r, "删除失败")
 	}
@@ -179,5 +189,40 @@ func (c *Dict) DataDelete(r *ghttp.Request) {
 	if err != nil {
 		response.FailJson(true, r, "删除失败")
 	}
+	//清除tag缓存
+	cache_service.New().RemoveByTag(cache_service.AdminSysConfigTag)
 	response.SusJson(true, r, "删除成功")
 }
+
+/**
+状态
+*/
+func (c *Dict) SysNormalDisable(r *ghttp.Request) {
+	//菜单正常or停用状态
+	statusOptions, err := dict_service.GetDictWithDataByType("sys_normal_disable", "", "")
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	response.SusJson(true, r, "", statusOptions)
+
+}
+
+func (c *Dict) SysCommonStatus(r *ghttp.Request) {
+	//获取相关选项
+	logStatus, err := dict_service.GetDictWithDataByType("sys_oper_log_status", "", "全部")
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+
+	response.SusJson(true, r, "ok", logStatus)
+}
+
+// 获取字典选择框列表
+func (c *Dict) OptionSelect(r *ghttp.Request) {
+	//获取所有字典类型列表
+	list, err := dict_service.GetAllDictType()
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	response.SusJson(true, r, "ok", list)
+}

+ 8 - 2
app/controller/admin/config_params.go

@@ -2,6 +2,7 @@ package admin
 
 import (
 	"gfast/app/model/admin/sys_config"
+	"gfast/app/service/admin/dict_service"
 	"gfast/app/service/admin/params_service"
 	"gfast/app/service/admin/user_service"
 	"gfast/app/service/cache_service"
@@ -24,11 +25,16 @@ func (c *Params) List(r *ghttp.Request) {
 	if err != nil {
 		response.FailJson(true, r, err.Error())
 	}
+	//系统内置选项
+	sysOptions, err := dict_service.GetDictWithDataByType("sys_yes_no", "", "")
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
 	result := g.Map{
 		"currentPage": page,
 		"total":       total,
 		"list":        list,
-		"searchTypes": map[string]string{"": "所有", "0": "否", "1": "是"},
+		"searchTypes": sysOptions,
 	}
 	response.SusJson(true, r, "字典列表", result)
 }
@@ -80,7 +86,7 @@ func (c *Params) Edit(r *ghttp.Request) {
 	if err != nil {
 		response.FailJson(true, r, err.Error())
 	}
-	response.SusJson(true, r, "ok", g.Map{"params": params})
+	response.SusJson(true, r, "ok", params)
 }
 
 //删除参数

+ 168 - 0
app/controller/admin/dept.go

@@ -0,0 +1,168 @@
+package admin
+
+import (
+	"gfast/app/model/admin/sys_dept"
+	"gfast/app/service/admin/dept_service"
+	"gfast/library/response"
+	"gfast/library/utils"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/net/ghttp"
+	"github.com/gogf/gf/util/gvalid"
+)
+
+//菜单用户组用户管理
+type Dept struct{}
+
+func (c *Dept) List(r *ghttp.Request) {
+
+	var searchParams *sys_dept.SearchParams
+
+	if err := r.Parse(&searchParams); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+	}
+
+	if list, err := dept_service.GetList(searchParams); err != nil {
+		response.FailJson(true, r, err.Error())
+	} else {
+		if list != nil {
+			response.SusJson(true, r, "成功", list)
+		} else {
+			response.SusJson(true, r, "成功", g.Slice{})
+		}
+
+	}
+
+}
+
+/**
+新增
+*/
+func (c *Dept) AddDept(r *ghttp.Request) {
+	if r.Method == "POST" {
+		var addParams *sys_dept.AddParams
+
+		if err := r.Parse(&addParams); err != nil {
+			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+		}
+		//g.Log().Println(AddParams)
+		if _, err := dept_service.AddDept(addParams); err != nil {
+			response.FailJson(true, r, err.Error())
+		}
+		response.SusJson(true, r, "添加成功")
+	}
+}
+
+/**
+编辑
+*/
+func (c *Dept) EditDept(r *ghttp.Request) {
+	if r.Method == "POST" {
+		var editParams *sys_dept.EditParams
+		if err := r.Parse(&editParams); err != nil {
+			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+		}
+
+		if err := dept_service.EditDept(editParams); err != nil {
+			response.FailJson(true, r, err.Error())
+		}
+		response.SusJson(true, r, "编辑成功")
+
+	}
+
+	id := r.GetInt64("id")
+	if id == 0 {
+		response.FailJson(true, r, "参数错误")
+	}
+	if dept, err := dept_service.GetDeptById(id); err != nil {
+		response.FailJson(true, r, err.Error())
+	} else {
+		response.SusJson(true, r, "success", dept)
+	}
+
+}
+
+/**
+查询部门排除节点
+*/
+func (c *Dept) Exclude(r *ghttp.Request) {
+	id := r.GetInt64("id")
+	if id == 0 {
+		response.FailJson(true, r, "参数错误")
+	}
+
+	if depts, err := dept_service.Exclude(id); err != nil {
+		response.FailJson(true, r, err.Error())
+	} else {
+		response.SusJson(true, r, "success", depts)
+	}
+}
+
+/**
+删除
+*/
+func (c *Dept) DelDept(r *ghttp.Request) {
+	id := r.GetInt64("id")
+	if id == 0 {
+		response.FailJson(true, r, "删除失败")
+	}
+	err := dept_service.DelDept(id)
+	if err != nil {
+		response.FailJson(true, r, "删除失败")
+	}
+	response.SusJson(true, r, "删除信息成功")
+}
+
+func (c *Dept) TreeSelect(r *ghttp.Request) {
+	//获取正常状态部门数据
+	list, err := dept_service.GetList(&sys_dept.SearchParams{Status: "1"})
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	var dList g.ListStrAny
+	for _, entity := range list {
+		m := g.Map{
+			"id":    entity.DeptID,
+			"pid":   entity.ParentID,
+			"label": entity.DeptName,
+		}
+		dList = append(dList, m)
+	}
+	dList = utils.PushSonToParent(dList, 0, "pid", "id", "children", "", nil, false)
+	res := g.Map{
+		"depts": dList,
+	}
+	response.SusJson(true, r, "ok", res)
+}
+
+//获取角色部门
+func (c *Dept) RoleDeptTreeSelect(r *ghttp.Request) {
+	id := r.GetInt64("roleId")
+	if id == 0 {
+		response.FailJson(true, r, "参数错误")
+	}
+	//获取正常状态部门数据
+	list, err := dept_service.GetList(&sys_dept.SearchParams{Status: "1"})
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	var dList g.ListStrAny
+	for _, entity := range list {
+		m := g.Map{
+			"id":    entity.DeptID,
+			"pid":   entity.ParentID,
+			"label": entity.DeptName,
+		}
+		dList = append(dList, m)
+	}
+	//获取关联的角色数据权限
+	checkedKeys, err := dept_service.GetRoleDepts(id)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	dList = utils.PushSonToParent(dList)
+	res := g.Map{
+		"depts":       dList,
+		"checkedKeys": checkedKeys,
+	}
+	response.SusJson(true, r, "ok", res)
+}

+ 189 - 0
app/controller/admin/gen_table.go

@@ -0,0 +1,189 @@
+package admin
+
+import (
+	"gfast/app/model/admin/gen_table"
+	"gfast/app/service/admin/gen_service"
+	"gfast/app/service/admin/user_service"
+	"gfast/library/response"
+	"github.com/gogf/gf/encoding/gjson"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/net/ghttp"
+	"github.com/gogf/gf/text/gstr"
+	"github.com/gogf/gf/util/gconv"
+	"github.com/gogf/gf/util/gvalid"
+	"strings"
+)
+
+type Gen struct{}
+
+//查询数据库列表
+func (c *Gen) DataList(r *ghttp.Request) {
+	var req *gen_table.SelectPageReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+	}
+
+	total, list, err := gen_service.SelectDbTableList(req)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	response.SusJson(true, r, "ok", g.Map{
+		"total": total,
+		"list":  list,
+	})
+}
+
+//表列表
+func (c *Gen) TableList(r *ghttp.Request) {
+	var req *gen_table.SelectPageReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+	}
+	total, list, err := gen_service.SelectListByPage(req)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	response.SusJson(true, r, "ok", g.Map{
+		"total": total,
+		"list":  list,
+	})
+}
+
+//导入表结构操作
+func (c *Gen) ImportTableSave(r *ghttp.Request) {
+	tables := r.GetString("tables")
+	if tables == "" {
+		response.FailJson(true, r, "请选择要导入的表格")
+	}
+	user := user_service.GetLoginAdminInfo(r)
+	operName := user.UserName
+	tableArr := strings.Split(tables, ",")
+	tableList, err := gen_service.SelectDbTableListByNames(tableArr)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	if tableList == nil {
+		response.FailJson(true, r, "表信息不存在")
+	}
+	err = gen_service.ImportGenTable(tableList, operName)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	response.SusJson(true, r, "导入数据表成功")
+}
+
+//根据表格ID获取表格字段列表数据
+func (c *Gen) ColumnList(r *ghttp.Request) {
+	tableId := r.GetInt64("tableId")
+	if tableId == 0 {
+		response.FailJson(true, r, "参数错误")
+	}
+	list, err := gen_service.SelectGenTableColumnListByTableId(tableId)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	var tableInfo *gen_table.Entity
+	var tableMap g.Map
+	tableInfo, err = gen_service.GetTableInfoByTableId(tableId)
+	tableMap = gconv.Map(tableInfo)
+	//如果是树表则设置树表配置
+	if tableInfo != nil && tableInfo.TplCategory == "tree" {
+		options := gjson.New(tableInfo.Options)
+		tableMap["tree_code"] = options.Get("tree_code")
+		tableMap["tree_parent_code"] = options.Get("tree_parent_code")
+		tableMap["tree_name"] = options.Get("tree_name")
+	}
+
+	res := g.Map{
+		"rows": list,
+		"info": tableMap,
+	}
+	response.SusJson(true, r, "ok", res)
+}
+
+//编辑表格信息
+func (c *Gen) EditSave(r *ghttp.Request) {
+	var req *gen_table.EditReq
+	//获取参数
+	if err := r.Parse(&req); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+	}
+	userInfo := user_service.GetLoginAdminInfo(r)
+	req.UserName = userInfo.UserName
+	err := gen_service.SaveEdit(req)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	response.SusJson(true, r, "设置成功")
+}
+
+//删除表格数据
+func (c *Gen) Delete(r *ghttp.Request) {
+	ids := r.GetInts("ids")
+	if len(ids) == 0 {
+		response.FailJson(true, r, "参数错误")
+	}
+	err := gen_service.Delete(ids)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	response.SusJson(true, r, "删除成功")
+}
+
+//代码生成预览
+func (c *Gen) Preview(r *ghttp.Request) {
+	tableId := r.GetInt64("tableId")
+	if tableId == 0 {
+		response.FailJson(true, r, "参数错误")
+	}
+	entity, err := gen_service.SelectRecordById(tableId)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	if entity == nil {
+		response.FailJson(true, r, "表格数据不存在")
+	}
+	gen_service.SetPkColumn(entity, entity.Columns)
+
+	controllerKey := "vm/go/" + entity.BusinessName + "_controller.go.vm"
+	controllerValue := ""
+	serviceKey := "vm/go/" + entity.BusinessName + "_service.go.vm"
+	serviceValue := ""
+	extendKey := "vm/go/" + entity.BusinessName + "_extend.go.vm"
+	extendValue := ""
+	apiJsKey := "vm/html/" + entity.BusinessName + "_api.js.vm"
+	apiJsValue := ""
+	vueKey := "vm/html/" + entity.BusinessName + "_vue.js.vm"
+	vueValue := ""
+
+	g.View().BindFuncMap(g.Map{
+		"UcFirst": func(str string) string {
+			return gstr.UcFirst(str)
+		},
+	})
+	if tmpController, err := r.Response.ParseTpl("vm/go/controller.template", g.Map{"table": entity}); err == nil {
+		controllerValue = tmpController
+	}
+	if tmpService, err := r.Response.ParseTpl("vm/go/service.template", g.Map{"table": entity}); err == nil {
+		serviceValue = tmpService
+	}
+	if tmpExtend, err := r.Response.ParseTpl("vm/go/extend.template", g.Map{"table": entity}); err == nil {
+		extendValue = tmpExtend
+	}
+	if tmpExtend, err := r.Response.ParseTpl("vm/html/js.template", g.Map{"table": entity}); err == nil {
+		apiJsValue = tmpExtend
+	}
+	if tmpExtend, err := r.Response.ParseTpl("vm/html/vue.template", g.Map{"table": entity}); err == nil {
+		vueValue = tmpExtend
+	}
+
+	response.SusJson(true, r, "ok", g.Map{
+		extendKey:     extendValue,
+		serviceKey:    serviceValue,
+		controllerKey: controllerValue,
+		apiJsKey:      apiJsValue,
+		vueKey:        vueValue,
+	})
+}

+ 52 - 14
app/controller/admin/index.go

@@ -8,22 +8,65 @@ import (
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/net/ghttp"
 	"github.com/gogf/gf/util/gconv"
-	"strings"
 )
 
 type Index struct{}
 
-//后台首页接口数据
-func (c *Index) Index(r *ghttp.Request) {
+//获取登录用户信息
+func (c *Index) GetInfo(r *ghttp.Request) {
 	//获取用户信息
-	userEntity := user_service.GetLoginAdminInfo(r)
+	userEntity, err := user_service.GetCurrentUser(r)
+	if err != nil {
+		g.Log().Error(err)
+		response.FailJson(true, r, "获取当前登录用户信息失败")
+	}
 	userInfo := gconv.Map(userEntity)
+	rolesList := make([]string, 0, 10)
+	if userInfo != nil {
+		userId := userEntity.Id
+		delete(userInfo, "user_password")
+		userInfo["roles"] = make([]string, 0)
+
+		//获取用户角色信息
+		allRoles, err := auth_service.GetRoleList()
+		if err == nil {
+			roles, err := user_service.GetAdminRole(userId, allRoles)
+			if err == nil {
+				name := make([]string, len(roles))
+				roleIds := make([]int, len(roles))
+				for k, v := range roles {
+					name[k] = v.Name
+					roleIds[k] = v.Id
+				}
+				userInfo["roles"] = roles
+				rolesList = name
+			} else {
+				g.Log().Error(err)
+			}
+		} else {
+			g.Log().Error(err)
+		}
+	}
+
+	result := g.Map{
+		"user":        userInfo,
+		"roles":       rolesList,
+		"permissions": nil,
+	}
+
+	response.SusJson(true, r, "ok", result)
+}
+
+//获取后台菜单
+func (c *Index) GetRouters(r *ghttp.Request) {
+	//获取用户信息
+	userEntity := user_service.GetLoginAdminInfo(r)
 	//菜单列表
 	var menuList g.List
 	isSuperAdmin := false
-	if userInfo != nil {
+	if userEntity != nil {
 		userId := userEntity.Id
-		delete(userInfo, "user_password")
+
 		//获取无需验证权限的用户id
 		for _, v := range service.NotCheckAuthAdminIds {
 			if v == userId {
@@ -43,7 +86,6 @@ func (c *Index) Index(r *ghttp.Request) {
 					name[k] = v.Name
 					roleIds[k] = v.Id
 				}
-				userInfo["roles"] = strings.Join(name, ",")
 				//获取菜单信息
 				if isSuperAdmin {
 					//超管获取所有菜单
@@ -56,17 +98,13 @@ func (c *Index) Index(r *ghttp.Request) {
 				}
 			} else {
 				g.Log().Error(err)
-				userInfo["roles"] = ""
 			}
 		} else {
 			g.Log().Error(err)
-			userInfo["roles"] = ""
 		}
 	}
-
-	result := g.Map{
-		"userInfo": userInfo,
-		"menuList": menuList,
+	if menuList == nil {
+		menuList = g.List{}
 	}
-	response.SusJson(true, r, "ok", result)
+	response.SusJson(true, r, "ok", menuList)
 }

+ 11 - 1
app/controller/admin/monitor_job.go

@@ -122,9 +122,19 @@ func (c *MonitorJob) Edit(r *ghttp.Request) {
 	response.SusJson(true, r, "添加任务", res)
 }
 
+//详情
+func (c *MonitorJob) Details(r *ghttp.Request) {
+	id := r.GetInt64("id")
+	job, err := monitor_service.GetJobInfoById(id)
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	response.SusJson(true, r, "success", job)
+}
+
 //删除计划任务
 func (c *MonitorJob) Delete(r *ghttp.Request) {
-	ids := r.GetInts("ids")
+	ids := r.GetInts("id")
 	err := monitor_service.DeleteJobByIds(ids)
 	if err != nil {
 		response.FailJson(true, r, err.Error())

+ 91 - 0
app/controller/admin/post.go

@@ -0,0 +1,91 @@
+package admin
+
+import (
+	"gfast/app/model/admin/sys_post"
+	"gfast/app/service/admin/post_service"
+	"gfast/library/response"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/net/ghttp"
+	"github.com/gogf/gf/util/gvalid"
+)
+
+type Post struct{}
+
+func (c *Post) List(r *ghttp.Request) {
+	var req *sys_post.SearchParams
+
+	if err := r.Parse(&req); err != nil {
+		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+	}
+
+	total, page, list, err := post_service.List(req)
+
+	if err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+
+	result := g.Map{
+		"total": total,
+		"list":  list,
+		"page":  page,
+	}
+
+	response.SusJson(true, r, "成功", result)
+}
+
+func (c *Post) Add(r *ghttp.Request) {
+	if r.Method == "POST" {
+
+		var addParams *sys_post.AddParams
+
+		if err := r.Parse(&addParams); err != nil {
+			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+		}
+
+		if _, err := post_service.Add(addParams); err != nil {
+			response.FailJson(true, r, err.Error())
+		}
+
+		response.SusJson(true, r, "添加成功")
+	}
+}
+
+func (c *Post) Edit(r *ghttp.Request) {
+	if r.Method == "POST" {
+		var editParams *sys_post.EditParams
+
+		if err := r.Parse(&editParams); err != nil {
+			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+		}
+
+		if _, err := post_service.Edit(editParams); err != nil {
+			response.FailJson(true, r, err.Error())
+		}
+
+		response.SusJson(true, r, "修改成功")
+	}
+
+	id := r.GetInt64("id")
+	if id == 0 {
+		response.FailJson(true, r, "id必须")
+	}
+
+	if post, err := post_service.GetOneById(id); err != nil {
+		response.FailJson(true, r, err.Error())
+	} else {
+		response.SusJson(true, r, "success", post)
+	}
+
+}
+
+func (c *Post) Delete(r *ghttp.Request) {
+	ids := r.GetInts("ids")
+	if len(ids) == 0 {
+		response.FailJson(true, r, "删除失败")
+	}
+	err := post_service.Delete(ids)
+	if err != nil {
+		response.FailJson(true, r, "删除失败")
+	}
+	response.SusJson(true, r, "删除信息成功")
+}

+ 21 - 0
app/controller/admin/upload.go

@@ -5,10 +5,31 @@ import (
 	"gfast/library/response"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/net/ghttp"
+	"github.com/gogf/gf/text/gstr"
+	"net/url"
 )
 
 type Upload struct{}
 
+//CkEditor编辑器上传附件
+func (c *Upload) CkEditorUp(r *ghttp.Request) {
+	upFile := r.GetUploadFile("upload")
+	fType := gstr.ToLower(r.GetString("type"))
+	var info *upload_service.FileInfo
+	var err error
+	if fType == "images" {
+		info, err = upload_service.UpImg(upFile)
+	} else if fType == "files" {
+		info, err = upload_service.UpFile(upFile)
+	}
+	if err != nil {
+		r.Response.WriteJson(g.Map{"error": g.Map{"message": "上传失败," + err.Error(), "number": 105}})
+	} else {
+		parseInfo, _ := url.Parse(r.GetUrl())
+		r.Response.WriteJson(g.Map{"fileName": info.FileName, "uploaded": 1, "url": parseInfo.Scheme + "://" + parseInfo.Host + "/" + info.FileUrl})
+	}
+}
+
 //单图片上传
 func (c *Upload) UpImg(r *ghttp.Request) {
 	upFile := r.GetUploadFile("file")

+ 86 - 0
app/controller/admin/user.go

@@ -0,0 +1,86 @@
+package admin
+
+import (
+	"gfast/app/model/admin/user"
+	"gfast/app/service/admin/upload_service"
+	"gfast/app/service/admin/user_service"
+	"gfast/library/response"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/net/ghttp"
+	"github.com/gogf/gf/util/gvalid"
+)
+
+type User struct{}
+
+//头像上传上传
+func (c *User) Avatar(r *ghttp.Request) {
+	upFile := r.GetUploadFile("avatarfile")
+	info, err := upload_service.UpImg(upFile)
+	if err != nil {
+		response.FailJson(true, r, "上传失败,"+err.Error())
+	}
+	res := g.Map{
+		"fileInfo": info,
+	}
+	id := user_service.GetLoginID(r)
+	if _, err := user.Model.Where("id", id).Data(g.Map{
+		"avatar": info.FileUrl,
+	}).Update(); err != nil {
+		response.FailJson(true, r, err.Error())
+	}
+	response.SusJson(true, r, "上传成功", res)
+}
+
+/**
+获取当前登录用户详情
+*/
+func (c *User) Profile(r *ghttp.Request) {
+	//获取用户信息
+	userInfo, err := user_service.GetCurrentUserInfo(r)
+
+	if err != nil {
+		g.Log().Println(err.Error())
+		response.FailJson(true, r, err.Error())
+	}
+
+	delete(userInfo, "user_password")
+	response.SusJson(true, r, "ok", userInfo)
+}
+
+/**
+修改用户信息
+*/
+func (c *User) Edit(r *ghttp.Request) {
+
+	if r.Method == "POST" {
+
+		var req *user_service.EditParams
+		if err := r.Parse(&req); err != nil {
+			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+		}
+
+		if _, err := user_service.Edit(req); err != nil {
+			response.FailJson(true, r, err.Error())
+		}
+		response.SusJson(true, r, "修改成功")
+	}
+
+}
+
+/**
+修改密码
+*/
+func (c *User) UpdatePwd(r *ghttp.Request) {
+	if r.Method == "POST" {
+		var req *user_service.UpdatePwdReq
+		if err := r.Parse(&req); err != nil {
+			response.FailJson(true, r, err.(*gvalid.Error).FirstString())
+		}
+		if err := user_service.UpdatePwd(r, req); err != nil {
+			response.FailJson(true, r, err.Error())
+		} else {
+			response.SusJson(true, r, "修改成功")
+		}
+
+	}
+}

+ 13 - 0
app/controller/front/index.go

@@ -0,0 +1,13 @@
+package front
+
+import (
+	"gfast/library/response"
+	"github.com/gogf/gf/net/ghttp"
+)
+
+type Index struct{}
+
+//前台首页
+func (c *Index) Index(r *ghttp.Request) {
+	response.SusJson(true, r, "登录成功")
+}

+ 74 - 18
app/model/admin/auth_rule/auth_rule.go

@@ -3,6 +3,7 @@ package auth_rule
 import (
 	"gfast/app/service/cache_service"
 	"gfast/library/utils"
+	"github.com/gogf/gf/errors/gerror"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/os/gtime"
 	"github.com/gogf/gf/util/gconv"
@@ -10,15 +11,18 @@ import (
 
 //菜单对象
 type MenuReq struct {
-	IsMenu    int    `p:"ismenu" c:"ismenu" v:"min:0|max:1#菜单类型最小值为:min|菜单类型最大值为:max"`
-	Pid       int    `p:"pid" c:"pid" v:"min:0"`
-	Name      string `p:"name" c:"name" v:"required#请填写规则名称"`
-	Title     string `p:"title" c:"title" v:"required|length:1,100#请填写标题|标题长度在:min到:max位"`
-	Icon      string `p:"icon" c:"icon"`
-	Weigh     int    `p:"weigh" c:"weigh"`
-	Condition string `p:"condition" c:"condition"`
-	Remark    string `p:"remark" c:"remark"`
-	Status    int    `p:"status" c:"status"`
+	MenuType   uint   `p:"menuType"  v:"min:0|max:2#菜单类型最小值为:min|菜单类型最大值为:max"`
+	Pid        uint   `p:"parentId"  v:"min:0"`
+	Name       string `p:"component" v:"required#请填写规则名称"`
+	Title      string `p:"menuName"  v:"required|length:1,100#请填写标题|标题长度在:min到:max位"`
+	Icon       string `p:"icon"`
+	Weigh      int    `p:"orderNum" `
+	Condition  string `p:"condition" `
+	Remark     string `p:"remark" `
+	Status     uint   `p:"status" `
+	AlwaysShow uint   `p:"visible"`
+	Path       string `p:"path"`
+	IsFrame    uint   `p:"is_frame"`
 }
 
 //获取所有菜单
@@ -54,26 +58,73 @@ func CheckMenuNameUnique(name string, id int) bool {
 	return c == 0
 }
 
+//检查菜单路由地址是否已经存在
+func CheckMenuPathUnique(path string, id int) bool {
+	model := Model.Where("path=?", path).Where("menu_type<>?", 2)
+	if id != 0 {
+		model = model.And("id!=?", id)
+	}
+	c, err := model.Count()
+	if err != nil {
+		g.Log().Error(err)
+		return false
+	}
+	return c == 0
+}
+
 // 添加菜单操作
 func Add(req *MenuReq) (err error, insertId int64) {
-	menuMap := gconv.Map(req)
+	if req == nil {
+		err = gerror.New("参数错误")
+		return
+	}
 	now := gtime.Timestamp()
-	menuMap["createtime"] = now
-	menuMap["updatetime"] = now
-	res, e := Model.Insert(menuMap)
+	entity := new(Entity)
+	entity.Title = req.Title
+	entity.Status = req.Status
+	entity.MenuType = req.MenuType
+	entity.Path = req.Path
+	entity.AlwaysShow = req.AlwaysShow
+	entity.Icon = req.Icon
+	entity.Name = req.Name
+	entity.IsFrame = req.IsFrame
+	entity.Pid = req.Pid
+	entity.Createtime = gconv.Uint(now)
+	entity.Updatetime = gconv.Uint(now)
+
+	res, e := entity.Insert()
 	err = e
-	insertId, _ = res.LastInsertId()
+	if err != nil {
+		return
+	}
+	insertId, err = res.LastInsertId()
 	return
 }
 
 //修改菜单操作
 func Edit(req *MenuReq, id int) (err error, rows int64) {
-	menuMap := gconv.Map(req)
+	var entity *Entity
+	entity, err = Model.FindOne(id)
+	if err != nil {
+		return
+	}
 	now := gtime.Timestamp()
-	menuMap["updatetime"] = now
-	res, e := Model.Where("id=?", id).Update(menuMap)
+	entity.Updatetime = gconv.Uint(now)
+	entity.Title = req.Title
+	entity.Status = req.Status
+	entity.MenuType = req.MenuType
+	entity.Path = req.Path
+	entity.AlwaysShow = req.AlwaysShow
+	entity.Icon = req.Icon
+	entity.Name = req.Name
+	entity.IsFrame = req.IsFrame
+	entity.Pid = req.Pid
+	res, e := entity.Update()
 	err = e
-	rows, _ = res.RowsAffected()
+	if err != nil {
+		return
+	}
+	rows, err = res.RowsAffected()
 	return
 }
 
@@ -95,3 +146,8 @@ func DeleteByIds(ids []int) (err error) {
 	_, err = Model.Where("id in (?)", ids).Delete()
 	return
 }
+
+type ReqSearch struct {
+	Status string `p:"status" `
+	Title  string `p:"menuName" `
+}

+ 15 - 13
app/model/admin/auth_rule/auth_rule_entity.go

@@ -11,19 +11,21 @@ import (
 
 // Entity is the golang structure for table auth_rule.
 type Entity struct {
-	Id         uint   `orm:"id,primary"  json:"id"`         //
-	Type       string `orm:"type"        json:"type"`       // menu为菜单,file为权限节点
-	Pid        uint   `orm:"pid"         json:"pid"`        // 父ID
-	Name       string `orm:"name,unique" json:"name"`       // 规则名称
-	Title      string `orm:"title"       json:"title"`      // 规则名称
-	Icon       string `orm:"icon"        json:"icon"`       // 图标
-	Condition  string `orm:"condition"   json:"condition"`  // 条件
-	Remark     string `orm:"remark"      json:"remark"`     // 备注
-	Ismenu     uint   `orm:"ismenu"      json:"ismenu"`     // 是否为菜单
-	Createtime uint   `orm:"createtime"  json:"createtime"` // 创建时间
-	Updatetime uint   `orm:"updatetime"  json:"updatetime"` // 更新时间
-	Weigh      int    `orm:"weigh"       json:"weigh"`      // 权重
-	Status     uint   `orm:"status"      json:"status"`     // 状态
+	Id         uint   `orm:"id,primary"  json:"id"`           //
+	Pid        uint   `orm:"pid"         json:"pid"`          // 父ID
+	Name       string `orm:"name,unique" json:"name"`         // 规则名称
+	Title      string `orm:"title"       json:"title"`        // 规则名称
+	Icon       string `orm:"icon"        json:"icon"`         // 图标
+	Condition  string `orm:"condition"   json:"condition"`    // 条件
+	Remark     string `orm:"remark"      json:"remark"`       // 备注
+	MenuType   uint   `orm:"menu_type"      json:"menu_type"` // 类型 0目录 1菜单 2按钮
+	Createtime uint   `orm:"createtime"  json:"createtime"`   // 创建时间
+	Updatetime uint   `orm:"updatetime"  json:"updatetime"`   // 更新时间
+	Weigh      int    `orm:"weigh"       json:"weigh"`        // 权重
+	Status     uint   `orm:"status"      json:"status"`       // 状态
+	AlwaysShow uint   `orm:"always_show"   json:"alwaysShow"` //显示状态 0隐藏 1显示
+	Path       string `orm:"path"     json:"path"`            //路由地址
+	IsFrame    uint   `orm:"is_frame"  json:"isFrame"`        //是否外链 1是 0否
 }
 
 // OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers

+ 31 - 6
app/model/admin/cms_category/cms_category.go

@@ -2,6 +2,7 @@ package cms_category
 
 import (
 	"gfast/app/service/cache_service"
+	"github.com/gogf/gf/container/gset"
 	"github.com/gogf/gf/errors/gerror"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/text/gstr"
@@ -18,7 +19,8 @@ const (
 
 //列表搜索参数
 type ReqSearchList struct {
-	Name string `p:"name"`
+	Name   string `p:"name"`
+	Status string `p:"status"`
 }
 
 //添加请求参数
@@ -70,12 +72,20 @@ func AddSave(req *ReqAdd) (id int64, err error) {
 	entity.CateType = req.CateType
 	entity.Status = req.Status
 	entity.Name = req.Name
+	entity.Alias = req.Alias
 	entity.Description = req.Description
 	entity.SeoTitle = req.InputSeoTitle
 	entity.SeoKeywords = req.InputSeoKeywords
 	entity.SeoDescription = req.InputSeoDescription
 	entity.CateAddress = req.CateAddress
 	entity.CateContent = req.CateContent
+	moreFields := g.Map{}
+	if req.Thumbnail != "" {
+		moreFields["thumb"] = req.Thumbnail
+	}
+	if len(moreFields) != 0 {
+		entity.More = gconv.String(moreFields)
+	}
 	res, err := entity.Insert()
 	if err != nil {
 		g.Log().Error(err)
@@ -121,12 +131,20 @@ func EditSave(req *ReqEdit) (id int64, err error) {
 	entity.CateType = req.CateType
 	entity.Status = req.Status
 	entity.Name = req.Name
+	entity.Alias = req.Alias
 	entity.Description = req.Description
 	entity.SeoTitle = req.InputSeoTitle
 	entity.SeoKeywords = req.InputSeoKeywords
 	entity.SeoDescription = req.InputSeoDescription
 	entity.CateAddress = req.CateAddress
 	entity.CateContent = req.CateContent
+	moreFields := g.Map{}
+	if req.Thumbnail != "" {
+		moreFields["thumb"] = req.Thumbnail
+	}
+	if len(moreFields) != 0 {
+		entity.More = gconv.String(moreFields)
+	}
 	res, err := entity.Update()
 	if err != nil {
 		g.Log().Error(err)
@@ -146,12 +164,19 @@ func EditSave(req *ReqEdit) (id int64, err error) {
 func GetListSearch(req *ReqSearchList) (menus []*Entity, err error) {
 	menus, err = GetList()
 	if req != nil {
+		filterKey := gset.New(false)
+		for key, entity := range menus {
+			if req.Name != "" && !gstr.Contains(entity.Name, req.Name) {
+				filterKey.Add(key)
+			}
+			if req.Status != "" && gconv.Uint(req.Status) != entity.Status {
+				filterKey.Add(key)
+			}
+		}
 		searchMenus := make([]*Entity, 0, len(menus))
-		if req.Name != "" {
-			for _, entity := range menus {
-				if gstr.Contains(entity.Name, req.Name) {
-					searchMenus = append(searchMenus, entity)
-				}
+		for key, entity := range menus {
+			if !filterKey.Contains(key) {
+				searchMenus = append(searchMenus, entity)
 			}
 		}
 		menus = searchMenus

+ 1 - 0
app/model/admin/cms_category/cms_category_entity.go

@@ -17,6 +17,7 @@ type Entity struct {
 	DeleteTime     uint    `orm:"delete_time"     json:"delete_time"`     // 删除时间
 	ListOrder      float64 `orm:"list_order"      json:"list_order"`      // 排序
 	Name           string  `orm:"name"            json:"name"`            // 分类名称
+	Alias          string  `orm:"alias"            json:"alias"`          // 分类别名
 	Description    string  `orm:"description"     json:"description"`     // 分类描述
 	SeoTitle       string  `orm:"seo_title"       json:"seo_title"`       //
 	SeoKeywords    string  `orm:"seo_keywords"    json:"seo_keywords"`    //

+ 32 - 19
app/model/admin/cms_news/cms_news.go

@@ -20,18 +20,19 @@ import (
 
 //添加文章参数
 type ReqAddParams struct {
-	NewsStatus    uint   `p:"status"    v:"in:0,1#状态只能为0或1"`       // 状态;1:已发布;0:未发布;
-	IsTop         uint   `p:"IsTop"         v:"in:0,1#置顶只能为0或1"`   // 是否置顶;1:置顶;0:不置顶
-	Recommended   uint   `p:"recommended"    v:"in:0,1#推荐只能为0或1"`  // 是否推荐;1:推荐;0:不推荐
-	PublishedTime string `p:"published_time"`                      // 发布时间
-	NewsTitle     string `p:"title"     v:"required#标题不能为空"`       // post标题
-	NewsKeywords  string `p:"keywords"`                            // seo keywords
-	NewsExcerpt   string `p:"excerpt"`                             // post摘要
-	NewsSource    string `p:"source"  `                            // 转载文章的来源
-	NewsContent   string `p:"content"   v:"required#文章内容不能为空"`     // 文章内容
-	Thumbnail     string `p:"thumbnail"    `                       // 缩略图
-	IsJump        uint   `p:"IsJump"        v:"in:0,1#跳转类型只能为0或1"` // 是否跳转地址
-	JumpUrl       string `p:"JumpUrl"      `                       // 跳转地址
+	NewsStatus uint `p:"status"    v:"in:0,1#状态只能为0或1"` // 状态;1:已发布;0:未发布;
+	//IsTop         uint   `p:"IsTop"         v:"in:0,1#置顶只能为0或1"`   // 是否置顶;1:置顶;0:不置顶
+	//Recommended   uint   `p:"recommended"    v:"in:0,1#推荐只能为0或1"`  // 是否推荐;1:推荐;0:不推荐
+	Attr          []int  `p:attr`                                                           //文章标记 置顶 推荐
+	PublishedTime string `p:"published_time"`                                               // 发布时间
+	NewsTitle     string `p:"title"     v:"required#标题不能为空"`                                // post标题
+	NewsKeywords  string `p:"keywords"`                                                     // seo keywords
+	NewsExcerpt   string `p:"excerpt"`                                                      // post摘要
+	NewsSource    string `p:"source"  `                                                     // 转载文章的来源
+	NewsContent   string `p:"content"   v:"required-if:IsJump,0#文章内容不能为空"`                  // 文章内容
+	Thumbnail     string `p:"thumbnail"    `                                                // 缩略图
+	IsJump        uint   `p:"IsJump"        v:"in:0,1#跳转类型只能为0或1"`                          // 是否跳转地址
+	JumpUrl       string `p:"JumpUrl"      v:"required-if:IsJump,1|url#跳转地址不能为空|跳转地址格式不正确"` // 跳转地址
 }
 
 //文章搜索参数
@@ -61,22 +62,29 @@ func AddNews(req *ReqAddParams, cateIds []int, userId int) (insId int64, err err
 		err = gerror.New("添加失败")
 		return
 	}
+	nowTime := gconv.Uint(gtime.Timestamp())
 	entity := &Entity{
 		UserId:        gconv.Uint64(userId),
 		NewsStatus:    req.NewsStatus,
-		IsTop:         req.IsTop,
-		Recommended:   req.Recommended,
-		CreateTime:    gconv.Uint(gtime.Timestamp()),
+		CreateTime:    nowTime,
+		UpdateTime:    nowTime,
 		PublishedTime: gconv.Uint(utils.StrToTimestamp(req.PublishedTime)),
 		NewsTitle:     req.NewsTitle,
 		NewsKeywords:  req.NewsKeywords,
 		NewsExcerpt:   req.NewsExcerpt,
-		NewsSource:    req.NewsExcerpt,
+		NewsSource:    req.NewsSource,
 		NewsContent:   req.NewsContent,
 		Thumbnail:     req.Thumbnail,
 		IsJump:        req.IsJump,
 		JumpUrl:       req.JumpUrl,
 	}
+	for _, v := range req.Attr {
+		if v == 1 {
+			entity.IsTop = 1
+		} else if v == 2 {
+			entity.Recommended = 1
+		}
+	}
 	res, e := entity.Save()
 	if e != nil {
 		g.Log().Error(e)
@@ -129,18 +137,23 @@ func EditNews(req *ReqEditParams, cateIds []int) (err error) {
 		return
 	}
 	entity.NewsStatus = req.NewsStatus
-	entity.IsTop = req.IsTop
-	entity.Recommended = req.Recommended
 	entity.UpdateTime = gconv.Uint(gtime.Timestamp())
 	entity.PublishedTime = gconv.Uint(utils.StrToTimestamp(req.PublishedTime))
 	entity.NewsTitle = req.NewsTitle
 	entity.NewsKeywords = req.NewsKeywords
 	entity.NewsExcerpt = req.NewsExcerpt
-	entity.NewsSource = req.NewsExcerpt
+	entity.NewsSource = req.NewsSource
 	entity.NewsContent = req.NewsContent
 	entity.Thumbnail = req.Thumbnail
 	entity.IsJump = req.IsJump
 	entity.JumpUrl = req.JumpUrl
+	for _, v := range req.Attr {
+		if v == 1 {
+			entity.IsTop = 1
+		} else if v == 2 {
+			entity.Recommended = 1
+		}
+	}
 	_, err = entity.Update()
 	if err != nil {
 		g.Log().Error(err)

+ 191 - 0
app/model/admin/gen_table/gen_table.go

@@ -0,0 +1,191 @@
+// ============================================================================
+// This is auto-generated by gf cli tool only once. Fill this file as you wish.
+// ============================================================================
+
+package gen_table
+
+import (
+	"gfast/app/model/admin/gen_table_column"
+	"gfast/library/service"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/os/gtime"
+	"github.com/gogf/gf/text/gstr"
+	"github.com/gogf/gf/util/gconv"
+)
+
+//分页请求参数
+type SelectPageReq struct {
+	TableName    string `p:"tableName"`    //表名称
+	TableComment string `p:"tableComment"` //表描述
+	BeginTime    string `p:"beginTime"`    //开始时间
+	EndTime      string `p:"endTime"`      //结束时间
+	PageNum      int    `p:"pageNum"`      //当前页码
+	PageSize     int    `p:"pageSize"`     //每页数
+}
+
+//实体扩展
+type EntityExtend struct {
+	TableId        int64                      `orm:"table_id,primary" json:"table_id"`        // 编号
+	TableName      string                     `orm:"table_name"       json:"table_name"`      // 表名称
+	TableComment   string                     `orm:"table_comment"    json:"table_comment"`   // 表描述
+	ClassName      string                     `orm:"class_name"       json:"class_name"`      // 实体类名称
+	TplCategory    string                     `orm:"tpl_category"     json:"tpl_category"`    // 使用的模板(crud单表操作 tree树表操作)
+	PackageName    string                     `orm:"package_name"     json:"package_name"`    // 生成包路径
+	ModuleName     string                     `orm:"module_name"      json:"module_name"`     // 生成模块名
+	BusinessName   string                     `orm:"business_name"    json:"business_name"`   // 生成业务名
+	FunctionName   string                     `orm:"function_name"    json:"function_name"`   // 生成功能名
+	FunctionAuthor string                     `orm:"function_author"  json:"function_author"` // 生成功能作者
+	Options        string                     `orm:"options"          json:"options"`         // 其它生成选项
+	CreateBy       string                     `orm:"create_by"        json:"create_by"`       // 创建者
+	CreateTime     *gtime.Time                `orm:"create_time"      json:"create_time"`     // 创建时间
+	UpdateBy       string                     `orm:"update_by"        json:"update_by"`       // 更新者
+	UpdateTime     *gtime.Time                `orm:"update_time"      json:"update_time"`     // 更新时间
+	Remark         string                     `orm:"remark"           json:"remark"`          // 备注
+	TreeCode       string                     `json:"tree_code"`                              // 树编码字段
+	TreeParentCode string                     `json:"tree_parent_code"`                       // 树父编码字段
+	TreeName       string                     `json:"tree_name"`                              // 树名称字段
+	Columns        []*gen_table_column.Entity `json:"columns"`                                // 表列信息
+	PkColumn       *gen_table_column.Entity   `json:"pkColumn"`                               // 表列信息
+}
+
+//查询据库列表
+func SelectDbTableList(param *SelectPageReq) (total int, list []*Entity, err error) {
+	db := g.DB()
+	sql := " from information_schema.tables where table_schema = (select database())" +
+		" and table_name NOT LIKE 'qrtz_%' AND table_name NOT LIKE 'gen_%' and table_name NOT IN (select table_name from gen_table) "
+	if param != nil {
+		if param.TableName != "" {
+			sql += gdb.FormatSqlWithArgs(" and lower(table_name) like lower(?)", []interface{}{"%" + param.TableName + "%"})
+		}
+
+		if param.TableComment != "" {
+			sql += gdb.FormatSqlWithArgs(" and lower(table_comment) like lower(?)", []interface{}{"%" + param.TableComment + "%"})
+		}
+
+		if param.BeginTime != "" {
+			sql += gdb.FormatSqlWithArgs(" and date_format(create_time,'%y%m%d') >= date_format(?,'%y%m%d') ", []interface{}{param.BeginTime})
+		}
+
+		if param.EndTime != "" {
+			sql += gdb.FormatSqlWithArgs(" and date_format(create_time,'%y%m%d') <= date_format(?,'%y%m%d') ", []interface{}{param.EndTime})
+		}
+	}
+	countSql := "select count(1) " + sql
+	total, err = db.GetCount(countSql)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("读取总表数失败")
+		return
+	}
+	sql = "table_name, table_comment, create_time, update_time " + sql
+
+	if param.PageNum == 0 {
+		param.PageNum = 1
+	}
+
+	if param.PageSize == 0 {
+		param.PageSize = service.AdminPageNum
+	}
+	page := (param.PageNum - 1) * param.PageSize
+	sql += " order by create_time desc,table_name asc limit  " + gconv.String(page) + "," + gconv.String(param.PageSize)
+	var res gdb.Result
+	res, err = db.GetAll("select " + sql)
+	res.Structs(&list)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("读取数据失败")
+	}
+	return
+}
+
+//根据条件分页查询数据
+func SelectListByPage(param *SelectPageReq) (total int, list []*Entity, err error) {
+	model := Model
+	if param != nil {
+		if param.TableName != "" {
+			model = model.Where(Columns.TableName+" like ?", "%"+param.TableName+"%")
+		}
+		if param.TableComment != "" {
+			model = model.Where(Columns.TableComment+"like ?", "%"+param.TableComment+"%")
+		}
+		if param.BeginTime != "" {
+			model = model.Where(Columns.CreateTime+" >= ", param.BeginTime)
+		}
+		if param.EndTime != "" {
+			model = model.Where(Columns.CreateTime+" <= ", param.EndTime)
+		}
+		total, err = model.Count()
+		if err != nil {
+			g.Log().Error(err)
+			err = gerror.New("获取总行数失败")
+			return
+		}
+		if param.PageNum == 0 {
+			param.PageNum = 1
+		}
+		if param.PageSize == 0 {
+			param.PageSize = service.AdminPageNum
+		}
+		list, err = model.Page(param.PageNum, param.PageSize).Order(Columns.TableId + " asc").All()
+		if err != nil {
+			g.Log().Error(err)
+			err = gerror.New("获取数据失败")
+			return
+		}
+	}
+	return
+}
+
+//查询据库列表
+func SelectDbTableListByNames(tableNames []string) ([]*Entity, error) {
+	db := g.DB()
+	sql := "select * from information_schema.tables where table_name NOT LIKE 'qrtz_%' and table_name NOT LIKE 'gen_%' " +
+		" and table_schema = (select database()) "
+	if len(tableNames) > 0 {
+		in := gstr.TrimRight(gstr.Repeat("?,", len(tableNames)), ",")
+		sql += " and " + gdb.FormatSqlWithArgs("table_name in ("+in+")", gconv.SliceAny(tableNames))
+	}
+	var result []*Entity
+	res, err := db.GetAll(sql)
+	if err != nil {
+		g.Log().Error(err)
+		return nil, gerror.New("获取表格信息失败")
+	}
+	err = res.Structs(&result)
+	if err != nil {
+		g.Log().Error(err)
+		return nil, gerror.New("表格信息转换失败")
+	}
+	return result, err
+}
+
+//通过表格ID获取表格信息
+func GetInfoById(tableId int64) (entity *Entity, err error) {
+	entity, err = Model.FindOne(tableId)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取表格信息出错")
+	}
+	return
+}
+
+func SelectRecordById(tableId int64) (entityExtend *EntityExtend, err error) {
+	var entity *Entity
+	entity, err = GetInfoById(tableId)
+	if err != nil {
+		return
+	}
+	m := gconv.Map(entity)
+	gconv.Struct(m, &entityExtend)
+
+	//表字段数据
+	var columns []*gen_table_column.Entity
+	columns, err = gen_table_column.SelectGenTableColumnListByTableId(tableId)
+	if err != nil {
+		return
+	}
+	entityExtend.Columns = columns
+	return
+}

+ 94 - 0
app/model/admin/gen_table/gen_table_entity.go

@@ -0,0 +1,94 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package gen_table
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/os/gtime"
+)
+
+// Entity is the golang structure for table gen_table.
+type Entity struct {
+	TableId        int64       `orm:"table_id,primary" json:"table_id"`        // 编号
+	TableName      string      `orm:"table_name"       json:"table_name"`      // 表名称
+	TableComment   string      `orm:"table_comment"    json:"table_comment"`   // 表描述
+	ClassName      string      `orm:"class_name"       json:"class_name"`      // 实体类名称
+	TplCategory    string      `orm:"tpl_category"     json:"tpl_category"`    // 使用的模板(crud单表操作 tree树表操作)
+	PackageName    string      `orm:"package_name"     json:"package_name"`    // 生成包路径
+	ModuleName     string      `orm:"module_name"      json:"module_name"`     // 生成模块名
+	BusinessName   string      `orm:"business_name"    json:"business_name"`   // 生成业务名
+	FunctionName   string      `orm:"function_name"    json:"function_name"`   // 生成功能名
+	FunctionAuthor string      `orm:"function_author"  json:"function_author"` // 生成功能作者
+	Options        string      `orm:"options"          json:"options"`         // 其它生成选项
+	CreateBy       string      `orm:"create_by"        json:"create_by"`       // 创建者
+	CreateTime     *gtime.Time `orm:"create_time"      json:"create_time"`     // 创建时间
+	UpdateBy       string      `orm:"update_by"        json:"update_by"`       // 更新者
+	UpdateTime     *gtime.Time `orm:"update_time"      json:"update_time"`     // 更新时间
+	Remark         string      `orm:"remark"           json:"remark"`          // 备注
+}
+
+//修改页面请求参数
+type EditReq struct {
+	TableId        int64  `p:"tableId" v:"required#主键ID不能为空"`
+	TableName      string `p:"tableName"  v:"required#表名称不能为空"`
+	TableComment   string `p:"tableComment"  v:"required#表描述不能为空"`
+	ClassName      string `p:"className" v:"required#实体类名称不能为空"`
+	FunctionAuthor string `p:"functionAuthor"  v:"required#作者不能为空"`
+	TplCategory    string `p:"tplCategory"`
+	PackageName    string `p:"packageName" v:"required#生成包路径不能为空"`
+	ModuleName     string `p:"moduleName" v:"required#生成模块名不能为空"`
+	BusinessName   string `p:"businessName" v:"required#生成业务名不能为空"`
+	FunctionName   string `p:"functionName" v:"required#生成功能名不能为空"`
+	Remark         string `p:"remark"`
+	Params         string `p:"params"`
+	Columns        string `p:"columns"`
+	TreeCode       string `p:"tree_code"`
+	TreeParentCode string `p:"tree_parent_code"`
+	TreeName       string `p:"tree_name"`
+	UserName       string
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (r *Entity) OmitEmpty() *arModel {
+	return Model.Data(r).OmitEmpty()
+}
+
+// Inserts does "INSERT...INTO..." statement for inserting current object into table.
+func (r *Entity) Insert() (result sql.Result, err error) {
+	return Model.Data(r).Insert()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for inserting current object into table.
+func (r *Entity) InsertIgnore() (result sql.Result, err error) {
+	return Model.Data(r).InsertIgnore()
+}
+
+// Replace does "REPLACE...INTO..." statement for inserting current object into table.
+// If there's already another same record in the table (it checks using primary key or unique index),
+// it deletes it and insert this one.
+func (r *Entity) Replace() (result sql.Result, err error) {
+	return Model.Data(r).Replace()
+}
+
+// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Save() (result sql.Result, err error) {
+	return Model.Data(r).Save()
+}
+
+// Update does "UPDATE...WHERE..." statement for updating current object from table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Update() (result sql.Result, err error) {
+	return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
+}
+
+// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
+func (r *Entity) Delete() (result sql.Result, err error) {
+	return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
+}

+ 373 - 0
app/model/admin/gen_table/gen_table_model.go

@@ -0,0 +1,373 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package gen_table
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+	"time"
+)
+
+// arModel is a active record design model for table gen_table operations.
+type arModel struct {
+	gmvc.M
+}
+
+var (
+	// Table is the table name of gen_table.
+	Table = "gen_table"
+	// Model is the model object of gen_table.
+	Model = &arModel{g.DB("default").Table(Table).Safe()}
+	// Columns defines and stores column names for table gen_table.
+	Columns = struct {
+		TableId        string // 编号
+		TableName      string // 表名称
+		TableComment   string // 表描述
+		ClassName      string // 实体类名称
+		TplCategory    string // 使用的模板(crud单表操作 tree树表操作)
+		PackageName    string // 生成包路径
+		ModuleName     string // 生成模块名
+		BusinessName   string // 生成业务名
+		FunctionName   string // 生成功能名
+		FunctionAuthor string // 生成功能作者
+		Options        string // 其它生成选项
+		CreateBy       string // 创建者
+		CreateTime     string // 创建时间
+		UpdateBy       string // 更新者
+		UpdateTime     string // 更新时间
+		Remark         string // 备注
+	}{
+		TableId:        "table_id",
+		TableName:      "table_name",
+		TableComment:   "table_comment",
+		ClassName:      "class_name",
+		TplCategory:    "tpl_category",
+		PackageName:    "package_name",
+		ModuleName:     "module_name",
+		BusinessName:   "business_name",
+		FunctionName:   "function_name",
+		FunctionAuthor: "function_author",
+		Options:        "options",
+		CreateBy:       "create_by",
+		CreateTime:     "create_time",
+		UpdateBy:       "update_by",
+		UpdateTime:     "update_time",
+		Remark:         "remark",
+	}
+)
+
+// FindOne is a convenience method for Model.FindOne.
+// See Model.FindOne.
+func FindOne(where ...interface{}) (*Entity, error) {
+	return Model.FindOne(where...)
+}
+
+// FindAll is a convenience method for Model.FindAll.
+// See Model.FindAll.
+func FindAll(where ...interface{}) ([]*Entity, error) {
+	return Model.FindAll(where...)
+}
+
+// FindValue is a convenience method for Model.FindValue.
+// See Model.FindValue.
+func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
+	return Model.FindValue(fieldsAndWhere...)
+}
+
+// FindArray is a convenience method for Model.FindArray.
+// See Model.FindArray.
+func FindArray(fieldsAndWhere ...interface{}) ([]gdb.Value, error) {
+	return Model.FindArray(fieldsAndWhere...)
+}
+
+// FindCount is a convenience method for Model.FindCount.
+// See Model.FindCount.
+func FindCount(where ...interface{}) (int, error) {
+	return Model.FindCount(where...)
+}
+
+// Insert is a convenience method for Model.Insert.
+func Insert(data ...interface{}) (result sql.Result, err error) {
+	return Model.Insert(data...)
+}
+
+// InsertIgnore is a convenience method for Model.InsertIgnore.
+func InsertIgnore(data ...interface{}) (result sql.Result, err error) {
+	return Model.InsertIgnore(data...)
+}
+
+// Replace is a convenience method for Model.Replace.
+func Replace(data ...interface{}) (result sql.Result, err error) {
+	return Model.Replace(data...)
+}
+
+// Save is a convenience method for Model.Save.
+func Save(data ...interface{}) (result sql.Result, err error) {
+	return Model.Save(data...)
+}
+
+// Update is a convenience method for Model.Update.
+func Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
+	return Model.Update(dataAndWhere...)
+}
+
+// Delete is a convenience method for Model.Delete.
+func Delete(where ...interface{}) (result sql.Result, err error) {
+	return Model.Delete(where...)
+}
+
+// As sets an alias name for current table.
+func (m *arModel) As(as string) *arModel {
+	return &arModel{m.M.As(as)}
+}
+
+// TX sets the transaction for current operation.
+func (m *arModel) TX(tx *gdb.TX) *arModel {
+	return &arModel{m.M.TX(tx)}
+}
+
+// Master marks the following operation on master node.
+func (m *arModel) Master() *arModel {
+	return &arModel{m.M.Master()}
+}
+
+// Slave marks the following operation on slave node.
+// Note that it makes sense only if there's any slave node configured.
+func (m *arModel) Slave() *arModel {
+	return &arModel{m.M.Slave()}
+}
+
+// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) LeftJoin(table ...string) *arModel {
+	return &arModel{m.M.LeftJoin(table...)}
+}
+
+// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").RightJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) RightJoin(table ...string) *arModel {
+	return &arModel{m.M.RightJoin(table...)}
+}
+
+// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) InnerJoin(table ...string) *arModel {
+	return &arModel{m.M.InnerJoin(table...)}
+}
+
+// Fields sets the operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) Fields(fields string) *arModel {
+	return &arModel{m.M.Fields(fields)}
+}
+
+// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) FieldsEx(fields string) *arModel {
+	return &arModel{m.M.FieldsEx(fields)}
+}
+
+// Option sets the extra operation option for the model.
+func (m *arModel) Option(option int) *arModel {
+	return &arModel{m.M.Option(option)}
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (m *arModel) OmitEmpty() *arModel {
+	return &arModel{m.M.OmitEmpty()}
+}
+
+// Filter marks filtering the fields which does not exist in the fields of the operated table.
+func (m *arModel) Filter() *arModel {
+	return &arModel{m.M.Filter()}
+}
+
+// Where sets the condition statement for the model. The parameter <where> can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+// Eg:
+// Where("uid=10000")
+// Where("uid", 10000)
+// Where("money>? AND name like ?", 99999, "vip_%")
+// Where("uid", 1).Where("name", "john")
+// Where("status IN (?)", g.Slice{1,2,3})
+// Where("age IN(?,?)", 18, 50)
+// Where(User{ Id : 1, UserName : "john"})
+func (m *arModel) Where(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Where(where, args...)}
+}
+
+// And adds "AND" condition to the where statement.
+func (m *arModel) And(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.And(where, args...)}
+}
+
+// Or adds "OR" condition to the where statement.
+func (m *arModel) Or(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Or(where, args...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (m *arModel) Group(groupBy string) *arModel {
+	return &arModel{m.M.Group(groupBy)}
+}
+
+// Order sets the "ORDER BY" statement for the model.
+func (m *arModel) Order(orderBy ...string) *arModel {
+	return &arModel{m.M.Order(orderBy...)}
+}
+
+// Limit sets the "LIMIT" statement for the model.
+// The parameter <limit> can be either one or two number, if passed two number is passed,
+// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
+// statement.
+func (m *arModel) Limit(limit ...int) *arModel {
+	return &arModel{m.M.Limit(limit...)}
+}
+
+// Offset sets the "OFFSET" statement for the model.
+// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
+func (m *arModel) Offset(offset int) *arModel {
+	return &arModel{m.M.Offset(offset)}
+}
+
+// Page sets the paging number for the model.
+// The parameter <page> is started from 1 for paging.
+// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
+func (m *arModel) Page(page, limit int) *arModel {
+	return &arModel{m.M.Page(page, limit)}
+}
+
+// Batch sets the batch operation number for the model.
+func (m *arModel) Batch(batch int) *arModel {
+	return &arModel{m.M.Batch(batch)}
+}
+
+// Cache sets the cache feature for the model. It caches the result of the sql, which means
+// if there's another same sql request, it just reads and returns the result from cache, it
+// but not committed and executed into the database.
+//
+// If the parameter <duration> < 0, which means it clear the cache with given <name>.
+// If the parameter <duration> = 0, which means it never expires.
+// If the parameter <duration> > 0, which means it expires after <duration>.
+//
+// The optional parameter <name> is used to bind a name to the cache, which means you can later
+// control the cache like changing the <duration> or clearing the cache with specified <name>.
+//
+// Note that, the cache feature is disabled if the model is operating on a transaction.
+func (m *arModel) Cache(duration time.Duration, name ...string) *arModel {
+	return &arModel{m.M.Cache(duration, name...)}
+}
+
+// Data sets the operation data for the model.
+// The parameter <data> can be type of string/map/gmap/slice/struct/*struct, etc.
+// Eg:
+// Data("uid=10000")
+// Data("uid", 10000)
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+func (m *arModel) Data(data ...interface{}) *arModel {
+	return &arModel{m.M.Data(data...)}
+}
+
+// All does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as []*Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) All(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.All(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// One retrieves one record from table and returns the result as *Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) One(where ...interface{}) (*Entity, error) {
+	one, err := m.M.One(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindOne retrieves and returns a single Record by Model.WherePri and Model.One.
+// Also see Model.WherePri and Model.One.
+func (m *arModel) FindOne(where ...interface{}) (*Entity, error) {
+	one, err := m.M.FindOne(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindAll retrieves and returns Result by by Model.WherePri and Model.All.
+// Also see Model.WherePri and Model.All.
+func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.FindAll(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// Chunk iterates the table with given size and callback function.
+func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) {
+	m.M.Chunk(limit, func(result gdb.Result, err error) bool {
+		var entities []*Entity
+		err = result.Structs(&entities)
+		if err == sql.ErrNoRows {
+			return false
+		}
+		return callback(entities, err)
+	})
+}
+
+// LockUpdate sets the lock for update for current operation.
+func (m *arModel) LockUpdate() *arModel {
+	return &arModel{m.M.LockUpdate()}
+}
+
+// LockShared sets the lock in share mode for current operation.
+func (m *arModel) LockShared() *arModel {
+	return &arModel{m.M.LockShared()}
+}
+
+// Unscoped enables/disables the soft deleting feature.
+func (m *arModel) Unscoped() *arModel {
+	return &arModel{m.M.Unscoped()}
+}

+ 97 - 0
app/model/admin/gen_table_column/gen_table_column.go

@@ -0,0 +1,97 @@
+// ============================================================================
+// This is auto-generated by gf cli tool only once. Fill this file as you wish.
+// ============================================================================
+
+package gen_table_column
+
+import (
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+)
+
+//数据库字符串类型
+var COLUMNTYPE_STR = []string{"char", "varchar", "narchar", "varchar2", "tinytext", "text", "mediumtext", "longtext"}
+
+//数据库时间类型
+var COLUMNTYPE_TIME = []string{"datetime", "time", "date", "timestamp"}
+
+//数据库数字类型
+var COLUMNTYPE_NUMBER = []string{"tinyint", "smallint", "mediumint", "int", "number", "integer", "bigint", "float", "float", "double", "decimal"}
+
+//页面不需要编辑字段
+var COLUMNNAME_NOT_EDIT = []string{"id", "create_by", "create_time", "del_flag", "update_by", "update_time"}
+
+//页面不需要显示的列表字段
+var COLUMNNAME_NOT_LIST = []string{"id", "create_by", "create_time", "del_flag", "update_by", "update_time"}
+
+//页面不需要查询字段
+var COLUMNNAME_NOT_QUERY = []string{"id", "create_by", "create_time", "del_flag", "update_by", "update_time", "remark"}
+
+//根据表名称查询列信息
+func SelectDbTableColumnsByName(tableName string) ([]*Entity, error) {
+	db := g.DB()
+	var entity []*Entity
+	sql := " select column_name, (case when (is_nullable = 'no' && column_key != 'PRI') then '1' else null end) as is_required, " +
+		"(case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment," +
+		" (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type from information_schema.columns" +
+		" where table_schema = (select database()) "
+	sql += " and " + gdb.FormatSqlWithArgs(" table_name=? ", []interface{}{tableName}) + " order by ordinal_position ASC "
+	result, err := db.GetAll(sql)
+	if err != nil {
+		g.Log().Error(err)
+		return nil, gerror.New("查询列信息失败")
+	}
+	result.Structs(&entity)
+	return entity, nil
+}
+
+//判断是否是数据库字符串类型
+func IsStringObject(value string) bool {
+	return IsExistInArray(value, COLUMNTYPE_STR)
+}
+
+//判断是否是数据库时间类型
+func IsTimeObject(value string) bool {
+	return IsExistInArray(value, COLUMNTYPE_TIME)
+}
+
+//判断是否是数据库数字类型
+func IsNumberObject(value string) bool {
+	return IsExistInArray(value, COLUMNTYPE_NUMBER)
+}
+
+//页面不需要编辑字段
+func IsNotEdit(value string) bool {
+	return !IsExistInArray(value, COLUMNNAME_NOT_EDIT)
+}
+
+//页面不需要显示的列表字段
+func IsNotList(value string) bool {
+	return !IsExistInArray(value, COLUMNNAME_NOT_LIST)
+}
+
+//页面不需要查询字段
+func IsNotQuery(value string) bool {
+	return !IsExistInArray(value, COLUMNNAME_NOT_QUERY)
+}
+
+//判断string 是否存在在数组中
+func IsExistInArray(value string, array []string) bool {
+	for _, v := range array {
+		if v == value {
+			return true
+		}
+	}
+	return false
+}
+
+//查询业务字段列表
+func SelectGenTableColumnListByTableId(tableId int64) ([]*Entity, error) {
+	list, err := Model.Where(Columns.TableId, tableId).Order(Columns.Sort + " asc, " + Columns.ColumnId + " asc").All()
+	if err != nil {
+		g.Log().Error(err)
+		return nil, gerror.New("获取字段信息出错")
+	}
+	return list, nil
+}

+ 80 - 0
app/model/admin/gen_table_column/gen_table_column_entity.go

@@ -0,0 +1,80 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package gen_table_column
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/os/gtime"
+)
+
+// Entity is the golang structure for table gen_table_column.
+type Entity struct {
+	ColumnId      int64       `orm:"column_id,primary" json:"column_id"`      // 编号
+	TableId       int64       `orm:"table_id"          json:"table_id"`       // 归属表编号
+	ColumnName    string      `orm:"column_name"       json:"column_name"`    // 列名称
+	ColumnComment string      `orm:"column_comment"    json:"column_comment"` // 列描述
+	ColumnType    string      `orm:"column_type"       json:"column_type"`    // 列类型
+	GoType        string      `orm:"go_type"           json:"go_type"`        // Go类型
+	GoField       string      `orm:"go_field"          json:"go_field"`       // Go字段名
+	HtmlField     string      `orm:"html_field"        json:"html_field"`     // html字段名
+	IsPk          string      `orm:"is_pk"             json:"is_pk"`          // 是否主键(1是)
+	IsIncrement   string      `orm:"is_increment"      json:"is_increment"`   // 是否自增(1是)
+	IsRequired    string      `orm:"is_required"       json:"is_required"`    // 是否必填(1是)
+	IsInsert      string      `orm:"is_insert"         json:"is_insert"`      // 是否为插入字段(1是)
+	IsEdit        string      `orm:"is_edit"           json:"is_edit"`        // 是否编辑字段(1是)
+	IsList        string      `orm:"is_list"           json:"is_list"`        // 是否列表字段(1是)
+	IsQuery       string      `orm:"is_query"          json:"is_query"`       // 是否查询字段(1是)
+	QueryType     string      `orm:"query_type"        json:"query_type"`     // 查询方式(等于、不等于、大于、小于、范围)
+	HtmlType      string      `orm:"html_type"         json:"html_type"`      // 显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)
+	DictType      string      `orm:"dict_type"         json:"dict_type"`      // 字典类型
+	Sort          int         `orm:"sort"              json:"sort"`           // 排序
+	CreateBy      string      `orm:"create_by"         json:"create_by"`      // 创建者
+	CreateTime    *gtime.Time `orm:"create_time"       json:"create_time"`    // 创建时间
+	UpdateBy      string      `orm:"update_by"         json:"update_by"`      // 更新者
+	UpdateTime    *gtime.Time `orm:"update_time"       json:"update_time"`    // 更新时间
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (r *Entity) OmitEmpty() *arModel {
+	return Model.Data(r).OmitEmpty()
+}
+
+// Inserts does "INSERT...INTO..." statement for inserting current object into table.
+func (r *Entity) Insert() (result sql.Result, err error) {
+	return Model.Data(r).Insert()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for inserting current object into table.
+func (r *Entity) InsertIgnore() (result sql.Result, err error) {
+	return Model.Data(r).InsertIgnore()
+}
+
+// Replace does "REPLACE...INTO..." statement for inserting current object into table.
+// If there's already another same record in the table (it checks using primary key or unique index),
+// it deletes it and insert this one.
+func (r *Entity) Replace() (result sql.Result, err error) {
+	return Model.Data(r).Replace()
+}
+
+// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Save() (result sql.Result, err error) {
+	return Model.Data(r).Save()
+}
+
+// Update does "UPDATE...WHERE..." statement for updating current object from table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Update() (result sql.Result, err error) {
+	return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
+}
+
+// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
+func (r *Entity) Delete() (result sql.Result, err error) {
+	return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
+}

+ 387 - 0
app/model/admin/gen_table_column/gen_table_column_model.go

@@ -0,0 +1,387 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package gen_table_column
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+	"time"
+)
+
+// arModel is a active record design model for table gen_table_column operations.
+type arModel struct {
+	gmvc.M
+}
+
+var (
+	// Table is the table name of gen_table_column.
+	Table = "gen_table_column"
+	// Model is the model object of gen_table_column.
+	Model = &arModel{g.DB("default").Table(Table).Safe()}
+	// Columns defines and stores column names for table gen_table_column.
+	Columns = struct {
+		ColumnId      string // 编号
+		TableId       string // 归属表编号
+		ColumnName    string // 列名称
+		ColumnComment string // 列描述
+		ColumnType    string // 列类型
+		GoType        string // Go类型
+		GoField       string // Go字段名
+		HtmlField     string // html字段名
+		IsPk          string // 是否主键(1是)
+		IsIncrement   string // 是否自增(1是)
+		IsRequired    string // 是否必填(1是)
+		IsInsert      string // 是否为插入字段(1是)
+		IsEdit        string // 是否编辑字段(1是)
+		IsList        string // 是否列表字段(1是)
+		IsQuery       string // 是否查询字段(1是)
+		QueryType     string // 查询方式(等于、不等于、大于、小于、范围)
+		HtmlType      string // 显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)
+		DictType      string // 字典类型
+		Sort          string // 排序
+		CreateBy      string // 创建者
+		CreateTime    string // 创建时间
+		UpdateBy      string // 更新者
+		UpdateTime    string // 更新时间
+	}{
+		ColumnId:      "column_id",
+		TableId:       "table_id",
+		ColumnName:    "column_name",
+		ColumnComment: "column_comment",
+		ColumnType:    "column_type",
+		GoType:        "go_type",
+		GoField:       "go_field",
+		HtmlField:     "html_field",
+		IsPk:          "is_pk",
+		IsIncrement:   "is_increment",
+		IsRequired:    "is_required",
+		IsInsert:      "is_insert",
+		IsEdit:        "is_edit",
+		IsList:        "is_list",
+		IsQuery:       "is_query",
+		QueryType:     "query_type",
+		HtmlType:      "html_type",
+		DictType:      "dict_type",
+		Sort:          "sort",
+		CreateBy:      "create_by",
+		CreateTime:    "create_time",
+		UpdateBy:      "update_by",
+		UpdateTime:    "update_time",
+	}
+)
+
+// FindOne is a convenience method for Model.FindOne.
+// See Model.FindOne.
+func FindOne(where ...interface{}) (*Entity, error) {
+	return Model.FindOne(where...)
+}
+
+// FindAll is a convenience method for Model.FindAll.
+// See Model.FindAll.
+func FindAll(where ...interface{}) ([]*Entity, error) {
+	return Model.FindAll(where...)
+}
+
+// FindValue is a convenience method for Model.FindValue.
+// See Model.FindValue.
+func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
+	return Model.FindValue(fieldsAndWhere...)
+}
+
+// FindArray is a convenience method for Model.FindArray.
+// See Model.FindArray.
+func FindArray(fieldsAndWhere ...interface{}) ([]gdb.Value, error) {
+	return Model.FindArray(fieldsAndWhere...)
+}
+
+// FindCount is a convenience method for Model.FindCount.
+// See Model.FindCount.
+func FindCount(where ...interface{}) (int, error) {
+	return Model.FindCount(where...)
+}
+
+// Insert is a convenience method for Model.Insert.
+func Insert(data ...interface{}) (result sql.Result, err error) {
+	return Model.Insert(data...)
+}
+
+// InsertIgnore is a convenience method for Model.InsertIgnore.
+func InsertIgnore(data ...interface{}) (result sql.Result, err error) {
+	return Model.InsertIgnore(data...)
+}
+
+// Replace is a convenience method for Model.Replace.
+func Replace(data ...interface{}) (result sql.Result, err error) {
+	return Model.Replace(data...)
+}
+
+// Save is a convenience method for Model.Save.
+func Save(data ...interface{}) (result sql.Result, err error) {
+	return Model.Save(data...)
+}
+
+// Update is a convenience method for Model.Update.
+func Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
+	return Model.Update(dataAndWhere...)
+}
+
+// Delete is a convenience method for Model.Delete.
+func Delete(where ...interface{}) (result sql.Result, err error) {
+	return Model.Delete(where...)
+}
+
+// As sets an alias name for current table.
+func (m *arModel) As(as string) *arModel {
+	return &arModel{m.M.As(as)}
+}
+
+// TX sets the transaction for current operation.
+func (m *arModel) TX(tx *gdb.TX) *arModel {
+	return &arModel{m.M.TX(tx)}
+}
+
+// Master marks the following operation on master node.
+func (m *arModel) Master() *arModel {
+	return &arModel{m.M.Master()}
+}
+
+// Slave marks the following operation on slave node.
+// Note that it makes sense only if there's any slave node configured.
+func (m *arModel) Slave() *arModel {
+	return &arModel{m.M.Slave()}
+}
+
+// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) LeftJoin(table ...string) *arModel {
+	return &arModel{m.M.LeftJoin(table...)}
+}
+
+// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").RightJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) RightJoin(table ...string) *arModel {
+	return &arModel{m.M.RightJoin(table...)}
+}
+
+// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) InnerJoin(table ...string) *arModel {
+	return &arModel{m.M.InnerJoin(table...)}
+}
+
+// Fields sets the operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) Fields(fields string) *arModel {
+	return &arModel{m.M.Fields(fields)}
+}
+
+// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) FieldsEx(fields string) *arModel {
+	return &arModel{m.M.FieldsEx(fields)}
+}
+
+// Option sets the extra operation option for the model.
+func (m *arModel) Option(option int) *arModel {
+	return &arModel{m.M.Option(option)}
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (m *arModel) OmitEmpty() *arModel {
+	return &arModel{m.M.OmitEmpty()}
+}
+
+// Filter marks filtering the fields which does not exist in the fields of the operated table.
+func (m *arModel) Filter() *arModel {
+	return &arModel{m.M.Filter()}
+}
+
+// Where sets the condition statement for the model. The parameter <where> can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+// Eg:
+// Where("uid=10000")
+// Where("uid", 10000)
+// Where("money>? AND name like ?", 99999, "vip_%")
+// Where("uid", 1).Where("name", "john")
+// Where("status IN (?)", g.Slice{1,2,3})
+// Where("age IN(?,?)", 18, 50)
+// Where(User{ Id : 1, UserName : "john"})
+func (m *arModel) Where(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Where(where, args...)}
+}
+
+// And adds "AND" condition to the where statement.
+func (m *arModel) And(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.And(where, args...)}
+}
+
+// Or adds "OR" condition to the where statement.
+func (m *arModel) Or(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Or(where, args...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (m *arModel) Group(groupBy string) *arModel {
+	return &arModel{m.M.Group(groupBy)}
+}
+
+// Order sets the "ORDER BY" statement for the model.
+func (m *arModel) Order(orderBy ...string) *arModel {
+	return &arModel{m.M.Order(orderBy...)}
+}
+
+// Limit sets the "LIMIT" statement for the model.
+// The parameter <limit> can be either one or two number, if passed two number is passed,
+// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
+// statement.
+func (m *arModel) Limit(limit ...int) *arModel {
+	return &arModel{m.M.Limit(limit...)}
+}
+
+// Offset sets the "OFFSET" statement for the model.
+// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
+func (m *arModel) Offset(offset int) *arModel {
+	return &arModel{m.M.Offset(offset)}
+}
+
+// Page sets the paging number for the model.
+// The parameter <page> is started from 1 for paging.
+// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
+func (m *arModel) Page(page, limit int) *arModel {
+	return &arModel{m.M.Page(page, limit)}
+}
+
+// Batch sets the batch operation number for the model.
+func (m *arModel) Batch(batch int) *arModel {
+	return &arModel{m.M.Batch(batch)}
+}
+
+// Cache sets the cache feature for the model. It caches the result of the sql, which means
+// if there's another same sql request, it just reads and returns the result from cache, it
+// but not committed and executed into the database.
+//
+// If the parameter <duration> < 0, which means it clear the cache with given <name>.
+// If the parameter <duration> = 0, which means it never expires.
+// If the parameter <duration> > 0, which means it expires after <duration>.
+//
+// The optional parameter <name> is used to bind a name to the cache, which means you can later
+// control the cache like changing the <duration> or clearing the cache with specified <name>.
+//
+// Note that, the cache feature is disabled if the model is operating on a transaction.
+func (m *arModel) Cache(duration time.Duration, name ...string) *arModel {
+	return &arModel{m.M.Cache(duration, name...)}
+}
+
+// Data sets the operation data for the model.
+// The parameter <data> can be type of string/map/gmap/slice/struct/*struct, etc.
+// Eg:
+// Data("uid=10000")
+// Data("uid", 10000)
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+func (m *arModel) Data(data ...interface{}) *arModel {
+	return &arModel{m.M.Data(data...)}
+}
+
+// All does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as []*Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) All(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.All(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// One retrieves one record from table and returns the result as *Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) One(where ...interface{}) (*Entity, error) {
+	one, err := m.M.One(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindOne retrieves and returns a single Record by Model.WherePri and Model.One.
+// Also see Model.WherePri and Model.One.
+func (m *arModel) FindOne(where ...interface{}) (*Entity, error) {
+	one, err := m.M.FindOne(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindAll retrieves and returns Result by by Model.WherePri and Model.All.
+// Also see Model.WherePri and Model.All.
+func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.FindAll(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// Chunk iterates the table with given size and callback function.
+func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) {
+	m.M.Chunk(limit, func(result gdb.Result, err error) bool {
+		var entities []*Entity
+		err = result.Structs(&entities)
+		if err == sql.ErrNoRows {
+			return false
+		}
+		return callback(entities, err)
+	})
+}
+
+// LockUpdate sets the lock for update for current operation.
+func (m *arModel) LockUpdate() *arModel {
+	return &arModel{m.M.LockUpdate()}
+}
+
+// LockShared sets the lock in share mode for current operation.
+func (m *arModel) LockShared() *arModel {
+	return &arModel{m.M.LockShared()}
+}
+
+// Unscoped enables/disables the soft deleting feature.
+func (m *arModel) Unscoped() *arModel {
+	return &arModel{m.M.Unscoped()}
+}

+ 126 - 0
app/model/admin/model_category/model_category.go

@@ -0,0 +1,126 @@
+// ============================================================================
+// This is auto-generated by gf cli tool only once. Fill this file as you wish.
+// ============================================================================
+
+package model_category
+
+import (
+	"gfast/library/service"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/os/gtime"
+	"github.com/gogf/gf/util/gconv"
+)
+
+//列表搜索参数
+type SearchReq struct {
+	Name     string `p:"cName"`
+	Status   string `p:"cStatus"`
+	PageNum  int    `p:"page"`     //当前页码
+	PageSize int    `p:"pageSize"` //每页数
+}
+
+//添加请求数据
+type AddReq struct {
+	CName    string `p:"cName" v:"required#分类名称不能为空"`
+	CSort    int    `p:"cSort"`
+	CStatus  uint   `p:"cStatus"`
+	CreateBy uint
+}
+
+//修改请求数据
+type EditReq struct {
+	CId      int64  `p:"cId" v:"required#参数错误"`
+	CName    string `p:"cName" v:"required#分类名称不能为空"`
+	CSort    int    `p:"cSort"`
+	CStatus  uint   `p:"cStatus"`
+	UpdateBy uint
+}
+
+func GetList(req *SearchReq) (total int, list []*Entity, err error) {
+	m := Model
+	if req != nil {
+		if req.Name != "" {
+			m = m.Where(Columns.CName+" like ?", "%"+req.Name+"%")
+		}
+		if req.Status != "" {
+			m = m.Where(Columns.CStatus, gconv.Int(req.Status))
+		}
+	}
+	total, err = m.Count()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取总行数失败")
+		return
+	}
+	if req.PageNum == 0 {
+		req.PageNum = 1
+	}
+
+	if req.PageSize == 0 {
+		req.PageSize = service.AdminPageNum
+	}
+	list, err = m.Page(req.PageNum, req.PageSize).Order(Columns.CSort + " asc," + Columns.CId + " asc").All()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取数据失败")
+		return
+	}
+	return
+}
+
+//添加分类操作
+func Add(req *AddReq) error {
+	entity := new(Entity)
+	entity.CName = req.CName
+	entity.CSort = req.CSort
+	entity.CStatus = req.CStatus
+	now := gconv.Uint64(gtime.Timestamp())
+	entity.CreateTime = now
+	entity.UpdateTime = now
+	entity.CreateBy = req.CreateBy
+	if _, err := entity.Save(); err != nil {
+		g.Log().Error(err)
+		return gerror.New("添加失败")
+	}
+	return nil
+}
+
+//修改
+func Edit(req *EditReq) error {
+	entity, err := Model.FindOne(req.CId)
+	if err != nil || entity == nil {
+		g.Log().Error(err)
+		return gerror.New("获取分类信息失败")
+	}
+	entity.UpdateBy = req.UpdateBy
+	entity.CName = req.CName
+	entity.CSort = req.CSort
+	entity.CStatus = req.CStatus
+	entity.UpdateTime = gconv.Uint64(gtime.Timestamp())
+	_, err = entity.Save()
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("修改分类信息失败")
+	}
+	return nil
+}
+
+func GetById(id int64) (entity *Entity, err error) {
+	entity, err = Model.FindOne(id)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取分类信息失败")
+	}
+	return
+}
+
+//删除模型分类
+func DeleteByIds(ids []int) error {
+	_, err := Model.Where(Columns.CId+" in (?)", ids).Delete()
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("删除失败")
+	}
+	return nil
+}

+ 64 - 0
app/model/admin/model_category/model_category_entity.go

@@ -0,0 +1,64 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package model_category
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+)
+
+// Entity is the golang structure for table model_category.
+type Entity struct {
+	CId        uint   `orm:"c_id,primary" json:"c_id"`        // 主键
+	CName      string `orm:"c_name"       json:"c_name"`      // 模型分类名称
+	CSort      int    `orm:"c_sort"       json:"c_sort"`      // 排序
+	CreateBy   uint   `orm:"create_by"    json:"create_by"`   // 创建人
+	CreateTime uint64 `orm:"create_time"  json:"create_time"` // 创建时间
+	UpdateBy   uint   `orm:"update_by"    json:"update_by"`   // 修改人
+	UpdateTime uint64 `orm:"update_time"  json:"update_time"` // 修改时间
+	CStatus    uint   `orm:"c_status"     json:"c_status"`    // 状态
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (r *Entity) OmitEmpty() *arModel {
+	return Model.Data(r).OmitEmpty()
+}
+
+// Inserts does "INSERT...INTO..." statement for inserting current object into table.
+func (r *Entity) Insert() (result sql.Result, err error) {
+	return Model.Data(r).Insert()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for inserting current object into table.
+func (r *Entity) InsertIgnore() (result sql.Result, err error) {
+	return Model.Data(r).InsertIgnore()
+}
+
+// Replace does "REPLACE...INTO..." statement for inserting current object into table.
+// If there's already another same record in the table (it checks using primary key or unique index),
+// it deletes it and insert this one.
+func (r *Entity) Replace() (result sql.Result, err error) {
+	return Model.Data(r).Replace()
+}
+
+// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Save() (result sql.Result, err error) {
+	return Model.Data(r).Save()
+}
+
+// Update does "UPDATE...WHERE..." statement for updating current object from table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Update() (result sql.Result, err error) {
+	return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
+}
+
+// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
+func (r *Entity) Delete() (result sql.Result, err error) {
+	return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
+}

+ 357 - 0
app/model/admin/model_category/model_category_model.go

@@ -0,0 +1,357 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package model_category
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+	"time"
+)
+
+// arModel is a active record design model for table model_category operations.
+type arModel struct {
+	gmvc.M
+}
+
+var (
+	// Table is the table name of model_category.
+	Table = "model_category"
+	// Model is the model object of model_category.
+	Model = &arModel{g.DB("default").Table(Table).Safe()}
+	// Columns defines and stores column names for table model_category.
+	Columns = struct {
+		CId        string // 主键
+		CName      string // 模型分类名称
+		CSort      string // 排序
+		CreateBy   string // 创建人
+		CreateTime string // 创建时间
+		UpdateBy   string // 修改人
+		UpdateTime string // 修改时间
+		CStatus    string // 状态
+	}{
+		CId:        "c_id",
+		CName:      "c_name",
+		CSort:      "c_sort",
+		CreateBy:   "create_by",
+		CreateTime: "create_time",
+		UpdateBy:   "update_by",
+		UpdateTime: "update_time",
+		CStatus:    "c_status",
+	}
+)
+
+// FindOne is a convenience method for Model.FindOne.
+// See Model.FindOne.
+func FindOne(where ...interface{}) (*Entity, error) {
+	return Model.FindOne(where...)
+}
+
+// FindAll is a convenience method for Model.FindAll.
+// See Model.FindAll.
+func FindAll(where ...interface{}) ([]*Entity, error) {
+	return Model.FindAll(where...)
+}
+
+// FindValue is a convenience method for Model.FindValue.
+// See Model.FindValue.
+func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
+	return Model.FindValue(fieldsAndWhere...)
+}
+
+// FindArray is a convenience method for Model.FindArray.
+// See Model.FindArray.
+func FindArray(fieldsAndWhere ...interface{}) ([]gdb.Value, error) {
+	return Model.FindArray(fieldsAndWhere...)
+}
+
+// FindCount is a convenience method for Model.FindCount.
+// See Model.FindCount.
+func FindCount(where ...interface{}) (int, error) {
+	return Model.FindCount(where...)
+}
+
+// Insert is a convenience method for Model.Insert.
+func Insert(data ...interface{}) (result sql.Result, err error) {
+	return Model.Insert(data...)
+}
+
+// InsertIgnore is a convenience method for Model.InsertIgnore.
+func InsertIgnore(data ...interface{}) (result sql.Result, err error) {
+	return Model.InsertIgnore(data...)
+}
+
+// Replace is a convenience method for Model.Replace.
+func Replace(data ...interface{}) (result sql.Result, err error) {
+	return Model.Replace(data...)
+}
+
+// Save is a convenience method for Model.Save.
+func Save(data ...interface{}) (result sql.Result, err error) {
+	return Model.Save(data...)
+}
+
+// Update is a convenience method for Model.Update.
+func Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
+	return Model.Update(dataAndWhere...)
+}
+
+// Delete is a convenience method for Model.Delete.
+func Delete(where ...interface{}) (result sql.Result, err error) {
+	return Model.Delete(where...)
+}
+
+// As sets an alias name for current table.
+func (m *arModel) As(as string) *arModel {
+	return &arModel{m.M.As(as)}
+}
+
+// TX sets the transaction for current operation.
+func (m *arModel) TX(tx *gdb.TX) *arModel {
+	return &arModel{m.M.TX(tx)}
+}
+
+// Master marks the following operation on master node.
+func (m *arModel) Master() *arModel {
+	return &arModel{m.M.Master()}
+}
+
+// Slave marks the following operation on slave node.
+// Note that it makes sense only if there's any slave node configured.
+func (m *arModel) Slave() *arModel {
+	return &arModel{m.M.Slave()}
+}
+
+// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) LeftJoin(table ...string) *arModel {
+	return &arModel{m.M.LeftJoin(table...)}
+}
+
+// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").RightJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) RightJoin(table ...string) *arModel {
+	return &arModel{m.M.RightJoin(table...)}
+}
+
+// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) InnerJoin(table ...string) *arModel {
+	return &arModel{m.M.InnerJoin(table...)}
+}
+
+// Fields sets the operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) Fields(fields string) *arModel {
+	return &arModel{m.M.Fields(fields)}
+}
+
+// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) FieldsEx(fields string) *arModel {
+	return &arModel{m.M.FieldsEx(fields)}
+}
+
+// Option sets the extra operation option for the model.
+func (m *arModel) Option(option int) *arModel {
+	return &arModel{m.M.Option(option)}
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (m *arModel) OmitEmpty() *arModel {
+	return &arModel{m.M.OmitEmpty()}
+}
+
+// Filter marks filtering the fields which does not exist in the fields of the operated table.
+func (m *arModel) Filter() *arModel {
+	return &arModel{m.M.Filter()}
+}
+
+// Where sets the condition statement for the model. The parameter <where> can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+// Eg:
+// Where("uid=10000")
+// Where("uid", 10000)
+// Where("money>? AND name like ?", 99999, "vip_%")
+// Where("uid", 1).Where("name", "john")
+// Where("status IN (?)", g.Slice{1,2,3})
+// Where("age IN(?,?)", 18, 50)
+// Where(User{ Id : 1, UserName : "john"})
+func (m *arModel) Where(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Where(where, args...)}
+}
+
+// And adds "AND" condition to the where statement.
+func (m *arModel) And(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.And(where, args...)}
+}
+
+// Or adds "OR" condition to the where statement.
+func (m *arModel) Or(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Or(where, args...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (m *arModel) Group(groupBy string) *arModel {
+	return &arModel{m.M.Group(groupBy)}
+}
+
+// Order sets the "ORDER BY" statement for the model.
+func (m *arModel) Order(orderBy ...string) *arModel {
+	return &arModel{m.M.Order(orderBy...)}
+}
+
+// Limit sets the "LIMIT" statement for the model.
+// The parameter <limit> can be either one or two number, if passed two number is passed,
+// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
+// statement.
+func (m *arModel) Limit(limit ...int) *arModel {
+	return &arModel{m.M.Limit(limit...)}
+}
+
+// Offset sets the "OFFSET" statement for the model.
+// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
+func (m *arModel) Offset(offset int) *arModel {
+	return &arModel{m.M.Offset(offset)}
+}
+
+// Page sets the paging number for the model.
+// The parameter <page> is started from 1 for paging.
+// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
+func (m *arModel) Page(page, limit int) *arModel {
+	return &arModel{m.M.Page(page, limit)}
+}
+
+// Batch sets the batch operation number for the model.
+func (m *arModel) Batch(batch int) *arModel {
+	return &arModel{m.M.Batch(batch)}
+}
+
+// Cache sets the cache feature for the model. It caches the result of the sql, which means
+// if there's another same sql request, it just reads and returns the result from cache, it
+// but not committed and executed into the database.
+//
+// If the parameter <duration> < 0, which means it clear the cache with given <name>.
+// If the parameter <duration> = 0, which means it never expires.
+// If the parameter <duration> > 0, which means it expires after <duration>.
+//
+// The optional parameter <name> is used to bind a name to the cache, which means you can later
+// control the cache like changing the <duration> or clearing the cache with specified <name>.
+//
+// Note that, the cache feature is disabled if the model is operating on a transaction.
+func (m *arModel) Cache(duration time.Duration, name ...string) *arModel {
+	return &arModel{m.M.Cache(duration, name...)}
+}
+
+// Data sets the operation data for the model.
+// The parameter <data> can be type of string/map/gmap/slice/struct/*struct, etc.
+// Eg:
+// Data("uid=10000")
+// Data("uid", 10000)
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+func (m *arModel) Data(data ...interface{}) *arModel {
+	return &arModel{m.M.Data(data...)}
+}
+
+// All does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as []*Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) All(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.All(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// One retrieves one record from table and returns the result as *Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) One(where ...interface{}) (*Entity, error) {
+	one, err := m.M.One(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindOne retrieves and returns a single Record by Model.WherePri and Model.One.
+// Also see Model.WherePri and Model.One.
+func (m *arModel) FindOne(where ...interface{}) (*Entity, error) {
+	one, err := m.M.FindOne(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindAll retrieves and returns Result by by Model.WherePri and Model.All.
+// Also see Model.WherePri and Model.All.
+func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.FindAll(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// Chunk iterates the table with given size and callback function.
+func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) {
+	m.M.Chunk(limit, func(result gdb.Result, err error) bool {
+		var entities []*Entity
+		err = result.Structs(&entities)
+		if err == sql.ErrNoRows {
+			return false
+		}
+		return callback(entities, err)
+	})
+}
+
+// LockUpdate sets the lock for update for current operation.
+func (m *arModel) LockUpdate() *arModel {
+	return &arModel{m.M.LockUpdate()}
+}
+
+// LockShared sets the lock in share mode for current operation.
+func (m *arModel) LockShared() *arModel {
+	return &arModel{m.M.LockShared()}
+}
+
+// Unscoped enables/disables the soft deleting feature.
+func (m *arModel) Unscoped() *arModel {
+	return &arModel{m.M.Unscoped()}
+}

+ 136 - 0
app/model/admin/plug_ad/plug_ad.go

@@ -0,0 +1,136 @@
+package plug_ad
+
+import (
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/os/gtime"
+)
+
+// AddReq 用于存储新增广告请求的请求参数
+type AddReq struct {
+	AdName     string `p:"adName"`     // 广告名称
+	AdAdtypeid int    `p:"adAdtypeid"` // 所属位置
+	AdCheckid  int    `p:"adCheckid"`  // 1=图片 2=JS
+	AdJs       string `p:"adJs"`       // JS代码
+	AdPic      string `p:"adPic"`      // 广告图片URL
+	AdUrl      string `p:"adUrl"`      // 广告链接
+	AdContent  string `p:"adContent"`  // 广告文字内容
+	AdSort     int    `p:"adSort"`     // 排序
+	AdOpen     int    `p:"adOpen"`     // 1=审核  0=未审核
+}
+
+// EditReq 用于存储修改广告位请求参数
+type EditReq struct {
+	PlugAdID int64 `p:"plugAdID"`
+	AddReq
+}
+
+// SelectPageReq 用于存储分页查询广告的请求参数
+type SelectPageReq struct {
+	AdName   string `p:"adName"`   // 广告名称
+	PageNo   int64  `p:"pageNo"`   // 当前页
+	PageSize int64  `p:"pageSize"` // 每页显示记录数
+}
+
+// GetPlugAdByID 根据ID查询广告记录
+func GetPlugAdByID(id int64) (*Entity, error) {
+	entity, err := Model.FindOne("ad_id", id)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("根据ID查询广告记录出错")
+	}
+	if entity == nil {
+		err = gerror.New("根据ID未能查询到广告记录")
+	}
+	return entity, nil
+}
+
+// AddSave 添加广告
+func AddSave(req *AddReq) error {
+	var entity Entity
+	entity.AdName = req.AdName                // 名称
+	entity.AdAdtypeid = req.AdAdtypeid        // 位置
+	entity.AdCheckid = req.AdCheckid          // 1=图片 2=JS
+	entity.AdJs = req.AdJs                    // JS代码
+	entity.AdPic = req.AdPic                  // 广告图片URL
+	entity.AdUrl = req.AdUrl                  // 广告链接
+	entity.AdContent = req.AdContent          // 广告文字内容
+	entity.AdAddtime = int(gtime.Timestamp()) // 时间戳
+	entity.AdSort = req.AdSort                // 排序
+	entity.AdOpen = req.AdOpen                // 1=审核  0=未审核
+	// 保存实体
+	_, err := entity.Insert()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("保存失败")
+		return err
+	}
+	return nil
+}
+
+// 删除广告
+func DeleteByIDs(Ids []int) error {
+	_, err := Model.Delete("ad_id in(?)", Ids)
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("删除广告失败")
+	}
+	return nil
+}
+
+// 根据广告ID来修改广告位信息
+func EditSave(editReq *EditReq) error {
+	// 先根据ID来查询要修改的广告记录
+	entity, err := GetPlugAdByID(editReq.PlugAdID)
+	if err != nil {
+		return err
+	}
+	// 修改实体
+	entity.AdName = editReq.AdName
+	entity.AdAdtypeid = editReq.AdAdtypeid
+	entity.AdCheckid = editReq.AdCheckid
+	entity.AdJs = editReq.AdJs
+	entity.AdPic = editReq.AdPic
+	entity.AdUrl = editReq.AdUrl
+	entity.AdContent = editReq.AdContent
+	entity.AdSort = editReq.AdSort
+	entity.AdOpen = editReq.AdOpen
+	_, err = entity.Update()
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("修改广告位失败")
+	}
+	return nil
+}
+
+// 分页查询,返回值total总记录数,page当前页
+func SelectListByPage(req *SelectPageReq) (total int, page int64, list []*Entity, err error) {
+	model := Model
+	if req != nil {
+		if req.AdName != "" {
+			model = model.Where("ad_name like ?", "%"+req.AdName+"%")
+		}
+	}
+	// 查询广告位总记录数(总行数)
+	total, err = model.Count()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取总记录数失败")
+		return 0, 0, nil, err
+	}
+	if req.PageNo == 0 {
+		req.PageNo = 1
+	}
+	page = req.PageNo
+	if req.PageSize == 0 {
+		req.PageSize = 10
+	}
+	// 分页排序查询
+	list, err = model.Page(int(page), int(req.PageSize)).Order("ad_sort asc,ad_id asc").All()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("分页查询广告失败")
+		return 0, 0, nil, err
+	}
+	return total, page, list, nil
+}

+ 67 - 0
app/model/admin/plug_ad/plug_ad_entity.go

@@ -0,0 +1,67 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package plug_ad
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+)
+
+// Entity is the golang structure for table plug_ad.
+type Entity struct {
+	AdId       int    `orm:"ad_id,primary" json:"ad_id"`       //
+	AdName     string `orm:"ad_name"       json:"ad_name"`     // 广告名称
+	AdAdtypeid int    `orm:"ad_adtypeid"   json:"ad_adtypeid"` // 所属位置
+	AdCheckid  int    `orm:"ad_checkid"    json:"ad_checkid"`  // 1=图片 2=JS
+	AdJs       string `orm:"ad_js"         json:"ad_js"`       // JS代码
+	AdPic      string `orm:"ad_pic"        json:"ad_pic"`      // 广告图片URL
+	AdUrl      string `orm:"ad_url"        json:"ad_url"`      // 广告链接
+	AdContent  string `orm:"ad_content"    json:"ad_content"`  // 广告文字内容
+	AdAddtime  int    `orm:"ad_addtime"    json:"ad_addtime"`  // 添加时间
+	AdSort     int    `orm:"ad_sort"       json:"ad_sort"`     // 排序
+	AdOpen     int    `orm:"ad_open"       json:"ad_open"`     // 1=审核  0=未审核
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (r *Entity) OmitEmpty() *arModel {
+	return Model.Data(r).OmitEmpty()
+}
+
+// Inserts does "INSERT...INTO..." statement for inserting current object into table.
+func (r *Entity) Insert() (result sql.Result, err error) {
+	return Model.Data(r).Insert()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for inserting current object into table.
+func (r *Entity) InsertIgnore() (result sql.Result, err error) {
+	return Model.Data(r).InsertIgnore()
+}
+
+// Replace does "REPLACE...INTO..." statement for inserting current object into table.
+// If there's already another same record in the table (it checks using primary key or unique index),
+// it deletes it and insert this one.
+func (r *Entity) Replace() (result sql.Result, err error) {
+	return Model.Data(r).Replace()
+}
+
+// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Save() (result sql.Result, err error) {
+	return Model.Data(r).Save()
+}
+
+// Update does "UPDATE...WHERE..." statement for updating current object from table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Update() (result sql.Result, err error) {
+	return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
+}
+
+// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
+func (r *Entity) Delete() (result sql.Result, err error) {
+	return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
+}

+ 363 - 0
app/model/admin/plug_ad/plug_ad_model.go

@@ -0,0 +1,363 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package plug_ad
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+	"time"
+)
+
+// arModel is a active record design model for table plug_ad operations.
+type arModel struct {
+	gmvc.M
+}
+
+var (
+	// Table is the table name of plug_ad.
+	Table = "plug_ad"
+	// Model is the model object of plug_ad.
+	Model = &arModel{g.DB("default").Table(Table).Safe()}
+	// Columns defines and stores column names for table plug_ad.
+	Columns = struct {
+		AdId       string //
+		AdName     string // 广告名称
+		AdAdtypeid string // 所属位置
+		AdCheckid  string // 1=图片 2=JS
+		AdJs       string // JS代码
+		AdPic      string // 广告图片URL
+		AdUrl      string // 广告链接
+		AdContent  string // 广告文字内容
+		AdAddtime  string // 添加时间
+		AdSort     string // 排序
+		AdOpen     string // 1=审核  0=未审核
+	}{
+		AdId:       "ad_id",
+		AdName:     "ad_name",
+		AdAdtypeid: "ad_adtypeid",
+		AdCheckid:  "ad_checkid",
+		AdJs:       "ad_js",
+		AdPic:      "ad_pic",
+		AdUrl:      "ad_url",
+		AdContent:  "ad_content",
+		AdAddtime:  "ad_addtime",
+		AdSort:     "ad_sort",
+		AdOpen:     "ad_open",
+	}
+)
+
+// FindOne is a convenience method for Model.FindOne.
+// See Model.FindOne.
+func FindOne(where ...interface{}) (*Entity, error) {
+	return Model.FindOne(where...)
+}
+
+// FindAll is a convenience method for Model.FindAll.
+// See Model.FindAll.
+func FindAll(where ...interface{}) ([]*Entity, error) {
+	return Model.FindAll(where...)
+}
+
+// FindValue is a convenience method for Model.FindValue.
+// See Model.FindValue.
+func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
+	return Model.FindValue(fieldsAndWhere...)
+}
+
+// FindArray is a convenience method for Model.FindArray.
+// See Model.FindArray.
+func FindArray(fieldsAndWhere ...interface{}) ([]gdb.Value, error) {
+	return Model.FindArray(fieldsAndWhere...)
+}
+
+// FindCount is a convenience method for Model.FindCount.
+// See Model.FindCount.
+func FindCount(where ...interface{}) (int, error) {
+	return Model.FindCount(where...)
+}
+
+// Insert is a convenience method for Model.Insert.
+func Insert(data ...interface{}) (result sql.Result, err error) {
+	return Model.Insert(data...)
+}
+
+// InsertIgnore is a convenience method for Model.InsertIgnore.
+func InsertIgnore(data ...interface{}) (result sql.Result, err error) {
+	return Model.InsertIgnore(data...)
+}
+
+// Replace is a convenience method for Model.Replace.
+func Replace(data ...interface{}) (result sql.Result, err error) {
+	return Model.Replace(data...)
+}
+
+// Save is a convenience method for Model.Save.
+func Save(data ...interface{}) (result sql.Result, err error) {
+	return Model.Save(data...)
+}
+
+// Update is a convenience method for Model.Update.
+func Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
+	return Model.Update(dataAndWhere...)
+}
+
+// Delete is a convenience method for Model.Delete.
+func Delete(where ...interface{}) (result sql.Result, err error) {
+	return Model.Delete(where...)
+}
+
+// As sets an alias name for current table.
+func (m *arModel) As(as string) *arModel {
+	return &arModel{m.M.As(as)}
+}
+
+// TX sets the transaction for current operation.
+func (m *arModel) TX(tx *gdb.TX) *arModel {
+	return &arModel{m.M.TX(tx)}
+}
+
+// Master marks the following operation on master node.
+func (m *arModel) Master() *arModel {
+	return &arModel{m.M.Master()}
+}
+
+// Slave marks the following operation on slave node.
+// Note that it makes sense only if there's any slave node configured.
+func (m *arModel) Slave() *arModel {
+	return &arModel{m.M.Slave()}
+}
+
+// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) LeftJoin(table ...string) *arModel {
+	return &arModel{m.M.LeftJoin(table...)}
+}
+
+// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").RightJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) RightJoin(table ...string) *arModel {
+	return &arModel{m.M.RightJoin(table...)}
+}
+
+// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) InnerJoin(table ...string) *arModel {
+	return &arModel{m.M.InnerJoin(table...)}
+}
+
+// Fields sets the operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) Fields(fields string) *arModel {
+	return &arModel{m.M.Fields(fields)}
+}
+
+// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) FieldsEx(fields string) *arModel {
+	return &arModel{m.M.FieldsEx(fields)}
+}
+
+// Option sets the extra operation option for the model.
+func (m *arModel) Option(option int) *arModel {
+	return &arModel{m.M.Option(option)}
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (m *arModel) OmitEmpty() *arModel {
+	return &arModel{m.M.OmitEmpty()}
+}
+
+// Filter marks filtering the fields which does not exist in the fields of the operated table.
+func (m *arModel) Filter() *arModel {
+	return &arModel{m.M.Filter()}
+}
+
+// Where sets the condition statement for the model. The parameter <where> can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+// Eg:
+// Where("uid=10000")
+// Where("uid", 10000)
+// Where("money>? AND name like ?", 99999, "vip_%")
+// Where("uid", 1).Where("name", "john")
+// Where("status IN (?)", g.Slice{1,2,3})
+// Where("age IN(?,?)", 18, 50)
+// Where(User{ Id : 1, UserName : "john"})
+func (m *arModel) Where(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Where(where, args...)}
+}
+
+// And adds "AND" condition to the where statement.
+func (m *arModel) And(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.And(where, args...)}
+}
+
+// Or adds "OR" condition to the where statement.
+func (m *arModel) Or(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Or(where, args...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (m *arModel) Group(groupBy string) *arModel {
+	return &arModel{m.M.Group(groupBy)}
+}
+
+// Order sets the "ORDER BY" statement for the model.
+func (m *arModel) Order(orderBy ...string) *arModel {
+	return &arModel{m.M.Order(orderBy...)}
+}
+
+// Limit sets the "LIMIT" statement for the model.
+// The parameter <limit> can be either one or two number, if passed two number is passed,
+// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
+// statement.
+func (m *arModel) Limit(limit ...int) *arModel {
+	return &arModel{m.M.Limit(limit...)}
+}
+
+// Offset sets the "OFFSET" statement for the model.
+// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
+func (m *arModel) Offset(offset int) *arModel {
+	return &arModel{m.M.Offset(offset)}
+}
+
+// Page sets the paging number for the model.
+// The parameter <page> is started from 1 for paging.
+// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
+func (m *arModel) Page(page, limit int) *arModel {
+	return &arModel{m.M.Page(page, limit)}
+}
+
+// Batch sets the batch operation number for the model.
+func (m *arModel) Batch(batch int) *arModel {
+	return &arModel{m.M.Batch(batch)}
+}
+
+// Cache sets the cache feature for the model. It caches the result of the sql, which means
+// if there's another same sql request, it just reads and returns the result from cache, it
+// but not committed and executed into the database.
+//
+// If the parameter <duration> < 0, which means it clear the cache with given <name>.
+// If the parameter <duration> = 0, which means it never expires.
+// If the parameter <duration> > 0, which means it expires after <duration>.
+//
+// The optional parameter <name> is used to bind a name to the cache, which means you can later
+// control the cache like changing the <duration> or clearing the cache with specified <name>.
+//
+// Note that, the cache feature is disabled if the model is operating on a transaction.
+func (m *arModel) Cache(duration time.Duration, name ...string) *arModel {
+	return &arModel{m.M.Cache(duration, name...)}
+}
+
+// Data sets the operation data for the model.
+// The parameter <data> can be type of string/map/gmap/slice/struct/*struct, etc.
+// Eg:
+// Data("uid=10000")
+// Data("uid", 10000)
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+func (m *arModel) Data(data ...interface{}) *arModel {
+	return &arModel{m.M.Data(data...)}
+}
+
+// All does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as []*Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) All(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.All(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// One retrieves one record from table and returns the result as *Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) One(where ...interface{}) (*Entity, error) {
+	one, err := m.M.One(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindOne retrieves and returns a single Record by Model.WherePri and Model.One.
+// Also see Model.WherePri and Model.One.
+func (m *arModel) FindOne(where ...interface{}) (*Entity, error) {
+	one, err := m.M.FindOne(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindAll retrieves and returns Result by by Model.WherePri and Model.All.
+// Also see Model.WherePri and Model.All.
+func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.FindAll(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// Chunk iterates the table with given size and callback function.
+func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) {
+	m.M.Chunk(limit, func(result gdb.Result, err error) bool {
+		var entities []*Entity
+		err = result.Structs(&entities)
+		if err == sql.ErrNoRows {
+			return false
+		}
+		return callback(entities, err)
+	})
+}
+
+// LockUpdate sets the lock for update for current operation.
+func (m *arModel) LockUpdate() *arModel {
+	return &arModel{m.M.LockUpdate()}
+}
+
+// LockShared sets the lock in share mode for current operation.
+func (m *arModel) LockShared() *arModel {
+	return &arModel{m.M.LockShared()}
+}
+
+// Unscoped enables/disables the soft deleting feature.
+func (m *arModel) Unscoped() *arModel {
+	return &arModel{m.M.Unscoped()}
+}

+ 136 - 0
app/model/admin/plug_adtype/plug_adtype.go

@@ -0,0 +1,136 @@
+// ============================================================================
+// This is auto-generated by gf cli tool only once. Fill this file as you wish.
+// ============================================================================
+
+package plug_adtype
+
+import (
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+)
+
+// AddReq 用于存储新增广告位请求参数
+type AddReq struct {
+	AdtypeName string `p:"adTypeName" v:"required#广告位名称不能为空"` // 广告位名称
+	AdtypeSort int    `p:"adTypeSort" v:"required#广告位排序不能为空"` // 广告位排序
+}
+
+// EditReq 用于存储修改广告位请求参数
+type EditReq struct {
+	AdtypeID int64 `p:"adtypeID" v:"required|min:1#主键ID不能为空|主键ID值错误"`
+	AddReq
+}
+
+// SelectPageReq 用于存储分页查询广告位的请求参数
+type SelectPageReq struct {
+	AdtypeName string `p:"adTypeName"` // 广告位名称
+	PageNo     int64  `p:"pageNo"`     // 当前页
+	PageSize   int64  `p:"pageSize"`   // 每页显示记录数
+}
+
+// GetAdtypeByID 根据ID查询广告位记录
+func GetAdtypeByID(id int64) (*Entity, error) {
+	entity, err := Model.FindOne(id)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("根据ID查询广告位记录出错")
+	}
+	if entity == nil {
+		err = gerror.New("根据ID未能查询到广告位记录")
+	}
+	return entity, nil
+}
+
+// 根据广告位的名称来判断是否已存在相同名称的广告位
+func CheakAdtypeNameUnique(adtypeName string, adTypeId int64) error {
+	var (
+		entity *Entity
+		err    error
+	)
+	if adTypeId == 0 {
+		entity, err = Model.FindOne(Columns.AdtypeName, adtypeName)
+	} else {
+		entity, err = Model.Where(Columns.AdtypeName, adtypeName).And(Columns.AdtypeId+"!=?", adTypeId).FindOne()
+	}
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("校验广告位唯一性失败")
+	}
+	if entity != nil {
+		return gerror.New("广告位名称已经存在")
+	}
+	return nil
+}
+
+// AddSave 添加广告位
+func AddSave(req *AddReq) error {
+	var entity Entity
+	entity.AdtypeName = req.AdtypeName
+	entity.AdtypeSort = req.AdtypeSort
+	_, err := entity.Insert()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("保存广告位失败")
+	}
+	return nil
+}
+
+// 根据广告位ID来删除广告位
+func DeleteAdTypeByID(id []int) error {
+	_, err := Model.Where("adtype_id in(?)", id).Delete()
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("删除广告位失败")
+	}
+	return nil
+}
+
+// 根据广告位ID来修改广告位信息
+func EditSave(editReq *EditReq) error {
+	// 先根据ID来查询要修改的广告位记录
+	entity, err := GetAdtypeByID(editReq.AdtypeID)
+	if err != nil {
+		return err
+	}
+	// 修改实体
+	entity.AdtypeName = editReq.AdtypeName
+	entity.AdtypeSort = editReq.AdtypeSort
+	_, err = entity.Update()
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("修改广告位失败")
+	}
+	return nil
+}
+
+// 分页查询,返回值total总记录数,page当前页
+func SelectListByPage(req *SelectPageReq) (total int, page int64, list []*Entity, err error) {
+	model := Model
+	if req != nil {
+		if req.AdtypeName != "" {
+			model = model.Where("adtype_name like ?", "%"+req.AdtypeName+"%")
+		}
+	}
+	// 查询广告位总记录数(总行数)
+	total, err = model.Count()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取总记录数失败")
+		return 0, 0, nil, err
+	}
+	if req.PageNo == 0 {
+		req.PageNo = 1
+	}
+	page = req.PageNo
+	if req.PageSize == 0 {
+		req.PageSize = 10
+	}
+	// 分页排序查询
+	list, err = model.Page(int(page), int(req.PageSize)).Order("adtype_sort asc,adtype_id asc").All()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("分页查询广告位失败")
+		return 0, 0, nil, err
+	}
+	return total, page, list, nil
+}

+ 59 - 0
app/model/admin/plug_adtype/plug_adtype_entity.go

@@ -0,0 +1,59 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package plug_adtype
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+)
+
+// Entity is the golang structure for table plug_adtype.
+type Entity struct {
+	AdtypeId   int    `orm:"adtype_id,primary" json:"adtype_id"`   //
+	AdtypeName string `orm:"adtype_name"       json:"adtype_name"` // 广告位名称
+	AdtypeSort int    `orm:"adtype_sort"       json:"adtype_sort"` // 广告位排序
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (r *Entity) OmitEmpty() *arModel {
+	return Model.Data(r).OmitEmpty()
+}
+
+// Inserts does "INSERT...INTO..." statement for inserting current object into table.
+func (r *Entity) Insert() (result sql.Result, err error) {
+	return Model.Data(r).Insert()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for inserting current object into table.
+func (r *Entity) InsertIgnore() (result sql.Result, err error) {
+	return Model.Data(r).InsertIgnore()
+}
+
+// Replace does "REPLACE...INTO..." statement for inserting current object into table.
+// If there's already another same record in the table (it checks using primary key or unique index),
+// it deletes it and insert this one.
+func (r *Entity) Replace() (result sql.Result, err error) {
+	return Model.Data(r).Replace()
+}
+
+// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Save() (result sql.Result, err error) {
+	return Model.Data(r).Save()
+}
+
+// Update does "UPDATE...WHERE..." statement for updating current object from table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Update() (result sql.Result, err error) {
+	return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
+}
+
+// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
+func (r *Entity) Delete() (result sql.Result, err error) {
+	return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
+}

+ 347 - 0
app/model/admin/plug_adtype/plug_adtype_model.go

@@ -0,0 +1,347 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package plug_adtype
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+	"time"
+)
+
+// arModel is a active record design model for table plug_adtype operations.
+type arModel struct {
+	gmvc.M
+}
+
+var (
+	// Table is the table name of plug_adtype.
+	Table = "plug_adtype"
+	// Model is the model object of plug_adtype.
+	Model = &arModel{g.DB("default").Table(Table).Safe()}
+	// Columns defines and stores column names for table plug_adtype.
+	Columns = struct {
+		AdtypeId   string //
+		AdtypeName string // 广告位名称
+		AdtypeSort string // 广告位排序
+	}{
+		AdtypeId:   "adtype_id",
+		AdtypeName: "adtype_name",
+		AdtypeSort: "adtype_sort",
+	}
+)
+
+// FindOne is a convenience method for Model.FindOne.
+// See Model.FindOne.
+func FindOne(where ...interface{}) (*Entity, error) {
+	return Model.FindOne(where...)
+}
+
+// FindAll is a convenience method for Model.FindAll.
+// See Model.FindAll.
+func FindAll(where ...interface{}) ([]*Entity, error) {
+	return Model.FindAll(where...)
+}
+
+// FindValue is a convenience method for Model.FindValue.
+// See Model.FindValue.
+func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
+	return Model.FindValue(fieldsAndWhere...)
+}
+
+// FindArray is a convenience method for Model.FindArray.
+// See Model.FindArray.
+func FindArray(fieldsAndWhere ...interface{}) ([]gdb.Value, error) {
+	return Model.FindArray(fieldsAndWhere...)
+}
+
+// FindCount is a convenience method for Model.FindCount.
+// See Model.FindCount.
+func FindCount(where ...interface{}) (int, error) {
+	return Model.FindCount(where...)
+}
+
+// Insert is a convenience method for Model.Insert.
+func Insert(data ...interface{}) (result sql.Result, err error) {
+	return Model.Insert(data...)
+}
+
+// InsertIgnore is a convenience method for Model.InsertIgnore.
+func InsertIgnore(data ...interface{}) (result sql.Result, err error) {
+	return Model.InsertIgnore(data...)
+}
+
+// Replace is a convenience method for Model.Replace.
+func Replace(data ...interface{}) (result sql.Result, err error) {
+	return Model.Replace(data...)
+}
+
+// Save is a convenience method for Model.Save.
+func Save(data ...interface{}) (result sql.Result, err error) {
+	return Model.Save(data...)
+}
+
+// Update is a convenience method for Model.Update.
+func Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
+	return Model.Update(dataAndWhere...)
+}
+
+// Delete is a convenience method for Model.Delete.
+func Delete(where ...interface{}) (result sql.Result, err error) {
+	return Model.Delete(where...)
+}
+
+// As sets an alias name for current table.
+func (m *arModel) As(as string) *arModel {
+	return &arModel{m.M.As(as)}
+}
+
+// TX sets the transaction for current operation.
+func (m *arModel) TX(tx *gdb.TX) *arModel {
+	return &arModel{m.M.TX(tx)}
+}
+
+// Master marks the following operation on master node.
+func (m *arModel) Master() *arModel {
+	return &arModel{m.M.Master()}
+}
+
+// Slave marks the following operation on slave node.
+// Note that it makes sense only if there's any slave node configured.
+func (m *arModel) Slave() *arModel {
+	return &arModel{m.M.Slave()}
+}
+
+// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) LeftJoin(table ...string) *arModel {
+	return &arModel{m.M.LeftJoin(table...)}
+}
+
+// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").RightJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) RightJoin(table ...string) *arModel {
+	return &arModel{m.M.RightJoin(table...)}
+}
+
+// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) InnerJoin(table ...string) *arModel {
+	return &arModel{m.M.InnerJoin(table...)}
+}
+
+// Fields sets the operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) Fields(fields string) *arModel {
+	return &arModel{m.M.Fields(fields)}
+}
+
+// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) FieldsEx(fields string) *arModel {
+	return &arModel{m.M.FieldsEx(fields)}
+}
+
+// Option sets the extra operation option for the model.
+func (m *arModel) Option(option int) *arModel {
+	return &arModel{m.M.Option(option)}
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (m *arModel) OmitEmpty() *arModel {
+	return &arModel{m.M.OmitEmpty()}
+}
+
+// Filter marks filtering the fields which does not exist in the fields of the operated table.
+func (m *arModel) Filter() *arModel {
+	return &arModel{m.M.Filter()}
+}
+
+// Where sets the condition statement for the model. The parameter <where> can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+// Eg:
+// Where("uid=10000")
+// Where("uid", 10000)
+// Where("money>? AND name like ?", 99999, "vip_%")
+// Where("uid", 1).Where("name", "john")
+// Where("status IN (?)", g.Slice{1,2,3})
+// Where("age IN(?,?)", 18, 50)
+// Where(User{ Id : 1, UserName : "john"})
+func (m *arModel) Where(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Where(where, args...)}
+}
+
+// And adds "AND" condition to the where statement.
+func (m *arModel) And(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.And(where, args...)}
+}
+
+// Or adds "OR" condition to the where statement.
+func (m *arModel) Or(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Or(where, args...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (m *arModel) Group(groupBy string) *arModel {
+	return &arModel{m.M.Group(groupBy)}
+}
+
+// Order sets the "ORDER BY" statement for the model.
+func (m *arModel) Order(orderBy ...string) *arModel {
+	return &arModel{m.M.Order(orderBy...)}
+}
+
+// Limit sets the "LIMIT" statement for the model.
+// The parameter <limit> can be either one or two number, if passed two number is passed,
+// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
+// statement.
+func (m *arModel) Limit(limit ...int) *arModel {
+	return &arModel{m.M.Limit(limit...)}
+}
+
+// Offset sets the "OFFSET" statement for the model.
+// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
+func (m *arModel) Offset(offset int) *arModel {
+	return &arModel{m.M.Offset(offset)}
+}
+
+// Page sets the paging number for the model.
+// The parameter <page> is started from 1 for paging.
+// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
+func (m *arModel) Page(page, limit int) *arModel {
+	return &arModel{m.M.Page(page, limit)}
+}
+
+// Batch sets the batch operation number for the model.
+func (m *arModel) Batch(batch int) *arModel {
+	return &arModel{m.M.Batch(batch)}
+}
+
+// Cache sets the cache feature for the model. It caches the result of the sql, which means
+// if there's another same sql request, it just reads and returns the result from cache, it
+// but not committed and executed into the database.
+//
+// If the parameter <duration> < 0, which means it clear the cache with given <name>.
+// If the parameter <duration> = 0, which means it never expires.
+// If the parameter <duration> > 0, which means it expires after <duration>.
+//
+// The optional parameter <name> is used to bind a name to the cache, which means you can later
+// control the cache like changing the <duration> or clearing the cache with specified <name>.
+//
+// Note that, the cache feature is disabled if the model is operating on a transaction.
+func (m *arModel) Cache(duration time.Duration, name ...string) *arModel {
+	return &arModel{m.M.Cache(duration, name...)}
+}
+
+// Data sets the operation data for the model.
+// The parameter <data> can be type of string/map/gmap/slice/struct/*struct, etc.
+// Eg:
+// Data("uid=10000")
+// Data("uid", 10000)
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+func (m *arModel) Data(data ...interface{}) *arModel {
+	return &arModel{m.M.Data(data...)}
+}
+
+// All does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as []*Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) All(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.All(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// One retrieves one record from table and returns the result as *Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) One(where ...interface{}) (*Entity, error) {
+	one, err := m.M.One(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindOne retrieves and returns a single Record by Model.WherePri and Model.One.
+// Also see Model.WherePri and Model.One.
+func (m *arModel) FindOne(where ...interface{}) (*Entity, error) {
+	one, err := m.M.FindOne(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindAll retrieves and returns Result by by Model.WherePri and Model.All.
+// Also see Model.WherePri and Model.All.
+func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.FindAll(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// Chunk iterates the table with given size and callback function.
+func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) {
+	m.M.Chunk(limit, func(result gdb.Result, err error) bool {
+		var entities []*Entity
+		err = result.Structs(&entities)
+		if err == sql.ErrNoRows {
+			return false
+		}
+		return callback(entities, err)
+	})
+}
+
+// LockUpdate sets the lock for update for current operation.
+func (m *arModel) LockUpdate() *arModel {
+	return &arModel{m.M.LockUpdate()}
+}
+
+// LockShared sets the lock in share mode for current operation.
+func (m *arModel) LockShared() *arModel {
+	return &arModel{m.M.LockShared()}
+}
+
+// Unscoped enables/disables the soft deleting feature.
+func (m *arModel) Unscoped() *arModel {
+	return &arModel{m.M.Unscoped()}
+}

+ 135 - 11
app/model/admin/role/role.go

@@ -4,8 +4,10 @@ import (
 	"database/sql"
 	"errors"
 	"fmt"
+	"gfast/app/model/admin/role_dept"
 	"gfast/app/service/cache_service"
 	"gfast/app/service/casbin_adapter_service"
+	"gfast/library/service"
 	"gfast/library/utils"
 	"github.com/gogf/gf/database/gdb"
 	"github.com/gogf/gf/errors/gerror"
@@ -15,6 +17,69 @@ import (
 	"github.com/gogf/gf/util/gvalid"
 )
 
+//分页请求参数
+type SelectPageReq struct {
+	RoleName  string `p:"roleName"`  //参数名称
+	BeginTime string `p:"beginTime"` //开始时间
+	EndTime   string `p:"endTime"`   //结束时间
+	Status    string `p:"status"`    //状态
+	PageNum   int    `p:"pageNum"`   //当前页码
+	PageSize  int    `p:"pageSize"`  //每页数
+}
+
+//修改状态参数
+type StatusSetReq struct {
+	RoleId uint `p:"roleId" v:"required#角色ID不能为空"`
+	Status int  `p:"status" v:"required#状态不能为空"`
+}
+
+//角色数据授权参数
+type DataScopeReq struct {
+	RoleId    uint   `p:"roleId" v:"required#角色ID不能为空"`
+	DataScope uint   `p:"dataScope" v:"required#权限范围不能为空"`
+	DeptIds   []uint `p:"deptIds"`
+}
+
+func GetRoleListSearch(req *SelectPageReq) (total, page int, list []*Entity, err error) {
+	model := Model
+	if req != nil {
+		if req.RoleName != "" {
+			model = model.Where("name like ?", "%"+req.RoleName+"%")
+		}
+		if req.Status != "" {
+			model = model.Where("status", gconv.Int(req.Status))
+		}
+		if req.BeginTime != "" {
+			model = model.Where("create_time >= ? ", utils.StrToTimestamp(req.BeginTime))
+		}
+
+		if req.EndTime != "" {
+			model = model.Where("create_time<=?", utils.StrToTimestamp(req.EndTime))
+		}
+	}
+	total, err = model.Count()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取总行数失败")
+		return
+	}
+	if req.PageNum == 0 {
+		req.PageNum = 1
+	}
+	page = req.PageNum
+	if req.PageSize == 0 {
+		req.PageSize = service.AdminPageNum
+	}
+
+	list, err = model.Page(page, req.PageSize).Order("id asc").All()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取数据失败")
+		return
+	}
+	return
+}
+
 //获取用户组(角色)列表
 func GetList() (list []*Entity, err error) {
 	cache := cache_service.New()
@@ -33,8 +98,7 @@ func GetList() (list []*Entity, err error) {
 
 func checkRoleData(params map[string]interface{}) error {
 	rules := []string{
-		"name@required|length:1,20#请填写角色名称|名称应在:min到:max个字符之间",
-		"parent_id@integer|min:0#父级ID必须为整数|父级ID必须大于等于0",
+		"roleName@required|length:1,20#请填写角色名称|名称应在:min到:max个字符之间",
 	}
 
 	e := gvalid.CheckMap(params, rules)
@@ -53,12 +117,11 @@ func Add(tx *gdb.TX, data map[string]interface{}) (InsId int64, err error) {
 	//保存角色信息
 	now := gtime.Timestamp()
 	roleMap := gdb.Map{
-		"parent_id":   data["parent_id"],
 		"status":      data["status"],
-		"name":        data["name"],
+		"name":        data["roleName"],
 		"create_time": now,
 		"update_time": now,
-		"list_order":  data["list_order"],
+		"list_order":  data["roleSort"],
 		"remark":      data["remark"],
 	}
 	var res sql.Result
@@ -72,7 +135,7 @@ func Add(tx *gdb.TX, data map[string]interface{}) (InsId int64, err error) {
 
 //修改角色信息操作
 func Edit(tx *gdb.TX, data map[string]interface{}) (err error) {
-	if _, k := data["id"]; !k {
+	if _, k := data["roleId"]; !k {
 		err = errors.New("缺少更新条件Id")
 		return
 	}
@@ -83,12 +146,11 @@ func Edit(tx *gdb.TX, data map[string]interface{}) (err error) {
 	//保存角色信息
 	now := gtime.Timestamp()
 	roleMap := gdb.Map{
-		"id":          data["id"],
-		"parent_id":   data["parent_id"],
+		"id":          data["roleId"],
 		"status":      data["status"],
-		"name":        data["name"],
+		"name":        data["roleName"],
 		"update_time": now,
-		"list_order":  data["list_order"],
+		"list_order":  data["roleSort"],
 		"remark":      data["remark"],
 	}
 	_, err = tx.Table(Table).Data(roleMap).Save()
@@ -98,6 +160,61 @@ func Edit(tx *gdb.TX, data map[string]interface{}) (err error) {
 	return
 }
 
+//设置角色状态
+func StatusSetRole(req *StatusSetReq) error {
+	if req != nil {
+		entity, err := Model.Where("id", req.RoleId).One()
+		if err != nil {
+			g.Log().Error(err)
+			return gerror.New("获取角色信息失败")
+		}
+		entity.Status = req.Status
+		_, err = entity.Update()
+		if err != nil {
+			g.Log().Error(err)
+			return gerror.New("设置状态失败")
+		}
+	}
+	return nil
+}
+
+//设置角色数据权限
+func DataScope(req *DataScopeReq) error {
+	tx, err := g.DB().Begin()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("设置失败")
+		return err
+	}
+	_, err = tx.Table(Table).Where("id", req.RoleId).Data(g.Map{"data_scope": req.DataScope}).Update()
+	if err != nil {
+		g.Log().Error(err)
+		tx.Rollback()
+		return gerror.New("设置失败")
+	}
+	if req.DataScope == 2 {
+		_, err := tx.Table(role_dept.Table).Delete(role_dept.Columns.RoleId, req.RoleId)
+		if err != nil {
+			g.Log().Error(err)
+			tx.Rollback()
+			return gerror.New("设置失败")
+		}
+		//自定义数据权限
+		data := g.List{}
+		for _, deptId := range req.DeptIds {
+			data = append(data, g.Map{role_dept.Columns.RoleId: req.RoleId, role_dept.Columns.DeptId: deptId})
+		}
+		_, err = tx.Table(role_dept.Table).Data(data).Insert()
+		if err != nil {
+			g.Log().Error(err)
+			tx.Rollback()
+			return gerror.New("设置失败")
+		}
+	}
+	tx.Commit()
+	return nil
+}
+
 //删除角色权限操作
 func DeleteRoleRule(roleId int) (err error) {
 	enforcer, e := casbin_adapter_service.GetEnforcer()
@@ -147,7 +264,7 @@ func DeleteByIds(ids []int) (err error) {
 		err = gerror.New("删除失败")
 		return
 	}
-	//删除角色的权限
+	//删除角色的权限和管理的部门数据权限
 	for _, v := range ids {
 		err = DeleteRoleRule(v)
 		if err != nil {
@@ -156,6 +273,13 @@ func DeleteByIds(ids []int) (err error) {
 			err = gerror.New("删除失败")
 			return
 		}
+		_, err = tx.Table(role_dept.Table).Delete(role_dept.Columns.RoleId, v)
+		if err != nil {
+			g.Log().Error(err)
+			tx.Rollback()
+			err = gerror.New("删除失败")
+			return
+		}
 	}
 	tx.Commit()
 	return

+ 8 - 8
app/model/admin/role/role_entity.go

@@ -11,14 +11,14 @@ import (
 
 // Entity is the golang structure for table _role.
 type Entity struct {
-	Id         int     `orm:"id,primary"  json:"id"`          //
-	ParentId   int     `orm:"parent_id"   json:"parent_id"`   // 父角色ID
-	Status     int     `orm:"status"      json:"status"`      // 状态;0:禁用;1:正常
-	CreateTime int     `orm:"create_time" json:"create_time"` // 创建时间
-	UpdateTime int     `orm:"update_time" json:"update_time"` // 更新时间
-	ListOrder  float64 `orm:"list_order"  json:"list_order"`  // 排序
-	Name       string  `orm:"name"        json:"name"`        // 角色名称
-	Remark     string  `orm:"remark"      json:"remark"`      // 备注
+	Id         int     `orm:"id,primary"  json:"id"`             //
+	Status     int     `orm:"status"      json:"status"`         // 状态;0:禁用;1:正常
+	CreateTime int     `orm:"create_time" json:"create_time"`    // 创建时间
+	UpdateTime int     `orm:"update_time" json:"update_time"`    // 更新时间
+	ListOrder  float64 `orm:"list_order"  json:"list_order"`     // 排序
+	Name       string  `orm:"name"        json:"name"`           // 角色名称
+	Remark     string  `orm:"remark"      json:"remark"`         // 备注
+	DataScope  int     `orm:"data_scope"      json:"data_scope"` // 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)
 }
 
 // Role is alias of Entity, which some developers say they just want.

+ 45 - 33
app/model/admin/role/role_model.go

@@ -13,7 +13,7 @@ import (
 
 // arModel is a active record design model for table _role operations.
 type arModel struct {
-	Model *gdb.Model
+	M *gdb.Model
 }
 
 var (
@@ -25,59 +25,59 @@ var (
 
 // TX sets the transaction for current operation.
 func (m *arModel) TX(tx *gdb.TX) *arModel {
-	return &arModel{m.Model.TX(tx)}
+	return &arModel{m.M.TX(tx)}
 }
 
 // Master marks the following operation on master node.
 func (m *arModel) Master() *arModel {
-	return &arModel{m.Model.Master()}
+	return &arModel{m.M.Master()}
 }
 
 // Slave marks the following operation on slave node.
 // Note that it makes sense only if there's any slave node configured.
 func (m *arModel) Slave() *arModel {
-	return &arModel{m.Model.Slave()}
+	return &arModel{m.M.Slave()}
 }
 
 // LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
 func (m *arModel) LeftJoin(joinTable string, on string) *arModel {
-	return &arModel{m.Model.LeftJoin(joinTable, on)}
+	return &arModel{m.M.LeftJoin(joinTable, on)}
 }
 
 // RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
 func (m *arModel) RightJoin(joinTable string, on string) *arModel {
-	return &arModel{m.Model.RightJoin(joinTable, on)}
+	return &arModel{m.M.RightJoin(joinTable, on)}
 }
 
 // InnerJoin does "INNER JOIN ... ON ..." statement on the model.
 func (m *arModel) InnerJoin(joinTable string, on string) *arModel {
-	return &arModel{m.Model.InnerJoin(joinTable, on)}
+	return &arModel{m.M.InnerJoin(joinTable, on)}
 }
 
 // Fields sets the operation fields of the model, multiple fields joined using char ','.
 func (m *arModel) Fields(fields string) *arModel {
-	return &arModel{m.Model.Fields(fields)}
+	return &arModel{m.M.Fields(fields)}
 }
 
 // FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
 func (m *arModel) FieldsEx(fields string) *arModel {
-	return &arModel{m.Model.FieldsEx(fields)}
+	return &arModel{m.M.FieldsEx(fields)}
 }
 
 // Option sets the extra operation option for the model.
 func (m *arModel) Option(option int) *arModel {
-	return &arModel{m.Model.Option(option)}
+	return &arModel{m.M.Option(option)}
 }
 
 // OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
 // the data and where attributes for empty values.
 func (m *arModel) OmitEmpty() *arModel {
-	return &arModel{m.Model.OmitEmpty()}
+	return &arModel{m.M.OmitEmpty()}
 }
 
 // Filter marks filtering the fields which does not exist in the fields of the operated table.
 func (m *arModel) Filter() *arModel {
-	return &arModel{m.Model.Filter()}
+	return &arModel{m.M.Filter()}
 }
 
 // Where sets the condition statement for the model. The parameter <where> can be type of
@@ -92,27 +92,27 @@ func (m *arModel) Filter() *arModel {
 // Where("age IN(?,?)", 18, 50)
 // Where(User{ Id : 1, UserName : "john"})
 func (m *arModel) Where(where interface{}, args ...interface{}) *arModel {
-	return &arModel{m.Model.Where(where, args...)}
+	return &arModel{m.M.Where(where, args...)}
 }
 
 // And adds "AND" condition to the where statement.
 func (m *arModel) And(where interface{}, args ...interface{}) *arModel {
-	return &arModel{m.Model.And(where, args...)}
+	return &arModel{m.M.And(where, args...)}
 }
 
 // Or adds "OR" condition to the where statement.
 func (m *arModel) Or(where interface{}, args ...interface{}) *arModel {
-	return &arModel{m.Model.Or(where, args...)}
+	return &arModel{m.M.Or(where, args...)}
 }
 
 // GroupBy sets the "GROUP BY" statement for the model.
 func (m *arModel) GroupBy(groupBy string) *arModel {
-	return &arModel{m.Model.GroupBy(groupBy)}
+	return &arModel{m.M.GroupBy(groupBy)}
 }
 
 // OrderBy sets the "ORDER BY" statement for the model.
 func (m *arModel) OrderBy(orderBy string) *arModel {
-	return &arModel{m.Model.OrderBy(orderBy)}
+	return &arModel{m.M.OrderBy(orderBy)}
 }
 
 // Limit sets the "LIMIT" statement for the model.
@@ -120,25 +120,25 @@ func (m *arModel) OrderBy(orderBy string) *arModel {
 // it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
 // statement.
 func (m *arModel) Limit(limit ...int) *arModel {
-	return &arModel{m.Model.Limit(limit...)}
+	return &arModel{m.M.Limit(limit...)}
 }
 
 // Offset sets the "OFFSET" statement for the model.
 // It only makes sense for some databases like SQLServer, PostgreSQL, etc.
 func (m *arModel) Offset(offset int) *arModel {
-	return &arModel{m.Model.Offset(offset)}
+	return &arModel{m.M.Offset(offset)}
 }
 
 // ForPage sets the paging number for the model.
 // The parameter <page> is started from 1 for paging.
 // Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
 func (m *arModel) ForPage(page, limit int) *arModel {
-	return &arModel{m.Model.ForPage(page, limit)}
+	return &arModel{m.M.ForPage(page, limit)}
 }
 
 // Batch sets the batch operation number for the model.
 func (m *arModel) Batch(batch int) *arModel {
-	return &arModel{m.Model.Batch(batch)}
+	return &arModel{m.M.Batch(batch)}
 }
 
 // Cache sets the cache feature for the model. It caches the result of the sql, which means
@@ -154,7 +154,7 @@ func (m *arModel) Batch(batch int) *arModel {
 //
 // Note that, the cache feature is disabled if the model is operating on a transaction.
 func (m *arModel) Cache(expire time.Duration, name ...string) *arModel {
-	return &arModel{m.Model.Cache(expire, name...)}
+	return &arModel{m.M.Cache(expire, name...)}
 }
 
 // Data sets the operation data for the model.
@@ -165,46 +165,46 @@ func (m *arModel) Cache(expire time.Duration, name ...string) *arModel {
 // Data(g.Map{"uid": 10000, "name":"john"})
 // Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
 func (m *arModel) Data(data ...interface{}) *arModel {
-	return &arModel{m.Model.Data(data...)}
+	return &arModel{m.M.Data(data...)}
 }
 
 // Insert does "INSERT INTO ..." statement for the model.
 func (m *arModel) Insert() (result sql.Result, err error) {
-	return m.Model.Insert()
+	return m.M.Insert()
 }
 
 // Replace does "REPLACE INTO ..." statement for the model.
 func (m *arModel) Replace() (result sql.Result, err error) {
-	return m.Model.Replace()
+	return m.M.Replace()
 }
 
 // Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the model.
 // It updates the record if there's primary or unique index in the saving data,
 // or else it inserts a new record into the table.
 func (m *arModel) Save() (result sql.Result, err error) {
-	return m.Model.Save()
+	return m.M.Save()
 }
 
 // Update does "UPDATE ... " statement for the model.
 func (m *arModel) Update() (result sql.Result, err error) {
-	return m.Model.Update()
+	return m.M.Update()
 }
 
 // Delete does "DELETE FROM ... " statement for the model.
 func (m *arModel) Delete() (result sql.Result, err error) {
-	return m.Model.Delete()
+	return m.M.Delete()
 }
 
 // Count does "SELECT COUNT(x) FROM ..." statement for the model.
 func (m *arModel) Count() (int, error) {
-	return m.Model.Count()
+	return m.M.Count()
 }
 
 // All does "SELECT FROM ..." statement for the model.
 // It retrieves the records from table and returns the result as []*Entity.
 // It returns nil if there's no record retrieved with the given conditions from table.
 func (m *arModel) All() ([]*Entity, error) {
-	all, err := m.Model.All()
+	all, err := m.M.All()
 	if err != nil {
 		return nil, err
 	}
@@ -218,7 +218,7 @@ func (m *arModel) All() ([]*Entity, error) {
 // One retrieves one record from table and returns the result as *Entity.
 // It returns nil if there's no record retrieved with the given conditions from table.
 func (m *arModel) One() (*Entity, error) {
-	one, err := m.Model.One()
+	one, err := m.M.One()
 	if err != nil {
 		return nil, err
 	}
@@ -232,12 +232,12 @@ func (m *arModel) One() (*Entity, error) {
 // Value retrieves a specified record value from table and returns the result as interface type.
 // It returns nil if there's no record found with the given conditions from table.
 func (m *arModel) Value() (gdb.Value, error) {
-	return m.Model.Value()
+	return m.M.Value()
 }
 
 // Chunk iterates the table with given size and callback function.
 func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) {
-	m.Model.Chunk(limit, func(result gdb.Result, err error) bool {
+	m.M.Chunk(limit, func(result gdb.Result, err error) bool {
 		var entities []*Entity
 		err = result.Structs(&entities)
 		if err == sql.ErrNoRows {
@@ -246,3 +246,15 @@ func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error)
 		return callback(entities, err)
 	})
 }
+
+// Page sets the paging number for the model.
+// The parameter <page> is started from 1 for paging.
+// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
+func (m *arModel) Page(page, limit int) *arModel {
+	return &arModel{m.M.Page(page, limit)}
+}
+
+// Order sets the "ORDER BY" statement for the model.
+func (m *arModel) Order(orderBy string) *arModel {
+	return &arModel{m.M.Order(orderBy)}
+}

+ 20 - 0
app/model/admin/role_dept/role_dept.go

@@ -0,0 +1,20 @@
+// ============================================================================
+// This is auto-generated by gf cli tool only once. Fill this file as you wish.
+// ============================================================================
+
+package role_dept
+
+// Fill with you ideas below.
+
+//获取角色的部门数据
+func GetRoleDepts(roleId int64) ([]int64, error) {
+	entity, err := Model.All(Columns.RoleId, roleId)
+	if err != nil {
+		return nil, err
+	}
+	d := make([]int64, len(entity))
+	for k, v := range entity {
+		d[k] = v.DeptId
+	}
+	return d, nil
+}

+ 58 - 0
app/model/admin/role_dept/role_dept_entity.go

@@ -0,0 +1,58 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package role_dept
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+)
+
+// Entity is the golang structure for table role_dept.
+type Entity struct {
+	RoleId int64 `orm:"role_id,primary" json:"role_id"` // 角色ID
+	DeptId int64 `orm:"dept_id,primary" json:"dept_id"` // 部门ID
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (r *Entity) OmitEmpty() *arModel {
+	return Model.Data(r).OmitEmpty()
+}
+
+// Inserts does "INSERT...INTO..." statement for inserting current object into table.
+func (r *Entity) Insert() (result sql.Result, err error) {
+	return Model.Data(r).Insert()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for inserting current object into table.
+func (r *Entity) InsertIgnore() (result sql.Result, err error) {
+	return Model.Data(r).InsertIgnore()
+}
+
+// Replace does "REPLACE...INTO..." statement for inserting current object into table.
+// If there's already another same record in the table (it checks using primary key or unique index),
+// it deletes it and insert this one.
+func (r *Entity) Replace() (result sql.Result, err error) {
+	return Model.Data(r).Replace()
+}
+
+// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Save() (result sql.Result, err error) {
+	return Model.Data(r).Save()
+}
+
+// Update does "UPDATE...WHERE..." statement for updating current object from table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Update() (result sql.Result, err error) {
+	return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
+}
+
+// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
+func (r *Entity) Delete() (result sql.Result, err error) {
+	return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
+}

+ 345 - 0
app/model/admin/role_dept/role_dept_model.go

@@ -0,0 +1,345 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package role_dept
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+	"time"
+)
+
+// arModel is a active record design model for table role_dept operations.
+type arModel struct {
+	gmvc.M
+}
+
+var (
+	// Table is the table name of role_dept.
+	Table = "role_dept"
+	// Model is the model object of role_dept.
+	Model = &arModel{g.DB("default").Table(Table).Safe()}
+	// Columns defines and stores column names for table role_dept.
+	Columns = struct {
+		RoleId string // 角色ID
+		DeptId string // 部门ID
+	}{
+		RoleId: "role_id",
+		DeptId: "dept_id",
+	}
+)
+
+// FindOne is a convenience method for Model.FindOne.
+// See Model.FindOne.
+func FindOne(where ...interface{}) (*Entity, error) {
+	return Model.FindOne(where...)
+}
+
+// FindAll is a convenience method for Model.FindAll.
+// See Model.FindAll.
+func FindAll(where ...interface{}) ([]*Entity, error) {
+	return Model.FindAll(where...)
+}
+
+// FindValue is a convenience method for Model.FindValue.
+// See Model.FindValue.
+func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
+	return Model.FindValue(fieldsAndWhere...)
+}
+
+// FindArray is a convenience method for Model.FindArray.
+// See Model.FindArray.
+func FindArray(fieldsAndWhere ...interface{}) ([]gdb.Value, error) {
+	return Model.FindArray(fieldsAndWhere...)
+}
+
+// FindCount is a convenience method for Model.FindCount.
+// See Model.FindCount.
+func FindCount(where ...interface{}) (int, error) {
+	return Model.FindCount(where...)
+}
+
+// Insert is a convenience method for Model.Insert.
+func Insert(data ...interface{}) (result sql.Result, err error) {
+	return Model.Insert(data...)
+}
+
+// InsertIgnore is a convenience method for Model.InsertIgnore.
+func InsertIgnore(data ...interface{}) (result sql.Result, err error) {
+	return Model.InsertIgnore(data...)
+}
+
+// Replace is a convenience method for Model.Replace.
+func Replace(data ...interface{}) (result sql.Result, err error) {
+	return Model.Replace(data...)
+}
+
+// Save is a convenience method for Model.Save.
+func Save(data ...interface{}) (result sql.Result, err error) {
+	return Model.Save(data...)
+}
+
+// Update is a convenience method for Model.Update.
+func Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
+	return Model.Update(dataAndWhere...)
+}
+
+// Delete is a convenience method for Model.Delete.
+func Delete(where ...interface{}) (result sql.Result, err error) {
+	return Model.Delete(where...)
+}
+
+// As sets an alias name for current table.
+func (m *arModel) As(as string) *arModel {
+	return &arModel{m.M.As(as)}
+}
+
+// TX sets the transaction for current operation.
+func (m *arModel) TX(tx *gdb.TX) *arModel {
+	return &arModel{m.M.TX(tx)}
+}
+
+// Master marks the following operation on master node.
+func (m *arModel) Master() *arModel {
+	return &arModel{m.M.Master()}
+}
+
+// Slave marks the following operation on slave node.
+// Note that it makes sense only if there's any slave node configured.
+func (m *arModel) Slave() *arModel {
+	return &arModel{m.M.Slave()}
+}
+
+// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) LeftJoin(table ...string) *arModel {
+	return &arModel{m.M.LeftJoin(table...)}
+}
+
+// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").RightJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) RightJoin(table ...string) *arModel {
+	return &arModel{m.M.RightJoin(table...)}
+}
+
+// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) InnerJoin(table ...string) *arModel {
+	return &arModel{m.M.InnerJoin(table...)}
+}
+
+// Fields sets the operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) Fields(fields string) *arModel {
+	return &arModel{m.M.Fields(fields)}
+}
+
+// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) FieldsEx(fields string) *arModel {
+	return &arModel{m.M.FieldsEx(fields)}
+}
+
+// Option sets the extra operation option for the model.
+func (m *arModel) Option(option int) *arModel {
+	return &arModel{m.M.Option(option)}
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (m *arModel) OmitEmpty() *arModel {
+	return &arModel{m.M.OmitEmpty()}
+}
+
+// Filter marks filtering the fields which does not exist in the fields of the operated table.
+func (m *arModel) Filter() *arModel {
+	return &arModel{m.M.Filter()}
+}
+
+// Where sets the condition statement for the model. The parameter <where> can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+// Eg:
+// Where("uid=10000")
+// Where("uid", 10000)
+// Where("money>? AND name like ?", 99999, "vip_%")
+// Where("uid", 1).Where("name", "john")
+// Where("status IN (?)", g.Slice{1,2,3})
+// Where("age IN(?,?)", 18, 50)
+// Where(User{ Id : 1, UserName : "john"})
+func (m *arModel) Where(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Where(where, args...)}
+}
+
+// And adds "AND" condition to the where statement.
+func (m *arModel) And(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.And(where, args...)}
+}
+
+// Or adds "OR" condition to the where statement.
+func (m *arModel) Or(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Or(where, args...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (m *arModel) Group(groupBy string) *arModel {
+	return &arModel{m.M.Group(groupBy)}
+}
+
+// Order sets the "ORDER BY" statement for the model.
+func (m *arModel) Order(orderBy ...string) *arModel {
+	return &arModel{m.M.Order(orderBy...)}
+}
+
+// Limit sets the "LIMIT" statement for the model.
+// The parameter <limit> can be either one or two number, if passed two number is passed,
+// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
+// statement.
+func (m *arModel) Limit(limit ...int) *arModel {
+	return &arModel{m.M.Limit(limit...)}
+}
+
+// Offset sets the "OFFSET" statement for the model.
+// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
+func (m *arModel) Offset(offset int) *arModel {
+	return &arModel{m.M.Offset(offset)}
+}
+
+// Page sets the paging number for the model.
+// The parameter <page> is started from 1 for paging.
+// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
+func (m *arModel) Page(page, limit int) *arModel {
+	return &arModel{m.M.Page(page, limit)}
+}
+
+// Batch sets the batch operation number for the model.
+func (m *arModel) Batch(batch int) *arModel {
+	return &arModel{m.M.Batch(batch)}
+}
+
+// Cache sets the cache feature for the model. It caches the result of the sql, which means
+// if there's another same sql request, it just reads and returns the result from cache, it
+// but not committed and executed into the database.
+//
+// If the parameter <duration> < 0, which means it clear the cache with given <name>.
+// If the parameter <duration> = 0, which means it never expires.
+// If the parameter <duration> > 0, which means it expires after <duration>.
+//
+// The optional parameter <name> is used to bind a name to the cache, which means you can later
+// control the cache like changing the <duration> or clearing the cache with specified <name>.
+//
+// Note that, the cache feature is disabled if the model is operating on a transaction.
+func (m *arModel) Cache(duration time.Duration, name ...string) *arModel {
+	return &arModel{m.M.Cache(duration, name...)}
+}
+
+// Data sets the operation data for the model.
+// The parameter <data> can be type of string/map/gmap/slice/struct/*struct, etc.
+// Eg:
+// Data("uid=10000")
+// Data("uid", 10000)
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+func (m *arModel) Data(data ...interface{}) *arModel {
+	return &arModel{m.M.Data(data...)}
+}
+
+// All does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as []*Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) All(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.All(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// One retrieves one record from table and returns the result as *Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) One(where ...interface{}) (*Entity, error) {
+	one, err := m.M.One(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindOne retrieves and returns a single Record by Model.WherePri and Model.One.
+// Also see Model.WherePri and Model.One.
+func (m *arModel) FindOne(where ...interface{}) (*Entity, error) {
+	one, err := m.M.FindOne(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindAll retrieves and returns Result by by Model.WherePri and Model.All.
+// Also see Model.WherePri and Model.All.
+func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.FindAll(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// Chunk iterates the table with given size and callback function.
+func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) {
+	m.M.Chunk(limit, func(result gdb.Result, err error) bool {
+		var entities []*Entity
+		err = result.Structs(&entities)
+		if err == sql.ErrNoRows {
+			return false
+		}
+		return callback(entities, err)
+	})
+}
+
+// LockUpdate sets the lock for update for current operation.
+func (m *arModel) LockUpdate() *arModel {
+	return &arModel{m.M.LockUpdate()}
+}
+
+// LockShared sets the lock in share mode for current operation.
+func (m *arModel) LockShared() *arModel {
+	return &arModel{m.M.LockShared()}
+}
+
+// Unscoped enables/disables the soft deleting feature.
+func (m *arModel) Unscoped() *arModel {
+	return &arModel{m.M.Unscoped()}
+}

+ 7 - 5
app/model/admin/sys_config/sys_config.go

@@ -32,7 +32,7 @@ type SelectPageReq struct {
 	ConfigType string `p:"configType"` //状态
 	BeginTime  string `p:"beginTime"`  //开始时间
 	EndTime    string `p:"endTime"`    //结束时间
-	PageNum    int    `p:"page"`       //当前页码
+	PageNum    int    `p:"pageNum"`    //当前页码
 	PageSize   int    `p:"pageSize"`   //每页数
 }
 
@@ -44,7 +44,9 @@ func AddSave(req *AddReq, userId int) (id int64, err error) {
 	entity.ConfigType = req.ConfigType
 	entity.ConfigValue = req.ConfigValue
 	entity.Remark = req.Remark
-	entity.CreateTime = gconv.Uint64(gtime.Timestamp())
+	time := gconv.Uint64(gtime.Timestamp())
+	entity.CreateTime = time
+	entity.UpdateTime = time
 	entity.CreateBy = gconv.Uint(userId)
 	result, err := entity.Insert()
 	if err != nil {
@@ -119,17 +121,17 @@ func SelectListByPage(req *SelectPageReq) (total, page int, list []*Entity, err
 			model = model.Where("config_name like ?", "%"+req.ConfigName+"%")
 		}
 		if req.ConfigType != "" {
-			model.Where("status = ", gconv.Int(req.ConfigType))
+			model = model.Where("status = ", gconv.Int(req.ConfigType))
 		}
 		if req.ConfigKey != "" {
-			model.Where("config_key like ?", "%"+req.ConfigKey+"%")
+			model = model.Where("config_key like ?", "%"+req.ConfigKey+"%")
 		}
 		if req.BeginTime != "" {
 			model = model.Where("create_time >= ? ", utils.StrToTimestamp(req.BeginTime))
 		}
 
 		if req.EndTime != "" {
-			model = model.Where("create_time<=", utils.StrToTimestamp(req.EndTime))
+			model = model.Where("create_time<=?", utils.StrToTimestamp(req.EndTime))
 		}
 	}
 	total, err = model.Count()

+ 213 - 0
app/model/admin/sys_dept/sys_dept.go

@@ -0,0 +1,213 @@
+// ============================================================================
+// This is auto-generated by gf cli tool only once. Fill this file as you wish.
+// ============================================================================
+
+package sys_dept
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/os/gtime"
+)
+
+//数据列表数据结构
+type Dept struct {
+	SearchValue interface{}            `json:"searchValue"`
+	CreateBy    string                 `json:"createBy"  orm:"create_by"`
+	CreateTime  *gtime.Time            `json:"createTime" orm:"create_time"`
+	UpdateBy    string                 `json:"updateBy"  orm:"update_by"`
+	UpdateTime  *gtime.Time            `json:"updateTime" orm:"update_time"`
+	Remark      string                 `json:"remark"`
+	DataScope   interface{}            `json:"dataScope"`
+	Params      map[string]interface{} `json:"params"`
+	DeptID      int64                  `json:"deptId" orm:"dept_id"`
+	ParentID    int64                  `json:"parentId" orm:"parent_id"`
+	Ancestors   string                 `json:"ancestors" orm:"ancestors"`
+	DeptName    string                 `json:"deptName" orm:"dept_name"`
+	OrderNum    int                    `json:"orderNum" orm:"order_num" `
+	Leader      string                 `json:"leader" orm:"leader"`
+	Phone       string                 `json:"phone" orm:"phone"`
+	Email       string                 `json:"email" orm:"email"`
+	Status      string                 `json:"status" orm:"status"`
+	DelFlag     string                 `json:"delFlag" orm:"del_flag" `
+	ParentName  string                 `json:"parentName"`
+	Children    []interface{}          `json:"children"`
+}
+
+//查询参数
+
+//文章搜索参数
+type SearchParams struct {
+	DeptName string `p:"deptName"`
+	Status   string `p:"status"`
+}
+
+type AddParams struct {
+	ParentID   int         `json:"parentId" orm:"parent_id"  p:"parentId"  v:"required#父级不能为空"`
+	DeptName   string      `json:"deptName" orm:"dept_name" p:"deptName"  v:"required#部门名称不能为空"`
+	OrderNum   int         `json:"orderNum" orm:"order_num"  p:"orderNum"  v:"required#排序不能为空"`
+	Leader     string      `json:"leader" orm:"leader" p:"leader"  v:"required#负责人不能为空"`
+	Phone      string      `json:"phone" orm:"Phone" p:"phone"  v:"required#电话不能为空"`
+	Email      string      `json:"email" orm:"email" p:"email"  v:"required#邮箱不能为空"`
+	Status     string      `json:"status" orm:"status" p:"status"  v:"required#状态必须"`
+	Ancestors  string      `json:"ancestors" orm:"ancestors"`
+	DelFlag    string      `json:"delFlag" orm:"del_flag"`
+	CreateBy   string      `json:"createBy"  orm:"create_by"`
+	CreateTime *gtime.Time `json:"createTime" orm:"create_time"`
+	UpdateBy   string      `json:"updateBy"  orm:"update_by"`
+	UpdateTime *gtime.Time `json:"updateTime" orm:"update_time"`
+}
+
+type EditParams struct {
+	DeptID int64 `json:"deptId" orm:"dept_id" p:"id" v:"integer|min:1#ID只能为整数|ID只能为正数"`
+	AddParams
+}
+
+//获取列表数据
+func GetList(searchParams *SearchParams) ([]*Dept, error) {
+	model := g.DB().Table(Table)
+	if searchParams.DeptName != "" {
+		model.Where("dept_name like ?", "%"+searchParams.DeptName+"%")
+	}
+
+	if searchParams.Status != "" {
+		model.Where("status", searchParams.Status)
+	}
+	depts := ([]*Dept)(nil)
+	if err := model.Structs(&depts); err != nil {
+		return nil, err
+	}
+
+	for _, v := range depts {
+		if v.Children == nil {
+			v.Children = []interface{}{}
+		}
+
+	}
+
+	return depts, nil
+}
+
+//添加
+func AddDept(data *AddParams) (sql.Result, error) {
+	data.DelFlag = "0"
+	data.CreateBy = ""
+	data.CreateTime = gtime.Now()
+	return Model.Data(data).Insert()
+}
+
+//编辑
+func EditDept(data *EditParams) error {
+	data.UpdateBy = ""
+	data.UpdateTime = gtime.Now()
+
+	if _, err := Model.Where("dept_id", data.DeptID).Data(data).Update(); err != nil {
+		return err
+	}
+	return nil
+}
+
+//删除失败
+func DelDept(id int64) error {
+
+	ids, _ := GetChilderenIds(id)
+	_, err := Model.Where("dept_id IN(?)", ids).Delete()
+	if err != nil {
+		return gerror.New("删除失败")
+	}
+	return nil
+}
+
+//根据部门id获取部门信息
+func GetDeptById(id int64) (*Dept, error) {
+
+	dept := (*Dept)(nil)
+
+	if err := Model.Where("dept_id", id).Struct(&dept); err != nil {
+		return nil, err
+	} else {
+		return dept, nil
+	}
+
+}
+
+/**
+获取排除节点
+*/
+func Exclude(id int64) ([]*Dept, error) {
+	ids, err := GetChilderenIds(id)
+	if err != nil {
+		return nil, err
+	}
+
+	model := g.DB().Table(Table)
+	if len(ids) > 0 {
+		model.Where("dept_id  NOT IN(?)", ids)
+	}
+
+	depts := ([]*Dept)(nil)
+	if err := model.Structs(&depts); err != nil {
+		return nil, err
+	}
+
+	for _, v := range depts {
+		if v.Children == nil {
+			v.Children = []interface{}{}
+		}
+
+	}
+	return depts, nil
+}
+
+/**
+根据id获取子孙节点id集合包含本身
+*/
+func GetChilderenIds(id int64) ([]int64, error) {
+
+	list, err := GetChildrenById(id)
+	if err != nil {
+		return nil, err
+	}
+	if len(list) == 0 {
+		return []int64{}, nil
+	}
+	var newResult []int64
+	for _, v := range list {
+		newResult = append(newResult, v.DeptId)
+	}
+
+	return newResult, nil
+}
+
+/**
+根据id获取所有子孙节点包含本身
+*/
+func GetChildrenById(id int64) ([]*Entity, error) {
+	depts, err := Model.All()
+	if err != nil {
+		return nil, err
+	}
+	result := recursion(id, depts, true)
+	return result, nil
+}
+
+/**
+根据id获取所有子孙元素
+
+hasroot true - 包含自身  false - 不含自身
+*/
+func recursion(id int64, depts []*Entity, hasRoot bool) (result []*Entity) {
+	for _, v := range depts {
+		if hasRoot == true && v.DeptId == id {
+			result = append(result, v)
+		}
+		if v.ParentId == id {
+			data := recursion(v.DeptId, depts, false)
+			result = append(result, v)
+			result = append(result, data...)
+		}
+	}
+
+	return
+}

+ 71 - 0
app/model/admin/sys_dept/sys_dept_entity.go

@@ -0,0 +1,71 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package sys_dept
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/os/gtime"
+)
+
+// Entity is the golang structure for table sys_dept.
+type Entity struct {
+	DeptId     int64       `orm:"dept_id,primary" json:"dept_id"`     // 部门id
+	ParentId   int64       `orm:"parent_id"       json:"parent_id"`   // 父部门id
+	Ancestors  string      `orm:"ancestors"       json:"ancestors"`   // 祖级列表
+	DeptName   string      `orm:"dept_name"       json:"dept_name"`   // 部门名称
+	OrderNum   int         `orm:"order_num"       json:"order_num"`   // 显示顺序
+	Leader     string      `orm:"leader"          json:"leader"`      // 负责人
+	Phone      string      `orm:"phone"           json:"phone"`       // 联系电话
+	Email      string      `orm:"email"           json:"email"`       // 邮箱
+	Status     string      `orm:"status"          json:"status"`      // 部门状态(0正常 1停用)
+	DelFlag    string      `orm:"del_flag"        json:"del_flag"`    // 删除标志(0代表存在 2代表删除)
+	CreateBy   string      `orm:"create_by"       json:"create_by"`   // 创建者
+	CreateTime *gtime.Time `orm:"create_time"     json:"create_time"` // 创建时间
+	UpdateBy   string      `orm:"update_by"       json:"update_by"`   // 更新者
+	UpdateTime *gtime.Time `orm:"update_time"     json:"update_time"` // 更新时间
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (r *Entity) OmitEmpty() *arModel {
+	return Model.Data(r).OmitEmpty()
+}
+
+// Inserts does "INSERT...INTO..." statement for inserting current object into table.
+func (r *Entity) Insert() (result sql.Result, err error) {
+	return Model.Data(r).Insert()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for inserting current object into table.
+func (r *Entity) InsertIgnore() (result sql.Result, err error) {
+	return Model.Data(r).InsertIgnore()
+}
+
+// Replace does "REPLACE...INTO..." statement for inserting current object into table.
+// If there's already another same record in the table (it checks using primary key or unique index),
+// it deletes it and insert this one.
+func (r *Entity) Replace() (result sql.Result, err error) {
+	return Model.Data(r).Replace()
+}
+
+// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Save() (result sql.Result, err error) {
+	return Model.Data(r).Save()
+}
+
+// Update does "UPDATE...WHERE..." statement for updating current object from table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Update() (result sql.Result, err error) {
+	return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
+}
+
+// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
+func (r *Entity) Delete() (result sql.Result, err error) {
+	return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
+}

+ 352 - 0
app/model/admin/sys_dept/sys_dept_model.go

@@ -0,0 +1,352 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package sys_dept
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+	"time"
+)
+
+// arModel is a active record design model for table sys_dept operations.
+type arModel struct {
+	gmvc.M
+}
+
+var (
+	// Table is the table name of sys_dept.
+	Table = "sys_dept"
+	// Model is the model object of sys_dept.
+	Model = &arModel{g.DB("default").Table(Table).Safe()}
+	// Columns defines and stores column names for table sys_dept.
+	Columns = struct {
+		DeptId     string // 部门id
+		ParentId   string // 父部门id
+		Ancestors  string // 祖级列表
+		DeptName   string // 部门名称
+		OrderNum   string // 显示顺序
+		Leader     string // 负责人
+		Phone      string // 联系电话
+		Email      string // 邮箱
+		Status     string // 部门状态(0正常 1停用)
+		DelFlag    string // 删除标志(0代表存在 2代表删除)
+		CreateBy   string // 创建者
+		CreateTime string // 创建时间
+		UpdateBy   string // 更新者
+		UpdateTime string // 更新时间
+	}{
+		DeptId:     "dept_id",
+		ParentId:   "parent_id",
+		Ancestors:  "ancestors",
+		DeptName:   "dept_name",
+		OrderNum:   "order_num",
+		Leader:     "leader",
+		Phone:      "phone",
+		Email:      "email",
+		Status:     "status",
+		DelFlag:    "del_flag",
+		CreateBy:   "create_by",
+		CreateTime: "create_time",
+		UpdateBy:   "update_by",
+		UpdateTime: "update_time",
+	}
+)
+
+// FindOne is a convenience method for Model.FindOne.
+// See Model.FindOne.
+func FindOne(where ...interface{}) (*Entity, error) {
+	return Model.FindOne(where...)
+}
+
+// FindAll is a convenience method for Model.FindAll.
+// See Model.FindAll.
+func FindAll(where ...interface{}) ([]*Entity, error) {
+	return Model.FindAll(where...)
+}
+
+// FindValue is a convenience method for Model.FindValue.
+// See Model.FindValue.
+func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
+	return Model.FindValue(fieldsAndWhere...)
+}
+
+// FindArray is a convenience method for Model.FindArray.
+// See Model.FindArray.
+func FindArray(fieldsAndWhere ...interface{}) ([]gdb.Value, error) {
+	return Model.FindArray(fieldsAndWhere...)
+}
+
+// FindCount is a convenience method for Model.FindCount.
+// See Model.FindCount.
+func FindCount(where ...interface{}) (int, error) {
+	return Model.FindCount(where...)
+}
+
+// Insert is a convenience method for Model.Insert.
+func Insert(data ...interface{}) (result sql.Result, err error) {
+	return Model.Insert(data...)
+}
+
+// InsertIgnore is a convenience method for Model.InsertIgnore.
+func InsertIgnore(data ...interface{}) (result sql.Result, err error) {
+	return Model.InsertIgnore(data...)
+}
+
+// Replace is a convenience method for Model.Replace.
+func Replace(data ...interface{}) (result sql.Result, err error) {
+	return Model.Replace(data...)
+}
+
+// Save is a convenience method for Model.Save.
+func Save(data ...interface{}) (result sql.Result, err error) {
+	return Model.Save(data...)
+}
+
+// Update is a convenience method for Model.Update.
+func Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
+	return Model.Update(dataAndWhere...)
+}
+
+// Delete is a convenience method for Model.Delete.
+func Delete(where ...interface{}) (result sql.Result, err error) {
+	return Model.Delete(where...)
+}
+
+// As sets an alias name for current table.
+func (m *arModel) As(as string) *arModel {
+	return &arModel{m.M.As(as)}
+}
+
+// TX sets the transaction for current operation.
+func (m *arModel) TX(tx *gdb.TX) *arModel {
+	return &arModel{m.M.TX(tx)}
+}
+
+// Master marks the following operation on master node.
+func (m *arModel) Master() *arModel {
+	return &arModel{m.M.Master()}
+}
+
+// Slave marks the following operation on slave node.
+// Note that it makes sense only if there's any slave node configured.
+func (m *arModel) Slave() *arModel {
+	return &arModel{m.M.Slave()}
+}
+
+// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
+func (m *arModel) LeftJoin(joinTable string, on string) *arModel {
+	return &arModel{m.M.LeftJoin(joinTable, on)}
+}
+
+// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
+func (m *arModel) RightJoin(joinTable string, on string) *arModel {
+	return &arModel{m.M.RightJoin(joinTable, on)}
+}
+
+// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
+func (m *arModel) InnerJoin(joinTable string, on string) *arModel {
+	return &arModel{m.M.InnerJoin(joinTable, on)}
+}
+
+// Fields sets the operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) Fields(fields string) *arModel {
+	return &arModel{m.M.Fields(fields)}
+}
+
+// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) FieldsEx(fields string) *arModel {
+	return &arModel{m.M.FieldsEx(fields)}
+}
+
+// Option sets the extra operation option for the model.
+func (m *arModel) Option(option int) *arModel {
+	return &arModel{m.M.Option(option)}
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (m *arModel) OmitEmpty() *arModel {
+	return &arModel{m.M.OmitEmpty()}
+}
+
+// Filter marks filtering the fields which does not exist in the fields of the operated table.
+func (m *arModel) Filter() *arModel {
+	return &arModel{m.M.Filter()}
+}
+
+// Where sets the condition statement for the model. The parameter <where> can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+// Eg:
+// Where("uid=10000")
+// Where("uid", 10000)
+// Where("money>? AND name like ?", 99999, "vip_%")
+// Where("uid", 1).Where("name", "john")
+// Where("status IN (?)", g.Slice{1,2,3})
+// Where("age IN(?,?)", 18, 50)
+// Where(User{ Id : 1, UserName : "john"})
+func (m *arModel) Where(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Where(where, args...)}
+}
+
+// And adds "AND" condition to the where statement.
+func (m *arModel) And(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.And(where, args...)}
+}
+
+// Or adds "OR" condition to the where statement.
+func (m *arModel) Or(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Or(where, args...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (m *arModel) Group(groupBy string) *arModel {
+	return &arModel{m.M.Group(groupBy)}
+}
+
+// Order sets the "ORDER BY" statement for the model.
+func (m *arModel) Order(orderBy string) *arModel {
+	return &arModel{m.M.Order(orderBy)}
+}
+
+// Limit sets the "LIMIT" statement for the model.
+// The parameter <limit> can be either one or two number, if passed two number is passed,
+// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
+// statement.
+func (m *arModel) Limit(limit ...int) *arModel {
+	return &arModel{m.M.Limit(limit...)}
+}
+
+// Offset sets the "OFFSET" statement for the model.
+// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
+func (m *arModel) Offset(offset int) *arModel {
+	return &arModel{m.M.Offset(offset)}
+}
+
+// Page sets the paging number for the model.
+// The parameter <page> is started from 1 for paging.
+// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
+func (m *arModel) Page(page, limit int) *arModel {
+	return &arModel{m.M.Page(page, limit)}
+}
+
+// Batch sets the batch operation number for the model.
+func (m *arModel) Batch(batch int) *arModel {
+	return &arModel{m.M.Batch(batch)}
+}
+
+// Cache sets the cache feature for the model. It caches the result of the sql, which means
+// if there's another same sql request, it just reads and returns the result from cache, it
+// but not committed and executed into the database.
+//
+// If the parameter <duration> < 0, which means it clear the cache with given <name>.
+// If the parameter <duration> = 0, which means it never expires.
+// If the parameter <duration> > 0, which means it expires after <duration>.
+//
+// The optional parameter <name> is used to bind a name to the cache, which means you can later
+// control the cache like changing the <duration> or clearing the cache with specified <name>.
+//
+// Note that, the cache feature is disabled if the model is operating on a transaction.
+func (m *arModel) Cache(duration time.Duration, name ...string) *arModel {
+	return &arModel{m.M.Cache(duration, name...)}
+}
+
+// Data sets the operation data for the model.
+// The parameter <data> can be type of string/map/gmap/slice/struct/*struct, etc.
+// Eg:
+// Data("uid=10000")
+// Data("uid", 10000)
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+func (m *arModel) Data(data ...interface{}) *arModel {
+	return &arModel{m.M.Data(data...)}
+}
+
+// All does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as []*Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) All(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.All(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// One retrieves one record from table and returns the result as *Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) One(where ...interface{}) (*Entity, error) {
+	one, err := m.M.One(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindOne retrieves and returns a single Record by Model.WherePri and Model.One.
+// Also see Model.WherePri and Model.One.
+func (m *arModel) FindOne(where ...interface{}) (*Entity, error) {
+	one, err := m.M.FindOne(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindAll retrieves and returns Result by by Model.WherePri and Model.All.
+// Also see Model.WherePri and Model.All.
+func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.FindAll(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// Chunk iterates the table with given size and callback function.
+func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) {
+	m.M.Chunk(limit, func(result gdb.Result, err error) bool {
+		var entities []*Entity
+		err = result.Structs(&entities)
+		if err == sql.ErrNoRows {
+			return false
+		}
+		return callback(entities, err)
+	})
+}
+
+// LockUpdate sets the lock for update for current operation.
+func (m *arModel) LockUpdate() *arModel {
+	return &arModel{m.M.LockUpdate()}
+}
+
+// LockShared sets the lock in share mode for current operation.
+func (m *arModel) LockShared() *arModel {
+	return &arModel{m.M.LockShared()}
+}

+ 6 - 4
app/model/admin/sys_dict_data/sys_dict_data.go

@@ -17,7 +17,7 @@ type AddDataReq struct {
 	DictType  string `p:"dictType"  v:"required#字典类型不能为空"`
 	DictSort  int    `p:"dictSort"  v:"integer#排序只能为整数"`
 	CssClass  string `p:"cssClass"`
-	ListClass string `p:"listClass" v:"required#回显样式不能为空"`
+	ListClass string `p:"listClass"`
 	IsDefault int    `p:"isDefault" v:"required|in:0,1#系统默认不能为空|默认值只能为0或1"`
 	Status    int    `p:"status"    v:"required|in:0,1#状态不能为空|状态只能为0或1"`
 	Remark    string `p:"remark"`
@@ -30,10 +30,10 @@ type EditDataReq struct {
 
 //分页请求参数
 type SelectDataPageReq struct {
-	DictType  string `p:"dictType"`  //字典名称
+	DictType  string `p:"dictType"`  //字典类型
 	DictLabel string `p:"dictLabel"` //字典标签
 	Status    string `p:"status"`    //状态
-	PageNum   int    `p:"page"`      //当前页码
+	PageNum   int    `p:"pageNum"`   //当前页码
 	PageSize  int    `p:"pageSize"`  //每页数
 }
 
@@ -49,7 +49,9 @@ func AddSaveData(req *AddDataReq, userId int) (int64, error) {
 	entity.IsDefault = req.IsDefault
 	entity.ListClass = req.ListClass
 	entity.Remark = req.Remark
-	entity.CreateTime = gconv.Uint64(gtime.Timestamp())
+	time := gconv.Uint64(gtime.Timestamp())
+	entity.CreateTime = time
+	entity.UpdateTime = time
 	entity.CreateBy = userId
 	result, err := entity.Insert()
 	if err != nil {

+ 25 - 2
app/model/admin/sys_dict_type/sys_dict_type.go

@@ -2,6 +2,7 @@ package sys_dict_type
 
 import (
 	"gfast/app/model/admin/sys_dict_data"
+	"gfast/app/service/cache_service"
 	"gfast/library/service"
 	"gfast/library/utils"
 	"github.com/gogf/gf/errors/gerror"
@@ -34,7 +35,7 @@ type SelectPageReq struct {
 	Status    string `p:"status"`    //字典状态
 	BeginTime string `p:"beginTime"` //开始时间
 	EndTime   string `p:"endTime"`   //结束时间
-	PageNum   int    `p:"page"`      //当前页码
+	PageNum   int    `p:"PageNum"`   //当前页码
 	PageSize  int    `p:"pageSize"`  //每页数
 }
 
@@ -168,7 +169,20 @@ func SelectListByPage(req *SelectPageReq) (total, page int, list []*Entity, err
 
 //通过字典键类型获取选项
 func GetDictWithDataByType(dictType, defaultValue, emptyLabel string) (dict g.Map, err error) {
-	dictEntity, err := Model.FindOne("dict_type", dictType)
+	//初始化dict的值
+	dict = g.Map{
+		"dict_name": "",
+		"remark":    "",
+		"values":    g.Slice{},
+	}
+	cache := cache_service.New()
+	//从缓存获取
+	data := cache.Get(gconv.String(cache_service.AdminConfigDict) + "_" + dictType)
+	if data != nil {
+		dict = data.(g.Map)
+		return
+	}
+	dictEntity, err := Model.FindOne(g.Map{"dict_type": dictType, "status": 1})
 	if err != nil {
 		g.Log().Error(err)
 		err = gerror.New("获取字典选项失败")
@@ -198,6 +212,7 @@ func GetDictWithDataByType(dictType, defaultValue, emptyLabel string) (dict g.Ma
 				"key":       v.DictValue,
 				"value":     v.DictLabel,
 				"isDefault": isDefault,
+				"remark":    v.Remark,
 			}
 		}
 		if emptyLabel != "" {
@@ -208,6 +223,8 @@ func GetDictWithDataByType(dictType, defaultValue, emptyLabel string) (dict g.Ma
 			"remark":    dictEntity.Remark,
 			"values":    values,
 		}
+		//缓存
+		cache.Set(gconv.String(cache_service.AdminConfigDict)+"_"+dictType, dict, 0, cache_service.AdminSysConfigTag)
 	}
 	return
 }
@@ -226,3 +243,9 @@ func DeleteDictByIds(ids []int) error {
 	}
 	return nil
 }
+
+//获取所有字典类型
+func GetAllDictType() (list []*Entity, err error) {
+	list, err = Model.Where("status", 1).Order("dict_id ASC").All()
+	return
+}

+ 8 - 8
app/model/admin/sys_job/sys_job.go

@@ -15,12 +15,12 @@ import (
 
 //添加操作请求参数
 type ReqAdd struct {
-	JobName        string `p:"jobName" v:"required#任务名称不能为空"`
-	JobParams      string `p:"jobParams"` // 任务参数
-	JobGroup       string `p:"jobGroup" `
-	InvokeTarget   string `p:"invokeTarget" v:"required#执行方法不能为空"`
-	CronExpression string `p:"cronExpression" v:"required#任务表达式不能为空"`
-	MisfirePolicy  int    `p:"misfirePolicy"`
+	JobName        string `p:"job_mame" v:"required#任务名称不能为空"`
+	JobParams      string `p:"job_params"` // 任务参数
+	JobGroup       string `p:"job_group" `
+	InvokeTarget   string `p:"invoke_target" v:"required#执行方法不能为空"`
+	CronExpression string `p:"cron_expression" v:"required#任务表达式不能为空"`
+	MisfirePolicy  int    `p:"misfire_policy"`
 	Concurrent     int    `p:"concurrent" `
 	Status         int    `p:"status" v:"required#状态(0正常 1暂停)不能为空"`
 	Remark         string `p:"remark" `
@@ -28,7 +28,7 @@ type ReqAdd struct {
 
 //修改操作请求参数
 type ReqEdit struct {
-	JobId int64 `p:"jobId" v:"min:1#任务id不能为空"`
+	JobId int64 `p:"job_id" v:"min:1#任务id不能为空"`
 	ReqAdd
 }
 
@@ -37,7 +37,7 @@ type SelectPageReq struct {
 	JobName  string `p:"jobName"`  //任务名称
 	JobGroup string `p:"jobGroup"` //任务组名
 	Status   string `p:"status"`   //状态(0正常 1暂停)
-	PageNum  int    `p:"page"`     //当前页码
+	PageNum  int    `p:"pageNum"`  //当前页码
 	PageSize int    `p:"pageSize"` //每页数
 }
 

+ 2 - 2
app/model/admin/sys_login_log/sys_login_log.go

@@ -10,12 +10,12 @@ import (
 // Fill with you ideas below.
 //查询列表请求参数
 type SelectPageReq struct {
-	LoginName string `p:"loginName"`     //登陆名
+	LoginName string `p:"userName"`      //登陆名
 	Status    string `p:"status"`        //状态
 	Ipaddr    string `p:"ipaddr"`        //登录地址
 	BeginTime string `p:"beginTime"`     //数据范围
 	EndTime   string `p:"endTime"`       //开始时间
-	PageNum   int    `p:"page"`          //当前页码
+	PageNum   int    `p:"pageNum"`       //当前页码
 	PageSize  int    `p:"pageSize"`      //每页数
 	SortName  string `p:"orderByColumn"` //排序字段
 	SortOrder string `p:"isAsc"`         //排序方式

+ 2 - 2
app/model/admin/sys_oper_log/sys_oper_log.go

@@ -22,7 +22,7 @@ type SelectPageReq struct {
 	Status    string `p:"status"`        //操作状态
 	BeginTime string `p:"beginTime"`     //数据范围
 	EndTime   string `p:"endTime"`       //开始时间
-	PageNum   int    `p:"page"`          //当前页码
+	PageNum   int    `p:"pageNum"`       //当前页码
 	PageSize  int    `p:"pageSize"`      //每页数
 	SortName  string `p:"orderByColumn"` //排序字段
 	SortOrder string `p:"isAsc"`         //排序方式
@@ -113,7 +113,7 @@ func ListByPage(req *SelectPageReq) (total, page int, list []*Entity, err error)
 	if req.PageSize == 0 {
 		req.PageSize = service.AdminPageNum
 	}
-	list, err = model.Page(page, req.PageSize).FieldsEx("oper_param,json_result").Order(order).All()
+	list, err = model.Page(page, req.PageSize).Order(order).All()
 	if err != nil {
 		g.Log().Error(err)
 		err = gerror.New("获取数据失败")

+ 151 - 0
app/model/admin/sys_post/sys_post.go

@@ -0,0 +1,151 @@
+// ============================================================================
+// This is auto-generated by gf cli tool only once. Fill this file as you wish.
+// ============================================================================
+
+package sys_post
+
+import (
+	"database/sql"
+	"gfast/library/service"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/os/gtime"
+)
+
+// Fill with you ideas below.
+
+type Post struct {
+	Entity
+	SearchValue interface{} `json:"searchValue"`
+	Remark      string      `json:"remark"`
+	DataScope   interface{} `json:"dataScope"`
+	Params      struct{}    `json:"params"`
+	Flag        bool        `json:"flag"`
+}
+
+type SearchParams struct {
+	PageNum  int    `p:"page"`     //当前页码
+	PageSize int    `p:"pageSize"` //每页数
+	PostCode string `p:"postCode"` //岗位编码
+	PostName string `p:"postName"` //岗位名称
+	Status   string `p:"status"`   //状态
+}
+
+type AddParams struct {
+	PostCode string `p:"postCode" v:"required#岗位编码不能为空"`
+	PostName string `p:"postName" v:"required#岗位名称不能为空"`
+	PostSort int    `p:"postSort" v:"required#岗位排序不能为空"`
+	Status   string `p:"status" v:"required#状态不能为空"`
+	Remark   string `p:"remark"`
+}
+
+type EditParams struct {
+	PostId int64 `p:"postId" v:"required#id必须"`
+	AddParams
+}
+
+func List(req *SearchParams) (total, page int, list gdb.Result, err error) {
+	model := g.DB().Table(Table)
+
+	if req != nil {
+		if req.PostCode != "" {
+			model.Where("post_code like ?", "%"+req.PostCode+"%")
+		}
+
+		if req.PostName != "" {
+			model.Where("post_name like ?", "%"+req.PostName+"%")
+		}
+
+		if req.Status != "" {
+			model.Where("status", req.Status)
+		}
+	}
+
+	total, err = model.Count()
+
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取总行数失败")
+	}
+
+	if req.PageNum == 0 {
+		req.PageNum = 1
+	}
+
+	page = req.PageNum
+
+	if req.PageSize == 0 {
+		req.PageSize = service.AdminPageNum
+	}
+
+	list, err = model.Page(page, req.PageSize).All()
+
+	//g.Log().Println(list)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取数据失败")
+		return
+	}
+
+	return
+}
+
+//获取正常状态的岗位
+func GetUsedPost() (list []*Entity, err error) {
+	list, err = Model.Where(Columns.Status, 1).Order(Columns.PostSort + " ASC, " + Columns.PostId + " ASC ").All()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取岗位数据失败")
+	}
+	return
+}
+
+/**
+添加
+*/
+func Add(addParams *AddParams) (result sql.Result, err error) {
+	//g.Log().Println(addParams)
+	entity := &Entity{
+		PostCode:   addParams.PostCode,
+		PostName:   addParams.PostName,
+		PostSort:   addParams.PostSort,
+		Status:     addParams.Status,
+		Remark:     addParams.Remark,
+		CreateBy:   "",
+		CreateTime: gtime.Now(),
+	}
+
+	return entity.Save()
+
+}
+
+func Edit(editParams *EditParams) (result sql.Result, err error) {
+	entity := &Entity{
+		PostId:     editParams.PostId,
+		PostCode:   editParams.PostCode,
+		PostName:   editParams.PostName,
+		PostSort:   editParams.PostSort,
+		Status:     editParams.Status,
+		Remark:     editParams.Remark,
+		UpdateBy:   "",
+		UpdateTime: gtime.Now(),
+	}
+
+	return entity.Update()
+}
+
+func GetOneById(id int64) (*Entity, error) {
+	return Model.One(g.Map{
+		"post_id": id,
+	})
+}
+
+func DeleteByIds(ids []int) error {
+	_, err := Model.Delete("post_id IN(?)", ids)
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("删除失败")
+	}
+	return nil
+}

+ 67 - 0
app/model/admin/sys_post/sys_post_entity.go

@@ -0,0 +1,67 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package sys_post
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/os/gtime"
+)
+
+// Entity is the golang structure for table sys_post.
+type Entity struct {
+	PostId     int64       `orm:"post_id,primary" json:"post_id"`     // 岗位ID
+	PostCode   string      `orm:"post_code"       json:"post_code"`   // 岗位编码
+	PostName   string      `orm:"post_name"       json:"post_name"`   // 岗位名称
+	PostSort   int         `orm:"post_sort"       json:"post_sort"`   // 显示顺序
+	Status     string      `orm:"status"          json:"status"`      // 状态(0正常 1停用)
+	CreateBy   string      `orm:"create_by"       json:"create_by"`   // 创建者
+	CreateTime *gtime.Time `orm:"create_time"     json:"create_time"` // 创建时间
+	UpdateBy   string      `orm:"update_by"       json:"update_by"`   // 更新者
+	UpdateTime *gtime.Time `orm:"update_time"     json:"update_time"` // 更新时间
+	Remark     string      `orm:"remark"          json:"remark"`      // 备注
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (r *Entity) OmitEmpty() *arModel {
+	return Model.Data(r).OmitEmpty()
+}
+
+// Inserts does "INSERT...INTO..." statement for inserting current object into table.
+func (r *Entity) Insert() (result sql.Result, err error) {
+	return Model.Data(r).Insert()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for inserting current object into table.
+func (r *Entity) InsertIgnore() (result sql.Result, err error) {
+	return Model.Data(r).InsertIgnore()
+}
+
+// Replace does "REPLACE...INTO..." statement for inserting current object into table.
+// If there's already another same record in the table (it checks using primary key or unique index),
+// it deletes it and insert this one.
+func (r *Entity) Replace() (result sql.Result, err error) {
+	return Model.Data(r).Replace()
+}
+
+// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Save() (result sql.Result, err error) {
+	return Model.Data(r).Save()
+}
+
+// Update does "UPDATE...WHERE..." statement for updating current object from table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Update() (result sql.Result, err error) {
+	return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
+}
+
+// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
+func (r *Entity) Delete() (result sql.Result, err error) {
+	return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
+}

+ 344 - 0
app/model/admin/sys_post/sys_post_model.go

@@ -0,0 +1,344 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package sys_post
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+	"time"
+)
+
+// arModel is a active record design model for table sys_post operations.
+type arModel struct {
+	gmvc.M
+}
+
+var (
+	// Table is the table name of sys_post.
+	Table = "sys_post"
+	// Model is the model object of sys_post.
+	Model = &arModel{g.DB("default").Table(Table).Safe()}
+	// Columns defines and stores column names for table sys_post.
+	Columns = struct {
+		PostId     string // 岗位ID
+		PostCode   string // 岗位编码
+		PostName   string // 岗位名称
+		PostSort   string // 显示顺序
+		Status     string // 状态(0正常 1停用)
+		CreateBy   string // 创建者
+		CreateTime string // 创建时间
+		UpdateBy   string // 更新者
+		UpdateTime string // 更新时间
+		Remark     string // 备注
+	}{
+		PostId:     "post_id",
+		PostCode:   "post_code",
+		PostName:   "post_name",
+		PostSort:   "post_sort",
+		Status:     "status",
+		CreateBy:   "create_by",
+		CreateTime: "create_time",
+		UpdateBy:   "update_by",
+		UpdateTime: "update_time",
+		Remark:     "remark",
+	}
+)
+
+// FindOne is a convenience method for Model.FindOne.
+// See Model.FindOne.
+func FindOne(where ...interface{}) (*Entity, error) {
+	return Model.FindOne(where...)
+}
+
+// FindAll is a convenience method for Model.FindAll.
+// See Model.FindAll.
+func FindAll(where ...interface{}) ([]*Entity, error) {
+	return Model.FindAll(where...)
+}
+
+// FindValue is a convenience method for Model.FindValue.
+// See Model.FindValue.
+func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
+	return Model.FindValue(fieldsAndWhere...)
+}
+
+// FindArray is a convenience method for Model.FindArray.
+// See Model.FindArray.
+func FindArray(fieldsAndWhere ...interface{}) ([]gdb.Value, error) {
+	return Model.FindArray(fieldsAndWhere...)
+}
+
+// FindCount is a convenience method for Model.FindCount.
+// See Model.FindCount.
+func FindCount(where ...interface{}) (int, error) {
+	return Model.FindCount(where...)
+}
+
+// Insert is a convenience method for Model.Insert.
+func Insert(data ...interface{}) (result sql.Result, err error) {
+	return Model.Insert(data...)
+}
+
+// InsertIgnore is a convenience method for Model.InsertIgnore.
+func InsertIgnore(data ...interface{}) (result sql.Result, err error) {
+	return Model.InsertIgnore(data...)
+}
+
+// Replace is a convenience method for Model.Replace.
+func Replace(data ...interface{}) (result sql.Result, err error) {
+	return Model.Replace(data...)
+}
+
+// Save is a convenience method for Model.Save.
+func Save(data ...interface{}) (result sql.Result, err error) {
+	return Model.Save(data...)
+}
+
+// Update is a convenience method for Model.Update.
+func Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
+	return Model.Update(dataAndWhere...)
+}
+
+// Delete is a convenience method for Model.Delete.
+func Delete(where ...interface{}) (result sql.Result, err error) {
+	return Model.Delete(where...)
+}
+
+// As sets an alias name for current table.
+func (m *arModel) As(as string) *arModel {
+	return &arModel{m.M.As(as)}
+}
+
+// TX sets the transaction for current operation.
+func (m *arModel) TX(tx *gdb.TX) *arModel {
+	return &arModel{m.M.TX(tx)}
+}
+
+// Master marks the following operation on master node.
+func (m *arModel) Master() *arModel {
+	return &arModel{m.M.Master()}
+}
+
+// Slave marks the following operation on slave node.
+// Note that it makes sense only if there's any slave node configured.
+func (m *arModel) Slave() *arModel {
+	return &arModel{m.M.Slave()}
+}
+
+// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
+func (m *arModel) LeftJoin(joinTable string, on string) *arModel {
+	return &arModel{m.M.LeftJoin(joinTable, on)}
+}
+
+// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
+func (m *arModel) RightJoin(joinTable string, on string) *arModel {
+	return &arModel{m.M.RightJoin(joinTable, on)}
+}
+
+// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
+func (m *arModel) InnerJoin(joinTable string, on string) *arModel {
+	return &arModel{m.M.InnerJoin(joinTable, on)}
+}
+
+// Fields sets the operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) Fields(fields string) *arModel {
+	return &arModel{m.M.Fields(fields)}
+}
+
+// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) FieldsEx(fields string) *arModel {
+	return &arModel{m.M.FieldsEx(fields)}
+}
+
+// Option sets the extra operation option for the model.
+func (m *arModel) Option(option int) *arModel {
+	return &arModel{m.M.Option(option)}
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (m *arModel) OmitEmpty() *arModel {
+	return &arModel{m.M.OmitEmpty()}
+}
+
+// Filter marks filtering the fields which does not exist in the fields of the operated table.
+func (m *arModel) Filter() *arModel {
+	return &arModel{m.M.Filter()}
+}
+
+// Where sets the condition statement for the model. The parameter <where> can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+// Eg:
+// Where("uid=10000")
+// Where("uid", 10000)
+// Where("money>? AND name like ?", 99999, "vip_%")
+// Where("uid", 1).Where("name", "john")
+// Where("status IN (?)", g.Slice{1,2,3})
+// Where("age IN(?,?)", 18, 50)
+// Where(User{ Id : 1, UserName : "john"})
+func (m *arModel) Where(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Where(where, args...)}
+}
+
+// And adds "AND" condition to the where statement.
+func (m *arModel) And(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.And(where, args...)}
+}
+
+// Or adds "OR" condition to the where statement.
+func (m *arModel) Or(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Or(where, args...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (m *arModel) Group(groupBy string) *arModel {
+	return &arModel{m.M.Group(groupBy)}
+}
+
+// Order sets the "ORDER BY" statement for the model.
+func (m *arModel) Order(orderBy string) *arModel {
+	return &arModel{m.M.Order(orderBy)}
+}
+
+// Limit sets the "LIMIT" statement for the model.
+// The parameter <limit> can be either one or two number, if passed two number is passed,
+// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
+// statement.
+func (m *arModel) Limit(limit ...int) *arModel {
+	return &arModel{m.M.Limit(limit...)}
+}
+
+// Offset sets the "OFFSET" statement for the model.
+// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
+func (m *arModel) Offset(offset int) *arModel {
+	return &arModel{m.M.Offset(offset)}
+}
+
+// Page sets the paging number for the model.
+// The parameter <page> is started from 1 for paging.
+// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
+func (m *arModel) Page(page, limit int) *arModel {
+	return &arModel{m.M.Page(page, limit)}
+}
+
+// Batch sets the batch operation number for the model.
+func (m *arModel) Batch(batch int) *arModel {
+	return &arModel{m.M.Batch(batch)}
+}
+
+// Cache sets the cache feature for the model. It caches the result of the sql, which means
+// if there's another same sql request, it just reads and returns the result from cache, it
+// but not committed and executed into the database.
+//
+// If the parameter <duration> < 0, which means it clear the cache with given <name>.
+// If the parameter <duration> = 0, which means it never expires.
+// If the parameter <duration> > 0, which means it expires after <duration>.
+//
+// The optional parameter <name> is used to bind a name to the cache, which means you can later
+// control the cache like changing the <duration> or clearing the cache with specified <name>.
+//
+// Note that, the cache feature is disabled if the model is operating on a transaction.
+func (m *arModel) Cache(duration time.Duration, name ...string) *arModel {
+	return &arModel{m.M.Cache(duration, name...)}
+}
+
+// Data sets the operation data for the model.
+// The parameter <data> can be type of string/map/gmap/slice/struct/*struct, etc.
+// Eg:
+// Data("uid=10000")
+// Data("uid", 10000)
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+func (m *arModel) Data(data ...interface{}) *arModel {
+	return &arModel{m.M.Data(data...)}
+}
+
+// All does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as []*Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) All(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.All(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// One retrieves one record from table and returns the result as *Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) One(where ...interface{}) (*Entity, error) {
+	one, err := m.M.One(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindOne retrieves and returns a single Record by Model.WherePri and Model.One.
+// Also see Model.WherePri and Model.One.
+func (m *arModel) FindOne(where ...interface{}) (*Entity, error) {
+	one, err := m.M.FindOne(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindAll retrieves and returns Result by by Model.WherePri and Model.All.
+// Also see Model.WherePri and Model.All.
+func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.FindAll(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// Chunk iterates the table with given size and callback function.
+func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) {
+	m.M.Chunk(limit, func(result gdb.Result, err error) bool {
+		var entities []*Entity
+		err = result.Structs(&entities)
+		if err == sql.ErrNoRows {
+			return false
+		}
+		return callback(entities, err)
+	})
+}
+
+// LockUpdate sets the lock for update for current operation.
+func (m *arModel) LockUpdate() *arModel {
+	return &arModel{m.M.LockUpdate()}
+}
+
+// LockShared sets the lock in share mode for current operation.
+func (m *arModel) LockShared() *arModel {
+	return &arModel{m.M.LockShared()}
+}

+ 154 - 51
app/model/admin/user/user.go

@@ -1,52 +1,93 @@
 package user
 
 import (
+	"gfast/library/utils"
 	"github.com/gogf/gf/errors/gerror"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/os/gtime"
 	"github.com/gogf/gf/util/gconv"
-	"github.com/gogf/gf/util/gvalid"
 )
 
-//验证用户表单数据
-func checkUserData(params map[string]interface{}, t string) error {
-	rules := []string{
-		"id@integer|min:1#管理员id必须为整数|管理员Id必须大于0",
-		"user_name@required|length:3,60#请填用户名|用户名应在:min到:max个字符之间",
-		"mobile@telephone#手机号码格式不正确",
-		"user_nickname@required|length:3,50#请填写姓名|姓名应在:min到:max个字符之间",
-		"user_email@email#邮箱格式错误",
-	}
-	if t == "add" {
-		rules = append(rules, "user_password@required|length:6,60#请填写密码|密码应在::min到:max个字符之间")
-	} else {
-		rules = append(rules, "user_password@length:6,60#密码应在::min到:max个字符之间")
-	}
-	e := gvalid.CheckMap(params, rules)
-	if e != nil {
-		return e
-	}
-	return nil
+//设置用户状态参数
+type StatusReq struct {
+	Id         int `p:"userId" v:"required#用户id不能为空"`
+	UserStatus int `p:"status" v:"required#用户状态不能为空"`
+}
+
+//重置用户密码状态参数
+type ResetPwdReq struct {
+	Id       int    `p:"userId" v:"required#用户id不能为空"`
+	Password string `p:"password" v:"required|password#密码不能为空|密码以字母开头,只能包含字母、数字和下划线,长度在6~18之间"`
+}
+
+//用户搜索请求参数
+type SearchReq struct {
+	DeptId      string `p:deptId` //部门id
+	DeptIds     []int  //所属部门id数据
+	BeginTime   string `p:"beginTime`
+	EndTime     string `p:"endTime"`
+	Phonenumber string `p:"phonenumber"`
+	Status      string `p:"status"`
+	KeyWords    string `p:"userName"`
+	PageNum     int    `p:"page"`     //当前页码
+	PageSize    int    `p:"pageSize"` //每页数
+}
+
+//添加修改用户公用请求字段
+type SetUserReq struct {
+	DeptId      int64   `p:"deptId" v:"required#用户部门不能为空"` //所属部门
+	Email       string  `p:"email" v:"email#邮箱格式错误"`       //邮箱
+	NickName    string  `p:"nickName" v:"required#用户昵称不能为空"`
+	Phonenumber string  `p:"phonenumber" v:"required|phone#手机号不能为空|手机号格式错误"`
+	PostIds     []int64 `p:"postIds"`
+	Remark      string  `p:"remark"`
+	RoleIds     []int64 `p:"roleIds"`
+	Sex         int     `p:"sex"`
+	Status      int     `p:"status"`
+	IsAdmin     int     `p:"is_admin"` // 是否后台管理员 1 是  0   否
+}
+
+//添加用户请求
+type AddUserReq struct {
+	SetUserReq
+	UserName string `p:"userName" v:"required#用户账号不能为空"`
+	Password string `p:"password" v:"required|password#密码不能为空|密码以字母开头,只能包含字母、数字和下划线,长度在6~18之间"`
+}
+
+//修改用户请求
+type EditUserReq struct {
+	SetUserReq
+	UserId int `p:"userId" v:"required#用户id不能为空"`
+}
+
+func GetUserById(id int) (*Entity, error) {
+	return Model.Where("id", id).One()
 }
 
 //添加管理员操作
-func Add(data map[string]interface{}) (InsertId int64, err error) {
-	e := checkUserData(data, "add")
-	if e != nil {
-		err = gerror.New(e.(*gvalid.Error).FirstString())
-		return
-	}
-	if i, _ := Model.Where("user_name=?", data["user_name"]).Count(); i != 0 {
+func Add(req *AddUserReq) (InsertId int64, err error) {
+	if i, _ := Model.Where("user_name=?", req.UserName).Count(); i != 0 {
 		err = gerror.New("用户名已经存在")
 		return
 	}
-	if i, _ := Model.Where("mobile=?", data["mobile"]).Count(); i != 0 {
+	if i, _ := Model.Where("mobile=?", req.Phonenumber).Count(); i != 0 {
 		err = gerror.New("手机号已经存在")
 		return
 	}
 	//保存管理员信息
-	data["create_time"] = gtime.Timestamp()
-	res, err := Model.Filter().Data(data).Save()
+	entity := new(Entity)
+	entity.UserName = req.UserName
+	entity.DeptId = req.DeptId
+	entity.UserStatus = req.Status
+	entity.CreateTime = gconv.Int(gtime.Timestamp())
+	entity.Mobile = req.Phonenumber
+	entity.Sex = req.Sex
+	entity.UserEmail = req.Email
+	entity.UserNickname = req.NickName
+	entity.UserPassword = req.Password
+	entity.Remark = req.Remark
+
+	res, err := entity.Save()
 	if err != nil {
 		return
 	}
@@ -55,40 +96,102 @@ func Add(data map[string]interface{}) (InsertId int64, err error) {
 }
 
 //修改用户信息
-func Edit(data map[string]interface{}) (err error) {
-	e := checkUserData(data, "edit")
-	if e != nil {
-		err = gerror.New(e.(*gvalid.Error).FirstString())
-		return
-	}
-	if i, _ := Model.Where("id!=? and user_name=?", data["id"], data["user_name"]).Count(); i != 0 {
-		err = gerror.New("用户名已经存在")
-		return
-	}
-	if i, _ := Model.Where("id!=? and mobile=?", data["mobile"]).Count(); i != 0 {
+func Edit(req *EditUserReq) (err error) {
+	if i, _ := Model.Where("id!=? and mobile=?", req.UserId, req.Phonenumber).Count(); i != 0 {
 		err = gerror.New("手机号已经存在")
 		return
 	}
 	//保存管理员信息
-	_, err = Model.Filter().Data(data).Save()
-	if err != nil {
+	var entity *Entity
+	entity, err = Model.Where("id", req.UserId).One()
+	if err != nil || entity == nil {
+		g.Log().Error(err)
+		err = gerror.New("获取用户信息失败")
 		return
 	}
+	entity.DeptId = req.DeptId
+	entity.UserStatus = req.Status
+	entity.Mobile = req.Phonenumber
+	entity.Sex = req.Sex
+	entity.UserEmail = req.Email
+	entity.UserNickname = req.NickName
+	entity.Remark = req.Remark
+	entity.IsAdmin = req.IsAdmin
+	_, err = entity.Update()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("修改用户信息失败")
+	}
 	return
 }
 
 //获取管理员列表
-func GetAdminList(where g.Map, page, pageNum int) (total int, userList []*Entity, err error) {
+func GetAdminList(req *SearchReq) (total, page int, userList []*Entity, err error) {
 	userModel := Model
-	if v, ok := where["keyWords"]; ok {
-		keyWords := gconv.String(v)
-		if keyWords != "" {
-			keyWords = "%" + keyWords + "%"
-			userModel = userModel.Where("user_name like ? or mobile like ? or user_nickname like ?",
-				keyWords, keyWords, keyWords)
+	if req != nil {
+		if req.KeyWords != "" {
+			keyWords := "%" + req.KeyWords + "%"
+			userModel = userModel.Where("user_name like ? or  user_nickname like ?",
+				keyWords, keyWords)
+		}
+		if len(req.DeptIds) != 0 {
+			userModel = userModel.Where("dept_id in (?)", req.DeptIds)
+		}
+		if req.Status != "" {
+			userModel = userModel.Where("user_status", gconv.Int(req.Status))
+		}
+		if req.Phonenumber != "" {
+			userModel = userModel.Where("mobile like ?", "%"+req.Phonenumber+"%")
+		}
+		if req.BeginTime != "" {
+			userModel = userModel.Where("create_time >=?", utils.StrToTimestamp(req.BeginTime))
+		}
+		if req.EndTime != "" {
+			userModel = userModel.Where("create_time <=?", utils.StrToTimestamp(req.EndTime))
 		}
 	}
 	total, err = userModel.Count()
-	userList, err = userModel.ForPage(page, pageNum).OrderBy("id asc").All()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取总行数失败")
+		return
+	}
+	if req.PageNum == 0 {
+		req.PageNum = 1
+	}
+	page = req.PageNum
+	userList, err = userModel.ForPage(page, req.PageSize).OrderBy("id asc").All()
 	return
 }
+
+//修改用户状态
+func ChangeUserStatus(req *StatusReq) error {
+	user, err := Model.Where("id", req.Id).One()
+	if err != nil || user == nil {
+		g.Log().Error(err)
+		return gerror.New("用户不存在")
+	}
+	user.UserStatus = req.UserStatus
+	_, err = user.Update()
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("修改用户状态失败")
+	}
+	return nil
+}
+
+//重置用户密码
+func ResetUserPwd(req *ResetPwdReq) error {
+	user, err := Model.Where("id", req.Id).One()
+	if err != nil || user == nil {
+		g.Log().Error(err)
+		return gerror.New("用户不存在")
+	}
+	user.UserPassword = req.Password
+	_, err = user.Update()
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("修改用户密码失败")
+	}
+	return nil
+}

+ 3 - 0
app/model/admin/user/user_entity.go

@@ -24,6 +24,9 @@ type Entity struct {
 	Avatar        string `orm:"avatar"           json:"avatar"`          // 用户头像
 	LastLoginTime int    `orm:"last_login_time"  json:"last_login_time"` // 最后登录时间
 	LastLoginIp   string `orm:"last_login_ip"    json:"last_login_ip"`   // 最后登录ip
+	DeptId        int64  `orm:"dept_id"       json:"dept_id"`            //所属部门id
+	Remark        string `orm:"remark"           json:"remark"`          // 备注
+	IsAdmin       int    `orm:"is_admin"         json:"is_admin"`        // 是否后台管理员 1 是  0   否
 }
 
 // User is alias of Entity, which some developers say they just want.

+ 2 - 2
app/model/admin/user_online/user_online.go

@@ -8,8 +8,8 @@ import (
 // Fill with you ideas below.
 //列表搜索参数
 type ReqListSearch struct {
-	Username string `p:"username"`
-	Ip       string `p:"ip"`
+	Username string `p:"userName"`
+	Ip       string `p:"ipaddr"`
 	PageNum  int    `p:"page"`     //当前页码
 	PageSize int    `p:"pageSize"` //每页数
 }

+ 57 - 0
app/model/admin/user_post/user_post.go

@@ -0,0 +1,57 @@
+// ============================================================================
+// This is auto-generated by gf cli tool only once. Fill this file as you wish.
+// ============================================================================
+
+package user_post
+
+import (
+	"gfast/app/model/admin/sys_post"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+)
+
+//删除对应用户的岗位信息
+func DeleteByUserId(userId int64) error {
+	_, err := Model.Delete(Columns.UserId, userId)
+	return err
+}
+
+//添加用户岗位
+func AddUserPost(postIds []int64, userId int64) (err error) {
+	data := g.List{}
+	for _, v := range postIds {
+		data = append(data, g.Map{
+			Columns.UserId: userId,
+			Columns.PostId: v,
+		})
+	}
+	_, err = Model.Data(data).Insert()
+	return
+}
+
+//获取用户岗位
+func GetAdminPosts(userId int) (postIds []int64, err error) {
+	list, e := Model.All(Columns.UserId, userId)
+	if e != nil {
+		g.Log().Error(e)
+		err = gerror.New("获取用户岗位信息失败")
+		return
+	}
+	for _, entity := range list {
+		postIds = append(postIds, entity.PostId)
+	}
+	return
+}
+
+//根据用户id获取岗位信息详情
+func GetPostsByUserId(userId int) ([]*sys_post.Entity, error) {
+	model := g.DB().Table(Table)
+	datas := ([]*sys_post.Entity)(nil)
+	err := model.As("a").InnerJoin("sys_post b", "a.post_id = b.post_id").Fields("b.*").Where(Columns.UserId, userId).Structs(&datas)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return datas, nil
+}

+ 58 - 0
app/model/admin/user_post/user_post_entity.go

@@ -0,0 +1,58 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package user_post
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+)
+
+// Entity is the golang structure for table user_post.
+type Entity struct {
+	UserId int64 `orm:"user_id,primary" json:"user_id"` // 用户ID
+	PostId int64 `orm:"post_id,primary" json:"post_id"` // 岗位ID
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (r *Entity) OmitEmpty() *arModel {
+	return Model.Data(r).OmitEmpty()
+}
+
+// Inserts does "INSERT...INTO..." statement for inserting current object into table.
+func (r *Entity) Insert() (result sql.Result, err error) {
+	return Model.Data(r).Insert()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for inserting current object into table.
+func (r *Entity) InsertIgnore() (result sql.Result, err error) {
+	return Model.Data(r).InsertIgnore()
+}
+
+// Replace does "REPLACE...INTO..." statement for inserting current object into table.
+// If there's already another same record in the table (it checks using primary key or unique index),
+// it deletes it and insert this one.
+func (r *Entity) Replace() (result sql.Result, err error) {
+	return Model.Data(r).Replace()
+}
+
+// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Save() (result sql.Result, err error) {
+	return Model.Data(r).Save()
+}
+
+// Update does "UPDATE...WHERE..." statement for updating current object from table.
+// It updates the record if there's already another same record in the table
+// (it checks using primary key or unique index).
+func (r *Entity) Update() (result sql.Result, err error) {
+	return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
+}
+
+// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
+func (r *Entity) Delete() (result sql.Result, err error) {
+	return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
+}

+ 345 - 0
app/model/admin/user_post/user_post_model.go

@@ -0,0 +1,345 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. You may not really want to edit it.
+// ==========================================================================
+
+package user_post
+
+import (
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+	"time"
+)
+
+// arModel is a active record design model for table user_post operations.
+type arModel struct {
+	gmvc.M
+}
+
+var (
+	// Table is the table name of user_post.
+	Table = "user_post"
+	// Model is the model object of user_post.
+	Model = &arModel{g.DB("default").Table(Table).Safe()}
+	// Columns defines and stores column names for table user_post.
+	Columns = struct {
+		UserId string // 用户ID
+		PostId string // 岗位ID
+	}{
+		UserId: "user_id",
+		PostId: "post_id",
+	}
+)
+
+// FindOne is a convenience method for Model.FindOne.
+// See Model.FindOne.
+func FindOne(where ...interface{}) (*Entity, error) {
+	return Model.FindOne(where...)
+}
+
+// FindAll is a convenience method for Model.FindAll.
+// See Model.FindAll.
+func FindAll(where ...interface{}) ([]*Entity, error) {
+	return Model.FindAll(where...)
+}
+
+// FindValue is a convenience method for Model.FindValue.
+// See Model.FindValue.
+func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
+	return Model.FindValue(fieldsAndWhere...)
+}
+
+// FindArray is a convenience method for Model.FindArray.
+// See Model.FindArray.
+func FindArray(fieldsAndWhere ...interface{}) ([]gdb.Value, error) {
+	return Model.FindArray(fieldsAndWhere...)
+}
+
+// FindCount is a convenience method for Model.FindCount.
+// See Model.FindCount.
+func FindCount(where ...interface{}) (int, error) {
+	return Model.FindCount(where...)
+}
+
+// Insert is a convenience method for Model.Insert.
+func Insert(data ...interface{}) (result sql.Result, err error) {
+	return Model.Insert(data...)
+}
+
+// InsertIgnore is a convenience method for Model.InsertIgnore.
+func InsertIgnore(data ...interface{}) (result sql.Result, err error) {
+	return Model.InsertIgnore(data...)
+}
+
+// Replace is a convenience method for Model.Replace.
+func Replace(data ...interface{}) (result sql.Result, err error) {
+	return Model.Replace(data...)
+}
+
+// Save is a convenience method for Model.Save.
+func Save(data ...interface{}) (result sql.Result, err error) {
+	return Model.Save(data...)
+}
+
+// Update is a convenience method for Model.Update.
+func Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
+	return Model.Update(dataAndWhere...)
+}
+
+// Delete is a convenience method for Model.Delete.
+func Delete(where ...interface{}) (result sql.Result, err error) {
+	return Model.Delete(where...)
+}
+
+// As sets an alias name for current table.
+func (m *arModel) As(as string) *arModel {
+	return &arModel{m.M.As(as)}
+}
+
+// TX sets the transaction for current operation.
+func (m *arModel) TX(tx *gdb.TX) *arModel {
+	return &arModel{m.M.TX(tx)}
+}
+
+// Master marks the following operation on master node.
+func (m *arModel) Master() *arModel {
+	return &arModel{m.M.Master()}
+}
+
+// Slave marks the following operation on slave node.
+// Note that it makes sense only if there's any slave node configured.
+func (m *arModel) Slave() *arModel {
+	return &arModel{m.M.Slave()}
+}
+
+// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) LeftJoin(table ...string) *arModel {
+	return &arModel{m.M.LeftJoin(table...)}
+}
+
+// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").RightJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) RightJoin(table ...string) *arModel {
+	return &arModel{m.M.RightJoin(table...)}
+}
+
+// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
+func (m *arModel) InnerJoin(table ...string) *arModel {
+	return &arModel{m.M.InnerJoin(table...)}
+}
+
+// Fields sets the operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) Fields(fields string) *arModel {
+	return &arModel{m.M.Fields(fields)}
+}
+
+// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
+func (m *arModel) FieldsEx(fields string) *arModel {
+	return &arModel{m.M.FieldsEx(fields)}
+}
+
+// Option sets the extra operation option for the model.
+func (m *arModel) Option(option int) *arModel {
+	return &arModel{m.M.Option(option)}
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (m *arModel) OmitEmpty() *arModel {
+	return &arModel{m.M.OmitEmpty()}
+}
+
+// Filter marks filtering the fields which does not exist in the fields of the operated table.
+func (m *arModel) Filter() *arModel {
+	return &arModel{m.M.Filter()}
+}
+
+// Where sets the condition statement for the model. The parameter <where> can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+// Eg:
+// Where("uid=10000")
+// Where("uid", 10000)
+// Where("money>? AND name like ?", 99999, "vip_%")
+// Where("uid", 1).Where("name", "john")
+// Where("status IN (?)", g.Slice{1,2,3})
+// Where("age IN(?,?)", 18, 50)
+// Where(User{ Id : 1, UserName : "john"})
+func (m *arModel) Where(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Where(where, args...)}
+}
+
+// And adds "AND" condition to the where statement.
+func (m *arModel) And(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.And(where, args...)}
+}
+
+// Or adds "OR" condition to the where statement.
+func (m *arModel) Or(where interface{}, args ...interface{}) *arModel {
+	return &arModel{m.M.Or(where, args...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (m *arModel) Group(groupBy string) *arModel {
+	return &arModel{m.M.Group(groupBy)}
+}
+
+// Order sets the "ORDER BY" statement for the model.
+func (m *arModel) Order(orderBy ...string) *arModel {
+	return &arModel{m.M.Order(orderBy...)}
+}
+
+// Limit sets the "LIMIT" statement for the model.
+// The parameter <limit> can be either one or two number, if passed two number is passed,
+// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
+// statement.
+func (m *arModel) Limit(limit ...int) *arModel {
+	return &arModel{m.M.Limit(limit...)}
+}
+
+// Offset sets the "OFFSET" statement for the model.
+// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
+func (m *arModel) Offset(offset int) *arModel {
+	return &arModel{m.M.Offset(offset)}
+}
+
+// Page sets the paging number for the model.
+// The parameter <page> is started from 1 for paging.
+// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
+func (m *arModel) Page(page, limit int) *arModel {
+	return &arModel{m.M.Page(page, limit)}
+}
+
+// Batch sets the batch operation number for the model.
+func (m *arModel) Batch(batch int) *arModel {
+	return &arModel{m.M.Batch(batch)}
+}
+
+// Cache sets the cache feature for the model. It caches the result of the sql, which means
+// if there's another same sql request, it just reads and returns the result from cache, it
+// but not committed and executed into the database.
+//
+// If the parameter <duration> < 0, which means it clear the cache with given <name>.
+// If the parameter <duration> = 0, which means it never expires.
+// If the parameter <duration> > 0, which means it expires after <duration>.
+//
+// The optional parameter <name> is used to bind a name to the cache, which means you can later
+// control the cache like changing the <duration> or clearing the cache with specified <name>.
+//
+// Note that, the cache feature is disabled if the model is operating on a transaction.
+func (m *arModel) Cache(duration time.Duration, name ...string) *arModel {
+	return &arModel{m.M.Cache(duration, name...)}
+}
+
+// Data sets the operation data for the model.
+// The parameter <data> can be type of string/map/gmap/slice/struct/*struct, etc.
+// Eg:
+// Data("uid=10000")
+// Data("uid", 10000)
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+func (m *arModel) Data(data ...interface{}) *arModel {
+	return &arModel{m.M.Data(data...)}
+}
+
+// All does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as []*Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) All(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.All(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// One retrieves one record from table and returns the result as *Entity.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *arModel) One(where ...interface{}) (*Entity, error) {
+	one, err := m.M.One(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindOne retrieves and returns a single Record by Model.WherePri and Model.One.
+// Also see Model.WherePri and Model.One.
+func (m *arModel) FindOne(where ...interface{}) (*Entity, error) {
+	one, err := m.M.FindOne(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *Entity
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindAll retrieves and returns Result by by Model.WherePri and Model.All.
+// Also see Model.WherePri and Model.All.
+func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) {
+	all, err := m.M.FindAll(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*Entity
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// Chunk iterates the table with given size and callback function.
+func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) {
+	m.M.Chunk(limit, func(result gdb.Result, err error) bool {
+		var entities []*Entity
+		err = result.Structs(&entities)
+		if err == sql.ErrNoRows {
+			return false
+		}
+		return callback(entities, err)
+	})
+}
+
+// LockUpdate sets the lock for update for current operation.
+func (m *arModel) LockUpdate() *arModel {
+	return &arModel{m.M.LockUpdate()}
+}
+
+// LockShared sets the lock in share mode for current operation.
+func (m *arModel) LockShared() *arModel {
+	return &arModel{m.M.LockShared()}
+}
+
+// Unscoped enables/disables the soft deleting feature.
+func (m *arModel) Unscoped() *arModel {
+	return &arModel{m.M.Unscoped()}
+}

+ 65 - 14
app/service/admin/auth_service/auth_rule.go

@@ -5,13 +5,17 @@ import (
 	"gfast/app/model/admin/auth_rule"
 	"gfast/app/model/admin/role"
 	"gfast/app/model/admin/user"
+	"gfast/app/model/admin/user_post"
 	"gfast/app/service/casbin_adapter_service"
 	"gfast/library/utils"
 	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/text/gstr"
 	"github.com/gogf/gf/util/gconv"
 )
 
-//获取isMenu==1菜单列表
+//获取MenuType==0,1菜单列表
 func GetIsMenuList() ([]*auth_rule.Entity, error) {
 	list, err := GetMenuList()
 	if err != nil {
@@ -19,7 +23,7 @@ func GetIsMenuList() ([]*auth_rule.Entity, error) {
 	}
 	var gList = make([]*auth_rule.Entity, 0, len(list))
 	for _, v := range list {
-		if v.Ismenu == 1 {
+		if v.MenuType == 0 || v.MenuType == 1 {
 			gList = append(gList, v)
 		}
 	}
@@ -34,7 +38,7 @@ func GetIsMenuStatusList() ([]*auth_rule.Entity, error) {
 	}
 	var gList = make([]*auth_rule.Entity, 0, len(list))
 	for _, v := range list {
-		if v.Ismenu == 1 && v.Status == 1 {
+		if (v.MenuType == 0 || v.MenuType == 1) && v.Status == 1 {
 			gList = append(gList, v)
 		}
 	}
@@ -61,11 +65,35 @@ func GetMenuList() (list []*auth_rule.Entity, err error) {
 	return auth_rule.GetMenuList()
 }
 
+func GetMenuListSearch(req *auth_rule.ReqSearch) (list []*auth_rule.Entity, err error) {
+	list, err = auth_rule.GetMenuList()
+	if err != nil {
+		return
+	}
+	if req != nil {
+		tmpList := make([]*auth_rule.Entity, 0, len(list))
+		for _, entity := range list {
+			if (req.Title == "" || gstr.Contains(gstr.ToUpper(entity.Title), gstr.ToUpper(req.Title))) &&
+				(req.Status == "" || gconv.Uint(req.Status) == entity.Status) {
+				tmpList = append(tmpList, entity)
+			}
+		}
+		list = tmpList
+	}
+	g.Log().Debug(list)
+	return
+}
+
 //检查菜单规则是否存在
 func CheckMenuNameUnique(name string, id int) bool {
 	return auth_rule.CheckMenuNameUnique(name, id)
 }
 
+//检查菜单路由地址是否已经存在
+func CheckMenuPathUnique(path string, id int) bool {
+	return auth_rule.CheckMenuPathUnique(path, id)
+}
+
 // 添加菜单操作
 func AddMenu(req *auth_rule.MenuReq) (err error, insertId int64) {
 	return auth_rule.Add(req)
@@ -81,6 +109,10 @@ func GetRoleList() (list []*role.Entity, err error) {
 	return role.GetList()
 }
 
+func GetRoleListSearch(req *role.SelectPageReq) (total, page int, list []*role.Entity, err error) {
+	return role.GetRoleListSearch(req)
+}
+
 //保存角色信息并返回插入的id
 func AddRole(tx *gdb.TX, data map[string]interface{}) (InsId int64, err error) {
 	return role.Add(tx, data)
@@ -108,6 +140,14 @@ func EditRole(tx *gdb.TX, data map[string]interface{}) (err error) {
 	return role.Edit(tx, data)
 }
 
+func StatusSetRole(req *role.StatusSetReq) error {
+	return role.StatusSetRole(req)
+}
+
+func RoleDataScope(req *role.DataScopeReq) error {
+	return role.DataScope(req)
+}
+
 //修改角色的授权规则
 func EditRoleRule(iRule interface{}, roleId int64) (err error) {
 	enforcer, e := casbin_adapter_service.GetEnforcer()
@@ -141,21 +181,15 @@ func DeleteRoleRule(roleId int) (err error) {
 }
 
 //添加管理员操作
-func AddUser(data map[string]interface{}) (InsertId int64, err error) {
+func AddUser(req *user.AddUserReq) (InsertId int64, err error) {
 	//密码加密
-	data["user_password"] = utils.EncryptCBC(gconv.String(data["user_password"]), utils.AdminCbcPublicKey)
-	return user.Add(data)
+	req.Password = utils.EncryptCBC(gconv.String(req.Password), utils.AdminCbcPublicKey)
+	return user.Add(req)
 }
 
 //修改用户信息
-func EditUser(data map[string]interface{}) (err error) {
-	//提交了密码?密码加密
-	if val, ok := data["user_password"]; ok && gconv.String(val) != "" {
-		data["user_password"] = utils.EncryptCBC(gconv.String(data["user_password"]), utils.AdminCbcPublicKey)
-	} else {
-		delete(data, "user_password")
-	}
-	return user.Edit(data)
+func EditUser(req *user.EditUserReq) (err error) {
+	return user.Edit(req)
 }
 
 //添加用户角色信息
@@ -175,6 +209,23 @@ func AddUserRole(roleIds interface{}, userId int64) (err error) {
 	return
 }
 
+//添加用户岗位信息
+func AddUserPost(postIds []int64, userId int64) (err error) {
+	//删除旧岗位信息
+	err = user_post.DeleteByUserId(userId)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("设置用户岗位信息失败")
+	}
+	//添加用户岗位信息
+	err = user_post.AddUserPost(postIds, userId)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("设置用户岗位信息失败")
+	}
+	return
+}
+
 //修改用户角色信息
 func EditUserRole(roleIds interface{}, userId int) (err error) {
 	enforcer, e := casbin_adapter_service.GetEnforcer()

+ 0 - 86
app/service/admin/cms_service/menu.go

@@ -1,86 +0,0 @@
-package cms_service
-
-import (
-	"gfast/app/model/admin/cms_category"
-	"github.com/gogf/gf/frame/g"
-	"github.com/gogf/gf/util/gconv"
-)
-
-//获取频道列表
-func GetMenuListChannel() (list []*cms_category.Entity, err error) {
-	//获取频道列表
-	listAll, err := GetMenuList()
-	if err != nil {
-		return
-	}
-	list = make([]*cms_category.Entity, 0, len(listAll))
-	for _, v := range listAll {
-		if v.Status == 1 && v.CateType == cms_category.ChannelCateType {
-			list = append(list, v)
-		}
-	}
-	return
-}
-
-//获取可发布文章栏目
-func GetPublishableMenuList(catId ...int) (list g.List, err error) {
-	menuList, err := GetMenuList()
-	var catIdMap map[int]int
-	if len(catId) > 0 {
-		catIdMap = make(map[int]int, len(catId))
-		for _, v := range catId {
-			catIdMap[v] = v
-		}
-	}
-	if err != nil {
-		return
-	}
-	list = make(g.List, 0)
-	for _, menu := range menuList {
-		if menu.Status == 1 {
-			mapMenu := gconv.Map(menu)
-			//可发布栏目
-			if menu.CateType == cms_category.PublishCateType {
-				mapMenu["checkAble"] = true
-			} else {
-				mapMenu["checkAble"] = false
-			}
-			if _, ok := catIdMap[gconv.Int(menu.Id)]; ok {
-				mapMenu["checked"] = true
-			} else {
-				mapMenu["checked"] = false
-			}
-			list = append(list, mapMenu)
-		}
-	}
-	return
-}
-
-//获取所有菜单列表
-func GetMenuList() (list []*cms_category.Entity, err error) {
-	return cms_category.GetList()
-}
-
-//保存栏目操作
-func AddSave(req *cms_category.ReqAdd) (id int64, err error) {
-	return cms_category.AddSave(req)
-}
-
-//修改栏目操作
-func EditSave(req *cms_category.ReqEdit) (id int64, err error) {
-	return cms_category.EditSave(req)
-}
-
-//获取搜索栏目结果
-func GetMenuListSearch(req *cms_category.ReqSearchList) (menus []*cms_category.Entity, err error) {
-	return cms_category.GetListSearch(req)
-}
-
-//根据栏目ID获取栏目信息
-func GetMenuInfoById(id int) (menu *cms_category.Entity, err error) {
-	return cms_category.GetInfoById(id)
-}
-
-func DeleteMenuByIds(ids []int) (err error) {
-	return cms_category.DeleteByIds(ids)
-}

+ 0 - 99
app/service/admin/cms_service/news.go

@@ -1,99 +0,0 @@
-package cms_service
-
-import (
-	"gfast/app/model/admin/cms_category"
-	"gfast/app/model/admin/cms_category_news"
-	"gfast/app/model/admin/cms_news"
-	"gfast/library/utils"
-	"github.com/gogf/gf/container/gvar"
-	"github.com/gogf/gf/database/gdb"
-	"github.com/gogf/gf/util/gconv"
-)
-
-//添加文章操作
-func AddNews(req *cms_news.ReqAddParams, cateIds []int, userId int) (insId int64, err error) {
-	return cms_news.AddNews(req, cateIds, userId)
-}
-
-//修改文章操作
-func EditNews(req *cms_news.ReqEditParams, cateIds []int) (err error) {
-	return cms_news.EditNews(req, cateIds)
-}
-
-//文章列表查询
-func NewsListByPage(req *cms_news.ReqListSearchParams) (total, page int, list gdb.Result, err error) {
-	var menuList []*cms_category.Entity
-	//获取所有栏目
-	menuList, err = GetMenuList()
-	if err != nil {
-		return
-	}
-	if len(req.CateId) > 0 {
-		//查询可发布栏目id
-		menuListSlice := gconv.SliceMap(menuList)
-		cateIds := req.CateId
-		for _, cid := range cateIds {
-			mList := make([]*cms_category.Entity, 0)
-			sonList := utils.FindSonByParentId(menuListSlice, cid, "parent_id", "id")
-			gconv.Structs(sonList, &mList)
-			for _, v := range mList {
-				if v.CateType == cms_category.PublishCateType {
-					req.CateId = append(req.CateId, gconv.Int(v.Id))
-				}
-			}
-		}
-	}
-	total, page, list, err = cms_news.ListByPage(req)
-	if err != nil || len(list) == 0 {
-		return
-	}
-	//匹配文章所属栏目
-	var cateIds []int
-	for _, v := range list {
-		cateIds, err = GetCheckedCategoryIdByNewsId(gconv.Uint64(v["id"]))
-		if err != nil {
-			return
-		}
-		cateNameList := make(map[int]string)
-		for _, menu := range menuList {
-			for _, cateId := range cateIds {
-				if menu.Id == gconv.Uint64(cateId) {
-					cateNameList[cateId] = menu.Name
-				}
-			}
-		}
-		cateVal := new(gvar.Var)
-		if len(cateNameList) > 0 {
-			cateVal.Set(cateNameList)
-		}
-		v["cateList"] = cateVal
-	}
-	return
-}
-
-//通过id获取文章信息
-func GetNewsById(id int) (news *cms_news.Entity, err error) {
-	return cms_news.GetById(id)
-}
-
-//通过文章id获取关联的栏目id
-func GetCheckedCategoryIdByNewsId(newsId uint64) (catIds []int, err error) {
-	categories, err := GetCategoriesByNewsId(newsId)
-	if err != nil {
-		return
-	}
-	catIds = make([]int, len(categories))
-	for k, v := range categories {
-		catIds[k] = gconv.Int(v.CategoryId)
-	}
-	return
-}
-
-//通过文章id获取关联栏目信息
-func GetCategoriesByNewsId(newsId uint64) (categories []*cms_category_news.Entity, err error) {
-	return cms_category_news.GetCategoriesByNewsId(newsId)
-}
-
-func DeleteCmsByIds(ids []int) (err error) {
-	return cms_news.DeleteByIds(ids)
-}

+ 48 - 0
app/service/admin/dept_service/dept.go

@@ -0,0 +1,48 @@
+package dept_service
+
+import (
+	"database/sql"
+	"gfast/app/model/admin/role_dept"
+	"gfast/app/model/admin/sys_dept"
+)
+
+/**
+获取列表数据
+*/
+func GetList(searchParams *sys_dept.SearchParams) ([]*sys_dept.Dept, error) {
+	if list, err := sys_dept.GetList(searchParams); err != nil {
+		return nil, err
+	} else {
+		return list, nil
+	}
+}
+
+func GetRoleDepts(roleId int64) ([]int64, error) {
+	return role_dept.GetRoleDepts(roleId)
+}
+
+func AddDept(data *sys_dept.AddParams) (sql.Result, error) {
+	return sys_dept.AddDept(data)
+}
+
+func EditDept(data *sys_dept.EditParams) error {
+	return sys_dept.EditDept(data)
+}
+
+func GetDeptById(id int64) (*sys_dept.Dept, error) {
+	return sys_dept.GetDeptById(id)
+}
+
+/**
+查询部门排除节点
+*/
+func Exclude(id int64) ([]*sys_dept.Dept, error) {
+	return sys_dept.Exclude(id)
+}
+
+/**
+删除
+*/
+func DelDept(id int64) error {
+	return sys_dept.DelDept(id)
+}

+ 22 - 0
app/service/admin/dict_service/dict_type.go

@@ -2,7 +2,10 @@ package dict_service
 
 import (
 	"gfast/app/model/admin/sys_dict_type"
+	"gfast/app/service/cache_service"
+	"github.com/gogf/gf/errors/gerror"
 	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/util/gconv"
 )
 
 //检查字典类型是否唯一
@@ -44,3 +47,22 @@ func GetDictWithDataByType(dictType, defaultValue, emptyLabel string) (dict g.Ma
 func DeleteDictByIds(ids []int) error {
 	return sys_dict_type.DeleteDictByIds(ids)
 }
+
+func GetAllDictType() (list []*sys_dict_type.Entity, err error) {
+	cache := cache_service.New()
+	//从缓存获取
+	data := cache.Get(gconv.String(cache_service.AdminConfigDict) + "_dict_type_all")
+	if data != nil {
+		list = data.([]*sys_dict_type.Entity)
+		return
+	}
+	list, err = sys_dict_type.GetAllDictType()
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取字典类型数据出错")
+		return
+	}
+	//缓存
+	cache.Set(gconv.String(cache_service.AdminConfigDict)+"_dict_type_all", list, 0, cache_service.AdminSysConfigTag)
+	return
+}

+ 498 - 0
app/service/admin/gen_service/table.go

@@ -0,0 +1,498 @@
+package gen_service
+
+import (
+	"gfast/app/model/admin/gen_table"
+	"gfast/app/model/admin/gen_table_column"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/encoding/gjson"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/os/gtime"
+	"github.com/gogf/gf/util/gconv"
+	"strings"
+)
+
+//根据条件分页查询数据
+func SelectDbTableList(param *gen_table.SelectPageReq) (total int, list []*gen_table.Entity, err error) {
+	return gen_table.SelectDbTableList(param)
+}
+
+//根据条件分页查询数据
+func SelectListByPage(param *gen_table.SelectPageReq) (total int, list []*gen_table.Entity, err error) {
+	return gen_table.SelectListByPage(param)
+}
+
+//查询据库列表
+func SelectDbTableListByNames(tableNames []string) ([]*gen_table.Entity, error) {
+	return gen_table.SelectDbTableListByNames(tableNames)
+}
+
+//导入表结构
+func ImportGenTable(tableList []*gen_table.Entity, operName string) error {
+	if tableList != nil && operName != "" {
+		tx, err := g.DB().Begin()
+		if err != nil {
+			return err
+		}
+
+		for _, table := range tableList {
+			tableName := table.TableName
+			InitTable(table, operName)
+			result, err := tx.Table(gen_table.Table).Insert(table)
+			if err != nil {
+				return err
+			}
+
+			tmpid, err := result.LastInsertId()
+
+			if err != nil || tmpid <= 0 {
+				tx.Rollback()
+				return gerror.New("保存数据失败")
+			}
+
+			table.TableId = tmpid
+
+			// 保存列信息
+			genTableColumns, err := gen_table_column.SelectDbTableColumnsByName(tableName)
+
+			if err != nil || len(genTableColumns) <= 0 {
+				tx.Rollback()
+				return gerror.New("获取列数据失败")
+			}
+
+			for _, column := range genTableColumns {
+				InitColumnField(column, table)
+				_, err = tx.Table("gen_table_column").Insert(column)
+				if err != nil {
+					tx.Rollback()
+					return gerror.New("保存列数据失败")
+				}
+			}
+		}
+		return tx.Commit()
+	} else {
+		return gerror.New("参数错误")
+	}
+}
+
+//获取数据库类型字段
+func GetDbType(columnType string) string {
+	if strings.Index(columnType, "(") > 0 {
+		return columnType[0:strings.Index(columnType, "(")]
+	} else {
+		return columnType
+	}
+}
+
+//将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
+func ConvertToCamelCase(name string) string {
+	if name == "" {
+		return ""
+	} else if !strings.Contains(name, "_") {
+		// 不含下划线,仅将首字母大写
+		return strings.ToUpper(name[0:1]) + name[1:len(name)]
+	}
+	var result string = ""
+	camels := strings.Split(name, "_")
+	for index := range camels {
+		if camels[index] == "" {
+			continue
+		}
+		camel := camels[index]
+		result = result + strings.ToUpper(camel[0:1]) + strings.ToLower(camel[1:len(camel)])
+	}
+	return result
+}
+
+////将下划线大写方式命名的字符串转换为驼峰式,首字母小写。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->helloWorld
+func ConvertToCamelCase1(name string) string {
+	if name == "" {
+		return ""
+	} else if !strings.Contains(name, "_") {
+		// 不含下划线,原值返回
+		return name
+	}
+	var result string = ""
+	camels := strings.Split(name, "_")
+	for index := range camels {
+		if camels[index] == "" {
+			continue
+		}
+		camel := camels[index]
+		if result == "" {
+			result = strings.ToLower(camel[0:1]) + strings.ToLower(camel[1:len(camel)])
+		} else {
+			result = result + strings.ToUpper(camel[0:1]) + strings.ToLower(camel[1:len(camel)])
+		}
+	}
+	return result
+}
+
+//获取字段长度
+func GetColumnLength(columnType string) int {
+	start := strings.Index(columnType, "(")
+	end := strings.Index(columnType, ")")
+	result := ""
+	if start >= 0 && end >= 0 {
+		result = columnType[start+1 : end-1]
+	}
+	return gconv.Int(result)
+}
+
+//初始化列属性字段
+func InitColumnField(column *gen_table_column.Entity, table *gen_table.Entity) {
+	dataType := GetDbType(column.ColumnType)
+	columnName := column.ColumnName
+	column.TableId = table.TableId
+	column.CreateBy = table.CreateBy
+	//设置字段名
+	column.GoField = ConvertToCamelCase(columnName)
+	column.HtmlField = ConvertToCamelCase1(columnName)
+
+	if gen_table_column.IsStringObject(dataType) {
+		//字段为字符串类型
+		column.GoType = "string"
+		columnLength := GetColumnLength(column.ColumnType)
+		if columnLength >= 500 {
+			column.HtmlType = "textarea"
+		} else {
+			column.HtmlType = "input"
+		}
+	} else if gen_table_column.IsTimeObject(dataType) {
+		//字段为时间类型
+		column.GoType = "Time"
+		column.HtmlType = "datatime"
+	} else if gen_table_column.IsNumberObject(dataType) {
+		//字段为数字类型
+		column.HtmlType = "input"
+		// 如果是浮点型
+		tmp := column.ColumnType
+		start := strings.Index(tmp, "(")
+		end := strings.Index(tmp, ")")
+		result := "0"
+		if start > 0 && end > 0 {
+			result = tmp[start+1 : end]
+		}
+		arr := strings.Split(result, ",")
+		if len(arr) == 2 && gconv.Int(arr[1]) > 0 {
+			column.GoType = "float64"
+		} else if len(arr) == 1 && gconv.Int(arr[0]) <= 10 {
+			column.GoType = "int"
+		} else {
+			column.GoType = "int64"
+		}
+	}
+	//新增字段
+	if columnName == "create_by" || columnName == "create_time" || columnName == "update_by" || columnName == "update_time" {
+		column.IsRequired = "0"
+		column.IsInsert = "0"
+	} else {
+		column.IsRequired = "0"
+		column.IsInsert = "1"
+		if strings.Index(columnName, "name") >= 0 || strings.Index(columnName, "status") >= 0 {
+			column.IsRequired = "1"
+		}
+	}
+
+	// 编辑字段
+	if gen_table_column.IsNotEdit(columnName) {
+		if column.IsPk == "1" {
+			column.IsEdit = "0"
+		} else {
+			column.IsEdit = "1"
+		}
+	} else {
+		column.IsEdit = "0"
+	}
+	// 列表字段
+	if gen_table_column.IsNotList(columnName) {
+		column.IsList = "1"
+	} else {
+		column.IsList = "0"
+	}
+	// 查询字段
+	if gen_table_column.IsNotQuery(columnName) {
+		column.IsQuery = "1"
+	} else {
+		column.IsQuery = "0"
+	}
+
+	// 查询字段类型
+	if CheckNameColumn(columnName) {
+		column.QueryType = "LIKE"
+	} else {
+		column.QueryType = "EQ"
+	}
+
+	// 状态字段设置单选框
+	if CheckStatusColumn(columnName) {
+		column.HtmlType = "radio"
+	} else if CheckTypeColumn(columnName) || CheckSexColumn(columnName) {
+		// 类型&性别字段设置下拉框
+		column.HtmlType = "select"
+	}
+}
+
+//检查字段名后3位是否是sex
+func CheckSexColumn(columnName string) bool {
+	if len(columnName) >= 3 {
+		end := len(columnName)
+		start := end - 3
+
+		if start <= 0 {
+			start = 0
+		}
+
+		if columnName[start:end] == "sex" {
+			return true
+		}
+	}
+	return false
+}
+
+//检查字段名后4位是否是type
+func CheckTypeColumn(columnName string) bool {
+	if len(columnName) >= 4 {
+		end := len(columnName)
+		start := end - 4
+
+		if start <= 0 {
+			start = 0
+		}
+
+		if columnName[start:end] == "type" {
+			return true
+		}
+	}
+	return false
+}
+
+//检查字段名后6位是否是status
+func CheckStatusColumn(columnName string) bool {
+	if len(columnName) >= 6 {
+		end := len(columnName)
+		start := end - 6
+
+		if start <= 0 {
+			start = 0
+		}
+		tmp := columnName[start:end]
+
+		if tmp == "status" {
+			return true
+		}
+	}
+
+	return false
+}
+
+//检查字段名后4位是否是name
+func CheckNameColumn(columnName string) bool {
+	if len(columnName) >= 4 {
+		end := len(columnName)
+		start := end - 4
+
+		if start <= 0 {
+			start = 0
+		}
+
+		tmp := columnName[start:end]
+
+		if tmp == "name" {
+			return true
+		}
+	}
+	return false
+}
+
+//初始化表信息
+func InitTable(table *gen_table.Entity, operName string) {
+	table.ClassName = ConvertClassName(table.TableName)
+	table.PackageName = g.Cfg().GetString("gen.packageName")
+	table.ModuleName = g.Cfg().GetString("gen.moduleName")
+	table.BusinessName = GetBusinessName(table.TableName)
+	table.FunctionName = strings.ReplaceAll(table.TableComment, "表", "")
+	table.FunctionAuthor = g.Cfg().GetString("gen.author")
+	table.CreateBy = operName
+	table.TplCategory = "crud"
+	table.CreateTime = gtime.Now()
+}
+
+//表名转换成类名
+func ConvertClassName(tableName string) string {
+	autoRemovePre := g.Cfg().GetBool("gen.autoRemovePre")
+	tablePrefix := g.Cfg().GetString("gen.tablePrefix")
+	if autoRemovePre && tablePrefix != "" {
+		searchList := strings.Split(tablePrefix, ",")
+		for _, str := range searchList {
+			tableName = strings.ReplaceAll(tableName, str, "")
+		}
+	}
+	return tableName
+}
+
+//获取业务名
+func GetBusinessName(tableName string) string {
+	lastIndex := strings.LastIndex(tableName, "_")
+	nameLength := len(tableName)
+	businessName := tableName[lastIndex+1 : nameLength]
+	return businessName
+}
+
+//根据table_id查询表列数据
+func SelectGenTableColumnListByTableId(tableId int64) ([]*gen_table_column.Entity, error) {
+	return gen_table_column.SelectGenTableColumnListByTableId(tableId)
+}
+
+func GetTableInfoByTableId(tableId int64) (info *gen_table.Entity, err error) {
+	return gen_table.GetInfoById(tableId)
+}
+
+//修改表和列信息
+func SaveEdit(req *gen_table.EditReq) (err error) {
+	if req == nil {
+		err = gerror.New("参数错误")
+		return
+	}
+	table, err := gen_table.FindOne("table_id=?", req.TableId)
+	if err != nil || table == nil {
+		err = gerror.New("数据不存在")
+		return
+	}
+	if req.TableName != "" {
+		table.TableName = req.TableName
+	}
+	if req.TableComment != "" {
+		table.TableComment = req.TableComment
+	}
+	if req.BusinessName != "" {
+		table.BusinessName = req.BusinessName
+	}
+	if req.ClassName != "" {
+		table.ClassName = req.ClassName
+	}
+	if req.FunctionAuthor != "" {
+		table.FunctionAuthor = req.FunctionAuthor
+	}
+	if req.FunctionName != "" {
+		table.FunctionName = req.FunctionName
+	}
+	if req.ModuleName != "" {
+		table.ModuleName = req.ModuleName
+	}
+	if req.PackageName != "" {
+		table.PackageName = req.PackageName
+	}
+	if req.Remark != "" {
+		table.Remark = req.Remark
+	}
+	if req.TplCategory != "" {
+		table.TplCategory = req.TplCategory
+	}
+	if req.Params != "" {
+		table.Options = req.Params
+	}
+	table.UpdateTime = gtime.Now()
+	table.UpdateBy = req.UserName
+	if req.TplCategory == "tree" {
+		//树表设置options
+		options := g.Map{
+			"tree_code":        req.TreeCode,
+			"tree_parent_code": req.TreeParentCode,
+			"tree_name":        req.TreeName,
+		}
+		table.Options = gconv.String(options)
+	} else {
+		table.Options = ""
+	}
+
+	var tx *gdb.TX
+	tx, err = g.DB().Begin()
+	if err != nil {
+		return
+	}
+	_, err = tx.Table(gen_table.Table).Save(table)
+	if err != nil {
+		tx.Rollback()
+		return err
+	}
+
+	//保存列数据
+	if req.Columns != "" {
+		var j *gjson.Json
+		if j, err = gjson.DecodeToJson([]byte(req.Columns)); err != nil {
+			tx.Rollback()
+			return
+		} else {
+			var columnList []gen_table_column.Entity
+			err = j.ToStructs(&columnList)
+			if err == nil && columnList != nil && len(columnList) > 0 {
+				for _, column := range columnList {
+					if column.ColumnId > 0 {
+						tmp, _ := gen_table_column.FindOne("column_id=?", column.ColumnId)
+						if tmp != nil {
+							tmp.ColumnComment = column.ColumnComment
+							tmp.GoType = column.GoType
+							tmp.HtmlType = column.HtmlType
+							tmp.QueryType = column.QueryType
+							tmp.GoField = column.GoField
+							tmp.DictType = column.DictType
+							tmp.IsInsert = column.IsInsert
+							tmp.IsEdit = column.IsEdit
+							tmp.IsList = column.IsList
+							tmp.IsQuery = column.IsQuery
+							_, err = tx.Table(gen_table_column.Table).Save(tmp)
+							if err != nil {
+								tx.Rollback()
+								return
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+	tx.Commit()
+	return
+}
+
+//删除表格
+func Delete(ids []int) error {
+	tx, err := g.DB().Begin()
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("开启删除事务出错")
+	}
+	_, err = tx.Table(gen_table.Table).Where(gen_table.Columns.TableId+" in(?)", ids).Delete()
+	if err != nil {
+		g.Log().Error(err)
+		tx.Rollback()
+		return gerror.New("删除表格数据失败")
+	}
+	_, err = tx.Table(gen_table_column.Table).Where(gen_table_column.Columns.TableId+" in(?)", ids).Delete()
+	if err != nil {
+		g.Log().Error(err)
+		tx.Rollback()
+		return gerror.New("删除表格字段数据失败")
+	}
+	tx.Commit()
+	return nil
+}
+
+func SelectRecordById(tableId int64) (entity *gen_table.EntityExtend, err error) {
+	entity, err = gen_table.SelectRecordById(tableId)
+	return
+}
+
+//设置主键列信息
+func SetPkColumn(table *gen_table.EntityExtend, columns []*gen_table_column.Entity) {
+	for _, column := range columns {
+		if column.IsPk == "1" {
+			table.PkColumn = column
+			break
+		}
+	}
+	if table.PkColumn == nil {
+		table.PkColumn = columns[0]
+	}
+}

+ 32 - 0
app/service/admin/post_service/post.go

@@ -0,0 +1,32 @@
+package post_service
+
+import (
+	"database/sql"
+	"gfast/app/model/admin/sys_post"
+	"github.com/gogf/gf/database/gdb"
+)
+
+func List(req *sys_post.SearchParams) (total, page int, list gdb.Result, err error) {
+	return sys_post.List(req)
+}
+
+//获取正常状态的岗位
+func GetUsedPost() (list []*sys_post.Entity, err error) {
+	return sys_post.GetUsedPost()
+}
+
+func Add(addParams *sys_post.AddParams) (result sql.Result, err error) {
+	return sys_post.Add(addParams)
+}
+
+func Edit(editParams *sys_post.EditParams) (result sql.Result, err error) {
+	return sys_post.Edit(editParams)
+}
+
+func GetOneById(id int64) (*sys_post.Entity, error) {
+	return sys_post.GetOneById(id)
+}
+
+func Delete(ids []int) error {
+	return sys_post.DeleteByIds(ids)
+}

+ 2 - 1
app/service/admin/upload_service/upload.go

@@ -70,6 +70,7 @@ func upByType(file *ghttp.UploadFile, fType string) (fileInfo *FileInfo, err err
 	if err != nil {
 		return
 	}
+
 	//检测文件类型
 	rightType := checkFileType(file.Filename, config.ConfigValue)
 	if !rightType {
@@ -206,7 +207,7 @@ func getUpConfig(key string) (config *sys_config.Entity, err error) {
 
 //判断上传文件类型是否合法
 func checkFileType(fileName, typeString string) bool {
-	suffix := gstr.SubStr(fileName, gstr.SearchArray(gstr.Split(fileName, ""), ".")+1)
+	suffix := gstr.SubStrRune(fileName, gstr.PosRRune(fileName, ".")+1, gstr.LenRune(fileName)-1)
 	imageType := gstr.Split(typeString, ",")
 	rightType := false
 	for _, v := range imageType {

+ 168 - 6
app/service/admin/user_service/user.go

@@ -1,20 +1,113 @@
 package user_service
 
 import (
+	"database/sql"
+	"errors"
 	"fmt"
+	"gfast/app/model/admin/auth_rule"
 	"gfast/app/model/admin/role"
+	"gfast/app/model/admin/sys_dept"
+	"gfast/app/model/admin/sys_post"
 	"gfast/app/model/admin/user"
+	"gfast/app/model/admin/user_post"
 	"gfast/app/service/admin/auth_service"
 	"gfast/app/service/casbin_adapter_service"
 	"gfast/boot"
 	"gfast/library/service"
 	"gfast/library/utils"
+	"github.com/gogf/gf/errors/gerror"
 	"github.com/gogf/gf/frame/g"
 	"github.com/gogf/gf/net/ghttp"
 	"github.com/gogf/gf/text/gstr"
 	"github.com/gogf/gf/util/gconv"
 )
 
+type EditParams struct {
+	Id           int    `p:"id" v:"required#用户id不能为空"`
+	UserNickname string `p:"user_nickname" v:"required#用户昵称不能为空" orm:"user_nickname"` // 用户昵称
+	Mobile       string `p:"mobile" v:"required|phone#手机号不能为空|手机号格式错误" orm:"mobile,unique"`
+	UserEmail    string `p:"user_email" v:"email#邮箱格式错误" orm:"user_email"`
+	Sex          int    `p:"sex" orm:"sex"`
+}
+
+type UpdatePwdReq struct {
+	OldPassword string `p:"oldPassword" v:"required#旧密码不能为空"`
+	NewPassword string `p:"newPassword" v:"required#新密码不能为空"`
+}
+
+/**
+修改密码
+*/
+func UpdatePwd(r *ghttp.Request, data *UpdatePwdReq) error {
+
+	currentUser, err := GetCurrentUserInfo(r)
+
+	if err != nil {
+		return err
+	}
+
+	OldPassword := utils.EncryptCBC(gconv.String(data.OldPassword), utils.AdminCbcPublicKey)
+
+	if OldPassword != currentUser["user_password"].(string) {
+		return errors.New("原始密码错误!")
+	}
+
+	return ResetUserPwd(&user.ResetPwdReq{
+		Id:       currentUser["id"].(int),
+		Password: data.NewPassword,
+	})
+}
+
+/**
+用户中心修改用户信息
+*/
+func Edit(info *EditParams) (sql.Result, error) {
+	return user.Model.Where("id", info.Id).Data(info).Update()
+}
+
+// 获取单前登录用户的信息
+func GetCurrentUserInfo(r *ghttp.Request) (map[string]interface{}, error) {
+	id := GetLoginID(r)
+	userEntity, err := user.GetUserById(id)
+	if err != nil {
+		return nil, err
+	}
+	userInfo := gconv.Map(userEntity)
+	//delete(userInfo, "user_password")
+	userInfo["roles"] = make([]string, 0)
+	userInfo["posts"] = new([]*user_post.Entity)
+	userInfo["dept_info"] = nil
+	allRoles, err := auth_service.GetRoleList()
+	if err != nil {
+		return nil, err
+	}
+	roles, err := GetAdminRole(userEntity.Id, allRoles)
+	if err != nil {
+		return nil, err
+	}
+	//角色
+	userInfo["roles"] = roles
+	//岗位
+	posts, err := GetPostsByUserId(userEntity.Id)
+	if err != nil {
+		return nil, err
+	}
+	userInfo["posts"] = posts
+	//部门
+	if dept_info, err := sys_dept.GetDeptById(userEntity.DeptId); err != nil {
+		return nil, err
+	} else {
+		userInfo["dept_info"] = dept_info
+	}
+
+	return userInfo, nil
+
+}
+
+func GetPostsByUserId(id int) ([]*sys_post.Entity, error) {
+	return user_post.GetPostsByUserId(id)
+}
+
 //获取登陆用户ID
 func GetLoginID(r *ghttp.Request) (userId int) {
 	userInfo := GetLoginAdminInfo(r)
@@ -31,9 +124,35 @@ func GetLoginAdminInfo(r *ghttp.Request) (userInfo *user.Entity) {
 	return
 }
 
+//获取当前登录用户信息,直接从数据库获取
+func GetCurrentUser(r *ghttp.Request) (userInfo *user.Entity, err error) {
+	id := GetLoginID(r)
+	userInfo, err = user.GetUserById(id)
+	return
+}
+
 //获取管理员列表
-func GetAdminList(where g.Map, page int) (total int, userList []*user.Entity, err error) {
-	return user.GetAdminList(where, page, service.AdminPageNum)
+func GetAdminList(req *user.SearchReq) (total, page int, userList []*user.Entity, err error) {
+	if req.PageSize == 0 {
+		req.PageSize = service.AdminPageNum
+	}
+	var depts []*sys_dept.Dept
+	if req.DeptId != "" {
+		depts, err = sys_dept.GetList(&sys_dept.SearchParams{Status: "1"})
+		if err != nil {
+			g.Log().Debug(err)
+			err = gerror.New("获取部门信息失败")
+			return
+		}
+		mDepts := gconv.SliceMap(depts)
+		deptId := gconv.Int(req.DeptId)
+		req.DeptIds = append(req.DeptIds, deptId)
+		childrenIds := utils.FindSonByParentId(mDepts, deptId, "parentId", "deptId")
+		for _, d := range childrenIds {
+			req.DeptIds = append(req.DeptIds, gconv.Int(d["deptId"]))
+		}
+	}
+	return user.GetAdminList(req)
 }
 
 //获取管理员的角色信息
@@ -72,6 +191,10 @@ func GetAdminRoleIds(userId int) (roleIds []int, err error) {
 	return
 }
 
+func GetAdminPosts(userId int) (postIds []int64, err error) {
+	return user_post.GetAdminPosts(userId)
+}
+
 //获取菜单
 func GetAllMenus() (menus g.List, err error) {
 	//获取所有开启的菜单
@@ -82,10 +205,10 @@ func GetAllMenus() (menus g.List, err error) {
 	menus = make(g.List, len(allMenus))
 	for k, v := range allMenus {
 		menu := gconv.Map(v)
-		menu["index"] = v.Name
+		menu = setMenuMap(menu, v)
 		menus[k] = menu
 	}
-	menus = utils.PushSonToParent(menus, 0, "pid", "id", "subs", "", nil, false)
+	menus = utils.PushSonToParent(menus, 0, "pid", "id", "children", "", nil, true)
 	return
 }
 
@@ -115,10 +238,49 @@ func GetAdminMenusByRoleIds(roleIds []int) (menus g.List, err error) {
 	for _, v := range allMenus {
 		if _, ok := menuIds[gconv.Int64(v.Id)]; gstr.Equal(v.Condition, "nocheck") || ok {
 			roleMenu := gconv.Map(v)
-			roleMenu["index"] = v.Name
+			roleMenu = setMenuMap(roleMenu, v)
 			roleMenus = append(roleMenus, roleMenu)
 		}
 	}
-	menus = utils.PushSonToParent(roleMenus, 0, "pid", "id", "subs", "", nil, false)
+	menus = utils.PushSonToParent(roleMenus, 0, "pid", "id", "children", "", nil, true)
 	return
 }
+
+//组合返回menu前端数据
+func setMenuMap(menu g.Map, entity *auth_rule.Entity) g.Map {
+	menu["index"] = entity.Name
+	menu["name"] = gstr.UcFirst(entity.Path)
+	menu["menuName"] = entity.Title
+	if entity.MenuType != 0 {
+		menu["component"] = entity.Name
+		menu["path"] = entity.Path
+	} else {
+		menu["path"] = "/" + entity.Path
+		menu["component"] = "Layout"
+	}
+	menu["meta"] = g.MapStrStr{
+		"icon":  entity.Icon,
+		"title": entity.Title,
+	}
+	if entity.AlwaysShow == 1 {
+		menu["hidden"] = false
+	} else {
+		menu["hidden"] = true
+	}
+	if entity.AlwaysShow == 1 && entity.MenuType == 0 {
+		menu["alwaysShow"] = true
+	} else {
+		menu["alwaysShow"] = false
+	}
+	return menu
+}
+
+func ChangeUserStatus(req *user.StatusReq) error {
+	return user.ChangeUserStatus(req)
+}
+
+func ResetUserPwd(req *user.ResetPwdReq) error {
+	//密码加密
+	req.Password = utils.EncryptCBC(gconv.String(req.Password), utils.AdminCbcPublicKey)
+	return user.ResetUserPwd(req)
+}

+ 1 - 0
app/service/cache_service/cache_values.go

@@ -5,6 +5,7 @@ const (
 	AdminAuthMenu = iota
 	AdminAuthRole
 	AdminCmsMenu
+	AdminConfigDict
 )
 
 //缓存TAG标签

+ 20 - 2
boot/boot.go

@@ -1,6 +1,7 @@
 package boot
 
 import (
+	"fmt"
 	"gfast/library/service"
 	"github.com/goflyfox/gtoken/gtoken"
 	"github.com/gogf/gf/frame/g"
@@ -10,12 +11,14 @@ import (
 var AdminGfToken *gtoken.GfToken
 
 func init() {
+	showLogo()
 	g.Log().SetFlags(glog.F_ASYNC | glog.F_TIME_DATE | glog.F_TIME_TIME | glog.F_FILE_LONG)
-	g.Server().SetPort(8200)
+	//g.Server().SetPort(8200)
 	g.Server().AddStaticPath("/public", g.Cfg().GetString("server.ServerRoot"))
 	//后台初始化配置
 	initAdmin()
-
+	//前台初始化
+	initFront()
 }
 
 func initAdmin() {
@@ -27,6 +30,17 @@ func initAdmin() {
 	initAdminGfToken()
 }
 
+func initFront() {
+	gtoken := &gtoken.GfToken{
+		LoginPath:       "/front/login",
+		LoginBeforeFunc: service.FrontLogin,
+		LogoutPath:      "/front/logout",
+		AuthPaths:       g.SliceStr{"/front/*"},
+		AuthAfterFunc:   service.AuthAfterFunc,
+	}
+	gtoken.Start()
+}
+
 func initAdminGfToken() {
 	//多端登陆配置
 	service.AdminMultiLogin = g.Cfg().GetBool("gToken.MultiLogin")
@@ -49,3 +63,7 @@ func initAdminGfToken() {
 	}
 	AdminGfToken.Start()
 }
+
+func showLogo() {
+	fmt.Println(" .----------------.  .----------------.  .----------------.  .----------------.  .----------------. \n| .--------------. || .--------------. || .--------------. || .--------------. || .--------------. |\n| |    ______    | || |  _________   | || |      __      | || |    _______   | || |  _________   | |\n| |  .' ___  |   | || | |_   ___  |  | || |     /  \\     | || |   /  ___  |  | || | |  _   _  |  | |\n| | / .'   \\_|   | || |   | |_  \\_|  | || |    / /\\ \\    | || |  |  (__ \\_|  | || | |_/ | | \\_|  | |\n| | | |    ____  | || |   |  _|      | || |   / ____ \\   | || |   '.___`-.   | || |     | |      | |\n| | \\ `.___]  _| | || |  _| |_       | || | _/ /    \\ \\_ | || |  |`\\____) |  | || |    _| |_     | |\n| |  `._____.'   | || | |_____|      | || ||____|  |____|| || |  |_______.'  | || |   |_____|    | |\n| |              | || |              | || |              | || |              | || |              | |\n| '--------------' || '--------------' || '--------------' || '--------------' || '--------------' |\n '----------------'  '----------------'  '----------------'  '----------------'  '----------------' ")
+}

+ 15 - 6
config/config.toml

@@ -1,6 +1,6 @@
 # 数据库连接
 [database]
-    link = "mysql:root:123456@tcp(127.0.0.1:3306)/gfast"
+    link = "mysql:root:123456@tcp(127.0.0.1:3306)/gfast_open"
     charset   = "utf8mb4" #数据库编码
     maxIdle      = "10" #连接池最大闲置的连接数
     maxOpen     = "10" #连接池最大打开的连接数
@@ -9,7 +9,7 @@
 
 #web服务器配置
 [server]
-    Address          = ":8080"
+    Address          = ":8200"
     ServerRoot       = "./public/resource"
     AccessLogEnabled = true
     ErrorLogEnabled  = true
@@ -19,6 +19,7 @@
     SessionPath      = "./data/session"
     SessionMaxAge    = "24h"
     DumpRouterMap    = true
+    NameToUriType = 3
 
 
 # Redis数据库配置
@@ -44,10 +45,18 @@
 
 #casbin配置
 [casbin]
-modelFile="./config/casbin_conf/rbac_model.conf"
-policyFile="./config/casbin_conf/rbac_policy.csv"
+    modelFile="./config/casbin_conf/rbac_model.conf"
+    policyFile="./config/casbin_conf/rbac_policy.csv"
 
 #后台相关配置
 [adminInfo]
-notCheckAuthAdminIds = [1,2,31]  #无需验证后台权限的用户id
-pageNum = 5  #后台列表分页长度
+    notCheckAuthAdminIds = [1,31]  #无需验证后台权限的用户id
+    pageNum = 5  #后台列表分页长度
+
+# Gen
+[gen]
+    author        = "gfast"
+    moduleName    = "module"
+    packageName   = "gfast"
+    autoRemovePre = true
+    tablePrefix   = "t_,sys_"

文件差异内容过多而无法显示
+ 6 - 4
data/db.sql


+ 2 - 2
go.mod

@@ -4,8 +4,8 @@ require (
 	github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
 	github.com/casbin/casbin/v2 v2.1.2
 	github.com/go-ole/go-ole v1.2.4 // indirect
-	github.com/goflyfox/gtoken v1.3.14
-	github.com/gogf/gf v1.11.7
+	github.com/goflyfox/gtoken v1.3.17
+	github.com/gogf/gf v1.13.1
 	github.com/mojocn/base64Captcha v1.3.0
 	github.com/mssola/user_agent v0.5.1
 	github.com/shirou/gopsutil v2.20.2+incompatible

+ 13 - 0
go.sum

@@ -26,10 +26,15 @@ github.com/goflyfox/gtoken v1.3.12 h1:ewet3ZzkfBIuOKkJ2T9uErheDAu/TxnyrmMmEaof2F
 github.com/goflyfox/gtoken v1.3.12/go.mod h1:KPGDYrhvNzcfqFJz4/rE6x0SyURAuAxfRNhwMxGbFxk=
 github.com/goflyfox/gtoken v1.3.14 h1:nQZDLbkQ/O0jAgAsP83jz+cofkuSDHWGha41p77LYEM=
 github.com/goflyfox/gtoken v1.3.14/go.mod h1:Tr2qiuVA9dnOPfLzTLch/QGuaonSKcoVrHxY0T4Tvmc=
+github.com/goflyfox/gtoken v1.3.17 h1:/HgPG7iArkJMn8SVXcDya5+6xXvWJEpR0bxnjigq2u8=
+github.com/goflyfox/gtoken v1.3.17/go.mod h1:a9Q08qaHzoS+ko/AFrCBnq4KCesnRFZ/3eLIiERRhtU=
 github.com/gogf/gf v1.11.5 h1:e6HB9x1QZ6EFD3eEWXDCsFeVs7KxNtmWQRVNh2c0+bQ=
 github.com/gogf/gf v1.11.5/go.mod h1:iuHZkqyEfxFtpwRYboAU7409O/sfdy79YTpY8si332I=
 github.com/gogf/gf v1.11.7 h1:rHt9g7OP3NPkkgQpN73zA9TJ4ItlQGworY1Jxb6mgQE=
 github.com/gogf/gf v1.11.7/go.mod h1:q6WSyX5jyJbUki7l66lpfsXvf2GeDEOgXNRz9Nb61qo=
+github.com/gogf/gf v1.12.1/go.mod h1:5ItmC5B/St8P4hp0/waKmnvHwAfAJ1uspMvR2wUD4UA=
+github.com/gogf/gf v1.13.1 h1:jwIUJ3rqhHkOBfdS9FfZzcW/cqlokSyTT/6u3E/x8TU=
+github.com/gogf/gf v1.13.1/go.mod h1:Ho7d+9F8dHe5LpEnIH+bky0aCtjwc8Gm82rUiCYnk/k=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -39,10 +44,14 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
 github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gqcn/structs v1.1.1 h1:cyzGRwfmn3d1d54fwW3KUNyG9QxR0ldIeqwFGeBt638=
+github.com/gqcn/structs v1.1.1/go.mod h1:/aBhTBSsKQ2Ec9pbnYdGphtdWXHFn4KrCL0fXM/Adok=
 github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf h1:wIOAyJMMen0ELGiFzlmqxdcV1yGbkyHBAB6PolcNbLA=
 github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
 github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
 github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mojocn/base64Captcha v1.3.0 h1:2mWu9fUoOx3ribrrsm4+8/UknSn8/g/xmPOkTwiY2Fo=
 github.com/mojocn/base64Captcha v1.3.0/go.mod h1:wAQCKEc5bDujxKRmbT6/vTnTt5CjStQ8bRfPWUuz/iY=
 github.com/mssola/user_agent v0.5.1 h1:sJUCUozh+j7c0dR2zMIUX5aJjoY/TNo/gXiNujoH5oY=
@@ -63,6 +72,8 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e h1:9vRrk9YW2BTzLP0VCB9ZDjU4cPqkg+IDWL7XgxA1yxQ=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -73,3 +84,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 2 - 1
hook/hook.go

@@ -24,8 +24,9 @@ func OperationLog(r *ghttp.Request) {
 		return
 	}
 	var menu *auth_rule.Entity
+	path := gstr.TrimLeft(url.Path, "/")
 	for _, m := range menuList {
-		if gstr.Equal(m.Name, url.Path) {
+		if gstr.Equal(m.Name, path) {
 			menu = m
 			break
 		}

+ 13 - 2
library/service/service.go

@@ -66,8 +66,14 @@ func VerifyString(id, answer string) bool {
 	return c.Verify(id, answer, true)
 }
 
+func FrontLogin(r *ghttp.Request) (string, interface{}) {
+	g.Log().Println("front login test...")
+	return "test", nil
+}
+
 //AdminLogin 后台用户登陆验证
 func AdminLogin(r *ghttp.Request) (string, interface{}) {
+
 	data := r.GetFormMapStrStr()
 	rules := map[string]string{
 		"idValueC": "required",
@@ -79,13 +85,14 @@ func AdminLogin(r *ghttp.Request) (string, interface{}) {
 		"username": "账号不能为空",
 		"password": "密码不能为空",
 	}
+
 	if e := gvalid.CheckMap(data, rules, msgs); e != nil {
 		response.JsonExit(r, response.ErrorCode, e.String())
 	}
 	//判断验证码是否正确
-	/*if !VerifyString(data["idKeyC"], data["idValueC"]) {
+	if !VerifyString(data["idKeyC"], data["idValueC"]) {
 		response.JsonExit(r, response.ErrorCode, "验证码输入错误")
-	}*/
+	}
 	password := utils.EncryptCBC(data["password"], utils.AdminCbcPublicKey)
 	var keys string
 	if AdminMultiLogin {
@@ -99,6 +106,10 @@ func AdminLogin(r *ghttp.Request) (string, interface{}) {
 		go loginLog(0, data["username"], ip, userAgent, err.Error())
 		response.JsonExit(r, response.ErrorCode, err.Error())
 	} else {
+		//判断是否后台用户
+		if user.IsAdmin != 1 {
+			response.JsonExit(r, response.ErrorCode, "抱歉!此用户不属于后台管理员!")
+		}
 		r.SetParam("userInfo", user)
 		go loginLog(1, data["username"], ip, userAgent, "登录成功")
 		return keys, user

+ 35 - 31
middleWare/middleware.go

@@ -21,6 +21,9 @@ func CORS(r *ghttp.Request) {
 
 //权限判断处理中间件
 func Auth(r *ghttp.Request) {
+	if r.Method != "GET" {
+		response.FailJson(true, r, "演示系统禁止操作")
+	}
 	//获取登陆用户id
 	adminId := user_service.GetLoginID(r)
 	//获取无需验证权限的用户id
@@ -30,51 +33,52 @@ func Auth(r *ghttp.Request) {
 			return
 		}
 	}
-	url := r.Request.URL
+	url := gstr.TrimLeft(r.Request.URL.Path, "/")
 	//获取地址对应的菜单id
 	menuList, err := auth_service.GetMenuIsStatusList()
+
 	if err != nil {
 		g.Log().Error(err)
 		response.FailJson(true, r, "请求数据失败")
 	}
 	var menu *auth_rule.Entity
 	for _, m := range menuList {
-		if gstr.Equal(m.Name, url.Path) {
+		if gstr.Equal(m.Name, url) {
 			menu = m
 			break
 		}
 	}
-	if menu == nil {
-		response.FailJson(true, r, "没有访问权限")
-	}
-	//若存在不需要验证的条件则跳过
-	if gstr.Equal(menu.Condition, "nocheck") {
-		r.Middleware.Next()
-		return
-	}
-	menuId := menu.Id
-	//菜单没存数据库不验证权限
-	if menuId != 0 {
-		//判断权限操作
-		enforcer, err := casbin_adapter_service.GetEnforcer()
-		if err != nil {
-			g.Log().Error(err)
-			response.FailJson(true, r, "获取权限失败")
-		}
-		groupPolicy := enforcer.GetFilteredGroupingPolicy(0,
-			fmt.Sprintf("u_%d", adminId))
-		if len(groupPolicy) == 0 {
-			response.FailJson(true, r, "没有访问权限")
+	//只验证存在数据库中的规则
+	if menu != nil {
+		//若存在不需要验证的条件则跳过
+		if gstr.Equal(menu.Condition, "nocheck") {
+			r.Middleware.Next()
+			return
 		}
-		hasAccess := false
-		for _, v := range groupPolicy {
-			if enforcer.HasPolicy(v[1], fmt.Sprintf("r_%d", menuId), "All") {
-				hasAccess = true
-				break
+		menuId := menu.Id
+		//菜单没存数据库不验证权限
+		if menuId != 0 {
+			//判断权限操作
+			enforcer, err := casbin_adapter_service.GetEnforcer()
+			if err != nil {
+				g.Log().Error(err)
+				response.FailJson(true, r, "获取权限失败")
+			}
+			groupPolicy := enforcer.GetFilteredGroupingPolicy(0,
+				fmt.Sprintf("u_%d", adminId))
+			if len(groupPolicy) == 0 {
+				response.FailJson(true, r, "没有访问权限")
+			}
+			hasAccess := false
+			for _, v := range groupPolicy {
+				if enforcer.HasPolicy(v[1], fmt.Sprintf("r_%d", menuId), "All") {
+					hasAccess = true
+					break
+				}
+			}
+			if !hasAccess {
+				response.FailJson(true, r, "没有访问权限")
 			}
-		}
-		if !hasAccess {
-			response.FailJson(true, r, "没有访问权限")
 		}
 	}
 	r.Middleware.Next()

二进制
public/resource/favicon.ico


文件差异内容过多而无法显示
+ 0 - 0
public/resource/index.html


+ 0 - 1
public/resource/static/css/403.c0a72452.css

@@ -1 +0,0 @@
-.error-page[data-v-0ef0d1b0]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%;height:100%;background:#f3f3f3;-webkit-box-sizing:border-box;box-sizing:border-box}.error-code[data-v-0ef0d1b0]{line-height:1;font-size:250px;font-weight:bolder;color:#f02d2d}.error-code span[data-v-0ef0d1b0]{color:#00a854}.error-desc[data-v-0ef0d1b0]{font-size:30px;color:#777}.error-handle[data-v-0ef0d1b0]{margin-top:30px;padding-bottom:200px}.error-btn[data-v-0ef0d1b0]{margin-left:100px}

+ 0 - 1
public/resource/static/css/404.1ecdb1c9.css

@@ -1 +0,0 @@
-.error-page[data-v-226a8a0f]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%;height:100%;background:#f3f3f3;-webkit-box-sizing:border-box;box-sizing:border-box}.error-code[data-v-226a8a0f]{line-height:1;font-size:250px;font-weight:bolder;color:#2d8cf0}.error-code span[data-v-226a8a0f]{color:#00a854}.error-desc[data-v-226a8a0f]{font-size:30px;color:#777}.error-handle[data-v-226a8a0f]{margin-top:30px;padding-bottom:200px}.error-btn[data-v-226a8a0f]{margin-left:100px}

文件差异内容过多而无法显示
+ 0 - 0
public/resource/static/css/app.09dd2287.css


文件差异内容过多而无法显示
+ 0 - 0
public/resource/static/css/app.f8955b3b.css


+ 0 - 1
public/resource/static/css/chart.97ce4739.css

@@ -1 +0,0 @@
-.schart-box[data-v-44528046]{display:inline-block;margin:20px}.schart[data-v-44528046]{width:600px;height:400px}.content-title[data-v-44528046]{clear:both;font-weight:400;line-height:50px;margin:10px 0;font-size:22px;color:#1f2f3d}

文件差异内容过多而无法显示
+ 0 - 0
public/resource/static/css/chunk-357f68a8.9e95771d.css


文件差异内容过多而无法显示
+ 0 - 0
public/resource/static/css/chunk-37ac3920.a257c198.css


+ 1 - 0
public/resource/static/css/chunk-680f17d1.8c5edb5c.css

@@ -0,0 +1 @@
+.errPage-container[data-v-2ebd819d]{width:800px;max-width:100%;margin:100px auto}.errPage-container .pan-back-btn[data-v-2ebd819d]{background:#008489;color:#fff;border:none!important}.errPage-container .pan-gif[data-v-2ebd819d]{margin:0 auto;display:block}.errPage-container .pan-img[data-v-2ebd819d]{display:block;margin:0 auto;width:100%}.errPage-container .text-jumbo[data-v-2ebd819d]{font-size:60px;font-weight:700;color:#484848}.errPage-container .list-unstyled[data-v-2ebd819d]{font-size:14px}.errPage-container .list-unstyled li[data-v-2ebd819d]{padding-bottom:5px}.errPage-container .list-unstyled a[data-v-2ebd819d]{color:#008489;text-decoration:none}.errPage-container .list-unstyled a[data-v-2ebd819d]:hover{text-decoration:underline}

+ 1 - 0
public/resource/static/css/chunk-68d5bf9e.3c72d4e5.css

@@ -0,0 +1 @@
+.login{display:flex;justify-content:center;align-items:center;height:100%;background-image:url(../../static/img/login-background.f9f49138.jpg);background-size:cover}.title{margin:0 auto 30px auto;text-align:center;color:#707070}.login-form{border-radius:6px;background:#fff;width:400px;padding:25px 25px 5px 25px}.login-form .el-input,.login-form .el-input input{height:38px}.login-form .input-icon{height:39px;width:14px;margin-left:2px}.login-tip{font-size:13px;text-align:center;color:#bfbfbf}.login-code{width:33%;height:38px;float:right}.login-code img{cursor:pointer;vertical-align:middle;width:120px}.el-login-footer{height:40px;line-height:40px;position:fixed;bottom:0;width:100%;text-align:center;color:#fff;font-family:Arial;font-size:12px;letter-spacing:1px}

文件差异内容过多而无法显示
+ 0 - 0
public/resource/static/css/chunk-768fe99a.af7d13f9.css


文件差异内容过多而无法显示
+ 0 - 0
public/resource/static/css/chunk-libs.da13e127.css


文件差异内容过多而无法显示
+ 0 - 0
public/resource/static/css/chunk-vendors.1aeb5dfd.css


+ 0 - 1
public/resource/static/css/dashboard.00d1b39a.css

@@ -1 +0,0 @@
-.el-row[data-v-aca3e710]{margin-bottom:20px}.grid-content[data-v-aca3e710]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:100px}.grid-cont-right[data-v-aca3e710]{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center;font-size:14px;color:#999}.grid-num[data-v-aca3e710]{font-size:30px;font-weight:700}.grid-con-icon[data-v-aca3e710]{font-size:50px;width:100px;height:100px;text-align:center;line-height:100px;color:#fff}.grid-con-1 .grid-con-icon[data-v-aca3e710]{background:#2d8cf0}.grid-con-1 .grid-num[data-v-aca3e710]{color:#2d8cf0}.grid-con-2 .grid-con-icon[data-v-aca3e710]{background:#64d572}.grid-con-2 .grid-num[data-v-aca3e710]{color:#2d8cf0}.grid-con-3 .grid-con-icon[data-v-aca3e710]{background:#f25e43}.grid-con-3 .grid-num[data-v-aca3e710]{color:#f25e43}.user-info[data-v-aca3e710]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-bottom:20px;border-bottom:2px solid #ccc;margin-bottom:20px}.user-avator[data-v-aca3e710]{width:120px;height:120px;border-radius:50%}.user-info-cont[data-v-aca3e710]{padding-left:50px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-size:14px;color:#999}.user-info-cont div[data-v-aca3e710]:first-child{font-size:30px;color:#222}.user-info-list[data-v-aca3e710]{font-size:14px;color:#999;line-height:25px}.user-info-list span[data-v-aca3e710]{margin-left:70px}.mgb20[data-v-aca3e710]{margin-bottom:20px}.todo-item[data-v-aca3e710]{font-size:14px}.todo-item-del[data-v-aca3e710]{text-decoration:line-through;color:#999}.schart[data-v-aca3e710]{width:100%;height:300px}

文件差异内容过多而无法显示
+ 0 - 0
public/resource/static/css/donate.b4c4bd8b.css


文件差异内容过多而无法显示
+ 0 - 12
public/resource/static/css/donate~editor.1f0a25b2.css


+ 0 - 1
public/resource/static/css/drag.1e417d77.css

@@ -1 +0,0 @@
-.drag-box[data-v-008819a0]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.drag-box-item[data-v-008819a0]{-webkit-box-flex:1;-ms-flex:1;flex:1;max-width:330px;min-width:300px;background-color:#eff1f5;margin-right:16px;border-radius:6px;border:1px solid #e1e4e8}.item-title[data-v-008819a0]{padding:8px 8px 8px 12px;font-size:14px;line-height:1.5;color:#24292e;font-weight:600}.item-ul[data-v-008819a0]{padding:0 8px 8px;height:500px;overflow-y:scroll}.item-ul[data-v-008819a0]::-webkit-scrollbar{width:0}.drag-list[data-v-008819a0]{border:1px solid #e1e4e8;padding:10px;margin:5px 0 10px;list-style:none;background-color:#fff;border-radius:6px;cursor:pointer;-webkit-transition:border .3s ease-in;transition:border .3s ease-in}.drag-list[data-v-008819a0]:hover{border:1px solid #20a0ff}.drag-title[data-v-008819a0]{font-weight:400;line-height:25px;margin:10px 0;font-size:22px;color:#1f2f3d}.ghost-style[data-v-008819a0]{display:block;color:transparent;border-style:dashed}

+ 0 - 1
public/resource/static/css/editor.ba996960.css

@@ -1 +0,0 @@
-.editor-btn[data-v-f6394cb6]{margin-top:20px}

文件差异内容过多而无法显示
+ 0 - 0
public/resource/static/css/home.32cf4d8d.css


+ 0 - 1
public/resource/static/css/i18n.01cc2333.css

@@ -1 +0,0 @@
-.list[data-v-28d0d535]{padding:30px 0}.list p[data-v-28d0d535]{margin-bottom:20px}a[data-v-28d0d535]{color:#409eff}

+ 0 - 1
public/resource/static/css/icon.3b04e6fe.css

@@ -1 +0,0 @@
-.example-p[data-v-78dfadcd]{height:45px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.search-box[data-v-78dfadcd]{text-align:center;margin-top:10px}.search[data-v-78dfadcd]{width:300px}li[data-v-78dfadcd],ul[data-v-78dfadcd]{list-style:none}.icon-li[data-v-78dfadcd]{display:inline-block;padding:10px;width:120px;height:120px}.icon-li-content[data-v-78dfadcd]{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;cursor:pointer}.icon-li-content i[data-v-78dfadcd]{font-size:36px;color:#606266}.icon-li-content span[data-v-78dfadcd]{margin-top:10px;color:#787878}

+ 0 - 1
public/resource/static/css/login.2ad1457b.css

@@ -1 +0,0 @@
-.login-wrap[data-v-45788674]{position:relative;width:100%;height:100%;background-image:url(../../static/img/login-bg.e2134055.jpg);background-size:100%}.ms-title[data-v-45788674]{width:100%;line-height:50px;text-align:center;font-size:20px;color:#fff;border-bottom:1px solid #ddd}.ms-login[data-v-45788674]{position:absolute;left:50%;top:50%;width:350px;margin:-190px 0 0 -175px;border-radius:5px;background:hsla(0,0%,100%,.3);overflow:hidden}.ms-content[data-v-45788674]{padding:30px 30px}.login-btn[data-v-45788674]{text-align:center}.login-btn button[data-v-45788674]{width:100%;height:36px;margin-bottom:10px}.login-tips[data-v-45788674]{font-size:12px;line-height:30px;color:#fff}

部分文件因为文件数量过多而无法显示