├── boot ├── .gitkeep └── boot.go ├── i18n └── .gitkeep ├── app ├── dao │ ├── .gitkeep │ ├── user.go │ ├── relation.go │ ├── role_resource.go │ ├── role.go │ ├── resource.go │ └── internal │ │ ├── role.go │ │ ├── user.go │ │ ├── relation.go │ │ ├── resource.go │ │ └── role_resource.go ├── model │ ├── .gitkeep │ ├── role_resource.go │ ├── relation.go │ ├── internal │ │ ├── relation.go │ │ ├── role.go │ │ ├── role_resource.go │ │ ├── user.go │ │ └── resource.go │ ├── role.go │ ├── user.go │ └── resource.go ├── service │ ├── .gitkeep │ ├── user_test.go │ ├── resource_test.go │ ├── relation_test.go │ ├── relation.go │ ├── user.go │ ├── role.go │ └── resource.go ├── api │ ├── hello │ │ └── hello.go │ └── v1 │ │ ├── user.go │ │ ├── relation.go │ │ ├── resource.go │ │ └── role.go └── middleware │ ├── common.go │ └── jwt.go ├── config ├── .gitkeep ├── config.yaml └── configDev.yaml ├── docker └── .gitkeep ├── document └── .gitkeep ├── router ├── .gitkeep └── router.go ├── template └── .gitkeep ├── public ├── html │ └── .gitkeep ├── plugin │ └── .gitkeep └── resource │ ├── css │ └── .gitkeep │ ├── js │ └── .gitkeep │ └── image │ └── .gitkeep ├── packed ├── packed.go └── swagger.go ├── .gitattributes ├── main.go ├── .gitignore ├── go.mod ├── library ├── common │ ├── id.go │ ├── page.go │ ├── tree_test.go │ └── tree.go └── response │ └── response.go ├── Dockerfile ├── README.MD ├── LICENSE └── swagger └── swagger.json /boot/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /i18n/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/dao/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/model/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docker/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /document/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /router/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/service/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/html/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/plugin/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/resource/css/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/resource/js/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/resource/image/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packed/packed.go: -------------------------------------------------------------------------------- 1 | package packed 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-language=GO 2 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "gf-react-admin-server/boot" 5 | _ "gf-react-admin-server/router" 6 | 7 | "github.com/gogf/gf/frame/g" 8 | ) 9 | 10 | func main() { 11 | g.Server().Run() 12 | } 13 | -------------------------------------------------------------------------------- /boot/boot.go: -------------------------------------------------------------------------------- 1 | package boot 2 | 3 | import ( 4 | _ "gf-react-admin-server/packed" 5 | "github.com/gogf/gf/frame/g" 6 | "github.com/gogf/swagger" 7 | ) 8 | 9 | func init() { 10 | s := g.Server() 11 | s.Plugin(&swagger.Swagger{}) 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .buildpath 2 | .hgignore.swp 3 | .project 4 | .orig 5 | .swp 6 | .idea/ 7 | .settings/ 8 | .vscode/ 9 | vender/ 10 | log/ 11 | composer.lock 12 | gitpush.sh 13 | pkg/ 14 | bin/ 15 | cbuild 16 | */.DS_Store 17 | main 18 | .vscode 19 | go.sum -------------------------------------------------------------------------------- /app/api/hello/hello.go: -------------------------------------------------------------------------------- 1 | package hello 2 | 3 | import ( 4 | "github.com/gogf/gf/net/ghttp" 5 | ) 6 | 7 | // Hello is a demonstration route handler for output "Hello World!". 8 | func Hello(r *ghttp.Request) { 9 | r.Response.Writeln("Hello World!") 10 | } 11 | -------------------------------------------------------------------------------- /app/service/user_test.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gogf/gf/test/gtest" 6 | "testing" 7 | ) 8 | 9 | func TestGetUserInfos(t *testing.T) { 10 | gtest.C(t, func(*gtest.T) { 11 | userInfos, _ := User.GetUserInfos(1) 12 | fmt.Printf("%v \n", userInfos) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module gf-react-admin-server 2 | 3 | require ( 4 | github.com/bwmarrin/snowflake v0.3.0 5 | github.com/gogf/gcache-adapter v0.1.1 6 | github.com/gogf/gf v1.15.7-0.20210416023255-30b60754e3e4 7 | github.com/gogf/gf-jwt v1.1.2 8 | github.com/gogf/swagger v1.2.0 9 | golang.org/x/crypto v0.1.0 10 | ) 11 | 12 | go 1.15 13 | -------------------------------------------------------------------------------- /library/common/id.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "github.com/bwmarrin/snowflake" 4 | 5 | type idUtils struct{} 6 | 7 | var ( 8 | Id = &idUtils{} 9 | ) 10 | 11 | // GenerateUUID 采用雪花算法生成id 12 | func (i *idUtils) GenerateUUID() (int64, error) { 13 | node, err := snowflake.NewNode(1) 14 | if err != nil { 15 | return 0, err 16 | } 17 | return int64(node.Generate()), nil 18 | } 19 | -------------------------------------------------------------------------------- /app/service/resource_test.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gogf/gf/test/gtest" 6 | "testing" 7 | ) 8 | 9 | func TestGetUserMenu(t *testing.T) { 10 | gtest.C(t, func(*gtest.T) { 11 | menus, _ := Resource.GetMenuByUserId(1) 12 | fmt.Printf("%v \n", menus) 13 | }) 14 | } 15 | 16 | func TestGetUserMenuTree(t *testing.T) { 17 | gtest.C(t, func(*gtest.T) { 18 | treeNode, _ := Resource.GetMenuTreeByUserId(1) 19 | fmt.Print(treeNode) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /app/model/role_resource.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // This is auto-generated by gf cli tool. Fill this file as you wish. 3 | // ========================================================================== 4 | 5 | package model 6 | 7 | import ( 8 | "gf-react-admin-server/app/model/internal" 9 | ) 10 | 11 | // RoleResource is the golang structure for table admin_role_resource. 12 | type RoleResource internal.RoleResource 13 | 14 | // Fill with you ideas below. 15 | -------------------------------------------------------------------------------- /app/middleware/common.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gogf/gf/frame/g" 5 | "github.com/gogf/gf/net/ghttp" 6 | ) 7 | 8 | // 允许接口跨域请求中间件 9 | func CORS(r *ghttp.Request) { 10 | r.Response.CORSDefault() 11 | r.Middleware.Next() 12 | } 13 | 14 | // 异常记录中间件 15 | func ErrorLog(r *ghttp.Request) { 16 | r.Middleware.Next() 17 | if err := r.GetError(); err != nil { 18 | g.Log().Error(err) 19 | } 20 | } 21 | 22 | func GetPath(r *ghttp.Request) { 23 | // 获取请求路径 24 | g.Log().Infof("请求路径:[%v],请求方法:[%v], router-method:[%v], router-uri:[%v], router-regNames [%v], router-regRule:[%v]", 25 | r.RequestURI, r.Method, r.Router.Method, r.Router.Uri, r.Router.RegNames, r.Router.RegRule) 26 | r.Middleware.Next() 27 | } 28 | -------------------------------------------------------------------------------- /app/model/relation.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // This is auto-generated by gf cli tool. Fill this file as you wish. 3 | // ========================================================================== 4 | 5 | package model 6 | 7 | import ( 8 | "gf-react-admin-server/app/model/internal" 9 | ) 10 | 11 | // Relation is the golang structure for table admin_relation. 12 | type Relation internal.Relation 13 | 14 | // Fill with you ideas below. 15 | 16 | // SaveRelationReq 创建用户关系参数 17 | type SaveRelationReq struct { 18 | UserId int `json:"userId" v:"required|min:1#用户id不能为空|用户id长度有误"` // 用户id 19 | RoleIds []int `json:"roleIds" v:"required|min-length:1#待关联角色id不能为空|至少关联一个角色id"` // 角色id slice 20 | } 21 | -------------------------------------------------------------------------------- /library/common/page.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | type PageReq struct { 4 | PageNo int `json:"pageNo" d:"1" v:"required|min:1#分页页数不能为空|分页页数参数非法"` // 分页页数 5 | PageSize int `json:"pageSize" d:"10" v:"required|min:1#分页大小不能为空|分页大小参数非法"` // 分页大小 6 | } 7 | 8 | // 分页统一返回体 9 | type PageResult struct { 10 | PageNo int `json:"pageNo"` // 分页页数 11 | PageSize int `json:"pageSize"` // 分页大小 12 | Total int `json:"total"` // 总记录数 13 | Records interface{} `json:"records"` // 对应数据 14 | } 15 | 16 | // NewResult init page result. 创建一个分页返回体 17 | func NewResult(pageNo, pageSize, total int, records interface{}) PageResult { 18 | return PageResult{ 19 | PageNo: pageNo, 20 | PageSize: pageSize, 21 | Total: total, 22 | Records: records, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/dao/user.go: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // This is auto-generated by gf cli tool only once. Fill this file as you wish. 3 | // ============================================================================ 4 | 5 | package dao 6 | 7 | import ( 8 | "gf-react-admin-server/app/dao/internal" 9 | ) 10 | 11 | // userDao is the manager for logic model data accessing 12 | // and custom defined data operations functions management. You can define 13 | // methods on it to extend its functionality as you wish. 14 | type userDao struct { 15 | *internal.UserDao 16 | } 17 | 18 | var ( 19 | // User is globally public accessible object for table admin_user operations. 20 | User = &userDao{ 21 | internal.User, 22 | } 23 | ) 24 | 25 | // Fill with you ideas below. 26 | -------------------------------------------------------------------------------- /app/dao/relation.go: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // This is auto-generated by gf cli tool only once. Fill this file as you wish. 3 | // ============================================================================ 4 | 5 | package dao 6 | 7 | import ( 8 | "gf-react-admin-server/app/dao/internal" 9 | ) 10 | 11 | // relationDao is the manager for logic model data accessing 12 | // and custom defined data operations functions management. You can define 13 | // methods on it to extend its functionality as you wish. 14 | type relationDao struct { 15 | *internal.RelationDao 16 | } 17 | 18 | var ( 19 | // Relation is globally public accessible object for table admin_relation operations. 20 | Relation = &relationDao{ 21 | internal.Relation, 22 | } 23 | ) 24 | 25 | // Fill with you ideas below. 26 | -------------------------------------------------------------------------------- /app/model/internal/relation.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // This is auto-generated by gf cli tool. DO NOT EDIT THIS FILE MANUALLY. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "github.com/gogf/gf/os/gtime" 9 | ) 10 | 11 | // Relation is the golang structure for table admin_relation. 12 | type Relation struct { 13 | Id int64 `orm:"id,primary" json:"id"` // 14 | UserId int64 `orm:"user_id" json:"userId"` // 用户id 15 | RoleId int64 `orm:"role_id" json:"roleId"` // 角色id 16 | CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建时间 17 | UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 更新时间 18 | DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除时间 19 | } 20 | -------------------------------------------------------------------------------- /app/dao/role_resource.go: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // This is auto-generated by gf cli tool only once. Fill this file as you wish. 3 | // ============================================================================ 4 | 5 | package dao 6 | 7 | import ( 8 | "gf-react-admin-server/app/dao/internal" 9 | ) 10 | 11 | // roleResourceDao is the manager for logic model data accessing 12 | // and custom defined data operations functions management. You can define 13 | // methods on it to extend its functionality as you wish. 14 | type roleResourceDao struct { 15 | *internal.RoleResourceDao 16 | } 17 | 18 | var ( 19 | // RoleResource is globally public accessible object for table admin_role_resource operations. 20 | RoleResource = &roleResourceDao{ 21 | internal.RoleResource, 22 | } 23 | ) 24 | 25 | // Fill with you ideas below. 26 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM loads/alpine:3.8 2 | 3 | LABEL maintainer="john@goframe.org" 4 | 5 | ############################################################################### 6 | # INSTALLATION 7 | ############################################################################### 8 | 9 | # 设置固定的项目路径 10 | ENV WORKDIR /var/www/gf-react-admin-server 11 | 12 | # 添加应用可执行文件,并设置执行权限 13 | ADD ./bin/linux_amd64/main $WORKDIR/main 14 | RUN chmod +x $WORKDIR/main 15 | 16 | # 添加I18N多语言文件、静态文件、配置文件、模板文件 17 | ADD i18n $WORKDIR/i18n 18 | ADD public $WORKDIR/public 19 | ADD config $WORKDIR/config 20 | ADD template $WORKDIR/template 21 | 22 | ############################################################################### 23 | # START 24 | ############################################################################### 25 | WORKDIR $WORKDIR 26 | CMD ./main 27 | -------------------------------------------------------------------------------- /app/model/internal/role.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // This is auto-generated by gf cli tool. DO NOT EDIT THIS FILE MANUALLY. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "github.com/gogf/gf/os/gtime" 9 | ) 10 | 11 | // Role is the golang structure for table admin_role. 12 | type Role struct { 13 | Id int64 `orm:"id,primary" json:"id"` // 14 | ParentId string `orm:"parent_id" json:"parentId"` // 父角色id 15 | RoleName string `orm:"role_name" json:"roleName"` // 角色名称 16 | Alias string `orm:"alias" json:"alias"` // 角色别名 17 | CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建时间 18 | UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 更新时间 19 | DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除时间时间 20 | } 21 | -------------------------------------------------------------------------------- /app/api/v1/user.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "gf-react-admin-server/app/service" 5 | "gf-react-admin-server/library/response" 6 | "github.com/gogf/gf/net/ghttp" 7 | "github.com/gogf/gf/util/gconv" 8 | "github.com/gogf/gf/util/gvalid" 9 | ) 10 | 11 | // apiUser is user api and func receiver 12 | type userApi struct{} 13 | 14 | var ( 15 | // User to global call 16 | User = &userApi{} 17 | ) 18 | 19 | // GetUserInfos 20 | // @summary 用户详情 21 | // @tags 用户服务 22 | // @produce json 23 | // @param id path int true "用户id" 24 | // @router /v1/user/{id} [GET] 25 | func (u *userApi) GetUserInfos(r *ghttp.Request) { 26 | id := r.Get("id") 27 | if err := gvalid.Check(id, "required|integer|min:1", "用户id为空|参数类型非法|用户id长度非法"); err != nil { 28 | response.FailMsgExit(r, err.Error()) 29 | } 30 | userInfos, err := service.User.GetUserInfos(gconv.Int(id)) 31 | if err != nil { 32 | response.FailMsgExit(r, err.Error()) 33 | } 34 | response.SuccessData(r, userInfos) 35 | } 36 | -------------------------------------------------------------------------------- /config/config.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | Address: ':8199' 3 | ServerRoot: public 4 | ServerAgent: gf-react-admin-server 5 | LogPath: ./log/gf-react-admin-server/server 6 | logger: 7 | Path: ./log/gf-react-admin-server/log 8 | Level: all 9 | Stdout: true 10 | database: 11 | default: 12 | - type: mysql 13 | link: 'root:123456@tcp(127.0.0.1:3306)/go_test' 14 | debug: true 15 | logger: 16 | Path: ./log/gf-react-admin-server/sql 17 | Level: all 18 | Stdout: true 19 | redis: 20 | default: '127.0.0.1:6379,0' 21 | cache: '127.0.0.1:6379,1' 22 | jwt: 23 | ExpireTime: 60 24 | RefreshTime: 480 25 | SignKey: gf-react-admin-server 26 | Realm: gf-react-admin-server zone 27 | IdentityKey: JWT_USER_ID 28 | TokenLookup: 'header: Authorization' 29 | TokenHeadName: Bearer 30 | gfcli: 31 | gen: 32 | dao: 33 | - link: 'mysql:root:123456@tcp(127.0.0.1:3306)/go_test' 34 | tables: admin_role_resource 35 | removePrefix: admin_ 36 | -------------------------------------------------------------------------------- /config/configDev.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | Address: ':8199' 3 | ServerRoot: public 4 | ServerAgent: gf-react-admin-server 5 | LogPath: ./log/gf-react-admin-server/server 6 | logger: 7 | Path: ./log/gf-react-admin-server/log 8 | Level: all 9 | Stdout: true 10 | database: 11 | default: 12 | - type: mysql 13 | link: 'root:123456@tcp(127.0.0.1:3306)/go_test' 14 | debug: true 15 | logger: 16 | Path: ./log/gf-react-admin-server/sql 17 | Level: all 18 | Stdout: true 19 | redis: 20 | default: '127.0.0.1:6379,0' 21 | cache: '127.0.0.1:6379,1' 22 | jwt: 23 | ExpireTime: 60 24 | RefreshTime: 480 25 | SignKey: gf-react-admin-server 26 | Realm: gf-react-admin-server zone 27 | IdentityKey: JWT_USER_ID 28 | TokenLookup: 'header: Authorization' 29 | TokenHeadName: Bearer 30 | gfcli: 31 | gen: 32 | dao: 33 | - link: 'mysql:root:123456@tcp(127.0.0.1:3306)/go_test' 34 | tables: admin_resource 35 | removePrefix: admin_ 36 | -------------------------------------------------------------------------------- /app/service/relation_test.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "gf-react-admin-server/app/model" 5 | "github.com/gogf/gf/test/gtest" 6 | "testing" 7 | ) 8 | 9 | func TestCreateRelation(t *testing.T) { 10 | gtest.C(t, func(t *gtest.T) { 11 | req := &model.SaveRelationReq{ 12 | UserId: 1, 13 | RoleIds: []int{1, 2, 4}, 14 | } 15 | t.Assert(Relation.SaveRelation(req), nil) 16 | }) 17 | } 18 | 19 | func TestCreateRelationErr1(t *testing.T) { 20 | gtest.C(t, func(t *gtest.T) { 21 | req := &model.SaveRelationReq{ 22 | UserId: 1, 23 | } 24 | if err := Relation.SaveRelation(req); err != nil { 25 | t.Log(err) 26 | } else { 27 | t.Error("测试失败") 28 | } 29 | }) 30 | } 31 | 32 | func TestCreateRelationErr2(t *testing.T) { 33 | gtest.C(t, func(t *gtest.T) { 34 | req := &model.SaveRelationReq{ 35 | RoleIds: []int{1}, 36 | } 37 | if err := Relation.SaveRelation(req); err != nil { 38 | t.Log(err) 39 | } else { 40 | t.Error("测试失败") 41 | } 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /app/api/v1/relation.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "gf-react-admin-server/app/model" 5 | "gf-react-admin-server/app/service" 6 | "gf-react-admin-server/library/response" 7 | "github.com/gogf/gf/errors/gerror" 8 | "github.com/gogf/gf/net/ghttp" 9 | "github.com/gogf/gf/util/gvalid" 10 | ) 11 | 12 | type relationApi struct{} 13 | 14 | var ( 15 | Relation = &relationApi{} 16 | ) 17 | 18 | // @summary 保存用户关系 19 | // @tags 用户关系服务 20 | // @produce json 21 | // @param entity body model.SaveRelationReq true "保存用户关系参数" 22 | // @router /v1/relation [PUT] 23 | func (r *relationApi) SaveRelation(req *ghttp.Request) { 24 | saveRelationReq := &model.SaveRelationReq{} 25 | if err := req.Parse(saveRelationReq); err != nil { 26 | if _, ok := err.(*gvalid.Error); ok { 27 | // 参数校验失败 28 | response.FailCodeAndMsgExit(req, response.ParamValidErr, err.Error()) 29 | } 30 | response.FailMsgExit(req, err.Error()) 31 | } 32 | if err := service.Relation.SaveRelation(saveRelationReq); err != nil { 33 | response.FailCodeAndMsgExit(req, gerror.Code(err), err.Error()) 34 | } 35 | response.SuccessMsgExit(req, "保存成功") 36 | } 37 | -------------------------------------------------------------------------------- /app/model/internal/role_resource.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // This is auto-generated by gf cli tool. DO NOT EDIT THIS FILE MANUALLY. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "github.com/gogf/gf/os/gtime" 9 | ) 10 | 11 | // RoleResource is the golang structure for table admin_role_resource. 12 | type RoleResource struct { 13 | Id int64 `orm:"id,primary" json:"id"` // 14 | RoleId int64 `orm:"role_id" json:"roleId"` // 角色id 15 | ResourceId int64 `orm:"resource_id" json:"resourceId"` // 资源id 16 | CreateBy int64 `orm:"create_by" json:"createBy"` // 创建人 17 | CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建时间 18 | UpdatedBy int64 `orm:"updated_by" json:"updatedBy"` // 更新人 19 | UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 更新时间 20 | DeleteBy int64 `orm:"delete_by" json:"deleteBy"` // 删除人 21 | DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除时间时间 22 | } 23 | -------------------------------------------------------------------------------- /app/dao/role.go: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // This is auto-generated by gf cli tool only once. Fill this file as you wish. 3 | // ============================================================================ 4 | 5 | package dao 6 | 7 | import ( 8 | "gf-react-admin-server/app/dao/internal" 9 | "gf-react-admin-server/app/model" 10 | ) 11 | 12 | // roleDao is the manager for logic model data accessing 13 | // and custom defined data operations functions management. You can define 14 | // methods on it to extend its functionality as you wish. 15 | type roleDao struct { 16 | *internal.RoleDao 17 | } 18 | 19 | var ( 20 | // Role is globally public accessible object for table admin_role operations. 21 | Role = &roleDao{ 22 | internal.Role, 23 | } 24 | ) 25 | 26 | // Fill with you ideas below. 27 | func (r *roleDao) FindByNameOrAlias(name, alias string) (role *model.Role, err error) { 28 | dao := r.Safe() 29 | if len(name) > 0 { 30 | dao = dao.Where(r.Columns.RoleName+" like ?", "%"+name+"%") 31 | } 32 | if len(alias) > 0 { 33 | dao = dao.Or(r.Columns.Alias+" like ?", "%"+alias+"%") 34 | } 35 | err = dao.Scan(&role) 36 | return 37 | } 38 | -------------------------------------------------------------------------------- /app/dao/resource.go: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // This is auto-generated by gf cli tool only once. Fill this file as you wish. 3 | // ============================================================================ 4 | 5 | package dao 6 | 7 | import ( 8 | "gf-react-admin-server/app/dao/internal" 9 | "gf-react-admin-server/app/model" 10 | ) 11 | 12 | // resourceDao is the manager for logic model data accessing 13 | // and custom defined data operations functions management. You can define 14 | // methods on it to extend its functionality as you wish. 15 | type resourceDao struct { 16 | *internal.ResourceDao 17 | } 18 | 19 | var ( 20 | // Resource is globally public accessible object for table admin_resource operations. 21 | Resource = &resourceDao{ 22 | internal.Resource, 23 | } 24 | ) 25 | 26 | // Fill with you ideas below. 27 | 28 | // FindByNameAndType find resource by name and type 29 | func (r *resourceDao) FindByNameAndType(name, types string) (resource *model.Resource, err error) { 30 | if len(name) <= 0 || len(types) <= 0 { 31 | return nil, nil 32 | } 33 | 34 | err = r.Where(r.Columns.Name, name).And(r.Columns.Type, types).Scan(&resource) 35 | return 36 | } 37 | -------------------------------------------------------------------------------- /app/model/internal/user.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // This is auto-generated by gf cli tool. DO NOT EDIT THIS FILE MANUALLY. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "github.com/gogf/gf/os/gtime" 9 | ) 10 | 11 | // User is the golang structure for table admin_user. 12 | type User struct { 13 | Id int64 `orm:"id,primary" json:"id"` // 14 | FullName string `orm:"full_name" json:"fullName"` // 姓名 15 | Account string `orm:"account" json:"account"` // 账号 16 | Password string `orm:"password" json:"password"` // 密码 17 | Email string `orm:"email" json:"email"` // 邮箱 18 | Mobile string `orm:"mobile" json:"mobile"` // 手机号码 19 | Wechat string `orm:"wechat" json:"wechat"` // 微信号 20 | Avatar string `orm:"avatar" json:"avatar"` // 头像 21 | Sex int `orm:"sex" json:"sex"` // 性别:0:未知,1:男,2:女 22 | Status int `orm:"status" json:"status"` // 0:禁用,1正常 23 | CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建时间 24 | UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 更新时间 25 | DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除时间时间 26 | } 27 | -------------------------------------------------------------------------------- /library/common/tree_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/gogf/gf/test/gtest" 7 | "testing" 8 | ) 9 | 10 | type Tee struct { 11 | Id int 12 | Name string 13 | ParentId int 14 | } 15 | 16 | func (r Tee) GetPrimKey() int { 17 | return r.Id 18 | } 19 | 20 | func (r Tee) GetParentPrimKey() int { 21 | return r.ParentId 22 | } 23 | 24 | func (r Tee) GetName() string { 25 | return r.Name 26 | } 27 | 28 | func (r Tee) GetData() interface{} { 29 | return r 30 | } 31 | 32 | func (r Tee) Root() bool { 33 | return r.ParentId == 0 34 | } 35 | 36 | func getData(datas []Tee) (iTrees []ITreeNode) { 37 | for _, v := range datas { 38 | iTrees = append(iTrees, v) 39 | } 40 | return 41 | } 42 | 43 | func TestCreateRelation(t *testing.T) { 44 | gtest.C(t, func(t *gtest.T) { 45 | datas := []Tee{ 46 | {Id: 1, Name: "根节点1", ParentId: 0}, 47 | {Id: 2, Name: "根节点2", ParentId: 0}, 48 | {Id: 3, Name: "根节点3", ParentId: 0}, 49 | {Id: 21, Name: "子节点1", ParentId: 2}, 50 | {Id: 11, Name: "子节点2", ParentId: 1}, 51 | {Id: 31, Name: "子节点3", ParentId: 3}, 52 | {Id: 211, Name: "子节点4", ParentId: 21}, 53 | {Id: 111, Name: "子节点5", ParentId: 11}, 54 | {Id: 311, Name: "子节点6", ParentId: 31}, 55 | {Id: 1111, Name: "子节点7", ParentId: 111}, 56 | } 57 | tree := GenerateTree(getData(datas)) 58 | by, _ := json.Marshal(tree) 59 | fmt.Print(string(by)) 60 | t.AssertNE(tree, nil) 61 | }) 62 | } 63 | -------------------------------------------------------------------------------- /app/service/relation.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "gf-react-admin-server/app/dao" 5 | "gf-react-admin-server/app/model" 6 | "gf-react-admin-server/library/common" 7 | "github.com/gogf/gf/util/gvalid" 8 | ) 9 | 10 | type relationService struct{} 11 | 12 | var ( 13 | // Relation 供外部调用 14 | Relation = &relationService{} 15 | ) 16 | 17 | // SaveRelation 保存用户关系 18 | func (r *relationService) SaveRelation(req *model.SaveRelationReq) error { 19 | if err := gvalid.CheckStruct(&req, nil); err != nil { 20 | return err 21 | } 22 | 23 | // 删除旧关系 24 | deleteParam := map[string]interface{}{ 25 | dao.Relation.Columns.UserId: req.UserId, 26 | dao.Relation.Columns.RoleId + " not in (?)": req.RoleIds, 27 | } 28 | _, _ = dao.Relation.Delete(deleteParam) 29 | 30 | for _, v := range req.RoleIds { 31 | // 根据用户id和需要新增的角色id查询是否已存在该关联关系 32 | queryParam := map[string]interface{}{ 33 | dao.Relation.Columns.UserId: req.UserId, 34 | dao.Relation.Columns.RoleId: v, 35 | } 36 | count, err := dao.Relation.Where(queryParam).Count() 37 | if err != nil { 38 | return err 39 | } 40 | if count > 0 { 41 | continue 42 | } 43 | 44 | var relation = &model.Relation{ 45 | UserId: int64(req.UserId), 46 | RoleId: int64(v), 47 | } 48 | relation.Id, err = common.Id.GenerateUUID() 49 | if err != nil { 50 | return err 51 | } 52 | // 创建 53 | _, err = dao.Relation.Insert(relation) 54 | if err != nil { 55 | return err 56 | } 57 | } 58 | 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /app/model/internal/resource.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // This is auto-generated by gf cli tool. DO NOT EDIT THIS FILE MANUALLY. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "github.com/gogf/gf/os/gtime" 9 | ) 10 | 11 | // Resource is the golang structure for table admin_resource. 12 | type Resource struct { 13 | Id int64 `orm:"id,primary" json:"id"` // 14 | ParentId int64 `orm:"parent_id" json:"parentId"` // 父资源id 15 | Name string `orm:"name" json:"name"` // 资源名称 16 | Alias string `orm:"alias" json:"alias"` // 资源别称 17 | Url string `orm:"url" json:"url"` // 资源路径 18 | Enable bool `orm:"enable" json:"enable"` // 0:不显示,1显示 19 | Icon string `orm:"icon" json:"icon"` // 资源图标 20 | Type string `orm:"type" json:"type"` // 资源类型:menu-菜单;button-按钮;link-链接 21 | Sn int `orm:"sn" json:"sn"` // 排序 22 | CreateBy int64 `orm:"create_by" json:"createBy"` // 创建人 23 | CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建时间 24 | UpdatedBy int64 `orm:"updated_by" json:"updatedBy"` // 更新人 25 | UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 更新时间 26 | DeleteBy int64 `orm:"delete_by" json:"deleteBy"` // 删除人 27 | DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除时间时间 28 | } 29 | -------------------------------------------------------------------------------- /app/model/role.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // This is auto-generated by gf cli tool. Fill this file as you wish. 3 | // ========================================================================== 4 | 5 | package model 6 | 7 | import ( 8 | "gf-react-admin-server/app/model/internal" 9 | "gf-react-admin-server/library/common" 10 | "github.com/gogf/gf/os/gtime" 11 | ) 12 | 13 | // Role is the golang structure for table admin_role. 14 | type Role internal.Role 15 | 16 | // Fill with you ideas below. 17 | 18 | // CreateRoleReq 用于接受创建角色请求参数 19 | type CreateRoleReq struct { 20 | ParentId string `json:"parentId"` // 父角色id 21 | RoleName string `json:"roleName" v:"roleName@required#角色名不能为空"` // 角色名称 22 | Alias string `json:"alias"` // 角色别名 23 | } 24 | 25 | // EditRoleReq 编辑角色请求参数 26 | type EditRoleReq struct { 27 | *CreateRoleReq 28 | Id int64 `json:"id" v:"id@required|min:1 #待编辑角色id不能为空|待编辑角色id长度非法"` // 角色id 29 | } 30 | 31 | // RoleQueryReq 角色列表查询参数 32 | type RoleQueryReq struct { 33 | common.PageReq 34 | } 35 | 36 | // RoleInfoReq 角色详情返回参数 37 | type RoleInfoReq struct { 38 | Id int64 `json:"id"` // 39 | ParentId string `json:"parentId"` // 父角色id 40 | RoleName string `json:"roleName"` // 角色名称 41 | Alias string `json:"alias"` // 角色别名 42 | CreatedAt *gtime.Time `json:"createdAt"` // 创建时间 43 | UpdatedAt *gtime.Time `json:"updatedAt"` // 更新时间 44 | } 45 | 46 | // RolePageListRes 角色列表返回参数 47 | type RolePageListRes struct { 48 | RoleInfoReq 49 | } 50 | -------------------------------------------------------------------------------- /router/router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | v1 "gf-react-admin-server/app/api/v1" 5 | "gf-react-admin-server/app/middleware" 6 | "github.com/gogf/gf/frame/g" 7 | "github.com/gogf/gf/net/ghttp" 8 | ) 9 | 10 | var ( 11 | // RouteGroupPrefix 路由统一前缀 12 | RouteGroupPrefix = "/v1" 13 | ) 14 | 15 | func init() { 16 | s := g.Server() 17 | // 跨域中间件 18 | s.Use(middleware.CORS) 19 | // 异常记录中间件 20 | s.Use(middleware.ErrorLog) 21 | s.Group(RouteGroupPrefix, func(group *ghttp.RouterGroup) { 22 | group.Middleware( 23 | middleware.GetPath) 24 | group.POST("/user/login", middleware.JwtMiddleware.LoginHandler) 25 | group.GET("/user/logout", middleware.JwtMiddleware.LogoutHandler) 26 | }) 27 | 28 | // 角色服务 29 | s.Group(RouteGroupPrefix, func(group *ghttp.RouterGroup) { 30 | group.Middleware(middleware.JwtAuth) 31 | group.POST("/role", v1.Role.CreateRole) 32 | group.PUT("/role", v1.Role.EditRole) 33 | group.GET("/role", v1.Role.RolePageList) 34 | group.GET("/role/{id}", v1.Role.RoleById) 35 | }) 36 | 37 | // 用户关系服务 38 | s.Group(RouteGroupPrefix, func(group *ghttp.RouterGroup) { 39 | group.Middleware(middleware.JwtAuth) 40 | group.PUT("/relation", v1.Relation.SaveRelation) 41 | }) 42 | 43 | // 资源服务 44 | s.Group(RouteGroupPrefix, func(group *ghttp.RouterGroup) { 45 | group.Middleware(middleware.JwtAuth) 46 | group.POST("/resource", v1.Resource.CreateResource) 47 | group.PUT("/resource", v1.Resource.EditResource) 48 | group.GET("/resource/tree", v1.Resource.GetResourceTree) 49 | }) 50 | 51 | // 用户服务 52 | s.Group(RouteGroupPrefix, func(group *ghttp.RouterGroup) { 53 | group.Middleware(middleware.JwtAuth) 54 | group.GET("/user/{id}", v1.User.GetUserInfos) 55 | }) 56 | } 57 | -------------------------------------------------------------------------------- /app/model/user.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // This is auto-generated by gf cli tool. Fill this file as you wish. 3 | // ========================================================================== 4 | 5 | package model 6 | 7 | import ( 8 | "gf-react-admin-server/app/model/internal" 9 | ) 10 | 11 | // User is the golang structure for table admin_user. 12 | type User internal.User 13 | 14 | // Fill with you ideas below. 15 | 16 | // UserLoginReq is login param 17 | type UserLoginReq struct { 18 | Account string `v:"required#请输入账户"` // 账号 19 | Password string `v:"required#请输入密码"` // 密码 20 | } 21 | 22 | // UserLoginRes is login response param 23 | type UserLoginRes struct { 24 | JWT_USER_ID int `json:"JWT_USER_ID"` // 25 | FullName string `json:"fullName"` // 姓名 26 | Account string `json:"account"` // 账号 27 | Email string `json:"email"` // 邮箱 28 | Mobile string `json:"mobile"` // 手机号码 29 | Wechat string `json:"wechat"` // 微信号 30 | Avatar string `json:"avatar"` // 头像 31 | Sex int `json:"sex"` // 性别:0:未知,1:男,2:女 32 | Password string `json:"-"` 33 | } 34 | 35 | // UserInfo 用户信息 36 | type UserInfo struct { 37 | FullName string `json:"fullName"` // 姓名 38 | Account string `json:"account"` // 账号 39 | Email string `json:"email"` // 邮箱 40 | Mobile string `json:"mobile"` // 手机号码 41 | Wechat string `json:"wechat"` // 微信号 42 | Avatar string `json:"avatar"` // 头像 43 | Sex int `json:"sex"` // 性别:0:未知,1:男,2:女 44 | } 45 | 46 | // UserInfos 用户的全部信息 47 | type UserInfos struct { 48 | User UserInfo `json:"user"` 49 | Menus []ResourceInfo `json:"menus"` 50 | } 51 | -------------------------------------------------------------------------------- /app/service/user.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "gf-react-admin-server/app/dao" 5 | "gf-react-admin-server/app/model" 6 | "gf-react-admin-server/library/response" 7 | "github.com/gogf/gf/errors/gerror" 8 | "golang.org/x/crypto/bcrypt" 9 | ) 10 | 11 | type userService struct { 12 | } 13 | 14 | var ( 15 | User = &userService{} 16 | ) 17 | 18 | func (u *userService) Login(loginReq *model.UserLoginReq) (user *model.UserLoginRes, err error) { 19 | var queryParam = map[string]string{ 20 | "account": loginReq.Account, 21 | } 22 | err = dao.User.Where(queryParam).Scan(&user) 23 | if err != nil { 24 | return nil, err 25 | } 26 | if user == nil { 27 | return nil, gerror.NewCode(response.AccountExist, "账户不存在") 28 | } 29 | 30 | err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(loginReq.Password)) 31 | if err != nil { 32 | return nil, gerror.NewCode(response.AccountValidErr, "账户或密码错误") 33 | } 34 | return user, nil 35 | } 36 | 37 | // GetUserInfos 获取用户信息 38 | func (u *userService) GetUserInfos(userId int) (*model.UserInfos, error) { 39 | if userId <= 0 { 40 | return nil, nil 41 | } 42 | 43 | // 用户信息 44 | var userInfo *model.UserInfo 45 | err := dao.User.WherePri(userId).Scan(&userInfo) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | // 菜单资源 51 | menuResources, err := Resource.GetMenuByUserId(userId) 52 | if err != nil { 53 | return nil, err 54 | } 55 | menus := make([]model.ResourceInfo, 0, len(menuResources)) 56 | for _, v := range menuResources { 57 | menus = append(menus, model.ResourceInfo{ 58 | Id: v.Id, 59 | ParentId: v.ParentId, 60 | Name: v.Name, 61 | Alias: v.Alias, 62 | Url: v.Url, 63 | Icon: v.Icon, 64 | Type: v.Type, 65 | Sn: v.Sn, 66 | }) 67 | } 68 | 69 | userInfos := &model.UserInfos{ 70 | User: *userInfo, 71 | Menus: menus, 72 | } 73 | return userInfos, nil 74 | } 75 | -------------------------------------------------------------------------------- /library/common/tree.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | // ITreeNode 要使用树形结构,对应结构体需要实现以下方法 4 | type ITreeNode interface { 5 | GetPrimKey() int // 主键 6 | GetParentPrimKey() int // 父主键 7 | GetName() string // 节点名称 8 | GetData() interface{} // 数据 9 | Root() bool // 是否根节点 10 | } 11 | 12 | // TreeNode 树形结构的节点数据 13 | type TreeNode struct { 14 | PrimKey int `json:"primKey"` 15 | ParentPrimKey int `json:"parentPrimKey"` 16 | Name string `json:"name"` 17 | Data interface{} `json:"data"` 18 | Children []TreeNode `json:"children"` 19 | } 20 | 21 | // GenerateTree 生成树形结构 22 | func GenerateTree(nodes []ITreeNode) (trees []TreeNode) { 23 | trees = make([]TreeNode, 0) 24 | if len(nodes) <= 0 { 25 | return 26 | } 27 | var roots, childs []ITreeNode 28 | 29 | // 分类根节点和子节点 30 | for _, v := range nodes { 31 | if v.Root() { 32 | roots = append(roots, v) 33 | } else { 34 | childs = append(childs, v) 35 | } 36 | } 37 | 38 | for _, root := range roots { 39 | treeNode := &TreeNode{ 40 | Name: root.GetName(), 41 | PrimKey: root.GetPrimKey(), 42 | ParentPrimKey: root.GetParentPrimKey(), 43 | Data: root.GetData(), 44 | } 45 | 46 | // 递归寻找子节点 47 | recursiveTree(treeNode, childs) 48 | 49 | trees = append(trees, *treeNode) 50 | } 51 | return 52 | } 53 | 54 | func recursiveTree(node *TreeNode, childs []ITreeNode) { 55 | iNode := node.Data.(ITreeNode) 56 | 57 | for _, v := range childs { 58 | if v.GetParentPrimKey() == iNode.GetPrimKey() { 59 | childTreeNode := &TreeNode{ 60 | Name: v.GetName(), 61 | PrimKey: v.GetPrimKey(), 62 | ParentPrimKey: v.GetParentPrimKey(), 63 | Data: v.GetData(), 64 | } 65 | 66 | // 递归寻找子节点 67 | recursiveTree(childTreeNode, childs) 68 | 69 | node.Children = append(node.Children, *childTreeNode) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packed/swagger.go: -------------------------------------------------------------------------------- 1 | package packed 2 | 3 | import "github.com/gogf/gf/os/gres" 4 | 5 | func init() { 6 | if err := gres.Add("H4sIAAAAAAAC/3yUfTTTix/Hv8Miv/Wb9EV0NUWJJrJYcku5HvL8TCWKyOZpyj00Wx5OjSJhbtTmqWHjNK15vtyQSR6aZhJF0TzVTLFCNbN73Hs7de7p3Pcfn8/5nM/n8z7vv17uTvIKIKAEKAFn7SiewHcCgfVAbHxQWFjoeeN/+p7wWFy0jzcUgECSUk+LKG5eI3Zg23uicuYL3Q6HrJOWB0PoubfIbytzOdsPPqZX+x6vIt/WRPBVhbWQTaqYE5h1DIcuZ/phqrvpzWxjjuPSVRavH0EIiQh1qod1PlDs5K/icWOSOcJsw6h2rp4DmWu5q1jR0M1RrJG/p3di1Z/5RAXvKZZcwIE0VJnJcmg/wR/WpHWFS6m6GNvAmtyFuRJEa6j9JI9Ux79Fu9NOKDfmXtTALibocHj3BFxqM1Y14PqvzXu3FubfJqZZFOqz5viHWmXP8P51aPXPxjdCaii+t5PfFEQ0TmQliVuLU/XJUHmYjQdkM+9CKM0OSwxRcyYF65pUHtYzlmFY75QV0AyeB2SUXYJ6PH1gsaPoGpYWJ7J9nUcyqBCXdVRAtRMoPUgwmzdrJD3EMJlwXEUy2mHP2M0nUH46hpj8u6UjJmqHzaANNNdwYnp73puRLWcES4ILlt072RVyv7idj8K9OnQsrn53n9i6+rM1zDItoq7UfhV8hNi9dL8wBfWTuoXwY2J5sLla8j6lhEcjXXrTb0qwrDmx8EElTVPdQohJdIDs3axXwGU08ihnQIUFM3ip/LkobHH+0IqBiGu/wollfBlONDfWN1Pr70sh1fuGw1fnFsAp+HQ5KSE0Kz/xjk8gnEhF2zS1i6Y2zLz84DEm8rK5hEOWxF4anplzwHRdt5e2aRb4rBjkBYrFp+TTUMjzT9kfr9vbbDm6pLlU6mF1TMxvIrhauCA52+21e8cx+3RMqG60k8XNGYMCRvZ8hCVLVPwuLMuIivpZfK9PB167ybvdC+KbG/Py9/wntSnDkcp0VGq3acr0PvIjmudo9kPr1qJBXde+9z6rQWaE7BcD1fpnn+qONezksQIwrmbzeGZRRtsQovLV+Ov/EVsCZ8zn8WNaQ6rbyvyN9QXpWzcKtOL0BtBHgqJmY9ioZFMYfbNTWZBeNFkhD27oUo7u8z3pjhWeMU1fJIJNtGQ9Xn9tSTQvEuc1IZ5ckNhK3uZ8EIxPzr9Wk/mjL9LX9wPr424c3cZUunuZUhV8h4l4TrWKH9ie6SOX6mXA/uMmOwJmcyTMb7AjfX+5jBgQ3BAYMqvv2eH8ToWAJSF+Q93YCnPcaVXRJvWaepJ40GKlFGgy89iNm384mMtZxGbspbkNwxFP/erd/j9kxkyy8kgihhjfF9HPabUe93aqxEUlpSG4y0zOzU8GBZa2rb595kVQUh2aiGfPkMLqsAcQMwQ+R0qKM/IBFzbwT4EOztaSqIHn1TE5I4IqMj6a073cuSAJl3bHLWfmGBadmnw2X5IxSunBcaj+HKiwJpMu38M0ENjxL1PSB4vqI61t+cNBXShCrzSgU0drF3zoqIAkQdct9gQStzH9QHGMtix7FPqgcCHDqGXEHnARXVqS2fQOb9iT4jdYuxFyh1wZBG2qQnikC4TXTM+6X9FA7qguBdnloMacSwnWnDgj9I7nkgmN5V9usQk5NBUnDQ3UjhzC2H3BlDQ6w3WTABZCiVdyica31IxHvpo9Ttpfk/U5KUOmCAAymbuTolKLnKtmjgIApCMB4CvbACDsX2xT/Ma2v3Aml5R6eu37+xt3J4gcKP+Njd87r7Hxq2Qpa/U/SfnN6sdR/pYKIDsyqgD8IBh03dpeDpADrgIAoAVdm/4MAAD//3+YgIK5BQAA"); err != nil { 7 | panic("add binary content to resource manager failed: " + err.Error()) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/api/v1/resource.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "gf-react-admin-server/app/model" 5 | "gf-react-admin-server/app/service" 6 | "gf-react-admin-server/library/response" 7 | "github.com/gogf/gf/errors/gerror" 8 | "github.com/gogf/gf/net/ghttp" 9 | "github.com/gogf/gf/util/gvalid" 10 | ) 11 | 12 | type resourceApi struct{} 13 | 14 | var ( 15 | Resource = &resourceApi{} 16 | ) 17 | 18 | // @summary 新建资源信息 19 | // @tags 资源管理 20 | // @produce json 21 | // @param entity body model.CreateResourceReq true "新建资源参数" 22 | // @router /v1/resource [POST] 23 | func (r *resourceApi) CreateResource(req *ghttp.Request) { 24 | createResource := &model.CreateResourceReq{} 25 | 26 | if err := req.Parse(createResource); err != nil { 27 | if _, ok := err.(*gvalid.Error); ok { 28 | // 参数校验失败 29 | response.FailCodeAndMsgExit(req, response.ParamValidErr, err.Error()) 30 | } 31 | response.FailMsgExit(req, err.Error()) 32 | } 33 | if err := service.Resource.CreateResource(createResource); err != nil { 34 | response.FailCodeAndMsgExit(req, gerror.Code(err), err.Error()) 35 | } 36 | response.SuccessMsgExit(req, "新建成功") 37 | } 38 | 39 | // @summary 编辑资源信息 40 | // @tags 资源管理 41 | // @produce json 42 | // @param entity body model.EditResourceReq true "编辑资源参数" 43 | // @router /v1/resource [PUT] 44 | func (r *resourceApi) EditResource(req *ghttp.Request) { 45 | editResourceReq := &model.EditResourceReq{} 46 | 47 | if err := req.Parse(editResourceReq); err != nil { 48 | if _, ok := err.(*gvalid.Error); ok { 49 | // 参数校验失败 50 | response.FailCodeAndMsgExit(req, response.ParamValidErr, err.Error()) 51 | } 52 | response.FailMsgExit(req, err.Error()) 53 | } 54 | if err := service.Resource.EditResource(editResourceReq); err != nil { 55 | response.FailCodeAndMsgExit(req, gerror.Code(err), err.Error()) 56 | } 57 | response.SuccessMsgExit(req, "编辑成功") 58 | } 59 | 60 | // @summary 获取资源树形结构 61 | // @tags 资源管理 62 | // @produce json 63 | // @router /v1/resource/tree [GET] 64 | func (r *resourceApi) GetResourceTree(req *ghttp.Request) { 65 | trees, err := service.Resource.GetResourceTree() 66 | if err != nil { 67 | response.FailMsgExit(req, err.Error()) 68 | } 69 | response.SuccessData(req, trees) 70 | } 71 | -------------------------------------------------------------------------------- /app/service/role.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "gf-react-admin-server/app/dao" 5 | "gf-react-admin-server/app/model" 6 | "gf-react-admin-server/library/common" 7 | "gf-react-admin-server/library/response" 8 | "github.com/gogf/gf/errors/gerror" 9 | "github.com/gogf/gf/util/gconv" 10 | ) 11 | 12 | type roleService struct{} 13 | 14 | var ( 15 | // Role 用于外部调用 16 | Role = &roleService{} 17 | ) 18 | 19 | // CreateRole 创建角色 20 | func (r *roleService) CreateRole(req *model.CreateRoleReq) error { 21 | // 判断是否已经存在该角色 22 | role, err := dao.Role.FindByNameOrAlias(req.RoleName, req.Alias) 23 | if err != nil { 24 | return err 25 | } 26 | if role != nil { 27 | return gerror.NewCode(response.DataExist, "该角色名或别名已存在,请勿重复创建。") 28 | } 29 | 30 | role = &model.Role{} 31 | err = gconv.Struct(req, role) 32 | if err != nil { 33 | return err 34 | } 35 | 36 | // 生成id 37 | id, err := common.Id.GenerateUUID() 38 | if err != nil { 39 | return err 40 | } 41 | role.Id = int64(id) 42 | // 创建角色 43 | _, err = dao.Role.Insert(role) 44 | if err != nil { 45 | return err 46 | } 47 | 48 | return nil 49 | } 50 | 51 | // EditRole 编辑角色信息 52 | func (r *roleService) EditRole(req *model.EditRoleReq) error { 53 | // 判断是否已经存在该角色 54 | role, err := dao.Role.FindByNameOrAlias(req.RoleName, req.Alias) 55 | if err != nil { 56 | return err 57 | } 58 | if role != nil && role.Id != req.Id { 59 | return gerror.NewCode(response.DataExist, "该角色名或别名已存在,请修改角色名或别名。") 60 | } 61 | 62 | err = gconv.Struct(req, role) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | // 更新角色 68 | _, err = dao.Role.Update(role, dao.Role.Columns.Id, role.Id) 69 | return err 70 | } 71 | 72 | // RolePageList 获取角色分页列表 73 | func (r *roleService) RolePageList(req *model.RoleQueryReq) (interface{}, error) { 74 | pageNo, pageSize := req.PageNo, req.PageSize 75 | total, err := dao.Role.Count() 76 | if err != nil { 77 | return nil, err 78 | } 79 | roles := make([]model.RolePageListRes, 0) 80 | err = dao.Role.Page(pageNo, pageSize).Structs(&roles) 81 | if err != nil { 82 | return nil, err 83 | } 84 | 85 | return &common.PageResult{ 86 | PageNo: pageNo, 87 | PageSize: pageSize, 88 | Total: total, 89 | Records: roles, 90 | }, nil 91 | } 92 | 93 | // RoleById 根据id获取角色信息 94 | func (r *roleService) RoleById(id int64) (role *model.RoleInfoReq, err error) { 95 | err = dao.Role.WherePri(id).Struct(&role) 96 | return 97 | } 98 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # gf-react-admin-server 2 | 3 | ## 简介 4 | 该项目为`gf-react-admin`项目对应后端项目,前端项目见[gf-react-admin](https://github.com/Riunshow/gf-react-admin),采用`Golang` + [GoFrame](https://github.com/gogf/gf) 进行开发,支持JWT鉴权、casbin权限控制。 5 | 6 | ## 主要技术 7 | - Golang 8 | - [GoFrame](https://github.com/gogf/gf) 9 | - JWT([gf-jwt](https://github.com/gogf/gf-jwt)) 10 | - [Casbin](https://github.com/casbin/casbin) 11 | - MySQL 12 | - Redis 13 | 14 | ## 项目细节 15 | ### 统一返回体 16 | 详情见项目`library`包 17 | 1. `resposne.go`文件,该文件中定义了统一的返回结构体如下: 18 | ```go 19 | type ResultRes struct { 20 | Code int `json:"code"` // response code, default: success-200 error-500 响应码 21 | Message string `json:"msg"` // response message 响应信息,若返回的是错误码,则此处对应相关错误信息 22 | Data interface{} `json:"data"` // response result data 返回数据 23 | } 24 | ``` 25 | 主要包含响应码、响应信息和相关数据,当响应码为200则表示服务正常,其余响应码对应相关错误,并会有对应的响应信息进行返回。 26 | 还定义了一些功能方法方便业务方进行调用返回,例如`Success(r *ghttp.Request)`、`SuccessExit(r *ghttp.Request)`,其中带有exit后缀的方法均表示会在返回response后退出当前HTTP执行函数 27 | 28 | 2. `page.go`定义了公共的分页返回参数结构体,并提供相关创建函数,结构体如下 29 | ```go 30 | // 分页统一返回体 31 | type PageResult struct { 32 | PageNum int `json:"pageNum"` // 分页页数 33 | PageSize int `json:"pageSize"` // 分页大小 34 | Total int `json:"total"` // 总记录数 35 | Records interface{} `json:"records"` // 对应数据 36 | } 37 | ``` 38 | ### JWT 39 | 本项目采用 [gf-jwt](https://github.com/gogf/gf-jwt) ,jwt的一些基础配置例如过期时间、签名key等都放在`config/config.toml`文件的中。jwt相关业务方发详情见`app/middleware/jwt.go`文件,该文件中的`init()`方法中初始化了 40 | gf-jwt的相关配置,通过自定义的结构体对外进行调用。`Authenticator`、`Authorization`、 41 | `Unauthorized`、`LoginResponse`分别对应了登录方法、鉴权方法、token校验失败方法、登录返回 42 | 方法,用来替换gf-jwt的对应默认方法。其他配置详情见gf-jwt的相关文档和案例。 43 | ```go 44 | // init to gf-jwt config. 进行jwt初始化 45 | func init() { 46 | // 初始化配置 47 | JwtCfg = new(JwtConfig) 48 | if err := g.Cfg().GetStruct("jwt", JwtCfg); err != nil { 49 | g.Log().Errorf("load jwt config fail, err: %v", err) 50 | } 51 | jwtMiddleware, err := jwt.New(&jwt.GfJWTMiddleware{ 52 | Realm: JwtCfg.Realm, 53 | Key: []byte(JwtCfg.SignKey), 54 | Timeout: time.Duration(JwtCfg.ExpireTime) * time.Minute, // 过期时间 55 | MaxRefresh: time.Duration(JwtCfg.RefreshTime) * time.Minute, // 刷新时间 56 | IdentityKey: JwtCfg.IdentityKey, 57 | TokenLookup: JwtCfg.TokenLookup, 58 | TokenHeadName: JwtCfg.TokenHeadName, 59 | TimeFunc: time.Now, 60 | CacheAdapter: adapter.NewRedis(g.Redis("cache")), // 采用redis替换默认的内存缓存 61 | Authenticator: Authenticator, 62 | Authorizator: Authorization, 63 | Unauthorized: Unauthorized, 64 | LoginResponse: LoginResponse, 65 | }) 66 | if err != nil { 67 | g.Log().Errorf("init jwt middleware fail, error: %v", err) 68 | } 69 | JwtMiddleware = jwtMiddleware 70 | } 71 | ``` 72 | -------------------------------------------------------------------------------- /app/api/v1/role.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "gf-react-admin-server/app/model" 5 | "gf-react-admin-server/app/service" 6 | "gf-react-admin-server/library/response" 7 | "github.com/gogf/gf/errors/gerror" 8 | "github.com/gogf/gf/net/ghttp" 9 | "github.com/gogf/gf/util/gconv" 10 | "github.com/gogf/gf/util/gvalid" 11 | ) 12 | 13 | type roleApi struct{} 14 | 15 | var ( 16 | // Role 外部调用 17 | Role = &roleApi{} 18 | ) 19 | 20 | // @summary 创建角色接口 21 | // @tags 角色服务 22 | // @produce json 23 | // @param entity body model.CreateRoleReq true "创建角色参数" 24 | // @router /v1/role [POST] 25 | func (ra *roleApi) CreateRole(r *ghttp.Request) { 26 | var createRoleReq = &model.CreateRoleReq{} 27 | if err := r.Parse(createRoleReq); err != nil { 28 | if _, ok := err.(*gvalid.Error); ok { 29 | // 参数校验失败 30 | response.FailCodeAndMsgExit(r, response.ParamValidErr, err.Error()) 31 | } 32 | response.FailMsgExit(r, err.Error()) 33 | } 34 | if err := service.Role.CreateRole(createRoleReq); err != nil { 35 | response.FailCodeAndMsgExit(r, gerror.Code(err), err.Error()) 36 | } 37 | response.SuccessMsgExit(r, "创建角色成功") 38 | } 39 | 40 | // @summary 编辑角色接口 41 | // @tags 角色服务 42 | // @produce json 43 | // @param entity body model.EditRoleReq true "编辑角色参数" 44 | // @router /v1/role [PUT] 45 | func (ra *roleApi) EditRole(r *ghttp.Request) { 46 | var editRoleReq = &model.EditRoleReq{} 47 | if err := r.ParseForm(editRoleReq); err != nil { 48 | if _, ok := err.(*gvalid.Error); ok { 49 | // 参数校验失败 50 | response.FailCodeAndMsgExit(r, response.ParamValidErr, err.Error()) 51 | } 52 | response.FailMsgExit(r, err.Error()) 53 | } 54 | if err := service.Role.EditRole(editRoleReq); err != nil { 55 | response.FailCodeAndMsgExit(r, gerror.Code(err), err.Error()) 56 | } 57 | response.SuccessMsgExit(r, "编辑角色信息成功") 58 | } 59 | 60 | // @summary 角色分页列表 61 | // @tags 角色服务 62 | // @produce json 63 | // @param entity body model.RoleQueryReq true "角色列表搜索参数" 64 | // @router /v1/role [GET] 65 | func (ra *roleApi) RolePageList(r *ghttp.Request) { 66 | var roleQueryReq = &model.RoleQueryReq{} 67 | if err := r.Parse(roleQueryReq); err != nil { 68 | if _, ok := err.(*gvalid.Error); ok { 69 | // 参数校验失败 70 | response.FailCodeAndMsgExit(r, response.ParamValidErr, err.Error()) 71 | } 72 | response.FailMsgExit(r, err.Error()) 73 | } 74 | 75 | roles, err := service.Role.RolePageList(roleQueryReq) 76 | if err != nil { 77 | response.FailCodeAndMsgExit(r, gerror.Code(err), err.Error()) 78 | } 79 | response.SuccessDataExit(r, roles) 80 | } 81 | 82 | // @summary 角色详情 83 | // @tags 角色服务 84 | // @produce json 85 | // @param id path int true "角色id" 86 | // @router /v1/role/{id} [GET] 87 | func (ra *roleApi) RoleById(r *ghttp.Request) { 88 | id := r.Get("id") 89 | if err := gvalid.Check(id, "required|integer|min:1", "角色id为空|参数类型非法|角色id长度非法"); err != nil { 90 | response.FailMsgExit(r, err.Error()) 91 | } 92 | role, err := service.Role.RoleById(gconv.Int64(id)) 93 | if err != nil { 94 | response.FailMsgExit(r, err.Error()) 95 | } 96 | response.SuccessData(r, role) 97 | } 98 | -------------------------------------------------------------------------------- /library/response/response.go: -------------------------------------------------------------------------------- 1 | package response 2 | 3 | import ( 4 | "github.com/gogf/gf/frame/g" 5 | "github.com/gogf/gf/net/ghttp" 6 | "net/http" 7 | ) 8 | 9 | var ( 10 | OK = http.StatusOK 11 | OkMessage = "正常" 12 | ERROR = http.StatusInternalServerError 13 | ErrorMessage = "服务器发生了一些错误" 14 | DataExist = 1001 // 数据已存在 15 | ParamValidErr = 1002 // 参数校验失败 16 | AccountExist = 1003 // 帐号不存在 17 | AccountValidErr = 1004 // 帐号或密码错误 18 | ) 19 | 20 | type ResultRes struct { 21 | Code int `json:"code"` // response code, default: success-200 error-500 响应码 22 | Message string `json:"msg"` // response message 响应信息,若返回的是错误码,则此处对应相关错误信息 23 | Data interface{} `json:"data"` // response result data 返回数据 24 | } 25 | 26 | // RestResult to write response, but not exit. 返回统一格式对象,但不退出。 27 | func RestResult(r *ghttp.Request, code int, msg string, data interface{}) { 28 | if err := r.Response.WriteJson(ResultRes{ 29 | Code: code, 30 | Message: msg, 31 | Data: data, 32 | }); err != nil { 33 | // response write error, print log. 返回错误,记录日志 34 | g.Log().Error(err) 35 | } 36 | } 37 | 38 | // RestResultExit to write response and exit. 返回统一格式对象,并退出。 39 | func RestResultExit(r *ghttp.Request, code int, msg string, data interface{}) { 40 | RestResult(r, code, msg, data) 41 | r.Exit() 42 | } 43 | 44 | // Success result default success message, but not exit. 返回默认成功信息,但不退出。 45 | func Success(r *ghttp.Request) { 46 | RestResult(r, OK, OkMessage, nil) 47 | } 48 | 49 | // SuccessExit result default success message and exit. 返回默认成功信息,并退出。 50 | func SuccessExit(r *ghttp.Request) { 51 | RestResultExit(r, OK, OkMessage, nil) 52 | } 53 | 54 | // SuccessMsg result success and custom message but not exit. 返回成功和自定义信息,但不退出。 55 | func SuccessMsg(r *ghttp.Request, msg string) { 56 | RestResult(r, OK, msg, nil) 57 | } 58 | 59 | // SuccessMsgExit result success and custom message and exit. 返回成功和自定义信息,并退出。 60 | func SuccessMsgExit(r *ghttp.Request, msg string) { 61 | RestResultExit(r, OK, msg, nil) 62 | } 63 | 64 | // SuccessData result success and custom data but not exit. 返回成功和数据,但不退出。 65 | func SuccessData(r *ghttp.Request, data interface{}) { 66 | RestResult(r, OK, OkMessage, data) 67 | } 68 | 69 | // SuccessDataExit result success and custom data and exit. 返回成功和数据,并退出。 70 | func SuccessDataExit(r *ghttp.Request, data interface{}) { 71 | RestResultExit(r, OK, OkMessage, data) 72 | } 73 | 74 | // Fail result default fail message, but not exit. 返回默认失败信息,但不退出。 75 | func Fail(r *ghttp.Request) { 76 | RestResult(r, ERROR, ErrorMessage, nil) 77 | } 78 | 79 | // FailExit result default fail message and exit. 返回默认失败信息,并退出。 80 | func FailExit(r *ghttp.Request) { 81 | RestResultExit(r, ERROR, ErrorMessage, nil) 82 | } 83 | 84 | // FailMsg result error and custom message but not exit. 返回失败和信息,但不退出 85 | func FailMsg(r *ghttp.Request, msg string) { 86 | RestResult(r, ERROR, msg, nil) 87 | } 88 | 89 | // FailMsgExit result error and custom message and exit. 返回失败和信息,并退出 90 | func FailMsgExit(r *ghttp.Request, msg string) { 91 | RestResultExit(r, ERROR, msg, nil) 92 | } 93 | 94 | // FailCodeAndMsg result error code and custom message but not exit. 返回失败,自定义状态码和信息,不退出 95 | func FailCodeAndMsg(r *ghttp.Request, code int, msg string) { 96 | RestResult(r, code, msg, nil) 97 | } 98 | 99 | // FailCodeAndMsgExit result error code and custom message and exit. 返回失败,自定义状态码和信息,并退出 100 | func FailCodeAndMsgExit(r *ghttp.Request, code int, msg string) { 101 | RestResultExit(r, code, msg, nil) 102 | } 103 | -------------------------------------------------------------------------------- /app/service/resource.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "gf-react-admin-server/app/dao" 5 | "gf-react-admin-server/app/model" 6 | "gf-react-admin-server/library/common" 7 | "gf-react-admin-server/library/response" 8 | "github.com/gogf/gf/errors/gerror" 9 | "github.com/gogf/gf/util/gconv" 10 | ) 11 | 12 | type resourceService struct{} 13 | 14 | var ( 15 | Resource = &resourceService{} 16 | ) 17 | 18 | // CreateResource create resource service method 19 | func (r *resourceService) CreateResource(req *model.CreateResourceReq) error { 20 | // 判断是否存在相同资源 21 | result, err := dao.Resource.FindByNameAndType(req.Name, req.Type) 22 | if err != nil { 23 | return err 24 | } 25 | if result != nil { 26 | return gerror.NewCode(response.DataExist, "该资源已存在,请勿重复创建。") 27 | } 28 | 29 | resource := &model.Resource{} 30 | err = gconv.Struct(req, resource) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | // 生成id 36 | id, err := common.Id.GenerateUUID() 37 | if err != nil { 38 | return err 39 | } 40 | resource.Id = id 41 | 42 | // 创建资源 43 | _, err = dao.Resource.Insert(resource) 44 | if err != nil { 45 | return err 46 | } 47 | 48 | return nil 49 | } 50 | 51 | // EditResource 编辑资源信息 52 | func (r *resourceService) EditResource(req *model.EditResourceReq) error { 53 | // 判断是否存在相同资源 54 | result, err := dao.Resource.FindByNameAndType(req.Name, req.Type) 55 | if err != nil { 56 | return err 57 | } 58 | if result != nil && result.Id != req.Id { 59 | return gerror.NewCode(response.DataExist, "资源名已存在,请修改资源名。") 60 | } 61 | 62 | // 更新 63 | _, err = dao.Resource.Update(req, dao.Resource.Columns.Id, req.Id) 64 | if err != nil { 65 | return err 66 | } 67 | return nil 68 | } 69 | 70 | // GetResourceTree 获取资源树形结构 71 | func (r *resourceService) GetResourceTree() (trees []common.TreeNode, err error) { 72 | resources := make([]*model.Resource, 0) 73 | err = dao.Resource.Order("sn ASC").Structs(&resources) 74 | if err != nil { 75 | return nil, err 76 | } 77 | 78 | trees = common.GenerateTree(model.GetResourceSlice(resources)) 79 | return 80 | } 81 | 82 | // GetMenuByUserId 获取用户具有的资源列表 83 | func (r *resourceService) GetMenuByUserId(userId int) ([]*model.Resource, error) { 84 | if userId <= 0 { 85 | err := gerror.New("userId不能为空") 86 | return nil, err 87 | } 88 | 89 | userRelations := ([]model.Relation)(nil) 90 | err := dao.Relation.Where(dao.Relation.Columns.UserId, userId).Structs(&userRelations) 91 | if len(userRelations) <= 0 { 92 | return nil, err 93 | } 94 | 95 | roleIds := make([]int64, 0, len(userRelations)) 96 | for _, v := range userRelations { 97 | roleIds = append(roleIds, v.RoleId) 98 | } 99 | 100 | roleResources := ([]model.RoleResource)(nil) 101 | err = dao.RoleResource.Where(dao.RoleResource.Columns.RoleId+" IN (?)", roleIds).Structs(&roleResources) 102 | if len(roleResources) <= 0 { 103 | return nil, err 104 | } 105 | 106 | resourceIds := make([]int64, 0, len(roleResources)) 107 | for _, v := range roleResources { 108 | resourceIds = append(resourceIds, v.ResourceId) 109 | } 110 | 111 | resources := make([]*model.Resource, 0) 112 | err = dao.Resource.Where("type = ?", "menu").WherePri(resourceIds).Order("sn ASC").Structs(&resources) 113 | if err != nil { 114 | return nil, err 115 | } 116 | 117 | return resources, nil 118 | } 119 | 120 | // GetMenuTreeByUserId 根据用户id获取改用户拥有的菜单资源 121 | func (r *resourceService) GetMenuTreeByUserId(userId int) (trees []common.TreeNode, err error) { 122 | resources, err := r.GetMenuByUserId(userId) 123 | if err != nil { 124 | return nil, err 125 | } 126 | 127 | trees = common.GenerateTree(model.GetResourceSlice(resources)) 128 | return 129 | } 130 | -------------------------------------------------------------------------------- /app/model/resource.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // This is auto-generated by gf cli tool. Fill this file as you wish. 3 | // ========================================================================== 4 | 5 | package model 6 | 7 | import ( 8 | "gf-react-admin-server/app/model/internal" 9 | "gf-react-admin-server/library/common" 10 | ) 11 | 12 | // Resource is the golang structure for table admin_resource. 13 | type Resource internal.Resource 14 | 15 | // Fill with you ideas below. 16 | func (r *Resource) GetPrimKey() int { 17 | return int(r.Id) 18 | } 19 | 20 | func (r *Resource) GetParentPrimKey() int { 21 | return int(r.ParentId) 22 | } 23 | 24 | func (r *Resource) GetName() string { 25 | return r.Name 26 | } 27 | 28 | func (r *Resource) GetData() interface{} { 29 | return r 30 | } 31 | 32 | func (r *Resource) Root() bool { 33 | return r.ParentId == 0 34 | } 35 | 36 | // GetResourceSlice 将菜单资源slice转换为树形结构通用slice 37 | func GetResourceSlice(data []*Resource) (iTrees []common.ITreeNode) { 38 | for _, v := range data { 39 | iTrees = append(iTrees, v) 40 | } 41 | return 42 | } 43 | 44 | // CreateResourceReq 新增资源参数 45 | type CreateResourceReq struct { 46 | ParentId int64 `json:"parentId"` // 父资源id 47 | Name string `json:"name" v:"name@required#资源名称不能为空"` // 资源名称 48 | Alias string `json:"alias"` // 资源别称 49 | Url string `json:"url"` // 资源路径 50 | Enable bool `json:"enable"` // 0:不显示,1显示 51 | Icon string `json:"icon"` // 资源图标 52 | Type string `json:"type" v:"type@required|in:menu,button,link#资源类型不能为空|请选择正确的资源类型"` // 资源类型:menu-菜单;button-按钮;link-链接 53 | Sn int `json:"sn"` // 排序 54 | } 55 | 56 | // EditResourceReq 编辑资源参数 57 | type EditResourceReq struct { 58 | Id int64 `json:"id" v:"id@required|min:1#待编辑资源id不能为空|待编辑资源id不能为空"` // 主键id 59 | ParentId int64 `json:"parentId"` // 父资源id 60 | Name string `json:"name" v:"name@required#资源名称不能为空"` // 资源名称 61 | Alias string `json:"alias"` // 资源别称 62 | Url string `json:"url"` // 资源路径 63 | Enable bool `json:"enable"` // 0:不显示,1显示 64 | Icon string `json:"icon"` // 资源图标 65 | Type string `json:"type" v:"name@required|in:menu,button,link#资源类型不能为空|请选择正确的资源类型"` // 资源类型:menu-菜单;button-按钮;link-链接 66 | Sn int `json:"sn"` // 排序 67 | } 68 | 69 | // ResourceTree 资源树形结构 70 | type ResourceTree struct { 71 | Resource 72 | Child []ResourceTree `json:"child"` // 子资源 73 | } 74 | 75 | // ResourceRoleTree 角色对应的资源树形结构 76 | type ResourceRoleTree struct { 77 | Resource 78 | Checked bool `json:"checked"` // 是否选中 79 | Child []ResourceRoleTree `json:"child"` // 子资源 80 | } 81 | 82 | // ResourceReq 资源信息 83 | type ResourceInfo struct { 84 | Id int64 `json:"id"` // 主键id 85 | ParentId int64 `json:"parentId"` // 父资源id 86 | Name string `json:"name"` // 资源名称 87 | Alias string `json:"alias"` // 资源别称 88 | Url string `json:"url"` // 资源路径 89 | Enable bool `json:"enable"` // 0:不显示,1显示 90 | Icon string `json:"icon"` // 资源图标 91 | Type string `json:"type"` // 资源类型:menu-菜单;button-按钮;link-链接 92 | Sn int `json:"sn"` // 排序 93 | } 94 | -------------------------------------------------------------------------------- /app/middleware/jwt.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "gf-react-admin-server/app/model" 5 | "gf-react-admin-server/app/service" 6 | "gf-react-admin-server/library/response" 7 | "github.com/gogf/gcache-adapter/adapter" 8 | jwt "github.com/gogf/gf-jwt" 9 | "github.com/gogf/gf/frame/g" 10 | "github.com/gogf/gf/net/ghttp" 11 | "github.com/gogf/gf/util/gconv" 12 | "time" 13 | ) 14 | 15 | type JwtConfig struct { 16 | ExpireTime int // 过期时间 17 | RefreshTime int // 刷新时间 18 | SignKey string // 签名 19 | Realm string // 域 20 | IdentityKey string // 鉴权中用户唯一标识 21 | TokenLookup string // token在请求中位置 22 | TokenHeadName string // token前缀 23 | } 24 | 25 | var ( 26 | // gf-jwt middleware. gf-jwt自带的中间件 27 | JwtMiddleware *jwt.GfJWTMiddleware 28 | // jwt config. jwt配置 29 | JwtCfg *JwtConfig 30 | errorMsg = "无访问权限" 31 | ) 32 | 33 | type loginRes struct { 34 | Token string `json:"token"` 35 | Expire time.Time `json:"expire"` 36 | } 37 | 38 | // init to gf-jwt config. 进行jwt初始化 39 | func init() { 40 | // 初始化配置 41 | JwtCfg = new(JwtConfig) 42 | if err := g.Cfg().GetStruct("jwt", JwtCfg); err != nil { 43 | g.Log().Errorf("load jwt config fail, err: %v", err) 44 | } 45 | jwtMiddleware, err := jwt.New(&jwt.GfJWTMiddleware{ 46 | Realm: JwtCfg.Realm, 47 | Key: []byte(JwtCfg.SignKey), 48 | Timeout: time.Duration(JwtCfg.ExpireTime) * time.Minute, // 过期时间 49 | MaxRefresh: time.Duration(JwtCfg.RefreshTime) * time.Minute, // 刷新时间 50 | IdentityKey: JwtCfg.IdentityKey, 51 | TokenLookup: JwtCfg.TokenLookup, 52 | TokenHeadName: JwtCfg.TokenHeadName, 53 | TimeFunc: time.Now, 54 | CacheAdapter: adapter.NewRedis(g.Redis("cache")), // 采用redis替换默认的内存缓存 55 | Authenticator: Authenticator, 56 | PayloadFunc: PayloadFunc, 57 | Authorizator: Authorization, 58 | Unauthorized: Unauthorized, 59 | LoginResponse: LoginResponse, 60 | }) 61 | if err != nil { 62 | g.Log().Errorf("init jwt middleware fail, error: %v", err) 63 | } 64 | JwtMiddleware = jwtMiddleware 65 | } 66 | 67 | //TODO Authenticator user login valid, and return userInfo. 进行登录校验,返回用户信息、错误 68 | // @summary 登录 69 | // @tags 用户服务 70 | // @produce json 71 | // @param entity body model.UserLoginReq true "登录参数" 72 | // @router /v1/user/login [POST] 73 | func Authenticator(r *ghttp.Request) (interface{}, error) { 74 | var ( 75 | loginReg *model.UserLoginReq 76 | ) 77 | if err := r.Parse(&loginReg); err != nil { 78 | g.Log().Errorf("登录失败,err:[%v]", err) 79 | response.FailMsgExit(r, err.Error()) 80 | } 81 | loginRes, err := service.User.Login(loginReg) 82 | return gconv.Map(&loginRes), err 83 | } 84 | 85 | // PayloadFunc customer info to jwt. 放入自定义信息到jwt的claims中 86 | func PayloadFunc(data interface{}) jwt.MapClaims { 87 | claims := jwt.MapClaims{} 88 | params := data.(map[string]interface{}) 89 | if len(params) > 0 { 90 | for k, v := range params { 91 | claims[k] = v 92 | } 93 | } 94 | return claims 95 | } 96 | 97 | //TODO Authorization check user auth role by IdentityHandler func. 根据IdentityHandler方法返回的信息检查用户权限,返回false则检查失败 98 | func Authorization(data interface{}, r *ghttp.Request) bool { 99 | return true 100 | } 101 | 102 | // Unauthorized custom unauthorized result. 自定义无权限返回方法 103 | func Unauthorized(r *ghttp.Request, code int, message string) { 104 | g.Log().Warningf("访问失败,错误码:[%v], 错误信息:[%v], 请求路径:[%v],请求方法:[%v], router-method:[%v], router-uri:[%v], router-regNames [%v], router-regRule:[%v]", 105 | code, message, 106 | r.RequestURI, r.Method, r.Router.Method, r.Router.Uri, r.Router.RegNames, r.Router.RegRule) 107 | if message == "" { 108 | message = errorMsg 109 | } 110 | response.FailCodeAndMsgExit(r, code, message) 111 | } 112 | 113 | // LoginResponse custom callback login response. 自定义登录返回方法 114 | func LoginResponse(r *ghttp.Request, code int, token string, expire time.Time) { 115 | response.RestResultExit(r, code, "", &loginRes{ 116 | Token: token, 117 | Expire: expire, 118 | }) 119 | } 120 | 121 | // JwtAuth request head token valid. 检查请求中的token合法性 122 | func JwtAuth(r *ghttp.Request) { 123 | JwtMiddleware.MiddlewareFunc()(r) 124 | r.Middleware.Next() 125 | } 126 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /swagger/swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "contact": {} 5 | }, 6 | "paths": { 7 | "/v1/relation": { 8 | "put": { 9 | "produces": [ 10 | "application/json" 11 | ], 12 | "tags": [ 13 | "用户关系服务" 14 | ], 15 | "summary": "保存用户关系", 16 | "parameters": [ 17 | { 18 | "description": "保存用户关系参数", 19 | "name": "entity", 20 | "in": "body", 21 | "required": true, 22 | "schema": { 23 | "$ref": "#/definitions/model.SaveRelationReq" 24 | } 25 | } 26 | ] 27 | } 28 | }, 29 | "/v1/resource": { 30 | "put": { 31 | "produces": [ 32 | "application/json" 33 | ], 34 | "tags": [ 35 | "资源管理" 36 | ], 37 | "summary": "编辑资源信息", 38 | "parameters": [ 39 | { 40 | "description": "编辑资源参数", 41 | "name": "entity", 42 | "in": "body", 43 | "required": true, 44 | "schema": { 45 | "$ref": "#/definitions/model.EditResourceReq" 46 | } 47 | } 48 | ] 49 | }, 50 | "post": { 51 | "produces": [ 52 | "application/json" 53 | ], 54 | "tags": [ 55 | "资源管理" 56 | ], 57 | "summary": "新建资源信息", 58 | "parameters": [ 59 | { 60 | "description": "新建资源参数", 61 | "name": "entity", 62 | "in": "body", 63 | "required": true, 64 | "schema": { 65 | "$ref": "#/definitions/model.CreateResourceReq" 66 | } 67 | } 68 | ] 69 | } 70 | }, 71 | "/v1/resource/tree": { 72 | "get": { 73 | "produces": [ 74 | "application/json" 75 | ], 76 | "tags": [ 77 | "资源管理" 78 | ], 79 | "summary": "获取资源树形结构" 80 | } 81 | }, 82 | "/v1/role": { 83 | "get": { 84 | "produces": [ 85 | "application/json" 86 | ], 87 | "tags": [ 88 | "角色服务" 89 | ], 90 | "summary": "角色分页列表", 91 | "parameters": [ 92 | { 93 | "description": "角色列表搜索参数", 94 | "name": "entity", 95 | "in": "body", 96 | "required": true, 97 | "schema": { 98 | "$ref": "#/definitions/model.RoleQueryReq" 99 | } 100 | } 101 | ] 102 | }, 103 | "put": { 104 | "produces": [ 105 | "application/json" 106 | ], 107 | "tags": [ 108 | "角色服务" 109 | ], 110 | "summary": "编辑角色接口", 111 | "parameters": [ 112 | { 113 | "description": "编辑角色参数", 114 | "name": "entity", 115 | "in": "body", 116 | "required": true, 117 | "schema": { 118 | "$ref": "#/definitions/model.EditRoleReq" 119 | } 120 | } 121 | ] 122 | }, 123 | "post": { 124 | "produces": [ 125 | "application/json" 126 | ], 127 | "tags": [ 128 | "角色服务" 129 | ], 130 | "summary": "创建角色接口", 131 | "parameters": [ 132 | { 133 | "description": "创建角色参数", 134 | "name": "entity", 135 | "in": "body", 136 | "required": true, 137 | "schema": { 138 | "$ref": "#/definitions/model.CreateRoleReq" 139 | } 140 | } 141 | ] 142 | } 143 | }, 144 | "/v1/role/{id}": { 145 | "get": { 146 | "produces": [ 147 | "application/json" 148 | ], 149 | "tags": [ 150 | "角色服务" 151 | ], 152 | "summary": "角色详情", 153 | "parameters": [ 154 | { 155 | "type": "integer", 156 | "description": "角色id", 157 | "name": "id", 158 | "in": "path", 159 | "required": true 160 | } 161 | ] 162 | } 163 | }, 164 | "/v1/user/login": { 165 | "post": { 166 | "produces": [ 167 | "application/json" 168 | ], 169 | "tags": [ 170 | "用户服务" 171 | ], 172 | "summary": "登录", 173 | "parameters": [ 174 | { 175 | "description": "登录参数", 176 | "name": "entity", 177 | "in": "body", 178 | "required": true, 179 | "schema": { 180 | "$ref": "#/definitions/model.UserLoginReq" 181 | } 182 | } 183 | ] 184 | } 185 | }, 186 | "/v1/user/{id}": { 187 | "get": { 188 | "produces": [ 189 | "application/json" 190 | ], 191 | "tags": [ 192 | "用户服务" 193 | ], 194 | "summary": "用户详情", 195 | "parameters": [ 196 | { 197 | "type": "integer", 198 | "description": "用户id", 199 | "name": "id", 200 | "in": "path", 201 | "required": true 202 | } 203 | ] 204 | } 205 | } 206 | }, 207 | "definitions": { 208 | "model.CreateResourceReq": { 209 | "type": "object", 210 | "properties": { 211 | "alias": { 212 | "description": "资源别称", 213 | "type": "string" 214 | }, 215 | "enable": { 216 | "description": "0:不显示,1显示", 217 | "type": "boolean" 218 | }, 219 | "icon": { 220 | "description": "资源图标", 221 | "type": "string" 222 | }, 223 | "name": { 224 | "description": "资源名称", 225 | "type": "string" 226 | }, 227 | "parentId": { 228 | "description": "父资源id", 229 | "type": "integer" 230 | }, 231 | "sn": { 232 | "description": "排序", 233 | "type": "integer" 234 | }, 235 | "type": { 236 | "description": "资源类型:menu-菜单;button-按钮;link-链接", 237 | "type": "string" 238 | }, 239 | "url": { 240 | "description": "资源路径", 241 | "type": "string" 242 | } 243 | } 244 | }, 245 | "model.CreateRoleReq": { 246 | "type": "object", 247 | "properties": { 248 | "alias": { 249 | "description": "角色别名", 250 | "type": "string" 251 | }, 252 | "parentId": { 253 | "description": "父角色id", 254 | "type": "string" 255 | }, 256 | "roleName": { 257 | "description": "角色名称", 258 | "type": "string" 259 | } 260 | } 261 | }, 262 | "model.EditResourceReq": { 263 | "type": "object", 264 | "properties": { 265 | "alias": { 266 | "description": "资源别称", 267 | "type": "string" 268 | }, 269 | "enable": { 270 | "description": "0:不显示,1显示", 271 | "type": "boolean" 272 | }, 273 | "icon": { 274 | "description": "资源图标", 275 | "type": "string" 276 | }, 277 | "id": { 278 | "description": "主键id", 279 | "type": "integer" 280 | }, 281 | "name": { 282 | "description": "资源名称", 283 | "type": "string" 284 | }, 285 | "parentId": { 286 | "description": "父资源id", 287 | "type": "integer" 288 | }, 289 | "sn": { 290 | "description": "排序", 291 | "type": "integer" 292 | }, 293 | "type": { 294 | "description": "资源类型:menu-菜单;button-按钮;link-链接", 295 | "type": "string" 296 | }, 297 | "url": { 298 | "description": "资源路径", 299 | "type": "string" 300 | } 301 | } 302 | }, 303 | "model.EditRoleReq": { 304 | "type": "object", 305 | "properties": { 306 | "alias": { 307 | "description": "角色别名", 308 | "type": "string" 309 | }, 310 | "id": { 311 | "description": "角色id", 312 | "type": "integer" 313 | }, 314 | "parentId": { 315 | "description": "父角色id", 316 | "type": "string" 317 | }, 318 | "roleName": { 319 | "description": "角色名称", 320 | "type": "string" 321 | } 322 | } 323 | }, 324 | "model.RoleQueryReq": { 325 | "type": "object", 326 | "properties": { 327 | "pageNo": { 328 | "description": "分页页数", 329 | "type": "integer" 330 | }, 331 | "pageSize": { 332 | "description": "分页大小", 333 | "type": "integer" 334 | } 335 | } 336 | }, 337 | "model.SaveRelationReq": { 338 | "type": "object", 339 | "properties": { 340 | "roleIds": { 341 | "description": "角色id slice", 342 | "type": "array", 343 | "items": { 344 | "type": "integer" 345 | } 346 | }, 347 | "userId": { 348 | "description": "用户id", 349 | "type": "integer" 350 | } 351 | } 352 | }, 353 | "model.UserLoginReq": { 354 | "type": "object", 355 | "properties": { 356 | "account": { 357 | "description": "账号", 358 | "type": "string" 359 | }, 360 | "password": { 361 | "description": "密码", 362 | "type": "string" 363 | } 364 | } 365 | } 366 | } 367 | } -------------------------------------------------------------------------------- /app/dao/internal/role.go: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // This is auto-generated by gf cli tool. DO NOT EDIT THIS FILE MANUALLY. 3 | // ========================================================================== 4 | 5 | package internal 6 | 7 | import ( 8 | "context" 9 | "database/sql" 10 | "github.com/gogf/gf/database/gdb" 11 | "github.com/gogf/gf/frame/g" 12 | "github.com/gogf/gf/frame/gmvc" 13 | "time" 14 | 15 | "gf-react-admin-server/app/model" 16 | ) 17 | 18 | // RoleDao is the manager for logic model data accessing 19 | // and custom defined data operations functions management. 20 | type RoleDao struct { 21 | gmvc.M 22 | DB gdb.DB 23 | Table string 24 | Columns roleColumns 25 | } 26 | 27 | // RoleColumns defines and stores column names for table admin_role. 28 | type roleColumns struct { 29 | Id string // 30 | ParentId string // 父角色id 31 | RoleName string // 角色名称 32 | Alias string // 角色别名 33 | CreatedAt string // 创建时间 34 | UpdatedAt string // 更新时间 35 | DeletedAt string // 删除时间时间 36 | } 37 | 38 | var ( 39 | // Role is globally public accessible object for table admin_role operations. 40 | Role = &RoleDao{ 41 | M: g.DB("default").Model("admin_role").Safe(), 42 | DB: g.DB("default"), 43 | Table: "admin_role", 44 | Columns: roleColumns{ 45 | Id: "id", 46 | ParentId: "parent_id", 47 | RoleName: "role_name", 48 | Alias: "alias", 49 | CreatedAt: "created_at", 50 | UpdatedAt: "updated_at", 51 | DeletedAt: "deleted_at", 52 | }, 53 | } 54 | ) 55 | 56 | // Ctx is a chaining function, which creates and returns a new DB that is a shallow copy 57 | // of current DB object and with given context in it. 58 | // Note that this returned DB object can be used only once, so do not assign it to 59 | // a global or package variable for long using. 60 | func (d *RoleDao) Ctx(ctx context.Context) *RoleDao { 61 | return &RoleDao{M: d.M.Ctx(ctx)} 62 | } 63 | 64 | // As sets an alias name for current table. 65 | func (d *RoleDao) As(as string) *RoleDao { 66 | return &RoleDao{M: d.M.As(as)} 67 | } 68 | 69 | // TX sets the transaction for current operation. 70 | func (d *RoleDao) TX(tx *gdb.TX) *RoleDao { 71 | return &RoleDao{M: d.M.TX(tx)} 72 | } 73 | 74 | // Master marks the following operation on master node. 75 | func (d *RoleDao) Master() *RoleDao { 76 | return &RoleDao{M: d.M.Master()} 77 | } 78 | 79 | // Slave marks the following operation on slave node. 80 | // Note that it makes sense only if there's any slave node configured. 81 | func (d *RoleDao) Slave() *RoleDao { 82 | return &RoleDao{M: d.M.Slave()} 83 | } 84 | 85 | // Args sets custom arguments for model operation. 86 | func (d *RoleDao) Args(args ...interface{}) *RoleDao { 87 | return &RoleDao{M: d.M.Args(args...)} 88 | } 89 | 90 | // LeftJoin does "LEFT JOIN ... ON ..." statement on the model. 91 | // The parameter