├── app ├── model │ ├── menu_meta.go │ ├── role_menu.go │ ├── role_menu_auto_create.go │ ├── role_name_auto_create.go │ ├── menu_meta_auto_create.go │ ├── policy_name_auto_create.go │ ├── menu_auto_create.go │ ├── user_auto_create.go │ ├── model.go │ ├── user.go │ ├── policy.go │ ├── role.go │ ├── casbin_adapter.go │ └── menu.go ├── service │ └── baseService.go └── api │ ├── baseController.go │ ├── policyController.go │ ├── roleController.go │ ├── menuController.go │ ├── userController.go │ └── auth.go ├── static ├── robots.txt ├── img │ ├── 401.089007e7.gif │ ├── 404.a57b6f31.png │ └── 404_cloud.0f4bc32b.png ├── fonts │ ├── element-icons.6f0a7632.ttf │ └── element-icons.2fad952a.woff ├── css │ ├── chunk-296d0504.a19c2bc2.css │ ├── chunk-2e555135.76ea626a.css │ ├── chunk-3296490b.9d63d053.css │ ├── chunk-7670121b.9d63d053.css │ ├── chunk-6a4eb3ee.50ac9a65.css │ ├── chunk-cbf46a0a.c19e23ad.css │ ├── chunk-libs.3dfb7769.css │ ├── chunk-2a330e22.d5adff47.css │ ├── chunk-015d6b7a.0a66699f.css │ └── chunk-508832c0.fed07099.css └── js │ ├── chunk-2d230fe7.9bb0c7e2.js │ ├── chunk-2d2105d3.ce6e26e5.js │ ├── chunk-508832c0.eea072a2.js │ ├── chunk-2e555135.9e9541fc.js │ ├── chunk-cbf46a0a.daf42114.js │ ├── chunk-2a330e22.9d637d72.js │ ├── chunk-296d0504.61c10fec.js │ ├── chunk-015d6b7a.3faa4a94.js │ ├── chunk-3296490b.44372469.js │ ├── chunk-7670121b.23245917.js │ └── chunk-6a4eb3ee.9b859229.js ├── docfile ├── showApiWithSwagger.bat ├── gadmin.png ├── tools │ └── codeCreater │ │ └── xorm │ │ ├── templates │ │ ├── extend │ │ │ ├── extend.go.tpl │ │ │ └── config │ │ └── struct │ │ │ ├── config │ │ │ └── structs.go.tpl │ │ ├── create_extend.bat │ │ ├── create_struct.bat │ │ └── readme.txt ├── sql │ ├── role_menu.sql │ ├── role_name.sql │ ├── policy_name.sql │ ├── menu_meta.sql │ ├── casbin_rule.sql │ ├── menu.sql │ ├── user.sql │ └── all.sql └── swagger.yaml ├── favicon.ico ├── vendor.bat ├── library ├── code │ └── code.go ├── timer │ └── timer.go ├── logger │ └── logger.go └── common │ ├── common.go │ └── rsa.go ├── go.mod ├── .gitignore ├── config ├── rbac.conf └── config.default.toml ├── main.go ├── readme.md ├── index.html ├── router └── router.go └── go.sum /app/model/menu_meta.go: -------------------------------------------------------------------------------- 1 | package model 2 | -------------------------------------------------------------------------------- /app/service/baseService.go: -------------------------------------------------------------------------------- 1 | package service 2 | -------------------------------------------------------------------------------- /static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / -------------------------------------------------------------------------------- /docfile/showApiWithSwagger.bat: -------------------------------------------------------------------------------- 1 | swagger serve -F=swagger swagger.yaml -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailaz/gadmin/HEAD/favicon.ico -------------------------------------------------------------------------------- /docfile/gadmin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailaz/gadmin/HEAD/docfile/gadmin.png -------------------------------------------------------------------------------- /docfile/tools/codeCreater/xorm/templates/extend/extend.go.tpl: -------------------------------------------------------------------------------- 1 | package {{.Models}} 2 | 3 | -------------------------------------------------------------------------------- /static/img/401.089007e7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailaz/gadmin/HEAD/static/img/401.089007e7.gif -------------------------------------------------------------------------------- /static/img/404.a57b6f31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailaz/gadmin/HEAD/static/img/404.a57b6f31.png -------------------------------------------------------------------------------- /vendor.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo will delete vendor dir... 3 | rd /s vendor 4 | go mod vendor 5 | @pause -------------------------------------------------------------------------------- /docfile/tools/codeCreater/xorm/templates/extend/config: -------------------------------------------------------------------------------- 1 | lang=go 2 | genJson=1 3 | prefix=cos_ 4 | postfix= -------------------------------------------------------------------------------- /static/img/404_cloud.0f4bc32b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailaz/gadmin/HEAD/static/img/404_cloud.0f4bc32b.png -------------------------------------------------------------------------------- /static/fonts/element-icons.6f0a7632.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailaz/gadmin/HEAD/static/fonts/element-icons.6f0a7632.ttf -------------------------------------------------------------------------------- /docfile/tools/codeCreater/xorm/templates/struct/config: -------------------------------------------------------------------------------- 1 | lang=go 2 | genJson=1 3 | genOrmType= 4 | prefix=cos_ 5 | postfix=_auto_create -------------------------------------------------------------------------------- /static/fonts/element-icons.2fad952a.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hailaz/gadmin/HEAD/static/fonts/element-icons.2fad952a.woff -------------------------------------------------------------------------------- /docfile/tools/codeCreater/xorm/create_extend.bat: -------------------------------------------------------------------------------- 1 | xorm reverse mysql root:root123@tcp(localhost:33061)/gadmin?charset=utf8 .\templates\extend .\model -------------------------------------------------------------------------------- /library/code/code.go: -------------------------------------------------------------------------------- 1 | package code 2 | 3 | const ( 4 | RESPONSE_ERROR = -1 5 | RESPONSE_IllegalToken = 50008 6 | RESPONSE_SUCCESS = 20000 7 | ) 8 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hailaz/gadmin 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/casbin/casbin v1.9.1 7 | github.com/gogf/gf v1.11.3 8 | github.com/gogf/gf-jwt v1.1.0 9 | ) 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | docfile/tools/codeCreater/xorm/model/* 2 | 3 | #编译的可执行文件 4 | *.exe 5 | *.exe~ 6 | 7 | #日志文件 8 | *.log 9 | 10 | 11 | debug 12 | .vscode/* 13 | .idea/* 14 | run.bat 15 | mod.bat 16 | config/config.toml 17 | debug.bat 18 | -------------------------------------------------------------------------------- /docfile/tools/codeCreater/xorm/create_struct.bat: -------------------------------------------------------------------------------- 1 | xorm reverse mysql root:root123@tcp(localhost:33061)/gadmin?charset=utf8 .\templates\struct .\model 2 | ::xorm reverse mysql root:root123@tcp(localhost:33061)/gadmin?charset=utf8 .\templates\struct .\models "^xxx$|^xxx$|^xxx$" 3 | @pause -------------------------------------------------------------------------------- /static/css/chunk-296d0504.a19c2bc2.css: -------------------------------------------------------------------------------- 1 | .pagination-container[data-v-f3b72548]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-f3b72548]{display:none}.edit-input[data-v-b1948282]{padding-right:100px}.cancel-btn[data-v-b1948282]{position:absolute;right:15px;top:10px} -------------------------------------------------------------------------------- /config/rbac.conf: -------------------------------------------------------------------------------- 1 | [request_definition] 2 | r = sub, obj, act 3 | 4 | [policy_definition] 5 | p = sub, obj, act 6 | 7 | [role_definition] 8 | g = _, _ 9 | 10 | [policy_effect] 11 | e = some(where (p.eft == allow)) 12 | 13 | [matchers] 14 | m = (g(r.sub, p.sub)||keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act) -------------------------------------------------------------------------------- /library/timer/timer.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/gogf/gf/os/gtimer" 7 | "github.com/hailaz/gadmin/library/common" 8 | ) 9 | 10 | // InitTimer 初始化定时任务 11 | // 12 | // createTime:2019年04月24日 14:50:34 13 | // author:hailaz 14 | func InitTimer() { 15 | 16 | gtimer.Add(time.Minute, common.RemoveTimeoutCryptoKey) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /config/config.default.toml: -------------------------------------------------------------------------------- 1 | #监听端口 2 | port = 8199 3 | 4 | #日志目录,默认log目录 5 | logpath = "log" 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | #数据库 14 | [database] 15 | [[database.default]] 16 | host = "localhost" 17 | port = "33061" 18 | user = "root" 19 | pass = "root123" 20 | name = "gadmin" 21 | type = "mysql" -------------------------------------------------------------------------------- /static/js/chunk-2d230fe7.9bb0c7e2.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d230fe7"],{ef3c:function(e,r,n){"use strict";n.r(r);n("a481");var t,u,a={created:function(){var e=this.$route,r=e.params,n=e.query,t=r.path;this.$router.replace({path:"/"+t,query:n})},render:function(e){return e()}},c=a,o=n("2877"),p=Object(o["a"])(c,t,u,!1,null,null,null);r["default"]=p.exports}}]); -------------------------------------------------------------------------------- /library/logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "github.com/gogf/gf/frame/g" 5 | "github.com/gogf/gf/os/glog" 6 | ) 7 | 8 | // InitLogger 初始化日志设置 9 | // 10 | // createTime:2019年05月13日 09:46:02 11 | // author:hailaz 12 | func InitLogger() { 13 | path := g.Config().GetString("logpath", "log") 14 | glog.SetPath(path) 15 | glog.SetFlags(glog.F_TIME_STD | glog.F_FILE_SHORT) 16 | } 17 | -------------------------------------------------------------------------------- /static/js/chunk-2d2105d3.ce6e26e5.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d2105d3"],{b829:function(n,e,o){"use strict";o.r(e);o("386d");var t,c,a={name:"AuthRedirect",created:function(){var n=window.location.search.slice(1);window.localStorage&&(window.localStorage.setItem("x-admin-oauth-code",n),window.close())},render:function(n){return n()}},d=a,i=o("2877"),l=Object(i["a"])(d,t,c,!1,null,null,null);e["default"]=l.exports}}]); -------------------------------------------------------------------------------- /library/common/common.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/hailaz/gadmin/app/model" 7 | ) 8 | 9 | func GetAction(act string) string { 10 | acts := strings.Split(strings.Split(strings.Split(act, ";")[0], ":")[0], ",") 11 | action := "" 12 | for _, v := range acts { 13 | if v == "All" || v == "REST" { 14 | return model.ACTION_ALL 15 | } 16 | if action == "" { 17 | action += strings.ToUpper("(" + v + ")") 18 | } else { 19 | action += strings.ToUpper("|(" + v + ")") 20 | } 21 | 22 | } 23 | return action 24 | } 25 | -------------------------------------------------------------------------------- /app/model/role_menu.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/gogf/gf/database/gdb" 5 | ) 6 | 7 | // DeleteRoleMenus description 8 | // 9 | // createTime:2019年05月21日 17:52:06 10 | // author:hailaz 11 | func DeleteRoleMenus(role string) { 12 | defDB.Delete("role_menu", "role_key=?", role) 13 | } 14 | 15 | // SetRoleMenus description 16 | // 17 | // createTime:2019年05月21日 17:54:38 18 | // author:hailaz 19 | func SetRoleMenus(role string, menus []string) { 20 | DeleteRoleMenus(role) 21 | ms := make(gdb.List, 0) 22 | for _, item := range menus { 23 | ms = append(ms, gdb.Map{"role_key": role, "menu_name": item}) 24 | } 25 | 26 | defDB.Table("role_menu").Data(ms).Insert() 27 | } 28 | -------------------------------------------------------------------------------- /docfile/tools/codeCreater/xorm/readme.txt: -------------------------------------------------------------------------------- 1 | 使用xorm工具,根据数据库自动生成 go 代码 - artong0416 - 博客园 https://www.cnblogs.com/artong0416/p/7456674.html 2 | go get github.com/go-xorm/cmd/xorm 3 | 4 | go get github.com/go-sql-driver/mysql //MyMysql 5 | go get github.com/ziutek/mymysql/godrv //MyMysql 6 | go get github.com/lib/pq //Postgres 7 | go get github.com/mattn/go-sqlite3 //SQLite 8 | 9 | go get github.com/go-xorm/xorm 10 | 11 | 12 | 编译github.com/go-xorm/cmd/xorm时需要cloud.google.com/go/civil 13 | 但因墙无法下载,所以手动使用以下地址: 14 | https://github.com/GoogleCloudPlatform/google-cloud-go 15 | 16 | git clone https://github.com/GoogleCloudPlatform/google-cloud-go.git 17 | 18 | 19 | 环境配置好后使用 20 | build.go 21 | created.bat即可 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /static/css/chunk-2e555135.76ea626a.css: -------------------------------------------------------------------------------- 1 | .errPage-container[data-v-2c77c6fb]{width:800px;max-width:100%;margin:100px auto}.errPage-container .pan-back-btn[data-v-2c77c6fb]{background:#008489;color:#fff;border:none!important}.errPage-container .pan-gif[data-v-2c77c6fb]{margin:0 auto;display:block}.errPage-container .pan-img[data-v-2c77c6fb]{display:block;margin:0 auto;width:100%}.errPage-container .text-jumbo[data-v-2c77c6fb]{font-size:60px;font-weight:700;color:#484848}.errPage-container .list-unstyled[data-v-2c77c6fb]{font-size:14px}.errPage-container .list-unstyled li[data-v-2c77c6fb]{padding-bottom:5px}.errPage-container .list-unstyled a[data-v-2c77c6fb]{color:#008489;text-decoration:none}.errPage-container .list-unstyled a[data-v-2c77c6fb]:hover{text-decoration:underline} -------------------------------------------------------------------------------- /static/css/chunk-3296490b.9d63d053.css: -------------------------------------------------------------------------------- 1 | .waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-f3b72548]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-f3b72548]{display:none} -------------------------------------------------------------------------------- /static/css/chunk-7670121b.9d63d053.css: -------------------------------------------------------------------------------- 1 | .waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-f3b72548]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-f3b72548]{display:none} -------------------------------------------------------------------------------- /static/css/chunk-6a4eb3ee.50ac9a65.css: -------------------------------------------------------------------------------- 1 | .waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-f3b72548]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-f3b72548]{display:none}.app-container .permission-tree[data-v-0c8289ae]{margin-bottom:30px} -------------------------------------------------------------------------------- /docfile/sql/role_menu.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : localhost 5 | Source Server Type : MySQL 6 | Source Server Version : 50542 7 | Source Host : localhost:33061 8 | Source Schema : gadmin 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 50542 12 | File Encoding : 65001 13 | 14 | Date: 16/05/2019 15:10:35 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for role_menu 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `role_menu`; 24 | CREATE TABLE `role_menu` ( 25 | `id` int(11) NOT NULL AUTO_INCREMENT, 26 | `role_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色key', 27 | `menu_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '菜单关键名', 28 | PRIMARY KEY (`id`) USING BTREE 29 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 30 | 31 | SET FOREIGN_KEY_CHECKS = 1; 32 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gogf/gf/frame/g" 5 | "github.com/gogf/gf/os/gcmd" 6 | "github.com/gogf/gf/os/gfile" 7 | "github.com/gogf/gf/os/glog" 8 | "github.com/hailaz/gadmin/app/model" 9 | "github.com/hailaz/gadmin/library/logger" 10 | "github.com/hailaz/gadmin/library/timer" 11 | "github.com/hailaz/gadmin/router" 12 | ) 13 | 14 | func init() { 15 | cfg := gcmd.GetOpt("c", "config.default.toml") 16 | 17 | if !gfile.Exists(cfg) && !gfile.Exists("config/"+cfg) { 18 | glog.Fatalf("config file(%s) no exist", cfg) 19 | } 20 | 21 | // 设置默认配置文件,默认的 config.toml 将会被覆盖 22 | g.Config().SetFileName(cfg) 23 | 24 | // 初始化日志 25 | logger.InitLogger() 26 | 27 | // 测试数据库 28 | err := g.DB().PingMaster() 29 | if err != nil { 30 | glog.Fatalf("DB err:%v", err) 31 | } 32 | 33 | // 初始化数据库 34 | model.InitModel() 35 | 36 | timer.InitTimer() 37 | 38 | } 39 | 40 | func main() { 41 | s := g.Server() 42 | s.SetIndexFolder(false) 43 | s.SetIndexFiles([]string{"index.html"}) 44 | s.SetServerRoot(".") 45 | // 初始化路由 46 | router.InitRouter(s) 47 | 48 | s.SetPort(g.Config().GetInt("port", 8080)) 49 | s.Run() 50 | 51 | } 52 | -------------------------------------------------------------------------------- /docfile/sql/role_name.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : localhost 5 | Source Server Type : MySQL 6 | Source Server Version : 50542 7 | Source Host : localhost:33061 8 | Source Schema : gadmin 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 50542 12 | File Encoding : 65001 13 | 14 | Date: 16/05/2019 15:07:50 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for role_name 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `role_name`; 24 | CREATE TABLE `role_name` ( 25 | `id` int(11) NOT NULL AUTO_INCREMENT, 26 | `role_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '角色key', 27 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '角色名', 28 | `descrption` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '描述', 29 | PRIMARY KEY (`id`) USING BTREE, 30 | UNIQUE INDEX `role_key_index`(`role_key`) USING BTREE 31 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 32 | 33 | SET FOREIGN_KEY_CHECKS = 1; 34 | -------------------------------------------------------------------------------- /docfile/sql/policy_name.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : localhost 5 | Source Server Type : MySQL 6 | Source Server Version : 50542 7 | Source Host : localhost:33061 8 | Source Schema : gadmin 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 50542 12 | File Encoding : 65001 13 | 14 | Date: 16/05/2019 15:07:34 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for policy_name 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `policy_name`; 24 | CREATE TABLE `policy_name` ( 25 | `id` int(11) NOT NULL AUTO_INCREMENT, 26 | `full_path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '权限完整路径', 27 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '权限名称', 28 | `descrption` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '描述', 29 | PRIMARY KEY (`id`) USING BTREE, 30 | UNIQUE INDEX `full_path_index`(`full_path`) USING BTREE 31 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 32 | 33 | SET FOREIGN_KEY_CHECKS = 1; 34 | -------------------------------------------------------------------------------- /docfile/sql/menu_meta.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : localhost 5 | Source Server Type : MySQL 6 | Source Server Version : 50542 7 | Source Host : localhost:33061 8 | Source Schema : gadmin 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 50542 12 | File Encoding : 65001 13 | 14 | Date: 16/05/2019 15:57:56 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for menu_meta 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `menu_meta`; 24 | CREATE TABLE `menu_meta` ( 25 | `id` int(11) NOT NULL AUTO_INCREMENT, 26 | `menu_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '菜单关键名', 27 | `title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '名称', 28 | `icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '图标', 29 | `nocache` tinyint(1) NULL DEFAULT 0 COMMENT '是否缓存', 30 | PRIMARY KEY (`id`) USING BTREE, 31 | UNIQUE INDEX `key_name`(`menu_name`) USING BTREE 32 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 33 | 34 | SET FOREIGN_KEY_CHECKS = 1; 35 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | #### 项目不定期更新 2 | 3 | 4 | ### 简要说明 5 | 6 | 基于GoFrame框架的前后端分离管理后台,项目首次启动会自动插入管理员用户。 7 | 8 | #### 使用方式 9 | 10 | 1. 准备数据库,数据结构在[docfile/sql](https://github.com/hailaz/gadmin/tree/master/docfile/sql)目录下,all.sql是全部结构。 11 | 2. 修改配置文件config/default.toml,也可指定其它配置文件 -c=xxx.toml 12 | 3. 启动编译后的二进制文件 13 | 4. 访问[http://localhost:8199](http://localhost:8199) 14 | 用户名:admin 15 | 密码:123456 16 | 17 | **当前项目已包含构建后的前端文件。** 未构建的前端项目地址:[gadmin-vue](https://github.com/hailaz/gadmin-vue) 18 | 19 | #### 自述 20 | 第一次设计,整体结构可能有些问题,望见谅,要是能给我个建议什么的就更好了。有bug可以提个issues。 21 | 22 | ![gadmin](/docfile/gadmin.png) 23 | 24 | 25 | ---- 26 | 27 | ### 技术栈 28 | 29 | #### 后端 30 | 31 | 框架:[GoFrame](https://github.com/gogf/gf) 32 | 33 | 登录加密:RSA 34 | 35 | 权限管理:[Casbin](https://github.com/casbin/casbin)的RBAC-restful 36 | 37 | API授权方式:JWT,使用[gf-jwt](https://github.com/gogf/gf-jwt) 38 | 39 | ---- 40 | #### 前端 41 | 框架:[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) 42 | 43 | ---- 44 | ---- 45 | ### 如何访问接口文档? 46 | 47 | 访问[https://petstore.swagger.io](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/hailaz/gadmin/master/docfile/swagger.yaml)查看。 48 | 49 | 或者启动项目后访问[http://localhost:8199/swagger](http://localhost:8199/swagger)显示接口文档。 50 | 51 | 或将docfile目录下的swagger.yaml文件内容复制到[http://editor.swagger.io](http://editor.swagger.io)查看。 52 | 53 | 54 | -------------------------------------------------------------------------------- /app/model/role_menu_auto_create.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // RoleMenu 表名:role_menu 8 | // 由数据库自动生成的结构体 9 | type RoleMenu struct { 10 | Id int64 `json:"id"` // 11 | RoleKey string `json:"role_key"` //角色key 12 | MenuName string `json:"menu_name"` //菜单关键名 13 | } 14 | 15 | // TableName 获取表名 16 | func (t *RoleMenu) TableName() string { 17 | return "role_menu" 18 | } 19 | 20 | // Insert 插入一条记录 21 | func (t *RoleMenu) Insert() (int64, error) { 22 | r, err := defDB.Insert("role_menu", t) 23 | if err != nil { 24 | return 0, err 25 | } 26 | id, err := r.LastInsertId() 27 | t.Id = id 28 | return id, err 29 | } 30 | 31 | // Update 更新对象 32 | func (t *RoleMenu) Update() (int64, error) { 33 | if t.Id <= 0 { 34 | return 0, errors.New("primary_key <= 0") 35 | } 36 | r, err := defDB.Update("role_menu", t, "id=?", t.Id) 37 | if err != nil { 38 | return 0, err 39 | } 40 | return r.RowsAffected() 41 | } 42 | 43 | // DeleteById 删除一条记录 44 | func (t *RoleMenu) DeleteById(id int64) (int64, error) { 45 | r, err := defDB.Delete("role_menu", "id=?", id) 46 | if err != nil { 47 | return 0, err 48 | } 49 | return r.RowsAffected() 50 | } 51 | 52 | // GetById 通过id查询记录 53 | func (t *RoleMenu) GetById(id int64) (RoleMenu, error) { 54 | obj := RoleMenu{} 55 | err := defDB.Table("role_menu").Where("id", id).Struct(&obj) 56 | return obj, err 57 | } 58 | -------------------------------------------------------------------------------- /app/model/role_name_auto_create.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // RoleName 表名:role_name 8 | // 由数据库自动生成的结构体 9 | type RoleName struct { 10 | Id int64 `json:"id"` // 11 | RoleKey string `json:"role_key"` //角色key 12 | Name string `json:"name"` //角色名 13 | Descrption string `json:"descrption"` //描述 14 | } 15 | 16 | // TableName 获取表名 17 | func (t *RoleName) TableName() string { 18 | return "role_name" 19 | } 20 | 21 | // Insert 插入一条记录 22 | func (t *RoleName) Insert() (int64, error) { 23 | r, err := defDB.Insert("role_name", t) 24 | if err != nil { 25 | return 0, err 26 | } 27 | id, err := r.LastInsertId() 28 | t.Id = id 29 | return id, err 30 | } 31 | 32 | // Update 更新对象 33 | func (t *RoleName) Update() (int64, error) { 34 | if t.Id <= 0 { 35 | return 0, errors.New("primary_key <= 0") 36 | } 37 | r, err := defDB.Update("role_name", t, "id=?", t.Id) 38 | if err != nil { 39 | return 0, err 40 | } 41 | return r.RowsAffected() 42 | } 43 | 44 | // DeleteById 删除一条记录 45 | func (t *RoleName) DeleteById(id int64) (int64, error) { 46 | r, err := defDB.Delete("role_name", "id=?", id) 47 | if err != nil { 48 | return 0, err 49 | } 50 | return r.RowsAffected() 51 | } 52 | 53 | // GetById 通过id查询记录 54 | func (t *RoleName) GetById(id int64) (RoleName, error) { 55 | obj := RoleName{} 56 | err := defDB.Table("role_name").Where("id", id).Struct(&obj) 57 | return obj, err 58 | } 59 | -------------------------------------------------------------------------------- /app/model/menu_meta_auto_create.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // MenuMeta 表名:menu_meta 8 | // 由数据库自动生成的结构体 9 | type MenuMeta struct { 10 | Id int64 `json:"id"` // 11 | MenuName string `json:"menu_name"` //菜单关键名 12 | Title string `json:"title"` //名称 13 | Icon string `json:"icon"` //图标 14 | Nocache bool `json:"noCache"` //是否缓存 15 | } 16 | 17 | // TableName 获取表名 18 | func (t *MenuMeta) TableName() string { 19 | return "menu_meta" 20 | } 21 | 22 | // Insert 插入一条记录 23 | func (t *MenuMeta) Insert() (int64, error) { 24 | r, err := defDB.Insert("menu_meta", t) 25 | if err != nil { 26 | return 0, err 27 | } 28 | id, err := r.LastInsertId() 29 | t.Id = id 30 | return id, err 31 | } 32 | 33 | // Update 更新对象 34 | func (t *MenuMeta) Update() (int64, error) { 35 | if t.Id <= 0 { 36 | return 0, errors.New("primary_key <= 0") 37 | } 38 | r, err := defDB.Update("menu_meta", t, "id=?", t.Id) 39 | if err != nil { 40 | return 0, err 41 | } 42 | return r.RowsAffected() 43 | } 44 | 45 | // DeleteById 删除一条记录 46 | func (t *MenuMeta) DeleteById(id int64) (int64, error) { 47 | r, err := defDB.Delete("menu_meta", "id=?", id) 48 | if err != nil { 49 | return 0, err 50 | } 51 | return r.RowsAffected() 52 | } 53 | 54 | // GetById 通过id查询记录 55 | func (t *MenuMeta) GetById(id int64) (MenuMeta, error) { 56 | obj := MenuMeta{} 57 | err := defDB.Table("menu_meta").Where("id", id).Struct(&obj) 58 | return obj, err 59 | } 60 | -------------------------------------------------------------------------------- /app/model/policy_name_auto_create.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // PolicyName 表名:policy_name 8 | // 由数据库自动生成的结构体 9 | type PolicyName struct { 10 | Id int64 `json:"id"` // 11 | FullPath string `json:"full_path"` //权限完整路径 12 | Name string `json:"name"` //权限名称 13 | Descrption string `json:"descrption"` //描述 14 | } 15 | 16 | // TableName 获取表名 17 | func (t *PolicyName) TableName() string { 18 | return "policy_name" 19 | } 20 | 21 | // Insert 插入一条记录 22 | func (t *PolicyName) Insert() (int64, error) { 23 | r, err := defDB.Insert("policy_name", t) 24 | if err != nil { 25 | return 0, err 26 | } 27 | id, err := r.LastInsertId() 28 | t.Id = id 29 | return id, err 30 | } 31 | 32 | // Update 更新对象 33 | func (t *PolicyName) Update() (int64, error) { 34 | if t.Id <= 0 { 35 | return 0, errors.New("primary_key <= 0") 36 | } 37 | r, err := defDB.Update("policy_name", t, "id=?", t.Id) 38 | if err != nil { 39 | return 0, err 40 | } 41 | return r.RowsAffected() 42 | } 43 | 44 | // DeleteById 删除一条记录 45 | func (t *PolicyName) DeleteById(id int64) (int64, error) { 46 | r, err := defDB.Delete("policy_name", "id=?", id) 47 | if err != nil { 48 | return 0, err 49 | } 50 | return r.RowsAffected() 51 | } 52 | 53 | // GetById 通过id查询记录 54 | func (t *PolicyName) GetById(id int64) (PolicyName, error) { 55 | obj := PolicyName{} 56 | err := defDB.Table("policy_name").Where("id", id).Struct(&obj) 57 | return obj, err 58 | } 59 | -------------------------------------------------------------------------------- /docfile/sql/casbin_rule.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : home.xiao3.top 5 | Source Server Type : MySQL 6 | Source Server Version : 50643 7 | Source Host : home.xiao3.top:3306 8 | Source Schema : mixweb 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 50643 12 | File Encoding : 65001 13 | 14 | Date: 23/04/2019 09:04:12 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for casbin_rule 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `casbin_rule`; 24 | CREATE TABLE `casbin_rule` ( 25 | `id` int(11) NOT NULL AUTO_INCREMENT, 26 | `p_type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 27 | `v0` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 28 | `v1` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 29 | `v2` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 30 | `v3` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 31 | `v4` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 32 | `v5` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 33 | PRIMARY KEY (`id`) USING BTREE 34 | ) ENGINE = InnoDB AUTO_INCREMENT = 181 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 35 | 36 | SET FOREIGN_KEY_CHECKS = 1; 37 | -------------------------------------------------------------------------------- /app/api/baseController.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | jwt "github.com/gogf/gf-jwt" 5 | "github.com/gogf/gf/frame/gmvc" 6 | "github.com/gogf/gf/net/ghttp" 7 | "github.com/hailaz/gadmin/app/model" 8 | "github.com/hailaz/gadmin/library/code" 9 | ) 10 | 11 | type BaseController struct { 12 | gmvc.Controller 13 | } 14 | 15 | // "析构函数"控制器方法 16 | func (c *BaseController) Shut() { 17 | 18 | } 19 | 20 | type BaseResult struct { 21 | Code int `json:"code"` 22 | Message string `json:"message"` 23 | Data interface{} `json:"data"` 24 | } 25 | 26 | // Response API返回 27 | // 28 | // createTime:2019年04月25日 11:32:47 29 | // author:hailaz 30 | func Response(r *ghttp.Request, rs BaseResult) { 31 | r.Response.WriteJson(rs) 32 | r.ExitAll() 33 | } 34 | 35 | // Success 返回成功 36 | // 37 | // createTime:2019年04月25日 11:41:44 38 | // author:hailaz 39 | func Success(r *ghttp.Request, data interface{}) { 40 | Response(r, BaseResult{Code: code.RESPONSE_SUCCESS, Message: "success", Data: data}) 41 | } 42 | 43 | // Fail 返回失败 44 | // 45 | // createTime:2019年04月25日 11:43:34 46 | // author:hailaz 47 | func Fail(r *ghttp.Request, errCode int, msg ...string) { 48 | if len(msg) > 0 { 49 | Response(r, BaseResult{Code: errCode, Message: msg[0]}) 50 | } else { 51 | Response(r, BaseResult{Code: errCode, Message: "fail"}) 52 | } 53 | 54 | } 55 | 56 | // funcName 获取当前用户 57 | // 58 | // createTime:2019年05月13日 10:01:17 59 | // author:hailaz 60 | func (c *BaseController) GetUser() *model.User { 61 | claims := jwt.ExtractClaims(c.Request) 62 | user, _ := model.GetUserByName(claims["username"].(string)) 63 | return user 64 | } 65 | -------------------------------------------------------------------------------- /docfile/sql/menu.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : home.xiao3.top 5 | Source Server Type : MySQL 6 | Source Server Version : 50643 7 | Source Host : home.xiao3.top:3306 8 | Source Schema : gadmin 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 50643 12 | File Encoding : 65001 13 | 14 | Date: 21/06/2019 14:12:48 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for menu 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `menu`; 24 | CREATE TABLE `menu` ( 25 | `id` int(11) NOT NULL AUTO_INCREMENT, 26 | `menu_path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '菜单路径', 27 | `component` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '页面模块', 28 | `redirect` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '重定向地址', 29 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '唯一关键名', 30 | `hidden` tinyint(1) NULL DEFAULT 0 COMMENT '是否隐藏', 31 | `alwaysshow` tinyint(1) NULL DEFAULT 0 COMMENT '是否常显示', 32 | `sort` tinyint(2) NULL DEFAULT 0 COMMENT '排序', 33 | `parent_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '父菜级关键名', 34 | `auto_create` tinyint(1) NULL DEFAULT 0 COMMENT '是否自动生成', 35 | PRIMARY KEY (`id`) USING BTREE, 36 | UNIQUE INDEX `key_name`(`name`) USING BTREE 37 | ) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 38 | 39 | SET FOREIGN_KEY_CHECKS = 1; 40 | -------------------------------------------------------------------------------- /app/model/menu_auto_create.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // Menu 表名:menu 8 | // 由数据库自动生成的结构体 9 | type Menu struct { 10 | Id int64 `json:"id"` // 11 | MenuPath string `json:"path"` //菜单路径 12 | Component string `json:"component"` //页面模块 13 | Redirect string `json:"redirect"` //重定向地址 14 | Name string `json:"name"` //唯一关键名 15 | Hidden bool `json:"hidden"` //是否隐藏 16 | Alwaysshow bool `json:"alwaysshow"` //是否常显示 17 | Sort int `json:"sort"` //排序 18 | ParentName string `json:"parent_name"` //父菜级关键名 19 | AutoCreate bool `json:"auto_create"` //是否自动生成 20 | MenuMeta MenuMeta `json:"meta"` 21 | } 22 | 23 | // TableName 获取表名 24 | func (t *Menu) TableName() string { 25 | return "menu" 26 | } 27 | 28 | // Insert 插入一条记录 29 | func (t *Menu) Insert() (int64, error) { 30 | r, err := defDB.Insert("menu", t) 31 | if err != nil { 32 | return 0, err 33 | } 34 | id, err := r.LastInsertId() 35 | t.Id = id 36 | return id, err 37 | } 38 | 39 | // Update 更新对象 40 | func (t *Menu) Update() (int64, error) { 41 | if t.Id <= 0 { 42 | return 0, errors.New("primary_key <= 0") 43 | } 44 | r, err := defDB.Update("menu", t, "id=?", t.Id) 45 | if err != nil { 46 | return 0, err 47 | } 48 | return r.RowsAffected() 49 | } 50 | 51 | // DeleteById 删除一条记录 52 | func (t *Menu) DeleteById(id int64) (int64, error) { 53 | r, err := defDB.Delete("menu", "id=?", id) 54 | if err != nil { 55 | return 0, err 56 | } 57 | return r.RowsAffected() 58 | } 59 | 60 | // GetById 通过id查询记录 61 | func (t *Menu) GetById(id int64) (Menu, error) { 62 | obj := Menu{} 63 | err := defDB.Table("menu").Where("id", id).Struct(&obj) 64 | return obj, err 65 | } 66 | -------------------------------------------------------------------------------- /static/js/chunk-508832c0.eea072a2.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-508832c0"],{"1bc5":function(t,s,a){"use strict";var e=a("9beb"),c=a.n(e);c.a},"1db4":function(t,s,a){"use strict";a.r(s);var e=function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"wscn-http404-container"},[a("div",{staticClass:"wscn-http404"},[t._m(0),t._v(" "),a("div",{staticClass:"bullshit"},[a("div",{staticClass:"bullshit__oops"},[t._v("OOPS!")]),t._v(" "),t._m(1),t._v(" "),a("div",{staticClass:"bullshit__headline"},[t._v(t._s(t.message))]),t._v(" "),a("div",{staticClass:"bullshit__info"},[t._v("Please check that the URL you entered is correct, or click the button below to return to the homepage.")]),t._v(" "),a("a",{staticClass:"bullshit__return-home",attrs:{href:""}},[t._v("Back to home")])])])])},c=[function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("div",{staticClass:"pic-404"},[e("img",{staticClass:"pic-404__parent",attrs:{src:a("a36b"),alt:"404"}}),t._v(" "),e("img",{staticClass:"pic-404__child left",attrs:{src:a("26fc"),alt:"404"}}),t._v(" "),e("img",{staticClass:"pic-404__child mid",attrs:{src:a("26fc"),alt:"404"}}),t._v(" "),e("img",{staticClass:"pic-404__child right",attrs:{src:a("26fc"),alt:"404"}})])},function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"bullshit__info"},[t._v("All rights reserved\n "),a("a",{staticStyle:{color:"#20a0ff"},attrs:{href:"https://wallstreetcn.com",target:"_blank"}},[t._v("wallstreetcn")])])}],i={name:"Page404",computed:{message:function(){return"The webmaster said that you can not enter this page..."}}},l=i,n=(a("1bc5"),a("2877")),r=Object(n["a"])(l,e,c,!1,null,"22c31b5a",null);s["default"]=r.exports},"26fc":function(t,s,a){t.exports=a.p+"static/img/404_cloud.0f4bc32b.png"},"9beb":function(t,s,a){},a36b:function(t,s,a){t.exports=a.p+"static/img/404.a57b6f31.png"}}]); -------------------------------------------------------------------------------- /docfile/tools/codeCreater/xorm/templates/struct/structs.go.tpl: -------------------------------------------------------------------------------- 1 | package {{.Models}} 2 | import ( 3 | {{$ilen := len .Imports}} 4 | {{if gt $ilen 0}} 5 | 6 | {{range .Imports}}"{{.}}"{{end}} 7 | 8 | {{end}} 9 | {{range .Tables}} 10 | {{if (PKIsId .)}}"errors"{{end}} 11 | "github.com/gogf/gf/os/gtime" 12 | ) 13 | // {{Mapper .Name}} 表名:{{.Name}} 14 | // 由数据库自动生成的结构体 15 | type {{Mapper .Name}} struct { {{$table := .}} 16 | {{range .ColumnsSeq}}{{$col := $table.GetColumn .}} {{Mapper $col.Name}} {{Type $col}} {{Tag $table $col}} 17 | {{end}}} 18 | 19 | 20 | 21 | // TableName 获取表名 22 | func (t *{{Mapper .Name}}) TableName() string { 23 | return "{{.Name}}" 24 | } 25 | 26 | // Insert 插入一条记录 27 | func (t *{{Mapper .Name}}) Insert() (int64, error) { 28 | t.AddTime = gtime.Now().String() 29 | t.UpdateTime = gtime.Now().String() 30 | r, err := defDB.Insert("{{.Name}}", t) 31 | if err != nil { 32 | return 0, err 33 | } 34 | id, err := r.LastInsertId() 35 | t.Id = id 36 | return id, err 37 | } 38 | {{if not (PKIsId .)}}/*{{end}} 39 | // Update 更新对象 40 | func (t *{{Mapper .Name}}) Update() (int64, error) { 41 | if t.Id <= 0 { 42 | return 0, errors.New("primary_key <= 0") 43 | } 44 | t.UpdateTime = gtime.Now().String() 45 | r, err := defDB.Update("{{.Name}}", t, "id=?", t.Id) 46 | if err != nil { 47 | return 0, err 48 | } 49 | return r.RowsAffected() 50 | } 51 | 52 | // DeleteById 删除一条记录 53 | func (t *{{Mapper .Name}}) DeleteById(id int64) (int64, error) { 54 | r, err := defDB.Delete("{{.Name}}", "id=?", id) 55 | if err != nil { 56 | return 0, err 57 | } 58 | return r.RowsAffected() 59 | } 60 | 61 | 62 | // GetById 通过id查询记录 63 | func (t *{{Mapper .Name}}) GetById(id int64) ({{Mapper .Name}}, error) { 64 | obj := {{Mapper .Name}}{} 65 | err := defDB.Table("{{.Name}}").Where("id", id).Struct(&obj) 66 | return obj, err 67 | } 68 | {{if not (PKIsId .)}}*/{{end}} 69 | {{end}} -------------------------------------------------------------------------------- /static/js/chunk-2e555135.9e9541fc.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2e555135"],{"24e2":function(t,a,i){"use strict";i.r(a);var e=function(){var t=this,a=t.$createElement,i=t._self._c||a;return i("div",{staticClass:"errPage-container"},[i("el-button",{staticClass:"pan-back-btn",attrs:{icon:"arrow-left"},on:{click:t.back}},[t._v("\n 返回\n ")]),t._v(" "),i("el-row",[i("el-col",{attrs:{span:12}},[i("h1",{staticClass:"text-jumbo text-ginormous"},[t._v("\n Oops!\n ")]),t._v("\n gif来源"),i("a",{attrs:{href:"https://zh.airbnb.com/",target:"_blank"}},[t._v("airbnb")]),t._v(" 页面\n "),i("h2",[t._v("你没有权限去该页面")]),t._v(" "),i("h6",[t._v("如有不满请联系你领导")]),t._v(" "),i("ul",{staticClass:"list-unstyled"},[i("li",[t._v("或者你可以去:")]),t._v(" "),i("li",{staticClass:"link-type"},[i("router-link",{attrs:{to:"/dashboard"}},[t._v("\n 回首页\n ")])],1),t._v(" "),i("li",{staticClass:"link-type"},[i("a",{attrs:{href:"https://www.taobao.com/"}},[t._v("随便看看")])]),t._v(" "),i("li",[i("a",{attrs:{href:"#"},on:{click:function(a){a.preventDefault(),t.dialogVisible=!0}}},[t._v("点我看图")])])])]),t._v(" "),i("el-col",{attrs:{span:12}},[i("img",{attrs:{src:t.errGif,width:"313",height:"428",alt:"Girl has dropped her ice cream."}})])],1),t._v(" "),i("el-dialog",{attrs:{visible:t.dialogVisible,title:"随便看"},on:{"update:visible":function(a){t.dialogVisible=a}}},[i("img",{staticClass:"pan-img",attrs:{src:t.ewizardClap}})])],1)},s=[],n=i("cc6c"),r=i.n(n),c={name:"Page401",data:function(){return{errGif:r.a+"?"+ +new Date,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}},methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/dashboard"}):this.$router.go(-1)}}},l=c,o=(i("efaf"),i("2877")),u=Object(o["a"])(l,e,s,!1,null,"2c77c6fb",null);a["default"]=u.exports},bbc8:function(t,a,i){},cc6c:function(t,a,i){t.exports=i.p+"static/img/401.089007e7.gif"},efaf:function(t,a,i){"use strict";var e=i("bbc8"),s=i.n(e);s.a}}]); -------------------------------------------------------------------------------- /docfile/sql/user.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : localhost 5 | Source Server Type : MySQL 6 | Source Server Version : 50542 7 | Source Host : localhost:33061 8 | Source Schema : gadmin 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 50542 12 | File Encoding : 65001 13 | 14 | Date: 16/05/2019 15:07:55 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for user 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `user`; 24 | CREATE TABLE `user` ( 25 | `id` int(11) NOT NULL AUTO_INCREMENT, 26 | `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '状态', 27 | `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户名', 28 | `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '昵称', 29 | `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '密码', 30 | `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱', 31 | `phone` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号', 32 | `sex` tinyint(6) NOT NULL DEFAULT 0 COMMENT '性别', 33 | `age` tinyint(6) NOT NULL DEFAULT 0 COMMENT '年龄', 34 | `add_time` datetime NOT NULL COMMENT '添加时间', 35 | `update_time` datetime NOT NULL COMMENT '修改时间', 36 | `add_user_id` int(11) NOT NULL DEFAULT 0 COMMENT '操作用户', 37 | `Introduction` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '介绍', 38 | `avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像', 39 | PRIMARY KEY (`id`) USING BTREE, 40 | UNIQUE INDEX `username`(`user_name`) USING BTREE 41 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; 42 | 43 | SET FOREIGN_KEY_CHECKS = 1; 44 | -------------------------------------------------------------------------------- /app/model/user_auto_create.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/gogf/gf/os/gtime" 7 | ) 8 | 9 | // User 表名:user 10 | // 由数据库自动生成的结构体 11 | type User struct { 12 | Id int64 `json:"id"` // 13 | Status int `json:"status"` //状态 14 | UserName string `json:"user_name"` //用户名 15 | NickName string `json:"nick_name"` //昵称 16 | Password string `json:"password"` //密码 17 | Email string `json:"email"` //邮箱 18 | Phone string `json:"phone"` //手机号 19 | Sex int `json:"sex"` //性别 20 | Age int `json:"age"` //年龄 21 | AddTime string `json:"add_time"` //添加时间 22 | UpdateTime string `json:"update_time"` //修改时间 23 | AddUserId int64 `json:"add_user_id"` //操作用户 24 | Introduction string `json:"Introduction"` //介绍 25 | Avatar string `json:"avatar"` //头像 26 | } 27 | 28 | // TableName 获取表名 29 | func (t *User) TableName() string { 30 | return "user" 31 | } 32 | 33 | // Insert 插入一条记录 34 | func (t *User) Insert() (int64, error) { 35 | t.AddTime = gtime.Now().String() 36 | t.UpdateTime = gtime.Now().String() 37 | t.Password = EncryptPassword(t.Password) 38 | r, err := defDB.Insert("user", t) 39 | if err != nil { 40 | return 0, err 41 | } 42 | id, err := r.LastInsertId() 43 | t.Id = id 44 | return id, err 45 | } 46 | 47 | // Update 更新对象 48 | func (t *User) Update() (int64, error) { 49 | if t.Id <= 0 { 50 | return 0, errors.New("primary_key <= 0") 51 | } 52 | t.UpdateTime = gtime.Now().String() 53 | r, err := defDB.Update("user", t, "id=?", t.Id) 54 | if err != nil { 55 | return 0, err 56 | } 57 | return r.RowsAffected() 58 | } 59 | 60 | // DeleteById 删除一条记录 61 | func (t *User) DeleteById(id int64) (int64, error) { 62 | r, err := defDB.Delete("user", "id=?", id) 63 | if err != nil { 64 | return 0, err 65 | } 66 | return r.RowsAffected() 67 | } 68 | 69 | // GetById 通过id查询记录 70 | func (t *User) GetById(id int64) (User, error) { 71 | obj := User{} 72 | err := defDB.Table("user").Where("id", id).Struct(&obj) 73 | return obj, err 74 | } 75 | -------------------------------------------------------------------------------- /app/api/policyController.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/hailaz/gadmin/app/model" 8 | "github.com/hailaz/gadmin/library/code" 9 | ) 10 | 11 | const ( 12 | UNDEFIND_POLICY_NAME = "未命名" 13 | ) 14 | 15 | type PolicyController struct { 16 | BaseController 17 | } 18 | 19 | func (c *PolicyController) Get() { 20 | page := c.Request.GetInt("page", 1) 21 | limit := c.Request.GetInt("limit", 10) 22 | 23 | var list struct { 24 | List []model.Policy `json:"items"` 25 | Total int `json:"total"` 26 | } 27 | 28 | list.List, list.Total = model.GetPolicyList(page, limit, UNDEFIND_POLICY_NAME) 29 | 30 | Success(c.Request, list) 31 | } 32 | 33 | func (c *PolicyController) Post() { 34 | Success(c.Request, "Post") 35 | } 36 | 37 | func (c *PolicyController) Put() { 38 | data, _ := c.Request.GetJson() 39 | name := data.GetString("name") 40 | path := data.GetString("policy") 41 | if name == UNDEFIND_POLICY_NAME { 42 | Fail(c.Request, code.RESPONSE_ERROR) 43 | } else { 44 | err := model.UpdatePolicyByFullPath(path, name) 45 | if err != nil { 46 | Fail(c.Request, code.RESPONSE_ERROR, err.Error()) 47 | } 48 | } 49 | Success(c.Request, "修改成功") 50 | } 51 | 52 | func (c *PolicyController) Delete() { 53 | Success(c.Request, "Delete") 54 | } 55 | 56 | func (c *PolicyController) GetPolicyByRole() { 57 | role := c.Request.GetString("role") 58 | var list struct { 59 | List []model.Policy `json:"all_policy_items"` 60 | RolePolicyList []model.Policy `json:"role_policy_items"` 61 | Total int `json:"total"` 62 | } 63 | 64 | list.List, list.Total = model.GetPolicyList(1, -1, "") 65 | list.RolePolicyList = model.GetPolicyByRole(role) 66 | 67 | Success(c.Request, list) 68 | } 69 | 70 | func (c *PolicyController) SetPolicyByRole() { 71 | data, _ := c.Request.GetJson() 72 | role := data.GetString("role") 73 | policys := data.GetStrings("policys") 74 | 75 | var routerMap = make(map[string]model.RolePolicy) 76 | for _, item := range policys { 77 | list := strings.Split(item, ":") 78 | path := list[0] 79 | atc := list[1] 80 | routerMap[fmt.Sprintf("%v %v %v", role, path, atc)] = model.RolePolicy{Role: role, Path: path, Atc: atc} 81 | } 82 | 83 | model.ReSetPolicy(role, routerMap) 84 | 85 | Success(c.Request, "success") 86 | } 87 | -------------------------------------------------------------------------------- /app/api/roleController.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "github.com/gogf/gf/os/glog" 5 | "github.com/hailaz/gadmin/app/model" 6 | "github.com/hailaz/gadmin/library/code" 7 | ) 8 | 9 | type RoleController struct { 10 | BaseController 11 | } 12 | 13 | func (c *RoleController) Get() { 14 | page := c.Request.GetInt("page", 1) 15 | limit := c.Request.GetInt("limit", 10) 16 | username := c.Request.GetString("username") 17 | var list struct { 18 | List []model.Role `json:"items"` 19 | UserRoleList []model.Role `json:"role_items"` 20 | Total int `json:"total"` 21 | } 22 | list.List, list.Total = model.GetRoleList(page, limit, UNDEFIND_POLICY_NAME) 23 | if username != "" { 24 | list.UserRoleList = model.GetRoleByUserName(username) 25 | } 26 | 27 | Success(c.Request, list) 28 | } 29 | 30 | func (c *RoleController) Post() { 31 | data, _ := c.Request.GetJson() 32 | name := data.GetString("name") 33 | role := data.GetString("role") 34 | 35 | err := model.AddRole(role, name) 36 | if err != nil { 37 | Fail(c.Request, code.RESPONSE_ERROR, err.Error()) 38 | } 39 | 40 | Success(c.Request, "Post") 41 | } 42 | 43 | func (c *RoleController) Put() { 44 | data, _ := c.Request.GetJson() 45 | name := data.GetString("name") 46 | role := data.GetString("role") 47 | glog.Debug(name, role) 48 | if name == UNDEFIND_POLICY_NAME { 49 | Fail(c.Request, code.RESPONSE_ERROR) 50 | } else { 51 | err := model.UpdateRoleByRoleKey(role, name) 52 | if err != nil { 53 | Fail(c.Request, code.RESPONSE_ERROR, err.Error()) 54 | } 55 | } 56 | Success(c.Request, "修改成功") 57 | } 58 | 59 | func (c *RoleController) Delete() { 60 | data, _ := c.Request.GetJson() 61 | role := data.GetString("role") 62 | 63 | err := model.DeleteRole(role) 64 | if err != nil { 65 | Fail(c.Request, code.RESPONSE_ERROR, err.Error()) 66 | } 67 | Success(c.Request, "Delete") 68 | } 69 | 70 | func (c *RoleController) SetRoleByUserName() { 71 | data, _ := c.Request.GetJson() 72 | roles := data.GetStrings("roles") 73 | username := data.GetString("username") 74 | model.SetRoleByUserName(username, roles) 75 | 76 | Success(c.Request, "success") 77 | } 78 | 79 | func (c *RoleController) SetRoleMenus() { 80 | data, _ := c.Request.GetJson() 81 | role := data.GetString("role") 82 | menus := data.GetStrings("menus") 83 | model.SetRoleMenus(role, menus) 84 | Success(c.Request, "success") 85 | } 86 | -------------------------------------------------------------------------------- /app/api/menuController.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "github.com/gogf/gf/database/gdb" 5 | "github.com/hailaz/gadmin/app/model" 6 | "github.com/hailaz/gadmin/library/code" 7 | ) 8 | 9 | type MenuController struct { 10 | BaseController 11 | } 12 | 13 | func (c *MenuController) Get() { 14 | page := c.Request.GetInt("page", 1) 15 | limit := c.Request.GetInt("limit", 10) 16 | var list struct { 17 | List []model.MenuOut `json:"items"` 18 | Total int `json:"total"` 19 | } 20 | list.List, list.Total = model.GetMenuList(page, limit) 21 | 22 | Success(c.Request, list) 23 | } 24 | 25 | func (c *MenuController) Post() { 26 | data, _ := c.Request.GetJson() 27 | m := model.MenuOut{} 28 | data.ToStruct(&m) 29 | model.InsertMenuWithMeta(gdb.List{ 30 | { 31 | "name": m.Name, 32 | "menu_path": m.MenuPath, 33 | "component": m.Component, 34 | "sort": m.Sort, 35 | "parent_name": m.ParentName, 36 | "hidden": m.Hidden, 37 | "redirect": m.Redirect, 38 | "alwaysshow": m.Alwaysshow, 39 | "meta": gdb.Map{ 40 | "title": m.MenuMetaOut.Title, 41 | "icon": m.MenuMetaOut.Icon, 42 | "noCache": m.MenuMetaOut.Nocache, 43 | }, 44 | }, 45 | }) 46 | Success(c.Request, "添加成功") 47 | } 48 | 49 | func (c *MenuController) Put() { 50 | data, _ := c.Request.GetJson() 51 | m := model.MenuOut{} 52 | data.ToStruct(&m) 53 | err := model.UpdateMenuByName( 54 | m.Name, 55 | gdb.Map{ 56 | "menu_path": m.MenuPath, 57 | "component": m.Component, 58 | "sort": m.Sort, 59 | "parent_name": m.ParentName, 60 | "hidden": m.Hidden, 61 | "redirect": m.Redirect, 62 | "alwaysshow": m.Alwaysshow, 63 | "meta": gdb.Map{ 64 | "title": m.MenuMetaOut.Title, 65 | "icon": m.MenuMetaOut.Icon, 66 | "noCache": m.MenuMetaOut.Nocache, 67 | }, 68 | }, 69 | ) 70 | if err != nil { 71 | Fail(c.Request, code.RESPONSE_ERROR, err.Error()) 72 | } 73 | Success(c.Request, "修改成功") 74 | } 75 | 76 | func (c *MenuController) Delete() { 77 | data, _ := c.Request.GetJson() 78 | name := data.GetString("name") 79 | m, err := model.GetMenuByName(name) 80 | if err != nil { 81 | Fail(c.Request, code.RESPONSE_ERROR, err.Error()) 82 | } 83 | if m.AutoCreate { 84 | Fail(c.Request, code.RESPONSE_ERROR) 85 | } 86 | res, _ := m.DeleteById(m.Id) 87 | if res <= 0 { 88 | Fail(c.Request, code.RESPONSE_ERROR) 89 | } 90 | Success(c.Request, "Delete") 91 | } 92 | -------------------------------------------------------------------------------- /static/css/chunk-cbf46a0a.c19e23ad.css: -------------------------------------------------------------------------------- 1 | .social-signup-container[data-v-c817cede]{margin:20px 0}.social-signup-container .sign-btn[data-v-c817cede]{display:inline-block;cursor:pointer}.social-signup-container .icon[data-v-c817cede]{color:#fff;font-size:24px;margin-top:8px}.social-signup-container .qq-svg-container[data-v-c817cede],.social-signup-container .wx-svg-container[data-v-c817cede]{display:inline-block;width:40px;height:40px;line-height:40px;text-align:center;padding-top:1px;border-radius:4px;margin-bottom:20px;margin-right:5px}.social-signup-container .wx-svg-container[data-v-c817cede]{background-color:#24da70}.social-signup-container .qq-svg-container[data-v-c817cede]{background-color:#6ba2d6;margin-left:50px}@supports (-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-40da4f90]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-40da4f90]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-40da4f90]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-40da4f90]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-40da4f90]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-40da4f90]{position:relative}.login-container .title-container .title[data-v-40da4f90]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .title-container .set-language[data-v-40da4f90]{color:#fff;position:absolute;top:3px;font-size:18px;right:0;cursor:pointer}.login-container .show-pwd[data-v-40da4f90]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-40da4f90]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-40da4f90]{display:none}} -------------------------------------------------------------------------------- /static/css/chunk-libs.3dfb7769.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:inherit;font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}[hidden],template{display:none}#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;-webkit-box-shadow:0 0 10px #29d,0 0 5px #29d;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;-webkit-transform:rotate(3deg) translateY(-4px);transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;-webkit-box-sizing:border-box;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}} -------------------------------------------------------------------------------- /app/model/model.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/casbin/casbin" 5 | "github.com/gogf/gf/database/gdb" 6 | "github.com/gogf/gf/frame/g" 7 | // _ "github.com/lib/pq" 8 | // _ "github.com/mattn/go-sqlite3" 9 | ) 10 | 11 | var defDB gdb.DB 12 | var Enforcer *casbin.Enforcer 13 | 14 | const ( 15 | ACTION_GET = "(GET)" 16 | ACTION_POST = "(POST)" 17 | ACTION_PUT = "(PUT)" 18 | ACTION_DELETE = "(DELETE)" 19 | ACTION_ALL = "(GET)|(POST)|(PUT)|(DELETE)|(PATCH)|(OPTIONS)|(HEAD)" 20 | ADMIN_NAME = "admin" //超级管理员用户名 21 | ADMIN_NICK_NAME = "超级管理员" //超级管理员显示名称 22 | ADMIN_DEFAULT_PASSWORD = "123456" //超级管理员默认密码 23 | ) 24 | 25 | // InitModel 初始化数据模型 26 | // 27 | // createTime:2019年05月13日 09:47:08 28 | // author:hailaz 29 | func InitModel() { 30 | defDB = g.DB() 31 | //defDB.SetDebug(true) 32 | initUser() 33 | initCasbin() 34 | initMenu() 35 | } 36 | 37 | // initUser 初始化用户 38 | // 39 | // createTime:2019年04月23日 14:57:23 40 | // author:hailaz 41 | func initUser() { 42 | u, err := GetUserByName(ADMIN_NAME) 43 | if err == nil && u != nil && u.Id != 0 { 44 | return 45 | } 46 | admin := User{ 47 | UserName: ADMIN_NAME, 48 | NickName: ADMIN_NICK_NAME, 49 | Password: ADMIN_DEFAULT_PASSWORD, 50 | } 51 | admin.Insert() 52 | } 53 | 54 | // initMenu 初始化菜单数据 55 | // 56 | // createTime:2019年05月16日 15:39:54 57 | // author:hailaz 58 | func initMenu() { 59 | InsertMenuWithMeta(gdb.List{ 60 | { 61 | "name": "user", 62 | "menu_path": "/user", 63 | "component": "layout", 64 | "redirect": "/user/list", 65 | "sort": "0", 66 | "parent_name": "", 67 | "auto_create": true, 68 | "meta": gdb.Map{ 69 | "title": "user", 70 | "icon": "user", 71 | "noCache": 0}, 72 | }, 73 | { 74 | "name": "userList", 75 | "menu_path": "list", 76 | "component": "user/user", 77 | "sort": "0", 78 | "parent_name": "user", 79 | "auto_create": true, 80 | "meta": gdb.Map{ 81 | "title": "userList", 82 | "icon": "", 83 | "noCache": 0}, 84 | }, 85 | { 86 | "name": "roleList", 87 | "menu_path": "/role/list", 88 | "component": "user/role", 89 | "sort": "1", 90 | "parent_name": "user", 91 | "auto_create": true, 92 | "meta": gdb.Map{ 93 | "title": "roleList", 94 | "icon": "", 95 | "noCache": 0}, 96 | }, 97 | { 98 | "name": "policyList", 99 | "menu_path": "/policy/list", 100 | "component": "user/policy", 101 | "sort": "2", 102 | "parent_name": "user", 103 | "auto_create": true, 104 | "meta": gdb.Map{ 105 | "title": "policyList", 106 | "icon": "", 107 | "noCache": 0}, 108 | }, 109 | { 110 | "name": "menuList", 111 | "menu_path": "/menu/list", 112 | "component": "user/menu", 113 | "sort": "3", 114 | "parent_name": "user", 115 | "auto_create": true, 116 | "meta": gdb.Map{ 117 | "title": "menuList", 118 | "icon": "", 119 | "noCache": 0}, 120 | }, 121 | }) 122 | 123 | } 124 | 125 | // initCasbin 初始化Casbin 126 | // 127 | // createTime:2019年04月23日 14:45:20 128 | // author:hailaz 129 | func initCasbin() { 130 | a := NewAdapter(defDB) 131 | Enforcer = casbin.NewEnforcer("./config/rbac.conf", a) 132 | Enforcer.LoadPolicy() 133 | //Enforcer.DeletePermissionsForUser("group_admin") 134 | Enforcer.AddPolicy(ADMIN_NAME, "*", ACTION_ALL) 135 | //Enforcer.AddGroupingPolicy("system", "user") 136 | 137 | } 138 | 139 | // GetDB 获取默认DB 140 | // 141 | // createTime:2019年04月23日 11:53:21 142 | // author:hailaz 143 | func GetDB() gdb.DB { 144 | return defDB 145 | } 146 | -------------------------------------------------------------------------------- /app/model/user.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/gogf/gf/crypto/gmd5" 7 | "github.com/gogf/gf/database/gdb" 8 | "github.com/gogf/gf/os/gtime" 9 | ) 10 | 11 | const ( 12 | ENCRYPTMD5 = "gadmin" 13 | ) 14 | 15 | type UserOut struct { 16 | Id int64 `json:"id"` // 17 | Status int `json:"status"` // 18 | UserName string `json:"user_name"` // 19 | NickName string `json:"nick_name"` // 20 | Email string `json:"email"` // 21 | Phone string `json:"phone"` // 22 | Sex int `json:"sex"` // 23 | Age int `json:"age"` // 24 | AddTime string `json:"add_time"` // 25 | UpdateTime string `json:"update_time"` // 26 | AddUserId int64 `json:"add_user_id"` // 27 | ThirdPartyId int64 `json:"third_party_id"` // 28 | Introduction string `json:"Introduction"` // 29 | Avatar string `json:"avatar"` // 30 | } 31 | 32 | type UserInfo struct { 33 | Roles []string `json:"roles"` 34 | Introduction string `json:"introduction"` 35 | Avatar string `json:"avatar"` 36 | Name string `json:"name"` 37 | } 38 | 39 | // GetUserByPageLimt 获取用户 40 | // 41 | // createTime:2019年05月07日 16:11:41 42 | // author:hailaz 43 | func GetUserByPageLimt(page, limit int) ([]UserOut, int) { 44 | if page < 1 { 45 | page = 1 46 | } 47 | if limit < 1 { 48 | limit = 10 49 | } 50 | total, _ := defDB.Table("user").Count() 51 | if total == 0 { 52 | return nil, 0 53 | } 54 | 55 | userList := make([]UserOut, 0) 56 | if total < page*limit { 57 | if total < limit { 58 | page = 1 59 | } 60 | } 61 | r, err := defDB.Table("user").Limit((page-1)*limit, (page-1)*limit+limit).Select() 62 | if err != nil { 63 | return nil, 0 64 | } 65 | r.ToStructs(&userList) 66 | return userList, total 67 | 68 | } 69 | 70 | // GetAllUser 获取所有用户 71 | // 72 | // createTime:2019年04月30日 10:20:50 73 | // author:hailaz 74 | func GetAllUser() (gdb.Result, error) { 75 | return defDB.Table("user").All() 76 | } 77 | 78 | // GetUserByName 根据用户名获取用户 79 | // 80 | // createTime:2019年04月23日 17:14:22 81 | // author:hailaz 82 | func GetUserByName(name string) (*User, error) { 83 | u := User{} 84 | err := defDB.Table("user").Where("user_name", name).Struct(&u) 85 | if err != nil { 86 | return nil, err 87 | } 88 | return &u, nil 89 | } 90 | 91 | // EncryptPassword 加密密码 92 | // 93 | // createTime:2019年04月25日 10:19:13 94 | // author:hailaz 95 | func EncryptPassword(data string) string { 96 | md5Str, _ := gmd5.EncryptString(data + ENCRYPTMD5) 97 | return md5Str 98 | } 99 | 100 | // UpdateUserById 更新用户 101 | // 102 | // createTime:2019年05月08日 14:28:18 103 | // author:hailaz 104 | func UpdateUserById(id int64, udmap gdb.Map) error { 105 | udmap["update_time"] = gtime.Now().String() 106 | r, err := defDB.Table("user").Data(udmap).Where("id=?", id).Update() 107 | if err != nil { 108 | return err 109 | } 110 | i, _ := r.RowsAffected() 111 | if i < 0 { 112 | return errors.New("update fail") 113 | } 114 | return nil 115 | } 116 | 117 | // { 118 | // roles: ['admin'], 119 | // introduction: 'I am a super administrator', 120 | // avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', 121 | // name: 'Super Admin' 122 | // } 123 | // GetUserInfo 获取用户信息 124 | // 125 | // createTime:2019年05月08日 16:53:24 126 | // author:hailaz 127 | func (u *User) GetUserInfo() UserInfo { 128 | info := UserInfo{} 129 | if u.UserName == ADMIN_NAME { 130 | info.Roles = []string{ADMIN_NAME} 131 | } else { 132 | info.Roles, _ = Enforcer.GetRolesForUser(u.UserName) 133 | } 134 | 135 | info.Avatar = u.Avatar 136 | info.Introduction = u.Introduction 137 | info.Name = u.NickName 138 | 139 | return info 140 | } 141 | -------------------------------------------------------------------------------- /library/common/rsa.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "crypto/rsa" 7 | "crypto/x509" 8 | "encoding/pem" 9 | "errors" 10 | 11 | "github.com/gogf/gf/container/gmap" 12 | "github.com/gogf/gf/os/glog" 13 | "github.com/gogf/gf/os/gtime" 14 | ) 15 | 16 | var CryptoKeyList = gmap.New() 17 | 18 | type CryptoKey struct { 19 | Id string `json:"kid"` 20 | CryptoType string `json:"cryptotype"` 21 | Key string `json:"key"` 22 | PrivateKey string `json:"-"` 23 | TimeStamp int64 `json:"timestamp"` //sec 24 | } 25 | 26 | // GetCryptoKey 获取加密key 27 | // 28 | // createTime:2019年04月26日 15:03:24 29 | // author:hailaz 30 | func GetCryptoKey(id string) *CryptoKey { 31 | var ck CryptoKey 32 | if k := CryptoKeyList.Get(id); k != nil { 33 | CryptoKeyList.Remove(id) //移除已使用密钥 34 | ck = k.(CryptoKey) 35 | return &ck 36 | } 37 | return nil 38 | } 39 | 40 | // RemoveTimeoutCryptoKey 移除超时加密key 41 | // 42 | // createTime:2019年04月26日 15:00:23 43 | // author:hailaz 44 | func RemoveTimeoutCryptoKey() { 45 | kList := make([]interface{}, 0) 46 | nowSec := gtime.Second() 47 | //遍历加密key 48 | CryptoKeyList.Iterator(func(k interface{}, v interface{}) bool { 49 | ck := v.(CryptoKey) 50 | if nowSec-ck.TimeStamp >= 10 { 51 | kList = append(kList, k) 52 | } 53 | return true 54 | }) 55 | //移除超时的加密key 56 | for _, v := range kList { 57 | CryptoKeyList.Remove(v) 58 | glog.Debugf("remove key:%v", v) 59 | } 60 | } 61 | 62 | // GenCryptoKey 创建加密key 63 | // 64 | // createTime:2019年04月26日 10:27:48 65 | // author:hailaz 66 | func GenCryptoKey(id string) CryptoKey { 67 | rsakp, _ := GenRsaKey(2048) 68 | ck := CryptoKey{ 69 | Id: id, 70 | CryptoType: "RSA-PKCS1v1.5", 71 | Key: rsakp.PublicKey, 72 | PrivateKey: rsakp.PrivateKey, 73 | TimeStamp: gtime.Second(), 74 | } 75 | CryptoKeyList.Set(id, ck) 76 | return ck 77 | 78 | } 79 | 80 | type RASKeyPair struct { 81 | PrivateKey string 82 | PublicKey string 83 | } 84 | 85 | // RAS密钥对生成可选1024 2048 4096 86 | func GenRsaKey(bits int) (*RASKeyPair, error) { 87 | kp := &RASKeyPair{} 88 | // 生成私钥文件 89 | privateKey, err := rsa.GenerateKey(rand.Reader, bits) 90 | if err != nil { 91 | return nil, err 92 | } 93 | derStream := x509.MarshalPKCS1PrivateKey(privateKey) 94 | block := &pem.Block{ 95 | Type: "RSA PRIVATE KEY", 96 | Bytes: derStream, 97 | } 98 | b := bytes.NewBuffer(make([]byte, 0)) 99 | pem.Encode(b, block) 100 | kp.PrivateKey = b.String() 101 | //glog.Debug(b.String()) 102 | // 生成公钥文件 103 | derPkix, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) 104 | if err != nil { 105 | return nil, err 106 | } 107 | block = &pem.Block{ 108 | Type: "PUBLIC KEY", 109 | Bytes: derPkix, 110 | } 111 | b1 := bytes.NewBuffer(make([]byte, 0)) 112 | pem.Encode(b1, block) 113 | //glog.Debug(b1.String()) 114 | kp.PublicKey = b1.String() 115 | 116 | return kp, nil 117 | } 118 | 119 | // 加密 120 | func RsaEncrypt(origData, publicKey []byte) ([]byte, error) { 121 | //解密pem格式的公钥 122 | block, _ := pem.Decode(publicKey) 123 | if block == nil { 124 | return nil, errors.New("public key error") 125 | } 126 | // 解析公钥 127 | pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) 128 | if err != nil { 129 | return nil, err 130 | } 131 | // 类型断言 132 | pub := pubInterface.(*rsa.PublicKey) 133 | //加密 134 | return rsa.EncryptPKCS1v15(rand.Reader, pub, origData) 135 | } 136 | 137 | // 解密 138 | func RsaDecrypt(ciphertext, privateKey []byte) ([]byte, error) { 139 | //解密 140 | block, _ := pem.Decode(privateKey) 141 | if block == nil { 142 | return nil, errors.New("private key error!") 143 | } 144 | //解析PKCS1格式的私钥 145 | priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) 146 | if err != nil { 147 | return nil, err 148 | } 149 | // 解密 150 | return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext) 151 | } 152 | -------------------------------------------------------------------------------- /app/model/policy.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/gogf/gf/os/glog" 8 | 9 | "github.com/gogf/gf/database/gdb" 10 | ) 11 | 12 | type Policy struct { 13 | Policy string `json:"policy"` // 14 | Name string `json:"name"` // 15 | Descrption string `json:"descrption"` // 16 | } 17 | 18 | type RolePolicy struct { 19 | Role string 20 | Path string 21 | Atc string 22 | } 23 | 24 | // GetPolicyList 获取权限列表 25 | // 26 | // createTime:2019年05月06日 17:24:12 27 | // author:hailaz 28 | func GetPolicyList(page, limit int, defaultname string) ([]Policy, int) { 29 | if page < 1 { 30 | page = 1 31 | } 32 | policyList := make([]Policy, 0) 33 | policys := Enforcer.GetPermissionsForUser("system") 34 | total := len(policys) 35 | r, _ := GetAllPolicy() 36 | pn := make([]PolicyName, 0) 37 | r.ToStructs(&pn) 38 | 39 | for _, item := range policys { 40 | full := fmt.Sprintf("%v:%v", item[1], item[2]) 41 | p := Policy{Policy: full, Name: defaultname} 42 | for _, itempn := range pn { 43 | if itempn.FullPath == full { 44 | p.Name = itempn.Name 45 | p.Descrption = itempn.Descrption 46 | break 47 | } 48 | } 49 | policyList = append(policyList, p) 50 | } 51 | if limit == -1 { 52 | return policyList, total 53 | } 54 | if len(policyList) < page*limit { 55 | if len(policyList) < limit { 56 | policyList = policyList 57 | } else { 58 | policyList = policyList[(page-1)*limit:] 59 | } 60 | } else { 61 | policyList = policyList[(page-1)*limit : (page-1)*limit+limit] 62 | } 63 | return policyList, total 64 | } 65 | 66 | // GetPolicyByRole 根据角色获取权限 67 | // 68 | // createTime:2019年05月07日 11:35:33 69 | // author:hailaz 70 | func GetPolicyByRole(role string) []Policy { 71 | policyList := make([]Policy, 0) 72 | policys := Enforcer.GetPermissionsForUser(role) 73 | glog.Debug(policys) 74 | for _, item := range policys { 75 | full := fmt.Sprintf("%v:%v", item[1], item[2]) 76 | p := Policy{Policy: full} 77 | policyList = append(policyList, p) 78 | } 79 | return policyList 80 | } 81 | 82 | // GetAllPolicy 获取所有权限名称 83 | // 84 | // createTime:2019年04月30日 10:20:50 85 | // author:hailaz 86 | func GetAllPolicy() (gdb.Result, error) { 87 | return defDB.Table("policy_name").All() 88 | } 89 | 90 | // GetPolicyByFullPath 根据权限全路径获取权限 91 | // 92 | // createTime:2019年05月06日 15:53:08 93 | // author:hailaz 94 | func GetPolicyByFullPath(path string) (PolicyName, error) { 95 | obj := PolicyName{} 96 | err := defDB.Table("policy_name").Where("full_path", path).Struct(&obj) 97 | return obj, err 98 | } 99 | 100 | // UpdatePolicyByFullPath 更新权限信息 101 | // 102 | // createTime:2019年05月06日 15:47:35 103 | // author:hailaz 104 | func UpdatePolicyByFullPath(path, name string) error { 105 | p, err := GetPolicyByFullPath(path) 106 | // 不存在插入新数据 107 | if err != nil || p.Id == 0 { 108 | p.FullPath = path 109 | p.Name = name 110 | id, _ := p.Insert() 111 | if id > 0 { 112 | return nil 113 | } else { 114 | return errors.New("update fail") 115 | } 116 | } 117 | // 存在则更新 118 | p.Name = name 119 | i, err := p.Update() 120 | if err != nil { 121 | glog.Error(err) 122 | return err 123 | } 124 | if i < 0 { 125 | return errors.New("update fail") 126 | } 127 | return nil 128 | } 129 | 130 | // ReSetPolicy 更新路由权限 131 | // 132 | // createTime:2019年04月29日 17:30:26 133 | // author:hailaz 134 | func ReSetPolicy(role string, rmap map[string]RolePolicy) { 135 | old := Enforcer.GetPermissionsForUser(role) 136 | for _, item := range old { 137 | glog.Debug(item) 138 | full := fmt.Sprintf("%v %v %v", item[0], item[1], item[2]) 139 | if _, ok := rmap[full]; ok { //从待插入列表中删除已存在的路由 140 | delete(rmap, full) 141 | } else { //删除不存在的旧路由 142 | Enforcer.DeletePermissionForUser(item[0], item[1], item[2]) 143 | if role == "system" { 144 | p, _ := GetPolicyByFullPath(fmt.Sprintf("%v:%v", item[1], item[2])) 145 | if p.Id > 0 { 146 | p.DeleteById(p.Id) 147 | } 148 | } 149 | } 150 | } 151 | for _, item := range rmap { //插入新路由 152 | Enforcer.AddPolicy(item.Role, item.Path, item.Atc) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /static/css/chunk-2a330e22.d5adff47.css: -------------------------------------------------------------------------------- 1 | .dashboard-editor-container[data-v-6eb39d8e]{padding:32px;background-color:#f0f2f5;position:relative}.dashboard-editor-container .github-corner[data-v-6eb39d8e]{position:absolute;top:0;border:0;right:0}.dashboard-editor-container .chart-wrapper[data-v-6eb39d8e]{background:#fff;padding:16px 16px 0;margin-bottom:32px}.pan-item[data-v-0d3d578f]{width:200px;height:200px;border-radius:50%;display:inline-block;position:relative;cursor:default;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.2);box-shadow:0 1px 3px rgba(0,0,0,.2)}.pan-info-roles-container[data-v-0d3d578f]{padding:20px;text-align:center}.pan-thumb[data-v-0d3d578f]{width:100%;height:100%;background-size:100%;border-radius:50%;overflow:hidden;position:absolute;-webkit-transform-origin:95% 40%;transform-origin:95% 40%;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.pan-thumb[data-v-0d3d578f]:after{content:"";width:8px;height:8px;position:absolute;border-radius:50%;top:40%;left:95%;margin:-4px 0 0 -4px;background:radial-gradient(ellipse at center,#0e0e0e 0,#7d7e7d 100%);-webkit-box-shadow:0 0 1px hsla(0,0%,100%,.9);box-shadow:0 0 1px hsla(0,0%,100%,.9)}.pan-info[data-v-0d3d578f]{position:absolute;width:inherit;height:inherit;border-radius:50%;overflow:hidden;-webkit-box-shadow:inset 0 0 0 5px rgba(0,0,0,.05);box-shadow:inset 0 0 0 5px rgba(0,0,0,.05)}.pan-info h3[data-v-0d3d578f]{color:#fff;text-transform:uppercase;position:relative;letter-spacing:2px;font-size:18px;margin:0 60px;padding:22px 0 0 0;height:85px;font-family:Open Sans,Arial,sans-serif;text-shadow:0 0 1px #fff,0 1px 2px rgba(0,0,0,.3)}.pan-info p[data-v-0d3d578f]{color:#fff;padding:10px 5px;font-style:italic;margin:0 30px;font-size:12px;border-top:1px solid hsla(0,0%,100%,.5)}.pan-info p a[data-v-0d3d578f]{display:block;color:#333;width:80px;height:80px;background:hsla(0,0%,100%,.3);border-radius:50%;color:#fff;font-style:normal;font-weight:700;text-transform:uppercase;font-size:9px;letter-spacing:1px;padding-top:24px;margin:7px auto 0;font-family:Open Sans,Arial,sans-serif;opacity:0;-webkit-transition:opacity .3s ease-in-out .2s,background .2s linear 0s,-webkit-transform .3s ease-in-out .2s;transition:opacity .3s ease-in-out .2s,background .2s linear 0s,-webkit-transform .3s ease-in-out .2s;transition:transform .3s ease-in-out .2s,opacity .3s ease-in-out .2s,background .2s linear 0s;transition:transform .3s ease-in-out .2s,opacity .3s ease-in-out .2s,background .2s linear 0s,-webkit-transform .3s ease-in-out .2s;-webkit-transform:translateX(60px) rotate(90deg);transform:translateX(60px) rotate(90deg)}.pan-info p a[data-v-0d3d578f]:hover{background:hsla(0,0%,100%,.5)}.pan-item:hover .pan-thumb[data-v-0d3d578f]{-webkit-transform:rotate(-110deg);transform:rotate(-110deg)}.pan-item:hover .pan-info p a[data-v-0d3d578f]{opacity:1;-webkit-transform:translateX(0) rotate(0deg);transform:translateX(0) rotate(0deg)}.github-corner:hover .octo-arm[data-v-4c6d8d88]{-webkit-animation:octocat-wave-data-v-4c6d8d88 .56s ease-in-out;animation:octocat-wave-data-v-4c6d8d88 .56s ease-in-out}@-webkit-keyframes octocat-wave-data-v-4c6d8d88{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@keyframes octocat-wave-data-v-4c6d8d88{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm[data-v-4c6d8d88]{-webkit-animation:none;animation:none}.github-corner .octo-arm[data-v-4c6d8d88]{-webkit-animation:octocat-wave-data-v-4c6d8d88 .56s ease-in-out;animation:octocat-wave-data-v-4c6d8d88 .56s ease-in-out}}.emptyGif[data-v-9c953d6a]{display:block;width:45%;margin:0 auto}.dashboard-editor-container[data-v-9c953d6a]{background-color:#e3e3e3;min-height:100vh;padding:50px 60px 0}.dashboard-editor-container .pan-info-roles[data-v-9c953d6a]{font-size:12px;font-weight:700;color:#333;display:block}.dashboard-editor-container .info-container[data-v-9c953d6a]{position:relative;margin-left:190px;height:150px;line-height:200px}.dashboard-editor-container .info-container .display_name[data-v-9c953d6a]{font-size:48px;line-height:48px;color:#212121;position:absolute;top:25px} -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | GAdmin vue
-------------------------------------------------------------------------------- /app/model/role.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/gogf/gf/database/gdb" 7 | "github.com/gogf/gf/os/glog" 8 | ) 9 | 10 | type Role struct { 11 | Role string `json:"role"` // 12 | Name string `json:"name"` // 13 | Descrption string `json:"descrption"` // 14 | } 15 | 16 | // GetRoleList 获取权限列表 17 | // 18 | // createTime:2019年05月06日 17:24:12 19 | // author:hailaz 20 | func GetRoleList(page, limit int, defaultname string) ([]Role, int) { 21 | if page < 1 { 22 | page = 1 23 | } 24 | roleList := make([]Role, 0) 25 | roles := Enforcer.GetAllRoles() 26 | total := len(roles) 27 | r, _ := GetAllRole() 28 | pn := make([]RoleName, 0) 29 | r.ToStructs(&pn) 30 | 31 | for _, item := range roles { 32 | p := Role{Role: item, Name: defaultname} 33 | for _, itempn := range pn { 34 | if itempn.RoleKey == item { 35 | p.Name = itempn.Name 36 | p.Descrption = itempn.Descrption 37 | break 38 | } 39 | } 40 | roleList = append(roleList, p) 41 | } 42 | if limit == -1 { 43 | return roleList, total 44 | } 45 | if len(roleList) < page*limit { 46 | if len(roleList) < limit { 47 | roleList = roleList 48 | } else { 49 | roleList = roleList[(page-1)*limit:] 50 | } 51 | } else { 52 | roleList = roleList[(page-1)*limit : (page-1)*limit+limit] 53 | } 54 | return roleList, total 55 | } 56 | 57 | // GetRoleByUserName 根据用户名获取对应角色 58 | // 59 | // createTime:2019年05月08日 15:08:19 60 | // author:hailaz 61 | func GetRoleByUserName(userName string) []Role { 62 | roles, _ := Enforcer.GetRolesForUser(userName) 63 | roleList := make([]Role, 0) 64 | for _, item := range roles { 65 | p := Role{Role: item} 66 | roleList = append(roleList, p) 67 | } 68 | return roleList 69 | } 70 | 71 | // GetAllRole 获取所有角色名称 72 | // 73 | // createTime:2019年04月30日 10:20:50 74 | // author:hailaz 75 | func GetAllRole() (gdb.Result, error) { 76 | return defDB.Table("role_name").All() 77 | } 78 | 79 | // GetRoleByRoleKey 根据角色唯一键获取角色 80 | // 81 | // createTime:2019年05月06日 15:53:08 82 | // author:hailaz 83 | func GetRoleByRoleKey(role string) (RoleName, error) { 84 | obj := RoleName{} 85 | err := defDB.Table("role_name").Where("role_key", role).Struct(&obj) 86 | return obj, err 87 | } 88 | 89 | // UpdateRoleByRoleKey 更新角色信息 90 | // 91 | // createTime:2019年05月06日 15:47:35 92 | // author:hailaz 93 | func UpdateRoleByRoleKey(role, name string) error { 94 | p, err := GetRoleByRoleKey(role) 95 | // 不存在插入新数据 96 | if err != nil || p.Id == 0 { 97 | p.RoleKey = role 98 | p.Name = name 99 | id, _ := p.Insert() 100 | if id > 0 { 101 | return nil 102 | } else { 103 | return errors.New("update fail") 104 | } 105 | } 106 | // 存在则更新 107 | p.Name = name 108 | i, err := p.Update() 109 | if err != nil { 110 | glog.Error(err) 111 | return err 112 | } 113 | if i < 0 { 114 | return errors.New("update fail") 115 | } 116 | return nil 117 | } 118 | 119 | // AddRole 添加角色 120 | // 121 | // createTime:2019年05月07日 10:45:04 122 | // author:hailaz 123 | func AddRole(role, name string) error { 124 | p, err := GetRoleByRoleKey(role) 125 | // 不存在插入新数据 126 | if err != nil || p.Id == 0 { 127 | res := Enforcer.AddGroupingPolicy("system", role) 128 | if !res { 129 | return errors.New("add fail") 130 | } 131 | p.RoleKey = role 132 | p.Name = name 133 | id, _ := p.Insert() 134 | if id > 0 { 135 | return nil 136 | } else { 137 | return errors.New("add fail") 138 | } 139 | } 140 | return errors.New("add fail") 141 | } 142 | 143 | // DeleteRole 删除角色 144 | // 145 | // createTime:2019年05月07日 11:12:59 146 | // author:hailaz 147 | func DeleteRole(role string) error { 148 | p, err := GetRoleByRoleKey(role) 149 | if err != nil || p.Id == 0 { 150 | return errors.New("delete fail") 151 | } 152 | Enforcer.DeleteRole(role) 153 | DeleteRoleMenus(role) 154 | i, _ := p.DeleteById(p.Id) 155 | if i > 0 { 156 | return nil 157 | } 158 | return errors.New("delete fail") 159 | } 160 | 161 | // SetRoleByUserName 设置用户角色 162 | // 163 | // createTime:2019年05月08日 15:22:05 164 | // author:hailaz 165 | func SetRoleByUserName(userName string, roles []string) { 166 | Enforcer.DeleteRolesForUser(userName) 167 | for _, item := range roles { 168 | Enforcer.AddRoleForUser(userName, item) 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /static/css/chunk-015d6b7a.0a66699f.css: -------------------------------------------------------------------------------- 1 | .pan-item[data-v-0d3d578f]{width:200px;height:200px;border-radius:50%;display:inline-block;position:relative;cursor:default;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.2);box-shadow:0 1px 3px rgba(0,0,0,.2)}.pan-info-roles-container[data-v-0d3d578f]{padding:20px;text-align:center}.pan-thumb[data-v-0d3d578f]{width:100%;height:100%;background-size:100%;border-radius:50%;overflow:hidden;position:absolute;-webkit-transform-origin:95% 40%;transform-origin:95% 40%;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.pan-thumb[data-v-0d3d578f]:after{content:"";width:8px;height:8px;position:absolute;border-radius:50%;top:40%;left:95%;margin:-4px 0 0 -4px;background:radial-gradient(ellipse at center,#0e0e0e 0,#7d7e7d 100%);-webkit-box-shadow:0 0 1px hsla(0,0%,100%,.9);box-shadow:0 0 1px hsla(0,0%,100%,.9)}.pan-info[data-v-0d3d578f]{position:absolute;width:inherit;height:inherit;border-radius:50%;overflow:hidden;-webkit-box-shadow:inset 0 0 0 5px rgba(0,0,0,.05);box-shadow:inset 0 0 0 5px rgba(0,0,0,.05)}.pan-info h3[data-v-0d3d578f]{color:#fff;text-transform:uppercase;position:relative;letter-spacing:2px;font-size:18px;margin:0 60px;padding:22px 0 0 0;height:85px;font-family:Open Sans,Arial,sans-serif;text-shadow:0 0 1px #fff,0 1px 2px rgba(0,0,0,.3)}.pan-info p[data-v-0d3d578f]{color:#fff;padding:10px 5px;font-style:italic;margin:0 30px;font-size:12px;border-top:1px solid hsla(0,0%,100%,.5)}.pan-info p a[data-v-0d3d578f]{display:block;color:#333;width:80px;height:80px;background:hsla(0,0%,100%,.3);border-radius:50%;color:#fff;font-style:normal;font-weight:700;text-transform:uppercase;font-size:9px;letter-spacing:1px;padding-top:24px;margin:7px auto 0;font-family:Open Sans,Arial,sans-serif;opacity:0;-webkit-transition:opacity .3s ease-in-out .2s,background .2s linear 0s,-webkit-transform .3s ease-in-out .2s;transition:opacity .3s ease-in-out .2s,background .2s linear 0s,-webkit-transform .3s ease-in-out .2s;transition:transform .3s ease-in-out .2s,opacity .3s ease-in-out .2s,background .2s linear 0s;transition:transform .3s ease-in-out .2s,opacity .3s ease-in-out .2s,background .2s linear 0s,-webkit-transform .3s ease-in-out .2s;-webkit-transform:translateX(60px) rotate(90deg);transform:translateX(60px) rotate(90deg)}.pan-info p a[data-v-0d3d578f]:hover{background:hsla(0,0%,100%,.5)}.pan-item:hover .pan-thumb[data-v-0d3d578f]{-webkit-transform:rotate(-110deg);transform:rotate(-110deg)}.pan-item:hover .pan-info p a[data-v-0d3d578f]{opacity:1;-webkit-transform:translateX(0) rotate(0deg);transform:translateX(0) rotate(0deg)}.box-center[data-v-562f534e]{margin:0 auto;display:table}.text-muted[data-v-562f534e]{color:#777}.user-profile .user-name[data-v-562f534e]{font-weight:700}.user-profile .box-center[data-v-562f534e]{padding-top:10px}.user-profile .user-role[data-v-562f534e]{padding-top:10px;font-weight:400;font-size:14px}.user-profile .box-social[data-v-562f534e]{padding-top:30px}.user-profile .box-social .el-table[data-v-562f534e]{border-top:1px solid #dfe6ec}.user-profile .user-follow[data-v-562f534e]{padding-top:20px}.user-bio[data-v-562f534e]{margin-top:20px;color:#606266}.user-bio span[data-v-562f534e]{padding-left:4px}.user-bio .user-bio-section[data-v-562f534e]{font-size:14px;padding:15px 0}.user-bio .user-bio-section .user-bio-section-header[data-v-562f534e]{border-bottom:1px solid #dfe6ec;padding-bottom:10px;margin-bottom:10px;font-weight:700}.user-activity .user-block .description[data-v-6fd9b025],.user-activity .user-block .username[data-v-6fd9b025]{display:block;margin-left:50px;padding:2px 0}.user-activity .user-block .username[data-v-6fd9b025]{font-size:16px;color:#000}.user-activity .user-block[data-v-6fd9b025] :after{clear:both}.user-activity .user-block .img-circle[data-v-6fd9b025]{border-radius:50%;width:40px;height:40px;float:left}.user-activity .user-block span[data-v-6fd9b025]{font-weight:500;font-size:12px}.user-activity .post[data-v-6fd9b025]{font-size:14px;border-bottom:1px solid #d2d6de;margin-bottom:15px;padding-bottom:15px;color:#666}.user-activity .post .image[data-v-6fd9b025]{width:100%;height:100%}.user-activity .post .user-images[data-v-6fd9b025]{padding-top:20px}.user-activity .list-inline[data-v-6fd9b025]{padding-left:0;margin-left:-5px;list-style:none}.user-activity .list-inline li[data-v-6fd9b025]{display:inline-block;padding-right:5px;padding-left:5px;font-size:13px}.user-activity .list-inline .link-black[data-v-6fd9b025]:focus,.user-activity .list-inline .link-black[data-v-6fd9b025]:hover{color:#999}.box-center[data-v-6fd9b025]{margin:0 auto;display:table}.text-muted[data-v-6fd9b025]{color:#777} -------------------------------------------------------------------------------- /static/css/chunk-508832c0.fed07099.css: -------------------------------------------------------------------------------- 1 | .wscn-http404-container[data-v-22c31b5a]{-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);position:absolute;top:40%;left:50%}.wscn-http404[data-v-22c31b5a]{position:relative;width:1200px;padding:0 50px;overflow:hidden}.wscn-http404 .pic-404[data-v-22c31b5a]{position:relative;float:left;width:600px;overflow:hidden}.wscn-http404 .pic-404__parent[data-v-22c31b5a]{width:100%}.wscn-http404 .pic-404__child[data-v-22c31b5a]{position:absolute}.wscn-http404 .pic-404__child.left[data-v-22c31b5a]{width:80px;top:17px;left:220px;opacity:0;-webkit-animation-name:cloudLeft-data-v-22c31b5a;animation-name:cloudLeft-data-v-22c31b5a;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}.wscn-http404 .pic-404__child.mid[data-v-22c31b5a]{width:46px;top:10px;left:420px;opacity:0;-webkit-animation-name:cloudMid-data-v-22c31b5a;animation-name:cloudMid-data-v-22c31b5a;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1.2s;animation-delay:1.2s}.wscn-http404 .pic-404__child.right[data-v-22c31b5a]{width:62px;top:100px;left:500px;opacity:0;-webkit-animation-name:cloudRight-data-v-22c31b5a;animation-name:cloudRight-data-v-22c31b5a;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}@-webkit-keyframes cloudLeft-data-v-22c31b5a{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@keyframes cloudLeft-data-v-22c31b5a{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@-webkit-keyframes cloudMid-data-v-22c31b5a{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@keyframes cloudMid-data-v-22c31b5a{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@-webkit-keyframes cloudRight-data-v-22c31b5a{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}@keyframes cloudRight-data-v-22c31b5a{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}.wscn-http404 .bullshit[data-v-22c31b5a]{position:relative;float:left;width:300px;padding:30px 0;overflow:hidden}.wscn-http404 .bullshit__oops[data-v-22c31b5a]{font-size:32px;line-height:40px;color:#1482f0;margin-bottom:20px;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__headline[data-v-22c31b5a],.wscn-http404 .bullshit__oops[data-v-22c31b5a]{font-weight:700;opacity:0;-webkit-animation-name:slideUp-data-v-22c31b5a;animation-name:slideUp-data-v-22c31b5a;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__headline[data-v-22c31b5a]{font-size:20px;line-height:24px;color:#222;margin-bottom:10px;-webkit-animation-delay:.1s;animation-delay:.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-22c31b5a]{font-size:13px;line-height:21px;color:grey;margin-bottom:30px;-webkit-animation-delay:.2s;animation-delay:.2s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-22c31b5a],.wscn-http404 .bullshit__return-home[data-v-22c31b5a]{opacity:0;-webkit-animation-name:slideUp-data-v-22c31b5a;animation-name:slideUp-data-v-22c31b5a;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__return-home[data-v-22c31b5a]{display:block;float:left;width:110px;height:36px;background:#1482f0;border-radius:100px;text-align:center;color:#fff;font-size:14px;line-height:36px;cursor:pointer;-webkit-animation-delay:.3s;animation-delay:.3s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}@-webkit-keyframes slideUp-data-v-22c31b5a{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes slideUp-data-v-22c31b5a{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}} -------------------------------------------------------------------------------- /app/model/casbin_adapter.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | 7 | "github.com/casbin/casbin/model" 8 | "github.com/casbin/casbin/persist" 9 | "github.com/gogf/gf/database/gdb" 10 | ) 11 | 12 | type CasbinRule struct { 13 | Id int64 `json:"id"` // 14 | PType string `json:"p_type"` // 15 | V0 string `json:"v0"` // 16 | V1 string `json:"v1"` // 17 | V2 string `json:"v2"` // 18 | V3 string `json:"v3"` // 19 | V4 string `json:"v4"` // 20 | V5 string `json:"v5"` // 21 | } 22 | 23 | const ( 24 | CASBINRULE_TABLE_NAME = "casbin_rule" 25 | ) 26 | 27 | // Adapter represents the Xorm adapter for policy storage. 28 | type Adapter struct { 29 | o gdb.DB 30 | } 31 | 32 | func NewAdapter(db gdb.DB) *Adapter { 33 | a := &Adapter{o: db} 34 | 35 | // Open the DB, create it if not existed. 36 | a.open() 37 | 38 | // Call the destructor when the object is released. 39 | runtime.SetFinalizer(a, finalizer) 40 | 41 | return a 42 | } 43 | 44 | // finalizer is the destructor for Adapter. 45 | func finalizer(a *Adapter) { 46 | } 47 | 48 | func (a *Adapter) open() { 49 | 50 | } 51 | 52 | func (a *Adapter) close() { 53 | a.o = nil 54 | } 55 | 56 | func (a *Adapter) createTable() { 57 | } 58 | 59 | func (a *Adapter) dropTable() { 60 | } 61 | 62 | func loadPolicyLine(line CasbinRule, model model.Model) { 63 | lineText := line.PType 64 | if line.V0 != "" { 65 | lineText += ", " + line.V0 66 | } 67 | if line.V1 != "" { 68 | lineText += ", " + line.V1 69 | } 70 | if line.V2 != "" { 71 | lineText += ", " + line.V2 72 | } 73 | if line.V3 != "" { 74 | lineText += ", " + line.V3 75 | } 76 | if line.V4 != "" { 77 | lineText += ", " + line.V4 78 | } 79 | if line.V5 != "" { 80 | lineText += ", " + line.V5 81 | } 82 | 83 | persist.LoadPolicyLine(lineText, model) 84 | } 85 | 86 | // LoadPolicy loads policy from database. 87 | func (a *Adapter) LoadPolicy(model model.Model) error { 88 | var lines []CasbinRule 89 | err := a.o.Table(CASBINRULE_TABLE_NAME).Structs(&lines) 90 | 91 | if err != nil { 92 | return err 93 | } 94 | 95 | for _, line := range lines { 96 | loadPolicyLine(line, model) 97 | } 98 | 99 | return nil 100 | } 101 | 102 | func savePolicyLine(ptype string, rule []string) CasbinRule { 103 | line := CasbinRule{} 104 | 105 | line.PType = ptype 106 | if len(rule) > 0 { 107 | line.V0 = rule[0] 108 | } 109 | if len(rule) > 1 { 110 | line.V1 = rule[1] 111 | } 112 | if len(rule) > 2 { 113 | line.V2 = rule[2] 114 | } 115 | if len(rule) > 3 { 116 | line.V3 = rule[3] 117 | } 118 | if len(rule) > 4 { 119 | line.V4 = rule[4] 120 | } 121 | if len(rule) > 5 { 122 | line.V5 = rule[5] 123 | } 124 | 125 | return line 126 | } 127 | 128 | // SavePolicy saves policy to database. 129 | func (a *Adapter) SavePolicy(model model.Model) error { 130 | 131 | var lines []CasbinRule 132 | 133 | for ptype, ast := range model["p"] { 134 | for _, rule := range ast.Policy { 135 | line := savePolicyLine(ptype, rule) 136 | lines = append(lines, line) 137 | } 138 | } 139 | 140 | for ptype, ast := range model["g"] { 141 | for _, rule := range ast.Policy { 142 | line := savePolicyLine(ptype, rule) 143 | lines = append(lines, line) 144 | } 145 | } 146 | 147 | _, err := a.o.BatchInsert(CASBINRULE_TABLE_NAME, lines) 148 | return err 149 | } 150 | 151 | // AddPolicy adds a policy rule to the storage. 152 | func (a *Adapter) AddPolicy(sec string, ptype string, rule []string) error { 153 | line := savePolicyLine(ptype, rule) 154 | _, err := a.o.Insert(CASBINRULE_TABLE_NAME, &line) 155 | return err 156 | } 157 | 158 | // RemovePolicy removes a policy rule from the storage. 159 | func (a *Adapter) RemovePolicy(sec string, ptype string, rule []string) error { 160 | qs := a.o.Table(CASBINRULE_TABLE_NAME).Safe() 161 | qs = qs.Where("p_type", ptype) 162 | for index := 0; index < len(rule); index++ { 163 | qs = qs.And(fmt.Sprintf("v%d", index), rule[index]) 164 | } 165 | _, err := qs.Delete() 166 | return err 167 | 168 | } 169 | 170 | // RemoveFilteredPolicy removes policy rules that match the filter from the storage. 171 | func (a *Adapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error { 172 | qs := a.o.Table(CASBINRULE_TABLE_NAME).Safe() 173 | qs = qs.Where("p_type", ptype) 174 | for index := 0; index <= 5; index++ { 175 | if fieldIndex <= index && index < fieldIndex+len(fieldValues) { 176 | qs = qs.And(fmt.Sprintf("v%d", index), fieldValues[index-fieldIndex]) 177 | } 178 | } 179 | _, err := qs.Delete() 180 | return err 181 | } 182 | -------------------------------------------------------------------------------- /app/api/userController.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "github.com/gogf/gf/database/gdb" 5 | 6 | "github.com/gogf/gf/os/glog" 7 | "github.com/hailaz/gadmin/app/model" 8 | "github.com/hailaz/gadmin/library/code" 9 | ) 10 | 11 | type UserController struct { 12 | BaseController 13 | } 14 | 15 | func (c *UserController) Info() { 16 | u := c.GetUser() 17 | if u != nil { 18 | Success(c.Request, u.GetUserInfo()) 19 | } 20 | Fail(c.Request, code.RESPONSE_ERROR, "获取用户信息失败") 21 | } 22 | 23 | func (c *UserController) Menu() { 24 | rolename := c.Request.GetString("rolename") 25 | if rolename != "" { 26 | var list struct { 27 | Menus []model.MenuOut `json:"menus"` 28 | RoleMenus []model.MenuOut `json:"role_menus"` 29 | } 30 | list.Menus = model.GetMenuByRoleName([]string{model.ADMIN_NAME}) 31 | list.RoleMenus = model.GetMenuByRoleName([]string{rolename}) 32 | Success(c.Request, list) 33 | } 34 | u := c.GetUser() 35 | if u != nil { 36 | if u.UserName == model.ADMIN_NAME { 37 | Success(c.Request, model.GetMenuByRoleName([]string{model.ADMIN_NAME})) 38 | } else { 39 | roles, _ := model.Enforcer.GetRolesForUser(u.UserName) 40 | Success(c.Request, model.GetMenuByRoleName(roles)) 41 | } 42 | 43 | } 44 | Fail(c.Request, code.RESPONSE_ERROR, "获取用户菜单失败") 45 | } 46 | 47 | func (c *UserController) Get() { 48 | page := c.Request.GetInt("page", 1) 49 | limit := c.Request.GetInt("limit", 10) 50 | var userList struct { 51 | List []model.UserOut `json:"items"` 52 | Total int `json:"total"` 53 | } 54 | userList.List, userList.Total = model.GetUserByPageLimt(page, limit) 55 | Success(c.Request, userList) 56 | } 57 | func (c *UserController) Post() { 58 | data, _ := c.Request.GetJson() 59 | username := data.GetString("user_name") 60 | 61 | nickname := data.GetString("nick_name") 62 | email := data.GetString("email") 63 | password := data.GetString("password") 64 | passwordconfirm := data.GetString("passwordconfirm") 65 | phone := data.GetString("phone") 66 | 67 | u, err := model.GetUserByName(username) 68 | if u != nil || err == nil { 69 | Fail(c.Request, code.RESPONSE_ERROR, "用户已存在") 70 | } 71 | if password == "" { 72 | Fail(c.Request, code.RESPONSE_ERROR, "密码为空") 73 | } 74 | if password != passwordconfirm { 75 | Fail(c.Request, code.RESPONSE_ERROR, "输入密码不一致") 76 | } 77 | addu := c.GetUser() 78 | var addUserId int64 = 0 79 | if addu != nil { 80 | addUserId = addu.Id 81 | } 82 | user := model.User{UserName: username, Password: password, NickName: nickname, Email: email, Phone: phone, AddUserId: addUserId} 83 | uid, _ := user.Insert() 84 | if uid > 0 { 85 | Success(c.Request, "success") 86 | } 87 | 88 | glog.Debug(uid) 89 | glog.Debug(data.ToJsonString()) 90 | Fail(c.Request, code.RESPONSE_ERROR) 91 | } 92 | func (c *UserController) Put() { 93 | data, _ := c.Request.GetJson() 94 | username := data.GetString("user_name") 95 | nickname := data.GetString("nick_name") 96 | email := data.GetString("email") 97 | password := data.GetString("password") 98 | passwordconfirm := data.GetString("passwordconfirm") 99 | phone := data.GetString("phone") 100 | 101 | u, err := model.GetUserByName(username) 102 | if err != nil || u.Id == 0 { 103 | Fail(c.Request, code.RESPONSE_ERROR, "用户不存在") 104 | } 105 | umap := gdb.Map{} 106 | if nickname != u.NickName && nickname != "" { 107 | umap["nick_name"] = nickname 108 | } 109 | if email != u.Email && email != "" { 110 | umap["email"] = email 111 | } 112 | if phone != u.Phone && phone != "" { 113 | umap["phone"] = phone 114 | } 115 | if password == "" { 116 | err := model.UpdateUserById(u.Id, umap) 117 | if err != nil { 118 | Fail(c.Request, code.RESPONSE_ERROR, err.Error()) 119 | } 120 | } else { 121 | if password != passwordconfirm { 122 | Fail(c.Request, code.RESPONSE_ERROR, "输入密码不一致") 123 | } 124 | umap["password"] = model.EncryptPassword(password) 125 | err := model.UpdateUserById(u.Id, umap) 126 | if err != nil { 127 | Fail(c.Request, code.RESPONSE_ERROR, err.Error()) 128 | } 129 | } 130 | 131 | Success(c.Request, "success") 132 | } 133 | func (c *UserController) Delete() { 134 | data, _ := c.Request.GetJson() 135 | id := data.GetInt64("id") 136 | if id < 1 { 137 | Fail(c.Request, code.RESPONSE_ERROR) 138 | } 139 | u := new(model.User) 140 | user, err := u.GetById(id) 141 | if err != nil { 142 | Fail(c.Request, code.RESPONSE_ERROR, err.Error()) 143 | } 144 | if user.UserName == model.ADMIN_NAME { 145 | Fail(c.Request, code.RESPONSE_ERROR, "无权限") 146 | } 147 | res, _ := u.DeleteById(id) 148 | if res <= 0 { 149 | Fail(c.Request, code.RESPONSE_ERROR) 150 | } 151 | model.Enforcer.DeleteRolesForUser(user.UserName) 152 | Success(c.Request, "success") 153 | } 154 | -------------------------------------------------------------------------------- /router/router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/gogf/gf/encoding/gparser" 7 | "github.com/gogf/gf/frame/g" 8 | 9 | "github.com/gogf/gf/net/ghttp" 10 | "github.com/gogf/gf/os/glog" 11 | "github.com/gogf/gf/util/gconv" 12 | "github.com/hailaz/gadmin/app/api" 13 | "github.com/hailaz/gadmin/app/model" 14 | "github.com/hailaz/gadmin/library/common" 15 | ) 16 | 17 | var routerMap = make(map[string]model.RolePolicy) 18 | 19 | func showURL(r *ghttp.Request) { 20 | glog.Debug("请求路径:", r.Method, r.Request.RequestURI) 21 | //r.Response.CORSDefault() 22 | } 23 | 24 | // InitRouter 初始化路由 25 | // 26 | // createTime:2019年05月13日 09:32:58 27 | // author:hailaz 28 | func InitRouter(s *ghttp.Server) { 29 | initApiDocRouter(s) 30 | 31 | s.BindHookHandler("/*", ghttp.HOOK_BEFORE_SERVE, showURL) 32 | InitV1(s) 33 | 34 | model.ReSetPolicy("system", routerMap) 35 | } 36 | 37 | // authHook 鉴权钩子 38 | // 39 | // createTime:2019年05月13日 09:33:58 40 | // author:hailaz 41 | // authHook is the HOOK function implements JWT logistics. 42 | func authHook(r *ghttp.Request) { 43 | switch r.Request.RequestURI { //登录相关免鉴权 44 | case "/v1/loginkey": 45 | return 46 | case "/v1/login": 47 | return 48 | default: 49 | r.Response.CORSDefault() //开启跨域 50 | api.GfJWTMiddleware.MiddlewareFunc()(r) //鉴权中间件 51 | } 52 | } 53 | 54 | // InitV1 初始化V1 55 | // 56 | // createTime:2019年04月25日 09:24:06 57 | // author:hailaz 58 | func InitV1(s *ghttp.Server) { 59 | //v1 := s.Group("/v1") 60 | //权限验证 61 | s.Group("/v1").ALL("/*any", authHook, ghttp.HOOK_BEFORE_SERVE) 62 | userCtrl := new(api.UserController) 63 | roleCtrl := new(api.RoleController) 64 | policyCtrl := new(api.PolicyController) 65 | menuCtrl := new(api.MenuController) 66 | 67 | // user 68 | BindGroup(s, "/v1", []ghttp.GroupItem{ 69 | //登录 70 | {"false", "GET", "/loginkey", api.GetLoginCryptoKey}, //获取登录加密公钥 71 | {"false", "POST", "/login", api.GfJWTMiddleware.LoginHandler}, //登录 72 | {"false", "GET", "/refresh_token", api.GfJWTMiddleware.RefreshHandler}, //获取登录加密公钥 73 | {"false", "POST", "/logout", api.Logout}, //登出 74 | //menu 75 | {"", "REST", "/menu", menuCtrl}, 76 | // 用户 77 | {"false", "GET", "/user/info", userCtrl, "Info"}, 78 | {"false", "GET", "/user/menu", userCtrl, "Menu"}, 79 | {"", "REST", "/user", userCtrl}, 80 | // 角色 81 | {"", "REST", "/role", roleCtrl}, 82 | {"", "PUT", "/role/byuser", roleCtrl, "SetRoleByUserName"}, 83 | {"", "PUT", "/role/menu", roleCtrl, "SetRoleMenus"}, 84 | // 权限 85 | {"", "REST", "/policy", policyCtrl}, 86 | {"", "GET", "/policy/byrole", policyCtrl, "GetPolicyByRole"}, 87 | {"", "PUT", "/policy/byrole", policyCtrl, "SetPolicyByRole"}, 88 | }) 89 | } 90 | 91 | // BindGroup 绑定分组路由 92 | // 93 | // createTime:2019年04月29日 16:45:55 94 | // author:hailaz 95 | func BindGroup(s *ghttp.Server, path string, items []ghttp.GroupItem) { 96 | for index, item := range items { 97 | if gconv.String(item[0]) == "false" { //不走权限的api 98 | addPolicy("*", path+gconv.String(item[2]), common.GetAction(gconv.String(item[1]))) 99 | } else { //走权限的api 100 | if gconv.String(item[1]) == "REST" { //rest api 101 | addPolicy("system", path+gconv.String(item[2]), model.ACTION_GET) 102 | addPolicy("system", path+gconv.String(item[2]), model.ACTION_POST) 103 | addPolicy("system", path+gconv.String(item[2]), model.ACTION_PUT) 104 | addPolicy("system", path+gconv.String(item[2]), model.ACTION_DELETE) 105 | } else { 106 | addPolicy("system", path+gconv.String(item[2]), common.GetAction(gconv.String(item[1]))) 107 | } 108 | } 109 | // 裁切掉权限控制 110 | items[index] = items[index][1:] 111 | } 112 | 113 | g := s.Group(path) 114 | g.Bind(items) 115 | 116 | } 117 | 118 | // addPolicy 记录需要系统路由 119 | // 120 | // createTime:2019年04月29日 17:18:25 121 | // author:hailaz 122 | func addPolicy(role, path, atc string) { 123 | routerMap[fmt.Sprintf("%v %v %v", role, path, atc)] = model.RolePolicy{Role: role, Path: path, Atc: atc} 124 | } 125 | 126 | // initApiDocRouter 初始化api文档路由 127 | // 128 | // createTime:2019年05月14日 09:05:26 129 | // author:hailaz 130 | func initApiDocRouter(s *ghttp.Server) { 131 | s.BindHandler("/swagger.{mime}", func(r *ghttp.Request) { 132 | r.Response.CORSDefault() 133 | r.Response.Header().Set("Access-Control-Allow-Origin", "*") 134 | //r.Response.Writeln(r.Get("mime")) 135 | p, err := gparser.Load("docfile/swagger.yaml") 136 | if err != nil { 137 | r.Response.Writeln(err.Error()) 138 | return 139 | } 140 | 141 | switch r.Get("mime") { 142 | case "json": 143 | j, _ := p.ToJson() 144 | r.Response.WriteJson(j) 145 | default: 146 | y, _ := p.ToYaml() 147 | r.Response.Write(y) 148 | } 149 | 150 | }) 151 | s.BindHandler("/swagger", func(r *ghttp.Request) { 152 | r.Response.RedirectTo("https://petstore.swagger.io/?url=http://localhost:" + g.Config().GetString("port", "8080") + "/swagger.yaml") 153 | }) 154 | } 155 | -------------------------------------------------------------------------------- /static/js/chunk-cbf46a0a.daf42114.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-cbf46a0a"],{"01e6":function(t,n,e){},2017:function(t,n,e){"use strict";var s=e("3b76"),o=e.n(s);o.a},"3b76":function(t,n,e){},"4cba":function(t,n,e){"use strict";var s=e("b63b"),o=e.n(s);o.a},"9ed6":function(t,n,e){"use strict";e.r(n);var s=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("div",{staticClass:"login-container"},[e("el-form",{ref:"loginForm",staticClass:"login-form",attrs:{model:t.loginForm,rules:t.loginRules,"auto-complete":"on","label-position":"left"}},[e("div",{staticClass:"title-container"},[e("h3",{staticClass:"title"},[t._v("\n "+t._s(t.$t("login.title"))+"\n ")]),t._v(" "),e("lang-select",{staticClass:"set-language"})],1),t._v(" "),e("el-form-item",{attrs:{prop:"username"}},[e("span",{staticClass:"svg-container"},[e("svg-icon",{attrs:{"icon-class":"user"}})],1),t._v(" "),e("el-input",{ref:"username",attrs:{placeholder:t.$t("login.username"),name:"username",type:"text",tabindex:"1","auto-complete":"on"},model:{value:t.loginForm.username,callback:function(n){t.$set(t.loginForm,"username",n)},expression:"loginForm.username"}})],1),t._v(" "),e("el-tooltip",{attrs:{content:"Caps lock is On",placement:"right",manual:""},model:{value:t.capsTooltip,callback:function(n){t.capsTooltip=n},expression:"capsTooltip"}},[e("el-form-item",{attrs:{prop:"password"}},[e("span",{staticClass:"svg-container"},[e("svg-icon",{attrs:{"icon-class":"password"}})],1),t._v(" "),e("el-input",{key:t.passwordType,ref:"password",attrs:{type:t.passwordType,placeholder:t.$t("login.password"),name:"password",tabindex:"2","auto-complete":"on"},on:{blur:function(n){t.capsTooltip=!1}},nativeOn:{keyup:[function(n){return t.checkCapslock(n)},function(n){return!n.type.indexOf("key")&&t._k(n.keyCode,"enter",13,n.key,"Enter")?null:t.handleLogin(n)}]},model:{value:t.loginForm.password,callback:function(n){t.$set(t.loginForm,"password",n)},expression:"loginForm.password"}}),t._v(" "),e("span",{staticClass:"show-pwd",on:{click:t.showPwd}},[e("svg-icon",{attrs:{"icon-class":"password"===t.passwordType?"eye":"eye-open"}})],1)],1)],1),t._v(" "),e("el-button",{staticStyle:{width:"100%","margin-bottom":"30px"},attrs:{loading:t.loading,type:"primary"},nativeOn:{click:function(n){return n.preventDefault(),t.handleLogin(n)}}},[t._v("\n "+t._s(t.$t("login.logIn"))+"\n ")])],1),t._v(" "),e("el-dialog",{attrs:{title:t.$t("login.thirdparty"),visible:t.showDialog},on:{"update:visible":function(n){t.showDialog=n}}},[t._v("\n "+t._s(t.$t("login.thirdpartyTips"))+"\n "),e("br"),t._v(" "),e("br"),t._v(" "),e("br"),t._v(" "),e("social-sign")],1)],1)},o=[],i=e("a4bb"),a=e.n(i),r=e("1131"),c=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("div",{staticClass:"social-signup-container"},[e("div",{staticClass:"sign-btn",on:{click:function(n){return t.wechatHandleClick("wechat")}}},[e("span",{staticClass:"wx-svg-container"},[e("svg-icon",{staticClass:"icon",attrs:{"icon-class":"wechat"}})],1),t._v("\n WeChat\n ")]),t._v(" "),e("div",{staticClass:"sign-btn",on:{click:function(n){return t.tencentHandleClick("tencent")}}},[e("span",{staticClass:"qq-svg-container"},[e("svg-icon",{staticClass:"icon",attrs:{"icon-class":"qq"}})],1),t._v("\n QQ\n ")])])},l=[],u={name:"SocialSignin",methods:{wechatHandleClick:function(t){alert("ok")},tencentHandleClick:function(t){alert("ok")}}},p=u,d=(e("edc1"),e("2877")),g=Object(d["a"])(p,c,l,!1,null,"c817cede",null),h=g.exports,f={name:"Login",components:{LangSelect:r["a"],SocialSign:h},data:function(){var t=function(t,n,e){e()},n=function(t,n,e){n.length<6?e(new Error("The password can not be less than 6 digits")):e()};return{loginForm:{username:"admin",password:"123456"},loginRules:{username:[{required:!0,trigger:"blur",validator:t}],password:[{required:!0,trigger:"blur",validator:n}]},passwordType:"password",capsTooltip:!1,loading:!1,showDialog:!1,redirect:void 0,otherQuery:{}}},watch:{$route:{handler:function(t){var n=t.query;n&&(this.redirect=n.redirect,this.otherQuery=this.getOtherQuery(n))},immediate:!0}},created:function(){},mounted:function(){""===this.loginForm.username?this.$refs.username.focus():""===this.loginForm.password&&this.$refs.password.focus()},destroyed:function(){},methods:{checkCapslock:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.shiftKey,e=t.key;e&&1===e.length&&(this.capsTooltip=!!(n&&e>="a"&&e<="z"||!n&&e>="A"&&e<="Z")),"CapsLock"===e&&!0===this.capsTooltip&&(this.capsTooltip=!1)},showPwd:function(){var t=this;"password"===this.passwordType?this.passwordType="":this.passwordType="password",this.$nextTick(function(){t.$refs.password.focus()})},handleLogin:function(){var t=this;this.$refs.loginForm.validate(function(n){if(!n)return console.log("error submit!!"),!1;t.loading=!0,t.$store.dispatch("user/login",t.loginForm).then(function(){t.$router.push({path:t.redirect||"/",query:t.otherQuery}),t.loading=!1}).catch(function(){t.loading=!1})})},getOtherQuery:function(t){return a()(t).reduce(function(n,e){return"redirect"!==e&&(n[e]=t[e]),n},{})}}},m=f,v=(e("2017"),e("4cba"),Object(d["a"])(m,s,o,!1,null,"40da4f90",null));n["default"]=v.exports},b63b:function(t,n,e){},edc1:function(t,n,e){"use strict";var s=e("01e6"),o=e.n(s);o.a}}]); -------------------------------------------------------------------------------- /static/js/chunk-2a330e22.9d637d72.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2a330e22"],{"0bca":function(t,a,e){"use strict";var n=e("e9b4"),i=e.n(n);i.a},"22a6":function(t,a,e){},2452:function(t,a,e){"use strict";var n=e("8715"),i=e.n(n);i.a},"364d":function(t,a,e){"use strict";var n=e("c65c"),i=e.n(n);i.a},"3cbc":function(t,a,e){"use strict";var n=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"pan-item",style:{zIndex:t.zIndex,height:t.height,width:t.width}},[e("div",{staticClass:"pan-info"},[e("div",{staticClass:"pan-info-roles-container"},[t._t("default")],2)]),t._v(" "),e("img",{staticClass:"pan-thumb",attrs:{src:t.image}})])},i=[],s=(e("c5f6"),{name:"PanThumb",props:{image:{type:String,required:!0},zIndex:{type:Number,default:1},width:{type:String,default:"150px"},height:{type:String,default:"150px"}}}),r=s,c=(e("2452"),e("2877")),o=Object(c["a"])(r,n,i,!1,null,"0d3d578f",null);a["a"]=o.exports},8715:function(t,a,e){},9406:function(t,a,e){"use strict";e.r(a);var n=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"dashboard-container"},[e(t.currentRole,{tag:"component"})],1)},i=[],s=(e("6762"),e("2fdb"),e("cebc")),r=e("2f62"),c=function(){var t=this,a=t.$createElement;t._self._c;return t._m(0)},o=[function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"dashboard-editor-container"},[t._v("\n Welcome to gadmin!\n "),e("br"),t._v(" "),e("a",{attrs:{href:"https://github.com/hailaz/gadmin",target:"_blank",rel:"noopener noreferrer"}},[e("img",{staticStyle:{width:"90%","max-width":"1200px"},attrs:{src:"https://github.com/hailaz/gadmin/raw/master/docfile/gadmin.png",alt:"gadmin结构",title:"访问 gadmin github"}})])])}],l={newVisitis:{expectedData:[100,120,161,134,105,160,165],actualData:[120,82,91,154,162,140,145]},messages:{expectedData:[200,192,120,144,160,130,140],actualData:[180,160,151,106,145,150,130]},purchases:{expectedData:[80,100,121,104,105,90,100],actualData:[120,90,100,138,142,130,130]},shoppings:{expectedData:[130,140,141,142,145,150,160],actualData:[120,82,91,154,162,140,130]}},d={name:"DashboardAdmin",components:{},data:function(){return{lineChartData:l.newVisitis}},methods:{handleSetLineChartData:function(t){this.lineChartData=l[t]}}},u=d,h=(e("0bca"),e("2877")),f=Object(h["a"])(u,c,o,!1,null,"6eb39d8e",null),p=f.exports,m=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"dashboard-editor-container"},[e("div",{staticClass:" clearfix"},[e("pan-thumb",{staticStyle:{float:"left"},attrs:{image:t.avatar}},[t._v("\n Your roles:\n "),t._l(t.roles,function(a){return e("span",{key:a,staticClass:"pan-info-roles"},[t._v(t._s(a))])})],2),t._v(" "),e("github-corner",{staticStyle:{position:"absolute",top:"0px",border:"0",right:"0"}}),t._v(" "),e("div",{staticClass:"info-container"},[e("span",{staticClass:"display_name"},[t._v(t._s(t.name))]),t._v(" "),e("span",{staticStyle:{"font-size":"20px","padding-top":"20px",display:"inline-block"}},[t._v("Editor's Dashboard")])])],1),t._v(" "),e("div",[e("img",{staticClass:"emptyGif",attrs:{src:t.emptyGif}})])])},b=[],C=e("3cbc"),v=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("a",{staticClass:"github-corner",attrs:{href:"https://github.com/PanJiaChen/vue-element-admin",target:"_blank","aria-label":"View source on Github"}},[e("svg",{staticStyle:{fill:"#40c9c6",color:"#fff"},attrs:{width:"80",height:"80",viewBox:"0 0 250 250","aria-hidden":"true"}},[e("path",{attrs:{d:"M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"}}),t._v(" "),e("path",{staticClass:"octo-arm",staticStyle:{"transform-origin":"130px 106px"},attrs:{d:"M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2",fill:"currentColor"}}),t._v(" "),e("path",{staticClass:"octo-body",attrs:{d:"M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z",fill:"currentColor"}})])])},g=[],_=(e("364d"),{}),x=Object(h["a"])(_,v,g,!1,null,"4c6d8d88",null),w=x.exports,D={name:"DashboardEditor",components:{PanThumb:C["a"],GithubCorner:w},data:function(){return{emptyGif:"https://wpimg.wallstcn.com/0e03b7da-db9e-4819-ba10-9016ddfdaed3"}},computed:Object(s["a"])({},Object(r["b"])(["name","avatar","roles"]))},y=D,S=(e("efff"),Object(h["a"])(y,m,b,!1,null,"9c953d6a",null)),j=S.exports,O={name:"Dashboard",components:{adminDashboard:p,editorDashboard:j},data:function(){return{currentRole:"adminDashboard"}},computed:Object(s["a"])({},Object(r["b"])(["roles"])),created:function(){this.roles.includes("admin")||(this.currentRole="editorDashboard")}},E=O,L=Object(h["a"])(E,n,i,!1,null,null,null);a["default"]=L.exports},c65c:function(t,a,e){},e9b4:function(t,a,e){},efff:function(t,a,e){"use strict";var n=e("22a6"),i=e.n(n);i.a}}]); -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= 4 | github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= 5 | github.com/casbin/casbin v1.9.1 h1:ucjbS5zTrmSLtH4XogqOG920Poe6QatdXtz1FEbApeM= 6 | github.com/casbin/casbin v1.9.1/go.mod h1:z8uPsfBJGUsnkagrt3G8QvjgTKFMBJ32UP8HpZllfog= 7 | github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= 8 | github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= 9 | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 10 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 11 | github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= 12 | github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= 13 | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= 14 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 15 | github.com/gf-third/mysql v1.4.2 h1:f1M5CNFUG3WkE07UOomtu4o0n/KJKeuUUf5Nc9ZFXs4= 16 | github.com/gf-third/mysql v1.4.2/go.mod h1:+dd90V663ppI2fV5uQ6+rHk0u8KCyU6FkG8Um8Cx3ms= 17 | github.com/gf-third/yaml v1.0.1 h1:pqD4ix+65DqGphU1MDnToPZfGYk0tuuwRzuTSl3g0d0= 18 | github.com/gf-third/yaml v1.0.1/go.mod h1:t443vj0txEw3+E0MOtkr83kt+PrZg2I8SRuYfn85NM0= 19 | github.com/gogf/gf v1.9.7/go.mod h1:sitJZHjmT9B+923N4mH5rkM19AugKG+BxI47R64bR08= 20 | github.com/gogf/gf v1.11.3 h1:2CRPTGqbeSRTLZLBF8r6TOeT3eMinQfUWReLWiJTJ9Q= 21 | github.com/gogf/gf v1.11.3/go.mod h1:/37gncPmuM06D4YSqiDze9GsasDtF2QnWkUfKeiGW/Q= 22 | github.com/gogf/gf-jwt v1.1.0 h1:FrtDAMyaexbj/cEDTcSn2ViPVwAvkds2eGhKO80ZA8w= 23 | github.com/gogf/gf-jwt v1.1.0/go.mod h1:m4TC9GrveQM7peXcZfsgz9QUkMlacSsk39e6kYQPUQs= 24 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 25 | github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= 26 | github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= 27 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= 28 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 29 | github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= 30 | github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 31 | github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf h1:wIOAyJMMen0ELGiFzlmqxdcV1yGbkyHBAB6PolcNbLA= 32 | github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= 33 | github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 34 | github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= 35 | github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 36 | github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88= 37 | github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= 38 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 39 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 40 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 41 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 42 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 43 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 44 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 45 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 46 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 47 | golang.org/x/sys v0.0.0-20190924092210-98129a5cf4a0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 48 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e h1:9vRrk9YW2BTzLP0VCB9ZDjU4cPqkg+IDWL7XgxA1yxQ= 49 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 50 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 51 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 52 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 53 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 54 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 55 | google.golang.org/appengine v1.6.3 h1:hvZejVcIxAKHR8Pq2gXaDggf6CWT1QEqO+JEBeOKCG8= 56 | google.golang.org/appengine v1.6.3/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 57 | -------------------------------------------------------------------------------- /app/api/auth.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "encoding/base64" 5 | "time" 6 | 7 | jwt "github.com/gogf/gf-jwt" 8 | "github.com/gogf/gf/frame/g" 9 | "github.com/gogf/gf/net/ghttp" 10 | "github.com/gogf/gf/os/glog" 11 | "github.com/gogf/gf/os/gtime" 12 | "github.com/hailaz/gadmin/app/model" 13 | "github.com/hailaz/gadmin/library/common" 14 | ) 15 | 16 | var ( 17 | // The underlying JWT middleware. 18 | GfJWTMiddleware *jwt.GfJWTMiddleware 19 | ) 20 | 21 | // Initialization function, 22 | // rewrite this function to customized your own JWT settings. 23 | func init() { 24 | authMiddleware, err := jwt.New(&jwt.GfJWTMiddleware{ 25 | Realm: "gf admin", 26 | Key: []byte("secret key"), 27 | Timeout: time.Minute * 10, //token有效时间 28 | MaxRefresh: time.Minute * 10, //token刷新有效时间 29 | IdentityKey: "username", // 用户关键字 30 | TokenLookup: "header: Authorization", // 捕抓请求的指定数据 31 | TokenHeadName: "gadmin", // token 头名称 32 | TimeFunc: time.Now, 33 | Authenticator: Authenticator, //登录验证 34 | LoginResponse: LoginResponse, //登录返回token 35 | RefreshResponse: RefreshResponse, //刷新token 36 | Unauthorized: Unauthorized, //未登录返回 37 | IdentityHandler: IdentityHandler, //返回数据给Authorizator 38 | PayloadFunc: PayloadFunc, //将Authenticator返回的内容记录到jwt 39 | Authorizator: Authorizator, //接收IdentityHandler数据并判断权限 40 | HTTPStatusMessageFunc: HTTPStatusMessageFunc, //错误处理 41 | }) 42 | if err != nil { 43 | glog.Fatal("JWT Error:" + err.Error()) 44 | } 45 | GfJWTMiddleware = authMiddleware 46 | } 47 | 48 | // GetLoginCryptoKey 获取登录的加密key 49 | // 50 | // createTime:2019年04月24日 13:57:34 51 | // author:hailaz 52 | func GetLoginCryptoKey(r *ghttp.Request) { 53 | kid := r.Session.Id() 54 | ck := common.GenCryptoKey(kid) 55 | // glog.Debug("kid:" + kid) 56 | Success(r, ck) 57 | } 58 | 59 | func Logout(r *ghttp.Request) { 60 | Success(r, "success") 61 | } 62 | 63 | func PayloadFunc(data interface{}) jwt.MapClaims { 64 | claims := jwt.MapClaims{} 65 | params := data.(map[string]interface{}) 66 | if len(params) > 0 { 67 | for k, v := range params { 68 | claims[k] = v 69 | } 70 | } 71 | return claims 72 | } 73 | 74 | func Authorizator(data interface{}, r *ghttp.Request) bool { 75 | method := r.Method 76 | path := r.URL.Path 77 | //glog.Debugf("user:%v ,method:%v ,path:%v", data, method, path) 78 | return model.Enforcer.Enforce(data, path, method) 79 | } 80 | 81 | // IdentityHandler sets the identity for JWT. 82 | func IdentityHandler(r *ghttp.Request) interface{} { 83 | claims := jwt.ExtractClaims(r) 84 | return claims["username"] 85 | } 86 | 87 | // Unauthorized is used to define customized Unauthorized callback function. 88 | func Unauthorized(r *ghttp.Request, code int, message string) { 89 | Fail(r, code, message) 90 | } 91 | 92 | func HTTPStatusMessageFunc(e error, r *ghttp.Request) string { 93 | glog.Debug(e.Error()) 94 | switch e.Error() { 95 | case "Token is expired": 96 | return "token超时" 97 | } 98 | return e.Error() 99 | } 100 | 101 | // LoginResponse is used to define customized login-successful callback function. 102 | func LoginResponse(r *ghttp.Request, code int, token string, expire time.Time) { 103 | var tk struct { 104 | Token string `json:"token"` 105 | Expire string `json:"expire"` 106 | } 107 | tk.Token = GfJWTMiddleware.TokenHeadName + " " + token 108 | tk.Expire = expire.Format(time.RFC3339) 109 | Success(r, tk) 110 | } 111 | 112 | // RefreshResponse is used to get a new token no matter current token is expired or not. 113 | func RefreshResponse(r *ghttp.Request, code int, token string, expire time.Time) { 114 | var tk struct { 115 | Token string `json:"token"` 116 | Expire string `json:"expire"` 117 | } 118 | tk.Token = GfJWTMiddleware.TokenHeadName + " " + token 119 | tk.Expire = expire.Format(time.RFC3339) 120 | Success(r, tk) 121 | } 122 | 123 | // Authenticator 登录验证 124 | // 125 | // createTime:2019年05月13日 10:00:22 126 | // author:hailaz 127 | func Authenticator(r *ghttp.Request) (interface{}, error) { 128 | data, _ := r.GetJson() 129 | name := data.GetString("username") 130 | pwd := data.GetString("password") 131 | kid := data.GetString("kid") 132 | 133 | if ck := common.GetCryptoKey(kid); ck != nil { 134 | if gtime.Second()-ck.TimeStamp >= 5 { //加密key超时时间 135 | return nil, jwt.ErrFailedAuthentication 136 | } 137 | //glog.Debugf("%v", ck.Id) 138 | //glog.Debugf("%v", ck.Key) 139 | //glog.Debugf("%v %v", name, pwd) 140 | decodePwd, err := base64.StdEncoding.DecodeString(pwd) 141 | if err != nil { 142 | return nil, err 143 | } 144 | decryptPwd, _ := common.RsaDecrypt(decodePwd, []byte(ck.PrivateKey)) 145 | //glog.Debug(string(decryptPwd)) 146 | password := string(decryptPwd) 147 | //glog.Debugf("%v %v", name, password) 148 | if password != "" { 149 | u, err := model.GetUserByName(name) 150 | if err != nil { 151 | return nil, err 152 | } 153 | if u.Password == model.EncryptPassword(password) { 154 | return g.Map{ 155 | "username": u.UserName, 156 | "id": u.Id, 157 | }, nil 158 | } 159 | 160 | } 161 | } 162 | 163 | return nil, jwt.ErrFailedAuthentication 164 | } 165 | -------------------------------------------------------------------------------- /app/model/menu.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/gogf/gf/frame/g" 5 | "github.com/gogf/gf/database/gdb" 6 | ) 7 | 8 | type MenuMetaOut struct { 9 | Id int64 `json:"-"` // 10 | MenuName string `json:"-"` //菜单关键名 11 | Title string `json:"title"` //名称 12 | Icon string `json:"icon"` //图标 13 | Nocache bool `json:"noCache"` //是否缓存 14 | } 15 | 16 | type MenuOut struct { 17 | Id int64 `json:"-"` // 18 | MenuPath string `json:"path"` //菜单路径 19 | Component string `json:"component"` //页面模块 20 | Redirect string `json:"redirect"` //重定向地址 21 | Name string `json:"name"` //唯一关键名 22 | Hidden bool `json:"hidden"` //是否隐藏 23 | Alwaysshow bool `json:"alwaysShow"` //是否常显示 24 | Sort int `json:"sort"` //排序 25 | ParentName string `json:"parent_name"` //父菜级关键名 26 | AutoCreate bool `json:"auto_create"` //是否自动生成 27 | MenuMetaOut MenuMetaOut `json:"meta"` 28 | Children []MenuOut `json:"children"` 29 | } 30 | 31 | // IsStringInSlice description 32 | // 33 | // createTime:2019年05月21日 15:50:15 34 | // author:hailaz 35 | func IsStringInSlice(str string, strs []string) bool { 36 | for _, item := range strs { 37 | if item == str { 38 | return true 39 | } 40 | } 41 | return false 42 | } 43 | 44 | // GetMenuByRoleName description 45 | // 46 | // createTime:2019年05月16日 17:19:53 47 | // author:hailaz 48 | func GetMenuByRoleName(roles []string) []MenuOut { 49 | menus := make([]MenuOut, 0) 50 | if IsStringInSlice(ADMIN_NAME, roles) { 51 | r, _ := defDB.Table("menu").All() 52 | r.ToStructs(&menus) 53 | } else { 54 | roleSlice := make(g.Slice, 0) 55 | for _, item := range roles { 56 | roleSlice = append(roleSlice, item) 57 | } 58 | r, _ := defDB.Table("role_menu rm,menu m").Where("rm.menu_name=m.name AND rm.role_key IN (?)", roleSlice).Fields("m.*").All() 59 | r.ToStructs(&menus) 60 | } 61 | 62 | for index, item := range menus { 63 | meta := MenuMetaOut{} 64 | r, _ := defDB.Table("menu_meta").Where("menu_name=?", item.Name).One() 65 | r.ToStruct(&meta) 66 | menus[index].MenuMetaOut = meta 67 | } 68 | menuRoot := make([]MenuOut, 0) 69 | childs := make([]*MenuOut, 0) 70 | for index, item := range menus { //分类菜单,一级菜单与非一级菜单 71 | if item.ParentName == "" { 72 | menuRoot = append(menuRoot, item) 73 | } else { 74 | childs = append(childs, &menus[index]) 75 | } 76 | } 77 | for index, _ := range menuRoot { 78 | FindChildren(&menuRoot[index], childs) 79 | } 80 | 81 | return menuRoot 82 | } 83 | 84 | // FindChildren 找子菜单 85 | // 86 | // createTime:2019年05月17日 09:15:52 87 | // author:hailaz 88 | func FindChildren(mo *MenuOut, list []*MenuOut) { 89 | for _, item := range list { 90 | if item.ParentName == mo.Name { 91 | mo.Children = append(mo.Children, *item) 92 | } 93 | } 94 | for index := 0; index < len(mo.Children); index++ { 95 | FindChildren(&mo.Children[index], list) 96 | } 97 | } 98 | 99 | // GetMenuByName 根据名称获取菜单 100 | // 101 | // createTime:2019年04月23日 17:14:22 102 | // author:hailaz 103 | func GetMenuByName(name string) (*Menu, error) { 104 | m := Menu{} 105 | err := defDB.Table("menu").Where("name", name).Struct(&m) 106 | if err != nil { 107 | return nil, err 108 | } 109 | return &m, nil 110 | } 111 | 112 | // IsMenuExist 菜单是否存在 113 | // 114 | // createTime:2019年05月17日 11:04:45 115 | // author:hailaz 116 | func IsMenuExist(name string) bool { 117 | m := Menu{} 118 | defDB.Table("menu").Where("name", name).Struct(&m) 119 | if m.Id > 0 { 120 | return true 121 | } 122 | return false 123 | } 124 | 125 | // InsertMenuWithMeta 插入菜单 126 | // 127 | // createTime:2019年05月17日 11:12:13 128 | // author:hailaz 129 | func InsertMenuWithMeta(list gdb.List) { 130 | for _, item := range list { 131 | if !IsMenuExist(item["name"].(string)) { 132 | mate := item["meta"].(gdb.Map) 133 | mate["menu_name"] = item["name"].(string) 134 | delete(item, "meta") 135 | defDB.Insert("menu", item) 136 | defDB.Insert("menu_meta", mate) 137 | } 138 | } 139 | } 140 | 141 | // GetMenuList 获取菜单列表 142 | // 143 | // createTime:2019年05月17日 16:17:33 144 | // author:hailaz 145 | func GetMenuList(page, limit int) ([]MenuOut, int) { 146 | if page < 1 { 147 | page = 1 148 | } 149 | if limit < 1 { 150 | limit = 10 151 | } 152 | total, _ := defDB.Table("menu").Count() 153 | if total == 0 { 154 | return nil, 0 155 | } 156 | 157 | menuList := make([]MenuOut, 0) 158 | if total < page*limit { 159 | if total < limit { 160 | page = 1 161 | } 162 | } 163 | r, err := defDB.Table("menu").Limit((page-1)*limit, (page-1)*limit+limit).Select() 164 | if err != nil { 165 | return nil, 0 166 | } 167 | r.ToStructs(&menuList) 168 | for index, item := range menuList { 169 | meta := MenuMetaOut{} 170 | r, _ := defDB.Table("menu_meta").Where("menu_name=?", item.Name).One() 171 | r.ToStruct(&meta) 172 | menuList[index].MenuMetaOut = meta 173 | } 174 | return menuList, total 175 | } 176 | 177 | // UpdateMenuByName description 178 | // 179 | // createTime:2019年05月17日 17:54:40 180 | // author:hailaz 181 | func UpdateMenuByName(name string, dataMap gdb.Map) error { 182 | mate := dataMap["meta"].(gdb.Map) 183 | delete(dataMap, "meta") 184 | _, err := defDB.Update("menu", dataMap, "name=?", name) 185 | if err != nil { 186 | return err 187 | } 188 | _, err = defDB.Update("menu_meta", mate, "menu_name=?", name) 189 | if err != nil { 190 | return err 191 | } 192 | return nil 193 | } 194 | -------------------------------------------------------------------------------- /static/js/chunk-296d0504.61c10fec.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-296d0504"],{"0f7b":function(t,e,n){"use strict";var i=n("e4d3"),a=n.n(i);a.a},"1b26":function(t,e,n){"use strict";n.d(e,"b",function(){return a}),n.d(e,"d",function(){return o}),n.d(e,"a",function(){return r}),n.d(e,"c",function(){return u});var i=n("b775");function a(t){return Object(i["a"])({url:"/policy",method:"get",params:t})}function o(t){return Object(i["a"])({url:"/policy",method:"put",data:t})}function r(t){return Object(i["a"])({url:"/policy/byrole",method:"get",params:t})}function u(t){return Object(i["a"])({url:"/policy/byrole",method:"put",data:t})}},"1c64":function(t,e,n){},"1cc6":function(t,e,n){"use strict";var i=n("1c64"),a=n.n(i);a.a},"333d":function(t,e,n){"use strict";var i=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"pagination-container",class:{hidden:t.hidden}},[n("el-pagination",t._b({attrs:{background:t.background,"current-page":t.currentPage,"page-size":t.pageSize,layout:t.layout,"page-sizes":t.pageSizes,total:t.total},on:{"update:currentPage":function(e){t.currentPage=e},"update:current-page":function(e){t.currentPage=e},"update:pageSize":function(e){t.pageSize=e},"update:page-size":function(e){t.pageSize=e},"size-change":t.handleSizeChange,"current-change":t.handleCurrentChange}},"el-pagination",t.$attrs,!1))],1)},a=[];n("c5f6");Math.easeInOutQuad=function(t,e,n,i){return t/=i/2,t<1?n/2*t*t+e:(t--,-n/2*(t*(t-2)-1)+e)};var o=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(t){window.setTimeout(t,1e3/60)}}();function r(t){document.documentElement.scrollTop=t,document.body.parentNode.scrollTop=t,document.body.scrollTop=t}function u(){return document.documentElement.scrollTop||document.body.parentNode.scrollTop||document.body.scrollTop}function c(t,e,n){var i=u(),a=t-i,c=20,l=0;e="undefined"===typeof e?500:e;var s=function t(){l+=c;var u=Math.easeInOutQuad(l,i,a,e);r(u),l0,expression:"total>0"}],attrs:{total:t.total,page:t.listQuery.page,limit:t.listQuery.limit},on:{"update:page":function(e){return t.$set(t.listQuery,"page",e)},"update:limit":function(e){return t.$set(t.listQuery,"limit",e)},pagination:t.getList}})],1)},a=[],o=(n("7f7f"),n("1b26")),r=n("333d"),u={name:"InlineEditTable",components:{Pagination:r["a"]},filters:{statusFilter:function(t){var e={published:"success",draft:"info",deleted:"danger"};return e[t]}},data:function(){return{list:null,listLoading:!0,total:0,listQuery:{page:1,limit:10,importance:void 0,title:void 0,type:void 0}}},created:function(){this.getList()},methods:{getList:function(){var t=this;this.listLoading=!0,Object(o["b"])(this.listQuery).then(function(e){t.total=e.data.total,t.list=e.data.items.map(function(e){return t.$set(e,"edit",!1),e.originalName=e.name,e}),setTimeout(function(){t.listLoading=!1},500)})},cancelEdit:function(t){t.name=t.originalName,t.edit=!1},confirmEdit:function(t){var e=this;t.edit=!1,t.originalName=t.name,Object(o["d"])(t).then(function(){console.log("123"),e.$message({message:"The title has been edited",type:"success"})}).catch(function(){e.$message({message:"编辑失败",type:"error"})})}}},c=u,l=(n("0f7b"),n("2877")),s=Object(l["a"])(c,i,a,!1,null,"b1948282",null);e["default"]=s.exports},e4d3:function(t,e,n){}}]); -------------------------------------------------------------------------------- /docfile/sql/all.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS `gadmin` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */ /*!80016 DEFAULT ENCRYPTION='N' */; 2 | USE `gadmin`; 3 | -- MySQL dump 10.13 Distrib 8.0.17, for Win64 (x86_64) 4 | -- 5 | -- Host: localhost Database: gadmin 6 | -- ------------------------------------------------------ 7 | -- Server version 8.0.17 8 | 9 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 10 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 11 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 12 | /*!50503 SET NAMES utf8 */; 13 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 14 | /*!40103 SET TIME_ZONE='+00:00' */; 15 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 16 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 17 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 18 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 19 | 20 | -- 21 | -- Table structure for table `casbin_rule` 22 | -- 23 | 24 | DROP TABLE IF EXISTS `casbin_rule`; 25 | /*!40101 SET @saved_cs_client = @@character_set_client */; 26 | /*!50503 SET character_set_client = utf8mb4 */; 27 | CREATE TABLE `casbin_rule` ( 28 | `id` int(11) NOT NULL AUTO_INCREMENT, 29 | `p_type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 30 | `v0` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 31 | `v1` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 32 | `v2` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 33 | `v3` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 34 | `v4` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 35 | `v5` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', 36 | PRIMARY KEY (`id`) USING BTREE 37 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 38 | /*!40101 SET character_set_client = @saved_cs_client */; 39 | 40 | -- 41 | -- Table structure for table `menu` 42 | -- 43 | 44 | DROP TABLE IF EXISTS `menu`; 45 | /*!40101 SET @saved_cs_client = @@character_set_client */; 46 | /*!50503 SET character_set_client = utf8mb4 */; 47 | CREATE TABLE `menu` ( 48 | `id` int(11) NOT NULL AUTO_INCREMENT, 49 | `menu_path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '菜单路径', 50 | `component` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '页面模块', 51 | `redirect` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '重定向地址', 52 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '唯一关键名', 53 | `hidden` tinyint(1) DEFAULT '0' COMMENT '是否隐藏', 54 | `alwaysshow` tinyint(1) DEFAULT '0' COMMENT '是否常显示', 55 | `sort` tinyint(2) DEFAULT '0' COMMENT '排序', 56 | `parent_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '父菜级关键名', 57 | `auto_create` tinyint(1) DEFAULT '0' COMMENT '是否自动生成', 58 | PRIMARY KEY (`id`) USING BTREE, 59 | UNIQUE KEY `key_name` (`name`) USING BTREE 60 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 61 | /*!40101 SET character_set_client = @saved_cs_client */; 62 | 63 | -- 64 | -- Table structure for table `menu_meta` 65 | -- 66 | 67 | DROP TABLE IF EXISTS `menu_meta`; 68 | /*!40101 SET @saved_cs_client = @@character_set_client */; 69 | /*!50503 SET character_set_client = utf8mb4 */; 70 | CREATE TABLE `menu_meta` ( 71 | `id` int(11) NOT NULL AUTO_INCREMENT, 72 | `menu_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '菜单关键名', 73 | `title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '名称', 74 | `icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '图标', 75 | `nocache` tinyint(1) DEFAULT '0' COMMENT '是否缓存', 76 | PRIMARY KEY (`id`) USING BTREE, 77 | UNIQUE KEY `key_name` (`menu_name`) USING BTREE 78 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 79 | /*!40101 SET character_set_client = @saved_cs_client */; 80 | 81 | -- 82 | -- Table structure for table `policy_name` 83 | -- 84 | 85 | DROP TABLE IF EXISTS `policy_name`; 86 | /*!40101 SET @saved_cs_client = @@character_set_client */; 87 | /*!50503 SET character_set_client = utf8mb4 */; 88 | CREATE TABLE `policy_name` ( 89 | `id` int(11) NOT NULL AUTO_INCREMENT, 90 | `full_path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '权限完整路径', 91 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '权限名称', 92 | `descrption` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '描述', 93 | PRIMARY KEY (`id`) USING BTREE, 94 | UNIQUE KEY `full_path_index` (`full_path`) USING BTREE 95 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 96 | /*!40101 SET character_set_client = @saved_cs_client */; 97 | 98 | -- 99 | -- Table structure for table `role_menu` 100 | -- 101 | 102 | DROP TABLE IF EXISTS `role_menu`; 103 | /*!40101 SET @saved_cs_client = @@character_set_client */; 104 | /*!50503 SET character_set_client = utf8mb4 */; 105 | CREATE TABLE `role_menu` ( 106 | `id` int(11) NOT NULL AUTO_INCREMENT, 107 | `role_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色key', 108 | `menu_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '菜单关键名', 109 | PRIMARY KEY (`id`) USING BTREE 110 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 111 | /*!40101 SET character_set_client = @saved_cs_client */; 112 | 113 | -- 114 | -- Table structure for table `role_name` 115 | -- 116 | 117 | DROP TABLE IF EXISTS `role_name`; 118 | /*!40101 SET @saved_cs_client = @@character_set_client */; 119 | /*!50503 SET character_set_client = utf8mb4 */; 120 | CREATE TABLE `role_name` ( 121 | `id` int(11) NOT NULL AUTO_INCREMENT, 122 | `role_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '角色key', 123 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '角色名', 124 | `descrption` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '描述', 125 | PRIMARY KEY (`id`) USING BTREE, 126 | UNIQUE KEY `role_key_index` (`role_key`) USING BTREE 127 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 128 | /*!40101 SET character_set_client = @saved_cs_client */; 129 | 130 | -- 131 | -- Table structure for table `user` 132 | -- 133 | 134 | DROP TABLE IF EXISTS `user`; 135 | /*!40101 SET @saved_cs_client = @@character_set_client */; 136 | /*!50503 SET character_set_client = utf8mb4 */; 137 | CREATE TABLE `user` ( 138 | `id` int(11) NOT NULL AUTO_INCREMENT, 139 | `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态', 140 | `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户名', 141 | `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '昵称', 142 | `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '密码', 143 | `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '邮箱', 144 | `phone` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '手机号', 145 | `sex` tinyint(6) NOT NULL DEFAULT '0' COMMENT '性别', 146 | `age` tinyint(6) NOT NULL DEFAULT '0' COMMENT '年龄', 147 | `add_time` datetime NOT NULL COMMENT '添加时间', 148 | `update_time` datetime NOT NULL COMMENT '修改时间', 149 | `add_user_id` int(11) NOT NULL DEFAULT '0' COMMENT '操作用户', 150 | `Introduction` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '介绍', 151 | `avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '头像', 152 | PRIMARY KEY (`id`) USING BTREE, 153 | UNIQUE KEY `username` (`user_name`) USING BTREE 154 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 155 | /*!40101 SET character_set_client = @saved_cs_client */; 156 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 157 | 158 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 159 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 160 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 161 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 162 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 163 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 164 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 165 | 166 | -- Dump completed on 2020-01-16 16:19:47 167 | -------------------------------------------------------------------------------- /static/js/chunk-015d6b7a.3faa4a94.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-015d6b7a"],{"22e9":function(t,e,s){},2452:function(t,e,s){"use strict";var a=s("8715"),i=s.n(a);i.a},"3cbc":function(t,e,s){"use strict";var a=function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"pan-item",style:{zIndex:t.zIndex,height:t.height,width:t.width}},[s("div",{staticClass:"pan-info"},[s("div",{staticClass:"pan-info-roles-container"},[t._t("default")],2)]),t._v(" "),s("img",{staticClass:"pan-thumb",attrs:{src:t.image}})])},i=[],n=(s("c5f6"),{name:"PanThumb",props:{image:{type:String,required:!0},zIndex:{type:Number,default:1},width:{type:String,default:"150px"},height:{type:String,default:"150px"}}}),r=n,l=(s("2452"),s("2877")),c=Object(l["a"])(r,a,i,!1,null,"0d3d578f",null);e["a"]=c.exports},6975:function(t,e,s){},8715:function(t,e,s){},"8fa5":function(t,e,s){"use strict";var a=s("22e9"),i=s.n(a);i.a},ec02:function(t,e,s){"use strict";var a=s("6975"),i=s.n(a);i.a},ecac:function(t,e,s){"use strict";s.r(e);var a=function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"app-container"},[t.user?s("div",[s("el-row",{attrs:{gutter:20}},[s("el-col",{attrs:{span:6,xs:24}},[s("user-card",{attrs:{user:t.user}})],1),t._v(" "),s("el-col",{attrs:{span:18,xs:24}},[s("el-card",[s("el-tabs",{model:{value:t.activeTab,callback:function(e){t.activeTab=e},expression:"activeTab"}},[s("el-tab-pane",{attrs:{label:"Activity",name:"activity"}},[s("activity")],1),t._v(" "),s("el-tab-pane",{attrs:{label:"Timeline",name:"timeline"}},[s("timeline")],1),t._v(" "),s("el-tab-pane",{attrs:{label:"Account",name:"account"}},[s("account",{attrs:{user:t.user}})],1)],1)],1)],1)],1)],1):t._e()])},i=[],n=(s("7f7f"),s("cebc")),r=s("2f62"),l=function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("el-card",{staticStyle:{"margin-bottom":"20px"}},[s("div",{staticClass:"clearfix",attrs:{slot:"header"},slot:"header"},[s("span",[t._v("About me")])]),t._v(" "),s("div",{staticClass:"user-profile"},[s("div",{staticClass:"box-center"},[s("pan-thumb",{attrs:{image:t.user.avatar,height:"100px",width:"100px",hoverable:!1}},[s("div",[t._v("Hello")]),t._v("\n "+t._s(t.user.role)+"\n ")])],1),t._v(" "),s("div",{staticClass:"box-center"},[s("div",{staticClass:"user-name text-center"},[t._v(t._s(t.user.name))]),t._v(" "),s("div",{staticClass:"user-role text-center text-muted"},[t._v(t._s(t._f("uppercaseFirst")(t.user.role)))])])]),t._v(" "),s("div",{staticClass:"user-bio"},[s("div",{staticClass:"user-education user-bio-section"},[s("div",{staticClass:"user-bio-section-header"},[s("svg-icon",{attrs:{"icon-class":"education"}}),s("span",[t._v("Education")])],1),t._v(" "),s("div",{staticClass:"user-bio-section-body"},[s("div",{staticClass:"text-muted"},[t._v("\n JS in Computer Science from the University of Technology\n ")])])]),t._v(" "),s("div",{staticClass:"user-skills user-bio-section"},[s("div",{staticClass:"user-bio-section-header"},[s("svg-icon",{attrs:{"icon-class":"skill"}}),s("span",[t._v("Skills")])],1),t._v(" "),s("div",{staticClass:"user-bio-section-body"},[s("div",{staticClass:"progress-item"},[s("span",[t._v("Vue")]),t._v(" "),s("el-progress",{attrs:{percentage:70}})],1),t._v(" "),s("div",{staticClass:"progress-item"},[s("span",[t._v("JavaScript")]),t._v(" "),s("el-progress",{attrs:{percentage:18}})],1),t._v(" "),s("div",{staticClass:"progress-item"},[s("span",[t._v("Css")]),t._v(" "),s("el-progress",{attrs:{percentage:12}})],1),t._v(" "),s("div",{staticClass:"progress-item"},[s("span",[t._v("ESLint")]),t._v(" "),s("el-progress",{attrs:{percentage:100,status:"success"}})],1)])])])])},c=[],o=s("3cbc"),u={components:{PanThumb:o["a"]},props:{user:{type:Object,default:function(){return{name:"",email:"",avatar:"",roles:""}}}}},m=u,p=(s("ec02"),s("2877")),v=Object(p["a"])(m,l,c,!1,null,"562f534e",null),d=v.exports,f=function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"user-activity"},[s("div",{staticClass:"post"},[s("div",{staticClass:"user-block"},[s("img",{staticClass:"img-circle",attrs:{src:"https://wpimg.wallstcn.com/57ed425a-c71e-4201-9428-68760c0537c4.jpg"+t.avatarPrefix}}),t._v(" "),s("span",{staticClass:"username text-muted"},[t._v("Iron Man")]),t._v(" "),s("span",{staticClass:"description"},[t._v("Shared publicly - 7:30 PM today")])]),t._v(" "),s("p",[t._v("\n Lorem ipsum represents a long-held tradition for designers,\n typographers and the like. Some people hate it and argue for\n its demise, but others ignore the hate as they create awesome\n tools to help create filler text for everyone from bacon lovers\n to Charlie Sheen fans.\n ")]),t._v(" "),s("ul",{staticClass:"list-inline"},[t._m(0),t._v(" "),s("li",[s("span",{staticClass:"link-black text-sm"},[s("svg-icon",{attrs:{"icon-class":"like"}}),t._v("\n Like\n ")],1)])])]),t._v(" "),s("div",{staticClass:"post"},[s("div",{staticClass:"user-block"},[s("img",{staticClass:"img-circle",attrs:{src:"https://wpimg.wallstcn.com/9e2a5d0a-bd5b-457f-ac8e-86554616c87b.jpg"+t.avatarPrefix}}),t._v(" "),s("span",{staticClass:"username text-muted"},[t._v("Captain American")]),t._v(" "),s("span",{staticClass:"description"},[t._v("Sent you a message - yesterday")])]),t._v(" "),s("p",[t._v("\n Lorem ipsum represents a long-held tradition for designers,\n typographers and the like. Some people hate it and argue for\n its demise, but others ignore the hate as they create awesome\n tools to help create filler text for everyone from bacon lovers\n to Charlie Sheen fans.\n ")]),t._v(" "),s("ul",{staticClass:"list-inline"},[t._m(1),t._v(" "),s("li",[s("span",{staticClass:"link-black text-sm"},[s("svg-icon",{attrs:{"icon-class":"like"}}),t._v("\n Like\n ")],1)])])]),t._v(" "),s("div",{staticClass:"post"},[s("div",{staticClass:"user-block"},[s("img",{staticClass:"img-circle",attrs:{src:"https://wpimg.wallstcn.com/fb57f689-e1ab-443c-af12-8d4066e202e2.jpg"+t.avatarPrefix}}),t._v(" "),s("span",{staticClass:"username"},[t._v("Spider Man")]),t._v(" "),s("span",{staticClass:"description"},[t._v("Posted 4 photos - 2 days ago")])]),t._v(" "),s("div",{staticClass:"user-images"},[s("el-carousel",{attrs:{interval:6e3,type:"card",height:"220px"}},t._l(t.carouselImages,function(e){return s("el-carousel-item",{key:e},[s("img",{staticClass:"image",attrs:{src:e+t.carouselPrefix}})])}),1)],1),t._v(" "),s("ul",{staticClass:"list-inline"},[t._m(2),t._v(" "),s("li",[s("span",{staticClass:"link-black text-sm"},[s("svg-icon",{attrs:{"icon-class":"like"}}),t._v(" Like")],1)])])])])},_=[function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("li",[s("span",{staticClass:"link-black text-sm"},[s("i",{staticClass:"el-icon-share"}),t._v("\n Share\n ")])])},function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("li",[s("span",{staticClass:"link-black text-sm"},[s("i",{staticClass:"el-icon-share"}),t._v("\n Share\n ")])])},function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("li",[s("span",{staticClass:"link-black text-sm"},[s("i",{staticClass:"el-icon-share"}),t._v(" Share")])])}],h="?imageView2/1/w/80/h/80",b="?imageView2/2/h/440",g={data:function(){return{carouselImages:["https://wpimg.wallstcn.com/9679ffb0-9e0b-4451-9916-e21992218054.jpg","https://wpimg.wallstcn.com/bcce3734-0837-4b9f-9261-351ef384f75a.jpg","https://wpimg.wallstcn.com/d1d7b033-d75e-4cd6-ae39-fcd5f1c0a7c5.jpg","https://wpimg.wallstcn.com/50530061-851b-4ca5-9dc5-2fead928a939.jpg"],avatarPrefix:h,carouselPrefix:b}}},C=g,x=(s("8fa5"),Object(p["a"])(C,f,_,!1,null,"6fd9b025",null)),y=x.exports,k=function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"block"},[s("el-timeline",t._l(t.timeline,function(e,a){return s("el-timeline-item",{key:a,attrs:{timestamp:e.timestamp,placement:"top"}},[s("el-card",[s("h4",[t._v(t._s(e.title))]),t._v(" "),s("p",[t._v(t._s(e.content))])])],1)}),1)],1)},w=[],S={data:function(){return{timeline:[{timestamp:"2019/4/20",title:"Update Github template",content:"PanJiaChen committed 2019/4/20 20:46"},{timestamp:"2019/4/21",title:"Update Github template",content:"PanJiaChen committed 2019/4/21 20:46"},{timestamp:"2019/4/22",title:"Build Template",content:"PanJiaChen committed 2019/4/22 20:46"},{timestamp:"2019/4/23",title:"Release New Version",content:"PanJiaChen committed 2019/4/23 20:46"}]}}},j=S,P=Object(p["a"])(j,k,w,!1,null,null,null),E=P.exports,$=function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("el-form",[s("el-form-item",{attrs:{label:"Name"}},[s("el-input",{model:{value:t.user.name,callback:function(e){t.$set(t.user,"name","string"===typeof e?e.trim():e)},expression:"user.name"}})],1),t._v(" "),s("el-form-item",{attrs:{label:"Email"}},[s("el-input",{model:{value:t.user.email,callback:function(e){t.$set(t.user,"email","string"===typeof e?e.trim():e)},expression:"user.email"}})],1),t._v(" "),s("el-form-item",[s("el-button",{attrs:{type:"primary"},on:{click:t.submit}},[t._v("Update")])],1)],1)},O=[],T={props:{user:{type:Object,default:function(){return{name:"",email:""}}}},methods:{submit:function(){this.$message({message:"User information has been updated successfully",type:"success",duration:5e3})}}},J=T,U=Object(p["a"])(J,$,O,!1,null,null,null),A=U.exports,I={name:"Profile",components:{UserCard:d,Activity:y,Timeline:E,Account:A},data:function(){return{user:{},activeTab:"activity"}},computed:Object(n["a"])({},Object(r["b"])(["name","avatar","roles"])),created:function(){this.getUser()},methods:{getUser:function(){this.user={name:this.name,role:this.roles.join(" | "),email:"admin@test.com",avatar:this.avatar}}}},L=I,V=Object(p["a"])(L,a,i,!1,null,null,null);e["default"]=V.exports}}]); -------------------------------------------------------------------------------- /static/js/chunk-3296490b.44372469.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-3296490b"],{"1c64":function(e,t,n){},"1cc6":function(e,t,n){"use strict";var a=n("1c64"),i=n.n(a);i.a},"333d":function(e,t,n){"use strict";var a=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"pagination-container",class:{hidden:e.hidden}},[n("el-pagination",e._b({attrs:{background:e.background,"current-page":e.currentPage,"page-size":e.pageSize,layout:e.layout,"page-sizes":e.pageSizes,total:e.total},on:{"update:currentPage":function(t){e.currentPage=t},"update:current-page":function(t){e.currentPage=t},"update:pageSize":function(t){e.pageSize=t},"update:page-size":function(t){e.pageSize=t},"size-change":e.handleSizeChange,"current-change":e.handleCurrentChange}},"el-pagination",e.$attrs,!1))],1)},i=[];n("c5f6");Math.easeInOutQuad=function(e,t,n,a){return e/=a/2,e<1?n/2*e*e+t:(e--,-n/2*(e*(e-2)-1)+t)};var l=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(e){window.setTimeout(e,1e3/60)}}();function o(e){document.documentElement.scrollTop=e,document.body.parentNode.scrollTop=e,document.body.scrollTop=e}function r(){return document.documentElement.scrollTop||document.body.parentNode.scrollTop||document.body.scrollTop}function s(e,t,n){var a=r(),i=e-a,s=20,c=0;t="undefined"===typeof t?500:t;var u=function e(){c+=s;var r=Math.easeInOutQuad(c,a,i,t);o(r),c0,expression:"total>0"}],attrs:{total:e.total,page:e.listQuery.page,limit:e.listQuery.limit},on:{"update:page":function(t){return e.$set(e.listQuery,"page",t)},"update:limit":function(t){return e.$set(e.listQuery,"limit",t)},pagination:e.getList}}),e._v(" "),n("el-dialog",{attrs:{title:e.textMap[e.dialogStatus],visible:e.dialogFormVisible},on:{"update:visible":function(t){e.dialogFormVisible=t}}},[n("el-form",{ref:"dataForm",staticStyle:{width:"400px","margin-left":"50px"},attrs:{rules:e.rules,model:e.temp,"label-position":"left","label-width":"120px"}},[n("el-form-item",{attrs:{label:e.$t("table.userName"),prop:"user_name"}},["create"===e.dialogStatus?n("el-input",{model:{value:e.temp.user_name,callback:function(t){e.$set(e.temp,"user_name",t)},expression:"temp.user_name"}}):n("span",[e._v(e._s(e.temp.user_name))])],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.nickName"),prop:"nick_name"}},[n("el-input",{model:{value:e.temp.nick_name,callback:function(t){e.$set(e.temp,"nick_name",t)},expression:"temp.nick_name"}})],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.password"),prop:"password"}},[n("el-input",{attrs:{type:"password"},model:{value:e.temp.password,callback:function(t){e.$set(e.temp,"password",t)},expression:"temp.password"}})],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.passwordconfirm"),prop:"passwordconfirm"}},[n("el-input",{attrs:{type:"password"},model:{value:e.temp.passwordconfirm,callback:function(t){e.$set(e.temp,"passwordconfirm",t)},expression:"temp.passwordconfirm"}})],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.email"),prop:"email"}},[n("el-input",{model:{value:e.temp.email,callback:function(t){e.$set(e.temp,"email",t)},expression:"temp.email"}})],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.phone"),prop:"phone"}},[n("el-input",{model:{value:e.temp.phone,callback:function(t){e.$set(e.temp,"phone",t)},expression:"temp.phone"}})],1)],1),e._v(" "),n("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[n("el-button",{on:{click:function(t){e.dialogFormVisible=!1}}},[e._v("\n "+e._s(e.$t("table.cancel"))+"\n ")]),e._v(" "),n("el-button",{attrs:{type:"primary"},on:{click:function(t){"create"===e.dialogStatus?e.createData():e.updateData()}}},[e._v("\n "+e._s(e.$t("table.confirm"))+"\n ")])],1)],1),e._v(" "),n("el-dialog",{attrs:{visible:e.dialogRoleVisible,title:"权限修改"},on:{"update:visible":function(t){e.dialogRoleVisible=t}}},[n("el-checkbox",{attrs:{indeterminate:e.isIndeterminate},on:{change:e.handleCheckAllChange},model:{value:e.checkAll,callback:function(t){e.checkAll=t},expression:"checkAll"}},[e._v("全选")]),e._v(" "),n("div",{staticStyle:{margin:"15px 0"}}),e._v(" "),n("el-checkbox-group",{attrs:{min:1},on:{change:e.handleCheckedRolesChange},model:{value:e.checkedRoles,callback:function(t){e.checkedRoles=t},expression:"checkedRoles"}},e._l(e.allRoles,function(t){return n("el-checkbox",{key:t.role,attrs:{label:t.role}},[e._v(e._s(t.name))])}),1),e._v(" "),n("span",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[n("el-button",{on:{click:function(t){e.dialogRoleVisible=!1}}},[e._v("\n "+e._s(e.$t("table.cancel"))+"\n ")]),e._v(" "),n("el-button",{attrs:{type:"primary"},on:{click:function(t){return e.handleUpdateRoleRole()}}},[e._v("\n "+e._s(e.$t("table.confirm"))+"\n ")])],1)],1)],1)},i=[],l=(n("7f7f"),n("ac6a"),n("5176")),o=n.n(l),r=n("c24f"),s=n("cc5e"),c=n("61f7"),u=n("6724"),d=n("333d"),p={name:"ComplexTable",components:{Pagination:d["a"]},directives:{waves:u["a"]},filters:{statusFilter:function(e){var t={published:"success",draft:"info",deleted:"danger"};return t[e]}},data:function(){var e=this,t=function(t,n,a){""===n&&"create"===e.dialogStatus?a(new Error("请输入密码")):(""!==e.temp.passwordconfirm&&e.$refs.dataForm.validateField("passwordconfirm"),a())},n=function(t,n,a){""===n&&"create"===e.dialogStatus?a(new Error("请再次输入密码")):n!==e.temp.password?a(new Error("两次输入密码不一致!")):a()},a=function(e,t,n){Object(c["d"])(t)?n():n(new Error("Please enter the correct user name"))};return{list:null,total:0,listLoading:!0,listQuery:{page:1,limit:10,name:void 0,sort:"+id"},showReviewer:!1,temp:{user_name:"",nick_name:"",email:"",phone:"",password:"",passwordconfirm:""},dialogFormVisible:!1,dialogStatus:"",textMap:{update:"Edit",create:"Create"},rules:{user_name:[{required:!0,message:"username is required",trigger:"blur"}],nick_name:[{required:!0,message:"nickname is required",trigger:"blur"}],email:[{required:!0,trigger:"blur",validator:a}],phone:[{required:!0,message:"phone is required",trigger:"blur"}],password:[{validator:t,trigger:"blur"}],passwordconfirm:[{validator:n,trigger:"blur"}]},dialogRoleVisible:!1,checkAll:!1,checkedRoles:[],checkedAllRoles:[],allRoles:[],isIndeterminate:!1,currentUserName:""}},created:function(){this.getList()},methods:{getList:function(){var e=this;this.listLoading=!0,Object(r["d"])(this.listQuery).then(function(t){e.list=t.data.items,e.total=t.data.total,setTimeout(function(){e.listLoading=!1},500)})},handleFilter:function(){this.listQuery.page=1,this.getList()},handleModifyStatus:function(e,t){"deleted"===t&&this.handleDelete(e)},resetTemp:function(){this.temp={user_name:"",nick_name:"",email:"",phone:"",password:"",passwordconfirm:""}},handleCreate:function(){var e=this;this.resetTemp(),this.dialogStatus="create",this.dialogFormVisible=!0,this.$nextTick(function(){e.$refs["dataForm"].clearValidate()})},createData:function(){var e=this;this.$refs["dataForm"].validate(function(t){t&&(e.temp.author="vue-element-admin",Object(r["a"])(e.temp).then(function(){e.dialogFormVisible=!1,e.getList(),e.$notify({title:"成功",message:"创建成功",type:"success",duration:2e3})}))})},handleUpdate:function(e){var t=this;this.temp=o()({},e),this.dialogStatus="update",this.dialogFormVisible=!0,this.$nextTick(function(){t.$refs["dataForm"].clearValidate()})},updateData:function(){var e=this;this.$refs["dataForm"].validate(function(t){if(t){var n=o()({},e.temp);Object(r["j"])(n).then(function(){e.dialogFormVisible=!1,e.getList(),e.$notify({title:"成功",message:"更新成功",type:"success",duration:2e3})})}})},handleDelete:function(e){var t=this;this.$confirm("是否删除?","确认信息",{distinguishCancelAndClose:!0,confirmButtonText:"删除",cancelButtonText:"取消"}).then(function(){Object(r["b"])({id:e.id}).then(function(){t.getList(),t.$notify({title:"成功",message:"删除成功",type:"success",duration:2e3})})})},handleUpdateRole:function(e){var t=this;this.currentUserName=e.user_name,Object(s["c"])({limit:-1,username:e.user_name}).then(function(e){t.allRoles=[],t.checkedRoles=[],t.checkedAllRoles=[],e.data.items.forEach(function(e){t.checkedAllRoles.push(e.role),""!==e.name?t.allRoles.push(e):(e.name=e.role,t.allRoles.push(e))}),e.data.role_items.forEach(function(e){t.checkedRoles.push(e.role)}),t.checkedRoles.length>0?(t.checkAll=t.checkedRoles.length===t.allRoles.length,t.isIndeterminate=!t.checkAll):(t.isIndeterminate=!1,t.checkAll=!1),t.dialogRoleVisible=!0})},handleCheckAllChange:function(e){this.checkedRoles=e?this.checkedAllRoles:[],this.isIndeterminate=!1},handleCheckedRolesChange:function(e){var t=e.length;this.checkAll=t===this.allRoles.length,this.isIndeterminate=t>0&&t0,expression:"total>0"}],attrs:{total:e.total,page:e.listQuery.page,limit:e.listQuery.limit},on:{"update:page":function(t){return e.$set(e.listQuery,"page",t)},"update:limit":function(t){return e.$set(e.listQuery,"limit",t)},pagination:e.getList}}),e._v(" "),n("el-dialog",{attrs:{title:e.textMap[e.dialogStatus],visible:e.dialogFormVisible},on:{"update:visible":function(t){e.dialogFormVisible=t}}},[n("el-form",{ref:"dataForm",staticStyle:{width:"400px","margin-left":"50px"},attrs:{rules:e.rules,model:e.temp,"label-position":"left","label-width":"90px"}},[n("el-form-item",{attrs:{label:e.$t("table.role"),prop:"role"}},["create"===e.dialogStatus?n("el-input",{model:{value:e.temp.role,callback:function(t){e.$set(e.temp,"role",t)},expression:"temp.role"}}):n("span",[e._v(e._s(e.temp.role))])],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.roleName"),prop:"name"}},[n("el-input",{model:{value:e.temp.name,callback:function(t){e.$set(e.temp,"name",t)},expression:"temp.name"}})],1)],1),e._v(" "),n("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[n("el-button",{on:{click:function(t){e.dialogFormVisible=!1}}},[e._v("\n "+e._s(e.$t("table.cancel"))+"\n ")]),e._v(" "),n("el-button",{attrs:{type:"primary"},on:{click:function(t){"create"===e.dialogStatus?e.createData():e.updateData()}}},[e._v("\n "+e._s(e.$t("table.confirm"))+"\n ")])],1)],1),e._v(" "),n("el-dialog",{attrs:{visible:e.dialogPolicyVisible,title:"权限修改"},on:{"update:visible":function(t){e.dialogPolicyVisible=t}}},[n("el-checkbox",{attrs:{indeterminate:e.isIndeterminate},on:{change:e.handleCheckAllChange},model:{value:e.checkAll,callback:function(t){e.checkAll=t},expression:"checkAll"}},[e._v("全选")]),e._v(" "),n("div",{staticStyle:{margin:"15px 0"}}),e._v(" "),n("el-checkbox-group",{on:{change:e.handleCheckedPolicysChange},model:{value:e.checkedPolicys,callback:function(t){e.checkedPolicys=t},expression:"checkedPolicys"}},e._l(e.allPolicys,function(t){return n("el-checkbox",{key:t.policy,attrs:{label:t.policy}},[e._v(e._s(t.name))])}),1),e._v(" "),n("span",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[n("el-button",{on:{click:function(t){e.dialogPolicyVisible=!1}}},[e._v("\n "+e._s(e.$t("table.cancel"))+"\n ")]),e._v(" "),n("el-button",{attrs:{type:"primary"},on:{click:function(t){return e.handleUpdateRolePolicy()}}},[e._v("\n "+e._s(e.$t("table.confirm"))+"\n ")])],1)],1),e._v(" "),n("el-dialog",{attrs:{visible:e.dialogViewMenuVisible,title:"预览菜单"},on:{"update:visible":function(t){e.dialogViewMenuVisible=t}}},[n("el-form",{attrs:{"label-width":"80px","label-position":"left"}},[n("el-tree",{ref:"tree",staticClass:"permission-tree",attrs:{data:e.routesData,"check-strictly":e.checkStrictly,props:e.defaultProps,"show-checkbox":"","default-expand-all":!0,"node-key":"name"}})],1),e._v(" "),n("div",{staticStyle:{"text-align":"right"}},[n("el-button",{attrs:{type:"danger"},on:{click:function(t){e.dialogViewMenuVisible=!1}}},[e._v("\n "+e._s(e.$t("permission.cancel"))+"\n ")]),e._v(" "),n("el-button",{attrs:{type:"primary"},on:{click:e.confirmRoleMenus}},[e._v("\n "+e._s(e.$t("permission.confirm"))+"\n ")])],1)],1)],1)},a=[],l=n("cebc"),o=(n("96cf"),n("3b8d")),r=n("b6d0"),c=n.n(r),s=n("774e"),u=n.n(s),d=n("75fc"),h=(n("55dd"),n("5d73")),p=n.n(h),f=(n("7f7f"),n("ac6a"),n("5176")),m=n.n(f),g=n("1f27"),v=n("cc5e"),y=n("1b26"),b=n("6724"),k=n("333d"),w=n("df7c"),_=n.n(w),P=n("9923"),x={name:"ComplexTable",components:{Pagination:k["a"]},directives:{waves:b["a"]},filters:{statusFilter:function(e){var t={published:"success",draft:"info",deleted:"danger"};return t[e]}},data:function(){return{list:null,total:0,listLoading:!0,listQuery:{page:1,limit:10,name:void 0,sort:"+id"},showReviewer:!1,temp:{role:"",name:""},dialogFormVisible:!1,dialogStatus:"",textMap:{update:"Edit",create:"Create"},rules:{role:[{required:!0,message:"role is required",trigger:"blur"}],name:[{required:!0,message:"name is required",trigger:"blur"}]},dialogPolicyVisible:!1,checkAll:!1,checkedPolicys:[],checkedAllPolicys:[],allPolicys:[],isIndeterminate:!1,currentRole:"",routes:[],roleRoutes:[],dialogViewMenuVisible:!1,checkStrictly:!1,defaultProps:{children:"children",label:"title"}}},computed:{routesData:function(){return this.routes}},created:function(){this.getList()},methods:{i18n:function(e){var t=this,n=e.map(function(e){return e.title=P["a"].t("route.".concat(e.title)),e.children&&(e.children=t.i18n(e.children)),e});return n},getList:function(){var e=this;this.listLoading=!0,Object(v["c"])(this.listQuery).then(function(t){e.list=t.data.items,e.total=t.data.total,setTimeout(function(){e.listLoading=!1},500)})},handleFilter:function(){this.listQuery.page=1,this.getList()},handleModifyStatus:function(e,t){"deleted"===t&&this.handleDelete(e)},resetTemp:function(){this.temp={role:"",name:""}},handleCreate:function(){var e=this;this.resetTemp(),this.dialogStatus="create",this.dialogFormVisible=!0,this.$nextTick(function(){e.$refs["dataForm"].clearValidate()})},createData:function(){var e=this;this.$refs["dataForm"].validate(function(t){t&&(e.temp.author="vue-element-admin",Object(v["a"])(e.temp).then(function(){e.list.unshift(e.temp),e.dialogFormVisible=!1,e.$notify({title:"成功",message:"创建成功",type:"success",duration:2e3})}))})},handleUpdate:function(e){var t=this;this.temp=m()({},e),this.dialogStatus="update",this.dialogFormVisible=!0,this.$nextTick(function(){t.$refs["dataForm"].clearValidate()})},handleUpdatePolicy:function(e){var t=this;this.currentRole=e.role,Object(y["a"])({role:e.role}).then(function(e){t.allPolicys=[],t.checkedPolicys=[],t.checkedAllPolicys=[],e.data.all_policy_items.forEach(function(e){t.checkedAllPolicys.push(e.policy),""!==e.name?t.allPolicys.push(e):(e.name=e.policy,t.allPolicys.push(e))}),e.data.role_policy_items.forEach(function(e){t.checkedPolicys.push(e.policy)}),t.checkedPolicys.length>0?(t.checkAll=t.checkedPolicys.length===t.allPolicys.length,t.isIndeterminate=!t.checkAll):(t.isIndeterminate=!1,t.checkAll=!1),t.dialogPolicyVisible=!0})},updateData:function(){var e=this;this.$refs["dataForm"].validate(function(t){if(t){var n=m()({},e.temp);Object(v["f"])(n).then(function(){var t=!0,n=!1,i=void 0;try{for(var a,l=p()(e.list);!(t=(a=l.next()).done);t=!0){var o=a.value;if(o.id===e.temp.id){var r=e.list.indexOf(o);e.list.splice(r,1,e.temp);break}}}catch(c){n=!0,i=c}finally{try{t||null==l.return||l.return()}finally{if(n)throw i}}e.dialogFormVisible=!1,e.$notify({title:"成功",message:"更新成功",type:"success",duration:2e3})})}})},handleDelete:function(e){var t=this;this.$confirm("是否删除?","确认信息",{distinguishCancelAndClose:!0,confirmButtonText:"删除",cancelButtonText:"取消"}).then(function(){t.temp=m()({},e),Object(v["b"])(t.temp).then(function(){var n=t.list.indexOf(e);t.list.splice(n,1),t.$notify({title:"成功",message:"删除成功",type:"success",duration:2e3})})})},handleCheckAllChange:function(e){this.checkedPolicys=e?this.checkedAllPolicys:[],this.isIndeterminate=!1},handleCheckedPolicysChange:function(e){var t=e.length;this.checkAll=t===this.allPolicys.length,this.isIndeterminate=t>0&&t1&&void 0!==arguments[1]?arguments[1]:"/",n=[];e.sort(function(e,t){return e.sort-t.sort});var i=!0,a=!1,l=void 0;try{for(var o,r=p()(e);!(i=(o=r.next()).done);i=!0){var c=o.value;if(!c.hidden){var s=this.onlyOneShowingChild(c.children,c);c.children&&s&&!c.alwaysShow&&(c=s);var u={name:c.name,path:_.a.resolve(t,c.path),title:c.meta&&c.meta.title,parent_name:c.parent_name};c.children&&(c.children.sort(function(e,t){return e.sort-t.sort}),u.children=this.generateRoutes(c.children,u.path)),n.push(u)}}}catch(d){a=!0,l=d}finally{try{i||null==r.return||r.return()}finally{if(a)throw l}}return n},generateArr:function(e){var t=this,n=[];return e.forEach(function(e){if(n.push(e),e.children){var i=t.generateArr(e.children);i.length>0&&(n=[].concat(Object(d["a"])(n),Object(d["a"])(i)))}}),n},getRealKeys:function(e){var t=[];return e.forEach(function(e){t.push(e.name),""!==e.parent_name&&t.push(e.parent_name)}),u()(new c.a(t))},confirmRoleMenus:function(){var e=Object(o["a"])(regeneratorRuntime.mark(function e(){var t,n=this;return regeneratorRuntime.wrap(function(e){while(1)switch(e.prev=e.next){case 0:t=this.$refs.tree.getCheckedNodes(),Object(v["d"])({role:this.currentRole,menus:this.getRealKeys(t)}).then(function(){n.currentRole="",n.dialogViewMenuVisible=!1,n.$message({type:"success",message:"success!"})});case 2:case"end":return e.stop()}},e,this)}));function t(){return e.apply(this,arguments)}return t}(),onlyOneShowingChild:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1?arguments[1]:void 0,n=null;if(null==e)return!1;var i=e.filter(function(e){return!e.hidden});return 1===i.length?(n=i[0],n.path=_.a.resolve(t.path,n.path),n):0===i.length&&(n=Object(l["a"])({},t,{path:"",noShowingChildren:!0}),n)}}},$=x,S=n("2877"),C=Object(S["a"])($,i,a,!1,null,null,null);t["default"]=C.exports},cc5e:function(e,t,n){"use strict";n.d(t,"c",function(){return a}),n.d(t,"a",function(){return l}),n.d(t,"f",function(){return o}),n.d(t,"b",function(){return r}),n.d(t,"e",function(){return c}),n.d(t,"d",function(){return s});var i=n("b775");function a(e){return Object(i["a"])({url:"/role",method:"get",params:e})}function l(e){return Object(i["a"])({url:"/role",method:"post",data:e})}function o(e){return Object(i["a"])({url:"/role",method:"put",data:e})}function r(e){return Object(i["a"])({url:"/role",method:"delete",data:e})}function c(e){return Object(i["a"])({url:"/role/byuser",method:"put",data:e})}function s(e){return Object(i["a"])({url:"/role/menu",method:"put",data:e})}}}]); -------------------------------------------------------------------------------- /static/js/chunk-6a4eb3ee.9b859229.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-6a4eb3ee"],{"0795":function(e,t,n){},"1c64":function(e,t,n){},"1cc6":function(e,t,n){"use strict";var a=n("1c64"),i=n.n(a);i.a},"333d":function(e,t,n){"use strict";var a=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"pagination-container",class:{hidden:e.hidden}},[n("el-pagination",e._b({attrs:{background:e.background,"current-page":e.currentPage,"page-size":e.pageSize,layout:e.layout,"page-sizes":e.pageSizes,total:e.total},on:{"update:currentPage":function(t){e.currentPage=t},"update:current-page":function(t){e.currentPage=t},"update:pageSize":function(t){e.pageSize=t},"update:page-size":function(t){e.pageSize=t},"size-change":e.handleSizeChange,"current-change":e.handleCurrentChange}},"el-pagination",e.$attrs,!1))],1)},i=[];n("c5f6");Math.easeInOutQuad=function(e,t,n,a){return e/=a/2,e<1?n/2*e*e+t:(e--,-n/2*(e*(e-2)-1)+t)};var l=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(e){window.setTimeout(e,1e3/60)}}();function o(e){document.documentElement.scrollTop=e,document.body.parentNode.scrollTop=e,document.body.scrollTop=e}function r(){return document.documentElement.scrollTop||document.body.parentNode.scrollTop||document.body.scrollTop}function s(e,t,n){var a=r(),i=e-a,s=20,c=0;t="undefined"===typeof t?500:t;var u=function e(){c+=s;var r=Math.easeInOutQuad(c,a,i,t);o(r),c0,expression:"total>0"}],attrs:{total:e.total,page:e.listQuery.page,limit:e.listQuery.limit},on:{"update:page":function(t){return e.$set(e.listQuery,"page",t)},"update:limit":function(t){return e.$set(e.listQuery,"limit",t)},pagination:e.getList}}),e._v(" "),n("el-dialog",{attrs:{title:e.textMap[e.dialogStatus],visible:e.dialogFormVisible},on:{"update:visible":function(t){e.dialogFormVisible=t}}},[n("el-form",{ref:"dataForm",staticStyle:{width:"400px","margin-left":"50px"},attrs:{rules:e.rules,model:e.temp,"label-position":"left","label-width":"120px"}},[n("el-form-item",{attrs:{label:e.$t("table.name"),prop:"name"}},["create"===e.dialogStatus?n("el-input",{model:{value:e.temp.name,callback:function(t){e.$set(e.temp,"name",t)},expression:"temp.name"}}):n("span",[e._v(e._s(e.temp.name))])],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.title"),prop:"title"}},[n("el-input",{model:{value:e.temp.meta.title,callback:function(t){e.$set(e.temp.meta,"title",t)},expression:"temp.meta.title"}})],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.path"),prop:"path"}},[n("el-input",{model:{value:e.temp.path,callback:function(t){e.$set(e.temp,"path",t)},expression:"temp.path"}})],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.redirect"),prop:"redirect"}},[n("el-input",{model:{value:e.temp.redirect,callback:function(t){e.$set(e.temp,"redirect",t)},expression:"temp.redirect"}})],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.hidden"),prop:"hidden"}},[n("el-select",{staticClass:"filter-item",attrs:{placeholder:"Please select"},model:{value:e.temp.hidden,callback:function(t){e.$set(e.temp,"hidden",t)},expression:"temp.hidden"}},e._l(e.tofOptions,function(e){return n("el-option",{key:e.key,attrs:{label:e.label,value:e.value}})}),1)],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.alwaysShow"),prop:"alwaysShow"}},[n("el-select",{staticClass:"filter-item",attrs:{placeholder:"Please select"},model:{value:e.temp.alwaysShow,callback:function(t){e.$set(e.temp,"alwaysShow",t)},expression:"temp.alwaysShow"}},e._l(e.tofOptions,function(e){return n("el-option",{key:e.key,attrs:{label:e.label,value:e.value}})}),1)],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.parentName"),prop:"parentName"}},[n("el-select",{staticClass:"filter-item",attrs:{placeholder:"Please select"},model:{value:e.temp.parent_name,callback:function(t){e.$set(e.temp,"parent_name",t)},expression:"temp.parent_name"}},[n("el-option",{key:"null",attrs:{label:"Null",value:""}}),e._v(" "),e._l(e.menuNameList,function(e){return n("el-option",{key:e,attrs:{label:e,value:e}})})],2)],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.component"),prop:"component"}},[n("el-input",{model:{value:e.temp.component,callback:function(t){e.$set(e.temp,"component",t)},expression:"temp.component"}})],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.sort"),prop:"sort"}},[n("el-input",{model:{value:e.temp.sort,callback:function(t){e.$set(e.temp,"sort",t)},expression:"temp.sort"}})],1),e._v(" "),n("el-form-item",{attrs:{label:e.$t("table.icon"),prop:"icon"}},[n("el-select",{staticClass:"filter-item",attrs:{placeholder:"Please select"},model:{value:e.temp.meta.icon,callback:function(t){e.$set(e.temp.meta,"icon",t)},expression:"temp.meta.icon"}},[n("el-option",{key:"null",attrs:{label:"Null",value:""}}),e._v(" "),e._l(e.svgIcons,function(e){return n("el-option",{key:e,attrs:{label:e,value:e}})})],2)],1)],1),e._v(" "),n("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[n("el-button",{on:{click:function(t){e.dialogFormVisible=!1}}},[e._v("\n "+e._s(e.$t("table.cancel"))+"\n ")]),e._v(" "),n("el-button",{attrs:{type:"primary"},on:{click:function(t){"create"===e.dialogStatus?e.createData():e.updateData()}}},[e._v("\n "+e._s(e.$t("table.confirm"))+"\n ")])],1)],1),e._v(" "),n("el-dialog",{attrs:{visible:e.dialogViewMenuVisible,title:"预览菜单"},on:{"update:visible":function(t){e.dialogViewMenuVisible=t}}},[n("el-form",{attrs:{"label-width":"80px","label-position":"left"}},[n("el-tree",{ref:"tree",staticClass:"permission-tree",attrs:{data:e.routesData,props:e.defaultProps,"node-key":"path","default-expand-all":!0}})],1),e._v(" "),n("div",{staticStyle:{"text-align":"right"}},[n("el-button",{attrs:{type:"danger"},on:{click:function(t){e.dialogViewMenuVisible=!1}}},[e._v("\n "+e._s(e.$t("table.close"))+"\n ")])],1)],1)],1)},i=[],l=n("cebc"),o=n("75fc"),r=n("5d73"),s=n.n(r),c=(n("55dd"),n("7f7f"),n("ac6a"),n("5176")),u=n.n(c),d=(n("96cf"),n("3b8d")),p=n("1f27"),m=n("6724"),f=n("333d"),h=n("df7c"),v=n.n(h),b=n("9923"),g=(n("4917"),n("51ff")),y=function(e){return e.keys()},w=/\.\/(.*)\.svg/,_=y(g).map(function(e){return e.match(w)[1]}),k=_,$={name:"ComplexTable",components:{Pagination:f["a"]},directives:{waves:m["a"]},filters:{statusFilter:function(e){var t={published:"success",draft:"info",deleted:"danger"};return t[e]}},data:function(){return{list:null,total:0,listLoading:!0,listQuery:{page:1,limit:10,name:void 0,sort:"+id"},showReviewer:!1,temp:{name:"",path:"",component:"",redirect:"",parent_name:"",sort:0,hidden:!1,alwaysShow:!1,meta:{title:"",noCache:!1,icon:""}},dialogFormVisible:!1,dialogStatus:"",textMap:{update:"Edit",create:"Create"},rules:{},tofOptions:[{key:1,label:"是",value:!0},{key:0,label:"否",value:!1}],menuNameList:[],routes:[],dialogViewMenuVisible:!1,defaultProps:{children:"children",label:"title"},svgIcons:k}},computed:{routesData:function(){return this.routes}},created:function(){this.getList()},methods:{getRoutes:function(){var e=Object(d["a"])(regeneratorRuntime.mark(function e(){var t,n;return regeneratorRuntime.wrap(function(e){while(1)switch(e.prev=e.next){case 0:return e.next=2,Object(p["d"])();case 2:t=e.sent,this.serviceRoutes=t.data,n=this.generateRoutes(t.data),this.routes=this.i18n(n);case 6:case"end":return e.stop()}},e,this)}));function t(){return e.apply(this,arguments)}return t}(),i18n:function(e){var t=this,n=e.map(function(e){return e.title=b["a"].t("route.".concat(e.title)),e.children&&(e.children=t.i18n(e.children)),e});return n},getList:function(){var e=this;this.listLoading=!0,Object(p["c"])(this.listQuery).then(function(t){e.list=t.data.items,e.total=t.data.total,setTimeout(function(){e.listLoading=!1},500)})},handleFilter:function(){this.listQuery.page=1,this.getList()},handleModifyStatus:function(e,t){"deleted"===t&&this.handleDelete(e)},resetTemp:function(){this.temp={name:"",path:"",component:"",redirect:"",parent_name:"",sort:0,hidden:!1,alwaysShow:!1,meta:{title:"",noCache:!1,icon:""}}},handleCreate:function(){var e=this;this.resetTemp(),this.dialogStatus="create",this.dialogFormVisible=!0,this.$nextTick(function(){e.$refs["dataForm"].clearValidate()})},createData:function(){var e=this;this.$refs["dataForm"].validate(function(t){t&&(e.temp.author="vue-element-admin",Object(p["a"])(e.temp).then(function(){e.dialogFormVisible=!1,e.getList(),e.$notify({title:"成功",message:"创建成功",type:"success",duration:2e3})}))})},handleUpdate:function(e){var t=this;this.temp=u()({},e),this.menuNameList=[],this.list.forEach(function(n){n.name!==e.name&&t.menuNameList.push(n.name)}),this.dialogStatus="update",this.dialogFormVisible=!0,this.$nextTick(function(){t.$refs["dataForm"].clearValidate()})},updateData:function(){var e=this;this.$refs["dataForm"].validate(function(t){if(t){var n=u()({},e.temp);Object(p["e"])(n).then(function(){e.dialogFormVisible=!1,e.getList(),e.$notify({title:"成功",message:"更新成功",type:"success",duration:2e3})})}})},handleDelete:function(e){var t=this;this.$confirm("是否删除?","确认信息",{distinguishCancelAndClose:!0,confirmButtonText:"删除",cancelButtonText:"取消"}).then(function(){Object(p["b"])({name:e.name}).then(function(){t.getList(),t.$notify({title:"成功",message:"删除成功",type:"success",duration:2e3})})})},setIcon:function(e){return e},viewMenu:function(){var e=this;this.getRoutes(),this.dialogViewMenuVisible=!0,this.checkStrictly=!0,this.$nextTick(function(){var t=e.generateRoutes(e.routes);e.$refs.tree.setCheckedNodes(e.generateArr(t)),e.checkStrictly=!1})},generateRoutes:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"/",n=[];e.sort(function(e,t){return e.sort-t.sort});var a=!0,i=!1,l=void 0;try{for(var o,r=s()(e);!(a=(o=r.next()).done);a=!0){var c=o.value;if(!c.hidden){var u=this.onlyOneShowingChild(c.children,c);c.children&&u&&!c.alwaysShow&&(c=u);var d={path:v.a.resolve(t,c.path),title:c.meta&&c.meta.title};c.children&&(c.children.sort(function(e,t){return e.sort-t.sort}),d.children=this.generateRoutes(c.children,d.path)),n.push(d)}}}catch(p){i=!0,l=p}finally{try{a||null==r.return||r.return()}finally{if(i)throw l}}return n},generateArr:function(e){var t=this,n=[];return e.forEach(function(e){if(n.push(e),e.children){var a=t.generateArr(e.children);a.length>0&&(n=[].concat(Object(o["a"])(n),Object(o["a"])(a)))}}),n},onlyOneShowingChild:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1?arguments[1]:void 0,n=null;if(null==e)return!1;var a=e.filter(function(e){return!e.hidden});return 1===a.length?(n=a[0],n.path=v.a.resolve(t.path,n.path),n):0===a.length&&(n=Object(l["a"])({},t,{path:"",noShowingChildren:!0}),n)}}},S=$,x=(n("78d1"),n("2877")),C=Object(x["a"])(S,a,i,!1,null,"0c8289ae",null);t["default"]=C.exports},"8d41":function(e,t,n){}}]); -------------------------------------------------------------------------------- /docfile/swagger.yaml: -------------------------------------------------------------------------------- 1 | swagger: '2.0' 2 | info: 3 | version: 0.0.2 4 | title: gadmin 接口文档 5 | description: | 6 | 更新时间:2019年5月24日 16:23:58 7 | schemes: 8 | - http 9 | host: localhost:8199 10 | basePath: /v1 11 | 12 | #请求路径 13 | paths: 14 | ##登录相关 15 | /loginkey: 16 | get: 17 | summary: 获取登录密码加密密钥 18 | description: | 19 | 请求一个加密密钥,返回的内容包含密钥id(kid)、加密类型(cryptotype)、加密密钥(key)。 20 | ```js 21 | { 22 | "code": 20000, 23 | "data": { 24 | "kid": "BU06PZLJPUNK90L44T", 25 | "cryptotype": "RSA-PKCS1v1.5", 26 | "key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsAj30qPj3YT7n4bm2uyr\nglOugXyvv34k/kwHkrS/KlLNsvbbGbmAv8fMakuPxm64LKXjX/16+P5IQgNuqWjg\nqoqllB+9Ex3fftEa+YE9hxIlkfBVrhV3SFxJe1bR2QbdgN/tNmnrmwjxCpgeyrCM\nKE/ifAkImgNfC6KCavY7idklRMv/Xji53H1TUoarN2kHFfde5NGfd/Z+9GoB633U\nWi6zJ6vMhinlCaPVQlBHHwIRqMlzC3CWXR3Tx42o4GgPktkZjWK0+DqUUhF7amXC\n/diypzSBsVmCEn68U52byW9vSHiWlRA0N9/stHCZ5M3NcnnZF9JV6XcYjlgHj3ZD\nEwIDAQAB\n-----END PUBLIC KEY-----\n", 27 | "timestamp": 1557542458 28 | }, 29 | "message": "success" 30 | } 31 | tags: 32 | - Login 33 | parameters: 34 | responses: 35 | 200: 36 | $ref: '#/responses/LoginKey' 37 | /login: 38 | post: 39 | summary: 登录 40 | description: | 41 | 登录需要先 get 请求/loginkey 获取 RSA 的加密公钥(单次有效,并密钥有时效),将密码使用 RSA-PKCS1v1.5 方式加密并使用 base64 编码 42 | 43 | 使用 forge.js 进行加密数据 44 | 45 | https://raw.githubusercontent.com/loveiset/RSAForPostman/master/forge.js 46 | 47 | var publicKey = forge.pki.publicKeyFromPem(公钥); 48 | 49 | var encryptedText = forge.util.encode64(publicKey.encrypt(真实密码)); 50 | 51 | 最终提交的格式 52 | 53 | ``` 54 | Content-Type: application/json 55 | POST 56 | { 57 | "username":"admin", 58 | "password":encryptedText, 59 | "kid":"BTNK5IF7DYC8287814"//公钥的 id 60 | } 61 | ``` 62 | 63 | tags: 64 | - Login 65 | parameters: 66 | - name: body 67 | in: body 68 | description: 登录数据 69 | schema: 70 | required: 71 | - kid 72 | - password 73 | - username 74 | properties: 75 | kid: 76 | type: string 77 | password: 78 | type: string 79 | username: 80 | type: string 81 | responses: 82 | 200: 83 | $ref: '#/responses/Login' 84 | /refresh_token: 85 | get: 86 | summary: 刷新token 87 | description: t 88 | tags: 89 | - Login 90 | security: 91 | - Authorization: [] 92 | responses: 93 | 200: 94 | $ref: '#/responses/Login' 95 | /logout: 96 | get: 97 | summary: 退出登录 98 | description: t 99 | tags: 100 | - Login 101 | security: 102 | - Authorization: [] 103 | responses: 104 | 200: 105 | $ref: '#/responses/Success' 106 | ##用户相关 107 | /user/info: 108 | get: 109 | summary: 获取用户信息 110 | description: t 111 | tags: 112 | - User 113 | security: 114 | - Authorization: [] 115 | responses: 116 | 200: 117 | $ref: '#/responses/UserInfo' 118 | /user: 119 | get: 120 | summary: 获取用户列表 121 | description: 获取用户列表 122 | tags: 123 | - User 124 | security: 125 | - Authorization: [] 126 | parameters: 127 | - $ref: "#/parameters/page" 128 | - $ref: "#/parameters/limit" 129 | responses: 130 | 200: 131 | $ref: '#/responses/UserList' 132 | post: 133 | summary: 添加用户 134 | description: 添加用户 135 | tags: 136 | - User 137 | security: 138 | - Authorization: [] 139 | parameters: 140 | - name: body 141 | in: body 142 | schema: 143 | $ref: "#/parameters/UserPost" 144 | responses: 145 | 200: 146 | $ref: '#/responses/Success' 147 | put: 148 | summary: 修改用户 149 | description: 修改用户 150 | tags: 151 | - User 152 | security: 153 | - Authorization: [] 154 | parameters: 155 | - name: body 156 | in: body 157 | schema: 158 | $ref: "#/parameters/UserPut" 159 | responses: 160 | 200: 161 | $ref: '#/responses/Login' 162 | delete: 163 | summary: 删除用户 164 | description: 删除用户 165 | tags: 166 | - User 167 | security: 168 | - Authorization: [] 169 | parameters: 170 | - name: body 171 | in: body 172 | schema: 173 | required: 174 | - id 175 | properties: 176 | id: 177 | type: integer 178 | responses: 179 | 200: 180 | $ref: '#/responses/Success' 181 | ##角色相关 182 | /role: 183 | get: 184 | summary: 获取角色列表 185 | description: 获取角色列表 186 | tags: 187 | - Role 188 | security: 189 | - Authorization: [] 190 | parameters: 191 | - $ref: "#/parameters/page" 192 | - $ref: "#/parameters/limit" 193 | - name: username 194 | in: query 195 | description: 用户名(编辑用户角色的时候使用这个参数,不使用分页参数) 196 | type: string 197 | responses: 198 | 200: 199 | $ref: '#/responses/RoleList' 200 | post: 201 | summary: 添加角色 202 | description: 添加角色 203 | tags: 204 | - Role 205 | security: 206 | - Authorization: [] 207 | parameters: 208 | - name: body 209 | in: body 210 | schema: 211 | $ref: "#/definitions/Role" 212 | responses: 213 | 200: 214 | $ref: '#/responses/Success' 215 | put: 216 | summary: 修改角色 217 | description: 修改角色 218 | tags: 219 | - Role 220 | security: 221 | - Authorization: [] 222 | parameters: 223 | - name: body 224 | in: body 225 | schema: 226 | $ref: "#/definitions/Role" 227 | responses: 228 | 200: 229 | $ref: '#/responses/Login' 230 | delete: 231 | summary: 删除角色 232 | description: 删除角色 233 | tags: 234 | - Role 235 | security: 236 | - Authorization: [] 237 | parameters: 238 | - name: body 239 | in: body 240 | schema: 241 | $ref: "#/definitions/Role" 242 | responses: 243 | 200: 244 | $ref: '#/responses/Success' 245 | /role/byuser: 246 | put: 247 | summary: 获取角色权限 248 | description: 获取角色权限 249 | tags: 250 | - Role 251 | security: 252 | - Authorization: [] 253 | parameters: 254 | - name: body 255 | in: body 256 | schema: 257 | $ref: "#/parameters/UserRolePut" 258 | responses: 259 | 200: 260 | $ref: '#/responses/Success' 261 | /role/menu: 262 | put: 263 | summary: 修改角色菜单 264 | description: 修改角色菜单 265 | tags: 266 | - Role 267 | security: 268 | - Authorization: [] 269 | parameters: 270 | - name: body 271 | in: body 272 | schema: 273 | $ref: "#/parameters/RoleMenuPut" 274 | responses: 275 | 200: 276 | $ref: '#/responses/Success' 277 | ##权限相关 278 | /policy: 279 | get: 280 | summary: 获取用户列表 281 | description: 获取用户列表 282 | tags: 283 | - Policy 284 | security: 285 | - Authorization: [] 286 | parameters: 287 | - $ref: "#/parameters/page" 288 | - $ref: "#/parameters/limit" 289 | responses: 290 | 200: 291 | $ref: '#/responses/PolicyList' 292 | put: 293 | summary: 修改用户 294 | description: 修改用户 295 | tags: 296 | - Policy 297 | security: 298 | - Authorization: [] 299 | parameters: 300 | - name: body 301 | in: body 302 | schema: 303 | $ref: "#/definitions/Policy" 304 | responses: 305 | 200: 306 | $ref: '#/responses/Success' 307 | /policy/byrole: 308 | get: 309 | summary: 获取角色权限 310 | description: 获取角色权限 311 | tags: 312 | - Policy 313 | security: 314 | - Authorization: [] 315 | parameters: 316 | - name: role 317 | in: query 318 | description: 角色名 319 | type: string 320 | responses: 321 | 200: 322 | $ref: '#/responses/RolePolicyList' 323 | put: 324 | summary: 设置角色权限 325 | description: 设置角色权限 326 | tags: 327 | - Policy 328 | security: 329 | - Authorization: [] 330 | parameters: 331 | - name: body 332 | in: body 333 | schema: 334 | $ref: "#/parameters/RolePolicyPut" 335 | responses: 336 | 200: 337 | $ref: '#/responses/Success' 338 | ##菜单相关 339 | /menu: 340 | get: 341 | summary: 获取菜单列表 342 | description: 获取菜单列表 343 | tags: 344 | - Menu 345 | security: 346 | - Authorization: [] 347 | parameters: 348 | - $ref: "#/parameters/page" 349 | - $ref: "#/parameters/limit" 350 | responses: 351 | 200: 352 | $ref: '#/responses/MenuList' 353 | post: 354 | summary: 添加菜单 355 | description: 添加菜单 356 | tags: 357 | - Menu 358 | security: 359 | - Authorization: [] 360 | parameters: 361 | - name: body 362 | in: body 363 | schema: 364 | $ref: "#/parameters/MenuPost" 365 | responses: 366 | 200: 367 | $ref: '#/responses/Success' 368 | put: 369 | summary: 修改菜单 370 | description: 修改菜单 371 | tags: 372 | - Menu 373 | security: 374 | - Authorization: [] 375 | parameters: 376 | - name: body 377 | in: body 378 | schema: 379 | $ref: "#/parameters/MenuPut" 380 | responses: 381 | 200: 382 | $ref: '#/responses/Login' 383 | delete: 384 | summary: 删除菜单 385 | description: 删除菜单 386 | tags: 387 | - Menu 388 | security: 389 | - Authorization: [] 390 | parameters: 391 | - name: body 392 | in: body 393 | schema: 394 | required: 395 | - id 396 | properties: 397 | id: 398 | type: integer 399 | responses: 400 | 200: 401 | $ref: '#/responses/Success' 402 | 403 | #自定义结构 404 | definitions: 405 | #基础返回 406 | Result: 407 | properties: 408 | code: 409 | type: integer 410 | format: int 411 | default: 2000 412 | message: 413 | type: string 414 | data: 415 | type: object 416 | Success: 417 | allOf: 418 | - $ref: '#/definitions/Result' 419 | - type: object 420 | Error: 421 | allOf: 422 | - $ref: '#/definitions/Result' 423 | - type: object 424 | ##User 425 | UserBase: 426 | properties: 427 | nick_name: 428 | type: string 429 | email: 430 | type: string 431 | phone: 432 | type: string 433 | User: 434 | allOf: 435 | - $ref: '#/definitions/UserBase' 436 | - type: object 437 | properties: 438 | id: 439 | type: integer 440 | readOnly: true 441 | user_name: 442 | type: string 443 | Introduction: 444 | type: string 445 | status: 446 | type: integer 447 | age: 448 | type: integer 449 | add_user_id: 450 | type: integer 451 | readOnly: true 452 | add_time: 453 | type: string 454 | format: date-time 455 | readOnly: true 456 | update_time: 457 | type: string 458 | format: date-time 459 | readOnly: true 460 | Users: 461 | type: array 462 | items: 463 | $ref: "#/definitions/User" 464 | ##Role 465 | Role: 466 | properties: 467 | name: 468 | type: string 469 | role: 470 | type: string 471 | Roles: 472 | type: array 473 | items: 474 | $ref: "#/definitions/Role" 475 | ##Policy 476 | Policy: 477 | properties: 478 | name: 479 | type: string 480 | policy: 481 | type: string 482 | Policys: 483 | type: array 484 | items: 485 | $ref: "#/definitions/Policy" 486 | ##Menu 487 | Meta: 488 | properties: 489 | noCache: 490 | type: boolean 491 | icon: 492 | type: string 493 | title: 494 | type: string 495 | Menu: 496 | properties: 497 | alwaysShow: 498 | type: boolean 499 | component: 500 | type: string 501 | hidden: 502 | type: boolean 503 | name: 504 | type: string 505 | parent_name: 506 | type: string 507 | path: 508 | type: string 509 | redirect: 510 | type: string 511 | sort: 512 | type: integer 513 | meta: 514 | $ref: "#/definitions/Meta" 515 | children: 516 | $ref: "#/definitions/Menus" 517 | Menus: 518 | type: array 519 | items: 520 | $ref: "#/definitions/Menu" 521 | 522 | #请求参数 523 | parameters: 524 | page: 525 | name: page 526 | in: query 527 | description: Page number 528 | type: integer 529 | limit: 530 | name: limit 531 | in: query 532 | description: limit 533 | type: integer 534 | UserPost: 535 | allOf: 536 | - $ref: '#/parameters/UserPut' 537 | - type: object 538 | properties: 539 | user_name: 540 | type: string 541 | UserPut: 542 | allOf: 543 | - $ref: '#/definitions/UserBase' 544 | - type: object 545 | properties: 546 | password: 547 | description: 添加时必填,修改时选填。 548 | type: string 549 | format: password 550 | passwordconfirm: 551 | description: 添加时必填,修改时选填。 552 | type: string 553 | format: password 554 | UserRolePut: 555 | properties: 556 | roles: 557 | type: array 558 | items: 559 | type: string 560 | username: 561 | type: string 562 | RolePolicyPut: 563 | properties: 564 | policys: 565 | type: array 566 | items: 567 | type: string 568 | role: 569 | type: string 570 | RoleMenuPut: 571 | properties: 572 | menus: 573 | type: array 574 | items: 575 | type: string 576 | role: 577 | type: string 578 | MenuPost: 579 | allOf: 580 | - $ref: '#/definitions/Menu' 581 | - type: object 582 | MenuPut: 583 | allOf: 584 | - $ref: '#/definitions/Menu' 585 | - type: object 586 | 587 | #响应 588 | responses: 589 | Success: 590 | description: Seccess 591 | schema: 592 | $ref: '#/definitions/Success' 593 | Error500: 594 | description: An unexpected error occured. 595 | schema: 596 | $ref: '#/definitions/Error' 597 | ##Login 598 | LoginKey: 599 | allOf: 600 | - $ref: '#/definitions/Result' 601 | - type: object 602 | properties: 603 | data: 604 | type: object 605 | properties: 606 | cryptotype: 607 | type: string 608 | key: 609 | type: string 610 | kid: 611 | type: string 612 | timestamp: 613 | type: string 614 | Login: 615 | allOf: 616 | - $ref: '#/definitions/Result' 617 | - type: object 618 | properties: 619 | data: 620 | type: object 621 | properties: 622 | expire: 623 | type: string 624 | token: 625 | type: string 626 | ##User 627 | UserInfo: 628 | allOf: 629 | - $ref: '#/definitions/Result' 630 | - type: object 631 | properties: 632 | data: 633 | type: object 634 | properties: 635 | avatar: 636 | type: string 637 | introduction: 638 | type: string 639 | name: 640 | type: string 641 | roles: 642 | type: array 643 | items: 644 | type: string 645 | UserList: 646 | allOf: 647 | - $ref: '#/definitions/Result' 648 | - type: object 649 | properties: 650 | data: 651 | type: object 652 | properties: 653 | total: 654 | type: integer 655 | items: 656 | $ref: "#/definitions/Users" 657 | ##Role 658 | RoleList: 659 | allOf: 660 | - $ref: '#/definitions/Result' 661 | - type: object 662 | properties: 663 | data: 664 | type: object 665 | properties: 666 | total: 667 | type: integer 668 | items: 669 | $ref: "#/definitions/Roles" 670 | role_items: 671 | $ref: "#/definitions/Roles" 672 | RolePolicyList: 673 | allOf: 674 | - $ref: '#/definitions/Result' 675 | - type: object 676 | properties: 677 | data: 678 | type: object 679 | properties: 680 | total: 681 | type: integer 682 | all_policy_items: 683 | $ref: "#/definitions/Policys" 684 | role_policy_items: 685 | $ref: "#/definitions/Policys" 686 | ##Policy 687 | PolicyList: 688 | allOf: 689 | - $ref: '#/definitions/Result' 690 | - type: object 691 | properties: 692 | data: 693 | type: object 694 | properties: 695 | total: 696 | type: integer 697 | items: 698 | $ref: "#/definitions/Policys" 699 | ##Menu 700 | MenuList: 701 | allOf: 702 | - $ref: '#/definitions/Result' 703 | - type: object 704 | properties: 705 | data: 706 | type: object 707 | properties: 708 | total: 709 | type: integer 710 | items: 711 | $ref: "#/definitions/Menus" 712 | 713 | #标签 714 | tags: 715 | - name: Login 716 | description: 登录相关 717 | - name: User 718 | description: 用户相关 719 | - name: Role 720 | description: 角色相关 721 | - name: Policy 722 | description: 权限相关 723 | - name: Menu 724 | description: 菜单相关 725 | 726 | #API鉴权 727 | securityDefinitions: 728 | Authorization: 729 | name: Authorization 730 | type: apiKey 731 | in: header 732 | --------------------------------------------------------------------------------