| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- <template>
- <el-select
- :value="displayValue"
- multiple
- filterable
- clearable
- :filter-method="handleFilter"
- @input="handleInput"
- @visible-change="handleVisibleChange">
- <el-option
- v-if="!query || filteredOptions.length"
- :value="0"
- :label="allLabel">
- </el-option>
- <el-option
- v-for="item in filteredOptions"
- :key="item.id"
- :value="item.id"
- :label="item.name">
- </el-option>
- </el-select>
- </template>
- <script>
- // 票种多选下拉:支持搜索过滤,且可通过顶部“全部票种”选项一键全选当前搜索结果
- // 对外的 v-model 只包含真实票种id(不含“全部”标记0),页面可直接提交
- export default {
- name: 'TicketTypeSelect',
- props: {
- value: {
- type: Array,
- default: () => []
- },
- // 票种列表,由外部传入(支持页面按订单类型等先过滤)
- options: {
- type: Array,
- default: () => []
- }
- },
- data () {
- return {
- query: ''
- }
- },
- computed: {
- // 当前搜索词过滤后的票种
- filteredOptions () {
- if (!this.query) return this.options
- const q = String(this.query).toLowerCase()
- return this.options.filter(i => i.name && String(i.name).toLowerCase().includes(q))
- },
- // 是否已全选(全部票种都在已选值中)
- allChecked () {
- return this.options.length > 0 && this.options.every(i => this.value.includes(i.id))
- },
- allLabel () {
- return this.query ? `全选搜索结果(${this.filteredOptions.length})` : '全部票种'
- },
- // 全选时附加“全部票种”标记用于展示,兼容历史数据中可能存在的0
- displayValue () {
- const realIds = this.value.filter(id => id !== 0)
- return this.allChecked ? [0, ...realIds] : realIds
- }
- },
- methods: {
- handleFilter (q) {
- this.query = q
- },
- handleVisibleChange (visible) {
- if (!visible) this.query = ''
- },
- handleInput (val) {
- val = Array.isArray(val) ? val : []
- const emitVal = (v) => {
- this.$emit('input', v)
- this.$emit('change', v)
- }
- // 清空
- if (!val.length) {
- emitVal([])
- return
- }
- const hadAll = this.allChecked
- const hasAll = val.includes(0)
- if (hasAll && !hadAll) {
- // 勾选“全选”:选中当前搜索结果内的全部票种(保留之前已勾选项)
- const visibleIds = this.filteredOptions.map(i => i.id)
- emitVal(Array.from(new Set([...this.value.filter(id => id !== 0), ...visibleIds])))
- } else if (hadAll && !hasAll) {
- // 取消“全选”:有搜索词时仅移除当前展示的票种,无搜索词时全部清空
- if (this.query) {
- const visibleIds = this.filteredOptions.map(i => i.id)
- emitVal(this.value.filter(id => id !== 0 && !visibleIds.includes(id)))
- } else {
- emitVal([])
- }
- } else {
- // 普通勾选/取消勾选,或在全选状态下取消某一项(此时去掉全选标记)
- emitVal(val.filter(id => id !== 0))
- }
- }
- }
- }
- </script>
|