vue-element-ui实现人员选择器

1.演示:

人员单选

人员多选

 2.代码:

封装单人选择器组件:

<!-- 主题党日-人员选择器(单人选择器) -->
<template>
  <div>
    <el-input v-model="perSelector.name" :readonly="true" :disabled="editVisible" placeholder="请选择人员" @focus="openPerSelector"><i slot="suffix" class="el-icon-s-operation" style="color: #c0c4cc;margin-right: 10px;" /></el-input>
    <el-dialog :title="title" :visible.sync="open" :before-close="handleCancel" width="70%" :append-to-body="true">
      <div>
        <el-row>
          <el-col :span="6">
            <el-input v-model="orgQuery.name" placeholder="请输入组织名称" clearable :validate-event="false" class="input-with-select perSelector-select-input-icon" size="mini" @input="orgFilter" @keyup.enter.native="orgFilter">
              <el-button slot="append" icon="el-icon-search" @click="orgFilter" />
            </el-input>
            <el-tree
              ref="tree"
              v-loading="orgLoading"
              class="el-table-high"
              :data="orgTree"
              :props="defaultProps"
              :default-expand-all="true"
              :expand-on-click-node="false"
              :draggable="false"
              :highlight-current="true"
              :filter-node-method="filterNode"
              :current-node-key="currentKey"
              node-key="id"
              @node-click="handleNodeClick"
            />
          </el-col>
          <el-col :span="13">
            <el-row>
              <el-col :span="24" align="right">
                <el-input
                  v-model="tableQuery.name"
                  placeholder="请输入姓名"
                  size="mini"
                  class="filter-item perSelector-select-input-icon"
                  clearable
                  :validate-event="false"
                  @input="queryDataSelect"
                  @keyup.enter.native="queryDataSelect"
                >
                  <i slot="suffix" style="cursor: pointer" class="el-input__icon el-icon-search" @click="queryDataSelect" />
                </el-input>
              </el-col>
            </el-row>
            <el-row>
              <el-table
                ref="multipleTable"
                v-loading="listLoading"
                highlight-current-row
                class="el-table-high"
                :data="tableData"
                style="width: 100%"
                size="mini"
                row-key="id"
                :header-cell-style="headerCellStyle"
                @current-change="handleSelect"
              >
                <el-table-column
                  type="index"
                  width="50"
                  label="序号"
                  align="center"
                />
                <el-table-column align="center" prop="name" label="人员姓名" />
                <el-table-column align="center" prop="phone" label="手机号码" />
              </el-table>
              <pagination
                v-show="tableQuery.total > 0"
                v-loading="paginationLoading"
                element-loading-spinner="el-icon-loading"
                class="perSelector-paginationIcon"
                :total="tableQuery.total"
                :page.sync="tableQuery.pageNo"
                :limit.sync="tableQuery.pageSize"
                @pagination="queryData"
              />
            </el-row>
          </el-col>
          <el-col :span="5">
            <el-row>
              <el-col :span="12">
                <div class="selectText">已选人员</div>
              </el-col>
              <el-col :span="12" align="right">
                <el-button type="text" size="mini" class="delAll" @click="delAll">清空</el-button>
              </el-col>
            </el-row>
            <el-row>
              <ul class="el-table-high">
                <li v-show="!nameDisplay" style="list-style-type: none;">
                  <el-row>
                    <div class="selectLi">
                      <el-col :span="8">
                        <div>{{ currentRow.name }}</div>
                      </el-col>
                      <el-col :span="16">
                        <div>{{ currentRow.phone }}</div>
                      </el-col>
                    </div>
                  </el-row>
                </li>
              </ul>
            </el-row>
          </el-col>
        </el-row>
      </div>
      <div align="right" class="tree_btn">
        <el-button type="primary" size="mini" @click="save">确 认</el-button>
        <el-button size="mini" @click="handleCancel">取 消</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import api from '@/api/hrOrganization'
