├── perm-vue ├── build │ ├── logo.png │ ├── vue-loader.conf.js │ ├── build.js │ ├── check-versions.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ ├── utils.js │ └── webpack.prod.conf.js ├── config │ ├── prod.env.js │ ├── dev.env.js │ └── index.js ├── static │ ├── img │ │ └── img.jpg │ ├── css │ │ ├── icon.css │ │ ├── theme-green │ │ │ ├── fonts │ │ │ │ ├── element-icons.ttf │ │ │ │ └── element-icons.woff │ │ │ └── color-green.css │ │ ├── color-dark.css │ │ └── main.css │ └── vuetable.json ├── src │ ├── assets │ │ ├── logo.png │ │ ├── login-bg.jpg │ │ ├── login-bg1.jpg │ │ ├── reset.css │ │ └── util.js │ ├── components │ │ ├── common │ │ │ ├── bus.js │ │ │ ├── Home.vue │ │ │ ├── Sidebar.vue │ │ │ └── Tags.vue │ │ └── page │ │ │ ├── demo │ │ │ ├── Permission.vue │ │ │ ├── VueEditor.vue │ │ │ ├── Markdown.vue │ │ │ ├── BaseCharts.vue │ │ │ ├── Upload.vue │ │ │ ├── Tabs.vue │ │ │ ├── DragList.vue │ │ │ └── BaseForm.vue │ │ │ ├── error-page │ │ │ ├── 403.vue │ │ │ └── 404.vue │ │ │ ├── sys-user │ │ │ └── department │ │ │ │ ├── tree.utils.js │ │ │ │ └── tree.scss │ │ │ └── Login.vue │ ├── App.vue │ ├── utils │ │ ├── utils.js │ │ └── rest.js │ ├── router │ │ ├── index.js │ │ └── sys-user-router.js │ └── main.js ├── .babelrc ├── .postcssrc.js ├── index.html └── package.json ├── perm-server ├── sys-common │ ├── supports │ │ ├── commonConst │ │ │ └── common_const.go │ │ ├── simple_result.go │ │ ├── response_message.go │ │ ├── responseHandle │ │ │ └── response_handle.go │ │ └── simple_response.go │ ├── conf │ │ ├── config.toml │ │ ├── rbac_model.conf │ │ ├── app.yml │ │ ├── config.go │ │ └── db.yml │ ├── utils │ │ ├── uuid.go │ │ ├── util.go │ │ ├── jsonUtil.go │ │ ├── sysconf.go │ │ ├── encrypt.go │ │ └── aes.go │ ├── vo │ │ ├── common │ │ │ └── table_vo.go │ │ ├── casbin_define.go │ │ ├── baseVo │ │ │ └── base_vo.go │ │ ├── page_vo.go │ │ └── Pagination.go │ ├── inits │ │ ├── sys │ │ │ ├── role.go │ │ │ └── user.go │ │ ├── init.go │ │ └── parse │ │ │ ├── app.go │ │ │ └── db.go │ ├── middleware │ │ ├── casbins │ │ │ ├── parse.go │ │ │ └── casbins.go │ │ ├── middleware.go │ │ └── jwts │ │ │ └── config.go │ ├── db │ │ └── db.go │ ├── models │ │ └── baseModel │ │ │ └── baseModel.go │ └── caches │ │ └── redis.go ├── main │ └── main.go ├── doc │ └── go-bindata-usage └── sys-sysbase │ ├── models │ └── user │ │ ├── role_resource.go │ │ ├── user_role.go │ │ ├── role.go │ │ ├── department.go │ │ ├── user.go │ │ └── resource.go │ ├── vo │ └── uservo │ │ ├── role_resource_vo.go │ │ ├── user_role_vo.go │ │ ├── role_vo.go │ │ ├── department_vo.go │ │ └── resource_vo.go │ ├── routes │ ├── hub.go │ └── user │ │ ├── department_route.go │ │ └── resource_route.go │ └── service │ └── userService │ ├── role_service.go │ └── resource_service.go ├── .gitignore ├── .vscode └── launch.json ├── go.mod └── README.md /perm-vue/build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alomnt/permissionManage/HEAD/perm-vue/build/logo.png -------------------------------------------------------------------------------- /perm-vue/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | }; 5 | -------------------------------------------------------------------------------- /perm-vue/static/img/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alomnt/permissionManage/HEAD/perm-vue/static/img/img.jpg -------------------------------------------------------------------------------- /perm-vue/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alomnt/permissionManage/HEAD/perm-vue/src/assets/logo.png -------------------------------------------------------------------------------- /perm-vue/src/assets/login-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alomnt/permissionManage/HEAD/perm-vue/src/assets/login-bg.jpg -------------------------------------------------------------------------------- /perm-vue/src/assets/login-bg1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alomnt/permissionManage/HEAD/perm-vue/src/assets/login-bg1.jpg -------------------------------------------------------------------------------- /perm-server/sys-common/supports/commonConst/common_const.go: -------------------------------------------------------------------------------- 1 | package commonConst 2 | 3 | const ( 4 | CURRENT_USER_KEY = "_user_id" 5 | ) 6 | -------------------------------------------------------------------------------- /perm-vue/src/components/common/bus.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | // 使用 Event Bus 4 | const bus = new Vue(); 5 | 6 | export default bus; -------------------------------------------------------------------------------- /perm-vue/static/css/icon.css: -------------------------------------------------------------------------------- 1 | 2 | [class*=" el-icon-lx"], [class^=el-icon-lx] { 3 | font-family: lx-iconfont!important; 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.idea 3 | *.iml 4 | */node_modules 5 | */package-lock.json 6 | *rebel.xml* 7 | .idea/vcs.xml 8 | perm-server/pkg/mod/cache/ 9 | -------------------------------------------------------------------------------- /perm-vue/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { "modules": false }], 4 | "stage-3" 5 | ], 6 | "plugins": ["transform-vue-jsx"] 7 | } 8 | -------------------------------------------------------------------------------- /perm-server/sys-common/supports/simple_result.go: -------------------------------------------------------------------------------- 1 | package supports 2 | 3 | type SimResult struct { 4 | Code bool 5 | Msg string 6 | Data interface{} 7 | } 8 | -------------------------------------------------------------------------------- /perm-vue/static/css/theme-green/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alomnt/permissionManage/HEAD/perm-vue/static/css/theme-green/fonts/element-icons.ttf -------------------------------------------------------------------------------- /perm-vue/static/css/theme-green/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alomnt/permissionManage/HEAD/perm-vue/static/css/theme-green/fonts/element-icons.woff -------------------------------------------------------------------------------- /perm-server/sys-common/conf/config.toml: -------------------------------------------------------------------------------- 1 | #reids 2 | [redis] 3 | Addr = "123.57.66.84:6379" 4 | Password = "123456" 5 | RedisMaxIdle = 10 6 | RedisIdleTimeoutSec = 43200 7 | DB = 1 8 | -------------------------------------------------------------------------------- /perm-vue/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const merge = require('webpack-merge'); 3 | const prodEnv = require('./prod.env'); 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }); 8 | -------------------------------------------------------------------------------- /perm-vue/src/assets/reset.css: -------------------------------------------------------------------------------- 1 | .el-row { 2 | margin-bottom: 20px; 3 | } 4 | .demo-input-suffix { 5 | display: inline-block; 6 | width: 35%; 7 | text-align: right; 8 | } 9 | .table { 10 | width: 100%!important; 11 | font-size: 14px!important; 12 | } -------------------------------------------------------------------------------- /perm-server/sys-common/utils/uuid.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/gofrs/uuid" 5 | "strings" 6 | ) 7 | 8 | func GetUuid() string { 9 | var uuid = uuid.Must(uuid.NewV4()).String() 10 | uuid = strings.Replace(uuid, "-", "", -1) 11 | return uuid 12 | } 13 | -------------------------------------------------------------------------------- /perm-vue/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "postcss-import": {}, 7 | "autoprefixer": {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /perm-vue/src/assets/util.js: -------------------------------------------------------------------------------- 1 | export default { 2 | GetSessionStorage: function (index, data) { 3 | if (data == '没有登录') { 4 | index.$router.push({path: '/login'}); 5 | } else { 6 | index.$message.error(data); 7 | } 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /perm-server/sys-common/vo/common/table_vo.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | type TableVO struct { 4 | Total int64 `json:"total"` 5 | Rows interface{} `json:"rows"` 6 | } 7 | 8 | func NewTableVO(total int64, rows interface{}) *TableVO { 9 | return &TableVO{ 10 | Total: total, 11 | Rows: rows, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /perm-vue/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /perm-server/sys-common/conf/rbac_model.conf: -------------------------------------------------------------------------------- 1 | [request_definition] 2 | r = sub, obj, act, suf 3 | 4 | [policy_definition] 5 | p = sub, obj, act, suf 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.obj, p.obj) && regexMatch(r.suf, p.suf) && regexMatch(r.act, p.act) || r.sub == "1" -------------------------------------------------------------------------------- /perm-server/sys-common/supports/response_message.go: -------------------------------------------------------------------------------- 1 | package supports 2 | 3 | const ( 4 | PARAM_IS_EMPTY string = "入参为空" 5 | 6 | QUERY_FAIL string = "查询异常" 7 | 8 | ADD_FAIL string = "添加失败" 9 | ADD_SUCCESS string = "添加成功" 10 | 11 | UPDATE_FAIL string = "更新失败" 12 | UPDATE_SUCCESS string = "更新成功" 13 | 14 | DELETE_FAIL string = "删除失败" 15 | DELETE_SUCCESS string = "删除成功" 16 | ) 17 | -------------------------------------------------------------------------------- /perm-vue/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 基础demo 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /perm-server/main/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "permissionManage/perm-server/sys-common/inits" 5 | conf "permissionManage/perm-server/sys-common/inits/parse" 6 | "permissionManage/perm-server/sys-sysbase/routes" 7 | 8 | "github.com/kataras/iris/v12" 9 | ) 10 | 11 | func main() { 12 | app := iris.New() 13 | routes.Hub(app) 14 | app.Run(iris.Addr(":"+conf.O.Port), iris.WithConfiguration(conf.C)) 15 | } 16 | -------------------------------------------------------------------------------- /perm-server/sys-common/conf/app.yml: -------------------------------------------------------------------------------- 1 | DisablePathCorrection: false 2 | EnablePathEscape: false 3 | FireMethodNotAllowed: false 4 | DisableBodyConsumptionOnUnmarshal: false 5 | TimeFormat: Mon, 01 Jan 2006 15:04:05 GMT 6 | Charset: UTF-8 7 | #自定义配置 8 | Other: 9 | Port: 8098 10 | IgnoreURLs: [/, /perm/user/login, /perm/user/registe, /perm/login_pwd] 11 | JWTTimeout: 900 #second 12 | LogLevel: debug 13 | Secret: xxx-Secret 14 | 15 | 16 | -------------------------------------------------------------------------------- /perm-server/sys-common/conf/config.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "fmt" 5 | "github.com/pelletier/go-toml" 6 | ) 7 | 8 | var ( 9 | Conf = New() 10 | ) 11 | 12 | /** 13 | * 返回单例实例 14 | * @method New 15 | */ 16 | func New() *toml.Tree { 17 | config, err := toml.LoadFile("./perm-server/sys-common/conf/config.toml") 18 | 19 | if err != nil { 20 | fmt.Println("TomlError ", err.Error()) 21 | } 22 | 23 | return config 24 | } 25 | -------------------------------------------------------------------------------- /perm-server/sys-common/vo/casbin_define.go: -------------------------------------------------------------------------------- 1 | package vo 2 | 3 | // 前端请求的结构体 4 | type ( 5 | RoleDefine struct { 6 | // 角色的标识等于casbin的sub,但角色需要加role_前缀 7 | Sub string `json:"sub"` 8 | // 对应casbin model的定义 9 | Obj string `json:"obj"` 10 | Act string `json:"act"` 11 | Suf string `json:"suf"` 12 | RoleName string `json:"roleName"` 13 | } 14 | 15 | // 用户所属角色组 16 | GroupDefine struct { 17 | Uid int64 `json:"uid"` 18 | Sub []string `json:"sub"` 19 | } 20 | ) 21 | -------------------------------------------------------------------------------- /perm-server/sys-common/supports/responseHandle/response_handle.go: -------------------------------------------------------------------------------- 1 | package responseHandle 2 | 3 | import ( 4 | "github.com/kataras/iris/v12" 5 | "permissionManage/perm-server/sys-common/supports" 6 | ) 7 | 8 | func Response(ctx iris.Context, res *supports.SimResult) { 9 | if res == nil { 10 | supports.Ok(ctx, "", "") 11 | return 12 | } 13 | 14 | if !res.Code { 15 | supports.Error(ctx, iris.StatusInternalServerError, res.Msg, nil) 16 | return 17 | } 18 | 19 | supports.Ok(ctx, res.Msg, res.Data) 20 | } 21 | -------------------------------------------------------------------------------- /perm-vue/static/css/color-dark.css: -------------------------------------------------------------------------------- 1 | .header{ 2 | background-color: #242f42; 3 | } 4 | .login-wrap{ 5 | background: #324157; 6 | } 7 | .plugins-tips{ 8 | background: #eef1f6; 9 | } 10 | .plugins-tips a{ 11 | color: #20a0ff; 12 | } 13 | .el-upload--text em { 14 | color: #20a0ff; 15 | } 16 | .pure-button{ 17 | background: #20a0ff; 18 | } 19 | .tags-li.active { 20 | border: 1px solid #409EFF; 21 | background-color: #409EFF; 22 | } 23 | .message-title{ 24 | color: #20a0ff; 25 | } 26 | .collapse-btn:hover{ 27 | background: rgb(40,52,70); 28 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | { 9 | "name": "Launch", 10 | "type": "go", 11 | "request": "launch", 12 | "mode": "auto", 13 | "program": "${fileDirname}", 14 | "env": {}, 15 | "args": [] 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /perm-server/sys-common/conf/db.yml: -------------------------------------------------------------------------------- 1 | 2 | master: 3 | dialect: mysql 4 | user: root 5 | password: 123456 6 | host: 123.57.66.84 7 | port: 3306 8 | database: cd_dev 9 | charset: utf8 10 | showSql: true 11 | logLevel: debug 12 | maxIdleConns: 10 # 连接池的空闲数大小 13 | # maxOpenConns: 10 # 最大打开连接数 14 | slave: 15 | dialect: mysql 16 | user: root 17 | password: 123456 18 | host: 127.0.0.1 19 | port: 3306 20 | database: cd_dev 21 | charset: utf8 22 | showSql: true 23 | logLevel: debug 24 | maxIdleConns: 10 # 连接池的空闲数大小 25 | # maxOpenConns: 10 # 最大打开连接数 26 | -------------------------------------------------------------------------------- /perm-server/sys-common/utils/util.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | const ( 10 | rolePrefix string = "role_" 11 | ) 12 | 13 | // 14 | func FmtRolePrefix(sub interface{}) string { 15 | var s string 16 | switch sub.(type) { 17 | case int64: 18 | uid := sub.(int64) 19 | s = strconv.FormatInt(uid, 10) 20 | case string: 21 | s = sub.(string) 22 | } 23 | return fmt.Sprintf("%s%s", rolePrefix, s) 24 | } 25 | 26 | // timestamp to time 27 | func StampToTime(st int64) time.Time { 28 | return time.Unix(st/1000, 0) 29 | } 30 | -------------------------------------------------------------------------------- /perm-server/sys-common/utils/jsonUtil.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/kataras/golog" 6 | ) 7 | 8 | // 9 | func StructToString(stru interface{}) string { 10 | 11 | jsons, err := json.Marshal(stru) //转换成JSON返回的是byte[] 12 | if err != nil { 13 | err.Error() 14 | golog.Error(err) 15 | return "" 16 | } 17 | return string(jsons) 18 | } 19 | 20 | func ByteToStruct(byt []byte, stru interface{}) interface{} { 21 | err := json.Unmarshal(byt, &stru) 22 | if err != nil { 23 | err.Error() 24 | golog.Error(err) 25 | return stru 26 | } 27 | return stru 28 | } 29 | -------------------------------------------------------------------------------- /perm-server/sys-common/utils/sysconf.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | /* 8 | 前面是含义,后面是 go 的表示值,多种表示,逗号","分割 9 | 年  06,2006 10 | 月份 1,01,Jan,January 11 | 日  2,02,_2 12 | 时  3,03,15,PM,pm,AM,am 13 | 分  4,04 14 | 秒  5,05 15 | 周几 Mon,Monday 16 | 时区时差表示 -07,-0700,Z0700,Z07:00,-07:00,MST 17 | 时区字母缩写 MST 18 | 您看出规律了么!哦是的,你发现了,这里面没有一个是重复的,所有的值表示都唯一对应一个时间部分。 19 | 并且涵盖了很多格式组合。 20 | */ 21 | const ( 22 | // 时间格式化字符串 23 | SysTimeform string = "2006-01-02 15:04:05" 24 | SysTimeformShort string = "2006-01-02" 25 | // 26 | 27 | ) 28 | 29 | // 中国时区 30 | var SysTimeLocation, _ = time.LoadLocation("Asia/Chongqing") 31 | -------------------------------------------------------------------------------- /perm-vue/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | module.exports = { 10 | loaders: utils.cssLoaders({ 11 | sourceMap: sourceMapEnabled, 12 | extract: isProduction 13 | }), 14 | cssSourceMap: sourceMapEnabled, 15 | cacheBusting: config.dev.cacheBusting, 16 | transformToRequire: { 17 | video: ['src', 'poster'], 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /perm-server/sys-common/inits/sys/role.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/middleware/casbins" 5 | 6 | "github.com/kataras/golog" 7 | ) 8 | 9 | var ( 10 | // 定义系统初始的角色 11 | Components = [][]string{ 12 | {"0", "角色管理", "role_admin*", "角色管理"}, 13 | {"0", "demo角色", "role_demo*", "demo角色"}, 14 | } 15 | ) 16 | 17 | // 创建系统默认角色 18 | func CreateSystemRole() bool { 19 | e := casbins.GetEnforcer() 20 | 21 | for _, v := range Components { 22 | p := e.GetFilteredPolicy(0, v[0]) 23 | if len(p) == 0 { 24 | if ok := e.AddPolicy(v); !ok { 25 | golog.Fatalf("初始化角色[%s]权限失败。%s", v) 26 | } 27 | } 28 | } 29 | return true 30 | } 31 | -------------------------------------------------------------------------------- /perm-vue/src/utils/utils.js: -------------------------------------------------------------------------------- 1 | export const getToken = () => { 2 | let token = ''; 3 | let user = JSON.parse(window.sessionStorage.getItem('user')); 4 | if (user) { 5 | token = user.token 6 | } 7 | return token 8 | }; 9 | 10 | export const fmtToken = () => { 11 | let fmttoken = 'bearer '; 12 | let user = window.sessionStorage.getItem('user'); 13 | if (user) { 14 | fmttoken += getToken() 15 | } 16 | return fmttoken 17 | }; 18 | 19 | export const getUserId = () => { 20 | let userId = ''; 21 | let user = JSON.parse(window.sessionStorage.getItem('user')); 22 | if (user) { 23 | userId = user.id 24 | } 25 | return userId 26 | }; -------------------------------------------------------------------------------- /perm-vue/static/css/theme-green/color-green.css: -------------------------------------------------------------------------------- 1 | .header{ 2 | background-color: #07c4a8; 3 | } 4 | .login-wrap{ 5 | background: rgba(56, 157, 170, 0.82);; 6 | } 7 | .plugins-tips{ 8 | background: #f2f2f2; 9 | } 10 | .plugins-tips a{ 11 | color: #00d1b2; 12 | } 13 | .el-upload--text em { 14 | color: #00d1b2; 15 | } 16 | .pure-button{ 17 | background: #00d1b2; 18 | } 19 | .pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus, .pagination > .active > span, .pagination > .active > span:hover, .pagination > .active > span:focus { 20 | background-color: #00d1b2 !important; 21 | border-color: #00d1b2 !important; 22 | } 23 | .tags-li.active { 24 | border: 1px solid #00d1b2; 25 | background-color: #00d1b2; 26 | } 27 | .collapse-btn:hover{ 28 | background: #00d1b2; 29 | } -------------------------------------------------------------------------------- /perm-vue/src/components/page/demo/Permission.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | 25 | -------------------------------------------------------------------------------- /perm-server/sys-common/inits/init.go: -------------------------------------------------------------------------------- 1 | package inits 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/inits/parse" 5 | "permissionManage/perm-server/sys-common/inits/sys" 6 | "permissionManage/perm-server/sys-sysbase/models/user" 7 | 8 | "github.com/kataras/golog" 9 | ) 10 | 11 | func init() { 12 | parse.AppOtherParse() 13 | parse.DBSettingParse() 14 | 15 | initRootUser() 16 | } 17 | 18 | func initRootUser() { 19 | // root is existed? 20 | if sys.CheckRootExit() { 21 | return 22 | } 23 | 24 | // create root user 25 | sys.CreateRoot() 26 | 27 | ok := sys.CreateSystemRole() 28 | if ok { 29 | addRoleMenu() 30 | } 31 | 32 | } 33 | 34 | func addRoleMenu() { 35 | // 添加role-menu关系 36 | rMenus := []*user.RoleResource{ 37 | {RoleId: "", ResourceId: ""}, 38 | } 39 | effect, err := user.CreateRelationRoleResource(rMenus...) 40 | if err != nil { 41 | golog.Fatalf("**@@@@@@@@@@@0> %d, %s", effect, err.Error()) 42 | } 43 | golog.Infof("@@@@@@@@@-> %s, %s", effect, err.Error()) 44 | } 45 | -------------------------------------------------------------------------------- /perm-server/doc/go-bindata-usage: -------------------------------------------------------------------------------- 1 | ### install go-bindata 2 | go get -u github.com/go-bindata/go-bindata/... 3 | 4 | eg: 5 | ** [Please select this command !] 6 | ** Pack current directory(conf/) all configs. 7 | go-bindata -pkg parse -o inits/parse/conf-data.go conf/ 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | ** [Don't exec below !] 59 | ** Pack current directory(conf/**), and to include all input sub-directories recursively configs. 60 | go-bindata -pkg parse -o inits/parse/conf-data.go conf/... 61 | 62 | ** Pack conf/app.yml 63 | go-bindata -pkg parse -o inits/parse/app-data.go conf/app.yml 64 | 65 | ** Pack conf/db.yml 66 | go-bindata -pkg parse -o inits/parse/db-data.go conf/db.yml 67 | 68 | ** Pack conf/app.yml 69 | go-bindata -pkg parse -o inits/parse/rbac_model-data.go conf/rbac_model.conf -------------------------------------------------------------------------------- /perm-vue/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import sys_user_router from './sys-user-router' 4 | 5 | Vue.use(Router); 6 | 7 | export default new Router({ 8 | routes: [ 9 | { 10 | path: '/', 11 | redirect: '/dashboard' 12 | }, 13 | { 14 | path: '/', 15 | component: resolve => require(['../components/common/Home.vue'], resolve), 16 | children: [ 17 | { 18 | path: '/dashboard', 19 | component: resolve => require(['../components/page/demo/Dashboard.vue'], resolve), 20 | meta: {title: '系统首页'} 21 | }, 22 | ...sys_user_router 23 | ] 24 | }, 25 | { 26 | path: '/login', 27 | component: resolve => require(['../components/page/Login.vue'], resolve) 28 | }, 29 | { 30 | path: '*', 31 | redirect: '/404' 32 | } 33 | ] 34 | }) 35 | -------------------------------------------------------------------------------- /perm-server/sys-common/middleware/casbins/parse.go: -------------------------------------------------------------------------------- 1 | package casbins 2 | 3 | import ( 4 | "github.com/kataras/golog" 5 | ) 6 | 7 | /** 8 | 用于解析权限 9 | */ 10 | 11 | // 通过uid获取用户的所有资源 12 | func GetAllResourcesByUID(uid string) map[string]interface{} { 13 | allRes := make(map[string]interface{}) 14 | 15 | e := GetEnforcer() 16 | 17 | myRes := e.GetPermissionsForUser(uid) 18 | golog.Infof("myRes=> %s", myRes) 19 | 20 | // 获取用户的隐形角色 21 | implicitRoles := e.GetImplicitRolesForUser(uid) 22 | for _, v := range implicitRoles{ 23 | // 查询用户隐形角色的资源权限 24 | subRes := e.GetPermissionsForUser(v) 25 | golog.Infof("-------------------------------------------------") 26 | golog.Infof("subRes[%s], len(res)=> %d", v, len(subRes)) 27 | golog.Infof("subRes[%s], res=> %s", v, subRes) 28 | golog.Infof("-------------------------------------------------") 29 | allRes[v] = subRes 30 | } 31 | 32 | allRes["myRes"] = myRes 33 | return allRes 34 | } 35 | 36 | // 通过uid获取用户的所有角色 37 | func GetAllRoleByUID(uid string) []string { 38 | e := GetEnforcer() 39 | roles := e.GetImplicitRolesForUser(uid) 40 | golog.Infof("roles=> %s", roles) 41 | return roles 42 | } 43 | -------------------------------------------------------------------------------- /perm-vue/static/vuetable.json: -------------------------------------------------------------------------------- 1 | { 2 | "list": [{ 3 | "date": "1997-11-11", 4 | "name": "林丽", 5 | "address": "吉林省 辽源市 龙山区" 6 | }, { 7 | "date": "1987-09-24", 8 | "name": "文敏", 9 | "address": "江西省 萍乡市 芦溪县" 10 | }, { 11 | "date": "1996-08-08", 12 | "name": "杨秀兰", 13 | "address": "黑龙江省 黑河市 五大连池市" 14 | }, { 15 | "date": "1978-06-18", 16 | "name": "魏强", 17 | "address": "广东省 韶关市 始兴县" 18 | }, { 19 | "date": "1977-07-09", 20 | "name": "石秀兰", 21 | "address": "江苏省 宿迁市 宿豫区" 22 | }, { 23 | "date": "1994-09-20", 24 | "name": "朱洋", 25 | "address": "海外 海外 -" 26 | }, { 27 | "date": "1980-01-22", 28 | "name": "傅敏", 29 | "address": "海外 海外 -" 30 | }, { 31 | "date": "1985-10-10", 32 | "name": "毛明", 33 | "address": "内蒙古自治区 包头市 九原区" 34 | }, { 35 | "date": "1975-09-08", 36 | "name": "何静", 37 | "address": "西藏自治区 阿里地区 普兰县" 38 | }, { 39 | "date": "1970-06-07", 40 | "name": "郭秀英", 41 | "address": "四川省 巴中市 恩阳区" 42 | }] 43 | } -------------------------------------------------------------------------------- /perm-server/sys-common/vo/baseVo/base_vo.go: -------------------------------------------------------------------------------- 1 | package baseVo 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // 基础信息 8 | type BaseVO struct { 9 | Id string `json:"id" form:"id"` 10 | CreateTime time.Time `json:"createTime" form:"createTime"` 11 | CreatorDepartmentId string `json:"creatorDepartmentId" form:"creatorDepartmentId"` 12 | CreatorDepartmentName string `json:"creatorDepartmentName" form:"creatorDepartmentName"` 13 | CreatorId string `json:"creatorId" form:"creatorId"` 14 | CreatorName string `json:"creatorName" form:"creatorName"` 15 | IsDeleted int64 `json:"isDeleted" form:"isDeleted"` 16 | UpdateTime time.Time `json:"updateTime" form:"updateTime"` 17 | UpdatorDepartmentId string `json:"updatorDepartmentId" form:"updatorDepartmentId"` 18 | UpdatorDepartmentName string `json:"updatorDepartmentName" form:"updatorDepartmentName"` 19 | UpdatorId string `json:"updatorId" form:"updatorId"` 20 | UpdatorName string `json:"updatorName" form:"updatorName"` 21 | Version int64 `json:"version" form:"version"` 22 | Token string `json:"token"` 23 | } 24 | -------------------------------------------------------------------------------- /perm-server/sys-common/middleware/middleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/inits/parse" 5 | "permissionManage/perm-server/sys-common/middleware/casbins" 6 | "permissionManage/perm-server/sys-common/middleware/jwts" 7 | "strings" 8 | 9 | "github.com/kataras/iris/v12/context" 10 | ) 11 | 12 | type Middleware struct { 13 | } 14 | 15 | func ServeHTTP(ctx context.Context) { 16 | path := ctx.Path() 17 | // 过滤静态资源、login接口、首页等...不需要验证 18 | if checkURL(path) || strings.Contains(path, "/static") { 19 | ctx.Next() 20 | return 21 | } 22 | 23 | // jwt token拦截 24 | if !jwts.Serve(ctx) { 25 | return 26 | } 27 | 28 | // 系统菜单不进行权限拦截 29 | if !strings.Contains(path, "/sysMenu") { 30 | // casbin权限拦截 31 | ok := casbins.CheckPermissions(ctx) 32 | if !ok { 33 | return 34 | } 35 | } 36 | 37 | // Pass to real API 38 | ctx.Next() 39 | } 40 | 41 | /** 42 | return 43 | true:则跳过不需验证,如登录接口等... 44 | false:需要进一步验证 45 | */ 46 | func checkURL(reqPath string) bool { 47 | //config := iris.YAML("conf/app.yml") 48 | //ignoreURLs := config.GetOther()["ignoreURLs"].([]interface{}) 49 | for _, v := range parse.O.IgnoreURLs { 50 | if reqPath == v { 51 | return true 52 | } 53 | } 54 | return false 55 | } 56 | -------------------------------------------------------------------------------- /perm-vue/src/router/sys-user-router.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | path: '/departments', 4 | component: resolve => require(['../components/page/sys-user/department/departments.vue'], resolve), 5 | meta: {title: '部门管理'} 6 | }, 7 | { 8 | path: '/new-user', 9 | component: resolve => require(['../components/page/sys-user/user/userList.vue'], resolve), 10 | meta: {title: '内部用户'} 11 | }, 12 | { 13 | path: '/role-list', 14 | component: resolve => require(['../components/page/sys-user/role/role-list.vue'], resolve), 15 | meta: {title: '角色管理'} 16 | }, 17 | { 18 | path: '/role-edit', 19 | component: resolve => require(['../components/page/sys-user/role/role-edit.vue'], resolve), 20 | meta: {title: '角色编辑'} 21 | }, 22 | { 23 | path: '/permission-list', 24 | component: resolve => require(['../components/page/sys-user/permission/permission-list.vue'], resolve), 25 | meta: {title: '资源管理'} 26 | }, 27 | { 28 | path: '/page-resource-list', 29 | component: resolve => require(['../components/page/sys-user/permission/page-resource-list.vue'], resolve), 30 | meta: {title: '页面元素管理'} 31 | } 32 | ] 33 | 34 | 35 | -------------------------------------------------------------------------------- /perm-server/sys-common/vo/page_vo.go: -------------------------------------------------------------------------------- 1 | package vo 2 | 3 | // 分页参数 4 | type PageVo struct { 5 | CurrentPage int `json:"currentPage"` 6 | PageSize int `json:"pageSize"` 7 | Start int `json:"start"` 8 | Limit int `json:"limit"` 9 | Total int64 `json:"total"` 10 | } 11 | 12 | func GetPageParam(param *PageVo) (res *PageVo) { 13 | if param == nil { 14 | res.CurrentPage = 0 15 | res.PageSize = 10 16 | res.Limit = 10 17 | res.Start = 0 18 | 19 | return 20 | } 21 | 22 | var ( 23 | current int 24 | size int 25 | ) 26 | res = new(PageVo) 27 | 28 | if param.CurrentPage < 0 { 29 | res.CurrentPage = 0 30 | current = 0 31 | } else { 32 | res.CurrentPage = param.CurrentPage 33 | current = param.CurrentPage - 1 34 | } 35 | 36 | if param.PageSize < 0 { 37 | res.PageSize = 10 38 | size = 10 39 | } else { 40 | res.PageSize = param.PageSize 41 | size = param.PageSize 42 | } 43 | res.Start = current * size 44 | res.Limit = param.PageSize 45 | res.Total = param.Total 46 | 47 | return 48 | } 49 | 50 | type PageResult struct { 51 | CurrentPage int `json:"currentPage"` 52 | PageSize int `json:"pageSize"` 53 | Total int64 `json:"total"` 54 | Data interface{} `json:"data"` 55 | } 56 | -------------------------------------------------------------------------------- /perm-server/sys-common/vo/Pagination.go: -------------------------------------------------------------------------------- 1 | package vo 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/kataras/iris/v12" 7 | ) 8 | 9 | // bootstraptable 分页参数 10 | type Pagination struct { 11 | PageNumber int //当前看的是第几页 12 | PageSize int //每页显示多少条数据 13 | 14 | // 用于分页设置的参数 15 | Start int 16 | Limit int 17 | 18 | SortName string //用于指定的排序 19 | SortOrder string // desc或asc 20 | 21 | // 时间范围 22 | StartDate string 23 | EndDate string 24 | 25 | Uid int64 // 公用的特殊参数 26 | } 27 | 28 | func NewPagination(ctx iris.Context) (*Pagination, error) { 29 | pageNumber, err1 := ctx.URLParamInt("pageNumber") 30 | pageSize, err2 := ctx.URLParamInt("pageSize") 31 | sortName := ctx.URLParam("sortName") 32 | sortOrder := ctx.URLParam("sortOrder") 33 | if err1 != nil || err2 != nil { 34 | return nil, errors.New("请求的分页参数解析错误.") 35 | } 36 | 37 | page := Pagination{ 38 | PageNumber: pageNumber, 39 | PageSize: pageSize, 40 | SortName: sortName, 41 | SortOrder: sortOrder, 42 | } 43 | page.pageSetting() 44 | return &page, nil 45 | } 46 | 47 | // 设置分页参数 48 | func (p *Pagination) pageSetting() { 49 | if p.PageNumber < 1 { 50 | p.PageNumber = 1 51 | } 52 | if p.PageSize < 1 { 53 | p.PageSize = 1 54 | } 55 | 56 | p.Start = (p.PageNumber - 1) * p.PageSize 57 | p.Limit = p.PageSize 58 | } 59 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module permissionManage 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect 7 | github.com/casbin/casbin v1.9.1 8 | github.com/dgrijalva/jwt-go v3.2.0+incompatible 9 | github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 // indirect 10 | github.com/garyburd/redigo v1.6.0 11 | github.com/go-sql-driver/mysql v1.4.1 12 | github.com/go-xorm/xorm v0.7.9 13 | github.com/gofrs/uuid v3.2.0+incompatible 14 | github.com/golang/protobuf v1.3.2 // indirectgo mod download 15 | github.com/gorilla/schema v1.1.0 // indirect 16 | github.com/iris-contrib/formBinder v5.0.0+incompatible // indirect 17 | github.com/iris-contrib/middleware/cors v0.0.0-20191219204441-78279b78a367 18 | github.com/json-iterator/go v1.1.7 // indirect 19 | github.com/kataras/golog v0.0.10 20 | github.com/kataras/iris v11.1.1+incompatible 21 | github.com/kataras/iris/v12 v12.1.2 22 | github.com/kr/pretty v0.1.0 // indirect 23 | github.com/lib/pq v1.1.1 24 | github.com/mattn/go-isatty v0.0.10 // indirect 25 | github.com/pelletier/go-toml v1.7.0 26 | github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect 27 | github.com/ugorji/go v1.1.7 // indirect 28 | golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae // indirect 29 | gopkg.in/yaml.v2 v2.2.8 30 | xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb 31 | ) 32 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/error-page/403.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | 24 | 25 | 57 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/error-page/404.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | 24 | 25 | 57 | -------------------------------------------------------------------------------- /perm-vue/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | require('./check-versions')(); 3 | 4 | process.env.NODE_ENV = 'production'; 5 | 6 | const ora = require('ora'); 7 | const rm = require('rimraf'); 8 | const path = require('path'); 9 | const chalk = require('chalk'); 10 | const webpack = require('webpack'); 11 | const config = require('../config'); 12 | const webpackConfig = require('./webpack.prod.conf'); 13 | 14 | const spinner = ora('building for production...'); 15 | spinner.start(); 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err; 19 | webpack(webpackConfig, (err, stats) => { 20 | spinner.stop(); 21 | if (err) throw err; 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /perm-vue/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | 7 | function exec (cmd) { 8 | return require('child_process').execSync(cmd).toString().trim() 9 | } 10 | 11 | const versionRequirements = [ 12 | { 13 | name: 'node', 14 | currentVersion: semver.clean(process.version), 15 | versionRequirement: packageConfig.engines.node 16 | } 17 | ] 18 | 19 | if (shell.which('npm')) { 20 | versionRequirements.push({ 21 | name: 'npm', 22 | currentVersion: exec('npm --version'), 23 | versionRequirement: packageConfig.engines.npm 24 | }) 25 | } 26 | 27 | module.exports = function () { 28 | const warnings = [] 29 | 30 | for (let i = 0; i < versionRequirements.length; i++) { 31 | const mod = versionRequirements[i] 32 | 33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 34 | warnings.push(mod.name + ': ' + 35 | chalk.red(mod.currentVersion) + ' should be ' + 36 | chalk.green(mod.versionRequirement) 37 | ) 38 | } 39 | } 40 | 41 | if (warnings.length) { 42 | console.log('') 43 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 44 | console.log() 45 | 46 | for (let i = 0; i < warnings.length; i++) { 47 | const warning = warnings[i] 48 | console.log(' ' + warning) 49 | } 50 | 51 | console.log() 52 | process.exit(1) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > #### 软件架构 2 | > 目前支持单web架构,如果部署成前后端分离,可用nginx中间件代理(已添加跨域访问设置)。 3 | > * 采用了golang iris框架; 4 | > * 采用jwt做用户认证、回话控制; 5 | > * 采用Mysql+xorm做持久层; 6 | > * 采用redis做tocken缓存; 7 | > * Vue前端项目; 8 | 9 | *** 10 | #### 项目目录结构 11 | ``` 12 | perm 13 | +-- perm-server 后端服务 14 | | +-- doc 说明文档目录 15 | | +-- sql sql文件目录(包含初始化sql) 16 | | +-- main 项目启动入口(包含main.go) 17 | | +-- sys_common 公共服务目录 18 | | +-- caches 缓存工具目录 19 | | +-- conf 配置文件目录 20 | | +-- db 初始化数据库连接 21 | | +-- inits 初始化系统用户,角色目录 22 | | +-- middleware 中间件目录 23 | | +-- models 公共数据库实体模型 24 | | +-- supports 系统常量目录 25 | | +-- utils 后端工具目录 26 | | +-- vo 页面所需公共数据类型目录 27 | | +-- sys_base 业务基础服务(包含:用户,菜单,角色,部门) 28 | | +-- models 数据库对应实体模型文件 29 | | +-- routes 请求路由处理目录 30 | | +-- service 业务逻辑处理目录 31 | | +-- vo 业务所需数据类型目录 32 | +-- perm-vue 前端页面 33 | | +-- build 构建静态文件目录 34 | | +-- config 前端配置文件目录 35 | | +-- src 前端资源文件 36 | | +-- components 页面目录 37 | | +-- router 前端路由目录 38 | | +-- utils 前端工具目录 39 | | +-- static 前端静态文件目录 40 | 41 | ### 服务启动 42 | 1. rizla main.go (go get -u github.com/kataras/rizla 热启动插件) 43 | 44 | 45 | > * 超级管理员登录: 46 | > > 初始账号:root 47 | > > 初始密码: 123456 48 | 49 | 50 | -------------------------------------------------------------------------------- /perm-vue/src/components/common/Home.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 50 | -------------------------------------------------------------------------------- /perm-server/sys-common/inits/parse/app.go: -------------------------------------------------------------------------------- 1 | package parse 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/kataras/golog" 7 | "github.com/kataras/iris/v12" 8 | ) 9 | 10 | var ( 11 | // conf strut 12 | C iris.Configuration 13 | 14 | // 解析app.yml中的Other项 15 | O Other 16 | // app.conf配置项key定义 17 | Port string = "Port" 18 | ignoreURLs string = "IgnoreURLs" 19 | jwtTimeout string = "JWTTimeout" 20 | logLevel string = "LogLevel" 21 | secret string = "Secret" 22 | ) 23 | 24 | type ( 25 | Other struct { 26 | Port string 27 | IgnoreURLs []string 28 | JWTTimeout int64 29 | LogLevel string 30 | Secret string 31 | } 32 | ) 33 | 34 | func AppOtherParse() { 35 | golog.Info("@@@ Init app conf") 36 | c := iris.YAML("./perm-server/sys-common/conf/app.yml") 37 | 38 | //appData, err := conf.Asset("conf/app.yml") 39 | //if err != nil { 40 | // golog.Fatalf("Error. %s", err) 41 | //} 42 | //c := iris.DefaultConfiguration() 43 | golog.Println(c) 44 | //if err = yaml.Unmarshal(appData, &c); err != nil { 45 | // golog.Fatalf("Error. %s", err) 46 | //} 47 | //C = c 48 | 49 | // -------------- 解析每个Other配置项 --------------- 50 | 51 | O.Port = strconv.Itoa(c.GetOther()[Port].(int)) 52 | 53 | // 解析other的key 54 | iURLs := c.GetOther()[ignoreURLs].([]interface{}) 55 | for _, v := range iURLs { 56 | O.IgnoreURLs = append(O.IgnoreURLs, v.(string)) 57 | } 58 | 59 | jTimeout := c.GetOther()[jwtTimeout].(int) 60 | O.JWTTimeout = int64(jTimeout) 61 | 62 | O.LogLevel = c.GetOther()[logLevel].(string) 63 | 64 | O.Secret = c.GetOther()[secret].(string) 65 | 66 | } 67 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/sys-user/department/tree.utils.js: -------------------------------------------------------------------------------- 1 | export function getEditContent(h, data, node) { 2 | let self = this; 3 | return ( 4 | 5 | self.close(data, node) } 9 | > 10 | 取消 11 | 12 | self.editMsg(data, node) } 16 | > 17 | 确认 18 | 19 | 20 | ) 21 | } 22 | 23 | export function getDefaultContent(h, data, node) { 24 | let self = this 25 | return ( 26 |
27 | { 28 | self.is_superuser && 29 | ( 30 | self.update(node, data) } 34 | > 35 | 编辑 36 | 37 | 38 | { 39 | data.level !== 6 && 40 | self.append(node, data) } 44 | > 45 | 添加 46 | 47 | } 48 | 49 | { 50 | data.level !== 1 && 51 | self.remove(node, data) } 55 | > 56 | 删除 57 | 58 | } 59 | ) 60 | } 61 |
62 | ) 63 | } 64 | -------------------------------------------------------------------------------- /perm-server/sys-common/inits/parse/db.go: -------------------------------------------------------------------------------- 1 | package parse 2 | 3 | import ( 4 | "github.com/kataras/golog" 5 | 6 | "gopkg.in/yaml.v2" 7 | "io/ioutil" 8 | ) 9 | 10 | var ( 11 | DBConfig DB 12 | ) 13 | 14 | func DBSettingParse() { 15 | golog.Info("@@@ Init db conf") 16 | data, err := ioutil.ReadFile("./perm-server/sys-common/conf/db.yml") 17 | golog.Infof("%s", data) 18 | if err != nil { 19 | golog.Fatalf("@@@ %s", err) 20 | } 21 | err = yaml.Unmarshal(data, &DBConfig) 22 | if err != nil { 23 | golog.Fatalf("@@@ Unmarshal db config error!! %s", err) 24 | } 25 | 26 | //dbData, err := Asset("conf/db.yml") 27 | //if err != nil { 28 | // golog.Fatalf("Error. %s", err) 29 | //} 30 | if err = yaml.Unmarshal(data, &DBConfig); err != nil { 31 | golog.Fatalf("Error. %s", err) 32 | } 33 | 34 | golog.Info(DBConfig) 35 | } 36 | 37 | type DB struct { 38 | Master DBConfigInfo 39 | Slave DBConfigInfo 40 | } 41 | 42 | type DBConfigInfo struct { 43 | Dialect string `yaml:"dialect"` 44 | User string `yaml:"user"` 45 | Password string `yaml:"password"` 46 | Host string `yaml:"host"` 47 | Port int `yaml:"port"` 48 | Database string `yaml:"database"` 49 | Charset string `yaml:"charset"` 50 | ShowSql bool `yaml:"showSql"` 51 | LogLevel string `yaml:"logLevel"` 52 | MaxIdleConns int `yaml:"maxIdleConns"` 53 | MaxOpenConns int `yaml:"maxOpenConns"` 54 | 55 | //ParseTime bool `yaml:"parseTime"` 56 | //MaxIdleConns int `yaml:"maxIdleConns"` 57 | //MaxOpenConns int `yaml:"maxOpenConns"` 58 | //ConnMaxLifetime int64 `yaml:"connMaxLifetime: 10"` 59 | //Sslmode string `yaml:"sslmode"` 60 | } 61 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/demo/VueEditor.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 49 | -------------------------------------------------------------------------------- /perm-vue/config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Template version: 1.2.7 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path'); 6 | 7 | module.exports = { 8 | dev: { 9 | env: require('./dev.env'), 10 | host: 'localhost', 11 | port: 8099, 12 | // Paths 13 | assetsSubDirectory: 'http://localhost:8099/static', 14 | assetsPublicPath: 'http://localhost:8099/', 15 | proxyTable: { 16 | '/perm': { 17 | // 本机 18 | target: 'http://127.0.0.1:8098', 19 | changeOrigin: true, 20 | pathRewrite: { 21 | '/perm': '/perm' 22 | } 23 | } 24 | }, 25 | cssSourceMap: false, 26 | }, 27 | 28 | build: { 29 | // Template for index.html 30 | index: path.resolve(__dirname, '../perm-vue-manage/index.html'), 31 | 32 | // Paths 33 | assetsRoot: path.resolve(__dirname, '../perm-vue-manage'), 34 | assetsSubDirectory: 'static', 35 | assetsPublicPath: './', 36 | 37 | /** 38 | * Source Maps 39 | */ 40 | 41 | productionSourceMap: false, 42 | // https://webpack.js.org/configuration/devtool/#production 43 | devtool: '#source-map', 44 | 45 | // Gzip off by default as many popular static hosts such as 46 | // Surge or Netlify already gzip all static assets for you. 47 | // Before setting to `true`, make sure to: 48 | // npm install --save-dev compression-webpack-plugin 49 | productionGzip: false, 50 | productionGzipExtensions: ['js', 'css'], 51 | 52 | // Run the build command with an extra argument to 53 | // View the bundle analyzer report after build finishes: 54 | // `npm run build --report` 55 | // Set to `true` or `false` to always turn it on or off 56 | bundleAnalyzerReport: process.env.npm_config_report 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /perm-server/sys-common/middleware/jwts/config.go: -------------------------------------------------------------------------------- 1 | package jwts 2 | 3 | import "github.com/dgrijalva/jwt-go" 4 | 5 | const ( 6 | //DefaultContextKey jwts 7 | DefaultContextKey = "iris-jwt" 8 | ) 9 | 10 | // Config is a struct for specifying configuration options for the jwts middleware. 11 | type Config struct { 12 | // The function that will return the Key to validate the JWT. 13 | // It can be either a shared secret or a public key. 14 | // Default value: nil 15 | ValidationKeyGetter jwt.Keyfunc 16 | // The name of the property in the request where the user (&token) information 17 | // from the JWT will be stored. 18 | // Default value: "jwts" 19 | ContextKey string 20 | // The function that will be called when there's an error validating the token 21 | // Default value: 22 | ErrorHandler errorHandler 23 | // A boolean indicating if the credentials are required or not 24 | // Default value: false 25 | CredentialsOptional bool 26 | // A function that extracts the token from the request 27 | // Default: FromAuthHeader (i.e., from Authorization header as bearer token) 28 | Extractor TokenExtractor 29 | // Debug flag turns on debugging output 30 | // Default: false 31 | Debug bool 32 | // When set, all requests with the OPTIONS method will use authentication 33 | // if you enable this option you should register your route with iris.Options(...) also 34 | // Default: false 35 | EnableAuthOnOptions bool 36 | // When set, the middelware verifies that tokens are signed with the specific signing algorithm 37 | // If the signing method is not constant the ValidationKeyGetter callback can be used to implement additional checks 38 | // Important to avoid security issues described here: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ 39 | // Default: nil 40 | SigningMethod jwt.SigningMethod 41 | // When set, the expiration time of token will be check every time 42 | // if the token was expired, expiration error will be returned 43 | // Default: false 44 | Expiration bool 45 | } 46 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/sys-user/department/tree.scss: -------------------------------------------------------------------------------- 1 | 2 | .ly-tree-container { 3 | margin: 20px 0 20px 20px; 4 | width: 60%; 5 | padding: 20px; 6 | 7 | span { 8 | font-size: 14px; 9 | } 10 | 11 | .el-tree > .el-tree-node > .el-tree-node__content:first-child { 12 | &::before, 13 | &::after { 14 | border: none; 15 | } 16 | } 17 | 18 | .ly-visible { 19 | margin-left: 50px; 20 | visibility: hidden; 21 | } 22 | 23 | .ly-edit__text { 24 | width: 25%; 25 | height: 25px; 26 | border: 1px solid #e6e6e6; 27 | border-radius: 3px; 28 | color: #666; 29 | text-indent: 10px; 30 | } 31 | 32 | .ly-tree__loading { 33 | color: #666; 34 | font-weight: bold; 35 | } 36 | 37 | .ly-tree-node { 38 | flex: 1; 39 | display: flex; 40 | align-items: center; 41 | // justify-content: space-between; 42 | justify-content: flex-start; 43 | font-size: 14px; 44 | padding-right: 8px; 45 | } 46 | 47 | .ly-tree-node > div > span:last-child { 48 | display: inline-block; 49 | width: 110px; 50 | text-align: left; 51 | } 52 | 53 | .ly-tree-node > span:last-child { 54 | display: inline-block; 55 | width: 110px; 56 | text-align: left; 57 | } 58 | 59 | .el-tree-node .el-tree-node__content { 60 | height: 30px; 61 | 62 | &:hover .ly-visible { 63 | visibility: visible; 64 | } 65 | 66 | &::before, 67 | &::after { 68 | content: ''; 69 | position: absolute; 70 | right: auto; 71 | } 72 | 73 | &::before { 74 | border-left: 1px solid #e6e6e6; 75 | bottom: 50px; 76 | height: 100%; 77 | top: 0; 78 | width: 1px; 79 | margin-left: -5px; 80 | margin-top: -15px; 81 | } 82 | 83 | &::after { 84 | border-top: 1px solid #e6e6e6; 85 | height: 20px; 86 | top: 14px; 87 | width: 10px; 88 | margin-left: -5px; 89 | } 90 | } 91 | 92 | .el-tree .el-tree-node { 93 | position: relative; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /perm-server/sys-common/inits/sys/user.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/db" 5 | "permissionManage/perm-server/sys-common/middleware/casbins" 6 | "permissionManage/perm-server/sys-common/utils" 7 | "permissionManage/perm-server/sys-sysbase/models/user" 8 | "time" 9 | 10 | "github.com/kataras/golog" 11 | ) 12 | 13 | const ( 14 | userNumber = "0" 15 | userAccount = "root" 16 | userPassword = "123456" 17 | userName = "超级管理员" 18 | ) 19 | 20 | // 检查超级用户是否存在 21 | func CheckRootExit() bool { 22 | e := db.MasterEngine() 23 | // root is existed? 24 | exit, err := e.Exist(&user.User{UserAccount: userAccount}) 25 | if err != nil { 26 | golog.Fatalf("@@@ When check Root User is exited? happened error. %s", err.Error()) 27 | } 28 | if exit { 29 | golog.Info("@@@ Root User is existed.") 30 | 31 | // 初始化rbac_model 32 | r := user.User{UserAccount: userAccount} 33 | if exit, _ := e.Get(&r); exit { 34 | casbins.SetRbacModel(r.Id) 35 | CreateSystemRole() 36 | } 37 | } 38 | return exit 39 | } 40 | 41 | func CreateRoot() { 42 | newRoot := user.User{ 43 | Id: utils.GetUuid(), 44 | UserNumber: userNumber, 45 | UserAccount: userAccount, 46 | UserPassword: utils.AESEncrypt([]byte(userPassword)), 47 | UserName: userName, 48 | CreateTime: time.Now(), 49 | } 50 | 51 | e := db.MasterEngine() 52 | if _, err := e.Insert(&newRoot); err != nil { 53 | golog.Fatalf("@@@ When create Root User happened error. %s", err.Error()) 54 | } 55 | rooId := newRoot.Id 56 | casbins.SetRbacModel(rooId) 57 | 58 | addAllpolicy(rooId) 59 | } 60 | 61 | func addAllpolicy(rooId string) { 62 | // add policy for root 63 | //p := casbins.GetEnforcer().AddPolicy(utils.FmtRolePrefix(newRoot.Id), "/*", "ANY", ".*") 64 | e := casbins.GetEnforcer() 65 | p := e.AddPolicy(rooId, "/*", "ANY", ".*", "", "", "", "", "", "超级用户") 66 | if !p { 67 | golog.Fatalf("初始化用户[%s]权限失败.", userName) 68 | } 69 | 70 | // 71 | for _, v := range Components { 72 | e.AddGroupingPolicy(rooId, v[0]) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/models/user/role_resource.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/db" 5 | "permissionManage/perm-server/sys-common/utils" 6 | "time" 7 | ) 8 | 9 | // 角色-资源关联表 10 | type RoleResource struct { 11 | Id string `xorm:"pk varchar(32) notnull unique 'id'"` 12 | CreateTime time.Time `xorm:"'create_time'"` 13 | CreatorDepartmentId string `xorm:"varchar(50) 'creator_department_id'"` 14 | CreatorDepartmentName string `xorm:"varchar(255) 'creator_department_name'"` 15 | CreatorId string `xorm:"varchar(50) 'creator_id'"` 16 | CreatorName string `xorm:"varchar(255) 'creator_name'"` 17 | IsDeleted int64 `xorm:"INT(1) notnull 'is_deleted'"` 18 | UpdateTime time.Time `xorm:"'update_time'"` 19 | UpdatorDepartmentId string `xorm:"varchar(50) 'updator_department_id'"` 20 | UpdatorDepartmentName string `xorm:"varchar(255) 'updator_department_name'"` 21 | UpdatorId string `xorm:"varchar(50) 'updator_id'"` 22 | UpdatorName string `xorm:"varchar(255) 'updator_name'"` 23 | Version int64 `xorm:"INT(11) 'version'"` 24 | 25 | RoleId string `xorm:"varchar(50) notnull 'role_id'"` 26 | ResourceId string `xorm:"varchar(50) notnull 'resource_id'"` 27 | } 28 | 29 | func (RoleResource) TableName() string { 30 | return "cd_sys_user_role_resource" 31 | } 32 | 33 | // 34 | func CreateRelationRoleResource(roleResources ...*RoleResource) (int64, error) { 35 | e := db.MasterEngine() 36 | var roleResourceEntitys []RoleResource 37 | for _, r := range roleResources { 38 | // 生成uuid 39 | r.Id = utils.GetUuid() 40 | r.CreateTime = time.Now() 41 | r.Version = 0 42 | r.IsDeleted = 0 43 | 44 | roleResourceEntitys = append(roleResourceEntitys, *r) 45 | } 46 | return e.Insert(roleResourceEntitys) 47 | } 48 | 49 | //========================= 物理删除 ============================ 50 | func RemoveRoleResource(roleId string) (effect int64, err error) { 51 | e := db.MasterEngine() 52 | 53 | rr := new(RoleResource) 54 | effect, err = e.Where("role_id = ?", roleId).Delete(rr) 55 | 56 | return 57 | } 58 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/vo/uservo/role_resource_vo.go: -------------------------------------------------------------------------------- 1 | package uservo 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/models/baseModel" 5 | "permissionManage/perm-server/sys-sysbase/models/user" 6 | "strings" 7 | "time" 8 | ) 9 | 10 | // 前端需要的数据结构 11 | type RoleResourceVO struct { 12 | Id string `json:"id"` 13 | CreateTime time.Time `json:"createTime"` 14 | CreatorDepartmentId string `json:"creatorDepartmentId"` 15 | CreatorDepartmentName string `json:"creatorDepartmentName"` 16 | CreatorId string `json:"creatorId"` 17 | CreatorName string `json:"creatorName"` 18 | IsDeleted int64 `json:"isDeleted"` 19 | UpdateTime time.Time `json:"updateTime"` 20 | UpdatorDepartmentId string `json:"updatorDepartmentId"` 21 | UpdatorDepartmentName string `json:"updatorDepartmentName"` 22 | UpdatorId string `json:"updatorId"` 23 | UpdatorName string `json:"updatorName"` 24 | Version int64 `json:"version"` 25 | 26 | RoleId string `json:"roleId"` 27 | ResourceId string `json:"resourceId"` 28 | } 29 | 30 | // 请求参数 31 | type RoleResourceParamVo struct { 32 | *baseModel.CurrentUser 33 | 34 | RoleId string `json:"roleId"` 35 | ResourceIds string `json:"resourceIds"` 36 | } 37 | 38 | func RoleResourceParamVoToRoleResource(paramVO *RoleResourceParamVo) (result []*user.RoleResource) { 39 | currentUser := paramVO.CurrentUser 40 | resourceIdArry := strings.Split(paramVO.ResourceIds, ",") 41 | for _, resourceId := range resourceIdArry { 42 | tmpRes := new(user.RoleResource) 43 | tmpRes.CreatorId = currentUser.UserAccount 44 | tmpRes.CreatorName = currentUser.UserName 45 | tmpRes.CreatorDepartmentId = currentUser.DepartmentId 46 | tmpRes.CreatorDepartmentName = currentUser.DepartmentName 47 | tmpRes.UpdatorId = currentUser.UserAccount 48 | tmpRes.UpdatorName = currentUser.UserName 49 | tmpRes.UpdatorDepartmentId = currentUser.DepartmentId 50 | tmpRes.UpdatorDepartmentName = currentUser.DepartmentName 51 | tmpRes.UpdateTime = time.Now() 52 | 53 | tmpRes.RoleId = paramVO.RoleId 54 | tmpRes.ResourceId = resourceId 55 | 56 | result = append(result, tmpRes) 57 | } 58 | 59 | return 60 | } 61 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/vo/uservo/user_role_vo.go: -------------------------------------------------------------------------------- 1 | package uservo 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/models/baseModel" 5 | "permissionManage/perm-server/sys-sysbase/models/user" 6 | "time" 7 | ) 8 | 9 | // 前端需要的数据结构 10 | type UserRoleVO struct { 11 | Id string `json:"id"` 12 | CreateTime time.Time `json:"createTime"` 13 | CreatorDepartmentId string `json:"creatorDepartmentId"` 14 | CreatorDepartmentName string `json:"creatorDepartmentName"` 15 | CreatorId string `json:"creatorId"` 16 | CreatorName string `json:"creatorName"` 17 | IsDeleted int64 `json:"isDeleted"` 18 | UpdateTime time.Time `json:"updateTime"` 19 | UpdatorDepartmentId string `json:"updatorDepartmentId"` 20 | UpdatorDepartmentName string `json:"updatorDepartmentName"` 21 | UpdatorId string `json:"updatorId"` 22 | UpdatorName string `json:"updatorName"` 23 | Version int64 `json:"version"` 24 | 25 | RoleId string `json:"roleId"` 26 | ResourceId string `json:"resourceId"` 27 | } 28 | 29 | // 请求参数 30 | type UserRoleParamVo struct { 31 | *baseModel.CurrentUser 32 | 33 | CheckType string `json:"checkType"` 34 | UserId string `json:"userId"` 35 | RoleIds []string `json:"roleIds"` 36 | } 37 | 38 | func UserRoleParamVoToUserRole(paramVO *UserRoleParamVo) (result []*user.UserRole) { 39 | currentUser := paramVO.CurrentUser 40 | //roleIdArry := strings.Split(paramVO.RoleIds, ",") 41 | roleIdArry := paramVO.RoleIds 42 | for _, roleId := range roleIdArry { 43 | tmpRes := new(user.UserRole) 44 | tmpRes.CreatorId = currentUser.UserAccount 45 | tmpRes.CreatorName = currentUser.UserName 46 | tmpRes.CreatorDepartmentId = currentUser.DepartmentId 47 | tmpRes.CreatorDepartmentName = currentUser.DepartmentName 48 | tmpRes.UpdatorId = currentUser.UserAccount 49 | tmpRes.UpdatorName = currentUser.UserName 50 | tmpRes.UpdatorDepartmentId = currentUser.DepartmentId 51 | tmpRes.UpdatorDepartmentName = currentUser.DepartmentName 52 | tmpRes.UpdateTime = time.Now() 53 | 54 | tmpRes.UserId = paramVO.UserId 55 | tmpRes.RoleId = roleId 56 | 57 | result = append(result, tmpRes) 58 | } 59 | 60 | return 61 | } 62 | -------------------------------------------------------------------------------- /perm-server/sys-common/supports/simple_response.go: -------------------------------------------------------------------------------- 1 | package supports 2 | 3 | import ( 4 | "github.com/kataras/iris/v12" 5 | ) 6 | 7 | const ( 8 | // key定义 9 | CODE string = "code" 10 | MSG string = "msg" 11 | DATA string = "data" 12 | 13 | // msg define 14 | Success = "恭喜, 成功" 15 | OptionSuccess string = "恭喜, 操作成功" 16 | OptionFailur string = "抱歉, 操作失败" 17 | ParseParamsFailur string = "解析参数失败" 18 | 19 | RegisteSuccess string = "恭喜, 注册用户成功" 20 | RegisteFailur string = "注册失败" 21 | LoginSuccess string = "恭喜, 登录成功" 22 | LogoutSuccess string = "恭喜, 退出成功" 23 | LoginFailur string = "登录失败" 24 | DeleteUsersSuccess string = "删除用户成功" 25 | DeleteUsersFailur string = "删除用户错误" 26 | 27 | DeleteRolesSuccess string = "删除角色成功" 28 | DeleteRolesFailur string = "删除角色错误" 29 | 30 | UsernameFailur string = "用户名错误" 31 | PasswordFailur string = "密码错误" 32 | TokenCreateFailur string = "生成token错误" 33 | TokenExactFailur string = "token不存在或header设置不正确" 34 | TokenExpire string = "回话已过期" 35 | TokenParseFailur string = "token解析错误" 36 | TokenParseFailurAndEmpty string = "解析错误,token为空" 37 | TokenParseFailurAndInvalid string = "解析错误,token无效" 38 | NotFound string = "您请求的url不存在" 39 | PermissionsLess string = "权限不足" 40 | 41 | RoleCreateFailur string = "创建角色失败" 42 | RoleCreateSuccess string = "创建角色成功" 43 | 44 | // value define 45 | 46 | ) 47 | 48 | // 200 define 49 | func Ok_(ctx iris.Context, msg string) { 50 | Ok(ctx, msg, nil) 51 | } 52 | 53 | func Ok(ctx iris.Context, msg string, data interface{}) { 54 | ctx.StatusCode(iris.StatusOK) 55 | ctx.JSON(iris.Map{ 56 | CODE: iris.StatusOK, 57 | MSG: msg, 58 | DATA: data, 59 | }) 60 | } 61 | 62 | // 401 error define 63 | func Unauthorized(ctx iris.Context, msg string, data interface{}) { 64 | unauthorized := iris.StatusUnauthorized 65 | 66 | ctx.StatusCode(unauthorized) 67 | ctx.JSON(iris.Map{ 68 | CODE: unauthorized, 69 | MSG: msg, 70 | DATA: data, 71 | }) 72 | } 73 | 74 | // common error define 75 | func Error(ctx iris.Context, status int, msg string, data interface{}) { 76 | ctx.StatusCode(status) 77 | ctx.JSON(iris.Map{ 78 | CODE: status, 79 | MSG: msg, 80 | DATA: data, 81 | }) 82 | } 83 | -------------------------------------------------------------------------------- /perm-server/sys-common/utils/encrypt.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/md5" 6 | "encoding/hex" 7 | "errors" 8 | ) 9 | 10 | // Md5 returns the MD5 checksum string of the data. 11 | func Md5(b []byte) string { 12 | checksum := md5.Sum(b) 13 | return hex.EncodeToString(checksum[:]) 14 | } 15 | 16 | // AESEncrypt encrypts a piece of data. 17 | // The cipherkey argument should be the AES key, 18 | // either 16, 24, or 32 bytes to select 19 | // AES-128, AES-192, or AES-256. 20 | func AESEncrypt2(cipherkey, src []byte) []byte { 21 | block, err := aes.NewCipher(cipherkey) 22 | if err != nil { 23 | panic(err) 24 | } 25 | bs := block.BlockSize() 26 | src = padData(src, bs) 27 | r := make([]byte, len(src)) 28 | dst := r 29 | for len(src) > 0 { 30 | block.Encrypt(dst, src) 31 | src = src[bs:] 32 | dst = dst[bs:] 33 | } 34 | dst = make([]byte, hex.EncodedLen(len(r))) 35 | hex.Encode(dst, r) 36 | return dst 37 | } 38 | 39 | // AESDecrypt decrypts a piece of data. 40 | // The cipherkey argument should be the AES key, 41 | // either 16, 24, or 32 bytes to select 42 | // AES-128, AES-192, or AES-256. 43 | func AESDecrypt2(cipherkey, ciphertext []byte) ([]byte, error) { 44 | block, err := aes.NewCipher(cipherkey) 45 | if err != nil { 46 | return nil, err 47 | } 48 | src := make([]byte, hex.DecodedLen(len(ciphertext))) 49 | _, err = hex.Decode(src, ciphertext) 50 | if err != nil { 51 | return nil, err 52 | } 53 | bs := block.BlockSize() 54 | r := make([]byte, len(src)) 55 | dst := r 56 | for len(src) > 0 { 57 | block.Decrypt(dst, src) 58 | src = src[bs:] 59 | dst = dst[bs:] 60 | } 61 | return removePad(r) 62 | } 63 | 64 | func padData(d []byte, bs int) []byte { 65 | padedSize := ((len(d) / bs) + 1) * bs 66 | pad := padedSize - len(d) 67 | for i := len(d); i < padedSize; i++ { 68 | d = append(d, byte(pad)) 69 | } 70 | return d 71 | } 72 | 73 | func removePad(r []byte) ([]byte, error) { 74 | l := len(r) 75 | if l == 0 { 76 | return []byte{}, errors.New("input []byte is empty") 77 | } 78 | last := int(r[l-1]) 79 | pad := r[l-last : l] 80 | isPad := true 81 | for _, v := range pad { 82 | if int(v) != last { 83 | isPad = false 84 | break 85 | } 86 | } 87 | if !isPad { 88 | return r, errors.New("remove pad error") 89 | } 90 | return r[:l-last], nil 91 | } 92 | -------------------------------------------------------------------------------- /perm-server/sys-common/utils/aes.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "encoding/base64" 8 | "fmt" 9 | ) 10 | 11 | /** 12 | AES加密解密 13 | 使用CBC模式+PKCS7 填充方式实现AES的加密和解密 14 | */ 15 | const key = "ARRSWdczx13213EDDSWQ!!@W" 16 | 17 | // 校验密码 18 | func CheckPWD(password, enPassword string) bool { 19 | de := AESDecrypt(enPassword) 20 | if (password == de) { 21 | return true 22 | } 23 | return false 24 | } 25 | 26 | // ----------------------------------------------------------- 27 | // ----------------------- 解密 ------------------------------ 28 | // ----------------------------------------------------------- 29 | // 先base64转码,再解密 30 | func AESDecrypt(baseStr string) string { 31 | crypted, err := base64.StdEncoding.DecodeString(baseStr) 32 | if (err != nil) { 33 | fmt.Println("base64 encoding 错误") 34 | } 35 | 36 | block, _ := aes.NewCipher([]byte(key)) 37 | blockSize := block.BlockSize() 38 | blockMode := cipher.NewCBCDecrypter(block, []byte(key)[:blockSize]) 39 | originPWD := make([]byte, len(crypted)) 40 | blockMode.CryptBlocks(originPWD, crypted) 41 | originPWD = pkcs7_unPadding(originPWD) 42 | return string(originPWD) 43 | } 44 | 45 | // 补码 46 | func pkcs7_unPadding(origData []byte) []byte { 47 | length := len(origData) 48 | unpadding := int(origData[length-1]) 49 | return origData[:length-unpadding] 50 | } 51 | 52 | // ----------------------------------------------------------- 53 | // ----------------------- 加密 ------------------------------ 54 | // ----------------------------------------------------------- 55 | // 加密后再base64编码成string 56 | func AESEncrypt(originPWD []byte) string { 57 | //获取block块 58 | block, _ := aes.NewCipher([]byte(key)) 59 | //补码 60 | originPWD = pkcs7_padding(originPWD, block.BlockSize()) 61 | //加密模式, 62 | blockMode := cipher.NewCBCEncrypter(block, []byte(key)[:block.BlockSize()]) 63 | //创建明文长度的数组 64 | crypted := make([]byte, len(originPWD)) 65 | //加密明文 66 | blockMode.CryptBlocks(crypted, originPWD) 67 | 68 | return base64.StdEncoding.EncodeToString(crypted) 69 | } 70 | 71 | // 补码 72 | func pkcs7_padding(origData []byte, blockSize int) []byte { 73 | //计算需要补几位数 74 | padding := blockSize - len(origData)%blockSize 75 | //在切片后面追加char数量的byte(char) 76 | padtext := bytes.Repeat([]byte{byte(padding)}, padding) 77 | return append(origData, padtext...) 78 | } 79 | -------------------------------------------------------------------------------- /perm-vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-manage-system", 3 | "version": "3.2.0", 4 | "description": "基于Vue.js 2.x系列 + element-ui 内容管理系统解决方案", 5 | "author": "lin-xin <2981207131@qq.com>", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "build": "node build/build.js" 10 | }, 11 | "dependencies": { 12 | "jquery": "^3.1.1", 13 | "axios": "^0.15.3", 14 | "babel-polyfill": "^6.23.0", 15 | "element-ui": "^2.4.5", 16 | "js-md5": "^0.7.3", 17 | "mavon-editor": "^2.5.4", 18 | "vue": "^2.5.16", 19 | "vue-cropperjs": "^2.2.0", 20 | "vue-quill-editor": "3.0.6", 21 | "vue-router": "^3.0.1", 22 | "vue-schart": "^1.0.0", 23 | "vuedraggable": "^2.16.0" 24 | }, 25 | "devDependencies": { 26 | "autoprefixer": "^7.1.2", 27 | "babel-core": "^6.22.1", 28 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 29 | "babel-loader": "^7.1.1", 30 | "babel-plugin-syntax-jsx": "^6.18.0", 31 | "babel-plugin-transform-runtime": "^6.22.0", 32 | "babel-plugin-transform-vue-jsx": "^3.5.0", 33 | "babel-preset-env": "^1.3.2", 34 | "babel-preset-stage-2": "^6.22.0", 35 | "chalk": "^2.0.1", 36 | "copy-webpack-plugin": "^4.0.1", 37 | "css-loader": "^0.28.0", 38 | "extract-text-webpack-plugin": "^3.0.0", 39 | "file-loader": "^1.1.4", 40 | "friendly-errors-webpack-plugin": "^1.6.1", 41 | "html-webpack-plugin": "^2.30.1", 42 | "node-notifier": "^5.1.2", 43 | "optimize-css-assets-webpack-plugin": "^3.2.0", 44 | "ora": "^1.2.0", 45 | "portfinder": "^1.0.13", 46 | "postcss-import": "^11.0.0", 47 | "postcss-loader": "^2.0.8", 48 | "rimraf": "^2.6.0", 49 | "semver": "^5.3.0", 50 | "shelljs": "^0.7.6", 51 | "uglifyjs-webpack-plugin": "^1.1.1", 52 | "url-loader": "^0.5.8", 53 | "vue-loader": "^13.3.0", 54 | "vue-style-loader": "^3.0.1", 55 | "vue-template-compiler": "^2.5.2", 56 | "webpack": "^3.6.0", 57 | "webpack-bundle-analyzer": "^2.9.0", 58 | "webpack-dev-server": "^2.9.1", 59 | "node-sass": "^4.9.2", 60 | "sass-loader": "^7.0.3", 61 | "webpack-merge": "^4.1.0" 62 | }, 63 | "engines": { 64 | "node": ">= 4.0.0", 65 | "npm": ">= 3.0.0" 66 | }, 67 | "browserslist": [ 68 | "> 1%", 69 | "last 5 versions", 70 | "not ie <= 8" 71 | ] 72 | } 73 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/demo/Markdown.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 63 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/models/user/user_role.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/db" 5 | "permissionManage/perm-server/sys-common/utils" 6 | "time" 7 | ) 8 | 9 | // 用户-角色关联表 10 | type UserRole struct { 11 | Id string `xorm:"pk varchar(32) notnull unique" json:"id" form:"id"` 12 | CreateTime time.Time `json:"create_time" form:"create_time"` 13 | CreatorDepartmentId string `xorm:"varchar(50)" json:"creator_department_id" form:"creator_department_id"` 14 | CreatorDepartmentName string `xorm:"varchar(255)" json:"creator_department_name" form:"creator_department_name"` 15 | CreatorId string `xorm:"varchar(50)"json:"creator_id" form:"creator_id"` 16 | CreatorName string `xorm:"varchar(255)"json:"creator_name" form:"creator_name"` 17 | IsDeleted int64 `xorm:"INT(1) notnull" json:"isDeleted" form:"isDeleted"` 18 | UpdateTime time.Time `json:"update_time" form:"update_time"` 19 | UpdatorDepartmentId string `xorm:"varchar(50)" json:"updator_department_id" form:"updator_department_id"` 20 | UpdatorDepartmentName string `xorm:"varchar(255)" json:"updator_department_name" form:"updator_department_name"` 21 | UpdatorId string `xorm:"varchar(50)"json:"updator_id" form:"updator_id"` 22 | UpdatorName string `xorm:"varchar(255)"json:"updator_name" form:"updator_name"` 23 | Version int64 `xorm:"INT(11)" json:"version" form:"version"` 24 | 25 | UserId string `xorm:"varchar(50) notnull" json:"user_id"` 26 | RoleId string `xorm:"varchar(50) notnull" json:"role_id"` 27 | } 28 | 29 | func (UserRole) TableName() string { 30 | return "cd_sys_user_user_role" 31 | } 32 | 33 | //========================= 新增用户角色 ============================ 34 | func CreateRelationUserRole(userRoles ...*UserRole) (int64, error) { 35 | e := db.MasterEngine() 36 | var userRolEntitys []UserRole 37 | for _, ur := range userRoles { 38 | // 生成uuid 39 | ur.Id = utils.GetUuid() 40 | ur.CreateTime = time.Now() 41 | ur.Version = 0 42 | ur.IsDeleted = 0 43 | 44 | userRolEntitys = append(userRolEntitys, *ur) 45 | } 46 | return e.Insert(userRolEntitys) 47 | } 48 | 49 | //========================= 物理删除 ============================ 50 | func RemoveUserRole(userId string, roleIds []string) (effect int64, err error) { 51 | e := db.MasterEngine() 52 | 53 | ur := new(UserRole) 54 | effect, err = e.Where("user_id = ?", userId).In("role_id", roleIds).Delete(ur) 55 | return 56 | } 57 | -------------------------------------------------------------------------------- /perm-vue/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App'; 3 | import router from './router'; 4 | import axios from 'axios'; 5 | import ElementUI from 'element-ui'; 6 | import './assets/reset.css'; 7 | import 'element-ui/lib/theme-chalk/index.css'; // 默认主题 8 | // import '../static/css/theme-green/index.css'; // 浅绿色主题 9 | import 'jquery'; 10 | import '../static/css/icon.css'; 11 | import "babel-polyfill"; 12 | import md5 from 'js-md5'; 13 | import Common from './assets/util'; 14 | import common from './assets/common.js'; 15 | 16 | import {fmtToken} from './utils/utils' 17 | 18 | Vue.use(ElementUI, {size: 'small'}); 19 | Vue.prototype.$axios = axios; 20 | Vue.config.productionTip = false; 21 | Vue.prototype.$md5 = md5; 22 | Vue.prototype.Common = Common; 23 | Vue.prototype.$Common = common; 24 | 25 | axios.interceptors.request.use(request => { 26 | request.headers.Authorization = fmtToken(); 27 | let type = axios.defaults.headers['urlencoded']; 28 | let requestData = []; 29 | //上传 30 | if (type > -1) { 31 | request.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; 32 | let _data = ''; 33 | if (request.data) { 34 | for (let key in request.data) { 35 | requestData.push(request.data[key]); 36 | _data += `${key}=${request.data[key]}`; 37 | Object.keys(request.data).pop() !== key && (_data += '&'); 38 | } 39 | request.data = _data; 40 | } 41 | return request; 42 | } else { 43 | request.headers['Content-Type'] = 'application/json;charset=UTF-8'; 44 | if (request.method != 'get') { 45 | } 46 | return request; 47 | } 48 | }); 49 | 50 | //使用钩子函数对路由进行权限跳转 51 | router.beforeEach((to, from, next) => { 52 | const role = localStorage.getItem('ms_username'); 53 | if (!role && to.path !== '/login') { 54 | next('/login'); 55 | } else if (to.meta.permission) { 56 | // 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已 57 | role === 'admin' ? next() : next('/403'); 58 | } else { 59 | // 简单的判断IE10及以下不进入富文本编辑器,该组件不兼容 60 | if (navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor') { 61 | Vue.prototype.$alert('vue-quill-editor组件不兼容IE10及以下浏览器,请使用更高版本的浏览器查看', '浏览器不兼容通知', { 62 | confirmButtonText: '确定' 63 | }); 64 | } else { 65 | next(); 66 | } 67 | } 68 | }); 69 | 70 | new Vue({ 71 | router, 72 | render: h => h(App) 73 | }).$mount('#app'); -------------------------------------------------------------------------------- /perm-server/sys-common/db/db.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "fmt" 5 | "permissionManage/perm-server/sys-common/inits/parse" 6 | "permissionManage/perm-server/sys-common/utils" 7 | "sync" 8 | 9 | "github.com/kataras/golog" 10 | "xorm.io/core" 11 | 12 | _ "github.com/go-sql-driver/mysql" 13 | "github.com/go-xorm/xorm" 14 | ) 15 | 16 | var ( 17 | masterEngine *xorm.Engine 18 | slaveEngine *xorm.Engine 19 | lock sync.Mutex 20 | ) 21 | 22 | // 主库,单例 23 | func MasterEngine() *xorm.Engine { 24 | if masterEngine != nil { 25 | return masterEngine 26 | } 27 | 28 | lock.Lock() 29 | defer lock.Unlock() 30 | 31 | if masterEngine != nil { 32 | return masterEngine 33 | } 34 | 35 | master := parse.DBConfig.Master 36 | engine, err := xorm.NewEngine(master.Dialect, GetConnURL(&master)) 37 | if err != nil { 38 | golog.Fatalf("@@@ Instance Master DB error!! %s", err) 39 | return nil 40 | } 41 | settings(engine, &master) 42 | engine.SetMapper(core.GonicMapper{}) 43 | 44 | masterEngine = engine 45 | return masterEngine 46 | } 47 | 48 | // 从库,单例 49 | func SlaveEngine() *xorm.Engine { 50 | if slaveEngine != nil { 51 | return slaveEngine 52 | } 53 | 54 | lock.Lock() 55 | defer lock.Unlock() 56 | 57 | if slaveEngine != nil { 58 | return slaveEngine 59 | } 60 | 61 | slave := parse.DBConfig.Slave 62 | engine, err := xorm.NewEngine(slave.Dialect, GetConnURL(&slave)) 63 | if err != nil { 64 | golog.Fatalf("@@@ Instance Slave DB error!! %s", err) 65 | return nil 66 | } 67 | settings(engine, &slave) 68 | 69 | slaveEngine = engine 70 | return engine 71 | } 72 | 73 | // 74 | func settings(engine *xorm.Engine, info *parse.DBConfigInfo) { 75 | engine.ShowSQL(info.ShowSql) 76 | engine.SetTZLocation(utils.SysTimeLocation) 77 | if info.MaxIdleConns > 0 { 78 | engine.SetMaxIdleConns(info.MaxIdleConns) 79 | } 80 | if info.MaxOpenConns > 0 { 81 | engine.SetMaxOpenConns(info.MaxOpenConns) 82 | } 83 | 84 | // 性能优化的时候才考虑,加上本机的SQL缓存 85 | //cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000) 86 | //engine.SetDefaultCacher(cacher) 87 | } 88 | 89 | // 获取数据库连接的url 90 | // true:master主库 91 | func GetConnURL(info *parse.DBConfigInfo) (url string) { 92 | //db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local") 93 | url = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s", 94 | info.User, 95 | info.Password, 96 | info.Host, 97 | info.Port, 98 | info.Database, 99 | info.Charset) 100 | //golog.Infof("@@@ DB conn==>> %s", url) 101 | return 102 | } 103 | -------------------------------------------------------------------------------- /perm-vue/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | const webpack = require('webpack') 7 | 8 | function resolve (dir) { 9 | return path.join(__dirname, '..', dir) 10 | } 11 | 12 | 13 | 14 | module.exports = { 15 | context: path.resolve(__dirname, '../'), 16 | entry: { 17 | app: './src/main.js' 18 | }, 19 | output: { 20 | path: config.build.assetsRoot, 21 | filename: '[name].js', 22 | publicPath: process.env.NODE_ENV === 'production' 23 | ? config.build.assetsPublicPath 24 | : config.dev.assetsPublicPath 25 | }, 26 | resolve: { 27 | extensions: ['*','.js', '.vue', '.json','.scss'], 28 | alias: { 29 | 'vue$': 'vue/dist/vue.esm.js', 30 | '@': resolve('src'), 31 | 'static': path.resolve(__dirname, '../static'), 32 | } 33 | }, 34 | plugins: [ 35 | new webpack.ProvidePlugin({ 36 | $: "jquery", 37 | jQuery: "jquery", 38 | jquery: "jquery", 39 | "window.jQuery": "jquery" 40 | }) 41 | ], 42 | module: { 43 | rules: [ 44 | { 45 | test: /\.vue$/, 46 | loader: 'vue-loader', 47 | options: vueLoaderConfig 48 | }, 49 | { 50 | test: /\.js$/, 51 | loader: 'babel-loader', 52 | include: [resolve('src'), resolve('test')] 53 | }, 54 | { 55 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 56 | loader: 'url-loader', 57 | options: { 58 | limit: 10000, 59 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 60 | } 61 | }, 62 | { 63 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 64 | loader: 'url-loader', 65 | options: { 66 | limit: 10000, 67 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 68 | } 69 | }, 70 | { 71 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 72 | loader: 'url-loader', 73 | options: { 74 | limit: 10000, 75 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 76 | } 77 | } 78 | ] 79 | }, 80 | node: { 81 | // prevent webpack from injecting useless setImmediate polyfill because Vue 82 | // source contains it (although only uses it if it's native). 83 | setImmediate: false, 84 | // prevent webpack from injecting mocks to Node native modules 85 | // that does not make sense for the client 86 | dgram: 'empty', 87 | fs: 'empty', 88 | net: 'empty', 89 | tls: 'empty', 90 | child_process: 'empty' 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/routes/hub.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/middleware" 5 | "permissionManage/perm-server/sys-common/supports" 6 | 7 | conf "permissionManage/perm-server/sys-common/inits/parse" 8 | 9 | "github.com/iris-contrib/middleware/cors" 10 | "github.com/kataras/iris/v12" 11 | "github.com/kataras/iris/v12/context" 12 | "github.com/kataras/iris/v12/middleware/logger" 13 | rcover "github.com/kataras/iris/v12/middleware/recover" 14 | "permissionManage/perm-server/sys-sysbase/routes/user" 15 | ) 16 | 17 | // 所有的路由 18 | func Hub(app *iris.Application) { 19 | preSettring(app) 20 | var main = corsSetting(app) 21 | 22 | // 用户模块路由 23 | user.UserHub(main) // 用户API模块 24 | user.ResoureHub(main) // 菜单资源 25 | user.RoleHub(main) // 角色 26 | user.DepartmentHub(main) // 部门 27 | } 28 | 29 | func corsSetting(app *iris.Application) (main iris.Party) { 30 | var ( 31 | crs context.Handler 32 | ) 33 | 34 | crs = cors.New(cors.Options{ 35 | AllowedOrigins: []string{"*"}, //允许通过的主机名称 36 | AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, 37 | AllowedHeaders: []string{"*"}, 38 | Debug: true, 39 | //AllowCredentials: true, 40 | }) 41 | 42 | /* 定义路由 */ 43 | main = app.Party("/perm", crs).AllowMethods(iris.MethodOptions) 44 | main.Use(middleware.ServeHTTP) 45 | //main := app.Party("/") 46 | //main.Use(middleware.ServeHTTP) 47 | 48 | return main 49 | } 50 | 51 | func preSettring(app *iris.Application) { 52 | app.Logger().SetLevel(conf.O.LogLevel) 53 | 54 | customLogger := logger.New(logger.Config{ 55 | //状态显示状态代码 56 | Status: true, 57 | // IP显示请求的远程地址 58 | IP: true, 59 | //方法显示http方法 60 | Method: true, 61 | // Path显示请求路径 62 | Path: true, 63 | // Query将url查询附加到Path。 64 | Query: true, 65 | //Columns:true, 66 | // 如果不为空然后它的内容来自`ctx.Values(),Get("logger_message") 67 | //将添加到日志中。 68 | MessageContextKeys: []string{"logger_message"}, 69 | //如果不为空然后它的内容来自`ctx.GetHeader(“User-Agent”) 70 | MessageHeaderKeys: []string{"User-Agent"}, 71 | }) 72 | app.Use( 73 | rcover.New(), 74 | customLogger, 75 | //middleware.ServeHTTP 76 | ) 77 | 78 | // ---------------------- 定义错误处理 ------------------------ 79 | app.OnErrorCode(iris.StatusNotFound, customLogger, func(ctx iris.Context) { 80 | supports.Error(ctx, iris.StatusNotFound, supports.NotFound, nil) 81 | }) 82 | //app.OnErrorCode(iris.StatusForbidden, customLogger, func(ctx iris.Context) { 83 | // ctx.JSON(utils.Error(iris.StatusForbidden, "权限不足", nil)) 84 | //}) 85 | //捕获所有http错误: 86 | //app.OnAnyErrorCode(customLogger, func(ctx iris.Context) { 87 | // //这应该被添加到日志中,因为`logger.Config#MessageContextKey` 88 | // ctx.Values().Set("logger_message", "a dynamic message passed to the logs") 89 | // ctx.JSON(utils.Error(500, "服务器内部错误", nil)) 90 | //}) 91 | } 92 | -------------------------------------------------------------------------------- /perm-vue/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const baseWebpackConfig = require('./webpack.base.conf') 7 | const HtmlWebpackPlugin = require('html-webpack-plugin') 8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 9 | const portfinder = require('portfinder') 10 | 11 | const HOST = process.env.HOST 12 | const PORT = process.env.PORT && Number(process.env.PORT) 13 | 14 | const devWebpackConfig = merge(baseWebpackConfig, { 15 | module: { 16 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) 17 | }, 18 | // cheap-module-eval-source-map is faster for development 19 | devtool: config.dev.devtool, 20 | 21 | // these devServer options should be customized in /config/index.js 22 | devServer: { 23 | clientLogLevel: 'warning', 24 | historyApiFallback: true, 25 | hot: true, 26 | compress: true, 27 | host: HOST || config.dev.host, 28 | port: PORT || config.dev.port, 29 | open: config.dev.autoOpenBrowser, 30 | overlay: config.dev.errorOverlay 31 | ? { warnings: false, errors: true } 32 | : false, 33 | publicPath: config.dev.assetsPublicPath, 34 | proxy: config.dev.proxyTable, 35 | quiet: true, // necessary for FriendlyErrorsPlugin 36 | watchOptions: { 37 | poll: config.dev.poll, 38 | } 39 | }, 40 | plugins: [ 41 | new webpack.DefinePlugin({ 42 | 'process.env': require('../config/dev.env') 43 | }), 44 | new webpack.HotModuleReplacementPlugin(), 45 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 46 | new webpack.NoEmitOnErrorsPlugin(), 47 | // https://github.com/ampedandwired/html-webpack-plugin 48 | new HtmlWebpackPlugin({ 49 | filename: 'index.html', 50 | template: 'index.html', 51 | inject: true 52 | }), 53 | ] 54 | }) 55 | 56 | module.exports = new Promise((resolve, reject) => { 57 | portfinder.basePort = process.env.PORT || config.dev.port 58 | portfinder.getPort((err, port) => { 59 | if (err) { 60 | reject(err) 61 | } else { 62 | // publish the new Port, necessary for e2e tests 63 | process.env.PORT = port 64 | // add port to devServer config 65 | devWebpackConfig.devServer.port = port 66 | 67 | // Add FriendlyErrorsPlugin 68 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 69 | compilationSuccessInfo: { 70 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], 71 | }, 72 | onErrors: config.dev.notifyOnErrors 73 | ? utils.createNotifierCallback() 74 | : undefined 75 | })) 76 | 77 | resolve(devWebpackConfig) 78 | } 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /perm-vue/build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const packageConfig = require('../package.json') 6 | 7 | exports.assetsPath = function (_path) { 8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 9 | ? config.build.assetsSubDirectory 10 | : config.dev.assetsSubDirectory 11 | 12 | return path.posix.join(assetsSubDirectory, _path) 13 | } 14 | 15 | exports.cssLoaders = function (options) { 16 | options = options || {} 17 | 18 | const cssLoader = { 19 | loader: 'css-loader', 20 | options: { 21 | sourceMap: options.sourceMap 22 | } 23 | } 24 | 25 | const postcssLoader = { 26 | loader: 'postcss-loader', 27 | options: { 28 | sourceMap: options.sourceMap 29 | } 30 | } 31 | 32 | // generate loader string to be used with extract text plugin 33 | function generateLoaders (loader, loaderOptions) { 34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 35 | 36 | if (loader) { 37 | loaders.push({ 38 | loader: loader + '-loader', 39 | options: Object.assign({}, loaderOptions, { 40 | sourceMap: options.sourceMap 41 | }) 42 | }) 43 | } 44 | 45 | // Extract CSS when that option is specified 46 | // (which is the case during production build) 47 | if (options.extract) { 48 | return ExtractTextPlugin.extract({ 49 | use: loaders, 50 | fallback: 'vue-style-loader', 51 | publicPath: 'permissionManage/perm-server/' 52 | }) 53 | } else { 54 | return ['vue-style-loader'].concat(loaders) 55 | } 56 | } 57 | 58 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 59 | return { 60 | css: generateLoaders(), 61 | postcss: generateLoaders(), 62 | less: generateLoaders('less'), 63 | sass: generateLoaders('sass', { indentedSyntax: true }), 64 | scss: generateLoaders('sass'), 65 | stylus: generateLoaders('stylus'), 66 | styl: generateLoaders('stylus') 67 | } 68 | } 69 | 70 | // Generate loaders for standalone style files (outside of .vue) 71 | exports.styleLoaders = function (options) { 72 | const output = [] 73 | const loaders = exports.cssLoaders(options) 74 | 75 | for (const extension in loaders) { 76 | const loader = loaders[extension] 77 | output.push({ 78 | test: new RegExp('\\.' + extension + '$'), 79 | use: loader 80 | }) 81 | } 82 | 83 | return output 84 | } 85 | 86 | exports.createNotifierCallback = () => { 87 | const notifier = require('node-notifier') 88 | 89 | return (severity, errors) => { 90 | if (severity !== 'error') return 91 | 92 | const error = errors[0] 93 | const filename = error.file && error.file.split('!').pop() 94 | 95 | notifier.notify({ 96 | title: packageConfig.name, 97 | message: severity + ': ' + error.name, 98 | subtitle: filename || '', 99 | icon: path.join(__dirname, 'logo.png') 100 | }) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /perm-vue/static/css/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | html, 7 | body, 8 | #app, 9 | .wrapper { 10 | width: 100%; 11 | height: 100%; 12 | overflow: hidden; 13 | } 14 | 15 | body { 16 | font-family: 'PingFang SC', "Helvetica Neue", Helvetica, "microsoft yahei", arial, STHeiTi, sans-serif; 17 | } 18 | 19 | a { 20 | text-decoration: none 21 | } 22 | 23 | 24 | .content-box { 25 | position: absolute; 26 | left: 220px; 27 | right: 0; 28 | top: 70px; 29 | bottom: 0; 30 | padding-bottom: 30px; 31 | -webkit-transition: left .3s ease-in-out; 32 | transition: left .3s ease-in-out; 33 | background: #f0f0f0; 34 | } 35 | 36 | .content { 37 | width: auto; 38 | height: 100%; 39 | padding: 10px; 40 | overflow-y: scroll; 41 | box-sizing: border-box; 42 | } 43 | 44 | .content-collapse { 45 | left: 65px; 46 | } 47 | 48 | .container { 49 | padding: 30px; 50 | background: #fff; 51 | border: 1px solid #ddd; 52 | border-radius: 5px; 53 | } 54 | 55 | .crumbs { 56 | margin: 10px 0; 57 | } 58 | 59 | .pagination { 60 | margin: 20px 0; 61 | text-align: right; 62 | } 63 | 64 | .plugins-tips { 65 | padding: 20px 10px; 66 | margin-bottom: 20px; 67 | } 68 | 69 | .el-button+.el-tooltip { 70 | margin-left: 10px; 71 | } 72 | 73 | .el-table tr:hover { 74 | background: #f6faff; 75 | } 76 | 77 | .mgb20 { 78 | margin-bottom: 20px; 79 | } 80 | 81 | .move-enter-active, 82 | .move-leave-active { 83 | transition: opacity .5s; 84 | } 85 | 86 | .move-enter, 87 | .move-leave { 88 | opacity: 0; 89 | } 90 | 91 | /*BaseForm*/ 92 | 93 | .form-box { 94 | width: 600px; 95 | } 96 | 97 | .form-box .line { 98 | text-align: center; 99 | } 100 | 101 | .el-time-panel__content::after, 102 | .el-time-panel__content::before { 103 | margin-top: -7px; 104 | } 105 | 106 | .el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default) { 107 | padding-bottom: 0; 108 | } 109 | 110 | /*Upload*/ 111 | 112 | .pure-button { 113 | width: 150px; 114 | height: 40px; 115 | line-height: 40px; 116 | text-align: center; 117 | color: #fff; 118 | border-radius: 3px; 119 | } 120 | 121 | .g-core-image-corp-container .info-aside { 122 | height: 45px; 123 | } 124 | 125 | .el-upload--text { 126 | background-color: #fff; 127 | border: 1px dashed #d9d9d9; 128 | border-radius: 6px; 129 | box-sizing: border-box; 130 | width: 360px; 131 | height: 180px; 132 | text-align: center; 133 | cursor: pointer; 134 | position: relative; 135 | overflow: hidden; 136 | } 137 | 138 | .el-upload--text .el-icon-upload { 139 | font-size: 67px; 140 | color: #97a8be; 141 | margin: 40px 0 16px; 142 | line-height: 50px; 143 | } 144 | 145 | .el-upload--text { 146 | color: #97a8be; 147 | font-size: 14px; 148 | text-align: center; 149 | } 150 | 151 | .el-upload--text em { 152 | font-style: normal; 153 | } 154 | 155 | /*VueEditor*/ 156 | 157 | .ql-container { 158 | min-height: 400px; 159 | } 160 | 161 | .ql-snow .ql-tooltip { 162 | transform: translateX(117.5px) translateY(10px) !important; 163 | } 164 | 165 | .editor-btn { 166 | margin-top: 20px; 167 | } 168 | 169 | /*markdown*/ 170 | 171 | .v-note-wrapper .v-note-panel { 172 | min-height: 500px; 173 | } 174 | -------------------------------------------------------------------------------- /perm-server/sys-common/models/baseModel/baseModel.go: -------------------------------------------------------------------------------- 1 | package baseModel 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/caches" 5 | "permissionManage/perm-server/sys-common/db" 6 | "permissionManage/perm-server/sys-common/utils" 7 | "time" 8 | ) 9 | 10 | // table cd_sys_user_user 11 | type BaseModel struct { 12 | Id string `json:"id" form:"id"` 13 | CreateTime time.Time `json:"create_time" form:"create_time"` 14 | CreatorDepartmentId string `json:"creator_department_id" form:"creator_department_id"` 15 | CreatorDepartmentName string `json:"creator_department_name" form:"creator_department_name"` 16 | CreatorId string `json:"creator_id" form:"creator_id"` 17 | CreatorName string `json:"creator_name" form:"creator_name"` 18 | IsDeleted int64 `json:"isDeleted" form:"isDeleted"` 19 | UpdateTime time.Time `json:"update_time" form:"update_time"` 20 | UpdaterDepartmentId string `json:"updater_department_id" form:"updater_department_id"` 21 | UpdaterDepartmentName string `json:"updater_department_name" form:"updater_department_name"` 22 | UpdaterId string `json:"updater_id" form:"updater_id"` 23 | UpdaterName string `json:"updater_name" form:"updater_name"` 24 | Version int64 `json:"version" form:"version"` 25 | } 26 | 27 | type CurrentUser struct { 28 | UserId string `json:"userId"` 29 | UserAccount string `json:"userAccount"` 30 | UserName string `json:"userName"` 31 | DepartmentId string `json:"departmentId"` 32 | DepartmentName string `json:"departmentName"` 33 | Roles string `json:"roles"` 34 | Resource string `json:"resource"` 35 | } 36 | 37 | func GetCreateBaseModel(currentUser *CurrentUser) (baseModel *BaseModel) { 38 | baseModel.Id = utils.GetUuid() 39 | baseModel.CreateTime = time.Now() 40 | baseModel.CreatorId = currentUser.UserAccount 41 | baseModel.CreatorName = currentUser.UserName 42 | baseModel.CreatorDepartmentId = currentUser.DepartmentId 43 | baseModel.CreatorDepartmentName = currentUser.DepartmentName 44 | baseModel.IsDeleted = 0 45 | 46 | return baseModel 47 | } 48 | 49 | func InitCurrentUserByUserAccount(userAccount string) (res *CurrentUser, err error) { 50 | e := db.MasterEngine() 51 | 52 | sql := "SELECT " + 53 | " u.id AS userId, " + 54 | " u.user_account AS userAccount, " + 55 | " u.user_name AS userName, " + 56 | " u.department_id AS departmentId, " + 57 | " ud.dep_name AS departmentName " + 58 | " FROM cd_sys_user_user u " + 59 | " LEFT JOIN cd_sys_user_department ud ON u.department_id = ud.id " + 60 | " WHERE u.is_deleted = FALSE " + 61 | " AND u.user_account = '" + userAccount + "'" 62 | s := e.SQL(sql) 63 | queryResult, err := s.QueryString(sql) 64 | if err != nil || len(queryResult) == 0 { 65 | return 66 | } 67 | 68 | res = new(CurrentUser) 69 | res.UserId = queryResult[0]["userId"] 70 | res.UserName = queryResult[0]["userName"] 71 | res.UserAccount = queryResult[0]["userAccount"] 72 | res.DepartmentId = queryResult[0]["departmentId"] 73 | res.DepartmentName = queryResult[0]["departmentName"] 74 | 75 | return 76 | } 77 | 78 | func GetCurrentUset(userId string) *CurrentUser { 79 | curr := new(CurrentUser) 80 | currByt, err := caches.GetJsonByte("currentUser_" + userId) 81 | if err != nil { 82 | err.Error() 83 | } 84 | res := utils.ByteToStruct(currByt, curr) 85 | return res.(*CurrentUser) 86 | } 87 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/vo/uservo/role_vo.go: -------------------------------------------------------------------------------- 1 | package uservo 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/models/baseModel" 5 | "permissionManage/perm-server/sys-common/vo" 6 | "permissionManage/perm-server/sys-sysbase/models/user" 7 | ) 8 | 9 | // 前端需要的数据结构 10 | type RoleVO struct { 11 | Id string `json:"id"` 12 | PType string `json:"pType"` 13 | RoleType string `json:"roleType" form:"roleType"` 14 | RoleName string `json:"roleName" form:"roleName"` 15 | RoleCode string `json:"roleCode" form:"roleCode"` 16 | Description string `json:"description" form:"description"` 17 | 18 | Token string `json:"token"` 19 | } 20 | 21 | // 请求参数 22 | type RoleParamVo struct { 23 | *baseModel.CurrentUser 24 | baseModel.BaseModel 25 | *vo.PageVo 26 | Id string `json:"id"` 27 | PType string `json:"pType"` 28 | RoleType string `json:"roleType" form:"roleType"` 29 | RoleName string `json:"roleName" form:"roleName"` 30 | RoleCode string `json:"roleCode" form:"roleCode"` 31 | Description string `json:"description" form:"description"` 32 | Token string `json:"token"` 33 | 34 | ResourceType string `json:"resourceType"` 35 | Ids string `json:"ids"` //批量删除入参 36 | UserId string `json:"userId"` //用户id 37 | } 38 | 39 | // 列表数据结构 40 | type RoleListVo struct { 41 | Id string `json:"id"` 42 | PType string `json:"pType"` 43 | RoleType string `json:"roleType" form:"roleType"` 44 | RoleName string `json:"roleName" form:"roleName"` 45 | RoleCode string `json:"roleCode" form:"roleCode"` 46 | Description string `json:"description" form:"description"` 47 | } 48 | 49 | func RoleParamVoToRole(paramVo *RoleParamVo) (result *user.Role) { 50 | currentUser := paramVo.CurrentUser 51 | if paramVo.Id != "" { 52 | result = user.FindRoleById(paramVo.Id) 53 | result.UpdatorId = currentUser.UserAccount 54 | result.UpdatorName = currentUser.UserName 55 | result.UpdatorDepartmentId = currentUser.DepartmentId 56 | result.UpdatorDepartmentName = currentUser.DepartmentName 57 | } else { 58 | result = new(user.Role) 59 | result.CreatorId = currentUser.UserAccount 60 | result.CreatorName = currentUser.UserName 61 | result.CreatorDepartmentId = currentUser.DepartmentId 62 | result.CreatorDepartmentName = currentUser.DepartmentName 63 | } 64 | 65 | result.PType = paramVo.PType 66 | result.RoleType = "p" 67 | result.RoleName = paramVo.RoleName 68 | result.RoleCode = paramVo.RoleCode 69 | result.Description = paramVo.Description 70 | return 71 | } 72 | 73 | func RoleToRoleLListVo(rl *user.Role) (rlvo *RoleListVo) { 74 | rlvo = new(RoleListVo) 75 | rlvo.Id = rl.Id 76 | rlvo.PType = rl.PType 77 | rlvo.RoleType = rl.RoleType 78 | rlvo.RoleName = rl.RoleName 79 | rlvo.RoleCode = rl.RoleCode 80 | rlvo.Description = rl.Description 81 | return 82 | } 83 | 84 | func RoleToRoleListVos(rls []*user.Role) (rlvos []*RoleListVo) { 85 | for _, r := range rls { 86 | rtVo := RoleToRoleLListVo(r) 87 | rlvos = append(rlvos, rtVo) 88 | } 89 | return 90 | } 91 | 92 | func RoleToRoleVo(param *user.Role) (result *RoleListVo) { 93 | result = new(RoleListVo) 94 | result.Id = param.Id 95 | result.PType = param.PType 96 | result.RoleType = param.RoleType 97 | result.RoleName = param.RoleName 98 | result.RoleCode = param.RoleCode 99 | result.Description = param.Description 100 | return 101 | } 102 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/models/user/role.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/db" 5 | "permissionManage/perm-server/sys-common/utils" 6 | "time" 7 | ) 8 | 9 | // table cd_sys_user_role 10 | type Role struct { 11 | Id string `xorm:"pk varchar(32) notnull unique 'id'"` 12 | CreateTime time.Time `xorm:"'create_time'"` 13 | CreatorDepartmentId string `xorm:"varchar(50) 'creator_department_id'"` 14 | CreatorDepartmentName string `xorm:"varchar(255) 'creator_department_name'"` 15 | CreatorId string `xorm:"varchar(50) 'creator_id'"` 16 | CreatorName string `xorm:"varchar(255) 'creator_name'"` 17 | IsDeleted int64 `xorm:"INT(1) notnull 'is_deleted'"` 18 | UpdateTime time.Time `xorm:"'update_time'"` 19 | UpdatorDepartmentId string `xorm:"varchar(50) 'updator_department_id'"` 20 | UpdatorDepartmentName string `xorm:"varchar(255) 'updator_department_name'"` 21 | UpdatorId string `xorm:"varchar(50) 'updator_id'"` 22 | UpdatorName string `xorm:"varchar(255) 'updator_name'"` 23 | Version int64 `xorm:"INT(11) 'version'"` 24 | 25 | PType string `xorm:"varchar(100) index 'p_type'"` 26 | RoleType string `xorm:"varchar(50) 'role_type'"` 27 | RoleName string `xorm:"varchar(100) 'role_name'"` 28 | RoleCode string `xorm:"varchar(20) 'role_code'"` 29 | Description string `xorm:"varchar(255) 'description'"` 30 | } 31 | 32 | func (Role) TableName() string { 33 | return "cd_sys_user_role" 34 | } 35 | 36 | //========================= 新增 ============================ 37 | func CreateRole(roles ...*Role) (int64, error) { 38 | e := db.MasterEngine() 39 | var roleEntitys []Role 40 | for _, r := range roles { 41 | // 生成uuid 42 | r.Id = utils.GetUuid() 43 | r.CreateTime = time.Now() 44 | r.Version = 0 45 | r.IsDeleted = 0 46 | 47 | roleEntitys = append(roleEntitys, *r) 48 | } 49 | return e.Insert(roleEntitys) 50 | } 51 | 52 | //========================= 更新 ============================ 53 | func UpdateRole(role *Role) (int64, error) { 54 | e := db.MasterEngine() 55 | role.UpdateTime = time.Now() 56 | role.Version = role.Version + 1 57 | aff, err := e.Id(role.Id).Update(role) 58 | if err != nil { 59 | err.Error() 60 | } 61 | return aff, err 62 | } 63 | 64 | //========================= 逻辑删除 ============================ 65 | func DeleteRoleByIds(ids []string) (effect int64, err error) { 66 | e := db.MasterEngine() 67 | for _, id := range ids { 68 | role := FindRoleById(id) 69 | if role != nil { 70 | role.IsDeleted = 1 71 | _, err := e.Id(id).Update(role) 72 | if err != nil { 73 | err.Error() 74 | } 75 | } 76 | } 77 | return 78 | } 79 | 80 | //========================= 物理删除 ============================ 81 | func RemoveRoleByIds(ids []int64) (effect int64, err error) { 82 | e := db.MasterEngine() 83 | 84 | cr := new(Role) 85 | for _, v := range ids { 86 | i, err1 := e.Id(v).Delete(cr) 87 | effect += i 88 | err = err1 89 | } 90 | return 91 | } 92 | 93 | //========================= 查询 ============================ 94 | // 根据id查询 95 | func FindRoleById(id string) (role *Role) { 96 | role = new(Role) 97 | e := db.MasterEngine() 98 | _, err := e.Id(id).Get(role) 99 | if err != nil { 100 | err.Error() 101 | return 102 | } 103 | 104 | return 105 | } 106 | -------------------------------------------------------------------------------- /perm-server/sys-common/caches/redis.go: -------------------------------------------------------------------------------- 1 | package caches 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "github.com/garyburd/redigo/redis" 8 | "github.com/pelletier/go-toml" 9 | "permissionManage/perm-server/sys-common/conf" 10 | "time" 11 | ) 12 | 13 | // NewRedisPool 返回redis连接池 14 | func NewRedisPool() *redis.Pool { 15 | configTree := conf.Conf.Get("redis").(*toml.Tree) 16 | var ( 17 | redisURL = "redis://" + configTree.Get("Addr").(string) 18 | redisMaxIdle = int(configTree.Get("RedisMaxIdle").(int64)) //最大空闲连接数 19 | redisIdleTimeoutSec = int64(configTree.Get("RedisIdleTimeoutSec").(int64)) 20 | redisPassword = configTree.Get("Password").(string) 21 | dB = int(configTree.Get("DB").(int64)) 22 | ) 23 | return &redis.Pool{ 24 | MaxIdle: redisMaxIdle, 25 | //IdleTimeout: redisIdleTimeoutSec * time.Second, 26 | Dial: func() (redis.Conn, error) { 27 | redis.DialConnectTimeout(time.Duration(redisIdleTimeoutSec)) 28 | redis.DialDatabase(dB) 29 | c, err := redis.DialURL(redisURL) 30 | if err != nil { 31 | return nil, fmt.Errorf("redis connection error: %s", err) 32 | } 33 | //验证redis密码 34 | if _, authErr := c.Do("AUTH", redisPassword); authErr != nil { 35 | return nil, fmt.Errorf("redis auth password error: %s", authErr) 36 | } 37 | return c, err 38 | }, 39 | TestOnBorrow: func(c redis.Conn, t time.Time) error { 40 | _, err := c.Do("PING") 41 | if err != nil { 42 | return fmt.Errorf("ping redis error: %s", err) 43 | } 44 | return nil 45 | }, 46 | } 47 | } 48 | 49 | func Set(k, v string) { 50 | c := NewRedisPool().Get() 51 | defer c.Close() 52 | _, err := c.Do("SET", k, v) 53 | if err != nil { 54 | fmt.Println("set error", err.Error()) 55 | } 56 | } 57 | func SetKVExpire(k, v string, ex int) { 58 | c := NewRedisPool().Get() 59 | defer c.Close() 60 | _, err := c.Do("EXPIRE", k, v, ex) 61 | if err != nil { 62 | fmt.Println("set error", err.Error()) 63 | } 64 | } 65 | 66 | func GetStringValue(k string) string { 67 | c := NewRedisPool().Get() 68 | defer c.Close() 69 | username, err := redis.String(c.Do("GET", k)) 70 | if err != nil { 71 | fmt.Println("Get Error: ", err.Error()) 72 | return "" 73 | } 74 | return username 75 | } 76 | 77 | func SetKeyExpire(k string, ex int) { 78 | c := NewRedisPool().Get() 79 | defer c.Close() 80 | _, err := c.Do("EXPIRE", k, ex) 81 | if err != nil { 82 | fmt.Println("set error", err.Error()) 83 | } 84 | } 85 | 86 | func CheckKey(k string) bool { 87 | c := NewRedisPool().Get() 88 | defer c.Close() 89 | exist, err := redis.Bool(c.Do("EXISTS", k)) 90 | if err != nil { 91 | fmt.Println(err) 92 | return false 93 | } else { 94 | return exist 95 | } 96 | } 97 | 98 | func DelKey(k string) error { 99 | c := NewRedisPool().Get() 100 | defer c.Close() 101 | _, err := c.Do("DEL", k) 102 | if err != nil { 103 | fmt.Println(err) 104 | return err 105 | } 106 | return nil 107 | } 108 | 109 | func SetJson(k string, data interface{}) error { 110 | c := NewRedisPool().Get() 111 | defer c.Close() 112 | value, _ := json.Marshal(data) 113 | n, _ := c.Do("SETNX", k, value) 114 | if n != int64(1) { 115 | return errors.New("set failed") 116 | } 117 | return nil 118 | } 119 | 120 | func GetJsonByte(k string) ([]byte, error) { 121 | c := NewRedisPool().Get() 122 | jsonGet, err := redis.Bytes(c.Do("GET", k)) 123 | if err != nil { 124 | fmt.Println(err) 125 | return nil, err 126 | } 127 | return jsonGet, nil 128 | } 129 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/vo/uservo/department_vo.go: -------------------------------------------------------------------------------- 1 | package uservo 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/models/baseModel" 5 | "permissionManage/perm-server/sys-common/vo" 6 | "permissionManage/perm-server/sys-sysbase/models/user" 7 | ) 8 | 9 | // 前端需要的数据结构 10 | type DepartmentVO struct { 11 | *user.User 12 | Token string `json:"token"` 13 | } 14 | 15 | // 请求参数 16 | type DepartmentParamVo struct { 17 | *baseModel.CurrentUser 18 | baseModel.BaseModel 19 | *vo.PageVo 20 | DepName string `json:"depName"` 21 | DepCode string `json:"depCode" form:"depCode"` 22 | DepLevel int64 `json:"depLevel" form:"depLevel"` 23 | DepOrder int64 `json:"depOrder" form:"depOrder"` 24 | ParentId string `json:"parentId" form:"parentId"` 25 | Token string `json:"token"` 26 | 27 | Ids string `json:"ids"` //批量删除入参 28 | } 29 | 30 | // 列表数据结构 31 | type DepartmentListVo struct { 32 | Id string `json:"id"` 33 | DepName string `json:"depName"` 34 | DepCode string `json:"depCode" form:"depCode"` 35 | DepLevel int64 `json:"depLevel" form:"depLevel"` 36 | DepOrder int64 `json:"depOrder" form:"depOrder"` 37 | ParentId string `json:"parentId" form:"parentId"` 38 | } 39 | 40 | // 树结构数据 41 | type DepartmentTreeVo struct { 42 | Id string `json:"id"` 43 | ParentId string `json:"parentId"` 44 | Subs []*DepartmentTreeVo `json:"subs"` 45 | Child []*DepartmentTreeVo `json:"child"` 46 | Name string `json:"name"` 47 | DepLevel int64 `json:"depLevel" form:"depLevel"` 48 | } 49 | 50 | func DepartmentToDepartmentTreeVo(resource *user.Department) (rtVo *DepartmentTreeVo) { 51 | rtVo = new(DepartmentTreeVo) 52 | rtVo.Id = resource.Id 53 | rtVo.ParentId = resource.ParentId 54 | rtVo.Name = resource.DepName 55 | rtVo.DepLevel = resource.DepLevel 56 | //golog.Infof("%s", rtVo) 57 | return 58 | } 59 | 60 | func DepartmentToDepartmentTreeVos(resources []*user.Department) (rtVos []*DepartmentTreeVo) { 61 | for _, r := range resources { 62 | rtVo := DepartmentToDepartmentTreeVo(r) 63 | rtVos = append(rtVos, rtVo) 64 | } 65 | return 66 | } 67 | 68 | func DepartmentParamVoVoToDepartment(paramVo *DepartmentParamVo) (result *user.Department) { 69 | currentUser := paramVo.CurrentUser 70 | if paramVo.Id != "" { 71 | result = user.FindDepartmentById(paramVo.Id) 72 | result.UpdatorId = currentUser.UserAccount 73 | result.UpdatorName = currentUser.UserName 74 | result.UpdatorDepartmentId = currentUser.DepartmentId 75 | result.UpdatorDepartmentName = currentUser.DepartmentName 76 | } else { 77 | result = new(user.Department) 78 | result.CreatorId = currentUser.UserAccount 79 | result.CreatorName = currentUser.UserName 80 | result.CreatorDepartmentId = currentUser.DepartmentId 81 | result.CreatorDepartmentName = currentUser.DepartmentName 82 | } 83 | result.DepName = paramVo.DepName 84 | result.DepCode = paramVo.DepCode 85 | result.DepOrder = paramVo.DepOrder 86 | result.ParentId = paramVo.ParentId 87 | result.DepLevel = paramVo.DepLevel 88 | return 89 | } 90 | 91 | func DepartmentToResourceListVo(dep *user.Department) (depvo *DepartmentListVo) { 92 | depvo = new(DepartmentListVo) 93 | depvo.Id = dep.Id 94 | depvo.DepName = dep.DepName 95 | depvo.DepCode = dep.DepCode 96 | depvo.DepOrder = dep.DepOrder 97 | depvo.ParentId = dep.ParentId 98 | depvo.DepLevel = dep.DepLevel 99 | return 100 | } 101 | 102 | func DepartmentToDepartmentListVos(deps []*user.Department) (depVos []*DepartmentListVo) { 103 | for _, dep := range deps { 104 | depVo := DepartmentToResourceListVo(dep) 105 | depVos = append(depVos, depVo) 106 | } 107 | return 108 | } 109 | -------------------------------------------------------------------------------- /perm-vue/src/components/common/Sidebar.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 78 | 79 | 101 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/demo/BaseCharts.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 90 | 91 | -------------------------------------------------------------------------------- /perm-vue/src/utils/rest.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | // import Qs from 'qs' 3 | import {Message} from 'element-ui' 4 | import {fmtToken} from "./utils"; 5 | 6 | /** 7 | const postData=JSON.stringify(this.formCustomer); 8 | 'Content-Type':'application/json'} 9 | 10 | const postData=Qs.stringify(this.formCustomer);//过滤成?&=格式 11 | 'Content-Type':'application/xxxx-form'} 12 | */ 13 | 14 | var axiosInstance = axios.create({ 15 | baseURL: 'http://localhost:8099', 16 | // config里面有这个transformRquest,这个选项会在发送参数前进行处理。 17 | // 这时候我们通过Qs.stringify转换为表单查询参数 18 | transformRequest: [function (data) { 19 | // data = Qs.stringify(data) 20 | data = JSON.stringify(data); // 转换json 21 | return data 22 | }], 23 | // 设置Content-Type 24 | headers: { 25 | 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' 26 | // 'Authorization': 'bearer ' + JSON.parse(window.sessionStorage.getItem('user')).token 27 | } 28 | }); 29 | 30 | // 请求拦截 31 | axiosInstance.interceptors.request.use(config => { 32 | config.headers['Authorization'] = fmtToken(); 33 | // config.headers.Authorization = 'bearer ' + token 34 | return config 35 | }, err => { 36 | Message.error({message: '请求超时!', showClose: true}); 37 | return Promise.resolve(err) 38 | }); 39 | // response拦截 40 | axiosInstance.interceptors.response.use(data => { 41 | // if (data.status && data.status === 200 && data.data.code != 200) { 42 | // console.log(data) 43 | // Message.error({message: data.data.msg}) 44 | // return 45 | // } 46 | return data 47 | }, err => { 48 | if (err.response) { 49 | var status = err.response.status; 50 | var msg = err.response.data.msg; 51 | switch (status) { 52 | case 400: 53 | Message.error({message: (msg != null && msg !== '') ? msg : '操作失败,参数不对!', showClose: true}); 54 | break; 55 | case 401: 56 | Message.error({message: (msg != null && msg !== '') ? msg : '未认证或认证过期,请重新登录!', showClose: true}); 57 | break; 58 | case 404: 59 | Message.error({message: '请求的资源不存在!', showClose: true}); 60 | break; 61 | case 403: 62 | Message.error({message: '权限不足,请联系管理员!', showClose: true}); 63 | break; 64 | case 500: 65 | Message.error({message: '服务器被吃了 ⊙﹏⊙...', showClose: true}); 66 | break; 67 | case 504: 68 | Message.error({message: '网关连接超时!', showClose: true}); 69 | break; 70 | default: 71 | Message.error({message: '未知错误!', showClose: true}) 72 | } 73 | } 74 | return Promise.resolve(err) 75 | }); 76 | 77 | // ---------- rest请求封装 ----------- 78 | let base = 'http://localhost:8088' 79 | // let base = '/api' 80 | // let base = '' 81 | export const ftmURL = function url(url) { 82 | return `${base}${url}` 83 | // return base + url 84 | }; 85 | 86 | export const postRequest = function (url, params) { 87 | return axiosInstance({ 88 | method: 'post', 89 | url: ftmURL(url), 90 | data: params, 91 | headers: { 92 | 'Content-Type': 'application/x-www-form-urlencoded' 93 | } 94 | }) 95 | }; 96 | 97 | export const uploadFileRequest = function (url, params) { 98 | return axiosInstance({ 99 | method: 'post', 100 | url: ftmURL(url), 101 | data: params, 102 | headers: { 103 | 'Content-Type': 'multipart/form-data' 104 | } 105 | }) 106 | }; 107 | 108 | export const putRequest = function (url, params) { 109 | return axiosInstance({ 110 | method: 'put', 111 | url: ftmURL(url), 112 | data: params 113 | }) 114 | }; 115 | 116 | export const deleteRequest = function (url) { 117 | return axiosInstance({ 118 | method: 'delete', 119 | url: ftmURL(url) 120 | }) 121 | }; 122 | 123 | export const getRequest = function (url) { 124 | return axiosInstance({ 125 | method: 'get', 126 | url: ftmURL(url) 127 | }) 128 | }; 129 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/models/user/department.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/db" 5 | "permissionManage/perm-server/sys-common/utils" 6 | "strconv" 7 | "time" 8 | ) 9 | 10 | // table cd_sys_user_department 11 | type Department struct { 12 | Id string `xorm:"pk varchar(32) notnull unique 'id'"` 13 | CreateTime time.Time `xorm:"'create_time'"` 14 | CreatorDepartmentId string `xorm:"varchar(50) 'creator_department_id'"` 15 | CreatorDepartmentName string `xorm:"varchar(255) 'creator_department_name'"` 16 | CreatorId string `xorm:"varchar(50) 'creator_id'"` 17 | CreatorName string `xorm:"varchar(255) 'creator_name'"` 18 | IsDeleted int64 `xorm:"INT(1) notnull 'is_deleted'"` 19 | UpdateTime time.Time `xorm:"'update_time'"` 20 | UpdatorDepartmentId string `xorm:"varchar(50) 'updator_department_id'"` 21 | UpdatorDepartmentName string `xorm:"varchar(255) 'updator_department_name'"` 22 | UpdatorId string `xorm:"varchar(50) 'updator_id'"` 23 | UpdatorName string `xorm:"varchar(255) 'updator_name'"` 24 | Version int64 `xorm:"INT(11) 'version'"` 25 | 26 | DepName string `xorm:"varchar(100) 'dep_name' index"` 27 | DepCode string `xorm:"varchar(50) 'dep_code'"` 28 | DepLevel int64 `xorm:"INT(11) 'dep_level'"` 29 | DepOrder int64 `xorm:"INT(11) 'dep_order'"` 30 | ParentId string `xorm:"varchar(100) 'parent_id'"` 31 | } 32 | 33 | func (Department) TableName() string { 34 | return "cd_sys_user_department" 35 | } 36 | 37 | //========================= 新增 ============================ 38 | func CreateDepartment(deps ...*Department) (int64, error) { 39 | e := db.MasterEngine() 40 | var roleEntitys []Department 41 | for _, d := range deps { 42 | // 生成uuid 43 | d.Id = utils.GetUuid() 44 | d.CreateTime = time.Now() 45 | d.Version = 0 46 | d.IsDeleted = 0 47 | 48 | roleEntitys = append(roleEntitys, *d) 49 | } 50 | return e.Insert(roleEntitys) 51 | } 52 | 53 | //========================= 更新 ============================ 54 | func UpdateDepartment(eParam *Department) (int64, error) { 55 | e := db.MasterEngine() 56 | eParam.UpdateTime = time.Now() 57 | eParam.Version = eParam.Version + 1 58 | aff, err := e.Id(eParam.Id).Update(eParam) 59 | if err != nil { 60 | err.Error() 61 | } 62 | return aff, err 63 | } 64 | 65 | //========================= 逻辑删除 ============================ 66 | func DeleteDepartmentByIds(ids []string) (effect int64, err error) { 67 | e := db.MasterEngine() 68 | for _, id := range ids { 69 | eModel := FindDepartmentById(id) 70 | if eModel != nil { 71 | eModel.IsDeleted = 1 72 | _, err := e.Id(id).Update(eModel) 73 | if err != nil { 74 | err.Error() 75 | } 76 | } 77 | } 78 | return 79 | } 80 | 81 | //========================= 物理删除 ============================ 82 | func RemoveDepartmentByIds(ids []int64) (effect int64, err error) { 83 | e := db.MasterEngine() 84 | 85 | cr := new(Department) 86 | for _, v := range ids { 87 | i, err1 := e.Id(v).Delete(cr) 88 | effect += i 89 | err = err1 90 | } 91 | return 92 | } 93 | 94 | //========================= 查询 ============================ 95 | // 根据id查询 96 | func FindDepartmentById(id string) (eRes *Department) { 97 | eRes = new(Department) 98 | e := db.MasterEngine() 99 | _, err := e.Id(id).Get(eRes) 100 | if err != nil { 101 | err.Error() 102 | return 103 | } 104 | 105 | return 106 | } 107 | 108 | // ===== 根据父id查询当前级别菜单最大序号 109 | func GetDepartmentMaxOrderByParentId(parentId string) (int64, error) { 110 | e := db.MasterEngine() 111 | 112 | sql := "SELECT MAX(ud.dep_order) AS maxOrder FROM cd_sys_user_department ud WHERE ud.parent_id = '" + parentId + "'" 113 | s := e.SQL(sql) 114 | re, err := s.QueryString(sql) 115 | if err != nil || len(re) == 0 { 116 | return int64(0), err 117 | } 118 | if re[0]["maxOrder"] == "" { 119 | return int64(0), nil 120 | } 121 | maxOrder, err := strconv.ParseInt(re[0]["maxOrder"], 10, 64) 122 | 123 | return maxOrder, err 124 | } 125 | 126 | // ===== 根据父id查询当前菜单级别 127 | func GetDepartmentParentLevelByParentId(parentId string) (int64, error) { 128 | e := db.MasterEngine() 129 | 130 | sql := "SELECT MAX(ud.dep_level) AS parentLevel FROM cd_sys_user_department ud WHERE ud.id = '" + parentId + "'" 131 | s := e.SQL(sql) 132 | re, err := s.QueryString(sql) 133 | if err != nil || len(re) == 0 { 134 | return int64(0), err 135 | } 136 | level, err := strconv.ParseInt(re[0]["parentLevel"], 10, 64) 137 | 138 | return level, err 139 | } 140 | -------------------------------------------------------------------------------- /perm-server/sys-common/middleware/casbins/casbins.go: -------------------------------------------------------------------------------- 1 | package casbins 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "permissionManage/perm-server/sys-common/db" 7 | "permissionManage/perm-server/sys-common/inits/parse" 8 | "permissionManage/perm-server/sys-common/middleware/jwts" 9 | "permissionManage/perm-server/sys-common/supports" 10 | "permissionManage/perm-server/sys-common/supports/commonConst" 11 | "strconv" 12 | "sync" 13 | 14 | "github.com/casbin/casbin" 15 | 16 | _ "github.com/go-sql-driver/mysql" 17 | "github.com/kataras/iris/v12/context" 18 | ) 19 | 20 | var ( 21 | adt *Adapter // Your driver and data source. 22 | e *casbin.Enforcer 23 | 24 | adtLook sync.Mutex 25 | eLook sync.Mutex 26 | 27 | rbacModel string 28 | ) 29 | 30 | // Casbin is the casbins services which contains the casbins enforcer. 31 | //type Casbin struct { 32 | // Enforcer *casbins.Enforcer 33 | //} 34 | 35 | // New returns the casbins service which receives a casbins enforcer. 36 | // 37 | // Adapt with its `Wrapper` for the entire application 38 | // or its `ServeHTTP` for specific routes or parties. 39 | //func New() *Casbin { 40 | // return &Casbin{Enforcer: e} 41 | //} 42 | 43 | func SetRbacModel(rootID string) { 44 | rbacModel = fmt.Sprintf(` 45 | [request_definition] 46 | r = sub, obj, act, suf 47 | 48 | [policy_definition] 49 | p = sub, obj, act, suf 50 | 51 | [role_definition] 52 | g = _, _ 53 | 54 | [policy_effect] 55 | e = some(where (p.eft == allow)) 56 | 57 | [matchers] 58 | m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && regexMatch(r.suf, p.suf) && regexMatch(r.act, p.act) || r.sub == "%s" 59 | `, rootID) 60 | } 61 | 62 | // 获取Enforcer 63 | func GetEnforcer() *casbin.Enforcer { 64 | if e != nil { 65 | e.LoadPolicy() 66 | return e 67 | } 68 | eLook.Lock() 69 | defer eLook.Unlock() 70 | if e != nil { 71 | e.LoadPolicy() 72 | return e 73 | } 74 | 75 | m := casbin.NewModel(rbacModel) 76 | //m.AddDef("r", "r", "sub, obj, act, suf") 77 | //m.AddDef("p", "p", "sub, obj, act, suf") 78 | //m.AddDef("g", "g", "_, _") 79 | //m.AddDef("e", "e", "some(where (p.eft == allow))") 80 | //m.AddDef("m", "m", `g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && regexMatch(r.suf, p.suf) && regexMatch(r.act, p.act) || r.sub == "1"`) 81 | 82 | // Or you can use an existing DB "abc" like this: 83 | // The adapter will use the table named "casbin_rule". 84 | // If it doesn't exist, the adapter will create it automatically. 85 | // a := xormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/abc", true) 86 | // TODO use go-bindata fill 87 | //e = casbin.NewEnforcer("conf/rbac_model.conf", singletonAdapter()) 88 | e = casbin.NewEnforcer(m, singleAdapter()) 89 | e.EnableLog(true) 90 | return e 91 | } 92 | 93 | func singleAdapter() *Adapter { 94 | if adt != nil { 95 | return adt 96 | } 97 | adtLook.Lock() 98 | defer adtLook.Unlock() 99 | if adt != nil { 100 | return adt 101 | } 102 | 103 | master := parse.DBConfig.Master 104 | url := db.GetConnURL(&master) 105 | // Initialize a Gorm adapter and use it in a Casbin enforcer: 106 | // The adapter will use the MySQL database named "casbins". 107 | // If it doesn't exist, the adapter will create it automatically. 108 | // a := xormadapter.NewAdapter("mysql", "root:root@tcp(127.0.0.1:3306)/?charset=utf8&parseTime=True&loc=Local") // Your driver and data source. 109 | adt = NewAdapter(master.Dialect, url, true) // Your driver and data source. 110 | return adt 111 | } 112 | 113 | // ServeHTTP is the iris compatible casbins handler which should be passed to specific routes or parties. 114 | // Usage: 115 | // [...] 116 | // app.Get("/dataset1/resource1", casbinMiddleware.ServeHTTP, myHandler) 117 | // [...] 118 | func CheckPermissions(ctx context.Context) bool { 119 | user, ok := jwts.ParseToken(ctx) 120 | if !ok { 121 | return false 122 | } 123 | 124 | //uid := strconv.Itoa(string(user.Id)) 125 | uid := strconv.Itoa(int(0)) 126 | fmt.Println(user) 127 | fmt.Println(uid) 128 | yes := true //GetEnforcer().Enforce(uid, ctx.Path(), ctx.Method(), ".*", "") 129 | if !yes { 130 | supports.Unauthorized(ctx, supports.PermissionsLess, nil) 131 | ctx.StopExecution() 132 | return false 133 | } 134 | ctx.Params().Set(commonConst.CURRENT_USER_KEY, user.Id) 135 | return true 136 | //ctx.Next() 137 | } 138 | 139 | // Wrapper is the router wrapper, prefer this method if you want to use casbins to your entire iris application. 140 | // Usage: 141 | // [...] 142 | // app.WrapRouter(casbinMiddleware.Wrapper()) 143 | // app.Get("/dataset1/resource1", myHandler) 144 | // [...] 145 | func Wrapper() func(w http.ResponseWriter, r *http.Request, router http.HandlerFunc) { 146 | return func(w http.ResponseWriter, r *http.Request, router http.HandlerFunc) { 147 | //if !c.Check(r) { 148 | // w.WriteHeader(http.StatusForbidden) 149 | // w.Write([]byte("403 Forbidden")) 150 | // return 151 | //} 152 | router(w, r) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/models/user/user.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/db" 5 | "permissionManage/perm-server/sys-common/utils" 6 | "strconv" 7 | "time" 8 | ) 9 | 10 | // table cd_sys_user_user 11 | type User struct { 12 | Id string `xorm:"pk varchar(32) notnull unique 'id'"` 13 | CreateTime time.Time `xorm:"'create_time'"` 14 | CreatorDepartmentId string `xorm:"varchar(50) 'creator_department_id'"` 15 | CreatorDepartmentName string `xorm:"varchar(255) 'creator_department_name'"` 16 | CreatorId string `xorm:"varchar(50) 'creator_id'"` 17 | CreatorName string `xorm:"varchar(255) 'creator_name'"` 18 | IsDeleted int64 `xorm:"INT(1) notnull 'is_deleted'"` 19 | UpdateTime time.Time `xorm:"'update_time'"` 20 | UpdatorDepartmentId string `xorm:"varchar(50) 'updator_department_id'"` 21 | UpdatorDepartmentName string `xorm:"varchar(255) 'updator_department_name'"` 22 | UpdatorId string `xorm:"varchar(50) 'updator_id'"` 23 | UpdatorName string `xorm:"varchar(255) 'updator_name'"` 24 | Version int64 `xorm:"INT(11) 'version'"` 25 | 26 | UserNumber string `xorm:"varchar(50) 'user_number'"` 27 | UserAccount string `xorm:"varchar(50) 'user_account'"` 28 | UserPassword string `xorm:"varchar(50) 'user_password'"` 29 | UserName string `xorm:"varchar(50) 'user_name'"` 30 | Sex string `xorm:"varchar(50) 'sex'"` 31 | DepartmentId string `xorm:"varchar(50) 'department_id'"` 32 | Mobile string `xorm:"varchar(50) 'mobile'"` 33 | Email string `xorm:"varchar(50) 'email'"` 34 | Address string `xorm:"varchar(255) 'address'"` 35 | } 36 | 37 | type UserDepartment struct { 38 | User `xorm:"extends"` 39 | Department `xorm:"extends"` 40 | } 41 | 42 | func (User) TableName() string { 43 | return "cd_sys_user_user" 44 | } 45 | 46 | func (UserDepartment) TableName() string { 47 | return "cd_sys_user_user" 48 | } 49 | 50 | //========================= 新增 ============================ 51 | func CreateUser(users ...*User) (int64, error) { 52 | e := db.MasterEngine() 53 | var userEntitys []User 54 | for _, u := range users { 55 | u.Id = utils.GetUuid() 56 | u.CreateTime = time.Now() 57 | u.IsDeleted = 0 58 | // 密码加密 59 | u.UserPassword = utils.AESEncrypt([]byte(u.UserPassword)) 60 | userEntitys = append(userEntitys, *u) 61 | } 62 | return e.Insert(userEntitys) 63 | } 64 | 65 | //========================= 更新 ============================ 66 | func UpdateUser(eParam *User) (int64, error) { 67 | e := db.MasterEngine() 68 | eParam.UpdateTime = time.Now() 69 | eParam.Version = eParam.Version + 1 70 | aff, err := e.Id(eParam.Id).Update(eParam) 71 | if err != nil { 72 | err.Error() 73 | } 74 | return aff, err 75 | } 76 | 77 | //========================= 逻辑删除 ============================ 78 | func DeleteUserByIds(ids []string) (effect int64, err error) { 79 | e := db.MasterEngine() 80 | for _, id := range ids { 81 | user := FindUserById(id) 82 | if user != nil { 83 | user.IsDeleted = 1 84 | _, err := e.Id(id).Update(user) 85 | if err != nil { 86 | err.Error() 87 | } 88 | } 89 | } 90 | return 91 | } 92 | 93 | //========================= 物理删除 ============================ 94 | func RemoveUserByIds(ids []int64) (effect int64, err error) { 95 | e := db.MasterEngine() 96 | 97 | cr := new(User) 98 | for _, v := range ids { 99 | i, err1 := e.Id(v).Delete(cr) 100 | effect += i 101 | err = err1 102 | } 103 | return 104 | } 105 | 106 | //========================= 查询 ============================ 107 | //// 根据id查询 108 | //func FindUserById(userId string) *User { 109 | // user := new(User) 110 | // e := db.MasterEngine() 111 | // e.Get(&User{Id: userId}) 112 | // 113 | // return user 114 | //} 115 | 116 | // 根据id查询 117 | func FindUserById(id string) (user *User) { 118 | user = new(User) 119 | e := db.MasterEngine() 120 | _, err := e.Id(id).Get(user) 121 | if err != nil { 122 | err.Error() 123 | return 124 | } 125 | 126 | return 127 | } 128 | 129 | // ===== 查询用户最大编号 130 | func GetMaxUserNumber() (int64, error) { 131 | e := db.MasterEngine() 132 | 133 | sql := "SELECT MAX(CONVERT(uu.user_number,SIGNED)) AS maxUserNumber FROM cd_sys_user_user uu" 134 | s := e.SQL(sql) 135 | re, err := s.QueryString(sql) 136 | if err != nil || len(re) == 0 { 137 | return int64(0), err 138 | } 139 | if re[0]["maxUserNumber"] == "" { 140 | return int64(0), nil 141 | } 142 | maxUserNumber, err := strconv.ParseInt(re[0]["maxUserNumber"], 10, 64) 143 | 144 | return maxUserNumber, err 145 | } 146 | 147 | func GetUserByUsername(user *User) (bool, error) { 148 | e := db.MasterEngine() 149 | return e.Get(user) 150 | } 151 | 152 | func UpdateUserById(user *User) (int64, error) { 153 | e := db.MasterEngine() 154 | return e.Id(user.Id).Update(user) 155 | } 156 | 157 | func DeleteByUsers(uids []int64) (effect int64, err error) { 158 | e := db.MasterEngine() 159 | 160 | u := new(User) 161 | for _, v := range uids { 162 | i, err1 := e.Id(v).Delete(u) 163 | effect += i 164 | err = err1 165 | } 166 | return 167 | } 168 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/demo/Upload.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 99 | 100 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/models/user/resource.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "fmt" 5 | "permissionManage/perm-server/sys-common/db" 6 | "permissionManage/perm-server/sys-common/utils" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | // cd_sys_user_resource 12 | type Resource struct { 13 | Id string `xorm:"pk varchar(32) notnull unique 'id'"` 14 | CreateTime time.Time `xorm:"'create_time'"` 15 | CreatorDepartmentId string `xorm:"varchar(50) 'creator_department_id'"` 16 | CreatorDepartmentName string `xorm:"varchar(255) 'creator_department_name'"` 17 | CreatorId string `xorm:"varchar(50) 'creator_id'"` 18 | CreatorName string `xorm:"varchar(255) 'creator_name'"` 19 | IsDeleted int64 `xorm:"INT(1) notnull 'is_deleted'"` 20 | UpdateTime time.Time `xorm:"'update_time'"` 21 | UpdatorDepartmentId string `xorm:"varchar(50) 'updator_department_id'"` 22 | UpdatorDepartmentName string `xorm:"varchar(255) 'updator_department_name'"` 23 | UpdatorId string `xorm:"varchar(50) 'updator_id'"` 24 | UpdatorName string `xorm:"varchar(255) 'updator_name'"` 25 | Version int64 `xorm:"INT(11) 'version'"` 26 | 27 | ResourceType string `xorm:"varchar(50) 'resource_type'"` 28 | ResourceName string `xorm:"varchar(100) 'resource_name'"` 29 | ResourceLevel int64 `xorm:"INT(11) 'resource_level'"` 30 | ResourceOrder int64 `xorm:"INT(11) 'resource_order'"` 31 | ResourceSate int64 `xorm:"tinyint(2) 'resource_sate'"` 32 | ParentId string `xorm:"varchar(50) 'parent_id'"` 33 | Url string `xorm:"varchar(100) 'url'"` 34 | Icon string `xorm:"varchar(100) 'icon'"` 35 | Description string `xorm:"varchar(255) 'description'"` 36 | } 37 | 38 | func (Resource) TableName() string { 39 | return "cd_sys_user_resource" 40 | } 41 | 42 | //========================= 新增 ============================ 43 | func CreateResource(resources ...*Resource) (int64, error) { 44 | e := db.MasterEngine() 45 | var resourcesEntitys []Resource 46 | for _, r := range resources { 47 | // 生成uuid 48 | r.Id = utils.GetUuid() 49 | r.CreateTime = time.Now() 50 | r.Version = 0 51 | r.IsDeleted = 0 52 | 53 | resourcesEntitys = append(resourcesEntitys, *r) 54 | } 55 | return e.Insert(resourcesEntitys) 56 | } 57 | 58 | //========================= 更新 ============================ 59 | func UpdateResource(resource *Resource) (int64, error) { 60 | e := db.MasterEngine() 61 | resource.UpdateTime = time.Now() 62 | resource.Version = resource.Version + 1 63 | aff, err := e.Id(resource.Id).Update(resource) 64 | if err != nil { 65 | err.Error() 66 | } 67 | return aff, err 68 | } 69 | 70 | //========================= 逻辑删除 ============================ 71 | func DeleteResourceByIds(ids []string) (effect int64, err error) { 72 | e := db.MasterEngine() 73 | for _, id := range ids { 74 | tmpResource := FindResourceById(id) 75 | if tmpResource != nil { 76 | tmpResource.IsDeleted = 1 77 | _, err := e.Id(id).Update(tmpResource) 78 | if err != nil { 79 | err.Error() 80 | } 81 | } 82 | } 83 | return 84 | } 85 | 86 | //========================= 物理删除 ============================ 87 | func RemoveResourceByIds(ids []int64) (effect int64, err error) { 88 | e := db.MasterEngine() 89 | 90 | cr := new(Resource) 91 | for _, v := range ids { 92 | i, err1 := e.Id(v).Delete(cr) 93 | effect += i 94 | err = err1 95 | } 96 | return 97 | } 98 | 99 | //========================= 查询 ============================ 100 | func FindResourceById(id string) (resource *Resource) { 101 | resource = new(Resource) 102 | e := db.MasterEngine() 103 | _, err := e.Id(id).Get(resource) 104 | if err != nil { 105 | err.Error() 106 | return 107 | } 108 | 109 | return 110 | } 111 | 112 | // ===== 根据父id查询当前级别菜单最大序号 113 | func GetResourceMaxOrderByParentId(parentId string) (int64, error) { 114 | e := db.MasterEngine() 115 | 116 | sql := "SELECT MAX(ur.resource_order) AS maxOrder FROM cd_sys_user_resource ur WHERE ur.parent_id = '" + parentId + "'" 117 | s := e.SQL(sql) 118 | re, err := s.QueryString(sql) 119 | if err != nil || len(re) == 0 { 120 | return int64(0), err 121 | } 122 | if re[0]["maxOrder"] == "" { 123 | return int64(0), nil 124 | } 125 | maxOrder, err := strconv.ParseInt(re[0]["maxOrder"], 10, 64) 126 | 127 | return maxOrder, err 128 | } 129 | 130 | // ===== 根据父id查询当前菜单级别 131 | func GetResourceLevelByParentId(parentId string) (int64, error) { 132 | e := db.MasterEngine() 133 | 134 | sql := "SELECT MAX(ur.resource_level) AS parentLevel FROM cd_sys_user_resource ur WHERE ur.id = '" + parentId + "'" 135 | s := e.SQL(sql) 136 | re, err := s.QueryString(sql) 137 | if err != nil || len(re) == 0 { 138 | return int64(0), err 139 | } 140 | level, err := strconv.ParseInt(re[0]["parentLevel"], 10, 64) 141 | 142 | return level, err 143 | } 144 | 145 | // ===== 根据用户Id获取该用户所拥有的菜单 146 | func GetResourceByUserId(uId string) ([]*Resource, error) { 147 | e := db.MasterEngine() 148 | sql := fmt.Sprintf(" SELECT * FROM cd_sys_user_resource ur "+ 149 | " WHERE ur.id IN ( SELECT urr.resource_id FROM cd_sys_user_role_resource urr "+ 150 | " WHERE urr.role_id IN ( SELECT uur.role_id FROM cd_sys_user_user_role uur "+ 151 | " WHERE uur.user_id = '%s' ) ) "+ 152 | " AND ur.resource_type = 0 "+ 153 | " AND ur.is_deleted = 0 "+ 154 | " ORDER BY ur.resource_order ASC", uId) 155 | 156 | result := make([]*Resource, 0) 157 | err := e.SQL(sql).Find(&result) 158 | 159 | return result, err 160 | } 161 | -------------------------------------------------------------------------------- /perm-vue/src/components/common/Tags.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 98 | 99 | 100 | 172 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/Login.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 96 | 97 | -------------------------------------------------------------------------------- /perm-vue/build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const webpack = require('webpack') 5 | const config = require('../config') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 12 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin') 13 | 14 | const env = require('../config/prod.env') 15 | 16 | const webpackConfig = merge(baseWebpackConfig, { 17 | module: { 18 | rules: utils.styleLoaders({ 19 | sourceMap: config.build.productionSourceMap, 20 | extract: true, 21 | usePostCSS: true 22 | }) 23 | }, 24 | devtool: config.build.productionSourceMap ? config.build.devtool : false, 25 | output: { 26 | path: config.build.assetsRoot, 27 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 28 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 29 | }, 30 | plugins: [ 31 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 32 | new webpack.DefinePlugin({ 33 | 'process.env': env 34 | }), 35 | new UglifyJsPlugin({ 36 | uglifyOptions: { 37 | compress: { 38 | warnings: false 39 | } 40 | }, 41 | sourceMap: config.build.productionSourceMap, 42 | parallel: true 43 | }), 44 | // extract css into its own file 45 | new ExtractTextPlugin({ 46 | filename: utils.assetsPath('css/[name].[contenthash].css'), 47 | // Setting the following option to `false` will not extract CSS from codesplit chunks. 48 | // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. 49 | // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 50 | // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110 51 | allChunks: true, 52 | }), 53 | // Compress extracted CSS. We are using this plugin so that possible 54 | // duplicated CSS from different components can be deduped. 55 | new OptimizeCSSPlugin({ 56 | cssProcessorOptions: config.build.productionSourceMap 57 | ? { safe: true, map: { inline: false } } 58 | : { safe: true } 59 | }), 60 | // generate dist index.html with correct asset hash for caching. 61 | // you can customize output by editing /index.html 62 | // see https://github.com/ampedandwired/html-webpack-plugin 63 | new HtmlWebpackPlugin({ 64 | filename: config.build.index, 65 | template: 'index.html', 66 | inject: true, 67 | minify: { 68 | removeComments: true, 69 | collapseWhitespace: true, 70 | removeAttributeQuotes: true 71 | // more options: 72 | // https://github.com/kangax/html-minifier#options-quick-reference 73 | }, 74 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 75 | chunksSortMode: 'dependency' 76 | }), 77 | // keep module.id stable when vender modules does not change 78 | new webpack.HashedModuleIdsPlugin(), 79 | // enable scope hoisting 80 | new webpack.optimize.ModuleConcatenationPlugin(), 81 | // split vendor js into its own file 82 | new webpack.optimize.CommonsChunkPlugin({ 83 | name: 'vendor', 84 | minChunks (module) { 85 | // any required modules inside node_modules are extracted to vendor 86 | return ( 87 | module.resource && 88 | /\.js$/.test(module.resource) && 89 | module.resource.indexOf( 90 | path.join(__dirname, '../node_modules') 91 | ) === 0 92 | ) 93 | } 94 | }), 95 | // extract webpack runtime and module manifest to its own file in order to 96 | // prevent vendor hash from being updated whenever app bundle is updated 97 | new webpack.optimize.CommonsChunkPlugin({ 98 | name: 'manifest', 99 | minChunks: Infinity 100 | }), 101 | // This instance extracts shared chunks from code splitted chunks and bundles them 102 | // in a separate chunk, similar to the vendor chunk 103 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk 104 | new webpack.optimize.CommonsChunkPlugin({ 105 | name: 'app', 106 | async: 'vendor-async', 107 | children: true, 108 | minChunks: 3 109 | }), 110 | 111 | // copy custom static assets 112 | new CopyWebpackPlugin([ 113 | { 114 | from: path.resolve(__dirname, '../static'), 115 | to: config.build.assetsSubDirectory, 116 | ignore: ['.*'] 117 | } 118 | ]) 119 | ] 120 | }) 121 | 122 | if (config.build.productionGzip) { 123 | const CompressionWebpackPlugin = require('compression-webpack-plugin') 124 | 125 | webpackConfig.plugins.push( 126 | new CompressionWebpackPlugin({ 127 | asset: '[path].gz[query]', 128 | algorithm: 'gzip', 129 | test: new RegExp( 130 | '\\.(' + 131 | config.build.productionGzipExtensions.join('|') + 132 | ')$' 133 | ), 134 | threshold: 10240, 135 | minRatio: 0.8 136 | }) 137 | ) 138 | } 139 | 140 | if (config.build.bundleAnalyzerReport) { 141 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 142 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 143 | } 144 | 145 | module.exports = webpackConfig 146 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/vo/uservo/resource_vo.go: -------------------------------------------------------------------------------- 1 | package uservo 2 | 3 | import ( 4 | "permissionManage/perm-server/sys-common/models/baseModel" 5 | "permissionManage/perm-server/sys-common/vo" 6 | "permissionManage/perm-server/sys-sysbase/models/user" 7 | "time" 8 | ) 9 | 10 | // 前端需要的数据结构 11 | type ResourceVO struct { 12 | Id string `json:"id"` 13 | CreateTime time.Time `json:"createTime"` 14 | CreatorDepartmentId string `json:"creatorDepartmentId"` 15 | CreatorDepartmentName string `json:"creatorDepartmentName"` 16 | CreatorId string `json:"creatorId"` 17 | CreatorName string `json:"creatorName"` 18 | IsDeleted int64 `json:"isDeleted"` 19 | UpdateTime time.Time `json:"updateTime"` 20 | UpdatorDepartmentId string `json:"updatorDepartmentId"` 21 | UpdatorDepartmentName string `json:"updatorDepartmentName"` 22 | UpdatorId string `json:"updatorId"` 23 | UpdatorName string `json:"updatorName"` 24 | Version int64 `json:"version"` 25 | 26 | ResourceType string `json:"resourceType"` 27 | ResourceName string `json:"resourceName"` 28 | ResourceLevel int64 `json:"resourceLevel"` 29 | ResourceOrder int64 `json:"resourceOrder"` 30 | ResourceSate int64 `json:"resourceSate"` 31 | ParentId string `json:"parentId"` 32 | Url string `json:"url"` 33 | Icon string `json:"icon"` 34 | Description string `json:"description"` 35 | } 36 | 37 | // 请求参数 38 | type ResourceParamVo struct { 39 | *baseModel.CurrentUser 40 | baseModel.BaseModel 41 | *vo.PageVo 42 | Id string `json:"id"` 43 | UserId string `json:"userId"` 44 | ResourceType string `json:"resourceType"` 45 | ResourceName string `json:"resourceName"` 46 | ResourceLevel int64 `json:"resourceLevel"` 47 | ResourceOrder int64 `json:"resourceOrder"` 48 | ResourceSate int64 `json:"resourceSate"` 49 | ParentId string `json:"parentId"` 50 | Url string `json:"url"` 51 | Icon string `json:"icon"` 52 | Description string `json:"description"` 53 | Token string `json:"token"` 54 | 55 | Ids string `json:"ids"` //批量删除入参 56 | } 57 | 58 | // 树结构数据 59 | type ResourceTreeVo struct { 60 | Id string `json:"id"` 61 | ParentId string `json:"parentId"` 62 | ResourceName string `json:"title"` 63 | Url string `json:"index"` 64 | Icon string `json:"icon"` 65 | Subs []*ResourceTreeVo `json:"subs"` 66 | Children []*ResourceTreeVo `json:"children"` 67 | Label string `json:"label"` 68 | } 69 | 70 | // 列表数据结构 71 | type ResourceListVo struct { 72 | Id string `json:"id"` 73 | ResourceType string `json:"resourceType"` 74 | ResourceName string `json:"resourceName"` 75 | ResourceLevel int64 `json:"resourceLevel"` 76 | ResourceOrder int64 `json:"resourceOrder"` 77 | ResourceSate int64 `json:"resourceSate"` 78 | ParentId string `json:"parentId"` 79 | Url string `json:"url"` 80 | Icon string `json:"icon"` 81 | Description string `json:"description"` 82 | } 83 | 84 | // 用户列表,不带token 85 | func ResourceToResourceTreeVo(resource *user.Resource) (rtVo *ResourceTreeVo) { 86 | rtVo = new(ResourceTreeVo) 87 | rtVo.Id = resource.Id 88 | rtVo.ParentId = resource.ParentId 89 | rtVo.ResourceName = resource.ResourceName 90 | rtVo.Url = resource.Url 91 | rtVo.Icon = resource.Icon 92 | rtVo.Label = resource.ResourceName 93 | //golog.Infof("%s", rtVo) 94 | return 95 | } 96 | 97 | func ResourceToResourceTreeVos(resources []*user.Resource) (rtVos []*ResourceTreeVo) { 98 | for _, r := range resources { 99 | rtVo := ResourceToResourceTreeVo(r) 100 | rtVos = append(rtVos, rtVo) 101 | } 102 | return 103 | } 104 | 105 | func ResourceToResourceListVo(resource *user.Resource) (rtVo *ResourceListVo) { 106 | rtVo = new(ResourceListVo) 107 | rtVo.Id = resource.Id 108 | rtVo.ResourceType = resource.ResourceType 109 | rtVo.ResourceName = resource.ResourceName 110 | rtVo.ResourceLevel = resource.ResourceLevel 111 | rtVo.ResourceLevel = resource.ResourceLevel 112 | rtVo.ResourceOrder = resource.ResourceOrder 113 | rtVo.ResourceSate = resource.ResourceSate 114 | rtVo.ParentId = resource.ParentId 115 | rtVo.Url = resource.Url 116 | rtVo.Icon = resource.Icon 117 | rtVo.Description = resource.Description 118 | //golog.Infof("%s", rtVo) 119 | return 120 | } 121 | 122 | func ResourceToResourceListVos(resources []*user.Resource) (rtVos []*ResourceListVo) { 123 | for _, r := range resources { 124 | rtVo := ResourceToResourceListVo(r) 125 | rtVos = append(rtVos, rtVo) 126 | } 127 | return 128 | } 129 | 130 | func ResourceParamVoToResource(rp *ResourceParamVo) (result *user.Resource) { 131 | currentUser := rp.CurrentUser 132 | if rp.Id != "" { 133 | result = user.FindResourceById(rp.Id) 134 | result.UpdatorId = currentUser.UserAccount 135 | result.UpdatorName = currentUser.UserName 136 | result.UpdatorDepartmentId = currentUser.DepartmentId 137 | result.UpdatorDepartmentName = currentUser.DepartmentName 138 | } else { 139 | result = new(user.Resource) 140 | result.CreatorId = currentUser.UserAccount 141 | result.CreatorName = currentUser.UserName 142 | result.CreatorDepartmentId = currentUser.DepartmentId 143 | result.CreatorDepartmentName = currentUser.DepartmentName 144 | 145 | result.ResourceLevel = rp.ResourceLevel 146 | result.ResourceOrder = rp.ResourceOrder 147 | result.ResourceSate = rp.ResourceSate 148 | } 149 | result.ResourceType = "0" 150 | result.ResourceName = rp.ResourceName 151 | result.ParentId = rp.ParentId 152 | result.Url = rp.Url 153 | result.Icon = rp.Icon 154 | result.Description = rp.Description 155 | 156 | return 157 | } 158 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/demo/Tabs.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 120 | 121 | 129 | 130 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/demo/DragList.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 108 | 109 | 165 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/routes/user/department_route.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "github.com/kataras/iris/v12" 5 | "github.com/kataras/iris/v12/hero" 6 | "permissionManage/perm-server/sys-common/models/baseModel" 7 | "permissionManage/perm-server/sys-common/supports" 8 | "permissionManage/perm-server/sys-common/supports/commonConst" 9 | "permissionManage/perm-server/sys-common/supports/responseHandle" 10 | "permissionManage/perm-server/sys-sysbase/service/userService" 11 | "permissionManage/perm-server/sys-sysbase/vo/uservo" 12 | ) 13 | 14 | func DepartmentHub(party iris.Party) { 15 | var menu = party.Party("/department") //菜单管理 16 | 17 | menu.Post("/addDepartment", hero.Handler(AddDepartment)) // 添加部门 18 | menu.Post("/updateDepartment", hero.Handler(UpdateDepartment)) // 更新部门 19 | menu.Post("/isDepartmentCanDelete", hero.Handler(IsDepartmentCanDelete)) // 删除部门 20 | menu.Post("/deleteDepartment", hero.Handler(DeleteDepartment)) // 删除部门 21 | 22 | menu.Post("/findDepartmentList", hero.Handler(FindDepartmentList)) // 列表 23 | menu.Post("/findDepartmentPages", hero.Handler(FindDepartmentPages)) // 分页 24 | menu.Post("/findDepartmentTreeAll", hero.Handler(FindDepartmentTreeAll)) // 获取菜单树带根 25 | } 26 | 27 | //============================= 新增 ========================================= 28 | func AddDepartment(ctx iris.Context) { 29 | var ( 30 | err error 31 | paramRVo = new(uservo.DepartmentParamVo) 32 | res *supports.SimResult 33 | ) 34 | 35 | if err = ctx.ReadJSON(¶mRVo); err != nil { 36 | ctx.Application().Logger().Errorf("", supports.PARAM_IS_EMPTY, err.Error()) 37 | supports.Error(ctx, iris.StatusBadRequest, supports.PARAM_IS_EMPTY, nil) 38 | return 39 | } 40 | paramRVo.CurrentUser = baseModel.GetCurrentUset(ctx.Params().Get(commonConst.CURRENT_USER_KEY)) 41 | 42 | res = userService.CreateDepartment(paramRVo) 43 | 44 | responseHandle.Response(ctx, res) 45 | } 46 | 47 | //============================= 更新 ========================================= 48 | func UpdateDepartment(ctx iris.Context) { 49 | var ( 50 | err error 51 | paramRVo = new(uservo.DepartmentParamVo) 52 | res *supports.SimResult 53 | ) 54 | 55 | if err = ctx.ReadJSON(¶mRVo); err != nil { 56 | ctx.Application().Logger().Errorf("", supports.PARAM_IS_EMPTY, err.Error()) 57 | supports.Error(ctx, iris.StatusBadRequest, supports.PARAM_IS_EMPTY, nil) 58 | return 59 | } 60 | paramRVo.CurrentUser = baseModel.GetCurrentUset(ctx.Params().Get(commonConst.CURRENT_USER_KEY)) 61 | 62 | res = userService.UpdateDepartment(paramRVo) 63 | 64 | responseHandle.Response(ctx, res) 65 | } 66 | 67 | //============================= 确认是否能删除 ========================================= 68 | func IsDepartmentCanDelete(ctx iris.Context) { 69 | var ( 70 | err error 71 | paramRVo = new(uservo.DepartmentParamVo) 72 | res *supports.SimResult 73 | ) 74 | 75 | if err = ctx.ReadJSON(¶mRVo); err != nil || paramRVo.Id == "" { 76 | ctx.Application().Logger().Errorf("", supports.PARAM_IS_EMPTY, err.Error()) 77 | supports.Error(ctx, iris.StatusBadRequest, supports.PARAM_IS_EMPTY, nil) 78 | return 79 | } 80 | 81 | res = userService.IsDepartmentCanDelete(paramRVo) 82 | 83 | responseHandle.Response(ctx, res) 84 | } 85 | 86 | //============================= 删除 ========================================= 87 | func DeleteDepartment(ctx iris.Context) { 88 | var ( 89 | err error 90 | paramRVo = new(uservo.DepartmentParamVo) 91 | res *supports.SimResult 92 | ) 93 | 94 | if err = ctx.ReadJSON(¶mRVo); err != nil || paramRVo.Ids == "" { 95 | ctx.Application().Logger().Errorf("", supports.PARAM_IS_EMPTY, err.Error()) 96 | supports.Error(ctx, iris.StatusBadRequest, supports.PARAM_IS_EMPTY, nil) 97 | return 98 | } 99 | 100 | res = userService.DeleteDepartment(paramRVo) 101 | 102 | responseHandle.Response(ctx, res) 103 | } 104 | 105 | // 获取菜单资源列表 106 | func FindDepartmentPages(ctx iris.Context) { 107 | var ( 108 | err error 109 | paramRVo = new(uservo.DepartmentParamVo) 110 | ) 111 | 112 | if err = ctx.ReadJSON(¶mRVo); err != nil { 113 | ctx.Application().Logger().Errorf("", supports.PARAM_IS_EMPTY, err.Error()) 114 | supports.Error(ctx, iris.StatusBadRequest, supports.PARAM_IS_EMPTY, nil) 115 | return 116 | } 117 | 118 | res := userService.FindDepartmentPages(paramRVo) 119 | if res == nil { 120 | supports.Ok(ctx, "", "") 121 | return 122 | } 123 | 124 | if !res.Code { 125 | supports.Error(ctx, iris.StatusInternalServerError, res.Msg, nil) 126 | return 127 | } 128 | 129 | supports.Ok(ctx, res.Msg, res.Data) 130 | } 131 | 132 | func FindDepartmentList(ctx iris.Context) { 133 | var ( 134 | err error 135 | paramRVo = new(uservo.DepartmentParamVo) 136 | ) 137 | 138 | if err = ctx.ReadJSON(¶mRVo); err != nil { 139 | ctx.Application().Logger().Errorf("", supports.PARAM_IS_EMPTY, err.Error()) 140 | supports.Error(ctx, iris.StatusBadRequest, supports.PARAM_IS_EMPTY, nil) 141 | return 142 | } 143 | 144 | tmpRes := userService.FindDepartmentList(paramRVo) 145 | if !tmpRes.Code { 146 | ctx.Application().Logger().Errorf("", tmpRes.Msg, err.Error()) 147 | supports.Error(ctx, iris.StatusInternalServerError, tmpRes.Msg, nil) 148 | return 149 | } 150 | 151 | supports.Ok(ctx, tmpRes.Msg, tmpRes.Data) 152 | 153 | return 154 | } 155 | 156 | // 获取菜单树 157 | func FindDepartmentTreeAll(ctx iris.Context) { 158 | var ( 159 | err error 160 | paramRVo = new(uservo.DepartmentParamVo) 161 | ) 162 | 163 | if err = ctx.ReadJSON(¶mRVo); err != nil { 164 | ctx.Application().Logger().Errorf("", supports.PARAM_IS_EMPTY, err.Error()) 165 | supports.Error(ctx, iris.StatusBadRequest, supports.PARAM_IS_EMPTY, nil) 166 | return 167 | } 168 | 169 | res := userService.FindDepartmentTreeAll(paramRVo) 170 | responseHandle.Response(ctx, res) 171 | } 172 | -------------------------------------------------------------------------------- /perm-vue/src/components/page/demo/BaseForm.vue: -------------------------------------------------------------------------------- 1 | 64 | 65 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/routes/user/resource_route.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "github.com/kataras/iris/v12" 5 | "github.com/kataras/iris/v12/hero" 6 | "permissionManage/perm-server/sys-common/models/baseModel" 7 | "permissionManage/perm-server/sys-common/supports" 8 | "permissionManage/perm-server/sys-common/supports/commonConst" 9 | "permissionManage/perm-server/sys-common/supports/responseHandle" 10 | "permissionManage/perm-server/sys-sysbase/service/userService" 11 | userVO "permissionManage/perm-server/sys-sysbase/vo/uservo" 12 | ) 13 | 14 | func ResoureHub(party iris.Party) { 15 | var menu = party.Party("/resoure") //菜单管理 16 | 17 | menu.Post("/addResource", hero.Handler(AddResource)) // 添加资源 18 | menu.Post("/updateResource", hero.Handler(UpdateResource)) // 更新资源 19 | menu.Post("/deleteResource", hero.Handler(DeleteResource)) // 删除资源 20 | 21 | menu.Post("/findResourceList", hero.Handler(FindResourceList)) // 给角色添加权限 22 | menu.Post("/findResourceTree", hero.Handler(FindResourceTree)) // 给角色添加权限 23 | menu.Post("/findResourceTreeAll", hero.Handler(FindResourceTreeAll)) // 获取菜单树带根 24 | menu.Post("/findResourceTreeAllWithoutRoot", hero.Handler(FindResourceTreeAllWithoutRoot)) // 获取菜单树不带带根 25 | menu.Post("/findPagesResource", hero.Handler(FindPagesResource)) // 给角色添加权限 26 | } 27 | 28 | //============================= 新增 ========================================= 29 | func AddResource(ctx iris.Context) { 30 | var ( 31 | err error 32 | paramRVo = new(userVO.ResourceParamVo) 33 | res *supports.SimResult 34 | ) 35 | 36 | if err = ctx.ReadJSON(¶mRVo); err != nil { 37 | ctx.Application().Logger().Errorf("", supports.PARAM_IS_EMPTY, err.Error()) 38 | supports.Error(ctx, iris.StatusBadRequest, supports.PARAM_IS_EMPTY, nil) 39 | return 40 | } 41 | paramRVo.CurrentUser = baseModel.GetCurrentUset(ctx.Params().Get(commonConst.CURRENT_USER_KEY)) 42 | 43 | res = userService.CreateResource(paramRVo) 44 | 45 | responseHandle.Response(ctx, res) 46 | } 47 | 48 | //============================= 更新 ========================================= 49 | func UpdateResource(ctx iris.Context) { 50 | var ( 51 | err error 52 | paramRVo = new(userVO.ResourceParamVo) 53 | res *supports.SimResult 54 | ) 55 | 56 | if err = ctx.ReadJSON(¶mRVo); err != nil { 57 | ctx.Application().Logger().Errorf("", supports.PARAM_IS_EMPTY, err.Error()) 58 | supports.Error(ctx, iris.StatusBadRequest, supports.PARAM_IS_EMPTY, nil) 59 | return 60 | } 61 | paramRVo.CurrentUser = baseModel.GetCurrentUset(ctx.Params().Get(commonConst.CURRENT_USER_KEY)) 62 | 63 | res = userService.UpdateResource(paramRVo) 64 | 65 | responseHandle.Response(ctx, res) 66 | } 67 | 68 | //============================= 删除 ========================================= 69 | func DeleteResource(ctx iris.Context) { 70 | var ( 71 | err error 72 | paramRVo = new(userVO.ResourceParamVo) 73 | res *supports.SimResult 74 | ) 75 | 76 | if err = ctx.ReadJSON(¶mRVo); err != nil || paramRVo.Ids == "" { 77 | ctx.Application().Logger().Errorf("", supports.PARAM_IS_EMPTY, err.Error()) 78 | supports.Error(ctx, iris.StatusBadRequest, supports.PARAM_IS_EMPTY, nil) 79 | return 80 | } 81 | 82 | res = userService.DeleteResource(paramRVo) 83 | 84 | responseHandle.Response(ctx, res) 85 | } 86 | 87 | //============================= 获取菜单资源列表 ========================================= 88 | func FindResourceList(ctx iris.Context) { 89 | var ( 90 | err error 91 | paramRVo = new(userVO.ResourceParamVo) 92 | res *supports.SimResult 93 | ) 94 | 95 | if err = ctx.ReadJSON(¶mRVo); err != nil { 96 | ctx.Application().Logger().Errorf("用户id为空", "", err.Error()) 97 | supports.Error(ctx, iris.StatusBadRequest, "用户id为空", nil) 98 | return 99 | } 100 | 101 | res = userService.FindResourceListByUser(paramRVo) 102 | 103 | responseHandle.Response(ctx, res) 104 | } 105 | 106 | //============================= 获取用户所拥有菜单 ========================================= 107 | func FindResourceTree(ctx iris.Context) { 108 | var ( 109 | err error 110 | paramRVo = new(userVO.ResourceParamVo) 111 | res *supports.SimResult 112 | ) 113 | 114 | if err = ctx.ReadJSON(¶mRVo); err != nil { 115 | ctx.Application().Logger().Errorf("用户id为空", "", err.Error()) 116 | supports.Error(ctx, iris.StatusBadRequest, "用户id为空", nil) 117 | return 118 | } 119 | 120 | res = userService.FindResourceTreeByUser(paramRVo) 121 | 122 | responseHandle.Response(ctx, res) 123 | 124 | } 125 | 126 | func FindPagesResource(ctx iris.Context) { 127 | var ( 128 | err error 129 | paramRVo = new(userVO.ResourceParamVo) 130 | ) 131 | 132 | if err = ctx.ReadJSON(¶mRVo); err != nil { 133 | ctx.Application().Logger().Errorf("用户id为空", "", err.Error()) 134 | supports.Error(ctx, iris.StatusBadRequest, "用户id为空", nil) 135 | return 136 | } 137 | 138 | tmpRes := userService.FindPagesResource(paramRVo) 139 | if !tmpRes.Code { 140 | ctx.Application().Logger().Errorf("用户id为空", "", err.Error()) 141 | return 142 | } 143 | 144 | supports.Ok(ctx, tmpRes.Msg, tmpRes.Data) 145 | 146 | return 147 | } 148 | 149 | // 获取菜单树 150 | func FindResourceTreeAll(ctx iris.Context) { 151 | var ( 152 | err error 153 | paramRVo = new(userVO.ResourceParamVo) 154 | subRtVo []*userVO.ResourceTreeVo 155 | rtVo *userVO.ResourceTreeVo 156 | ) 157 | 158 | if err = ctx.ReadJSON(¶mRVo); err != nil { 159 | ctx.Application().Logger().Errorf("用户id为空", "", err.Error()) 160 | supports.Error(ctx, iris.StatusBadRequest, "用户id为空", nil) 161 | return 162 | } 163 | 164 | subRtVo, res := userService.FindResourceTreeAll(paramRVo) 165 | if res == nil { 166 | supports.Ok(ctx, "", "") 167 | return 168 | } 169 | 170 | if !res.Code { 171 | supports.Error(ctx, iris.StatusBadRequest, res.Msg, nil) 172 | return 173 | } 174 | 175 | rtVo = &userVO.ResourceTreeVo{ 176 | Id: "0", 177 | ParentId: "-1", 178 | ResourceName: "总菜单", 179 | Subs: subRtVo, 180 | Children: subRtVo, 181 | Label: "总菜单", 182 | } 183 | supports.Ok(ctx, res.Msg, rtVo) 184 | } 185 | 186 | func FindResourceTreeAllWithoutRoot(ctx iris.Context) { 187 | var ( 188 | err error 189 | paramRVo = new(userVO.ResourceParamVo) 190 | subRtVo []*userVO.ResourceTreeVo 191 | ) 192 | 193 | if err = ctx.ReadJSON(¶mRVo); err != nil { 194 | ctx.Application().Logger().Errorf("用户id为空", "", err.Error()) 195 | supports.Error(ctx, iris.StatusBadRequest, "用户id为空", nil) 196 | return 197 | } 198 | 199 | subRtVo, res := userService.FindResourceTreeAll(paramRVo) 200 | res = &supports.SimResult{ 201 | Code: res.Code, 202 | Msg: res.Msg, 203 | Data: subRtVo, 204 | } 205 | responseHandle.Response(ctx, res) 206 | } 207 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/service/userService/role_service.go: -------------------------------------------------------------------------------- 1 | package userService 2 | 3 | import ( 4 | "fmt" 5 | "permissionManage/perm-server/sys-common/db" 6 | "permissionManage/perm-server/sys-common/supports" 7 | "permissionManage/perm-server/sys-common/vo" 8 | "permissionManage/perm-server/sys-sysbase/models/user" 9 | "permissionManage/perm-server/sys-sysbase/vo/uservo" 10 | "strings" 11 | ) 12 | 13 | //============================= 新增 ========================================= 14 | func CreateRole(paramVo *uservo.RoleParamVo) (res *supports.SimResult) { 15 | role := uservo.RoleParamVoToRole(paramVo) 16 | 17 | _, err := user.CreateRole(role) 18 | if err != nil { 19 | res = &supports.SimResult{ 20 | Code: false, 21 | Msg: supports.ADD_FAIL, 22 | } 23 | } 24 | 25 | res = &supports.SimResult{ 26 | Code: true, 27 | Msg: supports.ADD_SUCCESS, 28 | } 29 | 30 | return 31 | } 32 | 33 | //============================= 更新 ========================================= 34 | func UpdateRole(paramVo *uservo.RoleParamVo) (res *supports.SimResult) { 35 | eModel := uservo.RoleParamVoToRole(paramVo) 36 | _, err := user.UpdateRole(eModel) 37 | if err != nil { 38 | err.Error() 39 | res = &supports.SimResult{ 40 | Code: false, 41 | Msg: supports.UPDATE_FAIL, 42 | } 43 | return 44 | } 45 | 46 | res = &supports.SimResult{ 47 | Code: true, 48 | Msg: supports.UPDATE_SUCCESS, 49 | } 50 | 51 | return 52 | } 53 | 54 | //============================= 删除 ========================================= 55 | func DeleteRole(paramVo *uservo.RoleParamVo) (res *supports.SimResult) { 56 | idsStr := paramVo.Ids 57 | _, err := user.DeleteRoleByIds(strings.Split(idsStr, ",")) 58 | if err != nil { 59 | err.Error() 60 | res = &supports.SimResult{ 61 | Code: false, 62 | Msg: supports.DELETE_FAIL, 63 | } 64 | return 65 | } 66 | 67 | res = &supports.SimResult{ 68 | Code: true, 69 | Msg: supports.DELETE_SUCCESS, 70 | } 71 | 72 | return 73 | } 74 | 75 | //============================= 查询 ========================================= 76 | // 根据id查询 77 | func FindRoleById(roleParam *uservo.RoleParamVo) (res *supports.SimResult) { 78 | res = &supports.SimResult{ 79 | Code: true, 80 | Data: uservo.RoleToRoleVo(user.FindRoleById(roleParam.Id)), 81 | } 82 | return 83 | } 84 | func FindRoleList(roleParam *uservo.RoleParamVo) (res *supports.SimResult) { 85 | e := db.MasterEngine() 86 | result := make([]*user.Role, 0) 87 | 88 | sql := fmt.Sprintf(" SELECT * FROM cd_sys_user_role ur " + 89 | " WHERE ur.is_deleted = false") 90 | 91 | err := e.SQL(sql).Find(&result) 92 | if err != nil { 93 | res = &supports.SimResult{ 94 | Code: false, 95 | Msg: "", 96 | Data: nil, 97 | } 98 | return 99 | } 100 | 101 | res = &supports.SimResult{ 102 | Code: true, 103 | Data: uservo.RoleToRoleListVos(result), 104 | } 105 | 106 | return 107 | } 108 | 109 | // 分页 110 | func FindRolePages(paramVo *uservo.RoleParamVo) (res *supports.SimResult) { 111 | e := db.MasterEngine() 112 | roleListVos := make([]*uservo.RoleListVo, 0) 113 | roles := make([]*user.Role, 0) 114 | 115 | pageParam := vo.GetPageParam(paramVo.PageVo) 116 | 117 | sql := " is_deleted = false " 118 | if paramVo.RoleName != "" { 119 | sql += " and role_name like '%" + paramVo.RoleName + "%'" 120 | } 121 | s := e.Where(sql).Limit(pageParam.PageSize, pageParam.Start) 122 | count, err := s.FindAndCount(&roles) 123 | if err != nil { 124 | res = &supports.SimResult{ 125 | Code: false, 126 | Msg: supports.ADD_FAIL, 127 | } 128 | } 129 | 130 | roleListVos = uservo.RoleToRoleListVos(roles) 131 | 132 | pageResult := &vo.PageResult{ 133 | CurrentPage: pageParam.CurrentPage, 134 | PageSize: pageParam.PageSize, 135 | Total: count, 136 | Data: roleListVos, 137 | } 138 | res = &supports.SimResult{ 139 | Code: true, 140 | Msg: "", 141 | Data: pageResult, 142 | } 143 | return 144 | } 145 | 146 | // 查询角色所拥有的菜单 147 | func GetRoleResourceByRoleIds(paramVo *uservo.RoleParamVo) (res *supports.SimResult) { 148 | e := db.MasterEngine() 149 | sql := fmt.Sprintf("SELECT" + 150 | " ur.id" + 151 | " FROM cd_sys_user_resource ur" + 152 | " LEFT JOIN cd_sys_user_role_resource urr ON ur.id = urr.resource_id" + 153 | " WHERE ur.is_deleted = 0" + 154 | " AND ur.resource_type = '" + paramVo.ResourceType + "'" + 155 | " AND urr.role_id = '" + paramVo.Id + "'") 156 | tmpRes, err := e.QueryString(sql) 157 | 158 | if err != nil { 159 | err.Error() 160 | res = &supports.SimResult{ 161 | Code: false, 162 | Msg: supports.ADD_FAIL, 163 | } 164 | } 165 | resArry := make([]string, 0) 166 | for _, tmp := range tmpRes { 167 | resArry = append(resArry, tmp["id"]) 168 | } 169 | 170 | res = &supports.SimResult{ 171 | Code: true, 172 | Data: resArry, 173 | } 174 | return 175 | } 176 | 177 | //============================= 角色资源关联关系 ========================================= 178 | func FindRoluesByUserId(userId string) (res *supports.SimResult) { 179 | e := db.MasterEngine() 180 | result := make([]*user.Role, 0) 181 | sql := "SELECT * FROM cd_sys_user_role ur WHERE ur.id IN(SELECT uur.role_id FROM cd_sys_user_user_role uur WHERE uur.user_id = '" + 182 | "" + userId + "') AND ur.is_deleted = FALSE" 183 | err := e.SQL(sql).Find(&result) 184 | if err != nil { 185 | res = &supports.SimResult{ 186 | Code: false, 187 | Msg: "", 188 | Data: nil, 189 | } 190 | return 191 | } 192 | 193 | res = &supports.SimResult{ 194 | Code: true, 195 | Data: uservo.RoleToRoleListVos(result), 196 | } 197 | 198 | return 199 | } 200 | 201 | // 根据用户id查询用户未分配的角色 202 | func FindUnDistributeRoluesByUserId(userId string) (res *supports.SimResult) { 203 | e := db.MasterEngine() 204 | result := make([]*user.Role, 0) 205 | sql := "SELECT * FROM cd_sys_user_role ur WHERE ur.id NOT IN(SELECT uur.role_id FROM cd_sys_user_user_role uur WHERE uur.user_id = '" + 206 | "" + userId + "') AND ur.is_deleted = FALSE" 207 | err := e.SQL(sql).Find(&result) 208 | if err != nil { 209 | res = &supports.SimResult{ 210 | Code: false, 211 | Msg: "", 212 | Data: nil, 213 | } 214 | return 215 | } 216 | 217 | res = &supports.SimResult{ 218 | Code: true, 219 | Data: uservo.RoleToRoleListVos(result), 220 | } 221 | 222 | return 223 | } 224 | 225 | func CreateRoleResource(paramVo *uservo.RoleResourceParamVo) (res *supports.SimResult) { 226 | roleResource := uservo.RoleResourceParamVoToRoleResource(paramVo) 227 | 228 | // 删除现有的关系 229 | user.RemoveRoleResource(paramVo.RoleId) 230 | // 添加新的关系 231 | _, err := user.CreateRelationRoleResource(roleResource...) 232 | if err != nil { 233 | res = &supports.SimResult{ 234 | Code: false, 235 | Msg: supports.ADD_FAIL, 236 | } 237 | } 238 | 239 | res = &supports.SimResult{ 240 | Code: true, 241 | Msg: supports.ADD_SUCCESS, 242 | } 243 | 244 | return 245 | } 246 | -------------------------------------------------------------------------------- /perm-server/sys-sysbase/service/userService/resource_service.go: -------------------------------------------------------------------------------- 1 | package userService 2 | 3 | import ( 4 | "fmt" 5 | "github.com/kataras/golog" 6 | "permissionManage/perm-server/sys-common/db" 7 | "permissionManage/perm-server/sys-common/supports" 8 | "permissionManage/perm-server/sys-common/vo" 9 | "permissionManage/perm-server/sys-sysbase/models/user" 10 | "permissionManage/perm-server/sys-sysbase/vo/uservo" 11 | "strings" 12 | ) 13 | 14 | func CreateResource(resourceParam *uservo.ResourceParamVo) (res *supports.SimResult) { 15 | resource := uservo.ResourceParamVoToResource(resourceParam) 16 | maxOrder, orderErr := user.GetResourceMaxOrderByParentId(resourceParam.ParentId) 17 | if orderErr != nil { 18 | orderErr.Error() 19 | res = &supports.SimResult{ 20 | Code: false, 21 | Msg: supports.ADD_FAIL, 22 | } 23 | return 24 | } 25 | resource.ResourceOrder = maxOrder + 1 26 | 27 | if resourceParam.ParentId == "0" { 28 | resource.ResourceLevel = 1 29 | } else { 30 | level, levelErr := user.GetResourceLevelByParentId(resourceParam.ParentId) 31 | if levelErr != nil { 32 | levelErr.Error() 33 | res = &supports.SimResult{ 34 | Code: false, 35 | Msg: supports.ADD_FAIL, 36 | } 37 | return 38 | } 39 | resource.ResourceLevel = level + 1 40 | } 41 | 42 | _, err := user.CreateResource(resource) 43 | if err != nil { 44 | err.Error() 45 | res = &supports.SimResult{ 46 | Code: false, 47 | Msg: supports.ADD_FAIL, 48 | } 49 | return 50 | } 51 | 52 | res = &supports.SimResult{ 53 | Code: true, 54 | Msg: supports.ADD_SUCCESS, 55 | } 56 | 57 | return 58 | } 59 | 60 | func UpdateResource(resourceParam *uservo.ResourceParamVo) (res *supports.SimResult) { 61 | resource := uservo.ResourceParamVoToResource(resourceParam) 62 | _, err := user.UpdateResource(resource) 63 | if err != nil { 64 | err.Error() 65 | res = &supports.SimResult{ 66 | Code: false, 67 | Msg: supports.UPDATE_FAIL, 68 | } 69 | return 70 | } 71 | 72 | res = &supports.SimResult{ 73 | Code: true, 74 | Msg: supports.UPDATE_SUCCESS, 75 | } 76 | 77 | return 78 | } 79 | 80 | func DeleteResource(resourceParam *uservo.ResourceParamVo) (res *supports.SimResult) { 81 | idsStr := resourceParam.Ids 82 | _, err := user.DeleteResourceByIds(strings.Split(idsStr, ",")) 83 | if err != nil { 84 | err.Error() 85 | res = &supports.SimResult{ 86 | Code: false, 87 | Msg: supports.DELETE_FAIL, 88 | } 89 | return 90 | } 91 | 92 | res = &supports.SimResult{ 93 | Code: true, 94 | Msg: supports.DELETE_SUCCESS, 95 | } 96 | 97 | return 98 | } 99 | 100 | func FindResourceListByUser(resourceParam *uservo.ResourceParamVo) (res *supports.SimResult) { 101 | var ( 102 | err error 103 | resourceList []*user.Resource 104 | ) 105 | result := make([]*uservo.ResourceParamVo, 0) 106 | 107 | resourceList, err = user.GetResourceByUserId(resourceParam.UserId) 108 | if err != nil { 109 | err.Error() 110 | res = &supports.SimResult{ 111 | Code: false, 112 | Msg: "", 113 | Data: result, 114 | } 115 | return 116 | } 117 | 118 | res = &supports.SimResult{ 119 | Code: true, 120 | Data: uservo.ResourceToResourceListVos(resourceList), 121 | } 122 | 123 | return 124 | } 125 | 126 | // 构建 菜单 tree 127 | func FindResourceTreeByUser(resourceParam *uservo.ResourceParamVo) (res *supports.SimResult) { 128 | var ( 129 | err error 130 | resourceList []*user.Resource 131 | ) 132 | 133 | resourceList, err = user.GetResourceByUserId(resourceParam.UserId) 134 | if err != nil { 135 | err.Error() 136 | res = &supports.SimResult{ 137 | Code: false, 138 | Msg: supports.QUERY_FAIL, 139 | } 140 | return 141 | } 142 | tmpRtVO := uservo.ResourceToResourceTreeVos(resourceList) 143 | rtVO := buildResourceTree(tmpRtVO) 144 | res = &supports.SimResult{ 145 | Code: true, 146 | Msg: supports.LoginSuccess, 147 | Data: rtVO, 148 | } 149 | 150 | return 151 | } 152 | func FindResourceTreeAll(resourceParam *uservo.ResourceParamVo) (rtVO []*uservo.ResourceTreeVo, res *supports.SimResult) { 153 | var ( 154 | err error 155 | resourceList []*user.Resource 156 | ) 157 | 158 | resourceList, err = FindResourceList(resourceParam) 159 | if err != nil { 160 | err.Error() 161 | res = &supports.SimResult{ 162 | Code: false, 163 | Msg: supports.ADD_FAIL, 164 | } 165 | return 166 | } 167 | tmpRtVO := uservo.ResourceToResourceTreeVos(resourceList) 168 | rtVO = buildResourceTree(tmpRtVO) 169 | 170 | res = &supports.SimResult{ 171 | Code: true, 172 | Msg: "", 173 | Data: rtVO, 174 | } 175 | return 176 | } 177 | 178 | func buildResourceTree(resourceTreeVo []*uservo.ResourceTreeVo) (rtVO []*uservo.ResourceTreeVo) { 179 | for _, rt := range resourceTreeVo { 180 | subs := getSubResourceTree(rt.Id, resourceTreeVo) 181 | if subs == nil { 182 | if rt.ParentId == "0" { 183 | rtVO = append(rtVO, rt) 184 | } 185 | continue 186 | } 187 | rt.Subs = subs 188 | rt.Children = subs 189 | buildResourceTree(subs) 190 | if rt.ParentId == "0" { 191 | rtVO = append(rtVO, rt) 192 | } 193 | } 194 | return 195 | } 196 | func getSubResourceTree(parentId string, resourceTreeVoAll []*uservo.ResourceTreeVo) (rtVO []*uservo.ResourceTreeVo) { 197 | for _, rt := range resourceTreeVoAll { 198 | if rt.ParentId == parentId { 199 | rtVO = append(rtVO, rt) 200 | } 201 | } 202 | 203 | return 204 | } 205 | 206 | func FindResourceList(resourceParam *uservo.ResourceParamVo) (rs []*user.Resource, err error) { 207 | e := db.MasterEngine() 208 | result := make([]*user.Resource, 0) 209 | 210 | sql := fmt.Sprintf(" SELECT * FROM cd_sys_user_resource ur " + 211 | " WHERE ur.is_deleted = false") 212 | 213 | err = e.SQL(sql).Find(&result) 214 | 215 | return result, err 216 | } 217 | 218 | // 分页 219 | func FindPagesResource(paramVo *uservo.ResourceParamVo) (res *supports.SimResult) { 220 | e := db.MasterEngine() 221 | resourceListVos := make([]*uservo.ResourceListVo, 0) 222 | resources := make([]*user.Resource, 0) 223 | 224 | pageParam := vo.GetPageParam(paramVo.PageVo) 225 | 226 | sql := " is_deleted = false " 227 | if paramVo.ResourceName != "" { 228 | sql += " and resource_name like '%" + paramVo.ResourceName + "%'" 229 | } 230 | if paramVo.ResourceType != "" { 231 | sql += " and resource_type = '" + paramVo.ResourceType + "'" 232 | } 233 | s := e.Where(sql).Limit(pageParam.PageSize, pageParam.Start) 234 | count, err := s.FindAndCount(&resources) 235 | 236 | resourceListVos = uservo.ResourceToResourceListVos(resources) 237 | 238 | pageResult := &vo.PageResult{ 239 | CurrentPage: pageParam.CurrentPage, 240 | PageSize: pageParam.PageSize, 241 | Total: count, 242 | Data: resourceListVos, 243 | } 244 | res = &supports.SimResult{ 245 | Code: true, 246 | Msg: "", 247 | Data: pageResult, 248 | } 249 | golog.Println(count, err) 250 | return 251 | } 252 | --------------------------------------------------------------------------------