业务场景中,分配职责权限,职责权限是树的结构,需求是树的左侧为新勾选的职责,数的右侧为用户的角色带的职责。如图所示。
树用的是ant-design-vue
的a-tree,该组件默认是没有右侧的checkbox的,但是它提供的插槽可供开发人员自定义树中每个节点的展示形式。所以我们可以通过插槽的形式自定义树的节点。
该需求的难点是右侧checkbox的选中时,实现父级的全选与半选。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <a-input v-model:value="data.searchValue" placeholder="权限名称" style="width: 200px; margin: 8px 0" :maxlength="20" @change="searchFn" > <template #suffix> <search-outlined style="color: rgba(0, 0, 0, 0.45)" /> </template> </a-input> <a-tree v-if="data.permissionTrees.length" :auto-expand-parent="data.autoExpandParent" v-model:checkedKeys="data.checkedKeys" v-model:expandedKeys="data.expandedKeys" checkable :tree-data="data.permissionTrees" @expand="onExpand" @check="onCheck" :fieldNames="{ title: 'name', key: 'code', }" > <template #title="{ name, code, id, remark, children, roleDutyCodeAll, indeterminate }"> <span v-if="name.indexOf(data.searchValue) > -1" class="tagName" > {{ name.substr(0, name.indexOf(data.searchValue)) }} <span style="color: #f50">{{ data.searchValue }}</span> {{ name.substr(name.indexOf(data.searchValue) + data.searchValue.length) }} <a-checkbox :checked="data.roleDutyCodes.includes(code) || roleDutyCodeAll" :indeterminate="indeterminate" disabled style="margin-left: 10px" ></a-checkbox> </span> <span @click="showDetailFn(name, id, remark, children)" v-else class="tagName"> {{ name }} <a-checkbox :checked="data.roleDutyCodes.includes(code) || roleDutyCodeAll" :indeterminate="indeterminate" disabled style="margin-left: 10px" ></a-checkbox> </span> </template> </a-tree>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
onMounted(async () => { await getData(); await getDutyCodeList(); for (let i = 0; i < data.permissionTrees.length; i++) { recursionFn(data.permissionTrees[i], data.aTitle); } for (let i = 0; i < data.permissionTrees.length; i++) { recursionFn(data.permissionTrees[i], data.aTitle); } searchFn(); });
const recursionFn = (tree, aFlat) => { aFlat.push({ code: tree.code, name: tree.name, }); if (tree.children && tree.children.length > 0) { tree.roleDutyCodeAll = false; tree.indeterminate = false; let count = 0; tree.children.forEach(item => { if (data.roleDutyCodes.includes(item.code)) { count++; } if (item.indeterminate) { tree.indeterminate = true; } recursionFn(item, aFlat); }); if (tree.children.length == count) { tree.roleDutyCodeAll = true; } else if (count > 0) { tree.indeterminate = true; } tree.roleDutyCodeAll ? data.roleDutyCodes.push(tree.code) : ''; } else { } }; const onExpand = keys => { data.expandedKeys = keys; data.autoExpandParent = false; }; const onCheck = () => {};
const searchFn = () => { data.searchValue = data.searchValue.trim(); const expanded = data.aTitle.map(t => { if (t.name.indexOf(data.searchValue) > -1) { return getParentKey(t.code, data.permissionTrees); } return null; }); data.expandedKeys = expanded; data.autoExpandParent = true; };
const getParentKey = (key, tree) => { let parentKey; for (let i = 0; i < tree.length; i++) { const node = tree[i]; if (node.children) { if (node.children.some(item => item.code === key)) { parentKey = node.code; } else if (getParentKey(key, node.children)) { parentKey = getParentKey(key, node.children); } } } return parentKey; };
|