Files
lingji-work-fe/src/components/common-select/index.vue

128 lines
3.1 KiB
Vue
Raw Normal View History

2025-06-27 18:37:42 +08:00
<!--
* @Author: RenXiaoDong
* @Date: 2025-06-25 14:02:40
-->
<template>
2025-09-04 12:07:18 +08:00
<Select
v-model:value="selectedValues"
:mode="multiple ? 'multiple' : undefined"
size="middle"
2025-06-27 18:37:42 +08:00
:placeholder="placeholder"
2025-09-04 12:07:18 +08:00
:allowClear="allClear"
:showSearch="allowSearch"
showArrow
2025-09-15 19:40:07 +08:00
:maxTagCount="maxTagCount !== undefined ? maxTagCount : (multiple ? 3 : undefined)"
2025-06-27 18:37:42 +08:00
@change="handleChange"
2025-09-12 17:48:46 +08:00
:filterOption="allowSearch ? filterOption : undefined"
2025-06-27 18:37:42 +08:00
>
2025-09-12 17:46:01 +08:00
<Option v-for="(item, index) in validOptions" :key="index" :value="item.value" :label="item.label">
2025-09-04 11:09:21 +08:00
<div class="flex items-center">
2025-09-12 17:46:01 +08:00
<img v-if="item.icon" :src="item.icon" class="w-16px h-16px mr-4px rounded-4px" />
<span>{{ item.label }}</span>
2025-09-04 11:09:21 +08:00
</div>
2025-09-04 12:07:18 +08:00
</Option>
2025-09-12 17:46:01 +08:00
<template #tag="{ label, icon }">
<div class="flex items-center">
<img v-if="icon" :src="icon" class="w-16px h-16px mr-4px rounded-4px" />
<span>{{ label }}</span>
</div>
</template>
<template v-if="!allowSearch" #empty>
<div v-if="validOptions.length === 0" class="empty-placeholder">
{{ placeholder || '暂无数据' }}
</div>
</template>
2025-09-04 12:07:18 +08:00
</Select>
2025-06-27 18:37:42 +08:00
</template>
<script setup>
2025-09-04 12:07:18 +08:00
import { Select } from 'ant-design-vue';
const { Option } = Select;
2025-09-12 17:46:01 +08:00
import { ref, watch, computed } from 'vue';
2025-06-27 18:37:42 +08:00
const props = defineProps({
modelValue: {
type: [Array, String, Number],
default: () => [],
},
multiple: {
type: Boolean,
default: true,
},
placeholder: {
type: String,
default: '全部',
},
options: {
type: Array,
default: () => [],
},
maxTagCount: {
type: Number,
2025-09-15 19:40:07 +08:00
default: undefined,
2025-09-12 17:46:01 +08:00
},
2025-08-01 17:25:21 +08:00
allClear: {
type: Boolean,
default: true,
2025-09-01 17:33:19 +08:00
},
allowSearch: {
type: Boolean,
default: false,
2025-09-12 17:46:01 +08:00
},
2025-06-27 18:37:42 +08:00
});
const emits = defineEmits(['update:modelValue', 'change']);
const selectedValues = ref(props.multiple ? [] : '');
2025-06-27 18:37:42 +08:00
2025-09-12 17:46:01 +08:00
// 计算有效选项,兼容不同的数据格式
const validOptions = computed(() => {
if (!props.options || !Array.isArray(props.options)) {
return [];
}
return props.options
.filter(item => item && (item.id !== undefined || item.value !== undefined) && (item.name !== undefined || item.label !== undefined))
.map(item => ({
...item,
value: item.id !== undefined ? item.id : item.value,
label: item.name !== undefined ? item.name : item.label
}));
});
2025-06-27 18:37:42 +08:00
watch(
() => props.modelValue,
(newVal) => {
selectedValues.value = newVal;
2025-06-27 18:37:42 +08:00
},
{ immediate: true },
);
watch(selectedValues, (newVal) => {
2025-06-27 18:37:42 +08:00
emits('update:modelValue', newVal);
});
const handleChange = (value) => {
selectedValues.value = value;
2025-06-27 18:37:42 +08:00
emits('change', value);
};
2025-09-12 17:48:46 +08:00
// 搜索过滤函数
const filterOption = (input, option) => {
// 确保 input 和 option.label 都存在且为字符串
if (!input || !option || !option.label) {
return false;
}
// 不区分大小写的模糊搜索
return option.label.toString().toLowerCase().includes(input.toLowerCase());
};
2025-09-12 17:46:01 +08:00
</script>
<style scoped>
.empty-placeholder {
padding: 8px 12px;
color: #8f959e;
text-align: center;
}
</style>