2025-12-15 11:05:27 +08:00
|
|
|
|
<template>
|
2026-04-07 17:40:01 +08:00
|
|
|
|
<div class="muti-select">
|
|
|
|
|
|
<!-- 下拉选择模式 -->
|
2026-04-16 10:18:21 +08:00
|
|
|
|
<div v-if="type === 'select'" class="select-container">
|
|
|
|
|
|
<el-select
|
|
|
|
|
|
v-model="innerValue"
|
|
|
|
|
|
multiple
|
|
|
|
|
|
:placeholder="placeholder"
|
|
|
|
|
|
:filterable="filterable"
|
|
|
|
|
|
:clearable="clearable"
|
|
|
|
|
|
:allow-create="allowAdd"
|
|
|
|
|
|
:disabled="disabled"
|
|
|
|
|
|
:size="size"
|
2026-04-24 17:49:11 +08:00
|
|
|
|
:collapse-tags="collapseTags"
|
2026-04-16 10:18:21 +08:00
|
|
|
|
@change="handleChange"
|
|
|
|
|
|
>
|
|
|
|
|
|
<!-- 全选选项 -->
|
2026-04-16 15:50:54 +08:00
|
|
|
|
<!-- <el-option
|
2026-04-16 10:18:21 +08:00
|
|
|
|
v-if="showSelectAll && options.length > 0"
|
|
|
|
|
|
key="selectAll"
|
|
|
|
|
|
label="全选"
|
|
|
|
|
|
value="selectAll"
|
|
|
|
|
|
@click="toggleSelectAll"
|
2026-04-16 15:50:54 +08:00
|
|
|
|
/> -->
|
2026-04-16 10:18:21 +08:00
|
|
|
|
<el-option
|
|
|
|
|
|
v-for="item in options"
|
|
|
|
|
|
:key="item.value"
|
|
|
|
|
|
:label="item.label"
|
|
|
|
|
|
:value="item.value"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</div>
|
2026-04-07 17:40:01 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 复选框模式 -->
|
|
|
|
|
|
<div v-else-if="type === 'checkbox'" class="checkbox-group">
|
|
|
|
|
|
<el-checkbox-group v-model="innerValue" @change="handleCheckboxChange">
|
|
|
|
|
|
<el-checkbox
|
|
|
|
|
|
v-for="item in options"
|
|
|
|
|
|
:key="item.value"
|
|
|
|
|
|
:label="item.value"
|
|
|
|
|
|
:disabled="disabled"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ item.label }}
|
|
|
|
|
|
</el-checkbox>
|
|
|
|
|
|
</el-checkbox-group>
|
2026-04-16 10:18:21 +08:00
|
|
|
|
<el-button
|
2026-04-07 17:40:01 +08:00
|
|
|
|
v-if="showSelectAll && options.length > 0"
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="toggleSelectAll"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ isAllSelected ? '取消全选' : '全选' }}
|
2026-04-16 10:18:21 +08:00
|
|
|
|
</el-button>
|
2026-04-07 17:40:01 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-12-15 11:05:27 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
2026-04-07 17:40:01 +08:00
|
|
|
|
<!-- v-model 绑定逗号分隔的字符串,可以 props 配置是否允许新增 -->
|
2025-12-15 11:05:27 +08:00
|
|
|
|
<script>
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: 'MutiSelect',
|
|
|
|
|
|
props: {
|
|
|
|
|
|
value: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: ''
|
|
|
|
|
|
},
|
|
|
|
|
|
options: {
|
|
|
|
|
|
type: Array,
|
|
|
|
|
|
default: () => []
|
|
|
|
|
|
},
|
|
|
|
|
|
allowAdd: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: false
|
2026-04-07 17:40:01 +08:00
|
|
|
|
},
|
|
|
|
|
|
type: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: 'select' // select or checkbox
|
|
|
|
|
|
},
|
|
|
|
|
|
placeholder: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: '请选择'
|
|
|
|
|
|
},
|
|
|
|
|
|
filterable: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: true
|
|
|
|
|
|
},
|
|
|
|
|
|
clearable: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: true
|
|
|
|
|
|
},
|
|
|
|
|
|
disabled: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: false
|
|
|
|
|
|
},
|
|
|
|
|
|
size: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: 'default' // large, default, small
|
|
|
|
|
|
},
|
|
|
|
|
|
showSelectAll: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: true
|
2026-04-24 17:49:11 +08:00
|
|
|
|
},
|
|
|
|
|
|
collapseTags: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: true
|
2025-12-15 11:05:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 计算属性捕获实现双向绑定
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
innerValue: {
|
|
|
|
|
|
get() {
|
|
|
|
|
|
if (!this.value) {
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
2026-04-07 17:40:01 +08:00
|
|
|
|
return this.value?.split(',');
|
2025-12-15 11:05:27 +08:00
|
|
|
|
},
|
|
|
|
|
|
set(val) {
|
2026-04-07 17:40:01 +08:00
|
|
|
|
const newValue = val?.join(',') ?? '';
|
|
|
|
|
|
this.$emit('input', newValue);
|
|
|
|
|
|
this.$emit('change', newValue);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 是否全选
|
|
|
|
|
|
isAllSelected() {
|
|
|
|
|
|
return this.options.length > 0 && this.innerValue.length === this.options.length;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
// 处理选择变化
|
|
|
|
|
|
handleChange(val) {
|
2026-04-16 10:18:21 +08:00
|
|
|
|
// 过滤掉 'selectAll' 选项
|
|
|
|
|
|
const filteredVal = val.filter(item => item !== 'selectAll');
|
|
|
|
|
|
this.$emit('change', filteredVal.join(','));
|
2026-04-07 17:40:01 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 处理复选框变化
|
|
|
|
|
|
handleCheckboxChange(val) {
|
|
|
|
|
|
const newValue = val.join(',');
|
|
|
|
|
|
this.$emit('input', newValue);
|
|
|
|
|
|
this.$emit('change', newValue);
|
|
|
|
|
|
},
|
|
|
|
|
|
// 切换全选/取消全选
|
|
|
|
|
|
toggleSelectAll() {
|
|
|
|
|
|
if (this.isAllSelected) {
|
|
|
|
|
|
this.innerValue = [];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.innerValue = this.options.map(item => item.value);
|
2025-12-15 11:05:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-04-07 17:40:01 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.muti-select {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.checkbox-group {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.checkbox-group .el-checkbox {
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|