欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

树形选择变成表格树选择

发布时间:2024/1/1 编程问答 46 豆豆
生活随笔 收集整理的这篇文章主要介绍了 树形选择变成表格树选择 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

需求:在接口不改动的情况下由树形结构改成表格树结构,如下图

原图

调整后

1.这里使用的是antdesign框架,首先将a-tree改为a-table

<!-- <a-tree checkable v-model="checkedKeys" :treeData="menuTree" @check="checkItem"></a-tree> --><a-table :columns="columns" :data-source="data" :pagination="false"></a-table>

2.定义table中的columns

// 这里除了第一列是菜单名称以外,其余都是checkbox,checkbox采用插槽的方式实现 /*** slots里面定义的是头部插槽名字,头部也有一个多选框* scopedSlots定义的是当前列插槽的名字* */ columns: [{title: '授权菜单',dataIndex: 'title',key: 'title' },{dataIndex: 'entry',key: 'entry',align:'center',slots: { title: 'customEntry' },scopedSlots: { customRender: 'checkBoxEntry' }},{dataIndex: 'edit',align:'center',key: 'edit',slots: { title: 'customEdit' },scopedSlots: { customRender: 'checkBoxEdit' }},{dataIndex: 'approval',align:'center',key: 'approval',slots: { title: 'customApproval' },scopedSlots: { customRender: 'checkBoxApproval' }},{dataIndex: 'query',align:'center',key: 'query',slots: { title: 'customQuery' },scopedSlots: { customRender: 'checkBoxQuery' }}],

此时在table中加入checkbox插槽

// 例如头部 <a-checkbox slot="customEntry">录入</a-checkbox> <a-checkbox slot="customEdit">编辑</a-checkbox> <a-checkbox slot="customApproval">审核</a-checkbox> <a-checkbox slot="customQuery">查询</a-checkbox> // 每一列同理 <a-checkbox slot="checkBoxEntry" slot-scope="text,item"></a-checkbox>

3.修改后端返回数据data,由于之前是根据树形结构显示,后端在返回数据之前已经很友好的把数据封装成树形结构,示例如下:
(其中a10001、a10002、a10003、a10004分别表示录入、编辑、审核、查询权限)

