AntDesign中a-tree使用案例

<template>
  <a-modal :visible='true' :title='数据授权' @cancel='handleClose()' @ok='onSubmit' :width='600' :maskClosable='false'>
    <div class='tree-box'>
      <a-input-search style='margin-bottom: 8px' placeholder='请输入关键字搜索' @change='onChange'/>
      <a-tree v-if='treeData.length > 0' checkable :tree-data='treeData' @check='onCheck'
          :replace-fields='replaceFields' :multiple='true' :checkStrictly='false'
          :defaultExpandAll='true' :default-checked-keys='checkedKeys'>

      <a-tree>
    </div>
  </a-modal>
</template>

<script setup lang='ts'>
import {getOrgList} from '@/api/system.js'
import {authUserDataScope, queryUserDataScope, authRoleDataScope, queryRoleDataScope} from '@/api/dataAuthorization.js'
import {ref, reactive} from "vue"

export default {
  props: {
    id: String,
    type: String
  },
  data() {
    return {
      replaceFields: {
        title: 'label',
        key: 'id',
      },
      keyWorld: '',
      treeData: [],
      checkedKeys: [],
    }
  },
  created() {

  },
  methods() {
    // 获取组织树结构
    onLoadTreeData() {
      getOrgList().then((res) => {
        if(res.status === 0) {
          this.treeData = res.data;
        }
      })
    },
    // ★★★★★★ 获取数据授权
    getDataScope() {
      let requestFunc = '';
      let param = '';
      // ★ 通过方法引用充分减少代码冗余
      if(this.type === 'role') {
        requestFunc = queryRoleDataScope
        param = 'roleId'
      }else {
        requestFunc = queryUserDataScope
        param = 'userId'
      }
      func({[param]: this.id}).then((res) => {
        this.checkedKeys = res.data;
        message.info('授权成功!')
      })
    },
    onSubmit() {
      // !this.checkedKeys.length = true 等价于 this.checkedKeys.length = 0 
      if(!this.checkedKeys.length) {
          message.warn('请选择需要授权的数据!');
          return;
      }else {
        this.getDataScope();
      }
    },
    onCheck(checkedKeys) {
      this.checkedKeys = checkedKeys || [];
    },
    onChange(e) {
      this.keyWord = e.target.value;
    },
    handleClose() {
      this.$emit('handle')
    }
  }
}
</script>

<style lang="less" scoped>
.tree-box > .ant-tree {
  height: 600px;
  overflow-y: auto;
}
</style>

AntDesign Vue中:checkStrictly的作用

在 Ant Design Vue 中,checkStrictly 是 Tree(树形控件)组件的一个属性。它用于指定是否严格遵守父子节点间的勾选关联规则。
当 checkStrictly 属性设置为 true 时,父节点和子节点之间的勾选状态不会相互影响。也就是说,勾选或取消勾选父节点不会影响子节点的勾选状态,同时子节点的勾选状态也不会影响父节点> 的勾选状态。这意味着父节点和子节点之间的勾选状态是相互独立的。
当 checkStrictly 属性设置为 false 时,父节点和子节点之间的勾选状态是关联的。如果一个父节点被勾选或取消勾选,其所有子节点也会相应地被勾选或取消勾选。同样地,如果一个子节点> > 被勾选或取消勾选,它的父节点也会根据子节点的状态相应地被勾选或取消勾选。
通过设置 checkStrictly 属性,您可以根据自己的需求来控制树形控件中勾选状态的关联性。

Example Usage

