antd-vue 人员选择组件

<template>
  <div>
    <a-form-model-item label="参与人" :labelCol="labelCol" :wrapperCol="wrapperCol">
      <a-button type="primary" icon="plus" @click="onClickParticipatePerson">选择人员</a-button>
      <div class="person_container">
        <div class="person_item" :key="index" v-for="(item, index) in personCheckList">
          {{ item.dataRef.title }}
          <a-button
            icon="close"
            size="small"
            class="selected_del"
            @click="clearParticipatePersonItem(item.dataRef.key, index, item)"
          />
        </div>
      </div>
    </a-form-model-item>
    <a-modal
      width="666px"
      :footer="null"
      title="选择成员"
      @cancel="handleCancel"
      :visible="personVisible"
      :confirm-loading="confirmLoading"
    >
      <div class="flex">
        <a-card style="width: 50%; border: none">
          <a-spin :spinning="loading">
            <div class="treeNode">
              <a-input-search v-model="searchText" style="margin-bottom: 8px" placeholder="输入部门或成员名称" />
              <a-tree
                key="id"
                checkable
                show-icon
                @check="onCheck"
                @expand="onExpand"
                :checkStrictly="false"
                :defaultExpandAll="true"
                :tree-data="filteredData"
                :checkedKeys="checkedKeys"
                :expandedKeys.sync="expandedKeys"
                :auto-expand-parent="autoExpandParent"
              >
                <template slot="title" slot-scope="text">
                  <span v-if="text.title.indexOf(searchText) > -1">
                    {{ text.title.substr(0, text.title.indexOf(searchText)) }}
                    <span style="color: #ff0000">{{ searchText }}</span>
                    {{ text.title.substr(text.title.indexOf(searchText) + searchText.length) }}
                  </span>
                  <span v-else>{{ text.title }}</span>
                </template>
              </a-tree>
            </div>
          </a-spin>
        </a-card>
        <a-card style="width: 50%" :title="`已选:${searchData.length}`" size="small">
          <a slot="extra" @click="clearAll">清空</a>
          <div class="selected_list treeNode">
            <div class="selected_item" v-for="(item, index) in searchData" :key="index">
              {{ item.dataRef.title }}
              <a-button
                icon="close"
                size="small"
                class="selected_del"
                @click="clearItem(item.dataRef.key, index, item)"
              />
            </div>
          </div>
        </a-card>
      </div>
      <div class="group-footer">
        <a-button style="margin-right: 10px" @click="handleCancel">取消</a-button>
        <a-button type="primary" @click="handleOver">确定</a-button>
      </div>
    </a-modal>
  </div>
</template>

