Files
cn-rdms-web/src/components/custom/business-user-select.vue

132 lines
3.1 KiB
Vue
Raw Normal View History

<script setup lang="ts">
import { computed, ref } from 'vue';
defineOptions({ name: 'BusinessUserSelect' });
interface Props {
options: Api.SystemManage.UserSimple[];
placeholder?: string;
disabled?: boolean;
clearable?: boolean;
disabledUserIds?: readonly string[];
excludeUserIds?: readonly string[];
disabledLabel?: string;
noDataText?: string;
}
const props = withDefaults(defineProps<Props>(), {
placeholder: '请选择用户',
disabled: false,
clearable: true,
disabledUserIds: () => [],
excludeUserIds: () => [],
disabledLabel: '',
noDataText: ''
});
const model = defineModel<string | null>('modelValue', {
default: null
});
const searchKeyword = ref('');
const disabledUserIdSet = computed(() => new Set(props.disabledUserIds.map(id => String(id))));
const excludeUserIdSet = computed(() => new Set(props.excludeUserIds.map(id => String(id))));
const visibleOptions = computed(() => {
const keyword = searchKeyword.value.trim().toLocaleLowerCase();
const options = props.options.filter(item => !excludeUserIdSet.value.has(String(item.id)));
if (!keyword) {
return options;
}
return options.filter(item => {
const searchText = [item.nickname, item.username, item.deptName, item.id]
.filter(Boolean)
.join(' ')
.toLocaleLowerCase();
return searchText.includes(keyword);
});
});
function handleFilter(value: string) {
searchKeyword.value = value;
}
</script>
<template>
<ElSelect
v-model="model"
class="w-full"
filterable
:filter-method="handleFilter"
:clearable="clearable"
:disabled="disabled"
:placeholder="placeholder"
:no-data-text="noDataText || undefined"
>
<ElOption
v-for="item in visibleOptions"
:key="item.id"
:label="item.nickname"
:value="item.id"
:disabled="disabledUserIdSet.has(String(item.id))"
>
<div class="business-user-select__option">
<span class="business-user-select__name">{{ item.nickname }}</span>
<span class="business-user-select__suffix">
<ElTag
v-if="disabledLabel && disabledUserIdSet.has(String(item.id))"
size="small"
type="warning"
effect="light"
disable-transitions
>
{{ disabledLabel }}
</ElTag>
<span v-if="item.deptName || item.username" class="business-user-select__meta">
{{ [item.username, item.deptName].filter(Boolean).join(' · ') }}
</span>
</span>
</div>
</ElOption>
</ElSelect>
</template>
<style scoped>
.business-user-select__option {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
min-width: 0;
}
.business-user-select__name {
min-width: 0;
overflow: hidden;
color: rgb(15 23 42 / 94%);
font-weight: 500;
text-overflow: ellipsis;
white-space: nowrap;
}
.business-user-select__suffix {
display: inline-flex;
align-items: center;
flex: 0 0 auto;
max-width: 58%;
gap: 8px;
}
.business-user-select__meta {
min-width: 0;
overflow: hidden;
color: rgb(100 116 139 / 88%);
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>