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>
封装多人选择器组件:
<!-- 主题党日-人员选择器(多人选择器) -->
<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>
封装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>
替换组件内的获取组织树接口和获取人员接口
3.使用方法

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

浙公网安备 33010602011771号