<template>
  <div>
    <a-input-search style="margin-bottom: 8px" placeholder="请输入关键字搜索" @change="onChange" />
    <div class="allnode" :class="{'active': selectId === ''}">
      全部
      <a-icon type="plus-circle" @click.stop="nodeHandle({}, true)" />
    </div>
    <a-tree
      ref="nodeTree"
      class="group-tree"
      :tree-data="nodeData"
      :selectedKeys="selectedKeys"
      :replace-fields="replaceFields"
      :expanded-keys="expandedKeys"
      :auto-expand-parent="autoExpandParent"
      default-expand-all
      show-icon
      blockNode
      @select="onSelect"
      @expand="onExpand"
    >
      <template slot="title" slot-scope="{ groupName }">
        <span v-if="groupName.indexOf(searchValue) > -1">
          {{ groupName.substr(0, groupName.indexOf(searchValue)) }}
          <span style="color: #f50">{{ searchValue }}</span>
          {{ groupName.substr(groupName.indexOf(searchValue) + searchValue.length) }}
        </span>
        <span v-else>{{ groupName }}</span>
      </template>
      <!--   新增、修改、删除图标   -->
      <template slot="plus" slot-scope="record">
        <!-- <a-popover placement="bottom">
          <template slot="content"> -->
          <!-- <p @click.stop="nodeHandle(record, false)">编辑</p>
          <p @click.stop="nodeDel(record)">删除</p> -->
          <!-- </template> -->
          <!-- <img src="../../../assets/dict/more.png" class="more-btn" /> -->
        <!-- </a-popover> -->
        <a-icon type="edit" @click.stop="nodeHandle(record, false)" />
        <a-icon type="delete" @click.stop="nodeDel(record)" />
      </template>
    </a-tree>
      <a-modal v-model="visible" :title="title" destroyOnClose @ok="handleSubmit">
      <AddForm ref="addFormRef" :editData="editData" @setVisibleHide="setVisibleHide" />
    </a-modal>
  </div>
</template>

<script>
import { getGroupList, existPerson,deleteGroupData } from '@/api/group.js'
import AddForm from './modal/addGroupForm.vue'
// 数组对象中查找符合目标的对象
const parseArray = function (objArray, key, value) {
  for (let i in objArray) {
    let element = objArray[i]
    if (typeof element === 'object') {
      let result = parseArray(element, key, value)
      if (result) return result
    } else {
      if (i === key) {
        if (element === value) return objArray
      }
    }
  }
}

export default {
  name: 'treeComponent',
  data() {
    return {
      replaceFields: {
        title: 'groupName',
        key: 'groupCode',
      },
      nodeData: [],
      groupName: '',
      selectedKeys: null,
      filterResource: null,
      expandedKeys: [],
      searchValue: '',
      autoExpandParent: true,
      dataList: [],
      visible: false,
      editData: {},
      title: '新增',
      selectId: '',
    }
  },
  components: {
    AddForm,
  },
  mounted() {
    this.GetLimsConfigNode()
  },
  methods: {
    onExpand(expandedKeys) {
      this.expandedKeys = expandedKeys;
      this.autoExpandParent = false;
    },
    // 获取全部节点树
    async GetLimsConfigNode() {
      getGroupList({keyWord: ''}).then((res) => {
        this.nodeData = res.data;
        this.generateList(this.nodeData);
      })
    },
    generateList(data) {
      for (let i = 0; i < data.length; i++) {
        const node = data[i];
        this.dataList.push({ groupCode: node.groupCode, groupName: node.groupName });
        if (node.children) {
          this.generateList(node.children);
        }
      }
    },
    // 新增、修改节点操作,此处为打开新增修改界面,调用实际后端接口进行节点的处理操作
    async nodeHandle(record, isAdd) {
      this.visible = true;
      this.title = isAdd ? '新增' : '编辑';
      this.editData = record;
    },
    setVisibleHide() {
      this.visible = false;
      this.GetLimsConfigNode()
    },
    nodeDel(record) {
      this.$confirm({
        title: `您确定要删除该节点:${record.groupName}?`,
        okText: '删除',
        cancelText: '取消',
        onOk: async () => {
          existPerson({id: record.id}).then((res) => {
            if (res.status === 0) {
              if(!res.data) {
                delGroup(record.id)
              } else {
                this.$message.warning('请先删除组内人员!')
              }
            }
          })
        },
      })
    },
    delGroup(id) {
      deleteGroupData({id}).then((res) => {
        if (res.status === 0) {
          this.$message.success('删除成功!')
          this.GetLimsConfigNode()
        } else {
          this.$message.warning(res.msg)
        }
      })
    },
    async onSelect(params, e) {
      if (this.filterResource) {
        this.$set(this.filterResource, 'scopedSlots', {})
      }
      if (e.selected) {
        let groupName = e.selectedNodes[0].data.props.groupName
        let arr = groupName.split('-')
        this.filterResource = parseArray(this.nodeData, 'groupCode', params[0])
        let iconStr
        if (arr.length < 4) {
          iconStr = 'plus'
        } else {
          iconStr = 'edit'
        }
        this.$set(this.filterResource, 'scopedSlots', { icon: iconStr })
        this.selectedKeys = params
        this.groupName = groupName
        this.selectId = e.selectedNodes[0].data.props.id
        this.$emit('getCurrentGroupId', this.selectId)
      } else {
        this.selectedKeys = null
        this.groupName = ''
        this.selectId = '';
        this.$emit('getCurrentGroupId', this.selectId)
      }
    },
    onChange(e) {
      const value = e.target.value;
      const expandedKeys = this.dataList
        .map(item => {
          if (item.groupName.indexOf(value) > -1) {
            return this.getParentKey(item.groupCode, this.nodeData);
          }
          return null;
        })
        .filter((item, i, self) => item && self.indexOf(item) === i);
      Object.assign(this, {
        expandedKeys,
        searchValue: value,
        autoExpandParent: true,
      });
    },
    getParentKey(groupCode, tree) {
      let parentKey;
      for (let i = 0; i < tree.length; i++) {
        const node = tree[i];
        if (node.children) {
          if (node.children.some(item => item.groupCode === groupCode)) {
            parentKey = node.groupCode;
          } else if (this.getParentKey(groupCode, node.children)) {
            parentKey = this.getParentKey(groupCode, node.children);
          }
        }
      }
      return parentKey;
    },
    handleSubmit() {
      this.$refs.addFormRef.onSubmit();
    },
  },
}
</script>

