CombinationShowcase.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <template>
  2. <div class="flex flex-wrap items-center gap-8px">
  3. <div
  4. v-for="(combinationActivity, index) in Activitys"
  5. :key="combinationActivity.id"
  6. class="select-box spu-pic"
  7. >
  8. <el-tooltip :content="combinationActivity.name">
  9. <div class="relative h-full w-full">
  10. <el-image :src="combinationActivity.picUrl" class="h-full w-full" />
  11. <Icon
  12. v-show="!disabled"
  13. class="del-icon"
  14. icon="ep:circle-close-filled"
  15. @click="handleRemoveActivity(index)"
  16. />
  17. </div>
  18. </el-tooltip>
  19. </div>
  20. <el-tooltip content="选择活动" v-if="canAdd">
  21. <div class="select-box" @click="openCombinationActivityTableSelect">
  22. <Icon icon="ep:plus" />
  23. </div>
  24. </el-tooltip>
  25. </div>
  26. <!-- 拼团活动选择对话框(表格形式) -->
  27. <CombinationTableSelect
  28. ref="combinationActivityTableSelectRef"
  29. :multiple="limit != 1"
  30. @change="handleActivitySelected"
  31. />
  32. </template>
  33. <script lang="ts" setup>
  34. import * as CombinationActivityApi from '@/api/mall/promotion/combination/combinationActivity'
  35. import { propTypes } from '@/utils/propTypes'
  36. import { oneOfType } from 'vue-types'
  37. import { isArray } from '@/utils/is'
  38. import CombinationTableSelect from '@/views/mall/promotion/combination/components/CombinationTableSelect.vue'
  39. // 活动橱窗,一般用于装修时使用
  40. // 提供功能:展示活动列表、添加活动、删除活动
  41. defineOptions({ name: 'CombinationShowcase' })
  42. const props = defineProps({
  43. modelValue: oneOfType<number | Array<number>>([Number, Array]).isRequired,
  44. // 限制数量:默认不限制
  45. limit: propTypes.number.def(Number.MAX_VALUE),
  46. disabled: propTypes.bool.def(false)
  47. })
  48. // 计算是否可以添加
  49. const canAdd = computed(() => {
  50. // 情况一:禁用时不可以添加
  51. if (props.disabled) return false
  52. // 情况二:未指定限制数量时,可以添加
  53. if (!props.limit) return true
  54. // 情况三:检查已添加数量是否小于限制数量
  55. return Activitys.value.length < props.limit
  56. })
  57. // 拼团活动列表
  58. const Activitys = ref<CombinationActivityApi.CombinationActivityVO[]>([])
  59. watch(
  60. () => props.modelValue,
  61. async () => {
  62. const ids = isArray(props.modelValue)
  63. ? // 情况一:多选
  64. props.modelValue
  65. : // 情况二:单选
  66. props.modelValue
  67. ? [props.modelValue]
  68. : []
  69. // 不需要返显
  70. if (ids.length === 0) {
  71. Activitys.value = []
  72. return
  73. }
  74. // 只有活动发生变化之后,才会查询活动
  75. if (
  76. Activitys.value.length === 0 ||
  77. Activitys.value.some((combinationActivity) => !ids.includes(combinationActivity.id!))
  78. ) {
  79. Activitys.value = await CombinationActivityApi.getCombinationActivityDetailList(ids)
  80. }
  81. },
  82. { immediate: true }
  83. )
  84. /** 活动表格选择对话框 */
  85. const combinationActivityTableSelectRef = ref()
  86. // 打开对话框
  87. const openCombinationActivityTableSelect = () => {
  88. combinationActivityTableSelectRef.value.open(Activitys.value)
  89. }
  90. /**
  91. * 选择活动后触发
  92. * @param activityVOs 选中的活动列表
  93. */
  94. const handleActivitySelected = (
  95. activityVOs:
  96. | CombinationActivityApi.CombinationActivityVO
  97. | CombinationActivityApi.CombinationActivityVO[]
  98. ) => {
  99. Activitys.value = isArray(activityVOs) ? activityVOs : [activityVOs]
  100. emitActivityChange()
  101. }
  102. /**
  103. * 删除活动
  104. * @param index 活动索引
  105. */
  106. const handleRemoveActivity = (index: number) => {
  107. Activitys.value.splice(index, 1)
  108. emitActivityChange()
  109. }
  110. const emit = defineEmits(['update:modelValue', 'change'])
  111. const emitActivityChange = () => {
  112. if (props.limit === 1) {
  113. const combinationActivity = Activitys.value.length > 0 ? Activitys.value[0] : null
  114. emit('update:modelValue', combinationActivity?.id || 0)
  115. emit('change', combinationActivity)
  116. } else {
  117. emit(
  118. 'update:modelValue',
  119. Activitys.value.map((combinationActivity) => combinationActivity.id)
  120. )
  121. emit('change', Activitys.value)
  122. }
  123. }
  124. </script>
  125. <style lang="scss" scoped>
  126. .select-box {
  127. display: flex;
  128. width: 60px;
  129. height: 60px;
  130. border: 1px dashed var(--el-border-color-darker);
  131. border-radius: 8px;
  132. align-items: center;
  133. justify-content: center;
  134. cursor: pointer;
  135. }
  136. .spu-pic {
  137. position: relative;
  138. }
  139. .del-icon {
  140. position: absolute;
  141. top: -10px;
  142. right: -10px;
  143. z-index: 1;
  144. width: 20px !important;
  145. height: 20px !important;
  146. }
  147. </style>