From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/views/mall/product/spu/components/SpuShowcase.vue |  144 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 144 insertions(+), 0 deletions(-)

diff --git a/src/views/mall/product/spu/components/SpuShowcase.vue b/src/views/mall/product/spu/components/SpuShowcase.vue
new file mode 100644
index 0000000..b8527e0
--- /dev/null
+++ b/src/views/mall/product/spu/components/SpuShowcase.vue
@@ -0,0 +1,144 @@
+<template>
+  <div class="flex flex-wrap items-center gap-8px">
+    <div v-for="(spu, index) in productSpus" :key="spu.id" class="select-box spu-pic">
+      <el-tooltip :content="spu.name">
+        <div class="relative h-full w-full">
+          <el-image :src="spu.picUrl" class="h-full w-full" />
+          <Icon
+            v-show="!disabled"
+            class="del-icon"
+            icon="ep:circle-close-filled"
+            @click="handleRemoveSpu(index)"
+          />
+        </div>
+      </el-tooltip>
+    </div>
+    <el-tooltip content="閫夋嫨鍟嗗搧" v-if="canAdd">
+      <div class="select-box" @click="openSpuTableSelect">
+        <Icon icon="ep:plus" />
+      </div>
+    </el-tooltip>
+  </div>
+  <!-- 鍟嗗搧閫夋嫨瀵硅瘽妗嗭紙琛ㄦ牸褰㈠紡锛� -->
+  <SpuTableSelect ref="spuTableSelectRef" :multiple="limit != 1" @change="handleSpuSelected" />
+</template>
+<script lang="ts" setup>
+import * as ProductSpuApi from '@/api/mall/product/spu'
+import SpuTableSelect from '@/views/mall/product/spu/components/SpuTableSelect.vue'
+import { propTypes } from '@/utils/propTypes'
+import { oneOfType } from 'vue-types'
+import { isArray } from '@/utils/is'
+
+// 鍟嗗搧姗辩獥锛屼竴鑸敤浜庝笌鍟嗗搧寤虹珛鍏崇郴鏃朵娇鐢�
+// 鎻愪緵鍔熻兘锛氬睍绀哄晢鍝佸垪琛ㄣ�佹坊鍔犲晢鍝併�佺Щ闄ゅ晢鍝�
+defineOptions({ name: 'SpuShowcase' })
+
+const props = defineProps({
+  modelValue: oneOfType<number | Array<number>>([Number, Array]).isRequired,
+  // 闄愬埗鏁伴噺锛氶粯璁や笉闄愬埗
+  limit: propTypes.number.def(Number.MAX_VALUE),
+  disabled: propTypes.bool.def(false)
+})
+
+// 璁$畻鏄惁鍙互娣诲姞
+const canAdd = computed(() => {
+  // 鎯呭喌涓�锛氱鐢ㄦ椂涓嶅彲浠ユ坊鍔�
+  if (props.disabled) return false
+  // 鎯呭喌浜岋細鏈寚瀹氶檺鍒舵暟閲忔椂锛屽彲浠ユ坊鍔�
+  if (!props.limit) return true
+  // 鎯呭喌涓夛細妫�鏌ュ凡娣诲姞鏁伴噺鏄惁灏忎簬闄愬埗鏁伴噺
+  return productSpus.value.length < props.limit
+})
+
+// 鍟嗗搧鍒楄〃
+const productSpus = ref<ProductSpuApi.Spu[]>([])
+
+watch(
+  () => props.modelValue,
+  async () => {
+    const ids = isArray(props.modelValue)
+      ? // 鎯呭喌涓�锛氬閫�
+        props.modelValue
+      : // 鎯呭喌浜岋細鍗曢��
+        props.modelValue
+        ? [props.modelValue]
+        : []
+    // 涓嶉渶瑕佽繑鏄�
+    if (ids.length === 0) {
+      productSpus.value = []
+      return
+    }
+    // 鍙湁鍟嗗搧鍙戠敓鍙樺寲涔嬪悗锛屾墠鍘绘煡璇㈠晢鍝�
+    if (productSpus.value.length === 0 || productSpus.value.some((spu) => !ids.includes(spu.id!))) {
+      productSpus.value = await ProductSpuApi.getSpuDetailList(ids)
+    }
+  },
+  { immediate: true }
+)
+
+/** 鍟嗗搧琛ㄦ牸閫夋嫨瀵硅瘽妗� */
+const spuTableSelectRef = ref()
+// 鎵撳紑瀵硅瘽妗�
+const openSpuTableSelect = () => {
+  spuTableSelectRef.value.open(productSpus.value)
+}
+
+/**
+ * 閫夋嫨鍟嗗搧鍚庤Е鍙�
+ *
+ * @param spus 閫変腑鐨勫晢鍝佸垪琛�
+ */
+const handleSpuSelected = (spus: ProductSpuApi.Spu | ProductSpuApi.Spu[]) => {
+  productSpus.value = isArray(spus) ? spus : [spus]
+  emitSpuChange()
+}
+
+/**
+ * 鍒犻櫎鍟嗗搧
+ *
+ * @param index 鍟嗗搧绱㈠紩
+ */
+const handleRemoveSpu = (index: number) => {
+  productSpus.value.splice(index, 1)
+  emitSpuChange()
+}
+const emit = defineEmits(['update:modelValue', 'change'])
+const emitSpuChange = () => {
+  if (props.limit === 1) {
+    const spu = productSpus.value.length > 0 ? productSpus.value[0] : null
+    emit('update:modelValue', spu?.id || 0)
+    emit('change', spu)
+  } else {
+    emit(
+      'update:modelValue',
+      productSpus.value.map((spu) => spu.id)
+    )
+    emit('change', productSpus.value)
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.select-box {
+  display: flex;
+  width: 60px;
+  height: 60px;
+  border: 1px dashed var(--el-border-color-darker);
+  border-radius: 8px;
+  align-items: center;
+  justify-content: center;
+}
+
+.spu-pic {
+  position: relative;
+}
+
+.del-icon {
+  position: absolute;
+  top: -10px;
+  right: -10px;
+  z-index: 1;
+  width: 20px !important;
+  height: 20px !important;
+}
+</style>

--
Gitblit v1.8.0