import {
  getPartyMemberList
} from '@/api/party/database/partyMembers'
import Pagination from '@/components/Pagination'
import {
  mapGetters
} from 'vuex'
export default {
  name: 'PerSelectorThemeDay',
  components: {
    Pagination
  },
  props: {
    // 已选人员
    perSelector: {
      type: Object,
      default: () => {}
    },
    // 是否可编辑
    editVisible: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      headerCellStyle: {
        backgroundColor: '#FAFAFA'
      },
      orgLoading: true,
      listLoading: true,
      paginationLoading: true,
      title: '选择人员',
      // 组织查询参数
      orgQuery: {},
      // 组织树配置选项
      defaultProps: {
        id: 'id',
        children: 'children',
        label: 'name'
      },
      orgTree: [],
      // 组织树当前选中的节点
      currentKey: '',
      // 人员列表查询参数
      tableQuery: {
        name: null,
        orgId: null,
        pageNo: 1,
        pageSize: 10,
        total: 0
      },
      // 人员列表
      tableData: [],
      // 已选人员
      currentRow: {},
      // 是否显示弹出层
      open: false,
      nameDisplay: true
    }
  },
  watch: {
    perSelector(newVal, oldVal) {
      if (newVal === null) {
        this.$emit('handleConfirm', {})
      } else {
        this.nameDisplay = false
        this.perSelector = newVal
      }
    }
  },
  computed: {
    ...mapGetters(['orgId'])
  },
  created() {},
  methods: {
    // 打开人员窗口加载组织人员数据
    openPerSelector() {
      // 每次打开清空组织/人员搜索数据
      this.orgQuery = {}
      this.tableQuery.name = null
      // 每次打开窗口显示第一页
      this.tableQuery.pageNo = 1
      this.initOrgTree()
      // 初始化已选人员列表
      this.currentRow = this.perSelector
      this.open = true
    },
    initOrgTree() {
      this.orgLoading = true
      this.listLoading = true
      this.paginationLoading = true
      api.currentTree().then(res => {
        this.orgTree = res.data
        this.currentKey = res.data[0].id
        this.$nextTick(() => {
          this.$refs.tree.setCurrentKey(this.currentKey)
        })
        this.tableQuery.orgId = res.data[0].id
        this.queryData()
        this.orgLoading = false
      })
    },
    // 对树节点进行筛选时执行的方法
    filterNode(value, data) {
      if (!value) return true
      return data.name.indexOf(value) !== -1
    },
    // 树节点被点击时的回调
    handleNodeClick(data) {
      this.tableQuery.orgId = data.id
      this.queryDataSelect()
    },
    // 组织查询按钮
    orgFilter() {
      this.$nextTick(() => {
        this.$refs.tree.filter(this.orgQuery.name)
      })
    },
    // 查询人员列表
    queryData() {
      this.tableQuery.unfinished = false
      this.getTableList()
    },
    queryDataSelect() {
      this.tableQuery.pageNo = 1
      this.getTableList()
    },
    getTableList() {
      this.listLoading = true
      this.paginationLoading = true
      getPartyMemberList(this.tableQuery).then(res => {
        this.tableData = res.data.data
        this.tableQuery.total = Number(res.data.total)
        this.$nextTick(() => {
          this.seletListPer()
        })
        this.listLoading = false
        this.paginationLoading = false
      })
    },
    // 根据已选人员列表设置人员列表选中状态(初始化加载只有首页人员选中)
    seletListPer() {
      this.$nextTick(() => {
        for (var i = 0; i < this.tableData.length; i++) {
          var per = this.tableData[i]
          if (this.currentRow.userId === per.userId) {
            this.$refs.multipleTable.setCurrentRow(per)
          }
        }
      })
    },
    // 人员列表单选(手动勾选数据行时会触发该事件)
    handleSelect(val) {
      this.nameDisplay = false
      this.currentRow = val
    },
    // 取消
    handleCancel() {
      this.$emit('handleCancel', false)
      // 清空人员列表选中状态
      this.$nextTick(() => {
        var per = {
          name: undefined
        }
        this.$refs.multipleTable.setCurrentRow(per)
        if (this.perSelector.name === undefined) {
          this.nameDisplay = true
        }
      })
      this.open = false
    },
    // 清空已选员工
    delAll() {
      this.nameDisplay = true
      // 清空人员列表选中状态
      this.$nextTick(() => {
        var per = {
          name: undefined
        }
        this.$refs.multipleTable.setCurrentRow(per)
      })
    },
    save() {
      // if (this.currentRow.name !== undefined) {
      this.$emit('handleConfirm', this.currentRow)
      this.handleCancel()
      // } else {
      //   this.$message({
      //     showClose: true,
      //     message: '请选择人员',
      //     type: 'warning'
      //   })
      // }
    }
  }
}
</script>

