Files
klp-oa/klp-ui/src/components/EmployeeSelector/index.vue
砂糖 53692fd024 fix(EmployeeSelector): 修复员工选择器中重复员工的问题
因为员工可能出现重名情况,添加去重逻辑确保selectedEmployees中每个员工的keyField是唯一的
2026-03-16 17:32:28 +08:00

353 lines
9.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="employee-selector">
<!-- 触发器 -->
<div class="trigger" @click="toggleDialog">
<slot name="trigger">
<div class="default-trigger">
{{ displayText }}
</div>
</slot>
</div>
<!-- 选择对话框 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-input v-model="searchQuery" placeholder="请输入员工姓名或部门" clearable @keyup.enter.native="handleSearch">
<el-button slot="append" icon="el-icon-search" @click="handleSearch" />
</el-input>
<!-- 已选员工列表多选模式 -->
<div v-if="multiple && selectedEmployees.length > 0" class="selected-list">
<div class="selected-list-title">已选员工 ({{ selectedEmployees.length }})</div>
<el-tag v-for="employee in selectedEmployees" :key="employee[keyField]" closable
@close="removeSelectedEmployee(employee)" class="selected-tag">
{{ employee.name }} ({{ employee.dept }})
</el-tag>
</div>
<el-table v-loading="loading" :data="employeeList" style="width: 100%" height="400px" @row-click="handleRowClick"
:row-class-name="rowClassName">
<el-table-column label="部门" align="center" prop="dept" />
<el-table-column label="姓名" align="center" prop="name" />
<el-table-column label="岗位工种" align="center" prop="jobType" />
<el-table-column label="联系电话" align="center" prop="phone" />
</el-table>
<div slot="footer" class="dialog-footer">
<el-button @click="cancelSelection">取消</el-button>
<el-button v-if="multiple" type="primary" @click="confirmSelection" :disabled="selectedEmployees.length === 0">
确认选择 ({{ selectedEmployees.length }})
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listEmployeeInfo } from '@/api/wms/employeeInfo'
export default {
name: 'EmployeeSelector',
props: {
value: {
type: [String, Array],
default: ''
},
keyField: {
type: String,
default: 'infoId'
},
placeholder: {
type: String,
default: '请选择员工'
},
title: {
type: String,
default: '选择员工'
},
multiple: {
type: Boolean,
default: false
},
disabledNames: {
type: String,
default: ''
}
},
data() {
return {
selectedEmployee: {},
selectedEmployees: [],
rawEmployeeList: [],
open: false,
loading: false,
searchQuery: ''
}
},
computed: {
// 显示在触发器上的文本
displayText() {
if (this.multiple) {
if (this.selectedEmployees.length > 0) {
return `${this.selectedEmployees.length} 人已选择`
} else {
return this.placeholder
}
} else {
return this.selectedEmployee.name || this.placeholder
}
},
// 禁用的员工ID列表
disabledIdList() {
if (!this.disabledNames) {
return []
}
return this.disabledNames.split(',').map(id => id.trim()).filter(id => id)
},
// 处理后的员工列表,包含禁用状态
employeeList() {
return this.rawEmployeeList.filter(employee => {
return employee.name?.includes(this.searchQuery) || employee.dept?.includes(this.searchQuery)
}).map(employee => ({
...employee,
disabled: this.disabledIdList.includes(employee.infoId.toString())
}))
}
},
watch: {
value: {
handler(newVal) {
if (this.multiple) {
if (newVal) {
// 多选模式:根据逗号分隔的字符串查找已选员工
this.findSelectedEmployees(newVal.split(','))
} else {
this.selectedEmployees = []
}
} else {
if (newVal) {
this.findSelectedEmployee(newVal)
} else {
this.selectedEmployee = {}
}
}
},
immediate: true
}
},
methods: {
// 切换对话框显示
toggleDialog() {
if (!this.open) {
this.getEmployeeList()
}
this.open = !this.open
},
// 获取员工列表
getEmployeeList() {
this.loading = true
const params = {
pageNum: 1,
pageSize: 9999,
// name: this.searchQuery || undefined,
// dept: this.searchQuery || undefined
}
return new Promise((resolve) => {
listEmployeeInfo(params).then(response => {
// 前端筛选员工列表,根据姓名或部门
this.rawEmployeeList = response.rows;
this.loading = false
resolve()
}).catch(() => {
this.loading = false
resolve()
})
})
},
// 搜索员工
handleSearch() {
this.getEmployeeList()
},
// 选择员工
handleRowClick(row) {
// 检查员工是否被禁用
if (this.isDisabled(row)) {
return
}
if (this.multiple) {
// 多选模式:添加或移除员工
const index = this.selectedEmployees.findIndex(item => item[this.keyField] === row[this.keyField])
if (index > -1) {
this.selectedEmployees.splice(index, 1)
} else {
this.selectedEmployees.push(row)
}
} else {
// 单选模式:选择员工并关闭弹窗
this.selectedEmployee = row
this.$emit('input', row[this.keyField])
this.$emit('change', row)
this.open = false
}
},
// 检查员工是否被禁用
isDisabled(row) {
const isDisabled = this.disabledIdList.includes(row[this.keyField].toString())
if (isDisabled) {
this.$message.warning('该员工已禁用,不能选择')
}
return isDisabled
},
// 确认选择(多选模式)
confirmSelection() {
const selectedIds = this.selectedEmployees.map(item => item[this.keyField])
this.$emit('input', selectedIds.join(','))
this.$emit('change', this.selectedEmployees)
this.open = false
},
cancelSelection() {
if (this.multiple) {
if (this.value) {
// 多选模式:根据逗号分隔的字符串查找已选员工
this.findSelectedEmployees(this.value.split(','))
} else {
this.selectedEmployees = []
}
} else {
if (this.value) {
this.findSelectedEmployee(this.value)
} else {
this.selectedEmployee = {}
}
}
this.open = false
},
// 移除已选员工
removeSelectedEmployee(employee) {
const index = this.selectedEmployees.findIndex(item => item[this.keyField] === employee[this.keyField])
if (index > -1) {
this.selectedEmployees.splice(index, 1)
}
},
// 表格行样式
rowClassName({ row }) {
// if (this.isDisabled(row)) {
// return 'disabled-row'
// }
if (this.isSelected(row)) {
return 'selected-row'
}
return ''
},
// 检查员工是否已选
isSelected(row) {
if (this.multiple) {
return this.selectedEmployees.some(item => item[this.keyField] === row[this.keyField])
} else {
return this.selectedEmployee[this.keyField] === row[this.keyField]
}
},
// 根据value查找选中的员工单选
findSelectedEmployee(value) {
if (this.employeeList.length > 0) {
const employee = this.employeeList.find(item => item[this.keyField] === value)
if (employee) {
this.selectedEmployee = employee
}
} else {
// 如果员工列表为空,先获取列表再查找
this.getEmployeeList().then(() => {
const employee = this.employeeList.find(item => item[this.keyField] === value)
if (employee) {
this.selectedEmployee = employee
}
})
}
},
// 根据value查找选中的员工多选
findSelectedEmployees(values) {
if (this.employeeList.length > 0) {
this.selectedEmployees = this.employeeList.filter(item => values.includes(item[this.keyField]))
// 因为员工可能出现重名所以需要去重保证selectedEmployees[i][this.keyField]是唯一的
this.selectedEmployees = this.selectedEmployees.filter((item, index, arr) => arr.findIndex(t => t[this.keyField] === item[this.keyField]) === index)
} else {
// 如果员工列表为空,先获取列表再查找
this.getEmployeeList().then(() => {
this.selectedEmployees = this.employeeList.filter(item => values.includes(item[this.keyField]))
this.selectedEmployees = this.selectedEmployees.filter((item, index, arr) => arr.findIndex(t => t[this.keyField] === item[this.keyField]) === index)
})
}
}
}
}
</script>
<style scoped>
.employee-selector {
position: relative;
}
.trigger {
cursor: pointer;
user-select: none;
}
.default-trigger {
padding: 2px 4px;
border: 1px solid #dcdfe6;
min-width: 120px;
font-size: 13px;
display: inline-block;
}
.default-trigger:hover {
border-color: #409eff;
}
.selected-list {
margin: 10px 0;
padding: 10px;
background-color: #f5f7fa;
border-radius: 4px;
}
.selected-list-title {
font-weight: bold;
margin-bottom: 8px;
color: #606266;
}
.selected-tag {
margin-right: 8px;
margin-bottom: 8px;
}
.el-table .selected-row {
background-color: #ecf5ff !important;
}
.el-table .selected-row:hover {
background-color: #ecf5ff !important;
}
.el-table .disabled-row {
background-color: #f5f7fa !important;
color: #c0c4cc !important;
}
.el-table .disabled-row:hover {
background-color: #f5f7fa !important;
color: #c0c4cc !important;
}
</style>