<script>
export default {
  components: {},
  props: {
    // 树状图原始数据
    personList: {
      type: Array,
      default: () => [],
    },
    // 树状图选中数据
    personCheckList: {
      type: Array,
      default: () => [],
    },
    // 弹窗显示
    personVisible: {
      type: Boolean,
      default: false,
    },
  },
  watch: {
    personVisible: {
      handler() {
        this.initData()
      },
    },
  },
  data() {
    return {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 4 },
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 },
      },
      // 树状图数据
      treeData: [],
      // 加载状态
      loading: false,
      // 输入框
      searchText: '',
      // 选中数据
      searchData: [],
      checkedKeys: [],
      expandedKeys: [],
      // 默认选中数据
      // defaultCheckList: [],
      confirmLoading: false,
      // 父节点自动展开
      autoExpandParent: true,
    }
  },
  computed: {
    // 根据搜索关键字过滤数据
    filteredData() {
      return this.searchText ? this.filterData(this.treeData, this.searchText) : this.treeData
    },
  },
  created() {},
  methods: {
    // 初始化数据
    initData() {
      // 将默认选中数据中的key值存储checkedKeys数组中
      if (this.personCheckList.length > 0) {
        this.searchData = this.personCheckList
        this.checkedKeys = this.personCheckList.map((item) => item.dataRef.key)
      }
      this.treeData = this.processData(this.personList)
    },
    onClickParticipatePerson(e) {
      this.personVisible = true
    },
    // 删除当前选中审批人员数据
    clearParticipatePersonItem(id, index, record) {
      this.personCheckList.splice(index, 1)
    },
    // 树状图数据处理
    processData(data) {
      let result = []

      data.forEach((item) => {
        // 生成树状数据节点
        let nodeItem = {
          key: item.id,
          children: [],
          title: item.name,
        }
        // 人员列表
        if (item.personList && item.personList.length > 0) {
          nodeItem.children = this.processPersonList(item.personList)
        }
        // 如果当前节点包含下级子节点 递归调用方法
        if (item.children && item.children.length > 0) {
          nodeItem.children.push(...this.processData(item.children))
        }

        result.push(nodeItem)
      })
      return result
    },
    // 人员数据处理
    processPersonList(personList) {
      return personList.map((item) => ({
        key: item.id,
        title: item.realname,
      }))
    },
    // 输入框搜索
    filterData(data, searchText) {
      const result = []
      for (let item of data) {
        if (item.title.includes(searchText)) {
          result.push(item)
          continue
        }
        if (item.children) {
          const children = this.filterData(item.children, searchText)
          if (children.length > 0) {
            this.expandedKeys.push(item.key)
            result.push({ ...item, children })
          }
        }
      }
      return result
    },
    // 人员选择完成
    handleOver() {
      this.confirmLoading = true

      // 将选中数据传递向父组件
      this.$emit('personCheckUpdate', this.searchData)

      // 关闭弹窗
      this.$emit('personCancel', false)
    },
    // 关闭人员选择弹窗
    handleCancel() {
      // 清空选中数据
      this.searchText = ''
      this.searchData = []
      this.checkedKeys = []
      // 关闭弹窗
      this.$emit('personCancel', false)
    },
    onExpand(expandedKeys) {
      this.expandedKeys = expandedKeys
      this.autoExpandParent = false
    },
    // 树状图节点点击
    onCheck(checkedKeys, nodes) {
      this.searchData = []
      nodes.checkedNodes.forEach((item) => {
        // 只保留人员
        if (!item.data.props.dataRef.children) {
          this.searchData.push(item.data.props)
        }
      })
      this.checkedKeys = checkedKeys
    },
    // 清除所有选中节点
    clearAll() {
      this.searchData = []
      this.checkedKeys = []
    },
    // 清除当前选中节点
    clearItem(id, index, record) {
      this.searchData.splice(index, 1)
      for (let i = 0; i < this.checkedKeys.length; i++) {
        if (this.checkedKeys[i] == id) {
          this.checkedKeys.splice(i, 1)
        }
      }
    },
  },
}
</script>

<style lang="less" scoped>
.treeNode {
  height: 400px;
  overflow-y: scroll;

  &::-webkit-scrollbar {
    width: 6px;
    height: 1px;
  }

  &::-webkit-scrollbar-thumb {
    border-radius: 6px;
    background: rgba(144, 147, 153, 0.5);
  }

  &::-webkit-scrollbar-track {
    border-radius: 5px;
    background: transparent;
  }
}
.flex {
  display: flex;
}
/deep/ .ant-card-body {
  padding: 0;
}
/deep/ .ant-card-head {
  background-color: #fff;
}
.selected_list {
  flex: 1 1;
  margin: 0 4px;
  overflow: auto;
  .selected_item {
    height: 36px;
    display: flex;
    padding: 0 16px;
    font-size: 14px;
    cursor: pointer;
    border-radius: 2px;
    color: #111a34;
    position: relative;
    align-items: center;
    justify-content: space-between;
    &:hover {
      background-color: #f7f8fb;
      .selected_del {
        display: block;
      }
    }
    .selected_del {
      display: none;
      cursor: pointer;
      transition: all 0.3s;
    }
  }
}