<style lang="scss" scoped>
  .divTinymce {
    border: 1px solid #e4e7ed;
    border-radius: 5px;
    background-color: #f5f7fa;
    color: #c0c4cc;
  }

  .divTinymceIn {
    padding-right: 15px;
    padding-left: 15px;
    background-color: #f5f7fa;
    color: #c0c4cc;
  }

  .divTinymceShow {
    border: 1px solid #e4e7ed;
    border-radius: 5px;
  }

  .divTinymceInShow {
    padding-right: 15px;
    padding-left: 15px;
  }

  .selectText {
    text-align: center;
    height: 28px;
    line-height: 28px;
    font-size: 12px;
  }

  .selectLi {
    height: 28px;
    line-height: 28px;
    font-size: 12px;
  }

  .el-table-high {
    height: 54.9vh;
    overflow: auto;
  }
</style>
<style lang="scss">
  //不显示搜索input输入验证icon图标
  .perSelector-select-input-icon .el-input__validateIcon {
    width: 0% !important;
  }
  .perSelector-select-input-icon .el-input__validateIcon:before{
    content: "" !important;
  }
  //不显示分页组件input输入验证icon图标
  .perSelector-paginationIcon .el-input__validateIcon {
    width: 0% !important;
  }
  .perSelector-paginationIcon .el-input__validateIcon:before{
    content: "" !important;
  }
</style>
View Code

封装多人选择器组件:

<!-- 主题党日-人员选择器(多人选择器) -->
<template>
  <div>
    <div v-if="editVisible" class="divTinymce">
      <div class="divTinymceIn">
        <el-tag v-for="perSelector in perSelectorList" :key="perSelector.userId" size="mini" type="info">
          {{ perSelector.name }}
        </el-tag>
        <div v-show="!perSelectorList.length>0">
          <el-row>
            <el-col :span="20">
              <span style="color: #c0c4cc;">请选择人员</span>
            </el-col>
            <el-col :span="4" align="right">
              <i class="el-icon-s-operation" style="color: #c0c4cc;" />
            </el-col>
          </el-row>
        </div>
      </div>
    </div>
    <div v-else class="divTinymceShow" @click="openPerSelector">
      <div class="divTinymceInShow">
        <el-tag v-for="perSelector in perSelectorList" :key="perSelector.userId" size="mini" type="info">
          {{ perSelector.name }}
        </el-tag>
        <div v-show="!perSelectorList.length>0">
          <el-row>
            <el-col :span="20">
              <span style="color: #c0c4cc;">请选择人员</span>
            </el-col>
            <el-col :span="4" align="right">
              <i class="el-icon-s-operation" style="color: #c0c4cc;" />
            </el-col>
          </el-row>
        </div>
      </div>
    </div>
    <el-dialog :title="title" :visible.sync="open" :before-close="handleCancel" width="70%" :append-to-body="true">
      <div>
        <el-row>
          <el-col :span="6">
            <el-input v-model="orgQuery.name" placeholder="请输入组织名称" clearable :validate-event="false" class="input-with-select" size="mini" @input="orgFilter" @keyup.enter.native="orgFilter">
              <el-button slot="append" icon="el-icon-search" @click="orgFilter" />
            </el-input>
            <el-tree
              ref="tree"
              v-loading="orgLoading"
              class="el-table-high"
              :data="orgTree"
              :props="defaultProps"
              :default-expand-all="true"
              :expand-on-click-node="false"
              :draggable="false"
              :highlight-current="true"
              :filter-node-method="filterNode"
              :current-node-key="currentKey"
              node-key="id"
              @node-click="handleNodeClick"
            />
          </el-col>
          <el-col :span="13">
            <el-row>
              <el-col :span="24" align="right">
                <el-input
                  v-model="tableQuery.name"
                  placeholder="请输入姓名"
                  size="mini"
                  class="filter-item"
                  clearable
                  :validate-event="false"
                  @input="queryDataSelect"
                  @keyup.enter.native="queryDataSelect"
                >
                  <i slot="suffix" style="cursor: pointer" class="el-input__icon el-icon-search" @click="queryDataSelect" />
                </el-input>
              </el-col>
            </el-row>
            <el-row>
              <el-table
                ref="multipleTable"
                v-loading="listLoading"
                class="el-table-high"
                :data="tableData"
                style="width: 100%"
                size="mini"
                row-key="id"
                :header-cell-style="headerCellStyle"
                @selection-change="handleSelect"
                @row-click="rowClick"
              >
                <el-table-column align="center" type="selection" width="50px" :reserve-selection="true" />
                <el-table-column align="center" prop="name" label="人员姓名" />
                <el-table-column align="center" prop="phone" label="手机号码" />
              </el-table>
              <pagination
                v-show="tableQuery.total > 0"
                v-loading="paginationLoading"
                element-loading-spinner="el-icon-loading"
                :total="tableQuery.total"
                :page.sync="tableQuery.pageNo"
                :limit.sync="tableQuery.pageSize"
                @pagination="queryData"
              />
            </el-row>
          </el-col>
          <el-col :span="5">
            <el-row>
              <el-col :span="12">
                <div class="selectText">已选人员(<span style="color: #0080FF;">{{ selectList.length }}</span>)</div>
              </el-col>
              <el-col :span="12" align="right">
                <el-button type="text" size="mini" class="delAll" @click="delAll">清空</el-button>
              </el-col>
            </el-row>
            <el-row>
              <ul class="el-table-high">
                <li v-for="(item, index) in selectList" :key="index" style="list-style-type: none;">
                  <el-row>
                    <div class="selectLi">
                      <el-col :span="8">
                        <div>{{ item.name }}</div>
                      </el-col>
                      <el-col :span="12">
                        <div>{{ item.phone }}</div>
                      </el-col>
                      <el-col :span="4" align="right">
                        <!-- <el-button type="text" size="small" @click="handleDelSelect(item)"><i class="el-icon-delete" /> -->
                        <!-- </el-button> -->
                      </el-col>
                    </div>
                  </el-row>
                </li>
              </ul>
            </el-row>
          </el-col>
        </el-row>
      </div>
      <div align="right" class="tree_btn">
        <el-button type="primary" size="mini" @click="save">确 认</el-button>
        <el-button size="mini" @click="handleCancel">取 消</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import api from '@/api/hrOrganization'
