群控系统服务端开发模式-应用开发-前端角色功能开发
一、添加视图
在根目录下src文件夹下views文件夹下permission文件夹下role文件夹下,新建index.vue,代码如下
<template>
<div class="app-container"><div class="filter-container" style="float:left;">
<el-form :inline="true" :model="searchParams" class="demo-form-inline">
<el-form-item>
<el-input v-model="searchParams.id" style="width: 160px;" placeholder="请输入ID" clearable></el-input>
</el-form-item>
<el-form-item>
<el-input v-model="searchParams.rolename" style="width: 180px;" placeholder="请输入角色组名称" clearable></el-input>
</el-form-item>
<el-form-item>
<el-input v-model="searchParams.role_key" style="width: 180px;" placeholder="请输入Key" clearable></el-input>
</el-form-item>
<el-form-item>
<el-button class="search-btn el-button--infoSearch" type="primary" @click="search()">搜索</el-button>
<el-button class="search-btn el-button--infoSearch" @click="clearSearch" style="background:#F2F6FC;">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="filter-container" style="float:right;">
<el-button v-if="$store.getters.butts.includes('PermissionRoleIndexAdd')" class="filter-item" style="margin-left: 10px;" type="primary" @click="handleAdd">添加</el-button>
<el-button class="filter-item" style="margin-left: 10px;" @click="search()">刷新</el-button>
<el-button v-if="$store.getters.butts.includes('PermissionRoleIndexTostatus')" class="filter-item" style="margin-left: 10px;" @click="handleStatus(1)" type="success">启用</el-button>
<el-button v-if="$store.getters.butts.includes('PermissionRoleIndexTostatus')" class="filter-item" style="margin-left: 10px;" @click="handleStatus(0)" type="warning">禁用</el-button>
<el-button v-if="$store.getters.butts.includes('PermissionRoleIndexDelete')" class="filter-item" @click="handleDelete" type="danger">删除</el-button>
</div>
<el-table
ref="resTable"
v-loading="listLoading"
:data="list"
row-key="id"
highlight-current-row
max-height="750"
default-expand-all
style="width: 100%;margin-top:10px;"
border
:default-sort = "{prop: 'id', order: 'descending'}"
>
<el-table-column type="selection" width="50" align="center" :selectable="canSelect" />
<el-table-column align="center" label="ID" sortable prop="id">
<template slot-scope="{row}">
{{ row.id }}
</template>
</el-table-column>
<el-table-column align="center" label="Key(前端权限标识)">
<template slot-scope="{row}">
{{ row.role_key }}
</template>
</el-table-column>
<el-table-column align="center" label="角色组名称">
<template slot-scope="{row}">
<el-tag>{{ row.rolename }}</el-tag>
</template>
</el-table-column>
<el-table-column align="center" label="菜单组" :show-overflow-tooltip='true'>
<template slot-scope="{row}">
{{ row.menus }}
</template>
</el-table-column>
<el-table-column align="center" label="状态">
<template slot-scope="{row}">
<el-tag>{{ row.status === 1 ? '启用' : '禁用' }}</el-tag>
</template>
</el-table-column>
<el-table-column align="center" label="添加时间">
<template slot-scope="{row}">
<span>{{ row.create_time }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="修改时间">
<template slot-scope="{row}">
<span>{{ row.update_time }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="操作" width="210">
<template slot-scope="{row}">
<el-button v-if="$store.getters.butts.includes('PermissionRoleIndexDetails')" size="mini" @click="handleDetails(row.id)" type="info">详情</el-button>
<el-button v-if="$store.getters.butts.includes('PermissionRoleIndexEdit')" type="primary" size="small" @click="handleEdit(row.id)">编辑</el-button>
<el-button v-if="$store.getters.butts.includes('PermissionRoleIndexDelete') && row.role_key != 'SuperAdmin'" size="small" @click="handleDelete(row.id)" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="block">
<el-pagination
:hide-on-single-page="true"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="pageSizes"
:page-size="currentSize"
layout="total, sizes, prev, pager, next, jumper"
:total="dataTotal">
</el-pagination>
</div>
<el-dialog :visible.sync="dialogVisible" :title="resTemp.id === 0 ? '添加' : '编辑'" :close-on-click-modal="false" :close-on-press-escape="false">
<el-form ref="resForm" :rules="formRules" :model="resTemp" label-width="80px" label-position="left">
<el-form-item label="名称" prop="rolename">
<el-input v-model="resTemp.rolename" placeholder="请输入名称" />
</el-form-item>
<el-form-item label="Key" prop="role_key">
<el-input v-model="resTemp.role_key" placeholder="请输入角色组Key" v-if="resTemp.role_key != 'SuperAdmin'" />
<el-input v-model="resTemp.role_key" placeholder="请输入角色组Key" v-if="resTemp.role_key == 'SuperAdmin'" disabled />
</el-form-item>
<el-form-item label="路由菜单" prop="rules">
<el-tree
ref="tree"
:data="routes"
:props="defaultProps"
show-checkbox
node-key="id"
>
</el-tree>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-switch
v-model="resTemp.status"
active-value="1"
inactive-value="0">
</el-switch>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible=false">取消</el-button>
<el-button v-if="$store.getters.butts.includes('PermissionRoleIndexSave')" type="primary" @click="saveInfo()">提交</el-button>
</div>
</el-dialog>
<el-dialog :visible.sync="dialogDetails" title="详情" :close-on-click-modal="false" :close-on-press-escape="false">
<el-form ref="resDetailsForm" :model="resDetailsTemp" label-width="80px" label-position="left">
<el-form-item label="名称">
<el-input v-model="resDetailsTemp.rolename" placeholder="请输入名称" disabled />
</el-form-item>
<el-form-item label="Key">
<el-input v-model="resDetailsTemp.role_key" placeholder="请输入角色组Key" disabled />
</el-form-item>
<el-form-item label="路由菜单">
<el-tree
ref="treeDetails"
:data="routesDetails"
:props="defaultProps"
show-checkbox
node-key="id"
>
</el-tree>
</el-form-item>
<el-form-item label="状态">
<el-switch
v-model="resDetailsTemp.status"
active-value="1"
inactive-value="0"
disabled
>
</el-switch>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogDetails=false">取消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import path from 'path'
import { succ, warn, err } from '@/utils/message';
import { getInfo, getList, saveInfo, deleteInfo, statusInfo } from '@/api/permission/role'
import { getAll } from '@/api/permission/menu'
import moment from 'moment'
export default {
name: 'PermissionRoleIndex', // 名空间
data() {
//角色组验证
const validateRules = (rule, value, callback) => {
const checkedKeys = this.$refs.tree.getCheckedKeys()
if (checkedKeys.length === 0) {
callback(new Error('请选择路由菜单'))
} else {
this.resTemp.rules = checkedKeys
callback()
}
}
return {
//要提交数据
resTemp:{
id: 0,//0 添加 >0 编辑
rolename:'',
role_key:'',
rules:[],
status:'1'
},
resDetailsTemp:{
id: 0,//0 添加 >0 编辑
rolename:'',
role_key:'',
rules:[],
status:'1'
},
routes: [],
routesDetails: [],
list: [],
pageSizes:[10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500],
currentPage: 1,//当前页数
currentSize:10,//每页条数
dataTotal:0,//总数据
searchParams:{
id:'',
rolename:'',
role_key:''
},
//要验证数据
formRules: {
rolename: [
{ required: true, trigger: 'blur', message: '必须填写' },
{ min: 2, max: 30, message: '长度在 2 到 30 个字符', trigger: 'blur' }
],
role_key: [
{ required: true, trigger: 'change', message: '角色组Key' },
{ min: 2, max: 30, message: '长度在 2 到 30 个字符', trigger: 'blur' }
],
rules: [
{ required: true, validator: validateRules, trigger: 'blur' }
],
},
listLoading: true,
dialogVisible: false,
dialogDetails: false,
defaultProps: {
children: 'children',
label: 'title'
}
}
},
computed: {
},
created() {
this.getList()
this.getAll(false)// 获取文件类数据
},
methods: {
// 搜索
search() {
this.currentPage = 1;
this.getList(1)
},
// 列表
async getList(page=0) {
let params = {
currentPage:page === 0 ? this.currentPage : page,
currentSize:this.currentSize,
...this.searchParams
};
this.listLoading = true
await getList(params).then(res => {
this.list = res.data.list
this.dataTotal = res.data.meat.total*1;
// 延时
setTimeout(() => {
this.listLoading = false
}, 0.5 * 1000)
})
},
// 所有菜单
async getAll() {
const res = await getAll()
this.routes = this.generateRoutes(res.data,'/',false)
},
// 重塑路由结构,使其看起来与侧边栏相同
generateRoutes(routes, basePath = '/',disabled) {
const res = []
for (const route of routes) {
// 路由是否隐藏
if (route.hidden) { continue }
const data = {
path: path.resolve(basePath, route.path),
title: route.title,
id: route.id,
disabled:disabled
}
// 子路由处理
if (route.children) {
data.children = this.generateRoutes(route.children, data.path, disabled)
}
res.push(data)
}
return res
},
//重置表单数据 ---添加时候需要使用
resetTemp() {
this.resTemp = {
id: 0,//0 添加 >0 编辑
rolename:'',
role_key:'',
rules:[],
status:'1'
}
},
// 添加
handleAdd() {
this.resetTemp()
this.dialogVisible = true
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys([]);
this.$refs.tree.setCheckedNodes([]);
this.$refs['resForm'].clearValidate()
})
},
// 编辑
handleEdit(id) {
getInfo({id:id}).then(res=>{
let row = res.data
row.rules = row.menu_id.split(',')
this.resTemp = Object.assign({}, row)
this.resTemp.status = row.status+''//将数字强行转换成字符串
this.$nextTick(() => {
//优先清理一下
this.$refs.tree.setCheckedKeys([]);
this.$refs.tree.setCheckedNodes([]);
//清理完毕了再操作
row.rules.forEach(item => {
this.$refs.tree.getNode(item).checked = true;
this.$refs.tree.getNode(item).parent.checked = true;
this.$refs.tree.getNode(item).parent.indeterminate = false;
})
this.$refs['resForm'].clearValidate()
})
this.dialogVisible = true
})
},
handleDetails(id){
getAll().then(res => {
this.routesDetails = this.generateRoutes(res.data,'/',true)
getInfo({id:id}).then(res=>{
let row = res.data
row.rules = row.menu_id.split(',')
this.resDetailsTemp = Object.assign({}, row)
this.resDetailsTemp.status = row.status+''//将数字强行转换成字符串
this.$nextTick(() => {
//优先清理一下
this.$refs.treeDetails.setCheckedKeys([]);
this.$refs.treeDetails.setCheckedNodes([]);
//清理完毕了再操作
row.rules.forEach(item => {
this.$refs.treeDetails.getNode(item).checked = true;
this.$refs.treeDetails.getNode(item).parent.checked = true;
this.$refs.treeDetails.getNode(item).parent.indeterminate = false;
})
this.$refs['resDetailsForm'].clearValidate()
})
this.dialogDetails = true
})
});
},
// 保存
async saveInfo() {
this.$refs.resForm.validate(valid => {
if(valid) {
this.resTemp.menu_id = this.getCheckedKeys(this.routes, this.$refs.tree.getCheckedKeys(), 'id');//重新组合权限
this.loading = true
saveInfo(this.resTemp).then(res=>{
this.loading = false
succ(res.message)
this.getList()
this.dialogVisible = false
});
} else {
return false
}
})
},
//内部递归寻找父类组合
getCheckedKeys (data, keys, key) {
var res = [];
recursion(data, false);
return res;
// arr -> 树形总数据
// keys -> getCheckedKeys获取到的选中key值
// isChild -> 用来判断是否是子节点
function recursion (arr, isChild) {
var aCheck = [];
for ( var i = 0; i < arr.length; i++ ) {
var obj = arr[i];
aCheck[i] = false;
if ( obj.children ) {
aCheck[i] = recursion(obj.children, true) ? true : aCheck[i];
if ( aCheck[i] ) {
res.push(obj[key]);
}
}
for ( var j = 0; j < keys.length; j++ ) {
if ( obj[key] == keys[j] ) {
aCheck[i] = true;
if ( res.indexOf(obj[key]) == -1 ) {
res.push(obj[key]);
}
break;
}
}
}
if ( isChild ) {
return aCheck.indexOf(true) != -1;
}
}
},
//删除
handleDelete(id) {
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
center: true
}).then(async() => {
const ids = []
if(id > 0){//单个删除
ids.push(id)
}else{//批量删除
const select = this.$refs.resTable.selection
if(select.length === 0){
warn('批量删除必须选择指定产品');
return false;
}
//组合数据
select.forEach(item => {
ids.push(item.id)
})
}
//删除
deleteInfo({id:ids}).then(res=>{
this.getList()//更新列表
succ(res.message)//提示结果
})
}).catch(err => {
err(err.message)
return false
})
},
// 启禁用
handleStatus(status){
let statusText = status == 1 ? '启用' : '禁用';
this.$confirm('此操作将永久'+ statusText +'该产品, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
center: true
}).then(async() => {
const ids = []
const select = this.$refs.resTable.selection
if (select.length === 0) {
warn('批量'+ statusText +'必须选择指定产品')
return false
}
// 组合数据
select.forEach(item => {
ids.push(item.id)
})
// 删除
statusInfo({ id: ids, status:status }).then(res => {
this.getList()//更新列表
succ(res.message)// 提示结果
})
}).catch(err => {
err(err.message)
return false
})
},
// 禁止选择超级管理员组
canSelect(row) {
return row.role_key === 'SuperAdmin' ? 0 : 1
},
//清除搜索功能
clearSearch(){
this.searchParams = {
id:'',
rolename:'',
key:''
}
this.currentPage = 1;
this.getList()
},
//条数切换
handleSizeChange(val) {
this.currentSize = val;
this.getList();
},
//页数切换
handleCurrentChange(val) {
this.currentPage = val;
this.getList();
}
}
}
</script>
<style lang="scss" scoped>
.app-container {
padding:10px;
.roles-table {
margin-top: 30px;
}
.permission-tree {
margin-bottom: 30px;
}
}
.el-tooltip__popper{
max-width:20%;
}
.el-tooltip__popper,.el-tooltip__popper.is-dark{
background:rgb(48, 65, 86) !important;
color: #fff !important;
line-height: 24px;
}
</style>
二、添加ajax请求
在根目录下src文件夹下api文件夹下permission文件夹下role.js,代码如下
import request from '@/utils/request'
// 列表
export function getList(params) {
return request({
url: '/permission/role/get_list',
method: 'get',
params:params
})
}
// 所有
export function getAll() {
return request({
url: '/permission/role/get_all',
method: 'post'
})
}
// 获取
export function getInfo(data) {
return request({
url: '/permission/role/get_info',
method: 'post',
data
})
}
// 保存
export function saveInfo(data) {
return request({
url: '/permission/role/save_info',
method: 'post',
data
})
}
// 删除
export function deleteInfo(data) {
return request({
url: '/permission/role/delete_info',
method: 'post',
data
})
}
// 启禁用
export function statusInfo(data) {
return request({
url: '/permission/role/status_info',
method: 'post',
data
})
}
三、提前说明
明天将开发岗位配置、级别配置功能。