commit
5f0b0bd21d
@ -33,7 +33,7 @@ export interface MagicCubeItemProperty {
|
|||||||
export const component = {
|
export const component = {
|
||||||
id: 'MagicCube',
|
id: 'MagicCube',
|
||||||
name: '广告魔方',
|
name: '广告魔方',
|
||||||
icon: 'fluent:puzzle-cube-piece-20-filled',
|
icon: 'bi:columns',
|
||||||
property: {
|
property: {
|
||||||
borderRadiusTop: 0,
|
borderRadiusTop: 0,
|
||||||
borderRadiusBottom: 0,
|
borderRadiusBottom: 0,
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
/** 商品卡片属性 */
|
||||||
|
export interface ProductCardProperty {
|
||||||
|
// 布局类型:单列大图 | 单列小图 | 双列
|
||||||
|
layoutType: 'oneColBigImg' | 'oneColSmallImg' | 'twoCol'
|
||||||
|
// 商品字段
|
||||||
|
fields: {
|
||||||
|
// 商品名称
|
||||||
|
name: ProductCardFieldProperty
|
||||||
|
// 商品简介
|
||||||
|
introduction: ProductCardFieldProperty
|
||||||
|
// 商品价格
|
||||||
|
price: ProductCardFieldProperty
|
||||||
|
// 商品市场价
|
||||||
|
marketPrice: ProductCardFieldProperty
|
||||||
|
// 商品销量
|
||||||
|
salesCount: ProductCardFieldProperty
|
||||||
|
// 商品库存
|
||||||
|
stock: ProductCardFieldProperty
|
||||||
|
}
|
||||||
|
// 角标
|
||||||
|
badge: {
|
||||||
|
// 是否显示
|
||||||
|
show: boolean
|
||||||
|
// 角标图片
|
||||||
|
imgUrl: string
|
||||||
|
}
|
||||||
|
// 按钮
|
||||||
|
btnBuy: {
|
||||||
|
// 类型:文字 | 图片
|
||||||
|
type: 'text' | 'img'
|
||||||
|
// 文字
|
||||||
|
text: string
|
||||||
|
// 文字按钮:背景渐变起始颜色
|
||||||
|
bgBeginColor: string
|
||||||
|
// 文字按钮:背景渐变结束颜色
|
||||||
|
bgEndColor: string
|
||||||
|
// 图片按钮:图片地址
|
||||||
|
imgUrl: string
|
||||||
|
}
|
||||||
|
// 上圆角
|
||||||
|
borderRadiusTop: number
|
||||||
|
// 下圆角
|
||||||
|
borderRadiusBottom: number
|
||||||
|
// 间距
|
||||||
|
space: number
|
||||||
|
// 商品编号列表
|
||||||
|
spuIds: number[]
|
||||||
|
// 组件样式
|
||||||
|
style: ComponentStyle
|
||||||
|
}
|
||||||
|
// 商品字段
|
||||||
|
export interface ProductCardFieldProperty {
|
||||||
|
// 是否显示
|
||||||
|
show: boolean
|
||||||
|
// 颜色
|
||||||
|
color: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义组件
|
||||||
|
export const component = {
|
||||||
|
id: 'ProductCard',
|
||||||
|
name: '商品卡片',
|
||||||
|
icon: 'system-uicons:carousel',
|
||||||
|
property: {
|
||||||
|
layoutType: 'oneColBigImg',
|
||||||
|
fields: {
|
||||||
|
name: { show: true, color: '#000' },
|
||||||
|
introduction: { show: true, color: '#999' },
|
||||||
|
price: { show: true, color: '#ff3000' },
|
||||||
|
marketPrice: { show: true, color: '#c4c4c4' },
|
||||||
|
salesCount: { show: true, color: '#c4c4c4' },
|
||||||
|
stock: { show: false, color: '#c4c4c4' }
|
||||||
|
},
|
||||||
|
badge: { show: false, imgUrl: '' },
|
||||||
|
btnBuy: {
|
||||||
|
type: 'text',
|
||||||
|
text: '立即购买',
|
||||||
|
// todo: @owen 根据主题色配置
|
||||||
|
bgBeginColor: '#FF6000',
|
||||||
|
bgEndColor: '#FE832A',
|
||||||
|
imgUrl: ''
|
||||||
|
},
|
||||||
|
borderRadiusTop: 8,
|
||||||
|
borderRadiusBottom: 8,
|
||||||
|
space: 8,
|
||||||
|
spuIds: [],
|
||||||
|
style: {
|
||||||
|
bgType: 'color',
|
||||||
|
bgColor: '',
|
||||||
|
marginLeft: 8,
|
||||||
|
marginRight: 8,
|
||||||
|
marginBottom: 8
|
||||||
|
} as ComponentStyle
|
||||||
|
}
|
||||||
|
} as DiyComponent<ProductCardProperty>
|
165
src/components/DiyEditor/components/mobile/ProductCard/index.vue
Normal file
165
src/components/DiyEditor/components/mobile/ProductCard/index.vue
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="`box-content min-h-30px w-full flex flex-row flex-wrap`" ref="containerRef">
|
||||||
|
<div
|
||||||
|
class="relative box-content flex flex-row flex-wrap overflow-hidden bg-white"
|
||||||
|
:style="{
|
||||||
|
...calculateSpace(index),
|
||||||
|
...calculateWidth(),
|
||||||
|
borderTopLeftRadius: `${property.borderRadiusTop}px`,
|
||||||
|
borderTopRightRadius: `${property.borderRadiusTop}px`,
|
||||||
|
borderBottomLeftRadius: `${property.borderRadiusBottom}px`,
|
||||||
|
borderBottomRightRadius: `${property.borderRadiusBottom}px`
|
||||||
|
}"
|
||||||
|
v-for="(spu, index) in spuList"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<!-- 角标 -->
|
||||||
|
<div v-if="property.badge.show" class="absolute left-0 top-0 z-1 items-center justify-center">
|
||||||
|
<el-image fit="cover" :src="property.badge.imgUrl" class="h-26px w-38px" />
|
||||||
|
</div>
|
||||||
|
<!-- 商品封面图 -->
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
'h-140px',
|
||||||
|
{
|
||||||
|
'w-full': property.layoutType !== 'oneColSmallImg',
|
||||||
|
'w-140px': property.layoutType === 'oneColSmallImg'
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<el-image fit="cover" class="h-full w-full" :src="spu.picUrl" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
' flex flex-col gap-8px p-8px box-border',
|
||||||
|
{
|
||||||
|
'w-full': property.layoutType !== 'oneColSmallImg',
|
||||||
|
'w-[calc(100%-140px-16px)]': property.layoutType === 'oneColSmallImg'
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<!-- 商品名称 -->
|
||||||
|
<div
|
||||||
|
v-if="property.fields.name.show"
|
||||||
|
:class="[
|
||||||
|
'text-14px ',
|
||||||
|
{
|
||||||
|
truncate: property.layoutType !== 'oneColSmallImg',
|
||||||
|
'overflow-ellipsis line-clamp-2': property.layoutType === 'oneColSmallImg'
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
:style="{ color: property.fields.name.color }"
|
||||||
|
>
|
||||||
|
{{ spu.name }}
|
||||||
|
</div>
|
||||||
|
<!-- 商品简介 -->
|
||||||
|
<div
|
||||||
|
v-if="property.fields.introduction.show"
|
||||||
|
class="truncate text-12px"
|
||||||
|
:style="{ color: property.fields.introduction.color }"
|
||||||
|
>
|
||||||
|
{{ spu.introduction }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<!-- 价格 -->
|
||||||
|
<span
|
||||||
|
v-if="property.fields.price.show"
|
||||||
|
class="text-16px"
|
||||||
|
:style="{ color: property.fields.price.color }"
|
||||||
|
>
|
||||||
|
¥{{ spu.price }}
|
||||||
|
</span>
|
||||||
|
<!-- 市场价 -->
|
||||||
|
<span
|
||||||
|
v-if="property.fields.marketPrice.show && spu.marketPrice"
|
||||||
|
class="ml-4px text-10px line-through"
|
||||||
|
:style="{ color: property.fields.marketPrice.color }"
|
||||||
|
>¥{{ spu.marketPrice }}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="text-12px">
|
||||||
|
<!-- 销量 -->
|
||||||
|
<span
|
||||||
|
v-if="property.fields.salesCount.show"
|
||||||
|
:style="{ color: property.fields.salesCount.color }"
|
||||||
|
>
|
||||||
|
已售{{ (spu.salesCount || 0) + (spu.virtualSalesCount || 0) }}件
|
||||||
|
</span>
|
||||||
|
<!-- 库存 -->
|
||||||
|
<span v-if="property.fields.stock.show" :style="{ color: property.fields.stock.color }">
|
||||||
|
库存{{ spu.stock || 0 }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 购买按钮 -->
|
||||||
|
<div class="absolute bottom-8px right-8px">
|
||||||
|
<!-- 文字按钮 -->
|
||||||
|
<span
|
||||||
|
v-if="property.btnBuy.type === 'text'"
|
||||||
|
class="rounded-full p-x-12px p-y-4px text-12px text-white"
|
||||||
|
:style="{
|
||||||
|
background: `linear-gradient(to right, ${property.btnBuy.bgBeginColor}, ${property.btnBuy.bgEndColor}`
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ property.btnBuy.text }}
|
||||||
|
</span>
|
||||||
|
<!-- 图片按钮 -->
|
||||||
|
<el-image
|
||||||
|
v-else
|
||||||
|
class="h-28px w-28px rounded-full"
|
||||||
|
fit="cover"
|
||||||
|
:src="property.btnBuy.imgUrl"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ProductCardProperty } from './config'
|
||||||
|
import * as ProductSpuApi from '@/api/mall/product/spu'
|
||||||
|
|
||||||
|
/** 商品卡片 */
|
||||||
|
defineOptions({ name: 'ProductCard' })
|
||||||
|
// 定义属性
|
||||||
|
const props = defineProps<{ property: ProductCardProperty }>()
|
||||||
|
// 商品列表
|
||||||
|
const spuList = ref<ProductSpuApi.Spu[]>([])
|
||||||
|
watch(
|
||||||
|
() => props.property.spuIds,
|
||||||
|
async () => {
|
||||||
|
spuList.value = await ProductSpuApi.getSpuDetailList(props.property.spuIds)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
/**
|
||||||
|
* 计算商品的间距
|
||||||
|
* @param index 商品索引
|
||||||
|
*/
|
||||||
|
const calculateSpace = (index: number) => {
|
||||||
|
// 商品的列数
|
||||||
|
const columns = props.property.layoutType === 'twoCol' ? 2 : 1
|
||||||
|
// 第一列没有左边距
|
||||||
|
const marginLeft = index % columns === 0 ? '0' : props.property.space + 'px'
|
||||||
|
// 第一行没有上边距
|
||||||
|
const marginTop = index < columns ? '0' : props.property.space + 'px'
|
||||||
|
|
||||||
|
return { marginLeft, marginTop }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 容器
|
||||||
|
const containerRef = ref()
|
||||||
|
// 计算商品的宽度
|
||||||
|
const calculateWidth = () => {
|
||||||
|
let width = '100%'
|
||||||
|
// 双列时每列的宽度为:(总宽度 - 间距)/ 2
|
||||||
|
if (props.property.layoutType === 'twoCol') {
|
||||||
|
width = `${(containerRef.value.offsetWidth - props.property.space) / 2}px`
|
||||||
|
}
|
||||||
|
return { width }
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
@ -0,0 +1,149 @@
|
|||||||
|
<template>
|
||||||
|
<ComponentContainerProperty v-model="formData.style">
|
||||||
|
<el-form label-width="80px" :model="formData">
|
||||||
|
<el-card header="商品列表" class="property-group" shadow="never">
|
||||||
|
<SpuShowcase v-model="formData.spuIds" />
|
||||||
|
</el-card>
|
||||||
|
<el-card header="商品样式" class="property-group" shadow="never">
|
||||||
|
<el-form-item label="布局" prop="type">
|
||||||
|
<el-radio-group v-model="formData.layoutType">
|
||||||
|
<el-tooltip class="item" content="单列大图" placement="bottom">
|
||||||
|
<el-radio-button label="oneColBigImg">
|
||||||
|
<Icon icon="fluent:text-column-one-24-filled" />
|
||||||
|
</el-radio-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip class="item" content="单列小图" placement="bottom">
|
||||||
|
<el-radio-button label="oneColSmallImg">
|
||||||
|
<Icon icon="fluent:text-column-two-left-24-filled" />
|
||||||
|
</el-radio-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip class="item" content="双列" placement="bottom">
|
||||||
|
<el-radio-button label="twoCol">
|
||||||
|
<Icon icon="fluent:text-column-two-24-filled" />
|
||||||
|
</el-radio-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="商品名称" prop="fields.name.show">
|
||||||
|
<div class="flex gap-8px">
|
||||||
|
<ColorInput v-model="formData.fields.name.color" />
|
||||||
|
<el-checkbox v-model="formData.fields.name.show" />
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="商品简介" prop="fields.introduction.show">
|
||||||
|
<div class="flex gap-8px">
|
||||||
|
<ColorInput v-model="formData.fields.introduction.color" />
|
||||||
|
<el-checkbox v-model="formData.fields.introduction.show" />
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="商品价格" prop="fields.price.show">
|
||||||
|
<div class="flex gap-8px">
|
||||||
|
<ColorInput v-model="formData.fields.price.color" />
|
||||||
|
<el-checkbox v-model="formData.fields.price.show" />
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="市场价" prop="fields.marketPrice.show">
|
||||||
|
<div class="flex gap-8px">
|
||||||
|
<ColorInput v-model="formData.fields.marketPrice.color" />
|
||||||
|
<el-checkbox v-model="formData.fields.marketPrice.show" />
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="商品销量" prop="fields.salesCount.show">
|
||||||
|
<div class="flex gap-8px">
|
||||||
|
<ColorInput v-model="formData.fields.salesCount.color" />
|
||||||
|
<el-checkbox v-model="formData.fields.salesCount.show" />
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="商品库存" prop="fields.stock.show">
|
||||||
|
<div class="flex gap-8px">
|
||||||
|
<ColorInput v-model="formData.fields.stock.color" />
|
||||||
|
<el-checkbox v-model="formData.fields.stock.show" />
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-card>
|
||||||
|
<el-card header="角标" class="property-group" shadow="never">
|
||||||
|
<el-form-item label="角标" prop="badge.show">
|
||||||
|
<el-switch v-model="formData.badge.show" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="角标" prop="badge.imgUrl" v-if="formData.badge.show">
|
||||||
|
<UploadImg v-model="formData.badge.imgUrl" height="44px" width="72px">
|
||||||
|
<template #tip> 建议尺寸:36 * 22 </template>
|
||||||
|
</UploadImg>
|
||||||
|
</el-form-item>
|
||||||
|
</el-card>
|
||||||
|
<el-card header="按钮" class="property-group" shadow="never">
|
||||||
|
<el-form-item label="按钮类型" prop="btnBuy.type">
|
||||||
|
<el-radio-group v-model="formData.btnBuy.type">
|
||||||
|
<el-radio-button label="text">文字</el-radio-button>
|
||||||
|
<el-radio-button label="img">图片</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<template v-if="formData.btnBuy.type === 'text'">
|
||||||
|
<el-form-item label="按钮文字" prop="btnBuy.text">
|
||||||
|
<el-input v-model="formData.btnBuy.text" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="左侧背景" prop="btnBuy.bgBeginColor">
|
||||||
|
<ColorInput v-model="formData.btnBuy.bgBeginColor" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="右侧背景" prop="btnBuy.bgEndColor">
|
||||||
|
<ColorInput v-model="formData.btnBuy.bgEndColor" />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-form-item label="图片" prop="btnBuy.imgUrl">
|
||||||
|
<UploadImg v-model="formData.btnBuy.imgUrl" height="56px" width="56px">
|
||||||
|
<template #tip> 建议尺寸:56 * 56 </template>
|
||||||
|
</UploadImg>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-card>
|
||||||
|
<el-card header="商品样式" class="property-group" shadow="never">
|
||||||
|
<el-form-item label="上圆角" prop="borderRadiusTop">
|
||||||
|
<el-slider
|
||||||
|
v-model="formData.borderRadiusTop"
|
||||||
|
:max="100"
|
||||||
|
:min="0"
|
||||||
|
show-input
|
||||||
|
input-size="small"
|
||||||
|
:show-input-controls="false"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="下圆角" prop="borderRadiusBottom">
|
||||||
|
<el-slider
|
||||||
|
v-model="formData.borderRadiusBottom"
|
||||||
|
:max="100"
|
||||||
|
:min="0"
|
||||||
|
show-input
|
||||||
|
input-size="small"
|
||||||
|
:show-input-controls="false"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="间隔" prop="space">
|
||||||
|
<el-slider
|
||||||
|
v-model="formData.space"
|
||||||
|
:max="100"
|
||||||
|
:min="0"
|
||||||
|
show-input
|
||||||
|
input-size="small"
|
||||||
|
:show-input-controls="false"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-card>
|
||||||
|
</el-form>
|
||||||
|
</ComponentContainerProperty>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ProductCardProperty } from './config'
|
||||||
|
import { usePropertyForm } from '@/components/DiyEditor/util'
|
||||||
|
import SpuShowcase from '@/views/mall/product/spu/components/SpuShowcase.vue'
|
||||||
|
|
||||||
|
// 商品卡片属性面板
|
||||||
|
defineOptions({ name: 'ProductCardProperty' })
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: ProductCardProperty }>()
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const { formData } = usePropertyForm(props.modelValue, emit)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
126
src/views/mall/product/spu/components/SpuShowcase.vue
Normal file
126
src/views/mall/product/spu/components/SpuShowcase.vue
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<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="选择商品">
|
||||||
|
<div
|
||||||
|
v-show="!disabled"
|
||||||
|
v-if="!limit || limit <= productSpus.length"
|
||||||
|
class="select-box"
|
||||||
|
@click="openSpuTableSelect"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:plus" />
|
||||||
|
</div>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
<!-- 商品选择对话框(表格形式) -->
|
||||||
|
<SpuTableSelect ref="spuTableSelectRef" multiple @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 { array } from 'vue-types'
|
||||||
|
|
||||||
|
// 商品橱窗,一般用于与商品建立关系时使用
|
||||||
|
// 提供功能:展示商品列表、添加商品、移除商品
|
||||||
|
defineOptions({ name: 'SpuShowcase' })
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: array<number>().def([]).isRequired,
|
||||||
|
// 限制数量:默认不限制
|
||||||
|
limit: propTypes.number.def(0),
|
||||||
|
disabled: propTypes.bool.def(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 商品列表
|
||||||
|
const productSpus = ref<ProductSpuApi.Spu[]>([])
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
async () => {
|
||||||
|
if (props.modelValue.length === 0) {
|
||||||
|
productSpus.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 只有商品发生变化之后,才去查询商品
|
||||||
|
if (
|
||||||
|
productSpus.value.length === 0 ||
|
||||||
|
productSpus.value.some((spu) => !props.modelValue.includes(spu.id))
|
||||||
|
) {
|
||||||
|
debugger
|
||||||
|
productSpus.value = await ProductSpuApi.getSpuDetailList(props.modelValue)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
/** 商品表格选择对话框 */
|
||||||
|
const spuTableSelectRef = ref()
|
||||||
|
// 打开对话框
|
||||||
|
const openSpuTableSelect = () => {
|
||||||
|
spuTableSelectRef.value.open(productSpus.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择商品后触发
|
||||||
|
* @param spus 选中的商品列表
|
||||||
|
*/
|
||||||
|
const handleSpuSelected = (spus: ProductSpuApi.Spu[]) => {
|
||||||
|
productSpus.value = spus
|
||||||
|
emitSpuChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除商品
|
||||||
|
* @param index 商品索引
|
||||||
|
*/
|
||||||
|
const handleRemoveSpu = (index: number) => {
|
||||||
|
productSpus.value.splice(index, 1)
|
||||||
|
emitSpuChange()
|
||||||
|
}
|
||||||
|
const emit = defineEmits(['update:modelValue', 'change'])
|
||||||
|
const emitSpuChange = () => {
|
||||||
|
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>
|
Loading…
Reference in New Issue
Block a user