目录
1-角色列表
1.1-原型需求分析
1.2-接口封装和数据类型定义
1.3-请求服务器端获取列表页面数据
1.4-组件页面动态渲染数据
2-角色新增和编辑
2.1-需求原型分析
2.2-页面结构以及功能实现
3-角色的删除
4-分配权限
4.1-原型需求分析
4.2-获取服务器数据渲染数据
4.3-分配权限
页面布局结构和上一节用户管理列表页面类似,上部分是el-card里面有个行内的表单el-form :inline="true";一个搜索输入框,两个按钮。下部分是一个el-card里面有个按钮和el-table组件。操作列有三个按钮组件。最下面是一个分页el-pagination组件。所以列表页面就请求服务器端一个接口,角色列表接口。
本节我们就把此模块需要用到的接口全部封装,后续章节就不用重复编写接口和数据类型的定义了。
文件src\api\acl\role\index.ts定义此模块需要用到的接口信息
//角色管理模块的的接口
import request from '@/utils/request'
import type { RoleResponseData, RoleData, MenuResponseData } from './type'
//枚举地址
enum API {
ALLROLE_URL = '/admin/acl/role/',//获取全部的职位接口
ADDROLE_URL = '/admin/acl/role/save',//新增岗位的接口地址
UPDATEROLE_URL = '/admin/acl/role/update',//更新已有的职位
ALLPERMISSTION = '/admin/acl/permission/toAssign/',//获取全部的菜单与按钮的数据
SETPERMISTION_URL = '/admin/acl/permission/doAssign/?',//给相应的职位分配权限
REMOVEROLE_URL = '/admin/acl/role/remove/',//删除已有的职位
}
//获取全部的角色
export const reqAllRoleList = (page: number, limit: number, roleName: string) =>
request.get(
API.ALLROLE_URL + `${page}/${limit}/?roleName=${roleName}`,
)
//添加职位与更新已有职位接口
export const reqAddOrUpdateRole = (data: RoleData) => {
if (data.id) {
return request.put(API.UPDATEROLE_URL, data)
} else {
return request.post(API.ADDROLE_URL, data)
}
}
//获取全部菜单与按钮权限数据
export const reqAllMenuList = (roleId: number) =>
request.get(API.ALLPERMISSTION + roleId)
//给相应的职位下发权限
export const reqSetPermisstion = (roleId: number, permissionId: number[]) =>
request.post(
API.SETPERMISTION_URL + `roleId=${roleId}&permissionId=${permissionId}`,
)
//删除已有的职位
export const reqRemoveRole = (roleId: number) =>
request.delete(API.REMOVEROLE_URL + roleId)
文件src\api\acl\role\type.ts定义接口请求响应的数据类型
export interface ResponseData {
code: number
message: string
ok: boolean
}
//职位数据类型
export interface RoleData {
id?: number
createTime?: string
updateTime?: string
roleName: string
remark?: null
}
//全部职位的数组的ts类型
export type Records = RoleData[]
//全部职位数据的相应的ts类型
export interface RoleResponseData extends ResponseData {
data: {
records: Records
total: number
size: number
current: number
orders: []
optimizeCountSql: boolean
hitCount: boolean
countId: null
maxLimit: null
searchCount: boolean
pages: number
}
}
//菜单与按钮数据的ts类型
export interface MunuData {
id: number
createTime: string
updateTime: string
pid: number
name: string
code: string
toCode: string
type: number
status: null
level: number
children?: MenuList
select: boolean
}
export type MenuList = MunuData[]
//菜单权限与按钮权限数据的ts类型
export interface MenuResponseData extends ResponseData {
data: MenuList
}
在组件页面加载后,我们需要调用角色列表接口获取数据,搜索框输入关键字我们收集到关键字也需要获取数据,页码和页大小发生变化的时候我们同样需要调用接口重新获取列表数据。
import { ref, onMounted, reactive, nextTick } from 'vue';
//请求方法
import { reqRemoveRole, reqAllRoleList, reqAddOrUpdateRole, reqAllMenuList, reqSetPermisstion } from '@/api/acl/role';
import type { RoleResponseData, Records, RoleData, MenuResponseData, MenuList } from '@/api/acl/role/type'
//引入骨架的仓库
import useLayOutSettingStore from '@/store/modules/setting';
import { ElMessage } from 'element-plus';
let pageNo = ref(1);//当前页码
let pageSize = ref(5);//一页展示几条数据
let keyword = ref('');//搜索职位关键字
let allRole = ref([]);//存储全部已有的职位
let total = ref(0);//职位总个数
//组件挂载完毕
onMounted(() => {
//获取职位请求
getHasRole();
});
//获取全部用户信息的方法|分页器当前页码发生变化的回调
const getHasRole = async (pager = 1) => {
//修改当前页码
pageNo.value = pager;
let result: RoleResponseData = await reqAllRoleList(pageNo.value, pageSize.value, keyword.value);
if (result.code == 200) {
total.value = result.data.total;
allRole.value = result.data.records;
}
}
//下拉菜单的回调
const sizeChange = () => {
getHasRole();
}
当我们搜索框输入内容后,我们收集搜索关键字进行搜索。ps:请求接口后,可以优化不清空关键字(当然看个人项目的实际要求,个人认为展示关键字,可以让用户直观看到自己是按照什么关键字搜索的),点击重置才清空关键字。
//搜索按钮的回调
const search = () => {
//再次发请求根据关键字
getHasRole();
keyword.value = '';
}
当我们点击重置按钮的时候,重新刷新
//引入骨架的仓库
import useLayOutSettingStore from '@/store/modules/setting';
//重置按钮的回调
const reset = () => {
settingStore.refsh = !settingStore.refsh;
}
当我们列表页面数据的时候,需要在el-card中展示数据。
点击新增或者编辑都弹出dialog对话框,使用el-dialog组件,里面使用el-form表单组件,只有一个表单元素el-form-item;新增和编辑的标题不一样,根据是否有id值判断。表单元素输入框需要校验。点击保存提交数据,点击取消,隐藏dialog对话框。
页面结构如下:
校验规则
//自定义校验规则的回调
const validatorRoleName = (rule: any, value: any, callBack: any) => {
if (value.trim().length >= 2) {
callBack();
} else {
callBack(new Error('职位名称至少两位'))
}
}
//角色校验规则
const rules = {
roleName: [
{ required: true, trigger: 'blur', validator: validatorRoleName }
]
}
点击新增按钮逻辑
//控制对话框的显示与隐藏
let dialogVisite = ref(false);
//获取form组件实例
let form = ref();
//添加职位按钮的回调
const addRole = () => {
//对话框显示出来
dialogVisite.value = true;
//清空数据
Object.assign(RoleParams, {roleName: '',id: 0});
//清空上一次表单校验错误结果
nextTick(() => {
form.value.clearValidate('roleName');
})
}
点击编辑按钮逻辑
//收集新增岗位数据
let RoleParams = reactive({
roleName: ''
})
//更新已有的职位按钮的回调
const updateRole = (row: RoleData) => {
//显示出对话框
dialogVisite.value = true;
//存储已有的职位----带有ID的
Object.assign(RoleParams, row);
//清空上一次表单校验错误结果
nextTick(() => {
form.value.clearValidate('roleName');
})
}
点击保存按钮,首先需要先通过校验规则,校验规则通过再提交数据给服务端。
点击取消按钮,直接隐藏掉dialog对话框,
点击删除操作按钮时,需要弹框提示用户,用户点击确定后,提交数据给服务器。如果当前页数据大于1,停留在当前页,小于1,请求上一页的数据。
//删除已有的职位
const removeRole = async (id: number) => {
let result: any = await reqRemoveRole(id);
if (result.code == 200) {
//提示信息
ElMessage({ type: 'success', message: '删除成功' });
getHasRole(allRole.value.length > 1 ? pageNo.value : pageNo.value - 1);
}
}
点击某一个角色的分配权限按钮,需要查询当前角色的已有权限数据和全部的权限数据,服务端接口,目前服务端是全部返回,在每个权限里面有个标记字段select字段,字段为true表示当前角色有该权限。然后需要过滤出该角色拥有的权限,使用el-tree组件来实现上图效果。
请求服务端获取数据,获取全部权限,然后过滤出当前角色拥有的权限,过滤过程中,需要递归过滤,存放level=4的数据就行,目前系统第四级的是按钮权限。
//准备一个数组:数组用于存储勾选的节点的ID(四级的)
let selectArr = ref([]);
//定义数组存储用户权限的数据
let menuArr = ref([]);
//获取tree组件实例
let tree = ref();
let drawer = ref(false);//控制抽屉显示与隐藏
//分配权限按钮的回调
//已有的职位的数据
const setPermisstion = async (row: RoleData) => {
//抽屉显示出来
drawer.value = true;
//收集当前要分类权限的职位的数据
Object.assign(RoleParams, row);
//根据职位获取权限的数据
let result: MenuResponseData = await reqAllMenuList((RoleParams.id as number));
if (result.code == 200) {
menuArr.value = result.data;
selectArr.value = filterSelectArr(menuArr.value, []);
}
}
const filterSelectArr = (allData: any, initArr: any) => {
allData.forEach((item: any) => {
if (item.select && item.level == 4) {
initArr.push(item.id);
}
if (item.children && item.children.length > 0) {
filterSelectArr(item.children, initArr);
}
})
return initArr;
}
在el-tree组件中渲染数据:
当我们点击确定的时候,我们需要收集选中的节点数据id,传递给服务器。在el-tree插件中,我们有api获取选中的节点id和半选的节点id。我们合并两个数组,将数组传递给服务器端。点击取消按钮,直接隐藏当前抽屉就行。
//抽屉确定按钮的回调
const handler = async () => {
const roleId = (RoleParams.id as number);//职位的ID
let arr = tree.value.getCheckedKeys();//选中节点的ID
let arr1 = tree.value.getHalfCheckedKeys(); //半选的ID
let permissionId = arr.concat(arr1);
//下发权限
let result: any = await reqSetPermisstion(roleId, permissionId);
if (result.code == 200) {
drawer.value = false;//抽屉关闭
ElMessage({ type: 'success', message: '分配权限成功' });//提示信息
window.location.reload();//页面刷新
}
}