树形选择变成表格树选择
需求:在接口不改动的情况下由树形结构改成表格树结构,如下图
原图
调整后
1.这里使用的是antdesign框架,首先将a-tree改为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分别表示录入、编辑、审核、查询权限)
由于树形结构的数据与表格树的数据基本类型,因此只需要把最里面一层children(模块可分配的权限)拿出来即可。
处理完以后的数据结构如下:
处理数据的方法如下:
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'))":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>总结
以上是生活随笔为你收集整理的树形选择变成表格树选择的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: vue.js用benz-amr-reco
- 下一篇: 植物大战僵尸 1.0 简体中文版