业务场景中,分配职责权限,职责权限是树的结构,需求是树的左侧为新勾选的职责,数的右侧为用户的角色带的职责。如图所示。
树用的是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; };
 
  |