在element plus的表格中,这里我使用的是,2.3.4的版本
这里使用到的事件有
因为父子级并没有联系,所以会有问题,这个就需要自己去实现了,只有勾选了,就会项上面说的那样,会自动添加到对应的数组中的。这个不用担心是否会添加到那个数组中,勾选多个也会同时添加到对应的数组中的。通过给的默认事件获取就行
这就是一个组件,可以直接复制这代码到某个组件中进行试着展示一下就知道了
<template>
<el-table ref="multipleTableRef" :data="tableData" style="width: 100%" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column label="Date" width="120">
<template #default="scope">{{ scope.row.date }}</template>
</el-table-column>
<el-table-column property="name" label="Name" width="120" />
<el-table-column property="address" label="Address" show-overflow-tooltip />
</el-table>
<div style="margin-top: 20px">
<!-- 这里的[tableData[1], tableData[2]]是与table绑定的数组tableData的数据项 -->
<el-button @click="toggleSelection([tableData[1], tableData[2]])">
选中第二第三行是与table绑定的数组数据
</el-button>
<el-button @click="toggleSelection()">
清除以选中的选型
</el-button>
<!-- 这里的[userList[1], userList[2]]不是与table绑定的数组的数据项,这个点击的时候可以勾选,但复选框样式失效 -->
<el-button @click="userListToggleSelection([userList[1], userList[2]])">不是与table绑定的数组项,可以勾选得到数据,但复选框样式失效</el-button>
<!-- 这里的[userListFormTableData[1], userListFormTableData[2]],数据是从与table绑定的数据tableData遍历得来的,所以复选框生效-->
<el-button @click="userListFormTableDataToggleSelection([userListFormTableData[1], userListFormTableData[2]])">
数据是从与table绑定的数据tableData遍历得来的,即可以得到数据,复选框样式也生效
</el-button>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import { ElTable } from 'element-plus'
interface User {
date: string
name: string
address: string
}
const tableData: User[] = [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-08',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-06',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-07',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
}
]
const multipleTableRef = ref<InstanceType<typeof ElTable>>()
const multipleSelection = ref<User[]>([])
const toggleSelection = (rows?: User[]) => {
if (rows) {
rows.forEach((row) => {
/**
* 这里要特别注意,这row必须是与表格绑定的tableData的数据的项,具体看上放方传入的参数
* 是:[tableData[1], tableData[2]]
* 不是随便一个数据都行的
*/
// @ts-expect-error,这个可以忽略ts语法的错误提示
multipleTableRef.value!.toggleRowSelection(row, undefined)
})
} else {
multipleTableRef.value!.clearSelection()
}
}
const handleSelectionChange = (val: User[]) => {
console.log(val)
multipleSelection.value = val
}
/**
*
* @param rows 非跟table绑定的数组项
*/
const userListToggleSelection = (rows?: User[]) => {
if (rows) {
rows.forEach((row) => {
/**
* 这里要特别注意,这row必须是与表格绑定的tableData的数据的项,具体看上放方传入的参数
* 是:[userList[1], userList[2]],并不是table绑定的数组中的tableData的数子,所以这里
* multipleTableRef.value!.toggleRowSelection(row, undefined),生效了,得到数据了,但是复选框样式不生效
* 与userList是否是ref修饰的响应式数据无关
*/
// @ts-expect-error,这个可以忽略ts语法的错误提示
multipleTableRef.value!.toggleRowSelection(row, undefined)
})
} else {
multipleTableRef.value!.clearSelection()
}
}
const userList: User[] = [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-08',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-06',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
},
{
date: '2016-05-07',
name: 'Tom',
address: 'No. 1, Grove St, Los Angeles',
}
]
const userListFormTableData: User[] = []
const getUserListFormTableData = () => {
tableData.forEach((item: User) => {
userListFormTableData.push(item)
})
}
const userListFormTableDataToggleSelection = (rows: User[]) => {
if (rows) {
rows.forEach((row) => {
/**
* 这里要特别注意,这row必须是与表格绑定的tableData的数据的项,具体看上放方传入的参数
* 是:[userListFormTableData[1], userListFormTableData[2]],虽然不是tableData
* 但是这个数组的数据是从tableData中遍历得来的,所以里面的数据项,跟tableData指向同一个地址
* multipleTableRef.value!.toggleRowSelection(row, undefined),也是可以生效的,复选框样式也生效
* 与userListFormTableData是否是ref修饰的响应式数据无关
*/
// @ts-expect-error,这个可以忽略ts语法的错误提示
multipleTableRef.value!.toggleRowSelection(row, undefined)
})
} else {
multipleTableRef.value!.clearSelection()
}
}
onMounted(() => {
getUserListFormTableData()
})
</script>
这里吐槽一手,直接使用element plus的 更好,什么父子级联级选择,都实现了,只要稍微配置一下属性就好了。比在表格中使用这个更加实在,
建议不要使用这种方式,还有自己写父子级关联的逻辑。真心不建议使用上述gif图中的方式,如果是做权限分配的话。
这里先把代码,贴出来,具体代码的解释看后面,注意了,以下代码都是基于表格的树形结构只有两层的情况下进行的(也就是只有一个children),如果是多层,需要在代码中进行处理,递归的方式就挺不错的,注意看代码中使用到children的地方。
<template>
<div class="role-container">
<div style="height: 82%;">
<el-row style="height: 100%;">
<el-table :data="tableData" border style="width: 100%; height: 100%;">
<el-table-column width="225" label="操作">
<template #default="scope">
<!-- 注意了这里 handleCommand(command, scope.row) 传入了row,这里自己表格对应的行内容,根据自己表格来修改
这里是为了保证完整性我才没去掉的-->
<el-dropdown style="margin-left: 15px"
@command="(command: string | number | object) => handleCommand(command, scope.row)">
<!-- 表格的点击事件 -->
<el-button size="small" type="primary" plain>》更多</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="handleRoleAuth">分配权限</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-table-column>
</el-table>
</el-row>
<!-- 分配权限弹窗 -->
<el-dialog v-model="dialogVisibleRoleAuth" label-width="80px" title="角色菜单权限分配" width="600px"
@close="dialogVisibleRoleAuthClose">
<el-from>
<el-from-item>
<el-table ref="multipleTableRef" :data="roleMenuListTableData" border row-key="menuId" default-expand-all
@selection-change="handleSelectionChange" @select="handleSelect" @select-all="handleSelectAll">
<!--
@selection-change="handleSelectionChange"
@select="handleSelect"
@select-all="handleSelectAll"
是官网的内置事件
-->
<el-table-column type="selection" width="55" />
<el-table-column prop="menuName" label="菜单名称" />
<el-table-column label="菜单类型">
<template #default="scope">
<el-tag type="info" v-if="scope.row.menuType === 'M'">目录</el-tag>
<el-tag v-else-if="scope.row.menuType === 'C'">运维菜单</el-tag>
<el-tag type="success" v-else>前端菜单</el-tag>
</template>
</el-table-column>
</el-table>
</el-from-item>
</el-from>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisibleRoleAuth = false">取消</el-button>
<el-button type="primary" @click="fenPeiQuanXian">分配权限</el-button>
</span>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
// 这个是api接口,具体看后面的代码解释的内容,不需要关心这个
import { updateRoleAuthMenu, roleAuthMenuListByRoleId } from '../api/role';
// 这个是api接口,具体看后面的代码解释的内容,不需要关心这个
import { menuList } from '../api/menu'
// 数据类型定义,具体看后面的代码解释的内容,不需要关心这个
// import { Menu } from '../responsemodel/responseMenu.ts';
// 数据类型定义,具体看后面的代码解释的内容,不需要关心这个
// import { Role } from '../responsemodel/responseRole.ts';
// 菜单类型定义
/**
* Menu
*/
interface Menu {
/**
* 组件路径
*/
component?: string;
/**
* 创建者
*/
createBy?: string;
/**
* 创建时间
*/
createTime?: string;
/**
* 菜单图标
*/
icon?: string;
/**
* 菜单ID
*/
menuId?: number;
/**
* 菜单名称
*/
menuName?: string;
/**
* 菜单类型(M目录 C运维菜单 F前端菜单)
*/
menuType?: string;
/**
* 显示顺序
*/
orderNum?: number;
/**
* 父菜单ID
*/
parentId?: number;
/**
* 路由地址
*/
path?: string;
/**
* 权限标识
*/
perms?: string;
/**
* 路由参数
*/
query?: string;
/**
* 备注
*/
remark?: string;
/**
* 菜单状态(0正常 1停用)
*/
status?: string;
/**
* 更新者
*/
updateBy?: string;
/**
* 更新时间
*/
updateTime?: string;
/**
* 菜单子集
*/
children?: Menu[]
}
// 角色类型定义
/**
* Role
*/
export interface Role {
/**
* 创建者
*/
createBy?: string;
/**
* 创建时间
*/
createTime?: string;
/**
* 删除标志(0代表存在 1代表删除)
*/
delFlag?: string;
/**
* 备注
*/
remark?: string;
/**
* 角色ID
*/
roleId?: number;
/**
* 角色权限字符串
*/
roleKey?: string;
/**
* 角色名称
*/
roleName?: string;
/**
* 显示顺序
*/
roleSort?: number;
/**
* 角色状态(0正常 1停用)
*/
status?: string;
/**
* 更新者
*/
updateBy?: string;
/**
* 更新时间
*/
updateTime?: string;
}
import { ElMessage, ElTable } from 'element-plus'
let tableData = ref([])
/**分配配权限 */
const dialogVisibleRoleAuth = ref(false)
const queryMenuParams = reactive({
menuName: undefined,
menuType: undefined
})
const roleMenuListTableData = ref([])
const multipleTableRef = ref<InstanceType<typeof ElTable>>()
const menuIds = ref<(number | undefined)[]>([])
const roleId = ref()
let selectRoleMenuList = reactive<Menu[]>([])
/**
* 用户回显的,加弹窗展示,不需要回显的可以不用看这个
*/
const handleCommand = async (command: string | number | object, row: Role) => {
if (command === 'handleRoleAuth') {
selectRoleMenuList = []
// 这里是发送axios请求,得到的表格的菜单列表数据,树形结构,具体数据看后面说明
const result = await menuList(queryMenuParams)
roleMenuListTableData.value = result.data.data
dialogVisibleRoleAuth.value = true
roleId.value = row.roleId
// 发送axios请求,这个是传入角色id,然后根据id获取角色具有的菜单,这个是非树形结构,
// 这个回显角色具有的菜单选项时需要用到,具体数据看后面的代码说明,不同的角色具有的菜单权限是不一样的
const result2 = await roleAuthMenuListByRoleId(row.roleId)
selectRoleMenuList = result2.data.data
const selectRomeMenuLists: Menu[] = []
// 下面这个就是将菜单列表和角色权限列表,找出相同的,然后放到一个数组中,非树形结构
if (selectRoleMenuList) {
selectRoleMenuList.forEach((row: Menu) => {
// 这里的数据值考虑两层,也就是只有一个Children的情况,如果是多层,可以考虑递归
roleMenuListTableData.value.forEach((item: Menu) => {
if (item.children) {
item.children.forEach((childrenItem: Menu) => {
if (childrenItem.menuId === row.menuId && childrenItem.menuName === row.menuName) {
selectRomeMenuLists.push(childrenItem)
}
})
}
if (row.menuId === item.menuId && row.menuName === item.menuName) {
selectRomeMenuLists.push(item)
}
})
})
}
toggleSelection(selectRomeMenuLists)
}
}
/**
* 选择复选框,这里面处理了父子间的联级选择的问题
*/
const toggleSelection = (rows?: Menu[]) => {
if (rows) {
rows.forEach((item: Menu) => {
multipleTableRef.value!.toggleRowSelection(item, true)
})
// 获取当前复选框勾选的行,因为表格中,如果勾选了父选项,子选项也会全部勾选的,上面的注意事项中提到过,所以这里需要
// 排除某个角色中,没有的子选项权限,然后将 (选择状态 )变为 (未选择状态),这样回显才正确,这个
// multipleTableRef.value!.getSelectionRows()获得的是已经选中的,非树形结构的,数据
const selectionRows: Menu[] = multipleTableRef.value!.getSelectionRows()
// 获取对应的id为数组
const selectionRowPIds = selectionRows.map((item: Menu) => item.menuId)
// 获取对应的id为数组,这个selectRoleMenuList是上面提到的角色具有的权限的菜单列表,是非树形的结构,具体看后面代码解释中的数据
const selectRoleMenuListPIds = selectRoleMenuList.map((item: Menu) => item.menuId)
// 求差集,从选中的selectionRowPIds数组选项中,找到selectRoleMenuList数组不具有的数据选项,这就找到了对应角色不具有的菜单项的差集了,
// 然后把复选框的选择状态去掉,变为非选择状态
let diff = selectionRowPIds.filter(item => selectRoleMenuListPIds.indexOf(item) == -1);
// 将差集的选项勾选状态变为非选择状态
selectionRows.forEach((item: Menu) => {
diff.forEach(item2 => {
if (item.menuId === item2) {
multipleTableRef.value!.toggleRowSelection(item, false)
}
})
})
} else {
multipleTableRef.value!.clearSelection()
}
}
// 这两个是一个标记,为什么要加这两个,具体看后面的代码解释就知道了
let isFirstParentId = -1
let deleteParentId = -1
const handleSelect = (selection: Menu[], row: Menu) => {
// 这个selection是一个非树形结构的数组,上面的注意事项已经说明了
// 点击勾选的时候,或自动将勾选的项添加到selection这个数组中,点击取消勾选的时候会自动
// 将对应的(当前取消选择的)项从selection数组中移除,所以通过判断在selection数组中是否有对应的项
// 就可以判断中是否勾选了
// 复选框选中状态
if (selection.some((item: Menu) => item.menuId == row.menuId)) { // 复选框选中状态
// deleteParentId = -1、 isFirstParentId = -1。这两个标记,看后面解释代码的内容
deleteParentId = -1
isFirstParentId = -1
// 后端返回的数据中,这个就是,根节点的parentId就是0
if (row.parentId !== 0) {
// 判断选择的子节点中对应的父节点是否已经选择了
if (selection.some((item: Menu) => item.menuId == row.parentId)) {
isFirstParentId = -1
// console.log("已勾选父节点")
} else {
// 找父节点,点击某个子节点时候,如果父节点没有选上,则自动选择父节点,
// 记住了:这里值考虑两层数据的情况,也就是只有一个Children的情况,如果是多层数据,可以写一个方法,递归处理
const parentNode: any = roleMenuListTableData.value.find((item: Menu) => item.menuId == row.parentId)
multipleTableRef.value!.toggleRowSelection(parentNode, true)
parentNode.children.forEach((item: Menu) => {
if (item.menuId != row.menuId) {
multipleTableRef.value!.toggleRowSelection(item, false)
}
})
// ts数据类型断言,我这里知道了对应数据的id是number类型的
isFirstParentId = row.parentId as number
}
}
// console.log(selection)
// console.log("选中")
} else { // 非选中状态,也就是说取消复选框选中状态,执行这里的代码
// 判断所有选中的selection数组选项中,查找与当前取消选择时同一个父级parentId的选项,
// 判断是否有数据,如果没有存在一个父级选项相同的项,说明这个父级选项所有的子选项已经
// 是非选中状态了,这是就需要把对应的父级选项的(勾选状态)改为(非勾选状态)
// 也就是如果取消子选项选择状态的时候,子选项没有一个勾选的时,父选项就取消勾选
if (!(selection.some((item: Menu) => item.parentId == row.parentId))) {
selection.forEach((item: Menu) => {
if (item.menuId == row.parentId) {
multipleTableRef.value!.toggleRowSelection(item, false)
deleteParentId = item.menuId as number
}
})
}
// console.log(selection)
// console.log("取消选中")
}
}
/**
*
* @param val 勾选项变化的数组,这个官网有说明
*/
const handleSelectionChange = (val: Menu[]) => {
// 这里面是重新复制,而不是数组的push,所以这个数组会跟着val更新而更新的,
// 就不需要考虑后面push的时候的数据了。因为下一次就重新复制了,有没有push
// 对下一次进入这个方法都没有影响,更何况push之前还加了判断呢
menuIds.value = val.map(item => item.menuId)
if (isFirstParentId != -1) {
menuIds.value.push(isFirstParentId)
}
if (deleteParentId != -1) {
const index = menuIds.value.findIndex(item => item == deleteParentId)
if (index != -1) {
menuIds.value.splice(index, 1)
}
}
// console.log("选中长度:", menuIds.value.length)
// console.log(menuIds.value)
}
/**
* 全选,非全选
*/
// @ts-ignore
const handleSelectAll = (selection: Menu[]) => {
/**
* 全选和非全选无非就两种状态
* 1、要么selection > 0 全选,
* 2、要么selection < 0 非全选
* 或者使用element-plus中内置的标志判断是否需要进行全选,在对应的ref实例中可以找到
* multipleTableRef.value!.store.states.isAllSelected.value
*/
if (multipleTableRef.value!.store.states.isAllSelected.value) {
// console.log("全选");
// 因为这里只有两层数据,所以这里可以直接这样写,如果是多层数据,考虑递归的方式实现
roleMenuListTableData.value.forEach((item: Menu) => {
if (item.children!.length > 0) {
item.children!.forEach((item2: Menu) => {
multipleTableRef.value!.toggleRowSelection(item2, true)
})
}
})
}
// if (selection.length > 0) {
// roleMenuListTableData.value.forEach((item: Menu) => {
// if (item.children!.length > 0) {
// item.children!.forEach((item2: Menu) => {
// // 判断这个选中的selection中是否有对应的选,如果没有就设置选中,让其放入到selection中
// const index = selection.findIndex((selectionItem: Menu) => selectionItem.menuId == item2.menuId)
// if (index == -1) {
// multipleTableRef.value!.toggleRowSelection(item2, true)
// }
// })
// }
// })
// }
// console.log(selection)
}
const fenPeiQuanXian = async () => {
// 这个menuIds就是勾选得到的数组,handleSelectionChange()这个方法中,赋值的。
const menuIdToString = menuIds.value.join(',')
// 这个是发送一个axios请求,将角色id,和勾选的菜单选项的id数组,传给后端。然后后端根据,角色id先删除关联表的
// 内容,重新见角色id和菜单id循环插入数据关联表
const result = await updateRoleAuthMenu({ roleId: roleId.value, menuIds: menuIdToString })
if (result.data.code === 200) {
ElMessage({
type: 'success',
message: '分配菜单成功',
})
dialogVisibleRoleAuth.value = false
}
}
/**
* 关闭弹窗时的回调,具体看element plus的官网关于el-dialog的部分
*/
const dialogVisibleRoleAuthClose = () => {
isFirstParentId = -1
deleteParentId = -1
}
onMounted(() => {
})
</script>
<style lang="scss" scoped>
.role-container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
padding: 10px;
flex: 1;
}
</style>
菜单数据,也就是表格展示的数据,树形结构,在代码的位置如下所示
树形结构
[
{
"menuId": 100,
"menuName": "用户管理",
"parentId": 0,
"orderNum": 1,
"path": "user",
"component": "views/UserManager.vue",
"query": "",
"menuType": "C",
"status": "0",
"perms": "system:user:list",
"icon": "user",
"createBy": "admin",
"createTime": "2023-05-22T09:10:35",
"updateBy": "",
"updateTime": "2023-05-24T09:20:51",
"remark": "用户管理菜单",
"children": []
},
{
"menuId": 101,
"menuName": "角色管理",
"parentId": 0,
"orderNum": 2,
"path": "role",
"component": "views/RoleManager.vue",
"query": "",
"menuType": "C",
"status": "0",
"perms": "system:role:list",
"icon": "peoples",
"createBy": "admin",
"createTime": "2023-05-22T09:10:35",
"updateBy": "",
"updateTime": "2023-05-24T09:21:15",
"remark": "角色管理菜单",
"children": []
},
{
"menuId": 2003,
"menuName": "菜单管理",
"parentId": 0,
"orderNum": 3,
"path": "menus",
"component": "views/MenuManager.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": "system:menu",
"icon": "#",
"createBy": "",
"createTime": "2023-05-24T09:14:42",
"updateBy": "",
"updateTime": "2023-05-24T09:14:42",
"remark": "菜单管理",
"children": []
},
{
"menuId": 103,
"menuName": "部门管理",
"parentId": 0,
"orderNum": 4,
"path": "dept",
"component": "views/DeptManager.vue",
"query": "",
"menuType": "C",
"status": "0",
"perms": "system:dept:list",
"icon": "tree",
"createBy": "admin",
"createTime": "2023-05-22T09:10:35",
"updateBy": "",
"updateTime": "2023-05-24T09:21:46",
"remark": "部门管理菜单",
"children": []
},
{
"menuId": 500,
"menuName": "操作日志",
"parentId": 0,
"orderNum": 5,
"path": "operatelog",
"component": "views/OperateLogManager.vue",
"query": "",
"menuType": "C",
"status": "0",
"perms": "monitor:operlog:list",
"icon": "form",
"createBy": "admin",
"createTime": "2023-05-22T09:10:35",
"updateBy": "",
"updateTime": "2023-05-23T18:26:16",
"remark": "操作日志菜单说明",
"children": []
},
{
"menuId": 2007,
"menuName": "职位管理",
"parentId": 0,
"orderNum": 7,
"path": "post",
"component": "views/PostManager.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": "post:list",
"icon": "#",
"createBy": "",
"createTime": "2023-05-29T22:46:54",
"updateBy": "",
"updateTime": "2023-05-29T22:46:54",
"remark": "职位管理",
"children": []
},
{
"menuId": 2028,
"menuName": "进度圈管理",
"parentId": 0,
"orderNum": 8,
"path": "ProgressCircle",
"component": "views/ProgressCircle.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": "ProgressCircle:admin",
"icon": null,
"createBy": null,
"createTime": "2023-06-29T16:07:15.622081",
"updateBy": null,
"updateTime": "2023-06-29T16:07:15.622081",
"remark": "进度圈管理",
"children": []
},
{
"menuId": 2004,
"menuName": "项目管理",
"parentId": 0,
"orderNum": 9,
"path": "",
"component": null,
"query": null,
"menuType": "M",
"status": "0",
"perms": "adfadaa",
"icon": "#",
"createBy": "",
"createTime": "2023-05-24T09:49:19",
"updateBy": "",
"updateTime": "2023-05-24T09:49:19",
"remark": "系统管理",
"children": [
{
"menuId": 2005,
"menuName": "项目数据管理",
"parentId": 2004,
"orderNum": 1,
"path": "xiangmushuju",
"component": "views/ProjectData.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": "xiangmushuju",
"icon": "#",
"createBy": "",
"createTime": "2023-05-24T14:35:32",
"updateBy": "",
"updateTime": "2023-05-24T14:35:32",
"remark": "项目数据",
"children": []
},
{
"menuId": 2006,
"menuName": "空间数据管理",
"parentId": 2004,
"orderNum": 2,
"path": "kongjianshujuguanli",
"component": "views/SpatialData.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": null,
"icon": "#",
"createBy": "",
"createTime": "2023-05-24T15:02:23",
"updateBy": "",
"updateTime": "2023-05-24T15:02:23",
"remark": "项目空间数据管理",
"children": []
},
{
"menuId": 2010,
"menuName": "机械设备管理",
"parentId": 2004,
"orderNum": 3,
"path": "jixieshebei",
"component": "views/MechanicalData.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": null,
"icon": "#",
"createBy": "",
"createTime": "2023-06-05T14:51:19",
"updateBy": "",
"updateTime": "2023-06-05T14:51:19",
"remark": "机械设备管理",
"children": []
},
{
"menuId": 2008,
"menuName": "无人机数据",
"parentId": 2004,
"orderNum": 4,
"path": "wurenjishuju",
"component": "views/DroneData.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": null,
"icon": "#",
"createBy": "",
"createTime": "2023-06-05T14:47:39",
"updateBy": "",
"updateTime": "2023-06-05T14:47:39",
"remark": "无人机数据",
"children": []
},
{
"menuId": 2009,
"menuName": "民工管理",
"parentId": 2004,
"orderNum": 5,
"path": "mingongguanli",
"component": "views/MigrantWorkerData.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": null,
"icon": "#",
"createBy": "",
"createTime": "2023-06-05T14:49:32",
"updateBy": "",
"updateTime": "2023-06-05T14:49:32",
"remark": "民工管理",
"children": []
},
{
"menuId": 2011,
"menuName": "进度数据",
"parentId": 2004,
"orderNum": 6,
"path": "jindushuju",
"component": "views/ProgressData.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": null,
"icon": "#",
"createBy": "",
"createTime": "2023-06-05T14:53:39",
"updateBy": "",
"updateTime": "2023-06-05T14:53:39",
"remark": "项目进度数据",
"children": []
}
]
},
{
"menuId": 2027,
"menuName": "app管理员中心",
"parentId": 0,
"orderNum": 11,
"path": "FrontAppUserManager",
"component": "views/front/FrontAppUserManager.vue",
"query": null,
"menuType": "F",
"status": "0",
"perms": "app:admin:center",
"icon": null,
"createBy": null,
"createTime": "2023-06-28T14:52:50",
"updateBy": null,
"updateTime": "2023-06-28T14:52:50",
"remark": "app管理员中心",
"children": []
},
{
"menuId": 2033,
"menuName": "目录测试",
"parentId": 0,
"orderNum": 12,
"path": null,
"component": null,
"query": null,
"menuType": "M",
"status": "0",
"perms": null,
"icon": null,
"createBy": null,
"createTime": "2023-09-13T09:34:23.762803",
"updateBy": null,
"updateTime": "2023-09-13T09:34:23.762803",
"remark": null,
"children": [
{
"menuId": 2034,
"menuName": "菜单1",
"parentId": 2033,
"orderNum": 1,
"path": "/aaaaa",
"component": null,
"query": null,
"menuType": "C",
"status": "0",
"perms": null,
"icon": null,
"createBy": null,
"createTime": "2023-09-13T09:34:43.3276",
"updateBy": null,
"updateTime": "2023-09-13T09:34:43.3276",
"remark": null,
"children": []
},
{
"menuId": 2035,
"menuName": "菜单2",
"parentId": 2033,
"orderNum": 2,
"path": "/bbbbb",
"component": null,
"query": null,
"menuType": "C",
"status": "0",
"perms": null,
"icon": null,
"createBy": null,
"createTime": "2023-09-13T09:35:15.784714",
"updateBy": null,
"updateTime": "2023-09-13T09:35:15.784714",
"remark": null,
"children": []
}
]
}
]
某个具有的权限列表,这个是用于弹窗的时候的回显的,这个数据不是硬编码的,后台接口回根据传入的角色id,让其具有对应的菜单的。在代码中的位置
const result2 = await roleAuthMenuListByRoleId(row.roleId)
selectRoleMenuList = result2.data.data
[
{
"menuId": 103,
"menuName": "部门管理",
"parentId": 0,
"orderNum": 4,
"path": "dept",
"component": "views/DeptManager.vue",
"query": "",
"menuType": "C",
"status": "0",
"perms": "system:dept:list",
"icon": "tree",
"createBy": "admin",
"createTime": "2023-05-22T09:10:35",
"updateBy": "",
"updateTime": "2023-05-24T09:21:46",
"remark": "部门管理菜单"
},
{
"menuId": 2003,
"menuName": "菜单管理",
"parentId": 0,
"orderNum": 3,
"path": "menus",
"component": "views/MenuManager.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": "system:menu",
"icon": "#",
"createBy": "",
"createTime": "2023-05-24T09:14:42",
"updateBy": "",
"updateTime": "2023-05-24T09:14:42",
"remark": "菜单管理"
},
{
"menuId": 2004,
"menuName": "项目管理",
"parentId": 0,
"orderNum": 9,
"path": "",
"component": null,
"query": null,
"menuType": "M",
"status": "0",
"perms": "adfadaa",
"icon": "#",
"createBy": "",
"createTime": "2023-05-24T09:49:19",
"updateBy": "",
"updateTime": "2023-05-24T09:49:19",
"remark": "系统管理"
},
{
"menuId": 2005,
"menuName": "项目数据管理",
"parentId": 2004,
"orderNum": 1,
"path": "xiangmushuju",
"component": "views/ProjectData.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": "xiangmushuju",
"icon": "#",
"createBy": "",
"createTime": "2023-05-24T14:35:32",
"updateBy": "",
"updateTime": "2023-05-24T14:35:32",
"remark": "项目数据"
},
{
"menuId": 2006,
"menuName": "空间数据管理",
"parentId": 2004,
"orderNum": 2,
"path": "kongjianshujuguanli",
"component": "views/SpatialData.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": null,
"icon": "#",
"createBy": "",
"createTime": "2023-05-24T15:02:23",
"updateBy": "",
"updateTime": "2023-05-24T15:02:23",
"remark": "项目空间数据管理"
},
{
"menuId": 2010,
"menuName": "机械设备管理",
"parentId": 2004,
"orderNum": 3,
"path": "jixieshebei",
"component": "views/MechanicalData.vue",
"query": null,
"menuType": "C",
"status": "0",
"perms": null,
"icon": "#",
"createBy": "",
"createTime": "2023-06-05T14:51:19",
"updateBy": "",
"updateTime": "2023-06-05T14:51:19",
"remark": "机械设备管理"
},
{
"menuId": 2027,
"menuName": "app管理员中心",
"parentId": 0,
"orderNum": 11,
"path": "FrontAppUserManager",
"component": "views/front/FrontAppUserManager.vue",
"query": null,
"menuType": "F",
"status": "0",
"perms": "app:admin:center",
"icon": null,
"createBy": null,
"createTime": "2023-06-28T14:52:50",
"updateBy": null,
"updateTime": "2023-06-28T14:52:50",
"remark": "app管理员中心"
},
{
"menuId": 2033,
"menuName": "目录测试",
"parentId": 0,
"orderNum": 12,
"path": null,
"component": null,
"query": null,
"menuType": "M",
"status": "0",
"perms": null,
"icon": null,
"createBy": null,
"createTime": "2023-09-13T09:34:23.762803",
"updateBy": null,
"updateTime": "2023-09-13T09:34:23.762803",
"remark": null
},
{
"menuId": 2035,
"menuName": "菜单2",
"parentId": 2033,
"orderNum": 2,
"path": "/bbbbb",
"component": null,
"query": null,
"menuType": "C",
"status": "0",
"perms": null,
"icon": null,
"createBy": null,
"createTime": "2023-09-13T09:35:15.784714",
"updateBy": null,
"updateTime": "2023-09-13T09:35:15.784714",
"remark": null
}
]
使用isFirstParentId这个是因为通过,父子联级的时候,选择子选项,复选项虽然也勾选了,但是数组中并没有数据,第二次点击其他选项的时候,或者再点击的时候才有数据。
以下内容需要在代码查看handleSelect()和handleSelectionChange()这个两个函数,必要的时候,自己打一下断点就知道了。提交给后端数组的处理在,handleSelectionChange()中,这里就是提交给后端的数据数据。具体看:handleSelectionChange()。理解这两个逻辑,需要先看下面的gif,了解出现问题的原因,然后再,结合代码中的handleSelect()和handleSelectionChange()这个两个函数,有条件的断点调试一下
如果没有:isFirstParentId,得到的数据内容会有缺失,所以在第一次点击子选项的时候,需要勾选父级选项,需要记录下来,点击其他选项的时候,数组会从新赋值的,也就是父选项的也会添加进去选择的数组中,但是如果像下面GIF图所示的情况,第一次进来我就点击一次,那分配权限的时候就就缺少了一个字段。使用isFirstParentId就是为了防止第一次点击,不勾选其他选项然后导致提交给后端的数组中,数据缺失的情况。
使用了:isFirstParentId和对应的代码逻辑,这个之后,就可以防止第一次点击的时候数据缺失的问题了。
使用了:deleteParentId和对应的代码逻辑,就可以解决上述问题了,把多余的数据清除了
数据类型定义
import { Role } from ‘…/responsemodel/responseRole’;
responseRole.ts,注意这里有一个export导出
/**
* Role
*/
export interface Role {
/**
* 创建者
*/
createBy?: string;
/**
* 创建时间
*/
createTime?: string;
/**
* 删除标志(0代表存在 1代表删除)
*/
delFlag?: string;
/**
* 备注
*/
remark?: string;
/**
* 角色ID
*/
roleId?: number;
/**
* 角色权限字符串
*/
roleKey?: string;
/**
* 角色名称
*/
roleName?: string;
/**
* 显示顺序
*/
roleSort?: number;
/**
* 角色状态(0正常 1停用)
*/
status?: string;
/**
* 更新者
*/
updateBy?: string;
/**
* 更新时间
*/
updateTime?: string;
}
// 数据类型定义
import { Menu } from ‘…/responsemodel/responseMenu’;
responseMenu.ts,注意这里有一个export导出
/**
* Menu
*/
export interface Menu {
/**
* 组件路径
*/
component?: string;
/**
* 创建者
*/
createBy?: string;
/**
* 创建时间
*/
createTime?: string;
/**
* 菜单图标
*/
icon?: string;
/**
* 菜单ID
*/
menuId?: number;
/**
* 菜单名称
*/
menuName?: string;
/**
* 菜单类型(M目录 C运维菜单 F前端菜单)
*/
menuType?: string;
/**
* 显示顺序
*/
orderNum?: number;
/**
* 父菜单ID
*/
parentId?: number;
/**
* 路由地址
*/
path?: string;
/**
* 权限标识
*/
perms?: string;
/**
* 路由参数
*/
query?: string;
/**
* 备注
*/
remark?: string;
/**
* 菜单状态(0正常 1停用)
*/
status?: string;
/**
* 更新者
*/
updateBy?: string;
/**
* 更新时间
*/
updateTime?: string;
/**
* 菜单子集
*/
children?: Menu[]
}
打发
不需要看这个,我只是记录一下而已
代码中的 import { updateRoleAuthMenu, roleAuthMenuListByRoleId } from ‘…/api/role’;
role.ts,注意这里有一个export导出
import axios from './request'
export function roleList(query: any) {
return axios({
url: '/role',
method: 'get',
params: query
})
}
export function roleSave<T>(t: T) {
return axios.post('/role', t)
}
export function roleUpdate<T>(t: T) {
return axios.put('/role', t)
}
export function getRoleInfoById(id: number) {
return axios.get(`/role/${id}`)
}
export function roleRemoveById(id: number) {
return axios.delete(`/role/${id}`)
}
// 获取角色菜单列表
export function roleAuthMenuListByRoleId(roleId: number | undefined) {
return axios.get(`/role/authMenu/${roleId}`)
}
export function updateRoleAuthMenu(data: any) {
return axios({
url: '/role/authMenu/',
method: 'put',
params: data
})
}
// 这个是api接口,具体看后面的代码解释的内容,不需要关心这个,也可以不用看,这里只是记录一下而已
import { menuList } from ‘…/api/menu’
menu.ts,注意这里有一个export导出
import axios from './request'
export function menuList(query: any) {
return axios({
url: '/menu',
method: 'get',
params: query
})
}
export function menuSave<T>(t: T) {
return axios.post('/menu',t)
}
export function menuUpdate<T>(t: T) {
return axios.put('/menu',t)
}
export function getMenuInfoById(id: number) {
return axios.get(`/menu/${id}`)
}
export function menuRemoveById(id: number) {
return axios.delete(`/menu/${id}`)
}
export function menuTreeSelect() {
return axios.get('/menu/menuTreeSelect')
}
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- huatuo0.cn 版权所有 湘ICP备2023017654号-2
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务