.group-footer {
  display: flex;
  margin-top: 30px;
  justify-content: center;
}
</style>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: antd-mobile-vue是一个基于Vue.js框架的移动端组件库,它提供了一系列UI组件,用于开发高质量的移动端应用。 与其它UI组件库相比,antd-mobile-vue具有以下优势和特点: 1. 高质量的组件antd-mobile-vue提供了丰富的移动端UI组件,如按钮、表单、弹窗、导航等,这些组件都经过了精心设计和开发,具有统一的风格和良好的用户体验。 2. 灵活的布局:antd-mobile-vue提供了灵活的布局组件,如栅格布局、Flex布局,可帮助开发者快速搭建页面结构,并自适应不同的屏幕尺寸。 3. 易于使用和扩展:antd-mobile-vue组件使用简单,开发者可以通过简单的配置和参数就可以实现复杂的交互效果。而且,antd-mobile-vue组件提供了丰富的扩展能力,可以根据项目需求进行个性化的定制。 4. 生态丰富:antd-mobile-vue拥有庞大的开发者社区和活跃的维护团队,开发者可以通过官方文档和社区资源获取帮助和支持。此外,antd-mobile-vue还与其它Vue.js生态工具和库良好地兼容,如Vue Router、Vue CLI等。 5. 支持国际化:antd-mobile-vue提供了多语言支持,开发者可以根据项目需求灵活地切换多种语言环境。 总之,antd-mobile-vue是一个功能强大、易于使用和扩展的移动端组件库,它可以帮助开发者快速构建高质量的移动端应用,提高开发效率和用户体验。 ### 回答2: antd-mobile-vue是一种基于Vue.js框架的移动端UI库。它是对Ant Design Mobile的Vue组件实现的封装和扩展,旨在为开发者提供高质量、易用性的移动端组件库,帮助快速开发移动应用程序。 antd-mobile-vue提供了丰富的移动端UI组件,如按钮、导航栏、标签栏、列表、表单等,可以满足日常开发中绝大部分的界面需求。这些组件都经过精心设计和优化,在视觉和交互上都符合当前移动端的设计原则和用户体验。而且,它还提供了灵活的定制和扩展能力,允许开发者根据具体需求进行个性化定制,提高开发效率和用户体验。 除了UI组件外,antd-mobile-vue还提供了一些实用的工具和功能,如样式工具库、语言国际化、路由管理等。这些工具和功能都是为了让开发者更方便地进行移动应用开发,减少重复性的工作,提高开发效率。 antd-mobile-vue拥有广泛的社区支持和文档资料,开发者可以从社区中获取帮助和解决问题,学习和掌握使用该库的技巧和最佳实践。同时,antd-mobile-vue还提供了详细的官方文档和示例代码,方便开发者快速入手和上手该库。 总之,antd-mobile-vue是一款功能强大、易用性强的移动端UI库,适用于各种移动应用的开发。无论是个人开发者还是团队开发,都可以通过使用antd-mobile-vue来快速构建高质量的移动应用程序。 ### 回答3: antd-mobile-vue 是一个基于 Vue.js 的移动端 UI 组件库,它提供了丰富的移动端组件和样式风格,可以帮助开发者快速构建优雅的移动端应用。 antd-mobile-vue 的特点有以下几个方面: 1. 高度可定制:antd-mobile-vue 提供了大量的组件,涵盖了移动端常见的UI元素,如按钮、导航栏、表单等,这些组件的样式和交互行为都可以通过配置进行定制,满足不同项目的需求。 2. 兼容性强:antd-mobile-vue 提供了对不同移动端浏览器和操作系统的支持,保证组件在不同环境下的正常运行和展示,同时也保证了用户的使用体验。 3. 特色设计:antd-mobile-vue 的设计风格简洁、现代,符合移动端用户的审美要求,同时也遵循了 Material Design 和 iOS Human Interface Guidelines 等设计准则,保证了用户的熟悉感和易用性。 4. 文档丰富:antd-mobile-vue 提供了详细的文档和示例代码,开发者可以根据文档了解组件的使用方法和配置参数,快速上手使用。 5. 生态丰富:antd-mobile-vue 是基于 Ant Design Mobile(antd-mobile)的 Vue 实现,可以与其它 Vue 生态工具和插件无缝集成,如 Vue Router、Vuex 等,方便开发者构建复杂的移动应用。 总之,antd-mobile-vue 是一个强大而灵活的移动端 UI 组件库,它可以帮助开发者节省时间和精力,快速开发出高质量的移动应用。无论是个人项目还是企业应用,都可以考虑使用这个库来提升开发效率和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值