<style lang="scss">
.ant-tree.group-tree  {
  li {
    position: relative;
    padding: 6px 0;
    ul {
      padding: 0;
      margin-left: -30px;
      li {
        padding-left: 40px;
        .ant-tree-switcher {
          display: none;
        }
      }
    }
    .ant-tree-node-content-wrapper.ant-tree-node-selected {
      background: transparent;
    }
    .ant-tree-switcher_close,.ant-tree-switcher_open {
      position: absolute;
      left: 10px;
      z-index: 9;
      background: url('../../../assets/dict/organization.png') no-repeat;
      background-size: 16px 16px;
      background-position: center;
      i {
        display: none !important;
      }
    }
    .ant-tree-node-content-wrapper:hover {
      background-color: transparent;
    }
    span.ant-tree-iconEle {
      position: absolute;
      right: 10px;
      width: auto;
      .anticon {
        margin: 0 5px;
      }
    }
    &:hover {
      background: rgba(15, 34, 67, 0.05);
    }
  }
  li.ant-tree-treenode-selected {
    background: rgba(43, 121, 255, 0.1);
    border-radius: 4px;
    .ant-tree-title {
      color: #1F71FF;
    }
    ul {
      li {
        .ant-tree-title {
          color: rgba(0, 0, 0, 0.65);
        }
      }
    }
    &:before {
      content: '';
      position: absolute;
      width: 2px;
      height: 8px;
      left: 0px;
      top: calc(50% - 8px/2);
      background: #1F71FF;
      border-radius: 0px 3px 3px 0px;
    }
  }
}
.ant-tree li span.ant-tree-switcher.ant-tree-switcher-noop {
  width: 10px;
}
.allnode {
  padding: 6px 16px;
  position: relative;
  .anticon {
    float: right;
    line-height: 24px;
  }
}
.allnode.active {
  background: rgba(43, 121, 255, 0.1);
  &:before {
    content: '';
    position: absolute;
    width: 2px;
    height: 8px;
    left: 0px;
    top: calc(50% - 8px/2);
    background: #1F71FF;
    border-radius: 0px 3px 3px 0px;
  }
}
.ant-popover {
  padding-top: 0px;
  margin-top: 5px;
  .ant-popover-arrow {
    display: none;
  }
  .ant-popover-inner {
    box-shadow: 0px 16px 32px -6px rgba(15, 34, 67, 0.18), 0px 3px 8px -2px rgba(15, 34, 67, 0.16), 0px 0px 1px rgba(15, 34, 67, 0.16);
    border-radius: 8px;
    .ant-popover-inner-content {
      padding: 8px;
      p {
        padding: 5px 16px;
        margin: 0;
        cursor: pointer;
        &:hover {
          background: rgba(15, 34, 67, 0.05);
          border-radius: 6px;
        }
      }
    }
  }
}
</style>


posted @ 2023-06-03 23:39  Felix_Openmind  阅读(2412)  评论(0)    收藏  举报
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}