import {
  getPartyMemberList
} from '@/api/party/database/partyMembers'
import Pagination from '@/components/Pagination'
import {
  mapGetters
} from 'vuex'
export default {
  name: 'PerSelectorsThemeDay',
  components: {
    Pagination
  },
  props: {
    // 已选人员数组
    perSelectorList: {
      type: Array,
      default: () => []
    },
    // 是否可编辑
    editVisible: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      headerCellStyle: {
        backgroundColor: '#FAFAFA'
      },
      orgLoading: true,
      listLoading: true,
      paginationLoading: true,
      title: '选择人员',
      // 已选员工列表
      selectList: [],
      // 组织查询参数
      orgQuery: {},
      // 组织树配置选项
      defaultProps: {
        id: 'id',
        children: 'children',
        label: 'name'
      },
      orgTree: [],
      // 组织树当前选中的节点
      currentKey: '',
      // 人员列表查询参数
      tableQuery: {
        name: null,
        orgId: null,
        pageNo: 1,
        pageSize: 10,
        total: 0
      },
      // 人员列表
      tableData: [],
      // 是否显示弹出层
      open: false
    }
  },
  watch: {
    perSelectorList(newVal, oldVal) {
      this.perSelectorList = newVal
    }
  },
  computed: {
    ...mapGetters(['orgId'])
  },
  created() {},
  methods: {
    // 打开人员窗口加载组织人员数据
    openPerSelector() {
      // 每次打开清空组织/人员搜索数据
      this.orgQuery = {}
      this.tableQuery.name = null
      // 每次打开窗口显示第一页
      this.tableQuery.pageNo = 1
      this.initOrgTree()
      // 初始化已选人员列表,根据已选人员列表设置人员列表选中状态(初始化加载)
      this.$nextTick(() => {
        for (var j = 0; j < this.perSelectorList.length; j++) {
          this.$refs.multipleTable.toggleRowSelection(this.perSelectorList[j], true)
        }
      })
      this.open = true
    },
    initOrgTree() {
      this.orgLoading = true
      this.listLoading = true
      this.paginationLoading = true
      api.currentTree().then(res => {
        this.orgTree = res.data
        this.currentKey = res.data[0].id
        this.$nextTick(() => {
          this.$refs.tree.setCurrentKey(this.currentKey)
        })
        this.tableQuery.orgId = res.data[0].id
        this.queryData()
        this.orgLoading = false
      })
    },
    // 对树节点进行筛选时执行的方法
    filterNode(value, data) {
      if (!value) return true
      return data.name.indexOf(value) !== -1
    },
    // 树节点被点击时的回调
    handleNodeClick(data) {
      this.tableQuery.orgId = data.id
      this.queryDataSelect()
    },
    // 组织查询按钮
    orgFilter() {
      this.$nextTick(() => {
        this.$refs.tree.filter(this.orgQuery.name)
      })
    },
    // 查询人员列表
    queryData() {
      this.tableQuery.unfinished = false
      this.getTableList()
    },
    queryDataSelect() {
      this.tableQuery.pageNo = 1
      this.getTableList()
    },
    getTableList() {
      this.listLoading = true
      this.paginationLoading = true
      getPartyMemberList(this.tableQuery).then(res => {
        this.tableData = res.data.data
        this.tableQuery.total = Number(res.data.total)
        this.listLoading = false
        this.paginationLoading = false
      })
    },
    // 人员列表多选(手动勾选数据行时会触发该事件)
    handleSelect(val) {
      this.selectList = val
    },
    // 人员列表行点击事件
    rowClick(val) {
      this.$nextTick(() => {
        this.$refs.multipleTable.toggleRowSelection(val)
      })
    },
    // 选择员工内的删除
    handleDelSelect(data) {
      this.$nextTick(() => {
        this.$refs.multipleTable.toggleRowSelection(data, true)
        this.$refs.multipleTable.toggleRowSelection(data, false)
      })
    },
    // 取消
    handleCancel() {
      this.$emit('handleCancel', false)
      this.selectList = []
      // 清空人员列表选中状态
      this.$nextTick(() => {
        this.$refs.multipleTable.clearSelection()
      })
      this.open = false
    },
    // 清空已选员工
    delAll() {
      this.selectList = []
      // 清空人员列表选中状态
      this.$nextTick(() => {
        this.$refs.multipleTable.clearSelection()
      })
    },
    save() {
      // if (this.selectList.length) {
      this.$emit('handleConfirm', this.selectList)
      this.handleCancel()
      // } else {
      //   this.$message({
      //     showClose: true,
      //     message: '请选择人员',
      //     type: 'warning'
      //   })
      // }
    }
  }
}
</script>

