前端权限控制一般有4种
1.菜单的控制
2.界面的控制
3.按钮的控制
4.请求和响应的控制
本文主要讲述如何使用react框架事件前端权限对菜单的控制。
第一步:
准备菜单数据,在该菜单数据中配置好路由跳转的路径和组件存在的路径。
菜单数据如下所示:
permissionList:[{
permission_no: 1
menu_name: "系统设置"
menu_url: "/index/sysIndex"
path_name: "systemIndex"
component_path: "user/Home/SystemIndex"
menu_imgClass: ""
menu_state: 0
menu_father: 0
menu_id: 1
chidPermissions:[
{
permission_no: 2
menu_name: "会员信息统计"
menu_url: "/index/sysIndex/userTotal"
path_name: "loginLog"
component_path: "user/Home/UserTotal"
menu_imgClass: null
menu_state: 0
menu_father: 1
menu_id: 11
chidPermissions: []},
{
permission_no: 2
menu_name: "登录日志"
menu_url: "/index/sysIndex/loginLog"
path_name: "loginLog"
component_path: "user/Home/LoginLog"
menu_imgClass: null
menu_state: 0
menu_father: 1
menu_id: 11
chidPermissions: []},
{
permission_no: 2
menu_name: "登录日志"
menu_url: "/index/sysIndex/loginLog"
path_name: "loginLog"
component_path: "user/Home/LoginLog"
menu_imgClass: null
menu_state: 0
menu_father: 1
menu_id: 11
chidPermissions: []},
{
permission_no: 3
menu_name: "个人中心"
menu_url: "/index/sysIndex/userSet"
path_name: "userSet"
component_path: "user/Home/UserSet"
menu_imgClass: null
menu_state: 0
menu_father: 1
menu_id: 12
chidPermissions: []}
]},
{
permission_no: 4
menu_name: "任务管理"
menu_url: "/index/task"
path_name: "task"
component_path: "user/Task/TaskManger"
menu_imgClass: null
menu_state: 0
menu_father: 0
menu_id: 2,
chidPermissions:[
{
permission_no: 5
menu_name: "任务完成记录"
menu_url: "/index/task/taskFinish"
path_name: "taskFinish"
component_path: "user/Task/TaskFinish"
menu_imgClass: null
menu_state: 0
menu_father: 2
menu_id: 21
chidPermissions: []
},{
permission_no: 6
menu_name: "任务列表"
menu_url: "/index/task/taskList"
path_name: "taskList"
component_path: "user/Task/TaskList"
menu_imgClass: null
menu_state: 0
menu_father: 2
menu_id: 22
chidPermissions: []
}
]
},
{
permission_no: 7
menu_name: "权限管理"
menu_url: "/index/permission"
path_name: "permission"
component_path: "user/UserRole/Permission"
menu_imgClass: null
menu_state: 0
menu_father: 0
menu_id: 3,
chidPermissions:[
{
permission_no: 8
menu_name: "角色管理"
menu_url: "/index/permission/roleMange"
path_name: "roleManger"
component_path: "user/UserRole/RoleMange"
menu_imgClass: null
menu_state: 0
menu_father: 3
menu_id: 31
chidPermissions: []
},
{
permission_no: 9
menu_name: "用户管理"
menu_url: "/index/permission/userMange"
path_name: "userMange"
component_path: "user/UserRole/UserMange"
menu_imgClass: null
menu_state: 0
menu_father: 3
menu_id: 32
chidPermissions: []
}
]
},
{
permission_no: 10
menu_name: "小程序管理"
menu_url: "/index/appMange"
path_name: "appMange"
component_path: "user/AppAs/AppMange"
menu_imgClass: null
menu_state: 0
menu_father: 0
menu_id: 4,
chidPermissions:[
{
permission_no: 11
menu_name: "客服管理"
menu_url: "/index/appMange/serviceMange"
path_name: "serviceMange"
component_path: "user/AppAs/ServiceMange"
menu_imgClass: null
menu_state: 0
menu_father: 4
menu_id: 41
chidPermissions: []
},
{
permission_no: 12
menu_name: "导航管理"
menu_url: "/index/appMange/navMange"
path_name: "navMange"
component_path: "user/AppAs/NavMange"
menu_imgClass: null
menu_state: 0
menu_father: 4
menu_id: 42
chidPermissions: []
}
]
},
{
permission_no: 13
menu_name: "会员管理"
menu_url: "/index/memberMange"
path_name: "memberMange"
component_path: "user/UserSet/MemberMange"
menu_imgClass: null
menu_state: 0
menu_father: 0
menu_id: 5,
chidPermissions: [
{
permission_no: 14
menu_name: "会员等级设置"
menu_url: "/index/memberMange/memberLevel"
path_name: "memberLevel"
component_path: "user/UserSet/MemberLevel"
menu_imgClass: null
menu_state: 0
menu_father: 5
menu_id: 51
chidPermissions: []
},
{
permission_no: 15
menu_name: "会员积分"
menu_url: "/index/memberMange/memberScores"
path_name: "memberScores"
component_path: "user/UserSet/MemberScores"
menu_imgClass: null
menu_state: 0
menu_father: 5
menu_id: 52
chidPermissions: []
},
{
permission_no: 16
menu_name: "会员管理列表"
menu_url: "/index/memberMange/memberList"
path_name: "memberList"
component_path: "user/UserSet/MemberList"
menu_imgClass: null
menu_state: 0
menu_father: 5
menu_id: 53
chidPermissions: []
}
]
},
{
permission_no: 17
menu_name: "文章管理"
menu_url: "/index/articleMange"
path_name: "articleMange"
component_path: "user/TxtAs/ArticleMange"
menu_imgClass: null
menu_state: 0
menu_father: 0
menu_id: 6,
chidPermissions: [
{
permission_no: 18
menu_name: "文章分类"
menu_url: "/index/articleMange/articleClass"
path_name: "articleClass"
component_path: "user/TxtAs/ArticleClass"
menu_imgClass: null
menu_state: 0
menu_father: 6
menu_id: 61
chidPermissions: []
},{
permission_no: 19
menu_name: "审核文章"
menu_url: "/index/articleMange/articleAudit"
path_name: "articleAudit"
component_path: "user/TxtAs/ArticleAudit"
menu_imgClass: null
menu_state: 0
menu_father: 6
menu_id: 62
chidPermissions: []
}
]
},
{
permission_no: 20
menu_name: "意见与建议"
menu_url: "/index/advise"
path_name: "advise"
component_path: "user/Opinion/Advise"
menu_imgClass: null
menu_state: 0
menu_father: 0
menu_id: 7
chidPermissions: [
{
permission_no: 21
menu_name: "意见与建议"
menu_url: "/index/advise/OpinionAs"
path_name: "advise"
component_path: "user/Opinion/OpinionAs"
menu_imgClass: null
menu_state: 0
menu_father: 7
menu_id: 71
chidPermissions: []
}
]
}
]
第二步搭建项目结构
其中component的结构如下:
第三步动态生成菜单,写成一个组件:
// 生成左边菜单
bindMenu(menulist){
let MenuList= menulist.map((item)=>{
if(item.chidPermissions.length===0){ //没有子菜单
return <Menu.Item key={item.permission_no} onClick={()=>this.add(item.menu_name,item.menu_url,item.menu_id)} ><Link to={item.menu_url}>{item.menu_name}</Link></Menu.Item>
}
else{
return <SubMenu key={item.permission_no} icon={<UserOutlined />} title={item.menu_name}>
{this.bindMenu(item.chidPermissions)}
</SubMenu>
}
})
return MenuList
}
componentWillMount() {
console.log("will mount")
// console.log(JSON.parse(this.props.user.user.permissionList))
// let menuList = window.sessionStorage.getItem('user')?(JSON.parse(window.sessionStorage.getItem('user'))):[];
// console.log('类相关',typeof menuList);
let leftMenu = this.bindMenu(this.props.user.user.permissionList);
this.setState({
leftMenu:leftMenu
})
}
第四步
动态生成路由,写成一个组件
// 动态生成路由
bindRouter(list){
let routerList = list.map((item)=>{
if(item.chidPermissions.length === 0){
return <Route key={item.permission_no} path={item.menu_url} component={loadable(()=>import(`./${item.component_path}`))}></Route>
}else {
return <Route key={item.permission_no} path={item.menu_url} render={()=>{
let componentName = loadable(()=>import(`./${item.component_path}`));
return <componentName>
{this.bindRouter(item.chidPermissions)}
</componentName>
}}>
</Route>
}
})
return routerList
}
componentDidMount() {
let routerList = this.bindRouter(this.props.user.user.permissionList)
console.log('routerList',routerList);
this.setState({
routerList:routerList
})
}
第五步调用菜单组件和动态路由组件
第六步前端可勾选菜单向服务器发起请求(结合ant的树形控件)
先创建一个树形控件的组件名为TreeComponent.js
import React from 'react'
import { Tree } from 'antd';
import treeStore from '../../../store/TreeStore'
const { TreeNode } = Tree;
class Demo extends React.Component {
constructor(props){
super(props)
this.state={
autoExpandParent:true,
expandedKeys:[], //展开指定的树节点
checkedKeys:[],
selectedKeys:[],//设置选中的树节点
treeData:[],//数据
menuData:[],
children:[],
isdata:false,
isdisabled:true, //禁用子节点
isLevel:[], //存取点击的一级选项
}
}
componentDidMount() {
new Promise((resolve, reject) =>{
this.setState({
menuData:JSON.parse(sessionStorage.getItem("user")).permissionList
})
resolve()
} ).then(()=>{
new Promise((resolve, reject) =>{
this.setData(this.state.menuData)
resolve()
} ).then(()=>{
console.log(this.state.treeData)
this.setState({
isdata:true
})
})
})
}
setData(val){
for (let i=0; i<val.length;i++) {
this.setData({
treeData: this.state.treeData.push({
title: val[i].menu_name,
key: val[i].permission_no,
children: []
})
})
if (val[i].chidPermissions && val[i].chidPermissions.length>0){
for (let j=0 ;j<val[i].chidPermissions.length;j++){
this.setState({
'this.state.treeData[i].children':this.state.treeData[i].children.push({
title: val[i].chidPermissions[j].menu_name,
key: val[i].chidPermissions[j].permission_no,
disabled: this.state.isdisabled,
disableCheckbox:true
})
})
}
}
}
}
// 展开/收起节点时触发
onExpand =(expandedKeys) => {
console.log('onExpand', expandedKeys);
this.setState({
expandedKeys:expandedKeys,
})
}
onCheck = (checkedKeys,info )=> {
new Promise((resolve, reject) => {
this.setState({
checkedKeys:this.uniq(this.state. checkedKeys.concat(checkedKeys.checked)),
selectedKeys:this.uniq(this.state.selectedKeys.concat(checkedKeys.checked)),
})
this.childrenDisabled(info.node.children)
// 判断一级选项是否被选中
if(info.node.children){
// 判断是否点击的是一级选项
this.setState({
isLevel:this.uniq(this.state.isLevel.concat(checkedKeys.checked))
})
if(this.checkArr(info.node.key,this.state.isLevel)){
console.log(2)
// 移除一级选项
this.setState({
checkedKeys:this.remove(this.state.checkedKeys,info.node.key),
selectedKeys: this.remove(this.state.selectedKeys,info.node.key),
isLevel: this.remove(this.state.isLevel,info.node.key)
})
// 移除二级选中状态
new Promise(resolve1 => {
let chilArr = this.getLevelChilKey(info.node.key,this.state.treeData)
resolve1(chilArr)
}).then((valArr)=>{
for (let i=0; i<valArr.length;i++){
this.setState({
checkedKeys: this.remove(this.state.checkedKeys,valArr[i].key),
selectedKeys: this.remove(this.state.selectedKeys,valArr[i].key)
})
}
})
this.childeenIsDisabled(info.node.children)
}
}
resolve()
}).then(()=>{
console.log('选中1',this.state.selectedKeys)
})
};
onSelect = (selectedKeys, info) => {
new Promise((resolve, reject) => {
// 判断是否点击一级选项
// 判断是否有children
if (info.node.children){
// 判断是否点击一级选项
// 是
if(this.checkLevelOne(selectedKeys)){
// 设置它下面的子选项可用
this.childrenDisabled(info.node.children)
}
// 判断isLevel是否从复选框选中
if(this.checkArr(info.node.key,this.state.isLevel)){
this.setState({
isLevel: this.remove(this.state.isLevel,info.node.key)
})
}else {
this.setState({
isLevel:this.state.isLevel.concat(selectedKeys)
})
}
}
// 启用切换到禁用
if(this.checkISLevelOne(info.node.key,this.state.isLevel)){
let indexVal = this.getIndex(info.node.key,this.state.treeData)
this.childeenIsDisabled(info.node.children)
// 一级选项
this.setState({
isLevel: this.remove(this.state.isLevel,info.node.key)
})
}
// 所有元素
// 判断点击元素是否一点击
if(this.checkArr(selectedKeys,this.state.checkedKeys)){
// 已点击
// 取消选中状态
this.setState({
checkedKeys: this.remove(this.state.checkedKeys,selectedKeys),
selectedKeys: this.remove(this.state.selectedKeys,info.selectedNodes[0].key)
})
}else { //没点击 添加选中状态
this.setState({
checkedKeys:this.state.checkedKeys.concat(selectedKeys),
})
if (info.selectedNodes.length==0){
this.setState({
selectedKeys:[],
checkedKeys:[]
})
}else {
this.setState({
selectedKeys:this.state.selectedKeys.concat(info.selectedNodes[0].key)
})
}
}
resolve()
}).then(()=>{
console.log( '选择中2', this.state.selectedKeys)
treeStore.addKey( this.state.selectedKeys)
})
};
// 检查数组是否存在改值
checkArr(val,arr){
let istrue=false
for (let i=0;i<arr.length;i++){
if (val==arr[i]){
istrue = true
}
}
return istrue
}
// 移除指定的元素
remove(arr, item) {
var result=[];
for(var i=0; i<arr.length; i++){
if(arr[i]!=item){
result.push(arr[i]);
}
}
return result;
}
获取两数组不同元素
getArrDifference(arr1, arr2) {
return arr1.concat(arr2).filter(function(v, i, arr) {
return arr.indexOf(v) === arr.lastIndexOf(v);
});
}
// 获取一级选项key
getLevelOne(arr){
var newArr=[]
for (let i=0; i<arr.length;i++){
newArr.push( arr[i].key)
}
return newArr
}
// 判断是否点了一级选项
checkLevelOne(val){
var istrue = true
for (let i; i<this.getLevelOne(this.state.treeData).length;i++){
if (val== this.getLevelOne()[i]){
istrue = false
}
}
return istrue
}
// 设置子节点是启用
childrenDisabled(arr){
for(let i=0; i<arr.length; i++){
arr[i].disabled = false
}
}
// 判断一级选项是否已点击
checkISLevelOne(val,arr){
var istrue = false
for(let i=0;i<arr.length;i++){
if(val==arr[i]){
istrue = true
}
}
return istrue
}
// 获取选项在数组的下标
getIndex(val,arr){
for (let i=0; i<arr.length;i++){
if (val == arr[i].key){
return i
}
}
}
// 设置子节点是禁用
childeenIsDisabled(arr){
for (let i=0; i<arr.length;i++){
arr[i].disabled = true
}
}
// 判断一级选项下有哪些子选项的key
getLevelChilKey(LevelKey,arr){
let newArr
for(let i=0;i<arr.length;i++){
if (LevelKey==arr[i].key){
newArr=arr[i].children
}
}
return newArr
}
// 数组去重
uniq(array){
var temp = []; //一个新的临时数组
for(var i = 0; i < array.length; i++){
if(temp.indexOf(array[i]) == -1){
temp.push(array[i]);
}
}
return temp;
}
render() {
return (
<Tree
checkable
onExpand={this.onExpand}
expandedKeys={this.state.expandedKeys}
autoExpandParent={this.state.autoExpandParent} //是否自动展开父节点
checkedKeys={this.state.checkedKeys}
onCheck={this.onCheck}
onSelect={this.onSelect}
selectedKeys={this.state.selectedKeys}
treeData={this.state.isdata?this.state.treeData:null}
checkStrictly={true}
/>
)
}
}
export {Demo as default}
然后将树形控件中选中的菜单存储在mobx中
代码如下:
import { observable, action } from 'mobx'
class TreeStore {
@observable selectKey = []; 选中的状态key
@action
// 添加Key
addKey(arr){
console.log('接收',arr)
this.selectKey.concat(arr)
sessionStorage.setItem('menluList',JSON.stringify(arr))
}
// 获取selectKey
get(){
console.log('kkkkk', this.selectKey)
return this.selectKey
}
}
const treeStore = new TreeStore;
export default treeStore;
利用该属性控件给新角色赋予权限(即新角色可查看的菜单)
RoleMange.js 中部分代码如下
1.引入TreeComponet组件
import TreeDemo from './TreeComponet'
2.使用树形控件
<Form.Item
label='权限'
name='user_pwd'
>
{/*树形控件*/}
<TreeDemo getTreeData={this.handleOk}></TreeDemo>
</Form.Item>
RoleMange.js 完整代码如下:
import React, { useState } from 'react';
import {Button, Col, Input, Layout, Modal, Radio, Row, Select, Space, Switch, Table, Upload,Form,Tree} from "antd";
import Axios from "../../../util/axios";
import Api from '../../../api/index'
import TreeDemo from './TreeComponet'
import {inject,observer} from "mobx-react";
import treeStore from '../../../store/TreeStore'
const { TreeNode } = Tree;
@inject('user')
@observer
class RoleMange extends React.Component {
//获得登录管理员的编号
userLoginNo = JSON.parse(sessionStorage.getItem('user')).mgr_no
//通过ref获取表单数据域
formRef = React.createRef();//添加表单
constructor(){
super()
this.state = {
visible:false,//添加表单的显示隐藏
tableData:[],//表格数据
}
}
// 获得所有数据
getAllData(){
// const token = window.localStorage.getItem("token")
Axios.post(Api.user.roleData,{
mgr_no:this.userLoginNo,
page:1,
pageSize:10},
).then((res)=>{
console.log('角色列表',res);
if(res.data.code == 200 ){
this.setState({
tableData:res.data.data
})
}
else {
console.log(res);
}
console.log(res);
})
.catch((err)=>{
console.log('角色列表出错',err);
})
}
componentWillMount() {
this.getAllData()
}
// 添加表单成功
handleOk = val => {
console.log('hahaha',val);
console.log('获得mobx中的值',[...this.props.user.menuList]);
this.setState({
visible: false,
});
// 获得表单里面的值
let roleName = this.formRef.current.getFieldsValue().role
let roleState = this.formRef.current.getFieldsValue().user_state
let menuList = [...this.props.user.menuList]
console.log(roleName,roleState)
console.log('get',treeStore.get())
console.log('get1',JSON.parse(sessionStorage.getItem('menluList')))
// 发起请求
Axios.post(Api.user.addRole,{
role_name:roleName,
role_status:parseInt(roleState),
menuList:JSON.parse(sessionStorage.getItem('menluList'))
}).then((res)=>{
console.log('添加返回',res);
if(res.data.code == 200){
this.getAllData();
}
}).catch((err)=>{
console.log('添加出错',err);
})
};
// 添加表单模态框消失
handleCancel = e => {
console.log(e);
this.setState({
visible: false,
});
};
// 显示添加角色菜单
editRole=()=>{
this.setState({
visible: true,
})
}
render() {
const columns = [
{
title: '角色ID',
dataIndex: 'role_no',
// render: text => <a>{text}</a>,
},
{
title: '角色名称',
dataIndex: 'role_name',
},
{
title: '角色状态',
dataIndex: 'role_status',
render: (text, record,index) => (
<Space size="middle">
{function(txt){
if(txt == 1){
return '启用'
}else if(txt == 0){
return '禁用'
}
}
(text)}
</Space>
),
},
];//表格的列名
return (
<div>
{/*搜索*/}
<Layout>
<Row className='searchRow'>
<Col span={2} offset={22}>
<Row style={{display:'flex',justifyContent:'space-between',marginBottom:'10px'}}>
<Button type="primary" size={this.state.btnSize} onClick={this.editRole}>
添加角色
</Button>
</Row>
</Col>
</Row>
</Layout>
{/*表格*/}
<Table columns={columns} dataSource={this.state.tableData} />
{/*添加用户*/}
<Modal
title="添加角色"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
<Form
labelCol={{ span: 4 }}
wrapperCol={{ span: 14 }}
layout="horizontal"
onFinish={this.handleOk}
ref={this.formRef}
initialValues={{
user_name:'',
user_role:'',
user_state:-1
}}
>
<Form.Item
label='角色'
name='role'
>
<Input/>
</Form.Item>
<Form.Item
label='权限'
name='user_pwd'
>
{/*树形控件*/}
<TreeDemo getTreeData={this.handleOk}></TreeDemo>
</Form.Item>
<Form.Item
label='角色状态'
name='user_state'
>
<Radio.Group onChange={this.getFormRadio} value={this.state.formRadioVal}>
<Radio value={1}>正常</Radio>
<Radio value={2}>禁用</Radio>
</Radio.Group>
</Form.Item>
</Form>
</Modal>
</div>
)
}
}
export {RoleMange as default}