Files
BMS/bms-front/src/components/UserSelect/index.vue
T
2026-09-30 09:18:23 +08:00

149 lines
4.0 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>
<el-select
v-model="innerValue"
:placeholder="placeholder"
:clearable="clearable"
:filterable="filterable"
:filter-method="filterMethod"
:disabled="disabled"
:loading="loading"
:size="size"
:multiple="false"
style="width: 100%;"
@change="handleChange"
@visible-change="handleVisibleChange"
>
<el-option
v-for="item in options"
:key="item.userId"
:label="formatLabel(item)"
:value="String(item[valueField])"
:disabled="item.status === '1'"
>
<span>{{ item.nickName || item.userName }}<template v-if="item.status === '1'">(停用)</template></span>
<span
v-if="showCode && item.userName"
class="user-select-sub"
>{{ item.userName }}</span>
</el-option>
</el-select>
</template>
<script setup name="UserSelect">
import { computed, onMounted, ref, watch } from 'vue'
import { useUsers } from './useUsers'
const props = defineProps({
/** 绑定值:用户ID(字符串/数字),清空时为 null */
modelValue: {
type: [String, Number],
default: null
},
placeholder: {
type: String,
default: '请选择用户'
},
clearable: {
type: Boolean,
default: true
},
filterable: {
type: Boolean,
default: true
},
disabled: {
type: Boolean,
default: false
},
size: {
type: String,
default: ''
},
/** 选项右侧是否显示登录账号 */
showCode: {
type: Boolean,
default: true
},
/** 绑定值字段:userId=用户ID(默认);userName=登录账号/工号(老系统迁移数据按工号存储时使用) */
valueField: {
type: String,
default: 'userId'
}
})
const emit = defineEmits(['update:modelValue', 'change'])
const { userList, ensureUsers } = useUsers()
const loading = ref(false)
/** 下拉搜索关键字(可同时匹配昵称/姓名与登录账号/工号) */
const filterQuery = ref('')
const innerValue = ref(props.modelValue === null || props.modelValue === undefined ? null : String(props.modelValue))
watch(() => props.modelValue, (val) => {
innerValue.value = val === null || val === undefined || val === '' ? null : String(val)
})
/** 按当前绑定值字段(userId 或 userName/工号)查找用户 */
function findByValue(val) {
if (val === null || val === undefined || val === '') return null
return userList.value.find(u => String(u[props.valueField]) === String(val)) || null
}
/** 自定义过滤:昵称/姓名、登录账号/工号 任一命中即可(忽略大小写) */
function matchUser(item, q) {
if (!q) return true
const kw = q.trim().toLowerCase()
if (!kw) return true
return ['nickName', 'userName'].some(k => item[k] && String(item[k]).toLowerCase().includes(kw))
}
function filterMethod(q) {
filterQuery.value = q || ''
}
/** 下拉收起后清空搜索词,恢复完整选项 */
function handleVisibleChange(visible) {
if (!visible) filterQuery.value = ''
}
/** 兜底:当前值在用户列表中不存在(停用/未加载到)时补占位项,避免显示空白 */
const options = computed(() => {
const list = userList.value.filter(item => matchUser(item, filterQuery.value))
if (innerValue.value && !findByValue(innerValue.value) && !filterQuery.value) {
return [{ userId: innerValue.value, userName: '', nickName: String(innerValue.value) }, ...list]
}
return list
})
/** 选项文本:停用用户追加(停用)标记,便于编辑历史数据时识别 */
function formatLabel(item) {
const name = item.nickName || item.userName
return item.status === '1' ? `${name}(停用)` : name
}
function handleChange(val) {
const value = val === '' ? null : val
emit('update:modelValue', value)
emit('change', value, value === null ? null : findByValue(value))
}
onMounted(() => {
loading.value = true
ensureUsers().finally(() => {
loading.value = false
})
})
defineExpose({
reload: () => ensureUsers(true)
})
</script>
<style scoped>
.user-select-sub {
float: right;
color: var(--el-text-color-secondary);
font-size: 12px;
}
</style>