TicketTypeSelect.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. <template>
  2. <el-select
  3. :value="displayValue"
  4. multiple
  5. filterable
  6. clearable
  7. :filter-method="handleFilter"
  8. @input="handleInput"
  9. @visible-change="handleVisibleChange">
  10. <el-option
  11. v-if="!query || filteredOptions.length"
  12. :value="0"
  13. :label="allLabel">
  14. </el-option>
  15. <el-option
  16. v-for="item in filteredOptions"
  17. :key="item.id"
  18. :value="item.id"
  19. :label="item.name">
  20. </el-option>
  21. </el-select>
  22. </template>
  23. <script>
  24. // 票种多选下拉:支持搜索过滤,且可通过顶部“全部票种”选项一键全选当前搜索结果
  25. // 对外的 v-model 只包含真实票种id(不含“全部”标记0),页面可直接提交
  26. export default {
  27. name: 'TicketTypeSelect',
  28. props: {
  29. value: {
  30. type: Array,
  31. default: () => []
  32. },
  33. // 票种列表,由外部传入(支持页面按订单类型等先过滤)
  34. options: {
  35. type: Array,
  36. default: () => []
  37. }
  38. },
  39. data () {
  40. return {
  41. query: ''
  42. }
  43. },
  44. computed: {
  45. // 当前搜索词过滤后的票种
  46. filteredOptions () {
  47. if (!this.query) return this.options
  48. const q = String(this.query).toLowerCase()
  49. return this.options.filter(i => i.name && String(i.name).toLowerCase().includes(q))
  50. },
  51. // 是否已全选(全部票种都在已选值中)
  52. allChecked () {
  53. return this.options.length > 0 && this.options.every(i => this.value.includes(i.id))
  54. },
  55. allLabel () {
  56. return this.query ? `全选搜索结果(${this.filteredOptions.length})` : '全部票种'
  57. },
  58. // 全选时附加“全部票种”标记用于展示,兼容历史数据中可能存在的0
  59. displayValue () {
  60. const realIds = this.value.filter(id => id !== 0)
  61. return this.allChecked ? [0, ...realIds] : realIds
  62. }
  63. },
  64. methods: {
  65. handleFilter (q) {
  66. this.query = q
  67. },
  68. handleVisibleChange (visible) {
  69. if (!visible) this.query = ''
  70. },
  71. handleInput (val) {
  72. val = Array.isArray(val) ? val : []
  73. const emitVal = (v) => {
  74. this.$emit('input', v)
  75. this.$emit('change', v)
  76. }
  77. // 清空
  78. if (!val.length) {
  79. emitVal([])
  80. return
  81. }
  82. const hadAll = this.allChecked
  83. const hasAll = val.includes(0)
  84. if (hasAll && !hadAll) {
  85. // 勾选“全选”:选中当前搜索结果内的全部票种(保留之前已勾选项)
  86. const visibleIds = this.filteredOptions.map(i => i.id)
  87. emitVal(Array.from(new Set([...this.value.filter(id => id !== 0), ...visibleIds])))
  88. } else if (hadAll && !hasAll) {
  89. // 取消“全选”:有搜索词时仅移除当前展示的票种,无搜索词时全部清空
  90. if (this.query) {
  91. const visibleIds = this.filteredOptions.map(i => i.id)
  92. emitVal(this.value.filter(id => id !== 0 && !visibleIds.includes(id)))
  93. } else {
  94. emitVal([])
  95. }
  96. } else {
  97. // 普通勾选/取消勾选,或在全选状态下取消某一项(此时去掉全选标记)
  98. emitVal(val.filter(id => id !== 0))
  99. }
  100. }
  101. }
  102. }
  103. </script>