树形选择变成表格树选择
需求:在接口不改動的情況下由樹形結構改成表格樹結構,如下圖
原圖
調整后
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
- 下一篇: Android新手机开启日志功能(本人用