<style lang="scss" scoped>
  .divTinymce {
    border: 1px solid #e4e7ed;
    border-radius: 5px;
    background-color: #f5f7fa;
    color: #c0c4cc;
  }

  .divTinymceIn {
    padding-right: 15px;
    padding-left: 15px;
    background-color: #f5f7fa;
    color: #c0c4cc;
  }

  .divTinymceShow {
    border: 1px solid #e4e7ed;
    border-radius: 5px;
  }

  .divTinymceInShow {
    padding-right: 15px;
    padding-left: 15px;
  }

  .selectText {
    text-align: center;
    height: 28px;
    line-height: 28px;
    font-size: 12px;
  }

  .selectLi {
    height: 28px;
    line-height: 28px;
    font-size: 12px;
  }

  .el-table-high {
    height: 56.1vh;
    overflow: auto;
  }
</style>
View Code

封装Pagination分页组件:

<template>
  <div :class="{'hidden':hidden}" class="pagination-container">
    <el-pagination
      :background="background"
      :current-page.sync="currentPage"
      :page-size.sync="pageSize"
      :layout="layout"
      :page-sizes="pageSizes"
      :total="total"
      v-bind="$attrs"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  </div>
</template>

<script>
import { scrollTo } from '@/utils/scroll-to'

export default {
  name: 'Pagination',
  props: {
    total: {
      required: true,
      type: Number
    },
    page: {
      type: Number,
      default: 1
    },
    limit: {
      type: Number,
      default: 10
    },
    pageSizes: {
      type: Array,
      default() {
        return [10, 20, 50]
      }
    },
    layout: {
      type: String,
      default: 'total, sizes, prev, pager, next, jumper'
    },
    background: {
      type: Boolean,
      default: true
    },
    autoScroll: {
      type: Boolean,
      default: true
    },
    hidden: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    currentPage: {
      get() {
        return this.page
      },
      set(val) {
        this.$emit('update:page', val)
      }
    },
    pageSize: {
      get() {
        return this.limit
      },
      set(val) {
        this.$emit('update:limit', val)
      }
    }
  },
  methods: {
    handleSizeChange(val) {
      this.$emit('pagination', { page: this.currentPage, limit: val })
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    },
    handleCurrentChange(val) {
      this.$emit('pagination', { page: val, limit: this.pageSize })
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    }
  }
}
</script>

<style scoped>
.pagination-container {
  background: #fff;
  padding: 5px;
}
.pagination-container.hidden {
  display: none;
}
</style>
View Code

替换组件内的获取组织树接口和获取人员接口

3.使用方法

 

import perSelectorThemeDay from '@/components/perSelectorThemeDay'
export default {
    components: {
        perSelectorThemeDay,
    },
    data() {
        return {
            form: {
                content: null,
            },
        }
    },
}

 

posted @ 2022-05-27 11:37  Ning-  阅读(2608)  评论(2编辑  收藏  举报