[{ //一级菜单"title": "计划管理", "children": [{ // 授权模块"menuCode": "15","title": "设备需求计划", "children": [{ // 模块可分配的权限"authority_button_name": "录入","authority_button_code": "a10001","menu_id": "15"},{"authority_button_name": "编辑","authority_button_code": "a10002","menu_id": "15"},{"authority_button_name": "审核","authority_button_code": "a10003","menu_id": "15"},{"authority_button_name": "查询","authority_button_code": "a10004","menu_id": "15"}],}],"menuCode": "14"},{"title": "设备进场管理","children": [{"title": "设备进场验收管理","children": [{"authority_button_name": "录入","authority_button_code": "a10001","menu_id": "33"}],"menuCode": "33"},{"title": "水电管理","children": [{ // 二级菜单"title": "水电抄表记录单","children": [{"authority_button_name": "录入","authority_button_code": "a10001","menu_id": "40"},{"authority_button_name": "编辑","authority_button_code": "a10002","menu_id": "40"},{"authority_button_name": "审核","authority_button_code": "a10003","menu_id": "40"},{"authority_button_name": "查询","authority_button_code": "a10004","menu_id": "40"}],"menuCode": "40"}],"menuCode": "112"}],"menuCode": "38"},],

由于树形结构的数据与表格树的数据基本类型,因此只需要把最里面一层children(模块可分配的权限)拿出来即可。

处理完以后的数据结构如下:

  • authButtonGroup保存该模块下可选择的权限,即原始数据中的children中的数据,删除该children字段
  • authButton保存该用户在该模块下已经存在的权限
  • [{ //一级菜单"title": "计划管理", "children": [{ // 授权模块"menuCode": "15","title": "设备需求计划", authButtonGroup: ['a10001','a10002','a10003','a10004'], // 授权模块可选的权限authButton: ['a10001'] // 该用户目前已经拥有的权限}],"menuCode": "14"},{"title": "设备进场管理","children": [{"title": "设备进场验收管理",authButtonGroup: ['a10001'],authButton: ['a10001'],"menuCode": "33" },{"title": "水电管理","children": [{ // 二级菜单"title": "水电抄表记录单",authButtonGroup: ['a10001','a10002','a10003','a10004'],authButton: ['a10001'] "menuCode": "40"}],"menuCode": "112"}],"menuCode": "38"},],

    处理数据的方法如下:

    let promises = [获取用户权限的接口,获取权限树的接口];Promise.all(promises).then(result=>{// 对用户权限做处理,用授权模块的menu_code作为key存入对象,以便下面使用let authButton = result[0].responseList;let authButtonMap = {};Array.isArray(authButton) && authButton.forEach(item=>{authButtonMap[item.menu_code] = item.authority_button_codes ? item.authority_button_codes.split(',') : [];})// 获取到权限树let data = [...result[1].responseList];// 定义一个方法对树进行处理function dealTree(item){let child = item.children;// 子节点不是菜单就是权限按钮,一般子节点下都只存在一种类型,非1即2child.forEach(inner=>{// 通过title判断,没有的就是模块可选的权限if(inner.title){dealTree(inner)}else{// 是模块可选的权限了,存起来!item.authButtonGroup && (item.authButtonGroup = []);item.authButtonGroup.push(inner.authority_button_code);}})if(item.authButtonGroup){item.authButton = authButtonMap[item.menuCode] || []; // 存储用户在当前模块已有的权限delete item.children; // 删除children}return item;}this.data = data.map(item=>{return dealTree(item);});

    此时数据结构就变成了

    菜单授权模块(包含模块可选的权限)菜单授权模块(包含模块可选的权限)

    下面给checkbox绑定属性(点击事件、默认选中、菜单的半选状态)

    先根据用户存在的权限默认选中:

    // 如何当前授权模块中的authButton有a10001说明该用户存在这个权限,设置选中 <a-checkbox slot="checkBoxEntry" slot-scope="text,item" :checked="item.authButton.includes('a10001')"></a-checkbox>

    分析:
    1.当该节点是菜单时,不存在authButton这个数组
    2.checkbox是否显示应该根据authButtonGroup这个数组中是否有值,即该模块可以被授什么权

    进行如下改造:

    <template slot="checkBoxEntry" slot-scope="text,item">// 该节点存在authButtonGroup,即授权模块<template v-if="item.authButtonGroup">// 判断该模块是否可以授权a10001,即authButtonGroup是否存在,有就显示checkbox,没有就不显示<a-checkbox v-if="item.authButtonGroup.includes('a10001')" :checked="item.authButton.includes('a10001')"></a-checkbox><span v-else></span></template>// 菜单是否显示checkbox,// 菜单显示checkbox的用途是用于给下面所有模块的全选或者全取消功能// 所有应该判断下面的模块是否存在checkbox,这里的判读条件不够全面,下面再说<a-checkbox v-else-if="item.children.some(inner => inner.authButtonGroup.includes('a10001'))" ></a-checkbox><span v-else></span> </template>

    绑定点击事件
    (由于每个checkbox设置的选中状态都是通过该模块的authButton数组是否有a10001、a10002、a10003、a10004。因此原理就是在该授权模块的authButton将指定的authCode加入或者删除)

    <template slot="checkBoxEntry" slot-scope="text,item"><template v-if="item.authButtonGroup"><a-checkbox@change="onChangeRecord($event,item,'a10001')" v-if="item.authButtonGroup.includes('a10001')" :checked="item.authButton.includes('a10001')"></a-checkbox><span v-else></span></template><a-checkbox@change="onChangeRecordMenu($event,item,'a10001')"v-else-if="item.children.some(inner => inner.authButtonGroup.includes('a10001'))"></a-checkbox><span v-else></span> </template>/** 授权模块的点击事件 **/ onChangeRecord(event,record,authCode){this.compareDleteOrAdd(record.authButton,authCode,true,true); // 之前是选中点击即删除,之前未选中点击即添加this.$forceUpdate(); // 由于绑定的都是方法执行结果,手动触发视图更新 }, // 在数组中增加或者减少一项 compareDleteOrAdd(arr,item,isAdd,isDel){let index = arr.indexOf(item)if(index > -1){if(isDel){arr.splice(index,1);}}else{if(isAdd){arr.push(item);}}return index; }, /** 菜单的点击事件 **/ onChangeRecordMenu(event,record,authCode){// 先获取当前点击按钮是选中还是取消,选中即菜单下所有模块全部选中,相反取消则全部取消let flag = event.target.checked;// 获取菜单下面的授权模块或者下级菜单let children = record.children;let stack = [];// 循环遍历,将所有的子模块都添加或者删除authCodewhile(children){children.forEach(item=>{// 是授权模块则直接删除或添加if(item.authButtonGroup){if(item.authButtonGroup.includes(authCode)){if(flag){this.compareDleteOrAdd(item.authButton,authCode,true,false);}else{this.compareDleteOrAdd(item.authButton,authCode,false,true);}}}else{// 如果是菜单,定义一个stack栈存入,下级菜单中的授权模块也需要处理stack.push(item);}})// 将stack栈中的菜单从第一个推出,再循环(主要是存在多级菜单的原因)let next = stack.shift();children = next ? next.children : '';}this.$forceUpdate(); // 手动触发视图更新 },

    设置菜单的选中、半选状态

    <template slot="checkBoxEntry" slot-scope="text,item"><template v-if="item.authButtonGroup"><a-checkbox@change="onChangeRecord($event,item,'a10001')" v-if="item.authButtonGroup.includes('a10001')" :checked="item.authButton.includes('a10001')"></a-checkbox><span v-else></span></template><a-checkbox@change="onChangeRecordMenu($event,item,'a10001')"v-else-if="item.children.some(inner => inner.authButtonGroup.includes('a10001'))":checked="checkAllSelect(item,'a10001')":indeterminate="indeterminateCheck(item,'a10001') && !checkAllSelect(item,'a10001')" ></a-checkbox><span v-else></span> </template>/** 菜单的全选状态checkAllSelect返回true即全选 **/ // 即只需找到一个授权模块没有选中即返回false,找不到返回true checkAllSelect(item,authCode){// 找到一个不满足let flag = true;let children = item.children;if(!item || !item.children){return false;}let stack = [];while(children){children.some(item=>{if(item.authButtonGroup){if(item.authButtonGroup.includes(authCode)){flag = item.authButton.includes(authCode);return !flag;}}else{stack.push(item);return false;}})// 找到了不向下执行if(!flag){break;}let next = stack.shift();children = next ? next.children : '';}return flag; },/** 菜单的半选状态设置checkout的indeterminate属性为true,即半选**/ // 半选其实就是至少有一个选中并且不是全部选中 // :indeterminate="indeterminateCheck(item,'a10001') && !checkAllSelect(item,'a10001')" // 找到至少一个选中 indeterminateCheck(item,authCode){// 至少有一个选中let flag = false;let children = item.children;let stack = [];while(children){children.some(item=>{if(item.authButtonGroup){if(item.authButtonGroup.includes(authCode)){flag = item.authButton.includes(authCode);return flag;}}else{stack.push(item);return false;}})// 找到了有一个if(flag){break;}let next = stack.shift();children = next ? next.children : '';}return flag; },

    完成以上操作基本上菜单的全选、取消、半选状态,授权模块的选择取消都已经处理完了

    处理顶部的全选按钮(其实方法都是执行一样的,只是传参数的时候将这个表格数据data当初children传人即可)

    <a-checkbox @change="onChangeAll($event,'a10001')" :checked="checkAllSelect({children:data},'a10001')":indeterminate="indeterminateCheck({children:data},'a10001') && !checkAllSelect({children:data},'a10001')"slot="customEntry">录入</a-checkbox>/** 点击事件 **/ onChangeAll(event,authCode){this.onChangeRecordMenu(event,{children:this.data},authCode); },

    完整代码如下:

    <template><div class="permission-auth-model"><a-table :columns="columns" :data-source="data" :pagination="false"><a-checkbox @change="onChangeAll($event,'a10001')" :checked="checkAllSelect({children:data},'a10001')":indeterminate="indeterminateCheck({children:data},'a10001') && !checkAllSelect({children:data},'a10001')"slot="customEntry">录入</a-checkbox><a-checkbox @change="onChangeAll($event,'a10002')" :checked="checkAllSelect({children:data},'a10002')":indeterminate="indeterminateCheck({children:data},'a10002') && !checkAllSelect({children:data},'a10002')"slot="customEdit">编辑</a-checkbox><a-checkbox @change="onChangeAll($event,'a10003')":checked="checkAllSelect({children:data},'a10003')":indeterminate="indeterminateCheck({children:data},'a10003') && !checkAllSelect({children:data},'a10003')" slot="customApproval">审核</a-checkbox><a-checkbox @change="onChangeAll($event,'a10004')":checked="checkAllSelect({children:data},'a10004')":indeterminate="indeterminateCheck({children:data},'a10004') && !checkAllSelect({children:data},'a10004')"slot="customQuery">查询</a-checkbox><template slot="checkBoxEntry" slot-scope="text,item"><template v-if="item.authButtonGroup"><a-checkbox @change="onChangeRecord($event,item,'a10001')" v-if="item.authButtonGroup.includes('a10001')" :checked="item.authButton.includes('a10001')"></a-checkbox><span v-else></span></template><a-checkbox @change="onChangeRecordMenu($event,item,'a10001')" v-else-if="item.children.some(inner => inner.authButtonGroup.includes('a10001'))" :checked="checkAllSelect(item,'a10001')":indeterminate="indeterminateCheck(item,'a10001') && !checkAllSelect(item,'a10001')"></a-checkbox><span v-else></span></template><template slot="checkBoxEdit" slot-scope="text,item"><template v-if="item.authButtonGroup"><a-checkbox @change="onChangeRecord($event,item,'a10002')" v-if="item.authButtonGroup.includes('a10002')" :checked="item.authButton.includes('a10002')"></a-checkbox><span v-else></span></template><a-checkbox @change="onChangeRecordMenu($event,item,'a10002')" v-else-if="item.children.some(inner => inner.authButtonGroup.includes('a10002'))" :checked="checkAllSelect(item,'a10002')":indeterminate="indeterminateCheck(item,'a10002') && !checkAllSelect(item,'a10002')"></a-checkbox><span v-else></span></template><template slot="checkBoxApproval" slot-scope="text,item"><template v-if="item.authButtonGroup"><a-checkbox @change="onChangeRecord($event,item,'a10003')" v-if="item.authButtonGroup.includes('a10003')" :checked="item.authButton.includes('a10003')"></a-checkbox><span v-else></span></template><a-checkbox @change="onChangeRecordMenu($event,item,'a10003')" v-else-if="item.children.some(inner => inner.authButtonGroup.includes('a10003'))" :checked="checkAllSelect(item,'a10003')":indeterminate="indeterminateCheck(item,'a10003') && !checkAllSelect(item,'a10003')"></a-checkbox><span v-else></span></template><template slot="checkBoxQuery" slot-scope="text,item"><template v-if="item.authButtonGroup"><a-checkbox @change="onChangeRecord($event,item,'a10004')" v-if="item.authButtonGroup.includes('a10004')" :checked="item.authButton.includes('a10004')"></a-checkbox><span v-else></span></template><a-checkbox @change="onChangeRecordMenu($event,item,'a10004')" v-else-if="item.children.some(inner => inner.authButtonGroup.includes('a10004'))" :checked="checkAllSelect(item,'a10004')":indeterminate="indeterminateCheck(item,'a10004') && !checkAllSelect(item,'a10004')"></a-checkbox><span v-else></span></template></a-table></div> </template><script> export default {name: 'EnumModal',data() {return {columns: [{title: '授权菜单',dataIndex: 'title',key: 'title' },{dataIndex: 'entry',key: 'entry',align:'center',slots: { title: 'customEntry' },scopedSlots: { customRender: 'checkBoxEntry' }},{dataIndex: 'edit',align:'center',key: 'edit',slots: { title: 'customEdit' },scopedSlots: { customRender: 'checkBoxEdit' }},{dataIndex: 'approval',align:'center',key: 'approval',slots: { title: 'customApproval' },scopedSlots: { customRender: 'checkBoxApproval' }},{dataIndex: 'query',align:'center',key: 'query',slots: { title: 'customQuery' },scopedSlots: { customRender: 'checkBoxQuery' }}],data: []}},created(){this.getTableData();},methods: {// 校验一个是否存在menucode或者子节点存在checkAllSelect(item,authCode){// 找到一个不满足let flag = true;let children = item.children;if(!item || !item.children){return false;}let stack = [];while(children){children.some(item=>{if(item.authButtonGroup){if(item.authButtonGroup.includes(authCode)){flag = item.authButton.includes(authCode);return !flag;}}else{stack.push(item);return false;}})// 找到了不向下执行if(!flag){break;}let next = stack.shift();children = next ? next.children : '';}return flag;},// 校验是否是半选状态indeterminateCheck(item,authCode){// 至少有一个选中let flag = false;let children = item.children;let stack = [];while(children){children.some(item=>{if(item.authButtonGroup){if(item.authButtonGroup.includes(authCode)){flag = item.authButton.includes(authCode);return flag;}}else{stack.push(item);return false;}})// 找到了有一个if(flag){break;}let next = stack.shift();children = next ? next.children : '';}return flag;},onChangeAll(event,authCode){let data = this.data.filter(item=>{return item.menuCode != 82;})let flag = this.checkAllSelect({children:this.data},authCode);event.target.checked = !flag;this.onChangeRecordMenu(event,{children:data},authCode);},onChangeRecordMenu(event,record,authCode){let flag = event.target.checked;let children = record.children;let stack = [];while(children){console.log(children);children.forEach(item=>{if(item.authButtonGroup){if(item.authButtonGroup.includes(authCode)){if(flag){this.compareDleteOrAdd(item.authButton,authCode,true,false);}else{this.compareDleteOrAdd(item.authButton,authCode,false,true);}}}else{stack.push(item);}})let next = stack.shift();children = next ? next.children : '';}this.$forceUpdate();},onChangeRecord(event,record,authCode){this.compareDleteOrAdd(record.authButton,authCode,true,true);this.$forceUpdate();},// 在数组中增加或者减少一项compareDleteOrAdd(arr,item,isAdd,isDel){let index = arr.indexOf(item)if(index > -1){if(isDel){arr.splice(index,1);}}else{if(isAdd){arr.push(item);}}return index;},getTableData() {let promises = [获取人员权限,获取表格树];Promise.all(promises).then(result=>{let authButton = result[0].responseList;let authButtonMap = {};Array.isArray(authButton) && authButton.forEach(item=>{authButtonMap[item.menu_code] = item.authority_button_codes ? item.authority_button_codes.split(',') : [];})let data = [...result[1].responseList];function dealTree(item){let child = item.children;if(Array.isArray(child)){if(child.length == 0){item.authButtonGroup = ['a10004'];}else {child.forEach(inner=>{if(inner.title){dealTree(inner)}else{!item.authButtonGroup && (item.authButtonGroup = []);item.authButtonGroup.push(inner.authority_button_code);}})}}if(item.authButtonGroup){item.authButton = authButtonMap[item.menuCode] || [];delete item.children;}return item;}this.data = data.map(item=>{return dealTree(item);});}, } </script>

    总结

    以上是生活随笔为你收集整理的树形选择变成表格树选择的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。