目前项目中做了几个有关权限控制的页面,主要做了三个,角色管理,资源管理,角色权限的页面。
角色管理
该页面主要是对角色的crud
,这个比较简单就不多讲了。
资源管理
这个页面其实是对菜单的配置,也就是路由的设置,我采用了组件复用的思路,就是增加和更新页面用的是同一个组件,启用前判断是增加还是更新就好了。
如果是新增的话有一个会初始化
更新的话就会得到信息,显示出来
Vue代码
- 新建
src\views\pre\perm\edit.vue
文件,这个其实编辑按钮引用的组件,通过这里可以设置我们要进行的操作的是编辑,然后通过scope
获取到数据
<template>
<div>
<el-button size="mini" type="success" @click="to">编辑</el-button>
<eForm ref="form" :menus="menus" :sup_this="sup_this" :is-add="false"/>
</div>
</template>
<script>
import eForm from './form'
export default {
components: { eForm },
props: {
data: {
type: Object,
required: true
},
sup_this: {
type: Object,
required: true
},
menus: {
type: Array,
required: true
}
},
methods: {
to() {
const _this = this.$refs.form
_this.roleIds = []
_this.form = { per_id: this.data.per_id, per_component: this.data.per_component, per_name: this.data.per_name, per_sort: this.data.per_sort,
per_parent_id: this.data.per_parent_id, per_resource: this.data.per_resource, per_icon: this.data.per_icon, per_describe: this.data.per_describe }
_this.dialog = true
}
}
}
</script>
<style scoped>
div{
display: inline-block;
margin-right: 3px;
}
</style>
2.新建一个src\views\pre\perm\form.vue
文件
这个就是我们要复用的组件了
<template>
<el-dialog :append-to-body="true" :visible.sync="dialog" :title="isAdd ? '新增菜单' : '编辑菜单'" width="600px">
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px">
<el-form-item label="菜单图标">
<el-popover
placement="bottom-start"
width="460"
trigger="click"
@show="$refs['iconSelect'].reset()">
<el-input slot="reference" v-model="form.icon" style="width: 460px;" placeholder="点击选择图标" readonly>
<svg-icon v-if="form.icon" slot="prefix" :icon-class="form.icon" class="el-input__icon" style="height: 32px;width: 16px;" />
<i v-else slot="prefix" class="el-icon-search el-input__icon"/>
</el-input>
</el-popover>
</el-form-item>
<el-form-item label="菜单名称" prop="per_name">
<el-input v-model="form.per_name" placeholder="名称" style="width: 460px;"/>
</el-form-item>
<el-form-item label="菜单排序" prop="per_sort">
<el-input v-model.number="form.per_sort" placeholder="序号越小越靠前" style="width: 460px;"/>
</el-form-item>
<el-form-item label="URL地址">
<el-input v-model="form.per_resource" placeholder="组件路径" style="width: 460px;"/>
</el-form-item>
<el-form-item label="组件路径">
<el-input v-model="form.per_component" placeholder="组件路径" style="width: 460px;"/>
</el-form-item>
<el-form-item label="上级菜单">
<treeselect v-model="form.per_parent_id" :options="menus" style="width: 460px;" placeholder="选择上级类目" />
</el-form-item>
<el-form-item label="菜单描述" prop="per_describe">
<el-input v-model.number="form.per_describe" placeholder="请填写菜单描述" style="width: 460px;"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="cancel">取消</el-button>
<el-button :loading="loading" type="primary" @click="doSubmit">确认</el-button>
</div>
</el-dialog>
</template>
<script>
// import the component
import Treeselect from '@riophae/vue-treeselect'
// import the styles
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import { add, edit } from '@/api/menu'
export default {
components: { Treeselect },
props: {
menus: {
type: Array,
required: true
},
isAdd: {
type: Boolean,
required: true
},
sup_this: {
type: Object,
default: null
}
},
data() {
return {
loading: false, dialog: false,
form: { per_id: null, per_name: '', per_sort: 999, per_resource: '', per_component: '', per_parent_id: 0, per_icon: '', per_describe: '' },
roleIds: [],
rules: {
per_name: [
{ required: true, message: '请输入名称', trigger: 'blur' }
],
per_sort: [
{ required: true, message: '请输入序号', trigger: 'blur', type: 'number' }
]
}
}
},
methods: {
cancel() {
this.resetForm()
},
doSubmit() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.loading = true
this.form.roles = []
const _this = this
this.roleIds.forEach(function(data, index) {
const role = { id: data }
_this.form.roles.push(role)
})
if (this.isAdd) {
this.doAdd()
} else this.doEdit()
} else {
return false
}
})
},
doAdd() {
add(this.form).then(res => {
this.resetForm()
this.$notify({
title: '添加成功',
type: 'success',
duration: 2500
})
this.loading = false
this.$parent.$parent.init()
this.$parent.$parent.getMenus()
}).catch(error => {
this.loading = false
this.$message({
showClose: true,
message: error,
type: 'error'
})
})
},
doEdit() {
edit(this.form).then(res => {
this.resetForm()
this.$notify({
title: '修改成功',
type: 'success',
duration: 2500
})
this.loading = false
this.sup_this.init()
this.sup_this.getMenus()
}).catch(err => {
this.loading = false
console.log(err.msg)
})
},
resetForm() {
this.dialog = false
this.$refs['form'].resetFields()
this.form = { name: '', sort: 999, path: '', component: '', iframe: 'false', pid: 0, icon: '' }
this.roleIds = []
},
selected(name) {
this.form.icon = name
}
}
}
</script>
<style scoped>
</style>
做了这个通用的组件就不用在代码中同时引用两个组件了。
角色权限
我的这个项目前端对权限的控制对象主要是页面的路由,可以动态的去设置角色可以显示哪些菜单。使用了el-tree
这个组件…不会css…页面很丑莫见怪…
系统管理员的页面
测试用户,当然正常情况下用户是不应该可以看到这些关于全县的页面的,我这里只是拿来测试。
可以看到测试用户那边的路由页面根据我们的配置就显示出来了
动态配置的思路
角色权限这个页面中的树形组件其实是对我们数据库中的RolePermission
组件进行增删改查,大致过程是:
- 通过角色id获得用户的路由集合,然后通过
el-tree
组件去渲染是否被选中 - 更新的思路是首先删除
RolePermission
表中这个角色id所有的数据,然后根据我们前端拿到的id集合去批量增加。
小问题
由于el-tree
组件拿到我们后台给的父节点的id,会直接把子节点全部选中,但是这个明显不符合我们的要求,目前的解决办法是把父子节点的关联移除,这样有个问题是我们自己去配置的时候选中父节点,子节点要一个一个去选择…我还在想解决办法…